terça-feira, 10 de abril de 2007

Calculando dígito verificador (DV) para contas da Caixa Econômica Federal (CEF)

Hoje me deparei com uma situação: estou fazendo uma integração com a CEF e muitas vezes tenho registros rejeitados pois o DV da conta está incorreto.

Minha primeira pergunta: como calculo o dígito verificador? Descobri, por contato telefônico, que é pelo módulo 11.
Desta forma, encontrei uma referência no Wikipedia. Porém, ao calcular, não batia (eu possuo poupança na CEF e serviu para testes...).
Após mais alguns passos no Google, achei uma referência interessante (role direto para a página 3). É necessário considerar, também, a agência e operação de conta!

Agora, com o algoritmo claramente definido, implementei a função em PostgreSQL (pl/pgsql), que ficou assim (a formatação foi perdida quando colei... mais tarde tento aprender a fazer isto):

CREATE OR REPLACE FUNCTION calculaDigitoCaixa(_dados varchar) RETURNS int2 AS $$
DECLARE
i integer;
peso integer;
base integer;
total integer;
resto integer;
dados varchar;
BEGIN
-- Verificar a consistência dos dados!
dados := COALESCE(_dados, '');
IF (LENGTH(COALESCE(_dados, '')) != 15) THEN
RAISE WARNING 'Dados não contém um tamanho válido! Tamanho: % Nulo: % Entrada: %', LENGTH(dados), _dados IS NULL, dados;
END IF;

peso := null;
total := 0;
-- Iniciar cálculo...
FOR i IN REVERSE LENGTH(dados)..1 LOOP
-- Qual peso?
IF (COALESCE(peso, 10) >= 9) THEN
peso := 2;
ELSE
peso := peso + 1;END IF;
-- Qual base?
base := SUBSTR(dados, i, 1)::int;

RAISE NOTICE 'Peso % * Base %', peso, base;
-- multiplica base * peso e acumula total
total := total + base * peso;
END LOOP;
RAISE NOTICE 'Total: %', total;
-- Multiplicar total por 10
total := total * 10;

-- O resultado então é o resto da divisão por 11. Caso seja 10, então é 0.
resto := total % 11;

RAISE NOTICE 'Resto: %', resto;
IF (resto = 10) THEN
resto := 0;
END IF;

RETURN resto;
END;
$$ LANGUAGE plpgsql IMMUTABLE;

Coloquei a mesma IMMUTABLE, pois sempre haverá o mesmo retorno para uma mesma entrada (documentação)...

Agora basta validar, por exemplo:

SELECT calculaDigitoCaixa(agencia, operacao_conta, conta) FROM fornecedor ...

Um comentário:

Jeison disse...

Obrigado pelas infos! Estou procurando algo para todos os bancos.

Abs