diff --git a/modules/turnero/api/cambiar_estado.php b/modules/turnero/api/cambiar_estado.php index 2f78efb..9e891e9 100644 --- a/modules/turnero/api/cambiar_estado.php +++ b/modules/turnero/api/cambiar_estado.php @@ -64,10 +64,60 @@ try { $estadoActual = $turno['estado']; - // Estados finales no modificables + // Estados finales — solo admin (sin role_id) puede reabrir if (in_array($estadoActual, ['finalizado', 'ausente', 'cancelado'], true)) { - $pdo->rollBack(); - jsonError("El turno ya está en estado '{$estadoActual}' y no puede modificarse.", 422); + $roleId = $_SESSION['admin_user']['role_id'] ?? null; + if (!empty($roleId)) { + $pdo->rollBack(); + jsonError("El turno ya está en estado '{$estadoActual}' y no puede modificarse.", 422); + } + + $permitidosAdmin = ['en_servicio', 'en_espera_lugar', 'en_recepcion', 'espera']; + if (!in_array($nuevoEstado, $permitidosAdmin, true)) { + $pdo->rollBack(); + jsonError("Estado destino inválido para reapertura. Opciones: " . implode(', ', $permitidosAdmin), 422); + } + + $sets = ['estado = ?']; + $binds = [$nuevoEstado]; + + if ($nuevoEstado === 'en_servicio') { + $sets[] = 'fin_lugar_at = NULL'; + $sets[] = 'inicio_lugar_at = COALESCE(inicio_lugar_at, NOW())'; + $sets[] = 'atendido_lugar_por = COALESCE(atendido_lugar_por, ?)'; + $binds[] = adminId(); + } elseif ($nuevoEstado === 'en_espera_lugar') { + $sets[] = 'fin_lugar_at = NULL'; + $sets[] = 'inicio_lugar_at = NULL'; + $sets[] = 'llamado_lugar_at = NULL'; + } elseif ($nuevoEstado === 'espera') { + $sets[] = 'llamado_recepcion_at = NULL'; + $sets[] = 'inicio_recepcion_at = NULL'; + $sets[] = 'fin_recepcion_at = NULL'; + $sets[] = 'llamado_lugar_at = NULL'; + $sets[] = 'inicio_lugar_at = NULL'; + $sets[] = 'fin_lugar_at = NULL'; + $sets[] = 'atendido_recepcion_por = NULL'; + $sets[] = 'atendido_lugar_por = NULL'; + $sets[] = 'recepcion_desk_id = NULL'; + } + + $sql = 'UPDATE turnero_turnos SET ' . implode(', ', $sets) . ' WHERE id = ?'; + $binds[] = $turnoId; + $pdo->prepare($sql)->execute($binds); + $pdo->commit(); + + $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([$turnoId]); + $turnoActualizado = $stmt->fetch(PDO::FETCH_ASSOC); + + notificarSSE((int) $turnoActualizado['sesion_id']); + jsonOk(['turno' => $turnoActualizado], "Turno reabierto: estado actualizado a '{$nuevoEstado}'"); } // Verificar que la transición sea válida diff --git a/modules/turnero/views/historial.php b/modules/turnero/views/historial.php index c95696b..d54c45b 100644 --- a/modules/turnero/views/historial.php +++ b/modules/turnero/views/historial.php @@ -111,6 +111,21 @@ Layout::open('Historial de Turnos', 'fas fa-history'); .doc-pill.enviado { background:#fef9c3; color:#78350f; border:1px solid #fde68a; } .doc-pill.pendiente{ background:#f1f5f9; color:#64748b; border:1px solid #e2e8f0; } .docs-empty { font-size:.78rem; color:#94a3b8; font-style:italic; } + + /* ── Modal cambio de estado ── */ + .estado-modal-backdrop { + position:fixed; inset:0; background:rgba(0,0,0,.45); z-index:1050; + display:flex; align-items:center; justify-content:center; + } + .estado-modal { + background:#fff; border-radius:14px; padding:24px 28px; width:340px; + box-shadow:0 20px 60px rgba(0,0,0,.2); + } + .estado-modal h5 { font-size:.95rem; font-weight:700; margin-bottom:4px; } + .estado-modal .sub { font-size:.78rem; color:#64748b; margin-bottom:16px; } + .estado-modal select { width:100%; padding:8px 10px; border:1px solid #e2e8f0; + border-radius:8px; font-size:.85rem; margin-bottom:16px; } + .estado-modal .actions { display:flex; gap:8px; justify-content:flex-end; } @@ -445,12 +460,17 @@ function renderTabla(turnos) {