REST API service die UBL 2.1 Invoice XML-documenten omzet naar PEPPOL BIS Billing 3.0 formaat en valideert tegen de officiële Schematron-regels.
PEPPOL BIS Billing 3.0 is een Europese standaard voor elektronische facturering, gebaseerd op UBL 2.1. Deze service:
- Converteert een generieke UBL 2.1 factuur naar een PEPPOL-conforme factuur
- Valideert de output tegen de officiële CEN EN16931 en PEPPOL Schematron-regels
- Rapporteert precies welke velden zijn aangepast en welke validatiefouten er zijn
| Stap | Omschrijving |
|---|---|
| CustomizationID | Wordt gezet naar de PEPPOL BIS 3.0 identifier |
| ProfileID | Wordt gezet naar het PEPPOL billing profiel |
| UBLVersionID | Wordt toegevoegd als 2.1 indien ontbrekend |
| InvoiceTypeCode | Wordt gezet naar 380 (commerciële factuur) indien ontbrekend |
| Verplichte velden | Controle op aanwezigheid van leverancier, klant, bedragen, belasting en factuurregels |
- Python 3.11+
- Of: Docker
# 1. Clone de repository
git clone https://github.com/bert-script/peppol.git
cd peppol
# 2. Maak een virtual environment en installeer dependencies
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
# 3. Download de officiële PEPPOL validatie-artefacten
bash scripts/download_validation_artifacts.sh
# 4. Start de server
uvicorn app.main:app --reloadDe API draait nu op http://localhost:8000. Interactieve API-documentatie is beschikbaar op http://localhost:8000/docs.
docker compose up --buildControleer of de service draait en validatie-artefacten geladen zijn.
curl http://localhost:8000/health{
"status": "healthy",
"validation_artifacts_loaded": true,
"peppol_rules_version": "3.0.20"
}Converteer een UBL 2.1 Invoice naar PEPPOL BIS Billing 3.0.
curl -X POST http://localhost:8000/convert \
-H "Content-Type: application/xml" \
-d @factuur.xmlQuery parameters:
| Parameter | Default | Omschrijving |
|---|---|---|
validate |
true |
Valideer de output na conversie |
Response:
{
"success": true,
"invoice_xml": "<?xml version='1.0' ...?>...",
"modifications": [
"CustomizationID: added 'urn:cen.eu:en16931:2017#compliant#...'",
"ProfileID: added 'urn:fdc:peppol.eu:2017:poacc:billing:01:1.0'"
],
"validation": {
"valid": true,
"cen_rules": { "errors": [], "warnings": [] },
"peppol_rules": { "errors": [], "warnings": [] }
}
}Valideer een bestaande PEPPOL-factuur zonder conversie.
curl -X POST http://localhost:8000/validate \
-H "Content-Type: application/xml" \
-d @peppol-factuur.xmlResponse:
{
"valid": false,
"cen_rules": {
"errors": [
{
"rule_id": "BR-01",
"location": "/Invoice",
"message": "An Invoice shall have a Specification identifier.",
"severity": "error"
}
],
"warnings": []
},
"peppol_rules": {
"errors": [],
"warnings": []
}
}Minimaal voorbeeld van een UBL 2.1 factuur die geconverteerd kan worden:
<?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
<cbc:ID>FACTUUR-001</cbc:ID>
<cbc:IssueDate>2024-01-15</cbc:IssueDate>
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
<cac:AccountingSupplierParty>
<cac:Party>
<cbc:EndpointID schemeID="0106">12345678</cbc:EndpointID>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Mijn Bedrijf BV</cbc:RegistrationName>
</cac:PartyLegalEntity>
<cac:PostalAddress>
<cac:Country>
<cbc:IdentificationCode>NL</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
</cac:Party>
</cac:AccountingSupplierParty>
<cac:AccountingCustomerParty>
<cac:Party>
<cbc:EndpointID schemeID="0106">87654321</cbc:EndpointID>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Klant BV</cbc:RegistrationName>
</cac:PartyLegalEntity>
<cac:PostalAddress>
<cac:Country>
<cbc:IdentificationCode>NL</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
</cac:Party>
</cac:AccountingCustomerParty>
<cac:TaxTotal>
<cbc:TaxAmount currencyID="EUR">21.00</cbc:TaxAmount>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">100.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">21.00</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>21</cbc:Percent>
<cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
</cac:TaxTotal>
<cac:LegalMonetaryTotal>
<cbc:LineExtensionAmount currencyID="EUR">100.00</cbc:LineExtensionAmount>
<cbc:TaxExclusiveAmount currencyID="EUR">100.00</cbc:TaxExclusiveAmount>
<cbc:TaxInclusiveAmount currencyID="EUR">121.00</cbc:TaxInclusiveAmount>
<cbc:PayableAmount currencyID="EUR">121.00</cbc:PayableAmount>
</cac:LegalMonetaryTotal>
<cac:InvoiceLine>
<cbc:ID>1</cbc:ID>
<cbc:InvoicedQuantity unitCode="EA">1</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">100.00</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Consultancy</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>21</cbc:Percent>
<cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">100.00</cbc:PriceAmount>
</cac:Price>
</cac:InvoiceLine>
</Invoice>peppol/
├── app/
│ ├── main.py # FastAPI app met lifespan
│ ├── config.py # Configuratie via environment variables
│ ├── routers/ # API endpoints
│ ├── services/
│ │ ├── converter.py # UBL → PEPPOL conversielogica
│ │ └── validator.py # Schematron validatie via XSLT
│ ├── models/ # Pydantic response models
│ └── utils/ # XML helpers, SVRL parser
├── tests/ # Pytest tests
├── scripts/
│ └── download_validation_artifacts.sh
├── Dockerfile
└── docker-compose.yml
source .venv/bin/activate
pytest -vDe service gebruikt de officiële pre-compiled XSLT-bestanden van OpenPEPPOL:
- CEN-EN16931-UBL.xslt — Europese Norm EN16931 bedrijfsregels
- PEPPOL-EN16931-UBL.xslt — PEPPOL-specifieke regels bovenop EN16931
Deze worden gedownload via scripts/download_validation_artifacts.sh en niet meegecommit in git.
MIT