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