Actualizar server.js
This commit is contained in:
72
server.js
72
server.js
@@ -618,7 +618,7 @@ app.get("/whatsapp/status", authMiddleware, (req, res, next) => requirePlan(req,
|
||||
// 🧠 MOTOR INTELIGENTE DE AGENDAMIENTO Y AGENDA ADMIN
|
||||
// ==========================================
|
||||
|
||||
// 1. Obtener huecos disponibles inteligentes (Bloqueando por duración)
|
||||
// 1. Obtener huecos disponibles inteligentes (Bloqueando por duración y GREMIO)
|
||||
app.get("/public/portal/:token/slots", async (req, res) => {
|
||||
try {
|
||||
const { token } = req.params;
|
||||
@@ -636,14 +636,17 @@ app.get("/public/portal/:token/slots", async (req, res) => {
|
||||
|
||||
const raw = service.raw_data || {};
|
||||
const targetZone = (raw["Población"] || raw["POBLACION-PROVINCIA"] || raw["Código Postal"] || "").toLowerCase().trim();
|
||||
const targetGuildId = raw["guild_id"]; // Extraemos el gremio del servicio actual
|
||||
|
||||
// Extraemos la agenda respetando la duración (duration_minutes)
|
||||
// Extraemos la agenda respetando la duración (duration_minutes) y el gremio bloqueado
|
||||
const agendaQ = await pool.query(`
|
||||
SELECT raw_data->>'scheduled_date' as date,
|
||||
raw_data->>'scheduled_time' as time,
|
||||
raw_data->>'duration_minutes' as duration,
|
||||
raw_data->>'Población' as poblacion,
|
||||
raw_data->>'Código Postal' as cp
|
||||
raw_data->>'Código Postal' as cp,
|
||||
provider,
|
||||
raw_data->>'blocked_guild_id' as blocked_guild_id
|
||||
FROM scraped_services
|
||||
WHERE assigned_to = $1
|
||||
AND raw_data->>'scheduled_date' IS NOT NULL
|
||||
@@ -652,6 +655,13 @@ app.get("/public/portal/:token/slots", async (req, res) => {
|
||||
|
||||
const agendaMap = {};
|
||||
agendaQ.rows.forEach(row => {
|
||||
// INTELIGENCIA DE GREMIOS:
|
||||
// Si es un bloqueo de agenda que tiene un gremio específico, y NO coincide con el gremio del servicio actual...
|
||||
// ¡Lo ignoramos! (El hueco sigue libre para este servicio)
|
||||
if (row.provider === 'SYSTEM_BLOCK' && row.blocked_guild_id && String(row.blocked_guild_id) !== String(targetGuildId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!agendaMap[row.date]) agendaMap[row.date] = { times: [], zone: (row.poblacion || row.cp || "").toLowerCase().trim() };
|
||||
|
||||
// Calculamos cuántas horas bloquea este servicio según su duración
|
||||
@@ -704,7 +714,7 @@ app.get("/public/portal/:token/slots", async (req, res) => {
|
||||
d.setDate(d.getDate() + 1);
|
||||
}
|
||||
res.json({ ok: true, days: availableDays });
|
||||
} catch (e) { res.status(500).json({ ok: false }); }
|
||||
} catch (e) { console.error("Error Slots:", e); res.status(500).json({ ok: false }); }
|
||||
});
|
||||
|
||||
// 2. Guardar la cita como "SOLICITUD PENDIENTE"
|
||||
@@ -820,6 +830,60 @@ app.post("/agenda/requests/:id/reject", authMiddleware, async (req, res) => {
|
||||
} catch (e) { res.status(500).json({ok: false}); }
|
||||
});
|
||||
|
||||
|
||||
// 6. RUTAS DE BLOQUEOS (AGENDA) CON SOPORTE PARA GREMIOS
|
||||
app.post("/agenda/blocks", authMiddleware, async (req, res) => {
|
||||
try {
|
||||
const { worker_id, date, time, duration, reason, guild_id, guild_name } = req.body;
|
||||
|
||||
const raw = {
|
||||
"Nombre Cliente": "BLOQUEO DE AGENDA",
|
||||
"Descripción": reason,
|
||||
scheduled_date: date,
|
||||
scheduled_time: time,
|
||||
duration_minutes: duration,
|
||||
blocked_guild_id: guild_id || null, // Guardamos el gremio
|
||||
blocked_guild_name: guild_name || null
|
||||
};
|
||||
|
||||
await pool.query(`
|
||||
INSERT INTO scraped_services (owner_id, provider, service_ref, status, assigned_to, raw_data)
|
||||
VALUES ($1, 'SYSTEM_BLOCK', 'BLOCK-' || extract(epoch from now())::int, 'pending', $2, $3)
|
||||
`, [req.user.accountId, worker_id, JSON.stringify(raw)]);
|
||||
|
||||
res.json({ ok: true });
|
||||
} catch(e) { res.status(500).json({ ok: false }); }
|
||||
});
|
||||
|
||||
app.get("/agenda/blocks", authMiddleware, async (req, res) => {
|
||||
try {
|
||||
const q = await pool.query(`
|
||||
SELECT s.id, u.full_name as worker_name,
|
||||
s.raw_data->>'scheduled_date' as date,
|
||||
s.raw_data->>'scheduled_time' as time,
|
||||
s.raw_data->>'duration_minutes' as duration,
|
||||
s.raw_data->>'Descripción' as reason,
|
||||
s.raw_data->>'blocked_guild_name' as guild_name
|
||||
FROM scraped_services s
|
||||
JOIN users u ON s.assigned_to = u.id
|
||||
WHERE s.owner_id = $1 AND s.provider = 'SYSTEM_BLOCK'
|
||||
AND s.raw_data->>'scheduled_date' >= CURRENT_DATE::text
|
||||
ORDER BY s.raw_data->>'scheduled_date' ASC
|
||||
`, [req.user.accountId]);
|
||||
|
||||
res.json({ ok: true, blocks: q.rows });
|
||||
} catch(e) { res.status(500).json({ ok: false }); }
|
||||
});
|
||||
|
||||
app.delete("/agenda/blocks/:id", authMiddleware, async (req, res) => {
|
||||
try {
|
||||
await pool.query("DELETE FROM scraped_services WHERE id=$1 AND owner_id=$2 AND provider='SYSTEM_BLOCK'", [req.params.id, req.user.accountId]);
|
||||
res.json({ ok: true });
|
||||
} catch(e) { res.status(500).json({ ok: false }); }
|
||||
});
|
||||
|
||||
|
||||
|
||||
// ==========================================
|
||||
// ⚙️ MOTOR AUTOMÁTICO DE WHATSAPP
|
||||
// ==========================================
|
||||
|
||||
Reference in New Issue
Block a user