diff --git a/Controllers/LinesController.cs b/Controllers/LinesController.cs index fa1335d..992275c 100644 --- a/Controllers/LinesController.cs +++ b/Controllers/LinesController.cs @@ -1520,9 +1520,9 @@ namespace line_gestao_api.Controllers private async Task ImportResumoTabela1(IXLWorksheet ws, DateTime now) { - const int headerRow = 5; - const int totalRow = 72; - var lastRow = Math.Min(totalRow - 1, ws.LastRowUsed()?.RowNumber() ?? totalRow - 1); + var lastRowUsed = ws.LastRowUsed()?.RowNumber() ?? 1; + var headerRow = FindHeaderRowForMacrophonyPlans(ws, 1, lastRowUsed); + if (headerRow == 0) return; var map = BuildHeaderMap(ws.Row(headerRow)); var colPlano = GetCol(map, "PLANO CONTRATO"); @@ -1533,8 +1533,15 @@ namespace line_gestao_api.Controllers var colValorTotal = GetCol(map, "VALOR TOTAL"); var buffer = new List(200); + string? lastPlanoContrato = null; + decimal? lastGb = null; + var dataStarted = false; + var emptyDataStreak = 0; + int? totalRowIndex = null; + var missingPlanoCount = 0; + var missingGbCount = 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); @@ -1543,27 +1550,90 @@ namespace line_gestao_api.Controllers var totalLinhas = GetCellString(ws, r, colTotalLinhas); var valorTotal = GetCellString(ws, r, colValorTotal); - 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)); + + if (!hasAnyValue) + { + if (dataStarted) + { + emptyDataStreak++; + if (emptyDataStreak >= 2) break; + } + continue; + } + + emptyDataStreak = 0; + + var franquiaValue = TryDecimal(franquia); + var totalLinhasValue = TryNullableInt(totalLinhas); + var isDataRow = franquiaValue.HasValue || totalLinhasValue.HasValue; + if (isDataRow) dataStarted = true; + if (!isDataRow && dataStarted) + { + break; + } + if (!isDataRow) { continue; } + var planoNormalized = NormalizeHeader(plano); + if (!string.IsNullOrWhiteSpace(plano) + && planoNormalized != NormalizeHeader("PLANO CONTRATO") + && planoNormalized != NormalizeHeader("TOTAL")) + { + lastPlanoContrato = plano.Trim(); + } + + var gbValue = TryDecimal(gb); + if (gbValue.HasValue) + { + lastGb = gbValue; + } + + var resolvedPlano = isDataRow + ? (string.IsNullOrWhiteSpace(plano) ? lastPlanoContrato : plano.Trim()) + : (string.IsNullOrWhiteSpace(plano) ? null : plano.Trim()); + + var resolvedGb = isDataRow + ? (gbValue ?? lastGb) + : gbValue; + + if (isDataRow && string.IsNullOrWhiteSpace(resolvedPlano)) + { + missingPlanoCount++; + } + + if (isDataRow && !resolvedGb.HasValue) + { + missingGbCount++; + } + var vivoTravelCell = ws.Cell(r, 8).GetString(); var vivoTravel = !string.IsNullOrWhiteSpace(vivoTravelCell) && vivoTravelCell.Contains("VIVO TRAVEL", StringComparison.OrdinalIgnoreCase); buffer.Add(new ResumoMacrophonyPlan { - PlanoContrato = string.IsNullOrWhiteSpace(plano) ? null : plano.Trim(), - Gb = TryDecimal(gb), + PlanoContrato = string.IsNullOrWhiteSpace(resolvedPlano) ? null : resolvedPlano, + Gb = resolvedGb, ValorIndividualComSvas = TryDecimal(valorInd), - FranquiaGb = TryDecimal(franquia), - TotalLinhas = TryNullableInt(totalLinhas), + FranquiaGb = franquiaValue, + TotalLinhas = totalLinhasValue, ValorTotal = TryDecimal(valorTotal), VivoTravel = vivoTravel, CreatedAt = now, @@ -1577,11 +1647,21 @@ namespace line_gestao_api.Controllers await _db.SaveChangesAsync(); } + if (missingPlanoCount > 0 || missingGbCount > 0) + { + throw new InvalidOperationException($"Import RESUMO/MACROPHONY: {missingPlanoCount} linhas sem PLANO CONTRATO e {missingGbCount} linhas sem GB."); + } + + if (totalRowIndex == null) + { + return; + } + var total = new ResumoMacrophonyTotal { - FranquiaGbTotal = TryDecimal(GetCellString(ws, totalRow, colFranquiaGb)), - TotalLinhasTotal = TryNullableInt(GetCellString(ws, totalRow, colTotalLinhas)), - ValorTotal = TryDecimal(GetCellString(ws, totalRow, colValorTotal)), + FranquiaGbTotal = TryDecimal(GetCellString(ws, totalRowIndex.Value, colFranquiaGb)), + TotalLinhasTotal = TryNullableInt(GetCellString(ws, totalRowIndex.Value, colTotalLinhas)), + ValorTotal = TryDecimal(GetCellString(ws, totalRowIndex.Value, colValorTotal)), CreatedAt = now, UpdatedAt = now }; @@ -1590,6 +1670,27 @@ namespace line_gestao_api.Controllers await _db.SaveChangesAsync(); } + private static int FindHeaderRowForMacrophonyPlans(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 hasGb = GetCol(map, "GB") > 0; + var hasTotalLinhas = GetColAny(map, "TOTAL DE LINHAS", "TOTAL LINHAS") > 0; + + if (hasPlano && hasGb && hasTotalLinhas) + { + return r; + } + } + + return 0; + } + private async Task ImportResumoTabela2(IXLWorksheet ws, DateTime now) { const int headerRow = 5;