@happyvertical/smrt-commerce 0.57.3 → 0.57.4

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 (161) hide show
  1. package/AGENTS.md +17 -0
  2. package/README.md +130 -0
  3. package/agents/accounting-snapshot-mapper.md +11 -0
  4. package/agents/contract-billing-schedules.md +67 -0
  5. package/agents/contract-money.md +81 -0
  6. package/agents/customer-funds.md +96 -0
  7. package/agents/historical-sales.md +132 -0
  8. package/agents/money-calculator.md +36 -0
  9. package/agents/money-model.md +6 -3
  10. package/agents/observed-purchase-prices.md +37 -0
  11. package/agents/payment-allocations.md +59 -0
  12. package/agents/received-sales-contract-money.md +38 -0
  13. package/dist/accounting-snapshot.d.ts +8 -1
  14. package/dist/accounting-snapshot.d.ts.map +1 -1
  15. package/dist/allocation-integrity.d.ts.map +1 -1
  16. package/dist/chunks/{ContractLineItemCollection-BZcrlrrY.js → ContractLineItemCollection-J4xtRtzE.js} +6 -6
  17. package/dist/chunks/{ContractLineItemCollection-BZcrlrrY.js.map → ContractLineItemCollection-J4xtRtzE.js.map} +1 -1
  18. package/dist/chunks/DocumentTaxCollection-C42x0YLW.js +4385 -0
  19. package/dist/chunks/DocumentTaxCollection-C42x0YLW.js.map +1 -0
  20. package/dist/chunks/HistoricalCustomerFundsCollections-B5x8gTW3.js +170 -0
  21. package/dist/chunks/HistoricalCustomerFundsCollections-B5x8gTW3.js.map +1 -0
  22. package/dist/chunks/{InvoiceCollection-cinzAqt6.js → InvoiceCollection-BIcge9Wl.js} +131 -18
  23. package/dist/chunks/InvoiceCollection-BIcge9Wl.js.map +1 -0
  24. package/dist/chunks/{TaxCodeCollection-DaBOPG9c.js → TaxCodeCollection-RWdVaheF.js} +3 -4
  25. package/dist/chunks/TaxCodeCollection-RWdVaheF.js.map +1 -0
  26. package/dist/chunks/{TaxComponentCollection-C4zxnyVu.js → TaxComponentCollection-Dt2jeWiC.js} +3 -3
  27. package/dist/chunks/{TaxComponentCollection-C4zxnyVu.js.map → TaxComponentCollection-Dt2jeWiC.js.map} +1 -1
  28. package/dist/chunks/{allocation-integrity-WmWyXhtG.js → allocation-integrity-DJ7-LY1j.js} +7 -7
  29. package/dist/chunks/{allocation-integrity-WmWyXhtG.js.map → allocation-integrity-DJ7-LY1j.js.map} +1 -1
  30. package/dist/chunks/{contract-money-EuToOghh.js → contract-money-DSRTMoXm.js} +45 -12
  31. package/dist/chunks/contract-money-DSRTMoXm.js.map +1 -0
  32. package/dist/chunks/customer-funds-internal-BQzoJXK5.js +24 -0
  33. package/dist/chunks/customer-funds-internal-BQzoJXK5.js.map +1 -0
  34. package/dist/chunks/{detect-CY9ufaFb.js → detect-DAE-_NAk.js} +5 -2
  35. package/dist/chunks/{detect-CY9ufaFb.js.map → detect-DAE-_NAk.js.map} +1 -1
  36. package/dist/chunks/historical-commerce-internal-C9ButfuH.js +18 -0
  37. package/dist/chunks/historical-commerce-internal-C9ButfuH.js.map +1 -0
  38. package/dist/chunks/{invoice-posting-C2i5dOVZ.js → invoice-posting-BeTPw3h9.js} +5 -5
  39. package/dist/chunks/invoice-posting-BeTPw3h9.js.map +1 -0
  40. package/dist/chunks/retention-accounting-Brdj9x-V.js +2323 -0
  41. package/dist/chunks/retention-accounting-Brdj9x-V.js.map +1 -0
  42. package/dist/chunks/retention-accounting-internal-CBQRvd74.js +17 -0
  43. package/dist/chunks/retention-accounting-internal-CBQRvd74.js.map +1 -0
  44. package/dist/chunks/{tenant-money-barrier-6TlqUeVj.js → tenant-money-barrier-DoF6lR8h.js} +5 -5
  45. package/dist/chunks/{tenant-money-barrier-6TlqUeVj.js.map → tenant-money-barrier-DoF6lR8h.js.map} +1 -1
  46. package/dist/chunks/types-Bbm0Xflc.js.map +1 -1
  47. package/dist/collections/DocumentTaxCollection.d.ts +4 -1
  48. package/dist/collections/DocumentTaxCollection.d.ts.map +1 -1
  49. package/dist/collections/HistoricalCustomerFundsCollections.d.ts +10 -0
  50. package/dist/collections/HistoricalCustomerFundsCollections.d.ts.map +1 -0
  51. package/dist/collections/HistoricalSalesLineCollection.d.ts +6 -0
  52. package/dist/collections/HistoricalSalesLineCollection.d.ts.map +1 -0
  53. package/dist/collections/PaymentAllocationCollection.d.ts +2 -6
  54. package/dist/collections/PaymentAllocationCollection.d.ts.map +1 -1
  55. package/dist/collections/PurchasePriceObservationCollection.d.ts +6 -0
  56. package/dist/collections/PurchasePriceObservationCollection.d.ts.map +1 -0
  57. package/dist/collections/index.d.ts +1 -0
  58. package/dist/collections/index.d.ts.map +1 -1
  59. package/dist/contract-billing-schedule.d.ts +83 -0
  60. package/dist/contract-billing-schedule.d.ts.map +1 -0
  61. package/dist/contract-money.d.ts +2 -0
  62. package/dist/contract-money.d.ts.map +1 -1
  63. package/dist/customer-funds-internal.d.ts +6 -0
  64. package/dist/customer-funds-internal.d.ts.map +1 -0
  65. package/dist/customer-funds.d.ts +108 -0
  66. package/dist/customer-funds.d.ts.map +1 -0
  67. package/dist/document-money.d.ts +11 -0
  68. package/dist/document-money.d.ts.map +1 -1
  69. package/dist/historical-commerce-internal.d.ts +3 -0
  70. package/dist/historical-commerce-internal.d.ts.map +1 -0
  71. package/dist/historical-customer-funds-types.d.ts +113 -0
  72. package/dist/historical-customer-funds-types.d.ts.map +1 -0
  73. package/dist/historical-customer-funds.d.ts +23 -0
  74. package/dist/historical-customer-funds.d.ts.map +1 -0
  75. package/dist/historical-funds-internal.d.ts +5 -0
  76. package/dist/historical-funds-internal.d.ts.map +1 -0
  77. package/dist/historical-sales-money.d.ts +22 -0
  78. package/dist/historical-sales-money.d.ts.map +1 -0
  79. package/dist/historical-sales-reports.d.ts +31 -0
  80. package/dist/historical-sales-reports.d.ts.map +1 -0
  81. package/dist/historical-sales-types.d.ts +106 -0
  82. package/dist/historical-sales-types.d.ts.map +1 -0
  83. package/dist/historical-sales-validation.d.ts +12 -0
  84. package/dist/historical-sales-validation.d.ts.map +1 -0
  85. package/dist/index.d.ts +21 -0
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.js +1668 -1643
  88. package/dist/index.js.map +1 -1
  89. package/dist/invoice-accounting-sync.d.ts +0 -1
  90. package/dist/invoice-accounting-sync.d.ts.map +1 -1
  91. package/dist/invoice-mcp.d.ts.map +1 -1
  92. package/dist/invoice-posting.d.ts.map +1 -1
  93. package/dist/invoice-retention.d.ts +16 -0
  94. package/dist/invoice-retention.d.ts.map +1 -0
  95. package/dist/invoices.d.ts +2 -0
  96. package/dist/invoices.d.ts.map +1 -1
  97. package/dist/invoices.js +2 -2
  98. package/dist/manifest.json +7563 -4419
  99. package/dist/models/Contract.d.ts +14 -0
  100. package/dist/models/Contract.d.ts.map +1 -1
  101. package/dist/models/DocumentTax.d.ts +2 -0
  102. package/dist/models/DocumentTax.d.ts.map +1 -1
  103. package/dist/models/HistoricalCustomerFunds.d.ts +36 -0
  104. package/dist/models/HistoricalCustomerFunds.d.ts.map +1 -0
  105. package/dist/models/HistoricalCustomerFundsAllocation.d.ts +32 -0
  106. package/dist/models/HistoricalCustomerFundsAllocation.d.ts.map +1 -0
  107. package/dist/models/HistoricalSalesLine.d.ts +29 -0
  108. package/dist/models/HistoricalSalesLine.d.ts.map +1 -0
  109. package/dist/models/Invoice.d.ts +10 -1
  110. package/dist/models/Invoice.d.ts.map +1 -1
  111. package/dist/models/Payment.d.ts +7 -1
  112. package/dist/models/Payment.d.ts.map +1 -1
  113. package/dist/models/PaymentAllocation.d.ts +3 -1
  114. package/dist/models/PaymentAllocation.d.ts.map +1 -1
  115. package/dist/models/PaymentIntent.d.ts.map +1 -1
  116. package/dist/models/Payout.d.ts.map +1 -1
  117. package/dist/models/PurchasePriceObservation.d.ts +15 -0
  118. package/dist/models/PurchasePriceObservation.d.ts.map +1 -0
  119. package/dist/models/TaxCode.d.ts +1 -1
  120. package/dist/models/TaxCode.d.ts.map +1 -1
  121. package/dist/models/index.d.ts +1 -0
  122. package/dist/models/index.d.ts.map +1 -1
  123. package/dist/money.d.ts +5 -1
  124. package/dist/money.d.ts.map +1 -1
  125. package/dist/money.js +62 -15
  126. package/dist/money.js.map +1 -1
  127. package/dist/observed-purchase-price-internal.d.ts +3 -0
  128. package/dist/observed-purchase-price-internal.d.ts.map +1 -0
  129. package/dist/observed-purchase-price.d.ts +71 -0
  130. package/dist/observed-purchase-price.d.ts.map +1 -0
  131. package/dist/received-purchase-money.d.ts +87 -0
  132. package/dist/received-purchase-money.d.ts.map +1 -0
  133. package/dist/recipes.d.ts +4 -1
  134. package/dist/recipes.d.ts.map +1 -1
  135. package/dist/retention-accounting-internal.d.ts +3 -0
  136. package/dist/retention-accounting-internal.d.ts.map +1 -0
  137. package/dist/retention-accounting.d.ts +164 -0
  138. package/dist/retention-accounting.d.ts.map +1 -0
  139. package/dist/retention-money.d.ts +43 -0
  140. package/dist/retention-money.d.ts.map +1 -0
  141. package/dist/smrt-knowledge.json +1866 -113
  142. package/dist/tax/cookbook.d.ts.map +1 -1
  143. package/dist/tax-summary.d.ts +1 -0
  144. package/dist/tax-summary.d.ts.map +1 -1
  145. package/dist/types/index.d.ts +20 -1
  146. package/dist/types/index.d.ts.map +1 -1
  147. package/package.json +16 -16
  148. package/dist/chunks/CustomerCollection-BIPH2ZUx.js +0 -99
  149. package/dist/chunks/CustomerCollection-BIPH2ZUx.js.map +0 -1
  150. package/dist/chunks/DocumentTaxCollection-DDzlywMW.js +0 -1666
  151. package/dist/chunks/DocumentTaxCollection-DDzlywMW.js.map +0 -1
  152. package/dist/chunks/InvoiceCollection-cinzAqt6.js.map +0 -1
  153. package/dist/chunks/TaxCodeCollection-DaBOPG9c.js.map +0 -1
  154. package/dist/chunks/VendorCollection-D6ZcUYy8.js +0 -100
  155. package/dist/chunks/VendorCollection-D6ZcUYy8.js.map +0 -1
  156. package/dist/chunks/calculations-C9daQLsh.js +0 -82
  157. package/dist/chunks/calculations-C9daQLsh.js.map +0 -1
  158. package/dist/chunks/contract-money-EuToOghh.js.map +0 -1
  159. package/dist/chunks/document-money-DV5t4vlK.js +0 -1186
  160. package/dist/chunks/document-money-DV5t4vlK.js.map +0 -1
  161. package/dist/chunks/invoice-posting-C2i5dOVZ.js.map +0 -1
@@ -0,0 +1,170 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
+ import { t as assertHistoricalCommerceWrite } from "./historical-commerce-internal-C9ButfuH.js";
3
+ import { SmrtCollection, SmrtObject, crossPackageRef, field, foreignKey, smrt } from "@happyvertical/smrt-core";
4
+ import { TenantScoped, tenantId } from "@happyvertical/smrt-tenancy";
5
+ //#region src/models/HistoricalCustomerFunds.ts
6
+ var __defProp$1 = Object.defineProperty;
7
+ var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
8
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, {
9
+ enumerable: true,
10
+ configurable: true,
11
+ writable: true,
12
+ value
13
+ }) : obj[key] = value;
14
+ var __decorateClass$1 = (decorators, target, key, kind) => {
15
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1(target, key) : target;
16
+ for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
17
+ if (kind && result) __defProp$1(target, key, result);
18
+ return result;
19
+ };
20
+ var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
21
+ var HistoricalCustomerFunds = class extends SmrtObject {
22
+ tenantId = "";
23
+ customerId = "";
24
+ contractId = null;
25
+ sourceKeyHash = "";
26
+ kind = "receipt";
27
+ origin = "historical";
28
+ paymentId = null;
29
+ currency = "";
30
+ amountMinor = 0;
31
+ effectiveOn = "";
32
+ sourceReceiptId = null;
33
+ sourceCreditNoteId = null;
34
+ snapshotJson = "";
35
+ constructor(options = {}) {
36
+ super(options);
37
+ for (const key of [
38
+ "tenantId",
39
+ "customerId",
40
+ "contractId",
41
+ "sourceKeyHash",
42
+ "kind",
43
+ "origin",
44
+ "paymentId",
45
+ "currency",
46
+ "amountMinor",
47
+ "effectiveOn",
48
+ "sourceReceiptId",
49
+ "sourceCreditNoteId",
50
+ "snapshotJson"
51
+ ]) if (options[key] !== void 0) Object.assign(this, { [key]: options[key] });
52
+ }
53
+ async save(options) {
54
+ assertHistoricalCommerceWrite(this);
55
+ if (!this.tenantId || !this.customerId || !this.sourceKeyHash || !this.snapshotJson || !Number.isSafeInteger(this.amountMinor) || this.amountMinor <= 0) throw new Error("Historical customer funds require complete exact source evidence");
56
+ if (this.id && await this.db.get(this.tableName, { id: this.id })) throw new Error("Historical customer funds are immutable");
57
+ return super.save(options);
58
+ }
59
+ async delete() {
60
+ throw new Error("Historical customer cash evidence cannot be deleted");
61
+ }
62
+ };
63
+ __publicField$1(HistoricalCustomerFunds, "__smrtPackage__", "@happyvertical/smrt-commerce");
64
+ __decorateClass$1([tenantId()], HistoricalCustomerFunds.prototype, "tenantId", 2);
65
+ __decorateClass$1([foreignKey("Customer")], HistoricalCustomerFunds.prototype, "customerId", 2);
66
+ __decorateClass$1([foreignKey("Contract", { nullable: true })], HistoricalCustomerFunds.prototype, "contractId", 2);
67
+ __decorateClass$1([foreignKey("Payment", { nullable: true })], HistoricalCustomerFunds.prototype, "paymentId", 2);
68
+ __decorateClass$1([field({ ui: { format: "money" } })], HistoricalCustomerFunds.prototype, "amountMinor", 2);
69
+ __decorateClass$1([foreignKey("HistoricalCustomerFunds", { nullable: true })], HistoricalCustomerFunds.prototype, "sourceReceiptId", 2);
70
+ __decorateClass$1([foreignKey("Invoice", { nullable: true })], HistoricalCustomerFunds.prototype, "sourceCreditNoteId", 2);
71
+ HistoricalCustomerFunds = __decorateClass$1([TenantScoped({ mode: "required" }), smrt({
72
+ tableName: "historical_customer_funds",
73
+ indexes: [{
74
+ name: "historical_customer_funds_source",
75
+ columns: ["tenantId", "sourceKeyHash"],
76
+ unique: true
77
+ }],
78
+ api: { include: ["get", "list"] },
79
+ cli: { include: ["get", "list"] },
80
+ mcp: { include: ["get", "list"] }
81
+ })], HistoricalCustomerFunds);
82
+ //#endregion
83
+ //#region src/models/HistoricalCustomerFundsAllocation.ts
84
+ var __defProp = Object.defineProperty;
85
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
86
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, {
87
+ enumerable: true,
88
+ configurable: true,
89
+ writable: true,
90
+ value
91
+ }) : obj[key] = value;
92
+ var __decorateClass = (decorators, target, key, kind) => {
93
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
94
+ for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
95
+ if (kind && result) __defProp(target, key, result);
96
+ return result;
97
+ };
98
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
99
+ var HistoricalCustomerFundsAllocation = class extends SmrtObject {
100
+ tenantId = "";
101
+ receiptId = null;
102
+ creditNoteId = null;
103
+ invoiceId = "";
104
+ sourceKeyHash = "";
105
+ amountMinor = 0;
106
+ effectiveOn = "";
107
+ origin = "historical";
108
+ effect = "payment";
109
+ journalId = null;
110
+ snapshotJson = "";
111
+ constructor(options = {}) {
112
+ super(options);
113
+ for (const key of [
114
+ "tenantId",
115
+ "receiptId",
116
+ "creditNoteId",
117
+ "invoiceId",
118
+ "sourceKeyHash",
119
+ "amountMinor",
120
+ "effectiveOn",
121
+ "origin",
122
+ "effect",
123
+ "journalId",
124
+ "snapshotJson"
125
+ ]) if (options[key] !== void 0) Object.assign(this, { [key]: options[key] });
126
+ }
127
+ async save(options) {
128
+ assertHistoricalCommerceWrite(this);
129
+ if (!this.tenantId || !this.invoiceId || !this.sourceKeyHash || !this.snapshotJson || !Number.isSafeInteger(this.amountMinor) || this.amountMinor <= 0 || Boolean(this.receiptId) === Boolean(this.creditNoteId)) throw new Error("Historical funds allocation requires one exact source and an owned invoice");
130
+ if (this.id && await this.db.get(this.tableName, { id: this.id })) throw new Error("Historical customer funds applications are immutable");
131
+ return super.save(options);
132
+ }
133
+ async delete() {
134
+ throw new Error("Historical customer funds applications cannot be deleted");
135
+ }
136
+ };
137
+ __publicField(HistoricalCustomerFundsAllocation, "__smrtPackage__", "@happyvertical/smrt-commerce");
138
+ __decorateClass([tenantId()], HistoricalCustomerFundsAllocation.prototype, "tenantId", 2);
139
+ __decorateClass([foreignKey("HistoricalCustomerFunds", { nullable: true })], HistoricalCustomerFundsAllocation.prototype, "receiptId", 2);
140
+ __decorateClass([foreignKey("Invoice", { nullable: true })], HistoricalCustomerFundsAllocation.prototype, "creditNoteId", 2);
141
+ __decorateClass([foreignKey("Invoice")], HistoricalCustomerFundsAllocation.prototype, "invoiceId", 2);
142
+ __decorateClass([field({ ui: { format: "money" } })], HistoricalCustomerFundsAllocation.prototype, "amountMinor", 2);
143
+ __decorateClass([crossPackageRef("@happyvertical/smrt-ledgers:Journal", { nullable: true })], HistoricalCustomerFundsAllocation.prototype, "journalId", 2);
144
+ HistoricalCustomerFundsAllocation = __decorateClass([TenantScoped({ mode: "required" }), smrt({
145
+ tableName: "historical_customer_funds_allocations",
146
+ indexes: [{
147
+ name: "historical_funds_allocation_source",
148
+ columns: ["tenantId", "sourceKeyHash"],
149
+ unique: true
150
+ }],
151
+ api: { include: ["get", "list"] },
152
+ cli: { include: ["get", "list"] },
153
+ mcp: { include: ["get", "list"] }
154
+ })], HistoricalCustomerFundsAllocation);
155
+ //#endregion
156
+ //#region src/collections/HistoricalCustomerFundsCollections.ts
157
+ var HistoricalCustomerFundsCollections_exports = /* @__PURE__ */ __exportAll({
158
+ HistoricalCustomerFundsAllocationCollection: () => HistoricalCustomerFundsAllocationCollection,
159
+ HistoricalCustomerFundsCollection: () => HistoricalCustomerFundsCollection
160
+ });
161
+ var HistoricalCustomerFundsCollection = class extends SmrtCollection {
162
+ static _itemClass = HistoricalCustomerFunds;
163
+ };
164
+ var HistoricalCustomerFundsAllocationCollection = class extends SmrtCollection {
165
+ static _itemClass = HistoricalCustomerFundsAllocation;
166
+ };
167
+ //#endregion
168
+ export { HistoricalCustomerFunds as a, HistoricalCustomerFundsAllocation as i, HistoricalCustomerFundsCollection as n, HistoricalCustomerFundsCollections_exports as r, HistoricalCustomerFundsAllocationCollection as t };
169
+
170
+ //# sourceMappingURL=HistoricalCustomerFundsCollections-B5x8gTW3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HistoricalCustomerFundsCollections-B5x8gTW3.js","names":[],"sources":["../../src/models/HistoricalCustomerFunds.ts","../../src/models/HistoricalCustomerFundsAllocation.ts","../../src/collections/HistoricalCustomerFundsCollections.ts"],"sourcesContent":["import {\n field,\n foreignKey,\n SmrtObject,\n type SmrtObjectOptions,\n type SmrtSaveOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport { assertHistoricalCommerceWrite } from '../historical-commerce-internal.js';\nexport interface HistoricalCustomerFundsOptions extends SmrtObjectOptions {\n tenantId?: string;\n customerId?: string;\n contractId?: string | null;\n sourceKeyHash?: string;\n kind?: 'receipt' | 'refund';\n origin?: 'historical' | 'live';\n paymentId?: string | null;\n currency?: string;\n amountMinor?: number;\n effectiveOn?: string;\n sourceReceiptId?: string | null;\n sourceCreditNoteId?: string | null;\n snapshotJson?: string;\n}\n/** Retained original cash evidence. It is deliberately not a completed ledger-backed Payment. */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'historical_customer_funds',\n indexes: [\n {\n name: 'historical_customer_funds_source',\n columns: ['tenantId', 'sourceKeyHash'],\n unique: true,\n },\n ],\n api: { include: ['get', 'list'] },\n cli: { include: ['get', 'list'] },\n mcp: { include: ['get', 'list'] },\n})\nexport class HistoricalCustomerFunds extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-commerce\";\n @tenantId() tenantId = '';\n @foreignKey('Customer') customerId = '';\n @foreignKey('Contract', { nullable: true }) contractId: string | null = null;\n sourceKeyHash = '';\n kind: 'receipt' | 'refund' = 'receipt';\n origin: 'historical' | 'live' = 'historical';\n @foreignKey('Payment', { nullable: true }) paymentId: string | null = null;\n currency = '';\n @field({ ui: { format: 'money' } }) amountMinor = 0;\n effectiveOn = '';\n @foreignKey('HistoricalCustomerFunds', { nullable: true }) sourceReceiptId:\n | string\n | null = null;\n @foreignKey('Invoice', { nullable: true }) sourceCreditNoteId: string | null =\n null;\n snapshotJson = '';\n constructor(options: HistoricalCustomerFundsOptions = {}) {\n super(options);\n for (const key of [\n 'tenantId',\n 'customerId',\n 'contractId',\n 'sourceKeyHash',\n 'kind',\n 'origin',\n 'paymentId',\n 'currency',\n 'amountMinor',\n 'effectiveOn',\n 'sourceReceiptId',\n 'sourceCreditNoteId',\n 'snapshotJson',\n ] as const)\n if (options[key] !== undefined)\n Object.assign(this, { [key]: options[key] });\n }\n override async save(options?: SmrtSaveOptions): Promise<this> {\n assertHistoricalCommerceWrite(this);\n if (\n !this.tenantId ||\n !this.customerId ||\n !this.sourceKeyHash ||\n !this.snapshotJson ||\n !Number.isSafeInteger(this.amountMinor) ||\n this.amountMinor <= 0\n )\n throw new Error(\n 'Historical customer funds require complete exact source evidence',\n );\n if (this.id && (await this.db.get(this.tableName, { id: this.id })))\n throw new Error('Historical customer funds are immutable');\n return super.save(options);\n }\n override async delete(): Promise<void> {\n throw new Error('Historical customer cash evidence cannot be deleted');\n }\n}\n","import {\n crossPackageRef,\n field,\n foreignKey,\n SmrtObject,\n type SmrtObjectOptions,\n type SmrtSaveOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport { assertHistoricalCommerceWrite } from '../historical-commerce-internal.js';\nexport interface HistoricalCustomerFundsAllocationOptions\n extends SmrtObjectOptions {\n tenantId?: string;\n receiptId?: string | null;\n creditNoteId?: string | null;\n invoiceId?: string;\n sourceKeyHash?: string;\n amountMinor?: number;\n effectiveOn?: string;\n origin?: 'historical' | 'live';\n effect?: 'payment' | 'credit-audit' | 'refund-audit';\n journalId?: string | null;\n snapshotJson?: string;\n}\n/** Original applications have concrete identities; credit-audit records never count twice. */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'historical_customer_funds_allocations',\n indexes: [\n {\n name: 'historical_funds_allocation_source',\n columns: ['tenantId', 'sourceKeyHash'],\n unique: true,\n },\n ],\n api: { include: ['get', 'list'] },\n cli: { include: ['get', 'list'] },\n mcp: { include: ['get', 'list'] },\n})\nexport class HistoricalCustomerFundsAllocation extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-commerce\";\n @tenantId() tenantId = '';\n @foreignKey('HistoricalCustomerFunds', { nullable: true }) receiptId:\n | string\n | null = null;\n @foreignKey('Invoice', { nullable: true }) creditNoteId: string | null = null;\n @foreignKey('Invoice') invoiceId = '';\n sourceKeyHash = '';\n @field({ ui: { format: 'money' } }) amountMinor = 0;\n effectiveOn = '';\n origin: 'historical' | 'live' = 'historical';\n effect: 'payment' | 'credit-audit' | 'refund-audit' = 'payment';\n @crossPackageRef('@happyvertical/smrt-ledgers:Journal', { nullable: true })\n journalId: string | null = null;\n snapshotJson = '';\n constructor(options: HistoricalCustomerFundsAllocationOptions = {}) {\n super(options);\n for (const key of [\n 'tenantId',\n 'receiptId',\n 'creditNoteId',\n 'invoiceId',\n 'sourceKeyHash',\n 'amountMinor',\n 'effectiveOn',\n 'origin',\n 'effect',\n 'journalId',\n 'snapshotJson',\n ] as const)\n if (options[key] !== undefined)\n Object.assign(this, { [key]: options[key] });\n }\n override async save(options?: SmrtSaveOptions): Promise<this> {\n assertHistoricalCommerceWrite(this);\n if (\n !this.tenantId ||\n !this.invoiceId ||\n !this.sourceKeyHash ||\n !this.snapshotJson ||\n !Number.isSafeInteger(this.amountMinor) ||\n this.amountMinor <= 0 ||\n Boolean(this.receiptId) === Boolean(this.creditNoteId)\n )\n throw new Error(\n 'Historical funds allocation requires one exact source and an owned invoice',\n );\n if (this.id && (await this.db.get(this.tableName, { id: this.id })))\n throw new Error('Historical customer funds applications are immutable');\n return super.save(options);\n }\n override async delete(): Promise<void> {\n throw new Error('Historical customer funds applications cannot be deleted');\n }\n}\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { HistoricalCustomerFunds } from '../models/HistoricalCustomerFunds.js';\nimport { HistoricalCustomerFundsAllocation } from '../models/HistoricalCustomerFundsAllocation.js';\nexport class HistoricalCustomerFundsCollection extends SmrtCollection<HistoricalCustomerFunds> {\n static readonly _itemClass = HistoricalCustomerFunds;\n}\nexport class HistoricalCustomerFundsAllocationCollection extends SmrtCollection<HistoricalCustomerFundsAllocation> {\n static readonly _itemClass = HistoricalCustomerFundsAllocation;\n}\n"],"mappings":"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"}
@@ -1,11 +1,92 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
2
  import { s as InvoiceStatus } from "./types-Bbm0Xflc.js";
3
- import { i as claimAllocationParent, r as assertAllocationParent } from "./allocation-integrity-WmWyXhtG.js";
3
+ import { i as claimAllocationParent, r as assertAllocationParent } from "./allocation-integrity-DJ7-LY1j.js";
4
4
  import { MoneyValidationError, assertIntegerMinorUnits } from "../money.js";
5
- import { a as assertCommerceMoneySchemaCurrent, f as DOCUMENT_MONEY_READ_REBIND, p as DOCUMENT_MONEY_WRITE } from "./detect-CY9ufaFb.js";
6
- import { n as withTenantMoneyCollectionRead } from "./tenant-money-barrier-6TlqUeVj.js";
5
+ import { a as assertCommerceMoneySchemaCurrent, f as DOCUMENT_MONEY_READ_REBIND, p as DOCUMENT_MONEY_WRITE } from "./detect-DAE-_NAk.js";
6
+ import { n as withTenantMoneyCollectionRead } from "./tenant-money-barrier-DoF6lR8h.js";
7
7
  import { SmrtCollection, SmrtObject, crossPackageRef, field, foreignKey, smrt } from "@happyvertical/smrt-core";
8
8
  import { TenantScoped, getTenantId, queryGlobal, queryWithGlobals, tenantId } from "@happyvertical/smrt-tenancy";
9
+ //#region src/retention-money.ts
10
+ function invalid(message) {
11
+ throw new MoneyValidationError("INVALID_MONEY_INPUT", message);
12
+ }
13
+ function assertRetentionMinor(amount, label) {
14
+ if (!Number.isSafeInteger(amount)) invalid(`${label} must be a safe integer minor-unit amount`);
15
+ }
16
+ function validateRetentionEvidence(input) {
17
+ for (const key of [
18
+ "requestId",
19
+ "policyVersion",
20
+ "evidenceRef",
21
+ "actorId",
22
+ "reason"
23
+ ]) {
24
+ const value = input[key];
25
+ if (typeof value !== "string" || !value || value.trim() !== value) invalid(`Retention ${key} must be nonempty trimmed text`);
26
+ }
27
+ }
28
+ function parseInvoiceRetention(json) {
29
+ if (json === "") return null;
30
+ let state;
31
+ try {
32
+ state = JSON.parse(json);
33
+ } catch {
34
+ return invalid("Invalid retention state JSON");
35
+ }
36
+ if (!state || state.version !== 1 || state.creditPolicy !== "retained-first" || !Array.isArray(state.releases)) invalid("Unsupported retention state or credit policy");
37
+ validateRetentionEvidence(state);
38
+ if (!/^[A-Z]{3}$/.test(state.currency)) invalid("Retention currency is required");
39
+ const keys = /* @__PURE__ */ new Set([state.requestId]);
40
+ for (const event of [state, ...state.releases]) {
41
+ validateRetentionEvidence(event);
42
+ if (typeof event.recordedAt !== "string" || !Number.isFinite(Date.parse(event.recordedAt))) invalid("Retention event timestamp is required");
43
+ if (event.effectiveOn !== void 0 && (!/^\d{4}-\d{2}-\d{2}$/.test(event.effectiveOn) || !Number.isFinite(Date.parse(event.effectiveOn)) || new Date(event.effectiveOn).toISOString().slice(0, 10) !== event.effectiveOn)) invalid("Original retention event requires an exact calendar date");
44
+ if (event.sameDayCreditOrder !== void 0 && event.sameDayCreditOrder !== null && event.sameDayCreditOrder !== "release-before-credit" && event.sameDayCreditOrder !== "credit-before-release") invalid("Unsupported original retention release/credit ordering");
45
+ if (event !== state) {
46
+ if (keys.has(event.requestId)) invalid("Duplicate retention request identity");
47
+ keys.add(event.requestId);
48
+ }
49
+ }
50
+ return state;
51
+ }
52
+ function calculateInvoicePayable(input) {
53
+ for (const [name, amount] of Object.entries({
54
+ gross: input.totalAmount,
55
+ credits: input.creditedAmount,
56
+ paid: input.amountPaid
57
+ })) {
58
+ assertRetentionMinor(amount, name);
59
+ if (amount < 0) invalid(`${name} cannot be negative`);
60
+ }
61
+ if (input.creditedAmount > input.totalAmount || input.amountPaid > input.totalAmount) invalid("Credits or payments exceed invoice gross");
62
+ const state = parseInvoiceRetention(input.retentionStateJson ?? "");
63
+ const retained = state?.retainedMinor ?? 0;
64
+ assertRetentionMinor(retained, "Retained amount");
65
+ if (retained < 0 || retained > input.totalAmount) invalid("Retention exceeds invoice gross");
66
+ if (state && state.currency !== input.currency) invalid("Retention currency does not match invoice");
67
+ let released = 0n;
68
+ for (const event of state?.releases ?? []) {
69
+ assertRetentionMinor(event.amountMinor, "Released amount");
70
+ if (event.amountMinor <= 0) invalid("Release amount must be positive");
71
+ released += BigInt(event.amountMinor);
72
+ }
73
+ if (released > BigInt(retained)) invalid("Releases exceed retained amount");
74
+ const unreleased = retained - Number(released);
75
+ const creditedRetention = Math.min(unreleased, input.creditedAmount);
76
+ const remaining = unreleased - creditedRetention;
77
+ const cap = Math.max(0, input.totalAmount - input.creditedAmount - remaining);
78
+ return {
79
+ grossMinor: input.totalAmount,
80
+ retainedMinor: retained,
81
+ releasedMinor: Number(released),
82
+ creditedRetentionMinor: creditedRetention,
83
+ retainedRemainingMinor: remaining,
84
+ allocationCapMinor: cap,
85
+ grossBalanceMinor: input.totalAmount - input.creditedAmount - input.amountPaid,
86
+ currentlyDueMinor: Math.max(0, cap - input.amountPaid)
87
+ };
88
+ }
89
+ //#endregion
9
90
  //#region src/models/Invoice.ts
10
91
  var __defProp = Object.defineProperty;
11
92
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -77,6 +158,9 @@ var INVOICE_STATUS_TRANSITIONS = {
77
158
  };
78
159
  var loadedInvoiceStatus = /* @__PURE__ */ new WeakMap();
79
160
  var Invoice = class extends SmrtObject {
161
+ moneyAuthority = "calculated";
162
+ historicalSalesMoneyJson = "";
163
+ historicalSourceKeyHash = null;
80
164
  /** @internal Collection read guard returns this snapshot on its root DB. */
81
165
  rebindMoneyRead(capability, db) {
82
166
  if (capability !== DOCUMENT_MONEY_READ_REBIND) throw new MoneyValidationError("FROZEN_DOCUMENT", "Invoice read rebinding requires the owning capability");
@@ -87,6 +171,12 @@ var Invoice = class extends SmrtObject {
87
171
  kind = "invoice";
88
172
  creditedInvoiceId = null;
89
173
  creditedAmount = 0;
174
+ /** Server-owned immutable retention policy and append-only release evidence. */
175
+ retentionStateJson = "";
176
+ retentionAccountingStateJson = "";
177
+ getPayableFacts() {
178
+ return calculateInvoicePayable(this);
179
+ }
90
180
  tenantId = null;
91
181
  customerId = "";
92
182
  contractId = "";
@@ -180,6 +270,9 @@ var Invoice = class extends SmrtObject {
180
270
  super(options);
181
271
  if (options.kind !== void 0) this.kind = options.kind;
182
272
  if (options.creditedInvoiceId !== void 0) this.creditedInvoiceId = options.creditedInvoiceId;
273
+ if (options.moneyAuthority !== void 0) this.moneyAuthority = options.moneyAuthority;
274
+ if (options.historicalSalesMoneyJson !== void 0) this.historicalSalesMoneyJson = options.historicalSalesMoneyJson;
275
+ if (options.historicalSourceKeyHash !== void 0) this.historicalSourceKeyHash = options.historicalSourceKeyHash;
183
276
  if (options.creditedAmount !== void 0) this.creditedAmount = options.creditedAmount;
184
277
  if (options.tenantId !== void 0) this.tenantId = options.tenantId;
185
278
  if (options.customerId !== void 0) this.customerId = options.customerId;
@@ -231,7 +324,7 @@ var Invoice = class extends SmrtObject {
231
324
  async initialize() {
232
325
  await super.initialize();
233
326
  if (this.isPersisted) {
234
- const { assertHydratedMoneyRowCurrent } = await import("./detect-CY9ufaFb.js").then((n) => n.c);
327
+ const { assertHydratedMoneyRowCurrent } = await import("./detect-DAE-_NAk.js").then((n) => n.c);
235
328
  await assertHydratedMoneyRowCurrent(this);
236
329
  }
237
330
  if (await this.isSaved()) loadedInvoiceStatus.set(this, this.status);
@@ -254,7 +347,7 @@ var Invoice = class extends SmrtObject {
254
347
  * - **Status transitions** are validated against the prior persisted status.
255
348
  */
256
349
  async save() {
257
- const { saveInvoice } = await import("./document-money-DV5t4vlK.js").then((n) => n.t);
350
+ const { saveInvoice } = await import("./DocumentTaxCollection-C42x0YLW.js").then((n) => n.y);
258
351
  return await saveInvoice(this);
259
352
  }
260
353
  /** @internal Aggregate persistence only. */
@@ -272,6 +365,10 @@ var Invoice = class extends SmrtObject {
272
365
  this.assertNonNegativeAmounts();
273
366
  this.assertStatusTransition(prior);
274
367
  this.assertPaymentStatusConsistent();
368
+ const payable = calculateInvoicePayable(this);
369
+ if (this.retentionAccountingStateJson && [InvoiceStatus.CANCELLED, InvoiceStatus.WRITTEN_OFF].includes(this.status)) throw new MoneyValidationError("ACCOUNTING_SYNC_RECONCILIATION_REQUIRED", "Provider retention cannot be voided or written off without an explicit reconciled reversal contract");
370
+ if (this.retentionAccountingStateJson && (this.collectionMethod || this.providerTaxAmount)) throw new MoneyValidationError("INVALID_MONEY_INPUT", "Retention accounting does not support provider collection or tax overrides");
371
+ if (payable.retainedRemainingMinor > 0 && !this.retentionAccountingStateJson && (this.externalId || this.externalProvider || this.accountingSyncStateJson || this.collectionMethod || this.providerTaxAmount)) throw new MoneyValidationError("INVALID_MONEY_INPUT", "Unreleased retention requires an explicit provider retention contract");
275
372
  await this.assertDraftDeliveryHistory(persisted);
276
373
  await assertAllocationParent(this, "invoice");
277
374
  const result = await super.save();
@@ -279,7 +376,7 @@ var Invoice = class extends SmrtObject {
279
376
  return result;
280
377
  }
281
378
  async delete(options = {}) {
282
- const { deleteInvoice } = await import("./document-money-DV5t4vlK.js").then((n) => n.t);
379
+ const { deleteInvoice } = await import("./DocumentTaxCollection-C42x0YLW.js").then((n) => n.y);
283
380
  await deleteInvoice(this, options);
284
381
  }
285
382
  /** @internal Aggregate persistence only. */
@@ -304,7 +401,7 @@ var Invoice = class extends SmrtObject {
304
401
  return loadedInvoiceStatus.get(this);
305
402
  }
306
403
  async recomputeAmountPaid() {
307
- const { PaymentAllocationCollection } = await import("../index.js").then((n) => n.n);
404
+ const { PaymentAllocationCollection } = await import("./retention-accounting-Brdj9x-V.js").then((n) => n.x);
308
405
  const allocationCollection = await PaymentAllocationCollection.create({
309
406
  ...this.options,
310
407
  db: this.db
@@ -438,15 +535,16 @@ var Invoice = class extends SmrtObject {
438
535
  * Check if invoice is overdue
439
536
  */
440
537
  isOverdue() {
538
+ if (this.getAmountDue() === 0) return false;
441
539
  if (this.status === InvoiceStatus.OVERDUE) return true;
442
540
  if (this.isPaid() || this.status === InvoiceStatus.CANCELLED) return false;
443
- return /* @__PURE__ */ new Date() > this.dueDate;
541
+ return this.dueDate !== null && /* @__PURE__ */ new Date() > this.dueDate;
444
542
  }
445
543
  /**
446
544
  * Get remaining amount due
447
545
  */
448
546
  getAmountDue() {
449
- return Math.max(0, this.getBalance());
547
+ return this.getPayableFacts().currentlyDueMinor;
450
548
  }
451
549
  /** Signed amount still owed after payments and issued credit notes. */
452
550
  getBalance() {
@@ -489,7 +587,7 @@ var Invoice = class extends SmrtObject {
489
587
  this.amountPaid = amountPaid;
490
588
  if (this.status === InvoiceStatus.CANCELLED || this.status === InvoiceStatus.WRITTEN_OFF) return;
491
589
  if (this.isFullyPaid()) {
492
- if (this.status !== InvoiceStatus.PAID || !this.paidDate) this.paidDate = /* @__PURE__ */ new Date();
590
+ if (this.moneyAuthority !== "historical" && (this.status !== InvoiceStatus.PAID || !this.paidDate)) this.paidDate = /* @__PURE__ */ new Date();
493
591
  this.status = InvoiceStatus.PAID;
494
592
  } else if (amountPaid + this.creditedAmount > 0) {
495
593
  this.status = InvoiceStatus.PARTIAL;
@@ -497,7 +595,7 @@ var Invoice = class extends SmrtObject {
497
595
  } else {
498
596
  this.paidDate = null;
499
597
  if (this.viewedAt) this.status = InvoiceStatus.VIEWED;
500
- else if (this.sentAt) this.status = InvoiceStatus.SENT;
598
+ else if (this.sentAt || this.moneyAuthority === "historical") this.status = InvoiceStatus.SENT;
501
599
  else this.status = InvoiceStatus.DRAFT;
502
600
  }
503
601
  }
@@ -510,7 +608,7 @@ var Invoice = class extends SmrtObject {
510
608
  }
511
609
  /** Cancel a posted invoice with an exact atomic journal reversal. */
512
610
  async cancelWithRevenueReversal(options) {
513
- const { cancelInvoiceWithRevenueReversal, rebindJournal } = await import("./invoice-posting-C2i5dOVZ.js");
611
+ const { cancelInvoiceWithRevenueReversal, rebindJournal } = await import("./invoice-posting-BeTPw3h9.js");
514
612
  return rebindJournal(this.db, await cancelInvoiceWithRevenueReversal(this, options));
515
613
  }
516
614
  /**
@@ -541,7 +639,7 @@ var Invoice = class extends SmrtObject {
541
639
  * ```
542
640
  */
543
641
  async recognizeRevenue(options) {
544
- const { recognizeInvoiceRevenue, rebindJournal } = await import("./invoice-posting-C2i5dOVZ.js");
642
+ const { recognizeInvoiceRevenue, rebindJournal } = await import("./invoice-posting-BeTPw3h9.js");
545
643
  return rebindJournal(this.db, await recognizeInvoiceRevenue(this, options));
546
644
  }
547
645
  /**
@@ -579,7 +677,7 @@ var Invoice = class extends SmrtObject {
579
677
  async toAccountingInput(options) {
580
678
  if (!options) throw new MoneyValidationError("INVALID_MONEY_INPUT", "Accounting conversion requires explicit realm mapping");
581
679
  if (!this.id || !this.tenantId) throw new MoneyValidationError("INVALID_MONEY_INPUT", "Accounting conversion requires a persisted tenant invoice");
582
- const { toFrozenInvoiceAccountingInput } = await import("../index.js").then((n) => n.t);
680
+ const { toFrozenInvoiceAccountingInput } = await import("./retention-accounting-Brdj9x-V.js").then((n) => n.m);
583
681
  return toFrozenInvoiceAccountingInput({
584
682
  db: this.db,
585
683
  tenantId: this.tenantId,
@@ -589,15 +687,25 @@ var Invoice = class extends SmrtObject {
589
687
  }
590
688
  };
591
689
  __publicField(Invoice, "__smrtPackage__", "@happyvertical/smrt-commerce");
690
+ __decorateClass([field({ description: "Whether amounts were calculated or retained from an original issued invoice." })], Invoice.prototype, "moneyAuthority", 2);
691
+ __decorateClass([field({
692
+ type: "text",
693
+ nullable: true
694
+ })], Invoice.prototype, "historicalSourceKeyHash", 2);
592
695
  __decorateClass([field({ description: "Invoice or customer credit note." })], Invoice.prototype, "kind", 2);
593
696
  __decorateClass([foreignKey("Invoice", { nullable: true })], Invoice.prototype, "creditedInvoiceId", 2);
594
697
  __decorateClass([field({ ui: { format: "money" } })], Invoice.prototype, "creditedAmount", 2);
698
+ __decorateClass([field({ sensitive: true })], Invoice.prototype, "retentionAccountingStateJson", 2);
595
699
  __decorateClass([tenantId({ nullable: true })], Invoice.prototype, "tenantId", 2);
596
700
  __decorateClass([field({ description: "The customer being billed." }), foreignKey("Customer")], Invoice.prototype, "customerId", 2);
597
701
  __decorateClass([field({ description: "The order or agreement this invoice bills for, if any." }), foreignKey("SalesContract", { validateSubtype: true })], Invoice.prototype, "contractId", 2);
598
702
  __decorateClass([field({ description: "The number printed on the invoice." })], Invoice.prototype, "invoiceNumber", 2);
599
703
  __decorateClass([field({ description: "The date the invoice was issued." })], Invoice.prototype, "issueDate", 2);
600
- __decorateClass([field({ description: "The date payment is expected." })], Invoice.prototype, "dueDate", 2);
704
+ __decorateClass([field({
705
+ type: "datetime",
706
+ nullable: true,
707
+ description: "The date payment is expected; null when the original source did not establish it."
708
+ })], Invoice.prototype, "dueDate", 2);
601
709
  __decorateClass([field({ description: "The date it was paid in full." })], Invoice.prototype, "paidDate", 2);
602
710
  __decorateClass([field({
603
711
  description: "The amount before tax.",
@@ -671,7 +779,12 @@ Invoice = __decorateClass([TenantScoped({ mode: "optional" }), smrt({
671
779
  exportName: "serializeInvoiceMcpGet"
672
780
  } }
673
781
  },
674
- cli: { skipApiCheck: true }
782
+ cli: { skipApiCheck: true },
783
+ indexes: [{
784
+ name: "invoice_historical_source_identity",
785
+ columns: ["tenantId", "historicalSourceKeyHash"],
786
+ unique: true
787
+ }]
675
788
  })], Invoice);
676
789
  //#endregion
677
790
  //#region src/collections/InvoiceCollection.ts
@@ -931,6 +1044,6 @@ var InvoiceCollection = class extends SmrtCollection {
931
1044
  }
932
1045
  };
933
1046
  //#endregion
934
- export { Invoice as i, InvoiceCollection_exports as n, UNPAID_STATUSES as r, InvoiceCollection as t };
1047
+ export { assertRetentionMinor as a, validateRetentionEvidence as c, Invoice as i, InvoiceCollection_exports as n, calculateInvoicePayable as o, UNPAID_STATUSES as r, parseInvoiceRetention as s, InvoiceCollection as t };
935
1048
 
936
- //# sourceMappingURL=InvoiceCollection-cinzAqt6.js.map
1049
+ //# sourceMappingURL=InvoiceCollection-BIcge9Wl.js.map