@fin.cx/einvoice 5.0.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 (171) hide show
  1. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  2. package/dist_ts/00_commitinfo_data.js +9 -0
  3. package/dist_ts/classes.decoder.d.ts +40 -0
  4. package/dist_ts/classes.decoder.js +320 -0
  5. package/dist_ts/classes.encoder.d.ts +51 -0
  6. package/dist_ts/classes.encoder.js +293 -0
  7. package/dist_ts/classes.xinvoice.d.ts +136 -0
  8. package/dist_ts/classes.xinvoice.js +352 -0
  9. package/dist_ts/einvoice.d.ts +217 -0
  10. package/dist_ts/einvoice.js +505 -0
  11. package/dist_ts/errors.d.ts +121 -0
  12. package/dist_ts/errors.js +241 -0
  13. package/dist_ts/formats/base/base.decoder.d.ts +32 -0
  14. package/dist_ts/formats/base/base.decoder.js +52 -0
  15. package/dist_ts/formats/base/base.encoder.d.ts +13 -0
  16. package/dist_ts/formats/base/base.encoder.js +7 -0
  17. package/dist_ts/formats/base/base.validator.d.ts +44 -0
  18. package/dist_ts/formats/base/base.validator.js +39 -0
  19. package/dist_ts/formats/base.decoder.d.ts +19 -0
  20. package/dist_ts/formats/base.decoder.js +130 -0
  21. package/dist_ts/formats/base.validator.d.ts +44 -0
  22. package/dist_ts/formats/base.validator.js +39 -0
  23. package/dist_ts/formats/cii/cii.decoder.d.ts +61 -0
  24. package/dist_ts/formats/cii/cii.decoder.js +111 -0
  25. package/dist_ts/formats/cii/cii.encoder.d.ts +43 -0
  26. package/dist_ts/formats/cii/cii.encoder.js +48 -0
  27. package/dist_ts/formats/cii/cii.types.d.ts +31 -0
  28. package/dist_ts/formats/cii/cii.types.js +40 -0
  29. package/dist_ts/formats/cii/cii.validator.d.ts +56 -0
  30. package/dist_ts/formats/cii/cii.validator.js +146 -0
  31. package/dist_ts/formats/cii/facturx/facturx.decoder.d.ts +43 -0
  32. package/dist_ts/formats/cii/facturx/facturx.decoder.js +207 -0
  33. package/dist_ts/formats/cii/facturx/facturx.encoder.d.ts +82 -0
  34. package/dist_ts/formats/cii/facturx/facturx.encoder.js +400 -0
  35. package/dist_ts/formats/cii/facturx/facturx.types.d.ts +10 -0
  36. package/dist_ts/formats/cii/facturx/facturx.types.js +15 -0
  37. package/dist_ts/formats/cii/facturx/facturx.validator.d.ts +32 -0
  38. package/dist_ts/formats/cii/facturx/facturx.validator.js +138 -0
  39. package/dist_ts/formats/cii/zugferd/zugferd.decoder.d.ts +43 -0
  40. package/dist_ts/formats/cii/zugferd/zugferd.decoder.js +218 -0
  41. package/dist_ts/formats/cii/zugferd/zugferd.encoder.d.ts +97 -0
  42. package/dist_ts/formats/cii/zugferd/zugferd.encoder.js +550 -0
  43. package/dist_ts/formats/cii/zugferd/zugferd.types.d.ts +10 -0
  44. package/dist_ts/formats/cii/zugferd/zugferd.types.js +15 -0
  45. package/dist_ts/formats/cii/zugferd/zugferd.v1.decoder.d.ts +49 -0
  46. package/dist_ts/formats/cii/zugferd/zugferd.v1.decoder.js +229 -0
  47. package/dist_ts/formats/cii/zugferd/zugferd.validator.d.ts +16 -0
  48. package/dist_ts/formats/cii/zugferd/zugferd.validator.js +29 -0
  49. package/dist_ts/formats/decoder.factory.d.ts +15 -0
  50. package/dist_ts/formats/decoder.factory.js +46 -0
  51. package/dist_ts/formats/factories/decoder.factory.d.ts +13 -0
  52. package/dist_ts/formats/factories/decoder.factory.js +56 -0
  53. package/dist_ts/formats/factories/encoder.factory.d.ts +14 -0
  54. package/dist_ts/formats/factories/encoder.factory.js +40 -0
  55. package/dist_ts/formats/factories/validator.factory.d.ts +12 -0
  56. package/dist_ts/formats/factories/validator.factory.js +110 -0
  57. package/dist_ts/formats/factorx.decoder.d.ts +18 -0
  58. package/dist_ts/formats/factorx.decoder.js +178 -0
  59. package/dist_ts/formats/factorx.encoder.d.ts +51 -0
  60. package/dist_ts/formats/factorx.encoder.js +293 -0
  61. package/dist_ts/formats/facturx.decoder.d.ts +18 -0
  62. package/dist_ts/formats/facturx.decoder.js +210 -0
  63. package/dist_ts/formats/facturx.encoder.d.ts +51 -0
  64. package/dist_ts/formats/facturx.encoder.js +293 -0
  65. package/dist_ts/formats/facturx.validator.d.ts +67 -0
  66. package/dist_ts/formats/facturx.validator.js +266 -0
  67. package/dist_ts/formats/pdf/extractors/associated.extractor.d.ts +14 -0
  68. package/dist_ts/formats/pdf/extractors/associated.extractor.js +68 -0
  69. package/dist_ts/formats/pdf/extractors/base.extractor.d.ts +92 -0
  70. package/dist_ts/formats/pdf/extractors/base.extractor.js +319 -0
  71. package/dist_ts/formats/pdf/extractors/index.d.ts +4 -0
  72. package/dist_ts/formats/pdf/extractors/index.js +5 -0
  73. package/dist_ts/formats/pdf/extractors/standard.extractor.d.ts +13 -0
  74. package/dist_ts/formats/pdf/extractors/standard.extractor.js +74 -0
  75. package/dist_ts/formats/pdf/extractors/text.extractor.d.ts +45 -0
  76. package/dist_ts/formats/pdf/extractors/text.extractor.js +151 -0
  77. package/dist_ts/formats/pdf/pdf.embedder.d.ts +69 -0
  78. package/dist_ts/formats/pdf/pdf.embedder.js +183 -0
  79. package/dist_ts/formats/pdf/pdf.extractor.d.ts +49 -0
  80. package/dist_ts/formats/pdf/pdf.extractor.js +98 -0
  81. package/dist_ts/formats/pdf/robust-pdf.extractor.d.ts +40 -0
  82. package/dist_ts/formats/pdf/robust-pdf.extractor.js +324 -0
  83. package/dist_ts/formats/ubl/en16931.ubl.validator.d.ts +18 -0
  84. package/dist_ts/formats/ubl/en16931.ubl.validator.js +169 -0
  85. package/dist_ts/formats/ubl/generic/ubl.encoder.d.ts +151 -0
  86. package/dist_ts/formats/ubl/generic/ubl.encoder.js +892 -0
  87. package/dist_ts/formats/ubl/ubl.decoder.d.ts +61 -0
  88. package/dist_ts/formats/ubl/ubl.decoder.js +95 -0
  89. package/dist_ts/formats/ubl/ubl.encoder.d.ts +38 -0
  90. package/dist_ts/formats/ubl/ubl.encoder.js +46 -0
  91. package/dist_ts/formats/ubl/ubl.types.d.ts +16 -0
  92. package/dist_ts/formats/ubl/ubl.types.js +21 -0
  93. package/dist_ts/formats/ubl/ubl.validator.d.ts +50 -0
  94. package/dist_ts/formats/ubl/ubl.validator.js +112 -0
  95. package/dist_ts/formats/ubl/xrechnung/xrechnung.decoder.d.ts +34 -0
  96. package/dist_ts/formats/ubl/xrechnung/xrechnung.decoder.js +424 -0
  97. package/dist_ts/formats/ubl/xrechnung/xrechnung.encoder.d.ts +75 -0
  98. package/dist_ts/formats/ubl/xrechnung/xrechnung.encoder.js +555 -0
  99. package/dist_ts/formats/ubl/xrechnung.validator.d.ts +15 -0
  100. package/dist_ts/formats/ubl/xrechnung.validator.js +107 -0
  101. package/dist_ts/formats/ubl.validator.d.ts +82 -0
  102. package/dist_ts/formats/ubl.validator.js +306 -0
  103. package/dist_ts/formats/utils/format.detector.d.ts +62 -0
  104. package/dist_ts/formats/utils/format.detector.js +249 -0
  105. package/dist_ts/formats/validation/en16931.validator.d.ts +23 -0
  106. package/dist_ts/formats/validation/en16931.validator.js +119 -0
  107. package/dist_ts/formats/validator.factory.d.ts +18 -0
  108. package/dist_ts/formats/validator.factory.js +78 -0
  109. package/dist_ts/formats/xinvoice.decoder.d.ts +28 -0
  110. package/dist_ts/formats/xinvoice.decoder.js +332 -0
  111. package/dist_ts/formats/xinvoice.encoder.d.ts +19 -0
  112. package/dist_ts/formats/xinvoice.encoder.js +282 -0
  113. package/dist_ts/index.d.ts +51 -0
  114. package/dist_ts/index.js +90 -0
  115. package/dist_ts/interfaces/common.d.ts +79 -0
  116. package/dist_ts/interfaces/common.js +24 -0
  117. package/dist_ts/interfaces.d.ts +87 -0
  118. package/dist_ts/interfaces.js +23 -0
  119. package/dist_ts/plugins.d.ts +14 -0
  120. package/dist_ts/plugins.js +31 -0
  121. package/npmextra.json +35 -0
  122. package/package.json +71 -0
  123. package/readme.hints.md +1107 -0
  124. package/readme.howtofixtests.md +38 -0
  125. package/readme.literature.md +1 -0
  126. package/readme.md +998 -0
  127. package/readme.plan.md +481 -0
  128. package/ts/00_commitinfo_data.ts +8 -0
  129. package/ts/einvoice.ts +603 -0
  130. package/ts/errors.ts +341 -0
  131. package/ts/formats/base/base.decoder.ts +68 -0
  132. package/ts/formats/base/base.encoder.ts +14 -0
  133. package/ts/formats/base/base.validator.ts +64 -0
  134. package/ts/formats/cii/cii.decoder.ts +139 -0
  135. package/ts/formats/cii/cii.encoder.ts +64 -0
  136. package/ts/formats/cii/cii.types.ts +44 -0
  137. package/ts/formats/cii/cii.validator.ts +171 -0
  138. package/ts/formats/cii/facturx/facturx.decoder.ts +243 -0
  139. package/ts/formats/cii/facturx/facturx.encoder.ts +483 -0
  140. package/ts/formats/cii/facturx/facturx.types.ts +18 -0
  141. package/ts/formats/cii/facturx/facturx.validator.ts +180 -0
  142. package/ts/formats/cii/zugferd/zugferd.decoder.ts +256 -0
  143. package/ts/formats/cii/zugferd/zugferd.encoder.ts +661 -0
  144. package/ts/formats/cii/zugferd/zugferd.types.ts +18 -0
  145. package/ts/formats/cii/zugferd/zugferd.v1.decoder.ts +267 -0
  146. package/ts/formats/cii/zugferd/zugferd.validator.ts +31 -0
  147. package/ts/formats/factories/decoder.factory.ts +62 -0
  148. package/ts/formats/factories/encoder.factory.ts +47 -0
  149. package/ts/formats/factories/validator.factory.ts +134 -0
  150. package/ts/formats/pdf/extractors/associated.extractor.ts +78 -0
  151. package/ts/formats/pdf/extractors/base.extractor.ts +355 -0
  152. package/ts/formats/pdf/extractors/index.ts +4 -0
  153. package/ts/formats/pdf/extractors/standard.extractor.ts +86 -0
  154. package/ts/formats/pdf/extractors/text.extractor.ts +162 -0
  155. package/ts/formats/pdf/pdf.embedder.ts +242 -0
  156. package/ts/formats/pdf/pdf.extractor.ts +141 -0
  157. package/ts/formats/ubl/en16931.ubl.validator.ts +216 -0
  158. package/ts/formats/ubl/generic/ubl.encoder.ts +1041 -0
  159. package/ts/formats/ubl/ubl.decoder.ts +121 -0
  160. package/ts/formats/ubl/ubl.encoder.ts +63 -0
  161. package/ts/formats/ubl/ubl.types.ts +22 -0
  162. package/ts/formats/ubl/ubl.validator.ts +133 -0
  163. package/ts/formats/ubl/xrechnung/xrechnung.decoder.ts +471 -0
  164. package/ts/formats/ubl/xrechnung/xrechnung.encoder.ts +619 -0
  165. package/ts/formats/ubl/xrechnung.validator.ts +185 -0
  166. package/ts/formats/utils/format.detector.ts +306 -0
  167. package/ts/formats/validation/en16931.validator.ts +135 -0
  168. package/ts/index.ts +164 -0
  169. package/ts/interfaces/common.ts +90 -0
  170. package/ts/interfaces.ts +98 -0
  171. package/ts/plugins.ts +61 -0
@@ -0,0 +1,121 @@
1
+ import { BaseDecoder } from '../base/base.decoder.js';
2
+ import type { TInvoice, TCreditNote, TDebitNote } from '../../interfaces/common.js';
3
+ import { UBLDocumentType, UBL_NAMESPACES } from './ubl.types.js';
4
+ import { DOMParser, xpath } from '../../plugins.js';
5
+
6
+ /**
7
+ * Base decoder for UBL-based invoice formats
8
+ */
9
+ export abstract class UBLBaseDecoder extends BaseDecoder {
10
+ protected doc: Document;
11
+ protected namespaces: Record<string, string>;
12
+ protected select: xpath.XPathSelect;
13
+
14
+ constructor(xml: string, skipValidation: boolean = false) {
15
+ super(xml, skipValidation);
16
+
17
+ // Parse XML document
18
+ this.doc = new DOMParser().parseFromString(xml, 'application/xml');
19
+
20
+ // Set up namespaces for XPath queries
21
+ this.namespaces = {
22
+ cbc: UBL_NAMESPACES.CBC,
23
+ cac: UBL_NAMESPACES.CAC
24
+ };
25
+
26
+ // Create XPath selector with namespaces
27
+ this.select = xpath.useNamespaces(this.namespaces);
28
+ }
29
+
30
+ /**
31
+ * Decodes UBL XML into a TInvoice object
32
+ * @returns Promise resolving to a TInvoice object
33
+ */
34
+ public async decode(): Promise<TInvoice> {
35
+ // Determine document type
36
+ const documentType = this.getDocumentType();
37
+
38
+ if (documentType === UBLDocumentType.CREDIT_NOTE) {
39
+ return this.decodeCreditNote() as unknown as TInvoice;
40
+ } else {
41
+ return this.decodeDebitNote() as unknown as TInvoice;
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Gets the UBL document type
47
+ * @returns UBL document type
48
+ */
49
+ protected getDocumentType(): UBLDocumentType {
50
+ const rootName = this.doc.documentElement.nodeName;
51
+
52
+ if (rootName === UBLDocumentType.CREDIT_NOTE) {
53
+ return UBLDocumentType.CREDIT_NOTE;
54
+ } else {
55
+ return UBLDocumentType.INVOICE;
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Decodes a UBL credit note
61
+ * @returns Promise resolving to a TCreditNote object
62
+ */
63
+ protected abstract decodeCreditNote(): Promise<TCreditNote>;
64
+
65
+ /**
66
+ * Decodes a UBL debit note (invoice)
67
+ * @returns Promise resolving to a TDebitNote object
68
+ */
69
+ protected abstract decodeDebitNote(): Promise<TDebitNote>;
70
+
71
+ /**
72
+ * Gets a text value from an XPath expression
73
+ * @param xpath XPath expression
74
+ * @param context Optional context node
75
+ * @returns Text value or empty string if not found
76
+ */
77
+ protected getText(xpathExpr: string, context?: Node): string {
78
+ const node = this.select(xpathExpr, context || this.doc)[0];
79
+ return node ? (node.textContent || '') : '';
80
+ }
81
+
82
+ /**
83
+ * Gets a number value from an XPath expression
84
+ * @param xpath XPath expression
85
+ * @param context Optional context node
86
+ * @returns Number value or 0 if not found or not a number
87
+ */
88
+ protected getNumber(xpathExpr: string, context?: Node): number {
89
+ const text = this.getText(xpathExpr, context);
90
+ const num = parseFloat(text);
91
+ return isNaN(num) ? 0 : num;
92
+ }
93
+
94
+ /**
95
+ * Gets a date value from an XPath expression
96
+ * @param xpath XPath expression
97
+ * @param context Optional context node
98
+ * @returns Date timestamp or current time if not found or invalid
99
+ */
100
+ protected getDate(xpathExpr: string, context?: Node): number {
101
+ const text = this.getText(xpathExpr, context);
102
+ if (!text) return Date.now();
103
+
104
+ const date = new Date(text);
105
+ return isNaN(date.getTime()) ? Date.now() : date.getTime();
106
+ }
107
+
108
+ /**
109
+ * Checks if a node exists
110
+ * @param xpath XPath expression
111
+ * @param context Optional context node
112
+ * @returns True if node exists
113
+ */
114
+ protected exists(xpathExpr: string, context?: Node): boolean {
115
+ const nodes = this.select(xpathExpr, context || this.doc);
116
+ if (Array.isArray(nodes)) {
117
+ return nodes.length > 0;
118
+ }
119
+ return false;
120
+ }
121
+ }
@@ -0,0 +1,63 @@
1
+ import { BaseEncoder } from '../base/base.encoder.js';
2
+ import type { TInvoice, TCreditNote, TDebitNote } from '../../interfaces/common.js';
3
+ import { UBLDocumentType, UBL_NAMESPACES } from './ubl.types.js';
4
+
5
+ /**
6
+ * Base encoder for UBL-based invoice formats
7
+ */
8
+ export abstract class UBLBaseEncoder extends BaseEncoder {
9
+ /**
10
+ * Encodes a TInvoice object into UBL XML
11
+ * @param invoice TInvoice object to encode
12
+ * @returns UBL XML string
13
+ */
14
+ public async encode(invoice: TInvoice): Promise<string> {
15
+ // TInvoice is always an invoice, treat it as debit note for encoding
16
+ return this.encodeDebitNote(invoice as unknown as TDebitNote);
17
+ }
18
+
19
+ /**
20
+ * Encodes a TCreditNote object into UBL XML
21
+ * @param creditNote TCreditNote object to encode
22
+ * @returns UBL XML string
23
+ */
24
+ protected abstract encodeCreditNote(creditNote: TCreditNote): Promise<string>;
25
+
26
+ /**
27
+ * Encodes a TDebitNote object into UBL XML
28
+ * @param debitNote TDebitNote object to encode
29
+ * @returns UBL XML string
30
+ */
31
+ protected abstract encodeDebitNote(debitNote: TDebitNote): Promise<string>;
32
+
33
+ /**
34
+ * Creates the XML declaration and root element
35
+ * @param documentType UBL document type
36
+ * @returns XML string with declaration and root element
37
+ */
38
+ protected createXmlRoot(documentType: UBLDocumentType): string {
39
+ return `<?xml version="1.0" encoding="UTF-8"?>
40
+ <${documentType} xmlns="urn:oasis:names:specification:ubl:schema:xsd:${documentType}-2"
41
+ xmlns:cac="${UBL_NAMESPACES.CAC}"
42
+ xmlns:cbc="${UBL_NAMESPACES.CBC}">
43
+ </${documentType}>`;
44
+ }
45
+
46
+ /**
47
+ * Formats a date as an ISO string (YYYY-MM-DD)
48
+ * @param timestamp Timestamp to format
49
+ * @returns Formatted date string
50
+ */
51
+ protected formatDate(timestamp: number): string {
52
+ // Ensure timestamp is valid
53
+ if (!timestamp || isNaN(timestamp)) {
54
+ timestamp = Date.now();
55
+ }
56
+ const date = new Date(timestamp);
57
+ // Check if date is valid
58
+ if (isNaN(date.getTime())) {
59
+ return new Date().toISOString().split('T')[0];
60
+ }
61
+ return date.toISOString().split('T')[0];
62
+ }
63
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * UBL-specific types and constants
3
+ */
4
+
5
+ // UBL namespaces
6
+ export const UBL_NAMESPACES = {
7
+ CBC: 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2',
8
+ CAC: 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2',
9
+ UBL: 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2'
10
+ };
11
+
12
+ // UBL document types
13
+ export enum UBLDocumentType {
14
+ INVOICE = 'Invoice',
15
+ CREDIT_NOTE = 'CreditNote'
16
+ }
17
+
18
+ // UBL customization IDs for different formats
19
+ export const UBL_CUSTOMIZATION_IDS = {
20
+ XRECHNUNG: 'urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.0',
21
+ PEPPOL_BIS: 'urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0'
22
+ };
@@ -0,0 +1,133 @@
1
+ import { BaseValidator } from '../base/base.validator.js';
2
+ import { ValidationLevel } from '../../interfaces/common.js';
3
+ import type { ValidationResult } from '../../interfaces/common.js';
4
+ import { UBLDocumentType } from './ubl.types.js';
5
+ import { DOMParser, xpath } from '../../plugins.js';
6
+
7
+ /**
8
+ * Base validator for UBL-based invoice formats
9
+ */
10
+ export abstract class UBLBaseValidator extends BaseValidator {
11
+ protected doc: Document;
12
+ protected namespaces: Record<string, string>;
13
+ protected select: xpath.XPathSelect;
14
+
15
+ constructor(xml: string) {
16
+ super(xml);
17
+
18
+ try {
19
+ // Parse XML document
20
+ this.doc = new DOMParser().parseFromString(xml, 'application/xml');
21
+
22
+ // Set up namespaces for XPath queries
23
+ this.namespaces = {
24
+ cbc: 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2',
25
+ cac: 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2'
26
+ };
27
+
28
+ // Create XPath selector with namespaces
29
+ this.select = xpath.useNamespaces(this.namespaces);
30
+ } catch (error) {
31
+ this.addError('UBL-PARSE', `Failed to parse XML: ${error}`, '/');
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Validates UBL XML against the specified level of validation
37
+ * @param level Validation level
38
+ * @returns Result of validation
39
+ */
40
+ public validate(level: ValidationLevel = ValidationLevel.SYNTAX): ValidationResult {
41
+ // Reset errors
42
+ this.errors = [];
43
+
44
+ // Check if document was parsed successfully
45
+ if (!this.doc) {
46
+ return {
47
+ valid: false,
48
+ errors: this.errors,
49
+ level: level
50
+ };
51
+ }
52
+
53
+ // Perform validation based on level
54
+ let valid = true;
55
+
56
+ if (level === ValidationLevel.SYNTAX) {
57
+ valid = this.validateSchema();
58
+ } else if (level === ValidationLevel.SEMANTIC) {
59
+ valid = this.validateSchema() && this.validateStructure();
60
+ } else if (level === ValidationLevel.BUSINESS) {
61
+ valid = this.validateSchema() &&
62
+ this.validateStructure() &&
63
+ this.validateBusinessRules();
64
+ }
65
+
66
+ return {
67
+ valid,
68
+ errors: this.errors,
69
+ level
70
+ };
71
+ }
72
+
73
+ /**
74
+ * Validates UBL XML against schema
75
+ * @returns True if schema validation passed
76
+ */
77
+ protected validateSchema(): boolean {
78
+ // Basic schema validation (simplified for now)
79
+ if (!this.doc) return false;
80
+
81
+ // Check for root element
82
+ const root = this.doc.documentElement;
83
+ if (!root || (root.nodeName !== UBLDocumentType.INVOICE && root.nodeName !== UBLDocumentType.CREDIT_NOTE)) {
84
+ this.addError('UBL-SCHEMA-1', `Root element must be ${UBLDocumentType.INVOICE} or ${UBLDocumentType.CREDIT_NOTE}`, '/');
85
+ return false;
86
+ }
87
+
88
+ return true;
89
+ }
90
+
91
+ /**
92
+ * Validates structure of the UBL XML document
93
+ * @returns True if structure validation passed
94
+ */
95
+ protected abstract validateStructure(): boolean;
96
+
97
+ /**
98
+ * Gets a text value from an XPath expression
99
+ * @param xpath XPath expression
100
+ * @param context Optional context node
101
+ * @returns Text value or empty string if not found
102
+ */
103
+ protected getText(xpathExpr: string, context?: Node): string {
104
+ const node = this.select(xpathExpr, context || this.doc)[0];
105
+ return node ? (node.textContent || '') : '';
106
+ }
107
+
108
+ /**
109
+ * Gets a number value from an XPath expression
110
+ * @param xpath XPath expression
111
+ * @param context Optional context node
112
+ * @returns Number value or 0 if not found or not a number
113
+ */
114
+ protected getNumber(xpathExpr: string, context?: Node): number {
115
+ const text = this.getText(xpathExpr, context);
116
+ const num = parseFloat(text);
117
+ return isNaN(num) ? 0 : num;
118
+ }
119
+
120
+ /**
121
+ * Checks if a node exists
122
+ * @param xpath XPath expression
123
+ * @param context Optional context node
124
+ * @returns True if node exists
125
+ */
126
+ protected exists(xpathExpr: string, context?: Node): boolean {
127
+ const nodes = this.select(xpathExpr, context || this.doc);
128
+ if (Array.isArray(nodes)) {
129
+ return nodes.length > 0;
130
+ }
131
+ return false;
132
+ }
133
+ }