SqlSugarIqcReceiptUnitOfWork.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. using Admin.NET.Plugin.AiDOP.MaterialWarehouse.InventoryPosting.Inventory;
  2. using SqlSugar;
  3. using Yitter.IdGenerator;
  4. namespace Admin.NET.Plugin.AiDOP.MaterialWarehouse.InventoryPosting.Receipt;
  5. /// <summary>
  6. /// 生产 IQC 收货外层工作单元(DOP-L3,目标库 aidopdev)。**单外层事务**:BeginAndLock(BeginTran + 库存 FOR UPDATE)
  7. /// → C6 写 shadow → C5 写库存(InventorySqlWriter,不提交)→ 外层统一 Commit/Rollback。C5/C6 同成同败。
  8. /// **⚠️ Phase 5B 未实库验证。** C6 只写 DOP `ado_purchase_receipt_writeback`,**不写旧 PurOrd***。
  9. /// </summary>
  10. public sealed class SqlSugarIqcReceiptUnitOfWork : IIqcReceiptUnitOfWork
  11. {
  12. private readonly ISqlSugarClient _db;
  13. private bool _completed;
  14. public SqlSugarIqcReceiptUnitOfWork(ISqlSugarClient db) => _db = db;
  15. public async Task<InventoryContext> BeginAndLockAsync(IReadOnlyList<InventoryTransactionCommand> invCmds)
  16. {
  17. await _db.Ado.BeginTranAsync();
  18. return await InventorySqlWriter.LoadLockedAsync(_db, invCmds);
  19. }
  20. public Task BeginAsync(long tenantId, string domainCode) => _db.Ado.BeginTranAsync();
  21. public Task WriteMobileTaskAsync(MobileTaskCommand task) => MobileTaskSqlWriter.UpsertAsync(_db, task);
  22. public async Task WritePurchaseReceiptAsync(PurchaseReceiptWriteback c6)
  23. {
  24. if (c6 == null) throw new ArgumentNullException(nameof(c6));
  25. var now = DateTime.Now;
  26. await _db.Ado.ExecuteCommandAsync(
  27. """
  28. INSERT INTO ado_purchase_receipt_writeback
  29. (id,tenant_id,domain_code,posting_id,rct_nbr,pur_ord,pur_line,potype,accepted_qty,sample_qty,
  30. qty_ordered,returned_qty,before_received_qty,after_received_qty,before_outstanding_qty,after_outstanding_qty,detail_completed,
  31. qc_nbr,receiver,fbillno,qc_status,create_time,create_user)
  32. VALUES (@id,@t,@d,@pid,@rct,@po,@line,@pt,@aq,@sq,
  33. @ord,@ret,@br,@ar,@bo,@ao,@dc,
  34. @qc,@rcv,@fb,@st,@now,@u)
  35. ON DUPLICATE KEY UPDATE accepted_qty=@aq, sample_qty=@sq, after_received_qty=@ar, after_outstanding_qty=@ao,
  36. detail_completed=@dc, qc_status=@st, update_time=@now, update_user=@u
  37. """,
  38. new SugarParameter("@id", YitIdHelper.NextId()), new SugarParameter("@t", c6.TenantId), new SugarParameter("@d", c6.DomainCode ?? ""),
  39. new SugarParameter("@pid", c6.PostingId), new SugarParameter("@rct", c6.RctNbr), new SugarParameter("@po", c6.PurOrd ?? ""),
  40. new SugarParameter("@line", c6.PurLine), new SugarParameter("@pt", c6.Potype), new SugarParameter("@aq", c6.AcceptedQty), new SugarParameter("@sq", c6.SampleQty),
  41. new SugarParameter("@ord", c6.QtyOrdered), new SugarParameter("@ret", c6.ReturnedQty),
  42. new SugarParameter("@br", c6.BeforeReceivedQty), new SugarParameter("@ar", c6.AfterReceivedQty),
  43. new SugarParameter("@bo", c6.BeforeOutstandingQty), new SugarParameter("@ao", c6.AfterOutstandingQty),
  44. new SugarParameter("@dc", c6.DetailCompleted),
  45. new SugarParameter("@qc", c6.QcNbr), new SugarParameter("@rcv", c6.Receiver), new SugarParameter("@fb", c6.FbillNo),
  46. new SugarParameter("@st", c6.QcStatus), new SugarParameter("@now", now), new SugarParameter("@u", c6.User ?? ""));
  47. }
  48. public Task WriteInventoryAsync(InventoryWriteSet writeSet) => InventorySqlWriter.WriteAsync(_db, writeSet);
  49. public async Task WriteCompletionAsync(IqcCompletionMarker marker)
  50. {
  51. if (marker == null) throw new ArgumentNullException(nameof(marker));
  52. // 完成锚与业务写同事务提交;(tenant,domain,fbillno) UNIQUE 幂等(重跑 ON DUP 刷新 completed_at)。
  53. await _db.Ado.ExecuteCommandAsync(
  54. """
  55. INSERT INTO ado_iqc_posting_completion
  56. (id,tenant_id,domain_code,fbillno,posting_id,transaction_group_id,route_kind,completed_at,create_time,create_user)
  57. VALUES (@id,@t,@d,@fb,@pid,@tg,@rk,@now,@now,@u)
  58. ON DUPLICATE KEY UPDATE posting_id=@pid, transaction_group_id=@tg, route_kind=@rk, completed_at=@now, update_time=@now
  59. """,
  60. new SugarParameter("@id", YitIdHelper.NextId()), new SugarParameter("@t", marker.TenantId),
  61. new SugarParameter("@d", marker.DomainCode ?? ""), new SugarParameter("@fb", marker.FbillNo),
  62. new SugarParameter("@pid", marker.PostingId),
  63. new SugarParameter("@tg", (object)marker.TransactionGroupId ?? DBNull.Value),
  64. new SugarParameter("@rk", marker.RouteKind ?? ""), new SugarParameter("@now", DateTime.Now),
  65. new SugarParameter("@u", ""));
  66. }
  67. public async Task CommitAsync()
  68. {
  69. if (_completed) return;
  70. _completed = true;
  71. await _db.Ado.CommitTranAsync();
  72. }
  73. public async Task RollbackAsync()
  74. {
  75. if (_completed) return;
  76. _completed = true;
  77. await _db.Ado.RollbackTranAsync();
  78. }
  79. public async ValueTask DisposeAsync()
  80. {
  81. if (!_completed) await RollbackAsync();
  82. }
  83. }
  84. /// <summary>生产 IQC 收货外层工作单元工厂(每请求独立连接/事务)。</summary>
  85. public sealed class SqlSugarIqcReceiptUnitOfWorkFactory : IIqcReceiptUnitOfWorkFactory, ITransient
  86. {
  87. private readonly ISqlSugarClient _db;
  88. public SqlSugarIqcReceiptUnitOfWorkFactory(ISqlSugarClient db) => _db = db;
  89. public IIqcReceiptUnitOfWork Create() => new SqlSugarIqcReceiptUnitOfWork(_db);
  90. }