Browse Source

fix nfse natal

pull/262/head
Gabriela Cavalcante da Silva 6 years ago
parent
commit
9b125f513e
  1. 2
      .gitignore
  2. 51
      nfse-example.py
  3. 11
      pytrustnfe/nfe/assinatura.py
  4. 57
      pytrustnfe/nfse/natal/__init__.py
  5. 8
      pytrustnfe/nfse/natal/templates/EnvelopeSoap.xml
  6. 111
      pytrustnfe/nfse/natal/templates/Exemplo_LoteRPS.xml
  7. 45
      pytrustnfe/nfse/natal/templates/Rps.xml
  8. 3
      pytrustnfe/nfse/natal/templates/cabecalho.xml
  9. 6
      pytrustnfe/nfse/natal/templates/recepcionarLoteRps.xml
  10. 9
      pytrustnfe/nfse/susesu/templates/EnviarNota.xml
  11. 7
      pytrustnfe/xml/__init__.py
  12. 2
      tests/test_nfse_natal.py

2
.gitignore

@ -14,3 +14,5 @@ docs/_build
.cache .cache
.pytest_cache .pytest_cache
.vscode/ .vscode/
*.pfx
sent_xml.xml

51
nfse-example.py

@ -1,3 +1,4 @@
import ipdb
import xml.dom.minidom import xml.dom.minidom
import os import os
from pytrustnfe.nfse.natal import recepcionar_lote_rps from pytrustnfe.nfse.natal import recepcionar_lote_rps
@ -9,46 +10,45 @@ rps_list = [
"numero": "1", "numero": "1",
"serie": "UNICA", "serie": "UNICA",
"tipo_rps": "1", "tipo_rps": "1",
"data_emissao": "2020-01-279",
"data_emissao": "2010-06-16T21:00:00",
"natureza_operacao": "1", "natureza_operacao": "1",
"regime_tributacao": "1", "regime_tributacao": "1",
"optante_simples": "1", "optante_simples": "1",
"incentivador_cultural": "2", "incentivador_cultural": "2",
"status": "1",
"servico": { "servico": {
"valor_servico": "1.00", "valor_servico": "1.00",
"pis": "0",
"cofins": "0",
"inss": "0",
"ir": "0",
"csll": "0",
"iss_retido": "2", "iss_retido": "2",
"iss": "2",
"retencoes": "2",
"base_calculo": "0.00", "base_calculo": "0.00",
"aliquota": "2",
"codigo_servico": "01.07", "codigo_servico": "01.07",
"cnae_servico": "6209100", "cnae_servico": "6209100",
"descricao": "Sistema NFSe",
"discriminacao": "Sistema NFSe",
"codigo_municipio": "2408102", "codigo_municipio": "2408102",
}, },
"prestador": { "prestador": {
"cnpj": "23809070000190", "cnpj": "23809070000190",
"inscricao_municipal": "2143992",
"razao_social": "SERVICOS DE TI",
"fantasia": "SERVICOS DE TI",
"endereco": "AV AMINTAS",
"numero": "3755",
"complemento": "SALA 32",
"bairro": "Lagoa Nova",
"codigo_municipio": "2408102",
"uf": "RN",
"cep": "59075810",
"telefone": "4132095554",
"email": "SUPORTE@EMAIL.COM.BR",
"inscricao_municipal": "2143992"
}, },
"tomador": { "tomador": {
"cpf_cnpj": "01812418000166", "cpf_cnpj": "01812418000166",
"inscricao_municipal": "2143992",
"razao_social": "LEONIR", "razao_social": "LEONIR",
"endereco": "RUA GROBEIRO", "endereco": "RUA GROBEIRO",
"numero": "128", "numero": "128",
"complemento": "ANDAR 14",
"bairro": "Lagoa Nova", "bairro": "Lagoa Nova",
"cidade": "3159506",
"codigo_municipio": "3159506",
"uf": "BH", "uf": "BH",
"cep": "1231231313",
"cep": "30160010",
"email": "leonir@yahoo.com.br", "email": "leonir@yahoo.com.br",
"orgao_gerador": {"codigo_municipio": "3159506"},
}, },
} }
] ]
@ -60,15 +60,18 @@ nfse = {
} }
caminho = os.path.dirname(__file__) caminho = os.path.dirname(__file__)
pfx_source = open(os.path.join(caminho, "tests/teste.pfx"), "rb").read()
pfx = Certificado(pfx_source, "123456")
pfx_source = open(os.path.join(caminho, "tsmx-a1.pfx"), "rb").read()
pfx = Certificado(pfx_source, "12345678")
retorno = recepcionar_lote_rps(pfx, nfse=nfse, ambiente="homologacao") retorno = recepcionar_lote_rps(pfx, nfse=nfse, ambiente="homologacao")
# dom = xml.dom.minidom.parseString(retorno['received_xml'])
# received_xml = dom.toprettyxml()
# print(received_xml)
dom = xml.dom.minidom.parseString(retorno.get("sent_xml"))
dom = xml.dom.minidom.parseString(retorno['sent_xml']['nfseDadosMsg'])
sent_xml = dom.toprettyxml() sent_xml = dom.toprettyxml()
print(sent_xml) print(sent_xml)
myfile = open("sent_xml.xml", "w")
myfile.write(sent_xml)
dom = xml.dom.minidom.parseString(retorno['received_xml'])
received_xml = dom.toprettyxml()
print(received_xml)

11
pytrustnfe/nfe/assinatura.py

@ -24,9 +24,10 @@ class Assinatura(object):
method=signxml.methods.enveloped, method=signxml.methods.enveloped,
signature_algorithm="rsa-sha1", signature_algorithm="rsa-sha1",
digest_algorithm="sha1", digest_algorithm="sha1",
c14n_algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315",
c14n_algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments",
) )
#import ipdb
#ipdb.set_trace()
ns = {} ns = {}
ns[None] = signer.namespaces["ds"] ns[None] = signer.namespaces["ds"]
signer.namespaces = ns signer.namespaces = ns
@ -37,11 +38,11 @@ class Assinatura(object):
) )
if reference: if reference:
element_signed = signed_root.find(".//*[@Id='%s']" % reference) element_signed = signed_root.find(".//*[@Id='%s']" % reference)
signature = signed_root.find(
signature = signed_root.findall(
".//{http://www.w3.org/2000/09/xmldsig#}Signature" ".//{http://www.w3.org/2000/09/xmldsig#}Signature"
) )
if element_signed is not None and signature is not None: if element_signed is not None and signature is not None:
parent = element_signed.getparent()
parent.append(signature)
element_intern = element_signed.getchildren()
element_intern.append(signature)
return etree.tostring(signed_root, encoding=str) return etree.tostring(signed_root, encoding=str)

57
pytrustnfe/nfse/natal/__init__.py

@ -2,6 +2,9 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import os import os
from OpenSSL import crypto
from base64 import b64encode
from requests import Session from requests import Session
from zeep import Client from zeep import Client
from zeep.transports import Transport from zeep.transports import Transport
@ -12,24 +15,45 @@ from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key
from pytrustnfe.nfe.assinatura import Assinatura from pytrustnfe.nfe.assinatura import Assinatura
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')}"
)
return lote
return ""
def _render(certificado, method, **kwargs): def _render(certificado, method, **kwargs):
path = os.path.join(os.path.dirname(__file__), "templates") path = os.path.join(os.path.dirname(__file__), "templates")
xml_send = render_xml(path, "%s.xml" % method, True, **kwargs)
lote = ""
if method == "RecepcionarLoteRps":
lote = sign_rps(path, certificado, **kwargs)
kwargs["lote"] = lote
xml_send = render_xml(path, "%s.xml" % method, False, **kwargs)
reference = ""
signer = Assinatura(certificado.pfx, certificado.password) signer = Assinatura(certificado.pfx, certificado.password)
xml_send = signer.assina_xml(xml_send, reference)
referencia = "lote"
xml_send = signer.assina_xml(xml_send, f"{referencia}")
return xml_send return xml_send
def _send(certificado, method, **kwargs): def _send(certificado, method, **kwargs):
base_url = "" base_url = ""
if kwargs["ambiente"] == "producao": if kwargs["ambiente"] == "producao":
base_url = "https://aparecida.siltecnologia.com.br/tbw/services/Abrasf10?wsdl"
base_url = "" # https://wsnfsev1.natal.rn.gov.br:8444"
else: else:
base_url = "https://aparecida.siltecnologia.com.br/tbwhomologacao/services/Abrasf10?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 = extract_cert_and_key_from_pfx(
certificado.pfx, certificado.password)
cert, key = save_cert_key(cert, key) cert, key = save_cert_key(cert, key)
disable_warnings() disable_warnings()
@ -38,24 +62,29 @@ def _send(certificado, method, **kwargs):
session.verify = False session.verify = False
transport = Transport(session=session) transport = Transport(session=session)
client = Client(base_url, transport=transport)
xml_send = kwargs["xml"]
response = client.service[method](xml_send)
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) response, obj = sanitize_response(response)
return {"sent_xml": xml_send, "received_xml": response, "object": obj} return {"sent_xml": xml_send, "received_xml": response, "object": obj}
def xml_recepcionar_lote_rps(certificado, **kwargs): def xml_recepcionar_lote_rps(certificado, **kwargs):
return _render(certificado, "recepcionarLoteRps", **kwargs)
return _render(certificado, "RecepcionarLoteRps", **kwargs)
def recepcionar_lote_rps(certificado, **kwargs): def recepcionar_lote_rps(certificado, **kwargs):
if "xml" not in kwargs: if "xml" not in kwargs:
kwargs["xml"] = xml_recepcionar_lote_rps(certificado, **kwargs) kwargs["xml"] = xml_recepcionar_lote_rps(certificado, **kwargs)
print(kwargs["xml"])
return {"sent_xml": kwargs["xml"]}
# return _send(certificado, 'recepcionarLoteRps', **kwargs)
return _send(certificado, "RecepcionarLoteRps", **kwargs)
def xml_consultar_lote_rps(certificado, **kwargs): def xml_consultar_lote_rps(certificado, **kwargs):

8
pytrustnfe/nfse/natal/templates/EnvelopeSoap.xml

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

111
pytrustnfe/nfse/natal/templates/Exemplo_LoteRPS.xml

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

45
pytrustnfe/nfse/natal/templates/Rps.xml

@ -1,5 +1,5 @@
<Rps> <Rps>
<InfRps Id="{{ rps.numero }}">
<InfRps Id="rps:{{ rps.numero }}{{ rps.serie }}">
<IdentificacaoRps> <IdentificacaoRps>
<Numero>{{ rps.numero }}</Numero> <Numero>{{ rps.numero }}</Numero>
<Serie>{{ rps.serie }}</Serie> <Serie>{{ rps.serie }}</Serie>
@ -10,23 +10,29 @@
<RegimeEspecialTributacao>{{ rps.regime_tributacao }}</RegimeEspecialTributacao> <RegimeEspecialTributacao>{{ rps.regime_tributacao }}</RegimeEspecialTributacao>
<OptanteSimplesNacional>{{ rps.optante_simples }}</OptanteSimplesNacional> <OptanteSimplesNacional>{{ rps.optante_simples }}</OptanteSimplesNacional>
<IncentivadorCultural>{{ rps.incentivador_cultural }}</IncentivadorCultural> <IncentivadorCultural>{{ rps.incentivador_cultural }}</IncentivadorCultural>
<Status>{{ rps.status }}</Status>
<Servico> <Servico>
<Valores> <Valores>
<ValorServicos>{{ rps.servico.valor_servico }}</ValorServicos> <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> <IssRetido>{{ rps.servico.iss_retido }}</IssRetido>
<ValorIss>{{ rps.servico.iss }}</ValorIss>
<OutrasRetencoes>{{ rps.servico.retencoes }}</OutrasRetencoes>
<BaseCalculo>{{ rps.servico.base_calculo }}</BaseCalculo> <BaseCalculo>{{ rps.servico.base_calculo }}</BaseCalculo>
<Aliquota>{{ rps.servico.aliquota }}</Aliquota>
</Valores> </Valores>
<ItemListaServico>{{ rps.servico.codigo_servico }}</ItemListaServico> <ItemListaServico>{{ rps.servico.codigo_servico }}</ItemListaServico>
<CodigoCnae>{{ rps.servico.cnae_servico }}</CodigoCnae> <CodigoCnae>{{ rps.servico.cnae_servico }}</CodigoCnae>
<CodigoTributacaoMunicipio>{{ rps.servico.codigo_tributacao_municipio }}</CodigoTributacaoMunicipio>
<Discriminacao>{{ rps.servico.descricao }}</Discriminacao>
<Discriminacao>{{ rps.servico.discriminacao }}</Discriminacao>
<CodigoMunicipio>{{ rps.servico.codigo_municipio }}</CodigoMunicipio> <CodigoMunicipio>{{ rps.servico.codigo_municipio }}</CodigoMunicipio>
</Servico> </Servico>
<PrestadorServico>
<IdentificacaoPrestador>
<Prestador>
<Cnpj>{{ rps.prestador.cnpj }}</Cnpj> <Cnpj>{{ rps.prestador.cnpj }}</Cnpj>
<InscricaoMunicipal>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipal> <InscricaoMunicipal>{{ rps.prestador.inscricao_municipal }}</InscricaoMunicipal>
</IdentificacaoPrestador>
<RazaoSocial>{{ rps.prestador.razaosocial }}</RazaoSocial> <RazaoSocial>{{ rps.prestador.razaosocial }}</RazaoSocial>
<NomeFantasia>{{ rps.prestador.fantasia }}</NomeFantasia> <NomeFantasia>{{ rps.prestador.fantasia }}</NomeFantasia>
<Endereco> <Endereco>
@ -39,18 +45,22 @@
<Cep>{{ rps.prestador.cep }}</Cep> <Cep>{{ rps.prestador.cep }}</Cep>
</Endereco> </Endereco>
<Contato> <Contato>
{% if rps.prestador.telefone is defined -%}
<Telefone>{{ rps.prestador.telefone }}</Telefone> <Telefone>{{ rps.prestador.telefone }}</Telefone>
{% endif %}
{% if rps.prestador.email is defined -%}
<Email>{{ rps.prestador.email }}</Email> <Email>{{ rps.prestador.email }}</Email>
{% endif %}
</Contato> </Contato>
</PrestadorServico>
<TomadorServico>
</Prestador>
<Tomador>
<IdentificacaoTomador> <IdentificacaoTomador>
<CpfCnpj> <CpfCnpj>
{% if rps.tomador.cnpj_cpf|length == 14 %}
<Cnpj>{{ rps.tomador.cnpj_cpf }}</Cnpj>
{% if rps.tomador.cpf_cnpj|length == 14 %}
<Cnpj>{{ rps.tomador.cpf_cnpj }}</Cnpj>
{% endif %} {% endif %}
{% if rps.tomador.cnpj_cpf|length == 11 %}
<Cpf>{{ rps.tomador.cnpj_cpf }}</Cpf>
{% if rps.tomador.cpf_cnpj|length == 11 %}
<Cpf>{{ rps.tomador.cpf_cnpj }}</Cpf>
{% endif %} {% endif %}
</CpfCnpj> </CpfCnpj>
{% if rps.tomador.inscricao_municipal is defined -%} {% if rps.tomador.inscricao_municipal is defined -%}
@ -59,11 +69,9 @@
</IdentificacaoTomador> </IdentificacaoTomador>
<RazaoSocial>{{ rps.tomador.razao_social }}</RazaoSocial> <RazaoSocial>{{ rps.tomador.razao_social }}</RazaoSocial>
<Endereco> <Endereco>
<Endereco>{{ rps.tomador.logradouro }}</Endereco>
<Endereco>{{ rps.tomador.endereco }}</Endereco>
<Numero>{{ rps.tomador.numero }}</Numero> <Numero>{{ rps.tomador.numero }}</Numero>
{% if rps.tomador.complemento is defined -%}
<Complemento>{{ rps.tomador.complemento }}</Complemento> <Complemento>{{ rps.tomador.complemento }}</Complemento>
{% endif %}
<Bairro>{{ rps.tomador.bairro }}</Bairro> <Bairro>{{ rps.tomador.bairro }}</Bairro>
<CodigoMunicipio>{{ rps.tomador.codigo_municipio }}</CodigoMunicipio> <CodigoMunicipio>{{ rps.tomador.codigo_municipio }}</CodigoMunicipio>
<Uf>{{ rps.tomador.uf }}</Uf> <Uf>{{ rps.tomador.uf }}</Uf>
@ -74,14 +82,16 @@
<Telefone>{{ rps.tomador.telefone }}</Telefone> <Telefone>{{ rps.tomador.telefone }}</Telefone>
{% endif %} {% endif %}
{% if rps.tomador.email is defined -%} {% if rps.tomador.email is defined -%}
<Telefone>{{ rps.tomador.email }}</Telefone>
<Email>{{ rps.tomador.email }}</Email>
{% endif %} {% endif %}
</Contato> </Contato>
{% if rps.tomador.orgao_gerador is defined -%}
<OrgaoGerador> <OrgaoGerador>
<CodigoMunicipio>{{ rps.tomador.orgao_gerador.codigo_municipio }}</CodigoMunicipio> <CodigoMunicipio>{{ rps.tomador.orgao_gerador.codigo_municipio }}</CodigoMunicipio>
<Uf>{{ rps.tomador.orgao_gerador.uf }}</Uf> <Uf>{{ rps.tomador.orgao_gerador.uf }}</Uf>
</OrgaoGerador> </OrgaoGerador>
</TomadorServico>
{% endif %}
</Tomador>
{% if rps.intermediario is defined -%} {% if rps.intermediario is defined -%}
<IntermediarioServico> <IntermediarioServico>
<RazaoSocial>{{ rps.intermediario.razao_social }}</RazaoSocial> <RazaoSocial>{{ rps.intermediario.razao_social }}</RazaoSocial>
@ -98,4 +108,5 @@
</ContrucaoCivil> </ContrucaoCivil>
{% endif %} {% endif %}
</InfRps> </InfRps>
<Signature Id="placeholder"></Signature>
</Rps> </Rps>

3
pytrustnfe/nfse/natal/templates/cabecalho.xml

@ -0,0 +1,3 @@
<cabecalho versao="2.01" xmlns="http://www.abrasf.org.br/nfse.xsd">
<versaoDados>2.01</versaoDados>
</cabecalho>

6
pytrustnfe/nfse/natal/templates/recepcionarLoteRps.xml

@ -1,13 +1,11 @@
<EnviarLoteRpsEnvio xmlns="http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd"> <EnviarLoteRpsEnvio xmlns="http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd">
<LoteRps Id="{{ nfse.numero_lote }}">
<LoteRps Id="lote">
<NumeroLote>{{ nfse.numero_lote }}</NumeroLote> <NumeroLote>{{ nfse.numero_lote }}</NumeroLote>
<Cnpj>{{ nfse.cnpj_prestador }}</Cnpj> <Cnpj>{{ nfse.cnpj_prestador }}</Cnpj>
<InscricaoMunicipal>{{ nfse.inscricao_municipal }}</InscricaoMunicipal> <InscricaoMunicipal>{{ nfse.inscricao_municipal }}</InscricaoMunicipal>
<QuantidadeRps>{{ nfse.lista_rps|length }}</QuantidadeRps> <QuantidadeRps>{{ nfse.lista_rps|length }}</QuantidadeRps>
<ListaRps> <ListaRps>
{% for rps in nfse.lista_rps -%}
{% include 'Rps.xml' %}
{% endfor %}
{{lote}}
</ListaRps> </ListaRps>
</LoteRps> </LoteRps>
</EnviarLoteRpsEnvio> </EnviarLoteRpsEnvio>

9
pytrustnfe/nfse/susesu/templates/EnviarNota.xml

@ -1,5 +1,6 @@
<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>
<x:Envelope xmlns:x="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://services.nfse">
<x:Header/>
<x:Body>
<EnviarNota xmlns="http://susesu.com.br/"> <EnviarNota xmlns="http://susesu.com.br/">
<codPrefeitura>{{ codigo_prefeitura }}</codPrefeitura> <codPrefeitura>{{ codigo_prefeitura }}</codPrefeitura>
<notaFiscal> <notaFiscal>
@ -10,5 +11,5 @@
<cnpjPrestador>{{ cnpj_prestador }}</cnpjPrestador> <cnpjPrestador>{{ cnpj_prestador }}</cnpjPrestador>
<senhaNFD>{{ senha_nfd }}</senhaNFD> <senhaNFD>{{ senha_nfd }}</senhaNFD>
</EnviarNota> </EnviarNota>
</soap:Body>
</soap:Envelope>
</x:Body>
</x:Envelope>

7
pytrustnfe/xml/__init__.py

@ -17,7 +17,8 @@ def recursively_empty(e):
def render_xml(path, template_name, remove_empty, **nfe): def render_xml(path, template_name, remove_empty, **nfe):
nfe = recursively_normalize(nfe) nfe = recursively_normalize(nfe)
env = Environment(loader=FileSystemLoader(path), extensions=["jinja2.ext.with_"])
env = Environment(loader=FileSystemLoader(
path), extensions=["jinja2.ext.with_"])
env.filters["normalize"] = filters.strip_line_feed env.filters["normalize"] = filters.strip_line_feed
env.filters["normalize_str"] = filters.normalize_str env.filters["normalize_str"] = filters.normalize_str
env.filters["format_percent"] = filters.format_percent env.filters["format_percent"] = filters.format_percent
@ -41,7 +42,7 @@ def render_xml(path, template_name, remove_empty, **nfe):
if recursively_empty(elem): if recursively_empty(elem):
parent.remove(elem) parent.remove(elem)
return root return root
return etree.tostring(root, encoding=str)
return root
def sanitize_response(response): def sanitize_response(response):
@ -53,7 +54,7 @@ def sanitize_response(response):
continue continue
i = elem.tag.find("}") i = elem.tag.find("}")
if i >= 0: if i >= 0:
elem.tag = elem.tag[i + 1 :]
elem.tag = elem.tag[i + 1:]
objectify.deannotate(tree, cleanup_namespaces=True) objectify.deannotate(tree, cleanup_namespaces=True)
return response, objectify.fromstring(etree.tostring(tree)) return response, objectify.fromstring(etree.tostring(tree))

2
tests/test_nfse_natal.py

@ -70,7 +70,7 @@ class test_nfse_natal(unittest.TestCase):
def test_recepcionar_lote_rps(self): def test_recepcionar_lote_rps(self):
pfx_source = open(os.path.join(self.caminho, "teste.pfx"), "rb").read() pfx_source = open(os.path.join(self.caminho, "teste.pfx"), "rb").read()
pfx = Certificado(pfx_source, "123456")
pfx = Certificado(pfx_source, "123456", ambiente="homologacao")
nfse = self._get_nfse() nfse = self._get_nfse()
path = os.path.join(os.path.dirname(__file__), "XMLs") path = os.path.join(os.path.dirname(__file__), "XMLs")

Loading…
Cancel
Save