Allow conversation re-entry for flows

This commit is contained in:
Marco Gallegos
2025-12-15 12:30:46 -06:00
parent 68848cee49
commit d0e13da706
2 changed files with 29 additions and 11 deletions

View File

@@ -131,10 +131,10 @@ TECLADO_MESES = ReplyKeyboardMarkup(
one_time_keyboard=True, resize_keyboard=True one_time_keyboard=True, resize_keyboard=True
) )
# Años: Actual y Siguiente # Años de ingreso permitidos (2020-2026)
anio_actual = datetime.now().year ANIOS_INGRESO = [str(anio) for anio in range(2020, 2027)]
TECLADO_ANIOS_INICIO = ReplyKeyboardMarkup( 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 one_time_keyboard=True, resize_keyboard=True
) )
@@ -315,13 +315,16 @@ async def finalizar(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
# Derivados # Derivados
num_ext_texto = numero_a_texto(r.get(NUM_EXTERIOR, ""), r.get(NUM_INTERIOR, "")) 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. # 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: try:
fecha_inicio_dt = datetime.strptime(fecha_ini, "%Y-%m-%d") 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: except Exception:
# Fallback defensivo para no romper el flujo si viene un formato raro. # Fallback defensivo para no romper el flujo si viene un formato raro.
fecha_compacta = fecha_ini.replace("-", "") 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 ESTRUCTURADO PARA N8N
payload = { payload = {
@@ -426,7 +429,8 @@ states[34] = [MessageHandler(filters.TEXT & ~filters.COMMAND, finalizar)]
onboarding_handler = ConversationHandler( onboarding_handler = ConversationHandler(
entry_points=[CommandHandler("welcome", start)], # Cambiado a /welcome entry_points=[CommandHandler("welcome", start)], # Cambiado a /welcome
states=states, # Tu diccionario de estados states=states, # Tu diccionario de estados
fallbacks=[CommandHandler("cancelar", cancelar)] fallbacks=[CommandHandler("cancelar", cancelar)],
allow_reentry=True
) )
def main(): def main():

View File

@@ -1,6 +1,7 @@
import os import os
import requests import requests
import uuid import secrets
import string
from datetime import datetime, date from datetime import datetime, date
from telegram import ReplyKeyboardMarkup, ReplyKeyboardRemove, Update from telegram import ReplyKeyboardMarkup, ReplyKeyboardRemove, Update
from telegram.ext import CommandHandler, ContextTypes, ConversationHandler, MessageHandler, filters 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.ui import main_actions_keyboard
from modules.ai import classify_reason 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 # Helpers de webhooks
def _get_webhook_list(env_name: str) -> list: def _get_webhook_list(env_name: str) -> list:
raw = os.getenv(env_name, "") raw = os.getenv(env_name, "")
@@ -74,10 +80,16 @@ def _parse_anio(texto: str) -> int:
def _build_dates(datos: dict) -> dict: def _build_dates(datos: dict) -> dict:
"""Construye fechas ISO; si fin < inicio, se ajusta a inicio.""" """Construye fechas ISO; si fin < inicio, se ajusta a inicio."""
try: 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_dia = datos.get("fin_dia", datos.get("inicio_dia"))
fin_mes = datos.get("fin_mes", datos.get("inicio_mes")) fin_mes = datos.get("fin_mes", datos.get("inicio_mes"))
fin_anio = datos.get("fin_anio", datos.get("inicio_anio", inicio.year)) 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) fin = date(fin_anio, fin_mes, fin_dia)
if fin < inicio: if fin < inicio:
fin = inicio fin = inicio
@@ -262,7 +274,7 @@ async def recibir_motivo_fin(update: Update, context: ContextTypes.DEFAULT_TYPE)
return ConversationHandler.END return ConversationHandler.END
payload = { payload = {
"record_id": str(uuid.uuid4()), "record_id": _short_id(),
"solicitante": { "solicitante": {
"id_telegram": user.id, "id_telegram": user.id,
"nombre": user.full_name, "nombre": user.full_name,
@@ -381,7 +393,8 @@ vacaciones_handler = ConversationHandler(
FIN_ANIO: [MessageHandler(filters.TEXT & ~filters.COMMAND, recibir_fin_anio)], FIN_ANIO: [MessageHandler(filters.TEXT & ~filters.COMMAND, recibir_fin_anio)],
MOTIVO: [MessageHandler(filters.TEXT & ~filters.COMMAND, recibir_motivo_fin)] MOTIVO: [MessageHandler(filters.TEXT & ~filters.COMMAND, recibir_motivo_fin)]
}, },
fallbacks=[CommandHandler("cancelar", cancelar)] fallbacks=[CommandHandler("cancelar", cancelar)],
allow_reentry=True
) )
permiso_handler = ConversationHandler( permiso_handler = ConversationHandler(
@@ -396,5 +409,6 @@ permiso_handler = ConversationHandler(
HORARIO: [MessageHandler(filters.TEXT & ~filters.COMMAND, recibir_horario)], HORARIO: [MessageHandler(filters.TEXT & ~filters.COMMAND, recibir_horario)],
MOTIVO: [MessageHandler(filters.TEXT & ~filters.COMMAND, recibir_motivo_fin)] MOTIVO: [MessageHandler(filters.TEXT & ~filters.COMMAND, recibir_motivo_fin)]
}, },
fallbacks=[CommandHandler("cancelar", cancelar)] fallbacks=[CommandHandler("cancelar", cancelar)],
allow_reentry=True
) )