Biblioteca para auxiliar a assinar, gerar e consultar NFSe da Prefeitura Municipal de São José. Padrão ABRASF da Betha Software.
Instalação
A biblioteca está disponível no PyPi:
user@host:~$ pip install nfsepmsj
Desenvolvimento
Clonar o repositório:
user@host:~$ git clone https://github.com/qualitaocupacional/nfsepmsj.git
Instalar a lib em modo desenvolvimento:
(virtualenv) user@host:~/nfsepmsj$ pip install -e ".[testing]"
Usando
from nfsepmsj.client import NFSeAbrasf
pfx_file = '/caminho/do/arquivo.pfx'
pfx_passwd = 'Senha do arquivo pfx'
nfse = NFSeAbrasf(pfx_file, pfx_passwd)
nf_data = {
'rps.lote.id': 'loteid',
'nf.data.emissao': 'AAAA-MM-DD',
'nf.total_nota': '100.30'
# demais campos...
}
nfse.add_rps(data)
result, errors = nfse.send()
result vai ser uma lista de dicionários com a estrutura:
[
{
'rps.lote.id': 'loteid',
'xml.response': 'XML com a resposta do webservices',
'xml.request': 'o XML que foi gerado para envio',
}
]
E errors, se houver algum, como, por exemplo, erro de validação do XML, vai ser:
[
{
'rps.lote.id': 'loteid',
'xml.request': 'o XML que foi gerado para envio',
'error': 'a mensagem do erro'
}
]
Para utilizar o ambiente de Testes ao invés do de Produção:
from nfsepmsj.client import NFSeAbrasf
nfse = NFSeAbrasf(pfx_file, pfx_passwd, 'test')
# ...
Estrutura do dicionário com os campos da nota fiscal:
Nome |
Descrição |
|---|---|
‘rps.lote.id’ |
Identificação única do lote |
‘rps.numero’ |
|
‘rps.serie’ |
|
‘rps.tipo’ |
|
‘rps.data.emissao’ |
|
‘rps.status’ |
1-Normal, 2-Cancelado |
‘rps.substituido.numero’ |
|
‘rps.substituido.serie’ |
|
‘rps.substituido.tipo’ |
|
‘nf.data.emissao’ |
|
‘nf.total_servicos’ |
|
‘nf.valor_deducoes’ |
|
‘nf.valor_pis’ |
|
‘nf.valor_cofins’ |
|
‘nf.valor_inss’ |
|
‘nf.valor_IR’ |
|
‘nf.valor_csll’ |
|
‘nf.valor_outros’ |
|
‘nf.valor_iss’ |
|
‘nf.aliquota’ |
|
‘nf.desconto_incondicionado’ |
|
‘nf.desconto_condicionado’ |
|
‘nf.iss_retido’ |
|
‘nf.responsavel_retencao’ |
|
‘nf.codigo_servico’ |
|
‘nf.codigo_cnae’ |
|
‘nf.codigo_tributacao_municipio’ |
|
‘nf.discriminacao’ |
|
‘nf.codigo_municipio’ |
|
‘nf.codigo_pais’ |
|
‘nf.exigibilidade_iss’ |
|
‘nf.codigo_municipio_incidencia’ |
|
‘nf.numero_processo’ |
|
‘nf.prestador.documento’ |
|
‘nf.prestador.inscricao_municipal’ |
|
‘nf.tomador.documento’ |
|
‘nf.tomador.inscricao_municipal’ |
|
‘nf.tomador.razao_social’ |
|
‘nf.tomador.logradouro’ |
|
‘nf.tomador.numero_logradouro’ |
|
‘nf.tomador.complemento’ |
|
‘nf.tomador.bairro’ |
|
‘nf.tomador.codigo_municipio’ |
|
‘nf.tomador.uf’ |
|
‘nf.tomador.codigo_pais’ |
|
‘nf.tomador.cep’ |
|
‘nf.tomador.contato.telefone’ |
|
‘nf.tomador.contato.email’ |
|
‘nf.regime_especial_tributacao’ |
|
‘nf.optante_simples’ |
|
‘nf.incentivo_fiscal’ |
|
‘nf.intermediario.razao_social |
|
‘nf.intermediario.documento |
|
‘nf.intermediario.inscricao_municipal |
|
‘nf.construcao_civil.codigo_obra |
|
‘nf.construcao_civil.art |
Campos adicionais para Cancelamento de NFSe:
Nome |
Descrição |
|---|---|
‘nf.cancela.id’ |
Identificação única do cancelamento |
‘nf.numero’ |
Número da NFSe gerada |
‘nf.codigo_cancelamento’ |
Código do cancelamento |
O Código do Cancelamento é obrigatório, apesar que na documentação da versão 2.02 informar que esse código é opcional. Sem esse código o webservices retorna “Erro desconhecido”.
Os valores possíveis são:
1 - Erro na emissão
2 - Serviço não prestado
3 - Erro de assinatura
4 - Duplicidade da nota
5 - Erro de processamento
Sendo que os códigos 3 e 5 são de uso restrito da Administração Tributária Municipal.
Cancelando uma NFSe
from nfsepmsj.client import NFSeAbrasf
pfx_file = '/caminho/do/arquivo.pfx'
pfx_passwd = 'Senha do arquivo pfx'
nfse = NFSeAbrasf(pfx_file, pfx_passwd)
cancel_data = {
'nf.cancela.id': 'cancel_id1',
'nf.codigo_cancelamento': '1',
'nf.numero': '1',
'nf.prestador.documento': '99999999999999',
'nf.prestador.inscricao_municipal': '9999999',
'nf.codigo_municipio': '4216602',
}
nfse.add_to_cancel(cancel_data)
result, errors = nfse.cancel()
result vai ser uma lista de dicionários com a estrutura:
[
{
'nf.cancela.id': 'cancel_id1',
'xml.response': 'XML com a resposta do webservices',
'xml.request': 'o XML que foi gerado para envio',
}
]
E errors, se houver algum, como, por exemplo, erro de validação do XML, vai ser:
[
{
'nf.cancela.id': 'cancel_id1',
'xml.request': 'o XML que foi gerado para envio',
'error': 'a mensagem do erro'
}
]
Campos adicionais para Envio em Lote de NFSe:
Nome |
Descrição |
|---|---|
‘lote.id’ |
Identificação única do lote |
‘lote.numero’ |
Número do lote |
‘nf.prestador.documento’ |
CPF/CNPJ do prestador |
‘nf.prestador.inscricao_municipal’ |
Inscrição municipal do prestador |
Lembrando que nesta modalidade os dados de RPS devem conter os campos:
‘rps.numero’
‘rps.serie’
‘rps.tipo’
‘rps.data.emissao’
‘rps.status’
Enviando um lote (sincrono)
from nfsepmsj.client import NFSeAbrasf
pfx_file = '/caminho/do/arquivo.pfx'
pfx_passwd = 'Senha do arquivo pfx'
nfse = NFSeAbrasf(pfx_file, pfx_passwd)
# ...
nfse.add_rps(rps01_data)
nfse.add_rps(rps02_data)
# ...
batch_data = {
'lote.id': 'lote_id',
'lote.numero': '201901',
'nf.prestador.documento': '99999999999999',
'nf.prestador.inscricao_municipal': '9999999',
}
result, errors = nfse.send_batch(batch_data)
result vai ser um dicionário com a estrutura:
{
'lote.id': 'lote_id',
'xml.response': 'XML com a resposta do webservices',
'xml.request': 'o XML que foi gerado para envio',
}
E errors, se houver algum, como, por exemplo, erro de validação do XML, vai ser:
{
'lote.id': 'lote_id',
'xml.request': 'o XML que foi gerado para envio',
'error': 'a mensagem do erro'
}
Consultando o Status de um Lote
Campos adicionais para Consulta de Lote de NFSe:
Nome |
Descrição |
|---|---|
‘lote.protocolo’ |
Número do protocolo recebido (geralmente ao enviar lotes assíncronos) |
from nfsepmsj.client import NFSeAbrasf
pfx_file = '/caminho/do/arquivo.pfx'
pfx_passwd = 'Senha do arquivo pfx'
nfse = NFSeAbrasf(pfx_file, pfx_passwd)
params = {
'lote.protocolo': '12346',
'nf.prestador.documento': '99999999999999',
'nf.prestador.inscricao_municipal': '9999999',
}
result, error = nfse.get_batch_status(params)
result vai ser um dicionário com a estrutura:
{
'xml.response': 'XML com a resposta do webservices',
'xml.request': 'o XML que foi gerado para envio',
}
E error, se houver algum, como, por exemplo, erro de validação do XML, vai ser:
{
'xml.request': 'o XML que foi gerado para envio',
'error': 'a mensagem do erro'
}
Metadata
Release files for nfsepmsj 0.0.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| nfsepmsj-0.0.4.tar.gz | 34.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| nfsepmsj-0.0.4-py2.py3-none-any.whl | Python 2, Python 3 | none | any | Details |
Total release size: 68.5 kB
Release files / nfsepmsj-0.0.4.tar.gz
| Download URL | nfsepmsj-0.0.4.tar.gz |
|---|---|
| Size | 34.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
58ee6fb2b620c3c4f6b751024829caa989c61c35d798ab7ec8036d12f7491868
|
|
BLAKE2b-256 checksum How to use checksums |
6080ea171620640e598125e52bbcbd807f168029040705a98ccf795c5dc6a71a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/1.15.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/40.5.0 requests-toolbelt/0.8.0 tqdm/4.36.1 CPython/2.7.15+
|
Release files / nfsepmsj-0.0.4-py2.py3-none-any.whl
| Download URL | nfsepmsj-0.0.4-py2.py3-none-any.whl |
|---|---|
| Size | 34.4 kB |
| Tags | Python 2 Python 3 |
|
SHA-256 checksum How to use checksums |
4a43ba32b55b1861277451595fc790e4bb8d55f4495c30427b9cbeb076e445f3
|
|
BLAKE2b-256 checksum How to use checksums |
c394083d476da2bad3d640bcd3eb1d4c12edd68ecac2ad15275b5113ee5aa184
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/1.15.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/40.5.0 requests-toolbelt/0.8.0 tqdm/4.36.1 CPython/2.7.15+
|