@happyvertical/smrt-commerce 0.57.4 → 0.57.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/AGENTS.md +3 -0
  2. package/agents/historical-sales.md +18 -0
  3. package/agents/ordinary-accounting.md +72 -0
  4. package/dist/accounting-steps-internal.d.ts +49 -0
  5. package/dist/accounting-steps-internal.d.ts.map +1 -0
  6. package/dist/chunks/{ContractLineItemCollection-J4xtRtzE.js → ContractLineItemCollection-D5hBzrct.js} +4 -4
  7. package/dist/chunks/{ContractLineItemCollection-J4xtRtzE.js.map → ContractLineItemCollection-D5hBzrct.js.map} +1 -1
  8. package/dist/chunks/{DocumentTaxCollection-C42x0YLW.js → DocumentTaxCollection-C6cI5U89.js} +29 -19
  9. package/dist/chunks/DocumentTaxCollection-C6cI5U89.js.map +1 -0
  10. package/dist/chunks/{InvoiceCollection-BIcge9Wl.js → InvoiceCollection-BolwughC.js} +13 -11
  11. package/dist/chunks/InvoiceCollection-BolwughC.js.map +1 -0
  12. package/dist/chunks/{TaxCodeCollection-RWdVaheF.js → TaxCodeCollection-CW-tWjkU.js} +2 -2
  13. package/dist/chunks/{TaxCodeCollection-RWdVaheF.js.map → TaxCodeCollection-CW-tWjkU.js.map} +1 -1
  14. package/dist/chunks/{TaxComponentCollection-Dt2jeWiC.js → TaxComponentCollection-BiJ9aAe8.js} +3 -3
  15. package/dist/chunks/{TaxComponentCollection-Dt2jeWiC.js.map → TaxComponentCollection-BiJ9aAe8.js.map} +1 -1
  16. package/dist/chunks/{allocation-integrity-DJ7-LY1j.js → allocation-integrity-CH-i-hsY.js} +6 -6
  17. package/dist/chunks/{allocation-integrity-DJ7-LY1j.js.map → allocation-integrity-CH-i-hsY.js.map} +1 -1
  18. package/dist/chunks/{contract-money-DSRTMoXm.js → contract-money-BMsq4cpL.js} +6 -6
  19. package/dist/chunks/{contract-money-DSRTMoXm.js.map → contract-money-BMsq4cpL.js.map} +1 -1
  20. package/dist/chunks/{invoice-posting-BeTPw3h9.js → invoice-posting-IXic4UEP.js} +3 -3
  21. package/dist/chunks/{invoice-posting-BeTPw3h9.js.map → invoice-posting-IXic4UEP.js.map} +1 -1
  22. package/dist/chunks/{retention-accounting-Brdj9x-V.js → retention-accounting-c7kY7gFU.js} +504 -89
  23. package/dist/chunks/retention-accounting-c7kY7gFU.js.map +1 -0
  24. package/dist/chunks/retention-accounting-internal-DNxLLVvK.js +30 -0
  25. package/dist/chunks/retention-accounting-internal-DNxLLVvK.js.map +1 -0
  26. package/dist/chunks/{tenant-money-barrier-DoF6lR8h.js → tenant-money-barrier-DEVLrpaB.js} +3 -3
  27. package/dist/chunks/{tenant-money-barrier-DoF6lR8h.js.map → tenant-money-barrier-DEVLrpaB.js.map} +1 -1
  28. package/dist/document-money.d.ts.map +1 -1
  29. package/dist/index.d.ts +1 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +13 -13
  32. package/dist/index.js.map +1 -1
  33. package/dist/invoice-accounting-sync.d.ts.map +1 -1
  34. package/dist/invoices.d.ts +1 -0
  35. package/dist/invoices.d.ts.map +1 -1
  36. package/dist/invoices.js +2 -2
  37. package/dist/manifest.json +45 -9
  38. package/dist/models/Invoice.d.ts +2 -0
  39. package/dist/models/Invoice.d.ts.map +1 -1
  40. package/dist/models/Payment.d.ts +2 -0
  41. package/dist/models/Payment.d.ts.map +1 -1
  42. package/dist/models/PaymentAllocation.d.ts.map +1 -1
  43. package/dist/ordinary-accounting-internal.d.ts +3 -0
  44. package/dist/ordinary-accounting-internal.d.ts.map +1 -0
  45. package/dist/ordinary-accounting.d.ts +104 -0
  46. package/dist/ordinary-accounting.d.ts.map +1 -0
  47. package/dist/retention-accounting.d.ts +3 -24
  48. package/dist/retention-accounting.d.ts.map +1 -1
  49. package/dist/smrt-knowledge.json +14 -8
  50. package/package.json +16 -16
  51. package/dist/chunks/DocumentTaxCollection-C42x0YLW.js.map +0 -1
  52. package/dist/chunks/InvoiceCollection-BIcge9Wl.js.map +0 -1
  53. package/dist/chunks/retention-accounting-Brdj9x-V.js.map +0 -1
  54. package/dist/chunks/retention-accounting-internal-CBQRvd74.js +0 -17
  55. package/dist/chunks/retention-accounting-internal-CBQRvd74.js.map +0 -1
@@ -1,16 +1,16 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { Y as InvoiceLineItemCollection, t as DocumentTaxCollection, x as lockAndReloadInvoice } from "./DocumentTaxCollection-C42x0YLW.js";
2
+ import { Y as InvoiceLineItemCollection, t as DocumentTaxCollection, x as lockAndReloadInvoice } from "./DocumentTaxCollection-C6cI5U89.js";
3
3
  import { d as PaymentStatus, s as InvoiceStatus, u as PaymentMethod } from "./types-Bbm0Xflc.js";
4
4
  import { o as minorToMajorUnits } from "./units-8ElbjVZK.js";
5
- import { n as withRetentionAccountingAuthority, t as hasRetentionAccountingAuthority } from "./retention-accounting-internal-CBQRvd74.js";
6
- import { i as claimAllocationParent, n as allocationTotal, r as assertAllocationParent, t as allocationOwner } from "./allocation-integrity-DJ7-LY1j.js";
5
+ import { i as withOrdinaryAccountingAuthority, n as withRetentionAccountingAuthority, r as hasOrdinaryAccountingAuthority, t as hasRetentionAccountingAuthority } from "./retention-accounting-internal-DNxLLVvK.js";
6
+ import { i as claimAllocationParent, n as allocationTotal, r as assertAllocationParent, t as allocationOwner } from "./allocation-integrity-CH-i-hsY.js";
7
7
  import { n as customerFundsState, t as assertCustomerFundsWrite } from "./customer-funds-internal-BQzoJXK5.js";
8
8
  import { MoneyValidationError, assertIntegerMinorUnits, calculateMoneyDocument } from "../money.js";
9
9
  import { t as HistoricalCustomerFundsAllocationCollection } from "./HistoricalCustomerFundsCollections-B5x8gTW3.js";
10
10
  import { n as calculateAvailableRefund } from "./credit-allocation-yspz0Lab.js";
11
11
  import { _ as withDocumentMoneyTransaction, m as isMoneyTransaction, p as DOCUMENT_MONEY_WRITE } from "./detect-DAE-_NAk.js";
12
- import { c as validateRetentionEvidence, o as calculateInvoicePayable, s as parseInvoiceRetention, t as InvoiceCollection } from "./InvoiceCollection-BIcge9Wl.js";
13
- import { t as lockTenantMoneyRuntime } from "./tenant-money-barrier-DoF6lR8h.js";
12
+ import { c as validateRetentionEvidence, o as calculateInvoicePayable, s as parseInvoiceRetention, t as InvoiceCollection } from "./InvoiceCollection-BolwughC.js";
13
+ import { t as lockTenantMoneyRuntime } from "./tenant-money-barrier-DEVLrpaB.js";
14
14
  import { SmrtCollection, SmrtObject, crossPackageRef, field, foreignKey, isPostgresDatabase, smrt } from "@happyvertical/smrt-core";
15
15
  import { TenantScoped, getTenantId, queryGlobal, queryWithGlobals, tenantId } from "@happyvertical/smrt-tenancy";
16
16
  import { createHash, randomUUID } from "node:crypto";
@@ -50,6 +50,7 @@ var Payment = class extends SmrtObject {
50
50
  kind = "payment";
51
51
  customerFundsJson = "";
52
52
  retentionAccountingBindingJson = "";
53
+ ordinaryAccountingBindingJson = "";
53
54
  tenantId = null;
54
55
  contractId = null;
55
56
  customerId = null;
@@ -212,6 +213,8 @@ var Payment = class extends SmrtObject {
212
213
  ]);
213
214
  const priorRow = await this.loadPersistedRow();
214
215
  if (this.customerFundsJson || priorRow?.customer_funds_json) assertCustomerFundsWrite(this);
216
+ const ordinaryBinding = this.ordinaryAccountingBindingJson || String(priorRow?.ordinary_accounting_binding_json ?? "");
217
+ if (ordinaryBinding && !hasOrdinaryAccountingAuthority(this.tenantId, JSON.parse(ordinaryBinding).invoiceId)) throw new Error("Provider-recorded refund is immutable; use an explicit reversal workflow");
215
218
  const retainedBinding = this.retentionAccountingBindingJson || String(priorRow?.retention_accounting_binding_json ?? "");
216
219
  if (retainedBinding && !hasRetentionAccountingAuthority(this.tenantId, JSON.parse(retainedBinding).invoiceId)) throw new Error("Provider-recorded refund is immutable; use an explicit reversal workflow");
217
220
  const prior = priorRow && priorRow.status != null ? priorRow.status : loadedPaymentStatus.get(this);
@@ -231,7 +234,7 @@ var Payment = class extends SmrtObject {
231
234
  /** Managed receipts and refunds retain immutable cash provenance. */
232
235
  async delete(options = {}) {
233
236
  const persisted = await this.loadPersistedRow();
234
- if (this.retentionAccountingBindingJson || persisted?.retention_accounting_binding_json) throw new Error("Provider-recorded refund history cannot be deleted");
237
+ if (this.retentionAccountingBindingJson || persisted?.retention_accounting_binding_json || this.ordinaryAccountingBindingJson || persisted?.ordinary_accounting_binding_json) throw new Error("Provider-recorded refund history cannot be deleted");
235
238
  if (this.customerFundsJson || persisted?.customer_funds_json) throw new Error("Customer funds cash history cannot be deleted");
236
239
  return super.delete(options);
237
240
  }
@@ -509,6 +512,7 @@ var Payment = class extends SmrtObject {
509
512
  __publicField$1(Payment, "__smrtPackage__", "@happyvertical/smrt-commerce");
510
513
  __decorateClass$1([field({ type: "text" })], Payment.prototype, "customerFundsJson", 2);
511
514
  __decorateClass$1([field({ sensitive: true })], Payment.prototype, "retentionAccountingBindingJson", 2);
515
+ __decorateClass$1([field({ sensitive: true })], Payment.prototype, "ordinaryAccountingBindingJson", 2);
512
516
  __decorateClass$1([tenantId({ nullable: true })], Payment.prototype, "tenantId", 2);
513
517
  __decorateClass$1([field({ description: "The order or agreement this payment is for, if any." }), foreignKey("SalesContract", { validateSubtype: true })], Payment.prototype, "contractId", 2);
514
518
  __decorateClass$1([field({ description: "The customer who paid." }), foreignKey("Customer")], Payment.prototype, "customerId", 2);
@@ -809,7 +813,7 @@ var PaymentAllocation = class extends SmrtObject {
809
813
  if (!this.paymentId || !this.invoiceId) throw new Error("PaymentAllocation requires payment and invoice");
810
814
  return this.withTransaction(async () => {
811
815
  const { PaymentCollection } = await Promise.resolve().then(() => PaymentCollection_exports);
812
- const { InvoiceCollection } = await import("./InvoiceCollection-BIcge9Wl.js").then((n) => n.n);
816
+ const { InvoiceCollection } = await import("./InvoiceCollection-BolwughC.js").then((n) => n.n);
813
817
  const { PaymentAllocationCollection } = await Promise.resolve().then(() => PaymentAllocationCollection_exports);
814
818
  const payments = await PaymentCollection.create({ db: this.db });
815
819
  const invoices = await InvoiceCollection.create({ db: this.db });
@@ -818,7 +822,7 @@ var PaymentAllocation = class extends SmrtObject {
818
822
  if (prior && (prior.paymentId !== this.paymentId || prior.invoiceId !== this.invoiceId || prior.tenantId !== allocationOwner(this.tenantId))) throw new Error("PaymentAllocation parent identity is immutable");
819
823
  const payment = await payments.get({ id: this.paymentId }, { cache: false });
820
824
  if (!payment) throw new Error("PaymentAllocation referenced Payment does not exist");
821
- if (payment.retentionAccountingBindingJson) throw new Error("Provider-recorded refund allocation is immutable");
825
+ if (payment.retentionAccountingBindingJson || payment.ordinaryAccountingBindingJson) throw new Error("Provider-recorded refund allocation is immutable");
822
826
  if (customerFundsState(payment.customerFundsJson)) assertCustomerFundsWrite(this);
823
827
  if (!payment.updated_at) throw new Error("Allocation parent has no persisted revision");
824
828
  await payment.claimRevision(payment.updated_at);
@@ -882,7 +886,7 @@ var PaymentAllocation = class extends SmrtObject {
882
886
  if (!payment.updated_at) throw new Error("Allocation parent has no persisted revision");
883
887
  await payment.claimRevision(payment.updated_at);
884
888
  }
885
- if (payment?.retentionAccountingBindingJson) throw new Error("Provider-recorded refund allocation cannot be deleted");
889
+ if (payment?.retentionAccountingBindingJson || payment?.ordinaryAccountingBindingJson) throw new Error("Provider-recorded refund allocation cannot be deleted");
886
890
  if (payment?.customerFundsJson) assertCustomerFundsWrite(this);
887
891
  return super.delete(options);
888
892
  });
@@ -916,7 +920,7 @@ var PaymentAllocationCollection = class PaymentAllocationCollection extends Smrt
916
920
  async allocatePayment(input) {
917
921
  if (!input.allocations.length || new Set(input.allocations.map((item) => item.id)).size !== input.allocations.length) throw new Error("Allocation batch requires distinct stable allocation ids");
918
922
  const { PaymentCollection } = await Promise.resolve().then(() => PaymentCollection_exports);
919
- const { InvoiceCollection } = await import("./InvoiceCollection-BIcge9Wl.js").then((n) => n.n);
923
+ const { InvoiceCollection } = await import("./InvoiceCollection-BolwughC.js").then((n) => n.n);
920
924
  const { InvoiceStatus } = await import("./types-Bbm0Xflc.js").then((n) => n.m);
921
925
  const payment = await (await PaymentCollection.create({ db: this.db })).get({ id: input.paymentId }, { cache: false });
922
926
  if (!payment) throw new Error("Payment does not exist");
@@ -959,7 +963,7 @@ var PaymentAllocationCollection = class PaymentAllocationCollection extends Smrt
959
963
  const allocation = await this.get({ id }, { cache: false });
960
964
  if (!allocation) return;
961
965
  const { PaymentCollection } = await Promise.resolve().then(() => PaymentCollection_exports);
962
- const { InvoiceCollection } = await import("./InvoiceCollection-BIcge9Wl.js").then((n) => n.n);
966
+ const { InvoiceCollection } = await import("./InvoiceCollection-BolwughC.js").then((n) => n.n);
963
967
  const payment = await (await PaymentCollection.create({ db: this.db })).get({ id: allocation.paymentId }, { cache: false });
964
968
  if (!payment) throw new Error("Allocation payment does not exist");
965
969
  await payment.withTransaction(async () => {
@@ -1347,6 +1351,7 @@ async function loadSnapshot(db, tenantId, invoice) {
1347
1351
  const source = await (await InvoiceCollection.create({ db })).get({ id: invoice.creditedInvoiceId }, { cache: false });
1348
1352
  if (!source || source.tenantId !== tenantId || !source.externalId) throw new MoneyValidationError("INVALID_MONEY_INPUT", "Frozen credit note requires the source invoice external ID");
1349
1353
  if (source.retentionAccountingStateJson && !hasRetentionAccountingAuthority(source.tenantId, source.id)) unsupported("Provider-retained credit requires the retained-first accounting adjustment command");
1354
+ if (source.ordinaryAccountingStateJson && !hasOrdinaryAccountingAuthority(source.tenantId, source.id)) unsupported("Provider ordinary credit requires its owning accounting adjustment command");
1350
1355
  const sourceState = parseSyncState(source.accountingSyncStateJson);
1351
1356
  if (sourceState?.status !== "synced" || sourceState.externalId !== source.externalId) throw new MoneyValidationError("ACCOUNTING_SYNC_RECONCILIATION_REQUIRED", "Frozen credit note requires a reconciled source invoice accounting identity");
1352
1357
  creditedInvoiceExternalId = source.externalId;
@@ -1457,6 +1462,7 @@ async function prepareSync(input) {
1457
1462
  return withDocumentMoneyTransaction(input.db, async (tx) => {
1458
1463
  await lockTenantMoneyRuntime(tx, input.tenantId);
1459
1464
  const { invoice } = await lockAndReloadInvoice(tx, input.invoiceId, input.tenantId);
1465
+ if (invoice.ordinaryAccountingStateJson && !hasOrdinaryAccountingAuthority(invoice.tenantId, invoice.id)) unsupported("Provider ordinary invoice requires its owning accounting command");
1460
1466
  const snapshot = await loadSnapshot(tx, input.tenantId, invoice);
1461
1467
  const sdkInput = toSdkInput(snapshot, input.mapping);
1462
1468
  const prior = parseSyncState(invoice.accountingSyncStateJson);
@@ -1729,6 +1735,481 @@ function calculateInvoiceMinorLine(input) {
1729
1735
  };
1730
1736
  }
1731
1737
  //#endregion
1738
+ //#region src/accounting-steps-internal.ts
1739
+ function reject$2(message) {
1740
+ throw new MoneyValidationError("ACCOUNTING_SYNC_RECONCILIATION_REQUIRED", message);
1741
+ }
1742
+ function text$2(value, label) {
1743
+ if (typeof value !== "string" || !value || value.trim() !== value) reject$2(`${label} is required`);
1744
+ }
1745
+ async function executeAccountingStep(engine, key, make) {
1746
+ const prepared = await engine.locked(async (invoice, state) => {
1747
+ if (!state) reject$2("Retention provider contract is missing");
1748
+ const expected = make(invoice, state), prior = state.steps.find((s) => s.key === key);
1749
+ if (prior && prior.request.payloadHash !== expected.payloadHash) reject$2("Retention operation identity reused with changed facts");
1750
+ if (prior?.status === "confirmed") {
1751
+ if (!prior.result) reject$2("Confirmed retention step has no readback");
1752
+ return { complete: prior.result };
1753
+ }
1754
+ if (prior && prior.status !== "rejected") reject$2("Retention operation has an unresolved remote owner");
1755
+ if (state.steps.some((s) => s.key !== key && s.status !== "confirmed")) reject$2("Another retention operation requires reconciliation");
1756
+ const step2 = {
1757
+ key,
1758
+ status: "in_flight",
1759
+ attemptId: randomUUID(),
1760
+ request: expected,
1761
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
1762
+ priorAttempts: prior ? [...prior.priorAttempts ?? [], {
1763
+ attemptId: prior.attemptId,
1764
+ status: prior.status,
1765
+ startedAt: prior.startedAt,
1766
+ reconciliation: prior.reconciliation
1767
+ }] : []
1768
+ };
1769
+ if (prior) state.steps[state.steps.indexOf(prior)] = step2;
1770
+ else state.steps.push(step2);
1771
+ await engine.save(invoice, state);
1772
+ return { step: step2 };
1773
+ });
1774
+ if ("complete" in prepared && prepared.complete) return prepared.complete;
1775
+ if (!prepared.step) reject$2("Prepared retention step is missing");
1776
+ const step = prepared.step;
1777
+ let result;
1778
+ try {
1779
+ result = await engine.provider.execute(step.request);
1780
+ } catch (error) {
1781
+ await engine.locked(async (invoice, state) => {
1782
+ const current = state?.steps.find((s) => s.key === key);
1783
+ if (!state || current?.attemptId !== step.attemptId || current.status !== "in_flight") reject$2("Retention step ownership changed after remote failure");
1784
+ current.status = error?.outcome === "rejected" ? "rejected" : "unknown";
1785
+ await engine.save(invoice, state);
1786
+ });
1787
+ throw error;
1788
+ }
1789
+ return engine.locked(async (invoice, state) => {
1790
+ const current = state?.steps.find((s) => s.key === key);
1791
+ if (!state || current?.attemptId !== step.attemptId || current.status !== "in_flight" || result.payloadHash !== step.request.payloadHash) reject$2("Retention step ownership or readback changed after write");
1792
+ current.status = "confirmed";
1793
+ current.result = structuredClone(result);
1794
+ await engine.save(invoice, state);
1795
+ return result;
1796
+ });
1797
+ }
1798
+ async function reconcileAccountingStep(engine, input) {
1799
+ const step = await engine.locked(async (_invoice, state) => {
1800
+ const found = state?.steps.find((s) => s.key === input.stepKey);
1801
+ if (!found || found.request.requestId !== input.requestId || found.attemptId !== input.attemptId || !["in_flight", "unknown"].includes(found.status)) reject$2("Observed retention reconciliation owner differs");
1802
+ if (found.status === "in_flight" && !input.confirmInterruptedOwnerStopped) reject$2("Interrupted retention owner must be proven stopped");
1803
+ return structuredClone(found);
1804
+ });
1805
+ const result = input.outcome.status === "found" ? await engine.provider.read(step.request, input.outcome.externalId) : null;
1806
+ if (input.outcome.status === "absent") text$2(input.outcome.evidenceRef, "Authoritative provider absence evidence");
1807
+ return engine.locked(async (invoice, state) => {
1808
+ const current = state?.steps.find((s) => s.key === input.stepKey);
1809
+ if (!state || current?.attemptId !== step.attemptId || current.status !== step.status) reject$2("Retention reconciliation owner changed");
1810
+ current.reconciliation = {
1811
+ outcome: input.outcome.status,
1812
+ recordedAt: (/* @__PURE__ */ new Date()).toISOString(),
1813
+ interruptedOwnerStopped: input.confirmInterruptedOwnerStopped === true,
1814
+ ...input.outcome.status === "found" ? { externalId: input.outcome.externalId } : { evidenceRef: input.outcome.evidenceRef }
1815
+ };
1816
+ if (result) {
1817
+ if (result.payloadHash !== step.request.payloadHash) reject$2("Retention reconciliation readback differs");
1818
+ current.result = result;
1819
+ current.status = "confirmed";
1820
+ } else current.status = "rejected";
1821
+ await engine.save(invoice, state);
1822
+ return state;
1823
+ });
1824
+ }
1825
+ //#endregion
1826
+ //#region src/ordinary-accounting.ts
1827
+ var hash$1 = (value) => createHash("sha256").update(JSON.stringify(value)).digest("hex");
1828
+ function reject$1(message) {
1829
+ throw new MoneyValidationError("ACCOUNTING_SYNC_RECONCILIATION_REQUIRED", message);
1830
+ }
1831
+ function text$1(value, label) {
1832
+ if (typeof value !== "string" || !value || value.trim() !== value) reject$1(`${label} is required`);
1833
+ }
1834
+ function date$1(value, label) {
1835
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(value) || !Number.isFinite(Date.parse(value)) || new Date(value).toISOString().slice(0, 10) !== value) reject$1(`${label} is invalid`);
1836
+ }
1837
+ function principal$1(input) {
1838
+ if (!input.tenantId || getTenantId() !== input.tenantId) reject$1("Ordinary accounting requires its active tenant");
1839
+ if (isMoneyTransaction(input.db)) reject$1("Provider writes cannot run inside a caller-owned money transaction");
1840
+ if (input.provider.type !== "quickbooks" || !input.provider.receivableTransfers) reject$1("Provider lacks reviewed receivable operations");
1841
+ }
1842
+ function syncedIdentity(invoice, mapping) {
1843
+ const sync = readFrozenAccountingSyncState(invoice);
1844
+ if (!sync || sync.status !== "synced" || sync.documentKind !== "invoice" || sync.provider !== "quickbooks" || sync.moneySnapshotId !== invoice.moneySnapshotId || sync.realmId !== mapping.realmId || sync.environment !== mapping.environment || invoice.externalProvider !== "quickbooks" || !invoice.externalId) reject$1("Ordinary accounting requires its reconciled frozen invoice export identity");
1845
+ }
1846
+ function readOrdinaryInvoiceAccountingState(invoice) {
1847
+ if (!invoice.ordinaryAccountingStateJson) return null;
1848
+ let state;
1849
+ try {
1850
+ state = JSON.parse(invoice.ordinaryAccountingStateJson);
1851
+ } catch {
1852
+ return reject$1("Malformed ordinary accounting state");
1853
+ }
1854
+ if (!state || !state.mapping || state.version !== 1 || state.kind !== "ordinary" || state.mapping.kind !== "ordinary" || state.invoiceId !== invoice.id || state.moneySnapshotId !== invoice.moneySnapshotId || state.externalInvoiceId !== null && state.externalInvoiceId !== invoice.externalId || state.currency !== invoice.currency || state.grossMinor !== invoice.totalAmount || state.mapping.customerRef !== invoice.customerExternalId || !Array.isArray(state.steps) || !Array.isArray(state.credits) || !Array.isArray(state.refunds) || invoice.retentionStateJson || invoice.retentionAccountingStateJson || invoice.moneyAuthority !== "calculated") reject$1("Ordinary provider source identity changed");
1855
+ if (state.externalInvoiceId !== null) syncedIdentity(invoice, state.mapping);
1856
+ return state;
1857
+ }
1858
+ async function locked$1(input, operation) {
1859
+ return withDocumentMoneyTransaction(input.db, async (tx) => {
1860
+ await lockTenantMoneyRuntime(tx, input.tenantId);
1861
+ const { invoice } = await lockAndReloadInvoice(tx, input.invoiceId, input.tenantId);
1862
+ return operation(invoice, readOrdinaryInvoiceAccountingState(invoice));
1863
+ });
1864
+ }
1865
+ async function save$1(invoice, state) {
1866
+ invoice.ordinaryAccountingStateJson = JSON.stringify(state);
1867
+ await invoice.saveDerived(DOCUMENT_MONEY_WRITE);
1868
+ }
1869
+ function refreshStatus$1(state) {
1870
+ state.status = state.steps.every((s) => s.status === "confirmed") && state.credits.every((c) => c.committed) && state.refunds.every((r) => r.committed) ? "ready" : "pending";
1871
+ }
1872
+ function requireReady$1(state) {
1873
+ if (!state || state.status !== "ready" || state.steps.some((s) => s.status !== "confirmed")) reject$1("Ordinary provider operations require reconciliation");
1874
+ return state;
1875
+ }
1876
+ function requestId$1(state, key) {
1877
+ return `smrt_ord_${hash$1([
1878
+ state.invoiceId,
1879
+ state.moneySnapshotId,
1880
+ state.mapping.realmId,
1881
+ state.mapping.environment,
1882
+ key
1883
+ ]).slice(0, 40)}`;
1884
+ }
1885
+ function executeStep$1(input, key, make) {
1886
+ return executeAccountingStep({
1887
+ locked: (operation) => locked$1(input, operation),
1888
+ save: save$1,
1889
+ provider: input.provider.receivableTransfers
1890
+ }, key, make);
1891
+ }
1892
+ function validateOrdinarySource(invoice, input) {
1893
+ if (invoice.kind !== "invoice" || !invoice.moneySnapshotId || invoice.retentionStateJson || invoice.retentionAccountingStateJson || invoice.moneyAuthority !== "calculated" || [
1894
+ InvoiceStatus.DRAFT,
1895
+ InvoiceStatus.CANCELLED,
1896
+ InvoiceStatus.WRITTEN_OFF
1897
+ ].includes(invoice.status) || invoice.collectionMethod || invoice.providerTaxAmount || invoice.currency !== input.mapping.currency || invoice.customerExternalId !== input.mapping.customerRef || input.invoiceMapping.realmId !== input.mapping.realmId || input.invoiceMapping.environment !== input.mapping.environment) reject$1("Ordinary accounting requires its issued, nonretained canonical frozen source");
1898
+ }
1899
+ async function syncOrdinaryInvoiceToAccounting(input) {
1900
+ principal$1(input);
1901
+ text$1(input.requestId, "Ordinary request");
1902
+ text$1(input.evidenceRef, "Ordinary evidence");
1903
+ if (input.mapping.kind !== "ordinary") reject$1("Ordinary mapping is required");
1904
+ await locked$1(input, async (invoice) => {
1905
+ validateOrdinarySource(invoice, input);
1906
+ await toFrozenInvoiceAccountingInput({
1907
+ db: invoice.db,
1908
+ tenantId: input.tenantId,
1909
+ invoiceId: input.invoiceId,
1910
+ mapping: input.invoiceMapping
1911
+ });
1912
+ });
1913
+ await input.provider.receivableTransfers.verifyMapping(input.mapping);
1914
+ await locked$1(input, async (invoice, state) => {
1915
+ validateOrdinarySource(invoice, input);
1916
+ const prior = readFrozenAccountingSyncState(invoice);
1917
+ if (prior) {
1918
+ const request = prepareQuickBooksInvoiceRequest({
1919
+ ...await toFrozenInvoiceAccountingInput({
1920
+ db: invoice.db,
1921
+ tenantId: input.tenantId,
1922
+ invoiceId: input.invoiceId,
1923
+ mapping: input.invoiceMapping
1924
+ }),
1925
+ externalId: void 0
1926
+ }, {
1927
+ requestId: prior.requestId,
1928
+ realmId: input.invoiceMapping.realmId,
1929
+ environment: input.invoiceMapping.environment
1930
+ });
1931
+ if (prior.provider !== "quickbooks" || prior.documentKind !== "invoice" || prior.moneySnapshotId !== invoice.moneySnapshotId || prior.realmId !== request.realmId || prior.environment !== request.environment || prior.request.payloadHash !== request.payloadHash) reject$1("Ordinary invoice mapping differs from its frozen export request");
1932
+ }
1933
+ if (state) {
1934
+ if (hash$1([
1935
+ state.requestId,
1936
+ state.evidenceRef,
1937
+ state.mapping,
1938
+ state.invoiceMapping
1939
+ ]) !== hash$1([
1940
+ input.requestId,
1941
+ input.evidenceRef,
1942
+ input.mapping,
1943
+ input.invoiceMapping
1944
+ ])) reject$1("Ordinary accounting initialization changed");
1945
+ return;
1946
+ }
1947
+ await save$1(invoice, {
1948
+ version: 1,
1949
+ kind: "ordinary",
1950
+ invoiceId: input.invoiceId,
1951
+ moneySnapshotId: invoice.moneySnapshotId,
1952
+ externalInvoiceId: null,
1953
+ invoiceMapping: structuredClone(input.invoiceMapping),
1954
+ requestId: input.requestId,
1955
+ evidenceRef: input.evidenceRef,
1956
+ currency: invoice.currency,
1957
+ grossMinor: invoice.totalAmount,
1958
+ mapping: structuredClone(input.mapping),
1959
+ status: "pending",
1960
+ steps: [],
1961
+ credits: [],
1962
+ refunds: []
1963
+ });
1964
+ });
1965
+ const result = await withOrdinaryAccountingAuthority(input.tenantId, input.invoiceId, () => syncFrozenInvoiceToAccounting({
1966
+ ...input,
1967
+ mapping: input.invoiceMapping
1968
+ }));
1969
+ return locked$1(input, async (invoice, state) => {
1970
+ if (!state) reject$1("Ordinary provider reservation disappeared");
1971
+ syncedIdentity(invoice, state.mapping);
1972
+ state.externalInvoiceId = result.externalId;
1973
+ refreshStatus$1(state);
1974
+ await save$1(invoice, state);
1975
+ return state;
1976
+ });
1977
+ }
1978
+ async function reconcileOrdinaryBaseInvoice(input) {
1979
+ principal$1(input);
1980
+ await locked$1(input, async (_invoice, state) => {
1981
+ if (!state || hash$1(state.invoiceMapping) !== hash$1(input.mapping)) reject$1("Ordinary base mapping differs");
1982
+ });
1983
+ return reconcileFrozenInvoiceAccountingSync(input);
1984
+ }
1985
+ async function reconcileOrdinaryAccountingStep(input) {
1986
+ principal$1(input);
1987
+ return reconcileAccountingStep({
1988
+ locked: (operation) => locked$1(input, operation),
1989
+ save: save$1,
1990
+ provider: input.provider.receivableTransfers
1991
+ }, input);
1992
+ }
1993
+ async function syncOrdinaryCreditToAccounting(input) {
1994
+ principal$1(input);
1995
+ text$1(input.requestId, "Credit adjustment request");
1996
+ text$1(input.evidenceRef, "Credit adjustment evidence");
1997
+ date$1(input.effectiveOn, "Credit adjustment date");
1998
+ const reserved = await locked$1(input, async (invoice, state) => {
1999
+ if (!state) reject$1("Ordinary provider contract is missing");
2000
+ const credit = await (await InvoiceCollection.create({ db: invoice.db })).get({ id: input.creditInvoiceId }, { cache: false });
2001
+ if (!credit || credit.tenantId !== input.tenantId || credit.customerId !== invoice.customerId || credit.creditedInvoiceId !== invoice.id || credit.kind !== "credit_note" || !credit.moneySnapshotId || [InvoiceStatus.DRAFT, InvoiceStatus.CANCELLED].includes(credit.status) || credit.currency !== state.currency || credit.customerExternalId !== state.mapping.customerRef) reject$1("Credit adjustment requires its issued same-customer source credit");
2002
+ if (input.creditMapping.realmId !== state.mapping.realmId || input.creditMapping.environment !== state.mapping.environment) reject$1("Credit adjustment provider scope differs");
2003
+ const prior = state.credits.find((c) => c.creditId === input.creditInvoiceId || c.requestId === input.requestId);
2004
+ if (prior) {
2005
+ if (prior.creditId !== input.creditInvoiceId || prior.requestId !== input.requestId || prior.moneySnapshotId !== credit.moneySnapshotId || prior.grossMinor !== credit.totalAmount || prior.evidenceRef !== input.evidenceRef || prior.effectiveOn !== input.effectiveOn || hash$1(prior.mapping) !== hash$1(input.creditMapping)) reject$1("Credit adjustment identity reused with changed facts");
2006
+ return structuredClone(prior);
2007
+ }
2008
+ requireReady$1(state);
2009
+ if (state.credits.reduce((sum, c) => sum + c.grossMinor, 0) + credit.totalAmount > invoice.creditedAmount) reject$1("Provider credit exceeds issued source credit capacity");
2010
+ const next = {
2011
+ creditId: input.creditInvoiceId,
2012
+ moneySnapshotId: credit.moneySnapshotId,
2013
+ requestId: input.requestId,
2014
+ evidenceRef: input.evidenceRef,
2015
+ effectiveOn: input.effectiveOn,
2016
+ grossMinor: credit.totalAmount,
2017
+ appliedMinor: credit.creditedAmount,
2018
+ mapping: structuredClone(input.creditMapping),
2019
+ committed: false
2020
+ };
2021
+ state.credits.push(next);
2022
+ state.status = "pending";
2023
+ await save$1(invoice, state);
2024
+ return next;
2025
+ });
2026
+ const creditResult = await withOrdinaryAccountingAuthority(input.tenantId, input.invoiceId, () => syncFrozenInvoiceToAccounting({
2027
+ db: input.db,
2028
+ tenantId: input.tenantId,
2029
+ invoiceId: input.creditInvoiceId,
2030
+ provider: input.provider,
2031
+ mapping: input.creditMapping
2032
+ }));
2033
+ const prefix = `credit:${input.requestId}`;
2034
+ const creditSource = (state) => ({
2035
+ type: "CreditMemo",
2036
+ id: creditResult.externalId,
2037
+ customerRef: state.mapping.customerRef,
2038
+ evidenceRef: reserved.moneySnapshotId
2039
+ });
2040
+ if (reserved.appliedMinor > 0) await executeStep$1(input, `${prefix}:due-application`, (invoice, state) => prepareQuickBooksReceivableRequest({
2041
+ kind: "application",
2042
+ mapping: state.mapping,
2043
+ source: creditSource(state),
2044
+ requestId: requestId$1(state, `${prefix}:due-application`),
2045
+ effectiveOn: reserved.effectiveOn,
2046
+ evidenceRef: reserved.evidenceRef,
2047
+ amountMinor: reserved.appliedMinor,
2048
+ debit: {
2049
+ type: "Invoice",
2050
+ id: invoice.externalId
2051
+ },
2052
+ credit: {
2053
+ type: "CreditMemo",
2054
+ id: creditResult.externalId
2055
+ }
2056
+ }));
2057
+ return locked$1(input, async (invoice, state) => {
2058
+ if (!state) reject$1("Ordinary provider state is missing");
2059
+ const credit = state.credits.find((c) => c.creditId === input.creditInvoiceId);
2060
+ if (!credit) reject$1("Credit reservation disappeared");
2061
+ credit.committed = true;
2062
+ refreshStatus$1(state);
2063
+ await save$1(invoice, state);
2064
+ return state;
2065
+ });
2066
+ }
2067
+ async function syncOrdinaryRefundToAccounting(input) {
2068
+ principal$1(input);
2069
+ text$1(input.requestId, "Refund recording request");
2070
+ text$1(input.evidenceRef, "Refund settlement evidence");
2071
+ date$1(input.effectiveOn, "Refund effective date");
2072
+ const reservation = await locked$1(input, async (invoice, state) => {
2073
+ if (!state) reject$1("Ordinary provider contract is missing");
2074
+ const credit = state.credits.find((c) => c.creditId === input.creditInvoiceId && c.committed);
2075
+ if (!credit) reject$1("Refund requires its reconciled provider credit");
2076
+ const payment = await (await PaymentCollection.create({ db: invoice.db })).get({ id: input.paymentId }, { cache: false });
2077
+ const creditInvoice = await (await InvoiceCollection.create({ db: invoice.db })).get({ id: input.creditInvoiceId }, { cache: false });
2078
+ if (!payment || !creditInvoice || payment.tenantId !== input.tenantId || creditInvoice.tenantId !== input.tenantId || creditInvoice.customerId !== invoice.customerId || creditInvoice.currency !== state.currency || creditInvoice.creditedInvoiceId !== invoice.id || payment.customerId !== invoice.customerId || payment.currency !== state.currency || payment.kind !== "refund" || payment.status !== "completed" || !payment.journalId || !payment.paidAt || new Date(payment.paidAt).toISOString().slice(0, 10) !== input.effectiveOn || !creditInvoice.externalId || creditInvoice.moneySnapshotId !== credit.moneySnapshotId) reject$1("Provider refund requires its completed same-customer local cash journal and source credit");
2079
+ const allocations = await (await PaymentAllocationCollection.create({ db: invoice.db })).findByPayment(input.paymentId);
2080
+ if (allocations.length !== 1 || allocations[0].invoiceId !== input.creditInvoiceId || allocations[0].amount !== payment.amount) reject$1("Refund recording requires one exact full source-credit allocation");
2081
+ const fingerprint = hash$1([
2082
+ payment.id,
2083
+ payment.customerId,
2084
+ payment.currency,
2085
+ payment.amount,
2086
+ payment.journalId,
2087
+ new Date(payment.paidAt).toISOString(),
2088
+ allocations[0].id,
2089
+ allocations[0].amount,
2090
+ credit.moneySnapshotId
2091
+ ]);
2092
+ const next = {
2093
+ paymentId: input.paymentId,
2094
+ creditId: input.creditInvoiceId,
2095
+ requestId: input.requestId,
2096
+ evidenceRef: input.evidenceRef,
2097
+ effectiveOn: input.effectiveOn,
2098
+ amountMinor: payment.amount,
2099
+ paymentFingerprint: fingerprint,
2100
+ committed: false
2101
+ };
2102
+ const prior = state.refunds.find((r) => r.paymentId === input.paymentId || r.requestId === input.requestId);
2103
+ if (prior) {
2104
+ if (hash$1({
2105
+ ...prior,
2106
+ committed: false
2107
+ }) !== hash$1(next)) reject$1("Refund recording identity reused with changed facts");
2108
+ return {
2109
+ ...prior,
2110
+ externalCreditId: creditInvoice.externalId
2111
+ };
2112
+ }
2113
+ requireReady$1(state);
2114
+ if (!state.mapping.cashAccountRef) reject$1("Refund provider bank account must be explicitly reviewed");
2115
+ if (state.refunds.filter((r) => r.creditId === input.creditInvoiceId).reduce((sum, r) => sum + r.amountMinor, 0) + payment.amount > credit.grossMinor - credit.appliedMinor) reject$1("Refund exceeds unapplied provider credit capacity");
2116
+ if (payment.ordinaryAccountingBindingJson || payment.retentionAccountingBindingJson) reject$1("Refund is already bound to a provider operation");
2117
+ payment.ordinaryAccountingBindingJson = JSON.stringify({
2118
+ invoiceId: input.invoiceId,
2119
+ tenantId: input.tenantId,
2120
+ requestId: input.requestId,
2121
+ paymentFingerprint: fingerprint
2122
+ });
2123
+ await withOrdinaryAccountingAuthority(input.tenantId, input.invoiceId, () => payment.save());
2124
+ state.refunds.push(next);
2125
+ state.status = "pending";
2126
+ await save$1(invoice, state);
2127
+ return {
2128
+ ...next,
2129
+ externalCreditId: creditInvoice.externalId
2130
+ };
2131
+ });
2132
+ const prefix = `refund:${input.requestId}`;
2133
+ const creditSource = (state) => ({
2134
+ type: "CreditMemo",
2135
+ id: reservation.externalCreditId,
2136
+ customerRef: state.mapping.customerRef,
2137
+ evidenceRef: reservation.paymentFingerprint
2138
+ });
2139
+ const journal = await executeStep$1(input, prefix, (_invoice, state) => prepareQuickBooksReceivableRequest({
2140
+ kind: "cash-refund",
2141
+ mapping: state.mapping,
2142
+ source: creditSource(state),
2143
+ requestId: requestId$1(state, prefix),
2144
+ effectiveOn: reservation.effectiveOn,
2145
+ evidenceRef: reservation.evidenceRef,
2146
+ amountMinor: reservation.amountMinor
2147
+ }));
2148
+ await executeStep$1(input, `${prefix}:application`, (_invoice, state) => prepareQuickBooksReceivableRequest({
2149
+ kind: "application",
2150
+ mapping: state.mapping,
2151
+ source: creditSource(state),
2152
+ requestId: requestId$1(state, `${prefix}:application`),
2153
+ effectiveOn: reservation.effectiveOn,
2154
+ evidenceRef: reservation.evidenceRef,
2155
+ amountMinor: reservation.amountMinor,
2156
+ debit: {
2157
+ type: "JournalEntry",
2158
+ id: journal.externalId
2159
+ },
2160
+ credit: {
2161
+ type: "CreditMemo",
2162
+ id: reservation.externalCreditId
2163
+ }
2164
+ }));
2165
+ return locked$1(input, async (invoice, state) => {
2166
+ if (!state) reject$1("Ordinary provider state disappeared");
2167
+ const refund = state.refunds.find((r) => r.requestId === input.requestId);
2168
+ if (!refund) reject$1("Refund reservation disappeared");
2169
+ refund.committed = true;
2170
+ refreshStatus$1(state);
2171
+ await save$1(invoice, state);
2172
+ return state;
2173
+ });
2174
+ }
2175
+ async function reconcileOrdinaryCreditAccounting(input) {
2176
+ principal$1(input);
2177
+ const mapping = await locked$1(input, async (_invoice, state) => {
2178
+ const reserved = state?.credits.find((credit) => credit.creditId === input.creditInvoiceId);
2179
+ if (!reserved) reject$1("Ordinary credit has no approved provider reservation");
2180
+ return structuredClone(reserved.mapping);
2181
+ });
2182
+ return withOrdinaryAccountingAuthority(input.tenantId, input.invoiceId, () => reconcileFrozenInvoiceAccountingSync({
2183
+ ...input,
2184
+ invoiceId: input.creditInvoiceId,
2185
+ mapping
2186
+ }));
2187
+ }
2188
+ async function reviewOrdinaryCredit(input, read) {
2189
+ if (getTenantId() !== input.tenantId) reject$1("Ordinary review requires its active tenant");
2190
+ return withDocumentMoneyTransaction(input.db, async (tx) => {
2191
+ await lockTenantMoneyRuntime(tx, input.tenantId);
2192
+ const { invoice } = await lockAndReloadInvoice(tx, input.invoiceId, input.tenantId);
2193
+ if (!readOrdinaryInvoiceAccountingState(invoice)) reject$1("Ordinary provider contract is missing");
2194
+ const credit = await (await InvoiceCollection.create({ db: tx })).get({ id: input.creditInvoiceId }, { cache: false });
2195
+ if (!credit || credit.tenantId !== input.tenantId || credit.creditedInvoiceId !== invoice.id || credit.kind !== "credit_note" || credit.customerId !== invoice.customerId || credit.currency !== invoice.currency || credit.moneyAuthority !== "calculated") reject$1("Ordinary credit review requires exact source lineage");
2196
+ return withOrdinaryAccountingAuthority(input.tenantId, input.invoiceId, () => read({
2197
+ db: tx,
2198
+ tenantId: input.tenantId,
2199
+ invoiceId: input.creditInvoiceId
2200
+ }));
2201
+ });
2202
+ }
2203
+ function loadOrdinaryCreditAccountingSnapshot(input) {
2204
+ return reviewOrdinaryCredit(input, loadFrozenInvoiceAccountingSnapshot);
2205
+ }
2206
+ function toOrdinaryCreditAccountingInput(input) {
2207
+ return reviewOrdinaryCredit(input, async (scope) => await toFrozenInvoiceAccountingInput({
2208
+ ...scope,
2209
+ mapping: input.mapping
2210
+ }));
2211
+ }
2212
+ //#endregion
1732
2213
  //#region src/retention-accounting.ts
1733
2214
  var hash = (value) => createHash("sha256").update(JSON.stringify(value)).digest("hex");
1734
2215
  function reject(message) {
@@ -1841,57 +2322,11 @@ function source(invoice, state) {
1841
2322
  };
1842
2323
  }
1843
2324
  async function executeStep(input, key, make) {
1844
- const prepared = await locked(input, async (invoice, state) => {
1845
- if (!state) reject("Retention provider contract is missing");
1846
- const expected = make(invoice, state), prior = state.steps.find((s) => s.key === key);
1847
- if (prior && prior.request.payloadHash !== expected.payloadHash) reject("Retention operation identity reused with changed facts");
1848
- if (prior?.status === "confirmed") {
1849
- if (!prior.result) reject("Confirmed retention step has no readback");
1850
- return { complete: prior.result };
1851
- }
1852
- if (prior && prior.status !== "rejected") reject("Retention operation has an unresolved remote owner");
1853
- if (state.steps.some((s) => s.key !== key && s.status !== "confirmed")) reject("Another retention operation requires reconciliation");
1854
- const step2 = {
1855
- key,
1856
- status: "in_flight",
1857
- attemptId: randomUUID(),
1858
- request: expected,
1859
- startedAt: (/* @__PURE__ */ new Date()).toISOString(),
1860
- priorAttempts: prior ? [...prior.priorAttempts ?? [], {
1861
- attemptId: prior.attemptId,
1862
- status: prior.status,
1863
- startedAt: prior.startedAt,
1864
- reconciliation: prior.reconciliation
1865
- }] : []
1866
- };
1867
- if (prior) state.steps[state.steps.indexOf(prior)] = step2;
1868
- else state.steps.push(step2);
1869
- await save(invoice, state);
1870
- return { step: step2 };
1871
- });
1872
- if ("complete" in prepared && prepared.complete) return prepared.complete;
1873
- if (!prepared.step) reject("Prepared retention step is missing");
1874
- const step = prepared.step;
1875
- let result;
1876
- try {
1877
- result = await input.provider.receivableTransfers.execute(step.request);
1878
- } catch (error) {
1879
- await locked(input, async (invoice, state) => {
1880
- const current = state?.steps.find((s) => s.key === key);
1881
- if (!state || current?.attemptId !== step.attemptId || current.status !== "in_flight") reject("Retention step ownership changed after remote failure");
1882
- current.status = error?.outcome === "rejected" ? "rejected" : "unknown";
1883
- await save(invoice, state);
1884
- });
1885
- throw error;
1886
- }
1887
- return locked(input, async (invoice, state) => {
1888
- const current = state?.steps.find((s) => s.key === key);
1889
- if (!state || current?.attemptId !== step.attemptId || current.status !== "in_flight" || result.payloadHash !== step.request.payloadHash) reject("Retention step ownership or readback changed after write");
1890
- current.status = "confirmed";
1891
- current.result = structuredClone(result);
1892
- await save(invoice, state);
1893
- return result;
1894
- });
2325
+ return executeAccountingStep({
2326
+ locked: (operation) => locked(input, operation),
2327
+ save,
2328
+ provider: input.provider.receivableTransfers
2329
+ }, key, make);
1895
2330
  }
1896
2331
  async function syncRetainedInvoiceToAccounting(input) {
1897
2332
  principal(input);
@@ -2057,31 +2492,11 @@ async function releaseRetainedInvoiceToAccounting(input) {
2057
2492
  }
2058
2493
  async function reconcileRetainedAccountingStep(input) {
2059
2494
  principal(input);
2060
- const step = await locked(input, async (_invoice, state) => {
2061
- const found = state?.steps.find((s) => s.key === input.stepKey);
2062
- if (!found || found.request.requestId !== input.requestId || found.attemptId !== input.attemptId || !["in_flight", "unknown"].includes(found.status)) reject("Observed retention reconciliation owner differs");
2063
- if (found.status === "in_flight" && !input.confirmInterruptedOwnerStopped) reject("Interrupted retention owner must be proven stopped");
2064
- return structuredClone(found);
2065
- });
2066
- const result = input.outcome.status === "found" ? await input.provider.receivableTransfers.read(step.request, input.outcome.externalId) : null;
2067
- if (input.outcome.status === "absent") text(input.outcome.evidenceRef, "Authoritative provider absence evidence");
2068
- return locked(input, async (invoice, state) => {
2069
- const current = state?.steps.find((s) => s.key === input.stepKey);
2070
- if (!state || current?.attemptId !== step.attemptId || current.status !== step.status) reject("Retention reconciliation owner changed");
2071
- current.reconciliation = {
2072
- outcome: input.outcome.status,
2073
- recordedAt: (/* @__PURE__ */ new Date()).toISOString(),
2074
- interruptedOwnerStopped: input.confirmInterruptedOwnerStopped === true,
2075
- ...input.outcome.status === "found" ? { externalId: input.outcome.externalId } : { evidenceRef: input.outcome.evidenceRef }
2076
- };
2077
- if (result) {
2078
- if (result.payloadHash !== step.request.payloadHash) reject("Retention reconciliation readback differs");
2079
- current.result = result;
2080
- current.status = "confirmed";
2081
- } else current.status = "rejected";
2082
- await save(invoice, state);
2083
- return state;
2084
- });
2495
+ return reconcileAccountingStep({
2496
+ locked: (operation) => locked(input, operation),
2497
+ save,
2498
+ provider: input.provider.receivableTransfers
2499
+ }, input);
2085
2500
  }
2086
2501
  async function reconcileRetainedBaseInvoice(input) {
2087
2502
  principal(input);
@@ -2318,6 +2733,6 @@ async function reconcileRetainedCreditAccounting(input) {
2318
2733
  }));
2319
2734
  }
2320
2735
  //#endregion
2321
- export { historicalCreditRefundCommittedTotal as C, Payment as E, PaymentAllocation as S, PaymentCollection_exports as T, reconcileFrozenInvoiceAccountingSync as _, reconcileRetainedBaseInvoice as a, PaymentAllocationCollection as b, syncRetainedCreditToAccounting as c, toRetainedCreditAccountingInput as d, toRetainedInvoiceAccountingInput as f, readFrozenAccountingSyncState as g, loadFrozenInvoiceAccountingSnapshot as h, reconcileRetainedAccountingStep as i, syncRetainedInvoiceToAccounting as l, invoice_accounting_sync_exports as m, loadRetainedInvoiceAccountingSnapshot as n, reconcileRetainedCreditAccounting as o, calculateInvoiceMinorLine as p, readRetainedInvoiceAccountingState as r, releaseRetainedInvoiceToAccounting as s, loadRetainedCreditAccountingSnapshot as t, syncRetainedRefundToAccounting as u, syncFrozenInvoiceToAccounting as v, PaymentCollection as w, PaymentAllocationCollection_exports as x, toFrozenInvoiceAccountingInput as y };
2736
+ export { PaymentAllocationCollection_exports as A, invoice_accounting_sync_exports as C, syncFrozenInvoiceToAccounting as D, reconcileFrozenInvoiceAccountingSync as E, Payment as F, historicalCreditRefundCommittedTotal as M, PaymentCollection as N, toFrozenInvoiceAccountingInput as O, PaymentCollection_exports as P, calculateInvoiceMinorLine as S, readFrozenAccountingSyncState as T, reconcileOrdinaryCreditAccounting as _, reconcileRetainedBaseInvoice as a, syncOrdinaryRefundToAccounting as b, syncRetainedCreditToAccounting as c, toRetainedCreditAccountingInput as d, toRetainedInvoiceAccountingInput as f, reconcileOrdinaryBaseInvoice as g, reconcileOrdinaryAccountingStep as h, reconcileRetainedAccountingStep as i, PaymentAllocation as j, PaymentAllocationCollection as k, syncRetainedInvoiceToAccounting as l, readOrdinaryInvoiceAccountingState as m, loadRetainedInvoiceAccountingSnapshot as n, reconcileRetainedCreditAccounting as o, loadOrdinaryCreditAccountingSnapshot as p, readRetainedInvoiceAccountingState as r, releaseRetainedInvoiceToAccounting as s, loadRetainedCreditAccountingSnapshot as t, syncRetainedRefundToAccounting as u, syncOrdinaryCreditToAccounting as v, loadFrozenInvoiceAccountingSnapshot as w, toOrdinaryCreditAccountingInput as x, syncOrdinaryInvoiceToAccounting as y };
2322
2737
 
2323
- //# sourceMappingURL=retention-accounting-Brdj9x-V.js.map
2738
+ //# sourceMappingURL=retention-accounting-c7kY7gFU.js.map