@happyvertical/smrt-commerce 0.55.15 → 0.55.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/agents/invoice-calculations.md +28 -1
  2. package/agents/payment-allocations.md +19 -0
  3. package/dist/chunks/{calculations-DwBf83UE.js → calculations-Bz7RB3qK.js} +36 -2
  4. package/dist/chunks/calculations-Bz7RB3qK.js.map +1 -0
  5. package/dist/chunks/{units-BhVZswof.js → units-BpZ0_Dpk.js} +2 -2
  6. package/dist/chunks/{units-BhVZswof.js.map → units-BpZ0_Dpk.js.map} +1 -1
  7. package/dist/index.js +29 -8
  8. package/dist/index.js.map +1 -1
  9. package/dist/invoices.js +1 -1
  10. package/dist/manifest.json +1 -1
  11. package/dist/models/Invoice.d.ts +5 -3
  12. package/dist/models/Invoice.d.ts.map +1 -1
  13. package/dist/smrt-knowledge.json +5 -5
  14. package/dist/svelte/components/CustomerDetail.svelte +4 -1
  15. package/dist/svelte/components/CustomerDirectory.svelte +4 -1
  16. package/dist/svelte/components/CustomerForm.svelte +3 -0
  17. package/dist/svelte/components/InvoiceActions.svelte +4 -1
  18. package/dist/svelte/components/InvoiceAllocationFields.svelte +4 -1
  19. package/dist/svelte/components/InvoiceCard.svelte +12 -9
  20. package/dist/svelte/components/InvoiceEditor.svelte +7 -3
  21. package/dist/svelte/components/InvoiceEditor.svelte.d.ts.map +1 -1
  22. package/dist/svelte/components/InvoiceHeader.svelte +25 -22
  23. package/dist/svelte/components/InvoiceLineEditor.svelte +8 -1
  24. package/dist/svelte/components/InvoiceLineEditor.svelte.d.ts.map +1 -1
  25. package/dist/svelte/components/InvoiceLineItems.svelte +29 -26
  26. package/dist/svelte/components/InvoiceReview.svelte +4 -1
  27. package/dist/svelte/components/InvoiceTotals.svelte +14 -11
  28. package/dist/svelte/components/PartyAddressFields.svelte +3 -0
  29. package/dist/svelte/components/PartyContactFields.svelte +4 -1
  30. package/dist/svelte/components/PricingVersionDecision.svelte +4 -1
  31. package/dist/svelte/components/PricingVersionSummary.svelte +4 -1
  32. package/dist/svelte/components/PurchaseOrderEditor.svelte +4 -1
  33. package/dist/svelte/components/PurchaseOrderHeaderForm.svelte +1 -1
  34. package/dist/svelte/components/PurchaseSourceSelector.svelte +7 -2
  35. package/dist/svelte/components/QuoteEditor.svelte +4 -1
  36. package/dist/svelte/components/QuoteRevisionComparison.svelte +4 -1
  37. package/dist/svelte/components/QuoteRevisionHistory.svelte +4 -1
  38. package/dist/svelte/components/UnbilledItems.svelte +27 -24
  39. package/dist/svelte/components/VendorDetail.svelte +4 -1
  40. package/dist/svelte/components/VendorDirectory.svelte +4 -1
  41. package/dist/svelte/components/VendorForm.svelte +3 -0
  42. package/dist/svelte/invoices/calculations.d.ts +12 -3
  43. package/dist/svelte/invoices/calculations.d.ts.map +1 -1
  44. package/dist/svelte/invoices/calculations.js +40 -1
  45. package/dist/svelte/invoices/messages.d.ts +1 -0
  46. package/dist/svelte/invoices/messages.d.ts.map +1 -1
  47. package/dist/svelte/invoices/messages.js +1 -0
  48. package/dist/svelte/invoices/types.d.ts +3 -2
  49. package/dist/svelte/invoices/types.d.ts.map +1 -1
  50. package/dist/svelte/playground/InvoicePreparationPreview.svelte +6 -1
  51. package/dist/svelte/playground/PartySelectPreview.svelte +4 -1
  52. package/package.json +9 -9
  53. package/dist/chunks/calculations-DwBf83UE.js.map +0 -1
@@ -132,7 +132,7 @@ function vendorMeta(vendor: VendorDisplayData): string {
132
132
  }
133
133
  </script>
134
134
 
135
- <section class="party-directory">
135
+ <section class="party-directory" data-smrt-component="VendorDirectory">
136
136
  <PageHeader title={plural} subtitle={labels.plural ? t(M['commerce.party.manage_named'], { plural }) : t(M['commerce.vendor.manage'])}>
137
137
  {#snippet actions()}
138
138
  {#if canCreate && addHref}<Button href={addHref}>{labels.add ?? (labels.singular ? t(M['commerce.party.add_named'], { singular }) : t(M['commerce.vendor.add']))}</Button>{/if}
@@ -199,6 +199,8 @@ function vendorMeta(vendor: VendorDisplayData): string {
199
199
  </section>
200
200
 
201
201
  <style>
202
+ @layer smrt.reset, smrt.structure, smrt.theme;
203
+ @layer smrt.theme {
202
204
  .party-directory { display: grid; gap: var(--smrt-spacing-5); max-inline-size: 64rem; min-inline-size: 0; }
203
205
  :global(.directory-search) { display: grid; grid-template-columns: minmax(12rem, 2fr) minmax(10rem, 1fr) auto; align-items: end; gap: var(--smrt-spacing-3); }
204
206
  :global(.directory-search .form-group) { margin: 0; min-inline-size: 0; }
@@ -212,4 +214,5 @@ function vendorMeta(vendor: VendorDisplayData): string {
212
214
  .meta { margin-block-start: var(--smrt-spacing-2); color: var(--smrt-color-on-surface-variant); }
213
215
  .pagination { display: flex; align-items: center; justify-content: center; gap: var(--smrt-spacing-3); }
214
216
  @media (max-width: 42rem) { :global(.directory-search) { grid-template-columns: minmax(0, 1fr); } :global(.directory-search .button) { inline-size: 100%; } .party-row { align-items: start; } }
217
+ }
215
218
  </style>
@@ -213,6 +213,8 @@ const errorList = $derived(
213
213
  </Form>
214
214
 
215
215
  <style>
216
+ @layer smrt.reset, smrt.structure, smrt.theme;
217
+ @layer smrt.theme {
216
218
  :global(.party-form) { display: grid; gap: var(--smrt-spacing-5); min-inline-size: 0; padding-block-end: var(--smrt-spacing-8); }
217
219
  .native-default-submit { position: absolute; inline-size: 1px; block-size: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
218
220
  .form-error { margin: 0; padding: var(--smrt-spacing-4); border-inline-start: 4px solid var(--smrt-color-error); background: var(--smrt-color-error-container); color: var(--smrt-color-on-error-container); border-radius: var(--smrt-radius-small); }
@@ -221,4 +223,5 @@ const errorList = $derived(
221
223
  .locked-value { color: var(--smrt-color-on-surface-variant); }
222
224
  .field-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 var(--smrt-spacing-4); }
223
225
  @media (max-width: 42rem) { .field-grid { grid-template-columns: minmax(0, 1fr); } }
226
+ }
224
227
  </style>
@@ -69,8 +69,17 @@ export type InvoiceLineCalculation = ({
69
69
  errors: Partial<Record<InvoiceLineField, InvoiceCalculationError>>;
70
70
  };
71
71
  /** Header error keys include whole-invoice totals and line membership. */
72
- export type InvoiceDraftField = Exclude<keyof InvoiceDraftValues, 'lines'> | 'lines' | 'total';
73
- /** Aggregate result retains every line result for granular rendering. */
72
+ export type InvoiceDraftField = Exclude<keyof InvoiceDraftValues, 'lines'> | 'lines' | 'total' | 'roundingScope';
73
+ /** Server-authorized tax rounding; absent means the historical per-line behavior. */
74
+ export interface InvoiceDraftCalculationOptions {
75
+ /** Invoice scope groups equal effective percentages and rounds each group once. */
76
+ roundingScope?: 'line' | 'invoice';
77
+ }
78
+ /**
79
+ * Aggregate result retains standalone line calculations for validation/audit.
80
+ * With invoice rounding, line tax/total are estimates, NOT allocated invoice
81
+ * amounts, and must not be summed or persisted as authoritative invoice tax.
82
+ */
74
83
  export type InvoiceDraftCalculation = ({
75
84
  valid: true;
76
85
  lineResults: readonly InvoiceLineCalculation[];
@@ -117,5 +126,5 @@ export declare function resolveInvoiceLineDraft(line: InvoiceLineDraft, context:
117
126
  */
118
127
  export declare function calculateInvoiceLine(line: InvoiceLineDraft, context: InvoiceCalculationContext): InvoiceLineCalculation;
119
128
  /** Validate the header and sum validated lines without floating-point arithmetic. */
120
- export declare function calculateInvoiceDraft(values: InvoiceDraftValues): InvoiceDraftCalculation;
129
+ export declare function calculateInvoiceDraft(values: InvoiceDraftValues, options?: InvoiceDraftCalculationOptions): InvoiceDraftCalculation;
121
130
  //# sourceMappingURL=calculations.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"calculations.d.ts","sourceRoot":"","sources":["../../../src/svelte/invoices/calculations.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"calculations.d.ts","sourceRoot":"","sources":["../../../src/svelte/invoices/calculations.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  /** Exact, transport-neutral invoice draft validation shared by browser and server. */
2
+ import { calculateCostBillingTax } from '../../cost-billing.js';
2
3
  import { currencyMinorUnitExponent } from './currency.js';
3
4
  const MAX_MINOR = BigInt(Number.MAX_SAFE_INTEGER);
4
5
  const MAX_TEXT = 128;
@@ -209,8 +210,11 @@ function calendarDate(value) {
209
210
  return (Number.isFinite(date.getTime()) && date.toISOString().slice(0, 10) === value);
210
211
  }
211
212
  /** Validate the header and sum validated lines without floating-point arithmetic. */
212
- export function calculateInvoiceDraft(values) {
213
+ export function calculateInvoiceDraft(values, options = {}) {
213
214
  const errors = {};
215
+ const roundingScope = options.roundingScope === undefined ? 'line' : options.roundingScope;
216
+ if (roundingScope !== 'line' && roundingScope !== 'invoice')
217
+ errors.roundingScope = 'invalid-mode';
214
218
  if (!values.customerId?.trim())
215
219
  errors.customerId = 'required';
216
220
  if (!calendarDate(values.issuedOn))
@@ -243,6 +247,41 @@ export function calculateInvoiceDraft(values) {
243
247
  for (const key of Object.keys(sums))
244
248
  sums[key] += BigInt(result[key]);
245
249
  }
250
+ if (roundingScope === 'invoice' &&
251
+ !Object.keys(errors).length &&
252
+ lineResults.every((result) => result.valid)) {
253
+ // Rates have already passed exact decimal validation. Normalize textual
254
+ // equivalents without numeric conversion before assigning component IDs.
255
+ const taxable = lineResults.map((result, index) => {
256
+ if (!result.valid)
257
+ throw new Error('Validated invoice line expected');
258
+ const [whole, fraction = ''] = result.effectiveTaxRate.split('.');
259
+ const digits = fraction.replace(/0+$/, '');
260
+ const percent = `${BigInt(whole)}${digits ? `.${digits}` : ''}`;
261
+ return {
262
+ id: values.lines[index].key,
263
+ amountMinor: result.subtotalMinor,
264
+ category: percent,
265
+ };
266
+ });
267
+ try {
268
+ const tax = calculateCostBillingTax({
269
+ lines: taxable,
270
+ rules: [...new Set(taxable.map((row) => row.category))].map((percent) => ({
271
+ category: percent,
272
+ components: [{ id: percent, percent }],
273
+ })),
274
+ roundingScope: 'invoice',
275
+ });
276
+ sums.taxMinor = BigInt(tax.taxMinor);
277
+ sums.totalMinor = sums.subtotalMinor + sums.taxMinor;
278
+ }
279
+ catch (cause) {
280
+ if (!(cause instanceof RangeError))
281
+ throw cause;
282
+ errors.total = 'range';
283
+ }
284
+ }
246
285
  if (Object.values(sums).some((value) => value > MAX_MINOR))
247
286
  errors.total = 'range';
248
287
  if (Object.keys(errors).length || lineResults.some((result) => !result.valid))
@@ -29,6 +29,7 @@ export declare const invoicePreparationMessages: {
29
29
  readonly 'commerce.invoice.tax': "commerce.invoice.tax";
30
30
  readonly 'commerce.invoice.total': "commerce.invoice.total";
31
31
  readonly 'commerce.invoice.invalid': "commerce.invoice.invalid";
32
+ readonly 'commerce.invoice.invoiceRounding': "commerce.invoice.invoiceRounding";
32
33
  readonly 'commerce.invoice.preview': "commerce.invoice.preview";
33
34
  readonly 'commerce.invoice.retained': "commerce.invoice.retained";
34
35
  readonly 'commerce.preparation.allocation': "commerce.preparation.allocation";
@@ -1 +1 @@
1
- {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../src/svelte/invoices/messages.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4DrC,CAAC"}
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../src/svelte/invoices/messages.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8DrC,CAAC"}
@@ -30,6 +30,7 @@ export const invoicePreparationMessages = defineMessages({
30
30
  'commerce.invoice.tax': 'Tax',
31
31
  'commerce.invoice.total': 'Total',
32
32
  'commerce.invoice.invalid': 'Totals unavailable until quantity, price, discount, tax and currency are valid.',
33
+ 'commerce.invoice.invoiceRounding': 'Tax is rounded across the invoice for each effective rate; see the invoice totals.',
33
34
  'commerce.invoice.preview': 'Calculated preview; the server revalidates prices, tax and totals.',
34
35
  'commerce.invoice.retained': 'Retained reference: {reference}',
35
36
  'commerce.preparation.allocation': 'Allocation {number}',
@@ -1,6 +1,7 @@
1
1
  import type { FormRetryStatus } from '@happyvertical/smrt-ui/form-retry';
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { HTMLFormAttributes } from 'svelte/elements';
4
+ import type { InvoiceDraftCalculationOptions } from './calculations.js';
4
5
  /** Authorized source projection supplied by the application, not fetched by UI. */
5
6
  export interface InvoicePreparationSource {
6
7
  /** Opaque source reference submitted verbatim. */
@@ -115,7 +116,7 @@ export interface InvoiceFieldNames {
115
116
  intent: string;
116
117
  }
117
118
  /** General invoice line fields; never renders a nested form. */
118
- export interface InvoiceLineEditorProps {
119
+ export interface InvoiceLineEditorProps extends InvoiceDraftCalculationOptions {
119
120
  /** Lossless caller-owned line values. */
120
121
  line: InvoiceLineDraft;
121
122
  /** Current currency code for shared calculation. */
@@ -142,7 +143,7 @@ export interface InvoiceLineEditorProps {
142
143
  onchange?: (line: InvoiceLineDraft) => void;
143
144
  }
144
145
  /** General native invoice editor with optional domain extensions. */
145
- export interface InvoiceEditorProps {
146
+ export interface InvoiceEditorProps extends InvoiceDraftCalculationOptions {
146
147
  /** Caller native endpoint. */
147
148
  action: string;
148
149
  /** Native method, default POST. */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/svelte/invoices/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/svelte/invoices/types.ts"],"names":[],"mappings":"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"}
@@ -113,4 +113,9 @@ function submit(event: SubmitEvent & { currentTarget: HTMLFormElement }) {
113
113
  {/snippet}
114
114
  </InvoiceEditor>
115
115
  </div>
116
- <style>.preview { display: grid; gap: var(--smrt-spacing-4); }</style>
116
+ <style>
117
+ @layer smrt.reset, smrt.structure, smrt.theme;
118
+ @layer smrt.theme {
119
+ .preview { display: grid; gap: var(--smrt-spacing-4); }
120
+ }
121
+ </style>
@@ -96,13 +96,16 @@ const match = <T extends { profile: { name: string } }>(
96
96
  </div>
97
97
 
98
98
  <style>
99
+ @layer smrt.reset, smrt.structure, smrt.theme;
100
+ @layer smrt.theme {
99
101
  .preview {
100
102
  display: grid;
101
- gap: var(--smrt-spacing-2, 8px);
103
+ gap: var(--smrt-spacing-2);
102
104
  max-width: 28rem;
103
105
  color: var(--smrt-color-on-surface);
104
106
  }
105
107
  p {
106
108
  margin: 0;
107
109
  }
110
+ }
108
111
  </style>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happyvertical/smrt-commerce",
3
- "version": "0.55.15",
3
+ "version": "0.55.17",
4
4
  "smrtJsdoc": "strict",
5
5
  "description": "Commerce models for the SMRT framework - contracts, fulfillments, payments",
6
6
  "type": "module",
@@ -61,13 +61,13 @@
61
61
  "dependencies": {
62
62
  "@happyvertical/accounting": "^0.103.4",
63
63
  "@happyvertical/payments": "^0.103.4",
64
- "@happyvertical/smrt-core": "0.55.15",
65
- "@happyvertical/smrt-jobs": "0.55.15",
66
- "@happyvertical/smrt-ledgers": "0.55.15",
67
- "@happyvertical/smrt-subscriptions": "0.55.15",
68
- "@happyvertical/smrt-tenancy": "0.55.15",
69
- "@happyvertical/smrt-types": "0.55.15",
70
- "@happyvertical/smrt-ui": "0.55.15"
64
+ "@happyvertical/smrt-core": "0.55.17",
65
+ "@happyvertical/smrt-jobs": "0.55.17",
66
+ "@happyvertical/smrt-ledgers": "0.55.17",
67
+ "@happyvertical/smrt-subscriptions": "0.55.17",
68
+ "@happyvertical/smrt-tenancy": "0.55.17",
69
+ "@happyvertical/smrt-types": "0.55.17",
70
+ "@happyvertical/smrt-ui": "0.55.17"
71
71
  },
72
72
  "peerDependencies": {
73
73
  "svelte": "^5.57.0"
@@ -78,7 +78,7 @@
78
78
  }
79
79
  },
80
80
  "devDependencies": {
81
- "@happyvertical/smrt-vitest": "0.55.15",
81
+ "@happyvertical/smrt-vitest": "0.55.17",
82
82
  "@sveltejs/package": "^2.5.8",
83
83
  "@sveltejs/vite-plugin-svelte": "^7.3.0",
84
84
  "@testing-library/jest-dom": "^7.0.1",
@@ -1 +0,0 @@
1
- {"version":3,"file":"calculations-DwBf83UE.js","names":[],"sources":["../../src/svelte/invoices/currency.ts","../../src/svelte/invoices/calculations.ts"],"sourcesContent":["/** Svelte-free currency precision shared by invoice previews and billing. */\n\nimport { ISO_4217_MINOR_UNITS } from '@happyvertical/smrt-ui/currency';\n\nconst CURRENCY_PATTERN = /^[A-Z]{3}$/;\n\n/** Upper-case, validate, and return an ISO 4217-shaped currency code. */\nexport function normalizeCurrency(currency: string): string {\n const code = String(currency ?? '')\n .trim()\n .toUpperCase();\n if (!CURRENCY_PATTERN.test(code)) {\n throw new Error(`Currency '${currency}' must be a three-letter code.`);\n }\n return code;\n}\n\n/**\n * The ISO 4217 minor-unit exponent of a currency (2 for USD and RSD, 0 for\n * JPY, 3 for IQD). Unknown codes and currencies without a minor unit fail\n * closed because assigning either an inferred or invented exponent changes\n * the represented amount.\n */\nexport function currencyMinorUnitExponent(currency: string): number {\n const code = normalizeCurrency(currency);\n const exponent = ISO_4217_MINOR_UNITS.get(code);\n if (exponent === undefined)\n throw new Error(`Unsupported currency '${code}'.`);\n if (exponent === null)\n throw new Error(`Currency '${code}' does not define a minor unit.`);\n return exponent;\n}\n","/** Exact, transport-neutral invoice draft validation shared by browser and server. */\nimport { currencyMinorUnitExponent } from './currency.js';\n\n/** Unparsed editable invoice line; invalid values remain caller-owned. */\nexport interface InvoiceLineDraft {\n /** Stable caller-owned row identity. */\n key: string;\n /** Human-readable item description. */\n description: string;\n /** Optional stock or service code. */\n sku: string;\n /** Nonnegative decimal quantity, at most six decimal places. */\n quantity: string;\n /** Unit price in currency major units. */\n unitPrice: string;\n /** Flat major-unit discount or percentage; unknown drafts remain representable. */\n discountType: string;\n /** Discount in major units or percent according to discountType. */\n discountValue: string;\n /** Inherit the authorized default or use an explicit override. */\n taxMode: string;\n /** Override percent; zero is an explicit exemption, not inheritance. */\n taxRate: string;\n}\n\n/** Editable header and lines; clients never supply authoritative calculated totals. */\nexport interface InvoiceDraftValues {\n /** Customer reference; authorization/existence must be checked by the server. */\n customerId: string;\n /** Calendar issue date, YYYY-MM-DD. */\n issuedOn: string;\n /** Calendar due date, YYYY-MM-DD. */\n dueOn: string;\n /** Uppercase three-letter currency, with Commerce's explicit minor-unit table. */\n currency: string;\n /** Free-form payment terms. */\n paymentTerms: string;\n /** Default tax percent; the server must substitute its authorized rate. */\n taxRate: string;\n /** Caller-owned ordered lines. */\n lines: readonly InvoiceLineDraft[];\n}\n\n/** Fields on which line validation may report an error. */\nexport type InvoiceLineField = keyof InvoiceLineDraft;\n/** Stable validation reasons for caller-localized error messages. */\nexport type InvoiceCalculationError =\n | 'required'\n | 'invalid-decimal'\n | 'precision'\n | 'range'\n | 'invalid-mode'\n | 'discount-exceeds-gross'\n | 'invalid-date'\n | 'duplicate-key'\n | 'invalid-currency';\n/** Currency and server-authorized inherited percentage for a line. */\nexport interface InvoiceCalculationContext {\n /** Uppercase currency code. */\n currency: string;\n /** Default tax percent, for example \"5\". */\n inheritedTaxRate: string;\n}\n/** All monetary outputs are safe integer minor units. */\nexport interface InvoiceCalculatedAmounts {\n /** Rounded quantity times unit price before discounts. */\n grossMinor: number;\n /** Discount rounded to minor units before tax. */\n discountMinor: number;\n /** Gross less discount. */\n subtotalMinor: number;\n /** Rounded tax on the discounted subtotal. */\n taxMinor: number;\n /** Subtotal plus tax. */\n totalMinor: number;\n}\n/** Success or field errors, with no plausible monetary output for an invalid line. */\nexport type InvoiceLineCalculation =\n | ({ valid: true; effectiveTaxRate: string } & InvoiceCalculatedAmounts)\n | {\n valid: false;\n errors: Partial<Record<InvoiceLineField, InvoiceCalculationError>>;\n };\n/** Header error keys include whole-invoice totals and line membership. */\nexport type InvoiceDraftField =\n | Exclude<keyof InvoiceDraftValues, 'lines'>\n | 'lines'\n | 'total';\n/** Aggregate result retains every line result for granular rendering. */\nexport type InvoiceDraftCalculation =\n | ({\n valid: true;\n lineResults: readonly InvoiceLineCalculation[];\n } & InvoiceCalculatedAmounts)\n | {\n valid: false;\n errors: Partial<Record<InvoiceDraftField, InvoiceCalculationError>>;\n lineResults: readonly InvoiceLineCalculation[];\n };\n\ninterface Decimal {\n coefficient: bigint;\n scale: bigint;\n}\nconst MAX_MINOR = BigInt(Number.MAX_SAFE_INTEGER);\nconst MAX_TEXT = 128;\n\nfunction decimal(\n value: string,\n precision: number,\n): Decimal | InvoiceCalculationError {\n if (\n typeof value !== 'string' ||\n value.length > MAX_TEXT ||\n !/^\\d+(?:\\.\\d+)?$/.test(value)\n )\n return 'invalid-decimal';\n const [whole, fraction = ''] = value.split('.');\n if (fraction.length > precision) return 'precision';\n return {\n coefficient: BigInt(whole + fraction),\n scale: 10n ** BigInt(fraction.length),\n };\n}\n\nfunction roundHalfUp(numerator: bigint, denominator: bigint): bigint {\n return (numerator * 2n + denominator) / (denominator * 2n);\n}\n\nfunction minor(\n value: string,\n digits: number,\n): bigint | InvoiceCalculationError {\n const parsed = decimal(value, MAX_TEXT);\n if (typeof parsed === 'string') return parsed;\n const scaled = parsed.coefficient * 10n ** BigInt(digits);\n if (scaled % parsed.scale !== 0n) return 'precision';\n const result = scaled / parsed.scale;\n return result > MAX_MINOR ? 'range' : result;\n}\n\nfunction rate(value: string): Decimal | InvoiceCalculationError {\n const parsed = decimal(value, 6);\n if (typeof parsed === 'string') return parsed;\n return parsed.coefficient > 100n * parsed.scale ? 'range' : parsed;\n}\n\n/** Existing model monetary inputs, independent of currency display precision. */\nexport interface InvoiceMinorLineInput {\n /** Nonnegative quantity with at most six fractional digits. */\n quantity: number;\n /** Signed integer minor units; negative prices support existing credit lines. */\n unitPrice: number;\n /** Nonnegative flat discount in integer minor units. */\n discount: number;\n /** Resolved tax fraction, at most eight fractional digits, in [0, 1]. */\n taxRate: number;\n}\n\nfunction numberDecimal(value: number, precision: number): Decimal {\n if (!Number.isFinite(value) || value < 0 || value > Number.MAX_SAFE_INTEGER)\n throw new RangeError(\n 'Invoice rate or quantity is outside the supported range.',\n );\n // The shortest canonical decimal preserves the caller's Number. toFixed can\n // invent different decimal digits that round back to that same binary value.\n const [mantissa, exponent = '0'] = value.toString().split('e');\n const [whole, fraction = ''] = mantissa.split('.');\n const places = fraction.length - Number(exponent);\n if (places > precision)\n throw new RangeError(\n 'Invoice rate or quantity exceeds the supported decimal precision.',\n );\n const coefficient = BigInt(whole + fraction);\n return places < 0\n ? { coefficient: coefficient * 10n ** BigInt(-places), scale: 1n }\n : { coefficient, scale: 10n ** BigInt(places) };\n}\n\nfunction roundSigned(numerator: bigint, denominator: bigint): bigint {\n // Preserve Math.round's existing credit-line ties toward positive infinity.\n return numerator >= 0n\n ? roundHalfUp(numerator, denominator)\n : -((-numerator * 2n + denominator - 1n) / (denominator * 2n));\n}\n\n/**\n * Exact model calculation, including existing negative-price credit lines.\n * Throws before persistence for unsafe money, invalid quantity, or invalid tax.\n */\nexport function calculateInvoiceMinorLine(\n input: InvoiceMinorLineInput,\n): InvoiceCalculatedAmounts {\n for (const amount of [input.unitPrice, input.discount])\n if (!Number.isSafeInteger(amount))\n throw new RangeError('Invoice money must be safe integer minor units.');\n if (input.discount < 0 || input.taxRate > 1)\n throw new RangeError(\n 'Invoice discount or tax rate is outside the supported range.',\n );\n const quantity = numberDecimal(input.quantity, 6);\n const tax = numberDecimal(input.taxRate, 8);\n const gross = roundSigned(\n quantity.coefficient * BigInt(input.unitPrice),\n quantity.scale,\n );\n const discount = BigInt(input.discount);\n const subtotal = gross - discount;\n const taxMinor = roundSigned(subtotal * tax.coefficient, tax.scale);\n const total = subtotal + taxMinor;\n for (const amount of [gross, subtotal, taxMinor, total])\n if (amount > MAX_MINOR || amount < -MAX_MINOR)\n throw new RangeError(\n 'Invoice line amount exceeds safe integer minor units.',\n );\n return {\n grossMinor: Number(gross),\n discountMinor: input.discount,\n subtotalMinor: Number(subtotal),\n taxMinor: Number(taxMinor),\n totalMinor: Number(total),\n };\n}\n\n/** Validated line fields suitable for the existing model's resolved money columns. */\nexport interface InvoiceResolvedLine extends InvoiceMinorLineInput {\n /** Validated item description. */\n description: string;\n /** Caller stock code. */\n sku: string;\n /** Recomputed total; never copied from a browser total field. */\n amount: number;\n}\n\n/**\n * Resolve a validated editor draft to model fields. Percentage discounts become\n * exact flat minor units; inherited tax becomes the authorized effective rate.\n * Keep the raw draft alongside these fields when reopening its editing modes.\n */\nexport function resolveInvoiceLineDraft(\n line: InvoiceLineDraft,\n context: InvoiceCalculationContext,\n): InvoiceResolvedLine {\n const result = calculateInvoiceLine(line, context);\n if (!result.valid)\n throw new RangeError(\n `Invalid invoice line: ${JSON.stringify(result.errors)}`,\n );\n const quantity = Number(line.quantity);\n const sourceQuantity = decimal(line.quantity, 6);\n const storedQuantity = numberDecimal(quantity, 6);\n if (\n typeof sourceQuantity === 'string' ||\n sourceQuantity.coefficient * storedQuantity.scale !==\n storedQuantity.coefficient * sourceQuantity.scale\n )\n throw new RangeError(\n 'Invoice quantity cannot round-trip through numeric persistence.',\n );\n const [whole, fraction = ''] = result.effectiveTaxRate.split('.');\n const rateDigits = BigInt(whole + fraction)\n .toString()\n .padStart(fraction.length + 3, '0');\n const split = rateDigits.length - fraction.length - 2;\n const taxRate = Number(\n `${rateDigits.slice(0, split)}.${rateDigits.slice(split)}`,\n );\n const unitPrice = minor(\n line.unitPrice,\n currencyMinorUnitExponent(context.currency),\n );\n if (typeof unitPrice !== 'bigint')\n throw new RangeError('Invalid invoice unit price.');\n const resolved = {\n description: line.description,\n sku: line.sku,\n quantity,\n unitPrice: Number(unitPrice),\n discount: result.discountMinor,\n taxRate,\n amount: result.totalMinor,\n };\n const model = calculateInvoiceMinorLine(resolved);\n if (\n model.totalMinor !== result.totalMinor ||\n model.subtotalMinor !== result.subtotalMinor ||\n model.taxMinor !== result.taxMinor\n )\n throw new RangeError('Invoice draft and persisted calculation disagree.');\n return resolved;\n}\n\n/**\n * Validate and calculate one line using decimal integer arithmetic. Round half\n * up separately at gross, percentage discount, and tax boundaries. No rounding\n * is permitted when parsing a price or flat discount into currency minor units.\n */\nexport function calculateInvoiceLine(\n line: InvoiceLineDraft,\n context: InvoiceCalculationContext,\n): InvoiceLineCalculation {\n const errors: Partial<Record<InvoiceLineField, InvoiceCalculationError>> = {};\n if (!line.key?.trim()) errors.key = 'required';\n if (!line.description?.trim()) errors.description = 'required';\n if (!/^[A-Z]{3}$/.test(context.currency))\n return { valid: false, errors: { unitPrice: 'invalid-currency' } };\n const digits = currencyMinorUnitExponent(context.currency);\n const quantity = decimal(line.quantity, 6);\n const price = minor(line.unitPrice, digits);\n if (typeof quantity === 'string') errors.quantity = quantity;\n else if (quantity.coefficient > MAX_MINOR * quantity.scale)\n errors.quantity = 'range';\n else {\n try {\n const persisted = numberDecimal(Number(line.quantity), 6);\n if (\n quantity.coefficient * persisted.scale !==\n persisted.coefficient * quantity.scale\n )\n errors.quantity = 'precision';\n } catch {\n errors.quantity = 'precision';\n }\n }\n if (typeof price === 'string') errors.unitPrice = price;\n if (line.discountType !== 'flat' && line.discountType !== 'percent')\n errors.discountType = 'invalid-mode';\n if (line.taxMode !== 'inherit' && line.taxMode !== 'override')\n errors.taxMode = 'invalid-mode';\n const discount =\n line.discountType === 'percent'\n ? rate(line.discountValue)\n : minor(line.discountValue, digits);\n if (typeof discount === 'string') errors.discountValue = discount;\n const effectiveTaxRate =\n line.taxMode === 'inherit' ? context.inheritedTaxRate : line.taxRate;\n const tax = rate(effectiveTaxRate);\n if (typeof tax === 'string') errors.taxRate = tax;\n if (\n Object.keys(errors).length ||\n typeof quantity === 'string' ||\n typeof price === 'string' ||\n typeof discount === 'string' ||\n typeof tax === 'string'\n )\n return { valid: false, errors };\n const gross = roundHalfUp(quantity.coefficient * price, quantity.scale);\n const reduction =\n typeof discount === 'bigint'\n ? discount\n : roundHalfUp(gross * discount.coefficient, discount.scale * 100n);\n if (gross > MAX_MINOR) return { valid: false, errors: { quantity: 'range' } };\n if (reduction > gross)\n return {\n valid: false,\n errors: { discountValue: 'discount-exceeds-gross' },\n };\n const subtotal = gross - reduction;\n const taxMinor = roundHalfUp(subtotal * tax.coefficient, tax.scale * 100n);\n const total = subtotal + taxMinor;\n if (total > MAX_MINOR) return { valid: false, errors: { taxRate: 'range' } };\n return {\n valid: true,\n effectiveTaxRate,\n grossMinor: Number(gross),\n discountMinor: Number(reduction),\n subtotalMinor: Number(subtotal),\n taxMinor: Number(taxMinor),\n totalMinor: Number(total),\n };\n}\n\nfunction calendarDate(value: string): boolean {\n if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(value) || value.startsWith('0000'))\n return false;\n const date = new Date(`${value}T00:00:00.000Z`);\n return (\n Number.isFinite(date.getTime()) && date.toISOString().slice(0, 10) === value\n );\n}\n\n/** Validate the header and sum validated lines without floating-point arithmetic. */\nexport function calculateInvoiceDraft(\n values: InvoiceDraftValues,\n): InvoiceDraftCalculation {\n const errors: Partial<Record<InvoiceDraftField, InvoiceCalculationError>> =\n {};\n if (!values.customerId?.trim()) errors.customerId = 'required';\n if (!calendarDate(values.issuedOn)) errors.issuedOn = 'invalid-date';\n if (!calendarDate(values.dueOn) || values.dueOn < values.issuedOn)\n errors.dueOn = 'invalid-date';\n if (!/^[A-Z]{3}$/.test(values.currency)) errors.currency = 'invalid-currency';\n const inheritedRate = rate(values.taxRate);\n if (typeof inheritedRate === 'string') errors.taxRate = inheritedRate;\n if (values.lines.length === 0) errors.lines = 'required';\n if (\n new Set(values.lines.map((line) => line.key)).size !== values.lines.length\n )\n errors.lines = 'duplicate-key';\n const lineResults = values.lines.map((line) =>\n calculateInvoiceLine(line, {\n currency: values.currency,\n inheritedTaxRate: values.taxRate,\n }),\n );\n const sums = {\n grossMinor: 0n,\n discountMinor: 0n,\n subtotalMinor: 0n,\n taxMinor: 0n,\n totalMinor: 0n,\n };\n for (const result of lineResults) {\n if (!result.valid) continue;\n for (const key of Object.keys(sums) as Array<keyof typeof sums>)\n sums[key] += BigInt(result[key]);\n }\n if (Object.values(sums).some((value) => value > MAX_MINOR))\n errors.total = 'range';\n if (Object.keys(errors).length || lineResults.some((result) => !result.valid))\n return { valid: false, errors, lineResults };\n return {\n valid: true,\n lineResults,\n grossMinor: Number(sums.grossMinor),\n discountMinor: Number(sums.discountMinor),\n subtotalMinor: Number(sums.subtotalMinor),\n taxMinor: Number(sums.taxMinor),\n totalMinor: Number(sums.totalMinor),\n };\n}\n"],"mappings":"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"}