Prioriza móviles sobre fijos al elegir teléfono del cliente; expone phones[] en /services/active

This commit is contained in:
2026-08-27 07:03:39 +00:00
parent dc9485a13a
commit 59bc5b0130

View File

@@ -1078,11 +1078,51 @@ function extractValidPhone(rawPhone) {
let str = String(rawPhone).replace(/\D/g, ""); // Borra todo lo que no sea número (espacios, letras, +, -)
if (str.startsWith("0034")) str = str.slice(4);
if (str.startsWith("34") && str.length >= 11) str = str.slice(2);
const match = str.match(/[6789]\d{8}/);
const match = str.match(/[6789]\d{8}/);
return match ? match[0] : (str.length >= 9 ? str.slice(-9) : str);
}
// 📞 Un servicio puede traer VARIOS teléfonos mezclados en el mismo campo (típico de HomeServe:
// "629046101 de 09:00 a 20:00\n659153929 de 09:00 a 20:00..."), fijos y móviles sin ningún orden.
// Esto extrae TODOS los números válidos que encuentre (de "Teléfono"/"TELEFONO"/"TELEFONOS"),
// sin duplicados, y los devuelve con los MÓVILES (6xx/7xx) siempre primero.
function extractAllPhones(raw) {
if (!raw) return [];
const sources = [raw['TELEFONOS'], raw['Teléfonos'], raw['Teléfono'], raw['TELEFONO']].filter(Boolean);
const seen = new Set();
const result = [];
for (const src of sources) {
const lines = String(src).split(/\n+/);
for (const line of lines) {
const matches = line.match(/[6789]\d{8}/g) || [];
for (const number of matches) {
if (seen.has(number)) continue;
seen.add(number);
const horario = line.match(/de\s*\d{1,2}:\d{2}\s*a\s*\d{1,2}:\d{2}/i)?.[0] || '';
const contactoMatch = line.match(/Persona de Contacto:\s*([^\n]*?)(?:\s*Observaciones:|$)/i);
const contacto = contactoMatch ? contactoMatch[1].trim() : '';
result.push({ number, isMobile: /^[67]/.test(number), horario, contacto });
}
}
}
result.sort((a, b) => (b.isMobile - a.isMobile));
return result;
}
// Igual que extractValidPhone, pero PRIORIZANDO MÓVILES: para automatizaciones de WhatsApp/SMS,
// que solo pueden llegar de verdad a un número móvil, no a un fijo.
function extractBestMobile(raw) {
const phones = extractAllPhones(raw);
if (phones.length > 0) return phones[0].number;
// Red de seguridad: si no detectamos ningún número con el patrón habitual, mantenemos
// el comportamiento anterior para no perder del todo la posibilidad de contactar.
const fallbackRaw = (raw && (raw["Teléfono"] || raw["TELEFONO"] || raw["TELEFONOS"])) || "";
return extractValidPhone(fallbackRaw);
}
// 2. Normaliza SIEMPRE a Formato Internacional para la Base de Datos (+34600123456)
function normalizePhone(phone) {
const clean = extractValidPhone(phone);
@@ -1409,8 +1449,7 @@ async function triggerHomeServeRobot(ownerId, serviceId, eventType) {
// 3. Traducir variables personalizadas
let text = rule.obs || "";
const clientName = raw["Nombre Cliente"] || raw["CLIENTE"] || "Cliente";
let clientPhone = raw["Teléfono"] || raw["TELEFONO"] || raw["TELEFONOS"] || "";
clientPhone = extractValidPhone(clientPhone);
let clientPhone = extractBestMobile(raw);
// Formateo humano de la fecha para el texto de observaciones
let textoFechaCita = "hoy";
@@ -1503,8 +1542,7 @@ async function triggerMultiRobot(ownerId, serviceId, eventType) {
let text = rule.obs || "";
const clientName = raw["Nombre Cliente"] || raw["CLIENTE"] || "Cliente";
let clientPhone = raw["Teléfono"] || raw["TELEFONO"] || raw["TELEFONOS"] || "";
clientPhone = extractValidPhone(clientPhone);
let clientPhone = extractBestMobile(raw);
let textoFechaCita = "hoy";
if (raw.scheduled_date) {
@@ -3119,9 +3157,8 @@ async function triggerWhatsAppEvent(ownerId, serviceId, eventType) {
const s = svcQ.rows[0];
const raw = s.raw_data || {};
// 1. EXTRAER TELÉFONO DEL CLIENTE LIMPIO
let rawPhone = raw["Teléfono"] || raw["TELEFONO"] || raw["TELEFONOS"] || "";
let cleanPhoneToMatch = extractValidPhone(rawPhone);
// 1. EXTRAER TELÉFONO DEL CLIENTE LIMPIO (prioriza móvil sobre fijo)
let cleanPhoneToMatch = extractBestMobile(raw);
if (cleanPhoneToMatch.length < 9) return false; // Si no hay teléfono válido, cancelamos
const finalPhoneToSend = "34" + cleanPhoneToMatch;
@@ -3608,12 +3645,13 @@ app.get("/services/active", authMiddleware, async (req, res) => {
}
query += ` ORDER BY s.created_at DESC`;
const q = await pool.query(query, params);
res.json({ ok: true, services: q.rows });
} catch (e) {
const servicesWithPhones = q.rows.map(s => ({ ...s, phones: extractAllPhones(s.raw_data) }));
res.json({ ok: true, services: servicesWithPhones });
} catch (e) {
console.error("Error al cargar /services/active:", e);
res.status(500).json({ ok: false });
res.status(500).json({ ok: false });
}
});
@@ -3770,9 +3808,8 @@ app.post("/services/not-found/:id", authMiddleware, async (req, res) => {
// Guardamos en la base de datos
await pool.query("UPDATE scraped_services SET raw_data=$1 WHERE id=$2", [JSON.stringify(raw), id]);
// Intentamos enviar el WhatsApp usando la plantilla
let rawPhone = raw["Teléfono"] || raw["TELEFONOS"] || raw["TELEFONO"] || "";
let cleanPhoneToMatch = extractValidPhone(rawPhone);
// Intentamos enviar el WhatsApp usando la plantilla (prioriza móvil sobre fijo)
let cleanPhoneToMatch = extractBestMobile(raw);
if (cleanPhoneToMatch.length >= 9) { // Solo intentamos enviar si hay un número válido
@@ -5245,8 +5282,7 @@ app.post("/services/:id/work-report", authMiddleware, async (req, res) => {
const operatorName = userQ.rows[0]?.full_name || "Operario";
const clientName = raw["Nombre Cliente"] || raw["CLIENTE"] || "";
const clientPhoneRaw = raw["Teléfono"] || raw["TELEFONO"] || raw["TELEFONOS"] || "";
const clientPhone = extractValidPhone(clientPhoneRaw);
const clientPhone = extractBestMobile(raw);
const insert = await pool.query(
`INSERT INTO work_reports (scraped_id, owner_id, operator_id, operator_name, client_name, client_phone, raw_text, final_text, signature_data, pdf_base64)
@@ -6081,8 +6117,7 @@ async function enviarRecordatorioAutomatizacion(client, svc, tipo, testMode) {
if (tplQ.rowCount === 0 || !tplQ.rows[0].content) return;
let text = tplQ.rows[0].content;
const rawPhone = raw["Teléfono"] || raw["TELEFONO"] || raw["TELEFONOS"] || "";
const cleanPhone = extractValidPhone(rawPhone);
const cleanPhone = extractBestMobile(raw);
const nombre = raw["Nombre Cliente"] || raw["CLIENTE"] || raw["Nombre"] || "Cliente";
const direccion = raw["Dirección"] || raw["DOMICILIO"] || "";