Pewarta Proxy

πŸ“‹ Server Request & Proxy Logs

Loading active proxy settings...
Developed by Khairul Adha (adhexa.id)
Mengambil log server...

βš™οΈ Pengaturan Proxy Target

Skip to content

About

A high-performance Java builder for PEPPOL BIS Billing 3.0 & Norwegian EHF 3.0. Compliant with EN 16931 & UBL 2.1. Developed by Gus Hu (12+ YOE Architect).

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Latest commit

Β 

History

8 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

EHF Invoice Builder

A Java library for generating EHF 3.0 / PEPPOL BIS Billing 3.0 compliant invoices, with full support for Norwegian tax rules and B2G (Business-to-Government) requirements.

Built on top of ph-ubl β€” no XML template files, no string manipulation. Pure UBL 2.1 object model construction.


Why This Library Exists

Generating a PEPPOL-compliant invoice is not just about producing valid XML. The real challenge is the Norwegian localization layer:

  • Norwegian MVA-koder (e.g., 3, 5, 6, 31) must be translated to PEPPOL UNCL5305 tax category codes (S, Z, E, AE, etc.)
  • The supplier's VAT ID must follow the exact format: NO + OrgNr + MVA
  • BuyerReference is effectively mandatory for B2G (government) invoicing β€” missing it causes silent rejection by municipal ERP systems
  • KID (Kundeidentifikasjonsnummer) for OCR-based bank reconciliation must be mapped to PaymentID, not PaymentNote
  • Tax subtotals must be grouped strictly by category and rate (BR-CO-17) β€” merging two zero-rate categories will fail Schematron validation

This library encodes all of the above so you don't have to rediscover it.


Requirements

Dependency Version
Java 11+
ph-ubl 9.x
Lombok 1.18+
<!-- Maven dependency for ph-ubl -->
<dependency>
    <groupId>com.helger</groupId>
    <artifactId>ph-ubl21</artifactId>
    <version>9.x.x</version>
</dependency>

Quick Start

// 1. Build the DTO
EhfInvoiceDTO dto = new EhfInvoiceDTO();
dto.setInvoiceNo("INV-2024-001");
dto.setInvoiceDate(LocalDate.of(2024, 5, 1));
dto.setInvoiceDueDate(LocalDate.of(2024, 5, 31));
dto.setCurrency("NOK");
dto.setBuyerReference("Morten Tveten");           // Critical for B2G
dto.setCompanyOrganizationNo("123456789");
dto.setCompanyName("Supplier AS");
dto.setCompanyLegalName("Supplier AS");
dto.setCompanyCountryCode("NO");
dto.setIsVatRegistered(true);                     // Triggers NO...MVA format
dto.setCustomerOrgCode("987654321");
dto.setCustomerName("Buyer Kommune");
dto.setCustomerCountryCode("NO");
// ... set amounts, line items, VAT details

// 2. Generate the UBL object
EhfInvoiceFactory factory = new EhfInvoiceFactory();
InvoiceType invoice = factory.createInvoice(dto, null);

// 3. Serialize to XML
String xml = UBL21Marshaller.invoice()
        .setFormattedOutput(true)
        .getAsString(invoice);

See EhfInvoiceGeneratorTest.java for a complete working example with all fields populated.


Norwegian VAT Code Mapping

The NorwegianVatMapper translates internal Norwegian accounting system codes to PEPPOL-compliant UNCL5305 category codes.

Norwegian MVA-kode PEPPOL Category Description
3, 3U, 31, 31U, 32, 33, 33U S Standard rate (25%, 15%, 12%)
5, 5U Z Zero rated goods (books, used cars, etc.)
51 AE Reverse charge (domestic construction B2B)
52 G Free export item (outside Norway)
6 E Exempt from tax (healthcare, education, etc.)
0, 7 O Outside scope of VAT entirely

Important: An unknown VAT code throws IllegalArgumentException immediately. This is intentional β€” silently defaulting to O or S on an unknown code would produce a legally non-compliant document.

VAT Category Behavior Notes

  • S (Standard rate): Must be accompanied by the explicit percentage (25.00, 15.00, or 12.00). The percentage is part of the key for BR-CO-17 grouping.
  • Z vs E vs O: All three have a 0% rate in the XML, but they cannot be merged. They represent legally distinct tax treatments. Merging them will cause a fatal Schematron error.
  • AE (Reverse Charge): The tax amount in the subtotal must be 0.00. The buyer calculates and reports the VAT themselves.

Key DTO Fields

Document Header

Field Mandatory Notes
invoiceNo βœ… Unique invoice identifier (BR-02)
invoiceDate βœ… Issue date (BR-03)
invoiceDueDate βœ… Payment due date
currency βœ… ISO 4217 (e.g., NOK, EUR)
buyerReference ⚠️ Strongly recommended Required for all Norwegian B2G. Missing = likely rejection
invoiceType ⚠️ Currently not used β€” defaults to 380 (Commercial Invoice). See Known Limitations

Supplier (AccountingSupplierParty)

Field Notes
companyOrganizationNo Norwegian Org.nr (9 digits). Used for PEPPOL EndpointID routing
isVatRegistered If true, formats tax ID as NO{OrgNr}MVA per Norwegian requirements
companyLegalName Official name from Foretaksregisteret

Invoice Line Items

Field Notes
vatCode Required. Internal Norwegian code used by NorwegianVatMapper
vatRate Percentage value (e.g., 25.00, 0.00)
unitCode UN/ECE Rec 20 code. Examples: EA (each), HUR (hour), KGM (kg)
amount Net line amount. Must equal (price Γ— qty) βˆ’ discAmount per BR-LIN-04
disc Discount percentage (e.g., 10.00 for 10%). Maps to MultiplierFactorNumeric
type Only lines with type = 1 are included in the generated XML

VAT Breakdown (vatDetails)

The List<InvoiceVat> must contain one entry per unique combination of VAT category and rate. This is required by PEPPOL business rule BR-CO-17.

// Correct: Two separate entries for two different categories
InvoiceVat standard = new InvoiceVat();
standard.setVatCode("3");
standard.setVatRate(new BigDecimal("25.00"));
standard.setBaseAmount(new BigDecimal("1000.00"));
standard.setVatAmount(new BigDecimal("250.00"));

InvoiceVat exempt = new InvoiceVat();
exempt.setVatCode("6");       // E category
exempt.setVatRate(BigDecimal.ZERO);
exempt.setBaseAmount(new BigDecimal("500.00"));
exempt.setVatAmount(BigDecimal.ZERO);

// Do NOT merge these even though both have a 0% rate

Payment Means

The builder generates up to two PaymentMeans nodes:

  1. Domestic (always included): Local bank account (bankAccountNo) + KID (kid) for OCR reconciliation.
  2. International (when both IBAN and BIC are provided): Separate PaymentMeans node with bankAccountNoIban and bankAccountNoBic.

Attachments

Binary attachments (e.g., a PDF visual of the invoice) can be passed as List<DocumentReferenceType>:

DocumentReferenceType ref = new DocumentReferenceType();
// ... set ID, description, and embedded PDF bytes
List<DocumentReferenceType> attachments = List.of(ref);

InvoiceType invoice = factory.createInvoice(dto, attachments);

Known Limitations

The following features are not yet implemented and are candidates for future development:

  • Credit Note (type 381): dto.invoiceType field exists but is currently ignored β€” the factory always outputs 380 (Commercial Invoice). PRs welcome.
  • Customer VAT registration check: The customer tax scheme always formats as NO{OrgNr}MVA regardless of whether the customer is actually VAT-registered. This may cause issues for foreign customers or non-VAT-registered buyers.
  • Document-level allowances/charges: The LegalMonetaryTotal assumes LineExtensionAmount == TaxExclusiveAmount. Header-level discounts or charges are not yet supported.
  • nextInvoiceDate field: Defined in the DTO but not mapped to InvoicePeriod in the XML output.

Project Structure

src/
└── main/java/com/ehf/builder/
    β”œβ”€β”€ EhfInvoiceFactory.java       # Core builder β€” orchestrates the full UBL object graph
    β”œβ”€β”€ EhfInvoiceDTO.java           # Input data transfer object
    β”œβ”€β”€ EhfInvoiceLineItem.java      # Single invoice line DTO
    β”œβ”€β”€ InvoiceVat.java              # VAT subtotal / TaxSubtotal DTO
    β”œβ”€β”€ NorwegianVatMapper.java      # MVA-kode β†’ UNCL5305 category mapping
    └── VatCategoryEnum.java         # PEPPOL tax category codes (S, Z, E, AE, G, O, ...)

References


License

MIT

About

A high-performance Java builder for PEPPOL BIS Billing 3.0 & Norwegian EHF 3.0. Compliant with EN 16931 & UBL 2.1. Developed by Gus Hu (12+ YOE Architect).

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages