From 81c0d858c1e74dcf0d79136194347bb4df6f1c50 Mon Sep 17 00:00:00 2001 From: marsalva Date: Sat, 21 Feb 2026 16:31:57 +0000 Subject: [PATCH] Actualizar server.js --- server.js | 86 ++++++++++++------------------------------------------- 1 file changed, 19 insertions(+), 67 deletions(-) diff --git a/server.js b/server.js index 8d09456..a2d6680 100644 --- a/server.js +++ b/server.js @@ -1039,57 +1039,7 @@ app.post("/providers/automate/:id", authMiddleware, async (req, res) => { } }); -// AÑADIDO: CAPTURA COMPLETA DE DATOS (...EXTRA) -app.post("/providers/import/:id", authMiddleware, async (req, res) => { - const client = await pool.connect(); - try { - const scrapedId = req.params.id; - const { name, phone, address, cp, description, guild_id, assigned_to, internal_notes, client_notes, is_urgent, ...extra } = req.body; - - await client.query('BEGIN'); - const scrapedQ = await client.query("SELECT * FROM scraped_services WHERE id=$1 AND owner_id=$2", [scrapedId, req.user.accountId]); - if (scrapedQ.rowCount === 0) return res.status(404).json({ ok: false }); - - const raw = scrapedQ.rows[0].raw_data; - const provider = scrapedQ.rows[0].provider; - const ref = scrapedQ.rows[0].service_ref; - - const phoneClean = normalizePhone(phone); - let clientId = null; - if (phoneClean) { - const cCheck = await client.query("SELECT id FROM clients WHERE phone=$1 AND owner_id=$2", [phoneClean, req.user.accountId]); - if (cCheck.rowCount > 0) clientId = cCheck.rows[0].id; - } - if (!clientId) { - const newC = await client.query("INSERT INTO clients (owner_id, full_name, phone, addresses) VALUES ($1, $2, $3, $4) RETURNING id", [req.user.accountId, name, phoneClean, JSON.stringify([address])]); - clientId = newC.rows[0].id; - } - - const statusQ = await client.query("SELECT id FROM service_statuses WHERE owner_id=$1 AND is_default=TRUE LIMIT 1", [req.user.accountId]); - const finalStatusId = statusQ.rows[0]?.id; - - // Fusión total: datos originales del scraper + todo lo recibido en el body - const fullProviderData = { ...raw, ...extra, "Nombre Cliente": name, "Teléfono": phone, "Dirección": address, "Código Postal": cp, "Descripción": description }; - - const insertSvc = await client.query(` - INSERT INTO services - (owner_id, client_id, status_id, company_ref, title, description, address, contact_phone, contact_name, is_company, import_source, provider_data, guild_id, assigned_to, internal_notes, client_notes, is_urgent) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) - RETURNING id`, - [req.user.accountId, clientId, finalStatusId, ref, `${provider.toUpperCase()} - ${ref}`, description, address, phoneClean, name, true, provider, JSON.stringify(fullProviderData), guild_id || null, assigned_to || null, internal_notes, client_notes, is_urgent] - ); - - await client.query("UPDATE scraped_services SET status='imported' WHERE id=$1", [scrapedId]); - await client.query('COMMIT'); - res.json({ ok: true, serviceId: insertSvc.rows[0].id, assigned: !!assigned_to }); - } catch (e) { - await client.query('ROLLBACK'); - res.status(500).json({ ok: false }); - } finally { client.release(); } -}); - -// AÑADIDO Y BLINDADO: CAPTURA COMPLETA DE DATOS Y REGLA WHATSAPP MANUAL -// AÑADIDO Y BLINDADO: CAPTURA COMPLETA DE DATOS, REGLA WHATSAPP MANUAL Y DESASIGNACIÓN +// AÑADIDO Y BLINDADO: CAPTURA COMPLETA, REGLA WA MANUAL, DESASIGNACIÓN Y BORRADO DE FECHA app.put('/providers/scraped/:id', authMiddleware, async (req, res) => { const { id } = req.params; let { automation_status, status, name, phone, address, cp, description, guild_id, assigned_to, assigned_to_name, internal_notes, client_notes, is_urgent, ...extra } = req.body; @@ -1108,18 +1058,21 @@ app.put('/providers/scraped/:id', authMiddleware, async (req, res) => { const current = await pool.query('SELECT raw_data, assigned_to, status FROM scraped_services WHERE id = $1 AND owner_id = $2', [id, req.user.accountId]); if (current.rows.length === 0) return res.status(404).json({ error: 'No encontrado' }); - // --- BLINDAJE DE ESTADO VACÍO --- let oldStatus = current.rows[0].raw_data.status_operativo || null; let newStatus = extra.status_operativo || oldStatus; if (newStatus === "") newStatus = null; - // --- REGLAS DE CAMBIO DE ESTADO MANUAL --- if (newStatus && newStatus !== oldStatus) { const statusQ = await pool.query("SELECT name FROM service_statuses WHERE id=$1", [newStatus]); const stName = (statusQ.rows[0]?.name || "").toLowerCase(); + // --- NUEVA REGLA: BORRADO DE FECHA SI RETROCEDE O SE ANULA --- + if (stName.includes('pendiente') || stName.includes('desasignado') || stName.includes('asignado') || stName.includes('anulado') || stName.includes('esperando')) { + extra.scheduled_date = ""; + extra.scheduled_time = ""; + } + if (stName.includes('asignado')) { - // Regla Asignado -> Pasa a Esperando si se envía WA const waEnviadoExito = await triggerWhatsAppEvent(req.user.accountId, id, 'wa_evt_assigned'); if (waEnviadoExito) { const estadoEsperando = await pool.query("SELECT id FROM service_statuses WHERE owner_id=$1 AND name='Esperando al Cliente' LIMIT 1", [req.user.accountId]); @@ -1129,7 +1082,6 @@ app.put('/providers/scraped/:id', authMiddleware, async (req, res) => { } } } else if (stName.includes('pendiente de asignar') || stName.includes('desasignado')) { - // Regla Desasignar -> Avisa al Operario y borra datos const oldWorkerId = current.rows[0].assigned_to || current.rows[0].raw_data.assigned_to; if (oldWorkerId) { const workerQ = await pool.query("SELECT full_name, phone FROM users WHERE id=$1", [oldWorkerId]); @@ -1140,7 +1092,6 @@ app.put('/providers/scraped/:id', authMiddleware, async (req, res) => { sendWhatsAppAuto(w.phone, msg, `cliente_${req.user.accountId}`, false).catch(console.error); } } - // Forzamos el borrado del operario assigned_to = null; assigned_to_name = null; extra.assigned_to = null; @@ -1165,10 +1116,9 @@ app.put('/providers/scraped/:id', authMiddleware, async (req, res) => { "status_operativo": newStatus }; - // --- BLINDAJE DE OPERARIO VACÍO (Evita el error 500) --- let finalAssignedTo = assigned_to; - if (finalAssignedTo === "" || finalAssignedTo === null) finalAssignedTo = null; // Queda libre - else if (finalAssignedTo === undefined) finalAssignedTo = current.rows[0].assigned_to; // Mantiene el que tenía + if (finalAssignedTo === "" || finalAssignedTo === null) finalAssignedTo = null; + else if (finalAssignedTo === undefined) finalAssignedTo = current.rows[0].assigned_to; let currentDbStatus = current.rows[0].status; @@ -1224,17 +1174,15 @@ app.put("/services/set-appointment/:id", authMiddleware, async (req, res) => { const { id } = req.params; let { date, time, status_operativo, ...extra } = req.body; - // REPARADO: Añadido assigned_to al SELECT para poder avisar al operario const current = await pool.query('SELECT raw_data, assigned_to FROM scraped_services WHERE id = $1 AND owner_id = $2', [id, req.user.accountId]); if (current.rowCount === 0) return res.status(404).json({ ok: false, error: 'No encontrado' }); const oldDate = current.rows[0].raw_data.scheduled_date || ""; const oldTime = current.rows[0].raw_data.scheduled_time || ""; - const newDate = date || ""; - const newTime = time || ""; - let finalAssignedTo = current.rows[0].assigned_to; // Lo guardamos por defecto + let newDate = date || ""; + let newTime = time || ""; + let finalAssignedTo = current.rows[0].assigned_to; - // BLINDAJE DE ESTADO VACÍO if (status_operativo === "") status_operativo = null; let stName = ""; @@ -1243,6 +1191,12 @@ app.put("/services/set-appointment/:id", authMiddleware, async (req, res) => { stName = (statusQ.rows[0]?.name || "").toLowerCase(); } + // --- NUEVA REGLA: BORRAR FECHAS SI SE ANULA O RETROCEDE --- + if (stName.includes('pendiente') || stName.includes('desasignado') || stName.includes('asignado') || stName.includes('anulado') || stName.includes('esperando')) { + newDate = ""; + newTime = ""; + } + // --- MOTOR DE EVENTOS Y DESASIGNACIÓN --- if (stName.includes('asignado')) { const waEnviadoExito = await triggerWhatsAppEvent(req.user.accountId, id, 'wa_evt_assigned'); @@ -1254,7 +1208,6 @@ app.put("/services/set-appointment/:id", authMiddleware, async (req, res) => { } } else if (stName.includes('pendiente de asignar') || stName.includes('desasignado')) { - // DESASIGNAR: Notificar al operario y borrar rastro const oldWorkerId = finalAssignedTo || current.rows[0].raw_data.assigned_to; if (oldWorkerId) { const workerQ = await pool.query("SELECT full_name, phone FROM users WHERE id=$1", [oldWorkerId]); @@ -1267,7 +1220,7 @@ app.put("/services/set-appointment/:id", authMiddleware, async (req, res) => { } extra.assigned_to = null; extra.assigned_to_name = null; - finalAssignedTo = null; // Borramos el físico también + finalAssignedTo = null; } else if (stName.includes('citado') && newDate !== "") { if (oldDate === "") await triggerWhatsAppEvent(req.user.accountId, id, 'wa_evt_date'); @@ -1280,7 +1233,6 @@ app.put("/services/set-appointment/:id", authMiddleware, async (req, res) => { const updatedRawData = { ...current.rows[0].raw_data, ...extra, "scheduled_date": newDate, "scheduled_time": newTime, "status_operativo": status_operativo }; - // ACTUALIZAMOS RAW DATA Y EL OPERARIO FÍSICO await pool.query('UPDATE scraped_services SET raw_data = $1, assigned_to = $2 WHERE id = $3 AND owner_id = $4', [JSON.stringify(updatedRawData), finalAssignedTo, id, req.user.accountId]); res.json({ ok: true });