diff --git a/pytrustnfe/nfse/paulistana/__init__.py b/pytrustnfe/nfse/paulistana/__init__.py
index b31e95f..7bc1a87 100644
--- a/pytrustnfe/nfse/paulistana/__init__.py
+++ b/pytrustnfe/nfse/paulistana/__init__.py
@@ -1,59 +1,107 @@
import os
import logging
import suds
+from uuid import uuid4
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.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):
# A little hack to test
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:
xml = render_xml(path, '%s.xml' % method, **kwargs)
-
base_url = 'https://nfe.prefeitura.sp.gov.br/ws/lotenfe.asmx?wsdl'
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:
- response = getattr(client.service, method)(1, xml)
+ response = getattr(client.service, method)(1, xml_signed)
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):
- return _send(certificado, 'envio_rps', **kwargs)
+ return _send(certificado, 'EnvioRPS', **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):
return _send(certificado, 'TesteEnvioLoteRPS', **kwargs)
+
def cancelamento_nfe(certificado, **kwargs):
- return _send(certificado, 'cancelamento_n_fe', **kwargs)
+ return _send(certificado, 'CancelamentoNFe', **kwargs)
+
def consulta_nfe(certificado, **kwargs):
- return _send('consulta_n_fe', **kwargs)
+ return _send('ConsultaNFe', **kwargs)
+
def consulta_nfe_recebidas(certificado, **kwargs):
- return _send('consulta_n_fe_recebidas', **kwargs)
+ return _send('ConsultaNFeRecebidas', **kwargs)
+
def consulta_nfe_emitidas(data=None):
- return _send('consulta_n_fe_emitidas', data)
+ return _send('ConsultaNFeEmitidas', data)
+
def consulta_lote(data=None):
- return _send('consulta_lote', data)
+ return _send('ConsultaLote', data)
+
def consulta_informacoes_lote(data=None):
- return _send('consulta_informacoes_lote', data)
+ return _send('ConsultaInformacoesLote', data)
+
def consulta_cnpj(data=None):
- return _send('consulta_cnpj', data)
+ return _send('ConsultaCNPJ', data)
diff --git a/pytrustnfe/nfse/paulistana/templates/cancelamento.xml b/pytrustnfe/nfse/paulistana/templates/CancelamentoNFe.xml
similarity index 100%
rename from pytrustnfe/nfse/paulistana/templates/cancelamento.xml
rename to pytrustnfe/nfse/paulistana/templates/CancelamentoNFe.xml
diff --git a/pytrustnfe/nfse/paulistana/templates/consulta_cnpj.xml b/pytrustnfe/nfse/paulistana/templates/ConsultaCNPJ.xml
similarity index 100%
rename from pytrustnfe/nfse/paulistana/templates/consulta_cnpj.xml
rename to pytrustnfe/nfse/paulistana/templates/ConsultaCNPJ.xml
diff --git a/pytrustnfe/nfse/paulistana/templates/ConsultaInformacoesLote.xml b/pytrustnfe/nfse/paulistana/templates/ConsultaInformacoesLote.xml
new file mode 100644
index 0000000..e69de29
diff --git a/pytrustnfe/nfse/paulistana/templates/consulta_lote.xml b/pytrustnfe/nfse/paulistana/templates/ConsultaLote.xml
similarity index 100%
rename from pytrustnfe/nfse/paulistana/templates/consulta_lote.xml
rename to pytrustnfe/nfse/paulistana/templates/ConsultaLote.xml
diff --git a/pytrustnfe/nfse/paulistana/templates/consulta_nfse_por_rps.xml b/pytrustnfe/nfse/paulistana/templates/ConsultaNFe.xml
similarity index 100%
rename from pytrustnfe/nfse/paulistana/templates/consulta_nfse_por_rps.xml
rename to pytrustnfe/nfse/paulistana/templates/ConsultaNFe.xml
diff --git a/pytrustnfe/nfse/paulistana/templates/ConsultaNFeEmitidas.xml b/pytrustnfe/nfse/paulistana/templates/ConsultaNFeEmitidas.xml
new file mode 100644
index 0000000..e69de29
diff --git a/pytrustnfe/nfse/paulistana/templates/EnvioLoteRPS.xml b/pytrustnfe/nfse/paulistana/templates/EnvioLoteRPS.xml
new file mode 100644
index 0000000..5cc5e67
--- /dev/null
+++ b/pytrustnfe/nfse/paulistana/templates/EnvioLoteRPS.xml
@@ -0,0 +1,58 @@
+
+
+
+ {{ nfse.cpf_cnpj }}
+
+ false
+ 2016-02-08
+ 2016-02-08
+ 1
+ {{ nfse.total_servicos }}
+ {{ nfse.total_deducoes }}
+
+ {% for rps in nfse.lista_rps -%}
+
+ {{ rps.assinatura }}
+
+ {{ rps.prestador.inscricao_municipal }}
+ {{ rps.serie }}
+ {{ rps.numero }}
+
+ RPS
+ {{ rps.data_emissao }}
+ N
+ T
+ 1000
+ 0.00
+ 0.00
+ 0.00
+ 0.00
+ 0.00
+ 0.00
+ {{ rps.codigo_atividade }}
+ {{ rps.aliquota_atividade }}
+ false
+
+ {% if rps.tomador.tipo_cpfcnpj == 1 -%}
+ {{ rps.tomador.cpf_cnpj }}
+ {% endif %}
+ {% if rps.tomador.tipo_cpfcnpj == 2 -%}
+ {{ rps.tomador.cpf_cnpj }}
+ {% endif %}
+
+ 23354900
+ {{ rps.tomador.razao_social }}
+
+ {{ rps.tomador.tipo_logradouro }}
+ {{ rps.tomador.logradouro }}
+ {{ rps.tomador.numero }}
+ {{ rps.tomador.complemento }}
+ {{ rps.tomador.bairro }}
+ {{ rps.tomador.cidade }}
+ {{ rps.tomador.uf }}
+ {{ rps.tomador.cep }}
+
+ {{ rps.descricao }}
+
+ {% endfor %}
+
diff --git a/pytrustnfe/nfse/paulistana/templates/envio_rps.xml b/pytrustnfe/nfse/paulistana/templates/EnvioRPS.xml
similarity index 100%
rename from pytrustnfe/nfse/paulistana/templates/envio_rps.xml
rename to pytrustnfe/nfse/paulistana/templates/EnvioRPS.xml
diff --git a/pytrustnfe/nfse/paulistana/templates/TesteEnvioLoteRPS.xml b/pytrustnfe/nfse/paulistana/templates/TesteEnvioLoteRPS.xml
deleted file mode 100644
index f657b75..0000000
--- a/pytrustnfe/nfse/paulistana/templates/TesteEnvioLoteRPS.xml
+++ /dev/null
@@ -1,82 +0,0 @@
-
-
-
- {{ nfse.cpf_cnpj }}
-
- false
- 2016-02-08
- 2016-02-08
- 1
- {{ nfse.total_servicos }}
- {{ nfse.total_deducoes }}
-
- {% for rps in nfse.lista_rps -%}
-
- 31000000OL03 00000000000120070103TNN00000000205000000000000050000002658100013167474254
-
- {{ rps.prestador.inscricao_municipal }}
- {{ rps.serie }}
- {{ rps.numero }}
-
- RPS
- {{ rps.data_emissao }}
- N
- T
- 1000
- 0.00
- 0.00
- 0.00
- 0.00
- 0.00
- 0.00
- {{ rps.codigo_atividade }}
- {{ rps.aliquota_atividade }}
- false
-
- {% if rps.tomador.tipo_cpfcnpj == 1 -%}
- {{ rps.tomador.cpf_cnpj }}
- {% endif %}
- {% if rps.tomador.tipo_cpfcnpj == 2 -%}
- {{ rps.tomador.cpf_cnpj }}
- {% endif %}
-
- 23354900
- {{ rps.tomador.razao_social }}
-
- {{ rps.tomador.tipo_logradouro }}
- {{ rps.tomador.logradouro }}
- {{ rps.tomador.numero }}
- {{ rps.tomador.complemento }}
- {{ rps.tomador.bairro }}
- {{ rps.tomador.cidade }}
- {{ rps.tomador.uf }}
- {{ rps.tomador.cep }}
-
- {{ rps.descricao }}
-
-
-
-
-
-
-
-
-
-
-
-AkHyCjCwkANg3aRAnltAXR1YQ4c=
-
-
-
-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
-
-
-
-
- {% endfor %}
-
diff --git a/pytrustnfe/xml/__init__.py b/pytrustnfe/xml/__init__.py
index 8f5c95a..145731f 100644
--- a/pytrustnfe/xml/__init__.py
+++ b/pytrustnfe/xml/__init__.py
@@ -1,5 +1,10 @@
import os.path
+import unicodedata
from lxml import etree
+
+from StringIO import StringIO
+from lxml import objectify
+import xml.etree.ElementTree as ET
from jinja2 import Environment, FileSystemLoader
from . import filters
@@ -22,6 +27,23 @@ def render_xml(path, template_name, **nfe):
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):
'''Função que valida um XML usando lxml do Python via arquivo XSD'''
# Carrega o esquema XML do arquivo XSD