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.3.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.3.0
File Size Uploaded
pretix_pt_invoicing-0.3.0.tar.gz 49.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pretix-pt-invoicing 0.3.0
File Interpreter ABI Platform
pretix_pt_invoicing-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 102.5 kB

Release files / pretix_pt_invoicing-0.3.0.tar.gz

Download URL pretix_pt_invoicing-0.3.0.tar.gz
Size 49.5 kB
Tags Source
SHA-256 checksum
How to use checksums
5f5dea90b5e0565053301cb4d6246af99948040d54a7c87cdee8a58b710fafbb
BLAKE2b-256 checksum
How to use checksums
125bbbd994ee6d764bb2564ec0786d28081f80242e73ec0ce3e6d18197616663
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 28, 2026.

Transparency log

Release files / pretix_pt_invoicing-0.3.0-py3-none-any.whl

Download URL pretix_pt_invoicing-0.3.0-py3-none-any.whl
Size 53.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5f5b9d59bdb33b17618134ee1cc5ea11adbf6f34ffb960bbd7852b4aeeab1905
BLAKE2b-256 checksum
How to use checksums
372d7e78eb911039acd101e4631fbf3863d5f9470543e04e8de93bcb723dc519
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 28, 2026.

Transparency log

Release history Release notifications | RSS feed

0.5.0

2 release files

0.4.0

2 release files

This release

0.3.0 This release

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