feat(udt-011): T400.10 — inject TimeProvider into all Application handlers
All command handlers that call domain mutators now inject TimeProvider via constructor and use _timeProvider.GetUtcNow().UtcDateTime as the explicit 'now' argument. Replaces previous direct DateTime.UtcNow usage.
This commit is contained in:
@@ -22,6 +22,7 @@ public sealed class LoginCommandHandler : ICommandHandler<LoginCommand, LoginRes
|
|||||||
private readonly IRolPermisoRepository _rolPermisoRepository;
|
private readonly IRolPermisoRepository _rolPermisoRepository;
|
||||||
private readonly ISecurityEventLogger _security;
|
private readonly ISecurityEventLogger _security;
|
||||||
private readonly ILogger<LoginCommandHandler> _logger;
|
private readonly ILogger<LoginCommandHandler> _logger;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public LoginCommandHandler(
|
public LoginCommandHandler(
|
||||||
IUsuarioRepository repository,
|
IUsuarioRepository repository,
|
||||||
@@ -33,7 +34,8 @@ public sealed class LoginCommandHandler : ICommandHandler<LoginCommand, LoginRes
|
|||||||
AuthOptions authOptions,
|
AuthOptions authOptions,
|
||||||
IRolPermisoRepository rolPermisoRepository,
|
IRolPermisoRepository rolPermisoRepository,
|
||||||
ISecurityEventLogger security,
|
ISecurityEventLogger security,
|
||||||
ILogger<LoginCommandHandler> logger)
|
ILogger<LoginCommandHandler> logger,
|
||||||
|
TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_repository = repository;
|
_repository = repository;
|
||||||
_hasher = hasher;
|
_hasher = hasher;
|
||||||
@@ -45,6 +47,7 @@ public sealed class LoginCommandHandler : ICommandHandler<LoginCommand, LoginRes
|
|||||||
_rolPermisoRepository = rolPermisoRepository;
|
_rolPermisoRepository = rolPermisoRepository;
|
||||||
_security = security;
|
_security = security;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<LoginResponseDto> Handle(LoginCommand command)
|
public async Task<LoginResponseDto> Handle(LoginCommand command)
|
||||||
@@ -81,7 +84,7 @@ public sealed class LoginCommandHandler : ICommandHandler<LoginCommand, LoginRes
|
|||||||
// Generate and persist refresh token — only the hash hits the DB
|
// Generate and persist refresh token — only the hash hits the DB
|
||||||
var rawRefresh = _refreshGenerator.Generate();
|
var rawRefresh = _refreshGenerator.Generate();
|
||||||
var hash = TokenHasher.Sha256Base64Url(rawRefresh);
|
var hash = TokenHasher.Sha256Base64Url(rawRefresh);
|
||||||
var now = DateTime.UtcNow;
|
var now = _timeProvider.GetUtcNow().UtcDateTime;
|
||||||
var ttl = TimeSpan.FromDays(_authOptions.RefreshTokenDays);
|
var ttl = TimeSpan.FromDays(_authOptions.RefreshTokenDays);
|
||||||
var entity = RefreshToken.IssueForNewFamily(
|
var entity = RefreshToken.IssueForNewFamily(
|
||||||
usuario.Id, hash, now, ttl,
|
usuario.Id, hash, now, ttl,
|
||||||
|
|||||||
@@ -8,18 +8,24 @@ public sealed class LogoutCommandHandler : ICommandHandler<LogoutCommand, Logout
|
|||||||
{
|
{
|
||||||
private readonly IRefreshTokenRepository _refreshRepo;
|
private readonly IRefreshTokenRepository _refreshRepo;
|
||||||
private readonly ISecurityEventLogger _security;
|
private readonly ISecurityEventLogger _security;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public LogoutCommandHandler(IRefreshTokenRepository refreshRepo, ISecurityEventLogger security)
|
public LogoutCommandHandler(
|
||||||
|
IRefreshTokenRepository refreshRepo,
|
||||||
|
ISecurityEventLogger security,
|
||||||
|
TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_refreshRepo = refreshRepo;
|
_refreshRepo = refreshRepo;
|
||||||
_security = security;
|
_security = security;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<LogoutResponseDto> Handle(LogoutCommand command)
|
public async Task<LogoutResponseDto> Handle(LogoutCommand command)
|
||||||
{
|
{
|
||||||
// Revoke all active tokens for the user across all families.
|
// Revoke all active tokens for the user across all families.
|
||||||
// Idempotent: 0 rows affected is not an error.
|
// 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);
|
await _security.LogAsync("logout", "success", actorUserId: command.UsuarioId);
|
||||||
return new LogoutResponseDto(true, "Sesión cerrada correctamente");
|
return new LogoutResponseDto(true, "Sesión cerrada correctamente");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ public sealed class RefreshCommandHandler : ICommandHandler<RefreshCommand, Refr
|
|||||||
private readonly IClientContext _clientCtx;
|
private readonly IClientContext _clientCtx;
|
||||||
private readonly AuthOptions _authOptions;
|
private readonly AuthOptions _authOptions;
|
||||||
private readonly ISecurityEventLogger _security;
|
private readonly ISecurityEventLogger _security;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public RefreshCommandHandler(
|
public RefreshCommandHandler(
|
||||||
IRefreshTokenRepository refreshRepo,
|
IRefreshTokenRepository refreshRepo,
|
||||||
@@ -25,7 +26,8 @@ public sealed class RefreshCommandHandler : ICommandHandler<RefreshCommand, Refr
|
|||||||
IRefreshTokenGenerator refreshGenerator,
|
IRefreshTokenGenerator refreshGenerator,
|
||||||
IClientContext clientCtx,
|
IClientContext clientCtx,
|
||||||
AuthOptions authOptions,
|
AuthOptions authOptions,
|
||||||
ISecurityEventLogger security)
|
ISecurityEventLogger security,
|
||||||
|
TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_refreshRepo = refreshRepo;
|
_refreshRepo = refreshRepo;
|
||||||
_usuarioRepo = usuarioRepo;
|
_usuarioRepo = usuarioRepo;
|
||||||
@@ -34,6 +36,7 @@ public sealed class RefreshCommandHandler : ICommandHandler<RefreshCommand, Refr
|
|||||||
_clientCtx = clientCtx;
|
_clientCtx = clientCtx;
|
||||||
_authOptions = authOptions;
|
_authOptions = authOptions;
|
||||||
_security = security;
|
_security = security;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<RefreshResponseDto> Handle(RefreshCommand command)
|
public async Task<RefreshResponseDto> Handle(RefreshCommand command)
|
||||||
@@ -60,7 +63,7 @@ public sealed class RefreshCommandHandler : ICommandHandler<RefreshCommand, Refr
|
|||||||
if (stored is null)
|
if (stored is null)
|
||||||
throw new InvalidRefreshTokenException();
|
throw new InvalidRefreshTokenException();
|
||||||
|
|
||||||
var now = DateTime.UtcNow;
|
var now = _timeProvider.GetUtcNow().UtcDateTime;
|
||||||
|
|
||||||
// 4. Reuse detection: already revoked → chain revocation and throw
|
// 4. Reuse detection: already revoked → chain revocation and throw
|
||||||
if (stored.IsRevoked)
|
if (stored.IsRevoked)
|
||||||
|
|||||||
@@ -11,11 +11,13 @@ public sealed class CreateIngresosBrutosCommandHandler
|
|||||||
{
|
{
|
||||||
private readonly IIngresosBrutosRepository _repo;
|
private readonly IIngresosBrutosRepository _repo;
|
||||||
private readonly IAuditLogger _audit;
|
private readonly IAuditLogger _audit;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public CreateIngresosBrutosCommandHandler(IIngresosBrutosRepository repo, IAuditLogger audit)
|
public CreateIngresosBrutosCommandHandler(IIngresosBrutosRepository repo, IAuditLogger audit, TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_audit = audit;
|
_audit = audit;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IngresosBrutosDto> Handle(CreateIngresosBrutosCommand command)
|
public async Task<IngresosBrutosDto> Handle(CreateIngresosBrutosCommand command)
|
||||||
@@ -51,7 +53,7 @@ public sealed class CreateIngresosBrutosCommandHandler
|
|||||||
vigenciaDesde: entity.VigenciaDesde,
|
vigenciaDesde: entity.VigenciaDesde,
|
||||||
vigenciaHasta: entity.VigenciaHasta,
|
vigenciaHasta: entity.VigenciaHasta,
|
||||||
predecesorId: entity.PredecesorId,
|
predecesorId: entity.PredecesorId,
|
||||||
fechaCreacion: DateTime.UtcNow,
|
fechaCreacion: _timeProvider.GetUtcNow().UtcDateTime,
|
||||||
fechaModificacion: null));
|
fechaModificacion: null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,13 @@ public sealed class DeactivateIngresosBrutosCommandHandler
|
|||||||
{
|
{
|
||||||
private readonly IIngresosBrutosRepository _repo;
|
private readonly IIngresosBrutosRepository _repo;
|
||||||
private readonly IAuditLogger _audit;
|
private readonly IAuditLogger _audit;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public DeactivateIngresosBrutosCommandHandler(IIngresosBrutosRepository repo, IAuditLogger audit)
|
public DeactivateIngresosBrutosCommandHandler(IIngresosBrutosRepository repo, IAuditLogger audit, TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_audit = audit;
|
_audit = audit;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IngresosBrutosDto> Handle(DeactivateIngresosBrutosCommand command)
|
public async Task<IngresosBrutosDto> Handle(DeactivateIngresosBrutosCommand command)
|
||||||
@@ -41,6 +43,7 @@ public sealed class DeactivateIngresosBrutosCommandHandler
|
|||||||
|
|
||||||
tx.Complete();
|
tx.Complete();
|
||||||
|
|
||||||
return IngresosBrutosMapper.ToDto(entity.Deactivate());
|
var now = _timeProvider.GetUtcNow().UtcDateTime;
|
||||||
|
return IngresosBrutosMapper.ToDto(entity.Deactivate(now));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,13 @@ public sealed class NuevaVersionIngresosBrutosCommandHandler
|
|||||||
{
|
{
|
||||||
private readonly IIngresosBrutosRepository _repo;
|
private readonly IIngresosBrutosRepository _repo;
|
||||||
private readonly IAuditLogger _audit;
|
private readonly IAuditLogger _audit;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public NuevaVersionIngresosBrutosCommandHandler(IIngresosBrutosRepository repo, IAuditLogger audit)
|
public NuevaVersionIngresosBrutosCommandHandler(IIngresosBrutosRepository repo, IAuditLogger audit, TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_audit = audit;
|
_audit = audit;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<NuevaVersionIibbResultDto> Handle(NuevaVersionIngresosBrutosCommand command)
|
public async Task<NuevaVersionIibbResultDto> Handle(NuevaVersionIngresosBrutosCommand command)
|
||||||
@@ -29,10 +31,13 @@ public sealed class NuevaVersionIngresosBrutosCommandHandler
|
|||||||
if (!predecesora.Activo || predecesora.VigenciaHasta is not null)
|
if (!predecesora.Activo || predecesora.VigenciaHasta is not null)
|
||||||
throw new PredecesorYaCerradoException(command.PredecesoraId);
|
throw new PredecesorYaCerradoException(command.PredecesoraId);
|
||||||
|
|
||||||
|
var now = _timeProvider.GetUtcNow().UtcDateTime;
|
||||||
|
|
||||||
// Steps 3–4: domain validation + tuple creation (throws ArgumentException if vigencia invalid)
|
// Steps 3–4: domain validation + tuple creation (throws ArgumentException if vigencia invalid)
|
||||||
var (predecesoraCerrada, nuevaVersion) = predecesora.NuevaVersion(
|
var (predecesoraCerrada, nuevaVersion) = predecesora.NuevaVersion(
|
||||||
command.NuevaAlicuota,
|
command.NuevaAlicuota,
|
||||||
command.VigenciaDesde);
|
command.VigenciaDesde,
|
||||||
|
now);
|
||||||
|
|
||||||
using var tx = new TransactionScope(
|
using var tx = new TransactionScope(
|
||||||
TransactionScopeOption.Required,
|
TransactionScopeOption.Required,
|
||||||
|
|||||||
@@ -12,11 +12,13 @@ public sealed class ReactivateIngresosBrutosCommandHandler
|
|||||||
{
|
{
|
||||||
private readonly IIngresosBrutosRepository _repo;
|
private readonly IIngresosBrutosRepository _repo;
|
||||||
private readonly IAuditLogger _audit;
|
private readonly IAuditLogger _audit;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public ReactivateIngresosBrutosCommandHandler(IIngresosBrutosRepository repo, IAuditLogger audit)
|
public ReactivateIngresosBrutosCommandHandler(IIngresosBrutosRepository repo, IAuditLogger audit, TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_audit = audit;
|
_audit = audit;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IngresosBrutosDto> Handle(ReactivateIngresosBrutosCommand command)
|
public async Task<IngresosBrutosDto> Handle(ReactivateIngresosBrutosCommand command)
|
||||||
@@ -41,6 +43,7 @@ public sealed class ReactivateIngresosBrutosCommandHandler
|
|||||||
|
|
||||||
tx.Complete();
|
tx.Complete();
|
||||||
|
|
||||||
return IngresosBrutosMapper.ToDto(entity.Reactivate());
|
var now = _timeProvider.GetUtcNow().UtcDateTime;
|
||||||
|
return IngresosBrutosMapper.ToDto(entity.Reactivate(now));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,13 @@ public sealed class UpdateIngresosBrutosCommandHandler
|
|||||||
{
|
{
|
||||||
private readonly IIngresosBrutosRepository _repo;
|
private readonly IIngresosBrutosRepository _repo;
|
||||||
private readonly IAuditLogger _audit;
|
private readonly IAuditLogger _audit;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public UpdateIngresosBrutosCommandHandler(IIngresosBrutosRepository repo, IAuditLogger audit)
|
public UpdateIngresosBrutosCommandHandler(IIngresosBrutosRepository repo, IAuditLogger audit, TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_audit = audit;
|
_audit = audit;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IngresosBrutosDto> Handle(UpdateIngresosBrutosCommand command)
|
public async Task<IngresosBrutosDto> Handle(UpdateIngresosBrutosCommand command)
|
||||||
@@ -24,8 +26,9 @@ public sealed class UpdateIngresosBrutosCommandHandler
|
|||||||
var entity = await _repo.GetByIdAsync(command.Id)
|
var entity = await _repo.GetByIdAsync(command.Id)
|
||||||
?? throw new IngresosBrutosNotFoundException(command.Id);
|
?? throw new IngresosBrutosNotFoundException(command.Id);
|
||||||
|
|
||||||
var updated = entity.WithDescripcion(command.Descripcion);
|
var now = _timeProvider.GetUtcNow().UtcDateTime;
|
||||||
updated = command.Activo ? updated.Reactivate() : updated.Deactivate();
|
var updated = entity.WithDescripcion(command.Descripcion, now);
|
||||||
|
updated = command.Activo ? updated.Reactivate(now) : updated.Deactivate(now);
|
||||||
|
|
||||||
using var tx = new TransactionScope(
|
using var tx = new TransactionScope(
|
||||||
TransactionScopeOption.Required,
|
TransactionScopeOption.Required,
|
||||||
|
|||||||
@@ -11,11 +11,13 @@ public sealed class DeactivateMedioCommandHandler : ICommandHandler<DeactivateMe
|
|||||||
{
|
{
|
||||||
private readonly IMedioRepository _repo;
|
private readonly IMedioRepository _repo;
|
||||||
private readonly IAuditLogger _audit;
|
private readonly IAuditLogger _audit;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public DeactivateMedioCommandHandler(IMedioRepository repo, IAuditLogger audit)
|
public DeactivateMedioCommandHandler(IMedioRepository repo, IAuditLogger audit, TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_audit = audit;
|
_audit = audit;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<MedioStatusDto> Handle(DeactivateMedioCommand command)
|
public async Task<MedioStatusDto> Handle(DeactivateMedioCommand command)
|
||||||
@@ -27,7 +29,8 @@ public sealed class DeactivateMedioCommandHandler : ICommandHandler<DeactivateMe
|
|||||||
if (!target.Activo)
|
if (!target.Activo)
|
||||||
return new MedioStatusDto(target.Id, target.Codigo, target.Activo);
|
return new MedioStatusDto(target.Id, target.Codigo, target.Activo);
|
||||||
|
|
||||||
var updated = target.WithActivo(false);
|
var now = _timeProvider.GetUtcNow().UtcDateTime;
|
||||||
|
var updated = target.WithActivo(false, now);
|
||||||
|
|
||||||
using var tx = new TransactionScope(
|
using var tx = new TransactionScope(
|
||||||
TransactionScopeOption.Required,
|
TransactionScopeOption.Required,
|
||||||
|
|||||||
@@ -12,11 +12,13 @@ public sealed class ReactivateMedioCommandHandler : ICommandHandler<ReactivateMe
|
|||||||
{
|
{
|
||||||
private readonly IMedioRepository _repo;
|
private readonly IMedioRepository _repo;
|
||||||
private readonly IAuditLogger _audit;
|
private readonly IAuditLogger _audit;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public ReactivateMedioCommandHandler(IMedioRepository repo, IAuditLogger audit)
|
public ReactivateMedioCommandHandler(IMedioRepository repo, IAuditLogger audit, TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_audit = audit;
|
_audit = audit;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<MedioStatusDto> Handle(ReactivateMedioCommand command)
|
public async Task<MedioStatusDto> Handle(ReactivateMedioCommand command)
|
||||||
@@ -28,7 +30,8 @@ public sealed class ReactivateMedioCommandHandler : ICommandHandler<ReactivateMe
|
|||||||
if (target.Activo)
|
if (target.Activo)
|
||||||
return new MedioStatusDto(target.Id, target.Codigo, target.Activo);
|
return new MedioStatusDto(target.Id, target.Codigo, target.Activo);
|
||||||
|
|
||||||
var updated = target.WithActivo(true);
|
var now = _timeProvider.GetUtcNow().UtcDateTime;
|
||||||
|
var updated = target.WithActivo(true, now);
|
||||||
|
|
||||||
using var tx = new TransactionScope(
|
using var tx = new TransactionScope(
|
||||||
TransactionScopeOption.Required,
|
TransactionScopeOption.Required,
|
||||||
|
|||||||
@@ -11,11 +11,13 @@ public sealed class UpdateMedioCommandHandler : ICommandHandler<UpdateMedioComma
|
|||||||
{
|
{
|
||||||
private readonly IMedioRepository _repo;
|
private readonly IMedioRepository _repo;
|
||||||
private readonly IAuditLogger _audit;
|
private readonly IAuditLogger _audit;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public UpdateMedioCommandHandler(IMedioRepository repo, IAuditLogger audit)
|
public UpdateMedioCommandHandler(IMedioRepository repo, IAuditLogger audit, TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_audit = audit;
|
_audit = audit;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<MedioUpdatedDto> Handle(UpdateMedioCommand command)
|
public async Task<MedioUpdatedDto> Handle(UpdateMedioCommand command)
|
||||||
@@ -23,7 +25,8 @@ public sealed class UpdateMedioCommandHandler : ICommandHandler<UpdateMedioComma
|
|||||||
var target = await _repo.GetByIdAsync(command.Id)
|
var target = await _repo.GetByIdAsync(command.Id)
|
||||||
?? throw new MedioNotFoundException(command.Id);
|
?? throw new MedioNotFoundException(command.Id);
|
||||||
|
|
||||||
var updated = target.WithUpdatedProfile(command.Nombre, command.Tipo, command.PlataformaEmpresaId);
|
var now = _timeProvider.GetUtcNow().UtcDateTime;
|
||||||
|
var updated = target.WithUpdatedProfile(command.Nombre, command.Tipo, command.PlataformaEmpresaId, now);
|
||||||
|
|
||||||
using var tx = new TransactionScope(
|
using var tx = new TransactionScope(
|
||||||
TransactionScopeOption.Required,
|
TransactionScopeOption.Required,
|
||||||
|
|||||||
@@ -12,15 +12,18 @@ public sealed class DeactivatePuntoDeVentaCommandHandler : ICommandHandler<Deact
|
|||||||
private readonly IPuntoDeVentaRepository _repo;
|
private readonly IPuntoDeVentaRepository _repo;
|
||||||
private readonly IMedioRepository _medioRepo;
|
private readonly IMedioRepository _medioRepo;
|
||||||
private readonly IAuditLogger _audit;
|
private readonly IAuditLogger _audit;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public DeactivatePuntoDeVentaCommandHandler(
|
public DeactivatePuntoDeVentaCommandHandler(
|
||||||
IPuntoDeVentaRepository repo,
|
IPuntoDeVentaRepository repo,
|
||||||
IMedioRepository medioRepo,
|
IMedioRepository medioRepo,
|
||||||
IAuditLogger audit)
|
IAuditLogger audit,
|
||||||
|
TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_medioRepo = medioRepo;
|
_medioRepo = medioRepo;
|
||||||
_audit = audit;
|
_audit = audit;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PuntoDeVentaStatusDto> Handle(DeactivatePuntoDeVentaCommand command)
|
public async Task<PuntoDeVentaStatusDto> Handle(DeactivatePuntoDeVentaCommand command)
|
||||||
@@ -32,7 +35,8 @@ public sealed class DeactivatePuntoDeVentaCommandHandler : ICommandHandler<Deact
|
|||||||
if (!target.Activo)
|
if (!target.Activo)
|
||||||
return new PuntoDeVentaStatusDto(target.Id, target.NumeroAFIP, target.Activo);
|
return new PuntoDeVentaStatusDto(target.Id, target.NumeroAFIP, target.Activo);
|
||||||
|
|
||||||
var updated = target.WithActivo(false);
|
var now = _timeProvider.GetUtcNow().UtcDateTime;
|
||||||
|
var updated = target.WithActivo(false, now);
|
||||||
|
|
||||||
using var tx = new TransactionScope(
|
using var tx = new TransactionScope(
|
||||||
TransactionScopeOption.Required,
|
TransactionScopeOption.Required,
|
||||||
|
|||||||
@@ -13,15 +13,18 @@ public sealed class ReactivatePuntoDeVentaCommandHandler : ICommandHandler<React
|
|||||||
private readonly IPuntoDeVentaRepository _repo;
|
private readonly IPuntoDeVentaRepository _repo;
|
||||||
private readonly IMedioRepository _medioRepo;
|
private readonly IMedioRepository _medioRepo;
|
||||||
private readonly IAuditLogger _audit;
|
private readonly IAuditLogger _audit;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public ReactivatePuntoDeVentaCommandHandler(
|
public ReactivatePuntoDeVentaCommandHandler(
|
||||||
IPuntoDeVentaRepository repo,
|
IPuntoDeVentaRepository repo,
|
||||||
IMedioRepository medioRepo,
|
IMedioRepository medioRepo,
|
||||||
IAuditLogger audit)
|
IAuditLogger audit,
|
||||||
|
TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_medioRepo = medioRepo;
|
_medioRepo = medioRepo;
|
||||||
_audit = audit;
|
_audit = audit;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PuntoDeVentaStatusDto> Handle(ReactivatePuntoDeVentaCommand command)
|
public async Task<PuntoDeVentaStatusDto> Handle(ReactivatePuntoDeVentaCommand command)
|
||||||
@@ -39,7 +42,8 @@ public sealed class ReactivatePuntoDeVentaCommandHandler : ICommandHandler<React
|
|||||||
if (target.Activo)
|
if (target.Activo)
|
||||||
return new PuntoDeVentaStatusDto(target.Id, target.NumeroAFIP, target.Activo);
|
return new PuntoDeVentaStatusDto(target.Id, target.NumeroAFIP, target.Activo);
|
||||||
|
|
||||||
var updated = target.WithActivo(true);
|
var now = _timeProvider.GetUtcNow().UtcDateTime;
|
||||||
|
var updated = target.WithActivo(true, now);
|
||||||
|
|
||||||
using var tx = new TransactionScope(
|
using var tx = new TransactionScope(
|
||||||
TransactionScopeOption.Required,
|
TransactionScopeOption.Required,
|
||||||
|
|||||||
@@ -12,15 +12,18 @@ public sealed class UpdatePuntoDeVentaCommandHandler : ICommandHandler<UpdatePun
|
|||||||
private readonly IPuntoDeVentaRepository _repo;
|
private readonly IPuntoDeVentaRepository _repo;
|
||||||
private readonly IMedioRepository _medioRepo;
|
private readonly IMedioRepository _medioRepo;
|
||||||
private readonly IAuditLogger _audit;
|
private readonly IAuditLogger _audit;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public UpdatePuntoDeVentaCommandHandler(
|
public UpdatePuntoDeVentaCommandHandler(
|
||||||
IPuntoDeVentaRepository repo,
|
IPuntoDeVentaRepository repo,
|
||||||
IMedioRepository medioRepo,
|
IMedioRepository medioRepo,
|
||||||
IAuditLogger audit)
|
IAuditLogger audit,
|
||||||
|
TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_medioRepo = medioRepo;
|
_medioRepo = medioRepo;
|
||||||
_audit = audit;
|
_audit = audit;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PuntoDeVentaUpdatedDto> Handle(UpdatePuntoDeVentaCommand command)
|
public async Task<PuntoDeVentaUpdatedDto> Handle(UpdatePuntoDeVentaCommand command)
|
||||||
@@ -39,7 +42,8 @@ public sealed class UpdatePuntoDeVentaCommandHandler : ICommandHandler<UpdatePun
|
|||||||
if (exists)
|
if (exists)
|
||||||
throw new NumeroAFIPDuplicadoException(target.MedioId, command.NumeroAFIP);
|
throw new NumeroAFIPDuplicadoException(target.MedioId, command.NumeroAFIP);
|
||||||
|
|
||||||
var updated = target.WithUpdatedProfile(command.Nombre, command.NumeroAFIP, command.Descripcion);
|
var now = _timeProvider.GetUtcNow().UtcDateTime;
|
||||||
|
var updated = target.WithUpdatedProfile(command.Nombre, command.NumeroAFIP, command.Descripcion, now);
|
||||||
|
|
||||||
using var tx = new TransactionScope(
|
using var tx = new TransactionScope(
|
||||||
TransactionScopeOption.Required,
|
TransactionScopeOption.Required,
|
||||||
|
|||||||
@@ -12,12 +12,18 @@ public sealed class DeactivateSeccionCommandHandler : ICommandHandler<Deactivate
|
|||||||
private readonly ISeccionRepository _repo;
|
private readonly ISeccionRepository _repo;
|
||||||
private readonly IMedioRepository _medioRepo;
|
private readonly IMedioRepository _medioRepo;
|
||||||
private readonly IAuditLogger _audit;
|
private readonly IAuditLogger _audit;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public DeactivateSeccionCommandHandler(ISeccionRepository repo, IMedioRepository medioRepo, IAuditLogger audit)
|
public DeactivateSeccionCommandHandler(
|
||||||
|
ISeccionRepository repo,
|
||||||
|
IMedioRepository medioRepo,
|
||||||
|
IAuditLogger audit,
|
||||||
|
TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_medioRepo = medioRepo;
|
_medioRepo = medioRepo;
|
||||||
_audit = audit;
|
_audit = audit;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<SeccionStatusDto> Handle(DeactivateSeccionCommand command)
|
public async Task<SeccionStatusDto> Handle(DeactivateSeccionCommand command)
|
||||||
@@ -35,7 +41,8 @@ public sealed class DeactivateSeccionCommandHandler : ICommandHandler<Deactivate
|
|||||||
if (!target.Activo)
|
if (!target.Activo)
|
||||||
return new SeccionStatusDto(target.Id, target.Codigo, target.Activo);
|
return new SeccionStatusDto(target.Id, target.Codigo, target.Activo);
|
||||||
|
|
||||||
var updated = target.WithActivo(false);
|
var now = _timeProvider.GetUtcNow().UtcDateTime;
|
||||||
|
var updated = target.WithActivo(false, now);
|
||||||
|
|
||||||
using var tx = new TransactionScope(
|
using var tx = new TransactionScope(
|
||||||
TransactionScopeOption.Required,
|
TransactionScopeOption.Required,
|
||||||
|
|||||||
@@ -13,12 +13,18 @@ public sealed class ReactivateSeccionCommandHandler : ICommandHandler<Reactivate
|
|||||||
private readonly ISeccionRepository _repo;
|
private readonly ISeccionRepository _repo;
|
||||||
private readonly IMedioRepository _medioRepo;
|
private readonly IMedioRepository _medioRepo;
|
||||||
private readonly IAuditLogger _audit;
|
private readonly IAuditLogger _audit;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public ReactivateSeccionCommandHandler(ISeccionRepository repo, IMedioRepository medioRepo, IAuditLogger audit)
|
public ReactivateSeccionCommandHandler(
|
||||||
|
ISeccionRepository repo,
|
||||||
|
IMedioRepository medioRepo,
|
||||||
|
IAuditLogger audit,
|
||||||
|
TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_medioRepo = medioRepo;
|
_medioRepo = medioRepo;
|
||||||
_audit = audit;
|
_audit = audit;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<SeccionStatusDto> Handle(ReactivateSeccionCommand command)
|
public async Task<SeccionStatusDto> Handle(ReactivateSeccionCommand command)
|
||||||
@@ -36,7 +42,8 @@ public sealed class ReactivateSeccionCommandHandler : ICommandHandler<Reactivate
|
|||||||
if (target.Activo)
|
if (target.Activo)
|
||||||
return new SeccionStatusDto(target.Id, target.Codigo, target.Activo);
|
return new SeccionStatusDto(target.Id, target.Codigo, target.Activo);
|
||||||
|
|
||||||
var updated = target.WithActivo(true);
|
var now = _timeProvider.GetUtcNow().UtcDateTime;
|
||||||
|
var updated = target.WithActivo(true, now);
|
||||||
|
|
||||||
using var tx = new TransactionScope(
|
using var tx = new TransactionScope(
|
||||||
TransactionScopeOption.Required,
|
TransactionScopeOption.Required,
|
||||||
|
|||||||
@@ -12,12 +12,18 @@ public sealed class UpdateSeccionCommandHandler : ICommandHandler<UpdateSeccionC
|
|||||||
private readonly ISeccionRepository _repo;
|
private readonly ISeccionRepository _repo;
|
||||||
private readonly IMedioRepository _medioRepo;
|
private readonly IMedioRepository _medioRepo;
|
||||||
private readonly IAuditLogger _audit;
|
private readonly IAuditLogger _audit;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public UpdateSeccionCommandHandler(ISeccionRepository repo, IMedioRepository medioRepo, IAuditLogger audit)
|
public UpdateSeccionCommandHandler(
|
||||||
|
ISeccionRepository repo,
|
||||||
|
IMedioRepository medioRepo,
|
||||||
|
IAuditLogger audit,
|
||||||
|
TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_medioRepo = medioRepo;
|
_medioRepo = medioRepo;
|
||||||
_audit = audit;
|
_audit = audit;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<SeccionUpdatedDto> Handle(UpdateSeccionCommand command)
|
public async Task<SeccionUpdatedDto> Handle(UpdateSeccionCommand command)
|
||||||
@@ -31,7 +37,8 @@ public sealed class UpdateSeccionCommandHandler : ICommandHandler<UpdateSeccionC
|
|||||||
if (!medio.Activo)
|
if (!medio.Activo)
|
||||||
throw new MedioInactivoException(medio.Id);
|
throw new MedioInactivoException(medio.Id);
|
||||||
|
|
||||||
var updated = target.WithUpdatedProfile(command.Nombre, command.Tipo);
|
var now = _timeProvider.GetUtcNow().UtcDateTime;
|
||||||
|
var updated = target.WithUpdatedProfile(command.Nombre, command.Tipo, now);
|
||||||
|
|
||||||
using var tx = new TransactionScope(
|
using var tx = new TransactionScope(
|
||||||
TransactionScopeOption.Required,
|
TransactionScopeOption.Required,
|
||||||
|
|||||||
@@ -12,11 +12,13 @@ public sealed class CreateTipoDeIvaCommandHandler : ICommandHandler<CreateTipoDe
|
|||||||
{
|
{
|
||||||
private readonly ITipoDeIvaRepository _repo;
|
private readonly ITipoDeIvaRepository _repo;
|
||||||
private readonly IAuditLogger _audit;
|
private readonly IAuditLogger _audit;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public CreateTipoDeIvaCommandHandler(ITipoDeIvaRepository repo, IAuditLogger audit)
|
public CreateTipoDeIvaCommandHandler(ITipoDeIvaRepository repo, IAuditLogger audit, TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_audit = audit;
|
_audit = audit;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<TipoDeIvaDto> Handle(CreateTipoDeIvaCommand command)
|
public async Task<TipoDeIvaDto> Handle(CreateTipoDeIvaCommand command)
|
||||||
@@ -55,7 +57,7 @@ public sealed class CreateTipoDeIvaCommandHandler : ICommandHandler<CreateTipoDe
|
|||||||
vigenciaDesde: entity.VigenciaDesde,
|
vigenciaDesde: entity.VigenciaDesde,
|
||||||
vigenciaHasta: entity.VigenciaHasta,
|
vigenciaHasta: entity.VigenciaHasta,
|
||||||
predecesorId: entity.PredecesorId,
|
predecesorId: entity.PredecesorId,
|
||||||
fechaCreacion: DateTime.UtcNow,
|
fechaCreacion: _timeProvider.GetUtcNow().UtcDateTime,
|
||||||
fechaModificacion: null));
|
fechaModificacion: null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,11 +11,13 @@ public sealed class DeactivateTipoDeIvaCommandHandler : ICommandHandler<Deactiva
|
|||||||
{
|
{
|
||||||
private readonly ITipoDeIvaRepository _repo;
|
private readonly ITipoDeIvaRepository _repo;
|
||||||
private readonly IAuditLogger _audit;
|
private readonly IAuditLogger _audit;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public DeactivateTipoDeIvaCommandHandler(ITipoDeIvaRepository repo, IAuditLogger audit)
|
public DeactivateTipoDeIvaCommandHandler(ITipoDeIvaRepository repo, IAuditLogger audit, TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_audit = audit;
|
_audit = audit;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<TipoDeIvaDto> Handle(DeactivateTipoDeIvaCommand command)
|
public async Task<TipoDeIvaDto> Handle(DeactivateTipoDeIvaCommand command)
|
||||||
@@ -41,6 +43,7 @@ public sealed class DeactivateTipoDeIvaCommandHandler : ICommandHandler<Deactiva
|
|||||||
|
|
||||||
tx.Complete();
|
tx.Complete();
|
||||||
|
|
||||||
return TipoDeIvaMapper.ToDto(entity.Deactivate());
|
var now = _timeProvider.GetUtcNow().UtcDateTime;
|
||||||
|
return TipoDeIvaMapper.ToDto(entity.Deactivate(now));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,13 @@ public sealed class NuevaVersionTipoDeIvaCommandHandler
|
|||||||
{
|
{
|
||||||
private readonly ITipoDeIvaRepository _repo;
|
private readonly ITipoDeIvaRepository _repo;
|
||||||
private readonly IAuditLogger _audit;
|
private readonly IAuditLogger _audit;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public NuevaVersionTipoDeIvaCommandHandler(ITipoDeIvaRepository repo, IAuditLogger audit)
|
public NuevaVersionTipoDeIvaCommandHandler(ITipoDeIvaRepository repo, IAuditLogger audit, TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_audit = audit;
|
_audit = audit;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<NuevaVersionResultDto> Handle(NuevaVersionTipoDeIvaCommand command)
|
public async Task<NuevaVersionResultDto> Handle(NuevaVersionTipoDeIvaCommand command)
|
||||||
@@ -29,10 +31,13 @@ public sealed class NuevaVersionTipoDeIvaCommandHandler
|
|||||||
if (!predecesora.Activo || predecesora.VigenciaHasta is not null)
|
if (!predecesora.Activo || predecesora.VigenciaHasta is not null)
|
||||||
throw new PredecesorYaCerradoException(command.PredecesoraId);
|
throw new PredecesorYaCerradoException(command.PredecesoraId);
|
||||||
|
|
||||||
|
var now = _timeProvider.GetUtcNow().UtcDateTime;
|
||||||
|
|
||||||
// Steps 3–4: delegate validation + tuple creation to domain (throws ArgumentException on invalid vigencia)
|
// Steps 3–4: delegate validation + tuple creation to domain (throws ArgumentException on invalid vigencia)
|
||||||
var (predecesoraCerrada, nuevaVersion) = predecesora.NuevaVersion(
|
var (predecesoraCerrada, nuevaVersion) = predecesora.NuevaVersion(
|
||||||
command.NuevoPorcentaje,
|
command.NuevoPorcentaje,
|
||||||
command.VigenciaDesde);
|
command.VigenciaDesde,
|
||||||
|
now);
|
||||||
|
|
||||||
using var tx = new TransactionScope(
|
using var tx = new TransactionScope(
|
||||||
TransactionScopeOption.Required,
|
TransactionScopeOption.Required,
|
||||||
|
|||||||
@@ -11,11 +11,13 @@ public sealed class ReactivateTipoDeIvaCommandHandler : ICommandHandler<Reactiva
|
|||||||
{
|
{
|
||||||
private readonly ITipoDeIvaRepository _repo;
|
private readonly ITipoDeIvaRepository _repo;
|
||||||
private readonly IAuditLogger _audit;
|
private readonly IAuditLogger _audit;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public ReactivateTipoDeIvaCommandHandler(ITipoDeIvaRepository repo, IAuditLogger audit)
|
public ReactivateTipoDeIvaCommandHandler(ITipoDeIvaRepository repo, IAuditLogger audit, TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_audit = audit;
|
_audit = audit;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<TipoDeIvaDto> Handle(ReactivateTipoDeIvaCommand command)
|
public async Task<TipoDeIvaDto> Handle(ReactivateTipoDeIvaCommand command)
|
||||||
@@ -41,6 +43,7 @@ public sealed class ReactivateTipoDeIvaCommandHandler : ICommandHandler<Reactiva
|
|||||||
|
|
||||||
tx.Complete();
|
tx.Complete();
|
||||||
|
|
||||||
return TipoDeIvaMapper.ToDto(entity.Reactivate());
|
var now = _timeProvider.GetUtcNow().UtcDateTime;
|
||||||
|
return TipoDeIvaMapper.ToDto(entity.Reactivate(now));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,11 +11,13 @@ public sealed class UpdateTipoDeIvaCommandHandler : ICommandHandler<UpdateTipoDe
|
|||||||
{
|
{
|
||||||
private readonly ITipoDeIvaRepository _repo;
|
private readonly ITipoDeIvaRepository _repo;
|
||||||
private readonly IAuditLogger _audit;
|
private readonly IAuditLogger _audit;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public UpdateTipoDeIvaCommandHandler(ITipoDeIvaRepository repo, IAuditLogger audit)
|
public UpdateTipoDeIvaCommandHandler(ITipoDeIvaRepository repo, IAuditLogger audit, TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_audit = audit;
|
_audit = audit;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<TipoDeIvaDto> Handle(UpdateTipoDeIvaCommand command)
|
public async Task<TipoDeIvaDto> Handle(UpdateTipoDeIvaCommand command)
|
||||||
@@ -23,15 +25,16 @@ public sealed class UpdateTipoDeIvaCommandHandler : ICommandHandler<UpdateTipoDe
|
|||||||
var entity = await _repo.GetByIdAsync(command.Id)
|
var entity = await _repo.GetByIdAsync(command.Id)
|
||||||
?? throw new TipoDeIvaNotFoundException(command.Id);
|
?? throw new TipoDeIvaNotFoundException(command.Id);
|
||||||
|
|
||||||
|
var now = _timeProvider.GetUtcNow().UtcDateTime;
|
||||||
var updated = entity
|
var updated = entity
|
||||||
.WithCodigo(command.Codigo)
|
.WithCodigo(command.Codigo, now)
|
||||||
.WithDescripcion(command.Descripcion)
|
.WithDescripcion(command.Descripcion, now)
|
||||||
.WithAplicaIVA(command.AplicaIVA);
|
.WithAplicaIVA(command.AplicaIVA, now);
|
||||||
|
|
||||||
// Apply Activo change if needed
|
// Apply Activo change if needed
|
||||||
updated = command.Activo
|
updated = command.Activo
|
||||||
? updated.Reactivate()
|
? updated.Reactivate(now)
|
||||||
: updated.Deactivate();
|
: updated.Deactivate(now);
|
||||||
|
|
||||||
using var tx = new TransactionScope(
|
using var tx = new TransactionScope(
|
||||||
TransactionScopeOption.Required,
|
TransactionScopeOption.Required,
|
||||||
|
|||||||
@@ -13,15 +13,18 @@ public sealed class DeactivateUsuarioCommandHandler : ICommandHandler<Deactivate
|
|||||||
private readonly IUsuarioRepository _repository;
|
private readonly IUsuarioRepository _repository;
|
||||||
private readonly IRefreshTokenRepository _refreshTokenRepository;
|
private readonly IRefreshTokenRepository _refreshTokenRepository;
|
||||||
private readonly IAuditLogger _audit;
|
private readonly IAuditLogger _audit;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public DeactivateUsuarioCommandHandler(
|
public DeactivateUsuarioCommandHandler(
|
||||||
IUsuarioRepository repository,
|
IUsuarioRepository repository,
|
||||||
IRefreshTokenRepository refreshTokenRepository,
|
IRefreshTokenRepository refreshTokenRepository,
|
||||||
IAuditLogger audit)
|
IAuditLogger audit,
|
||||||
|
TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_repository = repository;
|
_repository = repository;
|
||||||
_refreshTokenRepository = refreshTokenRepository;
|
_refreshTokenRepository = refreshTokenRepository;
|
||||||
_audit = audit;
|
_audit = audit;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<UsuarioDetailDto> Handle(DeactivateUsuarioCommand cmd)
|
public async Task<UsuarioDetailDto> Handle(DeactivateUsuarioCommand cmd)
|
||||||
@@ -43,7 +46,7 @@ public sealed class DeactivateUsuarioCommandHandler : ICommandHandler<Deactivate
|
|||||||
throw new LastAdminLockoutException();
|
throw new LastAdminLockoutException();
|
||||||
|
|
||||||
var fields = new UpdateUsuarioFields(target.Nombre, target.Apellido, target.Email, target.Rol, false);
|
var fields = new UpdateUsuarioFields(target.Nombre, target.Apellido, target.Email, target.Rol, false);
|
||||||
var now = DateTime.UtcNow;
|
var now = _timeProvider.GetUtcNow().UtcDateTime;
|
||||||
|
|
||||||
using (var tx = new TransactionScope(
|
using (var tx = new TransactionScope(
|
||||||
TransactionScopeOption.Required,
|
TransactionScopeOption.Required,
|
||||||
|
|||||||
@@ -18,17 +18,20 @@ public sealed class UpdateUsuarioPermisosOverridesCommandHandler
|
|||||||
private readonly IRolPermisoRepository _rolPermisoRepo;
|
private readonly IRolPermisoRepository _rolPermisoRepo;
|
||||||
private readonly IPermisoRepository _permisoRepo;
|
private readonly IPermisoRepository _permisoRepo;
|
||||||
private readonly IAuditLogger _audit;
|
private readonly IAuditLogger _audit;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public UpdateUsuarioPermisosOverridesCommandHandler(
|
public UpdateUsuarioPermisosOverridesCommandHandler(
|
||||||
IUsuarioRepository usuarioRepo,
|
IUsuarioRepository usuarioRepo,
|
||||||
IRolPermisoRepository rolPermisoRepo,
|
IRolPermisoRepository rolPermisoRepo,
|
||||||
IPermisoRepository permisoRepo,
|
IPermisoRepository permisoRepo,
|
||||||
IAuditLogger audit)
|
IAuditLogger audit,
|
||||||
|
TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_usuarioRepo = usuarioRepo;
|
_usuarioRepo = usuarioRepo;
|
||||||
_rolPermisoRepo = rolPermisoRepo;
|
_rolPermisoRepo = rolPermisoRepo;
|
||||||
_permisoRepo = permisoRepo;
|
_permisoRepo = permisoRepo;
|
||||||
_audit = audit;
|
_audit = audit;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<UsuarioPermisosDto> Handle(UpdateUsuarioPermisosOverridesCommand command)
|
public async Task<UsuarioPermisosDto> Handle(UpdateUsuarioPermisosOverridesCommand command)
|
||||||
@@ -59,7 +62,8 @@ public sealed class UpdateUsuarioPermisosOverridesCommandHandler
|
|||||||
// 4. Persist — use WithPermisosJson to get updated FechaModificacion
|
// 4. Persist — use WithPermisosJson to get updated FechaModificacion
|
||||||
var newOverrides = new PermisosOverride(grant, deny);
|
var newOverrides = new PermisosOverride(grant, deny);
|
||||||
var previousOverrides = PermisosOverride.FromJson(usuario.PermisosJson);
|
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(
|
using (var tx = new TransactionScope(
|
||||||
TransactionScopeOption.Required,
|
TransactionScopeOption.Required,
|
||||||
|
|||||||
@@ -12,11 +12,16 @@ public sealed class ReactivateUsuarioCommandHandler : ICommandHandler<Reactivate
|
|||||||
{
|
{
|
||||||
private readonly IUsuarioRepository _repository;
|
private readonly IUsuarioRepository _repository;
|
||||||
private readonly IAuditLogger _audit;
|
private readonly IAuditLogger _audit;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public ReactivateUsuarioCommandHandler(IUsuarioRepository repository, IAuditLogger audit)
|
public ReactivateUsuarioCommandHandler(
|
||||||
|
IUsuarioRepository repository,
|
||||||
|
IAuditLogger audit,
|
||||||
|
TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_repository = repository;
|
_repository = repository;
|
||||||
_audit = audit;
|
_audit = audit;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<UsuarioDetailDto> Handle(ReactivateUsuarioCommand cmd)
|
public async Task<UsuarioDetailDto> Handle(ReactivateUsuarioCommand cmd)
|
||||||
@@ -34,7 +39,7 @@ public sealed class ReactivateUsuarioCommandHandler : ICommandHandler<Reactivate
|
|||||||
}
|
}
|
||||||
|
|
||||||
var fields = new UpdateUsuarioFields(target.Nombre, target.Apellido, target.Email, target.Rol, true);
|
var fields = new UpdateUsuarioFields(target.Nombre, target.Apellido, target.Email, target.Rol, true);
|
||||||
var now = DateTime.UtcNow;
|
var now = _timeProvider.GetUtcNow().UtcDateTime;
|
||||||
|
|
||||||
using (var tx = new TransactionScope(
|
using (var tx = new TransactionScope(
|
||||||
TransactionScopeOption.Required,
|
TransactionScopeOption.Required,
|
||||||
|
|||||||
@@ -14,17 +14,20 @@ public sealed class ResetUsuarioPasswordCommandHandler : ICommandHandler<ResetUs
|
|||||||
private readonly IPasswordHasher _hasher;
|
private readonly IPasswordHasher _hasher;
|
||||||
private readonly IRefreshTokenRepository _refreshTokenRepository;
|
private readonly IRefreshTokenRepository _refreshTokenRepository;
|
||||||
private readonly IAuditLogger _audit;
|
private readonly IAuditLogger _audit;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public ResetUsuarioPasswordCommandHandler(
|
public ResetUsuarioPasswordCommandHandler(
|
||||||
IUsuarioRepository repository,
|
IUsuarioRepository repository,
|
||||||
IPasswordHasher hasher,
|
IPasswordHasher hasher,
|
||||||
IRefreshTokenRepository refreshTokenRepository,
|
IRefreshTokenRepository refreshTokenRepository,
|
||||||
IAuditLogger audit)
|
IAuditLogger audit,
|
||||||
|
TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_repository = repository;
|
_repository = repository;
|
||||||
_hasher = hasher;
|
_hasher = hasher;
|
||||||
_refreshTokenRepository = refreshTokenRepository;
|
_refreshTokenRepository = refreshTokenRepository;
|
||||||
_audit = audit;
|
_audit = audit;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ResetUsuarioPasswordResponse> Handle(ResetUsuarioPasswordCommand cmd)
|
public async Task<ResetUsuarioPasswordResponse> Handle(ResetUsuarioPasswordCommand cmd)
|
||||||
@@ -45,8 +48,9 @@ public sealed class ResetUsuarioPasswordCommandHandler : ICommandHandler<ResetUs
|
|||||||
new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted },
|
new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted },
|
||||||
TransactionScopeAsyncFlowOption.Enabled);
|
TransactionScopeAsyncFlowOption.Enabled);
|
||||||
|
|
||||||
|
var now = _timeProvider.GetUtcNow().UtcDateTime;
|
||||||
await _repository.UpdatePasswordAsync(cmd.TargetId, hash, mustChangePassword: true);
|
await _repository.UpdatePasswordAsync(cmd.TargetId, hash, mustChangePassword: true);
|
||||||
await _refreshTokenRepository.RevokeAllActiveForUserAsync(cmd.TargetId, DateTime.UtcNow);
|
await _refreshTokenRepository.RevokeAllActiveForUserAsync(cmd.TargetId, now);
|
||||||
|
|
||||||
await _audit.LogAsync(
|
await _audit.LogAsync(
|
||||||
action: "usuario.password_reset",
|
action: "usuario.password_reset",
|
||||||
|
|||||||
@@ -14,17 +14,20 @@ public sealed class UpdateUsuarioCommandHandler : ICommandHandler<UpdateUsuarioC
|
|||||||
private readonly IRolRepository _rolRepository;
|
private readonly IRolRepository _rolRepository;
|
||||||
private readonly IRefreshTokenRepository _refreshTokenRepository;
|
private readonly IRefreshTokenRepository _refreshTokenRepository;
|
||||||
private readonly IAuditLogger _audit;
|
private readonly IAuditLogger _audit;
|
||||||
|
private readonly TimeProvider _timeProvider;
|
||||||
|
|
||||||
public UpdateUsuarioCommandHandler(
|
public UpdateUsuarioCommandHandler(
|
||||||
IUsuarioRepository repository,
|
IUsuarioRepository repository,
|
||||||
IRolRepository rolRepository,
|
IRolRepository rolRepository,
|
||||||
IRefreshTokenRepository refreshTokenRepository,
|
IRefreshTokenRepository refreshTokenRepository,
|
||||||
IAuditLogger audit)
|
IAuditLogger audit,
|
||||||
|
TimeProvider timeProvider)
|
||||||
{
|
{
|
||||||
_repository = repository;
|
_repository = repository;
|
||||||
_rolRepository = rolRepository;
|
_rolRepository = rolRepository;
|
||||||
_refreshTokenRepository = refreshTokenRepository;
|
_refreshTokenRepository = refreshTokenRepository;
|
||||||
_audit = audit;
|
_audit = audit;
|
||||||
|
_timeProvider = timeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<UsuarioDetailDto> Handle(UpdateUsuarioCommand cmd)
|
public async Task<UsuarioDetailDto> Handle(UpdateUsuarioCommand cmd)
|
||||||
@@ -52,7 +55,7 @@ public sealed class UpdateUsuarioCommandHandler : ICommandHandler<UpdateUsuarioC
|
|||||||
}
|
}
|
||||||
|
|
||||||
var fields = new UpdateUsuarioFields(cmd.Nombre, cmd.Apellido, cmd.Email, cmd.Rol, cmd.Activo);
|
var fields = new UpdateUsuarioFields(cmd.Nombre, cmd.Apellido, cmd.Email, cmd.Rol, cmd.Activo);
|
||||||
var now = DateTime.UtcNow;
|
var now = _timeProvider.GetUtcNow().UtcDateTime;
|
||||||
|
|
||||||
using (var tx = new TransactionScope(
|
using (var tx = new TransactionScope(
|
||||||
TransactionScopeOption.Required,
|
TransactionScopeOption.Required,
|
||||||
|
|||||||
Reference in New Issue
Block a user