import { useState, useMemo, useEffect, useCallback, useRef } from 'react'; import { useToast } from './useToast'; import { workspaceReceitasService } from '@/services/workspaceReceitasService'; import { workspaceEntradasPlanejadasService } from '@/services/workspaceEntradasPlanejadasService'; import { extratoService } from '@/services/extratoService'; import { parseCurrency } from '@/utils/dateUtils'; // Mock Transactions (Entradas focus) com datas padronizadas const MOCK_TRANSACTIONS = Array.from({ length: 50 }, (_, i) => { const day = String((i % 30) + 1).padStart(2, '0'); return { id: `REC-${2000 + i}`, dataEntrada: `2026-01-${day}`, descricao: i % 2 === 0 ? `Pagamento Boleto ${i}` : `Serviço Consultoria ${i}`, cliente: i % 3 === 0 ? 'Cliente A LTDA' : (i % 3 === 1 ? 'B Services' : 'Cliente C Comércio'), categoria: ['Venda de Produto', 'Serviços', 'Receita Financeira', 'Outros'][i % 4], valor: (Math.random() * 3000 + 500).toFixed(2), status: i % 4 === 0 ? 'Pendente' : 'Recebido' }; }).map(item => ({ ...item, valor: parseFloat(item.valor) })); // Mock Clients com dados mais realistas const MOCK_CLIENTS = [ { id: 1, nome: 'Sr. Daivid Alves', nome_exibicao: 'Novas industrias', email: 'Novas.industrias@gmail.com', status_serv: 'Ativo', telefone: '21995882003', caixinha: '1', cpf_cnpj: '12.345.678/0001-90', endereco: 'Rua 1 lote 15 do vilar gunabara', bairro: 'Vilar Gunabara', cidade: 'Rio de Janeiro', uf: 'RJ', cep: '2214214-650', dominio: 'novasindustrias.com.br', tipo_pessoa: 'JURIDICA', data_vencimento: 30, obs: 'Cliente premium desde 2020. Excelente histórico de pagamento. Contato preferencial via e-mail.', valor_servico: 45840940.00, contasReceber: 45840940.00, creditosNaoUtilizados: 46.20 }, { id: 2, nome: 'Tech Solutions Ltda', nome_exibicao: 'Tech Solutions', email: 'contato@techsolutions.com.br', status_serv: 'Ativo', telefone: '(11) 3456-7890', caixinha: '2', cpf_cnpj: '23.456.789/0001-12', endereco: 'Av. Paulista, 1578', bairro: 'Bela Vista', cidade: 'São Paulo', uf: 'SP', cep: '01310-200', dominio: 'techsolutions.com.br', tipo_pessoa: 'JURIDICA', data_vencimento: 15, obs: 'Empresa de tecnologia com foco em soluções corporativas. Cliente desde 2019.', valor_servico: 125000.00, contasReceber: 125000.00, creditosNaoUtilizados: 0.00 }, { id: 3, nome: 'Logística Rápida S.A.', nome_exibicao: 'Logística Rápida', email: 'financeiro@logisticarapida.com.br', status_serv: 'Ativo', telefone: '(21) 2345-6789', caixinha: '3', cpf_cnpj: '34.567.890/0001-23', endereco: 'Rua do Comércio, 450', bairro: 'Centro', cidade: 'Rio de Janeiro', uf: 'RJ', cep: '20010-000', dominio: 'logisticarapida.com.br', tipo_pessoa: 'JURIDICA', data_vencimento: 20, obs: 'Empresa de logística com operações em todo Brasil. Contrato anual renovado.', valor_servico: 250000.00, contasReceber: 250000.00, creditosNaoUtilizados: 150.00 }, { id: 4, nome: 'Indústrias Metalúrgicas ABC', nome_exibicao: 'Metalúrgicas ABC', email: 'contato@metalurgicasabc.com.br', status_serv: 'Ativo', telefone: '(11) 9876-5432', caixinha: '4', cpf_cnpj: '45.678.901/0001-34', endereco: 'Rodovia dos Bandeirantes, Km 45', bairro: 'Distrito Industrial', cidade: 'Campinas', uf: 'SP', cep: '13000-000', dominio: 'metalurgicasabc.com.br', tipo_pessoa: 'JURIDICA', data_vencimento: 30, obs: 'Grande indústria metalúrgica. Cliente estratégico com volume alto de transações.', valor_servico: 890000.20, contasReceber: 890000.20, creditosNaoUtilizados: 0.00 }, { id: 5, nome: 'B Services', nome_exibicao: 'B Services', email: 'admin@cliente-b.br', status_serv: 'Inativo', telefone: '(21) 8888-8888', caixinha: '5', cpf_cnpj: '98.765.432/0001-11', endereco: 'Av. Brasil, 500', bairro: 'Copacabana', cidade: 'Rio de Janeiro', uf: 'RJ', cep: '20000-000', dominio: 'bservices.com', tipo_pessoa: 'JURIDICA', data_vencimento: 15, obs: 'Aguardando renovação de contrato. Cliente em análise de crédito.', valor_servico: 750.00, contasReceber: 750.00, creditosNaoUtilizados: 0.00 }, ]; // Mock Services com mais opções const MOCK_SERVICES = [ { idservicos: 1, servico: 'Suporte Técnico Premium', valor: 750.00, descricao: 'Suporte técnico 24/7 com SLA garantido' }, { idservicos: 2, servico: 'VPS Custom', valor: 300.00, descricao: 'Servidor virtual personalizado com recursos dedicados' }, { idservicos: 3, servico: 'Hospedagem Cloud', valor: 150.00, descricao: 'Hospedagem em nuvem com alta disponibilidade' }, { idservicos: 4, servico: 'Consultoria em TI', valor: 2000.00, descricao: 'Consultoria especializada em transformação digital' }, { idservicos: 5, servico: 'Desenvolvimento Custom', valor: 5000.00, descricao: 'Desenvolvimento de software sob medida' }, { idservicos: 6, servico: 'Backup Automatizado', valor: 100.00, descricao: 'Sistema de backup automático diário' }, ]; // Mock Boletos com dados completos conforme imagem const MOCK_BOLETOS = [ { id: 1, pagador: 'Grupo Pralog', emitido: '2026-01-05', vencimento: '2026-01-10', tipoCobranca: 'SIMPLES', valorNominal: 4800.00, totalRecebido: 4800.00, status: 'RECEBIDO', banco: 'Banco do Brasil', descricao: 'Pagamento de serviços', numero: 'BOL-000001' }, { id: 2, pagador: 'ENSEG Participações', emitido: '2026-01-08', vencimento: '2026-01-15', tipoCobranca: 'RECORRENTE', valorNominal: 3500.00, totalRecebido: 3500.00, status: 'RECEBIDO', banco: 'Itaú', descricao: 'Mensalidade recorrente', numero: 'BOL-000002' }, { id: 3, pagador: 'Tech Solutions Ltda', emitido: '2026-01-10', vencimento: '2026-01-20', tipoCobranca: 'SIMPLES', valorNominal: 1500.00, totalRecebido: 0.00, status: 'VENCIDO', banco: 'Banco do Brasil', descricao: 'Consultoria em TI', numero: 'BOL-000003' }, { id: 4, pagador: 'Logística Rápida S.A.', emitido: '2026-01-12', vencimento: '2026-01-25', tipoCobranca: 'RECORRENTE', valorNominal: 12300.00, totalRecebido: 12300.00, status: 'RECEBIDO', banco: 'Itaú', descricao: 'Mensalidade de serviços', numero: 'BOL-000004' }, { id: 5, pagador: 'Indústrias Metalúrgicas ABC', emitido: '2026-01-15', vencimento: '2026-01-30', tipoCobranca: 'SIMPLES', valorNominal: 8900.20, totalRecebido: 0.00, status: 'VENCIDO', banco: 'Bradesco', descricao: 'Desenvolvimento Custom', numero: 'BOL-000005' }, { id: 6, pagador: 'B Services', emitido: '2026-01-18', vencimento: '2026-02-05', tipoCobranca: 'SIMPLES', valorNominal: 1200.00, totalRecebido: 0.00, status: 'PENDENTE', banco: 'Banco do Brasil', descricao: 'Renovação de contrato', numero: 'BOL-000006' }, { id: 7, pagador: 'Sr. Daivid Alves', emitido: '2026-01-20', vencimento: '2026-02-10', tipoCobranca: 'RECORRENTE', valorNominal: 2500.00, totalRecebido: 2500.00, status: 'MARCADO_RECEBIDO', banco: 'Banco do Brasil', descricao: 'Pagamento marcado', numero: 'BOL-000007' }, { id: 8, pagador: 'Tech Solutions Ltda', emitido: '2026-01-22', vencimento: '2026-02-15', tipoCobranca: 'SIMPLES', valorNominal: 500.00, totalRecebido: 0.00, status: 'CANCELADO', banco: 'Santander', descricao: 'Serviço cancelado', numero: 'BOL-000008' }, { id: 9, pagador: 'Logística Rápida S.A.', emitido: '2026-01-25', vencimento: '2026-02-20', tipoCobranca: 'PIX', valorNominal: 3565.80, totalRecebido: 3565.80, status: 'PIX', banco: 'Itaú', descricao: 'Pagamento via Pix', numero: 'BOL-000009' }, { id: 10, pagador: 'Grupo Pralog', emitido: '2026-01-28', vencimento: '2026-02-25', tipoCobranca: 'PIX', valorNominal: 4800.00, totalRecebido: 4800.00, status: 'PIX', banco: 'Banco do Brasil', descricao: 'Pagamento Pix', numero: 'BOL-000010' }, // Adicionar mais boletos para melhor visualização { id: 11, pagador: 'ENSEG Participações', emitido: '2026-01-03', vencimento: '2026-01-08', tipoCobranca: 'SIMPLES', valorNominal: 8200.00, totalRecebido: 0.00, status: 'VENCIDO', banco: 'Bradesco', descricao: 'Pagamento em atraso', numero: 'BOL-000011' }, { id: 12, pagador: 'Indústrias Metalúrgicas ABC', emitido: '2026-01-06', vencimento: '2026-01-12', tipoCobranca: 'RECORRENTE', valorNominal: 6300.00, totalRecebido: 0.00, status: 'VENCIDO', banco: 'Itaú', descricao: 'Mensalidade atrasada', numero: 'BOL-000012' }, { id: 13, pagador: 'Grupo Pralog', emitido: '2026-01-07', vencimento: '2026-01-14', tipoCobranca: 'SIMPLES', valorNominal: 2400.00, totalRecebido: 0.00, status: 'CANCELADO', banco: 'Santander', descricao: 'Boleto cancelado', numero: 'BOL-000013' }, { id: 14, pagador: 'Tech Solutions Ltda', emitido: '2026-01-09', vencimento: '2026-01-18', tipoCobranca: 'RECORRENTE', valorNominal: 5500.00, totalRecebido: 5500.00, status: 'RECEBIDO', banco: 'Banco do Brasil', descricao: 'Pagamento recebido', numero: 'BOL-000014' }, { id: 15, pagador: 'Logística Rápida S.A.', emitido: '2026-01-11', vencimento: '2026-01-22', tipoCobranca: 'PIX', valorNominal: 1800.00, totalRecebido: 1800.00, status: 'PIX', banco: 'Itaú', descricao: 'Pix recebido', numero: 'BOL-000015' }, ]; export const useContasReceber = (defaultView = 'default') => { const toast = useToast(); // Normalização de alias const normalizeSubView = (view) => { if (!view) return 'default'; if (view === 'boletos-pendentes') return 'boletos'; return view; }; const initialSubView = useMemo(() => normalizeSubView(defaultView), [defaultView]); const [activeSubView, setActiveSubView] = useState(initialSubView); // 'default' | 'servicos' | 'clientes' | 'entradas-planejadas' | 'boletos' // Atualizar view quando a prop mudar useEffect(() => { if (defaultView) { setActiveSubView(normalizeSubView(defaultView)); } }, [defaultView]); const [transactions, setTransactions] = useState([]); const [cruzamentoLoading, setCruzamentoLoading] = useState(true); const [clients, setClients] = useState([]); const [services, setServices] = useState([]); const [entradasPlanejadas, setEntradasPlanejadas] = useState([]); const [boletos, setBoletos] = useState(MOCK_BOLETOS || []); const [isLoadingServicos, setIsLoadingServicos] = useState(false); const [isLoadingClients, setIsLoadingClients] = useState(false); const [isLoadingEntradasPlanejadas, setIsLoadingEntradasPlanejadas] = useState(false); const [isLoadingItens, setIsLoadingItens] = useState(false); const [itensEntradaSelecionada, setItensEntradaSelecionada] = useState([]); const [categorias, setCategorias] = useState([]); const [caixas, setCaixas] = useState([]); // Cruzamento: alimentado por /api/extrato/apresentar (tipoOperacao C). Planejado zerado. useEffect(() => { let cancelled = false; setCruzamentoLoading(true); extratoService .fetchExtrato() .then((raw) => { if (cancelled) return; const list = Array.isArray(raw) ? raw : []; const receitas = list .filter((item) => item.tipoOperacao === 'C') .map((item) => ({ id: item.idextrato ?? item.id, idextrato: item.idextrato, dataEntrada: item.dataEntrada || '', descricao: item.descricao || item.titulo || '', valor: Math.abs(parseCurrency(item.valor || 0)), categoria: item.categoria ?? 'Sem Categoria', caixinha: item.caixinha ?? '', status: 'Recebido', beneficiario_pagador: item.beneficiario_pagador, tipoTransacao: item.tipoTransacao })); setTransactions(receitas); }) .catch((err) => { if (!cancelled) { console.error('[useContasReceber] Erro ao carregar extrato para cruzamento:', err); setTransactions([]); } }) .finally(() => { if (!cancelled) setCruzamentoLoading(false); }); return () => { cancelled = true; }; }, []); useEffect(() => { let cancelled = false; Promise.all([extratoService.fetchCategorias(), extratoService.fetchCaixinhas()]) .then(([cats, cxs]) => { if (cancelled) return; setCategorias(Array.isArray(cats) ? cats : []); setCaixas(Array.isArray(cxs) ? cxs : []); }) .catch(() => { if (!cancelled) { setCategorias([]); setCaixas([]); } }); return () => { cancelled = true; }; }, []); /** Carrega serviços do backend (GET /servicos/list ou /servicos/list?tipo=...). */ const loadServicos = useCallback(async (tipo) => { setIsLoadingServicos(true); try { const data = await workspaceReceitasService.fetchServicos(tipo); const servicesList = Array.isArray(data) ? data : []; setServices(servicesList); return servicesList; } catch (err) { console.warn('[useContasReceber] Erro ao carregar serviços:', err); toast.error('Erro ao carregar serviços'); setServices([]); return []; } finally { setIsLoadingServicos(false); } }, [toast]); /** Carrega clientes do backend (GET /empresas_financeiro). */ const loadClients = useCallback(async () => { setIsLoadingClients(true); try { const data = await workspaceReceitasService.fetchClientes(); setClients(Array.isArray(data) ? data : []); } catch (err) { console.warn('[useContasReceber] Erro ao carregar clientes:', err); toast.error('Erro ao carregar clientes'); setClients([]); } finally { setIsLoadingClients(false); } }, [toast]); /** Carrega entradas planejadas do backend (GET /empresas_planejadas). */ const loadEntradasPlanejadas = useCallback(async () => { setIsLoadingEntradasPlanejadas(true); try { const data = await workspaceEntradasPlanejadasService.fetchEntradasPlanejadas(); setEntradasPlanejadas(Array.isArray(data) ? data : []); } catch (err) { console.warn('[useContasReceber] Erro ao carregar entradas planejadas:', err); toast.error('Erro ao carregar entradas planejadas'); setEntradasPlanejadas([]); } finally { setIsLoadingEntradasPlanejadas(false); } }, [toast]); // Executa uma única vez no mount; ref evita reexecução mesmo com Strict Mode ou dependências instáveis const didLoadReceitas = useRef(false); useEffect(() => { if (didLoadReceitas.current) return; didLoadReceitas.current = true; loadServicos(); loadClients(); loadEntradasPlanejadas(); }, [loadServicos, loadClients, loadEntradasPlanejadas]); // Derived States seguros const totalRecebido = useMemo(() => { if (!Array.isArray(transactions)) return 0; return transactions .filter(t => t?.status === 'Recebido' || t?.status === 'Liquidado' || t?.status === 'Marcado como Recebido') .reduce((acc, t) => acc + (t?.valor || 0), 0); }, [transactions]); // Cruzamento: lado planejado alimentado por entradasPlanejadas; executado por extrato (transactions). const totalPendente = useMemo(() => { if (!Array.isArray(entradasPlanejadas)) return 0; return entradasPlanejadas.reduce((acc, item) => acc + (Number(item.total || 0)), 0); }, [entradasPlanejadas]); const totalGeral = totalRecebido + totalPendente; // Actions para Serviços const parseValor = useCallback((v) => { if (v == null || v === '') return NaN; const n = typeof v === 'number' ? v : Number(String(v).replace(',', '.')); return Number.isFinite(n) ? n : NaN; }, []); const formatDataEnvio = useCallback((dateStr) => { if (!dateStr) return ''; const d = new Date(dateStr); if (Number.isNaN(d.getTime())) return ''; const y = d.getFullYear(); const m = d.getMonth() + 1; const day = d.getDate(); return `${y}-${m}-${day}`; }, []); const createService = useCallback(async (serviceData) => { if (!serviceData.servico?.trim()) { toast.error('Nome do serviço é obrigatório', 'Campos Obrigatórios'); return null; } const valor = parseValor(serviceData.valor); if (valor <= 0 || !Number.isFinite(valor)) { toast.error('Valor do serviço deve ser maior que zero', 'Validação'); return null; } try { const payload = { servico: serviceData.servico.trim(), valor, imagem: serviceData.imagem ?? '', tipo_servico: serviceData.tipo_servico || 'Serviço' }; await workspaceReceitasService.createServico(payload); await loadServicos(); toast.success('Serviço criado com sucesso!', 'Sucesso'); return true; } catch (err) { console.warn('[useContasReceber] Erro ao criar serviço:', err); toast.error('Erro ao criar serviço. Tente novamente.'); return null; } }, [loadServicos, toast, parseValor]); const updateService = useCallback(async (id, serviceData) => { if (!serviceData.servico?.trim()) { toast.error('Nome do serviço é obrigatório', 'Campos Obrigatórios'); return null; } const valor = parseValor(serviceData.valor); if (valor <= 0 || !Number.isFinite(valor)) { toast.error('Valor do serviço deve ser maior que zero', 'Validação'); return null; } try { const payload = { idservicos: Number(id), servico: serviceData.servico.trim(), valor, imagem: serviceData.imagem ?? '', tipo_servico: serviceData.tipo_servico || 'Serviço' }; await workspaceReceitasService.editServico(payload); await loadServicos(); toast.success('Serviço atualizado com sucesso!', 'Sucesso'); return true; } catch (err) { console.warn('[useContasReceber] Erro ao editar serviço:', err); toast.error('Erro ao editar serviço. Tente novamente.'); return null; } }, [loadServicos, toast, parseValor]); const deleteService = useCallback(async (id) => { try { await workspaceReceitasService.deleteServico({ idservicos: Number(id) }); await loadServicos(); toast.success('Serviço excluído com sucesso!', 'Sucesso'); return true; } catch (err) { console.warn('[useContasReceber] Erro ao excluir serviço:', err); toast.error('Erro ao excluir serviço. Tente novamente.'); return null; } }, [loadServicos, toast]); // Actions para Clientes const createClient = useCallback(async (clientData) => { const camposObrigatorios = []; if (!clientData.nome?.trim()) camposObrigatorios.push('Nome'); if (!clientData.email?.trim()) camposObrigatorios.push('Email'); if (!clientData.cpf_cnpj?.trim()) camposObrigatorios.push('CPF/CNPJ'); if (camposObrigatorios.length > 0) { toast.notifyFields(camposObrigatorios); return null; } setIsLoadingClients(true); try { const response = await workspaceReceitasService.createClient(clientData); await loadClients(); toast.success('Cliente criado com sucesso!', 'Sucesso'); return response; } catch (err) { console.warn('[useContasReceber] Erro ao criar cliente:', err); toast.handleBackendError(err); return null; } finally { setIsLoadingClients(false); } }, [loadClients, toast]); const updateClient = useCallback(async (id, clientData) => { const camposObrigatorios = []; if (!clientData.nome?.trim()) camposObrigatorios.push('Nome'); if (!clientData.email?.trim()) camposObrigatorios.push('Email'); if (!clientData.cpf_cnpj?.trim()) camposObrigatorios.push('CPF/CNPJ'); if (camposObrigatorios.length > 0) { toast.notifyFields(camposObrigatorios); return false; } setIsLoadingClients(true); try { await workspaceReceitasService.updateClient({ ...clientData, idempresa: id }); await loadClients(); toast.success('Cliente atualizado com sucesso!', 'Sucesso'); return true; } catch (err) { console.warn('[useContasReceber] Erro ao atualizar cliente:', err); toast.handleBackendError(err); return false; } finally { setIsLoadingClients(false); } }, [loadClients, toast]); const updateClientStatus = useCallback(async (id, status) => { setIsLoadingClients(true); try { await workspaceReceitasService.updateClientStatus({ idempresa: id, status, data_envio: formatDataEnvio(new Date()) }); await loadClients(); toast.success(`Status do cliente alterado para ${status}!`, 'Sucesso'); return true; } catch (err) { console.warn('[useContasReceber] Erro ao alterar status do cliente:', err); toast.handleBackendError(err); return false; } finally { setIsLoadingClients(false); } }, [loadClients, toast, formatDataEnvio]); const deleteClient = useCallback(async (id) => { // Nota: O service não tem deleteClient explicitamente, geralmente é feito via status Inativo // Mas podemos implementar se houver rota. Como não vi rota de delete no service, usarei updateStatus return updateClientStatus(id, 'Inativo'); }, [updateClientStatus]); const loadItensEntradaPlanejada = useCallback(async (idEntrada) => { if (!idEntrada) return; setIsLoadingItens(true); try { const itens = await workspaceEntradasPlanejadasService.fetchItensEntradaPlanejada(idEntrada); setItensEntradaSelecionada(itens); return itens; } catch (err) { console.warn('[useContasReceber] Erro ao carregar itens da entrada:', err); toast.error('Erro ao carregar itens. Tente novamente.'); return []; } finally { setIsLoadingItens(false); } }, [toast]); // Actions para Entradas Planejadas const createEntradaPlanejada = useCallback(async (entradaData) => { const camposObrigatorios = []; if (!entradaData.dataEstimativa) camposObrigatorios.push('Data Estimativa'); if (!entradaData.cliente?.trim()) camposObrigatorios.push('Cliente'); if (!entradaData.vendedor?.trim()) camposObrigatorios.push('Vendedor'); if (!entradaData.itens || entradaData.itens.length === 0) camposObrigatorios.push('Itens'); if (camposObrigatorios.length > 0) { toast.notifyFields(camposObrigatorios); return null; } setIsLoadingEntradasPlanejadas(true); try { const { itens, ...parentData } = entradaData; const response = await workspaceEntradasPlanejadasService.createEntradaPlanejada(parentData); let idEntrada = response?.id || response?.idempresa || response?.identradas_planejadas || response?.Base_Dados_API?.[0]?.id || (response?.Base_Dados_API && response.Base_Dados_API.id); if (!idEntrada) { console.log('[useContasReceber] ID não retornado, consultando listagem para capturar ID...'); const list = await workspaceEntradasPlanejadasService.fetchEntradasPlanejadas(); const matched = list.find(e => String(e.numeroReferencia) === String(parentData.numeroReferencia) && e.cliente === parentData.cliente ); idEntrada = matched?.id || matched?.idempresa || matched?.identradas_planejadas; } if (!idEntrada) { console.warn('[useContasReceber] ID da entrada não encontrado:', response); await loadEntradasPlanejadas(); toast.error('Entrada criada, mas houve um problema ao vincular itens.'); return false; } const itemPromises = itens.map(item => workspaceEntradasPlanejadasService.createItemEntradaPlanejada({ ...item, idEntrada: idEntrada }) ); await Promise.all(itemPromises); await loadEntradasPlanejadas(); toast.success('Entrada e itens criados com sucesso!', 'Sucesso'); return true; } catch (err) { console.warn('[useContasReceber] Erro ao criar entrada planejada:', err); toast.error('Erro ao criar entrada planejada.'); return false; } finally { setIsLoadingEntradasPlanejadas(false); } }, [loadEntradasPlanejadas, toast]); const updateEntradaPlanejada = useCallback(async (id, entradaData) => { const camposObrigatorios = []; if (!entradaData.dataEstimativa) camposObrigatorios.push('Data Estimativa'); if (!entradaData.cliente?.trim()) camposObrigatorios.push('Cliente'); if (!entradaData.vendedor?.trim()) camposObrigatorios.push('Vendedor'); if (!entradaData.itens || entradaData.itens.length === 0) camposObrigatorios.push('Itens'); if (camposObrigatorios.length > 0) { toast.notifyFields(camposObrigatorios); return false; } setIsLoadingEntradasPlanejadas(true); try { const { itens, ...parentData } = entradaData; const idempresa = parentData.idempresa || id; await workspaceEntradasPlanejadasService.updateEntradaPlanejada(idempresa, parentData); const itemPromises = itens.map(item => { const idItem = item.identradas_planejadas_itens || item.id; if (idItem && typeof idItem === 'number') { return workspaceEntradasPlanejadasService.updateItemEntradaPlanejada(idItem, { ...item, idEntrada: idempresa }); } else { return workspaceEntradasPlanejadasService.createItemEntradaPlanejada({ ...item, idEntrada: idempresa }); } }); await Promise.all(itemPromises); await loadEntradasPlanejadas(); toast.success('Entrada planejada atualizada com sucesso!', 'Sucesso'); return true; } catch (err) { console.warn('[useContasReceber] Erro ao atualizar entrada planejada:', err); toast.error('Erro ao atualizar entrada planejada.'); return false; } finally { setIsLoadingEntradasPlanejadas(false); } }, [loadEntradasPlanejadas, toast]); const deleteEntradaPlanejada = useCallback(async (id) => { try { await workspaceEntradasPlanejadasService.deleteEntradaPlanejada(id); await loadEntradasPlanejadas(); toast.success('Entrada planejada excluída com sucesso!', 'Sucesso'); return true; } catch (err) { console.warn('[useContasReceber] Erro ao excluir entrada planejada:', err); toast.error('Erro ao excluir entrada planejada.'); return null; } }, [loadEntradasPlanejadas, toast]); // Actions para Boletos const downloadBoleto = useCallback((boletoId) => { console.log('Download boleto:', boletoId); }, []); const sendBoleto = useCallback((boletoId) => { console.log('Enviar boleto:', boletoId); }, []); const scheduleBoleto = useCallback((boletoId, newDate) => { setBoletos(prev => prev.map(b => b.id === boletoId ? { ...b, dataVencimento: newDate } : b)); }, []); const downloadFatura = useCallback((boletoId) => { console.log('Download fatura:', boletoId); }, []); const actions = useMemo(() => ({ setActiveSubView, loadServicos, loadClients, loadEntradasPlanejadas, // Serviços createService, updateService, deleteService, // Clientes createClient, updateClient, updateClientStatus, deleteClient, // Entradas Planejadas createEntradaPlanejada, updateEntradaPlanejada, deleteEntradaPlanejada, loadItensEntradaPlanejada, setItensEntradaSelecionada, // Boletos downloadBoleto, sendBoleto, scheduleBoleto, downloadFatura, }), [ setActiveSubView, loadServicos, loadClients, loadEntradasPlanejadas, createService, updateService, deleteService, createClient, updateClient, updateClientStatus, deleteClient, createEntradaPlanejada, updateEntradaPlanejada, deleteEntradaPlanejada, loadItensEntradaPlanejada, setItensEntradaSelecionada, downloadBoleto, sendBoleto, scheduleBoleto, downloadFatura ]); return { state: { activeSubView, transactions: transactions || [], clients: clients || [], services: services || [], entradasPlanejadas: entradasPlanejadas || [], itensEntradaSelecionada, boletos: boletos || [], isLoadingServicos, isLoadingClients, isLoadingEntradasPlanejadas, isLoadingItens, cruzamentoLoading, kpis: { totalRecebido, totalPendente, totalGeral }, categorias: categorias || [], caixas: caixas || [] }, actions }; };