From 5a4b6e73603129cdca9eb33cac60bd36089b8c05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marinho=20Brand=C3=A3o?= Date: Wed, 13 Jan 2010 23:35:12 -0200 Subject: [PATCH] Trabalhando na serializacao da NF para XML --- pynfe/__init__.py | 9 ++++++-- pynfe/entidades/notafiscal.py | 32 +++++++++++++++++++++++--- pynfe/processamento/serializacao.py | 23 ++++++++++++++++-- pynfe/utils/flags.py | 26 +++++++++++++++------ tests/02-modelo-05-notafiscal.txt | 14 +++++++++++ tests/03-processamento-01-serializacao-xml.txt | 14 ++++++++--- 6 files changed, 101 insertions(+), 17 deletions(-) diff --git a/pynfe/__init__.py b/pynfe/__init__.py index 16429f5..546296e 100644 --- a/pynfe/__init__.py +++ b/pynfe/__init__.py @@ -1,3 +1,8 @@ -__version__ = '0.1' +def get_version(): + return '0.1' + +__version__ = get_version() __author__ = 'Marinho Brandao' -__license__ = 'Lesser Gnu Public License' +__license__ = 'GNU Lesser General Public License (LGPL)' +__url__ = 'http://github.com/marinho/PyNFe' + diff --git a/pynfe/entidades/notafiscal.py b/pynfe/entidades/notafiscal.py index 9925536..9e5558e 100644 --- a/pynfe/entidades/notafiscal.py +++ b/pynfe/entidades/notafiscal.py @@ -1,10 +1,14 @@ +# -*- coding: utf-8 -*- from base import Entidade +from pynfe import get_version from pynfe.utils.flags import NF_STATUS, NF_TIPOS_DOCUMENTO, NF_TIPOS_IMPRESSAO_DANFE,\ NF_FORMAS_PAGAMENTO, NF_FORMAS_EMISSAO, NF_FINALIDADES_EMISSAO,\ NF_REFERENCIADA_TIPOS, NF_PRODUTOS_ESPECIFICOS, ICMS_TIPOS_TRIBUTACAO,\ ICMS_ORIGENS, ICMS_MODALIDADES, IPI_TIPOS_TRIBUTACAO, IPI_TIPOS_CALCULO,\ PIS_TIPOS_TRIBUTACAO, PIS_TIPOS_CALCULO, COFINS_TIPOS_TRIBUTACAO,\ - COFINS_TIPOS_CALCULO, MODALIDADES_FRETE, ORIGENS_PROCESSO, CODIGO_BRASIL + COFINS_TIPOS_CALCULO, MODALIDADES_FRETE, ORIGENS_PROCESSO, CODIGO_BRASIL,\ + NF_PROCESSOS_EMISSAO, CODIGOS_ESTADOS +from pynfe.utils import so_numeros, memoize from decimal import Decimal @@ -30,14 +34,20 @@ class NotaFiscal(Entidade): # - Tipo do Documento (obrigatorio - seleciona de lista) - NF_TIPOS_DOCUMENTO tipo_documento = int() + # - Processo de emissão da NF-e (obrigatorio - seleciona de lista) - NF_PROCESSOS_EMISSAO + processo_emissao = 0 + + # - Versao do processo de emissão da NF-e + versao_processo_emissao = get_version() + # - Tipo impressao DANFE (obrigatorio - seleciona de lista) - NF_TIPOS_IMPRESSAO_DANFE - tipo_impressao_danfe = str() + tipo_impressao_danfe = int() # - Data de saida/entrada data_saida_entrada = None # - Forma de pagamento (obrigatorio - seleciona de lista) - NF_FORMAS_PAGAMENTO - forma_pagamento = str() + forma_pagamento = int() # - Forma de emissao (obrigatorio - seleciona de lista) - NF_FORMAS_EMISSAO forma_emissao = str() @@ -321,6 +331,22 @@ class NotaFiscal(Entidade): u"""Adiciona uma instancia de Processo Referenciado""" self.processos_referenciados.append(NotaFiscalProcessoReferenciado(**kwargs)) + @property + @memoize + def identificador_unico(self): + # Monta 'Id' da raiz + # Ex.: NFe35080599999090910270550010000000015180051273 + return "NFe%(uf)s%(ano)s%(mes)s%(cnpj)s%(mod)s%(serie)s%(nNF)s%(cNF)s%(cDV)s"%{ + 'uf': CODIGOS_ESTADOS[self.uf], + 'ano': self.data_emissao.strftime('%y'), + 'mes': self.data_emissao.strftime('%m'), + 'cnpj': so_numeros(self.emitente.cnpj), + 'mod': self.modelo, + 'serie': str(self.serie).zfill(3), + 'nNF': str(self.numero_nf).zfill(9), + 'cNF': '518005127'.zfill(9), # FIXME + 'cDV': '3', # FIXME + } class NotaFiscalReferenciada(Entidade): # - Tipo (seleciona de lista) - NF_REFERENCIADA_TIPOS diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py index 9a5c61c..e041fd1 100644 --- a/pynfe/processamento/serializacao.py +++ b/pynfe/processamento/serializacao.py @@ -38,6 +38,8 @@ class Serializacao(object): Nao deve ser instanciada diretamente!""" _fonte_dados = None + _ambiente = 1 + _nome_aplicacao = 'PyNFe' def __new__(cls, *args, **kwargs): if cls == Serializacao: @@ -45,8 +47,9 @@ class Serializacao(object): else: return super(Serializacao, cls).__new__(cls, *args, **kwargs) - def __init__(self, fonte_dados): + def __init__(self, fonte_dados, homologacao=False): self._fonte_dados = fonte_dados + self._ambiente = homologacao and 2 or 1 def exportar(self, destino, **kwargs): """Gera o(s) arquivo(s) de exportacao a partir da Nofa Fiscal eletronica @@ -190,17 +193,29 @@ class SerializacaoXML(Serializacao): return '' def _serializar_notas_fiscal(self, nota_fiscal, tag_raiz='infNFe', retorna_string=True): - raiz = etree.Element(tag_raiz) + raiz = etree.Element(tag_raiz, versao="1.10") # Dados da Nota Fiscal ide = etree.SubElement(raiz, 'ide') etree.SubElement(ide, 'cUF').text = CODIGOS_ESTADOS[nota_fiscal.uf] + etree.SubElement(ide, 'cNF').text = '' # FIXME etree.SubElement(ide, 'natOp').text = nota_fiscal.natureza_operacao + etree.SubElement(ide, 'indPag').text = str(nota_fiscal.forma_pagamento) etree.SubElement(ide, 'mod').text = str(nota_fiscal.modelo) etree.SubElement(ide, 'serie').text = nota_fiscal.serie etree.SubElement(ide, 'nNF').text = nota_fiscal.numero_nf etree.SubElement(ide, 'dEmi').text = nota_fiscal.data_emissao.strftime('%Y-%m-%d') etree.SubElement(ide, 'dSaiEnt').text = nota_fiscal.data_saida_entrada.strftime('%Y-%m-%d') + etree.SubElement(ide, 'tpNF').text = str(nota_fiscal.tipo_documento) + etree.SubElement(ide, 'cMunFG').text = nota_fiscal.municipio + etree.SubElement(ide, 'tpImp').text = str(nota_fiscal.tipo_impressao_danfe) + etree.SubElement(ide, 'tpEmis').text = str(nota_fiscal.forma_emissao) + etree.SubElement(ide, 'cDV').text = '3' # FIXME + etree.SubElement(ide, 'tpAmb').text = str(self._ambiente) + etree.SubElement(ide, 'finNFe').text = str(nota_fiscal.finalidade_emissao) + etree.SubElement(ide, 'procEmi').text = str(nota_fiscal.processo_emissao) + etree.SubElement(ide, 'verProc').text = '%s %s'%(self._nome_aplicacao, + nota_fiscal.versao_processo_emissao) # Emitente raiz.append(self._serializar_emitente(nota_fiscal.emitente, retorna_string=False)) @@ -208,6 +223,10 @@ class SerializacaoXML(Serializacao): # Destinatário raiz.append(self._serializar_cliente(nota_fiscal.cliente, retorna_string=False)) + # 'Id' da tag raiz + # Ex.: NFe35080599999090910270550010000000015180051273 + raiz.attrib['Id'] = nota_fiscal.identificador_unico + if retorna_string: return etree.tostring(raiz, pretty_print=True) else: diff --git a/pynfe/utils/flags.py b/pynfe/utils/flags.py index 4a090f8..3be8135 100644 --- a/pynfe/utils/flags.py +++ b/pynfe/utils/flags.py @@ -47,9 +47,16 @@ NF_TIPOS_DOCUMENTO = ( (1, 'Saida'), ) +NF_PROCESSOS_EMISSAO = ( + (0, u'Emissão de NF-e com aplicativo do contribuinte'), + (1, u'Emissão de NF-e avulsa pelo Fisco'), + (2, u'Emissão de NF-e avulsa, pelo contribuinte com seu certificado digital, através do site do Fisco'), + (3, u'Emissão NF-e pelo contribuinte com aplicativo fornecido pelo Fisco'), +) + NF_TIPOS_IMPRESSAO_DANFE = ( - 'Retrato', - 'Paisagem', + (1, 'Retrato'), + (2, 'Paisagem'), ) NF_FORMAS_PAGAMENTO = ( @@ -59,11 +66,11 @@ NF_FORMAS_PAGAMENTO = ( ) NF_FORMAS_EMISSAO = ( - 'Normal', - 'Contingencia', - 'Contingencia com SCAN', - 'Contingencia via DPEC', - 'Contingencia FS-DA', + (1, 'Normal'), + (2, 'Contingencia'), + (3, 'Contingencia com SCAN'), + (4, 'Contingencia via DPEC'), + (5, 'Contingencia FS-DA'), ) NF_FINALIDADES_EMISSAO = ( @@ -84,6 +91,11 @@ NF_PRODUTOS_ESPECIFICOS = ( 'Combustivel', ) +NF_AMBIENTES = ( + (1, 'Producao'), + (2, 'Homologacao'), +) + IPI_TIPOS_TRIBUTACAO = ( ('00', 'IPI 00 - Entrada com recuperacao de credito'), ('01', 'IPI 01 - Entrada tributada com aliquota zero'), diff --git a/tests/02-modelo-05-notafiscal.txt b/tests/02-modelo-05-notafiscal.txt index e1f8050..ca4b67b 100644 --- a/tests/02-modelo-05-notafiscal.txt +++ b/tests/02-modelo-05-notafiscal.txt @@ -58,6 +58,20 @@ Nenhum dos campos deve permitir acentos e/ou cedilhas. >>> hasattr(NotaFiscal, 'tipo_documento') True + - Processo de emissão da NF-e + - 0 - emissão de NF-e com aplicativo do contribuinte; + - 1 - emissão de NF-e avulsa pelo Fisco; + - 2 - emissão de NF-e avulsa, pelo contribuinte com seu certificado digital, através do site do Fisco; + - 3 - emissão NF-e pelo contribuinte com aplicativo fornecido pelo Fisco. + + >>> hasattr(NotaFiscal, 'processo_emissao') + True + + - Versao do Processo de emissao da NF-e + + >>> hasattr(NotaFiscal, 'versao_processo_emissao') + True + - Tipo impressao DANFE (obrigatorio - seleciona de lista) - Retrato - Paisagem diff --git a/tests/03-processamento-01-serializacao-xml.txt b/tests/03-processamento-01-serializacao-xml.txt index 017d1e3..814b73c 100644 --- a/tests/03-processamento-01-serializacao-xml.txt +++ b/tests/03-processamento-01-serializacao-xml.txt @@ -69,6 +69,11 @@ Instancia a NF ... data_emissao=datetime.date.today(), ... data_saida_entrada=datetime.date.today(), ... natureza_operacao='Venda a vista', + ... forma_pagamento=0, + ... tipo_impressao_danfe=1, # Retrato + ... forma_emissao=1, # Normal + ... finalidade_emissao=1, + ... municipio='3550308', ... ) >>> _fonte_dados.contar_objetos() @@ -82,7 +87,7 @@ Gerar arquivos XML >>> CAMINHO_SAIDA = os.path.join(CUR_DIR, 'tests', 'saida') >>> from pynfe.processamento.serializacao import SerializacaoXML - >>> serializador = SerializacaoXML(_fonte_dados) + >>> serializador = SerializacaoXML(_fonte_dados, homologacao=True) Serializando por partes @@ -143,8 +148,11 @@ Serializando por partes - Gera os arquivos XML a partir dos dados das instancias da NF-e + >>> print nota_fiscal.identificador_unico + NFe52100112345678000190550010000000015180051273 + >>> print serializador._serializar_notas_fiscal(nota_fiscal) - + 52 518005127 @@ -163,7 +171,7 @@ Serializando por partes 2 1 0 - NF-eletronica.com + PyNFe 0.1 12345678000190