@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.
Files changed (186) hide show
  1. package/AGENTS.md +24 -11
  2. package/README.md +159 -93
  3. package/agents/accounting-snapshot-mapper.md +3 -3
  4. package/agents/commercial-ui.md +2 -2
  5. package/agents/contract-money.md +9 -6
  6. package/agents/cost-billing.md +3 -6
  7. package/agents/customer-vendor-ui.md +6 -1
  8. package/agents/document-money.md +59 -31
  9. package/agents/invoice-calculations.md +31 -56
  10. package/agents/invoice-preparation.md +62 -73
  11. package/agents/invoice-quantity.md +9 -21
  12. package/agents/minor-unit-migration.md +4 -4
  13. package/agents/money-calculator.md +7 -8
  14. package/agents/money-model.md +18 -22
  15. package/agents/money-upgrade.md +92 -0
  16. package/agents/revenue-journal.md +2 -2
  17. package/agents/tax-codes.md +17 -14
  18. package/agents/tax-summary.md +12 -8
  19. package/dist/billing/period-close.d.ts.map +1 -1
  20. package/dist/billing/runtime.d.ts +5 -2
  21. package/dist/billing/runtime.d.ts.map +1 -1
  22. package/dist/chunks/{ContractLineItemCollection-DYjhj_pU.js → ContractLineItemCollection-BZcrlrrY.js} +22 -27
  23. package/dist/chunks/ContractLineItemCollection-BZcrlrrY.js.map +1 -0
  24. package/dist/chunks/{CustomerCollection-DQIujn4f.js → CustomerCollection-BIPH2ZUx.js} +3 -3
  25. package/dist/chunks/{CustomerCollection-DQIujn4f.js.map → CustomerCollection-BIPH2ZUx.js.map} +1 -1
  26. package/dist/chunks/{DocumentTaxCollection-BEpoqXAQ.js → DocumentTaxCollection-DDzlywMW.js} +41 -14
  27. package/dist/chunks/DocumentTaxCollection-DDzlywMW.js.map +1 -0
  28. package/dist/chunks/{InvoiceCollection-CKQflFjc.js → InvoiceCollection-cinzAqt6.js} +53 -164
  29. package/dist/chunks/InvoiceCollection-cinzAqt6.js.map +1 -0
  30. package/dist/chunks/{TaxCodeCollection-DOpzW4y8.js → TaxCodeCollection-DaBOPG9c.js} +11 -4
  31. package/dist/chunks/{TaxCodeCollection-DOpzW4y8.js.map → TaxCodeCollection-DaBOPG9c.js.map} +1 -1
  32. package/dist/chunks/{TaxComponentCollection-Cs2uXwEl.js → TaxComponentCollection-C4zxnyVu.js} +3 -3
  33. package/dist/chunks/{TaxComponentCollection-Cs2uXwEl.js.map → TaxComponentCollection-C4zxnyVu.js.map} +1 -1
  34. package/dist/chunks/VendorCollection-D6ZcUYy8.js +100 -0
  35. package/dist/chunks/VendorCollection-D6ZcUYy8.js.map +1 -0
  36. package/dist/chunks/{allocation-integrity-DI3G16BN.js → allocation-integrity-WmWyXhtG.js} +6 -6
  37. package/dist/chunks/{allocation-integrity-DI3G16BN.js.map → allocation-integrity-WmWyXhtG.js.map} +1 -1
  38. package/dist/chunks/calculations-C9daQLsh.js +82 -0
  39. package/dist/chunks/calculations-C9daQLsh.js.map +1 -0
  40. package/dist/chunks/contract-money-EuToOghh.js +301 -0
  41. package/dist/chunks/contract-money-EuToOghh.js.map +1 -0
  42. package/dist/chunks/detect-CY9ufaFb.js +328 -0
  43. package/dist/chunks/detect-CY9ufaFb.js.map +1 -0
  44. package/dist/chunks/{document-money-DNVhDJyC.js → document-money-DV5t4vlK.js} +389 -63
  45. package/dist/chunks/document-money-DV5t4vlK.js.map +1 -0
  46. package/dist/chunks/{invoice-posting-BwV8g7z0.js → invoice-posting-C2i5dOVZ.js} +21 -23
  47. package/dist/chunks/invoice-posting-C2i5dOVZ.js.map +1 -0
  48. package/dist/chunks/{revenue-journal-DY9fro8E.js → revenue-journal-LLA9Kh_i.js} +3 -14
  49. package/dist/chunks/revenue-journal-LLA9Kh_i.js.map +1 -0
  50. package/dist/chunks/tenant-money-barrier-6TlqUeVj.js +255 -0
  51. package/dist/chunks/tenant-money-barrier-6TlqUeVj.js.map +1 -0
  52. package/dist/chunks/{types-LDETvQ1C.js → types-Bbm0Xflc.js} +2 -1
  53. package/dist/chunks/types-Bbm0Xflc.js.map +1 -0
  54. package/dist/chunks/{units-CNcjH_eE.js → units-8ElbjVZK.js} +18 -3
  55. package/dist/chunks/units-8ElbjVZK.js.map +1 -0
  56. package/dist/collections/ContractCollection.d.ts.map +1 -1
  57. package/dist/collections/ContractLineItemCollection.d.ts.map +1 -1
  58. package/dist/collections/InvoiceCollection.d.ts.map +1 -1
  59. package/dist/collections/InvoiceLineItemCollection.d.ts +0 -30
  60. package/dist/collections/InvoiceLineItemCollection.d.ts.map +1 -1
  61. package/dist/collections/TaxCodeCollection.d.ts +5 -1
  62. package/dist/collections/TaxCodeCollection.d.ts.map +1 -1
  63. package/dist/collections/TaxSettingsCollection.d.ts +15 -8
  64. package/dist/collections/TaxSettingsCollection.d.ts.map +1 -1
  65. package/dist/collections/TaxSummaryReportCollection.d.ts +3 -3
  66. package/dist/collections/TaxSummaryReportCollection.d.ts.map +1 -1
  67. package/dist/collections/index.d.ts +0 -1
  68. package/dist/collections/index.d.ts.map +1 -1
  69. package/dist/commerce-money-tools.d.ts.map +1 -1
  70. package/dist/contract-money.d.ts +1 -13
  71. package/dist/contract-money.d.ts.map +1 -1
  72. package/dist/document-money-internal.d.ts +7 -3
  73. package/dist/document-money-internal.d.ts.map +1 -1
  74. package/dist/document-money.d.ts +1 -11
  75. package/dist/document-money.d.ts.map +1 -1
  76. package/dist/index.d.ts +6 -5
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +686 -1656
  79. package/dist/index.js.map +1 -1
  80. package/dist/invoice-accounting-sync.d.ts.map +1 -1
  81. package/dist/invoice-mcp.d.ts +3 -3
  82. package/dist/invoice-mcp.d.ts.map +1 -1
  83. package/dist/invoice-posting.d.ts +11 -5
  84. package/dist/invoice-posting.d.ts.map +1 -1
  85. package/dist/invoice-record-screen.d.ts +1 -1
  86. package/dist/invoice-record-screen.d.ts.map +1 -1
  87. package/dist/invoices.d.ts +6 -1
  88. package/dist/invoices.d.ts.map +1 -1
  89. package/dist/invoices.js +2 -2
  90. package/dist/manifest.json +1041 -863
  91. package/dist/migrations/invoiceEditorStorage.d.ts +2 -4
  92. package/dist/migrations/invoiceEditorStorage.d.ts.map +1 -1
  93. package/dist/migrations/partyLinks.d.ts.map +1 -1
  94. package/dist/models/Contract.d.ts +10 -4
  95. package/dist/models/Contract.d.ts.map +1 -1
  96. package/dist/models/ContractLineItem.d.ts +9 -17
  97. package/dist/models/ContractLineItem.d.ts.map +1 -1
  98. package/dist/models/DocumentTax.d.ts.map +1 -1
  99. package/dist/models/Invoice.d.ts +18 -48
  100. package/dist/models/Invoice.d.ts.map +1 -1
  101. package/dist/models/InvoiceLineItem.d.ts +13 -32
  102. package/dist/models/InvoiceLineItem.d.ts.map +1 -1
  103. package/dist/models/TaxSettings.d.ts +0 -10
  104. package/dist/models/TaxSettings.d.ts.map +1 -1
  105. package/dist/models/index.d.ts +1 -2
  106. package/dist/models/index.d.ts.map +1 -1
  107. package/dist/playground.js +1 -1
  108. package/dist/playground.js.map +1 -1
  109. package/dist/recipes.d.ts +8 -11
  110. package/dist/recipes.d.ts.map +1 -1
  111. package/dist/revenue-journal.d.ts +0 -8
  112. package/dist/revenue-journal.d.ts.map +1 -1
  113. package/dist/smrt-knowledge.json +2886 -6121
  114. package/dist/svelte/components/InvoiceEditor.svelte +7 -148
  115. package/dist/svelte/components/InvoiceEditor.svelte.d.ts +4 -1
  116. package/dist/svelte/components/InvoiceEditor.svelte.d.ts.map +1 -1
  117. package/dist/svelte/components/InvoiceTotals.svelte +14 -118
  118. package/dist/svelte/components/InvoiceTotals.svelte.d.ts +4 -27
  119. package/dist/svelte/components/InvoiceTotals.svelte.d.ts.map +1 -1
  120. package/dist/svelte/components/MoneyInvoiceEditor.svelte +3 -23
  121. package/dist/svelte/components/MoneyInvoiceEditor.svelte.d.ts +3 -26
  122. package/dist/svelte/components/MoneyInvoiceEditor.svelte.d.ts.map +1 -1
  123. package/dist/svelte/index.d.ts +2 -3
  124. package/dist/svelte/index.d.ts.map +1 -1
  125. package/dist/svelte/index.js +1 -2
  126. package/dist/svelte/invoices/calculations.d.ts +3 -108
  127. package/dist/svelte/invoices/calculations.d.ts.map +1 -1
  128. package/dist/svelte/invoices/calculations.js +12 -309
  129. package/dist/svelte/invoices/messages.d.ts +1 -37
  130. package/dist/svelte/invoices/messages.d.ts.map +1 -1
  131. package/dist/svelte/invoices/messages.js +1 -37
  132. package/dist/svelte/invoices/money-editor.d.ts +1 -1
  133. package/dist/svelte/invoices/money-editor.d.ts.map +1 -1
  134. package/dist/svelte/invoices/types.d.ts +14 -114
  135. package/dist/svelte/invoices/types.d.ts.map +1 -1
  136. package/dist/svelte/playground/InvoicePreparationPreview.svelte +85 -94
  137. package/dist/svelte/playground/InvoicePreparationPreview.svelte.d.ts.map +1 -1
  138. package/dist/svelte/playground.js +1 -1
  139. package/dist/tax/index.d.ts +2 -1
  140. package/dist/tax/index.d.ts.map +1 -1
  141. package/dist/tax/standard-codes.d.ts +12 -0
  142. package/dist/tax/standard-codes.d.ts.map +1 -0
  143. package/dist/tax/tenant-bootstrap.d.ts +29 -0
  144. package/dist/tax/tenant-bootstrap.d.ts.map +1 -0
  145. package/dist/tenant-money-barrier.d.ts +12 -44
  146. package/dist/tenant-money-barrier.d.ts.map +1 -1
  147. package/dist/types/index.d.ts +11 -23
  148. package/dist/types/index.d.ts.map +1 -1
  149. package/dist/ui.js +1 -1
  150. package/dist/ui.js.map +1 -1
  151. package/dist/upgrade/detect.d.ts +129 -0
  152. package/dist/upgrade/detect.d.ts.map +1 -0
  153. package/dist/upgrade/money-v2.d.ts +81 -0
  154. package/dist/upgrade/money-v2.d.ts.map +1 -0
  155. package/package.json +14 -13
  156. package/agents/line-amount-migration.md +0 -50
  157. package/dist/chunks/ContractLineItemCollection-DYjhj_pU.js.map +0 -1
  158. package/dist/chunks/DocumentTaxCollection-BEpoqXAQ.js.map +0 -1
  159. package/dist/chunks/InvoiceCollection-CKQflFjc.js.map +0 -1
  160. package/dist/chunks/InvoiceLineItemCollection-CHm9zdqh.js +0 -467
  161. package/dist/chunks/InvoiceLineItemCollection-CHm9zdqh.js.map +0 -1
  162. package/dist/chunks/TaxSettingsCollection-BBTZDH1S.js +0 -319
  163. package/dist/chunks/TaxSettingsCollection-BBTZDH1S.js.map +0 -1
  164. package/dist/chunks/calculations-DaHR17il.js +0 -333
  165. package/dist/chunks/calculations-DaHR17il.js.map +0 -1
  166. package/dist/chunks/document-money-DNVhDJyC.js.map +0 -1
  167. package/dist/chunks/invoice-posting-BwV8g7z0.js.map +0 -1
  168. package/dist/chunks/revenue-journal-DY9fro8E.js.map +0 -1
  169. package/dist/chunks/tenant-money-barrier-DjRXgMnX.js +0 -135
  170. package/dist/chunks/tenant-money-barrier-DjRXgMnX.js.map +0 -1
  171. package/dist/chunks/types-LDETvQ1C.js.map +0 -1
  172. package/dist/chunks/units-CNcjH_eE.js.map +0 -1
  173. package/dist/collections/MoneyMigrationDocumentCollection.d.ts +0 -12
  174. package/dist/collections/MoneyMigrationDocumentCollection.d.ts.map +0 -1
  175. package/dist/migrations/commerceLineAmounts.d.ts +0 -84
  176. package/dist/migrations/commerceLineAmounts.d.ts.map +0 -1
  177. package/dist/models/MoneyMigrationDocument.d.ts +0 -28
  178. package/dist/models/MoneyMigrationDocument.d.ts.map +0 -1
  179. package/dist/svelte/components/InvoiceLineEditor.svelte +0 -92
  180. package/dist/svelte/components/InvoiceLineEditor.svelte.d.ts +0 -8
  181. package/dist/svelte/components/InvoiceLineEditor.svelte.d.ts.map +0 -1
  182. package/dist/svelte/invoices/fields.d.ts +0 -6
  183. package/dist/svelte/invoices/fields.d.ts.map +0 -1
  184. package/dist/svelte/invoices/fields.js +0 -22
  185. package/dist/tax/legacy.d.ts +0 -48
  186. package/dist/tax/legacy.d.ts.map +0 -1
@@ -1,57 +1,8 @@
1
- /** Unparsed editable invoice line; invalid values remain caller-owned. */
2
- export interface InvoiceLineDraft {
3
- /** Stable caller-owned row identity. */
4
- key: string;
5
- /** Human-readable item description. */
6
- description: string;
7
- /** Optional stock or service code. */
8
- sku: string;
9
- /** Nonnegative decimal quantity, at most six decimal places. */
10
- quantity: string;
11
- /** Unit price in currency major units. */
12
- unitPrice: string;
13
- /** Flat major-unit discount or percentage; unknown drafts remain representable. */
14
- discountType: string;
15
- /** Discount in major units or percent according to discountType. */
16
- discountValue: string;
17
- /** Inherit the authorized default or use an explicit override. */
18
- taxMode: string;
19
- /** Override percent; zero is an explicit exemption, not inheritance. */
20
- taxRate: string;
21
- }
22
- /** Editable header and lines; clients never supply authoritative calculated totals. */
23
- export interface InvoiceDraftValues {
24
- /** Customer reference; authorization/existence must be checked by the server. */
25
- customerId: string;
26
- /** Calendar issue date, YYYY-MM-DD. */
27
- issuedOn: string;
28
- /** Calendar due date, YYYY-MM-DD. */
29
- dueOn: string;
30
- /** Uppercase three-letter currency, with Commerce's explicit minor-unit table. */
31
- currency: string;
32
- /** Free-form payment terms. */
33
- paymentTerms: string;
34
- /** Default tax percent; the server must substitute its authorized rate. */
35
- taxRate: string;
36
- /** Caller-owned ordered lines. */
37
- lines: readonly InvoiceLineDraft[];
38
- }
39
- /** Fields on which line validation may report an error. */
40
- export type InvoiceLineField = keyof InvoiceLineDraft;
41
- /** Stable validation reasons for caller-localized error messages. */
42
- export type InvoiceCalculationError = 'required' | 'invalid-decimal' | 'precision' | 'range' | 'invalid-mode' | 'discount-exceeds-gross' | 'invalid-date' | 'duplicate-key' | 'invalid-currency';
43
- /** Currency and server-authorized inherited percentage for a line. */
44
- export interface InvoiceCalculationContext {
45
- /** Uppercase currency code. */
46
- currency: string;
47
- /** Default tax percent, for example "5". */
48
- inheritedTaxRate: string;
49
- }
50
1
  /** All monetary outputs are safe integer minor units. */
51
2
  export interface InvoiceCalculatedAmounts {
52
3
  /** Rounded quantity times unit price before discounts. */
53
4
  grossMinor: number;
54
- /** Discount rounded to minor units before tax. */
5
+ /** Discount in minor units before tax; it carries the gross sign. */
55
6
  discountMinor: number;
56
7
  /** Gross less discount. */
57
8
  subtotalMinor: number;
@@ -60,76 +11,20 @@ export interface InvoiceCalculatedAmounts {
60
11
  /** Subtotal plus tax. */
61
12
  totalMinor: number;
62
13
  }
63
- /** Success or field errors, with no plausible monetary output for an invalid line. */
64
- export type InvoiceLineCalculation = ({
65
- valid: true;
66
- effectiveTaxRate: string;
67
- } & InvoiceCalculatedAmounts) | {
68
- valid: false;
69
- errors: Partial<Record<InvoiceLineField, InvoiceCalculationError>>;
70
- };
71
- /** Header error keys include whole-invoice totals and line membership. */
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
- */
83
- export type InvoiceDraftCalculation = ({
84
- valid: true;
85
- lineResults: readonly InvoiceLineCalculation[];
86
- } & InvoiceCalculatedAmounts) | {
87
- valid: false;
88
- errors: Partial<Record<InvoiceDraftField, InvoiceCalculationError>>;
89
- lineResults: readonly InvoiceLineCalculation[];
90
- };
91
14
  /** Existing model monetary inputs, independent of currency display precision. */
92
15
  export interface InvoiceMinorLineInput {
93
16
  /** Nonnegative quantity with at most six fractional digits. */
94
17
  quantity: number;
95
18
  /** Signed integer minor units; negative prices support existing credit lines. */
96
19
  unitPrice: number;
97
- /** Legacy uses a nonnegative flat discount; v2 stores the gross sign. */
20
+ /** Flat discount in signed integer minor units; it carries the gross sign. */
98
21
  discount: number;
99
22
  /** Resolved tax fraction, at most eight fractional digits, in [0, 1]. */
100
23
  taxRate: number;
101
24
  }
102
- /** Explicit migration boundary for persisted legacy invoice-line arithmetic. */
103
- export interface InvoiceMinorLineCalculationOptions {
104
- /** Existing callers remain legacy until #3933's per-tenant marker selects v2. */
105
- moneyModel?: 'legacy' | 'v2';
106
- }
107
25
  /**
108
26
  * Exact model calculation, including existing negative-price credit lines.
109
27
  * Throws before persistence for unsafe money, invalid quantity, or invalid tax.
110
28
  */
111
- export declare function calculateInvoiceMinorLine(input: InvoiceMinorLineInput, options?: InvoiceMinorLineCalculationOptions): InvoiceCalculatedAmounts;
112
- /** Validated line fields suitable for the existing model's resolved money columns. */
113
- export interface InvoiceResolvedLine extends InvoiceMinorLineInput {
114
- /** Validated item description. */
115
- description: string;
116
- /** Caller stock code. */
117
- sku: string;
118
- /** Recomputed total; never copied from a browser total field. */
119
- amount: number;
120
- }
121
- /**
122
- * Resolve a validated editor draft to model fields. Percentage discounts become
123
- * exact flat minor units; inherited tax becomes the authorized effective rate.
124
- * Keep the raw draft alongside these fields when reopening its editing modes.
125
- */
126
- export declare function resolveInvoiceLineDraft(line: InvoiceLineDraft, context: InvoiceCalculationContext): InvoiceResolvedLine;
127
- /**
128
- * Validate and calculate one line using decimal integer arithmetic. Round half
129
- * up separately at gross, percentage discount, and tax boundaries. No rounding
130
- * is permitted when parsing a price or flat discount into currency minor units.
131
- */
132
- export declare function calculateInvoiceLine(line: InvoiceLineDraft, context: InvoiceCalculationContext): InvoiceLineCalculation;
133
- /** Validate the header and sum validated lines without floating-point arithmetic. */
134
- export declare function calculateInvoiceDraft(values: InvoiceDraftValues, options?: InvoiceDraftCalculationOptions): InvoiceDraftCalculation;
29
+ export declare function calculateInvoiceMinorLine(input: InvoiceMinorLineInput): InvoiceCalculatedAmounts;
135
30
  //# 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":"AAQA,yDAAyD;AACzD,MAAM,WAAW,wBAAwB;IACvC,0DAA0D;IAC1D,UAAU,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,aAAa,EAAE,MAAM,CAAC;IACtB,2BAA2B;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,yBAAyB;IACzB,UAAU,EAAE,MAAM,CAAC;CACpB;AAOD,iFAAiF;AACjF,MAAM,WAAW,qBAAqB;IACpC,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,SAAS,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;CACjB;AAsDD;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,qBAAqB,GAC3B,wBAAwB,CA2C1B"}
@@ -1,40 +1,5 @@
1
- /** Exact, transport-neutral invoice draft validation shared by browser and server. */
1
+ /** Exact, transport-neutral invoice line calculation shared by browser and server. */
2
2
  import { calculateMoneyDocument, MoneyValidationError, } from '../../money.js';
3
- import { currencyMinorUnitExponent } from './currency.js';
4
- const MAX_MINOR = BigInt(Number.MAX_SAFE_INTEGER);
5
- const MAX_TEXT = 128;
6
- function decimal(value, precision) {
7
- if (typeof value !== 'string' ||
8
- value.length > MAX_TEXT ||
9
- !/^\d+(?:\.\d+)?$/.test(value))
10
- return 'invalid-decimal';
11
- const [whole, fraction = ''] = value.split('.');
12
- if (fraction.length > precision)
13
- return 'precision';
14
- return {
15
- coefficient: BigInt(whole + fraction),
16
- scale: 10n ** BigInt(fraction.length),
17
- };
18
- }
19
- function roundHalfUp(numerator, denominator) {
20
- return (numerator * 2n + denominator) / (denominator * 2n);
21
- }
22
- function minor(value, digits) {
23
- const parsed = decimal(value, MAX_TEXT);
24
- if (typeof parsed === 'string')
25
- return parsed;
26
- const scaled = parsed.coefficient * 10n ** BigInt(digits);
27
- if (scaled % parsed.scale !== 0n)
28
- return 'precision';
29
- const result = scaled / parsed.scale;
30
- return result > MAX_MINOR ? 'range' : result;
31
- }
32
- function rate(value) {
33
- const parsed = decimal(value, 6);
34
- if (typeof parsed === 'string')
35
- return parsed;
36
- return parsed.coefficient > 100n * parsed.scale ? 'range' : parsed;
37
- }
38
3
  function numberDecimal(value, precision) {
39
4
  if (!Number.isFinite(value) || value < 0 || value > Number.MAX_SAFE_INTEGER)
40
5
  throw new RangeError('Invoice rate or quantity is outside the supported range.');
@@ -50,11 +15,6 @@ function numberDecimal(value, precision) {
50
15
  ? { coefficient: coefficient * 10n ** BigInt(-places), scale: 1n }
51
16
  : { coefficient, scale: 10n ** BigInt(places) };
52
17
  }
53
- function roundSignedLegacy(numerator, denominator) {
54
- return numerator >= 0n
55
- ? roundHalfUp(numerator, denominator)
56
- : -((-numerator * 2n + denominator - 1n) / (denominator * 2n));
57
- }
58
18
  function decimalText(value) {
59
19
  if (value.scale === 1n)
60
20
  return value.coefficient.toString();
@@ -65,19 +25,20 @@ function decimalText(value) {
65
25
  .replace(/0+$/, '')
66
26
  .replace(/\.$/, '');
67
27
  }
68
- function legacyTaxCode(percent) {
28
+ /** An in-memory single-rate tax code for editor previews of a percent rate. */
29
+ function rateTaxCode(percent) {
69
30
  const normalized = percent
70
31
  .replace(/^0+(?=\d)/, '')
71
32
  .replace(/(\.\d*?)0+$/, '$1')
72
33
  .replace(/\.$/, '') || '0';
73
34
  return normalized === '0'
74
- ? { id: 'legacy-zero', kind: 'zero-rated', components: [] }
35
+ ? { id: 'rate-zero', kind: 'zero-rated', components: [] }
75
36
  : {
76
- id: `legacy-${normalized}`,
37
+ id: `rate-${normalized}`,
77
38
  kind: 'taxable',
78
39
  components: [
79
40
  {
80
- taxComponentId: `legacy-${normalized}`,
41
+ taxComponentId: `rate-${normalized}`,
81
42
  percent: normalized,
82
43
  compound: false,
83
44
  },
@@ -88,34 +49,14 @@ function legacyTaxCode(percent) {
88
49
  * Exact model calculation, including existing negative-price credit lines.
89
50
  * Throws before persistence for unsafe money, invalid quantity, or invalid tax.
90
51
  */
91
- export function calculateInvoiceMinorLine(input, options = {}) {
52
+ export function calculateInvoiceMinorLine(input) {
92
53
  for (const amount of [input.unitPrice, input.discount])
93
54
  if (!Number.isSafeInteger(amount))
94
55
  throw new RangeError('Invoice money must be safe integer minor units.');
95
- const moneyModel = options.moneyModel ?? 'legacy';
96
- if ((moneyModel === 'legacy' && input.discount < 0) || input.taxRate > 1)
97
- throw new RangeError('Invoice discount or tax rate is outside the supported range.');
98
- const quantity = numberDecimal(input.quantity, 6);
56
+ if (input.taxRate > 1)
57
+ throw new RangeError('Invoice tax rate is outside the supported range.');
58
+ numberDecimal(input.quantity, 6);
99
59
  const tax = numberDecimal(input.taxRate, 8);
100
- if (moneyModel === 'legacy') {
101
- const gross = roundSignedLegacy(quantity.coefficient * BigInt(input.unitPrice), quantity.scale);
102
- const discount = BigInt(input.discount);
103
- const subtotal = gross - discount;
104
- const taxMinor = roundSignedLegacy(subtotal * tax.coefficient, tax.scale);
105
- const total = subtotal + taxMinor;
106
- for (const amount of [gross, subtotal, taxMinor, total])
107
- if (amount > MAX_MINOR || amount < -MAX_MINOR)
108
- throw new RangeError('Invoice line amount exceeds safe integer minor units.');
109
- return {
110
- grossMinor: Number(gross),
111
- discountMinor: input.discount,
112
- subtotalMinor: Number(subtotal),
113
- taxMinor: Number(taxMinor),
114
- totalMinor: Number(total),
115
- };
116
- }
117
- if (moneyModel !== 'v2')
118
- throw new TypeError('Unknown invoice money model');
119
60
  const percent = decimalText({
120
61
  coefficient: tax.coefficient * 100n,
121
62
  scale: tax.scale,
@@ -128,13 +69,13 @@ export function calculateInvoiceMinorLine(input, options = {}) {
128
69
  roundingScope: 'line',
129
70
  lines: [
130
71
  {
131
- id: 'legacy-line',
72
+ id: 'line',
132
73
  quantity: input.quantity,
133
74
  unitPrice: input.unitPrice,
134
75
  discount: input.discount === 0
135
76
  ? { kind: 'none' }
136
77
  : { kind: 'amount', minor: input.discount },
137
- taxCode: legacyTaxCode(percent),
78
+ taxCode: rateTaxCode(percent),
138
79
  },
139
80
  ],
140
81
  }).lines[0];
@@ -152,241 +93,3 @@ export function calculateInvoiceMinorLine(input, options = {}) {
152
93
  totalMinor: result.netMinor + result.taxMinor,
153
94
  };
154
95
  }
155
- /**
156
- * Resolve a validated editor draft to model fields. Percentage discounts become
157
- * exact flat minor units; inherited tax becomes the authorized effective rate.
158
- * Keep the raw draft alongside these fields when reopening its editing modes.
159
- */
160
- export function resolveInvoiceLineDraft(line, context) {
161
- const result = calculateInvoiceLine(line, context);
162
- if (!result.valid)
163
- throw new RangeError(`Invalid invoice line: ${JSON.stringify(result.errors)}`);
164
- const quantity = Number(line.quantity);
165
- const sourceQuantity = decimal(line.quantity, 6);
166
- const storedQuantity = numberDecimal(quantity, 6);
167
- if (typeof sourceQuantity === 'string' ||
168
- sourceQuantity.coefficient * storedQuantity.scale !==
169
- storedQuantity.coefficient * sourceQuantity.scale)
170
- throw new RangeError('Invoice quantity cannot round-trip through numeric persistence.');
171
- const [whole, fraction = ''] = result.effectiveTaxRate.split('.');
172
- const rateDigits = BigInt(whole + fraction)
173
- .toString()
174
- .padStart(fraction.length + 3, '0');
175
- const split = rateDigits.length - fraction.length - 2;
176
- const taxRate = Number(`${rateDigits.slice(0, split)}.${rateDigits.slice(split)}`);
177
- const unitPrice = minor(line.unitPrice, currencyMinorUnitExponent(context.currency));
178
- if (typeof unitPrice !== 'bigint')
179
- throw new RangeError('Invalid invoice unit price.');
180
- const resolved = {
181
- description: line.description,
182
- sku: line.sku,
183
- quantity,
184
- unitPrice: Number(unitPrice),
185
- discount: result.discountMinor,
186
- taxRate,
187
- amount: result.totalMinor,
188
- };
189
- const model = calculateInvoiceMinorLine(resolved);
190
- if (model.totalMinor !== result.totalMinor ||
191
- model.subtotalMinor !== result.subtotalMinor ||
192
- model.taxMinor !== result.taxMinor)
193
- throw new RangeError('Invoice draft and persisted calculation disagree.');
194
- return resolved;
195
- }
196
- /**
197
- * Validate and calculate one line using decimal integer arithmetic. Round half
198
- * up separately at gross, percentage discount, and tax boundaries. No rounding
199
- * is permitted when parsing a price or flat discount into currency minor units.
200
- */
201
- export function calculateInvoiceLine(line, context) {
202
- const errors = {};
203
- if (!line.key?.trim())
204
- errors.key = 'required';
205
- if (!line.description?.trim())
206
- errors.description = 'required';
207
- if (!/^[A-Z]{3}$/.test(context.currency))
208
- return { valid: false, errors: { unitPrice: 'invalid-currency' } };
209
- const digits = currencyMinorUnitExponent(context.currency);
210
- const quantity = decimal(line.quantity, 6);
211
- const price = minor(line.unitPrice, digits);
212
- if (typeof quantity === 'string')
213
- errors.quantity = quantity;
214
- else if (quantity.coefficient > MAX_MINOR * quantity.scale)
215
- errors.quantity = 'range';
216
- else {
217
- try {
218
- const persisted = numberDecimal(Number(line.quantity), 6);
219
- if (quantity.coefficient * persisted.scale !==
220
- persisted.coefficient * quantity.scale)
221
- errors.quantity = 'precision';
222
- }
223
- catch {
224
- errors.quantity = 'precision';
225
- }
226
- }
227
- if (typeof price === 'string')
228
- errors.unitPrice = price;
229
- if (line.discountType !== 'flat' && line.discountType !== 'percent')
230
- errors.discountType = 'invalid-mode';
231
- if (line.taxMode !== 'inherit' && line.taxMode !== 'override')
232
- errors.taxMode = 'invalid-mode';
233
- const discount = line.discountType === 'percent'
234
- ? rate(line.discountValue)
235
- : minor(line.discountValue, digits);
236
- if (typeof discount === 'string')
237
- errors.discountValue = discount;
238
- const effectiveTaxRate = line.taxMode === 'inherit' ? context.inheritedTaxRate : line.taxRate;
239
- const tax = rate(effectiveTaxRate);
240
- if (typeof tax === 'string')
241
- errors.taxRate = tax;
242
- if (Object.keys(errors).length ||
243
- typeof quantity === 'string' ||
244
- typeof price === 'string' ||
245
- typeof discount === 'string' ||
246
- typeof tax === 'string')
247
- return { valid: false, errors };
248
- let calculated;
249
- try {
250
- calculated = calculateMoneyDocument({
251
- currency: context.currency,
252
- lineAmountType: 'exclusive',
253
- roundingScope: 'line',
254
- lines: [
255
- {
256
- id: line.key,
257
- quantity: Number(line.quantity),
258
- unitPrice: Number(price),
259
- discount: line.discountType === 'percent'
260
- ? { kind: 'percent', rate: line.discountValue }
261
- : discount === 0n
262
- ? { kind: 'none' }
263
- : { kind: 'amount', minor: Number(discount) },
264
- taxCode: legacyTaxCode(effectiveTaxRate),
265
- },
266
- ],
267
- }).lines[0];
268
- }
269
- catch (cause) {
270
- if (cause instanceof Error &&
271
- 'code' in cause &&
272
- cause.code === 'DISCOUNT_EXCEEDS_GROSS')
273
- return {
274
- valid: false,
275
- errors: { discountValue: 'discount-exceeds-gross' },
276
- };
277
- return { valid: false, errors: { taxRate: 'range' } };
278
- }
279
- return {
280
- valid: true,
281
- effectiveTaxRate,
282
- grossMinor: calculated.grossMinor,
283
- discountMinor: calculated.discountMinor,
284
- subtotalMinor: calculated.netMinor,
285
- taxMinor: calculated.taxMinor,
286
- totalMinor: calculated.netMinor + calculated.taxMinor,
287
- };
288
- }
289
- function calendarDate(value) {
290
- if (!/^\d{4}-\d{2}-\d{2}$/.test(value) || value.startsWith('0000'))
291
- return false;
292
- const date = new Date(`${value}T00:00:00.000Z`);
293
- return (Number.isFinite(date.getTime()) && date.toISOString().slice(0, 10) === value);
294
- }
295
- /** Validate the header and sum validated lines without floating-point arithmetic. */
296
- export function calculateInvoiceDraft(values, options = {}) {
297
- const errors = {};
298
- const roundingScope = options.roundingScope === undefined ? 'line' : options.roundingScope;
299
- if (roundingScope !== 'line' && roundingScope !== 'invoice')
300
- errors.roundingScope = 'invalid-mode';
301
- if (!values.customerId?.trim())
302
- errors.customerId = 'required';
303
- if (!calendarDate(values.issuedOn))
304
- errors.issuedOn = 'invalid-date';
305
- if (!calendarDate(values.dueOn) || values.dueOn < values.issuedOn)
306
- errors.dueOn = 'invalid-date';
307
- if (!/^[A-Z]{3}$/.test(values.currency))
308
- errors.currency = 'invalid-currency';
309
- const inheritedRate = rate(values.taxRate);
310
- if (typeof inheritedRate === 'string')
311
- errors.taxRate = inheritedRate;
312
- if (values.lines.length === 0)
313
- errors.lines = 'required';
314
- if (new Set(values.lines.map((line) => line.key)).size !== values.lines.length)
315
- errors.lines = 'duplicate-key';
316
- const lineResults = values.lines.map((line) => calculateInvoiceLine(line, {
317
- currency: values.currency,
318
- inheritedTaxRate: values.taxRate,
319
- }));
320
- const sums = {
321
- grossMinor: 0n,
322
- discountMinor: 0n,
323
- subtotalMinor: 0n,
324
- taxMinor: 0n,
325
- totalMinor: 0n,
326
- };
327
- for (const result of lineResults) {
328
- if (!result.valid)
329
- continue;
330
- for (const key of Object.keys(sums))
331
- sums[key] += BigInt(result[key]);
332
- }
333
- if (roundingScope === 'invoice' &&
334
- !Object.keys(errors).length &&
335
- lineResults.every((result) => result.valid)) {
336
- // Rates have already passed exact decimal validation. Normalize textual
337
- // equivalents without numeric conversion before assigning component IDs.
338
- const taxable = lineResults.map((result, index) => {
339
- if (!result.valid)
340
- throw new Error('Validated invoice line expected');
341
- const [whole, fraction = ''] = result.effectiveTaxRate.split('.');
342
- const digits = fraction.replace(/0+$/, '');
343
- const percent = `${BigInt(whole)}${digits ? `.${digits}` : ''}`;
344
- return {
345
- id: values.lines[index].key,
346
- amountMinor: result.subtotalMinor,
347
- category: percent,
348
- };
349
- });
350
- try {
351
- const calculated = calculateMoneyDocument({
352
- currency: values.currency,
353
- lineAmountType: 'exclusive',
354
- roundingScope: 'document',
355
- lines: taxable.map((row, index) => {
356
- const result = lineResults[index];
357
- if (!result.valid)
358
- throw new Error('Validated invoice line expected');
359
- return {
360
- id: row.id,
361
- quantity: 1,
362
- unitPrice: result.grossMinor,
363
- discount: result.discountMinor === 0
364
- ? { kind: 'none' }
365
- : { kind: 'amount', minor: result.discountMinor },
366
- taxCode: legacyTaxCode(row.category),
367
- };
368
- }),
369
- });
370
- sums.taxMinor = BigInt(calculated.taxMinor);
371
- sums.totalMinor = sums.subtotalMinor + sums.taxMinor;
372
- }
373
- catch (cause) {
374
- if (!(cause instanceof RangeError || cause instanceof MoneyValidationError))
375
- throw cause;
376
- errors.total = 'range';
377
- }
378
- }
379
- if (Object.values(sums).some((value) => value > MAX_MINOR))
380
- errors.total = 'range';
381
- if (Object.keys(errors).length || lineResults.some((result) => !result.valid))
382
- return { valid: false, errors, lineResults };
383
- return {
384
- valid: true,
385
- lineResults,
386
- grossMinor: Number(sums.grossMinor),
387
- discountMinor: Number(sums.discountMinor),
388
- subtotalMinor: Number(sums.subtotalMinor),
389
- taxMinor: Number(sums.taxMinor),
390
- totalMinor: Number(sums.totalMinor),
391
- };
392
- }
@@ -1,37 +1,5 @@
1
+ /** Messages for the invoice allocation fields and review presentation. */
1
2
  export declare const invoicePreparationMessages: {
2
- readonly 'commerce.preparation.title': "commerce.preparation.title";
3
- readonly 'commerce.invoice.customer': "commerce.invoice.customer";
4
- readonly 'commerce.invoice.chooseCustomer': "commerce.invoice.chooseCustomer";
5
- readonly 'commerce.invoice.issued': "commerce.invoice.issued";
6
- readonly 'commerce.invoice.due': "commerce.invoice.due";
7
- readonly 'commerce.invoice.currency': "commerce.invoice.currency";
8
- readonly 'commerce.invoice.terms': "commerce.invoice.terms";
9
- readonly 'commerce.invoice.defaultTax': "commerce.invoice.defaultTax";
10
- readonly 'commerce.invoice.line': "commerce.invoice.line";
11
- readonly 'commerce.invoice.description': "commerce.invoice.description";
12
- readonly 'commerce.invoice.sku': "commerce.invoice.sku";
13
- readonly 'commerce.invoice.quantity': "commerce.invoice.quantity";
14
- readonly 'commerce.invoice.unitPrice': "commerce.invoice.unitPrice";
15
- readonly 'commerce.invoice.discountType': "commerce.invoice.discountType";
16
- readonly 'commerce.invoice.flat': "commerce.invoice.flat";
17
- readonly 'commerce.invoice.percent': "commerce.invoice.percent";
18
- readonly 'commerce.invoice.discountValue': "commerce.invoice.discountValue";
19
- readonly 'commerce.invoice.taxMode': "commerce.invoice.taxMode";
20
- readonly 'commerce.invoice.inherit': "commerce.invoice.inherit";
21
- readonly 'commerce.invoice.override': "commerce.invoice.override";
22
- readonly 'commerce.invoice.taxRate': "commerce.invoice.taxRate";
23
- readonly 'commerce.invoice.remove': "commerce.invoice.remove";
24
- readonly 'commerce.invoice.add': "commerce.invoice.add";
25
- readonly 'commerce.invoice.empty': "commerce.invoice.empty";
26
- readonly 'commerce.invoice.gross': "commerce.invoice.gross";
27
- readonly 'commerce.invoice.discount': "commerce.invoice.discount";
28
- readonly 'commerce.invoice.subtotal': "commerce.invoice.subtotal";
29
- readonly 'commerce.invoice.tax': "commerce.invoice.tax";
30
- readonly 'commerce.invoice.total': "commerce.invoice.total";
31
- readonly 'commerce.invoice.invalid': "commerce.invoice.invalid";
32
- readonly 'commerce.invoice.invoiceRounding': "commerce.invoice.invoiceRounding";
33
- readonly 'commerce.invoice.preview': "commerce.invoice.preview";
34
- readonly 'commerce.invoice.retained': "commerce.invoice.retained";
35
3
  readonly 'commerce.preparation.allocation': "commerce.preparation.allocation";
36
4
  readonly 'commerce.preparation.source': "commerce.preparation.source";
37
5
  readonly 'commerce.preparation.reference': "commerce.preparation.reference";
@@ -42,13 +10,9 @@ export declare const invoicePreparationMessages: {
42
10
  readonly 'commerce.preparation.help': "commerce.preparation.help";
43
11
  readonly 'commerce.preparation.remove': "commerce.preparation.remove";
44
12
  readonly 'commerce.preparation.add': "commerce.preparation.add";
45
- readonly 'commerce.preparation.save': "commerce.preparation.save";
46
- readonly 'commerce.preparation.cancel': "commerce.preparation.cancel";
47
13
  readonly 'commerce.preparation.restricted': "commerce.preparation.restricted";
48
14
  readonly 'commerce.preparation.empty': "commerce.preparation.empty";
49
15
  readonly 'commerce.preparation.no_rows': "commerce.preparation.no_rows";
50
- readonly 'commerce.preparation.readonly': "commerce.preparation.readonly";
51
- readonly 'commerce.preparation.uncertain': "commerce.preparation.uncertain";
52
16
  readonly 'commerce.preparation.review': "commerce.preparation.review";
53
17
  };
54
18
  //# sourceMappingURL=messages.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../src/svelte/invoices/messages.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8DrC,CAAC"}
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../src/svelte/invoices/messages.ts"],"names":[],"mappings":"AAEA,0EAA0E;AAC1E,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;CAoBrC,CAAC"}
@@ -1,38 +1,6 @@
1
1
  import { defineMessages } from '@happyvertical/smrt-ui/i18n';
2
+ /** Messages for the invoice allocation fields and review presentation. */
2
3
  export const invoicePreparationMessages = defineMessages({
3
- 'commerce.preparation.title': 'Prepare invoice',
4
- 'commerce.invoice.customer': 'Customer',
5
- 'commerce.invoice.chooseCustomer': 'Choose a customer',
6
- 'commerce.invoice.issued': 'Invoice date',
7
- 'commerce.invoice.due': 'Due date',
8
- 'commerce.invoice.currency': 'Currency',
9
- 'commerce.invoice.terms': 'Payment terms',
10
- 'commerce.invoice.defaultTax': 'Default tax (%)',
11
- 'commerce.invoice.line': 'Invoice line {number}',
12
- 'commerce.invoice.description': 'Description',
13
- 'commerce.invoice.sku': 'SKU',
14
- 'commerce.invoice.quantity': 'Quantity',
15
- 'commerce.invoice.unitPrice': 'Unit price ({currency})',
16
- 'commerce.invoice.discountType': 'Discount type',
17
- 'commerce.invoice.flat': 'Flat amount',
18
- 'commerce.invoice.percent': 'Percentage',
19
- 'commerce.invoice.discountValue': 'Discount value',
20
- 'commerce.invoice.taxMode': 'Tax mode',
21
- 'commerce.invoice.inherit': 'Inherit default tax',
22
- 'commerce.invoice.override': 'Override tax',
23
- 'commerce.invoice.taxRate': 'Line tax (%)',
24
- 'commerce.invoice.remove': 'Remove line',
25
- 'commerce.invoice.add': 'Add line',
26
- 'commerce.invoice.empty': 'No invoice lines. Add a line to begin.',
27
- 'commerce.invoice.gross': 'Gross',
28
- 'commerce.invoice.discount': 'Discount',
29
- 'commerce.invoice.subtotal': 'Subtotal',
30
- 'commerce.invoice.tax': 'Tax',
31
- 'commerce.invoice.total': 'Total',
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.',
34
- 'commerce.invoice.preview': 'Calculated preview; the server revalidates prices, tax and totals.',
35
- 'commerce.invoice.retained': 'Retained reference: {reference}',
36
4
  'commerce.preparation.allocation': 'Allocation {number}',
37
5
  'commerce.preparation.source': 'Reviewed source',
38
6
  'commerce.preparation.reference': 'Source reference',
@@ -43,12 +11,8 @@ export const invoicePreparationMessages = defineMessages({
43
11
  'commerce.preparation.help': 'Enter currency amounts, for example 125.00 for CAD. The server validates currency precision and source availability.',
44
12
  'commerce.preparation.remove': 'Remove this allocation',
45
13
  'commerce.preparation.add': 'Add allocation row',
46
- 'commerce.preparation.save': 'Save invoice draft',
47
- 'commerce.preparation.cancel': 'Cancel',
48
14
  'commerce.preparation.restricted': 'Source details are restricted. Enter references supplied through your authorized workflow.',
49
15
  'commerce.preparation.empty': 'No reviewed sources are available. Retained references remain visible for review.',
50
16
  'commerce.preparation.no_rows': 'No allocations. Add a row to prepare this draft.',
51
- 'commerce.preparation.readonly': 'This draft is read-only.',
52
- 'commerce.preparation.uncertain': 'The outcome is uncertain. Your values and request identity are retained; follow your application’s retry guidance.',
53
17
  'commerce.preparation.review': 'Invoice review',
54
18
  });
@@ -69,7 +69,7 @@ export interface MoneyEditorFieldNames {
69
69
  }
70
70
  export declare const moneyEditorFieldNames: MoneyEditorFieldNames;
71
71
  export interface MoneyEditorProps {
72
- /** Explicit opt-in: existing invoice-editor consumers continue using legacy UI. */
72
+ /** Money model discriminator; v2 is the only invoice money model. */
73
73
  mode: 'v2';
74
74
  draft: MoneyEditorDraft;
75
75
  taxCodes: readonly MoneyEditorTaxCode[];
@@ -1 +1 @@
1
- {"version":3,"file":"money-editor.d.ts","sourceRoot":"","sources":["../../../src/svelte/invoices/money-editor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"money-editor.d.ts","sourceRoot":"","sources":["../../../src/svelte/invoices/money-editor.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,OAAO,EAEL,KAAK,cAAc,EAEnB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACtB,MAAM,gBAAgB,CAAC;AAGxB,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,cAAc,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACnD;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC5C,sEAAsE;IACtE,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,SAAS,GAAG,UAAU,CAAC;IAChC,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,+DAA+D;IAC/D,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,sBAAsB,CAAC,EACnB,SAAS,GACT,UAAU,GACV,KAAK,GACL,iBAAiB,GACjB,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,cAAc,CAAC;IAC/B,aAAa,EAAE,gBAAgB,CAAC;IAChC,KAAK,EAAE,SAAS,oBAAoB,EAAE,CAAC;CACxC;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,4EAA4E;IAC5E,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,oFAAoF;AACpF,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAE,cAAc,CAAC;IAC/B,aAAa,EAAE,gBAAgB,CAAC;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;CAClC;AACD,kFAAkF;AAClF,MAAM,WAAW,kBAAkB;IACjC,cAAc,EAAE,cAAc,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,qBAAqB,EAAE,qBAWnC,CAAC;AAEF,MAAM,WAAW,gBAAgB;IAC/B,qEAAqE;IACrE,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,gBAAgB,CAAC;IACxB,QAAQ,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACxC,+EAA+E;IAC/E,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,yFAAyF;IACzF,IAAI,CAAC,EAAE,SAAS,GAAG,aAAa,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,sBAAsB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACxC;AAED,MAAM,MAAM,sBAAsB,GAC9B;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,mBAAmB,CAAA;CAAE,GAC5C;IACE,KAAK,EAAE,KAAK,CAAC;IACb,IAAI,EAAE,mBAAmB,GAAG,sBAAsB,CAAC;IACnD,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AA8BN;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,gBAAgB,EACvB,QAAQ,EAAE,SAAS,kBAAkB,EAAE,GACtC,sBAAsB,CA0CxB;AAED,oFAAoF;AACpF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,gBAAgB;;;;;;;;;;;;;EAe5D"}