Skip to content

Repository files navigation

en16931-cii2ubl

Sonatype Central javadoc

If this project saved you some time or made your day a little easier, a star would mean a lot — it helps others find it too.

Unidirectional converter for EN 16931 invoices from CII to UBL, supporting both editions of the standard:

Edition Input Output Specification identifier (BT-24)
EN 16931:2017 CII D16B UBL 2.1 urn:cen.eu:en16931:2017
EN 16931:2026 CII D25A UBL 2.5 urn:cen.eu:en16931:2026

Since v4.0.0 the UBL versions 2.2, 2.3 and 2.4 are no longer supported, because the two editions of EN 16931 prescribe exactly UBL 2.1 and UBL 2.5.

This is a Java 17+ library that converts a Cross Industry Invoice (CII) into a Universal Business Language (UBL) document following the rules of the European Norm (EN) 16931 that defines a common semantic data model for electronic invoices in Europe.

Special care was given to XRechnung invoices - all the CII examples of them translate to UBL that is valid according to the EN 16931 validation rules.

See https://peppol.helger.com/public/locale-en_US/menuitem-tools-rest-api#cii2ubl for a service implementation using this library.

This library is licensed under the Apache License Version 2.0.

The binary releases are available on Maven Central at https://repo1.maven.org/maven2/com/helger/en16931-cii2ubl/ and below.

Usage

This is a pure Java library and not a self-contained conversion tool. The entrance classes are:

  • EN 16931:2017, CII D16B to UBL 2.1: com.helger.en16931.cii2ubl.en2017.CIID16BToUBL21Converter
  • EN 16931:2026, CII D25A to UBL 2.5: com.helger.en16931.cii2ubl.en2026.CIID25AToUBL25Converter (since v4.0.0)

If you do not know the edition of a document up front, use com.helger.en16931.cii2ubl.CIIToUBLDispatcher (since v4.0.0). It determines the edition from BT-24 (Specification identifier) and routes to the matching converter:

final ErrorList aErrorList = new ErrorList ();
final Serializable aUBL = new CIIToUBLDispatcher ().convertCIItoUBL (aFile, aErrorList);

Note that the edition cannot be determined from the XML namespaces, because CII D16B, D22B and D25A all use identical namespace URIs, and it cannot be determined from the XML Schema either, because a D16B instance also validates against the D25A XSD. BT-24 is the only reliable discriminator. For documents that carry no EN 16931 identifier - for example legacy ZUGFeRD files - set the edition explicitly with setEdition (EEN16931Edition.EN2017). EEN16931Edition lives in en16931-basics, the artefact that holds the facts about EN 16931 that are shared between the conversion projects; since v4.0.0 it is a dependency of this library.

The main conversion method is called convertCIItoUBL and takes either a File as input or a pre-parsed CrossIndustryInvoiceType object. Reading is done with com.helger.cii.d16b.CIID16BCrossIndustryInvoiceTypeMarshaller respectively com.helger.cii.d25a.CIID25ACrossIndustryInvoiceTypeMarshaller from ph-cii. Additionally an ErrorList object must be provided as a container for all the errors that occur.

The conversion is deemed successful, if a non-null object is returned and if the error list contains no error (errorList.containsNoError ()).

The field mapping of both editions is documented in the docs folder:

Maven usage

Replace x.y.z with the effective version you want to use:

<dependency>
  <groupId>com.helger</groupId>
  <artifactId>en16931-cii2ubl</artifactId>
  <version>x.y.z</version>
</dependency>

Commandline usage

Call it via java -jar en16931-cii2ubl-cli-full.jar followed by the options and parameters.

Without --en-version the EN 16931 edition is determined from BT-24 of each source file.

[INFO] CII to UBL Converter v4.0.0-SNAPSHOT (build 2026-09-04T22:40:13Z)
Missing required parameter: 'source files'
Usage: CIItoUBLConverter [-hV] [--disable-wildcard-expansion]
                         [--swap-price-sign] [--swap-quantity-sign] [--verbose]
                         [--en-version edition] [--mode mode] [--output-suffix
                         filename part] [-t directory] [--ubl version]
                         [--ubl-cardaccountnetworkid ID] [--ubl-customizationid
                         ID] [--ubl-defaultorderrefid ID] [--ubl-profileid ID]
                         [--ubl-vatscheme vat scheme] source files...
CII to UBL Converter for EN 16931 invoices
      source files...        One or more CII file(s)
      --disable-wildcard-expansion
                             Disable wildcard expansion of filenames
      --en-version edition   The EN 16931 edition to use: '2017' (CII D16B to
                               UBL 2.1) or '2026' (CII D25A to UBL 2.5). If
                               omitted, the edition is determined from BT-24 of
                               each source file.
  -h, --help                 Show this help message and exit.
      --mode mode            Allowed values: AUTOMATIC, INVOICE, CREDIT_NOTE
                               (default: 'AUTOMATIC')
      --output-suffix filename part
                             The suffix added to the output filename (default:
                               '-ubl')
      --swap-price-sign      Swap price sign if needed for credit notes
                               (default: 'true')
      --swap-quantity-sign   Swap quantity sign if needed for credit notes
                               (default: 'true')
  -t, --target directory     The target directory for result output (default:
                               '.')
      --ubl version          Deprecated alias for --en-version: '2.1' selects
                               EN 16931:2017 and '2.5' selects EN 16931:2026.
                               Prefer --en-version.
      --ubl-cardaccountnetworkid ID
                             The UBL CardAccount network ID to be used
                               (default: 'mapped-from-cii')
      --ubl-customizationid ID
                             The UBL customization ID to be used
      --ubl-defaultorderrefid ID
                             The UBL default order reference ID to be used
                               (default: '')
      --ubl-profileid ID     The UBL profile ID to be used
      --ubl-vatscheme vat scheme
                             The UBL VAT scheme to be used (default: 'VAT')
  -V, --version              Print version information and exit.
      --verbose              Enable debug logging (default: 'false')

Open issues

  • The migration of CII NetPriceProductTradePrice/BasisQuantity to UBL Price/BaseQuantity is not consistent for me
    • See example files 2, 8 and 9
    • The UBL example files use a BaseQuanity of 1 in all cases

News and noteworthy

v4.0.1 - 2026-09-07

  • Fixed a CII ram:GlobalID with @schemeID="SEPA" being written as a party identifier BT-29/BT-46/BT-60/BT-71. In UBL that scheme identifier is reserved for BT-90, so the result carried two competing bank assigned creditor identifiers, and the scheme identifier is not an ISO 6523 ICD code either, which BR-CL-10 requires. Affects both editions
  • Now using EEN16931TaxSchemeCode.LOC and the new discriminator constants of en16931-basics 1.0.1 instead of local copies. NATIONAL_TAX_SCHEME, NON_VAT_TAX_CODE_LIST_ID and SUPPORTING_DOCUMENT_TYPE_CODE_LIST_ID of CIID25AToUBL25Converter are deprecated and now delegate there
  • BT-32-2 is derived from EN16931CodeLists.mapTaxSchemeCodeCIIToUBL rather than a hard coded "FC" to "LOC" special case
  • Fixed a schema invalid cac:OrderLineReference for an invoice line that has a sales order reference (BT-200/BT-201) but no purchase order line reference (BT-132) - the mandatory cbc:LineID was left out entirely
  • The placeholder for a mandatory cbc:LineID without a business term value is now the None prescribed by the UBL binding instead of 1, which is what en16931-ubl2cii reads back. Affects BT-132, BT-190, BT-192 and BT-199

v4.0.0 - 2026-09-05

  • Added the EN 16931:2026 syntax binding: com.helger.en16931.cii2ubl.en2026.CIID25AToUBL25Converter converts CII D25A to UBL 2.5, covering all 284 rows of the mapping table including the 70 business terms and groups that are new in 2026 (BG-33 to BG-39, BT-166 to BT-220)
  • Removed the support for creating UBL 2.2, 2.3 and 2.4 - the two editions of EN 16931 prescribe exactly UBL 2.1 and UBL 2.5
  • Moved the EN 16931:2017 conversion to the new package com.helger.en16931.cii2ubl.en2017 and renamed CIIToUBL21Converter to CIID16BToUBL21Converter. The UBL 2.1 output is unchanged
  • Split AbstractCIIToUBLConverter into the edition independent AbstractCIIToUBLConverterBase and the CII release specific AbstractCIIToUBL2017Converter and AbstractCIIToUBL2026Converter
  • Added CIIToUBLDispatcher to determine the EN 16931 edition of a CII document from BT-24 and to route to the matching converter. The edition can neither be determined from the XML namespaces, which are identical across CII releases, nor from the XML Schema, because a D16B instance also validates against the D25A XSD
  • Added the dependency to en16931-basics 1.0.0 and took EEN16931Edition, the code list knowledge and the UNTDID 2379 date formats from there instead of holding own copies. com.helger.en16931.cii2ubl.EEN16931Edition was therefore replaced by com.helger.en16931.basics.EEN16931Edition, and the BT-3, BT-8, BT-17/BT-18 and BT-81 classification now comes from com.helger.en16931.basics.codelist.EN16931CodeLists. The AbstractCIIToUBLConverterBase constants DEFAULT_DATE_TIME_FORMAT and DATE_TIME_FORMAT_WITH_TIME were replaced by com.helger.en16931.basics.EEN16931DateFormatCode. The converted output is unchanged
  • The CLI determines the edition per file from BT-24 by default; the new option --en-version 2017|2026 forces one instead. --ubl is deprecated and now only accepts 2.1 and 2.5
  • Fixed a long standing CLI bug: without --ubl-customizationid and --ubl-profileid the conversion aborted with a NullPointerException
  • The BT-3 (Invoice type code) subset of UNTDID 1001 now follows the EN 16931 code list registry (the CEN/TC 434 section of the European Commission registry), with the values taken from "EN16931 code lists values v17b - used from 2026-05-15". The list is versioned by date and not by EN 16931 edition, so both editions share it
  • Fixed the BT-3 classification of 81, 502 and 503: all three were treated as Invoice codes, although the code list has them as Credit Note codes. 502 and 503 were added to the list in v15 (used from 2025-05-15)
  • Added the dependencies to ph-cii-d25a and ph-ubl25
  • Added docs/en16931-2026-syntax.md with the three-way field mapping (UBL 2.5 invoice / UBL 2.5 credit note / CII D25A) of EN 16931:2026
  • Added docs/plan-4.0.0.md with the implementation plan for v4.0.0

v3.1.7 - 2026-04-22

  • Fixed BT-150 (Item price base quantity unit of measure): now falls back to the net price unitCode when no gross price is present, instead of losing it
  • Fixed BT-61/BT-61-1 (Payee legal registration identifier): _convertPartyLegalEntity is now called for the Payee party, mapping SpecifiedLegalOrganization/ID to PartyLegalEntity/CompanyID
  • Fixed UBL-CR-275 compliance: RegistrationName fallback is no longer set on the Payee PartyLegalEntity, as the EN 16931 Schematron forbids it
  • Fixed BT-11 (Project reference) for UBL 2.1 CreditNote: now mapped to AdditionalDocumentReference since UBL 2.1 CreditNote lacks ProjectReference

v3.1.6 - 2026-04-22

  • Added CLI options --swap-quantity-sign and --swap-price-sign to expose the full converter API
  • Improved BT-90 mapping so that it is correctly set to the PayeeParty if present
  • Improved BT-11 mapping for UBL CreditNote

v3.1.5 - 2026-04-13

  • Fixed the "main class" attribute for the manifest

v3.1.4 - 2026-04-13

  • No more OSGI bundle packaging
  • Avoid creating an empty UBL Delivery Party Name element. See issue #47
  • Fixed the Delivery element to also be created when only a delivery date is present but no ShipToParty
  • Unified the CreditNote line-item price handling (BT-147, BT-148, BT-149, BT-150) to match the Invoice logic

v3.1.3 - 2026-02-02

  • Fixed the BT-9 mapping of CreditNotes. See issue #45 - thx @AWickSimova
  • The list of allowed Invoice Type Codes was extended: Added 71, 81, 102, 218, 219, 331, 382, 471, 472, 473, 500, 501, 502, 503, 553, 817 and 870

v3.1.2 - 2026-01-05

  • Fixed a bug in the BG-17 conversion towards UBL 2.4. See issue #44 - thx @matmen

v3.1.1 - 2025-12-29

  • Fixed invalid mapping to BillingReference/CreditNoteDocumentReference. See issue #43 - thx @ycheuv-lgtm

v3.1.0 - 2025-11-16

  • Updated to ph-commons 12.1.0
  • Using JSpecify annotations

v3.0.1 - 2025-09-19

  • Added the mapping of BT-86 for DirectDebit case

v3.0.0 - 2025-08-27

  • Requires Java 17 as the minimum version
  • Updated to ph-commons 12.0.0

v2.3.1 - 2025-06-26

  • Avoid NullPointerException if a CII line item has no quantity

v2.3.0 - 2025-03-25

  • Removed the default values for BT-24 (CustomizationID) and BT-23 (ProfileID)
  • Emitting UBL 2.4 documents correctly
  • Taking the values of BT-23 and BT-24 from the source CII fields. See issue #37 - thx @shenazz
  • Handling BG-17 only if PayeePartyCreditorFinancialAccount is present. See issue #38 - thx @msccip

v2.2.6 - 2024-12-23

  • Supporting all values of the UNTDID 4461 code list. See issue #34 - thx @shenazz

v2.2.5 - 2024-10-22

  • Fixed the automatic module name. See issue #32 - thx @toherrmann

v2.2.4 - 2024-06-17

  • Fixed a regression from v2.2.3. See issue #31 - thx @msccip

v2.2.3 - 2024-06-12

  • Added additional mapping of BT-41. See issue #28 - thx @bdewein
  • Fixed the mapping of the Due Date Type Code for BT-8. See issue #29 - thx @bdewein
  • Fixed the mapping of BT-27 and BT-28. See issue #26 - thx @bdewein
  • Fixed the item price mapping around BT-146, BT-147, BT-148, BT-149 and BT-150. See issue #27 - thx @bdewein

v2.2.2 - 2024-04-12

  • Added support for providing the default UBL order reference ID, in case the empty String is not good enough. See issue #23 - thx @lkumai

v2.2.1 - 2024-03-29

  • Updated to ph-commons 11.1.5
  • Ensured Java 21 compatibility

v2.2.0 - 2024-03-08

  • Updated to ph-ubl 9.0.0
  • Tested output against EN 16931 rules v1.3.10 and v1.3.11 - no changes necessary
  • Updated to create UBL 2.4-CS01
  • Added support for BT-8 mapping. See issue #22

v2.1.0 - 2023-04-28

  • Updated to ph-ubl 8.0.1
  • Added support for converting to UBL 2.4

v2.0.3 - 2023-04-20

  • Improved mapping of references to external documents in additional document references. See issue #20 - thanks @msccip

v2.0.2 - 2023-03-30

  • Changed the default mode of the CLI version from INVOICE to AUTOMATIC. See issue #19 - thanks @msccip

v2.0.1 - 2023-03-15

  • Added manual wildcard expansion of filenames
  • Added new CLI option --disable-wildcard-expansion to disable the wildcard expansion and stick to the old resolution logic

v2.0.0 - 2023-02-20

  • Using Java 11 as the baseline
  • Updated to ph-commons 11
  • Updated to JAXB 4.0
  • Added the new CLI parameter --verbose for a few more details
  • Improved logging
  • Successfully tested the CLI parameter with wildcard parameters (because the Java Windows Runtime performs automatic wildcard expansion)

v1.4.10 - 2022-12-16

  • Fixed the conversion of the TypeCode element in AdditionalReferencedDocument. See issue #18 - thanks @L3Mars

v1.4.9 - 2022-11-15

  • Fixed an unnecessary division by 100 for creating MultiplierFactorNumeric. See issue #17 - thanks @L3Mars
  • Tested output against EN 16931 rules v1.3.9 - no changes necessary

v1.4.8 - 2022-09-28

  • Added new option --output-suffix to customize the output file suffix, that is currently hard coded to -ubl
  • Fixed a problem with the mapping of BT-147, BT-148, BT-149 and BT-150. See issue #15. Thanks to @cambid for pointing that out

v1.4.7 - 2022-02-15

  • Further improved null/empty handling to avoid creation of empty elements

v1.4.6 - 2022-02-12

  • Allowing the additional Payment Means Type Codes 1, 42 and 68. See issue #13
  • For decimal values, trailing zeroes are no longer emitted. See issue #13
  • Improved not creating empty UBL elements. See issue #13
  • The SubjectCode of IncludedNote elements is copied over. See issue #13
  • Improved the Party ID handling and allowing for multiple seller IDs. See issue #13

v1.4.5 - 2021-12-20

  • Tested output against EN 16931 rules v1.3.7 - no changes necessary
  • Fixed creating invalid UBL if SellerAssignedID is empty. See issue #12 - thanks @DerHamm

v1.4.4 - 2021-10-14

  • Improved sign swapping of Quantity and Price to avoid negative prices (BT-146)

v1.4.3 - 2021-10-07

  • Tested output against EN 16931 rules v1.3.6 - no changes necessary
  • Changed determination if Invoice or CreditNote primarily to rsm:ExchangedDocument/ram:TypeCode instead of the payable amount

v1.4.2 - 2021-06-10

  • Changed the default customization ID to urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0
  • If the UBL LineExtensionAmount is negative, but the line Quantity is positive, the Quantity will be changed to negative. Customizable via setSwapQuantitySignIfNeeded(boolean)

v1.4.1 - 2021-05-02

  • Updated to ph-commons 10.1
  • Tested output against EN 16931 rules v1.3.5 - no changes necessary

v1.4.0 - 2021-03-22

  • Updated to ph-commons 10

v1.3.0 - 2021-01-05

  • Added support for different CII time formats (2, 3, 4, 101, 102, 103 and 105) where 102 is the default
  • The error handling for the commandline client was improved (checking errors before writing UBL) (see issue #9)
  • Added the possibility to create UBL 2.3
  • Made the API more open to directly convert to Invoice or CreditNote
  • Improved the handling of payment means to be more EN compliant. See issue #7.
  • Added a possibility to retrieve the internal converter version number

v1.2.5 - 2020-11-30

  • Added Jakarta Activation dependency to the standalone CLI version. See issue #6.

v1.2.4 - 2020-10-20

v1.2.3 - 2020-09-17

  • Updated to Jakarta JAXB 2.3.3

v1.2.2 - 2020-08-30

  • Updated to ph-commons 9.4.7
  • Updated to ph-cii 2.3.0
  • Updated to ph-ubl 6.4.0

v1.2.1 - 2020-05-26

  • Updated to new Maven groupIds

v1.2.0 - 2020-03-09

  • Verified against EN 16931 validation artefacts 1.3.0 - no changes in the output
  • Added commandline interface (CLI). See PR #3. Thanks to @rkottmann
  • Fixed creating invalid UBL if SellerOrderReferencedDocument is present but BuyerOrderReferencedDocument is not set (see issue #5)
  • Made default VAT scheme, UBL CustomizationID, UBL ProfileID and the PaymentMeans/CardAccount/NetworkID customizable. See issue #1 and issue #2.
  • Fixed embedded attachment mapping. See issue #4.

v1.1.5 - 2019-09-13

  • Added possibility to enforce invoice creation
  • Verified against EN 16931 validation artefacts 1.3.0

v1.1.4 - 2019-07-15

  • Updated to EN 16931 validation artefacts 1.2.3

v1.1.3 - 2019-05-15

  • Updated to EN 16931 validation artefacts 1.2.1

v1.1.2 - 2019-04-26

  • Updated to EN 16931 validation artefacts 1.2.0

v1.1.1 - 2019-02-27

  • Improved delivery date handling
  • Improved price base quantity handling

v1.1.0 - 2019-02-26

  • Added support to create UBL 2.1 Invoice and CreditNote

v1.0.0 - 2019-02-26

  • Initial release creating UBL 2.2 Invoice and CreditNote

My personal Coding Styleguide | It is appreciated if you star the GitHub project if you like it.

About

Converter for EN16931 invoices from CII to UBL

Topics

Resources

Code of conduct

Stars

47 stars

Watchers

9 watching

Forks

Releases

Packages

Used by

Contributors

Languages