From d5e91b422355e0a16ccc2f93abce26d835fe52d0 Mon Sep 17 00:00:00 2001 From: marsalva Date: Sun, 22 Feb 2026 21:34:16 +0000 Subject: [PATCH] Actualizar server.js --- server.js | 56 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/server.js b/server.js index 6fd5079..3fbe325 100644 --- a/server.js +++ b/server.js @@ -254,14 +254,9 @@ async function autoUpdateDB() { -- AÑADIDO: Columna para guardar la configuración de WhatsApp IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='users' AND column_name='wa_settings') THEN - - -- AÑADIDO: Columna para guardar la configuración de WhatsApp - IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='users' AND column_name='wa_settings') THEN ALTER TABLE users ADD COLUMN wa_settings JSONB DEFAULT '{}'; END IF; - - -- AÑADIDO: Configuración del Portal del Cliente IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='users' AND column_name='company_logo') THEN ALTER TABLE users ADD COLUMN company_logo TEXT; @@ -290,8 +285,6 @@ async function autoUpdateDB() { ALTER TABLE service_statuses ADD COLUMN is_system BOOLEAN DEFAULT FALSE; END IF; - - IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='client_id') THEN ALTER TABLE services ADD COLUMN client_id INT REFERENCES clients(id) ON DELETE SET NULL; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='status_id') THEN ALTER TABLE services ADD COLUMN status_id INT REFERENCES service_statuses(id) ON DELETE SET NULL; END IF; IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='contact_phone') THEN ALTER TABLE services ADD COLUMN contact_phone TEXT; END IF; @@ -894,8 +887,48 @@ app.delete("/agenda/blocks/:id", authMiddleware, async (req, res) => { // ========================================== -// ⚙️ MOTOR AUTOMÁTICO DE WHATSAPP +// ⚙️ MOTOR AUTOMÁTICO DE WHATSAPP Y APP SETTINGS (AÑADIDO PARA SOLUCIONAR ERROR 404) // ========================================== +app.get("/whatsapp/status", authMiddleware, async (req, res) => { + try { + const instanceName = `cliente_${req.user.accountId}`; + if (!EVOLUTION_BASE_URL || !EVOLUTION_API_KEY) return res.json({ ok: false, error: "Servidor Evolution no configurado" }); + + const baseUrl = EVOLUTION_BASE_URL.replace(/\/$/, ""); + const headers = { "Content-Type": "application/json", "apikey": EVOLUTION_API_KEY.trim() }; + + // 1. Verificamos si la instancia existe en Evolution + let statusRes = await fetch(`${baseUrl}/instance/connectionState/${instanceName}`, { headers }); + + // 2. Si da 404, significa que nunca se ha creado. La creamos y pedimos el QR + if (statusRes.status === 404) { + await fetch(`${baseUrl}/instance/create`, { + method: 'POST', headers, + body: JSON.stringify({ instanceName: instanceName, qrcode: true, integration: "WHATSAPP-BAILEYS" }) + }); + // Esperamos un poco y volvemos a consultar + await new Promise(r => setTimeout(r, 2000)); + statusRes = await fetch(`${baseUrl}/instance/connectionState/${instanceName}`, { headers }); + } + + const data = await statusRes.json(); + + // 3. Devolvemos el estado + if (data.instance?.state === 'open') { + return res.json({ ok: true, state: 'open', instanceName }); + } else { + // Buscamos el QR + const qrRes = await fetch(`${baseUrl}/instance/connect/${instanceName}`, { headers }); + const qrData = await qrRes.json(); + return res.json({ ok: true, state: 'connecting', qr: qrData.base64 || qrData.code }); + } + } catch (e) { + console.error("Error consultando estado WA:", e); + res.status(500).json({ ok: false, error: "Error de conexión con el motor WA" }); + } +}); + + app.get("/whatsapp/settings", authMiddleware, async (req, res) => { try { const q = await pool.query("SELECT wa_settings FROM users WHERE id=$1", [req.user.accountId]); @@ -1457,9 +1490,12 @@ app.post("/admin/users", authMiddleware, async (req, res) => { const client = aw app.put("/admin/users/:id", authMiddleware, async (req, res) => { const client = await pool.connect(); try { const userId = req.params.id; const { fullName, email, phone, role, guilds, password, zones } = req.body; const p = normalizePhone(phone); await client.query('BEGIN'); if(password) { const hash = await bcrypt.hash(password, 10); await client.query("UPDATE users SET full_name=$1, email=$2, phone=$3, role=$4, password_hash=$5, zones=$6 WHERE id=$7", [fullName, email, p, role, hash, JSON.stringify(zones || []), userId]); } else { await client.query("UPDATE users SET full_name=$1, email=$2, phone=$3, role=$4, zones=$5 WHERE id=$6", [fullName, email, p, role, JSON.stringify(zones || []), userId]); } if (guilds && Array.isArray(guilds)) { await client.query("DELETE FROM user_guilds WHERE user_id=$1", [userId]); for (const gid of guilds) await client.query("INSERT INTO user_guilds (user_id, guild_id) VALUES ($1, $2)", [userId, gid]); } await client.query('COMMIT'); res.json({ ok: true }); } catch (e) { await client.query('ROLLBACK'); res.status(500).json({ ok: false }); } finally { client.release(); } }); app.delete("/admin/users/:id", authMiddleware, async (req, res) => { try { await pool.query("DELETE FROM users WHERE id=$1 AND owner_id=$2", [req.params.id, req.user.accountId]); res.json({ ok: true }); } catch (e) { res.status(500).json({ ok: false }); } }); +// ========================================== +// 🏢 CONFIGURACIÓN EMPRESA (COLORES, LOGO, PORTAL) +// ========================================== app.get("/config/company", authMiddleware, async (req, res) => { try { - const q = await pool.query("SELECT company_slug, full_name, plan_tier, company_logo, portal_settings FROM users WHERE id=$1", [req.user.accountId]); + const q = await pool.query("SELECT company_slug, full_name, plan_tier, company_logo, portal_settings, app_settings FROM users WHERE id=$1", [req.user.accountId]); res.json({ ok: true, config: q.rows[0] || {} }); } catch (e) { res.status(500).json({ ok: false }); } }); @@ -1467,7 +1503,6 @@ app.get("/config/company", authMiddleware, async (req, res) => { app.post("/config/company", authMiddleware, async (req, res) => { const client = await pool.connect(); try { - // Añadimos app_settings a la extracción de datos const { slug, company_name, company_logo, portal_settings, app_settings } = req.body; let cleanSlug = null; @@ -1478,7 +1513,6 @@ app.post("/config/company", authMiddleware, async (req, res) => { if (check.rowCount > 0) return res.status(400).json({ ok: false, error: "Ese enlace ya está en uso por otra empresa" }); } - // Actualizamos la consulta para incluir app_settings ($5) await client.query(` UPDATE users SET company_slug = COALESCE($1, company_slug),