using EnablementDAL.DTO; using EnablementDAL.Query.Show; using GB5Shared.DTO.Framework.Login; using GB5Shared.QueryExecutor; using GB5Shared.Validation; using GB5Shared.Resource.Response; namespace EnablementDAL.CustomCode.Show { // Moved from GB5Framework/FrameworkDAL/CustomCode/TourShow/TourShowDAL.cs — logic unchanged. public class ShowDAL : IShowDAL { private readonly IQueryExecutor _QueryExecutor; private readonly IValidation _Validation; public ShowDAL(IQueryExecutor QueryExecutor, IValidation IValidation) { _QueryExecutor = QueryExecutor; _Validation = IValidation; } /// /// Get Show with nested steps and step details /// public async Task> GetShow(LoginDTO loginDTO, string sql, object parameters) { var showDict = new Dictionary(); var result = await _QueryExecutor.QueryMultiMapAsync( loginDTO, sql, (show, step, detail) => { // Parent if (!showDict.TryGetValue(show.ShowId, out var currentShow)) { currentShow = show; currentShow.ShowStepArray = new List(); showDict.Add(currentShow.ShowId, currentShow); } // Child if (step != null) { var currentStep = currentShow.ShowStepArray .FirstOrDefault(s => s.ShowStepId == step.ShowStepId); if (currentStep == null) { currentStep = step; currentStep.ShowStepDetailArray = new List(); currentShow.ShowStepArray.Add(currentStep); } // Subchild if (detail != null && !currentStep.ShowStepDetailArray.Any(d => d.ShowStepDetailId == detail.ShowStepDetailId)) { currentStep.ShowStepDetailArray.Add(detail); } ; } return currentShow; }, parameters, splitOn: "ShowStepId,ShowStepDetailId" ); return showDict.Values.ToList(); } /// /// Get Select List of Shows with nested steps and step details /// public async Task> GetSelectListShow(GB5Shared.DTO.Framework.Criteria.CriteriaDTO criteriaDTO, LoginDTO loginDTO) { var showDict = new Dictionary(); var result = await _QueryExecutor.QueryMultiMapAsync( loginDTO, ShowQB.GET_SELECTLIST_SHOW, (show, step, detail) => { if (!showDict.TryGetValue(show.ShowId, out var currentShow)) { currentShow = show; currentShow.ShowStepArray = new List(); showDict.Add(currentShow.ShowId, currentShow); } if (step != null) { var currentStep = currentShow.ShowStepArray .FirstOrDefault(s => s.ShowStepId == step.ShowStepId); if (currentStep == null) { currentStep = step; currentStep.ShowStepDetailArray = new List(); currentShow.ShowStepArray.Add(currentStep); } if (detail != null && !currentStep.ShowStepDetailArray.Any(d => d.ShowStepDetailId == detail.ShowStepDetailId)) { currentStep.ShowStepDetailArray.Add(detail); } } return currentShow; }, null, splitOn: "ShowStepId,ShowStepDetailId" ); return showDict.Values.ToList(); } /// /// Save Show along with its related entities /// public async Task SaveCompleteShow(TShowDTO showDTO, LoginDTO loginDTO) { // -1 (this DTO's "not applicable" sentinel, matching the FE form's own convention) // must become a real NULL — CMSCHANNELID is a nullable FK, not a -1-sentinel column. if (showDTO.CmsChannelId is -1) showDTO.CmsChannelId = null; var trans = await _QueryExecutor.BeginTransactionAsync(loginDTO); try { // INSERT TSHOW showDTO.ShowId = await _QueryExecutor.QuerySingleAsync(loginDTO, ShowQB.SAVE_SHOW, showDTO, trans); if (showDTO.ShowId <= 0) throw new Exception("TSHOW insert failed."); // INSERT TSHOWSTEP foreach (var step in showDTO.ShowStepArray) { step.ShowId = showDTO.ShowId; step.ShowStepId = await _QueryExecutor.QuerySingleAsync(loginDTO, ShowQB.SAVE_SHOWSTEP, step, trans); if (step.ShowStepId <= 0) throw new Exception("TSHOWSTEP insert failed."); // INSERT TSHOWSTEPDETAIL foreach (var detail in step.ShowStepDetailArray) { detail.ShowStepId = step.ShowStepId; detail.ShowStepDetailId = await _QueryExecutor.QuerySingleAsync(loginDTO, ShowQB.SAVE_SHOWSTEPDETAIL, detail, trans); if (detail.ShowStepDetailId <= 0) throw new Exception("TSHOWSTEPDETAIL insert failed."); } } await _QueryExecutor.CommitAsync(trans); return showDTO.ShowId; } catch { await _QueryExecutor.RollbackAsync(trans); throw; } } /// /// Update Show along with its related entities /// public async Task UpdateCompleteShow(TShowDTO showDTO, LoginDTO loginDTO) { if (showDTO.CmsChannelId is -1) showDTO.CmsChannelId = null; var trans = await _QueryExecutor.BeginTransactionAsync(loginDTO); try { await _QueryExecutor.ExecuteAsync( loginDTO, ShowQB.UPDATE_SHOW, showDTO, trans); await _QueryExecutor.ExecuteAsync( loginDTO, ShowQB.DELETE_SHOWSTEPDETAIL, new { ShowId = showDTO.ShowId }, trans); await _QueryExecutor.ExecuteAsync( loginDTO, ShowQB.DELETE_SHOWSTEP, new { ShowId = showDTO.ShowId }, trans); foreach (var step in showDTO.ShowStepArray) { step.ShowId = showDTO.ShowId; step.ShowStepId = await _QueryExecutor.QuerySingleAsync( loginDTO, ShowQB.SAVE_SHOWSTEP, step, trans); foreach (var detail in step.ShowStepDetailArray) { detail.ShowStepId = step.ShowStepId; await _QueryExecutor.QuerySingleAsync( loginDTO, ShowQB.SAVE_SHOWSTEPDETAIL, detail, trans); } } await _QueryExecutor.CommitAsync(trans); } catch { await _QueryExecutor.RollbackAsync(trans); throw; } } /// /// Count of TSHOWRUN rows currently InProgress (RUNSTATE = 0) for this show — /// used to block deletion while a user is mid-flow. /// public async Task GetActiveRunCountForShow(int showId, LoginDTO loginDTO) => await _QueryExecutor.ExecuteScalarAsync( loginDTO, ShowQB.CHECK_ACTIVE_RUNS_FOR_SHOW, new { ShowId = showId }); /// /// Soft delete — sets STATUS = 0 rather than a hard DELETE, since TSHOW is /// referenced by non-cascading FKs from other Enablement tables. /// public async Task SoftDeleteShow(int showId, LoginDTO loginDTO) { try { return await _QueryExecutor.ExecuteAsync( loginDTO, ShowQB.SOFT_DELETE_SHOW, new { ShowId = showId, ModifiedById = loginDTO.UserId, ModifiedOn = DateTime.UtcNow }); } catch (Exception ex) { string error = await _Validation.HandleException(ex, $"{ErrorResponse.DeleteErrorMessage}"); throw new Exception(error); } } /// /// Aggregated dropdown data for the Show authoring form. Space/Channel are /// same-project tables; ContentCategory/Module are owned by other modules /// (CMS/Framework) — queried here by raw SQL only, no cross-project type /// dependency. /// public async Task GetShowPicklist(LoginDTO loginDTO) { var tenantParam = new { TenantId = loginDTO.ClientId }; var modules = await _QueryExecutor.QueryAsync( loginDTO, ShowQB.GET_MODULE_PICKLIST); var spaces = await _QueryExecutor.QueryAsync( loginDTO, ShowQB.GET_SPACE_PICKLIST, tenantParam); var channels = await _QueryExecutor.QueryAsync( loginDTO, ShowQB.GET_CHANNEL_PICKLIST, tenantParam); var contentCategories = await _QueryExecutor.QueryAsync( loginDTO, ShowQB.GET_CONTENTCATEGORY_PICKLIST, tenantParam); var userGroups = await _QueryExecutor.QueryAsync( loginDTO, ShowQB.GET_USERGROUP_PICKLIST); var picklist = new TShowPicklistDTO { Modules = modules.ToList(), Spaces = spaces.ToList(), Channels = channels.ToList(), ContentCategories = contentCategories.ToList(), UserGroups = userGroups.ToList() }; return picklist; } } }