CREATE OR REPLACE PROCEDURE GRAVA_LISTAPRECOTCO
(
   P_DTREFERENCIA IN DATE,
   P_CDREGIAO IN VARCHAR2,
   P_NRORG IN NUMBER,
   P_CDOPERADOR IN VARCHAR2,
   P_NRLISTAPRECOTCO OUT NUMBER
)
AS
   V_CDFILIAL VARCHAR2(4);
   V_CDFILCENTCMP VARCHAR2(4);
   V_IDTIPOAPUR VARCHAR2(1);

   V_CDPRODESTO VARCHAR2(10);
   V_VRFATOCONV FLOAT;
   V_VRCUSTO FLOAT;
   V_FORNECEDOR_OL VARCHAR2(1);

   V_NRLISTAPRECOTCO NUMBER;
   V_NRPRODLISTAPRECOTCO NUMBER;
   V_QTDE NUMBER;

   V_CDARVPROD VARCHAR2(20);
   V_FORNEPRIO VARCHAR2(1);
   V_CUSTOPELAMEDIA VARCHAR2(1);
   V_CDFORNECED VARCHAR2(21);
   V_CDMARCA VARCHAR2(5);

   V_VRTOTCUSTO FLOAT;
BEGIN
  -- Busca filial parametrizada no TCO
   SELECT MAX(CDFILIAL)
     INTO V_CDFILIAL
     FROM PARAMTCO;
  -- Busca a central de compras
   SELECT MAX(NVL(FILIAL.CDFILCENTCMP, FILIAL.CDFILIAL))
     INTO V_CDFILCENTCMP
     FROM FILIAL
    WHERE CDFILIAL = V_CDFILIAL;
   -- Busca informacoes da PARASUPRI
   SELECT MAX(IDTIPOAPUR)
     INTO V_IDTIPOAPUR
     FROM PARASUPRI
    WHERE CDFILIAL = V_CDFILCENTCMP;   

   IF V_CDFILCENTCMP IS NOT NULL THEN
--=========================================================
--=== Acesso a lista de precos e gravacao na lista do TCO
--=========================================================      
      V_NRLISTAPRECOTCO := TO_NUMBER(RETORNA_NOVO_CODIGO('LISTAPRECOTCO', 1));

      INSERT INTO LISTAPRECOTCO
      (NRLISTAPRECOTCO, DTREFERENCIA, CDREGIAO, CDFILIAL, IDTIPOAPUR,
       NRORG, NRORGINCLUSAO, NRORGULTATU,
       CDOPERINCLUSAO, CDOPERULTATU,
       DTINCLUSAO, DTULTATU)
      VALUES
      (V_NRLISTAPRECOTCO, P_DTREFERENCIA, P_CDREGIAO, V_CDFILCENTCMP, V_IDTIPOAPUR,
      P_NRORG, P_NRORG, P_NRORG,
      P_CDOPERADOR, P_CDOPERADOR,
      SYSDATE, SYSDATE);

      V_QTDE := 0;

      -- Percorre os itens da lista de precos segundo o filtro informado
      FOR C_ITEMCOLE IN
      (
      SELECT I.CDFILIAL,
             I.NRCOLEPRECO,
             I.CDMARCA,
             I.CDREGIAO,
             I.CDFORNECED,
             I.CDPRODUTO,                
             I.DTINIVALITM,
             I.DTFINVALITM,
             I.VRPRECUNIITM,                    
             I.VRPRECOITMPI,
             I.VRPRECECOITM,
             I.NRSEQPRELIST
         FROM ITEMCOLE I INNER JOIN COLETAPR C ON C.CDFILIAL = I.CDFILIAL AND
                                                       C.NRCOLEPRECO = I.NRCOLEPRECO
         WHERE I.CDFILIAL = V_CDFILCENTCMP
           AND P_DTREFERENCIA BETWEEN I.DTINIVALITM AND I.DTFINVALITM
           AND I.VRPRECUNIITM > 0
           AND I.CDREGIAO = P_CDREGIAO
           AND I.IDITMLISPREC = 'S'
           AND I.NRSEQPRELIST IS NOT NULL
      ) LOOP
      	-- Verifica validade da Lista disponibilizada
      	SELECT COUNT(1)
      	  INTO V_QTDE
      	  FROM PREVLISTA
      	 WHERE CDFILIAL = C_ITEMCOLE.CDFILIAL
      	   AND NRSEQPRELIST = C_ITEMCOLE.NRSEQPRELIST
      	   AND P_DTREFERENCIA BETWEEN DTINIVALLIST AND DTFINVALLIST;

      	-- Se o item da cotacao nao esta em lista de precos disponibilizada no periodo, desconsidera o item
      	IF V_QTDE = 0 THEN
      		CONTINUE;
      	END IF;


         -- Busca produto de estoque e fator de conversao
         SELECT MAX(CDPRODESTO), MAX(VRFATOCONV)
              INTO V_CDPRODESTO, V_VRFATOCONV
              FROM PRODUTO
             WHERE CDPRODUTO = C_ITEMCOLE.CDPRODUTO;
         IF NVL(V_VRFATOCONV, 0) <= 0 THEN
            V_VRFATOCONV := 1;
         END IF;

         /*Busca o codigo de arvore do produto de estoque*/
         SELECT MAX(CDARVPROD)
           INTO V_CDARVPROD
           FROM PRODUTO
          WHERE CDPRODUTO = V_CDPRODESTO;

         -- Calcula preco do produto de estoque para essa linha
         -- V_VRCUSTO := CASE NVL(V_IDTIPOAPUR, '0') WHEN '0' THEN C_ITEMCOLE.VRPRECUNIITM
         --                                         WHEN '1' THEN C_ITEMCOLE.VRPRECOITMPI
         --                                         WHEN '2' THEN C_ITEMCOLE.VRPRECECOITM
         --              END / V_VRFATOCONV;

         -- Fixo o preco nominal - solicitado pela GR
         V_VRCUSTO := C_ITEMCOLE.VRPRECUNIITM / V_VRFATOCONV;

         -- Insere item na lista de precos do TCO
         IF V_VRCUSTO > 0 THEN
            -- Verifica se fornecedor e prioritario para o produto na regiao
            SELECT MAX('S')
              INTO V_FORNEPRIO
              FROM FORNEPRIOTCO F
                   INNER JOIN PRODUTO P ON P.CDPRODUTO = F.CDPRODUTO
             WHERE F.CDREGIAO = P_CDREGIAO
               AND F.CDFORNECED = C_ITEMCOLE.CDFORNECED
               AND V_CDARVPROD LIKE P.CDARVPROD|| '%'
               /*Adicionado para que o fornecedor prioritario seja o mais proximo no cadastro do produto em questao*/
               AND NOT EXISTS (SELECT 1
                                 FROM FORNEPRIOTCO FP
                                      INNER JOIN PRODUTO PT ON PT.CDPRODUTO = FP.CDPRODUTO
                                WHERE FP.CDREGIAO = P_CDREGIAO
                                  AND FP.CDFORNECED <> F.CDFORNECED
                                  AND V_CDARVPROD LIKE PT.CDARVPROD|| '%'
                                  AND LENGTH(PT.CDARVPROD) > LENGTH(P.CDARVPROD) );

            V_FORNEPRIO := NVL(V_FORNEPRIO, 'N');

            -- Verifica se produto possui custo pela media
            SELECT MAX('S')
              INTO V_CUSTOPELAMEDIA
              FROM PRODCUSMEDIATCO PC
                   INNER JOIN PRODUTO P ON P.CDPRODUTO = PC.CDPRODUTO
             WHERE V_CDARVPROD LIKE P.CDARVPROD|| '%';

            V_CUSTOPELAMEDIA := NVL(V_CUSTOPELAMEDIA, 'N');

            V_NRPRODLISTAPRECOTCO := TO_NUMBER(RETORNA_NOVO_CODIGO('PRODLISTAPRECOTCO', 1));
            
            INSERT INTO PRODLISTAPRECOTCO
            (NRPRODLISTAPRECOTCO, NRLISTAPRECOTCO, IDESCOLHIDO, 
            CDPRODESTO, VRCUSTO, CDFILIAL, 
            NRCOLEPRECO, CDMARCA, CDREGIAO, 
            CDFORNECED, CDPRODUTO, 
            DTINIVALITM, DTFINVALITM, 
            VRPRECUNIITM, VRPRECOITMPI, VRPRECECOITM, 
            VRFATOCONV, IDFORNECEDOROL, IDCUSTOPELAMEDIA, IDFORNEPRIOTCO,
            NRORG, NRORGINCLUSAO, NRORGULTATU,
            CDOPERINCLUSAO, CDOPERULTATU,
            DTINCLUSAO, DTULTATU)
            VALUES
            (V_NRPRODLISTAPRECOTCO, V_NRLISTAPRECOTCO, 'N',
            V_CDPRODESTO, V_VRCUSTO, C_ITEMCOLE.CDFILIAL,
            C_ITEMCOLE.NRCOLEPRECO, C_ITEMCOLE.CDMARCA, C_ITEMCOLE.CDREGIAO,
            C_ITEMCOLE.CDFORNECED, C_ITEMCOLE.CDPRODUTO,
            C_ITEMCOLE.DTINIVALITM, C_ITEMCOLE.DTFINVALITM, 
            C_ITEMCOLE.VRPRECUNIITM, C_ITEMCOLE.VRPRECOITMPI, C_ITEMCOLE.VRPRECECOITM,
            V_VRFATOCONV, 'N', V_CUSTOPELAMEDIA, V_FORNEPRIO, 
            P_NRORG, P_NRORG, P_NRORG, 
            P_CDOPERADOR, P_CDOPERADOR, 
            SYSDATE, SYSDATE);
            V_QTDE := V_QTDE + 1;
         END IF;

      END LOOP;
         
--=========================================================
--=== Tratativas antes da escolha de precos
--=========================================================
      -- Apaga as linhas de fornecedores que nao atendem a regiao
      FOR C_FORN_N_ATENDE_REG IN
      (
        SELECT CDFORNECED
         FROM REFOREG
           WHERE REFOREG.CDREGIAO = P_CDREGIAO
      ) LOOP
         DELETE FROM PRODLISTAPRECOTCO
          WHERE NRLISTAPRECOTCO = V_NRLISTAPRECOTCO
            AND CDFORNECED = C_FORN_N_ATENDE_REG.CDFORNECED;
      END LOOP;

      -- Indica se fornecedor e um Operador Logistico (OL)
      FOR C_FORNOL IN
      (
         SELECT DISTINCT CDFORNOPELOG           
           FROM FILIAL
             WHERE NVL(FILIAL.IDFUNCAOFILI, 'F') = 'O'
      ) LOOP
         UPDATE PRODLISTAPRECOTCO
            SET IDFORNECEDOROL = 'S'
          WHERE NRLISTAPRECOTCO = V_NRLISTAPRECOTCO
            AND CDFORNECED = C_FORNOL.CDFORNOPELOG;
      END LOOP;

      -- Insere a linha dos itens com custo pela media     

      SELECT MAX(CDFORNECED), MAX(CDMARCA)
        INTO V_CDFORNECED, V_CDMARCA
        FROM PARAMTCO;

      FOR C_PRODCUSMEDIA IN
      (
         SELECT DISTINCT CDPRODESTO
           FROM PRODLISTAPRECOTCO
          WHERE NRLISTAPRECOTCO = V_NRLISTAPRECOTCO
            AND IDCUSTOPELAMEDIA = 'S'
      ) LOOP
         -- Se fornecedor e marca nao forem informados, nao e possivel efetuar o custo pela media, 
         -- por isso a rotina assume que e para escolher o preco no mecanismo tradicional
         IF V_CDFORNECED IS NULL OR V_CDMARCA IS NULL THEN
            UPDATE PRODLISTAPRECOTCO
               SET IDCUSTOPELAMEDIA = 'N'
             WHERE NRLISTAPRECOTCO = V_NRLISTAPRECOTCO
               AND CDPRODESTO = C_PRODCUSMEDIA.CDPRODESTO;
         ELSE
            V_VRTOTCUSTO := 0;
            V_QTDE := 0;
            -- Soma o custo unitario dos produtos a considerar a media
            FOR C_PROD IN
            (
               SELECT VRCUSTO
                 FROM PRODLISTAPRECOTCO
                WHERE NRLISTAPRECOTCO = V_NRLISTAPRECOTCO
                  AND CDPRODESTO = C_PRODCUSMEDIA.CDPRODESTO
            ) LOOP      
               V_VRTOTCUSTO := V_VRTOTCUSTO + C_PROD.VRCUSTO;
               V_QTDE := V_QTDE + 1;
            END LOOP;

            IF (V_VRTOTCUSTO > 0) THEN
               V_NRPRODLISTAPRECOTCO := TO_NUMBER(RETORNA_NOVO_CODIGO('PRODLISTAPRECOTCO', 1));
               INSERT INTO PRODLISTAPRECOTCO
               (NRPRODLISTAPRECOTCO, NRLISTAPRECOTCO, IDESCOLHIDO, 
                CDPRODESTO, VRCUSTO, CDFILIAL, 
                NRCOLEPRECO, CDMARCA, CDREGIAO, 
                CDFORNECED, CDPRODUTO, 
                DTINIVALITM, DTFINVALITM, 
                VRPRECUNIITM, VRPRECOITMPI, VRPRECECOITM, 
                VRFATOCONV, IDFORNECEDOROL, IDFORNEPRIOTCO, IDCUSTOPELAMEDIA,
                NRORG, NRORGINCLUSAO, NRORGULTATU,
                CDOPERINCLUSAO, CDOPERULTATU,
                DTINCLUSAO, DTULTATU)
               VALUES
               (V_NRPRODLISTAPRECOTCO, V_NRLISTAPRECOTCO, 'S',
                C_PRODCUSMEDIA.CDPRODESTO, V_VRTOTCUSTO/V_QTDE, V_CDFILCENTCMP,
                NULL, V_CDMARCA, P_CDREGIAO,
                V_CDFORNECED, C_PRODCUSMEDIA.CDPRODESTO,
                P_DTREFERENCIA, P_DTREFERENCIA, 
                V_VRTOTCUSTO/V_QTDE, V_VRTOTCUSTO/V_QTDE, V_VRTOTCUSTO/V_QTDE,
                1, 'N', 'N', 'S',
                P_NRORG, P_NRORG, P_NRORG, 
                P_CDOPERADOR, P_CDOPERADOR, 
                SYSDATE, SYSDATE);
            END IF;
         END IF;
      END LOOP;

--=========================================================
--=== Escolha do melhor preco segundo os criterios do TCO
--=========================================================    
      V_CDPRODESTO := NULL;
      V_NRPRODLISTAPRECOTCO := NULL;      
      FOR C_PRODLISTA IN
      (
      SELECT CDPRODESTO, NRPRODLISTAPRECOTCO, VRCUSTO, IDFORNECEDOROL, IDFORNEPRIOTCO
        FROM PRODLISTAPRECOTCO
       WHERE NRLISTAPRECOTCO = V_NRLISTAPRECOTCO
            AND IDCUSTOPELAMEDIA = 'N' -- desconsidera os custos pela media que ja foram incluidos
       /*ORDER BY OBRIGATORIO para que a logica por produto de estoque funcionar*/
       ORDER BY CDPRODESTO
      ) LOOP
         IF (V_CDPRODESTO IS NULL) OR (V_CDPRODESTO <> C_PRODLISTA.CDPRODESTO) THEN
            -- Se trocou o produto e se ja processou algum, inica o escolhido na tabela
            IF V_NRPRODLISTAPRECOTCO IS NOT NULL THEN
               UPDATE PRODLISTAPRECOTCO
                  SET IDESCOLHIDO = 'S'
                WHERE NRPRODLISTAPRECOTCO = V_NRPRODLISTAPRECOTCO; 
            END IF;
            V_CDPRODESTO := C_PRODLISTA.CDPRODESTO;
            V_NRPRODLISTAPRECOTCO := C_PRODLISTA.NRPRODLISTAPRECOTCO;
            V_VRCUSTO := C_PRODLISTA.VRCUSTO;
            V_FORNECEDOR_OL := C_PRODLISTA.IDFORNECEDOROL;
            V_FORNEPRIO := C_PRODLISTA.IDFORNEPRIOTCO;
         END IF;
         
         -- Se o escolhido ainda nao e operador OL, passa a ser o operador OL (independente do preco)
            -- Se OL e o mesmo do anteriormente escolhido e ainda nao e preferencial, passa a ser o preferencial (independente do preco)
         -- Se OL e preferencial nao mudaram, verifica se o preco e menor
         IF ((V_FORNECEDOR_OL = 'N') AND (C_PRODLISTA.IDFORNECEDOROL = 'S')) OR -- mudando para fornecedor OL
            (
               (V_FORNECEDOR_OL = C_PRODLISTA.IDFORNECEDOROL) AND 
               (
                  (V_FORNEPRIO = 'N' AND (C_PRODLISTA.IDFORNEPRIOTCO = 'S')) OR -- mudando para fornecedor prioritario
                  ((V_FORNECEDOR_OL = C_PRODLISTA.IDFORNECEDOROL) AND (V_FORNEPRIO = C_PRODLISTA.IDFORNEPRIOTCO ) AND (C_PRODLISTA.VRCUSTO < V_VRCUSTO)) -- Mudando para um preco melhor
               )
            ) THEN
            V_NRPRODLISTAPRECOTCO := C_PRODLISTA.NRPRODLISTAPRECOTCO;
            V_VRCUSTO := C_PRODLISTA.VRCUSTO;
            V_FORNECEDOR_OL := C_PRODLISTA.IDFORNECEDOROL;
            V_FORNEPRIO := C_PRODLISTA.IDFORNEPRIOTCO;
         END IF;
      END LOOP;
      IF (V_NRPRODLISTAPRECOTCO IS NOT NULL) THEN
         UPDATE PRODLISTAPRECOTCO
            SET IDESCOLHIDO = 'S'
          WHERE NRPRODLISTAPRECOTCO = V_NRPRODLISTAPRECOTCO;
      END IF;
   END IF;

   SELECT COUNT(1)
     INTO V_QTDE
     FROM PRODLISTAPRECOTCO
    WHERE NRLISTAPRECOTCO = V_NRLISTAPRECOTCO;

   -- Se nao ha itens, apaga a lista de precos gerada e sai do procedimento
   IF V_QTDE = 0 THEN
      DELETE FROM LISTAPRECOTCO
       WHERE NRLISTAPRECOTCO = V_NRLISTAPRECOTCO;

      RETURN;
   END IF;

   P_NRLISTAPRECOTCO := V_NRLISTAPRECOTCO;
END;
/