EscalaOper es una aplicación de escritorio que arma y mantiene la escala de un equipo que trabaja en turnos: mañana, tarde, noche y horario comercial, con descansos, vacaciones, ausencias, disponibilidades, convocaciones, cambios de horario y el transporte de ida y vuelta de cada turno. Está escrito en Java, guarda los datos en un archivo de Microsoft Access y genera la imagen del transporte que el equipo recibe por WhatsApp.
Este caso técnico muestra cómo el sistema representa una escala, qué ocurre cuando el día real se aparta de lo planificado y los errores que se volvieron regla. Los números se verificaron en el código, en la versión del 14/06/2026, la más reciente del repositorio.
Transparencia: EscalaOper fue diseñado y desarrollado por Jeremias Cardoso, autor de este blog. El texto no cita empresa, personas ni ciudad, y deja fuera rutas de carpetas y credenciales.
Nota de actualización (30/10/2026): este post se reescribió como caso técnico. La versión del 20/07/2026 describía un diseño idealizado: el día calculado mediante un cálculo a partir de una fecha ancla, las desviaciones guardadas en registros aparte y el equipo consultando la escala por aplicación, en tiempo real. Verificado en el código, el sistema graba una fila por persona por día, parte de los ajustes sobrescribe esa fila y el equipo recibe la escala por imagen y por correo. Este texto describe lo que hace el código.
El problema: la escala que no cabe en la semana comercial
La escala de turno parece una tabla simple hasta la primera semana real. Un equipo que cubre mañana, tarde y noche trabaja en ciclos que no respetan la semana del calendario: cinco días de trabajo y dos de descanso que caen en un martes y en un miércoles, seis de trabajo y tres de descanso, cuatro y dos. Encima del ciclo vienen las vacaciones, los certificados médicos, quién es llamado para cubrir una falta y la pregunta que todo el mundo hace la víspera: quién toma el transporte de cuál turno mañana.
Mientras una sola persona mueve el control, una hoja de cálculo alcanza, y hay modelos listos para la rutina. El problema empieza cuando la escala necesita historial, perfiles de acceso y reglas que la hoja de cálculo no sostiene sola: no lanzar dos veces el mismo día, saber quién está de descanso para convocar, avisar a la persona cuando cambia su turno. En el caso técnico de SIGCOT, otro sistema del autor, la escala de turno aparece como un programa aparte, con inicio de sesión y base propios: es este.
El sistema en números
Números del repositorio el 14/06/2026, fecha del último commit.
| Medida | Valor |
|---|---|
| Código de la aplicación, sin líneas en blanco y sin comentarios | cerca de 8,4 mil líneas: 6.750 en Java, 1.073 en las 12 pantallas y 564 en los estilos |
| Código de pruebas | 109 líneas, con 12 pruebas en 2 clases |
| Tablas que el sistema crea en la base | 6 |
| Turnos posibles | 5: Mañana, Tarde, Noche, Comercial y Descanso |
| Historial en Git | 52 commits, del 05/06 al 14/06/2026 |
| Primer commit (05/06/2026) | 54 archivos y 8.149 líneas: el sistema ya existía cuando pasó a versionarse |
| Versión | 1.0.0 |
La base guarda datos reales del equipo y queda fuera del control de versiones. Las contraseñas se guardan con PBKDF2, un método de hash hecho para contraseñas, y quien entra por primera vez está obligado a cambiar la contraseña inicial.
La escala es una receta de períodos
En EscalaOper, una escala no es una tabla de días de la semana. Es una lista ordenada de períodos, y cada período dice cuatro cosas: cuántos días dura, cuál es el turno, la hora de entrada y la hora de salida. Un 6x3 en el turno de la mañana se vuelve dos períodos: seis días de Mañana, por ejemplo de las 07:00 a las 15:00, seguidos de tres días de Descanso. Un ciclo que alterna turnos es solo una lista mayor: cinco mañanas, dos descansos, cinco tardes, dos descansos, y así en adelante.
El registro acepta cualquier combinación de los cinco turnos, exige al menos un día por período y verifica si el horario está en el formato de hora y minuto. Un formato nuevo de escala es registro, no código: nadie necesita programar un caso especial para un 4x2 o un 6x4. El límite está en la unidad: el modelo cuenta días enteros, no horas. Un ciclo que solo se describe en horas tiene que traducirse a días antes de entrar.
El lanzamiento junta la receta con las personas. El administrador elige la escala, las personas y el intervalo de fechas. A partir de la fecha de inicio, el sistema camina día a día: graba el turno del período actual, descuenta un día y, cuando el período termina, pasa al siguiente; cuando la lista termina, vuelve al primero. Sin períodos registrados, el lanzamiento se rechaza.
La fecha de inicio funciona como ancla del ciclo de esa persona. Dos personas en la misma escala, lanzadas con fechas de inicio distintas, quedan desfasadas, y es exactamente eso lo que una escala de rotación necesita para que siempre haya alguien en cada turno.
Una fila por persona por día
El resultado del lanzamiento no es una fórmula guardada. Es una fila en la tabla para cada persona en cada día del intervalo, y la tabla tiene una regla que impide dos filas para la misma persona en el mismo día.
Esa elección tiene una ventaja grande y un costo que solo aparece después. La ventaja es que todo lo que viene a continuación queda simple. El panel de más de 40 días, el resumen de cobertura por turno, la lista de quién está de descanso en una fecha y la imagen del transporte son consultas directas: “traiga las filas entre tal y tal día”. Nadie necesita recalcular el ciclo para saber quién trabaja mañana, y cualquier día puede corregirse sin tocar la receta.
El costo es que el día planificado y el día real disputan la misma fila. Como solo existe una fila por persona por día, un ajuste no tiene otro lugar donde quedar salvo encima de lo planificado.
El día real: convocatoria, ausencia, cambio y disponibilidad
Los ajustes del día a día quedan en una pantalla con pestañas, y cada tipo mueve la fila del día de una manera:
- Convocatoria: para cubrir una falta, el sistema lista quién está de descanso en la fecha. Al confirmar, la fila de la persona convocada recibe el turno nuevo, los horarios nuevos y el tipo “Convocatoria”. El descanso que estaba ahí deja de existir en la base.
- Ausencia: cambia solo el tipo y la observación; el turno planificado queda. Por eso una ausencia en un día de descanso sigue mostrando “F” en el panel, con un borde de trazos, y una ausencia en un día de trabajo muestra el código del motivo: LME (certificado médico), LMA y LPA (licencias de maternidad y paternidad), LGA (matrimonio), TRE (capacitación), VAS (viaje de servicio) o CHE (compensación de horas extra).
- Cambio de horario: sobrescribe el turno. Cuando dos personas cambian entre sí, las dos filas cambian en una sola transacción: o cambian las dos, o no cambia ninguna.
- Disponibilidad: es solo una marca en la fila. El turno y el tipo siguen como estaban.
- Fuera del transporte: quien no va a usar el transporte en un día gana un marcador en el campo de observación, sin borrar lo que ya estaba escrito ahí.
La ausencia y la disponibilidad preservan lo planificado. La convocatoria y el cambio, no. Convocaciones, cambios y decisiones de vacaciones generan correo para la persona: son siete puntos de disparo en el sistema.
Deshacer pide el turno correcto
El precio de sobrescribir aparece a la hora de deshacer. El sistema tiene una función para deshacer ajustes en lote: se elige la persona y el período, y los días vuelven a lo normal. Pero el sistema no sabe cuál era lo normal. La pantalla pregunta, con estas palabras: “¿Cuál es el turno CORRECTO ahora?”. Después graba el turno elegido en todos los días del período.
Eso funciona bien para deshacer una semana de convocaciones en un mismo turno. Para un período que mezclaba días de trabajo y de descanso, quien deshace necesita partir el intervalo en pedazos, uno por turno, o relanzar la escala, y relanzar tiene un efecto colateral propio, descrito más abajo.
La lección es de modelado y vale para cualquier sistema con planificado y realizado: lo planificado tiene que sobrevivir al ajuste. Guardar el turno original en una columna propia en el momento de la convocatoria o del cambio bastaría para que deshacer supiera, solo, a dónde volver. La versión anterior de este texto presentaba esa separación como si ya existiera. En el código, existe para la ausencia y la disponibilidad, y no existe para la convocatoria y el cambio.
Vacaciones, festivos y transporte
Las vacaciones tienen un flujo propio. La persona pide en hasta tres períodos, con un mapa visual, y RR. HH. aprueba o rechaza. El administrador también puede lanzar o revertir vacaciones en lote. Ese lote ya fue fuente de error: cada día se grababa solo, y una falla en el medio dejaba a la persona con vacaciones a medias en la escala. Hoy el período entero corre en una transacción, y cualquier falla deshace todo. La reversión pasó por el mismo arreglo: antes, la escala podía quedar revertida mientras el pedido seguía como aprobado.
Los festivos nacionales los calcula el propio sistema, incluidos los móviles: el Viernes Santo, el Carnaval y el Corpus Christi salen de la fecha de Pascua, y el 20 de noviembre entra desde 2024, cuando se volvió festivo nacional. Los festivos estatales y municipales vienen de la configuración, como día y mes (vale todo el año) o como fecha completa (vale solo ese año). El panel resalta fines de semana y festivos.
El transporte sigue una regla corta, aislada en un servicio con pruebas:
- quien es de la mañana o del comercial entra en la ventana de la mañana y sale en la de la tarde;
- quien es de la tarde entra en la ventana de la tarde y sale en la de la noche;
- quien es de la noche entra en la ventana de la noche y sale en la mañana del día siguiente.
Con esa regla y la ciudad de cada persona, el panel de logística muestra, por turno y por día, quién llega y quién sale. El mismo dato se vuelve una imagen cuadrada para WhatsApp, con seis nombres por cuadrícula y “+N” cuando pasa de eso.
La base: un archivo y una operación a la vez
La base es un archivo de Access, que puede quedar en una carpeta de red. El driver usado para abrirlo en Java, UCanAccess, recarga la base entera en cada conexión nueva, y por eso el sistema mantiene una sola conexión, abierta durante toda la ejecución. Un respaldo del archivo corre una vez por día, en el primer acceso, o cuando el administrador lo pide, y las copias de los últimos 15 días quedan guardadas.
Esa conexión única era segura mientras todo corría en la misma línea de ejecución de la interfaz. Dejó de serlo cuando el panel, el transporte y la imagen de WhatsApp pasaron a consultar la base en segundo plano, para que la pantalla no se trabe: dos consultas podían usar la misma conexión al mismo tiempo. El commit que corrigió eso, el 10/06/2026, llama al problema un bug crítico. La corrección fue un bloqueo que deja pasar una operación de base por vez, sin cambiar ninguno de los puntos del código que usan la base.
El bloqueo vale dentro de un programa abierto. No coordina dos computadoras abiertas en el mismo archivo de red. Lo que ocurre en ese caso se midió en otro sistema del autor, Sentinela, que guarda datos en el mismo tipo de archivo.
Incidentes que se volvieron regla
- El programa que solo abría en el ambiente de desarrollo (05/06/2026). Empaquetado, el programa no encontraba la pantalla de inicio de sesión, porque las pantallas estaban en una carpeta que el empaquetado no llevaba, y fallaba al abrir, porque los archivos de firma de una biblioteca de criptografía hacían que el paquete pareciera adulterado. Las pantallas fueron a la carpeta de recursos, y el empaquetado pasó a descartar esas firmas, con un comentario en el archivo de compilación que explica por qué.
- La tilde que rompía el filtro sin dar error. Los nombres de turno y de tipo de registro se escribían a mano en varios archivos. Un “Convocaçao” sin tilde bastaba para que un filtro no encontrara nada y un color no apareciera, sin ningún mensaje. Los valores se reunieron en un único archivo de constantes, con un aviso: también aparecen dentro de los comandos SQL y tienen que ser idénticos.
- La compilación verde con pantallas rotas (11/06/2026). Al cambiar los textos sueltos por las constantes, una edición en masa no reconoció el fin de línea de Windows, y la línea que traía las constantes no entró en tres pantallas. El ambiente de desarrollo generó clases con el error incrustado; Maven, al ver clases más nuevas que el código, no recompiló, empaquetó el programa roto y terminó con éxito. Las pantallas solo fallaban al abrir. La regla que quedó: después de una edición en masa, compile desde cero y verifique que todas las pantallas cargan. Es el mismo tipo de falla silenciosa que derriba automatizaciones: la herramienta dice que salió bien, y el efecto no ocurrió.
- El correo que nunca salió (10/06/2026). El envío directo por servidor de correo no funcionaba: la contraseña configurada era un ejemplo, y la red corporativa bloqueaba la salida. El envío pasó a usar el Outlook instalado en la máquina, por un pequeño script temporal que arma el mensaje y envía sin abrir ventana. El costo es depender de Outlook configurado, y el primer envío puede pedir confirmación.
- La copia de la base borrada en una limpieza (11/06/2026). Al limpiar archivos de una prueba, una copia de la base, del 30/04, se borró porque se tomó como sobra de la prueba. El comando de borrar del terminal no pasa por la papelera de reciclaje. La copia volvió idéntica de otra carpeta de copias, con el mismo tamaño y la misma fecha. Un archivo de base que parece sobra tiene que tener fecha y tamaño verificados antes de desaparecer.
Pruebas: pocas, y en el lugar donde la regla es pura
El sistema tiene 12 pruebas en 2 clases. Los dos servicios probados nacieron el 11/06/2026, cuando la regla de las siglas del panel y la regla del transporte salieron de dentro de las pantallas y fueron a clases que no dependen de la base ni de la interfaz. La convención de ese día: la lógica de negocio nueva va a un servicio que se puede probar, no a la pantalla.
Todo el resto (lanzamiento, ajustes, vacaciones, punto de restauración y base) no tiene prueba automática y se verifica a mano. Es el mayor riesgo del proyecto, y los hallazgos de la sección siguiente son del tipo que una prueba de base habría atrapado antes.
Lo que todavía no está resuelto
Los ítems de abajo vienen de la lectura del código. El sistema no se ejecutó para esta revisión.
- El punto de restauración olvida parte del día. Antes de tocar la escala, el administrador puede crear un punto de restauración. Es uno solo, y crear otro sustituye al anterior. La copia lleva ocho columnas: identificación, escala, persona, fecha, turno, tipo, observación y autor. Los horarios de entrada y salida, la justificación y la disponibilidad no entran. Restaurar devuelve los turnos, pero sin esos campos.
- Relanzar borra los ajustes del período. Si la persona ya tiene días lanzados en el intervalo, el sistema pregunta si debe sobrescribir. Si la respuesta es sí, borra todas las filas de la persona en el período, sin mirar el tipo: vacaciones, convocaciones y ausencias se van junto. El pedido de vacaciones aprobado sigue en la tabla propia, pero los días desaparecen de la escala.
- Vacaciones en un día sin escala. En la tabla creada por el sistema, todo día lanzado tiene que pertenecer a una escala, y el lanzamiento de vacaciones en lote inserta días sin decir la escala. Si esa regla vale en la base en uso, lanzar vacaciones en un período que tenga un día todavía sin escala deshace la operación entera, gracias a la transacción. No se probó.
- El deshacer en lote depende de que quien deshace sepa el turno correcto de cada día.
- Un archivo, varias máquinas. El bloqueo de la base no coordina computadoras distintas.
- Historial detenido. El repositorio termina el 14/06/2026. Si el sistema cambió después, el cambio no está en él.
Lecciones que valen fuera de la escala de turno
- Guarde el ciclo como receta, no como calendario. Un formato nuevo se vuelve registro, no código.
- Materializar el día simplifica la lectura, pero lo planificado necesita un lugar propio para sobrevivir a los ajustes.
- Deshacer solo es seguro si el sistema sabe a dónde volver sin preguntarle a nadie.
- Un valor que va a la base y al SQL necesita una fuente única. Un error de tilde no da error.
- El éxito de la herramienta no es prueba. Compile desde cero y abra las pantallas.
- Una operación de varias filas es todo o nada. Un lanzamiento a medias es peor que ninguno.
- Un punto de restauración tiene que copiar todo lo que muestra la pantalla, o restaura otra cosa.
Fuentes
- Código, documentación, historial de commits y notas del proyecto: repositorio de EscalaOper en la versión del 14/06/2026 y notas del proyecto en la base de conocimiento del autor, leídos por el autor; extracto con los fragmentos, el método del conteo y los límites de la verificación, verificado el 2026-10-30.



