// SGAB v2 — Propostas (PTC), Financeiro, Estoque, Relatórios, Configurações const { useState } = React; // ═══════════════════════════════════════════════════════════════ // PROPOSTAS // ═══════════════════════════════════════════════════════════════ function Propostas({ user, toast, onNav }) { const [db, setDb] = useState(() => SGAB.getDB()); const [modal, setModal] = useState(false); const [form, setForm] = useState({}); const [editItem, setEdit] = useState(null); const [q, setQ] = useState(''); const { fmt } = SGAB; const isAdmin = user.perfil === 'administrador' || user.perfil === 'administrativo'; function reload() { setDb(SGAB.getDB()); } function F(k,v) { setForm(f=>({...f,[k]:v})); } const lista = db.propostas.filter(p => !q || db.clientes.find(c=>c.id===p.clienteId)?.razaoSocial.toLowerCase().includes(q.toLowerCase()) || (p.numero||'').toLowerCase().includes(q.toLowerCase()) ).sort((a,b)=>b.data.localeCompare(a.data)); function openNew() { const ndb = SGAB.getDB(); const id = SGAB.nxtId(ndb,'prop'); SGAB.saveDB(ndb); const vd = new Date(); vd.setDate(vd.getDate()+15); setEdit(null); setForm({ numero:`PTC_${new Date().getFullYear()}${String(id).padStart(4,'0')}`, status:'Em Elaboração', data:fmt.today(), validade:vd.toISOString().slice(0,10), tipo:'Calibração RBC', equipIds:[], valor:'', desc:'' }); setModal(true); } function openEdit(p) { setEdit(p); setForm({...p}); setModal(true); } function salvar() { if (!form.clienteId) { toast('Selecione o cliente.','error'); return; } if (!form.tipo) { toast('Selecione o tipo.','error'); return; } const ndb = SGAB.getDB(); const obj = {...form, clienteId:+form.clienteId, valor:+form.valor||0, equipIds:(form.equipIds||[]).map(Number)}; if (editItem) { const i=ndb.propostas.findIndex(p=>p.id===editItem.id); if(i>=0) ndb.propostas[i]={...ndb.propostas[i],...obj}; } else { ndb.propostas.push({id:SGAB.nxtId(ndb,'prop'),...obj}); } SGAB.saveDB(ndb); reload(); setModal(false); toast(editItem?'PTC atualizada!':'PTC criada!'); } function excluir(p) { if (!confirm(`Excluir ${p.numero}?`)) return; const ndb=SGAB.getDB(); ndb.propostas=ndb.propostas.filter(x=>x.id!==p.id); SGAB.saveDB(ndb); reload(); toast('PTC removida.','info'); } function converterOS(p) { if (!confirm(`Converter ${p.numero} em Ordem de Serviço?`)) return; const ndb=SGAB.getDB(); const newOS = { id:SGAB.nxtId(ndb,'ordens'), numero:`OS_${new Date().getFullYear()}${String(ndb.nextIds.ordens).padStart(4,'0')}`, clienteId:p.clienteId, equipIds:p.equipIds||[], tipo:p.tipo, status:'Agendada', tecnicoId:db.usuarios.find(u=>u.perfil==='tecnico')?.id||1, data:fmt.today(), desc:p.desc, valor:p.valor, pecas:[], hIni:'08:00', viagem:'0.5h', obs:`Gerado a partir de ${p.numero}` }; ndb.ordens.push(newOS); const pi=ndb.propostas.findIndex(x=>x.id===p.id); if(pi>=0){ndb.propostas[pi].status='Aprovada';ndb.propostas[pi].osId=newOS.id;} SGAB.saveDB(ndb); reload(); toast(`OS ${newOS.numero} criada com sucesso!`); onNav('ordens'); } function printPTC(p) { const cli = db.clientes.find(c=>c.id===p.clienteId); const equips = db.equipamentos.filter(e=>(p.equipIds||[]).includes(e.id)); const config = db.config.empresa; const html = `${p.numero}
${config.nome}
${config.cnpj} | ${config.tel} | ${config.email}
${config.acred}
${p.numero}
PROPOSTA TÉCNICO-COMERCIAL
Emitida: ${fmt.date(p.data)} | Válida até: ${fmt.date(p.validade)}
01 — DADOS DO CLIENTE
Razão Social${cli?.razaoSocial||'—'}CNPJ${cli?.cnpj||'—'}
Endereço${cli?.endereco||'—'}, ${cli?.cidade||'—'}/${cli?.uf||'—'}
Contato${cli?.contato||'—'}Depto${cli?.depto||'—'}
Telefone${cli?.tel||'—'}E-mail${cli?.email||'—'}
02 — OBJETO DA PROPOSTA
Tipo de Serviço${p.tipo}
Descrição${p.desc||'—'}
${equips.length>0?`
03 — EQUIPAMENTOS
${equips.map(e=>``).join('')}
TAGFabricanteModeloN° SérieCapacidadeClasse
${e.tag}${e.fab}${e.modelo}${e.serie}${e.cap}${e.classe}
`:''}
04 — CONDIÇÕES COMERCIAIS
Forma de PagamentoPIX (5% desconto) | Cartão até 12x | Transferência Bancária
Prazo de Execução3 a 7 dias úteis após aprovação e pagamento do sinal (30%)
GarantiaCorreção gratuita de bugs. 10 alterações simples sem prazo de expiração.
Validade da Proposta${fmt.date(p.validade)}
VALOR TOTAL: ${fmt.money(p.valor)}
Aprovado pelo Cliente
${cli?.contato||'—'} — ${cli?.razaoSocial||'—'}
Responsável Comercial
${config.nome}
${config.email}