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, +, -)
|
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("0034")) str = str.slice(4);
|
||||||
if (str.startsWith("34") && str.length >= 11) str = str.slice(2);
|
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);
|
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)
|
// 2. Normaliza SIEMPRE a Formato Internacional para la Base de Datos (+34600123456)
|
||||||
function normalizePhone(phone) {
|
function normalizePhone(phone) {
|
||||||
const clean = extractValidPhone(phone);
|
const clean = extractValidPhone(phone);
|
||||||
@@ -1409,8 +1449,7 @@ async function triggerHomeServeRobot(ownerId, serviceId, eventType) {
|
|||||||
// 3. Traducir variables personalizadas
|
// 3. Traducir variables personalizadas
|
||||||
let text = rule.obs || "";
|
let text = rule.obs || "";
|
||||||
const clientName = raw["Nombre Cliente"] || raw["CLIENTE"] || "Cliente";
|
const clientName = raw["Nombre Cliente"] || raw["CLIENTE"] || "Cliente";
|
||||||
let clientPhone = raw["Teléfono"] || raw["TELEFONO"] || raw["TELEFONOS"] || "";
|
let clientPhone = extractBestMobile(raw);
|
||||||
clientPhone = extractValidPhone(clientPhone);
|
|
||||||
|
|
||||||
// Formateo humano de la fecha para el texto de observaciones
|
// Formateo humano de la fecha para el texto de observaciones
|
||||||
let textoFechaCita = "hoy";
|
let textoFechaCita = "hoy";
|
||||||
@@ -1503,8 +1542,7 @@ async function triggerMultiRobot(ownerId, serviceId, eventType) {
|
|||||||
|
|
||||||
let text = rule.obs || "";
|
let text = rule.obs || "";
|
||||||
const clientName = raw["Nombre Cliente"] || raw["CLIENTE"] || "Cliente";
|
const clientName = raw["Nombre Cliente"] || raw["CLIENTE"] || "Cliente";
|
||||||
let clientPhone = raw["Teléfono"] || raw["TELEFONO"] || raw["TELEFONOS"] || "";
|
let clientPhone = extractBestMobile(raw);
|
||||||
clientPhone = extractValidPhone(clientPhone);
|
|
||||||
|
|
||||||
let textoFechaCita = "hoy";
|
let textoFechaCita = "hoy";
|
||||||
if (raw.scheduled_date) {
|
if (raw.scheduled_date) {
|
||||||
@@ -3119,9 +3157,8 @@ async function triggerWhatsAppEvent(ownerId, serviceId, eventType) {
|
|||||||
const s = svcQ.rows[0];
|
const s = svcQ.rows[0];
|
||||||
const raw = s.raw_data || {};
|
const raw = s.raw_data || {};
|
||||||
|
|
||||||
// 1. EXTRAER TELÉFONO DEL CLIENTE LIMPIO
|
// 1. EXTRAER TELÉFONO DEL CLIENTE LIMPIO (prioriza móvil sobre fijo)
|
||||||
let rawPhone = raw["Teléfono"] || raw["TELEFONO"] || raw["TELEFONOS"] || "";
|
let cleanPhoneToMatch = extractBestMobile(raw);
|
||||||
let cleanPhoneToMatch = extractValidPhone(rawPhone);
|
|
||||||
if (cleanPhoneToMatch.length < 9) return false; // Si no hay teléfono válido, cancelamos
|
if (cleanPhoneToMatch.length < 9) return false; // Si no hay teléfono válido, cancelamos
|
||||||
|
|
||||||
const finalPhoneToSend = "34" + cleanPhoneToMatch;
|
const finalPhoneToSend = "34" + cleanPhoneToMatch;
|
||||||
@@ -3608,12 +3645,13 @@ app.get("/services/active", authMiddleware, async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
query += ` ORDER BY s.created_at DESC`;
|
query += ` ORDER BY s.created_at DESC`;
|
||||||
|
|
||||||
const q = await pool.query(query, params);
|
const q = await pool.query(query, params);
|
||||||
res.json({ ok: true, services: q.rows });
|
const servicesWithPhones = q.rows.map(s => ({ ...s, phones: extractAllPhones(s.raw_data) }));
|
||||||
} catch (e) {
|
res.json({ ok: true, services: servicesWithPhones });
|
||||||
|
} catch (e) {
|
||||||
console.error("Error al cargar /services/active:", 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
|
// Guardamos en la base de datos
|
||||||
await pool.query("UPDATE scraped_services SET raw_data=$1 WHERE id=$2", [JSON.stringify(raw), id]);
|
await pool.query("UPDATE scraped_services SET raw_data=$1 WHERE id=$2", [JSON.stringify(raw), id]);
|
||||||
|
|
||||||
// Intentamos enviar el WhatsApp usando la plantilla
|
// Intentamos enviar el WhatsApp usando la plantilla (prioriza móvil sobre fijo)
|
||||||
let rawPhone = raw["Teléfono"] || raw["TELEFONOS"] || raw["TELEFONO"] || "";
|
let cleanPhoneToMatch = extractBestMobile(raw);
|
||||||
let cleanPhoneToMatch = extractValidPhone(rawPhone);
|
|
||||||
|
|
||||||
if (cleanPhoneToMatch.length >= 9) { // Solo intentamos enviar si hay un número válido
|
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 operatorName = userQ.rows[0]?.full_name || "Operario";
|
||||||
|
|
||||||
const clientName = raw["Nombre Cliente"] || raw["CLIENTE"] || "";
|
const clientName = raw["Nombre Cliente"] || raw["CLIENTE"] || "";
|
||||||
const clientPhoneRaw = raw["Teléfono"] || raw["TELEFONO"] || raw["TELEFONOS"] || "";
|
const clientPhone = extractBestMobile(raw);
|
||||||
const clientPhone = extractValidPhone(clientPhoneRaw);
|
|
||||||
|
|
||||||
const insert = await pool.query(
|
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)
|
`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;
|
if (tplQ.rowCount === 0 || !tplQ.rows[0].content) return;
|
||||||
let text = tplQ.rows[0].content;
|
let text = tplQ.rows[0].content;
|
||||||
|
|
||||||
const rawPhone = raw["Teléfono"] || raw["TELEFONO"] || raw["TELEFONOS"] || "";
|
const cleanPhone = extractBestMobile(raw);
|
||||||
const cleanPhone = extractValidPhone(rawPhone);
|
|
||||||
|
|
||||||
const nombre = raw["Nombre Cliente"] || raw["CLIENTE"] || raw["Nombre"] || "Cliente";
|
const nombre = raw["Nombre Cliente"] || raw["CLIENTE"] || raw["Nombre"] || "Cliente";
|
||||||
const direccion = raw["Dirección"] || raw["DOMICILIO"] || "";
|
const direccion = raw["Dirección"] || raw["DOMICILIO"] || "";
|
||||||
|
|||||||
Reference in New Issue
Block a user