Carregando dados...
0)||(_rawChk&&_rawChk.length>10);if(\!_hasReal){DATA=gerarDadosDemostracao();window._MODO_DEMO=true;}else{window._MODO_DEMO=false;} } } else { window._MODO_DEMO=false; try {const res = await fetch(SCRIPT_URL + '?action=all&t=' + Date.now());const json = await res.json();if (json.sucesso) {DATA.pipeline = json.pipeline || [];DATA.metas = json.metas || [];DATA.recebimentos = json.recebimentos || [];DATA.historico = json.historico || [];DATA.config = json.config || [];}} catch (err) {console.warn('Erro ao carregar dados:', err);if (!DATA.pipeline.length) DATA = gerarDadosDemostracao();}}(function(){var _el=document.getElementById('footer-last-update');if(_el)_el.textContent='Atualizado: '+new Date().toLocaleTimeString('pt-BR');})();renderAll();document.getElementById('loading').style.display = 'none';}function setFilter(tipo, mesVal) {FILTER.tipo = tipo;if (tipo === 'mes-custom' && mesVal) FILTER.mesCustom = mesVal;if (tipo === 'mes-custom') {const sel = document.getElementById('mes-select');FILTER.mesCustom = sel.value || null;}document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));const mapa = { hoje: 0, semana: 1, mes: 2 };const btns = document.querySelectorAll('.filter-btn');if (tipo !== 'mes-custom' && mapa[tipo] !== undefined) btns[mapa[tipo]].classList.add('active');renderAll();}function filtrarPorData(registros) {const hoje = new Date();hoje.setHours(23, 59, 59, 999);const hojeStr = hoje.toISOString().split('T')[0];return registros.filter(r => {const dataStr = r.data_registro || r.data_venda || r.data_recebimento || '';if (!dataStr) return false;const d = new Date(dataStr + 'T00:00:00');if (FILTER.tipo === 'hoje') {return dataStr === hojeStr;}if (FILTER.tipo === 'semana') {const inicio = new Date(hoje);inicio.setDate(hoje.getDate() - hoje.getDay());inicio.setHours(0, 0, 0, 0);return d >= inicio && d <= hoje;}if (FILTER.tipo === 'mes') {const mes = hoje.toISOString().substring(0, 7);return dataStr.startsWith(mes);}if (FILTER.tipo === 'mes-custom' && FILTER.mesCustom) {return dataStr.startsWith(FILTER.mesCustom);}return true;});}function calcMetrics(pipeline, unit) {const base = unit === 'all'? pipeline: pipeline.filter(r => r.unidade === unit);const filtrado = filtrarPorData(base);const vendas = filtrado.filter(r => r.status === 'Vendido');const leads = filtrado;const agendados = filtrado.filter(r =>['Agendado','Consultado','Vendido'].includes(r.status));const consultados = filtrado.filter(r =>['Consultado','Vendido'].includes(r.status));const online = consultados.filter(r => r.tipo_consulta === 'Online');const presencial = consultados.filter(r => r.tipo_consulta === 'Presencial');const faturamento = vendas.reduce((s, r) => s + (parseFloat(r.valor_venda) || 0), 0);const ticket = vendas.length ? faturamento / vendas.length : 0;const conv = leads.length ? (vendas.length / leads.length * 100) : 0;const hoje = new Date().toISOString().split('T')[0];const vendasHoje = base.filter(r =>r.status === 'Vendido' &&(r.data_venda || r.data_registro || '').startsWith(hoje));const fatHoje = vendasHoje.reduce((s, r) => s + (parseFloat(r.valor_venda) || 0), 0);const mesAtual = new Date().toISOString().substring(0, 7);const vendasMes = base.filter(r =>r.status === 'Vendido' &&(r.data_venda || r.data_registro || '').startsWith(mesAtual));const fatMes = vendasMes.reduce((s, r) => s + (parseFloat(r.valor_venda) || 0), 0);return {leads: leads.length,agendados: agendados.length,consultados: consultados.length,vendas: vendas.length,faturamento,ticket,conv,online: online.length,presencial: presencial.length,pctOnline: consultados.length ? (online.length / consultados.length * 100) : 0,pctConvConsulta: consultados.length ? (vendas.length / consultados.length * 100) : 0,fatHoje,fatMes};}function getMeta(unit, vendedor) {const mesAtual = new Date().toISOString().substring(0, 7);const m = DATA.metas.find(r =>r.mes_ano === mesAtual &&r.unidade === (unit === 'all' ? 'GERAL' : unit) &&(r.vendedor === (vendedor || 'GERAL') || r.vendedor === 'GERAL'));return m ? {mensal: parseFloat(m.meta_mensal) || 0,semanal: parseFloat(m.meta_semanal) || 0} : { mensal: 0, semanal: 0 };}function fmtCurrency(v) {return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL', maximumFractionDigits: 0 }).format(v || 0);}function fmtPct(v) { return (v || 0).toFixed(1) + '%'; }function fmtNum(v) { return new Intl.NumberFormat('pt-BR').format(v || 0); } // ════════════════════════════════════════════ // BANNER MOTIVACIONAL (meta semanal faturamento) // ════════════════════════════════════════════ function renderBannerMotivacional() { try { const el = document.getElementById('banner-motivacional'); if (!el || !currentUser) { if(el) el.style.display='none'; return; } const uid = currentUser.usuario || currentUser.id; const m = muGet(uid); const metaMensal = parseFloat(m.aplica_faturamento !== false ? m.faturamento : 0) || 0; if (!metaMensal) { el.style.display='none'; return; } const metaSemanal = metaMensal / 4; const realSemanal = getUserMetrics(uid, 'semana').faturamento || 0; const pct = metaSemanal > 0 ? (realSemanal / metaSemanal) * 100 : 0; let msg, bg, color, cls = ''; if (pct >= 100) { msg = '🏆 PARABÉNS, META BATIDA. BATA RECORDES AGORA!'; bg = '#00ff41'; color = '#000'; cls = 'flash-meta'; } else if (pct > 70) { msg = '💪 FALTA POUQUÍSSIMO, FOCO TOTAL NO OBJETIVO, VOCÊ VAI CONSEGUIR!'; bg = '#1b5e20'; color = '#69f0ae'; } else if (pct > 50) { msg = '🔵 FALTA POUCO PARA QUE SUA META SEJA CUMPRIDA, SEJA RESILIENTE!'; bg = '#0d47a1'; color = '#90caf9'; } else if (pct > 30) { msg = '⚡ VOCÊ AVANÇOU E NÃO DUVIDE QUE É CAPAZ DE CUMPRIR SUA META'; bg = '#f57f17'; color = '#000'; } else { msg = '🔥 VAMOS LÁ, A SUPREMA FIO ACREDITA E CONFIA EM VOCÊ'; bg = '#b71c1c'; color = '#fff'; } el.className = 'banner-motivacional' + (cls ? ' ' + cls : ''); el.style.cssText = 'display:block;background:' + bg + ';color:' + color + ';' + 'padding:11px 24px;text-align:center;font-size:.97rem;font-weight:900;' + 'letter-spacing:.06em;text-transform:uppercase;position:sticky;top:0;z-index:200;' + 'box-shadow:0 2px 10px rgba(0,0,0,.35);'; if (cls) el.style.animation = 'flash-meta-batida .7s infinite'; else el.style.animation = ''; const subtext = ' · ' + fmtCurrency(realSemanal) + ' / ' + fmtCurrency(metaSemanal) + ' (' + pct.toFixed(0) + '%)'; el.innerHTML = msg + '' + subtext + ''; } catch(e) { console.warn('Banner motivacional:', e); } } // ════════════════════════════════════════════ // PROGRESSO MENSAL (geral, por clínica, por usuário) // ════════════════════════════════════════════ function renderProgressoMensal() { try { const wrap = document.getElementById('progresso-mensal-wrap'); if (!wrap) return; const mesAtual = new Date().toISOString().substring(0, 7); const pipeline = DATA.pipeline || []; function fatMes(arr) { return arr.filter(r => r.status === 'Vendido' && (r.data_venda || r.data_registro || '').startsWith(mesAtual)) .reduce((s, r) => s + (parseFloat(r.valor_venda) || 0), 0); } function pmRow(label, real, meta, cor, bold) { const pct = meta > 0 ? Math.min((real / meta) * 100, 110) : 0; const barPct = Math.min(pct, 100); const c = pct >= 100 ? '#00e676' : pct >= 70 ? '#69f0ae' : pct >= 50 ? '#42a5f5' : pct >= 30 ? '#ffa726' : '#ef5350'; const color = cor || c; return '
'; } // GERAL const totalReal = fatMes(pipeline); const metaGeral = getMeta('all').mensal || 0; let html = '
'; html += '
'; html += pmRow('TODAS AS CLÍNICAS', totalReal, metaGeral, null, true); // POR CLÍNICA html += '
'; UNITS.forEach(u => { const real = fatMes(pipeline.filter(r => r.unidade === u)); const meta = getMeta(u).mensal || 0; if (!real && !meta) return; html += pmRow((UNIT_NAMES[u] || u), real, meta, UNIT_COLORS[u], false); }); // POR USUÁRIO const usuariosAtivos = (window.USUARIOS || []).filter(u => u.ativo !== false && u.role !== 'master' && u.role !== 'admin'); if (usuariosAtivos.length) { html += '
'; usuariosAtivos.forEach(u => { const uid = u.usuario || u.id; const m = muGet(uid); const metaU = parseFloat(m.aplica_faturamento !== false ? m.faturamento : 0) || 0; const realU = getUserMetrics(uid, 'mes').faturamento || 0; if (!realU && !metaU) return; html += pmRow(u.nome || uid, realU, metaU, null, false); }); } wrap.innerHTML = html; wrap.style.display = ''; } catch(e) { console.warn('Progresso mensal:', e); } } // ════════════════════════════════════════════ // AVISOS DE SISTEMA (demo / fallback local) // ════════════════════════════════════════════ function renderAvisoSistema() { try { const wrap = document.getElementById('aviso-sistema'); if (!wrap) return; const avisos = []; if (window._MODO_DEMO) { avisos.push('
'); } const isLocalUsers = typeof window.USUARIOS !== 'undefined' && typeof DEFAULT_USUARIOS !== 'undefined' && window.USUARIOS === DEFAULT_USUARIOS; if (isLocalUsers && typeof _supabase !== 'undefined' && currentUser) { avisos.push('
'); } wrap.innerHTML = avisos.join(''); wrap.style.display = avisos.length ? '' : 'none'; } catch(e) { console.warn('renderAvisoSistema:', e); } } function renderAll() {renderAvisoSistema();renderBannerMotivacional();renderProgressoMensal();renderOverview();UNITS.forEach(u => renderUnit(u));renderRankings();renderMetas();renderComparativo();renderReceitas();}function renderOverview() {const el = document.getElementById('page-all');const m = calcMetrics(DATA.pipeline, 'all');const meta = getMeta('all');const hojeStr = new Date().toISOString().split('T')[0];const mesStr = new Date().toISOString().substring(0, 7);const unitsRow = UNITS.map(u => {const vendasHojeU = DATA.pipeline.filter(r =>r.unidade === u && r.status === 'Vendido' &&(r.data_venda || r.data_registro || '').startsWith(hojeStr));const fatU = vendasHojeU.reduce((s, r) => s + (parseFloat(r.valor_venda) || 0), 0);return `
`;}).join('');const metaPct = meta.mensal ? Math.min((m.fatMes / meta.mensal) * 100, 100) : 0;const diasMes = new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0).getDate();const diaAtual = new Date().getDate();const diasRestantes = diasMes - diaAtual + 1;const vendasDiaParaMeta = (meta.mensal && diasRestantes > 0)? Math.max(0, (meta.mensal - m.fatMes) / diasRestantes): 0;el.innerHTML = `
${meta.mensal ? `
` : ''} `; renderChartUnits('chart-all-units'); renderChartTipo('chart-all-tipo', m); renderChartDiario('chart-all-diario', 'all'); } function renderUnit(unit) { const el = document.getElementById('page-' + unit); if (!el) return; const m = calcMetrics(DATA.pipeline, unit); const meta = getMeta(unit); const color = UNIT_COLORS[unit]; const mesStr = new Date().toISOString().substring(0, 7); const metaPct = meta.mensal ? Math.min((m.fatMes / meta.mensal) * 100, 100) : 0; const diasMes = new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0).getDate(); const diaAtual = new Date().getDate(); const diasRestantes = diasMes - diaAtual + 1; const vendasDiaParaMeta = (meta.mensal && diasRestantes > 0) ? Math.max(0, (meta.mensal - m.fatMes) / diasRestantes) : 0; const filtrado = filtrarPorData(DATA.pipeline.filter(r => r.unidade === unit && r.status === 'Vendido')); const vendedores = {}; filtrado.forEach(r => { const v = r.vendedor || r.agente || 'Desconhecido'; vendedores[v] = (vendedores[v] || 0) + (parseFloat(r.valor_venda) || 0); }); const vendRanking = Object.entries(vendedores).sort((a, b) => b[1] - a[1]); const rankRows = vendRanking.map(([nome, fat], i) => { const ticket = filtrado.filter(r => (r.vendedor||r.agente) === nome).length; const rankClass = i === 0 ? 'rank-1' : i === 1 ? 'rank-2' : i === 2 ? 'rank-3' : 'rank-n'; return `
`; }).join('') || '
'; const convRows = (() => { const filtradoAll = filtrarPorData(DATA.pipeline.filter(r => r.unidade === unit)); const agentes = {}; filtradoAll.forEach(r => { const a = r.agente || r.vendedor || 'Desconhecido'; if (!agentes[a]) agentes[a] = { leads: 0, vendas: 0 }; agentes[a].leads++; if (r.status === 'Vendido') agentes[a].vendas++; }); return Object.entries(agentes).sort((a, b) => b[1].vendas - a[1].vendas).map(([nome, d], i) => { const taxa = d.leads ? (d.vendas / d.leads * 100) : 0; const rankClass = i === 0 ? 'rank-1' : i === 1 ? 'rank-2' : i === 2 ? 'rank-3' : 'rank-n'; return `
`; }).join('') || '
'; })(); el.innerHTML = `
| # | Vendedor | Faturamento | Vendas | Ticket Médio |
|---|
| # | Agente | Leads | Vendas | Conversão |
|---|
${meta.mensal ? `
` : `
`} `; renderChartVendedor('chart-' + unit + '-vend', unit, color); renderChartTipo('chart-' + unit + '-tipo', m, color); renderChartDiario('chart-' + unit + '-diario', unit, color); } function renderRankings() { const el = document.getElementById('page-ranking'); const mesStr = new Date().toISOString().substring(0, 7); const inicioSemana = new Date(); inicioSemana.setDate(inicioSemana.getDate() - inicioSemana.getDay()); function rankVendedores(filtroFn, label) { const filtrado = DATA.pipeline.filter(r => r.status === 'Vendido' && filtroFn(r)); const vend = {}; filtrado.forEach(r => { const v = r.vendedor || r.agente || 'Desconhecido'; const u = r.unidade || '?'; if (!vend[v]) vend[v] = { fat: 0, vendas: 0, unidade: u }; vend[v].fat += parseFloat(r.valor_venda) || 0; vend[v].vendas++; }); const rows = Object.entries(vend).sort((a, b) => b[1].fat - a[1].fat).slice(0, 10) .map(([nome, d], i) => { const rc = i===0?'rank-1':i===1?'rank-2':i===2?'rank-3':'rank-n'; return `
`; }).join('') || '
'; return `
| # | Vendedor | Unidade | Faturamento | Vendas | Ticket Médio |
|---|
`; } function rankUnidades(filtroFn, label) { const filtrado = DATA.pipeline.filter(r => r.status === 'Vendido' && filtroFn(r)); const unid = {}; filtrado.forEach(r => { const u = r.unidade || '?'; if (!unid[u]) unid[u] = { fat: 0, vendas: 0 }; unid[u].fat += parseFloat(r.valor_venda) || 0; unid[u].vendas++; }); const rows = Object.entries(unid).sort((a, b) => b[1].fat - a[1].fat) .map(([u, d], i) => { const rc = i===0?'rank-1':i===1?'rank-2':i===2?'rank-3':'rank-n'; const nome = UNIT_NAMES[u] || u; return `
`; }).join('') || '
'; return `
| # | Unidade | Faturamento | Vendas | Ticket Médio |
|---|
`; } const semanaFn = r => { const d = new Date((r.data_venda || r.data_registro || '') + 'T00:00:00'); return d >= inicioSemana; }; const mesFn = r => (r.data_venda || r.data_registro || '').startsWith(mesStr); el.innerHTML = `
`; } function renderMetas() { const el = document.getElementById('page-metas'); if (!window.METAS_USUARIOS) { window.METAS_USUARIOS = JSON.parse(localStorage.getItem('sf_metas_usuarios') || '{}'); if (typeof _supabase !== 'undefined' && _supabase) { const _mesMeta = new Date().toISOString().substring(0, 7); _supabase.from('metas_usuarios').select('*').eq('mes', _mesMeta) .then(({ data: _d, error: _e }) => { if (!_e && _d && _d.length) { _d.forEach(r => { const k = r.mes + '_' + r.usuario_id; window.METAS_USUARIOS[k] = { leads: r.leads||0, agendamentos: r.agendamentos||0, consultas: r.consultas||0, vendas: r.vendas||0, faturamento: r.faturamento||0, aplica_leads: r.aplica_leads !== false, aplica_agendamentos: r.aplica_agendamentos !== false, aplica_consultas: r.aplica_consultas !== false, aplica_vendas: r.aplica_vendas !== false, aplica_faturamento: r.aplica_faturamento || false }; }); localStorage.setItem('sf_metas_usuarios', JSON.stringify(window.METAS_USUARIOS)); renderMetas(); } }); } } const podeEditar = ROLES_GERENCIAIS.includes(currentUser?.role); const mesStr = new Date().toISOString().substring(0, 7); const hoje = new Date().toISOString().split('T')[0]; const diasMes = new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0).getDate(); const diaAtual = new Date().getDate(); const iniSemana = new Date(); iniSemana.setDate(iniSemana.getDate() - iniSemana.getDay()); iniSemana.setHours(0,0,0,0); const iniSemStr = iniSemana.toISOString().split('T')[0]; const usuariosAtivos = USUARIOS.filter(u => u.role !== 'founder'); if (!window.META_EDIT_USER && usuariosAtivos.length) window.META_EDIT_USER = usuariosAtivos[0].usuario || usuariosAtivos[0].id; const usuarioEditando = window.META_EDIT_USER; function muGet(uid) { const key = mesStr + '_' + uid; return window.METAS_USUARIOS[key] || {}; } function getUserMetrics(uid, periodo) { const usr = USUARIOS.find(x => (x.usuario||x.id) === uid); if (!usr) return { leads:0, agendamentos:0, consultas:0, vendas:0, faturamento:0 }; const base = DATA.pipeline.filter(r => { const a = r.agente || r.vendedor || ''; return a === usr.nome || a === usr.usuario; }); const filt = base.filter(r => { const ds = r.data_registro || r.data_venda || ''; if (periodo === 'hoje') return ds === hoje; if (periodo === 'semana') return ds >= iniSemStr; if (periodo === 'mes') return ds.startsWith(mesStr); return true; }); const vend = filt.filter(r => r.status === 'Vendido'); return { leads: filt.length, agendamentos: filt.filter(r => ['Agendado','Consultado','Vendido'].includes(r.status)).length, consultas: filt.filter(r => ['Consultado','Vendido'].includes(r.status)).length, vendas: vend.length, faturamento: vend.reduce((s,r) => s+(parseFloat(r.valor_venda)||0), 0) }; } function progBar(real, meta, cor) { if (!meta) return 'sem meta'; const pct = Math.min((real/meta)*100, 100); const cl = pct < 40 ? '#ff4444' : pct < 80 ? '#ff9800' : '#00e676'; return `
`; } // === EDITOR (gerentes) === const editorHTML = podeEditar ? (() => { const u = USUARIOS.find(x => (x.usuario||x.id) === usuarioEditando); const m = muGet(usuarioEditando); const tabs = usuariosAtivos.map(usr => { const uid = usr.usuario||usr.id; const active = uid === usuarioEditando; return ``; }).join(''); if (!u) return ''; const campos = [ { id:'leads', label:'Leads / mês', icon:'fa-user-plus', tipo:'int' }, { id:'agendamentos', label:'Agendamentos / mês', icon:'fa-calendar-check',tipo:'int' }, { id:'consultas', label:'Consultas / mês', icon:'fa-stethoscope', tipo:'int' }, { id:'vendas', label:'Vendas / mês', icon:'fa-handshake', tipo:'int' }, { id:'faturamento', label:'Faturamento / mês', icon:'fa-dollar-sign', tipo:'float'} ]; const inp = `background:var(--card2);border:1px solid var(--border);border-radius:8px;padding:7px 11px;color:var(--text);font-size:.88rem;width:150px`; const camposHTML = campos.map(c => { const aplica = c.id === 'faturamento' ? !!m.aplica_faturamento : m[`aplica_${c.id}`] !== false; const val = m[c.id] || 0; return `
`; }).join(''); const diasInfo = `Meta diária = mensal ÷ ${diasMes} dias. Meta semanal = mensal ÷ 4.`; return `
`; })() : ''; // === PROGRESSO POR AGENTE === const COR_METRICA = { leads:'#5c6bc0', agendamentos:'#26a69a', consultas:'#ec407a', vendas:'#00e676', faturamento:'#c9a84c' }; const LABEL_METRICA = { leads:'Leads', agendamentos:'Agendam.', consultas:'Consultas', vendas:'Vendas', faturamento:'Faturamento' }; const fmtM = (k,v) => k === 'faturamento' ? fmtCurrency(v) : fmtNum(v); const progressCards = usuariosAtivos.map(u => { const uid = u.usuario||u.id; const m = muGet(uid); const ativas = ['leads','agendamentos','consultas','vendas','faturamento'].filter(k => { const aplica = k === 'faturamento' ? !!m.aplica_faturamento : m[`aplica_${k}`] !== false; return aplica && (m[k]||0) > 0; }); if (!ativas.length) return ''; const cor = UNIT_COLORS[u.unidade] || '#c9a84c'; const hm = getUserMetrics(uid,'hoje'); const sm = getUserMetrics(uid,'semana'); const mm = getUserMetrics(uid,'mes'); const linhas = ativas.map(k => { const meta_mensal = m[k]||0; const meta_dia = diasMes > 0 ? meta_mensal/diasMes : 0; const meta_sem = meta_mensal/4; return `
`; }).join(''); return `
`; }).filter(Boolean).join(''); // === CONSOLIDADO POR CLÍNICA === const clinicCards = UNITS.map(unit => { const usersUnit = usuariosAtivos.filter(u => u.unidade === unit); const totalFat = usersUnit.reduce((s,u) => s+(muGet(u.usuario||u.id).faturamento||0), 0); const totalLeads= usersUnit.reduce((s,u) => s+(muGet(u.usuario||u.id).leads||0), 0); const totalAg = usersUnit.reduce((s,u) => s+(muGet(u.usuario||u.id).agendamentos||0), 0); const totalVend = usersUnit.reduce((s,u) => s+(muGet(u.usuario||u.id).vendas||0), 0); const mm_unit = calcMetrics(DATA.pipeline, unit); const pct = totalFat ? Math.min((mm_unit.fatMes/totalFat)*100,100) : 0; const cor = UNIT_COLORS[unit]; const falta = Math.max(0,(totalFat||0)-mm_unit.fatMes); const diasRest = diasMes - diaAtual + 1; const porDia = diasRest > 0 ? falta/diasRest : 0; return `
`; }).join(''); el.innerHTML = `
${progressCards ? `
` : `
`} ${editorHTML} `; } function salvarMetaUsuario(usuarioId, campo, valor) { if (!window.METAS_USUARIOS) window.METAS_USUARIOS = {}; const mes = new Date().toISOString().substring(0, 7); const key = mes + '_' + usuarioId; if (!window.METAS_USUARIOS[key]) window.METAS_USUARIOS[key] = {}; if (campo.startsWith('aplica_')) { window.METAS_USUARIOS[key][campo] = (valor === true || valor === 'true'); } else if (campo === 'faturamento') { window.METAS_USUARIOS[key][campo] = parseFloat(valor) || 0; } else { window.METAS_USUARIOS[key][campo] = parseInt(valor) || 0; } localStorage.setItem('sf_metas_usuarios', JSON.stringify(window.METAS_USUARIOS)); if (typeof _supabase !== 'undefined' && _supabase) { const _m = window.METAS_USUARIOS[key]; _supabase.rpc('set_meta_usuario', { p_mes: mes, p_usuario_id: usuarioId, p_leads: _m.leads||0, p_agendamentos: _m.agendamentos||0, p_consultas: _m.consultas||0, p_vendas: _m.vendas||0, p_faturamento: _m.faturamento||0, p_aplica_leads: _m.aplica_leads !== false, p_aplica_agendamentos: _m.aplica_agendamentos !== false, p_aplica_consultas: _m.aplica_consultas !== false, p_aplica_vendas: _m.aplica_vendas !== false, p_aplica_faturamento: !!_m.aplica_faturamento }).then(({ error: _e }) => { if (_e) console.warn('[Metas] RPC:', _e.message); }); } renderMetas(); } function getMetaUsuario(usuarioId, campo) { if (!window.METAS_USUARIOS) window.METAS_USUARIOS = JSON.parse(localStorage.getItem('sf_metas_usuarios') || '{}'); const mes = new Date().toISOString().substring(0, 7); const key = mes + '_' + usuarioId; return (window.METAS_USUARIOS[key] || {})[campo] || 0; } function renderSDR() { const el = document.getElementById('page-sdr'); if (!el) return; const u = currentUser; const hoje = new Date().toISOString().split('T')[0]; const mesAtual = new Date().toISOString().substring(0, 7); const iniSemana = new Date(); iniSemana.setDate(iniSemana.getDate() - iniSemana.getDay()); iniSemana.setHours(0,0,0,0); const [dIni, dFim] = (window.SDR_PERIODO || [hoje, hoje]); function filtrarSDR(tipo) { return DATA.pipeline.filter(r => { const ds = r.data_registro || r.data_venda || ''; if (!ds) return false; const d = new Date(ds + 'T00:00:00'); if (tipo === 'hoje') return ds === hoje; if (tipo === 'semana') return d >= iniSemana; if (tipo === 'mes') return ds.startsWith(mesAtual); if (tipo === 'periodo') return ds >= dIni && ds <= dFim; return true; }); } function metricasSDR(base) { return { leads: base.length, agendamentos: base.filter(r => ['Agendado','Consultado','Vendido'].includes(r.status)).length, consultas: base.filter(r => ['Consultado','Vendido'].includes(r.status)).length, vendas: base.filter(r => r.status === 'Vendido').length, }; } const periodos = ['hoje','semana','mes','periodo']; const labels = { hoje:'Hoje', semana:'Esta Semana', mes:'Este Mês', periodo:'Período' }; const ativo = window.SDR_FILTRO || 'hoje'; const base = filtrarSDR(ativo); const m = metricasSDR(base); const metaAg = getMetaUsuario(u?.usuario||u?.id, 'agendamentos'); const metaVend = getMetaUsuario(u?.usuario||u?.id, 'vendas'); const metaLeads = getMetaUsuario(u?.usuario||u?.id, 'leads'); const pctAg = metaAg ? Math.min(m.agendamentos/metaAg*100,100) : 0; const pctVend = metaVend ? Math.min(m.vendas/metaVend*100,100) : 0; const pctLeads = metaLeads ? Math.min(m.leads/metaLeads*100,100) : 0; el.innerHTML = `
Acompanhe sua performance em tempo real.
`; } function renderComparativo() { const el = document.getElementById('page-comparativo'); const mesAtual = new Date().toISOString().substring(0, 7); const mesComp = el.dataset.mescomp || MESES_HISTORICO[0].valor; const mesCompLabel = MESES_HISTORICO.find(m => m.valor === mesComp)?.label || mesComp; const fatAtual = {}; UNITS.forEach(u => { const vends = DATA.pipeline.filter(r => r.unidade === u && r.status === 'Vendido' && (r.data_venda || r.data_registro || '').startsWith(mesAtual)); fatAtual[u] = vends.reduce((s, r) => s + (parseFloat(r.valor_venda) || 0), 0); }); const fatComp = {}; UNITS.forEach(u => { const h = DATA.historico.find(r => r.mes_ano === mesComp && r.unidade === u); fatComp[u] = h ? parseFloat(h.total_faturamento) || 0 : 0; }); const selectOpts = MESES_HISTORICO.map(m => `` ).join(''); const cards = UNITS.map(u => { const atual = fatAtual[u] || 0; const comp = fatComp[u] || 0; const delta = comp ? ((atual - comp) / comp * 100) : 0; const isUp = delta >= 0; const color = UNIT_COLORS[u]; return `
`; }).join(''); const totalAtual = Object.values(fatAtual).reduce((s, v) => s + v, 0); const totalComp = Object.values(fatComp).reduce((s, v) => s + v, 0); const deltaGeral = totalComp ? ((totalAtual - totalComp) / totalComp * 100) : 0; const isUpGeral = deltaGeral >= 0; el.innerHTML = `
`; setTimeout(() => { const ctx = document.getElementById('chart-comparativo'); if (!ctx) return; if (chartInstances['comparativo']) chartInstances['comparativo'].destroy(); chartInstances['comparativo'] = new Chart(ctx, { type: 'bar', data: { labels: UNITS.map(u => UNIT_NAMES[u]), datasets: [ { label: mesAtual, data: UNITS.map(u => fatAtual[u] || 0), backgroundColor: UNITS.map(u => UNIT_COLORS[u] + 'cc'), borderColor: UNITS.map(u => UNIT_COLORS[u]), borderWidth: 2, borderRadius: 6 }, { label: mesCompLabel, data: UNITS.map(u => fatComp[u] || 0), backgroundColor: 'rgba(120,120,160,.3)', borderColor: 'rgba(180,180,220,.6)', borderWidth: 2, borderRadius: 6 } ] }, options: chartOptions({ currency: true }) }); }, 50); } function renderReceitas() { const el = document.getElementById('page-receitas'); const mesStr = new Date().toISOString().substring(0, 7); const filtrado = DATA.recebimentos.filter(r => (r.data_recebimento || '').startsWith(mesStr)); const totalRec = filtrado.reduce((s, r) => s + (parseFloat(r.valor_recebido) || 0), 0); const porUnidade = {}; filtrado.forEach(r => { const u = r.unidade || '?'; porUnidade[u] = (porUnidade[u] || 0) + (parseFloat(r.valor_recebido) || 0); }); const recRows = filtrado.slice().reverse().slice(0, 50).map(r => `
`).join('') || '
'; const unidCards = UNITS.map(u => `
`).join(''); el.innerHTML = `
| Data | Unidade | Vendedor | Valor | Referência |
|---|
`; } function chartOptions(opts = {}) { return { responsive: true, maintainAspectRatio: false, plugins: { legend: { labels: { color: '#8888aa', font: { size: 11 }, padding: 16 } }, tooltip: { callbacks: opts.currency ? { label: ctx => ' ' + fmtCurrency(ctx.raw) } : undefined } }, scales: opts.noAxes ? {} : { x: { ticks: { color: '#8888aa', font: { size: 10 } }, grid: { color: '#1a1a38' } }, y: { ticks: { color: '#8888aa', font: { size: 10 }, callback: opts.currency ? v => 'R$' + new Intl.NumberFormat('pt-BR',{notation:'compact'}).format(v) : undefined }, grid: { color: '#1a1a38' } } } }; } function renderChartUnits(canvasId) { setTimeout(() => { const ctx = document.getElementById(canvasId); if (!ctx) return; if (chartInstances[canvasId]) chartInstances[canvasId].destroy(); const filtrado = filtrarPorData(DATA.pipeline.filter(r => r.status === 'Vendido')); const data = UNITS.map(u => filtrado.filter(r => r.unidade === u) .reduce((s, r) => s + (parseFloat(r.valor_venda) || 0), 0)); chartInstances[canvasId] = new Chart(ctx, { type: 'bar', data: { labels: UNITS.map(u => UNIT_NAMES[u].split(' ')[0]), datasets: [{ label: 'Faturamento', data, backgroundColor: UNITS.map(u => UNIT_COLORS[u] + 'bb'), borderColor: UNITS.map(u => UNIT_COLORS[u]), borderWidth: 2, borderRadius: 8 }] }, options: chartOptions({ currency: true }) }); }, 50); } function renderChartTipo(canvasId, m, color = '#c9a84c') { setTimeout(() => { const ctx = document.getElementById(canvasId); if (!ctx) return; if (chartInstances[canvasId]) chartInstances[canvasId].destroy(); chartInstances[canvasId] = new Chart(ctx, { type: 'doughnut', data: { labels: ['Online', 'Presencial'], datasets: [{ data: [m.online || 0, m.presencial || 0], backgroundColor: [color + 'cc', 'rgba(120,120,200,.4)'], borderColor: [color, 'rgba(180,180,240,.5)'], borderWidth: 2 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { labels: { color: '#8888aa', font: { size: 11 } } } }, cutout: '65%' } }); }, 50); } function renderChartVendedor(canvasId, unit, color = '#c9a84c') { setTimeout(() => { const ctx = document.getElementById(canvasId); if (!ctx) return; if (chartInstances[canvasId]) chartInstances[canvasId].destroy(); const filtrado = filtrarPorData(DATA.pipeline.filter(r => r.unidade === unit && r.status === 'Vendido')); const vend = {}; filtrado.forEach(r => { const v = r.vendedor || r.agente || 'Desconhecido'; vend[v] = (vend[v] || 0) + (parseFloat(r.valor_venda) || 0); }); const sorted = Object.entries(vend).sort((a, b) => b[1] - a[1]).slice(0, 8); chartInstances[canvasId] = new Chart(ctx, { type: 'bar', data: { labels: sorted.map(([n]) => n), datasets: [{ label: 'Faturamento', data: sorted.map(([, v]) => v), backgroundColor: color + 'aa', borderColor: color, borderWidth: 2, borderRadius: 6 }] }, options: chartOptions({ currency: true }) }); }, 50); } function renderChartDiario(canvasId, unit, color = '#c9a84c') { setTimeout(() => { const ctx = document.getElementById(canvasId); if (!ctx) return; if (chartInstances[canvasId]) chartInstances[canvasId].destroy(); const mesStr = new Date().toISOString().substring(0, 7); const diasMes = new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0).getDate(); const labels = Array.from({ length: diasMes }, (_, i) => `${i + 1}`); const base = unit === 'all' ? DATA.pipeline : DATA.pipeline.filter(r => r.unidade === unit); const vendasMes = base.filter(r => r.status === 'Vendido' && (r.data_venda || r.data_registro || '').startsWith(mesStr)); const daily = Array(diasMes).fill(0); vendasMes.forEach(r => { const d = parseInt((r.data_venda || r.data_registro || '').split('-')[2]) - 1; if (d >= 0 && d < diasMes) daily[d] += parseFloat(r.valor_venda) || 0; }); const acumulado = []; let sum = 0; daily.forEach(v => { sum += v; acumulado.push(sum); }); chartInstances[canvasId] = new Chart(ctx, { type: 'bar', data: { labels, datasets: [ { type: 'bar', label: 'Fat. do Dia', data: daily, backgroundColor: color + '55', borderColor: color + '88', borderWidth: 1, borderRadius: 4, yAxisID: 'y' }, { type: 'line', label: 'Acumulado', data: acumulado, borderColor: color, backgroundColor: 'transparent', borderWidth: 2.5, pointRadius: 0, tension: 0.4, yAxisID: 'y2' } ] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { labels: { color: '#8888aa', font: { size: 11 } } }, tooltip: { callbacks: { label: ctx => ' ' + fmtCurrency(ctx.raw) } } }, scales: { x: { ticks: { color: '#8888aa', font: { size: 9 } }, grid: { color: '#1a1a38' } }, y: { position: 'left', ticks: { color: '#8888aa', font: { size: 10 }, callback: v => 'R$' + new Intl.NumberFormat('pt-BR', { notation: 'compact' }).format(v) }, grid: { color: '#1a1a38' } }, y2: { position: 'right', ticks: { color: color, font: { size: 10 }, callback: v => 'R$' + new Intl.NumberFormat('pt-BR', { notation: 'compact' }).format(v) }, grid: { drawOnChartArea: false } } } } }); }, 50); } function showPage(page) { if (currentUser && !podeFVerPagina(page) && currentUser.role === 'unidade') { return; // silencioso — o usuário não deveria ver este botão } activePage = page; document.querySelectorAll('.page').forEach(p => p.classList.remove('active')); document.querySelectorAll('.sb-item').forEach(i => i.classList.remove('active')); const pageEl = document.getElementById('page-' + page); if (pageEl) pageEl.classList.add('active'); event.currentTarget?.classList.add('active'); const titles = { all: 'Todas as Clínicas', SCS: 'São Caetano do Sul', GRU: 'Guarulhos', MGA: 'Maringá', RVD: 'Rio Verde', ranking: 'Rankings', metas: 'Metas', comparativo: 'Comparativo', receitas: 'Receitas', 'minha-conta': 'Minha Conta', usuarios: 'Gestão de Usuários', 'entrada-diaria': 'Entrada Diária de Leads', leads: 'CRM de Leads', sdr: 'Dashboard SDR' }; document.getElementById('topbar-title').textContent = titles[page] || page; if (page === 'minha-conta') renderPaginaMinhaConta(); if (page === 'usuarios') renderPaginaUsuarios(); if (page === 'sdr') renderSDR(); if (page === 'entrada-diaria') renderPaginaEntradaDiaria(); if (page === 'leads') renderPaginaLeads(); if (window.innerWidth < 900) document.getElementById('sidebar').classList.remove('open'); } function toggleSidebar() { document.getElementById('sidebar').classList.toggle('open'); } document.addEventListener('click', e => { const sidebar = document.getElementById('sidebar'); const toggle = document.getElementById('menu-toggle'); if (window.innerWidth < 900 && !sidebar.contains(e.target) && !toggle.contains(e.target)) { sidebar.classList.remove('open'); } }); function gerarDadosDemostracao() { const hoje = new Date(); const mesStr = hoje.toISOString().substring(0, 7); const hojeStr = hoje.toISOString().split('T')[0]; const origens = ['Instagram', 'Facebook', 'Google', 'Indicação', 'WhatsApp']; const statuses = ['Lead Novo', 'Agendado', 'Consultado', 'Vendido', 'Vendido', 'Perdido']; const tipos = ['Online', 'Presencial', 'Presencial']; const pipeline = []; const vendedores = { SCS: ['Ana Silva', 'Carlos Mendes'], GRU: ['Beatriz Costa', 'Diego Alves'], MGA: ['Fernanda Lima', 'Gabriel Souza'], RVD: ['Helena Rocha', 'Igor Santos'] }; let id = 1; UNITS.forEach(u => { for (let d = 1; d <= hoje.getDate(); d++) { const qtd = Math.floor(Math.random() * 5) + 2; for (let j = 0; j < qtd; j++) { const dia = String(d).padStart(2, '0'); const dataStr = `${mesStr}-${dia}`; const status = statuses[Math.floor(Math.random() * statuses.length)]; const vend = vendedores[u][Math.floor(Math.random() * vendedores[u].length)]; const valor = status === 'Vendido' ? Math.floor(Math.random() * 15000 + 8000) : 0; pipeline.push({ id: 'SF-' + String(id++).padStart(4, '0'), data_registro: dataStr, unidade: u, agente: vend, vendedor: vend, nome_cliente: '', origem: origens[Math.floor(Math.random() * origens.length)], status, tipo_consulta: tipos[Math.floor(Math.random() * tipos.length)], data_agendamento: status !== 'Lead Novo' ? dataStr : '', data_consulta: ['Consultado', 'Vendido'].includes(status) ? dataStr : '', data_venda: status === 'Vendido' ? dataStr : '', valor_venda: valor }); } } }); const metas = UNITS.map(u => ({ mes_ano: mesStr, unidade: u, vendedor: 'GERAL', meta_mensal: Math.floor(Math.random() * 100000 + 150000), meta_semanal: Math.floor(Math.random() * 25000 + 37500) })); const historico = MESES_HISTORICO.map(m => UNITS.map(u => ({ mes_ano: m.valor, unidade: u, total_faturamento: Math.floor(Math.random() * 120000 + 100000), total_vendas: Math.floor(Math.random() * 15 + 10), total_leads: Math.floor(Math.random() * 80 + 60), total_agendamentos: Math.floor(Math.random() * 40 + 30), total_consultas: Math.floor(Math.random() * 20 + 15) }))).flat(); return { pipeline, metas, recebimentos: [], historico, config: [] }; } function abrirEsqueciSenha() { document.getElementById('reset-email').value = ''; const msg = document.getElementById('reset-msg'); msg.style.display = 'none'; msg.textContent = ''; document.getElementById('modal-esqueci').style.display = 'flex'; setTimeout(() => document.getElementById('reset-email').focus(), 100); } function enviarResetSenha() { const email = document.getElementById('reset-email').value.trim().toLowerCase(); const msg = document.getElementById('reset-msg'); USUARIOS = INTEGRITY.loadWithVerification('sf_users') || DEFAULT_USUARIOS; const existe = USUARIOS.find(x => x.email.toLowerCase() === email); msg.style.display = 'block'; if (existe) { msg.style.background = 'rgba(0,230,118,.08)'; msg.style.border = '1px solid rgba(0,230,118,.25)'; msg.style.color = 'var(--green)'; msg.innerHTML = 'E-mail encontrado. Solicite ao administrador do sistema que redefina sua senha em Usuários → Editar.'; } else { msg.style.background = 'rgba(255,68,68,.08)'; msg.style.border = '1px solid rgba(255,68,68,.25)'; msg.style.color = 'var(--red)'; msg.innerHTML = 'E-mail não encontrado. Verifique o endereço ou contate o administrador.'; } } function fecharModal(id) { document.getElementById(id).style.display = 'none'; } function renderPaginaMinhaConta() { const el = document.getElementById('page-minha-conta'); if (!currentUser) return; el.innerHTML = `
Gerencie suas informações e senha de acesso.
`; } async function alterarMinhaSenha() { const atual = document.getElementById('conta-atual').value; const nova = document.getElementById('conta-nova').value; const conf = document.getElementById('conta-confirma').value; const msg = document.getElementById('conta-msg'); const mostrar = (txt, ok) => { msg.style.display = 'block'; msg.style.background = ok ? 'rgba(0,230,118,.08)' : 'rgba(255,68,68,.08)'; msg.style.border = ok ? '1px solid rgba(0,230,118,.25)' : '1px solid rgba(255,68,68,.25)'; msg.style.color = ok ? 'var(--green)' : 'var(--red)'; msg.innerHTML = txt; }; // Quando Supabase está configurado, troca de senha deve ser feita pelo painel do Supabase if (_supabase) { mostrar('Com Supabase ativo, altere sua senha pelo painel de autenticação do Supabase.', false); return; } const userRecord = (INTEGRITY ? (INTEGRITY.loadWithVerification('sf_users') || DEFAULT_USUARIOS) : DEFAULT_USUARIOS).find(x => x.id === currentUser.id); if (!userRecord || !userRecord.senha || atual !== userRecord.senha) { mostrar('Senha atual incorreta.', false); return; } if (nova.length < 6) { mostrar('A nova senha deve ter pelo menos 6 caracteres.', false); return; } if (nova !== conf) { mostrar('As senhas não coincidem.', false); return; } USUARIOS = INTEGRITY.loadWithVerification('sf_users') || DEFAULT_USUARIOS; const idx = USUARIOS.findIndex(x => x.id === currentUser.id); if (idx < 0) { mostrar('Usuário não encontrado.', false); return; } USUARIOS[idx].senha = await hashSenha(nova); currentUser.senha = nova; salvarUsuarios(); sessionStorage.setItem('sf_session', JSON.stringify(currentUser)); document.getElementById('conta-atual').value = ''; document.getElementById('conta-nova').value = ''; document.getElementById('conta-confirma').value = ''; mostrar('Senha alterada com sucesso!', true); } function renderPaginaUsuarios() { if (!currentUser || !ROLES_GERENCIAIS.includes(currentUser.role)) return; const el = document.getElementById('page-usuarios'); USUARIOS = INTEGRITY.loadWithVerification('sf_users') || DEFAULT_USUARIOS; const rows = USUARIOS.map((u, i) => `
`).join(''); el.innerHTML = `
Crie, edite e gerencie os acessos ao sistema.
`; } function atualizarUnidadeField() { const role = document.getElementById('edit-role').value; document.getElementById('edit-unidade-wrap').style.display = role === 'founder' ? 'none' : ''; } function abrirNovoUsuario() { document.getElementById('modal-user-title').textContent = 'Novo usuário'; document.getElementById('edit-user-idx').value = '-1'; document.getElementById('edit-nome').value = ''; document.getElementById('edit-usuario').value = ''; document.getElementById('edit-email').value = ''; document.getElementById('edit-senha').value = SENHA_PADRAO; document.getElementById('edit-role').value = 'unidade'; document.getElementById('edit-unidade').value = 'SCS'; document.getElementById('modal-user-err').style.display = 'none'; atualizarUnidadeField(); document.getElementById('modal-usuario').style.display = 'flex'; setTimeout(() => document.getElementById('edit-nome').focus(), 100); } function abrirEditarUsuario(idx) { USUARIOS = INTEGRITY.loadWithVerification('sf_users') || DEFAULT_USUARIOS; const u = USUARIOS[idx]; document.getElementById('modal-user-title').textContent = 'Editar usuário'; document.getElementById('edit-user-idx').value = idx; document.getElementById('edit-nome').value = u.nome; document.getElementById('edit-usuario').value = u.usuario || ''; document.getElementById('edit-email').value = u.email || ''; document.getElementById('edit-senha').value = ''; // Não preencher senha por segurança document.getElementById('edit-role').value = u.role; document.getElementById('edit-unidade').value = u.unidade || 'SCS'; document.getElementById('modal-user-err').style.display = 'none'; atualizarUnidadeField(); document.getElementById('modal-usuario').style.display = 'flex'; } async function salvarUsuarioForm() { const idx = parseInt(document.getElementById('edit-user-idx').value); const nome = document.getElementById('edit-nome').value.trim(); const usuario = document.getElementById('edit-usuario').value.trim().toLowerCase(); const email = document.getElementById('edit-email').value.trim().toLowerCase(); const senha = document.getElementById('edit-senha').value; const role = document.getElementById('edit-role').value; const unidade = (role !== 'founder') ? document.getElementById('edit-unidade').value : null; const err = document.getElementById('modal-user-err'); if (!nome || !usuario) { err.style.display='block'; err.textContent='Preencha nome e usuário.'; return; } if (!_supabase) { // Modo offline: senha obrigatória if (!senha) { err.style.display='block'; err.textContent='Preencha a senha.'; return; } if (senha.length < 4) { err.style.display='block'; err.textContent='Senha deve ter pelo menos 4 caracteres.'; return; } } USUARIOS = INTEGRITY.loadWithVerification('sf_users') || DEFAULT_USUARIOS; USUARIOS.forEach(u => { if (!u.usuario) u.usuario = u.email; }); const dupUser = USUARIOS.findIndex((x, i) => (x.usuario||'').toLowerCase() === usuario && i !== idx); if (dupUser >= 0) { err.style.display='block'; err.textContent='Este usuário já está cadastrado.'; return; } if (idx === -1) { const newId = 'u' + Date.now(); // Novo usuário sempre começa com senha padrão se não informada const senhaFinal = senha || SENHA_PADRAO; const senhaFinalHash = await hashSenha(senhaFinal); const novoUser = { id: newId, usuario, email, role, nome, unidade, senha: senhaFinalHash, primeiro_acesso: true }; USUARIOS.push(novoUser); } else { const senhaExistente = USUARIOS[idx].senha; USUARIOS[idx] = { ...USUARIOS[idx], usuario, email, role, nome, unidade }; // Só atualizar senha em modo offline; se campo preenchido, atualiza; senão mantém if (!_supabase) { USUARIOS[idx].senha = senha || senhaExistente; } else { delete USUARIOS[idx].senha; } // Remover senha ao salvar quando Supabase ativo } salvarUsuarios(); // Persistir no Supabase se disponível if (_supabase) { const u = idx === -1 ? USUARIOS[USUARIOS.length - 1] : USUARIOS[idx]; const _sHash = senha ? await hashSenha(senha) : null; DB.salvarUsuario({ ...u, senha: _sHash }).catch(e => console.warn('salvarUsuario Supabase:', e)); } fecharModal('modal-usuario'); renderPaginaUsuarios(); } function excluirUsuario(idx) { USUARIOS = INTEGRITY.loadWithVerification('sf_users') || DEFAULT_USUARIOS; const u = USUARIOS[idx]; if (!u) return; if (u.role === 'founder') { alert('O usuário Fundador não pode ser excluído.'); return; } if (!confirm(`Excluir usuário "${u.nome}" (${u.email})? Esta ação não pode ser desfeita.`)) return; USUARIOS.splice(idx, 1); salvarUsuarios(); renderPaginaUsuarios(); } // ============================================================ // CRM DE LEADS + ENTRADA DIÁRIA // ============================================================ const ETAPAS_FUNIL = ['conexão','qualificação','agendamento','consulta realizada','formalização','venda feita']; const ETAPA_CLASSES = { 'conexão':'funil-conexao','qualificação':'funil-qualificacao','agendamento':'funil-agendamento', 'consulta realizada':'funil-consulta','formalização':'funil-formalizacao','venda feita':'funil-venda' }; // ——— Domínios CRM ——— const PROCEDIMENTOS = [ 'Transplante Capilar', 'Transplante Capilar + 3 Meso', 'Transplante Capilar + 6 Meso', 'Transplante Capilar + 12 Meso', '1 Sessão de Meso', '3 Sessões de Meso', '6 Sessões de Meso', '12 Sessões de Meso' ]; const SESSOES_POR_PROCEDIMENTO = { 'Transplante Capilar': 0, 'Transplante Capilar + 3 Meso': 3, 'Transplante Capilar + 6 Meso': 6, 'Transplante Capilar + 12 Meso': 12, '1 Sessão de Meso': 1, '3 Sessões de Meso': 3, '6 Sessões de Meso': 6, '12 Sessões de Meso': 12 }; const ADICIONAIS = ['Sem Bodyhair', 'Com Bodyhair']; const ORIGENS_LEAD = ['Indicação', 'Instagram', 'Google', 'Outros']; const STATUS_LEAD = ['Novo', 'Em Contato', 'Agendado', 'Convertido', 'Perdido']; const FORMAS_PAGAMENTO = ['À Vista', 'Cartão de Crédito', 'Cartão de Débito', 'Financiamento', 'Boleto', 'Pix']; const STATUS_PAGAMENTO = ['Pendente', 'Pago', 'Parcelado', 'Cancelado']; const STATUS_LEAD_CLASSES = { 'Novo':'funil-conexao','Em Contato':'funil-qualificacao','Agendado':'funil-agendamento', 'Convertido':'funil-venda','Perdido':'funil-formalizacao' }; /* ── DADOS REAIS — inicialização síncrona ── */ const _FALLBACK_LEADS = [{"id":"sh_93573243134_2026_05_04","_from_sheets":true,"_sheets_key":"93573243134|2026-05-04","nome":"Eduardo do Prado Lobo","cpf":"935.732.431-34","unidade":"RVD","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-04","data_cirurgia":"2026-09-14","data_cadastro":"2026-05-04T00:00:00","data_registro":"2026-05-04","procedimento":"Transplante Capilar","valor_procedimento":17500.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Eliene","forma_pagamento":"","origem":"Indicação Vinicius","eh_mesoterapia":false,"entrada":3000.0,"saldo":14500.0},{"id":"sh_68666314591_2026_05_05","_from_sheets":true,"_sheets_key":"68666314591|2026-05-05","nome":"Marizaldo Santos Silva","cpf":"686.663.145-91","unidade":"RVD","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-05","data_cirurgia":"2026-07-04","data_cadastro":"2026-05-05T00:00:00","data_registro":"2026-05-05","procedimento":"Transplante Capilar","valor_procedimento":17400.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Micaelly","forma_pagamento":"","origem":"Rede Social","eh_mesoterapia":false,"entrada":3000.0,"saldo":14400.0},{"id":"sh_84297808153_2026_05_05","_from_sheets":true,"_sheets_key":"84297808153|2026-05-05","nome":"Alan Martins Queiroz","cpf":"842.978.081-53","unidade":"RVD","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-05","data_cirurgia":"2026-08-23","data_cadastro":"2026-05-05T00:00:00","data_registro":"2026-05-05","procedimento":"Transplante Capilar","valor_procedimento":16500.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Priscila","forma_pagamento":"","origem":"Lead do dia 19/01","eh_mesoterapia":false,"entrada":3000.0,"saldo":13500.0},{"id":"sh_64292355134_2026_05_08","_from_sheets":true,"_sheets_key":"64292355134|2026-05-08","nome":"Marcio Luiz Braz","cpf":"642.923.551-34","unidade":"RVD","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-08","data_cirurgia":"2026-06-14","data_cadastro":"2026-05-08T00:00:00","data_registro":"2026-05-08","procedimento":"Transplante Capilar","valor_procedimento":17500.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Micaelly","forma_pagamento":"","origem":"Lead do dia 05/03","eh_mesoterapia":false,"entrada":3000.0,"saldo":14500.0},{"id":"sh_04153838110_2026_05_15","_from_sheets":true,"_sheets_key":"04153838110|2026-05-15","nome":"Jean Carlos Eliazar Diniz","cpf":"041.538.381-10","unidade":"RVD","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-15","data_cirurgia":"2026-07-04","data_cadastro":"2026-05-15T00:00:00","data_registro":"2026-05-15","procedimento":"Transplante Capilar","valor_procedimento":16500.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Priscila","forma_pagamento":"","origem":"Lead do dia 05/03","eh_mesoterapia":false,"entrada":3000.0,"saldo":13500.0},{"id":"sh_02287348190_2026_05_18","_from_sheets":true,"_sheets_key":"02287348190|2026-05-18","nome":"Ridlle Moreira de Souza Silva","cpf":"022.873.481-90","unidade":"RVD","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-18","data_cirurgia":"","data_cadastro":"2026-05-18T00:00:00","data_registro":"2026-05-18","procedimento":"Transplante Capilar","valor_procedimento":16500.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Priscila","forma_pagamento":"","origem":"Lead do dia 23/01","eh_mesoterapia":false,"entrada":3000.0,"saldo":13500.0},{"id":"sh_45052956134_2026_05_18","_from_sheets":true,"_sheets_key":"45052956134|2026-05-18","nome":"Geraldo Cesar Martins da Silva","cpf":"450.529.561-34","unidade":"RVD","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-18","data_cirurgia":"","data_cadastro":"2026-05-18T00:00:00","data_registro":"2026-05-18","procedimento":"Transplante Capilar","valor_procedimento":16500.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Priscila","forma_pagamento":"","origem":"Indicação Ridlle","eh_mesoterapia":false,"entrada":3000.0,"saldo":13500.0},{"id":"sh_00596516100_2026_05_20","_from_sheets":true,"_sheets_key":"00596516100|2026-05-20","nome":"Fagner Costa Santos","cpf":"005.965.161-00","unidade":"RVD","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-20","data_cirurgia":"2026-07-05","data_cadastro":"2026-05-20T00:00:00","data_registro":"2026-05-20","procedimento":"Transplante Capilar","valor_procedimento":17500.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Micaelly","forma_pagamento":"","origem":"Paciente antigo","eh_mesoterapia":false,"entrada":3000.0,"saldo":14500.0},{"id":"sh_40306470144_2026_05_27","_from_sheets":true,"_sheets_key":"40306470144|2026-05-27","nome":"Arnoldo Kubelker","cpf":"403.064.701.44","unidade":"RVD","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-27","data_cirurgia":"2026-09-07","data_cadastro":"2026-05-27T00:00:00","data_registro":"2026-05-27","procedimento":"Transplante Capilar","valor_procedimento":17500.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Micaelly","forma_pagamento":"","origem":"Indicação Keila","eh_mesoterapia":false,"entrada":3000.0,"saldo":14500.0},{"id":"sh_89591534191_2026_05_29","_from_sheets":true,"_sheets_key":"89591534191|2026-05-29","nome":"Leandro Vieira da Silva","cpf":"895.915.341-91","unidade":"RVD","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-29","data_cirurgia":"2026-11-05","data_cadastro":"2026-05-29T00:00:00","data_registro":"2026-05-29","procedimento":"Transplante Capilar","valor_procedimento":16000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Priscila","forma_pagamento":"","origem":"Lead do dia 20/04","eh_mesoterapia":false,"entrada":0.0,"saldo":9000.0},{"id":"sh_30301761850_2026_04_01","_from_sheets":true,"_sheets_key":"30301761850|2026-04-01","nome":"Anderson Carvalho da Silva","cpf":"303.017.618-50","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-01","data_cirurgia":"","data_cadastro":"2026-04-01T00:00:00","data_registro":"2026-04-01","procedimento":"Transplante Capilar","valor_procedimento":13999.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Wagner","forma_pagamento":"Cartão Cred 12 X","origem":"Indicação Pcte","eh_mesoterapia":false,"entrada":2000.0,"saldo":11999.0},{"id":"sh_42054459895_2026_04_01","_from_sheets":true,"_sheets_key":"42054459895|2026-04-01","nome":"Luiz Fernando Roque da Silva","cpf":"420.544.598-95","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-01","data_cirurgia":"2026-07-02","data_cadastro":"2026-04-01T00:00:00","data_registro":"2026-04-01","procedimento":"Transplante Capilar","valor_procedimento":11000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Luciana","forma_pagamento":"PIX","origem":"Lead","eh_mesoterapia":false,"entrada":1000.0,"saldo":10000.0},{"id":"sh_29043340847_2026_04_01","_from_sheets":true,"_sheets_key":"29043340847|2026-04-01","nome":"Sidney Oliveira de França","cpf":"290.433.408-47","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-01","data_cirurgia":"2026-05-26","data_cadastro":"2026-04-01T00:00:00","data_registro":"2026-04-01","procedimento":"Transplante Capilar","valor_procedimento":14000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Luciana","forma_pagamento":"Cartão Cred 12 X","origem":"Lead","eh_mesoterapia":false,"entrada":2000.0,"saldo":12000.0},{"id":"sh_04041128544_2026_04_01","_from_sheets":true,"_sheets_key":"04041128544|2026-04-01","nome":"Mariza da Silva Cardoso","cpf":"040.411.285-44","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-01","data_cirurgia":"2026-05-05","data_cadastro":"2026-04-01T00:00:00","data_registro":"2026-04-01","procedimento":"Transplante Capilar","valor_procedimento":6500.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Luciana","forma_pagamento":"Cartão Debito","origem":"Indicação Pcte","eh_mesoterapia":false,"entrada":6500.0,"saldo":6500.0},{"id":"sh_27775405864_2026_04_01","_from_sheets":true,"_sheets_key":"27775405864|2026-04-01","nome":"Adriano da Silva CavalcantI","cpf":"277.754.058-64","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-01","data_cirurgia":"2026-06-02","data_cadastro":"2026-04-01T00:00:00","data_registro":"2026-04-01","procedimento":"Transplante Capilar","valor_procedimento":14000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Luciana","forma_pagamento":"Cartão Cred 12 X","origem":"Indicação Pcte","eh_mesoterapia":false,"entrada":2000.0,"saldo":12000.0},{"id":"sh_33619361878_2026_04_01","_from_sheets":true,"_sheets_key":"33619361878|2026-04-01","nome":"Flavio Luiz Marcondes de Campos","cpf":"336.193.618-78","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-01","data_cirurgia":"2026-06-24","data_cadastro":"2026-04-01T00:00:00","data_registro":"2026-04-01","procedimento":"Transplante Capilar","valor_procedimento":12000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Luciana","forma_pagamento":"PIX","origem":"Paciente Bse","eh_mesoterapia":false,"entrada":6000.0,"saldo":6000.0},{"id":"sh_11607743825_2026_04_01","_from_sheets":true,"_sheets_key":"11607743825|2026-04-01","nome":"Jefferson Alexandre Martinez","cpf":"116.077.438-25","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-01","data_cirurgia":"2026-06-24","data_cadastro":"2026-04-01T00:00:00","data_registro":"2026-04-01","procedimento":"Transplante Capilar","valor_procedimento":12000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Luciana","forma_pagamento":"PIX","origem":"Indicação Pcte","eh_mesoterapia":false,"entrada":6000.0,"saldo":6000.0},{"id":"sh_29086614892_2026_04_01","_from_sheets":true,"_sheets_key":"29086614892|2026-04-01","nome":"Deonircio Garcia Junior","cpf":"290.866.148-92","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-01","data_cirurgia":"2026-08-12","data_cadastro":"2026-04-01T00:00:00","data_registro":"2026-04-01","procedimento":"Transplante Capilar","valor_procedimento":13000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Luciana","forma_pagamento":"Cartão Cred 12 X","origem":"Lead","eh_mesoterapia":false,"entrada":2000.0,"saldo":11000.0},{"id":"sh_29313963892_2026_04_03","_from_sheets":true,"_sheets_key":"29313963892|2026-04-03","nome":"André Sandro da Silva Paiva","cpf":"293.139.638-92","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-03","data_cirurgia":"2026-06-26","data_cadastro":"2026-04-03T00:00:00","data_registro":"2026-04-03","procedimento":"Transplante Capilar","valor_procedimento":17999.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Wagner","forma_pagamento":"Cartão Cred 12 X","origem":"Indicação Pcte","eh_mesoterapia":false,"entrada":6800.0,"saldo":11199.0},{"id":"sh_29264028803_2026_04_09","_from_sheets":true,"_sheets_key":"29264028803|2026-04-09","nome":"Nilson Paulo da Silva","cpf":"292.640.288-03","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-09","data_cirurgia":"2026-06-01","data_cadastro":"2026-04-09T00:00:00","data_registro":"2026-04-09","procedimento":"Transplante Capilar","valor_procedimento":14000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Luciana","forma_pagamento":"Cartão Cred 12 X","origem":"Indicação Pcte","eh_mesoterapia":false,"entrada":2000.0,"saldo":12000.0},{"id":"sh_28270187801_2026_04_09","_from_sheets":true,"_sheets_key":"28270187801|2026-04-09","nome":"Henrique Nunes Carvalho","cpf":"282.701.878-01","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-09","data_cirurgia":"2026-08-12","data_cadastro":"2026-04-09T00:00:00","data_registro":"2026-04-09","procedimento":"Transplante Capilar","valor_procedimento":13000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Luciana","forma_pagamento":"PIX","origem":"Lead","eh_mesoterapia":false,"entrada":2000.0,"saldo":11000.0},{"id":"sh_30051162806_2026_04_09","_from_sheets":true,"_sheets_key":"30051162806|2026-04-09","nome":"Mohamad Adel Kassab","cpf":"300.511.628-06","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-09","data_cirurgia":"2026-05-05","data_cadastro":"2026-04-09T00:00:00","data_registro":"2026-04-09","procedimento":"Transplante Capilar","valor_procedimento":13999.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Luciana","forma_pagamento":"Cartão Cred 12 X","origem":"Paciente Base","eh_mesoterapia":false,"entrada":2000.0,"saldo":11999.0},{"id":"sh_34594662862_2026_04_09","_from_sheets":true,"_sheets_key":"34594662862|2026-04-09","nome":"Leandro da Silva Carvalho","cpf":"345.946.628-62","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-09","data_cirurgia":"2026-08-06","data_cadastro":"2026-04-09T00:00:00","data_registro":"2026-04-09","procedimento":"Transplante Capilar","valor_procedimento":13000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Luciana","forma_pagamento":"Cartão Cred 12 X","origem":"Paciente Base","eh_mesoterapia":false,"entrada":2000.0,"saldo":11000.0},{"id":"sh_31455957844_2026_04_09","_from_sheets":true,"_sheets_key":"31455957844|2026-04-09","nome":"Mauricio César da Silva Santos","cpf":"314.559.578-44","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-09","data_cirurgia":"2026-06-26","data_cadastro":"2026-04-09T00:00:00","data_registro":"2026-04-09","procedimento":"Transplante Capilar","valor_procedimento":14249.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Wagner","forma_pagamento":"Cartão Cred 12 X","origem":"Indicação Pcte","eh_mesoterapia":false,"entrada":14249.0,"saldo":0.0},{"id":"sh_00279326564_2026_04_15","_from_sheets":true,"_sheets_key":"00279326564|2026-04-15","nome":"Ednilson Oliveira Caetano","cpf":"002.793.265-64","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-15","data_cirurgia":"2026-07-20","data_cadastro":"2026-04-15T00:00:00","data_registro":"2026-04-15","procedimento":"Transplante Capilar","valor_procedimento":12500.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Wagner","forma_pagamento":"Cartão Cred 12 X","origem":"Indicação Pcte","eh_mesoterapia":false,"entrada":5000.0,"saldo":7500.0},{"id":"sh_46710371816_2026_04_18","_from_sheets":true,"_sheets_key":"46710371816|2026-04-18","nome":"Daniel dos Santos Vargas","cpf":"467.103.718-16","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-18","data_cirurgia":"2026-07-17","data_cadastro":"2026-04-18T00:00:00","data_registro":"2026-04-18","procedimento":"Transplante Capilar","valor_procedimento":12000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Luciana","forma_pagamento":"PIX","origem":"Lead","eh_mesoterapia":false,"entrada":2000.0,"saldo":10000.0},{"id":"sh_32331922829_2026_04_20","_from_sheets":true,"_sheets_key":"32331922829|2026-04-20","nome":"Hildeslandio Barbosa de Medeiros","cpf":"323.319.228-29","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-20","data_cirurgia":"","data_cadastro":"2026-04-20T00:00:00","data_registro":"2026-04-20","procedimento":"Transplante Capilar","valor_procedimento":13999.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Wagner","forma_pagamento":"Cartão Cred 12 X","origem":"Indicação Pcte","eh_mesoterapia":false,"entrada":2000.0,"saldo":11999.0},{"id":"sh_16579878843_2026_04_23","_from_sheets":true,"_sheets_key":"16579878843|2026-04-23","nome":"Fabio Luiz Santos Carvalho","cpf":"165.798.788-43","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-23","data_cirurgia":"2026-08-05","data_cadastro":"2026-04-23T00:00:00","data_registro":"2026-04-23","procedimento":"Transplante Capilar","valor_procedimento":14000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Luciana","forma_pagamento":"Cartão Cred 12 X","origem":"Indicação Pcte","eh_mesoterapia":false,"entrada":2000.0,"saldo":12000.0},{"id":"sh_35853895893_2026_04_23","_from_sheets":true,"_sheets_key":"35853895893|2026-04-23","nome":"Erick Vilela Mariano","cpf":"358.538.958-93","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-23","data_cirurgia":"2026-05-23","data_cadastro":"2026-04-23T00:00:00","data_registro":"2026-04-23","procedimento":"Transplante Capilar","valor_procedimento":14000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Luciana","forma_pagamento":"Cartão Cred 12 X","origem":"Lead","eh_mesoterapia":false,"entrada":2000.0,"saldo":12000.0},{"id":"sh_38419308838_2026_04_23","_from_sheets":true,"_sheets_key":"38419308838|2026-04-23","nome":"Reginaldo Carvalho de Matos","cpf":"384.193.088-38","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-23","data_cirurgia":"2026-08-20","data_cadastro":"2026-04-23T00:00:00","data_registro":"2026-04-23","procedimento":"Transplante Capilar","valor_procedimento":13999.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Wagner","forma_pagamento":"Cartão Cred 12 X","origem":"Indicação Pcte","eh_mesoterapia":false,"entrada":2000.0,"saldo":11999.0},{"id":"sh_16579878843_2026_04_23","_from_sheets":true,"_sheets_key":"16579878843|2026-04-23","nome":"Marcelo Rocha Farias","cpf":"165.798.788-43","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-23","data_cirurgia":"2026-07-20","data_cadastro":"2026-04-23T00:00:00","data_registro":"2026-04-23","procedimento":"Transplante Capilar","valor_procedimento":14000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Luciana","forma_pagamento":"Cartão Cred 12 X","origem":"Indicação Pcte","eh_mesoterapia":false,"entrada":2000.0,"saldo":12000.0},{"id":"sh_01207586528_2026_04_24","_from_sheets":true,"_sheets_key":"01207586528|2026-04-24","nome":"Leandro Aragão Dos Santos","cpf":"012.075.865-28","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-24","data_cirurgia":"","data_cadastro":"2026-04-24T00:00:00","data_registro":"2026-04-24","procedimento":"Transplante Capilar","valor_procedimento":10000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Wagner","forma_pagamento":"Cartão Cred 12 X","origem":"IIndicação","eh_mesoterapia":false,"entrada":10000.0,"saldo":0.0},{"id":"sh_18312961879_2026_04_30","_from_sheets":true,"_sheets_key":"18312961879|2026-04-30","nome":"Odair Dias de Oliveira","cpf":"183.129.618-79","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-30","data_cirurgia":"2026-08-13","data_cadastro":"2026-04-30T00:00:00","data_registro":"2026-04-30","procedimento":"Transplante Barba","valor_procedimento":11000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Luciana","forma_pagamento":"PIX","origem":"Indicação","eh_mesoterapia":false,"entrada":1000.0,"saldo":10000.0},{"id":"sh_50696518899_2026_04_30","_from_sheets":true,"_sheets_key":"50696518899|2026-04-30","nome":"Lucas Junior Souza Quintino","cpf":"506.965.188-99","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-30","data_cirurgia":"2026-05-29","data_cadastro":"2026-04-30T00:00:00","data_registro":"2026-04-30","procedimento":"Transplante Capilar","valor_procedimento":13000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Wagner","forma_pagamento":"PIX","origem":"Indicação Pcte","eh_mesoterapia":false,"entrada":10000.0,"saldo":3000.0},{"id":"sh_01448805805_2026_04_03","_from_sheets":true,"_sheets_key":"01448805805|2026-04-03","nome":"Joao Duarte Rito","cpf":"014.488.058-05","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-03","data_cirurgia":"","data_cadastro":"2026-04-03T00:00:00","data_registro":"2026-04-03","procedimento":"MESOTERAPIA","valor_procedimento":1800.0,"valor_adicional":0,"sessoes_contratadas":0,"consultor":"Wagner","forma_pagamento":"Cartão Cred 3 X","origem":"Paciente Base","eh_mesoterapia":true,"entrada":1800.0,"saldo":0},{"id":"sh_25095284839_2026_04_08","_from_sheets":true,"_sheets_key":"25095284839|2026-04-08","nome":"Davi Pereira De Souza","cpf":"250.952.848-39","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-08","data_cirurgia":"","data_cadastro":"2026-04-08T00:00:00","data_registro":"2026-04-08","procedimento":"MESOTERAPIA","valor_procedimento":3000.0,"valor_adicional":0,"sessoes_contratadas":0,"consultor":"Wagner","forma_pagamento":"Cartão Cred 4 X","origem":"Paciente Base","eh_mesoterapia":true,"entrada":3000.0,"saldo":0},{"id":"sh_16915965823_2026_04_11","_from_sheets":true,"_sheets_key":"16915965823|2026-04-11","nome":"Mateus Dos Santos","cpf":"169.159.658-23","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-11","data_cirurgia":"","data_cadastro":"2026-04-11T00:00:00","data_registro":"2026-04-11","procedimento":"MESOTERAPIA","valor_procedimento":3800.0,"valor_adicional":0,"sessoes_contratadas":0,"consultor":"Wagner","forma_pagamento":"Cartão Cred 3 X","origem":"Paciente Base","eh_mesoterapia":true,"entrada":3800.0,"saldo":0},{"id":"sh_24800064848_2026_04_14","_from_sheets":true,"_sheets_key":"24800064848|2026-04-14","nome":"Claudio Cesar Amici","cpf":"248.000.648-48","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-14","data_cirurgia":"","data_cadastro":"2026-04-14T00:00:00","data_registro":"2026-04-14","procedimento":"MESOTERAPIA","valor_procedimento":1800.0,"valor_adicional":0,"sessoes_contratadas":0,"consultor":"Wagner","forma_pagamento":"Cartão Cred 4 X","origem":"Paciente Base","eh_mesoterapia":true,"entrada":1800.0,"saldo":0},{"id":"sh_01435133897_2026_04_22","_from_sheets":true,"_sheets_key":"01435133897|2026-04-22","nome":"Selma Irineia de Lima","cpf":"014.351.338-97","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-22","data_cirurgia":"","data_cadastro":"2026-04-22T00:00:00","data_registro":"2026-04-22","procedimento":"MESOTERAPIA","valor_procedimento":1800.0,"valor_adicional":0,"sessoes_contratadas":0,"consultor":"Luciana","forma_pagamento":"Cartão Cred 3 X","origem":"Paciente Indicação","eh_mesoterapia":true,"entrada":1800.0,"saldo":0},{"id":"sh_34641742804_2026_04_22","_from_sheets":true,"_sheets_key":"34641742804|2026-04-22","nome":"Luiz Carlos Granata","cpf":"346.417.428-04","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-22","data_cirurgia":"","data_cadastro":"2026-04-22T00:00:00","data_registro":"2026-04-22","procedimento":"MESOTERAPIA","valor_procedimento":1800.0,"valor_adicional":0,"sessoes_contratadas":0,"consultor":"Luciana","forma_pagamento":"Cartão Cred 5 X","origem":"Paciente Indicação","eh_mesoterapia":true,"entrada":1800.0,"saldo":0},{"id":"sh_00782711855_2026_04_22","_from_sheets":true,"_sheets_key":"00782711855|2026-04-22","nome":"Elvira Solange de Lima","cpf":"007.827.118-55","unidade":"GRU","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-04-22","data_cirurgia":"","data_cadastro":"2026-04-22T00:00:00","data_registro":"2026-04-22","procedimento":"MESOTERAPIA","valor_procedimento":1800.0,"valor_adicional":0,"sessoes_contratadas":0,"consultor":"Luciana","forma_pagamento":"Cartão Cred 5 X","origem":"Paciente Indicação","eh_mesoterapia":true,"entrada":1800.0,"saldo":0},{"id":"sh_19523448838_2026_05_04","_from_sheets":true,"_sheets_key":"19523448838|2026-05-04","nome":"EMERSON ESTEVAM DA SILVA","cpf":"195.234.488-38","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-04","data_cirurgia":"2026-08-14","data_cadastro":"2026-05-04T00:00:00","data_registro":"2026-05-04","procedimento":"Transplante Capilar","valor_procedimento":13999.99,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"VANESSA","forma_pagamento":"ATÉ 5 DIAS","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":13999.99,"saldo":0.0},{"id":"sh_29871161875_2026_05_05","_from_sheets":true,"_sheets_key":"29871161875|2026-05-05","nome":"MARCILIO LUIS RODRIGUES","cpf":"298.711.618-75","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-05","data_cirurgia":"","data_cadastro":"2026-05-05T00:00:00","data_registro":"2026-05-05","procedimento":"Transplante Capilar","valor_procedimento":13999.99,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"VANESSA","forma_pagamento":"ATÉ 5 DIAS","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":2100.0,"saldo":11899.99},{"id":"sh_22481476867_2026_05_05","_from_sheets":true,"_sheets_key":"22481476867|2026-05-05","nome":"RODRIGO ANDRÉ MARTINS CAMARA","cpf":"224.814.768-67","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-05","data_cirurgia":"2026-10-14","data_cadastro":"2026-05-05T00:00:00","data_registro":"2026-05-05","procedimento":"Transplante Capilar","valor_procedimento":12000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"ANA","forma_pagamento":"ATÉ 5 DIAS","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":1080.0,"saldo":10920.0},{"id":"sh_37513824886_2026_05_06","_from_sheets":true,"_sheets_key":"37513824886|2026-05-06","nome":"CIVALDO RODRIGUES SILVA","cpf":"375.138.248-86","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-06","data_cirurgia":"","data_cadastro":"2026-05-06T00:00:00","data_registro":"2026-05-06","procedimento":"Transplante Capilar","valor_procedimento":12000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"ANA","forma_pagamento":"ATÉ 5 DIAS","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":1000.0,"saldo":11000.0},{"id":"sh_21619946890_2026_05_06","_from_sheets":true,"_sheets_key":"21619946890|2026-05-06","nome":"RICHARD AUGUSTO RODRIGUES","cpf":"216.199.468-90","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-06","data_cirurgia":"2026-08-07","data_cadastro":"2026-05-06T00:00:00","data_registro":"2026-05-06","procedimento":"Transplante Capilar","valor_procedimento":13999.99,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"VANESSA","forma_pagamento":"ATÉ 5 DIAS","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":2000.0,"saldo":11999.99},{"id":"sh_31635409888_2026_05_06","_from_sheets":true,"_sheets_key":"31635409888|2026-05-06","nome":"WENDELL GARCIA RODRIGUES","cpf":"316.354.098-88","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-06","data_cirurgia":"","data_cadastro":"2026-05-06T00:00:00","data_registro":"2026-05-06","procedimento":"Transplante Capilar","valor_procedimento":14000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"ANA","forma_pagamento":"ATÉ 5 DIAS","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":7000.0,"saldo":7000.0},{"id":"sh_03076228609_2026_06_07","_from_sheets":true,"_sheets_key":"03076228609|2026-06-07","nome":"HERNANE SANTOS MÓDENO","cpf":"030.762.286-09","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-06-07","data_cirurgia":"2026-06-09","data_cadastro":"2026-06-07T00:00:00","data_registro":"2026-06-07","procedimento":"Transplante Capilar","valor_procedimento":13000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"VANESSA","forma_pagamento":"ATÉ 5 DIAS","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":2000.0,"saldo":11000.0},{"id":"sh_33088236830_2026_06_07","_from_sheets":true,"_sheets_key":"33088236830|2026-06-07","nome":"FERNANDO BONFIM BRAIT","cpf":"330.882.368-30","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-06-07","data_cirurgia":"2026-06-25","data_cadastro":"2026-06-07T00:00:00","data_registro":"2026-06-07","procedimento":"Transplante Capilar","valor_procedimento":13000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"VANESSA","forma_pagamento":"ATÉ 5 DIAS","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":500.0,"saldo":12500.0},{"id":"sh_22996340884_2026_05_08","_from_sheets":true,"_sheets_key":"22996340884|2026-05-08","nome":"ROBERTO WAGNER DE SOUZA","cpf":"229.963.408-84","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-08","data_cirurgia":"2026-07-06","data_cadastro":"2026-05-08T00:00:00","data_registro":"2026-05-08","procedimento":"Transplante Capilar","valor_procedimento":13000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"ANA","forma_pagamento":"ATÉ 5 DIAS","origem":"BASE","eh_mesoterapia":false,"entrada":3000.0,"saldo":10000.0},{"id":"sh_34528413833_2026_05_11","_from_sheets":true,"_sheets_key":"34528413833|2026-05-11","nome":"RAFAEL DA SILVA GOMES","cpf":"345.284.138-33","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-11","data_cirurgia":"2026-05-20","data_cadastro":"2026-05-11T00:00:00","data_registro":"2026-05-11","procedimento":"Transplante Capilar","valor_procedimento":13999.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"ANA","forma_pagamento":"PAGO","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":13999.0,"saldo":0.0},{"id":"sh_05130244842_2026_05_11","_from_sheets":true,"_sheets_key":"05130244842|2026-05-11","nome":"JOSE NIVALDO DA CUNHA","cpf":"051.302.448-42","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-11","data_cirurgia":"2026-07-27","data_cadastro":"2026-05-11T00:00:00","data_registro":"2026-05-11","procedimento":"Transplante Capilar","valor_procedimento":13999.99,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"VANESSA","forma_pagamento":"PAGO","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":13999.99,"saldo":0.0},{"id":"sh_21683057813_2026_05_14","_from_sheets":true,"_sheets_key":"21683057813|2026-05-14","nome":"FABIO FERREIRA GOMES Y GOMES","cpf":"216.830.578-13","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-14","data_cirurgia":"","data_cadastro":"2026-05-14T00:00:00","data_registro":"2026-05-14","procedimento":"Transplante Capilar","valor_procedimento":14000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"ANA","forma_pagamento":"","origem":"LEAD","eh_mesoterapia":false,"entrada":1000.0,"saldo":13000.0},{"id":"sh_41496315812_2026_05_15","_from_sheets":true,"_sheets_key":"41496315812|2026-05-15","nome":"WILLIAM PESSOA RAMALHO","cpf":"414.963.158-12","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-15","data_cirurgia":"2026-06-06","data_cadastro":"2026-05-15T00:00:00","data_registro":"2026-05-15","procedimento":"Transplante Capilar","valor_procedimento":13999.99,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"VANESSA","forma_pagamento":"ATÉ 5 DIAS","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":2000.0,"saldo":11999.99},{"id":"sh_32157760814_2026_05_18","_from_sheets":true,"_sheets_key":"32157760814|2026-05-18","nome":"FELIPE MORGAN PEREIRA","cpf":"32157760814","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-18","data_cirurgia":"2026-08-17","data_cadastro":"2026-05-18T00:00:00","data_registro":"2026-05-18","procedimento":"Transplante Capilar","valor_procedimento":11999.99,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"VANESSA","forma_pagamento":"ATÉ 5 DIAS","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":1000.0,"saldo":10999.99},{"id":"sh_19433572858_2026_05_19","_from_sheets":true,"_sheets_key":"19433572858|2026-05-19","nome":"SERGIO LUIZ DOS SANTOS","cpf":"194.335.728-58","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-19","data_cirurgia":"2026-05-30","data_cadastro":"2026-05-19T00:00:00","data_registro":"2026-05-19","procedimento":"Transplante Capilar","valor_procedimento":11000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"ANA","forma_pagamento":"ATÉ 5 DIAS","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":5000.0,"saldo":6000.0},{"id":"sh_11064687830_2026_05_19","_from_sheets":true,"_sheets_key":"11064687830|2026-05-19","nome":"MAURICIO FERREIRA DE MACEDO","cpf":"110.646.878-30","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-19","data_cirurgia":"2026-08-14","data_cadastro":"2026-05-19T00:00:00","data_registro":"2026-05-19","procedimento":"Transplante Capilar","valor_procedimento":12000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"ANA","forma_pagamento":"ATÉ 5 DIAS","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":3000.0,"saldo":9000.0},{"id":"sh_27459851833_2026_05_19","_from_sheets":true,"_sheets_key":"27459851833|2026-05-19","nome":"EDMAR PEREIRA DOS SANTOS","cpf":"274.598.518-33","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-19","data_cirurgia":"","data_cadastro":"2026-05-19T00:00:00","data_registro":"2026-05-19","procedimento":"Transplante Capilar","valor_procedimento":14000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"ANA","forma_pagamento":"ATÉ 5 DIAS","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":3000.0,"saldo":12999.99},{"id":"sh_52438968896_2026_05_19","_from_sheets":true,"_sheets_key":"52438968896|2026-05-19","nome":"VITOR MARTINS CRUZ","cpf":"524.389.688-96","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-19","data_cirurgia":"2026-08-03","data_cadastro":"2026-05-19T00:00:00","data_registro":"2026-05-19","procedimento":"Transplante Capilar","valor_procedimento":13999.99,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"VANESSA","forma_pagamento":"ATÉ 5 DIAS","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":1000.0,"saldo":12999.99},{"id":"sh_33781665844_2026_05_19","_from_sheets":true,"_sheets_key":"33781665844|2026-05-19","nome":"JOSÉ ROBERTO MORENO DE PAULA","cpf":"337.816.658-44","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-19","data_cirurgia":"2026-06-22","data_cadastro":"2026-05-19T00:00:00","data_registro":"2026-05-19","procedimento":"Transplante Capilar","valor_procedimento":12000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"ANA","forma_pagamento":"ATÉ 5 DIAS","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":3000.0,"saldo":11000.0},{"id":"sh_21634869871_2026_05_21","_from_sheets":true,"_sheets_key":"21634869871|2026-05-21","nome":"ERICK BENTO DIAS FERREIRA","cpf":"216.348.698-71","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-21","data_cirurgia":"2026-07-18","data_cadastro":"2026-05-21T00:00:00","data_registro":"2026-05-21","procedimento":"Transplante Capilar","valor_procedimento":13000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"VANESSA","forma_pagamento":"ATÉ 5 DIAS","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":11000.0,"saldo":2000.0},{"id":"sh_42157945873_2026_05_21","_from_sheets":true,"_sheets_key":"42157945873|2026-05-21","nome":"YGOR AILLON ALVES NUNES","cpf":"421.579.458-73","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-21","data_cirurgia":"","data_cadastro":"2026-05-21T00:00:00","data_registro":"2026-05-21","procedimento":"Transplante Capilar","valor_procedimento":12000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"ANA","forma_pagamento":"ATÉ 5 DIAS","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":2000.0,"saldo":10000.0},{"id":"sh_36697440880_2026_05_22","_from_sheets":true,"_sheets_key":"36697440880|2026-05-22","nome":"NEILSON PEREIRA GAMA","cpf":"366.974.408-80","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-22","data_cirurgia":"2026-06-18","data_cadastro":"2026-05-22T00:00:00","data_registro":"2026-05-22","procedimento":"Transplante Capilar","valor_procedimento":13000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"VANESSA","forma_pagamento":"ATÉ 5 DIAS","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":5000.0,"saldo":8000.0},{"id":"sh_43717937898_2026_05_23","_from_sheets":true,"_sheets_key":"43717937898|2026-05-23","nome":"WESLLEY ALVES PEREIRA","cpf":"437.179.378-98","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-23","data_cirurgia":"","data_cadastro":"2026-05-23T00:00:00","data_registro":"2026-05-23","procedimento":"Transplante Capilar","valor_procedimento":13999.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"ANA","forma_pagamento":"ATÉ 5 DIAS","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":3000.0,"saldo":11999.0},{"id":"sh_00000000000_2026_05_25","_from_sheets":true,"_sheets_key":"0|2026-05-25","nome":"HENRIQUE BOSCO","cpf":"","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-25","data_cirurgia":"2026-06-01","data_cadastro":"2026-05-25T00:00:00","data_registro":"2026-05-25","procedimento":"Transplante Capilar","valor_procedimento":13999.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"ANA","forma_pagamento":"ATÉ 5 DIAS","origem":"LEAD","eh_mesoterapia":false,"entrada":1000.0,"saldo":12999.0},{"id":"sh_26026499881_2026_05_25","_from_sheets":true,"_sheets_key":"26026499881|2026-05-25","nome":"MARCELO RICARDO TELES BARBOSA","cpf":"260.264.998-81","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-25","data_cirurgia":"2026-08-04","data_cadastro":"2026-05-25T00:00:00","data_registro":"2026-05-25","procedimento":"Transplante Capilar","valor_procedimento":13999.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"ANA","forma_pagamento":"ATÉ 5 DIAS","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":1000.0,"saldo":12999.0},{"id":"sh_07442725643_2026_05_26","_from_sheets":true,"_sheets_key":"07442725643|2026-05-26","nome":"BERNARDO RODRIGUES DO NASCIMENTO","cpf":"074.427.256-43","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-26","data_cirurgia":"","data_cadastro":"2026-05-26T00:00:00","data_registro":"2026-05-26","procedimento":"Transplante Capilar","valor_procedimento":12999.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"ANA","forma_pagamento":"ATÉ 5 DIAS","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":1000.0,"saldo":11000.0},{"id":"sh_06963769540_2026_05_27","_from_sheets":true,"_sheets_key":"06963769540|2026-05-27","nome":"VAGNER SANTOS DOS ANJOS","cpf":"069.637.695-40","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-27","data_cirurgia":"","data_cadastro":"2026-05-27T00:00:00","data_registro":"2026-05-27","procedimento":"Transplante Capilar","valor_procedimento":12000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"ANA","forma_pagamento":"ATÉ 5 DIAS","origem":"GOOGLE","eh_mesoterapia":false,"entrada":2000.0,"saldo":10000.0},{"id":"sh_26282382840_2026_05_29","_from_sheets":true,"_sheets_key":"26282382840|2026-05-29","nome":"EDUARDO ALVADJAN","cpf":"262.823.828-40","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-29","data_cirurgia":"","data_cadastro":"2026-05-29T00:00:00","data_registro":"2026-05-29","procedimento":"Transplante Capilar","valor_procedimento":13999.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"VANESSA","forma_pagamento":"ATÉ 5 DIAS","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":3000.0,"saldo":10999.99},{"id":"sh_25320774842_2026_05_29","_from_sheets":true,"_sheets_key":"25320774842|2026-05-29","nome":"MARCO ANTONIO MARIQUE RANZAN","cpf":"253.207.748-42","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-29","data_cirurgia":"2026-06-27","data_cadastro":"2026-05-29T00:00:00","data_registro":"2026-05-29","procedimento":"Transplante Capilar","valor_procedimento":13999.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"VANESSA","forma_pagamento":"","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":13999.99,"saldo":0.0},{"id":"sh_07734045898_2026_05_29","_from_sheets":true,"_sheets_key":"07734045898|2026-05-29","nome":"ERNANDIS FARIA DA NOBREGA","cpf":"077.340.458-98","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-29","data_cirurgia":"2026-08-12","data_cadastro":"2026-05-29T00:00:00","data_registro":"2026-05-29","procedimento":"Transplante Capilar","valor_procedimento":14000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"ANA","forma_pagamento":"ATÉ 5 DIAS","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":2000.0,"saldo":12000.0},{"id":"sh_25731837856_2026_05_30","_from_sheets":true,"_sheets_key":"25731837856|2026-05-30","nome":"WAGNER MIRANDA DE OLIVEIRA","cpf":"257.318.378-56","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-30","data_cirurgia":"","data_cadastro":"2026-05-30T00:00:00","data_registro":"2026-05-30","procedimento":"Transplante Capilar","valor_procedimento":13000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"VANESSA","forma_pagamento":"ATÉ 5 DIAS","origem":"INDICAÇÃO","eh_mesoterapia":false,"entrada":1000.0,"saldo":12000.0},{"id":"sh_11650169825_2026_05_07","_from_sheets":true,"_sheets_key":"11650169825|2026-05-07","nome":"MARCIO RIBEIRO","cpf":"116.501.698-25","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-07","data_cirurgia":"","data_cadastro":"2026-05-07T00:00:00","data_registro":"2026-05-07","procedimento":"PRP","valor_procedimento":2000.0,"valor_adicional":0,"sessoes_contratadas":0,"consultor":"VANESSA","forma_pagamento":"","origem":"","eh_mesoterapia":true,"entrada":2000.0,"saldo":0},{"id":"sh_14793988881_2026_05_12","_from_sheets":true,"_sheets_key":"14793988881|2026-05-12","nome":"CESAR CARNEIRO DE MOURA","cpf":"147.939.888-81","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-12","data_cirurgia":"","data_cadastro":"2026-05-12T00:00:00","data_registro":"2026-05-12","procedimento":"MESOTERAPIA","valor_procedimento":350.0,"valor_adicional":0,"sessoes_contratadas":0,"consultor":"VANESSA","forma_pagamento":"","origem":"","eh_mesoterapia":true,"entrada":350.0,"saldo":0},{"id":"sh_50381535851_2026_05_13","_from_sheets":true,"_sheets_key":"50381535851|2026-05-13","nome":"SABRINA MIRANDA DE OLIVEIRA MOURA","cpf":"503.815.358-51","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-13","data_cirurgia":"","data_cadastro":"2026-05-13T00:00:00","data_registro":"2026-05-13","procedimento":"MESOTERAPIA","valor_procedimento":350.0,"valor_adicional":0,"sessoes_contratadas":0,"consultor":"VANESSA","forma_pagamento":"","origem":"","eh_mesoterapia":true,"entrada":350.0,"saldo":0},{"id":"sh_00000000000_2026_05_15","_from_sheets":true,"_sheets_key":"0|2026-05-15","nome":"STEFANIE MARTINEZ CHEHAB","cpf":"","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-15","data_cirurgia":"","data_cadastro":"2026-05-15T00:00:00","data_registro":"2026-05-15","procedimento":"PRP","valor_procedimento":400.0,"valor_adicional":0,"sessoes_contratadas":0,"consultor":"VANESSA","forma_pagamento":"","origem":"","eh_mesoterapia":true,"entrada":400.0,"saldo":0},{"id":"sh_91880807300_2026_05_21","_from_sheets":true,"_sheets_key":"91880807300|2026-05-21","nome":"SERGIO CARLOS JUSTINO","cpf":"918.808.073-00","unidade":"SCS","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-21","data_cirurgia":"","data_cadastro":"2026-05-21T00:00:00","data_registro":"2026-05-21","procedimento":"MESOTERAPIA/PRP","valor_procedimento":2100.0,"valor_adicional":0,"sessoes_contratadas":0,"consultor":"VANESSA","forma_pagamento":"","origem":"","eh_mesoterapia":true,"entrada":2100.0,"saldo":0},{"id":"sh_08033586877_2026_05_04","_from_sheets":true,"_sheets_key":"08033586877|2026-05-04","nome":"Cezar Gonzaga","cpf":"080.335.868-77","unidade":"MGA","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-04","data_cirurgia":"","data_cadastro":"2026-05-04T00:00:00","data_registro":"2026-05-04","procedimento":"Transplante Capilar","valor_procedimento":14999.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Márcia","forma_pagamento":"Pix","origem":"","eh_mesoterapia":false,"entrada":3000.0,"saldo":11999.0},{"id":"sh_13234800804_2026_05_04","_from_sheets":true,"_sheets_key":"13234800804|2026-05-04","nome":"William Donizete Cunha","cpf":"132.348.008-04","unidade":"MGA","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-04","data_cirurgia":"","data_cadastro":"2026-05-04T00:00:00","data_registro":"2026-05-04","procedimento":"Transplante Capilar","valor_procedimento":13999.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Márcia","forma_pagamento":"Cartão","origem":"","eh_mesoterapia":false,"entrada":12000.0,"saldo":1900.0},{"id":"sh_07758831907_2026_05_12","_from_sheets":true,"_sheets_key":"07758831907|2026-05-12","nome":"Wellington William","cpf":"077.588.319-07","unidade":"MGA","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-12","data_cirurgia":"","data_cadastro":"2026-05-12T00:00:00","data_registro":"2026-05-12","procedimento":"Transplante Capilar","valor_procedimento":13999.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Márcia","forma_pagamento":"pix","origem":"","eh_mesoterapia":false,"entrada":3000.0,"saldo":3000.0},{"id":"sh_60539349330_2026_05_26","_from_sheets":true,"_sheets_key":"60539349330|2026-05-26","nome":"Manoel Jorge da Silva Filho","cpf":"605.393.493-30","unidade":"MGA","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-26","data_cirurgia":"","data_cadastro":"2026-05-26T00:00:00","data_registro":"2026-05-26","procedimento":"Transplante Capilar","valor_procedimento":13000.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Marcia","forma_pagamento":"pix e cartão","origem":"","eh_mesoterapia":false,"entrada":3349.0,"saldo":3349.0},{"id":"sh_93027800906_2026_05_01","_from_sheets":true,"_sheets_key":"93027800906|2026-05-01","nome":"Reginaldo Tochio","cpf":"930.278.009-06","unidade":"MGA","etapa":"venda feita","status_lead":"Vendido","data_consulta":"2026-05-01","data_cirurgia":"","data_cadastro":"2026-05-01T00:00:00","data_registro":"2026-05-01","procedimento":"Transplante Capilar","valor_procedimento":13999.0,"valor_adicional":0,"sessoes_contratadas":18,"consultor":"Marcia","forma_pagamento":"pix","origem":"","eh_mesoterapia":false,"entrada":7000.0,"saldo":7000.0}]; let SF_LEADS = (function() { try { var raw = localStorage.getItem('sf_leads'); if (raw) { var parsed = JSON.parse(raw); if (Array.isArray(parsed) && parsed.length > 0) return parsed; } } catch(e) {} // Sem dados no localStorage — inicializa com dados reais e salva try { localStorage.setItem('sf_leads', JSON.stringify(_FALLBACK_LEADS)); } catch(e) {} return _FALLBACK_LEADS.slice(); })(); function salvarLeads() { if (typeof INTEGRITY !== 'undefined') INTEGRITY.saveWithChecksum('sf_leads', SF_LEADS); else localStorage.setItem('sf_leads', JSON.stringify(SF_LEADS)); if (typeof _registrarAtualizacao === 'function') _registrarAtualizacao(); } let SF_DAILY = JSON.parse(localStorage.getItem('sf_daily') || '{}'); function salvarDaily() { if (typeof INTEGRITY !== 'undefined') INTEGRITY.saveWithChecksum('sf_daily', SF_DAILY); else localStorage.setItem('sf_daily', JSON.stringify(SF_DAILY)); // ── Supabase: persistir entrada_diaria ── if (_supabase) { Object.values(SF_DAILY).flat().forEach(entry => { DB.saveEntrada(entry).catch(e => console.warn('[SupremaHub] saveEntrada error:', e)); }); } if (typeof _registrarAtualizacao === 'function') _registrarAtualizacao(); } // ---------- Normalização para busca ---------- function normalizarTexto(s) { return (s||'').normalize('NFD').replace(/[\u0300-\u036f]/g,'').toLowerCase().trim(); } function normalizarTelefone(s) { return (s||'').replace(/\D/g,''); } function normalizarCpf(s) { return (s||'').replace(/\D/g,''); } // ---------- Busca de CEP ---------- function buscarCep(val) { const clean = val.replace(/\D/g,''); if (clean.length !== 8) return; fetch('https://viacep.com.br/ws/' + clean + '/json/') .then(r => r.json()) .then(d => { if (!d.erro) { const setv = (id, v) => { const el = document.getElementById(id); if (el) el.value = v || ''; }; setv('lead-rua', d.logradouro); setv('lead-bairro', d.bairro); setv('lead-cidade', d.localidade); setv('lead-estado', d.uf); } }).catch(() => {}); } // ---------- Modal de Lead ---------- // ——— Helpers UI do modal de lead ——— function calcularValorTotal() { const vp = parseFloat(document.getElementById('lead-valor-procedimento').value) || 0; const va = parseFloat(document.getElementById('lead-valor-adicional').value) || 0; const total = vp + va; const wrap = document.getElementById('lead-valor-total-wrap'); const disp = document.getElementById('lead-valor-total-display'); if (wrap) wrap.style.display = (vp > 0 || va > 0) ? '' : 'none'; if (disp) disp.textContent = fmtCurrency(total); } function atualizarSessoesContratadas() { const proc = (document.getElementById('lead-procedimento') || {}).value || ''; const sessoes = SESSOES_POR_PROCEDIMENTO[proc] || 0; const el = document.getElementById('lead-sessoes-contratadas'); if (el) el.value = sessoes > 0 ? sessoes : ''; } function _limparModalLead() { ['lead-nome','lead-telefone','lead-cpf','lead-email','lead-cep','lead-rua','lead-numero', 'lead-bairro','lead-cidade','lead-estado','lead-data-consulta','lead-data-cirurgia', 'lead-obs','lead-consultor','lead-sessoes-realizadas','lead-sessoes-contratadas', 'lead-valor-procedimento','lead-valor-adicional'] .forEach(id => { const el = document.getElementById(id); if (el) el.value = ''; }); ['lead-etapa','lead-compareceu','lead-reagendou','lead-procedimento', 'lead-adicional','lead-status-lead','lead-origem','lead-forma-pagamento','lead-status-pagamento'] .forEach(id => { const el = document.getElementById(id); if (!el) return; if (id === 'lead-etapa') el.value = 'conexão'; else if (id === 'lead-adicional') el.value = 'Sem Bodyhair'; else if (id === 'lead-status-lead') el.value = 'Novo'; else el.value = ''; }); const wrap = document.getElementById('lead-valor-total-wrap'); if (wrap) wrap.style.display = 'none'; } function abrirNovoLead() { document.getElementById('modal-lead-title').textContent = 'Novo Lead'; document.getElementById('lead-idx').value = '-1'; _limparModalLead(); // Unidade: se unidade → oculta e preenche automaticamente const uw = document.getElementById('lead-unidade-wrap'); if (uw) uw.style.display = (currentUser && currentUser.role === 'unidade') ? 'none' : ''; if (currentUser && currentUser.role === 'unidade') { const lu = document.getElementById('lead-unidade'); if (lu) lu.value = currentUser.unidade; } // Preenche consultor com usuário logado se não for admin/gerente if (currentUser && currentUser.role === 'unidade') { const c = document.getElementById('lead-consultor'); if (c && !c.value) c.value = currentUser.nome; } document.getElementById('modal-lead-err').style.display = 'none'; atualizarCamposEtapa(); document.getElementById('modal-lead').style.display = 'flex'; setTimeout(() => document.getElementById('lead-nome').focus(), 100); } function abrirEditarLead(idx) { SF_LEADS = INTEGRITY.loadWithVerification('sf_leads', []); const l = SF_LEADS[idx]; if (!l) return; document.getElementById('modal-lead-title').textContent = 'Editar Lead'; document.getElementById('lead-idx').value = idx; const setv = (id, v) => { const el = document.getElementById(id); if (el) el.value = (v !== undefined && v !== null) ? v : ''; }; setv('lead-nome', l.nome); setv('lead-telefone', l.telefone); setv('lead-cpf', l.cpf); setv('lead-email', l.email); setv('lead-cep', l.cep); setv('lead-rua', l.rua); setv('lead-numero', l.numero); setv('lead-bairro', l.bairro); setv('lead-cidade', l.cidade); setv('lead-estado', l.estado); setv('lead-data-consulta', l.data_consulta); setv('lead-data-cirurgia', l.data_cirurgia); setv('lead-obs', l.obs); setv('lead-consultor', l.consultor); setv('lead-valor-procedimento', l.valor_procedimento || ''); setv('lead-valor-adicional', l.valor_adicional || ''); setv('lead-sessoes-realizadas', l.sessoes_realizadas || ''); setv('lead-sessoes-contratadas', l.sessoes_contratadas || ''); document.getElementById('lead-etapa').value = l.etapa || 'conexão'; document.getElementById('lead-compareceu').value = l.compareceu || ''; document.getElementById('lead-reagendou').value = l.reagendou || ''; document.getElementById('lead-procedimento').value = l.procedimento || ''; document.getElementById('lead-adicional').value = l.adicional || 'Sem Bodyhair'; document.getElementById('lead-status-lead').value = l.status_lead || 'Novo'; document.getElementById('lead-origem').value = l.origem || ''; document.getElementById('lead-forma-pagamento').value = l.forma_pagamento || ''; document.getElementById('lead-status-pagamento').value = l.status_pagamento || ''; const uw = document.getElementById('lead-unidade-wrap'); if (uw) uw.style.display = (currentUser && currentUser.role === 'unidade') ? 'none' : ''; const lu = document.getElementById('lead-unidade'); if (lu) lu.value = l.unidade || (currentUser && currentUser.unidade) || 'SCS'; document.getElementById('modal-lead-err').style.display = 'none'; calcularValorTotal(); atualizarCamposEtapa(); document.getElementById('modal-lead').style.display = 'flex'; } function atualizarCamposEtapa() { const etapa = (document.getElementById('lead-etapa') || {}).value; const isVenda = etapa === 'venda feita'; const notice = document.getElementById('venda-required-notice'); if (notice) notice.style.display = isVenda ? 'block' : 'none'; const reqIds = ['lead-cpf','lead-email','lead-cep','lead-rua','lead-bairro','lead-cidade','lead-data-consulta']; reqIds.forEach(id => { const el = document.getElementById(id); if (el) el.style.borderColor = isVenda ? 'rgba(201,168,76,.55)' : ''; }); ['lbl-consulta-req','lbl-cep-req','lbl-rua-req','lbl-bairro-req','lbl-cidade-req'].forEach(id => { const el = document.getElementById(id); if (el) el.innerHTML = isVenda ? '*' : ''; }); } function salvarLeadForm() { SF_LEADS = INTEGRITY.loadWithVerification('sf_leads', []); const idx = parseInt(document.getElementById('lead-idx').value); const nome = (document.getElementById('lead-nome').value || '').trim(); const telefone = (document.getElementById('lead-telefone').value || '').trim(); const etapa = document.getElementById('lead-etapa').value; const err = document.getElementById('modal-lead-err'); const showErr = (msg) => { err.style.display='block'; err.textContent=msg; err.scrollIntoView({behavior:'smooth',block:'nearest'}); }; // Validações obrigatórias if (!nome) { showErr('Nome é obrigatório.'); return; } if (!telefone) { showErr('Telefone é obrigatório.'); return; } const origem = document.getElementById('lead-origem').value; if (!origem) { showErr('Origem do lead é obrigatória.'); return; } // Validações adicionais para "Venda Feita" if (etapa === 'venda feita') { const obrig = [ ['lead-cpf','CPF'],['lead-email','E-mail'],['lead-cep','CEP'], ['lead-rua','Rua'],['lead-bairro','Bairro'],['lead-cidade','Cidade'], ['lead-data-consulta','Data da Consulta'] ]; for (const [id, label] of obrig) { const el = document.getElementById(id); if (!el || !el.value.trim()) { showErr('Para "Venda Feita" o campo "' + label + '" é obrigatório.'); return; } } if (!document.getElementById('lead-compareceu').value) { showErr('Informe se o lead compareceu à consulta.'); return; } const vp = parseFloat(document.getElementById('lead-valor-procedimento').value) || 0; if (vp <= 0) { showErr('Para "Venda Feita" informe o Valor do Procedimento.'); return; } if (!document.getElementById('lead-procedimento').value) { showErr('Para "Venda Feita" selecione o Procedimento.'); return; } } const getv = (id) => { const el = document.getElementById(id); return el ? el.value.trim() : ''; }; const getf = (id) => { const v = getv(id); return v ? (parseFloat(v) || 0) : 0; }; const unidade = (currentUser && currentUser.role === 'unidade') ? currentUser.unidade : getv('lead-unidade'); const procedimento = getv('lead-procedimento'); const sessoesContratadas = SESSOES_POR_PROCEDIMENTO[procedimento] || 0; const valorProcedimento = getf('lead-valor-procedimento'); const valorAdicional = getf('lead-valor-adicional'); const lead = { nome, telefone, cpf: getv('lead-cpf'), email: getv('lead-email'), cep: getv('lead-cep'), rua: getv('lead-rua'), numero: getv('lead-numero'), bairro: getv('lead-bairro'), cidade: getv('lead-cidade'), estado: getv('lead-estado'), data_consulta: getv('lead-data-consulta'), data_cirurgia: getv('lead-data-cirurgia'), // Campos financeiros procedimento, adicional: getv('lead-adicional') || 'Sem Bodyhair', valor_procedimento: valorProcedimento, valor_adicional: valorAdicional, valor_venda: valorProcedimento + valorAdicional, // campo legado para compatibilidade sessoes_contratadas: sessoesContratadas, sessoes_realizadas: parseInt(getv('lead-sessoes-realizadas')) || 0, // Campos comerciais status_lead: getv('lead-status-lead') || 'Novo', consultor: getv('lead-consultor'), origem: origem, forma_pagamento: getv('lead-forma-pagamento'), status_pagamento: getv('lead-status-pagamento'), // Campos operacionais compareceu: getv('lead-compareceu'), reagendou: getv('lead-reagendou'), etapa, unidade, obs: getv('lead-obs') }; // Integridade: sessões realizadas não pode exceder contratadas if (lead.sessoes_contratadas > 0 && lead.sessoes_realizadas > lead.sessoes_contratadas) { showErr('Sessões realizadas (' + lead.sessoes_realizadas + ') não podem exceder as contratadas (' + lead.sessoes_contratadas + ').'); return; } if (idx === -1) { lead.id = 'l' + Date.now(); lead.data_cadastro = new Date().toISOString(); lead.cadastrado_por = currentUser ? currentUser.usuario : ''; SF_LEADS.push(lead); } else { const existing = SF_LEADS[idx] || {}; SF_LEADS[idx] = Object.assign({}, existing, lead); } salvarLeads(); // ── Supabase: persistir lead ── if (_supabase) { DB.saveLead(lead).catch(e => console.warn('[SupremaHub] saveLead error:', e)); } fecharModal('modal-lead'); _leadSearch = ''; renderPaginaLeads(); sincronizarLeadsComDashboard(); } function excluirLead(idx) { SF_LEADS = INTEGRITY.loadWithVerification('sf_leads', []); const l = SF_LEADS[idx]; if (!l) return; if (!confirm('Excluir lead "' + l.nome + '"? Esta ação não pode ser desfeita.')) return; const _delLead = SF_LEADS[idx]; SF_LEADS.splice(idx, 1); if (_supabase && _delLead && (_delLead.supabase_id || _delLead.id)) DB.deleteLead(_delLead.supabase_id || _delLead.id).catch(console.error); salvarLeads(); renderPaginaLeads(); sincronizarLeadsComDashboard(); } function etapaParaStatus(etapa) { const map = { 'conexão':'Lead Novo','qualificação':'Lead Novo','agendamento':'Agendado', 'consulta realizada':'Consultado','formalização':'Consultado','venda feita':'Vendido' }; return map[etapa] || 'Lead Novo'; } function sincronizarLeadsComDashboard() { // Carrega dados com fallback robusto: INTEGRITY → raw localStorage → _FALLBACK_LEADS try { var _fromInteg = INTEGRITY.loadWithVerification('sf_leads', null); if (_fromInteg && _fromInteg.length > 0) { SF_LEADS = _fromInteg; } else { var _raw = localStorage.getItem('sf_leads'); SF_LEADS = (_raw ? JSON.parse(_raw) : null) || _FALLBACK_LEADS.slice(); INTEGRITY.saveWithChecksum('sf_leads', SF_LEADS); // corrige checksum } } catch(e) { if (\!SF_LEADS || SF_LEADS.length === 0) SF_LEADS = _FALLBACK_LEADS.slice(); } const mapped = SF_LEADS.map(l => ({ id: l.id, nome: l.nome, unidade: l.unidade || '', data_registro: l.data_cadastro ? l.data_cadastro.split('T')[0] : new Date().toISOString().split('T')[0], data_venda: (l.etapa === 'venda feita' && l.data_consulta) ? l.data_consulta : null, data_cirurgia: l.data_cirurgia || null, status: etapaParaStatus(l.etapa), status_lead: l.status_lead || 'Novo', // Financeiro procedimento: l.procedimento || '', adicional: l.adicional || 'Sem Bodyhair', valor_procedimento: parseFloat(l.valor_procedimento) || 0, valor_adicional: parseFloat(l.valor_adicional) || 0, valor_venda: (parseFloat(l.valor_procedimento) || 0) + (parseFloat(l.valor_adicional) || 0), sessoes_contratadas: l.sessoes_contratadas || 0, sessoes_realizadas: l.sessoes_realizadas || 0, // Comercial consultor: l.consultor || l.cadastrado_por || '', vendedor: l.consultor || l.cadastrado_por || '', origem: l.origem || '', forma_pagamento: l.forma_pagamento || '', status_pagamento: l.status_pagamento || '', tipo_consulta: 'Presencial', _from_crm: true })); DATA.pipeline = mapped; // Substitui inteiramente — impede que dados demo se misturem renderAll(); } // ---------- Busca de Leads ---------- let _leadSearch = ''; let _leadFiltroUnidade = ''; let _leadFiltroStatus = ''; let _leadFiltroOrigem = ''; let _leadFiltroProc = ''; function pesquisarLeads() { _leadSearch = (document.getElementById('crm-search') || {}).value || ''; renderPaginaLeads(); } function filtrarLeadUnidade(v) { _leadFiltroUnidade = v; renderPaginaLeads(); } function filtrarLeadStatus(v) { _leadFiltroStatus = v; renderPaginaLeads(); } function filtrarLeadOrigem(v) { _leadFiltroOrigem = v; renderPaginaLeads(); } function filtrarLeadProc(v) { _leadFiltroProc = v; renderPaginaLeads(); } function _buscarLeadGlobal(q) { // Busca rápida pelo nome, telefone ou CPF — navega para CRM se não estiver lá _leadSearch = q; _leadFiltroUnidade = ''; _leadFiltroStatus = ''; _leadFiltroOrigem = ''; _leadFiltroProc = ''; showPage('leads'); } function renderPaginaLeads() { const el = document.getElementById('page-leads'); if (!el) return; SF_LEADS = INTEGRITY.loadWithVerification('sf_leads', []); let leads = SF_LEADS; const isUnidade = currentUser && currentUser.role === 'unidade' && currentUser.unidade; if (isUnidade) leads = leads.filter(l => l.unidade === currentUser.unidade); // Filtros dropdown if (_leadFiltroUnidade) leads = leads.filter(l => l.unidade === _leadFiltroUnidade); if (_leadFiltroStatus) leads = leads.filter(l => (l.status_lead || 'Novo') === _leadFiltroStatus); if (_leadFiltroOrigem) leads = leads.filter(l => l.origem === _leadFiltroOrigem); if (_leadFiltroProc) leads = leads.filter(l => l.procedimento === _leadFiltroProc); // Busca textual (nome, telefone, CPF, consultor) if (_leadSearch.trim()) { const q = normalizarTexto(_leadSearch); const qTel = normalizarTelefone(_leadSearch); const qCpf = normalizarCpf(_leadSearch); leads = leads.filter(l => { if (normalizarTexto(l.nome).includes(q)) return true; if (normalizarTexto(l.consultor || '').includes(q)) return true; if (qTel.length >= 4 && normalizarTelefone(l.telefone).includes(qTel)) return true; if (qCpf.length >= 4 && normalizarCpf(l.cpf || '').includes(qCpf)) return true; return false; }); } // ——— KPIs financeiros da base filtrada ——— const baseFin = isUnidade ? SF_LEADS.filter(l => l.unidade === currentUser.unidade) : SF_LEADS; const convertidos = baseFin.filter(l => (l.status_lead === 'Convertido') || l.etapa === 'venda feita'); const fatTotal = convertidos.reduce((s, l) => s + ((parseFloat(l.valor_procedimento)||0) + (parseFloat(l.valor_adicional)||0)), 0); const fatMesAtual = (() => { const mesStr = new Date().toISOString().substring(0,7); return convertidos.filter(l => (l.data_consulta || l.data_cadastro || '').substring(0,7) === mesStr) .reduce((s, l) => s + ((parseFloat(l.valor_procedimento)||0) + (parseFloat(l.valor_adicional)||0)), 0); })(); const taxaConv = baseFin.length ? (convertidos.length / baseFin.length * 100) : 0; const mesoPendentes = baseFin.filter(l => { const cont = l.sessoes_contratadas || 0; const real = l.sessoes_realizadas || 0; return cont > 0 && real < cont; }).length; // KPIs por unidade const kpiUnidHtml = UNITS.map(u => { const uLeads = baseFin.filter(l => l.unidade === u); const uConv = uLeads.filter(l => (l.status_lead === 'Convertido') || l.etapa === 'venda feita'); const uFat = uConv.reduce((s, l) => s + ((parseFloat(l.valor_procedimento)||0) + (parseFloat(l.valor_adicional)||0)), 0); return '
'; }).join(''); // Funil por status_lead const statusCount = {}; STATUS_LEAD.forEach(s => { statusCount[s] = baseFin.filter(l => (l.status_lead || 'Novo') === s).length; }); const pillsHtml = STATUS_LEAD.map(s => '
'
).join('');
// Etapas funil clássico (compacto)
const etapaCount = {};
ETAPAS_FUNIL.forEach(e => { etapaCount[e] = baseFin.filter(l => l.etapa === e).length; });
// Tabela de leads
const rows = leads.length ? leads.map(l => {
const realIdx = SF_LEADS.indexOf(l);
const dt = l.data_cadastro ? new Date(l.data_cadastro).toLocaleDateString('pt-BR') : '—';
const valTotal = (parseFloat(l.valor_procedimento)||0) + (parseFloat(l.valor_adicional)||0);
const sessoesInfo = (l.sessoes_contratadas > 0)
? '
' + (l.sessoes_realizadas||0) + '/' + l.sessoes_contratadas + ' sessões'
: '';
return '
'; }).join('') : '
'; // Filtros rápidos (selects) const filtroUnidOpts = '' + UNITS.map(u => '').join(''); const filtroStatusOpts = '' + STATUS_LEAD.map(s => '').join(''); const filtroOrigemOpts = '' + ORIGENS_LEAD.map(o => '').join(''); const filtroProcOpts = '' + PROCEDIMENTOS.map(p => '').join(''); el.innerHTML = '
' + // KPIs financeiros '
' + // KPIs por unidade (!isUnidade ? '
' : '') + // Funil status '
' + (_leadFiltroStatus ? '
' : '') + // Barra de busca + filtros '
' + // Tabela '
| Nome / Telefone / CPF | Status / Etapa | Procedimento | Valor Total | Origem / Consultor | Unidade / Data | Ações |
|---|
' + // ——— Análise Financeira Detalhada ——— _renderAnaliseFinanceiraCRM(baseFin); } function _renderAnaliseFinanceiraCRM(leads) { // Faturamento por procedimento const procMap = {}; leads.forEach(l => { if (!l.procedimento) return; if (!procMap[l.procedimento]) procMap[l.procedimento] = { count: 0, fat: 0 }; procMap[l.procedimento].count++; procMap[l.procedimento].fat += (parseFloat(l.valor_procedimento)||0) + (parseFloat(l.valor_adicional)||0); }); const procRows = Object.entries(procMap).sort((a,b) => b[1].fat - a[1].fat).map(([p, d]) => '
' ).join('') || '
'; // Faturamento por origem const origMap = {}; leads.forEach(l => { const o = l.origem || 'Não informado'; if (!origMap[o]) origMap[o] = { count: 0, fat: 0 }; origMap[o].count++; origMap[o].fat += (parseFloat(l.valor_procedimento)||0) + (parseFloat(l.valor_adicional)||0); }); const origRows = Object.entries(origMap).sort((a,b) => b[1].fat - a[1].fat).map(([o, d]) => '
' ).join(''); // Faturamento por consultor const consMap = {}; leads.forEach(l => { const c = l.consultor || l.cadastrado_por || 'Não informado'; if (!consMap[c]) consMap[c] = { count: 0, fat: 0, conv: 0 }; consMap[c].count++; consMap[c].fat += (parseFloat(l.valor_procedimento)||0) + (parseFloat(l.valor_adicional)||0); if ((l.status_lead === 'Convertido') || l.etapa === 'venda feita') consMap[c].conv++; }); const consRows = Object.entries(consMap).sort((a,b) => b[1].fat - a[1].fat).map(([c, d]) => { const taxa = d.count ? (d.conv / d.count * 100).toFixed(1) : '0.0'; return '
'; }).join('') || '
'; // Pacotes de meso em aberto const mesoPend = leads.filter(l => (l.sessoes_contratadas||0) > 0 && (l.sessoes_realizadas||0) < (l.sessoes_contratadas||0)); const mesoRows = mesoPend.length ? mesoPend.map(l => { const pct = Math.round((l.sessoes_realizadas || 0) / l.sessoes_contratadas * 100); return '
'; }).join('') : '
'; const cardStyle = 'background:var(--card);border:1px solid var(--border);border-radius:12px;padding:18px;margin-bottom:12px'; const thStyle = 'text-align:left;padding:8px 12px;color:var(--muted);font-size:.67rem;text-transform:uppercase;letter-spacing:.4px;border-bottom:1px solid var(--border)'; const tdStyle = 'padding:9px 12px;border-bottom:1px solid rgba(37,37,69,.3);font-size:.8rem'; return '
| Procedimento | Qtd | Faturamento |
|---|
| Origem | Leads | Faturamento |
|---|
| Consultor | Leads | Conversões | Faturamento |
|---|
| Paciente | Procedimento | Sessões | Progresso | Unidade |
|---|
'; } // ---------- Entrada Diária ---------- function renderPaginaEntradaDiaria() { const el = document.getElementById('page-entrada-diaria'); if (!el) return; SF_DAILY = INTEGRITY.loadWithVerification('sf_daily', {}); const isUnidade = currentUser && currentUser.role === 'unidade'; const unidade = isUnidade ? currentUser.unidade : null; const hoje = new Date().toISOString().split('T')[0]; const chave = (unidade || 'GERAL') + '_' + hoje; const saved = SF_DAILY[chave] || {}; const v = field => saved[field] !== undefined ? saved[field] : ''; const unitSelectHtml = isUnidade ? '' : '
'; el.innerHTML = '
'; } function recarregarEntradaUnidade() { SF_DAILY = INTEGRITY.loadWithVerification('sf_daily', {}); const unid = (document.getElementById('ed-unidade') || {}).value || ''; const data = (document.getElementById('ed-data') || {}).value || ''; const chave = (unid || 'GERAL') + '_' + data; const saved = SF_DAILY[chave] || {}; const setv = (id, val) => { const el = document.getElementById(id); if (el) el.value = val !== undefined ? val : ''; }; setv('ed-recebidos', saved.recebidos); setv('ed-agendados', saved.agendados); setv('ed-compareceram', saved.compareceram); setv('ed-faltaram', saved.faltaram); setv('ed-reagendaram', saved.reagendaram); } function renderHistoricoEntradas(filtroUnidade) { SF_DAILY = INTEGRITY.loadWithVerification('sf_daily', {}); const entries = Object.entries(SF_DAILY) .filter(([k]) => !filtroUnidade || k.startsWith(filtroUnidade + '_')) .map(([k, v]) => v) .sort((a, b) => (b.data || '').localeCompare(a.data || '')) .slice(0, 14); if (!entries.length) return '
Nenhum registro ainda.
'; const rows = entries.map(e => '
' ).join(''); return '
| Data | Unidade | Recebidos | Agendados | Compareceram | Faltaram | Reagendaram |
|---|
';
}
function salvarEntradaDiaria() {
const unidade = (document.getElementById('ed-unidade') || {}).value || '';
const data = (document.getElementById('ed-data') || {}).value || new Date().toISOString().split('T')[0];
const chave = (unidade || 'GERAL') + '_' + data;
const msg = document.getElementById('ed-msg');
SF_DAILY[chave] = {
unidade, data,
recebidos: parseInt((document.getElementById('ed-recebidos') || {}).value) || 0,
agendados: parseInt((document.getElementById('ed-agendados') || {}).value) || 0,
compareceram: parseInt((document.getElementById('ed-compareceram') || {}).value) || 0,
faltaram: parseInt((document.getElementById('ed-faltaram') || {}).value) || 0,
reagendaram: parseInt((document.getElementById('ed-reagendaram') || {}).value) || 0,
salvo_em: new Date().toISOString(),
salvo_por: currentUser ? currentUser.usuario : ''
};
salvarDaily();
const hist = document.getElementById('ed-historico');
if (hist) hist.innerHTML = renderHistoricoEntradas(currentUser && currentUser.role === 'unidade' ? currentUser.unidade : null);
if (msg) {
msg.style.display = 'block';
msg.style.background = 'rgba(0,230,118,.08)';
msg.style.border = '1px solid rgba(0,230,118,.25)';
msg.style.color = 'var(--green)';
msg.innerHTML = 'Dados salvos com sucesso! Dashboard atualizado em tempo real.';
setTimeout(() => { if (msg) msg.style.display = 'none'; }, 4000);
}
sincronizarLeadsComDashboard();
}
// ================================================================
// MÓDULO DE SEGURANÇA, INTEGRIDADE E BACKUP — SupremaHub v3.0
// ================================================================
const SYSTEM_VERSION = '3.0.0';
const SYSTEM_BUILD = '2026-05-28';
// ── Integridade de dados ─────────────────────────────────────────
const INTEGRITY = {
checksum(str) {
let a = 1, b = 0;
for (let i = 0; i < str.length; i++) {
a = (a + str.charCodeAt(i)) % 65521;
b = (b + a) % 65521;
}
return ((b << 16) | a) >>> 0;
},
saveWithChecksum(key, data) {
try {
const json = JSON.stringify(data);
localStorage.setItem(key, json);
localStorage.setItem(key + '_cs', String(this.checksum(json)));
} catch(e) { console.error('[INTEGRITY] save error', key, e); }
},
loadWithVerification(key, fallback) {
if (fallback === undefined) fallback = null;
const json = localStorage.getItem(key);
if (!json) return fallback;
const stored_cs = localStorage.getItem(key + '_cs');
if (stored_cs) {
const actual_cs = this.checksum(json);
if (String(actual_cs) !== stored_cs) {
console.warn('[INTEGRITY] Checksum mismatch for', key, '— tentando recuperação de backup');
if (typeof AUDIT !== 'undefined') AUDIT.log('INTEGRITY', 'CHECKSUM_FAIL', { key });
const bk = typeof BACKUP !== 'undefined' ? BACKUP.getMostRecent() : null;
if (bk && bk.data) {
const recovered = key === 'sf_leads' ? bk.data.leads :
key === 'sf_daily' ? bk.data.daily :
key === 'sf_users' ? bk.data.users : null;
if (recovered !== null) return recovered;
}
return fallback;
}
}
try { return JSON.parse(json); } catch { return fallback; }
},
validateLead(l) {
return !!(l && typeof l === 'object' && l.nome && typeof l.nome === 'string' && l.nome.trim() && l.etapa);
},
validateAll() {
return SF_LEADS.map((l, i) => (!this.validateLead(l) ? { index: i, id: l.id } : null)).filter(Boolean);
}
};
// ── Log de auditoria ─────────────────────────────────────────────
const AUDIT = {
_key: 'sf_audit_log',
MAX: 500,
log(module, event, data) {
try {
const entries = this.get();
entries.push({ ts: new Date().toISOString(), user: typeof currentUser !== 'undefined' && currentUser ? currentUser.usuario : 'system', module, event, data: data || {} });
if (entries.length > this.MAX) entries.splice(0, entries.length - this.MAX);
localStorage.setItem(this._key, JSON.stringify(entries));
} catch(e) {}
},
get() { try { return JSON.parse(localStorage.getItem(this._key) || '[]'); } catch { return []; } },
clear() { localStorage.removeItem(this._key); }
};
// ── Segurança / Sessão ───────────────────────────────────────────
const SEC = {
MAX_ATTEMPTS: 5,
LOCKOUT_MS: 15 * 60 * 1000,
SESSION_MS: 60 * 60 * 1000,
_timer: null,
_key: 'sf_login_sec',
_state() { try { return JSON.parse(localStorage.getItem(this._key) || '{}'); } catch { return {}; } },
_save(s) { localStorage.setItem(this._key, JSON.stringify(s)); },
isLocked() {
const s = this._state();
if (!s.lockedUntil || Date.now() >= s.lockedUntil) { if (s.lockedUntil) this._save({ count: 0, lockedUntil: 0 }); return false; }
return true;
},
getLockRemaining() { const s = this._state(); return Math.max(0, Math.ceil(((s.lockedUntil||0) - Date.now()) / 60000)); },
recordFailure() {
const s = this._state();
const count = (s.count || 0) + 1;
this._save({ count, lockedUntil: count >= this.MAX_ATTEMPTS ? Date.now() + this.LOCKOUT_MS : (s.lockedUntil || 0) });
return count;
},
resetFailures() { this._save({ count: 0, lockedUntil: 0 }); },
startSessionTimer() {
clearTimeout(this._timer);
this._timer = setTimeout(() => {
if (typeof currentUser !== 'undefined' && currentUser) {
AUDIT.log('SEC', 'SESSION_TIMEOUT', { user: currentUser.usuario });
alert('Sessão expirada por inatividade (60 min). Faça login novamente.');
fazerLogout();
}
}, this.SESSION_MS);
},
resetSession() { if (typeof currentUser !== 'undefined' && currentUser) this.startSessionTimer(); },
sanitize(str) {
if (typeof str !== 'string') return str;
return str.replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"').replace(/'/g,''');
},
stripTags(str) { return typeof str === 'string' ? str.replace(/<[^>]*>/g,'').trim() : str; }
};
// ── Sistema de Backup ────────────────────────────────────────────
const BACKUP = {
PFX: 'sf_backup_',
KEY_LAST: 'sf_backup_last',
KEY_SHEETS: 'sf_backup_sheets_url',
MAX_LOCAL: 10,
INTERVAL_MS: 60 * 60 * 1000,
_timer: null,
start() {
clearInterval(this._timer);
this._timer = setInterval(() => this.perform('auto'), this.INTERVAL_MS);
const last = this.getLastInfo();
const age = last ? Date.now() - new Date(last.timestamp).getTime() : Infinity;
if (age > 2 * 60 * 60 * 1000) setTimeout(() => this.perform('init'), 6000);
},
async perform(trigger) {
trigger = trigger || 'manual';
const ts = new Date().toISOString();
const data = { leads: JSON.parse(JSON.stringify(SF_LEADS)), daily: JSON.parse(JSON.stringify(SF_DAILY)), users: JSON.parse(JSON.stringify(USUARIOS)) };
const cs = INTEGRITY.checksum(JSON.stringify(data.leads));
const obj = { timestamp: ts, trigger, version: SYSTEM_VERSION, counts: { leads: SF_LEADS.length, daily: Object.keys(SF_DAILY).length, users: USUARIOS.length }, checksum: cs, data };
const key = this.PFX + Date.now();
try { localStorage.setItem(key, JSON.stringify(obj)); } catch(e) { this._prune(true); try { localStorage.setItem(key, JSON.stringify(obj)); } catch {} }
localStorage.setItem(this.KEY_LAST, JSON.stringify({ timestamp: ts, key, trigger, counts: obj.counts, checksum: cs }));
this._prune();
AUDIT.log('BACKUP', 'PERFORMED', { trigger, counts: obj.counts });
this._updateFooter(ts);
const url = localStorage.getItem(this.KEY_SHEETS);
if (url && url.startsWith('https://script.google.com/')) {
try {
await fetch(url, { method: 'POST', mode: 'no-cors', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ timestamp: ts, version: SYSTEM_VERSION, trigger, leads_count: SF_LEADS.length, checksum: cs, leads: JSON.stringify(data.leads) }) });
AUDIT.log('BACKUP', 'SHEETS_SENT', { ts });
} catch(e) { AUDIT.log('BACKUP', 'SHEETS_ERROR', { error: e.message }); }
}
return obj;
},
_prune(aggressive) {
const keys = this._keys().sort();
const max = aggressive ? Math.floor(this.MAX_LOCAL / 2) : this.MAX_LOCAL;
while (keys.length > max) localStorage.removeItem(keys.shift());
},
_keys() { const k=[]; for(let i=0;i Cole a URL do Google Apps Script Web App para envio automático a cada hora. Cole a URL do Google Apps Script de leitura (
`).join('') : '${new Date(b.timestamp).toLocaleString('pt-BR')}
${b.trigger}
${b.counts ? b.counts.leads + ' leads' : '—'}
v${b.version}
';
const auditHTML = auditLog.length ? auditLog.map(e => `
Nenhum backup local.
`).join('') : '${new Date(e.ts).toLocaleString('pt-BR')}
${e.user}
${e.module}
${e.event}
';
const intHtml = issues.length
? ` ${issues.length} problema(s) detectado(s)`
: ` Todos os ${SF_LEADS.length} leads e ${Object.keys(SF_DAILY).length} entradas diárias passaram na verificação`;
const html = `Log vazio. Segurança, Integridade & Backup
${intHtml}
supremahub_sheets_sync.gs). O sistema importará vendas automaticamente a cada 60 segundos, sem duplicação. Leads, metas e entradas diárias permanecem manuais.Backups Locais (${list.length}/${BACKUP.MAX_LOCAL} máx)
${listHTML}
Data/Hora Tipo Dados Versão Ação
Log de Auditoria (últimas 50 de ${AUDIT.get().length})
${auditHTML}
Data/Hora
Usuário Módulo Evento
Como configurar Google Sheets (passo a passo)
2. Clique em Extensões → Apps Script.
3. Cole o código abaixo → Implantar → Novo Implantação → App da Web.
4. Em "Quem tem acesso" selecione "Qualquer pessoa" → copie a URL.
5. Cole a URL no campo acima e clique em Salvar.
function doPost(e) {
try {
var d = JSON.parse(e.postData.contents);
var ss = SpreadsheetApp.getActiveSpreadsheet();
var log = ss.getSheetByName('BackupLog') || ss.insertSheet('BackupLog');
if (log.getLastRow() === 0) log.appendRow(['Timestamp','Trigger','Leads','Versao','Checksum']);
log.appendRow([d.timestamp, d.trigger, d.leads_count, d.version, d.checksum]);
var ls = ss.getSheetByName('Leads') || ss.insertSheet('Leads');
var leads = JSON.parse(d.leads || '[]');
ls.clearContents();
if (leads.length > 0) {
ls.appendRow(Object.keys(leads[0]));
leads.forEach(function(l) { ls.appendRow(Object.values(l)); });
}
return ContentService.createTextOutput(JSON.stringify({ok:true})).setMimeType(ContentService.MimeType.JSON);
} catch(err) {
return ContentService.createTextOutput(JSON.stringify({ok:false,error:err.message})).setMimeType(ContentService.MimeType.JSON);
}
}