|
|
|
|
@ -719,83 +719,77 @@ namespace line_gestao_api.Controllers
|
|
|
|
|
if (string.IsNullOrWhiteSpace(linhaLimpa))
|
|
|
|
|
return BadRequest(new { message = "Número de linha inválido." });
|
|
|
|
|
|
|
|
|
|
MobileLine? lineToPersist = null;
|
|
|
|
|
|
|
|
|
|
if (req.ReservaLineId.HasValue && req.ReservaLineId.Value != Guid.Empty)
|
|
|
|
|
{
|
|
|
|
|
lineToPersist = await _db.MobileLines.FirstOrDefaultAsync(x => x.Id == req.ReservaLineId.Value);
|
|
|
|
|
if (lineToPersist == null)
|
|
|
|
|
return BadRequest(new { message = "A linha selecionada na Reserva não foi encontrada." });
|
|
|
|
|
|
|
|
|
|
if (!IsReservaLineForTransfer(lineToPersist))
|
|
|
|
|
return Conflict(new { message = "A linha selecionada não está mais disponível na Reserva." });
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(lineToPersist.Linha) &&
|
|
|
|
|
!string.Equals(lineToPersist.Linha, linhaLimpa, StringComparison.Ordinal))
|
|
|
|
|
{
|
|
|
|
|
return BadRequest(new { message = "A linha selecionada na Reserva não corresponde ao número informado." });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (lineToPersist == null)
|
|
|
|
|
{
|
|
|
|
|
var existingByLinha = await _db.MobileLines.FirstOrDefaultAsync(x => x.Linha == linhaLimpa);
|
|
|
|
|
if (existingByLinha != null)
|
|
|
|
|
{
|
|
|
|
|
if (IsReservaLineForTransfer(existingByLinha))
|
|
|
|
|
{
|
|
|
|
|
lineToPersist = existingByLinha;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
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." });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(chipLimpo))
|
|
|
|
|
{
|
|
|
|
|
var chipExists = await _db.MobileLines.AsNoTracking()
|
|
|
|
|
.AnyAsync(x => x.Chip == chipLimpo && (lineToPersist == null || x.Id != lineToPersist.Id));
|
|
|
|
|
var chipExists = await _db.MobileLines.AsNoTracking().AnyAsync(x => x.Chip == chipLimpo);
|
|
|
|
|
if (chipExists)
|
|
|
|
|
return Conflict(new { message = $"O Chip (ICCID) {req.Chip} já está cadastrado no sistema." });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var maxItem = await _db.MobileLines.MaxAsync(x => (int?)x.Item) ?? 0;
|
|
|
|
|
var nextItem = maxItem + 1;
|
|
|
|
|
|
|
|
|
|
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 isReassignmentFromReserva = lineToPersist != null;
|
|
|
|
|
if (!isReassignmentFromReserva)
|
|
|
|
|
{
|
|
|
|
|
var maxItem = await _db.MobileLines.MaxAsync(x => (int?)x.Item) ?? 0;
|
|
|
|
|
lineToPersist = new MobileLine
|
|
|
|
|
var newLine = new MobileLine
|
|
|
|
|
{
|
|
|
|
|
Id = Guid.NewGuid(),
|
|
|
|
|
Item = maxItem + 1,
|
|
|
|
|
CreatedAt = now
|
|
|
|
|
Item = nextItem,
|
|
|
|
|
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(),
|
|
|
|
|
|
|
|
|
|
DataBloqueio = ToUtc(req.DataBloqueio),
|
|
|
|
|
DataEntregaOpera = ToUtc(req.DataEntregaOpera),
|
|
|
|
|
DataEntregaCliente = ToUtc(req.DataEntregaCliente),
|
|
|
|
|
|
|
|
|
|
Cedente = req.Cedente?.Trim(),
|
|
|
|
|
Solicitante = req.Solicitante?.Trim(),
|
|
|
|
|
|
|
|
|
|
FranquiaVivo = franquiaVivo,
|
|
|
|
|
ValorPlanoVivo = valorPlanoVivo,
|
|
|
|
|
GestaoVozDados = req.GestaoVozDados,
|
|
|
|
|
Skeelo = req.Skeelo,
|
|
|
|
|
VivoNewsPlus = req.VivoNewsPlus,
|
|
|
|
|
VivoTravelMundo = req.VivoTravelMundo,
|
|
|
|
|
VivoSync = req.VivoSync,
|
|
|
|
|
VivoGestaoDispositivo = req.VivoGestaoDispositivo,
|
|
|
|
|
ValorContratoVivo = req.ValorContratoVivo,
|
|
|
|
|
FranquiaLine = req.FranquiaLine,
|
|
|
|
|
FranquiaGestao = req.FranquiaGestao,
|
|
|
|
|
LocacaoAp = req.LocacaoAp,
|
|
|
|
|
ValorContratoLine = req.ValorContratoLine,
|
|
|
|
|
Desconto = req.Desconto,
|
|
|
|
|
Lucro = req.Lucro,
|
|
|
|
|
TipoDeChip = req.TipoDeChip?.Trim(),
|
|
|
|
|
|
|
|
|
|
CreatedAt = now,
|
|
|
|
|
UpdatedAt = now
|
|
|
|
|
};
|
|
|
|
|
_db.MobileLines.Add(lineToPersist);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var previousLinha = lineToPersist!.Linha;
|
|
|
|
|
ApplyCreateRequestToLine(lineToPersist, req, linhaLimpa, chipLimpo, franquiaVivo, valorPlanoVivo, now);
|
|
|
|
|
ApplyReservaRule(lineToPersist);
|
|
|
|
|
var ensuredTenant = await EnsureTenantForClientAsync(lineToPersist.Cliente);
|
|
|
|
|
if (ensuredTenant != null)
|
|
|
|
|
{
|
|
|
|
|
lineToPersist.TenantId = ensuredTenant.Id;
|
|
|
|
|
lineToPersist.Cliente = ensuredTenant.NomeOficial;
|
|
|
|
|
}
|
|
|
|
|
ApplyReservaRule(newLine);
|
|
|
|
|
|
|
|
|
|
_db.MobileLines.Add(newLine);
|
|
|
|
|
var vigencia = await UpsertVigenciaFromMobileLineAsync(
|
|
|
|
|
lineToPersist,
|
|
|
|
|
newLine,
|
|
|
|
|
req.DtEfetivacaoServico,
|
|
|
|
|
req.DtTerminoFidelizacao,
|
|
|
|
|
overrideDates: false,
|
|
|
|
|
previousLinha: isReassignmentFromReserva ? previousLinha : null);
|
|
|
|
|
overrideDates: false);
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
@ -807,12 +801,7 @@ namespace line_gestao_api.Controllers
|
|
|
|
|
return StatusCode(500, new { message = "Erro ao salvar no banco de dados." });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isReassignmentFromReserva)
|
|
|
|
|
{
|
|
|
|
|
return Ok(ToDetailDto(lineToPersist, vigencia));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CreatedAtAction(nameof(GetById), new { id = lineToPersist.Id }, ToDetailDto(lineToPersist, vigencia));
|
|
|
|
|
return CreatedAtAction(nameof(GetById), new { id = newLine.Id }, ToDetailDto(newLine, vigencia));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ==========================================================
|
|
|
|
|
@ -864,7 +853,6 @@ namespace line_gestao_api.Controllers
|
|
|
|
|
var nextItem = (await _db.MobileLines.MaxAsync(x => (int?)x.Item) ?? 0);
|
|
|
|
|
var seenBatchLinhas = new HashSet<string>(StringComparer.Ordinal);
|
|
|
|
|
var seenBatchChips = new HashSet<string>(StringComparer.Ordinal);
|
|
|
|
|
var tenantCache = new Dictionary<string, Tenant?>(StringComparer.Ordinal);
|
|
|
|
|
var createdLines = new List<(MobileLine line, VigenciaLine? vigencia)>(requests.Count);
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < requests.Count; i++)
|
|
|
|
|
@ -919,7 +907,7 @@ namespace line_gestao_api.Controllers
|
|
|
|
|
{
|
|
|
|
|
Id = Guid.NewGuid(),
|
|
|
|
|
Item = nextItem,
|
|
|
|
|
Cliente = entry.Cliente.Trim(),
|
|
|
|
|
Cliente = entry.Cliente.Trim().ToUpper(),
|
|
|
|
|
Linha = linhaLimpa,
|
|
|
|
|
Chip = string.IsNullOrWhiteSpace(chipLimpo) ? null : chipLimpo,
|
|
|
|
|
Usuario = entry.Usuario?.Trim(),
|
|
|
|
|
@ -960,19 +948,6 @@ namespace line_gestao_api.Controllers
|
|
|
|
|
|
|
|
|
|
ApplyReservaRule(newLine);
|
|
|
|
|
|
|
|
|
|
var tenantCacheKey = NormalizeTenantKeyValue(newLine.Cliente ?? string.Empty);
|
|
|
|
|
if (!tenantCache.TryGetValue(tenantCacheKey, out var ensuredTenant))
|
|
|
|
|
{
|
|
|
|
|
ensuredTenant = await EnsureTenantForClientAsync(newLine.Cliente);
|
|
|
|
|
tenantCache[tenantCacheKey] = ensuredTenant;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ensuredTenant != null)
|
|
|
|
|
{
|
|
|
|
|
newLine.TenantId = ensuredTenant.Id;
|
|
|
|
|
newLine.Cliente = ensuredTenant.NomeOficial;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_db.MobileLines.Add(newLine);
|
|
|
|
|
|
|
|
|
|
var vigencia = await UpsertVigenciaFromMobileLineAsync(
|
|
|
|
|
@ -1066,8 +1041,7 @@ namespace line_gestao_api.Controllers
|
|
|
|
|
|
|
|
|
|
var usuarioDestino = string.IsNullOrWhiteSpace(req?.UsuarioDestino) ? null : req!.UsuarioDestino!.Trim();
|
|
|
|
|
var skilDestinoSolicitado = string.IsNullOrWhiteSpace(req?.SkilDestino) ? null : req!.SkilDestino!.Trim();
|
|
|
|
|
var ensuredTenantDestino = await EnsureTenantForClientAsync(clienteDestino);
|
|
|
|
|
var clienteDestinoOficial = ensuredTenantDestino?.NomeOficial ?? clienteDestino;
|
|
|
|
|
var clienteDestinoUpper = clienteDestino.ToUpperInvariant();
|
|
|
|
|
|
|
|
|
|
var linhas = await _db.MobileLines
|
|
|
|
|
.Where(x => ids.Contains(x.Id))
|
|
|
|
|
@ -1120,11 +1094,7 @@ namespace line_gestao_api.Controllers
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var clienteAnterior = line.Cliente;
|
|
|
|
|
line.Cliente = clienteDestinoOficial;
|
|
|
|
|
if (ensuredTenantDestino != null)
|
|
|
|
|
{
|
|
|
|
|
line.TenantId = ensuredTenantDestino.Id;
|
|
|
|
|
}
|
|
|
|
|
line.Cliente = clienteDestinoUpper;
|
|
|
|
|
|
|
|
|
|
if (IsReservaValue(line.Usuario))
|
|
|
|
|
{
|
|
|
|
|
@ -1364,12 +1334,6 @@ namespace line_gestao_api.Controllers
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ApplyReservaRule(x);
|
|
|
|
|
var ensuredTenant = await EnsureTenantForClientAsync(x.Cliente);
|
|
|
|
|
if (ensuredTenant != null)
|
|
|
|
|
{
|
|
|
|
|
x.TenantId = ensuredTenant.Id;
|
|
|
|
|
x.Cliente = ensuredTenant.NomeOficial;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await UpsertVigenciaFromMobileLineAsync(
|
|
|
|
|
x,
|
|
|
|
|
@ -4085,167 +4049,6 @@ namespace line_gestao_api.Controllers
|
|
|
|
|
|| IsReservaValue(line.Cliente);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void ApplyCreateRequestToLine(
|
|
|
|
|
MobileLine line,
|
|
|
|
|
CreateMobileLineDto req,
|
|
|
|
|
string linhaLimpa,
|
|
|
|
|
string? chipLimpo,
|
|
|
|
|
decimal? franquiaVivo,
|
|
|
|
|
decimal? valorPlanoVivo,
|
|
|
|
|
DateTime now)
|
|
|
|
|
{
|
|
|
|
|
line.Cliente = req.Cliente?.Trim();
|
|
|
|
|
line.Linha = linhaLimpa;
|
|
|
|
|
line.Chip = string.IsNullOrWhiteSpace(chipLimpo) ? null : chipLimpo;
|
|
|
|
|
line.Usuario = req.Usuario?.Trim();
|
|
|
|
|
line.Status = req.Status?.Trim();
|
|
|
|
|
line.Skil = req.Skil?.Trim();
|
|
|
|
|
line.Modalidade = req.Modalidade?.Trim();
|
|
|
|
|
line.PlanoContrato = req.PlanoContrato?.Trim();
|
|
|
|
|
line.Conta = req.Conta?.Trim();
|
|
|
|
|
line.VencConta = req.VencConta?.Trim();
|
|
|
|
|
|
|
|
|
|
line.DataBloqueio = ToUtc(req.DataBloqueio);
|
|
|
|
|
line.DataEntregaOpera = ToUtc(req.DataEntregaOpera);
|
|
|
|
|
line.DataEntregaCliente = ToUtc(req.DataEntregaCliente);
|
|
|
|
|
|
|
|
|
|
line.Cedente = req.Cedente?.Trim();
|
|
|
|
|
line.Solicitante = req.Solicitante?.Trim();
|
|
|
|
|
|
|
|
|
|
line.FranquiaVivo = franquiaVivo;
|
|
|
|
|
line.ValorPlanoVivo = valorPlanoVivo;
|
|
|
|
|
line.GestaoVozDados = req.GestaoVozDados;
|
|
|
|
|
line.Skeelo = req.Skeelo;
|
|
|
|
|
line.VivoNewsPlus = req.VivoNewsPlus;
|
|
|
|
|
line.VivoTravelMundo = req.VivoTravelMundo;
|
|
|
|
|
line.VivoSync = req.VivoSync;
|
|
|
|
|
line.VivoGestaoDispositivo = req.VivoGestaoDispositivo;
|
|
|
|
|
line.ValorContratoVivo = req.ValorContratoVivo;
|
|
|
|
|
line.FranquiaLine = req.FranquiaLine;
|
|
|
|
|
line.FranquiaGestao = req.FranquiaGestao;
|
|
|
|
|
line.LocacaoAp = req.LocacaoAp;
|
|
|
|
|
line.ValorContratoLine = req.ValorContratoLine;
|
|
|
|
|
line.Desconto = req.Desconto;
|
|
|
|
|
line.Lucro = req.Lucro;
|
|
|
|
|
line.TipoDeChip = req.TipoDeChip?.Trim();
|
|
|
|
|
line.UpdatedAt = now;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task<Tenant?> EnsureTenantForClientAsync(string? rawClientName)
|
|
|
|
|
{
|
|
|
|
|
var clientName = (rawClientName ?? string.Empty).Trim();
|
|
|
|
|
if (string.IsNullOrWhiteSpace(clientName) || IsReservaValue(clientName))
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var normalizedClient = NormalizeTenantKeyValue(clientName);
|
|
|
|
|
if (string.IsNullOrWhiteSpace(normalizedClient) ||
|
|
|
|
|
string.Equals(normalizedClient, "RESERVA", StringComparison.Ordinal))
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var existingCandidates = await _db.Tenants
|
|
|
|
|
.IgnoreQueryFilters()
|
|
|
|
|
.Where(t => !t.IsSystem && t.SourceType == SystemTenantConstants.MobileLinesClienteSourceType)
|
|
|
|
|
.ToListAsync();
|
|
|
|
|
|
|
|
|
|
var tenant = existingCandidates.FirstOrDefault(t =>
|
|
|
|
|
string.Equals(NormalizeTenantKeyValue(t.SourceKey ?? string.Empty), normalizedClient, StringComparison.Ordinal) ||
|
|
|
|
|
string.Equals(NormalizeTenantKeyValue(t.NomeOficial ?? string.Empty), normalizedClient, StringComparison.Ordinal));
|
|
|
|
|
|
|
|
|
|
if (tenant != null)
|
|
|
|
|
{
|
|
|
|
|
var changed = false;
|
|
|
|
|
if (!tenant.Ativo)
|
|
|
|
|
{
|
|
|
|
|
tenant.Ativo = true;
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(tenant.NomeOficial))
|
|
|
|
|
{
|
|
|
|
|
tenant.NomeOficial = clientName;
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(tenant.SourceKey))
|
|
|
|
|
{
|
|
|
|
|
tenant.SourceKey = clientName;
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!string.Equals(tenant.SourceType, SystemTenantConstants.MobileLinesClienteSourceType, StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
{
|
|
|
|
|
tenant.SourceType = SystemTenantConstants.MobileLinesClienteSourceType;
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (changed)
|
|
|
|
|
{
|
|
|
|
|
tenant.NomeOficial = tenant.NomeOficial.Trim();
|
|
|
|
|
tenant.SourceKey = tenant.SourceKey?.Trim();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return tenant;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var deterministicId = DeterministicGuid.FromString($"{SystemTenantConstants.MobileLinesClienteSourceType}:{normalizedClient}");
|
|
|
|
|
var idAlreadyExists = await _db.Tenants.IgnoreQueryFilters().AnyAsync(t => t.Id == deterministicId);
|
|
|
|
|
|
|
|
|
|
tenant = new Tenant
|
|
|
|
|
{
|
|
|
|
|
Id = idAlreadyExists ? Guid.NewGuid() : deterministicId,
|
|
|
|
|
NomeOficial = clientName,
|
|
|
|
|
IsSystem = false,
|
|
|
|
|
Ativo = true,
|
|
|
|
|
SourceType = SystemTenantConstants.MobileLinesClienteSourceType,
|
|
|
|
|
SourceKey = clientName,
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
_db.Tenants.Add(tenant);
|
|
|
|
|
return tenant;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static string NormalizeTenantKeyValue(string value)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrWhiteSpace(value))
|
|
|
|
|
{
|
|
|
|
|
return string.Empty;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var normalized = value.Trim().Normalize(NormalizationForm.FormD);
|
|
|
|
|
var sb = new StringBuilder(normalized.Length);
|
|
|
|
|
var previousWasSpace = false;
|
|
|
|
|
|
|
|
|
|
foreach (var ch in normalized)
|
|
|
|
|
{
|
|
|
|
|
var category = CharUnicodeInfo.GetUnicodeCategory(ch);
|
|
|
|
|
if (category == UnicodeCategory.NonSpacingMark)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (char.IsWhiteSpace(ch))
|
|
|
|
|
{
|
|
|
|
|
if (!previousWasSpace)
|
|
|
|
|
{
|
|
|
|
|
sb.Append(' ');
|
|
|
|
|
previousWasSpace = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sb.Append(char.ToUpperInvariant(ch));
|
|
|
|
|
previousWasSpace = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sb.ToString().Trim();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ==========================================================
|
|
|
|
|
// HELPERS (SEUS)
|
|
|
|
|
// ==========================================================
|
|
|
|
|
|