Prioriza móviles sobre fijos al elegir teléfono del cliente; expone phones[] en /services/active
This commit is contained in:
75
server.js
75
server.js
@@ -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"] || "";
|
||||
|
||||
Reference in New Issue
Block a user