CREATE OR REPLACE FUNCTION VALIDA_CHAVE_NFE
   (P_CDFILIAL   IN NOTAFISCAL.CDFILIAL%TYPE,
    P_NRLANCTONF IN NOTAFISCAL.NRLANCTONF%TYPE) RETURN VARCHAR
AS
   V_RETORNO      VARCHAR2(300);
   V_STPESO       VARCHAR2(43);
   V_NRSOMA       NUMBER;
   V_DIGVERIF     NUMBER;
   V_CNPJINSCEST  VARCHAR2(20);
   V_IDNFPRODUTOR VARCHAR2(01);
BEGIN
   FOR C_NOTA IN (SELECT LPAD(DECODE(N.IDENTRSAIDOP,'E',N.CDSERIEENTR,N.CDSERIE),3,'0') AS SERIE,
                         LPAD(DECODE(N.IDSTATUSNFE,'A',N.NRNOTAFISCALELE,N.NRNOTAFISC),20,'0') AS NUMERO,
                         TO_CHAR(N.DTEMISSAO,'MM') AS MES, TO_CHAR(N.DTEMISSAO,'YY') AS ANO, N.IDENTRSAIDOP,
                         REPLACE(REPLACE(N.NRACESSONFE,'.'),' ') AS CHAVE, N.CDMODDOCFISC AS MODELO, P.IDVERINSFORCHNFE,
                         REPLACE(REPLACE(REPLACE(REPLACE(DECODE(N.IDENTRSAIDOP,'E',N.NRINSJURNF,F.NRINSJURFILI),'.'),'-'),'/'),' ') AS CNPJ,
                         N.CDINSCESTA, N.CDFILIAL, N.NRLANCTONF
                    FROM NOTAFISCAL N, PARAMFORNE P, FILIAL F
                   WHERE N.CDFILIAL   = P_CDFILIAL
                     AND N.NRLANCTONF = P_NRLANCTONF
                     AND N.CDFORNECED = P.CDFORNECED(+)
                     AND DECODE(N.IDENTRSAIDOP,'E',N.CDFILIRECE,N.CDFILIEMIT) = F.CDFILIAL) LOOP

      /*VERIFICA SE A NOTA NAO E ELETRONICA E POSSUI CHAVE DE ACESSO*/
      IF (C_NOTA.MODELO NOT IN ('55','57')) AND (C_NOTA.CHAVE IS NOT NULL) THEN
         V_RETORNO := 'NF nao eletronica nao deve possuir chave de acesso';
         EXIT;

      /*VERIFICA SE A NOTA E ELETRONICA E NAO POSSUI CHAVE DE ACESSO*/
      ELSIF (C_NOTA.CHAVE IS NULL) AND (C_NOTA.MODELO IN ('55','57')) THEN
         V_RETORNO := 'NF-e (Modelo 55) ou CT-e (Modelo 57) sem chave de acesso';
         EXIT;
      END IF;

      /*VERIFICA O TAMANHO DA CHAVE DE ACESSO*/
      IF LENGTH(C_NOTA.CHAVE) <> 44 THEN
         V_RETORNO := 'Chave de acesso de NF-e deve possuir 44 caracteres';
         EXIT;
      ELSE
         /*VALIDA INFORMACOES DA CHAVE COM AS INFORMACOES DA NF*/

         /*DATA*/
         IF (SUBSTR(C_NOTA.CHAVE,3,4) <> C_NOTA.ANO||C_NOTA.MES) THEN
            V_RETORNO := 'Data da chave e diferente da data de emissao da nota';
            EXIT;
         END IF;

         /*CNPJ*/
         IF ((C_NOTA.IDENTRSAIDOP = 'S') OR ((C_NOTA.IDENTRSAIDOP = 'E') AND(C_NOTA.IDVERINSFORCHNFE = 'S'))) THEN
            IF (SUBSTR(C_NOTA.CHAVE,7,14) <> C_NOTA.CNPJ) THEN
               IF (C_NOTA.IDENTRSAIDOP = 'S') THEN
                  BEGIN
                     SELECT NRINSJURIEST
                       INTO V_CNPJINSCEST
                       FROM INSCRESTAD
                      WHERE CDINSCESTA = C_NOTA.CDINSCESTA;
                  EXCEPTION
                     WHEN NO_DATA_FOUND THEN
                        V_CNPJINSCEST := NULL;
                  END;
                  IF (SUBSTR(C_NOTA.CHAVE,7,14) <>  V_CNPJINSCEST) OR (V_CNPJINSCEST IS NULL) THEN
                     V_RETORNO := 'CNPJ da chave e diferente do CNPJ da nota';
                     EXIT;
                  END IF;
               ELSE
                  V_IDNFPRODUTOR := 'N';
                  BEGIN
                     SELECT 'S'
                       INTO V_IDNFPRODUTOR
                       FROM NFPRODRURAL
                      WHERE CDFILIAL   = C_NOTA.CDFILIAL
                        AND NRLANCTONF = C_NOTA.NRLANCTONF;
                  EXCEPTION
                     WHEN NO_DATA_FOUND THEN
                        V_IDNFPRODUTOR := 'N';
                  END;
                  IF ((NOT(C_NOTA.SERIE BETWEEN '890' AND '899')) AND (V_IDNFPRODUTOR = 'N')) THEN
                     V_RETORNO := 'CNPJ da chave e diferente do CNPJ da nota';
                     EXIT;
                  END IF;
               END IF;
            END IF;
         END IF;

         /*MODELO*/
         IF (SUBSTR(C_NOTA.CHAVE,21,2) <> C_NOTA.MODELO) THEN
            V_RETORNO := 'Modelo da chave e diferente do modelo da nota';
            EXIT;
         END IF;

         /*SERIE*/
         IF SUBSTR(C_NOTA.CHAVE,23,3) <> C_NOTA.SERIE THEN
            V_RETORNO := 'Serie da chave e diferente da serie da nota';
            EXIT;
         END IF;

         /*NUMERO*/
         IF (LPAD(SUBSTR(C_NOTA.CHAVE,26,9),20,'0') <> C_NOTA.NUMERO) THEN
            V_RETORNO := 'Numero da NF na chave e diferente do numero da nota';
            EXIT;
         END IF;

         /*DIGITO VERIFICADOR DA CHAVE*/
         V_STPESO := '4329876543298765432987654329876543298765432';
         V_NRSOMA := 0;
         FOR I IN 1..LENGTH(V_STPESO) LOOP
            V_NRSOMA :=  V_NRSOMA + (TO_NUMBER(SUBSTR(C_NOTA.CHAVE,I,1)) * TO_NUMBER(SUBSTR(V_STPESO,I,1)));
         END LOOP;
         V_DIGVERIF := V_NRSOMA MOD 11;
         IF V_DIGVERIF IN (0,1) THEN
            V_DIGVERIF := 0;
         ELSE
            V_DIGVERIF := 11 - V_DIGVERIF;
         END IF;
         IF SUBSTR(C_NOTA.CHAVE,44,1) <> TO_CHAR(V_DIGVERIF) THEN
            V_RETORNO := 'Digito verificador da chave de acesso invalido';
            EXIT;
         END IF;
      END IF;
   END LOOP;

   IF V_RETORNO IS NULL THEN
      V_RETORNO := 'OK';
   END IF;

   RETURN(V_RETORNO);
END;
/