Browse Source

Primeira NFSe de SP emitida em ambiente de teste.

Faltam ainda validações e melhorias no código e implementação de outros metodos
tags/0.1.5
Danimar Ribeiro 9 years ago
parent
commit
0ae9da3622
  1. 9
      pytrustnfe/certificado.py
  2. 4
      pytrustnfe/nfe/__init__.py
  3. 28
      pytrustnfe/nfe/assinatura.py
  4. 42
      pytrustnfe/nfse/paulistana/__init__.py
  5. 12
      pytrustnfe/nfse/paulistana/templates/EnvioLoteRPS.xml

9
pytrustnfe/certificado.py

@ -4,7 +4,6 @@
from uuid import uuid4
import os.path
from OpenSSL import crypto
@ -13,6 +12,13 @@ class Certificado(object):
self.pfx = pfx
self.password = password
def save_pfx(self):
pfx_temp = '/tmp/' + uuid4().hex
arq_temp = open(pfx_temp, 'w')
arq_temp.write(self.pfx)
arq_temp.close()
return pfx_temp
def extract_cert_and_key_from_pfx(pfx, password):
pfx = crypto.load_pkcs12(pfx, password)
@ -25,6 +31,7 @@ def extract_cert_and_key_from_pfx(pfx, password):
return cert, key
def save_cert_key(cert, key):
cert_temp = '/tmp/' + uuid4().hex
key_temp = '/tmp/' + uuid4().hex

4
pytrustnfe/nfe/__init__.py

@ -6,7 +6,7 @@
import os
from lxml import etree
from .comunicacao import Comunicacao
from .assinatura import assinar, Assinatura
from .assinatura import sign_xml, Assinatura
from pytrustnfe import utils
from pytrustnfe.xml import render_xml
@ -40,7 +40,7 @@ class NFe(Comunicacao):
xml = render_xml(path, 'nfeEnv.xml', **nfe)
xmlElem = etree.fromstring(xml)
xml_signed = assinar(xmlElem, self.cert, self.key, '#%s' % nfe_id)
xml_signed = sign_xml(xmlElem, self.cert, self.key, '#%s' % nfe_id)
xml_response, obj = self._executar_consulta(xml_signed)

28
pytrustnfe/nfe/assinatura.py

@ -31,27 +31,21 @@ def recursively_empty(e):
return all((recursively_empty(c) for c in e.iterchildren()))
def assinar(xml, cert, key, reference):
context = etree.iterwalk(xml)
for dummy, elem in context:
parent = elem.getparent()
if recursively_empty(elem):
parent.remove(elem)
element = xml.find('{' + xml.nsmap[None] + '}NFe')
def sign_xml(xml, cert, key):
parser = etree.XMLParser(remove_blank_text=True, remove_comments=True)
elem = etree.fromstring(xml, parser=parser)
signer = XMLSigner(
digest_algorithm=u'sha1', signature_algorithm="rsa-sha1",
method=methods.enveloped,
method=methods.enveloping,
c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
ns = {}
ns[None] = signer.namespaces['ds']
signer.namespaces = ns
signed_root = signer.sign(element, key=str(key), cert=cert,
reference_uri=reference)
signed_root = signer.sign(elem, key=str(key), cert=cert)
return etree.tostring(signed_root)
xml.remove(element)
xml.append(signed_root)
return etree.tostring(xml)
class Assinatura(object):
@ -84,12 +78,12 @@ class Assinatura(object):
self._inicializar_cripto()
try:
doc_xml = libxml2.parseMemory(
xml.encode('utf-8'), len(xml.encode('utf-8')))
xml, len(xml))
signNode = xmlsec.TmplSignature(doc_xml, xmlsec.transformInclC14NId(),
xmlsec.transformRsaSha1Id(), None)
doc_xml.getLastChild().addChild(signNode)
doc_xml.getRootElement().addChild(signNode)
refNode = signNode.addReference(xmlsec.transformSha1Id(),
None, reference, None)
@ -129,4 +123,4 @@ class Assinatura(object):
return xml
finally:
doc_xml.freeDoc()
self._finalizar_cripto()
# self._finalizar_cripto()

42
pytrustnfe/nfse/paulistana/__init__.py

@ -5,44 +5,30 @@
import os
import logging
import suds
from OpenSSL import crypto
from base64 import b64encode, b64decode
from uuid import uuid4
from lxml import etree
from pytrustnfe.xml import render_xml, valida_schema, sanitize_response
from pytrustnfe.client import get_authenticated_client
from pytrustnfe.certificado import extract_cert_and_key_from_pfx, save_cert_key
from pytrustnfe.nfe.assinatura import Assinatura
from signxml import XMLSigner
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 = XMLSigner(
digest_algorithm=u'sha1', signature_algorithm="rsa-sha1",
method=methods.enveloped,
c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
ns = {}
ns[None] = signer.namespaces['ds']
signer.namespaces = ns
signed_root = signer.sign(rps, key=str(key), cert=cert)
root.append(
signed_root.find('{http://www.w3.org/2000/09/xmldsig#}Signature'))
elem.remove(rps)
elem.append(signed_root)
elem.append(root.find('{http://www.w3.org/2000/09/xmldsig#}Signature'))
return etree.tostring(elem)
def sign_tag(certificado, **kwargs):
pkcs12 = crypto.load_pkcs12(certificado.pfx, certificado.password)
key = pkcs12.get_privatekey()
for item in kwargs['nfse']['lista_rps']:
signed = crypto.sign(key, item['assinatura'], 'SHA1')
item['assinatura'] = b64encode(signed)
def _send(certificado, method, **kwargs):
# A little hack to test
path = os.path.join(os.path.dirname(__file__), 'templates')
if method == 'TesteEnvioLoteRPS' or method == 'EnvioLoteRPS':
sign_tag(certificado, **kwargs)
if method == 'TesteEnvioLoteRPS':
xml = render_xml(path, 'EnvioLoteRPS.xml', **kwargs)
else:
@ -54,7 +40,9 @@ def _send(certificado, method, **kwargs):
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)
pfx_path = certificado.save_pfx()
signer = Assinatura(pfx_path, certificado.password)
xml_signed = signer.assina_xml(xml, '')
try:
response = getattr(client.service, method)(1, xml_signed)

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

@ -4,8 +4,8 @@
<CNPJ>{{ nfse.cpf_cnpj }}</CNPJ>
</CPFCNPJRemetente>
<transacao>false</transacao>
<dtInicio>2016-02-08</dtInicio>
<dtFim>2016-02-08</dtFim>
<dtInicio>{{ nfse.data_inicio }}</dtInicio>
<dtFim>{{ nfse.data_fim }}</dtFim>
<QtdRPS>1</QtdRPS>
<ValorTotalServicos>{{ nfse.total_servicos }}</ValorTotalServicos>
<ValorTotalDeducoes>{{ nfse.total_deducoes }}</ValorTotalDeducoes>
@ -22,8 +22,8 @@
<DataEmissao>{{ rps.data_emissao }}</DataEmissao>
<StatusRPS>N</StatusRPS>
<TributacaoRPS>T</TributacaoRPS>
<ValorServicos>1000</ValorServicos>
<ValorDeducoes>0.00</ValorDeducoes>
<ValorServicos>{{ rps.valor_servico }}</ValorServicos>
<ValorDeducoes>{{ rps.valor_deducao }}</ValorDeducoes>
<ValorPIS>0.00</ValorPIS>
<ValorCOFINS>0.00</ValorCOFINS>
<ValorINSS>0.00</ValorINSS>
@ -40,7 +40,9 @@
<CNPJ>{{ rps.tomador.cpf_cnpj }}</CNPJ>
{% endif %}
</CPFCNPJTomador>
<InscricaoMunicipalTomador>23354900</InscricaoMunicipalTomador>
{% if rps.tomador.inscricao_municipal -%}
<InscricaoMunicipalTomador>{{ rps.tomador.inscricao_municipal }}</InscricaoMunicipalTomador>
{% endif %}
<RazaoSocialTomador>{{ rps.tomador.razao_social }}</RazaoSocialTomador>
<EnderecoTomador>
<TipoLogradouro>{{ rps.tomador.tipo_logradouro }}</TipoLogradouro>

Loading…
Cancel
Save