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>} */ 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>} */ 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} */ 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} */ 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 : [] }; } }) };