From 0c17b5e48af5f03a14fd47aa954106eb0ea436ea Mon Sep 17 00:00:00 2001 From: Eduardo Date: Fri, 6 Feb 2026 08:40:26 -0300 Subject: [PATCH] =?UTF-8?q?Atualiza=C3=A7=C3=A3o=20de=20novas=20altera?= =?UTF-8?q?=C3=A7=C3=B5es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Controllers/BillingController.cs | 71 + Controllers/ChipsVirgensController.cs | 12 +- Controllers/ControleRecebidosController.cs | 38 +- Controllers/HistoricoController.cs | 156 ++ Controllers/LinesController.cs | 252 ++- Controllers/ParcelamentosController.cs | 354 +++- Controllers/RelatoriosController.cs | 6 +- Controllers/ResumoController.cs | 47 +- Controllers/UserDataController.cs | 223 ++- Controllers/VigenciaController.cs | 177 +- Data/AppDbContext.cs | 54 +- Dtos/AccountCompanyDtos.cs | 10 + Dtos/AuditLogDtos.cs | 34 + Dtos/BillingClientListDto.cs | 21 + Dtos/ParcelamentosDtos.cs | 35 + Dtos/ResumoDtos.cs | 15 + Dtos/UserDataDtos.cs | 48 +- Dtos/VigenciaDtos.cs | 34 +- ...20260202162920_AddResumoTables.Designer.cs | 1294 ++++++++++++++ Migrations/20260202162920_AddResumoTables.cs | 232 +++ ...2175823_AddParcelamentosTables.Designer.cs | 1405 +++++++++++++++ .../20260202175823_AddParcelamentosTables.cs | 98 ++ ...ivoSyncTipoDeChipToMobileLines.Designer.cs | 1412 +++++++++++++++ ...3033_AddVivoSyncTipoDeChipToMobileLines.cs | 39 + ...143959_AddUserDataPessoaFields.Designer.cs | 1509 ++++++++++++++++ .../20260205143959_AddUserDataPessoaFields.cs | 94 + ...645_AddResumoReservaTotalGeral.Designer.cs | 1512 +++++++++++++++++ ...260205151645_AddResumoReservaTotalGeral.cs | 28 + .../20260212120000_AddAuditLogs.Designer.cs | 19 + Migrations/20260212120000_AddAuditLogs.cs | 72 + Migrations/AppDbContextModelSnapshot.cs | 785 +++++++-- Models/AuditLog.cs | 28 + Models/ResumoReservaTotal.cs | 1 + Models/UserData.cs | 6 + Program.cs | 1 + Services/AuditLogBuilder.cs | 280 +++ Services/AutoFillRules.cs | 73 + Services/IAuditLogBuilder.cs | 10 + Services/ParcelamentosImportService.cs | 344 +++- .../VigenciaNotificationBackgroundService.cs | 2 +- appsettings.json | 2 +- 41 files changed, 10574 insertions(+), 259 deletions(-) create mode 100644 Controllers/HistoricoController.cs create mode 100644 Dtos/AccountCompanyDtos.cs create mode 100644 Dtos/AuditLogDtos.cs create mode 100644 Migrations/20260202162920_AddResumoTables.Designer.cs create mode 100644 Migrations/20260202162920_AddResumoTables.cs create mode 100644 Migrations/20260202175823_AddParcelamentosTables.Designer.cs create mode 100644 Migrations/20260202175823_AddParcelamentosTables.cs create mode 100644 Migrations/20260203193033_AddVivoSyncTipoDeChipToMobileLines.Designer.cs create mode 100644 Migrations/20260203193033_AddVivoSyncTipoDeChipToMobileLines.cs create mode 100644 Migrations/20260205143959_AddUserDataPessoaFields.Designer.cs create mode 100644 Migrations/20260205143959_AddUserDataPessoaFields.cs create mode 100644 Migrations/20260205151645_AddResumoReservaTotalGeral.Designer.cs create mode 100644 Migrations/20260205151645_AddResumoReservaTotalGeral.cs create mode 100644 Migrations/20260212120000_AddAuditLogs.Designer.cs create mode 100644 Migrations/20260212120000_AddAuditLogs.cs create mode 100644 Models/AuditLog.cs create mode 100644 Services/AuditLogBuilder.cs create mode 100644 Services/AutoFillRules.cs create mode 100644 Services/IAuditLogBuilder.cs diff --git a/Controllers/BillingController.cs b/Controllers/BillingController.cs index 8be1192..3067afa 100644 --- a/Controllers/BillingController.cs +++ b/Controllers/BillingController.cs @@ -1,5 +1,6 @@ using line_gestao_api.Data; using line_gestao_api.Dtos; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -146,5 +147,75 @@ namespace line_gestao_api.Controllers return Ok(clients); } + + [HttpGet("{id:guid}")] + public async Task> GetById(Guid id) + { + var x = await _db.BillingClients.AsNoTracking().FirstOrDefaultAsync(a => a.Id == id); + if (x == null) return NotFound(); + + return Ok(new BillingClientDetailDto + { + Id = x.Id, + Tipo = x.Tipo, + Item = x.Item, + Cliente = x.Cliente, + QtdLinhas = x.QtdLinhas, + FranquiaVivo = x.FranquiaVivo, + ValorContratoVivo = x.ValorContratoVivo, + FranquiaLine = x.FranquiaLine, + ValorContratoLine = x.ValorContratoLine, + Lucro = x.Lucro, + Aparelho = x.Aparelho, + FormaPagamento = x.FormaPagamento, + CreatedAt = x.CreatedAt, + UpdatedAt = x.UpdatedAt + }); + } + + [HttpPut("{id:guid}")] + [Authorize(Roles = "admin")] + public async Task Update(Guid id, [FromBody] UpdateBillingClientRequest req) + { + var x = await _db.BillingClients.FirstOrDefaultAsync(a => a.Id == id); + if (x == null) return NotFound(); + + if (!string.IsNullOrWhiteSpace(req.Tipo)) + { + var tipo = req.Tipo.Trim().ToUpperInvariant(); + if (tipo != "PF" && tipo != "PJ") + return BadRequest(new { message = "Tipo inválido. Use PF ou PJ." }); + x.Tipo = tipo; + } + + if (req.Item.HasValue) x.Item = req.Item.Value; + if (req.Cliente != null) x.Cliente = req.Cliente.Trim(); + + x.QtdLinhas = req.QtdLinhas; + x.FranquiaVivo = req.FranquiaVivo; + x.ValorContratoVivo = req.ValorContratoVivo; + x.FranquiaLine = req.FranquiaLine; + x.ValorContratoLine = req.ValorContratoLine; + x.Lucro = req.Lucro; + x.Aparelho = string.IsNullOrWhiteSpace(req.Aparelho) ? null : req.Aparelho.Trim(); + x.FormaPagamento = string.IsNullOrWhiteSpace(req.FormaPagamento) ? null : req.FormaPagamento.Trim(); + + x.UpdatedAt = DateTime.UtcNow; + + await _db.SaveChangesAsync(); + return NoContent(); + } + + [HttpDelete("{id:guid}")] + [Authorize(Roles = "admin")] + public async Task Delete(Guid id) + { + var x = await _db.BillingClients.FirstOrDefaultAsync(a => a.Id == id); + if (x == null) return NotFound(); + + _db.BillingClients.Remove(x); + await _db.SaveChangesAsync(); + return NoContent(); + } } } diff --git a/Controllers/ChipsVirgensController.cs b/Controllers/ChipsVirgensController.cs index 36c9731..572a917 100644 --- a/Controllers/ChipsVirgensController.cs +++ b/Controllers/ChipsVirgensController.cs @@ -1,6 +1,7 @@ using line_gestao_api.Data; using line_gestao_api.Dtos; using line_gestao_api.Models; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using System.Text; @@ -88,11 +89,18 @@ namespace line_gestao_api.Controllers public async Task> Create([FromBody] CreateChipVirgemDto req) { var now = DateTime.UtcNow; + var item = req.Item ?? 0; + + if (item <= 0) + { + var maxItem = await _db.ChipVirgemLines.MaxAsync(x => (int?)x.Item) ?? 0; + item = maxItem + 1; + } var e = new ChipVirgemLine { Id = Guid.NewGuid(), - Item = req.Item ?? 0, + Item = item, NumeroDoChip = NullIfEmptyDigits(req.NumeroDoChip), Observacoes = string.IsNullOrWhiteSpace(req.Observacoes) ? null : req.Observacoes.Trim(), CreatedAt = now, @@ -106,6 +114,7 @@ namespace line_gestao_api.Controllers } [HttpPut("{id:guid}")] + [Authorize(Roles = "admin")] public async Task Update(Guid id, [FromBody] UpdateChipVirgemRequest req) { var x = await _db.ChipVirgemLines.FirstOrDefaultAsync(a => a.Id == id); @@ -122,6 +131,7 @@ namespace line_gestao_api.Controllers } [HttpDelete("{id:guid}")] + [Authorize(Roles = "admin")] public async Task Delete(Guid id) { var x = await _db.ChipVirgemLines.FirstOrDefaultAsync(a => a.Id == id); diff --git a/Controllers/ControleRecebidosController.cs b/Controllers/ControleRecebidosController.cs index 4d46563..0d72fc4 100644 --- a/Controllers/ControleRecebidosController.cs +++ b/Controllers/ControleRecebidosController.cs @@ -1,6 +1,7 @@ using line_gestao_api.Data; using line_gestao_api.Dtos; using line_gestao_api.Models; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using System.Text; @@ -119,21 +120,46 @@ namespace line_gestao_api.Controllers { var now = DateTime.UtcNow; + var ano = req.Ano ?? (req.DataDaNf?.Year ?? DateTime.UtcNow.Year); + var item = req.Item ?? 0; + + if (item <= 0) + { + var maxItem = await _db.ControleRecebidoLines + .AsNoTracking() + .Where(x => x.Ano == ano) + .MaxAsync(x => (int?)x.Item) ?? 0; + item = maxItem + 1; + } + + var quantidade = req.Quantidade; + var valorUnit = req.ValorUnit; + var valorDaNf = req.ValorDaNf; + + if (!valorDaNf.HasValue && valorUnit.HasValue && quantidade.HasValue) + { + valorDaNf = Math.Round(valorUnit.Value * quantidade.Value, 2); + } + else if (!valorUnit.HasValue && valorDaNf.HasValue && quantidade.HasValue && quantidade.Value > 0) + { + valorUnit = Math.Round(valorDaNf.Value / quantidade.Value, 2); + } + var e = new ControleRecebidoLine { Id = Guid.NewGuid(), - Ano = req.Ano ?? DateTime.UtcNow.Year, - Item = req.Item ?? 0, + Ano = ano, + Item = item, NotaFiscal = TrimOrNull(req.NotaFiscal), Chip = NullIfEmptyDigits(req.Chip), Serial = TrimOrNull(req.Serial), ConteudoDaNf = TrimOrNull(req.ConteudoDaNf), NumeroDaLinha = NullIfEmptyDigits(req.NumeroDaLinha), - ValorUnit = req.ValorUnit, - ValorDaNf = req.ValorDaNf, + ValorUnit = valorUnit, + ValorDaNf = valorDaNf, DataDaNf = ToUtc(req.DataDaNf), DataDoRecebimento = ToUtc(req.DataDoRecebimento), - Quantidade = req.Quantidade, + Quantidade = quantidade, IsResumo = req.IsResumo ?? false, CreatedAt = now, UpdatedAt = now @@ -146,6 +172,7 @@ namespace line_gestao_api.Controllers } [HttpPut("{id:guid}")] + [Authorize(Roles = "admin")] public async Task Update(Guid id, [FromBody] UpdateControleRecebidoRequest req) { var x = await _db.ControleRecebidoLines.FirstOrDefaultAsync(a => a.Id == id); @@ -173,6 +200,7 @@ namespace line_gestao_api.Controllers } [HttpDelete("{id:guid}")] + [Authorize(Roles = "admin")] public async Task Delete(Guid id) { var x = await _db.ControleRecebidoLines.FirstOrDefaultAsync(a => a.Id == id); diff --git a/Controllers/HistoricoController.cs b/Controllers/HistoricoController.cs new file mode 100644 index 0000000..9540da6 --- /dev/null +++ b/Controllers/HistoricoController.cs @@ -0,0 +1,156 @@ +using System.Text.Json; +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/historico")] +[Authorize(Roles = "admin")] +public class HistoricoController : ControllerBase +{ + private readonly AppDbContext _db; + + public HistoricoController(AppDbContext db) + { + _db = db; + } + + [HttpGet] + public async Task>> GetAll( + [FromQuery] string? pageName, + [FromQuery] string? action, + [FromQuery] string? entity, + [FromQuery] Guid? userId, + [FromQuery] string? search, + [FromQuery] DateTime? dateFrom, + [FromQuery] DateTime? dateTo, + [FromQuery] int page = 1, + [FromQuery] int pageSize = 20) + { + page = page < 1 ? 1 : page; + pageSize = pageSize < 1 ? 20 : pageSize; + + var q = _db.AuditLogs.AsNoTracking(); + + if (!string.IsNullOrWhiteSpace(pageName)) + { + var p = pageName.Trim(); + q = q.Where(x => EF.Functions.ILike(x.Page, $"%{p}%")); + } + + if (!string.IsNullOrWhiteSpace(action)) + { + var a = action.Trim().ToUpperInvariant(); + q = q.Where(x => x.Action == a); + } + + if (!string.IsNullOrWhiteSpace(entity)) + { + var e = entity.Trim(); + q = q.Where(x => EF.Functions.ILike(x.EntityName, $"%{e}%")); + } + + if (userId.HasValue) + { + q = q.Where(x => x.UserId == userId.Value); + } + + if (!string.IsNullOrWhiteSpace(search)) + { + var s = search.Trim(); + q = q.Where(x => + EF.Functions.ILike(x.UserName ?? "", $"%{s}%") || + EF.Functions.ILike(x.UserEmail ?? "", $"%{s}%") || + EF.Functions.ILike(x.EntityName ?? "", $"%{s}%") || + EF.Functions.ILike(x.EntityLabel ?? "", $"%{s}%") || + EF.Functions.ILike(x.EntityId ?? "", $"%{s}%") || + EF.Functions.ILike(x.Page ?? "", $"%{s}%")); + } + + if (dateFrom.HasValue) + { + var fromUtc = ToUtc(dateFrom.Value); + q = q.Where(x => x.OccurredAtUtc >= fromUtc); + } + + if (dateTo.HasValue) + { + var toUtc = ToUtc(dateTo.Value); + if (dateTo.Value.TimeOfDay == TimeSpan.Zero) + { + toUtc = toUtc.Date.AddDays(1).AddTicks(-1); + } + + q = q.Where(x => x.OccurredAtUtc <= toUtc); + } + + var total = await q.CountAsync(); + + var items = await q + .OrderByDescending(x => x.OccurredAtUtc) + .ThenByDescending(x => x.Id) + .Skip((page - 1) * pageSize) + .Take(pageSize) + .ToListAsync(); + + return Ok(new PagedResult + { + Page = page, + PageSize = pageSize, + Total = total, + Items = items.Select(ToDto).ToList() + }); + } + + private static AuditLogDto ToDto(Models.AuditLog log) + { + return new AuditLogDto + { + Id = log.Id, + OccurredAtUtc = log.OccurredAtUtc, + Action = log.Action, + Page = log.Page, + EntityName = log.EntityName, + EntityId = log.EntityId, + EntityLabel = log.EntityLabel, + UserId = log.UserId, + UserName = log.UserName, + UserEmail = log.UserEmail, + RequestPath = log.RequestPath, + RequestMethod = log.RequestMethod, + IpAddress = log.IpAddress, + Changes = ParseChanges(log.ChangesJson) + }; + } + + private static List ParseChanges(string? json) + { + if (string.IsNullOrWhiteSpace(json)) + { + return new List(); + } + + try + { + return JsonSerializer.Deserialize>(json) ?? new List(); + } + catch + { + return new List(); + } + } + + private static DateTime ToUtc(DateTime value) + { + if (value.Kind == DateTimeKind.Utc) + return value; + if (value.Kind == DateTimeKind.Local) + return value.ToUniversalTime(); + + return DateTime.SpecifyKind(value, DateTimeKind.Utc); + } +} diff --git a/Controllers/LinesController.cs b/Controllers/LinesController.cs index 2ca0eeb..b181a93 100644 --- a/Controllers/LinesController.cs +++ b/Controllers/LinesController.cs @@ -23,6 +23,29 @@ namespace line_gestao_api.Controllers { private readonly AppDbContext _db; private readonly ParcelamentosImportService _parcelamentosImportService; + private static readonly List AccountCompanies = new() + { + new AccountCompanyDto + { + Empresa = "CLARO LINE MÓVEL", + Contas = new List { "172593311", "172593840" } + }, + new AccountCompanyDto + { + Empresa = "VIVO MACROPHONY", + Contas = new List { "0430237019", "0437488125", "0449508564", "0454371844" } + }, + new AccountCompanyDto + { + Empresa = "VIVO LINE MÓVEL", + Contas = new List { "0435288088" } + }, + new AccountCompanyDto + { + Empresa = "TIM LINE MÓVEL", + Contas = new List { "0072046192" } + } + }; public LinesController(AppDbContext db, ParcelamentosImportService parcelamentosImportService) { @@ -48,18 +71,30 @@ namespace line_gestao_api.Controllers page = page < 1 ? 1 : page; pageSize = pageSize < 1 ? 10 : pageSize; - var query = _db.MobileLines.AsNoTracking().Where(x => !string.IsNullOrEmpty(x.Cliente)); + var query = _db.MobileLines.AsNoTracking(); + var reservaFilter = false; // Filtro SKIL if (!string.IsNullOrWhiteSpace(skil)) { var sSkil = skil.Trim(); if (sSkil.Equals("RESERVA", StringComparison.OrdinalIgnoreCase)) - query = query.Where(x => x.Skil == "RESERVA" || EF.Functions.ILike(x.Skil ?? "", "%RESERVA%")); + { + reservaFilter = true; + query = query.Where(x => + EF.Functions.ILike((x.Cliente ?? "").Trim(), "%RESERVA%") || + EF.Functions.ILike((x.Usuario ?? "").Trim(), "%RESERVA%") || + EF.Functions.ILike((x.Skil ?? "").Trim(), "%RESERVA%")); + } else query = query.Where(x => EF.Functions.ILike(x.Skil ?? "", $"%{sSkil}%")); } + if (!reservaFilter) + { + query = query.Where(x => !string.IsNullOrEmpty(x.Cliente)); + } + // Filtro SEARCH (Busca pelo Nome do Cliente) if (!string.IsNullOrWhiteSpace(search)) { @@ -67,17 +102,27 @@ namespace line_gestao_api.Controllers query = query.Where(x => EF.Functions.ILike(x.Cliente ?? "", $"%{s}%")); } - var groupedQuery = query - .GroupBy(x => x.Cliente) - .Select(g => new ClientGroupDto - { - Cliente = g.Key!, - TotalLinhas = g.Count(), - Ativos = g.Count(x => EF.Functions.ILike(x.Status ?? "", "%ativo%")), - Bloqueados = g.Count(x => EF.Functions.ILike(x.Status ?? "", "%bloque%") || - EF.Functions.ILike(x.Status ?? "", "%perda%") || - EF.Functions.ILike(x.Status ?? "", "%roubo%")) - }); + var groupedQuery = reservaFilter + ? query.GroupBy(_ => "RESERVA") + .Select(g => new ClientGroupDto + { + Cliente = g.Key, + TotalLinhas = g.Count(), + Ativos = g.Count(x => EF.Functions.ILike(x.Status ?? "", "%ativo%")), + Bloqueados = g.Count(x => EF.Functions.ILike(x.Status ?? "", "%bloque%") || + EF.Functions.ILike(x.Status ?? "", "%perda%") || + EF.Functions.ILike(x.Status ?? "", "%roubo%")) + }) + : query.GroupBy(x => x.Cliente) + .Select(g => new ClientGroupDto + { + Cliente = g.Key!, + TotalLinhas = g.Count(), + Ativos = g.Count(x => EF.Functions.ILike(x.Status ?? "", "%ativo%")), + Bloqueados = g.Count(x => EF.Functions.ILike(x.Status ?? "", "%bloque%") || + EF.Functions.ILike(x.Status ?? "", "%perda%") || + EF.Functions.ILike(x.Status ?? "", "%roubo%")) + }); var totalGroups = await groupedQuery.CountAsync(); @@ -108,7 +153,10 @@ namespace line_gestao_api.Controllers { var sSkil = skil.Trim(); if (sSkil.Equals("RESERVA", StringComparison.OrdinalIgnoreCase)) - query = query.Where(x => x.Skil == "RESERVA" || EF.Functions.ILike(x.Skil ?? "", "%RESERVA%")); + query = query.Where(x => + EF.Functions.ILike((x.Cliente ?? "").Trim(), "%RESERVA%") || + EF.Functions.ILike((x.Usuario ?? "").Trim(), "%RESERVA%") || + EF.Functions.ILike((x.Skil ?? "").Trim(), "%RESERVA%")); else query = query.Where(x => EF.Functions.ILike(x.Skil ?? "", $"%{sSkil}%")); } @@ -207,6 +255,37 @@ namespace line_gestao_api.Controllers return Ok(clients); } + [HttpGet("account-companies")] + public ActionResult> GetAccountCompanies() + { + var items = AccountCompanies + .Select(x => new AccountCompanyDto + { + Empresa = x.Empresa, + Contas = x.Contas.ToList() + }) + .ToList(); + + return Ok(items); + } + + [HttpGet("accounts")] + public ActionResult> GetAccounts([FromQuery] string? empresa) + { + if (string.IsNullOrWhiteSpace(empresa)) + return Ok(new List()); + + var target = empresa.Trim(); + + var contas = AccountCompanies + .FirstOrDefault(x => string.Equals(x.Empresa, target, StringComparison.OrdinalIgnoreCase)) + ?.Contas + ?.ToList() + ?? new List(); + + return Ok(contas); + } + // ========================================================== // ✅ 2.1 ENDPOINT: LINHAS POR CLIENTE (para SELECT do MUREG) // GET: /api/lines/by-client?cliente=... @@ -262,7 +341,10 @@ namespace line_gestao_api.Controllers { var sSkil = skil.Trim(); if (sSkil.Equals("RESERVA", StringComparison.OrdinalIgnoreCase)) - q = q.Where(x => x.Skil == "RESERVA" || EF.Functions.ILike(x.Skil ?? "", "%RESERVA%")); + q = q.Where(x => + EF.Functions.ILike((x.Cliente ?? "").Trim(), "%RESERVA%") || + EF.Functions.ILike((x.Usuario ?? "").Trim(), "%RESERVA%") || + EF.Functions.ILike((x.Skil ?? "").Trim(), "%RESERVA%")); else q = q.Where(x => EF.Functions.ILike(x.Skil ?? "", $"%{sSkil}%")); } @@ -372,6 +454,10 @@ namespace line_gestao_api.Controllers var now = DateTime.UtcNow; + var planSuggestion = await AutoFillRules.ResolvePlanSuggestionAsync(_db, req.PlanoContrato); + var franquiaVivo = req.FranquiaVivo ?? planSuggestion?.FranquiaGb; + var valorPlanoVivo = req.ValorPlanoVivo ?? planSuggestion?.ValorPlano; + var newLine = new MobileLine { Id = Guid.NewGuid(), @@ -394,8 +480,8 @@ namespace line_gestao_api.Controllers Cedente = req.Cedente?.Trim(), Solicitante = req.Solicitante?.Trim(), - FranquiaVivo = req.FranquiaVivo, - ValorPlanoVivo = req.ValorPlanoVivo, + FranquiaVivo = franquiaVivo, + ValorPlanoVivo = valorPlanoVivo, GestaoVozDados = req.GestaoVozDados, Skeelo = req.Skeelo, VivoNewsPlus = req.VivoNewsPlus, @@ -879,6 +965,7 @@ namespace line_gestao_api.Controllers if (headerRow == null) return; var headerRowIndex = headerRow.RowNumber(); + var map = BuildHeaderMap(headerRow); // linha acima (grupos VIVO / LINE) var groupRowIndex = Math.Max(1, headerRowIndex - 1); @@ -943,8 +1030,6 @@ namespace line_gestao_api.Controllers if (colFranquiaVivo == 0 || colValorVivo == 0 || colFranquiaLine == 0 || colValorLine == 0) { - var map = BuildHeaderMap(headerRow); - if (colFranquiaLine == 0) colFranquiaLine = GetColAny(map, "FRAQUIA LINE", "FRANQUIA LINE", "FRANQUIALINE", "FRAQUIALINE"); @@ -973,6 +1058,9 @@ namespace line_gestao_api.Controllers "VALOR LINE"); } + var colRazao = GetColAny(map, "RAZAO SOCIAL", "RAZÃO SOCIAL", "RAZAOSOCIAL"); + var colNome = GetColAny(map, "NOME", "NOME COMPLETO"); + var startRow = headerRowIndex + 1; var lastRow = ws.LastRowUsed()?.RowNumber() ?? startRow; @@ -981,7 +1069,16 @@ namespace line_gestao_api.Controllers for (int r = startRow; r <= lastRow; r++) { - var cliente = GetCellString(ws, r, colCliente); + var cliente = colCliente > 0 ? GetCellString(ws, r, colCliente) : ""; + var nome = colNome > 0 ? GetCellString(ws, r, colNome) : ""; + var razao = colRazao > 0 ? GetCellString(ws, r, colRazao) : ""; + + if (string.IsNullOrWhiteSpace(cliente)) + { + if (!string.IsNullOrWhiteSpace(razao)) cliente = razao; + else if (!string.IsNullOrWhiteSpace(nome)) cliente = nome; + } + if (string.IsNullOrWhiteSpace(cliente)) break; seqItem++; @@ -1064,7 +1161,9 @@ namespace line_gestao_api.Controllers var headerRow = ws.RowsUsed().FirstOrDefault(r => r.CellsUsed().Any(c => NormalizeHeader(c.GetString()) == "ITEM" || - NormalizeHeader(c.GetString()) == "CLIENTE")); + NormalizeHeader(c.GetString()) == "CLIENTE" || + NormalizeHeader(c.GetString()) == "RAZAO SOCIAL" || + NormalizeHeader(c.GetString()) == "NOME")); if (headerRow == null) return; @@ -1072,9 +1171,11 @@ namespace line_gestao_api.Controllers var colItem = GetCol(map, "ITEM"); var colCliente = GetCol(map, "CLIENTE"); + var colRazao = GetColAny(map, "RAZAO SOCIAL", "RAZÃO SOCIAL", "RAZAOSOCIAL"); + var colNome = GetColAny(map, "NOME", "NOME COMPLETO"); var colLinha = GetCol(map, "LINHA"); - if (colCliente == 0) return; + if (colCliente == 0 && colRazao == 0 && colNome == 0) return; await _db.UserDatas.ExecuteDeleteAsync(); @@ -1085,6 +1186,7 @@ namespace line_gestao_api.Controllers var seq = 0; var colCpf = GetColAny(map, "CPF"); + var colCnpj = GetColAny(map, "CNPJ"); var colRg = GetColAny(map, "RG"); var colEmail = GetColAny(map, "EMAIL", "E-MAIL"); var colEndereco = GetColAny(map, "ENDERECO", "ENDEREÇO"); @@ -1101,8 +1203,16 @@ namespace line_gestao_api.Controllers for (int r = startRow; r <= lastRow; r++) { - var cliente = GetCellString(ws, r, colCliente); - if (string.IsNullOrWhiteSpace(cliente)) break; + var cliente = colCliente > 0 ? GetCellString(ws, r, colCliente) : ""; + var razao = colRazao > 0 ? GetCellString(ws, r, colRazao) : ""; + var nome = colNome > 0 ? GetCellString(ws, r, colNome) : ""; + + if (string.IsNullOrWhiteSpace(cliente) && string.IsNullOrWhiteSpace(razao) && string.IsNullOrWhiteSpace(nome)) break; + + if (string.IsNullOrWhiteSpace(cliente)) + { + cliente = !string.IsNullOrWhiteSpace(razao) ? razao : nome; + } seq++; @@ -1117,6 +1227,7 @@ namespace line_gestao_api.Controllers var linha = colLinha > 0 ? NullIfEmptyDigits(GetCellString(ws, r, colLinha)) : null; var cpf = colCpf > 0 ? NullIfEmptyDigits(GetCellString(ws, r, colCpf)) : null; + var cnpj = colCnpj > 0 ? NullIfEmptyDigits(GetCellString(ws, r, colCnpj)) : null; var rg = colRg > 0 ? NullIfEmptyDigits(GetCellString(ws, r, colRg)) : null; DateTime? dataNascimento = null; @@ -1131,6 +1242,13 @@ namespace line_gestao_api.Controllers var now = DateTime.UtcNow; + var tipoPessoa = !string.IsNullOrWhiteSpace(cnpj) || !string.IsNullOrWhiteSpace(razao) + ? "PJ" + : "PF"; + + var nomeFinal = string.IsNullOrWhiteSpace(nome) ? cliente : nome.Trim(); + var razaoFinal = string.IsNullOrWhiteSpace(razao) ? cliente : razao.Trim(); + var e = new UserData { Id = Guid.NewGuid(), @@ -1138,6 +1256,10 @@ namespace line_gestao_api.Controllers Linha = linha, Cliente = cliente.Trim(), + TipoPessoa = tipoPessoa, + Nome = tipoPessoa == "PF" ? nomeFinal : null, + RazaoSocial = tipoPessoa == "PJ" ? razaoFinal : null, + Cnpj = tipoPessoa == "PJ" ? cnpj : null, Cpf = cpf, Rg = rg, DataNascimento = ToUtc(dataNascimento), @@ -2022,9 +2144,12 @@ namespace line_gestao_api.Controllers var buffer = new List(200); string? lastDddValid = null; + decimal? lastTotalForDdd = null; var dataStarted = false; var emptyRowStreak = 0; int? totalRowIndex = null; + var totalsFromSheetByDdd = new Dictionary(); + var sumQtdByDdd = new Dictionary(); for (int r = headerRow + 1; r <= lastRowUsed; r++) { @@ -2050,23 +2175,36 @@ namespace line_gestao_api.Controllers emptyRowStreak = 0; - var franquiaValue = TryDecimal(franquia); - var qtdValue = TryNullableInt(qtdLinhas); - var isDataRow = franquiaValue.HasValue || qtdValue.HasValue; var dddCandidate = NullIfEmptyDigits(ddd); + var hasFranquiaText = !string.IsNullOrWhiteSpace(franquia); + var hasQtdText = !string.IsNullOrWhiteSpace(qtdLinhas); + var hasTotalText = !string.IsNullOrWhiteSpace(total); - if (!string.IsNullOrWhiteSpace(dddCandidate)) - { - lastDddValid = dddCandidate; - } + // ✅ Rodapé "TOTAL GERAL" (DDD vazio + franquia vazia + qtd + total preenchidos) + var isTotalGeralRow = string.IsNullOrWhiteSpace(dddCandidate) + && !hasFranquiaText + && hasQtdText + && hasTotalText; - var isTotalRow = !isDataRow && !string.IsNullOrWhiteSpace(total); - if (isTotalRow) + if (isTotalGeralRow) { totalRowIndex = r; break; } + var franquiaValue = TryDecimal(franquia); + var qtdValue = TryNullableInt(qtdLinhas); + var isDataRow = franquiaValue.HasValue || qtdValue.HasValue; + + if (!string.IsNullOrWhiteSpace(dddCandidate)) + { + if (!string.Equals(lastDddValid, dddCandidate, StringComparison.OrdinalIgnoreCase)) + { + lastTotalForDdd = null; + } + lastDddValid = dddCandidate; + } + if (!isDataRow && dataStarted) { break; @@ -2079,13 +2217,26 @@ namespace line_gestao_api.Controllers : dddCandidate; var totalValue = TryDecimal(total); + if (!string.IsNullOrWhiteSpace(resolvedDdd) && totalValue.HasValue) + { + lastTotalForDdd = totalValue; + totalsFromSheetByDdd[resolvedDdd] = totalValue; + } + + if (!string.IsNullOrWhiteSpace(resolvedDdd) && qtdValue.HasValue) + { + if (sumQtdByDdd.TryGetValue(resolvedDdd, out var acc)) + sumQtdByDdd[resolvedDdd] = acc + qtdValue.Value; + else + sumQtdByDdd[resolvedDdd] = qtdValue.Value; + } buffer.Add(new ResumoReservaLine { Ddd = string.IsNullOrWhiteSpace(resolvedDdd) ? null : resolvedDdd, FranquiaGb = franquiaValue, QtdLinhas = qtdValue, - Total = totalValue, + Total = totalValue ?? lastTotalForDdd, CreatedAt = now, UpdatedAt = now }); @@ -2103,6 +2254,33 @@ namespace line_gestao_api.Controllers await _db.SaveChangesAsync(); } + if (totalsFromSheetByDdd.Count > 0) + { + foreach (var kv in totalsFromSheetByDdd) + { + if (!kv.Value.HasValue) continue; + if (!sumQtdByDdd.TryGetValue(kv.Key, out var sum)) continue; + var totalInt = (int)Math.Round(kv.Value.Value); + if (totalInt != sum) + { + Console.WriteLine($"[WARN] RESUMO/RESERVA DDD {kv.Key}: TOTAL(planilha)={totalInt} vs SOMA(QTD)={sum}"); + } + } + } + + var totalGeralLinhasReserva = totalRowIndex.HasValue + ? TryNullableInt(GetCellString(ws, totalRowIndex.Value, colQtdLinhas)) + : null; + + if (totalGeralLinhasReserva.HasValue) + { + var somaPorDdd = sumQtdByDdd.Values.Sum(); + if (somaPorDdd != totalGeralLinhasReserva.Value) + { + Console.WriteLine($"[WARN] RESUMO/RESERVA TOTAL GERAL: planilha={totalGeralLinhasReserva.Value} vs SOMA(DDD)={somaPorDdd}"); + } + } + if (totalRowIndex == null) { return; @@ -2110,6 +2288,7 @@ namespace line_gestao_api.Controllers var totalEntity = new ResumoReservaTotal { + TotalGeralLinhasReserva = totalGeralLinhasReserva, QtdLinhasTotal = TryNullableInt(GetCellString(ws, totalRowIndex.Value, colQtdLinhas)), Total = TryDecimal(GetCellString(ws, totalRowIndex.Value, colTotal)), CreatedAt = now, @@ -2458,7 +2637,7 @@ namespace line_gestao_api.Controllers private static void ApplyReservaRule(MobileLine x) { - if ((x.Cliente ?? "").Trim().ToUpper() == "RESERVA" || (x.Usuario ?? "").Trim().ToUpper() == "RESERVA") + if (IsReservaValue(x.Cliente) || IsReservaValue(x.Usuario) || IsReservaValue(x.Skil)) { x.Cliente = "RESERVA"; x.Usuario = "RESERVA"; @@ -2466,6 +2645,9 @@ namespace line_gestao_api.Controllers } } + private static bool IsReservaValue(string? value) + => string.Equals(value?.Trim(), "RESERVA", StringComparison.OrdinalIgnoreCase); + private static int GetCol(Dictionary map, string name) => map.TryGetValue(NormalizeHeader(name), out var c) ? c : 0; diff --git a/Controllers/ParcelamentosController.cs b/Controllers/ParcelamentosController.cs index 989d143..4f655ca 100644 --- a/Controllers/ParcelamentosController.cs +++ b/Controllers/ParcelamentosController.cs @@ -1,5 +1,6 @@ using line_gestao_api.Data; using line_gestao_api.Dtos; +using line_gestao_api.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -57,26 +58,54 @@ public class ParcelamentosController : ControllerBase } var total = await query.CountAsync(); + var today = DateOnly.FromDateTime(DateTime.Today); - var items = await query + var rows = await query .OrderBy(x => x.Item) .Skip((page - 1) * pageSize) .Take(pageSize) - .Select(x => new ParcelamentoListDto + .Select(x => new + { + x.Id, + x.AnoRef, + x.Item, + x.Linha, + x.Cliente, + x.QtParcelas, + x.ParcelaAtual, + x.TotalParcelas, + x.ValorCheio, + x.Desconto, + x.ValorComDesconto, + ParcelaAtualCalc = x.MonthValues.Count(m => m.Competencia <= today), + TotalMeses = x.MonthValues.Count() + }) + .ToListAsync(); + + var items = rows.Select(x => + { + var (parcelaAtual, totalParcelas) = ResolveParcelasFromCounts( + x.ParcelaAtual, + x.TotalParcelas, + x.QtParcelas, + x.ParcelaAtualCalc, + x.TotalMeses); + + return 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, + QtParcelas = BuildQtParcelas(parcelaAtual, totalParcelas, x.QtParcelas), + ParcelaAtual = parcelaAtual, + TotalParcelas = totalParcelas, ValorCheio = x.ValorCheio, Desconto = x.Desconto, ValorComDesconto = x.ValorComDesconto - }) - .ToListAsync(); + }; + }).ToList(); return Ok(new PagedResult { @@ -90,39 +119,308 @@ public class ParcelamentosController : ControllerBase [HttpGet("{id:guid}")] public async Task> GetById(Guid id) { - var item = await _db.ParcelamentoLines + var entity = await _db.ParcelamentoLines .AsNoTracking() .Include(x => x.MonthValues) .FirstOrDefaultAsync(x => x.Id == id); - if (item == null) + if (entity == null) { return NotFound(); } + var monthValues = entity.MonthValues + .OrderBy(m => m.Competencia) + .Select(m => new ParcelamentoMonthDto + { + Competencia = m.Competencia, + Valor = m.Valor + }) + .ToList(); + + var (parcelaAtual, totalParcelas) = ResolveParcelasFromCompetencias( + entity.ParcelaAtual, + entity.TotalParcelas, + entity.QtParcelas, + monthValues.Select(m => m.Competencia)); + 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() + Id = entity.Id, + AnoRef = entity.AnoRef, + Item = entity.Item, + Linha = entity.Linha, + Cliente = entity.Cliente, + QtParcelas = BuildQtParcelas(parcelaAtual, totalParcelas, entity.QtParcelas), + ParcelaAtual = parcelaAtual, + TotalParcelas = totalParcelas, + ValorCheio = entity.ValorCheio, + Desconto = entity.Desconto, + ValorComDesconto = entity.ValorComDesconto, + MonthValues = monthValues, + AnnualRows = BuildAnnualRows(monthValues) }; return Ok(dto); } + + [HttpPost] + public async Task> Create([FromBody] ParcelamentoUpsertDto req) + { + var now = DateTime.UtcNow; + var entity = new ParcelamentoLine + { + Id = Guid.NewGuid(), + AnoRef = req.AnoRef, + Item = req.Item, + Linha = TrimOrNull(req.Linha), + Cliente = TrimOrNull(req.Cliente), + QtParcelas = TrimOrNull(req.QtParcelas), + ParcelaAtual = req.ParcelaAtual, + TotalParcelas = req.TotalParcelas, + ValorCheio = req.ValorCheio, + Desconto = req.Desconto, + ValorComDesconto = ResolveValorComDesconto(req.ValorComDesconto, req.ValorCheio, req.Desconto), + CreatedAt = now, + UpdatedAt = now + }; + + if (req.AnoRef.HasValue && req.Item.HasValue) + { + var exists = await _db.ParcelamentoLines.AnyAsync(x => x.AnoRef == req.AnoRef && x.Item == req.Item); + if (exists) return Conflict("Já existe um parcelamento com o mesmo AnoRef e Item."); + } + + entity.MonthValues = BuildMonthValues(req.MonthValues, entity.Id, now); + ApplyComputedParcelas(entity); + + _db.ParcelamentoLines.Add(entity); + await _db.SaveChangesAsync(); + + return CreatedAtAction(nameof(GetById), new { id = entity.Id }, ToDetailDto(entity)); + } + + [HttpPut("{id:guid}")] + public async Task Update(Guid id, [FromBody] ParcelamentoUpsertDto req) + { + var entity = await _db.ParcelamentoLines + .Include(x => x.MonthValues) + .FirstOrDefaultAsync(x => x.Id == id); + + if (entity == null) return NotFound(); + + if (req.AnoRef.HasValue && req.Item.HasValue) + { + var exists = await _db.ParcelamentoLines.AnyAsync(x => + x.Id != id && x.AnoRef == req.AnoRef && x.Item == req.Item); + if (exists) return Conflict("Já existe um parcelamento com o mesmo AnoRef e Item."); + } + + entity.AnoRef = req.AnoRef; + entity.Item = req.Item; + entity.Linha = TrimOrNull(req.Linha); + entity.Cliente = TrimOrNull(req.Cliente); + entity.QtParcelas = TrimOrNull(req.QtParcelas); + entity.ParcelaAtual = req.ParcelaAtual; + entity.TotalParcelas = req.TotalParcelas; + entity.ValorCheio = req.ValorCheio; + entity.Desconto = req.Desconto; + entity.ValorComDesconto = ResolveValorComDesconto(req.ValorComDesconto, req.ValorCheio, req.Desconto); + entity.UpdatedAt = DateTime.UtcNow; + + _db.ParcelamentoMonthValues.RemoveRange(entity.MonthValues); + entity.MonthValues = BuildMonthValues(req.MonthValues, entity.Id, entity.UpdatedAt); + ApplyComputedParcelas(entity); + + await _db.SaveChangesAsync(); + return NoContent(); + } + + [HttpDelete("{id:guid}")] + [Authorize(Roles = "admin")] + public async Task Delete(Guid id) + { + var entity = await _db.ParcelamentoLines.FirstOrDefaultAsync(x => x.Id == id); + if (entity == null) return NotFound(); + + _db.ParcelamentoLines.Remove(entity); + await _db.SaveChangesAsync(); + return NoContent(); + } + + private static List BuildAnnualRows(List monthValues) + { + if (monthValues.Count == 0) return new List(); + + var groups = monthValues + .GroupBy(m => m.Competencia.Year) + .OrderBy(g => g.Key); + + var rows = new List(); + foreach (var group in groups) + { + var monthMap = group + .GroupBy(m => m.Competencia.Month) + .ToDictionary(g => g.Key, g => g.Sum(x => x.Valor ?? 0m)); + + var months = Enumerable.Range(1, 12) + .Select(month => new ParcelamentoAnnualMonthDto + { + Month = month, + Valor = monthMap.TryGetValue(month, out var value) ? value : null + }) + .ToList(); + + var total = months.Sum(m => m.Valor ?? 0m); + + rows.Add(new ParcelamentoAnnualRowDto + { + Year = group.Key, + Total = total, + Months = months + }); + } + + return rows; + } + + private static List BuildMonthValues( + List inputs, + Guid parcelamentoId, + DateTime now) + { + var map = new Dictionary(); + foreach (var input in inputs ?? new List()) + { + if (input.Competencia == default) continue; + map[input.Competencia] = input.Valor; + } + + return map + .OrderBy(x => x.Key) + .Select(x => new ParcelamentoMonthValue + { + Id = Guid.NewGuid(), + ParcelamentoLineId = parcelamentoId, + Competencia = x.Key, + Valor = x.Value, + CreatedAt = now + }) + .ToList(); + } + + private static void ApplyComputedParcelas(ParcelamentoLine entity) + { + var competencias = entity.MonthValues.Select(m => m.Competencia).ToList(); + var (parcelaAtual, totalParcelas) = ResolveParcelasFromCompetencias( + entity.ParcelaAtual, + entity.TotalParcelas, + entity.QtParcelas, + competencias); + + entity.ParcelaAtual = parcelaAtual; + entity.TotalParcelas = totalParcelas; + entity.QtParcelas = BuildQtParcelas(parcelaAtual, totalParcelas, entity.QtParcelas); + } + + private static ParcelamentoDetailDto ToDetailDto(ParcelamentoLine entity) + { + var monthValues = entity.MonthValues + .OrderBy(m => m.Competencia) + .Select(m => new ParcelamentoMonthDto + { + Competencia = m.Competencia, + Valor = m.Valor + }) + .ToList(); + + var (parcelaAtual, totalParcelas) = ResolveParcelasFromCompetencias( + entity.ParcelaAtual, + entity.TotalParcelas, + entity.QtParcelas, + monthValues.Select(m => m.Competencia)); + + return new ParcelamentoDetailDto + { + Id = entity.Id, + AnoRef = entity.AnoRef, + Item = entity.Item, + Linha = entity.Linha, + Cliente = entity.Cliente, + QtParcelas = BuildQtParcelas(parcelaAtual, totalParcelas, entity.QtParcelas), + ParcelaAtual = parcelaAtual, + TotalParcelas = totalParcelas, + ValorCheio = entity.ValorCheio, + Desconto = entity.Desconto, + ValorComDesconto = entity.ValorComDesconto, + MonthValues = monthValues, + AnnualRows = BuildAnnualRows(monthValues) + }; + } + + private static (int? ParcelaAtual, int? TotalParcelas) ResolveParcelasFromCounts( + int? storedAtual, + int? storedTotal, + string? qtParcelas, + int mesesAteHoje, + int totalMeses) + { + var total = storedTotal ?? ParseQtParcelas(qtParcelas).Total ?? (totalMeses > 0 ? totalMeses : (int?)null); + int? atual = totalMeses > 0 ? mesesAteHoje : storedAtual ?? ParseQtParcelas(qtParcelas).Atual; + if (atual.HasValue && atual.Value < 0) atual = 0; + if (total.HasValue && atual.HasValue) + { + atual = Math.Min(atual.Value, total.Value); + } + return (atual, total); + } + + private static (int? ParcelaAtual, int? TotalParcelas) ResolveParcelasFromCompetencias( + int? storedAtual, + int? storedTotal, + string? qtParcelas, + IEnumerable competencias) + { + var list = competencias?.ToList() ?? new List(); + var totalMeses = list.Count; + var hoje = DateOnly.FromDateTime(DateTime.Today); + var mesesAteHoje = list.Count(c => c <= hoje); + return ResolveParcelasFromCounts(storedAtual, storedTotal, qtParcelas, mesesAteHoje, totalMeses); + } + + private static (int? Atual, int? Total) ParseQtParcelas(string? raw) + { + if (string.IsNullOrWhiteSpace(raw)) return (null, null); + var parts = raw.Split('/', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); + int? atual = null; + int? total = null; + if (parts.Length >= 1 && int.TryParse(OnlyDigits(parts[0]), out var a)) atual = a; + if (parts.Length >= 2 && int.TryParse(OnlyDigits(parts[1]), out var t)) total = t; + return (atual, total); + } + + private static string? BuildQtParcelas(int? atual, int? total, string? fallback) + { + if (atual.HasValue && total.HasValue) return $"{atual}/{total}"; + return string.IsNullOrWhiteSpace(fallback) ? null : fallback.Trim(); + } + + private static decimal? ResolveValorComDesconto(decimal? valorCom, decimal? valorCheio, decimal? desconto) + { + if (valorCom.HasValue) return valorCom; + if (!valorCheio.HasValue) return null; + return Math.Max(0, valorCheio.Value - (desconto ?? 0m)); + } + + private static string? TrimOrNull(string? s) + { + if (string.IsNullOrWhiteSpace(s)) return null; + return s.Trim(); + } + + private static string OnlyDigits(string? s) + { + if (string.IsNullOrWhiteSpace(s)) return ""; + return new string(s.Where(char.IsDigit).ToArray()); + } } diff --git a/Controllers/RelatoriosController.cs b/Controllers/RelatoriosController.cs index ff10924..5e56512 100644 --- a/Controllers/RelatoriosController.cs +++ b/Controllers/RelatoriosController.cs @@ -59,9 +59,9 @@ namespace line_gestao_api.Controllers var bloqueados = bloqueadosPerdaRoubo + bloqueados120Dias + bloqueadosOutros; var reservas = await qLines.CountAsync(x => - (x.Cliente ?? "").ToUpper() == "RESERVA" || - (x.Usuario ?? "").ToUpper() == "RESERVA" || - (x.Skil ?? "").ToUpper() == "RESERVA"); + EF.Functions.ILike((x.Cliente ?? "").Trim(), "%RESERVA%") || + EF.Functions.ILike((x.Usuario ?? "").Trim(), "%RESERVA%") || + EF.Functions.ILike((x.Skil ?? "").Trim(), "%RESERVA%")); var topClientes = await qLines .Where(x => x.Cliente != null && x.Cliente != "") diff --git a/Controllers/ResumoController.cs b/Controllers/ResumoController.cs index 51ef6d9..670ef8c 100644 --- a/Controllers/ResumoController.cs +++ b/Controllers/ResumoController.cs @@ -21,6 +21,32 @@ public class ResumoController : ControllerBase [HttpGet] public async Task> GetResumo() { + var reservaLines = await _db.ResumoReservaLines.AsNoTracking() + .OrderBy(x => x.Ddd) + .ToListAsync(); + + var reservaPorDdd = reservaLines + .Where(x => !string.IsNullOrWhiteSpace(x.Ddd)) + .GroupBy(x => x.Ddd!.Trim()) + .Select(g => new ResumoReservaPorDddDto + { + Ddd = g.Key, + TotalLinhas = g.Sum(x => x.QtdLinhas ?? 0), + PorFranquia = g.GroupBy(x => x.FranquiaGb) + .Select(fg => new ResumoReservaPorFranquiaDto + { + FranquiaGb = fg.Key, + TotalLinhas = fg.Sum(x => x.QtdLinhas ?? 0) + }) + .OrderBy(x => x.FranquiaGb) + .ToList() + }) + .OrderBy(x => x.Ddd) + .ToList(); + + var reservaTotalEntity = await _db.ResumoReservaTotals.AsNoTracking() + .FirstOrDefaultAsync(); + var response = new ResumoResponseDto { MacrophonyPlans = await _db.ResumoMacrophonyPlans.AsNoTracking() @@ -105,8 +131,7 @@ public class ResumoController : ControllerBase QtdLinhas = x.QtdLinhas }) .ToListAsync(), - ReservaLines = await _db.ResumoReservaLines.AsNoTracking() - .OrderBy(x => x.Ddd) + ReservaLines = reservaLines .Select(x => new ResumoReservaLineDto { Ddd = x.Ddd, @@ -114,14 +139,16 @@ public class ResumoController : ControllerBase QtdLinhas = x.QtdLinhas, Total = x.Total }) - .ToListAsync(), - ReservaTotal = await _db.ResumoReservaTotals.AsNoTracking() - .Select(x => new ResumoReservaTotalDto - { - QtdLinhasTotal = x.QtdLinhasTotal, - Total = x.Total - }) - .FirstOrDefaultAsync() + .ToList(), + ReservaPorDdd = reservaPorDdd, + TotalGeralLinhasReserva = reservaTotalEntity?.TotalGeralLinhasReserva + ?? reservaTotalEntity?.QtdLinhasTotal + ?? reservaPorDdd.Sum(x => x.TotalLinhas), + ReservaTotal = reservaTotalEntity == null ? null : new ResumoReservaTotalDto + { + QtdLinhasTotal = reservaTotalEntity.QtdLinhasTotal, + Total = reservaTotalEntity.Total + } }; return Ok(response); diff --git a/Controllers/UserDataController.cs b/Controllers/UserDataController.cs index 7ca64e4..e23bac3 100644 --- a/Controllers/UserDataController.cs +++ b/Controllers/UserDataController.cs @@ -1,7 +1,10 @@ using line_gestao_api.Data; using line_gestao_api.Dtos; +using line_gestao_api.Models; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using System.Linq; namespace line_gestao_api.Controllers { @@ -19,6 +22,7 @@ namespace line_gestao_api.Controllers public async Task>> GetAll( [FromQuery] string? search, [FromQuery] string? client, // Filtro por cliente + [FromQuery] string? tipo, // PF/PJ [FromQuery] int page = 1, [FromQuery] int pageSize = 20, [FromQuery] string? sortBy = "item", @@ -36,6 +40,12 @@ namespace line_gestao_api.Controllers q = q.Where(x => x.Cliente == c); } + if (!string.IsNullOrWhiteSpace(tipo)) + { + var t = tipo.Trim().ToUpperInvariant(); + if (t == "PF" || t == "PJ") q = q.Where(x => x.TipoPessoa == t); + } + // Busca global if (!string.IsNullOrWhiteSpace(search)) { @@ -43,7 +53,10 @@ namespace line_gestao_api.Controllers q = q.Where(x => EF.Functions.ILike(x.Linha ?? "", $"%{s}%") || EF.Functions.ILike(x.Cliente ?? "", $"%{s}%") || + EF.Functions.ILike(x.Nome ?? "", $"%{s}%") || + EF.Functions.ILike(x.RazaoSocial ?? "", $"%{s}%") || EF.Functions.ILike(x.Cpf ?? "", $"%{s}%") || + EF.Functions.ILike(x.Cnpj ?? "", $"%{s}%") || EF.Functions.ILike(x.Email ?? "", $"%{s}%") || EF.Functions.ILike(x.Celular ?? "", $"%{s}%")); } @@ -70,6 +83,10 @@ namespace line_gestao_api.Controllers Item = x.Item, Linha = x.Linha, Cliente = x.Cliente, + TipoPessoa = x.TipoPessoa, + Nome = x.Nome, + RazaoSocial = x.RazaoSocial, + Cnpj = x.Cnpj, Cpf = x.Cpf, Rg = x.Rg, DataNascimento = x.DataNascimento != null ? x.DataNascimento.Value.ToString("yyyy-MM-dd") : null, @@ -95,6 +112,7 @@ namespace line_gestao_api.Controllers [HttpGet("groups")] public async Task> GetGroups( [FromQuery] string? search, + [FromQuery] string? tipo, [FromQuery] int page = 1, [FromQuery] int pageSize = 10, [FromQuery] string? sortBy = "cliente", @@ -106,6 +124,12 @@ namespace line_gestao_api.Controllers var q = _db.UserDatas.AsNoTracking() .Where(x => x.Cliente != null && x.Cliente != ""); + if (!string.IsNullOrWhiteSpace(tipo)) + { + var t = tipo.Trim().ToUpperInvariant(); + if (t == "PF" || t == "PJ") q = q.Where(x => x.TipoPessoa == t); + } + if (!string.IsNullOrWhiteSpace(search)) { var s = search.Trim(); @@ -118,6 +142,7 @@ namespace line_gestao_api.Controllers TotalRegistros = await q.CountAsync(), ClientesUnicos = await q.Select(x => x.Cliente).Distinct().CountAsync(), ComCpf = await q.CountAsync(x => x.Cpf != null && x.Cpf != ""), + ComCnpj = await q.CountAsync(x => x.Cnpj != null && x.Cnpj != ""), ComEmail = await q.CountAsync(x => x.Email != null && x.Email != "") }; @@ -129,6 +154,7 @@ namespace line_gestao_api.Controllers Cliente = g.Key, TotalRegistros = g.Count(), ComCpf = g.Count(x => x.Cpf != null && x.Cpf != ""), + ComCnpj = g.Count(x => x.Cnpj != null && x.Cnpj != ""), ComEmail = g.Count(x => x.Email != null && x.Email != "") }); @@ -158,9 +184,17 @@ namespace line_gestao_api.Controllers } [HttpGet("clients")] - public async Task>> GetClients() + public async Task>> GetClients([FromQuery] string? tipo) { - return await _db.UserDatas.AsNoTracking() + var q = _db.UserDatas.AsNoTracking(); + + if (!string.IsNullOrWhiteSpace(tipo)) + { + var t = tipo.Trim().ToUpperInvariant(); + if (t == "PF" || t == "PJ") q = q.Where(x => x.TipoPessoa == t); + } + + return await q .Where(x => !string.IsNullOrEmpty(x.Cliente)) .Select(x => x.Cliente!) .Distinct() @@ -180,6 +214,10 @@ namespace line_gestao_api.Controllers Item = x.Item, Linha = x.Linha, Cliente = x.Cliente, + TipoPessoa = x.TipoPessoa, + Nome = x.Nome, + RazaoSocial = x.RazaoSocial, + Cnpj = x.Cnpj, Cpf = x.Cpf, Rg = x.Rg, Email = x.Email, @@ -189,5 +227,184 @@ namespace line_gestao_api.Controllers DataNascimento = x.DataNascimento }); } + + [HttpPost] + [Authorize(Roles = "admin")] + public async Task> Create([FromBody] CreateUserDataRequest req) + { + var now = DateTime.UtcNow; + + var linha = TrimOrNull(req.Linha); + var cliente = TrimOrNull(req.Cliente); + var nome = TrimOrNull(req.Nome); + var razao = TrimOrNull(req.RazaoSocial); + var cpf = NullIfEmptyDigits(req.Cpf); + var cnpj = NullIfEmptyDigits(req.Cnpj); + var tipo = NormalizeTipo(req.TipoPessoa, cpf, cnpj, razao, nome); + + if (string.IsNullOrWhiteSpace(cliente) && !string.IsNullOrWhiteSpace(linha)) + { + var linhaDigits = OnlyDigits(linha); + MobileLine? mobile = null; + + if (!string.IsNullOrWhiteSpace(linhaDigits)) + { + mobile = await _db.MobileLines.AsNoTracking() + .FirstOrDefaultAsync(x => x.Linha == linhaDigits); + } + else + { + var raw = linha.Trim(); + mobile = await _db.MobileLines.AsNoTracking() + .FirstOrDefaultAsync(x => EF.Functions.ILike(x.Linha ?? "", raw)); + } + + if (mobile != null) + { + cliente = mobile.Cliente; + if (string.IsNullOrWhiteSpace(tipo)) + { + var skil = (mobile.Skil ?? "").Trim().ToUpperInvariant(); + if (skil.Contains("JUR")) tipo = "PJ"; + else if (skil.Contains("FIS")) tipo = "PF"; + } + } + } + + if (string.IsNullOrWhiteSpace(cliente)) + { + cliente = !string.IsNullOrWhiteSpace(razao) ? razao : nome; + } + + if (string.IsNullOrWhiteSpace(nome) && tipo == "PF") nome = cliente; + if (string.IsNullOrWhiteSpace(razao) && tipo == "PJ") razao = cliente; + + var item = req.Item; + if (!item.HasValue || item.Value <= 0) + { + var maxItem = await _db.UserDatas.MaxAsync(x => (int?)x.Item) ?? 0; + item = maxItem + 1; + } + + var e = new UserData + { + Id = Guid.NewGuid(), + Item = item.Value, + Linha = linha, + Cliente = cliente, + TipoPessoa = tipo ?? "PF", + Nome = nome, + RazaoSocial = razao, + Cnpj = cnpj, + Cpf = cpf, + Rg = TrimOrNull(req.Rg), + Email = TrimOrNull(req.Email), + Endereco = TrimOrNull(req.Endereco), + Celular = TrimOrNull(req.Celular), + TelefoneFixo = TrimOrNull(req.TelefoneFixo), + DataNascimento = req.DataNascimento.HasValue ? ToUtc(req.DataNascimento.Value) : null, + CreatedAt = now, + UpdatedAt = now + }; + + _db.UserDatas.Add(e); + await _db.SaveChangesAsync(); + + return CreatedAtAction(nameof(GetById), new { id = e.Id }, new UserDataDetailDto + { + Id = e.Id, + Item = e.Item, + Linha = e.Linha, + Cliente = e.Cliente, + TipoPessoa = e.TipoPessoa, + Nome = e.Nome, + RazaoSocial = e.RazaoSocial, + Cnpj = e.Cnpj, + Cpf = e.Cpf, + Rg = e.Rg, + Email = e.Email, + Celular = e.Celular, + Endereco = e.Endereco, + TelefoneFixo = e.TelefoneFixo, + DataNascimento = e.DataNascimento + }); + } + + [HttpPut("{id:guid}")] + [Authorize(Roles = "admin")] + public async Task Update(Guid id, [FromBody] UpdateUserDataRequest req) + { + var x = await _db.UserDatas.FirstOrDefaultAsync(a => a.Id == id); + if (x == null) return NotFound(); + + if (req.Item.HasValue) x.Item = req.Item.Value; + if (req.Linha != null) x.Linha = TrimOrNull(req.Linha); + if (req.Cliente != null) x.Cliente = TrimOrNull(req.Cliente); + if (req.TipoPessoa != null) x.TipoPessoa = NormalizeTipo(req.TipoPessoa, req.Cpf, req.Cnpj, req.RazaoSocial, req.Nome) ?? x.TipoPessoa; + if (req.Nome != null) x.Nome = TrimOrNull(req.Nome); + if (req.RazaoSocial != null) x.RazaoSocial = TrimOrNull(req.RazaoSocial); + if (req.Cnpj != null) x.Cnpj = NullIfEmptyDigits(req.Cnpj); + if (req.Cpf != null) x.Cpf = NullIfEmptyDigits(req.Cpf); + if (req.Rg != null) x.Rg = TrimOrNull(req.Rg); + if (req.Email != null) x.Email = TrimOrNull(req.Email); + if (req.Endereco != null) x.Endereco = TrimOrNull(req.Endereco); + if (req.Celular != null) x.Celular = TrimOrNull(req.Celular); + if (req.TelefoneFixo != null) x.TelefoneFixo = TrimOrNull(req.TelefoneFixo); + + if (req.DataNascimento.HasValue) + { + x.DataNascimento = ToUtc(req.DataNascimento.Value); + } + + x.UpdatedAt = DateTime.UtcNow; + + await _db.SaveChangesAsync(); + return NoContent(); + } + + [HttpDelete("{id:guid}")] + [Authorize(Roles = "admin")] + public async Task Delete(Guid id) + { + var x = await _db.UserDatas.FirstOrDefaultAsync(a => a.Id == id); + if (x == null) return NotFound(); + + _db.UserDatas.Remove(x); + await _db.SaveChangesAsync(); + return NoContent(); + } + + private static string? TrimOrNull(string? s) + { + if (string.IsNullOrWhiteSpace(s)) return null; + return s.Trim(); + } + + private static DateTime ToUtc(DateTime dt) + { + return dt.Kind == DateTimeKind.Utc ? dt + : (dt.Kind == DateTimeKind.Local ? dt.ToUniversalTime() : DateTime.SpecifyKind(dt, DateTimeKind.Utc)); + } + + private static string? NormalizeTipo(string? tipo, string? cpf, string? cnpj, string? razao, string? nome) + { + var t = (tipo ?? "").Trim().ToUpperInvariant(); + if (t == "PF" || t == "PJ") return t; + if (!string.IsNullOrWhiteSpace(cnpj) || !string.IsNullOrWhiteSpace(razao)) return "PJ"; + if (!string.IsNullOrWhiteSpace(cpf) || !string.IsNullOrWhiteSpace(nome)) return "PF"; + return null; + } + + private static string? NullIfEmptyDigits(string? s) + { + var d = OnlyDigits(s); + return string.IsNullOrWhiteSpace(d) ? null : d; + } + + private static string OnlyDigits(string? s) + { + if (string.IsNullOrWhiteSpace(s)) return ""; + return new string(s.Where(char.IsDigit).ToArray()); + } } -} \ No newline at end of file +} diff --git a/Controllers/VigenciaController.cs b/Controllers/VigenciaController.cs index 0823df5..1b391c4 100644 --- a/Controllers/VigenciaController.cs +++ b/Controllers/VigenciaController.cs @@ -1,7 +1,11 @@ using line_gestao_api.Data; using line_gestao_api.Dtos; +using line_gestao_api.Models; +using line_gestao_api.Services; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using System.Linq; namespace line_gestao_api.Controllers { @@ -181,5 +185,176 @@ namespace line_gestao_api.Controllers .OrderBy(x => x) .ToListAsync(); } + + [HttpGet("{id:guid}")] + public async Task> GetById(Guid id) + { + var x = await _db.VigenciaLines.AsNoTracking().FirstOrDefaultAsync(a => a.Id == id); + if (x == null) return NotFound(); + + return Ok(new VigenciaLineDetailDto + { + Id = x.Id, + Item = x.Item, + Conta = x.Conta, + Linha = x.Linha, + Cliente = x.Cliente, + Usuario = x.Usuario, + PlanoContrato = x.PlanoContrato, + DtEfetivacaoServico = x.DtEfetivacaoServico, + DtTerminoFidelizacao = x.DtTerminoFidelizacao, + Total = x.Total, + CreatedAt = x.CreatedAt, + UpdatedAt = x.UpdatedAt + }); + } + + [HttpPost] + [Authorize(Roles = "admin")] + public async Task> Create([FromBody] CreateVigenciaRequest req) + { + var now = DateTime.UtcNow; + + var linha = TrimOrNull(req.Linha); + var conta = TrimOrNull(req.Conta); + var cliente = TrimOrNull(req.Cliente); + var usuario = TrimOrNull(req.Usuario); + var plano = TrimOrNull(req.PlanoContrato); + + MobileLine? mobile = null; + + if (!string.IsNullOrWhiteSpace(linha)) + { + var linhaDigits = OnlyDigits(linha); + + if (!string.IsNullOrWhiteSpace(linhaDigits)) + { + mobile = await _db.MobileLines.AsNoTracking() + .FirstOrDefaultAsync(x => x.Linha == linhaDigits); + } + else + { + var raw = linha.Trim(); + mobile = await _db.MobileLines.AsNoTracking() + .FirstOrDefaultAsync(x => EF.Functions.ILike(x.Linha ?? "", raw)); + } + + if (mobile != null) + { + conta ??= mobile.Conta; + cliente ??= mobile.Cliente; + usuario ??= mobile.Usuario; + plano ??= mobile.PlanoContrato; + } + } + + decimal? total = req.Total; + if (!total.HasValue && mobile?.ValorPlanoVivo != null) + { + total = mobile.ValorPlanoVivo; + } + if (!total.HasValue && !string.IsNullOrWhiteSpace(plano)) + { + var planSuggestion = await AutoFillRules.ResolvePlanSuggestionAsync(_db, plano); + total = planSuggestion?.ValorPlano; + } + + var item = req.Item; + if (!item.HasValue || item.Value <= 0) + { + var maxItem = await _db.VigenciaLines.MaxAsync(x => (int?)x.Item) ?? 0; + item = maxItem + 1; + } + + var e = new VigenciaLine + { + Id = Guid.NewGuid(), + Item = item.Value, + Conta = conta, + Linha = linha, + Cliente = cliente, + Usuario = usuario, + PlanoContrato = plano, + DtEfetivacaoServico = req.DtEfetivacaoServico.HasValue ? ToUtc(req.DtEfetivacaoServico.Value) : null, + DtTerminoFidelizacao = req.DtTerminoFidelizacao.HasValue ? ToUtc(req.DtTerminoFidelizacao.Value) : null, + Total = total, + CreatedAt = now, + UpdatedAt = now + }; + + _db.VigenciaLines.Add(e); + await _db.SaveChangesAsync(); + + return CreatedAtAction(nameof(GetById), new { id = e.Id }, new VigenciaLineDetailDto + { + Id = e.Id, + Item = e.Item, + Conta = e.Conta, + Linha = e.Linha, + Cliente = e.Cliente, + Usuario = e.Usuario, + PlanoContrato = e.PlanoContrato, + DtEfetivacaoServico = e.DtEfetivacaoServico, + DtTerminoFidelizacao = e.DtTerminoFidelizacao, + Total = e.Total, + CreatedAt = e.CreatedAt, + UpdatedAt = e.UpdatedAt + }); + } + + [HttpPut("{id:guid}")] + [Authorize(Roles = "admin")] + public async Task Update(Guid id, [FromBody] UpdateVigenciaRequest req) + { + var x = await _db.VigenciaLines.FirstOrDefaultAsync(a => a.Id == id); + if (x == null) return NotFound(); + + if (req.Item.HasValue) x.Item = req.Item.Value; + if (req.Conta != null) x.Conta = TrimOrNull(req.Conta); + if (req.Linha != null) x.Linha = TrimOrNull(req.Linha); + if (req.Cliente != null) x.Cliente = TrimOrNull(req.Cliente); + if (req.Usuario != null) x.Usuario = TrimOrNull(req.Usuario); + if (req.PlanoContrato != null) x.PlanoContrato = TrimOrNull(req.PlanoContrato); + + if (req.DtEfetivacaoServico.HasValue) x.DtEfetivacaoServico = ToUtc(req.DtEfetivacaoServico.Value); + if (req.DtTerminoFidelizacao.HasValue) x.DtTerminoFidelizacao = ToUtc(req.DtTerminoFidelizacao.Value); + + if (req.Total.HasValue) x.Total = req.Total.Value; + + x.UpdatedAt = DateTime.UtcNow; + + await _db.SaveChangesAsync(); + return NoContent(); + } + + [HttpDelete("{id:guid}")] + [Authorize(Roles = "admin")] + public async Task Delete(Guid id) + { + var x = await _db.VigenciaLines.FirstOrDefaultAsync(a => a.Id == id); + if (x == null) return NotFound(); + + _db.VigenciaLines.Remove(x); + await _db.SaveChangesAsync(); + return NoContent(); + } + + private static string? TrimOrNull(string? s) + { + if (string.IsNullOrWhiteSpace(s)) return null; + return s.Trim(); + } + + private static DateTime ToUtc(DateTime dt) + { + return dt.Kind == DateTimeKind.Utc ? dt + : (dt.Kind == DateTimeKind.Local ? dt.ToUniversalTime() : DateTime.SpecifyKind(dt, DateTimeKind.Utc)); + } + + private static string OnlyDigits(string? s) + { + if (string.IsNullOrWhiteSpace(s)) return ""; + return new string(s.Where(char.IsDigit).ToArray()); + } } -} \ No newline at end of file +} diff --git a/Data/AppDbContext.cs b/Data/AppDbContext.cs index 6b81d02..c88d60a 100644 --- a/Data/AppDbContext.cs +++ b/Data/AppDbContext.cs @@ -9,10 +9,15 @@ namespace line_gestao_api.Data; public class AppDbContext : IdentityDbContext, Guid> { private readonly ITenantProvider _tenantProvider; + private readonly IAuditLogBuilder _auditLogBuilder; - public AppDbContext(DbContextOptions options, ITenantProvider tenantProvider) : base(options) + public AppDbContext( + DbContextOptions options, + ITenantProvider tenantProvider, + IAuditLogBuilder auditLogBuilder) : base(options) { _tenantProvider = tenantProvider; + _auditLogBuilder = auditLogBuilder; } public DbSet Tenants => Set(); @@ -60,6 +65,9 @@ public class AppDbContext : IdentityDbContext ParcelamentoLines => Set(); public DbSet ParcelamentoMonthValues => Set(); + // ✅ tabela AUDIT LOGS (Histórico) + public DbSet AuditLogs => Set(); + protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); @@ -132,7 +140,6 @@ public class AppDbContext : IdentityDbContext(e => { @@ -141,6 +148,10 @@ public class AppDbContext : IdentityDbContext x.Linha); e.HasIndex(x => x.Cpf); e.HasIndex(x => x.Email); + e.HasIndex(x => x.TipoPessoa); + e.HasIndex(x => x.Cnpj); + e.HasIndex(x => x.Nome); + e.HasIndex(x => x.RazaoSocial); e.HasIndex(x => x.TenantId); }); @@ -248,6 +259,30 @@ public class AppDbContext : IdentityDbContext(e => + { + e.Property(x => x.Action).HasMaxLength(20); + e.Property(x => x.Page).HasMaxLength(80); + e.Property(x => x.EntityName).HasMaxLength(120); + e.Property(x => x.EntityId).HasMaxLength(200); + e.Property(x => x.EntityLabel).HasMaxLength(255); + e.Property(x => x.UserName).HasMaxLength(200); + e.Property(x => x.UserEmail).HasMaxLength(200); + e.Property(x => x.RequestPath).HasMaxLength(255); + e.Property(x => x.RequestMethod).HasMaxLength(10); + e.Property(x => x.IpAddress).HasMaxLength(80); + e.Property(x => x.ChangesJson).HasColumnType("jsonb"); + + e.HasIndex(x => x.TenantId); + e.HasIndex(x => x.OccurredAtUtc); + e.HasIndex(x => x.Page); + e.HasIndex(x => x.UserId); + e.HasIndex(x => x.EntityName); + }); + modelBuilder.Entity().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId); modelBuilder.Entity().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId); modelBuilder.Entity().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId); @@ -269,18 +304,21 @@ public class AppDbContext : IdentityDbContext().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId); modelBuilder.Entity().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId); modelBuilder.Entity().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId); + modelBuilder.Entity().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId); modelBuilder.Entity().HasQueryFilter(x => _tenantProvider.TenantId != null && x.TenantId == _tenantProvider.TenantId); } public override int SaveChanges() { ApplyTenantIds(); + AddAuditLogs(); return base.SaveChanges(); } public override Task SaveChangesAsync(CancellationToken cancellationToken = default) { ApplyTenantIds(); + AddAuditLogs(); return base.SaveChangesAsync(cancellationToken); } @@ -300,4 +338,16 @@ public class AppDbContext : IdentityDbContext 0) + { + AuditLogs.AddRange(logs); + } + } } diff --git a/Dtos/AccountCompanyDtos.cs b/Dtos/AccountCompanyDtos.cs new file mode 100644 index 0000000..298748b --- /dev/null +++ b/Dtos/AccountCompanyDtos.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace line_gestao_api.Dtos +{ + public class AccountCompanyDto + { + public string Empresa { get; set; } = ""; + public List Contas { get; set; } = new(); + } +} diff --git a/Dtos/AuditLogDtos.cs b/Dtos/AuditLogDtos.cs new file mode 100644 index 0000000..87ea364 --- /dev/null +++ b/Dtos/AuditLogDtos.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; + +namespace line_gestao_api.Dtos; + +public class AuditLogDto +{ + public Guid Id { get; set; } + public DateTime OccurredAtUtc { get; set; } + + public string Action { get; set; } = string.Empty; + public string Page { get; set; } = string.Empty; + public string EntityName { get; set; } = string.Empty; + public string? EntityId { get; set; } + public string? EntityLabel { get; set; } + + public Guid? UserId { get; set; } + public string? UserName { get; set; } + public string? UserEmail { get; set; } + + public string? RequestPath { get; set; } + public string? RequestMethod { get; set; } + public string? IpAddress { get; set; } + + public List Changes { get; set; } = new(); +} + +public class AuditFieldChangeDto +{ + public string Field { get; set; } = string.Empty; + public string ChangeType { get; set; } = string.Empty; + public string? OldValue { get; set; } + public string? NewValue { get; set; } +} diff --git a/Dtos/BillingClientListDto.cs b/Dtos/BillingClientListDto.cs index 11140ca..5eb931a 100644 --- a/Dtos/BillingClientListDto.cs +++ b/Dtos/BillingClientListDto.cs @@ -17,4 +17,25 @@ public string? Aparelho { get; set; } public string? FormaPagamento { get; set; } } + + public class BillingClientDetailDto : BillingClientListDto + { + public DateTime CreatedAt { get; set; } + public DateTime UpdatedAt { get; set; } + } + + public class UpdateBillingClientRequest + { + public string? Tipo { get; set; } + public int? Item { get; set; } + public string? Cliente { get; set; } + public int? QtdLinhas { get; set; } + public decimal? FranquiaVivo { get; set; } + public decimal? ValorContratoVivo { get; set; } + public decimal? FranquiaLine { get; set; } + public decimal? ValorContratoLine { get; set; } + public decimal? Lucro { get; set; } + public string? Aparelho { get; set; } + public string? FormaPagamento { get; set; } + } } diff --git a/Dtos/ParcelamentosDtos.cs b/Dtos/ParcelamentosDtos.cs index a1238fa..4451820 100644 --- a/Dtos/ParcelamentosDtos.cs +++ b/Dtos/ParcelamentosDtos.cs @@ -21,9 +21,44 @@ public sealed class ParcelamentoMonthDto public decimal? Valor { get; set; } } +public sealed class ParcelamentoMonthInputDto +{ + public DateOnly Competencia { get; set; } + public decimal? Valor { get; set; } +} + +public sealed class ParcelamentoUpsertDto +{ + 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 List MonthValues { get; set; } = new(); +} + +public sealed class ParcelamentoAnnualMonthDto +{ + public int Month { get; set; } + public decimal? Valor { get; set; } +} + +public sealed class ParcelamentoAnnualRowDto +{ + public int Year { get; set; } + public decimal Total { get; set; } + public List Months { get; set; } = new(); +} + public sealed class ParcelamentoDetailDto : ParcelamentoListDto { public List MonthValues { get; set; } = new(); + public List AnnualRows { get; set; } = new(); } public sealed class ParcelamentosImportErrorDto diff --git a/Dtos/ResumoDtos.cs b/Dtos/ResumoDtos.cs index 3b735ed..9fc132b 100644 --- a/Dtos/ResumoDtos.cs +++ b/Dtos/ResumoDtos.cs @@ -11,6 +11,8 @@ public sealed class ResumoResponseDto public ResumoPlanoContratoTotalDto? PlanoContratoTotal { get; set; } public List LineTotais { get; set; } = new(); public List ReservaLines { get; set; } = new(); + public List ReservaPorDdd { get; set; } = new(); + public int? TotalGeralLinhasReserva { get; set; } public ResumoReservaTotalDto? ReservaTotal { get; set; } } @@ -91,6 +93,19 @@ public sealed class ResumoReservaLineDto public decimal? Total { get; set; } } +public sealed class ResumoReservaPorDddDto +{ + public string Ddd { get; set; } = ""; + public int TotalLinhas { get; set; } + public List PorFranquia { get; set; } = new(); +} + +public sealed class ResumoReservaPorFranquiaDto +{ + public decimal? FranquiaGb { get; set; } + public int TotalLinhas { get; set; } +} + public sealed class ResumoReservaTotalDto { public int? QtdLinhasTotal { get; set; } diff --git a/Dtos/UserDataDtos.cs b/Dtos/UserDataDtos.cs index 039137f..6bf6ad9 100644 --- a/Dtos/UserDataDtos.cs +++ b/Dtos/UserDataDtos.cs @@ -8,6 +8,10 @@ namespace line_gestao_api.Dtos public int Item { get; set; } public string? Linha { get; set; } public string? Cliente { get; set; } + public string? TipoPessoa { get; set; } + public string? Nome { get; set; } + public string? RazaoSocial { get; set; } + public string? Cnpj { get; set; } public string? Cpf { get; set; } public string? Rg { get; set; } public string? DataNascimento { get; set; } @@ -23,6 +27,46 @@ namespace line_gestao_api.Dtos public int Item { get; set; } public string? Linha { get; set; } public string? Cliente { get; set; } + public string? TipoPessoa { get; set; } + public string? Nome { get; set; } + public string? RazaoSocial { get; set; } + public string? Cnpj { get; set; } + public string? Cpf { get; set; } + public string? Rg { get; set; } + public DateTime? DataNascimento { get; set; } + public string? Email { get; set; } + public string? Endereco { get; set; } + public string? Celular { get; set; } + public string? TelefoneFixo { get; set; } + } + + public class CreateUserDataRequest + { + public int? Item { get; set; } + public string? Linha { get; set; } + public string? Cliente { get; set; } + public string? TipoPessoa { get; set; } + public string? Nome { get; set; } + public string? RazaoSocial { get; set; } + public string? Cnpj { get; set; } + public string? Cpf { get; set; } + public string? Rg { get; set; } + public DateTime? DataNascimento { get; set; } + public string? Email { get; set; } + public string? Endereco { get; set; } + public string? Celular { get; set; } + public string? TelefoneFixo { get; set; } + } + + public class UpdateUserDataRequest + { + public int? Item { get; set; } + public string? Linha { get; set; } + public string? Cliente { get; set; } + public string? TipoPessoa { get; set; } + public string? Nome { get; set; } + public string? RazaoSocial { get; set; } + public string? Cnpj { get; set; } public string? Cpf { get; set; } public string? Rg { get; set; } public DateTime? DataNascimento { get; set; } @@ -37,6 +81,7 @@ namespace line_gestao_api.Dtos public int TotalRegistros { get; set; } public int ClientesUnicos { get; set; } public int ComCpf { get; set; } + public int ComCnpj { get; set; } public int ComEmail { get; set; } } @@ -46,6 +91,7 @@ namespace line_gestao_api.Dtos public string Cliente { get; set; } = ""; public int TotalRegistros { get; set; } public int ComCpf { get; set; } + public int ComCnpj { get; set; } public int ComEmail { get; set; } } @@ -55,4 +101,4 @@ namespace line_gestao_api.Dtos public PagedResult Data { get; set; } = new(); public UserDataKpisDto Kpis { get; set; } = new(); } -} \ No newline at end of file +} diff --git a/Dtos/VigenciaDtos.cs b/Dtos/VigenciaDtos.cs index 9196b9e..ccadec0 100644 --- a/Dtos/VigenciaDtos.cs +++ b/Dtos/VigenciaDtos.cs @@ -17,6 +17,38 @@ namespace line_gestao_api.Dtos public decimal? Total { get; set; } } + public class VigenciaLineDetailDto : VigenciaLineListDto + { + public DateTime CreatedAt { get; set; } + public DateTime UpdatedAt { get; set; } + } + + public class CreateVigenciaRequest + { + public int? Item { get; set; } + public string? Conta { get; set; } + public string? Linha { get; set; } + public string? Cliente { get; set; } + public string? Usuario { get; set; } + public string? PlanoContrato { get; set; } + public DateTime? DtEfetivacaoServico { get; set; } + public DateTime? DtTerminoFidelizacao { get; set; } + public decimal? Total { get; set; } + } + + public class UpdateVigenciaRequest + { + public int? Item { get; set; } + public string? Conta { get; set; } + public string? Linha { get; set; } + public string? Cliente { get; set; } + public string? Usuario { get; set; } + public string? PlanoContrato { get; set; } + public DateTime? DtEfetivacaoServico { get; set; } + public DateTime? DtTerminoFidelizacao { get; set; } + public decimal? Total { get; set; } + } + public class VigenciaClientGroupDto { public string Cliente { get; set; } = ""; @@ -42,4 +74,4 @@ namespace line_gestao_api.Dtos public int TotalVencidos { get; set; } public decimal ValorTotal { get; set; } } -} \ No newline at end of file +} diff --git a/Migrations/20260202162920_AddResumoTables.Designer.cs b/Migrations/20260202162920_AddResumoTables.Designer.cs new file mode 100644 index 0000000..5e7b03e --- /dev/null +++ b/Migrations/20260202162920_AddResumoTables.Designer.cs @@ -0,0 +1,1294 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using line_gestao_api.Data; + +#nullable disable + +namespace line_gestao_api.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20260202162920_AddResumoTables")] + partial class AddResumoTables + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("line_gestao_api.Models.ApplicationUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(120) + .HasColumnType("character varying(120)"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.HasIndex("TenantId", "NormalizedEmail") + .IsUnique(); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("line_gestao_api.Models.BillingClient", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Aparelho") + .HasColumnType("text"); + + b.Property("Cliente") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FormaPagamento") + .HasColumnType("text"); + + b.Property("FranquiaLine") + .HasColumnType("numeric"); + + b.Property("FranquiaVivo") + .HasColumnType("numeric"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Lucro") + .HasColumnType("numeric"); + + b.Property("QtdLinhas") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Tipo") + .IsRequired() + .HasMaxLength(2) + .HasColumnType("character varying(2)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorContratoLine") + .HasColumnType("numeric"); + + b.Property("ValorContratoVivo") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.HasIndex("Cliente"); + + b.HasIndex("Item"); + + b.HasIndex("TenantId"); + + b.HasIndex("Tipo"); + + b.HasIndex("Tipo", "Cliente"); + + b.ToTable("billing_clients", (string)null); + }); + + modelBuilder.Entity("line_gestao_api.Models.ChipVirgemLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("NumeroDoChip") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Observacoes") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("Item"); + + b.HasIndex("NumeroDoChip"); + + b.HasIndex("TenantId"); + + b.ToTable("ChipVirgemLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ControleRecebidoLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Ano") + .HasColumnType("integer"); + + b.Property("Chip") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("ConteudoDaNf") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataDaNf") + .HasColumnType("timestamp with time zone"); + + b.Property("DataDoRecebimento") + .HasColumnType("timestamp with time zone"); + + b.Property("IsResumo") + .HasColumnType("boolean"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("NotaFiscal") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("NumeroDaLinha") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Quantidade") + .HasColumnType("integer"); + + b.Property("Serial") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorDaNf") + .HasColumnType("numeric"); + + b.Property("ValorUnit") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.HasIndex("Ano"); + + b.HasIndex("Chip"); + + b.HasIndex("DataDaNf"); + + b.HasIndex("DataDoRecebimento"); + + b.HasIndex("Item"); + + b.HasIndex("NotaFiscal"); + + b.HasIndex("NumeroDaLinha"); + + b.HasIndex("Serial"); + + b.HasIndex("TenantId"); + + b.ToTable("ControleRecebidoLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.MobileLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Cedente") + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("Chip") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Cliente") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Conta") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataBloqueio") + .HasColumnType("timestamp with time zone"); + + b.Property("DataEntregaCliente") + .HasColumnType("timestamp with time zone"); + + b.Property("DataEntregaOpera") + .HasColumnType("timestamp with time zone"); + + b.Property("Desconto") + .HasColumnType("numeric"); + + b.Property("FranquiaGestao") + .HasColumnType("numeric"); + + b.Property("FranquiaLine") + .HasColumnType("numeric"); + + b.Property("FranquiaVivo") + .HasColumnType("numeric"); + + b.Property("GestaoVozDados") + .HasColumnType("numeric"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Linha") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("LocacaoAp") + .HasColumnType("numeric"); + + b.Property("Lucro") + .HasColumnType("numeric"); + + b.Property("Modalidade") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("PlanoContrato") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Skeelo") + .HasColumnType("numeric"); + + b.Property("Skil") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("Solicitante") + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("Status") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Usuario") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ValorContratoLine") + .HasColumnType("numeric"); + + b.Property("ValorContratoVivo") + .HasColumnType("numeric"); + + b.Property("ValorPlanoVivo") + .HasColumnType("numeric"); + + b.Property("VencConta") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("VivoGestaoDispositivo") + .HasColumnType("numeric"); + + b.Property("VivoNewsPlus") + .HasColumnType("numeric"); + + b.Property("VivoTravelMundo") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.HasIndex("Chip"); + + b.HasIndex("Cliente"); + + b.HasIndex("Skil"); + + b.HasIndex("Status"); + + b.HasIndex("Usuario"); + + b.HasIndex("TenantId", "Linha") + .IsUnique(); + + b.ToTable("MobileLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.MuregLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataDaMureg") + .HasColumnType("timestamp with time zone"); + + b.Property("ICCID") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("LinhaAntiga") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("LinhaNova") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("MobileLineId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("ICCID"); + + b.HasIndex("Item"); + + b.HasIndex("LinhaAntiga"); + + b.HasIndex("LinhaNova"); + + b.HasIndex("MobileLineId"); + + b.HasIndex("TenantId"); + + b.ToTable("MuregLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.Notification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Cliente") + .HasColumnType("text"); + + b.Property("Data") + .HasColumnType("timestamp with time zone"); + + b.Property("DedupKey") + .IsRequired() + .HasColumnType("text"); + + b.Property("DiasParaVencer") + .HasColumnType("integer"); + + b.Property("Lida") + .HasColumnType("boolean"); + + b.Property("LidaEm") + .HasColumnType("timestamp with time zone"); + + b.Property("Linha") + .HasColumnType("text"); + + b.Property("Mensagem") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReferenciaData") + .HasColumnType("timestamp with time zone"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Tipo") + .IsRequired() + .HasColumnType("text"); + + b.Property("Titulo") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("Usuario") + .HasColumnType("text"); + + b.Property("VigenciaLineId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("Cliente"); + + b.HasIndex("Data"); + + b.HasIndex("DedupKey") + .IsUnique(); + + b.HasIndex("Lida"); + + b.HasIndex("TenantId"); + + b.HasIndex("UserId"); + + b.HasIndex("VigenciaLineId"); + + b.ToTable("Notifications"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoClienteEspecial", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Nome") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Valor") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoClienteEspeciais"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoLineTotais", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LucroTotalLine") + .HasColumnType("numeric"); + + b.Property("QtdLinhas") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Tipo") + .HasColumnType("text"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorTotalLine") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoLineTotais"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoMacrophonyPlan", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaGb") + .HasColumnType("numeric"); + + b.Property("Gb") + .HasColumnType("numeric"); + + b.Property("PlanoContrato") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TotalLinhas") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorIndividualComSvas") + .HasColumnType("numeric"); + + b.Property("ValorTotal") + .HasColumnType("numeric"); + + b.Property("VivoTravel") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("ResumoMacrophonyPlans"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoMacrophonyTotal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaGbTotal") + .HasColumnType("numeric"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TotalLinhasTotal") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorTotal") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoMacrophonyTotals"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoPlanoContratoResumo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaGb") + .HasColumnType("numeric"); + + b.Property("Gb") + .HasColumnType("numeric"); + + b.Property("PlanoContrato") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TotalLinhas") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorIndividualComSvas") + .HasColumnType("numeric"); + + b.Property("ValorTotal") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoPlanoContratoResumos"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoPlanoContratoTotal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorTotal") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoPlanoContratoTotals"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoReservaLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Ddd") + .HasColumnType("text"); + + b.Property("FranquiaGb") + .HasColumnType("numeric"); + + b.Property("QtdLinhas") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Total") + .HasColumnType("numeric"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("ResumoReservaLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoReservaTotal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("QtdLinhasTotal") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Total") + .HasColumnType("numeric"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("ResumoReservaTotals"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoVivoLineResumo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Cliente") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaLine") + .HasColumnType("numeric"); + + b.Property("FranquiaTotal") + .HasColumnType("numeric"); + + b.Property("Lucro") + .HasColumnType("numeric"); + + b.Property("QtdLinhas") + .HasColumnType("integer"); + + b.Property("Skil") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorContratoLine") + .HasColumnType("numeric"); + + b.Property("ValorContratoVivo") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoVivoLineResumos"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoVivoLineTotal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaLine") + .HasColumnType("numeric"); + + b.Property("FranquiaTotal") + .HasColumnType("numeric"); + + b.Property("Lucro") + .HasColumnType("numeric"); + + b.Property("QtdLinhasTotal") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorContratoLine") + .HasColumnType("numeric"); + + b.Property("ValorContratoVivo") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoVivoLineTotals"); + }); + + modelBuilder.Entity("line_gestao_api.Models.Tenant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Tenants"); + }); + + modelBuilder.Entity("line_gestao_api.Models.TrocaNumeroLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataTroca") + .HasColumnType("timestamp with time zone"); + + b.Property("ICCID") + .HasColumnType("text"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("LinhaAntiga") + .HasColumnType("text"); + + b.Property("LinhaNova") + .HasColumnType("text"); + + b.Property("Motivo") + .HasColumnType("text"); + + b.Property("Observacao") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("DataTroca"); + + b.HasIndex("ICCID"); + + b.HasIndex("Item"); + + b.HasIndex("LinhaAntiga"); + + b.HasIndex("LinhaNova"); + + b.HasIndex("TenantId"); + + b.ToTable("TrocaNumeroLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.UserData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Celular") + .HasColumnType("text"); + + b.Property("Cliente") + .HasColumnType("text"); + + b.Property("Cpf") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataNascimento") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("Endereco") + .HasColumnType("text"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Linha") + .HasColumnType("text"); + + b.Property("Rg") + .HasColumnType("text"); + + b.Property("TelefoneFixo") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("Cliente"); + + b.HasIndex("Cpf"); + + b.HasIndex("Email"); + + b.HasIndex("Item"); + + b.HasIndex("Linha"); + + b.HasIndex("TenantId"); + + b.ToTable("UserDatas"); + }); + + modelBuilder.Entity("line_gestao_api.Models.VigenciaLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Cliente") + .HasColumnType("text"); + + b.Property("Conta") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DtEfetivacaoServico") + .HasColumnType("timestamp with time zone"); + + b.Property("DtTerminoFidelizacao") + .HasColumnType("timestamp with time zone"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Linha") + .HasColumnType("text"); + + b.Property("PlanoContrato") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Total") + .HasColumnType("numeric"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Usuario") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Cliente"); + + b.HasIndex("DtTerminoFidelizacao"); + + b.HasIndex("Item"); + + b.HasIndex("Linha"); + + b.HasIndex("TenantId"); + + b.ToTable("VigenciaLines"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("line_gestao_api.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("line_gestao_api.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("line_gestao_api.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("line_gestao_api.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("line_gestao_api.Models.MuregLine", b => + { + b.HasOne("line_gestao_api.Models.MobileLine", "MobileLine") + .WithMany("Muregs") + .HasForeignKey("MobileLineId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("MobileLine"); + }); + + modelBuilder.Entity("line_gestao_api.Models.Notification", b => + { + b.HasOne("line_gestao_api.Models.ApplicationUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("line_gestao_api.Models.VigenciaLine", "VigenciaLine") + .WithMany() + .HasForeignKey("VigenciaLineId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("User"); + + b.Navigation("VigenciaLine"); + }); + + modelBuilder.Entity("line_gestao_api.Models.MobileLine", b => + { + b.Navigation("Muregs"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Migrations/20260202162920_AddResumoTables.cs b/Migrations/20260202162920_AddResumoTables.cs new file mode 100644 index 0000000..89f5a58 --- /dev/null +++ b/Migrations/20260202162920_AddResumoTables.cs @@ -0,0 +1,232 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace line_gestao_api.Migrations +{ + /// + public partial class AddResumoTables : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "ResumoClienteEspeciais", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: false), + Nome = table.Column(type: "text", nullable: true), + Valor = table.Column(type: "numeric", nullable: true), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ResumoClienteEspeciais", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ResumoLineTotais", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: false), + Tipo = table.Column(type: "text", nullable: true), + ValorTotalLine = table.Column(type: "numeric", nullable: true), + LucroTotalLine = table.Column(type: "numeric", nullable: true), + QtdLinhas = table.Column(type: "integer", nullable: true), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ResumoLineTotais", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ResumoMacrophonyPlans", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: false), + PlanoContrato = table.Column(type: "text", nullable: true), + Gb = table.Column(type: "numeric", nullable: true), + ValorIndividualComSvas = table.Column(type: "numeric", nullable: true), + FranquiaGb = table.Column(type: "numeric", nullable: true), + TotalLinhas = table.Column(type: "integer", nullable: true), + ValorTotal = table.Column(type: "numeric", nullable: true), + VivoTravel = table.Column(type: "boolean", nullable: false), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ResumoMacrophonyPlans", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ResumoMacrophonyTotals", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: false), + FranquiaGbTotal = table.Column(type: "numeric", nullable: true), + TotalLinhasTotal = table.Column(type: "integer", nullable: true), + ValorTotal = table.Column(type: "numeric", nullable: true), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ResumoMacrophonyTotals", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ResumoPlanoContratoResumos", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: false), + PlanoContrato = table.Column(type: "text", nullable: true), + Gb = table.Column(type: "numeric", nullable: true), + ValorIndividualComSvas = table.Column(type: "numeric", nullable: true), + FranquiaGb = table.Column(type: "numeric", nullable: true), + TotalLinhas = table.Column(type: "integer", nullable: true), + ValorTotal = table.Column(type: "numeric", nullable: true), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ResumoPlanoContratoResumos", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ResumoPlanoContratoTotals", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: false), + ValorTotal = table.Column(type: "numeric", nullable: true), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ResumoPlanoContratoTotals", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ResumoReservaLines", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: false), + Ddd = table.Column(type: "text", nullable: true), + FranquiaGb = table.Column(type: "numeric", nullable: true), + QtdLinhas = table.Column(type: "integer", nullable: true), + Total = table.Column(type: "numeric", nullable: true), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ResumoReservaLines", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ResumoReservaTotals", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: false), + QtdLinhasTotal = table.Column(type: "integer", nullable: true), + Total = table.Column(type: "numeric", nullable: true), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ResumoReservaTotals", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ResumoVivoLineResumos", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: false), + Skil = table.Column(type: "text", nullable: true), + Cliente = table.Column(type: "text", nullable: true), + QtdLinhas = table.Column(type: "integer", nullable: true), + FranquiaTotal = table.Column(type: "numeric", nullable: true), + ValorContratoVivo = table.Column(type: "numeric", nullable: true), + FranquiaLine = table.Column(type: "numeric", nullable: true), + ValorContratoLine = table.Column(type: "numeric", nullable: true), + Lucro = table.Column(type: "numeric", nullable: true), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ResumoVivoLineResumos", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ResumoVivoLineTotals", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: false), + QtdLinhasTotal = table.Column(type: "integer", nullable: true), + FranquiaTotal = table.Column(type: "numeric", nullable: true), + ValorContratoVivo = table.Column(type: "numeric", nullable: true), + FranquiaLine = table.Column(type: "numeric", nullable: true), + ValorContratoLine = table.Column(type: "numeric", nullable: true), + Lucro = table.Column(type: "numeric", nullable: true), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ResumoVivoLineTotals", x => x.Id); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ResumoClienteEspeciais"); + + migrationBuilder.DropTable( + name: "ResumoLineTotais"); + + migrationBuilder.DropTable( + name: "ResumoMacrophonyPlans"); + + migrationBuilder.DropTable( + name: "ResumoMacrophonyTotals"); + + migrationBuilder.DropTable( + name: "ResumoPlanoContratoResumos"); + + migrationBuilder.DropTable( + name: "ResumoPlanoContratoTotals"); + + migrationBuilder.DropTable( + name: "ResumoReservaLines"); + + migrationBuilder.DropTable( + name: "ResumoReservaTotals"); + + migrationBuilder.DropTable( + name: "ResumoVivoLineResumos"); + + migrationBuilder.DropTable( + name: "ResumoVivoLineTotals"); + } + } +} diff --git a/Migrations/20260202175823_AddParcelamentosTables.Designer.cs b/Migrations/20260202175823_AddParcelamentosTables.Designer.cs new file mode 100644 index 0000000..cc4dbc1 --- /dev/null +++ b/Migrations/20260202175823_AddParcelamentosTables.Designer.cs @@ -0,0 +1,1405 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using line_gestao_api.Data; + +#nullable disable + +namespace line_gestao_api.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20260202175823_AddParcelamentosTables")] + partial class AddParcelamentosTables + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("line_gestao_api.Models.ApplicationUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(120) + .HasColumnType("character varying(120)"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.HasIndex("TenantId", "NormalizedEmail") + .IsUnique(); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("line_gestao_api.Models.BillingClient", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Aparelho") + .HasColumnType("text"); + + b.Property("Cliente") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FormaPagamento") + .HasColumnType("text"); + + b.Property("FranquiaLine") + .HasColumnType("numeric"); + + b.Property("FranquiaVivo") + .HasColumnType("numeric"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Lucro") + .HasColumnType("numeric"); + + b.Property("QtdLinhas") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Tipo") + .IsRequired() + .HasMaxLength(2) + .HasColumnType("character varying(2)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorContratoLine") + .HasColumnType("numeric"); + + b.Property("ValorContratoVivo") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.HasIndex("Cliente"); + + b.HasIndex("Item"); + + b.HasIndex("TenantId"); + + b.HasIndex("Tipo"); + + b.HasIndex("Tipo", "Cliente"); + + b.ToTable("billing_clients", (string)null); + }); + + modelBuilder.Entity("line_gestao_api.Models.ChipVirgemLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("NumeroDoChip") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Observacoes") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("Item"); + + b.HasIndex("NumeroDoChip"); + + b.HasIndex("TenantId"); + + b.ToTable("ChipVirgemLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ControleRecebidoLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Ano") + .HasColumnType("integer"); + + b.Property("Chip") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("ConteudoDaNf") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataDaNf") + .HasColumnType("timestamp with time zone"); + + b.Property("DataDoRecebimento") + .HasColumnType("timestamp with time zone"); + + b.Property("IsResumo") + .HasColumnType("boolean"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("NotaFiscal") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("NumeroDaLinha") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Quantidade") + .HasColumnType("integer"); + + b.Property("Serial") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorDaNf") + .HasColumnType("numeric"); + + b.Property("ValorUnit") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.HasIndex("Ano"); + + b.HasIndex("Chip"); + + b.HasIndex("DataDaNf"); + + b.HasIndex("DataDoRecebimento"); + + b.HasIndex("Item"); + + b.HasIndex("NotaFiscal"); + + b.HasIndex("NumeroDaLinha"); + + b.HasIndex("Serial"); + + b.HasIndex("TenantId"); + + b.ToTable("ControleRecebidoLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.MobileLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Cedente") + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("Chip") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Cliente") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Conta") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataBloqueio") + .HasColumnType("timestamp with time zone"); + + b.Property("DataEntregaCliente") + .HasColumnType("timestamp with time zone"); + + b.Property("DataEntregaOpera") + .HasColumnType("timestamp with time zone"); + + b.Property("Desconto") + .HasColumnType("numeric"); + + b.Property("FranquiaGestao") + .HasColumnType("numeric"); + + b.Property("FranquiaLine") + .HasColumnType("numeric"); + + b.Property("FranquiaVivo") + .HasColumnType("numeric"); + + b.Property("GestaoVozDados") + .HasColumnType("numeric"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Linha") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("LocacaoAp") + .HasColumnType("numeric"); + + b.Property("Lucro") + .HasColumnType("numeric"); + + b.Property("Modalidade") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("PlanoContrato") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Skeelo") + .HasColumnType("numeric"); + + b.Property("Skil") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("Solicitante") + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("Status") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Usuario") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ValorContratoLine") + .HasColumnType("numeric"); + + b.Property("ValorContratoVivo") + .HasColumnType("numeric"); + + b.Property("ValorPlanoVivo") + .HasColumnType("numeric"); + + b.Property("VencConta") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("VivoGestaoDispositivo") + .HasColumnType("numeric"); + + b.Property("VivoNewsPlus") + .HasColumnType("numeric"); + + b.Property("VivoTravelMundo") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.HasIndex("Chip"); + + b.HasIndex("Cliente"); + + b.HasIndex("Skil"); + + b.HasIndex("Status"); + + b.HasIndex("Usuario"); + + b.HasIndex("TenantId", "Linha") + .IsUnique(); + + b.ToTable("MobileLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.MuregLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataDaMureg") + .HasColumnType("timestamp with time zone"); + + b.Property("ICCID") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("LinhaAntiga") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("LinhaNova") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("MobileLineId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("ICCID"); + + b.HasIndex("Item"); + + b.HasIndex("LinhaAntiga"); + + b.HasIndex("LinhaNova"); + + b.HasIndex("MobileLineId"); + + b.HasIndex("TenantId"); + + b.ToTable("MuregLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.Notification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Cliente") + .HasColumnType("text"); + + b.Property("Data") + .HasColumnType("timestamp with time zone"); + + b.Property("DedupKey") + .IsRequired() + .HasColumnType("text"); + + b.Property("DiasParaVencer") + .HasColumnType("integer"); + + b.Property("Lida") + .HasColumnType("boolean"); + + b.Property("LidaEm") + .HasColumnType("timestamp with time zone"); + + b.Property("Linha") + .HasColumnType("text"); + + b.Property("Mensagem") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReferenciaData") + .HasColumnType("timestamp with time zone"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Tipo") + .IsRequired() + .HasColumnType("text"); + + b.Property("Titulo") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("Usuario") + .HasColumnType("text"); + + b.Property("VigenciaLineId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("Cliente"); + + b.HasIndex("Data"); + + b.HasIndex("DedupKey") + .IsUnique(); + + b.HasIndex("Lida"); + + b.HasIndex("TenantId"); + + b.HasIndex("UserId"); + + b.HasIndex("VigenciaLineId"); + + b.ToTable("Notifications"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ParcelamentoLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AnoRef") + .HasColumnType("integer"); + + b.Property("Cliente") + .HasMaxLength(120) + .HasColumnType("character varying(120)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Desconto") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Linha") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("ParcelaAtual") + .HasColumnType("integer"); + + b.Property("QtParcelas") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TotalParcelas") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorCheio") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.Property("ValorComDesconto") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("Linha"); + + b.HasIndex("TenantId"); + + b.HasIndex("AnoRef", "Item") + .IsUnique(); + + b.ToTable("ParcelamentoLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ParcelamentoMonthValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Competencia") + .HasColumnType("date"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ParcelamentoLineId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Valor") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.HasIndex("ParcelamentoLineId", "Competencia") + .IsUnique(); + + b.ToTable("ParcelamentoMonthValues"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoClienteEspecial", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Nome") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Valor") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoClienteEspeciais"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoLineTotais", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LucroTotalLine") + .HasColumnType("numeric"); + + b.Property("QtdLinhas") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Tipo") + .HasColumnType("text"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorTotalLine") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoLineTotais"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoMacrophonyPlan", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaGb") + .HasColumnType("numeric"); + + b.Property("Gb") + .HasColumnType("numeric"); + + b.Property("PlanoContrato") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TotalLinhas") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorIndividualComSvas") + .HasColumnType("numeric"); + + b.Property("ValorTotal") + .HasColumnType("numeric"); + + b.Property("VivoTravel") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("ResumoMacrophonyPlans"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoMacrophonyTotal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaGbTotal") + .HasColumnType("numeric"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TotalLinhasTotal") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorTotal") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoMacrophonyTotals"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoPlanoContratoResumo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaGb") + .HasColumnType("numeric"); + + b.Property("Gb") + .HasColumnType("numeric"); + + b.Property("PlanoContrato") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TotalLinhas") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorIndividualComSvas") + .HasColumnType("numeric"); + + b.Property("ValorTotal") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoPlanoContratoResumos"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoPlanoContratoTotal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorTotal") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoPlanoContratoTotals"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoReservaLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Ddd") + .HasColumnType("text"); + + b.Property("FranquiaGb") + .HasColumnType("numeric"); + + b.Property("QtdLinhas") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Total") + .HasColumnType("numeric"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("ResumoReservaLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoReservaTotal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("QtdLinhasTotal") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Total") + .HasColumnType("numeric"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("ResumoReservaTotals"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoVivoLineResumo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Cliente") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaLine") + .HasColumnType("numeric"); + + b.Property("FranquiaTotal") + .HasColumnType("numeric"); + + b.Property("Lucro") + .HasColumnType("numeric"); + + b.Property("QtdLinhas") + .HasColumnType("integer"); + + b.Property("Skil") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorContratoLine") + .HasColumnType("numeric"); + + b.Property("ValorContratoVivo") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoVivoLineResumos"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoVivoLineTotal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaLine") + .HasColumnType("numeric"); + + b.Property("FranquiaTotal") + .HasColumnType("numeric"); + + b.Property("Lucro") + .HasColumnType("numeric"); + + b.Property("QtdLinhasTotal") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorContratoLine") + .HasColumnType("numeric"); + + b.Property("ValorContratoVivo") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoVivoLineTotals"); + }); + + modelBuilder.Entity("line_gestao_api.Models.Tenant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Tenants"); + }); + + modelBuilder.Entity("line_gestao_api.Models.TrocaNumeroLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataTroca") + .HasColumnType("timestamp with time zone"); + + b.Property("ICCID") + .HasColumnType("text"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("LinhaAntiga") + .HasColumnType("text"); + + b.Property("LinhaNova") + .HasColumnType("text"); + + b.Property("Motivo") + .HasColumnType("text"); + + b.Property("Observacao") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("DataTroca"); + + b.HasIndex("ICCID"); + + b.HasIndex("Item"); + + b.HasIndex("LinhaAntiga"); + + b.HasIndex("LinhaNova"); + + b.HasIndex("TenantId"); + + b.ToTable("TrocaNumeroLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.UserData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Celular") + .HasColumnType("text"); + + b.Property("Cliente") + .HasColumnType("text"); + + b.Property("Cpf") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataNascimento") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("Endereco") + .HasColumnType("text"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Linha") + .HasColumnType("text"); + + b.Property("Rg") + .HasColumnType("text"); + + b.Property("TelefoneFixo") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("Cliente"); + + b.HasIndex("Cpf"); + + b.HasIndex("Email"); + + b.HasIndex("Item"); + + b.HasIndex("Linha"); + + b.HasIndex("TenantId"); + + b.ToTable("UserDatas"); + }); + + modelBuilder.Entity("line_gestao_api.Models.VigenciaLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Cliente") + .HasColumnType("text"); + + b.Property("Conta") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DtEfetivacaoServico") + .HasColumnType("timestamp with time zone"); + + b.Property("DtTerminoFidelizacao") + .HasColumnType("timestamp with time zone"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Linha") + .HasColumnType("text"); + + b.Property("PlanoContrato") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Total") + .HasColumnType("numeric"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Usuario") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Cliente"); + + b.HasIndex("DtTerminoFidelizacao"); + + b.HasIndex("Item"); + + b.HasIndex("Linha"); + + b.HasIndex("TenantId"); + + b.ToTable("VigenciaLines"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("line_gestao_api.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("line_gestao_api.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("line_gestao_api.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("line_gestao_api.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("line_gestao_api.Models.MuregLine", b => + { + b.HasOne("line_gestao_api.Models.MobileLine", "MobileLine") + .WithMany("Muregs") + .HasForeignKey("MobileLineId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("MobileLine"); + }); + + modelBuilder.Entity("line_gestao_api.Models.Notification", b => + { + b.HasOne("line_gestao_api.Models.ApplicationUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("line_gestao_api.Models.VigenciaLine", "VigenciaLine") + .WithMany() + .HasForeignKey("VigenciaLineId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("User"); + + b.Navigation("VigenciaLine"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ParcelamentoMonthValue", b => + { + b.HasOne("line_gestao_api.Models.ParcelamentoLine", "ParcelamentoLine") + .WithMany("MonthValues") + .HasForeignKey("ParcelamentoLineId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ParcelamentoLine"); + }); + + modelBuilder.Entity("line_gestao_api.Models.MobileLine", b => + { + b.Navigation("Muregs"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ParcelamentoLine", b => + { + b.Navigation("MonthValues"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Migrations/20260202175823_AddParcelamentosTables.cs b/Migrations/20260202175823_AddParcelamentosTables.cs new file mode 100644 index 0000000..ff3e61f --- /dev/null +++ b/Migrations/20260202175823_AddParcelamentosTables.cs @@ -0,0 +1,98 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace line_gestao_api.Migrations +{ + /// + public partial class AddParcelamentosTables : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "ParcelamentoLines", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: false), + AnoRef = table.Column(type: "integer", nullable: true), + Item = table.Column(type: "integer", nullable: true), + Linha = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + Cliente = table.Column(type: "character varying(120)", maxLength: 120, nullable: true), + QtParcelas = table.Column(type: "character varying(32)", maxLength: 32, nullable: true), + ParcelaAtual = table.Column(type: "integer", nullable: true), + TotalParcelas = table.Column(type: "integer", nullable: true), + ValorCheio = table.Column(type: "numeric(18,2)", precision: 18, scale: 2, nullable: true), + Desconto = table.Column(type: "numeric(18,2)", precision: 18, scale: 2, nullable: true), + ValorComDesconto = table.Column(type: "numeric(18,2)", precision: 18, scale: 2, nullable: true), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ParcelamentoLines", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ParcelamentoMonthValues", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: false), + ParcelamentoLineId = table.Column(type: "uuid", nullable: false), + Competencia = table.Column(type: "date", nullable: false), + Valor = table.Column(type: "numeric(18,2)", precision: 18, scale: 2, nullable: true), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ParcelamentoMonthValues", x => x.Id); + table.ForeignKey( + name: "FK_ParcelamentoMonthValues_ParcelamentoLines_ParcelamentoLineId", + column: x => x.ParcelamentoLineId, + principalTable: "ParcelamentoLines", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_ParcelamentoLines_AnoRef_Item", + table: "ParcelamentoLines", + columns: new[] { "AnoRef", "Item" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_ParcelamentoLines_Linha", + table: "ParcelamentoLines", + column: "Linha"); + + migrationBuilder.CreateIndex( + name: "IX_ParcelamentoLines_TenantId", + table: "ParcelamentoLines", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_ParcelamentoMonthValues_ParcelamentoLineId_Competencia", + table: "ParcelamentoMonthValues", + columns: new[] { "ParcelamentoLineId", "Competencia" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_ParcelamentoMonthValues_TenantId", + table: "ParcelamentoMonthValues", + column: "TenantId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ParcelamentoMonthValues"); + + migrationBuilder.DropTable( + name: "ParcelamentoLines"); + } + } +} diff --git a/Migrations/20260203193033_AddVivoSyncTipoDeChipToMobileLines.Designer.cs b/Migrations/20260203193033_AddVivoSyncTipoDeChipToMobileLines.Designer.cs new file mode 100644 index 0000000..6d7f8e3 --- /dev/null +++ b/Migrations/20260203193033_AddVivoSyncTipoDeChipToMobileLines.Designer.cs @@ -0,0 +1,1412 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using line_gestao_api.Data; + +#nullable disable + +namespace line_gestao_api.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20260203193033_AddVivoSyncTipoDeChipToMobileLines")] + partial class AddVivoSyncTipoDeChipToMobileLines + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("line_gestao_api.Models.ApplicationUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(120) + .HasColumnType("character varying(120)"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.HasIndex("TenantId", "NormalizedEmail") + .IsUnique(); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("line_gestao_api.Models.BillingClient", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Aparelho") + .HasColumnType("text"); + + b.Property("Cliente") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FormaPagamento") + .HasColumnType("text"); + + b.Property("FranquiaLine") + .HasColumnType("numeric"); + + b.Property("FranquiaVivo") + .HasColumnType("numeric"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Lucro") + .HasColumnType("numeric"); + + b.Property("QtdLinhas") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Tipo") + .IsRequired() + .HasMaxLength(2) + .HasColumnType("character varying(2)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorContratoLine") + .HasColumnType("numeric"); + + b.Property("ValorContratoVivo") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.HasIndex("Cliente"); + + b.HasIndex("Item"); + + b.HasIndex("TenantId"); + + b.HasIndex("Tipo"); + + b.HasIndex("Tipo", "Cliente"); + + b.ToTable("billing_clients", (string)null); + }); + + modelBuilder.Entity("line_gestao_api.Models.ChipVirgemLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("NumeroDoChip") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Observacoes") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("Item"); + + b.HasIndex("NumeroDoChip"); + + b.HasIndex("TenantId"); + + b.ToTable("ChipVirgemLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ControleRecebidoLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Ano") + .HasColumnType("integer"); + + b.Property("Chip") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("ConteudoDaNf") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataDaNf") + .HasColumnType("timestamp with time zone"); + + b.Property("DataDoRecebimento") + .HasColumnType("timestamp with time zone"); + + b.Property("IsResumo") + .HasColumnType("boolean"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("NotaFiscal") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("NumeroDaLinha") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Quantidade") + .HasColumnType("integer"); + + b.Property("Serial") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorDaNf") + .HasColumnType("numeric"); + + b.Property("ValorUnit") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.HasIndex("Ano"); + + b.HasIndex("Chip"); + + b.HasIndex("DataDaNf"); + + b.HasIndex("DataDoRecebimento"); + + b.HasIndex("Item"); + + b.HasIndex("NotaFiscal"); + + b.HasIndex("NumeroDaLinha"); + + b.HasIndex("Serial"); + + b.HasIndex("TenantId"); + + b.ToTable("ControleRecebidoLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.MobileLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Cedente") + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("Chip") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Cliente") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Conta") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataBloqueio") + .HasColumnType("timestamp with time zone"); + + b.Property("DataEntregaCliente") + .HasColumnType("timestamp with time zone"); + + b.Property("DataEntregaOpera") + .HasColumnType("timestamp with time zone"); + + b.Property("Desconto") + .HasColumnType("numeric"); + + b.Property("FranquiaGestao") + .HasColumnType("numeric"); + + b.Property("FranquiaLine") + .HasColumnType("numeric"); + + b.Property("FranquiaVivo") + .HasColumnType("numeric"); + + b.Property("GestaoVozDados") + .HasColumnType("numeric"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Linha") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("LocacaoAp") + .HasColumnType("numeric"); + + b.Property("Lucro") + .HasColumnType("numeric"); + + b.Property("Modalidade") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("PlanoContrato") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Skeelo") + .HasColumnType("numeric"); + + b.Property("Skil") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("Solicitante") + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("Status") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TipoDeChip") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Usuario") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ValorContratoLine") + .HasColumnType("numeric"); + + b.Property("ValorContratoVivo") + .HasColumnType("numeric"); + + b.Property("ValorPlanoVivo") + .HasColumnType("numeric"); + + b.Property("VencConta") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("VivoGestaoDispositivo") + .HasColumnType("numeric"); + + b.Property("VivoNewsPlus") + .HasColumnType("numeric"); + + b.Property("VivoSync") + .HasColumnType("numeric"); + + b.Property("VivoTravelMundo") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.HasIndex("Chip"); + + b.HasIndex("Cliente"); + + b.HasIndex("Skil"); + + b.HasIndex("Status"); + + b.HasIndex("Usuario"); + + b.HasIndex("TenantId", "Linha") + .IsUnique(); + + b.ToTable("MobileLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.MuregLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataDaMureg") + .HasColumnType("timestamp with time zone"); + + b.Property("ICCID") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("LinhaAntiga") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("LinhaNova") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("MobileLineId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("ICCID"); + + b.HasIndex("Item"); + + b.HasIndex("LinhaAntiga"); + + b.HasIndex("LinhaNova"); + + b.HasIndex("MobileLineId"); + + b.HasIndex("TenantId"); + + b.ToTable("MuregLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.Notification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Cliente") + .HasColumnType("text"); + + b.Property("Data") + .HasColumnType("timestamp with time zone"); + + b.Property("DedupKey") + .IsRequired() + .HasColumnType("text"); + + b.Property("DiasParaVencer") + .HasColumnType("integer"); + + b.Property("Lida") + .HasColumnType("boolean"); + + b.Property("LidaEm") + .HasColumnType("timestamp with time zone"); + + b.Property("Linha") + .HasColumnType("text"); + + b.Property("Mensagem") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReferenciaData") + .HasColumnType("timestamp with time zone"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Tipo") + .IsRequired() + .HasColumnType("text"); + + b.Property("Titulo") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("Usuario") + .HasColumnType("text"); + + b.Property("VigenciaLineId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("Cliente"); + + b.HasIndex("Data"); + + b.HasIndex("DedupKey") + .IsUnique(); + + b.HasIndex("Lida"); + + b.HasIndex("TenantId"); + + b.HasIndex("UserId"); + + b.HasIndex("VigenciaLineId"); + + b.ToTable("Notifications"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ParcelamentoLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AnoRef") + .HasColumnType("integer"); + + b.Property("Cliente") + .HasMaxLength(120) + .HasColumnType("character varying(120)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Desconto") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Linha") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("ParcelaAtual") + .HasColumnType("integer"); + + b.Property("QtParcelas") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TotalParcelas") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorCheio") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.Property("ValorComDesconto") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("Linha"); + + b.HasIndex("TenantId"); + + b.HasIndex("AnoRef", "Item") + .IsUnique(); + + b.ToTable("ParcelamentoLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ParcelamentoMonthValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Competencia") + .HasColumnType("date"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ParcelamentoLineId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Valor") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.HasIndex("ParcelamentoLineId", "Competencia") + .IsUnique(); + + b.ToTable("ParcelamentoMonthValues"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoClienteEspecial", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Nome") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Valor") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoClienteEspeciais"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoLineTotais", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LucroTotalLine") + .HasColumnType("numeric"); + + b.Property("QtdLinhas") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Tipo") + .HasColumnType("text"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorTotalLine") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoLineTotais"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoMacrophonyPlan", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaGb") + .HasColumnType("numeric"); + + b.Property("Gb") + .HasColumnType("numeric"); + + b.Property("PlanoContrato") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TotalLinhas") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorIndividualComSvas") + .HasColumnType("numeric"); + + b.Property("ValorTotal") + .HasColumnType("numeric"); + + b.Property("VivoTravel") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("ResumoMacrophonyPlans"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoMacrophonyTotal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaGbTotal") + .HasColumnType("numeric"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TotalLinhasTotal") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorTotal") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoMacrophonyTotals"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoPlanoContratoResumo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaGb") + .HasColumnType("numeric"); + + b.Property("Gb") + .HasColumnType("numeric"); + + b.Property("PlanoContrato") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TotalLinhas") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorIndividualComSvas") + .HasColumnType("numeric"); + + b.Property("ValorTotal") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoPlanoContratoResumos"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoPlanoContratoTotal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorTotal") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoPlanoContratoTotals"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoReservaLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Ddd") + .HasColumnType("text"); + + b.Property("FranquiaGb") + .HasColumnType("numeric"); + + b.Property("QtdLinhas") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Total") + .HasColumnType("numeric"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("ResumoReservaLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoReservaTotal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("QtdLinhasTotal") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Total") + .HasColumnType("numeric"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("ResumoReservaTotals"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoVivoLineResumo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Cliente") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaLine") + .HasColumnType("numeric"); + + b.Property("FranquiaTotal") + .HasColumnType("numeric"); + + b.Property("Lucro") + .HasColumnType("numeric"); + + b.Property("QtdLinhas") + .HasColumnType("integer"); + + b.Property("Skil") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorContratoLine") + .HasColumnType("numeric"); + + b.Property("ValorContratoVivo") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoVivoLineResumos"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoVivoLineTotal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaLine") + .HasColumnType("numeric"); + + b.Property("FranquiaTotal") + .HasColumnType("numeric"); + + b.Property("Lucro") + .HasColumnType("numeric"); + + b.Property("QtdLinhasTotal") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorContratoLine") + .HasColumnType("numeric"); + + b.Property("ValorContratoVivo") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoVivoLineTotals"); + }); + + modelBuilder.Entity("line_gestao_api.Models.Tenant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Tenants"); + }); + + modelBuilder.Entity("line_gestao_api.Models.TrocaNumeroLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataTroca") + .HasColumnType("timestamp with time zone"); + + b.Property("ICCID") + .HasColumnType("text"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("LinhaAntiga") + .HasColumnType("text"); + + b.Property("LinhaNova") + .HasColumnType("text"); + + b.Property("Motivo") + .HasColumnType("text"); + + b.Property("Observacao") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("DataTroca"); + + b.HasIndex("ICCID"); + + b.HasIndex("Item"); + + b.HasIndex("LinhaAntiga"); + + b.HasIndex("LinhaNova"); + + b.HasIndex("TenantId"); + + b.ToTable("TrocaNumeroLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.UserData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Celular") + .HasColumnType("text"); + + b.Property("Cliente") + .HasColumnType("text"); + + b.Property("Cpf") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataNascimento") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("Endereco") + .HasColumnType("text"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Linha") + .HasColumnType("text"); + + b.Property("Rg") + .HasColumnType("text"); + + b.Property("TelefoneFixo") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("Cliente"); + + b.HasIndex("Cpf"); + + b.HasIndex("Email"); + + b.HasIndex("Item"); + + b.HasIndex("Linha"); + + b.HasIndex("TenantId"); + + b.ToTable("UserDatas"); + }); + + modelBuilder.Entity("line_gestao_api.Models.VigenciaLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Cliente") + .HasColumnType("text"); + + b.Property("Conta") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DtEfetivacaoServico") + .HasColumnType("timestamp with time zone"); + + b.Property("DtTerminoFidelizacao") + .HasColumnType("timestamp with time zone"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Linha") + .HasColumnType("text"); + + b.Property("PlanoContrato") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Total") + .HasColumnType("numeric"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Usuario") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Cliente"); + + b.HasIndex("DtTerminoFidelizacao"); + + b.HasIndex("Item"); + + b.HasIndex("Linha"); + + b.HasIndex("TenantId"); + + b.ToTable("VigenciaLines"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("line_gestao_api.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("line_gestao_api.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("line_gestao_api.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("line_gestao_api.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("line_gestao_api.Models.MuregLine", b => + { + b.HasOne("line_gestao_api.Models.MobileLine", "MobileLine") + .WithMany("Muregs") + .HasForeignKey("MobileLineId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("MobileLine"); + }); + + modelBuilder.Entity("line_gestao_api.Models.Notification", b => + { + b.HasOne("line_gestao_api.Models.ApplicationUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("line_gestao_api.Models.VigenciaLine", "VigenciaLine") + .WithMany() + .HasForeignKey("VigenciaLineId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("User"); + + b.Navigation("VigenciaLine"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ParcelamentoMonthValue", b => + { + b.HasOne("line_gestao_api.Models.ParcelamentoLine", "ParcelamentoLine") + .WithMany("MonthValues") + .HasForeignKey("ParcelamentoLineId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ParcelamentoLine"); + }); + + modelBuilder.Entity("line_gestao_api.Models.MobileLine", b => + { + b.Navigation("Muregs"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ParcelamentoLine", b => + { + b.Navigation("MonthValues"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Migrations/20260203193033_AddVivoSyncTipoDeChipToMobileLines.cs b/Migrations/20260203193033_AddVivoSyncTipoDeChipToMobileLines.cs new file mode 100644 index 0000000..d600c30 --- /dev/null +++ b/Migrations/20260203193033_AddVivoSyncTipoDeChipToMobileLines.cs @@ -0,0 +1,39 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace line_gestao_api.Migrations +{ + /// + public partial class AddVivoSyncTipoDeChipToMobileLines : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "TipoDeChip", + table: "MobileLines", + type: "character varying(80)", + maxLength: 80, + nullable: true); + + migrationBuilder.AddColumn( + name: "VivoSync", + table: "MobileLines", + type: "numeric", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "TipoDeChip", + table: "MobileLines"); + + migrationBuilder.DropColumn( + name: "VivoSync", + table: "MobileLines"); + } + } +} diff --git a/Migrations/20260205143959_AddUserDataPessoaFields.Designer.cs b/Migrations/20260205143959_AddUserDataPessoaFields.Designer.cs new file mode 100644 index 0000000..1d687a5 --- /dev/null +++ b/Migrations/20260205143959_AddUserDataPessoaFields.Designer.cs @@ -0,0 +1,1509 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using line_gestao_api.Data; + +#nullable disable + +namespace line_gestao_api.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20260205143959_AddUserDataPessoaFields")] + partial class AddUserDataPessoaFields + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("line_gestao_api.Models.ApplicationUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(120) + .HasColumnType("character varying(120)"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.HasIndex("TenantId", "NormalizedEmail") + .IsUnique(); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("line_gestao_api.Models.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Action") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("ChangesJson") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("EntityId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("EntityLabel") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("EntityName") + .IsRequired() + .HasMaxLength(120) + .HasColumnType("character varying(120)"); + + b.Property("IpAddress") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("OccurredAtUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("Page") + .IsRequired() + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("RequestMethod") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("RequestPath") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UserEmail") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("UserName") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("Id"); + + b.HasIndex("EntityName"); + + b.HasIndex("OccurredAtUtc"); + + b.HasIndex("Page"); + + b.HasIndex("TenantId"); + + b.HasIndex("UserId"); + + b.ToTable("AuditLogs"); + }); + + modelBuilder.Entity("line_gestao_api.Models.BillingClient", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Aparelho") + .HasColumnType("text"); + + b.Property("Cliente") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FormaPagamento") + .HasColumnType("text"); + + b.Property("FranquiaLine") + .HasColumnType("numeric"); + + b.Property("FranquiaVivo") + .HasColumnType("numeric"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Lucro") + .HasColumnType("numeric"); + + b.Property("QtdLinhas") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Tipo") + .IsRequired() + .HasMaxLength(2) + .HasColumnType("character varying(2)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorContratoLine") + .HasColumnType("numeric"); + + b.Property("ValorContratoVivo") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.HasIndex("Cliente"); + + b.HasIndex("Item"); + + b.HasIndex("TenantId"); + + b.HasIndex("Tipo"); + + b.HasIndex("Tipo", "Cliente"); + + b.ToTable("billing_clients", (string)null); + }); + + modelBuilder.Entity("line_gestao_api.Models.ChipVirgemLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("NumeroDoChip") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Observacoes") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("Item"); + + b.HasIndex("NumeroDoChip"); + + b.HasIndex("TenantId"); + + b.ToTable("ChipVirgemLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ControleRecebidoLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Ano") + .HasColumnType("integer"); + + b.Property("Chip") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("ConteudoDaNf") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataDaNf") + .HasColumnType("timestamp with time zone"); + + b.Property("DataDoRecebimento") + .HasColumnType("timestamp with time zone"); + + b.Property("IsResumo") + .HasColumnType("boolean"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("NotaFiscal") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("NumeroDaLinha") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Quantidade") + .HasColumnType("integer"); + + b.Property("Serial") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorDaNf") + .HasColumnType("numeric"); + + b.Property("ValorUnit") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.HasIndex("Ano"); + + b.HasIndex("Chip"); + + b.HasIndex("DataDaNf"); + + b.HasIndex("DataDoRecebimento"); + + b.HasIndex("Item"); + + b.HasIndex("NotaFiscal"); + + b.HasIndex("NumeroDaLinha"); + + b.HasIndex("Serial"); + + b.HasIndex("TenantId"); + + b.ToTable("ControleRecebidoLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.MobileLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Cedente") + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("Chip") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Cliente") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Conta") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataBloqueio") + .HasColumnType("timestamp with time zone"); + + b.Property("DataEntregaCliente") + .HasColumnType("timestamp with time zone"); + + b.Property("DataEntregaOpera") + .HasColumnType("timestamp with time zone"); + + b.Property("Desconto") + .HasColumnType("numeric"); + + b.Property("FranquiaGestao") + .HasColumnType("numeric"); + + b.Property("FranquiaLine") + .HasColumnType("numeric"); + + b.Property("FranquiaVivo") + .HasColumnType("numeric"); + + b.Property("GestaoVozDados") + .HasColumnType("numeric"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Linha") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("LocacaoAp") + .HasColumnType("numeric"); + + b.Property("Lucro") + .HasColumnType("numeric"); + + b.Property("Modalidade") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("PlanoContrato") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Skeelo") + .HasColumnType("numeric"); + + b.Property("Skil") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("Solicitante") + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("Status") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TipoDeChip") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Usuario") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ValorContratoLine") + .HasColumnType("numeric"); + + b.Property("ValorContratoVivo") + .HasColumnType("numeric"); + + b.Property("ValorPlanoVivo") + .HasColumnType("numeric"); + + b.Property("VencConta") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("VivoGestaoDispositivo") + .HasColumnType("numeric"); + + b.Property("VivoNewsPlus") + .HasColumnType("numeric"); + + b.Property("VivoSync") + .HasColumnType("numeric"); + + b.Property("VivoTravelMundo") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.HasIndex("Chip"); + + b.HasIndex("Cliente"); + + b.HasIndex("Skil"); + + b.HasIndex("Status"); + + b.HasIndex("Usuario"); + + b.HasIndex("TenantId", "Linha") + .IsUnique(); + + b.ToTable("MobileLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.MuregLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataDaMureg") + .HasColumnType("timestamp with time zone"); + + b.Property("ICCID") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("LinhaAntiga") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("LinhaNova") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("MobileLineId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("ICCID"); + + b.HasIndex("Item"); + + b.HasIndex("LinhaAntiga"); + + b.HasIndex("LinhaNova"); + + b.HasIndex("MobileLineId"); + + b.HasIndex("TenantId"); + + b.ToTable("MuregLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.Notification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Cliente") + .HasColumnType("text"); + + b.Property("Data") + .HasColumnType("timestamp with time zone"); + + b.Property("DedupKey") + .IsRequired() + .HasColumnType("text"); + + b.Property("DiasParaVencer") + .HasColumnType("integer"); + + b.Property("Lida") + .HasColumnType("boolean"); + + b.Property("LidaEm") + .HasColumnType("timestamp with time zone"); + + b.Property("Linha") + .HasColumnType("text"); + + b.Property("Mensagem") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReferenciaData") + .HasColumnType("timestamp with time zone"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Tipo") + .IsRequired() + .HasColumnType("text"); + + b.Property("Titulo") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("Usuario") + .HasColumnType("text"); + + b.Property("VigenciaLineId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("Cliente"); + + b.HasIndex("Data"); + + b.HasIndex("DedupKey") + .IsUnique(); + + b.HasIndex("Lida"); + + b.HasIndex("TenantId"); + + b.HasIndex("UserId"); + + b.HasIndex("VigenciaLineId"); + + b.ToTable("Notifications"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ParcelamentoLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AnoRef") + .HasColumnType("integer"); + + b.Property("Cliente") + .HasMaxLength(120) + .HasColumnType("character varying(120)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Desconto") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Linha") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("ParcelaAtual") + .HasColumnType("integer"); + + b.Property("QtParcelas") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TotalParcelas") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorCheio") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.Property("ValorComDesconto") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("Linha"); + + b.HasIndex("TenantId"); + + b.HasIndex("AnoRef", "Item") + .IsUnique(); + + b.ToTable("ParcelamentoLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ParcelamentoMonthValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Competencia") + .HasColumnType("date"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ParcelamentoLineId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Valor") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.HasIndex("ParcelamentoLineId", "Competencia") + .IsUnique(); + + b.ToTable("ParcelamentoMonthValues"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoClienteEspecial", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Nome") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Valor") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoClienteEspeciais"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoLineTotais", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LucroTotalLine") + .HasColumnType("numeric"); + + b.Property("QtdLinhas") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Tipo") + .HasColumnType("text"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorTotalLine") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoLineTotais"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoMacrophonyPlan", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaGb") + .HasColumnType("numeric"); + + b.Property("Gb") + .HasColumnType("numeric"); + + b.Property("PlanoContrato") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TotalLinhas") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorIndividualComSvas") + .HasColumnType("numeric"); + + b.Property("ValorTotal") + .HasColumnType("numeric"); + + b.Property("VivoTravel") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("ResumoMacrophonyPlans"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoMacrophonyTotal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaGbTotal") + .HasColumnType("numeric"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TotalLinhasTotal") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorTotal") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoMacrophonyTotals"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoPlanoContratoResumo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaGb") + .HasColumnType("numeric"); + + b.Property("Gb") + .HasColumnType("numeric"); + + b.Property("PlanoContrato") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TotalLinhas") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorIndividualComSvas") + .HasColumnType("numeric"); + + b.Property("ValorTotal") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoPlanoContratoResumos"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoPlanoContratoTotal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorTotal") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoPlanoContratoTotals"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoReservaLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Ddd") + .HasColumnType("text"); + + b.Property("FranquiaGb") + .HasColumnType("numeric"); + + b.Property("QtdLinhas") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Total") + .HasColumnType("numeric"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("ResumoReservaLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoReservaTotal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("QtdLinhasTotal") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Total") + .HasColumnType("numeric"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("ResumoReservaTotals"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoVivoLineResumo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Cliente") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaLine") + .HasColumnType("numeric"); + + b.Property("FranquiaTotal") + .HasColumnType("numeric"); + + b.Property("Lucro") + .HasColumnType("numeric"); + + b.Property("QtdLinhas") + .HasColumnType("integer"); + + b.Property("Skil") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorContratoLine") + .HasColumnType("numeric"); + + b.Property("ValorContratoVivo") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoVivoLineResumos"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoVivoLineTotal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaLine") + .HasColumnType("numeric"); + + b.Property("FranquiaTotal") + .HasColumnType("numeric"); + + b.Property("Lucro") + .HasColumnType("numeric"); + + b.Property("QtdLinhasTotal") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorContratoLine") + .HasColumnType("numeric"); + + b.Property("ValorContratoVivo") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoVivoLineTotals"); + }); + + modelBuilder.Entity("line_gestao_api.Models.Tenant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Tenants"); + }); + + modelBuilder.Entity("line_gestao_api.Models.TrocaNumeroLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataTroca") + .HasColumnType("timestamp with time zone"); + + b.Property("ICCID") + .HasColumnType("text"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("LinhaAntiga") + .HasColumnType("text"); + + b.Property("LinhaNova") + .HasColumnType("text"); + + b.Property("Motivo") + .HasColumnType("text"); + + b.Property("Observacao") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("DataTroca"); + + b.HasIndex("ICCID"); + + b.HasIndex("Item"); + + b.HasIndex("LinhaAntiga"); + + b.HasIndex("LinhaNova"); + + b.HasIndex("TenantId"); + + b.ToTable("TrocaNumeroLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.UserData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Celular") + .HasColumnType("text"); + + b.Property("Cliente") + .HasColumnType("text"); + + b.Property("Cnpj") + .HasColumnType("text"); + + b.Property("Cpf") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataNascimento") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("Endereco") + .HasColumnType("text"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Linha") + .HasColumnType("text"); + + b.Property("Nome") + .HasColumnType("text"); + + b.Property("RazaoSocial") + .HasColumnType("text"); + + b.Property("Rg") + .HasColumnType("text"); + + b.Property("TelefoneFixo") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TipoPessoa") + .HasColumnType("text"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("Cliente"); + + b.HasIndex("Cnpj"); + + b.HasIndex("Cpf"); + + b.HasIndex("Email"); + + b.HasIndex("Item"); + + b.HasIndex("Linha"); + + b.HasIndex("Nome"); + + b.HasIndex("RazaoSocial"); + + b.HasIndex("TenantId"); + + b.HasIndex("TipoPessoa"); + + b.ToTable("UserDatas"); + }); + + modelBuilder.Entity("line_gestao_api.Models.VigenciaLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Cliente") + .HasColumnType("text"); + + b.Property("Conta") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DtEfetivacaoServico") + .HasColumnType("timestamp with time zone"); + + b.Property("DtTerminoFidelizacao") + .HasColumnType("timestamp with time zone"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Linha") + .HasColumnType("text"); + + b.Property("PlanoContrato") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Total") + .HasColumnType("numeric"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Usuario") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Cliente"); + + b.HasIndex("DtTerminoFidelizacao"); + + b.HasIndex("Item"); + + b.HasIndex("Linha"); + + b.HasIndex("TenantId"); + + b.ToTable("VigenciaLines"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("line_gestao_api.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("line_gestao_api.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("line_gestao_api.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("line_gestao_api.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("line_gestao_api.Models.MuregLine", b => + { + b.HasOne("line_gestao_api.Models.MobileLine", "MobileLine") + .WithMany("Muregs") + .HasForeignKey("MobileLineId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("MobileLine"); + }); + + modelBuilder.Entity("line_gestao_api.Models.Notification", b => + { + b.HasOne("line_gestao_api.Models.ApplicationUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("line_gestao_api.Models.VigenciaLine", "VigenciaLine") + .WithMany() + .HasForeignKey("VigenciaLineId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("User"); + + b.Navigation("VigenciaLine"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ParcelamentoMonthValue", b => + { + b.HasOne("line_gestao_api.Models.ParcelamentoLine", "ParcelamentoLine") + .WithMany("MonthValues") + .HasForeignKey("ParcelamentoLineId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ParcelamentoLine"); + }); + + modelBuilder.Entity("line_gestao_api.Models.MobileLine", b => + { + b.Navigation("Muregs"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ParcelamentoLine", b => + { + b.Navigation("MonthValues"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Migrations/20260205143959_AddUserDataPessoaFields.cs b/Migrations/20260205143959_AddUserDataPessoaFields.cs new file mode 100644 index 0000000..cf7456e --- /dev/null +++ b/Migrations/20260205143959_AddUserDataPessoaFields.cs @@ -0,0 +1,94 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace line_gestao_api.Migrations +{ + /// + public partial class AddUserDataPessoaFields : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Cnpj", + table: "UserDatas", + type: "text", + nullable: true); + + migrationBuilder.AddColumn( + name: "Nome", + table: "UserDatas", + type: "text", + nullable: true); + + migrationBuilder.AddColumn( + name: "RazaoSocial", + table: "UserDatas", + type: "text", + nullable: true); + + migrationBuilder.AddColumn( + name: "TipoPessoa", + table: "UserDatas", + type: "text", + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_UserDatas_Cnpj", + table: "UserDatas", + column: "Cnpj"); + + migrationBuilder.CreateIndex( + name: "IX_UserDatas_Nome", + table: "UserDatas", + column: "Nome"); + + migrationBuilder.CreateIndex( + name: "IX_UserDatas_RazaoSocial", + table: "UserDatas", + column: "RazaoSocial"); + + migrationBuilder.CreateIndex( + name: "IX_UserDatas_TipoPessoa", + table: "UserDatas", + column: "TipoPessoa"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_UserDatas_Cnpj", + table: "UserDatas"); + + migrationBuilder.DropIndex( + name: "IX_UserDatas_Nome", + table: "UserDatas"); + + migrationBuilder.DropIndex( + name: "IX_UserDatas_RazaoSocial", + table: "UserDatas"); + + migrationBuilder.DropIndex( + name: "IX_UserDatas_TipoPessoa", + table: "UserDatas"); + + migrationBuilder.DropColumn( + name: "Cnpj", + table: "UserDatas"); + + migrationBuilder.DropColumn( + name: "Nome", + table: "UserDatas"); + + migrationBuilder.DropColumn( + name: "RazaoSocial", + table: "UserDatas"); + + migrationBuilder.DropColumn( + name: "TipoPessoa", + table: "UserDatas"); + } + } +} diff --git a/Migrations/20260205151645_AddResumoReservaTotalGeral.Designer.cs b/Migrations/20260205151645_AddResumoReservaTotalGeral.Designer.cs new file mode 100644 index 0000000..04e8782 --- /dev/null +++ b/Migrations/20260205151645_AddResumoReservaTotalGeral.Designer.cs @@ -0,0 +1,1512 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using line_gestao_api.Data; + +#nullable disable + +namespace line_gestao_api.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20260205151645_AddResumoReservaTotalGeral")] + partial class AddResumoReservaTotalGeral + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("line_gestao_api.Models.ApplicationUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(120) + .HasColumnType("character varying(120)"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.HasIndex("TenantId", "NormalizedEmail") + .IsUnique(); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("line_gestao_api.Models.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Action") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("ChangesJson") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("EntityId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("EntityLabel") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("EntityName") + .IsRequired() + .HasMaxLength(120) + .HasColumnType("character varying(120)"); + + b.Property("IpAddress") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("OccurredAtUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("Page") + .IsRequired() + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("RequestMethod") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("RequestPath") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UserEmail") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("UserName") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("Id"); + + b.HasIndex("EntityName"); + + b.HasIndex("OccurredAtUtc"); + + b.HasIndex("Page"); + + b.HasIndex("TenantId"); + + b.HasIndex("UserId"); + + b.ToTable("AuditLogs"); + }); + + modelBuilder.Entity("line_gestao_api.Models.BillingClient", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Aparelho") + .HasColumnType("text"); + + b.Property("Cliente") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FormaPagamento") + .HasColumnType("text"); + + b.Property("FranquiaLine") + .HasColumnType("numeric"); + + b.Property("FranquiaVivo") + .HasColumnType("numeric"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Lucro") + .HasColumnType("numeric"); + + b.Property("QtdLinhas") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Tipo") + .IsRequired() + .HasMaxLength(2) + .HasColumnType("character varying(2)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorContratoLine") + .HasColumnType("numeric"); + + b.Property("ValorContratoVivo") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.HasIndex("Cliente"); + + b.HasIndex("Item"); + + b.HasIndex("TenantId"); + + b.HasIndex("Tipo"); + + b.HasIndex("Tipo", "Cliente"); + + b.ToTable("billing_clients", (string)null); + }); + + modelBuilder.Entity("line_gestao_api.Models.ChipVirgemLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("NumeroDoChip") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Observacoes") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("Item"); + + b.HasIndex("NumeroDoChip"); + + b.HasIndex("TenantId"); + + b.ToTable("ChipVirgemLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ControleRecebidoLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Ano") + .HasColumnType("integer"); + + b.Property("Chip") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("ConteudoDaNf") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataDaNf") + .HasColumnType("timestamp with time zone"); + + b.Property("DataDoRecebimento") + .HasColumnType("timestamp with time zone"); + + b.Property("IsResumo") + .HasColumnType("boolean"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("NotaFiscal") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("NumeroDaLinha") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Quantidade") + .HasColumnType("integer"); + + b.Property("Serial") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorDaNf") + .HasColumnType("numeric"); + + b.Property("ValorUnit") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.HasIndex("Ano"); + + b.HasIndex("Chip"); + + b.HasIndex("DataDaNf"); + + b.HasIndex("DataDoRecebimento"); + + b.HasIndex("Item"); + + b.HasIndex("NotaFiscal"); + + b.HasIndex("NumeroDaLinha"); + + b.HasIndex("Serial"); + + b.HasIndex("TenantId"); + + b.ToTable("ControleRecebidoLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.MobileLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Cedente") + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("Chip") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Cliente") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Conta") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataBloqueio") + .HasColumnType("timestamp with time zone"); + + b.Property("DataEntregaCliente") + .HasColumnType("timestamp with time zone"); + + b.Property("DataEntregaOpera") + .HasColumnType("timestamp with time zone"); + + b.Property("Desconto") + .HasColumnType("numeric"); + + b.Property("FranquiaGestao") + .HasColumnType("numeric"); + + b.Property("FranquiaLine") + .HasColumnType("numeric"); + + b.Property("FranquiaVivo") + .HasColumnType("numeric"); + + b.Property("GestaoVozDados") + .HasColumnType("numeric"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Linha") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("LocacaoAp") + .HasColumnType("numeric"); + + b.Property("Lucro") + .HasColumnType("numeric"); + + b.Property("Modalidade") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("PlanoContrato") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Skeelo") + .HasColumnType("numeric"); + + b.Property("Skil") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("Solicitante") + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("Status") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TipoDeChip") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Usuario") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ValorContratoLine") + .HasColumnType("numeric"); + + b.Property("ValorContratoVivo") + .HasColumnType("numeric"); + + b.Property("ValorPlanoVivo") + .HasColumnType("numeric"); + + b.Property("VencConta") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("VivoGestaoDispositivo") + .HasColumnType("numeric"); + + b.Property("VivoNewsPlus") + .HasColumnType("numeric"); + + b.Property("VivoSync") + .HasColumnType("numeric"); + + b.Property("VivoTravelMundo") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.HasIndex("Chip"); + + b.HasIndex("Cliente"); + + b.HasIndex("Skil"); + + b.HasIndex("Status"); + + b.HasIndex("Usuario"); + + b.HasIndex("TenantId", "Linha") + .IsUnique(); + + b.ToTable("MobileLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.MuregLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataDaMureg") + .HasColumnType("timestamp with time zone"); + + b.Property("ICCID") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("LinhaAntiga") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("LinhaNova") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("MobileLineId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("ICCID"); + + b.HasIndex("Item"); + + b.HasIndex("LinhaAntiga"); + + b.HasIndex("LinhaNova"); + + b.HasIndex("MobileLineId"); + + b.HasIndex("TenantId"); + + b.ToTable("MuregLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.Notification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Cliente") + .HasColumnType("text"); + + b.Property("Data") + .HasColumnType("timestamp with time zone"); + + b.Property("DedupKey") + .IsRequired() + .HasColumnType("text"); + + b.Property("DiasParaVencer") + .HasColumnType("integer"); + + b.Property("Lida") + .HasColumnType("boolean"); + + b.Property("LidaEm") + .HasColumnType("timestamp with time zone"); + + b.Property("Linha") + .HasColumnType("text"); + + b.Property("Mensagem") + .IsRequired() + .HasColumnType("text"); + + b.Property("ReferenciaData") + .HasColumnType("timestamp with time zone"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Tipo") + .IsRequired() + .HasColumnType("text"); + + b.Property("Titulo") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("Usuario") + .HasColumnType("text"); + + b.Property("VigenciaLineId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("Cliente"); + + b.HasIndex("Data"); + + b.HasIndex("DedupKey") + .IsUnique(); + + b.HasIndex("Lida"); + + b.HasIndex("TenantId"); + + b.HasIndex("UserId"); + + b.HasIndex("VigenciaLineId"); + + b.ToTable("Notifications"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ParcelamentoLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AnoRef") + .HasColumnType("integer"); + + b.Property("Cliente") + .HasMaxLength(120) + .HasColumnType("character varying(120)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Desconto") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Linha") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("ParcelaAtual") + .HasColumnType("integer"); + + b.Property("QtParcelas") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TotalParcelas") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorCheio") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.Property("ValorComDesconto") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("Linha"); + + b.HasIndex("TenantId"); + + b.HasIndex("AnoRef", "Item") + .IsUnique(); + + b.ToTable("ParcelamentoLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ParcelamentoMonthValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Competencia") + .HasColumnType("date"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ParcelamentoLineId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Valor") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.HasIndex("ParcelamentoLineId", "Competencia") + .IsUnique(); + + b.ToTable("ParcelamentoMonthValues"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoClienteEspecial", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Nome") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Valor") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoClienteEspeciais"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoLineTotais", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LucroTotalLine") + .HasColumnType("numeric"); + + b.Property("QtdLinhas") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Tipo") + .HasColumnType("text"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorTotalLine") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoLineTotais"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoMacrophonyPlan", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaGb") + .HasColumnType("numeric"); + + b.Property("Gb") + .HasColumnType("numeric"); + + b.Property("PlanoContrato") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TotalLinhas") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorIndividualComSvas") + .HasColumnType("numeric"); + + b.Property("ValorTotal") + .HasColumnType("numeric"); + + b.Property("VivoTravel") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("ResumoMacrophonyPlans"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoMacrophonyTotal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaGbTotal") + .HasColumnType("numeric"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TotalLinhasTotal") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorTotal") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoMacrophonyTotals"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoPlanoContratoResumo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaGb") + .HasColumnType("numeric"); + + b.Property("Gb") + .HasColumnType("numeric"); + + b.Property("PlanoContrato") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TotalLinhas") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorIndividualComSvas") + .HasColumnType("numeric"); + + b.Property("ValorTotal") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoPlanoContratoResumos"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoPlanoContratoTotal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorTotal") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoPlanoContratoTotals"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoReservaLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Ddd") + .HasColumnType("text"); + + b.Property("FranquiaGb") + .HasColumnType("numeric"); + + b.Property("QtdLinhas") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Total") + .HasColumnType("numeric"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("ResumoReservaLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoReservaTotal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("QtdLinhasTotal") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Total") + .HasColumnType("numeric"); + + b.Property("TotalGeralLinhasReserva") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("ResumoReservaTotals"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoVivoLineResumo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Cliente") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaLine") + .HasColumnType("numeric"); + + b.Property("FranquiaTotal") + .HasColumnType("numeric"); + + b.Property("Lucro") + .HasColumnType("numeric"); + + b.Property("QtdLinhas") + .HasColumnType("integer"); + + b.Property("Skil") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorContratoLine") + .HasColumnType("numeric"); + + b.Property("ValorContratoVivo") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoVivoLineResumos"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoVivoLineTotal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaLine") + .HasColumnType("numeric"); + + b.Property("FranquiaTotal") + .HasColumnType("numeric"); + + b.Property("Lucro") + .HasColumnType("numeric"); + + b.Property("QtdLinhasTotal") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorContratoLine") + .HasColumnType("numeric"); + + b.Property("ValorContratoVivo") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoVivoLineTotals"); + }); + + modelBuilder.Entity("line_gestao_api.Models.Tenant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Tenants"); + }); + + modelBuilder.Entity("line_gestao_api.Models.TrocaNumeroLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataTroca") + .HasColumnType("timestamp with time zone"); + + b.Property("ICCID") + .HasColumnType("text"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("LinhaAntiga") + .HasColumnType("text"); + + b.Property("LinhaNova") + .HasColumnType("text"); + + b.Property("Motivo") + .HasColumnType("text"); + + b.Property("Observacao") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("DataTroca"); + + b.HasIndex("ICCID"); + + b.HasIndex("Item"); + + b.HasIndex("LinhaAntiga"); + + b.HasIndex("LinhaNova"); + + b.HasIndex("TenantId"); + + b.ToTable("TrocaNumeroLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.UserData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Celular") + .HasColumnType("text"); + + b.Property("Cliente") + .HasColumnType("text"); + + b.Property("Cnpj") + .HasColumnType("text"); + + b.Property("Cpf") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataNascimento") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("Endereco") + .HasColumnType("text"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Linha") + .HasColumnType("text"); + + b.Property("Nome") + .HasColumnType("text"); + + b.Property("RazaoSocial") + .HasColumnType("text"); + + b.Property("Rg") + .HasColumnType("text"); + + b.Property("TelefoneFixo") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TipoPessoa") + .HasColumnType("text"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("Cliente"); + + b.HasIndex("Cnpj"); + + b.HasIndex("Cpf"); + + b.HasIndex("Email"); + + b.HasIndex("Item"); + + b.HasIndex("Linha"); + + b.HasIndex("Nome"); + + b.HasIndex("RazaoSocial"); + + b.HasIndex("TenantId"); + + b.HasIndex("TipoPessoa"); + + b.ToTable("UserDatas"); + }); + + modelBuilder.Entity("line_gestao_api.Models.VigenciaLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Cliente") + .HasColumnType("text"); + + b.Property("Conta") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DtEfetivacaoServico") + .HasColumnType("timestamp with time zone"); + + b.Property("DtTerminoFidelizacao") + .HasColumnType("timestamp with time zone"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Linha") + .HasColumnType("text"); + + b.Property("PlanoContrato") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Total") + .HasColumnType("numeric"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Usuario") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Cliente"); + + b.HasIndex("DtTerminoFidelizacao"); + + b.HasIndex("Item"); + + b.HasIndex("Linha"); + + b.HasIndex("TenantId"); + + b.ToTable("VigenciaLines"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("line_gestao_api.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("line_gestao_api.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("line_gestao_api.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("line_gestao_api.Models.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("line_gestao_api.Models.MuregLine", b => + { + b.HasOne("line_gestao_api.Models.MobileLine", "MobileLine") + .WithMany("Muregs") + .HasForeignKey("MobileLineId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("MobileLine"); + }); + + modelBuilder.Entity("line_gestao_api.Models.Notification", b => + { + b.HasOne("line_gestao_api.Models.ApplicationUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("line_gestao_api.Models.VigenciaLine", "VigenciaLine") + .WithMany() + .HasForeignKey("VigenciaLineId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("User"); + + b.Navigation("VigenciaLine"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ParcelamentoMonthValue", b => + { + b.HasOne("line_gestao_api.Models.ParcelamentoLine", "ParcelamentoLine") + .WithMany("MonthValues") + .HasForeignKey("ParcelamentoLineId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ParcelamentoLine"); + }); + + modelBuilder.Entity("line_gestao_api.Models.MobileLine", b => + { + b.Navigation("Muregs"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ParcelamentoLine", b => + { + b.Navigation("MonthValues"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Migrations/20260205151645_AddResumoReservaTotalGeral.cs b/Migrations/20260205151645_AddResumoReservaTotalGeral.cs new file mode 100644 index 0000000..24d4e43 --- /dev/null +++ b/Migrations/20260205151645_AddResumoReservaTotalGeral.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace line_gestao_api.Migrations +{ + /// + public partial class AddResumoReservaTotalGeral : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "TotalGeralLinhasReserva", + table: "ResumoReservaTotals", + type: "integer", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "TotalGeralLinhasReserva", + table: "ResumoReservaTotals"); + } + } +} diff --git a/Migrations/20260212120000_AddAuditLogs.Designer.cs b/Migrations/20260212120000_AddAuditLogs.Designer.cs new file mode 100644 index 0000000..4026ccd --- /dev/null +++ b/Migrations/20260212120000_AddAuditLogs.Designer.cs @@ -0,0 +1,19 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using line_gestao_api.Data; + +#nullable disable + +namespace line_gestao_api.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20260212120000_AddAuditLogs")] + partial class AddAuditLogs + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { + } + } +} diff --git a/Migrations/20260212120000_AddAuditLogs.cs b/Migrations/20260212120000_AddAuditLogs.cs new file mode 100644 index 0000000..9a7b810 --- /dev/null +++ b/Migrations/20260212120000_AddAuditLogs.cs @@ -0,0 +1,72 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace line_gestao_api.Migrations +{ + /// + public partial class AddAuditLogs : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AuditLogs", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + TenantId = table.Column(type: "uuid", nullable: false), + OccurredAtUtc = table.Column(type: "timestamp with time zone", nullable: false), + UserId = table.Column(type: "uuid", nullable: true), + UserName = table.Column(type: "character varying(200)", maxLength: 200, nullable: true), + UserEmail = table.Column(type: "character varying(200)", maxLength: 200, nullable: true), + Action = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), + Page = table.Column(type: "character varying(80)", maxLength: 80, nullable: false), + EntityName = table.Column(type: "character varying(120)", maxLength: 120, nullable: false), + EntityId = table.Column(type: "character varying(200)", maxLength: 200, nullable: true), + EntityLabel = table.Column(type: "character varying(255)", maxLength: 255, nullable: true), + ChangesJson = table.Column(type: "jsonb", nullable: false), + RequestPath = table.Column(type: "character varying(255)", maxLength: 255, nullable: true), + RequestMethod = table.Column(type: "character varying(10)", maxLength: 10, nullable: true), + IpAddress = table.Column(type: "character varying(80)", maxLength: 80, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AuditLogs", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_AuditLogs_EntityName", + table: "AuditLogs", + column: "EntityName"); + + migrationBuilder.CreateIndex( + name: "IX_AuditLogs_OccurredAtUtc", + table: "AuditLogs", + column: "OccurredAtUtc"); + + migrationBuilder.CreateIndex( + name: "IX_AuditLogs_Page", + table: "AuditLogs", + column: "Page"); + + migrationBuilder.CreateIndex( + name: "IX_AuditLogs_TenantId", + table: "AuditLogs", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_AuditLogs_UserId", + table: "AuditLogs", + column: "UserId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AuditLogs"); + } + } +} diff --git a/Migrations/AppDbContextModelSnapshot.cs b/Migrations/AppDbContextModelSnapshot.cs index f0e3565..4aed7b2 100644 --- a/Migrations/AppDbContextModelSnapshot.cs +++ b/Migrations/AppDbContextModelSnapshot.cs @@ -234,6 +234,83 @@ namespace line_gestao_api.Migrations b.ToTable("AspNetUsers", (string)null); }); + modelBuilder.Entity("line_gestao_api.Models.AuditLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Action") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("ChangesJson") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("EntityId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("EntityLabel") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("EntityName") + .IsRequired() + .HasMaxLength(120) + .HasColumnType("character varying(120)"); + + b.Property("IpAddress") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("OccurredAtUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("Page") + .IsRequired() + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("RequestMethod") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("RequestPath") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UserEmail") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("UserName") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("Id"); + + b.HasIndex("EntityName"); + + b.HasIndex("OccurredAtUtc"); + + b.HasIndex("Page"); + + b.HasIndex("TenantId"); + + b.HasIndex("UserId"); + + b.ToTable("AuditLogs"); + }); + modelBuilder.Entity("line_gestao_api.Models.BillingClient", b => { b.Property("Id") @@ -301,6 +378,125 @@ namespace line_gestao_api.Migrations b.ToTable("billing_clients", (string)null); }); + modelBuilder.Entity("line_gestao_api.Models.ChipVirgemLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("NumeroDoChip") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Observacoes") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("Item"); + + b.HasIndex("NumeroDoChip"); + + b.HasIndex("TenantId"); + + b.ToTable("ChipVirgemLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ControleRecebidoLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Ano") + .HasColumnType("integer"); + + b.Property("Chip") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("ConteudoDaNf") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DataDaNf") + .HasColumnType("timestamp with time zone"); + + b.Property("DataDoRecebimento") + .HasColumnType("timestamp with time zone"); + + b.Property("IsResumo") + .HasColumnType("boolean"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("NotaFiscal") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("NumeroDaLinha") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Quantidade") + .HasColumnType("integer"); + + b.Property("Serial") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorDaNf") + .HasColumnType("numeric"); + + b.Property("ValorUnit") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.HasIndex("Ano"); + + b.HasIndex("Chip"); + + b.HasIndex("DataDaNf"); + + b.HasIndex("DataDoRecebimento"); + + b.HasIndex("Item"); + + b.HasIndex("NotaFiscal"); + + b.HasIndex("NumeroDaLinha"); + + b.HasIndex("Serial"); + + b.HasIndex("TenantId"); + + b.ToTable("ControleRecebidoLines"); + }); + modelBuilder.Entity("line_gestao_api.Models.MobileLine", b => { b.Property("Id") @@ -389,6 +585,10 @@ namespace line_gestao_api.Migrations b.Property("TenantId") .HasColumnType("uuid"); + b.Property("TipoDeChip") + .HasMaxLength(80) + .HasColumnType("character varying(80)"); + b.Property("UpdatedAt") .HasColumnType("timestamp with time zone"); @@ -415,6 +615,9 @@ namespace line_gestao_api.Migrations b.Property("VivoNewsPlus") .HasColumnType("numeric"); + b.Property("VivoSync") + .HasColumnType("numeric"); + b.Property("VivoTravelMundo") .HasColumnType("numeric"); @@ -564,6 +767,433 @@ namespace line_gestao_api.Migrations b.ToTable("Notifications"); }); + modelBuilder.Entity("line_gestao_api.Models.ParcelamentoLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AnoRef") + .HasColumnType("integer"); + + b.Property("Cliente") + .HasMaxLength(120) + .HasColumnType("character varying(120)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Desconto") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.Property("Item") + .HasColumnType("integer"); + + b.Property("Linha") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("ParcelaAtual") + .HasColumnType("integer"); + + b.Property("QtParcelas") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TotalParcelas") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorCheio") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.Property("ValorComDesconto") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("Linha"); + + b.HasIndex("TenantId"); + + b.HasIndex("AnoRef", "Item") + .IsUnique(); + + b.ToTable("ParcelamentoLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ParcelamentoMonthValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Competencia") + .HasColumnType("date"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ParcelamentoLineId") + .HasColumnType("uuid"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Valor") + .HasPrecision(18, 2) + .HasColumnType("numeric(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId"); + + b.HasIndex("ParcelamentoLineId", "Competencia") + .IsUnique(); + + b.ToTable("ParcelamentoMonthValues"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoClienteEspecial", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Nome") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Valor") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoClienteEspeciais"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoLineTotais", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LucroTotalLine") + .HasColumnType("numeric"); + + b.Property("QtdLinhas") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Tipo") + .HasColumnType("text"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorTotalLine") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoLineTotais"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoMacrophonyPlan", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaGb") + .HasColumnType("numeric"); + + b.Property("Gb") + .HasColumnType("numeric"); + + b.Property("PlanoContrato") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TotalLinhas") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorIndividualComSvas") + .HasColumnType("numeric"); + + b.Property("ValorTotal") + .HasColumnType("numeric"); + + b.Property("VivoTravel") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("ResumoMacrophonyPlans"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoMacrophonyTotal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaGbTotal") + .HasColumnType("numeric"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TotalLinhasTotal") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorTotal") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoMacrophonyTotals"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoPlanoContratoResumo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaGb") + .HasColumnType("numeric"); + + b.Property("Gb") + .HasColumnType("numeric"); + + b.Property("PlanoContrato") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("TotalLinhas") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorIndividualComSvas") + .HasColumnType("numeric"); + + b.Property("ValorTotal") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoPlanoContratoResumos"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoPlanoContratoTotal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorTotal") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoPlanoContratoTotals"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoReservaLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Ddd") + .HasColumnType("text"); + + b.Property("FranquiaGb") + .HasColumnType("numeric"); + + b.Property("QtdLinhas") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Total") + .HasColumnType("numeric"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("ResumoReservaLines"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoReservaTotal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("QtdLinhasTotal") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("Total") + .HasColumnType("numeric"); + + b.Property("TotalGeralLinhasReserva") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("ResumoReservaTotals"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoVivoLineResumo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Cliente") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaLine") + .HasColumnType("numeric"); + + b.Property("FranquiaTotal") + .HasColumnType("numeric"); + + b.Property("Lucro") + .HasColumnType("numeric"); + + b.Property("QtdLinhas") + .HasColumnType("integer"); + + b.Property("Skil") + .HasColumnType("text"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorContratoLine") + .HasColumnType("numeric"); + + b.Property("ValorContratoVivo") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoVivoLineResumos"); + }); + + modelBuilder.Entity("line_gestao_api.Models.ResumoVivoLineTotal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FranquiaLine") + .HasColumnType("numeric"); + + b.Property("FranquiaTotal") + .HasColumnType("numeric"); + + b.Property("Lucro") + .HasColumnType("numeric"); + + b.Property("QtdLinhasTotal") + .HasColumnType("integer"); + + b.Property("TenantId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ValorContratoLine") + .HasColumnType("numeric"); + + b.Property("ValorContratoVivo") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.ToTable("ResumoVivoLineTotals"); + }); + modelBuilder.Entity("line_gestao_api.Models.Tenant", b => { b.Property("Id") @@ -582,125 +1212,6 @@ namespace line_gestao_api.Migrations b.ToTable("Tenants"); }); - modelBuilder.Entity("line_gestao_api.Models.ChipVirgemLine", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Item") - .HasColumnType("integer"); - - b.Property("NumeroDoChip") - .HasMaxLength(40) - .HasColumnType("character varying(40)"); - - b.Property("Observacoes") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("TenantId") - .HasColumnType("uuid"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("Item"); - - b.HasIndex("NumeroDoChip"); - - b.HasIndex("TenantId"); - - b.ToTable("ChipVirgemLines"); - }); - - modelBuilder.Entity("line_gestao_api.Models.ControleRecebidoLine", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Ano") - .HasColumnType("integer"); - - b.Property("Chip") - .HasMaxLength(40) - .HasColumnType("character varying(40)"); - - b.Property("ConteudoDaNf") - .HasMaxLength(255) - .HasColumnType("character varying(255)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DataDaNf") - .HasColumnType("timestamp with time zone"); - - b.Property("DataDoRecebimento") - .HasColumnType("timestamp with time zone"); - - b.Property("IsResumo") - .HasColumnType("boolean"); - - b.Property("Item") - .HasColumnType("integer"); - - b.Property("NotaFiscal") - .HasMaxLength(50) - .HasColumnType("character varying(50)"); - - b.Property("NumeroDaLinha") - .HasMaxLength(40) - .HasColumnType("character varying(40)"); - - b.Property("Quantidade") - .HasColumnType("integer"); - - b.Property("Serial") - .HasMaxLength(80) - .HasColumnType("character varying(80)"); - - b.Property("TenantId") - .HasColumnType("uuid"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("ValorDaNf") - .HasColumnType("numeric"); - - b.Property("ValorUnit") - .HasColumnType("numeric"); - - b.HasKey("Id"); - - b.HasIndex("Ano"); - - b.HasIndex("Chip"); - - b.HasIndex("DataDaNf"); - - b.HasIndex("DataDoRecebimento"); - - b.HasIndex("Item"); - - b.HasIndex("NotaFiscal"); - - b.HasIndex("NumeroDaLinha"); - - b.HasIndex("Serial"); - - b.HasIndex("TenantId"); - - b.ToTable("ControleRecebidoLines"); - }); - modelBuilder.Entity("line_gestao_api.Models.TrocaNumeroLine", b => { b.Property("Id") @@ -766,6 +1277,9 @@ namespace line_gestao_api.Migrations b.Property("Cliente") .HasColumnType("text"); + b.Property("Cnpj") + .HasColumnType("text"); + b.Property("Cpf") .HasColumnType("text"); @@ -787,6 +1301,12 @@ namespace line_gestao_api.Migrations b.Property("Linha") .HasColumnType("text"); + b.Property("Nome") + .HasColumnType("text"); + + b.Property("RazaoSocial") + .HasColumnType("text"); + b.Property("Rg") .HasColumnType("text"); @@ -796,6 +1316,9 @@ namespace line_gestao_api.Migrations b.Property("TenantId") .HasColumnType("uuid"); + b.Property("TipoPessoa") + .HasColumnType("text"); + b.Property("UpdatedAt") .HasColumnType("timestamp with time zone"); @@ -803,6 +1326,8 @@ namespace line_gestao_api.Migrations b.HasIndex("Cliente"); + b.HasIndex("Cnpj"); + b.HasIndex("Cpf"); b.HasIndex("Email"); @@ -811,8 +1336,14 @@ namespace line_gestao_api.Migrations b.HasIndex("Linha"); + b.HasIndex("Nome"); + + b.HasIndex("RazaoSocial"); + b.HasIndex("TenantId"); + b.HasIndex("TipoPessoa"); + b.ToTable("UserDatas"); }); @@ -952,10 +1483,26 @@ namespace line_gestao_api.Migrations b.Navigation("VigenciaLine"); }); + modelBuilder.Entity("line_gestao_api.Models.ParcelamentoMonthValue", b => + { + b.HasOne("line_gestao_api.Models.ParcelamentoLine", "ParcelamentoLine") + .WithMany("MonthValues") + .HasForeignKey("ParcelamentoLineId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ParcelamentoLine"); + }); + modelBuilder.Entity("line_gestao_api.Models.MobileLine", b => { b.Navigation("Muregs"); }); + + modelBuilder.Entity("line_gestao_api.Models.ParcelamentoLine", b => + { + b.Navigation("MonthValues"); + }); #pragma warning restore 612, 618 } } diff --git a/Models/AuditLog.cs b/Models/AuditLog.cs new file mode 100644 index 0000000..2584ff5 --- /dev/null +++ b/Models/AuditLog.cs @@ -0,0 +1,28 @@ +using System; + +namespace line_gestao_api.Models; + +public class AuditLog : ITenantEntity +{ + public Guid Id { get; set; } = Guid.NewGuid(); + + public Guid TenantId { get; set; } + + public DateTime OccurredAtUtc { get; set; } = DateTime.UtcNow; + + public Guid? UserId { get; set; } + public string? UserName { get; set; } + public string? UserEmail { get; set; } + + public string Action { get; set; } = string.Empty; + public string Page { get; set; } = string.Empty; + public string EntityName { get; set; } = string.Empty; + public string? EntityId { get; set; } + public string? EntityLabel { get; set; } + + public string ChangesJson { get; set; } = "[]"; + + public string? RequestPath { get; set; } + public string? RequestMethod { get; set; } + public string? IpAddress { get; set; } +} diff --git a/Models/ResumoReservaTotal.cs b/Models/ResumoReservaTotal.cs index a093ea5..7c123de 100644 --- a/Models/ResumoReservaTotal.cs +++ b/Models/ResumoReservaTotal.cs @@ -6,6 +6,7 @@ public class ResumoReservaTotal : ITenantEntity public Guid TenantId { get; set; } + public int? TotalGeralLinhasReserva { get; set; } public int? QtdLinhasTotal { get; set; } public decimal? Total { get; set; } diff --git a/Models/UserData.cs b/Models/UserData.cs index 3308fcd..2f1b3df 100644 --- a/Models/UserData.cs +++ b/Models/UserData.cs @@ -15,6 +15,12 @@ namespace line_gestao_api.Models public string? Linha { get; set; } public string? Cliente { get; set; } + // PF/PJ + public string? TipoPessoa { get; set; } // "PF" | "PJ" + public string? Nome { get; set; } // PF + public string? RazaoSocial { get; set; } // PJ + public string? Cnpj { get; set; } // PJ + public string? Cpf { get; set; } public string? Rg { get; set; } diff --git a/Program.cs b/Program.cs index 31f68dd..4a18b3d 100644 --- a/Program.cs +++ b/Program.cs @@ -35,6 +35,7 @@ builder.Services.AddDbContext(options => builder.Services.AddHttpContextAccessor(); builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); diff --git a/Services/AuditLogBuilder.cs b/Services/AuditLogBuilder.cs new file mode 100644 index 0000000..13dc141 --- /dev/null +++ b/Services/AuditLogBuilder.cs @@ -0,0 +1,280 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Security.Claims; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.IdentityModel.Tokens.Jwt; +using line_gestao_api.Dtos; +using line_gestao_api.Models; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; + +namespace line_gestao_api.Services; + +public class AuditLogBuilder : IAuditLogBuilder +{ + private static readonly Dictionary PageByEntity = new(StringComparer.OrdinalIgnoreCase) + { + { nameof(MobileLine), "Geral" }, + { nameof(MuregLine), "Mureg" }, + { nameof(BillingClient), "Faturamento" }, + { nameof(ParcelamentoLine), "Parcelamentos" }, + { nameof(ParcelamentoMonthValue), "Parcelamentos" }, + { nameof(UserData), "Dados e Usuários" }, + { nameof(ApplicationUser), "Dados e Usuários" }, + { nameof(VigenciaLine), "Vigência" }, + { nameof(ChipVirgemLine), "Chips Virgens e Recebidos" }, + { nameof(ControleRecebidoLine), "Chips Virgens e Recebidos" }, + { nameof(TrocaNumeroLine), "Troca de número" } + }; + + private static readonly HashSet IgnoredProperties = new(StringComparer.OrdinalIgnoreCase) + { + "TenantId", + "CreatedAt", + "UpdatedAt", + "PasswordHash", + "SecurityStamp", + "ConcurrencyStamp", + "NormalizedEmail", + "NormalizedUserName", + "LockoutEnd", + "AccessFailedCount", + "LockoutEnabled", + "EmailConfirmed", + "PhoneNumberConfirmed", + "TwoFactorEnabled" + }; + + private static readonly JsonSerializerOptions JsonOptions = new() + { + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull + }; + + private readonly IHttpContextAccessor _httpContextAccessor; + private readonly ITenantProvider _tenantProvider; + + public AuditLogBuilder(IHttpContextAccessor httpContextAccessor, ITenantProvider tenantProvider) + { + _httpContextAccessor = httpContextAccessor; + _tenantProvider = tenantProvider; + } + + public List BuildAuditLogs(ChangeTracker changeTracker) + { + var tenantId = _tenantProvider.TenantId; + if (tenantId == null) + { + return new List(); + } + + changeTracker.DetectChanges(); + + var httpContext = _httpContextAccessor.HttpContext; + var userInfo = ResolveUserInfo(httpContext?.User); + var request = httpContext?.Request; + var requestPath = request?.Path.Value; + var requestMethod = request?.Method; + var ipAddress = httpContext?.Connection?.RemoteIpAddress?.ToString(); + + var logs = new List(); + + foreach (var entry in changeTracker.Entries()) + { + if (entry.State == EntityState.Detached || entry.State == EntityState.Unchanged) + continue; + + if (entry.Entity is AuditLog) + continue; + + var entityName = entry.Metadata.ClrType.Name; + if (!PageByEntity.TryGetValue(entityName, out var page)) + continue; + + var changes = BuildChanges(entry); + if (changes.Count == 0) + continue; + + logs.Add(new AuditLog + { + TenantId = tenantId.Value, + OccurredAtUtc = DateTime.UtcNow, + UserId = userInfo.UserId, + UserName = userInfo.UserName, + UserEmail = userInfo.UserEmail, + Action = ResolveAction(entry.State), + Page = page, + EntityName = entityName, + EntityId = BuildEntityId(entry), + EntityLabel = BuildEntityLabel(entry), + ChangesJson = JsonSerializer.Serialize(changes, JsonOptions), + RequestPath = requestPath, + RequestMethod = requestMethod, + IpAddress = ipAddress + }); + } + + return logs; + } + + private static string ResolveAction(EntityState state) + => state switch + { + EntityState.Added => "CREATE", + EntityState.Modified => "UPDATE", + EntityState.Deleted => "DELETE", + _ => "UNKNOWN" + }; + + private static List BuildChanges(EntityEntry entry) + { + var changes = new List(); + + foreach (var property in entry.Properties) + { + if (IgnoredProperties.Contains(property.Metadata.Name)) + continue; + + if (entry.State == EntityState.Added) + { + var newValue = FormatValue(property.CurrentValue); + if (newValue == null) + continue; + + changes.Add(new AuditFieldChangeDto + { + Field = property.Metadata.Name, + ChangeType = "added", + NewValue = newValue + }); + } + else if (entry.State == EntityState.Deleted) + { + var oldValue = FormatValue(property.OriginalValue); + if (oldValue == null) + continue; + + changes.Add(new AuditFieldChangeDto + { + Field = property.Metadata.Name, + ChangeType = "removed", + OldValue = oldValue + }); + } + else if (entry.State == EntityState.Modified) + { + if (!property.IsModified) + continue; + + var oldValue = FormatValue(property.OriginalValue); + var newValue = FormatValue(property.CurrentValue); + if (string.Equals(oldValue, newValue, StringComparison.Ordinal)) + continue; + + changes.Add(new AuditFieldChangeDto + { + Field = property.Metadata.Name, + ChangeType = "modified", + OldValue = oldValue, + NewValue = newValue + }); + } + } + + return changes; + } + + private static string? BuildEntityId(EntityEntry entry) + { + var key = entry.Metadata.FindPrimaryKey(); + if (key == null) + return null; + + var parts = new List(); + foreach (var keyProperty in key.Properties) + { + var property = entry.Property(keyProperty.Name); + var value = FormatValue(property.CurrentValue ?? property.OriginalValue); + if (value == null) + continue; + parts.Add($"{keyProperty.Name}={value}"); + } + + return parts.Count == 0 ? null : string.Join(";", parts); + } + + private static string? BuildEntityLabel(EntityEntry entry) + { + var entityName = entry.Metadata.ClrType.Name; + return entityName switch + { + nameof(MobileLine) => GetValue(entry, "Linha") ?? GetValue(entry, "Item"), + nameof(MuregLine) => GetValue(entry, "LinhaAntiga") ?? GetValue(entry, "LinhaNova") ?? GetValue(entry, "Item"), + nameof(TrocaNumeroLine) => GetValue(entry, "LinhaAntiga") ?? GetValue(entry, "LinhaNova") ?? GetValue(entry, "Item"), + nameof(ChipVirgemLine) => GetValue(entry, "NumeroDoChip") ?? GetValue(entry, "Item"), + nameof(ControleRecebidoLine) => GetValue(entry, "NotaFiscal") ?? GetValue(entry, "Serial") ?? GetValue(entry, "Item"), + nameof(BillingClient) => GetValue(entry, "Cliente") ?? GetValue(entry, "Item"), + nameof(ParcelamentoLine) => GetValue(entry, "Linha") ?? GetValue(entry, "Cliente") ?? GetValue(entry, "Item"), + nameof(ParcelamentoMonthValue) => GetValue(entry, "Competencia") ?? GetValue(entry, "ParcelamentoLineId"), + nameof(UserData) => GetValue(entry, "Linha") ?? GetValue(entry, "Cliente") ?? GetValue(entry, "Item"), + nameof(VigenciaLine) => GetValue(entry, "Linha") ?? GetValue(entry, "Cliente") ?? GetValue(entry, "Item"), + nameof(ApplicationUser) => GetValue(entry, "Email") ?? GetValue(entry, "Name") ?? GetValue(entry, "Id"), + _ => null + }; + } + + private static string? GetValue(EntityEntry entry, string propertyName) + { + var property = entry.Properties.FirstOrDefault(p => p.Metadata.Name == propertyName); + return property == null ? null : FormatValue(property.CurrentValue ?? property.OriginalValue); + } + + private static string? FormatValue(object? value) + { + if (value == null) + return null; + + switch (value) + { + case DateTime dt: + var normalized = dt.Kind == DateTimeKind.Utc + ? dt + : (dt.Kind == DateTimeKind.Local ? dt.ToUniversalTime() : DateTime.SpecifyKind(dt, DateTimeKind.Utc)); + return normalized.ToString("O", CultureInfo.InvariantCulture); + case DateTimeOffset dto: + return dto.ToUniversalTime().ToString("O", CultureInfo.InvariantCulture); + case IFormattable formattable: + return formattable.ToString(null, CultureInfo.InvariantCulture); + default: + return value.ToString(); + } + } + + private static (Guid? UserId, string? UserName, string? UserEmail) ResolveUserInfo(ClaimsPrincipal? user) + { + if (user?.Identity?.IsAuthenticated != true) + { + return (null, "SYSTEM", null); + } + + var idValue = user.FindFirstValue(ClaimTypes.NameIdentifier) + ?? user.FindFirstValue(JwtRegisteredClaimNames.Sub) + ?? user.FindFirstValue("sub"); + + var name = user.FindFirstValue("name") + ?? user.FindFirstValue(ClaimTypes.Name) + ?? user.Identity?.Name; + + var email = user.FindFirstValue(ClaimTypes.Email) + ?? user.FindFirstValue(JwtRegisteredClaimNames.Email) + ?? user.FindFirstValue("email"); + + var userId = Guid.TryParse(idValue, out var parsed) ? parsed : (Guid?)null; + var userName = string.IsNullOrWhiteSpace(name) ? email : name; + + return (userId, userName, email); + } +} diff --git a/Services/AutoFillRules.cs b/Services/AutoFillRules.cs new file mode 100644 index 0000000..a3c45ec --- /dev/null +++ b/Services/AutoFillRules.cs @@ -0,0 +1,73 @@ +using System.Globalization; +using System.Text.RegularExpressions; +using line_gestao_api.Data; +using line_gestao_api.Models; +using Microsoft.EntityFrameworkCore; + +namespace line_gestao_api.Services; + +public static class AutoFillRules +{ + private static readonly Regex FranquiaRegex = new( + @"(?\d+(?:[.,]\d+)?)\s*(?GB|MB)", + RegexOptions.IgnoreCase | RegexOptions.Compiled); + + public sealed record PlanSuggestion(decimal? FranquiaGb, decimal? ValorPlano); + + public static async Task ResolvePlanSuggestionAsync(AppDbContext db, string? planoContrato) + { + var plan = (planoContrato ?? string.Empty).Trim(); + if (string.IsNullOrWhiteSpace(plan)) return null; + + ResumoPlanoContratoResumo? resumoPlano = await db.ResumoPlanoContratoResumos + .AsNoTracking() + .Where(x => x.PlanoContrato != null && EF.Functions.ILike(x.PlanoContrato, plan)) + .OrderByDescending(x => x.UpdatedAt) + .FirstOrDefaultAsync(); + + ResumoMacrophonyPlan? macroPlan = null; + if (resumoPlano == null) + { + macroPlan = await db.ResumoMacrophonyPlans + .AsNoTracking() + .Where(x => x.PlanoContrato != null && EF.Functions.ILike(x.PlanoContrato, plan)) + .OrderByDescending(x => x.UpdatedAt) + .FirstOrDefaultAsync(); + } + + decimal? franquia = resumoPlano?.FranquiaGb ?? resumoPlano?.Gb; + decimal? valor = resumoPlano?.ValorIndividualComSvas; + + if (macroPlan != null) + { + franquia ??= macroPlan.FranquiaGb ?? macroPlan.Gb; + valor ??= macroPlan.ValorIndividualComSvas; + } + + franquia ??= ParseFranquiaGbFromPlano(plan); + + return new PlanSuggestion(franquia, valor); + } + + public static decimal? ParseFranquiaGbFromPlano(string? planoContrato) + { + if (string.IsNullOrWhiteSpace(planoContrato)) return null; + + var match = FranquiaRegex.Match(planoContrato); + if (!match.Success) return null; + + var raw = match.Groups["val"].Value.Replace(",", "."); + if (!decimal.TryParse(raw, NumberStyles.Any, CultureInfo.InvariantCulture, out var value)) + { + return null; + } + + var unit = match.Groups["unit"].Value.ToUpperInvariant(); + if (unit == "MB") + { + return Math.Round(value / 1000m, 4); + } + + return value; + } +} diff --git a/Services/IAuditLogBuilder.cs b/Services/IAuditLogBuilder.cs new file mode 100644 index 0000000..af210a4 --- /dev/null +++ b/Services/IAuditLogBuilder.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using line_gestao_api.Models; + +namespace line_gestao_api.Services; + +public interface IAuditLogBuilder +{ + List BuildAuditLogs(ChangeTracker changeTracker); +} diff --git a/Services/ParcelamentosImportService.cs b/Services/ParcelamentosImportService.cs index b092aa9..cb5c0b7 100644 --- a/Services/ParcelamentosImportService.cs +++ b/Services/ParcelamentosImportService.cs @@ -41,16 +41,49 @@ public sealed class ParcelamentosImportService await _db.ParcelamentoLines.ExecuteDeleteAsync(cancellationToken); } - const int startRow = 6; - const int colAnoRef = 3; - const int colItem = 4; - const int colLinha = 5; - const int colCliente = 6; - const int colQtParcelas = 7; - const int colValorCheio = 8; - const int colDesconto = 9; - const int colValorComDesconto = 10; - var monthMap = BuildFixedMonthMap(); + if (!TryFindParcelamentosHeader(ws, out var headerRow, out var headerMap, out var lastCol)) + { + return new ParcelamentosImportSummaryDto + { + Erros = + { + new ParcelamentosImportErrorDto + { + LinhaExcel = 0, + Motivo = "Cabeçalho da aba PARCELAMENTOS não encontrado (LINHA/CLIENTE/QT PARCELAS/VALOR CHEIO/DESCONTO/VALOR C/ DESCONTO + meses)." + } + } + }; + } + + var colLinha = GetColAny(headerMap, "LINHA"); + var colCliente = GetColAny(headerMap, "CLIENTE"); + var colQtParcelas = GetColAny(headerMap, "QT PARCELAS", "QT. PARCELAS", "QTPARCELAS"); + var colValorCheio = GetColAny(headerMap, "VALOR CHEIO", "VALORCHEIO"); + var colDesconto = GetColAny(headerMap, "DESCONTO"); + var colValorComDesconto = GetColAny(headerMap, "VALOR C/ DESCONTO", "VALOR C\\ DESCONTO", "VALORCOMDESCONTO", "VALOR C DESCONTO"); + + var colItem = GetColAny(headerMap, "ITEM"); + var colAnoRef = GetColAny(headerMap, "ANO REF", "ANOREF", "ANO"); + + if (colItem == 0 && colLinha > 1) colItem = colLinha - 1; + if (colAnoRef == 0 && colLinha > 2) colAnoRef = colLinha - 2; + + var monthMap = BuildDynamicMonthMap(ws, headerRow, colValorComDesconto, lastCol); + if (monthMap.Count == 0) + { + return new ParcelamentosImportSummaryDto + { + Erros = + { + new ParcelamentosImportErrorDto + { + LinhaExcel = headerRow, + Motivo = "Meses (JAN..DEZ) não identificados no cabeçalho da aba PARCELAMENTOS." + } + } + }; + } var existing = await _db.ParcelamentoLines .AsNoTracking() @@ -60,22 +93,23 @@ public sealed class ParcelamentosImportService .ToDictionary(x => (x.AnoRef!.Value, x.Item!.Value), x => x.Id); var summary = new ParcelamentosImportSummaryDto(); + var startRow = headerRow + 1; var lastRow = ws.LastRowUsed()?.RowNumber() ?? startRow; for (int row = startRow; row <= lastRow; row++) { var linhaValue = GetCellStringValue(ws, row, colLinha); - var itemStr = GetCellStringValue(ws, row, colItem); - var anoRefStr = GetCellStringValue(ws, row, colAnoRef); - if (string.IsNullOrWhiteSpace(itemStr) - && string.IsNullOrWhiteSpace(linhaValue) - && string.IsNullOrWhiteSpace(anoRefStr)) + var qtParcelas = GetCellStringValue(ws, row, colQtParcelas); + if (!IsValidParcelamentoRow(linhaValue, qtParcelas)) { continue; } summary.Lidos++; + var itemStr = GetCellStringValue(ws, row, colItem); + var anoRefStr = GetCellStringValue(ws, row, colAnoRef); + var anoRef = TryNullableInt(anoRefStr); var item = TryNullableInt(itemStr); @@ -101,9 +135,12 @@ public sealed class ParcelamentosImportService continue; } - var qtParcelas = GetCellStringValue(ws, row, colQtParcelas); ParseParcelas(qtParcelas, out var parcelaAtual, out var totalParcelas); + var valorCheio = GetCellDecimalValue(ws, row, colValorCheio); + var desconto = GetCellDecimalValue(ws, row, colDesconto); + var valorComDesconto = GetCellDecimalValue(ws, row, colValorComDesconto); + var parcelamento = new ParcelamentoLine { AnoRef = anoRef, @@ -113,9 +150,9 @@ public sealed class ParcelamentosImportService QtParcelas = string.IsNullOrWhiteSpace(qtParcelas) ? null : qtParcelas.Trim(), ParcelaAtual = parcelaAtual, TotalParcelas = totalParcelas, - ValorCheio = TryDecimal(GetCellStringValue(ws, row, colValorCheio)), - Desconto = TryDecimal(GetCellStringValue(ws, row, colDesconto)), - ValorComDesconto = TryDecimal(GetCellStringValue(ws, row, colValorComDesconto)), + ValorCheio = valorCheio, + Desconto = desconto, + ValorComDesconto = valorComDesconto, UpdatedAt = DateTime.UtcNow }; @@ -145,7 +182,8 @@ public sealed class ParcelamentosImportService .Where(x => x.ParcelamentoLineId == existingEntity.Id) .ExecuteDeleteAsync(cancellationToken); - var monthValues = BuildMonthValuesFromMap(ws, row, monthMap, existingEntity.Id, summary); + var monthValues = BuildMonthValuesFromMap(ws, row, monthMap, existingEntity.Id, summary, out var rawMonths); + AuditParcelamentoRow(row, valorCheio, desconto, valorComDesconto, rawMonths, summary); if (monthValues.Count > 0) { await _db.ParcelamentoMonthValues.AddRangeAsync(monthValues, cancellationToken); @@ -157,7 +195,8 @@ public sealed class ParcelamentosImportService } parcelamento.CreatedAt = DateTime.UtcNow; - parcelamento.MonthValues = BuildMonthValuesFromMap(ws, row, monthMap, parcelamento.Id, summary); + parcelamento.MonthValues = BuildMonthValuesFromMap(ws, row, monthMap, parcelamento.Id, summary, out var rawMonthsNew); + AuditParcelamentoRow(row, valorCheio, desconto, valorComDesconto, rawMonthsNew, summary); summary.Inseridos++; await _db.ParcelamentoLines.AddAsync(parcelamento, cancellationToken); @@ -178,42 +217,21 @@ public sealed class ParcelamentosImportService }); } - private static List<(int Column, int Year, int Month)> BuildFixedMonthMap() - { - var map = new List<(int Column, int Year, int Month)> - { - (11, 2025, 12) - }; - - for (int month = 1; month <= 12; month++) - { - map.Add((11 + month, 2026, month)); - } - - for (int month = 1; month <= 6; month++) - { - map.Add((23 + month, 2027, month)); - } - - return map; - } - private static List BuildMonthValuesFromMap( IXLWorksheet ws, int row, List<(int Column, int Year, int Month)> monthMap, Guid parcelamentoId, - ParcelamentosImportSummaryDto summary) + ParcelamentosImportSummaryDto summary, + out Dictionary rawValues) { var monthValues = new List(); + rawValues = new Dictionary(); foreach (var (column, year, month) in monthMap) { - var valueStr = GetCellStringValue(ws, row, column); - var value = TryDecimal(valueStr); - if (!value.HasValue) - { - continue; - } + var value = GetCellDecimalValue(ws, row, column); + rawValues[$"C{column}:{year}-{month:00}"] = value; + if (!value.HasValue) continue; monthValues.Add(new ParcelamentoMonthValue { @@ -228,6 +246,236 @@ public sealed class ParcelamentosImportService return monthValues; } + private static List<(int Column, int Year, int Month)> BuildDynamicMonthMap( + IXLWorksheet ws, + int headerRow, + int colValorComDesconto, + int lastCol) + { + var header = ws.Row(headerRow); + var monthHeaders = new List<(int Col, int Month)>(); + + foreach (var cell in header.CellsUsed()) + { + var col = cell.Address.ColumnNumber; + if (colValorComDesconto > 0 && col <= colValorComDesconto) continue; + var month = ToMonthNumber(cell.GetString()); + if (month.HasValue) + { + monthHeaders.Add((col, month.Value)); + } + } + + monthHeaders = monthHeaders.OrderBy(x => x.Col).ToList(); + if (monthHeaders.Count == 0) return new List<(int Column, int Year, int Month)>(); + + var firstJanIdx = monthHeaders.FindIndex(x => x.Month == 1); + if (firstJanIdx < 0) return new List<(int Column, int Year, int Month)>(); + + var block1 = ExtractMonthBlock(monthHeaders, firstJanIdx); + var block2 = block1.NextIndex < monthHeaders.Count + ? ExtractMonthBlock(monthHeaders, block1.NextIndex) + : (new List<(int Col, int Month)>(), block1.NextIndex); + + var yearRow = headerRow - 1; + var year1 = block1.Block.Count > 0 + ? FindYearForBlock(ws, yearRow, block1.Block.First().Col, block1.Block.Last().Col, lastCol) + : null; + var year2 = block2.Block.Count > 0 + ? FindYearForBlock(ws, yearRow, block2.Block.First().Col, block2.Block.Last().Col, lastCol) + : null; + + var map = new List<(int Column, int Year, int Month)>(); + if (year1.HasValue) + { + foreach (var (col, month) in block1.Block) + map.Add((col, year1.Value, month)); + } + + if (year2.HasValue) + { + foreach (var (col, month) in block2.Block) + map.Add((col, year2.Value, month)); + } + + return map; + } + + private static (List<(int Col, int Month)> Block, int NextIndex) ExtractMonthBlock( + List<(int Col, int Month)> monthHeaders, + int startIndex) + { + var block = new List<(int Col, int Month)>(); + var idx = startIndex; + for (int m = 1; m <= 12; m++) + { + while (idx < monthHeaders.Count && monthHeaders[idx].Month != m) + idx++; + if (idx >= monthHeaders.Count) break; + block.Add(monthHeaders[idx]); + idx++; + } + return (block, idx); + } + + private static int? FindYearForBlock(IXLWorksheet ws, int yearRow, int startCol, int endCol, int lastCol) + { + if (yearRow < 1) return null; + + for (int col = startCol; col <= endCol; col++) + { + var year = TryParseYear(GetCellStringValue(ws, yearRow, col)); + if (year.HasValue) return year; + } + + int? found = null; + var bestDistance = int.MaxValue; + for (int col = 1; col <= lastCol; col++) + { + var year = TryParseYear(GetCellStringValue(ws, yearRow, col)); + if (!year.HasValue) continue; + var dist = Math.Abs(col - startCol); + if (dist < bestDistance) + { + bestDistance = dist; + found = year; + } + } + + return found; + } + + private static int? TryParseYear(string? s) + { + if (string.IsNullOrWhiteSpace(s)) return null; + var digits = new string(s.Where(char.IsDigit).ToArray()); + if (digits.Length == 4 && int.TryParse(digits, out var year)) return year; + if (digits.Length > 4) + { + for (int i = 0; i <= digits.Length - 4; i++) + { + if (int.TryParse(digits.Substring(i, 4), out var y) && y >= 2000 && y <= 2100) + return y; + } + } + return null; + } + + private static bool TryFindParcelamentosHeader( + IXLWorksheet ws, + out int headerRow, + out Dictionary map, + out int lastCol) + { + headerRow = 0; + map = new Dictionary(StringComparer.OrdinalIgnoreCase); + var firstRow = ws.FirstRowUsed()?.RowNumber() ?? 1; + var lastRow = ws.LastRowUsed()?.RowNumber() ?? firstRow; + lastCol = ws.LastColumnUsed()?.ColumnNumber() ?? 1; + + for (int r = firstRow; r <= lastRow; r++) + { + var row = ws.Row(r); + if (!row.CellsUsed().Any()) continue; + var headerMap = BuildHeaderMap(row); + if (!HasParcelamentosHeaders(row, headerMap)) continue; + headerRow = r; + map = headerMap; + return true; + } + return false; + } + + private static bool HasParcelamentosHeaders(IXLRow row, Dictionary map) + { + var hasLinha = GetColAny(map, "LINHA") > 0; + var hasCliente = GetColAny(map, "CLIENTE") > 0; + var hasQt = GetColAny(map, "QT PARCELAS", "QT. PARCELAS", "QTPARCELAS") > 0; + var hasCheio = GetColAny(map, "VALOR CHEIO", "VALORCHEIO") > 0; + var hasDesc = GetColAny(map, "DESCONTO") > 0; + var hasComDesc = GetColAny(map, "VALOR C/ DESCONTO", "VALOR C\\ DESCONTO", "VALORCOMDESCONTO", "VALOR C DESCONTO") > 0; + + var hasMonth = row.CellsUsed().Any(c => ToMonthNumber(c.GetString()).HasValue); + + return hasLinha && hasCliente && hasQt && hasCheio && hasDesc && hasComDesc && hasMonth; + } + + private static bool IsValidParcelamentoRow(string? linhaValue, string? qtParcelas) + { + if (string.IsNullOrWhiteSpace(linhaValue)) return false; + var digits = OnlyDigits(linhaValue); + if (string.IsNullOrWhiteSpace(digits) || digits.Length < 8) return false; + return !string.IsNullOrWhiteSpace(qtParcelas); + } + + private static decimal? GetCellDecimalValue(IXLWorksheet ws, int row, int col) + { + if (col <= 0) return null; + var cell = ws.Cell(row, col); + if (cell.IsEmpty()) return null; + + if (cell.DataType == XLDataType.Number) + { + if (cell.TryGetValue(out var dbl)) + return Convert.ToDecimal(dbl); + } + + if (cell.TryGetValue(out var dec)) + return dec; + + var s = cell.GetValue(); + return TryDecimal(s); + } + + private static void AuditParcelamentoRow( + int row, + decimal? valorCheio, + decimal? desconto, + decimal? valorComDesconto, + Dictionary monthValues, + ParcelamentosImportSummaryDto summary) + { + var issues = new List(); + + if (valorCheio.HasValue && desconto.HasValue && desconto.Value > 0 && valorComDesconto.HasValue + && Math.Abs(valorCheio.Value - valorComDesconto.Value) < 0.01m) + { + issues.Add("ValorCheio == ValorComDesconto com desconto > 0"); + } + + if (valorCheio.HasValue && desconto.HasValue && valorComDesconto.HasValue) + { + var esperado = valorCheio.Value - desconto.Value; + if (Math.Abs(esperado - valorComDesconto.Value) > 0.05m) + { + issues.Add("ValorComDesconto difere de ValorCheio - Desconto"); + } + } + + if (valorCheio.HasValue && monthValues.Values.Any(v => v.HasValue && v.Value == valorCheio.Value)) + { + issues.Add("ValorCheio igual a valor mensal (possível shift de coluna)"); + } + + var monthNonNull = monthValues.Values.Where(v => v.HasValue).Select(v => v!.Value).ToList(); + if (monthNonNull.Count >= 4 && monthNonNull.Distinct().Count() == 1) + { + issues.Add("Meses iguais (possível parse/shift)"); + } + + if (issues.Count == 0) return; + + var mapped = $"ValorCheio={valorCheio} Desconto={desconto} ValorComDesconto={valorComDesconto}"; + var raw = string.Join(" ", monthValues.Select(k => $"{k.Key}={k.Value}")); + Console.WriteLine($"[AUDITORIA PARCELAMENTOS] Linha {row} | {string.Join(" | ", issues)} | {mapped} | {raw}"); + + summary.Erros.Add(new ParcelamentosImportErrorDto + { + LinhaExcel = row, + Motivo = $"Auditoria: {string.Join(" | ", issues)}", + Valor = mapped + }); + } private static string GetCellStringValue(IXLWorksheet ws, int row, int col) { if (col <= 0) return ""; diff --git a/Services/VigenciaNotificationBackgroundService.cs b/Services/VigenciaNotificationBackgroundService.cs index 69c281a..c4f6517 100644 --- a/Services/VigenciaNotificationBackgroundService.cs +++ b/Services/VigenciaNotificationBackgroundService.cs @@ -113,7 +113,7 @@ public class VigenciaNotificationBackgroundService : BackgroundService var userByEmail = users .Where(u => !string.IsNullOrWhiteSpace(u.Email)) - .ToDictionary(u => u.Email.Trim().ToLowerInvariant(), u => u.Id); + .ToDictionary(u => u.Email!.Trim().ToLowerInvariant(), u => u.Id); var vigencias = await db.VigenciaLines.AsNoTracking() .Where(v => v.DtTerminoFidelizacao != null) diff --git a/appsettings.json b/appsettings.json index 93d1a76..dcdcbdd 100644 --- a/appsettings.json +++ b/appsettings.json @@ -6,7 +6,7 @@ "Key": "vI8/oEYEWN5sBDTisNuZFjZAl+YFvXEJ96POb73/eoq3NaFPkOFXyPRdf/HWGAFnUsF3e3QpYL6Wl4Bc2v+l3g==", "Issuer": "LineGestao", "Audience": "LineGestao", - "ExpiresMinutes": 120 + "ExpiresMinutes": 180 }, "Notifications": { "CheckIntervalMinutes": 60,