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 +