Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "cat \"${CLAUDE_PROJECT_DIR}/AGENTS.md\""
}
]
}
]
}
}
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
Expand Down
127 changes: 29 additions & 98 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,115 +1,46 @@
# AGENTS.md - PyNFe
# AGENTS.md — PyNFe

Brazilian electronic fiscal document library (NF-e, NFC-e, NFS-e, MDF-e, CT-e) for SEFAZ webservice communication.
Brazilian electronic fiscal document library for NF-e, NFC-e, NFS-e, MDF-e, CT-e, and SEFAZ communication. `AGENTS.md` is the sole canonical instruction source; client settings may load it but must not copy its policies.

## Source Map Navigation (MANDATORY)
## Bootstrap and Git identity

**Before reading any large file (>200 lines), you MUST first read its `{filename}_map.md` file** in the `docs/` directory. The source map contains:
- Section-by-section breakdown with exact line ranges
- Class/method index with purpose descriptions
- Field group documentation
- Resolve the repository with `git rev-parse --show-toplevel`. For shared Nuvel resources, prefer a validated `NUVEL_WORKSPACE_ROOT`; otherwise derive candidates from the common Git directory/original checkout and accept only a directory containing `.claude/workflows/issue-orchestrator.js`. Never assume `../docs` works from a detached worktree.
- Commit with the machine's global Git identity exactly as configured. Never set or override `user.name`, `user.email`, signing settings, author/committer environment variables, or `.git/config`. Derive branch prefixes and paths; never hardcode a developer identity or home path.
- Preserve user changes. Use focused branches and squash PR merges. Verify official SEFAZ/provider specifications before changing external fiscal contracts.

This allows you to navigate directly to the specific line-window you need instead of reading the entire file.
## Navigation gate

### Available Source Maps
Before reading a mapped source file longer than 200 lines, read its map in `docs/` and then open only the relevant source range. The maps cover `serializacao.py`, `comunicacao.py`, `autorizador_nfse.py`, `notafiscal.py`, `manifesto.py`, `evento.py`, `flags.py`, `webservices.py`, and `utils/__init__.py`; use [`docs/README.md`](docs/README.md) to select one.

| Source Map | File | Lines | Description |
|------------|------|-------|-------------|
| `docs/serializacao_map.md` | `pynfe/processamento/serializacao.py` | 2630 | XML serialization (NF-e, MDF-e, QR codes) |
| `docs/comunicacao_map.md` | `pynfe/processamento/comunicacao.py` | 1348 | SEFAZ webservice communication |
| `docs/autorizador_nfse_map.md` | `pynfe/processamento/autorizador_nfse.py` | 538 | NFS-e authorization (Betha/Ginfes) |
| `docs/notafiscal_map.md` | `pynfe/entidades/notafiscal.py` | 1253 | Invoice entities and tax fields |
| `docs/manifesto_map.md` | `pynfe/entidades/manifesto.py` | 447 | MDF-e manifest entities |
| `docs/evento_map.md` | `pynfe/entidades/evento.py` | 237 | Event entities (cancel, correction, etc.) |
| `docs/flags_map.md` | `pynfe/utils/flags.py` | 645 | Constants, namespaces, tax codes |
| `docs/webservices_map.md` | `pynfe/utils/webservices.py` | 572 | SEFAZ endpoint URLs by state |
| `docs/utils_map.md` | `pynfe/utils/__init__.py` | 253 | Utility functions (municipality lookup, signing) |
## Commands and full checks

### How to Use Source Maps
Use Python 3.9+ in an isolated environment.

1. **Read the `_map.md` file first** to understand the file structure
2. **Identify the line range** you need from the map tables
3. **Read only that section** using `offset` and `limit` parameters
4. Example: To understand ICMS CST 60 serialization, read `docs/serializacao_map.md`, find it's at lines 747-770, then read `pynfe/processamento/serializacao.py` with `offset=747, limit=25`

## Project Structure

```
docs/ # Documentation and source maps (*_map.md, reforma_tributaria.md)
pynfe/
├── entidades/ # Domain entities (data models)
│ ├── base.py # Base entity class with kwargs init
│ ├── certificado.py # A1 certificate handling
│ ├── cliente.py # Customer entity
│ ├── emitente.py # Issuer entity
│ ├── evento.py # Event entities (cancel, correction, MDF-e events)
│ ├── manifesto.py # MDF-e manifest entity
│ ├── notafiscal.py # NF-e/NFC-e invoice entity + products + taxes
│ ├── produto.py # Product entity (standalone)
│ ├── servico.py # Service entity (NFS-e)
│ └── transportadora.py # Carrier entity
├── processamento/ # Core processing logic
│ ├── assinatura.py # XML digital signing with A1 certificates
│ ├── autorizador_nfse.py # NFS-e serialization (Betha/Ginfes PyXB bindings)
│ ├── comunicacao.py # SEFAZ SOAP webservice communication
│ ├── serializacao.py # XML serialization (entities → SEFAZ XML)
│ └── validacao.py # XML schema validation
├── utils/ # Utilities
│ ├── __init__.py # Municipality lookup, XML signing helpers
│ ├── flags.py # Constants, namespaces, tax code enumerations
│ ├── webservices.py # SEFAZ endpoint URLs by state/environment
│ ├── bar_code_128.py # Code 128 barcode generation for DANFE
│ ├── xml_writer.py # XML element writing helpers
│ └── nfse/ # NFS-e provider-specific PyXB bindings (GENERATED - do not edit)
│ ├── betha/ # Betha provider bindings (13,941+ lines)
│ └── ginfes/ # Ginfes provider bindings (8,028+ lines)
├── data/ # Reference data files
│ ├── IBPT/ # Tax tables by state (CSV)
│ ├── ISSQN/ # Service tax classification
│ ├── MunIBGE/ # Municipality IBGE codes by UF
│ └── XSDs/ # XML Schema definitions (NF-e, NFC-e, NFS-e, MDF-e, CT-e)
tests/ # Test suite (37 test files)
```bash
python -m pip install --upgrade pip
python -m pip install build -e . -r requirements.txt -r requirements-dev.txt -r requirements-nfse.txt
pytest -v
ruff check .
ruff format --check .
python -m build
git diff --check
```

## Key Concepts

- **NF-e** (modelo 55): Standard electronic invoice
- **NFC-e** (modelo 65): Consumer electronic invoice (retail)
- **NFS-e**: Municipal service invoice (Betha/Ginfes providers)
- **MDF-e** (modelo 58): Transport manifest
- **CT-e**: Transport knowledge document (partial support)
- **SEFAZ**: State tax authority webservices
- **Homologacao**: Test environment (`_ambiente=2`)
- **SVRS/SVAN**: Virtual SEFAZ environments for states without own webservices
`requirements-dev.txt` pins Ruff 0.12.5, matching the existing Poetry minimum; use that environment so lint results are reproducible.

## Commands
A focused `pytest tests/<file>.py` is useful during development but never replaces the full suite. Project metadata requires Python 3.9+, and CI tests every supported minor from 3.9 through 3.13; do not claim support outside that declared range or weaken it to accommodate an obsolete runner. Pushes and PRs run format, lint, and tests across the CI matrix. Every push also builds distributions; publishing occurs only for tags. Do not create a tag or publish without explicit authorization.

```bash
# Run tests
pytest tests/

# Run specific test
pytest tests/test_nfe_serializacao_geral.py
## Architecture and invariants

# Lint
ruff check pynfe/

# Format
ruff format pynfe/
```
- `pynfe/entidades/` contains fiscal domain entities; `pynfe/processamento/` owns signing, serialization, communication, and validation; `pynfe/utils/` contains flags, endpoint tables, XML helpers, and generated NFS-e bindings; `pynfe/data/` holds schemas and reference data.
- Never manually edit generated PyXB bindings under `pynfe/utils/nfse/`. Treat XSDs and reference tables as controlled fiscal inputs; change them only with verified source material.
- SEFAZ XML order, namespaces, decimal formatting, optional element rules, endpoint/environment selection, and signature/certificate handling are protocol contracts. Preserve them and add fixture-based tests for changed output.
- Extend existing entities, flags, serializers, and communication paths before creating parallel models or pipelines. Keep public APIs backward-compatible unless a breaking release is explicitly authorized.
- Tests must exercise real entity serialization/validation state. Do not mock core entity or XML behavior merely to simulate fiscal success or failure.
- Read [`docs/reforma_tributaria.md`](docs/reforma_tributaria.md) before changing IBS/CBS or tax-reform fields.

## Dependencies

- `lxml` — XML processing
- `signxml` — XML digital signatures
- `cryptography` / `pyopenssl` — Certificate handling
- `requests` — HTTP communication with SEFAZ
- `suds-community` — SOAP client (NFS-e only)
- `PyXB-X` — XML Schema bindings (NFS-e only)

## Important Notes
Core dependencies include `lxml`, `signxml`, `cryptography`/`pyopenssl`, and `requests`; NFS-e additionally uses `suds-community` and `PyXB-X`. Do not casually broaden supported Python/dependency ranges because certificate and generated-binding compatibility is sensitive.

- Files under `pynfe/utils/nfse/` are **auto-generated** PyXB bindings — do not edit manually
- The `pynfe/data/` directory contains reference data files that should not be modified casually
- Tax code serialization follows strict SEFAZ XML schema ordering — field order matters
- Each Brazilian state has its own SEFAZ endpoint configuration in `webservices.py`
Language: anything not customer-visible (docs, rules, prompts, code comments, commits, PRs) is written in English; only customer-facing copy stays PT-BR.
16 changes: 16 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Documentation index

| Document | What it covers |
|---|---|
| [reforma_tributaria.md](reforma_tributaria.md) | Brazilian tax reform support and fiscal serialization decisions. |
| [serializacao_map.md](serializacao_map.md) | Navigation map for NF-e, NFC-e, and MDF-e XML serialization. |
| [comunicacao_map.md](comunicacao_map.md) | Navigation map for SEFAZ communication. |
| [autorizador_nfse_map.md](autorizador_nfse_map.md) | Navigation map for municipal NFS-e authorization. |
| [notafiscal_map.md](notafiscal_map.md) | Navigation map for invoice entities and tax fields. |
| [manifesto_map.md](manifesto_map.md) | Navigation map for MDF-e entities. |
| [evento_map.md](evento_map.md) | Navigation map for fiscal event entities. |
| [flags_map.md](flags_map.md) | Navigation map for fiscal constants, namespaces, and codes. |
| [webservices_map.md](webservices_map.md) | Navigation map for endpoints by state and environment. |
| [utils_map.md](utils_map.md) | Navigation map for shared utility functions. |

Read the matching source map before opening any mapped source file longer than 200 lines. Repository-wide commands and invariants live in [`../AGENTS.md`](../AGENTS.md).
Loading
Loading