@fin.cx/einvoice 5.0.2 → 5.1.2
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/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/einvoice.d.ts +4 -8
- package/dist_ts/einvoice.js +46 -7
- package/dist_ts/formats/converters/xml-to-einvoice.converter.d.ts +21 -0
- package/dist_ts/formats/converters/xml-to-einvoice.converter.js +127 -0
- package/dist_ts/formats/semantic/bt-bg.model.d.ts +445 -0
- package/dist_ts/formats/semantic/bt-bg.model.js +12 -0
- package/dist_ts/formats/semantic/semantic.adapter.d.ts +87 -0
- package/dist_ts/formats/semantic/semantic.adapter.js +538 -0
- package/dist_ts/formats/semantic/semantic.validator.d.ts +48 -0
- package/dist_ts/formats/semantic/semantic.validator.js +596 -0
- package/dist_ts/formats/utils/currency.calculator.decimal.d.ts +98 -0
- package/dist_ts/formats/utils/currency.calculator.decimal.js +212 -0
- package/dist_ts/formats/utils/currency.utils.d.ts +99 -0
- package/dist_ts/formats/utils/currency.utils.js +250 -0
- package/dist_ts/formats/utils/decimal.d.ts +151 -0
- package/dist_ts/formats/utils/decimal.js +435 -0
- package/dist_ts/formats/validation/codelist.validator.d.ts +49 -0
- package/dist_ts/formats/validation/codelist.validator.js +188 -0
- package/dist_ts/formats/validation/conformance.harness.d.ts +99 -0
- package/dist_ts/formats/validation/conformance.harness.js +471 -0
- package/dist_ts/formats/validation/en16931.business-rules.validator.d.ts +58 -0
- package/dist_ts/formats/validation/en16931.business-rules.validator.js +459 -0
- package/dist_ts/formats/validation/facturx.validator.d.ts +75 -0
- package/dist_ts/formats/validation/facturx.validator.js +522 -0
- package/dist_ts/formats/validation/integrated.validator.d.ts +82 -0
- package/dist_ts/formats/validation/integrated.validator.js +311 -0
- package/dist_ts/formats/validation/peppol.validator.d.ts +77 -0
- package/dist_ts/formats/validation/peppol.validator.js +529 -0
- package/dist_ts/formats/validation/schematron.downloader.d.ts +71 -0
- package/dist_ts/formats/validation/schematron.downloader.js +254 -0
- package/dist_ts/formats/validation/schematron.integration.d.ts +60 -0
- package/dist_ts/formats/validation/schematron.integration.js +230 -0
- package/dist_ts/formats/validation/schematron.validator.d.ts +79 -0
- package/dist_ts/formats/validation/schematron.validator.js +288 -0
- package/dist_ts/formats/validation/schematron.worker.d.ts +50 -0
- package/dist_ts/formats/validation/schematron.worker.js +185 -0
- package/dist_ts/formats/validation/validation.types.d.ts +163 -0
- package/dist_ts/formats/validation/validation.types.js +181 -0
- package/dist_ts/formats/validation/vat-categories.validator.d.ts +87 -0
- package/dist_ts/formats/validation/vat-categories.validator.js +497 -0
- package/dist_ts/formats/validation/xrechnung.validator.d.ts +92 -0
- package/dist_ts/formats/validation/xrechnung.validator.js +417 -0
- package/dist_ts/interfaces/common.d.ts +1 -0
- package/dist_ts/interfaces/en16931-metadata.d.ts +83 -0
- package/dist_ts/interfaces/en16931-metadata.js +6 -0
- package/dist_ts/plugins.d.ts +3 -1
- package/dist_ts/plugins.js +7 -2
- package/dist_ts_install/download-schematron.d.ts +6 -0
- package/dist_ts_install/download-schematron.js +62 -0
- package/dist_ts_install/download-test-samples.d.ts +19 -0
- package/dist_ts_install/download-test-samples.js +169 -0
- package/dist_ts_install/download-xrechnung-rules.d.ts +7 -0
- package/dist_ts_install/download-xrechnung-rules.js +146 -0
- package/dist_ts_install/index.d.ts +8 -0
- package/dist_ts_install/index.js +246 -0
- package/package.json +13 -8
- package/readme.md +255 -810
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/einvoice.ts +63 -14
- package/ts/formats/converters/xml-to-einvoice.converter.ts +142 -0
- package/ts/formats/semantic/bt-bg.model.ts +524 -0
- package/ts/formats/semantic/semantic.adapter.ts +600 -0
- package/ts/formats/semantic/semantic.validator.ts +654 -0
- package/ts/formats/utils/currency.calculator.decimal.ts +323 -0
- package/ts/formats/utils/currency.utils.ts +299 -0
- package/ts/formats/utils/decimal.ts +509 -0
- package/ts/formats/validation/codelist.validator.ts +317 -0
- package/ts/formats/validation/conformance.harness.ts +591 -0
- package/ts/formats/validation/en16931.business-rules.validator.ts +694 -0
- package/ts/formats/validation/facturx.validator.ts +579 -0
- package/ts/formats/validation/integrated.validator.ts +405 -0
- package/ts/formats/validation/peppol.validator.ts +589 -0
- package/ts/formats/validation/schematron.downloader.ts +304 -0
- package/ts/formats/validation/schematron.integration.ts +285 -0
- package/ts/formats/validation/schematron.validator.ts +348 -0
- package/ts/formats/validation/schematron.worker.ts +221 -0
- package/ts/formats/validation/validation.types.ts +274 -0
- package/ts/formats/validation/vat-categories.validator.ts +845 -0
- package/ts/formats/validation/xrechnung.validator.ts +494 -0
- package/ts/interfaces/common.ts +1 -0
- package/ts/interfaces/en16931-metadata.ts +104 -0
- package/ts/plugins.ts +8 -0
- package/ts/tspublish.json +3 -0
- package/dist_ts/classes.decoder.d.ts +0 -40
- package/dist_ts/classes.decoder.js +0 -320
- package/dist_ts/classes.encoder.d.ts +0 -51
- package/dist_ts/classes.encoder.js +0 -293
- package/dist_ts/classes.xinvoice.d.ts +0 -136
- package/dist_ts/classes.xinvoice.js +0 -352
- package/dist_ts/formats/base.decoder.d.ts +0 -19
- package/dist_ts/formats/base.decoder.js +0 -130
- package/dist_ts/formats/base.validator.d.ts +0 -44
- package/dist_ts/formats/base.validator.js +0 -39
- package/dist_ts/formats/decoder.factory.d.ts +0 -15
- package/dist_ts/formats/decoder.factory.js +0 -46
- package/dist_ts/formats/factorx.decoder.d.ts +0 -18
- package/dist_ts/formats/factorx.decoder.js +0 -178
- package/dist_ts/formats/factorx.encoder.d.ts +0 -51
- package/dist_ts/formats/factorx.encoder.js +0 -293
- package/dist_ts/formats/facturx.decoder.d.ts +0 -18
- package/dist_ts/formats/facturx.decoder.js +0 -210
- package/dist_ts/formats/facturx.encoder.d.ts +0 -51
- package/dist_ts/formats/facturx.encoder.js +0 -293
- package/dist_ts/formats/facturx.validator.d.ts +0 -67
- package/dist_ts/formats/facturx.validator.js +0 -266
- package/dist_ts/formats/pdf/robust-pdf.extractor.d.ts +0 -40
- package/dist_ts/formats/pdf/robust-pdf.extractor.js +0 -324
- package/dist_ts/formats/ubl.validator.d.ts +0 -82
- package/dist_ts/formats/ubl.validator.js +0 -306
- package/dist_ts/formats/validator.factory.d.ts +0 -18
- package/dist_ts/formats/validator.factory.js +0 -78
- package/dist_ts/formats/xinvoice.decoder.d.ts +0 -28
- package/dist_ts/formats/xinvoice.decoder.js +0 -332
- package/dist_ts/formats/xinvoice.encoder.d.ts +0 -19
- package/dist_ts/formats/xinvoice.encoder.js +0 -282
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
import { CurrencyCalculator, areMonetaryValuesEqual } from '../utils/currency.utils.js';
|
|
3
|
+
import { DecimalCurrencyCalculator } from '../utils/currency.calculator.decimal.js';
|
|
4
|
+
import { Decimal } from '../utils/decimal.js';
|
|
5
|
+
/**
|
|
6
|
+
* EN16931 Business Rules Validator
|
|
7
|
+
* Implements the full set of EN16931 business rules for invoice validation
|
|
8
|
+
*/
|
|
9
|
+
export class EN16931BusinessRulesValidator {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.results = [];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Validate an invoice against EN16931 business rules
|
|
15
|
+
*/
|
|
16
|
+
validate(invoice, options = {}) {
|
|
17
|
+
this.results = [];
|
|
18
|
+
// Initialize currency calculators if currency is available
|
|
19
|
+
if (invoice.currency) {
|
|
20
|
+
this.currencyCalculator = new CurrencyCalculator(invoice.currency);
|
|
21
|
+
this.decimalCalculator = new DecimalCurrencyCalculator(invoice.currency);
|
|
22
|
+
}
|
|
23
|
+
// Document level rules (BR-01 to BR-65)
|
|
24
|
+
this.validateDocumentRules(invoice);
|
|
25
|
+
// Calculation rules (BR-CO-*)
|
|
26
|
+
if (options.checkCalculations !== false) {
|
|
27
|
+
this.validateCalculationRules(invoice);
|
|
28
|
+
}
|
|
29
|
+
// VAT rules (BR-S-*, BR-Z-*, BR-E-*, BR-AE-*, BR-IC-*, BR-G-*, BR-O-*)
|
|
30
|
+
if (options.checkVAT !== false) {
|
|
31
|
+
this.validateVATRules(invoice);
|
|
32
|
+
}
|
|
33
|
+
// Line level rules (BR-21 to BR-30)
|
|
34
|
+
this.validateLineRules(invoice);
|
|
35
|
+
// Allowances and charges rules
|
|
36
|
+
if (options.checkAllowances !== false) {
|
|
37
|
+
this.validateAllowancesCharges(invoice);
|
|
38
|
+
}
|
|
39
|
+
return this.results;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Validate document level rules (BR-01 to BR-65)
|
|
43
|
+
*/
|
|
44
|
+
validateDocumentRules(invoice) {
|
|
45
|
+
// BR-01: An Invoice shall have a Specification identifier (BT-24)
|
|
46
|
+
if (!invoice.metadata?.customizationId) {
|
|
47
|
+
this.addError('BR-01', 'Invoice must have a Specification identifier (CustomizationID)', 'customizationId');
|
|
48
|
+
}
|
|
49
|
+
// BR-02: An Invoice shall have an Invoice number (BT-1)
|
|
50
|
+
if (!invoice.accountingDocId) {
|
|
51
|
+
this.addError('BR-02', 'Invoice must have an Invoice number', 'accountingDocId');
|
|
52
|
+
}
|
|
53
|
+
// BR-03: An Invoice shall have an Invoice issue date (BT-2)
|
|
54
|
+
if (!invoice.date) {
|
|
55
|
+
this.addError('BR-03', 'Invoice must have an issue date', 'date');
|
|
56
|
+
}
|
|
57
|
+
// BR-04: An Invoice shall have an Invoice type code (BT-3)
|
|
58
|
+
if (!invoice.accountingDocType) {
|
|
59
|
+
this.addError('BR-04', 'Invoice must have a type code', 'accountingDocType');
|
|
60
|
+
}
|
|
61
|
+
// BR-05: An Invoice shall have an Invoice currency code (BT-5)
|
|
62
|
+
if (!invoice.currency) {
|
|
63
|
+
this.addError('BR-05', 'Invoice must have a currency code', 'currency');
|
|
64
|
+
}
|
|
65
|
+
// BR-06: An Invoice shall contain the Seller name (BT-27)
|
|
66
|
+
if (!invoice.from?.name) {
|
|
67
|
+
this.addError('BR-06', 'Invoice must contain the Seller name', 'from.name');
|
|
68
|
+
}
|
|
69
|
+
// BR-07: An Invoice shall contain the Buyer name (BT-44)
|
|
70
|
+
if (!invoice.to?.name) {
|
|
71
|
+
this.addError('BR-07', 'Invoice must contain the Buyer name', 'to.name');
|
|
72
|
+
}
|
|
73
|
+
// BR-08: An Invoice shall contain the Seller postal address (BG-5)
|
|
74
|
+
if (!invoice.from?.address) {
|
|
75
|
+
this.addError('BR-08', 'Invoice must contain the Seller postal address', 'from.address');
|
|
76
|
+
}
|
|
77
|
+
// BR-09: The Seller postal address shall contain a Seller country code (BT-40)
|
|
78
|
+
if (!invoice.from?.address?.countryCode) {
|
|
79
|
+
this.addError('BR-09', 'Seller postal address must contain a country code', 'from.address.countryCode');
|
|
80
|
+
}
|
|
81
|
+
// BR-10: An Invoice shall contain the Buyer postal address (BG-8)
|
|
82
|
+
if (!invoice.to?.address) {
|
|
83
|
+
this.addError('BR-10', 'Invoice must contain the Buyer postal address', 'to.address');
|
|
84
|
+
}
|
|
85
|
+
// BR-11: The Buyer postal address shall contain a Buyer country code (BT-55)
|
|
86
|
+
if (!invoice.to?.address?.countryCode) {
|
|
87
|
+
this.addError('BR-11', 'Buyer postal address must contain a country code', 'to.address.countryCode');
|
|
88
|
+
}
|
|
89
|
+
// BR-16: An Invoice shall have at least one Invoice line (BG-25)
|
|
90
|
+
if (!invoice.items || invoice.items.length === 0) {
|
|
91
|
+
this.addError('BR-16', 'Invoice must have at least one invoice line', 'items');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Validate calculation rules (BR-CO-*)
|
|
96
|
+
*/
|
|
97
|
+
validateCalculationRules(invoice) {
|
|
98
|
+
if (!invoice.items || invoice.items.length === 0)
|
|
99
|
+
return;
|
|
100
|
+
// Use decimal calculator for precise calculations
|
|
101
|
+
const useDecimal = this.decimalCalculator !== undefined;
|
|
102
|
+
// BR-CO-10: Sum of Invoice line net amount = Σ(Invoice line net amount)
|
|
103
|
+
const calculatedLineTotal = useDecimal
|
|
104
|
+
? this.calculateLineTotalDecimal(invoice.items)
|
|
105
|
+
: this.calculateLineTotal(invoice.items);
|
|
106
|
+
const declaredLineTotal = useDecimal
|
|
107
|
+
? new Decimal(invoice.totalNet || 0)
|
|
108
|
+
: invoice.totalNet || 0;
|
|
109
|
+
const isEqual = useDecimal
|
|
110
|
+
? this.decimalCalculator.areEqual(calculatedLineTotal, declaredLineTotal)
|
|
111
|
+
: this.currencyCalculator
|
|
112
|
+
? this.currencyCalculator.areEqual(calculatedLineTotal, declaredLineTotal)
|
|
113
|
+
: Math.abs(calculatedLineTotal - declaredLineTotal) < 0.01;
|
|
114
|
+
if (!isEqual) {
|
|
115
|
+
this.addError('BR-CO-10', `Sum of line net amounts (${useDecimal ? calculatedLineTotal.toFixed(2) : calculatedLineTotal.toFixed(2)}) does not match declared total (${useDecimal ? declaredLineTotal.toFixed(2) : declaredLineTotal.toFixed(2)})`, 'totalNet', useDecimal ? declaredLineTotal.toNumber() : declaredLineTotal, useDecimal ? calculatedLineTotal.toNumber() : calculatedLineTotal);
|
|
116
|
+
}
|
|
117
|
+
// BR-CO-11: Sum of allowances on document level
|
|
118
|
+
const documentAllowances = useDecimal
|
|
119
|
+
? this.calculateDocumentAllowancesDecimal(invoice)
|
|
120
|
+
: this.calculateDocumentAllowances(invoice);
|
|
121
|
+
// BR-CO-12: Sum of charges on document level
|
|
122
|
+
const documentCharges = useDecimal
|
|
123
|
+
? this.calculateDocumentChargesDecimal(invoice)
|
|
124
|
+
: this.calculateDocumentCharges(invoice);
|
|
125
|
+
// BR-CO-13: Invoice total without VAT = Σ(line) - allowances + charges
|
|
126
|
+
const expectedTaxExclusive = useDecimal
|
|
127
|
+
? calculatedLineTotal.subtract(documentAllowances).add(documentCharges)
|
|
128
|
+
: calculatedLineTotal - documentAllowances + documentCharges;
|
|
129
|
+
const declaredTaxExclusive = useDecimal
|
|
130
|
+
? new Decimal(invoice.totalNet || 0)
|
|
131
|
+
: invoice.totalNet || 0;
|
|
132
|
+
const isTaxExclusiveEqual = useDecimal
|
|
133
|
+
? this.decimalCalculator.areEqual(expectedTaxExclusive, declaredTaxExclusive)
|
|
134
|
+
: this.currencyCalculator
|
|
135
|
+
? this.currencyCalculator.areEqual(expectedTaxExclusive, declaredTaxExclusive)
|
|
136
|
+
: Math.abs(expectedTaxExclusive - declaredTaxExclusive) < 0.01;
|
|
137
|
+
if (!isTaxExclusiveEqual) {
|
|
138
|
+
this.addError('BR-CO-13', `Tax exclusive amount (${useDecimal ? declaredTaxExclusive.toFixed(2) : declaredTaxExclusive.toFixed(2)}) does not match calculation (${useDecimal ? expectedTaxExclusive.toFixed(2) : expectedTaxExclusive.toFixed(2)})`, 'totalNet', useDecimal ? declaredTaxExclusive.toNumber() : declaredTaxExclusive, useDecimal ? expectedTaxExclusive.toNumber() : expectedTaxExclusive);
|
|
139
|
+
}
|
|
140
|
+
// BR-CO-14: Invoice total VAT amount = Σ(VAT category tax amount)
|
|
141
|
+
const calculatedVAT = useDecimal
|
|
142
|
+
? this.calculateTotalVATDecimal(invoice)
|
|
143
|
+
: this.calculateTotalVAT(invoice);
|
|
144
|
+
const declaredVAT = useDecimal
|
|
145
|
+
? new Decimal(invoice.totalVat || 0)
|
|
146
|
+
: invoice.totalVat || 0;
|
|
147
|
+
const isVATEqual = useDecimal
|
|
148
|
+
? this.decimalCalculator.areEqual(calculatedVAT, declaredVAT)
|
|
149
|
+
: this.currencyCalculator
|
|
150
|
+
? this.currencyCalculator.areEqual(calculatedVAT, declaredVAT)
|
|
151
|
+
: Math.abs(calculatedVAT - declaredVAT) < 0.01;
|
|
152
|
+
if (!isVATEqual) {
|
|
153
|
+
this.addError('BR-CO-14', `Total VAT (${useDecimal ? declaredVAT.toFixed(2) : declaredVAT.toFixed(2)}) does not match calculation (${useDecimal ? calculatedVAT.toFixed(2) : calculatedVAT.toFixed(2)})`, 'totalVat', useDecimal ? declaredVAT.toNumber() : declaredVAT, useDecimal ? calculatedVAT.toNumber() : calculatedVAT);
|
|
154
|
+
}
|
|
155
|
+
// BR-CO-15: Invoice total with VAT = Invoice total without VAT + Invoice total VAT
|
|
156
|
+
const expectedGrossTotal = useDecimal
|
|
157
|
+
? expectedTaxExclusive.add(calculatedVAT)
|
|
158
|
+
: expectedTaxExclusive + calculatedVAT;
|
|
159
|
+
const declaredGrossTotal = useDecimal
|
|
160
|
+
? new Decimal(invoice.totalGross || 0)
|
|
161
|
+
: invoice.totalGross || 0;
|
|
162
|
+
const isGrossEqual = useDecimal
|
|
163
|
+
? this.decimalCalculator.areEqual(expectedGrossTotal, declaredGrossTotal)
|
|
164
|
+
: this.currencyCalculator
|
|
165
|
+
? this.currencyCalculator.areEqual(expectedGrossTotal, declaredGrossTotal)
|
|
166
|
+
: Math.abs(expectedGrossTotal - declaredGrossTotal) < 0.01;
|
|
167
|
+
if (!isGrossEqual) {
|
|
168
|
+
this.addError('BR-CO-15', `Gross total (${useDecimal ? declaredGrossTotal.toFixed(2) : declaredGrossTotal.toFixed(2)}) does not match calculation (${useDecimal ? expectedGrossTotal.toFixed(2) : expectedGrossTotal.toFixed(2)})`, 'totalGross', useDecimal ? declaredGrossTotal.toNumber() : declaredGrossTotal, useDecimal ? expectedGrossTotal.toNumber() : expectedGrossTotal);
|
|
169
|
+
}
|
|
170
|
+
// BR-CO-16: Amount due for payment = Invoice total with VAT - Paid amount
|
|
171
|
+
const paidAmount = useDecimal
|
|
172
|
+
? new Decimal(invoice.metadata?.paidAmount || 0)
|
|
173
|
+
: invoice.metadata?.paidAmount || 0;
|
|
174
|
+
const expectedDueAmount = useDecimal
|
|
175
|
+
? expectedGrossTotal.subtract(paidAmount)
|
|
176
|
+
: expectedGrossTotal - paidAmount;
|
|
177
|
+
const declaredDueAmount = useDecimal
|
|
178
|
+
? new Decimal(invoice.metadata?.amountDue || (useDecimal ? expectedGrossTotal.toNumber() : expectedGrossTotal))
|
|
179
|
+
: invoice.metadata?.amountDue || expectedGrossTotal;
|
|
180
|
+
const isDueEqual = useDecimal
|
|
181
|
+
? this.decimalCalculator.areEqual(expectedDueAmount, declaredDueAmount)
|
|
182
|
+
: this.currencyCalculator
|
|
183
|
+
? this.currencyCalculator.areEqual(expectedDueAmount, declaredDueAmount)
|
|
184
|
+
: Math.abs(expectedDueAmount - declaredDueAmount) < 0.01;
|
|
185
|
+
if (!isDueEqual) {
|
|
186
|
+
this.addError('BR-CO-16', `Amount due (${useDecimal ? declaredDueAmount.toFixed(2) : declaredDueAmount.toFixed(2)}) does not match calculation (${useDecimal ? expectedDueAmount.toFixed(2) : expectedDueAmount.toFixed(2)})`, 'amountDue', useDecimal ? declaredDueAmount.toNumber() : declaredDueAmount, useDecimal ? expectedDueAmount.toNumber() : expectedDueAmount);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Validate VAT rules
|
|
191
|
+
*/
|
|
192
|
+
validateVATRules(invoice) {
|
|
193
|
+
const useDecimal = this.decimalCalculator !== undefined;
|
|
194
|
+
// Group items by VAT rate
|
|
195
|
+
const vatGroups = this.groupItemsByVAT(invoice.items || []);
|
|
196
|
+
// BR-S-01: An Invoice that contains an Invoice line where VAT category code is "Standard rated"
|
|
197
|
+
// shall contain in the VAT breakdown at least one VAT category code equal to "Standard rated"
|
|
198
|
+
const hasStandardRatedLine = invoice.items?.some(item => item.vatPercentage && item.vatPercentage > 0);
|
|
199
|
+
if (hasStandardRatedLine) {
|
|
200
|
+
const hasStandardRatedBreakdown = invoice.taxBreakdown?.some(breakdown => breakdown.taxPercent && breakdown.taxPercent > 0);
|
|
201
|
+
if (!hasStandardRatedBreakdown) {
|
|
202
|
+
this.addError('BR-S-01', 'Invoice with standard rated lines must have standard rated VAT breakdown', 'taxBreakdown');
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// BR-S-02: VAT category taxable amount for standard rated
|
|
206
|
+
// BR-S-03: VAT category tax amount for standard rated
|
|
207
|
+
vatGroups.forEach((group, rate) => {
|
|
208
|
+
if (rate > 0) { // Standard rated
|
|
209
|
+
const expectedTaxableAmount = useDecimal
|
|
210
|
+
? group.reduce((sum, item) => {
|
|
211
|
+
const unitPrice = new Decimal(item.unitNetPrice);
|
|
212
|
+
const quantity = new Decimal(item.unitQuantity);
|
|
213
|
+
return sum.add(unitPrice.multiply(quantity));
|
|
214
|
+
}, Decimal.ZERO)
|
|
215
|
+
: group.reduce((sum, item) => sum + (item.unitNetPrice * item.unitQuantity), 0);
|
|
216
|
+
const expectedTaxAmount = useDecimal
|
|
217
|
+
? this.decimalCalculator.calculateVAT(expectedTaxableAmount, new Decimal(rate))
|
|
218
|
+
: expectedTaxableAmount * (rate / 100);
|
|
219
|
+
// Find corresponding breakdown
|
|
220
|
+
const breakdown = invoice.taxBreakdown?.find(b => Math.abs((b.taxPercent || 0) - rate) < 0.01);
|
|
221
|
+
if (breakdown) {
|
|
222
|
+
const isTaxableEqual = useDecimal
|
|
223
|
+
? this.decimalCalculator.areEqual(expectedTaxableAmount, breakdown.netAmount)
|
|
224
|
+
: this.currencyCalculator
|
|
225
|
+
? this.currencyCalculator.areEqual(breakdown.netAmount, expectedTaxableAmount)
|
|
226
|
+
: Math.abs(breakdown.netAmount - expectedTaxableAmount) < 0.01;
|
|
227
|
+
if (!isTaxableEqual) {
|
|
228
|
+
this.addError('BR-S-02', `VAT taxable amount for ${rate}% incorrect`, 'taxBreakdown.netAmount', breakdown.netAmount, useDecimal ? expectedTaxableAmount.toNumber() : expectedTaxableAmount);
|
|
229
|
+
}
|
|
230
|
+
const isTaxEqual = useDecimal
|
|
231
|
+
? this.decimalCalculator.areEqual(expectedTaxAmount, breakdown.taxAmount)
|
|
232
|
+
: this.currencyCalculator
|
|
233
|
+
? this.currencyCalculator.areEqual(breakdown.taxAmount, expectedTaxAmount)
|
|
234
|
+
: Math.abs(breakdown.taxAmount - expectedTaxAmount) < 0.01;
|
|
235
|
+
if (!isTaxEqual) {
|
|
236
|
+
this.addError('BR-S-03', `VAT tax amount for ${rate}% incorrect`, 'taxBreakdown.vatAmount', breakdown.taxAmount, useDecimal ? expectedTaxAmount.toNumber() : expectedTaxAmount);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
// BR-Z-01: Zero rated VAT rules
|
|
242
|
+
const hasZeroRatedLine = invoice.items?.some(item => item.vatPercentage === 0);
|
|
243
|
+
if (hasZeroRatedLine) {
|
|
244
|
+
const hasZeroRatedBreakdown = invoice.taxBreakdown?.some(breakdown => breakdown.taxPercent === 0);
|
|
245
|
+
if (!hasZeroRatedBreakdown) {
|
|
246
|
+
this.addError('BR-Z-01', 'Invoice with zero rated lines must have zero rated VAT breakdown', 'taxBreakdown');
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Validate line level rules (BR-21 to BR-30)
|
|
252
|
+
*/
|
|
253
|
+
validateLineRules(invoice) {
|
|
254
|
+
invoice.items?.forEach((item, index) => {
|
|
255
|
+
// BR-21: Each Invoice line shall have an Invoice line identifier
|
|
256
|
+
if (!item.position && item.position !== 0) {
|
|
257
|
+
this.addError('BR-21', `Invoice line ${index + 1} must have an identifier`, `items[${index}].id`);
|
|
258
|
+
}
|
|
259
|
+
// BR-22: Each Invoice line shall have an Item name
|
|
260
|
+
if (!item.name) {
|
|
261
|
+
this.addError('BR-22', `Invoice line ${index + 1} must have an item name`, `items[${index}].name`);
|
|
262
|
+
}
|
|
263
|
+
// BR-23: An Invoice line shall have an Invoiced quantity
|
|
264
|
+
if (item.unitQuantity === undefined || item.unitQuantity === null) {
|
|
265
|
+
this.addError('BR-23', `Invoice line ${index + 1} must have a quantity`, `items[${index}].quantity`);
|
|
266
|
+
}
|
|
267
|
+
// BR-24: An Invoice line shall have an Invoiced quantity unit of measure code
|
|
268
|
+
if (!item.unitType) {
|
|
269
|
+
this.addError('BR-24', `Invoice line ${index + 1} must have a unit of measure code`, `items[${index}].unitCode`);
|
|
270
|
+
}
|
|
271
|
+
// BR-25: An Invoice line shall have an Invoice line net amount
|
|
272
|
+
const lineNetAmount = item.unitNetPrice * item.unitQuantity;
|
|
273
|
+
if (isNaN(lineNetAmount)) {
|
|
274
|
+
this.addError('BR-25', `Invoice line ${index + 1} must have a valid net amount`, `items[${index}]`);
|
|
275
|
+
}
|
|
276
|
+
// BR-26: Each Invoice line shall have an Invoice line VAT category code
|
|
277
|
+
if (item.vatPercentage === undefined) {
|
|
278
|
+
this.addError('BR-26', `Invoice line ${index + 1} must have a VAT category code`, `items[${index}].vatPercentage`);
|
|
279
|
+
}
|
|
280
|
+
// BR-27: Invoice line net price shall be present
|
|
281
|
+
if (item.unitNetPrice === undefined || item.unitNetPrice === null) {
|
|
282
|
+
this.addError('BR-27', `Invoice line ${index + 1} must have a net price`, `items[${index}].unitPrice`);
|
|
283
|
+
}
|
|
284
|
+
// BR-28: Item price base quantity shall be greater than zero
|
|
285
|
+
const baseQuantity = 1; // Default to 1 as TAccountingDocItem doesn't have priceBaseQuantity
|
|
286
|
+
if (baseQuantity <= 0) {
|
|
287
|
+
this.addError('BR-28', `Invoice line ${index + 1} price base quantity must be greater than zero`, `items[${index}].metadata.priceBaseQuantity`, baseQuantity, '> 0');
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Validate allowances and charges
|
|
293
|
+
*/
|
|
294
|
+
validateAllowancesCharges(invoice) {
|
|
295
|
+
// BR-31: Document level allowance shall have an amount
|
|
296
|
+
invoice.metadata?.allowances?.forEach((allowance, index) => {
|
|
297
|
+
if (!allowance.amount && allowance.amount !== 0) {
|
|
298
|
+
this.addError('BR-31', `Document allowance ${index + 1} must have an amount`, `metadata.allowances[${index}].amount`);
|
|
299
|
+
}
|
|
300
|
+
// BR-32: Document level allowance shall have VAT category code
|
|
301
|
+
if (!allowance.vatCategoryCode) {
|
|
302
|
+
this.addError('BR-32', `Document allowance ${index + 1} must have a VAT category code`, `metadata.allowances[${index}].vatCategoryCode`);
|
|
303
|
+
}
|
|
304
|
+
// BR-33: Document level allowance shall have a reason
|
|
305
|
+
if (!allowance.reason) {
|
|
306
|
+
this.addError('BR-33', `Document allowance ${index + 1} must have a reason`, `metadata.allowances[${index}].reason`);
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
// BR-36: Document level charge shall have an amount
|
|
310
|
+
invoice.metadata?.charges?.forEach((charge, index) => {
|
|
311
|
+
if (!charge.amount && charge.amount !== 0) {
|
|
312
|
+
this.addError('BR-36', `Document charge ${index + 1} must have an amount`, `metadata.charges[${index}].amount`);
|
|
313
|
+
}
|
|
314
|
+
// BR-37: Document level charge shall have VAT category code
|
|
315
|
+
if (!charge.vatCategoryCode) {
|
|
316
|
+
this.addError('BR-37', `Document charge ${index + 1} must have a VAT category code`, `metadata.charges[${index}].vatCategoryCode`);
|
|
317
|
+
}
|
|
318
|
+
// BR-38: Document level charge shall have a reason
|
|
319
|
+
if (!charge.reason) {
|
|
320
|
+
this.addError('BR-38', `Document charge ${index + 1} must have a reason`, `metadata.charges[${index}].reason`);
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
// Helper methods
|
|
325
|
+
calculateLineTotal(items) {
|
|
326
|
+
return items.reduce((sum, item) => {
|
|
327
|
+
const lineTotal = (item.unitNetPrice || 0) * (item.unitQuantity || 0);
|
|
328
|
+
const rounded = this.currencyCalculator
|
|
329
|
+
? this.currencyCalculator.round(lineTotal)
|
|
330
|
+
: lineTotal;
|
|
331
|
+
return sum + rounded;
|
|
332
|
+
}, 0);
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Calculate line total using decimal arithmetic for precision
|
|
336
|
+
*/
|
|
337
|
+
calculateLineTotalDecimal(items) {
|
|
338
|
+
let total = Decimal.ZERO;
|
|
339
|
+
for (const item of items) {
|
|
340
|
+
const unitPrice = new Decimal(item.unitNetPrice || 0);
|
|
341
|
+
const quantity = new Decimal(item.unitQuantity || 0);
|
|
342
|
+
const lineTotal = unitPrice.multiply(quantity);
|
|
343
|
+
total = total.add(this.decimalCalculator.round(lineTotal));
|
|
344
|
+
}
|
|
345
|
+
return total;
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Calculate document allowances using decimal arithmetic
|
|
349
|
+
*/
|
|
350
|
+
calculateDocumentAllowancesDecimal(invoice) {
|
|
351
|
+
if (!invoice.metadata?.allowances) {
|
|
352
|
+
return Decimal.ZERO;
|
|
353
|
+
}
|
|
354
|
+
let total = Decimal.ZERO;
|
|
355
|
+
for (const allowance of invoice.metadata.allowances) {
|
|
356
|
+
const amount = new Decimal(allowance.amount || 0);
|
|
357
|
+
total = total.add(this.decimalCalculator.round(amount));
|
|
358
|
+
}
|
|
359
|
+
return total;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Calculate document charges using decimal arithmetic
|
|
363
|
+
*/
|
|
364
|
+
calculateDocumentChargesDecimal(invoice) {
|
|
365
|
+
if (!invoice.metadata?.charges) {
|
|
366
|
+
return Decimal.ZERO;
|
|
367
|
+
}
|
|
368
|
+
let total = Decimal.ZERO;
|
|
369
|
+
for (const charge of invoice.metadata.charges) {
|
|
370
|
+
const amount = new Decimal(charge.amount || 0);
|
|
371
|
+
total = total.add(this.decimalCalculator.round(amount));
|
|
372
|
+
}
|
|
373
|
+
return total;
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Calculate total VAT using decimal arithmetic
|
|
377
|
+
*/
|
|
378
|
+
calculateTotalVATDecimal(invoice) {
|
|
379
|
+
let totalVAT = Decimal.ZERO;
|
|
380
|
+
// Group items by VAT rate
|
|
381
|
+
const vatGroups = new Map();
|
|
382
|
+
for (const item of invoice.items || []) {
|
|
383
|
+
const vatRate = item.vatPercentage || 0;
|
|
384
|
+
const rateKey = vatRate.toString();
|
|
385
|
+
const unitPrice = new Decimal(item.unitNetPrice || 0);
|
|
386
|
+
const quantity = new Decimal(item.unitQuantity || 0);
|
|
387
|
+
const lineNet = unitPrice.multiply(quantity);
|
|
388
|
+
if (vatGroups.has(rateKey)) {
|
|
389
|
+
vatGroups.set(rateKey, vatGroups.get(rateKey).add(lineNet));
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
vatGroups.set(rateKey, lineNet);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
// Calculate VAT for each group
|
|
396
|
+
for (const [rateKey, baseAmount] of vatGroups) {
|
|
397
|
+
const rate = new Decimal(rateKey);
|
|
398
|
+
const vat = this.decimalCalculator.calculateVAT(baseAmount, rate);
|
|
399
|
+
totalVAT = totalVAT.add(vat);
|
|
400
|
+
}
|
|
401
|
+
return totalVAT;
|
|
402
|
+
}
|
|
403
|
+
calculateDocumentAllowances(invoice) {
|
|
404
|
+
return invoice.metadata?.allowances?.reduce((sum, allowance) => sum + (allowance.amount || 0), 0) || 0;
|
|
405
|
+
}
|
|
406
|
+
calculateDocumentCharges(invoice) {
|
|
407
|
+
return invoice.metadata?.charges?.reduce((sum, charge) => sum + (charge.amount || 0), 0) || 0;
|
|
408
|
+
}
|
|
409
|
+
calculateTotalVAT(invoice) {
|
|
410
|
+
const vatGroups = this.groupItemsByVAT(invoice.items || []);
|
|
411
|
+
let totalVAT = 0;
|
|
412
|
+
vatGroups.forEach((items, rate) => {
|
|
413
|
+
const taxableAmount = items.reduce((sum, item) => {
|
|
414
|
+
const lineNet = item.unitNetPrice * item.unitQuantity;
|
|
415
|
+
return sum + (this.currencyCalculator ? this.currencyCalculator.round(lineNet) : lineNet);
|
|
416
|
+
}, 0);
|
|
417
|
+
const vatAmount = taxableAmount * (rate / 100);
|
|
418
|
+
const roundedVAT = this.currencyCalculator
|
|
419
|
+
? this.currencyCalculator.round(vatAmount)
|
|
420
|
+
: vatAmount;
|
|
421
|
+
totalVAT += roundedVAT;
|
|
422
|
+
});
|
|
423
|
+
return totalVAT;
|
|
424
|
+
}
|
|
425
|
+
groupItemsByVAT(items) {
|
|
426
|
+
const groups = new Map();
|
|
427
|
+
items.forEach(item => {
|
|
428
|
+
const rate = item.vatPercentage || 0;
|
|
429
|
+
if (!groups.has(rate)) {
|
|
430
|
+
groups.set(rate, []);
|
|
431
|
+
}
|
|
432
|
+
groups.get(rate).push(item);
|
|
433
|
+
});
|
|
434
|
+
return groups;
|
|
435
|
+
}
|
|
436
|
+
addError(ruleId, message, field, value, expected) {
|
|
437
|
+
this.results.push({
|
|
438
|
+
ruleId,
|
|
439
|
+
source: 'EN16931',
|
|
440
|
+
severity: 'error',
|
|
441
|
+
message,
|
|
442
|
+
field,
|
|
443
|
+
value,
|
|
444
|
+
expected
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
addWarning(ruleId, message, field, value, expected) {
|
|
448
|
+
this.results.push({
|
|
449
|
+
ruleId,
|
|
450
|
+
source: 'EN16931',
|
|
451
|
+
severity: 'warning',
|
|
452
|
+
message,
|
|
453
|
+
field,
|
|
454
|
+
value,
|
|
455
|
+
expected
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW4xNjkzMS5idXNpbmVzcy1ydWxlcy52YWxpZGF0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9mb3JtYXRzL3ZhbGlkYXRpb24vZW4xNjkzMS5idXNpbmVzcy1ydWxlcy52YWxpZGF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxrQkFBa0IsQ0FBQztBQUc1QyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUN4RixPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSx5Q0FBeUMsQ0FBQztBQUNwRixPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFHOUM7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLDZCQUE2QjtJQUExQztRQUNVLFlBQU8sR0FBdUIsRUFBRSxDQUFDO0lBd3FCM0MsQ0FBQztJQXBxQkM7O09BRUc7SUFDSSxRQUFRLENBQUMsT0FBaUIsRUFBRSxVQUE2QixFQUFFO1FBQ2hFLElBQUksQ0FBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1FBRWxCLDJEQUEyRDtRQUMzRCxJQUFJLE9BQU8sQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNyQixJQUFJLENBQUMsa0JBQWtCLEdBQUcsSUFBSSxrQkFBa0IsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDbkUsSUFBSSxDQUFDLGlCQUFpQixHQUFHLElBQUkseUJBQXlCLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQzNFLENBQUM7UUFFRCx3Q0FBd0M7UUFDeEMsSUFBSSxDQUFDLHFCQUFxQixDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBRXBDLDhCQUE4QjtRQUM5QixJQUFJLE9BQU8sQ0FBQyxpQkFBaUIsS0FBSyxLQUFLLEVBQUUsQ0FBQztZQUN4QyxJQUFJLENBQUMsd0JBQXdCLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDekMsQ0FBQztRQUVE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
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Factur-X validator for profile-specific compliance
|
|
3
|
+
* Implements validation for MINIMUM, BASIC, EN16931, and EXTENDED profiles
|
|
4
|
+
*/
|
|
5
|
+
import type { ValidationResult } from './validation.types.js';
|
|
6
|
+
import type { EInvoice } from '../../einvoice.js';
|
|
7
|
+
/**
|
|
8
|
+
* Factur-X Profile definitions
|
|
9
|
+
*/
|
|
10
|
+
export declare enum FacturXProfile {
|
|
11
|
+
MINIMUM = "MINIMUM",
|
|
12
|
+
BASIC = "BASIC",
|
|
13
|
+
BASIC_WL = "BASIC_WL",// Basic without lines
|
|
14
|
+
EN16931 = "EN16931",
|
|
15
|
+
EXTENDED = "EXTENDED"
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Factur-X Validator
|
|
19
|
+
* Validates invoices according to Factur-X profile specifications
|
|
20
|
+
*/
|
|
21
|
+
export declare class FacturXValidator {
|
|
22
|
+
private static instance;
|
|
23
|
+
/**
|
|
24
|
+
* Profile requirements mapping
|
|
25
|
+
*/
|
|
26
|
+
private profileRequirements;
|
|
27
|
+
/**
|
|
28
|
+
* Singleton pattern for validator instance
|
|
29
|
+
*/
|
|
30
|
+
static create(): FacturXValidator;
|
|
31
|
+
/**
|
|
32
|
+
* Main validation entry point for Factur-X
|
|
33
|
+
*/
|
|
34
|
+
validateFacturX(invoice: EInvoice, profile?: FacturXProfile): ValidationResult[];
|
|
35
|
+
/**
|
|
36
|
+
* Detect Factur-X profile from invoice metadata
|
|
37
|
+
*/
|
|
38
|
+
detectProfile(invoice: EInvoice): FacturXProfile | null;
|
|
39
|
+
/**
|
|
40
|
+
* Validate field requirements for a specific profile
|
|
41
|
+
*/
|
|
42
|
+
private validateProfileRequirements;
|
|
43
|
+
/**
|
|
44
|
+
* Get field value from invoice using dot notation
|
|
45
|
+
*/
|
|
46
|
+
private getFieldValue;
|
|
47
|
+
/**
|
|
48
|
+
* Profile-specific validation rules
|
|
49
|
+
*/
|
|
50
|
+
private validateProfileSpecificRules;
|
|
51
|
+
/**
|
|
52
|
+
* Validate MINIMUM profile specific rules
|
|
53
|
+
*/
|
|
54
|
+
private validateMinimumProfile;
|
|
55
|
+
/**
|
|
56
|
+
* Validate BASIC profile specific rules
|
|
57
|
+
*/
|
|
58
|
+
private validateBasicProfile;
|
|
59
|
+
/**
|
|
60
|
+
* Validate EN16931 profile specific rules
|
|
61
|
+
*/
|
|
62
|
+
private validateEN16931Profile;
|
|
63
|
+
/**
|
|
64
|
+
* Validate EXTENDED profile specific rules
|
|
65
|
+
*/
|
|
66
|
+
private validateExtendedProfile;
|
|
67
|
+
/**
|
|
68
|
+
* Get profile display name
|
|
69
|
+
*/
|
|
70
|
+
getProfileDisplayName(profile: FacturXProfile): string;
|
|
71
|
+
/**
|
|
72
|
+
* Get profile compliance level (for reporting)
|
|
73
|
+
*/
|
|
74
|
+
getProfileComplianceLevel(profile: FacturXProfile): number;
|
|
75
|
+
}
|