create or replace PROCEDURE ATUALIZA_CUSTO_ABSORCAO
   (P_CDFILIAL     IN FILIAL.CDFILIAL%TYPE,
    P_DATACUSTO    IN FILIAL.DTULTATU%TYPE,
    P_CDPRODINI    IN PRODUTO.CDARVPROD%TYPE,
    P_CDPRODFIN    IN PRODUTO.CDARVPROD%TYPE,
    P_ERRO         OUT VARCHAR)

AS
   V_VRCUSTOCONT   FLOAT;
   V_QTTEMPOAPO    FLOAT;
   V_COUNT         INTEGER;
   V_QTHRTOTAL     FLOAT;
   V_DTINICCONT    DATE;
   V_DTFINACONT    DATE;
BEGIN
   P_ERRO := 'N';

   /* Verifica contas contabeis associadas para calculo do custo */
   BEGIN
      SELECT ABS(SUM(S.VRLANCAMENT))
        INTO V_VRCUSTOCONT
        FROM ATUCUSTPROD P, FILIAL F, LANCCONT S
       WHERE P.CDFILIAL   = P_CDFILIAL
         AND F.CDFILIAL   = P.CDFILIAL
         AND S.CDEMPRESA  = F.CDEMPRESA
         AND S.CDCONTCTBL = P.CDCONTCTBL
         AND S.dtlanccont BETWEEN P_DATACUSTO AND LAST_DAY(P_DATACUSTO);
   EXCEPTION
      WHEN NO_DATA_FOUND THEN
         V_VRCUSTOCONT := 0;
   END;

   /* Verifica se foi realizado o calculo do custo de absorcao */
   BEGIN
      SELECT COUNT(*)
        INTO V_COUNT
        FROM CUSTOABSORCAOPR
       WHERE CDFILIAL = P_CDFILIAL
         AND DTCUSTOABSORCAO = LAST_DAY(P_DATACUSTO);
   EXCEPTION
      WHEN NO_DATA_FOUND THEN
         V_COUNT := 0;
   END;

   IF (V_VRCUSTOCONT > 0) AND (V_COUNT = 0) THEN

      /* Verifica se o periodo contabil esta aberto */
      BEGIN
         SELECT C.DTINICCONT, C.DTFINACONT
           INTO V_DTINICCONT, V_DTFINACONT
           FROM FILIAL F, EMPRESA E, CONTOPECTBL C
          WHERE F.CDFILIAL = P_CDFILIAL
            AND E.CDEMPRESA = F.CDEMPRESA
            AND C.CDEMPRESA = E.CDEMPRESA;
      EXCEPTION
         WHEN NO_DATA_FOUND THEN
            V_DTINICCONT := SYSDATE; V_DTFINACONT := SYSDATE;
      END;

      IF (P_DATACUSTO >= V_DTINICCONT) AND (P_DATACUSTO <= V_DTFINACONT) THEN
         /* Tempo apontado referente as tarefas por habilidade (homem/hora) por produto em todas as
            ordens de producao (OP) conforme mes informado (tempo de producao) */
         FOR C_PROD IN (SELECT P.CDSUBPRODETA AS CDPRODUTO, SUM(I.QTTOTLANCTO) AS QTPRODUZIDA, NVL(SUM(QTHSPRODUZIDOPR),0) AS QTHSPRODUZIDOPR
                          FROM ORDPRODUCAO O, PRODACABADO P, ITLANCTOEST I, PRODUTO A,
                               (SELECT O.CDFILIAL, O.NRORDPROD, O.NRSUBORDPROD, (R.DTFINUTRECOP - R.DTINIUTRECOP) * 24 AS QTHSPRODUZIDOPR
                                  FROM ORDPRODUCAO O, AUDITORIA A, RECURETAPAOP R, PRODUTO P
                                 WHERE P.CDARVPROD BETWEEN P_CDPRODINI AND P_CDPRODFIN
                                   AND O.CDPRODUTO = P.CDPRODUTO
                                   AND O.CDFILIAL = P_CDFILIAL
                                   AND A.CDFILIAL = O.CDFILIAL
                                   AND A.NRORDPROD = O.NRORDPROD
                                   AND A.NRSUBORDPROD = O.NRSUBORDPROD
                                   AND A.IDORIGAUDIT = 'TAR'
                                   AND R.CDFILIAL = A.CDFILIAL
                                   AND R.NRAUDITORIA = A.NRAUDITORIA
                                   AND R.IDRECURETAOP = 'H'
                                   AND TO_CHAR(P_DATACUSTO, 'MM/YYYY') = TO_CHAR(R.DTINIUTRECOP, 'MM/YYYY')
                                   AND NOT R.DTFINUTRECOP IS NULL) C
                         WHERE A.CDARVPROD BETWEEN P_CDPRODINI AND P_CDPRODFIN
                           AND O.CDPRODUTO = A.CDPRODUTO
                           AND O.CDFILIAL = P_CDFILIAL
                           AND O.IDSITORDPROD = '3'
                           AND TRUNC(O.DTHRFIMREAOP) BETWEEN P_DATACUSTO AND LAST_DAY(P_DATACUSTO)
                           AND P.CDFILIAL = O.CDFILIAL
                           AND P.NRORDPROD = O.NRORDPROD
                           AND P.NRSUBORDPROD = O.NRSUBORDPROD
                           AND O.CDFILIAL = C.CDFILIAL (+)
                           AND O.NRORDPROD = C.NRORDPROD (+)
                           AND O.NRSUBORDPROD = C.NRSUBORDPROD (+)
                           AND I.CDFILIAL = P.CDFILIAL
                           AND I.NRLANCESTQ = P.NRLANCESTQ
                           AND I.NRSEQUITEM = P.NRSEQUITEM
                         GROUP BY P.CDSUBPRODETA)
         LOOP
            INSERT INTO CUSTOABSORCAOPR
               (CDFILIAL, DTCUSTOABSORCAO, VRTOTRATEADO, CDPRODUTO, QTPRODUZIDA, QTHSPRODUZIDOPR, VRCUSTOABSORCAO)
            VALUES
               (P_CDFILIAL, LAST_DAY(P_DATACUSTO), V_VRCUSTOCONT, C_PROD.CDPRODUTO, C_PROD.QTPRODUZIDA, C_PROD.QTHSPRODUZIDOPR, 0);
         END LOOP;

         SELECT SUM(QTHSPRODUZIDOPR)
           INTO V_QTHRTOTAL
           FROM CUSTOABSORCAOPR
          WHERE CDFILIAL = P_CDFILIAL
            AND DTCUSTOABSORCAO = LAST_DAY(P_DATACUSTO);

         IF V_QTHRTOTAL > 0 THEN
         /* (Total de horas de producao do produto / total de horas * Valor total contabil) / qtde produzida do produto no periodo */
            UPDATE CUSTOABSORCAOPR
               SET VRCUSTOABSORCAO = ROUND(((QTHSPRODUZIDOPR / V_QTHRTOTAL) * VRTOTRATEADO) / QTPRODUZIDA, 5)
             WHERE CDFILIAL = P_CDFILIAL
               AND DTCUSTOABSORCAO = LAST_DAY(P_DATACUSTO);

            FOR C_CUSTOABSORCAO IN (SELECT CDFILIAL, CDPRODUTO, VRCUSTOABSORCAO
                                      FROM CUSTOABSORCAOPR
                                     WHERE CDFILIAL = P_CDFILIAL
                                       AND DTCUSTOABSORCAO = LAST_DAY(P_DATACUSTO)
                                     ORDER BY CDPRODUTO)
            LOOP
               FOR C_PRODACABADO IN (SELECT P.CDFILIAL, P.NRLANCESTQ, P.NRSEQUITEM, I.CDFILIMOVI, I.DTLANCMOVI
                                       FROM ORDPRODUCAO O, PRODACABADO P, ITLANCTOEST I, PRODUTO A
                                      WHERE A.CDARVPROD BETWEEN P_CDPRODINI AND P_CDPRODFIN
                                        AND O.CDPRODUTO = A.CDPRODUTO
                                        AND O.CDFILIAL = C_CUSTOABSORCAO.CDFILIAL
                                        AND O.IDSITORDPROD = '3'
                                        AND TRUNC(O.DTHRFIMREAOP) BETWEEN P_DATACUSTO AND LAST_DAY(P_DATACUSTO)
                                        AND P.CDFILIAL = O.CDFILIAL
                                        AND P.NRORDPROD = O.NRORDPROD
                                        AND P.NRSUBORDPROD = O.NRSUBORDPROD
                                        AND P.CDSUBPRODETA = C_CUSTOABSORCAO.CDPRODUTO
                                        AND I.CDFILIAL = P.CDFILIAL
                                        AND I.NRLANCESTQ = P.NRLANCESTQ
                                        AND I.NRSEQUITEM = P.NRSEQUITEM
                                      ORDER BY I.DTLANCMOVI)
               LOOP
                  UPDATE ITLANCTOEST
                     SET VRUNILANCTO  = VRUNILANCTO + C_CUSTOABSORCAO.VRCUSTOABSORCAO,
                         VRTOTLANCTO  = VRTOTLANCTO + (QTTOTLANCTO * C_CUSTOABSORCAO.VRCUSTOABSORCAO),
                         VRLANCTOEST  = VRLANCTOEST + C_CUSTOABSORCAO.VRCUSTOABSORCAO,
                         VRLANCTOBRUT = VRLANCTOBRUT + C_CUSTOABSORCAO.VRCUSTOABSORCAO,
                         VRCUSTENTR   = VRCUSTENTR + (QTTOTLANCTO * C_CUSTOABSORCAO.VRCUSTOABSORCAO),
                         VRUNILANCTOANT = VRUNILANCTO
                   WHERE CDFILIAL   = C_PRODACABADO.CDFILIAL
                     AND NRLANCESTQ = C_PRODACABADO.NRLANCESTQ
                     AND NRSEQUITEM = C_PRODACABADO.NRSEQUITEM;

                  ATUALIZA_ESTOQUE(C_PRODACABADO.CDFILIMOVI, C_PRODACABADO.DTLANCMOVI, TRUNC(SYSDATE), C_PRODACABADO.CDFILIAL, C_PRODACABADO.NRLANCESTQ);
               END LOOP;
            END LOOP;
         END IF;
      ELSE
         P_ERRO := 'S';
      END IF;
   ELSE
      P_ERRO := 'S';
   END IF;
END;
/