adicionado tela de rendimentos e filtrado bancos por usuario
This commit is contained in:
parent
345d6033a8
commit
0731328492
|
|
@ -7,6 +7,7 @@ const referenciasRoutes = require('./modules/referencias/routes/referencias.rout
|
||||||
const relatoriosRoutes = require('./modules/relatorios/routes/relatorios.routes');
|
const relatoriosRoutes = require('./modules/relatorios/routes/relatorios.routes');
|
||||||
const clientesRoutes = require('./modules/clientes/routes/clientes.routes');
|
const clientesRoutes = require('./modules/clientes/routes/clientes.routes');
|
||||||
const bancosRoutes = require('./modules/bancos/routes/bancos.routes');
|
const bancosRoutes = require('./modules/bancos/routes/bancos.routes');
|
||||||
|
const bancosRendimentosRoutes = require('./modules/bancos/routes/bancosRendimentos.routes');
|
||||||
const centrosCustoRoutes = require('./modules/centrosCusto/routes/centrosCusto.routes');
|
const centrosCustoRoutes = require('./modules/centrosCusto/routes/centrosCusto.routes');
|
||||||
const movimentosFixosRoutes = require('./modules/movimentosFixos/routes/movimentosFixos.routes');
|
const movimentosFixosRoutes = require('./modules/movimentosFixos/routes/movimentosFixos.routes');
|
||||||
const usuariosRoutes = require('./modules/usuarios/routes/usuarios.routes');
|
const usuariosRoutes = require('./modules/usuarios/routes/usuarios.routes');
|
||||||
|
|
@ -41,6 +42,7 @@ app.use('/api/referencias', referenciasRoutes);
|
||||||
app.use('/api/relatorios', relatoriosRoutes);
|
app.use('/api/relatorios', relatoriosRoutes);
|
||||||
app.use('/api/clientes', clientesRoutes);
|
app.use('/api/clientes', clientesRoutes);
|
||||||
app.use('/api/bancos', bancosRoutes);
|
app.use('/api/bancos', bancosRoutes);
|
||||||
|
app.use('/api/bancos/rendimentos', bancosRendimentosRoutes);
|
||||||
app.use('/api/centros-custo', centrosCustoRoutes);
|
app.use('/api/centros-custo', centrosCustoRoutes);
|
||||||
app.use('/api/movimentos-fixos', movimentosFixosRoutes);
|
app.use('/api/movimentos-fixos', movimentosFixosRoutes);
|
||||||
app.use('/api/usuarios', usuariosRoutes);
|
app.use('/api/usuarios', usuariosRoutes);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,14 @@
|
||||||
const bancosService = require('../services/bancos.service');
|
const bancosService = require('../services/bancos.service');
|
||||||
|
|
||||||
function validarDadosBanco(dados) {
|
function validarDadosBanco(dados) {
|
||||||
|
if (dados.idusuarios !== undefined && dados.idusuarios !== null && dados.idusuarios !== '') {
|
||||||
|
const idusuarios = Number(dados.idusuarios);
|
||||||
|
|
||||||
|
if (!Number.isFinite(idusuarios)) {
|
||||||
|
return 'ID usuário inválido.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!dados.descricao || !String(dados.descricao).trim()) {
|
if (!dados.descricao || !String(dados.descricao).trim()) {
|
||||||
return 'Descrição é obrigatória.';
|
return 'Descrição é obrigatória.';
|
||||||
}
|
}
|
||||||
|
|
@ -21,6 +29,14 @@ function validarDadosBanco(dados) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dados.investimento !== undefined && dados.investimento !== null && dados.investimento !== '') {
|
||||||
|
const investimento = Number(dados.investimento);
|
||||||
|
|
||||||
|
if (![0, 1].includes(investimento)) {
|
||||||
|
return 'Tipo investimento inválido.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (dados.habilitado !== undefined && dados.habilitado !== null && dados.habilitado !== '') {
|
if (dados.habilitado !== undefined && dados.habilitado !== null && dados.habilitado !== '') {
|
||||||
const habilitado = Number(dados.habilitado);
|
const habilitado = Number(dados.habilitado);
|
||||||
|
|
||||||
|
|
@ -32,7 +48,7 @@ function validarDadosBanco(dados) {
|
||||||
if (dados.dia_vencimento !== undefined && dados.dia_vencimento !== null && dados.dia_vencimento !== '') {
|
if (dados.dia_vencimento !== undefined && dados.dia_vencimento !== null && dados.dia_vencimento !== '') {
|
||||||
const dia_vencimento = Number(dados.dia_vencimento);
|
const dia_vencimento = Number(dados.dia_vencimento);
|
||||||
|
|
||||||
if (!Number.isFinite(dia_vencimento) || dia_vencimento > 31) {
|
if (!Number.isFinite(dia_vencimento) || dia_vencimento < 1 || dia_vencimento > 31) {
|
||||||
return 'Dia de Vencimeneto inválido.';
|
return 'Dia de Vencimeneto inválido.';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -47,7 +63,9 @@ async function listar(req, res) {
|
||||||
offset: req.query.offset,
|
offset: req.query.offset,
|
||||||
page: req.query.page,
|
page: req.query.page,
|
||||||
busca: req.query.busca,
|
busca: req.query.busca,
|
||||||
|
idusuarios: req.user.id,
|
||||||
debito: req.query.debito,
|
debito: req.query.debito,
|
||||||
|
investimento: req.query.investimento,
|
||||||
dia_vencimento: req.query.dia_vencimento,
|
dia_vencimento: req.query.dia_vencimento,
|
||||||
habilitado: req.query.habilitado,
|
habilitado: req.query.habilitado,
|
||||||
orderBy: req.query.orderBy,
|
orderBy: req.query.orderBy,
|
||||||
|
|
@ -81,7 +99,7 @@ async function buscarPorId(req, res) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const banco = await bancosService.buscarBancoPorId(id);
|
const banco = await bancosService.buscarBancoPorId(id, req.user.id);
|
||||||
|
|
||||||
if (!banco) {
|
if (!banco) {
|
||||||
return res.status(404).json({
|
return res.status(404).json({
|
||||||
|
|
@ -115,7 +133,7 @@ async function criar(req, res) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const novoBanco = await bancosService.criarBanco(req.body);
|
const novoBanco = await bancosService.criarBanco(req.user.id, req.body);
|
||||||
|
|
||||||
return res.status(201).json({
|
return res.status(201).json({
|
||||||
ok: true,
|
ok: true,
|
||||||
|
|
@ -152,7 +170,7 @@ async function atualizar(req, res) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const bancoAtualizado = await bancosService.atualizarBanco(id, req.body);
|
const bancoAtualizado = await bancosService.atualizarBanco(id, req.user.id, req.body);
|
||||||
|
|
||||||
if (!bancoAtualizado) {
|
if (!bancoAtualizado) {
|
||||||
return res.status(404).json({
|
return res.status(404).json({
|
||||||
|
|
@ -196,7 +214,7 @@ async function alterarHabilitado(req, res) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const bancoAtualizado = await bancosService.alterarHabilitadoBanco(id, habilitado);
|
const bancoAtualizado = await bancosService.alterarHabilitadoBanco(id, req.user.id, habilitado);
|
||||||
|
|
||||||
if (!bancoAtualizado) {
|
if (!bancoAtualizado) {
|
||||||
return res.status(404).json({
|
return res.status(404).json({
|
||||||
|
|
@ -233,7 +251,7 @@ async function deletar(req, res) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const deletado = await bancosService.deletarBanco(id);
|
const deletado = await bancosService.deletarBanco(id, req.user.id);
|
||||||
|
|
||||||
if (!deletado) {
|
if (!deletado) {
|
||||||
return res.status(404).json({
|
return res.status(404).json({
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,128 @@
|
||||||
|
const bancosRendimentosService = require('../services/bancosRendimentos.service');
|
||||||
|
|
||||||
|
function resolverIdUsuario(req) {
|
||||||
|
return Number(req.user?.idusuarios || req.user?.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function dashboard(req, res) {
|
||||||
|
try {
|
||||||
|
const idusuarios = resolverIdUsuario(req);
|
||||||
|
|
||||||
|
if (!idusuarios) {
|
||||||
|
return res.status(401).json({
|
||||||
|
ok: false,
|
||||||
|
message: 'Usuário inválido.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const resultado = await bancosRendimentosService.buscarDashboard(idusuarios, {
|
||||||
|
periodoMeses: req.query.periodoMeses,
|
||||||
|
dataInicio: req.query.dataInicio,
|
||||||
|
dataFim: req.query.dataFim,
|
||||||
|
mesesProjecao: req.query.mesesProjecao,
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.json({
|
||||||
|
ok: true,
|
||||||
|
data: resultado,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erro ao buscar dashboard de rendimentos:', error);
|
||||||
|
|
||||||
|
return res.status(500).json({
|
||||||
|
ok: false,
|
||||||
|
message: 'Erro ao buscar dashboard de rendimentos.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function historico(req, res) {
|
||||||
|
try {
|
||||||
|
const idusuarios = resolverIdUsuario(req);
|
||||||
|
|
||||||
|
if (!idusuarios) {
|
||||||
|
return res.status(401).json({
|
||||||
|
ok: false,
|
||||||
|
message: 'Usuário inválido.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const resultado = await bancosRendimentosService.buscarHistorico(idusuarios, {
|
||||||
|
idbancos: req.query.idbancos,
|
||||||
|
periodoMeses: req.query.periodoMeses,
|
||||||
|
dataInicio: req.query.dataInicio,
|
||||||
|
dataFim: req.query.dataFim,
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.json({
|
||||||
|
ok: true,
|
||||||
|
data: resultado,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erro ao buscar histórico de rendimentos:', error);
|
||||||
|
|
||||||
|
return res.status(500).json({
|
||||||
|
ok: false,
|
||||||
|
message: 'Erro ao buscar histórico de rendimentos.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function computarRendimentos(req, res) {
|
||||||
|
try {
|
||||||
|
const idusuarios = resolverIdUsuario(req);
|
||||||
|
|
||||||
|
if (!idusuarios) {
|
||||||
|
return res.status(401).json({
|
||||||
|
ok: false,
|
||||||
|
message: 'Usuário inválido.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const itens = Array.isArray(req.body?.itens) ? req.body.itens : [];
|
||||||
|
|
||||||
|
if (itens.length === 0) {
|
||||||
|
return res.status(400).json({
|
||||||
|
ok: false,
|
||||||
|
message: 'Informe ao menos um rendimento para computar.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const resultado = await bancosRendimentosService.computarRendimentos(
|
||||||
|
idusuarios,
|
||||||
|
{
|
||||||
|
itens,
|
||||||
|
data: req.body?.data,
|
||||||
|
descricao: req.body?.descricao,
|
||||||
|
confirmarDuplicado: req.body?.confirmarDuplicado,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return res.status(201).json({
|
||||||
|
ok: true,
|
||||||
|
message: 'Rendimentos computados com sucesso.',
|
||||||
|
data: resultado,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erro ao computar rendimentos:', error);
|
||||||
|
|
||||||
|
if (error.code === 'DUPLICIDADE_MOVIMENTO') {
|
||||||
|
return res.status(409).json({
|
||||||
|
ok: false,
|
||||||
|
message: error.message,
|
||||||
|
data: error.data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.status(500).json({
|
||||||
|
ok: false,
|
||||||
|
message: 'Erro ao computar rendimentos.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
dashboard,
|
||||||
|
historico,
|
||||||
|
computarRendimentos,
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
const express = require('express');
|
||||||
|
const authMiddleware = require('../../../middlewares/auth.middleware');
|
||||||
|
const bancosRendimentosController = require('../controllers/bancosRendimentos.controller');
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
router.use(authMiddleware);
|
||||||
|
|
||||||
|
router.get('/dashboard', bancosRendimentosController.dashboard);
|
||||||
|
router.get('/historico', bancosRendimentosController.historico);
|
||||||
|
router.post('/computar', bancosRendimentosController.computarRendimentos);
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
|
|
@ -2,9 +2,11 @@ const pool = require('../../../database/mysql');
|
||||||
|
|
||||||
const CAMPOS_BANCO_SELECT = `
|
const CAMPOS_BANCO_SELECT = `
|
||||||
idbancos,
|
idbancos,
|
||||||
|
idusuarios,
|
||||||
descricao,
|
descricao,
|
||||||
saldo,
|
saldo,
|
||||||
debito,
|
debito,
|
||||||
|
investimento,
|
||||||
habilitado,
|
habilitado,
|
||||||
dia_vencimento,
|
dia_vencimento,
|
||||||
insert_date,
|
insert_date,
|
||||||
|
|
@ -53,10 +55,12 @@ function limitarNumero(valor, padrao, minimo, maximo) {
|
||||||
|
|
||||||
function resolverOrdenacao(orderBy) {
|
function resolverOrdenacao(orderBy) {
|
||||||
const camposPermitidos = {
|
const camposPermitidos = {
|
||||||
|
idusuarios: 'idusuarios',
|
||||||
idbancos: 'idbancos',
|
idbancos: 'idbancos',
|
||||||
descricao: 'descricao',
|
descricao: 'descricao',
|
||||||
saldo: 'saldo',
|
saldo: 'saldo',
|
||||||
debito: 'debito',
|
debito: 'debito',
|
||||||
|
investimento: 'investimento',
|
||||||
habilitado: 'habilitado',
|
habilitado: 'habilitado',
|
||||||
dia_vencimento: 'dia_vencimento',
|
dia_vencimento: 'dia_vencimento',
|
||||||
insert_date: 'insert_date',
|
insert_date: 'insert_date',
|
||||||
|
|
@ -74,11 +78,21 @@ function montarWhereBancos(filtros = {}) {
|
||||||
const where = [];
|
const where = [];
|
||||||
const params = [];
|
const params = [];
|
||||||
|
|
||||||
|
if (filtros.idusuarios !== undefined && filtros.idusuarios !== null && filtros.idusuarios !== '') {
|
||||||
|
where.push('idusuarios = ?');
|
||||||
|
params.push(Number(filtros.idusuarios));
|
||||||
|
}
|
||||||
|
|
||||||
if (filtros.debito !== undefined && filtros.debito !== null && filtros.debito !== '') {
|
if (filtros.debito !== undefined && filtros.debito !== null && filtros.debito !== '') {
|
||||||
where.push('debito = ?');
|
where.push('debito = ?');
|
||||||
params.push(Number(filtros.debito));
|
params.push(Number(filtros.debito));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (filtros.investimento !== undefined && filtros.investimento !== null && filtros.investimento !== '') {
|
||||||
|
where.push('investimento = ?');
|
||||||
|
params.push(Number(filtros.investimento));
|
||||||
|
}
|
||||||
|
|
||||||
if (filtros.habilitado !== undefined && filtros.habilitado !== null && filtros.habilitado !== '') {
|
if (filtros.habilitado !== undefined && filtros.habilitado !== null && filtros.habilitado !== '') {
|
||||||
where.push('habilitado = ?');
|
where.push('habilitado = ?');
|
||||||
params.push(Number(filtros.habilitado));
|
params.push(Number(filtros.habilitado));
|
||||||
|
|
@ -146,8 +160,9 @@ async function listarBancos(filtros = {}) {
|
||||||
SELECT
|
SELECT
|
||||||
COUNT(*) AS quantidade,
|
COUNT(*) AS quantidade,
|
||||||
COALESCE(SUM(saldo), 0) AS saldoTotal,
|
COALESCE(SUM(saldo), 0) AS saldoTotal,
|
||||||
COALESCE(SUM(CASE WHEN debito = 0 THEN saldo ELSE 0 END), 0) AS saldoCarteiras,
|
COALESCE(SUM(CASE WHEN debito = 0 THEN saldo ELSE 0 END), 0) AS saldoCredito,
|
||||||
COALESCE(SUM(CASE WHEN debito = 1 THEN saldo ELSE 0 END), 0) AS saldoDebito
|
COALESCE(SUM(CASE WHEN debito = 1 and investimento = 0 THEN saldo ELSE 0 END), 0) AS saldoDebito,
|
||||||
|
COALESCE(SUM(CASE WHEN debito = 1 and investimento = 1 THEN saldo ELSE 0 END), 0) AS saldoInvestimento
|
||||||
FROM bancos
|
FROM bancos
|
||||||
${whereSql}
|
${whereSql}
|
||||||
`,
|
`,
|
||||||
|
|
@ -169,32 +184,36 @@ async function listarBancos(filtros = {}) {
|
||||||
summary: {
|
summary: {
|
||||||
quantidade: Number(summaryRows[0]?.quantidade || 0),
|
quantidade: Number(summaryRows[0]?.quantidade || 0),
|
||||||
saldoTotal: Number(summaryRows[0]?.saldoTotal || 0),
|
saldoTotal: Number(summaryRows[0]?.saldoTotal || 0),
|
||||||
saldoCarteiras: Number(summaryRows[0]?.saldoCarteiras || 0),
|
saldoCredito: Number(summaryRows[0]?.saldoCredito || 0),
|
||||||
saldoDebito: Number(summaryRows[0]?.saldoDebito || 0),
|
saldoDebito: Number(summaryRows[0]?.saldoDebito || 0),
|
||||||
|
saldoInvestimento: Number(summaryRows[0]?.saldoInvestimento || 0),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buscarBancoPorId(id) {
|
async function buscarBancoPorId(id, idusuarios) {
|
||||||
const [rows] = await pool.query(
|
const [rows] = await pool.query(
|
||||||
`
|
`
|
||||||
SELECT
|
SELECT
|
||||||
${CAMPOS_BANCO_SELECT}
|
${CAMPOS_BANCO_SELECT}
|
||||||
FROM bancos
|
FROM bancos
|
||||||
WHERE idbancos = ?
|
WHERE idbancos = ?
|
||||||
|
AND idusuarios = ?
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
`,
|
`,
|
||||||
[id]
|
[id, idusuarios]
|
||||||
);
|
);
|
||||||
|
|
||||||
return rows[0] || null;
|
return rows[0] || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function criarBanco(dados) {
|
async function criarBanco(_idusuarios, dados) {
|
||||||
const {
|
const {
|
||||||
|
idusuarios,
|
||||||
descricao,
|
descricao,
|
||||||
saldo,
|
saldo,
|
||||||
debito,
|
debito,
|
||||||
|
investimento,
|
||||||
habilitado,
|
habilitado,
|
||||||
dia_vencimento,
|
dia_vencimento,
|
||||||
} = dados;
|
} = dados;
|
||||||
|
|
@ -202,19 +221,23 @@ async function criarBanco(dados) {
|
||||||
const [result] = await pool.query(
|
const [result] = await pool.query(
|
||||||
`
|
`
|
||||||
INSERT INTO bancos (
|
INSERT INTO bancos (
|
||||||
|
idusuarios,
|
||||||
descricao,
|
descricao,
|
||||||
saldo,
|
saldo,
|
||||||
debito,
|
debito,
|
||||||
|
investimento,
|
||||||
habilitado,
|
habilitado,
|
||||||
dia_vencimento,
|
dia_vencimento,
|
||||||
insert_date,
|
insert_date,
|
||||||
update_date
|
update_date
|
||||||
) VALUES (?, ?, ?, ?, ?, NOW(), NOW())
|
) VALUES (?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
|
||||||
`,
|
`,
|
||||||
[
|
[
|
||||||
|
normalizarNumero(_idusuarios, 0),
|
||||||
normalizarTextoOuNull(descricao),
|
normalizarTextoOuNull(descricao),
|
||||||
normalizarNumero(saldo, 0),
|
normalizarNumero(saldo, 0),
|
||||||
Number(debito || 0),
|
Number(debito || 0),
|
||||||
|
Number(investimento || 0),
|
||||||
habilitado === undefined || habilitado === null || habilitado === ''
|
habilitado === undefined || habilitado === null || habilitado === ''
|
||||||
? 1
|
? 1
|
||||||
: Number(habilitado),
|
: Number(habilitado),
|
||||||
|
|
@ -222,20 +245,22 @@ async function criarBanco(dados) {
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
return buscarBancoPorId(result.insertId);
|
return buscarBancoPorId(result.insertId, _idusuarios);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function atualizarBanco(id, dados) {
|
async function atualizarBanco(id, _idusuarios, dados) {
|
||||||
const bancoAtual = await buscarBancoPorId(id);
|
const bancoAtual = await buscarBancoPorId(id, _idusuarios);
|
||||||
|
|
||||||
if (!bancoAtual) {
|
if (!bancoAtual) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
idusuarios,
|
||||||
descricao,
|
descricao,
|
||||||
saldo,
|
saldo,
|
||||||
debito,
|
debito,
|
||||||
|
investimento,
|
||||||
habilitado,
|
habilitado,
|
||||||
dia_vencimento
|
dia_vencimento
|
||||||
} = dados;
|
} = dados;
|
||||||
|
|
@ -244,31 +269,37 @@ async function atualizarBanco(id, dados) {
|
||||||
`
|
`
|
||||||
UPDATE bancos
|
UPDATE bancos
|
||||||
SET
|
SET
|
||||||
|
idusuarios = ?,
|
||||||
descricao = ?,
|
descricao = ?,
|
||||||
saldo = ?,
|
saldo = ?,
|
||||||
debito = ?,
|
debito = ?,
|
||||||
|
investimento = ?,
|
||||||
habilitado = ?,
|
habilitado = ?,
|
||||||
dia_vencimento = ?,
|
dia_vencimento = ?,
|
||||||
update_date = NOW()
|
update_date = NOW()
|
||||||
WHERE idbancos = ?
|
WHERE idbancos = ?
|
||||||
|
AND idusuarios = ?
|
||||||
`,
|
`,
|
||||||
[
|
[
|
||||||
|
normalizarNumero(_idusuarios, 0),
|
||||||
normalizarTextoOuNull(descricao),
|
normalizarTextoOuNull(descricao),
|
||||||
normalizarNumero(saldo, 0),
|
normalizarNumero(saldo, 0),
|
||||||
Number(debito || 0),
|
Number(debito || 0),
|
||||||
|
Number(investimento || 0),
|
||||||
habilitado === undefined || habilitado === null || habilitado === ''
|
habilitado === undefined || habilitado === null || habilitado === ''
|
||||||
? 1
|
? 1
|
||||||
: Number(habilitado),
|
: Number(habilitado),
|
||||||
normalizarNumero(dia_vencimento, null),
|
normalizarNumero(dia_vencimento, null),
|
||||||
id
|
id,
|
||||||
|
_idusuarios
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
return buscarBancoPorId(id);
|
return buscarBancoPorId(id, _idusuarios);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function alterarHabilitadoBanco(id, habilitado) {
|
async function alterarHabilitadoBanco(id, idusuarios, habilitado) {
|
||||||
const bancoAtual = await buscarBancoPorId(id);
|
const bancoAtual = await buscarBancoPorId(id, idusuarios);
|
||||||
|
|
||||||
if (!bancoAtual) {
|
if (!bancoAtual) {
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -281,18 +312,20 @@ async function alterarHabilitadoBanco(id, habilitado) {
|
||||||
habilitado = ?,
|
habilitado = ?,
|
||||||
update_date = NOW()
|
update_date = NOW()
|
||||||
WHERE idbancos = ?
|
WHERE idbancos = ?
|
||||||
|
AND idusuarios = ?
|
||||||
`,
|
`,
|
||||||
[
|
[
|
||||||
Number(habilitado),
|
Number(habilitado),
|
||||||
id,
|
id,
|
||||||
|
idusuarios
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
return buscarBancoPorId(id);
|
return buscarBancoPorId(id, idusuarios);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deletarBanco(id) {
|
async function deletarBanco(id, idusuarios) {
|
||||||
const bancoAtual = await buscarBancoPorId(id);
|
const bancoAtual = await buscarBancoPorId(id, idusuarios);
|
||||||
|
|
||||||
if (!bancoAtual) {
|
if (!bancoAtual) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -302,8 +335,9 @@ async function deletarBanco(id) {
|
||||||
`
|
`
|
||||||
DELETE FROM bancos
|
DELETE FROM bancos
|
||||||
WHERE idbancos = ?
|
WHERE idbancos = ?
|
||||||
|
AND idusuarios = ?
|
||||||
`,
|
`,
|
||||||
[id]
|
[id, idusuarios]
|
||||||
);
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,726 @@
|
||||||
|
const pool = require('../../../database/mysql');
|
||||||
|
const movimentosService = require('../../movimentos/services/movimentos.service');
|
||||||
|
|
||||||
|
const ID_CENTRO_CUSTO_RENDIMENTO = 33;
|
||||||
|
const ORIGEM_RENDIMENTO = 'rendimento_investimento';
|
||||||
|
|
||||||
|
function hojeDataString() {
|
||||||
|
return new Date().toISOString().slice(0, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
function extrairCompetencia(data) {
|
||||||
|
return String(data || hojeDataString()).slice(0, 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
function limitarNumero(valor, padrao, minimo, maximo) {
|
||||||
|
const numero = Number(valor);
|
||||||
|
|
||||||
|
if (!Number.isFinite(numero)) {
|
||||||
|
return padrao;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numero < minimo) return minimo;
|
||||||
|
if (numero > maximo) return maximo;
|
||||||
|
|
||||||
|
return numero;
|
||||||
|
}
|
||||||
|
|
||||||
|
function arredondar2(valor) {
|
||||||
|
return Number(Number(valor || 0).toFixed(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
function calcularPercentual(delta, base) {
|
||||||
|
const valorBase = Number(base || 0);
|
||||||
|
|
||||||
|
if (!valorBase) return 0;
|
||||||
|
|
||||||
|
return Number(((Number(delta || 0) / valorBase) * 100).toFixed(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolverPeriodo(filtros = {}) {
|
||||||
|
const periodoMeses = limitarNumero(filtros.periodoMeses, 12, 1, 60);
|
||||||
|
|
||||||
|
const hoje = new Date();
|
||||||
|
const dataFim = filtros.dataFim || hoje.toISOString().slice(0, 10);
|
||||||
|
|
||||||
|
const dataInicioObj = new Date(hoje.getFullYear(), hoje.getMonth() - periodoMeses + 1, 1);
|
||||||
|
const dataInicioPadrao = dataInicioObj.toISOString().slice(0, 10);
|
||||||
|
|
||||||
|
return {
|
||||||
|
dataInicio: filtros.dataInicio || dataInicioPadrao,
|
||||||
|
dataFim,
|
||||||
|
periodoMeses,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function listarBancosInvestimento(idusuarios) {
|
||||||
|
const [rows] = await pool.query(
|
||||||
|
`
|
||||||
|
SELECT
|
||||||
|
idbancos,
|
||||||
|
descricao,
|
||||||
|
saldo,
|
||||||
|
debito,
|
||||||
|
investimento,
|
||||||
|
habilitado,
|
||||||
|
update_date
|
||||||
|
FROM bancos
|
||||||
|
WHERE idusuarios = ?
|
||||||
|
AND investimento = 1
|
||||||
|
AND habilitado = 1
|
||||||
|
ORDER BY descricao ASC
|
||||||
|
`,
|
||||||
|
[idusuarios]
|
||||||
|
);
|
||||||
|
|
||||||
|
return rows.map((item) => ({
|
||||||
|
...item,
|
||||||
|
saldo: Number(item.saldo || 0),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function buscarBancoInvestimento(idusuarios, idbancos) {
|
||||||
|
const [rows] = await pool.query(
|
||||||
|
`
|
||||||
|
SELECT
|
||||||
|
idbancos,
|
||||||
|
descricao,
|
||||||
|
saldo,
|
||||||
|
debito,
|
||||||
|
investimento,
|
||||||
|
habilitado,
|
||||||
|
update_date
|
||||||
|
FROM bancos
|
||||||
|
WHERE idbancos = ?
|
||||||
|
AND idusuarios = ?
|
||||||
|
AND investimento = 1
|
||||||
|
AND habilitado = 1
|
||||||
|
LIMIT 1
|
||||||
|
`,
|
||||||
|
[idbancos, idusuarios]
|
||||||
|
);
|
||||||
|
|
||||||
|
return rows[0] || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function buscarUltimasApuracoes(idusuarios) {
|
||||||
|
const [rows] = await pool.query(
|
||||||
|
`
|
||||||
|
SELECT
|
||||||
|
bsa.idbancos,
|
||||||
|
MAX(bsa.insert_date) AS ultima_apuracao
|
||||||
|
FROM bancos_saldo_auditoria bsa
|
||||||
|
INNER JOIN bancos b ON b.idbancos = bsa.idbancos
|
||||||
|
WHERE bsa.idusuarios = ?
|
||||||
|
AND b.idusuarios = ?
|
||||||
|
AND b.investimento = 1
|
||||||
|
AND bsa.origem = ?
|
||||||
|
GROUP BY bsa.idbancos
|
||||||
|
`,
|
||||||
|
[idusuarios, idusuarios, ORIGEM_RENDIMENTO]
|
||||||
|
);
|
||||||
|
|
||||||
|
const mapa = new Map();
|
||||||
|
|
||||||
|
rows.forEach((row) => {
|
||||||
|
mapa.set(Number(row.idbancos), row.ultima_apuracao);
|
||||||
|
});
|
||||||
|
|
||||||
|
return mapa;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function buscarHistorico(idusuarios, filtros = {}) {
|
||||||
|
const { dataInicio, dataFim } = resolverPeriodo(filtros);
|
||||||
|
|
||||||
|
const params = [
|
||||||
|
idusuarios,
|
||||||
|
idusuarios,
|
||||||
|
ORIGEM_RENDIMENTO,
|
||||||
|
dataInicio,
|
||||||
|
dataFim,
|
||||||
|
];
|
||||||
|
|
||||||
|
let filtroBanco = '';
|
||||||
|
|
||||||
|
if (filtros.idbancos) {
|
||||||
|
filtroBanco = 'AND bsa.idbancos = ?';
|
||||||
|
params.push(Number(filtros.idbancos));
|
||||||
|
}
|
||||||
|
|
||||||
|
const [rows] = await pool.query(
|
||||||
|
`
|
||||||
|
SELECT
|
||||||
|
bsa.idbancossaldoauditoria,
|
||||||
|
bsa.idbancos,
|
||||||
|
b.descricao AS banco_descricao,
|
||||||
|
bsa.idcontasapagar,
|
||||||
|
bsa.tipo_operacao,
|
||||||
|
bsa.origem,
|
||||||
|
bsa.valor_delta,
|
||||||
|
bsa.saldo_anterior,
|
||||||
|
bsa.saldo_posterior,
|
||||||
|
bsa.descricao,
|
||||||
|
bsa.insert_date
|
||||||
|
FROM bancos_saldo_auditoria bsa
|
||||||
|
INNER JOIN bancos b ON b.idbancos = bsa.idbancos
|
||||||
|
WHERE bsa.idusuarios = ?
|
||||||
|
AND b.idusuarios = ?
|
||||||
|
AND b.investimento = 1
|
||||||
|
AND bsa.origem = ?
|
||||||
|
AND DATE(bsa.insert_date) >= ?
|
||||||
|
AND DATE(bsa.insert_date) <= ?
|
||||||
|
${filtroBanco}
|
||||||
|
ORDER BY bsa.insert_date ASC, bsa.idbancossaldoauditoria ASC
|
||||||
|
`,
|
||||||
|
params
|
||||||
|
);
|
||||||
|
|
||||||
|
return rows.map((row) => ({
|
||||||
|
...row,
|
||||||
|
valor_delta: Number(row.valor_delta || 0),
|
||||||
|
saldo_anterior: Number(row.saldo_anterior || 0),
|
||||||
|
saldo_posterior: Number(row.saldo_posterior || 0),
|
||||||
|
percentual: calcularPercentual(row.valor_delta, row.saldo_anterior),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function montarSeriesMensais(historico) {
|
||||||
|
const porBancoMes = new Map();
|
||||||
|
|
||||||
|
historico.forEach((item) => {
|
||||||
|
const mes = String(item.insert_date).slice(0, 7);
|
||||||
|
const chave = `${item.idbancos}|${mes}`;
|
||||||
|
|
||||||
|
if (!porBancoMes.has(chave)) {
|
||||||
|
porBancoMes.set(chave, {
|
||||||
|
idbancos: item.idbancos,
|
||||||
|
banco_descricao: item.banco_descricao,
|
||||||
|
competencia: mes,
|
||||||
|
rendimento: 0,
|
||||||
|
saldo_final: Number(item.saldo_posterior || 0),
|
||||||
|
eventos: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const atual = porBancoMes.get(chave);
|
||||||
|
|
||||||
|
atual.rendimento = arredondar2(atual.rendimento + Number(item.valor_delta || 0));
|
||||||
|
atual.saldo_final = Number(item.saldo_posterior || atual.saldo_final || 0);
|
||||||
|
atual.eventos += 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
return Array.from(porBancoMes.values()).sort((a, b) => {
|
||||||
|
if (a.competencia === b.competencia) {
|
||||||
|
return String(a.banco_descricao).localeCompare(String(b.banco_descricao));
|
||||||
|
}
|
||||||
|
|
||||||
|
return String(a.competencia).localeCompare(String(b.competencia));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function montarResumo(bancos, historico, ranking = [], projecao = null) {
|
||||||
|
const totalInvestidoAtual = bancos.reduce(
|
||||||
|
(acc, banco) => acc + Number(banco.saldo || 0),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
const rendimentoPeriodo = historico.reduce(
|
||||||
|
(acc, item) => acc + Number(item.valor_delta || 0),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
const positivos = historico.filter((item) => Number(item.valor_delta || 0) > 0);
|
||||||
|
|
||||||
|
const rendimentoMedioPercentual = positivos.length
|
||||||
|
? positivos.reduce((acc, item) => acc + Number(item.percentual || 0), 0) / positivos.length
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
const melhorBanco = ranking[0] || null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
totalInvestidoAtual: arredondar2(totalInvestidoAtual),
|
||||||
|
rendimentoPeriodo: arredondar2(rendimentoPeriodo),
|
||||||
|
rendimentoMedioPercentual: Number(rendimentoMedioPercentual.toFixed(4)),
|
||||||
|
quantidadeBancos: bancos.length,
|
||||||
|
melhorBanco,
|
||||||
|
projecao12Meses: projecao
|
||||||
|
? {
|
||||||
|
saldoProjetado: projecao.saldo_projetado_total,
|
||||||
|
rendimentoProjetado: projecao.rendimento_projetado_total,
|
||||||
|
taxaMediaMensal: projecao.taxa_media_mensal_total,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function agruparRendimentoPorBanco(historico) {
|
||||||
|
const mapa = new Map();
|
||||||
|
|
||||||
|
historico.forEach((item) => {
|
||||||
|
const idbancos = Number(item.idbancos);
|
||||||
|
const valorDelta = Number(item.valor_delta || 0);
|
||||||
|
const percentual = Number(item.percentual || 0);
|
||||||
|
|
||||||
|
if (!mapa.has(idbancos)) {
|
||||||
|
mapa.set(idbancos, {
|
||||||
|
idbancos,
|
||||||
|
banco_descricao: item.banco_descricao,
|
||||||
|
rendimento_total: 0,
|
||||||
|
quantidade_eventos: 0,
|
||||||
|
soma_percentual: 0,
|
||||||
|
maior_rendimento: null,
|
||||||
|
menor_rendimento: null,
|
||||||
|
primeira_data: item.insert_date,
|
||||||
|
ultima_data: item.insert_date,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const atual = mapa.get(idbancos);
|
||||||
|
|
||||||
|
atual.rendimento_total = arredondar2(atual.rendimento_total + valorDelta);
|
||||||
|
atual.quantidade_eventos += 1;
|
||||||
|
atual.soma_percentual += percentual;
|
||||||
|
|
||||||
|
if (!atual.maior_rendimento || valorDelta > Number(atual.maior_rendimento.valor_delta || 0)) {
|
||||||
|
atual.maior_rendimento = {
|
||||||
|
valor_delta: valorDelta,
|
||||||
|
percentual,
|
||||||
|
insert_date: item.insert_date,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!atual.menor_rendimento || valorDelta < Number(atual.menor_rendimento.valor_delta || 0)) {
|
||||||
|
atual.menor_rendimento = {
|
||||||
|
valor_delta: valorDelta,
|
||||||
|
percentual,
|
||||||
|
insert_date: item.insert_date,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (String(item.insert_date) < String(atual.primeira_data)) {
|
||||||
|
atual.primeira_data = item.insert_date;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (String(item.insert_date) > String(atual.ultima_data)) {
|
||||||
|
atual.ultima_data = item.insert_date;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Array.from(mapa.values()).map((item) => ({
|
||||||
|
...item,
|
||||||
|
percentual_medio: item.quantidade_eventos > 0
|
||||||
|
? Number((item.soma_percentual / item.quantidade_eventos).toFixed(4))
|
||||||
|
: 0,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function montarRanking(bancos, historico) {
|
||||||
|
const agrupado = agruparRendimentoPorBanco(historico);
|
||||||
|
|
||||||
|
const saldoPorBanco = new Map();
|
||||||
|
|
||||||
|
bancos.forEach((banco) => {
|
||||||
|
saldoPorBanco.set(Number(banco.idbancos), Number(banco.saldo || 0));
|
||||||
|
});
|
||||||
|
|
||||||
|
const ranking = agrupado.map((item) => {
|
||||||
|
const saldoAtual = saldoPorBanco.get(Number(item.idbancos)) || 0;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
saldo_atual: arredondar2(saldoAtual),
|
||||||
|
participacao_rendimento: 0,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const totalRendimento = ranking.reduce(
|
||||||
|
(acc, item) => acc + Number(item.rendimento_total || 0),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
return ranking
|
||||||
|
.map((item) => ({
|
||||||
|
...item,
|
||||||
|
participacao_rendimento: totalRendimento
|
||||||
|
? Number(((Number(item.rendimento_total || 0) / totalRendimento) * 100).toFixed(4))
|
||||||
|
: 0,
|
||||||
|
}))
|
||||||
|
.sort((a, b) => Number(b.rendimento_total || 0) - Number(a.rendimento_total || 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
function montarGraficoBarrasMensal(seriesMensais) {
|
||||||
|
const mapa = new Map();
|
||||||
|
|
||||||
|
seriesMensais.forEach((item) => {
|
||||||
|
const competencia = item.competencia;
|
||||||
|
|
||||||
|
if (!mapa.has(competencia)) {
|
||||||
|
mapa.set(competencia, {
|
||||||
|
competencia,
|
||||||
|
total: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const row = mapa.get(competencia);
|
||||||
|
const nomeBanco = item.banco_descricao;
|
||||||
|
|
||||||
|
row[nomeBanco] = arredondar2(Number(row[nomeBanco] || 0) + Number(item.rendimento || 0));
|
||||||
|
row.total = arredondar2(Number(row.total || 0) + Number(item.rendimento || 0));
|
||||||
|
});
|
||||||
|
|
||||||
|
return Array.from(mapa.values()).sort((a, b) =>
|
||||||
|
String(a.competencia).localeCompare(String(b.competencia))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function montarGraficoSaldoMensal(seriesMensais) {
|
||||||
|
const mapa = new Map();
|
||||||
|
|
||||||
|
seriesMensais.forEach((item) => {
|
||||||
|
const competencia = item.competencia;
|
||||||
|
|
||||||
|
if (!mapa.has(competencia)) {
|
||||||
|
mapa.set(competencia, {
|
||||||
|
competencia,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const row = mapa.get(competencia);
|
||||||
|
row[item.banco_descricao] = Number(item.saldo_final || 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Array.from(mapa.values()).sort((a, b) =>
|
||||||
|
String(a.competencia).localeCompare(String(b.competencia))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function montarGraficoRendimentoAcumulado(seriesMensais) {
|
||||||
|
const bancos = Array.from(
|
||||||
|
new Set(seriesMensais.map((item) => item.banco_descricao))
|
||||||
|
);
|
||||||
|
|
||||||
|
const competencias = Array.from(
|
||||||
|
new Set(seriesMensais.map((item) => item.competencia))
|
||||||
|
).sort();
|
||||||
|
|
||||||
|
const acumuladoPorBanco = new Map();
|
||||||
|
|
||||||
|
bancos.forEach((nomeBanco) => {
|
||||||
|
acumuladoPorBanco.set(nomeBanco, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
return competencias.map((competencia) => {
|
||||||
|
const row = {
|
||||||
|
competencia,
|
||||||
|
total: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
bancos.forEach((nomeBanco) => {
|
||||||
|
const item = seriesMensais.find(
|
||||||
|
(serie) =>
|
||||||
|
serie.competencia === competencia &&
|
||||||
|
serie.banco_descricao === nomeBanco
|
||||||
|
);
|
||||||
|
|
||||||
|
const rendimentoMes = item ? Number(item.rendimento || 0) : 0;
|
||||||
|
const novoAcumulado = Number(acumuladoPorBanco.get(nomeBanco) || 0) + rendimentoMes;
|
||||||
|
|
||||||
|
acumuladoPorBanco.set(nomeBanco, arredondar2(novoAcumulado));
|
||||||
|
row[nomeBanco] = arredondar2(novoAcumulado);
|
||||||
|
row.total = arredondar2(Number(row.total || 0) + novoAcumulado);
|
||||||
|
});
|
||||||
|
|
||||||
|
return row;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function calcularMesesEntreDatas(dataInicio, dataFim) {
|
||||||
|
if (!dataInicio || !dataFim) return 0;
|
||||||
|
|
||||||
|
const inicio = new Date(dataInicio);
|
||||||
|
const fim = new Date(dataFim);
|
||||||
|
|
||||||
|
if (Number.isNaN(inicio.getTime()) || Number.isNaN(fim.getTime())) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const anos = fim.getFullYear() - inicio.getFullYear();
|
||||||
|
const meses = fim.getMonth() - inicio.getMonth();
|
||||||
|
|
||||||
|
return Math.max(1, anos * 12 + meses + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function montarProjecao(bancos, seriesMensais, mesesProjetar = 12) {
|
||||||
|
const resultadoPorBanco = [];
|
||||||
|
|
||||||
|
bancos.forEach((banco) => {
|
||||||
|
const seriesBanco = seriesMensais
|
||||||
|
.filter((item) => Number(item.idbancos) === Number(banco.idbancos))
|
||||||
|
.sort((a, b) => String(a.competencia).localeCompare(String(b.competencia)));
|
||||||
|
|
||||||
|
const ultimasSeries = seriesBanco.slice(-6);
|
||||||
|
|
||||||
|
const rendimentosValidos = ultimasSeries.filter(
|
||||||
|
(item) => Number(item.saldo_final || 0) > 0
|
||||||
|
);
|
||||||
|
|
||||||
|
const taxasMensais = rendimentosValidos.map((item) => {
|
||||||
|
const saldoFinal = Number(item.saldo_final || 0);
|
||||||
|
const rendimento = Number(item.rendimento || 0);
|
||||||
|
const saldoBase = saldoFinal - rendimento;
|
||||||
|
|
||||||
|
if (saldoBase <= 0) return 0;
|
||||||
|
|
||||||
|
return rendimento / saldoBase;
|
||||||
|
});
|
||||||
|
|
||||||
|
const taxaMediaMensal = taxasMensais.length
|
||||||
|
? taxasMensais.reduce((acc, taxa) => acc + taxa, 0) / taxasMensais.length
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
const saldoAtual = Number(banco.saldo || 0);
|
||||||
|
const saldoProjetado = saldoAtual * Math.pow(1 + taxaMediaMensal, mesesProjetar);
|
||||||
|
const rendimentoProjetado = saldoProjetado - saldoAtual;
|
||||||
|
|
||||||
|
resultadoPorBanco.push({
|
||||||
|
idbancos: banco.idbancos,
|
||||||
|
banco_descricao: banco.descricao,
|
||||||
|
saldo_atual: arredondar2(saldoAtual),
|
||||||
|
taxa_media_mensal: Number((taxaMediaMensal * 100).toFixed(4)),
|
||||||
|
meses_base: taxasMensais.length,
|
||||||
|
meses_projecao: mesesProjetar,
|
||||||
|
saldo_projetado: arredondar2(saldoProjetado),
|
||||||
|
rendimento_projetado: arredondar2(rendimentoProjetado),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const saldoAtualTotal = resultadoPorBanco.reduce(
|
||||||
|
(acc, item) => acc + Number(item.saldo_atual || 0),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
const saldoProjetadoTotal = resultadoPorBanco.reduce(
|
||||||
|
(acc, item) => acc + Number(item.saldo_projetado || 0),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
const rendimentoProjetadoTotal = saldoProjetadoTotal - saldoAtualTotal;
|
||||||
|
|
||||||
|
return {
|
||||||
|
meses_projecao: mesesProjetar,
|
||||||
|
saldo_atual_total: arredondar2(saldoAtualTotal),
|
||||||
|
saldo_projetado_total: arredondar2(saldoProjetadoTotal),
|
||||||
|
rendimento_projetado_total: arredondar2(rendimentoProjetadoTotal),
|
||||||
|
taxa_media_mensal_total: saldoAtualTotal
|
||||||
|
? Number(((Math.pow(saldoProjetadoTotal / saldoAtualTotal, 1 / mesesProjetar) - 1) * 100).toFixed(4))
|
||||||
|
: 0,
|
||||||
|
bancos: resultadoPorBanco.sort((a, b) =>
|
||||||
|
Number(b.rendimento_projetado || 0) - Number(a.rendimento_projetado || 0)
|
||||||
|
),
|
||||||
|
observacao: 'Projeção estimada com base no histórico recente de rendimentos. Não representa garantia de rendimento futuro.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function buscarDashboard(idusuarios, filtros = {}) {
|
||||||
|
const bancos = await listarBancosInvestimento(idusuarios);
|
||||||
|
const ultimasApuracoes = await buscarUltimasApuracoes(idusuarios);
|
||||||
|
const historico = await buscarHistorico(idusuarios, filtros);
|
||||||
|
const seriesMensais = montarSeriesMensais(historico);
|
||||||
|
|
||||||
|
const mesesProjecao = limitarNumero(filtros.mesesProjecao, 12, 1, 60);
|
||||||
|
|
||||||
|
const ranking = montarRanking(bancos, historico);
|
||||||
|
const projecao = montarProjecao(bancos, seriesMensais, mesesProjecao);
|
||||||
|
|
||||||
|
const graficos = {
|
||||||
|
barrasMensal: montarGraficoBarrasMensal(seriesMensais),
|
||||||
|
saldoMensal: montarGraficoSaldoMensal(seriesMensais),
|
||||||
|
rendimentoAcumulado: montarGraficoRendimentoAcumulado(seriesMensais),
|
||||||
|
};
|
||||||
|
|
||||||
|
const resumo = montarResumo(bancos, historico, ranking, projecao);
|
||||||
|
|
||||||
|
const bancosComMetricas = bancos.map((banco) => {
|
||||||
|
const rankingBanco = ranking.find(
|
||||||
|
(item) => Number(item.idbancos) === Number(banco.idbancos)
|
||||||
|
);
|
||||||
|
|
||||||
|
const projecaoBanco = projecao.bancos.find(
|
||||||
|
(item) => Number(item.idbancos) === Number(banco.idbancos)
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...banco,
|
||||||
|
ultima_apuracao: ultimasApuracoes.get(Number(banco.idbancos)) || null,
|
||||||
|
rendimento_periodo: rankingBanco?.rendimento_total || 0,
|
||||||
|
percentual_medio_periodo: rankingBanco?.percentual_medio || 0,
|
||||||
|
projecao: projecaoBanco || null,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
resumo,
|
||||||
|
bancos: bancosComMetricas,
|
||||||
|
historico,
|
||||||
|
seriesMensais,
|
||||||
|
ranking,
|
||||||
|
projecao,
|
||||||
|
graficos,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function validarItemComputar(item) {
|
||||||
|
const idbancos = Number(item.idbancos);
|
||||||
|
const novoSaldo = Number(item.novoSaldo);
|
||||||
|
|
||||||
|
if (!Number.isFinite(idbancos) || idbancos <= 0) {
|
||||||
|
return 'Banco inválido.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Number.isFinite(novoSaldo)) {
|
||||||
|
return 'Novo saldo inválido.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (novoSaldo < 0) {
|
||||||
|
return 'Novo saldo não pode ser negativo.';
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function computarRendimentoBanco(idusuarios, item, opcoes = {}) {
|
||||||
|
const erro = validarItemComputar(item);
|
||||||
|
|
||||||
|
if (erro) {
|
||||||
|
return {
|
||||||
|
ok: false,
|
||||||
|
idbancos: item.idbancos,
|
||||||
|
message: erro,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const idbancos = Number(item.idbancos);
|
||||||
|
const novoSaldo = arredondar2(item.novoSaldo);
|
||||||
|
|
||||||
|
const banco = await buscarBancoInvestimento(idusuarios, idbancos);
|
||||||
|
|
||||||
|
if (!banco) {
|
||||||
|
return {
|
||||||
|
ok: false,
|
||||||
|
idbancos,
|
||||||
|
message: 'Banco de investimento não encontrado para este usuário.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const saldoAnterior = arredondar2(banco.saldo);
|
||||||
|
const valorDelta = arredondar2(novoSaldo - saldoAnterior);
|
||||||
|
|
||||||
|
if (valorDelta === 0) {
|
||||||
|
return {
|
||||||
|
ok: true,
|
||||||
|
ignorado: true,
|
||||||
|
idbancos,
|
||||||
|
banco_descricao: banco.descricao,
|
||||||
|
saldo_anterior: saldoAnterior,
|
||||||
|
saldo_posterior: novoSaldo,
|
||||||
|
valor_delta: 0,
|
||||||
|
percentual: 0,
|
||||||
|
message: 'Sem alteração de saldo.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valorDelta < 0) {
|
||||||
|
return {
|
||||||
|
ok: false,
|
||||||
|
idbancos,
|
||||||
|
banco_descricao: banco.descricao,
|
||||||
|
saldo_anterior: saldoAnterior,
|
||||||
|
saldo_posterior: novoSaldo,
|
||||||
|
valor_delta: valorDelta,
|
||||||
|
percentual: calcularPercentual(valorDelta, saldoAnterior),
|
||||||
|
message: 'O novo saldo é menor que o saldo atual. Para rendimento, informe apenas crescimento positivo.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = opcoes.data || hojeDataString();
|
||||||
|
|
||||||
|
const descricaoBase = item.descricao
|
||||||
|
|| opcoes.descricao
|
||||||
|
|| `Rendimento de investimento - ${banco.descricao}`;
|
||||||
|
|
||||||
|
const movimento = await movimentosService.criarMovimento(idusuarios, {
|
||||||
|
movimento: 'Entrada',
|
||||||
|
descricao: descricaoBase,
|
||||||
|
dataentrada: data,
|
||||||
|
datavencimento: data,
|
||||||
|
databaixa: data,
|
||||||
|
valor: valorDelta,
|
||||||
|
parcela: 1,
|
||||||
|
parcelas: 1,
|
||||||
|
status: 'Recebido',
|
||||||
|
idcentrodecustos: ID_CENTRO_CUSTO_RENDIMENTO,
|
||||||
|
idbancos,
|
||||||
|
idclientes: null,
|
||||||
|
idveiculosdetalhes: null,
|
||||||
|
idbancos_p: null,
|
||||||
|
idmovimentosfixos: null,
|
||||||
|
competencia: extrairCompetencia(data),
|
||||||
|
origem: ORIGEM_RENDIMENTO,
|
||||||
|
saldo_processado: 0,
|
||||||
|
observacao: `Saldo anterior: ${saldoAnterior}. Novo saldo informado: ${novoSaldo}.`,
|
||||||
|
confirmarDuplicado: opcoes.confirmarDuplicado === true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
ok: true,
|
||||||
|
idbancos,
|
||||||
|
banco_descricao: banco.descricao,
|
||||||
|
saldo_anterior: saldoAnterior,
|
||||||
|
saldo_posterior: novoSaldo,
|
||||||
|
valor_delta: valorDelta,
|
||||||
|
percentual: calcularPercentual(valorDelta, saldoAnterior),
|
||||||
|
movimento: movimento.data,
|
||||||
|
impactoSaldo: movimento.impactoSaldo || [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function computarRendimentos(idusuarios, dados = {}) {
|
||||||
|
const itens = Array.isArray(dados.itens) ? dados.itens : [];
|
||||||
|
|
||||||
|
const resultados = [];
|
||||||
|
|
||||||
|
for (const item of itens) {
|
||||||
|
const resultado = await computarRendimentoBanco(idusuarios, item, {
|
||||||
|
data: dados.data,
|
||||||
|
descricao: dados.descricao,
|
||||||
|
confirmarDuplicado: dados.confirmarDuplicado,
|
||||||
|
});
|
||||||
|
|
||||||
|
resultados.push(resultado);
|
||||||
|
}
|
||||||
|
|
||||||
|
const processados = resultados.filter((item) => item.ok && !item.ignorado);
|
||||||
|
const ignorados = resultados.filter((item) => item.ok && item.ignorado);
|
||||||
|
const erros = resultados.filter((item) => !item.ok);
|
||||||
|
|
||||||
|
return {
|
||||||
|
processados,
|
||||||
|
ignorados,
|
||||||
|
erros,
|
||||||
|
resumo: {
|
||||||
|
quantidadeProcessada: processados.length,
|
||||||
|
quantidadeIgnorada: ignorados.length,
|
||||||
|
quantidadeErro: erros.length,
|
||||||
|
totalRendimento: arredondar2(
|
||||||
|
processados.reduce((acc, item) => acc + Number(item.valor_delta || 0), 0)
|
||||||
|
),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
buscarDashboard,
|
||||||
|
buscarHistorico,
|
||||||
|
computarRendimentos,
|
||||||
|
};
|
||||||
|
|
@ -1,8 +1,21 @@
|
||||||
const dashboardService = require('../services/dashboard.service');
|
const dashboardService = require('../services/dashboard.service');
|
||||||
|
|
||||||
|
function resolverIdUsuario(req) {
|
||||||
|
return Number(req.user?.idusuarios || req.user?.id);
|
||||||
|
}
|
||||||
|
|
||||||
async function buscarResumo(req, res) {
|
async function buscarResumo(req, res) {
|
||||||
try {
|
try {
|
||||||
const resultado = await dashboardService.buscarResumoDashboard({
|
const idUsuario = resolverIdUsuario(req);
|
||||||
|
|
||||||
|
if (!idUsuario) {
|
||||||
|
return res.status(401).json({
|
||||||
|
ok: false,
|
||||||
|
message: 'Usuário inválido.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const resultado = await dashboardService.buscarResumoDashboard(idUsuario, {
|
||||||
dataInicio: req.query.dataInicio,
|
dataInicio: req.query.dataInicio,
|
||||||
dataFim: req.query.dataFim,
|
dataFim: req.query.dataFim,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -52,27 +52,95 @@ function calcularPercentual(valor, base) {
|
||||||
return (valorNormalizado / baseNormalizada) * 100;
|
return (valorNormalizado / baseNormalizada) * 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buscarCardsBancos() {
|
async function buscarCardsBancos(idUsuario) {
|
||||||
const [rows] = await pool.query(`
|
const [rows] = await pool.query(
|
||||||
|
`
|
||||||
SELECT
|
SELECT
|
||||||
COALESCE(SUM(CASE WHEN debito = 1 THEN saldo ELSE 0 END), 0) AS saldoDebito,
|
COALESCE(SUM(CASE
|
||||||
COALESCE(SUM(CASE WHEN debito = 0 THEN saldo ELSE 0 END), 0) AS dividaCredito,
|
WHEN debito = 1
|
||||||
|
AND COALESCE(investimento, 0) = 0
|
||||||
|
THEN saldo
|
||||||
|
ELSE 0
|
||||||
|
END), 0) AS saldoDisponivel,
|
||||||
|
|
||||||
|
COALESCE(SUM(CASE
|
||||||
|
WHEN debito = 1
|
||||||
|
AND COALESCE(investimento, 0) = 1
|
||||||
|
THEN saldo
|
||||||
|
ELSE 0
|
||||||
|
END), 0) AS totalInvestido,
|
||||||
|
|
||||||
|
COALESCE(SUM(CASE
|
||||||
|
WHEN debito = 1
|
||||||
|
THEN saldo
|
||||||
|
ELSE 0
|
||||||
|
END), 0) AS saldoDebitoTotal,
|
||||||
|
|
||||||
|
COALESCE(SUM(CASE
|
||||||
|
WHEN debito = 0
|
||||||
|
THEN saldo
|
||||||
|
ELSE 0
|
||||||
|
END), 0) AS dividaCredito,
|
||||||
|
|
||||||
COUNT(*) AS quantidadeCarteiras,
|
COUNT(*) AS quantidadeCarteiras,
|
||||||
SUM(CASE WHEN habilitado = 1 THEN 1 ELSE 0 END) AS carteirasHabilitadas
|
|
||||||
|
SUM(CASE
|
||||||
|
WHEN habilitado = 1 THEN 1
|
||||||
|
ELSE 0
|
||||||
|
END) AS carteirasHabilitadas,
|
||||||
|
|
||||||
|
SUM(CASE
|
||||||
|
WHEN debito = 1
|
||||||
|
AND COALESCE(investimento, 0) = 0
|
||||||
|
AND habilitado = 1
|
||||||
|
THEN 1
|
||||||
|
ELSE 0
|
||||||
|
END) AS quantidadeContasDisponiveis,
|
||||||
|
|
||||||
|
SUM(CASE
|
||||||
|
WHEN debito = 1
|
||||||
|
AND COALESCE(investimento, 0) = 1
|
||||||
|
AND habilitado = 1
|
||||||
|
THEN 1
|
||||||
|
ELSE 0
|
||||||
|
END) AS quantidadeInvestimentos,
|
||||||
|
|
||||||
|
SUM(CASE
|
||||||
|
WHEN debito = 0
|
||||||
|
AND habilitado = 1
|
||||||
|
THEN 1
|
||||||
|
ELSE 0
|
||||||
|
END) AS quantidadeCreditos
|
||||||
FROM bancos
|
FROM bancos
|
||||||
`);
|
WHERE idusuarios = ?
|
||||||
|
`,
|
||||||
|
[idUsuario]
|
||||||
|
);
|
||||||
|
|
||||||
const row = rows[0] || {};
|
const row = rows[0] || {};
|
||||||
|
|
||||||
|
const saldoDisponivel = normalizarNumero(row.saldoDisponivel);
|
||||||
|
const totalInvestido = normalizarNumero(row.totalInvestido);
|
||||||
|
const saldoDebitoTotal = normalizarNumero(row.saldoDebitoTotal);
|
||||||
|
const dividaCredito = normalizarNumero(row.dividaCredito);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
saldoDebito: normalizarNumero(row.saldoDebito),
|
saldoDisponivel,
|
||||||
dividaCredito: normalizarNumero(row.dividaCredito),
|
totalInvestido,
|
||||||
|
saldoDebitoTotal,
|
||||||
|
saldoDebito: saldoDisponivel, // mantém compatibilidade com o front atual
|
||||||
|
dividaCredito,
|
||||||
|
patrimonioBruto: saldoDisponivel + totalInvestido,
|
||||||
|
patrimonioLiquido: saldoDisponivel + totalInvestido - dividaCredito,
|
||||||
quantidadeCarteiras: normalizarNumero(row.quantidadeCarteiras),
|
quantidadeCarteiras: normalizarNumero(row.quantidadeCarteiras),
|
||||||
carteirasHabilitadas: normalizarNumero(row.carteirasHabilitadas),
|
carteirasHabilitadas: normalizarNumero(row.carteirasHabilitadas),
|
||||||
|
quantidadeContasDisponiveis: normalizarNumero(row.quantidadeContasDisponiveis),
|
||||||
|
quantidadeInvestimentos: normalizarNumero(row.quantidadeInvestimentos),
|
||||||
|
quantidadeCreditos: normalizarNumero(row.quantidadeCreditos),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buscarCardsMovimentos(dataInicio, dataFim) {
|
async function buscarCardsMovimentos(idUsuario, dataInicio, dataFim) {
|
||||||
const [rows] = await pool.query(
|
const [rows] = await pool.query(
|
||||||
`
|
`
|
||||||
SELECT
|
SELECT
|
||||||
|
|
@ -144,12 +212,15 @@ async function buscarCardsMovimentos(dataInicio, dataFim) {
|
||||||
|
|
||||||
COUNT(*) AS quantidadeMovimentos
|
COUNT(*) AS quantidadeMovimentos
|
||||||
FROM contasapagar cp
|
FROM contasapagar cp
|
||||||
|
LEFT JOIN bancos b
|
||||||
|
ON b.idbancos = cp.idbancos
|
||||||
LEFT JOIN centrodecustos cc
|
LEFT JOIN centrodecustos cc
|
||||||
ON cc.idcentrodecustos = cp.idcentrodecustos
|
ON cc.idcentrodecustos = cp.idcentrodecustos
|
||||||
WHERE cp.deleted_at IS NULL
|
WHERE cp.deleted_at IS NULL
|
||||||
|
AND b.idusuarios = ?
|
||||||
AND DATE(cp.datavencimento) BETWEEN ? AND ?
|
AND DATE(cp.datavencimento) BETWEEN ? AND ?
|
||||||
`,
|
`,
|
||||||
[dataInicio, dataFim]
|
[idUsuario, dataInicio, dataFim]
|
||||||
);
|
);
|
||||||
|
|
||||||
const row = rows[0] || {};
|
const row = rows[0] || {};
|
||||||
|
|
@ -188,7 +259,7 @@ async function buscarCardsMovimentos(dataInicio, dataFim) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buscarAlertasVencimento() {
|
async function buscarAlertasVencimento(idUsuario) {
|
||||||
const hoje = hojeISO();
|
const hoje = hojeISO();
|
||||||
|
|
||||||
const [rows] = await pool.query(
|
const [rows] = await pool.query(
|
||||||
|
|
@ -286,9 +357,12 @@ async function buscarAlertasVencimento() {
|
||||||
FROM contasapagar cp
|
FROM contasapagar cp
|
||||||
LEFT JOIN centrodecustos cc
|
LEFT JOIN centrodecustos cc
|
||||||
ON cc.idcentrodecustos = cp.idcentrodecustos
|
ON cc.idcentrodecustos = cp.idcentrodecustos
|
||||||
|
LEFT JOIN bancos b
|
||||||
|
ON b.idbancos = cp.idbancos
|
||||||
WHERE cp.deleted_at IS NULL
|
WHERE cp.deleted_at IS NULL
|
||||||
AND cp.status IN ('A pagar', 'A receber')
|
AND cp.status IN ('A pagar', 'A receber')
|
||||||
AND cp.datavencimento IS NOT NULL
|
AND cp.datavencimento IS NOT NULL
|
||||||
|
AND b.idusuarios = ?
|
||||||
`,
|
`,
|
||||||
[
|
[
|
||||||
hoje, hoje,
|
hoje, hoje,
|
||||||
|
|
@ -304,6 +378,8 @@ async function buscarAlertasVencimento() {
|
||||||
|
|
||||||
hoje, hoje,
|
hoje, hoje,
|
||||||
hoje, hoje,
|
hoje, hoje,
|
||||||
|
|
||||||
|
idUsuario
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -334,7 +410,7 @@ async function buscarAlertasVencimento() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buscarProximosVencimentos() {
|
async function buscarProximosVencimentos(idUsuario) {
|
||||||
const [rows] = await pool.query(`
|
const [rows] = await pool.query(`
|
||||||
SELECT
|
SELECT
|
||||||
cp.idcontasapagar,
|
cp.idcontasapagar,
|
||||||
|
|
@ -357,16 +433,18 @@ async function buscarProximosVencimentos() {
|
||||||
LEFT JOIN bancos bc ON bc.idbancos = cp.idbancos
|
LEFT JOIN bancos bc ON bc.idbancos = cp.idbancos
|
||||||
LEFT JOIN centrodecustos cc ON cc.idcentrodecustos = cp.idcentrodecustos
|
LEFT JOIN centrodecustos cc ON cc.idcentrodecustos = cp.idcentrodecustos
|
||||||
WHERE cp.deleted_at IS NULL
|
WHERE cp.deleted_at IS NULL
|
||||||
|
AND bc.idusuarios = ?
|
||||||
AND cp.status IN ('A pagar', 'A receber')
|
AND cp.status IN ('A pagar', 'A receber')
|
||||||
AND cp.datavencimento IS NOT NULL
|
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
|
LIMIT 10
|
||||||
`);
|
`,
|
||||||
|
[idUsuario]);
|
||||||
|
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buscarCreditosEmAberto(dataInicio, dataFim) {
|
async function buscarCreditosEmAberto(idUsuario, dataInicio, dataFim) {
|
||||||
const [rows] = await pool.query(
|
const [rows] = await pool.query(
|
||||||
`
|
`
|
||||||
SELECT
|
SELECT
|
||||||
|
|
@ -423,7 +501,8 @@ async function buscarCreditosEmAberto(dataInicio, dataFim) {
|
||||||
AND cp.deleted_at IS NULL
|
AND cp.deleted_at IS NULL
|
||||||
AND cp.status = 'A pagar'
|
AND cp.status = 'A pagar'
|
||||||
AND cp.movimento IN ('Saida', 'Sangria')
|
AND cp.movimento IN ('Saida', 'Sangria')
|
||||||
WHERE bc.debito = 0
|
WHERE bc.idusuarios = ?
|
||||||
|
AND bc.debito = 0
|
||||||
AND bc.habilitado = 1
|
AND bc.habilitado = 1
|
||||||
GROUP BY
|
GROUP BY
|
||||||
bc.idbancos,
|
bc.idbancos,
|
||||||
|
|
@ -443,6 +522,7 @@ async function buscarCreditosEmAberto(dataInicio, dataFim) {
|
||||||
dataFim,
|
dataFim,
|
||||||
dataFim,
|
dataFim,
|
||||||
dataFim,
|
dataFim,
|
||||||
|
idUsuario,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -460,7 +540,7 @@ async function buscarCreditosEmAberto(dataInicio, dataFim) {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buscarCarteiras(dataInicio, dataFim) {
|
async function buscarCarteiras(idUsuario, dataInicio, dataFim) {
|
||||||
const [rows] = await pool.query(
|
const [rows] = await pool.query(
|
||||||
`
|
`
|
||||||
SELECT
|
SELECT
|
||||||
|
|
@ -472,21 +552,25 @@ async function buscarCarteiras(dataInicio, dataFim) {
|
||||||
bc.dia_vencimento,
|
bc.dia_vencimento,
|
||||||
bc.insert_date,
|
bc.insert_date,
|
||||||
bc.update_date,
|
bc.update_date,
|
||||||
|
bc.investimento,
|
||||||
|
|
||||||
COALESCE(aud.delta_periodo, 0) AS delta_periodo
|
COALESCE(aud.delta_periodo, 0) AS delta_periodo
|
||||||
FROM bancos bc
|
FROM bancos bc
|
||||||
LEFT JOIN (
|
LEFT JOIN (
|
||||||
SELECT
|
SELECT
|
||||||
idbancos,
|
bsa.idbancos,
|
||||||
COALESCE(SUM(valor_delta), 0) AS delta_periodo
|
COALESCE(SUM(bsa.valor_delta), 0) AS delta_periodo
|
||||||
FROM bancos_saldo_auditoria
|
FROM bancos_saldo_auditoria bsa
|
||||||
WHERE DATE(insert_date) BETWEEN ? AND ?
|
INNER JOIN bancos b2 ON b2.idbancos = bsa.idbancos
|
||||||
GROUP BY idbancos
|
WHERE b2.idusuarios = ?
|
||||||
|
AND DATE(bsa.insert_date) BETWEEN ? AND ?
|
||||||
|
GROUP BY bsa.idbancos
|
||||||
) aud ON aud.idbancos = bc.idbancos
|
) aud ON aud.idbancos = bc.idbancos
|
||||||
WHERE bc.habilitado = 1
|
WHERE bc.habilitado = 1
|
||||||
|
AND bc.idusuarios = ?
|
||||||
ORDER BY bc.debito DESC, bc.descricao ASC
|
ORDER BY bc.debito DESC, bc.descricao ASC
|
||||||
`,
|
`,
|
||||||
[dataInicio, dataFim]
|
[idUsuario, dataInicio, dataFim, idUsuario]
|
||||||
);
|
);
|
||||||
|
|
||||||
return rows.map((item) => {
|
return rows.map((item) => {
|
||||||
|
|
@ -494,6 +578,7 @@ async function buscarCarteiras(dataInicio, dataFim) {
|
||||||
const deltaPeriodo = normalizarNumero(item.delta_periodo);
|
const deltaPeriodo = normalizarNumero(item.delta_periodo);
|
||||||
const saldoMesAnterior = saldoAtual - deltaPeriodo;
|
const saldoMesAnterior = saldoAtual - deltaPeriodo;
|
||||||
const variacaoValor = saldoAtual - saldoMesAnterior;
|
const variacaoValor = saldoAtual - saldoMesAnterior;
|
||||||
|
const isInvestimento = Number(item.investimento || 0) === 1;
|
||||||
|
|
||||||
const variacaoPercentual = saldoMesAnterior !== 0
|
const variacaoPercentual = saldoMesAnterior !== 0
|
||||||
? (variacaoValor / Math.abs(saldoMesAnterior)) * 100
|
? (variacaoValor / Math.abs(saldoMesAnterior)) * 100
|
||||||
|
|
@ -512,11 +597,16 @@ async function buscarCarteiras(dataInicio, dataFim) {
|
||||||
variacao_valor: variacaoValor,
|
variacao_valor: variacaoValor,
|
||||||
variacao_percentual: variacaoPercentual,
|
variacao_percentual: variacaoPercentual,
|
||||||
tendencia_boa: tendenciaBoa,
|
tendencia_boa: tendenciaBoa,
|
||||||
|
tipo_carteira: isCredito
|
||||||
|
? 'credito'
|
||||||
|
: isInvestimento
|
||||||
|
? 'investimento'
|
||||||
|
: 'disponivel',
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buscarUltimosMovimentos() {
|
async function buscarUltimosMovimentos(idUsuario) {
|
||||||
const [rows] = await pool.query(`
|
const [rows] = await pool.query(`
|
||||||
SELECT
|
SELECT
|
||||||
cp.idcontasapagar,
|
cp.idcontasapagar,
|
||||||
|
|
@ -543,14 +633,16 @@ async function buscarUltimosMovimentos() {
|
||||||
LEFT JOIN bancos bc ON bc.idbancos = cp.idbancos
|
LEFT JOIN bancos bc ON bc.idbancos = cp.idbancos
|
||||||
LEFT JOIN centrodecustos cc ON cc.idcentrodecustos = cp.idcentrodecustos
|
LEFT JOIN centrodecustos cc ON cc.idcentrodecustos = cp.idcentrodecustos
|
||||||
WHERE cp.deleted_at IS NULL
|
WHERE cp.deleted_at IS NULL
|
||||||
|
AND bc.idusuarios = ?
|
||||||
ORDER BY cp.insert_date DESC, cp.idcontasapagar DESC
|
ORDER BY cp.insert_date DESC, cp.idcontasapagar DESC
|
||||||
LIMIT 10
|
LIMIT 10
|
||||||
`);
|
`,
|
||||||
|
[idUsuario]);
|
||||||
|
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buscarGraficos(dataInicio, dataFim) {
|
async function buscarGraficos(idUsuario, dataInicio, dataFim) {
|
||||||
const [centrosRows] = await pool.query(
|
const [centrosRows] = await pool.query(
|
||||||
`
|
`
|
||||||
SELECT
|
SELECT
|
||||||
|
|
@ -560,9 +652,12 @@ async function buscarGraficos(dataInicio, dataFim) {
|
||||||
FROM contasapagar cp
|
FROM contasapagar cp
|
||||||
LEFT JOIN centrodecustos cc
|
LEFT JOIN centrodecustos cc
|
||||||
ON cc.idcentrodecustos = cp.idcentrodecustos
|
ON cc.idcentrodecustos = cp.idcentrodecustos
|
||||||
|
LEFT JOIN bancos b
|
||||||
|
ON b.idbancos = cp.idbancos
|
||||||
WHERE cp.deleted_at IS NULL
|
WHERE cp.deleted_at IS NULL
|
||||||
AND cp.movimento IN ('Saida')
|
AND cp.movimento IN ('Saida')
|
||||||
AND DATE(cp.datavencimento) BETWEEN ? AND ?
|
AND DATE(cp.datavencimento) BETWEEN ? AND ?
|
||||||
|
AND b.idusuarios = ?
|
||||||
GROUP BY
|
GROUP BY
|
||||||
cp.idcentrodecustos,
|
cp.idcentrodecustos,
|
||||||
COALESCE(cc.descricao, 'Sem centro de custo')
|
COALESCE(cc.descricao, 'Sem centro de custo')
|
||||||
|
|
@ -570,7 +665,7 @@ async function buscarGraficos(dataInicio, dataFim) {
|
||||||
ORDER BY valor DESC
|
ORDER BY valor DESC
|
||||||
LIMIT 8
|
LIMIT 8
|
||||||
`,
|
`,
|
||||||
[dataInicio, dataFim]
|
[dataInicio, dataFim, idUsuario]
|
||||||
);
|
);
|
||||||
|
|
||||||
const [entradasSaidasRows] = await pool.query(
|
const [entradasSaidasRows] = await pool.query(
|
||||||
|
|
@ -595,10 +690,13 @@ async function buscarGraficos(dataInicio, dataFim) {
|
||||||
FROM contasapagar cp
|
FROM contasapagar cp
|
||||||
LEFT JOIN centrodecustos cc
|
LEFT JOIN centrodecustos cc
|
||||||
ON cc.idcentrodecustos = cp.idcentrodecustos
|
ON cc.idcentrodecustos = cp.idcentrodecustos
|
||||||
|
LEFT JOIN bancos b
|
||||||
|
ON b.idbancos = cp.idbancos
|
||||||
WHERE cp.deleted_at IS NULL
|
WHERE cp.deleted_at IS NULL
|
||||||
AND DATE(cp.datavencimento) BETWEEN ? AND ?
|
AND DATE(cp.datavencimento) BETWEEN ? AND ?
|
||||||
|
AND b.idusuarios = ?
|
||||||
`,
|
`,
|
||||||
[dataInicio, dataFim]
|
[dataInicio, dataFim, idUsuario]
|
||||||
);
|
);
|
||||||
|
|
||||||
const entradas = normalizarNumero(entradasSaidasRows[0]?.entradas);
|
const entradas = normalizarNumero(entradasSaidasRows[0]?.entradas);
|
||||||
|
|
@ -627,13 +725,38 @@ async function buscarGraficos(dataInicio, dataFim) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buscarResumoDashboard(filtros = {}) {
|
async function buscarCardsInvestimentos(idUsuario, dataInicio, dataFim) {
|
||||||
|
const [rows] = await pool.query(
|
||||||
|
`
|
||||||
|
SELECT
|
||||||
|
COALESCE(SUM(bsa.valor_delta), 0) AS rendimentoInvestimentosPeriodo,
|
||||||
|
COUNT(*) AS quantidadeRendimentosPeriodo
|
||||||
|
FROM bancos_saldo_auditoria bsa
|
||||||
|
INNER JOIN bancos b ON b.idbancos = bsa.idbancos
|
||||||
|
WHERE b.idusuarios = ?
|
||||||
|
AND b.investimento = 1
|
||||||
|
AND bsa.origem = 'rendimento_investimento'
|
||||||
|
AND DATE(bsa.insert_date) BETWEEN ? AND ?
|
||||||
|
`,
|
||||||
|
[idUsuario, dataInicio, dataFim]
|
||||||
|
);
|
||||||
|
|
||||||
|
const row = rows[0] || {};
|
||||||
|
|
||||||
|
return {
|
||||||
|
rendimentoInvestimentosPeriodo: normalizarNumero(row.rendimentoInvestimentosPeriodo),
|
||||||
|
quantidadeRendimentosPeriodo: normalizarNumero(row.quantidadeRendimentosPeriodo),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function buscarResumoDashboard(idUsuario, filtros = {}) {
|
||||||
const dataInicio = normalizarDataISO(filtros.dataInicio, inicioMesAtualISO());
|
const dataInicio = normalizarDataISO(filtros.dataInicio, inicioMesAtualISO());
|
||||||
const dataFim = normalizarDataISO(filtros.dataFim, fimMesAtualISO());
|
const dataFim = normalizarDataISO(filtros.dataFim, fimMesAtualISO());
|
||||||
|
|
||||||
const [
|
const [
|
||||||
cardsBancos,
|
cardsBancos,
|
||||||
cardsMovimentos,
|
cardsMovimentos,
|
||||||
|
cardsInvestimentos,
|
||||||
alertasVencimento,
|
alertasVencimento,
|
||||||
proximosVencimentos,
|
proximosVencimentos,
|
||||||
creditos,
|
creditos,
|
||||||
|
|
@ -641,14 +764,15 @@ async function buscarResumoDashboard(filtros = {}) {
|
||||||
ultimosMovimentos,
|
ultimosMovimentos,
|
||||||
graficos,
|
graficos,
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
buscarCardsBancos(),
|
buscarCardsBancos(idUsuario),
|
||||||
buscarCardsMovimentos(dataInicio, dataFim),
|
buscarCardsMovimentos(idUsuario, dataInicio, dataFim),
|
||||||
buscarAlertasVencimento(),
|
buscarCardsInvestimentos(idUsuario, dataInicio, dataFim),
|
||||||
buscarProximosVencimentos(),
|
buscarAlertasVencimento(idUsuario),
|
||||||
buscarCreditosEmAberto(dataInicio, dataFim),
|
buscarProximosVencimentos(idUsuario),
|
||||||
buscarCarteiras(dataInicio, dataFim),
|
buscarCreditosEmAberto(idUsuario, dataInicio, dataFim),
|
||||||
buscarUltimosMovimentos(),
|
buscarCarteiras(idUsuario, dataInicio, dataFim),
|
||||||
buscarGraficos(dataInicio, dataFim),
|
buscarUltimosMovimentos(idUsuario),
|
||||||
|
buscarGraficos(idUsuario, dataInicio, dataFim),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
@ -660,6 +784,7 @@ async function buscarResumoDashboard(filtros = {}) {
|
||||||
cards: {
|
cards: {
|
||||||
...cardsBancos,
|
...cardsBancos,
|
||||||
...cardsMovimentos,
|
...cardsMovimentos,
|
||||||
|
...cardsInvestimentos,
|
||||||
...alertasVencimento,
|
...alertasVencimento,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,7 @@ async function listar(req, res) {
|
||||||
limite: req.query.limite,
|
limite: req.query.limite,
|
||||||
offset: req.query.offset,
|
offset: req.query.offset,
|
||||||
page: req.query.page,
|
page: req.query.page,
|
||||||
|
busca: req.query.busca,
|
||||||
movimento: req.query.movimento,
|
movimento: req.query.movimento,
|
||||||
status: req.query.status,
|
status: req.query.status,
|
||||||
idbancos: req.query.idbancos,
|
idbancos: req.query.idbancos,
|
||||||
|
|
@ -139,10 +140,11 @@ async function listar(req, res) {
|
||||||
dataCampo: req.query.dataCampo,
|
dataCampo: req.query.dataCampo,
|
||||||
dataInicio: req.query.dataInicio,
|
dataInicio: req.query.dataInicio,
|
||||||
dataFim: req.query.dataFim,
|
dataFim: req.query.dataFim,
|
||||||
busca: req.query.busca,
|
|
||||||
incluirExcluidos: req.query.incluirExcluidos,
|
incluirExcluidos: req.query.incluirExcluidos,
|
||||||
orderBy: req.query.orderBy,
|
orderBy: req.query.orderBy,
|
||||||
orderDirection: req.query.orderDirection,
|
orderDirection: req.query.orderDirection,
|
||||||
|
|
||||||
|
idusuarios: req.user.idusuarios || req.user.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
|
|
@ -172,7 +174,9 @@ async function buscarPorId(req, res) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const movimento = await movimentosService.buscarMovimentoPorId(id);
|
const movimento = await movimentosService.buscarMovimentoPorId(id, {
|
||||||
|
idUsuario: req.user.idusuarios || req.user.id,
|
||||||
|
});
|
||||||
|
|
||||||
if (!movimento) {
|
if (!movimento) {
|
||||||
return res.status(404).json({
|
return res.status(404).json({
|
||||||
|
|
|
||||||
|
|
@ -206,6 +206,11 @@ function montarWhereMovimentos(filtros = {}) {
|
||||||
where.push('cp.deleted_at IS NULL');
|
where.push('cp.deleted_at IS NULL');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (filtros.idusuarios) {
|
||||||
|
where.push('b.idusuarios = ?');
|
||||||
|
params.push(Number(filtros.idusuarios));
|
||||||
|
}
|
||||||
|
|
||||||
if (filtros.movimento) {
|
if (filtros.movimento) {
|
||||||
where.push('cp.movimento = ?');
|
where.push('cp.movimento = ?');
|
||||||
params.push(filtros.movimento);
|
params.push(filtros.movimento);
|
||||||
|
|
@ -411,6 +416,15 @@ async function listarMovimentos(filtros = {}) {
|
||||||
async function buscarMovimentoPorId(id, opcoes = {}) {
|
async function buscarMovimentoPorId(id, opcoes = {}) {
|
||||||
const executor = opcoes.connection || pool;
|
const executor = opcoes.connection || pool;
|
||||||
const incluirExcluidos = opcoes.incluirExcluidos === true;
|
const incluirExcluidos = opcoes.incluirExcluidos === true;
|
||||||
|
const idUsuario = opcoes.idUsuario || null;
|
||||||
|
|
||||||
|
const params = [id];
|
||||||
|
let filtroUsuario = '';
|
||||||
|
|
||||||
|
if (idUsuario) {
|
||||||
|
filtroUsuario = 'AND b.idusuarios = ?';
|
||||||
|
params.push(Number(idUsuario));
|
||||||
|
}
|
||||||
|
|
||||||
const [rows] = await executor.query(
|
const [rows] = await executor.query(
|
||||||
`
|
`
|
||||||
|
|
@ -419,26 +433,37 @@ async function buscarMovimentoPorId(id, opcoes = {}) {
|
||||||
${FROM_MOVIMENTO_JOIN}
|
${FROM_MOVIMENTO_JOIN}
|
||||||
WHERE cp.idcontasapagar = ?
|
WHERE cp.idcontasapagar = ?
|
||||||
${incluirExcluidos ? '' : 'AND cp.deleted_at IS NULL'}
|
${incluirExcluidos ? '' : 'AND cp.deleted_at IS NULL'}
|
||||||
|
${filtroUsuario}
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
`,
|
`,
|
||||||
[id]
|
params
|
||||||
);
|
);
|
||||||
|
|
||||||
return rows[0] || null;
|
return rows[0] || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buscarMovimentoPorIdParaUpdate(connection, id) {
|
async function buscarMovimentoPorIdParaUpdate(connection, id, idUsuario = null) {
|
||||||
|
const params = [id];
|
||||||
|
let filtroUsuario = '';
|
||||||
|
|
||||||
|
if (idUsuario) {
|
||||||
|
filtroUsuario = 'AND b.idusuarios = ?';
|
||||||
|
params.push(Number(idUsuario));
|
||||||
|
}
|
||||||
|
|
||||||
const [rows] = await connection.query(
|
const [rows] = await connection.query(
|
||||||
`
|
`
|
||||||
SELECT
|
SELECT
|
||||||
cp.*
|
cp.*
|
||||||
FROM contasapagar cp
|
FROM contasapagar cp
|
||||||
|
INNER JOIN bancos b ON b.idbancos = cp.idbancos
|
||||||
WHERE cp.idcontasapagar = ?
|
WHERE cp.idcontasapagar = ?
|
||||||
AND cp.deleted_at IS NULL
|
AND cp.deleted_at IS NULL
|
||||||
|
${filtroUsuario}
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
FOR UPDATE
|
FOR UPDATE
|
||||||
`,
|
`,
|
||||||
[id]
|
params
|
||||||
);
|
);
|
||||||
|
|
||||||
return rows[0] || null;
|
return rows[0] || null;
|
||||||
|
|
@ -713,7 +738,7 @@ function montarParcelas(idUsuario, dados) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function aplicarSaldoMovimento(connection, movimento, contexto) {
|
async function aplicarSaldoMovimento(connection, movimento, contexto) {
|
||||||
const deltas = await movimentosSaldoService.calcularImpactoMovimento(connection, movimento);
|
const deltas = await movimentosSaldoService.calcularImpactoMovimento(connection, movimento, contexto);
|
||||||
|
|
||||||
if (deltas.length === 0) {
|
if (deltas.length === 0) {
|
||||||
return {
|
return {
|
||||||
|
|
@ -826,7 +851,7 @@ async function atualizarMovimento(id, idUsuario, dados) {
|
||||||
try {
|
try {
|
||||||
await connection.beginTransaction();
|
await connection.beginTransaction();
|
||||||
|
|
||||||
const movimentoAntigo = await buscarMovimentoPorIdParaUpdate(connection, id);
|
const movimentoAntigo = await buscarMovimentoPorIdParaUpdate(connection, id, idUsuario);
|
||||||
|
|
||||||
if (!movimentoAntigo) {
|
if (!movimentoAntigo) {
|
||||||
await connection.rollback();
|
await connection.rollback();
|
||||||
|
|
@ -845,7 +870,8 @@ async function atualizarMovimento(id, idUsuario, dados) {
|
||||||
if (Number(movimentoAntigo.saldo_processado) === 1) {
|
if (Number(movimentoAntigo.saldo_processado) === 1) {
|
||||||
const deltasAntigos = await movimentosSaldoService.calcularImpactoMovimento(
|
const deltasAntigos = await movimentosSaldoService.calcularImpactoMovimento(
|
||||||
connection,
|
connection,
|
||||||
movimentoAntigo
|
movimentoAntigo,
|
||||||
|
{ idusuarios: idUsuario }
|
||||||
);
|
);
|
||||||
|
|
||||||
const impactosReversao = await movimentosSaldoService.aplicarDeltasSaldo(
|
const impactosReversao = await movimentosSaldoService.aplicarDeltasSaldo(
|
||||||
|
|
@ -924,7 +950,7 @@ async function deletarMovimento(id, idUsuario) {
|
||||||
try {
|
try {
|
||||||
await connection.beginTransaction();
|
await connection.beginTransaction();
|
||||||
|
|
||||||
const movimentoAntigo = await buscarMovimentoPorIdParaUpdate(connection, id);
|
const movimentoAntigo = await buscarMovimentoPorIdParaUpdate(connection, id, idUsuario);
|
||||||
|
|
||||||
if (!movimentoAntigo) {
|
if (!movimentoAntigo) {
|
||||||
await connection.rollback();
|
await connection.rollback();
|
||||||
|
|
@ -939,7 +965,8 @@ async function deletarMovimento(id, idUsuario) {
|
||||||
if (Number(movimentoAntigo.saldo_processado) === 1) {
|
if (Number(movimentoAntigo.saldo_processado) === 1) {
|
||||||
const deltasAntigos = await movimentosSaldoService.calcularImpactoMovimento(
|
const deltasAntigos = await movimentosSaldoService.calcularImpactoMovimento(
|
||||||
connection,
|
connection,
|
||||||
movimentoAntigo
|
movimentoAntigo,
|
||||||
|
{ idusuarios: idUsuario }
|
||||||
);
|
);
|
||||||
|
|
||||||
const impactosReversao = await movimentosSaldoService.aplicarDeltasSaldo(
|
const impactosReversao = await movimentosSaldoService.aplicarDeltasSaldo(
|
||||||
|
|
|
||||||
|
|
@ -12,42 +12,64 @@ function bancoEhCredito(banco) {
|
||||||
return Number(banco?.debito) === 0;
|
return Number(banco?.debito) === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buscarBanco(connection, idbancos) {
|
async function buscarBanco(connection, idbancos, idusuarios = null) {
|
||||||
if (!idbancos) return null;
|
if (!idbancos) return null;
|
||||||
|
|
||||||
|
const params = [idbancos];
|
||||||
|
let filtroUsuario = '';
|
||||||
|
|
||||||
|
if (idusuarios) {
|
||||||
|
filtroUsuario = 'AND idusuarios = ?';
|
||||||
|
params.push(idusuarios);
|
||||||
|
}
|
||||||
|
|
||||||
const [rows] = await connection.query(
|
const [rows] = await connection.query(
|
||||||
`
|
`
|
||||||
SELECT
|
SELECT
|
||||||
idbancos,
|
idbancos,
|
||||||
descricao,
|
descricao,
|
||||||
saldo,
|
saldo,
|
||||||
debito
|
debito,
|
||||||
|
investimento,
|
||||||
|
idusuarios
|
||||||
FROM bancos
|
FROM bancos
|
||||||
WHERE idbancos = ?
|
WHERE idbancos = ?
|
||||||
|
${filtroUsuario}
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
`,
|
`,
|
||||||
[idbancos]
|
params
|
||||||
);
|
);
|
||||||
|
|
||||||
return rows[0] || null;
|
return rows[0] || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buscarBancoParaUpdate(connection, idbancos) {
|
async function buscarBancoParaUpdate(connection, idbancos, idusuarios = null) {
|
||||||
if (!idbancos) return null;
|
if (!idbancos) return null;
|
||||||
|
|
||||||
|
const params = [idbancos];
|
||||||
|
let filtroUsuario = '';
|
||||||
|
|
||||||
|
if (idusuarios) {
|
||||||
|
filtroUsuario = 'AND idusuarios = ?';
|
||||||
|
params.push(idusuarios);
|
||||||
|
}
|
||||||
|
|
||||||
const [rows] = await connection.query(
|
const [rows] = await connection.query(
|
||||||
`
|
`
|
||||||
SELECT
|
SELECT
|
||||||
idbancos,
|
idbancos,
|
||||||
descricao,
|
descricao,
|
||||||
saldo,
|
saldo,
|
||||||
debito
|
debito,
|
||||||
|
investimento,
|
||||||
|
idusuarios
|
||||||
FROM bancos
|
FROM bancos
|
||||||
WHERE idbancos = ?
|
WHERE idbancos = ?
|
||||||
|
${filtroUsuario}
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
FOR UPDATE
|
FOR UPDATE
|
||||||
`,
|
`,
|
||||||
[idbancos]
|
params
|
||||||
);
|
);
|
||||||
|
|
||||||
return rows[0] || null;
|
return rows[0] || null;
|
||||||
|
|
@ -145,9 +167,9 @@ function calcularDeltasParaMovimento(movimento, bancoOrigem, bancoDestino = null
|
||||||
return deltas;
|
return deltas;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function calcularImpactoMovimento(connection, movimento) {
|
async function calcularImpactoMovimento(connection, movimento, contexto = {}) {
|
||||||
const bancoOrigem = await buscarBanco(connection, movimento.idbancos);
|
const bancoOrigem = await buscarBanco(connection, movimento.idbancos, contexto.idusuarios);
|
||||||
const bancoDestino = await buscarBanco(connection, movimento.idbancos_p);
|
const bancoDestino = await buscarBanco(connection, movimento.idbancos_p, contexto.idusuarios);
|
||||||
|
|
||||||
return calcularDeltasParaMovimento(movimento, bancoOrigem, bancoDestino);
|
return calcularDeltasParaMovimento(movimento, bancoOrigem, bancoDestino);
|
||||||
}
|
}
|
||||||
|
|
@ -164,7 +186,7 @@ async function aplicarDeltasSaldo(connection, deltas, contexto = {}) {
|
||||||
const impactos = [];
|
const impactos = [];
|
||||||
|
|
||||||
for (const delta of deltas) {
|
for (const delta of deltas) {
|
||||||
const banco = await buscarBancoParaUpdate(connection, delta.idbancos);
|
const banco = await buscarBancoParaUpdate(connection, delta.idbancos, contexto.idusuarios);
|
||||||
|
|
||||||
if (!banco) {
|
if (!banco) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
const quitacoesCreditoService = require('../services/quitacoesCredito.service');
|
const quitacoesCreditoService = require('../services/quitacoesCredito.service');
|
||||||
|
|
||||||
|
function resolverIdUsuario(req) {
|
||||||
|
return Number(req.user?.idusuarios || req.user?.id);
|
||||||
|
}
|
||||||
|
|
||||||
function tratarErro(error, res, mensagemPadrao) {
|
function tratarErro(error, res, mensagemPadrao) {
|
||||||
if (error?.statusCode) {
|
if (error?.statusCode) {
|
||||||
return res.status(error.statusCode).json({
|
return res.status(error.statusCode).json({
|
||||||
|
|
@ -43,7 +47,16 @@ function validarCriacao(dados) {
|
||||||
|
|
||||||
async function listarBancosCredito(req, res) {
|
async function listarBancosCredito(req, res) {
|
||||||
try {
|
try {
|
||||||
const bancos = await quitacoesCreditoService.listarBancosCredito();
|
const idUsuario = resolverIdUsuario(req);
|
||||||
|
|
||||||
|
if (!idUsuario) {
|
||||||
|
return res.status(401).json({
|
||||||
|
ok: false,
|
||||||
|
message: 'Usuário inválido.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const bancos = await quitacoesCreditoService.listarBancosCredito(idUsuario);
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
ok: true,
|
ok: true,
|
||||||
|
|
@ -57,7 +70,16 @@ async function listarBancosCredito(req, res) {
|
||||||
|
|
||||||
async function listarBancosPagamento(req, res) {
|
async function listarBancosPagamento(req, res) {
|
||||||
try {
|
try {
|
||||||
const bancos = await quitacoesCreditoService.listarBancosPagamento();
|
const idUsuario = resolverIdUsuario(req);
|
||||||
|
|
||||||
|
if (!idUsuario) {
|
||||||
|
return res.status(401).json({
|
||||||
|
ok: false,
|
||||||
|
message: 'Usuário inválido.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const bancos = await quitacoesCreditoService.listarBancosPagamento(idUsuario);
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
ok: true,
|
ok: true,
|
||||||
|
|
@ -71,7 +93,16 @@ async function listarBancosPagamento(req, res) {
|
||||||
|
|
||||||
async function preview(req, res) {
|
async function preview(req, res) {
|
||||||
try {
|
try {
|
||||||
const resultado = await quitacoesCreditoService.previewQuitacao({
|
const idUsuario = resolverIdUsuario(req);
|
||||||
|
|
||||||
|
if (!idUsuario) {
|
||||||
|
return res.status(401).json({
|
||||||
|
ok: false,
|
||||||
|
message: 'Usuário inválido.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const resultado = await quitacoesCreditoService.previewQuitacao(idUsuario, {
|
||||||
idBancoCredito: req.query.idBancoCredito || req.query.idbancos,
|
idBancoCredito: req.query.idBancoCredito || req.query.idbancos,
|
||||||
dataInicio: req.query.dataInicio,
|
dataInicio: req.query.dataInicio,
|
||||||
dataFim: req.query.dataFim,
|
dataFim: req.query.dataFim,
|
||||||
|
|
@ -102,7 +133,16 @@ async function criar(req, res) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const resultado = await quitacoesCreditoService.criarQuitacaoCredito(req.user.id, req.body);
|
const idUsuario = resolverIdUsuario(req);
|
||||||
|
|
||||||
|
if (!idUsuario) {
|
||||||
|
return res.status(401).json({
|
||||||
|
ok: false,
|
||||||
|
message: 'Usuário inválido.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const resultado = await quitacoesCreditoService.criarQuitacaoCredito(idUsuario, req.body);
|
||||||
|
|
||||||
return res.status(201).json({
|
return res.status(201).json({
|
||||||
ok: true,
|
ok: true,
|
||||||
|
|
@ -120,7 +160,16 @@ async function criar(req, res) {
|
||||||
|
|
||||||
async function listarHistorico(req, res) {
|
async function listarHistorico(req, res) {
|
||||||
try {
|
try {
|
||||||
const resultado = await quitacoesCreditoService.listarHistorico({
|
const idUsuario = resolverIdUsuario(req);
|
||||||
|
|
||||||
|
if (!idUsuario) {
|
||||||
|
return res.status(401).json({
|
||||||
|
ok: false,
|
||||||
|
message: 'Usuário inválido.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const resultado = await quitacoesCreditoService.listarHistorico(idUsuario, {
|
||||||
limite: req.query.limite,
|
limite: req.query.limite,
|
||||||
offset: req.query.offset,
|
offset: req.query.offset,
|
||||||
page: req.query.page,
|
page: req.query.page,
|
||||||
|
|
@ -154,7 +203,16 @@ async function buscarPorId(req, res) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const quitacao = await quitacoesCreditoService.buscarQuitacaoPorId(id);
|
const idUsuario = resolverIdUsuario(req);
|
||||||
|
|
||||||
|
if (!idUsuario) {
|
||||||
|
return res.status(401).json({
|
||||||
|
ok: false,
|
||||||
|
message: 'Usuário inválido.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const quitacao = await quitacoesCreditoService.buscarQuitacaoPorId(id, idUsuario);
|
||||||
|
|
||||||
if (!quitacao) {
|
if (!quitacao) {
|
||||||
return res.status(404).json({
|
return res.status(404).json({
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ function idsUnicos(ids = []) {
|
||||||
)];
|
)];
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buscarBancoParaUpdate(connection, idbancos) {
|
async function buscarBancoParaUpdate(connection, idbancos, idUsuario) {
|
||||||
const [rows] = await connection.query(
|
const [rows] = await connection.query(
|
||||||
`
|
`
|
||||||
SELECT
|
SELECT
|
||||||
|
|
@ -120,13 +120,15 @@ async function buscarBancoParaUpdate(connection, idbancos) {
|
||||||
descricao,
|
descricao,
|
||||||
saldo,
|
saldo,
|
||||||
debito,
|
debito,
|
||||||
habilitado
|
habilitado,
|
||||||
|
idusuarios
|
||||||
FROM bancos
|
FROM bancos
|
||||||
WHERE idbancos = ?
|
WHERE idbancos = ?
|
||||||
|
AND idusuarios = ?
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
FOR UPDATE
|
FOR UPDATE
|
||||||
`,
|
`,
|
||||||
[idbancos]
|
[idbancos, idUsuario]
|
||||||
);
|
);
|
||||||
|
|
||||||
return rows[0] || null;
|
return rows[0] || null;
|
||||||
|
|
@ -154,7 +156,7 @@ async function inserirAuditoriaConta(connection, dados) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function listarBancosCredito() {
|
async function listarBancosCredito(idUsuario) {
|
||||||
const [rows] = await pool.query(
|
const [rows] = await pool.query(
|
||||||
`
|
`
|
||||||
SELECT
|
SELECT
|
||||||
|
|
@ -166,16 +168,18 @@ async function listarBancosCredito() {
|
||||||
insert_date,
|
insert_date,
|
||||||
update_date
|
update_date
|
||||||
FROM bancos
|
FROM bancos
|
||||||
WHERE debito = 0
|
WHERE idusuarios = ?
|
||||||
|
AND debito = 0
|
||||||
AND COALESCE(habilitado, 1) = 1
|
AND COALESCE(habilitado, 1) = 1
|
||||||
ORDER BY descricao ASC, idbancos ASC
|
ORDER BY descricao ASC, idbancos ASC
|
||||||
`
|
`,
|
||||||
|
[idUsuario]
|
||||||
);
|
);
|
||||||
|
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function listarBancosPagamento() {
|
async function listarBancosPagamento(idUsuario) {
|
||||||
const [rows] = await pool.query(
|
const [rows] = await pool.query(
|
||||||
`
|
`
|
||||||
SELECT
|
SELECT
|
||||||
|
|
@ -187,10 +191,12 @@ async function listarBancosPagamento() {
|
||||||
insert_date,
|
insert_date,
|
||||||
update_date
|
update_date
|
||||||
FROM bancos
|
FROM bancos
|
||||||
WHERE debito = 1
|
WHERE idusuarios = ?
|
||||||
|
AND debito = 1
|
||||||
AND COALESCE(habilitado, 1) = 1
|
AND COALESCE(habilitado, 1) = 1
|
||||||
ORDER BY descricao ASC, idbancos ASC
|
ORDER BY descricao ASC, idbancos ASC
|
||||||
`
|
`,
|
||||||
|
[idUsuario]
|
||||||
);
|
);
|
||||||
|
|
||||||
return rows;
|
return rows;
|
||||||
|
|
@ -202,9 +208,13 @@ function montarWhereContasPreview(filtros = {}) {
|
||||||
"cp.movimento = 'Saida'",
|
"cp.movimento = 'Saida'",
|
||||||
"cp.status = 'A pagar'",
|
"cp.status = 'A pagar'",
|
||||||
'cp.idbancos = ?',
|
'cp.idbancos = ?',
|
||||||
|
'b.idusuarios = ?',
|
||||||
];
|
];
|
||||||
|
|
||||||
const params = [Number(filtros.idBancoCredito)];
|
const params = [
|
||||||
|
Number(filtros.idBancoCredito),
|
||||||
|
Number(filtros.idUsuario),
|
||||||
|
];
|
||||||
|
|
||||||
if (filtros.dataInicio) {
|
if (filtros.dataInicio) {
|
||||||
where.push('DATE(cp.datavencimento) >= ?');
|
where.push('DATE(cp.datavencimento) >= ?');
|
||||||
|
|
@ -237,7 +247,7 @@ function montarWhereContasPreview(filtros = {}) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function previewQuitacao(filtros = {}) {
|
async function previewQuitacao(idUsuario, filtros = {}) {
|
||||||
const idBancoCredito = normalizarNumeroOuNull(filtros.idBancoCredito || filtros.idbancos);
|
const idBancoCredito = normalizarNumeroOuNull(filtros.idBancoCredito || filtros.idbancos);
|
||||||
|
|
||||||
if (!idBancoCredito) {
|
if (!idBancoCredito) {
|
||||||
|
|
@ -257,12 +267,14 @@ async function previewQuitacao(filtros = {}) {
|
||||||
descricao,
|
descricao,
|
||||||
saldo,
|
saldo,
|
||||||
debito,
|
debito,
|
||||||
habilitado
|
habilitado,
|
||||||
|
idusuarios
|
||||||
FROM bancos
|
FROM bancos
|
||||||
WHERE idbancos = ?
|
WHERE idbancos = ?
|
||||||
|
AND idusuarios = ?
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
`,
|
`,
|
||||||
[idBancoCredito]
|
[idBancoCredito, idUsuario]
|
||||||
);
|
);
|
||||||
|
|
||||||
const bancoCredito = bancoRows[0] || null;
|
const bancoCredito = bancoRows[0] || null;
|
||||||
|
|
@ -278,6 +290,7 @@ async function previewQuitacao(filtros = {}) {
|
||||||
const { whereSql, params } = montarWhereContasPreview({
|
const { whereSql, params } = montarWhereContasPreview({
|
||||||
...filtros,
|
...filtros,
|
||||||
idBancoCredito,
|
idBancoCredito,
|
||||||
|
idUsuario,
|
||||||
});
|
});
|
||||||
|
|
||||||
const [rows] = await pool.query(
|
const [rows] = await pool.query(
|
||||||
|
|
@ -339,7 +352,7 @@ async function previewQuitacao(filtros = {}) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buscarContasSelecionadasParaUpdate(connection, ids) {
|
async function buscarContasSelecionadasParaUpdate(connection, ids, idBancoCredito, idUsuario) {
|
||||||
if (!ids.length) return [];
|
if (!ids.length) return [];
|
||||||
|
|
||||||
const placeholders = ids.map(() => '?').join(', ');
|
const placeholders = ids.map(() => '?').join(', ');
|
||||||
|
|
@ -349,16 +362,23 @@ async function buscarContasSelecionadasParaUpdate(connection, ids) {
|
||||||
SELECT
|
SELECT
|
||||||
cp.*
|
cp.*
|
||||||
FROM contasapagar cp
|
FROM contasapagar cp
|
||||||
|
INNER JOIN bancos b ON b.idbancos = cp.idbancos
|
||||||
WHERE cp.idcontasapagar IN (${placeholders})
|
WHERE cp.idcontasapagar IN (${placeholders})
|
||||||
|
AND cp.idbancos = ?
|
||||||
|
AND b.idusuarios = ?
|
||||||
FOR UPDATE
|
FOR UPDATE
|
||||||
`,
|
`,
|
||||||
ids
|
[
|
||||||
|
...ids,
|
||||||
|
idBancoCredito,
|
||||||
|
idUsuario,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buscarContasDetalhadasPorIds(connection, ids) {
|
async function buscarContasDetalhadasPorIds(connection, ids, idUsuario) {
|
||||||
if (!ids.length) return [];
|
if (!ids.length) return [];
|
||||||
|
|
||||||
const placeholders = ids.map(() => '?').join(', ');
|
const placeholders = ids.map(() => '?').join(', ');
|
||||||
|
|
@ -369,9 +389,10 @@ async function buscarContasDetalhadasPorIds(connection, ids) {
|
||||||
${CAMPOS_CONTA_SELECT}
|
${CAMPOS_CONTA_SELECT}
|
||||||
${FROM_CONTA_JOIN}
|
${FROM_CONTA_JOIN}
|
||||||
WHERE cp.idcontasapagar IN (${placeholders})
|
WHERE cp.idcontasapagar IN (${placeholders})
|
||||||
|
AND b.idusuarios = ?
|
||||||
ORDER BY cp.datavencimento ASC, cp.idcontasapagar ASC
|
ORDER BY cp.datavencimento ASC, cp.idcontasapagar ASC
|
||||||
`,
|
`,
|
||||||
ids
|
[...ids, idUsuario]
|
||||||
);
|
);
|
||||||
|
|
||||||
return rows;
|
return rows;
|
||||||
|
|
@ -405,8 +426,8 @@ async function criarQuitacaoCredito(idUsuario, dados = {}) {
|
||||||
try {
|
try {
|
||||||
await connection.beginTransaction();
|
await connection.beginTransaction();
|
||||||
|
|
||||||
const bancoCredito = await buscarBancoParaUpdate(connection, idBancoCredito);
|
const bancoCredito = await buscarBancoParaUpdate(connection, idBancoCredito, idUsuario);
|
||||||
const bancoPagamento = await buscarBancoParaUpdate(connection, idBancoPagamento);
|
const bancoPagamento = await buscarBancoParaUpdate(connection, idBancoPagamento, idUsuario);
|
||||||
|
|
||||||
if (!bancoCredito) {
|
if (!bancoCredito) {
|
||||||
throw criarErro('Banco de crédito não encontrado.', 404);
|
throw criarErro('Banco de crédito não encontrado.', 404);
|
||||||
|
|
@ -432,7 +453,12 @@ async function criarQuitacaoCredito(idUsuario, dados = {}) {
|
||||||
throw criarErro('O banco de pagamento está desabilitado.');
|
throw criarErro('O banco de pagamento está desabilitado.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const contasAntes = await buscarContasSelecionadasParaUpdate(connection, idsContas);
|
const contasAntes = await buscarContasSelecionadasParaUpdate(
|
||||||
|
connection,
|
||||||
|
idsContas,
|
||||||
|
idBancoCredito,
|
||||||
|
idUsuario
|
||||||
|
);
|
||||||
|
|
||||||
if (contasAntes.length !== idsContas.length) {
|
if (contasAntes.length !== idsContas.length) {
|
||||||
const encontrados = new Set(contasAntes.map((conta) => Number(conta.idcontasapagar)));
|
const encontrados = new Set(contasAntes.map((conta) => Number(conta.idcontasapagar)));
|
||||||
|
|
@ -538,7 +564,7 @@ async function criarQuitacaoCredito(idUsuario, dados = {}) {
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
const contasDepois = await buscarContasDetalhadasPorIds(connection, idsContas);
|
const contasDepois = await buscarContasDetalhadasPorIds(connection, idsContas, idUsuario);
|
||||||
const contasDepoisPorId = new Map(contasDepois.map((conta) => [Number(conta.idcontasapagar), conta]));
|
const contasDepoisPorId = new Map(contasDepois.map((conta) => [Number(conta.idcontasapagar), conta]));
|
||||||
|
|
||||||
for (const contaAntes of contasAntes) {
|
for (const contaAntes of contasAntes) {
|
||||||
|
|
@ -615,15 +641,19 @@ async function criarQuitacaoCredito(idUsuario, dados = {}) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function listarHistorico(filtros = {}) {
|
async function listarHistorico(idUsuario, filtros = {}) {
|
||||||
const limite = limitarNumero(filtros.limite, 20, 1, 100);
|
const limite = limitarNumero(filtros.limite, 20, 1, 100);
|
||||||
const page = limitarNumero(filtros.page, 1, 1, 999999);
|
const page = limitarNumero(filtros.page, 1, 1, 999999);
|
||||||
const offset = filtros.offset !== undefined
|
const offset = filtros.offset !== undefined
|
||||||
? limitarNumero(filtros.offset, 0, 0, 999999999)
|
? limitarNumero(filtros.offset, 0, 0, 999999999)
|
||||||
: (page - 1) * limite;
|
: (page - 1) * limite;
|
||||||
|
|
||||||
const where = ['cq.deleted_at IS NULL'];
|
const where = [
|
||||||
const params = [];
|
'cq.deleted_at IS NULL',
|
||||||
|
'bp.idusuarios = ?',
|
||||||
|
'bc.idusuarios = ?',
|
||||||
|
];
|
||||||
|
const params = [idUsuario, idUsuario];
|
||||||
|
|
||||||
if (filtros.idBancoCredito) {
|
if (filtros.idBancoCredito) {
|
||||||
where.push('cq.idbancos_p = ?');
|
where.push('cq.idbancos_p = ?');
|
||||||
|
|
@ -746,7 +776,7 @@ async function listarHistorico(filtros = {}) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buscarQuitacaoPorId(id) {
|
async function buscarQuitacaoPorId(id, idUsuario) {
|
||||||
const [quitacaoRows] = await pool.query(
|
const [quitacaoRows] = await pool.query(
|
||||||
`
|
`
|
||||||
SELECT
|
SELECT
|
||||||
|
|
@ -768,9 +798,11 @@ async function buscarQuitacaoPorId(id) {
|
||||||
LEFT JOIN bancos bc ON bc.idbancos = cq.idbancos_p
|
LEFT JOIN bancos bc ON bc.idbancos = cq.idbancos_p
|
||||||
LEFT JOIN usuarios u ON u.idusuarios = cq.idusuarios
|
LEFT JOIN usuarios u ON u.idusuarios = cq.idusuarios
|
||||||
WHERE cq.idcontasquitadas = ?
|
WHERE cq.idcontasquitadas = ?
|
||||||
|
AND bp.idusuarios = ?
|
||||||
|
AND bc.idusuarios = ?
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
`,
|
`,
|
||||||
[id]
|
[id, idUsuario, idUsuario]
|
||||||
);
|
);
|
||||||
|
|
||||||
const quitacao = quitacaoRows[0] || null;
|
const quitacao = quitacaoRows[0] || null;
|
||||||
|
|
@ -786,9 +818,10 @@ async function buscarQuitacaoPorId(id) {
|
||||||
${FROM_CONTA_JOIN}
|
${FROM_CONTA_JOIN}
|
||||||
INNER JOIN contasquitadasref cqr ON cqr.idcontasapagar = cp.idcontasapagar
|
INNER JOIN contasquitadasref cqr ON cqr.idcontasapagar = cp.idcontasapagar
|
||||||
WHERE cqr.idcontasquitadas = ?
|
WHERE cqr.idcontasquitadas = ?
|
||||||
|
AND b.idusuarios = ?
|
||||||
ORDER BY cp.datavencimento ASC, cp.idcontasapagar ASC
|
ORDER BY cp.datavencimento ASC, cp.idcontasapagar ASC
|
||||||
`,
|
`,
|
||||||
[id]
|
[id, idUsuario]
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,27 @@ async function listarBancos() {
|
||||||
const [rows] = await pool.query(
|
const [rows] = await pool.query(
|
||||||
`
|
`
|
||||||
SELECT
|
SELECT
|
||||||
idbancos AS id,
|
b.idbancos AS id,
|
||||||
descricao,
|
b.idbancos,
|
||||||
saldo,
|
b.descricao AS banco_descricao,
|
||||||
debito,
|
u.idusuarios,
|
||||||
dia_vencimento
|
u.nome AS usuario_nome,
|
||||||
FROM bancos
|
CONCAT(
|
||||||
WHERE habilitado = 1
|
COALESCE(u.nome, 'Usuário sem nome'),
|
||||||
ORDER BY descricao ASC
|
' - ',
|
||||||
|
b.descricao
|
||||||
|
) AS descricao,
|
||||||
|
b.saldo,
|
||||||
|
b.debito,
|
||||||
|
b.investimento,
|
||||||
|
b.dia_vencimento
|
||||||
|
FROM bancos b
|
||||||
|
LEFT JOIN usuarios u
|
||||||
|
ON u.idusuarios = b.idusuarios
|
||||||
|
WHERE b.habilitado = 1
|
||||||
|
ORDER BY
|
||||||
|
b.descricao ASC,
|
||||||
|
u.nome ASC
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import { NotFoundPage } from '../pages/NotFoundPage';
|
||||||
import { BancosPage } from '../features/bancos/pages/BancosPage';
|
import { BancosPage } from '../features/bancos/pages/BancosPage';
|
||||||
import { NovoBancoPage } from '../features/bancos/pages/NovoBancoPage';
|
import { NovoBancoPage } from '../features/bancos/pages/NovoBancoPage';
|
||||||
import { EditarBancoPage } from '../features/bancos/pages/EditarBancoPage';
|
import { EditarBancoPage } from '../features/bancos/pages/EditarBancoPage';
|
||||||
|
import { RendimentosPage } from '../features/bancos/pages/RendimentosPage';
|
||||||
import { ClientesPage } from '../features/clientes/pages/ClientesPage';
|
import { ClientesPage } from '../features/clientes/pages/ClientesPage';
|
||||||
import { NovoClientePage } from '../features/clientes/pages/NovoClientePage';
|
import { NovoClientePage } from '../features/clientes/pages/NovoClientePage';
|
||||||
import { EditarClientePage } from '../features/clientes/pages/EditarClientePage';
|
import { EditarClientePage } from '../features/clientes/pages/EditarClientePage';
|
||||||
|
|
@ -73,6 +74,10 @@ export const routes: RouteObject[] = [
|
||||||
path: 'bancos/:id/editar',
|
path: 'bancos/:id/editar',
|
||||||
element: <EditarBancoPage />,
|
element: <EditarBancoPage />,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'rendimentos',
|
||||||
|
element: <RendimentosPage />,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'clientes',
|
path: 'clientes',
|
||||||
element: <ClientesPage />,
|
element: <ClientesPage />,
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import DashboardIcon from '@mui/icons-material/Dashboard';
|
||||||
import SwapHorizIcon from '@mui/icons-material/SwapHoriz';
|
import SwapHorizIcon from '@mui/icons-material/SwapHoriz';
|
||||||
import AssessmentIcon from '@mui/icons-material/Assessment';
|
import AssessmentIcon from '@mui/icons-material/Assessment';
|
||||||
import AccountBalanceWalletIcon from '@mui/icons-material/AccountBalanceWallet';
|
import AccountBalanceWalletIcon from '@mui/icons-material/AccountBalanceWallet';
|
||||||
|
import SavingsIcon from '@mui/icons-material/Savings';
|
||||||
import SettingsIcon from '@mui/icons-material/Settings';
|
import SettingsIcon from '@mui/icons-material/Settings';
|
||||||
import PeopleAltIcon from '@mui/icons-material/PeopleAlt';
|
import PeopleAltIcon from '@mui/icons-material/PeopleAlt';
|
||||||
import AccountTreeIcon from '@mui/icons-material/AccountTree';
|
import AccountTreeIcon from '@mui/icons-material/AccountTree';
|
||||||
|
|
@ -49,6 +50,11 @@ const menuItems = [
|
||||||
path: '/bancos',
|
path: '/bancos',
|
||||||
icon: <AccountBalanceWalletIcon />,
|
icon: <AccountBalanceWalletIcon />,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'Rendimentos',
|
||||||
|
path: '/rendimentos',
|
||||||
|
icon: <SavingsIcon />,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'Centros de custo',
|
label: 'Centros de custo',
|
||||||
path: '/centros-custo',
|
path: '/centros-custo',
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ export function BancoForm({ mode, initialData }: BancoFormProps) {
|
||||||
|
|
||||||
const [descricao, setDescricao] = useState('');
|
const [descricao, setDescricao] = useState('');
|
||||||
const [saldo, setSaldo] = useState('0');
|
const [saldo, setSaldo] = useState('0');
|
||||||
const [debito, setDebito] = useState('1');
|
const [tipoCarteira, setTipoCarteira] = useState<'debito' | 'credito' | 'investimento'>('debito');
|
||||||
const [habilitado, setHabilitado] = useState('1');
|
const [habilitado, setHabilitado] = useState('1');
|
||||||
const [diaVencimento, setDiaVencimento] = useState('');
|
const [diaVencimento, setDiaVencimento] = useState('');
|
||||||
|
|
||||||
|
|
@ -124,17 +124,24 @@ export function BancoForm({ mode, initialData }: BancoFormProps) {
|
||||||
|
|
||||||
setDescricao(initialData.descricao || '');
|
setDescricao(initialData.descricao || '');
|
||||||
setSaldo(String(initialData.saldo ?? 0));
|
setSaldo(String(initialData.saldo ?? 0));
|
||||||
setDebito(String(initialData.debito ?? 1));
|
|
||||||
setHabilitado(String(initialData.habilitado ?? 1));
|
setHabilitado(String(initialData.habilitado ?? 1));
|
||||||
setDiaVencimento(
|
setDiaVencimento(
|
||||||
initialData.dia_vencimento ? String(initialData.dia_vencimento) : ''
|
initialData.dia_vencimento ? String(initialData.dia_vencimento) : ''
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (Number(initialData.investimento) === 1) {
|
||||||
|
setTipoCarteira('investimento');
|
||||||
|
} else if (Number(initialData.debito) === 0) {
|
||||||
|
setTipoCarteira('credito');
|
||||||
|
} else {
|
||||||
|
setTipoCarteira('debito');
|
||||||
|
}
|
||||||
}, [initialData]);
|
}, [initialData]);
|
||||||
|
|
||||||
function limparFormulario() {
|
function limparFormulario() {
|
||||||
setDescricao('');
|
setDescricao('');
|
||||||
setSaldo('0');
|
setSaldo('0');
|
||||||
setDebito('1');
|
setTipoCarteira('debito');
|
||||||
setHabilitado('1');
|
setHabilitado('1');
|
||||||
setDiaVencimento('');
|
setDiaVencimento('');
|
||||||
}
|
}
|
||||||
|
|
@ -152,7 +159,7 @@ export function BancoForm({ mode, initialData }: BancoFormProps) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Number(debito) === 0) {
|
if (tipoCarteira === 'credito') {
|
||||||
const dia = Number(diaVencimento);
|
const dia = Number(diaVencimento);
|
||||||
|
|
||||||
if (!diaVencimento || !Number.isInteger(dia) || dia < 1 || dia > 31) {
|
if (!diaVencimento || !Number.isInteger(dia) || dia < 1 || dia > 31) {
|
||||||
|
|
@ -169,9 +176,10 @@ export function BancoForm({ mode, initialData }: BancoFormProps) {
|
||||||
const payload: CriarBancoRequest = {
|
const payload: CriarBancoRequest = {
|
||||||
descricao: descricao.trim(),
|
descricao: descricao.trim(),
|
||||||
saldo: Number(saldo || 0),
|
saldo: Number(saldo || 0),
|
||||||
debito: Number(debito),
|
debito: tipoCarteira === 'credito' ? 0 : 1,
|
||||||
|
investimento: tipoCarteira === 'investimento' ? 1 : 0,
|
||||||
habilitado: Number(habilitado || 1),
|
habilitado: Number(habilitado || 1),
|
||||||
dia_vencimento: Number(debito) === 0 ? Number(diaVencimento) : null,
|
dia_vencimento: tipoCarteira === 'credito' ? Number(diaVencimento) : null,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isEdit) {
|
if (isEdit) {
|
||||||
|
|
@ -281,16 +289,19 @@ export function BancoForm({ mode, initialData }: BancoFormProps) {
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
label="Tipo"
|
label="Tipo"
|
||||||
value={debito}
|
value={tipoCarteira}
|
||||||
onChange={(event) => setDebito(event.target.value)}
|
onChange={(event) =>
|
||||||
|
setTipoCarteira(event.target.value as 'debito' | 'credito' | 'investimento')
|
||||||
|
}
|
||||||
fullWidth
|
fullWidth
|
||||||
sx={fieldSx}
|
sx={fieldSx}
|
||||||
>
|
>
|
||||||
<MenuItem value="1">Débito</MenuItem>
|
<MenuItem value="debito">Débito</MenuItem>
|
||||||
<MenuItem value="0">Crédito</MenuItem>
|
<MenuItem value="credito">Crédito</MenuItem>
|
||||||
|
<MenuItem value="investimento">Investimento</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
|
|
||||||
{Number(debito) === 0 && (
|
{tipoCarteira === 'credito' && (
|
||||||
<TextField
|
<TextField
|
||||||
label="Dia de vencimento"
|
label="Dia de vencimento"
|
||||||
type="number"
|
type="number"
|
||||||
|
|
@ -414,11 +425,15 @@ export function BancoForm({ mode, initialData }: BancoFormProps) {
|
||||||
Tipo
|
Tipo
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography fontWeight={800}>
|
<Typography fontWeight={800}>
|
||||||
{Number(debito) === 1 ? 'Débito' : 'Crédito'}
|
{tipoCarteira === 'investimento'
|
||||||
|
? 'Investimento'
|
||||||
|
: tipoCarteira === 'credito'
|
||||||
|
? 'Crédito'
|
||||||
|
: 'Débito'}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{Number(debito) === 0 && (
|
{tipoCarteira === 'credito' && (
|
||||||
<Box>
|
<Box>
|
||||||
<Typography variant="caption" color="text.secondary">
|
<Typography variant="caption" color="text.secondary">
|
||||||
Dia de vencimento
|
Dia de vencimento
|
||||||
|
|
|
||||||
|
|
@ -61,12 +61,14 @@ function formatarData(data: string | null) {
|
||||||
return new Date(`${String(data).slice(0, 10)}T00:00:00`).toLocaleDateString('pt-BR');
|
return new Date(`${String(data).slice(0, 10)}T00:00:00`).toLocaleDateString('pt-BR');
|
||||||
}
|
}
|
||||||
|
|
||||||
function tipoBancoLabel(debito: number) {
|
function tipoBancoLabel(item: Banco) {
|
||||||
return Number(debito) === 1 ? 'Débito' : 'Crédito';
|
if (Number(item.investimento) === 1) return 'Investimento';
|
||||||
|
return Number(item.debito) === 1 ? 'Débito' : 'Crédito';
|
||||||
}
|
}
|
||||||
|
|
||||||
function tipoBancoColor(debito: number) {
|
function tipoBancoColor(item: Banco) {
|
||||||
return Number(debito) === 1 ? 'success' : 'info';
|
if (Number(item.investimento) === 1) return 'secondary';
|
||||||
|
return Number(item.debito) === 1 ? 'success' : 'info';
|
||||||
}
|
}
|
||||||
|
|
||||||
function statusBancoLabel(habilitado: number) {
|
function statusBancoLabel(habilitado: number) {
|
||||||
|
|
@ -96,8 +98,9 @@ export function BancosPage() {
|
||||||
const [summary, setSummary] = useState<BancosSummary>({
|
const [summary, setSummary] = useState<BancosSummary>({
|
||||||
quantidade: 0,
|
quantidade: 0,
|
||||||
saldoTotal: 0,
|
saldoTotal: 0,
|
||||||
saldoCarteiras: 0,
|
saldoCredito: 0,
|
||||||
saldoDebito: 0,
|
saldoDebito: 0,
|
||||||
|
saldoInvestimento: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
const [alterandoStatusId, setAlterandoStatusId] = useState<number | null>(null);
|
const [alterandoStatusId, setAlterandoStatusId] = useState<number | null>(null);
|
||||||
|
|
@ -108,7 +111,7 @@ export function BancosPage() {
|
||||||
|
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
const [busca, setBusca] = useState('');
|
const [busca, setBusca] = useState('');
|
||||||
const [debito, setDebito] = useState<number | ''>('');
|
const [tipoFiltro, setTipoFiltro] = useState<'' | 'credito' | 'debito' | 'investimento'>('');
|
||||||
const [habilitado, setHabilitado] = useState<number | ''>('');
|
const [habilitado, setHabilitado] = useState<number | ''>('');
|
||||||
const [diaVencimento, setDiaVencimento] = useState<number | ''>('');
|
const [diaVencimento, setDiaVencimento] = useState<number | ''>('');
|
||||||
const [orderBy, setOrderBy] = useState('descricao');
|
const [orderBy, setOrderBy] = useState('descricao');
|
||||||
|
|
@ -121,12 +124,12 @@ export function BancosPage() {
|
||||||
let count = 0;
|
let count = 0;
|
||||||
|
|
||||||
if (busca.trim()) count += 1;
|
if (busca.trim()) count += 1;
|
||||||
if (debito !== '') count += 1;
|
if (tipoFiltro !== '') count += 1;
|
||||||
if (habilitado !== '') count += 1;
|
if (habilitado !== '') count += 1;
|
||||||
if (diaVencimento !== '') count += 1;
|
if (diaVencimento !== '') count += 1;
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}, [busca, debito, habilitado, diaVencimento]);
|
}, [busca, tipoFiltro, habilitado, diaVencimento]);
|
||||||
|
|
||||||
async function carregarBancos(pageToLoad = page) {
|
async function carregarBancos(pageToLoad = page) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -137,7 +140,18 @@ export function BancosPage() {
|
||||||
limite: LIMITE_PADRAO,
|
limite: LIMITE_PADRAO,
|
||||||
page: pageToLoad,
|
page: pageToLoad,
|
||||||
busca: busca.trim() || undefined,
|
busca: busca.trim() || undefined,
|
||||||
debito,
|
debito:
|
||||||
|
tipoFiltro === 'credito'
|
||||||
|
? 0
|
||||||
|
: tipoFiltro === 'debito'
|
||||||
|
? 1
|
||||||
|
: undefined,
|
||||||
|
investimento:
|
||||||
|
tipoFiltro === 'investimento'
|
||||||
|
? 1
|
||||||
|
: tipoFiltro === 'credito' || tipoFiltro === 'debito'
|
||||||
|
? 0
|
||||||
|
: undefined,
|
||||||
habilitado,
|
habilitado,
|
||||||
dia_vencimento: diaVencimento,
|
dia_vencimento: diaVencimento,
|
||||||
orderBy,
|
orderBy,
|
||||||
|
|
@ -168,7 +182,7 @@ export function BancosPage() {
|
||||||
|
|
||||||
function limparFiltros() {
|
function limparFiltros() {
|
||||||
setBusca('');
|
setBusca('');
|
||||||
setDebito('');
|
setTipoFiltro('');
|
||||||
setHabilitado('');
|
setHabilitado('');
|
||||||
setDiaVencimento('');
|
setDiaVencimento('');
|
||||||
setOrderBy('descricao');
|
setOrderBy('descricao');
|
||||||
|
|
@ -303,7 +317,7 @@ export function BancosPage() {
|
||||||
display="grid"
|
display="grid"
|
||||||
gridTemplateColumns={{
|
gridTemplateColumns={{
|
||||||
xs: '1fr',
|
xs: '1fr',
|
||||||
md: 'repeat(4, 1fr)',
|
md: 'repeat(5, 1fr)',
|
||||||
}}
|
}}
|
||||||
gap={{ xs: 2, md: 2.5 }}
|
gap={{ xs: 2, md: 2.5 }}
|
||||||
marginBottom={{ xs: 2.5, md: 3 }}
|
marginBottom={{ xs: 2.5, md: 3 }}
|
||||||
|
|
@ -337,10 +351,10 @@ export function BancosPage() {
|
||||||
<Card>
|
<Card>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<Typography variant="body2" color="text.secondary">
|
<Typography variant="body2" color="text.secondary">
|
||||||
Dívida em crédito
|
Saldo em crédito
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="h5" fontWeight={950} color="success.main">
|
<Typography variant="h5" fontWeight={950} color="info.main">
|
||||||
{formatarValor(summary.saldoCarteiras)}
|
{formatarValor(summary.saldoCredito)}
|
||||||
</Typography>
|
</Typography>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
@ -350,11 +364,22 @@ export function BancosPage() {
|
||||||
<Typography variant="body2" color="text.secondary">
|
<Typography variant="body2" color="text.secondary">
|
||||||
Saldo em débito
|
Saldo em débito
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="h5" fontWeight={950} color="warning.main">
|
<Typography variant="h5" fontWeight={950} color="success.main">
|
||||||
{formatarValor(summary.saldoDebito)}
|
{formatarValor(summary.saldoDebito)}
|
||||||
</Typography>
|
</Typography>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardContent>
|
||||||
|
<Typography variant="body2" color="text.secondary">
|
||||||
|
Investimentos
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="h5" fontWeight={950} color="secondary.main">
|
||||||
|
{formatarValor(summary.saldoInvestimento)}
|
||||||
|
</Typography>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Card sx={{ marginBottom: { xs: 2.5, md: 3 } }}>
|
<Card sx={{ marginBottom: { xs: 2.5, md: 3 } }}>
|
||||||
|
|
@ -382,7 +407,7 @@ export function BancosPage() {
|
||||||
display="grid"
|
display="grid"
|
||||||
gridTemplateColumns={{
|
gridTemplateColumns={{
|
||||||
xs: '1fr',
|
xs: '1fr',
|
||||||
md: 'repeat(4, 1fr)',
|
md: 'repeat(5, 1fr)',
|
||||||
}}
|
}}
|
||||||
gap={{ xs: 2, md: 2.25 }}
|
gap={{ xs: 2, md: 2.25 }}
|
||||||
>
|
>
|
||||||
|
|
@ -397,15 +422,16 @@ export function BancosPage() {
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
label="Tipo"
|
label="Tipo"
|
||||||
value={debito}
|
value={tipoFiltro}
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
setDebito(event.target.value === '' ? '' : Number(event.target.value))
|
setTipoFiltro(event.target.value as '' | 'credito' | 'debito' | 'investimento')
|
||||||
}
|
}
|
||||||
fullWidth
|
fullWidth
|
||||||
>
|
>
|
||||||
<MenuItem value="">Todos</MenuItem>
|
<MenuItem value="">Todos</MenuItem>
|
||||||
<MenuItem value={0}>Crédito</MenuItem>
|
<MenuItem value="credito">Crédito</MenuItem>
|
||||||
<MenuItem value={1}>Débito</MenuItem>
|
<MenuItem value="debito">Débito</MenuItem>
|
||||||
|
<MenuItem value="investimento">Investimento</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
|
|
@ -420,8 +446,12 @@ export function BancosPage() {
|
||||||
max: 31,
|
max: 31,
|
||||||
step: 1,
|
step: 1,
|
||||||
}}
|
}}
|
||||||
disabled={debito === 1}
|
disabled={tipoFiltro !== 'credito'}
|
||||||
helperText={debito === 1 ? 'Disponível apenas para crédito' : 'Filtra bancos de crédito'}
|
helperText={
|
||||||
|
tipoFiltro !== 'credito'
|
||||||
|
? 'Disponível apenas para crédito'
|
||||||
|
: 'Filtra bancos de crédito'
|
||||||
|
}
|
||||||
fullWidth
|
fullWidth
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
@ -550,9 +580,9 @@ export function BancosPage() {
|
||||||
|
|
||||||
<Stack direction="row" flexWrap="wrap" spacing={1} useFlexGap>
|
<Stack direction="row" flexWrap="wrap" spacing={1} useFlexGap>
|
||||||
<Chip
|
<Chip
|
||||||
label={tipoBancoLabel(item.debito)}
|
label={tipoBancoLabel(item)}
|
||||||
size="small"
|
size="small"
|
||||||
color={tipoBancoColor(item.debito) as any}
|
color={tipoBancoColor(item) as any}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
@ -664,9 +694,9 @@ export function BancosPage() {
|
||||||
|
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<Chip
|
<Chip
|
||||||
label={tipoBancoLabel(item.debito)}
|
label={tipoBancoLabel(item)}
|
||||||
size="small"
|
size="small"
|
||||||
color={tipoBancoColor(item.debito) as any}
|
color={tipoBancoColor(item) as any}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -15,6 +15,7 @@ export type ListarBancosParams = {
|
||||||
page?: number;
|
page?: number;
|
||||||
busca?: string;
|
busca?: string;
|
||||||
debito?: number | '';
|
debito?: number | '';
|
||||||
|
investimento?: number | '';
|
||||||
habilitado?: number | '';
|
habilitado?: number | '';
|
||||||
dia_vencimento?: number | '';
|
dia_vencimento?: number | '';
|
||||||
orderBy?: string;
|
orderBy?: string;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
import { api } from '../../../services/api';
|
||||||
|
import type {
|
||||||
|
ApiResponse,
|
||||||
|
ComputarRendimentosRequest,
|
||||||
|
ComputarRendimentosResponse,
|
||||||
|
RendimentosDashboard,
|
||||||
|
RendimentoHistoricoItem,
|
||||||
|
} from '../types/rendimentosTypes';
|
||||||
|
|
||||||
|
export type BuscarRendimentosDashboardParams = {
|
||||||
|
periodoMeses?: number;
|
||||||
|
mesesProjecao?: number;
|
||||||
|
dataInicio?: string;
|
||||||
|
dataFim?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type BuscarHistoricoRendimentosParams = {
|
||||||
|
idbancos?: number | '';
|
||||||
|
periodoMeses?: number;
|
||||||
|
dataInicio?: string;
|
||||||
|
dataFim?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function buscarDashboardRendimentos(
|
||||||
|
params?: BuscarRendimentosDashboardParams
|
||||||
|
): Promise<RendimentosDashboard> {
|
||||||
|
const response = await api.get<ApiResponse<RendimentosDashboard>>(
|
||||||
|
'/bancos/rendimentos/dashboard',
|
||||||
|
{ params }
|
||||||
|
);
|
||||||
|
|
||||||
|
return response.data.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function buscarHistoricoRendimentos(
|
||||||
|
params?: BuscarHistoricoRendimentosParams
|
||||||
|
): Promise<RendimentoHistoricoItem[]> {
|
||||||
|
const response = await api.get<ApiResponse<RendimentoHistoricoItem[]>>(
|
||||||
|
'/bancos/rendimentos/historico',
|
||||||
|
{ params }
|
||||||
|
);
|
||||||
|
|
||||||
|
return response.data.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function computarRendimentos(
|
||||||
|
data: ComputarRendimentosRequest
|
||||||
|
): Promise<ComputarRendimentosResponse> {
|
||||||
|
const response = await api.post<ApiResponse<ComputarRendimentosResponse>>(
|
||||||
|
'/bancos/rendimentos/computar',
|
||||||
|
data
|
||||||
|
);
|
||||||
|
|
||||||
|
return response.data.data;
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
export type Banco = {
|
export type Banco = {
|
||||||
idbancos: number;
|
idbancos: number;
|
||||||
|
idusuarios: number;
|
||||||
descricao: string;
|
descricao: string;
|
||||||
saldo: number;
|
saldo: number;
|
||||||
debito: number;
|
debito: number;
|
||||||
|
investimento: number;
|
||||||
habilitado: number;
|
habilitado: number;
|
||||||
dia_vencimento: number | null;
|
dia_vencimento: number | null;
|
||||||
insert_date: string | null;
|
insert_date: string | null;
|
||||||
|
|
@ -13,6 +15,7 @@ export type CriarBancoRequest = {
|
||||||
descricao: string;
|
descricao: string;
|
||||||
saldo: number;
|
saldo: number;
|
||||||
debito: number;
|
debito: number;
|
||||||
|
investimento: number;
|
||||||
habilitado: number;
|
habilitado: number;
|
||||||
dia_vencimento: number | null;
|
dia_vencimento: number | null;
|
||||||
};
|
};
|
||||||
|
|
@ -30,8 +33,9 @@ export type BancosPagination = {
|
||||||
export type BancosSummary = {
|
export type BancosSummary = {
|
||||||
quantidade: number;
|
quantidade: number;
|
||||||
saldoTotal: number;
|
saldoTotal: number;
|
||||||
saldoCarteiras: number;
|
saldoCredito: number;
|
||||||
saldoDebito: number;
|
saldoDebito: number;
|
||||||
|
saldoInvestimento: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ApiResponse<T> = {
|
export type ApiResponse<T> = {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,155 @@
|
||||||
|
export type BancoInvestimentoProjecao = {
|
||||||
|
idbancos: number;
|
||||||
|
banco_descricao: string;
|
||||||
|
saldo_atual: number;
|
||||||
|
taxa_media_mensal: number;
|
||||||
|
meses_base: number;
|
||||||
|
meses_projecao: number;
|
||||||
|
saldo_projetado: number;
|
||||||
|
rendimento_projetado: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type BancoInvestimento = {
|
||||||
|
idbancos: number;
|
||||||
|
descricao: string;
|
||||||
|
saldo: number;
|
||||||
|
debito: number;
|
||||||
|
investimento: number;
|
||||||
|
habilitado: number;
|
||||||
|
update_date: string | null;
|
||||||
|
ultima_apuracao: string | null;
|
||||||
|
rendimento_periodo?: number;
|
||||||
|
percentual_medio_periodo?: number;
|
||||||
|
projecao?: BancoInvestimentoProjecao | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RendimentoHistoricoItem = {
|
||||||
|
idbancossaldoauditoria: number;
|
||||||
|
idbancos: number;
|
||||||
|
banco_descricao: string;
|
||||||
|
idcontasapagar: number | null;
|
||||||
|
tipo_operacao: string | null;
|
||||||
|
origem: string | null;
|
||||||
|
valor_delta: number;
|
||||||
|
saldo_anterior: number;
|
||||||
|
saldo_posterior: number;
|
||||||
|
descricao: string | null;
|
||||||
|
insert_date: string;
|
||||||
|
percentual: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RendimentoSerieMensal = {
|
||||||
|
idbancos: number;
|
||||||
|
banco_descricao: string;
|
||||||
|
competencia: string;
|
||||||
|
rendimento: number;
|
||||||
|
saldo_final: number;
|
||||||
|
eventos: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RendimentoRankingItem = {
|
||||||
|
idbancos: number;
|
||||||
|
banco_descricao: string;
|
||||||
|
rendimento_total: number;
|
||||||
|
quantidade_eventos: number;
|
||||||
|
soma_percentual: number;
|
||||||
|
percentual_medio: number;
|
||||||
|
maior_rendimento: {
|
||||||
|
valor_delta: number;
|
||||||
|
percentual: number;
|
||||||
|
insert_date: string;
|
||||||
|
} | null;
|
||||||
|
menor_rendimento: {
|
||||||
|
valor_delta: number;
|
||||||
|
percentual: number;
|
||||||
|
insert_date: string;
|
||||||
|
} | null;
|
||||||
|
primeira_data: string;
|
||||||
|
ultima_data: string;
|
||||||
|
saldo_atual: number;
|
||||||
|
participacao_rendimento: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RendimentosProjecao = {
|
||||||
|
meses_projecao: number;
|
||||||
|
saldo_atual_total: number;
|
||||||
|
saldo_projetado_total: number;
|
||||||
|
rendimento_projetado_total: number;
|
||||||
|
taxa_media_mensal_total: number;
|
||||||
|
bancos: BancoInvestimentoProjecao[];
|
||||||
|
observacao: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RendimentosGraficos = {
|
||||||
|
barrasMensal: Array<Record<string, string | number>>;
|
||||||
|
saldoMensal: Array<Record<string, string | number>>;
|
||||||
|
rendimentoAcumulado: Array<Record<string, string | number>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RendimentosResumo = {
|
||||||
|
totalInvestidoAtual: number;
|
||||||
|
rendimentoPeriodo: number;
|
||||||
|
rendimentoMedioPercentual: number;
|
||||||
|
quantidadeBancos: number;
|
||||||
|
melhorBanco: RendimentoRankingItem | null;
|
||||||
|
projecao12Meses?: {
|
||||||
|
saldoProjetado: number;
|
||||||
|
rendimentoProjetado: number;
|
||||||
|
taxaMediaMensal: number;
|
||||||
|
} | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RendimentosDashboard = {
|
||||||
|
resumo: RendimentosResumo;
|
||||||
|
bancos: BancoInvestimento[];
|
||||||
|
historico: RendimentoHistoricoItem[];
|
||||||
|
seriesMensais: RendimentoSerieMensal[];
|
||||||
|
ranking: RendimentoRankingItem[];
|
||||||
|
projecao: RendimentosProjecao;
|
||||||
|
graficos: RendimentosGraficos;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ComputarRendimentoItemRequest = {
|
||||||
|
idbancos: number;
|
||||||
|
novoSaldo: number;
|
||||||
|
descricao?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ComputarRendimentosRequest = {
|
||||||
|
data?: string;
|
||||||
|
descricao?: string;
|
||||||
|
confirmarDuplicado?: boolean;
|
||||||
|
itens: ComputarRendimentoItemRequest[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ComputarRendimentoResultado = {
|
||||||
|
ok: boolean;
|
||||||
|
ignorado?: boolean;
|
||||||
|
idbancos: number;
|
||||||
|
banco_descricao?: string;
|
||||||
|
saldo_anterior?: number;
|
||||||
|
saldo_posterior?: number;
|
||||||
|
valor_delta?: number;
|
||||||
|
percentual?: number;
|
||||||
|
message?: string;
|
||||||
|
movimento?: any;
|
||||||
|
impactoSaldo?: any[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ComputarRendimentosResponse = {
|
||||||
|
processados: ComputarRendimentoResultado[];
|
||||||
|
ignorados: ComputarRendimentoResultado[];
|
||||||
|
erros: ComputarRendimentoResultado[];
|
||||||
|
resumo: {
|
||||||
|
quantidadeProcessada: number;
|
||||||
|
quantidadeIgnorada: number;
|
||||||
|
quantidadeErro: number;
|
||||||
|
totalRendimento: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ApiResponse<T> = {
|
||||||
|
ok: boolean;
|
||||||
|
message?: string;
|
||||||
|
data: T;
|
||||||
|
};
|
||||||
|
|
@ -291,7 +291,7 @@ export function QuitacoesCreditoPage() {
|
||||||
});
|
});
|
||||||
|
|
||||||
setSucesso(
|
setSucesso(
|
||||||
`Quitação realizada com sucesso. Valor quitado: ${formatarValor(response.valor)}.`
|
`Quitação realizada com sucesso. Valor quitado: ${formatarValor(response.valorQuitado)}.`
|
||||||
);
|
);
|
||||||
|
|
||||||
setImpactoSaldo(response.impactoSaldo || []);
|
setImpactoSaldo(response.impactoSaldo || []);
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ export type QuitacaoCreditoResponse = {
|
||||||
idcontasquitadas: number;
|
idcontasquitadas: number;
|
||||||
idbancos: number;
|
idbancos: number;
|
||||||
idbancos_p: number;
|
idbancos_p: number;
|
||||||
valor: number;
|
valorQuitado: number;
|
||||||
descricao: string | null;
|
descricao: string | null;
|
||||||
data_quitacao: string | null;
|
data_quitacao: string | null;
|
||||||
contasQuitadas?: ContaCreditoQuitacao[];
|
contasQuitadas?: ContaCreditoQuitacao[];
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue