".mb_strtoupper($materia_rs["materia_nombre"])." del día ".$fecha_falta." a las ".$hor." hrs. se propone reponer el ".$fecha_new." a las ".$hora." hrs.";
+ $texto .= "
".mb_strtoupper($materia_rs["materia_nombre"])." del día ".$fecha_falta." a las ".$hora." hrs. se propone reponer el ".$fecha_nueva." a las ".$hora_nueva." hrs.";
+ $texto .= "
El correo se envió atutomáticamente, no debes hacer nada más.
";
+$asunto="Prueba";
+Mailer::enviarCorreo($to, $asunto, $texto, true);
+echo "Enviado!".date("H:i:s");
+
+?>
diff --git a/action/force_session.php b/action/force_session.php
new file mode 100644
index 0000000..781fa82
--- /dev/null
+++ b/action/force_session.php
@@ -0,0 +1,37 @@
+ $usuario]);
+// die(json_encode($user));
+
+$facultad = [
+ "facultad_id" => $user["facultad"],
+ "facultad" => $user["facultad_nombre"]
+];
+
+$rol = [
+ "rol_id" => $user["rol"],
+ "rol" => $user["titulo"]
+];
+
+$admin = false;
+
+$periodo = $user["periodo"];
+
+$user = [
+ "id" => $user["id"],
+ "nombre" => $user["username"]
+];
+
+$user = new Login($user, $facultad, $rol, $admin, $periodo);
+if (isset($_SESSION))
+ session_start();
+$_SESSION['user'] = serialize($user);
+
+header("Location: ../main.php");
+exit;
\ No newline at end of file
diff --git a/action/horario_profesor.php b/action/horario_profesor.php
new file mode 100644
index 0000000..bea48a6
--- /dev/null
+++ b/action/horario_profesor.php
@@ -0,0 +1,46 @@
+ 'No se ha iniciado sesión']);
+ exit();
+}
+$user = Login::get_user();
+
+try {
+ switch ($_SERVER['REQUEST_METHOD']) {
+ case 'GET':
+ $profesor_id = $db
+ ->where('profesor_clave', $_GET['profesor'])
+ ->getOne('profesor', 'profesor_id');
+ // Fetch all puestos
+ $horarios = $db->query(<<periodo_id, $profesor_id['profesor_id']]
+ );
+
+ echo json_encode($horarios);
+ break;
+ default:
+ header('HTTP/1.1 405 Method Not Allowed');
+ echo json_encode(['error' => 'Método no permitido']);
+ break;
+ }
+} catch (PDOException $e) {
+ echo json_encode([
+ 'error' => $e->getMessage(),
+ 'query' => $db->getLastQuery(),
+ 'exception' => $e->getTraceAsString()
+ ]);
+}
\ No newline at end of file
diff --git a/action/justificar.php b/action/justificar.php
new file mode 100644
index 0000000..4b9308b
--- /dev/null
+++ b/action/justificar.php
@@ -0,0 +1,76 @@
+ 'No se ha iniciado sesión']);
+ exit();
+}
+$user = Login::get_user();
+
+try {
+ switch ($_SERVER['REQUEST_METHOD']) {
+ case 'POST':
+ // check parameters
+
+ $raw = file_get_contents('php://input');
+ $post_data = json_decode($raw, true);
+
+ $data = $db->querySingle(
+ 'WITH HORARIOS AS (
+ SELECT *
+ FROM horario
+ JOIN horario_profesor USING (horario_id)
+ WHERE horario.periodo_id = :periodo_id
+ )
+ INSERT INTO registro (profesor_id, horario_id, registro_fecha_ideal, registro_justificada, justificador_id, registro_fecha_justificacion, justificacion)
+ VALUES (:profesor_id, :horario_id, :registro_fecha_ideal, :registro_justificada, :justificador_id, NOW(), :justificacion)
+ ON CONFLICT (profesor_id, horario_id, registro_fecha_ideal)
+ DO UPDATE SET registro_justificada = :registro_justificada, justificador_id = :justificador_id, registro_fecha_justificacion = NOW(), justificacion = :justificacion
+ RETURNING *',
+ array(
+ 'periodo_id' => $user->periodo_id,
+ 'profesor_id' => $post_data['profesor_id'],
+ 'horario_id' => $post_data['horario_id'],
+ 'registro_fecha_ideal' => $post_data['registro_fecha_ideal'],
+ 'registro_justificada' => $post_data['registro_justificada'],
+ 'justificador_id' => $user->user['id'],
+ 'justificacion' => empty($post_data['justificacion']) ? null : $post_data['justificacion'],
+ )
+ );
+
+
+ $data_justificador = $db->querySingle(
+ "SELECT justificador.usuario_nombre as justificador_nombre,
+ justificador.usuario_clave as justificador_clave,
+ facultad.facultad_nombre as justificador_facultad, rol.rol_titulo as justificador_rol
+
+ FROM USUARIO JUSTIFICADOR
+ JOIN ROL on ROL.rol_id = justificador.rol_id
+ LEFT JOIN facultad on facultad.facultad_id = justificador.facultad_id
+ where justificador.usuario_id = :justificador_id",
+ array(
+ 'justificador_id' => $user->user['id'],
+ )
+ );
+ // exit('exit');
+
+ echo json_encode(array_merge($data, $data_justificador), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+ break;
+
+ default:
+ header('HTTP/1.1 405 Method Not Allowed');
+ echo json_encode(['error' => 'Método no permitido']);
+ }
+} catch (PDOException $e) {
+ echo json_encode([
+ 'error' => $e->getMessage(),
+ 'query' => $db->getLastQuery(),
+ 'exception' => $e->getTraceAsString()
+ ]);
+} catch (Exception $e) {
+ echo json_encode([
+ 'error' => $e->getMessage(),
+ 'exception' => $e->getTraceAsString()
+ ]);
+}
\ No newline at end of file
diff --git a/action/mail_javier.php b/action/mail_javier.php
new file mode 100644
index 0000000..9433b9b
--- /dev/null
+++ b/action/mail_javier.php
@@ -0,0 +1,7 @@
+ 'No se ha iniciado sesión']);
+ exit();
+}
+$user = Login::get_user();
+
+try {
+ switch ($_SERVER['REQUEST_METHOD']) {
+ case 'GET':
+ // Fetch all puestos
+ $nivel = $db->get('nivel');
+ echo json_encode($nivel);
+ break;
+ default:
+ header('HTTP/1.1 405 Method Not Allowed');
+ echo json_encode(['error' => 'Método no permitido']);
+ break;
+ }
+} catch (PDOException $e) {
+ echo json_encode([
+ 'error' => $e->getMessage(),
+ 'query' => $db->getLastQuery(),
+ 'exception' => $e->getTraceAsString()
+ ]);
+}
\ No newline at end of file
diff --git a/action/periodo_datos.php b/action/periodo_datos.php
new file mode 100644
index 0000000..7da8339
--- /dev/null
+++ b/action/periodo_datos.php
@@ -0,0 +1,44 @@
+
+#input $_GET['id_espacio_sgu']
+#output rutas: [ ...ruta, salones: [{...salon}] ]
+header('Content-Type: application/json charset=utf-8');
+ini_set('display_errors', 1);
+ini_set('display_startup_errors', 1);
+error_reporting(E_ALL);
+
+$ruta = "../";
+require_once $ruta . "class/c_login.php";
+
+if (!isset($_SESSION['user'])) {
+ http_response_code(401);
+ die(json_encode(['error' => 'unauthorized']));
+}
+$user = unserialize($_SESSION['user']);
+// check method
+if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
+ http_response_code(405);
+ die(json_encode(['error' => 'method not allowed']));
+}
+
+const JSON_OPTIONS = JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_PARTIAL_OUTPUT_ON_ERROR;
+try {
+ $data = $db->querySingle("SELECT *, LEAST(periodo_fecha_fin, CURRENT_DATE) as fecha_final FROM periodo WHERE periodo_id = ?", array($user->periodo_id));
+ $last_query = [
+ 'query' => $db->getLastQuery(),
+ ];
+
+ echo json_encode($data, JSON_OPTIONS);
+} catch (PDOException $th) {
+ http_response_code(500);
+ echo json_encode([
+ 'error' => $th->getMessage(),
+ 'query' => $db->getLastQuery(),
+ ], JSON_OPTIONS);
+ exit;
+} catch (Exception $th) {
+ http_response_code(500);
+ echo json_encode([
+ 'error' => $th->getMessage(),
+ ], JSON_OPTIONS);
+ exit;
+}
\ No newline at end of file
diff --git a/action/periodos.php b/action/periodos.php
new file mode 100644
index 0000000..bc1d98f
--- /dev/null
+++ b/action/periodos.php
@@ -0,0 +1,204 @@
+ 'No se ha iniciado sesión']);
+ exit();
+}
+$user = Login::get_user();
+
+try {
+ switch ($_SERVER['REQUEST_METHOD']) {
+ case 'GET':
+ // Fetch all puestos
+ $periodo_id = $user->periodo_id;
+ if (is_null($user->facultad['facultad_id'])) {
+ $periodos = $db
+ //->where('CURRENT_DATE BETWEEN periodo_fecha_inicio AND periodo_fecha_fin')
+ ->join('nivel', 'nivel.nivel_id = periodo.nivel_id')
+ ->orderBy('periodo_id')
+ ->get('periodo', null, 'periodo.*, nivel_nombre as nivel');
+ } else {
+ $periodos = $db->query(
+ "SELECT DISTINCT periodo.*, nivel_nombre as nivel FROM periodo
+ JOIN horario_view USING (periodo_id)
+ JOIN nivel ON nivel.nivel_id = periodo.nivel_id
+ WHERE /*CURRENT_DATE BETWEEN periodo.periodo_fecha_inicio AND periodo.periodo_fecha_fin
+ AND */facultad_id = :facultad_id
+ ORDER BY periodo_id
+ ",
+ ['facultad_id' => $user->facultad['facultad_id']]
+ );
+ }
+ echo json_encode($periodos);
+ break;
+
+ case 'PUT':
+ // Update nivel_id of a periodo
+ $raw = file_get_contents('php://input');
+ $data = json_decode($raw, true);
+
+ if (!isset($data['action'])) {
+ header('HTTP/1.1 400 Bad Request');
+ echo json_encode(['error' => 'Falta la acción a realizar']);
+ exit();
+ }
+
+ switch ($data['action']) {
+ case 'changeNivel':
+ if (!isset($data['periodo_id'], $data['nivel_id'])) {
+ header('HTTP/1.1 400 Bad Request');
+ echo json_encode(['error' => 'Falta el id del periodo o el nivel']);
+ exit();
+ }
+
+ $periodo_id = $data['periodo_id'];
+ $nivel_id = $data['nivel_id'];
+ $db->where('periodo_id', $periodo_id)->update('periodo', ['nivel_id' => $nivel_id]);
+
+ $periodo_nombre = $db->where('periodo_id', $periodo_id)->getOne('periodo', 'periodo_nombre')['periodo_nombre'];
+ $nivel_nombre = $db->where('nivel_id', $nivel_id)->getOne('nivel', 'nivel_nombre')['nivel_nombre'];
+
+ echo json_encode([
+ 'success' =>
+ "El nivel del periodo $periodo_nombre ha sido cambiado a $nivel_nombre"
+ ]);
+ break;
+
+ case 'changeFechaInicio':
+ if (!isset($data['periodo_id'], $data['periodo_fecha_inicio'])) {
+ header('HTTP/1.1 400 Bad Request');
+ echo json_encode(['error' => 'Falta el id del periodo o la fecha de inicio']);
+ exit();
+ }
+
+ $periodo_id = $data['periodo_id'];
+ $periodo_fecha_inicio = $data['periodo_fecha_inicio'];
+ $db->where('periodo_id', $periodo_id)->update('periodo', ['periodo_fecha_inicio' => $periodo_fecha_inicio]);
+
+ $periodo_nombre = $db->where('periodo_id', $periodo_id)->getOne('periodo', 'periodo_nombre')['periodo_nombre'];
+
+ echo json_encode([
+ 'success' =>
+ "La fecha de inicio del periodo $periodo_nombre ha sido cambiada a $periodo_fecha_inicio"
+ ]);
+ break;
+
+ case 'changeFechaFin':
+ if (!isset($data['periodo_id'], $data['periodo_fecha_fin'])) {
+ header('HTTP/1.1 400 Bad Request');
+ echo json_encode(['error' => 'Falta el id del periodo o la fecha de fin']);
+ exit();
+ }
+
+ $periodo_id = $data['periodo_id'];
+ $periodo_fecha_fin = $data['periodo_fecha_fin'];
+ $db->where('periodo_id', $periodo_id)->update('periodo', ['periodo_fecha_fin' => $periodo_fecha_fin]);
+
+ $periodo_nombre = $db->where('periodo_id', $periodo_id)->getOne('periodo', 'periodo_nombre')['periodo_nombre'];
+
+ echo json_encode([
+ 'success' =>
+ "La fecha de fin del periodo $periodo_nombre ha sido cambiada a $periodo_fecha_fin"
+ ]);
+ break;
+
+ case 'updatePeriodo':
+ if (!isset($data['periodo_id'], $data['periodo_nombre'], $data['id_periodo_sgu'], $data['periodo_clave'])) {
+ header('HTTP/1.1 400 Bad Request');
+ echo json_encode(['error' => 'Faltan datos para actualizar el periodo']);
+ exit();
+ }
+
+ $periodo_id = $data['periodo_id'];
+
+ $db->where('periodo_id', $periodo_id)->update('periodo', array_filter($data, fn($key) => in_array($key, [
+ 'periodo_nombre',
+ 'id_periodo_sgu',
+ 'periodo_clave',
+ ]), ARRAY_FILTER_USE_KEY));
+
+ $periodo_nombre = $db->where('periodo_id', $periodo_id)->getOne('periodo', 'periodo_nombre')['periodo_nombre'];
+
+ echo json_encode([
+ 'success' =>
+ "El periodo $periodo_nombre ha sido actualizado"
+ ]);
+ break;
+
+ default:
+ header('HTTP/1.1 400 Bad Request');
+ echo json_encode(['error' => 'Acción no válida']);
+ exit();
+ }
+
+ break;
+ case 'POST':
+ $raw = file_get_contents('php://input');
+ $data = json_decode($raw, true);
+
+ if (!isset($data['periodo_nombre'], $data['nivel_id'], $data['periodo_fecha_inicio'], $data['periodo_fecha_fin'])) {
+ header('HTTP/1.1 400 Bad Request');
+ echo json_encode(['error' => 'Faltan datos para crear el periodo']);
+ exit();
+ }
+
+ $newPeriodo = $db->insert(
+ 'periodo',
+ array_filter($data, fn($key) => in_array($key, [
+ 'periodo_nombre',
+ 'nivel_id',
+ 'periodo_fecha_inicio',
+ 'periodo_fecha_fin',
+ 'periodo_clave',
+ 'id_periodo_sgu',
+ ]), ARRAY_FILTER_USE_KEY)
+ );
+
+ echo json_encode([
+ 'success' => true,
+ 'message' => 'El periodo ha sido creado',
+ 'periodo' => $newPeriodo
+ ]);
+ break;
+
+ case 'DELETE':
+ // Delete a periodo
+ $raw = file_get_contents('php://input');
+ $data = json_decode($raw, true);
+
+ if (!isset($data['periodo_id'])) {
+ header('HTTP/1.1 400 Bad Request');
+ echo json_encode(['error' => 'Falta el id del periodo']);
+ exit();
+ }
+
+ $periodo_id = $data['periodo_id'];
+ $periodo_nombre = $db->where('periodo_id', $periodo_id)->getOne('periodo', 'periodo_nombre')['periodo_nombre'];
+
+ $db->where('periodo_id', $periodo_id)->delete('periodo');
+
+ echo json_encode([
+ 'success' => true,
+ 'message' => "El periodo $periodo_nombre ha sido eliminado"
+ ]);
+ break;
+ default:
+ header('HTTP/1.1 405 Method Not Allowed');
+ echo json_encode(['error' => 'Método no permitido']);
+ break;
+ }
+} catch (PDOException $e) {
+ echo json_encode([
+ 'error' => $e->getMessage(),
+ 'query' => $db->getLastQuery(),
+ 'exception' => $e->getTraceAsString()
+ ]);
+} catch (Exception $e) {
+ echo json_encode([
+ 'error' => $e->getMessage(),
+ 'exception' => $e->getTraceAsString()
+ ]);
+}
\ No newline at end of file
diff --git a/action/profesor_faltas.php b/action/profesor_faltas.php
new file mode 100644
index 0000000..0e9e896
--- /dev/null
+++ b/action/profesor_faltas.php
@@ -0,0 +1,135 @@
+
+require_once "{$_SERVER['DOCUMENT_ROOT']}/class/c_login.php";
+header('Content-Type: application/json');
+
+if (!Login::is_logged()) {
+ header('HTTP/1.1 401 Unauthorized');
+ echo json_encode(['error' => 'No se ha iniciado sesión']);
+ exit();
+}
+$user = Login::get_user();
+
+try {
+ switch ($_SERVER['REQUEST_METHOD']) {
+ case 'GET':
+ $facultad = $_GET['facultad'] ?? $user->facultad['facultad_id'] ?? null;
+ $porcentaje = $_GET['porcentaje'] ?? null;
+ $faltas = $_GET['faltas'] ?? null;
+
+ if (!isset($facultad) || !is_numeric($facultad)) {
+ $error = 'No se ha seleccionado una facultad';
+ } else if ((!isset($faltas) || !is_numeric($faltas)) && (!isset($porcentaje) || !is_numeric($porcentaje))) {
+ $error = 'Debe especificar las faltas o el porcentaje';
+ } else if (isset($faltas) && (!is_numeric($faltas) || $faltas <= 0)) {
+ $error = 'Las faltas deben ser un número mayor a 0';
+ } else if (isset($porcentaje) && (!is_numeric($porcentaje) || $porcentaje <= 0)) {
+ $error = 'El porcentaje debe ser un número mayor a 0';
+ } else if (isset($faltas) && isset($porcentaje)) {
+ $error = 'No se puede especificar las faltas y el porcentaje al mismo tiempo';
+ } else if (!isset($facultad) || !is_numeric($facultad)) {
+ $error = 'Debe especificar una facultad';
+ }
+
+ if (isset($error)) {
+ header('HTTP/1.1 400 Bad Request');
+ echo json_encode(['error' => $error]);
+ exit();
+ }
+ // Initialize the data array
+ $data = array();
+
+ // Check if 'profesor' or 'supervisor' is set and prepare the specific part of the SQL query accordingly.
+ if (isset($_GET['profesor']) || isset($_GET['supervisor'])) {
+
+ $condition = isset($_GET['profesor'])
+ ? "r.registro_fecha IS NULL AND NOT COALESCE(r.registro_justificada, FALSE)"
+ : "estado_supervisor_id = 2";
+
+ $filter = isset($faltas)
+ ? "afcp.faltas >= :faltas"
+ : "afcp.porcentaje >= :porcentaje";
+
+ // Prepare the SQL query with placeholders for parameters
+ $data = array_column($db->query(
+ "WITH fechas AS (
+ SELECT
+ h.horario_id,
+ fechas_clase(h.horario_id, true) AS registro_fecha_ideal,
+ hp.profesor_id
+ FROM horario h
+ JOIN horario_profesor hp USING (horario_id)
+ WHERE (h.PERIODO_ID, h.FACULTAD_ID) = (:periodo_id, :facultad_id) AND hp.profesor_id <> 0
+ ),
+ asistencia_faltas AS (
+ SELECT
+ f.profesor_id,
+ COUNT(1) AS total,
+ COUNT(1) FILTER (WHERE $condition AND f.registro_fecha_ideal <= current_date) AS faltas
+ FROM fechas f
+ LEFT JOIN registro r USING (registro_fecha_ideal, horario_id, profesor_id)
+ GROUP BY f.profesor_id
+ ),
+ asistencia_faltas_con_porcentaje AS (
+ SELECT
+ af.profesor_id,
+ af.faltas,
+ af.total,
+ CASE
+ WHEN af.total > 0 THEN ROUND((af.faltas::NUMERIC / af.total) * 100, 2)
+ ELSE NULL
+ END AS porcentaje
+ FROM asistencia_faltas af
+ WHERE af.faltas > 0
+ )
+ SELECT
+ json_build_object(
+ 'profesor', json_build_object(
+ 'profesor_nombre', p.profesor_nombre,
+ 'profesor_clave', p.profesor_clave,
+ 'profesor_correo', p.profesor_correo
+ ),
+ 'profesor_id', afcp.profesor_id,
+ 'faltas', afcp.faltas,
+ 'total', afcp.total,
+ 'porcentaje', afcp.porcentaje
+ ) AS result_json
+ FROM asistencia_faltas_con_porcentaje afcp
+ JOIN profesor p USING (profesor_id)
+ WHERE $filter
+ ORDER BY afcp.porcentaje DESC;
+ ",
+ [
+ 'periodo_id' => $user->periodo_id,
+ 'facultad_id' => $facultad,
+ ] + (isset($faltas)
+ ? ['faltas' => $faltas]
+ : ['porcentaje' => $porcentaje])
+ ), 'result_json');
+ } else {
+ // Send a 400 Bad Request header and an error message in JSON format
+ header('HTTP/1.1 400 Bad Request');
+ echo json_encode(['error' => 'Especifique si las faltas son de profesor o supervisor']);
+ exit();
+ }
+ if (empty($data)) {
+ header('HTTP/1.1 404 Not Found');
+ echo json_encode(['error' => 'No se encontraron faltas']);
+ } else {
+ echo json_encode(
+ array_map(fn($item) => json_decode($item), $data)
+ );
+ }
+
+ break;
+
+ default:
+ header('HTTP/1.1 405 Method Not Allowed');
+ echo json_encode(['error' => 'Método no permitido']);
+ break;
+ }
+} catch (PDOException $e) {
+ echo json_encode([
+ 'error' => $e->getMessage(),
+ 'query' => $db->getLastQuery(),
+ ]);
+}
diff --git a/action/puesto.php b/action/puesto.php
new file mode 100644
index 0000000..0eb4fe2
--- /dev/null
+++ b/action/puesto.php
@@ -0,0 +1,113 @@
+ 'No se ha iniciado sesión']);
+ exit();
+}
+$user = Login::get_user();
+
+try {
+ switch ($_SERVER['REQUEST_METHOD']) {
+ case 'GET':
+ // Fetch all puestos
+ $facultad_id = $user->facultad['facultad_id'] ?? -1;
+ $puestos = array_map(
+ fn($p) => array(
+ ...$p,
+ 'materias' => $db->where('puesto_id', $p['puesto_id'])
+ ->join('puesto_materia', 'puesto_materia.materia_id = materia.materia_id', 'LEFT')
+ ->get(tableName: 'materia', columns: ['materia.materia_id', 'materia_nombre', 'clave_materia',]),
+ 'encargado' => $db->where('puesto_id', $p['puesto_id'])
+ ->join('puesto_usuario', 'puesto_usuario.usuario_id = usuario.usuario_id', 'LEFT')
+ ->getOne('usuario', ['usuario.usuario_id', 'usuario_nombre', 'usuario_clave']),
+ ),
+ $db->orderBy('puesto.nombre', 'desc')
+ ->where('facultad_id', $facultad_id)
+ ->get(tableName: 'puesto', columns: 'puesto_id, nombre'),
+ );
+ echo json_encode($puestos);
+ break;
+
+ case 'POST':
+ $raw_input = file_get_contents('php://input');
+ $input_data = json_decode($raw_input, true);
+
+ if (!$input_data || !isset($input_data['puesto_nombre'])) {
+ header('HTTP/1.1 400 Bad Request');
+ echo json_encode(['error' => 'Datos inválidos']);
+ exit();
+ }
+
+ $puesto = $db->insert('puesto', [
+ 'nombre' => $input_data['puesto_nombre'],
+ 'facultad_id' => $user->facultad['facultad_id'],
+ ], ['puesto_id', 'nombre', 'facultad_id']);
+
+ echo json_encode(
+ array(
+ ...$puesto,
+ 'materias' => [],
+ 'encargado' => null,
+ ),
+ );
+ break;
+
+ case 'PUT':
+ $raw_input = file_get_contents('php://input');
+ $input_data = json_decode($raw_input, true);
+
+ if (!$input_data || !isset($input_data['puesto_id'], $input_data['materias'])) {
+ header('HTTP/1.1 400 Bad Request');
+ echo json_encode(['error' => 'Datos inválidos']);
+ exit();
+ }
+
+ $db->where('puesto_id', $input_data['puesto_id'])->delete('puesto_materia');
+ $db->where('puesto_id', $input_data['puesto_id'])->delete('puesto_usuario');
+
+ foreach ($input_data['materias'] as $materia_id) {
+ $db->insert('puesto_materia', [
+ 'puesto_id' => $input_data['puesto_id'],
+ 'materia_id' => $materia_id,
+ ]);
+ }
+
+ if (isset($input_data['usuario_id']))
+ $db->insert('puesto_usuario', [
+ 'puesto_id' => $input_data['puesto_id'],
+ 'usuario_id' => $input_data['usuario_id'],
+ ]);
+
+ echo json_encode(['msg' => 'Puesto actualizado exitosamente']);
+ break;
+
+ case 'DELETE':
+ $raw_input = file_get_contents('php://input');
+ $input_data = json_decode($raw_input, true);
+
+ if (!$input_data || !isset($input_data['puesto_id'])) {
+ header('HTTP/1.1 400 Bad Request');
+ echo json_encode(['error' => 'Datos inválidos']);
+ exit();
+ }
+
+ $db->where('puesto_id', $input_data['puesto_id'])->delete('puesto');
+ echo json_encode(['msg' => 'Puesto eliminado exitosamente']);
+ break;
+
+ default:
+ header('HTTP/1.1 405 Method Not Allowed');
+ echo json_encode(['error' => 'Método no permitido']);
+ break;
+ }
+} catch (PDOException $e) {
+ echo json_encode([
+ 'error' => $e->getMessage(),
+ 'query' => $db->getLastQuery(),
+ 'exception' => $e->getTraceAsString()
+ ]);
+}
\ No newline at end of file
diff --git a/action/registro_supervisor.php b/action/registro_supervisor.php
new file mode 100644
index 0000000..b279381
--- /dev/null
+++ b/action/registro_supervisor.php
@@ -0,0 +1,60 @@
+
+#input $_GET['id_espacio_sgu']
+define("INFORMATION", [
+ 'POST' => [
+ 'profesor_id',
+ 'horario_id',
+ 'estado',
+ 'comentario',
+ 'supervisor_id',
+ ],
+]);
+#output rutas: [ ...ruta, salones: [{...salon}] ]
+header('Content-Type: application/json charset=utf-8');
+#return html
+$ruta = "../";
+require_once "../class/c_login.php";
+// check method
+try {
+ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ // check parameters
+ $raw = file_get_contents('php://input');
+ $post_data = json_decode($raw, true);
+ // if it's a list
+ // step 1: get subrutas
+ if (empty($post_data)) {
+ http_response_code(400);
+ echo json_encode(['error' => 'No hay clases pendientes']);
+ exit;
+ }
+
+ $data = $db->query(
+ 'INSERT INTO registro (profesor_id, horario_id, registro_fecha_supervisor, estado_supervisor_id, registro_fecha_ideal, supervisor_id, comentario)
+ VALUES' .
+ implode(',', array_map(fn($x) => "({$x['profesor_id']} , {$x['horario_id']}, NOW()," . (is_null($x['estado']) ? 'null' : $x['estado']) . ", NOW(), {$x['supervisor_id']}," . (empty($x['comentario']) ? 'null' : "'{$x['comentario']}'") . ')', $post_data))
+ . ' ON CONFLICT (profesor_id, horario_id, registro_fecha_ideal) DO UPDATE SET estado_supervisor_id = EXCLUDED.estado_supervisor_id, registro_fecha_supervisor = NOW(), comentario = EXCLUDED.comentario, supervisor_id = EXCLUDED.supervisor_id
+ RETURNING *'
+ );
+ echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+ } else {
+ http_response_code(405);
+ echo json_encode(['error' => 'method not allowed']);
+ exit;
+
+ }
+
+} catch (PDOException $th) {
+ http_response_code(500);
+ echo json_encode([
+ 'error' => $th->getMessage(),
+ 'query' => $db->getLastQuery(),
+ 'post_data' => $post_data,
+ ], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+ exit;
+} catch (Exception $th) {
+ http_response_code(500);
+ echo json_encode([
+ 'error' => $th->getMessage(),
+ ], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+ exit;
+}
\ No newline at end of file
diff --git a/action/reposicion_autoriza.php b/action/reposicion_autoriza.php
new file mode 100644
index 0000000..e3a1d8a
--- /dev/null
+++ b/action/reposicion_autoriza.php
@@ -0,0 +1,195 @@
+querySingle('SELECT h.materia, r.fecha_nueva, r.hora_nueva, r.fecha_clase, h.horario_hora, h.facultad_id, h.facultad, f.clave_dependencia, r.motivo_cancelacion, ta.tipoaula_supervisor , ta.tipoaula_nombre
+ from reposicion_solicitud r
+ inner join horario_view h on h.horario_id = r.horario_id
+ inner join facultad f on f.facultad_id = h.facultad_id
+ inner join tipoaula ta on ta.tipoaula_id = r.tipoaula_id
+ where r.reposicion_solicitud_id = :id_repo',
+ [':id_repo' => $id_repo]
+ );
+
+//Obtiene datos de salón asignado
+$salon_desc = "Pendiente";
+if(!empty($salon)){
+ $salon_rs = $db->querySingle('SELECT s.salon_id, s.salon_array FROM salon_view s where s.salon_id = :id_salon',
+ [':id_salon' => $salon]
+ );
+ if($salon_rs["salon_id"] == "" || $salon_rs["salon_id"] == NULL){
+ $salon_desc = "Pendiente";
+ }else{
+ $salon_json = json_decode($salon_rs["salon_array"], true);
+ if($salon_json[0]== "UNIVERSIDAD LA SALLE"){
+ unset($salon_json[0]);
+ }
+ $salon_desc = join(" / ",$salon_json);
+ }
+}
+
+//Obtiene correos
+$correos_rs = $db->query('SELECT p.profesor_nombre, p.profesor_correo, u.usuario_nombre as jefe_nombre, u.usuario_correo as jefe_correo,
+ coor.usuario_nombre as coordinador_nombre, coor.usuario_correo as coordinador_correo
+ from reposicion_solicitud rs
+ inner join profesor p on rs.profesor_id =p.profesor_id
+ inner join usuario u on u.usuario_id = rs.usuario_id
+ inner join horario_view hv on hv.horario_id = rs.horario_id
+ inner join usuario coor on hv.facultad_id = coor.facultad_id and coor.rol_id = :rol_coord
+ where rs.reposicion_solicitud_id = :id_repo',
+ [':rol_coord' => COORDINADOR, ':id_repo' => $id_repo]
+ );
+//print_r($correos_rs); exit();
+
+$prof_correos=array();
+$jefe_correos=[];
+$coord_correos=[];
+
+foreach($correos_rs as $correo){
+ if( count($prof_correos)==0 && $correo["profesor_correo"]!=""){
+ if( !isset($prof_correos["correo"]) || !in_array($correo["profesor_correo"], $prof_correos["correo"]) ){
+ array_push($prof_correos, $correo["profesor_correo"]);
+ }
+ }
+ if( count($jefe_correos)==0 && $correo["jefe_correo"]!=""){
+ if(!isset($jefe_correos["correo"]) || !in_array($correo["jefe_correo"], $jefe_correos["correo"])){
+ array_push($jefe_correos, $correo["jefe_correo"]);
+ }
+ }
+ if( count($coord_correos)==0 && $correo["coordinador_correo"]!=""){
+ if(!isset($coord_correos["correo"]) || !in_array($correo["coordinador_correo"], $coord_correos["correo"])){
+ array_push($coord_correos, $correo["coordinador_correo"]);
+ }
+ }
+}
+
+$correosSup_rs = $db->query("SELECT DISTINCT sup.usuario_correo as supervisor_correo
+ FROM horario_supervisor hs
+ inner join usuario sup on sup.usuario_id =hs.usuario_id
+ where :facultad = ANY(hs.facultad_id_array)",
+ [':facultad'=>$reposicion_rs["facultad_id"]] );
+
+$sup_correos=[];
+foreach($correosSup_rs as $correo){
+ array_push($sup_correos, $correo["supervisor_correo"]);
+}
+
+
+if($edo == 4){//cancelación
+ $motivo = "";
+ if(isset($_POST["motivo"]) && $_POST["motivo"] != "")
+ $motivo = trim($_POST["motivo"]);
+ $db->querySingle('SELECT fu_reposicion_cancela(:id, :motivo)',
+ [':id' => $id_repo, ':motivo' => $motivo]
+ );
+}else{
+ if(!empty($salon)){
+ $db->querySingle('SELECT fu_reposicion_solicitud(:id, NULL, NULL, NULL, :sal, :edo, NULL, NULL, NULL, NULL)',
+ [':id' => $id_repo, ':sal' => $salon, ':edo' => $edo]
+ );
+ }else{
+ $db->querySingle('SELECT fu_reposicion_solicitud(:id, NULL, NULL, NULL, NULL, :edo, NULL, NULL, NULL, NULL)',
+ [':id' => $id_repo, ':edo' => $edo]
+ );
+ }
+}
+
+
+$fecha_clase = date('d/m/Y', strtotime($reposicion_rs["fecha_clase"]));
+$fecha_nueva = date('d/m/Y', strtotime($reposicion_rs["fecha_nueva"]));
+$hora_tmp = explode(":",$reposicion_rs["horario_hora"]);
+$hora_clase = $hora_tmp[0].":".$hora_tmp[1];
+$hora_tmp = explode(":",$reposicion_rs["hora_nueva"]);
+$hora_nueva = $hora_tmp[0].":".$hora_tmp[1];
+
+$asunto = "";
+$texto = "";
+$to = "";
+switch($edo){
+ case 2://Correo a supervisor
+ $asunto = "Reposición nueva - ".$reposicion_rs["clave_dependencia"]." ".$reposicion_rs["facultad"];
+ //crear plantilla
+ $texto = "
Se creó una reposición nueva para: ".$reposicion_rs["clave_dependencia"]." ".$reposicion_rs["facultad"].".
";
+ $texto .= "
".mb_strtoupper($reposicion_rs["materia"])." del día ".$fecha_clase." a las ".$hora_clase." hrs. se propone reponer el ".$fecha_nueva." a las ".$hora_nueva." hrs.";
+ if(!$reposicion_rs["tipoaula_supervisor"]){
+ $texto .= " en el salón: ".$salon_desc."
";
+ }else{
+ $texto .= " en un salón de tipo: ".$reposicion_rs["tipoaula_nombre"]."
";
+ $to = join(",", $sup_correos);
+ $ok = 0;
+ break;
+ case 3://Correo a coordinador, profesor y jefe
+ $asunto = "Reposición autorizada - ".$reposicion_rs["materia"];
+ $texto = "
La resposición de la clase de ".$reposicion_rs["materia"]." del día ".$fecha_clase." a las ".$hora_clase." hrs. está autorizada para realizarse el día ".$fecha_nueva." a las ".$hora_nueva." hrs. en: $salon_desc
La resposición de la clase de ".$reposicion_rs["materia"]." planeada para el día ".$fecha_nueva." a las ".$hora_nueva." hrs. ha sido declinada por el siguiente motivo:
".mb_strtoupper($materia_rs["materia_nombre"])." del día ".$fecha_clase." a las ".$horario_rs["horario_hora"]." hrs. se propone reponer el ".$fecha_nueva." a las ".$hora." hrs.";
+ $texto .= "
".mb_strtoupper($materia_rs["materia_nombre"])." del día ".$fecha_falta." a las ".$hora." hrs. se propone reponer el ".$fecha_nueva." a las ".$hora." hrs.";
+ $texto .= "
Los encabezados deberán mantenerse en todo momento, tal cual se encuentran en la plantilla.
+
Las horas válidas son de 7:00 a 22:00 en bloques de 15 minutos.
+
La columna DURACIÓN es la duración de una clase en horas. Si la clase es de 7:15–8:45 se pone que la hora de la clase es de 7:15 con una duración de 180.
+
+
Si se encuentra un error en la revisión del archivo no se guardará ningún registro.
+
Una vez revisado el archivo haz clic en el botón [Guardar horario] para que se guarde la información.
+ El profesor registró su asistencia a las
+ {{clase_vista.registro_fecha?.slice(11, 19)}}
+
+
+
+ A tiempo
+
+
+
+ Con retardo
+
+
+
+
+
+
+
+ Justificada
+
+
+ por
+ {{clase_vista.justificador_nombre}} de
+ {{clase_vista.justificador_rol}}
+ de
+ {{clase_vista.justificador_facultad}}
+
+
+ el día {{clase_vista.registro_fecha_justificacion?.slice(0, 10)}} a
+ las
+ {{clase_vista.registro_fecha_justificacion?.slice(11, 16)}}
+
+
+
+
+ Observación:
+ {{clase_vista.justificacion}}
+
+
+
+
+
+
+
+
+
+ Sin justificar,
+ {{clase_vista.justificador_nombre}}
+ ({{clase_vista.justificador_rol}}{{clase_vista.justificador_facultad
+ ? ' de ' + clase_vista.justificador_facultad : ''}})
+ borró la justificación, el día
+ {{clase_vista.registro_fecha_justificacion?.slice(0, 10)}} a las
+ {{clase_vista.registro_fecha_justificacion?.slice(11, 16)}}
+
+
+
+
+
+
+
+ Sin justificar
+
+
+
+
+
+
+
Reposición
+
+
+
+ Esta clase se reprogramó para el día
+ {{ clase_vista.reposicion_fecha }} a las
+ {{ clase_vista.reposicion_hora?.slice(0, 5) }} -
+ {{clase_vista.reposicion_hora_fin?.slice(0, 5) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{store.current.modal_state}}
+
+
+
+
+
+
+
+
+
+
+
+
+ if ($user->acceso == 'w') { ?>
+
+
+
+
+
Justificar Asistencia
+
+
+
+
¿Desea justificar la asistencia?
+
+
+
+ Justificar
+ {{store.current.justificada.nombre}} del día {{store.current.justificada.registro_fecha_ideal}}
+ a
+ las {{store.current.justificada.horario_hora?.slice(0,5)}}
+ para el profesor {{store.current.justificada.profesor_nombre}}
+
+
+
+
+
+ Observaciones
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Justificación de profesores
+
+
+
+
+
+ Selecciona los bloques que deseas justificar, puedes seleccionar varios bloques
+
+ Todos los profesores que tengan clases en los bloques seleccionados serán
+ justificados
+
+
+
+
+
+
+
+
+ } ?>
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/avisos.php b/avisos.php
new file mode 100644
index 0000000..e0c0fdf
--- /dev/null
+++ b/avisos.php
@@ -0,0 +1,351 @@
+
+
+
+
+
+
+ Auditoría asistencial
+
+
+
+
+
+
+
+
+
+
+ $redirect = $_SERVER['PHP_SELF'];
+ include "import/html_header.php";
+ global $user;
+
+ html_header(
+ "Avisos del checador",
+ "Sistema de gestión de checador",
+ );
+ ?>
+
+
+
+ include_once 'import/periodo.php' ?>
+
+
+
\ No newline at end of file
diff --git a/import/html_forms_justificacion.php b/import/html_forms_justificacion.php
new file mode 100644
index 0000000..402556c
--- /dev/null
+++ b/import/html_forms_justificacion.php
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+ Selecciona la fecha que deseas justificar.
+
+
+ Fecha *
+
+
+
No es una fecha válida.
+
+
+
+
+ Hora estimada *
+
+
+
+
+
+
+
+
No es una hora válida.
+
+
+
+
+
+
+ Hora límite
+
+
+
+
+
+
+
+
No es una hora válida.
+
+
+
+
+ Clave
+
+
+
No es una clave válida.
+
+
+
+
+
+ Nombre
+
+
+
No es un nombre válido.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/import/html_forms_vista.php b/import/html_forms_vista.php
new file mode 100644
index 0000000..ea3cc39
--- /dev/null
+++ b/import/html_forms_vista.php
@@ -0,0 +1,163 @@
+
+ $id, ':per' => $user->periodo_id]);
+// materia por carrera
+#print_r($carreras);
+$materias = queryAll("SELECT DISTINCT * FROM FS_MATERIA WHERE CARRERA = COALESCE(:car, CARRERA) AND ID IN (SELECT distinct materia_id FROM HORARIO WHERE :id IN (SELECT HORARIO_ID FROM HORARIO_PROFESOR WHERE PROFESOR_ID = :id) AND PERIODO_ID = :per) ORDER BY NOMBRE", [":car" => empty($carrera) ? null : $carrera, ':id' => $id, ':per' => $user->periodo_id]);
+#exit();
+$periodo = query("SELECT inicio, fin FROM FS_PERIODO WHERE ID = :per", [':per' => $user->periodo_id]);
+?>
+
+
+
\ No newline at end of file
diff --git a/import/html_scroll.php b/import/html_scroll.php
new file mode 100644
index 0000000..c4721e5
--- /dev/null
+++ b/import/html_scroll.php
@@ -0,0 +1,42 @@
+
+
+
+ = $ICO['arriba'] ?>
+
+
+
+ = $ICO['abajo'] ?>
+
+
+
\ No newline at end of file
diff --git a/import/periodo.php b/import/periodo.php
new file mode 100644
index 0000000..b4a8e3c
--- /dev/null
+++ b/import/periodo.php
@@ -0,0 +1,73 @@
+
+
+$user or die("Error: no se pudo cargar el usuario");
+?>
+
+
+
+ orderBy('nivel_nombre')
+ ->get("nivel");
+
+ // collect facultad_id's with facultad from $periodos
+ ?>
+
+
+
+ Cambiar de periodo
+
+
+
+ Selecciona un periodo
+
+
+
+
+
+ = $nivel['nivel_nombre'] ?>
+
+
+ $periodos_rs = $db->query('SELECT periodo_id, periodo_nombre FROM PERIODO_VIEW
+ WHERE
+ nivel_id = :nivel_id AND
+ (facultad_id = :facultad_id OR :facultad_id IS NULL)
+ GROUP BY periodo_id, periodo_nombre, periodo_fecha_inicio
+ ORDER BY periodo_fecha_inicio DESC',
+ [
+ ':nivel_id' => $nivel['nivel_id'],
+ ':facultad_id' => $user->facultad['facultad_id']
+ ]
+ );
+ array_walk($periodos_rs, function ($per) {
+ global $user;
+ ?>
+