using Admin.NET.Plugin.AiDOP.MaterialWarehouse.InventoryPosting; using Xunit; namespace Admin.NET.Plugin.AiDOP.Tests.S5.MaterialWarehouse; /// /// C1 IqcResultMapping 契约测试(Phase 1 · 契约测试先行)。 /// 把 dopdemorq 旧 LIVE 链(qms_WMS_SaveIQCResult → pr_WMS_SaveIQCResult 真定义) /// 的 5 个 (pd,clfs) 分支行为固化为测试:QCStatus / MRBStatus / QtyAcc / QtyReject / /// PartRctFlag / 是否进入收货编排 / 是否进入库存过账。 /// 样本 dhsl=10(检验/收货数)、bhgsl=3(不合格数)。 /// public class IqcResultMappingContractTests { // 分支 | pd | clfs | 语义 | QCStatus | MRB | QtyAcc | QtyReject | PartRctFlag | 进过账 | 路由 // ① | 0 | '' | 合格无处理 | YES | 0 | 10 | 0 | 0 | 是 | FullReceiptPosting // ② | 0 | 3 | 合格挑选 | NO | 1 | 10 | 3 | 1 | 否 | MrbChooseMobileTask // ③ | 1 | 0 | 不良退货 | NO | 2 | 0 | 13 | 0 | 否 | ReturnOnly // ④ | 1 | 2 | 不良让步接收 | NO | 3 | 13 | 0 | 0 | 是 | FullReceiptPosting // ⑤ | 1 | 3 | 不良挑选 | NO | 1 | 10 | 3 | 1 | 否 | MrbChooseMobileTask [Theory] [InlineData(1, 0, "", 10, 3, "YES", 0, 10, 0, 0, true, IqcRoutingKind.FullReceiptPosting)] [InlineData(2, 0, "3", 10, 3, "NO", 1, 10, 3, 1, false, IqcRoutingKind.MrbChooseMobileTask)] [InlineData(3, 1, "0", 10, 3, "NO", 2, 0, 13, 0, false, IqcRoutingKind.ReturnOnly)] [InlineData(4, 1, "2", 10, 3, "NO", 3, 13, 0, 0, true, IqcRoutingKind.FullReceiptPosting)] [InlineData(5, 1, "3", 10, 3, "NO", 1, 10, 3, 1, false, IqcRoutingKind.MrbChooseMobileTask)] public void Map_FiveMrbBranches_MatchLiveContract( int expBranchNo, int pd, string clfs, int dhsl, int bhgsl, string expQcStatus, int expMrb, int expQtyAcc, int expQtyReject, int expPartRctFlag, bool expEntersPosting, IqcRoutingKind expRouting) { var result = IqcResultMapping.Map(new IqcResultMappingInput { Pd = pd, Clfs = clfs, Dhsl = dhsl, Bhgsl = bhgsl, }); Assert.True(result.Matched); Assert.Equal(expBranchNo, result.BranchNo); Assert.Equal(expQcStatus, result.QcStatus); Assert.Equal(expMrb, result.MrbStatus); Assert.Equal(expQtyAcc, result.QtyAcc); Assert.Equal(expQtyReject, result.QtyReject); Assert.Equal(expPartRctFlag, result.PartRctFlag); Assert.Equal(expEntersPosting, result.EntersInventoryPosting); // 收货编排与库存过账同门(pr_WMS_SaveIQCResult L299 块内) Assert.Equal(expEntersPosting, result.EntersReceiptOrchestration); Assert.Equal(expRouting, result.RoutingKind); } [Fact] public void Map_Branch1_QtyRejectAlwaysZero_AndQtyAccEqualsDhsl() { var r = IqcResultMapping.Map(new IqcResultMappingInput { Pd = 0, Clfs = null, Dhsl = 7, Bhgsl = 2 }); // clfs=null 与 '' 等价,命中分支 ① Assert.Equal(1, r.BranchNo); Assert.Equal("YES", r.QcStatus); Assert.Equal(7, r.QtyAcc); Assert.Equal(0, r.QtyReject); } [Fact] public void Map_Branch3_Return_QtyAccZero_QtyRejectSumsBoth() { // 退货:QtyAcc=0,QtyReject=dhsl+bhgsl(旧入口 set @QtyReject=@QtyAcc+@QtyReject) var r = IqcResultMapping.Map(new IqcResultMappingInput { Pd = 1, Clfs = "0", Dhsl = 8, Bhgsl = 5 }); Assert.Equal(2, r.MrbStatus); Assert.Equal(0, r.QtyAcc); Assert.Equal(13, r.QtyReject); Assert.False(r.EntersInventoryPosting); Assert.Equal(IqcRoutingKind.ReturnOnly, r.RoutingKind); } [Fact] public void Map_Branch4_Concession_QtyAccSumsBoth_QtyRejectZero_EntersPosting() { // 让步接收:QtyAcc=dhsl+bhgsl,QtyReject=0,进过账 var r = IqcResultMapping.Map(new IqcResultMappingInput { Pd = 1, Clfs = "2", Dhsl = 8, Bhgsl = 5 }); Assert.Equal(3, r.MrbStatus); Assert.Equal(13, r.QtyAcc); Assert.Equal(0, r.QtyReject); Assert.True(r.EntersInventoryPosting); Assert.Equal(IqcRoutingKind.FullReceiptPosting, r.RoutingKind); } [Fact] public void Map_Branch1_WhenDhslZero_DoesNotEnterPosting() { // QtyAcc>0 是过账门的可纯判定部分:合格但收货数=0 → 不进过账 var r = IqcResultMapping.Map(new IqcResultMappingInput { Pd = 0, Clfs = "", Dhsl = 0, Bhgsl = 0 }); Assert.Equal(1, r.BranchNo); Assert.False(r.EntersInventoryPosting); } [Theory] [InlineData(0, "0")] // 合格但处理方式=退货:旧入口无此分支 [InlineData(0, "2")] // 合格但处理方式=让步接收:无此分支 [InlineData(1, "")] // 不合格但处理方式为空:isnull(clfs,100) 不匹配任何分支 [InlineData(1, "9")] // 未知处理方式 [InlineData(2, "")] // 未知 pd public void Map_UnmatchedCombos_ReturnUnmatched_NoRouting(int pd, string clfs) { var r = IqcResultMapping.Map(new IqcResultMappingInput { Pd = pd, Clfs = clfs, Dhsl = 10, Bhgsl = 3 }); Assert.False(r.Matched); Assert.Equal(0, r.BranchNo); Assert.Equal(IqcRoutingKind.Unmatched, r.RoutingKind); Assert.False(r.EntersInventoryPosting); Assert.False(r.EntersReceiptOrchestration); } [Fact] public void Map_NullInput_Throws() { Assert.Throws(() => IqcResultMapping.Map(null)); } }