Metadata-Version: 2.4
Name: foxnfe
Version: 1.3.0
Summary: SDK oficial FOX NF-e para Python — emissão NF-e, NFSe, cancelamento, consulta e MCP
Author-email: Central Fox Tecnologia <dev@centralfox.online>
License: MIT
Project-URL: Homepage, https://centralfox.online
Project-URL: Documentation, https://docs.centralfox.online/sdks/python
Project-URL: Repository, https://github.com/foxdigital/foxnfe-python
Keywords: nfe,nfse,nota-fiscal,fiscal,brasil
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: License :: OSI Approved :: MIT License
Classifier: Topic :: Office/Business :: Financial
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: requests>=2.28.0

# foxnfe (Python SDK)

SDK oficial FOX NF-e para Python — emissão NF-e, NFSe, cancelamento, consulta e integração MCP.

## Requisitos

- Python 3.9+
- [requests](https://requests.readthedocs.io) `>=2.28`

## Instalação

```bash
pip install foxnfe
# ou
poetry add foxnfe
# ou
uv add foxnfe
```

## Quick Start

```python
from foxnfe import Client

client = Client(tenant_slug="minha-empresa")

# Autenticar
auth = client.login("email@empresa.com", "senha-segura")
print(f"Token: {auth.token}")

# Ou usar token existente
client = Client(tenant_slug="minha-empresa", token="seu-token-aqui")
# Ou via with_token (retorna nova instância)
authed = client.with_token("seu-token-aqui")
```

## NF-e

```python
from foxnfe import Client, NfeEmitRequest

client = Client(tenant_slug="minha-empresa", token="seu-token")

payload = NfeEmitRequest(
    ambiente=2,  # 2=homologação
    certificate_id=1,
    tomador={
        "cnpj": "12345678000190",
        "razao_social": "Empresa Tomadora Ltda",
        "endereco": {
            "logradouro": "Rua das Flores",
            "numero": "100",
            "municipio": "São Paulo",
            "uf": "SP",
            "cep": "01310100",
        },
    },
    itens=[{
        "codigo": "SRV001",
        "descricao": "Serviço de consultoria",
        "cfop": "5933",
        "quantidade": 1,
        "valor_unitario": 1000.00,
        "valor_total": 1000.00,
    }],
    pagamentos=[{"forma": "01", "valor": 1000.00}],
    total=1000.00,
)

result = client.nfe.emit(payload)
print(f"NF-e ID: {result['id']}")

# Aguardar autorização (polling automático)
nfe_autorizada = client.nfe.wait_for_authorization(result["id"])
print(f"Status: {nfe_autorizada.status}")  # authorized

# Baixar XML
xml_bytes = client.nfe.xml(result["id"])
with open("nfe.xml", "wb") as f:
    f.write(xml_bytes)

# Baixar DANFE PDF
pdf_bytes = client.nfe.pdf(result["id"])
with open("danfe.pdf", "wb") as f:
    f.write(pdf_bytes)

# Cancelar
client.nfe.cancel(result["id"], "Cancelamento solicitado pelo cliente")
```

## NFSe

```python
from foxnfe import Client, NfseEmitRequest

client = Client(tenant_slug="minha-empresa", token="seu-token")

payload = NfseEmitRequest(
    ambiente=2,
    certificate_id=1,
    prestador={
        "cnpj": "12345678000190",
        "inscricao_municipal": "123456",
        "razao_social": "Minha Empresa Ltda",
        "codigo_municipio": "3550308",  # São Paulo (IBGE)
    },
    tomador={
        "cnpj": "98765432000110",
        "nome": "Cliente S.A.",
    },
    servico={
        "codigo_tributacao_nacional": "01.01.00001",
        "descricao": "Desenvolvimento de software",
        "data_competencia": "2026-05-01",
        "valor": 5000.00,
        "aliquota_iss": 2.0,
    },
)

result = client.nfse.emit(payload)
nfse = client.nfse.get(result["id"])
print(f"Número NFSe: {nfse.numero_nfse}")

# Consultar por RPS ou chave
client.nfse.consult_by_numero("00000001")
client.nfse.consult_by_chave("SP3550308202605010000000000001")

# Cancelar / Substituir
client.nfse.cancel(result["id"], "Erro nos dados do tomador")
client.nfse.substitute(result["id"], payload, "Correção de dados")
```

## MCP (Model Context Protocol)

```python
from foxnfe import Client

client = Client(tenant_slug="minha-empresa", token="seu-token")

# Inicializar sessão MCP
info = client.mcp.initialize()
print(f"MCP Server: {info['result']['serverInfo']['name']}")

# Listar tools
tools = client.mcp.list_tools()
for tool in tools:
    print(f"{tool.name}: {tool.description}")

# Chamar uma tool
result = client.mcp.call_tool("emitir_nfe", {
    "ambiente": 2,
    "certificate_id": 1,
})

if result.get("result", {}).get("isError"):
    print("Tool error:", result["result"]["content"][0]["text"])
else:
    print("Tool result:", result["result"]["content"][0]["text"])
```

## Tratamento de Erros

```python
from foxnfe import Client
from foxnfe.exceptions import ApiException, AuthException, FoxNfeException

try:
    client.nfe.emit(payload)
except AuthException as e:
    # Token inválido ou expirado (401/403)
    print(f"Auth error: {e}")
except ApiException as e:
    # Erro da API (422, 500, etc.)
    print(f"API error {e.status_code}: {e}")
    print(f"Body: {e.response_body}")
except FoxNfeException as e:
    # Timeout, erro de conexão, etc.
    print(f"SDK error: {e}")
```

## Uso com context manager

```python
from foxnfe import Client

# Client usa requests.Session internamente (pode ser fechado manualmente)
client = Client(tenant_slug="minha-empresa", token="seu-token")
try:
    result = client.nfe.emit(payload)
finally:
    client._session.close()
```

## Configuração avançada

```python
client = Client(
    tenant_slug="minha-empresa",
    token="seu-token",
    base_url="https://sandbox.centralfox.online/api/v1",
    timeout=60.0,
)
```

## Estrutura do pacote

```
foxnfe/
├── __init__.py      # Exports públicos
├── client.py        # Cliente HTTP principal
├── nfe.py           # Módulo NF-e
├── nfse.py          # Módulo NFSe
├── mcp.py           # Módulo MCP
├── types.py         # Dataclasses com tipagem
└── exceptions.py    # Classes de erro
```

## Links

- [Documentação API](https://docs.centralfox.online)
- [Portal FOX NF-e](https://foxnfe.centralfox.online)
- [Suporte](mailto:suporte@centralfox.online)

## 1.3.0 — eventos, rejeições, homologação, RTC, cobertura NFS-e e suporte

```python
ev = client.nfe_events
ev.ator_interessado(15, "11222333000181")                       # 110150
ev.insucesso_entrega(15, "2026-09-08T10:00:00-03:00", tp_motivo=1)  # 110192
ev.inutilizar(serie=1, numero_inicial=10, numero_final=12, justificativa="Numeração pulada por falha do ERP")
ev.contratos(); ev.registrar_evento(15, "econf", {...})           # eventos por contrato (conciliação financeira, RTC…)

client.nfe.rejeicao("539"); client.nfe.homologacao_run(65)         # rejeições explicadas / amostras simuladas
client.nfse.cobertura_municipio("2304400")                        # driver, operações e provas
client.rtc.verify_resolution("550e8400-e29b-41d4-a716-446655440000")
client.support.create_case("Webhook sem entrega desde ontem", priority="high")
```

Validação local (ids, dígitos, tamanhos, enums) antes do transporte; regra fiscal fica na API. `NfeResource.rejection` traz a rejeição classificada.
