using System.Transactions; using SIGCM2.Application.Abstractions; using SIGCM2.Application.Abstractions.Persistence; using SIGCM2.Application.Audit; using SIGCM2.Application.Common; namespace SIGCM2.Application.Pricing.ChargeableChars.Delete; /// /// PRC-001 — Handler for DeleteChargeableCharConfigCommand. /// Flow: load existing → open TX → DeleteAsync → audit → tx.Complete(). /// /// NOTE on SYSTEM_VERSIONING: SQL Server moves the deleted row to the _History table with /// SysEndTime = deletion timestamp. This means: /// - Current-state queries (no FOR SYSTEM_TIME) return nothing — effectively "deleted". /// - Historical queries (FOR SYSTEM_TIME ALL / AS OF) still return the row — temporal audit intact. /// This is intentional. A "physical delete" (bypass SYSTEM_VERSIONING) is not supported here. /// /// Future FAC-001 will add a guard to block delete if the row was used in invoicing. /// public sealed class DeleteChargeableCharConfigCommandHandler : ICommandHandler { private readonly IChargeableCharConfigRepository _repo; private readonly IAuditLogger _audit; private readonly TimeProvider _timeProvider; public DeleteChargeableCharConfigCommandHandler( IChargeableCharConfigRepository repo, IAuditLogger audit, TimeProvider timeProvider) { _repo = repo; _audit = audit; _timeProvider = timeProvider; } public async Task Handle( DeleteChargeableCharConfigCommand command) { // 1. Load existing — ensures the row exists before opening TX. var existing = await _repo.GetByIdAsync(command.Id) ?? throw new KeyNotFoundException($"ChargeableCharConfig con Id={command.Id} no existe."); // 2. TX + delete + audit (fail-closed). using (var tx = new TransactionScope( TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted }, TransactionScopeAsyncFlowOption.Enabled)) { await _repo.DeleteAsync(command.Id); await _audit.LogAsync( action: "tasacion.chargeable_char.delete", targetType: "ChargeableCharConfig", targetId: command.Id.ToString(), metadata: new { before = new { id = existing.Id, symbol = existing.Symbol, productTypeId = existing.ProductTypeId, isActive = existing.IsActive, validFrom = existing.ValidFrom.ToString("yyyy-MM-dd"), }, deletedOn = _timeProvider.GetArgentinaToday().ToString("yyyy-MM-dd"), }); tx.Complete(); } return new DeleteChargeableCharConfigResponse(Id: command.Id); } }