241 lines
8.5 KiB
C#
241 lines
8.5 KiB
C#
using System.Globalization;
|
|
using System.Security.Claims;
|
|
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;
|
|
|
|
namespace line_gestao_api.Controllers;
|
|
|
|
[ApiController]
|
|
[Route("api/solicitacoes-linhas")]
|
|
[Authorize]
|
|
public class SolicitacoesLinhasController : ControllerBase
|
|
{
|
|
private const string TipoAlteracaoFranquia = "ALTERACAO_FRANQUIA";
|
|
private const string TipoBloqueio = "BLOQUEIO";
|
|
private readonly AppDbContext _db;
|
|
|
|
public SolicitacoesLinhasController(AppDbContext db)
|
|
{
|
|
_db = db;
|
|
}
|
|
|
|
[HttpPost]
|
|
[Authorize(Roles = "sysadmin,gestor,cliente")]
|
|
public async Task<ActionResult<SolicitacaoLinhaListDto>> Create([FromBody] CreateSolicitacaoLinhaRequestDto req)
|
|
{
|
|
if (req.LineId == Guid.Empty)
|
|
{
|
|
return BadRequest(new { message = "Linha inválida para solicitação." });
|
|
}
|
|
|
|
var line = await _db.MobileLines
|
|
.AsNoTracking()
|
|
.FirstOrDefaultAsync(x => x.Id == req.LineId);
|
|
if (line == null)
|
|
{
|
|
return NotFound(new { message = "Linha não encontrada." });
|
|
}
|
|
|
|
var tipoSolicitacao = NormalizeTipoSolicitacao(req.TipoSolicitacao);
|
|
if (tipoSolicitacao == null)
|
|
{
|
|
return BadRequest(new { message = "Tipo de solicitação inválido. Use 'alteracao-franquia' ou 'bloqueio'." });
|
|
}
|
|
|
|
decimal? franquiaLineNova = null;
|
|
if (tipoSolicitacao == TipoAlteracaoFranquia)
|
|
{
|
|
if (!req.FranquiaLineNova.HasValue)
|
|
{
|
|
return BadRequest(new { message = "Informe a nova franquia para solicitar alteração." });
|
|
}
|
|
|
|
franquiaLineNova = decimal.Round(req.FranquiaLineNova.Value, 2, MidpointRounding.AwayFromZero);
|
|
if (franquiaLineNova < 0)
|
|
{
|
|
return BadRequest(new { message = "A nova franquia não pode ser negativa." });
|
|
}
|
|
}
|
|
|
|
var solicitanteNome = ResolveSolicitanteNome();
|
|
var usuarioLinha = NormalizeOptionalText(line.Usuario) ?? solicitanteNome;
|
|
var linha = NormalizeOptionalText(line.Linha) ?? "-";
|
|
var mensagem = tipoSolicitacao == TipoAlteracaoFranquia
|
|
? $"O Usuário \"{usuarioLinha}\" solicitou alteração da linha \"{linha}\" \"{FormatFranquia(line.FranquiaLine)}\" -> \"{FormatFranquia(franquiaLineNova)}\""
|
|
: $"O Usuário \"{usuarioLinha}\" solicitou bloqueio da linha \"{linha}\"";
|
|
|
|
var solicitacao = new SolicitacaoLinha
|
|
{
|
|
TenantId = line.TenantId,
|
|
MobileLineId = line.Id,
|
|
Linha = NormalizeOptionalText(line.Linha),
|
|
UsuarioLinha = NormalizeOptionalText(line.Usuario),
|
|
TipoSolicitacao = tipoSolicitacao,
|
|
FranquiaLineAtual = line.FranquiaLine,
|
|
FranquiaLineNova = franquiaLineNova,
|
|
SolicitanteUserId = ResolveSolicitanteUserId(),
|
|
SolicitanteNome = solicitanteNome,
|
|
Mensagem = mensagem,
|
|
Status = "PENDENTE",
|
|
CreatedAt = DateTime.UtcNow
|
|
};
|
|
|
|
_db.SolicitacaoLinhas.Add(solicitacao);
|
|
await _db.SaveChangesAsync();
|
|
|
|
var tenantNome = await _db.Tenants
|
|
.AsNoTracking()
|
|
.Where(t => t.Id == solicitacao.TenantId)
|
|
.Select(t => t.NomeOficial)
|
|
.FirstOrDefaultAsync();
|
|
|
|
return Ok(ToDto(solicitacao, tenantNome));
|
|
}
|
|
|
|
[HttpGet]
|
|
[Authorize(Roles = "sysadmin,gestor")]
|
|
public async Task<ActionResult<PagedResult<SolicitacaoLinhaListDto>>> List(
|
|
[FromQuery] string? search,
|
|
[FromQuery] int page = 1,
|
|
[FromQuery] int pageSize = 20)
|
|
{
|
|
page = page < 1 ? 1 : page;
|
|
pageSize = pageSize < 1 ? 20 : Math.Min(pageSize, 200);
|
|
|
|
var query =
|
|
from solicitacao in _db.SolicitacaoLinhas.AsNoTracking()
|
|
join tenant in _db.Tenants.AsNoTracking()
|
|
on solicitacao.TenantId equals tenant.Id into tenantJoin
|
|
from tenant in tenantJoin.DefaultIfEmpty()
|
|
select new
|
|
{
|
|
Solicitacao = solicitacao,
|
|
TenantNome = tenant != null ? tenant.NomeOficial : null
|
|
};
|
|
|
|
if (!string.IsNullOrWhiteSpace(search))
|
|
{
|
|
var term = search.Trim();
|
|
query = query.Where(x =>
|
|
EF.Functions.ILike(x.Solicitacao.Linha ?? "", $"%{term}%") ||
|
|
EF.Functions.ILike(x.Solicitacao.UsuarioLinha ?? "", $"%{term}%") ||
|
|
EF.Functions.ILike(x.Solicitacao.SolicitanteNome ?? "", $"%{term}%") ||
|
|
EF.Functions.ILike(x.Solicitacao.Mensagem ?? "", $"%{term}%"));
|
|
}
|
|
|
|
var total = await query.CountAsync();
|
|
var items = await query
|
|
.OrderByDescending(x => x.Solicitacao.CreatedAt)
|
|
.Skip((page - 1) * pageSize)
|
|
.Take(pageSize)
|
|
.Select(x => new SolicitacaoLinhaListDto
|
|
{
|
|
Id = x.Solicitacao.Id,
|
|
TenantId = x.Solicitacao.TenantId,
|
|
TenantNome = x.TenantNome,
|
|
MobileLineId = x.Solicitacao.MobileLineId,
|
|
Linha = x.Solicitacao.Linha,
|
|
UsuarioLinha = x.Solicitacao.UsuarioLinha,
|
|
TipoSolicitacao = x.Solicitacao.TipoSolicitacao,
|
|
FranquiaLineAtual = x.Solicitacao.FranquiaLineAtual,
|
|
FranquiaLineNova = x.Solicitacao.FranquiaLineNova,
|
|
SolicitanteNome = x.Solicitacao.SolicitanteNome,
|
|
Mensagem = x.Solicitacao.Mensagem,
|
|
Status = x.Solicitacao.Status,
|
|
CreatedAt = x.Solicitacao.CreatedAt
|
|
})
|
|
.ToListAsync();
|
|
|
|
return Ok(new PagedResult<SolicitacaoLinhaListDto>
|
|
{
|
|
Page = page,
|
|
PageSize = pageSize,
|
|
Total = total,
|
|
Items = items
|
|
});
|
|
}
|
|
|
|
private static string? NormalizeTipoSolicitacao(string? tipoSolicitacao)
|
|
{
|
|
var value = (tipoSolicitacao ?? string.Empty).Trim().ToLowerInvariant();
|
|
return value switch
|
|
{
|
|
"alteracao-franquia" => TipoAlteracaoFranquia,
|
|
"alteracao_franquia" => TipoAlteracaoFranquia,
|
|
"alteracaofranquia" => TipoAlteracaoFranquia,
|
|
"franquia" => TipoAlteracaoFranquia,
|
|
"bloqueio" => TipoBloqueio,
|
|
"solicitar-bloqueio" => TipoBloqueio,
|
|
_ => null
|
|
};
|
|
}
|
|
|
|
private string ResolveSolicitanteNome()
|
|
{
|
|
var fromClaim = User.FindFirstValue("name");
|
|
if (!string.IsNullOrWhiteSpace(fromClaim))
|
|
{
|
|
return fromClaim.Trim();
|
|
}
|
|
|
|
var fromIdentity = User.Identity?.Name;
|
|
if (!string.IsNullOrWhiteSpace(fromIdentity))
|
|
{
|
|
return fromIdentity.Trim();
|
|
}
|
|
|
|
var fromEmail = User.FindFirstValue(ClaimTypes.Email) ?? User.FindFirstValue("email");
|
|
if (!string.IsNullOrWhiteSpace(fromEmail))
|
|
{
|
|
return fromEmail.Trim();
|
|
}
|
|
|
|
return "Usuário";
|
|
}
|
|
|
|
private Guid? ResolveSolicitanteUserId()
|
|
{
|
|
var raw =
|
|
User.FindFirstValue(ClaimTypes.NameIdentifier) ??
|
|
User.FindFirstValue("sub");
|
|
|
|
return Guid.TryParse(raw, out var parsed) ? parsed : null;
|
|
}
|
|
|
|
private static string? NormalizeOptionalText(string? value)
|
|
{
|
|
return string.IsNullOrWhiteSpace(value) ? null : value.Trim();
|
|
}
|
|
|
|
private static string FormatFranquia(decimal? value)
|
|
{
|
|
return value.HasValue
|
|
? value.Value.ToString("0.##", CultureInfo.GetCultureInfo("pt-BR"))
|
|
: "-";
|
|
}
|
|
|
|
private static SolicitacaoLinhaListDto ToDto(SolicitacaoLinha solicitacao, string? tenantNome)
|
|
{
|
|
return new SolicitacaoLinhaListDto
|
|
{
|
|
Id = solicitacao.Id,
|
|
TenantId = solicitacao.TenantId,
|
|
TenantNome = tenantNome,
|
|
MobileLineId = solicitacao.MobileLineId,
|
|
Linha = solicitacao.Linha,
|
|
UsuarioLinha = solicitacao.UsuarioLinha,
|
|
TipoSolicitacao = solicitacao.TipoSolicitacao,
|
|
FranquiaLineAtual = solicitacao.FranquiaLineAtual,
|
|
FranquiaLineNova = solicitacao.FranquiaLineNova,
|
|
SolicitanteNome = solicitacao.SolicitanteNome,
|
|
Mensagem = solicitacao.Mensagem,
|
|
Status = solicitacao.Status,
|
|
CreatedAt = solicitacao.CreatedAt
|
|
};
|
|
}
|
|
}
|