Converting Italian E-Invoices (FatturaPA) to PEPPOL UBL with XSLT

In the Italian market, electronic invoicing is standardized through the FatturaPA XML format, while cross-border and European B2B integrations increasingly rely on the PEPPOL network and UBL (Universal Business Language).
Bridging these two worlds is not always straightforward.
In this article, I want to share a project I’ve been working on: an XSLT-based transformation that converts Italian electronic invoices into PEPPOL-compliant UBL invoices.

🔗 GitHub Repository
👉 https://github.com/MaverickFP/ConvertItaEInvoiceToPeppolUBLInvoice

Project Goal

The purpose of this project is simple in concept but complex in execution:

Transform an Italian electronic invoice (FatturaPA XML) into a valid UBL Invoice or CreditNote aligned with PEPPOL BIS Billing 3.0.

The transformation is implemented using:

  • XSLT 1.0 only
  • No external dependencies
  • Designed to be portable and easily integrated into existing systems (including Dynamics 365 scenarios)

Why This Matters

Italy has a very specific e-invoicing model, enforced by the SDI (Sistema di Interscambio), while PEPPOL is becoming the standard for:

  • Cross-border invoicing
  • Public sector integrations
  • Pan-European B2B exchanges

If you are working with systems like Dynamics 365 Finance & Operations, SAP, or custom integrations, you may face the need to:

  • Send Italian invoices abroad via PEPPOL
  • Normalize invoice formats across countries
  • Integrate with PEPPOL Access Points

This is exactly where an XSLT-based approach can help.

Technical Overview

The transformation takes:

  • Source: Italian e-invoice XML (FatturaElettronica / FatturaPA)
  • Target:
    • UBL Invoice
    • or UBL CreditNote
      compliant with PEPPOL BIS 3.0

Main Mapping Areas

The XSLT focuses on mapping key business data, including:

  • Supplier and customer information
  • Invoice number and date
  • Invoice lines:
    • Description
    • Quantity
    • Unit price
    • Taxable amount
  • Totals and taxes
  • Currency
  • Payment terms

The goal is to preserve all relevant fiscal and business information while adapting it to the UBL structure.

VAT Nature Mapping (Natura → PEPPOL Tax Category)

One of the most critical parts of the transformation is handling Italian VAT “Natura” codes.
Here is the current mapping implemented:

Italian NaturaPEPPOL Tax Category ID
(empty)S
N1O
N2, N2.*O
N3.1G
N3.2K
N3.3K
N3.4G
N3.5O
N3.6O
N4E
N5O
N6, N6.*AE
N7O
Other/unknownO

⚠️ This mapping may need adjustments depending on:

  • Country-specific PEPPOL rules
  • Validator configurations
  • Business requirements

Withholding Tax (Ritenuta) Handling

Another non-trivial aspect is the handling of withholding tax.
Current implementation:

  • Calculates the withholding taxable base from invoice lines where Ritenuta = SI
  • Aggregates withholding amounts from:
    • DatiRitenuta/ImportoRitenuta
  • Outputs:
    • cac:WithholdingTaxTotal
  • Uses the aggregated value as fallback in payable amount calculations

This ensures better alignment with UBL expectations while preserving Italian fiscal logic.

Validation Considerations

PEPPOL validation can be strict and varies depending on:

  • Country rulesets
  • Access Point requirements
  • Validator implementations

👉 Key recommendation:

Always validate the generated UBL XML using the same PEPPOL validator used in your production environment.

Final Thoughts

This project is still evolving and should be considered a foundation rather than a finished product.

The actual mapping logic may vary depending on:

  • Business scenarios
  • Localization requirements
  • PEPPOL community rules

However, using XSLT as a transformation layer provides:

  • Transparency
  • Maintainability
  • Easy integration into enterprise pipelines

Feedback & Contributions

If you are working with:

  • Dynamics 365 Finance & Operations
  • PEPPOL integrations
  • Electronic invoicing transformations

I’d be happy to hear your feedback or discuss improvements.

Feel free to open issues or contribute directly on GitHub.

Lascia un commento