Actualizar server.js

This commit is contained in:
2026-03-14 16:57:02 +00:00
parent 3ff7788667
commit c9605c9497

113
server.js
View File

@@ -904,6 +904,119 @@ async function procesarConIA(ownerId, mensajeCliente, datosExpediente) {
return null;
}
}
// ==========================================
// 🌐 EMBUDO PÚBLICO DE ENTRADA DE CLIENTES
// ==========================================
app.post("/public/new-request", async (req, res) => {
const clientDb = await pool.connect();
try {
const { phone, name, address, guild_id, description, is_urgent, owner_id } = req.body;
if (!phone || !guild_id) return res.status(400).json({ ok: false, error: "Faltan datos clave" });
// Por ahora, como es público, asumiremos que entra a la instancia principal (owner_id = 1),
// a menos que uses subdominios por empresa. Lo forzamos a 1 para este ejemplo.
const targetOwnerId = owner_id || 1;
const cleanPhone = phone.replace(/\D/g, "");
if (cleanPhone.length < 9) return res.status(400).json({ ok: false, error: "Teléfono inválido" });
await clientDb.query('BEGIN');
// 1. BUSCAR O CREAR CLIENTE
let clientId, clientToken;
const qClient = await clientDb.query("SELECT id, portal_token FROM clients WHERE phone LIKE $1 AND owner_id = $2 LIMIT 1", [`%${cleanPhone}%`, targetOwnerId]);
if (qClient.rowCount > 0) {
clientId = qClient.rows[0].id;
clientToken = qClient.rows[0].portal_token;
} else {
clientToken = crypto.randomBytes(6).toString('hex');
const newClient = await clientDb.query(
"INSERT INTO clients (owner_id, full_name, phone, addresses, portal_token) VALUES ($1, $2, $3, $4, $5) RETURNING id",
[targetOwnerId, name || "Cliente Web", phone, JSON.stringify([address || ""]), clientToken]
);
clientId = newClient.rows[0].id;
}
// 2. BUSCAR OPERARIO AL AZAR (Si es NORMAL)
let assignedWorkerId = null;
if (!is_urgent) {
// Buscamos un operario activo de ese gremio al azar
const qWorker = await clientDb.query(`
SELECT u.id FROM users u
JOIN user_guilds ug ON u.id = ug.user_id
WHERE u.owner_id = $1 AND u.role = 'operario' AND u.status = 'active' AND ug.guild_id = $2
ORDER BY RANDOM() LIMIT 1
`, [targetOwnerId, guild_id]);
if (qWorker.rowCount > 0) {
assignedWorkerId = qWorker.rows[0].id;
} else {
// Si no hay operarios para asignar calendario, lo forzamos a manual/bolsa
return res.status(400).json({ ok: false, error: "No hay técnicos disponibles para cita normal en este gremio. Llama a la oficina." });
}
}
// 3. CREAR EL SERVICIO
const rawData = {
"Nombre Cliente": name || "Cliente Web",
"Teléfono": phone,
"Dirección": address || "",
"Descripción": description || "Aviso desde Web",
"guild_id": guild_id,
"Compañía": "Particular",
"Origen": "Web Público"
};
const ref = `WEB-${Date.now().toString().slice(-6)}`;
const qSvc = await clientDb.query(`
INSERT INTO scraped_services (owner_id, provider, service_ref, status, automation_status, assigned_to, is_urgent, raw_data)
VALUES ($1, 'particular', $2, 'pending', $3, $4, $5, $6) RETURNING id
`, [
targetOwnerId,
ref,
is_urgent ? 'in_progress' : 'manual', // Si es urgente, va a la bolsa
assignedWorkerId, // Solo tendrá id si NO es urgente
is_urgent,
JSON.stringify(rawData)
]);
const newServiceId = qSvc.rows[0].id;
await clientDb.query('COMMIT');
// 4. BIFURCACIÓN DE RUTAS
if (is_urgent) {
// Mandamos a la cola automáticamente para que suene a los técnicos
// Lo ejecutamos en segundo plano llamando a tu propio endpoint
const port = process.env.PORT || 3000;
fetch(`http://127.0.0.1:${port}/providers/automate/${newServiceId}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${process.env.ADMIN_TOKEN || 'hack_interno'}` }, // Necesitarás un token interno para esto
body: JSON.stringify({ guild_id, cp: "00000", useDelay: false })
}).catch(e => console.error("Error lanzando bolsa urgente:", e));
res.json({ ok: true, action: 'queued', message: "Aviso urgente en cola." });
} else {
// Devolvemos el token del cliente y el ID del servicio para redirigirlo al calendario
res.json({
ok: true,
action: 'calendar',
redirectUrl: `https://portal.integrarepara.es/?token=${clientToken}&service=${newServiceId}`
});
}
} catch (e) {
await clientDb.query('ROLLBACK');
console.error("Error en Web Pública:", e);
res.status(500).json({ ok: false, error: "Error procesando solicitud" });
} finally {
clientDb.release();
}
});
// ==========================================
// 🔗 PORTAL PÚBLICO DEL CLIENTE
// ==========================================