@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.
Files changed (116) 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/package.json +13 -8
  58. package/readme.md +255 -810
  59. package/ts/00_commitinfo_data.ts +1 -1
  60. package/ts/einvoice.ts +63 -14
  61. package/ts/formats/converters/xml-to-einvoice.converter.ts +142 -0
  62. package/ts/formats/semantic/bt-bg.model.ts +524 -0
  63. package/ts/formats/semantic/semantic.adapter.ts +600 -0
  64. package/ts/formats/semantic/semantic.validator.ts +654 -0
  65. package/ts/formats/utils/currency.calculator.decimal.ts +323 -0
  66. package/ts/formats/utils/currency.utils.ts +299 -0
  67. package/ts/formats/utils/decimal.ts +509 -0
  68. package/ts/formats/validation/codelist.validator.ts +317 -0
  69. package/ts/formats/validation/conformance.harness.ts +591 -0
  70. package/ts/formats/validation/en16931.business-rules.validator.ts +694 -0
  71. package/ts/formats/validation/facturx.validator.ts +579 -0
  72. package/ts/formats/validation/integrated.validator.ts +405 -0
  73. package/ts/formats/validation/peppol.validator.ts +589 -0
  74. package/ts/formats/validation/schematron.downloader.ts +304 -0
  75. package/ts/formats/validation/schematron.integration.ts +285 -0
  76. package/ts/formats/validation/schematron.validator.ts +348 -0
  77. package/ts/formats/validation/schematron.worker.ts +221 -0
  78. package/ts/formats/validation/validation.types.ts +274 -0
  79. package/ts/formats/validation/vat-categories.validator.ts +845 -0
  80. package/ts/formats/validation/xrechnung.validator.ts +494 -0
  81. package/ts/interfaces/common.ts +1 -0
  82. package/ts/interfaces/en16931-metadata.ts +104 -0
  83. package/ts/plugins.ts +8 -0
  84. package/ts/tspublish.json +3 -0
  85. package/dist_ts/classes.decoder.d.ts +0 -40
  86. package/dist_ts/classes.decoder.js +0 -320
  87. package/dist_ts/classes.encoder.d.ts +0 -51
  88. package/dist_ts/classes.encoder.js +0 -293
  89. package/dist_ts/classes.xinvoice.d.ts +0 -136
  90. package/dist_ts/classes.xinvoice.js +0 -352
  91. package/dist_ts/formats/base.decoder.d.ts +0 -19
  92. package/dist_ts/formats/base.decoder.js +0 -130
  93. package/dist_ts/formats/base.validator.d.ts +0 -44
  94. package/dist_ts/formats/base.validator.js +0 -39
  95. package/dist_ts/formats/decoder.factory.d.ts +0 -15
  96. package/dist_ts/formats/decoder.factory.js +0 -46
  97. package/dist_ts/formats/factorx.decoder.d.ts +0 -18
  98. package/dist_ts/formats/factorx.decoder.js +0 -178
  99. package/dist_ts/formats/factorx.encoder.d.ts +0 -51
  100. package/dist_ts/formats/factorx.encoder.js +0 -293
  101. package/dist_ts/formats/facturx.decoder.d.ts +0 -18
  102. package/dist_ts/formats/facturx.decoder.js +0 -210
  103. package/dist_ts/formats/facturx.encoder.d.ts +0 -51
  104. package/dist_ts/formats/facturx.encoder.js +0 -293
  105. package/dist_ts/formats/facturx.validator.d.ts +0 -67
  106. package/dist_ts/formats/facturx.validator.js +0 -266
  107. package/dist_ts/formats/pdf/robust-pdf.extractor.d.ts +0 -40
  108. package/dist_ts/formats/pdf/robust-pdf.extractor.js +0 -324
  109. package/dist_ts/formats/ubl.validator.d.ts +0 -82
  110. package/dist_ts/formats/ubl.validator.js +0 -306
  111. package/dist_ts/formats/validator.factory.d.ts +0 -18
  112. package/dist_ts/formats/validator.factory.js +0 -78
  113. package/dist_ts/formats/xinvoice.decoder.d.ts +0 -28
  114. package/dist_ts/formats/xinvoice.decoder.js +0 -332
  115. package/dist_ts/formats/xinvoice.encoder.d.ts +0 -19
  116. package/dist_ts/formats/xinvoice.encoder.js +0 -282
@@ -0,0 +1,497 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import { CurrencyCalculator } from '../utils/currency.utils.js';
3
+ /**
4
+ * VAT Category codes according to UNCL5305
5
+ */
6
+ export var VATCategory;
7
+ (function (VATCategory) {
8
+ VATCategory["S"] = "S";
9
+ VATCategory["Z"] = "Z";
10
+ VATCategory["E"] = "E";
11
+ VATCategory["AE"] = "AE";
12
+ VATCategory["K"] = "K";
13
+ VATCategory["G"] = "G";
14
+ VATCategory["O"] = "O";
15
+ VATCategory["L"] = "L";
16
+ VATCategory["M"] = "M"; // Tax for production, services and importation in Ceuta and Melilla
17
+ })(VATCategory || (VATCategory = {}));
18
+ /**
19
+ * Comprehensive VAT Category Rules Validator
20
+ * Implements all EN16931 VAT category-specific business rules
21
+ */
22
+ export class VATCategoriesValidator {
23
+ constructor() {
24
+ this.results = [];
25
+ }
26
+ /**
27
+ * Validate VAT categories according to EN16931
28
+ */
29
+ validate(invoice) {
30
+ this.results = [];
31
+ // Initialize currency calculator if currency is available
32
+ if (invoice.currency) {
33
+ this.currencyCalculator = new CurrencyCalculator(invoice.currency);
34
+ }
35
+ // Group items by VAT category
36
+ const itemsByCategory = this.groupItemsByVATCategory(invoice.items || []);
37
+ const breakdownsByCategory = this.groupBreakdownsByCategory(invoice.taxBreakdown || []);
38
+ // Validate each VAT category
39
+ this.validateStandardRate(itemsByCategory.get('S'), breakdownsByCategory.get('S'), invoice);
40
+ this.validateZeroRated(itemsByCategory.get('Z'), breakdownsByCategory.get('Z'), invoice);
41
+ this.validateExempt(itemsByCategory.get('E'), breakdownsByCategory.get('E'), invoice);
42
+ this.validateReverseCharge(itemsByCategory.get('AE'), breakdownsByCategory.get('AE'), invoice);
43
+ this.validateIntraCommunity(itemsByCategory.get('K'), breakdownsByCategory.get('K'), invoice);
44
+ this.validateExport(itemsByCategory.get('G'), breakdownsByCategory.get('G'), invoice);
45
+ this.validateOutOfScope(itemsByCategory.get('O'), breakdownsByCategory.get('O'), invoice);
46
+ // Cross-category validation
47
+ this.validateCrossCategoryRules(invoice, itemsByCategory, breakdownsByCategory);
48
+ return this.results;
49
+ }
50
+ /**
51
+ * Validate Standard Rate VAT (BR-S-*)
52
+ */
53
+ validateStandardRate(items, breakdown, invoice) {
54
+ if (!items || items.length === 0)
55
+ return;
56
+ // BR-S-01: Invoice with standard rated items must have standard rated breakdown
57
+ if (!breakdown) {
58
+ this.addError('BR-S-01', 'Invoice with standard rated items must have a standard rated VAT breakdown', 'taxBreakdown');
59
+ return;
60
+ }
61
+ // BR-S-02: Standard rate VAT category taxable amount
62
+ const expectedTaxable = this.calculateTaxableAmount(items);
63
+ if (!this.areAmountsEqual(breakdown.netAmount, expectedTaxable)) {
64
+ this.addError('BR-S-02', `Standard rate VAT taxable amount mismatch`, 'taxBreakdown.netAmount', breakdown.netAmount, expectedTaxable);
65
+ }
66
+ // BR-S-03: Standard rate VAT category tax amount
67
+ const rate = breakdown.taxPercent || 0;
68
+ const expectedTax = this.calculateVATAmount(expectedTaxable, rate);
69
+ if (!this.areAmountsEqual(breakdown.taxAmount, expectedTax)) {
70
+ this.addError('BR-S-03', `Standard rate VAT tax amount mismatch`, 'taxBreakdown.taxAmount', breakdown.taxAmount, expectedTax);
71
+ }
72
+ // BR-S-04: Standard rate VAT category code must be "S"
73
+ if (breakdown.categoryCode && breakdown.categoryCode !== 'S') {
74
+ this.addError('BR-S-04', 'Standard rate VAT category code must be "S"', 'taxBreakdown.categoryCode', breakdown.categoryCode, 'S');
75
+ }
76
+ // BR-S-05: Standard rate VAT rate must be greater than zero
77
+ if (rate <= 0) {
78
+ this.addError('BR-S-05', 'Standard rate VAT rate must be greater than zero', 'taxBreakdown.taxPercent', rate, '> 0');
79
+ }
80
+ // BR-S-08: No exemption reason for standard rate
81
+ if (breakdown.exemptionReason) {
82
+ this.addError('BR-S-08', 'Standard rate VAT must not have an exemption reason', 'taxBreakdown.exemptionReason');
83
+ }
84
+ }
85
+ /**
86
+ * Validate Zero Rated VAT (BR-Z-*)
87
+ */
88
+ validateZeroRated(items, breakdown, invoice) {
89
+ if (!items || items.length === 0)
90
+ return;
91
+ // BR-Z-01: Invoice with zero rated items must have zero rated breakdown
92
+ if (!breakdown) {
93
+ this.addError('BR-Z-01', 'Invoice with zero rated items must have a zero rated VAT breakdown', 'taxBreakdown');
94
+ return;
95
+ }
96
+ // BR-Z-02: Zero rate VAT category taxable amount
97
+ const expectedTaxable = this.calculateTaxableAmount(items);
98
+ if (!this.areAmountsEqual(breakdown.netAmount, expectedTaxable)) {
99
+ this.addError('BR-Z-02', 'Zero rate VAT taxable amount mismatch', 'taxBreakdown.netAmount', breakdown.netAmount, expectedTaxable);
100
+ }
101
+ // BR-Z-03: Zero rate VAT tax amount must be zero
102
+ if (breakdown.taxAmount !== 0) {
103
+ this.addError('BR-Z-03', 'Zero rate VAT tax amount must be zero', 'taxBreakdown.taxAmount', breakdown.taxAmount, 0);
104
+ }
105
+ // BR-Z-04: Zero rate VAT category code must be "Z"
106
+ if (breakdown.categoryCode && breakdown.categoryCode !== 'Z') {
107
+ this.addError('BR-Z-04', 'Zero rate VAT category code must be "Z"', 'taxBreakdown.categoryCode', breakdown.categoryCode, 'Z');
108
+ }
109
+ // BR-Z-05: Zero rate VAT rate must be zero
110
+ if (breakdown.taxPercent !== 0) {
111
+ this.addError('BR-Z-05', 'Zero rate VAT rate must be zero', 'taxBreakdown.taxPercent', breakdown.taxPercent, 0);
112
+ }
113
+ }
114
+ /**
115
+ * Validate Exempt from Tax (BR-E-*)
116
+ */
117
+ validateExempt(items, breakdown, invoice) {
118
+ if (!items || items.length === 0)
119
+ return;
120
+ // BR-E-01: Invoice with exempt items must have exempt breakdown
121
+ if (!breakdown) {
122
+ this.addError('BR-E-01', 'Invoice with tax exempt items must have an exempt VAT breakdown', 'taxBreakdown');
123
+ return;
124
+ }
125
+ // BR-E-02: Exempt VAT category taxable amount
126
+ const expectedTaxable = this.calculateTaxableAmount(items);
127
+ if (!this.areAmountsEqual(breakdown.netAmount, expectedTaxable)) {
128
+ this.addError('BR-E-02', 'Exempt VAT taxable amount mismatch', 'taxBreakdown.netAmount', breakdown.netAmount, expectedTaxable);
129
+ }
130
+ // BR-E-03: Exempt VAT tax amount must be zero
131
+ if (breakdown.taxAmount !== 0) {
132
+ this.addError('BR-E-03', 'Exempt VAT tax amount must be zero', 'taxBreakdown.taxAmount', breakdown.taxAmount, 0);
133
+ }
134
+ // BR-E-04: Exempt VAT category code must be "E"
135
+ if (breakdown.categoryCode && breakdown.categoryCode !== 'E') {
136
+ this.addError('BR-E-04', 'Exempt VAT category code must be "E"', 'taxBreakdown.categoryCode', breakdown.categoryCode, 'E');
137
+ }
138
+ // BR-E-05: Exempt VAT rate must be zero
139
+ if (breakdown.taxPercent !== 0) {
140
+ this.addError('BR-E-05', 'Exempt VAT rate must be zero', 'taxBreakdown.taxPercent', breakdown.taxPercent, 0);
141
+ }
142
+ // BR-E-06: Exempt VAT must have exemption reason
143
+ if (!breakdown.exemptionReason && !breakdown.exemptionReasonCode) {
144
+ this.addError('BR-E-06', 'Exempt VAT must have an exemption reason or exemption reason code', 'taxBreakdown.exemptionReason');
145
+ }
146
+ }
147
+ /**
148
+ * Validate VAT Reverse Charge (BR-AE-*)
149
+ */
150
+ validateReverseCharge(items, breakdown, invoice) {
151
+ if (!items || items.length === 0)
152
+ return;
153
+ // BR-AE-01: Invoice with reverse charge items must have reverse charge breakdown
154
+ if (!breakdown) {
155
+ this.addError('BR-AE-01', 'Invoice with reverse charge items must have a reverse charge VAT breakdown', 'taxBreakdown');
156
+ return;
157
+ }
158
+ // BR-AE-02: Reverse charge VAT category taxable amount
159
+ const expectedTaxable = this.calculateTaxableAmount(items);
160
+ if (!this.areAmountsEqual(breakdown.netAmount, expectedTaxable)) {
161
+ this.addError('BR-AE-02', 'Reverse charge VAT taxable amount mismatch', 'taxBreakdown.netAmount', breakdown.netAmount, expectedTaxable);
162
+ }
163
+ // BR-AE-03: Reverse charge VAT tax amount must be zero
164
+ if (breakdown.taxAmount !== 0) {
165
+ this.addError('BR-AE-03', 'Reverse charge VAT tax amount must be zero', 'taxBreakdown.taxAmount', breakdown.taxAmount, 0);
166
+ }
167
+ // BR-AE-04: Reverse charge VAT category code must be "AE"
168
+ if (breakdown.categoryCode && breakdown.categoryCode !== 'AE') {
169
+ this.addError('BR-AE-04', 'Reverse charge VAT category code must be "AE"', 'taxBreakdown.categoryCode', breakdown.categoryCode, 'AE');
170
+ }
171
+ // BR-AE-05: Reverse charge VAT rate must be zero
172
+ if (breakdown.taxPercent !== 0) {
173
+ this.addError('BR-AE-05', 'Reverse charge VAT rate must be zero', 'taxBreakdown.taxPercent', breakdown.taxPercent, 0);
174
+ }
175
+ // BR-AE-06: Reverse charge must have exemption reason
176
+ if (!breakdown.exemptionReason && !breakdown.exemptionReasonCode) {
177
+ this.addError('BR-AE-06', 'Reverse charge VAT must have an exemption reason', 'taxBreakdown.exemptionReason');
178
+ }
179
+ // BR-AE-08: Buyer must have VAT identifier for reverse charge
180
+ if (!invoice?.metadata?.buyerTaxId) {
181
+ this.addError('BR-AE-08', 'Buyer must have a VAT identifier for reverse charge invoices', 'metadata.buyerTaxId');
182
+ }
183
+ }
184
+ /**
185
+ * Validate Intra-Community Supply (BR-K-*)
186
+ */
187
+ validateIntraCommunity(items, breakdown, invoice) {
188
+ if (!items || items.length === 0)
189
+ return;
190
+ // BR-K-01: Invoice with intra-community items must have intra-community breakdown
191
+ if (!breakdown) {
192
+ this.addError('BR-K-01', 'Invoice with intra-community supply must have corresponding VAT breakdown', 'taxBreakdown');
193
+ return;
194
+ }
195
+ // BR-K-02: Intra-community VAT category taxable amount
196
+ const expectedTaxable = this.calculateTaxableAmount(items);
197
+ if (!this.areAmountsEqual(breakdown.netAmount, expectedTaxable)) {
198
+ this.addError('BR-K-02', 'Intra-community VAT taxable amount mismatch', 'taxBreakdown.netAmount', breakdown.netAmount, expectedTaxable);
199
+ }
200
+ // BR-K-03: Intra-community VAT tax amount must be zero
201
+ if (breakdown.taxAmount !== 0) {
202
+ this.addError('BR-K-03', 'Intra-community VAT tax amount must be zero', 'taxBreakdown.taxAmount', breakdown.taxAmount, 0);
203
+ }
204
+ // BR-K-04: Intra-community VAT category code must be "K"
205
+ if (breakdown.categoryCode && breakdown.categoryCode !== 'K') {
206
+ this.addError('BR-K-04', 'Intra-community VAT category code must be "K"', 'taxBreakdown.categoryCode', breakdown.categoryCode, 'K');
207
+ }
208
+ // BR-K-05: Intra-community VAT rate must be zero
209
+ if (breakdown.taxPercent !== 0) {
210
+ this.addError('BR-K-05', 'Intra-community VAT rate must be zero', 'taxBreakdown.taxPercent', breakdown.taxPercent, 0);
211
+ }
212
+ // BR-K-06: Must have exemption reason
213
+ if (!breakdown.exemptionReason && !breakdown.exemptionReasonCode) {
214
+ this.addError('BR-K-06', 'Intra-community supply must have an exemption reason', 'taxBreakdown.exemptionReason');
215
+ }
216
+ // BR-K-08: Both seller and buyer must have VAT identifiers
217
+ if (!invoice?.metadata?.sellerTaxId) {
218
+ this.addError('BR-K-08', 'Seller must have a VAT identifier for intra-community supply', 'metadata.sellerTaxId');
219
+ }
220
+ if (!invoice?.metadata?.buyerTaxId) {
221
+ this.addError('BR-K-09', 'Buyer must have a VAT identifier for intra-community supply', 'metadata.buyerTaxId');
222
+ }
223
+ // BR-K-10: Must be in different EU member states
224
+ if (invoice?.from?.address?.countryCode === invoice?.to?.address?.countryCode) {
225
+ this.addWarning('BR-K-10', 'Intra-community supply should be between different EU member states', 'address.countryCode');
226
+ }
227
+ }
228
+ /**
229
+ * Validate Export Outside EU (BR-G-*)
230
+ */
231
+ validateExport(items, breakdown, invoice) {
232
+ if (!items || items.length === 0)
233
+ return;
234
+ // BR-G-01: Invoice with export items must have export breakdown
235
+ if (!breakdown) {
236
+ this.addError('BR-G-01', 'Invoice with export items must have an export VAT breakdown', 'taxBreakdown');
237
+ return;
238
+ }
239
+ // BR-G-02: Export VAT category taxable amount
240
+ const expectedTaxable = this.calculateTaxableAmount(items);
241
+ if (!this.areAmountsEqual(breakdown.netAmount, expectedTaxable)) {
242
+ this.addError('BR-G-02', 'Export VAT taxable amount mismatch', 'taxBreakdown.netAmount', breakdown.netAmount, expectedTaxable);
243
+ }
244
+ // BR-G-03: Export VAT tax amount must be zero
245
+ if (breakdown.taxAmount !== 0) {
246
+ this.addError('BR-G-03', 'Export VAT tax amount must be zero', 'taxBreakdown.taxAmount', breakdown.taxAmount, 0);
247
+ }
248
+ // BR-G-04: Export VAT category code must be "G"
249
+ if (breakdown.categoryCode && breakdown.categoryCode !== 'G') {
250
+ this.addError('BR-G-04', 'Export VAT category code must be "G"', 'taxBreakdown.categoryCode', breakdown.categoryCode, 'G');
251
+ }
252
+ // BR-G-05: Export VAT rate must be zero
253
+ if (breakdown.taxPercent !== 0) {
254
+ this.addError('BR-G-05', 'Export VAT rate must be zero', 'taxBreakdown.taxPercent', breakdown.taxPercent, 0);
255
+ }
256
+ // BR-G-06: Must have exemption reason
257
+ if (!breakdown.exemptionReason && !breakdown.exemptionReasonCode) {
258
+ this.addError('BR-G-06', 'Export must have an exemption reason', 'taxBreakdown.exemptionReason');
259
+ }
260
+ // BR-G-08: Buyer should be outside EU
261
+ const buyerCountry = invoice?.to?.address?.countryCode;
262
+ if (buyerCountry && this.isEUCountry(buyerCountry)) {
263
+ this.addWarning('BR-G-08', 'Export category should be used for buyers outside EU', 'to.address.countryCode', buyerCountry, 'non-EU');
264
+ }
265
+ }
266
+ /**
267
+ * Validate Out of Scope Services (BR-O-*)
268
+ */
269
+ validateOutOfScope(items, breakdown, invoice) {
270
+ if (!items || items.length === 0)
271
+ return;
272
+ // BR-O-01: Invoice with out of scope items must have out of scope breakdown
273
+ if (!breakdown) {
274
+ this.addError('BR-O-01', 'Invoice with out of scope items must have corresponding VAT breakdown', 'taxBreakdown');
275
+ return;
276
+ }
277
+ // BR-O-02: Out of scope VAT category taxable amount
278
+ const expectedTaxable = this.calculateTaxableAmount(items);
279
+ if (!this.areAmountsEqual(breakdown.netAmount, expectedTaxable)) {
280
+ this.addError('BR-O-02', 'Out of scope VAT taxable amount mismatch', 'taxBreakdown.netAmount', breakdown.netAmount, expectedTaxable);
281
+ }
282
+ // BR-O-03: Out of scope VAT tax amount must be zero
283
+ if (breakdown.taxAmount !== 0) {
284
+ this.addError('BR-O-03', 'Out of scope VAT tax amount must be zero', 'taxBreakdown.taxAmount', breakdown.taxAmount, 0);
285
+ }
286
+ // BR-O-04: Out of scope VAT category code must be "O"
287
+ if (breakdown.categoryCode && breakdown.categoryCode !== 'O') {
288
+ this.addError('BR-O-04', 'Out of scope VAT category code must be "O"', 'taxBreakdown.categoryCode', breakdown.categoryCode, 'O');
289
+ }
290
+ // BR-O-05: Out of scope VAT rate must be zero
291
+ if (breakdown.taxPercent !== 0) {
292
+ this.addError('BR-O-05', 'Out of scope VAT rate must be zero', 'taxBreakdown.taxPercent', breakdown.taxPercent, 0);
293
+ }
294
+ // BR-O-06: Must have exemption reason
295
+ if (!breakdown.exemptionReason && !breakdown.exemptionReasonCode) {
296
+ this.addError('BR-O-06', 'Out of scope services must have an exemption reason', 'taxBreakdown.exemptionReason');
297
+ }
298
+ }
299
+ /**
300
+ * Cross-category validation rules
301
+ */
302
+ validateCrossCategoryRules(invoice, itemsByCategory, breakdownsByCategory) {
303
+ // BR-CO-17: VAT category tax amount = Σ(VAT category taxable amount × VAT rate)
304
+ breakdownsByCategory.forEach((breakdown, category) => {
305
+ if (category === 'S' && breakdown.taxPercent > 0) {
306
+ const expectedTax = this.calculateVATAmount(breakdown.netAmount, breakdown.taxPercent);
307
+ if (!this.areAmountsEqual(breakdown.taxAmount, expectedTax)) {
308
+ this.addError('BR-CO-17', `VAT tax amount calculation error for category ${category}`, 'taxBreakdown.taxAmount', breakdown.taxAmount, expectedTax);
309
+ }
310
+ }
311
+ });
312
+ // BR-CO-18: Invoice with mixed VAT categories
313
+ const categoriesUsed = new Set();
314
+ itemsByCategory.forEach((items, category) => {
315
+ if (items.length > 0)
316
+ categoriesUsed.add(category);
317
+ });
318
+ // BR-IC-01: Supply to EU countries without VAT ID should use standard rate
319
+ if (categoriesUsed.has('K') && !invoice.metadata?.buyerTaxId) {
320
+ this.addError('BR-IC-01', 'Intra-community supply requires buyer VAT identifier', 'metadata.buyerTaxId');
321
+ }
322
+ // BR-IC-02: Reverse charge requires specific conditions
323
+ if (categoriesUsed.has('AE')) {
324
+ // Check for service codes that qualify for reverse charge
325
+ const hasQualifyingServices = invoice.items?.some(item => this.isReverseChargeService(item));
326
+ if (!hasQualifyingServices) {
327
+ this.addWarning('BR-IC-02', 'Reverse charge should only be used for qualifying services', 'items');
328
+ }
329
+ }
330
+ // BR-CO-19: Sum of VAT breakdown taxable amounts must equal invoice tax exclusive total
331
+ let totalTaxable = 0;
332
+ breakdownsByCategory.forEach(breakdown => {
333
+ totalTaxable += breakdown.netAmount || 0;
334
+ });
335
+ const declaredTotal = invoice.totalNet || 0;
336
+ if (!this.areAmountsEqual(totalTaxable, declaredTotal)) {
337
+ this.addError('BR-CO-19', 'Sum of VAT breakdown taxable amounts must equal invoice total without VAT', 'totalNet', declaredTotal, totalTaxable);
338
+ }
339
+ }
340
+ // Helper methods
341
+ groupItemsByVATCategory(items) {
342
+ const groups = new Map();
343
+ items.forEach(item => {
344
+ const category = this.determineVATCategory(item);
345
+ if (!groups.has(category)) {
346
+ groups.set(category, []);
347
+ }
348
+ groups.get(category).push(item);
349
+ });
350
+ return groups;
351
+ }
352
+ groupBreakdownsByCategory(breakdowns) {
353
+ const groups = new Map();
354
+ breakdowns.forEach(breakdown => {
355
+ const category = breakdown.categoryCode || this.inferCategoryFromRate(breakdown.taxPercent);
356
+ groups.set(category, breakdown);
357
+ });
358
+ return groups;
359
+ }
360
+ determineVATCategory(item) {
361
+ // Determine VAT category from item metadata or rate
362
+ const metadata = item.metadata;
363
+ if (metadata?.vatCategory) {
364
+ return metadata.vatCategory;
365
+ }
366
+ // Infer from rate
367
+ if (item.vatPercentage === undefined || item.vatPercentage === null) {
368
+ return 'S'; // Default to standard
369
+ }
370
+ else if (item.vatPercentage > 0) {
371
+ return 'S'; // Standard rate
372
+ }
373
+ else if (item.vatPercentage === 0) {
374
+ // Could be Z, E, AE, K, G, or O - need more context
375
+ if (metadata?.exemptionReason) {
376
+ if (metadata.exemptionReason.includes('reverse'))
377
+ return 'AE';
378
+ if (metadata.exemptionReason.includes('intra'))
379
+ return 'K';
380
+ if (metadata.exemptionReason.includes('export'))
381
+ return 'G';
382
+ if (metadata.exemptionReason.includes('scope'))
383
+ return 'O';
384
+ return 'E'; // Default exempt
385
+ }
386
+ return 'Z'; // Default zero-rated
387
+ }
388
+ return 'S'; // Default
389
+ }
390
+ inferCategoryFromRate(rate) {
391
+ if (!rate || rate === 0)
392
+ return 'Z';
393
+ if (rate > 0)
394
+ return 'S';
395
+ return 'S';
396
+ }
397
+ calculateTaxableAmount(items) {
398
+ const total = items.reduce((sum, item) => {
399
+ const lineNet = (item.unitNetPrice || 0) * (item.unitQuantity || 0);
400
+ return sum + (this.currencyCalculator ? this.currencyCalculator.round(lineNet) : lineNet);
401
+ }, 0);
402
+ return this.currencyCalculator ? this.currencyCalculator.round(total) : total;
403
+ }
404
+ calculateVATAmount(taxableAmount, rate) {
405
+ const vat = taxableAmount * (rate / 100);
406
+ return this.currencyCalculator ? this.currencyCalculator.round(vat) : vat;
407
+ }
408
+ areAmountsEqual(value1, value2) {
409
+ if (this.currencyCalculator) {
410
+ return this.currencyCalculator.areEqual(value1, value2);
411
+ }
412
+ return Math.abs(value1 - value2) < 0.01;
413
+ }
414
+ isEUCountry(countryCode) {
415
+ const euCountries = [
416
+ 'AT', 'BE', 'BG', 'HR', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR',
417
+ 'DE', 'GR', 'HU', 'IE', 'IT', 'LV', 'LT', 'LU', 'MT', 'NL',
418
+ 'PL', 'PT', 'RO', 'SK', 'SI', 'ES', 'SE'
419
+ ];
420
+ return euCountries.includes(countryCode);
421
+ }
422
+ isReverseChargeService(item) {
423
+ // Check if item qualifies for reverse charge
424
+ // This would typically check service codes
425
+ const metadata = item.metadata;
426
+ if (metadata?.serviceCode) {
427
+ // Construction services, telecommunication, etc.
428
+ const reverseChargeServices = ['44', '45', '61', '62'];
429
+ return reverseChargeServices.some(code => metadata.serviceCode.startsWith(code));
430
+ }
431
+ return false;
432
+ }
433
+ addError(ruleId, message, field, value, expected) {
434
+ this.results.push({
435
+ ruleId,
436
+ source: 'EN16931',
437
+ severity: 'error',
438
+ message,
439
+ field,
440
+ value,
441
+ expected,
442
+ btReference: this.getBTReference(ruleId),
443
+ bgReference: 'BG-23' // VAT breakdown
444
+ });
445
+ }
446
+ addWarning(ruleId, message, field, value, expected) {
447
+ this.results.push({
448
+ ruleId,
449
+ source: 'EN16931',
450
+ severity: 'warning',
451
+ message,
452
+ field,
453
+ value,
454
+ expected,
455
+ btReference: this.getBTReference(ruleId),
456
+ bgReference: 'BG-23'
457
+ });
458
+ }
459
+ getBTReference(ruleId) {
460
+ const btMap = {
461
+ 'BR-S-': 'BT-118', // VAT category rate
462
+ 'BR-Z-': 'BT-118',
463
+ 'BR-E-': 'BT-120', // VAT exemption reason
464
+ 'BR-AE-': 'BT-120',
465
+ 'BR-K-': 'BT-120',
466
+ 'BR-G-': 'BT-120',
467
+ 'BR-O-': 'BT-120',
468
+ 'BR-CO-17': 'BT-117', // VAT category tax amount
469
+ 'BR-CO-18': 'BT-118',
470
+ 'BR-CO-19': 'BT-116' // VAT category taxable amount
471
+ };
472
+ for (const [prefix, bt] of Object.entries(btMap)) {
473
+ if (ruleId.startsWith(prefix)) {
474
+ return bt;
475
+ }
476
+ }
477
+ return undefined;
478
+ }
479
+ }
480
+ /**
481
+ * Get VAT category name
482
+ */
483
+ export function getVATCategoryName(category) {
484
+ const names = {
485
+ [VATCategory.S]: 'Standard rate',
486
+ [VATCategory.Z]: 'Zero rated',
487
+ [VATCategory.E]: 'Exempt from tax',
488
+ [VATCategory.AE]: 'VAT Reverse Charge',
489
+ [VATCategory.K]: 'VAT exempt for EEA intra-community supply',
490
+ [VATCategory.G]: 'Free export outside EU',
491
+ [VATCategory.O]: 'Services outside scope of tax',
492
+ [VATCategory.L]: 'Canary Islands general indirect tax',
493
+ [VATCategory.M]: 'Tax for production, services and importation in Ceuta and Melilla'
494
+ };
495
+ return names[category] || 'Unknown';
496
+ }
497
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmF0LWNhdGVnb3JpZXMudmFsaWRhdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvZm9ybWF0cy92YWxpZGF0aW9uL3ZhdC1jYXRlZ29yaWVzLnZhbGlkYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBRzVDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBR2hFOztHQUVHO0FBQ0gsTUFBTSxDQUFOLElBQVksV0FVWDtBQVZELFdBQVksV0FBVztJQUNyQixzQkFBTyxDQUFBO0lBQ1Asc0JBQU8sQ0FBQTtJQUNQLHNCQUFPLENBQUE7SUFDUCx3QkFBUyxDQUFBO0lBQ1Qsc0JBQU8sQ0FBQTtJQUNQLHNCQUFPLENBQUE7SUFDUCxzQkFBTyxDQUFBO0lBQ1Asc0JBQU8sQ0FBQTtJQUNQLHNCQUFPLENBQUEsQ0FBSSxvRUFBb0U7QUFDakYsQ0FBQyxFQVZXLFdBQVcsS0FBWCxXQUFXLFFBVXRCO0FBY0Q7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLHNCQUFzQjtJQUFuQztRQUNVLFlBQU8sR0FBdUIsRUFBRSxDQUFDO0lBbXhCM0MsQ0FBQztJQWh4QkM7O09BRUc7SUFDSSxRQUFRLENBQUMsT0FBaUI7UUFDL0IsSUFBSSxDQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFFbEIsMERBQTBEO1FBQzFELElBQUksT0FBTyxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ3JCLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFJLGtCQUFrQixDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNyRSxDQUFDO1FBRUQsOEJBQThCO1FBQzlCLE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxPQUFPLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQzFFLE1BQU0sb0JBQW9CLEdBQUcsSUFBSSxDQUFDLHlCQUF5QixD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
@@ -0,0 +1,92 @@
1
+ /**
2
+ * XRechnung CIUS Validator
3
+ * Implements German-specific validation rules for XRechnung 3.0
4
+ *
5
+ * XRechnung is the German Core Invoice Usage Specification (CIUS) of EN16931
6
+ * Required for B2G invoicing in Germany since November 2020
7
+ */
8
+ import type { EInvoice } from '../../einvoice.js';
9
+ import type { ValidationResult } from './validation.types.js';
10
+ /**
11
+ * XRechnung-specific validator implementing German CIUS rules
12
+ */
13
+ export declare class XRechnungValidator {
14
+ private static readonly LEITWEG_ID_PATTERN;
15
+ private static readonly IBAN_PATTERNS;
16
+ private static readonly BIC_PATTERN;
17
+ private static readonly SEPA_COUNTRIES;
18
+ /**
19
+ * Validate XRechnung-specific requirements
20
+ */
21
+ validateXRechnung(invoice: EInvoice): ValidationResult[];
22
+ /**
23
+ * Check if invoice is XRechnung based on profile/customization ID
24
+ */
25
+ private isXRechnungInvoice;
26
+ /**
27
+ * Validate Leitweg-ID (routing ID for German public administration)
28
+ * Pattern: [0-9]{2,3}-[0-9]{1,12}-[0-9]{2,30}
29
+ * Rule: XR-DE-01
30
+ */
31
+ private validateLeitwegId;
32
+ /**
33
+ * Check if string looks like a Leitweg-ID
34
+ */
35
+ private looksLikeLeitwegId;
36
+ /**
37
+ * Check if this is a B2G invoice
38
+ */
39
+ private isB2GInvoice;
40
+ /**
41
+ * Validate mandatory buyer reference (BT-10)
42
+ * Rule: XR-DE-15
43
+ */
44
+ private validateBuyerReference;
45
+ /**
46
+ * Validate payment details (IBAN/BIC for SEPA)
47
+ * Rules: XR-DE-19, XR-DE-20
48
+ */
49
+ private validatePaymentDetails;
50
+ /**
51
+ * Validate IBAN format and checksum
52
+ */
53
+ private validateIBAN;
54
+ /**
55
+ * Validate BIC format
56
+ */
57
+ private validateBIC;
58
+ /**
59
+ * Validate seller contact details
60
+ * Rule: XR-DE-02
61
+ */
62
+ private validateSellerContact;
63
+ /**
64
+ * Validate email format
65
+ */
66
+ private isValidEmail;
67
+ /**
68
+ * Validate phone format (basic)
69
+ */
70
+ private isValidPhone;
71
+ /**
72
+ * Validate tax registration details
73
+ * Rules: XR-DE-03, XR-DE-04
74
+ */
75
+ private validateTaxRegistration;
76
+ /**
77
+ * Validate German VAT ID format
78
+ */
79
+ private isValidGermanVatId;
80
+ /**
81
+ * Check if value looks like a German Tax ID
82
+ */
83
+ private looksLikeGermanTaxId;
84
+ /**
85
+ * Validate German Tax ID format
86
+ */
87
+ private isValidGermanTaxId;
88
+ /**
89
+ * Create XRechnung profile validator instance
90
+ */
91
+ static create(): XRechnungValidator;
92
+ }