Compare commits
No commits in common. "8cb0b72474034bd6c5615094b3e0367df1306b42" and "02acc181a53db8f64c2e2efc4f0e63f82e080ea6" have entirely different histories.
8cb0b72474
...
02acc181a5
|
|
@ -2,7 +2,6 @@
|
||||||
using line_gestao_api.Data;
|
using line_gestao_api.Data;
|
||||||
using line_gestao_api.Dtos;
|
using line_gestao_api.Dtos;
|
||||||
using line_gestao_api.Models;
|
using line_gestao_api.Models;
|
||||||
using line_gestao_api.Services;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
@ -21,12 +20,10 @@ namespace line_gestao_api.Controllers
|
||||||
public class LinesController : ControllerBase
|
public class LinesController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly AppDbContext _db;
|
private readonly AppDbContext _db;
|
||||||
private readonly ParcelamentosImportService _parcelamentosImportService;
|
|
||||||
|
|
||||||
public LinesController(AppDbContext db, ParcelamentosImportService parcelamentosImportService)
|
public LinesController(AppDbContext db)
|
||||||
{
|
{
|
||||||
_db = db;
|
_db = db;
|
||||||
_parcelamentosImportService = parcelamentosImportService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ImportExcelForm
|
public class ImportExcelForm
|
||||||
|
|
@ -649,18 +646,8 @@ namespace line_gestao_api.Controllers
|
||||||
// =========================
|
// =========================
|
||||||
await ImportControleRecebidosFromWorkbook(wb);
|
await ImportControleRecebidosFromWorkbook(wb);
|
||||||
|
|
||||||
// =========================
|
|
||||||
// ✅ IMPORTA RESUMO
|
|
||||||
// =========================
|
|
||||||
await ImportResumoFromWorkbook(wb);
|
|
||||||
|
|
||||||
// =========================
|
|
||||||
// ✅ IMPORTA PARCELAMENTOS
|
|
||||||
// =========================
|
|
||||||
var parcelamentosSummary = await _parcelamentosImportService.ImportFromWorkbookAsync(wb, replaceAll: true);
|
|
||||||
|
|
||||||
await tx.CommitAsync();
|
await tx.CommitAsync();
|
||||||
return Ok(new ImportResultDto { Imported = imported, Parcelamentos = parcelamentosSummary });
|
return Ok(new ImportResultDto { Imported = imported });
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
@ -1487,398 +1474,6 @@ namespace line_gestao_api.Controllers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==========================================================
|
|
||||||
// ✅ IMPORTAÇÃO DA ABA RESUMO
|
|
||||||
// ==========================================================
|
|
||||||
private async Task ImportResumoFromWorkbook(XLWorkbook wb)
|
|
||||||
{
|
|
||||||
var ws = wb.Worksheets.FirstOrDefault(w => NormalizeHeader(w.Name) == NormalizeHeader("RESUMO"));
|
|
||||||
if (ws == null) return;
|
|
||||||
|
|
||||||
await _db.ResumoMacrophonyPlans.ExecuteDeleteAsync();
|
|
||||||
await _db.ResumoMacrophonyTotals.ExecuteDeleteAsync();
|
|
||||||
await _db.ResumoVivoLineResumos.ExecuteDeleteAsync();
|
|
||||||
await _db.ResumoVivoLineTotals.ExecuteDeleteAsync();
|
|
||||||
await _db.ResumoClienteEspeciais.ExecuteDeleteAsync();
|
|
||||||
await _db.ResumoPlanoContratoResumos.ExecuteDeleteAsync();
|
|
||||||
await _db.ResumoPlanoContratoTotals.ExecuteDeleteAsync();
|
|
||||||
await _db.ResumoLineTotais.ExecuteDeleteAsync();
|
|
||||||
await _db.ResumoReservaLines.ExecuteDeleteAsync();
|
|
||||||
await _db.ResumoReservaTotals.ExecuteDeleteAsync();
|
|
||||||
|
|
||||||
var now = DateTime.UtcNow;
|
|
||||||
|
|
||||||
await ImportResumoTabela1(ws, now);
|
|
||||||
await ImportResumoTabela2(ws, now);
|
|
||||||
await ImportResumoTabela3(ws, now);
|
|
||||||
await ImportResumoTabela4(ws, now);
|
|
||||||
await ImportResumoTabela5(ws, now);
|
|
||||||
await ImportResumoTabela6(ws, now);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 map = BuildHeaderMap(ws.Row(headerRow));
|
|
||||||
var colPlano = GetCol(map, "PLANO CONTRATO");
|
|
||||||
var colGb = GetCol(map, "GB");
|
|
||||||
var colValorIndividual = GetColAny(map, "VALOR INDIVIDUAL C/ SVAs", "VALOR INDIVIDUAL C/ SVAS", "VALOR INDIVIDUAL");
|
|
||||||
var colFranquiaGb = GetColAny(map, "FRANQUIA GB", "FRAQUIA GB");
|
|
||||||
var colTotalLinhas = GetColAny(map, "TOTAL DE LINHAS", "TOTAL LINHAS");
|
|
||||||
var colValorTotal = GetCol(map, "VALOR TOTAL");
|
|
||||||
|
|
||||||
var buffer = new List<ResumoMacrophonyPlan>(200);
|
|
||||||
|
|
||||||
for (int r = headerRow + 1; r <= lastRow; r++)
|
|
||||||
{
|
|
||||||
var plano = GetCellString(ws, r, colPlano);
|
|
||||||
var gb = GetCellString(ws, r, colGb);
|
|
||||||
var valorInd = GetCellString(ws, r, colValorIndividual);
|
|
||||||
var franquia = GetCellString(ws, r, colFranquiaGb);
|
|
||||||
var totalLinhas = GetCellString(ws, r, colTotalLinhas);
|
|
||||||
var valorTotal = GetCellString(ws, r, colValorTotal);
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(plano)
|
|
||||||
&& string.IsNullOrWhiteSpace(gb)
|
|
||||||
&& string.IsNullOrWhiteSpace(valorInd)
|
|
||||||
&& string.IsNullOrWhiteSpace(franquia)
|
|
||||||
&& string.IsNullOrWhiteSpace(totalLinhas)
|
|
||||||
&& string.IsNullOrWhiteSpace(valorTotal))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
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),
|
|
||||||
ValorIndividualComSvas = TryDecimal(valorInd),
|
|
||||||
FranquiaGb = TryDecimal(franquia),
|
|
||||||
TotalLinhas = TryNullableInt(totalLinhas),
|
|
||||||
ValorTotal = TryDecimal(valorTotal),
|
|
||||||
VivoTravel = vivoTravel,
|
|
||||||
CreatedAt = now,
|
|
||||||
UpdatedAt = now
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer.Count > 0)
|
|
||||||
{
|
|
||||||
await _db.ResumoMacrophonyPlans.AddRangeAsync(buffer);
|
|
||||||
await _db.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
var total = new ResumoMacrophonyTotal
|
|
||||||
{
|
|
||||||
FranquiaGbTotal = TryDecimal(GetCellString(ws, totalRow, colFranquiaGb)),
|
|
||||||
TotalLinhasTotal = TryNullableInt(GetCellString(ws, totalRow, colTotalLinhas)),
|
|
||||||
ValorTotal = TryDecimal(GetCellString(ws, totalRow, colValorTotal)),
|
|
||||||
CreatedAt = now,
|
|
||||||
UpdatedAt = now
|
|
||||||
};
|
|
||||||
|
|
||||||
await _db.ResumoMacrophonyTotals.AddAsync(total);
|
|
||||||
await _db.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ImportResumoTabela2(IXLWorksheet ws, DateTime now)
|
|
||||||
{
|
|
||||||
const int headerRow = 5;
|
|
||||||
const int totalRow = 219;
|
|
||||||
var lastRow = Math.Min(totalRow - 1, ws.LastRowUsed()?.RowNumber() ?? totalRow - 1);
|
|
||||||
|
|
||||||
var map = BuildHeaderMap(ws.Row(headerRow));
|
|
||||||
var colSkil = GetCol(map, "SKIL");
|
|
||||||
var colCliente = GetCol(map, "CLIENTE");
|
|
||||||
var colQtdLinhas = GetColAny(map, "QTD DE LINHAS", "QTD. DE LINHAS", "QTD LINHAS");
|
|
||||||
var colFranquiaTotal = GetColAny(map, "FRANQUIA TOTAL", "FRAQUIA TOTAL");
|
|
||||||
var colValorContratoVivo = GetColAny(map, "VALOR CONTRATO VIVO", "VALOR DO CONTRATO VIVO");
|
|
||||||
var colFranquiaLine = GetColAny(map, "FRANQUIA LINE", "FRAQUIA LINE");
|
|
||||||
var colValorContratoLine = GetColAny(map, "VALOR CONTRATO LINE", "VALOR DO CONTRATO LINE");
|
|
||||||
var colLucro = GetCol(map, "LUCRO");
|
|
||||||
|
|
||||||
var buffer = new List<ResumoVivoLineResumo>(400);
|
|
||||||
|
|
||||||
for (int r = headerRow + 1; r <= lastRow; r++)
|
|
||||||
{
|
|
||||||
var skil = GetCellString(ws, r, colSkil);
|
|
||||||
var cliente = GetCellString(ws, r, colCliente);
|
|
||||||
var qtdLinhas = GetCellString(ws, r, colQtdLinhas);
|
|
||||||
var franquiaTotal = GetCellString(ws, r, colFranquiaTotal);
|
|
||||||
var valorContratoVivo = GetCellString(ws, r, colValorContratoVivo);
|
|
||||||
var franquiaLine = GetCellString(ws, r, colFranquiaLine);
|
|
||||||
var valorContratoLine = GetCellString(ws, r, colValorContratoLine);
|
|
||||||
var lucro = GetCellString(ws, r, colLucro);
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(skil)
|
|
||||||
&& string.IsNullOrWhiteSpace(cliente)
|
|
||||||
&& string.IsNullOrWhiteSpace(qtdLinhas)
|
|
||||||
&& string.IsNullOrWhiteSpace(franquiaTotal)
|
|
||||||
&& string.IsNullOrWhiteSpace(valorContratoVivo)
|
|
||||||
&& string.IsNullOrWhiteSpace(franquiaLine)
|
|
||||||
&& string.IsNullOrWhiteSpace(valorContratoLine)
|
|
||||||
&& string.IsNullOrWhiteSpace(lucro))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.Add(new ResumoVivoLineResumo
|
|
||||||
{
|
|
||||||
Skil = string.IsNullOrWhiteSpace(skil) ? null : skil.Trim(),
|
|
||||||
Cliente = string.IsNullOrWhiteSpace(cliente) ? null : cliente.Trim(),
|
|
||||||
QtdLinhas = TryNullableInt(qtdLinhas),
|
|
||||||
FranquiaTotal = TryDecimal(franquiaTotal),
|
|
||||||
ValorContratoVivo = TryDecimal(valorContratoVivo),
|
|
||||||
FranquiaLine = TryDecimal(franquiaLine),
|
|
||||||
ValorContratoLine = TryDecimal(valorContratoLine),
|
|
||||||
Lucro = TryDecimal(lucro),
|
|
||||||
CreatedAt = now,
|
|
||||||
UpdatedAt = now
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer.Count > 0)
|
|
||||||
{
|
|
||||||
await _db.ResumoVivoLineResumos.AddRangeAsync(buffer);
|
|
||||||
await _db.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
var total = new ResumoVivoLineTotal
|
|
||||||
{
|
|
||||||
QtdLinhasTotal = TryNullableInt(GetCellString(ws, totalRow, colQtdLinhas)),
|
|
||||||
FranquiaTotal = TryDecimal(GetCellString(ws, totalRow, colFranquiaTotal)),
|
|
||||||
ValorContratoVivo = TryDecimal(GetCellString(ws, totalRow, colValorContratoVivo)),
|
|
||||||
FranquiaLine = TryDecimal(GetCellString(ws, totalRow, colFranquiaLine)),
|
|
||||||
ValorContratoLine = TryDecimal(GetCellString(ws, totalRow, colValorContratoLine)),
|
|
||||||
Lucro = TryDecimal(GetCellString(ws, totalRow, colLucro)),
|
|
||||||
CreatedAt = now,
|
|
||||||
UpdatedAt = now
|
|
||||||
};
|
|
||||||
|
|
||||||
await _db.ResumoVivoLineTotals.AddAsync(total);
|
|
||||||
await _db.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ImportResumoTabela3(IXLWorksheet ws, DateTime now)
|
|
||||||
{
|
|
||||||
const int headerStartRow = 223;
|
|
||||||
const int headerEndRow = 225;
|
|
||||||
const int valuesRow = 227;
|
|
||||||
|
|
||||||
var headerColumns = new Dictionary<int, string>();
|
|
||||||
for (int row = headerStartRow; row <= headerEndRow; row++)
|
|
||||||
{
|
|
||||||
var rowData = ws.Row(row);
|
|
||||||
var lastCol = rowData.LastCellUsed()?.Address.ColumnNumber ?? 1;
|
|
||||||
for (int col = 1; col <= lastCol; col++)
|
|
||||||
{
|
|
||||||
var name = rowData.Cell(col).GetString();
|
|
||||||
if (string.IsNullOrWhiteSpace(name)) continue;
|
|
||||||
if (!headerColumns.ContainsKey(col))
|
|
||||||
{
|
|
||||||
headerColumns[col] = name.Trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (headerColumns.Count == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var buffer = new List<ResumoClienteEspecial>(headerColumns.Count);
|
|
||||||
foreach (var entry in headerColumns)
|
|
||||||
{
|
|
||||||
var valueStr = ws.Cell(valuesRow, entry.Key).GetString();
|
|
||||||
buffer.Add(new ResumoClienteEspecial
|
|
||||||
{
|
|
||||||
Nome = entry.Value,
|
|
||||||
Valor = TryDecimal(valueStr),
|
|
||||||
CreatedAt = now,
|
|
||||||
UpdatedAt = now
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
await _db.ResumoClienteEspeciais.AddRangeAsync(buffer);
|
|
||||||
await _db.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
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 map = BuildHeaderMap(ws.Row(headerRow));
|
|
||||||
var colPlano = GetCol(map, "PLANO CONTRATO");
|
|
||||||
var colGb = GetCol(map, "GB");
|
|
||||||
var colValorIndividual = GetColAny(map, "VALOR INDIVIDUAL C/ SVAs", "VALOR INDIVIDUAL C/ SVAS", "VALOR INDIVIDUAL");
|
|
||||||
var colFranquiaGb = GetColAny(map, "FRANQUIA GB", "FRAQUIA GB");
|
|
||||||
var colTotalLinhas = GetColAny(map, "TOTAL DE LINHAS", "TOTAL LINHAS");
|
|
||||||
var colValorTotal = GetCol(map, "VALOR TOTAL");
|
|
||||||
|
|
||||||
var buffer = new List<ResumoPlanoContratoResumo>(200);
|
|
||||||
|
|
||||||
for (int r = headerRow + 1; r <= lastRow; r++)
|
|
||||||
{
|
|
||||||
var plano = GetCellString(ws, r, colPlano);
|
|
||||||
var gb = GetCellString(ws, r, colGb);
|
|
||||||
var valorInd = GetCellString(ws, r, colValorIndividual);
|
|
||||||
var franquia = GetCellString(ws, r, colFranquiaGb);
|
|
||||||
var totalLinhas = GetCellString(ws, r, colTotalLinhas);
|
|
||||||
var valorTotal = GetCellString(ws, r, colValorTotal);
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(plano)
|
|
||||||
&& string.IsNullOrWhiteSpace(gb)
|
|
||||||
&& string.IsNullOrWhiteSpace(valorInd)
|
|
||||||
&& string.IsNullOrWhiteSpace(franquia)
|
|
||||||
&& string.IsNullOrWhiteSpace(totalLinhas)
|
|
||||||
&& string.IsNullOrWhiteSpace(valorTotal))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.Add(new ResumoPlanoContratoResumo
|
|
||||||
{
|
|
||||||
PlanoContrato = string.IsNullOrWhiteSpace(plano) ? null : plano.Trim(),
|
|
||||||
Gb = TryDecimal(gb),
|
|
||||||
ValorIndividualComSvas = TryDecimal(valorInd),
|
|
||||||
FranquiaGb = TryDecimal(franquia),
|
|
||||||
TotalLinhas = TryNullableInt(totalLinhas),
|
|
||||||
ValorTotal = TryDecimal(valorTotal),
|
|
||||||
CreatedAt = now,
|
|
||||||
UpdatedAt = now
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer.Count > 0)
|
|
||||||
{
|
|
||||||
await _db.ResumoPlanoContratoResumos.AddRangeAsync(buffer);
|
|
||||||
await _db.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
var total = new ResumoPlanoContratoTotal
|
|
||||||
{
|
|
||||||
ValorTotal = TryDecimal(ws.Cell(totalRow, 7).GetString()),
|
|
||||||
CreatedAt = now,
|
|
||||||
UpdatedAt = now
|
|
||||||
};
|
|
||||||
|
|
||||||
await _db.ResumoPlanoContratoTotals.AddAsync(total);
|
|
||||||
await _db.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ImportResumoTabela5(IXLWorksheet ws, DateTime now)
|
|
||||||
{
|
|
||||||
const int headerRow = 83;
|
|
||||||
var map = BuildHeaderMap(ws.Row(headerRow));
|
|
||||||
var colValorTotalLine = GetColAny(map, "VALOR TOTAL LINE", "VALOR TOTAL LINE R$", "VALOR TOTAL LINE R$");
|
|
||||||
var colLucroTotalLine = GetColAny(map, "LUCRO TOTAL LINE", "LUCRO TOTAL LINE R$", "LUCRO TOTAL LINE R$");
|
|
||||||
var colQtdLinhas = GetColAny(map, "QTD. LINHAS", "QTD LINHAS", "QTD. DE LINHAS");
|
|
||||||
|
|
||||||
var buffer = new List<ResumoLineTotais>(3);
|
|
||||||
for (int r = headerRow + 1; r <= headerRow + 3; r++)
|
|
||||||
{
|
|
||||||
var tipo = ws.Cell(r, 2).GetString();
|
|
||||||
if (string.IsNullOrWhiteSpace(tipo))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.Add(new ResumoLineTotais
|
|
||||||
{
|
|
||||||
Tipo = tipo.Trim(),
|
|
||||||
ValorTotalLine = TryDecimal(GetCellString(ws, r, colValorTotalLine)),
|
|
||||||
LucroTotalLine = TryDecimal(GetCellString(ws, r, colLucroTotalLine)),
|
|
||||||
QtdLinhas = TryNullableInt(GetCellString(ws, r, colQtdLinhas)),
|
|
||||||
CreatedAt = now,
|
|
||||||
UpdatedAt = now
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer.Count > 0)
|
|
||||||
{
|
|
||||||
await _db.ResumoLineTotais.AddRangeAsync(buffer);
|
|
||||||
await _db.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ImportResumoTabela6(IXLWorksheet ws, DateTime now)
|
|
||||||
{
|
|
||||||
const int headerRow = 91;
|
|
||||||
const int totalRow = 139;
|
|
||||||
var lastRow = Math.Min(totalRow - 1, ws.LastRowUsed()?.RowNumber() ?? totalRow - 1);
|
|
||||||
|
|
||||||
var map = BuildHeaderMap(ws.Row(headerRow));
|
|
||||||
var colDdd = GetCol(map, "DDD");
|
|
||||||
var colFranquiaGb = GetColAny(map, "FRANQUIA GB", "FRAQUIA GB");
|
|
||||||
var colQtdLinhas = GetColAny(map, "QTD. DE LINHAS", "QTD DE LINHAS", "QTD. LINHAS");
|
|
||||||
var colTotal = GetCol(map, "TOTAL");
|
|
||||||
|
|
||||||
var buffer = new List<ResumoReservaLine>(200);
|
|
||||||
decimal? lastTotal = null;
|
|
||||||
|
|
||||||
for (int r = headerRow + 1; r <= lastRow; r++)
|
|
||||||
{
|
|
||||||
var ddd = GetCellString(ws, r, colDdd);
|
|
||||||
var franquia = GetCellString(ws, r, colFranquiaGb);
|
|
||||||
var qtdLinhas = GetCellString(ws, r, colQtdLinhas);
|
|
||||||
var total = GetCellString(ws, r, colTotal);
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(ddd)
|
|
||||||
&& string.IsNullOrWhiteSpace(franquia)
|
|
||||||
&& string.IsNullOrWhiteSpace(qtdLinhas)
|
|
||||||
&& string.IsNullOrWhiteSpace(total))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var totalValue = TryDecimal(total);
|
|
||||||
if (!totalValue.HasValue && lastTotal.HasValue)
|
|
||||||
{
|
|
||||||
totalValue = lastTotal;
|
|
||||||
}
|
|
||||||
else if (totalValue.HasValue)
|
|
||||||
{
|
|
||||||
lastTotal = totalValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.Add(new ResumoReservaLine
|
|
||||||
{
|
|
||||||
Ddd = string.IsNullOrWhiteSpace(ddd) ? null : ddd.Trim(),
|
|
||||||
FranquiaGb = TryDecimal(franquia),
|
|
||||||
QtdLinhas = TryNullableInt(qtdLinhas),
|
|
||||||
Total = totalValue,
|
|
||||||
CreatedAt = now,
|
|
||||||
UpdatedAt = now
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer.Count > 0)
|
|
||||||
{
|
|
||||||
await _db.ResumoReservaLines.AddRangeAsync(buffer);
|
|
||||||
await _db.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
var totalEntity = new ResumoReservaTotal
|
|
||||||
{
|
|
||||||
QtdLinhasTotal = TryNullableInt(GetCellString(ws, totalRow, colQtdLinhas)),
|
|
||||||
Total = TryDecimal(GetCellString(ws, totalRow, colTotal)),
|
|
||||||
CreatedAt = now,
|
|
||||||
UpdatedAt = now
|
|
||||||
};
|
|
||||||
|
|
||||||
await _db.ResumoReservaTotals.AddAsync(totalEntity);
|
|
||||||
await _db.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ImportControleRecebidosSheet(IXLWorksheet ws, int year)
|
private async Task ImportControleRecebidosSheet(IXLWorksheet ws, int year)
|
||||||
{
|
{
|
||||||
var buffer = new List<ControleRecebidoLine>(500);
|
var buffer = new List<ControleRecebidoLine>(500);
|
||||||
|
|
|
||||||
|
|
@ -24,45 +24,24 @@ public class NotificationsController : ControllerBase
|
||||||
[HttpGet("/notifications")]
|
[HttpGet("/notifications")]
|
||||||
public async Task<ActionResult<List<NotificationDto>>> GetNotifications()
|
public async Task<ActionResult<List<NotificationDto>>> GetNotifications()
|
||||||
{
|
{
|
||||||
var items = await (
|
var query = _db.Notifications.AsNoTracking();
|
||||||
from notification in _db.Notifications.AsNoTracking()
|
|
||||||
join vigencia in _db.VigenciaLines.AsNoTracking()
|
var items = await query
|
||||||
on notification.VigenciaLineId equals vigencia.Id into vigencias
|
.OrderByDescending(n => n.Data)
|
||||||
from vigencia in vigencias.DefaultIfEmpty()
|
.Select(n => new NotificationDto
|
||||||
let vigenciaByLinha = _db.VigenciaLines.AsNoTracking()
|
|
||||||
.Where(v => notification.Linha != null && v.Linha == notification.Linha)
|
|
||||||
.OrderByDescending(v => v.UpdatedAt)
|
|
||||||
.FirstOrDefault()
|
|
||||||
orderby notification.Data descending
|
|
||||||
select new NotificationDto
|
|
||||||
{
|
{
|
||||||
Id = notification.Id,
|
Id = n.Id,
|
||||||
Tipo = notification.Tipo,
|
Tipo = n.Tipo,
|
||||||
Titulo = notification.Titulo,
|
Titulo = n.Titulo,
|
||||||
Mensagem = notification.Mensagem,
|
Mensagem = n.Mensagem,
|
||||||
Data = notification.Data,
|
Data = n.Data,
|
||||||
ReferenciaData = notification.ReferenciaData,
|
ReferenciaData = n.ReferenciaData,
|
||||||
DiasParaVencer = notification.DiasParaVencer,
|
DiasParaVencer = n.DiasParaVencer,
|
||||||
Lida = notification.Lida,
|
Lida = n.Lida,
|
||||||
LidaEm = notification.LidaEm,
|
LidaEm = n.LidaEm,
|
||||||
VigenciaLineId = notification.VigenciaLineId,
|
VigenciaLineId = n.VigenciaLineId,
|
||||||
Cliente = notification.Cliente
|
Cliente = n.Cliente,
|
||||||
?? (vigencia != null ? vigencia.Cliente : null)
|
Linha = n.Linha
|
||||||
?? (vigenciaByLinha != null ? vigenciaByLinha.Cliente : null),
|
|
||||||
Linha = notification.Linha
|
|
||||||
?? (vigencia != null ? vigencia.Linha : null)
|
|
||||||
?? (vigenciaByLinha != null ? vigenciaByLinha.Linha : null),
|
|
||||||
Conta = (vigencia != null ? vigencia.Conta : null)
|
|
||||||
?? (vigenciaByLinha != null ? vigenciaByLinha.Conta : null),
|
|
||||||
Usuario = notification.Usuario
|
|
||||||
?? (vigencia != null ? vigencia.Usuario : null)
|
|
||||||
?? (vigenciaByLinha != null ? vigenciaByLinha.Usuario : null),
|
|
||||||
PlanoContrato = (vigencia != null ? vigencia.PlanoContrato : null)
|
|
||||||
?? (vigenciaByLinha != null ? vigenciaByLinha.PlanoContrato : null),
|
|
||||||
DtEfetivacaoServico = (vigencia != null ? vigencia.DtEfetivacaoServico : null)
|
|
||||||
?? (vigenciaByLinha != null ? vigenciaByLinha.DtEfetivacaoServico : null),
|
|
||||||
DtTerminoFidelizacao = (vigencia != null ? vigencia.DtTerminoFidelizacao : null)
|
|
||||||
?? (vigenciaByLinha != null ? vigenciaByLinha.DtTerminoFidelizacao : null)
|
|
||||||
})
|
})
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
|
|
@ -133,30 +112,15 @@ public class NotificationsController : ControllerBase
|
||||||
join vigencia in _db.VigenciaLines.AsNoTracking()
|
join vigencia in _db.VigenciaLines.AsNoTracking()
|
||||||
on notification.VigenciaLineId equals vigencia.Id into vigencias
|
on notification.VigenciaLineId equals vigencia.Id into vigencias
|
||||||
from vigencia in vigencias.DefaultIfEmpty()
|
from vigencia in vigencias.DefaultIfEmpty()
|
||||||
let vigenciaByLinha = _db.VigenciaLines.AsNoTracking()
|
|
||||||
.Where(v => notification.Linha != null && v.Linha == notification.Linha)
|
|
||||||
.OrderByDescending(v => v.UpdatedAt)
|
|
||||||
.FirstOrDefault()
|
|
||||||
orderby notification.ReferenciaData descending, notification.Data descending
|
orderby notification.ReferenciaData descending, notification.Data descending
|
||||||
select new NotificationExportRow(
|
select new NotificationExportRow(
|
||||||
(vigencia != null ? vigencia.Conta : null)
|
vigencia.Conta,
|
||||||
?? (vigenciaByLinha != null ? vigenciaByLinha.Conta : null),
|
notification.Linha ?? vigencia.Linha,
|
||||||
notification.Linha
|
notification.Cliente ?? vigencia.Cliente,
|
||||||
?? (vigencia != null ? vigencia.Linha : null)
|
notification.Usuario ?? vigencia.Usuario,
|
||||||
?? (vigenciaByLinha != null ? vigenciaByLinha.Linha : null),
|
vigencia.PlanoContrato,
|
||||||
notification.Cliente
|
vigencia.DtEfetivacaoServico,
|
||||||
?? (vigencia != null ? vigencia.Cliente : null)
|
notification.ReferenciaData ?? vigencia.DtTerminoFidelizacao,
|
||||||
?? (vigenciaByLinha != null ? vigenciaByLinha.Cliente : null),
|
|
||||||
notification.Usuario
|
|
||||||
?? (vigencia != null ? vigencia.Usuario : null)
|
|
||||||
?? (vigenciaByLinha != null ? vigenciaByLinha.Usuario : null),
|
|
||||||
(vigencia != null ? vigencia.PlanoContrato : null)
|
|
||||||
?? (vigenciaByLinha != null ? vigenciaByLinha.PlanoContrato : null),
|
|
||||||
(vigencia != null ? vigencia.DtEfetivacaoServico : null)
|
|
||||||
?? (vigenciaByLinha != null ? vigenciaByLinha.DtEfetivacaoServico : null),
|
|
||||||
notification.ReferenciaData
|
|
||||||
?? (vigencia != null ? vigencia.DtTerminoFidelizacao : null)
|
|
||||||
?? (vigenciaByLinha != null ? vigenciaByLinha.DtTerminoFidelizacao : null),
|
|
||||||
notification.Tipo))
|
notification.Tipo))
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
|
|
@ -192,12 +156,12 @@ public class NotificationsController : ControllerBase
|
||||||
var rowIndex = i + 2;
|
var rowIndex = i + 2;
|
||||||
worksheet.Cell(rowIndex, 1).Value = row.Conta ?? string.Empty;
|
worksheet.Cell(rowIndex, 1).Value = row.Conta ?? string.Empty;
|
||||||
worksheet.Cell(rowIndex, 2).Value = row.Linha ?? string.Empty;
|
worksheet.Cell(rowIndex, 2).Value = row.Linha ?? string.Empty;
|
||||||
worksheet.Cell(rowIndex, 3).Value = (row.Cliente ?? string.Empty).ToUpperInvariant();
|
worksheet.Cell(rowIndex, 3).Value = row.Cliente ?? string.Empty;
|
||||||
worksheet.Cell(rowIndex, 4).Value = (row.Usuario ?? string.Empty).ToUpperInvariant();
|
worksheet.Cell(rowIndex, 4).Value = row.Usuario ?? string.Empty;
|
||||||
worksheet.Cell(rowIndex, 5).Value = row.PlanoContrato ?? string.Empty;
|
worksheet.Cell(rowIndex, 5).Value = row.PlanoContrato ?? string.Empty;
|
||||||
worksheet.Cell(rowIndex, 6).Value = row.DataInicio;
|
worksheet.Cell(rowIndex, 6).Value = row.DataInicio;
|
||||||
worksheet.Cell(rowIndex, 7).Value = row.DataReferencia;
|
worksheet.Cell(rowIndex, 7).Value = row.DataReferencia;
|
||||||
worksheet.Cell(rowIndex, 8).Value = row.Tipo.ToUpperInvariant();
|
worksheet.Cell(rowIndex, 8).Value = row.Tipo;
|
||||||
}
|
}
|
||||||
|
|
||||||
worksheet.Column(1).Width = 18;
|
worksheet.Column(1).Width = 18;
|
||||||
|
|
|
||||||
|
|
@ -1,128 +0,0 @@
|
||||||
using line_gestao_api.Data;
|
|
||||||
using line_gestao_api.Dtos;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace line_gestao_api.Controllers;
|
|
||||||
|
|
||||||
[ApiController]
|
|
||||||
[Route("api/parcelamentos")]
|
|
||||||
[Authorize]
|
|
||||||
public class ParcelamentosController : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly AppDbContext _db;
|
|
||||||
|
|
||||||
public ParcelamentosController(AppDbContext db)
|
|
||||||
{
|
|
||||||
_db = db;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet]
|
|
||||||
public async Task<ActionResult<PagedResult<ParcelamentoListDto>>> GetAll(
|
|
||||||
[FromQuery] int? anoRef,
|
|
||||||
[FromQuery] string? linha,
|
|
||||||
[FromQuery] string? cliente,
|
|
||||||
[FromQuery] int? competenciaAno,
|
|
||||||
[FromQuery] int? competenciaMes,
|
|
||||||
[FromQuery] int page = 1,
|
|
||||||
[FromQuery] int pageSize = 20)
|
|
||||||
{
|
|
||||||
page = page < 1 ? 1 : page;
|
|
||||||
pageSize = pageSize < 1 ? 20 : pageSize;
|
|
||||||
|
|
||||||
var query = _db.ParcelamentoLines.AsNoTracking();
|
|
||||||
|
|
||||||
if (anoRef.HasValue)
|
|
||||||
{
|
|
||||||
query = query.Where(x => x.AnoRef == anoRef.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(linha))
|
|
||||||
{
|
|
||||||
var l = linha.Trim();
|
|
||||||
query = query.Where(x => x.Linha == l);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(cliente))
|
|
||||||
{
|
|
||||||
var c = cliente.Trim();
|
|
||||||
query = query.Where(x => x.Cliente != null && EF.Functions.ILike(x.Cliente, $"%{c}%"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (competenciaAno.HasValue && competenciaMes.HasValue)
|
|
||||||
{
|
|
||||||
var competencia = new DateOnly(competenciaAno.Value, competenciaMes.Value, 1);
|
|
||||||
query = query.Where(x => x.MonthValues.Any(m => m.Competencia == competencia));
|
|
||||||
}
|
|
||||||
|
|
||||||
var total = await query.CountAsync();
|
|
||||||
|
|
||||||
var items = await query
|
|
||||||
.OrderBy(x => x.Item)
|
|
||||||
.Skip((page - 1) * pageSize)
|
|
||||||
.Take(pageSize)
|
|
||||||
.Select(x => new ParcelamentoListDto
|
|
||||||
{
|
|
||||||
Id = x.Id,
|
|
||||||
AnoRef = x.AnoRef,
|
|
||||||
Item = x.Item,
|
|
||||||
Linha = x.Linha,
|
|
||||||
Cliente = x.Cliente,
|
|
||||||
QtParcelas = x.QtParcelas,
|
|
||||||
ParcelaAtual = x.ParcelaAtual,
|
|
||||||
TotalParcelas = x.TotalParcelas,
|
|
||||||
ValorCheio = x.ValorCheio,
|
|
||||||
Desconto = x.Desconto,
|
|
||||||
ValorComDesconto = x.ValorComDesconto
|
|
||||||
})
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
return Ok(new PagedResult<ParcelamentoListDto>
|
|
||||||
{
|
|
||||||
Page = page,
|
|
||||||
PageSize = pageSize,
|
|
||||||
Total = total,
|
|
||||||
Items = items
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{id:guid}")]
|
|
||||||
public async Task<ActionResult<ParcelamentoDetailDto>> GetById(Guid id)
|
|
||||||
{
|
|
||||||
var item = await _db.ParcelamentoLines
|
|
||||||
.AsNoTracking()
|
|
||||||
.Include(x => x.MonthValues)
|
|
||||||
.FirstOrDefaultAsync(x => x.Id == id);
|
|
||||||
|
|
||||||
if (item == null)
|
|
||||||
{
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
var dto = new ParcelamentoDetailDto
|
|
||||||
{
|
|
||||||
Id = item.Id,
|
|
||||||
AnoRef = item.AnoRef,
|
|
||||||
Item = item.Item,
|
|
||||||
Linha = item.Linha,
|
|
||||||
Cliente = item.Cliente,
|
|
||||||
QtParcelas = item.QtParcelas,
|
|
||||||
ParcelaAtual = item.ParcelaAtual,
|
|
||||||
TotalParcelas = item.TotalParcelas,
|
|
||||||
ValorCheio = item.ValorCheio,
|
|
||||||
Desconto = item.Desconto,
|
|
||||||
ValorComDesconto = item.ValorComDesconto,
|
|
||||||
MonthValues = item.MonthValues
|
|
||||||
.OrderBy(x => x.Competencia)
|
|
||||||
.Select(x => new ParcelamentoMonthDto
|
|
||||||
{
|
|
||||||
Competencia = x.Competencia,
|
|
||||||
Valor = x.Valor
|
|
||||||
})
|
|
||||||
.ToList()
|
|
||||||
};
|
|
||||||
|
|
||||||
return Ok(dto);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,129 +0,0 @@
|
||||||
using line_gestao_api.Data;
|
|
||||||
using line_gestao_api.Dtos;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace line_gestao_api.Controllers;
|
|
||||||
|
|
||||||
[ApiController]
|
|
||||||
[Route("api/resumo")]
|
|
||||||
[Authorize]
|
|
||||||
public class ResumoController : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly AppDbContext _db;
|
|
||||||
|
|
||||||
public ResumoController(AppDbContext db)
|
|
||||||
{
|
|
||||||
_db = db;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet]
|
|
||||||
public async Task<ActionResult<ResumoResponseDto>> GetResumo()
|
|
||||||
{
|
|
||||||
var response = new ResumoResponseDto
|
|
||||||
{
|
|
||||||
MacrophonyPlans = await _db.ResumoMacrophonyPlans.AsNoTracking()
|
|
||||||
.OrderBy(x => x.PlanoContrato)
|
|
||||||
.Select(x => new ResumoMacrophonyPlanDto
|
|
||||||
{
|
|
||||||
PlanoContrato = x.PlanoContrato,
|
|
||||||
Gb = x.Gb,
|
|
||||||
ValorIndividualComSvas = x.ValorIndividualComSvas,
|
|
||||||
FranquiaGb = x.FranquiaGb,
|
|
||||||
TotalLinhas = x.TotalLinhas,
|
|
||||||
ValorTotal = x.ValorTotal,
|
|
||||||
VivoTravel = x.VivoTravel
|
|
||||||
})
|
|
||||||
.ToListAsync(),
|
|
||||||
MacrophonyTotals = await _db.ResumoMacrophonyTotals.AsNoTracking()
|
|
||||||
.Select(x => new ResumoMacrophonyTotalDto
|
|
||||||
{
|
|
||||||
FranquiaGbTotal = x.FranquiaGbTotal,
|
|
||||||
TotalLinhasTotal = x.TotalLinhasTotal,
|
|
||||||
ValorTotal = x.ValorTotal
|
|
||||||
})
|
|
||||||
.FirstOrDefaultAsync(),
|
|
||||||
VivoLineResumos = await _db.ResumoVivoLineResumos.AsNoTracking()
|
|
||||||
.OrderBy(x => x.Cliente)
|
|
||||||
.Select(x => new ResumoVivoLineResumoDto
|
|
||||||
{
|
|
||||||
Skil = x.Skil,
|
|
||||||
Cliente = x.Cliente,
|
|
||||||
QtdLinhas = x.QtdLinhas,
|
|
||||||
FranquiaTotal = x.FranquiaTotal,
|
|
||||||
ValorContratoVivo = x.ValorContratoVivo,
|
|
||||||
FranquiaLine = x.FranquiaLine,
|
|
||||||
ValorContratoLine = x.ValorContratoLine,
|
|
||||||
Lucro = x.Lucro
|
|
||||||
})
|
|
||||||
.ToListAsync(),
|
|
||||||
VivoLineTotals = await _db.ResumoVivoLineTotals.AsNoTracking()
|
|
||||||
.Select(x => new ResumoVivoLineTotalDto
|
|
||||||
{
|
|
||||||
QtdLinhasTotal = x.QtdLinhasTotal,
|
|
||||||
FranquiaTotal = x.FranquiaTotal,
|
|
||||||
ValorContratoVivo = x.ValorContratoVivo,
|
|
||||||
FranquiaLine = x.FranquiaLine,
|
|
||||||
ValorContratoLine = x.ValorContratoLine,
|
|
||||||
Lucro = x.Lucro
|
|
||||||
})
|
|
||||||
.FirstOrDefaultAsync(),
|
|
||||||
ClienteEspeciais = await _db.ResumoClienteEspeciais.AsNoTracking()
|
|
||||||
.OrderBy(x => x.Nome)
|
|
||||||
.Select(x => new ResumoClienteEspecialDto
|
|
||||||
{
|
|
||||||
Nome = x.Nome,
|
|
||||||
Valor = x.Valor
|
|
||||||
})
|
|
||||||
.ToListAsync(),
|
|
||||||
PlanoContratoResumos = await _db.ResumoPlanoContratoResumos.AsNoTracking()
|
|
||||||
.OrderBy(x => x.PlanoContrato)
|
|
||||||
.Select(x => new ResumoPlanoContratoResumoDto
|
|
||||||
{
|
|
||||||
PlanoContrato = x.PlanoContrato,
|
|
||||||
Gb = x.Gb,
|
|
||||||
ValorIndividualComSvas = x.ValorIndividualComSvas,
|
|
||||||
FranquiaGb = x.FranquiaGb,
|
|
||||||
TotalLinhas = x.TotalLinhas,
|
|
||||||
ValorTotal = x.ValorTotal
|
|
||||||
})
|
|
||||||
.ToListAsync(),
|
|
||||||
PlanoContratoTotal = await _db.ResumoPlanoContratoTotals.AsNoTracking()
|
|
||||||
.Select(x => new ResumoPlanoContratoTotalDto
|
|
||||||
{
|
|
||||||
ValorTotal = x.ValorTotal
|
|
||||||
})
|
|
||||||
.FirstOrDefaultAsync(),
|
|
||||||
LineTotais = await _db.ResumoLineTotais.AsNoTracking()
|
|
||||||
.OrderBy(x => x.Tipo)
|
|
||||||
.Select(x => new ResumoLineTotaisDto
|
|
||||||
{
|
|
||||||
Tipo = x.Tipo,
|
|
||||||
ValorTotalLine = x.ValorTotalLine,
|
|
||||||
LucroTotalLine = x.LucroTotalLine,
|
|
||||||
QtdLinhas = x.QtdLinhas
|
|
||||||
})
|
|
||||||
.ToListAsync(),
|
|
||||||
ReservaLines = await _db.ResumoReservaLines.AsNoTracking()
|
|
||||||
.OrderBy(x => x.Ddd)
|
|
||||||
.Select(x => new ResumoReservaLineDto
|
|
||||||
{
|
|
||||||
Ddd = x.Ddd,
|
|
||||||
FranquiaGb = x.FranquiaGb,
|
|
||||||
QtdLinhas = x.QtdLinhas,
|
|
||||||
Total = x.Total
|
|
||||||
})
|
|
||||||
.ToListAsync(),
|
|
||||||
ReservaTotal = await _db.ResumoReservaTotals.AsNoTracking()
|
|
||||||
.Select(x => new ResumoReservaTotalDto
|
|
||||||
{
|
|
||||||
QtdLinhasTotal = x.QtdLinhasTotal,
|
|
||||||
Total = x.Total
|
|
||||||
})
|
|
||||||
.FirstOrDefaultAsync()
|
|
||||||
};
|
|
||||||
|
|
||||||
return Ok(response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -44,22 +44,6 @@ public class AppDbContext : IdentityDbContext<ApplicationUser, IdentityRole<Guid
|
||||||
// ✅ tabela NOTIFICAÇÕES
|
// ✅ tabela NOTIFICAÇÕES
|
||||||
public DbSet<Notification> Notifications => Set<Notification>();
|
public DbSet<Notification> Notifications => Set<Notification>();
|
||||||
|
|
||||||
// ✅ tabela RESUMO
|
|
||||||
public DbSet<ResumoMacrophonyPlan> ResumoMacrophonyPlans => Set<ResumoMacrophonyPlan>();
|
|
||||||
public DbSet<ResumoMacrophonyTotal> ResumoMacrophonyTotals => Set<ResumoMacrophonyTotal>();
|
|
||||||
public DbSet<ResumoVivoLineResumo> ResumoVivoLineResumos => Set<ResumoVivoLineResumo>();
|
|
||||||
public DbSet<ResumoVivoLineTotal> ResumoVivoLineTotals => Set<ResumoVivoLineTotal>();
|
|
||||||
public DbSet<ResumoClienteEspecial> ResumoClienteEspeciais => Set<ResumoClienteEspecial>();
|
|
||||||
public DbSet<ResumoPlanoContratoResumo> ResumoPlanoContratoResumos => Set<ResumoPlanoContratoResumo>();
|
|
||||||
public DbSet<ResumoPlanoContratoTotal> ResumoPlanoContratoTotals => Set<ResumoPlanoContratoTotal>();
|
|
||||||
public DbSet<ResumoLineTotais> ResumoLineTotais => Set<ResumoLineTotais>();
|
|
||||||
public DbSet<ResumoReservaLine> ResumoReservaLines => Set<ResumoReservaLine>();
|
|
||||||
public DbSet<ResumoReservaTotal> ResumoReservaTotals => Set<ResumoReservaTotal>();
|
|
||||||
|
|
||||||
// ✅ tabela PARCELAMENTOS
|
|
||||||
public DbSet<ParcelamentoLine> ParcelamentoLines => Set<ParcelamentoLine>();
|
|
||||||
public DbSet<ParcelamentoMonthValue> ParcelamentoMonthValues => Set<ParcelamentoMonthValue>();
|
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
base.OnModelCreating(modelBuilder);
|
base.OnModelCreating(modelBuilder);
|
||||||
|
|
@ -219,35 +203,6 @@ public class AppDbContext : IdentityDbContext<ApplicationUser, IdentityRole<Guid
|
||||||
.OnDelete(DeleteBehavior.Restrict);
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
});
|
});
|
||||||
|
|
||||||
// =========================
|
|
||||||
// ✅ PARCELAMENTOS
|
|
||||||
// =========================
|
|
||||||
modelBuilder.Entity<ParcelamentoLine>(e =>
|
|
||||||
{
|
|
||||||
e.Property(x => x.Linha).HasMaxLength(32);
|
|
||||||
e.Property(x => x.Cliente).HasMaxLength(120);
|
|
||||||
e.Property(x => x.QtParcelas).HasMaxLength(32);
|
|
||||||
e.Property(x => x.ValorCheio).HasPrecision(18, 2);
|
|
||||||
e.Property(x => x.Desconto).HasPrecision(18, 2);
|
|
||||||
e.Property(x => x.ValorComDesconto).HasPrecision(18, 2);
|
|
||||||
|
|
||||||
e.HasIndex(x => new { x.AnoRef, x.Item }).IsUnique();
|
|
||||||
e.HasIndex(x => x.Linha);
|
|
||||||
e.HasIndex(x => x.TenantId);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity<ParcelamentoMonthValue>(e =>
|
|
||||||
{
|
|
||||||
e.Property(x => x.Valor).HasPrecision(18, 2);
|
|
||||||
e.HasIndex(x => new { x.ParcelamentoLineId, x.Competencia }).IsUnique();
|
|
||||||
e.HasIndex(x => x.TenantId);
|
|
||||||
|
|
||||||
e.HasOne(x => x.ParcelamentoLine)
|
|
||||||
.WithMany(x => x.MonthValues)
|
|
||||||
.HasForeignKey(x => x.ParcelamentoLineId)
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity<MobileLine>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
modelBuilder.Entity<MobileLine>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
||||||
modelBuilder.Entity<MuregLine>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
modelBuilder.Entity<MuregLine>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
||||||
modelBuilder.Entity<BillingClient>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
modelBuilder.Entity<BillingClient>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
||||||
|
|
@ -257,18 +212,6 @@ public class AppDbContext : IdentityDbContext<ApplicationUser, IdentityRole<Guid
|
||||||
modelBuilder.Entity<ChipVirgemLine>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
modelBuilder.Entity<ChipVirgemLine>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
||||||
modelBuilder.Entity<ControleRecebidoLine>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
modelBuilder.Entity<ControleRecebidoLine>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
||||||
modelBuilder.Entity<Notification>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
modelBuilder.Entity<Notification>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
||||||
modelBuilder.Entity<ResumoMacrophonyPlan>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
|
||||||
modelBuilder.Entity<ResumoMacrophonyTotal>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
|
||||||
modelBuilder.Entity<ResumoVivoLineResumo>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
|
||||||
modelBuilder.Entity<ResumoVivoLineTotal>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
|
||||||
modelBuilder.Entity<ResumoClienteEspecial>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
|
||||||
modelBuilder.Entity<ResumoPlanoContratoResumo>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
|
||||||
modelBuilder.Entity<ResumoPlanoContratoTotal>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
|
||||||
modelBuilder.Entity<ResumoLineTotais>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
|
||||||
modelBuilder.Entity<ResumoReservaLine>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
|
||||||
modelBuilder.Entity<ResumoReservaTotal>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
|
||||||
modelBuilder.Entity<ParcelamentoLine>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
|
||||||
modelBuilder.Entity<ParcelamentoMonthValue>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
|
||||||
modelBuilder.Entity<ApplicationUser>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
modelBuilder.Entity<ApplicationUser>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,6 @@
|
||||||
public class ImportResultDto
|
public class ImportResultDto
|
||||||
{
|
{
|
||||||
public int Imported { get; set; }
|
public int Imported { get; set; }
|
||||||
public ParcelamentosImportSummaryDto? Parcelamentos { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class LineOptionDto
|
public class LineOptionDto
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,4 @@ public class NotificationDto
|
||||||
public Guid? VigenciaLineId { get; set; }
|
public Guid? VigenciaLineId { get; set; }
|
||||||
public string? Cliente { get; set; }
|
public string? Cliente { get; set; }
|
||||||
public string? Linha { get; set; }
|
public string? Linha { get; set; }
|
||||||
public string? Conta { get; set; }
|
|
||||||
public string? Usuario { get; set; }
|
|
||||||
public string? PlanoContrato { get; set; }
|
|
||||||
public DateTime? DtEfetivacaoServico { get; set; }
|
|
||||||
public DateTime? DtTerminoFidelizacao { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
namespace line_gestao_api.Dtos;
|
|
||||||
|
|
||||||
public sealed class ParcelamentoListDto
|
|
||||||
{
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
public int? AnoRef { get; set; }
|
|
||||||
public int? Item { get; set; }
|
|
||||||
public string? Linha { get; set; }
|
|
||||||
public string? Cliente { get; set; }
|
|
||||||
public string? QtParcelas { get; set; }
|
|
||||||
public int? ParcelaAtual { get; set; }
|
|
||||||
public int? TotalParcelas { get; set; }
|
|
||||||
public decimal? ValorCheio { get; set; }
|
|
||||||
public decimal? Desconto { get; set; }
|
|
||||||
public decimal? ValorComDesconto { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ParcelamentoMonthDto
|
|
||||||
{
|
|
||||||
public DateOnly Competencia { get; set; }
|
|
||||||
public decimal? Valor { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ParcelamentoDetailDto : ParcelamentoListDto
|
|
||||||
{
|
|
||||||
public List<ParcelamentoMonthDto> MonthValues { get; set; } = new();
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ParcelamentosImportErrorDto
|
|
||||||
{
|
|
||||||
public int LinhaExcel { get; set; }
|
|
||||||
public string Motivo { get; set; } = string.Empty;
|
|
||||||
public string? Valor { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ParcelamentosImportSummaryDto
|
|
||||||
{
|
|
||||||
public int Lidos { get; set; }
|
|
||||||
public int Inseridos { get; set; }
|
|
||||||
public int Atualizados { get; set; }
|
|
||||||
public int ParcelasInseridas { get; set; }
|
|
||||||
public List<ParcelamentosImportErrorDto> Erros { get; set; } = new();
|
|
||||||
}
|
|
||||||
|
|
@ -1,98 +0,0 @@
|
||||||
namespace line_gestao_api.Dtos;
|
|
||||||
|
|
||||||
public sealed class ResumoResponseDto
|
|
||||||
{
|
|
||||||
public List<ResumoMacrophonyPlanDto> MacrophonyPlans { get; set; } = new();
|
|
||||||
public ResumoMacrophonyTotalDto? MacrophonyTotals { get; set; }
|
|
||||||
public List<ResumoVivoLineResumoDto> VivoLineResumos { get; set; } = new();
|
|
||||||
public ResumoVivoLineTotalDto? VivoLineTotals { get; set; }
|
|
||||||
public List<ResumoClienteEspecialDto> ClienteEspeciais { get; set; } = new();
|
|
||||||
public List<ResumoPlanoContratoResumoDto> PlanoContratoResumos { get; set; } = new();
|
|
||||||
public ResumoPlanoContratoTotalDto? PlanoContratoTotal { get; set; }
|
|
||||||
public List<ResumoLineTotaisDto> LineTotais { get; set; } = new();
|
|
||||||
public List<ResumoReservaLineDto> ReservaLines { get; set; } = new();
|
|
||||||
public ResumoReservaTotalDto? ReservaTotal { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ResumoMacrophonyPlanDto
|
|
||||||
{
|
|
||||||
public string? PlanoContrato { get; set; }
|
|
||||||
public decimal? Gb { get; set; }
|
|
||||||
public decimal? ValorIndividualComSvas { get; set; }
|
|
||||||
public decimal? FranquiaGb { get; set; }
|
|
||||||
public int? TotalLinhas { get; set; }
|
|
||||||
public decimal? ValorTotal { get; set; }
|
|
||||||
public bool VivoTravel { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ResumoMacrophonyTotalDto
|
|
||||||
{
|
|
||||||
public decimal? FranquiaGbTotal { get; set; }
|
|
||||||
public int? TotalLinhasTotal { get; set; }
|
|
||||||
public decimal? ValorTotal { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ResumoVivoLineResumoDto
|
|
||||||
{
|
|
||||||
public string? Skil { get; set; }
|
|
||||||
public string? Cliente { get; set; }
|
|
||||||
public int? QtdLinhas { get; set; }
|
|
||||||
public decimal? FranquiaTotal { get; set; }
|
|
||||||
public decimal? ValorContratoVivo { get; set; }
|
|
||||||
public decimal? FranquiaLine { get; set; }
|
|
||||||
public decimal? ValorContratoLine { get; set; }
|
|
||||||
public decimal? Lucro { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ResumoVivoLineTotalDto
|
|
||||||
{
|
|
||||||
public int? QtdLinhasTotal { get; set; }
|
|
||||||
public decimal? FranquiaTotal { get; set; }
|
|
||||||
public decimal? ValorContratoVivo { get; set; }
|
|
||||||
public decimal? FranquiaLine { get; set; }
|
|
||||||
public decimal? ValorContratoLine { get; set; }
|
|
||||||
public decimal? Lucro { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ResumoClienteEspecialDto
|
|
||||||
{
|
|
||||||
public string? Nome { get; set; }
|
|
||||||
public decimal? Valor { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ResumoPlanoContratoResumoDto
|
|
||||||
{
|
|
||||||
public string? PlanoContrato { get; set; }
|
|
||||||
public decimal? Gb { get; set; }
|
|
||||||
public decimal? ValorIndividualComSvas { get; set; }
|
|
||||||
public decimal? FranquiaGb { get; set; }
|
|
||||||
public int? TotalLinhas { get; set; }
|
|
||||||
public decimal? ValorTotal { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ResumoPlanoContratoTotalDto
|
|
||||||
{
|
|
||||||
public decimal? ValorTotal { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ResumoLineTotaisDto
|
|
||||||
{
|
|
||||||
public string? Tipo { get; set; }
|
|
||||||
public decimal? ValorTotalLine { get; set; }
|
|
||||||
public decimal? LucroTotalLine { get; set; }
|
|
||||||
public int? QtdLinhas { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ResumoReservaLineDto
|
|
||||||
{
|
|
||||||
public string? Ddd { get; set; }
|
|
||||||
public decimal? FranquiaGb { get; set; }
|
|
||||||
public int? QtdLinhas { get; set; }
|
|
||||||
public decimal? Total { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ResumoReservaTotalDto
|
|
||||||
{
|
|
||||||
public int? QtdLinhasTotal { get; set; }
|
|
||||||
public decimal? Total { get; set; }
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
namespace line_gestao_api.Models;
|
|
||||||
|
|
||||||
public class ParcelamentoLine : ITenantEntity
|
|
||||||
{
|
|
||||||
public Guid Id { get; set; } = Guid.NewGuid();
|
|
||||||
|
|
||||||
public Guid TenantId { get; set; }
|
|
||||||
|
|
||||||
public int? AnoRef { get; set; }
|
|
||||||
public int? Item { get; set; }
|
|
||||||
public string? Linha { get; set; }
|
|
||||||
public string? Cliente { get; set; }
|
|
||||||
public string? QtParcelas { get; set; }
|
|
||||||
public int? ParcelaAtual { get; set; }
|
|
||||||
public int? TotalParcelas { get; set; }
|
|
||||||
public decimal? ValorCheio { get; set; }
|
|
||||||
public decimal? Desconto { get; set; }
|
|
||||||
public decimal? ValorComDesconto { get; set; }
|
|
||||||
|
|
||||||
public DateTime CreatedAt { get; set; }
|
|
||||||
public DateTime UpdatedAt { get; set; }
|
|
||||||
|
|
||||||
public List<ParcelamentoMonthValue> MonthValues { get; set; } = new();
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
namespace line_gestao_api.Models;
|
|
||||||
|
|
||||||
public class ParcelamentoMonthValue : ITenantEntity
|
|
||||||
{
|
|
||||||
public Guid Id { get; set; } = Guid.NewGuid();
|
|
||||||
|
|
||||||
public Guid TenantId { get; set; }
|
|
||||||
|
|
||||||
public Guid ParcelamentoLineId { get; set; }
|
|
||||||
public ParcelamentoLine? ParcelamentoLine { get; set; }
|
|
||||||
|
|
||||||
public DateOnly Competencia { get; set; }
|
|
||||||
public decimal? Valor { get; set; }
|
|
||||||
|
|
||||||
public DateTime CreatedAt { get; set; }
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
namespace line_gestao_api.Models;
|
|
||||||
|
|
||||||
public class ResumoClienteEspecial : ITenantEntity
|
|
||||||
{
|
|
||||||
public Guid Id { get; set; } = Guid.NewGuid();
|
|
||||||
|
|
||||||
public Guid TenantId { get; set; }
|
|
||||||
|
|
||||||
public string? Nome { get; set; }
|
|
||||||
public decimal? Valor { get; set; }
|
|
||||||
|
|
||||||
public DateTime CreatedAt { get; set; }
|
|
||||||
public DateTime UpdatedAt { get; set; }
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
namespace line_gestao_api.Models;
|
|
||||||
|
|
||||||
public class ResumoLineTotais : ITenantEntity
|
|
||||||
{
|
|
||||||
public Guid Id { get; set; } = Guid.NewGuid();
|
|
||||||
|
|
||||||
public Guid TenantId { get; set; }
|
|
||||||
|
|
||||||
public string? Tipo { get; set; }
|
|
||||||
public decimal? ValorTotalLine { get; set; }
|
|
||||||
public decimal? LucroTotalLine { get; set; }
|
|
||||||
public int? QtdLinhas { get; set; }
|
|
||||||
|
|
||||||
public DateTime CreatedAt { get; set; }
|
|
||||||
public DateTime UpdatedAt { get; set; }
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
namespace line_gestao_api.Models;
|
|
||||||
|
|
||||||
public class ResumoMacrophonyPlan : ITenantEntity
|
|
||||||
{
|
|
||||||
public Guid Id { get; set; } = Guid.NewGuid();
|
|
||||||
|
|
||||||
public Guid TenantId { get; set; }
|
|
||||||
|
|
||||||
public string? PlanoContrato { get; set; }
|
|
||||||
public decimal? Gb { get; set; }
|
|
||||||
public decimal? ValorIndividualComSvas { get; set; }
|
|
||||||
public decimal? FranquiaGb { get; set; }
|
|
||||||
public int? TotalLinhas { get; set; }
|
|
||||||
public decimal? ValorTotal { get; set; }
|
|
||||||
public bool VivoTravel { get; set; }
|
|
||||||
|
|
||||||
public DateTime CreatedAt { get; set; }
|
|
||||||
public DateTime UpdatedAt { get; set; }
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
namespace line_gestao_api.Models;
|
|
||||||
|
|
||||||
public class ResumoMacrophonyTotal : ITenantEntity
|
|
||||||
{
|
|
||||||
public Guid Id { get; set; } = Guid.NewGuid();
|
|
||||||
|
|
||||||
public Guid TenantId { get; set; }
|
|
||||||
|
|
||||||
public decimal? FranquiaGbTotal { get; set; }
|
|
||||||
public int? TotalLinhasTotal { get; set; }
|
|
||||||
public decimal? ValorTotal { get; set; }
|
|
||||||
|
|
||||||
public DateTime CreatedAt { get; set; }
|
|
||||||
public DateTime UpdatedAt { get; set; }
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
namespace line_gestao_api.Models;
|
|
||||||
|
|
||||||
public class ResumoPlanoContratoResumo : ITenantEntity
|
|
||||||
{
|
|
||||||
public Guid Id { get; set; } = Guid.NewGuid();
|
|
||||||
|
|
||||||
public Guid TenantId { get; set; }
|
|
||||||
|
|
||||||
public string? PlanoContrato { get; set; }
|
|
||||||
public decimal? Gb { get; set; }
|
|
||||||
public decimal? ValorIndividualComSvas { get; set; }
|
|
||||||
public decimal? FranquiaGb { get; set; }
|
|
||||||
public int? TotalLinhas { get; set; }
|
|
||||||
public decimal? ValorTotal { get; set; }
|
|
||||||
|
|
||||||
public DateTime CreatedAt { get; set; }
|
|
||||||
public DateTime UpdatedAt { get; set; }
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
namespace line_gestao_api.Models;
|
|
||||||
|
|
||||||
public class ResumoPlanoContratoTotal : ITenantEntity
|
|
||||||
{
|
|
||||||
public Guid Id { get; set; } = Guid.NewGuid();
|
|
||||||
|
|
||||||
public Guid TenantId { get; set; }
|
|
||||||
|
|
||||||
public decimal? ValorTotal { get; set; }
|
|
||||||
|
|
||||||
public DateTime CreatedAt { get; set; }
|
|
||||||
public DateTime UpdatedAt { get; set; }
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
namespace line_gestao_api.Models;
|
|
||||||
|
|
||||||
public class ResumoReservaLine : ITenantEntity
|
|
||||||
{
|
|
||||||
public Guid Id { get; set; } = Guid.NewGuid();
|
|
||||||
|
|
||||||
public Guid TenantId { get; set; }
|
|
||||||
|
|
||||||
public string? Ddd { get; set; }
|
|
||||||
public decimal? FranquiaGb { get; set; }
|
|
||||||
public int? QtdLinhas { get; set; }
|
|
||||||
public decimal? Total { get; set; }
|
|
||||||
|
|
||||||
public DateTime CreatedAt { get; set; }
|
|
||||||
public DateTime UpdatedAt { get; set; }
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
namespace line_gestao_api.Models;
|
|
||||||
|
|
||||||
public class ResumoReservaTotal : ITenantEntity
|
|
||||||
{
|
|
||||||
public Guid Id { get; set; } = Guid.NewGuid();
|
|
||||||
|
|
||||||
public Guid TenantId { get; set; }
|
|
||||||
|
|
||||||
public int? QtdLinhasTotal { get; set; }
|
|
||||||
public decimal? Total { get; set; }
|
|
||||||
|
|
||||||
public DateTime CreatedAt { get; set; }
|
|
||||||
public DateTime UpdatedAt { get; set; }
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
namespace line_gestao_api.Models;
|
|
||||||
|
|
||||||
public class ResumoVivoLineResumo : ITenantEntity
|
|
||||||
{
|
|
||||||
public Guid Id { get; set; } = Guid.NewGuid();
|
|
||||||
|
|
||||||
public Guid TenantId { get; set; }
|
|
||||||
|
|
||||||
public string? Skil { get; set; }
|
|
||||||
public string? Cliente { get; set; }
|
|
||||||
public int? QtdLinhas { get; set; }
|
|
||||||
public decimal? FranquiaTotal { get; set; }
|
|
||||||
public decimal? ValorContratoVivo { get; set; }
|
|
||||||
public decimal? FranquiaLine { get; set; }
|
|
||||||
public decimal? ValorContratoLine { get; set; }
|
|
||||||
public decimal? Lucro { get; set; }
|
|
||||||
|
|
||||||
public DateTime CreatedAt { get; set; }
|
|
||||||
public DateTime UpdatedAt { get; set; }
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
namespace line_gestao_api.Models;
|
|
||||||
|
|
||||||
public class ResumoVivoLineTotal : ITenantEntity
|
|
||||||
{
|
|
||||||
public Guid Id { get; set; } = Guid.NewGuid();
|
|
||||||
|
|
||||||
public Guid TenantId { get; set; }
|
|
||||||
|
|
||||||
public int? QtdLinhasTotal { get; set; }
|
|
||||||
public decimal? FranquiaTotal { get; set; }
|
|
||||||
public decimal? ValorContratoVivo { get; set; }
|
|
||||||
public decimal? FranquiaLine { get; set; }
|
|
||||||
public decimal? ValorContratoLine { get; set; }
|
|
||||||
public decimal? Lucro { get; set; }
|
|
||||||
|
|
||||||
public DateTime CreatedAt { get; set; }
|
|
||||||
public DateTime UpdatedAt { get; set; }
|
|
||||||
}
|
|
||||||
|
|
@ -35,7 +35,6 @@ builder.Services.AddDbContext<AppDbContext>(options =>
|
||||||
|
|
||||||
builder.Services.AddHttpContextAccessor();
|
builder.Services.AddHttpContextAccessor();
|
||||||
builder.Services.AddScoped<ITenantProvider, TenantProvider>();
|
builder.Services.AddScoped<ITenantProvider, TenantProvider>();
|
||||||
builder.Services.AddScoped<ParcelamentosImportService>();
|
|
||||||
|
|
||||||
builder.Services.AddIdentityCore<ApplicationUser>(options =>
|
builder.Services.AddIdentityCore<ApplicationUser>(options =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,447 +0,0 @@
|
||||||
using System.Globalization;
|
|
||||||
using System.Text;
|
|
||||||
using ClosedXML.Excel;
|
|
||||||
using line_gestao_api.Data;
|
|
||||||
using line_gestao_api.Dtos;
|
|
||||||
using line_gestao_api.Models;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace line_gestao_api.Services;
|
|
||||||
|
|
||||||
public sealed class ParcelamentosImportService
|
|
||||||
{
|
|
||||||
private readonly AppDbContext _db;
|
|
||||||
|
|
||||||
public ParcelamentosImportService(AppDbContext db)
|
|
||||||
{
|
|
||||||
_db = db;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<ParcelamentosImportSummaryDto> ImportFromWorkbookAsync(XLWorkbook wb, bool replaceAll, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
var ws = FindWorksheet(wb);
|
|
||||||
if (ws == null)
|
|
||||||
{
|
|
||||||
return new ParcelamentosImportSummaryDto
|
|
||||||
{
|
|
||||||
Erros =
|
|
||||||
{
|
|
||||||
new ParcelamentosImportErrorDto
|
|
||||||
{
|
|
||||||
LinhaExcel = 0,
|
|
||||||
Motivo = "Aba 'PARCELAMENTOS DE APARELHOS' ou 'PARCELAMENTOS' não encontrada."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (replaceAll)
|
|
||||||
{
|
|
||||||
await _db.ParcelamentoMonthValues.ExecuteDeleteAsync(cancellationToken);
|
|
||||||
await _db.ParcelamentoLines.ExecuteDeleteAsync(cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
var headerRowIndex = FindHeaderRow(ws);
|
|
||||||
if (headerRowIndex == 0)
|
|
||||||
{
|
|
||||||
return new ParcelamentosImportSummaryDto
|
|
||||||
{
|
|
||||||
Erros =
|
|
||||||
{
|
|
||||||
new ParcelamentosImportErrorDto
|
|
||||||
{
|
|
||||||
LinhaExcel = 0,
|
|
||||||
Motivo = "Cabeçalho 'LINHA' não encontrado na aba de parcelamentos."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var yearRowIndex = headerRowIndex - 1;
|
|
||||||
var headerRow = ws.Row(headerRowIndex);
|
|
||||||
var map = BuildHeaderMap(headerRow);
|
|
||||||
|
|
||||||
var colLinha = GetCol(map, "LINHA");
|
|
||||||
var colCliente = GetCol(map, "CLIENTE");
|
|
||||||
var colQtParcelas = GetColAny(map, "QT PARCELAS", "QT. PARCELAS", "QT PARCELAS (NN/TT)", "QTDE PARCELAS");
|
|
||||||
var colValorCheio = GetColAny(map, "VALOR CHEIO");
|
|
||||||
var colDesconto = GetColAny(map, "DESCONTO");
|
|
||||||
var colValorComDesconto = GetColAny(map, "VALOR C/ DESCONTO", "VALOR COM DESCONTO");
|
|
||||||
|
|
||||||
if (colLinha == 0 || colValorComDesconto == 0)
|
|
||||||
{
|
|
||||||
return new ParcelamentosImportSummaryDto
|
|
||||||
{
|
|
||||||
Erros =
|
|
||||||
{
|
|
||||||
new ParcelamentosImportErrorDto
|
|
||||||
{
|
|
||||||
LinhaExcel = headerRowIndex,
|
|
||||||
Motivo = "Colunas obrigatórias não encontradas (LINHA / VALOR C/ DESCONTO)."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var yearMap = BuildYearMap(ws, yearRowIndex, headerRow);
|
|
||||||
var monthColumns = BuildMonthColumns(headerRow, colValorComDesconto + 1);
|
|
||||||
|
|
||||||
var existing = await _db.ParcelamentoLines
|
|
||||||
.AsNoTracking()
|
|
||||||
.ToListAsync(cancellationToken);
|
|
||||||
var existingByKey = existing
|
|
||||||
.Where(x => x.AnoRef.HasValue && x.Item.HasValue)
|
|
||||||
.ToDictionary(x => (x.AnoRef!.Value, x.Item!.Value), x => x.Id);
|
|
||||||
|
|
||||||
var summary = new ParcelamentosImportSummaryDto();
|
|
||||||
var lastRow = ws.LastRowUsed()?.RowNumber() ?? headerRowIndex;
|
|
||||||
|
|
||||||
for (int row = headerRowIndex + 1; row <= lastRow; row++)
|
|
||||||
{
|
|
||||||
var linhaValue = GetCellString(ws, row, colLinha);
|
|
||||||
var itemStr = GetCellString(ws, row, 4);
|
|
||||||
if (string.IsNullOrWhiteSpace(itemStr) && string.IsNullOrWhiteSpace(linhaValue))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
summary.Lidos++;
|
|
||||||
|
|
||||||
var anoRef = TryNullableInt(GetCellString(ws, row, 3));
|
|
||||||
var item = TryNullableInt(itemStr);
|
|
||||||
|
|
||||||
if (!item.HasValue)
|
|
||||||
{
|
|
||||||
summary.Erros.Add(new ParcelamentosImportErrorDto
|
|
||||||
{
|
|
||||||
LinhaExcel = row,
|
|
||||||
Motivo = "Item inválido ou vazio.",
|
|
||||||
Valor = itemStr
|
|
||||||
});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!anoRef.HasValue)
|
|
||||||
{
|
|
||||||
summary.Erros.Add(new ParcelamentosImportErrorDto
|
|
||||||
{
|
|
||||||
LinhaExcel = row,
|
|
||||||
Motivo = "AnoRef inválido ou vazio.",
|
|
||||||
Valor = GetCellString(ws, row, 3)
|
|
||||||
});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var qtParcelas = GetCellString(ws, row, colQtParcelas);
|
|
||||||
ParseParcelas(qtParcelas, out var parcelaAtual, out var totalParcelas);
|
|
||||||
|
|
||||||
var parcelamento = new ParcelamentoLine
|
|
||||||
{
|
|
||||||
AnoRef = anoRef,
|
|
||||||
Item = item,
|
|
||||||
Linha = string.IsNullOrWhiteSpace(linhaValue) ? null : linhaValue.Trim(),
|
|
||||||
Cliente = NormalizeText(GetCellString(ws, row, colCliente)),
|
|
||||||
QtParcelas = string.IsNullOrWhiteSpace(qtParcelas) ? null : qtParcelas.Trim(),
|
|
||||||
ParcelaAtual = parcelaAtual,
|
|
||||||
TotalParcelas = totalParcelas,
|
|
||||||
ValorCheio = TryDecimal(GetCellString(ws, row, colValorCheio)),
|
|
||||||
Desconto = TryDecimal(GetCellString(ws, row, colDesconto)),
|
|
||||||
ValorComDesconto = TryDecimal(GetCellString(ws, row, colValorComDesconto)),
|
|
||||||
UpdatedAt = DateTime.UtcNow
|
|
||||||
};
|
|
||||||
|
|
||||||
if (existingByKey.TryGetValue((anoRef.Value, item.Value), out var existingId))
|
|
||||||
{
|
|
||||||
var existingEntity = await _db.ParcelamentoLines
|
|
||||||
.FirstOrDefaultAsync(x => x.Id == existingId, cancellationToken);
|
|
||||||
if (existingEntity == null)
|
|
||||||
{
|
|
||||||
existingByKey.Remove((anoRef ?? 0, item.Value));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
existingEntity.AnoRef = parcelamento.AnoRef;
|
|
||||||
existingEntity.Item = parcelamento.Item;
|
|
||||||
existingEntity.Linha = parcelamento.Linha;
|
|
||||||
existingEntity.Cliente = parcelamento.Cliente;
|
|
||||||
existingEntity.QtParcelas = parcelamento.QtParcelas;
|
|
||||||
existingEntity.ParcelaAtual = parcelamento.ParcelaAtual;
|
|
||||||
existingEntity.TotalParcelas = parcelamento.TotalParcelas;
|
|
||||||
existingEntity.ValorCheio = parcelamento.ValorCheio;
|
|
||||||
existingEntity.Desconto = parcelamento.Desconto;
|
|
||||||
existingEntity.ValorComDesconto = parcelamento.ValorComDesconto;
|
|
||||||
existingEntity.UpdatedAt = parcelamento.UpdatedAt;
|
|
||||||
|
|
||||||
await _db.ParcelamentoMonthValues
|
|
||||||
.Where(x => x.ParcelamentoLineId == existingEntity.Id)
|
|
||||||
.ExecuteDeleteAsync(cancellationToken);
|
|
||||||
|
|
||||||
var monthValues = BuildMonthValues(ws, headerRowIndex, row, monthColumns, yearMap, existingEntity.Id, summary);
|
|
||||||
if (monthValues.Count > 0)
|
|
||||||
{
|
|
||||||
await _db.ParcelamentoMonthValues.AddRangeAsync(monthValues, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
summary.Atualizados++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
parcelamento.CreatedAt = DateTime.UtcNow;
|
|
||||||
parcelamento.MonthValues = BuildMonthValues(ws, headerRowIndex, row, monthColumns, yearMap, parcelamento.Id, summary);
|
|
||||||
summary.Inseridos++;
|
|
||||||
|
|
||||||
await _db.ParcelamentoLines.AddAsync(parcelamento, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
await _db.SaveChangesAsync(cancellationToken);
|
|
||||||
return summary;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IXLWorksheet? FindWorksheet(XLWorkbook wb)
|
|
||||||
{
|
|
||||||
return wb.Worksheets.FirstOrDefault(w => NormalizeHeader(w.Name) == NormalizeHeader("PARCELAMENTOS DE APARELHOS"))
|
|
||||||
?? wb.Worksheets.FirstOrDefault(w => NormalizeHeader(w.Name) == NormalizeHeader("PARCELAMENTOS"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int FindHeaderRow(IXLWorksheet ws)
|
|
||||||
{
|
|
||||||
var firstRow = ws.FirstRowUsed()?.RowNumber() ?? 1;
|
|
||||||
var lastRow = Math.Min(firstRow + 20, ws.LastRowUsed()?.RowNumber() ?? firstRow);
|
|
||||||
|
|
||||||
for (int r = firstRow; r <= lastRow; r++)
|
|
||||||
{
|
|
||||||
var row = ws.Row(r);
|
|
||||||
foreach (var cell in row.CellsUsed())
|
|
||||||
{
|
|
||||||
if (NormalizeHeader(cell.GetString()) == NormalizeHeader("LINHA"))
|
|
||||||
{
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Dictionary<int, int> BuildYearMap(IXLWorksheet ws, int yearRowIndex, IXLRow headerRow)
|
|
||||||
{
|
|
||||||
var yearMap = new Dictionary<int, int>();
|
|
||||||
var lastCol = headerRow.LastCellUsed()?.Address.ColumnNumber ?? 1;
|
|
||||||
|
|
||||||
if (yearRowIndex <= 0)
|
|
||||||
{
|
|
||||||
return yearMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int col = 1; col <= lastCol; col++)
|
|
||||||
{
|
|
||||||
var yearCell = ws.Cell(yearRowIndex, col);
|
|
||||||
var yearText = yearCell.GetString();
|
|
||||||
if (string.IsNullOrWhiteSpace(yearText))
|
|
||||||
{
|
|
||||||
var merged = ws.MergedRanges.FirstOrDefault(r =>
|
|
||||||
r.RangeAddress.FirstAddress.RowNumber == yearRowIndex &&
|
|
||||||
r.RangeAddress.FirstAddress.ColumnNumber <= col &&
|
|
||||||
r.RangeAddress.LastAddress.ColumnNumber >= col);
|
|
||||||
|
|
||||||
if (merged != null)
|
|
||||||
{
|
|
||||||
yearText = merged.FirstCell().GetString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (int.TryParse(OnlyDigits(yearText), out var year))
|
|
||||||
{
|
|
||||||
yearMap[col] = year;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return yearMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<int> BuildMonthColumns(IXLRow headerRow, int startCol)
|
|
||||||
{
|
|
||||||
var lastCol = headerRow.LastCellUsed()?.Address.ColumnNumber ?? startCol;
|
|
||||||
var months = new List<int>();
|
|
||||||
for (int col = startCol; col <= lastCol; col++)
|
|
||||||
{
|
|
||||||
var header = NormalizeHeader(headerRow.Cell(col).GetString());
|
|
||||||
if (ToMonthNumber(header).HasValue)
|
|
||||||
{
|
|
||||||
months.Add(col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return months;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<ParcelamentoMonthValue> BuildMonthValues(
|
|
||||||
IXLWorksheet ws,
|
|
||||||
int headerRowIndex,
|
|
||||||
int row,
|
|
||||||
List<int> monthColumns,
|
|
||||||
Dictionary<int, int> yearMap,
|
|
||||||
Guid parcelamentoId,
|
|
||||||
ParcelamentosImportSummaryDto summary)
|
|
||||||
{
|
|
||||||
var monthValues = new List<ParcelamentoMonthValue>();
|
|
||||||
foreach (var col in monthColumns)
|
|
||||||
{
|
|
||||||
if (!yearMap.TryGetValue(col, out var year))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var header = NormalizeHeader(ws.Cell(headerRowIndex, col).GetString());
|
|
||||||
var monthNumber = ToMonthNumber(header);
|
|
||||||
if (!monthNumber.HasValue)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var valueStr = ws.Cell(row, col).GetString();
|
|
||||||
var value = TryDecimal(valueStr);
|
|
||||||
if (!value.HasValue)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
monthValues.Add(new ParcelamentoMonthValue
|
|
||||||
{
|
|
||||||
ParcelamentoLineId = parcelamentoId,
|
|
||||||
Competencia = new DateOnly(year, monthNumber.Value, 1),
|
|
||||||
Valor = value,
|
|
||||||
CreatedAt = DateTime.UtcNow
|
|
||||||
});
|
|
||||||
summary.ParcelasInseridas++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return monthValues;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ParseParcelas(string? qtParcelas, out int? parcelaAtual, out int? totalParcelas)
|
|
||||||
{
|
|
||||||
parcelaAtual = null;
|
|
||||||
totalParcelas = null;
|
|
||||||
if (string.IsNullOrWhiteSpace(qtParcelas))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var parts = qtParcelas.Split('/', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
|
||||||
if (parts.Length >= 1 && int.TryParse(OnlyDigits(parts[0]), out var atual))
|
|
||||||
{
|
|
||||||
parcelaAtual = atual;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parts.Length >= 2 && int.TryParse(OnlyDigits(parts[1]), out var total))
|
|
||||||
{
|
|
||||||
totalParcelas = total;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Dictionary<string, int> BuildHeaderMap(IXLRow headerRow)
|
|
||||||
{
|
|
||||||
var map = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
|
||||||
foreach (var cell in headerRow.CellsUsed())
|
|
||||||
{
|
|
||||||
var k = NormalizeHeader(cell.GetString());
|
|
||||||
if (!string.IsNullOrWhiteSpace(k) && !map.ContainsKey(k))
|
|
||||||
map[k] = cell.Address.ColumnNumber;
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int GetCol(Dictionary<string, int> map, string name)
|
|
||||||
=> map.TryGetValue(NormalizeHeader(name), out var c) ? c : 0;
|
|
||||||
|
|
||||||
private static int GetColAny(Dictionary<string, int> map, params string[] headers)
|
|
||||||
{
|
|
||||||
foreach (var h in headers)
|
|
||||||
{
|
|
||||||
var k = NormalizeHeader(h);
|
|
||||||
if (map.TryGetValue(k, out var c)) return c;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetCellString(IXLWorksheet ws, int row, int col)
|
|
||||||
{
|
|
||||||
if (col <= 0) return "";
|
|
||||||
return (ws.Cell(row, col).GetValue<string>() ?? "").Trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string? NormalizeText(string value)
|
|
||||||
=> string.IsNullOrWhiteSpace(value) ? null : value.Trim();
|
|
||||||
|
|
||||||
private static decimal? TryDecimal(string? s)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(s)) return null;
|
|
||||||
|
|
||||||
s = s.Replace("R$", "", StringComparison.OrdinalIgnoreCase).Trim();
|
|
||||||
|
|
||||||
if (decimal.TryParse(s, NumberStyles.Any, new CultureInfo("pt-BR"), out var d)) return d;
|
|
||||||
if (decimal.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out d)) return d;
|
|
||||||
|
|
||||||
var s2 = s.Replace(".", "").Replace(",", ".");
|
|
||||||
if (decimal.TryParse(s2, NumberStyles.Any, CultureInfo.InvariantCulture, out d)) return d;
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int? TryNullableInt(string? s)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(s)) return null;
|
|
||||||
var d = OnlyDigits(s);
|
|
||||||
if (string.IsNullOrWhiteSpace(d)) return null;
|
|
||||||
return int.TryParse(d, out var n) ? n : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string OnlyDigits(string? s)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(s)) return "";
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
foreach (var c in s) if (char.IsDigit(c)) sb.Append(c);
|
|
||||||
return sb.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int? ToMonthNumber(string? month)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(month)) return null;
|
|
||||||
return NormalizeHeader(month) switch
|
|
||||||
{
|
|
||||||
"JAN" => 1,
|
|
||||||
"FEV" => 2,
|
|
||||||
"MAR" => 3,
|
|
||||||
"ABR" => 4,
|
|
||||||
"MAI" => 5,
|
|
||||||
"JUN" => 6,
|
|
||||||
"JUL" => 7,
|
|
||||||
"AGO" => 8,
|
|
||||||
"SET" => 9,
|
|
||||||
"OUT" => 10,
|
|
||||||
"NOV" => 11,
|
|
||||||
"DEZ" => 12,
|
|
||||||
_ => null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string NormalizeHeader(string? s)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(s)) return "";
|
|
||||||
s = s.Trim().ToUpperInvariant().Normalize(NormalizationForm.FormD);
|
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
foreach (var c in s)
|
|
||||||
if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark)
|
|
||||||
sb.Append(c);
|
|
||||||
|
|
||||||
return sb.ToString()
|
|
||||||
.Normalize(NormalizationForm.FormC)
|
|
||||||
.Replace(" ", "")
|
|
||||||
.Replace("\t", "")
|
|
||||||
.Replace("\n", "")
|
|
||||||
.Replace("\r", "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -119,11 +119,6 @@ public class VigenciaNotificationBackgroundService : BackgroundService
|
||||||
.Where(v => v.DtTerminoFidelizacao != null)
|
.Where(v => v.DtTerminoFidelizacao != null)
|
||||||
.ToListAsync(stoppingToken);
|
.ToListAsync(stoppingToken);
|
||||||
|
|
||||||
if (vigencias.Count > 0)
|
|
||||||
{
|
|
||||||
await CleanupOutdatedNotificationsAsync(db, vigencias, reminderDays, today, stoppingToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
var candidates = new List<Notification>();
|
var candidates = new List<Notification>();
|
||||||
foreach (var vigencia in vigencias)
|
foreach (var vigencia in vigencias)
|
||||||
{
|
{
|
||||||
|
|
@ -228,92 +223,6 @@ public class VigenciaNotificationBackgroundService : BackgroundService
|
||||||
await db.SaveChangesAsync(stoppingToken);
|
await db.SaveChangesAsync(stoppingToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task CleanupOutdatedNotificationsAsync(
|
|
||||||
AppDbContext db,
|
|
||||||
IReadOnlyCollection<VigenciaLine> vigencias,
|
|
||||||
IReadOnlyCollection<int> reminderDays,
|
|
||||||
DateTime today,
|
|
||||||
CancellationToken stoppingToken)
|
|
||||||
{
|
|
||||||
var vigenciasById = vigencias.ToDictionary(v => v.Id, v => v);
|
|
||||||
var vigenciasByLinha = vigencias
|
|
||||||
.Where(v => !string.IsNullOrWhiteSpace(v.Linha))
|
|
||||||
.GroupBy(v => v.Linha!)
|
|
||||||
.Select(g => g.OrderByDescending(v => v.UpdatedAt).First())
|
|
||||||
.ToDictionary(v => v.Linha!, v => v);
|
|
||||||
|
|
||||||
var existingNotifications = await db.Notifications.AsNoTracking()
|
|
||||||
.Where(n => n.Tipo == "Vencido" || n.Tipo == "AVencer")
|
|
||||||
.ToListAsync(stoppingToken);
|
|
||||||
|
|
||||||
if (existingNotifications.Count == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var idsToDelete = new List<Guid>();
|
|
||||||
foreach (var notification in existingNotifications)
|
|
||||||
{
|
|
||||||
var vigencia = ResolveVigencia(notification, vigenciasById, vigenciasByLinha);
|
|
||||||
if (vigencia?.DtTerminoFidelizacao is null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var endDate = vigencia.DtTerminoFidelizacao.Value.Date;
|
|
||||||
if (endDate < today)
|
|
||||||
{
|
|
||||||
if (notification.Tipo != "Vencido")
|
|
||||||
{
|
|
||||||
idsToDelete.Add(notification.Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var daysUntil = (endDate - today).Days;
|
|
||||||
if (notification.Tipo == "Vencido")
|
|
||||||
{
|
|
||||||
idsToDelete.Add(notification.Id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!reminderDays.Contains(daysUntil) || notification.DiasParaVencer != daysUntil)
|
|
||||||
{
|
|
||||||
idsToDelete.Add(notification.Id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (idsToDelete.Count == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await db.Notifications
|
|
||||||
.Where(n => idsToDelete.Contains(n.Id))
|
|
||||||
.ExecuteDeleteAsync(stoppingToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static VigenciaLine? ResolveVigencia(
|
|
||||||
Notification notification,
|
|
||||||
IReadOnlyDictionary<Guid, VigenciaLine> vigenciasById,
|
|
||||||
IReadOnlyDictionary<string, VigenciaLine> vigenciasByLinha)
|
|
||||||
{
|
|
||||||
if (notification.VigenciaLineId.HasValue
|
|
||||||
&& vigenciasById.TryGetValue(notification.VigenciaLineId.Value, out var byId))
|
|
||||||
{
|
|
||||||
return byId;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(notification.Linha)
|
|
||||||
&& vigenciasByLinha.TryGetValue(notification.Linha, out var byLinha))
|
|
||||||
{
|
|
||||||
return byLinha;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Notification BuildNotification(
|
private static Notification BuildNotification(
|
||||||
string tipo,
|
string tipo,
|
||||||
string titulo,
|
string titulo,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue