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.
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í:
| Entidad | Responsabilidad |
|---|---|
PersonSchool | Relación del funcionario con un establecimiento. |
PersonFunction | Información contractual. |
PersonSchoolNthTable | Configuración horaria aplicada. |
GradeSubjectTeacher | Horas asignadas en asignaturas. |
Activity | Actividades no lectivas. |
CalculatePersonSchool | Resultado consolidado individual. |
CalculateSchoolPeriod | Resultado 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:
| Campo | Descripción |
|---|---|
teachingHoursHa | Horas aula. |
teachingHoursHc | Horas cronológicas. |
recreation | Tiempo recreo. |
nonTeachingHours | Horas 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:
| Subsidio | Descripción |
|---|---|
SG | Subvención General. |
PIE | Programa de Integración Escolar. |
SEP | Subvenció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:
| Tabla | Propósito |
|---|---|
CalculatePersonSchool | Resultado individual. |
CalculateSchoolPeriod | Resultado 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
- 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.
- Obtención del servicio principal: se obtiene el servicio encargado de ejecutar los cálculos institucionales.
- 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.
- 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ámetro | Descripción |
|---|---|
1 | Identificador 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:
| Estrategia | Beneficio |
|---|---|
Promise.all | Paralelismo. |
| Procesamiento concurrente | Mejor throughput. |
| Consolidación persistida | Menos recálculo. |
| Debounce | Reducción de eventos. |
| Conversión en memoria | Menos operaciones SQL. |
| Agrupación previa | Menos 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.