IqcResultMappingContractTests.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. using Admin.NET.Plugin.AiDOP.MaterialWarehouse.InventoryPosting;
  2. using Xunit;
  3. namespace Admin.NET.Plugin.AiDOP.Tests.S5.MaterialWarehouse;
  4. /// <summary>
  5. /// C1 IqcResultMapping 契约测试(Phase 1 · 契约测试先行)。
  6. /// 把 dopdemorq 旧 LIVE 链(qms_WMS_SaveIQCResult → pr_WMS_SaveIQCResult 真定义)
  7. /// 的 5 个 (pd,clfs) 分支行为固化为测试:QCStatus / MRBStatus / QtyAcc / QtyReject /
  8. /// PartRctFlag / 是否进入收货编排 / 是否进入库存过账。
  9. /// 样本 dhsl=10(检验/收货数)、bhgsl=3(不合格数)。
  10. /// </summary>
  11. public class IqcResultMappingContractTests
  12. {
  13. // 分支 | pd | clfs | 语义 | QCStatus | MRB | QtyAcc | QtyReject | PartRctFlag | 进过账 | 路由
  14. // ① | 0 | '' | 合格无处理 | YES | 0 | 10 | 0 | 0 | 是 | FullReceiptPosting
  15. // ② | 0 | 3 | 合格挑选 | NO | 1 | 10 | 3 | 1 | 否 | MrbChooseMobileTask
  16. // ③ | 1 | 0 | 不良退货 | NO | 2 | 0 | 13 | 0 | 否 | ReturnOnly
  17. // ④ | 1 | 2 | 不良让步接收 | NO | 3 | 13 | 0 | 0 | 是 | FullReceiptPosting
  18. // ⑤ | 1 | 3 | 不良挑选 | NO | 1 | 10 | 3 | 1 | 否 | MrbChooseMobileTask
  19. [Theory]
  20. [InlineData(1, 0, "", 10, 3, "YES", 0, 10, 0, 0, true, IqcRoutingKind.FullReceiptPosting)]
  21. [InlineData(2, 0, "3", 10, 3, "NO", 1, 10, 3, 1, false, IqcRoutingKind.MrbChooseMobileTask)]
  22. [InlineData(3, 1, "0", 10, 3, "NO", 2, 0, 13, 0, false, IqcRoutingKind.ReturnOnly)]
  23. [InlineData(4, 1, "2", 10, 3, "NO", 3, 13, 0, 0, true, IqcRoutingKind.FullReceiptPosting)]
  24. [InlineData(5, 1, "3", 10, 3, "NO", 1, 10, 3, 1, false, IqcRoutingKind.MrbChooseMobileTask)]
  25. public void Map_FiveMrbBranches_MatchLiveContract(
  26. int expBranchNo, int pd, string clfs, int dhsl, int bhgsl,
  27. string expQcStatus, int expMrb, int expQtyAcc, int expQtyReject,
  28. int expPartRctFlag, bool expEntersPosting, IqcRoutingKind expRouting)
  29. {
  30. var result = IqcResultMapping.Map(new IqcResultMappingInput
  31. {
  32. Pd = pd,
  33. Clfs = clfs,
  34. Dhsl = dhsl,
  35. Bhgsl = bhgsl,
  36. });
  37. Assert.True(result.Matched);
  38. Assert.Equal(expBranchNo, result.BranchNo);
  39. Assert.Equal(expQcStatus, result.QcStatus);
  40. Assert.Equal(expMrb, result.MrbStatus);
  41. Assert.Equal(expQtyAcc, result.QtyAcc);
  42. Assert.Equal(expQtyReject, result.QtyReject);
  43. Assert.Equal(expPartRctFlag, result.PartRctFlag);
  44. Assert.Equal(expEntersPosting, result.EntersInventoryPosting);
  45. // 收货编排与库存过账同门(pr_WMS_SaveIQCResult L299 块内)
  46. Assert.Equal(expEntersPosting, result.EntersReceiptOrchestration);
  47. Assert.Equal(expRouting, result.RoutingKind);
  48. }
  49. [Fact]
  50. public void Map_Branch1_QtyRejectAlwaysZero_AndQtyAccEqualsDhsl()
  51. {
  52. var r = IqcResultMapping.Map(new IqcResultMappingInput { Pd = 0, Clfs = null, Dhsl = 7, Bhgsl = 2 });
  53. // clfs=null 与 '' 等价,命中分支 ①
  54. Assert.Equal(1, r.BranchNo);
  55. Assert.Equal("YES", r.QcStatus);
  56. Assert.Equal(7, r.QtyAcc);
  57. Assert.Equal(0, r.QtyReject);
  58. }
  59. [Fact]
  60. public void Map_Branch3_Return_QtyAccZero_QtyRejectSumsBoth()
  61. {
  62. // 退货:QtyAcc=0,QtyReject=dhsl+bhgsl(旧入口 set @QtyReject=@QtyAcc+@QtyReject)
  63. var r = IqcResultMapping.Map(new IqcResultMappingInput { Pd = 1, Clfs = "0", Dhsl = 8, Bhgsl = 5 });
  64. Assert.Equal(2, r.MrbStatus);
  65. Assert.Equal(0, r.QtyAcc);
  66. Assert.Equal(13, r.QtyReject);
  67. Assert.False(r.EntersInventoryPosting);
  68. Assert.Equal(IqcRoutingKind.ReturnOnly, r.RoutingKind);
  69. }
  70. [Fact]
  71. public void Map_Branch4_Concession_QtyAccSumsBoth_QtyRejectZero_EntersPosting()
  72. {
  73. // 让步接收:QtyAcc=dhsl+bhgsl,QtyReject=0,进过账
  74. var r = IqcResultMapping.Map(new IqcResultMappingInput { Pd = 1, Clfs = "2", Dhsl = 8, Bhgsl = 5 });
  75. Assert.Equal(3, r.MrbStatus);
  76. Assert.Equal(13, r.QtyAcc);
  77. Assert.Equal(0, r.QtyReject);
  78. Assert.True(r.EntersInventoryPosting);
  79. Assert.Equal(IqcRoutingKind.FullReceiptPosting, r.RoutingKind);
  80. }
  81. [Fact]
  82. public void Map_Branch1_WhenDhslZero_DoesNotEnterPosting()
  83. {
  84. // QtyAcc>0 是过账门的可纯判定部分:合格但收货数=0 → 不进过账
  85. var r = IqcResultMapping.Map(new IqcResultMappingInput { Pd = 0, Clfs = "", Dhsl = 0, Bhgsl = 0 });
  86. Assert.Equal(1, r.BranchNo);
  87. Assert.False(r.EntersInventoryPosting);
  88. }
  89. [Theory]
  90. [InlineData(0, "0")] // 合格但处理方式=退货:旧入口无此分支
  91. [InlineData(0, "2")] // 合格但处理方式=让步接收:无此分支
  92. [InlineData(1, "")] // 不合格但处理方式为空:isnull(clfs,100) 不匹配任何分支
  93. [InlineData(1, "9")] // 未知处理方式
  94. [InlineData(2, "")] // 未知 pd
  95. public void Map_UnmatchedCombos_ReturnUnmatched_NoRouting(int pd, string clfs)
  96. {
  97. var r = IqcResultMapping.Map(new IqcResultMappingInput { Pd = pd, Clfs = clfs, Dhsl = 10, Bhgsl = 3 });
  98. Assert.False(r.Matched);
  99. Assert.Equal(0, r.BranchNo);
  100. Assert.Equal(IqcRoutingKind.Unmatched, r.RoutingKind);
  101. Assert.False(r.EntersInventoryPosting);
  102. Assert.False(r.EntersReceiptOrchestration);
  103. }
  104. [Fact]
  105. public void Map_NullInput_Throws()
  106. {
  107. Assert.Throws<ArgumentNullException>(() => IqcResultMapping.Map(null));
  108. }
  109. }