Alejandro Rosales 1 年之前
父节点
当前提交
c927cb02bb

+ 3 - 2
action/action_carreras.php

@@ -14,7 +14,8 @@ $ruta = "../";
 require_once "../include/bd_pdo.php";
 $facultad_id = $user->facultad['facultad_id'];
 $carreras = $db->query(
-    "SELECT * FROM carrera
+    "SELECT carrera_id, carrera_nombre, clave_carrera
+     FROM carrera
     WHERE
         (facultad_id = :facultad_id OR :facultad_id IS NULL)
     ORDER BY carrera_nombre DESC",
@@ -23,4 +24,4 @@ $carreras = $db->query(
 
 // $user->print_to_log("Crea carrera", old: $_POST);
 
-die(json_encode($carreras));
+die(json_encode($carreras));

+ 8 - 3
action/action_facultad.php

@@ -26,9 +26,14 @@ try {
                 exit;
             }
         });
-        // step 1: get subrutas
-        $data = $db->get('facultad');
-
+        $data = $db->query(<<<SQL
+                SELECT facultad_nombre, facultad_id, clave_dependencia
+                FROM facultad
+                WHERE facultad_id = :facultad_id OR :facultad_id IS NULL
+                SQL
+            ,
+            [':facultad_id' => $user->facultad['facultad_id']]
+        );
         echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
     } else {
         http_response_code(405);

+ 30 - 10
action/action_grupo.php

@@ -1,21 +1,41 @@
 <?php
+header('Content-Type: application/json');
 $ruta = "../";
 require_once "../class/c_login.php";
 
 // check if the session is started
-$user = Login::get_user();
+if (Login::is_logged())
+    $user = Login::get_user();
+else {
+    header('HTTP/1.1 401 Unauthorized');
+    echo json_encode(['error' => 'No se ha iniciado sesión']);
+    exit();
+}
 
 $ruta = "../";
 require_once("../include/bd_pdo.php");
-extract($_POST);
-$params = ['per' => $_POST['periodo'], 'fac' => $_POST['facultad'], 'car' => $_POST['carrera']];
 
-$user->print_to_log("Acceso a grupos", old: $params);
-$grupos = queryAll("SELECT DISTINCT LENGTH(GRUPO), GRUPO FROM fs_horario_basic WHERE PERIODO_ID = COALESCE(:per, PERIODO_ID) AND FACULTAD_ID = COALESCE(:fac, FACULTAD_ID) AND CARRERA_ID = COALESCE(:car, CARRERA_ID) ORDER BY LENGTH(GRUPO), GRUPO", $params);
+if (!isset($_GET['carrera_id'])) {
+    echo json_encode([
+        'status' => 'error',
+        'error' => 'No se ha especificado una carrera'
+    ]);
+    exit();
+}
 
-$grupos = array_map(fn ($grupo) => $grupo['grupo'], $grupos);
+$grupos = $db->query(<<<SQL
+    SELECT distinct substring(horario_grupo, 7, 3)::int - 1 as horario_grupo FROM horario_view WHERE
+        PERIODO_ID = :periodo_id AND
+        (FACULTAD_ID = :facultad_id OR :facultad_id IS NULL) AND
+        CARRERA_ID = :carrera_id
+    GROUP BY horario_grupo
+        ORDER BY horario_grupo ASC
+    SQL,
+    [
+        ':periodo_id' => $user->periodo_id,
+        ':facultad_id' => $user->facultad['facultad_id'],
+        ':carrera_id' => $_GET['carrera_id']
+    ]
+);
 
-echo json_encode([
-    'status' => 'success',
-    'grupos' => $grupos
-]);
+echo json_encode(array_map(fn($grupo) => $grupo['horario_grupo'], $grupos));

+ 22 - 8
action/action_horario.php

@@ -17,20 +17,34 @@ $user = unserialize($_SESSION['user']);
 // check method
 try {
     if ($_SERVER['REQUEST_METHOD'] === 'GET') {
-        if (!isset($_GET['profesor_id'])) {
+        if (!(isset($_GET['profesor_id']) || isset($_GET['grupo']))) {
             throw new Exception('missing parameters');
         }
-        $data = $db->query(
-            "SELECT *, (EXTRACT(EPOCH FROM (horario_fin - horario_hora) ) / EXTRACT(EPOCH FROM interval '15 minute'))::INT AS bloques
+        if (isset($_GET['profesor_id'])) {
+            $data = $db->query(
+                "SELECT *, (EXTRACT(EPOCH FROM (horario_fin - horario_hora) ) / EXTRACT(EPOCH FROM interval '15 minute'))::INT AS bloques
             FROM horario_view
             JOIN horario_profesor ON horario_profesor.horario_id = horario_view.horario_id
             WHERE horario_profesor.profesor_id = :profesor_id
             AND (facultad_id = :facultad_id OR :facultad_id IS NULL)",
-            [
-                'profesor_id' => $_GET['profesor_id'],
-                'facultad_id' => $user->facultad['facultad_id'],
-            ]
-        );
+                [
+                    'profesor_id' => $_GET['profesor_id'],
+                    'facultad_id' => $user->facultad['facultad_id'],
+                ]
+            );
+        } else if (isset($_GET['grupo'])) {
+            $data = $db->query(
+                "SELECT *, (EXTRACT(EPOCH FROM (horario_fin - horario_hora) ) / EXTRACT(EPOCH FROM interval '15 minute'))::INT AS bloques
+            FROM horario_view
+            WHERE substring(horario_grupo, 7, 3) = (CAST(:grupo AS INT) + 1)::varchar
+            AND (facultad_id = :facultad_id OR :facultad_id IS NULL) AND carrera_id = :carrera_id",
+                [
+                    'grupo' => $_GET['grupo'],
+                    'facultad_id' => $user->facultad['facultad_id'],
+                    'carrera_id' => $_GET['carrera_id'],
+                ]
+            );
+        }
 
         $last_query = [
             'query' => $db->getLastQuery(),

+ 20 - 16
action/action_materias.php

@@ -1,26 +1,30 @@
 <?php
+header('Content-Type: application/json');
+
 $ruta = "../";
 require_once "../class/c_login.php";
 
-extract($_POST);
-# print_r($_POST); exit;
-
+// check if the session is started
 if (!isset($_SESSION['user']))
-    die(header('Location: index.php'));
+    die(json_encode(['error' => 'No se ha iniciado sesión']));
 
 $user = unserialize($_SESSION['user']);
 
-if (($access = $user->access('asistencia')) == 'n')
-    die(json_encode(['error' => true]));
-
-$user->print_to_log('Consultar materias');
-$materias = queryAll(
-    "SELECT id, nombre FROM FS_MATERIA WHERE carrera = COALESCE(:carrera, carrera) ORDER BY nombre",
-    [':carrera' => empty($carrera) ? null : $carrera]
+$ruta = "../";
+require_once "../include/bd_pdo.php";
+$facultad_id = $user->facultad['facultad_id'];
+$materias = $db->query(<<<SQL
+    SELECT materia_id, materia_nombre, clave_materia, materia.carrera_id
+    FROM materia
+    JOIN carrera USING (carrera_id)
+    JOIN facultad USING (facultad_id)
+    WHERE
+        (facultad_id = :facultad_id OR :facultad_id IS NULL)
+    ORDER BY carrera_nombre DESC
+    SQL,
+    array('facultad_id' => $facultad_id)
 );
-?>
 
-<?= json_encode([
-    'status' => 'success',
-    'materias' => $materias,
-]); ?>
+// $user->print_to_log("Crea carrera", old: $_POST);
+
+die(json_encode($materias));

+ 36 - 0
action/carrera.php

@@ -0,0 +1,36 @@
+<?php
+
+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':
+            // Fetch all puestos
+            $facultad_id = $user->facultad['facultad_id'];
+            $carreras = $db->query(<<<SQL
+                SELECT carrera_id, carrera_nombre, clave_carrera, facultad_id
+                FROM carrera
+                WHERE facultad_id = :facultad_id OR :facultad_id IS NULL
+            SQL, ['facultad_id' => $facultad_id]);
+            echo json_encode($carreras);
+            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()
+    ]);
+}

+ 8 - 7
action/puesto.php

@@ -26,7 +26,7 @@ try {
                         ->join('puesto_usuario', 'puesto_usuario.usuario_id = usuario.usuario_id', 'LEFT')
                         ->getOne('usuario', ['usuario.usuario_id', 'usuario_nombre', 'usuario_clave']),
                 ),
-                $db->orderBy('puesto_id', 'desc')
+                $db->orderBy('puesto.nombre', 'desc')
                     ->where('facultad_id', $facultad_id)
                     ->get(tableName: 'puesto', numRows: count($carreras), columns: 'puesto_id, nombre'),
             );
@@ -61,7 +61,7 @@ try {
             $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'], $input_data['usuario_id'])) {
+            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();
@@ -77,10 +77,11 @@ try {
                 ]);
             }
 
-            $db->insert('puesto_usuario', [
-                'puesto_id' => $input_data['puesto_id'],
-                'usuario_id' => $input_data['usuario_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;
@@ -95,7 +96,7 @@ try {
                 exit();
             }
 
-            $db->where('puesto_id', $input_data['puesto_id'])->delete('puestos');
+            $db->where('puesto_id', $input_data['puesto_id'])->delete('puesto');
             echo json_encode(['msg' => 'Puesto eliminado exitosamente']);
             break;
 

+ 12 - 9
action/reposicion_autoriza.php

@@ -7,10 +7,12 @@ $ruta = "../";
 require_once "../class/c_login.php";
 
 // check if the session is started
-$user = Login::get_user();
+if (!isset($_SESSION['user']))
+    die('No se ha iniciado sesión');
 
-$pag = "../reposiciones_autorizar.php";
+$user = unserialize($_SESSION['user']);
 
+$pag = "../reposiciones_autorizar.php";
 
 
 if(!isset($_POST["id"]) || !isset($_POST["edo"]) ){
@@ -21,30 +23,31 @@ if(!isset($_POST["id"]) || !isset($_POST["edo"]) ){
 $id_repo = filter_input(INPUT_POST, "id", FILTER_SANITIZE_NUMBER_INT);//limpia texto
 $edo = filter_input(INPUT_POST, "edo", FILTER_SANITIZE_NUMBER_INT);//limpia texto
 if(isset($_POST["salon"]) && $_POST["salon"] != "")
-    $salon = trim(filter_input(INPUT_POST, "salon", FILTER_SANITIZE_STRING,array('flags' => FILTER_FLAG_STRIP_LOW)));//limpia texto
+    $salon = filter_input(INPUT_POST, "salon", FILTER_SANITIZE_NUMBER_INT);//limpia texto
 
-$motivo = "";
-if(isset($_POST["motivo"]) && $_POST["motivo"] != "")
-    $motivo = trim($_POST["motivo"]);
 
 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(:id, NULL, NULL, NULL, :sal, :edo, NULL, NULL, NULL, NULL)',
+        $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(:id, NULL, NULL, NULL, NULL, :edo, NULL, NULL, NULL, NULL)',
+        $db->querySingle('SELECT fu_reposicion_solicitud(:id, NULL, NULL, NULL, NULL, :edo, NULL, NULL, NULL, NULL)',
             [':id' => $id_repo, ':edo' => $edo]
         );
     } 
 }
 
 //Obtener datos del usuario que creó la reposición y mandar correo
-/*$stmt = $pdo->prepare('Select * from fs_reposicion(:id, :periodo, NULL, NULL, NULL, NULL, NULL, 0, 1)');
+/*$stmt = $pdo->prepare('Select * from 
+:id, :periodo, NULL, NULL, NULL, NULL, NULL, 0, 1)');
 $stmt->bindParam(":id", $id_repo);
 $stmt->bindParam(":periodo", $_SESSION["periodo_id"]);
 if(!$stmt->execute()){

+ 7 - 4
action/reposicion_delete.php

@@ -7,17 +7,20 @@ $ruta = "../";
 require_once "../class/c_login.php";
 
 // check if the session is started
-$user = Login::get_user();
+if (!isset($_SESSION['user']))
+    die('No se ha iniciado sesión');
+
+$user = unserialize($_SESSION['user']);
 
 //--- Objeto para validar usuario. El id de usuario lo lee desde sesión
-if(!isset($_POST["id"], $_POST["prof"])){
+if(!isset($_POST["id"])){
     $return["error"] = "Error! No se recibió la información necesaria.";
 }else{
     $id = filter_input(INPUT_POST, "id", FILTER_SANITIZE_NUMBER_INT);//limpia texto
-    $prof = $user["id"];
+    $creador = $user->user["id"];
 
     try{
-        $db->query('SELECT * from fd_reposicion(:id, :prof)', [":id"=> $id, ":prof"=>$prof]);
+        $db->query('SELECT * from fd_reposicion_solicitud(:id, :creador)', [":id"=> $id, ":creador"=>$creador]);
         $return["ok"] = "La reposición se borró correctamente";
     
     }catch(Exception $e){

+ 12 - 1
action/reposicion_select.php

@@ -55,7 +55,17 @@ $user = unserialize($_SESSION['user']);
     $return["materia"] = $rs["materia_id"];
     $return["materia_desc"] = $rs["materia_nombre"];
     $return["salon"] = $rs["salon_id"];
-    $return["salon_desc"] = $rs["salon"]=="" ? "-Pendiente-": $rs["salon"];
+    if($rs["salon_id"]==""){
+        $return["salon_desc"] = "Pendiente";
+    }else{
+        $salon_json = json_decode($rs["salon_array"], true);
+        if($salon_json[0]== "UNIVERSIDAD LA SALLE"){
+            unset($salon_json[0]);
+        }
+        $return["salon_desc"] = join(" / ",$salon_json);
+    }
+
+    //$return["salon_desc"] = $rs["salon"]=="" ? "-Pendiente-": $rs["salon"];
     $return["ciclo"] = $rs["ciclo"];
     $return["bloque"] = $rs["bloque"];
     $return["profesor"] = $rs["profesor_id"];
@@ -69,6 +79,7 @@ $user = unserialize($_SESSION['user']);
     $return["dia"] = date('w', strtotime($rs["fecha_clase"]));
     $return["motivo_cancelacion"] = $rs["motivo_cancelacion"];
     $return["estado"] = $rs["estado_reposicion_id"];
+    $return["facultad"] = $rs["facultad_nombre"];
 }
 echo json_encode($return);
 ?>

+ 2 - 1
action/rutas_salón_horario.php

@@ -60,7 +60,6 @@ try {
             'reposicion_hora',
             'salon_reposicion.salon as reposicion_salon',
         ];
-
         $data = array_map(
             fn($ruta) => array_merge(
                 [
@@ -77,6 +76,8 @@ try {
                         ->where('horario_dia = EXTRACT(DOW FROM CURRENT_DATE)')
                         ->where('bloque_horario.id', $_GET['bloque_horario_id'])
                         ->where('salon_view.id_espacio_padre', $ruta['id_espacio_sgu'])
+                        ->orderBy('horario_hora')
+                        ->orderBy('salon_view.salon')
                         ->get(
                             'horario_view',
                             columns: $columns

+ 28 - 0
action/usuarios.php

@@ -0,0 +1,28 @@
+<?php
+header('Content-Type: application/json');
+
+$ruta = "../";
+require_once "../class/c_login.php";
+
+// check if the session is started
+if (!isset($_SESSION['user']))
+    die(json_encode(['error' => 'No se ha iniciado sesión']));
+
+$user = unserialize($_SESSION['user']);
+
+$ruta = "../";
+require_once "../include/bd_pdo.php";
+$facultad_id = $user->facultad['facultad_id'];
+$materias = $db->query(<<<SQL
+    SELECT usuario_id, usuario_nombre, usuario_clave
+    FROM usuario
+    WHERE
+        (facultad_id = :facultad_id OR :facultad_id IS NULL)
+    ORDER BY usuario_nombre ASC
+    SQL,
+    array('facultad_id' => $facultad_id)
+);
+
+// $user->print_to_log("Crea carrera", old: $_POST);
+
+die(json_encode($materias));

+ 21 - 19
auditoria.php

@@ -218,7 +218,16 @@
 
         <div class="mt-3 d-flex justify-content-between flex-wrap align-items-center">
             <!-- botón descargar -->
-            <div class="col-md-5 col-12 text-center">
+            <div class="col-md-2 col-12 text-center">
+                <div class="btn-group my-3">
+                    <button type="button" class="btn btn-outline-primary mr-3">
+                        Justificar profesores
+                        <i class="ing-justificar"></i>
+                    </button>
+                </div>
+            </div>
+            <!-- botón descargar -->
+            <div class="col-md-2 col-12 text-center">
                 <div class="btn-group my-3" v-if="store.registros.relevant.length > 0">
                     <button type="button" class="btn btn-outline-primary mr-3" @click="store.registros.descargar">
                         Descargar reporte
@@ -233,7 +242,7 @@
                 </div>
             </div>
             <!-- Reporte -->
-            <div class="col-md-7 col-12 justify-content-around d-flex align-items-center">
+            <div class="col-md-8 col-12 justify-content-around d-flex align-items-center">
                 <span v-for="estado in store.estados.data" :class="`text-${estado.estado_color}`"
                     class="text-center col-2">
                     <i :class="`${estado.estado_icon} ing-lg`"></i>
@@ -313,7 +322,8 @@
                                             <span class="mr-2" :class="`text-${registro.estado_color}`">
                                                 <i :class="`${registro.estado_icon} ing-2x`"></i>
                                             </span>
-                                            <strong v-if="registro.usuario_nombre">{{ registro.usuario_nombre }}</strong>
+                                            <strong v-if="registro.usuario_nombre">{{ registro.usuario_nombre
+                                                }}</strong>
                                         </div>
                                         <div class="col-12" v-if="registro.registro_fecha_supervisor">
                                             Hora
@@ -452,7 +462,8 @@
                                         </div>
                                         <div class="col-12">
                                             <strong>Horario:</strong>
-                                            {{ clase_vista.horario_hora?.slice(0, 5) }} - {{clase_vista.horario_fin?.slice(0, 5) }}
+                                            {{ clase_vista.horario_hora?.slice(0, 5) }} -
+                                            {{clase_vista.horario_fin?.slice(0, 5) }}
                                         </div>
                                         <div class="col-12">
                                             <strong>Salón:</strong>
@@ -602,20 +613,8 @@
                                             class="text-muted">{{store.current.justificada.profesor_nombre}}</span>
                                     </div>
                                 </div>
-                                <div class="row mt-3">
-                                    <div class="col-12">
-                                        <div class="form-check" v-if="!store.current.justificada.justificacion">
-                                            <input class="form-check-input" type="checkbox" value="" id="observaciones"
-                                                v-model="store.current.observaciones">
-                                            <label class="form-check-label" for="observaciones">
-                                                ¿Deseas añadir observaciones?
-                                            </label>
-                                        </div>
-                                    </div>
-                                </div>
-
-                                <hr v-if="store.current.observaciones || store.current.justificada.justificacion">
-                                <div class="input-group" v-if="store.current.observaciones || store.current.justificada.justificacion">
+                                <hr>
+                                <div class="input-group">
                                     <div class="input-group-prepend">
                                         <span class="input-group-text text-white bg-primary">Observaciones</span>
                                     </div>
@@ -632,7 +631,10 @@
                                 <i class="ing-cancelar"></i>
                                 Cancelar
                             </button>
-                            <button type="button" class="btn btn-primary" data-dismiss="modal" @click="store.justificar">
+                            <button type="button" class="btn btn-primary"
+                                :disabled="!store.current.justificada.justificacion"
+                                :class="{'disabled': !store.current.justificada.justificacion}" data-dismiss="modal"
+                                @click="store.justificar">
                                 Justificar
                             </button>
                         </div>

+ 97 - 26
consultar_horario.php

@@ -37,29 +37,99 @@ $write = $user->admin || in_array($user->acceso, ['r']);
     include("import/html_header.php");
     html_header("Consultar horario", "Sistema de gestión de checador");
     ?>
-    <main class="container px-4 mt-4 h-100" id="app" v-cloak @vue:mounted="mounted" style="min-height: 60vh;">
+    <main class="container px-4 mt-4 h-100" id="app" v-cloak @vue:mounted="mounted" style="min-height: 60vh;"
+        v-scope="">
         <section id="message"></section>
-        <? // require('import/periodo.php') ?>
-        <div class="form-box">
-            <div class="form-group row">
-                <label for="profesor" class="col-4 col-form-label">Seleccionar profesor</label>
-                <div class="col-6">
-                    <div class="form-row justify-content-around align-items-center">
-                        <input id="profesor" name="profesor" class="form-control col-11 mr-1 px-2"
-                            placeholder="Seleccione un profesor" list="dlProfesor" v-model="profesores.search"
-                            @input="horarios.fetch">
-                        <button type="button" class="btn btn-outline-danger btn-sm form-control col ml-auto"
-                            @click="profesores.search = null; horarios.data = []">
-                            <i class="ing-borrar"></i>
-                        </button>
+        <nav>
+            <div class="nav nav-tabs" id="nav-tab" role="tablist">
+                <button class="nav-link active" id="nav-home-tab" data-toggle="tab" data-target="#nav-home"
+                    type="button" role="tab" aria-controls="nav-home" aria-selected="true" @click="horarios.data = []">
+                    Horario por profesor
+                </button>
+                <button class="nav-link" id="nav-profile-tab" data-toggle="tab" data-target="#nav-profile" type="button"
+                    role="tab" aria-controls="nav-profile" aria-selected="false" @click="horarios.data = []">
+                    Horario por grupo
+                </button>
+            </div>
+        </nav>
+        <div class="tab-content" id="nav-tabContent">
+            <div class="tab-pane fade show active" id="nav-home" role="tabpanel" aria-labelledby="nav-home-tab">
+                <div class="form-box">
+                    <div class="form-group row">
+                        <label for="profesor" class="col-4 col-form-label">Seleccionar profesor</label>
+                        <div class="col-6">
+                            <div class="form-row justify-content-around align-items-center">
+                                <input id="profesor" name="profesor" class="form-control col-11 mr-1 px-2"
+                                    placeholder="Seleccione un profesor" list="dlProfesor" v-model="profesores.search"
+                                    @input="horarios.fetch(null)">
+                                <button type="button" class="btn btn-outline-danger btn-sm form-control col ml-auto"
+                                    @click="profesores.search = null; horarios.data = []">
+                                    <i class="ing-borrar"></i>
+                                </button>
+                            </div>
+                            <datalist id="dlProfesor">
+                                <option v-for="profesor in profesores.data" :key="profesor.profesor_id"
+                                    :value="`(${profesor.profesor_clave}) ${profesor.profesor_nombre}`">
+                            </datalist>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="tab-pane fade" id="nav-profile" role="tabpanel" aria-labelledby="nav-profile-tab"
+                v-scope="{facultad_id: null, carrera_id: null, grupo: null}">
+                <?
+                require('import/periodo.php');
+                ?>
+                <div class="form-box" v-show="facultades.data.every(facultad => facultad.carreras.length > 0)">
+                    <div class="form-group row">
+                        <label for="carrera_id" class="col-4 col-form-label">Carrera</label>
+                        <div class="col-6">
+                            <div id="dlCarreras" class="datalist datalist-select mb-1 w-100">
+                                <div class="datalist-input">
+                                    Selecciona una carrera
+                                </div>
+                                <span class="icono ing-buscar"></span>
+                                <ul style="display:none">
+                                    <div v-for="facultad in facultades.data">
+                                        <li class="not-selectable">
+                                            {{ facultad.facultad_nombre }}
+                                        </li>
+                                        <li v-for="carrera in facultad.carreras" :key="carrera.carrera_id"
+                                            @click="carrera_id = carrera.carrera_id; facultad_id = facultad.facultad_id; grupo = null">
+                                            {{ carrera.carrera_nombre }}
+                                        </li>
+                                    </div>
+                                </ul>
+                                <input type="hidden" id="carrera_id" name="id">
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="form-box" v-if="carrera_id">
+                    <div class="form-group row">
+                        <label for="grupo" class="col-4 col-form-label">Grupo</label>
+                        <div class="col-6">
+                            <div id="dlGrupo" class="datalist datalist-select mb-1 w-100">
+                                <div class="datalist-input">
+                                    Selecciona un grupo
+                                </div>
+                                <span class="icono ing-buscar"></span>
+                                <ul style="display:none">
+                                    <li v-for="grupo in facultades.data.find(facultad => facultad.facultad_id === facultad_id).carreras.find(carrera => carrera.carrera_id === carrera_id).grupos"
+                                        @click="grupo = grupo; horarios.fetch(grupo, carrera_id)">
+                                        {{ grupo }}
+                                    </li>
+                                </ul>
+                                <input type="hidden" id="grupo" name="grupo">
+                            </div>
+                        </div>
                     </div>
-                    <datalist id="dlProfesor">
-                        <option v-for="profesor in profesores.data" :key="profesor.profesor_id"
-                            :value="`(${profesor.profesor_clave}) ${profesor.profesor_nombre}`">
-                    </datalist>
+
                 </div>
             </div>
         </div>
+        </div>
+
         <hr>
         <div id="btn-excel-horario" class="mb-2 float-right hidden">
             <button class="btn btn-outline-secondary " title="Exportar a Excel" v-if="false">
@@ -94,8 +164,7 @@ $write = $user->admin || in_array($user->acceso, ['r']);
                             class="align-middle h-100"
                             :style="`width: ${(100 - 6) / (horarios.structure?.sábado ? 6 : 5)}%;`">
                             <!-- Content Container -->
-                            <div class="overflow-auto"
-                                :style="`max-height: ${horarios.getHorarioData(hour, block, día)?.bloques * 2}em;
+                            <div class="overflow-auto" :style="`max-height: ${horarios.getHorarioData(hour, block, día)?.bloques * 2}em;
                                 min-height: 2em;
                                 `">
                                 <div v-if="horarios.getHorarioData(hour, block, día)" class="text-center">
@@ -111,12 +180,14 @@ $write = $user->admin || in_array($user->acceso, ['r']);
                                             {{horarios.getHorarioData(hour, block, día)?.materia}}
                                         </b>
                                     </div>
-                                    <small
-                                        class="text-muted">{{horarios.getHorarioData(hour,
-                                        block, día)?.carrera}}</small>
-                                    <br><span>Salón: </span><small
-                                        class="font-weight-lighter text-muted">{{horarios.getHorarioData(hour,
-                                        block, día)?.salon}}</small>
+                                    <small class="text-muted">
+                                        {{horarios.getHorarioData(hour, block, día)?.carrera}}
+                                    </small>
+                                    <br>
+                                    <span>Salón: </span>
+                                    <small class="font-weight-lighter text-muted">
+                                        {{horarios.getHorarioData(hour, block, día)?.salon}}
+                                    </small>
                                 </div>
                                 <div v-else> &nbsp; </div>
                             </div>

+ 26 - 2
js/horario.js

@@ -14,10 +14,32 @@ const profesores = reactive({
         return this.data.find((profesor) => profesor.profesor_clave === profesores.clave);
     },
 });
-const horarios = reactive({
+const facultades = reactive({
     data: [],
     fetch: async function () {
-        if (profesores.current) {
+        const facultades = await fetch('action/action_facultad.php').then(response => response.json());
+        const carreras = await fetch(`action/carrera.php`).then(response => response.json());
+        this.data = await Promise.all(facultades.map(async (facultad) => ({
+            ...facultad,
+            carreras: await Promise.all(carreras.filter((carrera) => carrera.facultad_id === facultad.facultad_id).map(async (carrera) => {
+                const grupos = await fetch(`action/action_grupo.php?carrera_id=${carrera.carrera_id}`).then(response => response.json());
+                return {
+                    ...carrera,
+                    grupos,
+                };
+            })),
+        })));
+        this.data = this.data.filter((facultad) => facultad.carreras.length > 0);
+    }
+});
+const horarios = reactive({
+    data: [],
+    fetch: async function (grupo = null, carrera_id = null) {
+        if (grupo && carrera_id) {
+            const response = await fetch(`action/action_horario.php?grupo=${grupo}&carrera_id=${carrera_id}`);
+            this.data = await response.json();
+        }
+        else if (profesores.current) {
             const response = await fetch(`action/action_horario.php?profesor_id=${profesores.current.profesor_id}`);
             this.data = await response.json();
         }
@@ -76,7 +98,9 @@ const horarios = reactive({
 const app = createApp({
     profesores,
     horarios,
+    facultades,
     mounted: async function () {
         await profesores.fetch();
+        await facultades.fetch();
     }
 }).mount('#app');

+ 25 - 0
js/puestos.js

@@ -15,6 +15,31 @@ const app = createApp({
             });
             const data = await res.json();
             this.puestos.push(data);
+            // order by puesto.nombre
+            this.puestos.sort((a, b) => a.nombre.localeCompare(b.nombre));
+        }
+        catch (error) {
+            alert(`Error: ${error}`);
+        }
+    },
+    to_delete: null,
+    async eliminarPuesto(puesto_id) {
+        try {
+            const res = await fetch('action/puesto.php', {
+                method: 'DELETE',
+                body: JSON.stringify({
+                    puesto_id
+                })
+            });
+            const data = await res.json();
+            this.message = data.msg;
+            // after 3 seconds, remove the message
+            setTimeout(() => {
+                this.message = null;
+            }, 3000);
+            this.puestos = this.puestos.filter((p) => p.puesto_id !== puesto_id);
+            // order by puesto.nombre
+            this.puestos.sort((a, b) => a.nombre.localeCompare(b.nombre));
         }
         catch (error) {
             alert(`Error: ${error}`);

+ 1 - 1
logs.php

@@ -49,7 +49,7 @@
                     <?
                     global $db;
                     $registros = $db
-                        ->where('momento::DATE = CURRENT_DATE')
+                        ->where('momento::DATE = ' . (isset($_GET['fecha']) ? "'{$_GET['fecha']}'" : 'CURRENT_DATE'))
                         ->orderBy('momento', 'desc')
                         ->get('log_registro');
 

+ 211 - 132
puestos.php

@@ -26,164 +26,243 @@
     global $user;
 
     html_header(
-        "Puestos de la {$user->facultad['facultad']}",
+        is_null($user->facultad['facultad_id']) ? "Puestos" : "Puestos de la {$user->facultad['facultad']}",
         "Sistema de gestión de checador",
     );
-    ?>
+    if (!is_null($user->facultad['facultad_id'])) {
+        ?>
 
-    <main class="container-fluid px-4 mt-4" id="app" v-cloak @vue:mounted="mounted" style="min-height: 70vh;"
-        v-scope="{new_puesto: null}">
+        <main class="container-fluid px-4 mt-4" id="app" v-cloak @vue:mounted="mounted" style="min-height: 70vh;"
+            v-scope="{new_puesto: null}">
 
-        <div class="alert alert-success" role="alert" v-if="message">
-            {{message}}
-        </div>
-        <div class="justify-content-between align-items-center d-flex mb-4">
-            <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#nuevo-puesto">
-                <span class="ing-mas"></span>
-                Agregar puesto
-            </button>
-        </div>
-        <div class="d-flex flex-wrap justify-content-around">
-            <div class="col-6" v-for="puesto in puestos" :key="puesto.puesto_id">
-                <div class="card text-center"
-                    v-scope="{selected_carrera_id: -1, current_materia: null, current_encargado: null}">
-                    <div class="card-header bg-primary text-white font-weight-bold text-uppercase">
-                        {{puesto.nombre}}
-                    </div>
-                    <div class="card-body">
-                        <!-- Encargado -->
-                        <div class="form-row justify-content-around align-items-center mb-2">
-                            <label :for="`encargado-${puesto.puesto_id}`" class="col-3">
-                                Encargado del área
-                            </label>
-                            <div id="encargados" class="datalist datalist-select mb-1 col-9">
-                                <div class="datalist-input" v-if="puesto.encargado">
-                                    ({{puesto.encargado.usuario_clave}}) {{ puesto.encargado.usuario_nombre }}
-                                </div>
-                                <div class="datalist-input" v-else>
-                                    Selecciona un encargado
-                                </div>
-                                <span class="icono ing-buscar"></span>
-                                <ul style="display:none">
-                                    <li class="datalist-option" v-for="usuario in usuarios" :key="usuario.usuario_id"
-                                        :data-id="usuario.usuario_id" style=" white-space: nowrap;"
-                                        @click="puesto.encargado = usuario"
-                                        :class="{'selected': puesto.encargado.usuario_id == usuario.usuario_id}">
-                                        (<small> {{usuario.usuario_clave}} </small>) {{ usuario.usuario_nombre }}
-                                    </li>
-                                </ul>
-                                <input type="hidden" id="encargado_id" name="id">
-                            </div>
+            <div class="alert alert-success" role="alert" v-if="message">
+                {{message}}
+            </div>
+            <div class="justify-content-between align-items-center d-flex mb-4">
+                <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#nuevo-puesto">
+                    <span class="ing-mas"></span>
+                    Agregar puesto
+                </button>
+            </div>
+
+            <div class="d-flex flex-wrap justify-content-around">
+                <div class="accordion col-8 mb-4" id="puestos"
+                    v-scope="{selected_carrera_id: -1, current_materia: null, current_encargado: null}"
+                    v-if="puestos.length">
+                    <div class="card" v-for="(puesto, index) in puestos" :key="puesto.puesto_id">
+                        <div class="card-header bg-primary" :id="`puesto-${puesto.nombre}`">
+                            <h2 class="mb-0">
+                                <button class="btn btn-link btn-block text-left text-light" type="button"
+                                    data-toggle="collapse" :data-target="`#puesto-${puesto.puesto_id}`" aria-expanded="true"
+                                    :aria-controls="`puesto-${puesto.puesto_id}`">
+                                    {{puesto.nombre}}
+
+                                    <button type="button" class="btn btn-outline-danger float-right"
+                                        data-target="#eliminar-puesto" data-toggle="modal" @click="to_delete = puesto">
+                                        <span class="icono ing-basura"></span>
+                                    </button>
+                                </button>
+                            </h2>
                         </div>
-                        <hr>
-                        <fieldset class="container d-flex flex-column justify-content-center align-items-center">
-                            <legend>Materias Asignadas <span
-                                    class="badge badge-secondary">{{puesto.materias.length}}</span></legend>
-                            <ul class="list-group overflow-auto col-10" v-if="puesto.materias.length"
-                                style="max-height: 200px; overflow-y: auto;">
-                                <li class="list-group-item list-group-item-action" v-for="materia in puesto.materias"
-                                    :key="materia.materia_id"
-                                    @click="puesto.materias.splice(puesto.materias.indexOf(materia), 1); materias.push(materia)"
-                                    style="cursor: pointer;">
-                                    <div class="d-flex justify-content-center">
-                                        <div class="col-2">
-                                            <span class="icono ing-borrar text-danger"></span>
+
+                        <div :id="`puesto-${puesto.puesto_id}`" class="collapse" :class="{'show': index == 0}"
+                            :aria-labelledby="`puesto-${puesto.nombre}`" data-parent="#puestos">
+                            <div class="card-body">
+                                <!-- Encargado -->
+                                <div class="form-row justify-content-around align-items-center mb-2">
+                                    <label :for="`encargado-${puesto.puesto_id}`" class="col-3">
+                                        Encargado del área
+                                    </label>
+                                    <div id="encargados" class="datalist datalist-select mb-1 col-9">
+                                        <div class="datalist-input" v-if="puesto.encargado">
+                                            ({{puesto.encargado.usuario_clave}}) {{ puesto.encargado.usuario_nombre }}
                                         </div>
-                                        <div class="col-10 text-left">
-                                            {{materia.clave_materia}} - {{materia.materia_nombre}}
+                                        <div class="datalist-input" v-else>
+                                            Selecciona un encargado
                                         </div>
+                                        <span class="icono ing-buscar"></span>
+                                        <ul style="display:none">
+                                            <li class="datalist-option" v-for="usuario in usuarios"
+                                                :key="usuario.usuario_id" :data-id="usuario.usuario_id"
+                                                style=" white-space: nowrap;" @click="puesto.encargado = usuario"
+                                                :class="{'selected': puesto.encargado?.usuario_id == usuario.usuario_id}">
+                                                (<small> {{usuario.usuario_clave}} </small>) {{ usuario.usuario_nombre }}
+                                            </li>
+                                        </ul>
+                                        <input type="hidden" id="encargado_id" name="id">
                                     </div>
-                                </li>
-                            </ul>
-                            <div class="alert alert-light" role="alert" v-else>
-                                No hay materias asignadas
-                            </div>
-                        </fieldset>
-                        <hr>
+                                </div>
+                                <hr>
 
-                        <div class="form-row justify-content-around align-items-center mb-2" v-show="carreras.length">
-                            <label :for="`carrera-${puesto.puesto_id}`" class="col-3">
-                                Carrera
-                            </label>
-                            <div id="dlCarreras" class="datalist datalist-select mb-1 col-9">
-                                <div class="datalist-input">
-                                    Selecciona una carrera
+                                <div class="form-row justify-content-around align-items-center mb-2"
+                                    v-show="carreras.length">
+                                    <label :for="`carrera-${puesto.puesto_id}`" class="col-3">
+                                        Carrera
+                                    </label>
+                                    <div id="dlCarreras" class="datalist datalist-select mb-1 col-9">
+                                        <div class="datalist-input">
+                                            Selecciona una carrera
+                                        </div>
+                                        <span class="icono ing-buscar"></span>
+                                        <ul style="display:none">
+                                            <li class="datalist-option" data-id="0" @click="selected_carrera_id = 0">
+                                                Todas las carreras
+                                            </li>
+                                            <li class="datalist-option" v-for="carrera in carreras"
+                                                :key="carrera.carrera_id" :data-id="carrera.carrera_id"
+                                                style=" white-space: nowrap;"
+                                                @click="selected_carrera_id = carrera.carrera_id">
+                                                (<small> {{carrera.clave_carrera}} </small>) {{ carrera.carrera_nombre }}
+                                            </li>
+                                        </ul>
+                                        <input type="hidden" id="carrera_id" name="id">
+                                    </div>
                                 </div>
-                                <span class="icono ing-buscar"></span>
-                                <ul style="display:none">
-                                    <li class="datalist-option" data-id="0" @click="selected_carrera_id = 0">
-                                        Todas las carreras
-                                    </li>
-                                    <li class="datalist-option" v-for="carrera in carreras" :key="carrera.carrera_id"
-                                        :data-id="carrera.carrera_id" style=" white-space: nowrap;"
-                                        @click="selected_carrera_id = carrera.carrera_id">
-                                        (<small> {{carrera.clave_carrera}} </small>) {{ carrera.carrera_nombre }}
-                                    </li>
-                                </ul>
-                                <input type="hidden" id="carrera_id" name="id">
-                            </div>
-                        </div>
-                        <div class="form-row justify-content-around align-items-center"
-                            v-scope="{to_add_materia: null}">
-                            <label :for="`materias-${puesto.puesto_id}`" class="col-3">
-                                Materias
-                            </label>
-                            <input name="materia" placeholder="Seleccione una materia" list="datalist-materias"
-                                class="form-control col-9 " v-model="current_materia" @input="to_add_materia = materias.find(m => current_materia == `${m.clave_materia} - ${m.materia_nombre}`);
+                                <div class="form-row justify-content-around align-items-center"
+                                    v-scope="{to_add_materia: null}">
+                                    <label :for="`materias-${puesto.puesto_id}`" class="col-3">
+                                        Materias
+                                    </label>
+                                    <input name="materia" placeholder="Seleccione una materia" list="datalist-materias"
+                                        class="form-control col-9 " v-model="current_materia" @input="to_add_materia = materias.find(m => current_materia == `${m.clave_materia} - ${m.materia_nombre}`);
                                 if (to_add_materia) {
+                                    if (puesto.materias.find(p => p.materia_id == to_add_materia.materia_id)) {
+                                        console.log('La materia ya está asignada');
+                                        current_materia = null;
+                                        return;
+                                    }
                                     puesto.materias.push(to_add_materia);
                                     materias.splice(materias.indexOf(to_add_materia), 1);
                                     current_materia = null;
                                 }" :disabled="selected_carrera_id == -1" v-model="current_materia"
-                                :id="`materias-${puesto.puesto_id}`">
+                                        :id="`materias-${puesto.puesto_id}`" autocomplete="off">
+                                </div>
+                                <datalist id="datalist-materias">
+                                    <option
+                                        v-for="materia in materias.filter(m => selected_carrera_id == 0 || m.carrera_id == selected_carrera_id).filter(m => !puesto.materias.find(p => p.materia_id == m.materia_id))"
+                                        :value="`${materia.clave_materia} - ${materia.materia_nombre}`">
+                                </datalist>
+
+                                <hr>
+                                <fieldset class="container d-flex flex-column justify-content-center align-items-center">
+                                    <legend>Materias Asignadas <span
+                                            class="badge badge-secondary">{{puesto.materias.length}}</span></legend>
+                                    <ul class="list-group overflow-auto col-10" v-if="puesto.materias.length"
+                                        style="max-height: 200px; overflow-y: auto;">
+                                        <li class="list-group-item list-group-item-action"
+                                            v-for="materia in puesto.materias" :key="materia.materia_id"
+                                            @click="puesto.materias.splice(puesto.materias.indexOf(materia), 1); materias.push(materia)"
+                                            style="cursor: pointer;">
+                                            <div class="d-flex justify-content-center">
+                                                <div class="col-2 text-center">
+                                                    <span class="icono ing-borrar text-danger"></span>
+                                                </div>
+                                                <div class="col-10 text-left">
+                                                    {{materia.clave_materia}} - {{materia.materia_nombre}}
+                                                </div>
+                                            </div>
+                                        </li>
+                                    </ul>
+                                    <div class="alert alert-light" role="alert" v-else>
+                                        No hay materias asignadas
+                                    </div>
+                                </fieldset>
+
+                            </div>
+                            <div class="card-footer text-muted">
+                                <!-- scroll to top -->
+                                <button type="button" class="btn btn-outline-primary btn-lg btn-block"
+                                    @click="actualizarPuesto(puesto.puesto_id, puesto.materias, puesto.encargado?.usuario_id)"
+                                    onclick="window.scrollTo(0, 0);">
+                                    {{ puesto.encargado ? 'Guardar cambios' : 'Guardar sin encargado' }}
+                                </button>
+                            </div>
                         </div>
-                        <datalist id="datalist-materias">
-                            <option
-                                v-for="materia in materias.filter(m => selected_carrera_id == 0 || m.carrera_id == selected_carrera_id)"
-                                :value="`${materia.clave_materia} - ${materia.materia_nombre}`">
-                        </datalist>
                     </div>
-                    <div class="card-footer text-muted">
-                        <button type="button" class="btn btn-outline-primary btn-lg btn-block" v-if="puesto.encargado"
-                            @click="actualizarPuesto(puesto.puesto_id, puesto.materias, puesto.encargado.usuario_id)">
-                            Guardar cambios
-                        </button>
+                </div>
+                <div v-else>
+                    <div class="alert alert-dark" role="alert">
+                        No hay puestos registrados
                     </div>
                 </div>
             </div>
-        </div>
 
-        <div class="modal" tabindex="-1" role="dialog" accesskey="a" id="nuevo-puesto">
-            <div class="modal-dialog modal-dialog-centered" role="document">
-                <div class="modal-content">
-                    <div class="modal-header text-white">
-                        <h5 class="modal-title">Agregar un nuevo puesto</h5>
-                        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
-                            <span aria-hidden="true" class="text-white">&times;</span>
-                        </button>
-                    </div>
-                    <div class="modal-body">
-                        <fieldset>
-                            <legend>Nombre del puesto</legend>
-                            <div class="form-row">
-                                <input type="text" class="form-control" v-model="new_puesto"
-                                    placeholder="Área del puesto">
-                            </div>
-                        </fieldset>
+            <div class="modal" tabindex="-1" role="dialog" accesskey="a" id="nuevo-puesto">
+                <div class="modal-dialog modal-dialog-centered" role="document">
+                    <div class="modal-content">
+                        <div class="modal-header text-white">
+                            <h5 class="modal-title">Agregar un nuevo puesto</h5>
+                            <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                                <span aria-hidden="true" class="text-white">&times;</span>
+                            </button>
+                        </div>
+                        <div class="modal-body">
+                            <fieldset>
+                                <legend>Nombre del puesto</legend>
+                                <div class="form-row">
+                                    <input type="text" class="form-control" v-model="new_puesto"
+                                        placeholder="Área del puesto">
+                                </div>
+                            </fieldset>
+                        </div>
+                        <div class="modal-footer">
+                            <button type="button" class="btn btn-outline-danger" data-dismiss="modal"
+                                @click="new_puesto = null">Cancelar</button>
+                            <button type="button" class="btn btn-primary" data-dismiss="modal"
+                                @click="nuevoPuesto(new_puesto); new_puesto = null">Guardar</button>
+                        </div>
                     </div>
-                    <div class="modal-footer">
-                        <button type="button" class="btn btn-outline-danger" data-dismiss="modal"
-                            @click="new_puesto = null">Cancelar</button>
-                        <button type="button" class="btn btn-primary" data-dismiss="modal"
-                            @click="nuevoPuesto(new_puesto)">Guardar</button>
+                </div>
+            </div>
+            <div class="modal" tabindex="-1" role="dialog" accesskey="a" id="eliminar-puesto">
+                <div class="modal-dialog modal-dialog-centered" role="document" v-if="to_delete">
+                    <div class="modal-content">
+                        <div class="modal-header text-white">
+                            <h5 class="modal-title">Eliminar puesto</h5>
+                            <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                                <span aria-hidden="true" class="text-white">&times;</span>
+                            </button>
+                        </div>
+                        <div class="modal-body">
+                            <fieldset>
+                                <legend>¿Estás seguro de que deseas eliminar el puesto?</legend>
+                                <p>Esta acción no se puede deshacer. Se perderán las asignaciones de materias y de
+                                    encargado.</p>
+                            </fieldset>
+                        </div>
+                        <div class="modal-footer">
+                            <button type="button" class="btn btn-outline-danger" data-dismiss="modal"
+                                @click="new_puesto = null">Cancelar</button>
+                            <button type="button" class="btn btn-danger" data-dismiss="modal"
+                                @click="eliminarPuesto(to_delete.puesto_id)">Eliminar</button>
+                        </div>
                     </div>
                 </div>
             </div>
-        </div>
-    </main>
-
-    <? include "import/html_footer.php"; ?>
+        </main>
 
+        <?
+    } else {
+        ?>
+        <main class="container mt-5" style="min-height: 70vh;">
+            <div class="row">
+                <div class="col-md-8 offset-md-2">
+                    <div class="card">
+                        <div class="card-header text-white bg-danger">
+                            Sin Facultad Asociada
+                        </div>
+                        <div class="card-body">
+                            <h5 class="card-title">Atención</h5>
+                            <p class="card-text">No tienes una facultad asociada a tu perfil. El rol
+                                <?= $user->rol['rol'] ?> no tiene acceso a esta sección.
+                            </p>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </main>
+    <? }
+    include "import/html_footer.php"; ?>
     <script src="js/jquery.min.js"></script>
     <script src="js/jquery-ui.js"></script>
     <script src="js/bootstrap/bootstrap.min.js"></script>

+ 63 - 21
reposiciones_autorizar.php

@@ -9,7 +9,7 @@ if (!isset($_SESSION['user'])){
 $user = Login::get_user();
 
 $user->access();
-echo $user;
+//echo $user;
 /*print_r($user);
 print_r($user->user["id"]);
 echo "****|";
@@ -53,7 +53,7 @@ if($user->periodo_id!= ""){
         $carrera_rs = $db->query('SELECT * FROM fs_profesor_facultad(NULL, :periodo)', [ ':periodo' => $user->periodo_id]);
     }
 
-    $salones_rs = $db->query('SELECT * FROM salon_view WHERE tiene_salones IS true');
+    $salones_rs = $db->query('SELECT * from salon_view where es_salon is true');
 
     //Periodo
     $periodo_rs = $db->querySingle('SELECT periodo_fecha_inicio, periodo_fecha_fin FROM periodo WHERE periodo_id = :periodo_id', [':periodo_id' => $user->periodo_id]);
@@ -227,7 +227,7 @@ if($user->periodo_id!= ""){
                 <a class="nav-link" id="tab3-tab" data-toggle="tab" href="#tab3" role="tab" aria-controls="lista" aria-selected="false">Autorizadas por Vicerrectoría</a>
             </li>
             <li class="nav-item">
-                <a class="nav-link" id="tab4-tab" data-toggle="tab" href="#tab4" role="tab" aria-controls="lista" aria-selected="false">Rechazadas</a>
+                <a class="nav-link" id="tab4-tab" data-toggle="tab" href="#tab4" role="tab" aria-controls="lista" aria-selected="false">Declinadas</a>
             </li>
         </ul>
         <div class="tab-content" id="TabContent">
@@ -303,7 +303,8 @@ if($user->periodo_id!= ""){
                             </td>
                             <td class="text-center align-middle"><?php
                                 if($reposicion["salon_id"] != ""){
-                                    echo $reposicion["salon_id"];
+                                    $salon_json = json_decode($reposicion["salon_array"], true);
+                                    echo $salon_json[count($salon_json)-1];
                                 }else
                                     echo "Pendiente";
                                 ?>
@@ -313,13 +314,13 @@ if($user->periodo_id!= ""){
                             <td class="text-center align-middle icono-acciones text-nowrap">
                                 <?php if (duracionMinutos($reposicion["fecha_nueva"], date("Y-m-d H:i:00")) < 0){ ?>
                                     <?php //no se cumple la fecha de la reposicion, es jefe de carrera
-                                    if(($user->jefe_carrera || $user->admin) && $reposicion["estado_reposicion_id"] == 1){?>
+                                    if((!$user->jefe_carrera || $user->admin || !$coordinador) && $reposicion["estado_reposicion_id"] == 1){?>
                                     <a href="#" data-toggle="modal" data-target="#modal_aprobar" data-tipo="2" title="Aprobar"><?php echo $ICO["ver"];?></a>
                                     <?php } //no se cumple la fecha de la reposicion, no es jefe de carrera
-                                    else if((!$user->jefe_carrera || $user->admin) && $reposicion["estado_reposicion_id"] >= 2){?>
+                                    else if(($supervisor || $user->admin) && $reposicion["estado_reposicion_id"] == 2){?>
                                     <a href="#" data-toggle="modal" data-target="#modal_aprobar" data-tipo="3" title="Autorizar" ><?php echo $ICO["ver"];?></a>
                                     <?php } else { ?>
-                                        <a href="#" data-toggle="modal" data-target="#modal_aprobar" data-tipo="1" title="Aprobar"><?php echo $ICO["ver"];?></a>
+                                        <a href="#" data-toggle="modal" data-target="#modal_aprobar" data-tipo="1" title="Ver detalle"><?php echo $ICO["ver"];?></a>
                                     <?php } ?>
                                     <?php
                                 }else{ //fecha ya pasó?>
@@ -375,6 +376,14 @@ if($user->periodo_id!= ""){
                                     <p class="rep-prof"></p>
                                 </div>
                             </div>
+                            <div class="row">
+                                <div class="col-6 col-sm-4 barra-right text-right">
+                                    <p class="font-weight-bold">Dependencia</p>
+                                </div>
+                                <div class="col-6">
+                                    <p class="rep-fac"></p>
+                                </div>
+                            </div>
                             <div class="row">
                                 <div class="col-6 col-sm-4 barra-right text-right">
                                     <p class="font-weight-bold">Materia</p>
@@ -461,13 +470,18 @@ if($user->periodo_id!= ""){
                                         <?php
                                         foreach ($salones_rs as $salon) {
                                             extract($salon);
+                                            $salon_json = json_decode($salon_array, true);
+                                            if($salon_json[0]== "UNIVERSIDAD LA SALLE"){
+                                                unset($salon_json[0]);
+                                            }
+                                            $salon_nombre = join(" / ",$salon_json);
                                         ?>
-                                            <option data-id="<?= $salon_id ?>" data-nombre="<?= $salon ?>" value="<?= $salon ?>"></option>
+                                            <option data-id="<?= $salon_id ?>" data-nombre="<?= $salon_nombre ?>" value="<?= $salon_nombre ?>"></option>
                                         <?php
                                         }
                                         ?>
                                     </datalist>
-                                    <ul class="list-group" id="salones"></ul>
+                                    <!-- <ul class="list-group" id="salones"></ul> -->
                                     <input type="hidden" id="salon" name="salon" value="">
                                 </div>
                             </div>
@@ -610,6 +624,27 @@ if($user->periodo_id!= ""){
             $("#motivo").val("")
         });
 
+       
+
+        $('#dlSalon').on('change', function() {
+            const selectedValue = $(this).val();
+            //console.log(selectedValue)
+            const selectedOption = $(`option[value="${selectedValue}"]`);
+            //console.log(selectedOption.length)
+
+            const salonesList = $('#salones');
+
+            if (selectedOption.length) {
+                const salonId = selectedOption.data('id');
+                $('#salon').val(salonId);
+                //const salonNombre = selectedOption.data('nombre');
+                //salonesList.html(`<li class="list-group-item">${salonNombre}</li>`);
+            } else {
+                $('#salon').val('');
+                //salonesList.empty();
+            }
+        });
+
         $('#modal_aprobar').on('show.bs.modal', function (event) {
             var button = $(event.relatedTarget); // Button that triggered the modal
             var id = button.parents("tr").data("id");
@@ -619,7 +654,6 @@ if($user->periodo_id!= ""){
             $("#edo").val(edo);
             $("#id").val(id);
             
-            
 
             $.ajax({
                 url:  './action/reposicion_select.php',
@@ -631,8 +665,9 @@ if($user->periodo_id!= ""){
                         triggerMessage(result["error"], "Error");
                         $('#modal_aprobar').modal("hide");
                     }else{
-
+                        $("#dlSalon").val("");
                         $("#modal_aprobar .rep-prof").text(result["profesor_nombre"]);
+                        $("#modal_aprobar .rep-fac").text(result["facultad"]);
                         $("#modal_aprobar .rep-mat").text(result["materia_desc"]);
                         $("#modal_aprobar .rep-ciclo").text(result["ciclo"]);
                         $("#modal_aprobar .rep-bloque").text(result["bloque"]);
@@ -663,23 +698,30 @@ if($user->periodo_id!= ""){
                         if(edo == 1){// 1  ver
                             $("#modalLabel").text("Detalle de reposición");
                             $(".aprobar-block").hide();
+
+                            /*if(parseInt($("#modal_aprobar .rep-aula").data("aula")) != 1){//tipo aula 1 (salon normal)  - ver
+                                $("#salon-ver").hide();
+                                $("#salon-editar").show();
+                            }else{
+                                $("#salon-ver").show();
+                                $("#salon-editar").hide();
+                            }*/
                             $("#salon-ver").show();
                             $("#salon-editar").hide();
                             
                         }else{
-                            if(parseInt($("#modal_aprobar .rep-aula").data("aula")) == 1){//tipo aula 1 (salon normal)  - ver
-                                $("#modalLabel").text("Detalle de reposición");
-                                $(".aprobar-block").hide();
+                            $("#modalLabel").text("Aprobar reposición");
+                            $(".aprobar-block").show();
+
+                            if(edo == 2 && parseInt($("#modal_aprobar .rep-aula").data("aula")) == 1){//tipo aula 1 (salon normal)  - ver
+                                $("#salon-ver").show();
+                                $("#salon-editar").hide();
+                            }else if(edo == 3 && parseInt($("#modal_aprobar .rep-aula").data("aula")) != 1){//aprobar (con salón especial)
                                 $("#salon-ver").show();
                                 $("#salon-editar").hide();
                             }else{
-                                $("#modalLabel").text("Aprobar reposición");
-                                $(".aprobar-block").show();
-                                if(edo == 3){//aprobar (con salón)
-                                    $("#salon-ver").hide();
-                                    $("#salon-editar").show();
-                                    
-                                }
+                                $("#salon-ver").hide();
+                                $("#salon-editar").show();
                             }
                         }
 

+ 92 - 66
reposiciones_crear.php

@@ -24,7 +24,6 @@ if ($user->acceso === null && !$user->admin){
     exit();
 }
 
-
 //if (!$user->admin && in_array($user->acceso, ['n']))
     //die(header('Location: main.php?error=1'));
 //$user->print_to_log('Reposiciones');
@@ -34,51 +33,59 @@ $write = true; //
 
 $en_fecha = $db->querySingle("SELECT ESTA_EN_PERIODO(NOW()::DATE, :periodo_id)", [':periodo_id' => $user->periodo_id])['esta_en_periodo'];
 
-if($user->jefe_carrera){
+//if($user->jefe_carrera){
 
-    $prof_rs = $db->query('SELECT DISTINCT * FROM fs_profesores(null, null, :fac) ORDER BY PROFESOR_NOMBRE', [':fac' => $user->facultad["facultad_id"]]);
-}
+    //$prof_rs = $db->query('SELECT DISTINCT * FROM fs_profesores(null, null, :fac) ORDER BY PROFESOR_NOMBRE', [':fac' => $user->facultad["facultad_id"]]);
+    $prof_rs = $db->query('SELECT DISTINCT PROFESOR.* FROM PUESTO_USUARIO
+        JOIN PUESTO_MATERIA USING (PUESTO_ID)
+        JOIN HORARIO_VIEW USING (MATERIA_ID)
+        JOIN HORARIO_PROFESOR USING (HORARIO_ID)
+        JOIN PROFESOR USING (PROFESOR_ID)
+        WHERE USUARIO_ID = :usr', [':usr' => $user->user["id"]]);
+//}
 
 //Duraciones
 $duracion_rs = $db->query("select * from duracion order by duracion_interval");
 
-//Periodo
-$periodo_rs = $db->querySingle('SELECT periodo_fecha_inicio, periodo_fecha_fin FROM periodo WHERE periodo_id = :periodo_id', [':periodo_id' => $user->periodo_id]);
-$periodo_fin = $periodo_rs["periodo_fecha_fin"];
-if(strtotime($periodo_rs["periodo_fecha_inicio"])>strtotime(date("Y-m-d")) )
-    $fecha_man = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_inicio"]));
-else{
-    $dias = 3;
-    if( intval(date("w")) >=3 && intval(date("w"))<=5 )//Mie a Vie
-        $dias+=3;
-    else if( intval(date("w")) ==6 )//Sab
-        $dias+=2;
-    else if( intval(date("w")) ==0 )//Do
-        $dias+=1;
-    
-    $fecha_man = date("d/m/Y", strtotime("+".$dias." day"));
+if(!is_null($user->periodo_id)){
+    //Periodo
+    $periodo_rs = $db->querySingle('SELECT periodo_fecha_inicio, periodo_fecha_fin FROM periodo WHERE periodo_id = :periodo_id', [':periodo_id' => $user->periodo_id]);
+    $periodo_fin = $periodo_rs["periodo_fecha_fin"];
+    if(strtotime($periodo_rs["periodo_fecha_inicio"])>strtotime(date("Y-m-d")) )
+        $fecha_man = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_inicio"]));
+    else{
+        $dias = 3;
+        if( intval(date("w")) >=3 && intval(date("w"))<=5 )//Mie a Vie
+            $dias+=3;
+        else if( intval(date("w")) ==6 )//Sab
+            $dias+=2;
+        else if( intval(date("w")) ==0 )//Do
+            $dias+=1;
+        
+        $fecha_man = date("d/m/Y", strtotime("+".$dias." day"));
+    }
+    /*
+    // Materias
+    $id_prof = $user->profesor;
+    //$facultad_id = 28;
+    $materias_rs = $db->query('SELECT * FROM fs_materiasprofesor(:id)', [':id' => $id_prof]);
+    */
+    if(isset($_POST["fecha_inicial"]))
+        $fecha_ini = $_POST["fecha_inicial"];
+    else
+        $fecha_ini = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_inicio"]));
+
+    if(isset($_POST["fecha_final"]))
+        $fecha_fin = $_POST["fecha_final"];
+    else
+        $fecha_fin = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_fin"]));
+
+    $date = DateTime::createFromFormat('d/m/Y', $fecha_ini);
+    $fecha_ini_db = $date->format('Y-m-d');
+
+    $date = DateTime::createFromFormat('d/m/Y', $fecha_fin);
+    $fecha_fin_db = $date->format('Y-m-d');
 }
-/*
-// Materias
-$id_prof = $user->profesor;
-//$facultad_id = 28;
-$materias_rs = $db->query('SELECT * FROM fs_materiasprofesor(:id)', [':id' => $id_prof]);
-*/
-if(isset($_POST["fecha_inicial"]))
-    $fecha_ini = $_POST["fecha_inicial"];
-else
-    $fecha_ini = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_inicio"]));
-
-if(isset($_POST["fecha_final"]))
-    $fecha_fin = $_POST["fecha_final"];
-else
-    $fecha_fin = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_fin"]));
-
-$date = DateTime::createFromFormat('d/m/Y', $fecha_ini);
-$fecha_ini_db = $date->format('Y-m-d');
-
-$date = DateTime::createFromFormat('d/m/Y', $fecha_fin);
-$fecha_fin_db = $date->format('Y-m-d');
 
 ?>
 <!DOCTYPE html>
@@ -132,7 +139,7 @@ $fecha_fin_db = $date->format('Y-m-d');
         <?php }?>
         <section id="message"></section>
         <?php require('import/periodo.php') ?>
-        
+        <?php if(!is_null($user->periodo_id)) { ?>
         <form id="asistencia" method="post" onsubmit="return validaFechas()">
             <div class="form-box">
                 <input type="hidden" name="facultad" value="">
@@ -160,8 +167,8 @@ $fecha_fin_db = $date->format('Y-m-d');
 
         <?php
         
-        $reposiciones_rs = $db->query('SELECT * FROM fs_reposiciones_solicitud(:f_ini, :f_fin, :usr ,NULL, NULL)', [':f_ini' => $fecha_ini_db, ':f_fin' => $fecha_fin_db, ':usr' => $user->user["id"]]);
-        
+            $reposiciones_rs = $db->query('SELECT * FROM fs_reposiciones_solicitud(:f_ini, :f_fin, :usr ,NULL, NULL)', [':f_ini' => $fecha_ini_db, ':f_fin' => $fecha_fin_db, ':usr' => $user->user["id"]]);
+        }
         ?>
 
         <div class="row">
@@ -245,11 +252,17 @@ $fecha_fin_db = $date->format('Y-m-d');
                     </tbody>
                 </table>
             </div>
-            <?php } else { ?>
+            <?php } else { 
+                if(is_null($user->periodo_id)){ ?>
+            <div class="col-12 text-center">
+                <h4 class="mt-4 text-danger">Selecciona un periodo</h4>
+            </div>
+            <?php } else {?>    
             <div class="col-12 text-center">
                 <h4 class="mt-4 text-danger">No tienes reposiciones disponibles que cumplan con los filtros</h4>
             </div>
-            <?php } ?>
+            <?php }
+            } ?>
         </div>
 
         <div class="modal fade" id="modal" tabindex="-1" role="dialog" aria-labelledby="modal" aria-hidden="true">
@@ -752,15 +765,13 @@ $fecha_fin_db = $date->format('Y-m-d');
             $("#filtro_final").removeClass("is-invalid");
         });
 
-        $("#dlProfesor ul li").click(function(){//cambia datalist
-            var pid = $(this).data('id');
-            //busca materias del profesor
-            $.ajax({
+        function obtieneProf(pid){
+            return $.ajax({
                 url:  './action/reposicion_profesor_materias.php',
                 type: 'POST', 
                 dataType: 'json',
                 data: { id: pid, },
-                async: false,
+                //async: false,
                 success: function(result) {
                     if(result["error"]!= "" &&  result["error"] !== undefined){
                         triggerMessage(result["error"], "Error");
@@ -780,29 +791,42 @@ $fecha_fin_db = $date->format('Y-m-d');
                                 );
                             $("#dlMateria ul").append(html);
                         }
-                        //setDatalistFirst("#horario");
-                        $("#dlMateria ul li:first").click();
                     }
                 },
                 error: function(jqXHR, textStatus, errorThrown ){
                     triggerMessage(errorThrown, "Error");
                 }
             });//ajax
-            
+        }
+
+        $(document).on( "click", "#dlProfesor ul li", function(event){//cambia datalist
+            var pid = $(this).data('id');
+            //busca materias del profesor
+            var profCarga = obtieneProf(pid);
+            profCarga.done(function(){
+                $("#dlMateria ul li:first").click();
+            });
         });
         
         
         //Actualiza días elegibles de calendario
         $(document).on( "click", "#dlMateria ul li", function(event){//manda al frente de todos
-            _dia_valido = $(this).data('dia');
+            _dia_valido = $(this).data('dia');//variable global
             var grupo = $(this).data("gpo");
             var duracionMateria = $(this).data("duracion");
 
-            $.ajax({
+            $(".date-picker" ).datepicker(datepickerOptions);
+            var hora = $(this).data("hr");
+            var min = $(this).data("min");
+            $("#hora_ini").val(hora)
+            $("#min_ini").val(min)
+
+            return $.ajax({
                 url:  './action/asistenciasprofesor_select.php',
                 type: 'POST', 
                 dataType: 'json',
                 data: { "id": $("#prof").val(), "hor": $(this).data("id") },
+                //async: false,
                 success: function(result) {
                     if(result["error"]!= "" &&  result["error"] !== undefined){
                         triggerMessage(result["error"], "Error");
@@ -819,7 +843,6 @@ $fecha_fin_db = $date->format('Y-m-d');
                                 $(this).prop('selected', true);
                             }
                         });
-                        console.log("fin materia click");
                     }
 
                 },
@@ -827,12 +850,8 @@ $fecha_fin_db = $date->format('Y-m-d');
                     triggerMessage(errorThrown, "Error");
                 }
             });//ajax
-
-            $(".date-picker" ).datepicker(datepickerOptions);
-            var hora = $(this).data("hr");
-            var min = $(this).data("min");
-            $("#hora_ini").val(hora)
-            $("#min_ini").val(min)
+            
+            
         });
         
         $("#dlTipo ul li").click(function(){//cambia datalist
@@ -857,7 +876,7 @@ $fecha_fin_db = $date->format('Y-m-d');
                     if(result["error"]!= "" &&  result["error"] !== undefined){
                         triggerMessage(result["error"], "Error");
                     }else{
-                        triggerMessage(result["ok"], "Éxito");
+                        triggerMessage(result["ok"], "Éxito", "success");
                         $("#id"+r_id).remove();
                     }
                 },
@@ -919,13 +938,17 @@ $fecha_fin_db = $date->format('Y-m-d');
                     type: 'POST', 
                     dataType: 'json',
                     data: { id: r_id },
+                    async: true,
                     success: function(result) {
                         if(result["error"]!= "" &&  result["error"] !== undefined){
                             triggerMessage(result["error"], "Error");
                             $("#modal").modal('hide');
                         }else{
                             //setDatalist("#prof", result["profesor"]);
-                            setDatalist("#prof", result["profesor"])
+                            setDatalist("#prof", result["profesor"]);
+                            
+                            var profCarga = obtieneProf(result["profesor"]);
+
                             //$('#salon').val(result["salon"]);
                             $("#fecha_falta").val(result["fecha_clase"]);
                             $('#hora_ini').val(result["hora_ini"]);
@@ -947,8 +970,11 @@ $fecha_fin_db = $date->format('Y-m-d');
                             _dia_valido = parseInt(result["dia"]);
                             $(".date-picker" ).datepicker(datepickerOptions);
                             $("#dlTipo ul li:selected").click();
-                            console.log("llega a cambio horario"+result["horario"]);
-                            setTimeout(setDatalist("#horario", result["horario"]), 20);// No se actualiza TODO
+                            
+                            
+                            profCarga.done(function(){
+                                setDatalist("#horario", result["horario"]);// No se actualiza TODO
+                            });
                             setDatalist("#aula", result["aula"]);
                             modal.modal('show');
                         }

+ 43 - 2
ts/horario.ts

@@ -38,6 +38,21 @@ type Horario = {
     bloques: number;
 }
 
+type Facultad = {
+    clave_dependencia: string;
+    facultad_id: number;
+    facultad_nombre: string;
+    carreras: Carrera[];
+}
+
+type Carrera = {
+    carrera_id: number;
+    carrera_nombre: string;
+    clave_carrera: string;
+    facultad_id: number;
+}
+
+
 
 const profesores = reactive({
     data: [] as Profesor[],
@@ -55,6 +70,26 @@ const profesores = reactive({
     },
 })
 
+const facultades = reactive({
+    data: [] as Facultad[],
+    fetch: async function () {
+        const facultades = await fetch('action/action_facultad.php').then(response => response.json()) as Facultad[]
+        const carreras = await fetch(`action/carrera.php`).then(response => response.json()) as Carrera[]
+        this.data = await Promise.all(facultades.map(async facultad => ({
+            ...facultad,
+            carreras: await Promise.all(carreras.filter((carrera: Carrera) => carrera.facultad_id === facultad.facultad_id).map(async (carrera: Carrera) => {
+                const grupos = await fetch(`action/action_grupo.php?carrera_id=${carrera.carrera_id}`).then(response => response.json())
+                return {
+                    ...carrera,
+                    grupos,
+                }
+            })),
+        })))
+
+        this.data = this.data.filter((facultad: Facultad) => facultad.carreras.length > 0)
+    }
+})
+
 type Structure = {
     sábado: boolean;
     hora_mínima: number;
@@ -64,8 +99,12 @@ type Structure = {
 
 const horarios = reactive({
     data: [] as Horario[],
-    fetch: async function () {
-        if (profesores.current) {
+    fetch: async function (grupo: number | null = null, carrera_id: number | null = null) {
+        if (grupo && carrera_id) {
+            const response = await fetch(`action/action_horario.php?grupo=${grupo}&carrera_id=${carrera_id}`)
+            this.data = await response.json()
+        }
+        else if (profesores.current) {
             const response = await fetch(`action/action_horario.php?profesor_id=${profesores.current.profesor_id}`)
             this.data = await response.json()
         }
@@ -134,7 +173,9 @@ const horarios = reactive({
 const app = createApp({
     profesores,
     horarios,
+    facultades,
     mounted: async function () {
         await profesores.fetch()
+        await facultades.fetch()
     }
 }).mount('#app')

+ 29 - 1
ts/puestos.ts

@@ -41,13 +41,41 @@ const app = createApp({
             })
             const data = await res.json()
             this.puestos.push(data)
+            // order by puesto.nombre
+            this.puestos.sort((a: Puesto, b: Puesto) => a.nombre.localeCompare(b.nombre))
         } catch (error) {
             alert(`Error: ${error}`)
 
         }
     },
 
-    async actualizarPuesto(puesto_id: number, materias: Materia[], usuario_id: number) {
+    to_delete: null as Puesto | null,
+    async eliminarPuesto(puesto_id: number) {
+        try {
+            const res = await fetch('action/puesto.php', {
+                method: 'DELETE',
+                body: JSON.stringify({
+                    puesto_id
+                })
+            })
+            const data = await res.json()
+            this.message = data.msg;
+
+            // after 3 seconds, remove the message
+            setTimeout(() => {
+                this.message = null
+            }, 3000)
+
+            this.puestos = this.puestos.filter((p: Puesto) => p.puesto_id !== puesto_id)
+            // order by puesto.nombre
+            this.puestos.sort((a: Puesto, b: Puesto) => a.nombre.localeCompare(b.nombre))
+        } catch (error) {
+            alert(`Error: ${error}`)
+
+        }
+    },
+
+    async actualizarPuesto(puesto_id: number, materias: Materia[], usuario_id: number | null) {
         try {
             const res = await fetch('action/puesto.php', {
                 method: 'PUT',