Metadata-Version: 2.5
Name: erechnung-core
Version: 1.0.0
Summary: Deterministic German E-Rechnung (XRechnung) generation and validation, verified against the official KoSIT validator
Project-URL: Homepage, https://github.com/shahidkarimi/erechnung-core
Project-URL: Repository, https://github.com/shahidkarimi/erechnung-core
Project-URL: Issues, https://github.com/shahidkarimi/erechnung-core/issues
Author: Shahid Karimi
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: e-invoicing,e-rechnung,en16931,germany,invoice,kosit,ubl,xrechnung,zugferd
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Natural Language :: English
Classifier: Natural Language :: German
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Office/Business :: Financial :: Accounting
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: lxml>=5.3
Requires-Dist: pydantic>=2.9
Description-Content-Type: text/markdown

# erechnung-core

[![PyPI](https://img.shields.io/pypi/v/erechnung-core.svg)](https://pypi.org/project/erechnung-core/)
[![Python versions](https://img.shields.io/pypi/pyversions/erechnung-core.svg)](https://pypi.org/project/erechnung-core/)
[![Tests](https://github.com/shahidkarimi/erechnung-core/actions/workflows/tests.yml/badge.svg)](https://github.com/shahidkarimi/erechnung-core/actions/workflows/tests.yml)
[![Coverage](https://codecov.io/gh/shahidkarimi/erechnung-core/branch/main/graph/badge.svg)](https://codecov.io/gh/shahidkarimi/erechnung-core)
[![Licence](https://img.shields.io/pypi/l/erechnung-core.svg)](LICENSE)

Deterministic German E-Rechnung generation and validation for Python.

Takes finalized invoice data, returns an XRechnung document that the official
KoSIT validator accepts — plus a checksum, a normalized validation report, and
the exact standard versions it was built with.

It is **not** an invoicing application. It has no opinion about invoice
numbering, tax treatment, delivery, or archiving, and it never alters the values
you give it. It is the piece you drop into software that already creates
invoices.

```bash
pip install erechnung-core
```

## Quick start

```python
from erechnung_core import Invoice, KositValidator, process

invoice = Invoice.model_validate(payload)  # strict input contract
result = process(invoice, validator=KositValidator.from_manifest())

result.valid  # verified, generated, and officially validated
result.document.content  # XRechnung UBL bytes
result.document.sha256  # stable for identical input
result.validation.errors  # normalized, bilingual, rule-identified
```

Generating without validating needs no Java and no toolchain:

```python
from erechnung_core import Invoice, process

result = process(Invoice.model_validate(payload))  # verify + generate only
```

Verifying the arithmetic without generating anything:

```python
from erechnung_core import Invoice, verify

report = verify(Invoice.model_validate(payload))
report.valid
report.computed.tax_breakdown  # what the amounts should have been
```

## Official validation

Validation runs the real [KoSIT validator](https://github.com/itplr-kosit/validator)
against the official XRechnung rule bundle. That toolchain is a Java archive
with its own licence and release cadence, so it is not bundled in the wheel —
it is downloaded on demand and checksum-verified against a manifest that ships
inside the package:

```bash
erechnung-fetch-standards           # ~11 MB into ./validators/kosit
erechnung-fetch-standards --list    # manifests shipped with this version
```

Point it elsewhere with `--target`, or set `ERECHNUNG_VALIDATOR_HOME` and the
library will find it. An artifact whose checksum does not match is deleted, not
installed.

Java is required only for validation. If you have your own validator — hosted,
cached, or a test double — implement `DocumentValidator` and pass it to
`process()`; nothing else changes.

## What it guarantees

Each of these is enforced by a test, not just documented:

- **Money never becomes a float.** Amounts arrive as decimal strings; a float in
  the payload is a validation error, not a silent conversion.
- **Nothing is silently corrected.** A supplied total that disagrees with the
  calculated one is reported with both values and the difference. The generator
  serializes what it was given.
- **Verification precedes generation.** No document is produced from numbers
  that do not add up, unless you explicitly ask for one.
- **The official validator decides.** A document that was not validated is never
  reported as valid; a missing toolchain raises rather than passes.
- **Generation is byte-stable.** No timestamps, locale, or map ordering reach
  the output — which is what makes the stored checksum meaningful.
- **Standards are pinned data, not code.** Every document records the standard,
  bundle, validator, and generator versions it was made with.
- **No LLM anywhere in the pipeline.** Rule text is curated by hand.

## Errors

Findings from every layer — input contract, arithmetic, XSD, Schematron — arrive
in one shape, in English and German, keyed by rule identifier:

```python
{
    "code": "BR-CO-16",
    "category": "CALCULATION",
    "severity": "error",
    "field": "invoice.totals.payable_amount",
    "message": "The payable amount does not equal the tax inclusive amount minus "
    "the prepaid amount plus the rounding amount.",
    "message_de": "Der Zahlbetrag entspricht nicht dem Gesamtbetrag mit "
    "Umsatzsteuer abzueglich des bereits gezahlten Betrags ...",
    "context": {"supplied": "1784.00", "calculated": "1784.94", "difference": "-0.94"},
}
```

Results separate `errors`, `warnings`, and `notices`, so a "should" rule never
inflates the failure count and never disappears either.

## Supported standards

```text
XRechnung 3.0.2   bundle 2026-01-31, UBL 2.1 syntax          supported
                  urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0
KoSIT validator   1.6.2, configuration v2026-01-31           pinned
XRechnung CII                                                not yet
ZUGFeRD 2.5       EN16931 profile, PDF/A-3                   not yet
```

Covered today: standard and reduced rates, mixed rates on one invoice, reverse
charge and other exemption categories, line and document allowances and charges,
prepayments, service periods, SEPA credit transfer and direct debit with
mandate, payee (factoring), delivery party and location, invoiced object and
supporting document references, item identifiers, price discounts, and
attachments.

Six golden fixtures cover these, and every one of them is checked against the
official validator in CI on each change.

## Requirements

Python 3.10 through 3.14, `pydantic`, and `lxml`. Nothing else. A Java runtime
is needed only for official validation.

Every supported version is tested in CI, and all of them produce byte-identical
documents — the checksum of a given invoice does not depend on the interpreter
that generated it.

## Development

```bash
uv sync                              # venv, dependencies, this package
uv run erechnung-fetch-standards     # validator toolchain
uv run pytest                        # 90 tests, ~45s
uv run pytest -m "not official"      # 76 tests, ~0.4s, no Java needed
uv run pytest --cov                  # with coverage
```

Checks:

```bash
uv run ruff check . && uv run ruff format . && uv run mypy erechnung_core
```

Install the hooks with `uv run pre-commit install` to run the same checks before
each commit.

Golden fixtures live in `fixtures/scenarios/`. Each holds an `input.json` and
the `expected-xrechnung.xml` it must produce byte for byte; all of them are
additionally run through the official validator in CI. A change that alters
generated output shows up as a failing golden test, which is the point.

```text
erechnung_core/
  canonical/       EN 16931 input contract
  calculations/    independent recalculation and comparison
  xrechnung/       UBL 2.1 serializer
  validation/      KoSIT wrapper, validator protocol
  error_mapping/   curated bilingual rule catalogue
  data/            pinned standards manifests (shipped in the wheel)
  pipeline.py      verify -> generate -> validate
fixtures/          golden scenarios
tests/             unit tests and official-validator tests
```

## Scope

Deliberately excluded: invoice editing, customer and product management, email
or Peppol delivery, DATEV, bookkeeping, long-term archiving, OCR, and PDF-to-
invoice extraction. Those belong to the application using this library.

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md). Bug reports that include a minimal
anonymised invoice and the official validator's verdict are the most useful.
Security issues go through [SECURITY.md](SECURITY.md), never a public issue.

## Licence

Apache-2.0. See [LICENSE](LICENSE) and [CHANGELOG.md](CHANGELOG.md).

**Technical validity is not fiscal correctness.** This library checks that a
document conforms to EN 16931 and XRechnung rules and that its arithmetic is
self-consistent. It cannot tell whether the VAT treatment is right. Whoever
supplies the data remains responsible for its commercial, legal, and tax
accuracy, and for pinning a bundle version appropriate to the period being
invoiced. Provided without warranty; this is not tax or legal advice.
