diff --git a/src/api/SIGCM2.Application/Auth/Login/LoginCommandHandler.cs b/src/api/SIGCM2.Application/Auth/Login/LoginCommandHandler.cs index e74a07f..d1e8459 100644 --- a/src/api/SIGCM2.Application/Auth/Login/LoginCommandHandler.cs +++ b/src/api/SIGCM2.Application/Auth/Login/LoginCommandHandler.cs @@ -22,6 +22,7 @@ public sealed class LoginCommandHandler : ICommandHandler _logger; + private readonly TimeProvider _timeProvider; public LoginCommandHandler( IUsuarioRepository repository, @@ -33,7 +34,8 @@ public sealed class LoginCommandHandler : ICommandHandler logger) + ILogger logger, + TimeProvider timeProvider) { _repository = repository; _hasher = hasher; @@ -45,6 +47,7 @@ public sealed class LoginCommandHandler : ICommandHandler Handle(LoginCommand command) @@ -81,7 +84,7 @@ public sealed class LoginCommandHandler : ICommandHandler Handle(LogoutCommand command) { // Revoke all active tokens for the user across all families. // Idempotent: 0 rows affected is not an error. - await _refreshRepo.RevokeAllActiveForUserAsync(command.UsuarioId, DateTime.UtcNow); + var now = _timeProvider.GetUtcNow().UtcDateTime; + await _refreshRepo.RevokeAllActiveForUserAsync(command.UsuarioId, now); await _security.LogAsync("logout", "success", actorUserId: command.UsuarioId); return new LogoutResponseDto(true, "Sesión cerrada correctamente"); } diff --git a/src/api/SIGCM2.Application/Auth/Refresh/RefreshCommandHandler.cs b/src/api/SIGCM2.Application/Auth/Refresh/RefreshCommandHandler.cs index b9dbbaa..b9d56e5 100644 --- a/src/api/SIGCM2.Application/Auth/Refresh/RefreshCommandHandler.cs +++ b/src/api/SIGCM2.Application/Auth/Refresh/RefreshCommandHandler.cs @@ -17,6 +17,7 @@ public sealed class RefreshCommandHandler : ICommandHandler Handle(RefreshCommand command) @@ -60,7 +63,7 @@ public sealed class RefreshCommandHandler : ICommandHandler Handle(CreateIngresosBrutosCommand command) @@ -51,7 +53,7 @@ public sealed class CreateIngresosBrutosCommandHandler vigenciaDesde: entity.VigenciaDesde, vigenciaHasta: entity.VigenciaHasta, predecesorId: entity.PredecesorId, - fechaCreacion: DateTime.UtcNow, + fechaCreacion: _timeProvider.GetUtcNow().UtcDateTime, fechaModificacion: null)); } } diff --git a/src/api/SIGCM2.Application/IngresosBrutos/Deactivate/DeactivateIngresosBrutosCommandHandler.cs b/src/api/SIGCM2.Application/IngresosBrutos/Deactivate/DeactivateIngresosBrutosCommandHandler.cs index d78b769..b21b179 100644 --- a/src/api/SIGCM2.Application/IngresosBrutos/Deactivate/DeactivateIngresosBrutosCommandHandler.cs +++ b/src/api/SIGCM2.Application/IngresosBrutos/Deactivate/DeactivateIngresosBrutosCommandHandler.cs @@ -12,11 +12,13 @@ public sealed class DeactivateIngresosBrutosCommandHandler { private readonly IIngresosBrutosRepository _repo; private readonly IAuditLogger _audit; + private readonly TimeProvider _timeProvider; - public DeactivateIngresosBrutosCommandHandler(IIngresosBrutosRepository repo, IAuditLogger audit) + public DeactivateIngresosBrutosCommandHandler(IIngresosBrutosRepository repo, IAuditLogger audit, TimeProvider timeProvider) { _repo = repo; _audit = audit; + _timeProvider = timeProvider; } public async Task Handle(DeactivateIngresosBrutosCommand command) @@ -41,6 +43,7 @@ public sealed class DeactivateIngresosBrutosCommandHandler tx.Complete(); - return IngresosBrutosMapper.ToDto(entity.Deactivate()); + var now = _timeProvider.GetUtcNow().UtcDateTime; + return IngresosBrutosMapper.ToDto(entity.Deactivate(now)); } } diff --git a/src/api/SIGCM2.Application/IngresosBrutos/NuevaVersion/NuevaVersionIngresosBrutosCommandHandler.cs b/src/api/SIGCM2.Application/IngresosBrutos/NuevaVersion/NuevaVersionIngresosBrutosCommandHandler.cs index 741b93b..6131c1c 100644 --- a/src/api/SIGCM2.Application/IngresosBrutos/NuevaVersion/NuevaVersionIngresosBrutosCommandHandler.cs +++ b/src/api/SIGCM2.Application/IngresosBrutos/NuevaVersion/NuevaVersionIngresosBrutosCommandHandler.cs @@ -12,11 +12,13 @@ public sealed class NuevaVersionIngresosBrutosCommandHandler { private readonly IIngresosBrutosRepository _repo; private readonly IAuditLogger _audit; + private readonly TimeProvider _timeProvider; - public NuevaVersionIngresosBrutosCommandHandler(IIngresosBrutosRepository repo, IAuditLogger audit) + public NuevaVersionIngresosBrutosCommandHandler(IIngresosBrutosRepository repo, IAuditLogger audit, TimeProvider timeProvider) { _repo = repo; _audit = audit; + _timeProvider = timeProvider; } public async Task Handle(NuevaVersionIngresosBrutosCommand command) @@ -29,10 +31,13 @@ public sealed class NuevaVersionIngresosBrutosCommandHandler if (!predecesora.Activo || predecesora.VigenciaHasta is not null) throw new PredecesorYaCerradoException(command.PredecesoraId); + var now = _timeProvider.GetUtcNow().UtcDateTime; + // Steps 3–4: domain validation + tuple creation (throws ArgumentException if vigencia invalid) var (predecesoraCerrada, nuevaVersion) = predecesora.NuevaVersion( command.NuevaAlicuota, - command.VigenciaDesde); + command.VigenciaDesde, + now); using var tx = new TransactionScope( TransactionScopeOption.Required, diff --git a/src/api/SIGCM2.Application/IngresosBrutos/Reactivate/ReactivateIngresosBrutosCommandHandler.cs b/src/api/SIGCM2.Application/IngresosBrutos/Reactivate/ReactivateIngresosBrutosCommandHandler.cs index 4b96bd3..c203c7e 100644 --- a/src/api/SIGCM2.Application/IngresosBrutos/Reactivate/ReactivateIngresosBrutosCommandHandler.cs +++ b/src/api/SIGCM2.Application/IngresosBrutos/Reactivate/ReactivateIngresosBrutosCommandHandler.cs @@ -12,11 +12,13 @@ public sealed class ReactivateIngresosBrutosCommandHandler { private readonly IIngresosBrutosRepository _repo; private readonly IAuditLogger _audit; + private readonly TimeProvider _timeProvider; - public ReactivateIngresosBrutosCommandHandler(IIngresosBrutosRepository repo, IAuditLogger audit) + public ReactivateIngresosBrutosCommandHandler(IIngresosBrutosRepository repo, IAuditLogger audit, TimeProvider timeProvider) { _repo = repo; _audit = audit; + _timeProvider = timeProvider; } public async Task Handle(ReactivateIngresosBrutosCommand command) @@ -41,6 +43,7 @@ public sealed class ReactivateIngresosBrutosCommandHandler tx.Complete(); - return IngresosBrutosMapper.ToDto(entity.Reactivate()); + var now = _timeProvider.GetUtcNow().UtcDateTime; + return IngresosBrutosMapper.ToDto(entity.Reactivate(now)); } } diff --git a/src/api/SIGCM2.Application/IngresosBrutos/Update/UpdateIngresosBrutosCommandHandler.cs b/src/api/SIGCM2.Application/IngresosBrutos/Update/UpdateIngresosBrutosCommandHandler.cs index d87e4c3..4b0ef12 100644 --- a/src/api/SIGCM2.Application/IngresosBrutos/Update/UpdateIngresosBrutosCommandHandler.cs +++ b/src/api/SIGCM2.Application/IngresosBrutos/Update/UpdateIngresosBrutosCommandHandler.cs @@ -12,11 +12,13 @@ public sealed class UpdateIngresosBrutosCommandHandler { private readonly IIngresosBrutosRepository _repo; private readonly IAuditLogger _audit; + private readonly TimeProvider _timeProvider; - public UpdateIngresosBrutosCommandHandler(IIngresosBrutosRepository repo, IAuditLogger audit) + public UpdateIngresosBrutosCommandHandler(IIngresosBrutosRepository repo, IAuditLogger audit, TimeProvider timeProvider) { _repo = repo; _audit = audit; + _timeProvider = timeProvider; } public async Task Handle(UpdateIngresosBrutosCommand command) @@ -24,8 +26,9 @@ public sealed class UpdateIngresosBrutosCommandHandler var entity = await _repo.GetByIdAsync(command.Id) ?? throw new IngresosBrutosNotFoundException(command.Id); - var updated = entity.WithDescripcion(command.Descripcion); - updated = command.Activo ? updated.Reactivate() : updated.Deactivate(); + var now = _timeProvider.GetUtcNow().UtcDateTime; + var updated = entity.WithDescripcion(command.Descripcion, now); + updated = command.Activo ? updated.Reactivate(now) : updated.Deactivate(now); using var tx = new TransactionScope( TransactionScopeOption.Required, diff --git a/src/api/SIGCM2.Application/Medios/Deactivate/DeactivateMedioCommandHandler.cs b/src/api/SIGCM2.Application/Medios/Deactivate/DeactivateMedioCommandHandler.cs index 7b87564..92dacc1 100644 --- a/src/api/SIGCM2.Application/Medios/Deactivate/DeactivateMedioCommandHandler.cs +++ b/src/api/SIGCM2.Application/Medios/Deactivate/DeactivateMedioCommandHandler.cs @@ -11,11 +11,13 @@ public sealed class DeactivateMedioCommandHandler : ICommandHandler Handle(DeactivateMedioCommand command) @@ -27,7 +29,8 @@ public sealed class DeactivateMedioCommandHandler : ICommandHandler Handle(ReactivateMedioCommand command) @@ -28,7 +30,8 @@ public sealed class ReactivateMedioCommandHandler : ICommandHandler Handle(UpdateMedioCommand command) @@ -23,7 +25,8 @@ public sealed class UpdateMedioCommandHandler : ICommandHandler Handle(DeactivatePuntoDeVentaCommand command) @@ -32,7 +35,8 @@ public sealed class DeactivatePuntoDeVentaCommandHandler : ICommandHandler Handle(ReactivatePuntoDeVentaCommand command) @@ -39,7 +42,8 @@ public sealed class ReactivatePuntoDeVentaCommandHandler : ICommandHandler Handle(UpdatePuntoDeVentaCommand command) @@ -39,7 +42,8 @@ public sealed class UpdatePuntoDeVentaCommandHandler : ICommandHandler Handle(DeactivateSeccionCommand command) @@ -35,7 +41,8 @@ public sealed class DeactivateSeccionCommandHandler : ICommandHandler Handle(ReactivateSeccionCommand command) @@ -36,7 +42,8 @@ public sealed class ReactivateSeccionCommandHandler : ICommandHandler Handle(UpdateSeccionCommand command) @@ -31,7 +37,8 @@ public sealed class UpdateSeccionCommandHandler : ICommandHandler Handle(CreateTipoDeIvaCommand command) @@ -55,7 +57,7 @@ public sealed class CreateTipoDeIvaCommandHandler : ICommandHandler Handle(DeactivateTipoDeIvaCommand command) @@ -41,6 +43,7 @@ public sealed class DeactivateTipoDeIvaCommandHandler : ICommandHandler Handle(NuevaVersionTipoDeIvaCommand command) @@ -29,10 +31,13 @@ public sealed class NuevaVersionTipoDeIvaCommandHandler if (!predecesora.Activo || predecesora.VigenciaHasta is not null) throw new PredecesorYaCerradoException(command.PredecesoraId); + var now = _timeProvider.GetUtcNow().UtcDateTime; + // Steps 3–4: delegate validation + tuple creation to domain (throws ArgumentException on invalid vigencia) var (predecesoraCerrada, nuevaVersion) = predecesora.NuevaVersion( command.NuevoPorcentaje, - command.VigenciaDesde); + command.VigenciaDesde, + now); using var tx = new TransactionScope( TransactionScopeOption.Required, diff --git a/src/api/SIGCM2.Application/TiposDeIva/Reactivate/ReactivateTipoDeIvaCommandHandler.cs b/src/api/SIGCM2.Application/TiposDeIva/Reactivate/ReactivateTipoDeIvaCommandHandler.cs index 2a2ab9a..7a617b7 100644 --- a/src/api/SIGCM2.Application/TiposDeIva/Reactivate/ReactivateTipoDeIvaCommandHandler.cs +++ b/src/api/SIGCM2.Application/TiposDeIva/Reactivate/ReactivateTipoDeIvaCommandHandler.cs @@ -11,11 +11,13 @@ public sealed class ReactivateTipoDeIvaCommandHandler : ICommandHandler Handle(ReactivateTipoDeIvaCommand command) @@ -41,6 +43,7 @@ public sealed class ReactivateTipoDeIvaCommandHandler : ICommandHandler Handle(UpdateTipoDeIvaCommand command) @@ -23,15 +25,16 @@ public sealed class UpdateTipoDeIvaCommandHandler : ICommandHandler Handle(DeactivateUsuarioCommand cmd) @@ -43,7 +46,7 @@ public sealed class DeactivateUsuarioCommandHandler : ICommandHandler Handle(UpdateUsuarioPermisosOverridesCommand command) @@ -59,7 +62,8 @@ public sealed class UpdateUsuarioPermisosOverridesCommandHandler // 4. Persist — use WithPermisosJson to get updated FechaModificacion var newOverrides = new PermisosOverride(grant, deny); var previousOverrides = PermisosOverride.FromJson(usuario.PermisosJson); - var updated = usuario.WithPermisosJson(newOverrides.ToJson()); + var now = _timeProvider.GetUtcNow().UtcDateTime; + var updated = usuario.WithPermisosJson(newOverrides.ToJson(), now); using (var tx = new TransactionScope( TransactionScopeOption.Required, diff --git a/src/api/SIGCM2.Application/Usuarios/Reactivate/ReactivateUsuarioCommandHandler.cs b/src/api/SIGCM2.Application/Usuarios/Reactivate/ReactivateUsuarioCommandHandler.cs index c89a473..4c73270 100644 --- a/src/api/SIGCM2.Application/Usuarios/Reactivate/ReactivateUsuarioCommandHandler.cs +++ b/src/api/SIGCM2.Application/Usuarios/Reactivate/ReactivateUsuarioCommandHandler.cs @@ -12,11 +12,16 @@ public sealed class ReactivateUsuarioCommandHandler : ICommandHandler Handle(ReactivateUsuarioCommand cmd) @@ -34,7 +39,7 @@ public sealed class ReactivateUsuarioCommandHandler : ICommandHandler Handle(ResetUsuarioPasswordCommand cmd) @@ -45,8 +48,9 @@ public sealed class ResetUsuarioPasswordCommandHandler : ICommandHandler Handle(UpdateUsuarioCommand cmd) @@ -52,7 +55,7 @@ public sealed class UpdateUsuarioCommandHandler : ICommandHandler