@happyvertical/smrt-commerce 0.56.0 → 0.56.1
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 +9 -8
- package/README.md +76 -0
- package/agents/accounting-snapshot-mapper.md +111 -0
- package/agents/contract-money.md +18 -0
- package/agents/cost-billing.md +7 -2
- package/agents/document-money.md +126 -0
- package/agents/invoice-calculations.md +14 -2
- package/agents/line-amount-migration.md +50 -0
- package/agents/minor-unit-migration.md +20 -0
- package/agents/money-calculator.md +45 -0
- package/agents/money-model.md +113 -0
- package/agents/revenue-journal.md +23 -0
- package/agents/tax-codes.md +48 -0
- package/agents/tax-summary.md +126 -0
- package/dist/accounting-snapshot.d.ts +79 -0
- package/dist/accounting-snapshot.d.ts.map +1 -0
- package/dist/billing/runtime.d.ts +2 -0
- package/dist/billing/runtime.d.ts.map +1 -1
- package/dist/chunks/ContractLineItemCollection-DYjhj_pU.js +265 -0
- package/dist/chunks/ContractLineItemCollection-DYjhj_pU.js.map +1 -0
- package/dist/chunks/CustomerCollection-DQIujn4f.js +99 -0
- package/dist/chunks/CustomerCollection-DQIujn4f.js.map +1 -0
- package/dist/chunks/DocumentTaxCollection-BEpoqXAQ.js +1639 -0
- package/dist/chunks/DocumentTaxCollection-BEpoqXAQ.js.map +1 -0
- package/dist/chunks/InvoiceCollection-CKQflFjc.js +1047 -0
- package/dist/chunks/InvoiceCollection-CKQflFjc.js.map +1 -0
- package/dist/chunks/InvoiceLineItemCollection-CHm9zdqh.js +467 -0
- package/dist/chunks/InvoiceLineItemCollection-CHm9zdqh.js.map +1 -0
- package/dist/chunks/TaxCodeCollection-DOpzW4y8.js +149 -0
- package/dist/chunks/TaxCodeCollection-DOpzW4y8.js.map +1 -0
- package/dist/chunks/TaxComponentCollection-Cs2uXwEl.js +129 -0
- package/dist/chunks/TaxComponentCollection-Cs2uXwEl.js.map +1 -0
- package/dist/chunks/TaxSettingsCollection-BBTZDH1S.js +319 -0
- package/dist/chunks/TaxSettingsCollection-BBTZDH1S.js.map +1 -0
- package/dist/chunks/{money-DfrRxrel.js → allocation-integrity-DI3G16BN.js} +7 -12
- package/dist/chunks/allocation-integrity-DI3G16BN.js.map +1 -0
- package/dist/chunks/{calculations-Bz7RB3qK.js → calculations-DaHR17il.js} +134 -54
- package/dist/chunks/calculations-DaHR17il.js.map +1 -0
- package/dist/chunks/credit-allocation-yspz0Lab.js +121 -0
- package/dist/chunks/credit-allocation-yspz0Lab.js.map +1 -0
- package/dist/chunks/document-money-DNVhDJyC.js +860 -0
- package/dist/chunks/document-money-DNVhDJyC.js.map +1 -0
- package/dist/chunks/invoice-posting-BwV8g7z0.js +229 -0
- package/dist/chunks/invoice-posting-BwV8g7z0.js.map +1 -0
- package/dist/chunks/money-rational-CcW7gzG5.js +64 -0
- package/dist/chunks/money-rational-CcW7gzG5.js.map +1 -0
- package/dist/chunks/revenue-journal-DY9fro8E.js +140 -0
- package/dist/chunks/revenue-journal-DY9fro8E.js.map +1 -0
- package/dist/chunks/rolldown-runtime-D7D4PA-g.js +13 -0
- package/dist/chunks/tenant-money-barrier-DjRXgMnX.js +135 -0
- package/dist/chunks/tenant-money-barrier-DjRXgMnX.js.map +1 -0
- package/dist/chunks/{types-zVnIjSOk.js → types-LDETvQ1C.js} +3 -14
- package/dist/chunks/types-LDETvQ1C.js.map +1 -0
- package/dist/chunks/{units-BpZ0_Dpk.js → units-CNcjH_eE.js} +2 -2
- package/dist/chunks/{units-BpZ0_Dpk.js.map → units-CNcjH_eE.js.map} +1 -1
- package/dist/collections/ContractCollection.d.ts +35 -1
- package/dist/collections/ContractCollection.d.ts.map +1 -1
- package/dist/collections/ContractLineItemCollection.d.ts +26 -1
- package/dist/collections/ContractLineItemCollection.d.ts.map +1 -1
- package/dist/collections/DocumentTaxCollection.d.ts +75 -0
- package/dist/collections/DocumentTaxCollection.d.ts.map +1 -0
- package/dist/collections/InvoiceCollection.d.ts +26 -1
- package/dist/collections/InvoiceCollection.d.ts.map +1 -1
- package/dist/collections/InvoiceLineItemCollection.d.ts +26 -1
- package/dist/collections/InvoiceLineItemCollection.d.ts.map +1 -1
- package/dist/collections/MoneyMigrationDocumentCollection.d.ts +12 -0
- package/dist/collections/MoneyMigrationDocumentCollection.d.ts.map +1 -0
- package/dist/collections/PaymentAllocationCollection.d.ts +2 -0
- package/dist/collections/PaymentAllocationCollection.d.ts.map +1 -1
- package/dist/collections/TaxCodeCollection.d.ts +7 -0
- package/dist/collections/TaxCodeCollection.d.ts.map +1 -0
- package/dist/collections/TaxComponentCollection.d.ts +6 -0
- package/dist/collections/TaxComponentCollection.d.ts.map +1 -0
- package/dist/collections/TaxSettingsCollection.d.ts +16 -0
- package/dist/collections/TaxSettingsCollection.d.ts.map +1 -0
- package/dist/collections/TaxSummaryReportCollection.d.ts +151 -0
- package/dist/collections/TaxSummaryReportCollection.d.ts.map +1 -0
- package/dist/collections/index.d.ts +6 -0
- package/dist/collections/index.d.ts.map +1 -1
- package/dist/commerce-money-tools.d.ts +9 -0
- package/dist/commerce-money-tools.d.ts.map +1 -0
- package/dist/contract-money.d.ts +27 -0
- package/dist/contract-money.d.ts.map +1 -0
- package/dist/cost-billing.d.ts +0 -1
- package/dist/cost-billing.d.ts.map +1 -1
- package/dist/cost-billing.js +10 -15
- package/dist/cost-billing.js.map +1 -1
- package/dist/credit-allocation.d.ts +48 -0
- package/dist/credit-allocation.d.ts.map +1 -0
- package/dist/document-money-internal.d.ts +44 -0
- package/dist/document-money-internal.d.ts.map +1 -0
- package/dist/document-money.d.ts +85 -0
- package/dist/document-money.d.ts.map +1 -0
- package/dist/index.d.ts +15 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5395 -4246
- package/dist/index.js.map +1 -1
- package/dist/invoice-accounting-sync.d.ts +96 -0
- package/dist/invoice-accounting-sync.d.ts.map +1 -0
- package/dist/invoice-mcp.d.ts +16 -0
- package/dist/invoice-mcp.d.ts.map +1 -0
- package/dist/invoice-posting.d.ts +9 -0
- package/dist/invoice-posting.d.ts.map +1 -0
- package/dist/invoice-record-screen.d.ts +60 -0
- package/dist/invoice-record-screen.d.ts.map +1 -0
- package/dist/invoices.d.ts +2 -0
- package/dist/invoices.d.ts.map +1 -1
- package/dist/invoices.js +3 -2
- package/dist/manifest.json +10365 -4562
- package/dist/migrations/commerceLineAmounts.d.ts +84 -0
- package/dist/migrations/commerceLineAmounts.d.ts.map +1 -0
- package/dist/models/Contract.d.ts +25 -1
- package/dist/models/Contract.d.ts.map +1 -1
- package/dist/models/ContractLineItem.d.ts +30 -1
- package/dist/models/ContractLineItem.d.ts.map +1 -1
- package/dist/models/Customer.d.ts +7 -0
- package/dist/models/Customer.d.ts.map +1 -1
- package/dist/models/DocumentTax.d.ts +50 -0
- package/dist/models/DocumentTax.d.ts.map +1 -0
- package/dist/models/Invoice.d.ts +46 -2
- package/dist/models/Invoice.d.ts.map +1 -1
- package/dist/models/InvoiceLineItem.d.ts +33 -2
- package/dist/models/InvoiceLineItem.d.ts.map +1 -1
- package/dist/models/MoneyMigrationDocument.d.ts +28 -0
- package/dist/models/MoneyMigrationDocument.d.ts.map +1 -0
- package/dist/models/Payment.d.ts +5 -1
- package/dist/models/Payment.d.ts.map +1 -1
- package/dist/models/PaymentAllocation.d.ts.map +1 -1
- package/dist/models/TaxCode.d.ts +22 -0
- package/dist/models/TaxCode.d.ts.map +1 -0
- package/dist/models/TaxComponent.d.ts +21 -0
- package/dist/models/TaxComponent.d.ts.map +1 -0
- package/dist/models/TaxSettings.d.ts +33 -0
- package/dist/models/TaxSettings.d.ts.map +1 -0
- package/dist/models/TaxSummaryReport.d.ts +35 -0
- package/dist/models/TaxSummaryReport.d.ts.map +1 -0
- package/dist/models/Vendor.d.ts +9 -0
- package/dist/models/Vendor.d.ts.map +1 -1
- package/dist/models/index.d.ts +6 -0
- package/dist/models/index.d.ts.map +1 -1
- package/dist/money-rational.d.ts +15 -0
- package/dist/money-rational.d.ts.map +1 -0
- package/dist/money.d.ts +106 -25
- package/dist/money.d.ts.map +1 -1
- package/dist/money.js +274 -0
- package/dist/money.js.map +1 -0
- package/dist/recipes.d.ts +15 -15
- package/dist/revenue-journal.d.ts +61 -0
- package/dist/revenue-journal.d.ts.map +1 -0
- package/dist/smrt-knowledge.json +5711 -1029
- package/dist/svelte/components/InvoiceActions.svelte +12 -0
- package/dist/svelte/components/InvoiceActions.svelte.d.ts +5 -0
- package/dist/svelte/components/InvoiceActions.svelte.d.ts.map +1 -1
- package/dist/svelte/components/InvoiceEditor.svelte +15 -1
- package/dist/svelte/components/InvoiceEditor.svelte.d.ts.map +1 -1
- package/dist/svelte/components/InvoiceLineItems.svelte +3 -3
- package/dist/svelte/components/InvoiceRecordScreen.svelte +94 -0
- package/dist/svelte/components/InvoiceRecordScreen.svelte.d.ts +21 -0
- package/dist/svelte/components/InvoiceRecordScreen.svelte.d.ts.map +1 -0
- package/dist/svelte/components/InvoiceTotals.svelte +2 -2
- package/dist/svelte/components/MoneyInvoiceEditor.svelte +282 -0
- package/dist/svelte/components/MoneyInvoiceEditor.svelte.d.ts +31 -0
- package/dist/svelte/components/MoneyInvoiceEditor.svelte.d.ts.map +1 -0
- package/dist/svelte/components/PurchaseOrderEditor.svelte +53 -1
- package/dist/svelte/components/PurchaseOrderEditor.svelte.d.ts +5 -0
- package/dist/svelte/components/PurchaseOrderEditor.svelte.d.ts.map +1 -1
- package/dist/svelte/components/QuoteEditor.svelte +54 -1
- package/dist/svelte/components/QuoteEditor.svelte.d.ts +5 -0
- package/dist/svelte/components/QuoteEditor.svelte.d.ts.map +1 -1
- package/dist/svelte/i18n.d.ts +16 -0
- package/dist/svelte/i18n.d.ts.map +1 -1
- package/dist/svelte/i18n.js +16 -0
- package/dist/svelte/index.d.ts +7 -2
- package/dist/svelte/index.d.ts.map +1 -1
- package/dist/svelte/index.js +4 -1
- package/dist/svelte/invoices/calculations.d.ts +7 -2
- package/dist/svelte/invoices/calculations.d.ts.map +1 -1
- package/dist/svelte/invoices/calculations.js +141 -47
- package/dist/svelte/invoices/money-editor.d.ts +123 -0
- package/dist/svelte/invoices/money-editor.d.ts.map +1 -0
- package/dist/svelte/invoices/money-editor.js +101 -0
- package/dist/svelte/invoices/types.d.ts +5 -1
- package/dist/svelte/invoices/types.d.ts.map +1 -1
- package/dist/svelte/purchasing-i18n.d.ts +5 -0
- package/dist/svelte/purchasing-i18n.d.ts.map +1 -1
- package/dist/svelte/purchasing-i18n.js +5 -0
- package/dist/svelte/quote-i18n.d.ts +5 -0
- package/dist/svelte/quote-i18n.d.ts.map +1 -1
- package/dist/svelte/quote-i18n.js +5 -0
- package/dist/tax/cookbook.d.ts +22 -0
- package/dist/tax/cookbook.d.ts.map +1 -0
- package/dist/tax/example-pack.d.ts +25 -0
- package/dist/tax/example-pack.d.ts.map +1 -0
- package/dist/tax/identity.d.ts +5 -0
- package/dist/tax/identity.d.ts.map +1 -0
- package/dist/tax/index.d.ts +4 -0
- package/dist/tax/index.d.ts.map +1 -0
- package/dist/tax/legacy.d.ts +48 -0
- package/dist/tax/legacy.d.ts.map +1 -0
- package/dist/tax-summary-report-adapter.d.ts +37 -0
- package/dist/tax-summary-report-adapter.d.ts.map +1 -0
- package/dist/tax-summary.d.ts +129 -0
- package/dist/tax-summary.d.ts.map +1 -0
- package/dist/tenant-money-barrier.d.ts +66 -0
- package/dist/tenant-money-barrier.d.ts.map +1 -0
- package/dist/types/index.d.ts +137 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +19 -11
- package/dist/chunks/calculations-Bz7RB3qK.js.map +0 -1
- package/dist/chunks/money-DfrRxrel.js.map +0 -1
- package/dist/chunks/types-zVnIjSOk.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PaymentAllocation.d.ts","sourceRoot":"","sources":["../../src/models/PaymentAllocation.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAqB,UAAU,EAAQ,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"PaymentAllocation.d.ts","sourceRoot":"","sources":["../../src/models/PaymentAllocation.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAqB,UAAU,EAAQ,MAAM,0BAA0B,CAAC;AAK/E,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAYlE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,qBAoBa,iBAAkB,SAAQ,UAAU;IAC/C;;;OAGG;IAEH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE/B;;OAEG;IAGH,SAAS,EAAE,MAAM,CAAM;IAEvB;;OAEG;IAGH,SAAS,EAAE,MAAM,CAAM;IAEvB;;;;;;;;;OASG;IAKH,MAAM,EAAE,MAAM,CAAK;IAEnB;;OAEG;IAEH,WAAW,EAAE,IAAI,CAAc;IAE/B;;OAEG;IACH,WAAW,EAAE,MAAM,CAAM;IAEzB;;OAEG;IAEH,KAAK,EAAE,MAAM,CAAM;gBAEP,OAAO,GAAE,wBAA6B;IAalD,6EAA6E;IAC9D,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAkJrC;AAED,eAAe,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { SmrtObject } from '@happyvertical/smrt-core';
|
|
2
|
+
import type { TaxCodeOptions, TaxCodePart } from '../types/index.js';
|
|
3
|
+
export type TaxCodeKind = 'taxable' | 'zero-rated' | 'exempt' | 'out-of-scope';
|
|
4
|
+
export type TaxCodeAppliesTo = 'sales' | 'purchases' | 'both';
|
|
5
|
+
/** A reusable tax code whose ordered component list is safe to edit. */
|
|
6
|
+
export declare class TaxCode extends SmrtObject {
|
|
7
|
+
tenantId: string;
|
|
8
|
+
code: string;
|
|
9
|
+
name: string;
|
|
10
|
+
kind: TaxCodeKind;
|
|
11
|
+
appliesTo: TaxCodeAppliesTo;
|
|
12
|
+
/** Ordered component IDs; compound is reserved and deliberately unsupported. */
|
|
13
|
+
/** Stored JSON is guarded through the typed accessor below. */
|
|
14
|
+
componentsJson: string;
|
|
15
|
+
get components(): TaxCodePart[];
|
|
16
|
+
set components(value: TaxCodePart[] | string);
|
|
17
|
+
active: boolean;
|
|
18
|
+
constructor(options?: TaxCodeOptions);
|
|
19
|
+
save(): Promise<this>;
|
|
20
|
+
private parsedComponents;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=TaxCode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TaxCode.d.ts","sourceRoot":"","sources":["../../src/models/TaxCode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,UAAU,EAAQ,MAAM,0BAA0B,CAAC;AAGnE,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErE,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,YAAY,GAAG,QAAQ,GAAG,cAAc,CAAC;AAC/E,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,WAAW,GAAG,MAAM,CAAC;AAE9D,wEAAwE;AACxE,qBAUa,OAAQ,SAAQ,UAAU;IAErC,QAAQ,SAAM;IAGd,IAAI,SAAM;IAGV,IAAI,SAAM;IAGV,IAAI,EAAE,WAAW,CAAa;IAK9B,SAAS,EAAE,gBAAgB,CAAU;IAErC,gFAAgF;IAChF,+DAA+D;IAC/D,cAAc,SAAQ;IAEtB,IAII,UAAU,IAAI,WAAW,EAAE,CAc9B;IAED,IAAI,UAAU,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,MAAM,EAG3C;IAKD,MAAM,UAAQ;gBAEF,OAAO,GAAE,cAAmB;IAYzB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAiEpC,OAAO,CAAC,gBAAgB;CAoBzB"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { SmrtObject } from '@happyvertical/smrt-core';
|
|
2
|
+
import type { TaxComponentOptions } from '../types/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* One reusable tax rate component. Codes may combine components, but the
|
|
5
|
+
* component's percent is immutable after it has been saved: archive it and
|
|
6
|
+
* repoint editable codes to a replacement rate instead of rewriting history.
|
|
7
|
+
*/
|
|
8
|
+
export declare class TaxComponent extends SmrtObject {
|
|
9
|
+
tenantId: string;
|
|
10
|
+
name: string;
|
|
11
|
+
/** Percent, not a fraction: 7.125 means 7.125%. Stored as DECIMAL. */
|
|
12
|
+
percent: string;
|
|
13
|
+
liabilityAccountId: string;
|
|
14
|
+
recoverable: boolean;
|
|
15
|
+
active: boolean;
|
|
16
|
+
constructor(options?: TaxComponentOptions);
|
|
17
|
+
initialize(): Promise<this>;
|
|
18
|
+
save(): Promise<this>;
|
|
19
|
+
private isReferenced;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=TaxComponent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TaxComponent.d.ts","sourceRoot":"","sources":["../../src/models/TaxComponent.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EAEX,MAAM,0BAA0B,CAAC;AAIlC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAqB7D;;;;GAIG;AACH,qBAea,YAAa,SAAQ,UAAU;IAE1C,QAAQ,SAAM;IAGd,IAAI,SAAM;IAEV,sEAAsE;IAKtE,OAAO,SAAS;IAKhB,kBAAkB,SAAM;IAMxB,WAAW,UAAS;IAGpB,MAAM,UAAQ;gBAEF,OAAO,GAAE,mBAAwB;IAY9B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAM3B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YA8CtB,YAAY;CA8B3B"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { SmrtObject } from '@happyvertical/smrt-core';
|
|
2
|
+
import { type MoneyMigrationWriteCapability } from '../document-money-internal.js';
|
|
3
|
+
import type { TaxSettingsOptions } from '../types/index.js';
|
|
4
|
+
export interface TaxRegistration {
|
|
5
|
+
taxComponentId: string;
|
|
6
|
+
number: string;
|
|
7
|
+
label: string;
|
|
8
|
+
}
|
|
9
|
+
/** Tenant-level defaults and registration numbers for tax determination. */
|
|
10
|
+
export declare class TaxSettings extends SmrtObject {
|
|
11
|
+
tenantId: string;
|
|
12
|
+
defaultSalesTaxCodeId: string;
|
|
13
|
+
defaultPurchaseTaxCodeId: string;
|
|
14
|
+
defaultLineAmountType: 'exclusive' | 'inclusive' | 'none';
|
|
15
|
+
taxRoundingScope: 'line' | 'document';
|
|
16
|
+
/** Stored JSON is guarded through the typed accessor below. */
|
|
17
|
+
taxRegistrationsJson: string;
|
|
18
|
+
/** Server-owned runtime semantics gate. Never exposed as a generated write. */
|
|
19
|
+
moneyModel: 'legacy' | 'migrating' | 'v2';
|
|
20
|
+
/** Opaque owner token while a tenant migration is in progress. */
|
|
21
|
+
moneyMigrationId: string;
|
|
22
|
+
get taxRegistrations(): TaxRegistration[];
|
|
23
|
+
set taxRegistrations(value: TaxRegistration[] | string);
|
|
24
|
+
constructor(options?: TaxSettingsOptions);
|
|
25
|
+
save(): Promise<this>;
|
|
26
|
+
/** @internal Money migration owns marker transitions. */
|
|
27
|
+
saveMoneyModel(capability: MoneyMigrationWriteCapability): Promise<this>;
|
|
28
|
+
/** @internal Caller already owns the transaction-bound migration barrier. */
|
|
29
|
+
saveMoneyModelOnTransaction(capability: MoneyMigrationWriteCapability): Promise<this>;
|
|
30
|
+
private saveValidated;
|
|
31
|
+
private parsedRegistrations;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=TaxSettings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TaxSettings.d.ts","sourceRoot":"","sources":["../../src/models/TaxSettings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,UAAU,EAAQ,MAAM,0BAA0B,CAAC;AAM/E,OAAO,EAEL,KAAK,6BAA6B,EACnC,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,4EAA4E;AAC5E,qBAgBa,WAAY,SAAQ,UAAU;IAEzC,QAAQ,SAAM;IAKd,qBAAqB,SAAM;IAK3B,wBAAwB,SAAM;IAM9B,qBAAqB,EAAE,WAAW,GAAG,WAAW,GAAG,MAAM,CAAe;IAGxE,gBAAgB,EAAE,MAAM,GAAG,UAAU,CAAU;IAE/C,+DAA+D;IAC/D,oBAAoB,SAAQ;IAE5B,+EAA+E;IAC/E,UAAU,EAAE,QAAQ,GAAG,WAAW,GAAG,IAAI,CAAY;IAErD,kEAAkE;IAClE,gBAAgB,SAAM;IAEtB,IAMI,gBAAgB,IAAI,eAAe,EAAE,CAexC;IAED,IAAI,gBAAgB,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,MAAM,EAGrD;gBAEW,OAAO,GAAE,kBAAuB;IAkB7B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIpC,yDAAyD;IACnD,cAAc,CAClB,UAAU,EAAE,6BAA6B,GACxC,OAAO,CAAC,IAAI,CAAC;IAUhB,6EAA6E;IACvE,2BAA2B,CAC/B,UAAU,EAAE,6BAA6B,GACxC,OAAO,CAAC,IAAI,CAAC;YAUF,aAAa;IAgG3B,OAAO,CAAC,mBAAmB;CAoB5B"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** Materialized tax-summary rows compiled from immutable commerce snapshots. */
|
|
2
|
+
import { SmrtReport } from '@happyvertical/smrt-reports';
|
|
3
|
+
export type TaxSummaryReportRowKind = 'component' | 'kind' | 'reconciliation' | 'warning';
|
|
4
|
+
export declare class TaxSummaryReport extends SmrtReport {
|
|
5
|
+
tenantId: string;
|
|
6
|
+
/** Inclusive report window, stored as an RFC3339 instant. */
|
|
7
|
+
periodFrom: Date;
|
|
8
|
+
/** Inclusive report window, stored as an RFC3339 instant. */
|
|
9
|
+
periodTo: Date;
|
|
10
|
+
currency: string;
|
|
11
|
+
rowKind: TaxSummaryReportRowKind;
|
|
12
|
+
/** Stable key for replacement and a source drilldown dimension. */
|
|
13
|
+
dimensionKey: string;
|
|
14
|
+
direction: string;
|
|
15
|
+
taxComponentId: string | null;
|
|
16
|
+
taxCodeKind: string | null;
|
|
17
|
+
liabilityAccountId: string | null;
|
|
18
|
+
taxableMinor: number;
|
|
19
|
+
taxMinor: number;
|
|
20
|
+
recoverableMinor: number | null;
|
|
21
|
+
ledgerMovementMinor: number | null;
|
|
22
|
+
netTaxMinor: number | null;
|
|
23
|
+
differenceMinor: number | null;
|
|
24
|
+
documentCount: number;
|
|
25
|
+
/** Canonical source classes present when this row was materialized. */
|
|
26
|
+
sourceScopes: string;
|
|
27
|
+
complete: boolean;
|
|
28
|
+
warningCode: string | null;
|
|
29
|
+
/** Stable source category for an incomplete-source warning drilldown. */
|
|
30
|
+
warningSourceType: string | null;
|
|
31
|
+
/** Stable source identity for an incomplete-source warning drilldown. */
|
|
32
|
+
warningSourceId: string | null;
|
|
33
|
+
warningMessage: string | null;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=TaxSummaryReport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TaxSummaryReport.d.ts","sourceRoot":"","sources":["../../src/models/TaxSummaryReport.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAGhF,OAAO,EAAmB,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAI1E,MAAM,MAAM,uBAAuB,GAC/B,WAAW,GACX,MAAM,GACN,gBAAgB,GAChB,SAAS,CAAC;AAEd,qBAgBa,gBAAiB,SAAQ,UAAU;IAE9C,QAAQ,SAAM;IAEd,6DAA6D;IAM7D,UAAU,EAAE,IAAI,CAAe;IAE/B,6DAA6D;IAM7D,QAAQ,EAAE,IAAI,CAAe;IAM7B,QAAQ,SAAM;IAId,OAAO,EAAE,uBAAuB,CAAe;IAE/C,mEAAmE;IAKnE,YAAY,SAAM;IAMlB,SAAS,SAAM;IAOf,cAAc,EAAE,MAAM,GAAG,IAAI,CAAQ;IAIrC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAQ;IAOlC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAIzC,YAAY,SAAK;IAOjB,QAAQ,SAAK;IASb,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAOvC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAQ1C,WAAW,EAAE,MAAM,GAAG,IAAI,CAAQ;IAOlC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAQ;IAItC,aAAa,SAAK;IAElB,uEAAuE;IAMvE,YAAY,SAAM;IAMlB,QAAQ,UAAQ;IAIhB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAQ;IAElC,yEAAyE;IAGzE,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAExC,yEAAyE;IAGzE,eAAe,EAAE,MAAM,GAAG,IAAI,CAAQ;IAOtC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAQ;CACtC"}
|
package/dist/models/Vendor.d.ts
CHANGED
|
@@ -49,6 +49,15 @@ export declare class Vendor extends SmrtObject {
|
|
|
49
49
|
* Default currency for transactions with this vendor
|
|
50
50
|
*/
|
|
51
51
|
currency: string;
|
|
52
|
+
/**
|
|
53
|
+
* Supplier registration number.
|
|
54
|
+
*
|
|
55
|
+
* Sensitive for the same reason as a customer's tax ID: it is identifying
|
|
56
|
+
* business information and must not enter generated list/search surfaces.
|
|
57
|
+
*/
|
|
58
|
+
taxId: string;
|
|
59
|
+
/** Tax code normally used for purchases from this vendor. */
|
|
60
|
+
defaultTaxCodeId: string;
|
|
52
61
|
/**
|
|
53
62
|
* Default contact email for orders
|
|
54
63
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Vendor.d.ts","sourceRoot":"","sources":["../../src/models/Vendor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"Vendor.d.ts","sourceRoot":"","sources":["../../src/models/Vendor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAIL,UAAU,EAEX,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,YAAY,EACb,MAAM,mBAAmB,CAAC;AAE3B;;;;;;;;;;;;;;;GAeG;AACH,qBAMa,MAAO,SAAQ,UAAU;IACpC;;;OAGG;IAEH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE/B;;;OAGG;IAKH,SAAS,EAAE,MAAM,CAAM;IAEvB;;OAEG;IAKH,YAAY,EAAE,MAAM,CAAK;IAEzB;;;;OAIG;IAKH,kBAAkB,EAAE,MAAM,CAAK;IAE/B;;OAEG;IAKH,YAAY,EAAE,MAAM,CAAM;IAE1B;;OAEG;IAKH,QAAQ,EAAE,MAAM,CAAS;IAEzB;;;;;OAKG;IAKH,KAAK,EAAE,MAAM,CAAM;IAEnB,6DAA6D;IAI7D,gBAAgB,EAAE,MAAM,CAAM;IAE9B;;OAEG;IAKH,mBAAmB,EAAE,MAAM,CAAM;IAEjC;;OAEG;IAKH,mBAAmB,EAAE,MAAM,CAAM;IAEjC;;OAEG;IAKH,MAAM,EAAE,YAAY,CAAuB;IAE3C;;OAEG;IAKH,KAAK,EAAE,MAAM,CAAM;IAEnB;;;;;;;;;;;;;;;;;;;OAmBG;IAKH,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAM;IAE7C;;;OAGG;IAKH,QAAQ,EAAE,YAAY,EAAE,CAAM;gBAElB,OAAO,GAAE,aAAkB;IA6BvC;;;;;;;;OAQG;IACY,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAS1C;;;;OAIG;IACY,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAQpC;;OAEG;IACH,QAAQ,IAAI,OAAO;IAInB;;OAEG;IACH,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAI1C;;;;;;;;;;OAUG;IACH,YAAY,IAAI,MAAM;IAItB;;;;;;;OAOG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAOtD;;;;OAIG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAQ7D;;;OAGG;IACH,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAU1C;;;;;;;;;OASG;IACH,OAAO,CAAC,MAAM,CAAC,wBAAwB;CAqBxC;AAED,eAAe,MAAM,CAAC"}
|
package/dist/models/index.d.ts
CHANGED
|
@@ -6,14 +6,20 @@ export { BillingAccount, type BillingCloseKind, BillingLineSource, type BillingL
|
|
|
6
6
|
export { Agreement, Cart, Contract, Estimate, Lease, type LicenseRightsSnapshot, LicenseSale, Order, ProductionOrder, PurchaseContract, PurchaseOrder, SalesContract, WholesaleOrder, } from './Contract.js';
|
|
7
7
|
export { ContractLineItem } from './ContractLineItem.js';
|
|
8
8
|
export { Customer } from './Customer.js';
|
|
9
|
+
export { type CommerceDocumentType, DocumentTax, type DocumentTaxOptions, } from './DocumentTax.js';
|
|
9
10
|
export { Fulfillment } from './Fulfillment.js';
|
|
10
11
|
export { FulfillmentLineItem } from './FulfillmentLineItem.js';
|
|
11
12
|
export { Invoice } from './Invoice.js';
|
|
12
13
|
export { InvoiceLineItem } from './InvoiceLineItem.js';
|
|
14
|
+
export { MoneyMigrationDocument, type MoneyMigrationDocumentOptions, type MoneyMigrationDocumentState, type MoneyMigrationDocumentType, } from './MoneyMigrationDocument.js';
|
|
13
15
|
export { Payment } from './Payment.js';
|
|
14
16
|
export { PaymentAllocation } from './PaymentAllocation.js';
|
|
15
17
|
export { PaymentInstrument } from './PaymentInstrument.js';
|
|
16
18
|
export { PaymentIntent } from './PaymentIntent.js';
|
|
17
19
|
export { Payout } from './Payout.js';
|
|
20
|
+
export { TaxCode, type TaxCodeAppliesTo, type TaxCodeKind } from './TaxCode.js';
|
|
21
|
+
export { TaxComponent } from './TaxComponent.js';
|
|
22
|
+
export { type TaxRegistration, TaxSettings } from './TaxSettings.js';
|
|
23
|
+
export { TaxSummaryReport, type TaxSummaryReportRowKind, } from './TaxSummaryReport.js';
|
|
18
24
|
export { Vendor } from './Vendor.js';
|
|
19
25
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/models/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,cAAc,EACd,KAAK,gBAAgB,EACrB,iBAAiB,EACjB,KAAK,qBAAqB,EAC1B,qBAAqB,EACrB,KAAK,yBAAyB,EAC9B,KAAK,4BAA4B,EACjC,KAAK,+BAA+B,EACpC,kBAAkB,EAClB,KAAK,wBAAwB,EAC7B,KAAK,eAAe,GACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,SAAS,EACT,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,KAAK,qBAAqB,EAC1B,WAAW,EACX,KAAK,EACL,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,cAAc,GACf,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/models/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,cAAc,EACd,KAAK,gBAAgB,EACrB,iBAAiB,EACjB,KAAK,qBAAqB,EAC1B,qBAAqB,EACrB,KAAK,yBAAyB,EAC9B,KAAK,4BAA4B,EACjC,KAAK,+BAA+B,EACpC,kBAAkB,EAClB,KAAK,wBAAwB,EAC7B,KAAK,eAAe,GACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,SAAS,EACT,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,KAAK,qBAAqB,EAC1B,WAAW,EACX,KAAK,EACL,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,cAAc,GACf,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EACL,KAAK,oBAAoB,EACzB,WAAW,EACX,KAAK,kBAAkB,GACxB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EACL,sBAAsB,EACtB,KAAK,6BAA6B,EAClC,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,GAChC,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,KAAK,eAAe,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EACL,gBAAgB,EAChB,KAAK,uBAAuB,GAC7B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Internal exact-rational primitives shared by commerce money calculators. */
|
|
2
|
+
export interface SignedRationalInput {
|
|
3
|
+
id: string;
|
|
4
|
+
numerator: bigint;
|
|
5
|
+
denominator: bigint;
|
|
6
|
+
}
|
|
7
|
+
export declare function roundSignedRational(numerator: bigint, denominator: bigint): bigint;
|
|
8
|
+
export declare function allocateSignedRationals(values: readonly SignedRationalInput[]): {
|
|
9
|
+
target: bigint;
|
|
10
|
+
allocations: {
|
|
11
|
+
id: string;
|
|
12
|
+
value: bigint;
|
|
13
|
+
}[];
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=money-rational.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"money-rational.d.ts","sourceRoot":"","sources":["../src/money-rational.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AASD,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAClB,MAAM,CAMR;AAYD,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,SAAS,mBAAmB,EAAE,GACrC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CAyClE"}
|
package/dist/money.d.ts
CHANGED
|
@@ -1,27 +1,108 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* Every money column in this package is INTEGER minor units — cents,
|
|
5
|
-
* satoshis — so `$19.99` is `1999`. Before #2401 the models carried
|
|
6
|
-
* `EPSILON = 0.01` tolerances on every comparison, because the values really
|
|
7
|
-
* were floats and `0.1 * 3` really is `0.30000000000000004`. With exact
|
|
8
|
-
* integers those tolerances are not merely unnecessary, they are wrong: a
|
|
9
|
-
* one-cent discrepancy is a one-cent discrepancy, not rounding fuzz.
|
|
10
|
-
*
|
|
11
|
-
* Dropping the tolerances is only safe if the values are *actually* integers,
|
|
12
|
-
* which is what this guard establishes. A fractional major-unit write (`19.99`
|
|
13
|
-
* into a cents column) is the bug the whole convention exists to prevent;
|
|
14
|
-
* PostgreSQL catches it with a `22P02` and SQLite's type affinity does not
|
|
15
|
-
* catch it at all, so the model catches it first, on every engine and every
|
|
16
|
-
* write surface.
|
|
17
|
-
*/
|
|
18
|
-
/**
|
|
19
|
-
* Throw unless every named value is a finite integer.
|
|
20
|
-
*
|
|
21
|
-
* @param context - Model name for the error message, e.g. `Invoice`.
|
|
22
|
-
* @param label - Row identifier used in the error, e.g. an invoice number.
|
|
23
|
-
* @param entries - `[fieldName, value]` pairs to check.
|
|
24
|
-
* @throws When any value is non-finite or has a fractional part.
|
|
25
|
-
*/
|
|
1
|
+
/** Exact, transport-neutral commercial document money calculation. */
|
|
2
|
+
/** Throw unless every named model value is a finite integer minor-unit amount. */
|
|
26
3
|
export declare function assertIntegerMinorUnits(context: string, label: string, entries: ReadonlyArray<readonly [string, number]>): void;
|
|
4
|
+
export type LineAmountType = 'exclusive' | 'inclusive' | 'none';
|
|
5
|
+
export type TaxRoundingScope = 'line' | 'document';
|
|
6
|
+
export type TaxCodeKind = 'taxable' | 'zero-rated' | 'exempt' | 'out-of-scope';
|
|
7
|
+
export type TaxCodeAppliesTo = 'sales' | 'purchases' | 'both';
|
|
8
|
+
export type MoneyValidationCode = 'DISCOUNT_BOTH_FORMS' | 'DISCOUNT_EXCEEDS_GROSS' | 'DISCOUNT_SIGN' | 'PERCENT_OUT_OF_RANGE' | 'COMPOUND_UNSUPPORTED' | 'INVALID_MONEY_INPUT' | 'TAX_CODE_DUPLICATE_COMPONENT' | 'TAX_CODE_KIND' | 'TAX_CODE_NON_TAXABLE_COMPONENTS' | 'TAX_CODE_NOT_FOUND' | 'TAX_CODE_TAXABLE_EMPTY' | 'TAX_COMPONENT_RATE_CONFLICT' | 'TAX_CODE_INACTIVE' | 'TAX_CODE_SCOPE' | 'UNSAFE_MONEY' | 'FROZEN_DOCUMENT' | 'CURRENCY_MISMATCH' | 'ACCOUNTING_SYNC_IN_PROGRESS' | 'ACCOUNTING_SYNC_RECONCILIATION_REQUIRED' | 'ACCOUNTING_SYNC_UNSUPPORTED' | 'CREDIT_EXCEEDS_LINE' | 'CREDIT_TARGET_NOT_ISSUED';
|
|
9
|
+
/** Stable validation error shared by model, editor, and transport adapters. */
|
|
10
|
+
export declare class MoneyValidationError extends Error {
|
|
11
|
+
readonly code: MoneyValidationCode;
|
|
12
|
+
readonly name = "MoneyValidationError";
|
|
13
|
+
/** Explicit marker consumed by public transports that preserve typed errors. */
|
|
14
|
+
readonly publicMessage: string;
|
|
15
|
+
constructor(code: MoneyValidationCode, message: string);
|
|
16
|
+
}
|
|
17
|
+
export interface TaxComponentInput {
|
|
18
|
+
taxComponentId: string;
|
|
19
|
+
/** Exact percent: "7" means 7%; at most six fractional digits. */
|
|
20
|
+
percent: string;
|
|
21
|
+
compound: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface MoneyTaxCodeInput {
|
|
24
|
+
id: string;
|
|
25
|
+
kind: TaxCodeKind;
|
|
26
|
+
components: readonly TaxComponentInput[];
|
|
27
|
+
}
|
|
28
|
+
export interface ResolvableTaxCodeInput extends MoneyTaxCodeInput {
|
|
29
|
+
active: boolean;
|
|
30
|
+
appliesTo: TaxCodeAppliesTo;
|
|
31
|
+
}
|
|
32
|
+
export type MoneyDiscountInput = {
|
|
33
|
+
kind: 'none';
|
|
34
|
+
} | {
|
|
35
|
+
kind: 'percent';
|
|
36
|
+
rate: string;
|
|
37
|
+
} | {
|
|
38
|
+
kind: 'amount';
|
|
39
|
+
minor: number;
|
|
40
|
+
};
|
|
41
|
+
export interface MoneyLineInput {
|
|
42
|
+
id: string;
|
|
43
|
+
/** Nonnegative decimal quantity with at most six fractional digits. */
|
|
44
|
+
quantity: number;
|
|
45
|
+
/** Signed safe integer minor units. */
|
|
46
|
+
unitPrice: number;
|
|
47
|
+
discount: MoneyDiscountInput;
|
|
48
|
+
/** Explicit tax-exclusive basis for credit-note amount allocations. */
|
|
49
|
+
netAmountMinor?: number;
|
|
50
|
+
/** Null means no code resolved; `none` pricing requires an out-of-scope code. */
|
|
51
|
+
taxCode: MoneyTaxCodeInput | null;
|
|
52
|
+
}
|
|
53
|
+
export interface MoneyLineResult {
|
|
54
|
+
id: string;
|
|
55
|
+
grossMinor: number;
|
|
56
|
+
discountMinor: number;
|
|
57
|
+
amountMinor: number;
|
|
58
|
+
components: {
|
|
59
|
+
taxComponentId: string;
|
|
60
|
+
taxMinor: number;
|
|
61
|
+
}[];
|
|
62
|
+
taxMinor: number;
|
|
63
|
+
netMinor: number;
|
|
64
|
+
}
|
|
65
|
+
export interface MoneyDocumentTaxResult {
|
|
66
|
+
/** Null records an unassigned line without inventing a persisted tax-code ID. */
|
|
67
|
+
taxCodeId: string | null;
|
|
68
|
+
taxComponentId: string | null;
|
|
69
|
+
taxableMinor: number;
|
|
70
|
+
taxMinor: number;
|
|
71
|
+
}
|
|
72
|
+
export interface MoneyDocumentResult {
|
|
73
|
+
lines: MoneyLineResult[];
|
|
74
|
+
subtotalMinor: number;
|
|
75
|
+
discountTotalMinor: number;
|
|
76
|
+
taxMinor: number;
|
|
77
|
+
totalMinor: number;
|
|
78
|
+
taxes: MoneyDocumentTaxResult[];
|
|
79
|
+
}
|
|
80
|
+
export type TaxCodeResolutionSource = 'line' | 'exempt-customer' | 'product' | 'customer' | 'app' | 'none';
|
|
81
|
+
export interface ResolveLineTaxCodeInput {
|
|
82
|
+
lineAmountType: LineAmountType;
|
|
83
|
+
lineOverride?: string | null;
|
|
84
|
+
}
|
|
85
|
+
export interface ResolveLineTaxCodeContext {
|
|
86
|
+
direction: 'sales' | 'purchases';
|
|
87
|
+
codes: Readonly<Record<string, ResolvableTaxCodeInput>>;
|
|
88
|
+
customerTaxExempt: boolean;
|
|
89
|
+
exemptCodeId?: string | null;
|
|
90
|
+
productCodeId?: string | null;
|
|
91
|
+
partyCodeId?: string | null;
|
|
92
|
+
appDefaultCodeId?: string | null;
|
|
93
|
+
outOfScopeCodeId?: string | null;
|
|
94
|
+
}
|
|
95
|
+
export interface ResolvedLineTaxCode {
|
|
96
|
+
taxCode: ResolvableTaxCodeInput | null;
|
|
97
|
+
source: TaxCodeResolutionSource;
|
|
98
|
+
}
|
|
99
|
+
/** Calculate exact line amounts, per-component tax, and document totals. */
|
|
100
|
+
export declare function calculateMoneyDocument(input: {
|
|
101
|
+
currency: string;
|
|
102
|
+
lineAmountType: LineAmountType;
|
|
103
|
+
roundingScope: TaxRoundingScope;
|
|
104
|
+
lines: readonly MoneyLineInput[];
|
|
105
|
+
}): MoneyDocumentResult;
|
|
106
|
+
/** Resolve a line tax code from already-loaded values, without model or I/O access. */
|
|
107
|
+
export declare function resolveLineTaxCode(line: ResolveLineTaxCodeInput, context: ResolveLineTaxCodeContext): ResolvedLineTaxCode;
|
|
27
108
|
//# sourceMappingURL=money.d.ts.map
|
package/dist/money.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"money.d.ts","sourceRoot":"","sources":["../src/money.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"money.d.ts","sourceRoot":"","sources":["../src/money.ts"],"names":[],"mappings":"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"}
|
package/dist/money.js
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { n as roundSignedRational, t as allocateSignedRationals } from "./chunks/money-rational-CcW7gzG5.js";
|
|
2
|
+
import { ISO_4217_MINOR_UNITS } from "@happyvertical/smrt-ui/currency";
|
|
3
|
+
//#region src/money.ts
|
|
4
|
+
function assertIntegerMinorUnits(context, label, entries) {
|
|
5
|
+
for (const [field, value] of entries) if (!Number.isFinite(value) || !Number.isInteger(value)) throw new Error(`${context} ${label}: ${field} must be an integer number of minor units (cents, satoshis) \u2014 got ${value}. Money is exact: $19.99 is 1999, not 19.99.`);
|
|
6
|
+
}
|
|
7
|
+
var MoneyValidationError = class extends Error {
|
|
8
|
+
constructor(code, message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.publicMessage = message;
|
|
12
|
+
}
|
|
13
|
+
code;
|
|
14
|
+
name = "MoneyValidationError";
|
|
15
|
+
/** Explicit marker consumed by public transports that preserve typed errors. */
|
|
16
|
+
publicMessage;
|
|
17
|
+
};
|
|
18
|
+
var PERCENT_SCALE = 1000000n;
|
|
19
|
+
var PERCENT_DENOMINATOR = 100n * PERCENT_SCALE;
|
|
20
|
+
var MAX_SAFE_MONEY = BigInt(Number.MAX_SAFE_INTEGER);
|
|
21
|
+
var IDENTIFIER = /^\S(?:.*\S)?$/;
|
|
22
|
+
function validationError(code, message) {
|
|
23
|
+
throw new MoneyValidationError(code, message);
|
|
24
|
+
}
|
|
25
|
+
function assertIdentifier(value, label) {
|
|
26
|
+
if (typeof value !== "string" || !IDENTIFIER.test(value)) validationError("INVALID_MONEY_INPUT", `${label} must be a nonempty string`);
|
|
27
|
+
}
|
|
28
|
+
function safeMoney(value) {
|
|
29
|
+
if (value > MAX_SAFE_MONEY || value < -MAX_SAFE_MONEY) validationError("UNSAFE_MONEY", "Money exceeds safe integer minor units");
|
|
30
|
+
return Number(value);
|
|
31
|
+
}
|
|
32
|
+
function money(value) {
|
|
33
|
+
if (!Number.isSafeInteger(value)) validationError("UNSAFE_MONEY", "Money must be safe integer minor units");
|
|
34
|
+
return BigInt(value);
|
|
35
|
+
}
|
|
36
|
+
function numberDecimal(value, precision) {
|
|
37
|
+
if (!Number.isFinite(value) || value < 0 || value > Number.MAX_SAFE_INTEGER) validationError("INVALID_MONEY_INPUT", "Quantity is outside the supported range");
|
|
38
|
+
const [mantissa, exponentText = "0"] = value.toString().split("e");
|
|
39
|
+
const [whole, fraction = ""] = mantissa.split(".");
|
|
40
|
+
const places = fraction.length - Number(exponentText);
|
|
41
|
+
if (places > precision) validationError("INVALID_MONEY_INPUT", "Quantity exceeds the supported decimal precision");
|
|
42
|
+
const coefficient = BigInt(whole + fraction);
|
|
43
|
+
return places < 0 ? {
|
|
44
|
+
coefficient: coefficient * 10n ** BigInt(-places),
|
|
45
|
+
scale: 1n
|
|
46
|
+
} : {
|
|
47
|
+
coefficient,
|
|
48
|
+
scale: 10n ** BigInt(places)
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function percentUnits(value) {
|
|
52
|
+
if (typeof value !== "string" || !/^(?:0|[1-9]\d{0,2})(?:\.\d{1,6})?$/.test(value)) validationError("PERCENT_OUT_OF_RANGE", "Percent must be an exact decimal from 0 through 100 with at most six fractional digits");
|
|
53
|
+
const [whole, fraction = ""] = value.split(".");
|
|
54
|
+
const units = BigInt(whole) * PERCENT_SCALE + BigInt(fraction.padEnd(6, "0"));
|
|
55
|
+
if (units > PERCENT_DENOMINATOR) validationError("PERCENT_OUT_OF_RANGE", "Percent exceeds 100");
|
|
56
|
+
return units;
|
|
57
|
+
}
|
|
58
|
+
function validateTaxCode(code, rates) {
|
|
59
|
+
if (!code || typeof code !== "object") validationError("INVALID_MONEY_INPUT", "Tax code must be an object");
|
|
60
|
+
assertIdentifier(code.id, "Tax code ID");
|
|
61
|
+
if (code.kind !== "taxable" && code.kind !== "zero-rated" && code.kind !== "exempt" && code.kind !== "out-of-scope") validationError("TAX_CODE_KIND", "Unknown tax code kind");
|
|
62
|
+
if (!Array.isArray(code.components)) validationError("INVALID_MONEY_INPUT", "Tax code components must be an array");
|
|
63
|
+
if (code.kind === "taxable" && code.components.length === 0) validationError("TAX_CODE_TAXABLE_EMPTY", "Taxable codes require at least one component");
|
|
64
|
+
if (code.kind !== "taxable" && code.components.length !== 0) validationError("TAX_CODE_NON_TAXABLE_COMPONENTS", "Non-taxable codes cannot contain components");
|
|
65
|
+
const seen = /* @__PURE__ */ new Set();
|
|
66
|
+
return code.components.map((component) => {
|
|
67
|
+
if (!component || typeof component !== "object") validationError("INVALID_MONEY_INPUT", "Tax component must be an object");
|
|
68
|
+
assertIdentifier(component.taxComponentId, "Tax component ID");
|
|
69
|
+
if (seen.has(component.taxComponentId)) validationError("TAX_CODE_DUPLICATE_COMPONENT", "Duplicate tax component within code");
|
|
70
|
+
seen.add(component.taxComponentId);
|
|
71
|
+
if (typeof component.compound !== "boolean") validationError("INVALID_MONEY_INPUT", "Tax component compound must be boolean");
|
|
72
|
+
if (component.compound) validationError("COMPOUND_UNSUPPORTED", "Compound tax components are not supported");
|
|
73
|
+
const rate = percentUnits(component.percent);
|
|
74
|
+
const existing = rates.get(component.taxComponentId);
|
|
75
|
+
if (existing !== void 0 && existing !== rate) validationError("TAX_COMPONENT_RATE_CONFLICT", "Shared tax component has conflicting percentages");
|
|
76
|
+
rates.set(component.taxComponentId, rate);
|
|
77
|
+
return {
|
|
78
|
+
taxComponentId: component.taxComponentId,
|
|
79
|
+
rate
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function discountFor(gross, discount) {
|
|
84
|
+
if (!discount || typeof discount !== "object") validationError("INVALID_MONEY_INPUT", "Discount must be a tagged object");
|
|
85
|
+
const runtime = discount;
|
|
86
|
+
if (runtime.rate !== void 0 && runtime.minor !== void 0) validationError("DISCOUNT_BOTH_FORMS", "A discount cannot include both percent and amount forms");
|
|
87
|
+
let result;
|
|
88
|
+
if (discount.kind === "none") {
|
|
89
|
+
if (runtime.rate !== void 0 || runtime.minor !== void 0) validationError("DISCOUNT_BOTH_FORMS", "A none discount cannot include percent or amount values");
|
|
90
|
+
result = 0n;
|
|
91
|
+
} else if (discount.kind === "percent") result = roundSignedRational(gross * percentUnits(discount.rate), PERCENT_DENOMINATOR);
|
|
92
|
+
else if (discount.kind === "amount") result = money(discount.minor);
|
|
93
|
+
else validationError("INVALID_MONEY_INPUT", "Unknown discount kind");
|
|
94
|
+
if (result !== 0n && gross !== 0n && result < 0n !== gross < 0n) validationError("DISCOUNT_SIGN", "Discount amount must carry the sign of gross");
|
|
95
|
+
if (gross === 0n && result !== 0n) validationError("DISCOUNT_SIGN", "A zero gross cannot carry a discount");
|
|
96
|
+
const magnitude = (value) => value < 0n ? -value : value;
|
|
97
|
+
if (magnitude(result) > magnitude(gross)) validationError("DISCOUNT_EXCEEDS_GROSS", "Discount cannot exceed gross");
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
function validateDocumentInput(input) {
|
|
101
|
+
if (!input || typeof input !== "object") validationError("INVALID_MONEY_INPUT", "Money input must be an object");
|
|
102
|
+
if (typeof input.currency !== "string" || !/^[A-Z]{3}$/.test(input.currency) || !ISO_4217_MINOR_UNITS.has(input.currency) || ISO_4217_MINOR_UNITS.get(input.currency) === null) validationError("CURRENCY_MISMATCH", "Currency must be a supported uppercase ISO 4217 code with minor units");
|
|
103
|
+
if (input.lineAmountType !== "exclusive" && input.lineAmountType !== "inclusive" && input.lineAmountType !== "none") validationError("INVALID_MONEY_INPUT", "Unknown line amount type");
|
|
104
|
+
if (input.roundingScope !== "line" && input.roundingScope !== "document") validationError("INVALID_MONEY_INPUT", "Unknown tax rounding scope");
|
|
105
|
+
if (!Array.isArray(input.lines)) validationError("INVALID_MONEY_INPUT", "Lines must be an array");
|
|
106
|
+
}
|
|
107
|
+
function calculateMoneyDocument(input) {
|
|
108
|
+
validateDocumentInput(input);
|
|
109
|
+
const ids = /* @__PURE__ */ new Set();
|
|
110
|
+
const rates = /* @__PURE__ */ new Map();
|
|
111
|
+
const working = input.lines.map((line) => {
|
|
112
|
+
if (!line || typeof line !== "object") validationError("INVALID_MONEY_INPUT", "Money line must be an object");
|
|
113
|
+
assertIdentifier(line.id, "Line ID");
|
|
114
|
+
if (ids.has(line.id)) validationError("INVALID_MONEY_INPUT", "Duplicate money line ID");
|
|
115
|
+
ids.add(line.id);
|
|
116
|
+
const explicitNet = line.netAmountMinor === void 0 ? null : money(line.netAmountMinor);
|
|
117
|
+
const quantity = numberDecimal(line.quantity, 6);
|
|
118
|
+
const gross = explicitNet ?? roundSignedRational(quantity.coefficient * money(line.unitPrice), quantity.scale);
|
|
119
|
+
safeMoney(gross);
|
|
120
|
+
const discount = explicitNet === null ? discountFor(gross, line.discount) : 0n;
|
|
121
|
+
const amount = gross - discount;
|
|
122
|
+
safeMoney(amount);
|
|
123
|
+
if (input.lineAmountType === "none" && !line.taxCode) validationError("TAX_CODE_NOT_FOUND", "None pricing requires an out-of-scope tax code");
|
|
124
|
+
if (input.lineAmountType === "none" && line.taxCode?.kind !== "out-of-scope") validationError("TAX_CODE_KIND", "None pricing requires an out-of-scope tax code");
|
|
125
|
+
const components = line.taxCode ? validateTaxCode(line.taxCode, rates) : [];
|
|
126
|
+
const totalRate = components.reduce((sum, component) => sum + component.rate, 0n);
|
|
127
|
+
const denominator = explicitNet === null && input.lineAmountType === "inclusive" ? PERCENT_DENOMINATOR + totalRate : PERCENT_DENOMINATOR;
|
|
128
|
+
return {
|
|
129
|
+
input: line,
|
|
130
|
+
gross,
|
|
131
|
+
discount,
|
|
132
|
+
amount,
|
|
133
|
+
explicitNet,
|
|
134
|
+
exact: input.lineAmountType === "none" ? [] : components.map((component) => ({
|
|
135
|
+
taxComponentId: component.taxComponentId,
|
|
136
|
+
numerator: amount * component.rate,
|
|
137
|
+
denominator
|
|
138
|
+
})),
|
|
139
|
+
taxes: /* @__PURE__ */ new Map()
|
|
140
|
+
};
|
|
141
|
+
});
|
|
142
|
+
if (input.roundingScope === "line") for (const line of working) for (const component of line.exact) line.taxes.set(component.taxComponentId, roundSignedRational(component.numerator, component.denominator));
|
|
143
|
+
else for (const componentId of [...rates.keys()].sort()) {
|
|
144
|
+
const eligible = working.flatMap((line) => {
|
|
145
|
+
const exact = line.exact.find((component) => component.taxComponentId === componentId);
|
|
146
|
+
return exact ? [{
|
|
147
|
+
line,
|
|
148
|
+
exact
|
|
149
|
+
}] : [];
|
|
150
|
+
});
|
|
151
|
+
const allocated = allocateSignedRationals(eligible.map(({ line, exact }) => ({
|
|
152
|
+
id: line.input.id,
|
|
153
|
+
numerator: exact.numerator,
|
|
154
|
+
denominator: exact.denominator
|
|
155
|
+
})));
|
|
156
|
+
for (const allocation of allocated.allocations) eligible.find(({ line }) => line.input.id === allocation.id)?.line.taxes.set(componentId, allocation.value);
|
|
157
|
+
}
|
|
158
|
+
const lines = working.map((line) => {
|
|
159
|
+
const components = line.exact.map((component) => ({
|
|
160
|
+
taxComponentId: component.taxComponentId,
|
|
161
|
+
taxMinor: safeMoney(line.taxes.get(component.taxComponentId) ?? 0n)
|
|
162
|
+
}));
|
|
163
|
+
const tax2 = components.reduce((sum, component) => sum + BigInt(component.taxMinor), 0n);
|
|
164
|
+
const net = line.explicitNet ?? (input.lineAmountType === "inclusive" ? line.amount - tax2 : line.amount);
|
|
165
|
+
const amount = line.explicitNet !== null && input.lineAmountType === "inclusive" ? net + tax2 : line.amount;
|
|
166
|
+
return {
|
|
167
|
+
id: line.input.id,
|
|
168
|
+
grossMinor: safeMoney(line.gross),
|
|
169
|
+
discountMinor: safeMoney(line.discount),
|
|
170
|
+
amountMinor: safeMoney(amount),
|
|
171
|
+
components,
|
|
172
|
+
taxMinor: safeMoney(tax2),
|
|
173
|
+
netMinor: safeMoney(net)
|
|
174
|
+
};
|
|
175
|
+
});
|
|
176
|
+
const taxRows = /* @__PURE__ */ new Map();
|
|
177
|
+
for (let index = 0; index < working.length; index++) {
|
|
178
|
+
const source = working[index].input;
|
|
179
|
+
const result = lines[index];
|
|
180
|
+
if (!source.taxCode || source.taxCode.components.length === 0 || input.lineAmountType === "none") {
|
|
181
|
+
const key = `${source.taxCode?.id ?? ""}\0`;
|
|
182
|
+
const row = taxRows.get(key) ?? {
|
|
183
|
+
taxCodeId: source.taxCode?.id ?? null,
|
|
184
|
+
taxComponentId: null,
|
|
185
|
+
taxableMinor: 0,
|
|
186
|
+
taxMinor: 0
|
|
187
|
+
};
|
|
188
|
+
row.taxableMinor = safeMoney(BigInt(row.taxableMinor) + BigInt(result.netMinor));
|
|
189
|
+
taxRows.set(key, row);
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
for (const component of result.components) {
|
|
193
|
+
if (!source.taxCode) validationError("INVALID_MONEY_INPUT", "Tax component requires a tax code");
|
|
194
|
+
const key = `${source.taxCode.id}\0${component.taxComponentId}`;
|
|
195
|
+
const row = taxRows.get(key) ?? {
|
|
196
|
+
taxCodeId: source.taxCode.id,
|
|
197
|
+
taxComponentId: component.taxComponentId,
|
|
198
|
+
taxableMinor: 0,
|
|
199
|
+
taxMinor: 0
|
|
200
|
+
};
|
|
201
|
+
row.taxableMinor = safeMoney(BigInt(row.taxableMinor) + BigInt(result.netMinor));
|
|
202
|
+
row.taxMinor = safeMoney(BigInt(row.taxMinor) + BigInt(component.taxMinor));
|
|
203
|
+
taxRows.set(key, row);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
const taxes = [...taxRows.values()].sort((left, right) => {
|
|
207
|
+
const leftCode = left.taxCodeId ?? "";
|
|
208
|
+
const rightCode = right.taxCodeId ?? "";
|
|
209
|
+
if (leftCode !== rightCode) return leftCode < rightCode ? -1 : 1;
|
|
210
|
+
const leftComponent = left.taxComponentId ?? "";
|
|
211
|
+
const rightComponent = right.taxComponentId ?? "";
|
|
212
|
+
return leftComponent < rightComponent ? -1 : leftComponent > rightComponent ? 1 : 0;
|
|
213
|
+
});
|
|
214
|
+
const subtotal = lines.reduce((sum, line) => sum + BigInt(line.netMinor), 0n);
|
|
215
|
+
const discountTotal = lines.reduce((sum, line) => sum + BigInt(line.discountMinor), 0n);
|
|
216
|
+
const tax = lines.reduce((sum, line) => sum + BigInt(line.taxMinor), 0n);
|
|
217
|
+
return {
|
|
218
|
+
lines,
|
|
219
|
+
subtotalMinor: safeMoney(subtotal),
|
|
220
|
+
discountTotalMinor: safeMoney(discountTotal),
|
|
221
|
+
taxMinor: safeMoney(tax),
|
|
222
|
+
totalMinor: safeMoney(subtotal + tax),
|
|
223
|
+
taxes
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
function selectedCode(id, source, context) {
|
|
227
|
+
if (!id) return null;
|
|
228
|
+
const taxCode = context.codes[id];
|
|
229
|
+
if (!taxCode) validationError("TAX_CODE_NOT_FOUND", `Unknown tax code: ${id}`);
|
|
230
|
+
if (typeof taxCode.active !== "boolean") validationError("INVALID_MONEY_INPUT", `Tax code ${id} has invalid state`);
|
|
231
|
+
if (!taxCode.active) validationError("TAX_CODE_INACTIVE", `Tax code ${id} is inactive`);
|
|
232
|
+
if (taxCode.appliesTo !== "sales" && taxCode.appliesTo !== "purchases" && taxCode.appliesTo !== "both") validationError("INVALID_MONEY_INPUT", `Tax code ${id} has invalid applicability`);
|
|
233
|
+
if (taxCode.appliesTo !== "both" && taxCode.appliesTo !== context.direction) validationError("TAX_CODE_SCOPE", `Tax code ${id} does not apply to ${context.direction}`);
|
|
234
|
+
return {
|
|
235
|
+
taxCode,
|
|
236
|
+
source
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
function resolveLineTaxCode(line, context) {
|
|
240
|
+
if (!line || typeof line !== "object" || !context || typeof context !== "object") validationError("INVALID_MONEY_INPUT", "Tax-code resolution inputs must be objects");
|
|
241
|
+
if (!context.codes || typeof context.codes !== "object") validationError("INVALID_MONEY_INPUT", "Tax-code map must be an object");
|
|
242
|
+
if (line.lineAmountType !== "exclusive" && line.lineAmountType !== "inclusive" && line.lineAmountType !== "none") validationError("INVALID_MONEY_INPUT", "Unknown line amount type");
|
|
243
|
+
if (context.direction !== "sales" && context.direction !== "purchases") validationError("INVALID_MONEY_INPUT", "Unknown tax-code direction");
|
|
244
|
+
if (line.lineAmountType === "none") {
|
|
245
|
+
if (!context.outOfScopeCodeId) validationError("TAX_CODE_NOT_FOUND", "None mode requires an out-of-scope tax code");
|
|
246
|
+
const resolved = selectedCode(context.outOfScopeCodeId, "none", context);
|
|
247
|
+
if (resolved?.taxCode?.kind !== "out-of-scope") validationError("TAX_CODE_KIND", "None mode requires an out-of-scope tax code");
|
|
248
|
+
return resolved;
|
|
249
|
+
}
|
|
250
|
+
if (context.customerTaxExempt && !line.lineOverride) {
|
|
251
|
+
if (!context.exemptCodeId) validationError("TAX_CODE_NOT_FOUND", "An exempt customer requires an exempt tax code");
|
|
252
|
+
const exempt = selectedCode(context.exemptCodeId, "exempt-customer", context);
|
|
253
|
+
if (exempt?.taxCode?.kind !== "exempt") validationError("TAX_CODE_KIND", "Customer exemption requires an exempt tax code");
|
|
254
|
+
return exempt;
|
|
255
|
+
}
|
|
256
|
+
const candidates = [
|
|
257
|
+
[line.lineOverride, "line"],
|
|
258
|
+
[context.productCodeId, "product"],
|
|
259
|
+
[context.partyCodeId, "customer"],
|
|
260
|
+
[context.appDefaultCodeId, "app"]
|
|
261
|
+
];
|
|
262
|
+
for (const [id, source] of candidates) {
|
|
263
|
+
const resolved = selectedCode(id, source, context);
|
|
264
|
+
if (resolved) return resolved;
|
|
265
|
+
}
|
|
266
|
+
return {
|
|
267
|
+
taxCode: null,
|
|
268
|
+
source: "none"
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
//#endregion
|
|
272
|
+
export { MoneyValidationError, assertIntegerMinorUnits, calculateMoneyDocument, resolveLineTaxCode };
|
|
273
|
+
|
|
274
|
+
//# sourceMappingURL=money.js.map
|