intra_max_chatbot/bot/handlers/menu.py
2026-04-03 00:30:24 +03:00

108 lines
4 KiB
Python

"""Обработчик главного меню."""
import asyncio
from maxapi.context import BaseContext
from maxapi.dispatcher import Router
from maxapi.filters import F
from maxapi.types.updates.message_callback import MessageCallback
from bot.flow_config import PAYLOADS, TRANSITIONS
from bot.keyboards import main_menu_kb
from bot.nav_helper import nav_finish, nav_prepare
from bot.texts import MenuTexts
from database.queries.organizations import get_organization
from external.intradesk_api import count_client_open_tasks, get_client_last_comment
router = Router(router_id="menu")
async def build_main_menu_text(bot_user: dict) -> str:
"""Формирует текст главного меню — данные берутся из Intradesk API."""
org_id = bot_user.get("org_id")
org_name: str | None = None
intradesk_id: int | None = None
if org_id:
org = await get_organization(org_id)
org_name = org["name"] if org else None
intradesk_id = org.get("intradesk_id") if org else None
lines: list[str] = []
lines.append(MenuTexts.ORG_HEADER.format(org_name=org_name) if org_name else MenuTexts.NO_ORG_HEADER)
lines.append(MenuTexts.SEPARATOR)
if intradesk_id:
# Счётчик активных и последний комментарий — параллельно
active, last_comment = await asyncio.gather(
count_client_open_tasks(intradesk_id),
get_client_last_comment(intradesk_id),
)
if active == 0:
lines += [
MenuTexts.NO_TICKETS,
"",
MenuTexts.NO_TICKETS_HINT,
]
else:
lines.append(MenuTexts.ACTIVE_COUNT.format(active=active))
if last_comment and last_comment.get("text"):
ctext = last_comment["text"]
if len(ctext) > 120:
ctext = ctext[:120] + ""
raw_date = last_comment.get("date") or ""
date_part = raw_date[:10]
time_part = raw_date[11:16] if len(raw_date) >= 16 else ""
if len(date_part) == 10:
y, m, d = date_part.split("-")
short_date = f"{d}.{m}" + (f" {time_part}" if time_part else "")
else:
short_date = raw_date
author = (last_comment.get("author") or "").strip()
task_num = last_comment.get("task_number")
num_str = f" (заявка #{task_num})" if task_num else ""
lines += [
"",
MenuTexts.LAST_COMMENT.format(num_str=num_str),
f"«{ctext}»",
MenuTexts.LAST_COMMENT_AUTHOR.format(author=author, short_date=short_date),
]
else:
lines += ["", MenuTexts.NO_NEW_COMMENTS]
else:
lines.append(MenuTexts.NO_ORG_DATA)
lines += ["", MenuTexts.SEPARATOR, MenuTexts.CHOOSE_ACTION]
return "\n".join(lines)
@router.message_callback(F.callback.payload == PAYLOADS.MAIN_MENU)
async def cb_main_menu(
event: MessageCallback, context: BaseContext, bot_user: dict
) -> None:
from bot.handlers.create_ticket import cleanup_ticket_flow
await cleanup_ticket_flow(event.bot, context)
await context.set_state(TRANSITIONS["nav:menu"])
await event.answer(notification="")
chat_id = event.message.recipient.chat_id if event.message else None
# Показываем «⏳» — edit-in-place если это последнее навигационное сообщение
mid = await nav_prepare(
event, context,
loading_text=MenuTexts.LOADING,
chat_id=chat_id,
user_id=bot_user["max_user_id"],
)
text = await build_main_menu_text(bot_user)
await nav_finish(
event.bot, context,
mid=mid,
chat_id=chat_id,
user_id=bot_user["max_user_id"],
text=text,
attachments=[main_menu_kb()],
)