810 lines
42 KiB
Python
810 lines
42 KiB
Python
import requests
|
||
import aiohttp
|
||
from aiogram import Bot, Dispatcher, types
|
||
from aiogram.contrib.fsm_storage.memory import MemoryStorage
|
||
from aiogram.dispatcher.filters.state import State, StatesGroup
|
||
from aiogram.utils import executor
|
||
import re
|
||
from aiogram.types import ReplyKeyboardMarkup, KeyboardButton
|
||
import asyncio
|
||
from aiogram.dispatcher import FSMContext
|
||
from aiogram import types
|
||
from aiogram.dispatcher.filters import Command
|
||
from datetime import datetime, timedelta
|
||
import gspread
|
||
from oauth2client.service_account import ServiceAccountCredentials
|
||
import re
|
||
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton, WebAppInfo
|
||
import logging
|
||
from aiogram.types import ReplyKeyboardRemove
|
||
from aiogram.utils.callback_data import CallbackData
|
||
|
||
|
||
TOKEN = '7907319434:AAEEM55xbWHhp5uPAlJ5AS2vNoleES_z_Kk'
|
||
bot = Bot(token=TOKEN)
|
||
storage = MemoryStorage()
|
||
dp = Dispatcher(bot, storage=storage)
|
||
|
||
# Кнопка для перезапуска
|
||
restart_button = ReplyKeyboardMarkup(resize_keyboard=True)
|
||
restart_button.add(KeyboardButton("Перезапустить бота"))
|
||
|
||
MAX_ATTEMPTS = 3 # Максимальное количество попыток ввода кода
|
||
TIMEOUT = 30 # Время в секундах
|
||
|
||
# Словарь для хранения данных о пользователях
|
||
user_data = {}
|
||
last_bot_message_id = {}
|
||
|
||
|
||
# Авторизация и доступ к таблице
|
||
scope = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/drive"]
|
||
credentials = ServiceAccountCredentials.from_json_keyfile_name("botforclinic-436512-0c117dd103a8.json", scope)
|
||
client = gspread.authorize(credentials)
|
||
sheet = client.open("Пациенты клиники").sheet1 # Открытие таблицы, используйте название вашей таблицы
|
||
|
||
|
||
# Словарь для хранения данных о сообщениях пользователей
|
||
user_messages = {}
|
||
|
||
# История состояний для каждого пользователя
|
||
user_states = {}
|
||
|
||
|
||
|
||
|
||
class Form(StatesGroup):
|
||
telegram_id = State()
|
||
existing_patient = State()
|
||
phone_number = State()
|
||
fio = State()
|
||
birthday = State()
|
||
verification_code = State()
|
||
confirm_fio = State()
|
||
confirm_phone_number = State()
|
||
|
||
|
||
|
||
# Создаем состояния
|
||
class QuestionForm(StatesGroup):
|
||
waiting_for_question = State()
|
||
|
||
|
||
from aiogram import types
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
# Настройка логирования
|
||
logging.basicConfig(level=logging.INFO)
|
||
|
||
# Главное меню
|
||
main_menu = InlineKeyboardMarkup(row_width=2).add(
|
||
InlineKeyboardButton("🌍 Контакты", callback_data="menu_contacts"),
|
||
InlineKeyboardButton("📞 Связь", callback_data="menu_contact"),
|
||
InlineKeyboardButton("✅ Добавить пациента", callback_data="menu_registration"),
|
||
InlineKeyboardButton("🏥 О Клинике", callback_data="o_klinike"),
|
||
InlineKeyboardButton("📑 Заказать справку для налоговой", callback_data="fns_spravka")
|
||
)
|
||
|
||
# Подменю "контакты"
|
||
contacts_menu = InlineKeyboardMarkup(row_width=1).add(
|
||
InlineKeyboardButton("▶️ Назад", callback_data="main_menu")
|
||
)
|
||
|
||
# Подменю "О Клинике"
|
||
Klinik_o = InlineKeyboardMarkup(row_width=1).add(
|
||
InlineKeyboardButton("▶️ Назад", callback_data="main_menu")
|
||
)
|
||
|
||
|
||
# Меню связь
|
||
contact_menu = InlineKeyboardMarkup(row_width=1).add(
|
||
InlineKeyboardButton("💬 Отправить сообщение администратору Клиники", callback_data="contact_administrator"),
|
||
InlineKeyboardButton("🛎 Заказать звонок от администратора Клиники", callback_data="order_call"),
|
||
InlineKeyboardButton("▶️ Назад", callback_data="main_menu")
|
||
)
|
||
|
||
|
||
# # Меню Добавить пациента
|
||
# registration_menu = InlineKeyboardMarkup(row_width=1).add(
|
||
# InlineKeyboardButton(text="Заполнить форму",web_app=WebAppInfo(url=form_url), callback_data="form_regist"),
|
||
# InlineKeyboardButton("▶️ Назад", callback_data="main_menu")
|
||
# )
|
||
|
||
|
||
administrator_contact = InlineKeyboardMarkup(row_width=1).add(
|
||
InlineKeyboardButton("✍🏼 Написать сообщение", callback_data="message_admin"),
|
||
InlineKeyboardButton("▶️ Назад", callback_data="menu_contact"),
|
||
InlineKeyboardButton("🔘 Главное меню", callback_data="main_menu")
|
||
)
|
||
|
||
message_ad = InlineKeyboardMarkup(row_width=1).add(
|
||
InlineKeyboardButton("▶️ Назад", callback_data="contact_administrator"),
|
||
InlineKeyboardButton("🔘 Главное меню", callback_data="main_menu")
|
||
)
|
||
|
||
|
||
call_order = InlineKeyboardMarkup(row_width=1).add(
|
||
InlineKeyboardButton("📞 Позвонить мне", callback_data="call_me"),
|
||
InlineKeyboardButton("▶️ Назад", callback_data="menu_contact"),
|
||
InlineKeyboardButton("🔘 Главное меню", callback_data="main_menu")
|
||
)
|
||
|
||
return_call_me = InlineKeyboardMarkup(row_width=1).add(
|
||
InlineKeyboardButton("▶️ Назад", callback_data="order_call"),
|
||
InlineKeyboardButton("🔘 Главное меню", callback_data="main_menu")
|
||
)
|
||
|
||
whatsapp = InlineKeyboardMarkup(row_width=1).add(
|
||
InlineKeyboardButton("🔘 Главное меню", callback_data="main_menu")
|
||
)
|
||
|
||
|
||
# Обработчик команды /menu
|
||
@dp.message_handler(Command("menu"))
|
||
async def show_menu(message: types.Message):
|
||
await message.answer("В настоящее время я, как Ваш виртуальный помощник, активно развиваюсь."
|
||
" В ближайшее время у меня появятся новые функции и возможности."
|
||
" А пока Вы можете ознакомиться с текущим меню.", reply_markup=main_menu)
|
||
|
||
# Обработка нажатий на инлайн-кнопки
|
||
@dp.callback_query_handler(lambda c: c.data.startswith("menu_") or c.data == "main_menu")
|
||
async def handle_main_menu(call: types.CallbackQuery):
|
||
user_id = call.from_user.id
|
||
|
||
# Генерируем ссылку с user_id
|
||
form_url = f"https://tgbotpolimed.pirogov.ai/?user_id={user_id}"
|
||
if call.data == "main_menu":
|
||
await call.message.edit_text("В настоящее время я, как Ваш виртуальный помощник, активно развиваюсь."
|
||
" В ближайшее время у меня появятся новые функции и возможности."
|
||
" А пока Вы можете ознакомиться с текущим меню.", reply_markup=main_menu)
|
||
elif call.data == "menu_contacts":
|
||
await call.message.edit_text("<b>Клиники им. проф. Е.Н.Оленевой</b>\n\n"
|
||
"Клиника <b>УХО•ГОРЛО•НОС</b>\n"
|
||
"Записаться на приём, задать вопрос:\n"
|
||
"📞 +7 (342) 207-03-03\n\n"
|
||
"Больше информации о клинике и врачах на нашем <a href='https://perm.oclinica.ru/lor'>🔗САЙТЕ</a>\n"
|
||
"📍г. Пермь, ул. К. Цеткин, 9\n"
|
||
"(ост. Строительный факультет)\n"
|
||
"<a href='https://tinyurl.com/286a8tv7'>Построить маршрут</a>\n\n"
|
||
"--------------\n\n"
|
||
"Клиника лечения <b>КАШЛЯ•АЛЛЕРГИИ</b>\n"
|
||
"Записаться на приём, задать вопрос:\n"
|
||
"📞 +7 (342) 200-02-03\n\n"
|
||
"Больше информации о клинике и врачах на нашем <a href='https://perm.oclinica.ru/allergo'>🔗САЙТЕ</a>\n\n"
|
||
"📍г. Пермь, ул. Пермь, ул. Г. Звезда, 31А\n"
|
||
"(ост. Г. Звезда)\n"
|
||
"<a href='https://tinyurl.com/9a9w5pdu'>Построить маршрут</a>\n\n"
|
||
"--------------\n\n"
|
||
"Центр <b>ДИАГНОСТИКИ И РЕАБИЛИТАЦИИ</b> \n"
|
||
"📞 +7 (342) 287-16-94\n\n"
|
||
"Больше информации о клинике и врачах на нашем <a href='https://cdr.oclinica.ru/'>🔗САЙТЕ</a>\n\n"
|
||
"📍 г. Пермь, ул. Пермь, ул. Г. Звезда, 31А\n"
|
||
" (ост. Г. Звезда)\n"
|
||
"<a href='https://tinyurl.com/9a9w5pdu'>Построить маршрут</a>\n\n"
|
||
"Присоединяйтесь к нашему каналу новостей в <a href='https://t.me/permlor'>Telegram</a>.", reply_markup=contacts_menu, parse_mode="HTML")
|
||
elif call.data == "menu_contact":
|
||
await call.message.edit_text("Выберите способ связи", reply_markup=contact_menu)
|
||
elif call.data == "menu_registration":
|
||
await call.message.edit_text("Обращаем Ваше внимание, что добавить можно только тех пациентов, которые ранее уже посещали нашу клинику.\n"
|
||
'Для ввода данных, пожалуйста, заполните форму, нажав на кнопку ниже: "Заполнить форму"\n'
|
||
'После заполнения формы вернитесь к боту и нажмите на кнопку ниже: "Проверить данные"', reply_markup=InlineKeyboardMarkup(row_width=1).add(InlineKeyboardButton(text="Заполнить форму", web_app=WebAppInfo(url=form_url)),
|
||
InlineKeyboardButton(text="Проверить данные",callback_data="check_verification"),
|
||
InlineKeyboardButton("▶️ Назад", callback_data="main_menu")))
|
||
|
||
|
||
|
||
|
||
|
||
@dp.callback_query_handler(lambda c: c.data == "fns_spravka")
|
||
async def show_patient_list(call: types.CallbackQuery):
|
||
user_id = call.from_user.id
|
||
form_url = f"https://tgbotpolimed.pirogov.ai/?user_id={user_id}"
|
||
form_url_fns = f"https://tgbotpolimed.pirogov.ai/fns?user_id={user_id}"
|
||
telegram_id = call.from_user.id
|
||
patients = find_patients_by_id(telegram_id)
|
||
|
||
if not patients:
|
||
await call.message.edit_text("Пациенты с вашим Telegram ID не найдены.")
|
||
return
|
||
|
||
patient_list = "\n".join(
|
||
[f"{i + 1}. {patient['ФИО']}" for i, patient in enumerate(patients)]
|
||
)
|
||
|
||
await call.message.edit_text(f'Если пациент присутствует в списке, то для оформления налогового вычета за медицинские услуги, предоставленные в Клинике, пожалуйста, заполните форму ниже, нажав на кнопку "Заказать справку".\n\n'
|
||
f'☝🏼Если пациента нет в списке зарегистрированных, пожалуйста, добавьте его через Telegram, нажав на кнопку ниже "Добавить пациента".\n\n'
|
||
f"<b>Список зарегистрированных пациентов:</b>\n\n{patient_list}\n\n",
|
||
reply_markup=InlineKeyboardMarkup(row_width=1).add(InlineKeyboardButton(text="Заказать справку", web_app=WebAppInfo(url=form_url_fns)),
|
||
InlineKeyboardButton(text="Добавить пациента", web_app=WebAppInfo(url=form_url)),
|
||
InlineKeyboardButton("▶️ Назад", callback_data="main_menu")),parse_mode="HTML")
|
||
|
||
|
||
|
||
|
||
# Обработка нажатия на "Запись на исследование"
|
||
@dp.callback_query_handler(lambda c: c.data == "form_regist")
|
||
async def handle_call_menu(call: types.CallbackQuery):
|
||
await call.message.edit_text("После того как Вы заполните форму, нажмите на кнопку ниже для проверки данных.\n"
|
||
"Если Вы хотите начать общение с ботом заново, нажмите /start.", reply_markup=InlineKeyboardMarkup().add(InlineKeyboardButton(
|
||
text="Проверить данные",
|
||
callback_data="check_verification"
|
||
)
|
||
)
|
||
)
|
||
|
||
|
||
|
||
# Обработка нажатия на "Запись на исследование"
|
||
@dp.callback_query_handler(lambda c: c.data == "o_klinike")
|
||
async def klinik_inf(call: types.CallbackQuery):
|
||
await call.message.edit_text("<b>Добро пожаловать в специализированную ЛОР-клинику им. проф.Е.Н. Оленевой!</b> 🎉🤗\n\n"
|
||
"С 2007 года мы заботимся о здоровье наших пациентов, предоставляя высококачественные медицинские услуги.\n\n"
|
||
"✨ <b>Наши преимущества</b>\n"
|
||
"🔹Команда из 47 профессиональных специалистов, включая 5 кандидатов медицинских наук и 1 доктора медицинских наук\n"
|
||
"🔹Комплексный подход к лечению с учетом индивидуальных особенностей каждого пациента\n"
|
||
"🔹Высокое качество первичной диагностики\n"
|
||
"🔹Оснащение клиники современным оборудованием экспертного класса\n"
|
||
"🔹Прием пациентов всех возрастных категорий\n\n"
|
||
"💼<b>Наши услуги</b>\n"
|
||
"🔹<u>Прием специалистов:</u> ЛОР-врачи, сурдологи, отоневрологи (вестибулологи), фониатр, пульмонологи, аллергологи-иммунологи\n"
|
||
"🔹<u>Диагностика:</u> эндоскопическая диагностика, аудиометрия, тимпанометрия, ОАЭ, УЗИ, ЭКГ, КТ, КСП\n"
|
||
"🔹<u>Терапия:</u> ФДТ, АСИТ-терапия, галотерапия\n"
|
||
"🔹<u>Хирургия:</u> малоинвазивные ЛОР-операции\n"
|
||
"🔹<u>Слухопротезирование:</u> диагностика слуха, подбор слуховых аппаратов\n\n"
|
||
"🏢 <b>Наши клиники</b>\n"
|
||
"🔹Клиника ухо,горло, нос им. проф. Е.Н. Оленевой\n"
|
||
"🔹Клиника лечения кашля и аллергии им. проф. Е.Н. Оленевой\n"
|
||
"🔹Центр диагностики и реабилитации им. проф. Е.Н. Оленевой\n\n"
|
||
"<b>Работаем 7 дней в неделю для вашего удобства!</b>\n\n"
|
||
"🕙 <b>Часы работы</b>\n"
|
||
"Пн-пт: 9:00 – 21:00\n"
|
||
"Сб-вс: 9:00 – 19:00\n"
|
||
"❗️Каждый 4-ый четверг месяца клиника работает до 17:00\n\n"
|
||
"📍 <b>Наши адреса</b>\n"
|
||
"г. Пермь, ул. Клары Цеткин, 9\n"
|
||
"г. Пермь, ул. Газеты Звезда, 31А\n\n"
|
||
"📧clinic-lor@mail.ru\n\n\n"
|
||
"<b>Будьте здоровы вместе с нами</b>❣️", reply_markup=Klinik_o, parse_mode='HTML')
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
# Обработка нажатия на "Запись на исследование"
|
||
@dp.callback_query_handler(lambda c: c.data == "contact_administrator")
|
||
async def handle_call_menu(call: types.CallbackQuery):
|
||
await call.message.edit_text('💬 Для отправки сообщения администратору Клиники нажмите кнопку ниже "Написать сообщение".', reply_markup=administrator_contact)
|
||
|
||
|
||
|
||
|
||
# Обработка нажатия на "Запись на исследование"
|
||
@dp.callback_query_handler(lambda c: c.data == "order_call")
|
||
async def handle_admin_call_menu(call: types.CallbackQuery):
|
||
await call.message.edit_text('Для получения обратного звонка от администратора Клиники нажмите кнопку ниже "Позвонить мне".', reply_markup=call_order)
|
||
|
||
|
||
|
||
@dp.callback_query_handler(lambda c: c.data == "call_me")
|
||
async def handle_ad_call_menu(call: types.CallbackQuery):
|
||
try:
|
||
user_id = call.from_user.id # ID пользователя
|
||
records = sheet.get_all_records()
|
||
|
||
# Получаем данные пользователя из таблицы
|
||
user_data = next((entry for entry in records if str(entry['Telegram ID']) == str(user_id)), None)
|
||
if not user_data:
|
||
await call.message.answer("Ваши данные не найдены.", reply_markup=return_call_me)
|
||
return
|
||
|
||
phone_number = user_data['Номер телефона']
|
||
text = "Позвонить мне"
|
||
message_id = call.message.message_id
|
||
date = call.message.date.isoformat() # Конвертация даты
|
||
reply_to_message_id = call.message.reply_to_message.message_id if call.message.reply_to_message else None
|
||
|
||
# Передаём данные на сервер
|
||
await send_message_server(phone_number, text, message_id, user_id, date, reply_to_message_id)
|
||
|
||
await call.message.edit_text(
|
||
"Администратор Клиники свяжется с Вами в ближайшее время в рабочие часы и проконсультирует по всем вопросам.",
|
||
reply_markup=return_call_me
|
||
)
|
||
except Exception as e:
|
||
logging.error(f"Ошибка при обработке запроса: {e}")
|
||
await call.message.edit_text("Произошла ошибка. Попробуйте снова позже.", reply_markup=return_call_me)
|
||
|
||
|
||
# Обработчик кнопки "message_admin"
|
||
@dp.callback_query_handler(lambda c: c.data == "message_admin")
|
||
async def handle_ad_message(call: types.CallbackQuery, state: FSMContext):
|
||
user_id = str(call.from_user.id) # Преобразуем в строку для сравнения
|
||
|
||
try:
|
||
# Получение всех записей из таблицы
|
||
records = sheet.get_all_records()
|
||
|
||
# Поиск пользователя по Telegram ID
|
||
user_data = next((entry for entry in records if str(entry['Telegram ID']) == user_id), None)
|
||
|
||
if not user_data:
|
||
await call.message.answer("Ваши данные не найдены.", reply_markup=message_ad)
|
||
return
|
||
|
||
# Переход в состояние ожидания вопроса
|
||
prompt_message = await call.message.edit_text(
|
||
"Пожалуйста, отправьте Ваш вопрос администратору одним сообщением.",
|
||
reply_markup=message_ad
|
||
)
|
||
|
||
# Сохраняем ID сообщения
|
||
async with state.proxy() as data:
|
||
data["prompt_message_id"] = prompt_message.message_id
|
||
|
||
await QuestionForm.waiting_for_question.set() # Устанавливаем состояние ожидания=
|
||
|
||
except Exception as e:
|
||
logging.error(f"Ошибка при доступе к таблице: {e}")
|
||
await call.message.edit_text("Произошла ошибка. Попробуйте снова позже.", reply_markup=message_ad)
|
||
|
||
|
||
# Обработчик ввода вопроса
|
||
@dp.message_handler(state=QuestionForm.waiting_for_question, content_types=types.ContentTypes.TEXT)
|
||
async def handle_user_question(message: types.Message, state: FSMContext):
|
||
user_id = str(message.from_user.id) # ID пользователя
|
||
text = message.text # Сообщение пользователя
|
||
|
||
try:
|
||
# Удаление предыдущего сообщения
|
||
async with state.proxy() as data:
|
||
if "prompt_message_id" in data:
|
||
await bot.delete_message(chat_id=message.chat.id, message_id=data["prompt_message_id"])
|
||
|
||
# Отправка сообщения пользователя на сервер
|
||
await send_message_server2(user_id, text, message.message_id, user_id, message.date.isoformat(), None)
|
||
|
||
# Ответ пользователю
|
||
await message.answer(
|
||
"Ваше сообщение успешно отправлено! Администратор Клиники ответит Вам в ближайшее время в рабочие часы. Спасибо за Ваше обращение!",
|
||
reply_markup=message_ad
|
||
)
|
||
except Exception as e:
|
||
logging.error(f"Ошибка при обработке вопроса: {e}")
|
||
await message.answer(
|
||
"Произошла ошибка при отправке вопроса. Попробуйте позже.",
|
||
reply_markup=message_ad
|
||
)
|
||
|
||
# Завершаем состояние
|
||
await state.finish()
|
||
|
||
|
||
|
||
|
||
|
||
|
||
# Хранилище для уже обработанных пользователей
|
||
processed_users = set()
|
||
|
||
# Обработка нажатия на кнопку "Проверить данные"
|
||
@dp.callback_query_handler(lambda c: c.data == 'check_verification')
|
||
async def process_check_verification(callback_query: types.CallbackQuery, state: FSMContext):
|
||
user_id = callback_query.from_user.id
|
||
try:
|
||
# Чтение всех строк таблицы
|
||
records = sheet.get_all_records()
|
||
user_data_verified = False
|
||
|
||
for row in records:
|
||
fio = str(row.get("ФИО", "")).strip()
|
||
phone = str(row.get("Номер телефона", "")).strip()
|
||
telegram_id = str(row.get("Telegram ID", "")).strip()
|
||
|
||
# Проверяем, если в таблице есть данные для этого пользователя
|
||
if telegram_id == str(user_id):
|
||
user_data_verified = True
|
||
break
|
||
|
||
if user_data_verified:
|
||
await send_success_message(user_id) # Отправляем сообщение о успешной регистрации
|
||
else:
|
||
await bot.send_message(
|
||
user_id,
|
||
"Мы не нашли ваших данных в системе. Пожалуйста, проверьте, что вы правильно заполнили форму и попробуйте снова.",
|
||
reply_markup=InlineKeyboardMarkup().add(
|
||
InlineKeyboardButton("Попробовать снова", callback_data="check_verification")
|
||
)
|
||
)
|
||
except Exception as e:
|
||
print(f"Ошибка при проверке верификации: {e}")
|
||
await bot.send_message(user_id, "Произошла ошибка при проверке данных. Попробуйте позже.")
|
||
|
||
|
||
|
||
|
||
# Функция отправки сообщения об успешной регистрации
|
||
async def send_success_message(user_id):
|
||
try:
|
||
await bot.send_message(
|
||
chat_id=user_id,
|
||
text=("Ура! Ваша регистрация прошла успешно! 🥳\n\n"
|
||
"Теперь все уведомления о записи на приём будут приходить сюда, в чат-бот. "
|
||
"Если Вы также получаете рассылку в WhatsApp, то сообщения будут дублироваться. "
|
||
'Для получения рассылки только в чат-бот Telegram, нажмите кнопку ниже "Не дублировать сообщения в WhatsApp".'),
|
||
reply_markup=InlineKeyboardMarkup().add(
|
||
InlineKeyboardButton("Не дублировать сообщения в WhatsApp", callback_data="stop_replying"),
|
||
InlineKeyboardButton("🔘 Главное меню", callback_data="main_menu")
|
||
)
|
||
)
|
||
except Exception as e:
|
||
print(f"Ошибка при отправке сообщения пользователю {user_id}: {e}")
|
||
|
||
|
||
|
||
@dp.callback_query_handler(lambda c: c.data == "stop_replying")
|
||
async def stop_replying_handler(call: types.CallbackQuery):
|
||
user_id = str(call.from_user.id) # Преобразуем в строку для сравнения
|
||
|
||
try:
|
||
# Получение всех записей из таблицы
|
||
records = sheet.get_all_records()
|
||
|
||
# Поиск пользователя по Telegram ID
|
||
user_data = next((entry for entry in records if str(entry['Telegram ID']) == user_id), None)
|
||
|
||
if not user_data:
|
||
await call.message.answer("Ваши данные не найдены.", reply_markup=whatsapp)
|
||
return
|
||
|
||
phone_number = user_data['Номер телефона'] # Измените на название вашего столбца
|
||
text = "Отключить дублирование в WhatsApp"
|
||
message_id = call.message.message_id
|
||
date = call.message.date.isoformat()
|
||
reply_to_message_id = call.message.reply_to_message.message_id if call.message.reply_to_message else None
|
||
|
||
# Отправка данных на сервер
|
||
await send_message_server(phone_number, text, message_id, call.from_user.id, date, reply_to_message_id)
|
||
|
||
# Ответ пользователю
|
||
await call.message.edit_text("Рассылка уведомлений в WhatsApp отключена.", reply_markup=whatsapp)
|
||
|
||
except Exception as e:
|
||
logging.error(f"Ошибка при доступе к таблице: {e}")
|
||
await call.message.edit_text("Произошла ошибка. Попробуйте снова позже.", reply_markup=whatsapp)
|
||
|
||
|
||
|
||
|
||
|
||
|
||
@dp.message_handler(commands=['help'])
|
||
async def handle_help(message: types.Message):
|
||
#await save_message_data(message)
|
||
user_id = message.from_user.id
|
||
help_message = "Список доступных команд:\n"
|
||
help_message += "/start - начать взаимодействие с ботом\n"
|
||
help_message += "/registration - регистрация\n"
|
||
help_message += "/help - показать список команд и их описания\n"
|
||
sent_message = await bot.send_message(user_id, help_message)
|
||
last_bot_message_id[user_id] = sent_message.message_id
|
||
|
||
|
||
@dp.message_handler(Command("start"), state="*")
|
||
async def handle_start(message: types.Message, state: FSMContext):
|
||
# Завершаем текущее состояние и очищаем данные пользователя
|
||
await state.finish() # Завершает текущее состояние
|
||
await state.storage.reset_data(user=message.from_user.id) # Удаляет все данные пользователя в FSM хранилище
|
||
|
||
# Отправляем фото
|
||
with open("s-blob-v1-IMAGE-tdNCrEv8Ldo.png", "rb") as photo:
|
||
await bot.send_photo(
|
||
chat_id=message.from_user.id,
|
||
photo=photo,
|
||
caption=("Добро пожаловать!\nЯ чат-бот Клиники и Ваш надежный виртуальный помощник.\nЧтобы узнать, что я могу для Вас сделать, просто введите /help\nДля начала работы нажмите кнопку /registration внизу."),
|
||
reply_markup=generate_markup_registration() # Кнопка для продолжения
|
||
)
|
||
|
||
|
||
@dp.message_handler(commands=['registration'], chat_type=types.ChatType.PRIVATE)
|
||
async def handle_registration(message: types.Message):
|
||
user_id = message.from_user.id
|
||
sent_message = await bot.send_message(user_id, "Вы уже являетесь пациентом нашей Клиники?\nЕсли Вы хотите начать общение с ботом заново, нажмите /start.",
|
||
reply_markup=yes_no_markup())
|
||
last_bot_message_id[user_id] = sent_message.message_id
|
||
await Form.existing_patient.set()
|
||
|
||
def generate_markup_telegram_id():
|
||
markup = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True)
|
||
item3 = types.KeyboardButton("Отправить Telegram ID")
|
||
markup.add(item3)
|
||
return markup
|
||
|
||
|
||
def generate_markup_registration():
|
||
markup = types.ReplyKeyboardMarkup(row_width=1, resize_keyboard=True)
|
||
item_registration = types.KeyboardButton("/registration")
|
||
markup.add(item_registration)
|
||
return markup
|
||
|
||
|
||
def generate_back_button():
|
||
"""Создает клавиатуру с кнопкой 'Назад'."""
|
||
markup = ReplyKeyboardMarkup(row_width=1, resize_keyboard=True)
|
||
back_button = KeyboardButton("Назад") # Текст кнопки "Назад"
|
||
markup.add(back_button)
|
||
return markup
|
||
|
||
@dp.message_handler(state=Form.existing_patient)
|
||
async def handle_existing_patient(message: types.Message, state: FSMContext):
|
||
user_id = message.from_user.id
|
||
form_url = f"https://tgbotpolimed.pirogov.ai/?user_id={user_id}"
|
||
|
||
if not message.text.strip():
|
||
await message.answer(
|
||
"Пожалуйста, выберите 'Да' или 'Нет' с помощью кнопок.",
|
||
reply_markup=ReplyKeyboardRemove()
|
||
)
|
||
return
|
||
|
||
if message.text.lower() == "да":
|
||
await message.answer(
|
||
"В соответствии с Федеральным законом № 152-ФЗ «О персональных данных», для идентификации Вас как пациента нашей Клиники, просим заполнить форму, нажав на кнопку ниже.",
|
||
reply_markup=ReplyKeyboardRemove()
|
||
)
|
||
await message.answer(
|
||
"Ввод персональных данных",
|
||
reply_markup=InlineKeyboardMarkup().add(
|
||
InlineKeyboardButton(
|
||
text="Заполнить форму",
|
||
web_app=WebAppInfo(url=form_url)
|
||
)
|
||
)
|
||
)
|
||
|
||
# Отправляем кнопку для проверки данных
|
||
await message.answer(
|
||
"После того как Вы заполните форму, нажмите на кнопку ниже для проверки данных.\n"
|
||
"Если Вы хотите начать общение с ботом заново, нажмите /start.",
|
||
reply_markup=InlineKeyboardMarkup().add(
|
||
InlineKeyboardButton(
|
||
text="Проверить данные",
|
||
callback_data="check_verification"
|
||
)
|
||
)
|
||
)
|
||
await state.finish()
|
||
|
||
elif message.text.lower() == "нет":
|
||
await bot.send_message(
|
||
user_id,
|
||
"Полный доступ к функциям сервиса предоставляется только пациентам нашей Клиники.\n\n"
|
||
"Вы можете связаться с нами по тел.: +7 (342) 207-03-03 или посетить Клинику лично для заключения договора по следующим адресам:\n"
|
||
"г. Пермь, ул. Клары Цеткин, д. 9; ул. Газеты Звезда, д. 31-а.\n\n"
|
||
"Будьте здоровы!\n"
|
||
"Если Вы хотите начать общение с ботом заново, нажмите /start.",
|
||
reply_markup=generate_back_button() # Клавиатура с кнопкой "Назад"
|
||
)
|
||
await state.finish()
|
||
|
||
else:
|
||
await bot.send_message(
|
||
user_id,
|
||
"Пожалуйста, выберите 'Да' или 'Нет' с помощью кнопок.",
|
||
reply_markup=ReplyKeyboardRemove()
|
||
)
|
||
await state.finish()
|
||
|
||
# Обработчик кнопки "Назад"
|
||
@dp.message_handler(lambda message: message.text == "Назад")
|
||
async def handle_back_button(message: types.Message):
|
||
await handle_registration(message) # Вызываем функцию обработки команды /registration
|
||
|
||
|
||
|
||
|
||
|
||
def find_patients_by_id(telegram_id):
|
||
records = sheet.get_all_records() # Получаем все строки таблицы
|
||
patients = []
|
||
for record in records:
|
||
if str(record["Telegram ID"]) == str(telegram_id) and str(record["Верификация"]) == "Пройдена":
|
||
patients.append(record)
|
||
return patients
|
||
|
||
async def prompt_patient_selection(user_id, patient_records):
|
||
# Создаем кнопки с ФИО пациентов
|
||
markup = ReplyKeyboardMarkup(row_width=1, resize_keyboard=True)
|
||
for record in patient_records:
|
||
markup.add(KeyboardButton(record["ФИО"]))
|
||
|
||
# Сохраняем данные пациентов временно
|
||
user_data[user_id]["patients"] = patient_records
|
||
|
||
await bot.send_message(
|
||
user_id,
|
||
"Найдено несколько записей с вашим Telegram ID. Пожалуйста, выберите пациента:",
|
||
reply_markup=markup,
|
||
)
|
||
await Form.fio.set()
|
||
|
||
|
||
async def save_message_data(message: types.Message, reply_to_message_id=None):
|
||
user_id = message.from_user.id
|
||
reply_to_message_id = last_bot_message_id.get(user_id, None)
|
||
|
||
user_messages[message.message_id] = {
|
||
"message_id": message.message_id,
|
||
"text": message.text,
|
||
"date": message.date.isoformat(), # Исправлено
|
||
"user_id": message.from_user.id,
|
||
"reply_to_message_id": reply_to_message_id
|
||
}
|
||
|
||
print(f"Сообщение пользователя {user_id} сохранено: {user_messages[message.message_id]}")
|
||
await send_message_to_server(user_messages[message.message_id])
|
||
|
||
|
||
|
||
async def send_message_to_server(message_data):
|
||
url = "http://192.168.1.10:8080/AppSaveMessage"
|
||
headers = {"Content-Type": "application/json"}
|
||
|
||
async with aiohttp.ClientSession() as session:
|
||
async with session.post(url, headers=headers, json=message_data) as response:
|
||
if response.status == 200:
|
||
print(f"Сообщение {message_data['message_id']} успешно отправлено на сервер.")
|
||
else:
|
||
print(f"Ошибка при отправке сообщения {message_data['message_id']} на сервер. Статус-код: {response.status}")
|
||
|
||
|
||
|
||
# Функция для выполнения POST-запроса и получения списка врачей
|
||
def get_doctors():
|
||
url = "http://192.168.1.10:8080/AppZaprSpecDoc"
|
||
# Данные для отправки в запросе
|
||
data = {"spec_id": 1}
|
||
|
||
# Выполняем POST-запрос
|
||
response = requests.post(url, json=data)
|
||
|
||
# Проверяем статус ответа
|
||
if response.status_code == 200:
|
||
# Если запрос успешен, возвращаем данные
|
||
return response.json()
|
||
else:
|
||
# Если запрос не удался, выводим ошибку
|
||
print(f"Ошибка: {response.status_code}")
|
||
return []
|
||
|
||
|
||
def yes_no_markup():
|
||
markup = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True)
|
||
item_no = types.KeyboardButton("Нет")
|
||
item_yes = types.KeyboardButton("Да")
|
||
markup.add(item_yes, item_no)
|
||
return markup
|
||
|
||
def markup2():
|
||
markup = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True)
|
||
item_good = types.KeyboardButton("Всё верно")
|
||
item_no_good = types.KeyboardButton("Указать ФИО ещё раз")
|
||
markup.add(item_good, item_no_good)
|
||
return markup
|
||
|
||
|
||
def generate_start_markup():
|
||
markup = types.ReplyKeyboardMarkup(row_width=1, resize_keyboard=True)
|
||
start_button = types.KeyboardButton("/start")
|
||
markup.add(start_button)
|
||
return markup
|
||
|
||
|
||
async def send_message_server(phone_number, text, message_id, user_id, date, reply_to_message_id=None):
|
||
url = "http://192.168.1.10:8080/AppSaveMessage"
|
||
headers = {"Content-Type": "application/json"}
|
||
|
||
message_data = {
|
||
"message_id": message_id,
|
||
"text": text,
|
||
"date": date,
|
||
"user_id": user_id, # Передача ID пользователя
|
||
"reply_to_message_id": reply_to_message_id, # Если нужно указать reply_to_message_id
|
||
"phone_number": phone_number
|
||
}
|
||
|
||
async with aiohttp.ClientSession() as session:
|
||
async with session.post(url, json=message_data, headers=headers) as response:
|
||
if response.status == 200:
|
||
print(message_data)
|
||
logging.info("Сообщение успешно отправлено на сервер")
|
||
else:
|
||
logging.error(f"Ошибка при отправке сообщения: {response.status}")
|
||
|
||
|
||
async def send_message_server2(user_id, text, message_id, from_user_id, date, reply_to_message_id):
|
||
url = "http://192.168.1.10:8080/AppSaveMessage"
|
||
headers = {"Content-Type": "application/json"}
|
||
|
||
message_data = {
|
||
"user_id": user_id,
|
||
"text": text,
|
||
"message_id": message_id,
|
||
"from_user_id": from_user_id,
|
||
"date": date,
|
||
"reply_to_message_id": reply_to_message_id,
|
||
}
|
||
|
||
async with aiohttp.ClientSession() as session:
|
||
async with session.post(url, json=message_data, headers=headers) as response:
|
||
if response.status == 200:
|
||
logging.info("Сообщение успешно отправлено на сервер")
|
||
else:
|
||
logging.error(f"Ошибка при отправке сообщения: {response.status}")
|
||
|
||
|
||
|
||
|
||
|
||
def find_patient_by_id(telegram_id):
|
||
records = sheet.get_all_records() # Получаем все строки таблицы
|
||
for record in records:
|
||
if str(record["Telegram ID"]) == str(telegram_id): # Сравнение с Telegram ID
|
||
phone_raw = record["Номер телефона"]
|
||
# Удаляем все нецифровые символы
|
||
phone_formatted = re.sub(r"\D", "", phone_raw)
|
||
|
||
# Проверка на правильную длину номера и корректировка, если необходимо
|
||
if len(phone_formatted) == 11:
|
||
if phone_formatted.startswith("8"): # Если номер начинается с 8, заменяем на 7
|
||
phone_formatted = "7" + phone_formatted[1:]
|
||
return phone_formatted
|
||
else:
|
||
return None # Возвращаем None, если номер неправильной длины
|
||
return None
|
||
|
||
# Коллбек-дата для кнопок
|
||
patient_callback = CallbackData("patient", "index")
|
||
|
||
@dp.message_handler(Command("patients"))
|
||
async def show_patients(message: types.Message):
|
||
telegram_id = message.from_user.id
|
||
patients = find_patients_by_id(telegram_id)
|
||
print(patients)
|
||
|
||
if not patients:
|
||
await message.answer("Пациенты с вашим Telegram ID не найдены.")
|
||
return
|
||
|
||
# Формируем текстовый список пациентов
|
||
patient_list = "\n".join(
|
||
[f"{index + 1}. {patient['ФИО']}" for index, patient in enumerate(patients)]
|
||
)
|
||
|
||
await message.answer(f"Вот список ваших пациентов:\n\n{patient_list}")
|
||
|
||
|
||
def authorize_google():
|
||
# google_json = {}
|
||
# for key in config["GOOGLE"].keys():
|
||
# google_json[key] = config["GOOGLE"][key]
|
||
scope = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/drive"]
|
||
creds = ServiceAccountCredentials.from_json_keyfile_name("botforclinic-436512-0c117dd103a8.json", scope)
|
||
# creds = ServiceAccountCredentials.from_json_keyfile_dict(google_json, scope)
|
||
client = gspread.authorize(creds)
|
||
return client
|
||
|
||
@dp.message_handler(content_types=types.ContentType.TEXT)
|
||
async def handle_message(message: types.Message):
|
||
await save_message_data(message)
|
||
|
||
if __name__ == '__main__':
|
||
executor.start_polling(dp, skip_updates=True) |