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

72 lines
2.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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);
}
}