testes/src/services/extratoService.js

417 lines
14 KiB
JavaScript

import api from './api';
import { handleRequest, simulateLatency } from './serviceUtils';
/**
* Service de Extrato para financeiro-v2
* Alimenta as telas de cruzamento (receitas e despesas) com /api/extrato/apresentar.
* tipoOperacao: "C" = receitas (entradas), "D" = despesas (saídas).
*/
export const extratoService = {
/**
* Busca extrato bancário
* Rota: GET /extrato/apresentar
* Retorna array bruto; o consumidor filtra por tipoOperacao (C/D).
* @param {Object} params - Opcional { mes, ano }
* @returns {Promise<Array<{idextrato, dataEntrada, descricao, valor, tipoOperacao, categoria, beneficiario_pagador, ...}>>}
*/
fetchExtrato: (params) => handleRequest({
mockFn: () => simulateLatency([]),
apiFn: async () => {
const response = await api.get('/extrato/apresentar', { params });
const raw = response?.data ?? response;
// Lógica robusta de extração (igual ao workspaceConciliacaoService)
// Prioridade: dados -> Base_Dados_API -> raw (se array) -> Object.values(raw)
let data = raw?.dados ?? raw?.Base_Dados_API ?? raw;
if (!Array.isArray(data)) {
// Se for objeto (ex: { '0': {...}, '1': {...} }), converte para array
data = Object.values(data || {});
}
return Array.isArray(data) ? data : [];
}
}),
/**
* Categorias (opcional, para labels)
* Rota: GET /categorias/apresentar
*/
fetchCategorias: () => handleRequest({
mockFn: () => simulateLatency([]),
apiFn: async () => {
const response = await api.get('/categorias/apresentar');
const raw = response?.data ?? response;
let data = raw?.dados ?? raw?.Base_Dados_API ?? raw;
if (!Array.isArray(data)) {
data = Object.values(data || {});
}
return Array.isArray(data) ? data : [];
}
}),
/**
* Caixinhas (opcional, para labels)
* Rota: GET /caixinhas/apresentar
*/
fetchCaixinhas: () => handleRequest({
mockFn: () => simulateLatency([]),
apiFn: async () => {
const response = await api.get('/caixinhas/apresentar');
const raw = response?.data ?? response;
let data = raw?.dados ?? raw?.Base_Dados_API ?? raw;
if (!Array.isArray(data)) {
data = Object.values(data || {});
}
return Array.isArray(data) ? data : [];
}
}),
/**
* Saldo atual da conta
* Rota: GET /saldo
* Resposta: { bloqueado?, disponivel, total? }
* @returns {Promise<{ disponivel: number, bloqueado?: number, total?: number }>}
*/
fetchSaldo: () => handleRequest({
mockFn: () => simulateLatency({ disponivel: 0, bloqueado: null, total: null }),
apiFn: async () => {
const response = await api.get('/saldo');
// Tenta extrair de varias formas, pois saldo costuma variar a estrutura
const raw = response?.data ?? response;
const data = raw?.dados ?? raw?.Base_Dados_API ?? raw ?? {};
const num = (v) => (v != null && v !== '' ? Number(v) : null);
// Procura propriedade disponivel/saldo/valor em data ou no raw
const disponivel = num(data.disponivel) ?? num(data.saldo) ?? num(data.valor) ??
num(raw.disponivel) ?? num(raw.saldo) ?? num(raw.valor) ??
(typeof data === 'number' ? data : 0);
return {
disponivel: Number(disponivel) || 0,
bloqueado: num(data.bloqueado ?? raw.bloqueado),
total: num(data.total ?? raw.total)
};
}
}),
/**
* Saldos armazenados (histórico)
* Rota: GET /saldo/armazenado/apresentar
* Pode retornar array ou objeto único { data_saldo, saldo_disponivel, ... }.
* Usado para obter último saldo do mês passado (cruzamento fluxo de caixa).
* @returns {Promise<Array<{ data?: string, data_saldo?: string, mes?: number, ano?: number, saldo?: number, saldo_disponivel?: string, ... }>>}
*/
fetchSaldoArmazenado: () => handleRequest({
mockFn: () => simulateLatency([]),
apiFn: async () => {
const response = await api.get('/saldo/armazenado/apresentar');
const raw = response?.data ?? response;
let list = raw?.dados ?? raw?.Base_Dados_API ?? raw;
if (!Array.isArray(list)) {
if (list && typeof list === 'object' && list !== null) {
const keys = Object.keys(list);
const isSingleRecord = keys.some(k => k === 'data_saldo' || k === 'saldo_disponivel' || k === 'idsaldos_mensais');
if (isSingleRecord) {
list = [list];
} else {
// Tenta converter objeto indexado em array
list = Object.values(list).map(v => typeof v === 'object' ? v : { saldo: v });
}
} else {
list = [];
}
}
return list.map((item) => {
const data = item.data ?? item.dataSaldo ?? item.data_saldo ?? item.data_armazenado;
const d = data ? new Date(data) : null;
const valid = d && !Number.isNaN(d.getTime());
const saldoVal = item.saldo_disponivel ?? item.saldo ?? item.valor;
const saldo = typeof saldoVal === 'string' ? Number(saldoVal.replace(',', '.')) : Number(saldoVal ?? 0);
return {
...item,
data: data ?? null,
data_saldo: item.data_saldo ?? data,
mes: item.mes ?? (valid ? d.getMonth() + 1 : null),
ano: item.ano ?? (valid ? d.getFullYear() : null),
saldo: Number.isFinite(saldo) ? saldo : 0
};
});
}
}),
/**
* Fluxo de entrada e saída mensal
* Rota: GET /extrato/fluxo
* Retorna dados mensais de entrada e saída
* @param {Object} params - Opcional { mes, ano }
* @returns {Promise<{ mensal: Array<{ mes, ano, entrada, saida, ... }> }>}
*/
fetchFluxo: (params) => handleRequest({
mockFn: () => simulateLatency({ mensal: [], anual: [], diario: [] }),
apiFn: async () => {
const response = await api.get('/extrato/fluxo', { params });
const raw = response?.data ?? response;
const data = raw?.dados ?? raw?.Base_Dados_API ?? raw ?? {};
const mensal = data.mensal ?? raw.mensal ?? [];
const anual = data.anual ?? raw.anual ?? [];
const diario = data.diario ?? raw.diario ?? [];
const toArray = (obj) => Array.isArray(obj) ? obj : (obj ? Object.values(obj) : []);
return {
mensal: toArray(mensal),
anual: toArray(anual),
diario: toArray(diario)
};
}
}),
/**
* Busca soma por categoria
* Rota: GET /extrato/soma_por_categoria
* @param {Object} params - { mes, ano, tipoOperacao }
*/
getSomaPorCategoria: (params) => handleRequest({
mockFn: () => simulateLatency([]),
apiFn: async () => {
const response = await api.get('/extrato/soma_por_categoria', { params });
return response?.data ?? response;
}
}),
/**
* Exporta extrato em PDF
* Rota: GET /extrato/pdf
*/
exportPDF: () => handleRequest({
mockFn: () => simulateLatency(new Blob(['PDF mock'], { type: 'application/pdf' })),
apiFn: async () => {
const response = await api.get('/extrato/pdf', {
responseType: 'blob'
});
return response.data;
}
}),
/**
* Busca navegação hierárquica detalhada por caixinha
* Rota: GET /extrato/apresentar/caixinha/detalhado
* @param {Object} params - { caixinha, mes, ano }
*/
getCaixinhaDetalhada: (params) => handleRequest({
mockFn: () => simulateLatency({}),
apiFn: async () => {
const response = await api.get('/extrato/apresentar/caixinha/detalhado', {
params
});
return response.data;
}
}),
/**
* Busca saldo consolidado com entradas e saídas do mês vigente e saldo anterior
* Rota: GET /saldo/entradas_mes_mais_ultimo_saldo
* @param {Object} params - { mes, ano }
*/
fetchSaldoConsolidado: (params) => handleRequest({
mockFn: () => simulateLatency({ entradas: 0, saidas: 0, saldo_anterior: 0, saldo_atual: 0, lista_entradas: [] }),
apiFn: async () => {
const response = await api.get('/saldo/entradas_mes_mais_ultimo_saldo', { params });
return response?.data ?? response;
}
}),
/**
* Busca empresas/clientes financeiros
* Rota: GET /empresas_financeiro
* @returns {Promise<Array>}
*/
fetchEmpresas: () => handleRequest({
mockFn: () => simulateLatency([]),
apiFn: async () => {
const response = await api.get('/empresas_financeiro');
const raw = response?.data ?? response;
let data = raw?.dados ?? raw?.Base_Dados_API ?? raw;
if (!Array.isArray(data)) {
data = Object.values(data || {});
}
return Array.isArray(data) ? data : [];
}
}),
/**
* Busca dados de recebimento de juros (mensal e anual)
* Rota: GET /extrato/mensal_anual
* @returns {Promise<{ mensal: Array, anual: Array }>}
*/
fetchJuros: () => handleRequest({
mockFn: () => simulateLatency({ mensal: [], anual: [] }),
apiFn: async () => {
const response = await api.get('/extrato/mensal_anual');
return response?.data ?? response;
}
}),
/**
* Busca soma de recebimentos via PIX para o painel
* Rota: GET /extrato/pix
*/
fetchPixSoma: () => handleRequest({
mockFn: () => simulateLatency({ total: 0, quantidade: 0 }),
apiFn: async () => {
const response = await api.get('/extrato/pix');
return response?.data ?? response;
}
}),
/**
* Busca lista de itens recebidos via PIX para apresentar
* Rota: GET /extrato/pix/apresentar
*/
fetchPixApresentar: () => handleRequest({
mockFn: () => simulateLatency([]),
apiFn: async () => {
const response = await api.get('/extrato/pix/apresentar');
const raw = response?.data ?? response;
let data = raw?.dados ?? raw?.Base_Dados_API ?? raw;
if (!Array.isArray(data)) {
data = Object.values(data || {});
}
return Array.isArray(data) ? data : [];
}
}),
/**
* Busca dados detalhados de PIX por empresa
* Rota: GET /extrato/pix/empresas
* @param {Object} params - { mes, ano } (opcional)
* @returns {Promise<Array>}
*/
fetchPixEmpresas: (params) => handleRequest({
mockFn: () => simulateLatency([]),
apiFn: async () => {
const response = await api.get('/extrato/pix/empresas', { params });
const raw = response?.data ?? response;
let data = raw?.dados ?? raw?.Base_Dados_API ?? raw;
if (!Array.isArray(data)) {
data = Object.values(data || {});
}
return Array.isArray(data) ? data : [];
}
}),
/**
* Busca totais de entradas planejadas para o painel de cruzamento
* Rota: GET /financeiro/resumo_mes
* @param {Object} params - { mes, ano }
*/
fetchEntradasPlanejadasTotal: (params) => handleRequest({
mockFn: () => simulateLatency({
mes: Number(params.mes),
ano: Number(params.ano),
total_planejado: 0,
total_boletos_a_receber: 0,
total_planejado_geral: 0,
total_realizado: 0,
diferenca: 0
}),
apiFn: async () => {
const response = await api.get('/financeiro/resumo_mes', { params });
return response?.data ?? response;
}
}),
/**
* Busca dados para o gráfico de planejado vs executado (Receitas)
* Rota: GET /extrato/planejado/grafico
* @param {Object} params - { dia, mes, ano }
*/
fetchPlanejadoGrafico: (params) => handleRequest({
mockFn: () => simulateLatency({ filtro: params, grafico: [] }),
apiFn: async () => {
const response = await api.get('/extrato/planejado/grafico', { params });
return response?.data ?? response;
}
}),
/**
* Busca totais de despesas planejadas para o painel de cruzamento
* Rota: GET /financeiro/despesas_mes
* @param {Object} params - { mes, ano }
*/
fetchDespesasResumo: (params) => handleRequest({
mockFn: () => simulateLatency({
mes: Number(params.mes),
ano: Number(params.ano),
total_planejado: 0,
total_realizado: 0,
diferenca: 0
}),
apiFn: async () => {
const response = await api.get('/financeiro/despesas_mes', { params });
return response?.data ?? response;
}
}),
/**
* Busca dados para o gráfico de planejado vs executado (Despesas)
* Rota: GET /extrato/despesas/grafico
* @param {Object} params - { dia, mes, ano }
*/
fetchDespesasGrafico: (params) => handleRequest({
mockFn: () => simulateLatency({ filtro: params, grafico: [] }),
apiFn: async () => {
const response = await api.get('/extrato/despesas/grafico', { params });
return response?.data ?? response;
}
}),
/**
* Busca detalhamento de juros adicionados
* Rota: GET /extrato/adicionado
* @param {Object} params - { mes, ano }
*/
fetchJurosAdicionados: (params) => handleRequest({
mockFn: () => simulateLatency({ adicionado: [], total_adicionado: 0, total_registros: 0 }),
apiFn: async () => {
const response = await api.get('/extrato/adicionado', { params });
return response?.data ?? response;
}
}),
/**
* Busca transações de um beneficiário específico
* Rota: POST /beneficiario_aplicado
* Resposta esperada: { "categoria": "NOME DO CLIENTE", "linha_tempo": [...] }
* Retorna: { categoria: string, linhaTemp: Array }
* @param {string} beneficiario_pagador
*/
fetchBeneficiarioAplicado: (beneficiario_pagador) => handleRequest({
mockFn: () => simulateLatency({ categoria: '', linha_tempo: [] }),
apiFn: async () => {
const response = await api.post('/beneficiario_aplicado', {
beneficiario_pagador: beneficiario_pagador
});
const raw = response?.data ?? response;
// A resposta é um objeto com "categoria" e "linha_tempo"
const root = raw?.dados ?? raw?.Base_Dados_API ?? raw;
const categoria = root?.categoria ?? '';
const linhaTemp = root?.linha_tempo ?? [];
return {
categoria,
linha_tempo: Array.isArray(linhaTemp) ? linhaTemp : []
};
}
})
};