From 382aece077205ec3882300f50277c43607c52d96 Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Tue, 3 Feb 2026 15:10:32 -0300 Subject: [PATCH] Forward-fill plano contrato in resumo import --- Controllers/LinesController.cs | 102 ++++++++++++++++++++++++++++++--- 1 file changed, 94 insertions(+), 8 deletions(-) diff --git a/Controllers/LinesController.cs b/Controllers/LinesController.cs index 36dcf60..fa1335d 100644 --- a/Controllers/LinesController.cs +++ b/Controllers/LinesController.cs @@ -1714,9 +1714,9 @@ namespace line_gestao_api.Controllers private async Task ImportResumoTabela4(IXLWorksheet ws, DateTime now) { - const int headerRow = 74; - const int totalRow = 81; - var lastRow = Math.Min(totalRow - 1, ws.LastRowUsed()?.RowNumber() ?? totalRow - 1); + var lastRowUsed = ws.LastRowUsed()?.RowNumber() ?? 1; + var headerRow = FindHeaderRowForPlanoContratoResumo(ws, 1, lastRowUsed); + if (headerRow == 0) return; var map = BuildHeaderMap(ws.Row(headerRow)); var colPlano = GetCol(map, "PLANO CONTRATO"); @@ -1725,10 +1725,17 @@ namespace line_gestao_api.Controllers var colFranquiaGb = GetColAny(map, "FRANQUIA GB", "FRAQUIA GB"); var colTotalLinhas = GetColAny(map, "TOTAL DE LINHAS", "TOTAL LINHAS"); var colValorTotal = GetCol(map, "VALOR TOTAL"); + var colCliente = GetCol(map, "CLIENTE"); + var colQtdLinhas = GetColAny(map, "QTD DE LINHAS", "QTD. DE LINHAS", "QTD LINHAS"); var buffer = new List(200); + string? lastPlanoContrato = null; + var dataStarted = false; + var emptyDataStreak = 0; + int? totalRowIndex = null; + var missingPlanoCount = 0; - for (int r = headerRow + 1; r <= lastRow; r++) + for (int r = headerRow + 1; r <= lastRowUsed; r++) { var plano = GetCellString(ws, r, colPlano); var gb = GetCellString(ws, r, colGb); @@ -1736,20 +1743,68 @@ namespace line_gestao_api.Controllers var franquia = GetCellString(ws, r, colFranquiaGb); var totalLinhas = GetCellString(ws, r, colTotalLinhas); var valorTotal = GetCellString(ws, r, colValorTotal); + var cliente = GetCellString(ws, r, colCliente); + var qtdLinhas = GetCellString(ws, r, colQtdLinhas); - if (string.IsNullOrWhiteSpace(plano) + var isPlanoTotal = !string.IsNullOrWhiteSpace(plano) + && NormalizeHeader(plano) == NormalizeHeader("TOTAL"); + + if (isPlanoTotal) + { + totalRowIndex = r; + break; + } + + var hasAnyValue = !(string.IsNullOrWhiteSpace(plano) && string.IsNullOrWhiteSpace(gb) && string.IsNullOrWhiteSpace(valorInd) && string.IsNullOrWhiteSpace(franquia) && string.IsNullOrWhiteSpace(totalLinhas) - && string.IsNullOrWhiteSpace(valorTotal)) + && string.IsNullOrWhiteSpace(valorTotal) + && string.IsNullOrWhiteSpace(cliente) + && string.IsNullOrWhiteSpace(qtdLinhas)); + + if (!hasAnyValue) { + if (dataStarted) + { + emptyDataStreak++; + if (emptyDataStreak >= 2) break; + } continue; } + emptyDataStreak = 0; + + var isDataRow = !string.IsNullOrWhiteSpace(cliente) || TryNullableInt(qtdLinhas).HasValue; + + var planoNormalized = NormalizeHeader(plano); + if (!string.IsNullOrWhiteSpace(plano) + && planoNormalized != NormalizeHeader("PLANO CONTRATO") + && planoNormalized != NormalizeHeader("TOTAL")) + { + lastPlanoContrato = plano.Trim(); + } + + if (!isDataRow && dataStarted) + { + break; + } + + if (isDataRow) dataStarted = true; + + var resolvedPlano = isDataRow + ? (string.IsNullOrWhiteSpace(plano) ? lastPlanoContrato : plano.Trim()) + : (string.IsNullOrWhiteSpace(plano) ? null : plano.Trim()); + + if (isDataRow && string.IsNullOrWhiteSpace(resolvedPlano)) + { + missingPlanoCount++; + } + buffer.Add(new ResumoPlanoContratoResumo { - PlanoContrato = string.IsNullOrWhiteSpace(plano) ? null : plano.Trim(), + PlanoContrato = string.IsNullOrWhiteSpace(resolvedPlano) ? null : resolvedPlano, Gb = TryDecimal(gb), ValorIndividualComSvas = TryDecimal(valorInd), FranquiaGb = TryDecimal(franquia), @@ -1766,9 +1821,19 @@ namespace line_gestao_api.Controllers await _db.SaveChangesAsync(); } + if (missingPlanoCount > 0) + { + throw new InvalidOperationException($"Import RESUMO/PLANO CONTRATO: {missingPlanoCount} linhas de dados ficaram sem PLANO CONTRATO."); + } + + if (totalRowIndex == null) + { + return; + } + var total = new ResumoPlanoContratoTotal { - ValorTotal = TryDecimal(ws.Cell(totalRow, 7).GetString()), + ValorTotal = TryDecimal(GetCellString(ws, totalRowIndex.Value, colValorTotal)), CreatedAt = now, UpdatedAt = now }; @@ -1777,6 +1842,27 @@ namespace line_gestao_api.Controllers await _db.SaveChangesAsync(); } + private static int FindHeaderRowForPlanoContratoResumo(IXLWorksheet ws, int startRow, int lastRow) + { + for (int r = startRow; r <= lastRow; r++) + { + var row = ws.Row(r); + if (!row.CellsUsed().Any()) continue; + + var map = BuildHeaderMap(row); + var hasPlano = GetCol(map, "PLANO CONTRATO") > 0; + var hasCliente = GetCol(map, "CLIENTE") > 0; + var hasQtd = GetColAny(map, "QTD DE LINHAS", "QTD. DE LINHAS", "QTD LINHAS") > 0; + + if (hasPlano && hasCliente && hasQtd) + { + return r; + } + } + + return 0; + } + private async Task ImportResumoTabela5(IXLWorksheet ws, DateTime now) { const int headerRow = 83;