ajustado filtros na dashboard e movimentos
This commit is contained in:
parent
180d756195
commit
12dcc8506f
|
|
@ -157,87 +157,225 @@ async function buscarCardsMovimentos(idUsuario, dataInicio, dataFim) {
|
|||
const [rows] = await pool.query(
|
||||
`
|
||||
SELECT
|
||||
COALESCE(SUM(CASE
|
||||
WHEN cp.movimento IN ('Entrada', 'Estorno') THEN cp.valor
|
||||
ELSE 0
|
||||
END), 0) AS entradas,
|
||||
COALESCE(SUM(
|
||||
CASE
|
||||
/* Entradas e estornos normais */
|
||||
WHEN cp.movimento IN ('Entrada', 'Estorno')
|
||||
AND banco_origem.idusuarios = ?
|
||||
THEN cp.valor
|
||||
|
||||
COALESCE(SUM(CASE
|
||||
WHEN cp.movimento IN ('Saida', 'Sangria')
|
||||
/* Sangria recebida de outro usuário */
|
||||
WHEN cp.movimento = 'Sangria'
|
||||
AND banco_destino.idusuarios = ?
|
||||
AND (
|
||||
banco_origem.idusuarios IS NULL
|
||||
OR banco_origem.idusuarios <> ?
|
||||
)
|
||||
THEN cp.valor
|
||||
|
||||
ELSE 0
|
||||
END
|
||||
), 0) AS entradas,
|
||||
|
||||
COALESCE(SUM(
|
||||
CASE
|
||||
/* Saída operacional normal */
|
||||
WHEN cp.movimento = 'Saida'
|
||||
AND banco_origem.idusuarios = ?
|
||||
AND COALESCE(cc.investimento, 0) = 0
|
||||
THEN cp.valor
|
||||
ELSE 0
|
||||
END), 0) AS saidas,
|
||||
|
||||
COALESCE(SUM(CASE
|
||||
WHEN cp.movimento IN ('Saida', 'Sangria')
|
||||
/* Sangria enviada para outro usuário */
|
||||
WHEN cp.movimento = 'Sangria'
|
||||
AND banco_origem.idusuarios = ?
|
||||
AND (
|
||||
banco_destino.idusuarios IS NULL
|
||||
OR banco_destino.idusuarios <> ?
|
||||
)
|
||||
THEN cp.valor
|
||||
|
||||
ELSE 0
|
||||
END
|
||||
), 0) AS saidas,
|
||||
|
||||
COALESCE(SUM(
|
||||
CASE
|
||||
/* Saída marcada como investimento pelo centro de custo */
|
||||
WHEN cp.movimento = 'Saida'
|
||||
AND banco_origem.idusuarios = ?
|
||||
AND COALESCE(cc.investimento, 0) = 1
|
||||
THEN cp.valor
|
||||
ELSE 0
|
||||
END), 0) AS investimentos,
|
||||
|
||||
COALESCE(SUM(CASE
|
||||
/* Transferência para banco de investimento do próprio usuário */
|
||||
WHEN cp.movimento = 'Sangria'
|
||||
AND banco_origem.idusuarios = ?
|
||||
AND banco_destino.idusuarios = ?
|
||||
AND COALESCE(banco_destino.investimento, 0) = 1
|
||||
THEN cp.valor
|
||||
|
||||
ELSE 0
|
||||
END
|
||||
), 0) AS investimentos,
|
||||
|
||||
COALESCE(SUM(
|
||||
CASE
|
||||
WHEN cp.status = 'A receber'
|
||||
AND cp.movimento IN ('Entrada', 'Estorno')
|
||||
AND banco_origem.idusuarios = ?
|
||||
THEN cp.valor
|
||||
ELSE 0
|
||||
END), 0) AS abertoEntradas,
|
||||
END
|
||||
), 0) AS abertoEntradas,
|
||||
|
||||
COUNT(CASE
|
||||
COUNT(
|
||||
CASE
|
||||
WHEN cp.status = 'A receber'
|
||||
AND cp.movimento IN ('Entrada', 'Estorno')
|
||||
AND banco_origem.idusuarios = ?
|
||||
THEN 1
|
||||
ELSE NULL
|
||||
END) AS quantidadeAbertoEntradas,
|
||||
END
|
||||
) AS quantidadeAbertoEntradas,
|
||||
|
||||
COALESCE(SUM(CASE
|
||||
COALESCE(SUM(
|
||||
CASE
|
||||
WHEN cp.status = 'A pagar'
|
||||
AND cp.movimento IN ('Saida', 'Sangria')
|
||||
AND cp.movimento = 'Saida'
|
||||
AND banco_origem.idusuarios = ?
|
||||
AND COALESCE(cc.investimento, 0) = 0
|
||||
THEN cp.valor
|
||||
ELSE 0
|
||||
END), 0) AS abertoSaidas,
|
||||
END
|
||||
), 0) AS abertoSaidas,
|
||||
|
||||
COUNT(CASE
|
||||
COUNT(
|
||||
CASE
|
||||
WHEN cp.status = 'A pagar'
|
||||
AND cp.movimento IN ('Saida', 'Sangria')
|
||||
AND cp.movimento = 'Saida'
|
||||
AND banco_origem.idusuarios = ?
|
||||
AND COALESCE(cc.investimento, 0) = 0
|
||||
THEN 1
|
||||
ELSE NULL
|
||||
END) AS quantidadeAbertoSaidas,
|
||||
END
|
||||
) AS quantidadeAbertoSaidas,
|
||||
|
||||
COALESCE(SUM(CASE
|
||||
COALESCE(SUM(
|
||||
CASE
|
||||
WHEN cp.status = 'A pagar'
|
||||
AND cp.movimento IN ('Saida', 'Sangria')
|
||||
AND cp.movimento = 'Saida'
|
||||
AND banco_origem.idusuarios = ?
|
||||
AND COALESCE(cc.investimento, 0) = 1
|
||||
THEN cp.valor
|
||||
ELSE 0
|
||||
END), 0) AS abertoInvestimentos,
|
||||
END
|
||||
), 0) AS abertoInvestimentos,
|
||||
|
||||
COUNT(CASE
|
||||
COUNT(
|
||||
CASE
|
||||
WHEN cp.status = 'A pagar'
|
||||
AND cp.movimento IN ('Saida', 'Sangria')
|
||||
AND cp.movimento = 'Saida'
|
||||
AND banco_origem.idusuarios = ?
|
||||
AND COALESCE(cc.investimento, 0) = 1
|
||||
THEN 1
|
||||
ELSE NULL
|
||||
END) AS quantidadeAbertoInvestimentos,
|
||||
END
|
||||
) AS quantidadeAbertoInvestimentos,
|
||||
|
||||
COALESCE(SUM(CASE
|
||||
WHEN cp.status IN ('Pago', 'Recebido') THEN cp.valor
|
||||
COALESCE(SUM(
|
||||
CASE
|
||||
WHEN cp.status IN ('Pago', 'Recebido')
|
||||
AND (
|
||||
cp.movimento <> 'Sangria'
|
||||
|
||||
OR (
|
||||
cp.movimento = 'Sangria'
|
||||
AND banco_origem.idusuarios = ?
|
||||
AND (
|
||||
banco_destino.idusuarios IS NULL
|
||||
OR banco_destino.idusuarios <> ?
|
||||
)
|
||||
)
|
||||
|
||||
OR (
|
||||
cp.movimento = 'Sangria'
|
||||
AND banco_destino.idusuarios = ?
|
||||
AND banco_origem.idusuarios <> ?
|
||||
)
|
||||
)
|
||||
THEN cp.valor
|
||||
ELSE 0
|
||||
END), 0) AS baixado,
|
||||
END
|
||||
), 0) AS baixado,
|
||||
|
||||
COUNT(*) AS quantidadeMovimentos
|
||||
|
||||
FROM contasapagar cp
|
||||
INNER JOIN bancos b
|
||||
ON b.idbancos = cp.idbancos
|
||||
|
||||
INNER JOIN bancos banco_origem
|
||||
ON banco_origem.idbancos = cp.idbancos
|
||||
|
||||
LEFT JOIN bancos banco_destino
|
||||
ON banco_destino.idbancos = cp.idbancos_p
|
||||
|
||||
LEFT JOIN centrodecustos cc
|
||||
ON cc.idcentrodecustos = cp.idcentrodecustos
|
||||
|
||||
WHERE cp.deleted_at IS NULL
|
||||
AND b.idusuarios = ?
|
||||
AND DATE(cp.datavencimento) BETWEEN ? AND ?
|
||||
AND (
|
||||
banco_origem.idusuarios = ?
|
||||
OR banco_destino.idusuarios = ?
|
||||
)
|
||||
AND DATE(COALESCE(cp.dataentrada, cp.insert_date))
|
||||
BETWEEN ? AND ?
|
||||
`,
|
||||
[idUsuario, dataInicio, dataFim]
|
||||
[
|
||||
/* entradas */
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
|
||||
/* saídas */
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
|
||||
/* investimentos */
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
|
||||
/* abertoEntradas */
|
||||
idUsuario,
|
||||
|
||||
/* quantidadeAbertoEntradas */
|
||||
idUsuario,
|
||||
|
||||
/* abertoSaidas */
|
||||
idUsuario,
|
||||
|
||||
/* quantidadeAbertoSaidas */
|
||||
idUsuario,
|
||||
|
||||
/* abertoInvestimentos */
|
||||
idUsuario,
|
||||
|
||||
/* quantidadeAbertoInvestimentos */
|
||||
idUsuario,
|
||||
|
||||
/* baixado */
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
|
||||
/* usuário na origem ou destino */
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
|
||||
/* período */
|
||||
dataInicio,
|
||||
dataFim,
|
||||
]
|
||||
);
|
||||
|
||||
const row = rows[0] || {};
|
||||
|
|
@ -267,9 +405,14 @@ async function buscarCardsMovimentos(idUsuario, dataInicio, dataFim) {
|
|||
abertoInvestimentos,
|
||||
aberto: abertoEntradas - abertoSaidas - abertoInvestimentos,
|
||||
|
||||
quantidadeAbertoEntradas: normalizarNumero(row.quantidadeAbertoEntradas),
|
||||
quantidadeAbertoSaidas: normalizarNumero(row.quantidadeAbertoSaidas),
|
||||
quantidadeAbertoInvestimentos: normalizarNumero(row.quantidadeAbertoInvestimentos),
|
||||
quantidadeAbertoEntradas:
|
||||
normalizarNumero(row.quantidadeAbertoEntradas),
|
||||
|
||||
quantidadeAbertoSaidas:
|
||||
normalizarNumero(row.quantidadeAbertoSaidas),
|
||||
|
||||
quantidadeAbertoInvestimentos:
|
||||
normalizarNumero(row.quantidadeAbertoInvestimentos),
|
||||
|
||||
baixado: normalizarNumero(row.baixado),
|
||||
quantidadeMovimentos: normalizarNumero(row.quantidadeMovimentos),
|
||||
|
|
@ -430,7 +573,8 @@ async function buscarAlertasVencimento(idUsuario) {
|
|||
}
|
||||
|
||||
async function buscarProximosVencimentos(idUsuario) {
|
||||
const [rows] = await pool.query(`
|
||||
const [rows] = await pool.query(
|
||||
`
|
||||
SELECT
|
||||
cp.idcontasapagar,
|
||||
cp.movimento,
|
||||
|
|
@ -443,22 +587,40 @@ async function buscarProximosVencimentos(idUsuario) {
|
|||
cp.parcela,
|
||||
cp.parcelas,
|
||||
cp.idbancos,
|
||||
bc.descricao AS banco_descricao,
|
||||
bc.debito AS banco_debito,
|
||||
|
||||
banco_origem.descricao AS banco_descricao,
|
||||
banco_origem.debito AS banco_debito,
|
||||
|
||||
cp.idcentrodecustos,
|
||||
cc.descricao AS centro_custo_descricao,
|
||||
DATEDIFF(DATE(cp.datavencimento), CURDATE()) AS dias_para_vencer
|
||||
|
||||
DATEDIFF(
|
||||
DATE(cp.datavencimento),
|
||||
CURDATE()
|
||||
) AS dias_para_vencer
|
||||
|
||||
FROM contasapagar cp
|
||||
INNER JOIN bancos bc ON bc.idbancos = cp.idbancos
|
||||
LEFT JOIN centrodecustos cc ON cc.idcentrodecustos = cp.idcentrodecustos
|
||||
|
||||
INNER JOIN bancos banco_origem
|
||||
ON banco_origem.idbancos = cp.idbancos
|
||||
|
||||
LEFT JOIN centrodecustos cc
|
||||
ON cc.idcentrodecustos = cp.idcentrodecustos
|
||||
|
||||
WHERE cp.deleted_at IS NULL
|
||||
AND bc.idusuarios = ?
|
||||
AND banco_origem.idusuarios = ?
|
||||
AND cp.status IN ('A pagar', 'A receber')
|
||||
AND cp.movimento IN ('Entrada', 'Estorno', 'Saida')
|
||||
AND cp.datavencimento IS NOT NULL
|
||||
ORDER BY DATE(cp.datavencimento) ASC, cp.idcontasapagar ASC
|
||||
|
||||
ORDER BY
|
||||
DATE(cp.datavencimento) ASC,
|
||||
cp.idcontasapagar ASC
|
||||
|
||||
LIMIT 10
|
||||
`,
|
||||
[idUsuario]);
|
||||
[idUsuario]
|
||||
);
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
|
@ -626,7 +788,8 @@ async function buscarCarteiras(idUsuario, dataInicio, dataFim) {
|
|||
}
|
||||
|
||||
async function buscarUltimosMovimentos(idUsuario) {
|
||||
const [rows] = await pool.query(`
|
||||
const [rows] = await pool.query(
|
||||
`
|
||||
SELECT
|
||||
cp.idcontasapagar,
|
||||
cp.movimento,
|
||||
|
|
@ -643,87 +806,362 @@ async function buscarUltimosMovimentos(idUsuario) {
|
|||
cp.saldo_processado,
|
||||
cp.insert_date,
|
||||
cp.update_date,
|
||||
|
||||
cp.idbancos,
|
||||
bc.descricao AS banco_descricao,
|
||||
bc.debito AS banco_debito,
|
||||
cp.idbancos_p,
|
||||
|
||||
banco_origem.descricao AS banco_descricao,
|
||||
banco_origem.descricao AS banco_origem_descricao,
|
||||
banco_origem.debito AS banco_debito,
|
||||
banco_origem.idusuarios AS idusuario_origem,
|
||||
usuario_origem.nome AS usuario_origem_nome,
|
||||
|
||||
banco_destino.descricao AS banco_destino_descricao,
|
||||
banco_destino.debito AS banco_destino_debito,
|
||||
banco_destino.idusuarios AS idusuario_destino,
|
||||
usuario_destino.nome AS usuario_destino_nome,
|
||||
|
||||
cp.idcentrodecustos,
|
||||
cc.descricao AS centro_custo_descricao
|
||||
cc.descricao AS centro_custo_descricao,
|
||||
|
||||
CASE
|
||||
/*
|
||||
* Movimento normal:
|
||||
* mantém o tipo original.
|
||||
*/
|
||||
WHEN cp.movimento <> 'Sangria'
|
||||
THEN cp.movimento
|
||||
|
||||
/*
|
||||
* Origem e destino pertencem ao usuário:
|
||||
* transferência interna.
|
||||
*/
|
||||
WHEN banco_origem.idusuarios = ?
|
||||
AND banco_destino.idusuarios = ?
|
||||
THEN 'TransferenciaInterna'
|
||||
|
||||
/*
|
||||
* Usuário é o dono do banco de origem:
|
||||
* dinheiro saiu para outro usuário.
|
||||
*/
|
||||
WHEN banco_origem.idusuarios = ?
|
||||
THEN 'Saida'
|
||||
|
||||
/*
|
||||
* Usuário é o dono do banco de destino:
|
||||
* dinheiro entrou vindo de outro usuário.
|
||||
*/
|
||||
WHEN banco_destino.idusuarios = ?
|
||||
THEN 'Entrada'
|
||||
|
||||
ELSE cp.movimento
|
||||
END AS movimento_dashboard,
|
||||
|
||||
CASE
|
||||
WHEN cp.movimento <> 'Sangria'
|
||||
AND cp.movimento IN ('Entrada', 'Estorno')
|
||||
THEN 'entrada'
|
||||
|
||||
WHEN cp.movimento <> 'Sangria'
|
||||
AND cp.movimento = 'Saida'
|
||||
THEN 'saida'
|
||||
|
||||
WHEN cp.movimento = 'Sangria'
|
||||
AND banco_origem.idusuarios = ?
|
||||
AND banco_destino.idusuarios = ?
|
||||
THEN 'transferencia_interna'
|
||||
|
||||
WHEN cp.movimento = 'Sangria'
|
||||
AND banco_origem.idusuarios = ?
|
||||
THEN 'saida'
|
||||
|
||||
WHEN cp.movimento = 'Sangria'
|
||||
AND banco_destino.idusuarios = ?
|
||||
THEN 'entrada'
|
||||
|
||||
ELSE 'neutro'
|
||||
END AS direcao_dashboard,
|
||||
|
||||
CASE
|
||||
WHEN cp.movimento = 'Sangria'
|
||||
AND banco_origem.idusuarios = ?
|
||||
AND banco_destino.idusuarios = ?
|
||||
THEN 1
|
||||
|
||||
ELSE 0
|
||||
END AS transferencia_interna
|
||||
|
||||
FROM contasapagar cp
|
||||
INNER JOIN bancos bc ON bc.idbancos = cp.idbancos
|
||||
LEFT JOIN centrodecustos cc ON cc.idcentrodecustos = cp.idcentrodecustos
|
||||
|
||||
INNER JOIN bancos banco_origem
|
||||
ON banco_origem.idbancos = cp.idbancos
|
||||
|
||||
LEFT JOIN bancos banco_destino
|
||||
ON banco_destino.idbancos = cp.idbancos_p
|
||||
|
||||
LEFT JOIN usuarios usuario_origem
|
||||
ON usuario_origem.idusuarios = banco_origem.idusuarios
|
||||
|
||||
LEFT JOIN usuarios usuario_destino
|
||||
ON usuario_destino.idusuarios = banco_destino.idusuarios
|
||||
|
||||
LEFT JOIN centrodecustos cc
|
||||
ON cc.idcentrodecustos = cp.idcentrodecustos
|
||||
|
||||
WHERE cp.deleted_at IS NULL
|
||||
AND bc.idusuarios = ?
|
||||
ORDER BY cp.insert_date DESC, cp.idcontasapagar DESC
|
||||
AND (
|
||||
banco_origem.idusuarios = ?
|
||||
OR banco_destino.idusuarios = ?
|
||||
)
|
||||
|
||||
ORDER BY
|
||||
cp.insert_date DESC,
|
||||
cp.idcontasapagar DESC
|
||||
|
||||
LIMIT 10
|
||||
`,
|
||||
[idUsuario]);
|
||||
[
|
||||
/* movimento_dashboard */
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
|
||||
return rows;
|
||||
/* direcao_dashboard */
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
|
||||
/* transferencia_interna */
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
|
||||
/* WHERE */
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
]
|
||||
);
|
||||
|
||||
return rows.map((item) => ({
|
||||
...item,
|
||||
|
||||
valor: normalizarNumero(item.valor),
|
||||
|
||||
transferencia_interna:
|
||||
Number(item.transferencia_interna || 0) === 1,
|
||||
}));
|
||||
}
|
||||
|
||||
async function buscarGraficos(idUsuario, dataInicio, dataFim) {
|
||||
/*
|
||||
* Gastos por centro de custo
|
||||
*
|
||||
* Aqui entram:
|
||||
* - Saídas normais do usuário;
|
||||
* - Sangrias enviadas para outro usuário;
|
||||
*
|
||||
* Não entram:
|
||||
* - Sangrias entre bancos do próprio usuário;
|
||||
* - Sangrias recebidas;
|
||||
* - Movimentos classificados como investimento.
|
||||
*/
|
||||
const [centrosRows] = await pool.query(
|
||||
`
|
||||
SELECT
|
||||
cp.idcentrodecustos,
|
||||
COALESCE(cc.descricao, 'Sem centro de custo') AS descricao,
|
||||
COALESCE(SUM(cp.valor), 0) AS valor
|
||||
|
||||
FROM contasapagar cp
|
||||
|
||||
INNER JOIN bancos banco_origem
|
||||
ON banco_origem.idbancos = cp.idbancos
|
||||
|
||||
LEFT JOIN bancos banco_destino
|
||||
ON banco_destino.idbancos = cp.idbancos_p
|
||||
|
||||
LEFT JOIN centrodecustos cc
|
||||
ON cc.idcentrodecustos = cp.idcentrodecustos
|
||||
LEFT JOIN bancos b
|
||||
ON b.idbancos = cp.idbancos
|
||||
|
||||
WHERE cp.deleted_at IS NULL
|
||||
AND cp.movimento IN ('Saida', 'Sangria')
|
||||
AND DATE(COALESCE(cp.dataentrada, cp.insert_date))
|
||||
BETWEEN ? AND ?
|
||||
AND COALESCE(cc.investimento, 0) = 0
|
||||
AND DATE(cp.datavencimento) BETWEEN ? AND ?
|
||||
AND b.idusuarios = ?
|
||||
|
||||
AND (
|
||||
(
|
||||
cp.movimento = 'Saida'
|
||||
AND banco_origem.idusuarios = ?
|
||||
)
|
||||
|
||||
OR
|
||||
|
||||
(
|
||||
cp.movimento = 'Sangria'
|
||||
AND banco_origem.idusuarios = ?
|
||||
AND (
|
||||
banco_destino.idusuarios IS NULL
|
||||
OR banco_destino.idusuarios <> ?
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
GROUP BY
|
||||
cp.idcentrodecustos,
|
||||
COALESCE(cc.descricao, 'Sem centro de custo')
|
||||
|
||||
HAVING valor > 0
|
||||
|
||||
ORDER BY valor DESC
|
||||
|
||||
LIMIT 8
|
||||
`,
|
||||
[dataInicio, dataFim, idUsuario]
|
||||
[
|
||||
dataInicio,
|
||||
dataFim,
|
||||
|
||||
idUsuario,
|
||||
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
]
|
||||
);
|
||||
|
||||
/*
|
||||
* Resumo de entradas, saídas e investimentos.
|
||||
*
|
||||
* Para sangria:
|
||||
* - destino é do usuário e origem é de outro usuário = entrada;
|
||||
* - origem é do usuário e destino é de outro usuário = saída;
|
||||
* - origem e destino são do usuário = transferência interna, ignorada.
|
||||
*/
|
||||
const [entradasSaidasRows] = await pool.query(
|
||||
`
|
||||
SELECT
|
||||
COALESCE(SUM(CASE
|
||||
WHEN cp.movimento IN ('Entrada', 'Estorno') THEN cp.valor
|
||||
ELSE 0
|
||||
END), 0) AS entradas,
|
||||
COALESCE(
|
||||
SUM(
|
||||
CASE
|
||||
/* Entrada ou estorno normal */
|
||||
WHEN cp.movimento IN ('Entrada', 'Estorno')
|
||||
AND banco_origem.idusuarios = ?
|
||||
THEN cp.valor
|
||||
|
||||
COALESCE(SUM(CASE
|
||||
WHEN cp.movimento IN ('Saida', 'Sangria')
|
||||
/* Sangria recebida de outro usuário */
|
||||
WHEN cp.movimento = 'Sangria'
|
||||
AND banco_destino.idusuarios = ?
|
||||
AND banco_origem.idusuarios <> ?
|
||||
THEN cp.valor
|
||||
|
||||
ELSE 0
|
||||
END
|
||||
),
|
||||
0
|
||||
) AS entradas,
|
||||
|
||||
COALESCE(
|
||||
SUM(
|
||||
CASE
|
||||
/* Saída normal */
|
||||
WHEN cp.movimento = 'Saida'
|
||||
AND banco_origem.idusuarios = ?
|
||||
AND COALESCE(cc.investimento, 0) = 0
|
||||
THEN cp.valor
|
||||
ELSE 0
|
||||
END), 0) AS saidas,
|
||||
|
||||
COALESCE(SUM(CASE
|
||||
WHEN cp.movimento IN ('Saida', 'Sangria')
|
||||
/* Sangria enviada para outro usuário */
|
||||
WHEN cp.movimento = 'Sangria'
|
||||
AND banco_origem.idusuarios = ?
|
||||
AND (
|
||||
banco_destino.idusuarios IS NULL
|
||||
OR banco_destino.idusuarios <> ?
|
||||
)
|
||||
AND COALESCE(cc.investimento, 0) = 0
|
||||
THEN cp.valor
|
||||
|
||||
ELSE 0
|
||||
END
|
||||
),
|
||||
0
|
||||
) AS saidas,
|
||||
|
||||
COALESCE(
|
||||
SUM(
|
||||
CASE
|
||||
WHEN cp.movimento = 'Saida'
|
||||
AND banco_origem.idusuarios = ?
|
||||
AND COALESCE(cc.investimento, 0) = 1
|
||||
THEN cp.valor
|
||||
|
||||
WHEN cp.movimento = 'Sangria'
|
||||
AND banco_origem.idusuarios = ?
|
||||
AND banco_destino.idusuarios = ?
|
||||
AND COALESCE(banco_destino.investimento, 0) = 1
|
||||
THEN cp.valor
|
||||
|
||||
ELSE 0
|
||||
END), 0) AS investimentos
|
||||
END
|
||||
),
|
||||
0
|
||||
) AS investimentos
|
||||
|
||||
FROM contasapagar cp
|
||||
|
||||
INNER JOIN bancos banco_origem
|
||||
ON banco_origem.idbancos = cp.idbancos
|
||||
|
||||
LEFT JOIN bancos banco_destino
|
||||
ON banco_destino.idbancos = cp.idbancos_p
|
||||
|
||||
LEFT JOIN centrodecustos cc
|
||||
ON cc.idcentrodecustos = cp.idcentrodecustos
|
||||
LEFT JOIN bancos b
|
||||
ON b.idbancos = cp.idbancos
|
||||
|
||||
WHERE cp.deleted_at IS NULL
|
||||
AND DATE(cp.datavencimento) BETWEEN ? AND ?
|
||||
AND b.idusuarios = ?
|
||||
AND DATE(COALESCE(cp.dataentrada, cp.insert_date))
|
||||
BETWEEN ? AND ?
|
||||
|
||||
AND (
|
||||
banco_origem.idusuarios = ?
|
||||
OR banco_destino.idusuarios = ?
|
||||
)
|
||||
`,
|
||||
[dataInicio, dataFim, idUsuario]
|
||||
[
|
||||
/* Entradas */
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
|
||||
/* Saídas */
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
|
||||
/* Investimentos */
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
|
||||
/* Período */
|
||||
dataInicio,
|
||||
dataFim,
|
||||
|
||||
/* Usuário presente em uma das pontas */
|
||||
idUsuario,
|
||||
idUsuario,
|
||||
]
|
||||
);
|
||||
|
||||
const entradas = normalizarNumero(
|
||||
entradasSaidasRows[0]?.entradas
|
||||
);
|
||||
|
||||
const saidas = normalizarNumero(
|
||||
entradasSaidasRows[0]?.saidas
|
||||
);
|
||||
|
||||
const investimentos = normalizarNumero(
|
||||
entradasSaidasRows[0]?.investimentos
|
||||
);
|
||||
|
||||
const entradas = normalizarNumero(entradasSaidasRows[0]?.entradas);
|
||||
const saidas = normalizarNumero(entradasSaidasRows[0]?.saidas);
|
||||
const investimentos = normalizarNumero(entradasSaidasRows[0]?.investimentos);
|
||||
const resultado = entradas - saidas - investimentos;
|
||||
|
||||
return {
|
||||
|
|
@ -741,8 +1179,14 @@ async function buscarGraficos(idUsuario, dataInicio, dataFim) {
|
|||
|
||||
percentualEntradas: entradas > 0 ? 100 : 0,
|
||||
percentualSaidas: calcularPercentual(saidas, entradas),
|
||||
percentualInvestimentos: calcularPercentual(investimentos, entradas),
|
||||
percentualResultado: calcularPercentual(resultado, entradas),
|
||||
percentualInvestimentos: calcularPercentual(
|
||||
investimentos,
|
||||
entradas
|
||||
),
|
||||
percentualResultado: calcularPercentual(
|
||||
resultado,
|
||||
entradas
|
||||
),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -72,7 +72,14 @@ function formatarData(data: string | null | undefined) {
|
|||
}
|
||||
|
||||
function movimentoColor(movimento: string) {
|
||||
if (movimento === 'Entrada' || movimento === 'Estorno') return 'success.main';
|
||||
if (movimento === 'Entrada' || movimento === 'Estorno') {
|
||||
return 'success.main';
|
||||
}
|
||||
|
||||
if (movimento === 'TransferenciaInterna') {
|
||||
return 'info.main';
|
||||
}
|
||||
|
||||
return 'error.main';
|
||||
}
|
||||
|
||||
|
|
@ -95,7 +102,15 @@ function isMovimentoEntrada(movimento: string) {
|
|||
}
|
||||
|
||||
function movimentoBorderColor(movimento: string) {
|
||||
return isMovimentoEntrada(movimento) ? 'success.main' : 'error.main';
|
||||
if (isMovimentoEntrada(movimento)) {
|
||||
return 'success.main';
|
||||
}
|
||||
|
||||
if (movimento === 'TransferenciaInterna') {
|
||||
return 'info.main';
|
||||
}
|
||||
|
||||
return 'error.main';
|
||||
}
|
||||
|
||||
function movimentoActionLabel(item: DashboardMovimentoResumo) {
|
||||
|
|
@ -213,7 +228,15 @@ function StatCard({
|
|||
}
|
||||
|
||||
function MovimentoLinha({ item }: { item: DashboardMovimentoResumo }) {
|
||||
const isEntrada = isMovimentoEntrada(item.movimento);
|
||||
const movimentoVisual =
|
||||
item.movimento_dashboard || item.movimento;
|
||||
|
||||
const isTransferenciaInterna =
|
||||
movimentoVisual === 'TransferenciaInterna';
|
||||
|
||||
const isEntrada =
|
||||
movimentoVisual === 'Entrada'
|
||||
|| movimentoVisual === 'Estorno';
|
||||
|
||||
return (
|
||||
<Box
|
||||
|
|
@ -224,8 +247,10 @@ function MovimentoLinha({ item }: { item: DashboardMovimentoResumo }) {
|
|||
border: '1px solid',
|
||||
borderColor: 'divider',
|
||||
borderLeft: '6px solid',
|
||||
borderLeftColor: movimentoBorderColor(item.movimento),
|
||||
background: isEntrada
|
||||
borderLeftColor: movimentoBorderColor(movimentoVisual),
|
||||
background: isTransferenciaInterna
|
||||
? 'linear-gradient(90deg, rgba(2,136,209,0.08) 0%, rgba(255,255,255,0.9) 42%)'
|
||||
: isEntrada
|
||||
? 'linear-gradient(90deg, rgba(46,125,50,0.08) 0%, rgba(255,255,255,0.9) 42%)'
|
||||
: 'linear-gradient(90deg, rgba(211,47,47,0.08) 0%, rgba(255,255,255,0.9) 42%)',
|
||||
}}
|
||||
|
|
@ -241,9 +266,19 @@ function MovimentoLinha({ item }: { item: DashboardMovimentoResumo }) {
|
|||
</Typography>
|
||||
|
||||
<Chip
|
||||
label={item.movimento}
|
||||
label={
|
||||
isTransferenciaInterna
|
||||
? 'Transferência interna'
|
||||
: movimentoVisual
|
||||
}
|
||||
color={
|
||||
isTransferenciaInterna
|
||||
? 'info'
|
||||
: isEntrada
|
||||
? 'success'
|
||||
: 'error'
|
||||
}
|
||||
size="small"
|
||||
color={isEntrada ? 'success' : 'error'}
|
||||
variant="outlined"
|
||||
/>
|
||||
</Stack>
|
||||
|
|
@ -276,7 +311,7 @@ function MovimentoLinha({ item }: { item: DashboardMovimentoResumo }) {
|
|||
spacing={0.75}
|
||||
flexShrink={0}
|
||||
>
|
||||
<Typography fontWeight={950} color={movimentoColor(item.movimento)}>
|
||||
<Typography fontWeight={950} color={movimentoColor(movimentoVisual)}>
|
||||
{formatarValor(item.valor)}
|
||||
</Typography>
|
||||
|
||||
|
|
@ -292,7 +327,13 @@ function MovimentoLinha({ item }: { item: DashboardMovimentoResumo }) {
|
|||
to={`/movimentos/${item.idcontasapagar}/editar`}
|
||||
size="small"
|
||||
variant="contained"
|
||||
color={isEntrada ? 'success' : 'error'}
|
||||
color={
|
||||
isTransferenciaInterna
|
||||
? 'info'
|
||||
: isEntrada
|
||||
? 'success'
|
||||
: 'error'
|
||||
}
|
||||
sx={{ borderRadius: 2, boxShadow: 0 }}
|
||||
>
|
||||
{movimentoActionLabel(item)}
|
||||
|
|
@ -833,7 +874,7 @@ export function DashboardPage() {
|
|||
<StatCard
|
||||
title="Investimentos"
|
||||
value={formatarValor(cards.investimentos)}
|
||||
subtitle="Sangrias marcadas como investimento"
|
||||
subtitle="Valores destinados a investimentos"
|
||||
icon={<AccountBalanceWalletIcon />}
|
||||
color="info"
|
||||
percent={cards.percentualInvestimentos}
|
||||
|
|
|
|||
|
|
@ -70,6 +70,9 @@ export type DashboardMovimentoResumo = {
|
|||
idcentrodecustos?: number | null;
|
||||
centro_custo_descricao?: string | null;
|
||||
dias_para_vencer?: number;
|
||||
movimento_dashboard?: string;
|
||||
direcao_dashboard?: string;
|
||||
transferencia_interna?: boolean;
|
||||
};
|
||||
|
||||
export type DashboardCredito = {
|
||||
|
|
@ -144,10 +144,57 @@ function campoDataLabel(campo: DataCampo) {
|
|||
return labels[campo];
|
||||
}
|
||||
|
||||
function getMovimentoVisual(item: Movimento) {
|
||||
return item.movimento_dashboard || item.movimento;
|
||||
}
|
||||
|
||||
function movimentoEhEntrada(item: Movimento) {
|
||||
return item.direcao_dashboard
|
||||
? item.direcao_dashboard === 'entrada'
|
||||
: item.movimento === 'Entrada'
|
||||
|| item.movimento === 'Estorno';
|
||||
}
|
||||
|
||||
function movimentoEhSaida(item: Movimento) {
|
||||
return item.direcao_dashboard
|
||||
? item.direcao_dashboard === 'saida'
|
||||
: item.movimento === 'Saida';
|
||||
}
|
||||
|
||||
function movimentoEhTransferenciaInterna(item: Movimento) {
|
||||
return item.transferencia_interna === true
|
||||
|| item.direcao_dashboard === 'transferencia_interna'
|
||||
|| getMovimentoVisual(item) === 'TransferenciaInterna';
|
||||
}
|
||||
|
||||
function movimentoEhInvestimento(item: Movimento) {
|
||||
return item.investimento_dashboard === true;
|
||||
}
|
||||
|
||||
function movimentoChipColor(movimento: string) {
|
||||
if (movimento === 'Entrada') return 'success';
|
||||
if (movimento === 'Saida') return 'error';
|
||||
if (movimento === 'Sangria') return 'warning';
|
||||
if (movimento === 'Entrada' || movimento === 'Estorno') {
|
||||
return 'success';
|
||||
}
|
||||
|
||||
if (movimento === 'Saida' || movimento === 'Saída') {
|
||||
return 'error';
|
||||
}
|
||||
|
||||
if (
|
||||
movimento === 'TransferenciaInterna'
|
||||
|| movimento === 'Transferência interna'
|
||||
) {
|
||||
return 'info';
|
||||
}
|
||||
|
||||
if (movimento === 'Investimento') {
|
||||
return 'primary';
|
||||
}
|
||||
|
||||
if (movimento === 'Sangria') {
|
||||
return 'warning';
|
||||
}
|
||||
|
||||
return 'default';
|
||||
}
|
||||
|
||||
|
|
@ -264,7 +311,7 @@ function getMovimentoRowVisual(item: Movimento) {
|
|||
};
|
||||
}
|
||||
|
||||
function getMovimentoIconVisual(movimento: MovimentoTipo) {
|
||||
function getMovimentoIconVisual(movimento: string) {
|
||||
if (movimento === 'Entrada') {
|
||||
return {
|
||||
icon: <ArrowDownwardIcon fontSize="small" />,
|
||||
|
|
@ -273,7 +320,7 @@ function getMovimentoIconVisual(movimento: MovimentoTipo) {
|
|||
};
|
||||
}
|
||||
|
||||
if (movimento === 'Saida') {
|
||||
if (movimento === 'Saida' || movimento === 'Saída') {
|
||||
return {
|
||||
icon: <ArrowUpwardIcon fontSize="small" />,
|
||||
label: 'Saída',
|
||||
|
|
@ -281,6 +328,25 @@ function getMovimentoIconVisual(movimento: MovimentoTipo) {
|
|||
};
|
||||
}
|
||||
|
||||
if (
|
||||
movimento === 'TransferenciaInterna'
|
||||
|| movimento === 'Transferência interna'
|
||||
) {
|
||||
return {
|
||||
icon: <SwapHorizIcon fontSize="small" />,
|
||||
label: 'Transferência interna',
|
||||
color: 'info' as const,
|
||||
};
|
||||
}
|
||||
|
||||
if (movimento === 'Investimento') {
|
||||
return {
|
||||
icon: <AccountBalanceIcon fontSize="small" />,
|
||||
label: 'Investimento',
|
||||
color: 'primary' as const,
|
||||
};
|
||||
}
|
||||
|
||||
if (movimento === 'Sangria') {
|
||||
return {
|
||||
icon: <SwapHorizIcon fontSize="small" />,
|
||||
|
|
@ -304,6 +370,24 @@ function getMovimentoIconVisual(movimento: MovimentoTipo) {
|
|||
};
|
||||
}
|
||||
|
||||
function movimentoVisualLabel(item: Movimento) {
|
||||
if (movimentoEhInvestimento(item)) {
|
||||
return 'Investimento';
|
||||
}
|
||||
|
||||
const movimento = getMovimentoVisual(item);
|
||||
|
||||
if (movimento === 'TransferenciaInterna') {
|
||||
return 'Transferência interna';
|
||||
}
|
||||
|
||||
if (movimento === 'Saida') {
|
||||
return 'Saída';
|
||||
}
|
||||
|
||||
return movimento;
|
||||
}
|
||||
|
||||
function formatarDataGrupo(dataISO: string) {
|
||||
if (!dataISO || dataISO === 'sem-data') return 'Sem data';
|
||||
|
||||
|
|
@ -329,13 +413,21 @@ function getDataGrupo(item: Movimento, campo: DataCampo) {
|
|||
function valorAssinadoMovimento(item: Movimento) {
|
||||
const valor = Number(item.valor || 0);
|
||||
|
||||
if (item.movimento === 'Entrada' || item.movimento === 'Estorno') {
|
||||
if (movimentoEhTransferenciaInterna(item)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (movimentoEhEntrada(item)) {
|
||||
return valor;
|
||||
}
|
||||
|
||||
if (movimentoEhSaida(item) || movimentoEhInvestimento(item)) {
|
||||
return valor * -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function criarResumoGrupo() {
|
||||
return {
|
||||
totalEntradas: 0,
|
||||
|
|
@ -345,15 +437,15 @@ function criarResumoGrupo() {
|
|||
};
|
||||
}
|
||||
|
||||
function aplicarMovimentoNoResumo<T extends ReturnType<typeof criarResumoGrupo>>(
|
||||
resumo: T,
|
||||
item: Movimento
|
||||
) {
|
||||
function aplicarMovimentoNoResumo<T extends ReturnType<typeof criarResumoGrupo>>(resumo: T, item: Movimento) {
|
||||
const valorAssinado = valorAssinadoMovimento(item);
|
||||
|
||||
if (valorAssinado >= 0) {
|
||||
resumo.totalEntradas += valorAssinado;
|
||||
} else {
|
||||
if (movimentoEhEntrada(item)) {
|
||||
resumo.totalEntradas += Math.abs(valorAssinado);
|
||||
} else if (
|
||||
movimentoEhSaida(item)
|
||||
|| movimentoEhInvestimento(item)
|
||||
) {
|
||||
resumo.totalSaidas += Math.abs(valorAssinado);
|
||||
}
|
||||
|
||||
|
|
@ -377,10 +469,24 @@ function agruparMovimentos(movimentos: Movimento[], campo: DataCampo): GrupoDiaM
|
|||
|
||||
for (const item of movimentos) {
|
||||
const chaveDia = getDataGrupo(item, campo);
|
||||
const bancoNome = item.banco_descricao || 'Sem banco';
|
||||
const bancoNome =
|
||||
item.direcao_dashboard === 'entrada'
|
||||
&& item.movimento === 'Sangria'
|
||||
? item.banco_referencia_descricao
|
||||
|| item.banco_descricao
|
||||
|| 'Sem banco'
|
||||
: item.banco_descricao
|
||||
|| 'Sem banco';
|
||||
const centroNome = item.centro_custo_descricao || 'Sem centro de custo';
|
||||
|
||||
const chaveBanco = String(item.idbancos || bancoNome);
|
||||
const idBancoVisual =
|
||||
item.direcao_dashboard === 'entrada'
|
||||
&& item.movimento === 'Sangria'
|
||||
? item.idbancos_p
|
||||
: item.idbancos;
|
||||
|
||||
const chaveBanco =
|
||||
String(idBancoVisual || bancoNome);
|
||||
const chaveCentro = String(item.idcentrodecustos || centroNome);
|
||||
|
||||
if (!gruposDia.has(chaveDia)) {
|
||||
|
|
@ -473,17 +579,41 @@ export function MovimentosPage() {
|
|||
page: 1,
|
||||
totalPages: 1,
|
||||
});
|
||||
const [summary, setSummary] = useState<MovimentosSummary>({
|
||||
|
||||
const SUMMARY_INICIAL: MovimentosSummary = {
|
||||
quantidade: 0,
|
||||
|
||||
totalEntradas: 0,
|
||||
entradasRecebidas: 0,
|
||||
entradasPendentes: 0,
|
||||
quantidadeEntradasRecebidas: 0,
|
||||
quantidadeEntradasPendentes: 0,
|
||||
percentualEntradasRecebidas: 0,
|
||||
percentualEntradasPendentes: 0,
|
||||
|
||||
totalSaidas: 0,
|
||||
totalSangrias: 0,
|
||||
saidasPagas: 0,
|
||||
saidasPendentes: 0,
|
||||
quantidadeSaidasPagas: 0,
|
||||
quantidadeSaidasPendentes: 0,
|
||||
percentualSaidasPagas: 0,
|
||||
percentualSaidasPendentes: 0,
|
||||
|
||||
totalInvestimentos: 0,
|
||||
investimentosRealizados: 0,
|
||||
investimentosPendentes: 0,
|
||||
quantidadeInvestimentosRealizados: 0,
|
||||
quantidadeInvestimentosPendentes: 0,
|
||||
percentualInvestimentosRealizados: 0,
|
||||
percentualInvestimentosPendentes: 0,
|
||||
|
||||
totalEstornos: 0,
|
||||
totalBaixado: 0,
|
||||
totalAberto: 0,
|
||||
saldoProcessado: 0,
|
||||
saldo: 0,
|
||||
});
|
||||
};
|
||||
|
||||
const [summary, setSummary] =
|
||||
useState<MovimentosSummary>(SUMMARY_INICIAL);
|
||||
|
||||
const [modoVisualizacao, setModoVisualizacao] = useState<ModoVisualizacao>('tabela');
|
||||
const [gruposAbertos, setGruposAbertos] = useState<Record<string, boolean>>({});
|
||||
|
|
@ -968,7 +1098,8 @@ export function MovimentosPage() {
|
|||
<Stack spacing={0.75} padding={1.25} paddingTop={0}>
|
||||
{centro.movimentos.map((item) => {
|
||||
const rowVisual = getMovimentoRowVisual(item);
|
||||
const movimentoIcon = getMovimentoIconVisual(item.movimento);
|
||||
const movimentoVisual = movimentoVisualLabel(item);
|
||||
const movimentoIcon = getMovimentoIconVisual(movimentoVisual);
|
||||
const dataPrincipal = getDataPrincipal(item, dataCampo);
|
||||
|
||||
return (
|
||||
|
|
@ -1046,13 +1177,17 @@ export function MovimentosPage() {
|
|||
<Typography
|
||||
fontWeight={950}
|
||||
color={
|
||||
item.movimento === 'Entrada' || item.movimento === 'Estorno'
|
||||
movimentoEhTransferenciaInterna(item)
|
||||
? 'info.main'
|
||||
: movimentoEhEntrada(item)
|
||||
? 'success.main'
|
||||
: 'error.main'
|
||||
}
|
||||
whiteSpace="nowrap"
|
||||
>
|
||||
{item.movimento === 'Entrada' || item.movimento === 'Estorno'
|
||||
{movimentoEhTransferenciaInterna(item)
|
||||
? ''
|
||||
: movimentoEhEntrada(item)
|
||||
? '+'
|
||||
: '-'}
|
||||
{formatarValor(item.valor)}
|
||||
|
|
@ -1094,6 +1229,133 @@ export function MovimentosPage() {
|
|||
);
|
||||
}
|
||||
|
||||
function CardResumoFinanceiro({
|
||||
titulo,
|
||||
total,
|
||||
realizadoLabel,
|
||||
realizado,
|
||||
realizadoQuantidade,
|
||||
realizadoPercentual,
|
||||
pendenteLabel,
|
||||
pendente,
|
||||
pendenteQuantidade,
|
||||
pendentePercentual,
|
||||
corTotal,
|
||||
}: {
|
||||
titulo: string;
|
||||
total: number;
|
||||
realizadoLabel: string;
|
||||
realizado: number;
|
||||
realizadoQuantidade: number;
|
||||
realizadoPercentual: number;
|
||||
pendenteLabel: string;
|
||||
pendente: number;
|
||||
pendenteQuantidade: number;
|
||||
pendentePercentual: number;
|
||||
corTotal: 'success.main' | 'error.main' | 'primary.main';
|
||||
}) {
|
||||
return (
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="text.secondary"
|
||||
>
|
||||
{titulo}
|
||||
</Typography>
|
||||
|
||||
<Typography
|
||||
variant="h5"
|
||||
fontWeight={950}
|
||||
color={corTotal}
|
||||
marginTop={0.25}
|
||||
>
|
||||
{formatarValor(total)}
|
||||
</Typography>
|
||||
|
||||
<Divider sx={{ marginY: 1.25 }} />
|
||||
|
||||
<Stack spacing={0.75}>
|
||||
<Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
spacing={1}
|
||||
>
|
||||
<Box>
|
||||
<Typography
|
||||
variant="caption"
|
||||
color="text.secondary"
|
||||
>
|
||||
{realizadoLabel}
|
||||
</Typography>
|
||||
|
||||
<Typography
|
||||
variant="body2"
|
||||
fontWeight={850}
|
||||
>
|
||||
{formatarValor(realizado)}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Chip
|
||||
size="small"
|
||||
color="success"
|
||||
variant="outlined"
|
||||
label={`${realizadoPercentual.toFixed(1)}%`}
|
||||
/>
|
||||
</Stack>
|
||||
|
||||
<Typography
|
||||
variant="caption"
|
||||
color="text.secondary"
|
||||
>
|
||||
{realizadoQuantidade} movimento(s)
|
||||
</Typography>
|
||||
|
||||
<Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
spacing={1}
|
||||
marginTop={0.5}
|
||||
>
|
||||
<Box>
|
||||
<Typography
|
||||
variant="caption"
|
||||
color="text.secondary"
|
||||
>
|
||||
{pendenteLabel}
|
||||
</Typography>
|
||||
|
||||
<Typography
|
||||
variant="body2"
|
||||
fontWeight={850}
|
||||
>
|
||||
{formatarValor(pendente)}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Chip
|
||||
size="small"
|
||||
color="warning"
|
||||
variant="outlined"
|
||||
label={`${pendentePercentual.toFixed(1)}%`}
|
||||
/>
|
||||
</Stack>
|
||||
|
||||
<Typography
|
||||
variant="caption"
|
||||
color="text.secondary"
|
||||
>
|
||||
{pendenteQuantidade} movimento(s)
|
||||
</Typography>
|
||||
</Stack>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Stack
|
||||
|
|
@ -1153,77 +1415,132 @@ export function MovimentosPage() {
|
|||
display="grid"
|
||||
gridTemplateColumns={{
|
||||
xs: '1fr',
|
||||
md: 'repeat(6, 1fr)',
|
||||
md: 'repeat(2, minmax(0, 1fr))',
|
||||
xl: 'repeat(5, minmax(0, 1fr))',
|
||||
}}
|
||||
gap={{ xs: 2, md: 2.5 }}
|
||||
marginBottom={{ xs: 2.5, md: 3 }}
|
||||
>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="text.secondary"
|
||||
>
|
||||
Registros encontrados
|
||||
</Typography>
|
||||
<Typography variant="h5" fontWeight={950}>
|
||||
{summary.quantidade}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Entradas
|
||||
</Typography>
|
||||
<Typography variant="h5" fontWeight={950} color="success.main">
|
||||
{formatarValor(summary.totalEntradas)}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Saídas
|
||||
</Typography>
|
||||
<Typography variant="h5" fontWeight={950} color="error.main">
|
||||
{formatarValor(summary.totalSaidas + summary.totalSangrias)}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Saldo filtrado
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="h5"
|
||||
fontWeight={950}
|
||||
color={summary.saldo >= 0 ? 'success.main' : 'error.main'}
|
||||
>
|
||||
{summary.quantidade}
|
||||
</Typography>
|
||||
|
||||
<Typography
|
||||
variant="caption"
|
||||
color="text.secondary"
|
||||
>
|
||||
Movimentos financeiros filtrados
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<CardResumoFinanceiro
|
||||
titulo="Entradas"
|
||||
total={summary.totalEntradas}
|
||||
realizadoLabel="Recebido"
|
||||
realizado={summary.entradasRecebidas}
|
||||
realizadoQuantidade={
|
||||
summary.quantidadeEntradasRecebidas
|
||||
}
|
||||
realizadoPercentual={
|
||||
summary.percentualEntradasRecebidas
|
||||
}
|
||||
pendenteLabel="A receber"
|
||||
pendente={summary.entradasPendentes}
|
||||
pendenteQuantidade={
|
||||
summary.quantidadeEntradasPendentes
|
||||
}
|
||||
pendentePercentual={
|
||||
summary.percentualEntradasPendentes
|
||||
}
|
||||
corTotal="success.main"
|
||||
/>
|
||||
|
||||
<CardResumoFinanceiro
|
||||
titulo="Saídas"
|
||||
total={summary.totalSaidas}
|
||||
realizadoLabel="Pago"
|
||||
realizado={summary.saidasPagas}
|
||||
realizadoQuantidade={
|
||||
summary.quantidadeSaidasPagas
|
||||
}
|
||||
realizadoPercentual={
|
||||
summary.percentualSaidasPagas
|
||||
}
|
||||
pendenteLabel="A pagar"
|
||||
pendente={summary.saidasPendentes}
|
||||
pendenteQuantidade={
|
||||
summary.quantidadeSaidasPendentes
|
||||
}
|
||||
pendentePercentual={
|
||||
summary.percentualSaidasPendentes
|
||||
}
|
||||
corTotal="error.main"
|
||||
/>
|
||||
|
||||
<CardResumoFinanceiro
|
||||
titulo="Investimentos"
|
||||
total={summary.totalInvestimentos}
|
||||
realizadoLabel="Realizado"
|
||||
realizado={summary.investimentosRealizados}
|
||||
realizadoQuantidade={
|
||||
summary.quantidadeInvestimentosRealizados
|
||||
}
|
||||
realizadoPercentual={
|
||||
summary.percentualInvestimentosRealizados
|
||||
}
|
||||
pendenteLabel="Pendente"
|
||||
pendente={summary.investimentosPendentes}
|
||||
pendenteQuantidade={
|
||||
summary.quantidadeInvestimentosPendentes
|
||||
}
|
||||
pendentePercentual={
|
||||
summary.percentualInvestimentosPendentes
|
||||
}
|
||||
corTotal="primary.main"
|
||||
/>
|
||||
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="text.secondary"
|
||||
>
|
||||
Saldo filtrado
|
||||
</Typography>
|
||||
|
||||
<Typography
|
||||
variant="h5"
|
||||
fontWeight={950}
|
||||
color={
|
||||
summary.saldo >= 0
|
||||
? 'success.main'
|
||||
: 'error.main'
|
||||
}
|
||||
marginTop={0.25}
|
||||
>
|
||||
{formatarValor(summary.saldo)}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Em aberto
|
||||
</Typography>
|
||||
<Typography variant="h5" fontWeight={950} color="warning.main">
|
||||
{formatarValor(summary.totalAberto)}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Divider sx={{ marginY: 1.25 }} />
|
||||
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Baixados
|
||||
</Typography>
|
||||
<Typography variant="h5" fontWeight={950} color="info.main">
|
||||
{formatarValor(summary.totalBaixado)}
|
||||
<Typography
|
||||
variant="caption"
|
||||
color="text.secondary"
|
||||
>
|
||||
Entradas menos saídas e investimentos
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
|
@ -1553,7 +1870,8 @@ export function MovimentosPage() {
|
|||
{movimentos.map((item) => {
|
||||
const dataPrincipal = getDataPrincipal(item, dataCampo);
|
||||
const rowVisual = getMovimentoRowVisual(item);
|
||||
const movimentoIcon = getMovimentoIconVisual(item.movimento);
|
||||
const movimentoVisual = movimentoVisualLabel(item);
|
||||
const movimentoIcon = getMovimentoIconVisual(movimentoVisual);
|
||||
|
||||
return (
|
||||
<Box
|
||||
|
|
@ -1609,8 +1927,13 @@ export function MovimentosPage() {
|
|||
<Typography
|
||||
fontWeight={950}
|
||||
color={
|
||||
item.movimento === 'Entrada' || item.movimento === 'Estorno'
|
||||
movimentoEhTransferenciaInterna(item)
|
||||
? 'info.main'
|
||||
: movimentoEhEntrada(item)
|
||||
? 'success.main'
|
||||
: movimentoEhSaida(item)
|
||||
|| movimentoEhInvestimento(item)
|
||||
? 'error.main'
|
||||
: 'text.primary'
|
||||
}
|
||||
whiteSpace="nowrap"
|
||||
|
|
@ -1621,9 +1944,11 @@ export function MovimentosPage() {
|
|||
|
||||
<Stack direction="row" flexWrap="wrap" spacing={1} useFlexGap>
|
||||
<Chip
|
||||
label={item.movimento}
|
||||
label={movimentoVisual}
|
||||
size="small"
|
||||
color={movimentoChipColor(item.movimento) as any}
|
||||
color={
|
||||
movimentoChipColor(movimentoVisual) as any
|
||||
}
|
||||
/>
|
||||
|
||||
<Chip
|
||||
|
|
@ -1749,7 +2074,8 @@ export function MovimentosPage() {
|
|||
{movimentos.map((item) => {
|
||||
const dataPrincipal = getDataPrincipal(item, dataCampo);
|
||||
const rowVisual = getMovimentoRowVisual(item);
|
||||
const movimentoIcon = getMovimentoIconVisual(item.movimento);
|
||||
const movimentoVisual = movimentoVisualLabel(item);
|
||||
const movimentoIcon = getMovimentoIconVisual(movimentoVisual);
|
||||
|
||||
return (
|
||||
<TableRow
|
||||
|
|
@ -1825,8 +2151,13 @@ export function MovimentosPage() {
|
|||
<Typography
|
||||
fontWeight={950}
|
||||
color={
|
||||
item.movimento === 'Entrada' || item.movimento === 'Estorno'
|
||||
movimentoEhTransferenciaInterna(item)
|
||||
? 'info.main'
|
||||
: movimentoEhEntrada(item)
|
||||
? 'success.main'
|
||||
: movimentoEhSaida(item)
|
||||
|| movimentoEhInvestimento(item)
|
||||
? 'error.main'
|
||||
: 'text.primary'
|
||||
}
|
||||
>
|
||||
|
|
@ -1853,9 +2184,11 @@ export function MovimentosPage() {
|
|||
|
||||
<TableCell>
|
||||
<Chip
|
||||
label={item.movimento}
|
||||
label={movimentoVisual}
|
||||
size="small"
|
||||
color={movimentoChipColor(item.movimento) as any}
|
||||
color={
|
||||
movimentoChipColor(movimentoVisual) as any
|
||||
}
|
||||
/>
|
||||
</TableCell>
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,15 @@ export type Movimento = {
|
|||
banco_referencia_debito?: number | null;
|
||||
movimento_fixo_descricao?: string | null;
|
||||
ocorrencia_extrato?: 'lancamento' | 'baixa' | null;
|
||||
|
||||
movimento_dashboard?: string;
|
||||
direcao_dashboard?: 'entrada' | 'saida' | 'transferencia_interna' | 'neutro';
|
||||
transferencia_interna?: boolean;
|
||||
investimento_dashboard?: boolean;
|
||||
|
||||
idusuario_origem?: number | null;
|
||||
idusuario_destino?: number | null;
|
||||
banco_destino_investimento?: number | null;
|
||||
};
|
||||
|
||||
export type CriarMovimentoRequest = {
|
||||
|
|
@ -115,14 +124,41 @@ export type MovimentosPagination = {
|
|||
|
||||
export type MovimentosSummary = {
|
||||
quantidade: number;
|
||||
|
||||
totalEntradas: number;
|
||||
entradasRecebidas: number;
|
||||
entradasPendentes: number;
|
||||
quantidadeEntradasRecebidas: number;
|
||||
quantidadeEntradasPendentes: number;
|
||||
percentualEntradasRecebidas: number;
|
||||
percentualEntradasPendentes: number;
|
||||
|
||||
totalSaidas: number;
|
||||
totalSangrias: number;
|
||||
saidasPagas: number;
|
||||
saidasPendentes: number;
|
||||
quantidadeSaidasPagas: number;
|
||||
quantidadeSaidasPendentes: number;
|
||||
percentualSaidasPagas: number;
|
||||
percentualSaidasPendentes: number;
|
||||
|
||||
totalInvestimentos: number;
|
||||
investimentosRealizados: number;
|
||||
investimentosPendentes: number;
|
||||
quantidadeInvestimentosRealizados: number;
|
||||
quantidadeInvestimentosPendentes: number;
|
||||
percentualInvestimentosRealizados: number;
|
||||
percentualInvestimentosPendentes: number;
|
||||
|
||||
totalEstornos: number;
|
||||
totalBaixado: number;
|
||||
totalAberto: number;
|
||||
saldoProcessado: number;
|
||||
saldo: number;
|
||||
|
||||
/*
|
||||
* Compatibilidade temporária com versões antigas da API.
|
||||
*/
|
||||
totalSangrias?: number;
|
||||
totalBaixado?: number;
|
||||
totalAberto?: number;
|
||||
};
|
||||
|
||||
export type ApiResponse<T> = {
|
||||
|
|
|
|||
Loading…
Reference in New Issue