Skip to main content

faturapt

CI PyPI Versões de Python Licença: MIT

Lê e valida o código QR das faturas portuguesas (o que a AT exige desde 2022, Portaria n.º 195/2020) e NIFs. Python puro, sem dependências obrigatórias, com tipos.

>>> import faturapt
>>> inv = faturapt.parse("A:500000000*B:999999990*C:PT*D:FS*E:N*F:20261015*G:FS 01/1234"
...                      "*H:JJ3XY2KD-1234*I1:PT*I7:10.00*I8:2.30*N:2.30*O:12.30*Q:Ab1z*R:1234")
>>> inv.document_type_name, inv.document_date, inv.total
('Fatura simplificada', datetime.date(2026, 10, 15), Decimal('12.30'))
>>> inv.is_final_consumer
True
>>> faturapt.check(inv)      # NIFs e contas; lista vazia = tudo certo
[]
>>> faturapt.nif_type("PT 123 456 789")
<NifType.INDIVIDUAL: 'pessoa singular'>

Instalar

pip install faturapt             # só texto: sem dependências
pip install 'faturapt[image]'    # também lê fotografias (Pillow e zxing-cpp)
>>> fatura = faturapt.read_image("talao.jpg")    # doctest: +SKIP
>>> fatura.total, faturapt.check(fatura)          # doctest: +SKIP
(Decimal('12.30'), [])

O que faz

  • parse(texto): converte o texto do QR num InvoiceQR (datas em date, valores em Decimal, IVA por espaço fiscal: continente, Açores e Madeira). Lança QRCodeError, com a mensagem em português, se faltarem campos obrigatórios, houver campos repetidos, desconhecidos ou acima do tamanho máximo, ou valores mal formados.
  • check(fatura): devolve os problemas de conteúdo: campos fora de ordem, valores sem duas casas decimais, NIFs inválidos, ATCUD que não acaba no número do documento (G) ou documento (G) de outro tipo que não o D, total de impostos (N) diferente de IVA + selo, ou total (O) diferente de bases + não sujeito + impostos.
  • fatura.to_text(): o caminho inverso, para quem gera faturas: escreve o texto do QR pela ordem da especificação, com duas casas decimais, e recusa valores acima do tamanho máximo. parse(fatura.to_text()) devolve sempre a mesma fatura (os testes confirmam-no com o Hypothesis, em faturas geradas ao acaso).
  • is_valid_nif, nif_type, normalize_nif: dígito de controlo, prefixos e tipo de contribuinte (pessoa singular, coletiva, condomínio, …). Aceita espaços, pontos e o prefixo PT.
  • read_image(imagem): encontra o QR da fatura numa fotografia ou digitalização (caminho, bytes ou imagem do Pillow) e lê-o com o parse. Respeita a orientação EXIF do telemóvel e, se houver outros QR na imagem (um site, uma promoção), escolhe o da fatura. Precisa de faturapt[image].
  • Linha de comandos: faturapt "A:...*B:..." (ou pelo stdin) ou faturapt -i talao.jpg mostra a fatura em JSON. Sai com 0 se estiver tudo certo, com 1 se houver problemas e com 2 se o texto ou a imagem não tiverem um QR válido.

As regras seguem as especificações técnicas da AT (versão 1.0, agosto de 2020), e os quatro exemplos do documento fazem parte dos testes. O parse recusa o que não se consegue ler (campos desconhecidos, repetidos ou acima do tamanho máximo, obrigatórios em falta); o check aponta o resto (campos fora de ordem, valores sem duas casas decimais, NIFs e contas).

Campos do QR

Chave Campo InvoiceQR
A, B, C NIF do emitente, NIF e país do adquirente issuer_nif, buyer_nif, buyer_country
D, E, F, G Tipo, estado, data e identificação do documento document_type, document_status, document_date, document_id
H ATCUD atcud
I1–I8, J1–J8, K1–K8 IVA por espaço fiscal (isento, reduzida, intermédia, normal) taxes (TaxBreakdown)
L, M, N, O, P Não sujeito, selo, total de impostos, total, retenção na fonte non_taxable, stamp_duty, total_taxes, total, withholding
Q, R, S 4 caracteres do hash, n.º do certificado, outras informações hash_chars, certificate, other_info

Desenvolvimento

uv sync --all-extras                      # ambiente com as dependências de desenvolvimento e de imagem
uv run pytest                             # testes, com cobertura mínima de 95 %
uv run ruff check . && uv run ruff format --check . && uv run mypy

O CI corre o mesmo em Python 3.10 a 3.14. Para publicar uma versão: atualizar __version__, passar as entradas de "Por publicar" do CHANGELOG.md para a versão nova, com a data, e criar uma tag vX.Y.Z. O workflow release.yml publica no PyPI por trusted publishing (sem tokens guardados no GitHub).

Licença

MIT.

Metadata

Release files for faturapt 0.1.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 faturapt 0.1.0
File Size Uploaded Provenance Actions
faturapt-0.1.0.tar.gz 101.4 kB With provenance Details for faturapt-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for faturapt 0.1.0
File Interpreter ABI Platform Actions
faturapt-0.1.0-py3-none-any.whl Python 3 none any Details for faturapt-0.1.0-py3-none-any.whl

Total release size: 114.8 kB

Release files / faturapt-0.1.0.tar.gz

Download URL faturapt-0.1.0.tar.gz
Size 101.4 kB
Tags Source
SHA-256 checksum
How to use checksums
8a08cd26412a32345c6de198cf27bdbf7cad43d94d570b4f417885c6dc23895a
BLAKE2b-256 checksum
How to use checksums
e390fa569f33ecdb8261eeff0f33fb021a8fd1922a70bd969bb648f8a425ce16
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 Oct 21, 2026.

Transparency log

Release files / faturapt-0.1.0-py3-none-any.whl

Download URL faturapt-0.1.0-py3-none-any.whl
Size 13.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
20c9d80ae6d45fa045401d719851de2aecda9dcd5c572d1a904fb201d32d1aa3
BLAKE2b-256 checksum
How to use checksums
88c2d442b155c0c1bf9951d18034c99070da46adcf1b5def1c3a4cd7fc04ff34
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 Oct 21, 2026.

Transparency log

Security for faturapt 0.1.0

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.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for faturapt-0.1.0.tar.gz

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 Oct 21, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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