From 799b74ecf27300111360d0af8831586ce863ef0c Mon Sep 17 00:00:00 2001 From: Junior Tada Date: Thu, 9 Jul 2015 12:11:00 -0300 Subject: [PATCH 1/2] teste com a lib --- pynfe/processamento/serializacao.py | 17 +++++++++-------- pynfe/utils/flags.py | 2 +- test.py | 11 ++++++++--- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py index 85b2244..0eab435 100644 --- a/pynfe/processamento/serializacao.py +++ b/pynfe/processamento/serializacao.py @@ -9,7 +9,7 @@ from pynfe.entidades import Emitente, Cliente, Produto, Transportadora, NotaFisc from pynfe.excecoes import NenhumObjetoEncontrado, MuitosObjetosEncontrados from pynfe.utils import etree, so_numeros, obter_municipio_por_codigo, \ obter_pais_por_codigo, obter_municipio_e_codigo, \ - formatar_decimal, safe_str, obter_uf_por_codigo + formatar_decimal, safe_str, obter_uf_por_codigo, obter_codigo_por_municipio from pynfe.utils.flags import CODIGOS_ESTADOS, VERSAO_PADRAO class Serializacao(object): @@ -48,7 +48,7 @@ class SerializacaoXML(Serializacao): _versao = VERSAO_PADRAO 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 Nota Fiscal eletronica no padrao oficial da SEFAZ e Receita Federal, para ser(em) enviado(s) para o webservice ou para ser(em) armazenado(s) em cache local.""" @@ -59,7 +59,7 @@ class SerializacaoXML(Serializacao): notas_fiscais = self._fonte_dados.obter_lista(_classe=NotaFiscal, **kwargs) for nf in notas_fiscais: - raiz.append(self._serializar_notas_fiscal(nf, retorna_string=False)) + raiz.append(self._serializar_nota_fiscal(nf, retorna_string=False)) if retorna_string: return etree.tostring(raiz, pretty_print=True) @@ -221,7 +221,7 @@ class SerializacaoXML(Serializacao): else: return raiz - def _serializar_notas_fiscal(self, nota_fiscal, tag_raiz='infNFe', retorna_string=True): + def _serializar_nota_fiscal(self, nota_fiscal, tag_raiz='infNFe', retorna_string=True): raiz = etree.Element(tag_raiz, versao=self._versao) # Dados da Nota Fiscal @@ -298,10 +298,11 @@ class SerializacaoXML(Serializacao): etree.SubElement(transp, 'modFrete').text = str(nota_fiscal.transporte_modalidade_frete) # Transportadora - transp.append(self._serializar_transportadora( - nota_fiscal.transporte_transportadora, - retorna_string=False, - )) + if nota_fiscal.transporte_transportadora: + transp.append(self._serializar_transportadora( + nota_fiscal.transporte_transportadora, + retorna_string=False, + )) # Veículo veiculo = etree.SubElement(transp, 'veicTransp') diff --git a/pynfe/utils/flags.py b/pynfe/utils/flags.py index 0c100d9..7a844bd 100644 --- a/pynfe/utils/flags.py +++ b/pynfe/utils/flags.py @@ -4,7 +4,7 @@ NAMESPACE_NFE = 'http://www.portalfiscal.inf.br/nfe' NAMESPACE_SIG = 'http://www.w3.org/2000/09/xmldsig#' NAMESPACE_SOAP = 'http://www.w3.org/2003/05/soap-envelope' -VERSAO_PADRAO = '1.01' +VERSAO_PADRAO = '3.10' TIPOS_DOCUMENTO = ( 'CNPJ', diff --git a/test.py b/test.py index 7a49de1..a88cfbf 100644 --- a/test.py +++ b/test.py @@ -8,11 +8,12 @@ from pynfe.entidades.cliente import Cliente from pynfe.entidades.emitente import Emitente from pynfe.entidades.notafiscal import NotaFiscal, NotaFiscalProduto from pynfe.entidades.fonte_dados import _fonte_dados -from pynfe.processamento.serializacao import SerializacaoPipes +from pynfe.processamento.serializacao import SerializacaoPipes, SerializacaoXML from pynfe.utils.flags import CODIGO_BRASIL import datetime -serializador = SerializacaoPipes(_fonte_dados, homologacao=True) +#serializador = SerializacaoPipes(_fonte_dados, homologacao=True) +serializador = SerializacaoXML(_fonte_dados, homologacao=True) emitente = Emitente( razao_social='Spring Publicacoes Ltda', @@ -95,4 +96,8 @@ nota_fiscal.adicionar_produto_servico(codigo='000328', # id do produto (000328 e cofins_aliquota_percentual=Decimal('3.00'), cofins_valor=Decimal('3.51')) -print serializador._serializar_nota_fiscal(nota_fiscal) +#print serializador._serializar_nota_fiscal(nota_fiscal) +#print serializador._serializar_nota_fiscal(nota_fiscal) +arquivo = file('teste.xml', 'w') +arquivo.write(serializador._serializar_nota_fiscal(nota_fiscal)) +arquivo.close() \ No newline at end of file From 4963b3b74f5b7fbe0de1cf1bfb7b239fa667430d Mon Sep 17 00:00:00 2001 From: Junior Tada Date: Mon, 13 Jul 2015 17:02:35 -0300 Subject: [PATCH 2/2] teste --- pynfe/entidades/notafiscal.py | 39 +++++++++++++++++++++++++++++++++++-- pynfe/processamento/assinatura.py | 11 ++++++++--- pynfe/processamento/serializacao.py | 25 +++++++++++++++++------- pynfe/processamento/validacao.py | 8 +++++--- test.py | 37 +++++++++++++++++++++++------------ 5 files changed, 93 insertions(+), 27 deletions(-) diff --git a/pynfe/entidades/notafiscal.py b/pynfe/entidades/notafiscal.py index 1ee3d22..32f622f 100644 --- a/pynfe/entidades/notafiscal.py +++ b/pynfe/entidades/notafiscal.py @@ -350,11 +350,46 @@ class NotaFiscal(Entidade): self.processos_referenciados.append(obj) return obj + def _codigo_numerico_aleatorio(self): + codigo_numerico_aleatorio = str(random.randint(0, 99999999)).zfill(8) + return codigo_numerico_aleatorio + + def _dv_codigo_numerico(self, key): + assert len(key) == 43 + + weights = [2, 3, 4, 5, 6, 7, 8, 9] + weights_size = len(weights) + key_numbers = [int(k) for k in key] + key_numbers.reverse() + + key_sum = 0 + for i, key_number in enumerate(key_numbers): + # cycle though weights + i = i % weights_size + key_sum += key_number * weights[i] + + remainder = key_sum % 11 + if remainder == 0 or remainder == 1: + return '0' + dv_codigo_numerico_aleatorio = str(11 - remainder) + return str(dv_codigo_numerico_aleatorio) + @property # @memoize def identificador_unico(self): # Monta 'Id' da tag raiz # Ex.: NFe35080599999090910270550010000000011518005123 + key = "%(uf)s%(ano)s%(mes)s%(cnpj)s%(mod)s%(serie)s%(nNF)s%(tpEmis)s%(cNF)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), + 'tpEmis': str(self.forma_emissao), + 'cNF': self._codigo_numerico_aleatorio(), + } return "NFe%(uf)s%(ano)s%(mes)s%(cnpj)s%(mod)s%(serie)s%(nNF)s%(tpEmis)s%(cNF)s%(cDV)s"%{ 'uf': CODIGOS_ESTADOS[self.uf], 'ano': self.data_emissao.strftime('%y'), @@ -364,8 +399,8 @@ class NotaFiscal(Entidade): 'serie': str(self.serie).zfill(3), 'nNF': str(self.numero_nf).zfill(9), 'tpEmis': str(self.forma_emissao), - 'cNF': self.codigo_numerico_aleatorio.zfill(8), - 'cDV': self.dv_codigo_numerico_aleatorio, + 'cNF': str(self.codigo_numerico_aleatorio), + 'cDV': self._dv_codigo_numerico(key), } class NotaFiscalReferenciada(Entidade): diff --git a/pynfe/processamento/assinatura.py b/pynfe/processamento/assinatura.py index 256a8e4..f25035e 100644 --- a/pynfe/processamento/assinatura.py +++ b/pynfe/processamento/assinatura.py @@ -160,8 +160,8 @@ class AssinaturaA1(Assinatura): # Ativa as funções da API de criptografia xmlsec.init() - xmlsec.cryptoAppInit(None) - xmlsec.cryptoInit() + #xmlsec.cryptoAppInit(None) + #xmlsec.cryptoInit() def _desativar_funcoes_criptograficas(self): ''' Desativa as funções criptográficas e de análise XML @@ -219,13 +219,18 @@ class AssinaturaA1(Assinatura): noh_assinatura = ctxt.xpathEval(u'//*/sig:Signature')[0] # Buscamos a chave no arquivo do certificado - chave = xmlsec.cryptoAppKeyLoad( + chave = xmlsec.CryptoAppKeyLoad( filename=str(self.certificado.caminho_arquivo), format=xmlsec.KeyDataFormatPkcs12, pwd=str(self.senha), pwdCallback=None, pwdCallbackCtx=None, ) + # chave = xmlsec.key.from_file( + # filename=str(self.certificado.caminho_arquivo), + # format=xmlsec.KeyDataFormatPkcs12, + # pwd=str(self.senha) + # ) # Cria a variável de chamada (callable) da função de assinatura assinador = xmlsec.DSigCtx() diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py index 0eab435..8cc7225 100644 --- a/pynfe/processamento/serializacao.py +++ b/pynfe/processamento/serializacao.py @@ -222,8 +222,17 @@ class SerializacaoXML(Serializacao): return raiz def _serializar_nota_fiscal(self, nota_fiscal, tag_raiz='infNFe', retorna_string=True): + #raiz = etree.Element('NFe', xmlns='http://www.portalfiscal.inf.br/nfe') raiz = etree.Element(tag_raiz, versao=self._versao) + # 'Id' da tag raiz + # Ex.: NFe35080599999090910270550010000000011518005123 + raiz.attrib['Id'] = nota_fiscal.identificador_unico + + # timezone Brasília -03:00 + tz = time.strftime("%z") + tz = "{}:{}".format(tz[:-2], tz[-2:]) + # Dados da Nota Fiscal ide = etree.SubElement(raiz, 'ide') etree.SubElement(ide, 'cUF').text = CODIGOS_ESTADOS[nota_fiscal.uf] @@ -233,9 +242,15 @@ class SerializacaoXML(Serializacao): etree.SubElement(ide, 'mod').text = str(nota_fiscal.modelo) etree.SubElement(ide, 'serie').text = nota_fiscal.serie etree.SubElement(ide, 'nNF').text = str(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, 'dhEmi').text = nota_fiscal.data_emissao.strftime('%Y-%m-%dT%H:%M:%S') + tz + etree.SubElement(ide, 'dhSaiEnt').text = nota_fiscal.data_saida_entrada.strftime('%Y-%m-%dT%H:%M:%S') + tz + """dhCont Data e Hora da entrada em contingência E B01 D 0-1 Formato AAAA-MM-DDThh:mm:ssTZD (UTC - Universal + Coordinated Time) + Exemplo: no formato UTC para os campos de Data-Hora, "TZD" pode ser -02:00 (Fernando de Noronha), -03:00 (Brasília) ou -04:00 (Manaus), no + horário de verão serão -01:00, -02:00 e -03:00. Exemplo: "2010-08-19T13:00:15-03:00". + """ + etree.SubElement(ide, 'tpNF').text = str(nota_fiscal.tipo_documento) # 0=entrada 1=saida + etree.SubElement(ide, 'idDest').text = str(1) # Identificador de local de destino da operação 1=Operação interna;2=Operação interestadual;3=Operação com exterior. 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) @@ -336,10 +351,6 @@ class SerializacaoXML(Serializacao): etree.SubElement(info_ad, 'infAdFisco').text = nota_fiscal.informacoes_adicionais_interesse_fisco etree.SubElement(info_ad, 'infCpl').text = nota_fiscal.informacoes_complementares_interesse_contribuinte - # 'Id' da tag raiz - # Ex.: NFe35080599999090910270550010000000011518005123 - raiz.attrib['Id'] = nota_fiscal.identificador_unico - if retorna_string: return etree.tostring(raiz, pretty_print=True) else: diff --git a/pynfe/processamento/validacao.py b/pynfe/processamento/validacao.py index e1caef3..72c3b95 100644 --- a/pynfe/processamento/validacao.py +++ b/pynfe/processamento/validacao.py @@ -62,14 +62,16 @@ class Validacao(object): xsd_file - caminho para o arquivo xsd use_assert - levantar exceção caso documento não valide? ''' - xsd_filepath = get_xsd(xsd_file) + #xsd_filepath = get_xsd(xsd_file) try: # checa se o schema ja existe no cache - xsd_schema = self.MEM_CACHE[xsd_filepath] + #xsd_schema = self.MEM_CACHE[xsd_filepath] + xsd_schema = self.MEM_CACHE[xsd_file] except: # lê xsd e atualiza cache - xsd_doc = etree.parse(xsd_filepath) + #xsd_doc = etree.parse(xsd_filepath) + xsd_doc = etree.parse(xsd_file) xsd_schema = etree.XMLSchema(xsd_doc) self.MEM_CACHE[xsd_file] = xsd_schema return use_assert and xsd_schema.assertValid(xml_doc) \ diff --git a/test.py b/test.py index a88cfbf..32292b9 100644 --- a/test.py +++ b/test.py @@ -9,14 +9,17 @@ from pynfe.entidades.emitente import Emitente from pynfe.entidades.notafiscal import NotaFiscal, NotaFiscalProduto from pynfe.entidades.fonte_dados import _fonte_dados from pynfe.processamento.serializacao import SerializacaoPipes, SerializacaoXML +from pynfe.processamento.validacao import Validacao +from pynfe.processamento.assinatura import AssinaturaA1 from pynfe.utils.flags import CODIGO_BRASIL import datetime #serializador = SerializacaoPipes(_fonte_dados, homologacao=True) -serializador = SerializacaoXML(_fonte_dados, homologacao=True) +#serializador = SerializacaoXML(_fonte_dados, homologacao=True) emitente = Emitente( razao_social='Spring Publicacoes Ltda', + nome_fantasia='Falcao Ferragens', cnpj='08234482000156', codigo_de_regime_tributario='3', # 1 para simples nacional ou 3 para normal inscricao_estadual='149431130117', # numero de IE da empresa @@ -37,6 +40,7 @@ cliente = Cliente( tipo_documento='CPF', #CPF ou CNPJ email='email@email.com', numero_documento='12345678900', # numero do cpf ou cnpj + inscricao_estadual='ISENTO', endereco_logradouro='Rua dos Bobos', endereco_numero='Zero', endereco_complemento='Ao lado de lugar nenhum', @@ -52,19 +56,19 @@ cliente = Cliente( nota_fiscal = NotaFiscal( emitente=emitente, cliente=cliente, - uf='SP', + uf='PR', codigo_numerico_aleatorio='66998237', natureza_operacao='VENDA ASSINATURAS', forma_pagamento='1', modelo=55, - serie='2', - numero_nf='1138', - data_emissao=datetime.date(2012,03,06), - data_saida_entrada=datetime.date(2012,03,06), + serie='1', + numero_nf='1', + data_emissao=datetime.datetime.now(), + data_saida_entrada=datetime.datetime.now(), hora_saida_entrada=datetime.time(03,12,00), tipo_documento=1, - municipio='SAO PAULO', - tipo_impressao_danfe=1, + municipio='4118402', + tipo_impressao_danfe=1, # nfce 4 forma_emissao='1', #dv_codigo_numerico_aleatorio=, ? finalidade_emissao='1', @@ -96,8 +100,17 @@ nota_fiscal.adicionar_produto_servico(codigo='000328', # id do produto (000328 e cofins_aliquota_percentual=Decimal('3.00'), cofins_valor=Decimal('3.51')) +#_fonte_dados.adicionar_objeto(nota_fiscal) + +serializador = SerializacaoXML(_fonte_dados, homologacao=True) +xml= serializador.exportar(retorna_string=True) +arquivo = file('nota1.xml', 'w') +arquivo.write(xml) +certificado = '/home/junior/Projetos/falcao/doc/JC FERRAGENS S=12345678.pfx' +senha = '12345328' +# assinatura +a = AssinaturaA1(certificado, senha) +print a.assinar_xml(xml) + #print serializador._serializar_nota_fiscal(nota_fiscal) -#print serializador._serializar_nota_fiscal(nota_fiscal) -arquivo = file('teste.xml', 'w') -arquivo.write(serializador._serializar_nota_fiscal(nota_fiscal)) -arquivo.close() \ No newline at end of file +