// Caririaçu Guincho — Financeiro Screen const { useState: useStateFin, useEffect: useEffectFin } = React; const FinanceiroScreen = () => { const [transacoes, setTransacoes] = useStateFin([]); const [categorias, setCategorias] = useStateFin([]); const [motoristas, setMotoristas] = useStateFin([]); const [loading, setLoading] = useStateFin(true); const [modal, setModal] = useStateFin(false); const [holModal, setHolModal] = useStateFin(false); const [filtroTipo, setFiltroTipo] = useStateFin(''); const [busca, setBusca] = useStateFin(''); const [page, setPage] = useStateFin(1); const PER = 6; const [form, setForm] = useStateFin({ tipo: 'entrada', descricao: '', categoria: 'Serviço Prestado', valor: '', data: new Date().toISOString().slice(0,10), assistencia_numero: '', obs: '' }); const set = (k,v) => setForm(f => ({...f,[k]:v})); const fmtBRL = v => Number(v || 0).toLocaleString('pt-BR',{style:'currency',currency:'BRL'}); const refresh = async () => { setLoading(true); const [t, c, m] = await Promise.all([ db.list('transacoes', { order: 'data' }), db.list('categorias_financeiras', { order: 'nome', asc: true }), db.list('motoristas', { order: 'nome', asc: true }) ]); setTransacoes(t); setCategorias(c); setMotoristas(m); setLoading(false); }; useEffectFin(() => { refresh(); }, []); const entradas = transacoes.filter(t=>t.tipo==='entrada').reduce((s,t)=>s+Number(t.valor||0),0); const saidas = transacoes.filter(t=>t.tipo==='saida').reduce((s,t)=>s+Number(t.valor||0),0); const saldo = entradas - saidas; const hoje = new Date().toISOString().slice(0,10); const caixaDia = transacoes.filter(t => t.data === hoje).reduce((s,t)=>s+(t.tipo==='entrada'?Number(t.valor||0):-Number(t.valor||0)),0); const filtered = transacoes.filter(t => { const q = busca.toLowerCase(); const mQ = !q || t.descricao.toLowerCase().includes(q) || (t.categoria || '').toLowerCase().includes(q); const mT = !filtroTipo || t.tipo === filtroTipo; return mQ && mT; }); const paged = filtered.slice((page-1)*PER, page*PER); const handleSave = async () => { if (!form.descricao || !form.valor) { showToast('Preencha descrição e valor', 'warning'); return; } const created = await db.insert('transacoes', { tipo: form.tipo, descricao: form.descricao, categoria: form.categoria, valor: parseFloat(form.valor) || 0, data: form.data, obs: form.obs, assistencia_numero: form.assistencia_numero || null, }); if (created) { showToast('Transação registrada!','success'); setModal(false); setForm({ tipo:'entrada', descricao:'', categoria:'Serviço Prestado', valor:'', data:new Date().toISOString().slice(0,10), assistencia_numero:'', obs:'' }); refresh(); } }; const handleDelete = async (id) => { const ok = await db.remove('transacoes', id); if (ok) { showToast('Transação removida','warning'); refresh(); } }; // Holerite const [holForm, setHolForm] = useStateFin({ motoristaId: '', periodo: new Date().toISOString().slice(0,7), salarioBase: '', adicionais: '', descontos: '', }); useEffectFin(() => { if (motoristas.length > 0 && !holForm.motoristaId) setHolForm(f => ({ ...f, motoristaId: motoristas[0].id })); }, [motoristas]); const setHol = (k,v) => setHolForm(f => ({...f,[k]:v})); const holLiquido = (parseFloat(holForm.salarioBase) || 0) + (parseFloat(holForm.adicionais) || 0) - (parseFloat(holForm.descontos) || 0); const holMotorista = motoristas.find(m => m.id === parseInt(holForm.motoristaId)) || motoristas[0] || {}; const gerarHoleritePDF = () => { if (!holMotorista.id) { showToast('Cadastre um motorista antes', 'warning'); return; } const fmt = v => (parseFloat(v) || 0).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); const [ano, mes] = (holForm.periodo || '').split('-'); const meses = ['Janeiro','Fevereiro','Março','Abril','Maio','Junho','Julho','Agosto','Setembro','Outubro','Novembro','Dezembro']; const periodoLabel = mes ? `${meses[parseInt(mes)-1]} de ${ano}` : holForm.periodo; const numHolerite = `HOL-${Date.now().toString().slice(-6)}`; const dataEmissao = new Date().toLocaleDateString('pt-BR'); const html = `Holerite ${holMotorista.nome} — ${periodoLabel}
Nº ${numHolerite}
${dataEmissao}
Período
${periodoLabel}
Funcionário
${holMotorista.nome}
Cargo
Motorista de Guincho

Dados do Funcionário

Nome Completo
${holMotorista.nome}
CNH
${holMotorista.cnh || '—'} · Cat. ${holMotorista.categoria || '—'}
Telefone
${holMotorista.telefone || '—'}
Guincho
${holMotorista.guincho_code || '—'}

Composição do Salário

DescriçãoReferênciaValor
Salário Base30 diasR$ ${fmt(holForm.salarioBase)}
Adicionais (HE / Bonificação)+ R$ ${fmt(holForm.adicionais)}
Descontos (INSS / IRRF / Outros)− R$ ${fmt(holForm.descontos)}
Total de VencimentosR$ ${fmt((parseFloat(holForm.salarioBase)||0) + (parseFloat(holForm.adicionais)||0))}
Total de DescontosR$ ${fmt(holForm.descontos)}
VALOR LÍQUIDO A RECEBERR$ ${fmt(holLiquido)}
Assinatura do Funcionário
Assinatura da Empresa
`; const win = window.open('', '_blank', 'width=860,height=900'); if (!win) { showToast('Habilite popups para gerar o PDF','warning'); return; } win.document.write(html); win.document.close(); showToast('Holerite gerado','success'); setHolModal(false); }; const CATS_ENT = ['Serviço Prestado','Reembolso Seguradora','Outros']; const CATS_SAI = ['Combustível','Manutenção','Salários','Seguros','Impostos','Outros']; const opcoesCat = form.tipo === 'entrada' ? CATS_ENT : CATS_SAI; return (

Financeiro

Controle de entradas, saídas e holerites
setHolModal(true)}>Gerar Holerite setModal(true)}>Nova Transação
Total Entradas
{fmtBRL(entradas)}
Total Saídas
{fmtBRL(saidas)}
Saldo
= 0 ? '#10B981' : '#EF4444', fontFamily: 'DM Mono, monospace' }}>{fmtBRL(saldo)}
Hoje
= 0 ? '#10B981' : '#EF4444', fontFamily: 'DM Mono, monospace' }}>{fmtBRL(caixaDia)}
{ setBusca(e.target.value); setPage(1); }} placeholder="Buscar transação..." style={{ width: '100%', paddingLeft: 34, paddingRight: 12, paddingTop: 9, paddingBottom: 9, borderRadius: 8, border: '1px solid #E2E8F0', fontSize: 13, color: '#0F172A', fontFamily: 'Inter, sans-serif', outline: 'none', boxSizing: 'border-box' }} />
{loading ? (
Carregando...
) : paged.length === 0 ? (
{transacoes.length === 0 ? 'Nenhuma transação registrada' : 'Nenhum resultado'}
{transacoes.length === 0 ? 'Comece registrando entradas e saídas' : 'Tente ajustar os filtros'}
) : ( {['Data','Descrição','Categoria','Tipo','Valor','Ações'].map(h=>( ))} {paged.map((t,i)=>( ))}
{h}
{new Date(t.data).toLocaleDateString('pt-BR')} {t.descricao} {t.categoria || '—'} {t.tipo==='entrada'?'+ ':'− '}R$ {Number(t.valor).toFixed(2)}
)}
Mostrando {Math.min(filtered.length, PER)} de {filtered.length} registros
setModal(false)} title="Nova Transação" width={520}>
set('data',e.target.value)}/>
set('descricao',e.target.value)}/>
set('valor',e.target.value)}/>
set('assistencia_numero',e.target.value)}/> set('obs',e.target.value)}/>
setModal(false)}>Cancelar Registrar
setHolModal(false)} title="Gerar Holerite" width={460}>
{motoristas.length === 0 ? (
Cadastre um motorista antes de gerar holerite.
) : ( <> setHol('periodo', e.target.value)}/> setHol('salarioBase', e.target.value)}/> setHol('adicionais', e.target.value)}/> setHol('descontos', e.target.value)}/>
Salário Base{fmtBRL(parseFloat(holForm.salarioBase) || 0)}
+ Adicionais{fmtBRL(parseFloat(holForm.adicionais) || 0)}
- Descontos{fmtBRL(parseFloat(holForm.descontos) || 0)}
Líquido{fmtBRL(holLiquido)}
setHolModal(false)}>Cancelar Gerar PDF
)}
); }; Object.assign(window, { FinanceiroScreen });