Обновить lk/handlers.py

This commit is contained in:
2026-07-23 15:50:52 +07:00
parent f0be37b18f
commit de47c39e76
+56 -30
View File
@@ -57,7 +57,7 @@ EMOJI_DIGITS = {
"10": "🔟" "10": "🔟"
} }
# Список из 7 справок строго по структуру портала # Список из 7 справок строго по структуре портала
DOC_TYPES = { DOC_TYPES = {
"1": "Справка о доходах физического лица (2-НДФЛ)", "1": "Справка о доходах физического лица (2-НДФЛ)",
"2": "Справка об удержаниях за ДМС", "2": "Справка об удержаниях за ДМС",
@@ -74,7 +74,7 @@ LK_DOCS_MENU_TEXT = (
f"\n\n<i>{EMOJI_DIGITS['9']} — Назад\n{EMOJI_DIGITS['0']} — В главное меню</i>" f"\n\n<i>{EMOJI_DIGITS['9']} — Назад\n{EMOJI_DIGITS['0']} — В главное меню</i>"
) )
USER_COOLDOWN_SEC = 1.5 USER_COOLDOWN_SEC = 0.5
EMAIL_COOLDOWN_SEC = 10.0 EMAIL_COOLDOWN_SEC = 10.0
user_last_request = {} user_last_request = {}
@@ -129,18 +129,17 @@ async def handle_lk_error(msg: Message, user_id: str, action: str, error_details
# ИНТЕГРАЦИЯ С ACTIVE DIRECTORY ЧЕРЕЗ extensionAttribute2 # ИНТЕГРАЦИЯ С ACTIVE DIRECTORY ЧЕРЕЗ extensionAttribute2
# ========================================================= # =========================================================
def get_card_id_from_ad(user_id: str) -> str: def get_card_id_from_ad(user_id: str) -> str:
# Поиск CARD_ID по всем OU из AD_BASES
from utils.ad_search import search_by_user_id from utils.ad_search import search_by_user_id
try: try:
entries = search_by_user_id(user_id, ['extensionAttribute2']) search_id = user_id.replace("@tcs.sibcem.ru", "@sibcem.ru")
if not entries: entries = search_by_user_id(search_id, attributes=['extensionAttribute2'])
raise Exception("Пользователь не найден в AD.")
entry = entries[0] if entries and 'extensionAttribute2' in entries[0] and entries[0].extensionAttribute2.value:
if 'extensionAttribute2' in entry and entry.extensionAttribute2.value: return str(entries[0].extensionAttribute2.value).strip()
return str(entry.extensionAttribute2.value).strip()
raise Exception("Поле extensionAttribute2 не заполнено в AD.") raise Exception("Поле extensionAttribute2 не заполнено в AD.")
except Exception as e: except Exception as e:
raise Exception("AD Card Query Error: {}".format(e)) raise Exception(f"AD Card Query Error: {e}")
# ========================================================= # =========================================================
# МОДНОЕ УНИВЕРСАЛЬНОЕ ЯДРО ПАГИНАЦИИ СПИСКОВ ДЛЯ ЧАТА # МОДНОЕ УНИВЕРСАЛЬНОЕ ЯДРО ПАГИНАЦИИ СПИСКОВ ДЛЯ ЧАТА
@@ -205,12 +204,25 @@ async def send_dynamic_lk_main_menu(msg: Message, user_id: str):
await msg.answer(menu_text, parse_mode="html") await msg.answer(menu_text, parse_mode="html")
async def send_tabel_months_menu(msg: Message, user_id: str): async def send_tabel_months_menu(msg: Message, user_id: str):
now = datetime(2026, 6, 3) now = datetime.now()
prev_1 = now.replace(day=1) - timedelta(days=1) m1 = now.replace(day=1) - timedelta(days=1) # Прошлый месяц (M-1)
prev_2 = prev_1.replace(day=1) - timedelta(days=1) m2 = m1.replace(day=1) - timedelta(days=1) # Позапрошлый месяц (M-2)
months_ru = {1: "Январь", 2: "Февраль", 3: "Март", 4: "Апрель", 5: "Май", 6: "Июнь", 7: "Июль", 8: "Август", 9: "Сентябрь", 10: "Октябрь", 11: "Ноябрь", 12: "Декабрь"}
months_ru = {
1: "Январь", 2: "Февраль", 3: "Март", 4: "Апрель", 5: "Май", 6: "Июнь",
7: "Июль", 8: "Август", 9: "Сентябрь", 10: "Октябрь", 11: "Ноябрь", 12: "Декабрь"
}
m1_str = f"{months_ru[m1.month]} {m1.year} г."
m2_str = f"{months_ru[m2.month]} {m2.year} г."
menu_text = (
"⏱ <b>Выберите месяц для просмотра табеля:</b>\n\n"
f"{EMOJI_DIGITS['1']}{m1_str}\n"
f"{EMOJI_DIGITS['2']}{m2_str}\n\n"
f"<i>{EMOJI_DIGITS['9']} — Назад\n{EMOJI_DIGITS['0']} — В главное меню</i>"
)
menu_text = lk_tabel_months_menu_text(prev_1, prev_2, months_ru, EMOJI_DIGITS)
set_state(user_id, "LK_TABEL_MONTHS") set_state(user_id, "LK_TABEL_MONTHS")
await msg.answer(menu_text, parse_mode="html") await msg.answer(menu_text, parse_mode="html")
@@ -266,13 +278,22 @@ async def build_confirmation_text(user_id: str, doc: dict) -> str:
async def lk_router_handler(msg: Message): async def lk_router_handler(msg: Message):
user_id = msg.from_user.id user_id = msg.from_user.id
current_time = time.time() current_time = time.time()
if current_time - user_last_request.get(user_id, 0) < USER_COOLDOWN_SEC: return current_state = get_state(user_id)
# Если пользователь находится внутри меню ЛК, помечаем сообщение обработанным,
# чтобы оно не улетало в ServiceDesk / Instruct роутеры
if current_state and current_state.startswith("LK_"):
msg.handled = True
# Проверка на слишком частые клики (кулдаун)
if current_time - user_last_request.get(user_id, 0) < USER_COOLDOWN_SEC:
return
user_last_request[user_id] = current_time user_last_request[user_id] = current_time
current_state = get_state(user_id)
nav_text = lk_nav_text(EMOJI_DIGITS) nav_text = lk_nav_text(EMOJI_DIGITS)
if not msg.text: return if not msg.text:
return
cmd = msg.text.strip().lower() cmd = msg.text.strip().lower()
for raw_num, emoji_num in EMOJI_DIGITS.items(): for raw_num, emoji_num in EMOJI_DIGITS.items():
@@ -371,7 +392,6 @@ async def lk_router_handler(msg: Message):
set_state(user_id, "LK_DOCS_MENU") set_state(user_id, "LK_DOCS_MENU")
await msg.answer(LK_DOCS_MENU_TEXT, parse_mode="html") await msg.answer(LK_DOCS_MENU_TEXT, parse_mode="html")
else: else:
# 🎯 ИСПРАВЛЕНО: Вместо спама копии меню ЛК выводим строгое предупреждение
await msg.answer(UNKNOWN_MAIN_CMD_TEXT, parse_mode="html") await msg.answer(UNKNOWN_MAIN_CMD_TEXT, parse_mode="html")
elif current_state == "LK_TABEL_MONTHS": elif current_state == "LK_TABEL_MONTHS":
@@ -384,16 +404,28 @@ async def lk_router_handler(msg: Message):
set_state(user_id, "LK_MODE") set_state(user_id, "LK_MODE")
await send_dynamic_lk_main_menu(msg, user_id) await send_dynamic_lk_main_menu(msg, user_id)
elif cmd in ["1", "2"]: elif cmd in ["1", "2"]:
log_menu_stats(user_id, "Личный кабинет", "Просмотр табеля за месяц") log_menu_stats(user_id, "Личный кабинет", f"Просмотр табеля (вариант {cmd})")
await msg.answer(lk_tabel_loading(EMOJI_DIGITS), parse_mode="html") await msg.answer(lk_tabel_loading(EMOJI_DIGITS), parse_mode="html")
try: try:
card_id = await asyncio.to_thread(get_card_id_from_ad, user_id) card_id = await asyncio.to_thread(get_card_id_from_ad, user_id)
now = datetime(2026, 6, 3) now = datetime.now()
target_date = now.replace(day=1) - timedelta(days=1) if cmd == "1" else (now.replace(day=1) - timedelta(days=1)).replace(day=1) - timedelta(days=1)
tabel_report = await asyncio.to_thread(get_tabel_report_text, card_id, target_date.year, target_date.month) m1 = now.replace(day=1) - timedelta(days=1)
if cmd == "1":
target_date = m1 # Прошлый месяц
elif cmd == "2":
target_date = m1.replace(day=1) - timedelta(days=1) # Позапрошлый месяц
tabel_report = await asyncio.to_thread(
get_tabel_report_text,
card_id,
target_date.year,
target_date.month
)
set_state(user_id, "LK_TABEL_VIEW") set_state(user_id, "LK_TABEL_VIEW")
await msg.answer(tabel_report + nav_text, parse_mode="html") await msg.answer(tabel_report + nav_text, parse_mode="html")
except Exception as e: await handle_lk_error(msg, user_id, "Формирование табеля", str(e)) except Exception as e:
await handle_lk_error(msg, user_id, "Формирование табеля", str(e))
else: else:
await msg.answer(UNKNOWN_MAIN_CMD_TEXT, parse_mode="html") await msg.answer(UNKNOWN_MAIN_CMD_TEXT, parse_mode="html")
@@ -577,7 +609,6 @@ async def lk_router_handler(msg: Message):
set_state(user_id, "LK_DOCS_QUANTITY") set_state(user_id, "LK_DOCS_QUANTITY")
await msg.answer(lk_docs_quantity_prompt(EMOJI_DIGITS), parse_mode="html") await msg.answer(lk_docs_quantity_prompt(EMOJI_DIGITS), parse_mode="html")
else: else:
# 🎯 ИСПРАВЛЕНО: Заменен спам списка документов на чистую ошибку ввода
await msg.answer(UNKNOWN_MAIN_CMD_TEXT, parse_mode="html") await msg.answer(UNKNOWN_MAIN_CMD_TEXT, parse_mode="html")
elif current_state == "LK_DOCS_QUANTITY": elif current_state == "LK_DOCS_QUANTITY":
@@ -605,7 +636,6 @@ async def lk_router_handler(msg: Message):
confirm_txt = await build_confirmation_text(user_id, user_docs_session[user_id]) confirm_txt = await build_confirmation_text(user_id, user_docs_session[user_id])
await msg.answer(confirm_txt, parse_mode="html") await msg.answer(confirm_txt, parse_mode="html")
else: else:
# 🎯 ИСПРАВЛЕНО: Вместо кастомной подсказки выводим единый стандарт
await msg.answer(UNKNOWN_MAIN_CMD_TEXT, parse_mode="html") await msg.answer(UNKNOWN_MAIN_CMD_TEXT, parse_mode="html")
elif current_state == "LK_DOCS_PERIOD": elif current_state == "LK_DOCS_PERIOD":
@@ -618,14 +648,12 @@ async def lk_router_handler(msg: Message):
if cmd in ["1", "2", "3", "4", "5", "6", "7", "8"]: if cmd in ["1", "2", "3", "4", "5", "6", "7", "8"]:
user_docs_session[user_id]['period'] = f"за {datetime.now().year - (int(cmd) - 1)} год" user_docs_session[user_id]['period'] = f"за {datetime.now().year - (int(cmd) - 1)} год"
else: else:
# 🎯 ИСПРАВЛЕНО: Убран спам меню годов при абракадабре
await msg.answer(UNKNOWN_MAIN_CMD_TEXT, parse_mode="html") await msg.answer(UNKNOWN_MAIN_CMD_TEXT, parse_mode="html")
return return
elif doc_id == "5": elif doc_id == "5":
if cmd == "1": user_docs_session[user_id]['period'] = "до 1.5 лет" if cmd == "1": user_docs_session[user_id]['period'] = "до 1.5 лет"
elif cmd == "2": user_docs_session[user_id]['period'] = "до 3 лет" elif cmd == "2": user_docs_session[user_id]['period'] = "до 3 лет"
else: else:
# 🎯 ИСПРАВЛЕНО: Убран спам меню возраста при некорректном вводе
await msg.answer(UNKNOWN_MAIN_CMD_TEXT, parse_mode="html") await msg.answer(UNKNOWN_MAIN_CMD_TEXT, parse_mode="html")
return return
elif doc_id == "3": elif doc_id == "3":
@@ -669,7 +697,6 @@ async def lk_router_handler(msg: Message):
except Exception as e: await handle_lk_error(msg, user_id, f"Заказ справки {user_docs_session.get(user_id, {}).get('doc_id')}", str(e)); set_state(user_id, "LK_MODE") except Exception as e: await handle_lk_error(msg, user_id, f"Заказ справки {user_docs_session.get(user_id, {}).get('doc_id')}", str(e)); set_state(user_id, "LK_MODE")
finally: user_docs_session.pop(user_id, None) finally: user_docs_session.pop(user_id, None)
else: else:
# 🎯 ИСПРАВЛЕНО: Удален спам-текст подтверждения
await msg.answer(UNKNOWN_MAIN_CMD_TEXT, parse_mode="html") await msg.answer(UNKNOWN_MAIN_CMD_TEXT, parse_mode="html")
elif current_state == "LK_DOCS_SUCCESS": elif current_state == "LK_DOCS_SUCCESS":
@@ -677,5 +704,4 @@ async def lk_router_handler(msg: Message):
if cmd == "0": clear_state(user_id); from utils.menu import MENU_TEXT; await msg.answer(MENU_TEXT, parse_mode="html") if cmd == "0": clear_state(user_id); from utils.menu import MENU_TEXT; await msg.answer(MENU_TEXT, parse_mode="html")
elif cmd == "9": set_state(user_id, "LK_DOCS_MENU"); await msg.answer(LK_DOCS_MENU_TEXT, parse_mode="html") elif cmd == "9": set_state(user_id, "LK_DOCS_MENU"); await msg.answer(LK_DOCS_MENU_TEXT, parse_mode="html")
else: else:
# 🎯 ИСПРАВЛЕНО: Унифицировано под общий шаблон ошибки
await msg.answer(UNKNOWN_MAIN_CMD_TEXT, parse_mode="html") await msg.answer(UNKNOWN_MAIN_CMD_TEXT, parse_mode="html")