@fin.cx/einvoice 5.0.3 → 5.1.3

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 (117) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/einvoice.d.ts +4 -8
  3. package/dist_ts/einvoice.js +46 -7
  4. package/dist_ts/formats/converters/xml-to-einvoice.converter.d.ts +21 -0
  5. package/dist_ts/formats/converters/xml-to-einvoice.converter.js +127 -0
  6. package/dist_ts/formats/semantic/bt-bg.model.d.ts +445 -0
  7. package/dist_ts/formats/semantic/bt-bg.model.js +12 -0
  8. package/dist_ts/formats/semantic/semantic.adapter.d.ts +87 -0
  9. package/dist_ts/formats/semantic/semantic.adapter.js +538 -0
  10. package/dist_ts/formats/semantic/semantic.validator.d.ts +48 -0
  11. package/dist_ts/formats/semantic/semantic.validator.js +596 -0
  12. package/dist_ts/formats/utils/currency.calculator.decimal.d.ts +98 -0
  13. package/dist_ts/formats/utils/currency.calculator.decimal.js +212 -0
  14. package/dist_ts/formats/utils/currency.utils.d.ts +99 -0
  15. package/dist_ts/formats/utils/currency.utils.js +250 -0
  16. package/dist_ts/formats/utils/decimal.d.ts +151 -0
  17. package/dist_ts/formats/utils/decimal.js +435 -0
  18. package/dist_ts/formats/validation/codelist.validator.d.ts +49 -0
  19. package/dist_ts/formats/validation/codelist.validator.js +188 -0
  20. package/dist_ts/formats/validation/conformance.harness.d.ts +99 -0
  21. package/dist_ts/formats/validation/conformance.harness.js +471 -0
  22. package/dist_ts/formats/validation/en16931.business-rules.validator.d.ts +58 -0
  23. package/dist_ts/formats/validation/en16931.business-rules.validator.js +459 -0
  24. package/dist_ts/formats/validation/facturx.validator.d.ts +75 -0
  25. package/dist_ts/formats/validation/facturx.validator.js +522 -0
  26. package/dist_ts/formats/validation/integrated.validator.d.ts +82 -0
  27. package/dist_ts/formats/validation/integrated.validator.js +311 -0
  28. package/dist_ts/formats/validation/peppol.validator.d.ts +77 -0
  29. package/dist_ts/formats/validation/peppol.validator.js +529 -0
  30. package/dist_ts/formats/validation/schematron.downloader.d.ts +71 -0
  31. package/dist_ts/formats/validation/schematron.downloader.js +254 -0
  32. package/dist_ts/formats/validation/schematron.integration.d.ts +60 -0
  33. package/dist_ts/formats/validation/schematron.integration.js +230 -0
  34. package/dist_ts/formats/validation/schematron.validator.d.ts +79 -0
  35. package/dist_ts/formats/validation/schematron.validator.js +288 -0
  36. package/dist_ts/formats/validation/schematron.worker.d.ts +50 -0
  37. package/dist_ts/formats/validation/schematron.worker.js +185 -0
  38. package/dist_ts/formats/validation/validation.types.d.ts +163 -0
  39. package/dist_ts/formats/validation/validation.types.js +181 -0
  40. package/dist_ts/formats/validation/vat-categories.validator.d.ts +87 -0
  41. package/dist_ts/formats/validation/vat-categories.validator.js +497 -0
  42. package/dist_ts/formats/validation/xrechnung.validator.d.ts +92 -0
  43. package/dist_ts/formats/validation/xrechnung.validator.js +417 -0
  44. package/dist_ts/interfaces/common.d.ts +1 -0
  45. package/dist_ts/interfaces/en16931-metadata.d.ts +83 -0
  46. package/dist_ts/interfaces/en16931-metadata.js +6 -0
  47. package/dist_ts/plugins.d.ts +3 -1
  48. package/dist_ts/plugins.js +7 -2
  49. package/dist_ts_install/download-schematron.d.ts +6 -0
  50. package/dist_ts_install/download-schematron.js +62 -0
  51. package/dist_ts_install/download-test-samples.d.ts +19 -0
  52. package/dist_ts_install/download-test-samples.js +169 -0
  53. package/dist_ts_install/download-xrechnung-rules.d.ts +7 -0
  54. package/dist_ts_install/download-xrechnung-rules.js +146 -0
  55. package/dist_ts_install/index.d.ts +8 -0
  56. package/dist_ts_install/index.js +246 -0
  57. package/npmextra.json +1 -1
  58. package/package.json +12 -6
  59. package/readme.md +255 -810
  60. package/ts/00_commitinfo_data.ts +1 -1
  61. package/ts/einvoice.ts +63 -14
  62. package/ts/formats/converters/xml-to-einvoice.converter.ts +142 -0
  63. package/ts/formats/semantic/bt-bg.model.ts +524 -0
  64. package/ts/formats/semantic/semantic.adapter.ts +600 -0
  65. package/ts/formats/semantic/semantic.validator.ts +654 -0
  66. package/ts/formats/utils/currency.calculator.decimal.ts +323 -0
  67. package/ts/formats/utils/currency.utils.ts +299 -0
  68. package/ts/formats/utils/decimal.ts +509 -0
  69. package/ts/formats/validation/codelist.validator.ts +317 -0
  70. package/ts/formats/validation/conformance.harness.ts +591 -0
  71. package/ts/formats/validation/en16931.business-rules.validator.ts +694 -0
  72. package/ts/formats/validation/facturx.validator.ts +579 -0
  73. package/ts/formats/validation/integrated.validator.ts +405 -0
  74. package/ts/formats/validation/peppol.validator.ts +589 -0
  75. package/ts/formats/validation/schematron.downloader.ts +304 -0
  76. package/ts/formats/validation/schematron.integration.ts +285 -0
  77. package/ts/formats/validation/schematron.validator.ts +348 -0
  78. package/ts/formats/validation/schematron.worker.ts +221 -0
  79. package/ts/formats/validation/validation.types.ts +274 -0
  80. package/ts/formats/validation/vat-categories.validator.ts +845 -0
  81. package/ts/formats/validation/xrechnung.validator.ts +494 -0
  82. package/ts/interfaces/common.ts +1 -0
  83. package/ts/interfaces/en16931-metadata.ts +104 -0
  84. package/ts/plugins.ts +8 -0
  85. package/ts/tspublish.json +3 -0
  86. package/dist_ts/classes.decoder.d.ts +0 -40
  87. package/dist_ts/classes.decoder.js +0 -320
  88. package/dist_ts/classes.encoder.d.ts +0 -51
  89. package/dist_ts/classes.encoder.js +0 -293
  90. package/dist_ts/classes.xinvoice.d.ts +0 -136
  91. package/dist_ts/classes.xinvoice.js +0 -352
  92. package/dist_ts/formats/base.decoder.d.ts +0 -19
  93. package/dist_ts/formats/base.decoder.js +0 -130
  94. package/dist_ts/formats/base.validator.d.ts +0 -44
  95. package/dist_ts/formats/base.validator.js +0 -39
  96. package/dist_ts/formats/decoder.factory.d.ts +0 -15
  97. package/dist_ts/formats/decoder.factory.js +0 -46
  98. package/dist_ts/formats/factorx.decoder.d.ts +0 -18
  99. package/dist_ts/formats/factorx.decoder.js +0 -178
  100. package/dist_ts/formats/factorx.encoder.d.ts +0 -51
  101. package/dist_ts/formats/factorx.encoder.js +0 -293
  102. package/dist_ts/formats/facturx.decoder.d.ts +0 -18
  103. package/dist_ts/formats/facturx.decoder.js +0 -210
  104. package/dist_ts/formats/facturx.encoder.d.ts +0 -51
  105. package/dist_ts/formats/facturx.encoder.js +0 -293
  106. package/dist_ts/formats/facturx.validator.d.ts +0 -67
  107. package/dist_ts/formats/facturx.validator.js +0 -266
  108. package/dist_ts/formats/pdf/robust-pdf.extractor.d.ts +0 -40
  109. package/dist_ts/formats/pdf/robust-pdf.extractor.js +0 -324
  110. package/dist_ts/formats/ubl.validator.d.ts +0 -82
  111. package/dist_ts/formats/ubl.validator.js +0 -306
  112. package/dist_ts/formats/validator.factory.d.ts +0 -18
  113. package/dist_ts/formats/validator.factory.js +0 -78
  114. package/dist_ts/formats/xinvoice.decoder.d.ts +0 -28
  115. package/dist_ts/formats/xinvoice.decoder.js +0 -332
  116. package/dist_ts/formats/xinvoice.encoder.d.ts +0 -19
  117. 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
+ }