Тикеты заявок, «пробное занятие», доработка ветки вебинара
- Тикеты: add_lead возвращает id заявки; при передаче менеджеру клиент получает «🎫 Номер вашей заявки: №N», тот же номер — в карточке оператору и в письме. Один тикет на заход (сбрасывается при новом старте воронки/интенсива). - Кнопка «Записаться на пробное» → «Записаться на пробное занятие» (лейблы + распознавание). - Ветка вебинара: вход по callback-кнопке и по тексту «записаться на вебинар», текст выровнен по ТЗ, после регистрации состояние FREE_CHAT — основное меню остаётся доступным (не блокирует продающую ветку). Дата/время — в config. Тесты: test_baza_question_ticket, test_webinar_registration. pytest 36 passed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+19
-1
@@ -377,7 +377,7 @@ class DatabaseManager:
|
||||
def add_lead(self, user_id: int, source: str, name: str, phone: str,
|
||||
service: Optional[str] = None, call_time: Optional[str] = None,
|
||||
promo: Optional[str] = None, marketing: bool = False):
|
||||
"""Записать завершённую заявку в единый журнал leads (для статистики и истории)."""
|
||||
"""Записать завершённую заявку в единый журнал leads. Возвращает id заявки (тикет)."""
|
||||
with self._get_connection() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(
|
||||
@@ -386,6 +386,7 @@ class DatabaseManager:
|
||||
(user_id, source, name, phone, service, call_time, promo, 1 if marketing else 0)
|
||||
)
|
||||
conn.commit()
|
||||
return cursor.lastrowid
|
||||
|
||||
def get_marketing_subscribers(self) -> list:
|
||||
"""Список user_id, давших согласие на маркетинговую рассылку (consent_2 = 'Согласен')."""
|
||||
@@ -606,6 +607,23 @@ class DatabaseManager:
|
||||
return answer
|
||||
return None
|
||||
|
||||
# --- Вебинар: список зарегистрированных ---
|
||||
def get_webinar_registered_users(self) -> list:
|
||||
"""Список user_id с меткой 'webinar_registered' (профиль JSON)."""
|
||||
with self._get_connection() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT user_id, profile FROM user_states WHERE profile IS NOT NULL")
|
||||
result = []
|
||||
for uid, profile_json in cursor.fetchall():
|
||||
try:
|
||||
profile = json.loads(profile_json) if profile_json else {}
|
||||
except (ValueError, TypeError):
|
||||
profile = {}
|
||||
metki = profile.get("metki", [])
|
||||
if "webinar_registered" in metki:
|
||||
result.append(uid)
|
||||
return result
|
||||
|
||||
# --- Отклики: статусы и статистика ---
|
||||
def set_application_status(self, app_id: int, status: str) -> bool:
|
||||
with self._get_connection() as conn:
|
||||
|
||||
Reference in New Issue
Block a user