Primer subida completa
This commit is contained in:
384
src/Asignacion.php
Executable file
384
src/Asignacion.php
Executable file
@@ -0,0 +1,384 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/Database.php';
|
||||
|
||||
class Asignacion {
|
||||
private $db;
|
||||
|
||||
public function __construct() {
|
||||
$this->db = Database::getInstance()->getConnection();
|
||||
}
|
||||
|
||||
public function getAsignacionActual() {
|
||||
$currentWeekStart = date('Y-m-d', strtotime('monday this week'));
|
||||
$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();
|
||||
}
|
||||
}
|
||||
78
src/Auth.php
Executable file
78
src/Auth.php
Executable file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/Database.php';
|
||||
require_once __DIR__ . '/User.php';
|
||||
|
||||
$sessionPath = dirname(__DIR__) . '/sessions';
|
||||
if (!is_dir($sessionPath)) {
|
||||
mkdir($sessionPath, 0733, true);
|
||||
}
|
||||
session_save_path($sessionPath);
|
||||
session_name('contenedor_session');
|
||||
|
||||
class Auth {
|
||||
private $db;
|
||||
private $userModel;
|
||||
|
||||
public function __construct() {
|
||||
$this->db = Database::getInstance()->getConnection();
|
||||
$this->userModel = new User();
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
}
|
||||
|
||||
public function login($login, $password) {
|
||||
$user = $this->userModel->findByLogin($login);
|
||||
|
||||
if ($user && password_verify($password, $user['password'])) {
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
$_SESSION['user_name'] = $user['nombre'];
|
||||
$_SESSION['user_rol'] = $user['rol'];
|
||||
$_SESSION['logged_in'] = true;
|
||||
session_write_close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function logout() {
|
||||
session_destroy();
|
||||
$_SESSION = [];
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isLoggedIn() {
|
||||
return isset($_SESSION['logged_in']) && $_SESSION['logged_in'] === true;
|
||||
}
|
||||
|
||||
public function isAdmin() {
|
||||
return isset($_SESSION['user_rol']) && $_SESSION['user_rol'] === 'admin';
|
||||
}
|
||||
|
||||
public function getCurrentUser() {
|
||||
if (!$this->isLoggedIn()) {
|
||||
return null;
|
||||
}
|
||||
return [
|
||||
'id' => $_SESSION['user_id'],
|
||||
'nombre' => $_SESSION['user_name'],
|
||||
'rol' => $_SESSION['user_rol']
|
||||
];
|
||||
}
|
||||
|
||||
public function requireAuth() {
|
||||
if (!$this->isLoggedIn()) {
|
||||
header('Location: /login.php');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
public function requireAdmin() {
|
||||
$this->requireAuth();
|
||||
if (!$this->isAdmin()) {
|
||||
header('Location: /ayudante.php');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
50
src/Database.php
Executable file
50
src/Database.php
Executable file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/../config/config.php';
|
||||
|
||||
class Database {
|
||||
private static $instance = null;
|
||||
private $connection;
|
||||
|
||||
private function __construct() {
|
||||
$config = require __DIR__ . '/../config/config.php';
|
||||
|
||||
$hostPort = $config['db']['host'];
|
||||
$dbname = $config['db']['database'];
|
||||
$username = $config['db']['username'];
|
||||
$password = $config['db']['password'];
|
||||
|
||||
if (strpos($hostPort, ':') !== false) {
|
||||
list($host, $port) = explode(':', $hostPort);
|
||||
} else {
|
||||
$host = $hostPort;
|
||||
$port = $config['db']['port'] ?? '3306';
|
||||
}
|
||||
|
||||
try {
|
||||
$this->connection = new PDO(
|
||||
"mysql:host=$host;port=$port;dbname=$dbname;charset=utf8mb4",
|
||||
$username,
|
||||
$password,
|
||||
[
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false
|
||||
]
|
||||
);
|
||||
} catch (PDOException $e) {
|
||||
die("Error de conexión a la base de datos: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static function getInstance() {
|
||||
if (self::$instance === null) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
public function getConnection() {
|
||||
return $this->connection;
|
||||
}
|
||||
}
|
||||
46
src/DiasHorarios.php
Executable file
46
src/DiasHorarios.php
Executable file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/Database.php';
|
||||
|
||||
class DiasHorarios {
|
||||
private $db;
|
||||
|
||||
public function __construct() {
|
||||
$this->db = Database::getInstance()->getConnection();
|
||||
}
|
||||
|
||||
public function getAll() {
|
||||
$stmt = $this->db->query("SELECT * FROM dias_horarios ORDER BY FIELD(dia_semana, 'domingo', 'lunes', 'martes', 'miercoles', 'jueves', 'viernes', 'sabado')");
|
||||
return $stmt->fetchAll();
|
||||
}
|
||||
|
||||
public function getActivos() {
|
||||
$stmt = $this->db->query("SELECT * FROM dias_horarios WHERE activo = 1 ORDER BY FIELD(dia_semana, 'domingo', 'lunes', 'martes', 'miercoles', 'jueves', 'viernes', 'sabado')");
|
||||
return $stmt->fetchAll();
|
||||
}
|
||||
|
||||
public function getByDia($dia) {
|
||||
$stmt = $this->db->prepare("SELECT * FROM dias_horarios WHERE dia_semana = ?");
|
||||
$stmt->execute([$dia]);
|
||||
return $stmt->fetch();
|
||||
}
|
||||
|
||||
public function update($dia, $data) {
|
||||
$stmt = $this->db->prepare("
|
||||
UPDATE dias_horarios
|
||||
SET hora_apertura = ?, hora_cierre = ?, activo = ?
|
||||
WHERE dia_semana = ?
|
||||
");
|
||||
return $stmt->execute([
|
||||
$data['hora_apertura'],
|
||||
$data['hora_cierre'],
|
||||
$data['activo'] ?? 1,
|
||||
$dia
|
||||
]);
|
||||
}
|
||||
|
||||
public function getDiasConActividad() {
|
||||
$stmt = $this->db->query("SELECT dia_semana FROM dias_horarios WHERE activo = 1");
|
||||
return $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
}
|
||||
}
|
||||
72
src/RotacionTurnos.php
Executable file
72
src/RotacionTurnos.php
Executable file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/../src/Database.php';
|
||||
require_once __DIR__ . '/../src/User.php';
|
||||
require_once __DIR__ . '/../src/Asignacion.php';
|
||||
|
||||
class RotacionTurnos {
|
||||
private $db;
|
||||
private $userModel;
|
||||
private $asignacionModel;
|
||||
|
||||
public function __construct() {
|
||||
$this->db = Database::getInstance()->getConnection();
|
||||
$this->userModel = new User();
|
||||
$this->asignacionModel = new Asignacion();
|
||||
}
|
||||
|
||||
public function rotarSemanaActual() {
|
||||
$currentWeekStart = date('Y-m-d', strtotime('monday this week'));
|
||||
return $this->rotarSemana($currentWeekStart);
|
||||
}
|
||||
|
||||
public function rotarSemana($semanaInicio) {
|
||||
$asignacionActual = $this->asignacionModel->getAsignacionPorSemana($semanaInicio);
|
||||
|
||||
$userIdActual = $asignacionActual ? $asignacionActual['user_id'] : null;
|
||||
$proximaPersona = $this->asignacionModel->getProximaPersona($userIdActual);
|
||||
|
||||
if (!$proximaPersona) {
|
||||
return ['success' => false, 'message' => 'No hay personas disponibles para asignar'];
|
||||
}
|
||||
|
||||
$this->asignacionModel->asignar($proximaPersona['id'], $semanaInicio);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => "Turno asignado a: {$proximaPersona['nombre']}",
|
||||
'persona' => $proximaPersona
|
||||
];
|
||||
}
|
||||
|
||||
public function verificarYRotar() {
|
||||
$currentWeekStart = date('Y-m-d', strtotime('monday this week'));
|
||||
$asignacionActual = $this->asignacionModel->getAsignacionPorSemana($currentWeekStart);
|
||||
|
||||
if (!$asignacionActual) {
|
||||
return $this->rotarSemana($currentWeekStart);
|
||||
}
|
||||
|
||||
return ['success' => true, 'message' => 'Ya existe asignación para esta semana', 'already_assigned' => true];
|
||||
}
|
||||
}
|
||||
|
||||
if (php_sapi_name() === 'cli' || basename($_SERVER['SCRIPT_FILENAME']) === 'rotar.php') {
|
||||
$rotacion = new RotacionTurnos();
|
||||
$resultado = $rotacion->verificarYRotar();
|
||||
|
||||
echo "Resultado: " . $resultado['message'] . "\n";
|
||||
|
||||
if (isset($resultado['already_assigned'])) {
|
||||
echo "No se realizó rotación (ya estaba asignada)\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if ($resultado['success']) {
|
||||
echo "Rotación completada exitosamente\n";
|
||||
exit(0);
|
||||
} else {
|
||||
echo "Error: " . $resultado['message'] . "\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
128
src/User.php
Executable file
128
src/User.php
Executable file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/Database.php';
|
||||
|
||||
class User {
|
||||
private $db;
|
||||
|
||||
public function __construct() {
|
||||
$this->db = Database::getInstance()->getConnection();
|
||||
}
|
||||
|
||||
public function getAll($includeInactive = false) {
|
||||
$sql = "SELECT * FROM users";
|
||||
if (!$includeInactive) {
|
||||
$sql .= " WHERE activo = 1";
|
||||
}
|
||||
$sql .= " ORDER BY nombre";
|
||||
$stmt = $this->db->query($sql);
|
||||
return $stmt->fetchAll();
|
||||
}
|
||||
|
||||
public function getById($id) {
|
||||
$stmt = $this->db->prepare("SELECT * FROM users WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
return $stmt->fetch();
|
||||
}
|
||||
|
||||
public function getByEmail($email) {
|
||||
$stmt = $this->db->prepare("SELECT * FROM users WHERE email = ?");
|
||||
$stmt->execute([$email]);
|
||||
return $stmt->fetch();
|
||||
}
|
||||
|
||||
public function findByLogin($login) {
|
||||
$login = trim($login);
|
||||
$stmt = $this->db->prepare("SELECT * FROM users WHERE (email = ? OR username = ?) AND activo = 1");
|
||||
$stmt->execute([$login, $login]);
|
||||
return $stmt->fetch();
|
||||
}
|
||||
|
||||
public function getByUsername($username) {
|
||||
$stmt = $this->db->prepare("SELECT * FROM users WHERE username = ?");
|
||||
$stmt->execute([$username]);
|
||||
return $stmt->fetch();
|
||||
}
|
||||
|
||||
public function usernameExists($username, $excludeId = null) {
|
||||
$sql = "SELECT COUNT(*) as total FROM users WHERE username = ?";
|
||||
$params = [$username];
|
||||
if ($excludeId) {
|
||||
$sql .= " AND id != ?";
|
||||
$params[] = $excludeId;
|
||||
}
|
||||
$stmt = $this->db->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
return $stmt->fetch()['total'] > 0;
|
||||
}
|
||||
|
||||
public function create($data) {
|
||||
$username = !empty($data['username']) ? $data['username'] : strtolower(preg_replace('/[^a-zA-Z0-9]/', '', $data['nombre']));
|
||||
$stmt = $this->db->prepare("
|
||||
INSERT INTO users (username, nombre, email, password, rol)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
");
|
||||
$password = password_hash($data['password'], PASSWORD_DEFAULT);
|
||||
$stmt->execute([
|
||||
$username,
|
||||
$data['nombre'],
|
||||
$data['email'],
|
||||
$password,
|
||||
$data['rol'] ?? 'ayudante'
|
||||
]);
|
||||
|
||||
$userId = $this->db->lastInsertId();
|
||||
|
||||
// Si es un ayudante, agregar automáticamente a rotacion_orden
|
||||
if (isset($data['rol']) && $data['rol'] === 'ayudante') {
|
||||
$this->agregarARotacion($userId);
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
|
||||
private function agregarARotacion($userId) {
|
||||
// Obtener el siguiente orden disponible
|
||||
$stmt = $this->db->query("SELECT MAX(orden) as max_orden FROM rotacion_orden WHERE activo = 1");
|
||||
$result = $stmt->fetch();
|
||||
$nuevoOrden = ($result['max_orden'] ?? 0) + 1;
|
||||
|
||||
// Insertar en rotacion_orden
|
||||
$stmt = $this->db->prepare("
|
||||
INSERT INTO rotacion_orden (user_id, orden, activo)
|
||||
VALUES (?, ?, 1)
|
||||
");
|
||||
$stmt->execute([$userId, $nuevoOrden]);
|
||||
}
|
||||
|
||||
public function update($id, $data) {
|
||||
$sql = "UPDATE users SET username = ?, nombre = ?, email = ?, rol = ?";
|
||||
$params = [$data['username'] ?? '', $data['nombre'], $data['email'], $data['rol']];
|
||||
|
||||
if (!empty($data['password'])) {
|
||||
$sql .= ", password = ?";
|
||||
$params[] = password_hash($data['password'], PASSWORD_DEFAULT);
|
||||
}
|
||||
|
||||
$sql .= " WHERE id = ?";
|
||||
$params[] = $id;
|
||||
|
||||
$stmt = $this->db->prepare($sql);
|
||||
return $stmt->execute($params);
|
||||
}
|
||||
|
||||
public function deactivate($id) {
|
||||
$stmt = $this->db->prepare("UPDATE users SET activo = 0 WHERE id = ?");
|
||||
return $stmt->execute([$id]);
|
||||
}
|
||||
|
||||
public function activate($id) {
|
||||
$stmt = $this->db->prepare("UPDATE users SET activo = 1 WHERE id = ?");
|
||||
return $stmt->execute([$id]);
|
||||
}
|
||||
|
||||
public function getAyudantesActivos() {
|
||||
$stmt = $this->db->query("SELECT * FROM users WHERE rol = 'ayudante' AND activo = 1 ORDER BY nombre");
|
||||
return $stmt->fetchAll();
|
||||
}
|
||||
}
|
||||
4
src/layout/footer.php
Executable file
4
src/layout/footer.php
Executable file
@@ -0,0 +1,4 @@
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
51
src/layout/header.php
Executable file
51
src/layout/header.php
Executable file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
$currentPage = $currentPage ?? '';
|
||||
$auth = require_once __DIR__ . '/Auth.php';
|
||||
$user = $auth->getCurrentUser() ?? [];
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?= $pageTitle ?? 'Panel' ?> - Contenedor Ibiza</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="/admin/index.php">Contenedor Ibiza</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav me-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= $currentPage === 'dashboard' ? 'active' : '' ?>" href="/admin/index.php">Dashboard</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= $currentPage === 'usuarios' ? 'active' : '' ?>" href="/admin/usuarios.php">Usuarios</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= $currentPage === 'horarios' ? 'active' : '' ?>" href="/admin/horarios.php">Horarios</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= $currentPage === 'asignaciones' ? 'active' : '' ?>" href="/admin/asignaciones.php">Asignaciones</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown">
|
||||
<?= htmlspecialchars($user['nombre'] ?? 'Usuario') ?>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><span class="dropdown-item-text"><strong>Rol:</strong> <?= htmlspecialchars(ucfirst($user['rol'] ?? '')) ?></span></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" href="/logout.php">Cerrar Sesión</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container mt-4">
|
||||
Reference in New Issue
Block a user