Browse Source

Enviando arquivos esquecidos e iniciando trabalho na assinatura do XML.

Tambem iniciado o arquivo de autores, devido ao inicio da colaboracao
da TaugaRS
tags/0.1
Marinho Brandão 16 years ago
parent
commit
97d1375888
  1. 25
      AUTHORS
  2. 27
      pynfe/entidades/certificado.py
  3. 128
      pynfe/entidades/fonte_dados.py
  4. 35
      pynfe/processamento/assinatura.py
  5. 35
      tests/01-basico.txt
  6. 25
      tests/03-processamento-03-assinatura.txt

25
AUTHORS

@ -0,0 +1,25 @@
Sobre os autores deste e outros créditos
========================================
O PyNFe foi criado por Marinho Brandão <marinho at gmail.com> e seu
desenvolvimento só foi possível graças à massiva colaboração de pessoas,
empresas e outros projetos livres para o mesmo fim, disponívels para outras
linguagens.
A TaugaRS Sistemas <http://taugars.com.br/> gentil e voluntariamente forneceu o
código-fonte de seu pacote já testado e maduro para servir de base de apoio
neste processo, assim como seu know-how de mais de 2 anos em NF-eletronicas.
Por esse motivo, encontra-se em igual ou maior importância que a do criador, o
desenvolvedor Ari Caldeira e o restante da diretoria desta empresa.
Outra fonte importante de informação foi do projeto de componentes para Delphi
voltados para automação comercial ACBr <http://acbr.sourceforge.net/>, que
inclui um componente que tem a mesma finalidade que o PyNFe.
Outras pessoas que devem ser referenciadas por sua colaboração, seja através de
know-how e debates, seja através de código enviado para colaborar:
- Diogo Daniel (Prosig Sistemas)
- Antonio Prado (Antonio Prado Sistemas)
- Italo Maia <italomaia at gmail.com>

27
pynfe/entidades/certificado.py

@ -0,0 +1,27 @@
# -*- coding; utf-8 -*-
from base import Entidade
class Certificado(Entidade):
u"""Classe abstrata responsavel por definir o modelo padrao para as demais
classes de certificados digitais.
Caso va implementar um novo formato de certificado, crie uma classe que
herde desta."""
def __new__(cls, *args, **kwargs):
if cls == Certificado:
raise Exception('Esta classe nao pode ser instanciada diretamente!')
else:
return super(Certificado, cls).__new__(cls, *args, **kwargs)
class CertificadoA1(Certificado):
"""Implementa a entidade do certificado eCNPJ A1, suportado pelo OpenSSL,
e amplamente utilizado."""
caminho_arquivo = None
conteudo_x509 = None
def __init__(self, caminho_arquivo=None, conteudo_x509=None):
self.caminho_arquivo = caminho_arquivo or self.caminho_arquivo
self.conteudo_x509 = conteudo_x509 or self.conteudo_x509

128
pynfe/entidades/fonte_dados.py

@ -0,0 +1,128 @@
# -*- coding: utf-8 -*-
from pynfe.excecoes import NenhumObjetoEncontrado, MuitosObjetosEncontrados
class FonteDados(object):
u"""Classe responsável por ser o repositório dos objetos em memória e que
pode ser extendida para persistir esses objetos. Também tem a função de
memorizar os objetos redundantes como um e assim otimizar o desempenho."""
_objetos = None
def __init__(self, objetos=None):
# Inicializa variável que armazena os objetos contidos na Fonte de Dados
if objetos:
self._objetos = objetos
else:
self._objetos = []
def carregar_objetos(self, **kwargs):
u"""Método responsavel por retornar os objetos que casem com os atributos
informados no argumento **kwargs (argumentos nomeados).
Um argumento especial é o '_classe', que representa a classe da entidade
desejada.
FIXME: Este algoritimo pode ser melhorado pra fazer pesquisas melhores,
mas por enquanto vamos nos focar no processo em geral para depois nos
preocupar com otimizações e desempenho."""
# Função de filtro
def filtrar(obj):
ret = True
for k,v in kwargs.items():
# Filtra pela classe e pelos atributos
ret = (k == '_classe' and isinstance(obj, v)) or\
(k != '_classe' and getattr(obj, k, None) == v)
if not ret:
break
return ret
# Filtra a lista de objetos
lista = filter(filtrar, self._objetos)
return lista
def adicionar_objeto(self, _objeto):
u"""Método responsável por adicionar o(s) objeto(s) informado(s) ao
repositorio de objetos da fonte de dados."""
from base import Entidade
# Adiciona _objeto como objeto
if isinstance(_objeto, Entidade):
self._objetos.append(_objeto)
# Adiciona _objeto como lista
elif isinstance(_objeto, (list, tuple)):
self._objetos += _objeto
else:
raise Exception('Objeto informado e invalido!')
def remover_objeto(self, _objeto=None, **kwargs):
u"""Método responsavel por remover os objetos que casem com os atributos
informados no argumento **kwargs (argumentos nomeados).
Um argumento especial é o '_classe', que representa a classe da entidade
desejada.
Outro argumetno especial é o '_objeto', que representa o objeto a ser
removido. Caso o argumento _objeto seja uma lista de objetos, eles serão
removidos também."""
from base import Entidade
lista = None
# Remove objetos
if not _objeto:
lista = self.carregar_objetos(**kwargs)
# Remove _objeto como objeto
elif isinstance(_objeto, Entidade):
lista = [_objeto]
# Remove _objeto como objeto
elif isinstance(_objeto, (list, tuple)):
lista = _objeto
else:
raise Exception('Objeto informado e invalido!')
# Efetiva a remoção
for obj in lista:
self._objetos.remove(obj)
def obter_objeto(self, **kwargs):
u"""Faz a ponte para o método 'carregar_objetos' mas obriga o retorno de
apenas um objeto, levantando exceção se nenhum for encontrado ou se forem
encontrados mais de um."""
lista = self.carregar_objetos(**kwargs)
if len(lista) == 0:
raise NenhumObjetoEncontrado('Nenhum objeto foi encontrado!')
elif len(lista) > 1:
raise MuitosObjetosEncontrados('Muitos objetos foram encontrados!')
return lista[0]
def obter_lista(self, **kwargs):
u"""Método de proxy, que somente repassa a chamada ao metodo 'carregar_objetos'"""
return self.carregar_objetos(**kwargs)
def contar_objetos(self, **kwargs):
u"""Método que repassa a chamada ao metodo 'carregar_objetos' mas retorna
somente a quantidade de objetos encontrados."""
if kwargs:
return len(self.carregar_objetos(**kwargs))
else:
return len(self._objetos)
# Instancia da fonte de dados default
_fonte_dados = FonteDados()

35
pynfe/processamento/assinatura.py

@ -1,3 +1,36 @@
# -*- coding: utf-8 -*-
class Assinatura(object):
pass
"""Classe abstrata responsavel por definir os metodos e logica das classes
de assinatura digital."""
def __init__(self, certificado):
self.certificado = certificado
def assinar_arquivos(self, caminho_raiz):
"""Efetua a assinatura dos arquivos XML informados"""
pass
def assinar_xml(self, xml):
"""Efetua a assinatura numa string contendo XML valido."""
pass
def assinar_etree(self, raiz):
u"""Efetua a assinatura numa instancia da biblioteca lxml.etree.
Este metodo de assinatura será utilizado internamente pelos demais,
sendo que eles convertem para uma instancia lxml.etree para somente
depois efetivar a assinatura.
TODO: Verificar o funcionamento da PyXMLSec antes de efetivar isso."""
pass
def assinar_objetos(self, objetos):
"""Efetua a assinatura em instancias do PyNFe"""
pass
class AssinaturaA1(Assinatura):
"""Classe abstrata responsavel por efetuar a assinatura do certificado
digital no XML informado."""
pass

35
tests/01-basico.txt

@ -45,21 +45,26 @@ modelo:
| PROCESSAMENTO |
----------------------------------------------------------------------------
| |
| ------------------- -------------- -------------------------------- |
| | SerializacaoXML | | Assinatura | | Comunicacao | |
| ------------------- -------------- -------------------------------- |
| | exportar() | | assinar() | | transmitir() | |
| | importar() | -------------- | cancelar() | |
| ------------------- | situacao_nfe() | |
| ---------------------- | status_servico() | |
| -------------- | Validacao | | consultar_cadastro() | |
| | DANFE | ---------------------- | inutilizar_faixa_numeracao() | |
| -------------- | validar_arquivos() | -------------------------------- |
| | imprimir() | | validar_xml() | |
| -------------- | validar_etree() | |
| | validar_objetos() | |
| ---------------------- |
| |
| ------------------ -------------- -------------------------------- |
| | Serializacao | | DANFE | | Comunicacao | |
| ------------------ -------------- -------------------------------- |
| | exportar() | | imprimir() | | transmitir() | |
| | importar() | -------------- | cancelar() | |
| ------------------ | situacao_nfe() | |
| | status_servico() | |
| ---------------------- | consultar_cadastro() | |
| | Validacao | | inutilizar_faixa_numeracao() | |
| ---------------------- -------------------------------- |
| | validar_arquivos() | |
| | validar_xml() | |
| | validar_etree() | ---------------------- |
| | validar_objetos() | | Assinatura | |
| ---------------------- ---------------------- |
| | assinar_arquivos() | |
| | assinar_xml() | |
| | assinar_etree() | |
| | assinar_objetos() | |
| ---------------------- |
----------------------------------------------------------------------------
Os pacotes da biblioteca sao:

25
tests/03-processamento-03-assinatura.txt

@ -0,0 +1,25 @@
PROCESSAMENTO - ASSINATURA DE XML
=================================
Carregando Certificado Digital tipo A1
--------------------------------------
>>> from pynfe.entidades import CertificadoA1
Assinando NF-e
--------------
>>> from pynfe.processamento import AssinaturaC1
Na hora de assinar, selecionar um Certificado Digital
>>>
A assinatura deve ser feita em quatro tipos diferentes de origem do XML:
- Arquivos
-
- Utilizar pyXMLSec para isso
- verificar qual eh a integracao do PyXMLSec com o lxml.etree
Loading…
Cancel
Save