Merge 255f63f546 into 40a94f0e4e
This commit is contained in:
commit
437bd2de4f
|
|
@ -646,6 +646,11 @@ namespace line_gestao_api.Controllers
|
||||||
// =========================
|
// =========================
|
||||||
await ImportControleRecebidosFromWorkbook(wb);
|
await ImportControleRecebidosFromWorkbook(wb);
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// ✅ IMPORTA RESUMO
|
||||||
|
// =========================
|
||||||
|
await ImportResumoFromWorkbook(wb);
|
||||||
|
|
||||||
await tx.CommitAsync();
|
await tx.CommitAsync();
|
||||||
return Ok(new ImportResultDto { Imported = imported });
|
return Ok(new ImportResultDto { Imported = imported });
|
||||||
}
|
}
|
||||||
|
|
@ -1474,6 +1479,398 @@ 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);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
|
using ClosedXML.Excel;
|
||||||
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 Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
@ -22,24 +24,45 @@ public class NotificationsController : ControllerBase
|
||||||
[HttpGet("/notifications")]
|
[HttpGet("/notifications")]
|
||||||
public async Task<ActionResult<List<NotificationDto>>> GetNotifications()
|
public async Task<ActionResult<List<NotificationDto>>> GetNotifications()
|
||||||
{
|
{
|
||||||
var query = _db.Notifications.AsNoTracking();
|
var items = await (
|
||||||
|
from notification in _db.Notifications.AsNoTracking()
|
||||||
var items = await query
|
join vigencia in _db.VigenciaLines.AsNoTracking()
|
||||||
.OrderByDescending(n => n.Data)
|
on notification.VigenciaLineId equals vigencia.Id into vigencias
|
||||||
.Select(n => new NotificationDto
|
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.Data descending
|
||||||
|
select new NotificationDto
|
||||||
{
|
{
|
||||||
Id = n.Id,
|
Id = notification.Id,
|
||||||
Tipo = n.Tipo,
|
Tipo = notification.Tipo,
|
||||||
Titulo = n.Titulo,
|
Titulo = notification.Titulo,
|
||||||
Mensagem = n.Mensagem,
|
Mensagem = notification.Mensagem,
|
||||||
Data = n.Data,
|
Data = notification.Data,
|
||||||
ReferenciaData = n.ReferenciaData,
|
ReferenciaData = notification.ReferenciaData,
|
||||||
DiasParaVencer = n.DiasParaVencer,
|
DiasParaVencer = notification.DiasParaVencer,
|
||||||
Lida = n.Lida,
|
Lida = notification.Lida,
|
||||||
LidaEm = n.LidaEm,
|
LidaEm = notification.LidaEm,
|
||||||
VigenciaLineId = n.VigenciaLineId,
|
VigenciaLineId = notification.VigenciaLineId,
|
||||||
Cliente = n.Cliente,
|
Cliente = notification.Cliente
|
||||||
Linha = n.Linha
|
?? (vigencia != null ? vigencia.Cliente : null)
|
||||||
|
?? (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();
|
||||||
|
|
||||||
|
|
@ -68,4 +91,184 @@ public class NotificationsController : ControllerBase
|
||||||
return NoContent();
|
return NoContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPatch("read-all")]
|
||||||
|
[HttpPatch("/notifications/read-all")]
|
||||||
|
public async Task<IActionResult> MarkAllAsRead(
|
||||||
|
[FromQuery] string? filter,
|
||||||
|
[FromBody] NotificationSelectionRequest? request)
|
||||||
|
{
|
||||||
|
var utcNow = DateTime.UtcNow;
|
||||||
|
var query = ApplySelectionAndFilter(_db.Notifications, filter, request?.NotificationIds)
|
||||||
|
.Where(n => !n.Lida);
|
||||||
|
|
||||||
|
await query.ExecuteUpdateAsync(updates => updates
|
||||||
|
.SetProperty(n => n.Lida, true)
|
||||||
|
.SetProperty(n => n.LidaEm, utcNow));
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("export")]
|
||||||
|
[HttpGet("/notifications/export")]
|
||||||
|
public async Task<IActionResult> ExportNotifications([FromQuery] string? filter)
|
||||||
|
{
|
||||||
|
var query = ApplySelectionAndFilter(_db.Notifications.AsNoTracking(), filter, null);
|
||||||
|
return await ExportNotificationsAsync(query, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("export")]
|
||||||
|
[HttpPost("/notifications/export")]
|
||||||
|
public async Task<IActionResult> ExportNotifications(
|
||||||
|
[FromQuery] string? filter,
|
||||||
|
[FromBody] NotificationSelectionRequest? request)
|
||||||
|
{
|
||||||
|
var query = ApplySelectionAndFilter(_db.Notifications.AsNoTracking(), filter, request?.NotificationIds);
|
||||||
|
return await ExportNotificationsAsync(query, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<IActionResult> ExportNotificationsAsync(IQueryable<Notification> query, string? filter)
|
||||||
|
{
|
||||||
|
var rows = await (
|
||||||
|
from notification in query
|
||||||
|
join vigencia in _db.VigenciaLines.AsNoTracking()
|
||||||
|
on notification.VigenciaLineId equals vigencia.Id into vigencias
|
||||||
|
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
|
||||||
|
select new NotificationExportRow(
|
||||||
|
(vigencia != null ? vigencia.Conta : null)
|
||||||
|
?? (vigenciaByLinha != null ? vigenciaByLinha.Conta : null),
|
||||||
|
notification.Linha
|
||||||
|
?? (vigencia != null ? vigencia.Linha : null)
|
||||||
|
?? (vigenciaByLinha != null ? vigenciaByLinha.Linha : null),
|
||||||
|
notification.Cliente
|
||||||
|
?? (vigencia != null ? vigencia.Cliente : null)
|
||||||
|
?? (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))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
using var workbook = new XLWorkbook();
|
||||||
|
var worksheet = workbook.Worksheets.Add("Notificacoes");
|
||||||
|
|
||||||
|
var normalizedFilter = NormalizeFilter(filter);
|
||||||
|
var headers = new[]
|
||||||
|
{
|
||||||
|
"CONTA",
|
||||||
|
"LINHA",
|
||||||
|
"Cliente",
|
||||||
|
"Usuário",
|
||||||
|
"PLANO CONTRATO",
|
||||||
|
"DATA INICIO",
|
||||||
|
normalizedFilter is "vencidas" or "vencido" ? "DATA VENCIMENTO" : "DATA A VENCER",
|
||||||
|
"Status"
|
||||||
|
};
|
||||||
|
|
||||||
|
for (var i = 0; i < headers.Length; i++)
|
||||||
|
{
|
||||||
|
worksheet.Cell(1, i + 1).Value = headers[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
var headerRange = worksheet.Range(1, 1, 1, headers.Length);
|
||||||
|
headerRange.Style.Font.Bold = true;
|
||||||
|
headerRange.Style.Fill.BackgroundColor = XLColor.LightGray;
|
||||||
|
headerRange.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
|
||||||
|
|
||||||
|
for (var i = 0; i < rows.Count; i++)
|
||||||
|
{
|
||||||
|
var row = rows[i];
|
||||||
|
var rowIndex = i + 2;
|
||||||
|
worksheet.Cell(rowIndex, 1).Value = row.Conta ?? string.Empty;
|
||||||
|
worksheet.Cell(rowIndex, 2).Value = row.Linha ?? string.Empty;
|
||||||
|
worksheet.Cell(rowIndex, 3).Value = (row.Cliente ?? string.Empty).ToUpperInvariant();
|
||||||
|
worksheet.Cell(rowIndex, 4).Value = (row.Usuario ?? string.Empty).ToUpperInvariant();
|
||||||
|
worksheet.Cell(rowIndex, 5).Value = row.PlanoContrato ?? string.Empty;
|
||||||
|
worksheet.Cell(rowIndex, 6).Value = row.DataInicio;
|
||||||
|
worksheet.Cell(rowIndex, 7).Value = row.DataReferencia;
|
||||||
|
worksheet.Cell(rowIndex, 8).Value = row.Tipo.ToUpperInvariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
worksheet.Column(1).Width = 18;
|
||||||
|
worksheet.Column(2).Width = 18;
|
||||||
|
worksheet.Column(3).Width = 26;
|
||||||
|
worksheet.Column(4).Width = 24;
|
||||||
|
worksheet.Column(5).Width = 22;
|
||||||
|
worksheet.Column(6).Width = 16;
|
||||||
|
worksheet.Column(7).Width = 18;
|
||||||
|
worksheet.Column(8).Width = 14;
|
||||||
|
|
||||||
|
worksheet.Column(6).Style.DateFormat.Format = "dd/MM/yyyy";
|
||||||
|
worksheet.Column(7).Style.DateFormat.Format = "dd/MM/yyyy";
|
||||||
|
|
||||||
|
worksheet.Columns().AdjustToContents();
|
||||||
|
|
||||||
|
using var stream = new MemoryStream();
|
||||||
|
workbook.SaveAs(stream);
|
||||||
|
stream.Position = 0;
|
||||||
|
|
||||||
|
var fileName = $"notificacoes-{DateTime.UtcNow:yyyyMMddHHmmss}.xlsx";
|
||||||
|
return File(
|
||||||
|
stream.ToArray(),
|
||||||
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||||
|
fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IQueryable<Notification> ApplySelectionAndFilter(
|
||||||
|
IQueryable<Notification> query,
|
||||||
|
string? filter,
|
||||||
|
IReadOnlyCollection<Guid>? notificationIds)
|
||||||
|
{
|
||||||
|
query = ApplyFilter(query, filter);
|
||||||
|
|
||||||
|
if (notificationIds is { Count: > 0 })
|
||||||
|
{
|
||||||
|
query = query.Where(n => notificationIds.Contains(n.Id));
|
||||||
|
}
|
||||||
|
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IQueryable<Notification> ApplyFilter(IQueryable<Notification> query, string? filter)
|
||||||
|
{
|
||||||
|
var normalized = NormalizeFilter(filter);
|
||||||
|
return normalized switch
|
||||||
|
{
|
||||||
|
"a-vencer" or "avencer" => query.Where(n => n.Tipo == "AVencer"),
|
||||||
|
"vencidas" or "vencido" => query.Where(n => n.Tipo == "Vencido"),
|
||||||
|
_ => query
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? NormalizeFilter(string? filter)
|
||||||
|
{
|
||||||
|
return filter?.Trim().ToLowerInvariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed record NotificationExportRow(
|
||||||
|
string? Conta,
|
||||||
|
string? Linha,
|
||||||
|
string? Cliente,
|
||||||
|
string? Usuario,
|
||||||
|
string? PlanoContrato,
|
||||||
|
DateTime? DataInicio,
|
||||||
|
DateTime? DataReferencia,
|
||||||
|
string Tipo);
|
||||||
|
|
||||||
|
public sealed class NotificationSelectionRequest
|
||||||
|
{
|
||||||
|
public List<Guid>? NotificationIds { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,129 @@
|
||||||
|
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,6 +44,18 @@ 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>();
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
base.OnModelCreating(modelBuilder);
|
base.OnModelCreating(modelBuilder);
|
||||||
|
|
@ -212,6 +224,16 @@ 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<ApplicationUser>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
modelBuilder.Entity<ApplicationUser>().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,4 +14,9 @@ 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; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
|
@ -119,6 +119,11 @@ 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)
|
||||||
{
|
{
|
||||||
|
|
@ -223,6 +228,92 @@ 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