Files
SIG-CM2.0/src/api/SIGCM2.Application/IngresosBrutos/NuevaVersion/NuevaVersionIngresosBrutosCommandHandler.cs

72 lines
2.6 KiB
C#
Raw Normal View History

using System.Transactions;
using SIGCM2.Application.Abstractions;
using SIGCM2.Application.Abstractions.Persistence;
using SIGCM2.Application.Audit;
using SIGCM2.Application.IngresosBrutos.Dtos;
using SIGCM2.Domain.Exceptions;
namespace SIGCM2.Application.IngresosBrutos.NuevaVersion;
public sealed class NuevaVersionIngresosBrutosCommandHandler
: ICommandHandler<NuevaVersionIngresosBrutosCommand, NuevaVersionIibbResultDto>
{
private readonly IIngresosBrutosRepository _repo;
private readonly IAuditLogger _audit;
public NuevaVersionIngresosBrutosCommandHandler(IIngresosBrutosRepository repo, IAuditLogger audit)
{
_repo = repo;
_audit = audit;
}
public async Task<NuevaVersionIibbResultDto> Handle(NuevaVersionIngresosBrutosCommand command)
{
// Step 1: load predecesora
var predecesora = await _repo.GetByIdAsync(command.PredecesoraId)
?? throw new IngresosBrutosNotFoundException(command.PredecesoraId);
// Step 2: guard — predecesora must be open and active
if (!predecesora.Activo || predecesora.VigenciaHasta is not null)
throw new PredecesorYaCerradoException(command.PredecesoraId);
// Steps 34: domain validation + tuple creation (throws ArgumentException if vigencia invalid)
var (predecesoraCerrada, nuevaVersion) = predecesora.NuevaVersion(
command.NuevaAlicuota,
command.VigenciaDesde);
using var tx = new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted },
TransactionScopeAsyncFlowOption.Enabled);
// Step 5: optimistic close — race guard
var closed = await _repo.UpdateCierreVigenciaAsync(
command.PredecesoraId,
predecesoraCerrada.VigenciaHasta!.Value);
if (!closed)
throw new PredecesorYaCerradoException(command.PredecesoraId);
// Step 6: insert new version
var nuevoId = await _repo.InsertAsync(nuevaVersion);
// Step 7: audit (fail-closed)
await _audit.LogAsync(
action: "ingresos_brutos.nueva_version",
targetType: "IngresosBrutos",
targetId: nuevoId.ToString(),
metadata: new
{
predecesoraId = command.PredecesoraId,
nuevoId,
alicuotaNueva = command.NuevaAlicuota,
vigenciaDesde = command.VigenciaDesde,
});
// Step 8: commit
tx.Complete();
return new NuevaVersionIibbResultDto(command.PredecesoraId, nuevoId);
}
}