From d0e13da7063cdac77bc0f9b1fc92713e03fcbfef Mon Sep 17 00:00:00 2001 From: Marco Gallegos Date: Mon, 15 Dec 2025 12:30:46 -0600 Subject: [PATCH] Allow conversation re-entry for flows --- modules/onboarding.py | 16 ++++++++++------ modules/rh_requests.py | 24 +++++++++++++++++++----- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/modules/onboarding.py b/modules/onboarding.py index 23b041a..553c0ef 100644 --- a/modules/onboarding.py +++ b/modules/onboarding.py @@ -131,10 +131,10 @@ TECLADO_MESES = ReplyKeyboardMarkup( one_time_keyboard=True, resize_keyboard=True ) -# Años: Actual y Siguiente -anio_actual = datetime.now().year +# Años de ingreso permitidos (2020-2026) +ANIOS_INGRESO = [str(anio) for anio in range(2020, 2027)] TECLADO_ANIOS_INICIO = ReplyKeyboardMarkup( - [[str(anio_actual), str(anio_actual + 1)]], + [ANIOS_INGRESO[i:i+3] for i in range(0, len(ANIOS_INGRESO), 3)], one_time_keyboard=True, resize_keyboard=True ) @@ -315,13 +315,16 @@ async def finalizar(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: # Derivados num_ext_texto = numero_a_texto(r.get(NUM_EXTERIOR, ""), r.get(NUM_INTERIOR, "")) # El número de empleado debe ser solo la fecha de inicio en formato AAMMDD. + curp_val = (r.get(CURP) or "").upper() + curp_prefijo = curp_val[:4] if len(curp_val) >= 4 else "XXXX" try: fecha_inicio_dt = datetime.strptime(fecha_ini, "%Y-%m-%d") - n_empleado = fecha_inicio_dt.strftime("%y%m%d") + n_empleado = f"{curp_prefijo}{fecha_inicio_dt.strftime('%y%m%d')}" except Exception: # Fallback defensivo para no romper el flujo si viene un formato raro. fecha_compacta = fecha_ini.replace("-", "") - n_empleado = fecha_compacta[-6:] if len(fecha_compacta) >= 6 else fecha_compacta or "N/A" + sufijo_fecha = fecha_compacta[-6:] if len(fecha_compacta) >= 6 else fecha_compacta or "N/A" + n_empleado = f"{curp_prefijo}{sufijo_fecha}" # PAYLOAD ESTRUCTURADO PARA N8N payload = { @@ -426,7 +429,8 @@ states[34] = [MessageHandler(filters.TEXT & ~filters.COMMAND, finalizar)] onboarding_handler = ConversationHandler( entry_points=[CommandHandler("welcome", start)], # Cambiado a /welcome states=states, # Tu diccionario de estados - fallbacks=[CommandHandler("cancelar", cancelar)] + fallbacks=[CommandHandler("cancelar", cancelar)], + allow_reentry=True ) def main(): diff --git a/modules/rh_requests.py b/modules/rh_requests.py index 9b6b99b..11fcdb9 100644 --- a/modules/rh_requests.py +++ b/modules/rh_requests.py @@ -1,6 +1,7 @@ import os import requests -import uuid +import secrets +import string from datetime import datetime, date from telegram import ReplyKeyboardMarkup, ReplyKeyboardRemove, Update from telegram.ext import CommandHandler, ContextTypes, ConversationHandler, MessageHandler, filters @@ -8,6 +9,11 @@ from modules.database import log_request from modules.ui import main_actions_keyboard from modules.ai import classify_reason +# IDs cortos para correlación y trazabilidad +def _short_id(length: int = 11) -> str: + alphabet = string.ascii_letters + string.digits + return "".join(secrets.choice(alphabet) for _ in range(length)) + # Helpers de webhooks def _get_webhook_list(env_name: str) -> list: raw = os.getenv(env_name, "") @@ -74,10 +80,16 @@ def _parse_anio(texto: str) -> int: def _build_dates(datos: dict) -> dict: """Construye fechas ISO; si fin < inicio, se ajusta a inicio.""" try: - inicio = date(datos.get("inicio_anio", ANIO_ACTUAL), datos["inicio_mes"], datos["inicio_dia"]) + inicio_anio = datos.get("inicio_anio", ANIO_ACTUAL) + inicio = date(inicio_anio, datos["inicio_mes"], datos["inicio_dia"]) fin_dia = datos.get("fin_dia", datos.get("inicio_dia")) fin_mes = datos.get("fin_mes", datos.get("inicio_mes")) fin_anio = datos.get("fin_anio", datos.get("inicio_anio", inicio.year)) + # Ajuste automático para cruces de año (ej: 28 Dic -> 15 Ene) + if fin_anio == inicio.year and ( + fin_mes < inicio.month or (fin_mes == inicio.month and fin_dia < inicio.day) + ): + fin_anio = inicio.year + 1 fin = date(fin_anio, fin_mes, fin_dia) if fin < inicio: fin = inicio @@ -262,7 +274,7 @@ async def recibir_motivo_fin(update: Update, context: ContextTypes.DEFAULT_TYPE) return ConversationHandler.END payload = { - "record_id": str(uuid.uuid4()), + "record_id": _short_id(), "solicitante": { "id_telegram": user.id, "nombre": user.full_name, @@ -381,7 +393,8 @@ vacaciones_handler = ConversationHandler( FIN_ANIO: [MessageHandler(filters.TEXT & ~filters.COMMAND, recibir_fin_anio)], MOTIVO: [MessageHandler(filters.TEXT & ~filters.COMMAND, recibir_motivo_fin)] }, - fallbacks=[CommandHandler("cancelar", cancelar)] + fallbacks=[CommandHandler("cancelar", cancelar)], + allow_reentry=True ) permiso_handler = ConversationHandler( @@ -396,5 +409,6 @@ permiso_handler = ConversationHandler( HORARIO: [MessageHandler(filters.TEXT & ~filters.COMMAND, recibir_horario)], MOTIVO: [MessageHandler(filters.TEXT & ~filters.COMMAND, recibir_motivo_fin)] }, - fallbacks=[CommandHandler("cancelar", cancelar)] + fallbacks=[CommandHandler("cancelar", cancelar)], + allow_reentry=True )