Browse Source

Metodo para assinar o xml com certificado digital

tags/0.1.5
Danimar Ribeiro 9 years ago
parent
commit
77429ae725
  1. 84
      pytrustnfe/nfse/paulistana/__init__.py
  2. 0
      pytrustnfe/nfse/paulistana/templates/CancelamentoNFe.xml
  3. 0
      pytrustnfe/nfse/paulistana/templates/ConsultaCNPJ.xml
  4. 0
      pytrustnfe/nfse/paulistana/templates/ConsultaInformacoesLote.xml
  5. 0
      pytrustnfe/nfse/paulistana/templates/ConsultaLote.xml
  6. 0
      pytrustnfe/nfse/paulistana/templates/ConsultaNFe.xml
  7. 0
      pytrustnfe/nfse/paulistana/templates/ConsultaNFeEmitidas.xml
  8. 58
      pytrustnfe/nfse/paulistana/templates/EnvioLoteRPS.xml
  9. 0
      pytrustnfe/nfse/paulistana/templates/EnvioRPS.xml
  10. 82
      pytrustnfe/nfse/paulistana/templates/TesteEnvioLoteRPS.xml
  11. 22
      pytrustnfe/xml/__init__.py

84
pytrustnfe/nfse/paulistana/__init__.py

@ -1,59 +1,107 @@
import os import os
import logging import logging
import suds import suds
from uuid import uuid4
from lxml import etree from lxml import etree
from pytrustnfe.xml import render_xml, valida_schema
from pytrustnfe.xml import render_xml, valida_schema, sanitize_response
from pytrustnfe.client import get_authenticated_client from pytrustnfe.client import get_authenticated_client
from pytrustnfe.certificado import converte_pfx_pem, save_cert_key from pytrustnfe.certificado import converte_pfx_pem, save_cert_key
from signxml import xmldsig
from signxml import methods
def sign_xml(xml, cert, key):
parser = etree.XMLParser(remove_blank_text=True, remove_comments=True)
elem = etree.fromstring(xml, parser=parser)
root = etree.Element('root')
rps = elem.find('RPS')
signer = xmldsig(rps, digest_algorithm=u'sha1')
ns = {}
ns[None] = signer.namespaces['ds']
signer.namespaces = ns
signed_root = signer.sign(
key=str(key), cert=cert,
algorithm="rsa-sha1", method=methods.enveloped,
c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
root.append(
signed_root.find('{http://www.w3.org/2000/09/xmldsig#}Signature'))
elem.append(signed_root)
elem.append(root.find('{http://www.w3.org/2000/09/xmldsig#}Signature'))
return etree.tostring(elem)
def _send(certificado, method, **kwargs): def _send(certificado, method, **kwargs):
# A little hack to test # A little hack to test
path = os.path.join(os.path.dirname(__file__), 'templates') path = os.path.join(os.path.dirname(__file__), 'templates')
if method == 'teste_envio_lote_rps':
xml = render_xml(path, 'envio_lote_rps.xml', **kwargs)
if method == 'TesteEnvioLoteRPS':
xml = render_xml(path, 'EnvioLoteRPS.xml', **kwargs)
else: else:
xml = render_xml(path, '%s.xml' % method, **kwargs) xml = render_xml(path, '%s.xml' % method, **kwargs)
base_url = 'https://nfe.prefeitura.sp.gov.br/ws/lotenfe.asmx?wsdl' base_url = 'https://nfe.prefeitura.sp.gov.br/ws/lotenfe.asmx?wsdl'
cert, key = converte_pfx_pem(certificado.pfx, certificado.password) cert, key = converte_pfx_pem(certificado.pfx, certificado.password)
cert, key = save_cert_key(cert, key)eh
client = get_authenticated_client(base_url, cert, key)
cert_path, key_path = save_cert_key(cert, key)
client = get_authenticated_client(base_url, cert_path, key_path)
xml_signed = sign_xml(xml, cert, key)
try: try:
response = getattr(client.service, method)(1, xml)
response = getattr(client.service, method)(1, xml_signed)
except suds.WebFault, e: except suds.WebFault, e:
response = e.fault.faultstring
return response
return {
'sent_xml': xml_signed,
'received_xml': e.fault.faultstring,
'object': None
}
response, obj = sanitize_response(response)
return {
'sent_xml': xml_signed,
'received_xml': response,
'object': obj
}
def envio_rps(certificado, **kwargs): def envio_rps(certificado, **kwargs):
return _send(certificado, 'envio_rps', **kwargs)
return _send(certificado, 'EnvioRPS', **kwargs)
def envio_lote_rps(certificado, **kwargs): def envio_lote_rps(certificado, **kwargs):
return _send(certificado, 'envio_lote_rps', **kwargs)
return _send(certificado, 'EnvioLoteRPS', **kwargs)
def teste_envio_lote_rps(certificado, **kwargs): def teste_envio_lote_rps(certificado, **kwargs):
return _send(certificado, 'TesteEnvioLoteRPS', **kwargs) return _send(certificado, 'TesteEnvioLoteRPS', **kwargs)
def cancelamento_nfe(certificado, **kwargs): def cancelamento_nfe(certificado, **kwargs):
return _send(certificado, 'cancelamento_n_fe', **kwargs)
return _send(certificado, 'CancelamentoNFe', **kwargs)
def consulta_nfe(certificado, **kwargs): def consulta_nfe(certificado, **kwargs):
return _send('consulta_n_fe', **kwargs)
return _send('ConsultaNFe', **kwargs)
def consulta_nfe_recebidas(certificado, **kwargs): def consulta_nfe_recebidas(certificado, **kwargs):
return _send('consulta_n_fe_recebidas', **kwargs)
return _send('ConsultaNFeRecebidas', **kwargs)
def consulta_nfe_emitidas(data=None): def consulta_nfe_emitidas(data=None):
return _send('consulta_n_fe_emitidas', data)
return _send('ConsultaNFeEmitidas', data)
def consulta_lote(data=None): def consulta_lote(data=None):
return _send('consulta_lote', data)
return _send('ConsultaLote', data)
def consulta_informacoes_lote(data=None): def consulta_informacoes_lote(data=None):
return _send('consulta_informacoes_lote', data)
return _send('ConsultaInformacoesLote', data)
def consulta_cnpj(data=None): def consulta_cnpj(data=None):
return _send('consulta_cnpj', data)
return _send('ConsultaCNPJ', data)

0
pytrustnfe/nfse/paulistana/templates/cancelamento.xml → pytrustnfe/nfse/paulistana/templates/CancelamentoNFe.xml

0
pytrustnfe/nfse/paulistana/templates/consulta_cnpj.xml → pytrustnfe/nfse/paulistana/templates/ConsultaCNPJ.xml

0
pytrustnfe/nfse/paulistana/templates/ConsultaInformacoesLote.xml

0
pytrustnfe/nfse/paulistana/templates/consulta_lote.xml → pytrustnfe/nfse/paulistana/templates/ConsultaLote.xml

0
pytrustnfe/nfse/paulistana/templates/consulta_nfse_por_rps.xml → pytrustnfe/nfse/paulistana/templates/ConsultaNFe.xml

0
pytrustnfe/nfse/paulistana/templates/ConsultaNFeEmitidas.xml

58
pytrustnfe/nfse/paulistana/templates/EnvioLoteRPS.xml

@ -0,0 +1,58 @@
<PedidoEnvioLoteRPS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.prefeitura.sp.gov.br/nfe">
<Cabecalho Versao="1" xmlns="">
<CPFCNPJRemetente>
<CNPJ>{{ nfse.cpf_cnpj }}</CNPJ>
</CPFCNPJRemetente>
<transacao>false</transacao>
<dtInicio>2016-02-08</dtInicio>
<dtFim>2016-02-08</dtFim>
<QtdRPS>1</QtdRPS>
<ValorTotalServicos>{{ nfse.total_servicos }}</ValorTotalServicos>
<ValorTotalDeducoes>{{ nfse.total_deducoes }}</ValorTotalDeducoes>
</Cabecalho>
{% for rps in nfse.lista_rps -%}
<RPS xmlns="">
<Assinatura>{{ rps.assinatura }}</Assinatura>
<ChaveRPS>
<InscricaoPrestador>{{ rps.prestador.inscricao_municipal }}</InscricaoPrestador>
<SerieRPS>{{ rps.serie }}</SerieRPS>
<NumeroRPS>{{ rps.numero }}</NumeroRPS>
</ChaveRPS>
<TipoRPS>RPS</TipoRPS>
<DataEmissao>{{ rps.data_emissao }}</DataEmissao>
<StatusRPS>N</StatusRPS>
<TributacaoRPS>T</TributacaoRPS>
<ValorServicos>1000</ValorServicos>
<ValorDeducoes>0.00</ValorDeducoes>
<ValorPIS>0.00</ValorPIS>
<ValorCOFINS>0.00</ValorCOFINS>
<ValorINSS>0.00</ValorINSS>
<ValorIR>0.00</ValorIR>
<ValorCSLL>0.00</ValorCSLL>
<CodigoServico>{{ rps.codigo_atividade }}</CodigoServico>
<AliquotaServicos>{{ rps.aliquota_atividade }}</AliquotaServicos>
<ISSRetido>false</ISSRetido>
<CPFCNPJTomador>
{% if rps.tomador.tipo_cpfcnpj == 1 -%}
<CPF>{{ rps.tomador.cpf_cnpj }}</CPF>
{% endif %}
{% if rps.tomador.tipo_cpfcnpj == 2 -%}
<CNPJ>{{ rps.tomador.cpf_cnpj }}</CNPJ>
{% endif %}
</CPFCNPJTomador>
<InscricaoMunicipalTomador>23354900</InscricaoMunicipalTomador>
<RazaoSocialTomador>{{ rps.tomador.razao_social }}</RazaoSocialTomador>
<EnderecoTomador>
<TipoLogradouro>{{ rps.tomador.tipo_logradouro }}</TipoLogradouro>
<Logradouro>{{ rps.tomador.logradouro }}</Logradouro>
<NumeroEndereco>{{ rps.tomador.numero }}</NumeroEndereco>
<ComplementoEndereco>{{ rps.tomador.complemento }}</ComplementoEndereco>
<Bairro>{{ rps.tomador.bairro }}</Bairro>
<Cidade>{{ rps.tomador.cidade }}</Cidade>
<UF>{{ rps.tomador.uf }}</UF>
<CEP>{{ rps.tomador.cep }}</CEP>
</EnderecoTomador>
<Discriminacao>{{ rps.descricao }}</Discriminacao>
</RPS>
{% endfor %}
</PedidoEnvioLoteRPS>

0
pytrustnfe/nfse/paulistana/templates/envio_rps.xml → pytrustnfe/nfse/paulistana/templates/EnvioRPS.xml

82
pytrustnfe/nfse/paulistana/templates/TesteEnvioLoteRPS.xml

@ -1,82 +0,0 @@
<PedidoEnvioLoteRPS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.prefeitura.sp.gov.br/nfe">
<Cabecalho xmlns="" Versao="1">
<CPFCNPJRemetente>
<CNPJ>{{ nfse.cpf_cnpj }}</CNPJ>
</CPFCNPJRemetente>
<transacao>false</transacao>
<dtInicio>2016-02-08</dtInicio>
<dtFim>2016-02-08</dtFim>
<QtdRPS>1</QtdRPS>
<ValorTotalServicos>{{ nfse.total_servicos }}</ValorTotalServicos>
<ValorTotalDeducoes>{{ nfse.total_deducoes }}</ValorTotalDeducoes>
</Cabecalho>
{% for rps in nfse.lista_rps -%}
<RPS xmlns="">
<Assinatura>31000000OL03 00000000000120070103TNN00000000205000000000000050000002658100013167474254</Assinatura>
<ChaveRPS>
<InscricaoPrestador>{{ rps.prestador.inscricao_municipal }}</InscricaoPrestador>
<SerieRPS>{{ rps.serie }}</SerieRPS>
<NumeroRPS>{{ rps.numero }}</NumeroRPS>
</ChaveRPS>
<TipoRPS>RPS</TipoRPS>
<DataEmissao>{{ rps.data_emissao }}</DataEmissao>
<StatusRPS>N</StatusRPS>
<TributacaoRPS>T</TributacaoRPS>
<ValorServicos>1000</ValorServicos>
<ValorDeducoes>0.00</ValorDeducoes>
<ValorPIS>0.00</ValorPIS>
<ValorCOFINS>0.00</ValorCOFINS>
<ValorINSS>0.00</ValorINSS>
<ValorIR>0.00</ValorIR>
<ValorCSLL>0.00</ValorCSLL>
<CodigoServico>{{ rps.codigo_atividade }}</CodigoServico>
<AliquotaServicos>{{ rps.aliquota_atividade }}</AliquotaServicos>
<ISSRetido>false</ISSRetido>
<CPFCNPJTomador>
{% if rps.tomador.tipo_cpfcnpj == 1 -%}
<CPF>{{ rps.tomador.cpf_cnpj }}</CPF>
{% endif %}
{% if rps.tomador.tipo_cpfcnpj == 2 -%}
<CNPJ>{{ rps.tomador.cpf_cnpj }}</CNPJ>
{% endif %}
</CPFCNPJTomador>
<InscricaoMunicipalTomador>23354900</InscricaoMunicipalTomador>
<RazaoSocialTomador>{{ rps.tomador.razao_social }}</RazaoSocialTomador>
<EnderecoTomador>
<TipoLogradouro>{{ rps.tomador.tipo_logradouro }}</TipoLogradouro>
<Logradouro>{{ rps.tomador.logradouro }}</Logradouro>
<NumeroEndereco>{{ rps.tomador.numero }}</NumeroEndereco>
<ComplementoEndereco>{{ rps.tomador.complemento }}</ComplementoEndereco>
<Bairro>{{ rps.tomador.bairro }}</Bairro>
<Cidade>{{ rps.tomador.cidade }}</Cidade>
<UF>{{ rps.tomador.uf }}</UF>
<CEP>{{ rps.tomador.cep }}</CEP>
</EnderecoTomador>
<Discriminacao>{{ rps.descricao }}</Discriminacao>
</RPS>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>AkHyCjCwkANg3aRAnltAXR1YQ4c=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>
IkLB0qfZLDuTNXNB83tXXsZ2TFNK9X0l7gq8jRCOcwhit059iF5gNHfmuM4NoUhyhZ+rC6UGn9lSMv1A35lofsplIuWUJO13yPtHsxaY6/rP9DTB4Ve3ihzwrEkpenANoEU1C5wLenX0lRtYc1k3fWeDmZUvv+b/M81pwoPBL8k=
</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>
MIIFUzCCBDugAwIBAgIQSUJS8pELZyjasDkgGzKm0TANBgkqhkiG9w0BAQUFADBuMQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDEsMCoGA1UECxMjU2VjcmV0YXJpYSBkYSBSZWNlaXRhIEZlZGVyYWwgLSBTUkYxHDAaBgNVBAMTE0FDIENlcnRpU2lnbiBTUkYgVjMwHhcNMDYwNzE5MDAwMDAwWhcNMDkwNzE4MjM1OTU5WjCB1DELMAkGA1UEBhMCQlIxEzARBgNVBAoUCklDUC1CcmFzaWwxKjAoBgNVBAsTIVNlY3JldGFyaWEgZGEgUmVjZWl0YSBGZWRlcmFsLVNSRjETMBEGA1UECxQKU1JGIGUtQ05QSjELMAkGA1UECBMCUkoxFzAVBgNVBAcUDlJJTyBERSBKQU5FSVJPMUkwRwYDVQQDE0BUSVBMQU4gQ09OU1VMVE9SSUEgRSBTRVJWSUNPUyBFTSBJTkZPUk1BVElDQSBMVERBOjA0NjQyNTU0MDAwMTQzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCx86LAoJRVmtQMzmtdWpyNgKy200+bwjtz/TuywNcTjvfw7qHFGIgTjipmuZ3zhX28CgYLYXp3tj1Dfh2B7EhjHdLJPfvoF4MgbN/dQGXmGpMpF5cNxYusOGCZiyASvI7Gqt/xE4xLSIalNr6kF6CaPLkpFgTNNe+WQkG0fMqsQQIDAQABo4ICCDCCAgQwgbEGA1UdEQSBqTCBpqA/BgVgTAEDBKA2DDQyNDA3MTk3NjA3MTM4NTM3Nzg2MDAwMDAwMDAwMDAwMDAwMDAwOTI5OTA2MjFDTkggIFJKoB8GBWBMAQMCoBYMFEZFUk5BTkRPIFNJTFZBIEJSQUdBoBkGBWBMAQMDoBAMDjA0NjQyNTU0MDAwMTQzoBEGBWBMAQMHoAgMBjIzOTU0OIEUZmJyYWdhQHRpcGxhbi5jb20uYnIwCQYDVR0TBAIwADBiBgNVHR8EWzBZMFegVaBThlFodHRwOi8vaWNwLWJyYXNpbC5jZXJ0aXNpZ24uY29tLmJyL3JlcG9zaXRvcmlvL2xjci9BQ0NlcnRpU2lnblNSRlYzL0xhdGVzdENSTC5jcmwwHwYDVR0jBBgwFoAU9p1ZXf6/xXLN3c7ELmYbLu4Iz3YwDgYDVR0PAQH/BAQDAgXgMFUGA1UdIAROMEwwSgYGYEwBAgMGMEAwPgYIKwYBBQUHAgEWMmh0dHA6Ly9pY3AtYnJhc2lsLmNlcnRpc2lnbi5jb20uYnIvcmVwb3NpdG9yaW8vZHBjMB0GA1UdJQQWMBQGCCsGAQUFBwMEBggrBgEFBQcDAjA4BggrBgEFBQcBAQQsMCowKAYIKwYBBQUHMAGGHGh0dHA6Ly9vY3NwLmNlcnRpc2lnbi5jb20uYnIwDQYJKoZIhvcNAQEFBQADggEBAC5w/CBXAykvPSbBGf+u0UPcWVJATL2ix0hCfNUVtHaCjMz8hRjgYqmhpefzDm2LCTvoCPzG6XQBYxAmnDhX1f/gyjHz+E1xJg451qtqcyCJ9861o9R2bHd4zR0DuyxCNGOTiYJ4Gc/Xa4xqECorAx5ktkk1T/HOc1K/ntRGpdL+llsO/jqSRmTOnRgdeNHcKkyXsOgL5BwxxgGNuIyqirgGXW0by4Io1GnSXtixxfvEOnqOicxBY6AcVS9HHuhmOBYiK9skAUp0Sm2v41hpsC8uIkfUeRxsJIp2CNZ4DjoyfmKwNLMCRZQAKpwMXyyHZlX1a4o/9iGTszNeeShw61g=
</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
{% endfor %}
</PedidoEnvioLoteRPS>

22
pytrustnfe/xml/__init__.py

@ -1,5 +1,10 @@
import os.path import os.path
import unicodedata
from lxml import etree from lxml import etree
from StringIO import StringIO
from lxml import objectify
import xml.etree.ElementTree as ET
from jinja2 import Environment, FileSystemLoader from jinja2 import Environment, FileSystemLoader
from . import filters from . import filters
@ -22,6 +27,23 @@ def render_xml(path, template_name, **nfe):
return etree.tostring(elem) return etree.tostring(elem)
def sanitize_response(response):
response = unicode(response)
response = unicodedata.normalize('NFKD', response).encode('ascii',
'ignore')
tree = etree.fromstring(response)
# Remove namespaces inuteis na resposta
for elem in tree.getiterator():
if not hasattr(elem.tag, 'find'):
continue
i = elem.tag.find('}')
if i >= 0:
elem.tag = elem.tag[i+1:]
objectify.deannotate(tree, cleanup_namespaces=True)
return response, objectify.fromstring(etree.tostring(tree))
def valida_schema(xml, arquivo_xsd): def valida_schema(xml, arquivo_xsd):
'''Função que valida um XML usando lxml do Python via arquivo XSD''' '''Função que valida um XML usando lxml do Python via arquivo XSD'''
# Carrega o esquema XML do arquivo XSD # Carrega o esquema XML do arquivo XSD

Loading…
Cancel
Save