@happyvertical/smrt-commerce 0.56.1 → 0.57.0
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 +24 -11
- package/README.md +159 -93
- package/agents/accounting-snapshot-mapper.md +3 -3
- package/agents/commercial-ui.md +2 -2
- package/agents/contract-money.md +9 -6
- package/agents/cost-billing.md +3 -6
- package/agents/customer-vendor-ui.md +6 -1
- package/agents/document-money.md +59 -31
- package/agents/invoice-calculations.md +31 -56
- package/agents/invoice-preparation.md +62 -73
- package/agents/invoice-quantity.md +9 -21
- package/agents/minor-unit-migration.md +4 -4
- package/agents/money-calculator.md +7 -8
- package/agents/money-model.md +18 -22
- package/agents/money-upgrade.md +92 -0
- package/agents/revenue-journal.md +2 -2
- package/agents/tax-codes.md +17 -14
- package/agents/tax-summary.md +12 -8
- package/dist/billing/period-close.d.ts.map +1 -1
- package/dist/billing/runtime.d.ts +5 -2
- package/dist/billing/runtime.d.ts.map +1 -1
- package/dist/chunks/{ContractLineItemCollection-DYjhj_pU.js → ContractLineItemCollection-BZcrlrrY.js} +22 -27
- package/dist/chunks/ContractLineItemCollection-BZcrlrrY.js.map +1 -0
- package/dist/chunks/{CustomerCollection-DQIujn4f.js → CustomerCollection-BIPH2ZUx.js} +3 -3
- package/dist/chunks/{CustomerCollection-DQIujn4f.js.map → CustomerCollection-BIPH2ZUx.js.map} +1 -1
- package/dist/chunks/{DocumentTaxCollection-BEpoqXAQ.js → DocumentTaxCollection-DDzlywMW.js} +41 -14
- package/dist/chunks/DocumentTaxCollection-DDzlywMW.js.map +1 -0
- package/dist/chunks/{InvoiceCollection-CKQflFjc.js → InvoiceCollection-cinzAqt6.js} +53 -164
- package/dist/chunks/InvoiceCollection-cinzAqt6.js.map +1 -0
- package/dist/chunks/{TaxCodeCollection-DOpzW4y8.js → TaxCodeCollection-DaBOPG9c.js} +11 -4
- package/dist/chunks/{TaxCodeCollection-DOpzW4y8.js.map → TaxCodeCollection-DaBOPG9c.js.map} +1 -1
- package/dist/chunks/{TaxComponentCollection-Cs2uXwEl.js → TaxComponentCollection-C4zxnyVu.js} +3 -3
- package/dist/chunks/{TaxComponentCollection-Cs2uXwEl.js.map → TaxComponentCollection-C4zxnyVu.js.map} +1 -1
- package/dist/chunks/VendorCollection-D6ZcUYy8.js +100 -0
- package/dist/chunks/VendorCollection-D6ZcUYy8.js.map +1 -0
- package/dist/chunks/{allocation-integrity-DI3G16BN.js → allocation-integrity-WmWyXhtG.js} +6 -6
- package/dist/chunks/{allocation-integrity-DI3G16BN.js.map → allocation-integrity-WmWyXhtG.js.map} +1 -1
- package/dist/chunks/calculations-C9daQLsh.js +82 -0
- package/dist/chunks/calculations-C9daQLsh.js.map +1 -0
- package/dist/chunks/contract-money-EuToOghh.js +301 -0
- package/dist/chunks/contract-money-EuToOghh.js.map +1 -0
- package/dist/chunks/detect-CY9ufaFb.js +328 -0
- package/dist/chunks/detect-CY9ufaFb.js.map +1 -0
- package/dist/chunks/{document-money-DNVhDJyC.js → document-money-DV5t4vlK.js} +389 -63
- package/dist/chunks/document-money-DV5t4vlK.js.map +1 -0
- package/dist/chunks/{invoice-posting-BwV8g7z0.js → invoice-posting-C2i5dOVZ.js} +21 -23
- package/dist/chunks/invoice-posting-C2i5dOVZ.js.map +1 -0
- package/dist/chunks/{revenue-journal-DY9fro8E.js → revenue-journal-LLA9Kh_i.js} +3 -14
- package/dist/chunks/revenue-journal-LLA9Kh_i.js.map +1 -0
- package/dist/chunks/tenant-money-barrier-6TlqUeVj.js +255 -0
- package/dist/chunks/tenant-money-barrier-6TlqUeVj.js.map +1 -0
- package/dist/chunks/{types-LDETvQ1C.js → types-Bbm0Xflc.js} +2 -1
- package/dist/chunks/types-Bbm0Xflc.js.map +1 -0
- package/dist/chunks/{units-CNcjH_eE.js → units-8ElbjVZK.js} +18 -3
- package/dist/chunks/units-8ElbjVZK.js.map +1 -0
- package/dist/collections/ContractCollection.d.ts.map +1 -1
- package/dist/collections/ContractLineItemCollection.d.ts.map +1 -1
- package/dist/collections/InvoiceCollection.d.ts.map +1 -1
- package/dist/collections/InvoiceLineItemCollection.d.ts +0 -30
- package/dist/collections/InvoiceLineItemCollection.d.ts.map +1 -1
- package/dist/collections/TaxCodeCollection.d.ts +5 -1
- package/dist/collections/TaxCodeCollection.d.ts.map +1 -1
- package/dist/collections/TaxSettingsCollection.d.ts +15 -8
- package/dist/collections/TaxSettingsCollection.d.ts.map +1 -1
- package/dist/collections/TaxSummaryReportCollection.d.ts +3 -3
- package/dist/collections/TaxSummaryReportCollection.d.ts.map +1 -1
- package/dist/collections/index.d.ts +0 -1
- package/dist/collections/index.d.ts.map +1 -1
- package/dist/commerce-money-tools.d.ts.map +1 -1
- package/dist/contract-money.d.ts +1 -13
- package/dist/contract-money.d.ts.map +1 -1
- package/dist/document-money-internal.d.ts +7 -3
- package/dist/document-money-internal.d.ts.map +1 -1
- package/dist/document-money.d.ts +1 -11
- package/dist/document-money.d.ts.map +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +686 -1656
- package/dist/index.js.map +1 -1
- package/dist/invoice-accounting-sync.d.ts.map +1 -1
- package/dist/invoice-mcp.d.ts +3 -3
- package/dist/invoice-mcp.d.ts.map +1 -1
- package/dist/invoice-posting.d.ts +11 -5
- package/dist/invoice-posting.d.ts.map +1 -1
- package/dist/invoice-record-screen.d.ts +1 -1
- package/dist/invoice-record-screen.d.ts.map +1 -1
- package/dist/invoices.d.ts +6 -1
- package/dist/invoices.d.ts.map +1 -1
- package/dist/invoices.js +2 -2
- package/dist/manifest.json +1041 -863
- package/dist/migrations/invoiceEditorStorage.d.ts +2 -4
- package/dist/migrations/invoiceEditorStorage.d.ts.map +1 -1
- package/dist/migrations/partyLinks.d.ts.map +1 -1
- package/dist/models/Contract.d.ts +10 -4
- package/dist/models/Contract.d.ts.map +1 -1
- package/dist/models/ContractLineItem.d.ts +9 -17
- package/dist/models/ContractLineItem.d.ts.map +1 -1
- package/dist/models/DocumentTax.d.ts.map +1 -1
- package/dist/models/Invoice.d.ts +18 -48
- package/dist/models/Invoice.d.ts.map +1 -1
- package/dist/models/InvoiceLineItem.d.ts +13 -32
- package/dist/models/InvoiceLineItem.d.ts.map +1 -1
- package/dist/models/TaxSettings.d.ts +0 -10
- package/dist/models/TaxSettings.d.ts.map +1 -1
- package/dist/models/index.d.ts +1 -2
- package/dist/models/index.d.ts.map +1 -1
- package/dist/playground.js +1 -1
- package/dist/playground.js.map +1 -1
- package/dist/recipes.d.ts +8 -11
- package/dist/recipes.d.ts.map +1 -1
- package/dist/revenue-journal.d.ts +0 -8
- package/dist/revenue-journal.d.ts.map +1 -1
- package/dist/smrt-knowledge.json +2886 -6121
- package/dist/svelte/components/InvoiceEditor.svelte +7 -148
- package/dist/svelte/components/InvoiceEditor.svelte.d.ts +4 -1
- package/dist/svelte/components/InvoiceEditor.svelte.d.ts.map +1 -1
- package/dist/svelte/components/InvoiceTotals.svelte +14 -118
- package/dist/svelte/components/InvoiceTotals.svelte.d.ts +4 -27
- package/dist/svelte/components/InvoiceTotals.svelte.d.ts.map +1 -1
- package/dist/svelte/components/MoneyInvoiceEditor.svelte +3 -23
- package/dist/svelte/components/MoneyInvoiceEditor.svelte.d.ts +3 -26
- package/dist/svelte/components/MoneyInvoiceEditor.svelte.d.ts.map +1 -1
- package/dist/svelte/index.d.ts +2 -3
- package/dist/svelte/index.d.ts.map +1 -1
- package/dist/svelte/index.js +1 -2
- package/dist/svelte/invoices/calculations.d.ts +3 -108
- package/dist/svelte/invoices/calculations.d.ts.map +1 -1
- package/dist/svelte/invoices/calculations.js +12 -309
- package/dist/svelte/invoices/messages.d.ts +1 -37
- package/dist/svelte/invoices/messages.d.ts.map +1 -1
- package/dist/svelte/invoices/messages.js +1 -37
- package/dist/svelte/invoices/money-editor.d.ts +1 -1
- package/dist/svelte/invoices/money-editor.d.ts.map +1 -1
- package/dist/svelte/invoices/types.d.ts +14 -114
- package/dist/svelte/invoices/types.d.ts.map +1 -1
- package/dist/svelte/playground/InvoicePreparationPreview.svelte +85 -94
- package/dist/svelte/playground/InvoicePreparationPreview.svelte.d.ts.map +1 -1
- package/dist/svelte/playground.js +1 -1
- package/dist/tax/index.d.ts +2 -1
- package/dist/tax/index.d.ts.map +1 -1
- package/dist/tax/standard-codes.d.ts +12 -0
- package/dist/tax/standard-codes.d.ts.map +1 -0
- package/dist/tax/tenant-bootstrap.d.ts +29 -0
- package/dist/tax/tenant-bootstrap.d.ts.map +1 -0
- package/dist/tenant-money-barrier.d.ts +12 -44
- package/dist/tenant-money-barrier.d.ts.map +1 -1
- package/dist/types/index.d.ts +11 -23
- package/dist/types/index.d.ts.map +1 -1
- package/dist/ui.js +1 -1
- package/dist/ui.js.map +1 -1
- package/dist/upgrade/detect.d.ts +129 -0
- package/dist/upgrade/detect.d.ts.map +1 -0
- package/dist/upgrade/money-v2.d.ts +81 -0
- package/dist/upgrade/money-v2.d.ts.map +1 -0
- package/package.json +14 -13
- package/agents/line-amount-migration.md +0 -50
- package/dist/chunks/ContractLineItemCollection-DYjhj_pU.js.map +0 -1
- package/dist/chunks/DocumentTaxCollection-BEpoqXAQ.js.map +0 -1
- package/dist/chunks/InvoiceCollection-CKQflFjc.js.map +0 -1
- package/dist/chunks/InvoiceLineItemCollection-CHm9zdqh.js +0 -467
- package/dist/chunks/InvoiceLineItemCollection-CHm9zdqh.js.map +0 -1
- package/dist/chunks/TaxSettingsCollection-BBTZDH1S.js +0 -319
- package/dist/chunks/TaxSettingsCollection-BBTZDH1S.js.map +0 -1
- package/dist/chunks/calculations-DaHR17il.js +0 -333
- package/dist/chunks/calculations-DaHR17il.js.map +0 -1
- package/dist/chunks/document-money-DNVhDJyC.js.map +0 -1
- package/dist/chunks/invoice-posting-BwV8g7z0.js.map +0 -1
- package/dist/chunks/revenue-journal-DY9fro8E.js.map +0 -1
- package/dist/chunks/tenant-money-barrier-DjRXgMnX.js +0 -135
- package/dist/chunks/tenant-money-barrier-DjRXgMnX.js.map +0 -1
- package/dist/chunks/types-LDETvQ1C.js.map +0 -1
- package/dist/chunks/units-CNcjH_eE.js.map +0 -1
- package/dist/collections/MoneyMigrationDocumentCollection.d.ts +0 -12
- package/dist/collections/MoneyMigrationDocumentCollection.d.ts.map +0 -1
- package/dist/migrations/commerceLineAmounts.d.ts +0 -84
- package/dist/migrations/commerceLineAmounts.d.ts.map +0 -1
- package/dist/models/MoneyMigrationDocument.d.ts +0 -28
- package/dist/models/MoneyMigrationDocument.d.ts.map +0 -1
- package/dist/svelte/components/InvoiceLineEditor.svelte +0 -92
- package/dist/svelte/components/InvoiceLineEditor.svelte.d.ts +0 -8
- package/dist/svelte/components/InvoiceLineEditor.svelte.d.ts.map +0 -1
- package/dist/svelte/invoices/fields.d.ts +0 -6
- package/dist/svelte/invoices/fields.d.ts.map +0 -1
- package/dist/svelte/invoices/fields.js +0 -22
- package/dist/tax/legacy.d.ts +0 -48
- package/dist/tax/legacy.d.ts.map +0 -1
package/agents/document-money.md
CHANGED
|
@@ -1,27 +1,51 @@
|
|
|
1
1
|
# Document money persistence
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
Commerce has one money model. Tax codes resolve each line's tax, the server
|
|
4
|
+
computes line `taxAmount` and the header totals, and issuing a document freezes
|
|
5
|
+
it with a money snapshot. Every Invoice and Contract money write needs a
|
|
6
|
+
tenant; a tenantless write fails with `MoneyValidationError`
|
|
7
|
+
`INVALID_MONEY_INPUT` (`Commerce money documents require a tenant`).
|
|
8
|
+
|
|
9
|
+
### Tenant settings and bootstrap (#4009)
|
|
10
|
+
|
|
11
|
+
Each tenant has one `TaxSettings` row. It is created once, wherever the first
|
|
12
|
+
caller reaches it: `getOrCreateForTenant`, the cookbook path, a generated
|
|
13
|
+
create, or the runtime barrier ahead of a tenant's first document. Creation
|
|
14
|
+
runs in one transaction under a tenant advisory lock on PostgreSQL (the
|
|
15
|
+
embedded write queue elsewhere), re-reads before inserting, and inserts the
|
|
16
|
+
deterministic settings id, so racing first writers converge on one row.
|
|
17
|
+
|
|
18
|
+
`ensureCommerceTenant(db, tenantId, { cookbook? })` is the one host bootstrap
|
|
19
|
+
call after tenant creation. It seeds the settings row, the standard tax codes
|
|
20
|
+
(`exempt`, `zero-rated`, `out-of-scope`), and the cookbook's commerce tax
|
|
21
|
+
settings when one is given. It returns `{ tenantId }` and is idempotent;
|
|
22
|
+
re-running it with a cookbook re-applies the cookbook defaults.
|
|
23
|
+
|
|
24
|
+
Money data written by an earlier version is refused, never read. A schema with
|
|
25
|
+
the earlier version's money columns or table, or an Invoice or Contract row
|
|
26
|
+
without a tenant, refuses the whole database. A tenant with Invoice or Contract
|
|
27
|
+
rows but no settings row, or with old-format documents (an issued document
|
|
28
|
+
without a money snapshot, or a line with neither a tax code nor a component
|
|
29
|
+
snapshot), is refused on its own. All fail with `COMMERCE_DATA_NEEDS_UPGRADE`
|
|
30
|
+
and name `smrt db:upgrade-commerce-money`.
|
|
31
|
+
See [money data upgrade](money-upgrade.md). Rows written with raw SQL bypass
|
|
32
|
+
the model and are not recalculated.
|
|
8
33
|
|
|
9
34
|
Every Invoice/InvoiceLineItem get, list, preview, mutation, posting, and
|
|
10
|
-
accounting-sync phase
|
|
11
|
-
rows. The
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
and runtime never creates schema.
|
|
18
|
-
|
|
19
|
-
In `v2`, saving an invoice line locks and reloads its parent on the caller's
|
|
35
|
+
accounting-sync phase checks for old-format data, then acquires the tenant
|
|
36
|
+
settings row before document rows. The lock is held through the owning
|
|
37
|
+
transaction. Nested coordinators reuse an explicitly registered transaction
|
|
38
|
+
executor; adapter shape is never used as transaction proof. Runtime code never
|
|
39
|
+
creates schema.
|
|
40
|
+
|
|
41
|
+
Saving an invoice line locks and reloads its parent on the caller's
|
|
20
42
|
transaction, reloads every sibling, resolves current tax defaults, calculates
|
|
21
43
|
the document once, and writes line snapshots, `DocumentTax`, and header totals
|
|
22
|
-
atomically. Tax resolution order is line override,
|
|
23
|
-
|
|
24
|
-
|
|
44
|
+
atomically. Tax resolution order is line override, customer exemption (unless
|
|
45
|
+
the line overrides), product, customer code, then the tenant default; `none`
|
|
46
|
+
mode uses the tenant's `out-of-scope` code. Product reads use the products
|
|
47
|
+
package's collection on that same transaction executor; tenant-owned and
|
|
48
|
+
catalog-global products are accepted.
|
|
25
49
|
|
|
26
50
|
The first transition away from `DRAFT`, or setting `arJournalId`, freezes the
|
|
27
51
|
money document. The invoice and every line receive the same stable
|
|
@@ -68,18 +92,17 @@ draft overlay through the owning resolver/calculator without writes and rejects
|
|
|
68
92
|
frozen documents. A supplied line id must name a stored line exactly once; omit
|
|
69
93
|
the id for a new preview-only line. `getInvoiceMoneyFacts({ db, tenantId,
|
|
70
94
|
invoiceId })` reads the authoritative stored header, lines, `moneySnapshotId`,
|
|
71
|
-
and `DocumentTax` rows without recalculation. Both facades
|
|
72
|
-
|
|
73
|
-
partially migrated amounts are never presented as money-v2 facts.
|
|
95
|
+
and `DocumentTax` rows without recalculation. Both facades take the tenant
|
|
96
|
+
settings lock and refuse a tenant whose data needs the upgrade.
|
|
74
97
|
|
|
75
98
|
### Record-screen composition
|
|
76
99
|
|
|
77
100
|
`loadInvoiceRecordScreenData({ db, tenantId, invoiceId })` is the commerce
|
|
78
101
|
server adapter for a generic invoice record page. A caller must already have
|
|
79
102
|
that exact active tenant; the adapter never switches principals based on its
|
|
80
|
-
argument. It holds the
|
|
81
|
-
|
|
82
|
-
|
|
103
|
+
argument. It holds the tenant money lock while it reads the stored header,
|
|
104
|
+
lines, `DocumentTax`, and related credit-note summaries, so it never mixes a
|
|
105
|
+
stale header with a different snapshot of those rows. Its totals
|
|
83
106
|
are a direct projection of persisted minor-unit values and component snapshots;
|
|
84
107
|
it does not resolve a code or recalculate tax.
|
|
85
108
|
|
|
@@ -90,9 +113,10 @@ may expose `onCreateCreditNote` only with a server-derived
|
|
|
90
113
|
`canCreateCreditNote` authorization result. The wrapper hides the action for
|
|
91
114
|
credit-note records and never treats a client callback as authorization.
|
|
92
115
|
|
|
93
|
-
`InvoiceLineItem.amount` is
|
|
94
|
-
`
|
|
95
|
-
|
|
116
|
+
`InvoiceLineItem.amount` is the post-discount amount in the document's
|
|
117
|
+
`lineAmountType`: tax-exclusive net for `exclusive`, tax-inclusive for
|
|
118
|
+
`inclusive`. `taxAmount` is separate. `taxRate` is derived by the server from
|
|
119
|
+
the resolved components (`0.05` means 5%); it is never an input. `taxCodeId` and component identity may be null for
|
|
96
120
|
a genuine unassigned zero-tax line. Optional `productId` and
|
|
97
121
|
`revenueAccountId` are nullable UUID references so PostgreSQL never receives an
|
|
98
122
|
empty-string sentinel.
|
|
@@ -102,7 +126,7 @@ labels, percentage, liability account, taxable minor units, and tax minor
|
|
|
102
126
|
units. Provider tax remains the invoice header's `providerTaxAmount`; commerce
|
|
103
127
|
does not invent a tax code or component for provider-owned tax.
|
|
104
128
|
|
|
105
|
-
Revenue recognition
|
|
129
|
+
Revenue recognition reads only the frozen invoice, lines, and
|
|
106
130
|
`DocumentTax` rows. It groups each line's stored net by its snapshotted revenue
|
|
107
131
|
account (falling back to the caller's revenue account), groups component tax by
|
|
108
132
|
the snapshotted liability account (falling back to the caller's tax account),
|
|
@@ -117,10 +141,14 @@ the invoice parent lock and transaction, so retries converge. Account IDs from
|
|
|
117
141
|
frozen snapshots are still authorization checked: every used account must be
|
|
118
142
|
active and owned by the invoice tenant.
|
|
119
143
|
|
|
120
|
-
A posted
|
|
144
|
+
A posted invoice cannot move directly to `CANCELLED`. Call
|
|
121
145
|
`cancelWithRevenueReversal({ bookCurrency })`; it reads the original posted
|
|
122
146
|
journal, posts one deterministic journal with every debit and credit reversed,
|
|
123
147
|
and stores `arReversalJournalId` with the status transition atomically. The
|
|
124
148
|
original journal remains posted. Failed link or reversal writes roll back the
|
|
125
|
-
entire operation, and retry returns the same reversal.
|
|
126
|
-
|
|
149
|
+
entire operation, and retry returns the same reversal.
|
|
150
|
+
|
|
151
|
+
Billing period close writes ordinary money-model invoices. The payment provider
|
|
152
|
+
taxes them, so each billing line is an explicit override to the seller's
|
|
153
|
+
`out-of-scope` code, and the provider's tax is stored in `providerTaxAmount`
|
|
154
|
+
in the save that issues the invoice.
|
|
@@ -1,56 +1,31 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
`@happyvertical/smrt-commerce/invoices` is a Svelte-free entry
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
`calculateInvoiceDraft(values, { roundingScope: 'invoice' })` and the shared
|
|
33
|
-
`InvoiceEditor` / `InvoiceLineEditor` `roundingScope` prop accept `line` or
|
|
34
|
-
`invoice`. Omission preserves per-line rounding. The server chooses this option
|
|
35
|
-
from its authorized policy, and supplies it again when rendering rejected forms
|
|
36
|
-
or reopening retained drafts; it is not a client authority field.
|
|
37
|
-
|
|
38
|
-
Invoice scope groups numerically equal effective percentages, including textual
|
|
39
|
-
variants such as `5` and `5.000000`, and rounds each rate group once through
|
|
40
|
-
`calculateCostBillingTax`. Different rates remain independent components; explicit
|
|
41
|
-
zero overrides remain exempt. Quantity and discount rounding are unchanged. Two
|
|
42
|
-
10-minor lines at 5% therefore have tax 1 in invoice scope and 2 in line scope.
|
|
43
|
-
This is an additive single-rate-per-line editor, not a tax determination or
|
|
44
|
-
compound-tax solver. Invalid scope is a validation error. Drafts still reject
|
|
45
|
-
negative quantities/prices; the signed model calculator is unchanged.
|
|
46
|
-
|
|
47
|
-
`lineResults` and `resolveInvoiceLineDraft` remain standalone per-line
|
|
48
|
-
calculations, useful for validation and existing line-mode model storage. They
|
|
49
|
-
are **not allocations** of invoice-rounded tax: their tax/total fields may not
|
|
50
|
-
sum to the aggregate. In invoice mode the UI displays each line's subtotal and
|
|
51
|
-
an explanation, with tax and total shown only at invoice level. Persist the
|
|
52
|
-
aggregate with the authorized scope and retained draft when using invoice
|
|
53
|
-
rounding; do not reconstruct it by summing standalone resolved line totals.
|
|
54
|
-
No persistence schema or `InvoiceLineItem` tax behavior is changed by this
|
|
55
|
-
legacy-compatible adapter API. V2 persistence and issued tax snapshots are
|
|
56
|
-
defined by the [commercial money model](money-model.md).
|
|
1
|
+
# Invoice line calculation helper
|
|
2
|
+
|
|
3
|
+
`@happyvertical/smrt-commerce/invoices` is a Svelte-free entry for server
|
|
4
|
+
handlers and browsers. It exports `calculateInvoiceMinorLine`,
|
|
5
|
+
`MoneyValidationError` and the `MoneyValidationCode` type.
|
|
6
|
+
|
|
7
|
+
Document arithmetic, tax-code resolution, persisted tax components and issued
|
|
8
|
+
snapshots belong to the [commercial money model](money-model.md) and the
|
|
9
|
+
[money calculator](money-calculator.md). The invoice editor previews with
|
|
10
|
+
`calculateMoneyEditorDraft`; see [the invoice editor](invoice-preparation.md).
|
|
11
|
+
|
|
12
|
+
`calculateInvoiceMinorLine({ quantity, unitPrice, discount, taxRate })`
|
|
13
|
+
calculates one stored line in integer minor units, independent of currency. It
|
|
14
|
+
returns `grossMinor`, `discountMinor`, `subtotalMinor`, `taxMinor` and
|
|
15
|
+
`totalMinor`, and it runs the same money calculator the documents use:
|
|
16
|
+
|
|
17
|
+
- `quantity` is nonnegative, with at most six fractional digits;
|
|
18
|
+
- `unitPrice` is a signed safe integer, so credit lines may be negative;
|
|
19
|
+
- `discount` is a flat signed safe integer that carries the gross sign;
|
|
20
|
+
- `taxRate` is an already-resolved fraction in [0, 1], with at most eight
|
|
21
|
+
fractional digits. It is an input to this helper only; it never determines
|
|
22
|
+
tax on a stored invoice line, whose tax comes from its tax codes.
|
|
23
|
+
|
|
24
|
+
Rounding follows the money calculator, so a negative credit line rounds
|
|
25
|
+
symmetrically with its positive counterpart. Numeric quantities and rates use
|
|
26
|
+
their canonical decimal form, including exponent notation, and never a
|
|
27
|
+
`toFixed` expansion. Invalid quantities or rates, fractional or unsafe money,
|
|
28
|
+
and a discount with the wrong sign throw `RangeError` before persistence.
|
|
29
|
+
|
|
30
|
+
The [invoice quantity migration](invoice-quantity.md) uses this helper to
|
|
31
|
+
check that every stored quantity round-trips exactly.
|
|
@@ -1,86 +1,75 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Invoice editor and allocation fields
|
|
2
2
|
|
|
3
|
-
Import `InvoiceEditor`, `
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
Import `InvoiceEditor`, `InvoiceAllocationFields`, `InvoiceReview` and their
|
|
4
|
+
Props types from `@happyvertical/smrt-commerce/svelte`. `InvoiceEditor` is the
|
|
5
|
+
invoice form. It renders `MoneyInvoiceEditor` (also exported) and uses the
|
|
6
|
+
commercial money model, the only invoice money model. Line tax
|
|
7
|
+
comes from tax codes, never from a typed rate. See the
|
|
8
|
+
[commercial money model](money-model.md) and the
|
|
9
|
+
[money calculator](money-calculator.md).
|
|
8
10
|
|
|
9
|
-
`
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
Unit price and flat discount are currency-unit text; percentage values use `5`
|
|
14
|
-
for five percent. `discountType` is `flat` or `percent`; `taxMode` is `inherit` or
|
|
15
|
-
`override`. Explicit override `0` means zero tax; it never means inherit. Unknown
|
|
16
|
-
modes remain representable for rejected submissions. Dates remain text so invalid
|
|
17
|
-
values survive action failures. Customer options are caller-authorized projections;
|
|
18
|
-
unknown retained IDs remain visible. Currency uses the shared CurrencySelect.
|
|
11
|
+
`InvoiceEditorProps` requires `action` and `money: MoneyEditorProps`. Optional
|
|
12
|
+
props are `method` (default `post`), `canEdit`, `pending`, `hiddenFields`,
|
|
13
|
+
`intentField` (default `intent`), `saveIntent` (default `save`), `saveLabel`
|
|
14
|
+
and `onsubmit`. `money` carries:
|
|
19
15
|
|
|
20
|
-
|
|
16
|
+
- `mode: 'v2'` (a fixed discriminator);
|
|
17
|
+
- `draft`: currency, `lineAmountType` (`exclusive`, `inclusive` or `none`),
|
|
18
|
+
`roundingScope` (`line` or `document`) and ordered `lines`;
|
|
19
|
+
- `taxCodes`: the authorized tax-code choices, each with its components;
|
|
20
|
+
- optionally `frozen`, `status`, `kind` (`invoice` or `credit_note`), `stored`,
|
|
21
|
+
`onCreateCreditNote`, `customerTaxExempt`, `sellerTaxRegistrations`,
|
|
22
|
+
`partyTaxId`, `showNetSubtotal` and `names`.
|
|
21
23
|
|
|
22
|
-
`
|
|
23
|
-
|
|
24
|
-
the
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
`
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
drafts show an unavailable-total message rather than plausible numbers. The
|
|
31
|
-
calculator uses Commerce's explicit exponent table and its existing two-digit
|
|
32
|
-
fallback for other uppercase three-letter codes; the server must authorize its
|
|
33
|
-
supported currencies. Calculated values are never submitted as authority.
|
|
34
|
-
The server revalidates customer/SKU, prices, quantity, discounts, tax policy,
|
|
35
|
-
permissions and calculated totals. Header taxRate is a draft preview default,
|
|
36
|
-
not a new persisted Invoice tax field; replace it with authorized tax context
|
|
37
|
-
on the server. Client edits never establish approval or allocate inventory.
|
|
24
|
+
Each `MoneyEditorLineDraft` holds id, description, quantity, unitPrice,
|
|
25
|
+
`discountType` (`none`, `percent` or `amount`), discountValue (a nonnegative
|
|
26
|
+
magnitude; the calculator applies the line sign), `taxMode` (`inherit` or
|
|
27
|
+
`override`), `taxCodeId`, and the resolver's `inheritedTaxCodeId` and
|
|
28
|
+
`inheritedTaxCodeSource` (`product`, `customer`, `app`, `exempt-customer` or
|
|
29
|
+
`none`). Values are lossless strings, so input the server rejected comes back
|
|
30
|
+
unchanged. Choosing a tax code sets `taxMode` to `override`. Clearing it goes
|
|
31
|
+
back to the inherited code, and the editor shows that code's source.
|
|
38
32
|
|
|
39
33
|
```svelte
|
|
40
|
-
<InvoiceEditor action="?/save"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
hiddenFields={[{ name: 'requestId', value: form?.requestId ?? data.requestId }]}>
|
|
44
|
-
{#snippet children(current)}
|
|
45
|
-
<InvoiceAllocationFields currency={current.currency}
|
|
46
|
-
allocations={form?.allocations ?? data.allocations}
|
|
47
|
-
sources={data.authorizedSources} mayReadSources={data.mayReadSources}
|
|
48
|
-
canEdit={data.mayEdit} />
|
|
49
|
-
{/snippet}
|
|
50
|
-
</InvoiceEditor>
|
|
34
|
+
<InvoiceEditor action="?/save" money={form?.money ?? data.money}
|
|
35
|
+
canEdit={data.mayEdit}
|
|
36
|
+
hiddenFields={[{ name: 'requestId', value: form?.requestId ?? data.requestId }]} />
|
|
51
37
|
```
|
|
52
38
|
|
|
53
|
-
Native
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
39
|
+
Native field names default to `lineAmountType`, `roundingScope`, then repeated
|
|
40
|
+
`lineId`, `lineDescription`, `lineQuantity`, `lineUnitPrice`,
|
|
41
|
+
`lineDiscountType`, `lineDiscountValue`, `lineTaxMode` and `lineTaxCodeId`, in
|
|
42
|
+
displayed order. Use `money.names` to rename them. `moneyEditorFieldNames`
|
|
43
|
+
exports the defaults, and `moneyEditorSubmission(draft)` returns the typed
|
|
44
|
+
shape those controls represent. Hidden fields are submitted exactly as given,
|
|
45
|
+
including repeated names. The default transport is a native POST, which also
|
|
46
|
+
works without JavaScript. `onsubmit` can enhance it.
|
|
47
|
+
|
|
48
|
+
`calculateMoneyEditorDraft(draft, taxCodes)` is the editor's only calculation:
|
|
49
|
+
the pure money calculator, run on the retained text. The preview gives no
|
|
50
|
+
authority. The server resolves tax codes (line override, else product, else
|
|
51
|
+
customer, else the tenant default), recomputes `taxAmount` and the totals, and
|
|
52
|
+
ignores any client total. Invalid input shows the calculator's message instead
|
|
53
|
+
of a total.
|
|
59
54
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
request identity simply because the user added a line. The default transport
|
|
66
|
-
is native POST, including without JavaScript. With JavaScript, input changes
|
|
67
|
-
update exact previews without mutating the supplied values object. `onsubmit`
|
|
68
|
-
may enhance transport; caller-owned retryStatus/pending controls submission.
|
|
55
|
+
A frozen document (`frozen: true`) renders only `stored`, the server's issued
|
|
56
|
+
snapshot. It never recalculates and disables every field. If `stored` is
|
|
57
|
+
missing, the editor reports that. A frozen invoice shows a credit-note action,
|
|
58
|
+
enabled only when the host supplies `onCreateCreditNote`. A credit note never
|
|
59
|
+
offers one.
|
|
69
60
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
61
|
+
`InvoiceAllocationFields` renders source-allocation rows without a form of its
|
|
62
|
+
own; put it in a caller-owned native form. Each row has key, sourceId, a
|
|
63
|
+
currency-unit amount, optional remove, and field errors.
|
|
64
|
+
`mayReadSources=false` hides supplied labels and balances and renders
|
|
65
|
+
references instead. Unavailable sources that were retained stay postable, so
|
|
66
|
+
the server can reconcile them. Native names stay sourceId, allocationAmount
|
|
67
|
+
and the checked zero-based removeRow. `fields` renames them, and `addIntent`
|
|
68
|
+
defaults to `addAllocation`. Availability, reservations, budget policy and
|
|
69
|
+
approval belong to the caller and server.
|
|
78
70
|
|
|
79
|
-
`
|
|
80
|
-
|
|
81
|
-
uncertain actions, return every original string, stable row key, errors and
|
|
82
|
-
caller request/tenant/fingerprint identity. No component generates request keys.
|
|
71
|
+
`InvoiceReview` presents a review snapshot that the caller supplies. Edits
|
|
72
|
+
never infer a status change. No component generates request keys.
|
|
83
73
|
|
|
84
74
|
Focused validation: Commerce `vitest.invoices.config.ts`,
|
|
85
|
-
`e2e/invoices/playwright.config.ts`, `typecheck
|
|
86
|
-
release gates and calculator/model checks remain separate owning validations.
|
|
75
|
+
`e2e/invoices/playwright.config.ts`, `typecheck` and `build`.
|
|
@@ -1,22 +1,11 @@
|
|
|
1
|
-
# Invoice quantity persistence
|
|
1
|
+
# Invoice quantity persistence
|
|
2
2
|
|
|
3
3
|
InvoiceLineItem accepts nonnegative decimal quantities with at most six decimal
|
|
4
4
|
places. The `1.0` default declares a floating-point quantity column. Unit price,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
credit lines). Tax is a resolved fraction in [0, 1], with eight decimal places.
|
|
10
|
-
Accounting export retains an explicit zero rate instead of omitting it.
|
|
11
|
-
|
|
12
|
-
`applyEditorDraft(draft, authorizedContext)` resolves the shared invoice draft
|
|
13
|
-
helper into description/SKU/quantity/price/flat discount/tax and stores cloned
|
|
14
|
-
`invoiceEditorStateJson` TEXT, accessed through a guarded typed `invoiceEditorState` getter/setter. It does not save.
|
|
15
|
-
`getEditorDraft(authorizedContext)` returns a clone only when currency, inherited
|
|
16
|
-
tax authority, and all source fields still agree. Otherwise it returns null so the
|
|
17
|
-
caller can reconstruct a flat-discount/explicit-tax editor from resolved fields.
|
|
18
|
-
Normal save clears stale editor state and never derives money from metadata.
|
|
19
|
-
All other object metadata, authorization, and transaction ownership are unchanged.
|
|
5
|
+
discount and amount stay safe integer minor units. Every save goes through the
|
|
6
|
+
invoice money aggregate, which recomputes the line and ignores
|
|
7
|
+
any supplied amount. Tax comes from the line's resolved tax code, never from a
|
|
8
|
+
stored rate. See the [commercial money model](money-model.md).
|
|
20
9
|
|
|
21
10
|
## Existing integer columns
|
|
22
11
|
|
|
@@ -34,11 +23,10 @@ SQLite uses the public core table-rebuild planner to change the declaration to
|
|
|
34
23
|
REAL while preserving existing columns, constraints, indexes, and triggers. If
|
|
35
24
|
incoming foreign keys make that rebuild unsafe, the migration throws with the
|
|
36
25
|
planner reason and rolls back; it does not disable constraints or lose children.
|
|
37
|
-
Resolve that maintenance condition before deploying fractional writers. The
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
No schema mutation runs implicitly during runtime initialization or model save.
|
|
26
|
+
Resolve that maintenance condition before deploying fractional writers. The
|
|
27
|
+
migration no longer adds an editor-state column. An `invoice_editor_state_json`
|
|
28
|
+
column that an earlier version added is left in place and unused. No schema
|
|
29
|
+
mutation runs implicitly during runtime initialization or model save.
|
|
42
30
|
|
|
43
31
|
The actual DuckDB quantity/storage migration is tested. Complete Commerce model
|
|
44
32
|
persistence on DuckDB is currently unsupported because its hard foreign keys use
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Major-unit to minor-unit migration
|
|
2
2
|
|
|
3
|
-
This guide covers the
|
|
4
|
-
|
|
5
|
-
calculate tax, create snapshots
|
|
3
|
+
This guide covers the numeric-column rescale only. It is not the
|
|
4
|
+
[money data upgrade](money-upgrade.md): it does not change `TaxSettings`,
|
|
5
|
+
calculate tax, or create snapshots.
|
|
6
6
|
|
|
7
7
|
`preflightCommerceMoneyMinorUnits(db)` reports whether known commerce columns
|
|
8
8
|
still contain major units, rows that would round, and values outside JavaScript
|
|
@@ -35,11 +35,10 @@ codes include `TAX_CODE_DUPLICATE_COMPONENT`,
|
|
|
35
35
|
shared input, discount, percent, compound, state, scope, safety, freeze, and
|
|
36
36
|
currency codes exported as `MoneyValidationCode`.
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
before constructing that stored input.
|
|
38
|
+
`calculateInvoiceMinorLine(input)` in `src/svelte/invoices/calculations.ts`
|
|
39
|
+
(also exported from `@happyvertical/smrt-commerce/invoices`) runs one line
|
|
40
|
+
through this calculator with a single-component code built from its resolved
|
|
41
|
+
fraction. It takes no options. Its discount is signed minor units and passes
|
|
42
|
+
through unchanged, and its ties round half away from zero for negative
|
|
43
|
+
lines too. Editor magnitude normalization happens before constructing that
|
|
44
|
+
input. See [invoice line calculation](invoice-calculations.md).
|
package/agents/money-model.md
CHANGED
|
@@ -5,9 +5,9 @@ shapes, validation codes, and worked calculator examples live in the
|
|
|
5
5
|
[calculator guide](money-calculator.md) and
|
|
6
6
|
[package documentation](../../../docs/content/commerce-money.md). Money values
|
|
7
7
|
are signed safe-integer minor units; calculator tax percentages are exact text,
|
|
8
|
-
so `'5'` means 5%. The
|
|
9
|
-
`ContractLineItem.taxRate` fields are
|
|
10
|
-
`0.05` means 5
|
|
8
|
+
so `'5'` means 5%. The `InvoiceLineItem.taxRate` and
|
|
9
|
+
`ContractLineItem.taxRate` fields are server-derived fractions of the resolved
|
|
10
|
+
components (`0.05` means 5%); they are never tax inputs.
|
|
11
11
|
|
|
12
12
|
## Calculation contract
|
|
13
13
|
|
|
@@ -39,10 +39,10 @@ catalogue, seeds, registrations, and cookbook boundary are documented in
|
|
|
39
39
|
|
|
40
40
|
## Stored Invoice facts
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
There is one money model. Saving a draft resolves its current tax settings
|
|
43
|
+
once and atomically writes the header, line snapshots, and `DocumentTax` rows.
|
|
44
|
+
Every money document needs a tenant, and data written by an earlier version is
|
|
45
|
+
refused until it is upgraded ([money data upgrade](money-upgrade.md)). The detailed persistence, freeze, preview, credit-note, and
|
|
46
46
|
refund contracts are in [document money](document-money.md).
|
|
47
47
|
|
|
48
48
|
Once an Invoice leaves `DRAFT`, or receives an AR journal, its money snapshot
|
|
@@ -55,7 +55,7 @@ not invent a taxable component.
|
|
|
55
55
|
|
|
56
56
|
A credit note is an `Invoice` with `kind: 'credit_note'`. It stores positive
|
|
57
57
|
amounts; posting, reporting, and accounting adapters apply that direction once.
|
|
58
|
-
Issued-credit capacity and refunds are stable Invoice
|
|
58
|
+
Issued-credit capacity and refunds are stable Invoice behavior. A refund is
|
|
59
59
|
a positive `Payment` of kind `refund`, allocated only to a credit note. See
|
|
60
60
|
[document money](document-money.md) before presenting either balance as an
|
|
61
61
|
ordinary incoming payment.
|
|
@@ -63,15 +63,13 @@ ordinary incoming payment.
|
|
|
63
63
|
## Invoice MCP `get` projection
|
|
64
64
|
|
|
65
65
|
The standard Invoice MCP `get` tool uses `serializeInvoiceMcpGet`. For a
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
`FROZEN_DOCUMENT` code and the public message `Tenant money migration is in
|
|
74
|
-
progress`. If the caller's `PublicJsonOptions` hide any Invoice,
|
|
66
|
+
tenant invoice, the optional `money` value is the stored `InvoiceMoneyFacts`
|
|
67
|
+
projection: its header, line snapshots, and `DocumentTax` facts are read from
|
|
68
|
+
the stored snapshot and are never recalculated. An invoice without an id or
|
|
69
|
+
tenant returns the ordinary public Invoice projection.
|
|
70
|
+
|
|
71
|
+
A tenant whose data needs the upgrade refuses this read with
|
|
72
|
+
`COMMERCE_DATA_NEEDS_UPGRADE`. If the caller's `PublicJsonOptions` hide any Invoice,
|
|
75
73
|
`InvoiceLineItem`, or `DocumentTax` field needed by the money projection, the
|
|
76
74
|
serializer returns the base Invoice and omits the entire `money` alias. It does
|
|
77
75
|
not expose restricted values through a partial plain-object alias.
|
|
@@ -84,7 +82,7 @@ serializers](../../core/agents/generators.md#mcp-get-serializers).
|
|
|
84
82
|
## Reporting and integrations
|
|
85
83
|
|
|
86
84
|
The materialized `TaxSummaryReport` and its public descriptor/drilldown bridge
|
|
87
|
-
read stored Invoice `DocumentTax` facts under the tenant
|
|
85
|
+
read stored Invoice `DocumentTax` facts under the tenant money lock. See
|
|
88
86
|
[tax summary aggregation](tax-summary.md). Commerce exports
|
|
89
87
|
`createTaxSummaryMaterializedReportHost()` for an application-owned,
|
|
90
88
|
server-only host; register that host in the app's fixed report-host registry to
|
|
@@ -104,10 +102,8 @@ mapper](accounting-snapshot-mapper.md).
|
|
|
104
102
|
|
|
105
103
|
## Deliberate boundaries
|
|
106
104
|
|
|
107
|
-
|
|
108
|
-
[
|
|
109
|
-
The marker is a maintenance gate, not a customer-controlled setting. Contract
|
|
110
|
-
money persistence remains a separate aggregate contract; production report
|
|
105
|
+
Upgrading data written by an earlier version is documented in
|
|
106
|
+
[money data upgrade](money-upgrade.md). Contract money persistence remains a separate aggregate contract; production report
|
|
111
107
|
hosting is an application opt-in over the public host described above. The
|
|
112
108
|
model also does not provide currency conversion, cash-basis/deposit accounting,
|
|
113
109
|
partial recoverability, period locking, or compound tax.
|