using System.Transactions; using SIGCM2.Application.Abstractions; using SIGCM2.Application.Abstractions.Persistence; using SIGCM2.Application.Audit; using SIGCM2.Application.Roles.Dtos; using SIGCM2.Domain.Entities; using SIGCM2.Domain.Exceptions; namespace SIGCM2.Application.Roles.Create; public sealed class CreateRolCommandHandler : ICommandHandler { private readonly IRolRepository _repository; private readonly IAuditLogger _audit; public CreateRolCommandHandler(IRolRepository repository, IAuditLogger audit) { _repository = repository; _audit = audit; } public async Task Handle(CreateRolCommand command) { // Check-then-insert: explicit check produces a clear 409 message. // SqlException 2627 (UQ violation) acts as race-condition fallback — caught in ExceptionFilter. var existing = await _repository.GetByCodigoAsync(command.Codigo); if (existing is not null) throw new RolAlreadyExistsException(command.Codigo); var rol = Rol.ForCreation(command.Codigo, command.Nombre, command.Descripcion); int newId; using (var tx = new TransactionScope( TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }, TransactionScopeAsyncFlowOption.Enabled)) { newId = await _repository.AddAsync(rol); await _audit.LogAsync( action: "rol.create", targetType: "Rol", targetId: newId.ToString(), metadata: new { after = new { rol.Codigo, rol.Nombre, rol.Descripcion } }); tx.Complete(); } return new RolCreatedDto( Id: newId, Codigo: rol.Codigo, Nombre: rol.Nombre, Descripcion: rol.Descripcion, Activo: rol.Activo); } }