From ad8307117157aef3d86184274c2789de700d99a2 Mon Sep 17 00:00:00 2001 From: Danimar Ribeiro Date: Wed, 21 Aug 2019 17:00:44 -0300 Subject: [PATCH 1/6] =?UTF-8?q?[WIP]=20Implementa=C3=A7=C3=A3o=20de=20NFSe?= =?UTF-8?q?=20Aparecida=20SP.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pytrustnfe/nfse/aparecida/__init__.py | 81 +++++++++++++++++++ pytrustnfe/nfse/aparecida/templates/Rps.xml | 91 ++++++++++++++++++++++ .../nfse/aparecida/templates/cancelarNfse.xml | 15 ++++ .../nfse/aparecida/templates/consultarLoteRps.xml | 7 ++ .../aparecida/templates/recepcionarLoteRps.xml | 13 ++++ setup.py | 1 + 6 files changed, 208 insertions(+) create mode 100644 pytrustnfe/nfse/aparecida/__init__.py create mode 100644 pytrustnfe/nfse/aparecida/templates/Rps.xml create mode 100644 pytrustnfe/nfse/aparecida/templates/cancelarNfse.xml create mode 100644 pytrustnfe/nfse/aparecida/templates/consultarLoteRps.xml create mode 100644 pytrustnfe/nfse/aparecida/templates/recepcionarLoteRps.xml diff --git a/pytrustnfe/nfse/aparecida/__init__.py b/pytrustnfe/nfse/aparecida/__init__.py new file mode 100644 index 0000000..9e063ec --- /dev/null +++ b/pytrustnfe/nfse/aparecida/__init__.py @@ -0,0 +1,81 @@ +# © 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) diff --git a/pytrustnfe/nfse/aparecida/templates/Rps.xml b/pytrustnfe/nfse/aparecida/templates/Rps.xml new file mode 100644 index 0000000..d366389 --- /dev/null +++ b/pytrustnfe/nfse/aparecida/templates/Rps.xml @@ -0,0 +1,91 @@ + + + + {{ rps.numero }} + {{ rps.serie }} + {{ rps.tipo_rps }} + + {{ rps.data_emissao }} + {{ rps.natureza_operacao }} + {{ rps.regime_tributacao }} + {{ rps.optante_simples }} + {{ rps.incentivador_cultural }} + {{ rps.status }} + + {{ rps.numero_substituido }} + {{ rps.serie_substituido }} + {{ rps.tipo_substituido }} + + + + {{ rps.valor_servico }} + {{ rps.valor_deducao }} + {{ rps.valor_pis }} + {{ rps.valor_cofins }} + {{ rps.valor_inss }} + {{ rps.valor_ir }} + {{ rps.valor_csll }} + {{ rps.iss_retido }} + {{ rps.valor_iss }} + {{ rps.valor_iss_retido }} + {{ rps.outras_retencoes }} + {{ rps.base_calculo }} + {{ rps.aliquota_issqn }} + {{ rps.valor_liquido_nfse }} + {{ rps.desconto_incondicionado }} + {{ rps.desconto_condicionado }} + + {{ rps.codigo_servico }} + {{ rps.cnae_servico }} + {{ rps.codigo_tributacao_municipio }} + {{ rps.descricao }} + {{ rps.codigo_municipio }} + + + {{ rps.prestador.cnpj }} + {{ rps.prestador.inscricao_municipal }} + + + + + {% if rps.tomador.cnpj_cpf|length == 14 %} + {{ rps.tomador.cnpj_cpf }} + {% endif %} + {% if rps.tomador.cnpj_cpf|length == 11 %} + {{ rps.tomador.cnpj_cpf }} + {% endif %} + + {{ rps.tomador.inscricao_municipal }} + + {{ rps.tomador.razao_social }} + + {{ rps.tomador.logradouro }} + {{ rps.tomador.numero }} + {{ rps.tomador.complemento }} + {{ rps.tomador.bairro }} + {{ rps.tomador.cidade }} + {{ rps.tomador.uf }} + {{ rps.tomador.cep }} + + + {{ rps.tomador.telefone }} + {{ rps.tomador.email }} + + + {% if rps.intermediario is defined -%} + + {{ rps.intermediario.razao_social }} + + {{ rps.intermediario.cnpj }} + + {{ rps.intermediario.inscricao_municipal }} + + {% endif %} + {% if rps.construcao_civil is defined -%} + + {{ rps.construcao_civil.codigo_obra }} + {{ rps.construcao_civil.art }} + + {% endif %} + + diff --git a/pytrustnfe/nfse/aparecida/templates/cancelarNfse.xml b/pytrustnfe/nfse/aparecida/templates/cancelarNfse.xml new file mode 100644 index 0000000..f5ec25b --- /dev/null +++ b/pytrustnfe/nfse/aparecida/templates/cancelarNfse.xml @@ -0,0 +1,15 @@ + + + + + {{ cancelamento.numero_nfse }} + + {{ cancelamento.cnpj_prestador }} + + {{ cancelamento.inscricao_municipal }} + {{ cancelamento.cidade }} + + {{ cancelamento.codigo_cancelamento }} + + + diff --git a/pytrustnfe/nfse/aparecida/templates/consultarLoteRps.xml b/pytrustnfe/nfse/aparecida/templates/consultarLoteRps.xml new file mode 100644 index 0000000..7e4df96 --- /dev/null +++ b/pytrustnfe/nfse/aparecida/templates/consultarLoteRps.xml @@ -0,0 +1,7 @@ + + + {{ consulta.cnpj_prestador }} + {{ consulta.inscricao_municipal }} + + {{ consulta.protocolo }} + diff --git a/pytrustnfe/nfse/aparecida/templates/recepcionarLoteRps.xml b/pytrustnfe/nfse/aparecida/templates/recepcionarLoteRps.xml new file mode 100644 index 0000000..78dcaff --- /dev/null +++ b/pytrustnfe/nfse/aparecida/templates/recepcionarLoteRps.xml @@ -0,0 +1,13 @@ + + + {{ nfse.numero_lote }} + {{ nfse.cnpj_prestador }} + {{ nfse.inscricao_municipal }} + {{ nfse.lista_rps|length }} + + {% for rps in nfse.lista_rps -%} + {% include 'Rps.xml' %} + {% endfor %} + + + diff --git a/setup.py b/setup.py index 84578c5..d886a7d 100644 --- a/setup.py +++ b/setup.py @@ -39,6 +39,7 @@ later (LGPLv2+)', 'nfse/carioca/templates/*xml', 'nfse/bh/templates/*xml', 'nfse/mga/templates/*xml', + 'nfse/aparecida/templates/*xml', 'xml/schemas/*xsd', ]}, url='https://github.com/danimaribeiro/PyTrustNFe', From 704cd29b420f26c76119cbbc8ca63d2def350fea Mon Sep 17 00:00:00 2001 From: Danimar Ribeiro Date: Thu, 29 Aug 2019 13:26:53 -0300 Subject: [PATCH 2/6] [FIX] Corrige NFS-e Simpliss --- pytrustnfe/nfse/simpliss/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pytrustnfe/nfse/simpliss/__init__.py b/pytrustnfe/nfse/simpliss/__init__.py index 62daa4a..b93bd2d 100644 --- a/pytrustnfe/nfse/simpliss/__init__.py +++ b/pytrustnfe/nfse/simpliss/__init__.py @@ -40,7 +40,7 @@ def _send(method, **kwargs): base_url = 'http://wshomologacao.simplissweb.com.br/nfseservice.svc' # noqa base_url = 'http://wshomologacao.simplissweb.com.br/nfseservice.svc' - xml_send = kwargs["xml"].replace('', '') + xml_send = kwargs["xml"] path = os.path.join(os.path.dirname(__file__), 'templates') soap = render_xml(path, 'SoapRequest.xml', False, soap_body=xml_send) diff --git a/setup.py b/setup.py index d886a7d..c599f94 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages -VERSION = "1.0.40" +VERSION = "1.0.41" setup( From a9154ba93d683933bf47e5fdf8cac87eb0bc3c47 Mon Sep 17 00:00:00 2001 From: Danimar Ribeiro Date: Thu, 12 Sep 2019 00:41:17 -0300 Subject: [PATCH 3/6] [FIX] Utilizando o campo xPed diretamente do produto --- pytrustnfe/Servidores.py | 2 +- pytrustnfe/nfe/templates/NfeAutorizacao.xml | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/pytrustnfe/Servidores.py b/pytrustnfe/Servidores.py index 7482c6f..543ca03 100644 --- a/pytrustnfe/Servidores.py +++ b/pytrustnfe/Servidores.py @@ -142,7 +142,7 @@ SVRS = { WS_NFE_RECEPCAO_EVENTO: 'ws/recepcaoevento/recepcaoevento4.asmx?wsdl', # noqa WS_NFE_AUTORIZACAO: 'ws/NfeAutorizacao/NFeAutorizacao4.asmx?wsdl', WS_NFE_RET_AUTORIZACAO: 'ws/NfeRetAutorizacao/NFeRetAutorizacao4.asmx?wsdl', # noqa - WS_NFE_CADASTRO: 'ws/cadconsultacadastro/cadconsultacadastro2.asmx?wsdl', # noqa + WS_NFE_CADASTRO: 'ws/cadconsultacadastro/cadconsultacadastro4.asmx?wsdl', # noqa } }, NFCE_MODELO: { diff --git a/pytrustnfe/nfe/templates/NfeAutorizacao.xml b/pytrustnfe/nfe/templates/NfeAutorizacao.xml index 0eb2e3c..0efd5cd 100644 --- a/pytrustnfe/nfe/templates/NfeAutorizacao.xml +++ b/pytrustnfe/nfe/templates/NfeAutorizacao.xml @@ -27,7 +27,7 @@ {{ ide.indFinal }} {{ ide.indPres }} {{ ide.procEmi }} - Odoo Brasil 10 + {{ ide.verProc }} {% if ide.NFref is defined -%} {% for ref in ide.NFref %} @@ -259,9 +259,7 @@ {% endfor %} {% endif %} - {% if NFe.infNFe.compra is defined %} - {{ NFe.infNFe.compra.xPed }} - {% endif %} + {{ prod.xPed }} {{ prod.nItemPed }} {{ prod.nFCI }} {% for rastro in prod.rastro %} From 4ebc84823789e95e30038f7adc119f7615f511fc Mon Sep 17 00:00:00 2001 From: Danimar Ribeiro Date: Thu, 12 Sep 2019 02:18:29 -0300 Subject: [PATCH 4/6] [VER] Increment version --- setup.py | 2 +- tests/test_servidores.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index c599f94..5b77fd0 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages -VERSION = "1.0.41" +VERSION = "1.0.42" setup( diff --git a/tests/test_servidores.py b/tests/test_servidores.py index a072f97..e83ac1a 100644 --- a/tests/test_servidores.py +++ b/tests/test_servidores.py @@ -21,7 +21,7 @@ url_rs = 'https://nfe.sefazrs.rs.gov.br/ws/NfeAutorizacao/NFeAutorizacao4.asmx?w url_cad_rs = 'https://cad.sefazrs.rs.gov.br/ws/cadconsultacadastro/cadconsultacadastro4.asmx?wsdl' url_cad_sc = 'https://cad.svrs.rs.gov.br/ws/cadconsultacadastro/cadconsulta\ -cadastro2.asmx?wsdl' +cadastro4.asmx?wsdl' class test_servidores(unittest.TestCase): From 8e2b3260107a31c1b2fbf3c22d47e0e7a7376efa Mon Sep 17 00:00:00 2001 From: Danimar Ribeiro Date: Thu, 12 Sep 2019 16:49:47 -0300 Subject: [PATCH 5/6] =?UTF-8?q?[FIX]=20Cancelamento=20pode=20tamb=C3=A9m?= =?UTF-8?q?=20ser=20status=20155?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pytrustnfe/nfe/danfe.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pytrustnfe/nfe/danfe.py b/pytrustnfe/nfe/danfe.py index 54ea885..9cbeea1 100644 --- a/pytrustnfe/nfe/danfe.py +++ b/pytrustnfe/nfe/danfe.py @@ -359,7 +359,7 @@ class danfe(object): self.canvas.restoreState() # Cancelado - if tagtext(oNode=elem_evento, cTag='cStat') == '135': + if tagtext(oNode=elem_evento, cTag='cStat') in ('135', '155'): self.canvas.saveState() self.canvas.rotate(45) self.canvas.setFont('NimbusSanL-Bold', 60) diff --git a/setup.py b/setup.py index 5b77fd0..505c17b 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages -VERSION = "1.0.42" +VERSION = "1.0.43" setup( From 8768b24202677e8b2e6e052082ac2f1b6f707668 Mon Sep 17 00:00:00 2001 From: Danimar Ribeiro Date: Thu, 12 Sep 2019 17:30:13 -0300 Subject: [PATCH 6/6] =?UTF-8?q?[IMP]=20Implementa=C3=A7=C3=A3o=20de=20danf?= =?UTF-8?q?ce=20de=20conting=C3=AAncia=20-=20mensagens=20no=20danfce?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pytrustnfe/nfe/danfce.py | 52 +++++++++++++++++++++++++++++++----------------- setup.py | 2 +- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/pytrustnfe/nfe/danfce.py b/pytrustnfe/nfe/danfce.py index 7773798..9e64c24 100644 --- a/pytrustnfe/nfe/danfce.py +++ b/pytrustnfe/nfe/danfce.py @@ -122,16 +122,24 @@ class danfce(object): self._drawCenteredParagraph(cEnd) self.drawLine() - def danfce_information(self): - self.drawTitle( - "DANFE NFC-e - Documento Auxiliar da Nota Fiscal de", - 7, 'NimbusSanL-Bold') + 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.drawTitle("Consumidor Eletrônica", 7, 'NimbusSanL-Bold') - self.drawString( - "NFC-e não permite aproveitamento de crédito de ICMS", True) - self.drawLine() + 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): @@ -309,18 +317,26 @@ class danfce(object): dataSolicitacao = getdateUTC(tagtext(oNode=el_ide, cTag="dhEmi")) dataSolicitacao = dataSolicitacao[0] + " " + dataSolicitacao[1] - numProtocolo = tagtext(oNode=el_prot_nfe, cTag="nProt") + text = u"%s
%s
NFC-e nº%s Série %s %s
" % ( + frase_chave_acesso, cnpj_cpf, nNFC, serie, dataSolicitacao) - dataAutorizacao = getdateUTC(tagtext(oNode=el_prot_nfe, - cTag='dhRecbto')) - dataAutorizacao = dataAutorizacao[0] + " " + dataAutorizacao[1] + 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") - text = u"%s
%s
NFC-e nº%s Série %s %s
\ -Protocolo de autorização: %s
Data de autorização %s
\ -" % (frase_chave_acesso, cnpj_cpf, nNFC, serie, dataSolicitacao, - numProtocolo, dataAutorizacao) + dataAutorizacao = getdateUTC(tagtext(oNode=el_prot_nfe, + cTag='dhRecbto')) + dataAutorizacao = dataAutorizacao[0] + " " + dataAutorizacao[1] - self._drawCenteredParagraph(text) + text = "Protocolo de autorização: %s
Data de autorização %s
" % ( + numProtocolo, dataAutorizacao) + self._drawCenteredParagraph(text) self.draw_qr_code(qrcode) @@ -428,7 +444,7 @@ Protocolo de autorização: %s
Data de autorização %s
\ self.ide_emit(oXML=oXML) # self.destinatario(oXML=oXML) - self.danfce_information() + 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) diff --git a/setup.py b/setup.py index 505c17b..73e2fb8 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages -VERSION = "1.0.43" +VERSION = "1.0.44" setup(