using GB5Shared.DaprCache; using GB5Shared.DTO.Framework.Login; using GB5Shared.GenerateAutoNumber; using GB5Shared.QueryExecutor; using GB5Shared.Resource.Response; using IDMSDAL.DTOs; using IDMSDAL.Interfaces; using IDMSBLL.Interfaces; using static GB5Shared.GB5Constant.Constant; using GB5Shared.EntityHandler; namespace IDMSBLL.Implementations; public class DomainItemBLL : IDomainItemBLL { private readonly IDomainItemDAL _DomainItemDAL; private readonly AutoNumber _AutoNumber; private readonly IQueryExecutor _QueryExecutor; private readonly KeyInvalidate _KeyInvalidate; private readonly BaseEntityAppService _BaseEntityAppService; public DomainItemBLL( IDomainItemDAL domainItemDAL, AutoNumber autoNumber, IQueryExecutor queryExecutor, KeyInvalidate keyInvalidate, BaseEntityAppService baseEntityAppService) { _DomainItemDAL = domainItemDAL; _AutoNumber = autoNumber; _QueryExecutor = queryExecutor; _KeyInvalidate = keyInvalidate; _BaseEntityAppService = baseEntityAppService; } // ── Reads ───────────────────────────────────────────────────────────────── public async Task GetDeliveryItemAsync( int deliveryItemId, LoginDTO login, CancellationToken ct) { return await _DomainItemDAL.GetDeliveryItemAsync(deliveryItemId, login, ct) .ConfigureAwait(false); } public async Task> GetDeliveryItemsByDomainAsync( int engagementId, string domainCode, LoginDTO login, CancellationToken ct) { return await _DomainItemDAL.GetDeliveryItemsByDomainAsync(engagementId, domainCode, login, ct) .ConfigureAwait(false); } public async Task> GetDomainProgressAsync( int engagementId, LoginDTO login, CancellationToken ct) { return await _DomainItemDAL.GetDomainProgressAsync(engagementId, login, ct) .ConfigureAwait(false); } // ── Writes ──────────────────────────────────────────────────────────────── public async Task SaveDeliveryItemAsync( DeliveryItemDTO dto, LoginDTO login, CancellationToken ct) { if (dto is null) throw new ArgumentNullException(nameof(dto)); if (string.IsNullOrWhiteSpace(dto.ItemName)) throw new ArgumentException("ItemName is required.", nameof(dto)); if (string.IsNullOrWhiteSpace(dto.DomainCode)) throw new ArgumentException("DomainCode is required.", nameof(dto)); bool isNew = dto.DeliveryItemId == 0; if (!isNew && dto.IsImmutable) throw new InvalidOperationException("This delivery item is signed off and cannot be modified."); if (isNew) { var auto = await _AutoNumber.GetNumberAsync(1, AUTONUMBERCONSTANT.IDMSDELIVERYITEM, login) .ConfigureAwait(false); dto.DeliveryItemId = auto.StartNumber; } var Trans = await _QueryExecutor.BeginTransactionAsync(login).ConfigureAwait(false); try { await _BaseEntityAppService.ExecuteSaveAsync( EntityConstant.OBJECTIDMSDELIVERYITEM, isNew ? EventTypeConstant.SAVEIDMSDELIVERYITEMEVENTTYPEID : EventTypeConstant.UPDATEIDMSDELIVERYITEMEVENTTYPEID, dto, login, async tx => { if (isNew) await _DomainItemDAL.SaveDeliveryItemAsync(dto, login, tx, ct).ConfigureAwait(false); else await _DomainItemDAL.UpdateDeliveryItemAsync(dto, login, tx, ct).ConfigureAwait(false); return dto.DeliveryItemId; }, new Dictionary { { "EngagementId", dto.EngagementId } }, BIZTRANSACTIONCLASSCONSTANT.IDMSDELIVERYITEM, BizTransactionConstant.IDMSDELIVERYITEM, Trans).ConfigureAwait(false); await _QueryExecutor.CommitAsync(Trans).ConfigureAwait(false); var cacheKey = new CacheKeyGeneration().KeyGeneration( dto.EngagementId, EntityConstant.OBJECTIDMSDELIVERYITEM, CacheKeyLevel.CLIENT_LEVEL, login); await _KeyInvalidate.AllInvalidateCache(cacheKey).ConfigureAwait(false); return isNew ? SuccessResponse.SaveSuccess : SuccessResponse.UpdateSuccess; } catch (Exception) { await _QueryExecutor.RollbackAsync(Trans).ConfigureAwait(false); throw; } } public async Task CompleteDeliveryItemAsync( int deliveryItemId, int completedById, decimal? actualHours, DateTime? completedOn, LoginDTO login, CancellationToken ct) { var item = await _DomainItemDAL.GetDeliveryItemAsync(deliveryItemId, login, ct) .ConfigureAwait(false) ?? throw new InvalidOperationException($"Delivery item {deliveryItemId} not found."); if (item.IsImmutable) throw new InvalidOperationException("This delivery item is signed off and cannot be modified."); if (item.Status == 3) throw new InvalidOperationException("Delivery item is already completed."); var Trans = await _QueryExecutor.BeginTransactionAsync(login).ConfigureAwait(false); try { await _BaseEntityAppService.ExecuteSaveAsync( EntityConstant.OBJECTIDMSDELIVERYITEM, EventTypeConstant.COMPLETEIDMSDELIVERYITEMEVENTTYPEID, item, login, async tx => { await _DomainItemDAL.CompleteDeliveryItemAsync( deliveryItemId, completedById, actualHours, completedOn, login, tx, ct) .ConfigureAwait(false); return deliveryItemId; }, new Dictionary { { "EngagementId", item.EngagementId } }, BIZTRANSACTIONCLASSCONSTANT.IDMSDELIVERYITEM, BizTransactionConstant.IDMSDELIVERYITEM, Trans).ConfigureAwait(false); await _QueryExecutor.CommitAsync(Trans).ConfigureAwait(false); var cacheKey = new CacheKeyGeneration().KeyGeneration( item.EngagementId, EntityConstant.OBJECTIDMSDELIVERYITEM, CacheKeyLevel.CLIENT_LEVEL, login); await _KeyInvalidate.AllInvalidateCache(cacheKey).ConfigureAwait(false); return SuccessResponse.UpdateSuccess; } catch (Exception) { await _QueryExecutor.RollbackAsync(Trans).ConfigureAwait(false); throw; } } }