@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,317 @@
1
+ import type { ValidationResult } from './validation.types.js';
2
+ import { CodeLists } from './validation.types.js';
3
+ import type { TAccountingDocItem } from '@tsclass/tsclass/dist_ts/finance/index.js';
4
+ import type { EInvoice } from '../../einvoice.js';
5
+ import type { IExtendedAccountingDocItem } from '../../interfaces/en16931-metadata.js';
6
+
7
+ /**
8
+ * Code List Validator for EN16931 compliance
9
+ * Validates against standard code lists (ISO, UNCL, UNECE)
10
+ */
11
+ export class CodeListValidator {
12
+ private results: ValidationResult[] = [];
13
+
14
+ /**
15
+ * Validate all code lists in an invoice
16
+ */
17
+ public validate(invoice: EInvoice): ValidationResult[] {
18
+ this.results = [];
19
+
20
+ // Currency validation
21
+ this.validateCurrency(invoice);
22
+
23
+ // Country codes
24
+ this.validateCountryCodes(invoice);
25
+
26
+ // Document type
27
+ this.validateDocumentType(invoice);
28
+
29
+ // Tax categories
30
+ this.validateTaxCategories(invoice);
31
+
32
+ // Payment means
33
+ this.validatePaymentMeans(invoice);
34
+
35
+ // Unit codes
36
+ this.validateUnitCodes(invoice);
37
+
38
+ return this.results;
39
+ }
40
+
41
+ /**
42
+ * Validate currency codes (ISO 4217)
43
+ */
44
+ private validateCurrency(invoice: EInvoice): void {
45
+ // Document currency (BT-5)
46
+ if (invoice.currency) {
47
+ if (!CodeLists.ISO4217.codes.has(invoice.currency.toUpperCase())) {
48
+ this.addError(
49
+ 'BR-CL-03',
50
+ `Invalid currency code: ${invoice.currency}. Must be ISO 4217`,
51
+ 'EN16931',
52
+ 'currency',
53
+ 'BT-5',
54
+ invoice.currency,
55
+ Array.from(CodeLists.ISO4217.codes).join(', ')
56
+ );
57
+ }
58
+ }
59
+
60
+ // VAT accounting currency (BT-6)
61
+ const vatCurrency = invoice.metadata?.vatAccountingCurrency;
62
+ if (vatCurrency && !CodeLists.ISO4217.codes.has(vatCurrency.toUpperCase())) {
63
+ this.addError(
64
+ 'BR-CL-04',
65
+ `Invalid VAT accounting currency: ${vatCurrency}. Must be ISO 4217`,
66
+ 'EN16931',
67
+ 'metadata.vatAccountingCurrency',
68
+ 'BT-6',
69
+ vatCurrency,
70
+ Array.from(CodeLists.ISO4217.codes).join(', ')
71
+ );
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Validate country codes (ISO 3166-1 alpha-2)
77
+ */
78
+ private validateCountryCodes(invoice: EInvoice): void {
79
+ // Seller country (BT-40)
80
+ const sellerCountry = invoice.from?.address?.countryCode;
81
+ if (sellerCountry && !CodeLists.ISO3166.codes.has(sellerCountry.toUpperCase())) {
82
+ this.addError(
83
+ 'BR-CL-14',
84
+ `Invalid seller country code: ${sellerCountry}. Must be ISO 3166-1 alpha-2`,
85
+ 'EN16931',
86
+ 'from.address.countryCode',
87
+ 'BT-40',
88
+ sellerCountry,
89
+ 'Two-letter country code (e.g., DE, FR, IT)'
90
+ );
91
+ }
92
+
93
+ // Buyer country (BT-55)
94
+ const buyerCountry = invoice.to?.address?.countryCode;
95
+ if (buyerCountry && !CodeLists.ISO3166.codes.has(buyerCountry.toUpperCase())) {
96
+ this.addError(
97
+ 'BR-CL-15',
98
+ `Invalid buyer country code: ${buyerCountry}. Must be ISO 3166-1 alpha-2`,
99
+ 'EN16931',
100
+ 'to.address.countryCode',
101
+ 'BT-55',
102
+ buyerCountry,
103
+ 'Two-letter country code (e.g., DE, FR, IT)'
104
+ );
105
+ }
106
+
107
+ // Delivery country (BT-80)
108
+ const deliveryCountry = invoice.metadata?.deliveryAddress?.countryCode;
109
+ if (deliveryCountry && !CodeLists.ISO3166.codes.has(deliveryCountry.toUpperCase())) {
110
+ this.addError(
111
+ 'BR-CL-16',
112
+ `Invalid delivery country code: ${deliveryCountry}. Must be ISO 3166-1 alpha-2`,
113
+ 'EN16931',
114
+ 'metadata.deliveryAddress.countryCode',
115
+ 'BT-80',
116
+ deliveryCountry,
117
+ 'Two-letter country code (e.g., DE, FR, IT)'
118
+ );
119
+ }
120
+ }
121
+
122
+ /**
123
+ * Validate document type code (UNCL1001)
124
+ */
125
+ private validateDocumentType(invoice: EInvoice): void {
126
+ const typeCode = invoice.metadata?.documentTypeCode ||
127
+ (invoice.accountingDocType === 'invoice' ? '380' :
128
+ invoice.accountingDocType === 'creditnote' ? '381' :
129
+ invoice.accountingDocType === 'debitnote' ? '383' : null);
130
+
131
+ if (typeCode && !CodeLists.UNCL1001.codes.has(typeCode)) {
132
+ this.addError(
133
+ 'BR-CL-01',
134
+ `Invalid document type code: ${typeCode}. Must be UNCL1001`,
135
+ 'EN16931',
136
+ 'metadata.documentTypeCode',
137
+ 'BT-3',
138
+ typeCode,
139
+ Array.from(CodeLists.UNCL1001.codes.entries()).map(([k, v]) => `${k} (${v})`).join(', ')
140
+ );
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Validate tax category codes (UNCL5305)
146
+ */
147
+ private validateTaxCategories(invoice: EInvoice): void {
148
+ // Document level tax breakdown
149
+ // Note: taxBreakdown is a computed property that doesn't have metadata
150
+ // We would need to access the raw tax breakdown data from metadata if it exists
151
+ invoice.taxBreakdown?.forEach((breakdown, index) => {
152
+ // Since the computed taxBreakdown doesn't have metadata,
153
+ // we'll skip the tax category code validation for now
154
+ // This would need to be implemented differently to access the raw data
155
+
156
+ // TODO: Access raw tax breakdown data with metadata from invoice.metadata.taxBreakdown
157
+ // when that structure is implemented
158
+ });
159
+
160
+ // Line level tax categories
161
+ invoice.items?.forEach((item, index) => {
162
+ // Cast to extended type to access metadata
163
+ const extendedItem = item as IExtendedAccountingDocItem;
164
+ const categoryCode = extendedItem.metadata?.vatCategoryCode;
165
+ if (categoryCode && !CodeLists.UNCL5305.codes.has(categoryCode)) {
166
+ this.addError(
167
+ 'BR-CL-10',
168
+ `Invalid line tax category: ${categoryCode}. Must be UNCL5305`,
169
+ 'EN16931',
170
+ `items[${index}].metadata.vatCategoryCode`,
171
+ 'BT-151',
172
+ categoryCode,
173
+ Array.from(CodeLists.UNCL5305.codes.entries()).map(([k, v]) => `${k} (${v})`).join(', ')
174
+ );
175
+ }
176
+ });
177
+ }
178
+
179
+ /**
180
+ * Validate payment means codes (UNCL4461)
181
+ */
182
+ private validatePaymentMeans(invoice: EInvoice): void {
183
+ const paymentMeans = invoice.metadata?.paymentMeansCode;
184
+ if (paymentMeans && !CodeLists.UNCL4461.codes.has(paymentMeans)) {
185
+ this.addError(
186
+ 'BR-CL-16',
187
+ `Invalid payment means code: ${paymentMeans}. Must be UNCL4461`,
188
+ 'EN16931',
189
+ 'metadata.paymentMeansCode',
190
+ 'BT-81',
191
+ paymentMeans,
192
+ Array.from(CodeLists.UNCL4461.codes.entries()).map(([k, v]) => `${k} (${v})`).join(', ')
193
+ );
194
+ }
195
+
196
+ // Validate payment requirements based on means code
197
+ if (paymentMeans === '30' || paymentMeans === '58') { // Credit transfer
198
+ if (!invoice.metadata?.paymentAccount?.iban) {
199
+ this.addWarning(
200
+ 'BR-CL-16-1',
201
+ `Payment means ${paymentMeans} (${CodeLists.UNCL4461.codes.get(paymentMeans)}) typically requires IBAN`,
202
+ 'EN16931',
203
+ 'metadata.paymentAccount.iban',
204
+ 'BT-84'
205
+ );
206
+ }
207
+ }
208
+ }
209
+
210
+ /**
211
+ * Validate unit codes (UNECE Rec 20)
212
+ */
213
+ private validateUnitCodes(invoice: EInvoice): void {
214
+ invoice.items?.forEach((item, index) => {
215
+ const unitCode = item.unitType;
216
+ if (unitCode && !CodeLists.UNECERec20.codes.has(unitCode)) {
217
+ this.addError(
218
+ 'BR-CL-23',
219
+ `Invalid unit code: ${unitCode}. Must be UNECE Rec 20`,
220
+ 'EN16931',
221
+ `items[${index}].unitCode`,
222
+ 'BT-130',
223
+ unitCode,
224
+ 'Common codes: C62 (one), KGM (kilogram), HUR (hour), DAY (day), MTR (metre)'
225
+ );
226
+ }
227
+
228
+ // Validate quantity is positive for standard units
229
+ if (unitCode && item.unitQuantity <= 0 && unitCode !== 'LS') { // LS = Lump sum can be 1
230
+ this.addError(
231
+ 'BR-25',
232
+ `Quantity must be positive for unit ${unitCode}`,
233
+ 'EN16931',
234
+ `items[${index}].quantity`,
235
+ 'BT-129',
236
+ item.unitQuantity,
237
+ '> 0'
238
+ );
239
+ }
240
+ });
241
+ }
242
+
243
+ /**
244
+ * Add validation error
245
+ */
246
+ private addError(
247
+ ruleId: string,
248
+ message: string,
249
+ source: string,
250
+ field: string,
251
+ btReference?: string,
252
+ value?: any,
253
+ expected?: any
254
+ ): void {
255
+ this.results.push({
256
+ ruleId,
257
+ source,
258
+ severity: 'error',
259
+ message,
260
+ field,
261
+ btReference,
262
+ value,
263
+ expected,
264
+ codeList: this.getCodeListForRule(ruleId)
265
+ });
266
+ }
267
+
268
+ /**
269
+ * Add validation warning
270
+ */
271
+ private addWarning(
272
+ ruleId: string,
273
+ message: string,
274
+ source: string,
275
+ field: string,
276
+ btReference?: string,
277
+ value?: any,
278
+ expected?: any
279
+ ): void {
280
+ this.results.push({
281
+ ruleId,
282
+ source,
283
+ severity: 'warning',
284
+ message,
285
+ field,
286
+ btReference,
287
+ value,
288
+ expected,
289
+ codeList: this.getCodeListForRule(ruleId)
290
+ });
291
+ }
292
+
293
+ /**
294
+ * Get code list metadata for a rule
295
+ */
296
+ private getCodeListForRule(ruleId: string): { name: string; version: string } | undefined {
297
+ if (ruleId.includes('CL-03') || ruleId.includes('CL-04')) {
298
+ return { name: 'ISO4217', version: CodeLists.ISO4217.version };
299
+ }
300
+ if (ruleId.includes('CL-14') || ruleId.includes('CL-15') || ruleId.includes('CL-16')) {
301
+ return { name: 'ISO3166', version: CodeLists.ISO3166.version };
302
+ }
303
+ if (ruleId.includes('CL-01')) {
304
+ return { name: 'UNCL1001', version: CodeLists.UNCL1001.version };
305
+ }
306
+ if (ruleId.includes('CL-10')) {
307
+ return { name: 'UNCL5305', version: CodeLists.UNCL5305.version };
308
+ }
309
+ if (ruleId.includes('CL-16')) {
310
+ return { name: 'UNCL4461', version: CodeLists.UNCL4461.version };
311
+ }
312
+ if (ruleId.includes('CL-23')) {
313
+ return { name: 'UNECERec20', version: CodeLists.UNECERec20.version };
314
+ }
315
+ return undefined;
316
+ }
317
+ }