CREATE OR REPLACE PROCEDURE FCT_GERAR_ITENS_TRAB_FATURA (
    P_NRSEQCONTRATO IN FCT_CONTRATO.NRSEQCONTRATO%TYPE,
    P_NRORG         IN NUMBER
)
AS
    V_DTFINCOMPET        DATE;
    V_DTINICOMPET        DATE;
    V_NRDIAINI           INTEGER;
    V_NRDIAFIN           INTEGER;
    V_DTFINCOMPET_ATUAL  DATE;
    V_DTINICOMPET_ATUAL  DATE;
    V_DTVENCIMENTO       DATE;
    V_NRDIASVENCIMENTO   INTEGER;
    V_QTDIASFATUVENC     INTEGER;
    V_DTLIMITEAPU        DATE;
    V_CONT_PARCELAS      INTEGER;
    V_DTINIPARCELA       DATE;
    V_VRPARCELA          FLOAT;

    V_NRTRABITFATURACONT NOVOCODIGO.NRSEQUENCIAL%TYPE;
BEGIN

    DELETE FROM FCT_TRAB_ITFATURACONT
     WHERE NRSEQCONTRATO = P_NRSEQCONTRATO
       AND NRORG         = P_NRORG;

    SELECT NVL(DTINIVIGENCONT, DTINICIOCONTRATO) AS DTINI,
           NVL(DTFINVIGENCONT, DTFIMCONTRATO) AS DTFIN
      INTO V_DTINICOMPET,
           V_DTFINCOMPET
      FROM FCT_CONTRATO
     WHERE NRSEQCONTRATO = P_NRSEQCONTRATO
       AND NRORG         = P_NRORG;

    FOR C_PARCELAS IN (
        SELECT NRDIACOMPETINI,
               NRDIACOMPETFIN,
               IDMESCOMPETINI,
               IDMESCOMPETFIN,
               QTDIASAPURACAO,
               IDTPCALCVENC,
               NRDIACALCVENC,
               IDMESCALCVENC,
               QTDIASFATUVENC
          FROM FCT_PARAMFATCON
         WHERE NRSEQCONTRATO = P_NRSEQCONTRATO
           AND NRORG         = P_NRORG
    ) LOOP

        FOR C_ITENS IN (
            SELECT ITEM.NRITEMOCONTRATO,
                   ITEM.CDPRODUTO,
                   ITEM.CDSERVORCA,
                   ITEM.VRUNITITEMCONT,
                   ITEM.QTITEMCONTRATO,
                   ITEM.VRTOTITEMCONT,
                   NVL(PFATIT.IDTPFATURA, CAPAPFAT.IDTPFATURA) AS IDTPFATURA,
                   NVL(PFATIT.QTPARCELASFATU, CAPAPFAT.QTPARCELASFATU) AS QTPARCELASFATU,
                   NVL(CONT.DTINIVIGENCONT, CONT.DTINICIOCONTRATO) AS DTINICIOCONTRATO,
                   NVL(CONT.DTFINVIGENCONT, CONT.DTFIMCONTRATO) AS DTFIMCONTRATO,
                   NVL(PFATIT.NRGRUPOFATURA, CAPAPFAT.NRGRUPOFATURA) AS NRGRUPOFATURA,
                   NVL(PFATIT.CDPRODFATURA, NVL(CAPAPFAT.CDPRODFATURA, DECODE(GRUPO.IDPRODUTOFATURA, 'UNICO', GRUPO.CDPRODUTOVENDA, SERV.CDPRODFATSERV))) AS CDPRODFATURA,
                   NVL(PFATIT.CDFILIALFATURA, NVL(CAPAPFAT.CDFILIALFATURA, NVL(CONT.CDFILIALFATURA, CONT.CDFILIALORCA))) AS CDFILIALFATURA,
                   NVL(PFATIT.NRPARCFATURA, NVL(CAPAPFAT.NRPARCFATURA, CONT.NRPARCNEGOCIO)) AS NRPARCFATURA
              FROM FCT_ITEMCONTRATO ITEM
             INNER JOIN FCT_CONTRATO CONT
                ON ITEM.NRSEQCONTRATO = CONT.NRSEQCONTRATO
               AND ITEM.NRORG         = CONT.NRORG
              LEFT JOIN FCT_CAPAPARAMFATCON CAPAPFAT
                ON CONT.NRSEQCONTRATO = CAPAPFAT.NRSEQCONTRATO
               AND CONT.NRORG         = CAPAPFAT.NRORG
              LEFT JOIN FCT_PARAMFATITCON PFATIT
                ON ITEM.NRSEQCONTRATO   = PFATIT.NRSEQCONTRATO
               AND ITEM.NRITEMOCONTRATO = PFATIT.NRITEMOCONTRATO
               AND ITEM.NRORG           = PFATIT.NRORG
              LEFT JOIN FCT_GRUPOFATURA GRUPO
                ON NVL(PFATIT.NRGRUPOFATURA, CAPAPFAT.NRGRUPOFATURA) = GRUPO.NRGRUPOFATURA
               AND ITEM.NRORG                                        = GRUPO.NRORG
              LEFT JOIN FCT_SERVICOORCA SERV
                ON ITEM.CDSERVORCA = SERV.CDSERVORCA
               AND ITEM.NRORG      = SERV.NRORG
             WHERE ITEM.NRSEQCONTRATO = P_NRSEQCONTRATO
               AND ITEM.NRORG         = P_NRORG
        ) LOOP

            /*
            IDTPFATURA
            A = Periodico (valor de parcela fixo)
            X = Periodico (Valor Apurado por Medicao)
            P = Parcelamento (Quantidade de Parcelas)
            */
            IF (C_ITENS.IDTPFATURA <> 'P') THEN

                FOR C_DATA IN (
                    SELECT DISTINCT
                        TRUNC(DTMES) AS DTINICIAL,
                        TRUNC(LAST_DAY(DTMES)) AS DTFINAL
                    FROM DATA
                    WHERE DTDATA BETWEEN V_DTINICOMPET AND V_DTFINCOMPET
                    ORDER BY DTINICIAL
                ) LOOP

                    V_NRDIAINI := C_PARCELAS.NRDIACOMPETINI;
                    IF (V_NRDIAINI > EXTRACT(DAY FROM LAST_DAY(C_DATA.DTINICIAL))) THEN
                        V_NRDIAINI := EXTRACT(DAY FROM LAST_DAY(C_DATA.DTINICIAL));
                    END IF;

                    V_NRDIAFIN := C_PARCELAS.NRDIACOMPETFIN;
                    IF (V_NRDIAFIN > EXTRACT(DAY FROM LAST_DAY(C_DATA.DTFINAL))) THEN
                        V_NRDIAFIN := EXTRACT(DAY FROM LAST_DAY(C_DATA.DTFINAL));
                    END IF;

                    --CALCULAR DATA INICIAL DA COMPETENCIA
                    --1 = mes anterior
                    IF (C_PARCELAS.IDMESCOMPETINI = '1') THEN

                        V_DTINICOMPET_ATUAL := LPAD(V_NRDIAINI, 2, '0') || '/' || TO_CHAR(ADD_MONTHS(C_DATA.DTINICIAL, -1), 'MM/YYYY');

                    --2 = mes atual
                    ELSIF (C_PARCELAS.IDMESCOMPETINI = '2') THEN
                        V_DTINICOMPET_ATUAL := LPAD(V_NRDIAINI, 2, '0') || '/' || TO_CHAR(C_DATA.DTINICIAL, 'MM/YYYY');

                    --3 = proximo mes
                    ELSE
                        V_DTINICOMPET_ATUAL := LPAD(V_NRDIAINI, 2, '0') || '/' || TO_CHAR(ADD_MONTHS(C_DATA.DTINICIAL, 1), 'MM/YYYY');
                    END IF;

                    --CALCULAR DATA FINAL DA COMPETENCIA
                    --1 = mes anterior
                    IF (C_PARCELAS.IDMESCOMPETFIN = '1') THEN
                        V_DTFINCOMPET_ATUAL := LPAD(V_NRDIAFIN, 2, '0') || '/' || TO_CHAR(ADD_MONTHS(C_DATA.DTFINAL, -1), 'MM/YYYY');

                    --2 = mes atual
                    ELSIF (C_PARCELAS.IDMESCOMPETFIN = '2') THEN
                        V_DTFINCOMPET_ATUAL := LPAD(V_NRDIAFIN, 2, '0') || '/' || TO_CHAR(C_DATA.DTFINAL, 'MM/YYYY');

                    --3 = proximo mes
                    ELSE
                        V_DTFINCOMPET_ATUAL := LPAD(V_NRDIAFIN, 2, '0') || '/' || TO_CHAR(ADD_MONTHS(C_DATA.DTFINAL, 1), 'MM/YYYY');
                    END IF;

                    --CALCULO DATA DE VENCIMENTO
                    V_DTVENCIMENTO     := NULL;
                    V_NRDIASVENCIMENTO := NULL;
                    V_QTDIASFATUVENC   := NULL;

                    V_DTLIMITEAPU := V_DTFINCOMPET_ATUAL + C_PARCELAS.QTDIASAPURACAO;

                    --1 - Dia fixo para a data de vencimento
                    IF (C_PARCELAS.IDTPCALCVENC = '1') THEN

                        --1 = mes anterior
                        IF (C_PARCELAS.IDMESCALCVENC = '1') THEN
                            V_DTVENCIMENTO := LPAD(C_PARCELAS.NRDIACALCVENC, 2, '0') || '/' || TO_CHAR(ADD_MONTHS(C_DATA.DTINICIAL, -1), 'MM/YYYY');

                        --2 = mes atual
                        ELSIF (C_PARCELAS.IDMESCALCVENC = '2') THEN
                            V_DTVENCIMENTO := LPAD(C_PARCELAS.NRDIACALCVENC, 2, '0') || '/' || TO_CHAR(C_DATA.DTINICIAL, 'MM/YYYY');

                        --3 = proximo mes
                        ELSE
                            V_DTVENCIMENTO := LPAD(C_PARCELAS.NRDIACALCVENC, 2, '0') || '/' || TO_CHAR(ADD_MONTHS(C_DATA.DTINICIAL, 1), 'MM/YYYY');
                        END IF;

                    --2 = Quantidade de dias após a data de emissão
                    ELSE
                        V_NRDIASVENCIMENTO := C_PARCELAS.NRDIACALCVENC;
                        V_QTDIASFATUVENC := C_PARCELAS.QTDIASFATUVENC;
                    END IF;

                    NOVO_CODIGO_SC('FCT_TRAB_ITFATURACONT', V_NRTRABITFATURACONT, 1, P_NRORG);

                    INSERT INTO FCT_TRAB_ITFATURACONT (
                        NRTRABITFATURACONT,
                        NRSEQCONTRATO,
                        NRITEMOCONTRATO,
                        IDTPFATURA,
                        DTINICOMPET,
                        DTFINCOMPET,
                        VRVENCIMENTO,
                        DTLIMITEAPU,
                        DTVENCIMENTO,
                        NRDIASVENCIMENTO,
                        QTDIASFATUVENC,
                        NRGRUPOFATURA,
                        CDPRODFATURA,
                        CDFILIALFATURA,
                        NRPARCFATURA,
                        CDSERVORCA,
                        NRORG
                    )
                    VALUES (
                        V_NRTRABITFATURACONT,
                        P_NRSEQCONTRATO,
                        C_ITENS.NRITEMOCONTRATO,
                        C_ITENS.IDTPFATURA,
                        V_DTINICOMPET_ATUAL,
                        V_DTFINCOMPET_ATUAL,
                        C_ITENS.VRTOTITEMCONT,
                        V_DTLIMITEAPU,
                        V_DTVENCIMENTO,
                        V_NRDIASVENCIMENTO,
                        V_QTDIASFATUVENC,
                        C_ITENS.NRGRUPOFATURA,
                        C_ITENS.CDPRODFATURA,
                        C_ITENS.CDFILIALFATURA,
                        C_ITENS.NRPARCFATURA,
                        C_ITENS.CDSERVORCA,
                        P_NRORG
                    );

                END LOOP; --C_DATA

            ELSE --IDTPFATURA = P

                V_CONT_PARCELAS := 1;
                V_DTINIPARCELA := V_DTINICOMPET;
                V_VRPARCELA := TRUNC(C_ITENS.VRTOTITEMCONT / C_ITENS.QTPARCELASFATU, 2);

                WHILE (V_CONT_PARCELAS <= C_ITENS.QTPARCELASFATU) LOOP

                    --Verifica se eh a ultima parcela, para setar seu valor com o valor restante do total item.
                    IF (V_CONT_PARCELAS = C_ITENS.QTPARCELASFATU) THEN

                        IF ((V_VRPARCELA * V_CONT_PARCELAS) < C_ITENS.VRTOTITEMCONT) THEN
                            V_VRPARCELA := C_ITENS.VRTOTITEMCONT - (V_VRPARCELA * (V_CONT_PARCELAS - 1));
                        END IF;

                    END IF;

                    V_NRDIAINI := C_PARCELAS.NRDIACOMPETINI;
                    IF (V_NRDIAINI > EXTRACT(DAY FROM LAST_DAY(V_DTINIPARCELA))) THEN
                        V_NRDIAINI := EXTRACT(DAY FROM LAST_DAY(V_DTINIPARCELA));
                    END IF;

                    V_NRDIAFIN := C_PARCELAS.NRDIACOMPETFIN;
                    IF (V_NRDIAFIN > EXTRACT(DAY FROM LAST_DAY(V_DTINIPARCELA))) THEN
                        V_NRDIAFIN := EXTRACT(DAY FROM LAST_DAY(V_DTINIPARCELA));
                    END IF;

                    --CALCULAR DATA INICIAL DA COMPETENCIA
                    --1 = mes anterior
                    IF (C_PARCELAS.IDMESCOMPETINI = '1') THEN
                        V_DTINICOMPET_ATUAL := LPAD(V_NRDIAINI, 2, '0') || '/' || TO_CHAR(ADD_MONTHS(V_DTINIPARCELA, -1), 'MM/YYYY');

                    --2 = mes atual
                    ELSIF (C_PARCELAS.IDMESCOMPETINI = '2') THEN
                        V_DTINICOMPET_ATUAL := LPAD(V_NRDIAINI, 2, '0') || '/' || TO_CHAR(V_DTINIPARCELA, 'MM/YYYY');

                    --3 = proximo mes
                    ELSE
                        V_DTINICOMPET_ATUAL := LPAD(V_NRDIAINI, 2, '0') || '/' || TO_CHAR(ADD_MONTHS(V_DTINIPARCELA, 1), 'MM/YYYY');
                    END IF;

                    --CALCULAR DATA FINAL DA COMPETENCIA
                    --1 = mes anterior
                    IF (C_PARCELAS.IDMESCOMPETFIN = '1') THEN
                        V_DTFINCOMPET_ATUAL := LPAD(V_NRDIAFIN, 2, '0') || '/' || TO_CHAR(ADD_MONTHS(V_DTINIPARCELA, -1), 'MM/YYYY');

                    --2 = mes atual
                    ELSIF (C_PARCELAS.IDMESCOMPETFIN = '2') THEN
                        V_DTFINCOMPET_ATUAL := LPAD(V_NRDIAFIN, 2, '0') || '/' || TO_CHAR(V_DTINIPARCELA, 'MM/YYYY');

                    --3 = proximo mes
                    ELSE
                        V_DTFINCOMPET_ATUAL := LPAD(V_NRDIAFIN, 2, '0') || '/' || TO_CHAR(ADD_MONTHS(V_DTINIPARCELA, 1), 'MM/YYYY');
                    END IF;

                    --CALCULO DATA DE VENCIMENTO
                    V_DTVENCIMENTO     := NULL;
                    V_NRDIASVENCIMENTO := NULL;
                    V_QTDIASFATUVENC   := NULL;

                    V_DTLIMITEAPU := V_DTFINCOMPET_ATUAL + C_PARCELAS.QTDIASAPURACAO;

                    --1 - Dia fixo para a data de vencimento
                    IF (C_PARCELAS.IDTPCALCVENC = '1') THEN

                        --1 = mes anterior
                        IF (C_PARCELAS.IDMESCALCVENC = '1') THEN
                            V_DTVENCIMENTO := LPAD(C_PARCELAS.NRDIACALCVENC, 2, '0') || '/' || TO_CHAR(ADD_MONTHS(V_DTINIPARCELA, -1), 'MM/YYYY');

                        --2 = mes atual
                        ELSIF (C_PARCELAS.IDMESCALCVENC = '2') THEN
                            V_DTVENCIMENTO := LPAD(C_PARCELAS.NRDIACALCVENC, 2, '0') || '/' || TO_CHAR(V_DTINIPARCELA, 'MM/YYYY');

                        --3 = proximo mes
                        ELSE
                            V_DTVENCIMENTO := LPAD(C_PARCELAS.NRDIACALCVENC, 2, '0') || '/' || TO_CHAR(ADD_MONTHS(V_DTINIPARCELA, 1), 'MM/YYYY');
                        END IF;

                    --2 = Quantidade de dias após a data de emissão
                    ELSE
                        V_NRDIASVENCIMENTO := C_PARCELAS.NRDIACALCVENC;
                        V_QTDIASFATUVENC := C_PARCELAS.QTDIASFATUVENC;
                    END IF;

                    NOVO_CODIGO_SC('FCT_TRAB_ITFATURACONT', V_NRTRABITFATURACONT, 1, P_NRORG);

                    INSERT INTO FCT_TRAB_ITFATURACONT (
                        NRTRABITFATURACONT,
                        NRSEQCONTRATO,
                        NRITEMOCONTRATO,
                        IDTPFATURA,
                        DTINICOMPET,
                        DTFINCOMPET,
                        VRVENCIMENTO,
                        DTLIMITEAPU,
                        DTVENCIMENTO,
                        NRDIASVENCIMENTO,
                        QTDIASFATUVENC,
                        NRGRUPOFATURA,
                        CDPRODFATURA,
                        CDFILIALFATURA,
                        NRPARCFATURA,
                        NRORG
                    )
                    VALUES (
                        V_NRTRABITFATURACONT,
                        P_NRSEQCONTRATO,
                        C_ITENS.NRITEMOCONTRATO,
                        C_ITENS.IDTPFATURA,
                        V_DTINICOMPET_ATUAL,
                        V_DTFINCOMPET_ATUAL,
                        V_VRPARCELA,
                        V_DTLIMITEAPU,
                        V_DTVENCIMENTO,
                        V_NRDIASVENCIMENTO,
                        V_QTDIASFATUVENC,
                        C_ITENS.NRGRUPOFATURA,
                        C_ITENS.CDPRODFATURA,
                        C_ITENS.CDFILIALFATURA,
                        C_ITENS.NRPARCFATURA,
                        P_NRORG
                    );

                    V_CONT_PARCELAS := V_CONT_PARCELAS + 1;
                    V_DTINIPARCELA := ADD_MONTHS(V_DTINIPARCELA, 1);

                END LOOP;

            END IF;

        END LOOP; --C_ITENS

    END LOOP; --C_PARCELAS

END;