pretix-pt-invoicing
This is a plugin for pretix that issues AT-certified invoice-receipts through a Portuguese electronic invoicing provider, automatically once an order is paid — with a Control-panel dashboard to track each issuance and retry the ones that failed.
The pretix-facing half (the order_paid hook, the Celery task, idempotency, the tracking model, the dashboard and the settings page) is provider-agnostic; each provider only supplies its own API client, payload mapping and settings fields.
Providers
Provider |
Identifier |
Status |
|---|---|---|
factpt |
Implemented, verified against a real sandbox account |
|
Moloni |
moloni |
Implemented from the published API docs, not yet run against a real account — verify before production use |
One provider is active per event.
Status
Verified against a real pretix instance and covered by a test suite. For the Fact.pt provider, the GET /taxes lookup has been exercised against a real account; invoice issuance itself hasn’t — check the “Known rough edges” section of CLAUDE.md before relying on this in production.
Installation
Install the plugin into the same Python environment as your pretix instance:
pip install pretix-pt-invoicing
Then restart your pretix server. The plugin registers itself with pretix’s plugin registry automatically via a setuptools entry point — no changes to INSTALLED_APPS are needed. You can now enable it for an event under the “plugins” tab in that event’s settings.
Development setup
Make sure that you have a working pretix development setup.
Clone this repository.
Activate the virtual environment you use for pretix development.
Execute pip install -e . (or, if you use uv, uv sync --extra test) within this directory to register this application with pretix’s plugin registry.
Execute make within this directory to compile translations.
Restart your local pretix server. You can now use the plugin from this repository for your events by enabling it in the ‘plugins’ tab in the settings.
Run make test to run the test suite and make lint to run ruff.
Configuration
Enable the plugin for an event, then open Settings → Invoicing and pick an invoicing provider. Only the selected provider’s fields are saved and used for issuance.
For Fact.pt:
API token (x-auth-token) — your Fact.pt API token, sandbox or production.
Use sandbox environment — issue against Fact.pt’s sandbox instead of production.
VAT rate — a dropdown populated live from your Fact.pt account (GET /taxes) as soon as a valid API token is entered, applied to every line of every invoice issued for this event.
Unit — Fact.pt’s fixed product-unit list (Units / Meters / Boxes / Kilograms / Liters).
Item type — service or product, per Fact.pt’s own item model.
Send the buyer’s e-mail address to Fact.pt — off by default; when on, the buyer’s e-mail is stored on the Fact.pt client record, which lets Fact.pt send them the document.
The configured VAT rate must match the rate pretix charged on the order: Fact.pt is sent the net line price and applies its own rate on top, so a mismatch would issue a document for an amount the buyer never paid. Issuance refuses, with an explicit error, rather than letting that happen.
Once an order is paid, an invoice-receipt is issued asynchronously via Celery — see the “Invoicing” entry in the event’s Control-panel sidebar for the issuance dashboard, including a “Retry” action for any issuance that failed.
Two provider-independent options sit above the provider’s own settings:
E-mail the invoice to the buyer — off by default. Sends the issued document as a PDF attachment once it is issued. pretix’s own order e-mails can’t carry it: they attach pretix’s own invoice records, and the provider’s document isn’t one.
Show the invoice on the buyer’s order page — on by default. Adds a download link next to pretix’s own invoice list, served through the plugin so the provider’s API token never leaves the server. It is authenticated by the order secret, like every other buyer-facing order link.
Every order’s page in the Control panel also gets an Invoicing panel showing what was issued for that order, with an Issue invoice now button. Use it for orders that were paid before the plugin was configured, for orders marked as paid by hand, or to re-run an issuance the provider rejected once the underlying data is fixed. Unpaid orders are never issued, whichever route triggers it.
Adding a provider
Write one package under pretix_ptinvoicing/providers/<name>/ with a subclass of providers.base.InvoiceProvider:
identifier / verbose_name — the settings value and the label shown to admins.
settings_form_class — a pretix SettingsForm with this provider’s credentials and defaults. Field names must be namespaced by hand (e.g. moloni_client_id), since pretix keeps all event settings in one flat namespace.
is_configured — False while the provider isn’t set up; issuance then skips silently.
issue(order, identifier_id) — return an IssuedDocument. Pass identifier_id through to whatever field the API dedupes on. Raise ProviderError for a rejection the provider won’t accept on retry; let transient failures propagate so the task retries them.
download(document_id) — the document’s PDF bytes.
lookups(data) — optional; {field_name: [{"id", "label"}, ...]} to turn settings fields into live dropdowns, using the values the admin has currently typed in.
deduplicates_issuance — whether the API itself rejects a second document for the same identifier_id. Leave it True only if that is really the case: it is what allows an automatic retry after a network failure. Set it False for an API with no such field, and a timed-out issuance is then left for a human to retry from the Control panel.
self.settings is the event’s settings store and is writable, so a provider with expiring credentials can cache a refreshed token there.
Then add the class to PROVIDERS in pretix_ptinvoicing/providers/__init__.py. That’s the whole registration story — no entry points, no autodiscovery, no migration.
License
Copyright 2026 Afonso Santos
Released under the terms of the Apache License 2.0, see the LICENSE file for details.
Metadata
Release files for pretix-pt-invoicing 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pretix_pt_invoicing-0.4.0.tar.gz | 56.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pretix_pt_invoicing-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 114.4 kB
Release files / pretix_pt_invoicing-0.4.0.tar.gz
| Download URL | pretix_pt_invoicing-0.4.0.tar.gz |
|---|---|
| Size | 56.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bd8946a5f05638cd7b751870d28b39b26b5c369e4a96a50c3b250d42ad377d25
|
|
BLAKE2b-256 checksum How to use checksums |
363ae7e6abdb47e276a715d6e63e87917c7bb6f75614a810abbaa41506f0362c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.
Transparency logRelease files / pretix_pt_invoicing-0.4.0-py3-none-any.whl
| Download URL | pretix_pt_invoicing-0.4.0-py3-none-any.whl |
|---|---|
| Size | 57.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
084808f0368397cff802af40e50283165531a15c0fe5f05364ee83f54cb16c73
|
|
BLAKE2b-256 checksum How to use checksums |
f03933c2850969679a7b96313535bd289a5cf7cbf6e1bca77aaab457924362d3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.
Transparency log