Files
contenedor_ibiza/src/Asignacion.php
nickpons666 76b0584667 fix: Corregir funcionalidad de reordenamiento y generación automática de turnos
- Añadir jQuery para resolver error 'jQuery is not defined'
- Corregir variable $db indefinida en reordenamiento de rotación
- Añadir método getDb() a clase Asignacion para acceso a base de datos
- Implementar procesamiento correcto de acción 'rotacion_automatica'
- Actualizar inputs ocultos al reordenar elementos visuales
- Añadir redirección para recargar datos actualizados después de guardar orden
- Mejorar manejo de mensajes de éxito/errores en generación automática
2026-01-30 22:30:55 -06:00

394 lines
15 KiB
PHP
Executable File

<?php
require_once __DIR__ . '/Database.php';
class Asignacion {
private $db;
public function __construct() {
$this->db = Database::getInstance()->getConnection();
}
public function getDb() {
return $this->db;
}
public function getAsignacionActual() {
$hoy = new DateTime();
$diaSemana = (int)$hoy->format('w');
$domingo = clone $hoy;
$domingo->modify('-' . $diaSemana . ' days');
$currentWeekStart = $domingo->format('Y-m-d');
$stmt = $this->db->prepare("
SELECT u.*, a.semana_inicio
FROM asignaciones_turnos a
JOIN users u ON a.user_id = u.id
WHERE a.semana_inicio = ?
");
$stmt->execute([$currentWeekStart]);
return $stmt->fetch();
}
public function getAsignacionPorSemana($semanaInicio) {
$stmt = $this->db->prepare("
SELECT u.*, a.semana_inicio, a.semana_fin, a.id as asignacion_id
FROM asignaciones_turnos a
JOIN users u ON a.user_id = u.id
WHERE a.semana_inicio = ?
ORDER BY a.orden_turno ASC
LIMIT 1
");
$stmt->execute([$semanaInicio]);
return $stmt->fetch();
}
public function getTodasAsignaciones() {
$stmt = $this->db->query("
SELECT u.nombre, a.*
FROM asignaciones_turnos a
JOIN users u ON a.user_id = u.id
ORDER BY a.semana_inicio DESC
LIMIT 20
");
return $stmt->fetchAll();
}
public function asignar($userId, $semanaInicio) {
$semanaFin = date('Y-m-d', strtotime('+5 days', strtotime($semanaInicio))); // Domingo a viernes
$ordenTurno = $this->getOrdenTurno($userId);
$stmt = $this->db->prepare("
INSERT INTO asignaciones_turnos (user_id, semana_inicio, semana_fin, orden_turno)
VALUES (?, ?, ?, ?)
ON DUPLICATE KEY UPDATE user_id = VALUES(user_id), semana_fin = VALUES(semana_fin), orden_turno = VALUES(orden_turno)
");
return $stmt->execute([$userId, $semanaInicio, $semanaFin, $ordenTurno]);
}
private function getOrdenTurno($userId) {
$stmt = $this->db->prepare("SELECT orden FROM rotacion_orden WHERE user_id = ? AND activo = 1");
$stmt->execute([$userId]);
$result = $stmt->fetch();
return $result ? $result['orden'] : 999;
}
public function getProximaPersona($userIdActual = null) {
$sql = "SELECT * FROM users WHERE rol = 'ayudante' AND activo = 1 ORDER BY id";
if ($userIdActual) {
$stmt = $this->db->query($sql);
$ayudantes = $stmt->fetchAll();
$encontrado = false;
foreach ($ayudantes as $a) {
if ($encontrado) return $a;
if ($a['id'] == $userIdActual) $encontrado = true;
}
return $ayudantes[0] ?? null;
}
$stmt = $this->db->query($sql);
return $stmt->fetch();
}
public function asignarMasivo($userIds, $semanaInicio, $rotacionAutomatica = false) {
$resultados = [];
$errores = [];
foreach ($userIds as $index => $userId) {
try {
$semanaFin = date('Y-m-d', strtotime('+5 days', strtotime($semanaInicio))); // Domingo a viernes
$ordenTurno = $this->getOrdenTurno($userId);
$stmt = $this->db->prepare("
INSERT INTO asignaciones_turnos (user_id, semana_inicio, semana_fin, orden_turno)
VALUES (?, ?, ?, ?)
ON DUPLICATE KEY UPDATE user_id = VALUES(user_id), semana_fin = VALUES(semana_fin), orden_turno = VALUES(orden_turno)
");
$success = $stmt->execute([$userId, $semanaInicio, $semanaFin, $ordenTurno]);
if ($success) {
$resultados[] = [
'user_id' => $userId,
'semana' => $semanaInicio,
'rotar_siguiente' => $rotacionAutomatica && $index === count($userIds) - 1
];
// Si es el último usuario y se activó rotación automática
if ($rotacionAutomatica && $index === count($userIds) - 1) {
$this->asignarSiguienteSemana($userId, $semanaInicio);
}
} else {
$errores[] = "Error al asignar usuario ID: $userId";
}
} catch (Exception $e) {
$errores[] = "Error usuario ID $userId: " . $e->getMessage();
}
}
return [
'success' => count($resultados),
'errors' => $errores,
'resultados' => $resultados
];
}
private function asignarSiguienteSemana($ultimoUserId, $semanaActual) {
$siguienteSemana = date('Y-m-d', strtotime('+1 week', strtotime($semanaActual)));
$siguientePersona = $this->getProximaPersona($ultimoUserId);
if ($siguientePersona) {
$semanaFin = date('Y-m-d', strtotime('+5 days', strtotime($siguienteSemana))); // Domingo a viernes
$ordenTurno = $this->getOrdenTurno($siguientePersona['id']);
$stmt = $this->db->prepare("
INSERT INTO asignaciones_turnos (user_id, semana_inicio, semana_fin, orden_turno)
VALUES (?, ?, ?, ?)
ON DUPLICATE KEY UPDATE user_id = VALUES(user_id), semana_fin = VALUES(semana_fin), orden_turno = VALUES(orden_turno)
");
return $stmt->execute([$siguientePersona['id'], $siguienteSemana, $semanaFin, $ordenTurno]);
}
return false;
}
public function asignarSemanasFuturasAutomaticas($semanasFuturas = 12) {
$resultados = [];
$errores = [];
// Obtener todos los ayudantes en orden de rotación
$ayudantesOrdenados = $this->getAyudantesPorOrden();
if (empty($ayudantesOrdenados)) {
return ['success' => 0, 'errors' => ['No hay ayudantes configurados'], 'resultados' => []];
}
// Encontrar la última semana asignada
$ultimaAsignacion = $this->getUltimaAsignacion();
$semanaActual = $ultimaAsignacion
? date('Y-m-d', strtotime('+1 week', strtotime($ultimaAsignacion['semana_inicio'])))
: date('Y-m-d', strtotime('last sunday', strtotime('today'))); // Empezar desde domingo
// Determinar el siguiente ayudante en el ciclo
$indiceActual = 0;
if ($ultimaAsignacion) {
$indiceActual = $this->findIndiceSiguiente($ultimaAsignacion['user_id'], $ayudantesOrdenados);
}
// Asignar semanas futuras
for ($i = 0; $i < $semanasFuturas; $i++) {
$semanaInicio = date('Y-m-d', strtotime("+$i weeks", strtotime($semanaActual)));
$semanaFin = date('Y-m-d', strtotime('+5 days', strtotime($semanaInicio))); // Domingo a viernes
// Seleccionar ayudante usando ciclo cíclico
$ayudanteIndex = ($indiceActual + $i) % count($ayudantesOrdenados);
$ayudante = $ayudantesOrdenados[$ayudanteIndex];
try {
$ordenTurno = $this->getOrdenTurno($ayudante['id']);
$stmt = $this->db->prepare("
INSERT INTO asignaciones_turnos (user_id, semana_inicio, semana_fin, orden_turno)
VALUES (?, ?, ?, ?)
ON DUPLICATE KEY UPDATE user_id = VALUES(user_id), semana_fin = VALUES(semana_fin), orden_turno = VALUES(orden_turno)
");
$success = $stmt->execute([$ayudante['id'], $semanaInicio, $semanaFin, $ordenTurno]);
if ($success) {
$resultados[] = [
'semana' => $semanaInicio,
'usuario' => $ayudante['nombre'],
'orden' => $ordenTurno
];
} else {
$errores[] = "Error al asignar semana $semanaInicio a {$ayudante['nombre']}";
}
} catch (Exception $e) {
$errores[] = "Error semana $semanaInicio: " . $e->getMessage();
}
}
return [
'success' => count($resultados),
'errors' => $errores,
'resultados' => $resultados
];
}
public function getAyudantesPorOrden() {
$stmt = $this->db->query("
SELECT u.*, ro.orden
FROM users u
LEFT JOIN rotacion_orden ro ON u.id = ro.user_id AND ro.activo = 1
WHERE u.rol = 'ayudante' AND u.activo = 1
ORDER BY COALESCE(ro.orden, 999), u.nombre
");
return $stmt->fetchAll();
}
private function getUltimaAsignacion() {
$stmt = $this->db->query("
SELECT a.*, u.nombre
FROM asignaciones_turnos a
JOIN users u ON a.user_id = u.id
WHERE a.semana_inicio <= CURDATE()
ORDER BY a.semana_inicio DESC
LIMIT 1
");
return $stmt->fetch();
}
private function findIndiceSiguiente($ultimoUserId, $ayudantesOrdenados) {
foreach ($ayudantesOrdenados as $index => $ayudante) {
if ($ayudante['id'] == $ultimoUserId) {
return ($index + 1) % count($ayudantesOrdenados);
}
}
return 0;
}
public function recalcularAsignaciones($semanasFuturas = 20) {
$resultados = [];
$errores = [];
// Obtener todos los ayudantes en orden de rotación
$ayudantesOrdenados = $this->getAyudantesPorOrden();
if (empty($ayudantesOrdenados)) {
return ['success' => 0, 'errors' => ['No hay ayudantes configurados'], 'resultados' => []];
}
// Encontrar la última asignación existente (histórica)
$stmt = $this->db->query("
SELECT a.*, u.nombre
FROM asignaciones_turnos a
JOIN users u ON a.user_id = u.id
ORDER BY a.semana_inicio DESC
LIMIT 1
");
$ultimaAsignacion = $stmt->fetch();
// Determinar desde dónde empezar a recalcular
if ($ultimaAsignacion) {
$semanaInicio = date('Y-m-d', strtotime('+1 week', strtotime($ultimaAsignacion['semana_inicio'])));
// Encontrar posición del último usuario en el nuevo orden
$indiceInicial = 0;
foreach ($ayudantesOrdenados as $index => $ayudante) {
if ($ayudante['id'] == $ultimaAsignacion['user_id']) {
$indiceInicial = ($index + 1) % count($ayudantesOrdenados);
break;
}
}
} else {
// No hay asignaciones, empezar desde el próximo domingo
$hoy = new DateTime();
$diaSemana = (int)$hoy->format('w');
$domingo = clone $hoy;
$domingo->modify('-' . $diaSemana . ' days');
$semanaInicio = $domingo->format('Y-m-d');
$indiceInicial = 0;
}
// Eliminar asignaciones futuras
$stmt = $this->db->prepare("DELETE FROM asignaciones_turnos WHERE semana_inicio >= ?");
$stmt->execute([$semanaInicio]);
// Generar nuevas asignaciones
for ($i = 0; $i < $semanasFuturas; $i++) {
$siguienteDomingo = new DateTime($semanaInicio);
$siguienteDomingo->modify("+{$i} weeks");
$fechaInicio = $siguienteDomingo->format('Y-m-d');
$fechaFin = $siguienteDomingo->modify('+5 days')->format('Y-m-d');
$ayudanteIndex = ($indiceInicial + $i) % count($ayudantesOrdenados);
$ayudante = $ayudantesOrdenados[$ayudanteIndex];
try {
$stmt = $this->db->prepare("
INSERT INTO asignaciones_turnos (user_id, semana_inicio, semana_fin, orden_turno)
VALUES (?, ?, ?, ?)
");
$success = $stmt->execute([
$ayudante['id'],
$fechaInicio,
$fechaFin,
$ayudante['orden']
]);
if ($success) {
$resultados[] = [
'semana' => $fechaInicio,
'usuario' => $ayudante['nombre'],
'orden' => $ayudante['orden']
];
} else {
$errores[] = "Error al asignar semana $fechaInicio a {$ayudante['nombre']}";
}
} catch (Exception $e) {
$errores[] = "Error semana $fechaInicio: " . $e->getMessage();
}
}
return [
'success' => count($resultados),
'errors' => $errores,
'resultados' => $resultados
];
}
public function inicializarOrdenRotacion() {
$ayudantes = $this->getAyudantesPorOrden();
$errores = [];
$actualizados = 0;
foreach ($ayudantes as $index => $ayudante) {
if ($ayudante['orden'] === null) {
try {
$stmt = $this->db->prepare("
INSERT INTO rotacion_orden (user_id, orden, activo)
VALUES (?, ?, 1)
ON DUPLICATE KEY UPDATE orden = VALUES(orden), activo = 1
");
$stmt->execute([$ayudante['id'], $index + 1]);
$actualizados++;
} catch (Exception $e) {
$errores[] = "Error con {$ayudante['nombre']}: " . $e->getMessage();
}
}
}
return [
'actualizados' => $actualizados,
'errores' => $errores
];
}
public function getAsignacionesPorRango($semanaInicio, $semanaFin) {
$stmt = $this->db->prepare("
SELECT u.*, a.semana_inicio, a.semana_fin, a.orden_turno
FROM asignaciones_turnos a
JOIN users u ON a.user_id = u.id
WHERE a.semana_inicio >= ? AND a.semana_inicio <= ?
ORDER BY a.semana_inicio, u.nombre
");
$stmt->execute([$semanaInicio, $semanaFin]);
return $stmt->fetchAll();
}
public function getTodasAsignacionesPorSemana($semanaInicio) {
$stmt = $this->db->prepare("
SELECT u.*, a.semana_inicio, a.orden_turno
FROM asignaciones_turnos a
JOIN users u ON a.user_id = u.id
WHERE a.semana_inicio = ?
ORDER BY a.orden_turno
");
$stmt->execute([$semanaInicio]);
return $stmt->fetchAll();
}
}