WITH niveis AS (
    SELECT * FROM (
        WITH RECURSIVE niveis(id_categoria_item, id_categoria_item_pai) AS (
            SELECT	id_categoria_item,
                id_categoria_item_pai,
                1 AS nivel
            FROM	categoria_item
            WHERE	id_categoria_item IN (:IdCategoriaItemMultSlc)
            UNION ALL
            SELECT	ci.id_categoria_item,
                ci.id_categoria_item_pai,
                nv.nivel +1
            FROM	categoria_item AS ci
                INNER JOIN niveis AS nv ON (nv.id_categoria_item = ci.id_categoria_item_pai)
        )
        SELECT * FROM niveis
    ) AS niveis
),

vendas AS (

    SELECT	
        r.nome_empresa,
        r.categoria_item,
        r.cod_item,
        r.denominacao_item,
        r.data_movimento,
        7 AS dias,
        SUM(r.venda_periodo_qtde) AS venda_periodo_qtde,
        SUM(r.venda_periodo_valor) AS venda_periodo_valor

    FROM	(
        SELECT	
            se.nome AS nome_empresa,
            ci.denominacao AS categoria_item,
            i.codigo AS cod_item,
            i.denominacao AS denominacao_item,
            mvt.data_movimento,
            SUM(ivc.quantidade) AS venda_periodo_qtde,
            SUM(ivc.total_item - (ivc.desconto_rateado + ivc.desconto_ajuste_rateado + ivc.desconto_automatico_rateado + ivc.desconto_fidelidade_rateado)
                + (ivc.acrescimo_rateado + ivc.acrescimo_ajuste_rateado + ivc.acrescimo_automatico_rateado)) AS venda_periodo_valor

        FROM	item_venda_cf AS ivc 
            INNER JOIN venda_cf AS vc ON (vc.id_venda_cf = ivc.id_venda_cf)
            INNER JOIN movimento_venda_terminal AS mvt ON (mvt.id_movimento_venda_terminal = vc.id_movimento_venda_terminal)
            INNER JOIN item AS i ON (ivc.id_item = i.id_item)
            INNER JOIN categoria_item AS ci ON (i.id_categoria_item = ci.id_categoria_item)
            INNER JOIN unidade_medida AS um ON (i.id_unidade_medida = um.id_unidade_medida)
            INNER JOIN sis_empresa AS se ON (se.id_empresa = mvt.id_empresa)
        WHERE	DATE(mvt.data_movimento) BETWEEN date(CURRENT_DATE) - :DiasCalculoMedioVenda AND date(CURRENT_DATE) -1
        AND	DATE(vc.data_cupom) BETWEEN date(CURRENT_DATE) - :DiasCalculoMedioVenda AND date(CURRENT_DATE) -1
        AND	DATE(ivc.data_venda) BETWEEN date(CURRENT_DATE) - :DiasCalculoMedioVenda AND date(CURRENT_DATE) -1
        AND	mvt.id_empresa IN (:IdEmpresaMultSlc)
        AND	(ci.id_categoria_item IN (SELECT id_categoria_item FROM niveis))
        AND	(ivc.cancelado = 'N' AND vc.cancelada = 'N')
        GROUP BY 1,2,3,4,5

        UNION ALL

        SELECT	se.nome AS nome_empresa,
            ci.denominacao AS categoria_item,
            i.codigo AS cod_item,
            i.denominacao AS denominacao_item,
            nfs.emissao AS data_movimento,
            SUM(infs.quantidade) AS venda_periodo_qtde,
            SUM(infs.total_item) AS venda_periodo_valor

        FROM	nota_fiscal_saida AS nfs
            INNER JOIN item_nfs AS infs ON (infs.id_nota_fiscal_saida = nfs.id_nota_fiscal_saida)
            INNER JOIN item AS i ON (i.id_item = infs.id_item)
            INNER JOIN categoria_item AS ci ON (i.id_categoria_item = ci.id_categoria_item)
            INNER JOIN unidade_medida AS um ON (i.id_unidade_medida = um.id_unidade_medida)
            INNER JOIN sis_empresa AS se ON (se.id_empresa = nfs.id_empresa)
        WHERE	DATE(nfs.emissao) BETWEEN date(CURRENT_DATE) - :DiasCalculoMedioVenda AND date(CURRENT_DATE) -1
        AND	nfs.id_empresa IN (:IdEmpresaMultSlc)
        AND	(ci.id_categoria_item IN (SELECT id_categoria_item FROM niveis))
        AND	nfs.situacao = 1 
        AND	EXISTS(SELECT 1 FROM cfop WHERE tipo_movimento_estoque != 4 AND gera_titulo_financeiro = 'S' AND id_tipo_movimento_estoque = 7 AND id_cfop = infs.id_cfop)
        AND	EXISTS(SELECT 1 FROM movimento_estoque AS me1 INNER JOIN sis_referencia_registro AS rr1 ON (me1.id_movimento_estoque = rr1.id_chave_registro_b)
                WHERE rr1.id_chave_registro_a = infs.id_item_nfs AND rr1.tipo_referencia = 'ref_1101_0411_movimento_estoque_nfs')
        GROUP BY 1,2,3,4,5

        UNION ALL

        SELECT	se.nome AS nome_empresa,
            ci.denominacao AS categoria_item,
            i.codigo AS cod_item,
            i.denominacao AS denominacao_item,
            nfe.emissao AS data_movimento,
            (SUM(infe.quantidade) * -1) AS venda_periodo_qtde,
            (SUM(infe.total_produto) * -1) AS venda_periodo_valor
        FROM	nota_fiscal_entrada AS nfe
            INNER JOIN item_nfe AS infe ON (infe.id_nota_fiscal_entrada = nfe.id_nota_fiscal_entrada)
            INNER JOIN item AS i ON (i.id_item = infe.id_item)
            INNER JOIN categoria_item AS ci ON (i.id_categoria_item = ci.id_categoria_item)
            INNER JOIN unidade_medida AS um ON (i.id_unidade_medida = um.id_unidade_medida)
            INNER JOIN sis_empresa AS se ON (se.id_empresa = nfe.id_empresa)
        WHERE	DATE(nfe.emissao) BETWEEN date(CURRENT_DATE) - :DiasCalculoMedioVenda AND date(CURRENT_DATE) -1
        AND	nfe.id_empresa IN (:IdEmpresaMultSlc)
        AND	(ci.id_categoria_item IN (SELECT id_categoria_item FROM niveis))
        AND	nfe.situacao = 1 
        AND	EXISTS(SELECT 1 FROM cfop WHERE tipo_movimento_estoque != 4 AND id_tipo_movimento_estoque = 3 AND id_cfop = infe.id_cfop)
        AND	infe.id_movimento_estoque IS NOT NULL
        GROUP BY 1,2,3,4,5
        ) AS r
    GROUP BY 1,2,3,4,5
    ORDER BY r.nome_empresa, r.data_movimento, r.cod_item
),

titulo_pagar_receber AS (
    -- Títulos a Pagar Liquidados por Vencimento
    SELECT	
        tf.pagar_receber,
        se.nome AS nome_empresa,
        p.codigo,
        p.nome,
        tf.numero_titulo,
        tf.numero_parcela,
        tf.data_emissao,
        tf.data_vencimento,
        tf.data_liquidacao,
        tf.valor_titulo,
        tf.valor_liquidado,
        (tf.valor_titulo
        - (tf.desconto_financeiro + tf.desconto_cobranca + tf.retencao_tributaria + tf.valor_taxa_administracao + tf.tarifa_transacao)
        + (tf.acrescimo_financeiro + tf.juros_cobranca + tf.multa_cobranca)) AS valor_pagar_receber,
        (CASE WHEN tdr.denominacao is not null THEN tdr.denominacao
                ELSE (select array_to_string(array(
                select 	tdr2.denominacao 
                        from despesa_receita AS dr2 
                        LEFT OUTER JOIN tipo_despesa_receita AS tdr2 ON tdr2.id_tipo_despesa_receita = dr2.id_tipo_despesa_receita
                        where dr2.id_empresa = tf.id_empresa and  tf.id_credor_devedor = dr2.id_pessoa 
                        and dr2.data_despesa_receita = tf.data_emissao and tf.numero_titulo = dr2.numero_documento
                        group by tdr2.denominacao 
                        ),',' ))
        END) AS denominacao,
        tf.observacao,
        tf.situacao,
        uap.nome AS usuario_aprovador,
        cf.denominacao AS denominacao_conta_financeira,
        cf.codigo AS codigo_conta
    FROM	titulo_financeiro AS tf
        INNER JOIN pessoa AS p ON (p.id_pessoa = tf.id_credor_devedor)
        LEFT OUTER JOIN parcela_despesa_receita AS pdr ON (pdr.id_titulo_financeiro = tf.id_titulo_financeiro)
        LEFT OUTER JOIN despesa_receita AS dr ON (dr.id_despesa_receita = pdr.id_despesa_receita)
        LEFT OUTER JOIN sis_usuario AS uap ON (uap.id_usuario = dr.id_usuario_aprovador)
        LEFT OUTER JOIN tipo_despesa_receita AS tdr ON (tdr.id_tipo_despesa_receita = dr.id_tipo_despesa_receita)
        INNER JOIN sis_empresa AS se ON (se.id_empresa = tf.id_empresa)
        LEFT JOIN conta_financeira AS cf ON (cf.id_conta_financeira = tf.id_conta_liquidacao)
    WHERE	tf.id_empresa IN (:IdEmpresaMultSlc)
    AND (CASE WHEN tf.pagar_receber = 1 THEN tf.data_vencimento <=  date(CURRENT_DATE) + :DiasContasVencer ELSE tf.data_vencimento <=  date(CURRENT_DATE) END)
    -- AND	tf.pagar_receber = 1 --Pagar
    AND	tf.situacao IN (1, 9) 
    AND	tf.natureza_titulo IN (101, 106, 116, 109, 114, 222, 201, 202, 203, 204, 205, 209, 220, 221) -- 206 = adiantamennto a fornecedores
    ORDER BY se.nome, tf.data_vencimento,  p.nome

),

saldo_conta AS (


    SELECT	r.codigo,
        r.denominacao,
        r.usuario_responsavel,
        SUM(r.saldo_disponivel) AS saldo_disponivel,
        SUM(r.saldo_conciliado) AS saldo_conciliado
    FROM	(
        SELECT cf.codigo,
            cf.denominacao,
            su.nome AS usuario_responsavel,
            SUM(mf.valor_movimento * (POSITION(CAST('1' AS CHAR) IN CAST(tmf.entrada_saida AS CHAR(1))) * 2 - 1)) AS saldo_disponivel,
            CAST(0 AS DECIMAL(12,2)) AS saldo_conciliado
        FROM	movimento_financeiro AS mf
            INNER JOIN tipo_movimento_financeiro AS tmf ON (tmf.id_tipo_movimento_financeiro = mf.id_tipo_movimento_financeiro)
            INNER JOIN conta_financeira AS cf ON (cf.id_conta_financeira = mf.id_conta_financeira)
            INNER JOIN sis_usuario AS su ON (su.id_usuario = cf.id_usuario_responsavel)
        WHERE	mf.data_movimento <= CURRENT_DATE
        AND cf.id_conta_financeira IN (:IdContaFinanceiraAtivaFluxo)

        GROUP BY 1,2,3

        UNION ALL

        SELECT	cf.codigo,
            cf.denominacao,
            su.nome AS usuario_responsavel,
            CAST(0 AS DECIMAL(12,2)) AS saldo_disponivel,
            SUM(mf.valor_movimento * (POSITION(CAST('1' AS CHAR) IN CAST(tmf.entrada_saida AS CHAR(1))) * 2 - 1)) AS saldo_conciliado
        FROM	movimento_financeiro AS mf
            INNER JOIN tipo_movimento_financeiro AS tmf ON (tmf.id_tipo_movimento_financeiro = mf.id_tipo_movimento_financeiro)
            INNER JOIN conta_financeira AS cf ON (cf.id_conta_financeira = mf.id_conta_financeira)
            INNER JOIN sis_usuario AS su ON (su.id_usuario = cf.id_usuario_responsavel)
        WHERE	mf.data_conciliacao <= CURRENT_DATE
        AND cf.id_conta_financeira IN (:IdContaFinanceiraAtivaFluxo)

        GROUP BY 1,2,3 ) AS r
    GROUP BY r.codigo,
        r.denominacao,
        r.usuario_responsavel
    ORDER BY r.codigo,
        r.denominacao
),

titulo_pagar_receber_periodo AS (

    SELECT 

        (CASE WHEN p.sequencia = 0 THEN 'Vencidos Até Hoje' ELSE 
            CASE EXTRACT( DOW FROM p.data)
                WHEN 0 THEN 'Domingo'
                WHEN 1 THEN 'Segunda'
                WHEN 2 THEN 'Terça'
                WHEN 3 THEN 'Quarta'
                WHEN 4 THEN 'Quinta'
                WHEN 5 THEN 'Sexta'
                WHEN 6 THEN 'Sábado'
            END || ', ' ||
            to_char(p.data, 'DD')  || ' ' ||
            
            (ARRAY[
            'Janeiro',
            'Fevereiro',
            'Março',
            'Abril',
            'Maio',
            'Junho',
            'Julho',
            'Agosto',
            'Setembro',
            'Outubro',
            'Novembro',
            'Dezembro'])[ EXTRACT(MONTH FROM p.data) ] || ' ' ||
            to_char(p.data, 'YYYY') 

        END)  AS data_texto,

        s.saldo_disponivel,
        v.media_recebido_dia,
        v.venda_periodo_valor,
        v.dias,
	 	(CASE WHEN p.sequencia = 0 THEN CURRENT_DATE - 1 ELSE p.data END) AS  data_movimento,
        (
            SELECT 
                SUM(valor_pagar_receber) 
            FROM titulo_pagar_receber 
            WHERE (CASE WHEN p.sequencia = 0 THEN data_vencimento <= CURRENT_DATE ELSE data_vencimento = p.data END)
            AND pagar_receber = 1 
            
        ) AS titulo_pagar_receber,
        (
            SELECT 
               (CASE WHEN p.sequencia = 0 THEN SUM(valor_pagar_receber) ELSE v.media_recebido_dia END)
            FROM titulo_pagar_receber 
            WHERE(CASE WHEN p.sequencia = 0 THEN data_vencimento <= CURRENT_DATE ELSE data_vencimento = p.data END)
            AND pagar_receber = 2 

        ) AS titulo_receber,

        (

            s.saldo_disponivel
            + SUM(v.media_recebido_dia * p.sequencia) 
            - (
                SELECT SUM(valor_pagar_receber * (CASE WHEN pagar_receber = 1 THEN 1 ELSE -1 END)) 
                FROM titulo_pagar_receber WHERE data_vencimento <= p.data
            )
        ) AS saldo_calculado,
		p.sequencia + 1 AS sequencia 
		
    FROM  (
        SELECT
           SUM(saldo_disponivel) AS saldo_disponivel,
           SUM(saldo_conciliado) AS saldo_conciliado 
        FROM saldo_conta

    ) AS s, 
	(	
		SELECT
		generate_series(0, 7) AS sequencia,
		generate_series(CURRENT_DATE, CURRENT_DATE + 7, interval  '1 day') as data

	) AS p, 
    (
        SELECT
            dias,
            SUM(v.venda_periodo_valor) AS venda_periodo_valor,
            ROUND(SUM(v.venda_periodo_valor)/v.dias, 2) AS media_recebido_dia
        FROM vendas AS v
        GROUP BY v.dias
    ) AS v
    
    GROUP BY data, s.saldo_disponivel, v.media_recebido_dia, v.venda_periodo_valor, v.dias, p.sequencia
	ORDER BY p.sequencia
),

resultado AS (
    

    SELECT 
        'CONTAS VENCIDAS / A PAGAR' AS cabecalho,
        d.data_texto,
        d.venda_periodo_valor,
        d.saldo_disponivel,
        d.dias,
        d.media_recebido_dia,
        d.data_movimento,
        d.sequencia,
        SUM(d.titulo_pagar_receber) AS valor

    FROM titulo_pagar_receber_periodo AS d
    GROUP BY 1,2,3,4,5,6,7,8

    UNION ALL

        SELECT 
        'CONTAS VENCIDAS / A PAGAR' AS cabecalho,
        'TOTAL' AS data_texto,
        d.venda_periodo_valor,
        d.saldo_disponivel,
        d.dias,
        d.media_recebido_dia,
        NULL::DATE AS data_movimento,
        0 AS sequencia,
        SUM(d.titulo_pagar_receber) AS valor

    FROM titulo_pagar_receber_periodo AS d
    GROUP BY 1,2,3,4,5,6,7,8

    UNION ALL

    SELECT 
        'CONTAS VENCIDAS / A RECEBER' AS cabecalho,
        d.data_texto,
        d.venda_periodo_valor,
        d.saldo_disponivel,
        d.dias,
        d.media_recebido_dia,
        d.data_movimento,
        d.sequencia,
        SUM(d.titulo_receber) AS valor

    FROM titulo_pagar_receber_periodo AS d
    GROUP BY 1,2,3,4,5,6,7,8

    UNION ALL

    SELECT 
        'CONTAS VENCIDAS / A RECEBER' AS cabecalho,
        'TOTAL' AS data_texto,
        d.venda_periodo_valor,
        d.saldo_disponivel,
        d.dias,
        d.media_recebido_dia,
        NULL::DATE AS data_movimento,
        0 AS sequencia,
        SUM(d.titulo_receber) AS valor

    FROM titulo_pagar_receber_periodo AS d
    GROUP BY 1,2,3,4,5,6,7,8
        
    UNION ALL

    SELECT 
        'SALDO DO DIA' AS cabecalho,
        d.data_texto,
        d.venda_periodo_valor,
        d.saldo_disponivel,
        d.dias,
        d.media_recebido_dia,
        d.data_movimento,
        d.sequencia,
        SUM(d.saldo_calculado) AS valor
    FROM titulo_pagar_receber_periodo AS d
    GROUP BY 1,2,3,4,5,6,7,8

        UNION ALL

    SELECT 
        'SALDO DO DIA' AS cabecalho,
        'TOTAL' AS data_texto,
        0 AS venda_periodo_valor,
        0 AS saldo_disponivel,
        0 AS dias,
        0 AS media_recebido_dia,
        NULL::DATE AS data_movimento,
        0 AS sequencia,
        SUM(t.titulo_receber - t.titulo_pagar_receber + s.saldo_calculado) AS valor
    FROM 
    (
        SELECT 
            SUM(titulo_receber) AS titulo_receber,
            SUM(titulo_pagar_receber) AS titulo_pagar_receber
        FROM titulo_pagar_receber_periodo 
    ) AS t,
    (
        SELECT 
            SUM(saldo_calculado) AS saldo_calculado
        FROM titulo_pagar_receber_periodo WHERE sequencia = 8
    ) AS s 

	ORDER BY data_movimento
)
SELECT * FROM resultado