using GB5Shared.DTO.Framework.Criteria; namespace MMDAL.DTO.MRPRun { public class WorkBenchDTO { // MRP Run header public int MrpRunId { get; set; } public int MasterScheduleId { get; set; } public string MasterScheduleCode { get; set; } = string.Empty; public string MasterScheduleName { get; set; } = string.Empty; public int MrpId { get; set; } public string MrpCode { get; set; } = string.Empty; public string MrpName { get; set; } = string.Empty; public DateTime MrpRunDate { get; set; } public byte MrpRunType { get; set; } // MRP Run Detail public int MrpRunDetailId { get; set; } public short SlNo { get; set; } public byte LowLevelCode { get; set; } public short LeadTime { get; set; } public DateTime RequiredPeriod { get; set; } // Item public int PlanItemId { get; set; } public string PlanItemCode { get; set; } = string.Empty; public string PlanItemName { get; set; } = string.Empty; public string PlanItemShortName { get; set; } = string.Empty; public byte PlanItemMakeOrBuy { get; set; } public decimal PlanItemLotSize { get; set; } = 1; // SKU public int PlanSKUId { get; set; } = -1; public string PlanSKUCode { get; set; } = string.Empty; public string PlanSKUName { get; set; } = string.Empty; // Quantities public decimal TotalGrossRequirement { get; set; } public decimal IndependentPlanDemand { get; set; } public decimal IndependentCustomerOrder { get; set; } public decimal DependentPlanDemand { get; set; } public decimal DependentCustomerOrder { get; set; } public decimal Allocation { get; set; } public decimal ScheduledReceipts { get; set; } public decimal ProjectedSOH { get; set; } public decimal SOH { get; set; } public decimal WIP { get; set; } public decimal NetRequirement { get; set; } public decimal PlannedOrderReceipts { get; set; } public decimal PlannedOrderReleases { get; set; } // MRP Action public int MrpActionId { get; set; } public int MrpActionObjectId { get; set; } = -1; public byte PlanType { get; set; } public byte PlanStatus { get; set; } // 0=Unreleased,1=ToBeReleased,2=Released,3=OnHold public decimal PlannedQuantity { get; set; } public decimal OriginalPlannedQuantity { get; set; } public decimal FirmQuantity { get; set; } public decimal InProcessQuantity { get; set; } public decimal ImplementedQuantity { get; set; } public byte PlannedAction { get; set; } public bool IsFirmPlan { get; set; } public DateTime PlannedStartDate { get; set; } public DateTime PlannedOrderDate { get; set; } public DateTime PlannedDueDate { get; set; } public DateTime FirmDate { get; set; } public short CompressionDays { get; set; } public int NestingPlanId { get; set; } = -1; public string Remarks { get; set; } = string.Empty; // Release public byte ReleaseType { get; set; } // 0=None,1=PO,2=PR,3=WorkIndent public int ReleaseBizTransactionTypeId { get; set; } = -1; public string ReleaseBizTransactionTypeCode { get; set; } = string.Empty; public string ReleaseBizTransactionTypeName { get; set; } = string.Empty; public int ReleaseId { get; set; } = -1; public byte IsAllocationBasedRelease { get; set; } // Party public int PartyId { get; set; } = -1; public string PartyCode { get; set; } = string.Empty; public string PartyName { get; set; } = string.Empty; public int PartyBranchId { get; set; } = -1; public string PartyBranchCode { get; set; } = string.Empty; public string PartyBranchName { get; set; } = string.Empty; // Store public int StoreId { get; set; } = -1; public string StoreCode { get; set; } = string.Empty; public string StoreName { get; set; } = string.Empty; // BOM / Routing public int AlternateBOMId { get; set; } = -1; public string AlternateBOMVersionName { get; set; } = string.Empty; public int AlternateRoutingId { get; set; } = -1; public string AlternateRoutingCode { get; set; } = string.Empty; public string AlternateRoutingName { get; set; } = string.Empty; // Priority + scope tracking (v3) public short Priority { get; set; } // 0=unset (lowest); 1=highest public int AllocationId { get; set; } = -1; public int SalesOrderId { get; set; } = -1; public byte RunScope { get; set; } // 0=Macro,1=Allocation,2=SalesOrder,3=FGItem // Rate / UOM enrichment (post-query, joined in by ItemId) public decimal MaterialTotalCost { get; set; } public int StockUOMId { get; set; } = -1; public string StockUOMName { get; set; } = string.Empty; public int PurchaseUOMId { get; set; } = -1; public string PurchaseUOMName { get; set; } = string.Empty; // Only populated when WorkBenchCriteriaDTO.OnlyParent is honoured public bool IsParentItem { get; set; } public int TenantId { get; set; } } public class WorkBenchCriteriaDTO { public int MrpRunId { get; set; } public int MrpId { get; set; } public DateTime FromDate { get; set; } public DateTime ToDate { get; set; } public int? AllocationId { get; set; } public int? SalesOrderId { get; set; } public int? MinPriority { get; set; } public int? MaxPriority { get; set; } public byte? PlanStatus { get; set; } public byte? ReleaseType { get; set; } public string SortBy { get; set; } = "RequiredPeriod"; public bool SortDesc { get; set; } public int PageOffset { get; set; } public int PageSize { get; set; } = 50; // Item classification / party filters (GB4 parity — see MRPRun.svc.cs GetWorkBenchDetail) public int? ItemId { get; set; } public int? CategoryId { get; set; } public int? SubCategoryId { get; set; } public int? ItemGroupId { get; set; } public int? ItemBrandId { get; set; } public int? ModelId { get; set; } public int? PartyId { get; set; } public byte? MakeOrBuy { get; set; } // 0=Make, 1=Buy — filters on MITEM.ISMAKEORBUY public byte? PlanType { get; set; } public int? FromItem { get; set; } public int? ToItem { get; set; } // GB4 parity (MRPRun.svc.cs GetWorkBenchDetail): Status=-1 broadens to the // "not yet released" bucket (PlanStatus IN 0,1,3) instead of an exact match. // Set instead of PlanStatus when that broadening applies. public byte[]? PlanStatusIn { get; set; } // Parent-item restriction (Make items only) — mirrors GB4's OnlyParent branch. // Requires MasterScheduleId since parent items are resolved from MMASTERSCHEDULEDETAIL. public bool OnlyParent { get; set; } public int? MasterScheduleId { get; set; } // Builds a WorkBenchCriteriaDTO from the generic CriteriaDTO filter payload // (GB4 parity — MRPRun.svc.cs GetWorkBenchDetail manually extracted Status, // PartyId, MrpRunId and OnlyParent out of the same CriteriaDTO shape; the // remaining fields went through its generic HQL criteria mapping). All fields // are optional except MRPRunId. public static WorkBenchCriteriaDTO FromCriteria(CriteriaDTO criteriaDTO) { var c = new WorkBenchCriteriaDTO(); var attrs = criteriaDTO?.SectionCriteriaList? .Where(s => s?.AttributesCriteriaList != null) .SelectMany(s => s.AttributesCriteriaList) ?? Enumerable.Empty(); int? mrpRunId = null; int? statusRaw = null; int? onlyParentRaw = null; foreach (var attr in attrs) { if (string.IsNullOrWhiteSpace(attr.FieldName)) continue; switch (attr.FieldName.Trim().ToLowerInvariant()) { case "mrprunid": mrpRunId = ToInt(attr.FieldValue); break; case "plantype": c.PlanType = ToByte(attr.FieldValue); break; case "status": statusRaw = ToInt(attr.FieldValue); break; case "makrorbuy": c.MakeOrBuy = ToByte(attr.FieldValue); break; case "subcategoryid": c.SubCategoryId = ToInt(attr.FieldValue); break; case "categoryid": c.CategoryId = ToInt(attr.FieldValue); break; case "partyid": c.PartyId = ToInt(attr.FieldValue); break; case "fromitem": c.FromItem = ToInt(attr.FieldValue); break; case "toitem": c.ToItem = ToInt(attr.FieldValue); break; case "periodfromdate": c.FromDate = ParseDate(attr.FieldValue); break; case "periodtodate": c.ToDate = ParseDate(attr.FieldValue); break; case "onlyparent": onlyParentRaw = ToInt(attr.FieldValue); break; case "masterscheduleid": c.MasterScheduleId = ToInt(attr.FieldValue); break; } } if (mrpRunId is null) throw new ArgumentException("MRPRunId is required."); c.MrpRunId = mrpRunId.Value; if (statusRaw.HasValue) { if (statusRaw.Value == -1) c.PlanStatusIn = new byte[] { 0, 1, 3 }; else c.PlanStatus = (byte)statusRaw.Value; } // GB4 parity: OnlyParent is 0=Yes/1=No — the framework's usual boolean sense is reversed. c.OnlyParent = onlyParentRaw.HasValue && onlyParentRaw.Value == 0; return c; } private static object? Unwrap(object? value) { if (value is not System.Text.Json.JsonElement je) return value; return je.ValueKind switch { System.Text.Json.JsonValueKind.String => je.GetString(), System.Text.Json.JsonValueKind.Number => je.TryGetInt64(out var l) ? (object)l : je.GetDouble(), System.Text.Json.JsonValueKind.True => true, System.Text.Json.JsonValueKind.False => false, System.Text.Json.JsonValueKind.Null => null, _ => je.ToString() }; } private static int? ToInt(object? raw) { var v = Unwrap(raw); return v switch { null => null, int i => i, long l => (int)l, double d => (int)d, decimal m => (int)m, _ => int.TryParse(v.ToString(), out var parsed) ? parsed : null }; } private static byte? ToByte(object? raw) { var i = ToInt(raw); return i.HasValue ? (byte)i.Value : null; } // Dates arrive as plain date strings (e.g. "2024-09-01"), not Unix epoch values. private static DateTime ParseDate(object? raw) { var v = Unwrap(raw); if (v is null) return default; if (v is DateTime dt) return dt.Date; return DateTime.TryParse( v.ToString(), System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out var parsed) ? parsed.Date : default; } } }