Files
whatsapp/modules/turnero/api/llamar_turno.php
T
2026-06-16 13:20:13 -05:00

143 lines
5.4 KiB
PHP

<?php
/**
* POST /modules/turnero/api/llamar_turno.php
* Llama el siguiente turno de una cola con el motor de prioridades.
* Requiere login + módulo turnero.
*
* Body JSON:
* area string requerido "recepcion" | "lugar"
* lugar_id int requerido si area = "lugar"
*/
require_once __DIR__ . '/_helpers.php';
requireMethod('POST');
requireTurnero();
$datos = inputJson();
$area = $datos['area'] ?? '';
$lugarId = isset($datos['lugar_id']) ? (int) $datos['lugar_id'] : null;
$deskId = isset($datos['desk_id']) ? (int) $datos['desk_id'] : null;
$turnoId = isset($datos['turno_id']) ? (int) $datos['turno_id'] : null; // llamar uno específico
// ── Validación ────────────────────────────────────────────────
if (!in_array($area, ['recepcion', 'lugar'], true)) {
jsonError('area debe ser "recepcion" o "lugar".');
}
if ($area === 'lugar' && !$lugarId) {
jsonError('lugar_id es obligatorio cuando area = "lugar".');
}
$pdo = db();
$pdo->beginTransaction();
try {
if ($area === 'recepcion') {
// Cola recepción: turnos en estado 'espera' sin filtro de lugar
$turno = siguienteTurnoEnCola('espera');
if (!$turno) {
$pdo->rollBack();
jsonOk(['turno' => null], 'Cola de recepción vacía');
}
// Actualizar estado + timestamp
$stmt = $pdo->prepare(
'UPDATE turnero_turnos
SET estado = "en_recepcion",
llamado_recepcion_at = NOW(),
inicio_recepcion_at = NOW(),
atendido_recepcion_por = ?,
recepcion_desk_id = COALESCE(?, recepcion_desk_id)
WHERE id = ? AND estado = "espera"'
);
$stmt->execute([adminId(), $deskId, $turno['id']]);
if ($stmt->rowCount() === 0) {
// Otro proceso lo tomó primero (race condition)
$pdo->rollBack();
jsonError('El turno ya fue tomado por otro operador. Intente de nuevo.', 409);
}
} else {
// Cola de un Lugar específico: turnos 'en_espera_lugar' asignados a ese lugar
if ($turnoId) {
// Llamar uno específico por id (puede ser en_espera_lugar o ya en_servicio para re-llamar)
$stmt = $pdo->prepare(
'SELECT t.*, p.codigo AS prioridad_codigo, p.nombre AS prioridad_nombre, p.color AS prioridad_color
FROM turnero_turnos t
JOIN turnero_prioridades p ON p.id = t.prioridad_id
WHERE t.id = ? AND t.estado IN ("en_espera_lugar", "en_servicio")'
);
$stmt->execute([$turnoId]);
$turno = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$turno) {
$pdo->rollBack();
jsonError('El turno no está en espera o no existe.', 404);
}
} else {
$turno = siguienteTurnoEnCola('en_espera_lugar', $lugarId);
if (!$turno) {
$pdo->rollBack();
jsonOk(['turno' => null], 'Cola del lugar vacía');
}
}
// Re-llamar: si ya está en_servicio en ESTA estación, solo actualiza llamado_at
if ($turno['estado'] === 'en_servicio' && $turno['lugar_destino_id'] == $lugarId) {
$pdo->prepare(
'UPDATE turnero_turnos SET llamado_lugar_at = NOW() WHERE id = ?'
)->execute([$turno['id']]);
$pdo->commit();
// Refrescar y retornar
$stmt = $pdo->prepare(
'SELECT t.*, p.codigo AS prioridad_codigo, p.nombre AS prioridad_nombre, p.color AS prioridad_color
FROM turnero_turnos t JOIN turnero_prioridades p ON p.id = t.prioridad_id WHERE t.id = ?'
);
$stmt->execute([$turno['id']]);
$turnoActualizado = $stmt->fetch(PDO::FETCH_ASSOC);
notificarSSE((int)$turnoActualizado['sesion_id']);
jsonOk(['turno' => $turnoActualizado], "Turno {$turnoActualizado['codigo']} re-llamado");
}
$stmt = $pdo->prepare(
'UPDATE turnero_turnos
SET estado = "en_servicio",
llamado_lugar_at = NOW(),
inicio_lugar_at = NOW(),
atendido_lugar_por= ?,
lugar_destino_id = ?
WHERE id = ? AND estado = "en_espera_lugar"'
);
$stmt->execute([adminId(), $lugarId, $turno['id']]);
if ($stmt->rowCount() === 0) {
$pdo->rollBack();
jsonError('El turno ya fue tomado por otro operador. Intente de nuevo.', 409);
}
}
// Refrescar datos del turno actualizado
$stmt = $pdo->prepare(
'SELECT t.*,
p.codigo AS prioridad_codigo,
p.nombre AS prioridad_nombre,
p.color AS prioridad_color
FROM turnero_turnos t
JOIN turnero_prioridades p ON p.id = t.prioridad_id
WHERE t.id = ?'
);
$stmt->execute([$turno['id']]);
$turnoActualizado = $stmt->fetch(PDO::FETCH_ASSOC);
$pdo->commit();
notificarSSE((int) $turnoActualizado['sesion_id']);
jsonOk(['turno' => $turnoActualizado], "Turno {$turnoActualizado['codigo']} llamado");
} catch (\Throwable $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
jsonError('Error al llamar turno: ' . $e->getMessage(), 500);
}