WITH saldo_conta AS (

    WITH saldo AS (

        SELECT
            mf.data_movimento,
            cf.codigo,
            cf.denominacao,
            (SELECT id_empresa FROM sis_parametro_empresa WHERE id_parametro = 'sistema.id_pessoa_empresa' AND valor_numerico = cf.id_pessoa_conta) AS id_empresa,
            SUM(mf.valor_movimento * (POSITION(CAST('1' AS CHAR) IN CAST(tmf.entrada_saida AS CHAR(1))) * 2 - 1)) AS saldo_disponivel
        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)

        WHERE	mf.data_movimento <= :DataFinal
        AND cf.id_conta_financeira IN (:IdContaFinanceiraPessoa)
        AND cf.id_pessoa_conta IN (SELECT COALESCE(valor_numerico, 0)
                                    FROM sis_parametro_empresa 
                                    WHERE id_parametro = 'sistema.id_pessoa_empresa' 
                                    AND id_empresa IN (:IdEmpresaMultSlc))
        GROUP BY  mf.data_movimento, cf.codigo, cf.denominacao, cf.id_pessoa_conta

    )


    SELECT
        'MES' AS tipo,
        se.nome AS nome_empresa,
        r.id_empresa,
        SUM(r.saldo_disponivel) AS saldo_disponivel
    FROM	saldo AS r
    INNER JOIN sis_empresa AS se ON se.id_empresa = r.id_empresa
    GROUP BY se.nome, r.id_empresa

    UNION ALL

    SELECT
        'MES_ANTERIOR' AS tipo,
        se.nome AS nome_empresa,
        r.id_empresa,
        SUM(r.saldo_disponivel) AS saldo_disponivel
    FROM	saldo AS r
    INNER JOIN sis_empresa AS se ON se.id_empresa = r.id_empresa
    WHERE	r.data_movimento <= date_trunc('month',CAST(:DataFinal AS DATE)) - INTERVAL'1 day'
    GROUP BY se.nome, r.id_empresa

    
    ORDER BY nome_empresa
),

saldo_estoque AS (

    WITH saldo_mes_anterior AS (

        SELECT
            se.nome AS nome_empresa,
            le.id_empresa,
            SUM(rme.valor_entrada - rme.valor_saida) AS saldo_valor
        FROM    resumo_movimento_estoque AS rme
            INNER JOIN local_estoque AS le ON (le.id_local_estoque = rme.id_local_estoque)
            INNER JOIN item AS i ON (i.id_item = rme.id_item)
            INNER JOIN categoria_item AS ci ON (ci.id_categoria_item = i.id_categoria_item)
            INNER JOIN sis_empresa AS se ON se.id_empresa = le.id_empresa
        WHERE   rme.ano_mes <= EXTRACT('YEAR' FROM (DATE_TRUNC('MONTH', :DataFinal::DATE) - INTERVAL '1 DAY')) * 100 + EXTRACT('MONTH' FROM (DATE_TRUNC('MONTH', :DataFinal::DATE) - INTERVAL '1 DAY'))
        AND le.id_empresa IN (:IdEmpresaMultSlc)
        AND i.id_categoria_item IN (:IdCategoriaItemMultSlc)
        GROUP BY le.id_empresa, se.nome

        HAVING SUM(rme.quantidade_entrada - rme.quantidade_saida) != 0 
    ),

    saldo_mes AS (
        
        SELECT 
            nome_empresa,
            id_empresa,
            saldo_valor
        FROM saldo_mes_anterior

        UNION ALL

        SELECT
            se.nome AS nome_empresa,
            me.id_empresa,
            SUM(me.valor * (POSITION(CAST('1' AS CHAR) IN CAST(tme.entrada_saida AS CHAR(1))) * 2 - 1)) AS saldo_valor
        FROM    movimento_estoque AS me
            INNER JOIN item AS i ON (i.id_item = me.id_item)
            INNER JOIN categoria_item AS ci ON (ci.id_categoria_item = i.id_categoria_item)
            INNER JOIN tipo_movimento_estoque AS tme ON (tme.id_tipo_movimento_estoque = me.id_tipo_movimento_estoque)
            INNER JOIN sis_empresa AS se ON se.id_empresa = me.id_empresa
        WHERE   me.id_empresa IN (:IdEmpresaMultSlc)
        AND me.data_movimento BETWEEN DATE_TRUNC('MONTH', :DataFinal::DATE) AND :DataFinal::DATE
        AND i.id_categoria_item IN (:IdCategoriaItemMultSlc)
        GROUP BY me.id_empresa, se.nome
    )

    SELECT 
        'MES_ANTERIOR' AS tipo,
		nome_empresa,
        id_empresa,
        saldo_valor
    FROM saldo_mes_anterior

    UNION ALL

    SELECT
        'MES' AS tipo,
        r.nome_empresa,
        r.id_empresa,
        SUM(r.saldo_valor)  AS saldo_valor

    FROM saldo_mes AS r
    GROUP BY r.id_empresa,r.nome_empresa

),

titulo_financeiro AS (

    WITH titulo_mes AS (

        WITH tmp_titulo_financeiro AS (

            SELECT
                p.codigo AS codigo_credor_devedor,
                p.nome AS credor_devedor,
                tf.data_emissao,
                tf.data_vencimento,
                tf.numero_titulo,
                tf.data_liquidacao,
                tf.valor_titulo AS valor_principal,
                (tf.acrescimo_financeiro + tf.juros_cobranca + tf.multa_cobranca) AS total_acrescimo,
                (tf.desconto_financeiro + tf.desconto_cobranca + tf.retencao_tributaria + tf.valor_taxa_administracao + tf.tarifa_transacao) AS total_desconto,
                se.nome AS nome_empresa, 
                tf.id_titulo_financeiro,
                tf.pagar_receber, -- 1 - Pagar, 2 - Receber
                tf.natureza_titulo as codigo_natureza_titulo,
                tf.tipo_titulo,
                tf.situacao,
                ovl1.titulo AS natureza_titulo,
                CASE WHEN tf.valor_liquidado > 0 THEN tf.valor_liquidado ELSE
                (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)) END AS valor_titulo
            FROM titulo_financeiro AS tf 
            INNER JOIN sis_empresa AS se ON se.id_empresa = tf.id_empresa
            LEFT JOIN pessoa AS p ON (tf.id_credor_devedor = p.id_pessoa)
            LEFT JOIN sis_opcao_lista_valor AS ovl1 ON (ovl1.id = tf.natureza_titulo AND ovl1.id_lista_valor = 'C043EFC0EDD5414995003170978F8878')

            WHERE tf.id_empresa IN (:IdEmpresaMultSlc) 
            AND tf.data_vencimento <= :DataFinal AND	(tf.situacao IN (1, 9) OR tf.data_liquidacao > :DataFinal)
            ORDER BY tf.pagar_receber,  tf.id_titulo_financeiro
        )
        
        SELECT 
            1 AS orderby,
            nome_empresa,
            'Título a Receber' AS natureza,
            SUM(valor_titulo) AS valor_titulo
        FROM tmp_titulo_financeiro WHERE pagar_receber = 2 AND codigo_natureza_titulo NOT IN (206) AND codigo_natureza_titulo IN (:NaturezaTituloReceberMultEscTodos)
        GROUP BY nome_empresa

        UNION ALL
        
        SELECT 
            2 AS orderby,
            nome_empresa,
            'Adiantamento a Fornecedores' AS natureza,
            SUM(valor_titulo) AS valor_titulo
        FROM tmp_titulo_financeiro WHERE pagar_receber = 2 AND codigo_natureza_titulo = 206 AND codigo_natureza_titulo IN (:NaturezaTituloReceberMultEscTodos)
        GROUP BY nome_empresa

        UNION ALL

        SELECT 
            3 AS orderby,
            nome_empresa,
            'Título a Pagar' AS natureza,
            SUM(valor_titulo) * -1 AS valor_titulo
        FROM tmp_titulo_financeiro WHERE pagar_receber = 1 AND codigo_natureza_titulo IN (:NaturezaTituloPagarMultEscTodos)
        GROUP BY nome_empresa

    ),

    titulo_mes_anterior AS (

        WITH tmp_titulo_financeiro AS (

            SELECT
                p.codigo AS codigo_credor_devedor,
                p.nome AS credor_devedor,
                tf.data_emissao,
                tf.data_vencimento,
                tf.numero_titulo,
                tf.data_liquidacao,
                tf.valor_titulo AS valor_principal,
                (tf.acrescimo_financeiro + tf.juros_cobranca + tf.multa_cobranca) AS total_acrescimo,
                (tf.desconto_financeiro + tf.desconto_cobranca + tf.retencao_tributaria + tf.valor_taxa_administracao + tf.tarifa_transacao) AS total_desconto,
                se.nome AS nome_empresa, 
                tf.id_titulo_financeiro,
                tf.pagar_receber, -- 1 - Pagar, 2 - Receber
                tf.natureza_titulo as codigo_natureza_titulo,
                tf.tipo_titulo,
                tf.situacao,
                ovl1.titulo AS natureza_titulo,
                CASE WHEN tf.valor_liquidado > 0 THEN tf.valor_liquidado ELSE
                (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)) END AS valor_titulo
            FROM titulo_financeiro AS tf 
            INNER JOIN sis_empresa AS se ON se.id_empresa = tf.id_empresa
            LEFT JOIN sis_opcao_lista_valor AS ovl1 ON (ovl1.id = tf.natureza_titulo AND ovl1.id_lista_valor = 'C043EFC0EDD5414995003170978F8878')
            LEFT JOIN pessoa AS p ON (tf.id_credor_devedor = p.id_pessoa)
            WHERE tf.id_empresa IN (:IdEmpresaMultSlc) 
            AND tf.data_vencimento <= date_trunc('month',CAST(:DataFinal AS DATE)) - INTERVAL'1 day' AND	(tf.situacao IN (1, 9) OR tf.data_liquidacao > date_trunc('month',CAST(:DataFinal AS DATE)) - INTERVAL'1 day')
            ORDER BY tf.pagar_receber,  tf.id_titulo_financeiro
        )
        
        SELECT 
            1 AS orderby,
            nome_empresa,
            'Título a Receber' AS natureza,
            SUM(valor_titulo) AS valor_titulo
        FROM tmp_titulo_financeiro WHERE pagar_receber = 2 AND codigo_natureza_titulo NOT IN (206) AND codigo_natureza_titulo IN (:NaturezaTituloReceberMultEscTodos)
        GROUP BY nome_empresa

        UNION ALL
        
        SELECT 
            2 AS orderby,
            nome_empresa,
            'Adiantamento a Fornecedores' AS natureza,
            SUM(valor_titulo) AS valor_titulo
        FROM tmp_titulo_financeiro WHERE pagar_receber = 2 AND codigo_natureza_titulo = 206 AND codigo_natureza_titulo IN (:NaturezaTituloReceberMultEscTodos)
        GROUP BY nome_empresa

        UNION ALL

        SELECT 
            3 AS orderby,
            nome_empresa,
            'Título a Pagar' AS natureza,
            SUM(valor_titulo) * -1 AS valor_titulo
        FROM tmp_titulo_financeiro WHERE pagar_receber = 1 AND codigo_natureza_titulo IN (:NaturezaTituloPagarMultEscTodos)
        GROUP BY nome_empresa
        
    )

    SELECT
        orderby,
        'MES' AS tipo,  
        nome_empresa,
        natureza,
        valor_titulo
    FROM titulo_mes

    UNION ALL

    SELECT
        orderby,
        'MES_ANTERIOR' AS tipo,  
        nome_empresa,
        natureza,
        valor_titulo
    FROM titulo_mes_anterior

    ORDER BY nome_empresa, orderby

),

mes AS (
    SELECT :DataFinal::DATE AS data
),

mes_anterior AS (
    SELECT date_trunc('month',CAST(:DataFinal AS DATE)) - INTERVAL'1 day' AS data
),

resultado AS (

    WITH mes AS (

        /*MES*/
        SELECT 
            1 AS ord,
            1 AS orderby,
            mes.data AS cabecalho,
            nome_empresa,
            'Dinheiro em Conta' AS dado,
            saldo_disponivel AS valor
        FROM saldo_conta, mes WHERE tipo = 'MES'

        UNION ALL

        SELECT 
            2 AS ord,
            2 AS orderby,
            mes.data  AS cabecalho,
            nome_empresa,
            'Valores em Estoques' AS dado,
            saldo_valor AS valor
        FROM saldo_estoque, mes WHERE tipo = 'MES'

        UNION ALL

        SELECT 
            3 AS ord,
            orderby,
            mes.data  AS cabecalho,
            nome_empresa,
            natureza AS dado,
            valor_titulo AS valor
        FROM titulo_financeiro, mes WHERE tipo = 'MES'

        ORDER BY ord, orderby
    ),

    mes_anterior AS (

        /*MES ANTERIOR*/
        SELECT 
            10 AS ord,
            10 AS orderby,
            mes_anterior.data AS cabecalho,
            nome_empresa,
            'Dinheiro em Conta' AS dado,
            saldo_disponivel AS valor
        FROM saldo_conta, mes_anterior WHERE tipo = 'MES_ANTERIOR'

        UNION ALL

        SELECT
            20 AS ord, 
            20 AS orderby,
            mes_anterior.data  AS cabecalho,
            nome_empresa,
            'Valores em Estoques' AS dado,
            saldo_valor AS valor
        FROM saldo_estoque, mes_anterior WHERE tipo = 'MES_ANTERIOR'

        UNION ALL

        SELECT 
            30 AS ord,
            orderby,
            mes_anterior.data  AS cabecalho,
            nome_empresa,
            natureza AS dado,
            valor_titulo AS valor
        FROM titulo_financeiro, mes_anterior WHERE tipo = 'MES_ANTERIOR'

        ORDER BY ord, orderby
    ),

    soma AS (

        SELECT 
            4 AS ord,
            4 AS orderby,
            cabecalho,
            nome_empresa,
            'Saldo' AS dado,
            SUM(valor) AS valor
        FROM mes
        GROUP BY cabecalho, nome_empresa

        UNION ALL

        SELECT 
            40 AS ord,
            40 AS orderby,
            cabecalho,
            nome_empresa,
            'Saldo' AS dado,
            SUM(valor) AS valor
        FROM mes_anterior
        GROUP BY cabecalho, nome_empresa

        UNION ALL  

        SELECT 
            500 AS ord,
            500 AS orderby,
            NULL::DATE AS cabecalho,
            nome_empresa,
            'TOTAL' AS dado,
            SUM(valor) AS valor
        FROM mes
        GROUP BY nome_empresa

        UNION ALL

        SELECT 
            500 AS ord,
            500 AS orderby,
            NULL::DATE AS cabecalho,
            nome_empresa,
            'TOTAL' AS dado,
            SUM(valor) * -1 AS valor
        FROM mes_anterior
        GROUP BY nome_empresa
    )

    SELECT 
    *
    FROM mes

    UNION ALL

    SELECT 
    *
    FROM mes_anterior

    UNION ALL

    SELECT 
    *
    FROM soma
 
    ORDER BY ord, orderby

)

SELECT * FROM resultado