Actualizar server.js
This commit is contained in:
70
server.js
70
server.js
@@ -1064,7 +1064,7 @@ app.get("/providers/scraped", authMiddleware, async (req, res) => {
|
||||
});
|
||||
|
||||
// ==========================================
|
||||
// 🤖 RUTA DE AUTOMATIZACIÓN (CORREGIDA)
|
||||
// 🤖 RUTA DE AUTOMATIZACIÓN (MEJORADA)
|
||||
// ==========================================
|
||||
app.post("/providers/automate/:id", authMiddleware, async (req, res) => {
|
||||
const { id } = req.params;
|
||||
@@ -1073,9 +1073,9 @@ app.post("/providers/automate/:id", authMiddleware, async (req, res) => {
|
||||
try {
|
||||
const { guild_id, cp, useDelay } = req.body;
|
||||
|
||||
if (!guild_id || !cp) {
|
||||
console.error("❌ [AUTOMATE] Faltan datos: guild_id o CP");
|
||||
return res.status(400).json({ ok: false, error: "Faltan datos (Gremio o CP)" });
|
||||
if (!guild_id) {
|
||||
console.error("❌ [AUTOMATE] Faltan datos: guild_id");
|
||||
return res.status(400).json({ ok: false, error: "Falta Gremio" });
|
||||
}
|
||||
|
||||
// 1. Verificar si el expediente existe
|
||||
@@ -1085,11 +1085,8 @@ app.post("/providers/automate/:id", authMiddleware, async (req, res) => {
|
||||
return res.status(404).json({ ok: false, error: "Expediente no encontrado" });
|
||||
}
|
||||
|
||||
const serviceData = serviceQ.rows[0];
|
||||
const raw = serviceData.raw_data;
|
||||
|
||||
// 2. Buscar operarios que cumplan Gremio + Zona (CP) + Activos
|
||||
const workersQ = await pool.query(`
|
||||
let workersQ = await pool.query(`
|
||||
SELECT u.id, u.full_name, u.phone
|
||||
FROM users u
|
||||
JOIN user_guilds ug ON u.id = ug.user_id
|
||||
@@ -1098,11 +1095,26 @@ app.post("/providers/automate/:id", authMiddleware, async (req, res) => {
|
||||
AND u.status = 'active'
|
||||
AND ug.guild_id = $2
|
||||
AND u.zones::jsonb @> $3::jsonb
|
||||
`, [req.user.accountId, guild_id, JSON.stringify([{ cps: cp.toString() }])]);
|
||||
`, [req.user.accountId, guild_id, JSON.stringify([{ cps: (cp || "00000").toString() }])]);
|
||||
|
||||
// MEJORA: Si no hay nadie para ese CP exacto (o si no se puso CP en el presupuesto),
|
||||
// buscamos a CUALQUIER operario de ese gremio
|
||||
if (workersQ.rowCount === 0) {
|
||||
console.log(`⚠️ [AUTOMATE] No hay operario para el CP exacto, buscando a cualquiera del gremio ${guild_id}...`);
|
||||
workersQ = await pool.query(`
|
||||
SELECT u.id, u.full_name, u.phone
|
||||
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
|
||||
`, [req.user.accountId, guild_id]);
|
||||
}
|
||||
|
||||
if (workersQ.rowCount === 0) {
|
||||
console.warn(`⚠️ [AUTOMATE] No hay operarios activos para Gremio:${guild_id} y CP:${cp}`);
|
||||
return res.status(404).json({ ok: false, error: "No hay operarios disponibles para esta zona/gremio" });
|
||||
console.warn(`❌ [AUTOMATE] No hay operarios activos para el Gremio:${guild_id}`);
|
||||
return res.status(404).json({ ok: false, error: "No hay operarios disponibles para este gremio" });
|
||||
}
|
||||
|
||||
// 3. Marcar como "En progreso"
|
||||
@@ -1123,9 +1135,10 @@ app.post("/providers/automate/:id", authMiddleware, async (req, res) => {
|
||||
});
|
||||
|
||||
const link = `https://web.integrarepara.es/aceptar.html?t=${token}`;
|
||||
const mensaje = `🛠️ *NUEVO SERVICIO DISPONIBLE*\n\n👤 *Operario:* ${worker.full_name}\n📍 *Zona:* ${cp}\n⏱️ *Expira:* ${horaCaducidad}\n\nRevisa y acepta aquí:\n🔗 ${link}`;
|
||||
const cpMostrar = (cp && cp !== "00000") ? cp : "Zona asignada";
|
||||
const mensaje = `🛠️ *NUEVO SERVICIO DISPONIBLE*\n\n👤 *Operario:* ${worker.full_name}\n📍 *Zona:* ${cpMostrar}\n⏱️ *Expira:* ${horaCaducidad}\n\nRevisa y acepta aquí:\n🔗 ${link}`;
|
||||
|
||||
// 6. Envío WA (Sandbox 667248132 activo en sendWhatsAppAuto)
|
||||
// 6. Envío WA
|
||||
const instanceName = `cliente_${req.user.accountId}`;
|
||||
sendWhatsAppAuto(worker.phone, mensaje, instanceName, useDelay).catch(e => console.error("Error WA Automate:", e.message));
|
||||
|
||||
@@ -2096,7 +2109,7 @@ app.patch("/budgets/:id/status", authMiddleware, async (req, res) => {
|
||||
} catch(e) { res.status(500).json({ok: false}); }
|
||||
});
|
||||
|
||||
// Convertir Presupuesto en Servicio Activo
|
||||
// Convertir Presupuesto en Servicio Activo (CON SOPORTE RED INTERNA)
|
||||
app.post("/budgets/:id/convert", authMiddleware, async (req, res) => {
|
||||
try {
|
||||
const { date, time, guild_id, assigned_to, use_automation } = req.body;
|
||||
@@ -2117,13 +2130,12 @@ app.post("/budgets/:id/convert", authMiddleware, async (req, res) => {
|
||||
"scheduled_time": time || ""
|
||||
};
|
||||
|
||||
// 2. Insertamos en el Panel Operativo (Buzón)
|
||||
// 2. Insertamos en el Panel Operativo (Buzón) empezando en manual
|
||||
const insertSvc = await pool.query(
|
||||
"INSERT INTO scraped_services (owner_id, provider, service_ref, status, automation_status, assigned_to, raw_data) VALUES ($1, 'particular', $2, 'pending', $3, $4, $5) RETURNING id",
|
||||
"INSERT INTO scraped_services (owner_id, provider, service_ref, status, automation_status, assigned_to, raw_data) VALUES ($1, 'particular', $2, 'pending', 'manual', $3, $4) RETURNING id",
|
||||
[
|
||||
req.user.accountId,
|
||||
`PRE-${budget.id}`,
|
||||
use_automation ? 'manual' : 'manual', // Empezamos en manual siempre
|
||||
assigned_to || null,
|
||||
JSON.stringify(rawData)
|
||||
]
|
||||
@@ -2138,36 +2150,38 @@ app.post("/budgets/:id/convert", authMiddleware, async (req, res) => {
|
||||
[newServiceId, budget.total]
|
||||
);
|
||||
|
||||
// 4. Si pide automatización, la disparamos internamente simulando la llamada
|
||||
// 4. Si pide automatización, la disparamos internamente llamando a nuestra propia IP (127.0.0.1)
|
||||
if (use_automation && guild_id) {
|
||||
// Buscamos código postal por si acaso para la automatización
|
||||
const cpMatch = budget.client_address ? budget.client_address.match(/\b\d{5}\b/) : null;
|
||||
const cp = cpMatch ? cpMatch[0] : "00000"; // Fallback si no hay CP
|
||||
const cp = cpMatch ? cpMatch[0] : "00000";
|
||||
|
||||
// Reutilizamos la lógica de automatización (hacemos un fetch a nosotros mismos para aprovechar el motor existente)
|
||||
const port = process.env.PORT || 3000;
|
||||
const autoUrl = `http://localhost:${port}/providers/automate/${newServiceId}`;
|
||||
// IMPORTANTE: 127.0.0.1 en lugar de localhost para evitar errores en Node
|
||||
const autoUrl = `http://127.0.0.1:${port}/providers/automate/${newServiceId}`;
|
||||
|
||||
// Lo lanzamos sin esperar (asíncrono) para no bloquear la respuesta
|
||||
fetch(autoUrl, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${req.headers.authorization.split(' ')[1]}` },
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': req.headers.authorization
|
||||
},
|
||||
body: JSON.stringify({ guild_id, cp, useDelay: false })
|
||||
}).catch(e => console.error("Error lanzando automatización interna:", e));
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(d => console.log("Llamada interna a automatización finalizada.", d))
|
||||
.catch(e => console.error("Error lanzando automatización interna:", e));
|
||||
|
||||
// Si va a la bolsa, no avisamos al cliente de la fecha (aún no se sabe)
|
||||
if (budget.client_phone) {
|
||||
const msg = `✅ *PRESUPUESTO ACEPTADO*\n\nHola ${budget.client_name}, confirmamos la aceptación del presupuesto por un total de *${budget.total}€*.\n\nEn breve un técnico se pondrá en contacto contigo para agendar la cita. ¡Gracias por confiar en nosotros!`;
|
||||
sendWhatsAppAuto(budget.client_phone, msg, `cliente_${req.user.accountId}`, false).catch(console.error);
|
||||
}
|
||||
}
|
||||
// 5. Si se asigna manual con fecha
|
||||
else if (budget.client_phone && date && time) {
|
||||
// Asignación directa a un técnico con fecha y hora
|
||||
const [y, m, d] = date.split('-');
|
||||
const msg = `✅ *PRESUPUESTO ACEPTADO*\n\nHola ${budget.client_name}, confirmamos la aceptación del presupuesto por un total de *${budget.total}€*.\n\nEl servicio ha sido agendado para el *${d}/${m}/${y} a las ${time}*. ¡Gracias por confiar en nosotros!`;
|
||||
sendWhatsAppAuto(budget.client_phone, msg, `cliente_${req.user.accountId}`, false).catch(console.error);
|
||||
|
||||
// Forzar estado Asignado si hay un técnico
|
||||
if (assigned_to) {
|
||||
const statusQ = await pool.query("SELECT id FROM service_statuses WHERE owner_id=$1 AND name ILIKE '%asignado%' LIMIT 1", [req.user.accountId]);
|
||||
if (statusQ.rowCount > 0) {
|
||||
|
||||
Reference in New Issue
Block a user