using GB5Shared.DaprCache; using GB5Shared.DTO.Framework.Login; using GB5Shared.EventLogPublish; using GB5Shared.GB5Constant; using GB5Shared.GenerateAutoNumber; using GB5Shared.Resource.Response; using GoodBooks.PAY.PAYDAL.CustomCode.Checkout; using GoodBooks.PAY.PAYDAL.DTO.Gateway; using Microsoft.Extensions.Logging; using static GB5Shared.GB5Constant.Constant; namespace GoodBooks.PAY.PAYBLL.Checkout { // ───────────────────────────────────────────────────────────────────────── // CheckoutConfigBLL // // One active checkout config per tenant. Cache at CLIENT_LEVEL. // No delete — config is updated in place; deactivate via Status=0. // EntityConstant.OBJECTPAYCHECKOUTCONFIG = -1382000003 // ───────────────────────────────────────────────────────────────────────── public class CheckoutConfigBLL : ICheckoutConfigBLL { private readonly ICheckoutConfigDAL _dal; private readonly AutoNumber _autoNumber; private readonly KeyInvalidate _keyInvalidate; private readonly EventLogPublish _eventLogPublish; private readonly ILogger _logger; public CheckoutConfigBLL( ICheckoutConfigDAL dal, AutoNumber autoNumber, KeyInvalidate keyInvalidate, EventLogPublish eventLogPublish, ILogger logger) { _dal = dal; _autoNumber = autoNumber; _keyInvalidate = keyInvalidate; _eventLogPublish = eventLogPublish; _logger = logger; } // ── Get single ─────────────────────────────────────────────────────── public async Task GetCheckoutConfig(int checkoutConfigId, LoginDTO login, CancellationToken ct) { try { return await _dal.GetCheckoutConfig(checkoutConfigId, login).ConfigureAwait(false); } catch (Exception ex) { _logger.LogError(ex, "GetCheckoutConfig failed for CheckoutConfigId {CheckoutConfigId}", checkoutConfigId); throw; } } // ── Get tenant-active config ────────────────────────────────────────── public async Task GetCheckoutConfigForTenant(LoginDTO login, CancellationToken ct) { try { return await _dal.GetCheckoutConfigForTenant(login).ConfigureAwait(false); } catch (Exception ex) { _logger.LogError(ex, "GetCheckoutConfigForTenant failed for TenantId {TenantId}", login.ClientId); throw; } } // ── Save (insert or update) ─────────────────────────────────────────── public async Task SaveCheckoutConfig(CheckoutConfigDTO dto, LoginDTO login, CancellationToken ct) { if (dto is null) throw new ArgumentNullException(nameof(dto)); try { bool isNew = dto.CheckoutConfigId == 0; if (isNew) { var autoNum = await _autoNumber.GetAutoNumber(1, "PAYCHECKOUTCONFIG", login) .ConfigureAwait(false); dto.CheckoutConfigId = autoNum.StartNumber; dto.CreatedById = login.UserId; dto.CreatedOn = DateTime.UtcNow; } dto.ModifiedById = login.UserId; dto.ModifiedOn = DateTime.UtcNow; if (isNew) await _dal.SaveCheckoutConfig(dto, login).ConfigureAwait(false); else await _dal.UpdateCheckoutConfig(dto, login).ConfigureAwait(false); // Invalidate tenant-level cache var cacheKey = new CacheKeyGeneration().KeyGeneration( dto.CheckoutConfigId.ToString(), EntityConstant.OBJECTPAYCHECKOUTCONFIG, CacheKeyLevel.CLIENT_LEVEL, login); await _keyInvalidate.AllInvalidateCache(cacheKey).ConfigureAwait(false); // Also invalidate the tenant-wide "active config" lookup used by the runtime Checkout screen var tenantCacheKey = new CacheKeyGeneration().KeyGeneration( "ForTenant", EntityConstant.OBJECTPAYCHECKOUTCONFIG, CacheKeyLevel.CLIENT_LEVEL, login); await _keyInvalidate.AllInvalidateCache(tenantCacheKey).ConfigureAwait(false); try { await _eventLogPublish.PublishEventLogAsync( isNew ? "Checkout Config Created" : "Checkout Config Updated", new { dto.CheckoutConfigId }, Constant.EventTypeConstant.SAVECHECKOUTCONFIGENTTYPEID, 0, login).ConfigureAwait(false); } catch (Exception ex) { _logger.LogWarning(ex, "Event log publish failed for CheckoutConfig {CheckoutConfigId}", dto.CheckoutConfigId); } return isNew ? $"{SuccessResponse.SaveSuccessMessage} {dto.CheckoutConfigId}" : $"{SuccessResponse.UpdateSuccessMessage} {dto.CheckoutConfigId}"; } catch (Exception ex) { _logger.LogError(ex, "SaveCheckoutConfig failed for TenantId {TenantId}", login.ClientId); throw; } } } }