InventoryGuardModels.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. namespace Admin.NET.Plugin.AiDOP.MaterialWarehouse.InventoryPosting.Inventory;
  2. /// <summary>C5 前置守卫代码(LIVE pr_SFM_InventoryTransactionProcessing2 实核 9 道)。</summary>
  3. public enum InventoryGuardCode
  4. {
  5. /// <summary>G1 进销存数据重复(基础数据 fan-out)。</summary>
  6. DuplicateBaseData = 1,
  7. /// <summary>G2 物料无基础资料(ItemMaster)。</summary>
  8. ItemMasterMissing = 2,
  9. /// <summary>G3 库位未维护(LocationMaster)。</summary>
  10. LocationMasterMissing = 3,
  11. /// <summary>G4 物料_库位无库存(InvMaster)——净出库前置。</summary>
  12. InvMasterMissing = 4,
  13. /// <summary>G5 物料_库位[_批次]无库存(LocationDetail)——净出库前置。</summary>
  14. LocationDetailMissing = 5,
  15. /// <summary>G6 解冻数 &gt; 冻结库存(inv-unfrz)。</summary>
  16. UnfreezeExceedsFreeze = 6,
  17. /// <summary>G7 冻结数 &gt; 非限制库存(inv-frz)。</summary>
  18. FreezeExceedsAvail = 7,
  19. /// <summary>G8 质检过账数 &gt; 质检库存(iss-tr-ins)——旧总结遗漏。</summary>
  20. AssayIssueExceedsAssay = 8,
  21. /// <summary>G9 出库数 &gt; 非限制库存(其它 TransType)。</summary>
  22. IssueExceedsAvail = 9,
  23. }
  24. /// <summary>单条守卫错误(结构化,非仅中文串;保留 LIVE ReturnMsg 语义供对账)。</summary>
  25. public sealed class InventoryGuardError
  26. {
  27. public InventoryGuardCode Code { get; set; }
  28. public string Message { get; set; }
  29. public string ItemNum { get; set; }
  30. public string Location { get; set; }
  31. public string LotSerial { get; set; }
  32. }
  33. /// <summary>
  34. /// C5 库存上下文快照(守卫与写入的输入;由 store 加载,测试可 fake)。
  35. /// 余额取自 DOP-L3(ado_inventory_master / ado_inventory_location_detail)变动前值;
  36. /// 存在性取自主数据(ItemMaster/LocationMaster,态①/②只读)。
  37. /// </summary>
  38. public sealed class InventoryContext
  39. {
  40. public bool IsLotControl { get; set; }
  41. /// <summary>G1:加载时任一键 fan-out(一条命令匹配到多行基础数据)。</summary>
  42. public bool HasDuplicateBaseData { get; set; }
  43. public HashSet<string> Items { get; } = new(StringComparer.Ordinal);
  44. public HashSet<string> Locations { get; } = new(StringComparer.Ordinal);
  45. /// <summary>InvMaster 变动前余额,键 = item|loc(存在性 = ContainsKey)。</summary>
  46. public Dictionary<string, InventoryBalance> InvMasters { get; } = new(StringComparer.Ordinal);
  47. /// <summary>LocationDetail 变动前余额,键 = item|loc|lot|refs。</summary>
  48. public Dictionary<string, InventoryBalance> LocationDetails { get; } = new(StringComparer.Ordinal);
  49. /// <summary>item → 当前默认库位(ItemMaster.Location 等价;空串/缺失=未落位)。</summary>
  50. public Dictionary<string, string> ItemDefaultLocation { get; } = new(StringComparer.Ordinal);
  51. public static string InvKey(string item, string loc) => (item ?? "") + "|" + (loc ?? "");
  52. public static string DetailKey(string item, string loc, string lot, string refs)
  53. => (item ?? "") + "|" + (loc ?? "") + "|" + (lot ?? "") + "|" + (refs ?? "");
  54. public bool ItemExists(string item) => Items.Contains(item ?? "");
  55. public bool LocationExists(string loc) => Locations.Contains(loc ?? "");
  56. public bool HasInvMaster(string item, string loc) => InvMasters.ContainsKey(InvKey(item, loc));
  57. /// <summary>取 InvMaster 变动前余额;缺失返回 null。</summary>
  58. public InventoryBalance GetInvMaster(string item, string loc)
  59. => InvMasters.TryGetValue(InvKey(item, loc), out var b) ? b : null;
  60. /// <summary>取 LocationDetail 变动前余额;缺失返回 null。</summary>
  61. public InventoryBalance GetLocationDetail(string item, string loc, string lot, string refs)
  62. => LocationDetails.TryGetValue(DetailKey(item, loc, lot, refs), out var b) ? b : null;
  63. public string GetItemDefaultLocation(string item)
  64. => ItemDefaultLocation.TryGetValue(item ?? "", out var l) ? (l ?? "") : "";
  65. }