Adição Lote de Linhas

This commit is contained in:
Eduardo 2026-02-25 11:33:20 -03:00
parent 5101c3665a
commit 0ab7fa955f
2 changed files with 180 additions and 0 deletions

View File

@ -785,6 +785,162 @@ namespace line_gestao_api.Controllers
return CreatedAtAction(nameof(GetById), new { id = newLine.Id }, ToDetailDto(newLine, vigencia)); return CreatedAtAction(nameof(GetById), new { id = newLine.Id }, ToDetailDto(newLine, vigencia));
} }
// ==========================================================
// ✅ 5.1. CREATE BATCH
// ==========================================================
[HttpPost("batch")]
[Authorize(Roles = "admin,gestor")]
public async Task<ActionResult<CreateMobileLinesBatchResultDto>> CreateBatch([FromBody] CreateMobileLinesBatchRequestDto req)
{
var requests = req?.Lines ?? new List<CreateMobileLineDto>();
if (requests.Count == 0)
return BadRequest(new { message = "Informe ao menos uma linha para cadastro em lote." });
if (requests.Count > 1000)
return BadRequest(new { message = "O lote excede o limite de 1000 linhas por envio." });
var requestedLinhas = requests
.Select(x => OnlyDigits(x?.Linha))
.Where(x => !string.IsNullOrWhiteSpace(x))
.Distinct(StringComparer.Ordinal)
.ToList();
var existingLinhas = requestedLinhas.Count == 0
? new HashSet<string>(StringComparer.Ordinal)
: (await _db.MobileLines.AsNoTracking()
.Where(x => x.Linha != null && requestedLinhas.Contains(x.Linha))
.Select(x => x.Linha!)
.ToListAsync())
.ToHashSet(StringComparer.Ordinal);
await using var tx = await _db.Database.BeginTransactionAsync();
try
{
var nextItem = (await _db.MobileLines.MaxAsync(x => (int?)x.Item) ?? 0);
var seenBatchLinhas = new HashSet<string>(StringComparer.Ordinal);
var createdLines = new List<(MobileLine line, VigenciaLine? vigencia)>(requests.Count);
for (var i = 0; i < requests.Count; i++)
{
var entry = requests[i];
var lineNo = i + 1;
if (entry == null)
return BadRequest(new { message = $"Linha do lote #{lineNo} está vazia." });
if (string.IsNullOrWhiteSpace(entry.Cliente))
return BadRequest(new { message = $"Linha do lote #{lineNo}: o nome do Cliente é obrigatório." });
if (string.IsNullOrWhiteSpace(entry.Linha))
return BadRequest(new { message = $"Linha do lote #{lineNo}: o número da Linha é obrigatório." });
if (!entry.DtEfetivacaoServico.HasValue)
return BadRequest(new { message = $"Linha do lote #{lineNo}: a Dt. Efetivação Serviço é obrigatória." });
if (!entry.DtTerminoFidelizacao.HasValue)
return BadRequest(new { message = $"Linha do lote #{lineNo}: a Dt. Término Fidelização é obrigatória." });
var linhaLimpa = OnlyDigits(entry.Linha);
var chipLimpo = OnlyDigits(entry.Chip);
if (string.IsNullOrWhiteSpace(linhaLimpa))
return BadRequest(new { message = $"Linha do lote #{lineNo}: número de linha inválido." });
if (!seenBatchLinhas.Add(linhaLimpa))
return Conflict(new { message = $"A linha {entry.Linha} está duplicada dentro do lote (registro #{lineNo})." });
if (existingLinhas.Contains(linhaLimpa))
return Conflict(new { message = $"A linha {entry.Linha} já está cadastrada no sistema (registro #{lineNo})." });
nextItem++;
var planSuggestion = await AutoFillRules.ResolvePlanSuggestionAsync(_db, entry.PlanoContrato);
var franquiaVivo = entry.FranquiaVivo ?? planSuggestion?.FranquiaGb;
var valorPlanoVivo = entry.ValorPlanoVivo ?? planSuggestion?.ValorPlano;
var now = DateTime.UtcNow;
var newLine = new MobileLine
{
Id = Guid.NewGuid(),
Item = nextItem,
Cliente = entry.Cliente.Trim().ToUpper(),
Linha = linhaLimpa,
Chip = string.IsNullOrWhiteSpace(chipLimpo) ? null : chipLimpo,
Usuario = entry.Usuario?.Trim(),
Status = entry.Status?.Trim(),
Skil = entry.Skil?.Trim(),
Modalidade = entry.Modalidade?.Trim(),
PlanoContrato = entry.PlanoContrato?.Trim(),
Conta = entry.Conta?.Trim(),
VencConta = entry.VencConta?.Trim(),
DataBloqueio = ToUtc(entry.DataBloqueio),
DataEntregaOpera = ToUtc(entry.DataEntregaOpera),
DataEntregaCliente = ToUtc(entry.DataEntregaCliente),
Cedente = entry.Cedente?.Trim(),
Solicitante = entry.Solicitante?.Trim(),
FranquiaVivo = franquiaVivo,
ValorPlanoVivo = valorPlanoVivo,
GestaoVozDados = entry.GestaoVozDados,
Skeelo = entry.Skeelo,
VivoNewsPlus = entry.VivoNewsPlus,
VivoTravelMundo = entry.VivoTravelMundo,
VivoSync = entry.VivoSync,
VivoGestaoDispositivo = entry.VivoGestaoDispositivo,
ValorContratoVivo = entry.ValorContratoVivo,
FranquiaLine = entry.FranquiaLine,
FranquiaGestao = entry.FranquiaGestao,
LocacaoAp = entry.LocacaoAp,
ValorContratoLine = entry.ValorContratoLine,
Desconto = entry.Desconto,
Lucro = entry.Lucro,
TipoDeChip = entry.TipoDeChip?.Trim(),
CreatedAt = now,
UpdatedAt = now
};
ApplyReservaRule(newLine);
_db.MobileLines.Add(newLine);
var vigencia = await UpsertVigenciaFromMobileLineAsync(
newLine,
entry.DtEfetivacaoServico,
entry.DtTerminoFidelizacao,
overrideDates: false);
createdLines.Add((newLine, vigencia));
}
await _db.SaveChangesAsync();
await tx.CommitAsync();
await _vigenciaNotificationSyncService.SyncCurrentTenantAsync();
return Ok(new CreateMobileLinesBatchResultDto
{
Created = createdLines.Count,
Items = createdLines
.Select(x => new CreateMobileLinesBatchCreatedItemDto
{
Id = x.line.Id,
Item = x.line.Item,
Linha = x.line.Linha,
Cliente = x.line.Cliente
})
.ToList()
});
}
catch (DbUpdateException)
{
await tx.RollbackAsync();
return StatusCode(500, new { message = "Erro ao salvar o lote no banco de dados." });
}
}
// ========================================================== // ==========================================================
// ✅ 6. UPDATE // ✅ 6. UPDATE
// ========================================================== // ==========================================================

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
namespace line_gestao_api.Dtos
{
public class CreateMobileLinesBatchRequestDto
{
public List<CreateMobileLineDto> Lines { get; set; } = new();
}
public class CreateMobileLinesBatchResultDto
{
public int Created { get; set; }
public List<CreateMobileLinesBatchCreatedItemDto> Items { get; set; } = new();
}
public class CreateMobileLinesBatchCreatedItemDto
{
public Guid Id { get; set; }
public int Item { get; set; }
public string? Linha { get; set; }
public string? Cliente { get; set; }
}
}