Browse Source

Adicionado geração do RPS para a prefeitura de Goiânia/GO.

pull/292/head
Flavyo Henrique 5 years ago
parent
commit
ab57f6c4e0
  1. 73
      pytrustnfe/nfse/goiania/__init__.py
  2. 38
      pytrustnfe/nfse/goiania/assinatura.py
  3. 4
      pytrustnfe/nfse/goiania/templates/GerarNfse.xml
  4. 60
      pytrustnfe/nfse/goiania/templates/Rps.xml

73
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'

38
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)

4
pytrustnfe/nfse/goiania/templates/GerarNfse.xml

@ -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>

60
pytrustnfe/nfse/goiania/templates/Rps.xml

@ -0,0 +1,60 @@
<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>
<ValorPis>{{ servico.valor_pis }}</ValorPis>
<ValorCofins>{{ servico.valor_confins }}</ValorCofins>
<ValorInss>{{ servico.valor_inss }}</ValorInss>
<ValorCsll>{{ servico.valor_csll }}</ValorCsll>
</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>
<Endereco>
<Endereco>{{ tomador.endereco.rua }}</Endereco>
<Numero>{{ tomador.endereco.numero }}</Numero>
<Complemento>{{ tomador.endereco.complemento }}</Complemento>
<Bairro>{{ tomador.endereco.bairro }}</Bairro>
<CodigoMunicipio>{{ tomador.endereco.codigo_municipio }}</CodigoMunicipio>
<Uf>{{ tomador.endereco.uf }}</Uf>
</Endereco>
</Tomador>
</InfDeclaracaoPrestacaoServico>
</Rps>
Loading…
Cancel
Save