diff --git a/pytrustnfe/Certificado.py b/pytrustnfe/certificado.py similarity index 63% rename from pytrustnfe/Certificado.py rename to pytrustnfe/certificado.py index 1d37302..a2485b9 100644 --- a/pytrustnfe/Certificado.py +++ b/pytrustnfe/certificado.py @@ -8,12 +8,15 @@ import os.path from OpenSSL import crypto -def converte_pfx_pem(caminho, senha): - if not os.path.isfile(caminho): - raise Exception('Certificado não existe') - stream = open(caminho, 'rb').read() +class Certificado(object): + def __init__(self, pfx, password): + self.pfx = pfx + self.password = password + + +def converte_pfx_pem(pfx_stream, senha): try: - certificado = crypto.load_pkcs12(stream, senha) + certificado = crypto.load_pkcs12(pfx_stream, senha) privada = crypto.dump_privatekey(crypto.FILETYPE_PEM, certificado.get_privatekey()) @@ -21,7 +24,7 @@ def converte_pfx_pem(caminho, senha): certificado.get_certificate()) except Exception as e: if len(e.message) == 1 and len(e.message[0]) == 3 and \ - e.message[0][2] == 'mac verify failure': + e.message[0][2] == 'mac verify failure': raise Exception('Senha inválida') raise - return privada, certificado + return certificado, privada diff --git a/pytrustnfe/client.py b/pytrustnfe/client.py new file mode 100644 index 0000000..7e4ad4e --- /dev/null +++ b/pytrustnfe/client.py @@ -0,0 +1,31 @@ + +import requests +import suds.client +import suds_requests + + +def get_authenticated_client(base_url, key_p, cert): + 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, + transport=suds_requests.RequestsTransport(session) + ) + + +def get_client(base_url): + cache_location = '/tmp/suds' + cache = suds.cache.DocumentCache(location=cache_location) + + session = requests.Session() + + return suds.client.Client( + base_url, + cache=cache, + transport=suds_requests.RequestsTransport(session) + ) diff --git a/pytrustnfe/nfse/paulistana/__init__.py b/pytrustnfe/nfse/paulistana/__init__.py index a978e59..3a6c026 100644 --- a/pytrustnfe/nfse/paulistana/__init__.py +++ b/pytrustnfe/nfse/paulistana/__init__.py @@ -1,27 +1,45 @@ +import os +from pytrustnfe.xml import render_xml +from pytrustnfe.client import get_authenticated_client +from pytrustnfe.certificado import converte_pfx_pem -def _send(method, data): - pass - # TODO Assinar xml e retornar objeto de resposta +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) + else: + xml = render_xml(path, '%s.xml' % method, **kwargs) + base_url = 'https://nfe.prefeitura.sp.gov.br/ws/lotenfe.asmx' -def envio_rps(data=None): - return _send('envio_rps', data) + import ipdb; ipdb.set_trace() + key, cert = converte_pfx_pem(certificado.pfx, certificado.password) + client = get_authenticated_client(base_url, key, cert) -def envio_lote_rps(data=None): - return _send('envio_lote_rps', data) + response = client.teste_envio_lote_rps(xml) -def teste_envio_lote_rps(data=None): - return _send('teste_envio_lote_rps', data) + return response -def cancelamento_nfe(data=None): - return _send('cancelamento_n_fe', data) -def consulta_nfe(data=None): - return _send('consulta_n_fe', data) +def envio_rps(certificado, **kwargs): + return _send(certificado, 'envio_rps', **kwargs) -def consulta_nfe_recebidas(data=None): - return _send('consulta_n_fe_recebidas', data) +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) + +def cancelamento_nfe(certificado, **kwargs): + return _send(certificado, 'cancelamento_n_fe', **kwargs) + +def consulta_nfe(certificado, **kwargs): + return _send('consulta_n_fe', **kwargs) + +def consulta_nfe_recebidas(certificado, **kwargs): + return _send('consulta_n_fe_recebidas', **kwargs) def consulta_nfe_emitidas(data=None): return _send('consulta_n_fe_emitidas', data) @@ -34,4 +52,3 @@ def consulta_informacoes_lote(data=None): def consulta_cnpj(data=None): return _send('consulta_cnpj', data) - diff --git a/pytrustnfe/nfse/paulistana/templates/cancelamento.xml b/pytrustnfe/nfse/paulistana/templates/cancelamento.xml new file mode 100755 index 0000000..886e0a6 --- /dev/null +++ b/pytrustnfe/nfse/paulistana/templates/cancelamento.xml @@ -0,0 +1,18 @@ + + + {{ cancelamento.cidade }} + {{ cancelamento.cpf_cnpj }} + {{ cancelamento.transacao }} + 1 + + + + {{ cancelamento.inscricao_municipal }} + {{ cancelamento.nota_id }} + {{ cancelamento.assinatura }} + {{ cancelamento.motivo }} + + + diff --git a/pytrustnfe/nfse/paulistana/templates/consulta_cnpj.xml b/pytrustnfe/nfse/paulistana/templates/consulta_cnpj.xml new file mode 100644 index 0000000..9b4bbcb --- /dev/null +++ b/pytrustnfe/nfse/paulistana/templates/consulta_cnpj.xml @@ -0,0 +1,12 @@ + + + + {{ nfse.cpf_cnpj }} + + + + 08944335000170 + + diff --git a/pytrustnfe/nfse/paulistana/templates/consulta_lote.xml b/pytrustnfe/nfse/paulistana/templates/consulta_lote.xml new file mode 100755 index 0000000..24afc5d --- /dev/null +++ b/pytrustnfe/nfse/paulistana/templates/consulta_lote.xml @@ -0,0 +1,10 @@ + + + {{ consulta.cidade }} + {{ consulta.cpf_cnpj }} + 1 + {{ consulta.lote }} + + \ No newline at end of file diff --git a/pytrustnfe/nfse/paulistana/templates/consulta_nfse_por_rps.xml b/pytrustnfe/nfse/paulistana/templates/consulta_nfse_por_rps.xml new file mode 100755 index 0000000..676a6fc --- /dev/null +++ b/pytrustnfe/nfse/paulistana/templates/consulta_nfse_por_rps.xml @@ -0,0 +1,19 @@ + + + {{ consulta.cidade }} + {{ consulta.cpf_cnpj }} + {{ consulta.transacao }} + 1 + + + + + {{ consulta.inscricao_municipal }} + {{ consulta.rps_id }} + {{ consulta.serie_prestacao }} + + + + diff --git a/pytrustnfe/nfse/paulistana/templates/envio_lote_rps.xml b/pytrustnfe/nfse/paulistana/templates/envio_lote_rps.xml new file mode 100644 index 0000000..e0cc849 --- /dev/null +++ b/pytrustnfe/nfse/paulistana/templates/envio_lote_rps.xml @@ -0,0 +1,54 @@ + + + + {{ 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/nfse/paulistana/templates/envio_rps.xml b/pytrustnfe/nfse/paulistana/templates/envio_rps.xml new file mode 100644 index 0000000..d828534 --- /dev/null +++ b/pytrustnfe/nfse/paulistana/templates/envio_rps.xml @@ -0,0 +1,51 @@ + + + + {{ nfse.cpf_cnpj }} + + + {% for rps in nfse.lista_rps -%} + + {{ rps.assinatura }} + + {{ rps.prestador.inscricao_municipal }} + {{ rps.serie }} + {{ rps.numero }} + + RPS-M + {{ rps.data_emissao }} + N + T + {{ nfse.total_servicos }} + {{ nfse.total_deducoes }} + {{ rps.valor_pis }} + {{ rps.valor_cofins }} + {{ rps.valor_inss }} + {{ rps.valor_pis }} + {{ rps.valor_csll }} + {{ 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/nfse/paulistana/templates/soap_header.xml b/pytrustnfe/nfse/paulistana/templates/soap_header.xml new file mode 100755 index 0000000..e9d1dd2 --- /dev/null +++ b/pytrustnfe/nfse/paulistana/templates/soap_header.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/pytrustnfe/xml/__init__.py b/pytrustnfe/xml/__init__.py index 759854f..dbac3df 100644 --- a/pytrustnfe/xml/__init__.py +++ b/pytrustnfe/xml/__init__.py @@ -4,8 +4,7 @@ from jinja2 import Environment, FileSystemLoader from . import filters -def render_xml(template_name, **nfe): - path = os.path.dirname(__file__) +def render_xml(path, template_name, **nfe): env = Environment( loader=FileSystemLoader(path), extensions=['jinja2.ext.with_']) @@ -19,4 +18,5 @@ def render_xml(template_name, **nfe): xml = template.render(**nfe) xml = xml.replace('&', '&') parser = etree.XMLParser(remove_blank_text=True, remove_comments=True) - return etree.fromstring(xml, parser=parser) + elem = etree.fromstring(xml, parser=parser) + return etree.tostring(elem) diff --git a/setup.py b/setup.py index 04fa4a2..5daabff 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,8 @@ setup( 'Topic :: Software Development :: Libraries :: Python Modules', ], packages=find_packages(exclude=['*test*']), - package_data={'pytrustnfe': ['xml/*xml']}, + package_data={'pytrustnfe': ['xml/*xml', + 'nfse/paulistana/templates/*xml']}, url='https://github.com/danimaribeiro/PyNfeTrust', license='LGPL-v2.1+', description='PyNfeTrust é uma biblioteca para envio de NF-e',