diff --git a/bot.py b/bot.py index ab35c47..64c0fbf 100644 --- a/bot.py +++ b/bot.py @@ -695,17 +695,48 @@ class VKBotApplication: return True return False + # Шаги воронки: порядок и какое поле профиля заполняет каждый (format — без поля, + # это выбор действия, поэтому спрашивается всегда). + _FUNNEL_ORDER = ["BAZA_FORWHO", "BAZA_AGE", "BAZA_GAME", "BAZA_LEVEL", "BAZA_FORMAT"] + _FUNNEL_FIELD = {"BAZA_FORWHO": "role", "BAZA_AGE": "age", "BAZA_GAME": "game", "BAZA_LEVEL": "level"} + + def _baza_ask(self, user_id: int, state: str): + """Задаёт вопрос конкретного шага воронки и ставит соответствующее состояние.""" + prompts = { + "BAZA_FORWHO": ("Для кого подбираем тренировки?", get_baza_forwho_keyboard()), + "BAZA_AGE": ("Сколько лет игроку?", get_baza_age_keyboard()), + "BAZA_GAME": ("По какой игре хотите заниматься?", get_baza_game_keyboard()), + "BAZA_LEVEL": ("Как бы вы описали текущий уровень игрока?", get_baza_level_keyboard()), + "BAZA_FORMAT": ("Какой формат рассматриваете?", get_baza_format_keyboard()), + } + msg, kb = prompts[state] + db.update_user_state(user_id, state) + self.send_message(user_id, msg, keyboard=kb) + + def _baza_advance(self, user_id: int, from_state=None): + """Переходит к следующему шагу воронки, ПРОПУСКАЯ уже заполненные поля (§15).""" + p = db.get_profile(user_id) + start = 0 if from_state is None else self._FUNNEL_ORDER.index(from_state) + 1 + for state in self._FUNNEL_ORDER[start:]: + field = self._FUNNEL_FIELD.get(state) + if not field or not p.get(field): + self._baza_ask(user_id, state) + return + self._baza_ask(user_id, "BAZA_FORMAT") + def _baza_start_funnel(self, user_id: int): - """Старт воронки «Подобрать тренировку».""" + """Старт воронки «Подобрать тренировку» (уже известные ответы не переспрашиваем).""" self._baza_started(user_id) db.set_profile_field(user_id, "source", "Основное меню") db.add_metka(user_id, "source_main_menu") - db.update_user_state(user_id, "BAZA_FORWHO") - self.send_message( - user_id, - "Для кого подбираем тренировки?", - keyboard=get_baza_forwho_keyboard() - ) + p = db.get_profile(user_id) + if any(p.get(f) for f in ("role", "age", "game", "level")): + self.send_message( + user_id, + "С возвращением! Что вы уже указывали, переспрашивать не буду. " + "Если нужно изменить прошлый ответ — нажмите «Назад ⬅️»." + ) + self._baza_advance(user_id, None) def _handle_baza_forwho(self, user_id: int, text: str, text_lower: str): if self._baza_nav(user_id, text_lower): @@ -719,8 +750,7 @@ class VKBotApplication: else: self.send_message(user_id, "Выберите вариант на кнопках ниже 👇", keyboard=get_baza_forwho_keyboard()) return - db.update_user_state(user_id, "BAZA_AGE") - self.send_message(user_id, "Сколько лет игроку?", keyboard=get_baza_age_keyboard()) + self._baza_advance(user_id, "BAZA_FORWHO") def _handle_baza_age(self, user_id: int, text: str, text_lower: str): if self._baza_nav(user_id, text_lower): @@ -750,8 +780,7 @@ class VKBotApplication: self.send_message(user_id, "Выберите возраст на кнопках ниже 👇", keyboard=get_baza_age_keyboard()) return db.set_profile_field(user_id, "age", age) - db.update_user_state(user_id, "BAZA_GAME") - self.send_message(user_id, "По какой игре хотите заниматься?", keyboard=get_baza_game_keyboard()) + self._baza_advance(user_id, "BAZA_AGE") def _handle_baza_young(self, user_id: int, text: str, text_lower: str): if text_lower.startswith("обсудить"): @@ -793,8 +822,7 @@ class VKBotApplication: return db.set_profile_field(user_id, "game", game) db.add_metka(user_id, metka) - db.update_user_state(user_id, "BAZA_LEVEL") - self.send_message(user_id, "Как бы вы описали текущий уровень игрока?", keyboard=get_baza_level_keyboard()) + self._baza_advance(user_id, "BAZA_GAME") def _handle_baza_game_other(self, user_id: int, text: str, text_lower: str): if self._baza_nav(user_id, text_lower): @@ -827,8 +855,7 @@ class VKBotApplication: self.send_message(user_id, "Выберите уровень на кнопках ниже 👇", keyboard=get_baza_level_keyboard()) return db.set_profile_field(user_id, "level", match) - db.update_user_state(user_id, "BAZA_FORMAT") - self.send_message(user_id, "Какой формат рассматриваете?", keyboard=get_baza_format_keyboard()) + self._baza_advance(user_id, "BAZA_LEVEL") def _handle_baza_format(self, user_id: int, text: str, text_lower: str): if self._baza_nav(user_id, text_lower): @@ -985,8 +1012,14 @@ class VKBotApplication: if self._baza_nav(user_id, text_lower): return if "участвовать" in text_lower or "записаться" in text_lower or "хочу" in text_lower or "да" == text_lower: - db.update_user_state(user_id, "BAZA_INT_AGE") - self.send_message(user_id, "Сколько лет игроку?", keyboard=get_baza_age_keyboard()) + age = (db.get_profile(user_id).get("age") or "").lower() + if age and "младше 12" not in age: + # возраст уже известен из подбора — не переспрашиваем (§15) + db.update_user_state(user_id, "BAZA_INT_LEVEL") + self.send_message(user_id, "Какой сейчас уровень в CS2?", keyboard=get_baza_int_level_keyboard()) + else: + db.update_user_state(user_id, "BAZA_INT_AGE") + self.send_message(user_id, "Сколько лет игроку?", keyboard=get_baza_age_keyboard()) return self.send_message(user_id, "Выберите действие на кнопках ниже 👇", keyboard=get_baza_intensive_keyboard()) diff --git a/tests/test_flow.py b/tests/test_flow.py index 4ec233d..724d973 100644 --- a/tests/test_flow.py +++ b/tests/test_flow.py @@ -62,6 +62,32 @@ def test_baza_other_game_goes_to_manager(app): assert "Valorant" in _prof(u)["game"] +def test_baza_smart_skip_known_fields(app): + """§15: уже сохранённые ответы не переспрашиваются.""" + u = 70020 + bot.db.set_profile_field(u, "role", "Игрок (пишет сам)") + bot.db.set_profile_field(u, "age", "16 лет и старше") + # роль и возраст известны → воронка стартует сразу с игры + app.handle_message(u, "Подобрать тренировку 🎯") + assert _state(u) == "BAZA_GAME" + # уровень известен → после игры сразу формат (пропуская уровень) + bot.db.set_profile_field(u, "level", "Играет для себя") + app.handle_message(u, "CS2") + assert _state(u) == "BAZA_FORMAT" + # «Назад» позволяет переопределить пропущенный уровень + app.handle_message(u, "Назад ⬅️") + assert _state(u) == "BAZA_LEVEL" + + +def test_baza_intensive_skips_known_age(app): + """§15: в интенсиве известный возраст не переспрашивается.""" + u = 70021 + bot.db.set_profile_field(u, "age", "14–15 лет") + app.handle_message(u, "Летний интенсив CS2 🔥") + app.handle_message(u, "Хочу участвовать 🔥") + assert _state(u) == "BAZA_INT_LEVEL" # возраст пропущен + + def test_baza_intensive_by_keyword(app): """Кодовое слово «лето» запускает интенсив; ветка доходит до оплаты.""" u = 70014