Referencia

Sistema de Cálculo de Carga Horaria

Documentación técnica del motor de cálculo de carga horaria: arquitectura, consolidación institucional, procesamiento asincrónico y ejecución por CLI.

Ariel Mamani ·
carga-horaria arquitectura nestjs postgresql eventos

Documento técnico que describe cómo está construido el motor de cálculo de carga horaria: entidades involucradas, flujo de cálculo individual e institucional, procesamiento masivo concurrente y ejecución mediante scripts CLI.

Descarga: Artículo técnico (PDF) — versión 1.0, mayo 2026. Documento original generado por el DTI; esta página es la versión navegable equivalente.

Resumen

El sistema implementa un motor de cálculo de carga horaria orientado a la administración académica y operativa de establecimientos educacionales.

La solución permite:

  • Calcular horas pedagógicas y no pedagógicas.
  • Consolidar métricas institucionales.
  • Validar distribución horaria.
  • Detectar sobreasignaciones.
  • Automatizar recálculos.
  • Ejecutar procesamiento masivo concurrente.
  • Mantener sincronización institucional mediante eventos asincrónicos.

El módulo fue desarrollado utilizando NestJS, PostgreSQL y TypeORM, bajo una arquitectura desacoplada basada en servicios, listeners y tareas ejecutables.

Introducción

El sistema implementa un módulo de cálculo de carga horaria orientado a la gestión académica y administrativa de establecimientos educacionales. Su propósito es centralizar el cálculo de horas asignadas a docentes y asistentes, controlar la distribución de horas pedagógicas y no pedagógicas, y mantener indicadores consolidados por período escolar.

La solución fue desarrollada utilizando:

  • NestJS como framework backend.
  • TypeORM para acceso a datos.
  • PostgreSQL como motor de base de datos.
  • Arquitectura basada en eventos asincrónicos mediante listeners y tareas desacopladas.

Objetivo del módulo

El módulo de cálculo tiene como finalidad:

  • Calcular la carga horaria total de funcionarios.
  • Distribuir horas pedagógicas y no pedagógicas.
  • Validar porcentajes de utilización.
  • Detectar sobreasignaciones horarias.
  • Consolidar métricas por período escolar.
  • Automatizar recálculos ante cambios en asignaciones.
  • Mantener sincronizada la información institucional.

Arquitectura general del cálculo

El sistema trabaja sobre múltiples entidades relacionadas entre sí:

EntidadResponsabilidad
PersonSchoolRelación del funcionario con un establecimiento.
PersonFunctionInformación contractual.
PersonSchoolNthTableConfiguración horaria aplicada.
GradeSubjectTeacherHoras asignadas en asignaturas.
ActivityActividades no lectivas.
CalculatePersonSchoolResultado consolidado individual.
CalculateSchoolPeriodResultado consolidado institucional.

Flujo general del cálculo

El proceso completo se divide en tres niveles.

Cálculo individual del funcionario

Método principal:

calculateCompleteFuncionary(personSchoolId)

Responsable de calcular horas pedagógicas, horas no pedagógicas, horas no lectivas, recreos, porcentajes, excedentes y disponibilidad restante.

Consolidación institucional

Método:

calculateFunctionaryHours(schoolPeriodId)

Responsable de consolidar métricas globales, calcular progreso institucional, totalizar horas docentes y asistentes, y medir avance del período escolar.

Recálculo masivo

Método:

calculateFunctionaryAll(academicPeriodId)

Responsable de recalcular todos los establecimientos y funcionarios de un período académico completo.

Cálculo individual del funcionario

Obtención de datos base

El sistema obtiene: funcionario (PersonSchool), período escolar, período académico, configuración horaria, asignaturas asignadas y actividades registradas. Esto permite construir el contexto completo del cálculo.

Configuración automática de tablas horarias

Cuando un docente no posee configuración horaria asociada, el sistema crea automáticamente una configuración inicial para garantizar que todo docente tenga: horas lectivas, horas no lectivas, recreos y planificación.

Uso de tablas NTH

Las configuraciones horarias se obtienen desde tablas institucionales NTH. Cada configuración define:

CampoDescripción
teachingHoursHaHoras aula.
teachingHoursHcHoras cronológicas.
recreationTiempo recreo.
nonTeachingHoursHoras no lectivas.

Conversión de tiempos

El sistema utiliza intervalos PostgreSQL para almacenar tiempos.

intervalToSeconds()       // Conversión a segundos
secondsToIntervalString() // Conversión a intervalos

Esto permite cálculos precisos, compatibilidad con PostgreSQL y operaciones matemáticas eficientes.

Cálculo de horas pedagógicas

Las horas pedagógicas consideran horas lectivas, horas no lectivas y recreos. Fórmula general:

totalPedagogicalHours = totalTeachingHoursHc + totalNonTeachingHours + totalRecreation

Cálculo de horas utilizadas

Las horas utilizadas provienen de asignaturas (GradeSubjectTeacher) y actividades (Activity). Cada hora pedagógica se transforma a segundos para unificar cálculos y las horas de actividades se manejan cronológicamente:

totalUsedTeachingHoursHc = totalUsedTeachingHoursHa * 45 * 60

Cálculo de disponibilidad restante

El sistema calcula horas restantes mediante la fórmula rest = total - used, utilizando Math.max(total - used, 0) para evitar valores negativos.

Cálculo de excedentes

Cuando las horas utilizadas superan el límite disponible, el sistema registra sobreasignación horaria:

exceeded = used - total

Cálculo porcentual

Se utiliza una función segura safeDivide(num, den) que evita divisiones por cero:

percentage = den > 0 ? (num / den) * 100 : 0

Subsidios institucionales

El cálculo separa horas según subsidio. Cada bloque horario se consolida individualmente:

SubsidioDescripción
SGSubvención General.
PIEPrograma de Integración Escolar.
SEPSubvención Escolar Preferencial.

Consolidación institucional

El método calculateFunctionaryHours() realiza la consolidación global del establecimiento.

Métricas calculadas

El sistema contabiliza funcionarios con percentageTotal === 100 y calcula:

  • Progreso docentes.
  • Progreso asistentes.
  • Progreso cursos.
totalProgress = (progressAssistants + progressTeachers + progressGrades) / 3

Consolidación de horas

El sistema totaliza: horas docentes, horas asistentes, horas utilizadas, horas restantes y horas de cursos.

Persistencia de resultados

Los resultados son almacenados para evitar recalcular información constantemente:

TablaPropósito
CalculatePersonSchoolResultado individual.
CalculateSchoolPeriodResultado institucional.

Procesamiento masivo concurrente

El sistema incorpora procesamiento concurrente controlado mediante el método runWithConcurrency(), que permite recalcular múltiples funcionarios simultáneamente sin saturar la base de datos.

Arquitectura asincrónica basada en eventos

El sistema utiliza listeners desacoplados mediante @OnEvent(), implementado con EventEmitter, tareas asincrónicas y procesamiento diferido.

Eventos soportados

Recálculo institucional:

school-period.recalculate → ejecuta calculateFunctionaryHours()

Recálculo individual:

school-period.recalculate-person-school → ejecuta calculateCompleteFuncionary()

Debounce de eventos

El listener implementa un mecanismo debounce utilizando Map<number, NodeJS.Timeout> para evitar múltiples recálculos consecutivos innecesarios. Cuando ocurren múltiples cambios: se cancela el temporizador anterior, se espera un intervalo y se ejecuta un único recálculo consolidado.

Beneficios:

  • Menor carga de base de datos.
  • Menos recálculos duplicados.
  • Mejor rendimiento.
  • Mayor estabilidad.

Ejecución mediante scripts CLI

El sistema incorpora scripts ejecutables mediante npm para permitir la ejecución manual o automatizada de recálculos masivos de carga horaria. Estos scripts permiten: recalcular períodos académicos completos, ejecutar procesos de mantenimiento, sincronizar información institucional, reprocesar datos históricos y automatizar tareas programadas.

Definición del script

"calculate-all-values": "npx ts-node -r tsconfig-paths/register ./src/scripts/calculate-all-values.ts"

Implementación

import { NestFactory } from '@nestjs/core';
import { AppModule } from 'src/app.module';
import { CalculateSchoolPeriodTaskService } from 'src/school-general/...';

async function bootstrap() {
  const app = await NestFactory.createApplicationContext(AppModule);
  const taskService = app.get(CalculateSchoolPeriodTaskService);
  const academicPeriodId = parseInt(process.argv[2], 10);
  if (!academicPeriodId) {
    process.exit(1);
  }
  await taskService.calculateFunctionaryAll(academicPeriodId);
  console.log('Ejecución completada');
}

Funcionamiento del script

  1. Inicialización del contexto NestJS: el script inicializa el contenedor completo sin levantar servidor HTTP, reutilizando servicios, repositorios, inyección de dependencias y lógica de negocio.
  2. Obtención del servicio principal: se obtiene el servicio encargado de ejecutar los cálculos institucionales.
  3. Recepción y validación de parámetros: el identificador del período académico es recibido desde la línea de comandos y validado antes de ejecutar el proceso.
  4. Ejecución del cálculo masivo: el sistema ejecuta recálculo individual de funcionarios, consolidación institucional, actualización de métricas y persistencia de resultados.

Ejemplo de ejecución

npm run calculate-all-values 1
ParámetroDescripción
1Identificador del período académico.

Beneficios del enfoque CLI

La ejecución mediante scripts desacoplados permite:

  • Automatización mediante cron jobs.
  • Integración con pipelines CI/CD.
  • Mantenimiento institucional.
  • Reprocesamiento controlado.
  • Independencia del servidor HTTP.
  • Menor consumo de recursos.

Estrategias de rendimiento

El módulo incorpora las siguientes optimizaciones:

EstrategiaBeneficio
Promise.allParalelismo.
Procesamiento concurrenteMejor throughput.
Consolidación persistidaMenos recálculo.
DebounceReducción de eventos.
Conversión en memoriaMenos operaciones SQL.
Agrupación previaMenos consultas repetidas.

Beneficios de la arquitectura

La solución implementada proporciona:

  • Alta escalabilidad.
  • Desacoplamiento de procesos.
  • Trazabilidad de cálculos.
  • Consolidación institucional.
  • Automatización de recálculos.
  • Control de sobrecarga horaria.
  • Flexibilidad para distintas configuraciones académicas.

Conclusión

El sistema de cálculo de carga horaria implementa una arquitectura orientada a procesos asincrónicos y consolidación progresiva de información académica. Sumado a su manejo de las horas a nivel de segundos para tener el control completo de las asignaciones de las horas en los funcionarios.

Mediante el uso de eventos, cálculos desacoplados y persistencia de resultados, el sistema logra administrar eficientemente la distribución horaria institucional, manteniendo consistencia y rendimiento incluso en escenarios de alta carga operativa.