Skip to main content

pretix-pt-invoicing

PyPI version Supported Python versions License CI status

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

Fact.pt

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

  1. Make sure that you have a working pretix development setup.

  2. Clone this repository.

  3. Activate the virtual environment you use for pretix development.

  4. 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.

  5. Execute make within this directory to compile translations.

  6. 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)

Source distribution for pretix-pt-invoicing 0.4.0
File Size Uploaded
pretix_pt_invoicing-0.4.0.tar.gz 56.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pretix-pt-invoicing 0.4.0
File Interpreter ABI Platform
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 log

Release 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

Release history Release notifications | RSS feed

0.5.0

2 release files

This release

0.4.0 This release

2 release files

0.3.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page