einvoice

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 27, 2026 License: BSD-3-Clause Imports: 15 Imported by: 0

README

Go Reference Go Report Card Releases

einvoice - a Go library to read, write and verify electronic invoices

This is an independently versioned public fork of speedata/einvoice. It retains the upstream history and BSD-3-Clause attribution while using the Go module path github.com/jxsl13/einvoice. See UPSTREAM.md for the sync and release policy and CONFORMANCE.md for the public validation baseline and release gates.

The stable pure-Go XRechnung rule pack is backed by published, reproducible KoSIT differential evidence. Java is used only by the isolated CI oracle and is never part of the module, release assets, or production runtime.

This library will be used to read, write and verify electronic invoices (XML) which conform to the EN 16931 standard.

Installation

go get github.com/jxsl13/einvoice

Usage

For bounded XRechnung 3.0.2 validation, use the stable rule pack:

result, err := validator.Validate(ctx, input, validator.Options{
	RulePack: validator.RulePackXRechnung302,
})
if err != nil {
	// Typed operational error: malformed input, unsupported profile, limit, etc.
}
if !result.Accepted {
	// result.Findings contains deterministic rule IDs and message codes.
}

This API supports standard UBL 2.1 Invoice/CreditNote and CII D16B XRechnung 3.0.2 documents. Extension and CVD profiles fail closed as unsupported.

The lower-level API remains available for parsing, writing, and compatibility:

invoice, err := einvoice.ParseXMLFile(filename)
if err != nil {
	...
}
// now invoice contains all the information from the XML file
// check for validation violations
err = invoice.Validate()
if err != nil {
	var valErr *einvoice.ValidationError
	if errors.As(err, &valErr) {
		for _, v := range valErr.Violations() {
			fmt.Printf("Error: %s - %s\n", v.Rule.Code, v.Text)
		}
		for _, w := range valErr.Warnings() {
			fmt.Printf("Warning: %s - %s\n", w.Rule.Code, w.Text)
		}
	}
} else {
	// Validation passed - check for recommendations
	for _, w := range invoice.Warnings() {
		fmt.Printf("Recommendation: %s - %s\n", w.Rule.Code, w.Text)
	}
}

Building and validating an invoice programmatically:

import "errors"

func buildInvoice() error {
	inv := &einvoice.Invoice{
		InvoiceNumber: "INV-001",
		// ... set all required fields
	}

	// Validate before writing
	if err := inv.Validate(); err != nil {
		var valErr *einvoice.ValidationError
		if errors.As(err, &valErr) {
			for _, v := range valErr.Violations() {
				fmt.Printf("Rule %s: %s\n", v.Rule, v.Text)
			}
		}
		return err
	}

	return inv.Write(os.Stdout)
}

Round-trip: parsing and writing back:

func dothings() error {
	inv, err := einvoice.ParseXMLFile("...")
	if err != nil {
		return err
	}

	// Write back in the same format (CII or UBL)
	return inv.Write(os.Stdout)
}
Intelligent Validation with Auto-Detection

The Validate() method automatically detects and applies the appropriate validation rules:

  • EN 16931 Core Rules: Always validated for all invoices
  • PEPPOL BIS Billing 3.0: Auto-detected based on specification identifier (BT-24)
  • Country-Specific Rules: Auto-detected based on seller country (future: DK, IT, NL, NO, SE)

Example of a PEPPOL invoice being automatically validated:

inv := &einvoice.Invoice{
	GuidelineSpecifiedDocumentContextParameter: "urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0",
	BPSpecifiedDocumentContextParameter: "urn:fdc:peppol.eu:2017:poacc:billing:01:1.0",
	// ... other fields
}

// Automatically validates both EN 16931 AND PEPPOL rules
if err := inv.Validate(); err != nil {
	// Handle validation errors
}

No need to call separate validation methods - Validate() handles everything automatically!

Warnings vs Errors

The validation framework distinguishes between errors (hard requirements) and warnings (recommendations):

  • Errors: Violations of "must" requirements cause Validate() to return an error
  • Warnings: Violations of "should" recommendations don't fail validation but are reported
err := invoice.Validate()
if err == nil {
	// Validation passed - but check for recommendations
	if invoice.HasWarnings() {
		for _, w := range invoice.Warnings() {
			fmt.Printf("Recommendation: %s - %s\n", w.Rule.Code, w.Text)
		}
	}
}

The warning infrastructure is available for future "should" (German: "soll") rules from various CIUS specifications.

There is a dedicated example in the documentation.

Command Line Tool

A CLI tool is available for validating invoices from the command line.

Installation
go install github.com/jxsl13/einvoice/cmd/einvoice@latest
Usage

Validate an invoice and display violations in human-readable format:

einvoice validate invoice.xml

Output validation results as JSON (useful for automation and CI/CD):

einvoice validate --format json invoice.xml
Exit Codes
  • 0 - Invoice is valid (no violations)
  • 1 - Error occurred (file not found, parse error, etc.)
  • 2 - Invoice has validation violations

These exit codes make it easy to integrate the validator into shell scripts and CI/CD pipelines:

if einvoice validate invoice.xml; then
    echo "Invoice is valid!"
else
    echo "Validation failed"
fi

Current status

  • Reading and writing of EN 16931 invoices in both formats:
    • ZUGFeRD/Factur-X (CII format)
    • UBL 2.1 (Invoice and CreditNote)
  • Intelligent validation with auto-detection:
    • EN 16931 Core Rules: BR-1 to BR-65, BR-CO-, BR-DEC-
    • VAT Category Rules: BR-S-, BR-AE-, BR-E-, BR-Z-, BR-G-, BR-IC-, BR-IG-, BR-IP-, BR-O-*
    • PEPPOL BIS Billing 3.0: Auto-detected and validated (PEPPOL-EN16931-R*)
    • Single Validate() method handles all rule sets automatically
  • XML output for all ZUGFeRD profiles (Minimum, BasicWL, Basic, EN16931, Extended, XRechnung)
  • UBL 2.1 Invoice and CreditNote output with full EN 16931 compliance
  • Profile detection based on specification identifier URN (BT-24)
  • Format auto-detection when parsing (automatically recognizes CII or UBL)
  • Round-trip support: parse and write back in the same format

Contributing

We welcome contributions! Please see CONTRIBUTING.md for:

  • Development setup and prerequisites
  • Running tests and checking coverage
  • Code style and conventions
  • Pull request process
  • How to work with test fixtures

Test Fixtures

Test fixtures are organized by profile and format in the testdata/ directory. See testdata/README.md for:

  • Directory structure and organization
  • Fixture sources and provenance (from official EN 16931 and PEPPOL test suites)
  • How to add new fixtures
  • Usage patterns in tests

Documentation

Index

Examples

Constants

View Source
const (
	// EAS0002 is SIRENE - French business registry system identifier.
	EAS0002 = "0002"

	// EAS0007 is Organisationsnummer - Swedish legal entity identifier.
	EAS0007 = "0007"

	// EAS0009 is SIRET-CODE - French establishment identifier.
	EAS0009 = "0009"

	// EAS0037 is LY-tunnus - Finnish organization identifier.
	EAS0037 = "0037"

	// EAS0060 is Data Universal Numbering System (D-U-N-S) Number.
	// Widely used international business identifier (9 digits).
	EAS0060 = "0060"

	// EAS0088 is EAN Location Code / Global Location Number (GLN).
	// Used for identifying parties and locations in supply chains (13 digits).
	EAS0088 = "0088"

	// EAS0096 is Danish CVR (Central Business Register) number.
	EAS0096 = "0096"

	// EAS0130 is Global Legal Entity Identifier (LEI).
	// ISO 17442 standard identifier for legal entities (20 alphanumeric characters).
	EAS0130 = "0130"

	// EAS0135 is Swiss Business Identification Number (UIDB).
	// Also known as Enterprise Identification Number (IDI/IDE/IDI).
	EAS0135 = "0135"

	// EAS0183 is the older code for Swiss Business Identification Number (UIDB).
	// Still in use for compatibility.
	//
	// Deprecated: use EAS0135 instead.
	EAS0183 = "0183"

	// EAS0184 is Dutch Chamber of Commerce number (KvK).
	EAS0184 = "0184"

	// EAS0188 is Belgian Crossroad Bank of Enterprises (CBE/KBO) number.
	EAS0188 = "0188"

	// EAS0190 is Norwegian Organization Number (Organisasjonsnummer).
	EAS0190 = "0190"

	// EAS0192 is German Leitweg-ID for routing to German public entities.
	EAS0192 = "0192"

	// EAS0195 is Singapore Nationwide E-Invoice Framework (InvoiceNow) identifier.
	EAS0195 = "0195"

	// EAS0196 is Icelandic national identifier (Kennitala).
	EAS0196 = "0196"

	// EAS0198 is Irish VAT registration number.
	EAS0198 = "0198"

	// EAS0204 is Portuguese VAT registration number (NIPC).
	EAS0204 = "0204"

	// EAS0208 is Belgian VAT registration number.
	EAS0208 = "0208"

	// EAS0209 is Spanish VAT registration number (NIF).
	EAS0209 = "0209"

	// EAS0210 is Italian VAT registration number (Partita IVA).
	EAS0210 = "0210"

	// EAS0211 is Dutch VAT registration number.
	EAS0211 = "0211"

	// EAS0212 is Norwegian VAT registration number (MVA).
	EAS0212 = "0212"

	// EAS0213 is Swiss VAT registration number (MWST/TVA/IVA).
	EAS0213 = "0213"

	// EAS9901 is Danish NEMHANDELSSYSTEM identifier (NemHandel).
	EAS9901 = "9901"

	// EAS9906 is Italian Codice Fiscale (tax code for individuals and entities).
	EAS9906 = "9906"

	// EAS9907 is French CHORUS Pro identifier.
	EAS9907 = "9907"

	// EAS9910 is Hungarian VAT registration number.
	EAS9910 = "9910"

	// EAS9913 is Austrian Ergänzungsregister für sonstige Betroffene (ERsB) number.
	EAS9913 = "9913"

	// EAS9914 is Austrian Firmenregister (FN) - company register number.
	EAS9914 = "9914"

	// EAS9915 is Austrian Umsatzsteueridentifikationsnummer (UID) - VAT number.
	EAS9915 = "9915"

	// EAS9918 is Latvian VAT registration number.
	EAS9918 = "9918"

	// EAS9919 is Maltese VAT registration number.
	EAS9919 = "9919"

	// EAS9920 is Slovenian VAT registration number.
	EAS9920 = "9920"

	// EAS9922 is Croatian VAT registration number (OIB).
	EAS9922 = "9922"

	// EAS9923 is Luxembourgish VAT registration number.
	EAS9923 = "9923"

	// EAS9925 is United Kingdom VAT registration number.
	EAS9925 = "9925"

	// EAS9926 is Bosnia and Herzegovina VAT registration number.
	EAS9926 = "9926"

	// EAS9927 is EU VAT registration number (generic EU VAT).
	EAS9927 = "9927"

	// EAS9928 is Belgian Crossroad Bank of Social Security number (CBSS/KSZ).
	EAS9928 = "9928"

	// EAS9929 is French SIRENE - INSEE identifier (alternative to 0002).
	EAS9929 = "9929"

	// EAS9930 is German Umsatzsteuernummer (VAT number).
	EAS9930 = "9930"

	// EAS9931 is Estonian VAT registration number.
	EAS9931 = "9931"

	// EAS9933 is Finnish Organization Identifier (Y-tunnus).
	EAS9933 = "9933"

	// EAS9934 is Swedish Organization Number (Organisationsnummer).
	EAS9934 = "9934"

	// EAS9935 is Austrian Government Agency identifier (GovAgency).
	EAS9935 = "9935"

	// EAS9936 is Norwegian Public Sector identifier.
	EAS9936 = "9936"

	// EAS9937 is Dutch Overheid identifier (Government).
	EAS9937 = "9937"

	// EAS9938 is Welsh public sector identifier.
	EAS9938 = "9938"

	// EAS9939 is Cypriot VAT registration number.
	EAS9939 = "9939"

	// EAS9940 is Danish CVR-nummer (Central Business Register).
	EAS9940 = "9940"

	// EAS9941 is Italian Sistema di Interscambio (SDI) identifier.
	// Used for the Italian electronic invoicing system.
	EAS9941 = "9941"

	// EAS9942 is German Leitweg-ID (routing identifier for public entities).
	EAS9942 = "9942"

	// EAS9943 is Estonian e-Delivery identifier.
	EAS9943 = "9943"

	// EAS9944 is Netherlands PEPPOL identifier.
	EAS9944 = "9944"

	// EAS9945 is Polish REGON (National Business Registry Number).
	EAS9945 = "9945"

	// EAS9946 is Italian SFE (Sistema Fatturazione Elettronica) identifier.
	EAS9946 = "9946"

	// EAS9947 is Romanian VAT registration number.
	EAS9947 = "9947"

	// EAS9948 is German Steuernummer (tax number).
	EAS9948 = "9948"

	// EAS9949 is Greek VAT registration number.
	EAS9949 = "9949"

	// EAS9950 is Spanish Código de Identificación Fiscal (CIF).
	EAS9950 = "9950"

	// EAS9951 is Portuguese NIPC (Número de Identificação de Pessoa Coletiva).
	EAS9951 = "9951"

	// EAS9952 is Hungarian Adószám (Tax Number).
	EAS9952 = "9952"

	// EAS9953 is Bulgarian VAT registration number.
	EAS9953 = "9953"

	// EAS9955 is Czech VAT registration number (DIČ).
	EAS9955 = "9955"

	// EAS9956 is Latvian Pievienotās vērtības nodokļa (PVN) reģistrācijas numurs.
	EAS9956 = "9956"

	// EAS9957 is French SIRET number (alternative to 0009).
	EAS9957 = "9957"

	// EAS9958 is German Vergabenummer (procurement identifier).
	EAS9958 = "9958"
)

PEPPOL Electronic Address Scheme (EAS) Codes

These constants represent commonly used Electronic Address Scheme identifiers for BT-34 (Seller electronic address) and BT-49 (Buyer electronic address).

EAS codes identify the scheme that an electronic address identifier is based on. The complete list is maintained by the Digital European Programme and updated twice yearly.

Usage: Set these as the scheme for Party.URIUniversalCommunicationScheme

Reference: https://docs.peppol.eu/poacc/billing/3.0/codelist/eas/ Full list: https://ec.europa.eu/digital-building-blocks (EAS Code List v13+)

View Source
const (
	// SpecFacturXMinimum is the Factur-X Minimum profile (lowest level).
	// Use for basic invoice data without line details.
	// Version: 1.0.7
	SpecFacturXMinimum = "urn:factur-x.eu:1p0:minimum"

	// SpecFacturXBasicWL is the Factur-X Basic WL (Without Lines) profile.
	// Use when invoice totals are needed but line item details are not required.
	// Version: 1.0.7
	SpecFacturXBasicWL = "urn:factur-x.eu:1p0:basicwl"

	// SpecFacturXBasic is the Factur-X Basic profile (EN 16931 subset).
	// This is EN 16931 compliant and includes essential invoice line items.
	// Version: 1.0.7
	SpecFacturXBasic = "urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basic"

	// SpecFacturXBasicAlt is an alternative format for Factur-X Basic profile.
	// Uses colons instead of hash symbols. Some systems accept this variant.
	// Version: 1.0
	SpecFacturXBasicAlt = "urn:cen.eu:en16931:2017:compliant:factur-x.eu:1p0:basic"

	// SpecFacturXExtended is the Factur-X Extended profile (most comprehensive).
	// This is EN 16931 conformant (superset) and includes advanced features.
	// Use for complex invoicing scenarios with all optional data.
	// Version: 1.0.7
	SpecFacturXExtended = "urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended"
)

Factur-X Specification Identifiers

Factur-X is the French/European standard for electronic invoicing, developed jointly by French and German organizations. It's based on the Cross Industry Invoice (CII) format and provides multiple profile levels.

View Source
const (
	// SpecZUGFeRDMinimum is the ZUGFeRD 2.0 Minimum profile.
	// Equivalent to Factur-X Minimum. German variant.
	// Version: 2.0+
	SpecZUGFeRDMinimum = "urn:zugferd.de:2p0:minimum"

	// SpecZUGFeRDBasic is the ZUGFeRD 2.0 Basic profile (EN 16931 subset).
	// Equivalent to Factur-X Basic. German variant.
	// Version: 2.0+
	SpecZUGFeRDBasic = "urn:cen.eu:en16931:2017#compliant#urn:zugferd.de:2p0:basic"

	// SpecZUGFeRDExtended is the ZUGFeRD 2.0 Extended profile.
	// Equivalent to Factur-X Extended. German variant.
	// Version: 2.0+
	SpecZUGFeRDExtended = "urn:cen.eu:en16931:2017#conformant#urn:zugferd.de:2p0:extended"
)

ZUGFeRD Specification Identifiers

ZUGFeRD is the German standard for electronic invoicing. Version 2.0 and later are aligned with Factur-X. ZUGFeRD 2.x is technically equivalent to Factur-X 1.0.

View Source
const (
	// SpecXRechnung20 is the XRechnung 2.0 specification identifier.
	// Required for German public sector invoicing (B2G).
	// This is EN 16931 compliant with German extensions.
	// Version: 2.0
	SpecXRechnung20 = "urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.0"

	// SpecXRechnung21 is the XRechnung 2.1 specification identifier.
	// Required for German public sector invoicing (B2G).
	// This is EN 16931 compliant with German extensions.
	// Version: 2.1
	SpecXRechnung21 = "urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.1"

	// SpecXRechnung22 is the XRechnung 2.2 specification identifier.
	// Required for German public sector invoicing (B2G).
	// This is EN 16931 compliant with German extensions.
	// Version: 2.2
	SpecXRechnung22 = "urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.2"

	// SpecXRechnung23 is the XRechnung 2.3 specification identifier.
	// Required for German public sector invoicing (B2G).
	// This is EN 16931 compliant with German extensions.
	// Version: 2.3
	SpecXRechnung23 = "urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.3"

	// SpecXRechnung30 is the XRechnung 3.0 specification identifier.
	// Required for German public sector invoicing (B2G).
	// This is EN 16931 compliant with German extensions.
	// Version: 3.0
	SpecXRechnung30 = "urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0"
)

XRechnung Specification Identifiers

XRechnung is the German implementation of EN 16931, required for invoices to German public sector entities. It adds German-specific business rules and extensions to the base EN 16931 standard.

View Source
const (
	// BPPEPPOLBilling01 is the standard PEPPOL BIS Billing 3.0 process (most common).
	// Use this for standard billing invoices and credit notes.
	BPPEPPOLBilling01 = "urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"
)

PEPPOL BIS Billing 3.0 Business Process Identifiers (BT-23)

These constants represent valid ProfileID values for PEPPOL BIS Billing 3.0. The business process identifier specifies the business process context in which the transaction appears, enabling the buyer to process the invoice appropriately.

Reference: PEPPOL-EN16931-R007 requires format: urn:fdc:peppol.eu:2017:poacc:billing:NN:1.0 Documentation: https://docs.peppol.eu/poacc/billing/3.0/

View Source
const (
	// SpecEN16931 is the pure EN 16931:2017 specification.
	// This is the base European standard without any country or domain extensions.
	// Use for standard EN 16931 compliant invoices.
	SpecEN16931 = "urn:cen.eu:en16931:2017"
)

EN 16931 Specification Identifier

EN 16931 is the European standard for electronic invoicing, mandated by the European Directive 2014/55/EU for invoices to public sector buyers.

View Source
const (
	// SpecPEPPOLBilling30 is the PEPPOL BIS Billing 3.0 specification identifier.
	// This is the required value per PEPPOL-EN16931-R004.
	SpecPEPPOLBilling30 = "urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0"
)

PEPPOL BIS Billing 3.0 Specification Identifiers (BT-24)

These constants represent valid CustomizationID values for PEPPOL BIS Billing 3.0. The specification identifier identifies the technical specification containing the total set of rules regarding semantic content, cardinalities, and business rules.

Reference: PEPPOL-EN16931-R004 requires the exact value below for PEPPOL BIS Billing 3.0 Documentation: https://docs.peppol.eu/poacc/billing/3.0/

Variables

View Source
var ErrUnsupportedSchema = errors.New("unsupported schema")

ErrUnsupportedSchema is returned when the library does not recognize the schema.

View Source
var ErrWrite = errors.New("creating the XML failed")

Functions

func GetProfileName

func GetProfileName(urn string) string

GetProfileName returns a human-readable name for a profile URN. This is useful for display purposes and user interfaces.

Returns the profile name (e.g., "Factur-X Basic", "XRechnung 3.0") or "Unknown" if the URN is not recognized.

func IsProfileURN

func IsProfileURN(urn string) bool

IsProfileURN checks if the given string is a recognized profile specification URN. This helper function can validate user input or configuration values.

Returns true if the URN matches any known profile specification identifier.

func ValidateBusinessProcessID

func ValidateBusinessProcessID(id string) error

ValidateBusinessProcessID validates that a business process identifier (BT-23) conforms to the PEPPOL-EN16931-R007 format requirement.

The format must be: urn:fdc:peppol.eu:2017:poacc:billing:NN:1.0 where NN is a two-digit process number (e.g., "01" for standard billing).

Returns nil if valid, error otherwise.

func ValidateEASCode

func ValidateEASCode(code string) error

ValidateEASCode validates that an Electronic Address Scheme code is in the correct 4-digit format (e.g., "0088", "9901").

Note: This only validates the format, not whether the code is registered in the official EAS code list. For the complete list, see: https://docs.peppol.eu/poacc/billing/3.0/codelist/eas/

Returns nil if valid, error otherwise.

func ValidatePEPPOLSpecificationID

func ValidatePEPPOLSpecificationID(id string) error

ValidatePEPPOLSpecificationID validates that a specification identifier (BT-24) matches the PEPPOL BIS Billing 3.0 requirement (PEPPOL-EN16931-R004).

This is ONLY required if you need full PEPPOL BIS Billing 3.0 compliance. You can use PEPPOL business process (BT-23) with ANY specification identifier (BT-24).

For full PEPPOL BIS Billing 3.0, the specification identifier must be exactly: urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0

Returns nil if valid, error otherwise.

Types

type AllowanceCharge

type AllowanceCharge struct {
	ChargeIndicator                       bool            // BG-20, BG-21, BG-27, BG-28
	CalculationPercent                    decimal.Decimal // BT-94, BT-101, BT-138, BT-143
	BasisAmount                           decimal.Decimal // BT-93, BT-100, BT-137, BT-142
	ActualAmount                          decimal.Decimal // BT-92, BT-99, BT-136, BT-141
	ReasonCode                            string          // BT-98, BT-105, BT-140, BT-145
	Reason                                string          // BT-97, BT-104, BT-139, BT-144
	CategoryTradeTaxType                  string          // BT-95, BT-102
	CategoryTradeTaxCategoryCode          string          // BT-95, BT-102
	CategoryTradeTaxRateApplicablePercent decimal.Decimal // BT-96, BT-103
	// contains filtered or unexported fields
}

AllowanceCharge specifies charges and deductions.

type Characteristic

type Characteristic struct {
	Description string // BT-160
	Value       string // BT-161
}

Characteristic add details to a product, BG-32.

type Classification

type Classification struct {
	ClassCode     string
	ListID        string
	ListVersionID string
	// contains filtered or unexported fields
}

Classification specifies a product classification, BT-158.

type CodeDocument

type CodeDocument int

CodeDocument contains the UNTDID 1001 document code.

func (CodeDocument) String

func (cd CodeDocument) String() string

type CodePartyType

type CodePartyType int

CodePartyType distinguishes between seller, buyer, ..

const (
	CUnknownParty CodePartyType = iota
	CSellerParty
	CBuyerParty
	CShipToParty
	CPayeeParty
)

CodePartyType represents the type of the party.

type CodeProfileType

type CodeProfileType int

CodeProfileType represents the CII subtype (extended, minimum, ...)

const (
	// CProfileUnknown is the unknown profile, zero value.
	CProfileUnknown CodeProfileType = iota
	// CProfileMinimum urn:factur-x.eu:1p0:minimum.
	CProfileMinimum
	// CProfileBasicWL urn:factur-x.eu:1p0:basicwl.
	CProfileBasicWL
	// CProfileBasic urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basic.
	CProfileBasic
	// CProfileEN16931 (previously Comfort) represents urn:cen.eu:en16931:2017.
	CProfileEN16931
	// CProfileExtended represents the urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended schema.
	CProfileExtended
	// CProfileXRechnung represents an XRechnung invoice.
	CProfileXRechnung
)

Don't change the order. extended > EN16931 > basic > basicwl > minimum.

func (CodeProfileType) String

func (cp CodeProfileType) String() string

func (CodeProfileType) ToProfileName

func (cp CodeProfileType) ToProfileName() string

ToProfileName returns the identifier for this profile such as urn:cen.eu:en16931:2017.

type CodeSchemaType

type CodeSchemaType int

CodeSchemaType represents the type of the invoice (CII or UBL).

const (
	SchemaTypeUnknown CodeSchemaType = iota // Zero value for programmatically created invoices
	CII                                     // ZUGFeRD/Factur-X (Cross Industry Invoice)
	UBL                                     // Universal Business Language
)

CodeSchemaType is the main XML flavor. Currently only CII is supported.

func (CodeSchemaType) String

func (cp CodeSchemaType) String() string

type DefinedTradeContact

type DefinedTradeContact struct {
	PersonName     string // BT-41, BT-56
	DepartmentName string // BT-41, BT-56
	EMail          string // BT-43, BT-58
	PhoneNumber    string // BT-44, BT-57

}

DefinedTradeContact represents a person. BG-6, BG-9.

type Document

type Document struct {
	IssuerAssignedID       string // BT-17, BT-18, BT-122
	URIID                  string // BT-18, BT-124
	TypeCode               string // BT-17: 50, BT-18: 130  BT-122: 916
	ReferenceTypeCode      string // BT-18
	Name                   string // BT-123
	AttachmentMimeCode     string // BT-125
	AttachmentFilename     string // BT-125
	AttachmentBinaryObject []byte // BT-125
}

Document contains a reference to a document or the document itself.

type GlobalID

type GlobalID struct {
	ID     string
	Scheme string
}

GlobalID stores a ISO/EIC 6523 encoded ID.

type Invoice

type Invoice struct {
	GuidelineSpecifiedDocumentContextParameter string                       // BT-24 (Specification identifier URN)
	DespatchAdviceReferencedDocument           string                       // BT-16
	ReceivingAdviceReferencedDocument          string                       // BT-15
	BuyerReference                             string                       // BT-10
	BPSpecifiedDocumentContextParameter        string                       // BT-23
	PayeeTradeParty                            *Party                       // BG-10
	PaymentMeans                               []PaymentMeans               // BG-16
	BillingSpecifiedPeriodStart                time.Time                    // BT-73
	BillingSpecifiedPeriodEnd                  time.Time                    // BT-74
	InvoiceDate                                time.Time                    // BT-2
	CreditorReferenceID                        string                       // BT-90
	PaymentReference                           string                       // BT-83
	TaxCurrencyCode                            string                       // BT-6
	InvoiceCurrencyCode                        string                       // BT-5
	LineTotal                                  decimal.Decimal              // BT-106
	AllowanceTotal                             decimal.Decimal              // BT-107
	ChargeTotal                                decimal.Decimal              // BT-108
	TaxBasisTotal                              decimal.Decimal              // BT-109
	TaxTotalCurrency                           string                       // BT-110
	TaxTotal                                   decimal.Decimal              // BT-110
	TaxTotalAccountingCurrency                 string                       // BT-111
	TaxTotalAccounting                         decimal.Decimal              // BT-111
	GrandTotal                                 decimal.Decimal              // BT-112
	TotalPrepaid                               decimal.Decimal              // BT-113
	RoundingAmount                             decimal.Decimal              // BT-114
	DuePayableAmount                           decimal.Decimal              // BT-115
	Buyer                                      Party                        // BG-7
	SellerTaxRepresentativeTradeParty          *Party                       // BG-11
	SellerOrderReferencedDocument              string                       // BT-14
	BuyerOrderReferencedDocument               string                       // BT-13
	ContractReferencedDocument                 string                       // BT-12
	AdditionalReferencedDocument               []Document                   // BG-24
	SpecifiedProcuringProjectID                string                       // BT-11
	SpecifiedProcuringProjectName              string                       // BT-11
	Seller                                     Party                        // BG-4
	OccurrenceDateTime                         time.Time                    // BT-72
	Notes                                      []Note                       // BG-1
	InvoiceLines                               []InvoiceLine                // BG-25
	InvoiceNumber                              string                       // BT-1
	InvoiceTypeCode                            CodeDocument                 // BT-3
	TradeTaxes                                 []TradeTax                   // BG-23
	SpecifiedTradeAllowanceCharge              []AllowanceCharge            // BG-20, BG-21
	ShipTo                                     *Party                       // BG-13
	SpecifiedTradePaymentTerms                 []SpecifiedTradePaymentTerms // BT-20
	SchemaType                                 CodeSchemaType               // UBL or CII
	InvoiceReferencedDocument                  []ReferencedDocument         // BG-3
	ReceivableSpecifiedTradeAccountingAccount  string                       // BT-19
	// contains filtered or unexported fields
}

Invoice is the main element of the e-invoice.

func ParseReader

func ParseReader(r io.Reader) (*Invoice, error)

ParseReader reads the XML from the reader and auto-detects the format (CII or UBL). It detects the format by examining the root element namespace and routes to the appropriate parser. Each parser handles its own namespace setup.

func ParseReaderContext

func ParseReaderContext(operationCtx context.Context, r io.Reader) (inv *Invoice, err error)

ParseReaderContext reads one XML invoice and stops when ctx is canceled. ParseReader remains available for callers that do not need cancellation.

func ParseXMLFile

func ParseXMLFile(filename string) (*Invoice, error)

ParseXMLFile reads the XML file at filename.

func (*Invoice) HasWarnings

func (inv *Invoice) HasWarnings() bool

HasWarnings returns true if there are any warnings from the last Validate() call.

func (*Invoice) Information

func (inv *Invoice) Information() []SemanticError

Information returns a copy of informational findings from the last validation.

func (*Invoice) IsBasic

func (inv *Invoice) IsBasic() bool

IsBasic checks if the invoice uses the Basic profile. URN: urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basic

func (*Invoice) IsBasicWL

func (inv *Invoice) IsBasicWL() bool

IsBasicWL checks if the invoice uses the Basic WL (Without Lines) profile. URN: urn:factur-x.eu:1p0:basicwl

func (*Invoice) IsEN16931

func (inv *Invoice) IsEN16931() bool

IsEN16931 checks if the invoice uses the EN 16931 profile. URN: urn:cen.eu:en16931:2017

func (*Invoice) IsExtended

func (inv *Invoice) IsExtended() bool

IsExtended checks if the invoice uses the Extended profile. URN: urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended

func (*Invoice) IsMinimum

func (inv *Invoice) IsMinimum() bool

IsMinimum checks if the invoice uses the Minimum profile. URN: urn:factur-x.eu:1p0:minimum or urn:zugferd.de:2p0:minimum

func (*Invoice) IsXRechnung

func (inv *Invoice) IsXRechnung() bool

IsXRechnung checks if the invoice uses the XRechnung profile. Supports XRechnung 2.0, 2.1, 2.2, 2.3, and 3.0. URN examples:

  • urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0
  • urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.1

func (*Invoice) MeetsProfileLevel

func (inv *Invoice) MeetsProfileLevel(minLevel int) bool

MeetsProfileLevel checks if the invoice meets or exceeds a minimum profile level. This replaces the old Profile enum comparison (inv.Profile >= targetProfile).

Example: inv.MeetsProfileLevel(3) returns true if profile is Basic, EN16931, Extended, or XRechnung

func (*Invoice) ProfileLevel

func (inv *Invoice) ProfileLevel() int

ProfileLevel returns an integer representing the profile hierarchy level. Higher numbers indicate more inclusive profiles. This is used by the writer to determine which fields to include.

Levels: 0=Unknown, 1=Minimum, 2=BasicWL, 3=Basic, 4=EN16931/PEPPOL/XRechnung, 5=Extended

func (*Invoice) UpdateApplicableTradeTax

func (inv *Invoice) UpdateApplicableTradeTax(exemptReason map[string]string)

UpdateApplicableTradeTax removes the existing trade tax lines in the invoice and re-creates new ones from the line items and document-level allowances/charges. er is a map that contains exemption reasons for each category code. According to BR-45 and category-specific rules (BR-S-8, BR-AE-8, BR-E-8, etc.), the VAT category taxable amount must include: - Sum of invoice line net amounts for that category - Minus document level allowance amounts for that category - Plus document level charge amounts for that category

func (*Invoice) UpdateTotals

func (inv *Invoice) UpdateTotals()

UpdateTotals recalculates all monetary totals according to EN 16931 business rules. This function implements the following business rules in calculation order: - BR-CO-10: LineTotal (BT-106) = Sum of all invoice line net amounts (BT-131) - BR-CO-11: AllowanceTotal (BT-107) = Sum of all document level allowance amounts (BT-92) - BR-CO-12: ChargeTotal (BT-108) = Sum of all document level charge amounts (BT-99) - BR-CO-13: TaxBasisTotal (BT-109) = LineTotal - AllowanceTotal + ChargeTotal - BR-CO-15: GrandTotal (BT-112) = TaxBasisTotal + TaxTotal (BT-110) - BR-CO-16: DuePayableAmount (BT-115) = GrandTotal - TotalPrepaid (BT-113) + RoundingAmount (BT-114)

Profile handling: Only recalculate for EN 16931 profiles that support line items. - Level 0 (unknown): Skip - may not follow EN 16931 calculation rules - Level 1 (Minimum): Skip - no line items by design, totals provided directly - Level 2 (BasicWL): Skip - no line items by design, totals provided directly - Level 3+ (Basic, EN16931, Extended, etc.): Calculate - have line items

func (*Invoice) UsesPEPPOLBusinessProcess

func (inv *Invoice) UsesPEPPOLBusinessProcess() bool

UsesPEPPOLBusinessProcess checks if an invoice uses a PEPPOL business process (BT-23).

This only checks the business process identifier format, NOT the specification. You can use PEPPOL business process with any specification (Factur-X, EN16931, etc.).

Returns true if BT-23 is set to a valid PEPPOL business process URN.

func (*Invoice) Validate

func (inv *Invoice) Validate() error

Validate checks the invoice against applicable business rules with intelligent auto-detection.

The method automatically detects which validation rules to apply based on: - Specification identifier (BT-24) for PEPPOL BIS Billing 3.0 detection - Seller country for country-specific rules (DK, IT, NL, NO, SE)

All invoices are validated against EN 16931 core rules. Additional rules are applied automatically when the invoice metadata indicates they are required.

This method clears any previous violations and warnings, then performs a fresh validation. Returns a ValidationError if violations (errors) exist, nil if invoice is valid. Warnings do NOT cause validation to fail - use Invoice.Warnings() or ValidationError.Warnings() to access them.

This method should be called: - After building an invoice programmatically - After modifying invoice data (e.g., after UpdateTotals) - Before writing XML to ensure compliance

Example:

err := inv.Validate()
if err != nil {
    var valErr *ValidationError
    if errors.As(err, &valErr) {
        for _, v := range valErr.Violations() {
            fmt.Printf("Error: %s - %s\n", v.Rule.Code, v.Text)
        }
        for _, w := range valErr.Warnings() {
            fmt.Printf("Warning: %s - %s\n", w.Rule.Code, w.Text)
        }
    }
    return err
} else {
    // Validation passed, but check for recommendations
    for _, w := range inv.Warnings() {
        fmt.Printf("Recommendation: %s - %s\n", w.Rule.Code, w.Text)
    }
}

func (*Invoice) ValidateContext

func (inv *Invoice) ValidateContext(ctx context.Context) (err error)

ValidateContext validates the invoice and stops when ctx is canceled. Validate remains available for callers that do not need cancellation.

func (*Invoice) Warnings

func (inv *Invoice) Warnings() []SemanticError

Warnings returns a copy of all validation warnings found during the last Validate() call. Warnings are recommendation violations ("soll"/"should") that don't cause validation to fail but are reported for user attention.

This method should be called after Validate() to check for recommendations even when validation passes (returns nil).

Example:

err := inv.Validate()
if err == nil {
    // Validation passed, but check for recommendations
    for _, w := range inv.Warnings() {
        fmt.Printf("Recommendation: %s - %s\n", w.Rule.Code, w.Text)
    }
}

func (*Invoice) Write

func (inv *Invoice) Write(w io.Writer) error

Write writes the invoice as XML to the given writer.

The output format is determined by the SchemaType field:

  • UBL: Outputs UBL 2.1 XML with <Invoice> root (InvoiceTypeCode 380) or <CreditNote> root (InvoiceTypeCode 381)
  • CII or SchemaTypeUnknown: Outputs ZUGFeRD/Factur-X CII format with rsm/ram/udt/qdt namespaces

Programmatically created invoices have SchemaTypeUnknown (zero value) and default to CII format for backwards compatibility.

Write does not perform validation. Consider calling Validate() before Write() to ensure the invoice meets EN 16931 requirements. You should also call UpdateApplicableTradeTax() and UpdateTotals() to calculate monetary values.

Returns ErrUnsupportedSchema if SchemaType is not recognized.

Example for CII format:

inv := &einvoice.Invoice{
	SchemaType: einvoice.CII, // or omit for default
	InvoiceNumber: "INV-001",
	// ... set required fields
}
inv.UpdateApplicableTradeTax(nil)
inv.UpdateTotals()
if err := inv.Validate(); err != nil {
	// handle validation errors
}
err := inv.Write(os.Stdout)

Example for UBL format:

inv := &einvoice.Invoice{
	SchemaType: einvoice.UBL,
	InvoiceNumber: "INV-001",
	InvoiceTypeCode: 380, // 380 = Invoice, 381 = CreditNote
	// ... set required fields
}
inv.UpdateApplicableTradeTax(nil)
inv.UpdateTotals()
err := inv.Write(os.Stdout)
Example
fixedDate, _ := time.Parse("02.01.2006", "31.12.2025")
fourteenDays := time.Hour * 24 * 14
inv := Invoice{
	InvoiceNumber:   "1234",
	InvoiceTypeCode: 380,
	GuidelineSpecifiedDocumentContextParameter: SpecEN16931,
	InvoiceDate:         fixedDate,
	OccurrenceDateTime:  fixedDate.Add(-fourteenDays),
	InvoiceCurrencyCode: "EUR",
	TaxCurrencyCode:     "EUR",
	Notes: []Note{{
		Text: "Some text",
	}},
	Seller: Party{
		Name:              "Company name",
		VATaxRegistration: "DE123456",
		PostalAddress: &PostalAddress{
			Line1:        "Line one",
			Line2:        "Line two",
			City:         "City",
			PostcodeCode: "12345",
			CountryID:    "DE",
		},
		DefinedTradeContact: []DefinedTradeContact{{
			PersonName: "Jon Doe",
			EMail:      "doe@example.com",
		}},
	},
	Buyer: Party{
		Name: "Buyer",
		PostalAddress: &PostalAddress{
			Line1:        "Buyer line 1",
			Line2:        "Buyer line 2",
			City:         "Buyercity",
			PostcodeCode: "33441",
			CountryID:    "FR",
		},
		DefinedTradeContact: []DefinedTradeContact{{
			PersonName: "Buyer Person",
		}},
		VATaxRegistration: "FR4441112",
	},
	PaymentMeans: []PaymentMeans{
		{
			TypeCode:                                      30,
			PayeePartyCreditorFinancialAccountIBAN:        "DE123455958381",
			PayeePartyCreditorFinancialAccountName:        "My own bank",
			PayeeSpecifiedCreditorFinancialInstitutionBIC: "BANKDEFXXX",
		},
	},
	SpecifiedTradePaymentTerms: []SpecifiedTradePaymentTerms{{
		DueDate: fixedDate.Add(fourteenDays),
	}},
	InvoiceLines: []InvoiceLine{
		{
			LineID:                   "1",
			ItemName:                 "Item name one",
			BilledQuantity:           decimal.NewFromFloat(12.5),
			BilledQuantityUnit:       "C62",
			NetPrice:                 decimal.NewFromInt(100),
			TaxRateApplicablePercent: decimal.NewFromInt(19),
			Total:                    decimal.NewFromInt(1250),
			TaxTypeCode:              "VAT",
			TaxCategoryCode:          "S",
		},
		{
			LineID:                   "2",
			ItemName:                 "Item name two",
			BilledQuantity:           decimal.NewFromFloat(2),
			BilledQuantityUnit:       "HUR",
			NetPrice:                 decimal.NewFromInt(200),
			TaxRateApplicablePercent: decimal.NewFromInt(0),
			Total:                    decimal.NewFromInt(400),
			TaxTypeCode:              "VAT",
			TaxCategoryCode:          "AE",
		},
	},
}

inv.UpdateApplicableTradeTax(map[string]string{"AE": "Reason for reverse charge"})
inv.UpdateTotals()
if err := inv.Write(os.Stdout); err != nil {
	panic(err.Error())
}
Output:
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
  <rsm:ExchangedDocumentContext>
    <ram:GuidelineSpecifiedDocumentContextParameter>
      <ram:ID>urn:cen.eu:en16931:2017</ram:ID>
    </ram:GuidelineSpecifiedDocumentContextParameter>
  </rsm:ExchangedDocumentContext>
  <rsm:ExchangedDocument>
    <ram:ID>1234</ram:ID>
    <ram:TypeCode>380</ram:TypeCode>
    <ram:IssueDateTime>
      <udt:DateTimeString format="102">20251231</udt:DateTimeString>
    </ram:IssueDateTime>
    <ram:IncludedNote>
      <ram:Content>Some text</ram:Content>
    </ram:IncludedNote>
  </rsm:ExchangedDocument>
  <rsm:SupplyChainTradeTransaction>
    <ram:IncludedSupplyChainTradeLineItem>
      <ram:AssociatedDocumentLineDocument>
        <ram:LineID>1</ram:LineID>
      </ram:AssociatedDocumentLineDocument>
      <ram:SpecifiedTradeProduct>
        <ram:Name>Item name one</ram:Name>
      </ram:SpecifiedTradeProduct>
      <ram:SpecifiedLineTradeAgreement>
        <ram:NetPriceProductTradePrice>
          <ram:ChargeAmount>100</ram:ChargeAmount>
        </ram:NetPriceProductTradePrice>
      </ram:SpecifiedLineTradeAgreement>
      <ram:SpecifiedLineTradeDelivery>
        <ram:BilledQuantity unitCode="C62">12.5000</ram:BilledQuantity>
      </ram:SpecifiedLineTradeDelivery>
      <ram:SpecifiedLineTradeSettlement>
        <ram:ApplicableTradeTax>
          <ram:TypeCode>VAT</ram:TypeCode>
          <ram:CategoryCode>S</ram:CategoryCode>
          <ram:RateApplicablePercent>19</ram:RateApplicablePercent>
        </ram:ApplicableTradeTax>
        <ram:SpecifiedTradeSettlementLineMonetarySummation>
          <ram:LineTotalAmount>1250.00</ram:LineTotalAmount>
        </ram:SpecifiedTradeSettlementLineMonetarySummation>
      </ram:SpecifiedLineTradeSettlement>
    </ram:IncludedSupplyChainTradeLineItem>
    <ram:IncludedSupplyChainTradeLineItem>
      <ram:AssociatedDocumentLineDocument>
        <ram:LineID>2</ram:LineID>
      </ram:AssociatedDocumentLineDocument>
      <ram:SpecifiedTradeProduct>
        <ram:Name>Item name two</ram:Name>
      </ram:SpecifiedTradeProduct>
      <ram:SpecifiedLineTradeAgreement>
        <ram:NetPriceProductTradePrice>
          <ram:ChargeAmount>200</ram:ChargeAmount>
        </ram:NetPriceProductTradePrice>
      </ram:SpecifiedLineTradeAgreement>
      <ram:SpecifiedLineTradeDelivery>
        <ram:BilledQuantity unitCode="HUR">2.0000</ram:BilledQuantity>
      </ram:SpecifiedLineTradeDelivery>
      <ram:SpecifiedLineTradeSettlement>
        <ram:ApplicableTradeTax>
          <ram:TypeCode>VAT</ram:TypeCode>
          <ram:CategoryCode>AE</ram:CategoryCode>
          <ram:RateApplicablePercent>0</ram:RateApplicablePercent>
        </ram:ApplicableTradeTax>
        <ram:SpecifiedTradeSettlementLineMonetarySummation>
          <ram:LineTotalAmount>400.00</ram:LineTotalAmount>
        </ram:SpecifiedTradeSettlementLineMonetarySummation>
      </ram:SpecifiedLineTradeSettlement>
    </ram:IncludedSupplyChainTradeLineItem>
    <ram:ApplicableHeaderTradeAgreement>
      <ram:SellerTradeParty>
        <ram:Name>Company name</ram:Name>
        <ram:DefinedTradeContact>
          <ram:PersonName>Jon Doe</ram:PersonName>
          <ram:EmailURIUniversalCommunication>
            <ram:URIID>doe@example.com</ram:URIID>
          </ram:EmailURIUniversalCommunication>
        </ram:DefinedTradeContact>
        <ram:PostalTradeAddress>
          <ram:PostcodeCode>12345</ram:PostcodeCode>
          <ram:LineOne>Line one</ram:LineOne>
          <ram:LineTwo>Line two</ram:LineTwo>
          <ram:CityName>City</ram:CityName>
          <ram:CountryID>DE</ram:CountryID>
        </ram:PostalTradeAddress>
        <ram:SpecifiedTaxRegistration>
          <ram:ID schemeID="VA">DE123456</ram:ID>
        </ram:SpecifiedTaxRegistration>
      </ram:SellerTradeParty>
      <ram:BuyerTradeParty>
        <ram:Name>Buyer</ram:Name>
        <ram:DefinedTradeContact>
          <ram:PersonName>Buyer Person</ram:PersonName>
        </ram:DefinedTradeContact>
        <ram:PostalTradeAddress>
          <ram:PostcodeCode>33441</ram:PostcodeCode>
          <ram:LineOne>Buyer line 1</ram:LineOne>
          <ram:LineTwo>Buyer line 2</ram:LineTwo>
          <ram:CityName>Buyercity</ram:CityName>
          <ram:CountryID>FR</ram:CountryID>
        </ram:PostalTradeAddress>
        <ram:SpecifiedTaxRegistration>
          <ram:ID schemeID="VA">FR4441112</ram:ID>
        </ram:SpecifiedTaxRegistration>
      </ram:BuyerTradeParty>
    </ram:ApplicableHeaderTradeAgreement>
    <ram:ApplicableHeaderTradeDelivery>
      <ram:ActualDeliverySupplyChainEvent>
        <ram:OccurrenceDateTime>
          <udt:DateTimeString format="102">20251217</udt:DateTimeString>
        </ram:OccurrenceDateTime>
      </ram:ActualDeliverySupplyChainEvent>
    </ram:ApplicableHeaderTradeDelivery>
    <ram:ApplicableHeaderTradeSettlement>
      <ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
      <ram:SpecifiedTradeSettlementPaymentMeans>
        <ram:TypeCode>30</ram:TypeCode>
        <ram:PayeePartyCreditorFinancialAccount>
          <ram:IBANID>DE123455958381</ram:IBANID>
          <ram:AccountName>My own bank</ram:AccountName>
        </ram:PayeePartyCreditorFinancialAccount>
        <ram:PayeeSpecifiedCreditorFinancialInstitution>
          <ram:BICID>BANKDEFXXX</ram:BICID>
        </ram:PayeeSpecifiedCreditorFinancialInstitution>
      </ram:SpecifiedTradeSettlementPaymentMeans>
      <ram:ApplicableTradeTax>
        <ram:CalculatedAmount>237.50</ram:CalculatedAmount>
        <ram:TypeCode>VAT</ram:TypeCode>
        <ram:BasisAmount>1250.00</ram:BasisAmount>
        <ram:CategoryCode>S</ram:CategoryCode>
        <ram:RateApplicablePercent>19</ram:RateApplicablePercent>
      </ram:ApplicableTradeTax>
      <ram:ApplicableTradeTax>
        <ram:CalculatedAmount>0.00</ram:CalculatedAmount>
        <ram:TypeCode>VAT</ram:TypeCode>
        <ram:ExemptionReason>Reason for reverse charge</ram:ExemptionReason>
        <ram:BasisAmount>400.00</ram:BasisAmount>
        <ram:CategoryCode>AE</ram:CategoryCode>
        <ram:RateApplicablePercent>0</ram:RateApplicablePercent>
      </ram:ApplicableTradeTax>
      <ram:SpecifiedTradePaymentTerms>
        <ram:DueDateDateTime>
          <udt:DateTimeString format="102">20260114</udt:DateTimeString>
        </ram:DueDateDateTime>
      </ram:SpecifiedTradePaymentTerms>
      <ram:SpecifiedTradeSettlementHeaderMonetarySummation>
        <ram:LineTotalAmount>1650.00</ram:LineTotalAmount>
        <ram:TaxBasisTotalAmount>1650.00</ram:TaxBasisTotalAmount>
        <ram:TaxTotalAmount currencyID="EUR">237.50</ram:TaxTotalAmount>
        <ram:GrandTotalAmount>1887.50</ram:GrandTotalAmount>
        <ram:DuePayableAmount>1887.50</ram:DuePayableAmount>
      </ram:SpecifiedTradeSettlementHeaderMonetarySummation>
    </ram:ApplicableHeaderTradeSettlement>
  </rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>

type InvoiceLine

type InvoiceLine struct {
	LineID                                    string            // BT-126
	ParentLineID                              string            // BT-X-304 (EXTENDED): parent line ID for sub invoice lines
	LineStatusCode                            string            // BT-X-7 (EXTENDED): invoice line status code
	LineStatusReasonCode                      string            // BT-X-8 (EXTENDED): invoice line subtype (DETAIL, GROUP, INFORMATION)
	ArticleNumber                             string            // BT-155 seller assigned ID
	ArticleNumberBuyer                        string            // BT-156 buyer assigned ID
	ItemName                                  string            // BT-153
	AdditionalReferencedDocumentID            string            // BT-128
	AdditionalReferencedDocumentTypeCode      string            // BT-128
	AdditionalReferencedDocumentRefTypeCode   string            // BT-128
	BillingSpecifiedPeriodStart               time.Time         // BT-134
	BillingSpecifiedPeriodEnd                 time.Time         // BT-135
	BuyerOrderReferencedDocument              string            // BT-132
	Note                                      string            // BT-127
	GlobalID                                  string            // BT-157
	GlobalIDType                              string            // BT-157
	Characteristics                           []Characteristic  // BG-32
	ProductClassification                     []Classification  // BT-158, UNTDID 7143
	Description                               string            // BT-154 (optional)
	OriginTradeCountry                        string            // BT-159 (optional) alpha-2 code ISO 3166-1 such as DE, US,...
	ReceivableSpecifiedTradeAccountingAccount string            // BT-133
	GrossPrice                                decimal.Decimal   // BT-148
	BasisQuantity                             decimal.Decimal   // BT-149
	BasisQuantityUnit                         string            // BT-149
	InvoiceLineAllowances                     []AllowanceCharge // BG-27
	InvoiceLineCharges                        []AllowanceCharge // BG-28
	AppliedTradeAllowanceCharge               []AllowanceCharge // BT-147
	NetPrice                                  decimal.Decimal   // BT-146
	NetBilledQuantity                         decimal.Decimal   // BT-149
	NetBilledQuantityUnit                     string            // BT-150
	BilledQuantity                            decimal.Decimal   // BT-129
	BilledQuantityUnit                        string            // BT-130
	TaxTypeCode                               string            // BT-151 must be VAT
	TaxCategoryCode                           string            // BT-151
	TaxRateApplicablePercent                  decimal.Decimal   // BT-152
	Total                                     decimal.Decimal   // BT-131
	// contains filtered or unexported fields
}

InvoiceLine represents one position of items.

type Note

type Note struct {
	Text        string // BT-22
	SubjectCode string // BT-21
}

Note contains text and the subject code.

func (Note) String

func (n Note) String() string

type Party

type Party struct {
	ID                              []string                    // BT-29, BT-46, BT-60, BT-71
	GlobalID                        []GlobalID                  // BT-29, BT-64, BT-60, BT-71
	Name                            string                      // BT-27, BT-44, BT-59, BT-62, BT-70
	DefinedTradeContact             []DefinedTradeContact       // BG-9
	Description                     string                      // BT-33
	URIUniversalCommunication       string                      // BT-34, BT-49
	URIUniversalCommunicationScheme string                      // BT-34, BT-49
	PostalAddress                   *PostalAddress              // BG-5, BG-8
	SpecifiedLegalOrganization      *SpecifiedLegalOrganization // BT-30, BT-47, BT-61
	VATaxRegistration               string                      // BT-31, BT-48, BT-63
	FCTaxRegistration               string                      // BT-32
	// contains filtered or unexported fields
}

Party represents buyer and seller.

type PaymentMeans

type PaymentMeans struct {
	TypeCode                                             int    // BT-81
	Information                                          string // BT-82
	PayeePartyCreditorFinancialAccountIBAN               string // BT-84
	PayeePartyCreditorFinancialAccountName               string // BT-85
	PayeePartyCreditorFinancialAccountProprietaryID      string // BT-84
	PayeeSpecifiedCreditorFinancialInstitutionBIC        string // BT-86
	PayerPartyDebtorFinancialAccountIBAN                 string // BT-91
	ApplicableTradeSettlementFinancialCardID             string // BT-87
	ApplicableTradeSettlementFinancialCardCardholderName string // BT-88
	// contains filtered or unexported fields
}

PaymentMeans represents a payment means.

type PostalAddress

type PostalAddress struct {
	CountryID              string
	PostcodeCode           string // BT-38, BT-53, BT-67, BT-78
	Line1                  string // BT-35, BT-50, BT-64, BT-75
	Line2                  string // BT-36, BT-51, BT-65, BT-76
	Line3                  string // BT-162, BT-163, BT-164, BT-165
	City                   string // BT-37, BT-52, BT-66, BT-77
	CountrySubDivisionName string // BT-39, BT-54, BT-68, BT-79
}

A PostalAddress belongs to the seller, buyer and some other entities.

type ReferencedDocument

type ReferencedDocument struct {
	Date time.Time // BT-26
	ID   string    // BT-25
}

ReferencedDocument links to a previous invoice BG-3.

type SemanticError

type SemanticError struct {
	Rule rules.Rule // The business rule that was violated
	Text string     // Human-readable description with actual values
}

SemanticError contains a business rule violation found during validation.

type SpecifiedLegalOrganization

type SpecifiedLegalOrganization struct {
	ID                  string //  BT-30, BT-47, BT-61
	Scheme              string // BT-30, BT-61
	TradingBusinessName string // BT-28, BT-45

}

SpecifiedLegalOrganization represents a division BT-30, BT-47, BT-61.

type SpecifiedTradePaymentTerms

type SpecifiedTradePaymentTerms struct {
	Description          string    // BT-20
	DueDate              time.Time // BT-9
	DirectDebitMandateID string    // BT-89
}

SpecifiedTradePaymentTerms is unbounded in extended.

type TradeTax

type TradeTax struct {
	CalculatedAmount    decimal.Decimal // BT-117
	BasisAmount         decimal.Decimal // BT-116
	TypeCode            string          // BT-118-0
	CategoryCode        string          // BT-118
	Percent             decimal.Decimal // BT-119
	ExemptionReason     string          // BT-120
	ExemptionReasonCode string          // BT-121
	TaxPointDate        time.Time       // BT-7
	DueDateTypeCode     string          // BT-8
	// contains filtered or unexported fields
}

TradeTax is the VAT breakdown for each percentage.

func (TradeTax) String

func (tt TradeTax) String() string

type ValidationError

type ValidationError struct {
	// contains filtered or unexported fields
}

ValidationError is returned when invoice validation fails. It contains all EN 16931 business rule violations found during validation, as well as any warnings (recommendation violations).

Example usage:

err := inv.Validate()
if err != nil {
    var valErr *ValidationError
    if errors.As(err, &valErr) {
        for _, v := range valErr.Violations() {
            fmt.Printf("Error: %s - %s\n", v.Rule.Code, v.Text)
        }
        for _, w := range valErr.Warnings() {
            fmt.Printf("Warning: %s - %s\n", w.Rule.Code, w.Text)
        }
    }
}

func (*ValidationError) Count

func (e *ValidationError) Count() int

Count returns the number of validation violations (errors).

func (*ValidationError) Error

func (e *ValidationError) Error() string

Error implements the error interface. Returns a human-readable description of the validation failure.

func (*ValidationError) HasRule

func (e *ValidationError) HasRule(rule rules.Rule) bool

HasRule checks if a specific business rule violation exists. Accepts a Rule constant (e.g., rules.BR1, rules.BRS8, rules.BRCO14).

Example:

if valErr.HasRule(rules.BR1) {
    // Handle missing specification identifier
}

func (*ValidationError) HasRuleCode

func (e *ValidationError) HasRuleCode(code string) bool

HasRuleCode checks if a specific business rule code violation exists. The code parameter should be a business rule identifier string like "BR-1", "BR-S-8", etc.

Example:

if valErr.HasRuleCode("BR-1") {
    // Handle missing specification identifier
}

func (*ValidationError) HasWarnings

func (e *ValidationError) HasWarnings() bool

HasWarnings returns true if there are any warnings.

func (*ValidationError) Information

func (e *ValidationError) Information() []SemanticError

Information returns a copy of non-rejecting informational findings.

func (*ValidationError) Violations

func (e *ValidationError) Violations() []SemanticError

Violations returns a copy of all validation violations. This ensures the internal violations slice cannot be modified externally.

func (*ValidationError) WarningCount

func (e *ValidationError) WarningCount() int

WarningCount returns the number of validation warnings.

func (*ValidationError) Warnings

func (e *ValidationError) Warnings() []SemanticError

Warnings returns a copy of all validation warnings. Warnings are recommendation violations ("soll"/"should") that don't cause validation to fail but are reported for user attention. This ensures the internal warnings slice cannot be modified externally.

Directories

Path Synopsis
cmd
checkrulecoverage command
Command checkrulecoverage verifies that every predicate in an enabled inventory capability is referenced by production validation code.
Command checkrulecoverage verifies that every predicate in an enabled inventory capability is referenced by production validation code.
compareoracle command
Command compareoracle compares native pure-Go validation results with pinned KoSIT VARL reports.
Command compareoracle compares native pure-Go validation results with pinned KoSIT VARL reports.
einvoice command
Command einvoice validates electronic invoices against EN 16931 business rules.
Command einvoice validates electronic invoices against EN 16931 business rules.
gencodelists command
gencodelists generates code lists for human-readable descriptions of codes used in electronic invoicing (UNTDID, UNECE, etc.).
gencodelists generates code lists for human-readable descriptions of codes used in electronic invoicing (UNTDID, UNECE, etc.).
genruleinventory command
Command genruleinventory generates or verifies the pinned XRechnung rule inventory.
Command genruleinventory generates or verifies the pinned XRechnung rule inventory.
genrules command
genrules generates Go code from EN 16931 schematron specifications.
genrules generates Go code from EN 16931 schematron specifications.
genxsdassets command
Command genxsdassets builds the deterministic, unmodified XSD bundle used by the production validator.
Command genxsdassets builds the deterministic, unmodified XSD bundle used by the production validator.
internal
kositreport
Package kositreport parses the stable, machine-readable subset of KoSIT validator assessment reports used by the conformance parity gate.
Package kositreport parses the stable, machine-readable subset of KoSIT validator assessment reports used by the conformance parity gate.
ruleinventory
Package ruleinventory extracts a deterministic rule inventory from pinned Schematron sources.
Package ruleinventory extracts a deterministic rule inventory from pinned Schematron sources.
xsdvalidate
Package xsdvalidate validates invoice XML against the pinned, embedded XML schemas without filesystem or network access.
Package xsdvalidate validates invoice XML against the pinned, embedded XML schemas without filesystem or network access.
pkg
codelists
Package codelists provides human-readable descriptions for standard code lists used in electronic invoicing (UNTDID, UNECE, etc.).
Package codelists provides human-readable descriptions for standard code lists used in electronic invoicing (UNTDID, UNECE, etc.).
Package rules contains EN 16931 business rule definitions.
Package rules contains EN 16931 business rule definitions.
Package validator provides the bounded, context-aware validation API.
Package validator provides the bounded, context-aware validation API.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL