using System.Data.Common; using GB5Shared.DTO.Framework.Login; using GB5Shared.QueryExecutor; using GoodBooks.PAY.PAYDAL.DTO.Loyalty; using GoodBooks.PAY.PAYDAL.Query.Loyalty; using Newtonsoft.Json; namespace GoodBooks.PAY.PAYDAL.CustomCode.Loyalty { /// /// APPEND-ONLY DAL for TLOYALTYLEDGER. /// No UPDATE or DELETE methods. To reverse points, the BLL inserts a /// compensating negative-points row. This contract is enforced by the /// interface definition and the QB file (which contains no UPDATE constants). /// public class LoyaltyLedgerDAL : ILoyaltyLedgerDAL { private readonly IQueryExecutor _queryExecutor; public LoyaltyLedgerDAL(IQueryExecutor queryExecutor) { _queryExecutor = queryExecutor; } // ── Insert ledger entry ─────────────────────────────────────────────── public async Task InsertLedgerEntry(LoyaltyLedgerDTO dto, LoginDTO login, DbTransaction? tx) { try { int rows = await _queryExecutor.ExecuteAsync( login, LoyaltyLedgerQB.INSERT_LEDGER_ENTRY, dto, tx).ConfigureAwait(false); return rows; } catch (Exception) { throw; } } // ── Live balance (never cached) ─────────────────────────────────────── public async Task GetAvailablePoints(int enrollmentId, LoginDTO login) { try { decimal points = await _queryExecutor.ExecuteScalarAsync( login, LoyaltyLedgerQB.GET_AVAILABLE_POINTS, new { EnrollmentId = enrollmentId, TenantId = login.ClientId }).ConfigureAwait(false); return points; } catch (Exception) { throw; } } // ── Paged ledger history ────────────────────────────────────────────── public async Task GetLoyaltyLedger(int enrollmentId, int pageOffset, int pageSize, LoginDTO login) { try { var param = new { EnrollmentId = enrollmentId, TenantId = login.ClientId, Offset = pageOffset, PageSize = pageSize }; var result = await _queryExecutor.QueryPagedAsync( login, LoyaltyLedgerQB.GET_LEDGER_PAGED, param).ConfigureAwait(false); return JsonConvert.SerializeObject(result); } catch (Exception) { throw; } } // ── Expiry job — points expiring today ─────────────────────────────── public async Task> GetExpiringPoints(LoginDTO login) { try { var rows = await _queryExecutor.QueryAsync( login, LoyaltyLedgerQB.GET_EXPIRING_POINTS, new { TenantId = login.ClientId }).ConfigureAwait(false); return rows.Select(r => (r.EnrollmentId, r.PointsExpiring)); } catch (Exception) { throw; } } // Internal projection type for the expiry query private sealed class ExpiringPointsRow { public int EnrollmentId { get; set; } public decimal PointsExpiring { get; set; } } } }