domingo, 20 de novembro de 2011

Como Validar Código de Barras GTIN, antigo EAN13 no SQL SERVER 2008


Como Validar Código de Barras GTIN, antigo EAN13 no SQL SERVER 2008

Com as exigências da SEFAZ, no tocante a Nota Fiscal Eletrônica, tornou-se uma exigência do Governo Federal Brasileiro o uso do código de barras EAN13 ou GTIN (Global Trade Item Number), válido.

Então segue uma store function desenvolvida em T-SQL do SQL Server 2008, para validar esse troço.

Depois vai ser o chip na mão e na testa ... Espero está na Glória com Cristo, para não vê o resultado final... 666 tá chegando...

Mas, enquanto não chega, segue uma store function para aliviar o stress de quem trabalhar com isso...

-- Nome Artefato/Programa..: sp_valida_ean13.sql
-- Autor(es)...............: Emerson Hermann (emersonhermann [at] gmail.com) O Peregrino (http://www.emersonhermann.blogspot.com) 
-- Data Inicio ............: 20/11/2011
-- Data Atualizacao........: 22/11/2011
-- Versao..................: 0.01
-- Compilador/Interpretador: T-SQL (Transact SQL) 
-- Sistemas Operacionais...: Windows
-- SGBD....................: MS SQL Server 2005/2008
-- Kernel..................: Nao informado!
-- Finalidade..............: store procedure (function) para testa se um um código de barras (EAN13-GTIN) é valido ou não, retorna 1 para verdadeiro e 0 para falso 
-- OBS.....................: 
--

IF EXISTS (
            SELECT * 
              FROM sys.objects 
             WHERE object_id = OBJECT_ID(N'[dbo].[sp_valida_ean13]') 
               AND type IN (N'FN')
           )
 DROP FUNCTION sp_valida_ean13;
GO
CREATE FUNCTION sp_valida_ean13(@number varchar(max)) RETURNS smallint AS
BEGIN
 DECLARE @c bigint
 DECLARE @r smallint
 DECLARE @i smallint
 DECLARE @x smallint
 DECLARE @sum smallint
 DECLARE @mult smallint
 DECLARE @number_split varchar(1)
 SET @x   = 0
 SET @sum = 0 
 SET @i   = 1 
 SET @c   = len(@number)

 -- se cb for maior que 13 
 IF @c > 13 BEGIN
    SET @r = 0
 END

 -- se cb for menor que 13
 IF @c < 13 BEGIN
    SET @r = 0
 END

 --se for nulo 
 IF @number IS NULL BEGIN
    SET @r = NULL  
 
 END ELSE BEGIN

    --se não for nulo pode ser válido 
    SET @x = (SELECT CASE WHEN patindex('%[^0-9]%', @number) > 0 THEN 0 ELSE 1 END) 
 
    IF @c = 13 AND @x = 1  BEGIN

       WHILE @i<=(@c-1) BEGIN

          --fazendo um split do cb 
          SET @number_split=substring (@number,@i,1)
          --multiplicam-se os digitos do cb por 1 e por 3, em sequencia repetitiva de 1 e 3;
          IF (@i % 2) = 0 BEGIN
             SET @sum = @sum + cast(@number_split as int) * 3  
          END ELSE BEGIN
             SET @sum = @sum + cast(@number_split as int) * 1  
          END
          --incremento
          SET @i=@i+1

       END

       --com a soma do resultado das multiplicacoes...
       --sera necessario encontrar o multiplo de 10 mais proximo do resultado da soma. 
       --atencao: o multiplo de 10 deve ser maior ou igual ao resultado da soma (nunca menor).  
       SET @mult = ( ( 1 + cast(@sum / 10 as int) ) * 10 ) 
       --subtraindo o resultado da soma do multiplo que foi encontrado
       SET @mult = @mult - @sum 
       --o resultado desta subtracao será o digito verificador
       --entao se o ultimo digito do cb, isto e, 
       --13o numero for igual ao resultado desta subtracao entao e um cb valido

       IF cast(substring(@number,13,1) as int) = @mult BEGIN
          SET @r = 1
       END ELSE BEGIN
          SET @r = 0
       END   

    END ELSE BEGIN
       SET @r = 0 
    END    
 
 END --fim_se
 
 RETURN (@r)

END;
GO



-- Exemplo de Uso: 

-- Exemplo: 01, uso simples
-- O EAN13 impresso na Lata de Leite Ninho 400g
-- SELECT dbo.sp_valida_ean13('7891000142202');   --retorna 1, pois é valido 

-- Exemplo: 02, descobrir todos os produtos com EAN13 ou GTIN inválido 
-- SELECT * FROM produto WHERE dbo.sp_valida_ean13(gtim)=0; 
-- GO

12 comentários:

  1. Parabéns!!!

    Att,

    Claudio Estezi

    ResponderExcluir
  2. Fantástico!

    Já coloquei em uso aqui na empresa onde desenvolvo e quebrou um puta galho, pois algumas de nossas fiscais não estavam sendo autorizadas pelo Sefaz pois o EAN era inválido... ...e pra descobrir no "olhometro" é impossível!

    Parabéns!

    ResponderExcluir
  3. Este código já me tirou do sufoco várias vezes. Contudo, ele ainda traz alguns resultados falsos. Exemplo:

    0885370314670
    0790069343100
    7945045858410
    7892509072670
    7898560270420
    8713439198560
    7899403703375

    só o último tá inválido, porém, o script aponta todos estes.

    ResponderExcluir
  4. create Function UDF_Valida_Ean_13(@Ean varchar(13)) returns varchar(1) as
    begin

    --declare @Ean varchar(13) = '5010017088439' -- 088537031467
    declare @12Dig varchar(12)
    declare @Valor1 int
    declare @Valor2 int
    declare @Valor3 int
    declare @Mult10 int
    declare @DigVerificador int
    declare @DigVerifCalculado int
    declare @Retorno varchar(1)

    set @DigVerificador = convert(int,substring(@Ean,13,1))

    set @12Dig = SUBSTRING(@Ean,1,12)

    -- Soma Posições Pares e Multiplica por 3
    set @Valor1 = convert(int,SUBSTRING(@Ean,2,1)) +
    convert(int,SUBSTRING(@Ean,4,1)) +
    convert(int,SUBSTRING(@Ean,6,1)) +
    convert(int,SUBSTRING(@Ean,8,1)) +
    convert(int,SUBSTRING(@Ean,10,1)) +
    convert(int,SUBSTRING(@Ean,12,1))
    set @Valor1 = @Valor1 * 3

    -- Soma Posições Impares
    set @Valor2 = convert(int,SUBSTRING(@Ean,1,1)) +
    convert(int,SUBSTRING(@Ean,3,1)) +
    convert(int,SUBSTRING(@Ean,5,1)) +
    convert(int,SUBSTRING(@Ean,7,1)) +
    convert(int,SUBSTRING(@Ean,9,1)) +
    convert(int,SUBSTRING(@Ean,11,1))

    set @Valor3 = @Valor1 + @Valor2

    -- Verifica Próximo Múltiplo de 10
    if (@Valor3 <= 10)
    set @Mult10 = 10
    else
    if ((@Valor3 % 10) = 0)
    set @Mult10 = @Valor3
    else
    begin
    if (@Valor3 >= 100)
    set @Mult10 = (convert(int,Substring(convert(varchar(3),@Valor3),1,2)) + 1) * 10
    else
    set @Mult10 = (convert(int,Substring(convert(varchar(2),@Valor3),1,1)) + 1) * 10
    end

    -- Subtrai o Múltiplo de 10 pelo valor calculado para achar o Dígito Verificador
    set @DigVerifCalculado = @Mult10 - @Valor3

    if (@DigVerifCalculado = @DigVerificador)
    set @Retorno = 'S'
    else
    set @Retorno = 'N'

    return(@Retorno)

    end

    ResponderExcluir
    Respostas
    1. Obrigado Lukinhas pela sugestão de solução, não testei, mas espero que tenha corrigindo o BUG, apresentado por Daniel Viana, estava sem tempo para corrigir.
      O bom da internet é isso, compartilhar o conhecimento.
      Desde já agradeço.

      Excluir
  5. Como faço para adptar esse código para vb6 ?

    ResponderExcluir
    Respostas
    1. Sugiro vê o algoritmo do EAN13 [1], inclusive tem apresentação codificada em Transact SQL SERVER(outro forma de se chegar ao mesmo resultado) e em outras linguagens
      [1] https://pt.wikipedia.org/wiki/EAN-13
      Boa sorte!

      Excluir
  6. /* FIZ EM MYSQL, VALIDA TUDO CERTINHO */

    DELIMITER $$

    DROP FUNCTION IF EXISTS `Valida_Ean_13` $$
    CREATE FUNCTION `valida_ean_13`(ean varchar(255)) RETURNS BOOLEAN
    BEGIN

    IF(length(ean)!=13) THEN RETURN FALSE; END IF;

    SET @ean=ean;
    SET @digverificador = cast(substring(@ean, 13, 1) AS unsigned);
    SET @factor='3';
    SET @sum='0';

    /* soma todos os digitos multiplicando os impares pelo factor;*/
    SET @sum=(
    (cast(substring(@ean, 1, 1) AS unsigned)*1)
    + (cast(substring(@ean, 2, 1) AS unsigned)*@factor)
    + (cast(substring(@ean, 3, 1) AS unsigned)*1)
    + (cast(substring(@ean, 4, 1) AS unsigned)*@factor)
    + (cast(substring(@ean, 5, 1) AS unsigned)*1)
    + (cast(substring(@ean, 6, 1) AS unsigned)*@factor)
    + (cast(substring(@ean, 7, 1) AS unsigned)*1)
    + (cast(substring(@ean, 8, 1) AS unsigned)*@factor)
    + (cast(substring(@ean, 9, 1) AS unsigned)*1)
    + (cast(substring(@ean, 10, 1) AS unsigned)*@factor)
    + (cast(substring(@ean, 11, 1) AS unsigned)*1)
    + (cast(substring(@ean, 12, 1) AS unsigned)*@factor));

    SET @digverifcalculado=((1000 - @sum) % 10);

    IF (@digverifcalculado = @digverificador) THEN
    SET @retorno = TRUE;
    ELSE
    SET @retorno = FALSE;
    END IF;

    RETURN @retorno;

    END $$
    DELIMITER ;

    ResponderExcluir
  7. /* EM MYSQL VALIDANDO GTIN-8 , 12 E 13 */

    DELIMITER $$

    DROP FUNCTION IF EXISTS `valida_ean` $$
    CREATE FUNCTION `valida_ean`(codigo varchar(255)) RETURNS int(11)
    BEGIN

    IF(length(codigo)!=8
    && length(codigo)!=12
    && length(codigo)!=13)
    THEN RETURN FALSE; END IF;

    SET @ean=codigo;

    SET @factor='3';
    SET @sum='0';
    SET @digverifcalculado=null;
    SET @numLenSemDv = (length(@ean) - 1);
    SET @digverificador = cast(substring(@ean, @numLenSemDv+1, 1) AS unsigned);

    SET @index = @numLenSemDv;

    ##################################
    loop_while: LOOP
    -- -- -- -- -- -- -- -- -- -- --

    SET @sum = (@sum+(cast(substring(@ean, @index, 1) AS unsigned)*@factor));
    SET @factor = (4 - @factor);

    -- -- -- -- -- -- -- -- -- -- --
    SET @index = (@index - 1);
    IF @index = 0 THEN
    LEAVE loop_while;
    END IF;
    END LOOP loop_while;
    ##################################

    SET @digverifcalculado=((1000 - @sum) % 10);

    IF (@digverifcalculado = @digverificador) THEN
    SET @retorno = TRUE;
    ELSE
    SET @retorno = FALSE;
    END IF;

    RETURN @retorno;

    END $$

    DELIMITER ;

    ResponderExcluir