using Admin.NET.Plugin.AiDOP.MaterialWarehouse.InventoryPosting.Inventory; using SqlSugar; using Yitter.IdGenerator; namespace Admin.NET.Plugin.AiDOP.MaterialWarehouse.InventoryPosting.Receipt; /// /// 生产 IQC 收货外层工作单元(DOP-L3,目标库 aidopdev)。**单外层事务**:BeginAndLock(BeginTran + 库存 FOR UPDATE) /// → C6 写 shadow → C5 写库存(InventorySqlWriter,不提交)→ 外层统一 Commit/Rollback。C5/C6 同成同败。 /// **⚠️ Phase 5B 未实库验证。** C6 只写 DOP `ado_purchase_receipt_writeback`,**不写旧 PurOrd***。 /// public sealed class SqlSugarIqcReceiptUnitOfWork : IIqcReceiptUnitOfWork { private readonly ISqlSugarClient _db; private bool _completed; public SqlSugarIqcReceiptUnitOfWork(ISqlSugarClient db) => _db = db; public async Task BeginAndLockAsync(IReadOnlyList invCmds) { await _db.Ado.BeginTranAsync(); return await InventorySqlWriter.LoadLockedAsync(_db, invCmds); } public Task BeginAsync(long tenantId, string domainCode) => _db.Ado.BeginTranAsync(); public Task WriteMobileTaskAsync(MobileTaskCommand task) => MobileTaskSqlWriter.UpsertAsync(_db, task); public async Task WritePurchaseReceiptAsync(PurchaseReceiptWriteback c6) { if (c6 == null) throw new ArgumentNullException(nameof(c6)); var now = DateTime.Now; await _db.Ado.ExecuteCommandAsync( """ INSERT INTO ado_purchase_receipt_writeback (id,tenant_id,domain_code,posting_id,rct_nbr,pur_ord,pur_line,potype,accepted_qty,sample_qty, qty_ordered,returned_qty,before_received_qty,after_received_qty,before_outstanding_qty,after_outstanding_qty,detail_completed, qc_nbr,receiver,fbillno,qc_status,create_time,create_user) VALUES (@id,@t,@d,@pid,@rct,@po,@line,@pt,@aq,@sq, @ord,@ret,@br,@ar,@bo,@ao,@dc, @qc,@rcv,@fb,@st,@now,@u) ON DUPLICATE KEY UPDATE accepted_qty=@aq, sample_qty=@sq, after_received_qty=@ar, after_outstanding_qty=@ao, detail_completed=@dc, qc_status=@st, update_time=@now, update_user=@u """, new SugarParameter("@id", YitIdHelper.NextId()), new SugarParameter("@t", c6.TenantId), new SugarParameter("@d", c6.DomainCode ?? ""), new SugarParameter("@pid", c6.PostingId), new SugarParameter("@rct", c6.RctNbr), new SugarParameter("@po", c6.PurOrd ?? ""), new SugarParameter("@line", c6.PurLine), new SugarParameter("@pt", c6.Potype), new SugarParameter("@aq", c6.AcceptedQty), new SugarParameter("@sq", c6.SampleQty), new SugarParameter("@ord", c6.QtyOrdered), new SugarParameter("@ret", c6.ReturnedQty), new SugarParameter("@br", c6.BeforeReceivedQty), new SugarParameter("@ar", c6.AfterReceivedQty), new SugarParameter("@bo", c6.BeforeOutstandingQty), new SugarParameter("@ao", c6.AfterOutstandingQty), new SugarParameter("@dc", c6.DetailCompleted), new SugarParameter("@qc", c6.QcNbr), new SugarParameter("@rcv", c6.Receiver), new SugarParameter("@fb", c6.FbillNo), new SugarParameter("@st", c6.QcStatus), new SugarParameter("@now", now), new SugarParameter("@u", c6.User ?? "")); } public Task WriteInventoryAsync(InventoryWriteSet writeSet) => InventorySqlWriter.WriteAsync(_db, writeSet); public async Task WriteCompletionAsync(IqcCompletionMarker marker) { if (marker == null) throw new ArgumentNullException(nameof(marker)); // 完成锚与业务写同事务提交;(tenant,domain,fbillno) UNIQUE 幂等(重跑 ON DUP 刷新 completed_at)。 await _db.Ado.ExecuteCommandAsync( """ INSERT INTO ado_iqc_posting_completion (id,tenant_id,domain_code,fbillno,posting_id,transaction_group_id,route_kind,completed_at,create_time,create_user) VALUES (@id,@t,@d,@fb,@pid,@tg,@rk,@now,@now,@u) ON DUPLICATE KEY UPDATE posting_id=@pid, transaction_group_id=@tg, route_kind=@rk, completed_at=@now, update_time=@now """, new SugarParameter("@id", YitIdHelper.NextId()), new SugarParameter("@t", marker.TenantId), new SugarParameter("@d", marker.DomainCode ?? ""), new SugarParameter("@fb", marker.FbillNo), new SugarParameter("@pid", marker.PostingId), new SugarParameter("@tg", (object)marker.TransactionGroupId ?? DBNull.Value), new SugarParameter("@rk", marker.RouteKind ?? ""), new SugarParameter("@now", DateTime.Now), new SugarParameter("@u", "")); } public async Task CommitAsync() { if (_completed) return; _completed = true; await _db.Ado.CommitTranAsync(); } public async Task RollbackAsync() { if (_completed) return; _completed = true; await _db.Ado.RollbackTranAsync(); } public async ValueTask DisposeAsync() { if (!_completed) await RollbackAsync(); } } /// 生产 IQC 收货外层工作单元工厂(每请求独立连接/事务)。 public sealed class SqlSugarIqcReceiptUnitOfWorkFactory : IIqcReceiptUnitOfWorkFactory, ITransient { private readonly ISqlSugarClient _db; public SqlSugarIqcReceiptUnitOfWorkFactory(ISqlSugarClient db) => _db = db; public IIqcReceiptUnitOfWork Create() => new SqlSugarIqcReceiptUnitOfWork(_db); }