quinta-feira, 16 de dezembro de 2010

CÁLCULO DO DÍGITO VERIFICADOR DA CHAVE DE ACESSO DO CT-e

Olá pessoal!!
Neste artigo pretendo demonstrar como realizar o cálculo do dígito verificador da chave de acesso do CTe.
Antes de demonstrar o como gerar o digito verificador, vamos entender do que é composta a chave de acesso.
A Chave de Acesso do Conhecimento de Transporte Eletrônico é representada por uma seqüência de 44 caracteres numéricos, representados da seguinte forma:

Código da UF - Código da UF do emitente do Documento Fiscal (Tamanho 2 caracteres)
Ano e Mês da Emissão (AAMM) - Ano e Mês de emissão do CT-e (Tamanho 4 caracteres)
CNPJ - CNPJ do emitente (Tamanho 14 caracteres)
Modelo - Modelo do Documento Fiscal (Tamanho 2 caracteres)
Série - Série do Documento Fiscal (Tamanho 3 caracteres)
Numero do CTe - Número do Documento Fiscal (Tamanho 9 caracteres)
Código Numérico - Código Numérico que compõe a Chave de Acesso (Tamanho 9 caracteres)
 Digito - Dígito Verificador da Chave de Acesso (Tamanho 1 caractere)

CÁLCULO DO DÍGITO VERIFICADOR DA CHAVE DE ACESSO DO CT-e
O dígito verificador da chave de acesso do CT-e é baseado em um cálculo do módulo 11.
O módulo 11 de um número é calculado multiplicando-se cada algarismo pela seqüência de multiplicadores 2,3,4,5,6,7,8,9,2,3, ... posicionados da direita para a esquerda.
A somatória dos resultados das ponderações dos algarismos é dividida por 11 e o DV (dígito verificador) será a diferença entre o divisor (11) e o resto da divisão:
DV = 11 - (resto da divisão)
Quando o resto da divisão for 0 (zero) ou 1 (um), o DV deverá ser igual a 0 (zero).


  

Vamos exemplificar toda essa teoria no Delphi
Primeiro devemos desenhar o formulário, nesse exemplo estou utilizando dois edit’s para exemplificar melhor o funcionamento, porém em seu projeto poderá realizar tudo no mesmo Edit... Coloquei um botão para acionar o evento do cálculo quando clicar.

O primeiro Edit vamos chamá-lo de edtChave. O segundo Edit vamos chamá-lo de edtDV.
No edtChave, vamos informar uma chave de exemplo, retirada da página 74 do Manual de Integração – Contribuinte Padrões Técnicos de Comunicação.

Chave Exemplo:
5206043300991100250655012000000780026730161
O dígito verificador dessa chave deverá ser à “5”

Agora vamos ao código do botão,  vou montar esse algoritmo de forma bem primária, lembre-se que você pode usar arrays para facilitar...

procedure TForm2.btnGerarDigitoClick(Sender: TObject);
Var

// Essas serão as variáveis responsáveis por armazenar cada numero da chave
V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, V30, V31, V32, V33, V34, V35, V36, V37, V38, V39, V40,V41, V42, V43 : Real;
// as variáveis abaixo serão responsáveis por armazenar os resultados das multiplicações
R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, R18, R19, R20, R21, R22, R23, R24, R25, R26, R27, R28, R29, R30, R31, R32, R33, R34, R35, R36, R37, R38, R39, R40, R41, R42, R43 : Real;
//Utilizaremos as variáveis abaixo para formulação do resultado
Soma, Divisao, Resultado :real;
SomaI: integer;
begin
// Através do código abaixo, vamos separar os valores com a “função Copy”da chave de acesso
V1 := StrToFloat(Copy(edtChaveAcesso.Text,1,1));
V2 := StrToFloat(Copy(edtChaveAcesso.Text,2,1));
V3 := StrToFloat(Copy(edtChaveAcesso.Text,3,1));
V4 := StrToFloat(Copy(edtChaveAcesso.Text,4,1));
V5 := StrToFloat(Copy(edtChaveAcesso.Text,5,1));
V6 := StrToFloat(Copy(edtChaveAcesso.Text,6,1));
V7 := StrToFloat(Copy(edtChaveAcesso.Text,7,1));
V8 := StrToFloat(Copy(edtChaveAcesso.Text,8,1));
V9 := StrToFloat(Copy(edtChaveAcesso.Text,9,1));
V10 := StrToFloat(Copy(edtChaveAcesso.Text,10,1));
V11 := StrToFloat(Copy(edtChaveAcesso.Text,11,1));
V12 := StrToFloat(Copy(edtChaveAcesso.Text,12,1));
V13 := StrToFloat(Copy(edtChaveAcesso.Text,13,1));
V14 := StrToFloat(Copy(edtChaveAcesso.Text,14,1));
V15 := StrToFloat(Copy(edtChaveAcesso.Text,15,1));
V16 := StrToFloat(Copy(edtChaveAcesso.Text,16,1));
V17 := StrToFloat(Copy(edtChaveAcesso.Text,17,1));
V18 := StrToFloat(Copy(edtChaveAcesso.Text,18,1));
V19 := StrToFloat(Copy(edtChaveAcesso.Text,19,1));
V20 := StrToFloat(Copy(edtChaveAcesso.Text,20,1));
V21 := StrToFloat(Copy(edtChaveAcesso.Text,21,1));
V22 := StrToFloat(Copy(edtChaveAcesso.Text,22,1));
V23 := StrToFloat(Copy(edtChaveAcesso.Text,23,1));
V24 := StrToFloat(Copy(edtChaveAcesso.Text,24,1));
V25 := StrToFloat(Copy(edtChaveAcesso.Text,25,1));
V26 := StrToFloat(Copy(edtChaveAcesso.Text,26,1));
V27 := StrToFloat(Copy(edtChaveAcesso.Text,27,1));
V28 := StrToFloat(Copy(edtChaveAcesso.Text,28,1));
V29 := StrToFloat(Copy(edtChaveAcesso.Text,29,1));
V30 := StrToFloat(Copy(edtChaveAcesso.Text,30,1));
V31 := StrToFloat(Copy(edtChaveAcesso.Text,31,1));
V32 := StrToFloat(Copy(edtChaveAcesso.Text,32,1));
V33 := StrToFloat(Copy(edtChaveAcesso.Text,33,1));
V34 := StrToFloat(Copy(edtChaveAcesso.Text,34,1));
V35 := StrToFloat(Copy(edtChaveAcesso.Text,35,1));
V36 := StrToFloat(Copy(edtChaveAcesso.Text,36,1));
V37 := StrToFloat(Copy(edtChaveAcesso.Text,37,1));
V38 := StrToFloat(Copy(edtChaveAcesso.Text,38,1));
V39 := StrToFloat(Copy(edtChaveAcesso.Text,39,1));
V40 := StrToFloat(Copy(edtChaveAcesso.Text,40,1));
V41 := StrToFloat(Copy(edtChaveAcesso.Text,41,1));
V42 := StrToFloat(Copy(edtChaveAcesso.Text,42,1));
V43 := StrToFloat(Copy(edtChaveAcesso.Text,43,1));

// Conforme explicado anteriormente neste artigo, faremos a multiplicação por  2,3,4,....9
R43 := V43*2;
R42 := V42*3;
R41 := V41*4;
R40 := V40*5;
R39 := V39*6;
R38 := V38*7;
R37 := V37*8;
R36 := V36*9;
R35 := V35*2;
R34 := V34*3;
R33 := V33*4;
R32 := V32*5;
R31 := V31*6;
R30 := V30*7;
R29 := V29*8;
R28 := V28*9;
R27 := V27*2;
R26 := V26*3;
R25 := V25*4;
R24 := V24*5;
R23 := V23*6;
R22 := V22*7;
R21 := V21*8;
R20 := V20*9;
R19 := V19*2;
R18 := V18*3;
R17 := V17*4;
R16 := V16*5;
R15 := V15*6;
R14 := V14*7;
R13 := V13*8;
R12 := V12*9;
R11 := V11*2;
R10 := V10*3;
R9 := V9*4;
R8 := V8*5;
R7 := V7*6;
R6 := V6*7;
R5 := V5*8;
R4 := V4*9;
R3 := V3*2;
R2 := V2*3;
R1 := V1*4;
// Somaremos os valores obtidos dos resultados das multiplicações
Soma := R1+ R2+ R3+ R4+ R5+ R6+ R7+ R8+ R9+ R10+ R11+ R12+ R13+ R14+ R15+ R16+ R17+ R18+ R19+ R20+R21+ R22+ R23+ R24+ R25+ R26+ R27+ R28+ R29+ R30+R31+ R32+ R33+ R34+ R35+ R36+ R37+ R38+ R39+ R40+ R41+ R42+ R43;

SomaI := Trunc(Soma);
Divisao := (SomaI mod 11);
Resultado := 11-Divisao;

// Compara se o resultado é igual a 1 (Se for deverá ser = 0)
if Resultado = 1 then
begin
  edtDV.Text := '0';
end
    else
      begin

      edtDV.Text := FloatToStr(Resultado);
      end;

Pronto!! Agora é só adaptar o algoritmo ao seu projeto, para customizar e reduzir o tamanho do código, você poderá utilizar arrays para alimentação das variáveis e multiplicação dos resultados...
Um grade abraço!
Até o próximo artigo!

6 comentários:

  1. Este comentário foi removido pelo autor.

    ResponderExcluir
  2. valeu mesmo a dica cara..
    adaptei para a linguagem 4gl da progress e fiz umas simplificações.
    O seu algoritmo não funcionou pra mim. Tinha um erro no teste final do resto da divisão
    fiz como o site mostra que deve ser feito:

    pagina 77 - https://www.fazenda.sp.gov.br/cte/downloads/Manual_CTe_v101.pdf



    abaixo o meu código:



    run pi-valida-chave-cte ( "5206043300991100250655012000000780026730161" ).
    MESSAGE "Digito: " return-value VIEW-AS ALERT-BOX INFO BUTTONS OK.


    procedure pi-valida-chave-cte:

    DEFINE INPUT PARAMETER p-chave AS CHARACTER NO-UNDO. /*chave com as 43 posições iniciais*/

    DEFINE VARIABLE Soma AS DECIMAL NO-UNDO.
    DEFINE VARIABLE resto-da-Divisao AS DECIMAL NO-UNDO.
    DEFINE VARIABLE Resultado AS DECIMAL NO-UNDO.
    DEFINE VARIABLE vetor-resultados AS DECIMAL no-undo extent 43.

    DEFINE VARIABLE i-cont AS INTEGER NO-UNDO.
    DEFINE VARIABLE i-multiplicador AS INTEGER no-undo init 2.
    DEFINE VARIABLE c-digito AS CHARACTER NO-UNDO.

    do i-cont = 43 to 1 by -1:
    vetor-resultados[i-cont] = DECIMAL ( substring ( p-chave,i-cont,1 ) ) * i-multiplicador.
    i-multiplicador = i-multiplicador + 1.
    if i-multiplicador = 10 then i-multiplicador = 2.
    end.

    /* // Somaremos os valores obtidos dos resultados das multiplicações */
    do i-cont = 1 to 43:
    soma = soma + vetor-resultados[i-cont].
    end.

    resto-da-Divisao = (Soma modulo 11).
    c-digito = string(11 - resto-da-Divisao).

    /* Quando o resto da divisão for 0 (zero) ou 1 (um), o DV deverá ser igual a 0 (zero). */
    if resto-da-Divisao = 0 or resto-da-Divisao = 1 then c-digito = '0'.

    return c-digito.

    end procedure.


    Se rolar alguma duvida é só me procurar:
    walder kneip filho
    kfwalder@gmail.com

    ResponderExcluir
  3. Exite um erro
    if Resultado > 9 then
    begin
    edtDV.Text := '0';
    end
    else
    begin
    edtDV.Text := FloatToStr(Resultado);
    end;

    ResponderExcluir