perf: otimiza importacao e exportacao de linhas
This commit is contained in:
parent
b25cdaa507
commit
b5b36276cb
|
|
@ -144,7 +144,13 @@ namespace line_gestao_api.Controllers
|
|||
if (!string.IsNullOrWhiteSpace(search))
|
||||
{
|
||||
var s = search.Trim();
|
||||
reservaRows = reservaRows.Where(x => EF.Functions.ILike(x.Cliente ?? "", $"%{s}%"));
|
||||
reservaRows = reservaRows.Where(x =>
|
||||
EF.Functions.ILike(x.Linha ?? "", $"%{s}%") ||
|
||||
EF.Functions.ILike(x.Chip ?? "", $"%{s}%") ||
|
||||
EF.Functions.ILike(x.Cliente ?? "", $"%{s}%") ||
|
||||
EF.Functions.ILike(x.Usuario ?? "", $"%{s}%") ||
|
||||
EF.Functions.ILike(x.Conta ?? "", $"%{s}%") ||
|
||||
EF.Functions.ILike(x.Status ?? "", $"%{s}%"));
|
||||
}
|
||||
|
||||
groupedQuery = reservaRows
|
||||
|
|
@ -166,7 +172,13 @@ namespace line_gestao_api.Controllers
|
|||
if (!string.IsNullOrWhiteSpace(search))
|
||||
{
|
||||
var s = search.Trim();
|
||||
query = query.Where(x => EF.Functions.ILike(x.Cliente ?? "", $"%{s}%"));
|
||||
query = query.Where(x =>
|
||||
EF.Functions.ILike(x.Linha ?? "", $"%{s}%") ||
|
||||
EF.Functions.ILike(x.Chip ?? "", $"%{s}%") ||
|
||||
EF.Functions.ILike(x.Cliente ?? "", $"%{s}%") ||
|
||||
EF.Functions.ILike(x.Usuario ?? "", $"%{s}%") ||
|
||||
EF.Functions.ILike(x.Conta ?? "", $"%{s}%") ||
|
||||
EF.Functions.ILike(x.Status ?? "", $"%{s}%"));
|
||||
}
|
||||
|
||||
groupedQuery = query.GroupBy(x => x.Cliente)
|
||||
|
|
@ -622,6 +634,122 @@ namespace line_gestao_api.Controllers
|
|||
return Ok(ToDetailDto(x, vigencia));
|
||||
}
|
||||
|
||||
[HttpPost("export-details")]
|
||||
public async Task<ActionResult<List<MobileLineDetailDto>>> GetExportDetails([FromBody] MobileLineExportDetailsRequestDto? req)
|
||||
{
|
||||
var orderedIds = (req?.Ids ?? new List<Guid>())
|
||||
.Where(id => id != Guid.Empty)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
if (orderedIds.Count == 0)
|
||||
{
|
||||
return Ok(new List<MobileLineDetailDto>());
|
||||
}
|
||||
|
||||
var lines = await _db.MobileLines
|
||||
.AsNoTracking()
|
||||
.Include(x => x.Setor)
|
||||
.Include(x => x.Aparelho)
|
||||
.Where(x => orderedIds.Contains(x.Id))
|
||||
.ToListAsync();
|
||||
|
||||
if (lines.Count == 0)
|
||||
{
|
||||
return Ok(new List<MobileLineDetailDto>());
|
||||
}
|
||||
|
||||
var vigenciaByLinha = new Dictionary<string, VigenciaLine>(StringComparer.Ordinal);
|
||||
var vigenciaByItem = new Dictionary<int, VigenciaLine>();
|
||||
|
||||
var lineKeys = lines
|
||||
.Select(x => NullIfEmptyDigits(x.Linha))
|
||||
.Where(x => !string.IsNullOrWhiteSpace(x))
|
||||
.Distinct(StringComparer.Ordinal)
|
||||
.ToList();
|
||||
|
||||
var itemKeys = lines
|
||||
.Where(x => x.Item > 0)
|
||||
.Select(x => x.Item)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
if (lineKeys.Count > 0 || itemKeys.Count > 0)
|
||||
{
|
||||
IQueryable<VigenciaLine> vigenciaQuery = _db.VigenciaLines.AsNoTracking();
|
||||
|
||||
if (lineKeys.Count > 0 && itemKeys.Count > 0)
|
||||
{
|
||||
vigenciaQuery = vigenciaQuery.Where(v => lineKeys.Contains(v.Linha!) || itemKeys.Contains(v.Item));
|
||||
}
|
||||
else if (lineKeys.Count > 0)
|
||||
{
|
||||
vigenciaQuery = vigenciaQuery.Where(v => lineKeys.Contains(v.Linha!));
|
||||
}
|
||||
else
|
||||
{
|
||||
vigenciaQuery = vigenciaQuery.Where(v => itemKeys.Contains(v.Item));
|
||||
}
|
||||
|
||||
var vigencias = await vigenciaQuery.ToListAsync();
|
||||
|
||||
foreach (var vigencia in vigencias
|
||||
.Where(v => !string.IsNullOrWhiteSpace(v.Linha))
|
||||
.GroupBy(v => NullIfEmptyDigits(v.Linha)!, StringComparer.Ordinal)
|
||||
.Select(g => g
|
||||
.OrderByDescending(x => x.UpdatedAt)
|
||||
.ThenByDescending(x => x.CreatedAt)
|
||||
.First()))
|
||||
{
|
||||
var key = NullIfEmptyDigits(vigencia.Linha);
|
||||
if (!string.IsNullOrWhiteSpace(key))
|
||||
{
|
||||
vigenciaByLinha[key] = vigencia;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var vigencia in vigencias
|
||||
.Where(v => string.IsNullOrWhiteSpace(v.Linha))
|
||||
.GroupBy(v => v.Item)
|
||||
.Select(g => g
|
||||
.OrderByDescending(x => x.UpdatedAt)
|
||||
.ThenByDescending(x => x.CreatedAt)
|
||||
.First()))
|
||||
{
|
||||
if (vigencia.Item > 0)
|
||||
{
|
||||
vigenciaByItem[vigencia.Item] = vigencia;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var linesById = lines.ToDictionary(x => x.Id);
|
||||
var result = new List<MobileLineDetailDto>(orderedIds.Count);
|
||||
|
||||
foreach (var id in orderedIds)
|
||||
{
|
||||
if (!linesById.TryGetValue(id, out var line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
VigenciaLine? vigencia = null;
|
||||
var lineKey = NullIfEmptyDigits(line.Linha);
|
||||
if (!string.IsNullOrWhiteSpace(lineKey))
|
||||
{
|
||||
vigenciaByLinha.TryGetValue(lineKey, out vigencia);
|
||||
}
|
||||
else if (line.Item > 0)
|
||||
{
|
||||
vigenciaByItem.TryGetValue(line.Item, out vigencia);
|
||||
}
|
||||
|
||||
result.Add(ToDetailDto(line, vigencia));
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
// ==========================================================
|
||||
// ✅ 5. CREATE
|
||||
// ==========================================================
|
||||
|
|
@ -1738,7 +1866,7 @@ namespace line_gestao_api.Controllers
|
|||
await _db.MuregLines.ExecuteDeleteAsync();
|
||||
await _db.MobileLines.ExecuteDeleteAsync();
|
||||
|
||||
var buffer = new List<MobileLine>(600);
|
||||
var buffer = new List<MobileLine>(1000);
|
||||
var imported = 0;
|
||||
var maxItemFromGeral = 0;
|
||||
|
||||
|
|
@ -1805,11 +1933,12 @@ namespace line_gestao_api.Controllers
|
|||
imported++;
|
||||
if (item > maxItemFromGeral) maxItemFromGeral = item;
|
||||
|
||||
if (buffer.Count >= 500)
|
||||
if (buffer.Count >= 1000)
|
||||
{
|
||||
await _db.MobileLines.AddRangeAsync(buffer);
|
||||
await _db.SaveChangesAsync();
|
||||
buffer.Clear();
|
||||
ClearImportTracking();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1817,6 +1946,8 @@ namespace line_gestao_api.Controllers
|
|||
{
|
||||
await _db.MobileLines.AddRangeAsync(buffer);
|
||||
await _db.SaveChangesAsync();
|
||||
buffer.Clear();
|
||||
ClearImportTracking();
|
||||
}
|
||||
|
||||
auditSession = _spreadsheetImportAuditService.StartRun(
|
||||
|
|
@ -1828,40 +1959,48 @@ namespace line_gestao_api.Controllers
|
|||
// ✅ IMPORTA MUREG (ALTERADO: NÃO ESTOURA ERRO SE LINHANOVA JÁ EXISTIR)
|
||||
// =========================
|
||||
await ImportMuregFromWorkbook(wb);
|
||||
ClearImportTracking();
|
||||
|
||||
// =========================
|
||||
// ✅ IMPORTA FATURAMENTO PF/PJ
|
||||
// =========================
|
||||
await ImportBillingFromWorkbook(wb);
|
||||
ClearImportTracking();
|
||||
|
||||
// =========================
|
||||
// ✅ IMPORTA DADOS DOS USUÁRIOS (UserDatas)
|
||||
// =========================
|
||||
var userDataImported = await ImportUserDatasFromWorkbook(wb);
|
||||
ClearImportTracking();
|
||||
if (userDataImported)
|
||||
{
|
||||
await RepairReservaClientAssignmentsAsync();
|
||||
ClearImportTracking();
|
||||
}
|
||||
|
||||
// =========================
|
||||
// ✅ IMPORTA VIGÊNCIA
|
||||
// =========================
|
||||
await ImportVigenciaFromWorkbook(wb);
|
||||
ClearImportTracking();
|
||||
|
||||
// =========================
|
||||
// ✅ IMPORTA TROCA DE NÚMERO
|
||||
// =========================
|
||||
await ImportTrocaNumeroFromWorkbook(wb);
|
||||
ClearImportTracking();
|
||||
|
||||
// =========================
|
||||
// ✅ IMPORTA CHIPS VIRGENS
|
||||
// =========================
|
||||
await ImportChipsVirgensFromWorkbook(wb);
|
||||
ClearImportTracking();
|
||||
|
||||
// =========================
|
||||
// ✅ IMPORTA CONTROLE DE RECEBIDOS
|
||||
// =========================
|
||||
await ImportControleRecebidosFromWorkbook(wb);
|
||||
ClearImportTracking();
|
||||
|
||||
// =========================
|
||||
// ✅ IMPORTA RESUMO
|
||||
|
|
@ -1872,11 +2011,13 @@ namespace line_gestao_api.Controllers
|
|||
}
|
||||
|
||||
await ImportResumoFromWorkbook(wb, auditSession);
|
||||
ClearImportTracking();
|
||||
|
||||
// =========================
|
||||
// ✅ IMPORTA PARCELAMENTOS
|
||||
// =========================
|
||||
var parcelamentosSummary = await _parcelamentosImportService.ImportFromWorkbookAsync(wb, replaceAll: true);
|
||||
ClearImportTracking();
|
||||
if (auditSession != null)
|
||||
{
|
||||
await _spreadsheetImportAuditService.SaveRunAsync(auditSession);
|
||||
|
|
@ -2122,17 +2263,15 @@ namespace line_gestao_api.Controllers
|
|||
// limpa MUREG antes (idempotente)
|
||||
await _db.MuregLines.ExecuteDeleteAsync();
|
||||
|
||||
// ✅ dicionários para resolver MobileLineId por Linha/Chip
|
||||
var mobilePairs = await _db.MobileLines
|
||||
.AsNoTracking()
|
||||
.Select(x => new { x.Id, x.Item, x.Linha, x.Chip })
|
||||
.ToListAsync();
|
||||
// Carrega uma vez para evitar consultas por linha durante a importacao da MUREG.
|
||||
var mobileCache = await _db.MobileLines
|
||||
.ToDictionaryAsync(x => x.Id);
|
||||
|
||||
var mobileByLinha = new Dictionary<string, Guid>(StringComparer.Ordinal);
|
||||
var mobileByChip = new Dictionary<string, Guid>(StringComparer.Ordinal);
|
||||
var mobileByItem = new Dictionary<int, Guid>();
|
||||
|
||||
foreach (var m in mobilePairs)
|
||||
foreach (var m in mobileCache.Values)
|
||||
{
|
||||
if (m.Item > 0 && !mobileByItem.ContainsKey(m.Item))
|
||||
mobileByItem[m.Item] = m.Id;
|
||||
|
|
@ -2152,10 +2291,7 @@ namespace line_gestao_api.Controllers
|
|||
}
|
||||
}
|
||||
|
||||
// ✅ cache de entidades tracked para atualizar a GERAL sem consultar toda hora
|
||||
var mobileCache = new Dictionary<Guid, MobileLine>();
|
||||
|
||||
var buffer = new List<MuregLine>(600);
|
||||
var buffer = new List<MuregLine>(1000);
|
||||
var lastRow = wsM.LastRowUsed()?.RowNumber() ?? startRow;
|
||||
|
||||
for (int r = startRow; r <= lastRow; r++)
|
||||
|
|
@ -2204,12 +2340,7 @@ namespace line_gestao_api.Controllers
|
|||
string? linhaAntigaSnapshot = linhaAntiga;
|
||||
if (string.IsNullOrWhiteSpace(linhaAntigaSnapshot))
|
||||
{
|
||||
if (!mobileCache.TryGetValue(mobileLineId, out var mobTmp))
|
||||
{
|
||||
mobTmp = await _db.MobileLines.FirstOrDefaultAsync(x => x.Id == mobileLineId);
|
||||
if (mobTmp != null) mobileCache[mobileLineId] = mobTmp;
|
||||
}
|
||||
|
||||
mobileCache.TryGetValue(mobileLineId, out var mobTmp);
|
||||
linhaAntigaSnapshot = mobTmp?.Linha;
|
||||
}
|
||||
|
||||
|
|
@ -2241,12 +2372,7 @@ namespace line_gestao_api.Controllers
|
|||
}
|
||||
else
|
||||
{
|
||||
// carrega entity tracked (cache) e atualiza
|
||||
if (!mobileCache.TryGetValue(mobileLineId, out var mobile))
|
||||
{
|
||||
mobile = await _db.MobileLines.FirstOrDefaultAsync(x => x.Id == mobileLineId);
|
||||
if (mobile != null) mobileCache[mobileLineId] = mobile;
|
||||
}
|
||||
mobileCache.TryGetValue(mobileLineId, out var mobile);
|
||||
|
||||
if (mobile != null)
|
||||
{
|
||||
|
|
@ -2277,7 +2403,7 @@ namespace line_gestao_api.Controllers
|
|||
}
|
||||
}
|
||||
|
||||
if (buffer.Count >= 500)
|
||||
if (buffer.Count >= 1000)
|
||||
{
|
||||
await _db.MuregLines.AddRangeAsync(buffer);
|
||||
await _db.SaveChangesAsync();
|
||||
|
|
@ -2289,6 +2415,7 @@ namespace line_gestao_api.Controllers
|
|||
{
|
||||
await _db.MuregLines.AddRangeAsync(buffer);
|
||||
await _db.SaveChangesAsync();
|
||||
buffer.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -5244,9 +5371,16 @@ namespace line_gestao_api.Controllers
|
|||
DtEfetivacaoServico = vigencia?.DtEfetivacaoServico,
|
||||
DtTerminoFidelizacao = vigencia?.DtTerminoFidelizacao,
|
||||
VencConta = x.VencConta,
|
||||
TipoDeChip = x.TipoDeChip
|
||||
TipoDeChip = x.TipoDeChip,
|
||||
CreatedAt = x.CreatedAt,
|
||||
UpdatedAt = x.UpdatedAt
|
||||
};
|
||||
|
||||
private void ClearImportTracking()
|
||||
{
|
||||
_db.ChangeTracker.Clear();
|
||||
}
|
||||
|
||||
private static void ApplyReservaRule(MobileLine x)
|
||||
{
|
||||
if (IsReservaValue(x.Cliente)) x.Cliente = "RESERVA";
|
||||
|
|
|
|||
|
|
@ -84,6 +84,8 @@
|
|||
public DateTime? DtTerminoFidelizacao { get; set; }
|
||||
public string? VencConta { get; set; }
|
||||
public string? TipoDeChip { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
public DateTime UpdatedAt { get; set; }
|
||||
}
|
||||
|
||||
// ✅ UPDATE REQUEST (SEM Id)
|
||||
|
|
@ -153,4 +155,9 @@
|
|||
public string? Skil { get; set; }
|
||||
}
|
||||
|
||||
public class MobileLineExportDetailsRequestDto
|
||||
{
|
||||
public List<Guid> Ids { get; set; } = new();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue