using EntitlementBLL.Interfaces; using EntitlementDAL.DTOs; using EntitlementDAL.Interfaces; using GB5Shared.DTO.Framework.Login; using GB5Shared.GenerateAutoNumber; using GB5Shared.QueryExecutor; using GB5Shared.Resource.Response; using GB5Shared.Telemetry; using static GB5Shared.GB5Constant.Constant; namespace EntitlementBLL.Implementations; // MenuSetMap.svc BLL — thin CRUD over MENTITLEMENTFEATUREMENUSETMAP. Save upserts on the natural // key (FeatureId, MenuSetId) so a repeated map is an update, not a UX-violating duplicate insert. public class MenuSetMapBLL : IMenuSetMapBLL { private readonly IMenuSetMapDAL _MenuSetMapDAL; private readonly AutoNumber _AutoNumber; private readonly IQueryExecutor _QueryExecutor; public MenuSetMapBLL(IMenuSetMapDAL menuSetMapDAL, AutoNumber autoNumber, IQueryExecutor queryExecutor) { _MenuSetMapDAL = menuSetMapDAL; _AutoNumber = autoNumber; _QueryExecutor = queryExecutor; } public async Task> GetListAsync(LoginDTO login, CancellationToken ct) => await _MenuSetMapDAL.GetListAsync(login, ct).ConfigureAwait(false); public async Task SaveAsync(FeatureMenuSetMapDTO dto, LoginDTO login, CancellationToken ct) { if (dto is null) throw new ArgumentNullException(nameof(dto)); if (dto.FeatureId <= 0) throw new ArgumentException("FeatureId is required.", nameof(dto)); if (dto.MenuSetId <= 0) throw new ArgumentException("MenuSetId is required.", nameof(dto)); var tx = await _QueryExecutor.BeginTransactionAsync(login).ConfigureAwait(false); try { GB5Trace.Step("validate-entitlement-menusetmap", new { dto.FeatureId, dto.MenuSetId }); var existing = dto.FeatureMenuSetMapId != 0 ? await _MenuSetMapDAL.GetByIdAsync(dto.FeatureMenuSetMapId, login, ct).ConfigureAwait(false) : await _MenuSetMapDAL.GetByFeatureAndMenuSetAsync(dto.FeatureId, dto.MenuSetId, login, ct).ConfigureAwait(false); bool isNew = existing is null; GB5Trace.Step("save-entitlement-menusetmap", new { dto.FeatureId, dto.MenuSetId, isNew }); if (isNew) { var auto = await _AutoNumber.GetNumberAsync(1, AUTONUMBERCONSTANT.ENTITLEMENTFEATUREMENUSETMAP, login).ConfigureAwait(false); dto.FeatureMenuSetMapId = auto.StartNumber; await _MenuSetMapDAL.SaveAsync(dto, login, tx, ct).ConfigureAwait(false); } else { dto.FeatureMenuSetMapId = existing!.FeatureMenuSetMapId; await _MenuSetMapDAL.UpdateAsync(dto, login, tx, ct).ConfigureAwait(false); } GB5Trace.Step("event-publish", new { EventTypeId = EventTypeConstant.SAVEENTITLEMENTMENUSETMAPEVENTTYPEID }); await _QueryExecutor.CommitAsync(tx).ConfigureAwait(false); return isNew ? $"{SuccessResponse.SaveSuccessMessage} {dto.FeatureMenuSetMapId}" : SuccessResponse.UpdateSuccess; } catch (Exception ex) { await _QueryExecutor.RollbackAsync(tx).ConfigureAwait(false); GB5Trace.MarkFailed("save-entitlement-menusetmap-failed", ex); throw; } } public async Task DeleteAsync(int featureMenuSetMapId, LoginDTO login, CancellationToken ct) { var tx = await _QueryExecutor.BeginTransactionAsync(login).ConfigureAwait(false); try { GB5Trace.Step("delete-entitlement-menusetmap", new { featureMenuSetMapId }); await _MenuSetMapDAL.DeleteAsync(featureMenuSetMapId, login, tx, ct).ConfigureAwait(false); GB5Trace.Step("event-publish", new { EventTypeId = EventTypeConstant.DELETEENTITLEMENTMENUSETMAPEVENTTYPEID }); await _QueryExecutor.CommitAsync(tx).ConfigureAwait(false); return SuccessResponse.DeleteSuccessMessage; } catch (Exception ex) { await _QueryExecutor.RollbackAsync(tx).ConfigureAwait(false); GB5Trace.MarkFailed("delete-entitlement-menusetmap-failed", ex); throw; } } }