Browse Source

Trabalhando na serializacao da Nota Fiscal

tags/0.1
Marinho Brandão 16 years ago
parent
commit
bbdf541ecc
  1. 91
      pynfe/entidades/notafiscal.py
  2. 2
      pynfe/entidades/produto.py
  3. 74
      pynfe/processamento/serializacao.py
  4. 67
      tests/02-modelo-05-notafiscal.txt
  5. 91
      tests/03-processamento-01-serializacao-xml.txt

91
pynfe/entidades/notafiscal.py

@ -9,7 +9,7 @@ from pynfe.utils.flags import NF_STATUS, NF_TIPOS_DOCUMENTO, NF_TIPOS_IMPRESSAO_
ICMS_ORIGENS, ICMS_MODALIDADES, IPI_TIPOS_TRIBUTACAO, IPI_TIPOS_CALCULO,\ ICMS_ORIGENS, ICMS_MODALIDADES, IPI_TIPOS_TRIBUTACAO, IPI_TIPOS_CALCULO,\
PIS_TIPOS_TRIBUTACAO, PIS_TIPOS_CALCULO, COFINS_TIPOS_TRIBUTACAO,\ 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
NF_PROCESSOS_EMISSAO, CODIGOS_ESTADOS, TIPOS_DOCUMENTO
from pynfe.utils import so_numeros, memoize from pynfe.utils import so_numeros, memoize
from decimal import Decimal from decimal import Decimal
@ -97,33 +97,11 @@ class NotaFiscal(Entidade):
# - Identificacao (seleciona de Clientes) # - Identificacao (seleciona de Clientes)
destinatario_remetente = None destinatario_remetente = None
# - Endereco (ver se pode copiar do Cliente)
# - Logradouro (obrigatorio)
destinatario_endereco_logradouro = str()
# - Numero (obrigatorio)
destinatario_endereco_numero = str()
# - Complemento
destinatario_endereco_complemento = str()
# - Bairro (obrigatorio)
destinatario_endereco_bairro = str()
# - CEP
destinatario_endereco_cep = str()
# - Entrega (XXX sera possivel ter entrega e retirada ao mesmo tempo na NF?)
entrega = None
# - Pais (seleciona de lista)
destinatario_endereco_pais = CODIGO_BRASIL
# - UF (obrigatorio)
destinatario_endereco_uf = str()
# - Municipio (obrigatorio)
destinatario_endereco_municipio = str()
# - Telefone
destinatario_endereco_telefone = str()
# - Retirada
retirada = None
# - Local Retirada/Entrega # - Local Retirada/Entrega
# - Local de retirada diferente do emitente (Sim/Nao) # - Local de retirada diferente do emitente (Sim/Nao)
@ -317,27 +295,39 @@ class NotaFiscal(Entidade):
def adicionar_nota_fiscal_referenciada(self, **kwargs): def adicionar_nota_fiscal_referenciada(self, **kwargs):
u"""Adiciona uma instancia de Nota Fisca referenciada""" u"""Adiciona uma instancia de Nota Fisca referenciada"""
self.notas_fiscais_referenciadas.append(NotaFiscalReferenciada(**kwargs))
obj = NotaFiscalReferenciada(**kwargs)
self.notas_fiscais_referenciadas.append(obj)
return obj
def adicionar_produto_servico(self, **kwargs): def adicionar_produto_servico(self, **kwargs):
u"""Adiciona uma instancia de Produto""" u"""Adiciona uma instancia de Produto"""
self.produtos_e_servicos.append(NotaFiscalProduto(**kwargs))
obj = NotaFiscalProduto(**kwargs)
self.produtos_e_servicos.append(obj)
return obj
def adicionar_transporte_volume(self, **kwargs): def adicionar_transporte_volume(self, **kwargs):
u"""Adiciona uma instancia de Volume de Transporte""" u"""Adiciona uma instancia de Volume de Transporte"""
self.transporte_volumes.append(NotaFiscalTransporteVolume(**kwargs))
obj = NotaFiscalTransporteVolume(**kwargs)
self.transporte_volumes.append(obj)
return obj
def adicionar_duplicata(self, **kwargs): def adicionar_duplicata(self, **kwargs):
u"""Adiciona uma instancia de Duplicata""" u"""Adiciona uma instancia de Duplicata"""
self.duplicatas.append(NotaFiscalCobrancaDuplicata(**kwargs))
obj = NotaFiscalCobrancaDuplicata(**kwargs)
self.duplicatas.append(obj)
return obj
def adicionar_observacao_contribuinte(self, **kwargs): def adicionar_observacao_contribuinte(self, **kwargs):
u"""Adiciona uma instancia de Observacao do Contribuinte""" u"""Adiciona uma instancia de Observacao do Contribuinte"""
self.observacoes_contribuinte.append(NotaFiscalObservacaoContribuinte(**kwargs))
obj = NotaFiscalObservacaoContribuinte(**kwargs)
self.observacoes_contribuinte.append(obj)
return obj
def adicionar_processo_referenciado(self, **kwargs): def adicionar_processo_referenciado(self, **kwargs):
u"""Adiciona uma instancia de Processo Referenciado""" u"""Adiciona uma instancia de Processo Referenciado"""
self.processos_referenciados.append(NotaFiscalProcessoReferenciado(**kwargs))
obj = NotaFiscalProcessoReferenciado(**kwargs)
self.processos_referenciados.append(obj)
return obj
@property @property
@memoize @memoize
@ -776,3 +766,38 @@ class NotaFiscalProcessoReferenciado(Entidade):
# - Outros # - Outros
origem = str() origem = str()
class NotaFiscalEntregaRetirada(Entidade):
# - Tipo de Documento (obrigatorio) - default CNPJ
tipo_documento = 'CNPJ'
# - Numero do Documento (obrigatorio)
numero_documento = str()
# - Endereco
# - Logradouro (obrigatorio)
endereco_logradouro = str()
# - Numero (obrigatorio)
endereco_numero = str()
# - Complemento
endereco_complemento = str()
# - Bairro (obrigatorio)
endereco_bairro = str()
# - CEP
endereco_cep = str()
# - Pais (seleciona de lista)
endereco_pais = CODIGO_BRASIL
# - UF (obrigatorio)
endereco_uf = str()
# - Municipio (obrigatorio)
endereco_municipio = str()
# - Telefone
endereco_telefone = str()

2
pynfe/entidades/produto.py

@ -5,6 +5,8 @@ from pynfe.utils.flags import ICMS_TIPOS_TRIBUTACAO, ICMS_ORIGENS, ICMS_MODALIDA
from decimal import Decimal from decimal import Decimal
class Produto(Entidade): class Produto(Entidade):
"""XXX: E provavel que esta entidade sera descartada."""
# Dados do Produto # Dados do Produto
# - Descricao (obrigatorio) # - Descricao (obrigatorio)
descricao = str() descricao = str()

74
pynfe/processamento/serializacao.py

@ -187,10 +187,53 @@ class SerializacaoXML(Serializacao):
else: else:
return raiz return raiz
def _serializar_produto(self, produto, tag_raiz='prod', retorna_string=True):
# Provavelmente nao vai ser feito desta forma, e sim como serializacao do produto
# na NF (NotaFiscalProduto)
return ''
def _serializar_entrega_retirada(self, entrega_retirada, tag_raiz='entrega', retorna_string=True):
raiz = etree.Element(tag_raiz)
# Dados da entrega/retirada
etree.SubElement(raiz, entrega_retirada.tipo_documento).text = so_numeros(entrega_retirada.numero_documento)
# Endereço
etree.SubElement(raiz, 'xLgr').text = entrega_retirada.endereco_logradouro
etree.SubElement(raiz, 'nro').text = entrega_retirada.endereco_numero
etree.SubElement(raiz, 'xCpl').text = entrega_retirada.endereco_complemento
etree.SubElement(raiz, 'xBairro').text = entrega_retirada.endereco_bairro
etree.SubElement(raiz, 'cMun').text = entrega_retirada.endereco_municipio
etree.SubElement(raiz, 'xMun').text = obter_municipio_por_codigo(
entrega_retirada.endereco_municipio, entrega_retirada.endereco_uf,
)
etree.SubElement(raiz, 'UF').text = entrega_retirada.endereco_uf
if retorna_string:
return etree.tostring(raiz, pretty_print=True)
else:
return raiz
def _serializar_produto_servico(self, produto_servico, tag_raiz='det', retorna_string=True):
raiz = etree.Element(tag_raiz)
# Produto
prod = etree.SubElement(raiz, 'prod')
etree.SubElement(prod, 'cProd').text = str(produto_servico.codigo)
etree.SubElement(prod, 'cEAN').text = produto_servico.ean
etree.SubElement(prod, 'xProd').text = produto_servico.descricao
etree.SubElement(prod, 'CFOP').text = produto_servico.cfop
etree.SubElement(prod, 'uCom').text = produto_servico.unidade_comercial
etree.SubElement(prod, 'qCom').text = '%f'%(produto_servico.quantidade_comercial or 0)
etree.SubElement(prod, 'vUnCom').text = '%f'%(produto_servico.valor_unitario_comercial or 0)
etree.SubElement(prod, 'vProd').text = '%f'%(produto_servico.valor_total_bruto or 0)
etree.SubElement(prod, 'cEANTrib').text = produto_servico.ean_tributavel
etree.SubElement(prod, 'uTrib').text = produto_servico.unidade_tributavel
etree.SubElement(prod, 'qTrib').text = '%f'%(produto_servico.quantidade_tributavel)
etree.SubElement(prod, 'vUnTrib').text = '%f'%(produto_servico.valor_unitario_tributavel)
# Imposto
imposto = etree.SubElement(raiz, 'imposto')
if retorna_string:
return etree.tostring(raiz, pretty_print=True)
else:
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="2.00")
@ -223,6 +266,29 @@ class SerializacaoXML(Serializacao):
# Destinatário # Destinatário
raiz.append(self._serializar_cliente(nota_fiscal.cliente, retorna_string=False)) raiz.append(self._serializar_cliente(nota_fiscal.cliente, retorna_string=False))
# Retirada
if nota_fiscal.retirada:
raiz.append(self._serializar_entrega_retirada(
nota_fiscal.retirada,
retorna_string=False,
tag_raiz='retirada',
))
# Entrega
if nota_fiscal.entrega:
raiz.append(self._serializar_entrega_retirada(
nota_fiscal.entrega,
retorna_string=False,
tag_raiz='entrega',
))
# Itens
for num, item in enumerate(nota_fiscal.produtos_e_servicos):
det = self._serializar_produto_servico(item, retorna_string=False)
det.attrib['nItem'] = str(num+1)
raiz.append(det)
# Transporte # Transporte
transp = etree.SubElement(raiz, 'transp') transp = etree.SubElement(raiz, 'transp')
transp.append(self._serializar_transportadora(nota_fiscal.transporte_transportadora, retorna_string=False)) transp.append(self._serializar_transportadora(nota_fiscal.transporte_transportadora, retorna_string=False))

67
tests/02-modelo-05-notafiscal.txt

@ -10,7 +10,8 @@ Nenhum dos campos deve permitir acentos e/ou cedilhas.
... NotaFiscalProduto, NotaFiscalDeclaracaoImportacao,\ ... NotaFiscalProduto, NotaFiscalDeclaracaoImportacao,\
... NotaFiscalDeclaracaoImportacaoAdicao, NotaFiscalTransporteVolume,\ ... NotaFiscalDeclaracaoImportacaoAdicao, NotaFiscalTransporteVolume,\
... NotaFiscalTransporteVolumeLacre, NotaFiscalCobrancaDuplicata,\ ... NotaFiscalTransporteVolumeLacre, NotaFiscalCobrancaDuplicata,\
... NotaFiscalObservacaoContribuinte, NotaFiscalProcessoReferenciado
... NotaFiscalObservacaoContribuinte, NotaFiscalProcessoReferenciado,\
... NotaFiscalEntregaRetirada
- Dados da NF-e - Dados da NF-e
- Status (controle de estados da NF) - Status (controle de estados da NF)
@ -208,61 +209,83 @@ Nenhum dos campos deve permitir acentos e/ou cedilhas.
>>> hasattr(NotaFiscal, 'destinatario_remetente') >>> hasattr(NotaFiscal, 'destinatario_remetente')
True True
- Endereco (ver se pode copiar do Cliente)
- Entrega/Retirada
- Local de retirada diferente do emitente (Sim/Nao)
>>> hasattr(NotaFiscal, 'local_retirada_diferente_emitente')
True
- Local de entrega diferente do destinatario (Sim/Nao)
>>> hasattr(NotaFiscal, 'local_entrega_diferente_destinatario')
True
- Entrega
>>> hasattr(NotaFiscal, 'entrega')
True
- Retirada
>>> hasattr(NotaFiscal, 'retirada')
True
- Campos de Entrega e Retirada
- Tipo de Documento (obrigatorio) - default CNPJ
- CNPJ
- CPF
>>> hasattr(NotaFiscalEntregaRetirada, 'tipo_documento')
True
- Numero do Documento (obrigatorio)
>>> hasattr(NotaFiscalEntregaRetirada, 'numero_documento')
True
- Logradouro (obrigatorio) - Logradouro (obrigatorio)
>>> hasattr(NotaFiscal, 'destinatario_endereco_logradouro')
>>> hasattr(NotaFiscalEntregaRetirada, 'endereco_logradouro')
True True
- Numero (obrigatorio) - Numero (obrigatorio)
>>> hasattr(NotaFiscal, 'destinatario_endereco_numero')
>>> hasattr(NotaFiscalEntregaRetirada, 'endereco_numero')
True True
- Complemento - Complemento
>>> hasattr(NotaFiscal, 'destinatario_endereco_complemento')
>>> hasattr(NotaFiscalEntregaRetirada, 'endereco_complemento')
True True
- Bairro (obrigatorio) - Bairro (obrigatorio)
>>> hasattr(NotaFiscal, 'destinatario_endereco_bairro')
>>> hasattr(NotaFiscalEntregaRetirada, 'endereco_bairro')
True True
- CEP - CEP
>>> hasattr(NotaFiscal, 'destinatario_endereco_cep')
>>> hasattr(NotaFiscalEntregaRetirada, 'endereco_cep')
True True
- Pais (seleciona de lista) - Pais (seleciona de lista)
>>> hasattr(NotaFiscal, 'destinatario_endereco_pais')
>>> hasattr(NotaFiscalEntregaRetirada, 'endereco_pais')
True True
- UF (obrigatorio) - UF (obrigatorio)
>>> hasattr(NotaFiscal, 'destinatario_endereco_uf')
>>> hasattr(NotaFiscalEntregaRetirada, 'endereco_uf')
True True
- Municipio (obrigatorio) - Municipio (obrigatorio)
>>> hasattr(NotaFiscal, 'destinatario_endereco_municipio')
>>> hasattr(NotaFiscalEntregaRetirada, 'endereco_municipio')
True True
- Telefone - Telefone
>>> hasattr(NotaFiscal, 'destinatario_endereco_telefone')
True
- Local Retirada/Entrega
- Local de retirada diferente do emitente (Sim/Nao)
>>> hasattr(NotaFiscal, 'local_retirada_diferente_emitente')
True
- Local de entrega diferente do destinatario (Sim/Nao)
>>> hasattr(NotaFiscal, 'local_entrega_diferente_destinatario')
>>> hasattr(NotaFiscalEntregaRetirada, 'endereco_telefone')
True True
- Produtos e Servicos (lista 1 para * / ManyToManyField) - Produtos e Servicos (lista 1 para * / ManyToManyField)

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

@ -4,9 +4,9 @@ PROCESSAMENTO - SERIALIZACAO PARA XML
Populando fonte de dados Populando fonte de dados
------------------------ ------------------------
>>> import datetime
>>> from pynfe.entidades import Emitente, Cliente, NotaFiscal, Produto,\
... Transportadora
>>> import datetime, decimal
>>> from pynfe.entidades import Emitente, Cliente, NotaFiscal, Transportadora
>>> from pynfe.entidades.notafiscal import NotaFiscalEntregaRetirada
>>> from pynfe.entidades.fontes_dados import _fonte_dados >>> from pynfe.entidades.fontes_dados import _fonte_dados
>>> from pynfe.utils.flags import CODIGO_BRASIL >>> from pynfe.utils.flags import CODIGO_BRASIL
@ -43,9 +43,6 @@ Popula dependentes da NF
... endereco_telefone='2132011234', ... endereco_telefone='2132011234',
... ) ... )
>>> produto1 = Produto(codigo=1, descricao='Tenis Adidas Cinza')
>>> produto2 = Produto(codigo=2, descricao='Sapato Ferracini Preto')
>>> transportadora = Transportadora( >>> transportadora = Transportadora(
... razao_social='WS Cargas S/A', ... razao_social='WS Cargas S/A',
... tipo_documento='CNPJ', ... tipo_documento='CNPJ',
@ -66,8 +63,8 @@ Instancia a NF
... modelo=55, ... modelo=55,
... serie='1', ... serie='1',
... numero_nf='1', ... numero_nf='1',
... data_emissao=datetime.date.today(),
... data_saida_entrada=datetime.date.today(),
... data_emissao=datetime.date(2010,1,13),
... data_saida_entrada=datetime.date(2010,1,13),
... natureza_operacao='Venda a vista', ... natureza_operacao='Venda a vista',
... forma_pagamento=0, ... forma_pagamento=0,
... tipo_impressao_danfe=1, # Retrato ... tipo_impressao_danfe=1, # Retrato
@ -77,9 +74,53 @@ Instancia a NF
... codigo_numerico_aleatorio='51800512', ... codigo_numerico_aleatorio='51800512',
... dv_codigo_numerico_aleatorio='3', ... dv_codigo_numerico_aleatorio='3',
... ) ... )
>>> nota_fiscal.retirada = NotaFiscalEntregaRetirada(
... tipo_documento='CNPJ',
... numero_documento='99.171.171/0001-94',
... endereco_logradouro='AV PAULISTA',
... endereco_numero='12345',
... endereco_complemento='TERREO',
... endereco_bairro='CERQUEIRA CESAR',
... endereco_municipio='3304557', # Rio de Janeiro
... endereco_uf='RJ',
... )
>>> nota_fiscal.entrega = NotaFiscalEntregaRetirada(
... tipo_documento='CNPJ',
... numero_documento='99.299.299/0001-94',
... endereco_logradouro='AV FARIA LIMA',
... endereco_numero='1500',
... endereco_complemento='15 ANDAR',
... endereco_bairro='PINHEIROS',
... endereco_municipio='3304557', # Rio de Janeiro
... endereco_uf='RJ',
... )
>>> nf_prod1 = nota_fiscal.adicionar_produto_servico(
... codigo='00001',
... descricao='Agua Mineral',
... cfop='5101',
... unidade_comercial='dz',
... quantidade_comercial=decimal.Decimal('2'),
... valor_unitario_comercial=decimal.Decimal('10.0'),
... valor_total_bruto=decimal.Decimal('20.0'),
... unidade_tributavel='und',
... quantidade_tributavel=decimal.Decimal('24.0'),
... valor_unitario_tributavel=decimal.Decimal('3.00'),
... )
>>> nf_prod2 = nota_fiscal.adicionar_produto_servico(
... codigo='00002',
... descricao='Agua Mineral',
... cfop='5101',
... unidade_comercial='pack',
... quantidade_comercial=decimal.Decimal('5000000'),
... valor_unitario_comercial=decimal.Decimal('2.0'),
... valor_total_bruto=decimal.Decimal('10000000.0'),
... unidade_tributavel='und',
... quantidade_tributavel=decimal.Decimal('3000000.0'),
... valor_unitario_tributavel=decimal.Decimal('0.3333'),
... )
>>> _fonte_dados.contar_objetos() >>> _fonte_dados.contar_objetos()
6
8
Gerar arquivos XML Gerar arquivos XML
------------------ ------------------
@ -218,9 +259,9 @@ Serializando por partes
<nro>12345</nro> <nro>12345</nro>
<xCpl>TERREO</xCpl> <xCpl>TERREO</xCpl>
<xBairro>CERQUEIRA CESAR</xBairro> <xBairro>CERQUEIRA CESAR</xBairro>
<cMun>3550308</cMun>
<xMun>SAO PAULO</xMun>
<UF>SP</UF>
<cMun>3304557</cMun>
<xMun>Rio de Janeiro</xMun>
<UF>RJ</UF>
</retirada> </retirada>
<entrega> <entrega>
<CNPJ>99299299000194</CNPJ> <CNPJ>99299299000194</CNPJ>
@ -228,9 +269,9 @@ Serializando por partes
<nro>1500</nro> <nro>1500</nro>
<xCpl>15 ANDAR</xCpl> <xCpl>15 ANDAR</xCpl>
<xBairro>PINHEIROS</xBairro> <xBairro>PINHEIROS</xBairro>
<cMun>3550308</cMun>
<xMun>SAO PAULO</xMun>
<UF>SP</UF>
<cMun>3304557</cMun>
<xMun>Rio de Janeiro</xMun>
<UF>RJ</UF>
</entrega> </entrega>
<det nItem="1"> <det nItem="1">
<prod> <prod>
@ -239,13 +280,13 @@ Serializando por partes
<xProd>Agua Mineral</xProd> <xProd>Agua Mineral</xProd>
<CFOP>5101</CFOP> <CFOP>5101</CFOP>
<uCom>dz</uCom> <uCom>dz</uCom>
<qCom>1000000.0000</qCom>
<vUnCom>1</vUnCom>
<vProd>10000000.00</vProd>
<qCom>2.000000</qCom>
<vUnCom>10.000000</vUnCom>
<vProd>20.000000</vProd>
<cEANTrib /> <cEANTrib />
<uTrib>und</uTrib> <uTrib>und</uTrib>
<qTrib>12000000.0000</qTrib>
<vUnTrib>1</vUnTrib>
<qTrib>24.000000</qTrib>
<vUnTrib>3.000000</vUnTrib>
</prod> </prod>
<imposto> <imposto>
<ICMS> <ICMS>
@ -283,13 +324,13 @@ Serializando por partes
<xProd>Agua Mineral</xProd> <xProd>Agua Mineral</xProd>
<CFOP>5101</CFOP> <CFOP>5101</CFOP>
<uCom>pack</uCom> <uCom>pack</uCom>
<qCom>5000000.0000</qCom>
<vUnCom>2</vUnCom>
<vProd>10000000.00</vProd>
<qCom>5000000.000000</qCom>
<vUnCom>2.000000</vUnCom>
<vProd>10000000.000000</vProd>
<cEANTrib /> <cEANTrib />
<uTrib>und</uTrib> <uTrib>und</uTrib>
<qTrib>3000000.0000</qTrib>
<vUnTrib>0.3333</vUnTrib>
<qTrib>3000000.000000</qTrib>
<vUnTrib>0.333300</vUnTrib>
</prod> </prod>
<imposto> <imposto>
<ICMS> <ICMS>

Loading…
Cancel
Save