From 2661b3bcfceb15a7bf37873a9bf33155a991d2fd Mon Sep 17 00:00:00 2001 From: marsalva Date: Wed, 25 Feb 2026 22:59:11 +0000 Subject: [PATCH] Actualizar server.js --- server.js | 81 ++++++++++++++++++++++++++----------------------------- 1 file changed, 38 insertions(+), 43 deletions(-) diff --git a/server.js b/server.js index b7df35e..ec24ea4 100644 --- a/server.js +++ b/server.js @@ -506,64 +506,59 @@ app.get("/public/portal/:token", async (req, res) => { try { const { token } = req.params; - // 1. Validar Token y Obtener Cliente + // 1. Validar Token const qClient = await pool.query("SELECT * FROM clients WHERE portal_token = $1", [token]); if (qClient.rowCount === 0) return res.status(404).json({ ok: false, error: "Enlace inválido" }); const client = qClient.rows[0]; + const ownerId = client.owner_id; - // Asegurar IDs y Teléfono para la búsqueda - const ownerId = client.owner_id || client.account_id; - const clientPhone = client.phone ? `%${client.phone.replace('+34', '').trim()}%` : '%000000000%'; - - // 2. Obtener la Configuración de la Empresa - const qConfig = await pool.query("SELECT * FROM config WHERE account_id::text = $1::text", [ownerId]); + // 2. Obtener Configuración Empresa + const qConfig = await pool.query("SELECT portal_settings FROM users WHERE id = $1", [ownerId]); let company = { name: "IntegraRepara", logo: "" }; if (qConfig.rowCount > 0 && qConfig.rows[0].portal_settings) { company = qConfig.rows[0].portal_settings; } - // 3. Buscar TODOS los servicios del cliente (SQL Protegido contra NULLs) + // 3. LA CONSULTA MÁS SIMPLE POSIBLE (Para evitar el Error 500) + // Buscamos servicios que pertenezcan al dueño y que coincidan con el teléfono del cliente + // He quitado los JOINs complejos y los filtros raros de JSON para que no explote const qServices = await pool.query(` - SELECT - s.id, s.service_ref, s.is_urgent, s.raw_data, - st.name as status_name, - st.is_final as status_is_final, - u.name as assigned_worker - FROM scraped_services s - LEFT JOIN service_statuses st ON st.id::text = (s.raw_data->>'status_operativo')::text - LEFT JOIN users u ON u.id::text = s.assigned_to::text - WHERE s.owner_id::text = $1::text - AND s.provider != 'SYSTEM_BLOCK' - AND s.raw_data IS NOT NULL - AND ( - COALESCE(s.raw_data->>'Teléfono', '') LIKE $2 OR - COALESCE(s.raw_data->>'TELEFONOS', '') LIKE $2 OR - COALESCE(s.raw_data->>'TELEFONO', '') LIKE $2 OR - COALESCE(s.raw_data->>'Teléfono 1', '') LIKE $2 - ) - ORDER BY - st.is_final ASC NULLS FIRST, - s.created_at DESC - `, [ownerId, clientPhone]); + SELECT id, service_ref, is_urgent, raw_data, created_at + FROM scraped_services + WHERE owner_id = $1 + AND provider != 'SYSTEM_BLOCK' + AND raw_data::text LIKE '%' || $2 || '%' + ORDER BY created_at DESC + `, [ownerId, client.phone.replace('+34', '').trim()]); - // Formatear servicios para el frontal - const formattedServices = qServices.rows.map(s => ({ - id: s.id, - title: s.is_urgent ? `🚨 URGENTE: Expediente #${s.service_ref}` : `Expediente #${s.service_ref}`, - description: s.raw_data?.["Descripción"] || s.raw_data?.["DESCRIPCION"] || "Revisión técnica solicitada.", - status_name: s.status_name || 'Pendiente', - is_final: s.status_is_final === true, - scheduled_date: s.raw_data?.scheduled_date, - scheduled_time: s.raw_data?.scheduled_time, - assigned_worker: s.assigned_worker || 'Pendiente', - raw_data: s.raw_data - })); + // 4. PROCESAMOS LOS ESTADOS EN JAVASCRIPT (No en SQL, para que no falle) + // Necesitamos los nombres de los estados + const qStats = await pool.query("SELECT id, name, is_final FROM service_statuses WHERE owner_id = $1", [ownerId]); + const statsMap = {}; + qStats.rows.forEach(s => { statsMap[String(s.id)] = s; }); + + const formattedServices = qServices.rows.map(s => { + const statusId = String(s.raw_data?.status_operativo || ""); + const statusObj = statsMap[statusId]; + + return { + id: s.id, + title: s.is_urgent ? `🚨 URGENTE: Expediente #${s.service_ref}` : `Expediente #${s.service_ref}`, + description: s.raw_data?.["Descripción"] || s.raw_data?.["DESCRIPCION"] || "Revisión técnica.", + status_name: statusObj ? statusObj.name : 'Pendiente', + is_final: statusObj ? statusObj.is_final : false, + scheduled_date: s.raw_data?.scheduled_date, + scheduled_time: s.raw_data?.scheduled_time, + assigned_worker: s.raw_data?.assigned_to_name || 'Pendiente', + raw_data: s.raw_data + }; + }); res.json({ ok: true, client, company, services: formattedServices }); } catch (e) { - console.error("🔥 Error 500 en Portal Cliente:", e); - res.status(500).json({ ok: false, error: "Error interno del servidor" }); + console.error("Error Crítico Portal:", e); + res.status(500).json({ ok: false, error: "Error de conexión" }); } });