@arslankhan/doc-forge 0.0.0-stage → 0.1.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/CHANGELOG.md +11 -0
- package/LICENSE +13 -0
- package/LICENSING.md +80 -0
- package/README.md +547 -2
- package/RELEASE.md +50 -0
- package/dist/binding-path.d.ts +15 -0
- package/dist/binding-path.d.ts.map +1 -0
- package/dist/binding-path.js +37 -0
- package/dist/binding-path.js.map +1 -0
- package/dist/binding.d.ts +91 -0
- package/dist/binding.d.ts.map +1 -0
- package/dist/binding.js +229 -0
- package/dist/binding.js.map +1 -0
- package/dist/designer/Canvas.d.ts +51 -0
- package/dist/designer/Canvas.d.ts.map +1 -0
- package/dist/designer/Canvas.js +188 -0
- package/dist/designer/Canvas.js.map +1 -0
- package/dist/designer/DocumentDesigner.d.ts +14 -0
- package/dist/designer/DocumentDesigner.d.ts.map +1 -0
- package/dist/designer/DocumentDesigner.js +351 -0
- package/dist/designer/DocumentDesigner.js.map +1 -0
- package/dist/designer/HtmlPreview.d.ts +9 -0
- package/dist/designer/HtmlPreview.d.ts.map +1 -0
- package/dist/designer/HtmlPreview.js +20 -0
- package/dist/designer/HtmlPreview.js.map +1 -0
- package/dist/designer/ImageBindingFields.d.ts +11 -0
- package/dist/designer/ImageBindingFields.d.ts.map +1 -0
- package/dist/designer/ImageBindingFields.js +106 -0
- package/dist/designer/ImageBindingFields.js.map +1 -0
- package/dist/designer/InvoiceFields.d.ts +13 -0
- package/dist/designer/InvoiceFields.d.ts.map +1 -0
- package/dist/designer/InvoiceFields.js +85 -0
- package/dist/designer/InvoiceFields.js.map +1 -0
- package/dist/designer/PreviewDataDialog.d.ts +13 -0
- package/dist/designer/PreviewDataDialog.d.ts.map +1 -0
- package/dist/designer/PreviewDataDialog.js +16 -0
- package/dist/designer/PreviewDataDialog.js.map +1 -0
- package/dist/designer/PropertiesPanel.d.ts +15 -0
- package/dist/designer/PropertiesPanel.d.ts.map +1 -0
- package/dist/designer/PropertiesPanel.js +63 -0
- package/dist/designer/PropertiesPanel.js.map +1 -0
- package/dist/designer/ReportFields.d.ts +14 -0
- package/dist/designer/ReportFields.d.ts.map +1 -0
- package/dist/designer/ReportFields.js +257 -0
- package/dist/designer/ReportFields.js.map +1 -0
- package/dist/designer/StyleFields.d.ts +16 -0
- package/dist/designer/StyleFields.d.ts.map +1 -0
- package/dist/designer/StyleFields.js +138 -0
- package/dist/designer/StyleFields.js.map +1 -0
- package/dist/designer/TextBindingFields.d.ts +11 -0
- package/dist/designer/TextBindingFields.d.ts.map +1 -0
- package/dist/designer/TextBindingFields.js +105 -0
- package/dist/designer/TextBindingFields.js.map +1 -0
- package/dist/designer/Toolbar.d.ts +52 -0
- package/dist/designer/Toolbar.d.ts.map +1 -0
- package/dist/designer/Toolbar.js +62 -0
- package/dist/designer/Toolbar.js.map +1 -0
- package/dist/designer/Toolbox.d.ts +8 -0
- package/dist/designer/Toolbox.d.ts.map +1 -0
- package/dist/designer/Toolbox.js +43 -0
- package/dist/designer/Toolbox.js.map +1 -0
- package/dist/designer/border-preview.d.ts +15 -0
- package/dist/designer/border-preview.d.ts.map +1 -0
- package/dist/designer/border-preview.js +34 -0
- package/dist/designer/border-preview.js.map +1 -0
- package/dist/designer/history.d.ts +13 -0
- package/dist/designer/history.d.ts.map +1 -0
- package/dist/designer/history.js +51 -0
- package/dist/designer/history.js.map +1 -0
- package/dist/designer/index.d.ts +5 -0
- package/dist/designer/index.d.ts.map +1 -0
- package/dist/designer/index.js +3 -0
- package/dist/designer/index.js.map +1 -0
- package/dist/designer/page-geometry.d.ts +35 -0
- package/dist/designer/page-geometry.d.ts.map +1 -0
- package/dist/designer/page-geometry.js +123 -0
- package/dist/designer/page-geometry.js.map +1 -0
- package/dist/designer/styles.d.ts +3 -0
- package/dist/designer/styles.d.ts.map +1 -0
- package/dist/designer/styles.js +594 -0
- package/dist/designer/styles.js.map +1 -0
- package/dist/designer/template-edits.d.ts +26 -0
- package/dist/designer/template-edits.d.ts.map +1 -0
- package/dist/designer/template-edits.js +323 -0
- package/dist/designer/template-edits.js.map +1 -0
- package/dist/designer/theme.d.ts +31 -0
- package/dist/designer/theme.d.ts.map +1 -0
- package/dist/designer/theme.js +92 -0
- package/dist/designer/theme.js.map +1 -0
- package/dist/examples/bound-invoice.d.ts +143 -0
- package/dist/examples/bound-invoice.d.ts.map +1 -0
- package/dist/examples/bound-invoice.js +99 -0
- package/dist/examples/bound-invoice.js.map +1 -0
- package/dist/examples/full-invoice-data.d.ts +81 -0
- package/dist/examples/full-invoice-data.d.ts.map +1 -0
- package/dist/examples/full-invoice-data.js +86 -0
- package/dist/examples/full-invoice-data.js.map +1 -0
- package/dist/examples/full-invoice.d.ts +402 -0
- package/dist/examples/full-invoice.d.ts.map +1 -0
- package/dist/examples/full-invoice.js +199 -0
- package/dist/examples/full-invoice.js.map +1 -0
- package/dist/examples/invoice-data.d.ts +51 -0
- package/dist/examples/invoice-data.d.ts.map +1 -0
- package/dist/examples/invoice-data.js +51 -0
- package/dist/examples/invoice-data.js.map +1 -0
- package/dist/examples/invoice.d.ts +90 -0
- package/dist/examples/invoice.d.ts.map +1 -0
- package/dist/examples/invoice.js +62 -0
- package/dist/examples/invoice.js.map +1 -0
- package/dist/examples/jobs-report-data.d.ts +84 -0
- package/dist/examples/jobs-report-data.d.ts.map +1 -0
- package/dist/examples/jobs-report-data.js +79 -0
- package/dist/examples/jobs-report-data.js.map +1 -0
- package/dist/examples/jobs-report.d.ts +182 -0
- package/dist/examples/jobs-report.d.ts.map +1 -0
- package/dist/examples/jobs-report.js +96 -0
- package/dist/examples/jobs-report.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/invoice/calculate.d.ts +59 -0
- package/dist/invoice/calculate.d.ts.map +1 -0
- package/dist/invoice/calculate.js +270 -0
- package/dist/invoice/calculate.js.map +1 -0
- package/dist/invoice/context.d.ts +15 -0
- package/dist/invoice/context.d.ts.map +1 -0
- package/dist/invoice/context.js +79 -0
- package/dist/invoice/context.js.map +1 -0
- package/dist/invoice/format.d.ts +10 -0
- package/dist/invoice/format.d.ts.map +1 -0
- package/dist/invoice/format.js +95 -0
- package/dist/invoice/format.js.map +1 -0
- package/dist/license/capabilities.d.ts +17 -0
- package/dist/license/capabilities.d.ts.map +1 -0
- package/dist/license/capabilities.js +46 -0
- package/dist/license/capabilities.js.map +1 -0
- package/dist/license/client.d.ts +109 -0
- package/dist/license/client.d.ts.map +1 -0
- package/dist/license/client.js +346 -0
- package/dist/license/client.js.map +1 -0
- package/dist/license/codec.d.ts +5 -0
- package/dist/license/codec.d.ts.map +1 -0
- package/dist/license/codec.js +26 -0
- package/dist/license/codec.js.map +1 -0
- package/dist/license/errors.d.ts +11 -0
- package/dist/license/errors.d.ts.map +1 -0
- package/dist/license/errors.js +19 -0
- package/dist/license/errors.js.map +1 -0
- package/dist/license/features.d.ts +20 -0
- package/dist/license/features.d.ts.map +1 -0
- package/dist/license/features.js +28 -0
- package/dist/license/features.js.map +1 -0
- package/dist/license/index.d.ts +16 -0
- package/dist/license/index.d.ts.map +1 -0
- package/dist/license/index.js +9 -0
- package/dist/license/index.js.map +1 -0
- package/dist/license/provider.d.ts +59 -0
- package/dist/license/provider.d.ts.map +1 -0
- package/dist/license/provider.js +150 -0
- package/dist/license/provider.js.map +1 -0
- package/dist/license/redact.d.ts +4 -0
- package/dist/license/redact.d.ts.map +1 -0
- package/dist/license/redact.js +15 -0
- package/dist/license/redact.js.map +1 -0
- package/dist/license/store.d.ts +26 -0
- package/dist/license/store.d.ts.map +1 -0
- package/dist/license/store.js +90 -0
- package/dist/license/store.js.map +1 -0
- package/dist/license/token.d.ts +45 -0
- package/dist/license/token.d.ts.map +1 -0
- package/dist/license/token.js +195 -0
- package/dist/license/token.js.map +1 -0
- package/dist/pdf/browser-blocked.d.ts +12 -0
- package/dist/pdf/browser-blocked.d.ts.map +1 -0
- package/dist/pdf/browser-blocked.js +25 -0
- package/dist/pdf/browser-blocked.js.map +1 -0
- package/dist/pdf/browser.d.ts +12 -0
- package/dist/pdf/browser.d.ts.map +1 -0
- package/dist/pdf/browser.js +69 -0
- package/dist/pdf/browser.js.map +1 -0
- package/dist/pdf/errors.d.ts +6 -0
- package/dist/pdf/errors.d.ts.map +1 -0
- package/dist/pdf/errors.js +11 -0
- package/dist/pdf/errors.js.map +1 -0
- package/dist/pdf/index.d.ts +10 -0
- package/dist/pdf/index.d.ts.map +1 -0
- package/dist/pdf/index.js +9 -0
- package/dist/pdf/index.js.map +1 -0
- package/dist/pdf/options.d.ts +143 -0
- package/dist/pdf/options.d.ts.map +1 -0
- package/dist/pdf/options.js +322 -0
- package/dist/pdf/options.js.map +1 -0
- package/dist/pdf/render-pdf.d.ts +13 -0
- package/dist/pdf/render-pdf.d.ts.map +1 -0
- package/dist/pdf/render-pdf.js +195 -0
- package/dist/pdf/render-pdf.js.map +1 -0
- package/dist/render/appearance.d.ts +25 -0
- package/dist/render/appearance.d.ts.map +1 -0
- package/dist/render/appearance.js +149 -0
- package/dist/render/appearance.js.map +1 -0
- package/dist/render/css.d.ts +17 -0
- package/dist/render/css.d.ts.map +1 -0
- package/dist/render/css.js +170 -0
- package/dist/render/css.js.map +1 -0
- package/dist/render/errors.d.ts +6 -0
- package/dist/render/errors.d.ts.map +1 -0
- package/dist/render/errors.js +11 -0
- package/dist/render/errors.js.map +1 -0
- package/dist/render/escape.d.ts +7 -0
- package/dist/render/escape.d.ts.map +1 -0
- package/dist/render/escape.js +27 -0
- package/dist/render/escape.js.map +1 -0
- package/dist/render/image-policy.d.ts +21 -0
- package/dist/render/image-policy.d.ts.map +1 -0
- package/dist/render/image-policy.js +62 -0
- package/dist/render/image-policy.js.map +1 -0
- package/dist/render/render-html.d.ts +28 -0
- package/dist/render/render-html.d.ts.map +1 -0
- package/dist/render/render-html.js +364 -0
- package/dist/render/render-html.js.map +1 -0
- package/dist/render/render-report.d.ts +23 -0
- package/dist/render/render-report.d.ts.map +1 -0
- package/dist/render/render-report.js +313 -0
- package/dist/render/render-report.js.map +1 -0
- package/dist/report/process.d.ts +48 -0
- package/dist/report/process.d.ts.map +1 -0
- package/dist/report/process.js +347 -0
- package/dist/report/process.js.map +1 -0
- package/dist/schema.d.ts +30 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +8 -0
- package/dist/schema.js.map +1 -0
- package/dist/serialize.d.ts +13 -0
- package/dist/serialize.d.ts.map +1 -0
- package/dist/serialize.js +42 -0
- package/dist/serialize.js.map +1 -0
- package/dist/types.d.ts +335 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +40 -0
- package/dist/types.js.map +1 -0
- package/dist/validate.d.ts +15 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +977 -0
- package/dist/validate.js.map +1 -0
- package/package.json +105 -4
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invoice arithmetic in minor units.
|
|
3
|
+
* This is a configurable policy, not a claim of tax compliance for any country.
|
|
4
|
+
*
|
|
5
|
+
* Order of operations:
|
|
6
|
+
* 1. Line gross = quantity × rate, rounded to `fractionDigits`.
|
|
7
|
+
* 2. Line discount, when the item has one, is applied to that gross amount.
|
|
8
|
+
* 3. Subtotal is the sum of line amounts after line discounts.
|
|
9
|
+
* 4. The invoice discount is applied once to that subtotal.
|
|
10
|
+
* 5. The invoice discount is shared across lines in proportion to their net amounts.
|
|
11
|
+
* 6. Tax is calculated on each line's discounted taxable amount.
|
|
12
|
+
* An item tax rate wins. Otherwise `invoice.taxRate` is used. Otherwise tax is 0.
|
|
13
|
+
* 7. Grand total = subtotal − invoice discount + tax.
|
|
14
|
+
*
|
|
15
|
+
* Rounding is half away from zero at each monetary step.
|
|
16
|
+
* Quantity totals use 6 decimal places. Values at or above 1e12 are rejected.
|
|
17
|
+
* Negative quantities, rates, discounts, and tax rates are rejected.
|
|
18
|
+
* Missing or non-numeric quantities and rates throw; they are not treated as zero.
|
|
19
|
+
*/
|
|
20
|
+
export class InvoiceCalculationError extends Error {
|
|
21
|
+
code;
|
|
22
|
+
constructor(code, message) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.name = "InvoiceCalculationError";
|
|
25
|
+
this.code = code;
|
|
26
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const QUANTITY_DIGITS = 6;
|
|
30
|
+
const AMOUNT_LIMIT = 1_000_000_000_000;
|
|
31
|
+
export function calculateInvoice(data, policy = {}) {
|
|
32
|
+
const digits = fractionDigits(policy.fractionDigits);
|
|
33
|
+
if (!isRecord(data)) {
|
|
34
|
+
throw new InvoiceCalculationError("invalid_data", "Invoice data must be a JSON object.");
|
|
35
|
+
}
|
|
36
|
+
const invoice = data.invoice === undefined ? {} : data.invoice;
|
|
37
|
+
if (!isRecord(invoice)) {
|
|
38
|
+
throw new InvoiceCalculationError("invalid_invoice", "invoice must be an object when it is present.");
|
|
39
|
+
}
|
|
40
|
+
const defaultTax = optionalPercent(invoice.taxRate, "invoice.taxRate");
|
|
41
|
+
const items = readItems(invoice.items);
|
|
42
|
+
const lines = items.map((item, index) => calculateLine(item, index, digits, defaultTax));
|
|
43
|
+
const subtotalMinor = lines.reduce((sum, line) => sum + line.netMinor, 0n);
|
|
44
|
+
const discountMinor = invoiceDiscount(invoice.discount, subtotalMinor, digits);
|
|
45
|
+
const shares = allocate(discountMinor, lines.map((line) => line.netMinor));
|
|
46
|
+
const calculated = lines.map((line, index) => {
|
|
47
|
+
const share = shares[index] ?? 0n;
|
|
48
|
+
const taxableMinor = line.netMinor - share;
|
|
49
|
+
const taxMinor = percentOf(taxableMinor, line.taxRate);
|
|
50
|
+
return toLineResult(line, share, taxableMinor, taxMinor, digits);
|
|
51
|
+
});
|
|
52
|
+
const taxMinor = calculated.reduce((sum, line) => sum + toMinor(line.taxAmount, digits), 0n);
|
|
53
|
+
const taxableMinor = subtotalMinor - discountMinor;
|
|
54
|
+
const grandMinor = taxableMinor + taxMinor;
|
|
55
|
+
return {
|
|
56
|
+
fractionDigits: digits,
|
|
57
|
+
lines: calculated,
|
|
58
|
+
totals: {
|
|
59
|
+
subtotal: minorToNumber(subtotalMinor, digits),
|
|
60
|
+
discountAmount: minorToNumber(discountMinor, digits),
|
|
61
|
+
taxableAmount: minorToNumber(taxableMinor, digits),
|
|
62
|
+
taxTotal: minorToNumber(taxMinor, digits),
|
|
63
|
+
grandTotal: minorToNumber(grandMinor, digits),
|
|
64
|
+
totalQuantity: minorToNumber(lines.reduce((sum, line) => sum + toMinor(line.quantity, QUANTITY_DIGITS), 0n), QUANTITY_DIGITS),
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function calculateLine(item, index, digits, defaultTax) {
|
|
69
|
+
const where = `invoice.items[${index}]`;
|
|
70
|
+
const description = readText(item.description, `${where}.description`);
|
|
71
|
+
const unit = readText(item.unit, `${where}.unit`);
|
|
72
|
+
const quantity = readAmount(item.quantity, `${where}.quantity`);
|
|
73
|
+
const rate = readAmount(item.rate, `${where}.rate`);
|
|
74
|
+
const taxRate = item.taxRate === undefined || item.taxRate === null ? defaultTax : optionalPercent(item.taxRate, `${where}.taxRate`);
|
|
75
|
+
const grossMinor = multiplyRounded(quantity, rate, digits);
|
|
76
|
+
const discountMinor = lineDiscount(item.discount, grossMinor, digits, where);
|
|
77
|
+
if (discountMinor > grossMinor) {
|
|
78
|
+
throw new InvoiceCalculationError("discount_exceeds_amount", `${where} discount is greater than the line amount.`);
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
description,
|
|
82
|
+
quantity,
|
|
83
|
+
unit,
|
|
84
|
+
rate,
|
|
85
|
+
taxRate,
|
|
86
|
+
grossMinor,
|
|
87
|
+
discountMinor,
|
|
88
|
+
netMinor: grossMinor - discountMinor,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function toLineResult(line, share, taxableMinor, taxMinor, digits) {
|
|
92
|
+
const netAmount = minorToNumber(line.netMinor, digits);
|
|
93
|
+
return {
|
|
94
|
+
description: line.description,
|
|
95
|
+
quantity: line.quantity,
|
|
96
|
+
unit: line.unit,
|
|
97
|
+
rate: line.rate,
|
|
98
|
+
grossAmount: minorToNumber(line.grossMinor, digits),
|
|
99
|
+
discountAmount: minorToNumber(line.discountMinor, digits),
|
|
100
|
+
netAmount,
|
|
101
|
+
lineTotal: netAmount,
|
|
102
|
+
invoiceDiscountShare: minorToNumber(share, digits),
|
|
103
|
+
taxableAmount: minorToNumber(taxableMinor, digits),
|
|
104
|
+
taxRate: line.taxRate,
|
|
105
|
+
taxAmount: minorToNumber(taxMinor, digits),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function readItems(value) {
|
|
109
|
+
if (value === undefined || value === null) {
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
if (!Array.isArray(value)) {
|
|
113
|
+
throw new InvoiceCalculationError("invalid_items", "invoice.items must be an array when it is present.");
|
|
114
|
+
}
|
|
115
|
+
return value.map((item, index) => {
|
|
116
|
+
if (!isRecord(item)) {
|
|
117
|
+
throw new InvoiceCalculationError("invalid_item", `invoice.items[${index}] must be an object.`);
|
|
118
|
+
}
|
|
119
|
+
return item;
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
function invoiceDiscount(value, subtotalMinor, digits) {
|
|
123
|
+
if (value === undefined || value === null) {
|
|
124
|
+
return 0n;
|
|
125
|
+
}
|
|
126
|
+
const discount = readDiscount(value, "invoice.discount");
|
|
127
|
+
const amount = discountAmount(discount, subtotalMinor, digits);
|
|
128
|
+
if (amount > subtotalMinor) {
|
|
129
|
+
throw new InvoiceCalculationError("discount_exceeds_amount", "Invoice discount is greater than the subtotal.");
|
|
130
|
+
}
|
|
131
|
+
return amount;
|
|
132
|
+
}
|
|
133
|
+
function lineDiscount(value, grossMinor, digits, where) {
|
|
134
|
+
if (value === undefined || value === null) {
|
|
135
|
+
return 0n;
|
|
136
|
+
}
|
|
137
|
+
return discountAmount(readDiscount(value, `${where}.discount`), grossMinor, digits);
|
|
138
|
+
}
|
|
139
|
+
function readDiscount(value, where) {
|
|
140
|
+
if (!isRecord(value) || (value.type !== "percentage" && value.type !== "fixed")) {
|
|
141
|
+
throw new InvoiceCalculationError("invalid_discount", `${where} must be a percentage or fixed discount.`);
|
|
142
|
+
}
|
|
143
|
+
const amount = readAmount(value.value, `${where}.value`);
|
|
144
|
+
if (value.type === "percentage" && amount > 100) {
|
|
145
|
+
throw new InvoiceCalculationError("invalid_discount", `${where} percentage must be from 0 to 100.`);
|
|
146
|
+
}
|
|
147
|
+
return { type: value.type, value: amount };
|
|
148
|
+
}
|
|
149
|
+
function discountAmount(discount, baseMinor, digits) {
|
|
150
|
+
if (discount.type === "percentage") {
|
|
151
|
+
return percentOf(baseMinor, discount.value);
|
|
152
|
+
}
|
|
153
|
+
return toMinor(discount.value, digits);
|
|
154
|
+
}
|
|
155
|
+
function optionalPercent(value, where) {
|
|
156
|
+
if (value === undefined || value === null) {
|
|
157
|
+
return 0;
|
|
158
|
+
}
|
|
159
|
+
const rate = readAmount(value, where);
|
|
160
|
+
if (rate > 100) {
|
|
161
|
+
throw new InvoiceCalculationError("invalid_tax_rate", `${where} must be from 0 to 100.`);
|
|
162
|
+
}
|
|
163
|
+
return rate;
|
|
164
|
+
}
|
|
165
|
+
function readText(value, where) {
|
|
166
|
+
if (value === undefined || value === null) {
|
|
167
|
+
return "";
|
|
168
|
+
}
|
|
169
|
+
if (typeof value !== "string") {
|
|
170
|
+
throw new InvoiceCalculationError("invalid_text", `${where} must be a string.`);
|
|
171
|
+
}
|
|
172
|
+
return value;
|
|
173
|
+
}
|
|
174
|
+
function readAmount(value, where) {
|
|
175
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
176
|
+
throw new InvoiceCalculationError("invalid_number", `${where} must be a finite number.`);
|
|
177
|
+
}
|
|
178
|
+
if (Object.is(value, -0)) {
|
|
179
|
+
return 0;
|
|
180
|
+
}
|
|
181
|
+
if (value < 0) {
|
|
182
|
+
throw new InvoiceCalculationError("negative_value", `${where} must be greater than or equal to 0.`);
|
|
183
|
+
}
|
|
184
|
+
if (value >= AMOUNT_LIMIT) {
|
|
185
|
+
throw new InvoiceCalculationError("amount_out_of_range", `${where} must be less than ${AMOUNT_LIMIT}.`);
|
|
186
|
+
}
|
|
187
|
+
return value;
|
|
188
|
+
}
|
|
189
|
+
function fractionDigits(value) {
|
|
190
|
+
if (value === undefined) {
|
|
191
|
+
return 2;
|
|
192
|
+
}
|
|
193
|
+
if (!Number.isInteger(value) || value < 0 || value > 6) {
|
|
194
|
+
throw new InvoiceCalculationError("invalid_policy", "fractionDigits must be an integer from 0 to 6.");
|
|
195
|
+
}
|
|
196
|
+
return value;
|
|
197
|
+
}
|
|
198
|
+
function multiplyRounded(left, right, digits) {
|
|
199
|
+
const scale = QUANTITY_DIGITS;
|
|
200
|
+
return rescale(toMinor(left, scale) * toMinor(right, scale), scale * 2, digits);
|
|
201
|
+
}
|
|
202
|
+
function percentOf(baseMinor, percent) {
|
|
203
|
+
const percentScale = QUANTITY_DIGITS;
|
|
204
|
+
const product = baseMinor * toMinor(percent, percentScale);
|
|
205
|
+
return divRound(product, 100n * 10n ** BigInt(percentScale));
|
|
206
|
+
}
|
|
207
|
+
function allocate(total, parts) {
|
|
208
|
+
if (parts.length === 0 || total === 0n) {
|
|
209
|
+
return parts.map(() => 0n);
|
|
210
|
+
}
|
|
211
|
+
const sum = parts.reduce((acc, part) => acc + part, 0n);
|
|
212
|
+
if (sum === 0n) {
|
|
213
|
+
return parts.map(() => 0n);
|
|
214
|
+
}
|
|
215
|
+
let remaining = total;
|
|
216
|
+
return parts.map((part, index) => {
|
|
217
|
+
if (index === parts.length - 1) {
|
|
218
|
+
return remaining;
|
|
219
|
+
}
|
|
220
|
+
const share = divRound(total * part, sum);
|
|
221
|
+
remaining -= share;
|
|
222
|
+
return share;
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
function toMinor(value, digits) {
|
|
226
|
+
const negative = value < 0;
|
|
227
|
+
const formatted = new Intl.NumberFormat("en-US", {
|
|
228
|
+
useGrouping: false,
|
|
229
|
+
maximumFractionDigits: 20,
|
|
230
|
+
minimumFractionDigits: 0,
|
|
231
|
+
}).format(Math.abs(value));
|
|
232
|
+
const [wholeText, fractionText = ""] = formatted.split(".");
|
|
233
|
+
const head = fractionText.slice(0, digits).padEnd(digits, "0");
|
|
234
|
+
const roundDigit = fractionText[digits] ?? "0";
|
|
235
|
+
let minor = BigInt(wholeText || "0") * 10n ** BigInt(digits) + BigInt(head || "0");
|
|
236
|
+
if (roundDigit >= "5") {
|
|
237
|
+
minor += 1n;
|
|
238
|
+
}
|
|
239
|
+
return negative ? -minor : minor;
|
|
240
|
+
}
|
|
241
|
+
function rescale(value, fromDigits, toDigits) {
|
|
242
|
+
if (fromDigits === toDigits) {
|
|
243
|
+
return value;
|
|
244
|
+
}
|
|
245
|
+
if (fromDigits > toDigits) {
|
|
246
|
+
return divRound(value, 10n ** BigInt(fromDigits - toDigits));
|
|
247
|
+
}
|
|
248
|
+
return value * 10n ** BigInt(toDigits - fromDigits);
|
|
249
|
+
}
|
|
250
|
+
function divRound(value, divisor) {
|
|
251
|
+
const negative = value < 0n;
|
|
252
|
+
const abs = negative ? -value : value;
|
|
253
|
+
const quotient = abs / divisor;
|
|
254
|
+
const remainder = abs % divisor;
|
|
255
|
+
const rounded = remainder * 2n >= divisor ? quotient + 1n : quotient;
|
|
256
|
+
return negative ? -rounded : rounded;
|
|
257
|
+
}
|
|
258
|
+
function minorToNumber(minor, digits) {
|
|
259
|
+
const negative = minor < 0n;
|
|
260
|
+
const abs = negative ? -minor : minor;
|
|
261
|
+
const scale = 10n ** BigInt(digits);
|
|
262
|
+
const whole = abs / scale;
|
|
263
|
+
const fraction = (abs % scale).toString().padStart(digits, "0");
|
|
264
|
+
const text = digits === 0 ? `${whole}` : `${whole}.${fraction}`;
|
|
265
|
+
return Number(negative ? `-${text}` : text);
|
|
266
|
+
}
|
|
267
|
+
function isRecord(value) {
|
|
268
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=calculate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calculate.js","sourceRoot":"","sources":["../../src/invoice/calculate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { JsonValue } from "../binding.js";
|
|
2
|
+
import { type InvoiceCalculationPolicy } from "./calculate.js";
|
|
3
|
+
export type { InvoiceCalculationPolicy } from "./calculate.js";
|
|
4
|
+
/**
|
|
5
|
+
* Builds a rendering copy of invoice JSON and adds calculated fields.
|
|
6
|
+
* The input object is not modified. User fields are copied, then calculated
|
|
7
|
+
* names are written on the copy: `invoice.subtotal`, `invoice.discountAmount`,
|
|
8
|
+
* `invoice.taxableAmount`, `invoice.taxTotal`, `invoice.grandTotal`,
|
|
9
|
+
* `invoice.totalQuantity`, and each item's `lineTotal`, `grossAmount`,
|
|
10
|
+
* `discountAmount`, `netAmount`, `taxAmount`, and `taxableAmount`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function prepareInvoiceContext(data: unknown, policy?: InvoiceCalculationPolicy): {
|
|
13
|
+
[key: string]: JsonValue;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/invoice/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAGL,KAAK,wBAAwB,EAE9B,MAAM,gBAAgB,CAAC;AAExB,YAAY,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAE/D;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,wBAAwB,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAiBpH"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { calculateInvoice, InvoiceCalculationError, } from "./calculate.js";
|
|
2
|
+
/**
|
|
3
|
+
* Builds a rendering copy of invoice JSON and adds calculated fields.
|
|
4
|
+
* The input object is not modified. User fields are copied, then calculated
|
|
5
|
+
* names are written on the copy: `invoice.subtotal`, `invoice.discountAmount`,
|
|
6
|
+
* `invoice.taxableAmount`, `invoice.taxTotal`, `invoice.grandTotal`,
|
|
7
|
+
* `invoice.totalQuantity`, and each item's `lineTotal`, `grossAmount`,
|
|
8
|
+
* `discountAmount`, `netAmount`, `taxAmount`, and `taxableAmount`.
|
|
9
|
+
*/
|
|
10
|
+
export function prepareInvoiceContext(data, policy) {
|
|
11
|
+
if (!isJsonObject(data)) {
|
|
12
|
+
throw new InvoiceCalculationError("invalid_data", "Invoice data must be a JSON object.");
|
|
13
|
+
}
|
|
14
|
+
const calculation = calculateInvoice(data, policy);
|
|
15
|
+
const clone = structuredClone(data);
|
|
16
|
+
const invoice = isRecord(clone.invoice) ? { ...clone.invoice } : {};
|
|
17
|
+
const sourceItems = Array.isArray(invoice.items) ? invoice.items : [];
|
|
18
|
+
invoice.items = calculation.lines.map((line, index) => enrichItem(sourceItems[index], line));
|
|
19
|
+
invoice.subtotal = calculation.totals.subtotal;
|
|
20
|
+
invoice.discountAmount = calculation.totals.discountAmount;
|
|
21
|
+
invoice.taxableAmount = calculation.totals.taxableAmount;
|
|
22
|
+
invoice.taxTotal = calculation.totals.taxTotal;
|
|
23
|
+
invoice.grandTotal = calculation.totals.grandTotal;
|
|
24
|
+
invoice.totalQuantity = calculation.totals.totalQuantity;
|
|
25
|
+
clone.invoice = invoice;
|
|
26
|
+
return clone;
|
|
27
|
+
}
|
|
28
|
+
function enrichItem(source, line) {
|
|
29
|
+
const base = isRecord(source) ? { ...source } : {};
|
|
30
|
+
return {
|
|
31
|
+
...jsonRecord(base),
|
|
32
|
+
description: line.description,
|
|
33
|
+
quantity: line.quantity,
|
|
34
|
+
unit: line.unit,
|
|
35
|
+
rate: line.rate,
|
|
36
|
+
grossAmount: line.grossAmount,
|
|
37
|
+
discountAmount: line.discountAmount,
|
|
38
|
+
netAmount: line.netAmount,
|
|
39
|
+
lineTotal: line.lineTotal,
|
|
40
|
+
taxRate: line.taxRate,
|
|
41
|
+
taxAmount: line.taxAmount,
|
|
42
|
+
taxableAmount: line.taxableAmount,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function jsonRecord(value) {
|
|
46
|
+
const result = {};
|
|
47
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
48
|
+
if (isJsonValue(entry)) {
|
|
49
|
+
result[key] = entry;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
function isJsonObject(value) {
|
|
55
|
+
return isRecord(value) && isJsonValue(value);
|
|
56
|
+
}
|
|
57
|
+
function isRecord(value) {
|
|
58
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
const prototype = Object.getPrototypeOf(value);
|
|
62
|
+
return prototype === Object.prototype || prototype === null;
|
|
63
|
+
}
|
|
64
|
+
function isJsonValue(value) {
|
|
65
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
if (typeof value === "number") {
|
|
69
|
+
return Number.isFinite(value);
|
|
70
|
+
}
|
|
71
|
+
if (Array.isArray(value)) {
|
|
72
|
+
return value.every((entry) => isJsonValue(entry));
|
|
73
|
+
}
|
|
74
|
+
if (isRecord(value)) {
|
|
75
|
+
return Object.values(value).every((entry) => isJsonValue(entry));
|
|
76
|
+
}
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/invoice/context.ts"],"names":[],"mappings":"AACA,OAAO,EACL,gBAAgB,EAChB,uBAAuB,GAGxB,MAAM,gBAAgB,CAAC;AAIxB;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAa,EAAE,MAAiC;IACpF,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,uBAAuB,CAAC,cAAc,EAAE,qCAAqC,CAAC,CAAC;IAC3F,CAAC;IACD,MAAM,WAAW,GAAG,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACpE,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IACtE,OAAO,CAAC,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;IAC7F,OAAO,CAAC,QAAQ,GAAG,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC;IAC/C,OAAO,CAAC,cAAc,GAAG,WAAW,CAAC,MAAM,CAAC,cAAc,CAAC;IAC3D,OAAO,CAAC,aAAa,GAAG,WAAW,CAAC,MAAM,CAAC,aAAa,CAAC;IACzD,OAAO,CAAC,QAAQ,GAAG,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC;IAC/C,OAAO,CAAC,UAAU,GAAG,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC;IACnD,OAAO,CAAC,aAAa,GAAG,WAAW,CAAC,MAAM,CAAC,aAAa,CAAC;IACzD,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC;IACxB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,UAAU,CAAC,MAAe,EAAE,IAAuB;IAC1D,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACnD,OAAO;QACL,GAAG,UAAU,CAAC,IAAI,CAAC;QACnB,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,cAAc,EAAE,IAAI,CAAC,cAAc;QACnC,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,aAAa,EAAE,IAAI,CAAC,aAAa;KAClC,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,KAA8B;IAChD,MAAM,MAAM,GAAiC,EAAE,CAAC;IAChD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,IAAI,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;YACvB,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACtB,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,YAAY,CAAC,KAAc;IAClC,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,WAAW,CAAC,KAAK,CAAC,CAAC;AAC/C,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxE,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,SAAS,GAAG,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;IAC/C,OAAO,SAAS,KAAK,MAAM,CAAC,SAAS,IAAI,SAAS,KAAK,IAAI,CAAC;AAC9D,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IACjC,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC;QAC9E,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;IACpD,CAAC;IACD,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACpB,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { JsonValue } from "../binding.js";
|
|
2
|
+
import type { ValueFormat } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Formats a calculated or bound scalar for display.
|
|
5
|
+
* The numeric calculation result is not modified. Invalid locales fall back to `en`.
|
|
6
|
+
* A currency style without a 3-letter code is shown as a decimal number.
|
|
7
|
+
* A date must be `YYYY-MM-DD`. Anything else returns null so the caller can use a fallback.
|
|
8
|
+
*/
|
|
9
|
+
export declare function formatScalar(value: JsonValue, format: ValueFormat | undefined, currencyCode?: string): string | null;
|
|
10
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/invoice/format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,GAAG,SAAS,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA4BpH"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formats a calculated or bound scalar for display.
|
|
3
|
+
* The numeric calculation result is not modified. Invalid locales fall back to `en`.
|
|
4
|
+
* A currency style without a 3-letter code is shown as a decimal number.
|
|
5
|
+
* A date must be `YYYY-MM-DD`. Anything else returns null so the caller can use a fallback.
|
|
6
|
+
*/
|
|
7
|
+
export function formatScalar(value, format, currencyCode) {
|
|
8
|
+
if (format === undefined) {
|
|
9
|
+
return plainScalar(value);
|
|
10
|
+
}
|
|
11
|
+
if (format.style === "date") {
|
|
12
|
+
return formatDate(value, format);
|
|
13
|
+
}
|
|
14
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
const minimum = format.minimumFractionDigits;
|
|
18
|
+
const maximum = format.maximumFractionDigits ?? minimum;
|
|
19
|
+
const options = {
|
|
20
|
+
useGrouping: true,
|
|
21
|
+
minimumFractionDigits: minimum,
|
|
22
|
+
maximumFractionDigits: maximum ?? 20,
|
|
23
|
+
};
|
|
24
|
+
if (format.style === "percent") {
|
|
25
|
+
return formatNumber(value, format.locale, { ...options, style: "percent" });
|
|
26
|
+
}
|
|
27
|
+
if (format.style === "currency") {
|
|
28
|
+
const currency = currencyCode && /^[A-Za-z]{3}$/.test(currencyCode) ? currencyCode.toUpperCase() : undefined;
|
|
29
|
+
if (!currency) {
|
|
30
|
+
return formatNumber(value, format.locale, options);
|
|
31
|
+
}
|
|
32
|
+
return formatNumber(value, format.locale, { ...options, style: "currency", currency });
|
|
33
|
+
}
|
|
34
|
+
return formatNumber(value, format.locale, options);
|
|
35
|
+
}
|
|
36
|
+
function plainScalar(value) {
|
|
37
|
+
if (typeof value === "string") {
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
if (typeof value === "number") {
|
|
41
|
+
return Number.isFinite(value) ? String(value) : null;
|
|
42
|
+
}
|
|
43
|
+
if (typeof value === "boolean") {
|
|
44
|
+
return value ? "true" : "false";
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
function formatDate(value, format) {
|
|
49
|
+
if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}$/.test(value)) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
const [yearText, monthText, dayText] = value.split("-");
|
|
53
|
+
const year = Number(yearText);
|
|
54
|
+
const month = Number(monthText);
|
|
55
|
+
const day = Number(dayText);
|
|
56
|
+
const utc = new Date(Date.UTC(year, month - 1, day));
|
|
57
|
+
if (utc.getUTCFullYear() !== year || utc.getUTCMonth() !== month - 1 || utc.getUTCDate() !== day) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
if (format.dateStyle === undefined || format.dateStyle === "iso") {
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
return new Intl.DateTimeFormat(normalizeLocale(format.locale), {
|
|
65
|
+
dateStyle: format.dateStyle,
|
|
66
|
+
timeZone: "UTC",
|
|
67
|
+
}).format(utc);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return new Intl.DateTimeFormat("en", { dateStyle: format.dateStyle, timeZone: "UTC" }).format(utc);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function formatNumber(value, locale, options) {
|
|
74
|
+
try {
|
|
75
|
+
return new Intl.NumberFormat(normalizeLocale(locale), options).format(value);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
const decimal = { ...options };
|
|
79
|
+
delete decimal.currency;
|
|
80
|
+
decimal.style = "decimal";
|
|
81
|
+
return new Intl.NumberFormat("en", decimal).format(value);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function normalizeLocale(locale) {
|
|
85
|
+
if (locale === undefined || locale.trim().length === 0) {
|
|
86
|
+
return "en";
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
return new Intl.Locale(locale).toString();
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return "en";
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/invoice/format.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { DocumentTemplate } from "../schema.js";
|
|
2
|
+
/**
|
|
3
|
+
* What a template uses. This is not a license decision and does not block rendering.
|
|
4
|
+
*/
|
|
5
|
+
export interface DocumentCapabilities {
|
|
6
|
+
documentType: DocumentTemplate["documentType"];
|
|
7
|
+
elementTypes: readonly string[];
|
|
8
|
+
elementCount: number;
|
|
9
|
+
usesInvoiceCalculation: boolean;
|
|
10
|
+
usesReportGrouping: boolean;
|
|
11
|
+
usesReportAggregates: boolean;
|
|
12
|
+
usesReportSort: boolean;
|
|
13
|
+
usesAdvancedTableStyle: boolean;
|
|
14
|
+
usesElementStyle: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function inspectDocumentCapabilities(template: DocumentTemplate): DocumentCapabilities;
|
|
17
|
+
//# sourceMappingURL=capabilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../../src/license/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAC;IAC/C,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,sBAAsB,EAAE,OAAO,CAAC;IAChC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,cAAc,EAAE,OAAO,CAAC;IACxB,sBAAsB,EAAE,OAAO,CAAC;IAChC,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,gBAAgB,GAAG,oBAAoB,CA4C5F"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export function inspectDocumentCapabilities(template) {
|
|
2
|
+
const elements = Array.isArray(template.elements) ? template.elements : [];
|
|
3
|
+
const elementTypes = [...new Set(elements.map((element) => element.type))];
|
|
4
|
+
let usesReportGrouping = false;
|
|
5
|
+
let usesReportAggregates = false;
|
|
6
|
+
let usesReportSort = false;
|
|
7
|
+
let usesAdvancedTableStyle = false;
|
|
8
|
+
let usesElementStyle = false;
|
|
9
|
+
for (const element of elements) {
|
|
10
|
+
if (element.style) {
|
|
11
|
+
usesElementStyle = true;
|
|
12
|
+
}
|
|
13
|
+
if (element.type === "reportTable") {
|
|
14
|
+
usesReportGrouping = usesReportGrouping || (element.groupBy?.length ?? 0) > 0;
|
|
15
|
+
usesReportSort = usesReportSort || (element.sort?.length ?? 0) > 0;
|
|
16
|
+
usesReportAggregates = usesReportAggregates || element.columns.some((column) => column.aggregate !== undefined);
|
|
17
|
+
usesAdvancedTableStyle =
|
|
18
|
+
usesAdvancedTableStyle ||
|
|
19
|
+
element.headerStyle !== undefined ||
|
|
20
|
+
element.bodyStyle !== undefined ||
|
|
21
|
+
element.groupStyle !== undefined ||
|
|
22
|
+
element.subtotalStyle !== undefined ||
|
|
23
|
+
element.grandTotalStyle !== undefined ||
|
|
24
|
+
(element.rowRules?.length ?? 0) > 0 ||
|
|
25
|
+
element.alternateRowColor !== undefined ||
|
|
26
|
+
element.oddRowColor !== undefined ||
|
|
27
|
+
element.evenRowColor !== undefined ||
|
|
28
|
+
element.columns.some((column) => column.style !== undefined || column.headerStyle !== undefined);
|
|
29
|
+
}
|
|
30
|
+
if (element.type === "items" && element.headerStyle !== undefined) {
|
|
31
|
+
usesAdvancedTableStyle = true;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
documentType: template.documentType,
|
|
36
|
+
elementTypes,
|
|
37
|
+
elementCount: elements.length,
|
|
38
|
+
usesInvoiceCalculation: template.documentType === "invoice",
|
|
39
|
+
usesReportGrouping,
|
|
40
|
+
usesReportAggregates,
|
|
41
|
+
usesReportSort,
|
|
42
|
+
usesAdvancedTableStyle,
|
|
43
|
+
usesElementStyle,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=capabilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../src/license/capabilities.ts"],"names":[],"mappings":"AAiBA,MAAM,UAAU,2BAA2B,CAAC,QAA0B;IACpE,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3E,MAAM,YAAY,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3E,IAAI,kBAAkB,GAAG,KAAK,CAAC;IAC/B,IAAI,oBAAoB,GAAG,KAAK,CAAC;IACjC,IAAI,cAAc,GAAG,KAAK,CAAC;IAC3B,IAAI,sBAAsB,GAAG,KAAK,CAAC;IACnC,IAAI,gBAAgB,GAAG,KAAK,CAAC;IAC7B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YAClB,gBAAgB,GAAG,IAAI,CAAC;QAC1B,CAAC;QACD,IAAI,OAAO,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YACnC,kBAAkB,GAAG,kBAAkB,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YAC9E,cAAc,GAAG,cAAc,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YACnE,oBAAoB,GAAG,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC;YAChH,sBAAsB;gBACpB,sBAAsB;oBACtB,OAAO,CAAC,WAAW,KAAK,SAAS;oBACjC,OAAO,CAAC,SAAS,KAAK,SAAS;oBAC/B,OAAO,CAAC,UAAU,KAAK,SAAS;oBAChC,OAAO,CAAC,aAAa,KAAK,SAAS;oBACnC,OAAO,CAAC,eAAe,KAAK,SAAS;oBACrC,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC;oBACnC,OAAO,CAAC,iBAAiB,KAAK,SAAS;oBACvC,OAAO,CAAC,WAAW,KAAK,SAAS;oBACjC,OAAO,CAAC,YAAY,KAAK,SAAS;oBAClC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC;QACrG,CAAC;QACD,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,IAAI,OAAO,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;YAClE,sBAAsB,GAAG,IAAI,CAAC;QAChC,CAAC;IACH,CAAC;IACD,OAAO;QACL,YAAY,EAAE,QAAQ,CAAC,YAAY;QACnC,YAAY;QACZ,YAAY,EAAE,QAAQ,CAAC,MAAM;QAC7B,sBAAsB,EAAE,QAAQ,CAAC,YAAY,KAAK,SAAS;QAC3D,kBAAkB;QAClB,oBAAoB;QACpB,cAAc;QACd,sBAAsB;QACtB,gBAAgB;KACjB,CAAC;AACJ,CAAC"}
|