diff --git a/pytrustnfe/certificado.py b/pytrustnfe/certificado.py
index a2485b9..b385a03 100644
--- a/pytrustnfe/certificado.py
+++ b/pytrustnfe/certificado.py
@@ -4,6 +4,7 @@ Created on Jun 16, 2015
@author: danimar
'''
+from uuid import uuid4
import os.path
from OpenSSL import crypto
@@ -18,13 +19,28 @@ def converte_pfx_pem(pfx_stream, senha):
try:
certificado = crypto.load_pkcs12(pfx_stream, senha)
- privada = crypto.dump_privatekey(crypto.FILETYPE_PEM,
- certificado.get_privatekey())
- certificado = crypto.dump_certificate(crypto.FILETYPE_PEM,
- certificado.get_certificate())
+ cert = crypto.dump_certificate(crypto.FILETYPE_PEM,
+ certificado.get_certificate())
+ key = crypto.dump_privatekey(crypto.FILETYPE_PEM,
+ certificado.get_privatekey())
except Exception as e:
if len(e.message) == 1 and len(e.message[0]) == 3 and \
e.message[0][2] == 'mac verify failure':
raise Exception('Senha inválida')
raise
- return certificado, privada
+ return cert, key
+
+
+def save_cert_key(cert, key):
+ cert_temp = '/tmp/' + uuid4().hex
+ key_temp = '/tmp/' + uuid4().hex
+
+ arq_temp = open(cert_temp, 'w')
+ arq_temp.write(cert)
+ arq_temp.close()
+
+ arq_temp = open(key_temp, 'w')
+ arq_temp.write(key)
+ arq_temp.close()
+
+ return cert_temp, key_temp
diff --git a/pytrustnfe/client.py b/pytrustnfe/client.py
index 7e4ad4e..6bd130b 100644
--- a/pytrustnfe/client.py
+++ b/pytrustnfe/client.py
@@ -4,13 +4,12 @@ import suds.client
import suds_requests
-def get_authenticated_client(base_url, key_p, cert):
+def get_authenticated_client(base_url, cert, key):
cache_location = '/tmp/suds'
cache = suds.cache.DocumentCache(location=cache_location)
session = requests.Session()
session.cert = (cert, key)
-
return suds.client.Client(
base_url,
cache=cache,
diff --git a/pytrustnfe/nfse/paulistana/__init__.py b/pytrustnfe/nfse/paulistana/__init__.py
index 3a6c026..b31e95f 100644
--- a/pytrustnfe/nfse/paulistana/__init__.py
+++ b/pytrustnfe/nfse/paulistana/__init__.py
@@ -1,7 +1,10 @@
import os
-from pytrustnfe.xml import render_xml
+import logging
+import suds
+from lxml import etree
+from pytrustnfe.xml import render_xml, valida_schema
from pytrustnfe.client import get_authenticated_client
-from pytrustnfe.certificado import converte_pfx_pem
+from pytrustnfe.certificado import converte_pfx_pem, save_cert_key
def _send(certificado, method, **kwargs):
@@ -12,14 +15,16 @@ def _send(certificado, method, **kwargs):
else:
xml = render_xml(path, '%s.xml' % method, **kwargs)
- base_url = 'https://nfe.prefeitura.sp.gov.br/ws/lotenfe.asmx'
+ base_url = 'https://nfe.prefeitura.sp.gov.br/ws/lotenfe.asmx?wsdl'
- import ipdb; ipdb.set_trace()
- key, cert = converte_pfx_pem(certificado.pfx, certificado.password)
- client = get_authenticated_client(base_url, key, cert)
-
- response = client.teste_envio_lote_rps(xml)
+ 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)
+ try:
+ response = getattr(client.service, method)(1, xml)
+ except suds.WebFault, e:
+ response = e.fault.faultstring
return response
@@ -30,7 +35,7 @@ def envio_lote_rps(certificado, **kwargs):
return _send(certificado, 'envio_lote_rps', **kwargs)
def teste_envio_lote_rps(certificado, **kwargs):
- return _send(certificado, 'teste_envio_lote_rps', **kwargs)
+ return _send(certificado, 'TesteEnvioLoteRPS', **kwargs)
def cancelamento_nfe(certificado, **kwargs):
return _send(certificado, 'cancelamento_n_fe', **kwargs)
diff --git a/pytrustnfe/nfse/paulistana/templates/TesteEnvioLoteRPS.xml b/pytrustnfe/nfse/paulistana/templates/TesteEnvioLoteRPS.xml
new file mode 100644
index 0000000..f657b75
--- /dev/null
+++ b/pytrustnfe/nfse/paulistana/templates/TesteEnvioLoteRPS.xml
@@ -0,0 +1,82 @@
+
+
+
+ {{ 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/nfse/paulistana/templates/envio_lote_rps.xml b/pytrustnfe/nfse/paulistana/templates/envio_lote_rps.xml
deleted file mode 100644
index e0cc849..0000000
--- a/pytrustnfe/nfse/paulistana/templates/envio_lote_rps.xml
+++ /dev/null
@@ -1,54 +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 -%}
-
- {{ rps.assinatura }}
-
- {{ rps.prestador.inscricao_municipal }}
- {{ rps.serie }}
- {{ rps.numero }}
-
- RPS
- {{ rps.data_emissao }}
- N
- T
- 1000
- 100
- {{ 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 %}
-
- {{ 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/xml/__init__.py b/pytrustnfe/xml/__init__.py
index dbac3df..8f5c95a 100644
--- a/pytrustnfe/xml/__init__.py
+++ b/pytrustnfe/xml/__init__.py
@@ -20,3 +20,30 @@ def render_xml(path, template_name, **nfe):
parser = etree.XMLParser(remove_blank_text=True, remove_comments=True)
elem = etree.fromstring(xml, parser=parser)
return etree.tostring(elem)
+
+
+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
+ xsd = etree.XMLSchema(file=arquivo_xsd)
+ # Converte o XML passado em XML do lxml
+ xml = etree.fromstring(str(xml))
+ # Verifica a validade do xml
+ erros = []
+ if not xsd(xml):
+ # Caso tenha erros, cria uma lista de erros
+ for erro in xsd.error_log:
+ erros.append({
+ 'message': erro.message,
+ 'domain': erro.domain,
+ 'type': erro.type,
+ 'level': erro.level,
+ 'line': erro.line,
+ 'column': erro.column,
+ 'filename': erro.filename,
+ 'domain_name': erro.domain_name,
+ 'type_name': erro.type_name,
+ 'level_name': erro.level_name
+ })
+ # Retorna os erros, sendo uma lista vazia caso não haja erros
+ return erros