https://github.com/alexzeitler/zugpferd
ZUGFeRD / XRECHNUNG / DIN EN 16931 E-Invoicing for Ruby
https://github.com/alexzeitler/zugpferd
invoicing ruby ruby-gem xrechnung zugferd
Last synced: 4 months ago
JSON representation
ZUGFeRD / XRECHNUNG / DIN EN 16931 E-Invoicing for Ruby
- Host: GitHub
- URL: https://github.com/alexzeitler/zugpferd
- Owner: AlexZeitler
- License: mit
- Created: 2026-02-14T21:13:57.000Z (5 months ago)
- Default Branch: master
- Last Pushed: 2026-02-19T11:23:16.000Z (4 months ago)
- Last Synced: 2026-02-19T15:22:30.448Z (4 months ago)
- Topics: invoicing, ruby, ruby-gem, xrechnung, zugferd
- Language: Ruby
- Homepage: https://alexzeitler.github.io/zugpferd/
- Size: 9.18 MB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# Zugpferd
A Ruby library for reading and writing **XRechnung** and **ZUGFeRD** electronic invoices (e-Rechnung) according to **EN 16931**, supporting both **UBL 2.1** and **UN/CEFACT CII** syntaxes.
Built for Ruby developers integrating XRechnung or ZUGFeRD e-invoicing into their applications.
## Features
- Syntax-agnostic data model based on EN 16931 Business Terms (BTs)
- UBL 2.1 Reader & Writer (Invoice and Credit Note)
- UN/CEFACT CII Reader & Writer
- PDF/A-3 embedding via Ghostscript — create ZUGFeRD / Factur-X hybrid invoices
- XSD and Schematron validation (EN 16931 + XRechnung) — optional, requires Java + Saxon
- Supported document types:
- `380` — Commercial Invoice
- `381` — Credit Note (UBL: separate `` root element)
- `384` — Corrected Invoice
- `389` — Self-billed Invoice
- `326` — Partial Invoice
- `386` — Prepayment Invoice
- No Rails dependency
- BigDecimal for all monetary amounts
## Installation
```ruby
# Gemfile
gem "zugpferd"
```
```bash
bundle install
```
Or install directly:
```bash
gem install zugpferd
```
## Usage
### Reading a UBL invoice
```ruby
require "zugpferd"
xml = File.read("invoice_ubl.xml")
invoice = Zugpferd::UBL::Reader.new.read(xml)
puts invoice.number # BT-1
puts invoice.seller.name # BG-4
puts invoice.type_code # "380", "381", etc.
invoice.line_items.each do |line|
puts "#{line.item.name}: #{line.line_extension_amount}"
end
```
### Reading a CII invoice
```ruby
xml = File.read("invoice_cii.xml")
invoice = Zugpferd::CII::Reader.new.read(xml)
```
The data model is identical regardless of whether UBL or CII is used.
### Writing a UBL invoice
```ruby
invoice = Zugpferd::Model::Invoice.new(
number: "INV-2024-001",
issue_date: Date.today,
type_code: "380",
currency_code: "EUR",
)
invoice.seller = Zugpferd::Model::TradeParty.new(name: "Seller GmbH")
invoice.buyer = Zugpferd::Model::TradeParty.new(name: "Buyer AG")
# ... set line items, tax, totals, payment ...
xml = Zugpferd::UBL::Writer.new.write(invoice)
File.write("output.xml", xml)
```
### Writing a Credit Note
```ruby
credit_note = Zugpferd::Model::CreditNote.new(
number: "CN-2024-001",
issue_date: Date.today,
)
# The writer automatically generates instead of
xml = Zugpferd::UBL::Writer.new.write(credit_note)
```
### Converting between syntaxes
```ruby
# Read CII, write as UBL
invoice = Zugpferd::CII::Reader.new.read(cii_xml)
ubl_xml = Zugpferd::UBL::Writer.new.write(invoice)
```
### Creating a ZUGFeRD / Factur-X PDF
Requires [Ghostscript](https://ghostscript.com/) installed on the system.
```ruby
require "zugpferd"
require "zugpferd/pdf" # explicit opt-in
xml = Zugpferd::CII::Writer.new.write(invoice)
embedder = Zugpferd::PDF::Embedder.new
embedder.embed(
pdf_path: "rechnung.pdf",
xml: xml,
output_path: "rechnung_zugferd.pdf",
version: "2p1",
conformance_level: "XRECHNUNG" # use "EN 16931" for non-XRechnung invoices
)
```
### Validating an invoice
Requires Java and Saxon HE. Install via `bin/setup-schemas`.
```ruby
require "zugpferd"
require "zugpferd/validation" # explicit opt-in, requires Java + Saxon
xml = Zugpferd::CII::Writer.new.write(invoice)
validator = Zugpferd::Validation::SchematronValidator.new(schemas_path: "vendor/schemas")
errors = validator.validate(xml, rule_set: :xrechnung_cii)
fatals = errors.select { |e| e.flag == "fatal" }
if fatals.any?
fatals.each { |e| puts "[#{e.id}] #{e.text}" }
end
```
## Data Model
The model maps to the Business Groups of EN 16931:
| Class | Business Group | Description |
|-------|---------------|-------------|
| `Model::Invoice` | BG-0 | Commercial Invoice (380) |
| `Model::CreditNote` | BG-0 | Credit Note (381) |
| `Model::CorrectedInvoice` | BG-0 | Corrected Invoice (384) |
| `Model::SelfBilledInvoice` | BG-0 | Self-billed Invoice (389) |
| `Model::PartialInvoice` | BG-0 | Partial Invoice (326) |
| `Model::PrepaymentInvoice` | BG-0 | Prepayment Invoice (386) |
| `Model::TradeParty` | BG-4 / BG-7 | Seller / Buyer |
| `Model::PostalAddress` | BG-5 / BG-8 | Postal address |
| `Model::Contact` | BG-6 / BG-9 | Contact information |
| `Model::LineItem` | BG-25 | Invoice line |
| `Model::Item` | BG-31 | Item information |
| `Model::Price` | BG-29 | Price details |
| `Model::MonetaryTotals` | BG-22 | Document totals |
| `Model::TaxBreakdown` | BG-23 | VAT breakdown |
| `Model::PaymentInstructions` | BG-16 | Payment information |
| `Model::AllowanceCharge` | BG-20 / BG-21 | Allowances and charges |
## Requirements
- Ruby >= 3.2
- nokogiri ~> 1.16
- bigdecimal ~> 3.1
## Development
```bash
bundle install
bin/setup-schemas # Downloads XSD schemas, CEN Schematron, XRechnung test suite
bundle exec rake test
```
## License
MIT