@stackforge-eu/factur-x 1.0.8 → 1.2.0
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.
- package/CHANGELOG.md +72 -0
- package/README.md +3 -3
- package/dist/index.cjs +49 -12
- package/dist/index.d.cts +83 -6
- package/dist/index.d.ts +83 -6
- package/dist/index.js +49 -12
- package/package.json +1 -1
- package/schema/README.md +18 -5
- package/schema/extended/FACTUR-X_EXTENDED_QualifiedDataType_100.xsd +3 -1
- package/schema/extended/FACTUR-X_EXTENDED_ReusableAggregateBusinessInformationEntity_100.xsd +19 -4
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,76 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.2.0] — 2026-07-11
|
|
11
|
+
|
|
12
|
+
- **Updated to Factur-X 1.09 / ZUGFeRD 2.5** (spec dated 2026-06-10). Factur-X
|
|
13
|
+
1.09 keeps the same UN/CEFACT CII **D22B** syntax, namespaces, and profile URNs
|
|
14
|
+
(`urn:factur-x.eu:1p0:*`) as 1.08, so this is a backward-compatible refresh:
|
|
15
|
+
XML produced by previous versions remains valid, and no input/output changes
|
|
16
|
+
are required.
|
|
17
|
+
- Bundled XSD schemas under `schema/` swapped to the official 1.09 set
|
|
18
|
+
(filenames normalized to the repo convention, internal `schemaLocation`
|
|
19
|
+
references rewritten to match). For MINIMUM / BASIC WL / BASIC / EN 16931 the
|
|
20
|
+
XSDs are content-identical to 1.08; the EXTENDED XSD gains only **optional**
|
|
21
|
+
additions (debited-account name, financial adjustment / charges on behalf of
|
|
22
|
+
a third party, an optional `listID` attribute on the allowance/charge reason
|
|
23
|
+
code).
|
|
24
|
+
- Reference `.sch` (Schematron) and `_codedb.xml` files updated to the 1.09
|
|
25
|
+
code lists and CEN validation rules (effective 2026-05-15). These are not
|
|
26
|
+
shipped in the npm package and not used at runtime — this library performs
|
|
27
|
+
XSD validation only.
|
|
28
|
+
- Documentation and code comments updated from "1.08 / 2.4" to "1.09 / 2.5".
|
|
29
|
+
|
|
30
|
+
- **New optional EXTENDED-profile input fields** for selected Factur-X 1.09
|
|
31
|
+
business terms (all additive, only emitted at `Profile.EXTENDED`):
|
|
32
|
+
- `PaymentInput.debtorAccountName` (BT-216) and `PaymentInput.debtorBic`
|
|
33
|
+
(BT-215) — debited-account name and its payment service provider BIC.
|
|
34
|
+
- `AllowanceChargeInput.exemptionReason` / `exemptionReasonCode`
|
|
35
|
+
(BT-173–176) — VAT exemption reason/code on document-level allowances and
|
|
36
|
+
charges.
|
|
37
|
+
- `FacturXInvoiceInput.financialAdjustments` (BG-34, new
|
|
38
|
+
`FinancialAdjustmentInput` with `reason` BT-180 + `amount` BT-179) —
|
|
39
|
+
charges collected on behalf of a third party.
|
|
40
|
+
- `InvoiceLineInput.manufacturer` (BG-X-94) — line-level product manufacturer
|
|
41
|
+
party (`ram:ManufacturerTradeParty`).
|
|
42
|
+
- Remaining 1.09 EXTENDED terms (e.g. document-level non-VAT tax codes,
|
|
43
|
+
logistic-service-charge exemption reasons) are still not emitted and can be
|
|
44
|
+
added later without breaking changes.
|
|
45
|
+
|
|
46
|
+
- **Fixed:** `ram:FormattedIssueDateTime` now emits a `qdt:DateTimeString` child
|
|
47
|
+
instead of `udt:DateTimeString`. It is typed as `qdt:FormattedDateTimeType` in
|
|
48
|
+
the CII XSD, so the previous `udt:` prefix failed XSD/Schematron validation for
|
|
49
|
+
every credit note or cancellation invoice referencing a dated preceding
|
|
50
|
+
invoice ([#5](https://github.com/StackForge-EU/factur-x/issues/5)).
|
|
51
|
+
- **Fixed:** XSD validation no longer exhausts libxml2's fixed-size input-callback
|
|
52
|
+
table. `validateXsd` now clears the table on each call, so validating many
|
|
53
|
+
documents in one process no longer causes spurious failures once ~15
|
|
54
|
+
validations have run.
|
|
55
|
+
|
|
56
|
+
## [1.1.0] — 2026-05-27
|
|
57
|
+
|
|
58
|
+
- **BREAKING:** Every `ram:GlobalID` and the legal-organization `ram:ID` now
|
|
59
|
+
carry the `@schemeID` attribute required by EN 16931. The XSD-canonical CII
|
|
60
|
+
mapping makes the scheme mandatory on `ram:GlobalID` (BT-29-1 / BT-46-1 for
|
|
61
|
+
parties, BT-157-1 for line items) and conditional on
|
|
62
|
+
`ram:SpecifiedLegalOrganization/ram:ID` (BT-30-1 / BT-47-1); without these
|
|
63
|
+
attributes Mustang / KoSIT / veraPDF's Factur-X profile reject the invoice
|
|
64
|
+
even though the embedded CII looked superficially correct. Three input
|
|
65
|
+
fields changed:
|
|
66
|
+
- `TradePartyInput.globalId` is now `IdentifierWithSchemeInput`
|
|
67
|
+
(`{ value: string; schemeID: string }`) instead of a bare `string`
|
|
68
|
+
- `InvoiceLineInput.standardIdentifier` is now `IdentifierWithSchemeInput`
|
|
69
|
+
instead of a bare `string` (sibling fix on top of #4 — the line-item
|
|
70
|
+
`ram:GlobalID` had the same defect as the party one)
|
|
71
|
+
- `LegalOrganizationInput.schemeID?: string` added (optional, mirrors the
|
|
72
|
+
conditional spec rule)
|
|
73
|
+
Migration: `globalId: "4000001000005"` →
|
|
74
|
+
`globalId: { value: "4000001000005", schemeID: "0088" }` (and the analogous
|
|
75
|
+
rewrite for `standardIdentifier`). The new `IdentifierWithSchemeInput` type
|
|
76
|
+
is exported from `src/index.ts`. Regression test added in
|
|
77
|
+
`tests/xsd-validator.test.ts` that drives all three schemed identifiers
|
|
78
|
+
through the EN16931 XSD in one go (thanks @sco-indy, #4).
|
|
79
|
+
|
|
10
80
|
## [1.0.8] — 2026-05-27
|
|
11
81
|
|
|
12
82
|
- **PDF trailer was missing the `/ID` entry required by PDF/A-3.** ISO 19005-3
|
|
@@ -129,6 +199,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
129
199
|
- Deno compatibility test suite
|
|
130
200
|
|
|
131
201
|
[Unreleased]: https://github.com/StackForge-EU/factur-x/commits/main
|
|
202
|
+
[1.2.0]: https://github.com/StackForge-EU/factur-x/compare/v1.1.0...v1.2.0
|
|
203
|
+
[1.1.0]: https://github.com/StackForge-EU/factur-x/compare/v1.0.8...v1.1.0
|
|
132
204
|
[1.0.8]: https://github.com/StackForge-EU/factur-x/compare/v1.0.7...v1.0.8
|
|
133
205
|
[1.0.7]: https://github.com/StackForge-EU/factur-x/compare/v1.0.6...v1.0.7
|
|
134
206
|
[1.0.6]: https://github.com/StackForge-EU/factur-x/compare/v1.0.5...v1.0.6
|
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
This TypeScript/Node.js package takes a simple, typed invoice input object and:
|
|
14
14
|
|
|
15
15
|
1. Validates it against profile requirements
|
|
16
|
-
2. Generates UN/CEFACT CII XML (Factur-X 1.
|
|
16
|
+
2. Generates UN/CEFACT CII XML (Factur-X 1.09 / ZUGFeRD 2.5)
|
|
17
17
|
3. Validates the XML against official XSD schemas (via WASM)
|
|
18
18
|
4. Embeds it into a PDF with PDF/A-3b metadata
|
|
19
19
|
5. Or outputs standalone XRechnung XML for German B2G use
|
|
@@ -68,8 +68,8 @@ import { embedFacturX, Profile } from "jsr:@stackforge-eu/factur-x";
|
|
|
68
68
|
|
|
69
69
|
| Flavor | Region | Output | Notes |
|
|
70
70
|
| ------------------- | ----------- | -------- | ----------------------------- |
|
|
71
|
-
| `Flavor.FACTUR_X` | France / EU | PDF/A-3 | Default, Factur-X 1.
|
|
72
|
-
| `Flavor.ZUGFERD` | Germany | PDF/A-3 | ZUGFeRD 2.
|
|
71
|
+
| `Flavor.FACTUR_X` | France / EU | PDF/A-3 | Default, Factur-X 1.09 |
|
|
72
|
+
| `Flavor.ZUGFERD` | Germany | PDF/A-3 | ZUGFeRD 2.5 (= Factur-X 1.09) |
|
|
73
73
|
| `Flavor.XRECHNUNG` | Germany B2G | XML only | PEPPOL business process |
|
|
74
74
|
| `Flavor.CHRONO_PRO` | Belgium | PDF/A-3 | Chrono Pro conventions |
|
|
75
75
|
|
package/dist/index.cjs
CHANGED
|
@@ -235,7 +235,7 @@ var FLAVOR_CONFIGS = {
|
|
|
235
235
|
defaultTypeCode: "380" /* COMMERCIAL_INVOICE */,
|
|
236
236
|
attachmentFilename: "factur-x.xml",
|
|
237
237
|
embedInPdf: true,
|
|
238
|
-
description: "German electronic invoice format. ZUGFeRD 2.
|
|
238
|
+
description: "German electronic invoice format. ZUGFeRD 2.5 uses factur-x.xml."
|
|
239
239
|
},
|
|
240
240
|
["xrechnung" /* XRECHNUNG */]: {
|
|
241
241
|
name: "XRechnung",
|
|
@@ -312,7 +312,8 @@ function tag(name, content, attrs) {
|
|
|
312
312
|
return `<${name}${a}>${content}</${name}>`;
|
|
313
313
|
}
|
|
314
314
|
function dateEl(wrapper, isoDate) {
|
|
315
|
-
|
|
315
|
+
const child = wrapper === "ram:FormattedIssueDateTime" ? "qdt:DateTimeString" : "udt:DateTimeString";
|
|
316
|
+
return tag(wrapper, tag(child, formatDate(isoDate), { format: "102" }));
|
|
316
317
|
}
|
|
317
318
|
function buildAddress(addr) {
|
|
318
319
|
let x = "";
|
|
@@ -340,13 +341,21 @@ function buildParty(p, profile) {
|
|
|
340
341
|
const ids = Array.isArray(p.id) ? p.id : [p.id];
|
|
341
342
|
for (const id of ids) x += tag("ram:ID", escapeXml(id));
|
|
342
343
|
}
|
|
343
|
-
if (p.globalId)
|
|
344
|
+
if (p.globalId) {
|
|
345
|
+
x += tag("ram:GlobalID", escapeXml(p.globalId.value), { schemeID: p.globalId.schemeID });
|
|
346
|
+
}
|
|
344
347
|
x += tag("ram:Name", escapeXml(p.name));
|
|
345
348
|
if (p.description && atLeast(profile, "EN16931" /* EN16931 */))
|
|
346
349
|
x += tag("ram:Description", escapeXml(p.description));
|
|
347
350
|
if (p.legalOrganization) {
|
|
348
351
|
let lo = "";
|
|
349
|
-
if (p.legalOrganization.id)
|
|
352
|
+
if (p.legalOrganization.id) {
|
|
353
|
+
lo += tag(
|
|
354
|
+
"ram:ID",
|
|
355
|
+
escapeXml(p.legalOrganization.id),
|
|
356
|
+
p.legalOrganization.schemeID ? { schemeID: p.legalOrganization.schemeID } : void 0
|
|
357
|
+
);
|
|
358
|
+
}
|
|
350
359
|
if (p.legalOrganization.tradingName)
|
|
351
360
|
lo += tag("ram:TradingBusinessName", escapeXml(p.legalOrganization.tradingName));
|
|
352
361
|
x += tag("ram:SpecifiedLegalOrganization", lo);
|
|
@@ -374,13 +383,19 @@ function buildLineItem(line, profile) {
|
|
|
374
383
|
let doc = tag("ram:LineID", escapeXml(line.id));
|
|
375
384
|
if (line.note) doc += tag("ram:IncludedNote", tag("ram:Content", escapeXml(line.note)));
|
|
376
385
|
let prod = "";
|
|
377
|
-
if (line.standardIdentifier)
|
|
386
|
+
if (line.standardIdentifier) {
|
|
387
|
+
prod += tag("ram:GlobalID", escapeXml(line.standardIdentifier.value), {
|
|
388
|
+
schemeID: line.standardIdentifier.schemeID
|
|
389
|
+
});
|
|
390
|
+
}
|
|
378
391
|
if (line.sellerAssignedId) prod += tag("ram:SellerAssignedID", escapeXml(line.sellerAssignedId));
|
|
379
392
|
if (line.buyerAssignedId) prod += tag("ram:BuyerAssignedID", escapeXml(line.buyerAssignedId));
|
|
380
393
|
prod += tag("ram:Name", escapeXml(line.name));
|
|
381
394
|
if (line.description) prod += tag("ram:Description", escapeXml(line.description));
|
|
382
395
|
if (line.originCountry && atLeast(profile, "EN16931" /* EN16931 */))
|
|
383
396
|
prod += tag("ram:OriginTradeCountry", tag("ram:ID", escapeXml(line.originCountry)));
|
|
397
|
+
if (line.manufacturer && atLeast(profile, "EXTENDED" /* EXTENDED */))
|
|
398
|
+
prod += tag("ram:ManufacturerTradeParty", buildParty(line.manufacturer, profile));
|
|
384
399
|
let agree = "";
|
|
385
400
|
if (line.buyerOrderLineId && atLeast(profile, "EN16931" /* EN16931 */))
|
|
386
401
|
agree += tag(
|
|
@@ -415,7 +430,7 @@ function buildLineItem(line, profile) {
|
|
|
415
430
|
tag("ram:AssociatedDocumentLineDocument", doc) + tag("ram:SpecifiedTradeProduct", prod) + tag("ram:SpecifiedLineTradeAgreement", agree) + tag("ram:SpecifiedLineTradeDelivery", delivery) + tag("ram:SpecifiedLineTradeSettlement", settle)
|
|
416
431
|
);
|
|
417
432
|
}
|
|
418
|
-
function buildAllowanceCharge(ac) {
|
|
433
|
+
function buildAllowanceCharge(ac, profile) {
|
|
419
434
|
let x = tag("ram:ChargeIndicator", tag("udt:Indicator", ac.isCharge ? "true" : "false"));
|
|
420
435
|
if (ac.percent !== void 0) x += tag("ram:CalculationPercent", ac.percent.toString());
|
|
421
436
|
if (ac.baseAmount !== void 0) x += tag("ram:BasisAmount", fmtAmt(ac.baseAmount));
|
|
@@ -423,8 +438,13 @@ function buildAllowanceCharge(ac) {
|
|
|
423
438
|
if (ac.reasonCode) x += tag("ram:ReasonCode", escapeXml(ac.reasonCode));
|
|
424
439
|
if (ac.reason) x += tag("ram:Reason", escapeXml(ac.reason));
|
|
425
440
|
if (ac.vatCategoryCode || ac.vatRatePercent !== void 0) {
|
|
441
|
+
const extended = atLeast(profile, "EXTENDED" /* EXTENDED */);
|
|
426
442
|
let tx = tag("ram:TypeCode", "VAT");
|
|
443
|
+
if (extended && ac.exemptionReason)
|
|
444
|
+
tx += tag("ram:ExemptionReason", escapeXml(ac.exemptionReason));
|
|
427
445
|
if (ac.vatCategoryCode) tx += tag("ram:CategoryCode", escapeXml(ac.vatCategoryCode));
|
|
446
|
+
if (extended && ac.exemptionReasonCode)
|
|
447
|
+
tx += tag("ram:ExemptionReasonCode", escapeXml(ac.exemptionReasonCode));
|
|
428
448
|
if (ac.vatRatePercent !== void 0)
|
|
429
449
|
tx += tag("ram:RateApplicablePercent", ac.vatRatePercent.toString());
|
|
430
450
|
x += tag("ram:CategoryTradeTax", tx);
|
|
@@ -592,11 +612,12 @@ function buildXml(input, profile, flavor) {
|
|
|
592
612
|
sett += tag("ram:PayeeTradeParty", buildParty(input.payee, profile));
|
|
593
613
|
if (payment?.meansCode && atLeast(profile, "BASIC_WL" /* BASIC_WL */)) {
|
|
594
614
|
let pm = tag("ram:TypeCode", escapeXml(payment.meansCode));
|
|
595
|
-
if (payment.debtorIban)
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
tag("ram:
|
|
599
|
-
);
|
|
615
|
+
if (payment.debtorIban) {
|
|
616
|
+
let dacct = tag("ram:IBANID", escapeXml(payment.debtorIban));
|
|
617
|
+
if (payment.debtorAccountName && atLeast(profile, "EXTENDED" /* EXTENDED */))
|
|
618
|
+
dacct += tag("ram:AccountName", escapeXml(payment.debtorAccountName));
|
|
619
|
+
pm += tag("ram:PayerPartyDebtorFinancialAccount", dacct);
|
|
620
|
+
}
|
|
600
621
|
if (payment.iban || payment.accountId || payment.accountName) {
|
|
601
622
|
let acct = "";
|
|
602
623
|
if (payment.iban) acct += tag("ram:IBANID", escapeXml(payment.iban));
|
|
@@ -605,6 +626,11 @@ function buildXml(input, profile, flavor) {
|
|
|
605
626
|
acct += tag("ram:AccountName", escapeXml(payment.accountName));
|
|
606
627
|
pm += tag("ram:PayeePartyCreditorFinancialAccount", acct);
|
|
607
628
|
}
|
|
629
|
+
if (payment.debtorBic && atLeast(profile, "EXTENDED" /* EXTENDED */))
|
|
630
|
+
pm += tag(
|
|
631
|
+
"ram:PayerSpecifiedDebtorFinancialInstitution",
|
|
632
|
+
tag("ram:BICID", escapeXml(payment.debtorBic))
|
|
633
|
+
);
|
|
608
634
|
if (payment.bic && atLeast(profile, "EN16931" /* EN16931 */))
|
|
609
635
|
pm += tag(
|
|
610
636
|
"ram:PayeeSpecifiedCreditorFinancialInstitution",
|
|
@@ -622,7 +648,7 @@ function buildXml(input, profile, flavor) {
|
|
|
622
648
|
sett += tag("ram:BillingSpecifiedPeriod", bp);
|
|
623
649
|
}
|
|
624
650
|
if (input.allowancesCharges && atLeast(profile, "BASIC_WL" /* BASIC_WL */))
|
|
625
|
-
for (const ac of input.allowancesCharges) sett += buildAllowanceCharge(ac);
|
|
651
|
+
for (const ac of input.allowancesCharges) sett += buildAllowanceCharge(ac, profile);
|
|
626
652
|
const dueDate = payment?.dueDate ?? doc.dueDate;
|
|
627
653
|
if (atLeast(profile, "BASIC_WL" /* BASIC_WL */) && (payment?.termsDescription || dueDate || payment?.mandateId)) {
|
|
628
654
|
let pt = "";
|
|
@@ -633,6 +659,14 @@ function buildXml(input, profile, flavor) {
|
|
|
633
659
|
sett += tag("ram:SpecifiedTradePaymentTerms", pt);
|
|
634
660
|
}
|
|
635
661
|
sett += buildMonetarySummation(totals, profile);
|
|
662
|
+
if (input.financialAdjustments && atLeast(profile, "EXTENDED" /* EXTENDED */)) {
|
|
663
|
+
for (const fa of input.financialAdjustments) {
|
|
664
|
+
sett += tag(
|
|
665
|
+
"ram:SpecifiedFinancialAdjustment",
|
|
666
|
+
tag("ram:Reason", escapeXml(fa.reason)) + tag("ram:ActualAmount", fmtAmt(fa.amount))
|
|
667
|
+
);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
636
670
|
if (input.references && atLeast(profile, "BASIC_WL" /* BASIC_WL */)) {
|
|
637
671
|
for (const ref of input.references) {
|
|
638
672
|
if (ref.type === "preceding") {
|
|
@@ -1065,6 +1099,7 @@ async function validateXsd(xml, profile, options) {
|
|
|
1065
1099
|
XsdValidator,
|
|
1066
1100
|
XmlValidateError,
|
|
1067
1101
|
xmlRegisterInputProvider,
|
|
1102
|
+
xmlCleanupInputProvider,
|
|
1068
1103
|
XmlBufferInputProvider
|
|
1069
1104
|
} = await import('libxml2-wasm');
|
|
1070
1105
|
const schemaDir = path__namespace.dirname(xsdPath);
|
|
@@ -1076,6 +1111,7 @@ async function validateXsd(xml, profile, options) {
|
|
|
1076
1111
|
buffers[`file://${filePath}`] = buffers[filePath];
|
|
1077
1112
|
buffers[file] = buffers[filePath];
|
|
1078
1113
|
}
|
|
1114
|
+
xmlCleanupInputProvider();
|
|
1079
1115
|
const provider = new XmlBufferInputProvider(buffers);
|
|
1080
1116
|
xmlRegisterInputProvider(provider);
|
|
1081
1117
|
let xsdDoc;
|
|
@@ -1105,6 +1141,7 @@ async function validateXsd(xml, profile, options) {
|
|
|
1105
1141
|
xmlDoc?.dispose();
|
|
1106
1142
|
validator?.dispose();
|
|
1107
1143
|
xsdDoc?.dispose();
|
|
1144
|
+
xmlCleanupInputProvider();
|
|
1108
1145
|
}
|
|
1109
1146
|
}
|
|
1110
1147
|
var AF_RELATIONSHIP_MAP = {
|
package/dist/index.d.cts
CHANGED
|
@@ -448,9 +448,18 @@ interface TaxRegistrationInput {
|
|
|
448
448
|
interface LegalOrganizationInput {
|
|
449
449
|
/** Registration identifier */
|
|
450
450
|
id?: string;
|
|
451
|
+
/** Registration identifier scheme (ICD code list value, e.g. `"0002"` for SIRENE) */
|
|
452
|
+
schemeID?: string;
|
|
451
453
|
/** Trading business name */
|
|
452
454
|
tradingName?: string;
|
|
453
455
|
}
|
|
456
|
+
/**
|
|
457
|
+
* Identifier value with its scheme identifier.
|
|
458
|
+
*/
|
|
459
|
+
interface IdentifierWithSchemeInput {
|
|
460
|
+
value: string;
|
|
461
|
+
schemeID: string;
|
|
462
|
+
}
|
|
454
463
|
/**
|
|
455
464
|
* Trade party (seller, buyer, payee, etc.).
|
|
456
465
|
*
|
|
@@ -468,10 +477,14 @@ interface TradePartyInput {
|
|
|
468
477
|
*/
|
|
469
478
|
id?: string | string[];
|
|
470
479
|
/**
|
|
471
|
-
* Global identifier with scheme (e.g. GLN `"
|
|
480
|
+
* Global identifier with scheme (e.g. GLN value `"4000001000005"` and
|
|
481
|
+
* ICD scheme `"0088"`).
|
|
482
|
+
*
|
|
483
|
+
* `schemeID` is required by EN 16931 for `ram:GlobalID`.
|
|
484
|
+
*
|
|
472
485
|
* @see EN 16931 BT-29-1 / BT-46-1
|
|
473
486
|
*/
|
|
474
|
-
globalId?:
|
|
487
|
+
globalId?: IdentifierWithSchemeInput;
|
|
475
488
|
/** Postal address — mandatory for BASIC_WL and above */
|
|
476
489
|
address?: AddressInput;
|
|
477
490
|
/**
|
|
@@ -581,10 +594,14 @@ interface InvoiceLineInput {
|
|
|
581
594
|
*/
|
|
582
595
|
description?: string;
|
|
583
596
|
/**
|
|
584
|
-
* Item standard identifier (e.g. GTIN
|
|
597
|
+
* Item standard identifier (e.g. GTIN value `"4012345678901"` and ICD
|
|
598
|
+
* scheme `"0160"` for GS1).
|
|
599
|
+
*
|
|
600
|
+
* `schemeID` is required by EN 16931 for `ram:GlobalID` (BT-157-1).
|
|
601
|
+
*
|
|
585
602
|
* @see EN 16931 BT-157
|
|
586
603
|
*/
|
|
587
|
-
standardIdentifier?:
|
|
604
|
+
standardIdentifier?: IdentifierWithSchemeInput;
|
|
588
605
|
/**
|
|
589
606
|
* Seller-assigned item identifier.
|
|
590
607
|
* @see EN 16931 BT-155
|
|
@@ -616,6 +633,14 @@ interface InvoiceLineInput {
|
|
|
616
633
|
* @since EN16931
|
|
617
634
|
*/
|
|
618
635
|
buyerOrderLineId?: string;
|
|
636
|
+
/**
|
|
637
|
+
* Product manufacturer of this line item. Uses the standard trade-party
|
|
638
|
+
* shape; only id/globalId (BT-X-600), name (BT-X-598), and postal address
|
|
639
|
+
* (BG-X-93) are typically relevant.
|
|
640
|
+
* @see Factur-X EXTENDED BG-X-94, Factur-X 1.09
|
|
641
|
+
* @since EXTENDED
|
|
642
|
+
*/
|
|
643
|
+
manufacturer?: TradePartyInput;
|
|
619
644
|
}
|
|
620
645
|
/**
|
|
621
646
|
* Allowance or charge at header or line level.
|
|
@@ -649,6 +674,18 @@ interface AllowanceChargeInput {
|
|
|
649
674
|
vatCategoryCode?: VatCategoryCode | (string & Record<never, never>);
|
|
650
675
|
/** VAT rate for this allowance/charge */
|
|
651
676
|
vatRatePercent?: number;
|
|
677
|
+
/**
|
|
678
|
+
* VAT exemption reason text for this document-level allowance/charge.
|
|
679
|
+
* @see Factur-X EXTENDED BT-173 (allowance) / BT-175 (charge), Factur-X 1.09
|
|
680
|
+
* @since EXTENDED
|
|
681
|
+
*/
|
|
682
|
+
exemptionReason?: string;
|
|
683
|
+
/**
|
|
684
|
+
* VAT exemption reason code for this document-level allowance/charge.
|
|
685
|
+
* @see Factur-X EXTENDED BT-174 (allowance) / BT-176 (charge), Factur-X 1.09
|
|
686
|
+
* @since EXTENDED
|
|
687
|
+
*/
|
|
688
|
+
exemptionReasonCode?: string;
|
|
652
689
|
}
|
|
653
690
|
/**
|
|
654
691
|
* Payment information.
|
|
@@ -709,6 +746,22 @@ interface PaymentInput {
|
|
|
709
746
|
* @see EN 16931 BT-91
|
|
710
747
|
*/
|
|
711
748
|
debtorIban?: string;
|
|
749
|
+
/**
|
|
750
|
+
* Debtor account name (holder of the debited account). Only emitted when
|
|
751
|
+
* {@link PaymentInput.debtorIban} is also set, since the CII schema requires
|
|
752
|
+
* the IBAN on the debtor account element.
|
|
753
|
+
* @see Factur-X EXTENDED BT-216 ("Debited account name", Factur-X 1.09)
|
|
754
|
+
* @since EXTENDED
|
|
755
|
+
*/
|
|
756
|
+
debtorAccountName?: string;
|
|
757
|
+
/**
|
|
758
|
+
* BIC/SWIFT of the debtor's payment service provider (the debited account's
|
|
759
|
+
* financial institution).
|
|
760
|
+
* @see Factur-X EXTENDED BT-215 ("Debited account payment service provider
|
|
761
|
+
* identifier", Factur-X 1.09)
|
|
762
|
+
* @since EXTENDED
|
|
763
|
+
*/
|
|
764
|
+
debtorBic?: string;
|
|
712
765
|
/**
|
|
713
766
|
* Payment terms description (free text).
|
|
714
767
|
* @see EN 16931 BT-20
|
|
@@ -957,6 +1010,30 @@ interface FacturXInvoiceInput {
|
|
|
957
1010
|
* @since BASIC_WL
|
|
958
1011
|
*/
|
|
959
1012
|
sellerTaxRepresentative?: TradePartyInput;
|
|
1013
|
+
/**
|
|
1014
|
+
* Charges collected on behalf of a third party (document level).
|
|
1015
|
+
* @see Factur-X EXTENDED BG-34, Factur-X 1.09
|
|
1016
|
+
* @since EXTENDED
|
|
1017
|
+
*/
|
|
1018
|
+
financialAdjustments?: FinancialAdjustmentInput[];
|
|
1019
|
+
}
|
|
1020
|
+
/**
|
|
1021
|
+
* A charge collected on behalf of a third party.
|
|
1022
|
+
*
|
|
1023
|
+
* @see Factur-X EXTENDED BG-34 (`ram:SpecifiedFinancialAdjustment`), Factur-X 1.09
|
|
1024
|
+
* @since EXTENDED
|
|
1025
|
+
*/
|
|
1026
|
+
interface FinancialAdjustmentInput {
|
|
1027
|
+
/**
|
|
1028
|
+
* Specification of the charge collected on behalf of a third party.
|
|
1029
|
+
* @see Factur-X EXTENDED BT-180
|
|
1030
|
+
*/
|
|
1031
|
+
reason: string;
|
|
1032
|
+
/**
|
|
1033
|
+
* Charge amount collected on behalf of a third party.
|
|
1034
|
+
* @see Factur-X EXTENDED BT-179
|
|
1035
|
+
*/
|
|
1036
|
+
amount: number;
|
|
960
1037
|
}
|
|
961
1038
|
|
|
962
1039
|
/**
|
|
@@ -1077,7 +1154,7 @@ declare function escapeXml(value: string): string;
|
|
|
1077
1154
|
/**
|
|
1078
1155
|
* Builds a UN/CEFACT CrossIndustryInvoice XML string from structured input.
|
|
1079
1156
|
*
|
|
1080
|
-
* The output conforms to the Factur-X 1.
|
|
1157
|
+
* The output conforms to the Factur-X 1.09 / ZUGFeRD 2.5 CII schema at the
|
|
1081
1158
|
* requested {@link Profile} level. Elements that do not belong to the chosen
|
|
1082
1159
|
* profile are silently omitted.
|
|
1083
1160
|
*
|
|
@@ -1435,4 +1512,4 @@ interface XRechnungResult {
|
|
|
1435
1512
|
*/
|
|
1436
1513
|
declare function toXRechnung(input: FacturXInvoiceInput, options?: XRechnungOptions): XRechnungResult;
|
|
1437
1514
|
|
|
1438
|
-
export { type AddressInput, type AllowanceChargeInput, type BillingPeriodInput, type ContactInput, type DeliveryInput, type DocumentReferenceInput, DocumentTypeCode, type EmbedOptions, type EmbedResult, type ExtractOptions, type ExtractResult, FLAVOR_CONFIGS, FLAVOR_DEFAULT_TYPE_CODES, type FacturXInvoiceInput, Flavor, type FlavorConfig, type InvoiceDocumentInput, type InvoiceLineInput, type InvoiceTotalsInput, type LegalOrganizationInput, type NoteInput, PROFILE_MAIN_XSD, PROFILE_SCHEMA_DIRS, PROFILE_URNS, type PaymentInput, Profile, type TaxRegistrationInput, type TradePartyInput, UnitCode, type ValidationError, type ValidationResult, type VatBreakdownInput, VatCategoryCode, XRECHNUNG_PROFILE_URN, type XRechnungOptions, type XRechnungResult, type XsdValidateOptions, type XsdValidationError, type XsdValidationResult, buildXml, embedFacturX, escapeXml, extractXml, getFlavorConfig, resolveBusinessProcessUrn, resolveTypeCode, toXRechnung, validateFlavorProfile, validateInput, validateXsd };
|
|
1515
|
+
export { type AddressInput, type AllowanceChargeInput, type BillingPeriodInput, type ContactInput, type DeliveryInput, type DocumentReferenceInput, DocumentTypeCode, type EmbedOptions, type EmbedResult, type ExtractOptions, type ExtractResult, FLAVOR_CONFIGS, FLAVOR_DEFAULT_TYPE_CODES, type FacturXInvoiceInput, type FinancialAdjustmentInput, Flavor, type FlavorConfig, type IdentifierWithSchemeInput, type InvoiceDocumentInput, type InvoiceLineInput, type InvoiceTotalsInput, type LegalOrganizationInput, type NoteInput, PROFILE_MAIN_XSD, PROFILE_SCHEMA_DIRS, PROFILE_URNS, type PaymentInput, Profile, type TaxRegistrationInput, type TradePartyInput, UnitCode, type ValidationError, type ValidationResult, type VatBreakdownInput, VatCategoryCode, XRECHNUNG_PROFILE_URN, type XRechnungOptions, type XRechnungResult, type XsdValidateOptions, type XsdValidationError, type XsdValidationResult, buildXml, embedFacturX, escapeXml, extractXml, getFlavorConfig, resolveBusinessProcessUrn, resolveTypeCode, toXRechnung, validateFlavorProfile, validateInput, validateXsd };
|
package/dist/index.d.ts
CHANGED
|
@@ -448,9 +448,18 @@ interface TaxRegistrationInput {
|
|
|
448
448
|
interface LegalOrganizationInput {
|
|
449
449
|
/** Registration identifier */
|
|
450
450
|
id?: string;
|
|
451
|
+
/** Registration identifier scheme (ICD code list value, e.g. `"0002"` for SIRENE) */
|
|
452
|
+
schemeID?: string;
|
|
451
453
|
/** Trading business name */
|
|
452
454
|
tradingName?: string;
|
|
453
455
|
}
|
|
456
|
+
/**
|
|
457
|
+
* Identifier value with its scheme identifier.
|
|
458
|
+
*/
|
|
459
|
+
interface IdentifierWithSchemeInput {
|
|
460
|
+
value: string;
|
|
461
|
+
schemeID: string;
|
|
462
|
+
}
|
|
454
463
|
/**
|
|
455
464
|
* Trade party (seller, buyer, payee, etc.).
|
|
456
465
|
*
|
|
@@ -468,10 +477,14 @@ interface TradePartyInput {
|
|
|
468
477
|
*/
|
|
469
478
|
id?: string | string[];
|
|
470
479
|
/**
|
|
471
|
-
* Global identifier with scheme (e.g. GLN `"
|
|
480
|
+
* Global identifier with scheme (e.g. GLN value `"4000001000005"` and
|
|
481
|
+
* ICD scheme `"0088"`).
|
|
482
|
+
*
|
|
483
|
+
* `schemeID` is required by EN 16931 for `ram:GlobalID`.
|
|
484
|
+
*
|
|
472
485
|
* @see EN 16931 BT-29-1 / BT-46-1
|
|
473
486
|
*/
|
|
474
|
-
globalId?:
|
|
487
|
+
globalId?: IdentifierWithSchemeInput;
|
|
475
488
|
/** Postal address — mandatory for BASIC_WL and above */
|
|
476
489
|
address?: AddressInput;
|
|
477
490
|
/**
|
|
@@ -581,10 +594,14 @@ interface InvoiceLineInput {
|
|
|
581
594
|
*/
|
|
582
595
|
description?: string;
|
|
583
596
|
/**
|
|
584
|
-
* Item standard identifier (e.g. GTIN
|
|
597
|
+
* Item standard identifier (e.g. GTIN value `"4012345678901"` and ICD
|
|
598
|
+
* scheme `"0160"` for GS1).
|
|
599
|
+
*
|
|
600
|
+
* `schemeID` is required by EN 16931 for `ram:GlobalID` (BT-157-1).
|
|
601
|
+
*
|
|
585
602
|
* @see EN 16931 BT-157
|
|
586
603
|
*/
|
|
587
|
-
standardIdentifier?:
|
|
604
|
+
standardIdentifier?: IdentifierWithSchemeInput;
|
|
588
605
|
/**
|
|
589
606
|
* Seller-assigned item identifier.
|
|
590
607
|
* @see EN 16931 BT-155
|
|
@@ -616,6 +633,14 @@ interface InvoiceLineInput {
|
|
|
616
633
|
* @since EN16931
|
|
617
634
|
*/
|
|
618
635
|
buyerOrderLineId?: string;
|
|
636
|
+
/**
|
|
637
|
+
* Product manufacturer of this line item. Uses the standard trade-party
|
|
638
|
+
* shape; only id/globalId (BT-X-600), name (BT-X-598), and postal address
|
|
639
|
+
* (BG-X-93) are typically relevant.
|
|
640
|
+
* @see Factur-X EXTENDED BG-X-94, Factur-X 1.09
|
|
641
|
+
* @since EXTENDED
|
|
642
|
+
*/
|
|
643
|
+
manufacturer?: TradePartyInput;
|
|
619
644
|
}
|
|
620
645
|
/**
|
|
621
646
|
* Allowance or charge at header or line level.
|
|
@@ -649,6 +674,18 @@ interface AllowanceChargeInput {
|
|
|
649
674
|
vatCategoryCode?: VatCategoryCode | (string & Record<never, never>);
|
|
650
675
|
/** VAT rate for this allowance/charge */
|
|
651
676
|
vatRatePercent?: number;
|
|
677
|
+
/**
|
|
678
|
+
* VAT exemption reason text for this document-level allowance/charge.
|
|
679
|
+
* @see Factur-X EXTENDED BT-173 (allowance) / BT-175 (charge), Factur-X 1.09
|
|
680
|
+
* @since EXTENDED
|
|
681
|
+
*/
|
|
682
|
+
exemptionReason?: string;
|
|
683
|
+
/**
|
|
684
|
+
* VAT exemption reason code for this document-level allowance/charge.
|
|
685
|
+
* @see Factur-X EXTENDED BT-174 (allowance) / BT-176 (charge), Factur-X 1.09
|
|
686
|
+
* @since EXTENDED
|
|
687
|
+
*/
|
|
688
|
+
exemptionReasonCode?: string;
|
|
652
689
|
}
|
|
653
690
|
/**
|
|
654
691
|
* Payment information.
|
|
@@ -709,6 +746,22 @@ interface PaymentInput {
|
|
|
709
746
|
* @see EN 16931 BT-91
|
|
710
747
|
*/
|
|
711
748
|
debtorIban?: string;
|
|
749
|
+
/**
|
|
750
|
+
* Debtor account name (holder of the debited account). Only emitted when
|
|
751
|
+
* {@link PaymentInput.debtorIban} is also set, since the CII schema requires
|
|
752
|
+
* the IBAN on the debtor account element.
|
|
753
|
+
* @see Factur-X EXTENDED BT-216 ("Debited account name", Factur-X 1.09)
|
|
754
|
+
* @since EXTENDED
|
|
755
|
+
*/
|
|
756
|
+
debtorAccountName?: string;
|
|
757
|
+
/**
|
|
758
|
+
* BIC/SWIFT of the debtor's payment service provider (the debited account's
|
|
759
|
+
* financial institution).
|
|
760
|
+
* @see Factur-X EXTENDED BT-215 ("Debited account payment service provider
|
|
761
|
+
* identifier", Factur-X 1.09)
|
|
762
|
+
* @since EXTENDED
|
|
763
|
+
*/
|
|
764
|
+
debtorBic?: string;
|
|
712
765
|
/**
|
|
713
766
|
* Payment terms description (free text).
|
|
714
767
|
* @see EN 16931 BT-20
|
|
@@ -957,6 +1010,30 @@ interface FacturXInvoiceInput {
|
|
|
957
1010
|
* @since BASIC_WL
|
|
958
1011
|
*/
|
|
959
1012
|
sellerTaxRepresentative?: TradePartyInput;
|
|
1013
|
+
/**
|
|
1014
|
+
* Charges collected on behalf of a third party (document level).
|
|
1015
|
+
* @see Factur-X EXTENDED BG-34, Factur-X 1.09
|
|
1016
|
+
* @since EXTENDED
|
|
1017
|
+
*/
|
|
1018
|
+
financialAdjustments?: FinancialAdjustmentInput[];
|
|
1019
|
+
}
|
|
1020
|
+
/**
|
|
1021
|
+
* A charge collected on behalf of a third party.
|
|
1022
|
+
*
|
|
1023
|
+
* @see Factur-X EXTENDED BG-34 (`ram:SpecifiedFinancialAdjustment`), Factur-X 1.09
|
|
1024
|
+
* @since EXTENDED
|
|
1025
|
+
*/
|
|
1026
|
+
interface FinancialAdjustmentInput {
|
|
1027
|
+
/**
|
|
1028
|
+
* Specification of the charge collected on behalf of a third party.
|
|
1029
|
+
* @see Factur-X EXTENDED BT-180
|
|
1030
|
+
*/
|
|
1031
|
+
reason: string;
|
|
1032
|
+
/**
|
|
1033
|
+
* Charge amount collected on behalf of a third party.
|
|
1034
|
+
* @see Factur-X EXTENDED BT-179
|
|
1035
|
+
*/
|
|
1036
|
+
amount: number;
|
|
960
1037
|
}
|
|
961
1038
|
|
|
962
1039
|
/**
|
|
@@ -1077,7 +1154,7 @@ declare function escapeXml(value: string): string;
|
|
|
1077
1154
|
/**
|
|
1078
1155
|
* Builds a UN/CEFACT CrossIndustryInvoice XML string from structured input.
|
|
1079
1156
|
*
|
|
1080
|
-
* The output conforms to the Factur-X 1.
|
|
1157
|
+
* The output conforms to the Factur-X 1.09 / ZUGFeRD 2.5 CII schema at the
|
|
1081
1158
|
* requested {@link Profile} level. Elements that do not belong to the chosen
|
|
1082
1159
|
* profile are silently omitted.
|
|
1083
1160
|
*
|
|
@@ -1435,4 +1512,4 @@ interface XRechnungResult {
|
|
|
1435
1512
|
*/
|
|
1436
1513
|
declare function toXRechnung(input: FacturXInvoiceInput, options?: XRechnungOptions): XRechnungResult;
|
|
1437
1514
|
|
|
1438
|
-
export { type AddressInput, type AllowanceChargeInput, type BillingPeriodInput, type ContactInput, type DeliveryInput, type DocumentReferenceInput, DocumentTypeCode, type EmbedOptions, type EmbedResult, type ExtractOptions, type ExtractResult, FLAVOR_CONFIGS, FLAVOR_DEFAULT_TYPE_CODES, type FacturXInvoiceInput, Flavor, type FlavorConfig, type InvoiceDocumentInput, type InvoiceLineInput, type InvoiceTotalsInput, type LegalOrganizationInput, type NoteInput, PROFILE_MAIN_XSD, PROFILE_SCHEMA_DIRS, PROFILE_URNS, type PaymentInput, Profile, type TaxRegistrationInput, type TradePartyInput, UnitCode, type ValidationError, type ValidationResult, type VatBreakdownInput, VatCategoryCode, XRECHNUNG_PROFILE_URN, type XRechnungOptions, type XRechnungResult, type XsdValidateOptions, type XsdValidationError, type XsdValidationResult, buildXml, embedFacturX, escapeXml, extractXml, getFlavorConfig, resolveBusinessProcessUrn, resolveTypeCode, toXRechnung, validateFlavorProfile, validateInput, validateXsd };
|
|
1515
|
+
export { type AddressInput, type AllowanceChargeInput, type BillingPeriodInput, type ContactInput, type DeliveryInput, type DocumentReferenceInput, DocumentTypeCode, type EmbedOptions, type EmbedResult, type ExtractOptions, type ExtractResult, FLAVOR_CONFIGS, FLAVOR_DEFAULT_TYPE_CODES, type FacturXInvoiceInput, type FinancialAdjustmentInput, Flavor, type FlavorConfig, type IdentifierWithSchemeInput, type InvoiceDocumentInput, type InvoiceLineInput, type InvoiceTotalsInput, type LegalOrganizationInput, type NoteInput, PROFILE_MAIN_XSD, PROFILE_SCHEMA_DIRS, PROFILE_URNS, type PaymentInput, Profile, type TaxRegistrationInput, type TradePartyInput, UnitCode, type ValidationError, type ValidationResult, type VatBreakdownInput, VatCategoryCode, XRECHNUNG_PROFILE_URN, type XRechnungOptions, type XRechnungResult, type XsdValidateOptions, type XsdValidationError, type XsdValidationResult, buildXml, embedFacturX, escapeXml, extractXml, getFlavorConfig, resolveBusinessProcessUrn, resolveTypeCode, toXRechnung, validateFlavorProfile, validateInput, validateXsd };
|
package/dist/index.js
CHANGED
|
@@ -205,7 +205,7 @@ var FLAVOR_CONFIGS = {
|
|
|
205
205
|
defaultTypeCode: "380" /* COMMERCIAL_INVOICE */,
|
|
206
206
|
attachmentFilename: "factur-x.xml",
|
|
207
207
|
embedInPdf: true,
|
|
208
|
-
description: "German electronic invoice format. ZUGFeRD 2.
|
|
208
|
+
description: "German electronic invoice format. ZUGFeRD 2.5 uses factur-x.xml."
|
|
209
209
|
},
|
|
210
210
|
["xrechnung" /* XRECHNUNG */]: {
|
|
211
211
|
name: "XRechnung",
|
|
@@ -282,7 +282,8 @@ function tag(name, content, attrs) {
|
|
|
282
282
|
return `<${name}${a}>${content}</${name}>`;
|
|
283
283
|
}
|
|
284
284
|
function dateEl(wrapper, isoDate) {
|
|
285
|
-
|
|
285
|
+
const child = wrapper === "ram:FormattedIssueDateTime" ? "qdt:DateTimeString" : "udt:DateTimeString";
|
|
286
|
+
return tag(wrapper, tag(child, formatDate(isoDate), { format: "102" }));
|
|
286
287
|
}
|
|
287
288
|
function buildAddress(addr) {
|
|
288
289
|
let x = "";
|
|
@@ -310,13 +311,21 @@ function buildParty(p, profile) {
|
|
|
310
311
|
const ids = Array.isArray(p.id) ? p.id : [p.id];
|
|
311
312
|
for (const id of ids) x += tag("ram:ID", escapeXml(id));
|
|
312
313
|
}
|
|
313
|
-
if (p.globalId)
|
|
314
|
+
if (p.globalId) {
|
|
315
|
+
x += tag("ram:GlobalID", escapeXml(p.globalId.value), { schemeID: p.globalId.schemeID });
|
|
316
|
+
}
|
|
314
317
|
x += tag("ram:Name", escapeXml(p.name));
|
|
315
318
|
if (p.description && atLeast(profile, "EN16931" /* EN16931 */))
|
|
316
319
|
x += tag("ram:Description", escapeXml(p.description));
|
|
317
320
|
if (p.legalOrganization) {
|
|
318
321
|
let lo = "";
|
|
319
|
-
if (p.legalOrganization.id)
|
|
322
|
+
if (p.legalOrganization.id) {
|
|
323
|
+
lo += tag(
|
|
324
|
+
"ram:ID",
|
|
325
|
+
escapeXml(p.legalOrganization.id),
|
|
326
|
+
p.legalOrganization.schemeID ? { schemeID: p.legalOrganization.schemeID } : void 0
|
|
327
|
+
);
|
|
328
|
+
}
|
|
320
329
|
if (p.legalOrganization.tradingName)
|
|
321
330
|
lo += tag("ram:TradingBusinessName", escapeXml(p.legalOrganization.tradingName));
|
|
322
331
|
x += tag("ram:SpecifiedLegalOrganization", lo);
|
|
@@ -344,13 +353,19 @@ function buildLineItem(line, profile) {
|
|
|
344
353
|
let doc = tag("ram:LineID", escapeXml(line.id));
|
|
345
354
|
if (line.note) doc += tag("ram:IncludedNote", tag("ram:Content", escapeXml(line.note)));
|
|
346
355
|
let prod = "";
|
|
347
|
-
if (line.standardIdentifier)
|
|
356
|
+
if (line.standardIdentifier) {
|
|
357
|
+
prod += tag("ram:GlobalID", escapeXml(line.standardIdentifier.value), {
|
|
358
|
+
schemeID: line.standardIdentifier.schemeID
|
|
359
|
+
});
|
|
360
|
+
}
|
|
348
361
|
if (line.sellerAssignedId) prod += tag("ram:SellerAssignedID", escapeXml(line.sellerAssignedId));
|
|
349
362
|
if (line.buyerAssignedId) prod += tag("ram:BuyerAssignedID", escapeXml(line.buyerAssignedId));
|
|
350
363
|
prod += tag("ram:Name", escapeXml(line.name));
|
|
351
364
|
if (line.description) prod += tag("ram:Description", escapeXml(line.description));
|
|
352
365
|
if (line.originCountry && atLeast(profile, "EN16931" /* EN16931 */))
|
|
353
366
|
prod += tag("ram:OriginTradeCountry", tag("ram:ID", escapeXml(line.originCountry)));
|
|
367
|
+
if (line.manufacturer && atLeast(profile, "EXTENDED" /* EXTENDED */))
|
|
368
|
+
prod += tag("ram:ManufacturerTradeParty", buildParty(line.manufacturer, profile));
|
|
354
369
|
let agree = "";
|
|
355
370
|
if (line.buyerOrderLineId && atLeast(profile, "EN16931" /* EN16931 */))
|
|
356
371
|
agree += tag(
|
|
@@ -385,7 +400,7 @@ function buildLineItem(line, profile) {
|
|
|
385
400
|
tag("ram:AssociatedDocumentLineDocument", doc) + tag("ram:SpecifiedTradeProduct", prod) + tag("ram:SpecifiedLineTradeAgreement", agree) + tag("ram:SpecifiedLineTradeDelivery", delivery) + tag("ram:SpecifiedLineTradeSettlement", settle)
|
|
386
401
|
);
|
|
387
402
|
}
|
|
388
|
-
function buildAllowanceCharge(ac) {
|
|
403
|
+
function buildAllowanceCharge(ac, profile) {
|
|
389
404
|
let x = tag("ram:ChargeIndicator", tag("udt:Indicator", ac.isCharge ? "true" : "false"));
|
|
390
405
|
if (ac.percent !== void 0) x += tag("ram:CalculationPercent", ac.percent.toString());
|
|
391
406
|
if (ac.baseAmount !== void 0) x += tag("ram:BasisAmount", fmtAmt(ac.baseAmount));
|
|
@@ -393,8 +408,13 @@ function buildAllowanceCharge(ac) {
|
|
|
393
408
|
if (ac.reasonCode) x += tag("ram:ReasonCode", escapeXml(ac.reasonCode));
|
|
394
409
|
if (ac.reason) x += tag("ram:Reason", escapeXml(ac.reason));
|
|
395
410
|
if (ac.vatCategoryCode || ac.vatRatePercent !== void 0) {
|
|
411
|
+
const extended = atLeast(profile, "EXTENDED" /* EXTENDED */);
|
|
396
412
|
let tx = tag("ram:TypeCode", "VAT");
|
|
413
|
+
if (extended && ac.exemptionReason)
|
|
414
|
+
tx += tag("ram:ExemptionReason", escapeXml(ac.exemptionReason));
|
|
397
415
|
if (ac.vatCategoryCode) tx += tag("ram:CategoryCode", escapeXml(ac.vatCategoryCode));
|
|
416
|
+
if (extended && ac.exemptionReasonCode)
|
|
417
|
+
tx += tag("ram:ExemptionReasonCode", escapeXml(ac.exemptionReasonCode));
|
|
398
418
|
if (ac.vatRatePercent !== void 0)
|
|
399
419
|
tx += tag("ram:RateApplicablePercent", ac.vatRatePercent.toString());
|
|
400
420
|
x += tag("ram:CategoryTradeTax", tx);
|
|
@@ -562,11 +582,12 @@ function buildXml(input, profile, flavor) {
|
|
|
562
582
|
sett += tag("ram:PayeeTradeParty", buildParty(input.payee, profile));
|
|
563
583
|
if (payment?.meansCode && atLeast(profile, "BASIC_WL" /* BASIC_WL */)) {
|
|
564
584
|
let pm = tag("ram:TypeCode", escapeXml(payment.meansCode));
|
|
565
|
-
if (payment.debtorIban)
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
tag("ram:
|
|
569
|
-
);
|
|
585
|
+
if (payment.debtorIban) {
|
|
586
|
+
let dacct = tag("ram:IBANID", escapeXml(payment.debtorIban));
|
|
587
|
+
if (payment.debtorAccountName && atLeast(profile, "EXTENDED" /* EXTENDED */))
|
|
588
|
+
dacct += tag("ram:AccountName", escapeXml(payment.debtorAccountName));
|
|
589
|
+
pm += tag("ram:PayerPartyDebtorFinancialAccount", dacct);
|
|
590
|
+
}
|
|
570
591
|
if (payment.iban || payment.accountId || payment.accountName) {
|
|
571
592
|
let acct = "";
|
|
572
593
|
if (payment.iban) acct += tag("ram:IBANID", escapeXml(payment.iban));
|
|
@@ -575,6 +596,11 @@ function buildXml(input, profile, flavor) {
|
|
|
575
596
|
acct += tag("ram:AccountName", escapeXml(payment.accountName));
|
|
576
597
|
pm += tag("ram:PayeePartyCreditorFinancialAccount", acct);
|
|
577
598
|
}
|
|
599
|
+
if (payment.debtorBic && atLeast(profile, "EXTENDED" /* EXTENDED */))
|
|
600
|
+
pm += tag(
|
|
601
|
+
"ram:PayerSpecifiedDebtorFinancialInstitution",
|
|
602
|
+
tag("ram:BICID", escapeXml(payment.debtorBic))
|
|
603
|
+
);
|
|
578
604
|
if (payment.bic && atLeast(profile, "EN16931" /* EN16931 */))
|
|
579
605
|
pm += tag(
|
|
580
606
|
"ram:PayeeSpecifiedCreditorFinancialInstitution",
|
|
@@ -592,7 +618,7 @@ function buildXml(input, profile, flavor) {
|
|
|
592
618
|
sett += tag("ram:BillingSpecifiedPeriod", bp);
|
|
593
619
|
}
|
|
594
620
|
if (input.allowancesCharges && atLeast(profile, "BASIC_WL" /* BASIC_WL */))
|
|
595
|
-
for (const ac of input.allowancesCharges) sett += buildAllowanceCharge(ac);
|
|
621
|
+
for (const ac of input.allowancesCharges) sett += buildAllowanceCharge(ac, profile);
|
|
596
622
|
const dueDate = payment?.dueDate ?? doc.dueDate;
|
|
597
623
|
if (atLeast(profile, "BASIC_WL" /* BASIC_WL */) && (payment?.termsDescription || dueDate || payment?.mandateId)) {
|
|
598
624
|
let pt = "";
|
|
@@ -603,6 +629,14 @@ function buildXml(input, profile, flavor) {
|
|
|
603
629
|
sett += tag("ram:SpecifiedTradePaymentTerms", pt);
|
|
604
630
|
}
|
|
605
631
|
sett += buildMonetarySummation(totals, profile);
|
|
632
|
+
if (input.financialAdjustments && atLeast(profile, "EXTENDED" /* EXTENDED */)) {
|
|
633
|
+
for (const fa of input.financialAdjustments) {
|
|
634
|
+
sett += tag(
|
|
635
|
+
"ram:SpecifiedFinancialAdjustment",
|
|
636
|
+
tag("ram:Reason", escapeXml(fa.reason)) + tag("ram:ActualAmount", fmtAmt(fa.amount))
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
606
640
|
if (input.references && atLeast(profile, "BASIC_WL" /* BASIC_WL */)) {
|
|
607
641
|
for (const ref of input.references) {
|
|
608
642
|
if (ref.type === "preceding") {
|
|
@@ -1035,6 +1069,7 @@ async function validateXsd(xml, profile, options) {
|
|
|
1035
1069
|
XsdValidator,
|
|
1036
1070
|
XmlValidateError,
|
|
1037
1071
|
xmlRegisterInputProvider,
|
|
1072
|
+
xmlCleanupInputProvider,
|
|
1038
1073
|
XmlBufferInputProvider
|
|
1039
1074
|
} = await import('libxml2-wasm');
|
|
1040
1075
|
const schemaDir = path.dirname(xsdPath);
|
|
@@ -1046,6 +1081,7 @@ async function validateXsd(xml, profile, options) {
|
|
|
1046
1081
|
buffers[`file://${filePath}`] = buffers[filePath];
|
|
1047
1082
|
buffers[file] = buffers[filePath];
|
|
1048
1083
|
}
|
|
1084
|
+
xmlCleanupInputProvider();
|
|
1049
1085
|
const provider = new XmlBufferInputProvider(buffers);
|
|
1050
1086
|
xmlRegisterInputProvider(provider);
|
|
1051
1087
|
let xsdDoc;
|
|
@@ -1075,6 +1111,7 @@ async function validateXsd(xml, profile, options) {
|
|
|
1075
1111
|
xmlDoc?.dispose();
|
|
1076
1112
|
validator?.dispose();
|
|
1077
1113
|
xsdDoc?.dispose();
|
|
1114
|
+
xmlCleanupInputProvider();
|
|
1078
1115
|
}
|
|
1079
1116
|
}
|
|
1080
1117
|
var AF_RELATIONSHIP_MAP = {
|
package/package.json
CHANGED
package/schema/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Factur-X / ZUGFeRD Schema Files
|
|
2
2
|
|
|
3
|
-
> **Source:** Factur-X 1.
|
|
4
|
-
> **Reorganized from:**
|
|
3
|
+
> **Source:** Factur-X 1.09 / ZUGFeRD 2.5 official specifications (2026-06-10)
|
|
4
|
+
> **Reorganized from:** the official `XSD_SCHEMATRON` distribution (filenames normalized; internal `schemaLocation` references rewritten to match)
|
|
5
5
|
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -26,10 +26,23 @@ The package validates generated XML **against the profile-specific XSD** before
|
|
|
26
26
|
|
|
27
27
|
## Version
|
|
28
28
|
|
|
29
|
-
- **Factur-X:** 1.
|
|
30
|
-
- **ZUGFeRD:** 2.
|
|
29
|
+
- **Factur-X:** 1.09
|
|
30
|
+
- **ZUGFeRD:** 2.5
|
|
31
31
|
- **CII:** D22B
|
|
32
|
-
- **Effective:** 2026-
|
|
32
|
+
- **Effective:** 2026-05-15 (code lists & validation rules)
|
|
33
|
+
|
|
34
|
+
> Factur-X 1.09 keeps the same CII **D22B** syntax, namespaces, and profile URNs
|
|
35
|
+
> (`urn:factur-x.eu:1p0:*`) as 1.08, so it is fully backward compatible — XML that
|
|
36
|
+
> validates against 1.08 also validates against 1.09. For the MINIMUM, BASIC WL,
|
|
37
|
+
> BASIC, and EN 16931 profiles the XSDs are content-identical to 1.08; the EXTENDED
|
|
38
|
+
> XSD adds only **optional** elements (debited account name, financial adjustment /
|
|
39
|
+
> charges-on-behalf-of-a-third-party, an optional `listID` attribute).
|
|
40
|
+
>
|
|
41
|
+
> The `.sch` (Schematron) and `_codedb.xml` files carry the updated 1.09 code lists
|
|
42
|
+
> and CEN validation rules. They are kept here as reference only — this package
|
|
43
|
+
> performs **XSD validation**, not Schematron validation, and ships only `*.xsd`.
|
|
44
|
+
> The per-profile `Factur-X_1.08_*.xlsx` workbooks are legacy human-reference
|
|
45
|
+
> extracts and are not used at runtime.
|
|
33
46
|
|
|
34
47
|
---
|
|
35
48
|
|
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
</xs:simpleType>
|
|
17
17
|
<xs:complexType name="AllowanceChargeReasonCodeType">
|
|
18
18
|
<xs:simpleContent>
|
|
19
|
-
<xs:extension base="qdt:AllowanceChargeReasonCodeContentType"
|
|
19
|
+
<xs:extension base="qdt:AllowanceChargeReasonCodeContentType">
|
|
20
|
+
<xs:attribute name="listID" type="xs:token" default="4465_AllowanceChargeReasonCode"/>
|
|
21
|
+
</xs:extension>
|
|
20
22
|
</xs:simpleContent>
|
|
21
23
|
</xs:complexType>
|
|
22
24
|
<xs:simpleType name="ContactTypeCodeContentType">
|
package/schema/extended/FACTUR-X_EXTENDED_ReusableAggregateBusinessInformationEntity_100.xsd
CHANGED
|
@@ -30,6 +30,12 @@
|
|
|
30
30
|
<xs:complexType name="DebtorFinancialAccountType">
|
|
31
31
|
<xs:sequence>
|
|
32
32
|
<xs:element name="IBANID" type="udt:IDType"/>
|
|
33
|
+
<xs:element name="AccountName" type="udt:TextType" minOccurs="0"/>
|
|
34
|
+
</xs:sequence>
|
|
35
|
+
</xs:complexType>
|
|
36
|
+
<xs:complexType name="DebtorFinancialInstitutionType">
|
|
37
|
+
<xs:sequence>
|
|
38
|
+
<xs:element name="BICID" type="udt:IDType" minOccurs="0"/>
|
|
33
39
|
</xs:sequence>
|
|
34
40
|
</xs:complexType>
|
|
35
41
|
<xs:complexType name="DocumentContextParameterType">
|
|
@@ -65,6 +71,12 @@
|
|
|
65
71
|
<xs:element name="EffectiveSpecifiedPeriod" type="ram:SpecifiedPeriodType" minOccurs="0"/>
|
|
66
72
|
</xs:sequence>
|
|
67
73
|
</xs:complexType>
|
|
74
|
+
<xs:complexType name="FinancialAdjustmentType">
|
|
75
|
+
<xs:sequence>
|
|
76
|
+
<xs:element name="Reason" type="udt:TextType"/>
|
|
77
|
+
<xs:element name="ActualAmount" type="udt:AmountType"/>
|
|
78
|
+
</xs:sequence>
|
|
79
|
+
</xs:complexType>
|
|
68
80
|
<xs:complexType name="HeaderTradeAgreementType">
|
|
69
81
|
<xs:sequence>
|
|
70
82
|
<xs:element name="BuyerReference" type="udt:TextType" minOccurs="0"/>
|
|
@@ -116,6 +128,7 @@
|
|
|
116
128
|
<xs:element name="SpecifiedLogisticsServiceCharge" type="ram:LogisticsServiceChargeType" minOccurs="0" maxOccurs="unbounded"/>
|
|
117
129
|
<xs:element name="SpecifiedTradePaymentTerms" type="ram:TradePaymentTermsType" minOccurs="0" maxOccurs="unbounded"/>
|
|
118
130
|
<xs:element name="SpecifiedTradeSettlementHeaderMonetarySummation" type="ram:TradeSettlementHeaderMonetarySummationType"/>
|
|
131
|
+
<xs:element name="SpecifiedFinancialAdjustment" type="ram:FinancialAdjustmentType" minOccurs="0" maxOccurs="unbounded"/>
|
|
119
132
|
<xs:element name="InvoiceReferencedDocument" type="ram:ReferencedDocumentType" minOccurs="0" maxOccurs="unbounded"/>
|
|
120
133
|
<xs:element name="ReceivableSpecifiedTradeAccountingAccount" type="ram:TradeAccountingAccountType" minOccurs="0" maxOccurs="unbounded"/>
|
|
121
134
|
<xs:element name="SpecifiedAdvancePayment" type="ram:AdvancePaymentType" minOccurs="0" maxOccurs="unbounded"/>
|
|
@@ -161,7 +174,7 @@
|
|
|
161
174
|
<xs:element name="ApplicableTradeTax" type="ram:TradeTaxType" minOccurs="0" maxOccurs="unbounded"/>
|
|
162
175
|
<xs:element name="BillingSpecifiedPeriod" type="ram:SpecifiedPeriodType" minOccurs="0"/>
|
|
163
176
|
<xs:element name="SpecifiedTradeAllowanceCharge" type="ram:TradeAllowanceChargeType" minOccurs="0" maxOccurs="unbounded"/>
|
|
164
|
-
<xs:element name="SpecifiedTradeSettlementLineMonetarySummation" type="ram:TradeSettlementLineMonetarySummationType"/>
|
|
177
|
+
<xs:element name="SpecifiedTradeSettlementLineMonetarySummation" type="ram:TradeSettlementLineMonetarySummationType" minOccurs="0"/>
|
|
165
178
|
<xs:element name="InvoiceReferencedDocument" type="ram:ReferencedDocumentType" minOccurs="0"/>
|
|
166
179
|
<xs:element name="AdditionalReferencedDocument" type="ram:ReferencedDocumentType" minOccurs="0" maxOccurs="unbounded"/>
|
|
167
180
|
<xs:element name="ReceivableSpecifiedTradeAccountingAccount" type="ram:TradeAccountingAccountType" minOccurs="0" maxOccurs="unbounded"/>
|
|
@@ -195,9 +208,9 @@
|
|
|
195
208
|
<xs:complexType name="ProductCharacteristicType">
|
|
196
209
|
<xs:sequence>
|
|
197
210
|
<xs:element name="TypeCode" type="udt:CodeType" minOccurs="0"/>
|
|
198
|
-
<xs:element name="Description" type="udt:TextType"/>
|
|
211
|
+
<xs:element name="Description" type="udt:TextType" minOccurs="0"/>
|
|
199
212
|
<xs:element name="ValueMeasure" type="udt:MeasureType" minOccurs="0"/>
|
|
200
|
-
<xs:element name="Value" type="udt:TextType"/>
|
|
213
|
+
<xs:element name="Value" type="udt:TextType" minOccurs="0"/>
|
|
201
214
|
</xs:sequence>
|
|
202
215
|
</xs:complexType>
|
|
203
216
|
<xs:complexType name="ProductClassificationType">
|
|
@@ -409,6 +422,7 @@
|
|
|
409
422
|
<xs:element name="DesignatedProductClassification" type="ram:ProductClassificationType" minOccurs="0" maxOccurs="unbounded"/>
|
|
410
423
|
<xs:element name="IndividualTradeProductInstance" type="ram:TradeProductInstanceType" minOccurs="0" maxOccurs="unbounded"/>
|
|
411
424
|
<xs:element name="OriginTradeCountry" type="ram:TradeCountryType" minOccurs="0"/>
|
|
425
|
+
<xs:element name="ManufacturerTradeParty" type="ram:TradePartyType" minOccurs="0"/>
|
|
412
426
|
<xs:element name="IncludedReferencedProduct" type="ram:ReferencedProductType" minOccurs="0" maxOccurs="unbounded"/>
|
|
413
427
|
</xs:sequence>
|
|
414
428
|
</xs:complexType>
|
|
@@ -433,7 +447,7 @@
|
|
|
433
447
|
</xs:complexType>
|
|
434
448
|
<xs:complexType name="TradeSettlementLineMonetarySummationType">
|
|
435
449
|
<xs:sequence>
|
|
436
|
-
<xs:element name="LineTotalAmount" type="udt:AmountType"/>
|
|
450
|
+
<xs:element name="LineTotalAmount" type="udt:AmountType" minOccurs="0"/>
|
|
437
451
|
<xs:element name="ChargeTotalAmount" type="udt:AmountType" minOccurs="0"/>
|
|
438
452
|
<xs:element name="AllowanceTotalAmount" type="udt:AmountType" minOccurs="0"/>
|
|
439
453
|
<xs:element name="TaxTotalAmount" type="udt:AmountType" minOccurs="0" maxOccurs="2"/>
|
|
@@ -448,6 +462,7 @@
|
|
|
448
462
|
<xs:element name="ApplicableTradeSettlementFinancialCard" type="ram:TradeSettlementFinancialCardType" minOccurs="0"/>
|
|
449
463
|
<xs:element name="PayerPartyDebtorFinancialAccount" type="ram:DebtorFinancialAccountType" minOccurs="0"/>
|
|
450
464
|
<xs:element name="PayeePartyCreditorFinancialAccount" type="ram:CreditorFinancialAccountType" minOccurs="0"/>
|
|
465
|
+
<xs:element name="PayerSpecifiedDebtorFinancialInstitution" type="ram:DebtorFinancialInstitutionType" minOccurs="0"/>
|
|
451
466
|
<xs:element name="PayeeSpecifiedCreditorFinancialInstitution" type="ram:CreditorFinancialInstitutionType" minOccurs="0"/>
|
|
452
467
|
</xs:sequence>
|
|
453
468
|
</xs:complexType>
|