using AdminDAL.CustomCode.ItemGroup; using GB5Shared.DTO.Framework.AutoNumber; using GB5Shared.DTO.Framework.Criteria; using GB5Shared.DTO.Framework.Logging; using GB5Shared.DTO.Framework.Login; using GB5Shared.GB5Exception; using GB5Shared.GenerateAutoNumber; using GB5Shared.Resource.Response; using GB5Shared.ResponseStandard; using GB5Shared.Validation; using MMBLL.Indent; using MMDAL.CustomCode.Item; using MMDAL.CustomCode.ItemGroup; using MMDAL.DTO.Indent; using MMDAL.DTO.Item; using MMDAL.DTO.ItemStock; using MMDAL.DTO.Store; using MMDAL.Query.ItemGroup; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Runtime.CompilerServices; using System.Security.AccessControl; using System.Text; using System.Threading.Tasks; namespace MMBLL.Item { public class ItemBLL : IItemBLL { private readonly AutoNumber _AutoNumber; private readonly IValidation _Validation; private IItemDAL _ItemDAL; private readonly IIndentBLL _IndentBLL; List ItemStockDTOs = new List(); IList StoreDTOs = new List(); private readonly CodeGeneration _codeGeneration; public ItemBLL(IItemDAL IItemDAL, AutoNumber AutoNumber, IValidation validation, CodeGeneration codeGeneration, IIndentBLL IndentBLL) { _ItemDAL = IItemDAL; _AutoNumber = AutoNumber; _Validation = validation; _codeGeneration=codeGeneration; _IndentBLL = IndentBLL; } public async Task GetItemMasterReport(CriteriaDTO CriteriaDTO, LoginDTO LoginDTO, int FromNumber, int ToNumber, string Orderbyfield, bool Count = false) { try { return await _ItemDAL.GetItemMasterReport(CriteriaDTO, LoginDTO, FromNumber, ToNumber, Orderbyfield, Count); } catch (Exception ex) { throw new Exception("Error in GetItemMasterReport", ex); } } public async Task GetSelectListItem(int FirstNumber, int MaxResult, CriteriaDTO criteriaDTO, LoginDTO loginDTO, bool IsCount = false) { try { return await _ItemDAL.GetSelectListItem(FirstNumber, MaxResult, criteriaDTO, loginDTO, IsCount); } catch (Exception) { throw; } } public async Task GetSelectListProductFamily(CriteriaDTO criteriaDTO, LoginDTO loginDTO) { try { return await _ItemDAL.GetSelectListProductFamily(criteriaDTO, loginDTO); } catch (Exception) { throw; } } public async Task GetItemSelectlistFromOU(int FirstNumber, int MaxResult, CriteriaDTO CriteriaDTO, LoginDTO LoginDTO, bool IsCount = false) { try { return await _ItemDAL.GetItemSelectlistFromOU(FirstNumber, MaxResult, CriteriaDTO, LoginDTO, IsCount); } catch (Exception) { throw; } } public async Task GetItemBasedOnDocument(int FirstNumber, int MaxResult, CriteriaDTO CriteriaDTO, LoginDTO LoginDTO, bool IsCount = false) { try { return await _ItemDAL.GetItemBasedOnDocument(FirstNumber, MaxResult, CriteriaDTO, LoginDTO, IsCount); } catch (Exception) { throw; } } // GB4 parity: Item.svc/DIMxxxSelectList — denormalized DIMITEMCLASS dropdown source. public async Task GetDIMItemBrandSelectList(CriteriaDTO CriteriaDTO, LoginDTO LoginDTO) { try { return await _ItemDAL.GetDIMItemBrandSelectList(CriteriaDTO, LoginDTO); } catch (Exception) { throw; } } public async Task GetDIMItemCategorySelectList(CriteriaDTO CriteriaDTO, LoginDTO LoginDTO) { try { return await _ItemDAL.GetDIMItemCategorySelectList(CriteriaDTO, LoginDTO); } catch (Exception) { throw; } } public async Task GetDIMItemGroupSelectList(CriteriaDTO CriteriaDTO, LoginDTO LoginDTO) { try { return await _ItemDAL.GetDIMItemGroupSelectList(CriteriaDTO, LoginDTO); } catch (Exception) { throw; } } public async Task GetDIMItemModelSelectList(CriteriaDTO CriteriaDTO, LoginDTO LoginDTO) { try { return await _ItemDAL.GetDIMItemModelSelectList(CriteriaDTO, LoginDTO); } catch (Exception) { throw; } } public async Task GetDIMItemSubCategorySelectList(CriteriaDTO CriteriaDTO, LoginDTO LoginDTO) { try { return await _ItemDAL.GetDIMItemSubCategorySelectList(CriteriaDTO, LoginDTO); } catch (Exception) { throw; } } // GB4 parity: PooledItemBLL.GetNestingItemRouting (Item.svc/GetItemRouting). // Thin adapter over the existing multi-level WO preview pipeline (IIndentBLL.PreviewMultiLevelWO) // instead of re-porting GetRouting/BOMIndent/BOMIndentWipWorkOrder's legacy NHibernate logic. public async Task GetItemRouting(List ListItemDTOs, LoginDTO LoginDTO, CancellationToken ct = default) { if (ListItemDTOs == null || ListItemDTOs.Count == 0) throw new ArgumentNullException(nameof(ListItemDTOs)); var results = new List(); foreach (var listItem in ListItemDTOs) { var request = new MultiLevelWORequestDTO { ItemId = listItem.ItemId, Quantity = (decimal)listItem.Quantity, GenParams = new IndentGenerationParamsDTO { OUId = LoginDTO.WorkOUId, PeriodId = LoginDTO.WorkPeriodId, BizTransactionTypeId = listItem.BiztransactionTypeId }, ConsiderStock = false, ConsiderReservation = false }; string previewJson = await _IndentBLL.PreviewMultiLevelWO(request, LoginDTO, ct).ConfigureAwait(false); var preview = JsonConvert.DeserializeObject>(previewJson) ?? new List(); results.Add(new { listItem.ItemId, listItem.ItemCode, listItem.SKUId, RoutingId = listItem.RoutingId, Routing = preview }); } return JsonConvert.SerializeObject(results); } public async Task SaveItem(ItemDTO ItemDTO, LoginDTO LoginDTO) { if (ItemDTO == null) throw new ArgumentNullException(nameof(ItemDTO)); AutoNumberDTO? autoNumberDTO = null; try { if (ItemDTO.CodeDefineGenerationType == 1) { await _Validation.NotEmpty(ItemDTO.ItemCode, nameof(ItemDTO.ItemCode)); } await _Validation.NotEmpty(ItemDTO.ItemName, nameof(ItemDTO.ItemName)); ItemDTO.ItemModifiedById = LoginDTO.UserId; ItemDTO.ItemModifiedOn = DateTime.UtcNow; ItemDTO.TenantId = LoginDTO.ClientId; ItemDTO.ItemSourceType = LoginDTO.SourceType; int initialId = ItemDTO.ItemId; int count = 1 + initialId; if (initialId == 0) { AutoNumberDTO AutoNumberDTO = await _AutoNumber.GetNumberAsync(count, "ITEM", LoginDTO); ItemDTO.ItemId = AutoNumberDTO.StartNumber; ItemDTO.ItemCreatedById = LoginDTO.UserId; ItemDTO.ItemCreatedOn = DateTime.UtcNow; ItemDTO.TenantId = LoginDTO.ClientId; ItemDTO = await _codeGeneration.AssignCode("ITEM", ItemDTO, LoginDTO); await _ItemDAL.SaveItem(ItemDTO, LoginDTO); return $"{SuccessResponse.SaveSuccessMessage} {ItemDTO.ItemCode}"; } else { await _ItemDAL.UpdateItem(ItemDTO, LoginDTO); return $"{SuccessResponse.UpdateSuccessMessage} {ItemDTO.ItemId}"; } } catch (ValidationException vex) { throw new Exception(vex.Message); } catch (Exception) { if (autoNumberDTO != null && ItemDTO.ItemId > 0) await _AutoNumber.RollbackAutoNumber("ITEM", ItemDTO.ItemId, LoginDTO); throw; } } //public async Task SaveItem(ItemDTO ItemDTO, LoginDTO LoginDTO) //{ // if (ItemDTO == null) // throw new ArgumentNullException(nameof(ItemDTO)); // AutoNumberDTO? autoNumberDTO = null; // try // { // await _Validation.NotEmpty(ItemDTO.ItemCode, nameof(ItemDTO.ItemCode)); // await _Validation.NotEmpty(ItemDTO.ItemName, nameof(ItemDTO.ItemName)); // if (ItemDTO.MaterialAccountId == -1 || ItemDTO.MaterialAccountId ==0) // { // await _Validation.NotEmpty("Material Account Cannot Passing NONE. Please Select Material Account"); // } // ItemDTO.ItemCreatedById = LoginDTO.UserId; // ItemDTO.ItemCreatedOn = DateTime.UtcNow; // int count = 1; // if (ItemDTO.ItemId== 0) // { // autoNumberDTO = await _AutoNumber.GetNumberAsync(count, "ITEM", LoginDTO); // ItemDTO.ItemId = autoNumberDTO.StartNumber; // await _ItemDAL.SaveItem(ItemDTO, LoginDTO); // return $"{SuccessResponse.SaveSuccessMessage} {ItemDTO.ItemId}"; // } // else // { // ItemDTO.ItemModifiedById = LoginDTO.UserId; // ItemDTO.ItemModifiedOn = DateTime.UtcNow; // await _ItemDAL.UpdateItem(ItemDTO, LoginDTO); // return $"{SuccessResponse.UpdateSuccessMessage} {ItemDTO.ItemId}"; // } // } // catch (ValidationException vex) // { // throw new Exception($"Validation Failed: {vex.Message}"); // } // catch (Exception ex) // { // if (autoNumberDTO != null && ItemDTO.ItemId > 0) // await _AutoNumber.RollbackAutoNumber("ITEM", ItemDTO.ItemId, LoginDTO); // throw new Exception($"An error occurred: {ex.Message}", ex); // } //} public async TaskGetItem(int ItemId, LoginDTO LoginDTO) { try { return await _ItemDAL.GetItem(ItemId, LoginDTO); } catch (Exception) { throw; } } // ── DeleteItem (GB4 migration: DELETE /mms/Item.svc/?ItemId={ItemId}) ──────────── // // GB4 source: Item.svc.cs Delete(int ItemId) → MMBLL.Item.ItemBLL.DeleteItem. // // GB4 ordered the work as: WhereUsed reference scan → CheckUserRights → cascade delete. // The reference scan is preserved here as an explicit transaction-usage count (see // ItemQB.GET_ITEM_TRANSACTION_USAGE_COUNT for why); rights checking moved out of the BLL // and onto the endpoint in GB5. // // GB4 deleted blind — no existence probe — so a bogus ItemId returned success. GB5 probes // first so the caller gets DeleteNotFoundMessage instead of a false positive, and so the // cascade is confined to the caller's tenant (MITEM is the only table in the cascade // carrying TENANTID). public async Task DeleteItem(int ItemId, LoginDTO LoginDTO, CancellationToken ct = default) { try { // GB5 primary keys come from AutoNumber and are negative (e.g. -1499989873), // so only 0 means "not supplied" — never range-check these against zero. if (ItemId == 0) throw new MethodNotAllowedException($"{nameof(ItemId)} is required."); bool Exists = await _ItemDAL.ItemExists(ItemId, LoginDTO, ct).ConfigureAwait(false); if (!Exists) throw new DataNotFoundException($"{ErrorResponse.DeleteNotFoundMessage} {ItemId}"); int UsageCount = await _ItemDAL.GetItemTransactionUsageCount(ItemId, LoginDTO, ct).ConfigureAwait(false); if (UsageCount > 0) throw new MethodNotAllowedException("Item is used in Transaction..."); // Master-side references (MPRODUCTCOST, MITEMPARTY, MBOMDETAIL, ...). Refused // here so the caller is told which table holds the item, rather than the delete // failing halfway through on a raw FK violation. var BlockingReferences = await _ItemDAL.GetItemBlockingReferences(ItemId, LoginDTO, ct).ConfigureAwait(false); if (BlockingReferences.Count > 0) throw new MethodNotAllowedException( $"Item is referenced by {string.Join(", ", BlockingReferences)} and cannot be deleted."); return await _ItemDAL.DeleteItem(ItemId, LoginDTO, ct).ConfigureAwait(false); } catch (Exception) { throw; } } public async Task> GetItemDetailsQualityParameter( int firstNumber, int maxResult, CriteriaDTO criteriaDTO, LoginDTO loginDTO, CancellationToken ct = default) { try { if (criteriaDTO?.SectionCriteriaList == null || criteriaDTO.SectionCriteriaList.Count == 0) throw new ArgumentException("At least one criteria section is required to fetch quality parameters."); return await _ItemDAL.GetItemDetailsQualityParameter(firstNumber, maxResult, criteriaDTO, loginDTO, ct); } catch (Exception) { throw; } } public async Task GetItemDetails(CriteriaDTO CriteriaDTO, LoginDTO LoginDTO, CancellationToken ct = default) { try { return await _ItemDAL.GetItemDetails(CriteriaDTO, LoginDTO, ct); } catch (Exception) { throw; } } } }