PyNFSeNacionalGT 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pynfsenacionalgt-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +50 -0
- pynfsenacionalgt-0.1.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
- pynfsenacionalgt-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +36 -0
- pynfsenacionalgt-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +17 -0
- pynfsenacionalgt-0.1.0/.github/workflows/ci.yml +55 -0
- pynfsenacionalgt-0.1.0/.github/workflows/release.yml +28 -0
- pynfsenacionalgt-0.1.0/.gitignore +51 -0
- pynfsenacionalgt-0.1.0/CHANGELOG.md +34 -0
- pynfsenacionalgt-0.1.0/CLAUDE.md +91 -0
- pynfsenacionalgt-0.1.0/CODE_OF_CONDUCT.md +31 -0
- pynfsenacionalgt-0.1.0/CONTRIBUTING.md +55 -0
- pynfsenacionalgt-0.1.0/LICENSE +21 -0
- pynfsenacionalgt-0.1.0/PKG-INFO +301 -0
- pynfsenacionalgt-0.1.0/README.md +248 -0
- pynfsenacionalgt-0.1.0/SECURITY.md +35 -0
- pynfsenacionalgt-0.1.0/docs/conhecimento-fiscal.md +214 -0
- pynfsenacionalgt-0.1.0/docs/roadmap.md +63 -0
- pynfsenacionalgt-0.1.0/examples/config-exemplo.json +36 -0
- pynfsenacionalgt-0.1.0/examples/config-exemplo.jsonc +48 -0
- pynfsenacionalgt-0.1.0/examples/emitir_exemplo.py +26 -0
- pynfsenacionalgt-0.1.0/pyproject.toml +84 -0
- pynfsenacionalgt-0.1.0/requirements-dev.txt +913 -0
- pynfsenacionalgt-0.1.0/src/pynfsenacional/__init__.py +26 -0
- pynfsenacionalgt-0.1.0/src/pynfsenacional/assinatura.py +46 -0
- pynfsenacionalgt-0.1.0/src/pynfsenacional/certificado.py +149 -0
- pynfsenacionalgt-0.1.0/src/pynfsenacional/cli.py +83 -0
- pynfsenacionalgt-0.1.0/src/pynfsenacional/config.py +229 -0
- pynfsenacionalgt-0.1.0/src/pynfsenacional/danfse.py +34 -0
- pynfsenacionalgt-0.1.0/src/pynfsenacional/documentos.py +43 -0
- pynfsenacionalgt-0.1.0/src/pynfsenacional/dps.py +136 -0
- pynfsenacionalgt-0.1.0/src/pynfsenacional/emissor.py +150 -0
- pynfsenacionalgt-0.1.0/src/pynfsenacional/relogio.py +41 -0
- pynfsenacionalgt-0.1.0/src/pynfsenacional/sefin.py +181 -0
- pynfsenacionalgt-0.1.0/tests/conftest.py +79 -0
- pynfsenacionalgt-0.1.0/tests/golden/gabarito_config.json +26 -0
- pynfsenacionalgt-0.1.0/tests/golden/gabarito_dps_assinado.xml +18 -0
- pynfsenacionalgt-0.1.0/tests/golden/regenerar_gabarito.sh +52 -0
- pynfsenacionalgt-0.1.0/tests/test_certificado.py +61 -0
- pynfsenacionalgt-0.1.0/tests/test_cli.py +67 -0
- pynfsenacionalgt-0.1.0/tests/test_danfse.py +57 -0
- pynfsenacionalgt-0.1.0/tests/test_dps.py +103 -0
- pynfsenacionalgt-0.1.0/tests/test_emissor.py +74 -0
- pynfsenacionalgt-0.1.0/tests/test_golden.py +128 -0
- pynfsenacionalgt-0.1.0/tests/test_sefin.py +109 -0
- pynfsenacionalgt-0.1.0/tests/test_smoke.py +46 -0
- pynfsenacionalgt-0.1.0/tests/test_validacao.py +142 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: 🐞 Reportar um bug
|
|
2
|
+
description: Algo não funcionou como esperado
|
|
3
|
+
labels: ["bug"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Obrigado por reportar! ⚠️ **NÃO cole dados reais** — nada de certificados (`.pfx`), senhas,
|
|
9
|
+
CNPJ/CPF ou XML/PDF de notas reais. Reproduza com dados **fictícios** (ex.: CNPJ `11222333000181`).
|
|
10
|
+
Para **vulnerabilidades de segurança**, use o canal privado (ver `SECURITY.md`), não esta issue.
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: o-que-aconteceu
|
|
13
|
+
attributes:
|
|
14
|
+
label: O que aconteceu?
|
|
15
|
+
description: Descreva o problema e o que você esperava que acontecesse.
|
|
16
|
+
validations:
|
|
17
|
+
required: true
|
|
18
|
+
- type: textarea
|
|
19
|
+
id: reproduzir
|
|
20
|
+
attributes:
|
|
21
|
+
label: Como reproduzir
|
|
22
|
+
description: Passos / trecho de código mínimo (com dados fictícios).
|
|
23
|
+
render: python
|
|
24
|
+
validations:
|
|
25
|
+
required: true
|
|
26
|
+
- type: textarea
|
|
27
|
+
id: erro
|
|
28
|
+
attributes:
|
|
29
|
+
label: Mensagem de erro / E-code do SEFIN
|
|
30
|
+
description: Cole o traceback ou o código de erro (ex.: E0312). Remova qualquer dado real.
|
|
31
|
+
render: text
|
|
32
|
+
- type: input
|
|
33
|
+
id: versao
|
|
34
|
+
attributes:
|
|
35
|
+
label: Versão do PyNFSeNacional
|
|
36
|
+
placeholder: "0.1.0.dev0"
|
|
37
|
+
validations:
|
|
38
|
+
required: true
|
|
39
|
+
- type: input
|
|
40
|
+
id: python
|
|
41
|
+
attributes:
|
|
42
|
+
label: Versão do Python
|
|
43
|
+
placeholder: "3.12"
|
|
44
|
+
validations:
|
|
45
|
+
required: true
|
|
46
|
+
- type: dropdown
|
|
47
|
+
id: ambiente
|
|
48
|
+
attributes:
|
|
49
|
+
label: Ambiente
|
|
50
|
+
options: ["homologacao", "producao", "não cheguei a enviar (validação/local)"]
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
blank_issues_enabled: false
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: 🔒 Vulnerabilidade de segurança
|
|
4
|
+
url: https://github.com/Gomes343/PyNFSeNacional/security/advisories/new
|
|
5
|
+
about: Reporte em PRIVADO (não abra issue pública). Ver SECURITY.md.
|
|
6
|
+
- name: 💬 Dúvidas e discussões
|
|
7
|
+
url: https://github.com/Gomes343/PyNFSeNacional/discussions
|
|
8
|
+
about: Para perguntas de uso, ideias e ajuda da comunidade.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
name: 💡 Sugerir uma melhoria
|
|
2
|
+
description: Propor um recurso, suporte a município/regime, ou melhoria
|
|
3
|
+
labels: ["enhancement"]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: problema
|
|
7
|
+
attributes:
|
|
8
|
+
label: Qual problema isso resolve?
|
|
9
|
+
description: O contexto fiscal/operacional por trás da ideia.
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: proposta
|
|
14
|
+
attributes:
|
|
15
|
+
label: Proposta
|
|
16
|
+
description: O que você gostaria que o pacote fizesse.
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
- type: textarea
|
|
20
|
+
id: alternativas
|
|
21
|
+
attributes:
|
|
22
|
+
label: Alternativas consideradas
|
|
23
|
+
- type: dropdown
|
|
24
|
+
id: area
|
|
25
|
+
attributes:
|
|
26
|
+
label: Área
|
|
27
|
+
options:
|
|
28
|
+
- "Emissão (DPS/assinatura/transporte)"
|
|
29
|
+
- "DANFSe (PDF)"
|
|
30
|
+
- "Validação fiscal / E-codes"
|
|
31
|
+
- "Suporte a município/regime"
|
|
32
|
+
- "Eventos (cancelamento)"
|
|
33
|
+
- "IBS/CBS (reforma tributária)"
|
|
34
|
+
- "CLI / DX"
|
|
35
|
+
- "Documentação"
|
|
36
|
+
- "Outro"
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<!-- Obrigado pela contribuição! Preencha o que se aplica. -->
|
|
2
|
+
|
|
3
|
+
## O que muda e por quê
|
|
4
|
+
|
|
5
|
+
<!-- Descreva a mudança e a motivação (o "porquê", não só o "como"). -->
|
|
6
|
+
|
|
7
|
+
## Como testei
|
|
8
|
+
|
|
9
|
+
<!-- pytest / emissão em homologação / etc. Use sempre dados fictícios. -->
|
|
10
|
+
|
|
11
|
+
## Checklist
|
|
12
|
+
|
|
13
|
+
- [ ] `ruff check .`, `mypy` e `pytest` passam localmente
|
|
14
|
+
- [ ] **Nenhum** dado sensível no diff (certificado, senha, `.env`, CNPJ/CPF ou nota real)
|
|
15
|
+
- [ ] Regra fiscal nova documentada em `docs/conhecimento-fiscal.md` (se aplicável)
|
|
16
|
+
- [ ] Mexeu em DPS/assinatura? O *golden* foi atualizado e o motivo está explicado (se aplicável)
|
|
17
|
+
- [ ] Atualizei o `CHANGELOG.md` (se for mudança relevante ao usuário)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master, main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
test:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
strategy:
|
|
15
|
+
fail-fast: false
|
|
16
|
+
matrix:
|
|
17
|
+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
22
|
+
uses: actions/setup-python@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: ${{ matrix.python-version }}
|
|
25
|
+
|
|
26
|
+
- name: Install (package + dev)
|
|
27
|
+
run: |
|
|
28
|
+
python -m pip install --upgrade pip
|
|
29
|
+
pip install -e ".[dev]"
|
|
30
|
+
|
|
31
|
+
- name: Lint (ruff)
|
|
32
|
+
run: ruff check .
|
|
33
|
+
|
|
34
|
+
- name: Type-check (mypy)
|
|
35
|
+
run: mypy
|
|
36
|
+
|
|
37
|
+
- name: Tests (pytest)
|
|
38
|
+
# requires_cert: precisa de um .pfx real — roda só localmente, nunca no CI.
|
|
39
|
+
run: pytest -m "not requires_cert"
|
|
40
|
+
|
|
41
|
+
lock:
|
|
42
|
+
# Verifica que o lock com hashes instala de forma reproduzível (ambiente canônico).
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
steps:
|
|
45
|
+
- uses: actions/checkout@v4
|
|
46
|
+
- uses: actions/setup-python@v5
|
|
47
|
+
with:
|
|
48
|
+
python-version: "3.14"
|
|
49
|
+
- name: Install from locked requirements
|
|
50
|
+
run: |
|
|
51
|
+
python -m pip install --upgrade pip
|
|
52
|
+
pip install --require-hashes -r requirements-dev.txt
|
|
53
|
+
pip install -e . --no-deps
|
|
54
|
+
- name: Smoke
|
|
55
|
+
run: pytest -m "not requires_cert and not golden"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Publica no PyPI ao empurrar uma tag vX.Y.Z. Usa Trusted Publishing (OIDC) —
|
|
4
|
+
# sem token/segredo no repo: configurar o publisher confiável no PyPI antes.
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
tags: ["v*"]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build-publish:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
environment: pypi
|
|
16
|
+
permissions:
|
|
17
|
+
id-token: write # OIDC para o Trusted Publishing do PyPI
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
- uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: "3.12"
|
|
23
|
+
- name: Build (sdist + wheel)
|
|
24
|
+
run: |
|
|
25
|
+
python -m pip install --upgrade pip build
|
|
26
|
+
python -m build
|
|
27
|
+
- name: Publish to PyPI
|
|
28
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# ── Segredos e dados de cliente (NUNCA versionar) ─────────────────────────────
|
|
2
|
+
# Certificados A1 ICP-Brasil e qualquer material criptográfico
|
|
3
|
+
*.pfx
|
|
4
|
+
*.p12
|
|
5
|
+
*.pem
|
|
6
|
+
*.key
|
|
7
|
+
*.crt
|
|
8
|
+
*.cer
|
|
9
|
+
*.der
|
|
10
|
+
*.jks
|
|
11
|
+
*.keystore
|
|
12
|
+
certs/
|
|
13
|
+
# Configs reais de cliente (contêm CNPJ, senha do certificado, etc.)
|
|
14
|
+
config/
|
|
15
|
+
!examples/config-exemplo.jsonc
|
|
16
|
+
!examples/config-exemplo.json
|
|
17
|
+
# Variáveis de ambiente e segredos (.env, secrets.env, *.env, etc.)
|
|
18
|
+
.env
|
|
19
|
+
.env.*
|
|
20
|
+
*.env
|
|
21
|
+
secrets*
|
|
22
|
+
|
|
23
|
+
# ── Saídas de emissão (XML/PDF/contadores) ────────────────────────────────────
|
|
24
|
+
out/
|
|
25
|
+
*.xml
|
|
26
|
+
*.pdf
|
|
27
|
+
!docs/**/*.pdf
|
|
28
|
+
# Gabarito de teste (XML assinado pela referência PHP, cert de teste descartável — sem
|
|
29
|
+
# chave privada, sem dado real): versionado de propósito p/ o golden rodar no CI.
|
|
30
|
+
!tests/golden/*.xml
|
|
31
|
+
|
|
32
|
+
# ── Python ────────────────────────────────────────────────────────────────────
|
|
33
|
+
__pycache__/
|
|
34
|
+
*.py[cod]
|
|
35
|
+
*.egg-info/
|
|
36
|
+
.eggs/
|
|
37
|
+
build/
|
|
38
|
+
dist/
|
|
39
|
+
.venv/
|
|
40
|
+
venv/
|
|
41
|
+
env/
|
|
42
|
+
.pytest_cache/
|
|
43
|
+
.ruff_cache/
|
|
44
|
+
.mypy_cache/
|
|
45
|
+
.coverage
|
|
46
|
+
htmlcov/
|
|
47
|
+
|
|
48
|
+
# ── Editores / SO ─────────────────────────────────────────────────────────────
|
|
49
|
+
.vscode/
|
|
50
|
+
.idea/
|
|
51
|
+
.DS_Store
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Formato baseado em [Keep a Changelog](https://keepachangelog.com/pt-BR/1.1.0/);
|
|
4
|
+
versionamento [SemVer](https://semver.org/lang/pt-BR/).
|
|
5
|
+
|
|
6
|
+
## [0.1.0] - 2026-06-24
|
|
7
|
+
|
|
8
|
+
### Adicionado
|
|
9
|
+
- **Emissão ponta a ponta** de NFS-e pela API SEFIN Nacional (DPS):
|
|
10
|
+
`config` → `certificado` → `montar_dps` → `assinar` → **transporte mTLS** → `Nota`.
|
|
11
|
+
- `dps.montar_dps`/`id_dps`: montagem da DPS (lxml, ordem do XSD AnexoI) com a lógica
|
|
12
|
+
fiscal dos E-codes; o C14N do `infDPS` bate **byte a byte** com a referência PHP.
|
|
13
|
+
- `assinatura.assinar_dps`: XMLDSIG enveloped (RSA-SHA1) via `erpbrasil.assinatura` —
|
|
14
|
+
mesmo `DigestValue` do gabarito de referência.
|
|
15
|
+
- `sefin.SefinClient`: transporte mTLS (`requests-pkcs12`, PKCS#12 direto), `POST /nfse`
|
|
16
|
+
(gzip+base64), `verificarDps` (idempotência) e mapeamento de E-codes. **Emissão real validada
|
|
17
|
+
em homologação** (certificado A1 real, Simples Nacional/RJ: nNFSe + chave de 50 díg + DANFSe).
|
|
18
|
+
- Correção **E1229**: o XML assinado precisa do prolog `<?xml encoding="UTF-8"?>` (o SEFIN rejeita
|
|
19
|
+
sem ele) — `assinar_dps` reserializa com `xml_declaration=True`.
|
|
20
|
+
- `danfse.render`: DANFSe local (PDF) via `BrazilFiscalReport` ≥ 1.0 — **dependência opcional**
|
|
21
|
+
(`pip install "PyNFSeNacionalGT[danfse]"`); o núcleo de emissão não a puxa (import lazy).
|
|
22
|
+
- `config.validar`/`validar_tomador`: portão de validação fiscal (E0312/E0712/E1235…,
|
|
23
|
+
CPF/CNPJ mód-11) + loader tolerante (`ConfigError`).
|
|
24
|
+
- `Certificado`: leitura do `.pfx` A1 via `cryptography` (+ fallback de cifra legada §9).
|
|
25
|
+
- CLI `nfse-nacional emitir` (`--pdf`, `--xml-out`, `--verbose`); logging com redação
|
|
26
|
+
(nunca loga senha do `.pfx` nem o XML com dados do tomador).
|
|
27
|
+
- Reprodutibilidade: lock com hashes (`requirements-dev.txt`), `mypy --strict`, CI em
|
|
28
|
+
matriz 3.10–3.14, golden harness (`tests/golden/`).
|
|
29
|
+
|
|
30
|
+
### Limitações conhecidas / próximas versões
|
|
31
|
+
- Reportar upstream o classifier de licença errado da BrazilFiscalReport (LICENSE/README=LGPL-3.0,
|
|
32
|
+
mas o classifier do pyproject diz AGPL-3.0).
|
|
33
|
+
- Tomador estrangeiro/sem documento; não-optantes (Lucro Presumido/Real); eventos
|
|
34
|
+
(cancelamento); IBS/CBS (reforma tributária).
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# CLAUDE.md — PyNFSeNacional
|
|
2
|
+
|
|
3
|
+
> Guia de desenvolvimento deste repositório. **Antes de qualquer tarefa, leia
|
|
4
|
+
> [`docs/conhecimento-fiscal.md`](docs/conhecimento-fiscal.md)** — é onde mora a regra fiscal
|
|
5
|
+
> (estrutura da DPS, E-codes, numeração, DANFSe). E o [`docs/roadmap.md`](docs/roadmap.md) para o
|
|
6
|
+
> escopo e a ordem de build.
|
|
7
|
+
|
|
8
|
+
## O que é
|
|
9
|
+
|
|
10
|
+
Pacote Python público (MIT) que emite **NFS-e pela API SEFIN Nacional** (DPS) e gera o **DANFSe
|
|
11
|
+
localmente**. Vai para GitHub/PyPI. Feito por um contador, para a comunidade que vai bater na
|
|
12
|
+
obrigatoriedade nacional (~set/2026).
|
|
13
|
+
|
|
14
|
+
## Origem
|
|
15
|
+
|
|
16
|
+
- Este projeto **porta para Python puro** o conhecimento de uma **implementação de referência em
|
|
17
|
+
PHP** (privada, fora deste repositório) que já emite em produção.
|
|
18
|
+
- Essa referência serve de **gabarito**: ao montar/assinar a DPS aqui, a saída é comparada byte a
|
|
19
|
+
byte com a dela (ver `tests/golden/` e o roadmap), desriscando o ponto mais delicado
|
|
20
|
+
(canonicalização XMLDSIG). O mantenedor aponta a referência via env `NFSE_PHP_REF` só ao
|
|
21
|
+
regenerar o gabarito; o CI usa o XML já versionado e não precisa dela.
|
|
22
|
+
- Este repo é **autocontido e público** — **nada** de certificado, config real ou segredo entra no
|
|
23
|
+
git (ver `.gitignore`). Dados de exemplo são fictícios.
|
|
24
|
+
|
|
25
|
+
## Princípio central: integrar, não reinventar
|
|
26
|
+
|
|
27
|
+
Não reimplementar criptografia. Cada peça tem uma lib madura do ecossistema fiscal Python; nós
|
|
28
|
+
costuramos e escrevemos só o que falta (transporte ao SEFIN + acabamento). Mapa no roadmap.
|
|
29
|
+
|
|
30
|
+
| Peça | Lib | Módulo |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| Montar/serializar XML da DPS | `lxml` | `dps.py` |
|
|
33
|
+
| Assinar XMLDSIG | `erpbrasil.assinatura` | `assinatura.py` |
|
|
34
|
+
| Ler `.pfx` A1 | `cryptography` | `certificado.py` |
|
|
35
|
+
| Transporte mTLS SEFIN | `requests` + próprio | `sefin.py` |
|
|
36
|
+
| DANFSe (PDF) | `BrazilFiscalReport` | `danfse.py` |
|
|
37
|
+
| Orquestração + CLI | — | `emissor.py`, `cli.py` |
|
|
38
|
+
|
|
39
|
+
## Estrutura
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
src/pynfsenacional/ # o pacote (config/cert/dps/assinatura/sefin/danfse/cli — pipeline completo)
|
|
43
|
+
docs/ # conhecimento-fiscal.md (regra) + roadmap.md (plano)
|
|
44
|
+
examples/ # config-exemplo.jsonc (fictício) + emitir_exemplo.py
|
|
45
|
+
tests/ # smoke + (futuro) testes de DPS/assinatura contra gabarito
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Como desenvolver
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
python -m venv .venv && source .venv/bin/activate
|
|
52
|
+
pip install -e ".[dev]"
|
|
53
|
+
pytest # smoke
|
|
54
|
+
ruff check . # lint
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Estado atual
|
|
58
|
+
|
|
59
|
+
**Alpha — pipeline completo.** Todas as peças estão implementadas; `Emissor.emitir()` roda
|
|
60
|
+
ponta a ponta: **validar → montar DPS → assinar → transporte mTLS → Nota** (+ `nota.danfse()`).
|
|
61
|
+
|
|
62
|
+
- `config.py` — dataclasses + `validar()` (E-codes) + loader tolerante. ✅
|
|
63
|
+
- `certificado.py` — leitura do `.pfx` via `cryptography` (+ fallback cifra legada §9). ✅
|
|
64
|
+
- `dps.py` — `montar_dps`/`id_dps`; o C14N do `infDPS` bate **byte-a-byte** com o PHP (golden). ✅
|
|
65
|
+
- `assinatura.py` — `assinar_dps` via `erpbrasil.assinatura`; mesmo `DigestValue` do gabarito. ✅
|
|
66
|
+
- `sefin.py` — transporte mTLS (`requests-pkcs12`, P12 direto), `POST /nfse`, `verificarDps`.
|
|
67
|
+
**mTLS validado ao vivo** em homologação (handshake + `HEAD /dps`, read-only). ✅
|
|
68
|
+
- `danfse.py` — DANFSe local via `BrazilFiscalReport` ≥ 1.0 (validado com XML de NFS-e real). ✅
|
|
69
|
+
- `cli.py` — `nfse-nacional emitir` (`--pdf`/`--xml-out`/`--verbose`); logging com redação. ✅
|
|
70
|
+
|
|
71
|
+
**Emissão real VALIDADA em homologação** (24/06): com um certificado A1 real (Simples Nacional, RJ) o
|
|
72
|
+
SEFIN devolveu o `nNFSe` + a chave de 50 díg e o DANFSe foi gerado localmente. (No caminho, corrigido o
|
|
73
|
+
**E1229**: faltava o prolog `<?xml encoding="UTF-8"?>` no XML assinado.)
|
|
74
|
+
|
|
75
|
+
**DANFSe é dependência OPCIONAL** (`pip install PyNFSeNacionalGT[danfse]`): o núcleo de emissão usa só
|
|
76
|
+
deps permissivas; a `BrazilFiscalReport` (LGPL-3.0 pelo LICENSE/README upstream — o classifier AGPL do
|
|
77
|
+
pyproject deles parece engano) só entra para gerar o PDF. Import lazy em `danfse.py`.
|
|
78
|
+
|
|
79
|
+
**Falta (pré-publicação):** (1) criar o repo no GitHub + reservar o nome no PyPI; (2) endurecimento a
|
|
80
|
+
partir de emissões reais; (3) reportar o classifier de licença errado upstream.
|
|
81
|
+
|
|
82
|
+
Tooling: `pip install -e ".[dev]"` (deps instalam no 3.10–3.14), lock com hashes
|
|
83
|
+
(`requirements-dev.txt`), CI (`.github/workflows/ci.yml`), release por tag (`release.yml`).
|
|
84
|
+
Testes: `pytest` (67, +2 skip locais), `ruff check .`, `mypy --strict` — tudo verde.
|
|
85
|
+
|
|
86
|
+
## Regras
|
|
87
|
+
|
|
88
|
+
- **Nunca** commitar `.pfx`, `config/` real, `.env`, XML/PDF de nota real.
|
|
89
|
+
- Toda regra fiscal nova vai **primeiro** para `docs/conhecimento-fiscal.md`, depois para o código.
|
|
90
|
+
- Ao implementar DPS/assinatura: **diffar contra o gabarito PHP** antes de mandar pro SEFIN.
|
|
91
|
+
- Mensagem de commit termina com a linha de co-autoria do Claude Code quando aplicável.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Código de Conduta
|
|
2
|
+
|
|
3
|
+
## Nosso compromisso
|
|
4
|
+
|
|
5
|
+
No interesse de promover um ambiente aberto e acolhedor, nós, como contribuidores e mantenedores,
|
|
6
|
+
nos comprometemos a fazer da participação neste projeto uma experiência livre de assédio para todos —
|
|
7
|
+
independentemente de idade, identidade ou expressão de gênero, deficiência, etnia, nível de
|
|
8
|
+
experiência, nacionalidade, aparência, raça, religião ou orientação sexual.
|
|
9
|
+
|
|
10
|
+
## Nossos padrões
|
|
11
|
+
|
|
12
|
+
Exemplos de comportamento que contribuem para um ambiente positivo:
|
|
13
|
+
|
|
14
|
+
- usar linguagem acolhedora e inclusiva;
|
|
15
|
+
- respeitar pontos de vista e experiências diferentes;
|
|
16
|
+
- aceitar críticas construtivas com elegância;
|
|
17
|
+
- focar no que é melhor para a comunidade.
|
|
18
|
+
|
|
19
|
+
Comportamentos inaceitáveis incluem assédio, comentários depreciativos, ataques pessoais ou políticos,
|
|
20
|
+
e divulgação de informação privada de terceiros sem permissão.
|
|
21
|
+
|
|
22
|
+
## Aplicação
|
|
23
|
+
|
|
24
|
+
Casos de comportamento abusivo ou inaceitável podem ser reportados de forma privada ao mantenedor
|
|
25
|
+
através do GitHub ([@Gomes343](https://github.com/Gomes343)) ou pelo canal de
|
|
26
|
+
**Security Advisories** do repositório. Todas as queixas serão analisadas e investigadas, resultando
|
|
27
|
+
em uma resposta apropriada às circunstâncias.
|
|
28
|
+
|
|
29
|
+
## Atribuição
|
|
30
|
+
|
|
31
|
+
Adaptado do [Contributor Covenant](https://www.contributor-covenant.org), versão 2.1.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Como contribuir
|
|
2
|
+
|
|
3
|
+
Obrigado pelo interesse! Este é um projeto da comunidade fiscal Python brasileira. Toda ajuda é
|
|
4
|
+
bem-vinda — relatos de erro, melhorias de documentação, suporte a mais municípios/regimes, testes.
|
|
5
|
+
|
|
6
|
+
## Antes de tudo: regra de ouro 🔒
|
|
7
|
+
|
|
8
|
+
**NUNCA** inclua material sensível em commits, issues ou PRs:
|
|
9
|
+
|
|
10
|
+
- certificados A1 (`.pfx`/`.p12`/`.pem`/`.key`), senhas, `.env`, tokens;
|
|
11
|
+
- CNPJ/CPF, nomes ou XML/PDF de **notas reais**.
|
|
12
|
+
|
|
13
|
+
O [`.gitignore`](.gitignore) já bloqueia esses padrões; os dados de exemplo e fixtures são **fictícios**.
|
|
14
|
+
Se precisar reproduzir um problema, **anonimize** (use CNPJ/CPF de teste, ex.: `11222333000181`).
|
|
15
|
+
|
|
16
|
+
## Ambiente de desenvolvimento
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
git clone https://github.com/Gomes343/PyNFSeNacional.git
|
|
20
|
+
cd PyNFSeNacional
|
|
21
|
+
python -m venv .venv && source .venv/bin/activate
|
|
22
|
+
pip install -e ".[dev]" # dev já inclui o extra [danfse]
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Antes de abrir o PR
|
|
26
|
+
|
|
27
|
+
Tudo precisa passar (é o que a CI roda, na matriz 3.10–3.14):
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
ruff check . # lint + ordenação de imports
|
|
31
|
+
mypy # tipos (strict)
|
|
32
|
+
pytest # testes (inclui o golden contra a referência)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
- **Regra fiscal nova** vai **primeiro** para [`docs/conhecimento-fiscal.md`](docs/conhecimento-fiscal.md),
|
|
36
|
+
depois para o código (o porquê fiscal precisa estar documentado).
|
|
37
|
+
- Mexeu na **montagem da DPS ou na assinatura**? O *golden* (`tests/golden/`) compara a saída ao
|
|
38
|
+
gabarito de referência byte a byte. Se a mudança for legítima, regenere com
|
|
39
|
+
`bash tests/golden/regenerar_gabarito.sh` e explique o porquê no PR.
|
|
40
|
+
- Mantenha o **núcleo de emissão sem dependências pesadas**; PDF/extras ficam atrás de `[danfse]`.
|
|
41
|
+
|
|
42
|
+
## Estilo de commit
|
|
43
|
+
|
|
44
|
+
Mensagens em **português**, no imperativo, dizendo **o quê** e **por quê** (não só o "como").
|
|
45
|
+
Um assunto curto + corpo quando precisar de contexto.
|
|
46
|
+
|
|
47
|
+
## Pull Requests
|
|
48
|
+
|
|
49
|
+
1. Crie um branch a partir de `main`.
|
|
50
|
+
2. Mantenha o PR focado num assunto.
|
|
51
|
+
3. Descreva o **porquê**, como testou, e marque itens do checklist do template.
|
|
52
|
+
4. CI verde é pré-requisito de merge.
|
|
53
|
+
|
|
54
|
+
Dúvidas? Abra uma [issue](https://github.com/Gomes343/PyNFSeNacional/issues) — de preferência antes de
|
|
55
|
+
um PR grande, para alinharmos a abordagem.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Murilo Gomes Teixeira
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|