// 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}
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ção | Referência | Valor |
| Salário Base | 30 dias | R$ ${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
{fmtBRL(entradas)}
{fmtBRL(saidas)}
= 0 ? '#10B981' : '#EF4444', fontFamily: 'DM Mono, monospace' }}>{fmtBRL(saldo)}
= 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=>(
| {h} |
))}
{paged.map((t,i)=>(
| {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('descricao',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}>
);
};
Object.assign(window, { FinanceiroScreen });