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; // Mirrors FeatureBLL's thin-CRUD pattern (AutoNumber PK, single-row transaction, GB5Trace steps, // soft-delete via STATUS=0). MENTITLEMENTFEATUREGROUP already existed as a table + DAL/QB from the // original build but had no BLL/endpoints — this closes that gap for FeatureGroup.svc. public class FeatureGroupBLL : IFeatureGroupBLL { private readonly IFeatureGroupDAL _FeatureGroupDAL; private readonly AutoNumber _AutoNumber; private readonly IQueryExecutor _QueryExecutor; public FeatureGroupBLL(IFeatureGroupDAL featureGroupDAL, AutoNumber autoNumber, IQueryExecutor queryExecutor) { _FeatureGroupDAL = featureGroupDAL; _AutoNumber = autoNumber; _QueryExecutor = queryExecutor; } public async Task GetAsync(int featureGroupId, LoginDTO login, CancellationToken ct) => await _FeatureGroupDAL.GetByIdAsync(featureGroupId, login, ct).ConfigureAwait(false); public async Task> GetListAsync(LoginDTO login, CancellationToken ct) => await _FeatureGroupDAL.GetListAsync(login, ct).ConfigureAwait(false); public async Task SaveAsync(FeatureGroupDTO dto, LoginDTO login, CancellationToken ct) { if (dto is null) throw new ArgumentNullException(nameof(dto)); if (string.IsNullOrWhiteSpace(dto.FeatureGroupCode)) throw new ArgumentException("FeatureGroupCode is required.", nameof(dto)); if (string.IsNullOrWhiteSpace(dto.FeatureGroupName)) throw new ArgumentException("FeatureGroupName is required.", nameof(dto)); bool isNew = dto.FeatureGroupId == 0; var tx = await _QueryExecutor.BeginTransactionAsync(login).ConfigureAwait(false); try { GB5Trace.Step("validate-entitlement-featuregroup", new { dto.FeatureGroupId, isNew }); var now = DateTime.UtcNow; if (isNew) { var auto = await _AutoNumber.GetNumberAsync(1, AUTONUMBERCONSTANT.ENTITLEMENTFEATUREGROUP, login).ConfigureAwait(false); dto.FeatureGroupId = auto.StartNumber; dto.CreatedById = login.UserId; dto.CreatedOn = now; } dto.ModifiedById = login.UserId; dto.ModifiedOn = now; GB5Trace.Step("save-entitlement-featuregroup", new { dto.FeatureGroupId, isNew }); if (isNew) await _FeatureGroupDAL.SaveAsync(dto, login, tx, ct).ConfigureAwait(false); else await _FeatureGroupDAL.UpdateAsync(dto, login, tx, ct).ConfigureAwait(false); GB5Trace.Step("event-publish", new { EventTypeId = isNew ? EventTypeConstant.SAVEENTITLEMENTFEATUREGROUPEVENTTYPEID : EventTypeConstant.UPDATEENTITLEMENTFEATUREGROUPEVENTTYPEID }); await _QueryExecutor.CommitAsync(tx).ConfigureAwait(false); return isNew ? $"{SuccessResponse.SaveSuccessMessage} {dto.FeatureGroupId}" : SuccessResponse.UpdateSuccess; } catch (Exception ex) { await _QueryExecutor.RollbackAsync(tx).ConfigureAwait(false); GB5Trace.MarkFailed("save-entitlement-featuregroup-failed", ex); throw; } } public async Task DeleteAsync(int featureGroupId, LoginDTO login, CancellationToken ct) { var tx = await _QueryExecutor.BeginTransactionAsync(login).ConfigureAwait(false); try { GB5Trace.Step("delete-entitlement-featuregroup", new { featureGroupId }); await _FeatureGroupDAL.DeleteAsync(featureGroupId, login, tx, ct).ConfigureAwait(false); GB5Trace.Step("event-publish", new { EventTypeId = EventTypeConstant.DELETEENTITLEMENTFEATUREGROUPEVENTTYPEID }); await _QueryExecutor.CommitAsync(tx).ConfigureAwait(false); return SuccessResponse.DeleteSuccessMessage; } catch (Exception ex) { await _QueryExecutor.RollbackAsync(tx).ConfigureAwait(false); GB5Trace.MarkFailed("delete-entitlement-featuregroup-failed", ex); throw; } } }