74a855819d
Из ТЗ Кибершколы БАЗА эти сценарии заменены воронкой подбора, поэтому убран мёртвый код: - клиентские FSM: FORM_* (форма-заявка, возвращающийся клиент, редактирование, согласия, выбор услуги, карусель) и VAC_* (карьера: игроки/сотрудники); - меню «Частые вопросы» и config.FAQ_ANSWERS; - осиротевшая админка: управление услугами + карусель, вакансии, кандидаты (в панели и в мастере ADMIN_SVC_*/ADMIN_VAC_*), блок статистики по откликам; - старый _handoff_to_operator и _notify_operator_about_lead (заменены _baza_to_manager); - неиспользуемые клавиатуры (форма/услуги/вакансии/согласия) и импорты (validators, random, string). Оставлено (используется/по ТЗ): воронка БАЗА, быстрые ответы (custom_faq), стата по лидам, рассылка, управление админами, чат с оператором, логотип. Слой БД не тронут — существующие установки не ломаются (таблицы services/applications/vacancy_options просто не используются). bot.py: -1490 строк. Тесты: pytest 28 passed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
142 lines
5.8 KiB
Python
142 lines
5.8 KiB
Python
import bot
|
||
|
||
|
||
def _state(uid):
|
||
return bot.db.get_user_data(uid)["state"]
|
||
|
||
|
||
def _prof(uid):
|
||
return bot.db.get_profile(uid)
|
||
|
||
|
||
def test_baza_group_funnel_to_payment(app):
|
||
"""Полный подбор → групповой абонемент → шаг оплаты (BAZA_PAY)."""
|
||
u = 70001
|
||
app.handle_message(u, "Подобрать тренировку 🎯"); assert _state(u) == "BAZA_FORWHO"
|
||
app.handle_message(u, "Для подростка"); assert _state(u) == "BAZA_AGE"
|
||
app.handle_message(u, "14–15 лет"); assert _state(u) == "BAZA_GAME"
|
||
app.handle_message(u, "CS2"); assert _state(u) == "BAZA_LEVEL"
|
||
app.handle_message(u, "Играет для себя"); assert _state(u) == "BAZA_FORMAT"
|
||
app.handle_message(u, "Групповые тренировки"); assert _state(u) == "BAZA_GROUP"
|
||
app.handle_message(u, "Купить 4 тренировки"); assert _state(u) == "BAZA_PAY"
|
||
p = _prof(u)
|
||
assert p["role"].startswith("Для подростка") and p["game"] == "CS2"
|
||
assert p["format"] == "Групповые тренировки" and "4" in p["tariff"]
|
||
assert {"role_parent", "game_cs2", "format_group", "clicked_payment", "lead_hot"} <= set(p["metki"])
|
||
|
||
|
||
def test_baza_individual_and_back(app):
|
||
"""Индивидуальная ветка + кнопка «Назад» возвращает на предыдущий шаг."""
|
||
u = 70011
|
||
app.handle_message(u, "Подобрать тренировку 🎯")
|
||
app.handle_message(u, "Для себя"); assert _state(u) == "BAZA_AGE"
|
||
app.handle_message(u, "16 лет и старше"); assert _state(u) == "BAZA_GAME"
|
||
app.handle_message(u, "Назад ⬅️"); assert _state(u) == "BAZA_AGE"
|
||
app.handle_message(u, "16 лет и старше")
|
||
app.handle_message(u, "Dota 2"); assert _state(u) == "BAZA_LEVEL"
|
||
app.handle_message(u, "Есть рейтинг или ранг")
|
||
app.handle_message(u, "Индивидуальные тренировки"); assert _state(u) == "BAZA_INDIVIDUAL"
|
||
app.handle_message(u, "Купить 8 тренировок"); assert _state(u) == "BAZA_PAY"
|
||
assert "8" in _prof(u)["tariff"]
|
||
|
||
|
||
def test_baza_under12_goes_to_manager(app):
|
||
u = 70012
|
||
app.handle_message(u, "Подобрать тренировку 🎯")
|
||
app.handle_message(u, "Для подростка")
|
||
app.handle_message(u, "Младше 12 лет"); assert _state(u) == "BAZA_YOUNG"
|
||
app.handle_message(u, "Обсудить с менеджером 💬")
|
||
assert _state(u) == "OPERATOR_CHAT"
|
||
assert "age_under12" in _prof(u)["metki"]
|
||
|
||
|
||
def test_baza_other_game_goes_to_manager(app):
|
||
u = 70013
|
||
app.handle_message(u, "Подобрать тренировку 🎯")
|
||
app.handle_message(u, "Для себя")
|
||
app.handle_message(u, "16 лет и старше")
|
||
app.handle_message(u, "Другая игра"); assert _state(u) == "BAZA_GAME_OTHER"
|
||
app.handle_message(u, "Valorant"); assert _state(u) == "OPERATOR_CHAT"
|
||
assert "Valorant" in _prof(u)["game"]
|
||
|
||
|
||
def test_baza_intensive_by_keyword(app):
|
||
"""Кодовое слово «лето» запускает интенсив; ветка доходит до оплаты."""
|
||
u = 70014
|
||
app.handle_message(u, "лето"); assert _state(u) == "BAZA_INT_INFO"
|
||
app.handle_message(u, "Хочу участвовать 🔥"); assert _state(u) == "BAZA_INT_AGE"
|
||
app.handle_message(u, "14–15 лет"); assert _state(u) == "BAZA_INT_LEVEL"
|
||
app.handle_message(u, "Играет в команде или турнирах"); assert _state(u) == "BAZA_PAY"
|
||
assert "intensive_interest" in _prof(u)["metki"]
|
||
|
||
|
||
def test_baza_question_button_handoff(app):
|
||
u = 70015
|
||
app.handle_message(u, "Задать вопрос 💬"); assert _state(u) == "OPERATOR_CHAT"
|
||
assert "lead_manager" in _prof(u)["metki"]
|
||
|
||
|
||
def test_baza_prices_and_menu(app):
|
||
u = 70016
|
||
app._sent.clear()
|
||
app.handle_message(u, "Посмотреть цены 💰")
|
||
assert _state(u) == "FREE_CHAT"
|
||
assert any("2 790" in s["msg"] for s in app._sent)
|
||
|
||
|
||
def test_flood_does_not_crash(app):
|
||
u = 70002
|
||
for _ in range(25):
|
||
app.handle_message(u, "спам")
|
||
# бот не падает; пользователь остаётся в FREE_CHAT (флуд/бан только игнорят)
|
||
assert _state(u) == "FREE_CHAT"
|
||
|
||
|
||
def test_admin_panel_visible_to_super(app):
|
||
admin = bot.config.SUPER_ADMIN_IDS[0]
|
||
app._sent.clear()
|
||
app.handle_message(admin, "Админка ⚙️")
|
||
assert any("Статистика" in (s["kb"] or "") for s in app._sent)
|
||
|
||
|
||
def test_non_admin_cannot_open_panel(app):
|
||
app._sent.clear()
|
||
app.handle_message(424242, "Админка ⚙️")
|
||
assert not any("Админ-панель" in s["msg"] for s in app._sent)
|
||
|
||
|
||
def _admin():
|
||
return bot.config.SUPER_ADMIN_IDS[0]
|
||
|
||
|
||
def test_admin_faq_crud(app):
|
||
a = _admin()
|
||
app.handle_message(a, "Быстрые ответы 💬")
|
||
app.handle_message(a, "➕ Добавить ответ")
|
||
app.handle_message(a, "вопрос | ответ")
|
||
assert any(kw == "вопрос" for _, kw, _ in bot.db.get_custom_faq())
|
||
|
||
|
||
def test_admin_add_remove_admin(app):
|
||
a = _admin()
|
||
app.handle_message(a, "Администраторы 👑")
|
||
app.handle_message(a, "➕ Добавить админа")
|
||
app.handle_message(a, "888001")
|
||
assert 888001 in bot.db.get_admins()
|
||
assert app._is_admin(888001)
|
||
|
||
|
||
def test_broadcast_preview_and_cancel(app):
|
||
a = _admin()
|
||
app.handle_message(a, "рассылка Привет, акция!")
|
||
assert a in app._pending_broadcasts
|
||
app.handle_message(a, "Отмена ❌")
|
||
assert a not in app._pending_broadcasts
|
||
|
||
|
||
def test_stats_runs(app):
|
||
a = _admin()
|
||
app._sent.clear()
|
||
app.handle_message(a, "Статистика 📊")
|
||
assert any("Статистика" in s["msg"] for s in app._sent)
|