| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970 |
- using Admin.NET.Plugin.AiDOP.MaterialWarehouse.InventoryPosting.Idempotency;
- using Admin.NET.Plugin.AiDOP.MaterialWarehouse.InventoryPosting.L1;
- using Admin.NET.Plugin.AiDOP.MaterialWarehouse.InventoryPosting.Numbering;
- using Admin.NET.Plugin.AiDOP.MaterialWarehouse.InventoryPosting.Receipt;
- using Xunit;
- namespace Admin.NET.Plugin.AiDOP.Tests.S5.MaterialWarehouse;
- /// <summary>Phase 5B-3 接线单测:IqcDomainResolver(无 8010 fallback)+ orchestrator 事务内 RctNbr 取号。</summary>
- public class IqcWiringTests
- {
- private const long T = 950000000000001L;
- [Fact]
- public void DomainResolver_NonEmpty_Trims()
- => Assert.Equal("2400", new IqcDomainResolver().Resolve(T, " 2400 "));
- [Fact]
- public void DomainResolver_Empty_Throws_NoFallback()
- {
- var r = new IqcDomainResolver();
- Assert.Throws<InvalidOperationException>(() => r.Resolve(T, ""));
- Assert.Throws<InvalidOperationException>(() => r.Resolve(T, null));
- Assert.Throws<InvalidOperationException>(() => r.Resolve(T, " "));
- }
- [Fact]
- public async Task Orchestrator_GeneratesRctNbr_InTx_StampsC6AndTrans()
- {
- var db = new FakeInventoryDatabase();
- db.SeedMaster(T, "D5B3", "IT", "L");
- var prov = new InMemoryBusinessNumberProvider(new[]
- {
- new BusinessNumberRule { RuleCode = "P5B3_RCT", Prefix1 = "RC", IniValue = 1 },
- });
- var orch = new IqcReceiptOrchestrator(new FakeIqcReceiptUnitOfWorkFactory(db), prov, "P5B3_RCT");
- var receipt = new IqcAcceptedReceipt
- {
- TenantId = T, DomainCode = "D5B3", PostingId = 1, TransactionGroupId = 1, RctNbr = "OLD-PLACEHOLDER",
- ItemNum = "IT", Location = "L", AcceptedQty = 100m, UmConversion = 1m,
- PurOrd = "PO", PurLine = 1, Potype = "po", OrderedQty = 100m, Fbillno = "FB", User = "u",
- };
- var gate = new PurchaseReceiptGateInput { HasPendingReceipt = true, AcceptedQty = 100m, HasReceivableDetails = true };
- var r = await orch.PostAsync(receipt, gate);
- Assert.Equal(IqcReceiptOutcome.Success, r.Outcome);
- var c6 = db.ReceiptWriteback.Values.Single();
- Assert.StartsWith("RC", c6.RctNbr); // 用取号结果(新收货号落 C6.rct_nbr)
- Assert.NotEqual("OLD-PLACEHOLDER", c6.RctNbr); // 非入参占位
- Assert.NotEmpty(db.Transactions); // C5 流水已生成(trans 经 posting_id/group 关联 C6,DOP shadow 无 ord_nbr 列)
- }
- [Fact]
- public async Task Consumer_EmptyDomain_WithResolver_Retryable()
- {
- var db = new FakeInventoryDatabase();
- var store = new InMemoryIqcPostingStore();
- var idem = new IqcPostingIdempotencyService(store);
- var factory = new FakeIqcReceiptUnitOfWorkFactory(db);
- var consumer = new IqcInventoryEventConsumer(
- idem, new InMemoryBusinessCompletionStore(db), new FakeIqcReceiptStateLoader { State = new IqcReceiptState { Found = true } },
- new IqcReceiptOrchestrator(factory), new IqcMrbSelectionTaskService(factory),
- null, new IqcDomainResolver());
- var e = new IqcInventoryEvent { TenantId = T, DomainCode = "", Fbillno = "FB-X", Pd = 0, Clfs = "", Dhsl = 100m, EventTime = new DateTime(2026, 8, 9) };
- var r = await consumer.ConsumeAsync(e);
- Assert.Equal(IqcConsumeOutcome.Retryable, r.Outcome);
- Assert.Equal(0, db.TotalPersisted); // domain 未解析 → 未认领未过账
- }
- }
|