4 changed files with 175 additions and 0 deletions
-
73pytrustnfe/nfse/goiania/__init__.py
-
38pytrustnfe/nfse/goiania/assinatura.py
-
4pytrustnfe/nfse/goiania/templates/GerarNfse.xml
-
60pytrustnfe/nfse/goiania/templates/Rps.xml
@ -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' |
|||
@ -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,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,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> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue