Actualizar server.js

This commit is contained in:
2026-02-21 16:31:57 +00:00
parent 49c34f01f6
commit 81c0d858c1

View File

@@ -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 });