Compare commits
merge into: felipe:master
felipe:feature/betha
felipe:feature/cte
felipe:feature/nfe-4.0
felipe:feature/nfe-mde
felipe:feature/nota-dsf
felipe:fix-endereco
felipe:fix-invalid-token-bug
felipe:fix-url-df
felipe:fix/warning
felipe:iss-net
felipe:master
felipe:master3
felipe:merge-master3
pull from: felipe:master3
felipe:feature/betha
felipe:feature/cte
felipe:feature/nfe-4.0
felipe:feature/nfe-mde
felipe:feature/nota-dsf
felipe:fix-endereco
felipe:fix-invalid-token-bug
felipe:fix-url-df
felipe:fix/warning
felipe:iss-net
felipe:master
felipe:master3
felipe:merge-master3
231 Commits
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
6eec69795c
|
Merge pull request #301 from danimaribeiro/order-exporta
Corrige a ordem da tag exportacao |
5 years ago |
|
|
75c2759196 |
Corrige a ordem da tag exportacao
|
5 years ago |
|
|
010939f062
|
Merge pull request #300 from fabioluna/feature/NT2020-0006
[IMP] NT2020-006 |
5 years ago |
|
|
19fcda59e7
|
[IMP] NT2020-006
Adiciona nova tag para adequar a NT2020-006 https://www.nfe.fazenda.gov.br/portal/exibirArquivo.aspx?conteudo=olkYgvQ3E7o= |
5 years ago |
|
|
98215954f8
|
Update README.md
|
5 years ago |
|
|
e05f972fee
|
Update README.md
|
5 years ago |
|
|
f052a5ae3f
|
Merge pull request #299 from filipealft/patch-3
Update setup.py |
5 years ago |
|
|
9a1cf24839
|
Merge pull request #298 from filipealft/patch-2
Update leiauteNFe_v4.00.xsd |
5 years ago |
|
|
41a0d028c1
|
Update setup.py
increment version |
5 years ago |
|
|
b552caa7ac
|
Update leiauteNFe_v4.00.xsd
fix leiauteNFe_v4 |
5 years ago |
|
|
092c467370
|
Merge pull request #297 from felipepaloschi/increment_version
Incrementing version |
5 years ago |
|
|
b71dee280c |
Incrementing version
|
5 years ago |
|
|
5e136c027a
|
Merge pull request #296 from filipealft/patch-1
Update NfeAutorizacao.xml |
5 years ago |
|
|
ae4ca15813
|
Update NfeAutorizacao.xml
Add indicativo do intermediador |
5 years ago |
|
|
969701912a
|
Merge pull request #292 from faio/master3
Geração NFSe prefeitura de Goiânia |
5 years ago |
|
|
922b26b7f4
|
Melhorias GINFES (#293) - Registrar nota assincronamente, Cancelar nota
* Fix ginfes cities link * Fix Cnpj in xml CancelarNfseV3 template * Update CancelarNfseV3.xml * Update CancelarNfseV3.xml * Update CancelarNfseV3.xml * Update CancelarNfseV3.xml * Update CancelarNfseV3.xml * Update CancelarNfseV3.xml * Update CancelarNfseV3.xml * Update CancelarNfseV3.xml * Update CancelarNfseV3.xml * Update CancelarNfseV3.xml * Update CancelarNfseV3.xml * Update CancelarNfseV3.xml * Update CancelarNfseV3.xml * Update CancelarNfseV3.xml * Update CancelarNfseV3.xml * Update CancelarNfseV3.xml * Update __init__.py * Update CancelarNfseV3.xml * Update CancelarNfseV3.xml * Update CancelarNfseV3.xml * Update CancelarNfseV3.xml * Update __init__.py * Create RecepcionarLoteRpsV3 * Update __init__.py * Update __init__.py * Implement xml_consultar_nfse_por_rps * Fix layout ConsultarNfseRpsEnvio * Add namespace to xml properties * Fix name of service in servico_consultar_nfse_rps_envio_v03 * Fix ConsultarNfseV3 * Fix xmlns ConsultarNfseEnvio * Fix property ConsultarNfseEnvio * Add PeriodoEmissao to ConsultarNfseEnvio * Change number to numero_nfse instead on ConsultarNfseEnvio * Remove periodo on ConsultarNfse |
5 years ago |
|
|
a008f99434 |
Retirado métodos não padrões na emissão de NFSe para a prefeitura de Goiânia/GO.
|
5 years ago |
|
|
79024b4747 |
Adicionado método para gerar o xml da NFSe para a prefeitura de Goiânia.
|
5 years ago |
|
|
17ee875c18 |
- Colocado como opcional tags de preenchimento de endereço do tomador conforme manual.
|
5 years ago |
|
|
54bf90863e |
- Colocado como opcional tags de preenchimento de impostos do serviço conforme manual da prefeitura.
|
5 years ago |
|
|
486d2ad1d9 |
- Adicionado consulta do RPS para a prefeitura de Goiânia/GO.
- Colocado como opcional a tag endereço na geração do rps conforme manual da prefeitura. |
5 years ago |
|
|
27c9ce902b |
- Correção no nome do método.
- Atualização do README.md |
5 years ago |
|
|
0b2c7259af
|
Merge pull request #1 from danimaribeiro/master3
Merge |
5 years ago |
|
|
ab57f6c4e0 |
Adicionado geração do RPS para a prefeitura de Goiânia/GO.
|
5 years ago |
|
|
719e15474b
|
Merge pull request #287 from danimaribeiro/fix-url-df
Corrige as urls do DF |
5 years ago |
|
|
f358b33d2f
|
Merge branch 'master3' into fix-url-df
|
5 years ago |
|
|
08c3bd31e3 |
Corrige as urls do DF
|
5 years ago |
|
|
c5b4d9e4e8 |
Fix unit tests
|
5 years ago |
|
|
7729c1df50 |
Carga tributaria media como opcional
|
5 years ago |
|
|
325bb78234 |
New urls for nfce RS
|
5 years ago |
|
|
ae1d57b5c6 |
Fixed overflow of address text
|
6 years ago |
|
|
05472e59a2 |
Melhoria na DANFE
Implementa blocos para impressão do endereço de entrega e endereço de retirada, conforme a NT2018 005. |
6 years ago |
|
|
6357ea46a0
|
Update XSD schemas for NFe (#272)
|
6 years ago |
|
|
4e6da7011e
|
Novos campos para icms retido por substituição tributária (#270)
* Fix the xml template for sending nfe * Novos campos para icms retido por substituição tributária |
6 years ago |
|
|
36c9b6c9ae |
Fix the xml template for sending nfe
|
6 years ago |
|
|
57672b4d9e
|
Bump version (#266)
|
6 years ago |
|
|
09a0ff15be
|
Criando parametros para contingência (#233)
* Criando parametros para contingência
Foi criado no template de autorização de NF-e o parametros:
dhCont = Data que o sistema entrou em contingência;
xJust = O motivo do sistema ter entrado em contingência.
E foi alterado versão
* Geração do QRCode
Foi alterado para gerar o QRCode pelo pytrustnfe ou manter da forma antiga sem afetar os usuarios que prefere gerar manualmente.
Foi alterado a função de assinatura para que possa retornar o etree ou string.
corrigindo o retorno do assina_xml para manter codigo
criado nova função para gerar qrcode com a possiblidade de assinatura tbm com parametro de entrada minimos;
edição do xml para gerar as tags de Informações Suplementares mesmo que não seja repassada a informação, gerando com informação de um ponto.
Co-authored-by: Michael Douglas <maiconkkl@users.noreply.github.com>
Co-authored-by: Danimar Ribeiro <danimaribeiro@gmail.com>
|
6 years ago |
|
|
09428c65a3
|
Merge pull request #265 from danimaribeiro/gabicavalcante-master3
Adicionando NFSe de Natal |
6 years ago |
|
|
944c7145bf |
Revert a few things before for nfe
|
6 years ago |
|
|
66127b4b1e
|
Merge branch 'master3' into gabicavalcante-master3
|
6 years ago |
|
|
4eaaa83016
|
Merge pull request #264 from danimaribeiro/loggi/master3
Loggi/master3 |
6 years ago |
|
|
79e192c9f8 |
Increment version
|
6 years ago |
|
|
3d2bd59f98 |
update gitignore
|
6 years ago |
|
|
9c4650d5da
|
Merge branch 'master3' into master3
|
6 years ago |
|
|
80950950d7
|
Merge pull request #7 from loggi/resolve-fork
[FINPD-69] Usar PyTrustNFe para emitar as notas fiscais |
6 years ago |
|
|
13900c782b |
test batch size
|
6 years ago |
|
|
7eb152da65 |
updates
|
6 years ago |
|
|
547af9d609 |
adding tests for rps batch
|
6 years ago |
|
|
77b4bfbfa9 |
fix tests
|
6 years ago |
|
|
404c9dd743 |
fix natal
|
6 years ago |
|
|
a14a06c2e9 |
remove
|
6 years ago |
|
|
0b5ffd82af |
base url
|
6 years ago |
|
|
9b125f513e |
fix nfse natal
|
6 years ago |
|
|
ecea3543ad |
add tests natal
|
6 years ago |
|
|
9574a48d8d |
flask8
|
6 years ago |
|
|
8c311d4caf |
black - python code formater
|
6 years ago |
|
|
c7beb73a6b |
add natal nfse
|
6 years ago |
|
|
100d6aa909
|
(Pytrust) fixing templete and bump version to 1.0.33.post3 (#6)
|
6 years ago |
|
|
09362d0f48
|
feat(pytrust) changing amount of rps sent. (#3)
* feat(pytrust) changing amount of rps sent. * Bump to v1.0.33.post2 |
6 years ago |
|
|
0b2e3ce204 |
New release
|
6 years ago |
|
|
55c44c2beb |
Adicionado as URL's para emissão de NFC-e no estado de MG. close issue #255
|
6 years ago |
|
|
90544b7301 |
Alterado webservice de consulta CNPJ do Estado de Minas Gerais
|
6 years ago |
|
|
a94092d128 |
[FIX] Corrigindo valor vISSRet
|
6 years ago |
|
|
8f98065ffc |
Add value 0.00 when ICMS value is not provided
|
6 years ago |
|
|
8768b24202 |
[IMP] Implementação de danfce de contingência - mensagens no danfce
|
6 years ago |
|
|
8e2b326010 |
[FIX] Cancelamento pode também ser status 155
|
6 years ago |
|
|
4ebc848237 |
[VER] Increment version
|
6 years ago |
|
|
a9154ba93d |
[FIX] Utilizando o campo xPed diretamente do produto
|
6 years ago |
|
|
704cd29b42 |
[FIX] Corrige NFS-e Simpliss
|
6 years ago |
|
|
ad83071171 |
[WIP] Implementação de NFSe Aparecida SP.
|
6 years ago |
|
|
b9f567953b |
Correção no arquivo xsd referenciado
|
7 years ago |
|
|
e229bd8f53 |
[ADD] new version
|
7 years ago |
|
|
7f360d39a8 |
[FIX] Corrige Urls de NFC-e para SP
|
7 years ago |
|
|
2ada587c2a |
Melhorias no DFeDistribuicao (#230)
* Corrigindo as URL de manaus * Alterando função da validação de esquema para não ser feito repetições e poder reutilizar a função só mudando o xsd; Foi alterado o template da função de consultra distribuição do DFe, permitindo consulta via NSU. * Remoção da classe de validação do esquema e deixando somente como função * Atualização do Readme para facilitar o uso das funções xml_consulta_distribuicao_nfe e valida_nfe; |
7 years ago |
|
|
cd9b87da94 |
Corrigindo as URL de manaus
Foi corrigido os webservices da nfce de manaus |
7 years ago |
|
|
9b8a37ce41 |
New version
|
7 years ago |
|
|
fd165c103b |
Correçao do erro gerado na mudança de versao 1.0.37
File "/usr/local/lib/python3.5/dist-packages/PyTrustNFe3-1.0.37-py3.5.egg/pytrustnfe/nfe/templates/NfeAutorizacao.xml", line 262, in top-level template code
<xPed>{{ NFe.infNFe.compra.xPed }}</xPed>
File "/usr/lib/python3/dist-packages/jinja2/environment.py", line 408, in getattr
return getattr(obj, attribute)
jinja2.exceptions.UndefinedError: 'dict object' has no attribute 'compra'
|
7 years ago |
|
|
a01421febd |
[FIX] servidor consulta svrs
|
7 years ago |
|
|
ba2ca969c8 |
[FIX] Add markdown type to readme
|
7 years ago |
|
|
d8d6b947a6 |
[ADD] Adiciona tag xped no item da nfe
* [FIX] xped path * [version] upgrade |
7 years ago |
|
|
0d3dd0693f |
[FIX] Ajusta a nota de petropolis ao novo formato
|
7 years ago |
|
|
710490dc1d |
[FIX] Product description overwriting NCM (#223)
* [FIX] Product description overwriting ncm * [VERSION] Increments |
7 years ago |
|
|
391dd1ae7d |
[IMP] NT 2018_005 v1.20 (#222)
Implementa novas tags incluídas na NT 2018_005 v1.20, que pode ser localizada em https://bit.ly/2FpEjp4. |
7 years ago |
|
|
eadc7b7306 |
[VER] New version
* [FIX] Dont duplicate items * [VERSION] Add |
7 years ago |
|
|
aea7429327 |
Merge branch 'master3' of github.com:danimaribeiro/PyTrustNFe into master3
|
7 years ago |
|
|
051f3b8f12 |
[VERSION] Increments version
|
7 years ago |
|
|
b5bcf0cd88 |
[FIX] Last item missed when doesnt fit in current page
|
7 years ago |
|
|
ba9e05538e |
Fix 'bytes' object has no attribute 'encode'
|
7 years ago |
|
|
c16a31469e |
Incrementa versão.
|
7 years ago |
|
|
452af1ecb3 |
Corrige url de consulta NFC-e Paraná.
|
7 years ago |
|
|
945dd77bea |
[FIX] nfeInutilizacaoCE url (#211)
* fix CE url in patch * flake8 * verifiy environment before choose URI |
7 years ago |
|
|
b01cde145e
|
Merge pull request #213 from danimaribeiro/Implanti-Solucoes-master3
Implanti solucoes master3 |
7 years ago |
|
|
bf03d54107 |
[VERSION] Increment pytest version to fix build
|
7 years ago |
|
|
197f36b9ed |
Erro na url de produção
Correção na url de produção, falha boba |
7 years ago |
|
|
628c3a20bf |
Correção do p=
Retirada do p= |
7 years ago |
|
|
9c4f76446b |
urlChave e Webservices
Foi adicionado uma função para retorno da urlChave do NFC-e que é diferente da url do QRCode; Foi corrigido os webservices da sefaz BA que estava as antigas; |
7 years ago |
|
|
b0a9e5370e |
[FIX] Fix patch method for inutilizacao - wrong merge
|
7 years ago |
|
|
c74893b658 |
[FIX] Inutilização NFe CE - Add a patch method
|
7 years ago |
|
|
59d4cf94b4 |
[FIX] Ajuste de cancelamento NFSe BH
|
7 years ago |
|
|
8de6521e8d |
[FIX] Adicionando complemento de endereço na danfe
|
7 years ago |
|
|
8c2de797aa
|
* [FIX] Ajuste na URL do parana
|
7 years ago |
|
|
a81c869a56 |
[FIX] Fix https warnings
|
7 years ago |
|
|
2723aece89 |
[ADD] Adiciona urls do qrcode para NFCe
|
7 years ago |
|
|
f01405affa |
[FIX] Sempre mostra o valor zerado de IPI e aliquota caso não existir
|
7 years ago |
|
|
ee047ef0cd |
[FIX] Corrige o encoding do retorno da nfse
|
7 years ago |
|
|
c7c380ce36 |
Webservices NFC-e Mato Grosso. (#194)
Inclui webservices para emissão de NFC-e no Mato Grosso. |
7 years ago |
|
|
b645b8ba78 |
Inclui Webservices para NFC-e do Mato Grosso do Sul. (#195)
|
7 years ago |
|
|
8b54bfa081 |
[IMP] Habilita enviar apenas o CPF no destinatário
|
7 years ago |
|
|
a25dd8a9d3 |
Webservices NFC-e Paraná
Incluí webservices da NFC-e do Paraná. |
7 years ago |
|
|
e233abfb04 |
[FIX] Corrige envio de NFS-e Ginfes
|
7 years ago |
|
|
ff75a6c77a |
[FIX] Calcula previamente o tamanho do proximo item
se ultrapassar o tamanho disponível finaliza e continua na próxima iteração |
7 years ago |
|
|
d4c3a8a0a7 |
[VER] New version
|
7 years ago |
|
|
36142aaf58 |
add troco and valor pago with the added values
|
7 years ago |
|
|
b81f3ddbc6 |
[FIX] first page overwriting (#188)
* change number of lines in first page * increments version |
7 years ago |
|
|
0ce7c3045f |
[FIX] Voltando as urls antigas, a principio DF não atualizaram ainda
|
7 years ago |
|
|
dbe2ab2ec5 |
[FIX] Ajusta a consulta de download de xml
|
7 years ago |
|
|
790543d36a |
[FIX] Ajustando as urls de consulta da danfce
|
7 years ago |
|
|
a252d86523 |
[FIX] Removing useless code for NFCe, adjusting xml template for NFCe
|
7 years ago |
|
|
4f3da1a075 |
[IMP] Fixing the fields for service invoices and danfe
|
7 years ago |
|
|
0c12982197 |
[FIX] Assign the correct variable when addin thousand separator
|
7 years ago |
|
|
7f5fe48999 |
thousandseparator added to monetary fields
|
7 years ago |
|
|
21994c73e8 |
[FIX] Removendo previamente os espaços resolve o problema
|
7 years ago |
|
|
43289e84c1 |
[FIX] Percentuais de tributação para nota paulistana
|
7 years ago |
|
|
3c5e8cd24c |
[FIX] Try to fix strange with spaces in some eletronic documents
|
7 years ago |
|
|
95e3e5710c |
Corrige webservice de retorno de autorização do Paraná.
|
7 years ago |
|
|
13a59b61b6 |
[FIX] Compare the operation name in lower case
|
7 years ago |
|
|
260a7e5add |
[11.0][IMP]different method to compute lines per page (#172)
* Adicionando mais espaço para as linhas de produtos |
7 years ago |
|
|
aafb2cf92a |
DSF - xml decode and url fix (#171)
* [WIP]NFS-e DSF * [WIP]NFS-e url * Update setup.py |
7 years ago |
|
|
0a1539ce1a |
[FIX] Corrige urls do MT
|
7 years ago |
|
|
59457090e9 |
[FIX] Ajusta os namespaces para envio de NFe no estado do PR
A biblioteca ZEEP remove namespaces duplicadas. O estado do PR exige a mesma namespace em duas tags, devemos adicionar a mesma na tag NFe antes do envio ao sefaz Paraná. |
7 years ago |
|
|
eea7fd74f4 |
nfse_mga minor changes in singnature, removed encode for byte type response and id on cancel template is now correct
|
7 years ago |
|
|
17770982cc |
[IMP] Migrando restante das urls da nfe 4.0
|
7 years ago |
|
|
de06defe5f |
[FIX] Realiza umas conversões de texto para evitar erros no Odoo
|
7 years ago |
|
|
2e9d83568e |
[FIX] Ajusta o danfe nos campos de frete e transportadora.
|
7 years ago |
|
|
8c132a3bbb |
[FIX] Certifica que vamos usar a operação correta ao enviar a NFE
|
7 years ago |
|
|
37506bd3ca |
Incrementa a versao da biblioteca
|
7 years ago |
|
|
92c1191d8f |
Revisado as urls da sefaz
|
7 years ago |
|
|
79abb1798c |
Atualizada as urls dos servidores sefaz ce
|
7 years ago |
|
|
bb5509c781 |
Correção do número de versão da tag nfeProc
Corrigido: número de versão da tag nfeProc de 3.10 para 4.00. A versão incorreta gerava erro de validação da nota fiscal enviada aos clientes, conforme testes realizados no site "https://www.sefaz.rs.gov.br/nfe/NFE-VAL.aspx" Alterado: número de versão do pytrustnfe da versão 0.10.1 para 0.10.2 |
7 years ago |
|
|
c9f71c9ea1 |
New zeep version uses settings instead of options
|
7 years ago |
|
|
4691c28623 |
[IMP] Novo release da pytrusnfe3
|
7 years ago |
|
|
bcbaf1474d |
[IMP] Atualizado schema da NFe
|
7 years ago |
|
|
f63ad7abbf |
[FIX] Corrige o build para o deploy
|
7 years ago |
|
|
40c3068447
|
Merge pull request #147 from danimaribeiro/feature/zeep
Feature/zeep |
7 years ago |
|
|
06764a249c |
[IMP] Fix unit tests and fix some urls
|
7 years ago |
|
|
16602cfa5b
|
Merge branch 'master3' into feature/zeep
|
7 years ago |
|
|
c95cba8ae7 |
Corrige webservice de recepção de eventos do Paraná
|
7 years ago |
|
|
9817897d30 |
update library version
|
8 years ago |
|
|
f0f38237f2 |
corrected issues in layout of danfe
|
8 years ago |
|
|
70816097e9 |
[IMP] Implementing NFe 4.0 - Cleaning up code and improve readability
|
8 years ago |
|
|
4572b99fcb |
[WIP]NFS-e Maringa
|
8 years ago |
|
|
5cbdd146f5 |
[WIP] Cleanup of useless code, using zeep for NFe soap, adjust xml files
|
8 years ago |
|
|
f4bcbb071c |
[WIP] Finalização do layout do xml, usando zeep para fazer chamada SOAP
|
8 years ago |
|
|
3180759fd9 |
Ajustando conforme validação.
|
8 years ago |
|
|
cbf17ee87d |
Adicionado campos novos da Nfe 4.0
|
8 years ago |
|
|
d4fdda4dab
|
Merge pull request #1 from loggi/frp-better-templates-for-nfse-paulistana-py3
Copy template from py2 version, fix setup.py |
8 years ago |
|
|
7fa4f4602f |
Add missing deps, bump version to 0.9.18.post2
|
8 years ago |
|
|
966ba5f795 |
[FIX] XML NFSe maringa and percent difal
|
8 years ago |
|
|
d616b3b9a6 |
Fix case name, bump version to 0.9.18.post1
|
8 years ago |
|
|
49113d7dab |
Better templates, for real.
|
8 years ago |
|
|
44bcedc33b |
Realiza a conversão do retorno corretamente com decode - BH
|
8 years ago |
|
|
8f4cf56a29 |
Adição das tags do veículo de transporte no danfe
|
8 years ago |
|
|
b474ec9913 |
Pequenos ajustes na impressão do danfce
|
8 years ago |
|
|
4f25b76ec8 |
Ajuste na url do qrcode amazonas
|
8 years ago |
|
|
c0dd5d02dd |
Implementação da danfe para NFC-e
|
8 years ago |
|
|
5893a0324b |
Correção de testes.
|
8 years ago |
|
|
c7bc21de2a |
Retira lixo código.
|
8 years ago |
|
|
5c9908da57 |
Insere servidor de cancelamento de NFC-e.
# Conflicts: # pytrustnfe/Servidores.py |
8 years ago |
|
|
cab13549cc |
Correções para envio de NFC-e
|
8 years ago |
|
|
4f8b752626 |
[WIP] NFC-e Corrige servidores.
Passa modelo do documento para localizar a url. |
8 years ago |
|
|
1d9f4b0776 |
[WIP] Implementando NFC-e SVRS
# Conflicts: # pytrustnfe/Servidores.py |
8 years ago |
|
|
e712bf0d6a |
Correção de envio Ginfes - Mudança para o zeep para webservice SOAP
|
8 years ago |
|
|
3db71b7b9a |
Nota de BH utiliza duas assinaturas
Correçõs nos templates |
8 years ago |
|
|
236515b12d |
Ajuste ao imprimir nfe cancelada, correção de encoding
|
8 years ago |
|
|
4f423e28f5 |
Implementa timezone ao imprimir a danfe
|
8 years ago |
|
|
9a1f406c62 |
Correção no envio de NFe para o estado do Ceará
|
8 years ago |
|
|
38874665b9 |
WIP - Implementação da nota de BH, tentativa de usar o zeep
|
8 years ago |
|
|
eb1db219b8 |
Nova tag de base de cálculo para nfse-floripa
|
8 years ago |
|
|
7a3f6275b8 |
Incrementando versão do pyopenssl
|
8 years ago |
|
|
1b2e206fcc |
Versão 0.9.15
|
8 years ago |
|
|
2aea7bae5d |
Update utils.py
|
8 years ago |
|
|
1f5645cf8e |
[FEAT][10.0]Cancelado no DANFE
# Conflicts: # setup.py |
8 years ago |
|
|
92a2505726 |
Correcao NFS-e Floripa - Descrição dos serviços
* decode no sent_xml nfse imperial * |
8 years ago |
|
|
ed322847ed |
decode no sent_xml nfse imperial
|
8 years ago |
|
|
6760152ed5 |
Ajuste no readme com novas implementações, remoção do appveyor build
Não vai ser desta vez que vamos atender o windows :/ |
8 years ago |
|
|
42d2a8d1e3 |
[DONE] Finalização do layout Nota Carioca - Geração e Cancelamento
|
8 years ago |
|
|
2bbd78c295 |
Implementação da nota carioca
|
8 years ago |
|
|
141fecb6a0 |
FIX - Corrige eventos do manifesto e geração da nfe processada
|
8 years ago |
|
|
9c2344c15e |
Master3 nfse imperial (#110)
* inserida danfse imperial * adicionado encode nfse imperial * correcao nfse imperial |
8 years ago |
|
|
105843d719 |
Master3 bug unicode (#109)
* correçao de bug unicode * bug encode nfse paulistana * incremento versao |
8 years ago |
|
|
6117a8b63f |
'Incrementar versão ;-;'
|
8 years ago |
|
|
6b00132c4b |
[FIX]Normalize e escape em campos de texto
|
8 years ago |
|
|
e1754c8e16 |
Incremento da versão do suds requests
|
8 years ago |
|
|
954dfcfecf |
Incremento de versão
|
8 years ago |
|
|
baca382a0f
|
Merge pull request #98 from danimaribeiro/master-fix
Master fix |
8 years ago |
|
|
f73aadada9
|
Merge branch 'master3' into master-fix
|
8 years ago |
|
|
57997f9164 |
Merge branch 'master3' into master-fix
# Conflicts: # .gitignore # pytrustnfe/nfe/danfe.py # setup.py |
8 years ago |
|
|
24be4815e1 |
Incremento de versão
|
8 years ago |
|
|
55031fe78d |
Implementação do cancelamento de NFSe - Floripa
|
8 years ago |
|
|
1f56dd5fa7 |
Retorna uma exceção correta quando não for possível obter o token
|
8 years ago |
|
|
7d6aacb655 |
Incremento de versões das dependencias
|
8 years ago |
|
|
d0ce9460b1
|
Merge pull request #86 from danimaribeiro/feature/nfse-floripa
Feature NFS-e Floripa |
8 years ago |
|
|
d53a0bb833
|
Merge branch 'master3' into feature/nfse-floripa
|
8 years ago |
|
|
78b0e47dfb |
Finalizado a parte de emissão de NFSe Floripa
|
8 years ago |
|
|
7d4f9079c8 |
* correção da url de campo grande-ms
|
8 years ago |
|
|
36611c8f81 |
alteração nfse campinas para dsf
|
8 years ago |
|
|
d2a0c26b1a |
mudança nfse campinas para dsf, adicionadas outras cidades também emitidas pela dsf
|
8 years ago |
|
|
4fc6b9dc89 |
adicionados urls de cidades do dsf
|
8 years ago |
|
|
f42937ae5f |
[FIX]
|
8 years ago |
|
|
4915472aa7 |
[FIX]
|
8 years ago |
|
|
0a21cfaad8 |
[FIX]Campo CPF
|
8 years ago |
|
|
22ac348b8b |
Implementa NFse de Campinas
|
8 years ago |
|
|
c2e2d1ed46 |
[WIP] Implementa NFS-e Campinas
|
8 years ago |
|
|
5a85580ba4 |
[WIP] - NFSE Floripa
|
8 years ago |
|
|
2138bd3ee2 |
adicionado string.strip no recursive_normalize
|
8 years ago |
|
|
7cff7bb5f1 |
[WIP] Implementação da nfse de florianópolis
|
8 years ago |
|
|
9219ec4243 |
[FIX] Corrige erro 225 na NF-e, devido a caracteres especiais.
|
8 years ago |
|
|
fa3f44b0de |
[FIX]Corrige envios de eventos
|
8 years ago |
|
|
914912ec7c |
Nova versão para publicar
|
8 years ago |
|
|
582742ecca |
[FIX] Corrige consulta de distribuíção de NF-e
|
8 years ago |
|
|
9b21368d25 |
Nova versão, atualização de badges
|
8 years ago |
|
|
0b47eba7b5 |
Refactor - Permitir criar o xml de envio separadamente
Ajuste na função de validação do xml |
8 years ago |
|
|
b05bd19354 |
Build para windows
|
8 years ago |
|
|
a1c65663bc |
Updating setup.py to include font files
|
8 years ago |
|
|
aa4fd2bb42 |
Inclui fonte NimbusSanL.
|
8 years ago |
|
|
c44cd90103 |
Fixing build for windows
|
8 years ago |
|
|
7b31a2f78f |
Removendo print - Ajustando encodings
|
8 years ago |
|
|
fabe0e0561 |
Preparando pypi package para versão python >= 3.4
|
8 years ago |
|
|
0c89b3e957 |
Modificação na estrutura do projeto - Movendo testes para fora do pacote
|
8 years ago |
|
|
5c5602acf9 |
Migração para python 3 - Correção de testes
|
8 years ago |
|
|
4581ea6dbe |
Ajuste de travis e dependencias da versão 3
|
8 years ago |
175 changed files with 14383 additions and 10120 deletions
-
6.flake8
-
10.gitignore
-
10.travis.yml
-
130README.md
-
7cidades/dsf.md
-
165docs/conf.py
-
1222pytrustnfe/Servidores.py
-
8pytrustnfe/__init__.py
-
23pytrustnfe/certificado.py
-
36pytrustnfe/client.py
-
4pytrustnfe/exceptions.py
-
501pytrustnfe/nfe/__init__.py
-
29pytrustnfe/nfe/assinatura.py
-
34pytrustnfe/nfe/comunicacao.py
-
529pytrustnfe/nfe/danfce.py
-
1268pytrustnfe/nfe/danfe.py
-
BINpytrustnfe/nfe/fonts/NimbusSanL Bold.ttf
-
BINpytrustnfe/nfe/fonts/NimbusSanL Regular.ttf
-
45pytrustnfe/nfe/patch.py
-
33pytrustnfe/nfe/templates/NFeDistribuicaoDFe.xml
-
286pytrustnfe/nfe/templates/NfeAutorizacao.xml
-
5pytrustnfe/nfe/templates/NfeConsultaProtocolo.xml
-
2pytrustnfe/nfe/templates/NfeInutilizacao.xml
-
2pytrustnfe/nfe/templates/NfeRetAutorizacao.xml
-
4pytrustnfe/nfe/templates/NfeStatusServico.xml
-
6pytrustnfe/nfe/templates/RecepcaoEvento.xml
-
21pytrustnfe/nfe/templates/RecepcaoEventoCarta.xml
-
31pytrustnfe/nfe/templates/RecepcaoEventoEPEC.xml
-
2pytrustnfe/nfe/templates/RecepcaoEventoManifesto.xml
-
76pytrustnfe/nfse/aparecida/__init__.py
-
91pytrustnfe/nfse/aparecida/templates/Rps.xml
-
15pytrustnfe/nfse/aparecida/templates/cancelarNfse.xml
-
7pytrustnfe/nfse/aparecida/templates/consultarLoteRps.xml
-
13pytrustnfe/nfse/aparecida/templates/recepcionarLoteRps.xml
-
99pytrustnfe/nfse/assinatura.py
-
78pytrustnfe/nfse/betha/__init__.py
-
79pytrustnfe/nfse/bh/__init__.py
-
47pytrustnfe/nfse/bh/assinatura.py
-
13pytrustnfe/nfse/bh/templates/CancelarNfse.xml
-
11pytrustnfe/nfse/bh/templates/GerarNfse.xml
-
91pytrustnfe/nfse/bh/templates/Rps.xml
-
69pytrustnfe/nfse/carioca/__init__.py
-
13pytrustnfe/nfse/carioca/templates/CancelarNfse.xml
-
3pytrustnfe/nfse/carioca/templates/GerarNfse.xml
-
91pytrustnfe/nfse/carioca/templates/Rps.xml
-
124pytrustnfe/nfse/dsf/__init__.py
-
18pytrustnfe/nfse/dsf/templates/cancelar.xml
-
11pytrustnfe/nfse/dsf/templates/consulta_notas.xml
-
10pytrustnfe/nfse/dsf/templates/consultarLote.xml
-
22pytrustnfe/nfse/dsf/templates/consultarNFSeRps.xml
-
100pytrustnfe/nfse/dsf/templates/enviar.xml
-
12pytrustnfe/nfse/dsf/templates/soap_header.xml
-
128pytrustnfe/nfse/floripa/__init__.py
-
7pytrustnfe/nfse/floripa/templates/cancelar_nota.xml
-
41pytrustnfe/nfse/floripa/templates/processar_nota.xml
-
110pytrustnfe/nfse/ginfes/__init__.py
-
25pytrustnfe/nfse/ginfes/templates/CancelarNfseV3.xml
-
15pytrustnfe/nfse/ginfes/templates/ConsultarNfsePorRpsV3.xml
-
12pytrustnfe/nfse/ginfes/templates/ConsultarNfseV3.xml
-
61pytrustnfe/nfse/goiania/__init__.py
-
38pytrustnfe/nfse/goiania/assinatura.py
-
19pytrustnfe/nfse/goiania/templates/ConsultarNfseRps.xml
-
4pytrustnfe/nfse/goiania/templates/GerarNfse.xml
-
63pytrustnfe/nfse/goiania/templates/Rps.xml
-
74pytrustnfe/nfse/imperial/__init__.py
-
17pytrustnfe/nfse/imperial/templates/CANCELANOTAELETRONICA.xml
-
9pytrustnfe/nfse/imperial/templates/CONSULTANOTASPROTOCOLO.xml
-
9pytrustnfe/nfse/imperial/templates/CONSULTAPROTOCOLO.xml
-
14pytrustnfe/nfse/imperial/templates/CancelarNota.xml
-
43pytrustnfe/nfse/imperial/templates/GerarNota.xml
-
81pytrustnfe/nfse/imperial/templates/PROCESSARPS.xml
-
5pytrustnfe/nfse/imperial/templates/SoapRequest.xml
-
70pytrustnfe/nfse/mga/__init__.py
-
48pytrustnfe/nfse/mga/assinatura.py
-
15pytrustnfe/nfse/mga/templates/CancelarNfse.xml
-
3pytrustnfe/nfse/mga/templates/GerarNfse.xml
-
81pytrustnfe/nfse/mga/templates/Rps.xml
-
116pytrustnfe/nfse/natal/__init__.py
-
8pytrustnfe/nfse/natal/templates/EnvelopeSoap.xml
-
111pytrustnfe/nfse/natal/templates/Exemplo_LoteRPS.xml
-
112pytrustnfe/nfse/natal/templates/Rps.xml
-
3pytrustnfe/nfse/natal/templates/cabecalho.xml
-
15pytrustnfe/nfse/natal/templates/cancelarNfse.xml
-
7pytrustnfe/nfse/natal/templates/consultarLoteRps.xml
-
11pytrustnfe/nfse/natal/templates/recepcionarLoteRps.xml
-
73pytrustnfe/nfse/paulistana/__init__.py
-
23pytrustnfe/nfse/paulistana/templates/EnvioLoteRPS.xml
-
62pytrustnfe/nfse/paulistana/templates/EnvioRPS.xml
-
66pytrustnfe/nfse/simpliss/__init__.py
-
36pytrustnfe/nfse/susesu/__init__.py
-
9pytrustnfe/nfse/susesu/templates/EnviarNota.xml
-
1pytrustnfe/test/XMLs/paulistana_resultado.xml
-
34pytrustnfe/test/test_add_qr_code.py
-
57pytrustnfe/test/test_assinatura.py
-
82pytrustnfe/test/test_certificado.py
-
20pytrustnfe/test/test_comunicacao.py
-
19pytrustnfe/test/test_consulta_cadastro.py
-
143pytrustnfe/test/test_nfse_paulistana.py
-
48pytrustnfe/test/test_servidores.py
-
119pytrustnfe/test/test_utils.py
@ -0,0 +1,6 @@ |
|||
[flake8] |
|||
ignore = E203, E266, E501, W503, F403, E402, E265, E231 |
|||
max-line-length = 79 |
|||
max-complexity = 18 |
|||
select = B,C,E,F,W,T4,B9 |
|||
exclude = .git,__pycache__,api/specs/,migrations/ |
|||
@ -0,0 +1,7 @@ |
|||
* Belém - PA |
|||
* Sorocaba - SP |
|||
* Teresina - PI |
|||
* Campinas - SP |
|||
* Uberlandia - MG |
|||
* São Luis - MA |
|||
* Campo Grande - MS |
|||
1222
pytrustnfe/Servidores.py
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,243 +1,378 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2016 Danimar Ribeiro, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
|
|||
import os |
|||
import hashlib |
|||
import os |
|||
import requests |
|||
from lxml import etree |
|||
from .comunicacao import executar_consulta |
|||
from .patch import has_patch |
|||
from .assinatura import Assinatura |
|||
from pytrustnfe.xml import render_xml |
|||
from pytrustnfe.utils import CabecalhoSoap |
|||
from pytrustnfe.xml import render_xml, sanitize_response |
|||
from pytrustnfe.utils import gerar_chave, ChaveNFe |
|||
from pytrustnfe.Servidores import localizar_url, localizar_qrcode |
|||
from pytrustnfe.xml.validate import valida_nfe |
|||
from pytrustnfe.exceptions import NFeValidationException |
|||
|
|||
|
|||
def _build_header(method, **kwargs): |
|||
action = { |
|||
'NfeAutorizacao': ('NfeAutorizacao', '3.10'), |
|||
'NfeRetAutorizacao': ('NfeRetAutorizacao', '3.10'), |
|||
'NfeConsultaCadastro': ('CadConsultaCadastro2', '2.00'), |
|||
'NfeInutilizacao': ('NfeInutilizacao2', '3.10'), |
|||
'RecepcaoEventoCancelamento': ('RecepcaoEvento', '1.00'), |
|||
'RecepcaoEventoCarta': ('RecepcaoEvento', '1.00'), |
|||
'NFeDistribuicaoDFe': ('NFeDistribuicaoDFe/nfeDistDFeInteresse', |
|||
'1.00'), |
|||
'RecepcaoEventoManifesto': ('RecepcaoEvento', '1.00'), |
|||
} |
|||
vals = {'estado': kwargs['estado'], |
|||
'soap_action': action[method][0], |
|||
'versao': action[method][1]} |
|||
return CabecalhoSoap(**vals) |
|||
from pytrustnfe.Servidores import localizar_url |
|||
from pytrustnfe.urls import url_qrcode, url_qrcode_exibicao |
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key |
|||
from requests.packages.urllib3.exceptions import InsecureRequestWarning |
|||
# Zeep |
|||
from requests import Session |
|||
from zeep import Client |
|||
from zeep.transports import Transport |
|||
|
|||
|
|||
def _generate_nfe_id(**kwargs): |
|||
for item in kwargs['NFes']: |
|||
for item in kwargs["NFes"]: |
|||
vals = { |
|||
'cnpj': item['infNFe']['emit']['cnpj_cpf'], |
|||
'estado': item['infNFe']['ide']['cUF'], |
|||
'emissao': '%s%s' % (item['infNFe']['ide']['dhEmi'][2:4], |
|||
item['infNFe']['ide']['dhEmi'][5:7]), |
|||
'modelo': item['infNFe']['ide']['mod'], |
|||
'serie': item['infNFe']['ide']['serie'], |
|||
'numero': item['infNFe']['ide']['nNF'], |
|||
'tipo': item['infNFe']['ide']['tpEmis'], |
|||
'codigo': item['infNFe']['ide']['cNF'], |
|||
"cnpj": item["infNFe"]["emit"]["cnpj_cpf"], |
|||
"estado": item["infNFe"]["ide"]["cUF"], |
|||
"emissao": "%s%s" |
|||
% ( |
|||
item["infNFe"]["ide"]["dhEmi"][2:4], |
|||
item["infNFe"]["ide"]["dhEmi"][5:7], |
|||
), |
|||
"modelo": item["infNFe"]["ide"]["mod"], |
|||
"serie": item["infNFe"]["ide"]["serie"], |
|||
"numero": item["infNFe"]["ide"]["nNF"], |
|||
"tipo": item["infNFe"]["ide"]["tpEmis"], |
|||
"codigo": item["infNFe"]["ide"]["cNF"], |
|||
} |
|||
chave_nfe = ChaveNFe(**vals) |
|||
chave_nfe = gerar_chave(chave_nfe, 'NFe') |
|||
item['infNFe']['Id'] = chave_nfe |
|||
item['infNFe']['ide']['cDV'] = chave_nfe[len(chave_nfe) - 1:] |
|||
|
|||
|
|||
def _add_required_node(elemTree): |
|||
ns = elemTree.nsmap |
|||
if None in ns: |
|||
ns['ns'] = ns[None] |
|||
ns.pop(None) |
|||
|
|||
prods = elemTree.findall('ns:NFe/ns:infNFe/ns:det/ns:prod', namespaces=ns) |
|||
for prod in prods: |
|||
element = prod.find('ns:cEAN', namespaces=ns) |
|||
if element is None: |
|||
cEan = etree.Element('cEAN') |
|||
prod.insert(1, cEan) |
|||
element = prod.find('ns:cEANTrib', namespaces=ns) |
|||
if element is None: |
|||
cEANTrib = etree.Element('cEANTrib') |
|||
vProd = prod.find('ns:vProd', namespaces=ns) |
|||
prod.insert(prod.index(vProd) + 1, cEANTrib) |
|||
return elemTree |
|||
|
|||
|
|||
def _add_qrCode(xml, **kwargs): |
|||
xml = etree.fromstring(xml) |
|||
inf_nfe = kwargs['NFes'][0]['infNFe'] |
|||
nfe = xml.find(".//{http://www.portalfiscal.inf.br/nfe}NFe") |
|||
infnfesupl = etree.Element('infNFeSupl') |
|||
qrcode = etree.Element('qrCode') |
|||
chave_nfe = inf_nfe['Id'][3:] |
|||
dh_emissao = inf_nfe['ide']['dhEmi'].encode('hex') |
|||
versao = '100' |
|||
ambiente = kwargs['ambiente'] |
|||
valor_total = inf_nfe['total']['vNF'] |
|||
dest_cpf = 'Inexistente' |
|||
dest = nfe.find(".//{http://www.portalfiscal.inf.br/nfe}dest") |
|||
if dest: |
|||
dest_parent = dest.getparent() |
|||
dest_parent.remove(dest) |
|||
if inf_nfe.get('dest', False): |
|||
if inf_nfe['dest'].get('CPF', False): |
|||
dest_cpf = inf_nfe['dest']['CPF'] |
|||
dest = etree.Element('dest') |
|||
cpf = etree.Element('CPF') |
|||
cpf.text = dest_cpf |
|||
dest.append(cpf) |
|||
dest_parent.append(dest) |
|||
icms_total = inf_nfe['total']['vICMS'] |
|||
dig_val = xml.find( |
|||
".//{http://www.w3.org/2000/09/xmldsig#}DigestValue")\ |
|||
.text.encode('hex') |
|||
cid_token = kwargs['NFes'][0]['infNFe']['codigo_seguranca']['cid_token'] |
|||
csc = kwargs['NFes'][0]['infNFe']['codigo_seguranca']['csc'] |
|||
|
|||
c_hash_QR_code = "chNFe={0}&nVersao={1}&tpAmb={2}&cDest={3}&dhEmi={4}&vNF\ |
|||
={5}&vICMS={6}&digVal={7}&cIdToken={8}{9}".\ |
|||
format(chave_nfe, versao, ambiente, dest_cpf, dh_emissao, |
|||
valor_total, icms_total, dig_val, cid_token, csc) |
|||
c_hash_QR_code = hashlib.sha1(c_hash_QR_code).hexdigest() |
|||
|
|||
QR_code_url = "?chNFe={0}&nVersao={1}&tpAmb={2}&{3}dhEmi={4}&vNF={5}&vICMS\ |
|||
={6}&digVal={7}&cIdToken={8}&cHashQRCode={9}".\ |
|||
format(chave_nfe, versao, ambiente, |
|||
'cDest={}&'.format(dest_cpf) if dest_cpf != 'Inexistente' |
|||
else '', dh_emissao, valor_total, icms_total, dig_val, |
|||
cid_token, c_hash_QR_code) |
|||
qr_code_server = localizar_qrcode(kwargs['estado'], ambiente) |
|||
qrcode_text = qr_code_server + QR_code_url |
|||
qrcode.text = etree.CDATA(qrcode_text) |
|||
infnfesupl.append(qrcode) |
|||
nfe.insert(1, infnfesupl) |
|||
return etree.tostring(xml) |
|||
chave_nfe = gerar_chave(chave_nfe, "NFe") |
|||
item["infNFe"]["Id"] = chave_nfe |
|||
item["infNFe"]["ide"]["cDV"] = chave_nfe[len(chave_nfe) - 1 :] |
|||
|
|||
|
|||
def _send(certificado, method, sign, **kwargs): |
|||
path = os.path.join(os.path.dirname(__file__), 'templates') |
|||
xmlElem_send = render_xml(path, '%s.xml' % method, True, **kwargs) |
|||
def _render(certificado, method, sign, **kwargs): |
|||
path = os.path.join(os.path.dirname(__file__), "templates") |
|||
xmlElem_send = render_xml(path, "%s.xml" % method, True, **kwargs) |
|||
|
|||
modelo = xmlElem_send.find(".//{http://www.portalfiscal.inf.br/nfe}mod") |
|||
modelo = modelo.text if modelo is not None else '55' |
|||
if modelo == '65': |
|||
pagamento = etree.Element('pag') |
|||
tipo_pagamento = etree.Element('tPag') |
|||
valor = etree.Element('vPag') |
|||
valor_pago = kwargs['NFes'][0]['infNFe']['total']['vNF'] |
|||
metodo_pagamento = kwargs['NFes'][0]['infNFe']['pagamento'] |
|||
tipo_pagamento.text, valor.text = metodo_pagamento, valor_pago |
|||
pagamento.append(tipo_pagamento) |
|||
pagamento.append(valor) |
|||
transp = xmlElem_send.find( |
|||
".//{http://www.portalfiscal.inf.br/nfe}transp") |
|||
transp.addnext(pagamento) |
|||
modelo = modelo.text if modelo is not None else "55" |
|||
|
|||
if sign: |
|||
# Caso for autorização temos que adicionar algumas tags tipo |
|||
# cEan, cEANTrib porque o governo sempre complica e não segue padrão |
|||
if method == 'NfeAutorizacao': |
|||
xmlElem_send = _add_required_node(xmlElem_send) |
|||
|
|||
signer = Assinatura(certificado.pfx, certificado.password) |
|||
if method == 'NfeInutilizacao': |
|||
xml_send = signer.assina_xml(xmlElem_send, kwargs['obj']['id']) |
|||
if method == 'NfeAutorizacao': |
|||
xml_send = signer.assina_xml( |
|||
xmlElem_send, kwargs['NFes'][0]['infNFe']['Id']) |
|||
if 'validate' in kwargs: |
|||
erros = valida_nfe(xml_send) |
|||
if erros: |
|||
raise NFeValidationException('Erro ao validar NFe', |
|||
erros=erros, |
|||
sent_xml=xml_send) |
|||
elif method == 'RecepcaoEventoCancelamento': |
|||
xml_send = signer.assina_xml( |
|||
xmlElem_send, kwargs['eventos'][0]['Id']) |
|||
|
|||
if method == 'RecepcaoEventoCarta': |
|||
if method == "NfeInutilizacao": |
|||
xml_send = signer.assina_xml(xmlElem_send, kwargs["obj"]["id"]) |
|||
if method == "NfeAutorizacao": |
|||
xml_send = signer.assina_xml( |
|||
xmlElem_send, kwargs['Id']) |
|||
elif method == 'RecepcaoEventoManifesto': |
|||
xmlElem_send, kwargs["NFes"][0]["infNFe"]["Id"] |
|||
) |
|||
elif method == "RecepcaoEvento": |
|||
xml_send = signer.assina_xml(xmlElem_send, kwargs["eventos"][0]["Id"]) |
|||
elif method == "RecepcaoEventoManifesto": |
|||
xml_send = signer.assina_xml( |
|||
xmlElem_send, kwargs['manifesto']['identificador']) |
|||
|
|||
if modelo == '65': |
|||
xml_send = _add_qrCode(xml_send, **kwargs) |
|||
xmlElem_send, kwargs["manifesto"]["identificador"] |
|||
) |
|||
|
|||
else: |
|||
xml_send = etree.tostring(xmlElem_send) |
|||
xml_send = etree.tostring(xmlElem_send, encoding=str) |
|||
return xml_send |
|||
|
|||
|
|||
def gerar_qrcode(id_csc: int, csc: str, xml_send: str, cert = False) -> str: |
|||
xml = etree.fromstring(xml_send) |
|||
signature = xml.find( |
|||
".//{http://www.w3.org/2000/09/xmldsig#}Signature") |
|||
id = xml.find( |
|||
".//{http://www.portalfiscal.inf.br/nfe}infNFe").get('Id') |
|||
if id is None: |
|||
raise Exception("XML Invalido - Sem o ID") |
|||
|
|||
chave = id.replace('NFe', '') |
|||
emit_uf = chave[:2] |
|||
|
|||
tp_amb = xml.find(".//{http://www.portalfiscal.inf.br/nfe}tpAmb") |
|||
if tp_amb is None: |
|||
raise Exception("XML Invalido - Sem o tipo de ambiente") |
|||
|
|||
dh_emi = xml.find(".//{http://www.portalfiscal.inf.br/nfe}dhEmi") |
|||
if dh_emi is None: |
|||
raise Exception("XML Invalido - Sem data de Emissao") |
|||
dh_emi = dh_emi.text.split("-")[2].split("T")[0] |
|||
|
|||
tp_emis = xml.find(".//{http://www.portalfiscal.inf.br/nfe}tpEmis") |
|||
if tp_emis is None: |
|||
raise Exception("XML Invalido - Sem tipo de emissao") |
|||
|
|||
v_nf = xml.find(".//{http://www.portalfiscal.inf.br/nfe}vNF") |
|||
if v_nf is None: |
|||
raise Exception("XML Invalido - Sem o valor da NFe") |
|||
|
|||
url_qrcode_str = url_qrcode( |
|||
estado=emit_uf, |
|||
ambiente=tp_amb.text) |
|||
url_qrcode_exibicao_str = url_qrcode_exibicao( |
|||
estado=emit_uf, |
|||
ambiente=tp_amb.text) |
|||
|
|||
if tp_emis != 1: |
|||
if signature is None: |
|||
if cert is not False: |
|||
signer = Assinatura(certificado.pfx, certificado.password) |
|||
xml_send = signer.assina_xml(xmlElem_send, id) |
|||
else: |
|||
raise Exception("XML Invalido - Sem assinatura e não " |
|||
"foi enviado o certificado nos parametros") |
|||
digest_value = xml.find( |
|||
".//{http://www.w3.org/2000/09/xmldsig#}DigestValue") |
|||
c_hash_qr_code = \ |
|||
"{ch_acesso}|{versao}|{tp_amb}|{dh_emi}|" \ |
|||
"{v_nf}|{dig_val}|{id_csc}|{csc}".format( |
|||
ch_acesso=chave, |
|||
versao=2, |
|||
tp_amb=tp_amb.text, |
|||
dh_emi=dh_emi, |
|||
v_nf=float(v_nf.text), |
|||
dig_val=digest_value.text, |
|||
id_csc=int(id_csc), |
|||
csc=csc |
|||
) |
|||
c_hash_qr_code = hashlib.sha1(c_hash_qr_code.encode()). \ |
|||
hexdigest() |
|||
qr_code_url = 'p={ch_acesso}|{versao}|{tp_amb}|{dh_emi}|" \ |
|||
"{v_nf}|{dig_val}|{id_csc}|{hash}'.format( |
|||
ch_acesso=chave, |
|||
versao=2, |
|||
tp_amb=tp_amb.text, |
|||
dh_emi=dh_emi, |
|||
v_nf=float(v_nf.text), |
|||
dig_val=digest_value.text, |
|||
id_csc=int(id_csc), |
|||
hash=c_hash_qr_code |
|||
) |
|||
qrcode = url_qrcode_str + qr_code_url |
|||
url_consulta = url_qrcode_exibicao_str |
|||
|
|||
qrCode = xml.find( |
|||
'.//{http://www.portalfiscal.inf.br/nfe}qrCode').text = \ |
|||
qrcode |
|||
urlChave = xml.find( |
|||
'.//{http://www.portalfiscal.inf.br/nfe}urlChave').text = \ |
|||
url_consulta |
|||
else: |
|||
c_hash_qr_code = \ |
|||
"{ch_acesso}|{versao}|{tp_amb}|{id_csc}|{csc}".format( |
|||
ch_acesso=chave, |
|||
versao=2, |
|||
tp_amb=tp_amb.text, |
|||
id_csc=int(id_csc), |
|||
csc=csc |
|||
) |
|||
c_hash_qr_code = hashlib.sha1(c_hash_qr_code.encode()).hexdigest() |
|||
|
|||
qr_code_url = "p={ch_acesso}|{versao}|{tp_amb}|{id_csc}|" \ |
|||
"{hash}".\ |
|||
format( |
|||
ch_acesso=chave, |
|||
versao=2, |
|||
tp_amb=tp_amb.text, |
|||
id_csc=int(id_csc), |
|||
hash=c_hash_qr_code |
|||
) |
|||
qrcode = url_qrcode_str + qr_code_url |
|||
url_consulta = url_qrcode_exibicao_str |
|||
qrCode = xml.find( |
|||
'.//{http://www.portalfiscal.inf.br/nfe}qrCode').text = \ |
|||
qrcode |
|||
urlChave = xml.find( |
|||
'.//{http://www.portalfiscal.inf.br/nfe}urlChave').text = \ |
|||
url_consulta |
|||
return etree.tostring(xml) |
|||
|
|||
url = localizar_url(method, kwargs['estado'], modelo, |
|||
kwargs['ambiente']) |
|||
cabecalho = _build_header(method, **kwargs) |
|||
def _get_session(certificado): |
|||
cert, key = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password) |
|||
cert, key = save_cert_key(cert, key) |
|||
|
|||
session = Session() |
|||
session.cert = (cert, key) |
|||
session.verify = False |
|||
return session |
|||
|
|||
|
|||
def _get_client(base_url, transport): |
|||
client = Client(base_url, transport=transport) |
|||
port = next(iter(client.wsdl.port_types)) |
|||
first_operation = [ |
|||
x |
|||
for x in iter(client.wsdl.port_types[port].operations) |
|||
if "zip" not in x.lower() |
|||
][0] |
|||
return first_operation, client |
|||
|
|||
|
|||
def _send(certificado, method, **kwargs): |
|||
xml_send = kwargs["xml"] |
|||
base_url = localizar_url( |
|||
method, kwargs["estado"], kwargs["modelo"], kwargs["ambiente"] |
|||
) |
|||
session = _get_session(certificado) |
|||
patch = has_patch(kwargs["estado"], method) |
|||
if patch: |
|||
return patch(session, xml_send, kwargs["ambiente"]) |
|||
transport = Transport(session=session) |
|||
first_op, client = _get_client(base_url, transport) |
|||
return _send_zeep(first_op, client, xml_send) |
|||
|
|||
|
|||
def _send_zeep(first_operation, client, xml_send): |
|||
parser = etree.XMLParser(strip_cdata=False) |
|||
xml = etree.fromstring(xml_send, parser=parser) |
|||
|
|||
namespaceNFe = xml.find(".//{http://www.portalfiscal.inf.br/nfe}NFe") |
|||
if namespaceNFe is not None: |
|||
namespaceNFe.set("xmlns", "http://www.portalfiscal.inf.br/nfe") |
|||
|
|||
requests.packages.urllib3.disable_warnings(InsecureRequestWarning) |
|||
with client.settings(raw_response=True): |
|||
response = client.service[first_operation](xml) |
|||
response, obj = sanitize_response(response.text) |
|||
return { |
|||
"sent_xml": xml_send, |
|||
"received_xml": response, |
|||
"object": obj.Body.getchildren()[0], |
|||
} |
|||
|
|||
send_raw = False |
|||
if method == 'NFeDistribuicaoDFe': |
|||
send_raw = True |
|||
|
|||
response, obj = executar_consulta(certificado, url, cabecalho, xml_send, |
|||
send_raw=send_raw) |
|||
return { |
|||
'sent_xml': xml_send, |
|||
'received_xml': response, |
|||
'object': obj |
|||
} |
|||
def xml_autorizar_nfe(certificado, **kwargs): |
|||
_generate_nfe_id(**kwargs) |
|||
return _render(certificado, "NfeAutorizacao", True, **kwargs) |
|||
|
|||
|
|||
def autorizar_nfe(certificado, **kwargs): # Assinar |
|||
_generate_nfe_id(**kwargs) |
|||
return _send(certificado, 'NfeAutorizacao', True, **kwargs) |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_autorizar_nfe(certificado, **kwargs) |
|||
return _send(certificado, "NfeAutorizacao", **kwargs) |
|||
|
|||
|
|||
def xml_retorno_autorizar_nfe(certificado, **kwargs): |
|||
return _render(certificado, "NfeRetAutorizacao", False, **kwargs) |
|||
|
|||
|
|||
def retorno_autorizar_nfe(certificado, **kwargs): |
|||
return _send(certificado, 'NfeRetAutorizacao', False, **kwargs) |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_retorno_autorizar_nfe(certificado, **kwargs) |
|||
return _send(certificado, "NfeRetAutorizacao", **kwargs) |
|||
|
|||
|
|||
def xml_recepcao_evento_cancelamento(certificado, **kwargs): # Assinar |
|||
return _render(certificado, "RecepcaoEvento", True, **kwargs) |
|||
|
|||
|
|||
def recepcao_evento_cancelamento(certificado, **kwargs): # Assinar |
|||
return _send(certificado, 'RecepcaoEventoCancelamento', True, **kwargs) |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_recepcao_evento_cancelamento(certificado, **kwargs) |
|||
return _send(certificado, "RecepcaoEvento", **kwargs) |
|||
|
|||
|
|||
def xml_inutilizar_nfe(certificado, **kwargs): |
|||
return _render(certificado, "NfeInutilizacao", True, **kwargs) |
|||
|
|||
|
|||
def inutilizar_nfe(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_inutilizar_nfe(certificado, **kwargs) |
|||
return _send(certificado, "NfeInutilizacao", **kwargs) |
|||
|
|||
def inutilizar_nfe(certificado, **kwargs): # Assinar |
|||
return _send(certificado, 'NfeInutilizacao', True, **kwargs) |
|||
|
|||
def xml_consultar_protocolo_nfe(certificado, **kwargs): |
|||
return _render(certificado, "NfeConsultaProtocolo", False, **kwargs) |
|||
|
|||
|
|||
def consultar_protocolo_nfe(certificado, **kwargs): |
|||
return _send(certificado, 'NfeConsultaProtocolo', True, **kwargs) |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_consultar_protocolo_nfe(certificado, **kwargs) |
|||
return _send(certificado, "NfeConsultaProtocolo", **kwargs) |
|||
|
|||
|
|||
def xml_nfe_status_servico(certificado, **kwargs): |
|||
return _render(certificado, "NfeStatusServico", False, **kwargs) |
|||
|
|||
|
|||
def nfe_status_servico(certificado, **kwargs): |
|||
return _send(certificado, 'NfeStatusServico', False, **kwargs) |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_nfe_status_servico(certificado, **kwargs) |
|||
return _send(certificado, "NfeStatusServico", **kwargs) |
|||
|
|||
|
|||
def xml_consulta_cadastro(certificado, **kwargs): |
|||
return _render(certificado, "NfeConsultaCadastro", False, **kwargs) |
|||
|
|||
|
|||
def consulta_cadastro(certificado, **kwargs): |
|||
return _send(certificado, 'NfeConsultaCadastro', False, **kwargs) |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_consulta_cadastro(certificado, **kwargs) |
|||
kwargs["modelo"] = "55" |
|||
return _send(certificado, "NfeConsultaCadastro", **kwargs) |
|||
|
|||
|
|||
def xml_recepcao_evento_carta_correcao(certificado, **kwargs): # Assinar |
|||
return _render(certificado, "RecepcaoEvento", True, **kwargs) |
|||
|
|||
|
|||
def recepcao_evento_carta_correcao(certificado, **kwargs): # Assinar |
|||
return _send(certificado, 'RecepcaoEventoCarta', True, **kwargs) |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_recepcao_evento_carta_correcao(certificado, **kwargs) |
|||
return _send(certificado, "RecepcaoEvento", **kwargs) |
|||
|
|||
|
|||
def xml_recepcao_evento_manifesto(certificado, **kwargs): # Assinar |
|||
return _render(certificado, "RecepcaoEvento", True, **kwargs) |
|||
|
|||
|
|||
def recepcao_evento_manifesto(certificado, **kwargs): # Assinar |
|||
return _send(certificado, 'RecepcaoEventoManifesto', True, **kwargs) |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_recepcao_evento_manifesto(certificado, **kwargs) |
|||
return _send(certificado, "RecepcaoEvento", **kwargs) |
|||
|
|||
|
|||
def recepcao_evento_epec(certificado, **kwargs): # Assinar |
|||
return _send(certificado, 'RecepcaoEventoEPEC', True, **kwargs) |
|||
def xml_consulta_distribuicao_nfe(certificado, **kwargs): # Assinar |
|||
return _render(certificado, "NFeDistribuicaoDFe", False, **kwargs) |
|||
|
|||
|
|||
def consulta_distribuicao_nfe(certificado, **kwargs): |
|||
return _send(certificado, 'NFeDistribuicaoDFe', False, **kwargs) |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_consulta_distribuicao_nfe(certificado, **kwargs) |
|||
return _send_v310(certificado, **kwargs) |
|||
|
|||
|
|||
def xml_download_nfe(certificado, **kwargs): # Assinar |
|||
return _render(certificado, "NFeDistribuicaoDFe", False, **kwargs) |
|||
|
|||
|
|||
def download_nfe(certificado, **kwargs): |
|||
return _send(certificado, 'NFeDistribuicaoDFe', False, **kwargs) |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_download_nfe(certificado, **kwargs) |
|||
return _send_v310(certificado, **kwargs) |
|||
|
|||
|
|||
def _send_v310(certificado, **kwargs): |
|||
xml_send = kwargs["xml"] |
|||
base_url = localizar_url( |
|||
"NFeDistribuicaoDFe", kwargs["estado"], kwargs["modelo"], kwargs["ambiente"] |
|||
) |
|||
|
|||
cert, key = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password) |
|||
cert, key = save_cert_key(cert, key) |
|||
|
|||
session = Session() |
|||
session.cert = (cert, key) |
|||
session.verify = False |
|||
transport = Transport(session=session) |
|||
|
|||
xml = etree.fromstring(xml_send) |
|||
xml_um = etree.fromstring( |
|||
'<nfeCabecMsg xmlns="http://www.portalfiscal.inf.br/nfe/wsdl/"><cUF>AN</cUF><versaoDados>1.00</versaoDados></nfeCabecMsg>' |
|||
) |
|||
client = Client(base_url, transport=transport) |
|||
|
|||
port = next(iter(client.wsdl.port_types)) |
|||
first_operation = next(iter(client.wsdl.port_types[port].operations)) |
|||
with client.settings(raw_response=True): |
|||
response = client.service[first_operation]( |
|||
nfeDadosMsg=xml, _soapheaders=[xml_um] |
|||
) |
|||
response, obj = sanitize_response(response.text) |
|||
return { |
|||
"sent_xml": xml_send, |
|||
"received_xml": response, |
|||
"object": obj.Body.nfeDistDFeInteresseResponse.nfeDistDFeInteresseResult, |
|||
} |
|||
@ -1,34 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2016 Danimar Ribeiro, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
|
|||
from pytrustnfe.client import HttpClient |
|||
from pytrustnfe.certificado import save_cert_key, extract_cert_and_key_from_pfx |
|||
|
|||
from ..xml import sanitize_response |
|||
|
|||
|
|||
def _soap_xml(body, cabecalho): |
|||
xml = '<?xml version="1.0" encoding="utf-8"?>' |
|||
xml += '<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"><soap:Header>' |
|||
xml += '<nfeCabecMsg xmlns="http://www.portalfiscal.inf.br/nfe/wsdl/' + cabecalho.soap_action + '">' |
|||
xml += '<cUF>' + cabecalho.estado + '</cUF><versaoDados>' + cabecalho.versao + '</versaoDados></nfeCabecMsg></soap:Header><soap:Body>' |
|||
xml += '<nfeDadosMsg xmlns="http://www.portalfiscal.inf.br/nfe/wsdl/' + cabecalho.soap_action + '">' |
|||
xml += body |
|||
xml += '</nfeDadosMsg></soap:Body></soap:Envelope>' |
|||
return xml.rstrip('\n') |
|||
|
|||
|
|||
def executar_consulta(certificado, url, cabecalho, xmlEnviar, send_raw=False): |
|||
cert, key = extract_cert_and_key_from_pfx( |
|||
certificado.pfx, certificado.password) |
|||
cert_path, key_path = save_cert_key(cert, key) |
|||
client = HttpClient(url, cert_path, key_path) |
|||
|
|||
xml_enviar = _soap_xml(xmlEnviar, cabecalho) |
|||
if send_raw: |
|||
xml = '<?xml version="1.0" encoding="utf-8"?>' + xmlEnviar.rstrip('\n') |
|||
xml_enviar = xml |
|||
xml_retorno = client.post_soap(xml_enviar, cabecalho) |
|||
return sanitize_response(xml_retorno) |
|||
@ -0,0 +1,529 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2017 Johny Chen Jy, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import os |
|||
import re |
|||
from textwrap import wrap |
|||
from io import BytesIO |
|||
from reportlab.pdfbase import pdfmetrics |
|||
from reportlab.pdfbase.ttfonts import TTFont |
|||
from reportlab.lib import utils |
|||
from reportlab.pdfgen import canvas |
|||
from reportlab.lib.units import cm, mm |
|||
from reportlab.graphics.barcode import qr |
|||
from reportlab.graphics import renderPDF |
|||
from reportlab.graphics.shapes import Drawing |
|||
from reportlab.platypus import Table, TableStyle, Paragraph, Image |
|||
from reportlab.lib.enums import TA_CENTER |
|||
from reportlab.lib.styles import ParagraphStyle |
|||
|
|||
|
|||
def format_cnpj_cpf(value): |
|||
if len(value) < 12: # CPF |
|||
cValue = "%s.%s.%s-%s" % (value[:-8], value[-8:-5], value[-5:-2], value[-2:]) |
|||
else: |
|||
cValue = "%s.%s.%s/%s-%s" % ( |
|||
value[:-12], |
|||
value[-12:-9], |
|||
value[-9:-6], |
|||
value[-6:-2], |
|||
value[-2:], |
|||
) |
|||
return cValue |
|||
|
|||
|
|||
def getdateUTC(cDateUTC): |
|||
cDt = cDateUTC[0:10].split("-") |
|||
cDt.reverse() |
|||
return "/".join(cDt), cDateUTC[11:16] |
|||
|
|||
|
|||
def format_number(cNumber, precision=0, group_sep=".", decimal_sep=","): |
|||
if cNumber: |
|||
number = float(cNumber) |
|||
return ( |
|||
("{:,." + str(precision) + "f}") |
|||
.format(number) |
|||
.replace(",", "X") |
|||
.replace(".", ",") |
|||
.replace("X", ".") |
|||
) |
|||
return "" |
|||
|
|||
|
|||
def tagtext(oNode=None, cTag=None): |
|||
try: |
|||
xpath = ".//{http://www.portalfiscal.inf.br/nfe}%s" % (cTag) |
|||
cText = oNode.find(xpath).text |
|||
except: |
|||
cText = "" |
|||
return cText |
|||
|
|||
|
|||
def get_image(path, width=1 * cm): |
|||
img = utils.ImageReader(path) |
|||
iw, ih = img.getSize() |
|||
aspect = ih / float(iw) |
|||
return Image(path, width=width, height=(width * aspect)) |
|||
|
|||
|
|||
def format_telefone(telefone): |
|||
telefone = re.sub("[^0-9]", "", telefone) |
|||
if len(telefone) == 10: |
|||
telefone = "(%s) %s-%s" % (telefone[0:2], telefone[2:6], telefone[6:]) |
|||
elif len(telefone) == 11: |
|||
telefone = "(%s) %s-%s" % (telefone[0:2], telefone[2:7], telefone[7:]) |
|||
return telefone |
|||
|
|||
|
|||
class danfce(object): |
|||
def __init__(self, list_xml, logo=None, timezone=None): |
|||
dir_fonts = os.path.dirname(os.path.realpath(__file__)) |
|||
pdfmetrics.registerFont( |
|||
TTFont( |
|||
'NimbusSanL-Bold', |
|||
os.path.join(dir_fonts,'fonts/NimbusSanL Bold.ttf'))) |
|||
pdfmetrics.registerFont( |
|||
TTFont( |
|||
'NimbusSanL-Regu', |
|||
os.path.join(dir_fonts, 'fonts/NimbusSanL Regular.ttf'))) |
|||
self.current_font_size = 7 |
|||
self.current_font_name = "NimbusSanL-Regu" |
|||
|
|||
self.max_height = 840 |
|||
self.min_height = 1 |
|||
self.min_width = 5 |
|||
self.max_width = 200 |
|||
self.current_height = 840 |
|||
|
|||
self.oPDF_IO = BytesIO() |
|||
self.canvas = canvas.Canvas(self.oPDF_IO, pagesize=(7.2 * cm, 30 * cm)) |
|||
self.canvas.setTitle("DANFCE") |
|||
self.canvas.setLineWidth(0.5) |
|||
self.canvas.setFont(self.current_font_name, self.current_font_size) |
|||
|
|||
self.list_xml = list_xml |
|||
self.logo = logo |
|||
|
|||
self.nfce_generate() |
|||
|
|||
def ide_emit(self, oXML=None): |
|||
|
|||
elem_emit = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}emit") |
|||
|
|||
# Razão Social emitente |
|||
nomeEmpresa = tagtext(oNode=elem_emit, cTag="xFant") |
|||
self.drawTitle(nomeEmpresa, 10) |
|||
|
|||
if self.logo: |
|||
img = get_image(self.logo, width=10 * mm) |
|||
img.drawOn(self.canvas, 5, 830) |
|||
|
|||
cEnd = tagtext(oNode=elem_emit, cTag="xNome") + "<br />" |
|||
cEnd += "CNPJ: %s " % (format_cnpj_cpf(tagtext(oNode=elem_emit, cTag="CNPJ"))) |
|||
cEnd += "IE: %s" % (tagtext(oNode=elem_emit, cTag="IE")) + "<br />" |
|||
cEnd += ( |
|||
tagtext(oNode=elem_emit, cTag="xLgr") |
|||
+ ", " |
|||
+ tagtext(oNode=elem_emit, cTag="nro") |
|||
+ " - " |
|||
) |
|||
cEnd += ( |
|||
tagtext(oNode=elem_emit, cTag="xBairro") |
|||
+ "<br />" |
|||
+ tagtext(oNode=elem_emit, cTag="xMun") |
|||
+ " - " |
|||
) |
|||
cEnd += ( |
|||
tagtext(oNode=elem_emit, cTag="UF") |
|||
+ " - " |
|||
+ tagtext(oNode=elem_emit, cTag="CEP") |
|||
+ "<br />" |
|||
) |
|||
cEnd += "Fone: " + format_telefone(tagtext(oNode=elem_emit, cTag="fone")) |
|||
|
|||
self._drawCenteredParagraph(cEnd) |
|||
self.drawLine() |
|||
|
|||
def danfce_information(self, oXML=None): |
|||
el_ide = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}ide") |
|||
tipo_emissao = tagtext(oNode=el_ide, cTag="tpEmis") |
|||
if tipo_emissao in ("5", "9"): |
|||
self.current_height -= 5 |
|||
self.drawTitle("EMITIDA EM CONTINGÊNCIA", 9, "NimbusSanL-Bold") |
|||
self.drawTitle("Pendente de autorização", 7, "NimbusSanL-Bold") |
|||
self.drawLine() |
|||
else: |
|||
self.drawTitle( |
|||
"DANFE NFC-e - Documento Auxiliar da Nota Fiscal de", |
|||
7, |
|||
"NimbusSanL-Bold", |
|||
) |
|||
|
|||
self.drawTitle("Consumidor Eletrônica", 7, "NimbusSanL-Bold") |
|||
|
|||
self.drawString("NFC-e não permite aproveitamento de crédito de ICMS", True) |
|||
self.drawLine() |
|||
|
|||
def produtos( |
|||
self, |
|||
oXML=None, |
|||
el_det=None, |
|||
oPaginator=None, |
|||
list_desc=None, |
|||
list_cod_prod=None, |
|||
): |
|||
|
|||
rows = [["Cód", "Descrição", "Qtde", "Un", "Unit.", "Total"]] |
|||
colWidths = (25, 90, 15, 15, 25, 25) |
|||
rowHeights = [7] |
|||
|
|||
for id in range(oPaginator[0], oPaginator[1]): |
|||
|
|||
item = el_det[id] |
|||
el_prod = item.find(".//{http://www.portalfiscal.inf.br/nfe}prod") |
|||
|
|||
cod = tagtext(oNode=el_prod, cTag="cProd") |
|||
descricao = tagtext(oNode=el_prod, cTag="xProd") |
|||
descricao = (descricao[:20] + "..") if len(descricao) > 20 else descricao |
|||
Un = tagtext(oNode=el_prod, cTag="uCom") |
|||
Un = (Un[:2]) if len(Un) > 2 else Un |
|||
qtde = format_number(tagtext(oNode=el_prod, cTag="qCom"), precision=2) |
|||
vl_unit = format_number(tagtext(oNode=el_prod, cTag="vUnCom"), precision=2) |
|||
vl_total = format_number(tagtext(oNode=el_prod, cTag="vProd"), precision=2) |
|||
|
|||
new_row = [cod, descricao, qtde, Un, vl_unit, vl_total] |
|||
|
|||
rows.append(new_row) |
|||
rowHeights.append(self.current_font_size + 2) |
|||
|
|||
self._draw_product_table(rows, colWidths, rowHeights) |
|||
|
|||
def _draw_product_table(self, rows, colWidths, rowHeights): |
|||
table = Table(rows, colWidths, tuple(rowHeights)) |
|||
table.setStyle( |
|||
TableStyle( |
|||
[ |
|||
("FONTSIZE", (0, 0), (-1, -1), 7), |
|||
("FONT", (0, 1), (-1, -1), "NimbusSanL-Regu"), |
|||
("FONT", (0, 0), (-1, 0), "NimbusSanL-Bold"), |
|||
("ALIGN", (0, 0), (-1, 0), "LEFT"), |
|||
("ALIGN", (1, 0), (-1, 0), "LEFT"), |
|||
("ALIGN", (2, 0), (-1, 0), "CENTER"), |
|||
("ALIGN", (3, 0), (-1, 0), "CENTER"), |
|||
("ALIGN", (0, 1), (-1, -1), "LEFT"), |
|||
("ALIGN", (1, 1), (-1, -1), "LEFT"), |
|||
("ALIGN", (2, 1), (-1, -1), "CENTER"), |
|||
("ALIGN", (3, 1), (-1, -1), "CENTER"), |
|||
] |
|||
) |
|||
) |
|||
|
|||
w, h = table.wrapOn(self.canvas, 200, 450) |
|||
table.drawOn(self.canvas, 0, self.current_height - (h * 1.2)) |
|||
self.current_height -= h * 1.1 |
|||
|
|||
def totais(self, oXML=None): |
|||
# Impostos |
|||
el_total = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}total") |
|||
|
|||
total_tributo = format_number( |
|||
tagtext(oNode=el_total, cTag="vTotTrib"), precision=2 |
|||
) |
|||
valor_total = format_number(tagtext(oNode=el_total, cTag="vProd"), precision=2) |
|||
desconto = format_number(tagtext(oNode=el_total, cTag="vDesc"), precision=2) |
|||
valor_a_pagar = format_number(tagtext(oNode=el_total, cTag="vNF"), precision=2) |
|||
el_pag = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}pag") |
|||
troco = tagtext(oNode=el_pag, cTag="vTroco") |
|||
|
|||
payment_method_list = { |
|||
"01": "Dinheiro", |
|||
"02": "Cheque", |
|||
"03": "Cartão de Crédito", |
|||
"04": "Cartão de Débito", |
|||
"05": "Crédito Loja", |
|||
"10": "Vale Alimentação", |
|||
"11": "Vale Refeição", |
|||
"12": "Vale Presente", |
|||
"13": "Vale Combustível", |
|||
"14": "Duplicata Mercantil", |
|||
"15": "Boleto Bancario", |
|||
"90": "Sem Pagamento", |
|||
"99": "Outros", |
|||
} |
|||
quant_produtos = len(oXML.findall(".//{http://www.portalfiscal.inf.br/nfe}det")) |
|||
|
|||
payment_methods = [] |
|||
for pagId, item in enumerate(el_pag): |
|||
payment = [] |
|||
tipo_pagamento = tagtext(oNode=item, cTag="tPag") |
|||
val = format_number(tagtext(oNode=item, cTag="vPag"), precision=2) |
|||
|
|||
method = payment_method_list.get(tipo_pagamento) |
|||
|
|||
payment.append(method) |
|||
payment.append(val) |
|||
payment_methods.append(payment) |
|||
|
|||
values = { |
|||
"quantidade_itens": quant_produtos, |
|||
"total_tributo": total_tributo, |
|||
"valor_total": valor_total, |
|||
"desconto": desconto, |
|||
"valor_a_pagar": valor_a_pagar, |
|||
"formas_de_pagamento": payment_methods, |
|||
"troco": troco, |
|||
} |
|||
|
|||
self.draw_totals_table(values) |
|||
|
|||
self.drawLine() |
|||
|
|||
def draw_totals_table(self, values): |
|||
rowHeights = [7, 7, 7, 7, 7] |
|||
data = [ |
|||
["QTD.TOTAL DE ITENS", values["quantidade_itens"]], |
|||
["VALOR TOTAL R$", values["valor_total"]], |
|||
["DESCONTO R$", values["desconto"]], |
|||
["VALOR A PAGAR R$", values["valor_a_pagar"]], |
|||
["FORMA DE PAGAMENTO", "VALOR PAGO R$"], |
|||
] |
|||
|
|||
for item in values["formas_de_pagamento"]: |
|||
data.append([item[0], item[1]]) |
|||
rowHeights.append(7) |
|||
data.append(["TROCO", format_number(values["troco"], precision=2)]) |
|||
rowHeights.append(7) |
|||
|
|||
table2 = Table(data, colWidths=(150, 50), rowHeights=tuple(rowHeights)) |
|||
table2.setStyle( |
|||
TableStyle( |
|||
[ |
|||
("FONTSIZE", (0, 0), (-1, -1), 7), |
|||
("FONT", (0, 0), (1, -1), "NimbusSanL-Regu"), |
|||
("FONT", (0, 4), (1, 4), "NimbusSanL-Bold"), |
|||
("ALIGN", (1, 0), (1, -1), "RIGHT"), |
|||
] |
|||
) |
|||
) |
|||
w, h = table2.wrapOn(self.canvas, 200, 450) |
|||
table2.drawOn(self.canvas, 0, self.current_height - (h * 1.1)) |
|||
self.current_height -= h |
|||
|
|||
def inf_authentication(self, oXML=None): |
|||
el_infNFe = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}infNFe") |
|||
# n nfce, serie e data de solicitacao |
|||
el_ide = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}ide") |
|||
|
|||
el_NFeSupl = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}infNFeSupl") |
|||
|
|||
el_dest = el_infNFe.find(".//{http://www.portalfiscal.inf.br/nfe}dest") |
|||
# chave, n protocolo, data autorizacao |
|||
el_prot_nfe = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}protNFe") |
|||
|
|||
el_infAdic = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}infAdic") |
|||
|
|||
url_chave = tagtext(oNode=el_NFeSupl, cTag="urlChave") |
|||
access_key = tagtext(oNode=el_prot_nfe, cTag="chNFe") |
|||
|
|||
frase_chave_acesso = ( |
|||
"Consulte pela Chave de Acesso em:<br />\ |
|||
%s<br />%s" |
|||
% (url_chave, access_key) |
|||
) |
|||
|
|||
qrcode = tagtext(oNode=el_NFeSupl, cTag="qrCode") |
|||
|
|||
cnpj = tagtext(oNode=el_dest, cTag="CNPJ") |
|||
cpf = tagtext(oNode=el_dest, cTag="CPF") |
|||
if cnpj: |
|||
cnpj_cpf = format_cnpj_cpf(cnpj) |
|||
cnpj_cpf = "CONSUMIDOR CNPJ: %s" % (cnpj) |
|||
elif cpf: |
|||
cnpj_cpf = format_cnpj_cpf(cpf) |
|||
cnpj_cpf = "CONSUMIDOR CPF: %s" % (cpf) |
|||
else: |
|||
cnpj_cpf = u"CONSUMIDOR NÃO IDENTIFICADO" |
|||
|
|||
nNFC = tagtext(oNode=el_ide, cTag="nNF") |
|||
serie = tagtext(oNode=el_ide, cTag="serie") |
|||
|
|||
dataSolicitacao = getdateUTC(tagtext(oNode=el_ide, cTag="dhEmi")) |
|||
dataSolicitacao = dataSolicitacao[0] + " " + dataSolicitacao[1] |
|||
|
|||
text = u"%s <br />%s <br />NFC-e nº%s Série %s %s<br />" % ( |
|||
frase_chave_acesso, |
|||
cnpj_cpf, |
|||
nNFC, |
|||
serie, |
|||
dataSolicitacao, |
|||
) |
|||
|
|||
self._drawCenteredParagraph(text) |
|||
|
|||
tipo_emissao = tagtext(oNode=el_ide, cTag="tpEmis") |
|||
if tipo_emissao in ("5", "9"): |
|||
self.current_height -= 8 |
|||
self.drawTitle("EMITIDA EM CONTINGÊNCIA", 9, "NimbusSanL-Bold") |
|||
self.drawTitle( |
|||
"Pendente de autorização - Via Consumidor", 7, "NimbusSanL-Bold" |
|||
) |
|||
else: |
|||
numProtocolo = tagtext(oNode=el_prot_nfe, cTag="nProt") |
|||
|
|||
dataAutorizacao = getdateUTC(tagtext(oNode=el_prot_nfe, cTag="dhRecbto")) |
|||
dataAutorizacao = dataAutorizacao[0] + " " + dataAutorizacao[1] |
|||
|
|||
text = "Protocolo de autorização: %s<br />Data de autorização %s<br />" % ( |
|||
numProtocolo, |
|||
dataAutorizacao, |
|||
) |
|||
self._drawCenteredParagraph(text) |
|||
|
|||
self.draw_qr_code(qrcode) |
|||
|
|||
infAdFisco = tagtext(oNode=el_infAdic, cTag="infAdFisco") |
|||
self._drawCenteredParagraph(infAdFisco) |
|||
|
|||
infCpl = tagtext(oNode=el_infAdic, cTag="infCpl") |
|||
self._drawCenteredParagraph(infCpl) |
|||
|
|||
def _drawCenteredParagraph(self, text): |
|||
|
|||
style = ParagraphStyle( |
|||
name="Normal", |
|||
fontName="NimbusSanL-Regu", |
|||
fontSize=7, |
|||
alignment=TA_CENTER, |
|||
leading=7, |
|||
) |
|||
|
|||
paragraph = Paragraph(text, style=style) |
|||
w, h = paragraph.wrapOn(self.canvas, 180, 300) |
|||
paragraph.drawOn(self.canvas, 10, self.current_height - h) |
|||
self.current_height -= h * 1.1 |
|||
|
|||
def drawString(self, string, centered=False): |
|||
if centered: |
|||
self.canvas.drawCentredString( |
|||
self.max_width / 2, self.current_height, string |
|||
) |
|||
self.current_height -= self.current_font_size |
|||
else: |
|||
self.canvas.drawString(self.min_width, self.current_height, string) |
|||
self.current_height -= self.current_font_size |
|||
|
|||
def drawTitle(self, string, size, font="NimbusSanL-Regu"): |
|||
self.canvas.setFont(font, size) |
|||
self.canvas.drawCentredString(self.max_width / 2, self.current_height, string) |
|||
self.current_height -= self.current_font_size |
|||
self.canvas.setFont(self.current_font_name, self.current_font_size) |
|||
|
|||
def drawLine(self): |
|||
self.canvas.line( |
|||
self.min_width, self.current_height, self.max_width, self.current_height |
|||
) |
|||
self.current_height -= self.current_font_size |
|||
|
|||
def draw_qr_code(self, string): |
|||
qr_code = qr.QrCodeWidget(string) |
|||
drawing = Drawing(23 * mm, 23 * mm) |
|||
drawing.add(qr_code) |
|||
renderPDF.draw(drawing, self.canvas, 20 * mm, self.current_height - 85) |
|||
self.current_height -= 85 |
|||
|
|||
def newpage(self): |
|||
self.current_height = self.max_height |
|||
self.Page += 1 |
|||
self.canvas.showPage() |
|||
|
|||
def nfce_generate(self): |
|||
for oXML in self.list_xml: |
|||
oXML_cobr = oXML.find(".//{http://www.portalfiscal.inf.br/nfe}cobr") |
|||
|
|||
self.NrPages = 1 |
|||
self.Page = 1 |
|||
|
|||
# Calculando total linhas usadas para descrições dos itens |
|||
# Com bloco fatura, apenas 29 linhas para itens na primeira folha |
|||
nNr_Lin_Pg_1 = 34 if oXML_cobr is None else 30 |
|||
# [ rec_ini , rec_fim , lines , limit_lines ] |
|||
oPaginator = [[0, 0, 0, nNr_Lin_Pg_1]] |
|||
el_det = oXML.findall(".//{http://www.portalfiscal.inf.br/nfe}det") |
|||
if el_det is not None: |
|||
list_desc = [] |
|||
list_cod_prod = [] |
|||
nPg = 0 |
|||
for nId, item in enumerate(el_det): |
|||
el_prod = item.find(".//{http://www.portalfiscal.inf.br/nfe}prod") |
|||
infAdProd = item.find( |
|||
".//{http://www.portalfiscal.inf.br/nfe}infAdProd" |
|||
) |
|||
|
|||
list_ = wrap(tagtext(oNode=el_prod, cTag="xProd"), 56) |
|||
if infAdProd is not None: |
|||
list_.extend(wrap(infAdProd.text, 56)) |
|||
list_desc.append(list_) |
|||
|
|||
list_cProd = wrap(tagtext(oNode=el_prod, cTag="cProd"), 14) |
|||
list_cod_prod.append(list_cProd) |
|||
|
|||
# Nr linhas necessárias p/ descrição item |
|||
nLin_Itens = len(list_) |
|||
|
|||
if (oPaginator[nPg][2] + nLin_Itens) >= oPaginator[nPg][3]: |
|||
oPaginator.append([0, 0, 0, 77]) |
|||
nPg += 1 |
|||
oPaginator[nPg][0] = nId |
|||
oPaginator[nPg][1] = nId + 1 |
|||
oPaginator[nPg][2] = nLin_Itens |
|||
else: |
|||
# adiciona-se 1 pelo funcionamento de xrange |
|||
oPaginator[nPg][1] = nId + 1 |
|||
oPaginator[nPg][2] += nLin_Itens |
|||
|
|||
self.NrPages = len(oPaginator) # Calculando nr. páginas |
|||
|
|||
self.ide_emit(oXML=oXML) |
|||
# self.destinatario(oXML=oXML) |
|||
self.danfce_information(oXML=oXML) |
|||
|
|||
self.produtos( |
|||
oXML=oXML, |
|||
el_det=el_det, |
|||
oPaginator=oPaginator[0], |
|||
list_desc=list_desc, |
|||
list_cod_prod=list_cod_prod, |
|||
) |
|||
|
|||
self.drawLine() |
|||
|
|||
self.totais(oXML=oXML) |
|||
|
|||
self.inf_authentication(oXML=oXML) |
|||
|
|||
# Gera o restante das páginas do XML |
|||
for oPag in oPaginator[1:]: |
|||
if oPag: |
|||
self.newpage() |
|||
self.ide_emit(oXML=oXML) |
|||
# self.destinatario(oXML=oXML) |
|||
self.produtos( |
|||
oXML=oXML, |
|||
el_det=el_det, |
|||
oPaginator=oPag, |
|||
list_desc=list_desc, |
|||
list_cod_prod=list_cod_prod, |
|||
) |
|||
self.totais(oXML=oXML) |
|||
self.inf_authentication(oXML=oXML) |
|||
|
|||
self.newpage() |
|||
|
|||
self.canvas.save() |
|||
|
|||
def writeto_pdf(self, fileObj): |
|||
pdf_out = self.oPDF_IO.getvalue() |
|||
self.oPDF_IO.close() |
|||
fileObj.write(pdf_out) |
|||
1268
pytrustnfe/nfe/danfe.py
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,45 @@ |
|||
from ..Servidores import SIGLA_ESTADO |
|||
from pytrustnfe.xml import sanitize_response |
|||
|
|||
|
|||
def nfeInutilizacaoCE(session, xml_send, ambiente): |
|||
soap = ( |
|||
'<Envelope xmlns="http://www.w3.org/2003/05/soap-envelope"><Body>\ |
|||
<nfeDadosMsg xmlns="http://www.portalfiscal.inf.br/nfe/wsdl/NFeInutilizacao4"\ |
|||
>' |
|||
+ xml_send |
|||
+ "</nfeDadosMsg></Body></Envelope>" |
|||
) |
|||
headers = { |
|||
"SOAPAction": "", |
|||
"Content-Type": 'application/soap+xml; charset="utf-8"', |
|||
} |
|||
if ambiente == 1: |
|||
response = session.post( |
|||
"https://nfe.sefaz.ce.gov.br/nfe4/services/NFeInutilizacao4", |
|||
data=soap, |
|||
headers=headers, |
|||
) |
|||
else: |
|||
response = session.post( |
|||
"https://nfeh.sefaz.ce.gov.br/nfe4/services/NFeInutilizacao4", |
|||
data=soap, |
|||
headers=headers, |
|||
) |
|||
response, obj = sanitize_response(response.text) |
|||
return { |
|||
"sent_xml": xml_send, |
|||
"received_xml": response, |
|||
"object": obj.Body.getchildren()[0], |
|||
} |
|||
|
|||
|
|||
methods = {"NfeInutilizacaoCE": nfeInutilizacaoCE} |
|||
|
|||
|
|||
def has_patch(cod_estado, metodo): |
|||
uf = SIGLA_ESTADO[cod_estado] |
|||
method = metodo + uf |
|||
if method in methods: |
|||
return methods[method] |
|||
return None |
|||
@ -1,19 +1,14 @@ |
|||
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"> |
|||
<Body> |
|||
<nfeDistDFeInteresse xmlns="http://www.portalfiscal.inf.br/nfe/wsdl/NFeDistribuicaoDFe"> |
|||
<nfeDadosMsg> |
|||
<distDFeInt xmlns="http://www.portalfiscal.inf.br/nfe" versao="1.01"> |
|||
<tpAmb>{{ ambiente }}</tpAmb> |
|||
<cUFAutor>{{ estado }}</cUFAutor> |
|||
<CNPJ>{{ cnpj_cpf }}</CNPJ> |
|||
<distNSU> |
|||
<ultNSU>{{ ultimo_nsu }}</ultNSU> |
|||
</distNSU> |
|||
<consChNFe> |
|||
<chNFe>{{ chave_nfe }}</chNFe> |
|||
</consChNFe> |
|||
</distDFeInt> |
|||
</nfeDadosMsg> |
|||
</nfeDistDFeInteresse> |
|||
</Body> |
|||
</Envelope> |
|||
<distDFeInt xmlns="http://www.portalfiscal.inf.br/nfe" versao="1.01"> |
|||
<tpAmb>{{ ambiente }}</tpAmb> |
|||
<cUFAutor>{{ estado }}</cUFAutor> |
|||
<CNPJ>{{ cnpj_cpf }}</CNPJ> |
|||
<distNSU> |
|||
<ultNSU>{{ ultimo_nsu }}</ultNSU> |
|||
</distNSU> |
|||
<consChNFe> |
|||
<chNFe>{{ chave_nfe }}</chNFe> |
|||
</consChNFe> |
|||
<consNSU> |
|||
<NSU>{{ nsu }}</NSU> |
|||
</consNSU> |
|||
</distDFeInt> |
|||
@ -1,6 +1,5 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<consSitNFe xmlns="http://www.portalfiscal.inf.br/nfe" versao="2.01"> |
|||
<consSitNFe xmlns="http://www.portalfiscal.inf.br/nfe" versao="4.00"> |
|||
<tpAmb>{{ obj.ambiente }}</tpAmb> |
|||
<xServ>CONSULTAR</xServ> |
|||
<chNFe>{{ obj.chave_nfe }}</chNFe> |
|||
</consSitNFe> |
|||
</consSitNFe> |
|||
@ -1,4 +1,4 @@ |
|||
<consReciNFe xmlns="http://www.portalfiscal.inf.br/nfe" versao="3.10"> |
|||
<consReciNFe xmlns="http://www.portalfiscal.inf.br/nfe" versao="4.00"> |
|||
<tpAmb>{{ obj.ambiente }}</tpAmb> |
|||
<nRec>{{ obj.numero_recibo }}</nRec> |
|||
</consReciNFe> |
|||
@ -1,6 +1,6 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<consStatServ xmlns="http://www.portalfiscal.inf.br/nfe" versao="3.10"> |
|||
<consStatServ xmlns="http://www.portalfiscal.inf.br/nfe" versao="4.00"> |
|||
<tpAmb>{{ obj.ambiente }}</tpAmb> |
|||
<cUF>{{ obj.estado }}</cUF> |
|||
<xServ>STATUS</xServ> |
|||
</consStatServ> |
|||
</consStatServ> |
|||
@ -1,21 +0,0 @@ |
|||
<envEvento xmlns="http://www.portalfiscal.inf.br/nfe" versao="1.00"> |
|||
<idLote>{{ idLote }}</idLote> |
|||
<evento xmlns="http://www.portalfiscal.inf.br/nfe" versao="1.00"> |
|||
<infEvento Id="{{ Id }}"> |
|||
<cOrgao>{{ cOrgao }}</cOrgao> |
|||
<tpAmb>{{ tpAmb }}</tpAmb> |
|||
<CNPJ>{{ CNPJ }}</CNPJ> |
|||
<CPF>{{ CPF }}</CPF> |
|||
<chNFe>{{ chNFe }}</chNFe> |
|||
<dhEvento>{{ dhEvento }}</dhEvento> |
|||
<tpEvento>{{ tpEvento }}</tpEvento> |
|||
<nSeqEvento>{{ nSeqEvento }}</nSeqEvento> |
|||
<verEvento>1.00</verEvento> |
|||
<detEvento versao="1.00"> |
|||
<descEvento>Carta de Correção</descEvento> |
|||
<xCorrecao>{{ xCorrecao|normalize|escape }}</xCorrecao> |
|||
<xCondUso>A Carta de Correção é disciplinada pelo § 1º-A do art. 7º do Convênio S/N, de 15 de dezembro de 1970 e pode ser utilizada para regularização de erro ocorrido na emissão de documento fiscal, desde que o erro não esteja relacionado com: I - as variáveis que determinam o valor do imposto tais como: base de cálculo, alíquota, diferença de preço, quantidade, valor da operação ou da prestação; II - a correção de dados cadastrais que implique mudança do remetente ou do destinatário; III - a data de emissão ou de saída.</xCondUso> |
|||
</detEvento> |
|||
</infEvento> |
|||
</evento> |
|||
</envEvento> |
|||
@ -1,31 +0,0 @@ |
|||
<envEvento xmlns="http://www.portalfiscal.inf.br/nfe" versao="1.00"> |
|||
<idLote>00106151340701</idLote> |
|||
<evento xmlns="http://www.portalfiscal.inf.br/nfe" versao="1.00"> |
|||
<infEvento Id="ID1101403514081014278500019055001001061513407959995201"> |
|||
<cOrgao>91</cOrgao> |
|||
<tpAmb>2</tpAmb> |
|||
<CNPJ>10142785000190</CNPJ> |
|||
<chNFe>35140810142785000190550010010615134079599952</chNFe> |
|||
<dhEvento>2014-08-07T04:52:51-03:00</dhEvento> |
|||
<tpEvento>110140</tpEvento> |
|||
<nSeqEvento>1</nSeqEvento> |
|||
<verEvento>1.00</verEvento> |
|||
<detEvento versao="1.00"> |
|||
<descEvento>EPEC</descEvento> |
|||
<cOrgaoAutor>35</cOrgaoAutor> |
|||
<tpAutor>1</tpAutor> |
|||
<verAplic>1.26</verAplic> |
|||
<dhEmi>2014-08-07T00:00:00-03:00</dhEmi> |
|||
<tpNF>1</tpNF> |
|||
<IE>495171423115</IE> |
|||
<dest> |
|||
<UF>SP</UF> |
|||
<CPF>00000000191</CPF> |
|||
<vNF>86.00</vNF> |
|||
<vICMS>6.02</vICMS> |
|||
<vST>0</vST> |
|||
</dest> |
|||
</detEvento> |
|||
</infEvento> |
|||
</evento> |
|||
</envEvento> |
|||
@ -0,0 +1,76 @@ |
|||
# © 2019 Danimar Ribeiro, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import os |
|||
from requests import Session |
|||
from zeep import Client |
|||
from zeep.transports import Transport |
|||
from requests.packages.urllib3 import disable_warnings |
|||
|
|||
from pytrustnfe.xml import render_xml, sanitize_response |
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key |
|||
from pytrustnfe.nfe.assinatura import Assinatura |
|||
|
|||
|
|||
def _render(certificado, method, **kwargs): |
|||
path = os.path.join(os.path.dirname(__file__), "templates") |
|||
xml_send = render_xml(path, "%s.xml" % method, True, **kwargs) |
|||
|
|||
reference = "" |
|||
signer = Assinatura(certificado.pfx, certificado.password) |
|||
xml_send = signer.assina_xml(xml_send, reference) |
|||
return xml_send |
|||
|
|||
|
|||
def _send(certificado, method, **kwargs): |
|||
base_url = "" |
|||
if kwargs["ambiente"] == "producao": |
|||
base_url = "https://aparecida.siltecnologia.com.br/tbw/services/Abrasf10?wsdl" |
|||
else: |
|||
base_url = "https://aparecida.siltecnologia.com.br/tbwhomologacao/services/Abrasf10?wsdl" |
|||
|
|||
cert, key = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password) |
|||
cert, key = save_cert_key(cert, key) |
|||
|
|||
disable_warnings() |
|||
session = Session() |
|||
session.cert = (cert, key) |
|||
session.verify = False |
|||
transport = Transport(session=session) |
|||
|
|||
client = Client(base_url, transport=transport) |
|||
|
|||
xml_send = kwargs["xml"] |
|||
response = client.service[method](xml_send) |
|||
response, obj = sanitize_response(response) |
|||
return {"sent_xml": xml_send, "received_xml": response, "object": obj} |
|||
|
|||
|
|||
def xml_recepcionar_lote_rps(certificado, **kwargs): |
|||
return _render(certificado, "recepcionarLoteRps", **kwargs) |
|||
|
|||
|
|||
def recepcionar_lote_rps(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_recepcionar_lote_rps(certificado, **kwargs) |
|||
return _send(certificado, "recepcionarLoteRps", **kwargs) |
|||
|
|||
|
|||
def xml_consultar_lote_rps(certificado, **kwargs): |
|||
return _render(certificado, "consultarLoteRps", **kwargs) |
|||
|
|||
|
|||
def consultar_lote_rps(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_consultar_lote_rps(certificado, **kwargs) |
|||
return _send(certificado, "consultarLoteRps", **kwargs) |
|||
|
|||
|
|||
def xml_cancelar_nfse(certificado, **kwargs): |
|||
return _render(certificado, "cancelarNfse", **kwargs) |
|||
|
|||
|
|||
def cancelar_nfse(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_cancelar_nfse(certificado, **kwargs) |
|||
return _send(certificado, "cancelarNfse", **kwargs) |
|||
@ -0,0 +1,91 @@ |
|||
<Rps> |
|||
<InfRps Id="rps{{ rps.numero }}"> |
|||
<IdentificacaoRps> |
|||
<Numero>{{ rps.numero }}</Numero> |
|||
<Serie>{{ rps.serie }}</Serie> |
|||
<Tipo>{{ rps.tipo_rps }}</Tipo> |
|||
</IdentificacaoRps> |
|||
<DataEmissao>{{ rps.data_emissao }}</DataEmissao> |
|||
<NaturezaOperacao>{{ rps.natureza_operacao }}</NaturezaOperacao> |
|||
<RegimeEspecialTributacao>{{ rps.regime_tributacao }}</RegimeEspecialTributacao> |
|||
<OptanteSimplesNacional>{{ rps.optante_simples }}</OptanteSimplesNacional> |
|||
<IncentivadorCultural>{{ rps.incentivador_cultural }}</IncentivadorCultural> |
|||
<Status>{{ rps.status }}</Status> |
|||
<RpsSubstituido> |
|||
<Numero>{{ rps.numero_substituido }}</Numero> |
|||
<Serie>{{ rps.serie_substituido }}</Serie> |
|||
<Tipo>{{ rps.tipo_substituido }}</Tipo> |
|||
</RpsSubstituido> |
|||
<Servico> |
|||
<Valores> |
|||
<ValorServicos>{{ rps.valor_servico }}</ValorServicos> |
|||
<ValorDeducoes>{{ rps.valor_deducao }}</ValorDeducoes> |
|||
<ValorPis>{{ rps.valor_pis }}</ValorPis> |
|||
<ValorCofins>{{ rps.valor_cofins }}</ValorCofins> |
|||
<ValorInss>{{ rps.valor_inss }}</ValorInss> |
|||
<ValorIr>{{ rps.valor_ir }}</ValorIr> |
|||
<ValorCsll>{{ rps.valor_csll }}</ValorCsll> |
|||
<IssRetido>{{ rps.iss_retido }}</IssRetido> |
|||
<ValorIss>{{ rps.valor_iss }}</ValorIss> |
|||
<ValorIssRetido>{{ rps.valor_iss_retido }}</ValorIssRetido> |
|||
<OutrasRetencoes>{{ rps.outras_retencoes }}</OutrasRetencoes> |
|||
<BaseCalculo>{{ rps.base_calculo }}</BaseCalculo> |
|||
<Aliquota>{{ rps.aliquota_issqn }}</Aliquota> |
|||
<ValorLiquidoNfse>{{ rps.valor_liquido_nfse }}</ValorLiquidoNfse> |
|||
<DescontoIncondicionado>{{ rps.desconto_incondicionado }}</DescontoIncondicionado> |
|||
<DescontoCondicionado>{{ rps.desconto_condicionado }}</DescontoCondicionado> |
|||
</Valores> |
|||
<ItemListaServico>{{ rps.codigo_servico }}</ItemListaServico> |
|||
<CodigoCnae>{{ rps.cnae_servico }}</CodigoCnae> |
|||
<CodigoTributacaoMunicipio>{{ rps.codigo_tributacao_municipio }}</CodigoTributacaoMunicipio> |
|||
<Discriminacao>{{ rps.descricao }}</Discriminacao> |
|||
<CodigoMunicipio>{{ rps.codigo_municipio }}</CodigoMunicipio> |
|||
</Servico> |
|||
<Prestador> |
|||
<Cnpj>{{ rps.prestador.cnpj }}</Cnpj> |
|||
<InscricaoMunicipal>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipal> |
|||
</Prestador> |
|||
<Tomador> |
|||
<IdentificacaoTomador> |
|||
<CpfCnpj> |
|||
{% if rps.tomador.cnpj_cpf|length == 14 %} |
|||
<Cnpj>{{ rps.tomador.cnpj_cpf }}</Cnpj> |
|||
{% endif %} |
|||
{% if rps.tomador.cnpj_cpf|length == 11 %} |
|||
<Cpf>{{ rps.tomador.cnpj_cpf }}</Cpf> |
|||
{% endif %} |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ rps.tomador.inscricao_municipal }}</InscricaoMunicipal> |
|||
</IdentificacaoTomador> |
|||
<RazaoSocial>{{ rps.tomador.razao_social }}</RazaoSocial> |
|||
<Endereco> |
|||
<Endereco>{{ rps.tomador.logradouro }}</Endereco> |
|||
<Numero>{{ rps.tomador.numero }}</Numero> |
|||
<Complemento>{{ rps.tomador.complemento }}</Complemento> |
|||
<Bairro>{{ rps.tomador.bairro }}</Bairro> |
|||
<CodigoMunicipio>{{ rps.tomador.cidade }}</CodigoMunicipio> |
|||
<Uf>{{ rps.tomador.uf }}</Uf> |
|||
<Cep>{{ rps.tomador.cep }}</Cep> |
|||
</Endereco> |
|||
<Contato> |
|||
<Telefone>{{ rps.tomador.telefone }}</Telefone> |
|||
<Email>{{ rps.tomador.email }}</Email> |
|||
</Contato> |
|||
</Tomador> |
|||
{% if rps.intermediario is defined -%} |
|||
<IntermediarioServico> |
|||
<RazaoSocial>{{ rps.intermediario.razao_social }}</RazaoSocial> |
|||
<CpfCnpj> |
|||
<Cnpj>{{ rps.intermediario.cnpj }}</Cnpj> |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ rps.intermediario.inscricao_municipal }}</InscricaoMunicipal> |
|||
</IntermediarioServico> |
|||
{% endif %} |
|||
{% if rps.construcao_civil is defined -%} |
|||
<ContrucaoCivil> |
|||
<CodigoObra>{{ rps.construcao_civil.codigo_obra }}</CodigoObra> |
|||
<Art>{{ rps.construcao_civil.art }}</Art> |
|||
</ContrucaoCivil> |
|||
{% endif %} |
|||
</InfRps> |
|||
</Rps> |
|||
@ -0,0 +1,15 @@ |
|||
<CancelarNfseEnvio xmlns="http://nfse.abrasf.org.br"> |
|||
<Pedido> |
|||
<InfPedidoCancelamento Id="1"> |
|||
<IdentificacaoNfse> |
|||
<Numero>{{ cancelamento.numero_nfse }}</Numero> |
|||
<CpfCnpj> |
|||
<Cnpj>{{ cancelamento.cnpj_prestador }}</Cnpj> |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ cancelamento.inscricao_municipal }}</InscricaoMunicipal> |
|||
<CodigoMunicipio>{{ cancelamento.cidade }}</CodigoMunicipio> |
|||
</IdentificacaoNfse> |
|||
<CodigoCancelamento>{{ cancelamento.codigo_cancelamento }}</CodigoCancelamento> |
|||
</InfPedidoCancelamento> |
|||
</Pedido> |
|||
</CancelarNfseEnvio> |
|||
@ -0,0 +1,7 @@ |
|||
<ConsultarLoteRpsEnvio xmlns="http://nfse.abrasf.org.br"> |
|||
<Prestador> |
|||
<Cnpj>{{ consulta.cnpj_prestador }}</Cnpj> |
|||
<InscricaoMunicipal>{{ consulta.inscricao_municipal }}</InscricaoMunicipal> |
|||
</Prestador> |
|||
<Protocolo>{{ consulta.protocolo }}</Protocolo> |
|||
</ConsultarLoteRpsEnvio> |
|||
@ -0,0 +1,13 @@ |
|||
<EnviarLoteRpsEnvio> |
|||
<LoteRps Id="lote{{ nfse.numero_lote }}"> |
|||
<NumeroLote>{{ nfse.numero_lote }}</NumeroLote> |
|||
<Cnpj>{{ nfse.cnpj_prestador }}</Cnpj> |
|||
<InscricaoMunicipal>{{ nfse.inscricao_municipal }}</InscricaoMunicipal> |
|||
<QuantidadeRps>{{ nfse.lista_rps|length }}</QuantidadeRps> |
|||
<ListaRps> |
|||
{% for rps in nfse.lista_rps -%} |
|||
{% include 'Rps.xml' %} |
|||
{% endfor %} |
|||
</ListaRps> |
|||
</LoteRps> |
|||
</EnviarLoteRpsEnvio> |
|||
@ -0,0 +1,79 @@ |
|||
# © 2018 Danimar Ribeiro, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import os |
|||
from lxml import etree |
|||
from requests import Session |
|||
from zeep import Client |
|||
from zeep.transports import Transport |
|||
|
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key |
|||
from pytrustnfe.xml import render_xml, sanitize_response |
|||
from pytrustnfe.nfse.bh.assinatura import Assinatura |
|||
|
|||
|
|||
def _render(certificado, method, **kwargs): |
|||
path = os.path.join(os.path.dirname(__file__), "templates") |
|||
xml_send = render_xml(path, "%s.xml" % method, True, **kwargs) |
|||
|
|||
reference = "" |
|||
ref_lote = "" |
|||
if method == "GerarNfse": |
|||
reference = "rps:%s" % kwargs["rps"]["numero"] |
|||
ref_lote = "lote%s" % kwargs["rps"]["numero_lote"] |
|||
elif method == "CancelarNfse": |
|||
reference = "pedidoCancelamento_%s" % kwargs["cancelamento"]["numero_nfse"] |
|||
|
|||
signer = Assinatura(certificado.pfx, certificado.password) |
|||
xml_send = signer.assina_xml(xml_send, reference) |
|||
if ref_lote: |
|||
xml_send = signer.assina_xml(etree.fromstring(xml_send), ref_lote) |
|||
return xml_send.encode("utf-8") |
|||
|
|||
|
|||
def _send(certificado, method, **kwargs): |
|||
base_url = "" |
|||
if kwargs["ambiente"] == "producao": |
|||
base_url = "https://bhissdigital.pbh.gov.br/bhiss-ws/nfse?wsdl" |
|||
else: |
|||
base_url = "https://bhisshomologa.pbh.gov.br/bhiss-ws/nfse?wsdl" |
|||
|
|||
xml_send = kwargs["xml"].decode("utf-8") |
|||
xml_cabecalho = '<?xml version="1.0" encoding="UTF-8"?>\ |
|||
<cabecalho xmlns="http://www.abrasf.org.br/nfse.xsd" versao="1.00">\ |
|||
<versaoDados>1.00</versaoDados></cabecalho>' |
|||
|
|||
cert, key = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password) |
|||
cert, key = save_cert_key(cert, key) |
|||
|
|||
session = Session() |
|||
session.cert = (cert, key) |
|||
session.verify = False |
|||
transport = Transport(session=session) |
|||
|
|||
client = Client(base_url, transport=transport) |
|||
|
|||
response = client.service[method](xml_cabecalho, xml_send) |
|||
|
|||
response, obj = sanitize_response(response) |
|||
return {"sent_xml": xml_send, "received_xml": response, "object": obj} |
|||
|
|||
|
|||
def xml_gerar_nfse(certificado, **kwargs): |
|||
return _render(certificado, "GerarNfse", **kwargs) |
|||
|
|||
|
|||
def gerar_nfse(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_gerar_nfse(certificado, **kwargs) |
|||
return _send(certificado, "GerarNfse", **kwargs) |
|||
|
|||
|
|||
def xml_cancelar_nfse(certificado, **kwargs): |
|||
return _render(certificado, "CancelarNfse", **kwargs) |
|||
|
|||
|
|||
def cancelar_nfse(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_cancelar_nfse(certificado, **kwargs) |
|||
return _send(certificado, "CancelarNfse", **kwargs) |
|||
@ -0,0 +1,47 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2016 Danimar Ribeiro, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import signxml |
|||
from lxml import etree |
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx |
|||
from signxml import XMLSigner |
|||
|
|||
|
|||
class Assinatura(object): |
|||
def __init__(self, arquivo, senha): |
|||
self.arquivo = arquivo |
|||
self.senha = senha |
|||
|
|||
def assina_xml(self, xml_element, reference): |
|||
cert, key = extract_cert_and_key_from_pfx(self.arquivo, self.senha) |
|||
|
|||
for element in xml_element.iter("*"): |
|||
if element.text is not None and not element.text.strip(): |
|||
element.text = None |
|||
|
|||
signer = XMLSigner( |
|||
method=signxml.methods.enveloped, |
|||
signature_algorithm="rsa-sha1", |
|||
digest_algorithm="sha1", |
|||
c14n_algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315", |
|||
) |
|||
|
|||
ns = {} |
|||
ns[None] = signer.namespaces["ds"] |
|||
signer.namespaces = ns |
|||
|
|||
ref_uri = ("#%s" % reference) if reference else None |
|||
signed_root = signer.sign( |
|||
xml_element, key=key.encode(), cert=cert.encode(), reference_uri=ref_uri |
|||
) |
|||
if reference: |
|||
element_signed = signed_root.find(".//*[@Id='%s']" % reference) |
|||
signature = ( |
|||
signed_root.find(".//*[@URI='#%s']" % reference).getparent().getparent() |
|||
) |
|||
|
|||
if element_signed is not None and signature is not None: |
|||
parent = element_signed.getparent() |
|||
parent.append(signature) |
|||
return etree.tostring(signed_root, encoding=str) |
|||
@ -0,0 +1,13 @@ |
|||
<CancelarNfseEnvio xmlns="http://www.abrasf.org.br/nfse.xsd"> |
|||
<Pedido xmlns="http://www.abrasf.org.br/nfse.xsd"> |
|||
<InfPedidoCancelamento Id="pedidoCancelamento_{{ cancelamento.numero_nfse }}"> |
|||
<IdentificacaoNfse> |
|||
<Numero>{{ cancelamento.numero_nfse }}</Numero> |
|||
<Cnpj>{{ cancelamento.cnpj_prestador }}</Cnpj> |
|||
<InscricaoMunicipal>{{ cancelamento.inscricao_municipal }}</InscricaoMunicipal> |
|||
<CodigoMunicipio>{{ cancelamento.cidade }}</CodigoMunicipio> |
|||
</IdentificacaoNfse> |
|||
<CodigoCancelamento>2</CodigoCancelamento> |
|||
</InfPedidoCancelamento> |
|||
</Pedido> |
|||
</CancelarNfseEnvio> |
|||
@ -0,0 +1,11 @@ |
|||
<GerarNfseEnvio xmlns="http://www.abrasf.org.br/nfse.xsd"> |
|||
<LoteRps Id="lote{{ rps.numero_lote }}" versao="1.00"> |
|||
<NumeroLote>{{ rps.numero_lote }}</NumeroLote> |
|||
<Cnpj>{{ rps.prestador.cnpj }}</Cnpj> |
|||
<InscricaoMunicipal>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipal> |
|||
<QuantidadeRps>1</QuantidadeRps> |
|||
<ListaRps xmlns="http://www.abrasf.org.br/nfse.xsd"> |
|||
{% include 'Rps.xml' %} |
|||
</ListaRps> |
|||
</LoteRps> |
|||
</GerarNfseEnvio> |
|||
@ -0,0 +1,91 @@ |
|||
<Rps> |
|||
<InfRps xmlns="http://www.abrasf.org.br/nfse.xsd" Id="rps:{{ rps.numero }}"> |
|||
<IdentificacaoRps> |
|||
<Numero>{{ rps.numero }}</Numero> |
|||
<Serie>{{ rps.serie }}</Serie> |
|||
<Tipo>{{ rps.tipo_rps }}</Tipo> |
|||
</IdentificacaoRps> |
|||
<DataEmissao>{{ rps.data_emissao }}</DataEmissao> |
|||
<NaturezaOperacao>{{ rps.natureza_operacao }}</NaturezaOperacao> |
|||
<RegimeEspecialTributacao>{{ rps.regime_tributacao }}</RegimeEspecialTributacao> |
|||
<OptanteSimplesNacional>{{ rps.optante_simples }}</OptanteSimplesNacional> |
|||
<IncentivadorCultural>{{ rps.incentivador_cultural }}</IncentivadorCultural> |
|||
<Status>{{ rps.status }}</Status> |
|||
<RpsSubstituido> |
|||
<Numero>{{ rps.numero_substituido }}</Numero> |
|||
<Serie>{{ rps.serie_substituido }}</Serie> |
|||
<Tipo>{{ rps.tipo_substituido }}</Tipo> |
|||
</RpsSubstituido> |
|||
<Servico> |
|||
<Valores> |
|||
<ValorServicos>{{ rps.valor_servico }}</ValorServicos> |
|||
<ValorDeducoes>{{ rps.valor_deducao }}</ValorDeducoes> |
|||
<ValorPis>{{ rps.valor_pis }}</ValorPis> |
|||
<ValorCofins>{{ rps.valor_cofins }}</ValorCofins> |
|||
<ValorInss>{{ rps.valor_inss }}</ValorInss> |
|||
<ValorIr>{{ rps.valor_ir }}</ValorIr> |
|||
<ValorCsll>{{ rps.valor_csll }}</ValorCsll> |
|||
<IssRetido>{{ rps.iss_retido }}</IssRetido> |
|||
<ValorIss>{{ rps.valor_iss }}</ValorIss> |
|||
<ValorIssRetido>{{ rps.valor_iss_retido }}</ValorIssRetido> |
|||
<OutrasRetencoes>{{ rps.outras_retencoes }}</OutrasRetencoes> |
|||
<BaseCalculo>{{ rps.base_calculo }}</BaseCalculo> |
|||
<Aliquota>{{ rps.aliquota_issqn }}</Aliquota> |
|||
<ValorLiquidoNfse>{{ rps.valor_liquido_nfse }}</ValorLiquidoNfse> |
|||
<DescontoIncondicionado>{{ rps.desconto_incondicionado }}</DescontoIncondicionado> |
|||
<DescontoCondicionado>{{ rps.desconto_condicionado }}</DescontoCondicionado> |
|||
</Valores> |
|||
<ItemListaServico>{{ rps.codigo_servico }}</ItemListaServico> |
|||
<CodigoCnae>{{ rps.cnae_servico }}</CodigoCnae> |
|||
<CodigoTributacaoMunicipio>{{ rps.codigo_tributacao_municipio }}</CodigoTributacaoMunicipio> |
|||
<Discriminacao>{{ rps.descricao }}</Discriminacao> |
|||
<CodigoMunicipio>{{ rps.codigo_municipio }}</CodigoMunicipio> |
|||
</Servico> |
|||
<Prestador> |
|||
<Cnpj>{{ rps.prestador.cnpj }}</Cnpj> |
|||
<InscricaoMunicipal>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipal> |
|||
</Prestador> |
|||
<Tomador> |
|||
<IdentificacaoTomador> |
|||
<CpfCnpj> |
|||
{% if rps.tomador.cnpj_cpf|length == 14 %} |
|||
<Cnpj>{{ rps.tomador.cnpj_cpf }}</Cnpj> |
|||
{% endif %} |
|||
{% if rps.tomador.cnpj_cpf|length == 11 %} |
|||
<Cpf>{{ rps.tomador.cnpj_cpf }}</Cpf> |
|||
{% endif %} |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ rps.tomador.inscricao_municipal }}</InscricaoMunicipal> |
|||
</IdentificacaoTomador> |
|||
<RazaoSocial>{{ rps.tomador.razao_social }}</RazaoSocial> |
|||
<Endereco> |
|||
<Endereco>{{ rps.tomador.logradouro }}</Endereco> |
|||
<Numero>{{ rps.tomador.numero }}</Numero> |
|||
<Complemento>{{ rps.tomador.complemento }}</Complemento> |
|||
<Bairro>{{ rps.tomador.bairro }}</Bairro> |
|||
<CodigoMunicipio>{{ rps.tomador.cidade }}</CodigoMunicipio> |
|||
<Uf>{{ rps.tomador.uf }}</Uf> |
|||
<Cep>{{ rps.tomador.cep }}</Cep> |
|||
</Endereco> |
|||
<Contato> |
|||
<Telefone>{{ rps.tomador.telefone }}</Telefone> |
|||
<Email>{{ rps.tomador.email }}</Email> |
|||
</Contato> |
|||
</Tomador> |
|||
{% if rps.intermediario is defined -%} |
|||
<IntermediarioServico> |
|||
<RazaoSocial>{{ rps.intermediario.razao_social }}</RazaoSocial> |
|||
<CpfCnpj> |
|||
<Cnpj>{{ rps.intermediario.cnpj }}</Cnpj> |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ rps.intermediario.inscricao_municipal }}</InscricaoMunicipal> |
|||
</IntermediarioServico> |
|||
{% endif %} |
|||
{% if rps.construcao_civil is defined -%} |
|||
<ContrucaoCivil> |
|||
<CodigoObra>{{ rps.construcao_civil.codigo_obra }}</CodigoObra> |
|||
<Art>{{ rps.construcao_civil.art }}</Art> |
|||
</ContrucaoCivil> |
|||
{% endif %} |
|||
</InfRps> |
|||
</Rps> |
|||
@ -0,0 +1,69 @@ |
|||
# © 2018 Danimar Ribeiro, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import os |
|||
import suds |
|||
from pytrustnfe.client import get_authenticated_client |
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key |
|||
from pytrustnfe.xml import render_xml, sanitize_response |
|||
from pytrustnfe.nfe.assinatura import Assinatura |
|||
|
|||
|
|||
def _render(certificado, method, **kwargs): |
|||
path = os.path.join(os.path.dirname(__file__), "templates") |
|||
xml_send = render_xml(path, "%s.xml" % method, True, **kwargs) |
|||
|
|||
reference = "" |
|||
if method == "GerarNfse": |
|||
reference = "r%s" % kwargs["rps"]["numero"] |
|||
elif method == "CancelarNfse": |
|||
reference = "Cancelamento_NF%s" % kwargs["cancelamento"]["numero_nfse"] |
|||
|
|||
signer = Assinatura(certificado.pfx, certificado.password) |
|||
xml_send = signer.assina_xml(xml_send, reference) |
|||
return xml_send.encode("utf-8") |
|||
|
|||
|
|||
def _send(certificado, method, **kwargs): |
|||
base_url = "" |
|||
if kwargs["ambiente"] == "producao": |
|||
base_url = "https://notacarioca.rio.gov.br/WSNacional/nfse.asmx?wsdl" |
|||
else: |
|||
base_url = "https://homologacao.notacarioca.rio.gov.br/WSNacional/nfse.asmx?wsdl" # noqa |
|||
|
|||
xml_send = kwargs["xml"].decode("utf-8") |
|||
cert, key = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password) |
|||
cert, key = save_cert_key(cert, key) |
|||
client = get_authenticated_client(base_url, cert, key) |
|||
|
|||
try: |
|||
response = getattr(client.service, method)(xml_send) |
|||
except suds.WebFault as e: |
|||
return { |
|||
"sent_xml": str(xml_send), |
|||
"received_xml": str(e.fault.faultstring), |
|||
"object": None, |
|||
} |
|||
|
|||
response, obj = sanitize_response(response) |
|||
return {"sent_xml": str(xml_send), "received_xml": str(response), "object": obj} |
|||
|
|||
|
|||
def xml_gerar_nfse(certificado, **kwargs): |
|||
return _render(certificado, "GerarNfse", **kwargs) |
|||
|
|||
|
|||
def gerar_nfse(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_gerar_nfse(certificado, **kwargs) |
|||
return _send(certificado, "GerarNfse", **kwargs) |
|||
|
|||
|
|||
def xml_cancelar_nfse(certificado, **kwargs): |
|||
return _render(certificado, "CancelarNfse", **kwargs) |
|||
|
|||
|
|||
def cancelar_nfse(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_cancelar_nfse(certificado, **kwargs) |
|||
return _send(certificado, "CancelarNfse", **kwargs) |
|||
@ -0,0 +1,13 @@ |
|||
<CancelarNfseEnvio xmlns="http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd"> |
|||
<Pedido> |
|||
<InfPedidoCancelamento Id="Cancelamento_NF{{ cancelamento.numero_nfse }}"> |
|||
<IdentificacaoNfse> |
|||
<Numero>{{ cancelamento.numero_nfse }}</Numero> |
|||
<Cnpj>{{ cancelamento.cnpj_prestador }}</Cnpj> |
|||
<InscricaoMunicipal>{{ cancelamento.inscricao_municipal }}</InscricaoMunicipal> |
|||
<CodigoMunicipio>{{ cancelamento.cidade }}</CodigoMunicipio> |
|||
</IdentificacaoNfse> |
|||
<CodigoCancelamento>1</CodigoCancelamento> |
|||
</InfPedidoCancelamento> |
|||
</Pedido> |
|||
</CancelarNfseEnvio> |
|||
@ -0,0 +1,3 @@ |
|||
<GerarNfseEnvio xmlns="http://notacarioca.rio.gov.br/WSNacional/XSD/1/nfse_pcrj_v01.xsd"> |
|||
{% include 'Rps.xml' %} |
|||
</GerarNfseEnvio> |
|||
@ -0,0 +1,91 @@ |
|||
<Rps> |
|||
<InfRps xmlns="http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd" Id="r{{ rps.numero }}"> |
|||
<IdentificacaoRps> |
|||
<Numero>{{ rps.numero }}</Numero> |
|||
<Serie>{{ rps.serie }}</Serie> |
|||
<Tipo>{{ rps.tipo_rps }}</Tipo> |
|||
</IdentificacaoRps> |
|||
<DataEmissao>{{ rps.data_emissao }}</DataEmissao> |
|||
<NaturezaOperacao>{{ rps.natureza_operacao }}</NaturezaOperacao> |
|||
<RegimeEspecialTributacao>{{ rps.regime_tributacao }}</RegimeEspecialTributacao> |
|||
<OptanteSimplesNacional>{{ rps.optante_simples }}</OptanteSimplesNacional> |
|||
<IncentivadorCultural>{{ rps.incentivador_cultural }}</IncentivadorCultural> |
|||
<Status>{{ rps.status }}</Status> |
|||
<RpsSubstituido> |
|||
<Numero>{{ rps.numero_substituido }}</Numero> |
|||
<Serie>{{ rps.serie_substituido }}</Serie> |
|||
<Tipo>{{ rps.tipo_substituido }}</Tipo> |
|||
</RpsSubstituido> |
|||
<Servico> |
|||
<Valores> |
|||
<ValorServicos>{{ rps.valor_servico }}</ValorServicos> |
|||
<ValorDeducoes>{{ rps.valor_deducao }}</ValorDeducoes> |
|||
<ValorPis>{{ rps.valor_pis }}</ValorPis> |
|||
<ValorCofins>{{ rps.valor_cofins }}</ValorCofins> |
|||
<ValorInss>{{ rps.valor_inss }}</ValorInss> |
|||
<ValorIr>{{ rps.valor_ir }}</ValorIr> |
|||
<ValorCsll>{{ rps.valor_csll }}</ValorCsll> |
|||
<IssRetido>{{ rps.iss_retido }}</IssRetido> |
|||
<ValorIss>{{ rps.valor_iss }}</ValorIss> |
|||
<ValorIssRetido>{{ rps.valor_iss_retido }}</ValorIssRetido> |
|||
<OutrasRetencoes>{{ rps.outras_retencoes }}</OutrasRetencoes> |
|||
<BaseCalculo>{{ rps.base_calculo }}</BaseCalculo> |
|||
<Aliquota>{{ rps.aliquota_issqn }}</Aliquota> |
|||
<ValorLiquidoNfse>{{ rps.valor_liquido_nfse }}</ValorLiquidoNfse> |
|||
<DescontoIncondicionado>{{ rps.desconto_incondicionado }}</DescontoIncondicionado> |
|||
<DescontoCondicionado>{{ rps.desconto_condicionado }}</DescontoCondicionado> |
|||
</Valores> |
|||
<ItemListaServico>{{ rps.codigo_servico }}</ItemListaServico> |
|||
<CodigoCnae>{{ rps.cnae_servico }}</CodigoCnae> |
|||
<CodigoTributacaoMunicipio>{{ rps.codigo_tributacao_municipio }}</CodigoTributacaoMunicipio> |
|||
<Discriminacao>{{ rps.descricao }}</Discriminacao> |
|||
<CodigoMunicipio>{{ rps.codigo_municipio }}</CodigoMunicipio> |
|||
</Servico> |
|||
<Prestador> |
|||
<Cnpj>{{ rps.prestador.cnpj }}</Cnpj> |
|||
<InscricaoMunicipal>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipal> |
|||
</Prestador> |
|||
<Tomador> |
|||
<IdentificacaoTomador> |
|||
<CpfCnpj> |
|||
{% if rps.tomador.cnpj_cpf|length == 14 %} |
|||
<Cnpj>{{ rps.tomador.cnpj_cpf }}</Cnpj> |
|||
{% endif %} |
|||
{% if rps.tomador.cnpj_cpf|length == 11 %} |
|||
<Cpf>{{ rps.tomador.cnpj_cpf }}</Cpf> |
|||
{% endif %} |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ rps.tomador.inscricao_municipal }}</InscricaoMunicipal> |
|||
</IdentificacaoTomador> |
|||
<RazaoSocial>{{ rps.tomador.razao_social }}</RazaoSocial> |
|||
<Endereco> |
|||
<Endereco>{{ rps.tomador.logradouro }}</Endereco> |
|||
<Numero>{{ rps.tomador.numero }}</Numero> |
|||
<Complemento>{{ rps.tomador.complemento }}</Complemento> |
|||
<Bairro>{{ rps.tomador.bairro }}</Bairro> |
|||
<CodigoMunicipio>{{ rps.tomador.cidade }}</CodigoMunicipio> |
|||
<Uf>{{ rps.tomador.uf }}</Uf> |
|||
<Cep>{{ rps.tomador.cep }}</Cep> |
|||
</Endereco> |
|||
<Contato> |
|||
<Telefone>{{ rps.tomador.telefone }}</Telefone> |
|||
<Email>{{ rps.tomador.email }}</Email> |
|||
</Contato> |
|||
</Tomador> |
|||
{% if rps.intermediario is defined -%} |
|||
<IntermediarioServico> |
|||
<RazaoSocial>{{ rps.intermediario.razao_social }}</RazaoSocial> |
|||
<CpfCnpj> |
|||
<Cnpj>{{ rps.intermediario.cnpj }}</Cnpj> |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ rps.intermediario.inscricao_municipal }}</InscricaoMunicipal> |
|||
</IntermediarioServico> |
|||
{% endif %} |
|||
{% if rps.construcao_civil is defined -%} |
|||
<ContrucaoCivil> |
|||
<CodigoObra>{{ rps.construcao_civil.codigo_obra }}</CodigoObra> |
|||
<Art>{{ rps.construcao_civil.art }}</Art> |
|||
</ContrucaoCivil> |
|||
{% endif %} |
|||
</InfRps> |
|||
</Rps> |
|||
@ -0,0 +1,124 @@ |
|||
# -*- encoding: utf-8 -*- |
|||
# © 2017 Fábio Luna, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import os |
|||
import suds |
|||
from lxml import etree |
|||
from pytrustnfe.xml import render_xml, sanitize_response |
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key |
|||
from pytrustnfe.nfse.assinatura import Assinatura |
|||
from pytrustnfe.client import get_client |
|||
|
|||
|
|||
def _render(certificado, method, **kwargs): |
|||
path = os.path.join(os.path.dirname(__file__), "templates") |
|||
if method == "testeEnviar": |
|||
xml_send = render_xml(path, "enviar.xml", True, **kwargs) |
|||
else: |
|||
xml_send = render_xml(path, "%s.xml" % method, False, **kwargs) |
|||
|
|||
if type(xml_send) != str: |
|||
xml_send = etree.tostring(xml_send) |
|||
return xml_send.decode() |
|||
|
|||
|
|||
def _get_url(**kwargs): |
|||
|
|||
try: |
|||
cod_cidade = kwargs["nfse"]["cidade"] |
|||
except (KeyError, TypeError): |
|||
raise KeyError("Código de cidade inválido!") |
|||
|
|||
urls = { |
|||
# Belém - PA |
|||
"2715": "http://www.issdigitalbel.com.br/WsNFe2/LoteRps.jws?wsdl", |
|||
# Sorocaba - SP |
|||
"7145": "http://issdigital.sorocaba.sp.gov.br/WsNFe2/LoteRps.jws?wsdl", |
|||
# Teresina - PI |
|||
"1219": "http://www.issdigitalthe.com.br/WsNFe2/LoteRps.jws?wsdl", |
|||
# Campinas - SP |
|||
"6291": "http://issdigital.campinas.sp.gov.br/WsNFe2/LoteRps.jws?wsdl", |
|||
# Uberlandia - MG |
|||
"5403": "http://udigital.uberlandia.mg.gov.br/WsNFe2/LoteRps.jws?wsdl", |
|||
# São Luis - MA |
|||
"0921": "http://sistemas.semfaz.saoluis.ma.gov.br/WsNFe2/LoteRps.jws?wsdl", |
|||
# Campo Grande - MS |
|||
"2729": "http://issdigital.pmcg.ms.gov.br/WsNFe2/LoteRps.jws?wsdl", |
|||
} |
|||
|
|||
try: |
|||
return urls[str(cod_cidade)] |
|||
except KeyError: |
|||
raise KeyError("DSF não emite notas da cidade {}!".format(cod_cidade)) |
|||
|
|||
|
|||
def _send(certificado, method, **kwargs): |
|||
url = _get_url(**kwargs) |
|||
|
|||
path = os.path.join(os.path.dirname(__file__), "templates") |
|||
|
|||
xml_send = _render(path, method, **kwargs) |
|||
client = get_client(url) |
|||
response = False |
|||
|
|||
if certificado: |
|||
cert, key = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password) |
|||
cert, key = save_cert_key(cert, key) |
|||
signer = Assinatura(cert, key, certificado.password) |
|||
xml_send = signer.assina_xml(xml_send, "") |
|||
|
|||
try: |
|||
response = getattr(client.service, method)(xml_send) |
|||
response, obj = sanitize_response(response.encode()) |
|||
except suds.WebFault as e: |
|||
return { |
|||
"sent_xml": xml_send, |
|||
"received_xml": e.fault.faultstring, |
|||
"object": None, |
|||
} |
|||
except Exception as e: |
|||
if response: |
|||
raise Exception(response) |
|||
else: |
|||
raise e |
|||
|
|||
return {"sent_xml": xml_send, "received_xml": response, "object": obj} |
|||
|
|||
|
|||
def xml_enviar(certificado, **kwargs): |
|||
return _render(certificado, "enviar", **kwargs) |
|||
|
|||
|
|||
def enviar(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_enviar(certificado, **kwargs) |
|||
return _send(certificado, "enviar", **kwargs) |
|||
|
|||
|
|||
def xml_teste_enviar(certificado, **kwargs): |
|||
return _render(certificado, "testeEnviar", **kwargs) |
|||
|
|||
|
|||
def teste_enviar(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_teste_enviar(certificado, **kwargs) |
|||
return _send(certificado, "testeEnviar", **kwargs) |
|||
|
|||
|
|||
def cancelar(certificado, **kwargs): |
|||
return _send(certificado, "cancelar", **kwargs) |
|||
|
|||
|
|||
def consulta_lote(**kwargs): |
|||
return _send(False, "consultarLote", **kwargs) |
|||
|
|||
|
|||
def xml_consultar_nfse_rps(certificado, **kwargs): |
|||
return _render(certificado, "consultarNFSeRps", **kwargs) |
|||
|
|||
|
|||
def consultar_nfse_rps(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_consultar_nfse_rps(certificado, **kwargs) |
|||
return _send(certificado, "consultarNFSeRps", **kwargs) |
|||
@ -0,0 +1,18 @@ |
|||
<ns1:ReqCancelamentoNFSe xmlns:ns1="http://localhost:8080/WsNFe2/lote" |
|||
xmlns:tipos="http://localhost:8080/WsNFe2/tp" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://localhost:8080/WsNFe2/lote http://localhost:8080/WsNFe2/xsd/ReqCancelamentoNFSe.xsd"> |
|||
<Cabecalho> |
|||
<CodCidade>{{ cancelamento.cidade }}</CodCidade> |
|||
<CPFCNPJRemetente>{{ cancelamento.cpf_cnpj }}</CPFCNPJRemetente> |
|||
<transacao>true</transacao> |
|||
<Versao>1</Versao> |
|||
</Cabecalho> |
|||
<Lote Id="lote:1ABCDZ"> |
|||
<Nota Id="nota:{{ cancelamento.nota_id }}"> |
|||
<InscricaoMunicipalPrestador>{{ cancelamento.inscricao_municipal }}</InscricaoMunicipalPrestador> |
|||
<NumeroNota>{{ cancelamento.nota_id }}</NumeroNota> |
|||
<CodigoVerificacao>{{ cancelamento.assinatura }}</CodigoVerificacao> |
|||
<MotivoCancelamento>{{ cancelamento.motivo }}</MotivoCancelamento> |
|||
</Nota> |
|||
</Lote> |
|||
</ns1:ReqCancelamentoNFSe> |
|||
@ -0,0 +1,11 @@ |
|||
<ns1:ReqConsultaNotas xmlns:ns1="http://localhost:8080/WsNFe2/lote" xmlns:tipos="http://localhost:8080/WsNFe2/tp" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://localhost:8080/WsNFe2/lote http://localhost:8080/WsNFe2/xsd/ReqConsultaNotas.xsd"> |
|||
<Cabecalho Id="Consulta:notas"> |
|||
<CodCidade>{{ consulta.cidade }}</CodCidade> |
|||
<CPFCNPJRemetente>{{ consulta.cpf_cnpj }}</CPFCNPJRemetente> |
|||
<InscricaoMunicipalPrestador>{{ consulta.inscricao_municipal }}</InscricaoMunicipalPrestador> |
|||
<dtInicio>{{ consulta.data_inicio }}</dtInicio> |
|||
<dtFim>{{ consulta.data_final }}</dtFim> |
|||
<NotaInicial>{{ consulta.nota_inicial }}</NotaInicial> |
|||
<Versao>1</Versao> |
|||
</Cabecalho> |
|||
</ns1:ReqConsultaNotas> |
|||
@ -0,0 +1,10 @@ |
|||
<ns1:ReqConsultaLote xmlns:ns1="http://localhost:8080/WsNFe2/lote" |
|||
xmlns:tipos="http://localhost:8080/WsNFe2/tp" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://localhost:8080/WsNFe2/lote http://localhost:8080/WsNFe2/xsd/ReqConsultaLote.xsd"> |
|||
<Cabecalho> |
|||
<CodCidade>{{ consulta.cidade }}</CodCidade> |
|||
<CPFCNPJRemetente>{{ consulta.cpf_cnpj }}</CPFCNPJRemetente> |
|||
<Versao>1</Versao> |
|||
<NumeroLote>{{ consulta.lote }}</NumeroLote> |
|||
</Cabecalho> |
|||
</ns1:ReqConsultaLote> |
|||
@ -0,0 +1,22 @@ |
|||
<ns1:ReqConsultaNFSeRPS |
|||
xmlns:ns1="http://localhost:8080/WsNFe2/lote" |
|||
xmlns:tipos="http://localhost:8080/WsNFe2/tp" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://localhost:8080/WsNFe2/lote http://localhost:8080/WsNFe2/xsd/ReqConsultaNFSeRPS.xsd"> |
|||
<Cabecalho> |
|||
<CodCidade>{{ nfse.cidade }}</CodCidade> |
|||
<CPFCNPJRemetente>{{ nfse.cpf_cnpj }}</CPFCNPJRemetente> |
|||
<transacao>true</transacao> |
|||
<Versao>1</Versao> |
|||
</Cabecalho> |
|||
<Lote Id="lote:{{ nfse.lote }}"> |
|||
{% for rps in nfse.lista_rps -%} |
|||
<RPSConsulta> |
|||
<RPS Id="rps:{{ rps.numero }}"> |
|||
<InscricaoMunicipalPrestador>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipalPrestador> |
|||
<NumeroRPS>{{ rps.numero }}</NumeroRPS> |
|||
<SeriePrestacao>{{ rps.serie_prestacao }}</SeriePrestacao> |
|||
</RPS> |
|||
</RPSConsulta> |
|||
{% endfor %} |
|||
</Lote> |
|||
</ns1:ReqConsultaNFSeRPS> |
|||
@ -0,0 +1,100 @@ |
|||
<ns1:ReqEnvioLoteRPS xmlns:ns1="http://localhost:8080/WsNFe2/lote" |
|||
xmlns:tipos="http://localhost:8080/WsNFe2/tp" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://localhost:8080/WsNFe2/lote http://localhost:8080/WsNFe2/xsd/ReqEnvioLoteRPS.xsd"> |
|||
<Cabecalho> |
|||
<CodCidade>{{ nfse.cidade }}</CodCidade> |
|||
<CPFCNPJRemetente>{{ nfse.cpf_cnpj }}</CPFCNPJRemetente> |
|||
<RazaoSocialRemetente>{{ nfse.remetente }}</RazaoSocialRemetente> |
|||
<transacao>{{ nfse.transacao }}</transacao> |
|||
<dtInicio>{{ nfse.data_inicio|format_date }}</dtInicio> |
|||
<dtFim>{{ nfse.data_fim|format_date }}</dtFim> |
|||
<QtdRPS>{{ nfse.total_rps }}</QtdRPS> |
|||
<ValorTotalServicos>{{ nfse.total_servicos }}</ValorTotalServicos> |
|||
<ValorTotalDeducoes>{{ nfse.total_deducoes }}</ValorTotalDeducoes> |
|||
<Versao>1</Versao> |
|||
<MetodoEnvio>WS</MetodoEnvio> |
|||
</Cabecalho> |
|||
<Lote Id="{{ nfse.lote_id }}"> |
|||
{% for rps in nfse.lista_rps -%} |
|||
<RPS Id="{{ rps.numero }}"> |
|||
<Assinatura>{{ rps.assinatura }}</Assinatura> |
|||
<InscricaoMunicipalPrestador>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipalPrestador> |
|||
<RazaoSocialPrestador>{{ rps.prestador.razao_social }}</RazaoSocialPrestador> |
|||
<TipoRPS>RPS</TipoRPS> |
|||
<SerieRPS>{{ rps.serie }}</SerieRPS> |
|||
<NumeroRPS>{{ rps.numero }}</NumeroRPS> |
|||
<DataEmissaoRPS>{{ rps.data_emissao|format_datetime }}</DataEmissaoRPS> |
|||
<SituacaoRPS>{{ rps.situacao }}</SituacaoRPS> |
|||
<SerieRPSSubstituido></SerieRPSSubstituido> |
|||
<NumeroRPSSubstituido>0</NumeroRPSSubstituido> |
|||
<NumeroNFSeSubstituida>0</NumeroNFSeSubstituida> |
|||
<DataEmissaoNFSeSubstituida>1900-01-01</DataEmissaoNFSeSubstituida> |
|||
<SeriePrestacao>{{ rps.serie_prestacao }}</SeriePrestacao> |
|||
<InscricaoMunicipalTomador>{{ rps.tomador.inscricao_municipal }}</InscricaoMunicipalTomador> |
|||
<CPFCNPJTomador>{{ rps.tomador.cpf_cnpj }}</CPFCNPJTomador> |
|||
<RazaoSocialTomador>{{ rps.tomador.razao_social }}</RazaoSocialTomador> |
|||
<TipoLogradouroTomador>{{ rps.tomador.tipo_logradouro }}</TipoLogradouroTomador> |
|||
<LogradouroTomador>{{ rps.tomador.logradouro }}</LogradouroTomador> |
|||
<NumeroEnderecoTomador>{{ rps.tomador.numero }}</NumeroEnderecoTomador> |
|||
<TipoBairroTomador>{{ rps.tomador.tipo_bairro }}</TipoBairroTomador> |
|||
<BairroTomador>{{ rps.tomador.bairro }}</BairroTomador> |
|||
<CidadeTomador>{{ rps.tomador.cidade }}</CidadeTomador> |
|||
<CidadeTomadorDescricao>{{ rps.tomador.cidade_descricao }}</CidadeTomadorDescricao> |
|||
<CEPTomador>{{ rps.tomador.cep }}</CEPTomador> |
|||
<EmailTomador>{{ rps.tomador.email }}</EmailTomador> |
|||
<CodigoAtividade>{{ rps.codigo_atividade }}</CodigoAtividade> |
|||
<AliquotaAtividade>{{ rps.aliquota_atividade }}</AliquotaAtividade> |
|||
<TipoRecolhimento>{{ rps.tipo_recolhimento }}</TipoRecolhimento> |
|||
<MunicipioPrestacao>{{ rps.municipio_prestacao }}</MunicipioPrestacao> |
|||
<MunicipioPrestacaoDescricao>{{ rps.municipio_prestacao_descricao }}</MunicipioPrestacaoDescricao> |
|||
<Operacao>{{ rps.operacao }}</Operacao> |
|||
<Tributacao>{{ rps.tributacao }}</Tributacao> |
|||
<ValorPIS>{{ rps.valor_pis }}</ValorPIS> |
|||
<ValorCOFINS>{{ rps.valor_cofins }}</ValorCOFINS> |
|||
<ValorINSS>{{ rps.valor_inss }}</ValorINSS> |
|||
<ValorIR>{{ rps.valor_ir }}</ValorIR> |
|||
<ValorCSLL>{{ rps.valor_csll }}</ValorCSLL> |
|||
<AliquotaPIS>{{ rps.aliquota_pis }}</AliquotaPIS> |
|||
<AliquotaCOFINS>{{ rps.aliquota_cofins }}</AliquotaCOFINS> |
|||
<AliquotaINSS>{{ rps.aliquota_inss }}</AliquotaINSS> |
|||
<AliquotaIR>{{ rps.aliquota_ir }}</AliquotaIR> |
|||
<AliquotaCSLL>{{ rps.aliquota_csll }}</AliquotaCSLL> |
|||
<DescricaoRPS>{{ rps.descricao }}</DescricaoRPS> |
|||
<DDDPrestador>{{ rps.prestador.ddd }}</DDDPrestador> |
|||
<TelefonePrestador>{{ rps.prestador.telefone }}</TelefonePrestador> |
|||
<DDDTomador>{{ rps.tomador.ddd }}</DDDTomador> |
|||
<TelefoneTomador>{{ rps.tomador.telefone }}</TelefoneTomador> |
|||
<MotCancelamento>{{ rps.motivo_cancelamento }}</MotCancelamento> |
|||
{% if rps.deducoes|count > 0 %} |
|||
<Deducoes> |
|||
{% for deducao in rps.deducoes -%} |
|||
<Deducao> |
|||
<DeducaoPor>{{ deducao.por }}</DeducaoPor> |
|||
<TipoDeducao>{{ deducao.tipo }}</TipoDeducao> |
|||
<CPFCNPJReferencia>{{ deducao.cnpj_referencia }}</CPFCNPJReferencia> |
|||
<NumeroNFReferencia>{{ deducao.nf_referencia }}</NumeroNFReferencia> |
|||
<ValorTotalReferencia>{{ deducao.valor_referencia }}</ValorTotalReferencia> |
|||
<PercentualDeduzir>{{ deducao.percentual_deduzir }}</PercentualDeduzir> |
|||
<ValorDeduzir>{{ deducao.valor_deduzir }}</ValorDeduzir> |
|||
</Deducao> |
|||
{% endfor %} |
|||
</Deducoes> |
|||
{% endif %} |
|||
{% if rps.deducoes|count == 0 %} |
|||
<Deducoes /> |
|||
{% endif %} |
|||
<Itens> |
|||
{% for item in rps.itens -%} |
|||
<Item> |
|||
<DiscriminacaoServico>{{ item.descricao }}</DiscriminacaoServico> |
|||
<Quantidade>{{ item.quantidade }}</Quantidade> |
|||
<ValorUnitario>{{ item.valor_unitario }}</ValorUnitario> |
|||
<ValorTotal>{{ item.valor_total }}</ValorTotal> |
|||
<Tributavel>S</Tributavel> |
|||
</Item> |
|||
{% endfor %} |
|||
</Itens> |
|||
</RPS> |
|||
{% endfor %} |
|||
</Lote> |
|||
</ns1:ReqEnvioLoteRPS> |
|||
@ -0,0 +1,12 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" |
|||
xmlns:dsf="http://dsfnet.com.br"> |
|||
<soapenv:Body> |
|||
<dsf:enviar soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> |
|||
<mensagemXml xsi:type="xsd:string"><![CDATA[ |
|||
{% block content %}{% endblock %} |
|||
]]></mensagemXml> |
|||
</dsf:enviar> |
|||
</soapenv:Body> |
|||
</soapenv:Envelope> |
|||
@ -0,0 +1,128 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2017 Danimar Ribeiro, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import os |
|||
import hashlib |
|||
import base64 |
|||
import requests |
|||
from pytrustnfe.xml import render_xml, sanitize_response |
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key |
|||
from pytrustnfe.nfse.assinatura import Assinatura |
|||
|
|||
URLS = { |
|||
"producao": { |
|||
"processar_nota": "https://nfps-e.pmf.sc.gov.br/api/v1/processamento/notas/processa", |
|||
"cancelar_nota": "https://nfps-e.pmf.sc.gov.br/api/v1/cancelamento/notas/cancela", |
|||
}, |
|||
"homologacao": { |
|||
"processar_nota": "https://nfps-e-hml.pmf.sc.gov.br/api/v1/processamento/notas/processa", |
|||
"cancelar_nota": "https://nfps-e-hml.pmf.sc.gov.br/api/v1/cancelamento/notas/cancela", |
|||
}, |
|||
} |
|||
|
|||
|
|||
def _render(certificado, method, **kwargs): |
|||
path = os.path.join(os.path.dirname(__file__), "templates") |
|||
xml_send = render_xml(path, "%s.xml" % method, False, **kwargs) |
|||
|
|||
cert, key = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password) |
|||
cert, key = save_cert_key(cert, key) |
|||
signer = Assinatura(cert, key, certificado.password) |
|||
xml_send = signer.assina_xml(xml_send, "") |
|||
return xml_send |
|||
|
|||
|
|||
def _get_oauth_token(**kwargs): |
|||
if kwargs["ambiente"] == "producao": |
|||
url = "https://nfps-e.pmf.sc.gov.br/api/v1/autenticacao/oauth/token" |
|||
else: |
|||
url = "https://nfps-e-hml.pmf.sc.gov.br/api/v1/autenticacao/oauth/token" |
|||
|
|||
m = hashlib.md5() |
|||
secret = "%s:%s" % (kwargs["client_id"], kwargs["secret_id"]) |
|||
auth = base64.b64encode(secret.encode("utf-8")) |
|||
headers = { |
|||
"Content-Type": "application/x-www-form-urlencoded", |
|||
"Authorization": "Basic %s" % auth.decode("utf-8").replace("\n", ""), |
|||
} |
|||
m.update(kwargs["password"].encode("utf-8")) |
|||
password = m.hexdigest().upper() |
|||
|
|||
dados = ( |
|||
"grant_type=password&username=%s&password=%s&client_id=%s&client_secret=%s" |
|||
% (kwargs["username"], password, kwargs["client_id"], kwargs["secret_id"]) |
|||
) |
|||
r = requests.post(url, data=dados, headers=headers) |
|||
if r.status_code == 200: |
|||
return r.json() |
|||
else: |
|||
return r.json() |
|||
|
|||
|
|||
def _send(certificado, method, **kwargs): |
|||
url = URLS[kwargs["ambiente"]][method] |
|||
xml_send = kwargs["xml"] |
|||
|
|||
token = _get_oauth_token(**kwargs) |
|||
if "access_token" not in token: |
|||
raise Exception( |
|||
"%s - %s: %s" % (token["status"], token["error"], token["message"]) |
|||
) |
|||
kwargs.update({"numero": 1, "access_token": token["access_token"]}) |
|||
|
|||
headers = { |
|||
"Accept": "application/xml;charset=UTF-8", |
|||
"Content-Type": "application/xml", |
|||
"Authorization": "Bearer %s" % kwargs["access_token"], |
|||
} |
|||
r = requests.post(url, headers=headers, data=xml_send) |
|||
|
|||
response, obj = sanitize_response(r.text.strip()) |
|||
return { |
|||
"sent_xml": xml_send, |
|||
"received_xml": response.encode("utf-8"), |
|||
"object": obj, |
|||
"status_code": r.status_code, |
|||
} |
|||
|
|||
|
|||
def xml_processar_nota(certificado, **kwargs): |
|||
return _render(certificado, "processar_nota", **kwargs) |
|||
|
|||
|
|||
def processar_nota(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_processar_nota(certificado, **kwargs) |
|||
return _send(certificado, "processar_nota", **kwargs) |
|||
|
|||
|
|||
def xml_cancelar_nota(certificado, **kwargs): |
|||
return _render(certificado, "cancelar_nota", **kwargs) |
|||
|
|||
|
|||
def cancelar_nota(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_cancelar_nota(certificado, **kwargs) |
|||
return _send(certificado, "cancelar_nota", **kwargs) |
|||
|
|||
|
|||
def consultar_nota(certificado, **kwargs): |
|||
if kwargs["ambiente"] == "producao": |
|||
url = "https://nfps-e.pmf.sc.gov.br/api/v1/consultas/notas/numero/%s" % ( |
|||
kwargs["numero"] |
|||
) |
|||
else: |
|||
url = "https://nfps-e-hml.pmf.sc.gov.br/api/v1/consultas/notas/numero/%s" % ( |
|||
kwargs["numero"] |
|||
) |
|||
|
|||
headers = { |
|||
"Accept": "application/json", |
|||
"Authorization": "Bearer %s" % kwargs["access_token"], |
|||
} |
|||
r = requests.get(url, headers=headers) |
|||
if r.status_code == 200: |
|||
return r.text |
|||
else: |
|||
return r.text |
|||
@ -0,0 +1,7 @@ |
|||
<?xml version="1.0"?> |
|||
<xmlCancelamentoNfpse> |
|||
<motivoCancelamento>{{ cancelamento.motivo }}</motivoCancelamento> |
|||
<nuAedf>{{ cancelamento.aedf }}</nuAedf> |
|||
<nuNotaFiscal>{{ cancelamento.numero }}</nuNotaFiscal> |
|||
<codigoVerificacao>{{ cancelamento.codigo_verificacao }}</codigoVerificacao> |
|||
</xmlCancelamentoNfpse> |
|||
@ -0,0 +1,41 @@ |
|||
<?xml version="1.0"?> |
|||
<xmlProcessamentoNfpse> |
|||
<bairroTomador>{{ rps.tomador.bairro|normalize|escape }}</bairroTomador> |
|||
<baseCalculo>{{ rps.base_calculo }}</baseCalculo> |
|||
<baseCalculoSubstituicao>0.0</baseCalculoSubstituicao> |
|||
<cfps>{{ rps.cfps }}</cfps> |
|||
<codigoMunicipioTomador>{{ rps.tomador.cidade }}</codigoMunicipioTomador> |
|||
<codigoPostalTomador>{{ rps.tomador.cep }}</codigoPostalTomador> |
|||
<complementoEnderecoTomador>{{ rps.tomador.complemento|normalize|escape }}</complementoEnderecoTomador> |
|||
<dadosAdicionais>{{ rps.observacoes|normalize|escape }}</dadosAdicionais> |
|||
<dataEmissao>{{ rps.data_emissao }}</dataEmissao> |
|||
<emailTomador>{{ rps.tomador.email }}</emailTomador> |
|||
<identificacao>{{ rps.numero }}</identificacao> |
|||
<identificacaoTomador>{{ rps.tomador.cnpj_cpf }}</identificacaoTomador> |
|||
<inscricaoMunicipalTomador>{{ rps.tomador.inscricao_municipal }}</inscricaoMunicipalTomador> |
|||
<itensServico> |
|||
{% for item in rps.itens_servico -%} |
|||
<itemServico> |
|||
<aliquota>{{ item.aliquota }}</aliquota> |
|||
<baseCalculo>{{ item.base_calculo }}</baseCalculo> |
|||
<cst>{{ item.cst_servico }}</cst> |
|||
<descricaoServico>{{ item.name|normalize|escape }}</descricaoServico> |
|||
<idCNAE>{{ item.cnae }}</idCNAE> |
|||
<quantidade>{{ item.quantidade }}</quantidade> |
|||
<valorTotal>{{ item.valor_total }}</valorTotal> |
|||
<valorUnitario>{{ item.valor_unitario }}</valorUnitario> |
|||
</itemServico> |
|||
{% endfor %} |
|||
</itensServico> |
|||
<logradouroTomador>{{ rps.tomador.logradouro|normalize|escape }}</logradouroTomador> |
|||
<nomeMunicipioTomador></nomeMunicipioTomador> |
|||
<numeroAEDF>{{ rps.aedf }}</numeroAEDF> |
|||
<numeroEnderecoTomador>{{ rps.tomador.numero }}</numeroEnderecoTomador> |
|||
<paisTomador>1058</paisTomador> |
|||
<razaoSocialTomador>{{ rps.tomador.razao_social|normalize|escape }}</razaoSocialTomador> |
|||
<telefoneTomador>{{ rps.tomador.telefone }}</telefoneTomador> |
|||
<ufTomador>{{ rps.tomador.uf }}</ufTomador> |
|||
<valorISSQN>{{rps.valor_issqn }}</valorISSQN> |
|||
<valorISSQNSubstituicao>0.0</valorISSQNSubstituicao> |
|||
<valorTotalServicos>{{ rps.valor_total }}</valorTotalServicos> |
|||
</xmlProcessamentoNfpse> |
|||
@ -1,15 +1,14 @@ |
|||
<CancelarNfseEnvio xmlns="http://www.betha.com.br/e-nota-contribuinte-ws"> |
|||
<Pedido> |
|||
<InfPedidoCancelamento Id="1"> |
|||
<IdentificacaoNfse> |
|||
<Numero>{{ cancelamento.numero_nfse }}</Numero> |
|||
<CpfCnpj> |
|||
<Cnpj>{{ cancelamento.cnpj_prestador }}</Cnpj> |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ cancelamento.inscricao_municipal }}</InscricaoMunicipal> |
|||
<CodigoMunicipio>{{ cancelamento.cidade }}</CodigoMunicipio> |
|||
</IdentificacaoNfse> |
|||
<CodigoCancelamento>{{ cancelamento.codigo_cancelamento }}</CodigoCancelamento> |
|||
</InfPedidoCancelamento> |
|||
<CancelarNfseEnvio xmlns="http://www.ginfes.com.br/servico_cancelar_nfse_envio_v03.xsd" |
|||
xmlns:tipos="http://www.ginfes.com.br/tipos_v03.xsd"> |
|||
<Pedido xmlns=""> |
|||
<tipos:InfPedidoCancelamento Id="C{{ cancelamento.numero_nfse }}"> |
|||
<tipos:IdentificacaoNfse> |
|||
<tipos:Numero>{{ cancelamento.numero_nfse }}</tipos:Numero> |
|||
<tipos:Cnpj>{{ cancelamento.cnpj_prestador }}</tipos:Cnpj> |
|||
<tipos:InscricaoMunicipal>{{ cancelamento.inscricao_municipal }}</tipos:InscricaoMunicipal> |
|||
<tipos:CodigoMunicipio>{{ cancelamento.cidade }}</tipos:CodigoMunicipio> |
|||
</tipos:IdentificacaoNfse> |
|||
<tipos:CodigoCancelamento>{{ cancelamento.codigo_cancelamento }}</tipos:CodigoCancelamento> |
|||
</tipos:InfPedidoCancelamento> |
|||
</Pedido> |
|||
</CancelarNfseEnvio> |
|||
@ -1,13 +1,12 @@ |
|||
<ConsultarNfseRpsEnvio xmlns="http://www.betha.com.br/e-nota-contribuinte-ws"> |
|||
<ConsultarNfseRpsEnvio xmlns="http://www.ginfes.com.br/servico_consultar_nfse_rps_envio_v03.xsd" |
|||
xmlns:tipos="http://www.ginfes.com.br/tipos_v03.xsd"> |
|||
<IdentificacaoRps> |
|||
<Numero>24</Numero> |
|||
<Serie>A1</Serie> |
|||
<Tipo>1</Tipo> |
|||
<tipos:Numero>{{ consulta.numero }}</tipos:Numero> |
|||
<tipos:Serie>{{ consulta.serie }}</tipos:Serie> |
|||
<tipos:Tipo>{{ consulta.tipo }}</tipos:Tipo> |
|||
</IdentificacaoRps> |
|||
<Prestador> |
|||
<CpfCnpj> |
|||
<Cnpj>45111111111100</Cnpj> |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>123498</InscricaoMunicipal> |
|||
<tipos:Cnpj>{{ consulta.cnpj_prestador }}</tipos:Cnpj> |
|||
<tipos:InscricaoMunicipal>{{ consulta.inscricao_municipal }}</tipos:InscricaoMunicipal> |
|||
</Prestador> |
|||
</ConsultarNfseRpsEnvio> |
|||
@ -1,8 +1,8 @@ |
|||
<ConsultarLoteRpsEnvio xmlns="http://www.betha.com.br/e-nota-contribuinte-ws"> |
|||
<ConsultarNfseEnvio xmlns="http://www.ginfes.com.br/servico_consultar_nfse_envio_v03.xsd" |
|||
xmlns:tipos="http://www.ginfes.com.br/tipos_v03.xsd"> |
|||
<Prestador> |
|||
<CpfCnpj> |
|||
<Cnpj>45111111111100</Cnpj> |
|||
</CpfCnpj> |
|||
<tipos:Cnpj>{{ consulta.cnpj_prestador }}</tipos:Cnpj> |
|||
<tipos:InscricaoMunicipal>{{ consulta.inscricao_municipal }}</tipos:InscricaoMunicipal> |
|||
</Prestador> |
|||
<Protocolo>141542179222170</Protocolo> |
|||
</ConsultarLoteRpsEnvio> |
|||
<NumeroNfse>{{ consulta.numero_nfse }}</NumeroNfse> |
|||
</ConsultarNfseEnvio> |
|||
@ -0,0 +1,61 @@ |
|||
import os |
|||
import suds |
|||
|
|||
from lxml import etree |
|||
|
|||
from pytrustnfe.client import get_authenticated_client |
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key |
|||
from pytrustnfe.xml import render_xml, sanitize_response |
|||
|
|||
from .assinatura import Assinatura |
|||
|
|||
|
|||
def _render(certificado, method, **kwargs): |
|||
path = os.path.join(os.path.dirname(__file__), "templates") |
|||
xml_send = render_xml(path, f"{method}.xml", False, **kwargs) |
|||
signer = Assinatura(certificado.pfx, certificado.password) |
|||
xml_send = etree.fromstring(xml_send) |
|||
xml_send = signer.assina_xml(xml_send) |
|||
return xml_send |
|||
|
|||
|
|||
def _send(certificado, method, **kwargs): |
|||
base_url = "https://nfse.goiania.go.gov.br/ws/nfse.asmx?wsdl" |
|||
xml_send = kwargs["xml"] |
|||
cert, key = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password) |
|||
cert, key = save_cert_key(cert, key) |
|||
client = get_authenticated_client(base_url, cert, key) |
|||
|
|||
try: |
|||
response = getattr(client.service, method)(xml_send) |
|||
except suds.WebFault as e: |
|||
return { |
|||
"send_xml": str(xml_send), |
|||
"received_xml": str(e.fault.faultstring), |
|||
"object": None, |
|||
} |
|||
|
|||
response, obj = sanitize_response(response) |
|||
return {"send_xml": str(xml_send), "received_xml": str(response), "object": obj} |
|||
|
|||
|
|||
def xml_gerar_nfse(certificado, **kwargs): |
|||
""" Retorna o XML montado para ser enviado para o Webservice """ |
|||
|
|||
return _render(certificado, "GerarNfse", **kwargs) |
|||
|
|||
|
|||
def gerar_nfse(certificado, **kwargs): |
|||
"""" Gera uma NFSe de saída """ |
|||
|
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_gerar_nfse |
|||
return _send(certificado, "GerarNfse", **kwargs) |
|||
|
|||
|
|||
def consulta_nfse_por_rps(certificado, **kwargs): |
|||
""" Consulta os dados de um NFSe já emitida """ |
|||
|
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = _render(certificado, "ConsultarNfseRps", **kwargs) |
|||
return _send(certificado, "ConsultarNfseRps", **kwargs) |
|||
@ -0,0 +1,38 @@ |
|||
from lxml import etree |
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx |
|||
from signxml import XMLSigner, methods |
|||
from pytrustnfe.nfe.assinatura import Assinatura as _Assinatura |
|||
|
|||
|
|||
class Assinatura(_Assinatura): |
|||
|
|||
def assina_xml(self, xml_element): |
|||
cert, key = extract_cert_and_key_from_pfx(self.arquivo, self.senha) |
|||
|
|||
for element in xml_element.iter("*"): |
|||
if element.text is not None and not element.text.strip(): |
|||
element.text = None |
|||
|
|||
signer = XMLSigner( |
|||
method=methods.enveloped, |
|||
signature_algorithm=u"rsa-sha1", |
|||
digest_algorithm=u"sha1", |
|||
c14n_algorithm=u"http://www.w3.org/TR/2001/REC-xml-c14n-20010315", |
|||
) |
|||
|
|||
ns = {} |
|||
ns[None] = signer.namespaces["ds"] |
|||
signer.namespaces = ns |
|||
element_signed = xml_element.find(".//{http://nfse.goiania.go.gov.br/xsd/nfse_gyn_v02.xsd}Rps") |
|||
signed_root = signer.sign( |
|||
xml_element, key=key.encode(), cert=cert.encode() |
|||
) |
|||
signature = signed_root.find( |
|||
".//{http://www.w3.org/2000/09/xmldsig#}Signature" |
|||
) |
|||
|
|||
if element_signed is not None and signature is not None: |
|||
parent = xml_element.getchildren()[0] |
|||
parent.append(signature) |
|||
|
|||
return etree.tostring(xml_element, encoding=str) |
|||
@ -0,0 +1,19 @@ |
|||
<?xml version="1.0"?> |
|||
<ConsultarNfseRpsEnvio xmlns="http://nfse.goiania.go.gov.br/xsd/nfse_gyn_v02.xsd"> |
|||
<IdentificacaoRps> |
|||
<Numero>{{ numero }}</Numero> |
|||
<Serie>{{ serie }}</Serie> |
|||
<Tipo>{{ tipo }}</Tipo> |
|||
</IdentificacaoRps> |
|||
<Prestador> |
|||
<CpfCnpj> |
|||
{% if cnpj_cpf|length == 14 %} |
|||
<Cnpj>{{ cnpj_cpf }}</Cnpj> |
|||
{% endif %} |
|||
{% if cnpj_cpf|length == 11 %} |
|||
<Cpf>{{ cnpj_cpf }}</Cpf> |
|||
{% endif %} |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ inscricao_municipal }}</InscricaoMunicipal> |
|||
</Prestador> |
|||
</ConsultarNfseRpsEnvio> |
|||
@ -0,0 +1,4 @@ |
|||
<?xml version="1.0"?> |
|||
<GerarNfseEnvio xmlns="http://nfse.goiania.go.gov.br/xsd/nfse_gyn_v02.xsd"> |
|||
{% include 'Rps.xml' %} |
|||
</GerarNfseEnvio> |
|||
@ -0,0 +1,63 @@ |
|||
<Rps> |
|||
<InfDeclaracaoPrestacaoServico> |
|||
<Rps> |
|||
<IdentificacaoRps> |
|||
<Numero>{{ numero }}</Numero> |
|||
<Serie>{{ serie }}</Serie> |
|||
<Tipo>{{ tipo }}</Tipo> |
|||
</IdentificacaoRps> |
|||
<DataEmissao>{{ data_emissao }}</DataEmissao> |
|||
<Status>{{ status }}</Status> |
|||
</Rps> |
|||
<Servico> |
|||
<Valores> |
|||
<ValorServicos>{{ servico.valor_servicos }}</ValorServicos> |
|||
{% if servico.valor_pis %}<ValorPis>{{ servico.valor_pis }}</ValorPis>{% endif %} |
|||
{% if servico.valor_confins %}<ValorCofins>{{ servico.valor_confins }}</ValorCofins>{% endif %} |
|||
{% if servico.valor_inss %}<ValorInss>{{ servico.valor_inss }}</ValorInss>{% endif %} |
|||
{% if servico.valor_csll %}<ValorCsll>{{ servico.valor_csll }}</ValorCsll>{% endif %} |
|||
{% if servico.aliquota %}<Aliquota>{{ servico.aliquota }}</Aliquota>{% endif %} |
|||
</Valores> |
|||
<CodigoTributacaoMunicipio>{{ servico.codigo_tributacao_municipio }}</CodigoTributacaoMunicipio> |
|||
<Discriminacao>{{ servico.discriminacao }}</Discriminacao> |
|||
<CodigoMunicipio>{{ servico.codigo_municipio }}</CodigoMunicipio> |
|||
</Servico> |
|||
<Prestador> |
|||
<CpfCnpj> |
|||
{% if prestador.cnpj_cpf|length == 14 %} |
|||
<Cnpj>{{ prestador.cnpj_cpf }}</Cnpj> |
|||
{% endif %} |
|||
{% if prestador.cnpj_cpf|length == 11 %} |
|||
<Cpf>{{ prestador.cnpj_cpf }}</Cpf> |
|||
{% endif %} |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ prestador.inscricao_municipal }}</InscricaoMunicipal> |
|||
</Prestador> |
|||
<Tomador> |
|||
<IdentificacaoTomador> |
|||
<CpfCnpj> |
|||
{% if tomador.cnpj_cpf|length == 14 %} |
|||
<Cnpj>{{ tomador.cnpj_cpf }}</Cnpj> |
|||
{% endif %} |
|||
{% if prestador.cnpj_cpf|length == 11 %} |
|||
<Cpf>{{ prestador.cnpj_cpf }}</Cpf> |
|||
{% endif %} |
|||
</CpfCnpj> |
|||
{% if tomador.inscricao_municipal %} |
|||
<InscricaoMunicipal>{{ tomador.inscricao_municipal }}</InscricaoMunicipal> |
|||
{% endif %} |
|||
</IdentificacaoTomador> |
|||
<RazaoSocial>{{ tomador.razao_social }}</RazaoSocial> |
|||
{% if tomador.endereco %} |
|||
<Endereco> |
|||
{% if tomador.endereco.rua %}<Endereco>{{ tomador.endereco.rua }}</Endereco>{%endif %} |
|||
{% if tomador.endereco.numero %}<Numero>{{ tomador.endereco.numero }}</Numero>{%endif %} |
|||
{% if tomador.endereco.complemento %}<Complemento>{{ tomador.endereco.complemento }}</Complemento>{%endif %} |
|||
{% if tomador.endereco.bairro %}<Bairro>{{ tomador.endereco.bairro }}</Bairro>{%endif %} |
|||
{% if tomador.endereco.codigo_municipio %}<CodigoMunicipio>{{ tomador.endereco.codigo_municipio }}</CodigoMunicipio>{%endif %} |
|||
{% if tomador.endereco.uf %}<Uf>{{ tomador.endereco.uf }}</Uf>{%endif %} |
|||
</Endereco> |
|||
{% endif %} |
|||
</Tomador> |
|||
</InfDeclaracaoPrestacaoServico> |
|||
</Rps> |
|||
@ -1,17 +0,0 @@ |
|||
<ws_nfe.CANCELANOTAELETRONICA xmlns="NFe"> |
|||
<Sdt_cancelanfe> |
|||
<Login> |
|||
<CodigoUsuario>{{ cancelamento.codigo_usuario }}</CodigoUsuario> |
|||
<CodigoContribuinte>{{ cancelamento.codigo_contribuinte }}</CodigoContribuinte> |
|||
</Login> |
|||
<Nota> |
|||
<SerieNota>{{ cancelamento.serie_nota }}</SerieNota> |
|||
<NumeroNota>{{ cancelamento.numero_nota }}</NumeroNota> |
|||
<SerieRPS>{{ cancelamento.serie_rps }}</SerieRPS> |
|||
<NumeroRps>{{ cancelamento.numero_rps }}</NumeroRps> |
|||
<ValorNota>{{ cancelamento.valor }}</ValorNota> |
|||
<MotivoCancelamento>{{ cancelamento.motivo }}</MotivoCancelamento> |
|||
<PodeCancelarGuia>{{ cancelamento.cancelar_guia }}</PodeCancelarGuia> |
|||
</Nota> |
|||
</Sdt_cancelanfe> |
|||
</ws_nfe.CANCELANOTAELETRONICA> |
|||
@ -1,9 +0,0 @@ |
|||
<ws_nfe.CONSULTANOTASPROTOCOLO xmlns="NFe"> |
|||
<Sdt_consultanotasprotocoloin> |
|||
<Protocolo>{{ consulta.protocolo }}</Protocolo> |
|||
<Login> |
|||
<CodigoUsuario>{{ consulta.codigo_usuario }}</CodigoUsuario> |
|||
<CodigoContribuinte>{{ consulta.codigo_contribuinte }}</CodigoContribuinte> |
|||
</Login> |
|||
</Sdt_consultanotasprotocoloin> |
|||
</ws_nfe.CONSULTANOTASPROTOCOLO> |
|||
@ -1,9 +0,0 @@ |
|||
<ws_nfe.CONSULTAPROTOCOLO xmlns="NFe"> |
|||
<Sdt_consultaprotocoloin> |
|||
<Protocolo>{{ consulta.protocolo }}</Protocolo> |
|||
<Login> |
|||
<CodigoUsuario>{{ consulta.codigo_usuario }}</CodigoUsuario> |
|||
<CodigoContribuinte>{{ consulta.codigo_contribuinte }}</CodigoContribuinte> |
|||
</Login> |
|||
</Sdt_consultaprotocoloin> |
|||
</ws_nfe.CONSULTAPROTOCOLO> |
|||
@ -0,0 +1,14 @@ |
|||
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"> |
|||
<Body> |
|||
<CancelarNota xmlns="urn:sigiss_ws"> |
|||
<DadosCancelaNota> |
|||
<ccm>{{ cancelamento.ccm }}</ccm> |
|||
<cnpj>{{ cancelamento.cnpj }}</cnpj> |
|||
<senha>{{ cancelamento.senha }}</senha> |
|||
<nota>{{ cancelamento.nota }}</nota> |
|||
<motivo>{{ cancelamento.motivo }}</motivo> |
|||
<email>{{ cancelamento.email }}</email> |
|||
</DadosCancelaNota> |
|||
</CancelarNota> |
|||
</Body> |
|||
</Envelope> |
|||
@ -0,0 +1,43 @@ |
|||
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"> |
|||
<Body> |
|||
<GerarNota xmlns="urn:sigiss_ws"> |
|||
<DescricaoRps> |
|||
<ccm>{{ nfse.ccm }}</ccm> |
|||
<cnpj>{{ nfse.cnpj }}</cnpj> |
|||
<senha>{{ nfse.senha }}</senha> |
|||
<crc>{{ nfse.crc }}</crc> |
|||
<crc_estado>{{ nfse.crc_estado }}</crc_estado> |
|||
<aliquota_simples>{{ nfse.aliquota_simples }}</aliquota_simples> |
|||
<id_sis_legado>{{ nfse.id_sis_legado }}</id_sis_legado> |
|||
<servico>{{ nfse.servico }}</servico> |
|||
<situacao>{{ nfse.situacao }}</situacao> |
|||
<valor>{{ nfse.valor }}</valor> |
|||
<base>{{ nfse.base }}</base> |
|||
<descricaoNF>{{ nfse.descricaoNF }}</descricaoNF> |
|||
<tomador_tipo>{{ nfse.tomador_tipo }}</tomador_tipo> |
|||
<tomador_cnpj>{{ nfse.tomador_cnpj }}</tomador_cnpj> |
|||
<tomador_email>{{ nfse.tomador_email }}</tomador_email> |
|||
<tomador_ie>{{ nfse.tomador_ie }}</tomador_ie> |
|||
<tomador_razao>{{ nfse.tomador_razao }}</tomador_razao> |
|||
<tomador_fantasia>{{ nfse.tomador_fantasia }}</tomador_fantasia> |
|||
<tomador_endereco>{{ nfse.tomador_endereco }}</tomador_endereco> |
|||
<tomador_numero>{{ nfse.tomador_endereco }}</tomador_numero> |
|||
<tomador_complemento>{{ nfse.tomador_complemento }}</tomador_complemento> |
|||
<tomador_bairro>{{ nfse.tomador_bairro }}</tomador_bairro> |
|||
<tomador_CEP>{{ nfse.tomador_CEP }}</tomador_CEP> |
|||
<tomador_cod_cidade>{{ nfse.tomador_cod_cidade }}</tomador_cod_cidade> |
|||
<tomador_fone>{{ nfse.tomador_fone }}</tomador_fone> |
|||
<tomador_ramal>{{ nfse.tomador_ramal }}</tomador_ramal> |
|||
<tomador_fax>{{ nfse.tomador_fax }}</tomador_fax> |
|||
<outro_municipio>{{ nfse.outro_municipio }}</outro_municipio> |
|||
<cod_outro_municipio>{{ nfse.cod_outro_municipio }}</cod_outro_municipio> |
|||
<retencao_iss>{{ nfse.retencao_iss }}</retencao_iss> |
|||
<pis>{{ nfse.pis }}</pis> |
|||
<cofins>{{ nfse.cofins }}</cofins> |
|||
<inss>{{ nfse.inss }}</inss> |
|||
<irrf>{{ nfse.irrf }}</irrf> |
|||
<csll>{{ nfse.csll }}</csll> |
|||
</DescricaoRps> |
|||
</GerarNota> |
|||
</Body> |
|||
</Envelope> |
|||
@ -1,81 +0,0 @@ |
|||
<ws_nfe.PROCESSARPS xmlns="NFe"> |
|||
<Sdt_processarpsin> |
|||
<Login> |
|||
<CodigoUsuario>{{ nfse.codigo_usuario }}</CodigoUsuario> |
|||
<CodigoContribuinte>{{ nfse.codigo_contribuinte }}</CodigoContribuinte> |
|||
</Login> |
|||
<SDTRPS> |
|||
<Ano>{{ nfse.ano }}</Ano> |
|||
<Mes>{{ nfse.mes }}</Mes> |
|||
<CPFCNPJ>{{ nfse.cnpj_prestador }}</CPFCNPJ> |
|||
<DTIni>{{ nfse.data_emissao }}</DTIni> |
|||
<DTFin>{{ nfse.data_emissao }}</DTFin> |
|||
<TipoTrib>{{ nfse.tipo_tributacao }}</TipoTrib> |
|||
<DtAdeSN>{{ nfse.data_adesao_simples }}</DtAdeSN> |
|||
<AlqIssSN_IP>{{ nfse.aliquota_simples_isencao|comma }}</AlqIssSN_IP> |
|||
<Versao>2.00</Versao> |
|||
{% for rps in nfse.lista_rps -%} |
|||
<Reg20> |
|||
<!-- Optional --> |
|||
<Reg20Item> |
|||
<TipoNFS>{{ rps.tipo_nfse }}</TipoNFS> |
|||
<NumRps>{{ rps.numero }}</NumRps> |
|||
<SerRps>{{ rps.serie }}</SerRps> |
|||
<DtEmi>{{ rps.data_emissao }}</DtEmi> |
|||
<RetFonte>{{ rps.iss_retido }}</RetFonte> |
|||
<CodSrv>{{ rps.codigo_servico }}</CodSrv> |
|||
<DiscrSrv>{{ rps.descricao}}</DiscrSrv> |
|||
<VlNFS>{{ rps.valor_liquido_nfse|comma }}</VlNFS> |
|||
<VlDed>{{ rps.valor_deducao|comma }}</VlDed> |
|||
<DiscrDed>{{ rps.discriminacao_deducao }}</DiscrDed> |
|||
<VlBasCalc>{{ rps.base_calculo|comma }}</VlBasCalc> |
|||
<AlqIss>{{ rps.aliquota_issqn|comma }}</AlqIss> |
|||
<VlIss>{{ rps.valor_iss|comma }}</VlIss> |
|||
<VlIssRet>{{ rps.valor_iss_retido|comma }}</VlIssRet> |
|||
<CpfCnpTom>{{ rps.tomador.cnpj_cpf }}</CpfCnpTom> |
|||
<RazSocTom>{{ rps.tomador.razao_social }}</RazSocTom> |
|||
<TipoLogtom>{{ rps.tomador.tipo_logradouro }}</TipoLogtom> |
|||
<LogTom>{{ rps.tomador.logradouro }}</LogTom> |
|||
<NumEndTom>{{ rps.tomador.numero }}</NumEndTom> |
|||
<ComplEndTom>{{ rps.tomador.complemento }}</ComplEndTom> |
|||
<BairroTom>{{ rps.tomador.bairro }}</BairroTom> |
|||
<MunTom>{{ rps.tomador.municipio }}</MunTom> |
|||
<SiglaUFTom>{{ rps.tomador.uf }}</SiglaUFTom> |
|||
<CepTom>{{ rps.tomador.cep }}</CepTom> |
|||
<Telefone>{{ rps.tomador.telefone }}</Telefone> |
|||
<InscricaoMunicipal>{{ rps.tomador.inscricao_municipal }}</InscricaoMunicipal> |
|||
{% if rps.local_prestacao == 'prestador' %} |
|||
<TipoLogLocPre>{{ rps.prestador.tipo_logradouro }}</TipoLogLocPre> |
|||
<LogLocPre>{{ rps.prestador.logradouro }}</LogLocPre> |
|||
<NumEndLocPre>{{ rps.prestador.numero }}</NumEndLocPre> |
|||
<ComplEndLocPre>{{ rps.prestador.complemento }}</ComplEndLocPre> |
|||
<BairroLocPre>{{ rps.prestador.bairro }}</BairroLocPre> |
|||
<MunLocPre>{{ rps.prestador.municipio }}</MunLocPre> |
|||
<SiglaUFLocpre>{{ rps.prestador.uf }}</SiglaUFLocpre> |
|||
<CepLocPre>{{ rps.prestador.cep }}</CepLocPre> |
|||
{% endif %} |
|||
<Email1>{{ rps.tomador.email }}</Email1> |
|||
{% for imposto in rps.impostos -%} |
|||
<Reg30> |
|||
<Reg30Item> |
|||
<TributoSigla>{{ imposto.sigla }}</TributoSigla> |
|||
<TributoAliquota>{{ imposto.aliquota|comma }}</TributoAliquota> |
|||
<TributoValor>{{ imposto.valor|comma }}</TributoValor> |
|||
</Reg30Item> |
|||
</Reg30> |
|||
{% endfor %} |
|||
</Reg20Item> |
|||
</Reg20> |
|||
{% endfor %} |
|||
<Reg90> |
|||
<QtdRegNormal>{{ nfse.lista_rps|length }}</QtdRegNormal> |
|||
<ValorNFS>{{ nfse.lista_rps|sum(attribute='valor_liquido_nfse')|comma }}</ValorNFS> |
|||
<ValorISS>{{ nfse.lista_rps|sum(attribute='valor_iss')|comma }}</ValorISS> |
|||
<ValorDed>{{ nfse.lista_rps|sum(attribute='valor_deducao')|comma }}</ValorDed> |
|||
<ValorIssRetTom>{{ nfse.lista_rps|sum(attribute='valor_iss_retido')|comma }}</ValorIssRetTom> |
|||
<QtdReg30>{{ nfse.quantidade_impostos }}</QtdReg30> |
|||
<ValorTributos>{{ nfse.valor_tributos|comma }}</ValorTributos> |
|||
</Reg90> |
|||
</SDTRPS> |
|||
</Sdt_processarpsin> |
|||
</ws_nfe.PROCESSARPS> |
|||
@ -1,5 +0,0 @@ |
|||
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"> |
|||
<Body> |
|||
{{ soap_body }} |
|||
</Body> |
|||
</Envelope> |
|||
@ -0,0 +1,70 @@ |
|||
# © 2018 Danimar Ribeiro, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import os |
|||
from requests import Session |
|||
from zeep import Client |
|||
from zeep.transports import Transport |
|||
|
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key |
|||
from pytrustnfe.xml import render_xml, sanitize_response |
|||
from pytrustnfe.nfse.mga.assinatura import Assinatura |
|||
|
|||
|
|||
def _render(certificado, method, **kwargs): |
|||
path = os.path.join(os.path.dirname(__file__), "templates") |
|||
xml_send = render_xml(path, "%s.xml" % method, True, **kwargs) |
|||
|
|||
reference = "" |
|||
if method == "GerarNfse": |
|||
reference = "rps:%s" % kwargs["rps"]["numero"] |
|||
elif method == "CancelarNfse": |
|||
reference = "Cancelamento_NF%s" % kwargs["cancelamento"]["numero_nfse"] |
|||
|
|||
signer = Assinatura(certificado.pfx, certificado.password) |
|||
xml_send = signer.assina_xml(xml_send, reference) |
|||
return xml_send.encode("utf-8") |
|||
|
|||
|
|||
def _send(certificado, method, **kwargs): |
|||
base_url = "" |
|||
if kwargs["ambiente"] == "producao": |
|||
base_url = "https://isse.maringa.pr.gov.br/ws/?wsdl" |
|||
else: |
|||
base_url = "https://isseteste.maringa.pr.gov.br/ws/?wsdl" |
|||
|
|||
xml_send = kwargs["xml"].decode("utf-8") |
|||
|
|||
cert, key = extract_cert_and_key_from_pfx(certificado.pfx, certificado.password) |
|||
cert, key = save_cert_key(cert, key) |
|||
|
|||
session = Session() |
|||
session.cert = (cert, key) |
|||
session.verify = False |
|||
transport = Transport(session=session) |
|||
|
|||
client = Client(base_url, transport=transport) |
|||
response = client.service[method](xml_send) |
|||
|
|||
response, obj = sanitize_response(response) |
|||
return {"sent_xml": str(xml_send), "received_xml": str(response), "object": obj} |
|||
|
|||
|
|||
def xml_gerar_nfse(certificado, **kwargs): |
|||
return _render(certificado, "GerarNfse", **kwargs) |
|||
|
|||
|
|||
def gerar_nfse(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_gerar_nfse(certificado, **kwargs) |
|||
return _send(certificado, "GerarNfse", **kwargs) |
|||
|
|||
|
|||
def xml_cancelar_nfse(certificado, **kwargs): |
|||
return _render(certificado, "CancelarNfse", **kwargs) |
|||
|
|||
|
|||
def cancelar_nfse(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_cancelar_nfse(certificado, **kwargs) |
|||
return _send(certificado, "CancelarNfse", **kwargs) |
|||
@ -0,0 +1,48 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2016 Danimar Ribeiro, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import signxml |
|||
from lxml import etree |
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx |
|||
from signxml import XMLSigner |
|||
|
|||
|
|||
class Assinatura(object): |
|||
def __init__(self, arquivo, senha): |
|||
self.arquivo = arquivo |
|||
self.senha = senha |
|||
|
|||
def assina_xml(self, xml_element, reference): |
|||
cert, key = extract_cert_and_key_from_pfx(self.arquivo, self.senha) |
|||
|
|||
for element in xml_element.iter("*"): |
|||
if element.text is not None and not element.text.strip(): |
|||
element.text = None |
|||
|
|||
signer = XMLSigner( |
|||
method=signxml.methods.enveloped, |
|||
signature_algorithm=u"rsa-sha1", |
|||
digest_algorithm=u"sha1", |
|||
c14n_algorithm=u"http://www.w3.org/TR/2001/REC-xml-c14n-20010315", |
|||
) |
|||
|
|||
ns = {} |
|||
ns[None] = signer.namespaces["ds"] |
|||
signer.namespaces = ns |
|||
element_to_be_signed = xml_element.getchildren()[0].getchildren()[0] |
|||
|
|||
signed_root = signer.sign( |
|||
element_to_be_signed, key=key.encode(), cert=cert.encode() |
|||
) |
|||
if reference: |
|||
element_signed = xml_element.find(".//*[@Id='%s']" % reference) |
|||
|
|||
signature = signed_root.find( |
|||
".//{http://www.w3.org/2000/09/xmldsig#}Signature" |
|||
) |
|||
|
|||
if element_signed is not None and signature is not None: |
|||
parent = xml_element.getchildren()[0] |
|||
parent.append(signature) |
|||
return etree.tostring(xml_element, encoding=str) |
|||
@ -0,0 +1,15 @@ |
|||
<CancelarNfseEnvio xmlns="http://www.abrasf.org.br/nfse.xsd"> |
|||
<Pedido> |
|||
<InfPedidoCancelamento Id="Cancelamento_NF{{ cancelamento.numero_nfse }}"> |
|||
<IdentificacaoNfse> |
|||
<Numero>{{ cancelamento.numero_nfse }}</Numero> |
|||
<CpfCnpj> |
|||
<Cnpj>{{ cancelamento.cnpj_prestador }}</Cnpj> |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ cancelamento.inscricao_municipal }}</InscricaoMunicipal> |
|||
<CodigoMunicipio>{{ cancelamento.cidade }}</CodigoMunicipio> |
|||
</IdentificacaoNfse> |
|||
<CodigoCancelamento>1</CodigoCancelamento> |
|||
</InfPedidoCancelamento> |
|||
</Pedido> |
|||
</CancelarNfseEnvio> |
|||
@ -0,0 +1,3 @@ |
|||
<GerarNfseEnvio xmlns="http://www.abrasf.org.br/nfse.xsd"> |
|||
{% include 'Rps.xml' %} |
|||
</GerarNfseEnvio> |
|||
@ -0,0 +1,81 @@ |
|||
<Rps> |
|||
<InfDeclaracaoPrestacaoServico> |
|||
<Rps Id="rps:{{ rps.numero }}"> |
|||
<IdentificacaoRps> |
|||
<Numero>{{ rps.numero }}</Numero> |
|||
<Serie>{{ rps.serie }}</Serie> |
|||
<Tipo>{{ rps.tipo_rps }}</Tipo> |
|||
</IdentificacaoRps> |
|||
<DataEmissao>{{ rps.data_emissao }}</DataEmissao> |
|||
<Status>{{ rps.status }}</Status> |
|||
</Rps> |
|||
<Competencia>{{ rps.data_emissao }}</Competencia> |
|||
<Servico> |
|||
<Valores> |
|||
<ValorServicos>{{ rps.valor_servico }}</ValorServicos> |
|||
<ValorDeducoes>{{ rps.valor_deducao }}</ValorDeducoes> |
|||
<ValorPis>{{ rps.valor_pis }}</ValorPis> |
|||
<ValorCofins>{{ rps.valor_cofins }}</ValorCofins> |
|||
<ValorInss>{{ rps.valor_inss }}</ValorInss> |
|||
<ValorIr>{{ rps.valor_ir }}</ValorIr> |
|||
<ValorCsll>{{ rps.valor_csll }}</ValorCsll> |
|||
<OutrasRetencoes>{{ rps.outras_retencoes }}</OutrasRetencoes> |
|||
<ValorIss>{{ rps.valor_iss }}</ValorIss> |
|||
<Aliquota>{{ rps.aliquota_issqn }}</Aliquota> |
|||
<DescontoIncondicionado>{{ rps.desconto_incondicionado }}</DescontoIncondicionado> |
|||
<DescontoCondicionado>{{ rps.desconto_condicionado }}</DescontoCondicionado> |
|||
</Valores> |
|||
<IssRetido>{{ rps.iss_retido }}</IssRetido> |
|||
<ItemListaServico>{{ rps.codigo_servico }}</ItemListaServico> |
|||
<CodigoCnae>{{ rps.cnae_servico }}</CodigoCnae> |
|||
<CodigoTributacaoMunicipio>{{ rps.codigo_tributacao_municipio }}</CodigoTributacaoMunicipio> |
|||
<Discriminacao>{{ rps.descricao }}</Discriminacao> |
|||
<CodigoMunicipio>{{ rps.codigo_municipio }}</CodigoMunicipio> |
|||
<CodigoPais>{{ rps.codigo_pais }}</CodigoPais> |
|||
<ExigibilidadeISS>{{ rps.exigibilidade_iss}}</ExigibilidadeISS> |
|||
</Servico> |
|||
<Prestador> |
|||
<CpfCnpj> |
|||
<Cnpj>{{ rps.prestador.cnpj }}</Cnpj> |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipal> |
|||
</Prestador> |
|||
<Tomador> |
|||
<IdentificacaoTomador> |
|||
<CpfCnpj> |
|||
{% if rps.tomador.cnpj_cpf|length == 14 %} |
|||
<Cnpj>{{ rps.tomador.cnpj_cpf }}</Cnpj> |
|||
{% endif %} |
|||
{% if rps.tomador.cnpj_cpf|length == 11 %} |
|||
<Cpf>{{ rps.tomador.cnpj_cpf }}</Cpf> |
|||
{% endif %} |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ rps.tomador.inscricao_municipal }}</InscricaoMunicipal> |
|||
</IdentificacaoTomador> |
|||
<RazaoSocial>{{ rps.tomador.razao_social }}</RazaoSocial> |
|||
<Endereco> |
|||
<Endereco>{{ rps.tomador.logradouro }}</Endereco> |
|||
<Numero>{{ rps.tomador.numero }}</Numero> |
|||
<Complemento>{{ rps.tomador.complemento }}</Complemento> |
|||
<Bairro>{{ rps.tomador.bairro }}</Bairro> |
|||
<CodigoMunicipio>{{ rps.tomador.cidade }}</CodigoMunicipio> |
|||
<Uf>{{ rps.tomador.uf }}</Uf> |
|||
<CodigoPais>{{ rps.tomador.codigo_pais }}</CodigoPais> |
|||
<Cep>{{ rps.tomador.cep }}</Cep> |
|||
</Endereco> |
|||
<Contato> |
|||
<Telefone>{{ rps.tomador.telefone }}</Telefone> |
|||
<Email>{{ rps.tomador.email }}</Email> |
|||
</Contato> |
|||
</Tomador> |
|||
{% if rps.construcao_civil is defined -%} |
|||
<ContrucaoCivil> |
|||
<CodigoObra>{{ rps.construcao_civil.codigo_obra }}</CodigoObra> |
|||
<Art>{{ rps.construcao_civil.art }}</Art> |
|||
</ContrucaoCivil> |
|||
{% endif %} |
|||
<RegimeEspecialTributacao>{{ rps.regime_tributacao }}</RegimeEspecialTributacao> |
|||
<OptanteSimplesNacional>{{ rps.optante_simples }}</OptanteSimplesNacional> |
|||
<IncentivoFiscal>{{ rps.incentivador_cultural }}</IncentivoFiscal> |
|||
</InfDeclaracaoPrestacaoServico> |
|||
</Rps> |
|||
@ -0,0 +1,116 @@ |
|||
# © 2019 Danimar Ribeiro, Trustcode |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import os |
|||
from OpenSSL import crypto |
|||
from base64 import b64encode |
|||
|
|||
from requests import Session |
|||
from zeep import Client |
|||
from zeep.transports import Transport |
|||
from requests.packages.urllib3 import disable_warnings |
|||
|
|||
from pytrustnfe.xml import render_xml, sanitize_response |
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key |
|||
from pytrustnfe.nfe.assinatura import Assinatura |
|||
from lxml import etree |
|||
|
|||
|
|||
def sign_rps(path, certificado, **kwargs): |
|||
if "nfse" in kwargs: |
|||
lote = "" |
|||
for item in kwargs["nfse"]["lista_rps"]: |
|||
data = {"rps": item} |
|||
xml_rps = render_xml(path, "Rps.xml", True, **data) |
|||
|
|||
signer = Assinatura(certificado.pfx, certificado.password) |
|||
lote += signer.assina_xml( |
|||
xml_rps, f"rps:{item.get('numero')}{item.get('serie')}", getchildren=True |
|||
) |
|||
return lote |
|||
return "" |
|||
|
|||
|
|||
def _render(certificado, method, **kwargs): |
|||
path = os.path.join(os.path.dirname(__file__), "templates") |
|||
parser = etree.XMLParser( |
|||
remove_blank_text=True, remove_comments=True, strip_cdata=False |
|||
) |
|||
|
|||
lote = "" |
|||
referencia = "" |
|||
if method == "RecepcionarLoteRps": |
|||
referencia = "lote" |
|||
lote = sign_rps(path, certificado, **kwargs) |
|||
|
|||
kwargs["lote"] = lote |
|||
xml_send = render_xml(path, "%s.xml" % method, False, **kwargs) |
|||
|
|||
signer = Assinatura(certificado.pfx, certificado.password) |
|||
|
|||
xml_send = signer.assina_xml(etree.fromstring( |
|||
xml_send, parser=parser), f"{referencia}", getchildren=True) |
|||
return xml_send |
|||
|
|||
|
|||
def _send(certificado, method, **kwargs): |
|||
base_url = "" |
|||
if kwargs["ambiente"] == "producao": |
|||
base_url = "https://wsnfsev1.natal.rn.gov.br:8444" |
|||
else: |
|||
base_url = "https://wsnfsev1homologacao.natal.rn.gov.br:8443/axis2/services/NfseWSServiceV1?wsdl" |
|||
|
|||
base_url = "https://wsnfsev1homologacao.natal.rn.gov.br:8443/axis2/services/NfseWSServiceV1?wsdl" |
|||
cert, key = extract_cert_and_key_from_pfx( |
|||
certificado.pfx, certificado.password) |
|||
cert, key = save_cert_key(cert, key) |
|||
|
|||
disable_warnings() |
|||
session = Session() |
|||
session.cert = (cert, key) |
|||
session.verify = False |
|||
transport = Transport(session=session) |
|||
|
|||
client = Client(wsdl=base_url, transport=transport) |
|||
xml_send = {} |
|||
xml_send = { |
|||
"nfseDadosMsg": kwargs["xml"], |
|||
"nfseCabecMsg": """<?xml version="1.0"?> |
|||
<cabecalho xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" versao="1" xmlns="http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd"> |
|||
<versaoDados>1</versaoDados> |
|||
</cabecalho>""", |
|||
} |
|||
|
|||
response = client.service[method](**xml_send) |
|||
response, obj = sanitize_response(response) |
|||
return {"sent_xml": xml_send, "received_xml": response, "object": obj} |
|||
|
|||
|
|||
def xml_recepcionar_lote_rps(certificado, **kwargs): |
|||
return _render(certificado, "RecepcionarLoteRps", **kwargs) |
|||
|
|||
|
|||
def recepcionar_lote_rps(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_recepcionar_lote_rps(certificado, **kwargs) |
|||
return _send(certificado, "RecepcionarLoteRps", **kwargs) |
|||
|
|||
|
|||
def xml_consultar_lote_rps(certificado, **kwargs): |
|||
return _render(certificado, "ConsultarLoteRps", **kwargs) |
|||
|
|||
|
|||
def consultar_lote_rps(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_consultar_lote_rps(certificado, **kwargs) |
|||
return _send(certificado, "ConsultarLoteRps", **kwargs) |
|||
|
|||
|
|||
def xml_cancelar_nfse(certificado, **kwargs): |
|||
return _render(certificado, "cancelarNfse", **kwargs) |
|||
|
|||
|
|||
def cancelar_nfse(certificado, **kwargs): |
|||
if "xml" not in kwargs: |
|||
kwargs["xml"] = xml_cancelar_nfse(certificado, **kwargs) |
|||
return _send(certificado, "cancelarNfse", **kwargs) |
|||
@ -0,0 +1,8 @@ |
|||
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> |
|||
<soap:Body> |
|||
<RecepcionarLoteRpsRequest xmlns="http://nfse.abrasf.org.br"> |
|||
<nfseCabecMsg><![CDATA[{% include 'cabecalho.xml' %}]]></nfseCabecMsg> |
|||
<nfseDadosMsg><![CDATA[{% include 'RecepcionarLoteRps.xml' %}]]></nfseDadosMsg> |
|||
</RecepcionarLoteRpsRequest> |
|||
</soap:Body> |
|||
</soap:Envelope> |
|||
@ -0,0 +1,111 @@ |
|||
<EnviarLoteRpsEnvio xmlns="http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd"> |
|||
<LoteRps Id="lote"> |
|||
<NumeroLote>1</NumeroLote> |
|||
<Cnpj>27596568000505</Cnpj> |
|||
<InscricaoMunicipal>1000047</InscricaoMunicipal> |
|||
<QuantidadeRps>1</QuantidadeRps> |
|||
<ListaRps> |
|||
<Rps> |
|||
<InfRps Id="rps:1ABCDZ"> |
|||
<IdentificacaoRps> |
|||
<Numero>1</Numero> |
|||
<Serie>ABCDH</Serie> |
|||
<Tipo>1</Tipo> |
|||
</IdentificacaoRps> |
|||
<DataEmissao>2010-06-16T21:00:00</DataEmissao> |
|||
<NaturezaOperacao>1</NaturezaOperacao> |
|||
<RegimeEspecialTributacao>6</RegimeEspecialTributacao> |
|||
<OptanteSimplesNacional>1</OptanteSimplesNacional> |
|||
<IncentivadorCultural>2</IncentivadorCultural> |
|||
<Status>1</Status> |
|||
<Servico> |
|||
<Valores> |
|||
<ValorServicos>1000</ValorServicos> |
|||
<ValorPis>10</ValorPis> |
|||
<ValorCofins>10</ValorCofins> |
|||
<ValorInss>10</ValorInss> |
|||
<ValorIr>10</ValorIr> |
|||
<ValorCsll>10</ValorCsll> |
|||
<IssRetido>1</IssRetido> |
|||
<ValorIss>50</ValorIss> |
|||
<OutrasRetencoes>10</OutrasRetencoes> |
|||
<BaseCalculo>1000</BaseCalculo> |
|||
<Aliquota>0.05</Aliquota> |
|||
</Valores> |
|||
<ItemListaServico>11.01</ItemListaServico> |
|||
<CodigoCnae>4520005</CodigoCnae> |
|||
<Discriminacao>Teste.</Discriminacao> |
|||
<CodigoMunicipio>3106200</CodigoMunicipio> |
|||
</Servico> |
|||
<Prestador> |
|||
<Cnpj>27596568000505</Cnpj> |
|||
<InscricaoMunicipal>1000047</InscricaoMunicipal> |
|||
</Prestador> |
|||
<Tomador> |
|||
<IdentificacaoTomador> |
|||
<CpfCnpj> |
|||
<Cnpj>24533572000102</Cnpj> |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>1000039</InscricaoMunicipal> |
|||
</IdentificacaoTomador> |
|||
<RazaoSocial>INSCRICAO DE TESTE SIATU - DAGUA -PAULINOS</RazaoSocial> |
|||
<Endereco> |
|||
<Endereco>DA BAHIA</Endereco> |
|||
<Numero>200</Numero> |
|||
<Complemento>ANDAR 14</Complemento> |
|||
<Bairro>CENTRO</Bairro> |
|||
<CodigoMunicipio>2408102</CodigoMunicipio> |
|||
<Uf>RN</Uf> |
|||
<Cep>30160010</Cep> |
|||
</Endereco> |
|||
<Contato> |
|||
<Email>marcelo@teste.com.br</Email> |
|||
</Contato> |
|||
</Tomador> |
|||
<ConstrucaoCivil> |
|||
<CodigoObra>1234</CodigoObra> |
|||
<Art>1234</Art> |
|||
</ConstrucaoCivil> |
|||
</InfRps> |
|||
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> |
|||
<SignedInfo> |
|||
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments" /> |
|||
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" /> |
|||
<Reference URI="#rps:1ABCDZ"> |
|||
<Transforms> |
|||
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /> |
|||
</Transforms> |
|||
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> |
|||
<DigestValue>mMyQLAm4psxx52kaD8Jlta3ouPM=</DigestValue> |
|||
</Reference> |
|||
</SignedInfo> |
|||
<SignatureValue>qBKfaNz6RbsYUxCOrjGZ9zrdgiGL7QSBxjlhYRlKDNlDERlDWvM8gi28yus8FoUb0v2CTKKIBz0tzfqxgk60rke4YCMkTzdWfpm7ofMIhYC9VHqbWdInC20znOKygJy5hyIx6JBoyXbejnw/0KF+2E1P1ZehqXJWZqY+KPaIGAY=</SignatureValue> |
|||
<KeyInfo> |
|||
<X509Data> |
|||
<X509Certificate>MIIE7DCCA9SgAwIBAgIQZMlLC9ZEsHWsnvJNdMI2yzANBgkqhkiG9w0BAQUFADBqMQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDEsMCoGA1UECxMjU2VjcmV0YXJpYSBkYSBSZWNlaXRhIEZlZGVyYWwgLSBTUkYxGDAWBgNVBAMTD0FDIFBST0RFTUdFIFNSRjAeFw0wNzEwMzEwMDAwMDBaFw0xMDEwMzAyMzU5NTlaMIGQMQswCQYDVQQGEwJCUjETMBEGA1UEChQKSUNQLUJyYXNpbDEqMCgGA1UECxQhU2VjcmV0YXJpYSBkYSBSZWNlaXRhIEZlZGVyYWwtU1JGMRIwEAYDVQQLFAlTUkYgZS1DUEYxLDAqBgNVBAMTI0VER0FSIERPIENBUk1PIEZFUlJFSVJBOjQzMjYwMTUyNjg3MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6M+9XT5KLQN3IH8mAr+S6vxiochY/EwF8EhtNoxPTYl+zr0Dh+eZsRG31bN410nr2OrwncrRorMK8Ngq+j3FnNF0nIMigaaa5NAEfIk3Yy4kuqrTUZBpqUJvCqc3mkF3C3XD0MTmtbVTWCvYIk+qn3t5ShHyMnQcuah5Q0ItSbQIDAQABo4IB6TCCAeUwgZUGA1UdEQSBjTCBiqA9BgVgTAEDAaA0BDIyMTAzMTk2NDQzMjYwMTUyNjg3MDAwMDAwMDAwMDAwMDAwMDBNLTI4ODQwODVTU1BNR6AXBgVgTAEDBqAOBAwwMDAwMDAwMDAwMDCgHgYFYEwBAwWgFQQTMDAwMDAwMDAwMDAwMDAwMDAwMIEQZWRnYXJAcGJoLmdvdi5icjAJBgNVHRMEAjAAMF8GA1UdHwRYMFYwVKBSoFCGTmh0dHA6Ly9pY3AtYnJhc2lsLmNlcnRpc2lnbi5jb20uYnIvcmVwb3NpdG9yaW8vbGNyL0FDUFJPREVNR0VTUkYvTGF0ZXN0Q1JMLmNybDAfBgNVHSMEGDAWgBTdO9vtjZcRRUMBQ020Ev0O7niacDAOBgNVHQ8BAf8EBAMCBeAwVQYDVR0gBE4wTDBKBgZgTAECAxQwQDA+BggrBgEFBQcCARYyaHR0cDovL2ljcC1icmFzaWwuY2VydGlzaWduLmNvbS5ici9yZXBvc2l0b3Jpby9kcGMwHQYDVR0lBBYwFAYIKwYBBQUHAwQGCCsGAQUFBwMCMDgGCCsGAQUFBwEBBCwwKjAoBggrBgEFBQcwAYYcaHR0cDovL29jc3AuY2VydGlzaWduLmNvbS5icjANBgkqhkiG9w0BAQUFAAOCAQEAYFcjZj4lGVEREHBaHtcRletWS6/mvpkxmodwj3ele5yXsxuqSZd7ebHbKewXx7gkyaWFkFAxFanQhls2tYKjg6haqt2b0AO1FsitVIHkMcxRwkU9G+1ec8yfdxymra2VdXazkxuvqKABgxkqKnaFdHjje7cjWDgwparymH64mTlHkSQz59GutJW0xfwBHcMGx0/9/iIug6pfMQivWf0NMVpFNzxO5ZNPEuOeBhVDxQr4+KB+4B9xDai/3J6f42UNbSy+z3xuB0K8/7V7BsFUYOYFSNnBrXhvbvXtZOtteX65V0r1+RJJX5OK+PAPhZ57T1LEmHMggdo5kli3Nr1KFQ==</X509Certificate> |
|||
</X509Data> |
|||
</KeyInfo> |
|||
</Signature> |
|||
</Rps> |
|||
</ListaRps> |
|||
</LoteRps> |
|||
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#" Id="Ass_lote"> |
|||
<SignedInfo> |
|||
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments" /> |
|||
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" /> |
|||
<Reference URI="#lote"> |
|||
<Transforms> |
|||
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /> |
|||
</Transforms> |
|||
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> |
|||
<DigestValue>n42EhtzDSnZ071g+44ZMBCc74UQ=</DigestValue> |
|||
</Reference> |
|||
</SignedInfo> |
|||
<SignatureValue>pQyeXnJ2S9KyUJ1BE3k3PZuDpk7WkD2nMPLoELSLJeNBe9TwmLhImsIUS4inAUreuTsjfrs2BUmChN6jPA0/1cSR0GbblLsHFN+IwPE2dnPN/u0vIOmsan4MuW1OnlH6KexmDHRj/uFwjoXfSJ0JJE1u9bYdbsp5LGlFuc//CCQ=</SignatureValue> |
|||
<KeyInfo> |
|||
<X509Data> |
|||
<X509Certificate>MIIE7DCCA9SgAwIBAgIQZMlLC9ZEsHWsnvJNdMI2yzANBgkqhkiG9w0BAQUFADBqMQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDEsMCoGA1UECxMjU2VjcmV0YXJpYSBkYSBSZWNlaXRhIEZlZGVyYWwgLSBTUkYxGDAWBgNVBAMTD0FDIFBST0RFTUdFIFNSRjAeFw0wNzEwMzEwMDAwMDBaFw0xMDEwMzAyMzU5NTlaMIGQMQswCQYDVQQGEwJCUjETMBEGA1UEChQKSUNQLUJyYXNpbDEqMCgGA1UECxQhU2VjcmV0YXJpYSBkYSBSZWNlaXRhIEZlZGVyYWwtU1JGMRIwEAYDVQQLFAlTUkYgZS1DUEYxLDAqBgNVBAMTI0VER0FSIERPIENBUk1PIEZFUlJFSVJBOjQzMjYwMTUyNjg3MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6M+9XT5KLQN3IH8mAr+S6vxiochY/EwF8EhtNoxPTYl+zr0Dh+eZsRG31bN410nr2OrwncrRorMK8Ngq+j3FnNF0nIMigaaa5NAEfIk3Yy4kuqrTUZBpqUJvCqc3mkF3C3XD0MTmtbVTWCvYIk+qn3t5ShHyMnQcuah5Q0ItSbQIDAQABo4IB6TCCAeUwgZUGA1UdEQSBjTCBiqA9BgVgTAEDAaA0BDIyMTAzMTk2NDQzMjYwMTUyNjg3MDAwMDAwMDAwMDAwMDAwMDBNLTI4ODQwODVTU1BNR6AXBgVgTAEDBqAOBAwwMDAwMDAwMDAwMDCgHgYFYEwBAwWgFQQTMDAwMDAwMDAwMDAwMDAwMDAwMIEQZWRnYXJAcGJoLmdvdi5icjAJBgNVHRMEAjAAMF8GA1UdHwRYMFYwVKBSoFCGTmh0dHA6Ly9pY3AtYnJhc2lsLmNlcnRpc2lnbi5jb20uYnIvcmVwb3NpdG9yaW8vbGNyL0FDUFJPREVNR0VTUkYvTGF0ZXN0Q1JMLmNybDAfBgNVHSMEGDAWgBTdO9vtjZcRRUMBQ020Ev0O7niacDAOBgNVHQ8BAf8EBAMCBeAwVQYDVR0gBE4wTDBKBgZgTAECAxQwQDA+BggrBgEFBQcCARYyaHR0cDovL2ljcC1icmFzaWwuY2VydGlzaWduLmNvbS5ici9yZXBvc2l0b3Jpby9kcGMwHQYDVR0lBBYwFAYIKwYBBQUHAwQGCCsGAQUFBwMCMDgGCCsGAQUFBwEBBCwwKjAoBggrBgEFBQcwAYYcaHR0cDovL29jc3AuY2VydGlzaWduLmNvbS5icjANBgkqhkiG9w0BAQUFAAOCAQEAYFcjZj4lGVEREHBaHtcRletWS6/mvpkxmodwj3ele5yXsxuqSZd7ebHbKewXx7gkyaWFkFAxFanQhls2tYKjg6haqt2b0AO1FsitVIHkMcxRwkU9G+1ec8yfdxymra2VdXazkxuvqKABgxkqKnaFdHjje7cjWDgwparymH64mTlHkSQz59GutJW0xfwBHcMGx0/9/iIug6pfMQivWf0NMVpFNzxO5ZNPEuOeBhVDxQr4+KB+4B9xDai/3J6f42UNbSy+z3xuB0K8/7V7BsFUYOYFSNnBrXhvbvXtZOtteX65V0r1+RJJX5OK+PAPhZ57T1LEmHMggdo5kli3Nr1KFQ==</X509Certificate> |
|||
</X509Data> |
|||
</KeyInfo> |
|||
</Signature> |
|||
</EnviarLoteRpsEnvio> |
|||
@ -0,0 +1,112 @@ |
|||
<Rps> |
|||
<InfRps Id="rps:{{ rps.numero }}{{ rps.serie }}"> |
|||
<IdentificacaoRps> |
|||
<Numero>{{ rps.numero }}</Numero> |
|||
<Serie>{{ rps.serie }}</Serie> |
|||
<Tipo>{{ rps.tipo_rps }}</Tipo> |
|||
</IdentificacaoRps> |
|||
<DataEmissao>{{ rps.data_emissao }}</DataEmissao> |
|||
<NaturezaOperacao>{{ rps.natureza_operacao }}</NaturezaOperacao> |
|||
<RegimeEspecialTributacao>{{ rps.regime_tributacao }}</RegimeEspecialTributacao> |
|||
<OptanteSimplesNacional>{{ rps.optante_simples }}</OptanteSimplesNacional> |
|||
<IncentivadorCultural>{{ rps.incentivador_cultural }}</IncentivadorCultural> |
|||
<Status>{{ rps.status }}</Status> |
|||
<Servico> |
|||
<Valores> |
|||
<ValorServicos>{{ rps.servico.valor_servico }}</ValorServicos> |
|||
<ValorPis>{{ rps.servico.pis }}</ValorPis> |
|||
<ValorCofins>{{ rps.servico.cofins }}</ValorCofins> |
|||
<ValorInss>{{ rps.servico.inss }}</ValorInss> |
|||
<ValorIr>{{ rps.servico.ir }}</ValorIr> |
|||
<ValorCsll>{{ rps.servico.csll }}</ValorCsll> |
|||
<IssRetido>{{ rps.servico.iss_retido }}</IssRetido> |
|||
<ValorIss>{{ rps.servico.iss }}</ValorIss> |
|||
<OutrasRetencoes>{{ rps.servico.retencoes }}</OutrasRetencoes> |
|||
<BaseCalculo>{{ rps.servico.base_calculo }}</BaseCalculo> |
|||
<Aliquota>{{ rps.servico.aliquota }}</Aliquota> |
|||
</Valores> |
|||
<ItemListaServico>{{ rps.servico.codigo_servico }}</ItemListaServico> |
|||
<CodigoCnae>{{ rps.servico.cnae_servico }}</CodigoCnae> |
|||
<Discriminacao>{{ rps.servico.discriminacao }}</Discriminacao> |
|||
<CodigoMunicipio>{{ rps.servico.codigo_municipio }}</CodigoMunicipio> |
|||
</Servico> |
|||
<Prestador> |
|||
<Cnpj>{{ rps.prestador.cnpj }}</Cnpj> |
|||
<InscricaoMunicipal>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipal> |
|||
<RazaoSocial>{{ rps.prestador.razaosocial }}</RazaoSocial> |
|||
<NomeFantasia>{{ rps.prestador.fantasia }}</NomeFantasia> |
|||
<Endereco> |
|||
<Endereco>{{ rps.prestador.endereco }}</Endereco> |
|||
<Numero>{{ rps.prestador.numero }}</Numero> |
|||
<Complemento>{{ rps.prestador.complemento }}</Complemento> |
|||
<Bairro>{{ rps.prestador.bairro }}</Bairro> |
|||
<CodigoMunicipio>{{ rps.prestador.codigomunicipal }}</CodigoMunicipio> |
|||
<Uf>{{ rps.prestador.uf }}</Uf> |
|||
<Cep>{{ rps.prestador.cep }}</Cep> |
|||
</Endereco> |
|||
<Contato> |
|||
{% if rps.prestador.telefone is defined -%} |
|||
<Telefone>{{ rps.prestador.telefone }}</Telefone> |
|||
{% endif %} |
|||
{% if rps.prestador.email is defined -%} |
|||
<Email>{{ rps.prestador.email }}</Email> |
|||
{% endif %} |
|||
</Contato> |
|||
</Prestador> |
|||
<Tomador> |
|||
<IdentificacaoTomador> |
|||
<CpfCnpj> |
|||
{% if rps.tomador.cpf_cnpj|length == 14 %} |
|||
<Cnpj>{{ rps.tomador.cpf_cnpj }}</Cnpj> |
|||
{% endif %} |
|||
{% if rps.tomador.cpf_cnpj|length == 11 %} |
|||
<Cpf>{{ rps.tomador.cpf_cnpj }}</Cpf> |
|||
{% endif %} |
|||
</CpfCnpj> |
|||
{% if rps.tomador.inscricao_municipal is defined -%} |
|||
<InscricaoMunicipal>{{ rps.tomador.inscricao_municipal }}</InscricaoMunicipal> |
|||
{% endif %} |
|||
</IdentificacaoTomador> |
|||
<RazaoSocial>{{ rps.tomador.razao_social }}</RazaoSocial> |
|||
<Endereco> |
|||
<Endereco>{{ rps.tomador.endereco }}</Endereco> |
|||
<Numero>{{ rps.tomador.numero }}</Numero> |
|||
<Complemento>{{ rps.tomador.complemento }}</Complemento> |
|||
<Bairro>{{ rps.tomador.bairro }}</Bairro> |
|||
<CodigoMunicipio>{{ rps.tomador.codigo_municipio }}</CodigoMunicipio> |
|||
<Uf>{{ rps.tomador.uf }}</Uf> |
|||
<Cep>{{ rps.tomador.cep }}</Cep> |
|||
</Endereco> |
|||
<Contato> |
|||
{% if rps.tomador.telefone is defined -%} |
|||
<Telefone>{{ rps.tomador.telefone }}</Telefone> |
|||
{% endif %} |
|||
{% if rps.tomador.email is defined -%} |
|||
<Email>{{ rps.tomador.email }}</Email> |
|||
{% endif %} |
|||
</Contato> |
|||
{% if rps.tomador.orgao_gerador is defined -%} |
|||
<OrgaoGerador> |
|||
<CodigoMunicipio>{{ rps.tomador.orgao_gerador.codigo_municipio }}</CodigoMunicipio> |
|||
<Uf>{{ rps.tomador.orgao_gerador.uf }}</Uf> |
|||
</OrgaoGerador> |
|||
{% endif %} |
|||
</Tomador> |
|||
{% if rps.intermediario is defined -%} |
|||
<IntermediarioServico> |
|||
<RazaoSocial>{{ rps.intermediario.razao_social }}</RazaoSocial> |
|||
<CpfCnpj> |
|||
<Cnpj>{{ rps.intermediario.cnpj }}</Cnpj> |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ rps.intermediario.inscricao_municipal }}</InscricaoMunicipal> |
|||
</IntermediarioServico> |
|||
{% endif %} |
|||
{% if rps.construcao_civil is defined -%} |
|||
<ContrucaoCivil> |
|||
<CodigoObra>{{ rps.construcao_civil.codigo_obra }}</CodigoObra> |
|||
<Art>{{ rps.construcao_civil.art }}</Art> |
|||
</ContrucaoCivil> |
|||
{% endif %} |
|||
</InfRps> |
|||
<Signature Id="placeholder"></Signature> |
|||
</Rps> |
|||
@ -0,0 +1,3 @@ |
|||
<cabecalho versao="2.01" xmlns="http://www.abrasf.org.br/nfse.xsd"> |
|||
<versaoDados>2.01</versaoDados> |
|||
</cabecalho> |
|||
@ -0,0 +1,15 @@ |
|||
<CancelarNfseEnvio xmlns="http://nfse.abrasf.org.br"> |
|||
<Pedido> |
|||
<InfPedidoCancelamento Id="1"> |
|||
<IdentificacaoNfse> |
|||
<Numero>{{ cancelamento.numero_nfse }}</Numero> |
|||
<CpfCnpj> |
|||
<Cnpj>{{ cancelamento.cnpj_prestador }}</Cnpj> |
|||
</CpfCnpj> |
|||
<InscricaoMunicipal>{{ cancelamento.inscricao_municipal }}</InscricaoMunicipal> |
|||
<CodigoMunicipio>{{ cancelamento.cidade }}</CodigoMunicipio> |
|||
</IdentificacaoNfse> |
|||
<CodigoCancelamento>{{ cancelamento.codigo_cancelamento }}</CodigoCancelamento> |
|||
</InfPedidoCancelamento> |
|||
</Pedido> |
|||
</CancelarNfseEnvio> |
|||
@ -0,0 +1,7 @@ |
|||
<ConsultarLoteRpsEnvio xmlns="http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd"> |
|||
<Prestador> |
|||
<Cnpj>{{ consulta.cnpj_prestador }}</Cnpj> |
|||
<InscricaoMunicipal>{{ consulta.inscricao_municipal }}</InscricaoMunicipal> |
|||
</Prestador> |
|||
<Protocolo>{{ consulta.protocolo }}</Protocolo> |
|||
</ConsultarLoteRpsEnvio> |
|||
@ -0,0 +1,11 @@ |
|||
<EnviarLoteRpsEnvio xmlns="http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd"> |
|||
<LoteRps Id="lote"> |
|||
<NumeroLote>{{ nfse.numero_lote }}</NumeroLote> |
|||
<Cnpj>{{ nfse.cnpj_prestador }}</Cnpj> |
|||
<InscricaoMunicipal>{{ nfse.inscricao_municipal }}</InscricaoMunicipal> |
|||
<QuantidadeRps>{{ nfse.lista_rps|length }}</QuantidadeRps> |
|||
<ListaRps> |
|||
{{lote}} |
|||
</ListaRps> |
|||
</LoteRps> |
|||
</EnviarLoteRpsEnvio> |
|||
@ -1 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?><RetornoEnvioLoteRPS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.prefeitura.sp.gov.br/nfe"><Cabecalho Versao="1" xmlns=""><Sucesso>true</Sucesso><InformacoesLote><NumeroLote>2654364</NumeroLote><InscricaoPrestador>51212</InscricaoPrestador><CPFCNPJRemetente><CNPJ>21332900163</CNPJ></CPFCNPJRemetente><DataEnvioLote>2016-08-29T10:52:15</DataEnvioLote><QtdNotasProcessadas>1</QtdNotasProcessadas><TempoProcessamento>0</TempoProcessamento><ValorTotalServicos>1.35</ValorTotalServicos></InformacoesLote></Cabecalho><ChaveNFeRPS xmlns=""><ChaveNFe><InscricaoPrestador>52382</InscricaoPrestador><NumeroNFe>446</NumeroNFe><CodigoVerificacao>APR9MJR</CodigoVerificacao></ChaveNFe><ChaveRPS><InscricaoPrestador>51282</InscricaoPrestador><SerieRPS>1</SerieRPS><NumeroRPS>6</NumeroRPS></ChaveRPS></ChaveNFeRPS></RetornoEnvioLoteRPS> |
|||
@ -1,34 +0,0 @@ |
|||
# -*- coding: utf-8-*- |
|||
# © 2016 Alessandro Fernandes Martini |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import unittest |
|||
# from lxml import etree |
|||
from pytrustnfe.nfe import _add_qrCode |
|||
|
|||
|
|||
class TestAddQRCode(unittest.TestCase): |
|||
def setUp(self): |
|||
self.xml_sem_qrcode = open('pytrustnfe/test/xml_sem_qrcode.xml', 'r') |
|||
self.xml_com_qrcode = open('pytrustnfe/test/xml_com_qrcode.xml', 'r') |
|||
dhEmi = '2016-11-09T16:03:25-00:00' |
|||
chave_nfe = u'NFe35161121332917000163650010000000011448875034' |
|||
ambiente = 2 |
|||
valor_total = '324.00' |
|||
icms_total = '61.56' |
|||
cid_token = '000001' |
|||
csc = '123456789' |
|||
estado = '35' |
|||
total = {'vNF': valor_total, 'vICMS': icms_total} |
|||
infnfe = {'ide': {'dhEmi': dhEmi}, 'Id': chave_nfe, 'total': total, |
|||
'codigo_seguranca': {'cid_token': cid_token, 'csc': csc}} |
|||
infnfe = {'infNFe': infnfe} |
|||
self.kwargs = {} |
|||
self.kwargs['ambiente'] = ambiente |
|||
self.kwargs['estado'] = estado |
|||
self.kwargs['NFes'] = [infnfe] |
|||
|
|||
def test_add_qrCode(self): |
|||
xml_init = self.xml_sem_qrcode.read() |
|||
xml_end = _add_qrCode(xml_init, **self.kwargs) |
|||
self.assertEqual(xml_end, self.xml_com_qrcode.read()) |
|||
@ -1,57 +0,0 @@ |
|||
# coding=utf-8 |
|||
''' |
|||
Created on Jun 14, 2015 |
|||
|
|||
@author: danimar |
|||
''' |
|||
import os |
|||
import os.path |
|||
import unittest |
|||
from lxml import etree |
|||
from pytrustnfe.nfe.assinatura import Assinatura |
|||
|
|||
|
|||
XML_ASSINAR = '<?xml version="1.0" encoding="UTF-8"?>' \ |
|||
'<Envelope xmlns="urn:envelope">' \ |
|||
' <Data Id="NFe43150602261542000143550010000000761792265342">'\ |
|||
' Hello, World!' \ |
|||
' </Data>' \ |
|||
'</Envelope>' |
|||
|
|||
|
|||
XML_ERRADO = '<?xml version="1.0" encoding="UTF-8"?>' \ |
|||
'<Envelope xmlns="urn:envelope">' \ |
|||
' <Data Id="NFe">' \ |
|||
' Hello, World!' \ |
|||
' </Data>' \ |
|||
'</Envelope>' |
|||
|
|||
|
|||
class test_assinatura(unittest.TestCase): |
|||
|
|||
caminho = os.path.dirname(__file__) |
|||
|
|||
def test_assinar_xml_senha_invalida(self): |
|||
pfx = open(os.path.join(self.caminho, 'teste.pfx')).read() |
|||
signer = Assinatura(pfx, '123') |
|||
self.assertRaises(Exception, signer.assina_xml, signer, |
|||
etree.fromstring(XML_ASSINAR), |
|||
'NFe43150602261542000143550010000000761792265342') |
|||
|
|||
def test_assinar_xml_invalido(self): |
|||
pfx = open(os.path.join(self.caminho, 'teste.pfx')).read() |
|||
signer = Assinatura(pfx, '123456') |
|||
self.assertRaises(Exception, signer.assina_xml, signer, |
|||
etree.fromstring(XML_ERRADO), |
|||
'NFe43150602261542000143550010000000761792265342') |
|||
|
|||
def test_assinar_xml_valido(self): |
|||
pfx = open(os.path.join(self.caminho, 'teste.pfx')).read() |
|||
signer = Assinatura(pfx, '123456') |
|||
xml = signer.assina_xml( |
|||
etree.fromstring(XML_ASSINAR), |
|||
'NFe43150602261542000143550010000000761792265342') |
|||
xml_assinado = open(os.path.join(self.caminho, |
|||
'xml_valido_assinado.xml'), |
|||
'r').read() |
|||
self.assertEqual(xml_assinado, xml, 'Xml assinado é inválido') |
|||
@ -1,82 +0,0 @@ |
|||
# coding=utf-8 |
|||
''' |
|||
Created on Jun 14, 2015 |
|||
|
|||
@author: danimar |
|||
''' |
|||
import unittest |
|||
import os |
|||
import os.path |
|||
from pytrustnfe.certificado import Certificado |
|||
from pytrustnfe.certificado import save_cert_key |
|||
from pytrustnfe.certificado import extract_cert_and_key_from_pfx |
|||
|
|||
CHAVE = '-----BEGIN PRIVATE KEY-----\n' \ |
|||
'MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJONRp6l1y2ojgv8\n' \ |
|||
'tP3AOLW0vjWQqiPseBLM7YAxbzz5R7LYlWHC0ZJ4uIvd4Cvc6AuoNJoeuhzFcwHx\n' \ |
|||
'PL0TcFuW+5up1ktUohwaJ+/zKrMODCKt0gvif302yqasMnwLh9mGZQIkLkHPOX8p\n' \ |
|||
'ZQDC4dlqwOyYDi0f+bRd5C7aWx3RAgMBAAECgYADqASP+dwTLZIXifOSNikxl4D/\n' \ |
|||
'Is6UhU+UZ6+a9Z6kDClSrTtGaOV4k7U/AgiEDb1STKDBEPHbtKjc63Vt2gV2teem\n' \ |
|||
'ohU0Giv+gD42uuwy2DM31OfYrpR46mzOK9JrpQc78b36ealL3AWJ1gyBbbcOWbAb\n' \ |
|||
'KmP742V7pcD07EEp4QJBAM/e7M8VdLgOyaQzH9KHekU6fJlI4vy1UwgRUwx3/1W6\n' \ |
|||
'zlBYo1qXfc7NSVG8ZaSrJwW4rPn393u31CpXv+oc/OMCQQC1txS6nxM9+p/641HX\n' \ |
|||
'CHXiWJRn0Wv7rT1FyF2dHO+OQOkCCnHCsGDMf3bacTNb7iyaPbXEDac8od5uF/3h\n' \ |
|||
'aUy7AkBDPGoAeYItXqseL2Mlp6iG5+oRcp/o+YWH4IKqT84JHslI98KutL1+vKvw\n'\ |
|||
'gi2mW63djeR1Xh1wqP85SvTKduHdAkAIJLlIF8Lr/yRWQQO06EsoJqIX+Pmm4L+j\n'\ |
|||
'NfSECvztWhlXHxK0D+V2pKu15GbR0t2q1+Micx4wiGyIcIjPJkHrAkAvlbXGFcGT\n'\ |
|||
'pk9bQ8nl7EYqlvVn1TejzTLfBhBYOse/xT/NI4Kwjkan9R+EJ1cOc9EE8gm1W3jv\n'\ |
|||
'fMw/Bh2wC5kj\n'\ |
|||
'-----END PRIVATE KEY-----\n' |
|||
|
|||
CERTIFICADO = '-----BEGIN CERTIFICATE-----\n'\ |
|||
'MIICMTCCAZqgAwIBAgIQfYOsIEVuAJ1FwwcTrY0t1DANBgkqhkiG9w0BAQUFADBX\n'\ |
|||
'MVUwUwYDVQQDHkwAewA1ADkARgAxAEUANAA2ADEALQBEAEQARQA1AC0ANABEADIA\n'\ |
|||
'RgAtAEEAMAAxAEEALQA4ADMAMwAyADIAQQA5AEUAQgA4ADMAOAB9MB4XDTE1MDYx\n'\ |
|||
'NTA1NDc1N1oXDTE2MDYxNDExNDc1N1owVzFVMFMGA1UEAx5MAHsANQA5AEYAMQBF\n'\ |
|||
'ADQANgAxAC0ARABEAEUANQAtADQARAAyAEYALQBBADAAMQBBAC0AOAAzADMAMgAy\n'\ |
|||
'AEEAOQBFAEIAOAAzADgAfTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAk41G\n'\ |
|||
'nqXXLaiOC/y0/cA4tbS+NZCqI+x4EsztgDFvPPlHstiVYcLRkni4i93gK9zoC6g0\n'\ |
|||
'mh66HMVzAfE8vRNwW5b7m6nWS1SiHBon7/Mqsw4MIq3SC+J/fTbKpqwyfAuH2YZl\n'\ |
|||
'AiQuQc85fyllAMLh2WrA7JgOLR/5tF3kLtpbHdECAwEAATANBgkqhkiG9w0BAQUF\n'\ |
|||
'AAOBgQArdh+RyT6VxKGsXk1zhHsgwXfToe6GpTF4W8PHI1+T0WIsNForDhvst6nm\n'\ |
|||
'QtgAhuZM9rxpOJuNKc+pM29EixpAiZZiRMCSWEItNyEVdUIi+YnKBcAHd88TwO86\n'\ |
|||
'd126MWQ2O8cu5W1VoDp7hYBYKOnLbYi11/StO+0rzK+oPYAvIw==\n'\ |
|||
'-----END CERTIFICATE-----\n' |
|||
|
|||
|
|||
class test_assinatura(unittest.TestCase): |
|||
|
|||
caminho = os.path.dirname(__file__) |
|||
|
|||
def test_preparar_pfx(self): |
|||
dir_pfx = open(os.path.join(self.caminho, 'teste.pfx'), 'r').read() |
|||
cert, key = extract_cert_and_key_from_pfx(dir_pfx, '123456') |
|||
self.assertEqual(key, CHAVE, 'Chave gerada inválida') |
|||
self.assertEqual(cert, CERTIFICADO, 'Certificado inválido') |
|||
|
|||
def test_save_pfx(self): |
|||
pfx_source = open(os.path.join(self.caminho, 'teste.pfx'), 'r').read() |
|||
pfx = Certificado(pfx_source, '123') |
|||
path = pfx.save_pfx() |
|||
saved = open(path, 'r').read() |
|||
self.assertEqual(pfx_source, saved, |
|||
'Arquivo pfx salvo não bate com arquivo lido') |
|||
|
|||
def test_save_cert_and_key(self): |
|||
dir_pfx = open(os.path.join(self.caminho, 'teste.pfx'), 'r').read() |
|||
cert, key = extract_cert_and_key_from_pfx(dir_pfx, '123456') |
|||
cert_path, key_path = save_cert_key(cert, key) |
|||
cert_saved = open(cert_path, 'r').read() |
|||
key_saved = open(key_path, 'r').read() |
|||
self.assertEqual( |
|||
cert, cert_saved, 'Certificado não corresponde ao original') |
|||
self.assertEqual(key, key_saved, 'Chave não corresponde ao original') |
|||
|
|||
def test_pfx_nao_existe(self): |
|||
self.assertRaises(Exception, extract_cert_and_key_from_pfx, |
|||
'file.pfx', '123456') |
|||
|
|||
def test_pfx_senha_invalida(self): |
|||
dir_pfx = os.path.join(self.caminho, 'teste.pfx') |
|||
self.assertRaises(Exception, extract_cert_and_key_from_pfx, |
|||
dir_pfx, '123') |
|||
@ -1,20 +0,0 @@ |
|||
# coding=utf-8 |
|||
''' |
|||
Created on Jun 16, 2015 |
|||
|
|||
@author: danimar |
|||
''' |
|||
import unittest |
|||
import os.path |
|||
|
|||
|
|||
XML_RETORNO = '<retEnviNFe><cStat>103</cStat>' \ |
|||
'<cUF>42</cUF></retEnviNFe>' |
|||
|
|||
|
|||
class test_comunicacao(unittest.TestCase): |
|||
|
|||
caminho = os.path.dirname(__file__) |
|||
|
|||
def test_envio_nfe(self): |
|||
pass |
|||
@ -1,19 +0,0 @@ |
|||
# coding=utf-8 |
|||
|
|||
import mock |
|||
import os.path |
|||
import unittest |
|||
from pytrustnfe.certificado import Certificado |
|||
from pytrustnfe.nfe import consulta_cadastro |
|||
|
|||
|
|||
class test_consulta_cadastro(unittest.TestCase): |
|||
|
|||
caminho = os.path.dirname(__file__) |
|||
|
|||
def test_conta_de_cadastro(self): |
|||
pfx_source = open(os.path.join(self.caminho, 'teste.pfx'), 'r').read() |
|||
pfx = Certificado(pfx_source, '123456') |
|||
|
|||
obj = {'cnpj': '12345678901234', 'estado': '42'} |
|||
consulta_cadastro(pfx, obj=obj, ambiente=1, estado='42') |
|||
@ -1,143 +0,0 @@ |
|||
# coding=utf-8 |
|||
|
|||
import mock |
|||
import os.path |
|||
import unittest |
|||
from pytrustnfe.certificado import Certificado |
|||
from pytrustnfe.nfse.paulistana import envio_lote_rps |
|||
from pytrustnfe.nfse.paulistana import cancelamento_nfe |
|||
from pytrustnfe.nfse.assinatura import Assinatura |
|||
from pytrustnfe.nfse.paulistana import sign_tag |
|||
|
|||
|
|||
class test_nfse_paulistana(unittest.TestCase): |
|||
|
|||
caminho = os.path.dirname(__file__) |
|||
|
|||
def _get_nfse(self): |
|||
rps = [ |
|||
{ |
|||
'assinatura': '123', |
|||
'serie': '1', |
|||
'numero': '1', |
|||
'data_emissao': '2016-08-29', |
|||
'codigo_atividade': '07498', |
|||
'total_servicos': '2.00', |
|||
'total_deducoes': '3.00', |
|||
'prestador': { |
|||
'inscricao_municipal': '123456' |
|||
}, |
|||
'tomador': { |
|||
'tipo_cpfcnpj': '1', |
|||
'cpf_cnpj': '12345678923256', |
|||
'inscricao_municipal': '123456', |
|||
'razao_social': 'Trustcode', |
|||
'tipo_logradouro': '1', |
|||
'logradouro': 'Vinicius de Moraes, 42', |
|||
'numero': '42', |
|||
'bairro': 'Corrego', |
|||
'cidade': 'Floripa', |
|||
'uf': 'SC', |
|||
'cep': '88037240', |
|||
}, |
|||
'codigo_atividade': '07498', |
|||
'aliquota_atividade': '5.00', |
|||
'descricao': 'Venda de servico' |
|||
} |
|||
] |
|||
nfse = { |
|||
'cpf_cnpj': '12345678901234', |
|||
'data_inicio': '2016-08-29', |
|||
'data_fim': '2016-08-29', |
|||
'lista_rps': rps |
|||
} |
|||
return nfse |
|||
|
|||
def test_envio_nfse(self): |
|||
pfx_source = open(os.path.join(self.caminho, 'teste.pfx'), 'r').read() |
|||
pfx = Certificado(pfx_source, '123456') |
|||
|
|||
nfse = self._get_nfse() |
|||
path = os.path.join(os.path.dirname(__file__), 'XMLs') |
|||
xml_return = open(os.path.join( |
|||
path, 'paulistana_resultado.xml'), 'r').read() |
|||
|
|||
with mock.patch('pytrustnfe.nfse.paulistana.get_authenticated_client') as client: |
|||
retorno = mock.MagicMock() |
|||
client.return_value = retorno |
|||
retorno.service.EnvioLoteRPS.return_value = xml_return |
|||
|
|||
retorno = envio_lote_rps(pfx, nfse=nfse) |
|||
|
|||
self.assertEqual(retorno['received_xml'], xml_return) |
|||
self.assertEqual(retorno['object'].Cabecalho.Sucesso, True) |
|||
self.assertEqual( |
|||
retorno['object'].ChaveNFeRPS.ChaveNFe.NumeroNFe, 446) |
|||
self.assertEqual( |
|||
retorno['object'].ChaveNFeRPS.ChaveRPS.NumeroRPS, 6) |
|||
|
|||
def test_nfse_signature(self): |
|||
pfx_source = open(os.path.join(self.caminho, 'teste.pfx'), 'r').read() |
|||
pfx = Certificado(pfx_source, '123456') |
|||
|
|||
nfse = self._get_nfse() |
|||
path = os.path.join(os.path.dirname(__file__), 'XMLs') |
|||
xml_sent = open(os.path.join( |
|||
path, 'paulistana_signature.xml'), 'r').read() |
|||
|
|||
with mock.patch('pytrustnfe.nfse.paulistana.get_authenticated_client') as client: |
|||
retorno = mock.MagicMock() |
|||
client.return_value = retorno |
|||
retorno.service.EnvioLoteRPS.return_value = '<xml></xml>' |
|||
|
|||
retorno = envio_lote_rps(pfx, nfse=nfse) |
|||
self.assertEqual(retorno['sent_xml'], xml_sent) |
|||
|
|||
def _get_cancelamento(self): |
|||
return { |
|||
'cnpj_remetente': '123', |
|||
'assinatura': 'assinatura', |
|||
'numero_nfse': '456', |
|||
'inscricao_municipal': '654', |
|||
'codigo_verificacao': '789', |
|||
} |
|||
|
|||
def test_cancelamento_nfse_ok(self): |
|||
pfx_source = open(os.path.join(self.caminho, 'teste.pfx'), 'r').read() |
|||
pfx = Certificado(pfx_source, '123456') |
|||
cancelamento = self._get_cancelamento() |
|||
|
|||
path = os.path.join(os.path.dirname(__file__), 'XMLs') |
|||
xml_return = open(os.path.join( |
|||
path, 'paulistana_canc_ok.xml'), 'r').read() |
|||
|
|||
with mock.patch('pytrustnfe.nfse.paulistana.get_authenticated_client') as client: |
|||
retorno = mock.MagicMock() |
|||
client.return_value = retorno |
|||
retorno.service.CancelamentoNFe.return_value = xml_return |
|||
|
|||
retorno = cancelamento_nfe(pfx, cancelamento=cancelamento) |
|||
|
|||
self.assertEqual(retorno['received_xml'], xml_return) |
|||
self.assertEqual(retorno['object'].Cabecalho.Sucesso, True) |
|||
|
|||
def test_cancelamento_nfse_com_erro(self): |
|||
pfx_source = open(os.path.join(self.caminho, 'teste.pfx'), 'r').read() |
|||
pfx = Certificado(pfx_source, '123456') |
|||
cancelamento = self._get_cancelamento() |
|||
|
|||
path = os.path.join(os.path.dirname(__file__), 'XMLs') |
|||
xml_return = open(os.path.join( |
|||
path, 'paulistana_canc_errado.xml'), 'r').read() |
|||
|
|||
with mock.patch('pytrustnfe.nfse.paulistana.get_authenticated_client') as client: |
|||
retorno = mock.MagicMock() |
|||
client.return_value = retorno |
|||
retorno.service.CancelamentoNFe.return_value = xml_return |
|||
|
|||
retorno = cancelamento_nfe(pfx, cancelamento=cancelamento) |
|||
|
|||
self.assertEqual(retorno['received_xml'], xml_return) |
|||
self.assertEqual(retorno['object'].Cabecalho.Sucesso, False) |
|||
self.assertEqual( |
|||
retorno['object'].Erro.ChaveNFe.NumeroNFe, 446) |
|||
@ -1,48 +0,0 @@ |
|||
# coding=utf-8 |
|||
''' |
|||
Created on Jun 14, 2015 |
|||
|
|||
@author: danimar |
|||
''' |
|||
import unittest |
|||
from pytrustnfe.Servidores import localizar_url, localizar_qrcode |
|||
|
|||
url_ba = 'https://nfe.sefaz.ba.gov.br/webservices/NfeAutorizacao/NfeAutoriza\ |
|||
cao.asmx' |
|||
|
|||
url_sp = 'https://nfe.fazenda.sp.gov.br/ws/nfeautorizacao.asmx' |
|||
|
|||
url_qrcode_homologacao_sp = 'https://homologacao.nfce.fazenda.sp.gov.br/NFCEConsultaPublica/Paginas/ConstultaQRCode.aspx' |
|||
|
|||
url_sc = 'https://nfe.svrs.rs.gov.br/ws/NfeAutorizacao/NfeAutorizacao.asmx' |
|||
|
|||
url_rs = 'https://nfe.sefazrs.rs.gov.br/ws/NfeAutorizacao/NFeAutorizacao.asmx' |
|||
|
|||
url_cad_rs = 'https://cad.sefazrs.rs.gov.br/ws/cadconsultacadastro/cadcon\ |
|||
sultacadastro2.asmx' |
|||
|
|||
url_cad_sc = 'https://cad.svrs.rs.gov.br/ws/CadConsultaCadastro/CadConsult\ |
|||
aCadastro2.asmx' |
|||
|
|||
|
|||
class test_servidores(unittest.TestCase): |
|||
|
|||
def test_localizar_url(self): |
|||
url = localizar_url('NfeAutorizacao', '29', ambiente=1) |
|||
self.assertEqual(url, url_ba) |
|||
url = localizar_url('NfeAutorizacao', '35', ambiente=1) |
|||
self.assertEqual(url, url_sp) |
|||
url = localizar_url('NfeAutorizacao', '42', ambiente=1) |
|||
self.assertEqual(url, url_sc) |
|||
url = localizar_url('NfeAutorizacao', '43', ambiente=1) |
|||
self.assertEqual(url, url_rs) |
|||
|
|||
url = localizar_url('NfeConsultaCadastro', '43', ambiente=2) |
|||
self.assertEqual(url, url_cad_rs) |
|||
|
|||
url = localizar_url('NfeConsultaCadastro', '42', ambiente=2) |
|||
self.assertEqual(url, url_cad_sc) |
|||
|
|||
def test_localizar_qrcode(self): |
|||
url = localizar_qrcode('35') |
|||
self.assertEqual(url, url_qrcode_homologacao_sp) |
|||
@ -1,119 +0,0 @@ |
|||
# coding=utf-8 |
|||
''' |
|||
Created on Jun 16, 2015 |
|||
|
|||
@author: danimar |
|||
''' |
|||
import unittest |
|||
import datetime |
|||
from pytrustnfe.utils import date_tostring, datetime_tostring, \ |
|||
gerar_chave |
|||
from pytrustnfe.utils import ChaveNFe, CabecalhoSoap |
|||
|
|||
|
|||
class test_utils(unittest.TestCase): |
|||
kwargs = { |
|||
'cnpj': '33009911002506', 'estado': '52', 'emissao': '0604', |
|||
'modelo': '55', 'serie': '012', 'numero': 780, |
|||
'tipo': 0, 'codigo': '26730161' |
|||
} |
|||
|
|||
def test_cabecalho_soap(self): |
|||
head = CabecalhoSoap(versao=1, estado='SC', soap_action='Autorizacao') |
|||
self.assertEqual(head.versao, 1) |
|||
self.assertEqual(head.estado, 'SC') |
|||
self.assertEqual(head.soap_action, 'Autorizacao') |
|||
|
|||
def test_date_tostring(self): |
|||
hoje = datetime.date.today() |
|||
data = date_tostring(hoje) |
|||
self.assertEqual(data, hoje.strftime("%d-%m-%y"), |
|||
"Não convertido corretamente") |
|||
self.assertRaises(Exception, date_tostring, "Not a date") |
|||
|
|||
def test_datetime_tostring(self): |
|||
hoje = datetime.datetime.now() |
|||
data = datetime_tostring(hoje) |
|||
self.assertEqual(data, hoje.strftime("%d-%m-%y %H:%M:%S"), |
|||
"Não convertido corretamente") |
|||
self.assertRaises(Exception, datetime_tostring, "Not a date") |
|||
|
|||
def test_geracao_chave(self): |
|||
chave = ChaveNFe(**self.kwargs) |
|||
str_chave = gerar_chave(chave) |
|||
chave_correta = '52060433009911002506550120000007800267301615' |
|||
self.assertEqual(str_chave, chave_correta, |
|||
"Geração de chave nf-e incorreta") |
|||
|
|||
str_chave = gerar_chave(chave, prefix='NFe') |
|||
chave_correta = 'NFe52060433009911002506550120000007800267301615' |
|||
self.assertEqual(str_chave, chave_correta, |
|||
"Geração de chave nf-e com prefixo incorreta") |
|||
|
|||
self.assertRaises(Exception, gerar_chave, "Not a ChaveNFe object") |
|||
self.assertRaises(Exception, gerar_chave, "Not a ChaveNFe object") |
|||
|
|||
def test_chave_nfe(self): |
|||
chave = ChaveNFe(**self.kwargs) |
|||
with self.assertRaises(AssertionError) as cm: |
|||
chave.cnpj = '' |
|||
chave.validar() |
|||
chave.cnpj = '1234567891011' |
|||
self.assertEqual('CNPJ necessário para criar chave NF-e', |
|||
cm.exception.message, |
|||
'Validação da chave nf-e incorreta') |
|||
|
|||
with self.assertRaises(AssertionError) as cm: |
|||
chave.estado = '' |
|||
chave.validar() |
|||
chave.estado = '42' |
|||
self.assertEqual('Estado necessário para criar chave NF-e', |
|||
cm.exception.message, |
|||
'Validação da chave nf-e incorreta') |
|||
|
|||
with self.assertRaises(AssertionError) as cm: |
|||
chave.emissao = '' |
|||
chave.validar() |
|||
chave.emissao = '0' |
|||
self.assertEqual('Emissão necessário para criar chave NF-e', |
|||
cm.exception.message, |
|||
'Validação da chave nf-e incorreta') |
|||
|
|||
with self.assertRaises(AssertionError) as cm: |
|||
chave.modelo = '' |
|||
chave.validar() |
|||
chave.modelo = '55' |
|||
self.assertEqual('Modelo necessário para criar chave NF-e', |
|||
cm.exception.message, |
|||
'Validação da chave nf-e incorreta') |
|||
|
|||
with self.assertRaises(AssertionError) as cm: |
|||
chave.serie = '' |
|||
chave.validar() |
|||
chave.serie = '012' |
|||
self.assertEqual('Série necessária para criar chave NF-e', |
|||
cm.exception.message, |
|||
'Validação da chave nf-e incorreta') |
|||
|
|||
with self.assertRaises(AssertionError) as cm: |
|||
chave.numero = '' |
|||
chave.validar() |
|||
chave.numero = '000000780' |
|||
self.assertEqual('Número necessário para criar chave NF-e', |
|||
cm.exception.message, |
|||
'Validação da chave nf-e incorreta') |
|||
|
|||
with self.assertRaises(AssertionError) as cm: |
|||
chave.tipo = '' |
|||
chave.validar() |
|||
chave.tipo = '42' |
|||
self.assertEqual('Tipo necessário para criar chave NF-e', |
|||
cm.exception.message, |
|||
'Validação da chave nf-e incorreta') |
|||
|
|||
with self.assertRaises(AssertionError) as cm: |
|||
chave.codigo = '' |
|||
chave.validar() |
|||
self.assertEqual('Código necessário para criar chave NF-e', |
|||
cm.exception.message, |
|||
'Validação da chave nf-e incorreta') |
|||
Some files were not shown because too many files changed in this diff
Write
Preview
Loading…
Cancel
Save
Reference in new issue