Metadata-Version: 2.5
Name: shade-plugins-nfse-nacional
Version: 0.1.0
Summary: NFS-e pela API do padrão nacional: baixa as notas do contribuinte e emite a nota a partir de campos nomeados, com o e-CNPJ do prestador.
Author: ShadeOne
License-Expression: Apache-2.0
License-File: LICENSE
Requires-Python: >=3.11
Requires-Dist: cryptography>=44
Requires-Dist: lxml>=5
Requires-Dist: nfelib==3.3.0
Requires-Dist: shade-sdk<0.23,>=0.22.20
Requires-Dist: signxml<5,>=4.2
Description-Content-Type: text/markdown

# shade-plugins-nfse-nacional

Plugin do ShadeOne para a NFS-e do padrão nacional: baixa as notas do contribuinte pela distribuição
do ADN e emite a nota pela API da SEFIN Nacional, com o e-CNPJ do prestador. Sem tela e sem captcha.

## Uso

No `shade.toml` do robô:

```toml
[hosts]
permitidos = ["sefin.nfse.gov.br", "adn.nfse.gov.br"]

[certificado]
modo = "fixo"             # ou "por_cnpj", com a coluna do CNPJ do prestador
nome = "Prestador"

[config]
nfse_nacional_ambiente = "producao"   # ou "producao_restrita"

[plugins]
nfse-nacional = "0.1.0"
```

No robô:

```python
from shade_sdk import http
import shade_plugins_nfse_nacional as nfse

dps = {
    "prestador_cnpj": "12.345.678/0001-90",
    "municipio": "3550308",             # código IBGE
    "competencia": "2026-10-01",
    "simples_nacional": "1",            # 1 não optante, 2 MEI, 3 ME/EPP
    "tomador_documento": "11.222.333/0001-81",
    "tomador_nome": "Tomador Ltda",
    "valor": "1.200,00",
    "codigo_servico": "010101",         # código de tributação nacional
    "descricao": "Consultoria em sistemas",
}

item.saida(resumo=nfse.nfse_conferir(dps)["nfse_resumo"])   # roda também no ensaio
with item.efetivar("emitir a nota", desfazer_se=(http.NadaSaiu,)):
    nota = nfse.nfse_emitir(dps)                            # no ensaio, não roda
print(nota["chave"], nota["arquivo"])
```

## `nfse_conferir(dps)`

Monta a DPS, assina e valida contra o XSD oficial, sem enviar, e devolve
`{"nfse_resumo": "Emitiria a nota de R$ 1.200,00 para Tomador Ltda"}`. Não fala com a rede e não
devolve o XML. `DpsInvalida.campo` diz o campo errado.

## `nfse_emitir(dps)`

Só roda dentro de `item.efetivar()`; no ensaio, o bloco não roda e a nota não sai. Devolve `chave`,
`numero`, `id_dps`, `ja_emitida`, `xml`, `arquivo` e `arquivo_pdf`, com o XML e o PDF anexados ao
item. Faltar o PDF ou o XML legível não muda nada: a nota existe, e a `chave` diz qual.

- **Um envio por chamada.** O plugin nunca repete a emissão. Sem resposta clara, levanta
  `EmissaoIncerta`, e o item fica retido para alguém conferir no Emissor Nacional pelo `id_dps`.
- **O número da DPS sai da chave do item,** salvo se `numero` vier nos campos. Ele é obrigatório em
  `Tarefa` e fora de item, e numa segunda nota do mesmo item. Um item, uma nota: refazer o item manda o mesmo `Id`, e o serviço não aceita dois. A recusa que encontra a DPS já emitida
  devolve a nota que existe, com `ja_emitida` igual a `"sim"`, se o prestador, o tomador, a competência,
  o serviço e o valor forem os destes campos. Se não forem, ou se o XML não vier, levanta `EmissaoIncerta`.
- **Não há operação de assinar.** O plugin assina só a DPS que ele montou a partir dos campos, em
  memória, e o certificado de outro CNPJ não assina.

Campos opcionais: `inscricao_municipal`, `municipio_prestacao`, `regime_simples`, `regime_especial`,
`tributacao_iss`, `iss_retido`, `percentual_tributos_sn`, `serie` e `numero`. Nome desconhecido é
recusado. O valor com mais de duas casas é recusado, nunca arredondado.

## `nfse_baixar(cnpj, desde=None)`

As NFS-e do CNPJ a partir do último NSU guardado, cada uma com `chave`, `nsu`, `data`, `xml` e
`arquivo`, já anexado ao item. O NSU fica em `estado/nfse-nacional/` no diretório de trabalho e só
avança depois de os arquivos da página estarem no disco. `desde` (AAAA-MM-DD) deixa de fora as notas
geradas antes: o serviço só anda por NSU, então o filtro é do plugin, e o NSU passa por cima delas.
Eventos ficam de fora. No ensaio a consulta roda, mas nada é gravado e o NSU não avança. A lista tem
`completa`, falso quando parou no teto de 20 páginas ou quando algo falhou depois da primeira: o que
veio está guardado, e a chamada seguinte continua dali. Na primeira página, o XML que não coube nos
anexos retém o item, antes de o NSU avançar.

## Erros

- `AdnIndisponivel`: falha técnica na leitura. O laço do robô repete o item.
- `RecusaDoAdn` (`ErroDeNegocio`): `motivo` é `certificado_recusado` ou `sem_autorizacao`.
- `DpsInvalida` (`ErroDeNegocio`, `NadaSaiu`): os campos não formam uma DPS.
- `EmissaoRecusada` (`ErroDeNegocio`, `NadaSaiu`): `motivo` e `codigo` do serviço; a DPS não está lá.
- `EmissaoAdiada` (`FalhaTransitoria`, `NadaSaiu`): limite de pedidos ou prazo antes do envio.
- `EmissaoIncerta`: pode ter emitido. Nunca se repete sozinha.

As mensagens trazem o status e o código do serviço, nunca os campos da nota, o certificado nem o XML.

## Licença

Apache-2.0. A DPS sai dos bindings do [`nfelib`](https://pypi.org/project/nfelib/) (MIT), gerados dos
XSDs oficiais, e a assinatura do [`signxml`](https://pypi.org/project/signxml/) (Apache-2.0).
