const pool = require('./db.js'); const crypto = require('crypto'); const PRODUCTS = [ "Pneu Aro 13 175/70R13", "Pneu Aro 14 175/70R14", "Pneu Aro 15 195/60R15", "Pneu Aro 16 205/55R16", "Pneu Aro 17 225/45R17", "Alinhamento e Balanceamento", "Revisão do Sistema de Arrefecimento", "Manutenção de Freios", "Troca de Óleo e Filtros", "Limpeza de Bico" ]; const DEFAULT_ORIGINS = ['WhatsApp', 'Instagram', 'Website', 'LinkedIn', 'Indicação']; const DEFAULT_FUNNELS = ['Sem atendimento', 'Identificação', 'Negociação', 'Ganhos', 'Perdidos']; const FIRST_NAMES = ["Ana", "Bruno", "Carlos", "Daniela", "Eduardo", "Fernanda", "Gabriel", "Helena", "Igor", "Julia", "Lucas", "Mariana", "Nicolas", "Olivia", "Pedro", "Quintino", "Rafael", "Sofia", "Thiago", "Ursula", "Victor", "Wagner", "Xuxa", "Yuri", "Zeca", "Amanda", "Beto", "Camila", "Diogo", "Elisa", "Fabio", "Gisele", "Henrique", "Isabela", "Joao", "Karla"]; const LAST_NAMES = ["Silva", "Santos", "Oliveira", "Souza", "Rodrigues", "Ferreira", "Alves", "Pereira", "Lima", "Gomes", "Costa", "Ribeiro", "Martins", "Carvalho", "Almeida", "Lopes", "Soares", "Fernandes", "Vieira", "Barbosa"]; function getRandomItem(arr) { return arr[Math.floor(Math.random() * arr.length)]; } function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } function generateUniqueNames(count) { const names = new Set(); while (names.size < count) { names.add(`${getRandomItem(FIRST_NAMES)} ${getRandomItem(LAST_NAMES)}`); } return Array.from(names); } async function run() { try { console.log('🔄 Iniciando geração de dados...'); // 1. Encontrar o tenant "teste" const [tenants] = await pool.query(`SELECT id FROM tenants WHERE slug = 'teste' OR name LIKE '%teste%' LIMIT 1`); if (tenants.length === 0) { console.log('❌ Tenant "teste" não encontrado.'); process.exit(1); } const tenantId = tenants[0].id; console.log(`✅ Tenant "teste" encontrado: ${tenantId}`); // Pegar origens e funis dinâmicos se existirem let origins = [...DEFAULT_ORIGINS]; let funnels = [...DEFAULT_FUNNELS]; let originGroupId = null; let funnelId = null; try { const [originGroups] = await pool.query(`SELECT id FROM origin_groups WHERE tenant_id = ? LIMIT 1`, [tenantId]); if (originGroups.length > 0) { originGroupId = originGroups[0].id; const [originItems] = await pool.query(`SELECT name FROM origin_items WHERE origin_group_id = ?`, [originGroupId]); if (originItems.length > 0) origins = originItems.map(o => o.name); } const [funnelGroups] = await pool.query(`SELECT id FROM funnels WHERE tenant_id = ? LIMIT 1`, [tenantId]); if (funnelGroups.length > 0) { funnelId = funnelGroups[0].id; const [funnelStages] = await pool.query(`SELECT name FROM funnel_stages WHERE funnel_id = ?`, [funnelId]); if (funnelStages.length > 0) funnels = funnelStages.map(f => f.name); } } catch (e) { console.log('Aviso: Usando origens/funis padrão devido a erro na busca de dinâmicos.'); } // 2. Limpar dados existentes do tenant (exceto admin e tenant em si) console.log('🧹 Limpando attendances antigas...'); await pool.query(`DELETE FROM attendances WHERE tenant_id = ?`, [tenantId]); console.log('🧹 Limpando usuários antigos (exceto admin)...'); await pool.query(`DELETE FROM users WHERE tenant_id = ? AND role != 'admin'`, [tenantId]); console.log('🧹 Limpando times antigos...'); await pool.query(`DELETE FROM teams WHERE tenant_id = ?`, [tenantId]); // 3. Criar 5 times const teams = []; for (let i = 1; i <= 5; i++) { const teamId = crypto.randomUUID(); await pool.query(`INSERT INTO teams (id, tenant_id, name, description, origin_group_id, funnel_id) VALUES (?, ?, ?, ?, ?, ?)`, [teamId, tenantId, `Equipe Vendas ${i}`, `Equipe responsável pela região ${i}`, originGroupId, funnelId]); teams.push(teamId); } console.log('✅ 5 times criados.'); // 4. Criar 36 usuários (1 manager por time = 5 managers, 31 agents) const users = []; const roles = ['manager', 'manager', 'manager', 'manager', 'manager', ...Array(31).fill('agent')]; const uniqueNames = generateUniqueNames(36); // Distribuir usuários entre os times for (let i = 0; i < 36; i++) { const userId = crypto.randomUUID(); const role = roles[i]; const teamId = teams[i % 5]; const name = uniqueNames[i]; const email = `${name.split(' ')[0].toLowerCase()}.${name.split(' ')[1].toLowerCase()}.${i}@teste.com`; await pool.query( `INSERT INTO users (id, tenant_id, team_id, name, email, password_hash, role, status) VALUES (?, ?, ?, ?, ?, ?, ?, 'active')`, [userId, tenantId, teamId, name, email, 'dummy_hash_not_for_login', role] ); users.push(userId); } console.log('✅ 36 usuários criados (5 managers, 31 agents).'); // 5. Gerar attendances (01/01/2026 até 22/04/2026) // 112 dias totais const startDate = new Date('2026-01-01T08:00:00Z'); const endDate = new Date('2026-04-22T18:00:00Z'); let currentDay = new Date(startDate); const attendancesToInsert = []; console.log('⏳ Gerando dados de attendances em memória...'); while (currentDay <= endDate) { // Pular domingos para dar mais realismo, ou deixar todos os dias? Vamos deixar todos os dias. for (const userId of users) { const numAttendances = getRandomInt(3, 5); // 3 a 5 por dia por usuário for (let a = 0; a < numAttendances; a++) { const createdAt = new Date(currentDay); createdAt.setHours(getRandomInt(8, 17), getRandomInt(0, 59), getRandomInt(0, 59)); const isConverted = Math.random() > 0.7; // 30% conversão const reqProduct = getRandomItem(PRODUCTS); const soldProduct = isConverted ? reqProduct : null; let score = getRandomInt(40, 100); if (isConverted) score = getRandomInt(85, 100); attendancesToInsert.push([ crypto.randomUUID(), tenantId, userId, isConverted ? "Venda efetuada com sucesso" : "Cliente não finalizou a compra", isConverted ? "Cliente comprou com sucesso. Excelente atendimento." : "Cliente achou o valor alto e desistiu.", score, getRandomInt(1, 45), // first_response_time_min getRandomInt(10, 120), // handling_time_min isConverted ? 'Ganhos' : (Math.random() > 0.5 ? 'Perdidos' : getRandomItem(funnels)), // funnel_stage getRandomItem(origins), // origin reqProduct, soldProduct, isConverted ? 1 : 0, JSON.stringify(isConverted ? [] : ["Faltou oferecer desconto", "Demora no primeiro contato"]), JSON.stringify(["Melhorar rapport inicial"]), createdAt ]); } } currentDay.setDate(currentDay.getDate() + 1); } // 6. Inserir em lotes console.log(`⏳ Inserindo ${attendancesToInsert.length} attendances no banco em lotes...`); const batchSize = 1000; for (let i = 0; i < attendancesToInsert.length; i += batchSize) { const batch = attendancesToInsert.slice(i, i + batchSize); await pool.query( `INSERT INTO attendances (id, tenant_id, user_id, title, full_summary, score, first_response_time_min, handling_time_min, funnel_stage, origin, product_requested, product_sold, converted, attention_points, improvement_points, created_at) VALUES ?`, [batch] ); process.stdout.write(`\r✅ Inseridos ${Math.min(i + batchSize, attendancesToInsert.length)} / ${attendancesToInsert.length}`); } console.log('\n🎉 Todos os dados foram gerados com sucesso!'); process.exit(0); } catch (error) { console.error('❌ Erro:', error); process.exit(1); } } run();