Ir para conteúdo
  • Cadastre-se

dev botao

gera chave GerarChaveAcesso


Antonio Gomes
Ver Solução Respondido por Italo Giurizzato Junior,
  • Este tópico foi criado há 1743 dias atrás.
  • Talvez seja melhor você criar um NOVO TÓPICO do que postar uma resposta aqui.

Recommended Posts

function GerarChaveAcesso(AUF: Integer; ADataEmissao: TDateTime; const ACNPJ: String;
                          ASerie, ANumero, AtpEmi, ACodigo: Integer; AModelo: Integer): String;
var
  vUF, vDataEmissao, vSerie, vNumero, vCodigo, vModelo, vCNPJ, vtpEmi: String;
begin
  // Se o usuario informar um código maior que zero validar o mesmo //
  if ACodigo > 0 then
    if ValidarCodigoDFe(ACodigo, ANumero) then
      raise EACBrDFeException.Create('Código Numérico inválido, Chave não Gerada');

  // Se o usuario informar um código inferior ou igual a -2 a chave não será gerada //
  if ACodigo <= -2 then
    raise EACBrDFeException.Create('Código Numérico inválido, Chave não Gerada');

  // Se o usuario informar 0 ou -1; o código numerico sera gerado de maneira aleatória //
  if ACodigo = -1 then
    ACodigo := 0;

  if ACodigo = 0 then
    ACodigo := GerarCodigoDFe(ANumero);

  // Se o usuario informar -2; o código numerico sera ZERO //
  // Pela Regra B03-10 que consta na NT 2019/001 versão 1.00 as notas vão ser
  // rejeitadas se o cNF for igual a zero.
//  if ACodigo = -2 then
//    ACodigo := 0;

  vUF          := Poem_Zeros(AUF, 2);
  vDataEmissao := FormatDateTime('YYMM', ADataEmissao);
  vCNPJ        := PadLeft(OnlyNumber(ACNPJ), 14, '0');
  vModelo      := Poem_Zeros(AModelo, 2);
  vSerie       := Poem_Zeros(ASerie, 3);
  vNumero      := Poem_Zeros(ANumero, 9);
  vtpEmi       := Poem_Zeros(AtpEmi, 1);
  vCodigo      := Poem_Zeros(ACodigo, 8);

  Result := vUF + vDataEmissao + vCNPJ + vModelo + vSerie + vNumero + vtpEmi + vCodigo;
  Result := Result + Modulo11(Result);
end;
 

Essa funcao, se eu mando um numero aleatorio = 54251212 está abortando a geracao da chave. penso que teria que que ser :

 

if ACodigo > 0 then
    if not ValidarCodigoDFe(ACodigo, ANumero) then
      raise EACBrDFeException.Create('Código Numérico inválido, Chave não Gerada');

Essa funcao está usando em um repeat until, que espera o result true... 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

  • Consultores

Boa tarde Antônio,

Muito obrigado pela correção, já enviei para o repositório.

  • Curtir 1
Consultor SAC ACBr

Italo Giurizzato Junior
Ajude o Projeto ACBr crescer - Assine o SAC

Projeto ACBr

Analista de Sistemas / e-mail: [email protected] / Fone: (16) 9-9701-5030 / Araraquara-SP

Araraquara - A era dos Trólebus

Link para o comentário
Compartilhar em outros sites

Fiz a alteração manualmente pois no SVN ainda n tinha tal alteração.

alterei para:

if ACodigo > 0 then
    if ValidarCodigoDFe(ACodigo, ANumero) then
      raise EACBrDFeException.Create('Código Numérico inválido, Chave não Gerada');

Pois a função espera true e não false conforme o Antonio comentou acima, só que a função dela é justamente verificar se os códigos informados são iguais, mesmo passando iguais retornava false e não estava gerando a chave de acesso.

Link para o comentário
Compartilhar em outros sites

Se coloca como if NOT  ACodigo > 0 then
    if ValidarCodigoDFe(ACodigo, ANumero) then
      raise EACBrDFeException.Create('Código Numérico inválido, Chave não Gerada');

Não gera a chave de acesso...

Se coloca como if ACodigo > 0 then
    if ValidarCodigoDFe(ACodigo, ANumero) then
      raise EACBrDFeException.Create('Código Numérico inválido, Chave não Gerada');

A chave é gerada porem vez ou outra dá mensagem de rejeição DUPLICIDADE DE CHAVE DE ACESSO com empresas que possuem mais de um terminal de caixa mesmo passando numeração diferente sequencial.

Afinal de contas qual funcionalidade da função? Sendo que apos atualização parou de funcionar uma função do ACBR que nunca tinha problemas...

Editado por LIDERNetwork
Link para o comentário
Compartilhar em outros sites

20 horas atrás, LIDERNetwork disse:

Se coloca como if NOT  ACodigo > 0 then
    if ValidarCodigoDFe(ACodigo, ANumero) then
      raise EACBrDFeException.Create('Código Numérico inválido, Chave não Gerada');

Não gera a chave de acesso...

Se coloca como if ACodigo > 0 then
    if ValidarCodigoDFe(ACodigo, ANumero) then
      raise EACBrDFeException.Create('Código Numérico inválido, Chave não Gerada');

A chave é gerada porem vez ou outra dá mensagem de rejeição DUPLICIDADE DE CHAVE DE ACESSO com empresas que possuem mais de um terminal de caixa mesmo passando numeração diferente sequencial.

Afinal de contas qual funcionalidade da função? Sendo que apos atualização parou de funcionar uma função do ACBR que nunca tinha problemas...

Na verdade, eu salvo esse campo no banco de dados, em outro campo. Por isso aconteceu de eu ter visto o erro.

Eu mesmo que gerei o número aleatório.

Poderia eu mesmo agora acionar a funcao do acbr de gerar essa chave e manter gravado, assim já passa pela validação. Isso no passado quando eu gerava ela a todo instante, acontecia o que foi reportado la embaixo, de duplicidade, dai o motivo dela ficar salvo na tabela de nota fiscal.. ao gerar simplesmente repasso o campo. 

Se você puser o not antes, nao vai dar certo, pois tem que entrar para validar, ou simplesmente gerar, a funcao gera se dentro for zero.

 

Aqui: f ACodigo = 0 then
    ACodigo := GerarCodigoDFe(ANumero);

 

Link para o comentário
Compartilhar em outros sites

7 minutos atrás, Antonio Gomes disse:

Na verdade, eu salvo esse campo no banco de dados, em outro campo. Por isso aconteceu de eu ter visto o erro.

Eu mesmo que gerei o número aleatório.

Poderia eu mesmo agora acionar a funcao do acbr de gerar essa chave e manter gravado, assim já passa pela validação. Isso no passado quando eu gerava ela a todo instante, acontecia o que foi reportado la embaixo, de duplicidade, dai o motivo dela ficar salvo na tabela de nota fiscal.. ao gerar simplesmente repasso o campo. 

Se você puser o not antes, nao vai dar certo, pois tem que entrar para validar, ou simplesmente gerar, a funcao gera se dentro for zero.

 

Aqui: f ACodigo = 0 then
    ACodigo := GerarCodigoDFe(ANumero);

 

Eu resolvi conforme o post citado acima e colocando um numero aleatorio ao gerar a NFCe e NFe. Nao guardo em banco o numero cNF pois para mim o que importa é o Numero nNF;

Link para o comentário
Compartilhar em outros sites

Pessoal bom dia. Baixei a ultima versão do ACBrNFCe e esta ocorrendo o erro

"Erro ao Gerar NFC-e Código Numérico inválido, Chave não Gerada" o que devo passar para função para não acontecer esse erro. 

image.thumb.png.27e90435a265beb8596591c805e436b5.png

image.thumb.png.6ab1b4c65e56bc867628969b0dfd3cef.png

 

 

Editado por ALA
Link para o comentário
Compartilhar em outros sites

Obrigado pela resposta Gabriel, mas como vcs estão procedendo quando perde a chave da NFe/NFC-e e tem a necessidade de criar a mesma chave que ja foi enviada para SEFAZ..?

Exemplo

   31190603601579000136650060000006501011596036 => enviar essa NFC-e, foi autorizada, mas não consegui gravar a chave no BD
    
    31190603601579000136650060000006501674046590 => mandei gerar a chave novamente para realizar a consulta da NFC-e, gerou outra chave, dessa forma não encontra o documento na SEFAZ..

 

Estou utilizando a regra abaixo para gerar a chave

                 CDS_VENDA.FieldByName( 'VEN_A05_ID' ).AsString := GerarChaveAcesso( CDS_VENDA.FieldByName( 'VEN_B02_CUF'       ).AsInteger,               // Código da UF do emitente do Documento Fiscal //);
                                                                                     CDS_VENDA.FieldByName( 'VEN_DT_EMISSAO'    ).AsDateTime,             // Data da emissao //
                                                                                     util.Retorna_Numeros( CDS_VENDA.FieldByName( 'VEN_C02_CNPJ' ).AsString ), // CNPJ do emitente
                                                                                     CDS_VENDA.FieldByName( 'VEN_SERIE'         ).AsInteger,              // Serie //
                                                                                     CDS_VENDA.FieldByName( 'VEN_NUMERO'        ).AsInteger,              // numero da nf,
                                                                                     CDS_VENDA.FieldByName( 'VEN_TPEMIS'        ).AsInteger,              // StrToInt( dmco_FormaEmissao_Normal   ),                                    // tipo de emissao
                                                                                     0, //CDS_VENDA.FieldByName( 'VEN_NUMERO'        ).AsInteger,
                                                                                     StrToInt( dmco_Modelo_NFCe       ));
 

 

Editado por ALA
Link para o comentário
Compartilhar em outros sites

5 minutos atrás, ALA disse:

mas como vcs estão procedendo quando perde a chave da NFe/NFC-e e tem a necessidade de criar a mesma chave que ja foi enviada para SEFAZ..?

Você deve armazenar o cNF no seu banco de dados. Dessa forma se precisar gerar a chave novamente, você utiliza o mesmo cNF da primeira vez. 

Link para o comentário
Compartilhar em outros sites

15 minutos atrás, ALA disse:

Obrigado pela resposta Gabriel, mas como vcs estão procedendo quando perde a chave da NFe/NFC-e e tem a necessidade de criar a mesma chave que ja foi enviada para SEFAZ..?

Exemplo

   31190603601579000136650060000006501011596036 => enviar essa NFC-e, foi autorizada, mas não consegui gravar a chave no BD
    
    31190603601579000136650060000006501674046590 => mandei gerar a chave novamente para realizar a consulta da NFC-e, gerou outra chave, dessa forma não encontra o documento na SEFAZ..

 

Estou utilizando a regra abaixo para gerar a chave

                 CDS_VENDA.FieldByName( 'VEN_A05_ID' ).AsString := GerarChaveAcesso( CDS_VENDA.FieldByName( 'VEN_B02_CUF'       ).AsInteger,               // Código da UF do emitente do Documento Fiscal //);
                                                                                     CDS_VENDA.FieldByName( 'VEN_DT_EMISSAO'    ).AsDateTime,             // Data da emissao //
                                                                                     util.Retorna_Numeros( CDS_VENDA.FieldByName( 'VEN_C02_CNPJ' ).AsString ), // CNPJ do emitente
                                                                                     CDS_VENDA.FieldByName( 'VEN_SERIE'         ).AsInteger,              // Serie //
                                                                                     CDS_VENDA.FieldByName( 'VEN_NUMERO'        ).AsInteger,              // numero da nf,
                                                                                     CDS_VENDA.FieldByName( 'VEN_TPEMIS'        ).AsInteger,              // StrToInt( dmco_FormaEmissao_Normal   ),                                    // tipo de emissao
                                                                                     0, //CDS_VENDA.FieldByName( 'VEN_NUMERO'        ).AsInteger,
                                                                                     StrToInt( dmco_Modelo_NFCe       ));
 

 

if CDS_VENDA.FieldByName( 'VEN_A05_ID' ).AsString = '' then 

 CDS_VENDA.FieldByName( 'VEN_A05_ID' ).AsString := GerarChaveAcesso( CDS_VENDA.FieldByName( 'VEN_B02_CUF'       ).AsInteger,               // Código da UF do emitente do Documento Fiscal //); := GerarChaveAcesso( CDS_VENDA.FieldByName( 'VEN_B02_CUF'       ).AsInteger,               // Código da UF do emitente do Documento Fiscal //);

 

usa campo do banco: 

 

CDS_VENDA.FieldByName( 'VEN_A05_ID' ).AsString

 

Link para o comentário
Compartilhar em outros sites

2 minutos atrás, ALA disse:

Então a regra e gravar o numero aleatorio no BD ?

Eu uso a chave primaria da tabela do campo ID no cNF e um numero sequencial no nNF, não preciso estar "criando números aleatórios" sem nexo apenas para gerar a chave. No sistema internamente qnd os dois campos são iguais apenas agora acrescentei uma função que incrementa +1 no nNF apenas para não enviar ao componente numeração iguais, mas isso fiz agora devido as alterações nos fontes do ACBR.

1 minuto atrás, Gabriel Franciscon disse:

Exatamente... Pois aí você terá todas as informações que são necessárias para gerar a mesma chave de acesso novamente

Num segundo envio apenas capturar os campos da tabela...

Link para o comentário
Compartilhar em outros sites

Estou pensando em enviar sempre 1 será que da algum problema. Hai os numeros serão diferentes, esse negocio de deixar o ACBr criar um numero aleatorio fico meio sismado com isso, se algum dia precisar gerar a chave novamente e não tiver o numero aleatorio gravado no bd, nunca mais consigo gerar a chave igual a que esta na SEFAZ...

Link para o comentário
Compartilhar em outros sites

Existe alguma forma de pegar o numero aleatorio gerado pelo ACBr, antes de enviar a NFC-e/NFe ? Utilizo a regra abaixo para gerar a chave e gravar no BD antes de enviar p SEFAZ, gostaria de utiliza a mesma regra p pegar o numero aleatorio, dessa forma gravo tudo no BD antes de enviar, se ocorrer algum problema referente ao retorno eu tenho tudo gravado..

         lcst_Chave := GerarChaveAcesso( DMXML.CDS_VENDA.FieldByName( 'VEN_B02_CUF'      ).AsInteger,               // Código da UF do emitente do Documento Fiscal //);
                                         DMXML.CDS_VENDA.FieldByName( 'VEN_DT_EMISSAO'    ).AsDateTime,             // Data da emissao //
                                         util.Retorna_Numeros( DMXML.CDS_VENDA.FieldByName( 'VEN_C02_CNPJ' ).AsString ), // CNPJ do emitente
                                         DMXML.CDS_VENDA.FieldByName( 'VEN_SERIE'         ).AsInteger,              // Serie //
                                         DMXML.CDS_VENDA.FieldByName( 'VEN_NUMERO'        ).AsInteger,              // numero da nf,
                                         DMXML.CDS_VENDA.FieldByName( 'VEN_TPEMIS'        ).AsInteger,              // StrToInt( dmco_FormaEmissao_Normal   ),                                    // tipo de emissao
                                         0, // Nota Técnica 2019/001 ALA 17/06/2019 DMXML.CDS_VENDA.FieldByName( 'VEN_NUMERO'        ).AsInteger,
                                         StrToInt( dmco_Modelo_NFCe       ));                                       // Modelo 65

Link para o comentário
Compartilhar em outros sites

Tem N opções de resolver isso.

Voce pode gravar a chave uma unica vez, e se precisar faz o explode da mesma.

O que mencionei antes foi:

Evento BeforePost do se dataset:

if IBDSPai.FieldByName('NFE_NUM_ALEATORIO_NF').AsInteger = 0 then
        begin
          Randomize;

          IBDSPai.FieldByName('NFE_NUM_ALEATORIO_NF').AsInteger :=
            Random(StrToInt(FormatDateTime('yymmddmm', IBDSPai.FieldByName('DATAEMISSAO_NF').AsDateTime + Time)));
        end;

ou

        if IBDSPai.FieldByName('NFE_NUM_ALEATORIO_NF').AsInteger = 0 then
          IBDSPai.FieldByName('NFE_NUM_ALEATORIO_NF').AsInteger := ACBrDFeUtil.GerarCodigoDFe(
            StrToInt(FormatDateTime('yymmddmm', IBDSPai.FieldByName('DATAEMISSAO_NF').AsDateTime + Time)));
 

 

depois, ao gerar a chave:

 Chave := ACBrDFeUtil.GerarChaveAcesso(
        TFuncoesNFe.UFTocUF(ParametroEmpresa.Cidade.UF_Cid),
        CDSNf.FieldByName('DATAEMISSAO_NF').AsDateTime,
        iif(ParametroEmpresa.CNPJ <> '', ParametroEmpresa.CNPJ, ParametroEmpresa.CPF),
        CDSNf.FieldByName('SERIE_NF').AsInteger,
        CDSNf.FieldByName('NUMNOTA_NF').AsLargeInt,
        StrToInt(CDSNf.FieldByName('NFE_TIPO_EMISSAO_NF').AsString),
        CDSNf.FieldByName('NFE_NUM_ALEATORIO_NF').AsInteger,
        CDSNf.FieldByName('MODELO_NF').AsInteger);

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

Bom dia. Se eu enviar a data de emissão no tag  Ide.cNF   sera que da algum problema ?

     Ide.cNF       := StrToInt64( FormatDateTime('DDMMYYYY', DMXML.CDS_VENDA.FieldByName( 'VEN_DT_EMISSAO' ).AsDateTime )); //0; // //Caso não seja preenchido será gerado um número aleatório pelo componente
     Ide.nNF       := DMXML.CDS_VENDA.FieldByName( 'VEN_NUMERO' ).AsInteger;    // StrToInt(NumNFe);
 

a chave ficou da seguinte forma 31190603601579000136650060000006561180620191

 

image.thumb.png.1fdb0ab04b79ee6b45d1eaf38b782512.png

Editado por ALA
Link para o comentário
Compartilhar em outros sites

  • Moderadores

Bom dia @ALA
A questão deste procedimento é justamente garantir uma segurança maior a informação gerada.
Já ocorreram muitas fraudes devido a este erro.  Só que quando acontecem todos gritam e ninguém quer assumir a responsabilidade.
Inclusive já culparam até a SEFAZ dizendo que os servidores da SEFAZ foram invadidos, outros disseram que os servidores de email foram invadidos e por ai se vai a imaginação fértil do povo.  (Inclusive há vídeos aonde a SEFAZ explica a situação.  Isto já é antigo, mas muitos tem dificuldades de entender o risco e ficam insistindo, até então que a SEFAZ se posiciona criando a rejeição.   Se você ver os números não permitidos vai perceber que eles tentaram imaginar o que alguns colocariam e não duvido que se tivessem acesso ao teu texto antes tentassem bloquear códigos de possíveis composição de data 😂 

Mas tirando a brincadeira de lado o caso é sério. 
Muitas empresas foram fraudadas, (como está citado nos links acima, que nossos colegas postaram sobre boletos falsos), pois já tiveram casos de que com posse da chave da nota, acessam o portal nacional e com informação de uma nota por exemplo  a crédito (duplicatas, boletos) enviaram no do email do cliente  (que está no xml) um novo boleto oferecendo descontos vantajosos se o pagamento fosse antecipado, algo assim e no boleto ou no email informavam dados da nota, data e as vezes até produtos fazendo com que isto desse credibilidade ao golpe.
Muitos por sua vez vê a vantagem, nem se importam com o email recebido e pagam, depois a empresa não recebeu e as vezes acionam na justiça o cliente que terá que pagar novamente a dívida.  Isto é muito sério e no google está cheio de relatos assim.   Aqui no forum, há um relato de alguém que diz que o fraudador chegou a ligar para eles (empresa que desenvolve)  e por telefone ia falando as notas que estavam sendo emitidas, os produtos e valores e ainda oferecendo serviço de proteção contra esta "fragilidade de segurança"   e o rapaz da software house,  pensando em vulnerabilidade do servidor de empresa, firewall, invasão de email etc, sendo que o fraudulento apenas tinha condição de criar as chaves (como ele criaria) e consultar na sefaz. Simples assim. 

Então não brinque com isto, se alguém pegar duas notas suas e entender que você usa a data para compor o código aleatorio  (cNF) ficará o mesmo caso de usar o numero da nota para cNF, ou seja não resolve nada. Todos que sabem como se compõe uma chave logo conseguirá compor a proxima. O cara faz uma tentativa de um novo número com a mesma data, digamos que  deu não encontrada ele acrescenta a próxima data e vai na tentativa novamente até dar o próximo erro, sendo necessário outra vez acrescentar a nota data.    

Quanto aos teus questionamento: 
- Sim seria bom vc gerar um número aleatório e guardar no banco de dados. (este é o ideal)

- Quando vc diz "Nunca mais consigo gerar a chave".  Em ultimo caso, se você tentar enviar novamente o mesmo numero de nota com chave diferente ele vai te retornar a informação de duplicação e vem o retorno da chave que está registrada na sefaz.  E isto só é possível com o uso do certificado e emitindo a nota, logo outros não saberão, mas o emitente tem sim a condição de saber, não estará perdido para sempre 😁

- Porém se mesmo assim você tem pouco domínio em gerar um código randômico e grava-lo no banco, você pode criar uma rotina sua para gerar este código aonde só você saiba como ele é composto. 

Exemplo: 
2 ultimos dígitos do cpf/cnpj do cliente;
2 últimos dig. do minuto da emissao ou do orçamento;
2 ult. dig. do número da nota;
1 dig. da forma de pagto, 
1 do prim. digito do valor da nota.   
Algo assim: você teria o código de 8 dígitos em mãos, uma vez que sabe a fórmula que usou para criar uma função: gerateucodigoaleatorio() e estaria dificultando para alguém que não sabe o código.     
Se for criar  invente uma, isto é apenas um  exemplo 😜  

Portanto tem N formas de fazer, porém fuja do óbvio. 
 

  • Curtir 2


logoacbr.pngConheça o Portal do Projeto ACBr

Ajude o Projeto ACBr crescer - Assine o SAC ACBr
Assine um dos planos de longa duração do SAC ACBr, obtenha Descontos Especiais, Parcele no Cartão e ainda ganhe Brindes Exclusivos. Saiba mais aqui

Conheça o ACBrLib, o ACBr de forma nativa para qualquer linguagem de programação. Saiba mais aqui

 

 

 

 

Link para o comentário
Compartilhar em outros sites

O problema de se usar a data de emissão no cNF (ou qualquer outra informação que não seja aleatória) é a possibilidade de que uma pessoa mal-intencionada descubra o padrão que está sendo utilizado para o cNF da sua aplicação. De conhecimento desse padrão, um cliente que receba uma NF-e da sua aplicação pode ter acesso a todas as NF-e emitidas pelo seu aplicativo, simplesmente consultando a chave no portal da NF-e.
O objetivo/filosofia do campo cNF é justamente impedir esse acesso indevido. Qualquer "gambiarra" objetivando enganar o sistema de validação do webservice da Receita só irá expor seus clientes a riscos desnecessários.

Link para o comentário
Compartilhar em outros sites

  • Este tópico foi criado há 1743 dias atrás.
  • Talvez seja melhor você criar um NOVO TÓPICO do que postar uma resposta aqui.

Crie uma conta ou entre para comentar

Você precisar ser um membro para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar Agora
×
×
  • Criar Novo...

Informação Importante

Colocamos cookies em seu dispositivo para ajudar a tornar este site melhor. Você pode ajustar suas configurações de cookies, caso contrário, assumiremos que você está bem para continuar.