intra_max_chatbot/bot/handlers/view_tickets.py

167 lines
5.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Обработчики просмотра заявок (Intradesk).
Навигация через callback payload — все переходы редактируют текущее сообщение:
"view_tickets" → список, страница 0
"itickets_page:{n}" → список, страница n
"iticket_detail:{id}" → карточка задачи
"main_menu" → в menu.py
"""
import re
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.filters import PayloadStartsWith
from bot.keyboards import intradesk_tasks_list_kb, iticket_detail_kb, menu_only_kb
from bot.send_helper import bot_reply
from database.connection import get_db
from database.queries.intradesk import (
count_tasks_for_local_org,
get_task_for_local_org,
get_tasks_for_local_org,
)
from external.intradesk_api import get_task_last_comment
router = Router(router_id="view_tickets")
_PAGE_SIZE = 8
def _status_icon(status_name: str) -> str:
sn = status_name.lower()
if "выполнен" in sn:
return "🟢"
if "работ" in sn:
return "🟡"
if "открыт" in sn:
return "🔴"
return ""
def _priority_icon(priority_name: str) -> str:
pn = priority_name.lower()
if "критич" in pn:
return "🔴"
if "высок" in pn:
return "🟠"
if "средн" in pn:
return "🟡"
return ""
async def _tasks_page_text(org_id: int, page: int) -> tuple[str, list[dict], int]:
"""Возвращает (текст, задачи, всего)."""
db = get_db()
tasks = await get_tasks_for_local_org(db, org_id, page=page, page_size=_PAGE_SIZE)
total = await count_tasks_for_local_org(db, org_id)
if not tasks:
return "📭 У вашей организации пока нет заявок.", [], 0
pages = max(1, -(-total // _PAGE_SIZE))
text = f"📋 Заявки — стр. {page + 1} из {pages} (всего: {total}):"
return text, tasks, total
@router.message_callback(F.callback.payload == "view_tickets")
async def cb_view_tickets(
event: MessageCallback, context: BaseContext, bot_user: dict
) -> None:
await event.answer(notification="")
text, tasks, total = await _tasks_page_text(bot_user["org_id"], 0)
kb = intradesk_tasks_list_kb(tasks, page=0, total=total) if tasks else menu_only_kb()
await bot_reply(
event,
text=text,
attachments=[kb],
user_id=bot_user["max_user_id"],
chat_id=event.message.recipient.chat_id if event.message else None,
)
@router.message_callback(PayloadStartsWith("itickets_page:"))
async def cb_itickets_page(
event: MessageCallback, context: BaseContext, bot_user: dict
) -> None:
await event.answer(notification="")
try:
page = int(event.callback.payload.split(":")[1])
except (IndexError, ValueError):
page = 0
text, tasks, total = await _tasks_page_text(bot_user["org_id"], page)
kb = intradesk_tasks_list_kb(tasks, page=page, total=total) if tasks else menu_only_kb()
await bot_reply(
event,
text=text,
attachments=[kb],
user_id=bot_user["max_user_id"],
chat_id=event.message.recipient.chat_id if event.message else None,
)
@router.message_callback(PayloadStartsWith("iticket_detail:"))
async def cb_iticket_detail(
event: MessageCallback, context: BaseContext, bot_user: dict
) -> None:
try:
task_id = int(event.callback.payload.split(":")[1])
except (IndexError, ValueError):
await event.answer(notification="Ошибка")
return
db = get_db()
task = await get_task_for_local_org(db, task_id, bot_user["org_id"])
if task is None:
await event.answer(notification="Нет доступа")
return
await event.answer(notification="")
sicon = _status_icon(task.get("status_name") or "")
picon = _priority_icon(task.get("priority_name") or "")
num = task.get("task_number") or task["id"]
lines = [
f"📌 Заявка #{num}",
f"Статус: {sicon} {task.get('status_name') or ''}",
f"Приоритет: {picon} {task.get('priority_name') or ''}",
]
if task.get("service_name"):
lines.append(f"Сервис: {task['service_name']}")
if task.get("executor_name"):
lines.append(f"Исполнитель: {task['executor_name']}")
lines.append(f"Создана: {(task.get('created_at') or '')[:10] or ''}")
lines.append(f"Обновлена: {(task.get('updated_at') or '')[:10] or ''}")
if task.get("name"):
lines += ["", f"📄 {task['name']}"]
if task.get("description"):
desc = re.sub(r"<[^>]+>", "", task["description"]).strip()
if desc:
if len(desc) > 800:
desc = desc[:800] + ""
lines += ["", f"💬 {desc}"]
# Последний комментарий — запрашиваем из Intradesk API
comment = await get_task_last_comment(task["id"])
if comment and comment.get("text"):
ctext = comment["text"]
if len(ctext) > 500:
ctext = ctext[:500] + ""
lines += [
"",
f"💭 Последний комментарий ({comment['date']}):",
f" {ctext}",
f"{comment['author']}",
]
await bot_reply(
event,
text="\n".join(lines),
attachments=[iticket_detail_kb()],
user_id=bot_user["max_user_id"],
chat_id=event.message.recipient.chat_id if event.message else None,
)