@stackforge-eu/factur-x 1.0.8 → 1.1.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 CHANGED
@@ -7,6 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.1.0] — 2026-05-27
11
+
12
+ - **BREAKING:** Every `ram:GlobalID` and the legal-organization `ram:ID` now
13
+ carry the `@schemeID` attribute required by EN 16931. The XSD-canonical CII
14
+ mapping makes the scheme mandatory on `ram:GlobalID` (BT-29-1 / BT-46-1 for
15
+ parties, BT-157-1 for line items) and conditional on
16
+ `ram:SpecifiedLegalOrganization/ram:ID` (BT-30-1 / BT-47-1); without these
17
+ attributes Mustang / KoSIT / veraPDF's Factur-X profile reject the invoice
18
+ even though the embedded CII looked superficially correct. Three input
19
+ fields changed:
20
+ - `TradePartyInput.globalId` is now `IdentifierWithSchemeInput`
21
+ (`{ value: string; schemeID: string }`) instead of a bare `string`
22
+ - `InvoiceLineInput.standardIdentifier` is now `IdentifierWithSchemeInput`
23
+ instead of a bare `string` (sibling fix on top of #4 — the line-item
24
+ `ram:GlobalID` had the same defect as the party one)
25
+ - `LegalOrganizationInput.schemeID?: string` added (optional, mirrors the
26
+ conditional spec rule)
27
+ Migration: `globalId: "4000001000005"` →
28
+ `globalId: { value: "4000001000005", schemeID: "0088" }` (and the analogous
29
+ rewrite for `standardIdentifier`). The new `IdentifierWithSchemeInput` type
30
+ is exported from `src/index.ts`. Regression test added in
31
+ `tests/xsd-validator.test.ts` that drives all three schemed identifiers
32
+ through the EN16931 XSD in one go (thanks @sco-indy, #4).
33
+
10
34
  ## [1.0.8] — 2026-05-27
11
35
 
12
36
  - **PDF trailer was missing the `/ID` entry required by PDF/A-3.** ISO 19005-3
@@ -129,6 +153,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
129
153
  - Deno compatibility test suite
130
154
 
131
155
  [Unreleased]: https://github.com/StackForge-EU/factur-x/commits/main
156
+ [1.1.0]: https://github.com/StackForge-EU/factur-x/compare/v1.0.8...v1.1.0
132
157
  [1.0.8]: https://github.com/StackForge-EU/factur-x/compare/v1.0.7...v1.0.8
133
158
  [1.0.7]: https://github.com/StackForge-EU/factur-x/compare/v1.0.6...v1.0.7
134
159
  [1.0.6]: https://github.com/StackForge-EU/factur-x/compare/v1.0.5...v1.0.6
package/dist/index.cjs CHANGED
@@ -340,13 +340,21 @@ function buildParty(p, profile) {
340
340
  const ids = Array.isArray(p.id) ? p.id : [p.id];
341
341
  for (const id of ids) x += tag("ram:ID", escapeXml(id));
342
342
  }
343
- if (p.globalId) x += tag("ram:GlobalID", escapeXml(p.globalId));
343
+ if (p.globalId) {
344
+ x += tag("ram:GlobalID", escapeXml(p.globalId.value), { schemeID: p.globalId.schemeID });
345
+ }
344
346
  x += tag("ram:Name", escapeXml(p.name));
345
347
  if (p.description && atLeast(profile, "EN16931" /* EN16931 */))
346
348
  x += tag("ram:Description", escapeXml(p.description));
347
349
  if (p.legalOrganization) {
348
350
  let lo = "";
349
- if (p.legalOrganization.id) lo += tag("ram:ID", escapeXml(p.legalOrganization.id));
351
+ if (p.legalOrganization.id) {
352
+ lo += tag(
353
+ "ram:ID",
354
+ escapeXml(p.legalOrganization.id),
355
+ p.legalOrganization.schemeID ? { schemeID: p.legalOrganization.schemeID } : void 0
356
+ );
357
+ }
350
358
  if (p.legalOrganization.tradingName)
351
359
  lo += tag("ram:TradingBusinessName", escapeXml(p.legalOrganization.tradingName));
352
360
  x += tag("ram:SpecifiedLegalOrganization", lo);
@@ -374,7 +382,11 @@ function buildLineItem(line, profile) {
374
382
  let doc = tag("ram:LineID", escapeXml(line.id));
375
383
  if (line.note) doc += tag("ram:IncludedNote", tag("ram:Content", escapeXml(line.note)));
376
384
  let prod = "";
377
- if (line.standardIdentifier) prod += tag("ram:GlobalID", escapeXml(line.standardIdentifier));
385
+ if (line.standardIdentifier) {
386
+ prod += tag("ram:GlobalID", escapeXml(line.standardIdentifier.value), {
387
+ schemeID: line.standardIdentifier.schemeID
388
+ });
389
+ }
378
390
  if (line.sellerAssignedId) prod += tag("ram:SellerAssignedID", escapeXml(line.sellerAssignedId));
379
391
  if (line.buyerAssignedId) prod += tag("ram:BuyerAssignedID", escapeXml(line.buyerAssignedId));
380
392
  prod += tag("ram:Name", escapeXml(line.name));
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 `"0088:1234567890123"`).
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?: string;
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/EAN).
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?: string;
604
+ standardIdentifier?: IdentifierWithSchemeInput;
588
605
  /**
589
606
  * Seller-assigned item identifier.
590
607
  * @see EN 16931 BT-155
@@ -1435,4 +1452,4 @@ interface XRechnungResult {
1435
1452
  */
1436
1453
  declare function toXRechnung(input: FacturXInvoiceInput, options?: XRechnungOptions): XRechnungResult;
1437
1454
 
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 };
1455
+ 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 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 `"0088:1234567890123"`).
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?: string;
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/EAN).
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?: string;
604
+ standardIdentifier?: IdentifierWithSchemeInput;
588
605
  /**
589
606
  * Seller-assigned item identifier.
590
607
  * @see EN 16931 BT-155
@@ -1435,4 +1452,4 @@ interface XRechnungResult {
1435
1452
  */
1436
1453
  declare function toXRechnung(input: FacturXInvoiceInput, options?: XRechnungOptions): XRechnungResult;
1437
1454
 
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 };
1455
+ 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 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
@@ -310,13 +310,21 @@ function buildParty(p, profile) {
310
310
  const ids = Array.isArray(p.id) ? p.id : [p.id];
311
311
  for (const id of ids) x += tag("ram:ID", escapeXml(id));
312
312
  }
313
- if (p.globalId) x += tag("ram:GlobalID", escapeXml(p.globalId));
313
+ if (p.globalId) {
314
+ x += tag("ram:GlobalID", escapeXml(p.globalId.value), { schemeID: p.globalId.schemeID });
315
+ }
314
316
  x += tag("ram:Name", escapeXml(p.name));
315
317
  if (p.description && atLeast(profile, "EN16931" /* EN16931 */))
316
318
  x += tag("ram:Description", escapeXml(p.description));
317
319
  if (p.legalOrganization) {
318
320
  let lo = "";
319
- if (p.legalOrganization.id) lo += tag("ram:ID", escapeXml(p.legalOrganization.id));
321
+ if (p.legalOrganization.id) {
322
+ lo += tag(
323
+ "ram:ID",
324
+ escapeXml(p.legalOrganization.id),
325
+ p.legalOrganization.schemeID ? { schemeID: p.legalOrganization.schemeID } : void 0
326
+ );
327
+ }
320
328
  if (p.legalOrganization.tradingName)
321
329
  lo += tag("ram:TradingBusinessName", escapeXml(p.legalOrganization.tradingName));
322
330
  x += tag("ram:SpecifiedLegalOrganization", lo);
@@ -344,7 +352,11 @@ function buildLineItem(line, profile) {
344
352
  let doc = tag("ram:LineID", escapeXml(line.id));
345
353
  if (line.note) doc += tag("ram:IncludedNote", tag("ram:Content", escapeXml(line.note)));
346
354
  let prod = "";
347
- if (line.standardIdentifier) prod += tag("ram:GlobalID", escapeXml(line.standardIdentifier));
355
+ if (line.standardIdentifier) {
356
+ prod += tag("ram:GlobalID", escapeXml(line.standardIdentifier.value), {
357
+ schemeID: line.standardIdentifier.schemeID
358
+ });
359
+ }
348
360
  if (line.sellerAssignedId) prod += tag("ram:SellerAssignedID", escapeXml(line.sellerAssignedId));
349
361
  if (line.buyerAssignedId) prod += tag("ram:BuyerAssignedID", escapeXml(line.buyerAssignedId));
350
362
  prod += tag("ram:Name", escapeXml(line.name));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackforge-eu/factur-x",
3
- "version": "1.0.8",
3
+ "version": "1.1.0",
4
4
  "type": "module",
5
5
  "description": "Embed Factur-X, ZUGFeRD, and XRechnung structured invoice XML into PDF/A-3 documents",
6
6
  "keywords": [