Обновить lk/handlers.py
This commit is contained in:
+56
-30
@@ -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")
|
||||||
Reference in New Issue
Block a user