using SIGCM2.Domain.Pricing.ChargeableChars; namespace SIGCM2.Application.Abstractions.Persistence; /// /// PRC-001 — Write + query access to dbo.ChargeableCharConfig. /// Implemented by ChargeableCharConfigRepository (Dapper) in Infrastructure. /// /// InsertWithCloseAsync: invokes usp_ChargeableCharConfig_InsertWithClose which atomically /// closes any active row for (ProductTypeId, Symbol) and inserts the new row. /// /// GetActiveForProductTypeAsync: invokes usp_ChargeableCharConfig_GetActiveForProductType which /// returns both per-ProductType rows AND global (ProductTypeId IS NULL) rows for the given asOfDate. /// The Application service applies the per-ProductType > global priority rule. /// public interface IChargeableCharConfigRepository { /// /// Invokes usp_ChargeableCharConfig_InsertWithClose inside the ambient TransactionScope. /// Closes any active row matching (ProductTypeId, Symbol) and inserts a new one. /// Returns the Id of the newly inserted row. /// Throws: /// - ChargeableCharConfigForwardOnlyException on SQL THROW 50409 /// - ChargeableCharConfigInvalidException on SQL THROW 50404 (not-found guard) /// Task InsertWithCloseAsync( long? productTypeId, string symbol, string category, decimal price, DateOnly validFrom, CancellationToken ct = default); /// /// Returns all active rows whose [ValidFrom, ValidTo] window covers the given asOfDate /// for the specified ProductType, including global rows (ProductTypeId IS NULL). /// The SP returns both per-ProductType AND global rows — callers apply priority. /// Task> GetActiveForProductTypeAsync( long productTypeId, DateOnly asOfDate, CancellationToken ct = default); /// /// Returns paginated rows filtered by ProductTypeId and IsActive. /// Skip = (page - 1) * pageSize computed by the caller. /// Task> ListAsync( long? productTypeId, bool activeOnly, int skip, int take, CancellationToken ct = default); /// /// Returns total row count for the given filters (used for pagination metadata). /// Task CountAsync( long? productTypeId, bool activeOnly, CancellationToken ct = default); /// /// Returns the row with the given Id, or null if not found. /// Task GetByIdAsync( long id, CancellationToken ct = default); /// /// Deactivates the row with the given Id by setting IsActive = false and ValidTo = today. /// Idempotent: no-op if already inactive. /// Called inside the ambient TransactionScope of the handler. /// Task DeactivateAsync( long id, DateOnly today, CancellationToken ct = default); /// /// Invokes usp_ChargeableCharConfig_ReactivateWithGuard. /// Guard rules (enforced by SP): /// 50410 → target row is already active → ChargeableCharConfigReactivationNotAllowedException(ALREADY_ACTIVE) /// 50411 → a vigente active row exists for (ProductTypeId, Symbol) → ChargeableCharConfigReactivationNotAllowedException(VIGENTE_EXISTS) /// 50412 → posterior rows exist after target row → ChargeableCharConfigReactivationNotAllowedException(POSTERIOR_ROWS_EXIST) /// 50404 → row not found → ChargeableCharConfigInvalidException /// On success: re-opens the row (IsActive=true, ValidTo=NULL) and returns the reactivated entity. /// Task ReactivateAsync( long id, CancellationToken ct = default); /// /// Physically deletes the row with the given Id from dbo.ChargeableCharConfig (current state). /// NOTE: Since SYSTEM_VERSIONING is ON, SQL Server moves the row to the history table with /// SysEndTime set to the delete time. The row disappears from all current-state queries but /// remains queryable via FOR SYSTEM_TIME. Temporal audit trail is preserved. /// Future guard for "used in invoicing" is deferred to FAC-001 followup issue. /// Throws KeyNotFoundException if the row does not exist. /// Task DeleteAsync( long id, CancellationToken ct = default); }