Actualizar server.js

This commit is contained in:
2026-02-16 20:40:28 +00:00
parent 266c7b5435
commit b79d37d955

View File

@@ -310,14 +310,20 @@ async function sendWhatsAppCode(phone, code) {
} catch (e) { console.error("Error envío WA:", e.message); } } catch (e) { console.error("Error envío WA:", e.message); }
} }
async function sendWhatsAppAuto(phone, text) { async function sendWhatsAppAuto(phone, text, instanceName) {
if (!EVOLUTION_BASE_URL || !EVOLUTION_API_KEY || !EVOLUTION_INSTANCE) return; if (!EVOLUTION_BASE_URL || !EVOLUTION_API_KEY || !instanceName) return;
try { try {
await fetch(`${EVOLUTION_BASE_URL.replace(/\/$/, "")}/message/sendText/${EVOLUTION_INSTANCE}`, { // MATEMÁTICA HUMANA: Tiempo simulado de escritura
const typingTimeMs = Math.min(Math.max(text.length * 30, 1500), 8000);
await fetch(`${EVOLUTION_BASE_URL.replace(/\/$/, "")}/message/sendText/${instanceName}`, {
method: "POST", headers: { "Content-Type": "application/json", "apikey": EVOLUTION_API_KEY }, method: "POST", headers: { "Content-Type": "application/json", "apikey": EVOLUTION_API_KEY },
body: JSON.stringify({ number: phone.replace("+", ""), text }) body: JSON.stringify({
number: phone.replace("+", ""),
text: text,
delay: typingTimeMs
})
}); });
} catch (e) {} } catch (e) { console.error("Error envío WA:", e.message); }
} }
async function ensureInstance(instanceName) { async function ensureInstance(instanceName) {
@@ -560,7 +566,9 @@ app.post("/providers/automate/:id", authMiddleware, async (req, res) => {
🔗 ${link}`; 🔗 ${link}`;
await sendWhatsAppAuto(worker.phone, mensaje); // SAAS: INSTANCIA DE CLIENTE ESPECÍFICA SIN AWAIT PARA NO BLOQUEAR
const instanceName = `cliente_${req.user.accountId}`;
sendWhatsAppAuto(worker.phone, mensaje, instanceName).catch(console.error);
res.json({ ok: true, message: "Automatismo iniciado con " + worker.full_name }); res.json({ ok: true, message: "Automatismo iniciado con " + worker.full_name });
} catch (e) { } catch (e) {
@@ -697,8 +705,7 @@ app.get("/services/active", authMiddleware, async (req, res) => {
} catch (e) { res.status(500).json({ ok: false }); } } catch (e) { res.status(500).json({ ok: false }); }
}); });
// AÑADIDO: Ruta para fijar la cita o el estado operativo // AÑADIDO: Ruta para fijar la cita o el estado operativo (CORREGIDA Y BLINDADA)
// AÑADIDO: Ruta para fijar la cita o el estado operativo
app.put("/services/set-appointment/:id", authMiddleware, async (req, res) => { app.put("/services/set-appointment/:id", authMiddleware, async (req, res) => {
try { try {
const { id } = req.params; const { id } = req.params;
@@ -841,37 +848,40 @@ app.delete("/services/:id", authMiddleware, async (req, res) => { try { await po
// 🕒 EL RELOJ DEL SISTEMA (Ejecutar cada minuto) // 🕒 EL RELOJ DEL SISTEMA (Ejecutar cada minuto)
// ========================================== // ==========================================
setInterval(async () => { setInterval(async () => {
    try { try {
       const expiredPings = await pool.query(` const expiredPings = await pool.query(`
            SELECT ap.id, ap.scraped_id, ap.user_id, s.owner_id, s.raw_data SELECT ap.id, ap.scraped_id, ap.user_id, s.owner_id, s.raw_data
            FROM assignment_pings ap FROM assignment_pings ap
            JOIN scraped_services s ON ap.scraped_id = s.id JOIN scraped_services s ON ap.scraped_id = s.id
            WHERE ap.status = 'pending'  WHERE ap.status = 'pending'
            AND EXTRACT(EPOCH FROM (ap.expires_at - CURRENT_TIMESTAMP)) <= 0 AND EXTRACT(EPOCH FROM (ap.expires_at - CURRENT_TIMESTAMP)) <= 0
            AND s.automation_status = 'in_progress' AND s.automation_status = 'in_progress'
        `);  `);
        for (const ping of expiredPings.rows) { for (const ping of expiredPings.rows) {
            await pool.query("UPDATE assignment_pings SET status = 'expired' WHERE id = $1", [ping.id]); await pool.query("UPDATE assignment_pings SET status = 'expired' WHERE id = $1", [ping.id]);
            const nextWorkerQ = await pool.query(` const nextWorkerQ = await pool.query(`
                SELECT u.id, u.phone, u.full_name  SELECT u.id, u.phone, u.full_name
                FROM users u FROM users u
                JOIN user_guilds ug ON u.id = ug.user_id JOIN user_guilds ug ON u.id = ug.user_id
                WHERE u.owner_id = $1 AND u.status = 'active' WHERE u.owner_id = $1 AND u.status = 'active'
                AND u.id NOT IN (SELECT user_id FROM assignment_pings WHERE scraped_id = $2) AND u.id NOT IN (SELECT user_id FROM assignment_pings WHERE scraped_id = $2)
                LIMIT 1 LIMIT 1
            `, [ping.owner_id, ping.scraped_id]); `, [ping.owner_id, ping.scraped_id]);
            if (nextWorkerQ.rowCount > 0) { if (nextWorkerQ.rowCount > 0) {
                const nextW = nextWorkerQ.rows[0]; const nextW = nextWorkerQ.rows[0];
                const newToken = crypto.randomBytes(16).toString('hex'); const newToken = crypto.randomBytes(16).toString('hex');
                await pool.query(`INSERT INTO assignment_pings (scraped_id, user_id, token, expires_at) VALUES ($1, $2, $3, CURRENT_TIMESTAMP + INTERVAL '5 minutes')`, [ping.scraped_id, nextW.id, newToken]); await pool.query(`INSERT INTO assignment_pings (scraped_id, user_id, token, expires_at) VALUES ($1, $2, $3, CURRENT_TIMESTAMP + INTERVAL '5 minutes')`, [ping.scraped_id, nextW.id, newToken]);
                await sendWhatsAppAuto(nextW.phone, `🛠️ *SERVICIO DISPONIBLE*\nEl anterior compañero no respondió. Es tu turno:\n🔗 https://integrarepara.es/aceptar.html?t=${newToken}`);
            } else { const mensaje = `🛠️ *SERVICIO DISPONIBLE*\nEl anterior compañero no respondió. Es tu turno:\n🔗 https://integrarepara.es/aceptar.html?t=${newToken}`;
                await pool.query("UPDATE scraped_services SET automation_status = 'failed' WHERE id = $1", [ping.scraped_id]); const instanceName = `cliente_${ping.owner_id}`;
            } sendWhatsAppAuto(nextW.phone, mensaje, instanceName).catch(console.error);
        } } else {
    } catch (e) { console.error("Reloj:", e); } await pool.query("UPDATE scraped_services SET automation_status = 'failed' WHERE id = $1", [ping.scraped_id]);
}
}
} catch (e) { console.error("Reloj:", e); }
}, 60000); }, 60000);
const port = process.env.PORT || 3000; const port = process.env.PORT || 3000;