Browse Source

Trabalhando na comunicação

tags/0.1
Marinho Brandão 16 years ago
parent
commit
536aecc273
  1. 57
      pynfe/processamento/assinatura.py
  2. 4
      pynfe/processamento/comunicacao.py
  3. 6
      pynfe/processamento/serializacao.py
  4. 2
      pynfe/utils/flags.py
  5. 2
      tests/03-processamento-01-serializacao-xml.txt

57
pynfe/processamento/assinatura.py

@ -61,16 +61,30 @@ class AssinaturaA1(Assinatura):
"""Classe abstrata responsavel por efetuar a assinatura do certificado """Classe abstrata responsavel por efetuar a assinatura do certificado
digital no XML informado.""" digital no XML informado."""
def assinar_arquivo(self, caminho_arquivo):
def assinar_arquivo(self, caminho_arquivo, salva=True):
# Carrega o XML do arquivo # Carrega o XML do arquivo
raiz = etree.parse(caminho_arquivo) raiz = etree.parse(caminho_arquivo)
return self.assinar_etree(raiz)
# Efetua a assinatura
xml = self.assinar_etree(raiz, retorna_xml=True)
raise Exception(xml)
# Grava XML assinado no arquivo
if salva:
fp = file(caminho_arquivo, 'w')
fp.write(xml)
fp.close()
return xml
def assinar_xml(self, xml): def assinar_xml(self, xml):
raiz = etree.parse(StringIO(xml)) raiz = etree.parse(StringIO(xml))
return self.assinar_etree(raiz)
def assinar_etree(self, raiz):
# Efetua a assinatura
return self.assinar_etree(raiz, retorna_xml=True)
def assinar_etree(self, raiz, retorna_xml=False):
# Extrai a tag do elemento raiz # Extrai a tag do elemento raiz
tipo = extrair_tag(raiz.getroot()) tipo = extrair_tag(raiz.getroot())
@ -91,6 +105,24 @@ class AssinaturaA1(Assinatura):
URI=raiz.getroot().getchildren()[0].attrib['Id'], URI=raiz.getroot().getchildren()[0].attrib['Id'],
nsmap={'sig': NAMESPACE_SIG}, nsmap={'sig': NAMESPACE_SIG},
) )
signed_info = etree.SubElement(signature, '{%s}SignedInfo'%NAMESPACE_SIG)
etree.SubElement(signed_info, 'CanonicalizationMethod', Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315")
etree.SubElement(signed_info, 'SignatureMethod', Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1")
reference = etree.SubElement(signed_info, '{%s}Reference'%NAMESPACE_SIG, URI=raiz.getroot().getchildren()[0].attrib['Id'])
transforms = etree.SubElement(reference, 'Transforms', URI=raiz.getroot().getchildren()[0].attrib['Id'])
etree.SubElement(transforms, 'Transform', Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature")
etree.SubElement(transforms, 'Transform', Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315")
etree.SubElement(reference, '{%s}DigestMethod'%NAMESPACE_SIG, Algorithm="http://www.w3.org/2000/09/xmldsig#sha1")
digest_value = etree.SubElement(reference, '{%s}DigestValue'%NAMESPACE_SIG)
signature_value = etree.SubElement(signature, '{%s}SignatureValue'%NAMESPACE_SIG)
key_info = etree.SubElement(signature, '{%s}KeyInfo'%NAMESPACE_SIG)
x509_data = etree.SubElement(key_info, '{%s}X509Data'%NAMESPACE_SIG)
x509_certificate = etree.SubElement(x509_data, '{%s}X509Certificate'%NAMESPACE_SIG)
raiz.getroot().insert(0, signature) raiz.getroot().insert(0, signature)
# Acrescenta a tag de doctype (como o lxml nao suporta alteracao do doctype, # Acrescenta a tag de doctype (como o lxml nao suporta alteracao do doctype,
@ -108,21 +140,27 @@ class AssinaturaA1(Assinatura):
assinador.sign(noh_assinatura) assinador.sign(noh_assinatura)
# Coloca na instância Signature os valores calculados # Coloca na instância Signature os valores calculados
doc.Signature.DigestValue = ctxt.xpathEval(u'//sig:DigestValue')[0].content.replace(u'\n', u'')
doc.Signature.SignatureValue = ctxt.xpathEval(u'//sig:SignatureValue')[0].content.replace(u'\n', u'')
digest_value.text = ctxt.xpathEval(u'//sig:DigestValue')[0].content.replace(u'\n', u'')
signature_value.text = ctxt.xpathEval(u'//sig:SignatureValue')[0].content.replace(u'\n', u'')
# Provavelmente retornarão vários certificados, já que o xmlsec inclui a cadeia inteira # Provavelmente retornarão vários certificados, já que o xmlsec inclui a cadeia inteira
certificados = ctxt.xpathEval(u'//sig:X509Data/sig:X509Certificate') certificados = ctxt.xpathEval(u'//sig:X509Data/sig:X509Certificate')
doc.Signature.X509Certificate = certificados[len(certificados)-1].content.replace(u'\n', u'')
x509_certificate.text = certificados[len(certificados)-1].content.replace(u'\n', u'')
resultado = assinador.status == xmlsec.DSigStatusSucceeded resultado = assinador.status == xmlsec.DSigStatusSucceeded
# Limpa objetos da memoria e desativa funções criptográficas # Limpa objetos da memoria e desativa funções criptográficas
self._depois_de_assinar_ou_verificar(doc_xml, ctxt, assinador) self._depois_de_assinar_ou_verificar(doc_xml, ctxt, assinador)
#print etree.tostring(raiz, pretty_print=True, xml_declaration=True, encoding='utf-8')
# Gera o XML para retornar
raise Exception(dir(doc_xml))
xml = doc_xml.serialize()
return resultado
if retorna_xml:
raise Exception(xml)
return xml
else:
return etree.parse(StringIO(xml))
def _ativar_funcoes_criptograficas(self): def _ativar_funcoes_criptograficas(self):
# FIXME: descobrir forma de evitar o uso do libxml2 neste processo # FIXME: descobrir forma de evitar o uso do libxml2 neste processo
@ -175,7 +213,6 @@ class AssinaturaA1(Assinatura):
return resultado return resultado
def _antes_de_assinar_ou_verificar(self, raiz): def _antes_de_assinar_ou_verificar(self, raiz):
raise Exception(dir(raiz))
# Converte etree para string # Converte etree para string
xml = etree.tostring(raiz, xml_declaration=True, encoding='utf-8') xml = etree.tostring(raiz, xml_declaration=True, encoding='utf-8')

4
pynfe/processamento/comunicacao.py

@ -3,7 +3,7 @@
from httplib import HTTPSConnection, HTTPResponse from httplib import HTTPSConnection, HTTPResponse
from pynfe.utils import etree, StringIO from pynfe.utils import etree, StringIO
from pynfe.utils.flags import NAMESPACE_NFE, NAMESPACE_SOAP
from pynfe.utils.flags import NAMESPACE_NFE, NAMESPACE_SOAP, VERSAO_PADRAO
class Comunicacao(object): class Comunicacao(object):
u"""Classe abstrata responsavel por definir os metodos e logica das classes u"""Classe abstrata responsavel por definir os metodos e logica das classes
@ -21,7 +21,7 @@ class Comunicacao(object):
class ComunicacaoSefaz(Comunicacao): class ComunicacaoSefaz(Comunicacao):
u"""Classe de comunicação que segue o padrão definido para as SEFAZ dos Estados.""" u"""Classe de comunicação que segue o padrão definido para as SEFAZ dos Estados."""
_versao = '1.01'
_versao = VERSAO_PADRAO
def transmitir(self, nota_fiscal): def transmitir(self, nota_fiscal):
pass pass

6
pynfe/processamento/serializacao.py

@ -7,7 +7,7 @@ except:
from pynfe.entidades import Emitente, Cliente, Produto, Transportadora, NotaFiscal from pynfe.entidades import Emitente, Cliente, Produto, Transportadora, NotaFiscal
from pynfe.excecoes import NenhumObjetoEncontrado, MuitosObjetosEncontrados from pynfe.excecoes import NenhumObjetoEncontrado, MuitosObjetosEncontrados
from pynfe.utils import etree, so_numeros, obter_municipio_por_codigo, obter_pais_por_codigo from pynfe.utils import etree, so_numeros, obter_municipio_por_codigo, obter_pais_por_codigo
from pynfe.utils.flags import CODIGOS_ESTADOS
from pynfe.utils.flags import CODIGOS_ESTADOS, VERSAO_PADRAO
class Serializacao(object): class Serializacao(object):
"""Classe abstrata responsavel por fornecer as funcionalidades basicas para """Classe abstrata responsavel por fornecer as funcionalidades basicas para
@ -43,6 +43,8 @@ class Serializacao(object):
raise Exception('Metodo nao implementado') raise Exception('Metodo nao implementado')
class SerializacaoXML(Serializacao): class SerializacaoXML(Serializacao):
_versao = VERSAO_PADRAO
def exportar(self, destino=None, retorna_string=False, **kwargs): def exportar(self, destino=None, retorna_string=False, **kwargs):
"""Gera o(s) arquivo(s) de Nofa Fiscal eletronica no padrao oficial da SEFAZ """Gera o(s) arquivo(s) de Nofa Fiscal eletronica no padrao oficial da SEFAZ
e Receita Federal, para ser(em) enviado(s) para o webservice ou para ser(em) e Receita Federal, para ser(em) enviado(s) para o webservice ou para ser(em)
@ -220,7 +222,7 @@ class SerializacaoXML(Serializacao):
return raiz return raiz
def _serializar_notas_fiscal(self, nota_fiscal, tag_raiz='infNFe', retorna_string=True): def _serializar_notas_fiscal(self, nota_fiscal, tag_raiz='infNFe', retorna_string=True):
raiz = etree.Element(tag_raiz, versao="2.00")
raiz = etree.Element(tag_raiz, versao=self._versao)
# Dados da Nota Fiscal # Dados da Nota Fiscal
ide = etree.SubElement(raiz, 'ide') ide = etree.SubElement(raiz, 'ide')

2
pynfe/utils/flags.py

@ -4,6 +4,8 @@ NAMESPACE_NFE = 'http://www.portalfiscal.inf.br/nfe'
NAMESPACE_SIG = 'http://www.w3.org/2000/09/xmldsig#' NAMESPACE_SIG = 'http://www.w3.org/2000/09/xmldsig#'
NAMESPACE_SOAP = 'http://www.w3.org/2003/05/soap-envelope' NAMESPACE_SOAP = 'http://www.w3.org/2003/05/soap-envelope'
VERSAO_PADRAO = '1.01'
TIPOS_DOCUMENTO = ( TIPOS_DOCUMENTO = (
'CNPJ', 'CNPJ',
'CPF', 'CPF',

2
tests/03-processamento-01-serializacao-xml.txt

@ -268,7 +268,7 @@ Serializando por partes
NFe52100112345678000190550010000000011518005123 NFe52100112345678000190550010000000011518005123
>>> print serializador._serializar_notas_fiscal(nota_fiscal) >>> print serializador._serializar_notas_fiscal(nota_fiscal)
<infNFe versao="2.00" Id="NFe52100112345678000190550010000000011518005123">
<infNFe versao="1.01" Id="NFe52100112345678000190550010000000011518005123">
<ide> <ide>
<cUF>52</cUF> <cUF>52</cUF>
<cNF>51800512</cNF> <cNF>51800512</cNF>

Loading…
Cancel
Save