@happyvertical/smrt-commerce 0.57.2 → 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.
- package/AGENTS.md +17 -0
- package/README.md +130 -0
- package/agents/accounting-snapshot-mapper.md +11 -0
- package/agents/contract-billing-schedules.md +67 -0
- package/agents/contract-money.md +81 -0
- package/agents/customer-funds.md +96 -0
- package/agents/historical-sales.md +132 -0
- package/agents/money-calculator.md +36 -0
- package/agents/money-model.md +6 -3
- package/agents/observed-purchase-prices.md +37 -0
- package/agents/payment-allocations.md +59 -0
- package/agents/received-sales-contract-money.md +38 -0
- package/dist/accounting-snapshot.d.ts +8 -1
- package/dist/accounting-snapshot.d.ts.map +1 -1
- package/dist/allocation-integrity.d.ts.map +1 -1
- package/dist/billing/period-close.d.ts.map +1 -1
- package/dist/chunks/{ContractLineItemCollection-BZcrlrrY.js → ContractLineItemCollection-J4xtRtzE.js} +6 -6
- package/dist/chunks/{ContractLineItemCollection-BZcrlrrY.js.map → ContractLineItemCollection-J4xtRtzE.js.map} +1 -1
- package/dist/chunks/DocumentTaxCollection-C42x0YLW.js +4385 -0
- package/dist/chunks/DocumentTaxCollection-C42x0YLW.js.map +1 -0
- package/dist/chunks/HistoricalCustomerFundsCollections-B5x8gTW3.js +170 -0
- package/dist/chunks/HistoricalCustomerFundsCollections-B5x8gTW3.js.map +1 -0
- package/dist/chunks/{InvoiceCollection-cinzAqt6.js → InvoiceCollection-BIcge9Wl.js} +131 -18
- package/dist/chunks/InvoiceCollection-BIcge9Wl.js.map +1 -0
- package/dist/chunks/{TaxCodeCollection-DaBOPG9c.js → TaxCodeCollection-RWdVaheF.js} +3 -4
- package/dist/chunks/TaxCodeCollection-RWdVaheF.js.map +1 -0
- package/dist/chunks/{TaxComponentCollection-C4zxnyVu.js → TaxComponentCollection-Dt2jeWiC.js} +3 -3
- package/dist/chunks/{TaxComponentCollection-C4zxnyVu.js.map → TaxComponentCollection-Dt2jeWiC.js.map} +1 -1
- package/dist/chunks/{allocation-integrity-WmWyXhtG.js → allocation-integrity-DJ7-LY1j.js} +7 -7
- package/dist/chunks/{allocation-integrity-WmWyXhtG.js.map → allocation-integrity-DJ7-LY1j.js.map} +1 -1
- package/dist/chunks/{contract-money-EuToOghh.js → contract-money-DSRTMoXm.js} +45 -12
- package/dist/chunks/contract-money-DSRTMoXm.js.map +1 -0
- package/dist/chunks/customer-funds-internal-BQzoJXK5.js +24 -0
- package/dist/chunks/customer-funds-internal-BQzoJXK5.js.map +1 -0
- package/dist/chunks/{detect-CY9ufaFb.js → detect-DAE-_NAk.js} +5 -2
- package/dist/chunks/{detect-CY9ufaFb.js.map → detect-DAE-_NAk.js.map} +1 -1
- package/dist/chunks/historical-commerce-internal-C9ButfuH.js +18 -0
- package/dist/chunks/historical-commerce-internal-C9ButfuH.js.map +1 -0
- package/dist/chunks/{invoice-posting-C2i5dOVZ.js → invoice-posting-BeTPw3h9.js} +5 -5
- package/dist/chunks/invoice-posting-BeTPw3h9.js.map +1 -0
- package/dist/chunks/retention-accounting-Brdj9x-V.js +2323 -0
- package/dist/chunks/retention-accounting-Brdj9x-V.js.map +1 -0
- package/dist/chunks/retention-accounting-internal-CBQRvd74.js +17 -0
- package/dist/chunks/retention-accounting-internal-CBQRvd74.js.map +1 -0
- package/dist/chunks/{tenant-money-barrier-6TlqUeVj.js → tenant-money-barrier-DoF6lR8h.js} +5 -5
- package/dist/chunks/{tenant-money-barrier-6TlqUeVj.js.map → tenant-money-barrier-DoF6lR8h.js.map} +1 -1
- package/dist/chunks/types-Bbm0Xflc.js.map +1 -1
- package/dist/collections/DocumentTaxCollection.d.ts +4 -1
- package/dist/collections/DocumentTaxCollection.d.ts.map +1 -1
- package/dist/collections/HistoricalCustomerFundsCollections.d.ts +10 -0
- package/dist/collections/HistoricalCustomerFundsCollections.d.ts.map +1 -0
- package/dist/collections/HistoricalSalesLineCollection.d.ts +6 -0
- package/dist/collections/HistoricalSalesLineCollection.d.ts.map +1 -0
- package/dist/collections/PaymentAllocationCollection.d.ts +2 -6
- package/dist/collections/PaymentAllocationCollection.d.ts.map +1 -1
- package/dist/collections/PurchasePriceObservationCollection.d.ts +6 -0
- package/dist/collections/PurchasePriceObservationCollection.d.ts.map +1 -0
- package/dist/collections/index.d.ts +1 -0
- package/dist/collections/index.d.ts.map +1 -1
- package/dist/contract-billing-schedule.d.ts +83 -0
- package/dist/contract-billing-schedule.d.ts.map +1 -0
- package/dist/contract-money.d.ts +2 -0
- package/dist/contract-money.d.ts.map +1 -1
- package/dist/customer-funds-internal.d.ts +6 -0
- package/dist/customer-funds-internal.d.ts.map +1 -0
- package/dist/customer-funds.d.ts +108 -0
- package/dist/customer-funds.d.ts.map +1 -0
- package/dist/document-money.d.ts +11 -0
- package/dist/document-money.d.ts.map +1 -1
- package/dist/historical-commerce-internal.d.ts +3 -0
- package/dist/historical-commerce-internal.d.ts.map +1 -0
- package/dist/historical-customer-funds-types.d.ts +113 -0
- package/dist/historical-customer-funds-types.d.ts.map +1 -0
- package/dist/historical-customer-funds.d.ts +23 -0
- package/dist/historical-customer-funds.d.ts.map +1 -0
- package/dist/historical-funds-internal.d.ts +5 -0
- package/dist/historical-funds-internal.d.ts.map +1 -0
- package/dist/historical-sales-money.d.ts +22 -0
- package/dist/historical-sales-money.d.ts.map +1 -0
- package/dist/historical-sales-reports.d.ts +31 -0
- package/dist/historical-sales-reports.d.ts.map +1 -0
- package/dist/historical-sales-types.d.ts +106 -0
- package/dist/historical-sales-types.d.ts.map +1 -0
- package/dist/historical-sales-validation.d.ts +12 -0
- package/dist/historical-sales-validation.d.ts.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1685 -1640
- package/dist/index.js.map +1 -1
- package/dist/invoice-accounting-sync.d.ts +0 -1
- package/dist/invoice-accounting-sync.d.ts.map +1 -1
- package/dist/invoice-mcp.d.ts.map +1 -1
- package/dist/invoice-posting.d.ts.map +1 -1
- package/dist/invoice-retention.d.ts +16 -0
- package/dist/invoice-retention.d.ts.map +1 -0
- package/dist/invoices.d.ts +2 -0
- package/dist/invoices.d.ts.map +1 -1
- package/dist/invoices.js +2 -2
- package/dist/manifest.json +7563 -4419
- package/dist/models/Contract.d.ts +14 -0
- package/dist/models/Contract.d.ts.map +1 -1
- package/dist/models/DocumentTax.d.ts +2 -0
- package/dist/models/DocumentTax.d.ts.map +1 -1
- package/dist/models/HistoricalCustomerFunds.d.ts +36 -0
- package/dist/models/HistoricalCustomerFunds.d.ts.map +1 -0
- package/dist/models/HistoricalCustomerFundsAllocation.d.ts +32 -0
- package/dist/models/HistoricalCustomerFundsAllocation.d.ts.map +1 -0
- package/dist/models/HistoricalSalesLine.d.ts +29 -0
- package/dist/models/HistoricalSalesLine.d.ts.map +1 -0
- package/dist/models/Invoice.d.ts +10 -1
- package/dist/models/Invoice.d.ts.map +1 -1
- package/dist/models/Payment.d.ts +7 -1
- package/dist/models/Payment.d.ts.map +1 -1
- package/dist/models/PaymentAllocation.d.ts +3 -1
- package/dist/models/PaymentAllocation.d.ts.map +1 -1
- package/dist/models/PaymentIntent.d.ts.map +1 -1
- package/dist/models/Payout.d.ts.map +1 -1
- package/dist/models/PurchasePriceObservation.d.ts +15 -0
- package/dist/models/PurchasePriceObservation.d.ts.map +1 -0
- package/dist/models/TaxCode.d.ts +1 -1
- package/dist/models/TaxCode.d.ts.map +1 -1
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.d.ts.map +1 -1
- package/dist/money.d.ts +5 -1
- package/dist/money.d.ts.map +1 -1
- package/dist/money.js +62 -15
- package/dist/money.js.map +1 -1
- package/dist/observed-purchase-price-internal.d.ts +3 -0
- package/dist/observed-purchase-price-internal.d.ts.map +1 -0
- package/dist/observed-purchase-price.d.ts +71 -0
- package/dist/observed-purchase-price.d.ts.map +1 -0
- package/dist/received-purchase-money.d.ts +87 -0
- package/dist/received-purchase-money.d.ts.map +1 -0
- package/dist/recipes.d.ts +4 -1
- package/dist/recipes.d.ts.map +1 -1
- package/dist/retention-accounting-internal.d.ts +3 -0
- package/dist/retention-accounting-internal.d.ts.map +1 -0
- package/dist/retention-accounting.d.ts +164 -0
- package/dist/retention-accounting.d.ts.map +1 -0
- package/dist/retention-money.d.ts +43 -0
- package/dist/retention-money.d.ts.map +1 -0
- package/dist/smrt-knowledge.json +1866 -113
- package/dist/tax/cookbook.d.ts.map +1 -1
- package/dist/tax-summary.d.ts +1 -0
- package/dist/tax-summary.d.ts.map +1 -1
- package/dist/types/index.d.ts +20 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +16 -16
- package/dist/chunks/CustomerCollection-BIPH2ZUx.js +0 -99
- package/dist/chunks/CustomerCollection-BIPH2ZUx.js.map +0 -1
- package/dist/chunks/DocumentTaxCollection-DDzlywMW.js +0 -1666
- package/dist/chunks/DocumentTaxCollection-DDzlywMW.js.map +0 -1
- package/dist/chunks/InvoiceCollection-cinzAqt6.js.map +0 -1
- package/dist/chunks/TaxCodeCollection-DaBOPG9c.js.map +0 -1
- package/dist/chunks/VendorCollection-D6ZcUYy8.js +0 -100
- package/dist/chunks/VendorCollection-D6ZcUYy8.js.map +0 -1
- package/dist/chunks/calculations-C9daQLsh.js +0 -82
- package/dist/chunks/calculations-C9daQLsh.js.map +0 -1
- package/dist/chunks/contract-money-EuToOghh.js.map +0 -1
- package/dist/chunks/document-money-DV5t4vlK.js +0 -1186
- package/dist/chunks/document-money-DV5t4vlK.js.map +0 -1
- package/dist/chunks/invoice-posting-C2i5dOVZ.js.map +0 -1
package/dist/smrt-knowledge.json
CHANGED
|
@@ -3,27 +3,32 @@
|
|
|
3
3
|
"sensitiveFieldsExcluded": true,
|
|
4
4
|
"generatedAt": "1970-01-01T00:00:00.000Z",
|
|
5
5
|
"packageName": "@happyvertical/smrt-commerce",
|
|
6
|
-
"packageVersion": "0.57.
|
|
6
|
+
"packageVersion": "0.57.4",
|
|
7
7
|
"sourceManifestPath": "dist/manifest.json",
|
|
8
8
|
"agentDocPath": "AGENTS.md",
|
|
9
9
|
"sourceHashes": {
|
|
10
|
-
"manifest": "
|
|
11
|
-
"packageJson": "
|
|
12
|
-
"agents": "
|
|
10
|
+
"manifest": "cfcb8d19b0cc6346fa3691630e4d39e76baa07515b4a6a14936c3c13c4467102",
|
|
11
|
+
"packageJson": "e12000397a9b930d72ec4fef92463a08d5b8f93a2815ec5a9a34bbd88663a0cd",
|
|
12
|
+
"agents": "f6e250043ec3384326ee0cbbf8c801c90a1fdf9d74ac42810e86ac320a8a8cf7",
|
|
13
13
|
"moduleDoc:agents/customer-vendor-ui.md": "2b22e519411a16d8c493496fc168da77b9acd25f6077ea8fbac00cfee3a3501c",
|
|
14
|
-
"moduleDoc:README.md": "
|
|
14
|
+
"moduleDoc:README.md": "7f56bd7667e5270acb18dc2b961f382a9e1bc450b98f7e7b3828c5bc8d7b050c",
|
|
15
15
|
"moduleDoc:agents/invoice-quantity.md": "3a5fbb464c8fe63acc021b2259ba36f052bb22c49b29e503639c5316814e2028",
|
|
16
|
-
"moduleDoc:agents/
|
|
16
|
+
"moduleDoc:agents/historical-sales.md": "b26b38a78ac0bdaeffb4279f06834aa1223698e1001cba2afb9defe4f8466dbe",
|
|
17
|
+
"moduleDoc:agents/payment-allocations.md": "679894f603f62522515bce338741bafda3f10d16ef0b817b105dc2e732471fdb",
|
|
17
18
|
"moduleDoc:agents/tax-codes.md": "6b07282f0ac93db4fd42ddb4a9551d880e24ec2bd2fae9d06c06561313b3cb9f",
|
|
18
19
|
"moduleDoc:agents/document-money.md": "7f198737c66d190dbdc9cc9a3dbef460fb7c9fb8ee47dd0eaaadde2f2ba91d47",
|
|
19
20
|
"moduleDoc:agents/money-upgrade.md": "904e218a271d4a8d36a47a50f5f26802a9cf8ba7a69daf7d8857b6b2e4ca814d",
|
|
20
|
-
"moduleDoc:agents/contract-money.md": "
|
|
21
|
-
"moduleDoc:agents/money-model.md": "
|
|
22
|
-
"moduleDoc:agents/money-calculator.md": "
|
|
21
|
+
"moduleDoc:agents/contract-money.md": "3806a844f0ee14fe429ac74880d59e728d6eab2eb991f83743ffcd6669388729",
|
|
22
|
+
"moduleDoc:agents/money-model.md": "ce996509c0a522aaa2f7fd63e66ae8a9958c2737aafb5578304d6122ca7e996a",
|
|
23
|
+
"moduleDoc:agents/money-calculator.md": "5cf5e89c926fc8a2ac4c4e65d85c0c4444fd323aa4131259bfe66843da48393d",
|
|
23
24
|
"moduleDoc:agents/commercial-ui.md": "37397f3e3d77c30ef40b0962d606e17fa61b5bb6f57d1cf13cdc26b4fc6a6cbc",
|
|
24
25
|
"moduleDoc:agents/quote-ui.md": "9d1faaa12f39e330294693f5309d9766c593dc0f7ced9e8b1dcaf5c81b066205",
|
|
25
26
|
"moduleDoc:agents/purchasing-ui.md": "d2b413009d466f3320934adf1e30ffbb7278138b859df69635e7c1f77efbbd1c",
|
|
26
|
-
"moduleDoc:agents/cost-billing.md": "eaedcc68bb5c2ad7994bf1fc873175b6b800a6ca87e04ba6a51e041d4b765561"
|
|
27
|
+
"moduleDoc:agents/cost-billing.md": "eaedcc68bb5c2ad7994bf1fc873175b6b800a6ca87e04ba6a51e041d4b765561",
|
|
28
|
+
"moduleDoc:agents/contract-billing-schedules.md": "b9e2cb806c3296d12928279a64119a67b105c57443fc7f57adcd1cf070533e26",
|
|
29
|
+
"moduleDoc:agents/customer-funds.md": "417af24b9de9c41c89917e3c6e50e324a1baa70de9e45a61772b3d84c8bfeda0",
|
|
30
|
+
"moduleDoc:agents/observed-purchase-prices.md": "e8e68d733b7b9453b4dbd54e1dcf11e1486b70ee855ac629bb4e6888eb90ca9c",
|
|
31
|
+
"moduleDoc:agents/received-sales-contract-money.md": "675d728c565346e5d808e8299a55f2543a423853be0ce9abc99dc7041af79570"
|
|
27
32
|
},
|
|
28
33
|
"exports": [
|
|
29
34
|
".",
|
|
@@ -93,7 +98,7 @@
|
|
|
93
98
|
"smrt"
|
|
94
99
|
],
|
|
95
100
|
"risks": [
|
|
96
|
-
"cross-package-refs:
|
|
101
|
+
"cross-package-refs:18",
|
|
97
102
|
"sensitive-fields-excluded",
|
|
98
103
|
"sti-inheritance"
|
|
99
104
|
],
|
|
@@ -1171,6 +1176,57 @@
|
|
|
1171
1176
|
"tags": [],
|
|
1172
1177
|
"risks": []
|
|
1173
1178
|
},
|
|
1179
|
+
{
|
|
1180
|
+
"name": "HistoricalCustomerFundsCollection",
|
|
1181
|
+
"qualifiedName": "@happyvertical/smrt-commerce:HistoricalCustomerFundsCollection",
|
|
1182
|
+
"collection": "historicalcustomerfundses",
|
|
1183
|
+
"tableName": "historical_customer_funds",
|
|
1184
|
+
"packageName": "@happyvertical/smrt-commerce",
|
|
1185
|
+
"extends": "SmrtCollection",
|
|
1186
|
+
"fields": [],
|
|
1187
|
+
"relationships": [],
|
|
1188
|
+
"methods": [],
|
|
1189
|
+
"surfaces": [],
|
|
1190
|
+
"relationshipFeatures": [
|
|
1191
|
+
"uuidColumns"
|
|
1192
|
+
],
|
|
1193
|
+
"tags": [],
|
|
1194
|
+
"risks": []
|
|
1195
|
+
},
|
|
1196
|
+
{
|
|
1197
|
+
"name": "HistoricalCustomerFundsAllocationCollection",
|
|
1198
|
+
"qualifiedName": "@happyvertical/smrt-commerce:HistoricalCustomerFundsAllocationCollection",
|
|
1199
|
+
"collection": "historicalcustomerfundsallocations",
|
|
1200
|
+
"tableName": "historical_customer_funds_allocations",
|
|
1201
|
+
"packageName": "@happyvertical/smrt-commerce",
|
|
1202
|
+
"extends": "SmrtCollection",
|
|
1203
|
+
"fields": [],
|
|
1204
|
+
"relationships": [],
|
|
1205
|
+
"methods": [],
|
|
1206
|
+
"surfaces": [],
|
|
1207
|
+
"relationshipFeatures": [
|
|
1208
|
+
"uuidColumns"
|
|
1209
|
+
],
|
|
1210
|
+
"tags": [],
|
|
1211
|
+
"risks": []
|
|
1212
|
+
},
|
|
1213
|
+
{
|
|
1214
|
+
"name": "HistoricalSalesLineCollection",
|
|
1215
|
+
"qualifiedName": "@happyvertical/smrt-commerce:HistoricalSalesLineCollection",
|
|
1216
|
+
"collection": "historicalsaleslines",
|
|
1217
|
+
"tableName": "historical_sales_lines",
|
|
1218
|
+
"packageName": "@happyvertical/smrt-commerce",
|
|
1219
|
+
"extends": "SmrtCollection",
|
|
1220
|
+
"fields": [],
|
|
1221
|
+
"relationships": [],
|
|
1222
|
+
"methods": [],
|
|
1223
|
+
"surfaces": [],
|
|
1224
|
+
"relationshipFeatures": [
|
|
1225
|
+
"uuidColumns"
|
|
1226
|
+
],
|
|
1227
|
+
"tags": [],
|
|
1228
|
+
"risks": []
|
|
1229
|
+
},
|
|
1174
1230
|
{
|
|
1175
1231
|
"name": "InvoiceCollection",
|
|
1176
1232
|
"qualifiedName": "@happyvertical/smrt-commerce:InvoiceCollection",
|
|
@@ -2995,6 +3051,23 @@
|
|
|
2995
3051
|
"tags": [],
|
|
2996
3052
|
"risks": []
|
|
2997
3053
|
},
|
|
3054
|
+
{
|
|
3055
|
+
"name": "PurchasePriceObservationCollection",
|
|
3056
|
+
"qualifiedName": "@happyvertical/smrt-commerce:PurchasePriceObservationCollection",
|
|
3057
|
+
"collection": "purchasepriceobservations",
|
|
3058
|
+
"tableName": "purchase_price_observations",
|
|
3059
|
+
"packageName": "@happyvertical/smrt-commerce",
|
|
3060
|
+
"extends": "SmrtCollection",
|
|
3061
|
+
"fields": [],
|
|
3062
|
+
"relationships": [],
|
|
3063
|
+
"methods": [],
|
|
3064
|
+
"surfaces": [],
|
|
3065
|
+
"relationshipFeatures": [
|
|
3066
|
+
"uuidColumns"
|
|
3067
|
+
],
|
|
3068
|
+
"tags": [],
|
|
3069
|
+
"risks": []
|
|
3070
|
+
},
|
|
2998
3071
|
{
|
|
2999
3072
|
"name": "SalesContractCollection",
|
|
3000
3073
|
"qualifiedName": "@happyvertical/smrt-commerce:SalesContractCollection",
|
|
@@ -3559,6 +3632,26 @@
|
|
|
3559
3632
|
"default": "USD",
|
|
3560
3633
|
"description": "The currency of the amounts."
|
|
3561
3634
|
},
|
|
3635
|
+
{
|
|
3636
|
+
"name": "moneyAuthority",
|
|
3637
|
+
"type": "text",
|
|
3638
|
+
"required": false,
|
|
3639
|
+
"columnType": "TEXT",
|
|
3640
|
+
"default": "calculated",
|
|
3641
|
+
"description": "Whether amounts were calculated or recorded from reviewed original paperwork."
|
|
3642
|
+
},
|
|
3643
|
+
{
|
|
3644
|
+
"name": "receivedPurchaseMoneyJson",
|
|
3645
|
+
"type": "text",
|
|
3646
|
+
"required": false,
|
|
3647
|
+
"columnType": "TEXT"
|
|
3648
|
+
},
|
|
3649
|
+
{
|
|
3650
|
+
"name": "billingScheduleJson",
|
|
3651
|
+
"type": "text",
|
|
3652
|
+
"required": false,
|
|
3653
|
+
"columnType": "TEXT"
|
|
3654
|
+
},
|
|
3562
3655
|
{
|
|
3563
3656
|
"name": "lineAmountType",
|
|
3564
3657
|
"type": "text",
|
|
@@ -3647,6 +3740,8 @@
|
|
|
3647
3740
|
],
|
|
3648
3741
|
"relationships": [],
|
|
3649
3742
|
"methods": [
|
|
3743
|
+
"delete",
|
|
3744
|
+
"deleteDerived",
|
|
3650
3745
|
"initialize",
|
|
3651
3746
|
"isAccepted",
|
|
3652
3747
|
"isCompleted",
|
|
@@ -3659,6 +3754,23 @@
|
|
|
3659
3754
|
"saveDerived"
|
|
3660
3755
|
],
|
|
3661
3756
|
"methodSignatures": [
|
|
3757
|
+
{
|
|
3758
|
+
"name": "delete",
|
|
3759
|
+
"async": true,
|
|
3760
|
+
"params": [
|
|
3761
|
+
"options?: object"
|
|
3762
|
+
],
|
|
3763
|
+
"returns": "Promise<void>"
|
|
3764
|
+
},
|
|
3765
|
+
{
|
|
3766
|
+
"name": "deleteDerived",
|
|
3767
|
+
"async": true,
|
|
3768
|
+
"params": [
|
|
3769
|
+
"capability: DocumentMoneyWriteCapability",
|
|
3770
|
+
"options?: object"
|
|
3771
|
+
],
|
|
3772
|
+
"returns": "Promise<void>"
|
|
3773
|
+
},
|
|
3662
3774
|
{
|
|
3663
3775
|
"name": "initialize",
|
|
3664
3776
|
"async": true,
|
|
@@ -3828,6 +3940,12 @@
|
|
|
3828
3940
|
"operation": "recalculateTotals",
|
|
3829
3941
|
"objectName": "@happyvertical/smrt-commerce:Contract"
|
|
3830
3942
|
},
|
|
3943
|
+
{
|
|
3944
|
+
"kind": "cli",
|
|
3945
|
+
"name": "contract_deleteDerived",
|
|
3946
|
+
"operation": "deleteDerived",
|
|
3947
|
+
"objectName": "@happyvertical/smrt-commerce:Contract"
|
|
3948
|
+
},
|
|
3831
3949
|
{
|
|
3832
3950
|
"kind": "cli",
|
|
3833
3951
|
"name": "contract_saveDerived",
|
|
@@ -3848,6 +3966,13 @@
|
|
|
3848
3966
|
}
|
|
3849
3967
|
],
|
|
3850
3968
|
"withheldSurfaces": [
|
|
3969
|
+
{
|
|
3970
|
+
"kind": "api",
|
|
3971
|
+
"operation": "deleteDerived",
|
|
3972
|
+
"code": "not-included",
|
|
3973
|
+
"reason": "not listed in api.include",
|
|
3974
|
+
"objectName": "@happyvertical/smrt-commerce:Contract"
|
|
3975
|
+
},
|
|
3851
3976
|
{
|
|
3852
3977
|
"kind": "api",
|
|
3853
3978
|
"operation": "initialize",
|
|
@@ -4005,6 +4130,26 @@
|
|
|
4005
4130
|
"default": "USD",
|
|
4006
4131
|
"description": "The currency of the amounts."
|
|
4007
4132
|
},
|
|
4133
|
+
{
|
|
4134
|
+
"name": "moneyAuthority",
|
|
4135
|
+
"type": "text",
|
|
4136
|
+
"required": false,
|
|
4137
|
+
"columnType": "TEXT",
|
|
4138
|
+
"default": "calculated",
|
|
4139
|
+
"description": "Whether amounts were calculated or recorded from reviewed original paperwork."
|
|
4140
|
+
},
|
|
4141
|
+
{
|
|
4142
|
+
"name": "receivedPurchaseMoneyJson",
|
|
4143
|
+
"type": "text",
|
|
4144
|
+
"required": false,
|
|
4145
|
+
"columnType": "TEXT"
|
|
4146
|
+
},
|
|
4147
|
+
{
|
|
4148
|
+
"name": "billingScheduleJson",
|
|
4149
|
+
"type": "text",
|
|
4150
|
+
"required": false,
|
|
4151
|
+
"columnType": "TEXT"
|
|
4152
|
+
},
|
|
4008
4153
|
{
|
|
4009
4154
|
"name": "lineAmountType",
|
|
4010
4155
|
"type": "text",
|
|
@@ -4109,6 +4254,8 @@
|
|
|
4109
4254
|
}
|
|
4110
4255
|
],
|
|
4111
4256
|
"methods": [
|
|
4257
|
+
"delete",
|
|
4258
|
+
"deleteDerived",
|
|
4112
4259
|
"initialize",
|
|
4113
4260
|
"isAccepted",
|
|
4114
4261
|
"isCompleted",
|
|
@@ -4121,6 +4268,23 @@
|
|
|
4121
4268
|
"saveDerived"
|
|
4122
4269
|
],
|
|
4123
4270
|
"methodSignatures": [
|
|
4271
|
+
{
|
|
4272
|
+
"name": "delete",
|
|
4273
|
+
"async": true,
|
|
4274
|
+
"params": [
|
|
4275
|
+
"options?: object"
|
|
4276
|
+
],
|
|
4277
|
+
"returns": "Promise<void>"
|
|
4278
|
+
},
|
|
4279
|
+
{
|
|
4280
|
+
"name": "deleteDerived",
|
|
4281
|
+
"async": true,
|
|
4282
|
+
"params": [
|
|
4283
|
+
"capability: DocumentMoneyWriteCapability",
|
|
4284
|
+
"options?: object"
|
|
4285
|
+
],
|
|
4286
|
+
"returns": "Promise<void>"
|
|
4287
|
+
},
|
|
4124
4288
|
{
|
|
4125
4289
|
"name": "initialize",
|
|
4126
4290
|
"async": true,
|
|
@@ -4222,6 +4386,13 @@
|
|
|
4222
4386
|
}
|
|
4223
4387
|
],
|
|
4224
4388
|
"withheldSurfaces": [
|
|
4389
|
+
{
|
|
4390
|
+
"kind": "api",
|
|
4391
|
+
"operation": "deleteDerived",
|
|
4392
|
+
"code": "excluded",
|
|
4393
|
+
"reason": "listed in api.exclude",
|
|
4394
|
+
"objectName": "@happyvertical/smrt-commerce:SalesContract"
|
|
4395
|
+
},
|
|
4225
4396
|
{
|
|
4226
4397
|
"kind": "api",
|
|
4227
4398
|
"operation": "initialize",
|
|
@@ -4380,6 +4551,26 @@
|
|
|
4380
4551
|
"default": "USD",
|
|
4381
4552
|
"description": "The currency of the amounts."
|
|
4382
4553
|
},
|
|
4554
|
+
{
|
|
4555
|
+
"name": "moneyAuthority",
|
|
4556
|
+
"type": "text",
|
|
4557
|
+
"required": false,
|
|
4558
|
+
"columnType": "TEXT",
|
|
4559
|
+
"default": "calculated",
|
|
4560
|
+
"description": "Whether amounts were calculated or recorded from reviewed original paperwork."
|
|
4561
|
+
},
|
|
4562
|
+
{
|
|
4563
|
+
"name": "receivedPurchaseMoneyJson",
|
|
4564
|
+
"type": "text",
|
|
4565
|
+
"required": false,
|
|
4566
|
+
"columnType": "TEXT"
|
|
4567
|
+
},
|
|
4568
|
+
{
|
|
4569
|
+
"name": "billingScheduleJson",
|
|
4570
|
+
"type": "text",
|
|
4571
|
+
"required": false,
|
|
4572
|
+
"columnType": "TEXT"
|
|
4573
|
+
},
|
|
4383
4574
|
{
|
|
4384
4575
|
"name": "lineAmountType",
|
|
4385
4576
|
"type": "text",
|
|
@@ -4484,6 +4675,8 @@
|
|
|
4484
4675
|
}
|
|
4485
4676
|
],
|
|
4486
4677
|
"methods": [
|
|
4678
|
+
"delete",
|
|
4679
|
+
"deleteDerived",
|
|
4487
4680
|
"initialize",
|
|
4488
4681
|
"isAccepted",
|
|
4489
4682
|
"isCompleted",
|
|
@@ -4496,6 +4689,23 @@
|
|
|
4496
4689
|
"saveDerived"
|
|
4497
4690
|
],
|
|
4498
4691
|
"methodSignatures": [
|
|
4692
|
+
{
|
|
4693
|
+
"name": "delete",
|
|
4694
|
+
"async": true,
|
|
4695
|
+
"params": [
|
|
4696
|
+
"options?: object"
|
|
4697
|
+
],
|
|
4698
|
+
"returns": "Promise<void>"
|
|
4699
|
+
},
|
|
4700
|
+
{
|
|
4701
|
+
"name": "deleteDerived",
|
|
4702
|
+
"async": true,
|
|
4703
|
+
"params": [
|
|
4704
|
+
"capability: DocumentMoneyWriteCapability",
|
|
4705
|
+
"options?: object"
|
|
4706
|
+
],
|
|
4707
|
+
"returns": "Promise<void>"
|
|
4708
|
+
},
|
|
4499
4709
|
{
|
|
4500
4710
|
"name": "initialize",
|
|
4501
4711
|
"async": true,
|
|
@@ -4597,6 +4807,13 @@
|
|
|
4597
4807
|
}
|
|
4598
4808
|
],
|
|
4599
4809
|
"withheldSurfaces": [
|
|
4810
|
+
{
|
|
4811
|
+
"kind": "api",
|
|
4812
|
+
"operation": "deleteDerived",
|
|
4813
|
+
"code": "excluded",
|
|
4814
|
+
"reason": "listed in api.exclude",
|
|
4815
|
+
"objectName": "@happyvertical/smrt-commerce:PurchaseContract"
|
|
4816
|
+
},
|
|
4600
4817
|
{
|
|
4601
4818
|
"kind": "api",
|
|
4602
4819
|
"operation": "initialize",
|
|
@@ -4754,6 +4971,26 @@
|
|
|
4754
4971
|
"default": "USD",
|
|
4755
4972
|
"description": "The currency of the amounts."
|
|
4756
4973
|
},
|
|
4974
|
+
{
|
|
4975
|
+
"name": "moneyAuthority",
|
|
4976
|
+
"type": "text",
|
|
4977
|
+
"required": false,
|
|
4978
|
+
"columnType": "TEXT",
|
|
4979
|
+
"default": "calculated",
|
|
4980
|
+
"description": "Whether amounts were calculated or recorded from reviewed original paperwork."
|
|
4981
|
+
},
|
|
4982
|
+
{
|
|
4983
|
+
"name": "receivedPurchaseMoneyJson",
|
|
4984
|
+
"type": "text",
|
|
4985
|
+
"required": false,
|
|
4986
|
+
"columnType": "TEXT"
|
|
4987
|
+
},
|
|
4988
|
+
{
|
|
4989
|
+
"name": "billingScheduleJson",
|
|
4990
|
+
"type": "text",
|
|
4991
|
+
"required": false,
|
|
4992
|
+
"columnType": "TEXT"
|
|
4993
|
+
},
|
|
4757
4994
|
{
|
|
4758
4995
|
"name": "lineAmountType",
|
|
4759
4996
|
"type": "text",
|
|
@@ -4857,6 +5094,8 @@
|
|
|
4857
5094
|
}
|
|
4858
5095
|
],
|
|
4859
5096
|
"methods": [
|
|
5097
|
+
"delete",
|
|
5098
|
+
"deleteDerived",
|
|
4860
5099
|
"initialize",
|
|
4861
5100
|
"isAccepted",
|
|
4862
5101
|
"isCompleted",
|
|
@@ -4869,6 +5108,23 @@
|
|
|
4869
5108
|
"saveDerived"
|
|
4870
5109
|
],
|
|
4871
5110
|
"methodSignatures": [
|
|
5111
|
+
{
|
|
5112
|
+
"name": "delete",
|
|
5113
|
+
"async": true,
|
|
5114
|
+
"params": [
|
|
5115
|
+
"options?: object"
|
|
5116
|
+
],
|
|
5117
|
+
"returns": "Promise<void>"
|
|
5118
|
+
},
|
|
5119
|
+
{
|
|
5120
|
+
"name": "deleteDerived",
|
|
5121
|
+
"async": true,
|
|
5122
|
+
"params": [
|
|
5123
|
+
"capability: DocumentMoneyWriteCapability",
|
|
5124
|
+
"options?: object"
|
|
5125
|
+
],
|
|
5126
|
+
"returns": "Promise<void>"
|
|
5127
|
+
},
|
|
4872
5128
|
{
|
|
4873
5129
|
"name": "initialize",
|
|
4874
5130
|
"async": true,
|
|
@@ -5032,6 +5288,12 @@
|
|
|
5032
5288
|
"operation": "recalculateTotals",
|
|
5033
5289
|
"objectName": "@happyvertical/smrt-commerce:Estimate"
|
|
5034
5290
|
},
|
|
5291
|
+
{
|
|
5292
|
+
"kind": "cli",
|
|
5293
|
+
"name": "estimate_deleteDerived",
|
|
5294
|
+
"operation": "deleteDerived",
|
|
5295
|
+
"objectName": "@happyvertical/smrt-commerce:Estimate"
|
|
5296
|
+
},
|
|
5035
5297
|
{
|
|
5036
5298
|
"kind": "cli",
|
|
5037
5299
|
"name": "estimate_saveDerived",
|
|
@@ -5052,6 +5314,13 @@
|
|
|
5052
5314
|
}
|
|
5053
5315
|
],
|
|
5054
5316
|
"withheldSurfaces": [
|
|
5317
|
+
{
|
|
5318
|
+
"kind": "api",
|
|
5319
|
+
"operation": "deleteDerived",
|
|
5320
|
+
"code": "not-included",
|
|
5321
|
+
"reason": "not listed in api.include",
|
|
5322
|
+
"objectName": "@happyvertical/smrt-commerce:Estimate"
|
|
5323
|
+
},
|
|
5055
5324
|
{
|
|
5056
5325
|
"kind": "api",
|
|
5057
5326
|
"operation": "initialize",
|
|
@@ -5209,6 +5478,26 @@
|
|
|
5209
5478
|
"default": "USD",
|
|
5210
5479
|
"description": "The currency of the amounts."
|
|
5211
5480
|
},
|
|
5481
|
+
{
|
|
5482
|
+
"name": "moneyAuthority",
|
|
5483
|
+
"type": "text",
|
|
5484
|
+
"required": false,
|
|
5485
|
+
"columnType": "TEXT",
|
|
5486
|
+
"default": "calculated",
|
|
5487
|
+
"description": "Whether amounts were calculated or recorded from reviewed original paperwork."
|
|
5488
|
+
},
|
|
5489
|
+
{
|
|
5490
|
+
"name": "receivedPurchaseMoneyJson",
|
|
5491
|
+
"type": "text",
|
|
5492
|
+
"required": false,
|
|
5493
|
+
"columnType": "TEXT"
|
|
5494
|
+
},
|
|
5495
|
+
{
|
|
5496
|
+
"name": "billingScheduleJson",
|
|
5497
|
+
"type": "text",
|
|
5498
|
+
"required": false,
|
|
5499
|
+
"columnType": "TEXT"
|
|
5500
|
+
},
|
|
5212
5501
|
{
|
|
5213
5502
|
"name": "lineAmountType",
|
|
5214
5503
|
"type": "text",
|
|
@@ -5312,6 +5601,8 @@
|
|
|
5312
5601
|
}
|
|
5313
5602
|
],
|
|
5314
5603
|
"methods": [
|
|
5604
|
+
"delete",
|
|
5605
|
+
"deleteDerived",
|
|
5315
5606
|
"initialize",
|
|
5316
5607
|
"isAccepted",
|
|
5317
5608
|
"isCompleted",
|
|
@@ -5325,17 +5616,34 @@
|
|
|
5325
5616
|
],
|
|
5326
5617
|
"methodSignatures": [
|
|
5327
5618
|
{
|
|
5328
|
-
"name": "
|
|
5619
|
+
"name": "delete",
|
|
5329
5620
|
"async": true,
|
|
5330
|
-
"
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
"
|
|
5334
|
-
"returns": "boolean"
|
|
5621
|
+
"params": [
|
|
5622
|
+
"options?: object"
|
|
5623
|
+
],
|
|
5624
|
+
"returns": "Promise<void>"
|
|
5335
5625
|
},
|
|
5336
5626
|
{
|
|
5337
|
-
"name": "
|
|
5338
|
-
"
|
|
5627
|
+
"name": "deleteDerived",
|
|
5628
|
+
"async": true,
|
|
5629
|
+
"params": [
|
|
5630
|
+
"capability: DocumentMoneyWriteCapability",
|
|
5631
|
+
"options?: object"
|
|
5632
|
+
],
|
|
5633
|
+
"returns": "Promise<void>"
|
|
5634
|
+
},
|
|
5635
|
+
{
|
|
5636
|
+
"name": "initialize",
|
|
5637
|
+
"async": true,
|
|
5638
|
+
"returns": "Promise<this>"
|
|
5639
|
+
},
|
|
5640
|
+
{
|
|
5641
|
+
"name": "isAccepted",
|
|
5642
|
+
"returns": "boolean"
|
|
5643
|
+
},
|
|
5644
|
+
{
|
|
5645
|
+
"name": "isCompleted",
|
|
5646
|
+
"returns": "boolean"
|
|
5339
5647
|
},
|
|
5340
5648
|
{
|
|
5341
5649
|
"name": "isDraft",
|
|
@@ -5487,6 +5795,12 @@
|
|
|
5487
5795
|
"operation": "recalculateTotals",
|
|
5488
5796
|
"objectName": "@happyvertical/smrt-commerce:Order"
|
|
5489
5797
|
},
|
|
5798
|
+
{
|
|
5799
|
+
"kind": "cli",
|
|
5800
|
+
"name": "order_deleteDerived",
|
|
5801
|
+
"operation": "deleteDerived",
|
|
5802
|
+
"objectName": "@happyvertical/smrt-commerce:Order"
|
|
5803
|
+
},
|
|
5490
5804
|
{
|
|
5491
5805
|
"kind": "cli",
|
|
5492
5806
|
"name": "order_saveDerived",
|
|
@@ -5507,6 +5821,13 @@
|
|
|
5507
5821
|
}
|
|
5508
5822
|
],
|
|
5509
5823
|
"withheldSurfaces": [
|
|
5824
|
+
{
|
|
5825
|
+
"kind": "api",
|
|
5826
|
+
"operation": "deleteDerived",
|
|
5827
|
+
"code": "not-included",
|
|
5828
|
+
"reason": "not listed in api.include",
|
|
5829
|
+
"objectName": "@happyvertical/smrt-commerce:Order"
|
|
5830
|
+
},
|
|
5510
5831
|
{
|
|
5511
5832
|
"kind": "api",
|
|
5512
5833
|
"operation": "initialize",
|
|
@@ -5664,6 +5985,26 @@
|
|
|
5664
5985
|
"default": "USD",
|
|
5665
5986
|
"description": "The currency of the amounts."
|
|
5666
5987
|
},
|
|
5988
|
+
{
|
|
5989
|
+
"name": "moneyAuthority",
|
|
5990
|
+
"type": "text",
|
|
5991
|
+
"required": false,
|
|
5992
|
+
"columnType": "TEXT",
|
|
5993
|
+
"default": "calculated",
|
|
5994
|
+
"description": "Whether amounts were calculated or recorded from reviewed original paperwork."
|
|
5995
|
+
},
|
|
5996
|
+
{
|
|
5997
|
+
"name": "receivedPurchaseMoneyJson",
|
|
5998
|
+
"type": "text",
|
|
5999
|
+
"required": false,
|
|
6000
|
+
"columnType": "TEXT"
|
|
6001
|
+
},
|
|
6002
|
+
{
|
|
6003
|
+
"name": "billingScheduleJson",
|
|
6004
|
+
"type": "text",
|
|
6005
|
+
"required": false,
|
|
6006
|
+
"columnType": "TEXT"
|
|
6007
|
+
},
|
|
5667
6008
|
{
|
|
5668
6009
|
"name": "lineAmountType",
|
|
5669
6010
|
"type": "text",
|
|
@@ -5767,6 +6108,8 @@
|
|
|
5767
6108
|
}
|
|
5768
6109
|
],
|
|
5769
6110
|
"methods": [
|
|
6111
|
+
"delete",
|
|
6112
|
+
"deleteDerived",
|
|
5770
6113
|
"initialize",
|
|
5771
6114
|
"isAccepted",
|
|
5772
6115
|
"isCompleted",
|
|
@@ -5779,6 +6122,23 @@
|
|
|
5779
6122
|
"saveDerived"
|
|
5780
6123
|
],
|
|
5781
6124
|
"methodSignatures": [
|
|
6125
|
+
{
|
|
6126
|
+
"name": "delete",
|
|
6127
|
+
"async": true,
|
|
6128
|
+
"params": [
|
|
6129
|
+
"options?: object"
|
|
6130
|
+
],
|
|
6131
|
+
"returns": "Promise<void>"
|
|
6132
|
+
},
|
|
6133
|
+
{
|
|
6134
|
+
"name": "deleteDerived",
|
|
6135
|
+
"async": true,
|
|
6136
|
+
"params": [
|
|
6137
|
+
"capability: DocumentMoneyWriteCapability",
|
|
6138
|
+
"options?: object"
|
|
6139
|
+
],
|
|
6140
|
+
"returns": "Promise<void>"
|
|
6141
|
+
},
|
|
5782
6142
|
{
|
|
5783
6143
|
"name": "initialize",
|
|
5784
6144
|
"async": true,
|
|
@@ -5942,6 +6302,12 @@
|
|
|
5942
6302
|
"operation": "recalculateTotals",
|
|
5943
6303
|
"objectName": "@happyvertical/smrt-commerce:Lease"
|
|
5944
6304
|
},
|
|
6305
|
+
{
|
|
6306
|
+
"kind": "cli",
|
|
6307
|
+
"name": "lease_deleteDerived",
|
|
6308
|
+
"operation": "deleteDerived",
|
|
6309
|
+
"objectName": "@happyvertical/smrt-commerce:Lease"
|
|
6310
|
+
},
|
|
5945
6311
|
{
|
|
5946
6312
|
"kind": "cli",
|
|
5947
6313
|
"name": "lease_saveDerived",
|
|
@@ -5962,6 +6328,13 @@
|
|
|
5962
6328
|
}
|
|
5963
6329
|
],
|
|
5964
6330
|
"withheldSurfaces": [
|
|
6331
|
+
{
|
|
6332
|
+
"kind": "api",
|
|
6333
|
+
"operation": "deleteDerived",
|
|
6334
|
+
"code": "not-included",
|
|
6335
|
+
"reason": "not listed in api.include",
|
|
6336
|
+
"objectName": "@happyvertical/smrt-commerce:Lease"
|
|
6337
|
+
},
|
|
5965
6338
|
{
|
|
5966
6339
|
"kind": "api",
|
|
5967
6340
|
"operation": "initialize",
|
|
@@ -6119,6 +6492,26 @@
|
|
|
6119
6492
|
"default": "USD",
|
|
6120
6493
|
"description": "The currency of the amounts."
|
|
6121
6494
|
},
|
|
6495
|
+
{
|
|
6496
|
+
"name": "moneyAuthority",
|
|
6497
|
+
"type": "text",
|
|
6498
|
+
"required": false,
|
|
6499
|
+
"columnType": "TEXT",
|
|
6500
|
+
"default": "calculated",
|
|
6501
|
+
"description": "Whether amounts were calculated or recorded from reviewed original paperwork."
|
|
6502
|
+
},
|
|
6503
|
+
{
|
|
6504
|
+
"name": "receivedPurchaseMoneyJson",
|
|
6505
|
+
"type": "text",
|
|
6506
|
+
"required": false,
|
|
6507
|
+
"columnType": "TEXT"
|
|
6508
|
+
},
|
|
6509
|
+
{
|
|
6510
|
+
"name": "billingScheduleJson",
|
|
6511
|
+
"type": "text",
|
|
6512
|
+
"required": false,
|
|
6513
|
+
"columnType": "TEXT"
|
|
6514
|
+
},
|
|
6122
6515
|
{
|
|
6123
6516
|
"name": "lineAmountType",
|
|
6124
6517
|
"type": "text",
|
|
@@ -6222,6 +6615,8 @@
|
|
|
6222
6615
|
}
|
|
6223
6616
|
],
|
|
6224
6617
|
"methods": [
|
|
6618
|
+
"delete",
|
|
6619
|
+
"deleteDerived",
|
|
6225
6620
|
"initialize",
|
|
6226
6621
|
"isAccepted",
|
|
6227
6622
|
"isCompleted",
|
|
@@ -6234,6 +6629,23 @@
|
|
|
6234
6629
|
"saveDerived"
|
|
6235
6630
|
],
|
|
6236
6631
|
"methodSignatures": [
|
|
6632
|
+
{
|
|
6633
|
+
"name": "delete",
|
|
6634
|
+
"async": true,
|
|
6635
|
+
"params": [
|
|
6636
|
+
"options?: object"
|
|
6637
|
+
],
|
|
6638
|
+
"returns": "Promise<void>"
|
|
6639
|
+
},
|
|
6640
|
+
{
|
|
6641
|
+
"name": "deleteDerived",
|
|
6642
|
+
"async": true,
|
|
6643
|
+
"params": [
|
|
6644
|
+
"capability: DocumentMoneyWriteCapability",
|
|
6645
|
+
"options?: object"
|
|
6646
|
+
],
|
|
6647
|
+
"returns": "Promise<void>"
|
|
6648
|
+
},
|
|
6237
6649
|
{
|
|
6238
6650
|
"name": "initialize",
|
|
6239
6651
|
"async": true,
|
|
@@ -6397,6 +6809,12 @@
|
|
|
6397
6809
|
"operation": "recalculateTotals",
|
|
6398
6810
|
"objectName": "@happyvertical/smrt-commerce:Agreement"
|
|
6399
6811
|
},
|
|
6812
|
+
{
|
|
6813
|
+
"kind": "cli",
|
|
6814
|
+
"name": "agreement_deleteDerived",
|
|
6815
|
+
"operation": "deleteDerived",
|
|
6816
|
+
"objectName": "@happyvertical/smrt-commerce:Agreement"
|
|
6817
|
+
},
|
|
6400
6818
|
{
|
|
6401
6819
|
"kind": "cli",
|
|
6402
6820
|
"name": "agreement_saveDerived",
|
|
@@ -6417,6 +6835,13 @@
|
|
|
6417
6835
|
}
|
|
6418
6836
|
],
|
|
6419
6837
|
"withheldSurfaces": [
|
|
6838
|
+
{
|
|
6839
|
+
"kind": "api",
|
|
6840
|
+
"operation": "deleteDerived",
|
|
6841
|
+
"code": "not-included",
|
|
6842
|
+
"reason": "not listed in api.include",
|
|
6843
|
+
"objectName": "@happyvertical/smrt-commerce:Agreement"
|
|
6844
|
+
},
|
|
6420
6845
|
{
|
|
6421
6846
|
"kind": "api",
|
|
6422
6847
|
"operation": "initialize",
|
|
@@ -6574,6 +6999,26 @@
|
|
|
6574
6999
|
"default": "USD",
|
|
6575
7000
|
"description": "The currency of the amounts."
|
|
6576
7001
|
},
|
|
7002
|
+
{
|
|
7003
|
+
"name": "moneyAuthority",
|
|
7004
|
+
"type": "text",
|
|
7005
|
+
"required": false,
|
|
7006
|
+
"columnType": "TEXT",
|
|
7007
|
+
"default": "calculated",
|
|
7008
|
+
"description": "Whether amounts were calculated or recorded from reviewed original paperwork."
|
|
7009
|
+
},
|
|
7010
|
+
{
|
|
7011
|
+
"name": "receivedPurchaseMoneyJson",
|
|
7012
|
+
"type": "text",
|
|
7013
|
+
"required": false,
|
|
7014
|
+
"columnType": "TEXT"
|
|
7015
|
+
},
|
|
7016
|
+
{
|
|
7017
|
+
"name": "billingScheduleJson",
|
|
7018
|
+
"type": "text",
|
|
7019
|
+
"required": false,
|
|
7020
|
+
"columnType": "TEXT"
|
|
7021
|
+
},
|
|
6577
7022
|
{
|
|
6578
7023
|
"name": "lineAmountType",
|
|
6579
7024
|
"type": "text",
|
|
@@ -6677,6 +7122,8 @@
|
|
|
6677
7122
|
}
|
|
6678
7123
|
],
|
|
6679
7124
|
"methods": [
|
|
7125
|
+
"delete",
|
|
7126
|
+
"deleteDerived",
|
|
6680
7127
|
"initialize",
|
|
6681
7128
|
"isAccepted",
|
|
6682
7129
|
"isCompleted",
|
|
@@ -6689,6 +7136,23 @@
|
|
|
6689
7136
|
"saveDerived"
|
|
6690
7137
|
],
|
|
6691
7138
|
"methodSignatures": [
|
|
7139
|
+
{
|
|
7140
|
+
"name": "delete",
|
|
7141
|
+
"async": true,
|
|
7142
|
+
"params": [
|
|
7143
|
+
"options?: object"
|
|
7144
|
+
],
|
|
7145
|
+
"returns": "Promise<void>"
|
|
7146
|
+
},
|
|
7147
|
+
{
|
|
7148
|
+
"name": "deleteDerived",
|
|
7149
|
+
"async": true,
|
|
7150
|
+
"params": [
|
|
7151
|
+
"capability: DocumentMoneyWriteCapability",
|
|
7152
|
+
"options?: object"
|
|
7153
|
+
],
|
|
7154
|
+
"returns": "Promise<void>"
|
|
7155
|
+
},
|
|
6692
7156
|
{
|
|
6693
7157
|
"name": "initialize",
|
|
6694
7158
|
"async": true,
|
|
@@ -6852,6 +7316,12 @@
|
|
|
6852
7316
|
"operation": "recalculateTotals",
|
|
6853
7317
|
"objectName": "@happyvertical/smrt-commerce:SupplierQuote"
|
|
6854
7318
|
},
|
|
7319
|
+
{
|
|
7320
|
+
"kind": "cli",
|
|
7321
|
+
"name": "supplierquote_deleteDerived",
|
|
7322
|
+
"operation": "deleteDerived",
|
|
7323
|
+
"objectName": "@happyvertical/smrt-commerce:SupplierQuote"
|
|
7324
|
+
},
|
|
6855
7325
|
{
|
|
6856
7326
|
"kind": "cli",
|
|
6857
7327
|
"name": "supplierquote_saveDerived",
|
|
@@ -6872,6 +7342,13 @@
|
|
|
6872
7342
|
}
|
|
6873
7343
|
],
|
|
6874
7344
|
"withheldSurfaces": [
|
|
7345
|
+
{
|
|
7346
|
+
"kind": "api",
|
|
7347
|
+
"operation": "deleteDerived",
|
|
7348
|
+
"code": "not-included",
|
|
7349
|
+
"reason": "not listed in api.include",
|
|
7350
|
+
"objectName": "@happyvertical/smrt-commerce:SupplierQuote"
|
|
7351
|
+
},
|
|
6875
7352
|
{
|
|
6876
7353
|
"kind": "api",
|
|
6877
7354
|
"operation": "initialize",
|
|
@@ -7029,6 +7506,26 @@
|
|
|
7029
7506
|
"default": "USD",
|
|
7030
7507
|
"description": "The currency of the amounts."
|
|
7031
7508
|
},
|
|
7509
|
+
{
|
|
7510
|
+
"name": "moneyAuthority",
|
|
7511
|
+
"type": "text",
|
|
7512
|
+
"required": false,
|
|
7513
|
+
"columnType": "TEXT",
|
|
7514
|
+
"default": "calculated",
|
|
7515
|
+
"description": "Whether amounts were calculated or recorded from reviewed original paperwork."
|
|
7516
|
+
},
|
|
7517
|
+
{
|
|
7518
|
+
"name": "receivedPurchaseMoneyJson",
|
|
7519
|
+
"type": "text",
|
|
7520
|
+
"required": false,
|
|
7521
|
+
"columnType": "TEXT"
|
|
7522
|
+
},
|
|
7523
|
+
{
|
|
7524
|
+
"name": "billingScheduleJson",
|
|
7525
|
+
"type": "text",
|
|
7526
|
+
"required": false,
|
|
7527
|
+
"columnType": "TEXT"
|
|
7528
|
+
},
|
|
7032
7529
|
{
|
|
7033
7530
|
"name": "lineAmountType",
|
|
7034
7531
|
"type": "text",
|
|
@@ -7146,6 +7643,8 @@
|
|
|
7146
7643
|
}
|
|
7147
7644
|
],
|
|
7148
7645
|
"methods": [
|
|
7646
|
+
"delete",
|
|
7647
|
+
"deleteDerived",
|
|
7149
7648
|
"initialize",
|
|
7150
7649
|
"isAccepted",
|
|
7151
7650
|
"isCompleted",
|
|
@@ -7158,6 +7657,23 @@
|
|
|
7158
7657
|
"saveDerived"
|
|
7159
7658
|
],
|
|
7160
7659
|
"methodSignatures": [
|
|
7660
|
+
{
|
|
7661
|
+
"name": "delete",
|
|
7662
|
+
"async": true,
|
|
7663
|
+
"params": [
|
|
7664
|
+
"options?: object"
|
|
7665
|
+
],
|
|
7666
|
+
"returns": "Promise<void>"
|
|
7667
|
+
},
|
|
7668
|
+
{
|
|
7669
|
+
"name": "deleteDerived",
|
|
7670
|
+
"async": true,
|
|
7671
|
+
"params": [
|
|
7672
|
+
"capability: DocumentMoneyWriteCapability",
|
|
7673
|
+
"options?: object"
|
|
7674
|
+
],
|
|
7675
|
+
"returns": "Promise<void>"
|
|
7676
|
+
},
|
|
7161
7677
|
{
|
|
7162
7678
|
"name": "initialize",
|
|
7163
7679
|
"async": true,
|
|
@@ -7321,6 +7837,12 @@
|
|
|
7321
7837
|
"operation": "recalculateTotals",
|
|
7322
7838
|
"objectName": "@happyvertical/smrt-commerce:PurchaseOrder"
|
|
7323
7839
|
},
|
|
7840
|
+
{
|
|
7841
|
+
"kind": "cli",
|
|
7842
|
+
"name": "purchaseorder_deleteDerived",
|
|
7843
|
+
"operation": "deleteDerived",
|
|
7844
|
+
"objectName": "@happyvertical/smrt-commerce:PurchaseOrder"
|
|
7845
|
+
},
|
|
7324
7846
|
{
|
|
7325
7847
|
"kind": "cli",
|
|
7326
7848
|
"name": "purchaseorder_saveDerived",
|
|
@@ -7341,6 +7863,13 @@
|
|
|
7341
7863
|
}
|
|
7342
7864
|
],
|
|
7343
7865
|
"withheldSurfaces": [
|
|
7866
|
+
{
|
|
7867
|
+
"kind": "api",
|
|
7868
|
+
"operation": "deleteDerived",
|
|
7869
|
+
"code": "not-included",
|
|
7870
|
+
"reason": "not listed in api.include",
|
|
7871
|
+
"objectName": "@happyvertical/smrt-commerce:PurchaseOrder"
|
|
7872
|
+
},
|
|
7344
7873
|
{
|
|
7345
7874
|
"kind": "api",
|
|
7346
7875
|
"operation": "initialize",
|
|
@@ -7498,6 +8027,26 @@
|
|
|
7498
8027
|
"default": "USD",
|
|
7499
8028
|
"description": "The currency of the amounts."
|
|
7500
8029
|
},
|
|
8030
|
+
{
|
|
8031
|
+
"name": "moneyAuthority",
|
|
8032
|
+
"type": "text",
|
|
8033
|
+
"required": false,
|
|
8034
|
+
"columnType": "TEXT",
|
|
8035
|
+
"default": "calculated",
|
|
8036
|
+
"description": "Whether amounts were calculated or recorded from reviewed original paperwork."
|
|
8037
|
+
},
|
|
8038
|
+
{
|
|
8039
|
+
"name": "receivedPurchaseMoneyJson",
|
|
8040
|
+
"type": "text",
|
|
8041
|
+
"required": false,
|
|
8042
|
+
"columnType": "TEXT"
|
|
8043
|
+
},
|
|
8044
|
+
{
|
|
8045
|
+
"name": "billingScheduleJson",
|
|
8046
|
+
"type": "text",
|
|
8047
|
+
"required": false,
|
|
8048
|
+
"columnType": "TEXT"
|
|
8049
|
+
},
|
|
7501
8050
|
{
|
|
7502
8051
|
"name": "lineAmountType",
|
|
7503
8052
|
"type": "text",
|
|
@@ -7601,6 +8150,8 @@
|
|
|
7601
8150
|
}
|
|
7602
8151
|
],
|
|
7603
8152
|
"methods": [
|
|
8153
|
+
"delete",
|
|
8154
|
+
"deleteDerived",
|
|
7604
8155
|
"initialize",
|
|
7605
8156
|
"isAccepted",
|
|
7606
8157
|
"isCompleted",
|
|
@@ -7613,6 +8164,23 @@
|
|
|
7613
8164
|
"saveDerived"
|
|
7614
8165
|
],
|
|
7615
8166
|
"methodSignatures": [
|
|
8167
|
+
{
|
|
8168
|
+
"name": "delete",
|
|
8169
|
+
"async": true,
|
|
8170
|
+
"params": [
|
|
8171
|
+
"options?: object"
|
|
8172
|
+
],
|
|
8173
|
+
"returns": "Promise<void>"
|
|
8174
|
+
},
|
|
8175
|
+
{
|
|
8176
|
+
"name": "deleteDerived",
|
|
8177
|
+
"async": true,
|
|
8178
|
+
"params": [
|
|
8179
|
+
"capability: DocumentMoneyWriteCapability",
|
|
8180
|
+
"options?: object"
|
|
8181
|
+
],
|
|
8182
|
+
"returns": "Promise<void>"
|
|
8183
|
+
},
|
|
7616
8184
|
{
|
|
7617
8185
|
"name": "initialize",
|
|
7618
8186
|
"async": true,
|
|
@@ -7776,6 +8344,12 @@
|
|
|
7776
8344
|
"operation": "recalculateTotals",
|
|
7777
8345
|
"objectName": "@happyvertical/smrt-commerce:WholesaleOrder"
|
|
7778
8346
|
},
|
|
8347
|
+
{
|
|
8348
|
+
"kind": "cli",
|
|
8349
|
+
"name": "wholesaleorder_deleteDerived",
|
|
8350
|
+
"operation": "deleteDerived",
|
|
8351
|
+
"objectName": "@happyvertical/smrt-commerce:WholesaleOrder"
|
|
8352
|
+
},
|
|
7779
8353
|
{
|
|
7780
8354
|
"kind": "cli",
|
|
7781
8355
|
"name": "wholesaleorder_saveDerived",
|
|
@@ -7798,7 +8372,14 @@
|
|
|
7798
8372
|
"withheldSurfaces": [
|
|
7799
8373
|
{
|
|
7800
8374
|
"kind": "api",
|
|
7801
|
-
"operation": "
|
|
8375
|
+
"operation": "deleteDerived",
|
|
8376
|
+
"code": "not-included",
|
|
8377
|
+
"reason": "not listed in api.include",
|
|
8378
|
+
"objectName": "@happyvertical/smrt-commerce:WholesaleOrder"
|
|
8379
|
+
},
|
|
8380
|
+
{
|
|
8381
|
+
"kind": "api",
|
|
8382
|
+
"operation": "initialize",
|
|
7802
8383
|
"code": "lifecycle-method",
|
|
7803
8384
|
"reason": "`initialize` is a framework lifecycle method, not a distinct operation",
|
|
7804
8385
|
"objectName": "@happyvertical/smrt-commerce:WholesaleOrder"
|
|
@@ -7953,6 +8534,26 @@
|
|
|
7953
8534
|
"default": "USD",
|
|
7954
8535
|
"description": "The currency of the amounts."
|
|
7955
8536
|
},
|
|
8537
|
+
{
|
|
8538
|
+
"name": "moneyAuthority",
|
|
8539
|
+
"type": "text",
|
|
8540
|
+
"required": false,
|
|
8541
|
+
"columnType": "TEXT",
|
|
8542
|
+
"default": "calculated",
|
|
8543
|
+
"description": "Whether amounts were calculated or recorded from reviewed original paperwork."
|
|
8544
|
+
},
|
|
8545
|
+
{
|
|
8546
|
+
"name": "receivedPurchaseMoneyJson",
|
|
8547
|
+
"type": "text",
|
|
8548
|
+
"required": false,
|
|
8549
|
+
"columnType": "TEXT"
|
|
8550
|
+
},
|
|
8551
|
+
{
|
|
8552
|
+
"name": "billingScheduleJson",
|
|
8553
|
+
"type": "text",
|
|
8554
|
+
"required": false,
|
|
8555
|
+
"columnType": "TEXT"
|
|
8556
|
+
},
|
|
7956
8557
|
{
|
|
7957
8558
|
"name": "lineAmountType",
|
|
7958
8559
|
"type": "text",
|
|
@@ -8069,6 +8670,8 @@
|
|
|
8069
8670
|
}
|
|
8070
8671
|
],
|
|
8071
8672
|
"methods": [
|
|
8673
|
+
"delete",
|
|
8674
|
+
"deleteDerived",
|
|
8072
8675
|
"initialize",
|
|
8073
8676
|
"isAccepted",
|
|
8074
8677
|
"isCompleted",
|
|
@@ -8081,6 +8684,23 @@
|
|
|
8081
8684
|
"saveDerived"
|
|
8082
8685
|
],
|
|
8083
8686
|
"methodSignatures": [
|
|
8687
|
+
{
|
|
8688
|
+
"name": "delete",
|
|
8689
|
+
"async": true,
|
|
8690
|
+
"params": [
|
|
8691
|
+
"options?: object"
|
|
8692
|
+
],
|
|
8693
|
+
"returns": "Promise<void>"
|
|
8694
|
+
},
|
|
8695
|
+
{
|
|
8696
|
+
"name": "deleteDerived",
|
|
8697
|
+
"async": true,
|
|
8698
|
+
"params": [
|
|
8699
|
+
"capability: DocumentMoneyWriteCapability",
|
|
8700
|
+
"options?: object"
|
|
8701
|
+
],
|
|
8702
|
+
"returns": "Promise<void>"
|
|
8703
|
+
},
|
|
8084
8704
|
{
|
|
8085
8705
|
"name": "initialize",
|
|
8086
8706
|
"async": true,
|
|
@@ -8244,6 +8864,12 @@
|
|
|
8244
8864
|
"operation": "recalculateTotals",
|
|
8245
8865
|
"objectName": "@happyvertical/smrt-commerce:ProductionOrder"
|
|
8246
8866
|
},
|
|
8867
|
+
{
|
|
8868
|
+
"kind": "cli",
|
|
8869
|
+
"name": "productionorder_deleteDerived",
|
|
8870
|
+
"operation": "deleteDerived",
|
|
8871
|
+
"objectName": "@happyvertical/smrt-commerce:ProductionOrder"
|
|
8872
|
+
},
|
|
8247
8873
|
{
|
|
8248
8874
|
"kind": "cli",
|
|
8249
8875
|
"name": "productionorder_saveDerived",
|
|
@@ -8264,6 +8890,13 @@
|
|
|
8264
8890
|
}
|
|
8265
8891
|
],
|
|
8266
8892
|
"withheldSurfaces": [
|
|
8893
|
+
{
|
|
8894
|
+
"kind": "api",
|
|
8895
|
+
"operation": "deleteDerived",
|
|
8896
|
+
"code": "not-included",
|
|
8897
|
+
"reason": "not listed in api.include",
|
|
8898
|
+
"objectName": "@happyvertical/smrt-commerce:ProductionOrder"
|
|
8899
|
+
},
|
|
8267
8900
|
{
|
|
8268
8901
|
"kind": "api",
|
|
8269
8902
|
"operation": "initialize",
|
|
@@ -8421,6 +9054,26 @@
|
|
|
8421
9054
|
"default": "USD",
|
|
8422
9055
|
"description": "The currency of the amounts."
|
|
8423
9056
|
},
|
|
9057
|
+
{
|
|
9058
|
+
"name": "moneyAuthority",
|
|
9059
|
+
"type": "text",
|
|
9060
|
+
"required": false,
|
|
9061
|
+
"columnType": "TEXT",
|
|
9062
|
+
"default": "calculated",
|
|
9063
|
+
"description": "Whether amounts were calculated or recorded from reviewed original paperwork."
|
|
9064
|
+
},
|
|
9065
|
+
{
|
|
9066
|
+
"name": "receivedPurchaseMoneyJson",
|
|
9067
|
+
"type": "text",
|
|
9068
|
+
"required": false,
|
|
9069
|
+
"columnType": "TEXT"
|
|
9070
|
+
},
|
|
9071
|
+
{
|
|
9072
|
+
"name": "billingScheduleJson",
|
|
9073
|
+
"type": "text",
|
|
9074
|
+
"required": false,
|
|
9075
|
+
"columnType": "TEXT"
|
|
9076
|
+
},
|
|
8424
9077
|
{
|
|
8425
9078
|
"name": "lineAmountType",
|
|
8426
9079
|
"type": "text",
|
|
@@ -8525,6 +9178,8 @@
|
|
|
8525
9178
|
}
|
|
8526
9179
|
],
|
|
8527
9180
|
"methods": [
|
|
9181
|
+
"delete",
|
|
9182
|
+
"deleteDerived",
|
|
8528
9183
|
"initialize",
|
|
8529
9184
|
"isAccepted",
|
|
8530
9185
|
"isCompleted",
|
|
@@ -8537,6 +9192,23 @@
|
|
|
8537
9192
|
"saveDerived"
|
|
8538
9193
|
],
|
|
8539
9194
|
"methodSignatures": [
|
|
9195
|
+
{
|
|
9196
|
+
"name": "delete",
|
|
9197
|
+
"async": true,
|
|
9198
|
+
"params": [
|
|
9199
|
+
"options?: object"
|
|
9200
|
+
],
|
|
9201
|
+
"returns": "Promise<void>"
|
|
9202
|
+
},
|
|
9203
|
+
{
|
|
9204
|
+
"name": "deleteDerived",
|
|
9205
|
+
"async": true,
|
|
9206
|
+
"params": [
|
|
9207
|
+
"capability: DocumentMoneyWriteCapability",
|
|
9208
|
+
"options?: object"
|
|
9209
|
+
],
|
|
9210
|
+
"returns": "Promise<void>"
|
|
9211
|
+
},
|
|
8540
9212
|
{
|
|
8541
9213
|
"name": "initialize",
|
|
8542
9214
|
"async": true,
|
|
@@ -8700,6 +9372,12 @@
|
|
|
8700
9372
|
"operation": "recalculateTotals",
|
|
8701
9373
|
"objectName": "@happyvertical/smrt-commerce:Cart"
|
|
8702
9374
|
},
|
|
9375
|
+
{
|
|
9376
|
+
"kind": "cli",
|
|
9377
|
+
"name": "cart_deleteDerived",
|
|
9378
|
+
"operation": "deleteDerived",
|
|
9379
|
+
"objectName": "@happyvertical/smrt-commerce:Cart"
|
|
9380
|
+
},
|
|
8703
9381
|
{
|
|
8704
9382
|
"kind": "cli",
|
|
8705
9383
|
"name": "cart_saveDerived",
|
|
@@ -8720,6 +9398,13 @@
|
|
|
8720
9398
|
}
|
|
8721
9399
|
],
|
|
8722
9400
|
"withheldSurfaces": [
|
|
9401
|
+
{
|
|
9402
|
+
"kind": "api",
|
|
9403
|
+
"operation": "deleteDerived",
|
|
9404
|
+
"code": "not-included",
|
|
9405
|
+
"reason": "not listed in api.include",
|
|
9406
|
+
"objectName": "@happyvertical/smrt-commerce:Cart"
|
|
9407
|
+
},
|
|
8723
9408
|
{
|
|
8724
9409
|
"kind": "api",
|
|
8725
9410
|
"operation": "initialize",
|
|
@@ -8877,6 +9562,26 @@
|
|
|
8877
9562
|
"default": "USD",
|
|
8878
9563
|
"description": "The currency of the amounts."
|
|
8879
9564
|
},
|
|
9565
|
+
{
|
|
9566
|
+
"name": "moneyAuthority",
|
|
9567
|
+
"type": "text",
|
|
9568
|
+
"required": false,
|
|
9569
|
+
"columnType": "TEXT",
|
|
9570
|
+
"default": "calculated",
|
|
9571
|
+
"description": "Whether amounts were calculated or recorded from reviewed original paperwork."
|
|
9572
|
+
},
|
|
9573
|
+
{
|
|
9574
|
+
"name": "receivedPurchaseMoneyJson",
|
|
9575
|
+
"type": "text",
|
|
9576
|
+
"required": false,
|
|
9577
|
+
"columnType": "TEXT"
|
|
9578
|
+
},
|
|
9579
|
+
{
|
|
9580
|
+
"name": "billingScheduleJson",
|
|
9581
|
+
"type": "text",
|
|
9582
|
+
"required": false,
|
|
9583
|
+
"columnType": "TEXT"
|
|
9584
|
+
},
|
|
8880
9585
|
{
|
|
8881
9586
|
"name": "lineAmountType",
|
|
8882
9587
|
"type": "text",
|
|
@@ -9071,6 +9776,8 @@
|
|
|
9071
9776
|
}
|
|
9072
9777
|
],
|
|
9073
9778
|
"methods": [
|
|
9779
|
+
"delete",
|
|
9780
|
+
"deleteDerived",
|
|
9074
9781
|
"getRightsSnapshot",
|
|
9075
9782
|
"initialize",
|
|
9076
9783
|
"isAccepted",
|
|
@@ -9085,6 +9792,23 @@
|
|
|
9085
9792
|
"saveDerived"
|
|
9086
9793
|
],
|
|
9087
9794
|
"methodSignatures": [
|
|
9795
|
+
{
|
|
9796
|
+
"name": "delete",
|
|
9797
|
+
"async": true,
|
|
9798
|
+
"params": [
|
|
9799
|
+
"options?: object"
|
|
9800
|
+
],
|
|
9801
|
+
"returns": "Promise<void>"
|
|
9802
|
+
},
|
|
9803
|
+
{
|
|
9804
|
+
"name": "deleteDerived",
|
|
9805
|
+
"async": true,
|
|
9806
|
+
"params": [
|
|
9807
|
+
"capability: DocumentMoneyWriteCapability",
|
|
9808
|
+
"options?: object"
|
|
9809
|
+
],
|
|
9810
|
+
"returns": "Promise<void>"
|
|
9811
|
+
},
|
|
9088
9812
|
{
|
|
9089
9813
|
"name": "getRightsSnapshot",
|
|
9090
9814
|
"returns": "LicenseRightsSnapshot"
|
|
@@ -9256,6 +9980,12 @@
|
|
|
9256
9980
|
"operation": "recalculateTotals",
|
|
9257
9981
|
"objectName": "@happyvertical/smrt-commerce:LicenseSale"
|
|
9258
9982
|
},
|
|
9983
|
+
{
|
|
9984
|
+
"kind": "cli",
|
|
9985
|
+
"name": "licensesale_deleteDerived",
|
|
9986
|
+
"operation": "deleteDerived",
|
|
9987
|
+
"objectName": "@happyvertical/smrt-commerce:LicenseSale"
|
|
9988
|
+
},
|
|
9259
9989
|
{
|
|
9260
9990
|
"kind": "cli",
|
|
9261
9991
|
"name": "licensesale_saveDerived",
|
|
@@ -9288,6 +10018,13 @@
|
|
|
9288
10018
|
}
|
|
9289
10019
|
],
|
|
9290
10020
|
"withheldSurfaces": [
|
|
10021
|
+
{
|
|
10022
|
+
"kind": "api",
|
|
10023
|
+
"operation": "deleteDerived",
|
|
10024
|
+
"code": "not-included",
|
|
10025
|
+
"reason": "not listed in api.include",
|
|
10026
|
+
"objectName": "@happyvertical/smrt-commerce:LicenseSale"
|
|
10027
|
+
},
|
|
9291
10028
|
{
|
|
9292
10029
|
"kind": "api",
|
|
9293
10030
|
"operation": "getRightsSnapshot",
|
|
@@ -10231,7 +10968,14 @@
|
|
|
10231
10968
|
"required": true,
|
|
10232
10969
|
"columnType": "INTEGER",
|
|
10233
10970
|
"default": 0,
|
|
10234
|
-
"description": "
|
|
10971
|
+
"description": "Actual component taxable basis, including prior compound taxes."
|
|
10972
|
+
},
|
|
10973
|
+
{
|
|
10974
|
+
"name": "netMinor",
|
|
10975
|
+
"type": "integer",
|
|
10976
|
+
"required": false,
|
|
10977
|
+
"columnType": "INTEGER",
|
|
10978
|
+
"description": "Net basis when different from the component taxable basis."
|
|
10235
10979
|
},
|
|
10236
10980
|
{
|
|
10237
10981
|
"name": "taxMinor",
|
|
@@ -10889,40 +11633,18 @@
|
|
|
10889
11633
|
"risks": []
|
|
10890
11634
|
},
|
|
10891
11635
|
{
|
|
10892
|
-
"name": "
|
|
10893
|
-
"qualifiedName": "@happyvertical/smrt-commerce:
|
|
10894
|
-
"collection": "
|
|
10895
|
-
"description": "
|
|
10896
|
-
"tableName": "
|
|
11636
|
+
"name": "HistoricalCustomerFunds",
|
|
11637
|
+
"qualifiedName": "@happyvertical/smrt-commerce:HistoricalCustomerFunds",
|
|
11638
|
+
"collection": "historicalcustomerfundses",
|
|
11639
|
+
"description": "Retained original cash evidence. It is deliberately not a completed ledger-backed Payment.",
|
|
11640
|
+
"tableName": "historical_customer_funds",
|
|
10897
11641
|
"packageName": "@happyvertical/smrt-commerce",
|
|
10898
11642
|
"extends": "SmrtObject",
|
|
10899
11643
|
"fields": [
|
|
10900
|
-
{
|
|
10901
|
-
"name": "kind",
|
|
10902
|
-
"type": "text",
|
|
10903
|
-
"required": false,
|
|
10904
|
-
"columnType": "TEXT",
|
|
10905
|
-
"default": "invoice",
|
|
10906
|
-
"description": "Invoice or customer credit note."
|
|
10907
|
-
},
|
|
10908
|
-
{
|
|
10909
|
-
"name": "creditedInvoiceId",
|
|
10910
|
-
"type": "foreignKey",
|
|
10911
|
-
"required": false,
|
|
10912
|
-
"related": "Invoice",
|
|
10913
|
-
"columnType": "UUID"
|
|
10914
|
-
},
|
|
10915
|
-
{
|
|
10916
|
-
"name": "creditedAmount",
|
|
10917
|
-
"type": "integer",
|
|
10918
|
-
"required": true,
|
|
10919
|
-
"columnType": "INTEGER",
|
|
10920
|
-
"default": 0
|
|
10921
|
-
},
|
|
10922
11644
|
{
|
|
10923
11645
|
"name": "tenantId",
|
|
10924
11646
|
"type": "text",
|
|
10925
|
-
"required":
|
|
11647
|
+
"required": true,
|
|
10926
11648
|
"columnType": "UUID"
|
|
10927
11649
|
},
|
|
10928
11650
|
{
|
|
@@ -10930,100 +11652,763 @@
|
|
|
10930
11652
|
"type": "foreignKey",
|
|
10931
11653
|
"required": false,
|
|
10932
11654
|
"related": "Customer",
|
|
10933
|
-
"columnType": "UUID"
|
|
10934
|
-
"description": "The customer being billed."
|
|
11655
|
+
"columnType": "UUID"
|
|
10935
11656
|
},
|
|
10936
11657
|
{
|
|
10937
11658
|
"name": "contractId",
|
|
10938
11659
|
"type": "foreignKey",
|
|
10939
11660
|
"required": false,
|
|
10940
|
-
"related": "
|
|
10941
|
-
"columnType": "UUID"
|
|
10942
|
-
"description": "The order or agreement this invoice bills for, if any."
|
|
11661
|
+
"related": "Contract",
|
|
11662
|
+
"columnType": "UUID"
|
|
10943
11663
|
},
|
|
10944
11664
|
{
|
|
10945
|
-
"name": "
|
|
11665
|
+
"name": "sourceKeyHash",
|
|
10946
11666
|
"type": "text",
|
|
10947
11667
|
"required": false,
|
|
10948
|
-
"columnType": "TEXT"
|
|
10949
|
-
"default": "",
|
|
10950
|
-
"description": "The number printed on the invoice."
|
|
11668
|
+
"columnType": "TEXT"
|
|
10951
11669
|
},
|
|
10952
11670
|
{
|
|
10953
|
-
"name": "
|
|
11671
|
+
"name": "kind",
|
|
10954
11672
|
"type": "text",
|
|
10955
11673
|
"required": false,
|
|
10956
11674
|
"columnType": "TEXT",
|
|
10957
|
-
"default": ""
|
|
10958
|
-
},
|
|
10959
|
-
{
|
|
10960
|
-
"name": "issueDate",
|
|
10961
|
-
"type": "datetime",
|
|
10962
|
-
"required": false,
|
|
10963
|
-
"columnType": "TIMESTAMP",
|
|
10964
|
-
"description": "The date the invoice was issued."
|
|
11675
|
+
"default": "receipt"
|
|
10965
11676
|
},
|
|
10966
11677
|
{
|
|
10967
|
-
"name": "
|
|
10968
|
-
"type": "
|
|
11678
|
+
"name": "origin",
|
|
11679
|
+
"type": "text",
|
|
10969
11680
|
"required": false,
|
|
10970
|
-
"columnType": "
|
|
10971
|
-
"
|
|
11681
|
+
"columnType": "TEXT",
|
|
11682
|
+
"default": "historical"
|
|
10972
11683
|
},
|
|
10973
11684
|
{
|
|
10974
|
-
"name": "
|
|
10975
|
-
"type": "
|
|
11685
|
+
"name": "paymentId",
|
|
11686
|
+
"type": "foreignKey",
|
|
10976
11687
|
"required": false,
|
|
10977
|
-
"
|
|
10978
|
-
"
|
|
11688
|
+
"related": "Payment",
|
|
11689
|
+
"columnType": "UUID"
|
|
10979
11690
|
},
|
|
10980
11691
|
{
|
|
10981
|
-
"name": "
|
|
10982
|
-
"type": "
|
|
11692
|
+
"name": "currency",
|
|
11693
|
+
"type": "text",
|
|
10983
11694
|
"required": false,
|
|
10984
|
-
"columnType": "
|
|
10985
|
-
"default": 0,
|
|
10986
|
-
"description": "The amount before tax."
|
|
11695
|
+
"columnType": "TEXT"
|
|
10987
11696
|
},
|
|
10988
11697
|
{
|
|
10989
|
-
"name": "
|
|
11698
|
+
"name": "amountMinor",
|
|
10990
11699
|
"type": "integer",
|
|
10991
|
-
"required":
|
|
11700
|
+
"required": true,
|
|
10992
11701
|
"columnType": "INTEGER",
|
|
10993
|
-
"default": 0
|
|
10994
|
-
"description": "The tax charged."
|
|
11702
|
+
"default": 0
|
|
10995
11703
|
},
|
|
10996
11704
|
{
|
|
10997
|
-
"name": "
|
|
10998
|
-
"type": "
|
|
11705
|
+
"name": "effectiveOn",
|
|
11706
|
+
"type": "text",
|
|
10999
11707
|
"required": false,
|
|
11000
|
-
"columnType": "
|
|
11001
|
-
"default": 0
|
|
11708
|
+
"columnType": "TEXT"
|
|
11002
11709
|
},
|
|
11003
11710
|
{
|
|
11004
|
-
"name": "
|
|
11005
|
-
"type": "
|
|
11711
|
+
"name": "sourceReceiptId",
|
|
11712
|
+
"type": "foreignKey",
|
|
11006
11713
|
"required": false,
|
|
11007
|
-
"
|
|
11008
|
-
"
|
|
11009
|
-
"description": "What the customer owes in all, tax included."
|
|
11714
|
+
"related": "HistoricalCustomerFunds",
|
|
11715
|
+
"columnType": "UUID"
|
|
11010
11716
|
},
|
|
11011
11717
|
{
|
|
11012
|
-
"name": "
|
|
11013
|
-
"type": "
|
|
11718
|
+
"name": "sourceCreditNoteId",
|
|
11719
|
+
"type": "foreignKey",
|
|
11014
11720
|
"required": false,
|
|
11015
|
-
"
|
|
11016
|
-
"
|
|
11017
|
-
"description": "How much of the total has been paid so far."
|
|
11721
|
+
"related": "Invoice",
|
|
11722
|
+
"columnType": "UUID"
|
|
11018
11723
|
},
|
|
11019
11724
|
{
|
|
11020
|
-
"name": "
|
|
11725
|
+
"name": "snapshotJson",
|
|
11021
11726
|
"type": "text",
|
|
11022
11727
|
"required": false,
|
|
11023
|
-
"columnType": "TEXT"
|
|
11024
|
-
|
|
11025
|
-
|
|
11026
|
-
|
|
11728
|
+
"columnType": "TEXT"
|
|
11729
|
+
}
|
|
11730
|
+
],
|
|
11731
|
+
"relationships": [
|
|
11732
|
+
{
|
|
11733
|
+
"name": "customerId",
|
|
11734
|
+
"type": "foreignKey",
|
|
11735
|
+
"required": false,
|
|
11736
|
+
"related": "Customer",
|
|
11737
|
+
"columnType": "UUID"
|
|
11738
|
+
},
|
|
11739
|
+
{
|
|
11740
|
+
"name": "contractId",
|
|
11741
|
+
"type": "foreignKey",
|
|
11742
|
+
"required": false,
|
|
11743
|
+
"related": "Contract",
|
|
11744
|
+
"columnType": "UUID"
|
|
11745
|
+
},
|
|
11746
|
+
{
|
|
11747
|
+
"name": "paymentId",
|
|
11748
|
+
"type": "foreignKey",
|
|
11749
|
+
"required": false,
|
|
11750
|
+
"related": "Payment",
|
|
11751
|
+
"columnType": "UUID"
|
|
11752
|
+
},
|
|
11753
|
+
{
|
|
11754
|
+
"name": "sourceReceiptId",
|
|
11755
|
+
"type": "foreignKey",
|
|
11756
|
+
"required": false,
|
|
11757
|
+
"related": "HistoricalCustomerFunds",
|
|
11758
|
+
"columnType": "UUID"
|
|
11759
|
+
},
|
|
11760
|
+
{
|
|
11761
|
+
"name": "sourceCreditNoteId",
|
|
11762
|
+
"type": "foreignKey",
|
|
11763
|
+
"required": false,
|
|
11764
|
+
"related": "Invoice",
|
|
11765
|
+
"columnType": "UUID"
|
|
11766
|
+
}
|
|
11767
|
+
],
|
|
11768
|
+
"methods": [
|
|
11769
|
+
"delete",
|
|
11770
|
+
"save"
|
|
11771
|
+
],
|
|
11772
|
+
"methodSignatures": [
|
|
11773
|
+
{
|
|
11774
|
+
"name": "delete",
|
|
11775
|
+
"async": true,
|
|
11776
|
+
"returns": "Promise<void>"
|
|
11777
|
+
},
|
|
11778
|
+
{
|
|
11779
|
+
"name": "save",
|
|
11780
|
+
"async": true,
|
|
11781
|
+
"params": [
|
|
11782
|
+
"options?: SmrtSaveOptions"
|
|
11783
|
+
],
|
|
11784
|
+
"returns": "Promise<this>"
|
|
11785
|
+
}
|
|
11786
|
+
],
|
|
11787
|
+
"tenant": {
|
|
11788
|
+
"scoped": true,
|
|
11789
|
+
"mode": "required",
|
|
11790
|
+
"field": "tenantId"
|
|
11791
|
+
},
|
|
11792
|
+
"conflictColumns": [
|
|
11793
|
+
"tenant_id",
|
|
11794
|
+
"slug",
|
|
11795
|
+
"context"
|
|
11796
|
+
],
|
|
11797
|
+
"surfaces": [
|
|
11798
|
+
{
|
|
11799
|
+
"kind": "api",
|
|
11800
|
+
"name": "historicalcustomerfundses.list",
|
|
11801
|
+
"operation": "list",
|
|
11802
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFunds",
|
|
11803
|
+
"path": "/historicalcustomerfundses",
|
|
11804
|
+
"method": "GET"
|
|
11805
|
+
},
|
|
11806
|
+
{
|
|
11807
|
+
"kind": "api",
|
|
11808
|
+
"name": "historicalcustomerfundses.get",
|
|
11809
|
+
"operation": "get",
|
|
11810
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFunds",
|
|
11811
|
+
"path": "/historicalcustomerfundses/[id]",
|
|
11812
|
+
"method": "GET"
|
|
11813
|
+
},
|
|
11814
|
+
{
|
|
11815
|
+
"kind": "cli",
|
|
11816
|
+
"name": "historicalcustomerfunds_list",
|
|
11817
|
+
"operation": "list",
|
|
11818
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFunds"
|
|
11819
|
+
},
|
|
11820
|
+
{
|
|
11821
|
+
"kind": "cli",
|
|
11822
|
+
"name": "historicalcustomerfunds_get",
|
|
11823
|
+
"operation": "get",
|
|
11824
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFunds"
|
|
11825
|
+
},
|
|
11826
|
+
{
|
|
11827
|
+
"kind": "mcp",
|
|
11828
|
+
"name": "historicalcustomerfunds_list",
|
|
11829
|
+
"operation": "list",
|
|
11830
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFunds"
|
|
11831
|
+
},
|
|
11832
|
+
{
|
|
11833
|
+
"kind": "mcp",
|
|
11834
|
+
"name": "historicalcustomerfunds_get",
|
|
11835
|
+
"operation": "get",
|
|
11836
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFunds"
|
|
11837
|
+
}
|
|
11838
|
+
],
|
|
11839
|
+
"withheldSurfaces": [
|
|
11840
|
+
{
|
|
11841
|
+
"kind": "api",
|
|
11842
|
+
"operation": "save",
|
|
11843
|
+
"code": "lifecycle-method",
|
|
11844
|
+
"reason": "`save` is a framework lifecycle method, not a distinct operation",
|
|
11845
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFunds"
|
|
11846
|
+
}
|
|
11847
|
+
],
|
|
11848
|
+
"relationshipFeatures": [
|
|
11849
|
+
"foreignKey",
|
|
11850
|
+
"uuidColumns"
|
|
11851
|
+
],
|
|
11852
|
+
"tags": [],
|
|
11853
|
+
"risks": []
|
|
11854
|
+
},
|
|
11855
|
+
{
|
|
11856
|
+
"name": "HistoricalCustomerFundsAllocation",
|
|
11857
|
+
"qualifiedName": "@happyvertical/smrt-commerce:HistoricalCustomerFundsAllocation",
|
|
11858
|
+
"collection": "historicalcustomerfundsallocations",
|
|
11859
|
+
"description": "Original applications have concrete identities; credit-audit records never count twice.",
|
|
11860
|
+
"tableName": "historical_customer_funds_allocations",
|
|
11861
|
+
"packageName": "@happyvertical/smrt-commerce",
|
|
11862
|
+
"extends": "SmrtObject",
|
|
11863
|
+
"fields": [
|
|
11864
|
+
{
|
|
11865
|
+
"name": "tenantId",
|
|
11866
|
+
"type": "text",
|
|
11867
|
+
"required": true,
|
|
11868
|
+
"columnType": "UUID"
|
|
11869
|
+
},
|
|
11870
|
+
{
|
|
11871
|
+
"name": "receiptId",
|
|
11872
|
+
"type": "foreignKey",
|
|
11873
|
+
"required": false,
|
|
11874
|
+
"related": "HistoricalCustomerFunds",
|
|
11875
|
+
"columnType": "UUID"
|
|
11876
|
+
},
|
|
11877
|
+
{
|
|
11878
|
+
"name": "creditNoteId",
|
|
11879
|
+
"type": "foreignKey",
|
|
11880
|
+
"required": false,
|
|
11881
|
+
"related": "Invoice",
|
|
11882
|
+
"columnType": "UUID"
|
|
11883
|
+
},
|
|
11884
|
+
{
|
|
11885
|
+
"name": "invoiceId",
|
|
11886
|
+
"type": "foreignKey",
|
|
11887
|
+
"required": false,
|
|
11888
|
+
"related": "Invoice",
|
|
11889
|
+
"columnType": "UUID"
|
|
11890
|
+
},
|
|
11891
|
+
{
|
|
11892
|
+
"name": "sourceKeyHash",
|
|
11893
|
+
"type": "text",
|
|
11894
|
+
"required": false,
|
|
11895
|
+
"columnType": "TEXT"
|
|
11896
|
+
},
|
|
11897
|
+
{
|
|
11898
|
+
"name": "amountMinor",
|
|
11899
|
+
"type": "integer",
|
|
11900
|
+
"required": true,
|
|
11901
|
+
"columnType": "INTEGER",
|
|
11902
|
+
"default": 0
|
|
11903
|
+
},
|
|
11904
|
+
{
|
|
11905
|
+
"name": "effectiveOn",
|
|
11906
|
+
"type": "text",
|
|
11907
|
+
"required": false,
|
|
11908
|
+
"columnType": "TEXT"
|
|
11909
|
+
},
|
|
11910
|
+
{
|
|
11911
|
+
"name": "origin",
|
|
11912
|
+
"type": "text",
|
|
11913
|
+
"required": false,
|
|
11914
|
+
"columnType": "TEXT",
|
|
11915
|
+
"default": "historical"
|
|
11916
|
+
},
|
|
11917
|
+
{
|
|
11918
|
+
"name": "effect",
|
|
11919
|
+
"type": "text",
|
|
11920
|
+
"required": false,
|
|
11921
|
+
"columnType": "TEXT",
|
|
11922
|
+
"default": "payment"
|
|
11923
|
+
},
|
|
11924
|
+
{
|
|
11925
|
+
"name": "journalId",
|
|
11926
|
+
"type": "crossPackageRef",
|
|
11927
|
+
"required": false,
|
|
11928
|
+
"related": "@happyvertical/smrt-ledgers:Journal",
|
|
11929
|
+
"columnType": "UUID"
|
|
11930
|
+
},
|
|
11931
|
+
{
|
|
11932
|
+
"name": "snapshotJson",
|
|
11933
|
+
"type": "text",
|
|
11934
|
+
"required": false,
|
|
11935
|
+
"columnType": "TEXT"
|
|
11936
|
+
}
|
|
11937
|
+
],
|
|
11938
|
+
"relationships": [
|
|
11939
|
+
{
|
|
11940
|
+
"name": "receiptId",
|
|
11941
|
+
"type": "foreignKey",
|
|
11942
|
+
"required": false,
|
|
11943
|
+
"related": "HistoricalCustomerFunds",
|
|
11944
|
+
"columnType": "UUID"
|
|
11945
|
+
},
|
|
11946
|
+
{
|
|
11947
|
+
"name": "creditNoteId",
|
|
11948
|
+
"type": "foreignKey",
|
|
11949
|
+
"required": false,
|
|
11950
|
+
"related": "Invoice",
|
|
11951
|
+
"columnType": "UUID"
|
|
11952
|
+
},
|
|
11953
|
+
{
|
|
11954
|
+
"name": "invoiceId",
|
|
11955
|
+
"type": "foreignKey",
|
|
11956
|
+
"required": false,
|
|
11957
|
+
"related": "Invoice",
|
|
11958
|
+
"columnType": "UUID"
|
|
11959
|
+
},
|
|
11960
|
+
{
|
|
11961
|
+
"name": "journalId",
|
|
11962
|
+
"type": "crossPackageRef",
|
|
11963
|
+
"required": false,
|
|
11964
|
+
"related": "@happyvertical/smrt-ledgers:Journal",
|
|
11965
|
+
"columnType": "UUID"
|
|
11966
|
+
}
|
|
11967
|
+
],
|
|
11968
|
+
"methods": [
|
|
11969
|
+
"delete",
|
|
11970
|
+
"save"
|
|
11971
|
+
],
|
|
11972
|
+
"methodSignatures": [
|
|
11973
|
+
{
|
|
11974
|
+
"name": "delete",
|
|
11975
|
+
"async": true,
|
|
11976
|
+
"returns": "Promise<void>"
|
|
11977
|
+
},
|
|
11978
|
+
{
|
|
11979
|
+
"name": "save",
|
|
11980
|
+
"async": true,
|
|
11981
|
+
"params": [
|
|
11982
|
+
"options?: SmrtSaveOptions"
|
|
11983
|
+
],
|
|
11984
|
+
"returns": "Promise<this>"
|
|
11985
|
+
}
|
|
11986
|
+
],
|
|
11987
|
+
"tenant": {
|
|
11988
|
+
"scoped": true,
|
|
11989
|
+
"mode": "required",
|
|
11990
|
+
"field": "tenantId"
|
|
11991
|
+
},
|
|
11992
|
+
"conflictColumns": [
|
|
11993
|
+
"tenant_id",
|
|
11994
|
+
"slug",
|
|
11995
|
+
"context"
|
|
11996
|
+
],
|
|
11997
|
+
"surfaces": [
|
|
11998
|
+
{
|
|
11999
|
+
"kind": "api",
|
|
12000
|
+
"name": "historicalcustomerfundsallocations.list",
|
|
12001
|
+
"operation": "list",
|
|
12002
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFundsAllocation",
|
|
12003
|
+
"path": "/historicalcustomerfundsallocations",
|
|
12004
|
+
"method": "GET"
|
|
12005
|
+
},
|
|
12006
|
+
{
|
|
12007
|
+
"kind": "api",
|
|
12008
|
+
"name": "historicalcustomerfundsallocations.get",
|
|
12009
|
+
"operation": "get",
|
|
12010
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFundsAllocation",
|
|
12011
|
+
"path": "/historicalcustomerfundsallocations/[id]",
|
|
12012
|
+
"method": "GET"
|
|
12013
|
+
},
|
|
12014
|
+
{
|
|
12015
|
+
"kind": "cli",
|
|
12016
|
+
"name": "historicalcustomerfundsallocation_list",
|
|
12017
|
+
"operation": "list",
|
|
12018
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFundsAllocation"
|
|
12019
|
+
},
|
|
12020
|
+
{
|
|
12021
|
+
"kind": "cli",
|
|
12022
|
+
"name": "historicalcustomerfundsallocation_get",
|
|
12023
|
+
"operation": "get",
|
|
12024
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFundsAllocation"
|
|
12025
|
+
},
|
|
12026
|
+
{
|
|
12027
|
+
"kind": "mcp",
|
|
12028
|
+
"name": "historicalcustomerfundsallocation_list",
|
|
12029
|
+
"operation": "list",
|
|
12030
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFundsAllocation"
|
|
12031
|
+
},
|
|
12032
|
+
{
|
|
12033
|
+
"kind": "mcp",
|
|
12034
|
+
"name": "historicalcustomerfundsallocation_get",
|
|
12035
|
+
"operation": "get",
|
|
12036
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFundsAllocation"
|
|
12037
|
+
}
|
|
12038
|
+
],
|
|
12039
|
+
"withheldSurfaces": [
|
|
12040
|
+
{
|
|
12041
|
+
"kind": "api",
|
|
12042
|
+
"operation": "save",
|
|
12043
|
+
"code": "lifecycle-method",
|
|
12044
|
+
"reason": "`save` is a framework lifecycle method, not a distinct operation",
|
|
12045
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFundsAllocation"
|
|
12046
|
+
}
|
|
12047
|
+
],
|
|
12048
|
+
"relationshipFeatures": [
|
|
12049
|
+
"crossPackageRef",
|
|
12050
|
+
"foreignKey",
|
|
12051
|
+
"uuidColumns"
|
|
12052
|
+
],
|
|
12053
|
+
"tags": [],
|
|
12054
|
+
"risks": []
|
|
12055
|
+
},
|
|
12056
|
+
{
|
|
12057
|
+
"name": "HistoricalSalesLine",
|
|
12058
|
+
"qualifiedName": "@happyvertical/smrt-commerce:HistoricalSalesLine",
|
|
12059
|
+
"collection": "historicalsaleslines",
|
|
12060
|
+
"description": "An immutable source line with explicit unknowns, never a calculated InvoiceLineItem.",
|
|
12061
|
+
"tableName": "historical_sales_lines",
|
|
12062
|
+
"packageName": "@happyvertical/smrt-commerce",
|
|
12063
|
+
"extends": "SmrtObject",
|
|
12064
|
+
"fields": [
|
|
12065
|
+
{
|
|
12066
|
+
"name": "tenantId",
|
|
12067
|
+
"type": "text",
|
|
12068
|
+
"required": true,
|
|
12069
|
+
"columnType": "UUID"
|
|
12070
|
+
},
|
|
12071
|
+
{
|
|
12072
|
+
"name": "invoiceId",
|
|
12073
|
+
"type": "foreignKey",
|
|
12074
|
+
"required": false,
|
|
12075
|
+
"related": "Invoice",
|
|
12076
|
+
"columnType": "UUID"
|
|
12077
|
+
},
|
|
12078
|
+
{
|
|
12079
|
+
"name": "creditedLineId",
|
|
12080
|
+
"type": "foreignKey",
|
|
12081
|
+
"required": false,
|
|
12082
|
+
"related": "HistoricalSalesLine",
|
|
12083
|
+
"columnType": "UUID"
|
|
12084
|
+
},
|
|
12085
|
+
{
|
|
12086
|
+
"name": "sourceKey",
|
|
12087
|
+
"type": "text",
|
|
12088
|
+
"required": false,
|
|
12089
|
+
"columnType": "TEXT"
|
|
12090
|
+
},
|
|
12091
|
+
{
|
|
12092
|
+
"name": "sourceKeyHash",
|
|
12093
|
+
"type": "text",
|
|
12094
|
+
"required": false,
|
|
12095
|
+
"columnType": "TEXT"
|
|
12096
|
+
},
|
|
12097
|
+
{
|
|
12098
|
+
"name": "description",
|
|
12099
|
+
"type": "text",
|
|
12100
|
+
"required": false,
|
|
12101
|
+
"columnType": "TEXT"
|
|
12102
|
+
},
|
|
12103
|
+
{
|
|
12104
|
+
"name": "netMinor",
|
|
12105
|
+
"type": "integer",
|
|
12106
|
+
"required": true,
|
|
12107
|
+
"columnType": "INTEGER",
|
|
12108
|
+
"default": 0
|
|
12109
|
+
},
|
|
12110
|
+
{
|
|
12111
|
+
"name": "taxMinor",
|
|
12112
|
+
"type": "integer",
|
|
12113
|
+
"required": false,
|
|
12114
|
+
"columnType": "INTEGER"
|
|
12115
|
+
},
|
|
12116
|
+
{
|
|
12117
|
+
"name": "grossMinor",
|
|
12118
|
+
"type": "integer",
|
|
12119
|
+
"required": false,
|
|
12120
|
+
"columnType": "INTEGER"
|
|
12121
|
+
},
|
|
12122
|
+
{
|
|
12123
|
+
"name": "quantityText",
|
|
12124
|
+
"type": "text",
|
|
12125
|
+
"required": false,
|
|
12126
|
+
"columnType": "TEXT"
|
|
12127
|
+
},
|
|
12128
|
+
{
|
|
12129
|
+
"name": "unitRateText",
|
|
12130
|
+
"type": "text",
|
|
12131
|
+
"required": false,
|
|
12132
|
+
"columnType": "TEXT"
|
|
12133
|
+
},
|
|
12134
|
+
{
|
|
12135
|
+
"name": "sourceFieldsJson",
|
|
12136
|
+
"type": "text",
|
|
12137
|
+
"required": false,
|
|
12138
|
+
"columnType": "TEXT"
|
|
12139
|
+
},
|
|
12140
|
+
{
|
|
12141
|
+
"name": "moneySnapshotId",
|
|
12142
|
+
"type": "text",
|
|
12143
|
+
"required": false,
|
|
12144
|
+
"columnType": "TEXT"
|
|
12145
|
+
}
|
|
12146
|
+
],
|
|
12147
|
+
"relationships": [
|
|
12148
|
+
{
|
|
12149
|
+
"name": "invoiceId",
|
|
12150
|
+
"type": "foreignKey",
|
|
12151
|
+
"required": false,
|
|
12152
|
+
"related": "Invoice",
|
|
12153
|
+
"columnType": "UUID"
|
|
12154
|
+
},
|
|
12155
|
+
{
|
|
12156
|
+
"name": "creditedLineId",
|
|
12157
|
+
"type": "foreignKey",
|
|
12158
|
+
"required": false,
|
|
12159
|
+
"related": "HistoricalSalesLine",
|
|
12160
|
+
"columnType": "UUID"
|
|
12161
|
+
}
|
|
12162
|
+
],
|
|
12163
|
+
"methods": [
|
|
12164
|
+
"delete",
|
|
12165
|
+
"save"
|
|
12166
|
+
],
|
|
12167
|
+
"methodSignatures": [
|
|
12168
|
+
{
|
|
12169
|
+
"name": "delete",
|
|
12170
|
+
"async": true,
|
|
12171
|
+
"returns": "Promise<void>"
|
|
12172
|
+
},
|
|
12173
|
+
{
|
|
12174
|
+
"name": "save",
|
|
12175
|
+
"async": true,
|
|
12176
|
+
"params": [
|
|
12177
|
+
"options?: SmrtSaveOptions"
|
|
12178
|
+
],
|
|
12179
|
+
"returns": "Promise<this>"
|
|
12180
|
+
}
|
|
12181
|
+
],
|
|
12182
|
+
"tenant": {
|
|
12183
|
+
"scoped": true,
|
|
12184
|
+
"mode": "required",
|
|
12185
|
+
"field": "tenantId"
|
|
12186
|
+
},
|
|
12187
|
+
"conflictColumns": [
|
|
12188
|
+
"tenant_id",
|
|
12189
|
+
"slug",
|
|
12190
|
+
"context"
|
|
12191
|
+
],
|
|
12192
|
+
"surfaces": [
|
|
12193
|
+
{
|
|
12194
|
+
"kind": "api",
|
|
12195
|
+
"name": "historicalsaleslines.list",
|
|
12196
|
+
"operation": "list",
|
|
12197
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalSalesLine",
|
|
12198
|
+
"path": "/historicalsaleslines",
|
|
12199
|
+
"method": "GET"
|
|
12200
|
+
},
|
|
12201
|
+
{
|
|
12202
|
+
"kind": "api",
|
|
12203
|
+
"name": "historicalsaleslines.get",
|
|
12204
|
+
"operation": "get",
|
|
12205
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalSalesLine",
|
|
12206
|
+
"path": "/historicalsaleslines/[id]",
|
|
12207
|
+
"method": "GET"
|
|
12208
|
+
},
|
|
12209
|
+
{
|
|
12210
|
+
"kind": "cli",
|
|
12211
|
+
"name": "historicalsalesline_list",
|
|
12212
|
+
"operation": "list",
|
|
12213
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalSalesLine"
|
|
12214
|
+
},
|
|
12215
|
+
{
|
|
12216
|
+
"kind": "cli",
|
|
12217
|
+
"name": "historicalsalesline_get",
|
|
12218
|
+
"operation": "get",
|
|
12219
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalSalesLine"
|
|
12220
|
+
},
|
|
12221
|
+
{
|
|
12222
|
+
"kind": "mcp",
|
|
12223
|
+
"name": "historicalsalesline_list",
|
|
12224
|
+
"operation": "list",
|
|
12225
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalSalesLine"
|
|
12226
|
+
},
|
|
12227
|
+
{
|
|
12228
|
+
"kind": "mcp",
|
|
12229
|
+
"name": "historicalsalesline_get",
|
|
12230
|
+
"operation": "get",
|
|
12231
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalSalesLine"
|
|
12232
|
+
}
|
|
12233
|
+
],
|
|
12234
|
+
"withheldSurfaces": [
|
|
12235
|
+
{
|
|
12236
|
+
"kind": "api",
|
|
12237
|
+
"operation": "save",
|
|
12238
|
+
"code": "lifecycle-method",
|
|
12239
|
+
"reason": "`save` is a framework lifecycle method, not a distinct operation",
|
|
12240
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalSalesLine"
|
|
12241
|
+
}
|
|
12242
|
+
],
|
|
12243
|
+
"relationshipFeatures": [
|
|
12244
|
+
"foreignKey",
|
|
12245
|
+
"uuidColumns"
|
|
12246
|
+
],
|
|
12247
|
+
"tags": [],
|
|
12248
|
+
"risks": []
|
|
12249
|
+
},
|
|
12250
|
+
{
|
|
12251
|
+
"name": "Invoice",
|
|
12252
|
+
"qualifiedName": "@happyvertical/smrt-commerce:Invoice",
|
|
12253
|
+
"collection": "invoices",
|
|
12254
|
+
"description": "Invoice represents a bill sent to a customer for goods or services.",
|
|
12255
|
+
"tableName": "invoices",
|
|
12256
|
+
"packageName": "@happyvertical/smrt-commerce",
|
|
12257
|
+
"extends": "SmrtObject",
|
|
12258
|
+
"fields": [
|
|
12259
|
+
{
|
|
12260
|
+
"name": "moneyAuthority",
|
|
12261
|
+
"type": "text",
|
|
12262
|
+
"required": false,
|
|
12263
|
+
"columnType": "TEXT",
|
|
12264
|
+
"default": "calculated",
|
|
12265
|
+
"description": "Whether amounts were calculated or retained from an original issued invoice."
|
|
12266
|
+
},
|
|
12267
|
+
{
|
|
12268
|
+
"name": "historicalSalesMoneyJson",
|
|
12269
|
+
"type": "text",
|
|
12270
|
+
"required": false,
|
|
12271
|
+
"columnType": "TEXT"
|
|
12272
|
+
},
|
|
12273
|
+
{
|
|
12274
|
+
"name": "historicalSourceKeyHash",
|
|
12275
|
+
"type": "text",
|
|
12276
|
+
"required": false,
|
|
12277
|
+
"columnType": "TEXT"
|
|
12278
|
+
},
|
|
12279
|
+
{
|
|
12280
|
+
"name": "kind",
|
|
12281
|
+
"type": "text",
|
|
12282
|
+
"required": false,
|
|
12283
|
+
"columnType": "TEXT",
|
|
12284
|
+
"default": "invoice",
|
|
12285
|
+
"description": "Invoice or customer credit note."
|
|
12286
|
+
},
|
|
12287
|
+
{
|
|
12288
|
+
"name": "creditedInvoiceId",
|
|
12289
|
+
"type": "foreignKey",
|
|
12290
|
+
"required": false,
|
|
12291
|
+
"related": "Invoice",
|
|
12292
|
+
"columnType": "UUID"
|
|
12293
|
+
},
|
|
12294
|
+
{
|
|
12295
|
+
"name": "creditedAmount",
|
|
12296
|
+
"type": "integer",
|
|
12297
|
+
"required": true,
|
|
12298
|
+
"columnType": "INTEGER",
|
|
12299
|
+
"default": 0
|
|
12300
|
+
},
|
|
12301
|
+
{
|
|
12302
|
+
"name": "retentionStateJson",
|
|
12303
|
+
"type": "text",
|
|
12304
|
+
"required": false,
|
|
12305
|
+
"columnType": "TEXT"
|
|
12306
|
+
},
|
|
12307
|
+
{
|
|
12308
|
+
"name": "tenantId",
|
|
12309
|
+
"type": "text",
|
|
12310
|
+
"required": false,
|
|
12311
|
+
"columnType": "UUID"
|
|
12312
|
+
},
|
|
12313
|
+
{
|
|
12314
|
+
"name": "customerId",
|
|
12315
|
+
"type": "foreignKey",
|
|
12316
|
+
"required": false,
|
|
12317
|
+
"related": "Customer",
|
|
12318
|
+
"columnType": "UUID",
|
|
12319
|
+
"description": "The customer being billed."
|
|
12320
|
+
},
|
|
12321
|
+
{
|
|
12322
|
+
"name": "contractId",
|
|
12323
|
+
"type": "foreignKey",
|
|
12324
|
+
"required": false,
|
|
12325
|
+
"related": "SalesContract",
|
|
12326
|
+
"columnType": "UUID",
|
|
12327
|
+
"description": "The order or agreement this invoice bills for, if any."
|
|
12328
|
+
},
|
|
12329
|
+
{
|
|
12330
|
+
"name": "invoiceNumber",
|
|
12331
|
+
"type": "text",
|
|
12332
|
+
"required": false,
|
|
12333
|
+
"columnType": "TEXT",
|
|
12334
|
+
"default": "",
|
|
12335
|
+
"description": "The number printed on the invoice."
|
|
12336
|
+
},
|
|
12337
|
+
{
|
|
12338
|
+
"name": "reference",
|
|
12339
|
+
"type": "text",
|
|
12340
|
+
"required": false,
|
|
12341
|
+
"columnType": "TEXT",
|
|
12342
|
+
"default": ""
|
|
12343
|
+
},
|
|
12344
|
+
{
|
|
12345
|
+
"name": "issueDate",
|
|
12346
|
+
"type": "datetime",
|
|
12347
|
+
"required": false,
|
|
12348
|
+
"columnType": "TIMESTAMP",
|
|
12349
|
+
"description": "The date the invoice was issued."
|
|
12350
|
+
},
|
|
12351
|
+
{
|
|
12352
|
+
"name": "dueDate",
|
|
12353
|
+
"type": "datetime",
|
|
12354
|
+
"required": false,
|
|
12355
|
+
"columnType": "TIMESTAMP",
|
|
12356
|
+
"description": "The date payment is expected; null when the original source did not establish it."
|
|
12357
|
+
},
|
|
12358
|
+
{
|
|
12359
|
+
"name": "paidDate",
|
|
12360
|
+
"type": "datetime",
|
|
12361
|
+
"required": false,
|
|
12362
|
+
"columnType": "TIMESTAMP",
|
|
12363
|
+
"description": "The date it was paid in full."
|
|
12364
|
+
},
|
|
12365
|
+
{
|
|
12366
|
+
"name": "subtotal",
|
|
12367
|
+
"type": "integer",
|
|
12368
|
+
"required": false,
|
|
12369
|
+
"columnType": "INTEGER",
|
|
12370
|
+
"default": 0,
|
|
12371
|
+
"description": "The amount before tax."
|
|
12372
|
+
},
|
|
12373
|
+
{
|
|
12374
|
+
"name": "taxAmount",
|
|
12375
|
+
"type": "integer",
|
|
12376
|
+
"required": false,
|
|
12377
|
+
"columnType": "INTEGER",
|
|
12378
|
+
"default": 0,
|
|
12379
|
+
"description": "The tax charged."
|
|
12380
|
+
},
|
|
12381
|
+
{
|
|
12382
|
+
"name": "providerTaxAmount",
|
|
12383
|
+
"type": "integer",
|
|
12384
|
+
"required": false,
|
|
12385
|
+
"columnType": "INTEGER",
|
|
12386
|
+
"default": 0
|
|
12387
|
+
},
|
|
12388
|
+
{
|
|
12389
|
+
"name": "totalAmount",
|
|
12390
|
+
"type": "integer",
|
|
12391
|
+
"required": false,
|
|
12392
|
+
"columnType": "INTEGER",
|
|
12393
|
+
"default": 0,
|
|
12394
|
+
"description": "What the customer owes in all, tax included."
|
|
12395
|
+
},
|
|
12396
|
+
{
|
|
12397
|
+
"name": "amountPaid",
|
|
12398
|
+
"type": "integer",
|
|
12399
|
+
"required": false,
|
|
12400
|
+
"columnType": "INTEGER",
|
|
12401
|
+
"default": 0,
|
|
12402
|
+
"description": "How much of the total has been paid so far."
|
|
12403
|
+
},
|
|
12404
|
+
{
|
|
12405
|
+
"name": "currency",
|
|
12406
|
+
"type": "text",
|
|
12407
|
+
"required": false,
|
|
12408
|
+
"columnType": "TEXT",
|
|
12409
|
+
"default": "CAD",
|
|
12410
|
+
"description": "The currency of the invoice."
|
|
12411
|
+
},
|
|
11027
12412
|
{
|
|
11028
12413
|
"name": "lineAmountType",
|
|
11029
12414
|
"type": "text",
|
|
@@ -11227,6 +12612,7 @@
|
|
|
11227
12612
|
"getAmountDue",
|
|
11228
12613
|
"getArJournal",
|
|
11229
12614
|
"getBalance",
|
|
12615
|
+
"getPayableFacts",
|
|
11230
12616
|
"initialize",
|
|
11231
12617
|
"isDraft",
|
|
11232
12618
|
"isOverdue",
|
|
@@ -11286,6 +12672,10 @@
|
|
|
11286
12672
|
"name": "getBalance",
|
|
11287
12673
|
"returns": "number"
|
|
11288
12674
|
},
|
|
12675
|
+
{
|
|
12676
|
+
"name": "getPayableFacts",
|
|
12677
|
+
"returns": "any"
|
|
12678
|
+
},
|
|
11289
12679
|
{
|
|
11290
12680
|
"name": "initialize",
|
|
11291
12681
|
"async": true,
|
|
@@ -11447,6 +12837,12 @@
|
|
|
11447
12837
|
"operation": "rebindMoneyRead",
|
|
11448
12838
|
"objectName": "@happyvertical/smrt-commerce:Invoice"
|
|
11449
12839
|
},
|
|
12840
|
+
{
|
|
12841
|
+
"kind": "cli",
|
|
12842
|
+
"name": "invoice_getPayableFacts",
|
|
12843
|
+
"operation": "getPayableFacts",
|
|
12844
|
+
"objectName": "@happyvertical/smrt-commerce:Invoice"
|
|
12845
|
+
},
|
|
11450
12846
|
{
|
|
11451
12847
|
"kind": "cli",
|
|
11452
12848
|
"name": "invoice_saveDerived",
|
|
@@ -11611,6 +13007,13 @@
|
|
|
11611
13007
|
"reason": "not listed in api.include",
|
|
11612
13008
|
"objectName": "@happyvertical/smrt-commerce:Invoice"
|
|
11613
13009
|
},
|
|
13010
|
+
{
|
|
13011
|
+
"kind": "api",
|
|
13012
|
+
"operation": "getPayableFacts",
|
|
13013
|
+
"code": "not-included",
|
|
13014
|
+
"reason": "not listed in api.include",
|
|
13015
|
+
"objectName": "@happyvertical/smrt-commerce:Invoice"
|
|
13016
|
+
},
|
|
11614
13017
|
{
|
|
11615
13018
|
"kind": "api",
|
|
11616
13019
|
"operation": "initialize",
|
|
@@ -12221,6 +13624,12 @@
|
|
|
12221
13624
|
"columnType": "TEXT",
|
|
12222
13625
|
"default": "payment"
|
|
12223
13626
|
},
|
|
13627
|
+
{
|
|
13628
|
+
"name": "customerFundsJson",
|
|
13629
|
+
"type": "text",
|
|
13630
|
+
"required": false,
|
|
13631
|
+
"columnType": "TEXT"
|
|
13632
|
+
},
|
|
12224
13633
|
{
|
|
12225
13634
|
"name": "tenantId",
|
|
12226
13635
|
"type": "text",
|
|
@@ -12398,6 +13807,7 @@
|
|
|
12398
13807
|
],
|
|
12399
13808
|
"methods": [
|
|
12400
13809
|
"cancel",
|
|
13810
|
+
"delete",
|
|
12401
13811
|
"getJournal",
|
|
12402
13812
|
"initialize",
|
|
12403
13813
|
"isCompleted",
|
|
@@ -12414,6 +13824,14 @@
|
|
|
12414
13824
|
"name": "cancel",
|
|
12415
13825
|
"returns": "void"
|
|
12416
13826
|
},
|
|
13827
|
+
{
|
|
13828
|
+
"name": "delete",
|
|
13829
|
+
"async": true,
|
|
13830
|
+
"params": [
|
|
13831
|
+
"options?: SmrtDeleteOptions"
|
|
13832
|
+
],
|
|
13833
|
+
"returns": "Promise<void>"
|
|
13834
|
+
},
|
|
12417
13835
|
{
|
|
12418
13836
|
"name": "getJournal",
|
|
12419
13837
|
"async": true,
|
|
@@ -12775,9 +14193,18 @@
|
|
|
12775
14193
|
}
|
|
12776
14194
|
],
|
|
12777
14195
|
"methods": [
|
|
14196
|
+
"delete",
|
|
12778
14197
|
"save"
|
|
12779
14198
|
],
|
|
12780
14199
|
"methodSignatures": [
|
|
14200
|
+
{
|
|
14201
|
+
"name": "delete",
|
|
14202
|
+
"async": true,
|
|
14203
|
+
"params": [
|
|
14204
|
+
"options?: SmrtDeleteOptions"
|
|
14205
|
+
],
|
|
14206
|
+
"returns": "Promise<void>"
|
|
14207
|
+
},
|
|
12781
14208
|
{
|
|
12782
14209
|
"name": "save",
|
|
12783
14210
|
"async": true,
|
|
@@ -14031,6 +15458,112 @@
|
|
|
14031
15458
|
"tags": [],
|
|
14032
15459
|
"risks": []
|
|
14033
15460
|
},
|
|
15461
|
+
{
|
|
15462
|
+
"name": "PurchasePriceObservation",
|
|
15463
|
+
"qualifiedName": "@happyvertical/smrt-commerce:PurchasePriceObservation",
|
|
15464
|
+
"collection": "purchasepriceobservations",
|
|
15465
|
+
"description": "Original purchase evidence with explicitly unavailable monetary aggregates.",
|
|
15466
|
+
"tableName": "purchase_price_observations",
|
|
15467
|
+
"packageName": "@happyvertical/smrt-commerce",
|
|
15468
|
+
"extends": "SmrtObject",
|
|
15469
|
+
"fields": [
|
|
15470
|
+
{
|
|
15471
|
+
"name": "tenantId",
|
|
15472
|
+
"type": "text",
|
|
15473
|
+
"required": true,
|
|
15474
|
+
"columnType": "UUID"
|
|
15475
|
+
},
|
|
15476
|
+
{
|
|
15477
|
+
"name": "sourceIdentity",
|
|
15478
|
+
"type": "text",
|
|
15479
|
+
"required": false,
|
|
15480
|
+
"columnType": "TEXT"
|
|
15481
|
+
},
|
|
15482
|
+
{
|
|
15483
|
+
"name": "vendorId",
|
|
15484
|
+
"type": "text",
|
|
15485
|
+
"required": false,
|
|
15486
|
+
"columnType": "TEXT"
|
|
15487
|
+
},
|
|
15488
|
+
{
|
|
15489
|
+
"name": "snapshotJson",
|
|
15490
|
+
"type": "text",
|
|
15491
|
+
"required": false,
|
|
15492
|
+
"columnType": "TEXT"
|
|
15493
|
+
},
|
|
15494
|
+
{
|
|
15495
|
+
"name": "completionJson",
|
|
15496
|
+
"type": "text",
|
|
15497
|
+
"required": false,
|
|
15498
|
+
"columnType": "TEXT"
|
|
15499
|
+
}
|
|
15500
|
+
],
|
|
15501
|
+
"relationships": [],
|
|
15502
|
+
"methods": [
|
|
15503
|
+
"delete",
|
|
15504
|
+
"save",
|
|
15505
|
+
"saveObserved"
|
|
15506
|
+
],
|
|
15507
|
+
"methodSignatures": [
|
|
15508
|
+
{
|
|
15509
|
+
"name": "delete",
|
|
15510
|
+
"async": true,
|
|
15511
|
+
"returns": "Promise<void>"
|
|
15512
|
+
},
|
|
15513
|
+
{
|
|
15514
|
+
"name": "save",
|
|
15515
|
+
"async": true,
|
|
15516
|
+
"returns": "Promise<this>"
|
|
15517
|
+
},
|
|
15518
|
+
{
|
|
15519
|
+
"name": "saveObserved",
|
|
15520
|
+
"async": true,
|
|
15521
|
+
"params": [
|
|
15522
|
+
"capability: any"
|
|
15523
|
+
],
|
|
15524
|
+
"returns": "Promise<this>"
|
|
15525
|
+
}
|
|
15526
|
+
],
|
|
15527
|
+
"tenant": {
|
|
15528
|
+
"scoped": true,
|
|
15529
|
+
"mode": "required",
|
|
15530
|
+
"field": "tenantId"
|
|
15531
|
+
},
|
|
15532
|
+
"conflictColumns": [
|
|
15533
|
+
"tenant_id",
|
|
15534
|
+
"slug",
|
|
15535
|
+
"context"
|
|
15536
|
+
],
|
|
15537
|
+
"surfaces": [],
|
|
15538
|
+
"withheldSurfaces": [
|
|
15539
|
+
{
|
|
15540
|
+
"kind": "api",
|
|
15541
|
+
"operation": "delete",
|
|
15542
|
+
"code": "api-disabled",
|
|
15543
|
+
"reason": "api is disabled",
|
|
15544
|
+
"objectName": "@happyvertical/smrt-commerce:PurchasePriceObservation"
|
|
15545
|
+
},
|
|
15546
|
+
{
|
|
15547
|
+
"kind": "api",
|
|
15548
|
+
"operation": "save",
|
|
15549
|
+
"code": "api-disabled",
|
|
15550
|
+
"reason": "api is disabled",
|
|
15551
|
+
"objectName": "@happyvertical/smrt-commerce:PurchasePriceObservation"
|
|
15552
|
+
},
|
|
15553
|
+
{
|
|
15554
|
+
"kind": "api",
|
|
15555
|
+
"operation": "saveObserved",
|
|
15556
|
+
"code": "api-disabled",
|
|
15557
|
+
"reason": "api is disabled",
|
|
15558
|
+
"objectName": "@happyvertical/smrt-commerce:PurchasePriceObservation"
|
|
15559
|
+
}
|
|
15560
|
+
],
|
|
15561
|
+
"relationshipFeatures": [
|
|
15562
|
+
"uuidColumns"
|
|
15563
|
+
],
|
|
15564
|
+
"tags": [],
|
|
15565
|
+
"risks": []
|
|
15566
|
+
},
|
|
14034
15567
|
{
|
|
14035
15568
|
"name": "TaxCode",
|
|
14036
15569
|
"qualifiedName": "@happyvertical/smrt-commerce:TaxCode",
|
|
@@ -16797,6 +18330,12 @@
|
|
|
16797
18330
|
"operation": "recalculateTotals",
|
|
16798
18331
|
"objectName": "@happyvertical/smrt-commerce:Contract"
|
|
16799
18332
|
},
|
|
18333
|
+
{
|
|
18334
|
+
"kind": "cli",
|
|
18335
|
+
"name": "contract_deleteDerived",
|
|
18336
|
+
"operation": "deleteDerived",
|
|
18337
|
+
"objectName": "@happyvertical/smrt-commerce:Contract"
|
|
18338
|
+
},
|
|
16800
18339
|
{
|
|
16801
18340
|
"kind": "cli",
|
|
16802
18341
|
"name": "contract_saveDerived",
|
|
@@ -16999,6 +18538,12 @@
|
|
|
16999
18538
|
"operation": "recalculateTotals",
|
|
17000
18539
|
"objectName": "@happyvertical/smrt-commerce:Estimate"
|
|
17001
18540
|
},
|
|
18541
|
+
{
|
|
18542
|
+
"kind": "cli",
|
|
18543
|
+
"name": "estimate_deleteDerived",
|
|
18544
|
+
"operation": "deleteDerived",
|
|
18545
|
+
"objectName": "@happyvertical/smrt-commerce:Estimate"
|
|
18546
|
+
},
|
|
17002
18547
|
{
|
|
17003
18548
|
"kind": "cli",
|
|
17004
18549
|
"name": "estimate_saveDerived",
|
|
@@ -17121,6 +18666,12 @@
|
|
|
17121
18666
|
"operation": "recalculateTotals",
|
|
17122
18667
|
"objectName": "@happyvertical/smrt-commerce:Order"
|
|
17123
18668
|
},
|
|
18669
|
+
{
|
|
18670
|
+
"kind": "cli",
|
|
18671
|
+
"name": "order_deleteDerived",
|
|
18672
|
+
"operation": "deleteDerived",
|
|
18673
|
+
"objectName": "@happyvertical/smrt-commerce:Order"
|
|
18674
|
+
},
|
|
17124
18675
|
{
|
|
17125
18676
|
"kind": "cli",
|
|
17126
18677
|
"name": "order_saveDerived",
|
|
@@ -17243,6 +18794,12 @@
|
|
|
17243
18794
|
"operation": "recalculateTotals",
|
|
17244
18795
|
"objectName": "@happyvertical/smrt-commerce:Lease"
|
|
17245
18796
|
},
|
|
18797
|
+
{
|
|
18798
|
+
"kind": "cli",
|
|
18799
|
+
"name": "lease_deleteDerived",
|
|
18800
|
+
"operation": "deleteDerived",
|
|
18801
|
+
"objectName": "@happyvertical/smrt-commerce:Lease"
|
|
18802
|
+
},
|
|
17246
18803
|
{
|
|
17247
18804
|
"kind": "cli",
|
|
17248
18805
|
"name": "lease_saveDerived",
|
|
@@ -17365,6 +18922,12 @@
|
|
|
17365
18922
|
"operation": "recalculateTotals",
|
|
17366
18923
|
"objectName": "@happyvertical/smrt-commerce:Agreement"
|
|
17367
18924
|
},
|
|
18925
|
+
{
|
|
18926
|
+
"kind": "cli",
|
|
18927
|
+
"name": "agreement_deleteDerived",
|
|
18928
|
+
"operation": "deleteDerived",
|
|
18929
|
+
"objectName": "@happyvertical/smrt-commerce:Agreement"
|
|
18930
|
+
},
|
|
17368
18931
|
{
|
|
17369
18932
|
"kind": "cli",
|
|
17370
18933
|
"name": "agreement_saveDerived",
|
|
@@ -17487,6 +19050,12 @@
|
|
|
17487
19050
|
"operation": "recalculateTotals",
|
|
17488
19051
|
"objectName": "@happyvertical/smrt-commerce:SupplierQuote"
|
|
17489
19052
|
},
|
|
19053
|
+
{
|
|
19054
|
+
"kind": "cli",
|
|
19055
|
+
"name": "supplierquote_deleteDerived",
|
|
19056
|
+
"operation": "deleteDerived",
|
|
19057
|
+
"objectName": "@happyvertical/smrt-commerce:SupplierQuote"
|
|
19058
|
+
},
|
|
17490
19059
|
{
|
|
17491
19060
|
"kind": "cli",
|
|
17492
19061
|
"name": "supplierquote_saveDerived",
|
|
@@ -17609,6 +19178,12 @@
|
|
|
17609
19178
|
"operation": "recalculateTotals",
|
|
17610
19179
|
"objectName": "@happyvertical/smrt-commerce:PurchaseOrder"
|
|
17611
19180
|
},
|
|
19181
|
+
{
|
|
19182
|
+
"kind": "cli",
|
|
19183
|
+
"name": "purchaseorder_deleteDerived",
|
|
19184
|
+
"operation": "deleteDerived",
|
|
19185
|
+
"objectName": "@happyvertical/smrt-commerce:PurchaseOrder"
|
|
19186
|
+
},
|
|
17612
19187
|
{
|
|
17613
19188
|
"kind": "cli",
|
|
17614
19189
|
"name": "purchaseorder_saveDerived",
|
|
@@ -17731,6 +19306,12 @@
|
|
|
17731
19306
|
"operation": "recalculateTotals",
|
|
17732
19307
|
"objectName": "@happyvertical/smrt-commerce:WholesaleOrder"
|
|
17733
19308
|
},
|
|
19309
|
+
{
|
|
19310
|
+
"kind": "cli",
|
|
19311
|
+
"name": "wholesaleorder_deleteDerived",
|
|
19312
|
+
"operation": "deleteDerived",
|
|
19313
|
+
"objectName": "@happyvertical/smrt-commerce:WholesaleOrder"
|
|
19314
|
+
},
|
|
17734
19315
|
{
|
|
17735
19316
|
"kind": "cli",
|
|
17736
19317
|
"name": "wholesaleorder_saveDerived",
|
|
@@ -17853,6 +19434,12 @@
|
|
|
17853
19434
|
"operation": "recalculateTotals",
|
|
17854
19435
|
"objectName": "@happyvertical/smrt-commerce:ProductionOrder"
|
|
17855
19436
|
},
|
|
19437
|
+
{
|
|
19438
|
+
"kind": "cli",
|
|
19439
|
+
"name": "productionorder_deleteDerived",
|
|
19440
|
+
"operation": "deleteDerived",
|
|
19441
|
+
"objectName": "@happyvertical/smrt-commerce:ProductionOrder"
|
|
19442
|
+
},
|
|
17856
19443
|
{
|
|
17857
19444
|
"kind": "cli",
|
|
17858
19445
|
"name": "productionorder_saveDerived",
|
|
@@ -17975,6 +19562,12 @@
|
|
|
17975
19562
|
"operation": "recalculateTotals",
|
|
17976
19563
|
"objectName": "@happyvertical/smrt-commerce:Cart"
|
|
17977
19564
|
},
|
|
19565
|
+
{
|
|
19566
|
+
"kind": "cli",
|
|
19567
|
+
"name": "cart_deleteDerived",
|
|
19568
|
+
"operation": "deleteDerived",
|
|
19569
|
+
"objectName": "@happyvertical/smrt-commerce:Cart"
|
|
19570
|
+
},
|
|
17978
19571
|
{
|
|
17979
19572
|
"kind": "cli",
|
|
17980
19573
|
"name": "cart_saveDerived",
|
|
@@ -18097,6 +19690,12 @@
|
|
|
18097
19690
|
"operation": "recalculateTotals",
|
|
18098
19691
|
"objectName": "@happyvertical/smrt-commerce:LicenseSale"
|
|
18099
19692
|
},
|
|
19693
|
+
{
|
|
19694
|
+
"kind": "cli",
|
|
19695
|
+
"name": "licensesale_deleteDerived",
|
|
19696
|
+
"operation": "deleteDerived",
|
|
19697
|
+
"objectName": "@happyvertical/smrt-commerce:LicenseSale"
|
|
19698
|
+
},
|
|
18100
19699
|
{
|
|
18101
19700
|
"kind": "cli",
|
|
18102
19701
|
"name": "licensesale_saveDerived",
|
|
@@ -18569,6 +20168,126 @@
|
|
|
18569
20168
|
"operation": "get",
|
|
18570
20169
|
"objectName": "@happyvertical/smrt-commerce:FulfillmentLineItem"
|
|
18571
20170
|
},
|
|
20171
|
+
{
|
|
20172
|
+
"kind": "api",
|
|
20173
|
+
"name": "historicalcustomerfundses.list",
|
|
20174
|
+
"operation": "list",
|
|
20175
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFunds",
|
|
20176
|
+
"path": "/historicalcustomerfundses",
|
|
20177
|
+
"method": "GET"
|
|
20178
|
+
},
|
|
20179
|
+
{
|
|
20180
|
+
"kind": "api",
|
|
20181
|
+
"name": "historicalcustomerfundses.get",
|
|
20182
|
+
"operation": "get",
|
|
20183
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFunds",
|
|
20184
|
+
"path": "/historicalcustomerfundses/[id]",
|
|
20185
|
+
"method": "GET"
|
|
20186
|
+
},
|
|
20187
|
+
{
|
|
20188
|
+
"kind": "cli",
|
|
20189
|
+
"name": "historicalcustomerfunds_list",
|
|
20190
|
+
"operation": "list",
|
|
20191
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFunds"
|
|
20192
|
+
},
|
|
20193
|
+
{
|
|
20194
|
+
"kind": "cli",
|
|
20195
|
+
"name": "historicalcustomerfunds_get",
|
|
20196
|
+
"operation": "get",
|
|
20197
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFunds"
|
|
20198
|
+
},
|
|
20199
|
+
{
|
|
20200
|
+
"kind": "mcp",
|
|
20201
|
+
"name": "historicalcustomerfunds_list",
|
|
20202
|
+
"operation": "list",
|
|
20203
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFunds"
|
|
20204
|
+
},
|
|
20205
|
+
{
|
|
20206
|
+
"kind": "mcp",
|
|
20207
|
+
"name": "historicalcustomerfunds_get",
|
|
20208
|
+
"operation": "get",
|
|
20209
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFunds"
|
|
20210
|
+
},
|
|
20211
|
+
{
|
|
20212
|
+
"kind": "api",
|
|
20213
|
+
"name": "historicalcustomerfundsallocations.list",
|
|
20214
|
+
"operation": "list",
|
|
20215
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFundsAllocation",
|
|
20216
|
+
"path": "/historicalcustomerfundsallocations",
|
|
20217
|
+
"method": "GET"
|
|
20218
|
+
},
|
|
20219
|
+
{
|
|
20220
|
+
"kind": "api",
|
|
20221
|
+
"name": "historicalcustomerfundsallocations.get",
|
|
20222
|
+
"operation": "get",
|
|
20223
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFundsAllocation",
|
|
20224
|
+
"path": "/historicalcustomerfundsallocations/[id]",
|
|
20225
|
+
"method": "GET"
|
|
20226
|
+
},
|
|
20227
|
+
{
|
|
20228
|
+
"kind": "cli",
|
|
20229
|
+
"name": "historicalcustomerfundsallocation_list",
|
|
20230
|
+
"operation": "list",
|
|
20231
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFundsAllocation"
|
|
20232
|
+
},
|
|
20233
|
+
{
|
|
20234
|
+
"kind": "cli",
|
|
20235
|
+
"name": "historicalcustomerfundsallocation_get",
|
|
20236
|
+
"operation": "get",
|
|
20237
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFundsAllocation"
|
|
20238
|
+
},
|
|
20239
|
+
{
|
|
20240
|
+
"kind": "mcp",
|
|
20241
|
+
"name": "historicalcustomerfundsallocation_list",
|
|
20242
|
+
"operation": "list",
|
|
20243
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFundsAllocation"
|
|
20244
|
+
},
|
|
20245
|
+
{
|
|
20246
|
+
"kind": "mcp",
|
|
20247
|
+
"name": "historicalcustomerfundsallocation_get",
|
|
20248
|
+
"operation": "get",
|
|
20249
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalCustomerFundsAllocation"
|
|
20250
|
+
},
|
|
20251
|
+
{
|
|
20252
|
+
"kind": "api",
|
|
20253
|
+
"name": "historicalsaleslines.list",
|
|
20254
|
+
"operation": "list",
|
|
20255
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalSalesLine",
|
|
20256
|
+
"path": "/historicalsaleslines",
|
|
20257
|
+
"method": "GET"
|
|
20258
|
+
},
|
|
20259
|
+
{
|
|
20260
|
+
"kind": "api",
|
|
20261
|
+
"name": "historicalsaleslines.get",
|
|
20262
|
+
"operation": "get",
|
|
20263
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalSalesLine",
|
|
20264
|
+
"path": "/historicalsaleslines/[id]",
|
|
20265
|
+
"method": "GET"
|
|
20266
|
+
},
|
|
20267
|
+
{
|
|
20268
|
+
"kind": "cli",
|
|
20269
|
+
"name": "historicalsalesline_list",
|
|
20270
|
+
"operation": "list",
|
|
20271
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalSalesLine"
|
|
20272
|
+
},
|
|
20273
|
+
{
|
|
20274
|
+
"kind": "cli",
|
|
20275
|
+
"name": "historicalsalesline_get",
|
|
20276
|
+
"operation": "get",
|
|
20277
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalSalesLine"
|
|
20278
|
+
},
|
|
20279
|
+
{
|
|
20280
|
+
"kind": "mcp",
|
|
20281
|
+
"name": "historicalsalesline_list",
|
|
20282
|
+
"operation": "list",
|
|
20283
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalSalesLine"
|
|
20284
|
+
},
|
|
20285
|
+
{
|
|
20286
|
+
"kind": "mcp",
|
|
20287
|
+
"name": "historicalsalesline_get",
|
|
20288
|
+
"operation": "get",
|
|
20289
|
+
"objectName": "@happyvertical/smrt-commerce:HistoricalSalesLine"
|
|
20290
|
+
},
|
|
18572
20291
|
{
|
|
18573
20292
|
"kind": "api",
|
|
18574
20293
|
"name": "invoices.list",
|
|
@@ -18637,6 +20356,12 @@
|
|
|
18637
20356
|
"operation": "rebindMoneyRead",
|
|
18638
20357
|
"objectName": "@happyvertical/smrt-commerce:Invoice"
|
|
18639
20358
|
},
|
|
20359
|
+
{
|
|
20360
|
+
"kind": "cli",
|
|
20361
|
+
"name": "invoice_getPayableFacts",
|
|
20362
|
+
"operation": "getPayableFacts",
|
|
20363
|
+
"objectName": "@happyvertical/smrt-commerce:Invoice"
|
|
20364
|
+
},
|
|
18640
20365
|
{
|
|
18641
20366
|
"kind": "cli",
|
|
18642
20367
|
"name": "invoice_saveDerived",
|
|
@@ -19712,14 +21437,14 @@
|
|
|
19712
21437
|
],
|
|
19713
21438
|
"prompts": [],
|
|
19714
21439
|
"relationshipsV2": {
|
|
19715
|
-
"foreignKeyFields":
|
|
19716
|
-
"crossPackageRefFields":
|
|
21440
|
+
"foreignKeyFields": 47,
|
|
21441
|
+
"crossPackageRefFields": 18,
|
|
19717
21442
|
"junctionCollections": 0,
|
|
19718
21443
|
"hierarchicalObjects": 0,
|
|
19719
21444
|
"polymorphicAssociations": 0,
|
|
19720
|
-
"uuidColumns":
|
|
21445
|
+
"uuidColumns": 262
|
|
19721
21446
|
},
|
|
19722
|
-
"agentDoc": "# @happyvertical/smrt-commerce\n\nE-commerce with Contract STI hierarchy, invoice lifecycle, payment tracking, payout remittance, and optional ledger integration.\n\n## Models\n\n- **Customer** / **Vendor**: linked to Profile via string ID (not FK). `contacts` (JSON) is written via [`savePartyContacts()`](agents/customer-vendor-ui.md#contact-rows-3501). Customer has creditLimit, paymentTerms, customerType (DTC / WHOLESALE / RETAIL). Vendor has leadTimeDays, minimumOrder, and `payoutAddresses: Record<string, string>` — a flat map from payout-rail-qualified currency code (`USDC-base`, `BTC`, `USD-stripe`, ...) to destination string (EVM address, BTC address, Stripe Connect account id, IBAN). Use `getPayoutAddress(currency)` for a `Map.get`-style lookup; missing entries return `undefined` (caller decides skip-vs-error).\n- **Contract**: concrete STI base. Abstract **SalesContract** owns `customerId`; **PurchaseContract** owns `vendorId`. `channelId` is open-ended. Before upgrade, run `preflightCommercePartyLinks(db)` and repair linked base rows, stray parties, and wrong-branch links. See [README](README.md).\n- **WholesaleOrder**: B2B order. Conventional pairing — customer has `customerType: 'wholesale'`, NET-30/60 terms, delivered via wholesale-portal channel.\n- **ProductionOrder**: manufacturing equivalent of a PurchaseOrder — commission your factory to make finished goods. Consumes raw materials per BOM (`@happyvertical/smrt-manufacturing`) and produces SKU stock (`@happyvertical/smrt-inventory`).\n- **Cart**: transient order-in-progress. Same shape as Order; the application promotes the row from `_meta_type: Cart` to `_meta_type: Order` at checkout instead of copying data between tables.\n- **LicenseSale**: industry-neutral licensing primitive. Carries an *immutable* rights snapshot (`rightsMedium`, `rightsDistributionScope`, `rightsExclusivity`, `rightsDuration`, `rightsTerritory`, `rightsSublicensing`, `rightsDerivatives` — typed `Meta<T>` fields), licensee identity (`licenseeEmail`, optional `licenseeLegalEntity` / `licenseeJurisdiction`), and a signed-PDF reference (`pdfUrl`, `pdfHash`, optional `onChainHashRegistryRef`). Once saved at `ContractStatus.ACCEPTED`, the rights snapshot is frozen — mutating any of the seven rights fields and re-saving throws. The only legal transition out of ACCEPTED is `revoke()` (moves to CANCELLED without touching rights). Useful for stock media, music licensing, code-asset marketplaces, license keys, anywhere rights are sold for a fee.\n- **ContractLineItem**: items on contracts.\n- **Invoice**: status machine `DRAFT → SENT → VIEWED → PARTIAL → PAID` (also OVERDUE, CANCELLED, WRITTEN_OFF). `recognizeRevenue()` creates balanced AR journal entry (DR: Accounts Receivable, CR: Revenue, CR: Tax Payable).\n- **InvoiceLineItem**: fractional-quantity line items with safe minor-unit validation/recalculation on save; the existing-column migration is documented in [invoice quantity persistence](agents/invoice-quantity.md).\n- **Payment** / **PaymentAllocation**: tracks payments against invoices (status: see Gotchas). Carries optional backend-adapter fields for PaymentBackend-routed flows: `backendId` (rail adapter id — `base-usdc`, `btc`, `stripe`, distinct from `externalProvider` which names an accounting sync destination), `backendTxRef` (chain tx hash or gateway settlement id), `nativeAmount` / `nativeCurrency` (what actually arrived), `usdAtQuote` / `usdAtConfirmation` (drift accounting for volatile-currency rails). `Payment.usdDrift()` returns the confirmation - quote delta, or `0` when either side is unset.\n- **PaymentInstrument**: reusable saved payment method (\"card on file\"). Stores only provider references and non-sensitive display metadata (`providerCustomerId`, `providerPaymentMethodId`, brand / last4 / expiry), never raw card data. `isDefault` is domain-managed, not API-writable: `PaymentInstrumentCollection.setDefaultForCustomer(customerId, instrumentId)` validates the target and clears the customer's other defaults (one per customer).\n- **PaymentIntent**: short-lived pre-payment commitment with multi-option semantics. Locks a USD price for a fixed window (default 15 minutes) and lists one or more `PaymentOption`s describing different rails (`backendId`, `currency`, `payTo`, `nativeAmount`, optional `chain` / `memo` / `x402Capable` / `expiresAt`). First option to receive payment wins; the others are implicitly retired. State machine `awaiting_payment → paid → (issued | retired)` plus `expired` and `cancelled`. Mutate via dedicated `markPaid` / `markIssued` / `expire` / `cancel` / `retire` helpers — direct status assignment bypasses the invariant checks. Idempotency: see the natural-key Gotcha.\n- **Payout**: operator-to-supplier remittance. Distinct from Payment because direction, status machine, and chain semantics differ. Status machine `pending → sent → confirmed → failed` (failed is terminal but resettable via `resetFromFailed()` after fixing the underlying problem). References source `paymentId` (plain string) and destination `vendorId` (foreign key). Amount invariant `supplierNet === grossAmount - operatorFee` enforced exactly on save (integer minor units, no tolerance — #2401). `PayoutCollection.createFromPayment()` is the typical entry point; it pulls native amount / currency from the source Payment.\n- **Fulfillment** / **FulfillmentLineItem**: shipment/delivery tracking.\n\n## Recipes (#3590)\n\n`src/recipes.ts` declares four minimal `SmrtRecipe`s, emitted into the built\n`manifest.json` and `smrt-knowledge.json` `recipes`: `commerce.customers`\n(Customer), `commerce.vendors` (Vendor), `commerce.sales` (Order, requires\ncustomers), `commerce.purchases` (PurchaseOrder, requires vendors). Headers\nonly; line items, fulfilment, invoices, and payments are later recipes. Each\nhas user-facing help in `src/<name>.recipe.md` (#3591), and the fields those\nrecipes show carry `@field({ description })` text; keep both in plain\nlanguage for end users and update them when a recipe's fields change. See\n[core recipes](../core/agents/recipes.md).\n\nSee [payment allocation integrity](agents/payment-allocations.md) for atomic splits,\nretry identity, parent corrections and supported dialects.\nSee [tax codes](agents/tax-codes.md) for tenant-owned rate components, default codes,\nand the standard codes every tenant gets.\nSee [document money persistence](agents/document-money.md) for the one money\nmodel: tax-code resolution, atomic aggregate writes, issued snapshots, and\nfrozen fields. Every Invoice and Contract money write needs a tenant. Host\nbootstrap is `ensureCommerceTenant(db, tenantId, { cookbook })`, which returns\n`{ tenantId }`. Money data written by an earlier version is refused with\n`COMMERCE_DATA_NEEDS_UPGRADE` until `smrt db:upgrade-commerce-money` converts\nit; see [money data upgrade](agents/money-upgrade.md).\nSee [Contract money persistence](agents/contract-money.md) for the Contract\naggregate and purchase recoverability.\n\n## Ledger Integration\n\n`@happyvertical/smrt-ledgers` is a regular dependency, loaded lazily via dynamic `import()` (never a static import) so the package graph stays a DAG (#1582). Invoice stores `arJournalId` and `revenueJournalId` as string references. `recognizeRevenue()` creates a balanced AR journal entry; `getArJournal()` returns null when no journal has been recognized yet.\n\n## Billing-period close (#3060)\n\n`src/billing/` closes periods from smrt-subscriptions charges; see the README\nfor usage.\n\n- **Port, not provider.** Period close, events, and credit checkout call only\n the `BillingProvider` port (integer minor units). `stripe.ts` adapts\n `@happyvertical/accounting`, which takes currency *major* units; convert with\n `units.ts` and never hand-roll a Stripe call here. `units.ts` exponents are\n an explicit ISO 4217 table matching the SDK's, never `Intl` display digits\n (CLDR differs for IQD, MGA, … and drifts by ICU release). The SDK's\n `*Minor` fields are already ISO minor units. Capabilities a rail may lack\n (`chargeSavedPaymentMethod`, `createSetupCheckout`, `getCheckout`,\n `setDefaultPaymentMethod`, `markInvoiceUncollectible`) are optional port\n methods: detect them by presence, and keep additions optional (#3139).\n `sendAndReconcile` refuses a provider invoice whose subtotal or total\n disagrees with the local invoice.\n- **Replay safety is identity.** Close, invoice, line, payment, allocation,\n and claim ids are `deterministicId()`s; `BillingLineSource` (conflict key\n `source_type, source_id`) is the only double-billing guard, so never bill a\n source without claiming it, and never widen that key. Each close step is\n persisted before the next; `acquireCloseLease()` serializes workers. A\n close that nets to a credit keeps its claims and ends `carried_forward`;\n its subtotal is a `credit_carry_forward` source for the payer's next billed\n close, which marks the carried close `completed`.\n- **Cycles and flat-plan coverage (#3116).** `cycles.ts` is the schedule\n (pure; `BillingAccount.billingAnchorAt`, null = calendar months). A close\n with no period closes each payer's `lastEndedBillingPeriod()`. Flat-plan\n claims are the exception to \"id from the source\": their `sourceId` is\n `<subscriptionId>:seq:<chainSequence>` and their `periodStart/End` is the\n exact time they bill. `claimFlatWindow()` reads the last number, then the\n coverage (claims ending after the window start), claims one gap as number\n n + 1, and retries on conflict; reading in that order is what makes it\n safe. That numbering, not the period, stops overlaps when schedules or\n payers change — never claim a flat plan outside it, and keep both reads\n bounded (no whole-history scans). Each numbered claim is its own invoice\n line keyed `lineKey|periodStart` (a function of the claim alone, so a\n resumed close rebuilds the same line ids). Proration is\n `prorateMinorUnits()` (half up, BigInt) against the period's full cycle.\n- **System tables.** `BillingAccount`, `BillingPeriodClose`, and\n `BillingLineSource` are not tenant-scoped and have no generated surface.\n Collections stay unexported; models are root exports (#3082). Invoices,\n payments, and journals are written in the seller's tenant; payer-owned\n subscriptions and credit grants in a system context, only after\n verification.\n- **Events** use smrt-jobs' delivery inbox under provider\n `<name>-billing:<sellerTenantId>` and a provider-filtered\n `ForgeProjectionRuntime`, so a runtime never claims another seller's\n events; any other runtime sharing the inbox must pass `providers` too. Only\n events this package acts on are stored: foreign checkouts are `ignored`,\n and only `smrt_*` checkout metadata is kept; it is\n HMAC-signed with the webhook secret at creation (empty values are omitted:\n Stripe drops them), so another integration on the same account cannot forge\n a credit purchase or a card setup; credit is granted only when the\n collected total equals it plus provider tax. Checkout amounts come from the\n re-read session (`getCheckout()`), never the Stripe event, whose amounts are\n in Stripe's unit. Rotating the webhook secret strands in-flight checkouts\n (up to 24 h). `observe()` re-reads provider state, so ordering never depends\n on delivery order; the only provider writes in `observe()` are idempotent\n (making a saved card the default). The standing hook runs inside the event\n transaction and must be idempotent.\n- **Card on file and top-ups (#3139).** A saved card is the payer customer's\n default `PaymentInstrument` (seller tenant, id from the provider method).\n `autoChargeInvoices` bills such payers `charge_automatically`, decided once\n and saved as `Invoice.collectionMethod` before the first push, which every\n retry reuses (never recompute it: a lost push response would record a\n method the provider was not asked for, #3190); activation follows `paid`, never send. An auto top-up attempt\n is a `PENDING` `Payment` (`reference` `auto-top-up:<policyId>`, id from the\n policy and `count()` of its attempts) inserted before the charge, so racing\n evaluations derive one id and one charge; the charge key is derived from\n that id. `applyAutoTopUpOutcome()` must run in a transaction and starts with\n a conditional `UPDATE … WHERE status = 'pending'` row lock, so the hook and\n the `payment` webhook settle once; the grant is keyed by the charge key.\n Never settle an attempt outside that function. Taxed accounts are charged\n with provider tax by default (#3194): the attempt row holds the credit\n (the charge subtotal), the tax is journaled to tax payable at settlement,\n and the attempt's tax decision is recorded in its `notes` so a re-drive\n repeats the same charge request (the provider refuses a key reused with\n different tax). `claimAttempt()` is the only place that decides a\n skip and reports it (`onAutoTopUpSkipped`); `cardOnFile()` and period close\n use `defaultCardInstrument()` — never copy that predicate. A provider write-off moves the local invoice to\n `WRITTEN_OFF` (a later payment, by card or on a rail (#3188), is recorded\n and reinstates the payer; the status stays, so \"paid in full\" for a\n written-off invoice is read from its allocations).\n- **Billing invoices are money-model invoices.** The provider taxes them\n (`providerTaxAmount`, server-managed, not API-writable, added to line tax),\n so every billing line is an explicit `taxMode: 'override'` to the seller's\n `out-of-scope` code. Charges are written before credits so the running\n subtotal never goes negative, and provider tax is written in the save that\n issues the invoice. Revenue posting is idempotent. `ledger.bookCurrency` is\n required (ISO 4217, validated by `BillingRuntime`) and must equal the\n billing currency. `toAccountingInput({ mapping })` emits major units.\n- **Payment rails (#3138).** A runtime has one issuing `provider` and any\n number of `paymentProviders` (unique names, one inbox namespace each; a\n provider with `capabilities.issuesInvoices === false` can never issue).\n `observe()` resolves the provider from the delivery namespace, never the\n payload. Crypto rails implement the port over `@happyvertical/payments`'\n `CryptoCheckoutGateway`; never call BTCPay (or any gateway) from here.\n Settlement is decided by the pure `decideAttempt()` from gateway state and\n `paymentPolicy` — the gateway's `settled` is authoritative and nothing here\n counts confirmations. A `BillingPaymentAttempt` (`(provider, checkout_id)`\n deterministic id) records every state and settles once; grants and payments\n are keyed by checkout id. Invoice payments close the issuer's invoice out of\n band in `observe()` (idempotent) before `project()` records the payment, and\n `settlePaidInvoice` skips (records nothing for) a `paidOutOfBand` invoice\n the rail latched with `outOfBandRequestedAt`; other out-of-band closes are\n recorded as `OTHER` payments. Rails never save cards or charge tax: a taxed\n credit purchase on a rail needs an explicit `automaticTax: false`. Exceptions are flags for operators;\n nothing reverses or refunds automatically.\n- **Known limits**: write-offs post no bad-debt journal (AR stays until paid\n or journaled by an operator); discounts still reach Stripe as negative lines (the SDK's\n line `discount` would change the lines a replayed push reconciles, so it\n needs its own migration); `RetailCharge` has no adjustment ledger. Flat\n plans are monthly, in arrears; plan changes are not prorated (#3119).\n\n## Cross-Package References\n\n- `customerId` → `@foreignKey('Customer')` (hard reference within package)\n- `vendorId` → `@foreignKey('Vendor')` on PurchaseContract only\n- `profileId` → plain string to smrt-profiles\n- `arJournalId`, `revenueJournalId` → plain string to smrt-ledgers\n- `skuId` (on `PaymentIntent`, `LicenseSale`) → plain string to smrt-products\n- `paymentId` (on `PaymentIntent`, `Payout`, `LicenseSale`) → plain string to `Payment` (same package, but kept as plain string for cross-model consistency)\n- `vendorId` on `Payout` → `@foreignKey(Vendor)` (hard reference within package)\n- Billing records reference tenants with `@crossPackageRef('@happyvertical/smrt-users:Tenant')` and charges, plan periods, and adjustments by plain `sourceId`\n\n## Gotchas\n\n- **Optional tenancy**: all models `@TenantScoped({ mode: 'optional' })` + nullable tenantId\n- **Money units and arithmetic**: money fields use signed integer minor units; rates and quantities remain decimal where their contracts require them. Exact rounding, tax-code resolution, safe-integer validation, and journal units are defined in the [commercial money model](agents/money-model.md) and [money calculator](agents/money-calculator.md). Do not reintroduce floating-point tolerances on money paths.\n- **Money documents need a tenant**: models are optionally tenant-scoped, but every Invoice and Contract money write requires one (`MoneyValidationError` `INVALID_MONEY_INPUT`, `Commerce money documents require a tenant`).\n- **Earlier-version money data is refused**: never add a read or conversion path for it. Detection and the one-shot upgrade are in [money data upgrade](agents/money-upgrade.md).\n- **Book currency is required**: `recognizeRevenue()` and `cancelWithRevenueReversal()` take a required `bookCurrency`, which must equal the invoice currency.\n- **Asset-native amounts stay outside line rescales**: `Payment.nativeAmount` and `PaymentIntent.paymentOptions[].nativeAmount` are per-asset values identified by `nativeCurrency`; normalize each asset to its own minor unit before any type conversion, and never apply the commerce ×100 line-money rescale to them.\n- **Invoice controls payment status**: not the Payment model — use `Invoice.updatePaymentStatus()`\n- **Tax comes from tax codes**: the server resolves each line's code and computes line tax and header totals; client totals and a line's stored `taxRate` are never inputs\n- **Profile linking**: separate `ProfileCollection.create()` needed to fetch actual Profile object\n- **PaymentIntent natural key**: `conflictColumns: ['tenant_id', 'offering_ref', 'licensee_email', 'idempotency_key']` — a retried `create` with the same tuple upserts the existing row. Use `PaymentIntentCollection.getOrCreateByIdempotencyKey()` to branch on `{ intent, created }`. Empty natural-key inputs (e.g. blank `idempotencyKey`) disable dedup by design.\n- **Payout state-machine guards**: `markSent` requires a non-empty `backendTxRef`; `markConfirmed` only valid from `SENT`; `markFailed` only valid from `PENDING` / `SENT` (a confirmed payout can't fail — that path is a refund). `resetFromFailed()` is the dedicated escape hatch from `FAILED` back to `PENDING` after an operator fixes the underlying problem; it clears `backendTxRef` so the next attempt picks up a fresh one.\n- **LicenseSale immutability**: rights snapshot freezes on save-with-status-ACCEPTED. The captured snapshot lives in a module-scoped `WeakMap<LicenseSale, string>` so it doesn't interact with the schema or round-trip through `_meta_data`. Drafts (status != ACCEPTED) remain mutable. To \"change\" an issued license: `revoke()` it, then issue a new `LicenseSale` row.\n- **Vendor.payoutAddresses normalization**: the constructor accepts either a `Record<string, string>` or a pre-serialized JSON string. `initialize()` re-normalizes after the framework's option-override pass; `save()` re-normalizes defensively against direct field assignment. Non-string values inside the input map are silently dropped to preserve the typed invariant downstream.\n\n## Commercial UI\n\n`CustomerSelect`/`VendorSelect` are the registered selectors for Customer and\nVendor (`selects` in `src/ui.ts`); models carry `ui.widget` / `ui.format` hints. See\n[customer/vendor UI](agents/customer-vendor-ui.md#selectors-3602).\n\nSee [commercial UI composition](agents/commercial-ui.md) for native form recovery, amount compatibility and backend ownership. Package-owned guides under `agents/` ship with the package.\n\n## Quote and estimate UI\n\n`src/svelte/quote-types.ts` separates unparsed draft strings from explicit\nminor-unit revision DTOs. Native row submitters, caller-owned retry identity and\nextension conventions are documented in [agents/quote-ui.md](agents/quote-ui.md).\n\n## Purchasing UI\n\n`PurchaseOrderEditor` preserves allocation IDs and explicit zeroes, including\nretained reduction rows; the server validates review fingerprints before recording.\nSee [agents/purchasing-ui.md](agents/purchasing-ui.md) for caller responsibilities.\n\n## Exact cost billing\n\nPure signed cost billing and explicit tax rounding are available through the\nindependent `cost-billing` subpath; see [contract](agents/cost-billing.md).\n",
|
|
21447
|
+
"agentDoc": "# @happyvertical/smrt-commerce\n\nE-commerce with Contract STI hierarchy, invoice lifecycle, payment tracking, payout remittance, and optional ledger integration.\n\n## Models\n\n- **Customer** / **Vendor**: linked to Profile via string ID (not FK). `contacts` (JSON) is written via [`savePartyContacts()`](agents/customer-vendor-ui.md#contact-rows-3501). Customer has creditLimit, paymentTerms, customerType (DTC / WHOLESALE / RETAIL). Vendor has leadTimeDays, minimumOrder, and `payoutAddresses: Record<string, string>` — a flat map from payout-rail-qualified currency code (`USDC-base`, `BTC`, `USD-stripe`, ...) to destination string (EVM address, BTC address, Stripe Connect account id, IBAN). Use `getPayoutAddress(currency)` for a `Map.get`-style lookup; missing entries return `undefined` (caller decides skip-vs-error).\n- **Contract**: concrete STI base. Abstract **SalesContract** owns `customerId`; **PurchaseContract** owns `vendorId`. `channelId` is open-ended. Before upgrade, run `preflightCommercePartyLinks(db)` and repair linked base rows, stray parties, and wrong-branch links. See [README](README.md).\n- **WholesaleOrder**: B2B order. Conventional pairing — customer has `customerType: 'wholesale'`, NET-30/60 terms, delivered via wholesale-portal channel.\n- **ProductionOrder**: manufacturing equivalent of a PurchaseOrder — commission your factory to make finished goods. Consumes raw materials per BOM (`@happyvertical/smrt-manufacturing`) and produces SKU stock (`@happyvertical/smrt-inventory`).\n- **Cart**: transient order-in-progress. Same shape as Order; the application promotes the row from `_meta_type: Cart` to `_meta_type: Order` at checkout instead of copying data between tables.\n- **LicenseSale**: industry-neutral licensing primitive. Carries an *immutable* rights snapshot (`rightsMedium`, `rightsDistributionScope`, `rightsExclusivity`, `rightsDuration`, `rightsTerritory`, `rightsSublicensing`, `rightsDerivatives` — typed `Meta<T>` fields), licensee identity (`licenseeEmail`, optional `licenseeLegalEntity` / `licenseeJurisdiction`), and a signed-PDF reference (`pdfUrl`, `pdfHash`, optional `onChainHashRegistryRef`). Once saved at `ContractStatus.ACCEPTED`, the rights snapshot is frozen — mutating any of the seven rights fields and re-saving throws. The only legal transition out of ACCEPTED is `revoke()` (moves to CANCELLED without touching rights). Useful for stock media, music licensing, code-asset marketplaces, license keys, anywhere rights are sold for a fee.\n- **ContractLineItem**: items on contracts.\n- **Invoice**: status machine `DRAFT → SENT → VIEWED → PARTIAL → PAID` (also OVERDUE, CANCELLED, WRITTEN_OFF). `recognizeRevenue()` creates balanced AR journal entry (DR: Accounts Receivable, CR: Revenue, CR: Tax Payable).\n- **InvoiceLineItem**: fractional-quantity line items with safe minor-unit validation/recalculation on save; the existing-column migration is documented in [invoice quantity persistence](agents/invoice-quantity.md).\n- **Payment** / **PaymentAllocation**: tracks payments against invoices (status: see Gotchas). Carries optional backend-adapter fields for PaymentBackend-routed flows: `backendId` (rail adapter id — `base-usdc`, `btc`, `stripe`, distinct from `externalProvider` which names an accounting sync destination), `backendTxRef` (chain tx hash or gateway settlement id), `nativeAmount` / `nativeCurrency` (what actually arrived), `usdAtQuote` / `usdAtConfirmation` (drift accounting for volatile-currency rails). `Payment.usdDrift()` returns the confirmation - quote delta, or `0` when either side is unset.\n- **PaymentInstrument**: reusable saved payment method (\"card on file\"). Stores only provider references and non-sensitive display metadata (`providerCustomerId`, `providerPaymentMethodId`, brand / last4 / expiry), never raw card data. `isDefault` is domain-managed, not API-writable: `PaymentInstrumentCollection.setDefaultForCustomer(customerId, instrumentId)` validates the target and clears the customer's other defaults (one per customer).\n- **PaymentIntent**: short-lived pre-payment commitment with multi-option semantics. Locks a USD price for a fixed window (default 15 minutes) and lists one or more `PaymentOption`s describing different rails (`backendId`, `currency`, `payTo`, `nativeAmount`, optional `chain` / `memo` / `x402Capable` / `expiresAt`). First option to receive payment wins; the others are implicitly retired. State machine `awaiting_payment → paid → (issued | retired)` plus `expired` and `cancelled`. Mutate via dedicated `markPaid` / `markIssued` / `expire` / `cancel` / `retire` helpers — direct status assignment bypasses the invariant checks. Idempotency: see the natural-key Gotcha.\n- **Payout**: operator-to-supplier remittance. Distinct from Payment because direction, status machine, and chain semantics differ. Status machine `pending → sent → confirmed → failed` (failed is terminal but resettable via `resetFromFailed()` after fixing the underlying problem). References source `paymentId` (plain string) and destination `vendorId` (foreign key). Amount invariant `supplierNet === grossAmount - operatorFee` enforced exactly on save (integer minor units, no tolerance — #2401). `PayoutCollection.createFromPayment()` is the typical entry point; it pulls native amount / currency from the source Payment.\n- **Fulfillment** / **FulfillmentLineItem**: shipment/delivery tracking.\n\n## Recipes (#3590)\n\n`src/recipes.ts` declares four minimal `SmrtRecipe`s, emitted into the built\n`manifest.json` and `smrt-knowledge.json` `recipes`: `commerce.customers`\n(Customer), `commerce.vendors` (Vendor), `commerce.sales` (Order, requires\ncustomers), `commerce.purchases` (PurchaseOrder, requires vendors). Headers\nonly; line items, fulfilment, invoices, and payments are later recipes. Each\nhas user-facing help in `src/<name>.recipe.md` (#3591), and the fields those\nrecipes show carry `@field({ description })` text; keep both in plain\nlanguage for end users and update them when a recipe's fields change. See\n[core recipes](../core/agents/recipes.md).\n\nSee [historical issued sales](agents/historical-sales.md) for exact original source\nmoney, immutable source children and combined historical/live customer funds.\nSee [payment allocation integrity](agents/payment-allocations.md) for atomic splits,\nretry identity, parent corrections and supported dialects.\nSee [tax codes](agents/tax-codes.md) for tenant-owned rate components, default codes,\nand the standard codes every tenant gets.\nSee [document money persistence](agents/document-money.md) for the one money\nmodel: tax-code resolution, atomic aggregate writes, issued snapshots, and\nfrozen fields. Every Invoice and Contract money write needs a tenant. Host\nbootstrap is `ensureCommerceTenant(db, tenantId, { cookbook })`, which returns\n`{ tenantId }`. Money data written by an earlier version is refused with\n`COMMERCE_DATA_NEEDS_UPGRADE` until `smrt db:upgrade-commerce-money` converts\nit; see [money data upgrade](agents/money-upgrade.md).\nSee [Contract money persistence](agents/contract-money.md) for the Contract\naggregate and purchase recoverability.\n\n## Ledger Integration\n\n`@happyvertical/smrt-ledgers` is a regular dependency, loaded lazily via dynamic `import()` (never a static import) so the package graph stays a DAG (#1582). Invoice stores `arJournalId` and `revenueJournalId` as string references. `recognizeRevenue()` creates a balanced AR journal entry; `getArJournal()` returns null when no journal has been recognized yet.\n\n## Billing-period close (#3060)\n\n`src/billing/` closes periods from smrt-subscriptions charges; see the README\nfor usage.\n\n- **Port, not provider.** Period close, events, and credit checkout call only\n the `BillingProvider` port (integer minor units). `stripe.ts` adapts\n `@happyvertical/accounting`, which takes currency *major* units; convert with\n `units.ts` and never hand-roll a Stripe call here. `units.ts` exponents are\n an explicit ISO 4217 table matching the SDK's, never `Intl` display digits\n (CLDR differs for IQD, MGA, … and drifts by ICU release). The SDK's\n `*Minor` fields are already ISO minor units. Capabilities a rail may lack\n (`chargeSavedPaymentMethod`, `createSetupCheckout`, `getCheckout`,\n `setDefaultPaymentMethod`, `markInvoiceUncollectible`) are optional port\n methods: detect them by presence, and keep additions optional (#3139).\n `sendAndReconcile` refuses a provider invoice whose subtotal or total\n disagrees with the local invoice.\n- **Replay safety is identity.** Close, invoice, line, payment, allocation,\n and claim ids are `deterministicId()`s; `BillingLineSource` (conflict key\n `source_type, source_id`) is the only double-billing guard, so never bill a\n source without claiming it, and never widen that key. Each close step is\n persisted before the next; `acquireCloseLease()` serializes workers. A\n close that nets to a credit keeps its claims and ends `carried_forward`;\n its subtotal is a `credit_carry_forward` source for the payer's next billed\n close, which marks the carried close `completed`.\n- **Cycles and flat-plan coverage (#3116).** `cycles.ts` is the schedule\n (pure; `BillingAccount.billingAnchorAt`, null = calendar months). A close\n with no period closes each payer's `lastEndedBillingPeriod()`. Flat-plan\n claims are the exception to \"id from the source\": their `sourceId` is\n `<subscriptionId>:seq:<chainSequence>` and their `periodStart/End` is the\n exact time they bill. `claimFlatWindow()` reads the last number, then the\n coverage (claims ending after the window start), claims one gap as number\n n + 1, and retries on conflict; reading in that order is what makes it\n safe. That numbering, not the period, stops overlaps when schedules or\n payers change — never claim a flat plan outside it, and keep both reads\n bounded (no whole-history scans). Each numbered claim is its own invoice\n line keyed `lineKey|periodStart` (a function of the claim alone, so a\n resumed close rebuilds the same line ids). Proration is\n `prorateMinorUnits()` (half up, BigInt) against the period's full cycle.\n- **System tables.** `BillingAccount`, `BillingPeriodClose`, and\n `BillingLineSource` are not tenant-scoped and have no generated surface.\n Collections stay unexported; models are root exports (#3082). Invoices,\n payments, and journals are written in the seller's tenant; payer-owned\n subscriptions and credit grants in a system context, only after\n verification.\n- **Events** use smrt-jobs' delivery inbox under provider\n `<name>-billing:<sellerTenantId>` and a provider-filtered\n `ForgeProjectionRuntime`, so a runtime never claims another seller's\n events; any other runtime sharing the inbox must pass `providers` too. Only\n events this package acts on are stored: foreign checkouts are `ignored`,\n and only `smrt_*` checkout metadata is kept; it is\n HMAC-signed with the webhook secret at creation (empty values are omitted:\n Stripe drops them), so another integration on the same account cannot forge\n a credit purchase or a card setup; credit is granted only when the\n collected total equals it plus provider tax. Checkout amounts come from the\n re-read session (`getCheckout()`), never the Stripe event, whose amounts are\n in Stripe's unit. Rotating the webhook secret strands in-flight checkouts\n (up to 24 h). `observe()` re-reads provider state, so ordering never depends\n on delivery order; the only provider writes in `observe()` are idempotent\n (making a saved card the default). The standing hook runs inside the event\n transaction and must be idempotent.\n- **Card on file and top-ups (#3139).** A saved card is the payer customer's\n default `PaymentInstrument` (seller tenant, id from the provider method).\n `autoChargeInvoices` bills such payers `charge_automatically`, decided once\n and saved as `Invoice.collectionMethod` before the first push, which every\n retry reuses (never recompute it: a lost push response would record a\n method the provider was not asked for, #3190); activation follows `paid`, never send. An auto top-up attempt\n is a `PENDING` `Payment` (`reference` `auto-top-up:<policyId>`, id from the\n policy and `count()` of its attempts) inserted before the charge, so racing\n evaluations derive one id and one charge; the charge key is derived from\n that id. `applyAutoTopUpOutcome()` must run in a transaction and starts with\n a conditional `UPDATE … WHERE status = 'pending'` row lock, so the hook and\n the `payment` webhook settle once; the grant is keyed by the charge key.\n Never settle an attempt outside that function. Taxed accounts are charged\n with provider tax by default (#3194): the attempt row holds the credit\n (the charge subtotal), the tax is journaled to tax payable at settlement,\n and the attempt's tax decision is recorded in its `notes` so a re-drive\n repeats the same charge request (the provider refuses a key reused with\n different tax). `claimAttempt()` is the only place that decides a\n skip and reports it (`onAutoTopUpSkipped`); `cardOnFile()` and period close\n use `defaultCardInstrument()` — never copy that predicate. A provider write-off moves the local invoice to\n `WRITTEN_OFF` (a later payment, by card or on a rail (#3188), is recorded\n and reinstates the payer; the status stays, so \"paid in full\" for a\n written-off invoice is read from its allocations).\n- **Billing invoices are money-model invoices.** The provider taxes them\n (`providerTaxAmount`, server-managed, not API-writable, added to line tax),\n so every billing line is an explicit `taxMode: 'override'` to the seller's\n `out-of-scope` code. Charges are written before credits so the running\n subtotal never goes negative, and provider tax is written in the save that\n issues the invoice. Revenue posting is idempotent. `ledger.bookCurrency` is\n required (ISO 4217, validated by `BillingRuntime`) and must equal the\n billing currency. `toAccountingInput({ mapping })` emits major units.\n- **Payment rails (#3138).** A runtime has one issuing `provider` and any\n number of `paymentProviders` (unique names, one inbox namespace each; a\n provider with `capabilities.issuesInvoices === false` can never issue).\n `observe()` resolves the provider from the delivery namespace, never the\n payload. Crypto rails implement the port over `@happyvertical/payments`'\n `CryptoCheckoutGateway`; never call BTCPay (or any gateway) from here.\n Settlement is decided by the pure `decideAttempt()` from gateway state and\n `paymentPolicy` — the gateway's `settled` is authoritative and nothing here\n counts confirmations. A `BillingPaymentAttempt` (`(provider, checkout_id)`\n deterministic id) records every state and settles once; grants and payments\n are keyed by checkout id. Invoice payments close the issuer's invoice out of\n band in `observe()` (idempotent) before `project()` records the payment, and\n `settlePaidInvoice` skips (records nothing for) a `paidOutOfBand` invoice\n the rail latched with `outOfBandRequestedAt`; other out-of-band closes are\n recorded as `OTHER` payments. Rails never save cards or charge tax: a taxed\n credit purchase on a rail needs an explicit `automaticTax: false`. Exceptions are flags for operators;\n nothing reverses or refunds automatically.\n- **Known limits**: write-offs post no bad-debt journal (AR stays until paid\n or journaled by an operator); discounts still reach Stripe as negative lines (the SDK's\n line `discount` would change the lines a replayed push reconciles, so it\n needs its own migration); `RetailCharge` has no adjustment ledger. Flat\n plans are monthly, in arrears; plan changes are not prorated (#3119).\n\n## Cross-Package References\n\n- `customerId` → `@foreignKey('Customer')` (hard reference within package)\n- `vendorId` → `@foreignKey('Vendor')` on PurchaseContract only\n- `profileId` → plain string to smrt-profiles\n- `arJournalId`, `revenueJournalId` → plain string to smrt-ledgers\n- `skuId` (on `PaymentIntent`, `LicenseSale`) → plain string to smrt-products\n- `paymentId` (on `PaymentIntent`, `Payout`, `LicenseSale`) → plain string to `Payment` (same package, but kept as plain string for cross-model consistency)\n- `vendorId` on `Payout` → `@foreignKey(Vendor)` (hard reference within package)\n- Billing records reference tenants with `@crossPackageRef('@happyvertical/smrt-users:Tenant')` and charges, plan periods, and adjustments by plain `sourceId`\n\n## Gotchas\n\n- **Optional tenancy**: all models `@TenantScoped({ mode: 'optional' })` + nullable tenantId\n- **Money units and arithmetic**: money fields use signed integer minor units; rates and quantities remain decimal where their contracts require them. Exact rounding, tax-code resolution, safe-integer validation, and journal units are defined in the [commercial money model](agents/money-model.md) and [money calculator](agents/money-calculator.md). Do not reintroduce floating-point tolerances on money paths.\n- **Money documents need a tenant**: models are optionally tenant-scoped, but every Invoice and Contract money write requires one (`MoneyValidationError` `INVALID_MONEY_INPUT`, `Commerce money documents require a tenant`).\n- **Earlier-version money data is refused**: never add a read or conversion path for it. Detection and the one-shot upgrade are in [money data upgrade](agents/money-upgrade.md).\n- **Book currency is required**: `recognizeRevenue()` and `cancelWithRevenueReversal()` take a required `bookCurrency`, which must equal the invoice currency.\n- **Asset-native amounts stay outside line rescales**: `Payment.nativeAmount` and `PaymentIntent.paymentOptions[].nativeAmount` are per-asset values identified by `nativeCurrency`; normalize each asset to its own minor unit before any type conversion, and never apply the commerce ×100 line-money rescale to them.\n- **Invoice controls payment status**: not the Payment model — use `Invoice.updatePaymentStatus()`\n- **Tax comes from tax codes**: the server resolves each line's code and computes line tax and header totals; client totals and a line's stored `taxRate` are never inputs\n- **Profile linking**: separate `ProfileCollection.create()` needed to fetch actual Profile object\n- **PaymentIntent natural key**: `conflictColumns: ['tenant_id', 'offering_ref', 'licensee_email', 'idempotency_key']` — a retried `create` with the same tuple upserts the existing row. Use `PaymentIntentCollection.getOrCreateByIdempotencyKey()` to branch on `{ intent, created }`. Empty natural-key inputs (e.g. blank `idempotencyKey`) disable dedup by design.\n- **Payout state-machine guards**: `markSent` requires a non-empty `backendTxRef`; `markConfirmed` only valid from `SENT`; `markFailed` only valid from `PENDING` / `SENT` (a confirmed payout can't fail — that path is a refund). `resetFromFailed()` is the dedicated escape hatch from `FAILED` back to `PENDING` after an operator fixes the underlying problem; it clears `backendTxRef` so the next attempt picks up a fresh one.\n- **LicenseSale immutability**: rights snapshot freezes on save-with-status-ACCEPTED. The captured snapshot lives in a module-scoped `WeakMap<LicenseSale, string>` so it doesn't interact with the schema or round-trip through `_meta_data`. Drafts (status != ACCEPTED) remain mutable. To \"change\" an issued license: `revoke()` it, then issue a new `LicenseSale` row.\n- **Vendor.payoutAddresses normalization**: the constructor accepts either a `Record<string, string>` or a pre-serialized JSON string. `initialize()` re-normalizes after the framework's option-override pass; `save()` re-normalizes defensively against direct field assignment. Non-string values inside the input map are silently dropped to preserve the typed invariant downstream.\n\n## Commercial UI\n\n`CustomerSelect`/`VendorSelect` are the registered selectors for Customer and\nVendor (`selects` in `src/ui.ts`); models carry `ui.widget` / `ui.format` hints. See\n[customer/vendor UI](agents/customer-vendor-ui.md#selectors-3602).\n\nSee [commercial UI composition](agents/commercial-ui.md) for native form recovery, amount compatibility and backend ownership. Package-owned guides under `agents/` ship with the package.\n\n## Quote and estimate UI\n\n`src/svelte/quote-types.ts` separates unparsed draft strings from explicit\nminor-unit revision DTOs. Native row submitters, caller-owned retry identity and\nextension conventions are documented in [agents/quote-ui.md](agents/quote-ui.md).\n\n## Purchasing UI\n\n`PurchaseOrderEditor` preserves allocation IDs and explicit zeroes, including\nretained reduction rows; the server validates review fingerprints before recording.\nSee [agents/purchasing-ui.md](agents/purchasing-ui.md) for caller responsibilities.\n\n## Exact cost billing\n\nPure signed cost billing and explicit tax rounding are available through the\nindependent `cost-billing` subpath; see [contract](agents/cost-billing.md).\n\nSee [contract billing schedules](agents/contract-billing-schedules.md) for exact\napproved milestone capacity, immutable amendments and atomic canonical invoice issue.\n\n## Customer funds (#4079)\n\nSee [customer advances](agents/customer-funds.md) for explicitly configured\nunapplied-AR/deposit-liability receipts, conserved application/refund capacity,\nreal liability reclassification, final-invoice attestation and mutation guards.\nUse the public commands; `Payment.customerFundsJson` is command-owned.\n\nSee [observed purchase prices](agents/observed-purchase-prices.md) for incomplete\noriginal supplier prices, explicit unknown totals and reviewed completion.\nSee [received sales agreement money](agents/received-sales-contract-money.md) for\nexact complete source Order/Agreement evidence without synthetic lines or tax recognition.\n",
|
|
19723
21448
|
"moduleDocs": [
|
|
19724
21449
|
{
|
|
19725
21450
|
"path": "agents/customer-vendor-ui.md",
|
|
@@ -19729,17 +21454,22 @@
|
|
|
19729
21454
|
{
|
|
19730
21455
|
"path": "README.md",
|
|
19731
21456
|
"module": "README",
|
|
19732
|
-
"content": "# @happyvertical/smrt-commerce\n\nCommerce models for the s-m-r-t framework. Covers customers, vendors, contracts (10 STI types), invoices with ledger integration, payments, and fulfillment tracking.\n\n## Installation\n\n```bash\npnpm add @happyvertical/smrt-commerce\n```\n\n## Usage\n\n```typescript\nimport { withTenant } from '@happyvertical/smrt-tenancy';\nimport {\n CustomerCollection,\n ContractCollection,\n InvoiceCollection,\n InvoiceLineItemCollection,\n PaymentCollection,\n PaymentMethod,\n ensureCommerceTenant,\n} from '@happyvertical/smrt-commerce';\n\n// Once per tenant, after the host creates it: tax settings and standard codes.\nawait ensureCommerceTenant(db, tenantId);\n\n// Money documents (invoices, contracts, and their lines) belong to a tenant.\nawait withTenant({ tenantId }, async () => {\n // Create a customer linked to a profile\n const customers = await CustomerCollection.create({ db });\n const customer = await customers.create({\n profileId: 'profile-uuid',\n creditLimit: 1000000, // $10,000.00 — money is integer minor units\n paymentTerms: 'Net 30',\n });\n\n // Create an order (STI contract type)\n const contracts = await ContractCollection.create({ db });\n const order = await contracts.create({\n _meta_type: 'Order',\n customerId: customer.id,\n currency: 'CAD',\n });\n\n // Create an invoice. The server resolves each line's tax code and computes\n // line tax and the header totals; header amounts are never inputs.\n const invoices = await InvoiceCollection.create({ db });\n const invoice = await invoices.create({\n customerId: customer.id,\n contractId: order.id,\n invoiceNumber: await invoices.generateInvoiceNumber(),\n currency: 'CAD',\n });\n const lines = await InvoiceLineItemCollection.create({ db });\n await lines.create({\n invoiceId: invoice.id,\n description: 'Consulting',\n quantity: 10,\n unitPrice: 10000, // $100.00\n });\n\n // Issuing freezes the money snapshot; then recognize revenue (creates a\n // balanced journal in smrt-ledgers from the frozen facts).\n const issued = await invoices.get({ id: invoice.id }, { cache: false });\n issued.markSent();\n await issued.save();\n await issued.recognizeRevenue({\n arAccountId: 'ar-account-id',\n revenueAccountId: 'revenue-account-id',\n taxAccountId: 'tax-account-id',\n bookCurrency: 'CAD', // must equal the invoice currency\n });\n\n // Record a payment with ledger integration\n const payments = await PaymentCollection.create({ db });\n const payment = await payments.create({\n contractId: order.id,\n customerId: customer.id,\n amount: issued.totalAmount,\n method: PaymentMethod.CREDIT_CARD,\n });\n await payment.recordPayment({\n ledgerId: 'ledger-id',\n receivablesAccountId: 'ar-account-id',\n cashAccountId: 'bank-account-id',\n });\n});\n```\n\n## Commercial money calculator\n\nThe public `/money` entry is a pure calculator for line amounts, discounts,\ncomponent tax, document rounding, and totals. It consumes and returns integer\nminor-unit money values; tax and discount percentages are exact text (`'5'`\nmeans 5%). It does not persist or load documents.\n\n```ts\nimport { calculateMoneyDocument } from '@happyvertical/smrt-commerce/money';\n\nconst totals = calculateMoneyDocument({\n currency: 'CAD',\n lineAmountType: 'exclusive',\n roundingScope: 'line',\n lines: [{\n id: 'consulting', quantity: 1, unitPrice: 10000,\n discount: { kind: 'none' },\n taxCode: {\n id: 'gst', kind: 'taxable',\n components: [{ taxComponentId: 'gst', percent: '5', compound: false }],\n },\n }],\n});\n```\n\n`resolveLineTaxCode()` resolves caller-loaded codes without I/O, and the\nSvelte `InvoiceEditor` renders the money controls from its required `money`\nprop. Frozen editor documents render a supplied stored snapshot without\nrecalculation. See the [commerce money calculator guide](../../docs/content/commerce-money.md)\nfor pricing modes, rounding, input and result types, the native-form editor\ncontract, and the boundaries this package does not define.\n\n### Tenant tax catalogue and defaults\n\nThe package root also exports tenant-scoped `TaxComponent`, `TaxCode`, and\n`TaxSettings` models and their collections. Components hold exact percentage\nrates and optional liability accounts; codes combine compatible components; the\none settings row per tenant supplies sales/purchase defaults, amount mode,\nrounding scope, and labelled registration numbers. A referenced component rate\nis immutable: archive it and create a replacement for a rate change.\n\n`ensureTenantTaxCodes(db, tenantId)` idempotently creates the standard\nnon-taxable codes, `exempt`, `zero-rated`, and `out-of-scope`\n(`STANDARD_TAX_CODES`). `applyTaxCodeExamplePack(db, tenantId)` installs illustrative\nregional examples for review, and `applyCommerceCookbookSettings(db, tenantId,\ncookbook)` explicitly materializes a validated cookbook's defaults after schema\nsetup and authentication establish the tenant. See the [commerce money\ncalculator guide](../../docs/content/commerce-money.md#tenant-tax-catalogue) for\nthe supported kinds, seed behavior, and cookbook rate units.\n\n### Persisted Invoice money\n\nCommerce has one money model. Tax codes resolve each line's tax: the line's\noverride, else `exempt` for an exempt customer, else the product's code, the\ncustomer's code, then the tenant default. The server computes line\n`taxAmount` and the header totals and ignores any client total. Every Invoice\nand Contract money write needs a tenant; without one it fails with\n`MoneyValidationError` `INVALID_MONEY_INPUT`.\n`ensureCommerceTenant(db, tenantId, { cookbook })` is the one bootstrap call a\nhost makes after creating a tenant. It seeds the tenant's tax settings, the\nstandard codes, and the cookbook's defaults, and returns `{ tenantId }`.\n\nIssuing an Invoice (leaving `DRAFT`) or assigning `arJournalId` freezes its\nmoney snapshot. Header and line money changes then fail with `FROZEN_DOCUMENT`,\nwhile later lifecycle and payment updates retain the snapshot. Provider tax\nstays separate in `providerTaxAmount` and contributes to the Invoice headers\nwithout creating an application tax code.\n`InvoiceLineItemCollection.getTotalForInvoice()` sums line amounts for\ncompatibility; use persisted `Invoice.totalAmount` for the amount due.\n`recognizeRevenue()` and `cancelWithRevenueReversal()` require a `bookCurrency`\nequal to the invoice currency, and `toAccountingInput({ mapping })` requires\nexplicit QuickBooks realm mapping. The\n[commerce money calculator guide](../../docs/content/commerce-money.md#persisted-invoice-money)\nand [document-money contract](agents/document-money.md) cover persisted Invoice\nsemantics, credits, refunds, and posting. The materialized Invoice tax-report\ndescriptor and tenant-safe drilldown are documented in\n[tax-summary contract](agents/tax-summary.md). Contract money persistence,\nPurchaseContract tax contributors, and the materialized tax-summary host and\ndrilldown are available. Applications opt in by registering\n`createTaxSummaryMaterializedReportHost()` in their server-only report-host\nregistry; the route binds the authenticated tenant and read permission. See the\ntax-summary contract for registration details.\n\n### Upgrading money data from an earlier version\n\nCommerce refuses money data written by an earlier version with\n`COMMERCE_DATA_NEEDS_UPGRADE` instead of reading it. That is a schema that\nstill has the earlier money columns or the `commerce_money_migration_documents` table,\nan invoice or contract without a tenant, or a tenant with invoices or contracts but no tax settings row or with\ndocuments in the earlier format. `smrt db:status`\nreports it, so `smrt app doctor` reports `migration-required`. Run the normal\nschema migration, then upgrade once:\n\n```sh\nsmrt db:upgrade-commerce-money --check # report only\nsmrt db:upgrade-commerce-money # every tenant\n```\n\nEach tenant converts in its own transaction. Stored rates become tax codes,\nissued documents keep every stored total, and drafts are recomputed. The\nearlier columns are dropped once no tenant needs the upgrade. See\n[money data upgrade](agents/money-upgrade.md) and the\n[CLI guide](../cli/agents/commerce-money-upgrade.md).\n\n## API\n\n### Models\n\n#### Supplier quotations\n\n`SupplierQuote` extends `PurchaseContract`, requires `vendorId`, and has\n`ContractType.SUPPLIER_QUOTE`. Create it through `PurchaseContractCollection`\n(or `ContractCollection`) with `_meta_type:\n'@happyvertical/smrt-commerce:SupplierQuote'`. It inherits `expiryDate`,\n`reference`, `notes`, and `terms`; it has no customer relationship. Purchase\nbranch reads include quotes and sales branch reads exclude them.\n\nKeep received quote revisions and shared quote identity in your application.\nAwarding a quote creates a separate `PurchaseOrder`; accepting or saving a\nquote never converts its identity into an order. Quotes use purchase-side\nmoney calculation and frozen snapshots, but never contribute incurred purchase\ntax to reports, regardless of status. Existing Estimate and PurchaseOrder\nreport eligibility is unchanged.\n\n#### Upgrading contract parties (#3898)\n\n`Contract` no longer declares `customerId` or `vendorId`. Narrow a contract to\n`SalesContract` to read `customerId`, or to `PurchaseContract` to read `vendorId`.\nThe existing leaf qualified names and the `contracts` table stay the same; a\n`db:migrate --dry-run` against a v0.55.19 schema reports no DDL changes on\nSQLite or PostgreSQL. Sales leaves no longer accept `vendorId`; purchase leaves\nno longer accept `customerId`. `Order`, `Estimate`, `Agreement`, `Lease`, and\n`WholesaleOrder` require a customer on save. `PurchaseOrder` and `SupplierQuote`\nrequire a vendor.\n`Cart`, `LicenseSale`, and `ProductionOrder` retain optional parties on their side.\n\nBefore upgrading existing data, run the read-only\n`preflightCommercePartyLinks(db)` and inspect its stray party links, missing\nrequired parties, base-typed rows, discriminator mismatches, and invalid\ndocument references. Its `unqualifiedDiscriminatorRows` lists legacy simple\n`_meta_type` values such as `Order` and `PurchaseOrder`; retype them to the\nqualified class name before upgrading, since branch collections cannot read\nthem. The report checks invoice, payment, fulfillment, ad group,\nand expense links when those tables exist. A linked base-typed or wrong-branch\ncontract blocks the next save of its document even when the link is unchanged.\nRegistered custom descendants of either contract branch are accepted in link\nchecks; load those model classes before running the preflight.\nTenant-owned documents linked to global or other-tenant contracts are also\nreported because the save-time lookup is tenant-scoped. Retype the contract to\nthe correct leaf, assign it to the document's tenant, or repair the link before\ndeployment. The deprecated `ContractCollection` party finders now return the\nappropriate branch\nonly, so retype legacy base rows with party links before relying on those\nfinders. Clear stray party columns and fill required parties before deploying\nwriters that save affected rows. Missing required parties remain readable but\nfail their next save. Regenerate cached manifests, planner catalogs, and\ngenerated screens after upgrading.\nThis preflight never edits rows; an operator chooses the data correction.\n\n| Export | Description |\n|--------|------------|\n| `Customer` | Customer record with creditLimit, paymentTerms, tax exemption, addresses, contacts |\n| `Vendor` | Vendor/supplier with leadTimeDays, minimumOrderAmount, currency, contacts |\n| `Contract` | STI base class for all commercial agreements |\n| `SalesContract` | Abstract customer-side Contract branch; owns `customerId` |\n| `PurchaseContract` | Abstract supplier-side Contract branch; owns `vendorId` |\n| `Estimate` | Quote or proposal sent to a customer |\n| `Order` | Customer purchase order |\n| `Lease` | Rental or lease agreement |\n| `Agreement` | Service or maintenance agreement |\n| `SupplierQuote` | Quotation received from a vendor; distinct from an awarded purchase order |\n| `PurchaseOrder` | Order sent to a vendor/supplier |\n| `ContractLineItem` | Line item within a contract |\n| `Invoice` | Billing document with status lifecycle and ledger integration |\n| `InvoiceLineItem` | Individual invoice line item |\n| `Payment` | Payment record with method, status, and optional ledger journal |\n| `PaymentAllocation` | Payment-to-invoice allocation |\n| `Fulfillment` | Shipment/delivery tracking with carrier and address |\n| `FulfillmentLineItem` | Individual fulfillment line item |\n| `BillingAccount` | A payer's account with a seller: customer, provider customer, terms, standing |\n| `BillingPeriodClose` | One payer's invoice for one period and currency; also the billing job target |\n| `BillingLineSource` | The claim that a charge or plan period is billed on exactly one close |\n\n### Collections\n\n`CustomerCollection`, `VendorCollection`, `ContractCollection`, `SalesContractCollection`, `PurchaseContractCollection`, `InvoiceCollection`, `InvoiceLineItemCollection`, `PaymentCollection`, `PaymentAllocationCollection`, `FulfillmentCollection`\n\n`PaymentAllocationCollection.allocatePayment()` splits a payment across invoices\nin one transaction using stable allocation IDs for retries. Direct allocation\nsaves also enforce matching owners, customers and currencies and both balance\ncaps. Read [payment allocation integrity](agents/payment-allocations.md) for\nreplay, parent revision refresh and compatibility requirements.\n\n\n### Enums\n\n| Export | Values |\n|--------|--------|\n| `ContractType` | `estimate`, `order`, `lease`, `agreement`, `supplier_quote`, `purchase_order`, `wholesale_order`, `production_order`, `cart`, `license_sale` |\n| `ContractStatus` | `draft`, `sent`, `accepted`, `declined`, `completed`, `cancelled` |\n| `CustomerStatus` | `active`, `inactive`, `suspended` |\n| `VendorStatus` | `active`, `inactive`, `suspended` |\n| `InvoiceStatus` | `draft`, `sent`, `viewed`, `partial`, `paid`, `overdue`, `cancelled`, `written_off` |\n| `PaymentMethod` | `cash`, `check`, `credit_card`, `bank_transfer`, `crypto`, `other` |\n| `PaymentStatus` | `pending`, `completed`, `failed`, `refunded`, `cancelled` |\n| `FulfillmentStatus` | `pending`, `processing`, `shipped`, `delivered`, `cancelled` |\n| `FulfillmentType` | `shipment`, `delivery`, `pickup`, `digital`, `service` |\n\n### Types and Constants\n\n| Export | Description |\n|--------|------------|\n| `Address` | Shared address interface (street1, street2, city, state, postalCode, country) |\n| `RecognizeRevenueOptions` | Account IDs for invoice revenue recognition |\n| `RecordPaymentOptions` | Ledger and account IDs for payment recording |\n| `InvoiceNumberOptions` | Options for `generateInvoiceNumber()` (prefix, format) |\n| `UNPAID_STATUSES` | Array of invoice statuses considered unpaid (sent, viewed, partial, overdue) |\n| `COMMERCE_MODULE_META` | UI module metadata |\n| `COMMERCE_UI_SLOTS` | UI slot definitions |\n\n### Ledger Integration\n\nInvoice and Payment integrate with `@happyvertical/smrt-ledgers` via dynamic import (optional dependency). Invoice stores `arJournalId` and `revenueJournalId` as plain string references to ledger journals. `recognizeRevenue()` creates a balanced AR entry (DR: Accounts Receivable, CR: Revenue, CR: Tax Payable). `recordPayment()` creates a balanced cash receipt entry (DR: Cash, CR: Accounts Receivable). Both methods return null or throw if the ledgers package is not installed.\n\n`Payment.recordPayment()` claims the payment revision and commits the journal,\nentries, and completed payment in one database transaction. A failed completion\nrolls back the posting and restores the instance's settlement fields for retry.\nThe claimed persisted status is authoritative even if a caller locally resets\nstatus or marks the instance failed without saving. Concurrent or stale instances\nfail instead of posting twice; reload the payment\nand retry only if it is still pending. An already completed payment retains the\n`Payment already recorded` error. A caller's enclosing transaction remains the\nowner: if it rolls back after settlement returns, reload the payment before retry.\nThese guarantees cover new postings, not orphaned journals written by older\nversions. The returned journal uses the caller's database executor.\n\n### Cross-Package References\n\nCustomer and Vendor link to `@happyvertical/smrt-profiles` via plain `profileId` string. Invoice and Payment reference `@happyvertical/smrt-ledgers` journals via plain string IDs (`arJournalId`, `revenueJournalId`, `journalId`). All models use `@TenantScoped({ mode: 'optional' })` with nullable `tenantId`.\n\n## Billing-period close\n\n`BillingRuntime` turns approved `@happyvertical/smrt-subscriptions` charges into\ninvoices for each billing owner, pushes them to a payment provider with\nprovider-calculated tax, posts revenue to the ledger, and applies the\nprovider's webhook events. Every provider call goes through\n`@happyvertical/accounting`; `createStripeBillingProvider()` adapts its Stripe\nprovider to the `BillingProvider` port. Money crossing the port is integer\nminor units.\n\n```ts\nimport { getAccountingProvider } from '@happyvertical/accounting';\nimport { SpendingPolicyEvaluator } from '@happyvertical/smrt-subscriptions';\nimport {\n BillingRuntime,\n createStripeBillingProvider,\n enqueueBillingPeriodClose,\n registerBillingRuntime,\n} from '@happyvertical/smrt-commerce';\n\nconst stripe = await getAccountingProvider({ type: 'stripe', secretKey });\nconst billing = await BillingRuntime.create({\n db,\n sellerTenantId: platformTenantId,\n kind: 'provider', // or 'reseller' to bill a reseller's children\n provider: createStripeBillingProvider({ stripe, webhookSecret }),\n billingRelationships, // smrt-tenancy BillingRelationshipService\n ledger: {\n bookCurrency: 'USD', // ISO 4217; must equal the billing currency\n arAccountId,\n revenueAccountId,\n taxAccountId,\n cashAccountId,\n prepaidCreditAccountId,\n },\n onPayerStanding: async ({ payerTenantId, standing, db }) => {\n // suspend or reinstate the payer; runs in the event transaction\n },\n});\n\n// One account per payer: its customer, tax location, and terms.\nawait billing.upsertAccount({\n payerTenantId,\n name: 'Network Co',\n email: 'billing@example.test',\n billingAddress: { country: 'CA', postalCode: 'T0L 0A0' },\n});\n\n// Optional: bill this payer from its activation date instead of calendar\n// months, prorating flat plans added mid-period (see \"Billing cycles\").\nawait billing.upsertAccount({\n payerTenantId,\n name: 'Network Co',\n billingAnchorAt: activatedAt,\n prorateFlatPlans: true,\n});\n\n// Close each payer's last ended period — safe to run on every schedule tick.\nregisterBillingRuntime('platform', billing);\nawait enqueueBillingPeriodClose({ runtime: 'platform' });\n\n// Webhook route: verify, enqueue, respond 2xx.\nconst intake = await billing.acceptWebhook(\n rawBody,\n request.headers.get('stripe-signature'),\n);\nif (intake.type?.endsWith(':unverified_credit_purchase')) {\n // alert: a paid checkout claimed to buy credit but failed verification\n}\nawait billing.processEvents(); // or enqueueBillingEvents({ runtime: 'platform' })\n\n// Prepaid credit through provider checkout: tax is added on top when the\n// payer's account is taxed; `savePaymentMethod` keeps the card for top-ups.\nconst { url } = await billing.createCreditCheckout({\n spendingPolicyId,\n amount: 5000,\n purchaseId: cartId,\n savePaymentMethod: true,\n successUrl,\n cancelUrl,\n});\n\n// Card on file at signup: a setup checkout that charges nothing. Its\n// completion event makes the card the payer's default and adopts the billing\n// address collected at checkout as the tax location.\nconst setup = await billing.createCardSetupCheckout({\n payerTenantId,\n currency: 'CAD',\n setupId: signupId,\n successUrl,\n cancelUrl,\n});\n\n// Automatic top-ups: charge the saved card when a balance would run out.\n// Accounts are taxed by default (`automaticTax`); a taxed account is charged\n// the credit plus provider-calculated tax (#3194).\nconst evaluator = await SpendingPolicyEvaluator.create({\n db,\n autoTopUp: billing.autoTopUpHook({ amount: () => 2500 }),\n});\n```\n\n- **What is billed.** A `provider` runtime bills `ClientCharge`s (and their\n `BillingAdjustment`s) to the payer each charge names, plus monthly flat plans\n it owns, to each subscriber's billing owner. A `reseller` runtime bills the\n `RetailCharge`s its children owe it plus its own flat plans. Charges approved\n before the period end are billed once, whatever period that is; flat plans\n are billed in arrears for the payer's closed period (trials and\n provider-managed subscriptions are skipped). One invoice per payer and\n currency carries both kinds of lines.\n- **Replay safety.** Close, invoice, and line ids are derived from the payer,\n currency, and period; each charge is claimed by exactly one close; the\n provider invoice uses the close id as its idempotency key; and every step is\n persisted before the next, so a retry resumes where it stopped. A lease stops\n two workers advancing the same close. A close without a period also resumes\n every unfinished close whose period has ended, even one the payer's current\n schedule no longer produces (#3116). A payer whose charges net to a credit\n gets no invoice; the credit is carried to its next invoice.\n- **Billing cycles (#3116).** A payer's periods follow its account's\n `billingAnchorAt`. Unset (the default) they are UTC calendar months. Set,\n they run monthly from the anchor at its UTC time of day; a day the month\n lacks is clamped to its last day, always from the anchor itself (an anchor\n on Jan 31 bills Jan 31 → Feb 28 → Mar 31). Before the anchor the schedule is\n calendar months, and the anchor's own month ends at the anchor (a *stub*).\n `closePeriod()` / `enqueueBillingPeriodClose()` with no period close each\n payer's **last ended period on its own schedule**, so payers on different\n anchors are closed by the same daily tick. An explicit\n `{ periodStart, periodEnd }` closes that period for calendar payers (flat\n plans only when it is a calendar month, as before) and for anchored payers\n whose schedule has exactly that period. `billingPeriodFor(payer, at)` returns\n a payer's current period; `billingPeriodContaining()`,\n `lastEndedBillingPeriod()`, and `prorateMinorUnits()` are exported.\n- **Proration.** A flat plan is priced `price × billed time / cycle length`,\n in integer minor units rounded half up (exact integer arithmetic; the\n cycle is the period's own month, so February prorates over 28 or 29 days).\n With `prorateFlatPlans` off (default) the billed time is the whole period\n whenever the subscription was active in it and out of trial at its start —\n the pre-#3116 behavior. With it on, the billed time is exactly the time the\n subscription was active and out of trial: a subscription starting, leaving\n trial, or canceled mid-period is billed pro rata. Proration happens before\n the account's flat discount. Split into parts, prorated amounts can differ\n from the full price by a minor unit.\n- **First period.** *Anchor at signup* (set `billingAnchorAt` to the\n signup/activation instant): the first period is a full period from signup;\n nothing before it is billed. *Bill from signup to the next anchor* (keep a\n fixed anchor, or calendar months, and set `prorateFlatPlans`): the first\n period is billed pro rata from signup. Items added later are prorated to the\n payer's anchor when `prorateFlatPlans` is on and billed a full period\n otherwise.\n- **Mid-period changes.** Billing is in arrears, so a cancellation needs no\n credit: with proration the canceled period is billed up to `canceledAt`,\n without it in full. A plan change is billed at the plan in effect at close\n for the whole window (no plan-change proration yet, #3119), and a cancellation\n back-dated into an already billed period is not credited — issue an\n adjustment.\n- **No double billing across schedule changes.** Every flat-plan claim records\n the exact time it bills, and a subscription's claims are numbered, so only\n one worker can write the next claim and two can never claim the same time.\n Moving an account from calendar months to an anchor, moving an anchor, or\n moving a subscription to a payer on another schedule bills only time not yet\n billed, prorated. For example, calendar months through February and then an\n anchor on Mar 20 bills the Mar 1 → Mar 20 stub pro rata, then Mar 20 → Apr\n 20. Time around an already billed window is billed as separate lines, each\n with its own service period. Stop workers running a pre-#3116 version\n before relying on this: they claim flat plans outside the numbering.\n- **Service periods.** Each flat-plan invoice line carries its billed window\n as `periodStart`/`periodEnd`, down to the provider port and on to Stripe's\n invoice item `period`.\n- **Upgrading to #3116.** Additive schema only: `_smrt_billing_accounts` gains\n `billing_anchor_at` (nullable) and `prorate_flat_plans` (default false), and\n `_smrt_billing_line_sources` gains `chain_sequence` (default 0) and an index\n on `(line_key, chain_sequence)`; run `smrt db:migrate`.\n Existing accounts stay on calendar months, and claims written before the\n upgrade (`<subscriptionId>:<periodStart>`, number 0) count as billed\n coverage, so nothing is billed again after it.\n- **Tax** comes from the provider (Stripe Tax) using the account customer's\n `defaultBillingAddress`; the invoice records it as `providerTaxAmount` in the\n save that issues it. Billing invoices are ordinary money-model invoices in\n the seller's tenant; period close seeds its standard codes if needed. Every\n billing line is an explicit override to the seller's `out-of-scope` code, so\n the seller's default code never taxes it a second time. Charges are written\n before credits, so the running subtotal never goes negative. Revenue posting\n uses `ledger.bookCurrency` and is idempotent.\n- **Events** are verified, stored in smrt-jobs' durable delivery inbox, and\n applied against current provider state: paid invoices record a payment and\n allocation; failures and overdue notices mark the payer `past_due` and its\n flat-plan subscriptions `past_due`; an invoice written off at the provider\n (`markInvoiceUncollectible(invoiceId)`, or in Stripe) is written off\n locally and marks the payer `uncollectible` (no bad-debt journal is\n posted; AR stays until it is paid or an operator journals it); payment\n reinstates them, including a late payment of the written-off invoice. Dunning is the provider's.\n Subscribe the webhook endpoint to `invoice.*`, `customer.subscription.*`,\n `checkout.session.completed`, `checkout.session.async_payment_succeeded`,\n and `payment_intent.*`.\n- **Prepaid credit** purchases credit a `period: 'balance'` spending policy\n once per checkout session, paid by the policy's tenant or, for a delegated\n balance, the parent that set it. Amounts are ISO 4217 minor units in any\n currency the provider supports. When the payer's account is taxed\n (`automaticTax`, not tax-exempt; override per call), provider tax is\n charged on top and collected at checkout with the buyer's address: the\n credit is the amount bought, the payment is the total collected, and the\n tax is booked to the tax account. For a payer with a provider customer but\n no local tax location, the address collected at checkout becomes its tax\n location. `savePaymentMethod` requires a provider that can re-read the\n checkout and set a default payment method, and is refused otherwise.\n- **Card on file (#3139).** `createCardSetupCheckout()` (or a credit purchase\n with `savePaymentMethod`) saves the payer's card without charging it. On\n completion the card becomes the provider customer's default and the\n payer's default `PaymentInstrument`. When the checkout collected the billing\n address (a taxed payer with no tax location), it becomes the payer's tax\n location. `cardOnFile(payerTenantId)` returns `{ onFile, savedAt? }` from\n the same check automatic charges use (a default card with the account's\n provider customer), for \"card on file\" displays and signup activation;\n the payer or a system context may call it (#3187).\n- **Automatically charged invoices.** With `autoChargeInvoices: true` on the\n runtime, a payer with a default card is invoiced `charge_automatically`:\n the provider charges the card after the invoice is sent, on its own\n schedule, and retries failures. Each pushed invoice records the method in\n `Invoice.collectionMethod` (`charge_automatically` or `send_invoice`; empty\n for invoices pushed before #3190). Do not offer another payment rail on a\n `charge_automatically` invoice the provider is still collecting.\n Upgrading adds the `collection_method` column to `invoices` (run\n `smrt db:migrate`). Activate service on the `current` standing\n from the `paid` event, not on send; a failure marks the payer `past_due`.\n- **Automatic top-ups.** Taxed accounts (the default: `automaticTax` on, not\n tax-exempt) are charged the credit plus provider-calculated tax (#3194):\n the balance is credited the credit, the payment records the credit, and\n the tax is booked to the tax account. `taxedAccounts: 'skip'` does not top\n them up, and `'charge_untaxed'` charges them without tax. A taxed payer\n without a tax location is not charged. A location Stripe rejects fails the\n attempt with `failureCode: 'customer_tax_location_invalid'`\n (`onAutoTopUpFailed`), and it is retried only after `retryAfterMs`. Pass\n `onAutoTopUpSkipped` to learn when a needed top-up will not be charged\n because of the payer's account. Its `reason` is `taxed_account`, `no_card`,\n `no_account`, or `tax_location_invalid`, and more may be added. Use it, for\n example, to ask the payer to top up by hand or to add a billing address; it is not called while a charge is processing, while a\n declined card waits out `retryAfterMs`, or when the top-up is no longer\n needed or `amount` declines it (#3189).\n `billing.autoTopUpHook()` is the `autoTopUp` hook for\n `SpendingPolicyEvaluator`: when a balance would run out it charges the\n payer's saved card off-session (the delegating parent's, for a delegated\n balance) and credits the balance only when the charge succeeds. A charge\n still processing is credited from its `payment_intent.succeeded` event; a\n decline or an authentication requirement credits nothing, closes the\n attempt, and calls the runtime's `onAutoTopUpFailed` (ask the payer to\n re-save their card with a setup checkout). One attempt runs per policy at a\n time, retries of a declined card wait `retryAfterMs` (default one hour),\n and the credit is granted exactly once however the outcome arrives.\n- **Product tax codes (#3194).** `taxCodes: { credit, invoice }` on the\n runtime classifies prepaid credit (checkout purchases and taxed top-ups)\n and billing-period invoice lines for Stripe Tax (`txcd_...`). Without it,\n the Stripe account's default product tax code applies.\n- **Upgrading to #3194.** Requires `@happyvertical/accounting` 0.96 or later.\n No schema change. Taxed accounts are now topped up with tax. To keep the\n previous behaviour, pass `taxedAccounts: 'skip'`.\n- **Upgrading to #3139.** Requires `@happyvertical/accounting` 0.92 or later.\n No schema change. Credit checkouts are now taxed for taxed accounts (pass\n `automaticTax: false` to keep them untaxed), and Stripe customers are\n created idempotently.\n\n### Payment rails: BTC and other crypto (#3138)\n\nA seller runtime can take payments on more than one **rail**. The issuing\n`provider` (Stripe) still issues, taxes, and emails every invoice; extra rails\nin `paymentProviders` let a payer choose, per payment, to pay an invoice or buy\nprepaid credit another way. The crypto rail runs short-lived, fiat-priced\ncheckouts through `@happyvertical/payments`' provider-neutral\n`CryptoCheckoutGateway` — BTCPay Server at launch — so another gateway can\nreplace BTCPay without changing this package or its consumers.\n\n```ts\nimport {\n BillingRuntime,\n createBtcPayBillingProvider,\n createStripeBillingProvider,\n} from '@happyvertical/smrt-commerce';\n\nconst btcpay = createBtcPayBillingProvider({\n baseUrl, apiKey, storeId, // one BTCPay store per seller entity\n webhookSecret, metadataSecret, // from the host's secret store, by name\n speedPolicy: 'LowMediumSpeed', // settle after 2 confirmations (BTCPay offers 0/1/2/6)\n rateSource: 'kraken',\n minimumAmount: { CAD: 500, USD: 500 },\n});\nconst billing = await BillingRuntime.create({\n db, sellerTenantId, kind: 'provider',\n provider: createStripeBillingProvider({ stripe, webhookSecret }),\n paymentProviders: [btcpay],\n paymentPolicy: { latePaymentPolicy: 'review', refundBasis: 'original_native' },\n billingRelationships,\n ledger: { ...ledger, cryptoHoldingsAccountId, fxGainLossAccountId, feesAccountId },\n});\n\n// Prepaid credit or an issued invoice, paid with BTC:\nawait billing.createCreditCheckout({ ...purchase, provider: 'btcpay' });\nawait billing.createInvoicePayment({ invoiceId, provider: 'btcpay', purchaseId, successUrl, cancelUrl });\n\n// Webhook route for the rail (BTCPay signs with its own header):\nawait billing.acceptWebhook(rawBody, '', { provider: 'btcpay', headers: request.headers });\nawait billing.processEvents();\n```\n\n- **Refusals are typed (#3185).** `createInvoicePayment()` and\n `createCreditCheckout()` throw `BillingPaymentRefusedError` for requests the\n payer can correct, with a stable `code`: `not_found`, `not_payable`,\n `payment_in_progress`, `nothing_due`, `invalid_amount`, `below_minimum`\n (under the rail's `minimumAmount`), or `no_account`. Show its message as a\n 4xx; any other error is a server failure, and `TenantIsolationError` still\n means the caller is not the payer. Treat an unknown code like\n `not_payable`.\n- **Settlement is the gateway's.** Credit is granted and invoices are paid\n only when the gateway reports `settled` under its own confirmation policy;\n this package never counts confirmations. BTCPay offers 0, 1, 2 or 6\n confirmations; the default is `LowMediumSpeed` (2 confirmations).\n- **Payment attempts.** Every rail checkout is a `BillingPaymentAttempt`\n recording the locked fiat price, fiat and native amounts received, rate and\n rate source, each payment's txid, rail and fee, a timeline of status changes,\n and what settlement produced. `listPaymentAttempts()` feeds \"payment\n confirming\" displays and operator queues; every filter applies before its\n `limit` and `offset`, so paging through `{ unresolved: true }` lists every\n open exception (flagged, not yet resolved) however old. `refreshPaymentAttempts()` is the polling\n fallback for missed webhooks.\n- **Dunning pauses** for an invoice while a payment for it is confirming\n (0-conf seen); if the payment then expires or is invalidated the payer's\n standing is re-applied.\n- **Invoices paid on a rail** are closed at the issuer with\n `markInvoicePaidOutOfBand` (Stripe `paid_out_of_band`), so Stripe stops\n collecting; Stripe's own `paid` event then records nothing more.\n `createInvoicePayment` refuses when the issuing provider cannot do that.\n A written-off (uncollectible) invoice with an amount due can be paid on a\n rail too, as it can by card at Stripe (#3188): the payment is recorded,\n Stripe's invoice is closed out of band, and the payer returns to `current`;\n the invoice keeps its `WRITTEN_OFF` status (its `amountPaid` shows the\n recovery).\n- **Exceptions never auto-refund.** Underpaid, overpaid, late, manually marked\n (at the gateway), invalidated-after-settlement, and paid-twice attempts are\n flagged for an operator (`resolvePaymentAttempt`). Per-seller\n `paymentPolicy` sets under/overpayment tolerances (basis points), late\n payments (`review` | `accept`), manually marked checkouts, hold vs convert\n (`conversionHandler`), and the refund basis.\n- **Ledger.** Receipts are booked at the locked fiat amount into\n `cryptoHoldingsAccountId` (default `cashAccountId`); money received above\n the price is booked as customer credit (prepaid-credit liability).\n `recordManualRefund()` refunds from that excess first, then from purchased\n credit (or an invoice payment kept as credit because the invoice was paid\n elsewhere) — capped cumulatively, once per reference; an invoice payment\n applied to its invoice is reversed at the issuer, not here.\n `recordCryptoConversion()` posts a conversion with FX gain/loss.\n- **Upgrading.** Additive schema: `_smrt_billing_payment_attempts` (run\n `smrt db:migrate`). A runtime without `paymentProviders` never reads it.\n- **One live payment per invoice.** The issuer's own `paid` event for an\n invoice a rail closed out of band records nothing (the rail records it); an\n out-of-band close made by someone else (wire, cheque) is recorded as an\n `OTHER`-method payment; a real card payment made while a rail payment\n confirms is recorded and the rail money is flagged `invoice_already_paid`.\n An issuer close whose rail payment never settles is flagged\n `out_of_band_without_settlement`: reopen the invoice at the issuer, then\n `resolvePaymentAttempt()` it, after which a later out-of-band close is\n recorded normally.\n- **Entities.** Each legal entity is its own seller runtime with its own\n store, keys, and ledger. Inter-entity resale is ordinary reseller billing\n between two sellers, payable on any rail the selling entity offers.\n\nSee [`AGENTS.md`](./AGENTS.md#billing-period-close-3060) for invariants and\nknown limits.\n\n## Dependencies\n\n- `@happyvertical/smrt-core` -- ORM and code generation\n- `@happyvertical/smrt-tenancy` -- multi-tenant scoping\n- `@happyvertical/smrt-subscriptions` -- charges, plans, and credit balances billed by period close\n- `@happyvertical/smrt-jobs` -- period-close jobs and the provider event inbox\n- `@happyvertical/accounting` -- payment-provider (Stripe) calls\n- `@happyvertical/smrt-types` -- shared type definitions\n- Peer: `@happyvertical/smrt-ledgers`, `@happyvertical/smrt-profiles`, `@happyvertical/smrt-svelte`\n\n## Contributor guide\n\nSee [`AGENTS.md`](./AGENTS.md) for package architecture, invariants, validation,\nand contributor guidance.\n\n## Pricing version UI\n\n`PricingVersionSummary` and `PricingVersionDecision` compose the quote revision\ncontract without adding a pricing ledger. Compare versions using\n`QuoteRevisionComparison`; the application owns every decision and native form\naction. See [pricing version presentation](agents/pricing-versions.md).\n\n## Commercial UI composition\n\nCustomer addresses and vendor/quote currencies use the shared localized code\nselectors while preserving native field names and rejected raw drafts. See\n[commercial UI contracts and backend boundaries](agents/commercial-ui.md) for\nnative forms, recovery, amount units and consumer adoption, plus the focused\n[customer/vendor](agents/customer-vendor-ui.md) and\n[quotation](agents/quote-ui.md) contracts for selector restrictions.\n\n## Customer and vendor contacts\n\n`Customer.contacts` and `Vendor.contacts` hold the people to reach at a party\n(`PartyContact`: `id`, `name`, `label`, `email`, `phone`, `address`) as a JSON\ncolumn; existing databases need `smrt db:migrate` for the new `contacts`\ncolumns. The form's contact rows are written with `savePartyContacts()`:\n\n```typescript\nimport {\n applyPartyContactIntent,\n PartyContactValidationError,\n readPartyContactRows,\n savePartyContacts,\n} from '@happyvertical/smrt-commerce';\n\nconst form = await request.formData();\n// Throws PartyContactPayloadError when the form's contactCount marker is absent\n// (block not rendered, or fieldNames differ), so a save never deletes by accident.\nconst rows = readPartyContactRows(form); // pass the form's fieldNames if overridden\nconst { contacts, handled } = applyPartyContactIntent(rows, String(form.get('intent')));\nif (handled) return { values: { ...values, contacts } }; // add/remove round trip, no save\ntry {\n await savePartyContacts(vendors, vendorId, rows, { expectedTenantId });\n} catch (error) {\n if (error instanceof PartyContactValidationError)\n return fail(400, { values: { ...values, contacts: rows }, errors: { contacts: toMessages(error.errors) } });\n throw error;\n}\n```\n\n`savePartyContacts` also accepts the `FormData` itself (with `fieldNames`) and\nreads it the same way. The rows replace the party's contacts: posted ids are kept, new rows get an\nid, unposted rows are removed, blank rows are dropped. See\n[customer/vendor UI](agents/customer-vendor-ui.md#contact-rows-3501).\n\n## Customer and vendor selectors\n\n`CustomerSelect` and `VendorSelect` from `@happyvertical/smrt-commerce/svelte`\nare searchable, field-sized pickers for a customer or vendor relation field.\nThey are registered in `COMMERCE_UI_SLOTS` with `selects:\n'@happyvertical/smrt-commerce:Customer'` / `':Vendor'`, so generic forms (via\n`findSelectorFor` over the manifest's `uiSelectors`) use them for any\n`@foreignKey` or `@crossPackageRef` field targeting those models.\n\nThey are presentation only. The caller owns the data: `search(query)` returns\nthe existing party DTOs (`CustomerDisplayData` / `VendorDisplayData`, whose\n`profile.name` is the label), and `resolve(id)` returns the record behind the\ncurrent value. Each row shows the profile name with status (and customer type).\nThe committed id, never the name, posts under `name`. Pass `onCreate` to offer a\n\"New customer\" / \"New vendor\" action; it receives the searched text, and a\nreturned record is selected.\n\n```svelte\n<CustomerSelect\n name=\"customerId\"\n bind:value={customerId}\n search={(query) => customers.search(query)}\n resolve={(id) => customers.byId(id)}\n onCreate={(query) => openCustomerDialog(query)}\n/>\n```\n\nThe same models carry `@field({ ui: { widget } })` hints in the manifest:\n`textarea` on `Contract` (and subclass) `terms` and `notes`, `Customer`/`Vendor`\n`notes`, and `Invoice` notes and terms; `currency` (an ISO 4217 code picker) on\n`Contract`, `Vendor`, `Invoice` and `Payment` `currency`; `email`/`phone` on\n`Vendor.defaultContactEmail`/`defaultContactPhone`. See\n[customer and vendor selectors](agents/customer-vendor-ui.md#selectors-3602).\n\n## Invoice preparation UI\n\n`InvoiceEditor` from `@happyvertical/smrt-commerce/svelte` is the invoice form,\nbuilt on the commercial money model, v2, which is the only invoice money model.\nIt requires a `money` prop (`MoneyEditorProps`): a lossless draft with\ndescriptions, fractional quantities, unit prices, percentage or amount\ndiscounts and a tax code per line (inherited or overridden), plus the\nauthorized tax codes. Its previews run the same exact calculator the server\nuses, and the server re-resolves tax codes and recomputes every stored amount.\nAn issued document renders only its frozen stored snapshot.\n`InvoiceAllocationFields` and `InvoiceReview` add caller-owned sources and\napprovals. See [the editor contract](agents/invoice-preparation.md), the\n[line calculation helper](agents/invoice-calculations.md), and the\n[existing-database storage migration](agents/invoice-quantity.md).\n\n## Exact cost billing\n\nThe independent `@happyvertical/smrt-commerce/cost-billing` entry point provides\nexact signed reimbursement/fee calculations, ordered generic markup provenance,\nand explicit line or invoice tax rounding. Its opt-in ordered tax calculator\nsupports subset compounding with caller-selected signed invoice allocation.\nSee [the cost billing contract](agents/cost-billing.md).\nIt does not alter Invoice persistence, editor defaults or settlement behavior.\n\n### Purchase-order header editing\n\nImport `PurchaseOrderHeaderForm` from `@happyvertical/smrt-commerce/svelte` for a\nnative POST of vendor, reference, notes, expected date and ship-to fields. Pass\n`action`, `vendors` and raw `values`; return canonical field `errors` and the same\n`hiddenFields` after server validation. This header-only form leaves purchase\nallocations and totals unchanged. `PurchaseOrder` stores `expectedDate` and\n`shipTo` in existing STI metadata. See [the purchasing contract](agents/purchasing-ui.md#purchase-order-header)\nfor validation, retained values and transport details.\n"
|
|
21457
|
+
"content": "# @happyvertical/smrt-commerce\n\nCommerce models for the s-m-r-t framework. Covers customers, vendors, contracts (10 STI types), invoices with ledger integration, payments, and fulfillment tracking.\n\n## Installation\n\n```bash\npnpm add @happyvertical/smrt-commerce\n```\n\n## Usage\n\n```typescript\nimport { withTenant } from '@happyvertical/smrt-tenancy';\nimport {\n CustomerCollection,\n ContractCollection,\n InvoiceCollection,\n InvoiceLineItemCollection,\n PaymentCollection,\n PaymentMethod,\n ensureCommerceTenant,\n} from '@happyvertical/smrt-commerce';\n\n// Once per tenant, after the host creates it: tax settings and standard codes.\nawait ensureCommerceTenant(db, tenantId);\n\n// Money documents (invoices, contracts, and their lines) belong to a tenant.\nawait withTenant({ tenantId }, async () => {\n // Create a customer linked to a profile\n const customers = await CustomerCollection.create({ db });\n const customer = await customers.create({\n profileId: 'profile-uuid',\n creditLimit: 1000000, // $10,000.00 — money is integer minor units\n paymentTerms: 'Net 30',\n });\n\n // Create an order (STI contract type)\n const contracts = await ContractCollection.create({ db });\n const order = await contracts.create({\n _meta_type: 'Order',\n customerId: customer.id,\n currency: 'CAD',\n });\n\n // Create an invoice. The server resolves each line's tax code and computes\n // line tax and the header totals; header amounts are never inputs.\n const invoices = await InvoiceCollection.create({ db });\n const invoice = await invoices.create({\n customerId: customer.id,\n contractId: order.id,\n invoiceNumber: await invoices.generateInvoiceNumber(),\n currency: 'CAD',\n });\n const lines = await InvoiceLineItemCollection.create({ db });\n await lines.create({\n invoiceId: invoice.id,\n description: 'Consulting',\n quantity: 10,\n unitPrice: 10000, // $100.00\n });\n\n // Issuing freezes the money snapshot; then recognize revenue (creates a\n // balanced journal in smrt-ledgers from the frozen facts).\n const issued = await invoices.get({ id: invoice.id }, { cache: false });\n issued.markSent();\n await issued.save();\n await issued.recognizeRevenue({\n arAccountId: 'ar-account-id',\n revenueAccountId: 'revenue-account-id',\n taxAccountId: 'tax-account-id',\n bookCurrency: 'CAD', // must equal the invoice currency\n });\n\n // Record a payment with ledger integration\n const payments = await PaymentCollection.create({ db });\n const payment = await payments.create({\n contractId: order.id,\n customerId: customer.id,\n amount: issued.totalAmount,\n method: PaymentMethod.CREDIT_CARD,\n });\n await payment.recordPayment({\n ledgerId: 'ledger-id',\n receivablesAccountId: 'ar-account-id',\n cashAccountId: 'bank-account-id',\n });\n});\n```\n\n## Commercial money calculator\n\nThe public `/money` entry is a pure calculator for line amounts, discounts,\ncomponent tax, document rounding, and totals. It consumes and returns integer\nminor-unit money values; tax and discount percentages are exact text (`'5'`\nmeans 5%). It does not persist or load documents.\n\n```ts\nimport { calculateMoneyDocument } from '@happyvertical/smrt-commerce/money';\n\nconst totals = calculateMoneyDocument({\n currency: 'CAD',\n lineAmountType: 'exclusive',\n roundingScope: 'line',\n lines: [{\n id: 'consulting', quantity: 1, unitPrice: 10000,\n discount: { kind: 'none' },\n taxCode: {\n id: 'gst', kind: 'taxable',\n components: [{ taxComponentId: 'gst', percent: '5', compound: false }],\n },\n }],\n});\n```\n\n`resolveLineTaxCode()` resolves caller-loaded codes without I/O, and the\nSvelte `InvoiceEditor` renders the money controls from its required `money`\nprop. Frozen editor documents render a supplied stored snapshot without\nrecalculation. See the [commerce money calculator guide](../../docs/content/commerce-money.md)\nfor pricing modes, rounding, input and result types, the native-form editor\ncontract, and the boundaries this package does not define.\n\n### Tenant tax catalogue and defaults\n\nThe package root also exports tenant-scoped `TaxComponent`, `TaxCode`, and\n`TaxSettings` models and their collections. Components hold exact percentage\nrates and optional liability accounts; codes combine compatible components; the\none settings row per tenant supplies sales/purchase defaults, amount mode,\nrounding scope, and labelled registration numbers. A referenced component rate\nis immutable: archive it and create a replacement for a rate change.\n\n`ensureTenantTaxCodes(db, tenantId)` idempotently creates the standard\nnon-taxable codes, `exempt`, `zero-rated`, and `out-of-scope`\n(`STANDARD_TAX_CODES`). `applyTaxCodeExamplePack(db, tenantId)` installs illustrative\nregional examples for review, and `applyCommerceCookbookSettings(db, tenantId,\ncookbook)` explicitly materializes a validated cookbook's defaults after schema\nsetup and authentication establish the tenant. See the [commerce money\ncalculator guide](../../docs/content/commerce-money.md#tenant-tax-catalogue) for\nthe supported kinds, seed behavior, and cookbook rate units.\n\n### Persisted Invoice money\n\nCommerce has one money model. Tax codes resolve each line's tax: the line's\noverride, else `exempt` for an exempt customer, else the product's code, the\ncustomer's code, then the tenant default. The server computes line\n`taxAmount` and the header totals and ignores any client total. Every Invoice\nand Contract money write needs a tenant; without one it fails with\n`MoneyValidationError` `INVALID_MONEY_INPUT`.\n`ensureCommerceTenant(db, tenantId, { cookbook })` is the one bootstrap call a\nhost makes after creating a tenant. It seeds the tenant's tax settings, the\nstandard codes, and the cookbook's defaults, and returns `{ tenantId }`.\n\nIssuing an Invoice (leaving `DRAFT`) or assigning `arJournalId` freezes its\nmoney snapshot. Header and line money changes then fail with `FROZEN_DOCUMENT`,\nwhile later lifecycle and payment updates retain the snapshot. Provider tax\nstays separate in `providerTaxAmount` and contributes to the Invoice headers\nwithout creating an application tax code.\n`InvoiceLineItemCollection.getTotalForInvoice()` sums line amounts for\ncompatibility; use persisted `Invoice.totalAmount` for the amount due.\n`recognizeRevenue()` and `cancelWithRevenueReversal()` require a `bookCurrency`\nequal to the invoice currency, and `toAccountingInput({ mapping })` requires\nexplicit QuickBooks realm mapping. The\n[commerce money calculator guide](../../docs/content/commerce-money.md#persisted-invoice-money)\nand [document-money contract](agents/document-money.md) cover persisted Invoice\nsemantics, credits, refunds, and posting. The materialized Invoice tax-report\ndescriptor and tenant-safe drilldown are documented in\n[tax-summary contract](agents/tax-summary.md). Contract money persistence,\nPurchaseContract tax contributors, and the materialized tax-summary host and\ndrilldown are available. Applications opt in by registering\n`createTaxSummaryMaterializedReportHost()` in their server-only report-host\nregistry; the route binds the authenticated tenant and read permission. See the\ntax-summary contract for registration details.\n\n### Upgrading money data from an earlier version\n\nCommerce refuses money data written by an earlier version with\n`COMMERCE_DATA_NEEDS_UPGRADE` instead of reading it. That is a schema that\nstill has the earlier money columns or the `commerce_money_migration_documents` table,\nan invoice or contract without a tenant, or a tenant with invoices or contracts but no tax settings row or with\ndocuments in the earlier format. `smrt db:status`\nreports it, so `smrt app doctor` reports `migration-required`. Run the normal\nschema migration, then upgrade once:\n\n```sh\nsmrt db:upgrade-commerce-money --check # report only\nsmrt db:upgrade-commerce-money # every tenant\n```\n\nEach tenant converts in its own transaction. Stored rates become tax codes,\nissued documents keep every stored total, and drafts are recomputed. The\nearlier columns are dropped once no tenant needs the upgrade. See\n[money data upgrade](agents/money-upgrade.md) and the\n[CLI guide](../cli/agents/commerce-money-upgrade.md).\n\n## API\n\n### Models\n\n#### Supplier quotations\n\n`SupplierQuote` extends `PurchaseContract`, requires `vendorId`, and has\n`ContractType.SUPPLIER_QUOTE`. Create it through `PurchaseContractCollection`\n(or `ContractCollection`) with `_meta_type:\n'@happyvertical/smrt-commerce:SupplierQuote'`. It inherits `expiryDate`,\n`reference`, `notes`, and `terms`; it has no customer relationship. Purchase\nbranch reads include quotes and sales branch reads exclude them.\n\nKeep received quote revisions and shared quote identity in your application.\nAwarding a quote creates a separate `PurchaseOrder`; accepting or saving a\nquote never converts its identity into an order. Quotes use purchase-side\nmoney calculation and frozen snapshots, but never contribute incurred purchase\ntax to reports, regardless of status. Existing Estimate and PurchaseOrder\nreport eligibility is unchanged.\n\n#### Upgrading contract parties (#3898)\n\n`Contract` no longer declares `customerId` or `vendorId`. Narrow a contract to\n`SalesContract` to read `customerId`, or to `PurchaseContract` to read `vendorId`.\nThe existing leaf qualified names and the `contracts` table stay the same; a\n`db:migrate --dry-run` against a v0.55.19 schema reports no DDL changes on\nSQLite or PostgreSQL. Sales leaves no longer accept `vendorId`; purchase leaves\nno longer accept `customerId`. `Order`, `Estimate`, `Agreement`, `Lease`, and\n`WholesaleOrder` require a customer on save. `PurchaseOrder` and `SupplierQuote`\nrequire a vendor.\n`Cart`, `LicenseSale`, and `ProductionOrder` retain optional parties on their side.\n\nBefore upgrading existing data, run the read-only\n`preflightCommercePartyLinks(db)` and inspect its stray party links, missing\nrequired parties, base-typed rows, discriminator mismatches, and invalid\ndocument references. Its `unqualifiedDiscriminatorRows` lists legacy simple\n`_meta_type` values such as `Order` and `PurchaseOrder`; retype them to the\nqualified class name before upgrading, since branch collections cannot read\nthem. The report checks invoice, payment, fulfillment, ad group,\nand expense links when those tables exist. A linked base-typed or wrong-branch\ncontract blocks the next save of its document even when the link is unchanged.\nRegistered custom descendants of either contract branch are accepted in link\nchecks; load those model classes before running the preflight.\nTenant-owned documents linked to global or other-tenant contracts are also\nreported because the save-time lookup is tenant-scoped. Retype the contract to\nthe correct leaf, assign it to the document's tenant, or repair the link before\ndeployment. The deprecated `ContractCollection` party finders now return the\nappropriate branch\nonly, so retype legacy base rows with party links before relying on those\nfinders. Clear stray party columns and fill required parties before deploying\nwriters that save affected rows. Missing required parties remain readable but\nfail their next save. Regenerate cached manifests, planner catalogs, and\ngenerated screens after upgrading.\nThis preflight never edits rows; an operator chooses the data correction.\n\n| Export | Description |\n|--------|------------|\n| `Customer` | Customer record with creditLimit, paymentTerms, tax exemption, addresses, contacts |\n| `Vendor` | Vendor/supplier with leadTimeDays, minimumOrderAmount, currency, contacts |\n| `Contract` | STI base class for all commercial agreements |\n| `SalesContract` | Abstract customer-side Contract branch; owns `customerId` |\n| `PurchaseContract` | Abstract supplier-side Contract branch; owns `vendorId` |\n| `Estimate` | Quote or proposal sent to a customer |\n| `Order` | Customer purchase order |\n| `Lease` | Rental or lease agreement |\n| `Agreement` | Service or maintenance agreement |\n| `SupplierQuote` | Quotation received from a vendor; distinct from an awarded purchase order |\n| `PurchaseOrder` | Order sent to a vendor/supplier |\n| `ContractLineItem` | Line item within a contract |\n| `Invoice` | Billing document with status lifecycle and ledger integration |\n| `InvoiceLineItem` | Individual invoice line item |\n| `Payment` | Payment record with method, status, and optional ledger journal |\n| `PaymentAllocation` | Payment-to-invoice allocation |\n| `Fulfillment` | Shipment/delivery tracking with carrier and address |\n| `FulfillmentLineItem` | Individual fulfillment line item |\n| `BillingAccount` | A payer's account with a seller: customer, provider customer, terms, standing |\n| `BillingPeriodClose` | One payer's invoice for one period and currency; also the billing job target |\n| `BillingLineSource` | The claim that a charge or plan period is billed on exactly one close |\n\n### Collections\n\n`CustomerCollection`, `VendorCollection`, `ContractCollection`, `SalesContractCollection`, `PurchaseContractCollection`, `InvoiceCollection`, `InvoiceLineItemCollection`, `PaymentCollection`, `PaymentAllocationCollection`, `FulfillmentCollection`\n\n`PaymentAllocationCollection.allocatePayment()` splits a payment across invoices\nin one transaction using stable allocation IDs for retries. Direct allocation\nsaves also enforce matching owners, customers and currencies and both balance\ncaps. Read [payment allocation integrity](agents/payment-allocations.md) for\nreplay, parent revision refresh and compatibility requirements.\n\n\n### Enums\n\n| Export | Values |\n|--------|--------|\n| `ContractType` | `estimate`, `order`, `lease`, `agreement`, `supplier_quote`, `purchase_order`, `wholesale_order`, `production_order`, `cart`, `license_sale` |\n| `ContractStatus` | `draft`, `sent`, `accepted`, `declined`, `completed`, `cancelled` |\n| `CustomerStatus` | `active`, `inactive`, `suspended` |\n| `VendorStatus` | `active`, `inactive`, `suspended` |\n| `InvoiceStatus` | `draft`, `sent`, `viewed`, `partial`, `paid`, `overdue`, `cancelled`, `written_off` |\n| `PaymentMethod` | `cash`, `check`, `credit_card`, `bank_transfer`, `crypto`, `other` |\n| `PaymentStatus` | `pending`, `completed`, `failed`, `refunded`, `cancelled` |\n| `FulfillmentStatus` | `pending`, `processing`, `shipped`, `delivered`, `cancelled` |\n| `FulfillmentType` | `shipment`, `delivery`, `pickup`, `digital`, `service` |\n\n### Types and Constants\n\n| Export | Description |\n|--------|------------|\n| `Address` | Shared address interface (street1, street2, city, state, postalCode, country) |\n| `RecognizeRevenueOptions` | Account IDs for invoice revenue recognition |\n| `RecordPaymentOptions` | Ledger and account IDs for payment recording |\n| `InvoiceNumberOptions` | Options for `generateInvoiceNumber()` (prefix, format) |\n| `UNPAID_STATUSES` | Array of invoice statuses considered unpaid (sent, viewed, partial, overdue) |\n| `COMMERCE_MODULE_META` | UI module metadata |\n| `COMMERCE_UI_SLOTS` | UI slot definitions |\n\n### Ledger Integration\n\nInvoice and Payment integrate with `@happyvertical/smrt-ledgers` via dynamic import (optional dependency). Invoice stores `arJournalId` and `revenueJournalId` as plain string references to ledger journals. `recognizeRevenue()` creates a balanced AR entry (DR: Accounts Receivable, CR: Revenue, CR: Tax Payable). `recordPayment()` creates a balanced cash receipt entry (DR: Cash, CR: Accounts Receivable). Both methods return null or throw if the ledgers package is not installed.\n\n`Payment.recordPayment()` claims the payment revision and commits the journal,\nentries, and completed payment in one database transaction. A failed completion\nrolls back the posting and restores the instance's settlement fields for retry.\nThe claimed persisted status is authoritative even if a caller locally resets\nstatus or marks the instance failed without saving. Concurrent or stale instances\nfail instead of posting twice; reload the payment\nand retry only if it is still pending. An already completed payment retains the\n`Payment already recorded` error. A caller's enclosing transaction remains the\nowner: if it rolls back after settlement returns, reload the payment before retry.\nThese guarantees cover new postings, not orphaned journals written by older\nversions. The returned journal uses the caller's database executor.\nBoth payment and refund journal lines retain the payment's explicit currency and\nexact amount; posting does not convert currencies or fall back to USD. When\nreporting accounts that contain different currencies, use the public\n`listPostedMovements` currency filter rather than combining their amounts.\n\n### Cross-Package References\n\nCustomer and Vendor link to `@happyvertical/smrt-profiles` via plain `profileId` string. Invoice and Payment reference `@happyvertical/smrt-ledgers` journals via plain string IDs (`arJournalId`, `revenueJournalId`, `journalId`). All models use `@TenantScoped({ mode: 'optional' })` with nullable `tenantId`.\n\n## Billing-period close\n\n`BillingRuntime` turns approved `@happyvertical/smrt-subscriptions` charges into\ninvoices for each billing owner, pushes them to a payment provider with\nprovider-calculated tax, posts revenue to the ledger, and applies the\nprovider's webhook events. Every provider call goes through\n`@happyvertical/accounting`; `createStripeBillingProvider()` adapts its Stripe\nprovider to the `BillingProvider` port. Money crossing the port is integer\nminor units.\n\n```ts\nimport { getAccountingProvider } from '@happyvertical/accounting';\nimport { SpendingPolicyEvaluator } from '@happyvertical/smrt-subscriptions';\nimport {\n BillingRuntime,\n createStripeBillingProvider,\n enqueueBillingPeriodClose,\n registerBillingRuntime,\n} from '@happyvertical/smrt-commerce';\n\nconst stripe = await getAccountingProvider({ type: 'stripe', secretKey });\nconst billing = await BillingRuntime.create({\n db,\n sellerTenantId: platformTenantId,\n kind: 'provider', // or 'reseller' to bill a reseller's children\n provider: createStripeBillingProvider({ stripe, webhookSecret }),\n billingRelationships, // smrt-tenancy BillingRelationshipService\n ledger: {\n bookCurrency: 'USD', // ISO 4217; must equal the billing currency\n arAccountId,\n revenueAccountId,\n taxAccountId,\n cashAccountId,\n prepaidCreditAccountId,\n },\n onPayerStanding: async ({ payerTenantId, standing, db }) => {\n // suspend or reinstate the payer; runs in the event transaction\n },\n});\n\n// One account per payer: its customer, tax location, and terms.\nawait billing.upsertAccount({\n payerTenantId,\n name: 'Network Co',\n email: 'billing@example.test',\n billingAddress: { country: 'CA', postalCode: 'T0L 0A0' },\n});\n\n// Optional: bill this payer from its activation date instead of calendar\n// months, prorating flat plans added mid-period (see \"Billing cycles\").\nawait billing.upsertAccount({\n payerTenantId,\n name: 'Network Co',\n billingAnchorAt: activatedAt,\n prorateFlatPlans: true,\n});\n\n// Close each payer's last ended period — safe to run on every schedule tick.\nregisterBillingRuntime('platform', billing);\nawait enqueueBillingPeriodClose({ runtime: 'platform' });\n\n// Webhook route: verify, enqueue, respond 2xx.\nconst intake = await billing.acceptWebhook(\n rawBody,\n request.headers.get('stripe-signature'),\n);\nif (intake.type?.endsWith(':unverified_credit_purchase')) {\n // alert: a paid checkout claimed to buy credit but failed verification\n}\nawait billing.processEvents(); // or enqueueBillingEvents({ runtime: 'platform' })\n\n// Prepaid credit through provider checkout: tax is added on top when the\n// payer's account is taxed; `savePaymentMethod` keeps the card for top-ups.\nconst { url } = await billing.createCreditCheckout({\n spendingPolicyId,\n amount: 5000,\n purchaseId: cartId,\n savePaymentMethod: true,\n successUrl,\n cancelUrl,\n});\n\n// Card on file at signup: a setup checkout that charges nothing. Its\n// completion event makes the card the payer's default and adopts the billing\n// address collected at checkout as the tax location.\nconst setup = await billing.createCardSetupCheckout({\n payerTenantId,\n currency: 'CAD',\n setupId: signupId,\n successUrl,\n cancelUrl,\n});\n\n// Automatic top-ups: charge the saved card when a balance would run out.\n// Accounts are taxed by default (`automaticTax`); a taxed account is charged\n// the credit plus provider-calculated tax (#3194).\nconst evaluator = await SpendingPolicyEvaluator.create({\n db,\n autoTopUp: billing.autoTopUpHook({ amount: () => 2500 }),\n});\n```\n\n- **What is billed.** A `provider` runtime bills `ClientCharge`s (and their\n `BillingAdjustment`s) to the payer each charge names, plus monthly flat plans\n it owns, to each subscriber's billing owner. A `reseller` runtime bills the\n `RetailCharge`s its children owe it plus its own flat plans. Charges approved\n before the period end are billed once, whatever period that is; flat plans\n are billed in arrears for the payer's closed period (trials and\n provider-managed subscriptions are skipped). One invoice per payer and\n currency carries both kinds of lines.\n- **Replay safety.** Close, invoice, and line ids are derived from the payer,\n currency, and period; each charge is claimed by exactly one close; the\n provider invoice uses the close id as its idempotency key; and every step is\n persisted before the next, so a retry resumes where it stopped. A lease stops\n two workers advancing the same close. A close without a period also resumes\n every unfinished close whose period has ended, even one the payer's current\n schedule no longer produces (#3116). A payer whose charges net to a credit\n gets no invoice; the credit is carried to its next invoice.\n- **Billing cycles (#3116).** A payer's periods follow its account's\n `billingAnchorAt`. Unset (the default) they are UTC calendar months. Set,\n they run monthly from the anchor at its UTC time of day; a day the month\n lacks is clamped to its last day, always from the anchor itself (an anchor\n on Jan 31 bills Jan 31 → Feb 28 → Mar 31). Before the anchor the schedule is\n calendar months, and the anchor's own month ends at the anchor (a *stub*).\n `closePeriod()` / `enqueueBillingPeriodClose()` with no period close each\n payer's **last ended period on its own schedule**, so payers on different\n anchors are closed by the same daily tick. An explicit\n `{ periodStart, periodEnd }` closes that period for calendar payers (flat\n plans only when it is a calendar month, as before) and for anchored payers\n whose schedule has exactly that period. `billingPeriodFor(payer, at)` returns\n a payer's current period; `billingPeriodContaining()`,\n `lastEndedBillingPeriod()`, and `prorateMinorUnits()` are exported.\n- **Proration.** A flat plan is priced `price × billed time / cycle length`,\n in integer minor units rounded half up (exact integer arithmetic; the\n cycle is the period's own month, so February prorates over 28 or 29 days).\n With `prorateFlatPlans` off (default) the billed time is the whole period\n whenever the subscription was active in it and out of trial at its start —\n the pre-#3116 behavior. With it on, the billed time is exactly the time the\n subscription was active and out of trial: a subscription starting, leaving\n trial, or canceled mid-period is billed pro rata. Proration happens before\n the account's flat discount. Split into parts, prorated amounts can differ\n from the full price by a minor unit.\n- **First period.** *Anchor at signup* (set `billingAnchorAt` to the\n signup/activation instant): the first period is a full period from signup;\n nothing before it is billed. *Bill from signup to the next anchor* (keep a\n fixed anchor, or calendar months, and set `prorateFlatPlans`): the first\n period is billed pro rata from signup. Items added later are prorated to the\n payer's anchor when `prorateFlatPlans` is on and billed a full period\n otherwise.\n- **Mid-period changes.** Billing is in arrears, so a cancellation needs no\n credit: with proration the canceled period is billed up to `canceledAt`,\n without it in full. A plan change is billed at the plan in effect at close\n for the whole window (no plan-change proration yet, #3119), and a cancellation\n back-dated into an already billed period is not credited — issue an\n adjustment.\n- **No double billing across schedule changes.** Every flat-plan claim records\n the exact time it bills, and a subscription's claims are numbered, so only\n one worker can write the next claim and two can never claim the same time.\n Moving an account from calendar months to an anchor, moving an anchor, or\n moving a subscription to a payer on another schedule bills only time not yet\n billed, prorated. For example, calendar months through February and then an\n anchor on Mar 20 bills the Mar 1 → Mar 20 stub pro rata, then Mar 20 → Apr\n 20. Time around an already billed window is billed as separate lines, each\n with its own service period. Stop workers running a pre-#3116 version\n before relying on this: they claim flat plans outside the numbering.\n- **Service periods.** Each flat-plan invoice line carries its billed window\n as `periodStart`/`periodEnd`, down to the provider port and on to Stripe's\n invoice item `period`.\n- **Upgrading to #3116.** Additive schema only: `_smrt_billing_accounts` gains\n `billing_anchor_at` (nullable) and `prorate_flat_plans` (default false), and\n `_smrt_billing_line_sources` gains `chain_sequence` (default 0) and an index\n on `(line_key, chain_sequence)`; run `smrt db:migrate`.\n Existing accounts stay on calendar months, and claims written before the\n upgrade (`<subscriptionId>:<periodStart>`, number 0) count as billed\n coverage, so nothing is billed again after it.\n- **Tax** comes from the provider (Stripe Tax) using the account customer's\n `defaultBillingAddress`; the invoice records it as `providerTaxAmount` in the\n save that issues it. Billing invoices are ordinary money-model invoices in\n the seller's tenant; period close seeds its standard codes if needed. Every\n billing line is an explicit override to the seller's `out-of-scope` code, so\n the seller's default code never taxes it a second time. Charges are written\n before credits, so the running subtotal never goes negative. Revenue posting\n uses `ledger.bookCurrency` and is idempotent.\n- **Events** are verified, stored in smrt-jobs' durable delivery inbox, and\n applied against current provider state: paid invoices record a payment and\n allocation; failures and overdue notices mark the payer `past_due` and its\n flat-plan subscriptions `past_due`; an invoice written off at the provider\n (`markInvoiceUncollectible(invoiceId)`, or in Stripe) is written off\n locally and marks the payer `uncollectible` (no bad-debt journal is\n posted; AR stays until it is paid or an operator journals it); payment\n reinstates them, including a late payment of the written-off invoice. Dunning is the provider's.\n Subscribe the webhook endpoint to `invoice.*`, `customer.subscription.*`,\n `checkout.session.completed`, `checkout.session.async_payment_succeeded`,\n and `payment_intent.*`.\n- **Prepaid credit** purchases credit a `period: 'balance'` spending policy\n once per checkout session, paid by the policy's tenant or, for a delegated\n balance, the parent that set it. Amounts are ISO 4217 minor units in any\n currency the provider supports. When the payer's account is taxed\n (`automaticTax`, not tax-exempt; override per call), provider tax is\n charged on top and collected at checkout with the buyer's address: the\n credit is the amount bought, the payment is the total collected, and the\n tax is booked to the tax account. For a payer with a provider customer but\n no local tax location, the address collected at checkout becomes its tax\n location. `savePaymentMethod` requires a provider that can re-read the\n checkout and set a default payment method, and is refused otherwise.\n- **Card on file (#3139).** `createCardSetupCheckout()` (or a credit purchase\n with `savePaymentMethod`) saves the payer's card without charging it. On\n completion the card becomes the provider customer's default and the\n payer's default `PaymentInstrument`. When the checkout collected the billing\n address (a taxed payer with no tax location), it becomes the payer's tax\n location. `cardOnFile(payerTenantId)` returns `{ onFile, savedAt? }` from\n the same check automatic charges use (a default card with the account's\n provider customer), for \"card on file\" displays and signup activation;\n the payer or a system context may call it (#3187).\n- **Automatically charged invoices.** With `autoChargeInvoices: true` on the\n runtime, a payer with a default card is invoiced `charge_automatically`:\n the provider charges the card after the invoice is sent, on its own\n schedule, and retries failures. Each pushed invoice records the method in\n `Invoice.collectionMethod` (`charge_automatically` or `send_invoice`; empty\n for invoices pushed before #3190). Do not offer another payment rail on a\n `charge_automatically` invoice the provider is still collecting.\n Upgrading adds the `collection_method` column to `invoices` (run\n `smrt db:migrate`). Activate service on the `current` standing\n from the `paid` event, not on send; a failure marks the payer `past_due`.\n- **Automatic top-ups.** Taxed accounts (the default: `automaticTax` on, not\n tax-exempt) are charged the credit plus provider-calculated tax (#3194):\n the balance is credited the credit, the payment records the credit, and\n the tax is booked to the tax account. `taxedAccounts: 'skip'` does not top\n them up, and `'charge_untaxed'` charges them without tax. A taxed payer\n without a tax location is not charged. A location Stripe rejects fails the\n attempt with `failureCode: 'customer_tax_location_invalid'`\n (`onAutoTopUpFailed`), and it is retried only after `retryAfterMs`. Pass\n `onAutoTopUpSkipped` to learn when a needed top-up will not be charged\n because of the payer's account. Its `reason` is `taxed_account`, `no_card`,\n `no_account`, or `tax_location_invalid`, and more may be added. Use it, for\n example, to ask the payer to top up by hand or to add a billing address; it is not called while a charge is processing, while a\n declined card waits out `retryAfterMs`, or when the top-up is no longer\n needed or `amount` declines it (#3189).\n `billing.autoTopUpHook()` is the `autoTopUp` hook for\n `SpendingPolicyEvaluator`: when a balance would run out it charges the\n payer's saved card off-session (the delegating parent's, for a delegated\n balance) and credits the balance only when the charge succeeds. A charge\n still processing is credited from its `payment_intent.succeeded` event; a\n decline or an authentication requirement credits nothing, closes the\n attempt, and calls the runtime's `onAutoTopUpFailed` (ask the payer to\n re-save their card with a setup checkout). One attempt runs per policy at a\n time, retries of a declined card wait `retryAfterMs` (default one hour),\n and the credit is granted exactly once however the outcome arrives.\n- **Product tax codes (#3194).** `taxCodes: { credit, invoice }` on the\n runtime classifies prepaid credit (checkout purchases and taxed top-ups)\n and billing-period invoice lines for Stripe Tax (`txcd_...`). Without it,\n the Stripe account's default product tax code applies.\n- **Upgrading to #3194.** Requires `@happyvertical/accounting` 0.96 or later.\n No schema change. Taxed accounts are now topped up with tax. To keep the\n previous behaviour, pass `taxedAccounts: 'skip'`.\n- **Upgrading to #3139.** Requires `@happyvertical/accounting` 0.92 or later.\n No schema change. Credit checkouts are now taxed for taxed accounts (pass\n `automaticTax: false` to keep them untaxed), and Stripe customers are\n created idempotently.\n\n### Payment rails: BTC and other crypto (#3138)\n\nA seller runtime can take payments on more than one **rail**. The issuing\n`provider` (Stripe) still issues, taxes, and emails every invoice; extra rails\nin `paymentProviders` let a payer choose, per payment, to pay an invoice or buy\nprepaid credit another way. The crypto rail runs short-lived, fiat-priced\ncheckouts through `@happyvertical/payments`' provider-neutral\n`CryptoCheckoutGateway` — BTCPay Server at launch — so another gateway can\nreplace BTCPay without changing this package or its consumers.\n\n```ts\nimport {\n BillingRuntime,\n createBtcPayBillingProvider,\n createStripeBillingProvider,\n} from '@happyvertical/smrt-commerce';\n\nconst btcpay = createBtcPayBillingProvider({\n baseUrl, apiKey, storeId, // one BTCPay store per seller entity\n webhookSecret, metadataSecret, // from the host's secret store, by name\n speedPolicy: 'LowMediumSpeed', // settle after 2 confirmations (BTCPay offers 0/1/2/6)\n rateSource: 'kraken',\n minimumAmount: { CAD: 500, USD: 500 },\n});\nconst billing = await BillingRuntime.create({\n db, sellerTenantId, kind: 'provider',\n provider: createStripeBillingProvider({ stripe, webhookSecret }),\n paymentProviders: [btcpay],\n paymentPolicy: { latePaymentPolicy: 'review', refundBasis: 'original_native' },\n billingRelationships,\n ledger: { ...ledger, cryptoHoldingsAccountId, fxGainLossAccountId, feesAccountId },\n});\n\n// Prepaid credit or an issued invoice, paid with BTC:\nawait billing.createCreditCheckout({ ...purchase, provider: 'btcpay' });\nawait billing.createInvoicePayment({ invoiceId, provider: 'btcpay', purchaseId, successUrl, cancelUrl });\n\n// Webhook route for the rail (BTCPay signs with its own header):\nawait billing.acceptWebhook(rawBody, '', { provider: 'btcpay', headers: request.headers });\nawait billing.processEvents();\n```\n\n- **Refusals are typed (#3185).** `createInvoicePayment()` and\n `createCreditCheckout()` throw `BillingPaymentRefusedError` for requests the\n payer can correct, with a stable `code`: `not_found`, `not_payable`,\n `payment_in_progress`, `nothing_due`, `invalid_amount`, `below_minimum`\n (under the rail's `minimumAmount`), or `no_account`. Show its message as a\n 4xx; any other error is a server failure, and `TenantIsolationError` still\n means the caller is not the payer. Treat an unknown code like\n `not_payable`.\n- **Settlement is the gateway's.** Credit is granted and invoices are paid\n only when the gateway reports `settled` under its own confirmation policy;\n this package never counts confirmations. BTCPay offers 0, 1, 2 or 6\n confirmations; the default is `LowMediumSpeed` (2 confirmations).\n- **Payment attempts.** Every rail checkout is a `BillingPaymentAttempt`\n recording the locked fiat price, fiat and native amounts received, rate and\n rate source, each payment's txid, rail and fee, a timeline of status changes,\n and what settlement produced. `listPaymentAttempts()` feeds \"payment\n confirming\" displays and operator queues; every filter applies before its\n `limit` and `offset`, so paging through `{ unresolved: true }` lists every\n open exception (flagged, not yet resolved) however old. `refreshPaymentAttempts()` is the polling\n fallback for missed webhooks.\n- **Dunning pauses** for an invoice while a payment for it is confirming\n (0-conf seen); if the payment then expires or is invalidated the payer's\n standing is re-applied.\n- **Invoices paid on a rail** are closed at the issuer with\n `markInvoicePaidOutOfBand` (Stripe `paid_out_of_band`), so Stripe stops\n collecting; Stripe's own `paid` event then records nothing more.\n `createInvoicePayment` refuses when the issuing provider cannot do that.\n A written-off (uncollectible) invoice with an amount due can be paid on a\n rail too, as it can by card at Stripe (#3188): the payment is recorded,\n Stripe's invoice is closed out of band, and the payer returns to `current`;\n the invoice keeps its `WRITTEN_OFF` status (its `amountPaid` shows the\n recovery).\n- **Exceptions never auto-refund.** Underpaid, overpaid, late, manually marked\n (at the gateway), invalidated-after-settlement, and paid-twice attempts are\n flagged for an operator (`resolvePaymentAttempt`). Per-seller\n `paymentPolicy` sets under/overpayment tolerances (basis points), late\n payments (`review` | `accept`), manually marked checkouts, hold vs convert\n (`conversionHandler`), and the refund basis.\n- **Ledger.** Receipts are booked at the locked fiat amount into\n `cryptoHoldingsAccountId` (default `cashAccountId`); money received above\n the price is booked as customer credit (prepaid-credit liability).\n `recordManualRefund()` refunds from that excess first, then from purchased\n credit (or an invoice payment kept as credit because the invoice was paid\n elsewhere) — capped cumulatively, once per reference; an invoice payment\n applied to its invoice is reversed at the issuer, not here.\n `recordCryptoConversion()` posts a conversion with FX gain/loss.\n- **Upgrading.** Additive schema: `_smrt_billing_payment_attempts` (run\n `smrt db:migrate`). A runtime without `paymentProviders` never reads it.\n- **One live payment per invoice.** The issuer's own `paid` event for an\n invoice a rail closed out of band records nothing (the rail records it); an\n out-of-band close made by someone else (wire, cheque) is recorded as an\n `OTHER`-method payment; a real card payment made while a rail payment\n confirms is recorded and the rail money is flagged `invoice_already_paid`.\n An issuer close whose rail payment never settles is flagged\n `out_of_band_without_settlement`: reopen the invoice at the issuer, then\n `resolvePaymentAttempt()` it, after which a later out-of-band close is\n recorded normally.\n- **Entities.** Each legal entity is its own seller runtime with its own\n store, keys, and ledger. Inter-entity resale is ordinary reseller billing\n between two sellers, payable on any rail the selling entity offers.\n\nSee [`AGENTS.md`](./AGENTS.md#billing-period-close-3060) for invariants and\nknown limits.\n\n## Dependencies\n\n- `@happyvertical/smrt-core` -- ORM and code generation\n- `@happyvertical/smrt-tenancy` -- multi-tenant scoping\n- `@happyvertical/smrt-subscriptions` -- charges, plans, and credit balances billed by period close\n- `@happyvertical/smrt-jobs` -- period-close jobs and the provider event inbox\n- `@happyvertical/accounting` -- payment-provider (Stripe) calls\n- `@happyvertical/smrt-types` -- shared type definitions\n- Peer: `@happyvertical/smrt-ledgers`, `@happyvertical/smrt-profiles`, `@happyvertical/smrt-svelte`\n\n## Contributor guide\n\nSee [`AGENTS.md`](./AGENTS.md) for package architecture, invariants, validation,\nand contributor guidance.\n\n## Pricing version UI\n\n`PricingVersionSummary` and `PricingVersionDecision` compose the quote revision\ncontract without adding a pricing ledger. Compare versions using\n`QuoteRevisionComparison`; the application owns every decision and native form\naction. See [pricing version presentation](agents/pricing-versions.md).\n\n## Commercial UI composition\n\nCustomer addresses and vendor/quote currencies use the shared localized code\nselectors while preserving native field names and rejected raw drafts. See\n[commercial UI contracts and backend boundaries](agents/commercial-ui.md) for\nnative forms, recovery, amount units and consumer adoption, plus the focused\n[customer/vendor](agents/customer-vendor-ui.md) and\n[quotation](agents/quote-ui.md) contracts for selector restrictions.\n\n## Customer and vendor contacts\n\n`Customer.contacts` and `Vendor.contacts` hold the people to reach at a party\n(`PartyContact`: `id`, `name`, `label`, `email`, `phone`, `address`) as a JSON\ncolumn; existing databases need `smrt db:migrate` for the new `contacts`\ncolumns. The form's contact rows are written with `savePartyContacts()`:\n\n```typescript\nimport {\n applyPartyContactIntent,\n PartyContactValidationError,\n readPartyContactRows,\n savePartyContacts,\n} from '@happyvertical/smrt-commerce';\n\nconst form = await request.formData();\n// Throws PartyContactPayloadError when the form's contactCount marker is absent\n// (block not rendered, or fieldNames differ), so a save never deletes by accident.\nconst rows = readPartyContactRows(form); // pass the form's fieldNames if overridden\nconst { contacts, handled } = applyPartyContactIntent(rows, String(form.get('intent')));\nif (handled) return { values: { ...values, contacts } }; // add/remove round trip, no save\ntry {\n await savePartyContacts(vendors, vendorId, rows, { expectedTenantId });\n} catch (error) {\n if (error instanceof PartyContactValidationError)\n return fail(400, { values: { ...values, contacts: rows }, errors: { contacts: toMessages(error.errors) } });\n throw error;\n}\n```\n\n`savePartyContacts` also accepts the `FormData` itself (with `fieldNames`) and\nreads it the same way. The rows replace the party's contacts: posted ids are kept, new rows get an\nid, unposted rows are removed, blank rows are dropped. See\n[customer/vendor UI](agents/customer-vendor-ui.md#contact-rows-3501).\n\n## Customer and vendor selectors\n\n`CustomerSelect` and `VendorSelect` from `@happyvertical/smrt-commerce/svelte`\nare searchable, field-sized pickers for a customer or vendor relation field.\nThey are registered in `COMMERCE_UI_SLOTS` with `selects:\n'@happyvertical/smrt-commerce:Customer'` / `':Vendor'`, so generic forms (via\n`findSelectorFor` over the manifest's `uiSelectors`) use them for any\n`@foreignKey` or `@crossPackageRef` field targeting those models.\n\nThey are presentation only. The caller owns the data: `search(query)` returns\nthe existing party DTOs (`CustomerDisplayData` / `VendorDisplayData`, whose\n`profile.name` is the label), and `resolve(id)` returns the record behind the\ncurrent value. Each row shows the profile name with status (and customer type).\nThe committed id, never the name, posts under `name`. Pass `onCreate` to offer a\n\"New customer\" / \"New vendor\" action; it receives the searched text, and a\nreturned record is selected.\n\n```svelte\n<CustomerSelect\n name=\"customerId\"\n bind:value={customerId}\n search={(query) => customers.search(query)}\n resolve={(id) => customers.byId(id)}\n onCreate={(query) => openCustomerDialog(query)}\n/>\n```\n\nThe same models carry `@field({ ui: { widget } })` hints in the manifest:\n`textarea` on `Contract` (and subclass) `terms` and `notes`, `Customer`/`Vendor`\n`notes`, and `Invoice` notes and terms; `currency` (an ISO 4217 code picker) on\n`Contract`, `Vendor`, `Invoice` and `Payment` `currency`; `email`/`phone` on\n`Vendor.defaultContactEmail`/`defaultContactPhone`. See\n[customer and vendor selectors](agents/customer-vendor-ui.md#selectors-3602).\n\n## Invoice preparation UI\n\n`InvoiceEditor` from `@happyvertical/smrt-commerce/svelte` is the invoice form,\nbuilt on the commercial money model, v2, which is the only invoice money model.\nIt requires a `money` prop (`MoneyEditorProps`): a lossless draft with\ndescriptions, fractional quantities, unit prices, percentage or amount\ndiscounts and a tax code per line (inherited or overridden), plus the\nauthorized tax codes. Its previews run the same exact calculator the server\nuses, and the server re-resolves tax codes and recomputes every stored amount.\nAn issued document renders only its frozen stored snapshot.\n`InvoiceAllocationFields` and `InvoiceReview` add caller-owned sources and\napprovals. See [the editor contract](agents/invoice-preparation.md), the\n[line calculation helper](agents/invoice-calculations.md), and the\n[existing-database storage migration](agents/invoice-quantity.md).\n\n## Exact cost billing\n\nThe independent `@happyvertical/smrt-commerce/cost-billing` entry point provides\nexact signed reimbursement/fee calculations, ordered generic markup provenance,\nand explicit line or invoice tax rounding. Its opt-in ordered tax calculator\nsupports subset compounding with caller-selected signed invoice allocation.\nSee [the cost billing contract](agents/cost-billing.md).\nIt does not alter Invoice persistence, editor defaults or settlement behavior.\n\n### Purchase-order header editing\n\nImport `PurchaseOrderHeaderForm` from `@happyvertical/smrt-commerce/svelte` for a\nnative POST of vendor, reference, notes, expected date and ship-to fields. Pass\n`action`, `vendors` and raw `values`; return canonical field `errors` and the same\n`hiddenFields` after server validation. This header-only form leaves purchase\nallocations and totals unchanged. `PurchaseOrder` stores `expectedDate` and\n`shipTo` in existing STI metadata. See [the purchasing contract](agents/purchasing-ui.md#purchase-order-header)\nfor validation, retained values and transport details.\n\n### Invoice retention and release\n\n`configureInvoiceRetention` freezes an explicit retained minor-unit amount on an\nunpaid draft. Supply tenant, invoice, currency, expected invoice revision,\nrequest identity, actor, reason, evidence reference, and versioned host policy.\nThe supported `creditPolicy: 'retained-first'` is an explicit caller choice:\nissued credits reduce unreleased retention first, then current payable. Hosts\nmust choose and authorize their regional policy; Commerce supplies no legal\npercentage or release date default. Configuration cannot be overwritten; replace\nan unissued draft to change the original agreement.\n\n`releaseInvoiceRetention` appends evidence under the invoice's transaction lock.\nIt cannot release more than the currently retained remainder. Exact request\nreplays are safe; changed payloads or stale revisions fail. Both commands retain\ncaller transaction affinity. Original gross, tax, line snapshots and approved\nconfiguration stay unchanged. Credits and credit cancellation derive remaining\nretention without rewriting release history.\n\n`invoice.getPayableFacts()` separates `grossBalanceMinor`,\n`retainedRemainingMinor`, `currentlyDueMinor`, and `allocationCapMinor`. The\nallocation API enforces the current cap. `getAmountDue()` returns current due;\n`getBalance()` remains the signed gross balance. An invoice with paid current\ndue and unreleased retention is not fully paid or overdue. Display gross and\ncurrent payable separately; pass explicit current due and remaining holdback to\nthe exact retained invoice UI props rather than treating gross as payable.\nStored money facts include `payable` for retained invoices; MCP projection honors\nfield visibility for every source of the payable alias.\n\nProvider-controlled imports/automatic collection cannot acquire retention.\nAccounting export refuses unreleased retention until the provider has an\nexplicit payable representation; it never silently requests collection of\ngross. Fully released invoices use the existing gross accounting contract.\n\n## Retained invoice accounting\n\n`loadRetainedInvoiceAccountingSnapshot` supplies a read-only frozen document for\nreviewing item/tax mapping before posting; `toRetainedInvoiceAccountingInput`\nvalidates that reviewed mapping against those frozen lines. Both preserve tenant and caller executor\nscope and performs no provider operation. Generic accounting snapshot/export still\nrefuses unreleased retention. A supplied host-managed release due date may precede\nthe release date: preserving original past-due terms makes the released amount\nimmediately overdue rather than silently extending payment terms.\n\n`loadRetainedCreditAccountingSnapshot` and `toRetainedCreditAccountingInput`\nprovide the equivalent review path for an issued calculated credit. The caller\nsupplies both original invoice and credit IDs; the owning API verifies tenant,\ncustomer, currency and exact original lineage, then retains the existing frozen\nreader's issue and provider-realm checks. Generic retained-credit export remains\nblocked. Review never creates a credit adjustment or contacts a provider.\n\nThe public `syncRetainedInvoiceToAccounting`, `releaseRetainedInvoiceToAccounting`,\n`syncRetainedCreditToAccounting`, and `syncRetainedRefundToAccounting` commands\nimplement an explicit QuickBooks accrual reclassification contract. They require\nSDK `receivableTransfers` from the published SDK0.104.1 cohort\n(happyvertical/sdk#1414 / #1415; absent from SDK0.104.0).\nThey are available from the Commerce root and `/invoices` entry points.\n\nThe tenant must review/version the realm, environment, customer, AR account,\nretained-asset account and optional bank account mapping. Supported choices are\n`accrual`, `invoice-tax-point` and `host-managed` release due dates. Verified home\ncurrency only; no inferred FX, tax timing, recovery percentage or release date.\nHosts authorize actors before these server commands and provide an active tenant.\n\nFor gross10500/retained1000, the original approved invoice remains10500. A\nwithholding journal debits retained assets and credits customer AR1000; a\nzero-cash application links that credit to the original invoice. A partial release\ncreates the opposite journal and an explicitly dated host collection obligation.\nThe original invoice and its tax snapshot are unchanged. Provider collections and\nprovider tax overrides are unsupported for this contract.\n\nInitial export requires an issued, unpaid, uncredited, unreleased host-owned\ninvoice with no prior provider identity. Historical source-owned invoices require\na separate reconciled ownership contract and are rejected: importing history must\nnot duplicate its original journal. Existing local retention commands continue to\nreject provider-controlled releases; use the provider release command instead.\n\nRetained-first credits cancel the applicable retained asset through a release\njournal, apply the exported credit memo to that journal, and apply any due portion\nto the original invoice. Unapplied credit remains available for a refund. Refund\nsync requires an already completed local refund Payment, its cash journal and one\nexact source-credit allocation. It records the cash journal and applies the\nexisting credit; it performs no bank action and makes no settlement-certification\nclaim. That source payment/allocation becomes immutable. Provider-managed invoice\nvoids/write-offs, credit cancellation/reallocation and refund deletion are rejected\nrather than silently erasing remote postings. Corrective reversal contracts are\nnot implemented by these commands.\n\n### Recovery and concurrency\n\nEach external write has persisted request bytes/hash, attempt owner, status and\nvalidated readback. Confirmed earlier steps survive a later failure. Unknown or\ninterrupted steps block new operations; `reconcileRetainedAccountingStep` requires\nthe observed request/attempt, a known remote ID for exact provider readback, or\nexplicit authoritative absence evidence. An interrupted in-flight owner must be\nproven stopped. Reconciliation evidence and previous attempts remain recorded.\n`reconcileRetainedBaseInvoice` wraps the existing frozen invoice recovery contract.\n`reconcileRetainedCreditAccounting` resolves the reserved credit-memo creation step. Ordinary credit export is blocked for provider-retained sources.\n\nThe descriptor hash is not remote idempotency. The SDK uses documented QuickBooks\nrequest-ID duplicate handling; never create a new request identity merely because\na response was lost. Exact local replays reuse confirmed steps. Competing commands\nserialize under the tenant/source invoice locks, and releases check an observed\ninvoice revision. Source credits cannot change during an unfinished retention\noperation. Commands reject caller-owned Commerce money transactions because a\nprovider write cannot be rolled back with local SQL.\n\n`readRetainedInvoiceAccountingState` exposes the persisted operation/readback\nhistory. Canonical `Invoice.getPayableFacts()` remains the source of local gross,\nretained, released, credited and currently due amounts. Provider invoice\n`TotalAmt - Balance` includes noncash applications and must never be labeled cash\nreceived. SDK readback separates noncash applications, recorded cash journals and\nunverified bank settlement.\n\nValidation uses native SQLite/PostgreSQL persistence with mocked public provider\noperations, plus the SDK's exact request/readback fixtures. No live provider call\nor sandbox certification has been performed. Primary contract evidence and\nprovider-field limits are documented in the SDK Accounting README.\n\n### Incomplete supplier price evidence\n\nUse `recordPurchasePriceObservation`, `readPurchasePriceObservation`, and\n`completePurchasePriceObservation` for source quotes/orders that lack complete\nnet/tax/gross facts. Unknown totals remain null and no calculated or reportable\nContract exists until explicit reviewed completion. See\n[observed purchase prices](agents/observed-purchase-prices.md).\n"
|
|
19733
21458
|
},
|
|
19734
21459
|
{
|
|
19735
21460
|
"path": "agents/invoice-quantity.md",
|
|
19736
21461
|
"module": "invoice-quantity",
|
|
19737
21462
|
"content": "# Invoice quantity persistence\n\nInvoiceLineItem accepts nonnegative decimal quantities with at most six decimal\nplaces. The `1.0` default declares a floating-point quantity column. Unit price,\ndiscount and amount stay safe integer minor units. Every save goes through the\ninvoice money aggregate, which recomputes the line and ignores\nany supplied amount. Tax comes from the line's resolved tax code, never from a\nstored rate. See the [commercial money model](money-model.md).\n\n## Existing integer columns\n\nRun a backup and pause invoice writers for this explicit migration. With a root\ndatabase handle and its known engine (`sqlite`, `postgres`, or `duckdb`), call\n`preflightInvoiceEditorStorage(db, engine)`, resolve every reported invalid row,\nthen `migrateInvoiceEditorStorage(db, engine)`. The preflight rejects negative,\nnonfinite, unsafe, excess-precision, and numerically non-roundtripping quantities.\nThe migration uses a transaction (and a PostgreSQL writer lock) and never rescales\nor rounds stored values. PostgreSQL widens INTEGER/BIGINT to DOUBLE PRECISION;\nDuckDB widens to DOUBLE. Repeating it leaves an already widened declaration alone.\nAn absent table is reported as absent and is never marked migrated.\n\nSQLite uses the public core table-rebuild planner to change the declaration to\nREAL while preserving existing columns, constraints, indexes, and triggers. If\nincoming foreign keys make that rebuild unsafe, the migration throws with the\nplanner reason and rolls back; it does not disable constraints or lose children.\nResolve that maintenance condition before deploying fractional writers. The\nmigration no longer adds an editor-state column. An `invoice_editor_state_json`\ncolumn that an earlier version added is left in place and unused. No schema\nmutation runs implicitly during runtime initialization or model save.\n\nThe actual DuckDB quantity/storage migration is tested. Complete Commerce model\npersistence on DuckDB is currently unsupported because its hard foreign keys use\nON UPDATE CASCADE, which DuckDB cannot preserve; the schema builder refuses that\ncontract. SQLite and PostgreSQL exercise complete save/reload model behavior.\n"
|
|
19738
21463
|
},
|
|
21464
|
+
{
|
|
21465
|
+
"path": "agents/historical-sales.md",
|
|
21466
|
+
"module": "historical-sales",
|
|
21467
|
+
"content": "# Historical issued sales and original customer funds (#4081)\n\nHistorical intake is a separate source authority, not a new sale, send, or cash\nposting. Hosts must authorize the reviewer/importer, preserve original evidence,\nand call these public commands with the explicit active tenant. All writes use\none caller-affine transaction and the existing tenant money serialization lock.\n\n`recordHistoricalSalesMoney({ db, tenantId, invoiceId, requestId, evidenceRef,\nreview, source, facts, creditedSource? })` adopts an empty draft Invoice. Supply\noriginal integer minor-unit net/tax/gross, explicit signed-versus-magnitude\npolarity, original issue calendar date/time zone, and a nullable unknown due date.\nNormal calculated Invoice construction still defaults its due date as before.\nHistorical invoices expose `moneyAuthority: 'historical'` and a frozen source\nsnapshot. They create no InvoiceLineItems, fake quantities/rates, delivery event,\nAR/revenue journal, or provider invoice.\n\nA `detail: { kind: 'lines', lines }` source creates immutable\n`HistoricalSalesLine` children. The returned `{ snapshot, lines }` binds every\nsource key to a concrete `lineId`; use these IDs for consumer crosswalks.\nUnknown line tax, gross, quantity and rate remain null. Signed real adjustment\nlines retain their source values. The line net sum and every fully known other\nsum must exactly equal its corresponding original header.\n\nHistorical credits specify the exact original invoice/money snapshot and\noptional concrete original child IDs. Independent net, tax and gross capacity\nchecks never prorate a header. `getHistoricalSalesMoney` and\n`readHistoricalSalesLines` validate immutable retained authority.\n`getInvoiceMoneyFacts` includes the historical source projection. Exact header\nreports remain available through `listHistoricalSalesHeaderFacts` even when tax\nclassification is unknown. Breakdown-dependent tax reports require explicit\nreviewed component identities, taxable and net bases and classification; they\nnever infer a percentage from the source amount or borrow today's rate.\n\nOptional original `source.retention` records exact retained cents, an explicit\nretained-first credit policy, source actors/evidence and original calendar-dated\nreleases. This contract represents retention configured at original issue; its\noriginal effective date must equal the issue calendar date. A later retention\nconfiguration requires its own supported source event contract. Derived retention\nevents retain actual `recordedAt` and separate\n`effectiveOn`; as-of original cash eligibility uses the original dates. Ordinary\ncurrent retention configuration/release commands keep their existing behavior.\nOriginal credit/release sequencing rejects a release whose retained-first\ncapacity was already consumed; same-day ordering must be explicitly reviewed.\nRelease payment terms remain the original invoice due date, including an\nexplicitly unknown date. No jurisdiction terms are invented.\n\n`recordHistoricalCustomerFunds` retains original receipt/refund evidence and\nexplicit original deposit/release policy without creating a Payment or journal.\nOriginal accounting ownership and journal references are evidence, not authority\nto create duplicate original cash. Refunds identify either conserved unapplied\nfunds or one exact issued credit. Their headers immediately reserve refund\ncapacity, even before their original allocation row is imported.\n\n`recordHistoricalCustomerAllocation` records exact source allocation identities.\nReceipt applications affect the shared invoice paid balance once. Same-original\ncredit allocation rows and refund allocation rows audit their already-recorded\neconomic effects and do not reduce balances again. Cross-invoice transferable\ncredits are not represented by this contract. Same-day cash/credit chronology\nrequires explicit reviewed ordering; earlier original cash remains preserved\nwhen a later credit creates owed/refundable overpayment. Original cash dates\nremain separate from current balances and import timestamps.\n\n`getHistoricalCustomerFundsPosition` returns exact received/allocated/refunded/\navailable minor units. `applyHistoricalCustomerFunds` and\n`refundHistoricalCustomerFunds` perform NEW movements against remaining original\nfunds using explicit current active same-tenant accounts and the pinned original\npolicy terms. Applications use the existing liability-to-AR reclassification;\nrefunds use the existing journal-backed Payment command and retain the historical\nreceipt ID. Original receipts are never forged into completed Payments. Shared\nlive/historical paid/refund capacity prevents a second allocation or refund.\n\nStable source namespace/key identities replay exact facts across import runs\nwithout replacing the original importer or evidence. Changed facts/policy or\nsource-version reuse conflicts. Ordinary/generated model writes and deletion\ncannot mutate these immutable records. Provider synchronization and new revenue\nrecognition reject historical authority until an explicit supported historical\naccounting representation is supplied; exact original money is still readable.\n\nFocused evidence covers source/header immutability, concrete children, original\ncash/credit/refund chronology, conservation, CAD journals for new movements,\ncaller rollback and isolated PostgreSQL execution. Consumer historical adapters\nmust still map every source table and prove full-cohort reconciliation; adopting\nthese public facts alone is not full reference-import acceptance.\n\nCurrent explicitly dated retention releases append after the immutable original\nrelease prefix. Both remain readable without changing original dates or source\nauthority; replay binds the explicit date and caller rollback restores the\ncomplete release history. Provider releases retain their effective date in the\ncanonical retention history as well as provider evidence. Shared SQLite and\nPostgreSQL retention suites verify reload, exact retry, original-prefix tamper\nrefusal, and transactional rollback.\n\nHistorical cash allocations are validated as dated payment prefixes, independent\nof source import order. Backdated insertion rechecks later application dates;\nordinary public allocations retain their canonical allocatedAt chronology.\nSame-day credit ordering remains explicit. Later credits alone do not\nretroactively invalidate cash received before their issue date.\n\nCurrent `releaseInvoiceRetention` commands retain optional `sameDayCreditOrder`\nin their immutable evidence, alongside the effective calendar date. An exact\nretry must preserve that ordering; changing or removing it is a changed request.\nA later original credit import on the release date uses the retained ordering:\n`release-before-credit` releases first, while `credit-before-release` applies\nthe retained-first credit before checking remaining release capacity. Missing\nordering remains ambiguous and is refused rather than inferred from record time.\n### Bounded historical report scope\n\nHistorical header and tax reports apply the explicit tenant, historical money\nauthority, inclusive issue-date period, optional currency, and non-draft/non-cancelled\nstatus predicates in the collection query before enforcing the 100,000-document\nscope limit. Unrelated archived invoices do not consume a smaller report's limit;\nmore than 100,000 matching documents is refused rather than truncated.\n\nRegression design (#4063, PR #4101 comment 4300513731):\n\n| Invariant / trigger | Positive / refusal | Actor and executor | Runtime / evidence |\n| --- | --- | --- | --- |\n| Small matching period in a large tenant archive | Query-boundary fixture returns the single matching row only when all predicates precede the limit; matching scope above the cap still refuses | Explicit tenant and caller database; reads only | Focused Vitest; sparse overflow result avoids creating an archive |\n| Native collection scope | Exact inclusive boundaries, optional currency, historical authority and tenant isolation; draft/cancelled excluded | Active tenant, native test database | Focused SQLite and isolated PostgreSQL public historical-money + report proof |\n\nNo persistence behavior changes; rollback/retry and external-provider edges are\nnot applicable to this read-only query correction. The coordinator owns broader\ncohort validation and exact-head review under the resumed four-comment batch.\n\nEvidence on Node26/pnpm11.25.0: the focused archive-query regression failed against\n78f3ac856 (two failures, one pass), then passed after this query fix. The standard\n`node scripts/run-with-ci-postgres.mjs -- pnpm --filter @happyvertical/smrt-commerce exec vitest run src/__tests__/historical-sales-report-scope.test.ts src/__tests__/historical-sales-report-scope-native.test.ts`\nproof passed all five cases in9.80seconds, including actual SQLite and isolated\nPostgreSQL scope/tenant checks. No100,000-row fixture, production writes or schema\nchanges were needed. Full logs remain external at the2026-10-16 MVP session's\n`nonfinancial-import/scoped-sales-regression-base.log`, `scoped-sales-focused.log`\nand `scoped-sales-postgres.log`. Native token usage was unavailable.\n"
|
|
21468
|
+
},
|
|
19739
21469
|
{
|
|
19740
21470
|
"path": "agents/payment-allocations.md",
|
|
19741
21471
|
"module": "payment-allocations",
|
|
19742
|
-
"content": "# Payment allocation integrity\n\n`PaymentAllocation.save()` owns the financial boundary for every direct or\ncollection write. Both payment and invoice must exist, belong to the same\nexact tenant (global is distinct), have the same customer and currency, and\nhave room for the positive safe-integer minor-unit amount. Zero-total invoices\nhave no room. Missing or zero-total invoice fixtures no longer bypass the cap.\nPending payments remain allocatable; this command does not establish settlement\nproof. Generated REST/MCP/CLI allocation writes remain closed. Applications\nmust authorize the actor before invoking these backend commands.\n\nUse `PaymentAllocationCollection.allocatePayment({ paymentId, allocations,\nallocatedBy })` for a split. Each allocation is `{ id, invoiceId, amount }`, with\na caller-generated stable UUID retained across retries. Exact replay\nreuses the existing rows without applying money again; an existing id with\ndifferent parents or amount fails. Replay preserves an already-paid invoice's\nrecorded payment date. Reversing\npayment clears that date; reaching full payment again records the new date.\nThe complete batch and invoice payment-status refresh share one transaction. Invoices must\nalready be in a status that permits payment (normally SENT); WRITTEN_OFF retains\nits terminal status. A failed leg rolls back every leg and parent revision.\nDirect allocation saves continue to leave status refresh to the caller. Allocation\nwrites advance both parent revisions: reload a previously held parent with\n`await parent.loadFromId()` before applying later edits or status refresh.\nStale parent saves continue to fail the core revision guard; no implicit\nrevision refresh bypasses another editor. In-package billing follows this rule.\n\nOnce inserted, allocation tenant/payment/invoice identity is immutable. Amount\ncorrections are capped against the other allocations. Parent saves reject\nchanges to tenant, customer, currency or amount that would invalidate committed\nallocations. A payment may be increased or reduced to its allocated total;\ninvoice totals continue to derive from persisted invoice lines where present.\nStandalone payments remain saveable when allocation storage has not been\nprovisioned. An existing allocation table always participates in validation;\nstorage probes and permission errors propagate instead of disabling the guard.\n\nAll participating writes bind collections to the owning transaction executor.\nThey claim parent revisions before reading balances. Concurrent writers can\nreceive a revision conflict or database serialization failure; reload and retry\nthe complete transaction with the same allocation ids. Never retry only the\nlast leg inside an already failed transaction. PostgreSQL Repeatable Read\nsnapshots fail closed through the same revision writes. SQLite serializes the\nowning write transaction. DuckDB is not a supported commerce allocation store:\nthe existing declared foreign keys require ON UPDATE CASCADE, which its DDL\nboundary explicitly refuses; no weaker schema is substituted.\n\n### Undelivered invoice payment progress\n\nAllocation may move an undelivered DRAFT invoice to PARTIAL or PAID without a\ncustomer delivery event. Neither operation invents `sentAt` or `viewedAt`.\nAfter allocations are removed, reload the parent and call\n`updatePaymentStatus(remainingTotal)` and `save()` within the caller transaction.\nZero remaining allocations restore DRAFT only for an undelivered invoice;\na delivered invoice returns to SENT/VIEWED according to its delivery history.\nDRAFT cannot conceal positive allocations. A DRAFT save checks both its supplied\ndelivery timestamps and the currently persisted timestamps, so clearing them\nlocally during reversal cannot bypass the undelivered requirement. This guard\ndoes not introduce an immutable lifetime delivery-history record.\n\nIf a prepaid invoice is actually delivered later, call `markSent()` and save.\nFor PARTIAL/PAID invoices it records the first `sentAt` while preserving payment\nstatus, paid amount, paid date and any existing view timestamp. Repeating this\ncall preserves the first send timestamp. It records the caller's delivery\nevent; it does not send a customer message or manufacture earlier delivery.\n"
|
|
21472
|
+
"content": "# Payment allocation integrity\n\n`PaymentAllocation.save()` owns the financial boundary for every direct or\ncollection write. Both payment and invoice must exist, belong to the same\nexact tenant (global is distinct), have the same customer and currency, and\nhave room for the positive safe-integer minor-unit amount. Zero-total invoices\nhave no room. Missing or zero-total invoice fixtures no longer bypass the cap.\nPending payments remain allocatable; this command does not establish settlement\nproof. Generated REST/MCP/CLI allocation writes remain closed. Applications\nmust authorize the actor before invoking these backend commands.\n\nUse `PaymentAllocationCollection.allocatePayment({ paymentId, allocations,\nallocatedBy })` for a split. Each allocation is `{ id, invoiceId, amount }`, with\na caller-generated stable UUID retained across retries. Exact replay\nreuses the existing rows without applying money again; an existing id with\ndifferent parents or amount fails. Replay preserves an already-paid invoice's\nrecorded payment date. Reversing\npayment clears that date; reaching full payment again records the new date.\nThe complete batch and invoice payment-status refresh share one transaction. Invoices must\nalready be in a status that permits payment (normally SENT); WRITTEN_OFF retains\nits terminal status. A failed leg rolls back every leg and parent revision.\nDirect allocation saves continue to leave status refresh to the caller. Allocation\nwrites advance both parent revisions: reload a previously held parent with\n`await parent.loadFromId()` before applying later edits or status refresh.\nStale parent saves continue to fail the core revision guard; no implicit\nrevision refresh bypasses another editor. In-package billing follows this rule.\n\nOnce inserted, allocation tenant/payment/invoice identity is immutable. Amount\ncorrections are capped against the other allocations. Parent saves reject\nchanges to tenant, customer, currency or amount that would invalidate committed\nallocations. A payment may be increased or reduced to its allocated total;\ninvoice totals continue to derive from persisted invoice lines where present.\nStandalone payments remain saveable when allocation storage has not been\nprovisioned. An existing allocation table always participates in validation;\nstorage probes and permission errors propagate instead of disabling the guard.\n\nAll participating writes bind collections to the owning transaction executor.\nThey claim parent revisions before reading balances. Concurrent writers can\nreceive a revision conflict or database serialization failure; reload and retry\nthe complete transaction with the same allocation ids. Never retry only the\nlast leg inside an already failed transaction. PostgreSQL Repeatable Read\nsnapshots fail closed through the same revision writes. SQLite serializes the\nowning write transaction. DuckDB is not a supported commerce allocation store:\nthe existing declared foreign keys require ON UPDATE CASCADE, which its DDL\nboundary explicitly refuses; no weaker schema is substituted.\n\n### Undelivered invoice payment progress\n\nAllocation may move an undelivered DRAFT invoice to PARTIAL or PAID without a\ncustomer delivery event. Neither operation invents `sentAt` or `viewedAt`.\nAfter allocations are removed, reload the parent and call\n`updatePaymentStatus(remainingTotal)` and `save()` within the caller transaction.\nZero remaining allocations restore DRAFT only for an undelivered invoice;\na delivered invoice returns to SENT/VIEWED according to its delivery history.\nDRAFT cannot conceal positive allocations. A DRAFT save checks both its supplied\ndelivery timestamps and the currently persisted timestamps, so clearing them\nlocally during reversal cannot bypass the undelivered requirement. This guard\ndoes not introduce an immutable lifetime delivery-history record.\n\nIf a prepaid invoice is actually delivered later, call `markSent()` and save.\nFor PARTIAL/PAID invoices it records the first `sentAt` while preserving payment\nstatus, paid amount, paid date and any existing view timestamp. Repeating this\ncall preserves the first send timestamp. It records the caller's delivery\nevent; it does not send a customer message or manufacture earlier delivery.\n\n\n## Original settlement dates (#4099)\n\n`Payment.recordPayment` and `recordRefund` accept optional `effectiveOn`, a strict\nreal `YYYY-MM-DD` calendar date. Explicit dates set the posted journal and `paidAt`\nto noon UTC on that date; omission preserves current-clock ordinary posting.\nCustomer-funds commands retain their reviewed date and reject a conflicting\nexplicit override. Recording cash evidence does not initiate a provider transfer.\nCompleted or refunded payment settlement dates and journal identities are immutable,\nincluding direct save; correcting evidence requires an explicit reversal workflow.\nPosting retains the caller transaction and rejects duplicate completion.\n\nValidation: shared payment-posting contracts and customer-funds proofs pass on\nSQLite and PostgreSQL (55 passed, one PostgreSQL-only case skipped in the SQLite\nlane). They cover leap-day settlement, malformed/impossible dates, immutable\nreloads, duplicate posting, rollback, concurrency and conflicting managed dates.\nPackage typecheck/Svelte check (zero errors/warnings) and build pass. Initial\nfailures retained in the MVP evidence identified the missing direct-save date\nfreeze and an order-dependent journal assertion; both were corrected.\n\n## Allocation deletion versus retained-refund reservation (#4063 / PR #4101)\n\nDeletion claims the persisted Payment revision in its owning transaction before\nchecking provider or customer-funds authority. It holds that revision through the\nallocation DELETE. A retained-refund reservation uses the same Payment revision\nclaim when saving its binding, so a stale unbound parent read cannot authorize\nremoval after the provider reservation commits. If deletion commits first, the\nprovider reservation must fail its stale Payment claim before provider I/O.\nOrdinary deletion advances the Payment revision; reload held Payment instances\nbefore subsequent edits. Invoice status refresh remains caller-owned.\n\nThe accepted review fix is high risk because concurrent deletion could remove\nsettlement evidence already reserved by an external accounting operation. No API,\nschema, accounting mapping or bank execution contract changes.\n\n| Behavior / reachable trigger | Positive / negative case | Actor / executor / runtime | External edge / focused evidence |\n| --- | --- | --- | --- |\n| Direct allocation deletion | Ordinary unbound row deletes; failed outer transaction preserves row and parent revision | Active owning tenant; one caller transaction; SQLite and PostgreSQL | No bank I/O; dedicated allocation-delete suite |\n| Existing provider binding | Protected row remains and rejected delete rolls back parent revision; foreign tenant cannot delete | Owning versus foreign active tenant; transaction-bound parent claim; both dialects | Public retained-refund sync plus immutable binding readback |\n| Claimed deletion commits first | Provider reservation reaches its Payment revision claim, then fails without binding, refund reservation or provider I/O | Separate native PostgreSQL transactions; deterministic claim barriers | Public refund operation fails closed after its stale settlement evidence is removed |\n| Stale unbound parent read | Provider reservation commits while delete is paused, then stale delete fails and exact allocation remains | Separate native PostgreSQL transactions; deterministic read barrier | Real public provider saga with fake provider port; exact retry creates no extra provider operation |\n\nThe PostgreSQL concurrency interleaving is intentionally not run on SQLite:\nSQLite serializes the owning write transaction instead of allowing PostgreSQL's\nstale-read interleaving. Shared mutation/rollback/tenant/binding cases run on both.\nThe dedicated native test must fail against the pre-fix implementation before\nclaiming regression coverage. External outcome recovery and malformed provider\ninputs are unchanged and covered by the retained-accounting suite; no new provider\nrequest shape is introduced here.\n\nFocused validation: the dedicated SQLite/PostgreSQL test file passes all four\ncases; both PostgreSQL races use real independent transactions and explicit\nmethod barriers, without sleeps or mocked database results. The stale deletion\ncase fails against the unchanged base because deletion succeeds after provider\nreservation. Existing SQLite allocation-integrity and customer-funds suites also\npass (19 cases), including the managed reversal caller. Scoped model/test\nTypeScript passes. Run the dedicated PostgreSQL proof with the standard managed\n`run-with-ci-postgres.mjs` wrapper; it creates and cleans its own database.\n"
|
|
19743
21473
|
},
|
|
19744
21474
|
{
|
|
19745
21475
|
"path": "agents/tax-codes.md",
|
|
@@ -19759,17 +21489,17 @@
|
|
|
19759
21489
|
{
|
|
19760
21490
|
"path": "agents/contract-money.md",
|
|
19761
21491
|
"module": "contract-money",
|
|
19762
|
-
"content": "# Contract money persistence\n\nContract money runs through `contract-money.ts`. A tenant operation enters\n`withTenantMoneyRuntime` before it locks and reloads its Contract and sibling\nlines on the scoped executor, resolves tax codes, and replaces the Contract\naggregate plus `DocumentTax` rows in the same transaction. Every Contract money\nwrite needs a tenant, and a tenant whose data needs the upgrade is refused (see\n[money data upgrade](money-upgrade.md)).\n\nDraft Contract line writes recompute every sibling. `subtotal` is tax-exclusive\nnet after discount, `taxAmount` is the component total, and `totalAmount` is\ntheir exact sum. Purchase component tax is recoverable only when the frozen\ncomponent says so. A Contract leaving draft snapshots registrations, party tax\nidentity, per-line component amounts, and `moneySnapshotId`; later money edits\nare refused with `FROZEN_DOCUMENT`.\n\n`SupplierQuote` uses purchase defaults and recoverability. Non-draft quotes\nfreeze just like other Contracts, but quote snapshots (including custom\ndescendants) are excluded by their hydrated STI subtype, not the mutable\n`contractType` scalar, from report candidates and purchase tax facts. Awarding\nrequires a separate PurchaseOrder.\n"
|
|
21492
|
+
"content": "# Contract money persistence\n\nContract money runs through `contract-money.ts`. A tenant operation enters\n`withTenantMoneyRuntime` before it locks and reloads its Contract and sibling\nlines on the scoped executor, resolves tax codes, and replaces the Contract\naggregate plus `DocumentTax` rows in the same transaction. Every Contract money\nwrite needs a tenant, and a tenant whose data needs the upgrade is refused (see\n[money data upgrade](money-upgrade.md)).\n\nDraft Contract line writes recompute every sibling. `subtotal` is tax-exclusive\nnet after discount, `taxAmount` is the component total, and `totalAmount` is\ntheir exact sum. Purchase component tax is recoverable only when the frozen\ncomponent says so. A Contract leaving draft snapshots registrations, party tax\nidentity, per-line component amounts, and `moneySnapshotId`; later money edits\nare refused with `FROZEN_DOCUMENT`.\n\n`SupplierQuote` uses purchase defaults and recoverability. Non-draft quotes\nfreeze just like other Contracts, but quote snapshots (including custom\ndescendants) are excluded by their hydrated STI subtype, not the mutable\n`contractType` scalar, from report candidates and purchase tax facts. Awarding\nrequires a separate PurchaseOrder.\n\n## Received supplier monetary evidence\n\n`recordReceivedPurchaseMoney({ db, tenantId, contractId, requestId, evidenceRef,\nfacts, sourceQuote? })` records declared money on an existing empty draft\n`SupplierQuote` or `PurchaseOrder`. Authorize the human in the host first and\ncall inside its active tenant context. The command locks tenant settings and\nthe document on its transaction executor; an outer transaction can include\ncreation of the quote/order. It returns a `ReceivedPurchaseMoneySnapshot`;\n`getReceivedPurchaseMoney(contract)` returns that validated snapshot or `null`\nfor calculated documents. The public command is not an unguarded MCP action.\n\n```ts\nawait recordReceivedPurchaseMoney({\n db, tenantId, contractId: quote.id, requestId: 'received-revision-1',\n evidenceRef: 'supplier-document:revision-1',\n facts: {\n currency: 'CAD', netMinor: 10000, taxMinor: 537, grossMinor: 10537,\n taxComponents: null,\n detail: { kind: 'header-only' },\n },\n});\n// Reload after the command; stale instances cannot overwrite its authority.\nconst received = await contracts.get({ id: quote.id }, { cache: false });\nreceived.status = ContractStatus.ACCEPTED;\nawait received.save();\n```\n\nThis sets `moneyAuthority='received'`; aggregate headers retain exactly\n10000/537/10537 without guessing a tax rate. The default `calculated` mode and\nits line/tax-code calculator are unchanged. Received facts become immutable\nwhen recorded. Exact retries return the original snapshot even after acceptance;\nchanged requests need a new document revision. Direct authority/evidence writes,\nheader edits, calculated lines, party/type changes and deleting received history\nare rejected. Acceptance sets the normal `moneySnapshotId` without recalculating\nsource amounts. A stable application quote identity may reference a distinct\ncanonical `SupplierQuote` for each immutable revision.\n\n`detail` must explicitly be `header-only` or `lines`. The latter supplies complete\nsource `netMinor`, `taxMinor`, `grossMinor` per uniquely keyed line with exact\naggregate reconciliation. Optional `quantityText`/`unitRateText` retain original\ndecimal text, never drive recomputation. When source lines are incomplete, retain\nthem in the referenced source evidence and use header-only monetary facts; do\nnot invent `ContractLineItem` quantities, tax lines, or allocations.\n\n`taxComponents:null` means unknown decomposition. `[]` means known zero tax,\nwhich requires `taxMinor:0`, but does not classify that zero as exempt/zero-rated.\nEach supplied component retains its source key, label, amount, explicit\n`classification` (`taxable`, `zero-rated`, `exempt`, `out-of-scope`, or `null`)\nand `recoverableMinor` (including explicit zero or unknown `null`). Optional\n`taxCodeId`, `taxComponentId` and `taxableMinor` remain unknown when omitted. Values are exact\nsafe nonnegative minor units; sums use integer arithmetic. No recoverability,\nrate, taxable basis or classification is inferred from a label or amount.\n\nAn order can include\n`sourceQuote:{contractId,relationship:'copy'|'negotiated'}`. The quote must be\naccepted, frozen, received, and match tenant/vendor/currency. `copy` requires\nidentical facts. `negotiated` requires separately supplied approved monetary\nfacts and a separate evidence reference; it never prorates a quote. The command\nrecords lineage but does not manufacture acceptance or financial approvals.\n\nReceived SupplierQuotes remain excluded from incurred purchase-tax reporting.\nPurchaseOrders retain their existing report eligibility. For a received order,\npublic document report facts project explicit source amounts without creating\ncalculated `DocumentTax` rows or fictitious rates. Each report component must\nhave an explicit classification, tenant-owned tax code, taxable basis, recoverable amount and, for\n`taxable`, a tenant-owned `taxComponentId`. Missing facts raise\n`ReceivedPurchaseTaxClassificationRequired` with code\n`RECEIVED_PURCHASE_TAX_CLASSIFICATION_REQUIRED` and the affected order ID. This\nblocks only a report whose tenant/date/currency window includes that order;\nrecording, accepting and awarding unknown-classification evidence remains valid.\nExisting calculated PO reporting is unchanged. Correct classification through an\nexplicit reviewed replacement revision and cancellation of the superseded\nreport-eligible order, preserving its history; never rewrite frozen evidence or\nsilently omit the unknown order from a report.\n\nThe two added Contract fields use the normal generated schema/migration flow;\napply the generated migration before using the new public command on an existing\ndatabase. Native SQLite/PostgreSQL acceptance is in\n`received-purchase-money.test.ts` / `received-purchase-money.optional.test.ts`.\nDuckDB retains the existing unsupported native Contract foreign-key boundary.\n"
|
|
19763
21493
|
},
|
|
19764
21494
|
{
|
|
19765
21495
|
"path": "agents/money-model.md",
|
|
19766
21496
|
"module": "money-model",
|
|
19767
|
-
"content": "# Commercial money model\n\nThis guide names the public commerce money contract. The exact input and result\nshapes, validation codes, and worked calculator examples live in the\n[calculator guide](money-calculator.md) and\n[package documentation](../../../docs/content/commerce-money.md). Money values\nare signed safe-integer minor units; calculator tax percentages are exact text,\nso `'5'` means 5%. The `InvoiceLineItem.taxRate` and\n`ContractLineItem.taxRate` fields are server-derived fractions of the resolved\ncomponents (`0.05` means 5%); they are never tax inputs.\n\n## Calculation contract\n\n`calculateMoneyDocument()` accepts `exclusive`, `inclusive`, and `none` line\namount modes. It first computes quantity times unit price, applies the one\nchosen discount, and returns the post-discount amount, tax components, net, and\nline total. `exclusive` line amounts are tax-exclusive net; `inclusive` line\namounts are the visible gross and derive net by removing tax; `none` has zero\ntax and requires an out-of-scope code. `subtotalMinor`, `taxMinor`, and\n`totalMinor` are document totals. `discountTotalMinor` is informational because\nthe line discounts were already applied; consumers must not subtract it again.\n\nThe `line` rounding scope rounds each line/component. The `document` scope\nrounds each shared component's exact total, truncates each allocation toward\nzero, and gives signed residual minor units to the largest remainders, with\nline-ID code-unit order breaking ties. It leaves no document residual. Across\n`n` small lines, the two scopes can differ by up to `ceil(n / 2)` minor units\nper component. Store the chosen scope; do not silently substitute a later\nsetting. `MoneyValidationError.code` is the public branch point for invalid\nmoney, discounts, tax-code state and scope,
|
|
21497
|
+
"content": "# Commercial money model\n\nThis guide names the public commerce money contract. The exact input and result\nshapes, validation codes, and worked calculator examples live in the\n[calculator guide](money-calculator.md) and\n[package documentation](../../../docs/content/commerce-money.md). Money values\nare signed safe-integer minor units; calculator tax percentages are exact text,\nso `'5'` means 5%. The `InvoiceLineItem.taxRate` and\n`ContractLineItem.taxRate` fields are server-derived fractions of the resolved\ncomponents (`0.05` means 5%); they are never tax inputs.\n\n## Calculation contract\n\n`calculateMoneyDocument()` accepts `exclusive`, `inclusive`, and `none` line\namount modes. It first computes quantity times unit price, applies the one\nchosen discount, and returns the post-discount amount, tax components, net, and\nline total. `exclusive` line amounts are tax-exclusive net; `inclusive` line\namounts are the visible gross and derive net by removing tax; `none` has zero\ntax and requires an out-of-scope code. `subtotalMinor`, `taxMinor`, and\n`totalMinor` are document totals. `discountTotalMinor` is informational because\nthe line discounts were already applied; consumers must not subtract it again.\n\nThe `line` rounding scope rounds each line/component. The `document` scope\nrounds each shared component's exact total, truncates each allocation toward\nzero, and gives signed residual minor units to the largest remainders, with\nline-ID code-unit order breaking ties. It leaves no document residual. Across\n`n` small lines, the two scopes can differ by up to `ceil(n / 2)` minor units\nper component. Store the chosen scope; do not silently substitute a later\nsetting. `MoneyValidationError.code` is the public branch point for invalid\nmoney, discounts, tax-code state and scope, contradictory compound dependencies, frozen\nrecords, and unsafe values.\n\nTax-code resolution is pure once the caller has loaded authorized codes. It\nuses a line override, customer exemption, product code, customer code, and app\ndefault in that order. An unresolved exclusive or inclusive line is a genuine\nzero-tax, null-code case; it is not an out-of-scope inference. The tax-code\ncatalogue, seeds, registrations, and cookbook boundary are documented in\n[tax codes](tax-codes.md).\n\n## Stored Invoice facts\n\nThere is one money model. Saving a draft resolves its current tax settings\nonce and atomically writes the header, line snapshots, and `DocumentTax` rows.\nEvery money document needs a tenant, and data written by an earlier version is\nrefused until it is upgraded ([money data upgrade](money-upgrade.md)). The detailed persistence, freeze, preview, credit-note, and\nrefund contracts are in [document money](document-money.md).\n\nOnce an Invoice leaves `DRAFT`, or receives an AR journal, its money snapshot\nis frozen. Reads use those stored values and must not recompute issued tax from\nnew defaults. `DocumentTax` is a derived, read-only per-document/code/component\nsnapshot with currency, code and component identities and labels, kind, exact\npercent, liability account, taxable, tax, and recoverable minor-unit values.\nIt also represents non-taxable and unassigned zero-tax rows so reporting does\nnot invent a taxable component.\n\nA credit note is an `Invoice` with `kind: 'credit_note'`. It stores positive\namounts; posting, reporting, and accounting adapters apply that direction once.\nIssued-credit capacity and refunds are stable Invoice behavior. A refund is\na positive `Payment` of kind `refund`, allocated only to a credit note. See\n[document money](document-money.md) before presenting either balance as an\nordinary incoming payment.\n\n## Invoice MCP `get` projection\n\nThe standard Invoice MCP `get` tool uses `serializeInvoiceMcpGet`. For a\ntenant invoice, the optional `money` value is the stored `InvoiceMoneyFacts`\nprojection: its header, line snapshots, and `DocumentTax` facts are read from\nthe stored snapshot and are never recalculated. An invoice without an id or\ntenant returns the ordinary public Invoice projection.\n\nA tenant whose data needs the upgrade refuses this read with\n`COMMERCE_DATA_NEEDS_UPGRADE`. If the caller's `PublicJsonOptions` hide any Invoice,\n`InvoiceLineItem`, or `DocumentTax` field needed by the money projection, the\nserializer returns the base Invoice and omits the entire `money` alias. It does\nnot expose restricted values through a partial plain-object alias.\n\nThis applies only to standard MCP `get`. Invoice list and MCP write behavior\nremain their existing public contracts. The general serializer configuration,\nauthorization order, and projection rule are in [core MCP get\nserializers](../../core/agents/generators.md#mcp-get-serializers).\n\n## Reporting and integrations\n\nThe materialized `TaxSummaryReport` and its public descriptor/drilldown bridge\nread stored Invoice `DocumentTax` facts under the tenant money lock. See\n[tax summary aggregation](tax-summary.md). Commerce exports\n`createTaxSummaryMaterializedReportHost()` for an application-owned,\nserver-only host; register that host in the app's fixed report-host registry to\nopt into the generic `MaterializedReportTable` and its tenant-scoped drilldown\nroute. The host binds the authenticated tenant, principal, and\n`taxsummaryreports.read` permission; browser input supplies only a row id\nand visible column id.\n\nThe accounting snapshot mapper consumes frozen facts and never re-calculates a\nrate or allocation. It maps an inclusive line to the accounting SDK's\n`TaxInclusiveAmt`; tenant mappings provide provider tax-code and component-rate\nidentities. The QuickBooks sync boundary persists SDK 0.103.7 invoice or credit\nmemo request descriptors before provider I/O, refuses competing writes, and\nrequires explicit reconciliation after an unknown outcome. Its supported\ninputs and recovery contract are documented in [accounting snapshot\nmapper](accounting-snapshot-mapper.md).\n\n## Deliberate boundaries\n\nUpgrading data written by an earlier version is documented in\n[money data upgrade](money-upgrade.md). Contract money persistence remains a separate aggregate contract; production report\nhosting is an application opt-in over the public host described above. The\nmodel also does not provide currency conversion or general cash-basis accounting,\npartial recoverability or period locking. Ordered compound taxes are supported as\ndocumented in [money calculator](money-calculator.md). Explicit invoice-tax-point\ncustomer deposits and unallocated cash are provided by the separate\n[customer-funds authority](customer-funds.md), not by invoice pricing.\n"
|
|
19768
21498
|
},
|
|
19769
21499
|
{
|
|
19770
21500
|
"path": "agents/money-calculator.md",
|
|
19771
21501
|
"module": "money-calculator",
|
|
19772
|
-
"content": "# Money calculator\n\n`src/money.ts` is the Svelte-free authority for commercial document arithmetic.\nImport it from `@happyvertical/smrt-commerce/money` (or the package root).\n\n- Inputs are signed safe-integer minor units. Quantity and percent values have at\n most six decimal places; calculations use exact `BigInt` rationals and round\n half away from zero. Currency must be a supported ISO 4217 code with a defined\n minor unit; the exponent validates the document currency but does not rescale\n already-minor-unit inputs.\n- `lineAmountType` is `exclusive`, `inclusive`, or `none`. Inclusive `amountMinor`\n is the customer-visible gross; `netMinor = amountMinor - taxMinor`.\n- `roundingScope: 'line'` rounds each line/component. `document` rounds the exact\n sum for each shared component, then allocates from truncation toward zero by\n signed largest remainder. Ties use code-unit line ID order, so input order does\n not affect allocation. The residual's sign, including mixed signed lines, is\n authoritative.\n- `taxes` is split by tax code and component for persistence. Shared components\n are rounded across codes at document scope. Non-taxable codes use a null\n component row with zero tax and taxable minor units equal to summed line net.\n A genuinely unassigned exclusive/inclusive line uses `taxCode: null` and emits\n `{ taxCodeId: null, taxComponentId: null }`; no synthetic ID is persisted.\n- Resolve already-loaded codes with `resolveLineTaxCode()`. `none` mode always\n chooses the supplied out-of-scope code before an override. Active/scope checks\n happen during resolution; issued snapshots are not passed back through it.\n Missing exempt/out-of-scope seeds fail closed and never fall through to a\n taxable default.\n- Discounts are either percent or signed minor units. An amount discount carries\n the gross sign. Editors may accept a positive magnitude, then apply the sign.\n\nAll business rejections use `MoneyValidationError`. The stable tax-code shape\ncodes include `TAX_CODE_DUPLICATE_COMPONENT`,\n`TAX_CODE_NON_TAXABLE_COMPONENTS`, and `TAX_CODE_TAXABLE_EMPTY`, in addition to\n`TAX_CODE_NOT_FOUND`, `TAX_CODE_KIND`, `TAX_COMPONENT_RATE_CONFLICT`, and the\nshared input, discount, percent, compound, state, scope, safety, freeze, and\ncurrency codes exported as `MoneyValidationCode`.\n\n`calculateInvoiceMinorLine(input)` in `src/svelte/invoices/calculations.ts`\n(also exported from `@happyvertical/smrt-commerce/invoices`) runs one line\nthrough this calculator with a single-component code built from its resolved\nfraction. It takes no options. Its discount is signed minor units and passes\nthrough unchanged, and its ties round half away from zero for negative\nlines too. Editor magnitude normalization happens before constructing that\ninput. See [invoice line calculation](invoice-calculations.md).\n"
|
|
21502
|
+
"content": "# Money calculator\n\n`src/money.ts` is the Svelte-free authority for commercial document arithmetic.\nImport it from `@happyvertical/smrt-commerce/money` (or the package root).\n\n- Inputs are signed safe-integer minor units. Quantity and percent values have at\n most six decimal places; calculations use exact `BigInt` rationals and round\n half away from zero. Currency must be a supported ISO 4217 code with a defined\n minor unit; the exponent validates the document currency but does not rescale\n already-minor-unit inputs.\n- `lineAmountType` is `exclusive`, `inclusive`, or `none`. Inclusive `amountMinor`\n is the customer-visible gross; `netMinor = amountMinor - taxMinor`.\n- `roundingScope: 'line'` rounds each line/component. `document` rounds the exact\n sum for each shared component, then allocates from truncation toward zero by\n signed largest remainder. Ties use code-unit line ID order, so input order does\n not affect allocation. The residual's sign, including mixed signed lines, is\n authoritative.\n- `taxes` is split by tax code and component for persistence. Shared components\n are rounded across codes at document scope. Non-taxable codes use a null\n component row with zero tax and taxable minor units equal to summed line net.\n A genuinely unassigned exclusive/inclusive line uses `taxCode: null` and emits\n `{ taxCodeId: null, taxComponentId: null }`; no synthetic ID is persisted.\n- Resolve already-loaded codes with `resolveLineTaxCode()`. `none` mode always\n chooses the supplied out-of-scope code before an override. Active/scope checks\n happen during resolution; issued snapshots are not passed back through it.\n Missing exempt/out-of-scope seeds fail closed and never fall through to a\n taxable default.\n- Discounts are either percent or signed minor units. An amount discount carries\n the gross sign. Editors may accept a positive magnitude, then apply the sign.\n\nAll business rejections use `MoneyValidationError`. The stable tax-code shape\ncodes include `TAX_CODE_DUPLICATE_COMPONENT`,\n`TAX_CODE_NON_TAXABLE_COMPONENTS`, and `TAX_CODE_TAXABLE_EMPTY`, in addition to\n`TAX_CODE_NOT_FOUND`, `TAX_CODE_KIND`, `TAX_COMPONENT_RATE_CONFLICT`, and the\nshared input, discount, percent, compound, state, scope, safety, freeze, and\ncurrency codes exported as `MoneyValidationCode`.\n\n`calculateInvoiceMinorLine(input)` in `src/svelte/invoices/calculations.ts`\n(also exported from `@happyvertical/smrt-commerce/invoices`) runs one line\nthrough this calculator with a single-component code built from its resolved\nfraction. It takes no options. Its discount is signed minor units and passes\nthrough unchanged, and its ties round half away from zero for negative\nlines too. Editor magnitude normalization happens before constructing that\ninput. See [invoice line calculation](invoice-calculations.md).\n\n## Ordered compound taxes\n\n`TaxComponentInput.compound: true` uses every preceding component in the same\nordered tax code. Different applicable line/category subsets use different codes;\nno missing predecessor is invented. Exclusive and explicit-net credit inputs use\nprior rounded taxes at line scope or prior allocated taxes at document scope.\nShared components retain one rate. Contradictory dependency orders across codes\nfail with `TAX_COMPONENT_DEPENDENCY_CYCLE`.\n\nInclusive extraction computes exact ordered rational factors, then rounds or\nallocates the extracted component taxes. Net is the gross-minus-tax residual.\nThis is not a promise that an inclusive extraction reverses an exclusive rounded\ncalculation penny-for-penny. Signed reversals use the same symmetric rules.\n\nCompound result components and frozen line snapshots carry `compound: true` and\n`taxableMinor`. Component tax rows preserve this actual basis, with `netMinor`\nseparate so kind/revenue summaries do not include tax-on-tax as net revenue.\nHistorical additive snapshots omit these optional fields. Credits reconstruct the\nfrozen ordered components; a final credit consumes the remaining frozen bases and\ntaxes. The compatibility line `taxRate` is the observed effective tax/net ratio\nfor compound lines, not a flattened statutory rate; never use it to reconstruct\na document. Use component snapshots and canonical minor-unit totals.\n\n`DocumentTax.netMinor` is a nullable generated-schema field. Additive records use\nnull and retain their previous reporting shape. Upgrade schemas before projecting\nreports. Received purchase components may declare a taxable basis above net;\nwhen that occurs their explicit `netMinor` is required for report classification.\nRecording evidence remains allowed without that classification.\n\nCompound accounting synchronization uses the public SDK ordered snapshot contract\n([SDK #1412](https://github.com/happyvertical/sdk/issues/1412)). The mapper preserves\noriginal rates, exact taxable bases and caller-verified realm TaxCode ordering.\nMissing or mismatched reviewed mapping still raises `ACCOUNTING_SYNC_UNSUPPORTED`.\nIt never substitutes a flattened rate. Deployment requires the SDK release that\ncontains this public contract; the prior additive-only SDK cannot accept it.\n"
|
|
19773
21503
|
},
|
|
19774
21504
|
{
|
|
19775
21505
|
"path": "agents/commercial-ui.md",
|
|
@@ -19790,6 +21520,26 @@
|
|
|
19790
21520
|
"path": "agents/cost-billing.md",
|
|
19791
21521
|
"module": "cost-billing",
|
|
19792
21522
|
"content": "# Exact cost billing\n\n`@happyvertical/smrt-commerce/cost-billing` is an independent, transport-neutral\nentry point without model, server or Svelte dependencies. It does not persist,\npost, authorize, select a currency/jurisdiction, or implement credit-note lifecycle.\nIt does not change Invoice calculations or the invoice editor; both use the\ncommerce money calculator, whose ties also round half away from zero. The\n`roundingScope: 'invoice'` behavior in this guide is a standalone cost-billing\nconvention; document arithmetic uses `roundingScope: 'document'` and stores\nallocated tax facts. See the [commercial money model](money-model.md) and\n[money calculator](money-calculator.md).\n\nCall `resolveCostMarkup(overrides)` with caller-approved precedence, most specific\nfirst. Each item has `source`, optional `policy` and `version`, and optional\n`percent`. The first defined percent wins, including `\"0\"`. At least one is\nrequired; even shadowed inputs are validated. The result contains the percent,\nselected index, and detached ordered provenance. Persist accepted snapshots in\nthe owning application; these helpers never reprice them automatically.\n\nCall `calculateCostBilling({ basisMinor, mode, markup })` with that result. Money\nis signed safe-integer minor units in a single caller-selected currency. The\nbasis is explicitly chosen by the caller (for example excluding recoverable tax).\n`reimbursement-plus-fee` returns principal once plus rounded fee; `fee-only`\nreturns only the fee; `nonbillable` and `fixed-contract` return zero charge.\nThe result includes `principalMinor`, `feeMinor`, `totalMinor`, and provenance.\nPercent strings use plain nonnegative decimal notation, range 0–100000 percent,\nat most six fractional places, without whitespace, exponent or leading zeroes.\nThe finite range and scale bound input parsing and arithmetic resource use; they\nare API limits, not tax or industry policy. Arithmetic uses BigInt intermediates and half-away-from-zero rounding. Invalid\ninputs, unknown modes, inconsistent provenance and unsafe outputs throw.\n\n`calculateCostBillingTax({ lines, rules, roundingScope })` accepts line\n`id`, signed `amountMinor`, and `category`; rules explicitly map every used\ncategory to `{ id, percent }` components. An empty component array explicitly\nmeans exempt. Components are additive, never compounded. Shared component IDs\nmust use equal rates across categories; distinct rate regimes need distinct IDs.\nThe caller owns taxable basis and jurisdiction mapping. Duplicate category,\ncomponent-within-category or line IDs fail closed. `line` scope rounds each\nline/component pair; `invoice` scope aggregates exact amounts per component and\nrounds once. Two 10-unit lines at 5 percent yield tax 2 versus 1 respectively.\nReturns `taxMinor` and component totals, deliberately without allocating rounded\ninvoice tax back to lines. Signed reversals use symmetric rounding, but mixed\npositive/negative lines may differ between rounding scopes.\n\n## Ordered compound tax with explicit allocation\n\n`calculateOrderedCostBillingTax` is a separate opt-in calculator on the same\nentry point. The additive calculator above, existing model/editor rounding and\nhistorical snapshots are unchanged. This helper neither infers regional rules\nnor persists policy. Applications must explicitly select approved tenant/regional\nsettings, preserve their accepted policy and result snapshots, and decide when a\nnew calculation is appropriate.\n\nSupply `lines` (`id`, signed safe-integer `amountMinor`, `category`), `categories`\n(`category`, `componentIds`) and ordered `components` (`id`, exact `percent`,\n`priorComponentIds`). Every component must explicitly supply `priorComponentIds`:\n`[]` means net-only; otherwise each ID must name a distinct earlier component.\nThe component basis on each eligible line is its net plus that line's allocated\ntax for exactly those prior components. A prior tax not applicable to that line\ncontributes zero. Category membership order does not control execution; the\nglobal component array does. A category's empty `componentIds` means exempt.\n\nChoose `roundingScope: 'line'` to round each eligible line/component pair\nhalf-away-from-zero. Invoice allocation options are forbidden in this mode,\nincluding an explicitly present `invoiceAllocation: undefined` property.\nChoose `roundingScope: 'invoice'` with the mandatory explicit\n`invoiceAllocation: 'signed-largest-remainder'` to round each component once\nover its eligible lines and distribute that rounded amount as follows:\n\n1. Calculate each eligible line's exact rational tax from its compound basis.\n2. Truncate each exact tax toward zero, retaining its signed fractional remainder.\n3. Round the exact component aggregate half-away-from-zero. Subtract the sum of\n truncated line taxes to obtain the signed residual.\n4. For positive residual, assign one extra minor unit to each of the lines with\n the largest signed remainders; for negative residual, subtract one unit from\n each line with the smallest (most negative) remainders. Stop when conserved.\n Ties use ascending JavaScript UTF-16 code-unit line ID order, never locale\n collation or input order. A zero residual leaves every truncated tax unchanged.\n\nThis allocation is a caller-selected arithmetic convention, not a jurisdiction\ndefault or independent per-line rounding. It supports mixed signs and exact full\nreversal: keeping the same IDs/policy and negating all amounts negates every\nreturned basis and allocation. An individual line's allocation can change when\nother lines change; independently recalculating a subset or a partial reversal\ndoes not preserve the original invoice allocation. Consumers needing historical\npartial adjustments must use their accepted snapshot and explicit adjustment\npolicy. Mixed exact taxes `+0.8` and `-0.8` have zero aggregate and allocate\n`0, 0` under this convention.\n\nFor example, lines `a` and `b`, each net 10, both receive `first` at 5 percent.\nThe invoice tax is 1, allocated `a: 1, b: 0`. If only `a` receives `second` at\n100 percent with `priorComponentIds: ['first']`, its basis is 11 and its tax 11;\nthe total tax is 12. If only `b` receives `second`, its basis and tax are 10.\nNegating both original amounts allocates `first` as `a: -1, b: 0`; the second\ntax on `a` has basis and tax -11, total tax -12. At line scope the positive\nexample instead yields first tax 2 and total tax 13.\n\nThe result is `{ taxMinor, components }`. Components follow the supplied global\norder and each returns `{ id, taxMinor, lines }`, where eligible lines are\n`{ id, basisMinor, taxMinor }` in ascending code-unit ID order. Each component's\nline allocations sum exactly to its total. Components with no eligible lines\nreturn zero and `lines: []`; well-formed unused categories and components remain\nvalid for reusable policy. Exempt lines appear in no component allocation.\nRepeated calculations and input line/category/membership permutations produce\nidentical output. All arithmetic intermediates use BigInt; every returned basis,\nallocation, component tax and final tax must fit a safe integer, even when a\nlarger value would later cancel or a component has a zero rate.\n\nAll configuration is validated, including unused entries. Missing category\nmapping, unknown IDs, duplicate line/category/component/membership/prior IDs,\nforward/self references, missing arrays, malformed rates and unknown modes fail\nclosed. Rates use the same bounded decimal-string contract as the additive API.\nThe input is never mutated and the result holds no aliases to input objects.\n"
|
|
21523
|
+
},
|
|
21524
|
+
{
|
|
21525
|
+
"path": "agents/contract-billing-schedules.md",
|
|
21526
|
+
"module": "contract-billing-schedules",
|
|
21527
|
+
"content": "# Contract milestone billing (#4074)\n\nUse the public Commerce `approveContractBillingSchedule`,\n`issueContractMilestoneInvoice`, `getContractBillingSchedule` and\n`allocateContractMilestones` exports for fixed-value milestone billing. These\ncommands own monetary capacity. The host owns construction scope, estimated cost,\napproval permissions, signed evidence, regional policy and UI.\n\nStart with an accepted, frozen customer `Order` or `Agreement`. The first schedule\nrequires `amendmentMinor: 0`, `expectedRevision: 0`, currency, explicit `basis:\n'net' | 'gross'`, `approvalEvidenceRef`, `taxPolicyEvidenceRef` and exact milestone\n`{ key, label, amountMinor }` entries. Their sum must equal the original Contract\nsubtotal for net basis or totalAmount for gross basis. There is no editable\nschedule override of the accepted Contract value.\n\nEach amendment supplies the current expected revision, a new request identity,\nan explicit signed `amendmentMinor`, approval evidence and the complete next\nschedule. Its ceiling is derived from the original frozen value plus all approved\namendments. Currency/basis cannot change. Already issued milestone keys, labels\nand amounts must remain unchanged. Prior revisions and original Contract money\nremain immutable. Unissued milestones can be rescheduled through an explicitly\napproved revision. Net capacity is not a gross ceiling: each invoice's tax must\nalso be explicitly approved under the versioned policy.\n\n`allocateContractMilestones(totalMinor, weights)` accepts positive integer\nrelative weights. All nonfinal shares truncate exact rational arithmetic; the\nfinal entry receives the exact remainder. For example 100 with weights [1,1,1]\nreturns [33,33,34]. Zero amounts are allowed; negative/unsafe money and nonpositive\nweights reject. The helper chooses no tax policy or commercial percentages.\n\nPrepare a normal canonical draft Invoice and real line items through the public\nCommerce collections. Draft preparation consumes no capacity; an unissued draft may be cancelled\nwithout a claim. Then call:\n\n```ts\nconst claim = await issueContractMilestoneInvoice({\n db, tenantId, contractId, requestId: 'issue:start:v1',\n revision: 1, milestoneKey: 'start', invoiceId,\n approvedMoney: { netMinor: 4000, taxMinor: 200, grossMinor: 4200 },\n invoiceApprovalEvidenceRef: 'approved-invoice:123',\n});\n```\n\nThe command checks same tenant/customer/currency/Contract, derives current line\nmoney, verifies the exact approved net/tax/gross and schedule amount, freezes the\ninvoice and records the claim atomically. Tax-policy evidence is a host-owned\nreviewed version reference, not an instruction to infer tax rates. Preserve the\napproval's policy and original evidence in the host. Ordinary issue against a\nscheduled Contract is refused, including direct creation in a non-draft state.\nExisting issued contract invoices prevent adopting a schedule retroactively.\n\nThe explicit capacity policy is `issued-consumed`: cancellation, credits,\nwrite-offs, payments, retention and refunds never reopen a claimed milestone.\nCredits correct the canonical receivable and settlement continues through existing\nPayment/PaymentAllocation facilities. Unapplied payments remain the deposit cash\nauthority. A replacement billing entitlement requires an explicit approved\namendment; this API does not infer that a credit authorizes re-billing. Applications\nmust explain that policy rather than present a hidden re-bill action. Issued\nclaims remain readable after later amendments and cancellations.\n\nEvery mutation requires the active tenant context and uses the tenant money\nserialization barrier on the exact parent transaction executor. Identical request\nreplay returns the original evidence; a changed payload, stale revision or second\nclaim rejects. A parent rollback reverses both invoice issue and schedule claim.\nA detached read DTO cannot modify persisted state. Ordinary Contract writes and\ndeletes cannot erase schedule history. Host authorization precedes these commands;\nnone is exposed as an unauthenticated generated mutation.\n"
|
|
21528
|
+
},
|
|
21529
|
+
{
|
|
21530
|
+
"path": "agents/customer-funds.md",
|
|
21531
|
+
"module": "customer-funds",
|
|
21532
|
+
"content": "# Customer advances and unallocated cash\n\nThe public `recordCustomerFunds`, `allocateCustomerFunds`, `refundCustomerFunds`,\n`reverseCustomerFundsAllocation` and `getCustomerFundsFacts` commands reuse\nPayment, PaymentAllocation and smrt-ledgers journals. They do not create invoice\nrevenue, issue credit notes, transmit money to a bank or call a provider.\nApplications authorize each command and supply human/source evidence.\n\nA receipt requires an explicit immutable policy version:\n\n- `mode`: `unapplied-ar` or `deposit-liability`.\n- `taxTiming: 'invoice-tax-point'`: the caller has explicitly reviewed that tax\n belongs on the eventual invoice. This is the only supported timing. The API\n does not assume that every jurisdiction treats deposits as untaxed; other\n timing policies are rejected and need a separate supported accounting model.\n- `releaseEligibility`: `any-issued-invoice` or `final-invoice-only`.\n- Distinct cash and receivables asset accounts, plus a liability account only\n for liability mode. Every account must be active in the same tenant chart.\n\nLedgers currently has no separate Ledger entity or currency-restricted Account\nfield. The ledger boundary is its tenant-owned chart; currency is explicit on\nthis receipt and every journal entry. The legacy `RecordPaymentOptions.ledgerId`\nis unused by existing Payment settlement. These commands neither pretend it\nvalidates an independent ledger nor invent account metadata conventions.\n\n| Operation | Unapplied AR | Deposit liability |\n| --- | --- | --- |\n| Receipt | DR cash / CR AR | DR cash / CR customer liability |\n| Application | Existing settlement allocation | DR customer liability / CR AR |\n| Unallocated refund | DR AR / CR cash | DR customer liability / CR cash |\n| Application reversal | Reverse settlement allocation | DR AR / CR customer liability |\n\nAll amounts are positive safe integer minor units. Available capacity is exactly\n`received - active applications - settled source-linked refunds`. A refund is a\npositive outgoing Payment with immutable source-receipt lineage; it is not an\ninvoice credit refund. Reversal retains the original application and appends an\ninverse operation and journal, removing only the active settlement row. An issued\ninvoice credit or credit refund blocks application reversal so previously spent\ncash cannot become refundable a second time. Resolve that invoice correction\nthrough its own authority first.\n\nEach request carries `effectiveOn` (calendar date), `evidenceRef`, `actorId` and a\nstable `requestId`. Effective dates are distinct from recording timestamps and\nmust be chronological within a receipt's movements. Receipt/refund `paidAt` and\njournal dates use the explicitly supplied effective date. Exact replays return\ncurrent conserved facts; changing the request payload fails. Refund/application\nraces serialize on the tenant money boundary and receipt revision. Caller-owned\ntransactions include the payment, journals, allocation, status and audit evidence.\n\nApplication requires a matching issued invoice, customer, currency, optional\nsales contract and actual `moneySnapshotId`. `release` also names the frozen\nreceipt policy version and the host's immutable invoice-approval evidence. Under\nfinal-only policy, the host must verify and attest `kind: 'final-invoice'` from\nthat frozen approval. This is an application authorization responsibility, not a\nuser-supplied checkbox or inference from invoice numbering. The generic library\nchecks the attestation shape and exact canonical monetary snapshot; it does not\nknow construction milestone/finality rules.\n\n`Payment.customerFundsJson` is command-owned. Ordinary saves, deletes,\nPaymentAllocation create/update/delete, collection allocation helpers, payment\nintent settlement and supplier payouts cannot repurpose managed advances or\nbypass required journal entries. Managed refunds cannot be allocated to invoice\ncredits. `getUnallocatedFromPayment` subtracts managed refunds and requires the\npersisted receipt amount. Direct SQL and administrative ledger mutations remain\noutside this domain authority; facts refuse missing/voided journal evidence.\n\n```ts\nawait withTenant({ tenantId }, async () => {\n const received = await recordCustomerFunds({\n db, tenantId, customerId, currency: 'CAD', amountMinor: 10000,\n method: PaymentMethod.BANK_TRANSFER, requestId: receiptRequestId,\n effectiveOn: '2026-10-01', evidenceRef: bankReceiptRef, actorId,\n policy: {\n version: reviewedPolicyVersion, mode: 'deposit-liability',\n taxTiming: 'invoice-tax-point', releaseEligibility: 'final-invoice-only',\n cashAccountId, receivablesAccountId, liabilityAccountId,\n },\n });\n await allocateCustomerFunds({\n db, tenantId, paymentId: received.paymentId, invoiceId, amountMinor: 8000,\n requestId: applicationRequestId, effectiveOn: '2026-10-10',\n evidenceRef: applicationEvidenceRef, actorId,\n release: {\n kind: 'final-invoice', invoiceSnapshotId,\n approvalEvidenceRef: frozenFinalInvoiceApprovalRef,\n policyVersion: reviewedPolicyVersion,\n },\n });\n});\n```\n\nNative `customer-funds.test.ts` and `customer-funds.optional.test.ts` prove exact\njournals, both modes, direct-path protections, dates, finality evidence,\nconservation, invoice-credit interaction, retries, caller rollback and a real\nPostgreSQL post-journal write fault plus refund/application race. Run PostgreSQL\nthrough the standard managed database wrapper; never use an application's schema.\n"
|
|
21533
|
+
},
|
|
21534
|
+
{
|
|
21535
|
+
"path": "agents/observed-purchase-prices.md",
|
|
21536
|
+
"module": "observed-purchase-prices",
|
|
21537
|
+
"content": "# Incomplete observed purchase prices\n\n`recordPurchasePriceObservation` records a supplier quote or purchase-order source\ninstrument when the source does not establish every monetary total. Each of\n`netMinor`, `taxMinor`, and `grossMinor` is an explicit safe nonnegative integer\nor `null`. Zero is a known value; null is unknown. At least one amount is known.\nThe host explicitly interprets whether a source amount is net or gross. The\ncommand neither derives absent tax nor uses current tax rates.\n\nThe public `PurchasePriceObservation` is separate from `Contract`. Its readback\nhas `monetaryAggregate: null`, the complete original snapshot, and an optional\ncompletion link. It cannot appear in ordinary purchase tax reports or be\naccepted as a calculated Contract. Source `selected`, `approved`, or other\nstatus text remains original evidence and grants no current approval.\n\nSource identity is `(tenant, namespace, kind, sourceKey)`. Exact replay returns\nthe original object. Changed evidence or request identity requires a new source\nrevision; it cannot rewrite the original. Concrete source lines retain their\nkeys and exact quantity/rate text, even when those texts do not explain the\nsupplier's observed amount. They are evidence, not calculator inputs.\n\n`completePurchasePriceObservation` requires separate reviewed evidence and the\nexisting complete `ReceivedPurchaseMoneyFacts` contract. It preserves every\nknown original header amount and every fully known source-line total. When\ncomplete line detail is supplied, identities, descriptions, quantity/rate text,\nand known amounts must also match. Header-only completion does not allocate tax\nor invent source line amounts: the original lines remain in the observation.\nThe command atomically creates a **draft** received SupplierQuote or\nPurchaseOrder and appends its link. The host separately authorizes any later\nacceptance. This is completion of unknown facts, not a negotiated price change.\n\nAll commands require the matching active tenant. The host authorizes the human\noperation and supplies the owning executor. The tenant money barrier serializes\nrecording/completion and participates in caller rollback. Ordinary model saves,\ncollection creates, and deletes are rejected. No original journal or provider\nwrite is created. The existing received-purchase tax-classification requirements\napply if a completed purchase order is subsequently accepted and reported.\n"
|
|
21538
|
+
},
|
|
21539
|
+
{
|
|
21540
|
+
"path": "agents/received-sales-contract-money.md",
|
|
21541
|
+
"module": "received-sales-contract-money",
|
|
21542
|
+
"content": "# Received sales agreement money\n\n`recordReceivedSalesContractMoney({ db, tenantId, contractId, requestId,\nevidenceRef, facts })` records explicitly supplied complete original monetary\nfacts on an empty draft `Order` or `Agreement` with a same-tenant customer.\nIt reuses the public complete received-money validator: safe nonnegative minor\nunits, exact net plus tax equals gross, known zero distinct from unknown tax\nclassification, and either header-only evidence or real complete source lines.\nNo quantity, price, tax rate, line allocation or current tax policy is invented.\nSales tax components must retain `recoverableMinor: null`; purchase recovery does\nnot apply. Supplier quote lineage is not accepted on this command.\n\n`getReceivedSalesContractMoney(contract)` returns the immutable evidence or null.\nSales-named facts, snapshot and input types are public. The snapshot shares the\nexisting version-1 received-money representation and keeps `sourceQuote: null`.\nThe legacy `receivedPurchaseMoneyJson` storage name remains for schema compatibility;\napplications must use commands rather than writing that field.\n\nThe host authorizes the review and binds its immutable original source separately\nto this newly completed authority. Merely importing a source label such as signed\nor approved does not grant current acceptance. Normal acceptance freezes the\ncomplete money snapshot and permits the existing approved billing-schedule\ncommands. Issued invoices remain separate actual financial instruments.\n\nRecording or accepting an agreement does not recognize revenue, create an AR or\ntax journal, or add incurred tax-report facts. Only the applicable invoice or\npurchase accounting authority contributes those facts. Incomplete original\nagreement totals remain host evidence until reviewed complete totals are supplied.\n\nThe command uses the caller executor and active tenant, locks the parent, rejects\ncalculated lines and frozen drafts, and preserves exact retry identity. Ordinary\nmoney mutations and deletion are guarded. Replays with changed evidence or facts\nrequire a separate contract revision. Competing requests cannot overwrite the\nfirst recorded authority; outer transaction rollback includes the entire record.\n\nThe customer is frozen as soon as original money is recorded, including while\nthe agreement or order is still a draft. Reassignment requires a new contract;\nacceptance and retry preserve the original customer and monetary evidence.\n"
|
|
19793
21543
|
}
|
|
19794
21544
|
],
|
|
19795
21545
|
"recipes": [
|
|
@@ -19810,7 +21560,7 @@
|
|
|
19810
21560
|
],
|
|
19811
21561
|
"nav": [
|
|
19812
21562
|
{
|
|
19813
|
-
"label": "
|
|
21563
|
+
"label": "General agreements",
|
|
19814
21564
|
"model": "@happyvertical/smrt-commerce:Agreement",
|
|
19815
21565
|
"icon": "fileText",
|
|
19816
21566
|
"description": "Signed deals and terms with your customers, in one place."
|
|
@@ -20186,6 +21936,9 @@
|
|
|
20186
21936
|
"options": {
|
|
20187
21937
|
"@happyvertical/smrt-commerce:Invoice": {
|
|
20188
21938
|
"fields": {
|
|
21939
|
+
"historicalSourceKeyHash": {
|
|
21940
|
+
"visibility": "hidden"
|
|
21941
|
+
},
|
|
20189
21942
|
"providerTaxAmount": {
|
|
20190
21943
|
"visibility": "hidden"
|
|
20191
21944
|
},
|