segunda-feira, 20 de dezembro de 2010

Cálculo do Dígito Verificador da Chave de Acesso do CT-e

Fonte:  www.activedelphi.com.br

Antes de demonstrar 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)

O Cálculo
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 também um botão para acionar o evento do cálculo quando clicar. Veja como ficou a interface na figura 1:
 O primeiro Edit vamos chamá-lo de edtChave. O segundo Edit, 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 igual à “5”
Agora vamos ao código do botão.  O algoritmo foi montada de forma bem primária para facilitar o entendimento, mas lembre-se que você pode usar arrays para facilitar:
procedure TForm1.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
    edtDV.Text := '0'
  else
    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.