@endevops/peppol-schema 0.1.2 → 0.1.4

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 (174) hide show
  1. package/README.md +5 -5
  2. package/dist/constants.d.ts +131 -0
  3. package/dist/constants.d.ts.map +1 -1
  4. package/dist/constants.js +114 -1
  5. package/dist/constants.js.map +1 -1
  6. package/dist/{index-BBzPjq7o.d.ts → index-CILtZytZ.d.ts} +1710 -669
  7. package/dist/index-CILtZytZ.d.ts.map +1 -0
  8. package/dist/index.d.ts +2 -2
  9. package/dist/index.js +1234 -187
  10. package/dist/index.js.map +1 -1
  11. package/dist/invoice-response-code-not-needs-schema-DNrfKYLh.js +36 -0
  12. package/dist/invoice-response-code-not-needs-schema-DNrfKYLh.js.map +1 -0
  13. package/dist/invoice-response-codes.d.ts +28 -0
  14. package/dist/invoice-response-codes.d.ts.map +1 -1
  15. package/dist/invoice-response-codes.js +11 -1
  16. package/dist/invoice-response-codes.js.map +1 -1
  17. package/dist/{is-valid-abn-160i38PG.js → is-valid-abn-D7eSygBG.js} +115 -2
  18. package/dist/is-valid-abn-D7eSygBG.js.map +1 -0
  19. package/dist/{is-valid-mod97-0208-CzMOXMO-.js → is-valid-mod97-0208-CjR324eG.js} +11 -1
  20. package/dist/is-valid-mod97-0208-CjR324eG.js.map +1 -0
  21. package/dist/message-level-response-profile-id-B9c0A7S_.js +27 -0
  22. package/dist/message-level-response-profile-id-B9c0A7S_.js.map +1 -0
  23. package/dist/{nodable-parser-CyDZtLCK.js → nodable-parser-CupS2H55.js} +31 -1
  24. package/dist/nodable-parser-CupS2H55.js.map +1 -0
  25. package/dist/schematron.d.ts +57 -1
  26. package/dist/schematron.d.ts.map +1 -1
  27. package/dist/schematron.js +453 -2
  28. package/dist/schematron.js.map +1 -1
  29. package/dist/validations.d.ts +132 -0
  30. package/dist/validations.d.ts.map +1 -1
  31. package/dist/validations.js +11 -2
  32. package/dist/validations.js.map +1 -1
  33. package/dist/values.d.ts +67 -2
  34. package/dist/values.d.ts.map +1 -1
  35. package/dist/xml.d.ts +30 -0
  36. package/dist/xml.d.ts.map +1 -1
  37. package/dist/xml.js +10 -1
  38. package/dist/xml.js.map +1 -1
  39. package/package.json +3 -2
  40. package/src/constants/credit-note-doctype-id.ts +9 -0
  41. package/src/constants/credit-note-process-id.ts +9 -0
  42. package/src/constants/document-scheme.ts +9 -0
  43. package/src/constants/invoice-doctype-id.ts +9 -0
  44. package/src/constants/invoice-process-id.ts +10 -0
  45. package/src/constants/invoice-response-doctype-id.ts +10 -0
  46. package/src/constants/invoice-response-process-id.ts +9 -0
  47. package/src/constants/invoice-response-profile-id.ts +9 -0
  48. package/src/constants/message-level-response-doctype-id.ts +10 -0
  49. package/src/constants/message-level-response-process-id.ts +9 -0
  50. package/src/constants/message-level-response-profile-id.ts +9 -0
  51. package/src/constants/participant-scheme.ts +10 -0
  52. package/src/constants/process-scheme.ts +9 -0
  53. package/src/constants/transport-profile.ts +10 -0
  54. package/src/invoice-response-codes/invoice-response-code-needs-schema.ts +9 -0
  55. package/src/invoice-response-codes/invoice-response-code-not-needs-schema.ts +9 -0
  56. package/src/invoice-response-codes/invoice-response-codes-order.ts +10 -0
  57. package/src/peppol-validations/add-piva.ts +12 -0
  58. package/src/peppol-validations/check-cf.ts +11 -0
  59. package/src/peppol-validations/check-cf16.ts +12 -0
  60. package/src/peppol-validations/check-piva-se-it.ts +11 -0
  61. package/src/peppol-validations/check-piva.ts +11 -0
  62. package/src/peppol-validations/check-se-orgnr.ts +9 -0
  63. package/src/peppol-validations/greek-tin-verification.ts +9 -0
  64. package/src/peppol-validations/is-valid-abn.ts +9 -0
  65. package/src/peppol-validations/is-valid-gln.ts +10 -0
  66. package/src/peppol-validations/is-valid-iban.ts +10 -0
  67. package/src/peppol-validations/is-valid-mod11.ts +9 -0
  68. package/src/peppol-validations/is-valid-mod97-0208.ts +10 -0
  69. package/src/peppol-validations/luhn-check.ts +9 -0
  70. package/src/schemas/fields/default-customization-id.ts +9 -0
  71. package/src/schemas/fields/default-profile-id.ts +9 -0
  72. package/src/schemas/fields/peppol-additional-document-reference-schema.ts +41 -2
  73. package/src/schemas/fields/peppol-address-schema.ts +25 -2
  74. package/src/schemas/fields/peppol-allowance-charge-schema.ts +65 -9
  75. package/src/schemas/fields/peppol-amount-schema.ts +15 -2
  76. package/src/schemas/fields/peppol-base-line-schema.ts +12 -2
  77. package/src/schemas/fields/peppol-billing-reference-schema.ts +13 -0
  78. package/src/schemas/fields/peppol-binary-object-schema.ts +12 -4
  79. package/src/schemas/fields/peppol-contact-schema.ts +11 -0
  80. package/src/schemas/fields/peppol-credit-note-line-schema.ts +7 -2
  81. package/src/schemas/fields/peppol-delivery-schema.ts +44 -2
  82. package/src/schemas/fields/peppol-identifier-schema.ts +8 -0
  83. package/src/schemas/fields/peppol-invoice-line-period-schema.ts +11 -0
  84. package/src/schemas/fields/peppol-invoice-line-schema.ts +9 -2
  85. package/src/schemas/fields/peppol-invoice-period-schema.ts +2 -2
  86. package/src/schemas/fields/peppol-item-classification-schema.ts +2 -2
  87. package/src/schemas/fields/peppol-line-allowance-charge-schema.ts +57 -9
  88. package/src/schemas/fields/peppol-line-item-schema.ts +69 -4
  89. package/src/schemas/fields/peppol-line-price-allowance-charge-schema.ts +20 -0
  90. package/src/schemas/fields/peppol-line-price-schema.ts +2 -0
  91. package/src/schemas/fields/peppol-order-reference-schema.ts +2 -0
  92. package/src/schemas/fields/peppol-party-base-schema.ts +36 -4
  93. package/src/schemas/fields/peppol-party-legal-entity-schema.ts +13 -0
  94. package/src/schemas/fields/peppol-party-tax-scheme-schema.ts +5 -0
  95. package/src/schemas/fields/peppol-payee-party-schema.ts +2 -2
  96. package/src/schemas/fields/peppol-payment-means-schema.ts +62 -2
  97. package/src/schemas/fields/peppol-payment-terms-schema.ts +2 -0
  98. package/src/schemas/fields/peppol-quantity-schema.ts +4 -2
  99. package/src/schemas/fields/peppol-reference-schema.ts +20 -1
  100. package/src/schemas/fields/peppol-tax-category-schema.ts +12 -2
  101. package/src/schemas/fields/peppol-tax-representative-schema.ts +5 -0
  102. package/src/schemas/fields/peppol-tax-subtotal-category-schema.ts +3 -0
  103. package/src/schemas/fields/peppol-tax-subtotal-schema.ts +2 -0
  104. package/src/schemas/fields/peppol-tax-totals-base-schema.ts +5 -0
  105. package/src/schemas/peppol-billing-base-schema.ts +47 -7
  106. package/src/schemas/peppol-credit-note-schema.ts +2 -2
  107. package/src/schemas/peppol-document-response-document-reference-schema.ts +15 -2
  108. package/src/schemas/peppol-document-response-document-schema.ts +8 -3
  109. package/src/schemas/peppol-document-response-line-response-content-schema.ts +22 -2
  110. package/src/schemas/peppol-document-response-line-response-schema.ts +26 -0
  111. package/src/schemas/peppol-document-schema.ts +74 -9
  112. package/src/schemas/peppol-invoice-response-document-actual-response-schema.ts +58 -5
  113. package/src/schemas/peppol-invoice-response-document-actual-response-status-schema.ts +25 -2
  114. package/src/schemas/peppol-invoice-response-schema.ts +57 -4
  115. package/src/schemas/peppol-invoice-response-status-reason-code-schema.ts +37 -10
  116. package/src/schemas/peppol-invoice-schema.ts +30 -2
  117. package/src/schemas/peppol-message-level-response-document-response-schema.ts +10 -0
  118. package/src/schemas/peppol-message-level-response-party-schema.ts +10 -0
  119. package/src/schemas/peppol-message-level-response-schema.ts +18 -0
  120. package/src/schemas/utils/format-quantity-with-unit.ts +19 -0
  121. package/src/schemas/utils/get-credit-note-type-code-description.ts +12 -0
  122. package/src/schemas/utils/get-invoice-type-code-description.ts +12 -0
  123. package/src/schemas/utils/is-valid-credit-note-type-code.ts +13 -0
  124. package/src/schemas/utils/is-valid-invoice-type-code.ts +13 -0
  125. package/src/schemas/utils/is-valid-process.ts +13 -0
  126. package/src/schemas/utils/peppol-base-64-schema.ts +14 -4
  127. package/src/schemas/utils/peppol-vat-regex-schema.ts +38 -30
  128. package/src/schemas/utils/peppol-xsd-time-schema.ts +12 -2
  129. package/src/schemas/utils/quantity-unit-code-to-intl-unit.ts +34 -0
  130. package/src/schemas/values/additional-document-reference-code-schema.ts +9 -15
  131. package/src/schemas/values/allowance-charge-reason-code-schema.ts +12 -14
  132. package/src/schemas/values/application-response-type-code-schema.ts +10 -14
  133. package/src/schemas/values/charge-reason-code-schema.ts +12 -14
  134. package/src/schemas/values/credit-note-type-code-schema.ts +8 -14
  135. package/src/schemas/values/currency-code-schema.ts +13 -16
  136. package/src/schemas/values/document-type-schemes-schema.ts +9 -5
  137. package/src/schemas/values/document-type-values-schema.ts +5 -6
  138. package/src/schemas/values/duty-tax-fee-category-schema.ts +15 -13
  139. package/src/schemas/values/electronic-codes-schema.ts +10 -12
  140. package/src/schemas/values/icd-codes-schema.ts +8 -12
  141. package/src/schemas/values/invoice-status-code-schema.ts +10 -12
  142. package/src/schemas/values/invoice-type-code-schema.ts +10 -12
  143. package/src/schemas/values/item-classification-codes-schema.ts +10 -12
  144. package/src/schemas/values/mime-codes-schema.ts +12 -14
  145. package/src/schemas/values/op-status-action-schema.ts +10 -12
  146. package/src/schemas/values/op-status-reason-schema.ts +10 -12
  147. package/src/schemas/values/participant-identifier-code-schema.ts +10 -13
  148. package/src/schemas/values/payment-means-code-schema.ts +10 -12
  149. package/src/schemas/values/peppol-country-code-schema.ts +10 -9
  150. package/src/schemas/values/peppol-document-type-code-schema.ts +10 -12
  151. package/src/schemas/values/peppol-document-type-schema.ts +12 -21
  152. package/src/schemas/values/peppol-process-schema.ts +19 -15
  153. package/src/schemas/values/process-from-document-type-schema.ts +3 -3
  154. package/src/schemas/values/quantity-unit-codes-schema.ts +10 -12
  155. package/src/schemas/values/vat-date-code-schema.ts +12 -5
  156. package/src/schemas/values/vatex-code-schema.ts +8 -12
  157. package/src/schematron/errors.ts +14 -0
  158. package/src/schematron/helpers.ts +451 -0
  159. package/src/schematron/run-all-rules.ts +10 -0
  160. package/src/schematron/schematron.ts +25 -0
  161. package/src/xml/builder-options.ts +9 -0
  162. package/src/xml/common-xml-options.ts +9 -0
  163. package/src/xml/nodable-parser.ts +12 -0
  164. package/src/xml/parser-options.ts +9 -0
  165. package/dist/index-BBzPjq7o.d.ts.map +0 -1
  166. package/dist/invoice-response-code-not-needs-schema-p_RKKNLc.js +0 -18
  167. package/dist/invoice-response-code-not-needs-schema-p_RKKNLc.js.map +0 -1
  168. package/dist/is-valid-abn-160i38PG.js.map +0 -1
  169. package/dist/is-valid-mod97-0208-CzMOXMO-.js.map +0 -1
  170. package/dist/message-level-response-profile-id-DBpOW91B.js +0 -9
  171. package/dist/message-level-response-profile-id-DBpOW91B.js.map +0 -1
  172. package/dist/nodable-parser-CyDZtLCK.js.map +0 -1
  173. package/dist/vat-dates.generated-CxFvt7m3.d.ts +0 -68
  174. package/dist/vat-dates.generated-CxFvt7m3.d.ts.map +0 -1
@@ -9,24 +9,56 @@ import { SchematronRuleError } from '#/schematron/errors.ts';
9
9
  import { chargeReasonCodesKeys } from '#/values/charge-reason-codes.generated';
10
10
  import { countryCodesKeys } from '#/values/country-code.generated';
11
11
 
12
+ /**
13
+ * @description Alias for a single line of a {@link PeppolDocument}, either an invoice line (BG-25) or a credit note line (BG-31).
14
+ */
12
15
  export type PeppolLine = PeppolDocumentLine;
13
16
 
14
17
  /**
15
18
  * @description Rule metadata shared by all schematron rules.
16
19
  */
17
20
  export interface SchematronRule {
21
+ /**
22
+ * @description The rule identifier, for example `PEPPOL-EN16931-R001`.
23
+ */
18
24
  id: string;
25
+ /**
26
+ * @description The severity of the rule, mirroring the schematron `flag` attribute.
27
+ */
19
28
  level: SchematronRuleLevel;
29
+ /**
30
+ * @description Human readable reason reported when the rule fails.
31
+ */
20
32
  message: string;
21
33
  }
22
34
 
23
35
  /**
24
36
  * @description An effectful schematron rule validator. Fails with a `SchematronRuleError` when the document does not satisfy the rule.
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * const validate: SchematronDocumentValidator = schematronRule(metadata, document => document.taxTotals.length > 0);
41
+ * ```;
42
+ *
43
+ * @see {@link schematronRule}
25
44
  */
26
45
  export type SchematronDocumentValidator = (document: PeppolDocument) => Effect.Effect<void, SchematronRuleError>;
27
46
 
28
47
  /**
29
48
  * @description Builds an effectful validator from rule metadata and a pure predicate.
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * const metadata: SchematronRule = { id: 'PEPPOL-EN16931-R001', level: 'fatal', message: 'The document must carry a number.' };
53
+ * const validate = schematronRule(metadata, document => document.taxTotals.length > 0);
54
+ * ```;
55
+ *
56
+ * @param rule - The rule identifier, severity and message reported on failure.
57
+ * @param predicate - The pure check applied to the document; returning `false` fails the rule.
58
+ *
59
+ * @returns A {@link SchematronDocumentValidator} that succeeds for a passing document and fails with a `SchematronRuleError` otherwise.
60
+ *
61
+ * @see {@link SchematronRule}
30
62
  */
31
63
  export function schematronRule(rule: SchematronRule, predicate: (document: PeppolDocument) => boolean): SchematronDocumentValidator {
32
64
  return Effect.fn(`schematron.${rule.id}`)(function* (document: PeppolDocument) {
@@ -38,6 +70,15 @@ export function schematronRule(rule: SchematronRule, predicate: (document: Peppo
38
70
 
39
71
  /**
40
72
  * @description Rounds a number to 2 decimals, mirroring the schematron `round(x * 10 * 10) div 100`.
73
+ *
74
+ * @example
75
+ * ```ts
76
+ * round2(1.2345); // 1.23
77
+ * ```;
78
+ *
79
+ * @param value - The number to round.
80
+ *
81
+ * @returns The value rounded to 2 decimals.
41
82
  */
42
83
  export function round2(value: number): number {
43
84
  return Math.round(value * 100) / 100;
@@ -45,6 +86,17 @@ export function round2(value: number): number {
45
86
 
46
87
  /**
47
88
  * @description Checks that `val` is within `slack` of `exp`, mirroring the schematron `u:slack` function.
89
+ *
90
+ * @example
91
+ * ```ts
92
+ * slack(100, 100.5, 1); // true
93
+ * ```;
94
+ *
95
+ * @param exp - The expected value, the centre of the accepted range.
96
+ * @param val - The actual value to test.
97
+ * @param tolerance - The absolute slack allowed on either side of `exp`.
98
+ *
99
+ * @returns `true` when `val` is within `tolerance` of `exp`, otherwise `false`.
48
100
  */
49
101
  export function slack(exp: number, val: number, tolerance: number): boolean {
50
102
  return exp + tolerance >= val && exp - tolerance <= val;
@@ -53,6 +105,15 @@ export function slack(exp: number, val: number, tolerance: number): boolean {
53
105
  /**
54
106
  * @description Extracts the process number from the business process identifier, mirroring the schematron `$profile` variable. Returns `'Unknown'` when the
55
107
  * identifier does not match the expected format.
108
+ *
109
+ * @example
110
+ * ```ts
111
+ * getProfile(document); // '01'
112
+ * ```;
113
+ *
114
+ * @param document - The document whose `profileId` is read.
115
+ *
116
+ * @returns The two digit process number, for example `'01'`, or `'Unknown'` when the identifier does not match the expected billing profile format.
56
117
  */
57
118
  export function getProfile(document: Pick<PeppolDocument, 'profileId'>): string {
58
119
  const profileId = document.profileId;
@@ -64,6 +125,15 @@ export function getProfile(document: Pick<PeppolDocument, 'profileId'>): string
64
125
 
65
126
  /**
66
127
  * @description Resolves the supplier country from the VAT identifier prefix or the supplier postal address, mirroring the schematron `$supplierCountry` variable.
128
+ *
129
+ * @example
130
+ * ```ts
131
+ * getSupplierCountry(document); // 'IT'
132
+ * ```;
133
+ *
134
+ * @param document - The document whose supplier VAT identifiers and postal address are read.
135
+ *
136
+ * @returns The upper case ISO 3166-1 alpha-2 country code, defaulting to `'XX'` when neither the VAT prefix nor the postal address provides one.
67
137
  */
68
138
  export function getSupplierCountry(document: PeppolDocument): string {
69
139
  const vatScheme = document.accountingSupplierParty.partyTaxSchemes?.find(s => s.taxSchemeId.id === 'VAT');
@@ -84,6 +154,15 @@ export function getSupplierCountry(document: PeppolDocument): string {
84
154
 
85
155
  /**
86
156
  * @description Resolves the customer country from the VAT identifier prefix or the customer postal address, mirroring the schematron `$customerCountry` variable.
157
+ *
158
+ * @example
159
+ * ```ts
160
+ * getCustomerCountry(document); // 'DE'
161
+ * ```;
162
+ *
163
+ * @param document - The document whose customer VAT identifiers and postal address are read.
164
+ *
165
+ * @returns The upper case ISO 3166-1 alpha-2 country code, defaulting to `'XX'` when neither the VAT prefix nor the postal address provides one.
87
166
  */
88
167
  export function getCustomerCountry(document: PeppolDocument): string {
89
168
  const vatScheme = document.accountingCustomerParty.partyTaxSchemes?.find(s => s.taxSchemeId.id === 'VAT');
@@ -97,6 +176,15 @@ export function getCustomerCountry(document: PeppolDocument): string {
97
176
 
98
177
  /**
99
178
  * @description Whether the supplier postal address country is Germany, mirroring the schematron `$supplierCountryIsDE` variable.
179
+ *
180
+ * @example
181
+ * ```ts
182
+ * isSupplierGermany(document); // false
183
+ * ```;
184
+ *
185
+ * @param document - The document whose supplier postal address is read.
186
+ *
187
+ * @returns `true` when the supplier postal address country code is `DE`, otherwise `false`.
100
188
  */
101
189
  export function isSupplierGermany(document: PeppolDocument): boolean {
102
190
  return document.accountingSupplierParty.postalAddress.countryCode.identificationCode.toUpperCase() === 'DE';
@@ -104,6 +192,15 @@ export function isSupplierGermany(document: PeppolDocument): boolean {
104
192
 
105
193
  /**
106
194
  * @description Whether the customer postal address country is Germany, mirroring the schematron `$customerCountryIsDE` variable.
195
+ *
196
+ * @example
197
+ * ```ts
198
+ * isCustomerGermany(document); // false
199
+ * ```;
200
+ *
201
+ * @param document - The document whose customer postal address is read.
202
+ *
203
+ * @returns `true` when the customer postal address country code is `DE`, otherwise `false`.
107
204
  */
108
205
  export function isCustomerGermany(document: PeppolDocument): boolean {
109
206
  return document.accountingCustomerParty.postalAddress.countryCode.identificationCode.toUpperCase() === 'DE';
@@ -111,6 +208,15 @@ export function isCustomerGermany(document: PeppolDocument): boolean {
111
208
 
112
209
  /**
113
210
  * @description Whether both the supplier and customer countries are Denmark, mirroring the schematron `$supplierCountryIsDK` and `$customerCountryIsDK` variables.
211
+ *
212
+ * @example
213
+ * ```ts
214
+ * isDanishSupplierAndCustomer(document); // true
215
+ * ```;
216
+ *
217
+ * @param document - The document whose supplier and customer countries are read.
218
+ *
219
+ * @returns `true` when both {@link getSupplierCountry} and {@link getCustomerCountry} return `DK`, otherwise `false`.
114
220
  */
115
221
  export function isDanishSupplierAndCustomer(document: PeppolDocument): boolean {
116
222
  return getSupplierCountry(document) === 'DK' && getCustomerCountry(document) === 'DK';
@@ -119,6 +225,15 @@ export function isDanishSupplierAndCustomer(document: PeppolDocument): boolean {
119
225
  /**
120
226
  * @description Whether both the supplier and customer postal address countries are Germany, mirroring the schematron `$supplierCountryIsDE` and
121
227
  * `$customerCountryIsDE` variables.
228
+ *
229
+ * @example
230
+ * ```ts
231
+ * isGermanSupplierAndCustomer(document); // true
232
+ * ```;
233
+ *
234
+ * @param document - The document whose supplier and customer postal addresses are read.
235
+ *
236
+ * @returns `true` when both postal address country codes are `DE`, otherwise `false`.
122
237
  */
123
238
  export function isGermanSupplierAndCustomer(document: PeppolDocument): boolean {
124
239
  return isSupplierGermany(document) && isCustomerGermany(document);
@@ -126,6 +241,15 @@ export function isGermanSupplierAndCustomer(document: PeppolDocument): boolean {
126
241
 
127
242
  /**
128
243
  * @description Returns the invoice lines or credit note lines of a document.
244
+ *
245
+ * @example
246
+ * ```ts
247
+ * getLines(document).length; // 3
248
+ * ```;
249
+ *
250
+ * @param document - The invoice or credit note whose lines are read.
251
+ *
252
+ * @returns The `invoiceLines` or `creditNoteLines` array, or an empty array when the document carries neither.
129
253
  */
130
254
  export function getLines(document: PeppolDocument): Array<PeppolLine> {
131
255
  if ('invoiceLines' in document && Array.isArray(document.invoiceLines)) {
@@ -139,6 +263,15 @@ export function getLines(document: PeppolDocument): Array<PeppolLine> {
139
263
 
140
264
  /**
141
265
  * @description Returns the line quantity (invoiced or credited quantity) of a line, defaulting to 1.
266
+ *
267
+ * @example
268
+ * ```ts
269
+ * getLineQuantity(line); // 2
270
+ * ```;
271
+ *
272
+ * @param line - The invoice or credit note line whose quantity is read.
273
+ *
274
+ * @returns The `invoicedQuantity` or `creditedQuantity` value, or `1` when the line carries neither.
142
275
  */
143
276
  export function getLineQuantity(line: PeppolLine): number {
144
277
  const quantity = 'invoicedQuantity' in line ? line.invoicedQuantity : 'creditedQuantity' in line ? line.creditedQuantity : undefined;
@@ -147,6 +280,15 @@ export function getLineQuantity(line: PeppolLine): number {
147
280
 
148
281
  /**
149
282
  * @description Returns all document level and line level allowance/charges of a document.
283
+ *
284
+ * @example
285
+ * ```ts
286
+ * getAllAllowanceCharges(document).length; // 2
287
+ * ```;
288
+ *
289
+ * @param document - The document whose document level and line level allowance/charges are collected.
290
+ *
291
+ * @returns Every allowance and charge as a flat array of normalised records, document level entries first.
150
292
  */
151
293
  export function getAllAllowanceCharges(
152
294
  document: PeppolDocument
@@ -184,6 +326,16 @@ export function getAllAllowanceCharges(
184
326
 
185
327
  /**
186
328
  * @description Whether a VAT breakdown group (BG-23) contains a VAT category code equal to `code`.
329
+ *
330
+ * @example
331
+ * ```ts
332
+ * hasVatBreakdownCode(document, 'S'); // true
333
+ * ```;
334
+ *
335
+ * @param document - The document whose VAT breakdown groups (BG-23) are read.
336
+ * @param code - The VAT category code (BT-118) to look for, for example `'S'`.
337
+ *
338
+ * @returns `true` when any VAT breakdown group carries `code`, otherwise `false`.
187
339
  */
188
340
  export function hasVatBreakdownCode(document: PeppolDocument, code: string): boolean {
189
341
  return document.taxTotals.some(t => t.taxSubtotals?.some(s => s.taxCategory.id === code) ?? false);
@@ -191,6 +343,16 @@ export function hasVatBreakdownCode(document: PeppolDocument, code: string): boo
191
343
 
192
344
  /**
193
345
  * @description Whether the document contains a VAT category code (BT-151, BT-95 or BT-102) equal to `code`.
346
+ *
347
+ * @example
348
+ * ```ts
349
+ * hasVatCategoryCode(document, 'S'); // true
350
+ * ```;
351
+ *
352
+ * @param document - The document whose lines and document level allowance/charges are read.
353
+ * @param code - The VAT category code (BT-151, BT-95 or BT-102) to look for.
354
+ *
355
+ * @returns `true` when any line or document level allowance/charge carries `code`, otherwise `false`.
194
356
  */
195
357
  export function hasVatCategoryCode(document: PeppolDocument, code: string): boolean {
196
358
  const lineCategories = getLines(document).some(line => line.item.classifiedTaxCategory.id === code);
@@ -200,6 +362,15 @@ export function hasVatCategoryCode(document: PeppolDocument, code: string): bool
200
362
 
201
363
  /**
202
364
  * @description Resolves the supplier VAT identifier (BT-31) or the seller tax registration identifier (BT-32).
365
+ *
366
+ * @example
367
+ * ```ts
368
+ * getSupplierTaxIdentifiers(document); // 'IT00743110157'
369
+ * ```;
370
+ *
371
+ * @param document - The document whose supplier party tax schemes are read.
372
+ *
373
+ * @returns The comma separated supplier and tax representative identifiers, or an empty string when none is present.
203
374
  */
204
375
  export function getSupplierTaxIdentifiers(document: PeppolDocument): string {
205
376
  const companyIds = document.accountingSupplierParty.partyTaxSchemes?.map(scheme => scheme.companyId) ?? [];
@@ -209,6 +380,15 @@ export function getSupplierTaxIdentifiers(document: PeppolDocument): string {
209
380
 
210
381
  /**
211
382
  * @description Whether the supplier has a VAT identifier (BT-31), a seller tax registration identifier (BT-32) or a tax representative VAT identifier (BT-63).
383
+ *
384
+ * @example
385
+ * ```ts
386
+ * hasSellerTaxIdentifier(document); // true
387
+ * ```;
388
+ *
389
+ * @param document - The document whose supplier party tax schemes are read.
390
+ *
391
+ * @returns `true` when the supplier carries at least one non-empty company identifier, otherwise `false`.
212
392
  */
213
393
  export function hasSellerTaxIdentifier(document: PeppolDocument): boolean {
214
394
  return document.accountingSupplierParty.partyTaxSchemes?.some(scheme => scheme.companyId.trim() !== '') ?? false;
@@ -216,6 +396,15 @@ export function hasSellerTaxIdentifier(document: PeppolDocument): boolean {
216
396
 
217
397
  /**
218
398
  * @description Whether the buyer has a VAT identifier (BT-48) or a legal registration identifier (BT-47).
399
+ *
400
+ * @example
401
+ * ```ts
402
+ * hasBuyerTaxIdentifier(document); // false
403
+ * ```;
404
+ *
405
+ * @param document - The document whose buyer party tax schemes and legal entity are read.
406
+ *
407
+ * @returns `true` when the buyer carries a VAT identifier (BT-48) or a legal registration identifier (BT-47), otherwise `false`.
219
408
  */
220
409
  export function hasBuyerTaxIdentifier(document: PeppolDocument): boolean {
221
410
  const buyerVat = document.accountingCustomerParty.partyTaxSchemes?.some(scheme => scheme.companyId.trim() !== '') ?? false;
@@ -227,6 +416,16 @@ export function hasBuyerTaxIdentifier(document: PeppolDocument): boolean {
227
416
 
228
417
  /**
229
418
  * @description Whether a number has at most two fraction digits, mirroring the schematron `string-length(substring-after(.,'.'))<=2` checks.
419
+ *
420
+ * @example
421
+ * ```ts
422
+ * hasMaxTwoDecimals(1.25); // true
423
+ * hasMaxTwoDecimals(1.255); // false
424
+ * ```;
425
+ *
426
+ * @param value - The number to inspect.
427
+ *
428
+ * @returns `true` when the value has at most two fraction digits, otherwise `false`.
230
429
  */
231
430
  export function hasMaxTwoDecimals(value: number): boolean {
232
431
  return Math.abs(Math.round(value * 100) / 100 - value) < 1e-9;
@@ -234,6 +433,16 @@ export function hasMaxTwoDecimals(value: number): boolean {
234
433
 
235
434
  /**
236
435
  * @description Whether two monetary values are equal, tolerating floating point drift of parsed decimals.
436
+ *
437
+ * @example
438
+ * ```ts
439
+ * amountsEqual(100, 100.0000000001); // true
440
+ * ```;
441
+ *
442
+ * @param a - The first monetary value.
443
+ * @param b - The second monetary value.
444
+ *
445
+ * @returns `true` when the two values differ by less than `1e-9`, otherwise `false`.
237
446
  */
238
447
  export function amountsEqual(a: number, b: number): boolean {
239
448
  return Math.abs(a - b) < 1e-9;
@@ -241,6 +450,16 @@ export function amountsEqual(a: number, b: number): boolean {
241
450
 
242
451
  /**
243
452
  * @description Counts the VAT breakdown groups (BG-23) whose VAT category code (BT-118) equals `code`.
453
+ *
454
+ * @example
455
+ * ```ts
456
+ * countVatBreakdownCode(document, 'S'); // 1
457
+ * ```;
458
+ *
459
+ * @param document - The document whose VAT breakdown groups (BG-23) are counted.
460
+ * @param code - The VAT category code (BT-118) to count.
461
+ *
462
+ * @returns The number of VAT breakdown groups carrying `code`.
244
463
  */
245
464
  export function countVatBreakdownCode(document: PeppolDocument, code: string): number {
246
465
  return document.taxTotals.reduce(
@@ -260,6 +479,16 @@ function countVatCategoryCode(document: PeppolDocument, code: string): number {
260
479
 
261
480
  /**
262
481
  * @description Whether an invoice line (BG-25) carries a VAT category code (BT-151) equal to `code`.
482
+ *
483
+ * @example
484
+ * ```ts
485
+ * hasLineVatCategoryCode(document, 'S'); // true
486
+ * ```;
487
+ *
488
+ * @param document - The document whose invoice lines (BG-25) are read.
489
+ * @param code - The VAT category code (BT-151) to look for.
490
+ *
491
+ * @returns `true` when any invoice line carries `code`, otherwise `false`.
263
492
  */
264
493
  export function hasLineVatCategoryCode(document: PeppolDocument, code: string): boolean {
265
494
  return getLines(document).some(line => line.item.classifiedTaxCategory.id === code);
@@ -267,6 +496,16 @@ export function hasLineVatCategoryCode(document: PeppolDocument, code: string):
267
496
 
268
497
  /**
269
498
  * @description Whether a document level allowance (BG-20) carries a VAT category code (BT-95) equal to `code`.
499
+ *
500
+ * @example
501
+ * ```ts
502
+ * hasDocumentAllowanceVatCategoryCode(document, 'S'); // false
503
+ * ```;
504
+ *
505
+ * @param document - The document whose document level allowances (BG-20) are read.
506
+ * @param code - The VAT category code (BT-95) to look for.
507
+ *
508
+ * @returns `true` when any document level allowance carries `code`, otherwise `false`.
270
509
  */
271
510
  export function hasDocumentAllowanceVatCategoryCode(document: PeppolDocument, code: string): boolean {
272
511
  return (document.allowanceCharges ?? []).some(ac => !ac.chargeIndicator && ac.taxCategory?.id === code);
@@ -274,6 +513,16 @@ export function hasDocumentAllowanceVatCategoryCode(document: PeppolDocument, co
274
513
 
275
514
  /**
276
515
  * @description Whether a document level charge (BG-21) carries a VAT category code (BT-102) equal to `code`.
516
+ *
517
+ * @example
518
+ * ```ts
519
+ * hasDocumentChargeVatCategoryCode(document, 'S'); // false
520
+ * ```;
521
+ *
522
+ * @param document - The document whose document level charges (BG-21) are read.
523
+ * @param code - The VAT category code (BT-102) to look for.
524
+ *
525
+ * @returns `true` when any document level charge carries `code`, otherwise `false`.
277
526
  */
278
527
  export function hasDocumentChargeVatCategoryCode(document: PeppolDocument, code: string): boolean {
279
528
  return (document.allowanceCharges ?? []).some(ac => ac.chargeIndicator && ac.taxCategory?.id === code);
@@ -281,6 +530,15 @@ export function hasDocumentChargeVatCategoryCode(document: PeppolDocument, code:
281
530
 
282
531
  /**
283
532
  * @description Whether the supplier has a VAT identifier (BT-31) on a party tax scheme whose tax scheme is "VAT".
533
+ *
534
+ * @example
535
+ * ```ts
536
+ * hasSellerVatCompanyId(document); // true
537
+ * ```;
538
+ *
539
+ * @param document - The document whose supplier party tax schemes are read.
540
+ *
541
+ * @returns `true` when the supplier has a non-empty VAT identifier on a `VAT` tax scheme, otherwise `false`.
284
542
  */
285
543
  export function hasSellerVatCompanyId(document: PeppolDocument): boolean {
286
544
  return (
@@ -292,6 +550,15 @@ export function hasSellerVatCompanyId(document: PeppolDocument): boolean {
292
550
 
293
551
  /**
294
552
  * @description Whether the buyer has a VAT identifier (BT-48) on a party tax scheme whose tax scheme is "VAT".
553
+ *
554
+ * @example
555
+ * ```ts
556
+ * hasBuyerVatCompanyId(document); // false
557
+ * ```;
558
+ *
559
+ * @param document - The document whose buyer party tax schemes are read.
560
+ *
561
+ * @returns `true` when the buyer has a non-empty VAT identifier on a `VAT` tax scheme, otherwise `false`.
295
562
  */
296
563
  export function hasBuyerVatCompanyId(document: PeppolDocument): boolean {
297
564
  return (
@@ -303,6 +570,15 @@ export function hasBuyerVatCompanyId(document: PeppolDocument): boolean {
303
570
 
304
571
  /**
305
572
  * @description Whether the seller tax representative has a VAT identifier (BT-63) on a "VAT" tax scheme.
573
+ *
574
+ * @example
575
+ * ```ts
576
+ * hasTaxRepresentativeVatCompanyId(document); // false
577
+ * ```;
578
+ *
579
+ * @param document - The document whose seller tax representative party is read.
580
+ *
581
+ * @returns `true` when a tax representative exists with a non-empty VAT identifier on a `VAT` tax scheme, otherwise `false`.
306
582
  */
307
583
  export function hasTaxRepresentativeVatCompanyId(document: PeppolDocument): boolean {
308
584
  const taxRepresentative = document.taxRepresentativeParty;
@@ -314,6 +590,15 @@ export function hasTaxRepresentativeVatCompanyId(document: PeppolDocument): bool
314
590
 
315
591
  /**
316
592
  * @description Whether the buyer has a legal registration identifier (BT-47).
593
+ *
594
+ * @example
595
+ * ```ts
596
+ * hasBuyerLegalCompanyId(document); // false
597
+ * ```;
598
+ *
599
+ * @param document - The document whose buyer legal entity is read.
600
+ *
601
+ * @returns `true` when the buyer has a non-empty legal registration identifier (BT-47), otherwise `false`.
317
602
  */
318
603
  export function hasBuyerLegalCompanyId(document: PeppolDocument): boolean {
319
604
  const id = document.accountingCustomerParty.partyLegalEntity.companyId?.id;
@@ -322,6 +607,17 @@ export function hasBuyerLegalCompanyId(document: PeppolDocument): boolean {
322
607
 
323
608
  /**
324
609
  * @description Whether every invoice line carrying a VAT category code (BT-151) equal to `code` satisfies `predicate` on its VAT rate (BT-152).
610
+ *
611
+ * @example
612
+ * ```ts
613
+ * everyLineCategoryPercent(document, 'S', percent => percent !== undefined && percent > 0); // true
614
+ * ```;
615
+ *
616
+ * @param document - The document whose invoice lines are read.
617
+ * @param code - The VAT category code (BT-151) to match.
618
+ * @param predicate - The check applied to the VAT rate (BT-152) of matching lines.
619
+ *
620
+ * @returns `true` when every matching line satisfies `predicate`, otherwise `false`.
325
621
  */
326
622
  export function everyLineCategoryPercent(document: PeppolDocument, code: string, predicate: (percent: number | undefined) => boolean): boolean {
327
623
  return getLines(document).every(line => line.item.classifiedTaxCategory.id !== code || predicate(line.item.classifiedTaxCategory.percent));
@@ -329,6 +625,17 @@ export function everyLineCategoryPercent(document: PeppolDocument, code: string,
329
625
 
330
626
  /**
331
627
  * @description Whether every document level allowance carrying a VAT category code (BT-95) equal to `code` satisfies `predicate` on its VAT rate (BT-96).
628
+ *
629
+ * @example
630
+ * ```ts
631
+ * everyDocumentAllowanceCategoryPercent(document, 'S', percent => percent === 0); // false
632
+ * ```;
633
+ *
634
+ * @param document - The document whose document level allowances are read.
635
+ * @param code - The VAT category code (BT-95) to match.
636
+ * @param predicate - The check applied to the VAT rate (BT-96) of matching allowances.
637
+ *
638
+ * @returns `true` when every matching allowance satisfies `predicate`, otherwise `false`.
332
639
  */
333
640
  export function everyDocumentAllowanceCategoryPercent(
334
641
  document: PeppolDocument,
@@ -340,6 +647,17 @@ export function everyDocumentAllowanceCategoryPercent(
340
647
 
341
648
  /**
342
649
  * @description Whether every document level charge carrying a VAT category code (BT-102) equal to `code` satisfies `predicate` on its VAT rate (BT-103).
650
+ *
651
+ * @example
652
+ * ```ts
653
+ * everyDocumentChargeCategoryPercent(document, 'S', percent => percent === 0); // false
654
+ * ```;
655
+ *
656
+ * @param document - The document whose document level charges are read.
657
+ * @param code - The VAT category code (BT-102) to match.
658
+ * @param predicate - The check applied to the VAT rate (BT-103) of matching charges.
659
+ *
660
+ * @returns `true` when every matching charge satisfies `predicate`, otherwise `false`.
343
661
  */
344
662
  export function everyDocumentChargeCategoryPercent(
345
663
  document: PeppolDocument,
@@ -352,6 +670,16 @@ export function everyDocumentChargeCategoryPercent(
352
670
  /**
353
671
  * @description Sum of invoice line net amounts (BT-131) plus document level charge amounts (BT-99) minus document level allowance amounts (BT-92) where the VAT
354
672
  * category codes (BT-151, BT-102, BT-95) equal `code`.
673
+ *
674
+ * @example
675
+ * ```ts
676
+ * categoryTaxableSum(document, 'S'); // 1000
677
+ * ```;
678
+ *
679
+ * @param document - The document whose lines and document level allowance/charges are summed.
680
+ * @param code - The VAT category code (BT-151, BT-102 or BT-95) to sum.
681
+ *
682
+ * @returns The sum of matching invoice line net amounts plus charges minus allowances.
355
683
  */
356
684
  export function categoryTaxableSum(document: PeppolDocument, code: string): number {
357
685
  const lineSum = getLines(document)
@@ -368,6 +696,16 @@ export function categoryTaxableSum(document: PeppolDocument, code: string): numb
368
696
 
369
697
  /**
370
698
  * @description Returns the VAT breakdown groups (BG-23) whose VAT category code (BT-118) equals `code`.
699
+ *
700
+ * @example
701
+ * ```ts
702
+ * getTaxSubtotalsWithCode(document, 'S').length; // 1
703
+ * ```;
704
+ *
705
+ * @param document - The document whose VAT breakdown groups are read.
706
+ * @param code - The VAT category code (BT-118) to collect.
707
+ *
708
+ * @returns The matching VAT breakdown groups with their amounts and category details.
371
709
  */
372
710
  export function getTaxSubtotalsWithCode(
373
711
  document: PeppolDocument,
@@ -412,6 +750,15 @@ function categoryTaxableSumAtRate(document: PeppolDocument, code: string, rate:
412
750
 
413
751
  /**
414
752
  * @description Whether the seller has a legal registration identifier (BT-30), used by BR-CO-26.
753
+ *
754
+ * @example
755
+ * ```ts
756
+ * hasSellerLegalCompanyId(document); // true
757
+ * ```;
758
+ *
759
+ * @param document - The document whose supplier legal entity is read.
760
+ *
761
+ * @returns `true` when the supplier has a non-empty legal registration identifier (BT-30), otherwise `false`.
415
762
  */
416
763
  export function hasSellerLegalCompanyId(document: PeppolDocument): boolean {
417
764
  const id = document.accountingSupplierParty.partyLegalEntity.companyId?.id;
@@ -420,6 +767,16 @@ export function hasSellerLegalCompanyId(document: PeppolDocument): boolean {
420
767
 
421
768
  /**
422
769
  * @description Whether every ISO 3166-1 alpha-2 country code present on the document equals `code`, used by BR-B-01.
770
+ *
771
+ * @example
772
+ * ```ts
773
+ * everyCountryCodeIs(document, 'DE'); // false
774
+ * ```;
775
+ *
776
+ * @param document - The document whose country codes are read.
777
+ * @param code - The upper case ISO 3166-1 alpha-2 code to match.
778
+ *
779
+ * @returns `true` when every non-empty country code on the document equals `code`, otherwise `false`.
423
780
  */
424
781
  export function everyCountryCodeIs(document: PeppolDocument, code: string): boolean {
425
782
  const codes = [
@@ -436,6 +793,15 @@ export function everyCountryCodeIs(document: PeppolDocument, code: string): bool
436
793
 
437
794
  /**
438
795
  * @description Whether every VAT identifier (BT-31, BT-63, BT-48) carries a country prefix from the ISO 3166-1 alpha-2 list (including EL), used by BR-CO-09.
796
+ *
797
+ * @example
798
+ * ```ts
799
+ * allVatCompanyIdsHaveValidPrefix(document); // true
800
+ * ```;
801
+ *
802
+ * @param document - The document whose supplier, customer and tax representative VAT identifiers are read.
803
+ *
804
+ * @returns `true` when every VAT identifier starts with a known ISO 3166-1 alpha-2 country code (including `EL`), otherwise `false`.
439
805
  */
440
806
  export function allVatCompanyIdsHaveValidPrefix(document: PeppolDocument): boolean {
441
807
  const companyIds: Array<string> = [];
@@ -459,6 +825,15 @@ export function allVatCompanyIdsHaveValidPrefix(document: PeppolDocument): boole
459
825
 
460
826
  /**
461
827
  * @description Whether every invoice period / line period has an end date after or equal to its start date, used by BR-29 and BR-30.
828
+ *
829
+ * @example
830
+ * ```ts
831
+ * everyPeriodEndAfterStart(document); // true
832
+ * ```;
833
+ *
834
+ * @param document - The document whose invoice periods and line invoice periods are read.
835
+ *
836
+ * @returns `true` when every period with both dates has an end date on or after its start date, otherwise `false`.
462
837
  */
463
838
  export function everyPeriodEndAfterStart(document: PeppolDocument): boolean {
464
839
  const ok = (period: PeppolInvoicePeriod | undefined): boolean => {
@@ -473,6 +848,15 @@ export function everyPeriodEndAfterStart(document: PeppolDocument): boolean {
473
848
 
474
849
  /**
475
850
  * @description Whether every invoice period has a start/end date or a description code, used by BR-CO-19 and BR-CO-20.
851
+ *
852
+ * @example
853
+ * ```ts
854
+ * everyPeriodHasDateOrDescriptionCode(document); // true
855
+ * ```;
856
+ *
857
+ * @param document - The document whose invoice periods and line invoice periods are read.
858
+ *
859
+ * @returns `true` when every period has a start date, an end date or a description code, otherwise `false`.
476
860
  */
477
861
  export function everyPeriodHasDateOrDescriptionCode(document: PeppolDocument): boolean {
478
862
  const ok = (period: PeppolInvoicePeriod | undefined): boolean => {
@@ -487,6 +871,15 @@ export function everyPeriodHasDateOrDescriptionCode(document: PeppolDocument): b
487
871
 
488
872
  /**
489
873
  * @description Whether the note subject code, when present, is coded using UNTDID 4451, used by BR-CL-08.
874
+ *
875
+ * @example
876
+ * ```ts
877
+ * noteSubjectCodeIsUncl4451(document); // true
878
+ * ```;
879
+ *
880
+ * @param document - The document whose note is read.
881
+ *
882
+ * @returns `true` when the note has no subject code, or the subject code is a UNTDID 4451 charge reason code, otherwise `false`.
490
883
  */
491
884
  export function noteSubjectCodeIsUncl4451(document: PeppolDocument): boolean {
492
885
  const note = document.note;
@@ -502,6 +895,15 @@ export function noteSubjectCodeIsUncl4451(document: PeppolDocument): boolean {
502
895
 
503
896
  /**
504
897
  * @description Total number of VAT breakdown groups (BG-23) present on the document.
898
+ *
899
+ * @example
900
+ * ```ts
901
+ * countAllVatBreakdowns(document); // 1
902
+ * ```;
903
+ *
904
+ * @param document - The document whose VAT breakdown groups (BG-23) are counted.
905
+ *
906
+ * @returns The total number of VAT breakdown groups.
505
907
  */
506
908
  export function countAllVatBreakdowns(document: PeppolDocument): number {
507
909
  return document.taxTotals.reduce((count, total) => count + (total.taxSubtotals?.length ?? 0), 0);
@@ -509,6 +911,16 @@ export function countAllVatBreakdowns(document: PeppolDocument): number {
509
911
 
510
912
  /**
511
913
  * @description Whether the document contains a VAT category code (BT-151, BT-95, BT-102) or a VAT breakdown category code (BT-118) equal to `code`.
914
+ *
915
+ * @example
916
+ * ```ts
917
+ * hasAnyVatCategoryCode(document, 'S'); // true
918
+ * ```;
919
+ *
920
+ * @param document - The document whose VAT categories and breakdowns are read.
921
+ * @param code - The VAT category code to look for.
922
+ *
923
+ * @returns `true` when the code appears on a line, an allowance/charge or a VAT breakdown group, otherwise `false`.
512
924
  */
513
925
  export function hasAnyVatCategoryCode(document: PeppolDocument, code: string): boolean {
514
926
  return countVatCategoryCode(document, code) > 0 || countVatBreakdownCode(document, code) > 0;
@@ -516,6 +928,16 @@ export function hasAnyVatCategoryCode(document: PeppolDocument, code: string): b
516
928
 
517
929
  /**
518
930
  * @description Whether `a` and `b` are within 1 of each other, mirroring the schematron slack used by BR-S-08, BR-AF-08 and BR-AG-08.
931
+ *
932
+ * @example
933
+ * ```ts
934
+ * withinSlackOne(100, 100.5); // true
935
+ * ```;
936
+ *
937
+ * @param a - The first value.
938
+ * @param b - The second value.
939
+ *
940
+ * @returns `true` when the two values differ by less than `1`, otherwise `false`.
519
941
  */
520
942
  export function withinSlackOne(a: number, b: number): boolean {
521
943
  return Math.abs(a - b) < 1;
@@ -524,6 +946,16 @@ export function withinSlackOne(a: number, b: number): boolean {
524
946
  /**
525
947
  * @description Whether the VAT category tax amount (BT-117) equals the VAT category taxable amount (BT-116) multiplied by the VAT category rate (BT-119), allowing
526
948
  * for a slack of 1, mirroring BR-CO-17.
949
+ *
950
+ * @example
951
+ * ```ts
952
+ * vatCategoryTaxAmountMatchesRate(subtotal); // true
953
+ * ```;
954
+ *
955
+ * @param subtotal - The VAT breakdown group (BG-23) whose tax amount and rate are compared.
956
+ *
957
+ * @returns `true` when the tax amount (BT-117) matches the taxable amount (BT-116) times the rate (BT-119), or when both are zero for a missing or
958
+ * zero rate; otherwise `false`.
527
959
  */
528
960
  export function vatCategoryTaxAmountMatchesRate(subtotal: PeppolTaxSubTotal): boolean {
529
961
  const percent = subtotal.taxCategory.percent;
@@ -542,6 +974,16 @@ export function vatCategoryTaxAmountMatchesRate(subtotal: PeppolTaxSubTotal): bo
542
974
  * @description Whether every VAT breakdown (BG-23) whose VAT category code (BT-118) is "Standard rated", "IGIC" or "IPSI" has a VAT category taxable amount
543
975
  * (BT-116) that equals the sum of invoice line net amounts (BT-131) plus document level charge amounts (BT-99) minus document level allowance amounts
544
976
  * (BT-92) at the same VAT rate, allowing a slack of 1, mirroring BR-S-08, BR-AF-08 and BR-AG-08.
977
+ *
978
+ * @example
979
+ * ```ts
980
+ * everyVatBreakdownTaxableMatchesRateSum(document); // true
981
+ * ```;
982
+ *
983
+ * @param document - The document whose VAT breakdown groups are checked.
984
+ *
985
+ * @returns `true` when every standard rated, IGIC or IPSI breakdown matches the summed line and allowance/charge amounts at its rate, otherwise
986
+ * `false`.
545
987
  */
546
988
  export function everyVatBreakdownTaxableMatchesRateSum(document: PeppolDocument): boolean {
547
989
  for (const total of document.taxTotals) {
@@ -564,6 +1006,15 @@ export function everyVatBreakdownTaxableMatchesRateSum(document: PeppolDocument)
564
1006
 
565
1007
  /**
566
1008
  * @description Returns all identifiers carrying a scheme identifier, used by the PEPPOL-COMMON-R* rules.
1009
+ *
1010
+ * @example
1011
+ * ```ts
1012
+ * getIdentifiersWithSchemeId(document); // [{ id: '00743110157', schemeId: '0088' }]
1013
+ * ```;
1014
+ *
1015
+ * @param document - The document whose supplier, customer and payee identifiers are read.
1016
+ *
1017
+ * @returns Every identifier that carries both an `id` and a `schemeId`, in supplier, customer then payee order.
567
1018
  */
568
1019
  export function getIdentifiersWithSchemeId(document: PeppolDocument): Array<{ id: string; schemeId: string }> {
569
1020
  const candidates: Array<{ id: string | undefined; schemeId: string | undefined }> = [];