Skip to content

[Invoices]: NLCIUS (Dutch CIUS) e-invoicing profile for UBL 2.1 export #487

Open

Description

@nielsdrost7

Parent issue: #126 (UBL 2.1 / Peppol e-invoicing support — implement that first)

SMART Plan — [Invoices] NLCIUS Dutch CIUS profile for UBL 2.1 export

Specific

Once the base UBL 2.1 export from #126 is in place, configure it to emit the Dutch NLCIUS profile when the invoice's customer country is NL. This requires two targeted changes:

  1. recommendedForCountry('NL') (or equivalent resolver) must return UBL_21 as the e-invoicing standard.
  2. The UBL document's <cbc:CustomizationID> element must be set to urn:cen.eu:en16931:2017#compliant#urn:fdc:nen.nl:nlcius:v1.0 for NL invoices.

Measurable

  • A NL-country invoice exported as UBL 2.1 contains the NLCIUS CustomizationID in the document root.
  • recommendedForCountry('NL') returns the UBL 2.1 standard (not null or another standard).
  • PHPUnit asserts both points above.

Achievable

  1. Locate the country→standard resolver in the UBL service layer (likely under Modules/Invoices/Services/Ubl/).
  2. Add 'NL' => UblStandard::UBL_21 (or equivalent) to the country map.
  3. Inject the NLCIUS customizationID into the UBL builder when the resolved standard is UBL_21 and country is NL.
  4. Add a PHPUnit test asserting the CustomizationID value in the generated XML.

Relevant

The Netherlands mandates NLCIUS for B2G e-invoicing and it is the de-facto standard for NL B2B e-invoicing. Without this profile, Dutch users cannot submit via Peppol to government bodies or major enterprise buyers.

Time-bound

Sprint 5 — blocked on #126.


Arrange · Act · Assert

#[Test]
public function it_sets_nlcius_customization_id_for_nl_invoices(): void
{
    /* Arrange */
    $invoice = Invoice::factory()->for($this->company)->create([
        'customer_country_code' => 'NL',
    ]);

    /* Act */
    $xml = app(\Modules\Invoices\Services\Ubl\UblExportService::class)->export($invoice);

    /* Assert */
    $this->assertStringContainsString(
        'urn:cen.eu:en16931:2017#compliant#urn:fdc:nen.nl:nlcius:v1.0',
        $xml
    );
}

Activity

  1. changed the title [-]NLCIUS (Dutch CIUS).[/-] [+][Invoices]: NLCIUS (Dutch CIUS) e-invoicing standard[/+] on Jun 13, 2026
  2. added this to the v2.0.0-alpha milestone on Jun 13, 2026
  3. nielsdrost7 commented on Jun 14, 2026

    @nielsdrost7
    CollaboratorAuthor

    Sprint 5 — Scoping Plan (Epic)

    Peppol/NLCIUS is a multi-sprint epic. Full implementation is too large for a single sprint. This comment proposes a phased approach.


    Phase 1 — UBL 2.1 Export (Sprint 5 goal)

    The smallest shippable piece: generate a valid UBL 2.1 XML from an existing invoice.

    Suggested package: horstoeko/ubl or build a raw XML generator using PHP's DOMDocument.

    Files to create:

    • Modules/Invoices/Services/UblExportService.php — converts an Invoice model to UBL 2.1 XML
    • Modules/Invoices/Http/Controllers/InvoiceUblController.php — returns the XML as a download
    • Add "Download UBL XML" action to InvoicesTable and EditInvoice header actions

    Minimum required UBL fields (EN 16931 mandatory):

    • cbc:ID (invoice number), cbc:IssueDate, cbc:DueDate
    • cac:AccountingSupplierParty (seller company)
    • cac:AccountingCustomerParty (customer from Relation model)
    • cac:InvoiceLine (from InvoiceItem)
    • cac:TaxTotal, cac:LegalMonetaryTotal

    NLCIUS profile: Adds Dutch-specific fields (cbc:CustomizationID = "urn:cen.eu:en16931:2017#compliant#urn:fdc:nen.nl:nlcius:v1.0").


    Phase 2 — Validation (Sprint 6+)

    • Validate generated XML against EN 16931 Schematron rules
    • Use horstoeko/zugferd or an external validator API

    Phase 3 — Peppol Network (Sprint 7+)

    • Register with a Peppol Access Point provider (e.g. Storecove, OpenPeppol)
    • Implement send/receive via Access Point API
    • Very significant infrastructure work — requires a service provider account

    Sprint 5 deliverable: Phase 1 only — generate and download a valid UBL 2.1 XML for any invoice.
    Effort: ~8–12 hours for Phase 1.

    Note: Issues #487 and #126 describe the same feature. Recommend closing #126 as a duplicate of #487 (the more detailed one).


    Generated by Claude Code

  4. changed the title [-][Invoices]: NLCIUS (Dutch CIUS) e-invoicing standard[/-] [+][Invoices]: NLCIUS (Dutch CIUS) e-invoicing profile for UBL 2.1 export[/+] on Jun 14, 2026
  5. nielsdrost7 commented on Jul 24, 2026

    @nielsdrost7
    CollaboratorAuthor

    Confirmed — NLCIUS/UBL 2.1 Epic Status

    The existing scoping plan above is sound. Status: Phase 1 (UBL 2.1 export) is not yet started.

    Supporting models/infrastructure confirmed:

    • Modules/Invoices/Models/Invoice.php — has invoiceItems() relation, company() BelongsTo, customer linked via relation_id to Modules/Clients/Models/Relation.php
    • Relation model provides billing company name, address, email fields (cf. cac:AccountingCustomerParty EN 16931 requirement)
    • InvoiceItem has item_name, description, quantity, price, tax_rate_id (cf. cac:InvoiceLine)
    • Tax model at Modules/Core/Models/TaxRate.php provides VAT percentages (cf. cac:TaxTotal)

    Phase 1 scope (UBL 2.1 generation + download action):

    1. Modules/Invoices/Services/UblExportService.php — converts Invoice → UBL 2.1 XML (EN 16931 mandatory fields minimum, NLCIUS profile identifier optional for Phase 1)
    2. Add download action to EditInvoice header (pattern: lines 96-99 download_pdf action) and Invoices table
    3. Optional: use horstoeko/ubl package (research first) or hand-roll with DOMDocument

    Note on issue #126: Appears to request the same feature (Peppol/e-invoicing); recommend consolidation if not yet closed.

    Time-bound: Phase 1 aimed for Sprint 5 per the plan above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    refinedRefined with SMART plan / test suggestions

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions