CREATE OR REPLACE FUNCTION CARREGA_LIMISEGU
(
   P_CDFILIAL        IN FILIAL.CDFILIAL%TYPE,
   P_CDARVPROD       IN PRODUTO.CDARVPROD%TYPE,
   P_DTENTREGA       IN DATE,
   P_NRLIMISEGU      IN LIMISEGPROD.NRLIMISEGU%TYPE DEFAULT NULL,
   P_CDPERIENTR      IN PERFILPROD.CDPERIENTR%TYPE DEFAULT NULL,
   P_TIPO            IN VARCHAR2 DEFAULT NULL
)  RETURN NUMBER
IS
   V_NRLIMISEGU             LIMISEGPROD.NRLIMISEGU%TYPE := P_NRLIMISEGU;
   V_NRLIMISEGCAD           LIMISEGPROD.NRLIMISEGU%TYPE;
   V_CDPERIENTR             PERIENTR.CDPERIENTR%TYPE := P_CDPERIENTR;
   V_IDDNULIMSEG            PERIENTR.IDDNULIMSEGP%TYPE;
   V_COUNT                  NUMBER := 0;
   V_NFERICOMP              NUMBER := 0;
   V_NRLIMISEGU_UTIL        NUMBER := 0;
   V_DTENTREGA              DATE;

   /* Cursor com dias uteis no intervalo de um ano a partir da data de entrega */
   CURSOR C_MAIORDATA IS
      (SELECT
          DTDATA
       FROM
          DATA
       WHERE
          (DTDATA BETWEEN P_DTENTREGA AND P_DTENTREGA + 364) AND
          ((V_IDDNULIMSEG = 'N') OR ((V_IDDNULIMSEG = 'S') AND
                                     (DTDATA NOT IN (SELECT
                                                        DTFERICOMP
                                                     FROM
                                                        FERICOMP
                                                     WHERE
                                                        (CDFILIAL   = P_CDFILIAL)  AND
                                                        (DTFERICOMP > P_DTENTREGA) AND
                                                         NOT EXISTS (SELECT 1
                                                                     FROM CALECOMP
                                                                     WHERE CALECOMP.CDFILIAL   = P_CDFILIAL
                                                                       AND CALECOMP.DTENTREGA  = DTFERICOMP
                                                                       AND CALECOMP.CDPERIENTR = P_CDPERIENTR) )))));
BEGIN
   IF P_TIPO IS NULL THEN
      IF P_CDARVPROD IS NOT NULL THEN
         SELECT NVL(MAX(TO_NUMBER(NRLIMISEGU)), 0)
           INTO V_NRLIMISEGU
           FROM LIMISEGPROD, PRODUTO
          WHERE (LIMISEGPROD.CDPRODUTO = PRODUTO.CDPRODUTO)
            AND (LIMISEGPROD.CDFILIAL  = P_CDFILIAL)
            AND (PRODUTO.CDARVPROD     = (SELECT MAX(CDARVPROD)
                                            FROM LIMISEGPROD A, PRODUTO B
                                           WHERE (A.CDPRODUTO = B.CDPRODUTO)
                                             AND (A.CDFILIAL  = P_CDFILIAL)
                                             AND (INSTR(P_CDARVPROD, B.CDARVPROD) = 1)));
         IF V_NRLIMISEGU > 0 THEN
            SELECT NVL(MAX(CDPERIENTR), 'XX')
              INTO V_CDPERIENTR
              FROM PERFILPROD
             WHERE CDFILIAL = P_CDFILIAL
               AND CDPRODUTO = (SELECT MAX(B.CDARVPROD)
                                  FROM PERFILPROD A, PRODUTO B
                                 WHERE A.CDPRODUTO = B.CDPRODUTO
                                   AND A.CDFILIAL  = P_CDFILIAL
                                   AND INSTR(P_CDARVPROD, B.CDARVPROD) = 1);
         END IF;
      END IF;
      IF V_NRLIMISEGU > 0 THEN
         IF V_CDPERIENTR <> 'XX' THEN
            SELECT NVL(MAX(PERIENTR.IDDIANUTIL), 'N')
              INTO V_IDDNULIMSEG
              FROM PERIENTR
             WHERE PERIENTR.CDPERIENTR = V_CDPERIENTR;
         END IF;
         IF V_IDDNULIMSEG IS NULL THEN
            SELECT NVL(MAX(PARASUPRI.IDDNULIMSEG), 'N')
              INTO V_IDDNULIMSEG
              FROM PARASUPRI, FILIAL
             WHERE FILIAL.CDFILIAL    = P_CDFILIAL
               AND PARASUPRI.CDFILIAL = NVL(FILIAL.CDFILCENTCMP, FILIAL.CDFILIAL);
         END IF;
         IF V_IDDNULIMSEG = 'S' THEN
            FOR C_DATA IN (SELECT DTDATA
                             FROM DATA
                            WHERE DTDATA >= P_DTENTREGA
                            ORDER BY DTDATA) LOOP

               SELECT COUNT(*)
                 INTO V_COUNT
                 FROM FERICOMP
                WHERE CDFILIAL   = P_CDFILIAL
                  AND DTFERICOMP = C_DATA.DTDATA AND
                  NOT EXISTS (SELECT 1
                                FROM CALECOMP
                               WHERE CALECOMP.CDFILIAL   = P_CDFILIAL
                                 AND CALECOMP.DTENTREGA  = DTFERICOMP
                                 AND CALECOMP.CDPERIENTR = V_CDPERIENTR);

               IF V_COUNT = 0 THEN
                  V_NFERICOMP := V_NFERICOMP + 1;
               END IF;

               V_NRLIMISEGU_UTIL := V_NRLIMISEGU_UTIL + 1;
               IF V_NFERICOMP = V_NRLIMISEGU THEN
                  V_NRLIMISEGU := V_NRLIMISEGU_UTIL;
                  EXIT;
               END IF;
            END LOOP;
         END IF;
      END IF;
   ELSIF P_TIPO = '1' THEN
      /* Busca o parametro que indica se considera dias nao uteis */
      SELECT
         MAX(PERIENTR.IDDNULIMSEGP) INTO V_IDDNULIMSEG
      FROM
         PERIENTR
      WHERE
         (PERIENTR.CDPERIENTR = P_CDPERIENTR);
      IF V_IDDNULIMSEG IS NULL THEN
         SELECT
            NVL(MAX(PARASUPRI.IDDNULIMSEG), 'N') INTO V_IDDNULIMSEG
         FROM
            PARASUPRI,
            FILIAL
         WHERE
            (FILIAL.CDFILIAL    = P_CDFILIAL) AND
            (PARASUPRI.CDFILIAL = NVL(FILIAL.CDFILCENTCMP, FILIAL.CDFILIAL));
      END IF;

      OPEN C_MAIORDATA;
      FOR V_NRCONTA IN 0..V_NRLIMISEGU LOOP
         /* Busca a ultima data ate o limite de seguranca */
         FETCH C_MAIORDATA INTO V_DTENTREGA;
         EXIT WHEN C_MAIORDATA%NOTFOUND;
      END LOOP;
      CLOSE C_MAIORDATA;
      IF V_IDDNULIMSEG = 'S' THEN
         LOOP /* loop para adiantar a data de entrega caso o dia anterior a entrega seja nao util */
            SELECT
               COUNT(*) INTO V_COUNT
            FROM
               FERICOMP
            WHERE
               (CDFILIAL   = P_CDFILIAL)     AND
               (DTFERICOMP = V_DTENTREGA - 1)AND
                NOT EXISTS (SELECT 1
                            FROM CALECOMP
                            WHERE CALECOMP.CDFILIAL   = P_CDFILIAL
                              AND CALECOMP.DTENTREGA  = DTFERICOMP
                              AND CALECOMP.CDPERIENTR = P_CDPERIENTR);
            IF V_COUNT > 0 THEN
               V_DTENTREGA := V_DTENTREGA - 1;
            ELSE
               EXIT;
            END IF;
         END LOOP;
      END IF;

      V_NRLIMISEGU := V_DTENTREGA - P_DTENTREGA;
   ELSIF P_TIPO = '2' THEN
      /* Busca o parametro que indica se considera dias nao uteis */
      SELECT
         MAX(PERIENTR.IDDNULIMSEGP) INTO V_IDDNULIMSEG
      FROM
         PERIENTR
      WHERE
         (PERIENTR.CDPERIENTR = P_CDPERIENTR);
      IF V_IDDNULIMSEG IS NULL THEN
         SELECT
            NVL(MAX(PARASUPRI.IDDNULIMSEG), 'N') INTO V_IDDNULIMSEG
         FROM
            PARASUPRI,
            FILIAL
         WHERE
            (FILIAL.CDFILIAL    = P_CDFILIAL) AND
            (PARASUPRI.CDFILIAL = NVL(FILIAL.CDFILCENTCMP, FILIAL.CDFILIAL));
      END IF;

      OPEN C_MAIORDATA;
      FOR V_NRCONTA IN 0..V_NRLIMISEGU LOOP
         /* Busca a ultima data ate o limite de seguranca */
         FETCH C_MAIORDATA INTO V_DTENTREGA;
         EXIT WHEN C_MAIORDATA%NOTFOUND;
      END LOOP;
      CLOSE C_MAIORDATA;
      V_NRLIMISEGU := V_DTENTREGA - P_DTENTREGA;
   END IF;
   RETURN(V_NRLIMISEGU);
END;
/