From ab57f6c4e0c1a8175aa4cc0b8bbb5c891569a70e Mon Sep 17 00:00:00 2001 From: Flavyo Henrique Date: Mon, 4 Jan 2021 17:18:10 -0300 Subject: [PATCH] =?UTF-8?q?Adicionado=20gera=C3=A7=C3=A3o=20do=20RPS=20par?= =?UTF-8?q?a=20a=20prefeitura=20de=20Goi=C3=A2nia/GO.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pytrustnfe/nfse/goiania/__init__.py | 73 +++++++++++++++++++++++++ pytrustnfe/nfse/goiania/assinatura.py | 38 +++++++++++++ pytrustnfe/nfse/goiania/templates/GerarNfse.xml | 4 ++ pytrustnfe/nfse/goiania/templates/Rps.xml | 60 ++++++++++++++++++++ 4 files changed, 175 insertions(+) create mode 100644 pytrustnfe/nfse/goiania/__init__.py create mode 100644 pytrustnfe/nfse/goiania/assinatura.py create mode 100644 pytrustnfe/nfse/goiania/templates/GerarNfse.xml create mode 100644 pytrustnfe/nfse/goiania/templates/Rps.xml diff --git a/pytrustnfe/nfse/goiania/__init__.py b/pytrustnfe/nfse/goiania/__init__.py new file mode 100644 index 0000000..726b548 --- /dev/null +++ b/pytrustnfe/nfse/goiania/__init__.py @@ -0,0 +1,73 @@ +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): + 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 strip_result(xml_received: str): + """ Retorna o código e a mensagem de retorno vindo do webservice """ + + xml = etree.fromstring(xml_received) + + if not xml: + return None, None + + ns = './/{http://nfse.goiania.go.gov.br/xsd/nfse_gyn_v02.xsd}' + msg_return = xml.find(f'{ns}MensagemRetorno') + code = msg_return.find(f"{ns}Codigo").text + msg = msg_return.find(f"{ns}Mensagem").text + return code, msg + + +def is_success(xml_received: str): + """ Retorna se a emissão da NFS-e deu certo """ + + code, _ = strip_result(xml_received) + + # Code L000 significa que a nota foi aprovada + return code == 'L000' diff --git a/pytrustnfe/nfse/goiania/assinatura.py b/pytrustnfe/nfse/goiania/assinatura.py new file mode 100644 index 0000000..94009fd --- /dev/null +++ b/pytrustnfe/nfse/goiania/assinatura.py @@ -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) diff --git a/pytrustnfe/nfse/goiania/templates/GerarNfse.xml b/pytrustnfe/nfse/goiania/templates/GerarNfse.xml new file mode 100644 index 0000000..7546f02 --- /dev/null +++ b/pytrustnfe/nfse/goiania/templates/GerarNfse.xml @@ -0,0 +1,4 @@ + + + {% include 'Rps.xml' %} + diff --git a/pytrustnfe/nfse/goiania/templates/Rps.xml b/pytrustnfe/nfse/goiania/templates/Rps.xml new file mode 100644 index 0000000..e4785f9 --- /dev/null +++ b/pytrustnfe/nfse/goiania/templates/Rps.xml @@ -0,0 +1,60 @@ + + + + + {{ numero }} + {{ serie }} + {{ tipo }} + + {{ data_emissao }} + {{ status }} + + + + {{ servico.valor_servicos }} + {{ servico.valor_pis }} + {{ servico.valor_confins }} + {{ servico.valor_inss }} + {{ servico.valor_csll }} + + {{ servico.codigo_tributacao_municipio }} + {{ servico.discriminacao }} + {{ servico.codigo_municipio }} + + + + {% if prestador.cnpj_cpf|length == 14 %} + {{ prestador.cnpj_cpf }} + {% endif %} + {% if prestador.cnpj_cpf|length == 11 %} + {{ prestador.cnpj_cpf }} + {% endif %} + + {{ prestador.inscricao_municipal }} + + + + + {% if tomador.cnpj_cpf|length == 14 %} + {{ tomador.cnpj_cpf }} + {% endif %} + {% if prestador.cnpj_cpf|length == 11 %} + {{ prestador.cnpj_cpf }} + {% endif %} + + {% if tomador.inscricao_municipal %} + {{ tomador.inscricao_municipal }} + {% endif %} + + {{ tomador.razao_social }} + + {{ tomador.endereco.rua }} + {{ tomador.endereco.numero }} + {{ tomador.endereco.complemento }} + {{ tomador.endereco.bairro }} + {{ tomador.endereco.codigo_municipio }} + {{ tomador.endereco.uf }} + + + +