financeiro/financeiro-api/src/modules/movimentosFixos/services/movimentosFixos.service.js

395 lines
8.9 KiB
JavaScript
Raw Normal View History

const pool = require('../../../database/mysql');
const CAMPOS_MOVIMENTO_FIXO_SELECT = `
mf.idmovimentosfixos,
mf.movimento,
mf.descricao,
mf.valor,
mf.dia_vencimento,
mf.idcentrodecustos,
mf.habilitado,
mf.idbancos,
mf.insert_date,
mf.update_date,
b.descricao AS banco_descricao,
cc.descricao AS centro_custo_descricao
`;
const FROM_MOVIMENTO_FIXO_JOIN = `
FROM movimentosfixos mf
LEFT JOIN bancos b ON b.idbancos = mf.idbancos
LEFT JOIN centrodecustos cc ON cc.idcentrodecustos = mf.idcentrodecustos
`;
function normalizarTextoOuNull(valor) {
if (valor === undefined || valor === null || valor === '') {
return null;
}
return String(valor).trim();
}
function normalizarNumeroOuNull(valor) {
if (valor === undefined || valor === null || valor === '') {
return null;
}
const numero = Number(valor);
if (!Number.isFinite(numero)) {
return null;
}
return numero;
}
function normalizarNumero(valor, padrao = 0) {
if (valor === undefined || valor === null || valor === '') {
return padrao;
}
const numero = Number(valor);
if (!Number.isFinite(numero)) {
return padrao;
}
return numero;
}
function normalizarFlag(valor, padrao = 0) {
if (valor === undefined || valor === null || valor === '') {
return padrao;
}
return Number(valor) === 1 ? 1 : 0;
}
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 resolverOrdenacao(orderBy) {
const camposPermitidos = {
idmovimentosfixos: 'mf.idmovimentosfixos',
movimento: 'mf.movimento',
descricao: 'mf.descricao',
valor: 'mf.valor',
dia_vencimento: 'mf.dia_vencimento',
idcentrodecustos: 'mf.idcentrodecustos',
idbancos: 'mf.idbancos',
habilitado: 'mf.habilitado',
insert_date: 'mf.insert_date',
update_date: 'mf.update_date',
banco_descricao: 'b.descricao',
centro_custo_descricao: 'cc.descricao',
};
return camposPermitidos[orderBy] || 'mf.dia_vencimento';
}
function resolverDirecao(orderDirection) {
return String(orderDirection || '').toUpperCase() === 'DESC' ? 'DESC' : 'ASC';
}
function montarWhereMovimentosFixos(filtros = {}) {
const where = [];
const params = [];
if (filtros.movimento) {
where.push('mf.movimento = ?');
params.push(filtros.movimento);
}
if (filtros.idbancos) {
where.push('mf.idbancos = ?');
params.push(Number(filtros.idbancos));
}
if (filtros.idcentrodecustos) {
where.push('mf.idcentrodecustos = ?');
params.push(Number(filtros.idcentrodecustos));
}
if (filtros.habilitado !== undefined && filtros.habilitado !== null && filtros.habilitado !== '') {
where.push('mf.habilitado = ?');
params.push(Number(filtros.habilitado));
}
if (filtros.diaInicio) {
where.push('mf.dia_vencimento >= ?');
params.push(Number(filtros.diaInicio));
}
if (filtros.diaFim) {
where.push('mf.dia_vencimento <= ?');
params.push(Number(filtros.diaFim));
}
if (filtros.busca) {
where.push(`
(
mf.descricao LIKE ?
OR mf.movimento LIKE ?
OR b.descricao LIKE ?
OR cc.descricao LIKE ?
)
`);
const termo = `%${String(filtros.busca).trim()}%`;
params.push(
termo,
termo,
termo,
termo
);
}
const whereSql = where.length > 0 ? `WHERE ${where.join(' AND ')}` : '';
return {
whereSql,
params,
};
}
async function listarMovimentosFixos(filtros = {}) {
const limite = limitarNumero(filtros.limite, 20, 1, 100);
const page = limitarNumero(filtros.page, 1, 1, 999999);
const offset = filtros.offset !== undefined
? limitarNumero(filtros.offset, 0, 0, 999999999)
: (page - 1) * limite;
const orderBy = resolverOrdenacao(filtros.orderBy);
const orderDirection = resolverDirecao(filtros.orderDirection);
const { whereSql, params } = montarWhereMovimentosFixos(filtros);
const [rows] = await pool.query(
`
SELECT
${CAMPOS_MOVIMENTO_FIXO_SELECT}
${FROM_MOVIMENTO_FIXO_JOIN}
${whereSql}
ORDER BY ${orderBy} ${orderDirection}, mf.idmovimentosfixos ASC
LIMIT ? OFFSET ?
`,
[...params, limite, offset]
);
const [countRows] = await pool.query(
`
SELECT COUNT(*) AS total
${FROM_MOVIMENTO_FIXO_JOIN}
${whereSql}
`,
params
);
const [summaryRows] = await pool.query(
`
SELECT
COUNT(*) AS quantidade,
COALESCE(SUM(mf.valor), 0) AS valorTotal,
COALESCE(SUM(CASE WHEN mf.movimento = 'Entrada' THEN mf.valor ELSE 0 END), 0) AS totalEntradas,
COALESCE(SUM(CASE WHEN mf.movimento = 'Saida' THEN mf.valor ELSE 0 END), 0) AS totalSaidas,
COALESCE(SUM(CASE WHEN mf.movimento = 'Sangria' THEN mf.valor ELSE 0 END), 0) AS totalSangrias,
COALESCE(SUM(CASE WHEN mf.movimento = 'Estorno' THEN mf.valor ELSE 0 END), 0) AS totalEstornos,
COALESCE(SUM(CASE WHEN mf.habilitado = 1 THEN 1 ELSE 0 END), 0) AS habilitados,
COALESCE(SUM(CASE WHEN mf.habilitado = 0 THEN 1 ELSE 0 END), 0) AS desabilitados
${FROM_MOVIMENTO_FIXO_JOIN}
${whereSql}
`,
params
);
const total = Number(countRows[0]?.total || 0);
const totalPages = Math.max(1, Math.ceil(total / limite));
return {
data: rows,
pagination: {
total,
limite,
offset,
page: Math.floor(offset / limite) + 1,
totalPages,
},
summary: {
quantidade: Number(summaryRows[0]?.quantidade || 0),
valorTotal: Number(summaryRows[0]?.valorTotal || 0),
totalEntradas: Number(summaryRows[0]?.totalEntradas || 0),
totalSaidas: Number(summaryRows[0]?.totalSaidas || 0),
totalSangrias: Number(summaryRows[0]?.totalSangrias || 0),
totalEstornos: Number(summaryRows[0]?.totalEstornos || 0),
habilitados: Number(summaryRows[0]?.habilitados || 0),
desabilitados: Number(summaryRows[0]?.desabilitados || 0),
},
};
}
async function buscarMovimentoFixoPorId(id) {
const [rows] = await pool.query(
`
SELECT
${CAMPOS_MOVIMENTO_FIXO_SELECT}
${FROM_MOVIMENTO_FIXO_JOIN}
WHERE mf.idmovimentosfixos = ?
LIMIT 1
`,
[id]
);
return rows[0] || null;
}
async function criarMovimentoFixo(dados) {
const {
movimento,
descricao,
valor,
dia_vencimento,
idcentrodecustos,
habilitado,
idbancos,
} = dados;
const [result] = await pool.query(
`
INSERT INTO movimentosfixos (
movimento,
descricao,
valor,
dia_vencimento,
idcentrodecustos,
habilitado,
idbancos,
insert_date,
update_date
) VALUES (?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
`,
[
normalizarTextoOuNull(movimento),
normalizarTextoOuNull(descricao),
normalizarNumero(valor, 0),
normalizarNumero(dia_vencimento, 1),
normalizarNumeroOuNull(idcentrodecustos),
normalizarFlag(habilitado, 1),
normalizarNumeroOuNull(idbancos),
]
);
return buscarMovimentoFixoPorId(result.insertId);
}
async function atualizarMovimentoFixo(id, dados) {
const movimentoAtual = await buscarMovimentoFixoPorId(id);
if (!movimentoAtual) {
return null;
}
const {
movimento,
descricao,
valor,
dia_vencimento,
idcentrodecustos,
habilitado,
idbancos,
} = dados;
await pool.query(
`
UPDATE movimentosfixos
SET
movimento = ?,
descricao = ?,
valor = ?,
dia_vencimento = ?,
idcentrodecustos = ?,
habilitado = ?,
idbancos = ?,
update_date = NOW()
WHERE idmovimentosfixos = ?
`,
[
normalizarTextoOuNull(movimento),
normalizarTextoOuNull(descricao),
normalizarNumero(valor, 0),
normalizarNumero(dia_vencimento, 1),
normalizarNumeroOuNull(idcentrodecustos),
normalizarFlag(habilitado, 1),
normalizarNumeroOuNull(idbancos),
id,
]
);
return buscarMovimentoFixoPorId(id);
}
async function alterarHabilitadoMovimentoFixo(id, habilitado) {
const movimentoAtual = await buscarMovimentoFixoPorId(id);
if (!movimentoAtual) {
return null;
}
await pool.query(
`
UPDATE movimentosfixos
SET
habilitado = ?,
update_date = NOW()
WHERE idmovimentosfixos = ?
`,
[
normalizarFlag(habilitado, 1),
id,
]
);
return buscarMovimentoFixoPorId(id);
}
async function deletarMovimentoFixo(id) {
const movimentoAtual = await buscarMovimentoFixoPorId(id);
if (!movimentoAtual) {
return false;
}
await pool.query(
`
DELETE FROM movimentosfixos
WHERE idmovimentosfixos = ?
`,
[id]
);
return true;
}
module.exports = {
listarMovimentosFixos,
buscarMovimentoFixoPorId,
criarMovimentoFixo,
atualizarMovimentoFixo,
alterarHabilitadoMovimentoFixo,
deletarMovimentoFixo,
};