diff --git a/.gitignore b/.gitignore index 32c3d58..2995de2 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ src/docbot/conversations.pkl conversations.pkl *.jpg *.png -*.jpeg \ No newline at end of file +*.jpeg +.vscode/ \ No newline at end of file diff --git a/src/core/utils.py b/src/core/utils.py index 0dc6bb1..ec861a0 100644 --- a/src/core/utils.py +++ b/src/core/utils.py @@ -1,6 +1,7 @@ import uuid import hashlib import base64 +import re from datetime import datetime @@ -29,3 +30,10 @@ def date_time_formatter(date_time: str) -> datetime: """ dt = datetime.strptime(date_time, '%d.%m.%y %H:%M') return dt + + +def is_phone_correct(phone: str) -> bool: + normalized = re.sub(r"[()\s-]", "", phone) + regex = r"^(?:\+7|8|7)\d{10}$" + + return re.match(regex, normalized) diff --git a/src/docbot/handlers/admins/generate_ref.py b/src/docbot/handlers/admins/generate_ref.py index 4826a2f..ed1a552 100644 --- a/src/docbot/handlers/admins/generate_ref.py +++ b/src/docbot/handlers/admins/generate_ref.py @@ -31,4 +31,4 @@ def get_referral_handlers(): """ Возвращает список готовых CommandHandler-ов для регистрации в Application. """ - return CommandHandler("genref", genref) \ No newline at end of file + return CommandHandler("genref", genref) diff --git a/src/docbot/handlers/admins/verify_handler.py b/src/docbot/handlers/admins/verify_handler.py index 56ba689..49c90e5 100644 --- a/src/docbot/handlers/admins/verify_handler.py +++ b/src/docbot/handlers/admins/verify_handler.py @@ -108,7 +108,7 @@ async def doctor_action(update: Update, context: ContextTypes.DEFAULT_TYPE): if action == "approve": # Здесь твоя логика верификации врача (например, запись в базу) - approve_doctor(doctor_telegram_id) + await approve_doctor(doctor_telegram_id) logger.info("Врач с ID %s верифицирован.", doctor_telegram_id) # Отправляем сообщение об успешной верификации await query.edit_message_text( diff --git a/src/docbot/handlers/patients/consultation_handler.py b/src/docbot/handlers/patients/consultation_handler.py index 2956496..9ddf54e 100644 --- a/src/docbot/handlers/patients/consultation_handler.py +++ b/src/docbot/handlers/patients/consultation_handler.py @@ -1,6 +1,5 @@ from telegram import ( - Update, ReplyKeyboardRemove, - InlineKeyboardButton, InlineKeyboardMarkup + Update, InlineKeyboardButton, InlineKeyboardMarkup ) from telegram.ext import ( ContextTypes, @@ -13,6 +12,7 @@ from telegram.ext import ( from docbot.handlers.utils.cancel_handler import get_cancel_handler from docbot.handlers.start_handler import get_start_handler from core.enums.dialog_helpers import ConfirmationMessage +from core.utils import is_phone_correct from docbot.services.patients_service import ( create_patient, update_patient_phone, get_patient_by_telegram_id, is_user_has_phone @@ -28,6 +28,7 @@ ENTER_PATIENT_PHONE = 4 ENTER_DOCTOR_NUMBER = 5 ENTER_CONSULTATION_DATE = 6 PAY_CONSULTATION = 7 +ERROR_PHONE_NUMBER = 8 STOPPING = 99 @@ -109,10 +110,10 @@ async def receive_patient_aceptance(update: Update, context: ContextTypes.DEFAUL else: user_data['accepted'] = False await update.callback_query.edit_message_text( - text="❌ Вы отказались от обработки персональных данных. Запись на консультацию невозможна.", + text="❌ Вы отказались от обработки персональных данных. Запись на консультацию невозможна. Запустите команду /consultation, чтобы начать заново", parse_mode="Markdown" ) - return STOPPING + return ConversationHandler.END async def choose_consultation_type(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: @@ -155,8 +156,9 @@ async def enter_patient_phone(update: Update, context: ContextTypes.DEFAULT_TYPE if not has_phone: logger.info(f"Ask user {user_id} enter a phone number.") - await update.callback_query.edit_message_text( - text="Пожалуйста, введите ваш номер телефона для записи на консультацию:" + await update.callback_query.message.reply_text( + text="Пожалуйста, введите ваш номер мобильного телефона для записи на консультацию:\n" + "Без знака +, вида 79991112233" ) return ENTER_PATIENT_PHONE else: @@ -176,13 +178,30 @@ async def receive_patient_phone(update: Update, context: ContextTypes.DEFAULT_TY # Например, вызов сервиса для обновления информации о пациенте # await update_patient_phone(telegram_id=user_id, phone=phone) + logger.info((f"Checking user's phone {is_phone_correct(phone=phone)}")) + if not is_phone_correct(phone=phone): + keyboard = [ + [ + InlineKeyboardButton( + "Изменить", + callback_data="back" + ), + ] + ] + await update.message.reply_text( + text=f"Вы ввели неверный номер телефона: {phone}\n", + parse_mode="Markdown", + reply_markup=InlineKeyboardMarkup(keyboard) + ) + return ERROR_PHONE_NUMBER + logger.info((f"receive_patient_phone User {user_id} provided phone: {phone}")) context.user_data['phone'] = phone keyboard = [ [ InlineKeyboardButton( - "Назад", + "Изменить", callback_data="back" ), ] @@ -190,7 +209,7 @@ async def receive_patient_phone(update: Update, context: ContextTypes.DEFAULT_TY await update.message.reply_text( text=f"Ваш номер телефона: {phone}\n" - "Если хотите изменить номер телефона, то нажмите кнопку Назад\n" + "Если хотите изменить номер телефона, то нажмите кнопку Изменить\n" "Если всё ок, то введите номер врача.", parse_mode="Markdown", reply_markup=InlineKeyboardMarkup(keyboard) @@ -201,12 +220,13 @@ async def receive_patient_phone(update: Update, context: ContextTypes.DEFAULT_TY async def receive_doctor_number(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: user_id = context.user_data['telegram_id'] if not context.user_data.get('doctor_number'): - patient_phone = context.user_data['phone'] doctor_number = update.message.text.strip() context.user_data['doctor_number'] = doctor_number - await update_patient_phone(telegram_id=user_id, phone=patient_phone) - logger.info((f"Saved patient's phone number {patient_phone}")) + if not await is_user_has_phone(user_id): + patient_phone = context.user_data['phone'] + await update_patient_phone(telegram_id=user_id, phone=patient_phone) + logger.info((f"Saved patient's phone number {patient_phone}")) await update.message.reply_text( text=f"Вы ввели серийный номер врача: {doctor_number}\n" @@ -215,8 +235,7 @@ async def receive_doctor_number(update: Update, context: ContextTypes.DEFAULT_TY ) else: logger.info(f"User {user_id} requested correction of their consultation date") - await update.callback_query.answer() - await update.callback_query.edit_message_text( + await update.effective_message.reply_text( text="Введите дату и время консультации в формате ДД.ММ.ГГ ЧЧ:ММ, например, 01.01.23 12:00.", parse_mode="Markdown" ) @@ -234,7 +253,7 @@ async def receive_consultation_date(update: Update, context: ContextTypes.DEFAUL keyboard = [ [ InlineKeyboardButton( - "Назад", + "Изменить", callback_data="back" ), InlineKeyboardButton( @@ -246,7 +265,7 @@ async def receive_consultation_date(update: Update, context: ContextTypes.DEFAUL await update.message.reply_text( text=f"Вы ввели следующую дату консультации: {consultation_date_time}\n" - "Если хотите изменить дату консультации, то нажмите кнопку Назад\n" + "Если хотите изменить дату консультации, то нажмите кнопку Изменить\n" "Если всё ок, то нажмите Продолжить.", parse_mode="Markdown", reply_markup=InlineKeyboardMarkup(keyboard) @@ -257,13 +276,12 @@ async def receive_consultation_date(update: Update, context: ContextTypes.DEFAUL async def pay_consultation(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: user_id = context.user_data['telegram_id'] - phone = context.user_data['phone'] consultation_date_time = context.user_data['consultation_date_time'] patient = await get_patient_by_telegram_id(user_id) await create_session( telegram_id=user_id, - phone=phone, + phone=patient.phone, consultation_date_time=consultation_date_time, patient=patient ) @@ -275,6 +293,8 @@ async def pay_consultation(update: Update, context: ContextTypes.DEFAULT_TYPE) - parse_mode="Markdown" ) + context.user_data.clear() + return ConversationHandler.END @@ -290,16 +310,17 @@ def get_consultation_handler() -> ConversationHandler: SEND_ACKNOWLEDGEMENT_INFO: [CallbackQueryHandler(receive_patient_aceptance)], PROCEED_WITH_CONSULTATION: [CallbackQueryHandler(choose_consultation_type)], SELECT_CONSULTATION_TYPE: [CallbackQueryHandler(enter_patient_phone)], - ENTER_PATIENT_PHONE: [MessageHandler(filters=None, callback=receive_patient_phone)], + ENTER_PATIENT_PHONE: [MessageHandler(filters=filters.TEXT & ~filters.COMMAND, callback=receive_patient_phone)], ENTER_DOCTOR_NUMBER: [ MessageHandler(filters.TEXT & ~filters.COMMAND, receive_doctor_number), CallbackQueryHandler(enter_patient_phone, pattern="^" + "back" + "$") ], - ENTER_CONSULTATION_DATE: [MessageHandler(filters=None, callback=receive_consultation_date)], + ENTER_CONSULTATION_DATE: [MessageHandler(filters=filters.TEXT & ~filters.COMMAND, callback=receive_consultation_date)], PAY_CONSULTATION: [ CallbackQueryHandler(pay_consultation, pattern="^" + "proceed" + "$"), CallbackQueryHandler(receive_doctor_number, pattern="^" + "back" + "$") ], + ERROR_PHONE_NUMBER: [CallbackQueryHandler(enter_patient_phone, pattern="^" + "back" + "$")], STOPPING: [get_start_handler()], }, fallbacks=[get_cancel_handler()], diff --git a/src/docbot/services/patients_service.py b/src/docbot/services/patients_service.py index 50794b9..62861a7 100644 --- a/src/docbot/services/patients_service.py +++ b/src/docbot/services/patients_service.py @@ -3,6 +3,7 @@ from datetime import datetime from sqlalchemy import select from db.session import AsyncSessionLocal from db.models import Patients +from core.logging import logger async def update_patient_phone(telegram_id: int, phone: str) -> bool: diff --git a/src/docbot/services/session_service.py b/src/docbot/services/session_service.py index cbbda6a..5ec0d6b 100644 --- a/src/docbot/services/session_service.py +++ b/src/docbot/services/session_service.py @@ -1,15 +1,13 @@ from __future__ import annotations -import uuid from datetime import datetime from sqlalchemy import select from db.session import AsyncSessionLocal from db.models import Sessions, Patients, SessionStatusHistory, SessionDateTimeHistory -from core.utils import ( - UUID_code_generator, generate_session_code, date_time_formatter -) +from core.utils import (generate_session_code, date_time_formatter) +from core.logging import logger async def create_session(telegram_id: int, phone: str, consultation_date_time: str, patient: Patients) -> str: @@ -18,6 +16,7 @@ async def create_session(telegram_id: int, phone: str, consultation_date_time: s Возвращает этот код. """ code = generate_session_code(telegram_id=telegram_id, phone=phone, consultation_date_time=consultation_date_time) + logger.info(f"Uniq session code generated: {code}") async with AsyncSessionLocal() as session: async with session.begin(): sessions = Sessions(