mirror of
https://github.com/olegvodyanov/docbot.git
synced 2025-12-19 23:57:05 +03:00
update logic, add time zones, add new db fields, send payment link
This commit is contained in:
parent
547cac174d
commit
dfb3de958b
@ -2,6 +2,7 @@ import uuid
|
|||||||
import hashlib
|
import hashlib
|
||||||
import base64
|
import base64
|
||||||
import re
|
import re
|
||||||
|
import pytz
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
@ -11,7 +12,7 @@ def UUID_code_generator(code_length: int) -> str:
|
|||||||
Генерирует уникальный код в формате UUID.
|
Генерирует уникальный код в формате UUID.
|
||||||
Возвращает строку с кодом.
|
Возвращает строку с кодом.
|
||||||
"""
|
"""
|
||||||
return str(uuid.uuid4().hex[:{code_length}].upper())
|
return str(uuid.uuid4().hex[:code_length].upper())
|
||||||
|
|
||||||
|
|
||||||
def generate_session_code(telegram_id: int, phone: str, consultation_date_time: str) -> str:
|
def generate_session_code(telegram_id: int, phone: str, consultation_date_time: str) -> str:
|
||||||
@ -40,6 +41,22 @@ def is_phone_correct(phone: str) -> bool:
|
|||||||
return re.match(regex, normalized)
|
return re.match(regex, normalized)
|
||||||
|
|
||||||
|
|
||||||
|
def get_timezones():
|
||||||
|
return_value = {}
|
||||||
|
for tz in pytz.common_timezones:
|
||||||
|
c = tz.split("/")
|
||||||
|
if len(c) > 1:
|
||||||
|
if c[0] not in return_value.keys():
|
||||||
|
return_value[c[0]] = []
|
||||||
|
return_value[c[0]].append(c[1])
|
||||||
|
|
||||||
|
for i in ["GMT"]:
|
||||||
|
if i in return_value.keys():
|
||||||
|
return_value.pop(i)
|
||||||
|
|
||||||
|
return return_value
|
||||||
|
|
||||||
|
|
||||||
def is_valid_url(text: str) -> bool:
|
def is_valid_url(text: str) -> bool:
|
||||||
try:
|
try:
|
||||||
result = urlparse(text)
|
result = urlparse(text)
|
||||||
|
|||||||
@ -83,6 +83,8 @@ class Doctors(Base):
|
|||||||
__tablename__ = "doctors"
|
__tablename__ = "doctors"
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||||
|
code: Mapped[str] = mapped_column(unique=True, nullable=True)
|
||||||
|
time_zone: Mapped[Optional[str]] = mapped_column(nullable=True)
|
||||||
telegram_id: Mapped[int] = mapped_column(unique=True, nullable=False)
|
telegram_id: Mapped[int] = mapped_column(unique=True, nullable=False)
|
||||||
name: Mapped[str] = mapped_column(nullable=False)
|
name: Mapped[str] = mapped_column(nullable=False)
|
||||||
available_formats: Mapped[Optional[List[str]]
|
available_formats: Mapped[Optional[List[str]]
|
||||||
|
|||||||
@ -5,6 +5,7 @@ from telegram.ext import (
|
|||||||
CommandHandler,
|
CommandHandler,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from core.logging import logger
|
||||||
from docbot.services.doctors_service import get_doctors_names
|
from docbot.services.doctors_service import get_doctors_names
|
||||||
from docbot.services.admins_service import get_admin_info
|
from docbot.services.admins_service import get_admin_info
|
||||||
|
|
||||||
@ -22,9 +23,14 @@ async def get_doctors(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int
|
|||||||
return ConversationHandler.END
|
return ConversationHandler.END
|
||||||
|
|
||||||
doctors = await get_doctors_names()
|
doctors = await get_doctors_names()
|
||||||
|
doctors_table = ""
|
||||||
|
for row in doctors:
|
||||||
|
logger.info(f"{row.Doctors.name} {row.VerificationRequests.code}")
|
||||||
|
doctors_table += f"\n- {row.Doctors.name} (код врача: {row.Doctors.code}) (код верификации: {row.VerificationRequests.code})"
|
||||||
|
|
||||||
if doctors:
|
if doctors:
|
||||||
await update.message.reply_text(
|
await update.message.reply_text(
|
||||||
f"📝 Список активных врачей. \n {doctors}",
|
f"📝 Список активных врачей. \n {doctors_table}",
|
||||||
parse_mode="Markdown"
|
parse_mode="Markdown"
|
||||||
)
|
)
|
||||||
return ConversationHandler.END
|
return ConversationHandler.END
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
from telegram import Update, ReplyKeyboardMarkup, ReplyKeyboardRemove
|
from telegram import Update, ReplyKeyboardMarkup, ReplyKeyboardRemove, InlineKeyboardButton
|
||||||
from telegram.ext import (
|
from telegram.ext import (
|
||||||
ContextTypes,
|
ContextTypes,
|
||||||
ConversationHandler,
|
ConversationHandler,
|
||||||
@ -11,7 +11,8 @@ from docbot.handlers.utils.cancel_handler import get_cancel_handler
|
|||||||
from docbot.services.referral_service import validate_referral_code
|
from docbot.services.referral_service import validate_referral_code
|
||||||
from docbot.services.doctors_service import create_doctor
|
from docbot.services.doctors_service import create_doctor
|
||||||
from core.enums.dialog_helpers import ConfirmationMessage, Acknowledgement
|
from core.enums.dialog_helpers import ConfirmationMessage, Acknowledgement
|
||||||
from core.utils import UUID_code_generator
|
from core.utils import UUID_code_generator, get_timezones
|
||||||
|
from core.logging import logger
|
||||||
|
|
||||||
ASK_REFERRAL_CODE = 1
|
ASK_REFERRAL_CODE = 1
|
||||||
SEND_ACKNOWLEDGEMENT_INFO = 2
|
SEND_ACKNOWLEDGEMENT_INFO = 2
|
||||||
@ -19,6 +20,8 @@ ASK_NAME = 3
|
|||||||
ASK_SPECIALITY = 4
|
ASK_SPECIALITY = 4
|
||||||
SEND_DIPLOMA_ACK_INFO = 5
|
SEND_DIPLOMA_ACK_INFO = 5
|
||||||
SEND_CONSULTATION_TYPE_ACK_INFO = 6
|
SEND_CONSULTATION_TYPE_ACK_INFO = 6
|
||||||
|
ASK_TIMEZONE = 7
|
||||||
|
ASK_CONTINENT = 8
|
||||||
|
|
||||||
SEND_ME_REFERRAL_CODE_TEXT = (
|
SEND_ME_REFERRAL_CODE_TEXT = (
|
||||||
"✌️ Пожалуйста, пришлите реферальный код, чтобы начать процесс регистрации."
|
"✌️ Пожалуйста, пришлите реферальный код, чтобы начать процесс регистрации."
|
||||||
@ -34,6 +37,9 @@ SEND_ME_YOUR_SPECIALITY_TEXT = (
|
|||||||
"📝 Пожалуйста, введите вашу специальность/специальности, в соответствии с которой планируете проводить консультации.\n"
|
"📝 Пожалуйста, введите вашу специальность/специальности, в соответствии с которой планируете проводить консультации.\n"
|
||||||
"Например: терапевт, кардиолог, невролог и т.д."
|
"Например: терапевт, кардиолог, невролог и т.д."
|
||||||
)
|
)
|
||||||
|
SELECT_YOUR_TIMEZONE_TEXT = (
|
||||||
|
"📝 Пожалуйста, выбирете временную зону, в соответствии с которой планируете проводить консультации.\n"
|
||||||
|
)
|
||||||
WAIT_FOR_ACTIVATION_TEXT = (
|
WAIT_FOR_ACTIVATION_TEXT = (
|
||||||
"📝 Заявка принята, направьте диплом и аккредитацию с указанием кода верификации {0} в теме письма на адрес электронной почты: docbot@docbot.ru\n"
|
"📝 Заявка принята, направьте диплом и аккредитацию с указанием кода верификации {0} в теме письма на адрес электронной почты: docbot@docbot.ru\n"
|
||||||
"В этом шаге нужно встроить подсказку: в каком формате направлять диплом, как скачать с госуслуг\n"
|
"В этом шаге нужно встроить подсказку: в каком формате направлять диплом, как скачать с госуслуг\n"
|
||||||
@ -101,6 +107,43 @@ async def receive_doctor_name(update: Update, context: ContextTypes.DEFAULT_TYPE
|
|||||||
doctor_name = update.message.text.strip()
|
doctor_name = update.message.text.strip()
|
||||||
context.user_data["doctor_name"] = doctor_name
|
context.user_data["doctor_name"] = doctor_name
|
||||||
|
|
||||||
|
keyboard = []
|
||||||
|
|
||||||
|
for continent in sorted(get_timezones().keys()):
|
||||||
|
keyboard.append([InlineKeyboardButton(continent)])
|
||||||
|
|
||||||
|
reply_markup = ReplyKeyboardMarkup(keyboard, one_time_keyboard=True)
|
||||||
|
|
||||||
|
await update.message.reply_text(
|
||||||
|
SELECT_YOUR_TIMEZONE_TEXT,
|
||||||
|
parse_mode="Markdown",
|
||||||
|
reply_markup=reply_markup,
|
||||||
|
)
|
||||||
|
return ASK_CONTINENT
|
||||||
|
|
||||||
|
|
||||||
|
async def receive_continent(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
||||||
|
keyboard = []
|
||||||
|
|
||||||
|
context.user_data["selected_continent"] = selected_continent = update.message.text
|
||||||
|
|
||||||
|
for continent in sorted(get_timezones()[selected_continent]):
|
||||||
|
keyboard.append([InlineKeyboardButton(continent)])
|
||||||
|
reply_markup = ReplyKeyboardMarkup(keyboard, one_time_keyboard=True)
|
||||||
|
|
||||||
|
await update.message.reply_text(
|
||||||
|
SELECT_YOUR_TIMEZONE_TEXT,
|
||||||
|
parse_mode="Markdown",
|
||||||
|
reply_markup=reply_markup,
|
||||||
|
)
|
||||||
|
return ASK_TIMEZONE
|
||||||
|
|
||||||
|
|
||||||
|
async def receive_time_zone(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
||||||
|
context.user_data["time_zone"] = context.user_data["selected_continent"] + "/" + update.message.text
|
||||||
|
|
||||||
|
logger.info(f"User {context.user_data['doctor_telegram_id']} selected timezone {context.user_data['time_zone']}")
|
||||||
|
|
||||||
await update.message.reply_text(
|
await update.message.reply_text(
|
||||||
SEND_ME_YOUR_SPECIALITY_TEXT,
|
SEND_ME_YOUR_SPECIALITY_TEXT,
|
||||||
parse_mode="Markdown"
|
parse_mode="Markdown"
|
||||||
@ -168,11 +211,15 @@ async def receive_doctor_consultation_packages_acknowledgement_status(update: Up
|
|||||||
reply_markup=ReplyKeyboardRemove()
|
reply_markup=ReplyKeyboardRemove()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
doc_code = UUID_code_generator(code_length=5)
|
||||||
|
|
||||||
await create_doctor(
|
await create_doctor(
|
||||||
context.user_data["ref_obj"],
|
context.user_data["ref_obj"],
|
||||||
context.user_data["doctor_telegram_id"],
|
context.user_data["doctor_telegram_id"],
|
||||||
context.user_data["doctor_name"],
|
context.user_data["doctor_name"],
|
||||||
context.user_data["verification_request_code"]
|
context.user_data["verification_request_code"],
|
||||||
|
code=doc_code,
|
||||||
|
time_zone=context.user_data["time_zone"]
|
||||||
)
|
)
|
||||||
return ConversationHandler.END
|
return ConversationHandler.END
|
||||||
|
|
||||||
@ -198,6 +245,14 @@ def get_register_doctor_first_stage_handler() -> ConversationHandler:
|
|||||||
MessageHandler(filters.TEXT & ~filters.COMMAND,
|
MessageHandler(filters.TEXT & ~filters.COMMAND,
|
||||||
receive_doctor_name)
|
receive_doctor_name)
|
||||||
],
|
],
|
||||||
|
ASK_TIMEZONE: [
|
||||||
|
MessageHandler(filters.TEXT & ~filters.COMMAND,
|
||||||
|
receive_time_zone)
|
||||||
|
],
|
||||||
|
ASK_CONTINENT: [
|
||||||
|
MessageHandler(filters.TEXT & ~filters.COMMAND,
|
||||||
|
receive_continent)
|
||||||
|
],
|
||||||
ASK_SPECIALITY: [
|
ASK_SPECIALITY: [
|
||||||
MessageHandler(filters.TEXT & ~filters.COMMAND,
|
MessageHandler(filters.TEXT & ~filters.COMMAND,
|
||||||
receive_doctor_speciality)
|
receive_doctor_speciality)
|
||||||
|
|||||||
@ -17,6 +17,7 @@ from docbot.services.patients_service import (
|
|||||||
create_patient, update_patient_phone, get_patient_by_telegram_id,
|
create_patient, update_patient_phone, get_patient_by_telegram_id,
|
||||||
is_user_has_phone
|
is_user_has_phone
|
||||||
)
|
)
|
||||||
|
from docbot.services.doctors_service import get_doctors_payment_link
|
||||||
from docbot.services.session_service import create_session
|
from docbot.services.session_service import create_session
|
||||||
from core.logging import logger
|
from core.logging import logger
|
||||||
|
|
||||||
@ -283,7 +284,8 @@ async def pay_consultation(update: Update, context: ContextTypes.DEFAULT_TYPE) -
|
|||||||
patient=patient
|
patient=patient
|
||||||
)
|
)
|
||||||
|
|
||||||
link = f"https://example.com/consultation/{user_id}"
|
link = await get_doctors_payment_link(context.user_data['doctor_number'])
|
||||||
|
|
||||||
await update.callback_query.answer()
|
await update.callback_query.answer()
|
||||||
await update.callback_query.message.reply_text(
|
await update.callback_query.message.reply_text(
|
||||||
f"Чтобы оплатить консультацию перейдите по ссылке {link}.",
|
f"Чтобы оплатить консультацию перейдите по ссылке {link}.",
|
||||||
|
|||||||
@ -24,6 +24,7 @@ async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> No
|
|||||||
"/start ‒ Запустить бота\n"
|
"/start ‒ Запустить бота\n"
|
||||||
"/genref ‒ Сгенерировать новый реферальный код для врача\n"
|
"/genref ‒ Сгенерировать новый реферальный код для врача\n"
|
||||||
"/doctors ‒ Посмотреть список зарегистрированных врачей\n"
|
"/doctors ‒ Посмотреть список зарегистрированных врачей\n"
|
||||||
|
"/verify ‒ Верифицировать врача по реферальному коду\n"
|
||||||
"/help ‒ Показать это меню\n"
|
"/help ‒ Показать это меню\n"
|
||||||
)
|
)
|
||||||
# (При необходимости в будущем можно добавить другие admin-команды)
|
# (При необходимости в будущем можно добавить другие admin-команды)
|
||||||
|
|||||||
@ -24,10 +24,28 @@ async def get_doctor(telegram_id: int) -> Doctors | None:
|
|||||||
async def get_doctors_names() -> Doctors | None:
|
async def get_doctors_names() -> Doctors | None:
|
||||||
async with AsyncSessionLocal() as session:
|
async with AsyncSessionLocal() as session:
|
||||||
result = await session.execute(
|
result = await session.execute(
|
||||||
select(Doctors.name)
|
select(Doctors, VerificationRequests)
|
||||||
|
.join(VerificationRequests, Doctors.id == VerificationRequests.doctor_id)
|
||||||
.where(Doctors.is_active)
|
.where(Doctors.is_active)
|
||||||
)
|
)
|
||||||
return result.all()
|
return result.fetchall()
|
||||||
|
|
||||||
|
|
||||||
|
async def get_doctors_payment_link(doctor_code: str) -> str | None:
|
||||||
|
async with AsyncSessionLocal() as session:
|
||||||
|
result = await session.execute(
|
||||||
|
select(PaymentMethod.method)
|
||||||
|
.join(Doctors, PaymentMethod.doctor_id == Doctors.id)
|
||||||
|
.where(
|
||||||
|
Doctors.code == doctor_code,
|
||||||
|
PaymentMethod.is_active.is_(True),
|
||||||
|
PaymentMethod.is_primary.is_(True)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
payment_link = result.scalar_one_or_none()
|
||||||
|
if payment_link:
|
||||||
|
return payment_link
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
async def is_there_primary_payment_method() -> PaymentMethod | None:
|
async def is_there_primary_payment_method() -> PaymentMethod | None:
|
||||||
@ -67,7 +85,7 @@ async def add_doctor(telegram_id: int, name: str, available_formats: Consultatio
|
|||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
async def create_doctor(referral_obj: ReferralCode, telegram_id: int, name: str, verification_code: str) -> Doctors:
|
async def create_doctor(referral_obj: ReferralCode, telegram_id: int, name: str, verification_code: str, code: str, time_zone: str) -> Doctors:
|
||||||
"""
|
"""
|
||||||
Помечает referral_obj как использованный, создаёт запись в таблице Doctors
|
Помечает referral_obj как использованный, создаёт запись в таблице Doctors
|
||||||
с привязкой к telegram_id и возвращает объект Doctor.
|
с привязкой к telegram_id и возвращает объект Doctor.
|
||||||
@ -84,7 +102,9 @@ async def create_doctor(referral_obj: ReferralCode, telegram_id: int, name: str,
|
|||||||
name=name,
|
name=name,
|
||||||
is_active=False,
|
is_active=False,
|
||||||
created_at=datetime.utcnow(),
|
created_at=datetime.utcnow(),
|
||||||
referral=referral_obj
|
referral=referral_obj,
|
||||||
|
code=code,
|
||||||
|
time_zone=time_zone
|
||||||
)
|
)
|
||||||
|
|
||||||
verification_request = VerificationRequests()
|
verification_request = VerificationRequests()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user