Support per-line data for bulk creation
This commit is contained in:
parent
bb6f1fc044
commit
f78446b361
|
|
@ -350,78 +350,174 @@ namespace line_gestao_api.Controllers
|
|||
if (string.IsNullOrWhiteSpace(req.Cliente))
|
||||
return BadRequest(new { message = "O nome do Cliente é obrigatório." });
|
||||
|
||||
var quantidade = req.QtdLinhas.GetValueOrDefault(1);
|
||||
if (quantidade < 1)
|
||||
return BadRequest(new { message = "A quantidade de linhas deve ser maior que zero." });
|
||||
if (req.Linhas != null && req.Linhas.Count > 0)
|
||||
{
|
||||
var itens = req.Linhas;
|
||||
var linhasNormalizadas = new List<string>(itens.Count);
|
||||
|
||||
for (var i = 0; i < itens.Count; i++)
|
||||
{
|
||||
var linhaOriginal = itens[i].Linha;
|
||||
if (string.IsNullOrWhiteSpace(linhaOriginal))
|
||||
return BadRequest(new { message = $"O número da Linha é obrigatório (linha {i + 1})." });
|
||||
|
||||
var linhaLimpa = OnlyDigits(linhaOriginal);
|
||||
if (string.IsNullOrWhiteSpace(linhaLimpa))
|
||||
return BadRequest(new { message = $"Número de linha inválido (linha {i + 1})." });
|
||||
|
||||
linhasNormalizadas.Add(linhaLimpa);
|
||||
}
|
||||
|
||||
var duplicadas = linhasNormalizadas
|
||||
.GroupBy(x => x)
|
||||
.Where(g => g.Count() > 1)
|
||||
.Select(g => g.Key)
|
||||
.ToList();
|
||||
|
||||
if (duplicadas.Count > 0)
|
||||
return Conflict(new { message = $"Existem linhas duplicadas na requisição: {string.Join(", ", duplicadas)}." });
|
||||
|
||||
var existentes = await _db.MobileLines
|
||||
.AsNoTracking()
|
||||
.Where(x => x.Linha != null && linhasNormalizadas.Contains(x.Linha))
|
||||
.Select(x => x.Linha!)
|
||||
.ToListAsync();
|
||||
|
||||
if (existentes.Count > 0)
|
||||
return Conflict(new { message = $"As linhas {string.Join(", ", existentes)} já estão cadastradas no sistema." });
|
||||
|
||||
var maxItem = await _db.MobileLines.MaxAsync(x => (int?)x.Item) ?? 0;
|
||||
var now = DateTime.UtcNow;
|
||||
var created = new List<MobileLine>(itens.Count);
|
||||
|
||||
for (var i = 0; i < itens.Count; i++)
|
||||
{
|
||||
var item = itens[i];
|
||||
var linhaLimpa = linhasNormalizadas[i];
|
||||
var chipLimpo = OnlyDigits(item.Chip);
|
||||
|
||||
var newLine = new MobileLine
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Item = maxItem + 1 + i,
|
||||
Cliente = req.Cliente.Trim().ToUpper(),
|
||||
Linha = linhaLimpa,
|
||||
Chip = string.IsNullOrWhiteSpace(chipLimpo) ? null : chipLimpo,
|
||||
Usuario = item.Usuario?.Trim(),
|
||||
Status = item.Status?.Trim(),
|
||||
Skil = item.Skil?.Trim(),
|
||||
Modalidade = item.Modalidade?.Trim(),
|
||||
PlanoContrato = item.PlanoContrato?.Trim(),
|
||||
Conta = item.Conta?.Trim(),
|
||||
VencConta = item.VencConta?.Trim(),
|
||||
|
||||
DataBloqueio = ToUtc(item.DataBloqueio),
|
||||
DataEntregaOpera = ToUtc(item.DataEntregaOpera),
|
||||
DataEntregaCliente = ToUtc(item.DataEntregaCliente),
|
||||
|
||||
Cedente = item.Cedente?.Trim(),
|
||||
Solicitante = item.Solicitante?.Trim(),
|
||||
|
||||
FranquiaVivo = item.FranquiaVivo,
|
||||
ValorPlanoVivo = item.ValorPlanoVivo,
|
||||
GestaoVozDados = item.GestaoVozDados,
|
||||
Skeelo = item.Skeelo,
|
||||
VivoNewsPlus = item.VivoNewsPlus,
|
||||
VivoTravelMundo = item.VivoTravelMundo,
|
||||
VivoGestaoDispositivo = item.VivoGestaoDispositivo,
|
||||
ValorContratoVivo = item.ValorContratoVivo,
|
||||
FranquiaLine = item.FranquiaLine,
|
||||
FranquiaGestao = item.FranquiaGestao,
|
||||
LocacaoAp = item.LocacaoAp,
|
||||
ValorContratoLine = item.ValorContratoLine,
|
||||
Desconto = item.Desconto,
|
||||
Lucro = item.Lucro,
|
||||
|
||||
CreatedAt = now,
|
||||
UpdatedAt = now
|
||||
};
|
||||
|
||||
ApplyReservaRule(newLine);
|
||||
created.Add(newLine);
|
||||
}
|
||||
|
||||
_db.MobileLines.AddRange(created);
|
||||
|
||||
try
|
||||
{
|
||||
await _db.SaveChangesAsync();
|
||||
}
|
||||
catch (DbUpdateException)
|
||||
{
|
||||
return StatusCode(500, new { message = "Erro ao salvar no banco de dados." });
|
||||
}
|
||||
|
||||
return StatusCode(StatusCodes.Status201Created, created.Select(ToDetailDto).ToList());
|
||||
}
|
||||
|
||||
if (req.QtdLinhas.GetValueOrDefault(1) > 1)
|
||||
return BadRequest(new { message = "Para criar múltiplas linhas, envie a lista em 'Linhas' com os dados de cada linha." });
|
||||
|
||||
if (string.IsNullOrWhiteSpace(req.Linha))
|
||||
return BadRequest(new { message = "O número da Linha é obrigatório." });
|
||||
|
||||
var linhaLimpa = OnlyDigits(req.Linha);
|
||||
var chipLimpo = OnlyDigits(req.Chip);
|
||||
|
||||
if (quantidade == 1 && string.IsNullOrWhiteSpace(req.Linha))
|
||||
return BadRequest(new { message = "O número da Linha é obrigatório." });
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(req.Linha) && string.IsNullOrWhiteSpace(linhaLimpa))
|
||||
if (string.IsNullOrWhiteSpace(linhaLimpa))
|
||||
return BadRequest(new { message = "Número de linha inválido." });
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(linhaLimpa))
|
||||
var exists = await _db.MobileLines.AsNoTracking().AnyAsync(x => x.Linha == linhaLimpa);
|
||||
if (exists)
|
||||
return Conflict(new { message = $"A linha {req.Linha} já está cadastrada no sistema." });
|
||||
|
||||
var maxItemSingle = await _db.MobileLines.MaxAsync(x => (int?)x.Item) ?? 0;
|
||||
var nowSingle = DateTime.UtcNow;
|
||||
|
||||
var newLineSingle = new MobileLine
|
||||
{
|
||||
var exists = await _db.MobileLines.AsNoTracking().AnyAsync(x => x.Linha == linhaLimpa);
|
||||
if (exists)
|
||||
return Conflict(new { message = $"A linha {req.Linha} já está cadastrada no sistema." });
|
||||
}
|
||||
Id = Guid.NewGuid(),
|
||||
Item = maxItemSingle + 1,
|
||||
Cliente = req.Cliente.Trim().ToUpper(),
|
||||
Linha = linhaLimpa,
|
||||
Chip = string.IsNullOrWhiteSpace(chipLimpo) ? null : chipLimpo,
|
||||
Usuario = req.Usuario?.Trim(),
|
||||
Status = req.Status?.Trim(),
|
||||
Skil = req.Skil?.Trim(),
|
||||
Modalidade = req.Modalidade?.Trim(),
|
||||
PlanoContrato = req.PlanoContrato?.Trim(),
|
||||
Conta = req.Conta?.Trim(),
|
||||
VencConta = req.VencConta?.Trim(),
|
||||
|
||||
var maxItem = await _db.MobileLines.MaxAsync(x => (int?)x.Item) ?? 0;
|
||||
var now = DateTime.UtcNow;
|
||||
var created = new List<MobileLine>(quantidade);
|
||||
DataBloqueio = ToUtc(req.DataBloqueio),
|
||||
DataEntregaOpera = ToUtc(req.DataEntregaOpera),
|
||||
DataEntregaCliente = ToUtc(req.DataEntregaCliente),
|
||||
|
||||
for (var i = 0; i < quantidade; i++)
|
||||
{
|
||||
var newLine = new MobileLine
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Item = maxItem + 1 + i,
|
||||
Cliente = req.Cliente.Trim().ToUpper(),
|
||||
Linha = i == 0 ? linhaLimpa : null,
|
||||
Chip = i == 0 && !string.IsNullOrWhiteSpace(chipLimpo) ? chipLimpo : null,
|
||||
Usuario = req.Usuario?.Trim(),
|
||||
Status = req.Status?.Trim(),
|
||||
Skil = req.Skil?.Trim(),
|
||||
Modalidade = req.Modalidade?.Trim(),
|
||||
PlanoContrato = req.PlanoContrato?.Trim(),
|
||||
Conta = req.Conta?.Trim(),
|
||||
VencConta = req.VencConta?.Trim(),
|
||||
Cedente = req.Cedente?.Trim(),
|
||||
Solicitante = req.Solicitante?.Trim(),
|
||||
|
||||
DataBloqueio = ToUtc(req.DataBloqueio),
|
||||
DataEntregaOpera = ToUtc(req.DataEntregaOpera),
|
||||
DataEntregaCliente = ToUtc(req.DataEntregaCliente),
|
||||
FranquiaVivo = req.FranquiaVivo,
|
||||
ValorPlanoVivo = req.ValorPlanoVivo,
|
||||
GestaoVozDados = req.GestaoVozDados,
|
||||
Skeelo = req.Skeelo,
|
||||
VivoNewsPlus = req.VivoNewsPlus,
|
||||
VivoTravelMundo = req.VivoTravelMundo,
|
||||
VivoGestaoDispositivo = req.VivoGestaoDispositivo,
|
||||
ValorContratoVivo = req.ValorContratoVivo,
|
||||
FranquiaLine = req.FranquiaLine,
|
||||
FranquiaGestao = req.FranquiaGestao,
|
||||
LocacaoAp = req.LocacaoAp,
|
||||
ValorContratoLine = req.ValorContratoLine,
|
||||
Desconto = req.Desconto,
|
||||
Lucro = req.Lucro,
|
||||
|
||||
Cedente = req.Cedente?.Trim(),
|
||||
Solicitante = req.Solicitante?.Trim(),
|
||||
CreatedAt = nowSingle,
|
||||
UpdatedAt = nowSingle
|
||||
};
|
||||
|
||||
FranquiaVivo = req.FranquiaVivo,
|
||||
ValorPlanoVivo = req.ValorPlanoVivo,
|
||||
GestaoVozDados = req.GestaoVozDados,
|
||||
Skeelo = req.Skeelo,
|
||||
VivoNewsPlus = req.VivoNewsPlus,
|
||||
VivoTravelMundo = req.VivoTravelMundo,
|
||||
VivoGestaoDispositivo = req.VivoGestaoDispositivo,
|
||||
ValorContratoVivo = req.ValorContratoVivo,
|
||||
FranquiaLine = req.FranquiaLine,
|
||||
FranquiaGestao = req.FranquiaGestao,
|
||||
LocacaoAp = req.LocacaoAp,
|
||||
ValorContratoLine = req.ValorContratoLine,
|
||||
Desconto = req.Desconto,
|
||||
Lucro = req.Lucro,
|
||||
ApplyReservaRule(newLineSingle);
|
||||
|
||||
CreatedAt = now,
|
||||
UpdatedAt = now
|
||||
};
|
||||
|
||||
ApplyReservaRule(newLine);
|
||||
created.Add(newLine);
|
||||
}
|
||||
|
||||
_db.MobileLines.AddRange(created);
|
||||
_db.MobileLines.Add(newLineSingle);
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -432,13 +528,7 @@ namespace line_gestao_api.Controllers
|
|||
return StatusCode(500, new { message = "Erro ao salvar no banco de dados." });
|
||||
}
|
||||
|
||||
if (created.Count == 1)
|
||||
{
|
||||
var newLine = created[0];
|
||||
return CreatedAtAction(nameof(GetById), new { id = newLine.Id }, ToDetailDto(newLine));
|
||||
}
|
||||
|
||||
return StatusCode(StatusCodes.Status201Created, created.Select(ToDetailDto).ToList());
|
||||
return CreatedAtAction(nameof(GetById), new { id = newLineSingle.Id }, ToDetailDto(newLineSingle));
|
||||
}
|
||||
|
||||
// ==========================================================
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace line_gestao_api.Dtos
|
||||
{
|
||||
|
|
@ -12,7 +13,8 @@ namespace line_gestao_api.Dtos
|
|||
public string? Chip { get; set; } // ICCID
|
||||
public string? Cliente { get; set; } // Obrigatório na validação do Controller
|
||||
public string? Usuario { get; set; }
|
||||
public int? QtdLinhas { get; set; } // Quantidade de linhas a serem criadas
|
||||
public int? QtdLinhas { get; set; } // Quantidade de linhas (uso legado)
|
||||
public List<CreateMobileLineItemDto>? Linhas { get; set; } // Linhas individuais para criação em lote
|
||||
|
||||
// ==========================
|
||||
// Classificação e Status
|
||||
|
|
@ -67,4 +69,67 @@ namespace line_gestao_api.Dtos
|
|||
public decimal? Desconto { get; set; }
|
||||
public decimal? Lucro { get; set; }
|
||||
}
|
||||
|
||||
public class CreateMobileLineItemDto
|
||||
{
|
||||
// ==========================
|
||||
// Identificação Básica
|
||||
// ==========================
|
||||
public string? Linha { get; set; }
|
||||
public string? Chip { get; set; }
|
||||
public string? Usuario { get; set; }
|
||||
|
||||
// ==========================
|
||||
// Classificação e Status
|
||||
// ==========================
|
||||
public string? Status { get; set; }
|
||||
public string? Skil { get; set; }
|
||||
public string? Modalidade { get; set; }
|
||||
|
||||
// ==========================
|
||||
// Dados Contratuais
|
||||
// ==========================
|
||||
public string? PlanoContrato { get; set; }
|
||||
public string? Conta { get; set; }
|
||||
public string? VencConta { get; set; }
|
||||
|
||||
// ==========================
|
||||
// Datas Importantes
|
||||
// ==========================
|
||||
public DateTime? DataBloqueio { get; set; }
|
||||
public DateTime? DataEntregaOpera { get; set; }
|
||||
public DateTime? DataEntregaCliente { get; set; }
|
||||
|
||||
// ==========================
|
||||
// Responsáveis / Logística
|
||||
// ==========================
|
||||
public string? Cedente { get; set; }
|
||||
public string? Solicitante { get; set; }
|
||||
|
||||
// ==========================
|
||||
// Financeiro - Vivo
|
||||
// ==========================
|
||||
public decimal? FranquiaVivo { get; set; }
|
||||
public decimal? ValorPlanoVivo { get; set; }
|
||||
public decimal? GestaoVozDados { get; set; }
|
||||
public decimal? Skeelo { get; set; }
|
||||
public decimal? VivoNewsPlus { get; set; }
|
||||
public decimal? VivoTravelMundo { get; set; }
|
||||
public decimal? VivoGestaoDispositivo { get; set; }
|
||||
public decimal? ValorContratoVivo { get; set; }
|
||||
|
||||
// ==========================
|
||||
// Financeiro - Line Móvel
|
||||
// ==========================
|
||||
public decimal? FranquiaLine { get; set; }
|
||||
public decimal? FranquiaGestao { get; set; }
|
||||
public decimal? LocacaoAp { get; set; }
|
||||
public decimal? ValorContratoLine { get; set; }
|
||||
|
||||
// ==========================
|
||||
// Resultado Financeiro
|
||||
// ==========================
|
||||
public decimal? Desconto { get; set; }
|
||||
public decimal? Lucro { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue