Creación de Stored Procedures: Login e Insertar Empleado
Fecha: 18 de abril de 2026
Hora de inicio: 12:00 a.m.
Hora de finalización: 2:30 p.m.
Hora de inicio: 3:00 p.m.
Hora de finalización: 5:30 p.m.
Horas trabajadas: 5h
Luego de consolidar los patrones con ListarEmplados y ListarPuestos el siguiente paso era implementar dos SPs críticos para la aplicación: Login, que maneja la autenticación y sesiones de usuarios, e InsertarEmpleado , que permite agregar nuevos empleados a la base de datos con validaciones de duplicados. Estos SPs representaron un salto en complejidad, ya que no solo devuelven datos, sino que modifican la base de datos, registran eventos en la bitácora y manejan lógica de negocio como el bloqueo por intentos fallidos.
Actividades realizadas
12:00 p.m. - 2:30 p.m.
Implementación de sp_Login
El SP de Login es uno de los más importantes, ya que es el punto de entrada a todo el sistema. Debe validar credenciales, implementar la lógica de seguridad de bloqueo por intentos fallidos, y devolver la información del usuario para mantener la sesión.
El flujo del SP es el siguiente:
1) Verificación de bloqueo por intentos fallidos: Antes de validar el username y password, se consulta la tabla BitacoraEventos para contar cuántos intentos fallidos de login ha habido en los últimos 20 minutos desde ese usuario (IP + username). Si hay 5 o más, se registra un evento de tipo 3 ("Login deshabilitado") y se devuelve el código de error 50003. Esta lógica se implementó porque el profesor indicó que después de 5 intentos fallidos en 20 minutos, el botón de login debe deshabilitarse y mostrar un mensaje al usuario.
Validación de password: Si el username existe pero el password es incorrecto, se asigna el código de error 50002 y se registra un evento tipo 2 en la bitácora con el id real del usuario.
Login exitoso: Si el username y password son correctos, se obtiene el id y username del usuario, se registra un evento de tipo 1 ("Login Exitoso") y se devuelve un resultset con el código 0, el id y el username.
Cada una de estas acciones (exitosa o fallida) se registra en BitacoraEvento mediante una llamada al SP de registrarBitacora , un SP creado por VB para registrar los eventos. Esto cumple con el requisito de trazabilidad: cada intento de login queda registrado para auditoría.
Implementación de InsertarEmpleado
Este SP permite insertar un nuevo empleado en la tabla Empleado. El profesor indicó que la inserción debe validarse tanto en la capa de presentación (Python/Flask) como en la capa de datos (SQL Server), de modo que incluso si algo bypasea la validación en Python, la base de datos lo rechazará.
El flujo del SP es
Validación de documento de identidad duplicado: Se verifica que no exista otro empleado activo con el mismo documento. Si existe, se asigna el código de error 50004 y se registra un evento de tipo 5 ("Inserción no exitosa") con la descripción del error.
Validación de nombre duplicado: Se verifica que no exista otro empleado activo con el mismo nombre. Si existe, se asigna el código de error 50005 y se registra un evento tipo 5 con la descripción del error.
Inserción: Si ambas validaciones pasan, se abre una transacción, se inserta el empleado con un saldo de vacaciones igual a 0 y la fecha de contratación se saca con GETDATE. Se cierra la transacción con COMMIT.
Registro de bitácora: Si la inserción fue exitosa, se registra un evento de tipo 6 ("Inserción exitosa") con los datos del empleado insertado.
Un detalle importante: las validaciones de duplicados se hacen antes de abrir la transacción. La transacción envuelve solo el INSERT y COMMIT, como indicó el profe. Esto es eficiente porque si una validación falla, no hay necesidad de abrir una transacción que luego se revertiría. Las validaciones fallidas simplemente registran el error en bitácora y usan GOTO FIN para saltar al final.
Errores encontrados
Error : La bitácora devuelve su propio resultset antes del resultCode
Al ejecutar Login desde Python, se obtenía un error indicando que pyodbc estaba leyendo un resultset inesperado o vacío.
Causa: El SP de Login llama a RegistrarBitacora en varias ocasiones. Cada vez que se llama un SP desde dentro de otro SP, ese SP devuelve su propio resultset. Entonces se recibían varios resulsets.
Sin saber cuál resultset contiene el resultCode, pyodbc termina leyendo uno de los resultsets de la bitácora que puede no tener las columnas esperadas.
Solución Encontrada: En Python, implementar un patrón de lectura que itera sobre todos los resultsets hasta encontrar el correcto.
Este patrón itera sobre todos los resultsets con cursor.nextset(), y en cada iteración verifica las columnas del resultset actual usando cursor.description. Cuando encuentra una columna llamada resultCode, sabe que encontró el resultset del SP principal y lee los datos. Luego rompe el ciclo con break.
Forma de trabajo del equipo
Buenas prácticas descubiertas
- Las validaciones deben ocurrir antes de las transacciones. Esto evita abrir transacciones innecesariamente. Si una validación falla, se registra el error en bitácora y se salta al final con
GOTO Finsin tocar la BD. - Múltiples llamadas a SPs anidados complican la lectura de resultsets en pyodbc. Cuando un SP llama a otros SPs, cada uno devuelve su propio resultset. La solución es iterar inteligentemente con cursor.nextset() y usar cursor.descriptoin para identificar el resultset correcto.
- Las descripciones en bitácora deben incluir datos suficientes para debugging. Por ejemplo, al registrar un login fallido, se incluye el número de intentos previos y el código de error, facilitando que el profesor o desarrolladores posteriores entiendan qué ocurrió.
Referencias consultadas
- Microsoft Docs:GOTO statement: https://learn.microsoft.com/en-us/sql/t-sql/statements/goto-transact-sql
- Microsoft Docs: DATEADD function: https://learn.microsoft.com/en-us/sql/t-sql/functions/dateadd-transact-sql
- Microsoft Docs :Transactions in SQL Server: https://learn.microsoft.com/en-us/sql/t-sql/language-elements/transactions-transact-sql
- pyodbc Documentation: Reading multiple result sets: https://github.com/mkleehammer/pyodbc/wiki
- Flask Documentation:Sessions: https://flask.palletsprojects.com/en/stable/
Comentarios
Publicar un comentario