using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using FrameworkDAL.DTO.RoleVsMenu; using FrameworkDAL.Query.RoleVsMenu; using GB5Shared.DTO.Framework.Login; using GB5Shared.DTO.Framework.AutoNumber; using GB5Shared.DTO.Framework.Criteria; using FrameworkDAL.CustomCode.RoleVsMenu; using System.Runtime.InteropServices; using GB5Shared.QueryExecutor; using GB5Shared.GenerateAutoNumber; using Newtonsoft.Json; using GB5Shared.Resource.Response; namespace FrameworkBLL.RoleVsMenu { /// /// RoleVsMenuBLL /// public class RoleVsMenuBLL : IRoleVsMenuBLL { private readonly IRoleVsMenuDAL _RoleVsMenuDAL; private readonly AutoNumber _autonumber; private readonly IQueryExecutor _queryExecutor; /// /// RoleVsMenuBLL /// /// /// /// public RoleVsMenuBLL(IRoleVsMenuDAL RoleVsMenuDAL , AutoNumber AutoNumber , IQueryExecutor QueryExecutor) { _RoleVsMenuDAL = RoleVsMenuDAL; _autonumber = AutoNumber; _queryExecutor = QueryExecutor; } /// /// Save /// /// /// /// /// /// /// /// Diff-based save: reconciles the incoming list against MROLEVSMENU by the /// (RoleId, MenuId) natural key — rows whose MenuId already exists in scope are /// UPDATEd in place (preserving ROLEVSMENUID/CREATEDON), rows no longer present are /// deleted, and only genuinely new (RoleId, MenuId) pairs get a freshly-issued /// ROLEVSMENUID. Replaces the previous delete-everything-then-reinsert-everything /// behavior (which also built its DELETE SQL via unparameterized string /// concatenation and ran the delete(s)/insert as separate, non-transactional calls) — /// this now runs as one parameterized transaction via ExecuteInTransactionAsync. /// public async Task Save(int ModuleId, int PageId, List RoleVsMenuDTOs, LoginDTO LoginDTO) { try { if (RoleVsMenuDTOs == null || RoleVsMenuDTOs.Count == 0) return SuccessResponse.SaveSuccessMessage; int RoleId = RoleVsMenuDTOs[0].RoleVsMenuRoleId; var incomingMenuIds = RoleVsMenuDTOs.Select(d => d.RoleVsMenuMenuId).Distinct().ToList(); List existingRows = PageId == -1 ? await _RoleVsMenuDAL.GetExistingForModule(RoleId, ModuleId, LoginDTO) : await _RoleVsMenuDAL.GetExistingForMenuIds(RoleId, incomingMenuIds, LoginDTO); var existingByMenuId = existingRows.ToDictionary(r => r.RoleVsMenuMenuId, r => r.RoleVsMenuId); var statements = new List<(string sql, object param)>(); // Rows that used to be in this scope but are no longer in the incoming list. var toDeleteIds = existingRows .Where(r => !incomingMenuIds.Contains(r.RoleVsMenuMenuId)) .Select(r => r.RoleVsMenuId) .ToList(); if (toDeleteIds.Count > 0) statements.Add((RoleVsMenuQB.DELETE_ROLEVSMENU_BY_IDS, (object)new { Ids = toDeleteIds })); int newCount = RoleVsMenuDTOs.Count(d => !existingByMenuId.ContainsKey(d.RoleVsMenuMenuId)); int nextNewId = 0; if (newCount > 0) { AutoNumberDTO autoNumberDTO = await _autonumber.GetNumberAsync(newCount, "ROLEVSMENU", LoginDTO); nextNewId = autoNumberDTO.StartNumber; } int firstNewId = nextNewId; foreach (var dto in RoleVsMenuDTOs) { dto.RoleVsMenuRoleId = RoleId; if (existingByMenuId.TryGetValue(dto.RoleVsMenuMenuId, out var existingId)) { dto.RoleVsMenuId = existingId; statements.Add((RoleVsMenuQB.UPDATE_ROLEVSMENU, (object)dto)); } else { dto.RoleVsMenuId = nextNewId++; statements.Add((RoleVsMenuQB.SAVE_ROLEVSMENU, (object)dto)); } } await _queryExecutor.ExecuteInTransactionAsync(LoginDTO, statements); int savedId = newCount > 0 ? firstNewId : (existingRows.Count > 0 ? existingRows[0].RoleVsMenuId : RoleId); return $"{SuccessResponse.SaveSuccessMessage} {savedId}"; } catch (Exception) { throw; } } /// /// GetRoleVsMenu /// /// /// /// /// public async Task GetRoleVsMenu(int RoleId, int ModuleId, LoginDTO LoginDTO) { try { string Json = ""; List RoleVsMenuDTOs = await _RoleVsMenuDAL.GetRoleVsMenu(RoleId, ModuleId, LoginDTO); if (RoleVsMenuDTOs.Count == 1) { Json =JsonConvert.SerializeObject(RoleVsMenuDTOs[0]); } else { Json = JsonConvert.SerializeObject(RoleVsMenuDTOs); } return Json; } catch (Exception) { throw; } } public async Task> GetRoleVsMenuBasedOnRoleId(int RoleId, LoginDTO LoginDTO) { try { return (await _queryExecutor.QueryAsync(LoginDTO, RoleVsMenuQB.GET_ROLE_VS_MENU_BY_ROLE_ID, new { RoleId })).ToList(); } catch (Exception) { throw; } } public async Task> GetRoleVsMenuDetail(int FirstNumber, int MaxResult, CriteriaDTO CriteriaDTO, LoginDTO LoginDTO) { try { int offset = FirstNumber == -1 ? 0 : FirstNumber; int fetch = MaxResult == -1 ? int.MaxValue : MaxResult; var filters = ExtractRoleVsMenuFilters(CriteriaDTO); return (await _queryExecutor.QueryAsync(LoginDTO, RoleVsMenuQB.GET_ROLE_VS_MENU_DETAIL, new { SearchKeyword = CriteriaDTO?.SearchKeyword, filters.MenuId, filters.RoleId, filters.ModuleId, filters.ParentMenuId, FirstNumber = offset, MaxResult = fetch })).ToList(); } catch (Exception) { throw; } } public async Task> GetRoleVsMenuReportDetail(int FirstNumber, int MaxResult, CriteriaDTO CriteriaDTO, LoginDTO LoginDTO) { try { int offset = FirstNumber == -1 ? 0 : FirstNumber; int fetch = MaxResult == -1 ? int.MaxValue : MaxResult; var filters = ExtractRoleVsMenuFilters(CriteriaDTO); return (await _queryExecutor.QueryAsync(LoginDTO, RoleVsMenuQB.GET_ROLE_VS_MENU_REPORT_DETAIL, new { SearchKeyword = CriteriaDTO?.SearchKeyword, filters.MenuId, filters.RoleId, filters.ModuleId, filters.ParentMenuId, FirstNumber = offset, MaxResult = fetch })).ToList(); } catch (Exception) { throw; } } private static (int? MenuId, int? RoleId, int? ModuleId, int? ParentMenuId) ExtractRoleVsMenuFilters(CriteriaDTO CriteriaDTO) { int? menuId = null, roleId = null, moduleId = null, parentMenuId = null; if (CriteriaDTO?.SectionCriteriaList == null) return (menuId, roleId, moduleId, parentMenuId); foreach (var section in CriteriaDTO.SectionCriteriaList) { if (section?.AttributesCriteriaList == null) continue; foreach (var attr in section.AttributesCriteriaList) { if (attr?.FieldName == null || attr.FieldValue == null) continue; if (int.TryParse(attr.FieldValue.ToString(), out int val) && val != -1) { switch (attr.FieldName.ToLower()) { case "menuid": menuId = val; break; case "roleid": roleId = val; break; case "moduleid": moduleId = val; break; case "parentmenuid": parentMenuId = val; break; } } } } return (menuId, roleId, moduleId, parentMenuId); } public async Task> GetRoleVsMenuForMenu(CriteriaDTO CriteriaDTO, LoginDTO LoginDTO) { try { int menuId = -1, moduleId = -1; if (CriteriaDTO?.SectionCriteriaList != null) { foreach (var section in CriteriaDTO.SectionCriteriaList) { if (section?.AttributesCriteriaList == null) continue; foreach (var attr in section.AttributesCriteriaList) { if (attr?.FieldName == null || attr.FieldValue == null) continue; if (int.TryParse(attr.FieldValue.ToString(), out int val)) { switch (attr.FieldName.ToLower()) { case "menuid": menuId = val; break; case "moduleid": moduleId = val; break; } } } } } return (await _queryExecutor.QueryAsync(LoginDTO, RoleVsMenuQB.GET_ROLE_VS_MENU_FOR_MENU, new { MenuId = menuId, ModuleId = moduleId })).ToList(); } catch (Exception) { throw; } } public async Task SaveOnlyRoleMenu(List RoleVsMenuDTOs, LoginDTO LoginDTO) { try { if (RoleVsMenuDTOs == null || RoleVsMenuDTOs.Count == 0) return $"{SuccessResponse.SaveSuccessMessage} 0"; AutoNumberDTO autoNumberDTO = await _autonumber.GetNumberAsync(RoleVsMenuDTOs.Count, "ROLEVSMENU", LoginDTO); int nextId = autoNumberDTO.StartNumber; var statements = new List<(string sql, object param)>(); foreach (var dto in RoleVsMenuDTOs) { dto.RoleVsMenuId = nextId++; statements.Add((RoleVsMenuQB.SAVE_ROLEVSMENU, (object)dto)); } await _queryExecutor.ExecuteInTransactionAsync(LoginDTO, statements); return $"{SuccessResponse.SaveSuccessMessage} {autoNumberDTO.StartNumber}"; } catch (Exception) { throw; } } } }