3.4.17. Gestión de gastos - diezMalena/api_FCTFiller GitHub Wiki

Introducción

Esta sección de la aplicación permite gestionar la hoja de gastos (Anexo VI), la confirmación de los mismos (Anexo V) y la confirmación de los trayectos (Anexo VII) de los alumnos de un grupo durante el transcurso de la Formación en Centros de Trabajo.

Vista de profesor

Cuando se accede a esta vista, se realiza una petición al servidor mediante el servicio de cliente de Angular GestionGastosService. Se invoca al método obtenerGastosProfesor() que llama a la ruta API api/gestionGastosProfesor [get]. Se obtiene un listado de entidades de la tabla Gasto, que incluye a los alumnos a los cuales los profesores han dado de alta para registrar sus gastos (se muestran en la tabla de la vista). Además, se obtiene en esta respuesta un listado de los alumnos tutorizados por el profesor que no están en esta tabla (se encuentran en el desplegable del botón "Añadir alumno")

Desde esta vista el tutor del centro educativo puede eliminar y editar los datos de los alumnos (accediendo a la vista en "modo" alumno), así como dar de alta nuevos billetes de transporte o de manutención para cada uno de los alumnos. También se pueden descargar los anexos VI y VII.

Anexo VI

En este libro de Excel se refleja el sumatorio de gastos en los que incurren los alumnos en sus prácticas. No se tienen en cuenta todos los gastos, sólo los gastos de locomoción y manutención extraordinarios relativos a la asistencia a las prácticas. Sólo se cubren en los siguientes supuestos:

  • Si el centro educativo se encuentra en la misma localidad de residencia del alumno y el centro de trabajo se encuentra a las afueras de esta o en otra localidad.
  • Si la residencia del alumno se encuentra en una localidad distinta a la del centro educativo y la distancia que los separa es menor que la distancia desde la residencia del alumno al centro de trabajo.
  • Si se cumple alguno de los anteriores casos y los gastos de manutención no superan los 9 euros.
  • El cálculo de la compensación por vehículo propio se calcula con la distancia de ida y vuelta absoluta multiplicado por 2 (se cubre ida y vuelta) multiplicado por el coeficiente 0,12€/Km.

Una vez tenidos en cuenta estos requisitos, se puede descargar el anexo. Para ello, haciendo click en el botón "Descargar Anexo VI" se invoca la función descargarAnexoVI() en el servicio, que realiza la petición a la ruta api/descargarAnexoVI [get].

Se utiliza la librería PhpOffice/PhpSpreadSheet para tratar libros de Excel. Tan sólo se necesita conocer el rango de columnas donde se encuentran los datos e iterar sobre ellas. Para ver cómo rellenar datos en un libro de Excel, consultar xxxxxxxxxxxxx.

Para completar este anexo se precisan de algunos datos que no persisten en base de datos por lo que se han creado las algunas funciones en la API Laravel que contienen la lógica presentada al inicio de la explicación de este anexo:

//Este método decide si el alumno tiene o no derecho compensación por gastos. 
$gasto->sumatorio_gasto_vehiculo_privado = $this->calcularGastoVehiculoPrivado($gasto);
//Estos dos métodos realizan un sumatorio de las cantidades de los tickets.
$gasto->sumatorio_gasto_transporte_publico = $this->calcularGastoTransportePublico($dni_alumno);
$gasto->sumatorio_gasto_manutencion = $this->calcularGastoManutencion($dni_alumno);

Tras generarse y guardarse el anexo en la correspondiente carpeta del tutor, desde la API se devuelve una Response del tipo download($pathAnexoVI), que envía una señal de descarga del fichero pasado por parámetro al cliente.

Anexo VII

Una vez los alumnos de un grupo hayan confirmado sus gastos de transporte privado, el tutor puede confirmar los trayectos que han realizado y subir el documento firmado por el director (Anexo VII).

La confirmación de trayectos sigue el siguiente proceso:

  1. En GestionGastosProfesorComponent, el método asíncrono confirmarTrayectos(), previa confirmación por parte del usuario, se subscribe al método confirmarTrayectos del servicio GestionGastosService, pasándole un objeto Gasto[] con los gastos de los alumnos que tienen algún día de transporte privado computado. El resto del proceso es igual que en la confirmación de gastos
  2. En GestionGastosService, el método confirmarTrayectos(gastos: Gasto[]) hace una petición POST al servidor mediante la ruta /confirmar_trayectos, enviándole el vector de gastos y devolviendo un Observable con la respuesta del servidor, que contiene la ruta del anexo generado.
  3. En el ControladorTutorFCT de la API se llama a la función confirmarTrayectos(Request $req). El Anexo VII se conforma de una parte con datos generales (la cabecera y la firma) y otra con una tabla de 12 filas para los alumnos. Podemos dividir este paso en varias partes:
    1. Extracción de las variables generales para el documento: tutor (Profesor), centro (CentroEstudios), curso (AuxCursoAcademico), Grupo, FamiliaProfesional y director (Profesor). Estos datos, junto con los de la fecha, se establecen en el documento y se da paso a la siguiente parte.
    2. Recorrido del vector de gastos para el relleno de la tabla.
      • Si en la posición del vector hay datos. Sólo se deben extraer los datos de la empresa (a través de la tabla fct y mediante el DNI del alumno y el curso académico) y calcular los campos de distancia diaria (calcularSumaKMVehiculoPrivado) y total de Kms.
      • Si no hay datos en la posición del vector, se establecen los datos como '-'.
    3. Se guarda el documento en el subdirectorio del Anexo VII del tutor y se crea un registro nuevo en la tabla anexos (previa eliminación por si ya hubiera otro con el mismo grupo).
    4. Se envía una response JSON con la ruta del anexo si todo ha salido bien y con los códigos de estado típicos.

La subida del documento firmado sigue un proceso muy similar al del Anexo V:

  1. En el componente, el método subirAnexoVII(event: any) construye un objeto con el curso académico del primer alumno del vector (todos tendrán el mismo) y el archivo en Base64. Este objeto se lo pasa al método homónimo del servicio FileUploadService, al cual se subscribe. Dentro de la subscripción, únicamente se invoca un toastr informando del éxito o del error de la operación.
  2. En FileUploadService, el método subirAnexoVII(datos: object) hace una petición POST al servidor mediante la ruta /firmar_anexo_vii, enviándole los datos en formato JSON y devolviendo un Observable con la respuesta del servidor.
  3. En la API, se llama al método subirAnexoVII(Request $req), del controlador de tutores. El proceso es el mismo que la subida del Anexo V.

Vista de alumno

Al acceder a esta vista, se visualiza el listado de facturas de transporte y manutención, así como el recuento de los subtotales de los gastos acumulados por un alumno en concreto.

Cuando un alumno (o profesor) accede a esta vista, se realiza una invocación del método obtenerGastosAlumno(dni: string) del servicio GestionGastosService, que realiza una petición a la ruta API api/gestionGastosAlumno/{$dni_alumno} [get]. La API responde con un JSON que incluye el objeto de la tabla Gasto del alumno en cuestión y dos arrays adicionales que contienen un listado de modelos FacturaManutencion y FacturaTransporte

Tras recoger la información que entrega la llamada, se hace una suscripción .next([...]) a un objeto del tipo Subject<any> que actúa como observador y observable, dándose cuenta de los cambios que sucedan dentro del array de alumnos y pudiendo actualizar los datos en la tabla.

Por último, se invoca a la carga del componente DataTable en Angular, que implementa add-ons como la ordenación de columnas y la paginación en la tabla mostrada.

Edición de datos del alumno

Permite modificar los datos del alumno en relación a la gestión de gastos (residencia del alumno con respecto al centro educativo, ubicación del centro de trabajo y distancias asociadas). Se invoca al modal ModalGestionGastosAlumnoComponent, emitiendo a una variable del tipo EventEmitter<any> en el servicio que actúa para recoger y actualizar los datos entre el modal y la vista padre, con la información del alumno.

Si se trata de un registro nuevo, los campos estarán vacíos, por lo que se carga por defecto la información referida al primer elemento en el combo Residencia del alumno. Sin embargo, si en la variable del tipo EventEmitter<any> existen datos, se cargan estos.

Si el formulario es válido (se han rellenado al menos los campos marcados con un asterisco rojo), se recogen los nuevos datos del alumno, se invoca al método actualizarDatosGastoAlumno(gasto: Gasto) del servicio y se llama a la ruta API api/actualizarDatosGastoAlumno [post]. Si todo ha salido bien, el servidor devuelve un código HTTP estándar 200. Si algo ha fallado, se devuelve un error HTTP estándar 400.

Tras esto, se actualiza el modelo Gasto para que se reflejen los cambios en el cliente.

Edición de días de transporte privado

Al pulsar el botón de guardar, se invoca al método actualizarDiasVehiculoPrivado(gasto: Gasto) del servicio (ruta api/actualizarDiasVehiculoPrivado [put] API). Se actualizan los días de vehículo propio en el campo correspondiente de la tabla gasto para el alumno y se devuelve una respuesta con código HTTP estándar (200 o 400).

Añadir o editar tickets

Como se ha mencionado anteriormente, esta vista permite almacenar, editar y eliminar tickets de manutención y transporte público. Cómo ambos funcionan de manera similar, se explicará su funcionamiento generalizado.

Al crear o editar tickets, al abrir el modal ModalTicketDesplazamiento o ModalTicketManutencion, se emite a la variable del tipo EventEmitter<any> del servicio un objeto del tipo FacturaManutencion o FacturaTransporte (vacía en caso de ser una creación, pasando por parámetro de la vista la factura correspondiente en caso de ser una edición) en la vista padre, además de una variable del tipo ModoEdicion; un enum que contiene valores según deseemos mostrar información o editarla en un modal.

En las facturas de transporte se pueden agregar o editar la siguiente información:

  • Fecha
  • Importe
  • Origen
  • Destino
  • Imagen

En las facturas de manutención:

  • Fecha
  • Importe
  • Imagen

Si el formulario es válido (se han rellenado al menos los campos marcados con un asterisco rojo), se recogen los datos de la factura, se invoca al método actualizarDatosGastoAlumno(gasto: Gasto) del servicio y se llama a la ruta API api/actualizarDatosGastoAlumno [post]. Si todo ha salido bien, el servidor devuelve un código HTTP estándar 200. Si algo ha fallado, se devuelve un error HTTP estándar 400.

La subida de ficheros (fotografías de los tickets) se gestiona de la misma manera que en el CRUD de alumnos

Anexo V

Una vez el alumno haya insertado sus gastos en el sistema, puede confirmarlos y generar el Anexo V. Tras esto, puede subir el documento firmado en formato .pdf. Estas funcionalidades están sólo disponibles si el alumno tiene gastos superiores a 0€:

<button (click)="confirmarGastos()" [disabled]="gasto?.total_gastos == 0 ? true : null">

El proceso que sigue la confirmación de gastos es el siguiente:

  1. En GestionGastosAlumnoComponent, el método asíncrono confirmarGastos(), previa confirmación por parte del usuario, se subscribe al método confirmarGastos del servicio GestionGastosService, pasándole un objeto Gasto con los gastos del alumno. En caso de que haya ido bien, se invoca un diálogo de confirmación para preguntarle al usuario si quiere descargar el anexo generado; si no, se muestra un toastr en el que se pide al usuario que vuelva a intentarlo más tarde. La gestión de la descarga se hace mediante el método descargarAnexoRuta del servicio CrudAnexoService, que hace una petición POST al servidor con una ruta en el cuerpo de la petición, y devuelve un Observable con la señal de descarga.
  2. En GestionGastosService, el método confirmarGastos(gasto: Gasto) hace una petición POST al servidor mediante la ruta /confirmar_gastos, enviándole el objeto de gastos y devolviendo un Observable con la respuesta del servidor, que contiene la ruta del anexo.
  3. En el ControladorAlumno de la API se llama a la función confirmarGastos(Request $req). Podemos dividir este paso en varias partes:
    1. Se actualiza el total de gastos en la tabla gastos, utilizando como filtros el DNI del alumno y el curso académico incluidos en el objeto de gastos recibido del cliente.
    2. Se recolectan de la BBDD todos los objetos necesarios para rellenar el Anexo V:
      • Alumno, a través de su DNI
      • Fct, a través del DNI del alumno y el curso académico
      • CentroEstudios, a través de la tabla matricula, mediante el DNI del alumno y el curso académico
      • Director (Profesor), a través del código del centro de estudios.
      • Grupo, a través del código de grupo de la matrícula del alumno
      • FamiliaProfesional, a través del grupo
      • Tutor (Profesor), a través de la tabla tutorias, mediante el grupo y el curso académico
      • Empresa, mediante Fct
    3. Tras convertir estos modelos en un solo array (ver Model to array), se rellena el documento, se crea en la ruta para el alumno y se copia en el directorio de su tutor. Tras esto, se eliminan los registros de la tabla anexos que puedan referenciar a esos archivos y se vuelven a crear (uno para el alumno y otro para el profesor).
    4. Finalmente, se envía una respuesta JSON: 200 si ha ido todo bien, junto con la ruta del anexo; 400, si ha habido un error relacionado con la BBDD; o 500, si se trata de otro error del servidor.

El proceso que sigue la subida del anexo firmado es el siguiente:

  1. En el componente, el método subirAnexoV(event: any) construye un objeto con el DNI del alumno, el curso académico y el archivo en Base64. Este objeto se lo pasa al método homónimo del servicio FileUploadService, al cual se subscribe. Dentro de la subscripción, únicamente se invoca un toastr informando del éxito o del error de la operación.
  2. En FileUploadService, el método subirAnexoV(datos: object) hace una petición POST al servidor mediante la ruta /firmar_anexo_v, enviándole los datos en formato JSON y devolviendo un Observable con la respuesta del servidor.
  3. En la API, se llama al método subirAnexoV(Request $req), del controlador de alumnos. En este método sólo se hacen dos cosas: guardar el fichero en las rutas del alumno y de su tutor (Auxiliar::guardarFichero); y actualizar los registros correspondientes en la tabla de anexos, para que se cambie el .docx por .pdf en las rutas y aparezcan como firmados por el alumno. Finralmente, se envía la respuesta JSON con los códigos de estado típicos: 200, 400 o 500.
⚠️ **GitHub.com Fallback** ⚠️