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));
}
}