From c2255c21668adb1db1bd294a89884d1cd1c61bcd Mon Sep 17 00:00:00 2001 From: krasi Date: Mon, 17 Jun 2024 10:40:49 +0300 Subject: [PATCH] 150600 --- .gitignore | 4 +- .idea/encodings.xml | 7 + README.md | 155 +++++++++++++++++++++ database.py | 53 ++++++++ handlers.py | 158 ++++++++++++++++++++++ logger.py | 6 + main.py | 197 +++------------------------ answers.db => old/answers.db | Bin 8192 -> 8192 bytes old/bot(OLD).py | 103 ++++++++++++++ bot.db => old/bot.db | Bin old/bot.py | 254 +++++++++++++++++++++++++++++++++++ old/database.py | 89 ++++++++++++ old/handlers.py | 183 +++++++++++++++++++++++++ old/klining_order.py | 185 +++++++++++++++++++++++++ old/logger.py | 17 +++ old/main(OLD).py | 213 +++++++++++++++++++++++++++++ old/main.py | 221 ++++++++++++++++++++++++++++++ old/remain.py | 76 +++++++++++ 18 files changed, 1742 insertions(+), 179 deletions(-) create mode 100644 .idea/encodings.xml create mode 100644 database.py create mode 100644 handlers.py create mode 100644 logger.py rename answers.db => old/answers.db (93%) create mode 100644 old/bot(OLD).py rename bot.db => old/bot.db (100%) create mode 100644 old/bot.py create mode 100644 old/database.py create mode 100644 old/handlers.py create mode 100644 old/klining_order.py create mode 100644 old/logger.py create mode 100644 old/main(OLD).py create mode 100644 old/main.py create mode 100644 old/remain.py diff --git a/.gitignore b/.gitignore index 5d381cc..73b87df 100644 --- a/.gitignore +++ b/.gitignore @@ -123,9 +123,9 @@ celerybeat.pid # Environments .env .venv -env/ +.env/ venv/ -ENV/ +.env/ env.bak/ venv.bak/ diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..1ce6493 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index b9f7596..f6d7b3a 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,157 @@ # BOTKlining +## Структура + +1. `main.py`: основной файл для запуска бота. +2. `handlers.py`: обработчики команд и состояний. +3. `database.py`: взаимодействие с базой данных. +4. `logger.py`: логирование действий пользователей. +5. `.env`: файл для хранения конфиденциальных данных. + +Для создания бота с указанной функциональностью и логикой, а также использования файла .env для хранения конфиденциальных данных, мы разобьем задачу на несколько шагов: + +Настройка окружения и установка зависимостей +Создание базы данных +Разработка основных обработчиков команд и колбэков +Создание функций для работы с базой данных +Настройка логирования +Реализация основной логики бота + +Вот подробное описание структуры и логики бота: + +## Inline клавиатура бота: +1. Учетные данные + +- Изменить ФИО: Пользователь может изменить свое ФИО. +- Изменить номер телефона: Позволяет изменить номер телефона. +- Добавить адрес: Пользователь может добавить новый адрес. +- Удалить адрес: Пользователь может удалить ранее добавленный адрес. +- Поделиться контактом: Позволяет поделиться контактными данными, для автоматического заполнения в базе данных. + +2. Сделать заказ + +- Добавить учетные данные: Если у пользователя нет учетных данных, он должен их добавить. Если данные есть они заполняются автоматически. +- Выбрать адрес: Пользователь выбирает адрес или добавляет новый. +- Выбрать время уборки: Предлагает утро, день, вечер. +- Выбрать тип уборки: Влажная, сухая, генеральная. +- Выбрать способ оплаты: Картой, наличными. +- Подтвердить заказ: Подтверждает заказ или позволяет изменить ответы. После подтверждения заказа автоматически отправлять уведомление в группу операторов, а также добавлять заказ в историю. +- Заказу присваивается ID номер + +3. История заказов + +- Просмотреть историю заказов: Позволяет пользователю просмотреть свою историю заказов. +- Добавить функцию повторного заказа на основе предыдущих заказов. + +4. Заказать звонок + +- Добавить учетные данные: Если у пользователя нет учетных данных, он должен их добавить. Если данные есть они заполняются автоматически. +- Заказать звонок: Отправляет учетные данные (ФИО, номер телефона) в группу операторов, с подписью об звонке. Пользователь видит сообщение "ожидайте звонок в течении 30 минут" + +5. Начать разговор с оператором + +- Добавить учетные данные: Если у пользователя нет учетных данных, он должен их добавить. Если данные есть они заполняются автоматически. +- Начать разговор: Отправляет учетные данные (ФИО, номер телефона, ID номер крайнего заказа) в группу операторов. +- Завершить разговор: Пользователь завершает разговор. +- После завершения разговора автоматически отправлять анкету о качестве обслуживания пользователю для обратной связи. Автоматически закрыть анкету в случае не ответа 2 часов. + +6. Назад + +- Возврат к предыдущему набору кнопок: Позволяет вернуться к предыдущему меню кнопок. + +## Логика нажатия кнопок и сохранения данных: +- При первом использовании бота запросить у пользователя учетные данные (ФИО, номер телефона) и сохранить их для последующих заказов. Можно использовать личные данные из Telegram (если пользователь разрешил) для заполнения некоторых полей автоматически. +- При нажатии кнопок пользователем, бот запоминает предыдущий выбор и отображает следующий набор кнопок соответственно. +- Когда пользователь нажимает на любую из кнопок, предыдущий выбор автоматически скрывается, а вместо него появляется следующий набор кнопок. Кнопка "Назад" позволяет вернуться к предыдущему набору кнопок в случае необходимости. Это помогает сделать интерфейс более удобным и интуитивно понятным для пользователей. +- Данные пользователя (учетные данные, адреса, заказы и т.д.) сохраняются в базе данных SQLite3 для последующего использования. +- Логирование действий пользователей осуществляется путем записи информации о каждом действии в лог-файлы, включая дату, время, ID пользователя и другие параметры. +## Управление из группы и внутри бота: +- Группа для заказов управляется операторами и администраторами, которые имеют доступ к соответствующим функциям. +- Операторы могут просматривать историю заказов пользователей, отвечать на сообщения, завершать разговоры и управлять заказами. +- Администраторы имеют дополнительные функции, такие как выгрузка переписки в формате JSON. +- Бот на aiogram используется для более эффективной работы и реализации функций бота через асинхронные методы. +- Эта структура и логика позволят создать функционального бота для управления заказами и общения с операторами, обеспечивая удобство пользователей и контроль над данными. +- Данные токена id групп, id администраторов, операторов дложны храниться в файле env +## Автоматизация + +- Добавить таймеры для отслеживания неактивности пользователя и предложения начать разговор с оператором или оформить заказ при необходимости. +- Использовать базу данных для хранения информации о пользователях, заказах и истории коммуникации с операторами. +- Реализовать механизм автоматического анализа данных о заказах для предложения персонализированных услуг или скидок. +- Создаем базу данных SQLite3 для хранения информации о пользователях, их учетных данных, заказах и истории сообщений с операторами. +- Создаем таблицы для каждой категории данных: пользователи, заказы, история сообщений и т.д. +- Связываем таблицы между собой по ключам (например, по ID пользователя). +- При каждом действии пользователя (нажатие кнопки, отправка сообщения) записываем соответствующую информацию в лог-файлы. +- Логируем дату, время действия, ID пользователя, текстовые данные (если есть) и другие необходимые параметры. +- Создаем специальную группу для приема заказов, где только операторы и администраторы имеют доступ. +- Назначаем операторов и администраторов, которые могут управлять заказами в этой группе. + +1. Функционал операторов: + - Операторы могут просматривать историю заказов конкретного пользователя по его ID. + - Операторы могут отвечать пользователю из группы используя функцию ответа (replay). + - Операторы могут завершать разговор с пользователем с помощью соответствующей кнопки. + +2. Функционал администраторов: + - Администраторы имеют все функции операторов. + - Дополнительно администраторы могут выгружать переписку операторов и пользователя в виде JSON файла. + + + +Логика Бота +есть inline клавиотура со следующими кнопками: +Учетные данные +Изменить ФИО +Изменить номер телефона +Добавит адрес +Поделиться контактом +сделать заказ +Добавит учетные данные, если данные не введены, если введены то пропустить вопрос. +выбрать адрес или указать новый адрес. все веденные адреса сохраняються. +спросить время для уборки: утро/День/вечер +Спросить тип уборки: Влажная/Сухая/Генеральная +Спросить способ оплаты: Картой/Наличными +Подьвердить заказ, или предложить изменить ответ на вопрос. далее кнопки вопросов что бы изменить один ответ и после изменения повторно подтвердить. +После подтверждения, сообщения с ответами отправляеться группу операторов. +История заказов +Все отправленные ответы в группу сохраняются как заказ и храниться в базе данных. +Заказать звонок +Добавит учетные данные, если данные не введены, если введены то пропустить вопрос. +Кнопка заказать звонок, отправляет учетные данные (ФИО, номер телефона) в группу операторов. +Начать разговор с оератором +Добавит учетные данные, если данные не введены, если введены то пропустить вопрос. +Кнопка начать разговор, отправляет учетные данные (ФИО, номер телефона) в группу операторов. +Оператор из группы нажимает ответить(replay) и пишет сообщение, сообшение отправляеться пользователю +пользователь пишет сообщение и оно отправляеться в группу до дех под пока пользователь не нажмет завершить разговор. +Если кнопка завершить разговор не нажато, то через 1 час разговор с оператором завершаеться автоматически. +При заходе пользователя через 2 часа появляеться первоначальное меню кнопок. +Допиши логику, слелай её более автоматизированной. + +ChatGPT +Ты создал очень хорошую базу для логики бота! Вот несколько дополнений и идей для автоматизации: + +Учетные данные: + +При первом использовании бота запросить у пользователя учетные данные (ФИО, номер телефона) и сохранить их для последующих заказов. Можно использовать личные данные из Telegram (если пользователь разрешил) для заполнения некоторых полей автоматически. +Добавить возможность изменения учетных данных через команду или кнопку "Изменить учетные данные". +Сделать заказ: + +После выбора адреса показывать пользователю карту с указанным адресом для подтверждения или возможности изменения. +Автоматически предлагать время уборки в зависимости от текущего времени (например, если пользователь заходит в 9 утра, предложить утреннее время уборки). +После подтверждения заказа автоматически отправлять уведомление в группу операторов, а также добавлять заказ в историю. +История заказов: + +Позволить пользователю просматривать историю своих заказов через бота. +Добавить функцию повторного заказа на основе предыдущих заказов. +Заказать звонок: + +Позволить пользователю выбрать время для звонка (например, "Заказать звонок через 30 минут"). +Автоматически отправлять уведомление о заказе звонка в группу операторов с указанием времени. +Начать разговор с оператором: + +Добавить возможность выбора темы разговора (например, "Техническая поддержка", "Вопрос по заказу" и т. д.). +После завершения разговора автоматически отправлять анкету о качестве обслуживания пользователю для обратной связи. +Автоматизация: + +Добавить таймеры для отслеживания неактивности пользователя и предложения начать разговор с оператором или оформить заказ при необходимости. +Использовать базу данных для хранения информации о пользователях, заказах и истории коммуникации с операторами. +Реализовать механизм автоматического анализа данных о заказах для предложения персонализированных услуг или скидок. +Эти функции помогут сделать бота более удобным и эффективным для пользователей и операторов. \ No newline at end of file diff --git a/database.py b/database.py new file mode 100644 index 0000000..adb6292 --- /dev/null +++ b/database.py @@ -0,0 +1,53 @@ +import sqlite3 + +def create_tables(): + conn = sqlite3.connect('bot_data.db') + cursor = conn.cursor() + + cursor.execute(''' + CREATE TABLE IF NOT EXISTS orders ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT, + phone TEXT, + address TEXT, + cleaning_time TEXT, + cleaning_type TEXT, + payment_method TEXT + ) + ''') + + cursor.execute(''' + CREATE TABLE IF NOT EXISTS users ( + user_id INTEGER PRIMARY KEY, + name TEXT, + phone TEXT, + address TEXT + ) + ''') + + conn.commit() + conn.close() + +def add_order(name, phone, address, cleaning_time, cleaning_type, payment_method): + conn = sqlite3.connect('bot_data.db') + cursor = conn.cursor() + + cursor.execute(''' + INSERT INTO orders (name, phone, address, cleaning_time, cleaning_type, payment_method) + VALUES (?, ?, ?, ?, ?, ?) + ''', (name, phone, address, cleaning_time, cleaning_type, payment_method)) + + conn.commit() + conn.close() + +def get_order_history(user_id): + conn = sqlite3.connect('bot_data.db') + cursor = conn.cursor() + + cursor.execute(''' + SELECT * FROM orders WHERE user_id = ? + ''', (user_id,)) + + orders = cursor.fetchall() + conn.close() + return orders diff --git a/handlers.py b/handlers.py new file mode 100644 index 0000000..a72fffc --- /dev/null +++ b/handlers.py @@ -0,0 +1,158 @@ +import logging +from aiogram import types +from aiogram.dispatcher import FSMContext +from aiogram.dispatcher.filters.state import State, StatesGroup +from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton +from database import add_order, get_order_history +from logger import log_action + +logging.basicConfig(level=logging.INFO) + +class OrderForm(StatesGroup): + waiting_for_name = State() + waiting_for_phone = State() + waiting_for_address = State() + waiting_for_cleaning_time = State() + waiting_for_cleaning_type = State() + waiting_for_payment_method = State() + confirmation = State() + +def main_menu_keyboard(): + keyboard = InlineKeyboardMarkup() + keyboard.add(InlineKeyboardButton('Учетные данные', callback_data='account_data')) + keyboard.add(InlineKeyboardButton('Сделать заказ', callback_data='make_order')) + keyboard.add(InlineKeyboardButton('История заказов', callback_data='order_history')) + keyboard.add(InlineKeyboardButton('Заказать звонок', callback_data='request_call')) + keyboard.add(InlineKeyboardButton('Начать разговор с оператором', callback_data='talk_operator')) + return keyboard + +def account_data_keyboard(): + keyboard = InlineKeyboardMarkup() + keyboard.add(InlineKeyboardButton('Изменить ФИО', callback_data='change_name')) + keyboard.add(InlineKeyboardButton('Изменить номер телефона', callback_data='change_phone')) + keyboard.add(InlineKeyboardButton('Добавить адрес', callback_data='add_address')) + keyboard.add(InlineKeyboardButton('Удалить адрес', callback_data='delete_address')) + keyboard.add(InlineKeyboardButton('Поделиться контактом', callback_data='share_contact')) + keyboard.add(InlineKeyboardButton('Назад', callback_data='back_to_main')) + return keyboard + +def order_confirmation_keyboard(): + keyboard = InlineKeyboardMarkup() + keyboard.add(InlineKeyboardButton('Подтвердить', callback_data='confirm_order')) + return keyboard + +def register_handlers(dp, OPERATORS_GROUP_ID): + @dp.message_handler(commands=['start']) + async def send_welcome(message: types.Message): + await message.answer("Добро пожаловать в BOTKlining!", reply_markup=main_menu_keyboard()) + log_action(message.from_user.id, 'start') + + @dp.callback_query_handler(lambda c: c.data == 'account_data') + async def process_account_data(callback_query: types.CallbackQuery): + await callback_query.answer() + await callback_query.message.answer("Учетные данные:", reply_markup=account_data_keyboard()) + log_action(callback_query.from_user.id, 'account_data') + + @dp.callback_query_handler(lambda c: c.data == 'make_order') + async def process_make_order(callback_query: types.CallbackQuery, state: FSMContext): + await callback_query.answer() + await callback_query.message.answer("Начнем с ваших учетных данных. Введите ваше ФИО:") + await OrderForm.waiting_for_name.set() + log_action(callback_query.from_user.id, 'make_order') + + @dp.callback_query_handler(lambda c: c.data == 'order_history') + async def process_order_history(callback_query: types.CallbackQuery): + await callback_query.answer() + orders = get_order_history(callback_query.from_user.id) + if orders: + history_message = "\n\n".join([f"Заказ {order['id']}:\nФИО: {order['name']}\nАдрес: {order['address']}\nТип уборки: {order['cleaning_type']}" for order in orders]) + await callback_query.message.answer(f"История заказов:\n{history_message}") + else: + await callback_query.message.answer("История заказов пуста.") + log_action(callback_query.from_user.id, 'order_history') + + @dp.callback_query_handler(lambda c: c.data == 'request_call') + async def process_request_call(callback_query: types.CallbackQuery): + await callback_query.answer() + await callback_query.message.answer("Заказ звонка оформлен. Ожидайте звонок в течение 30 минут.") + log_action(callback_query.from_user.id, 'request_call') + + @dp.callback_query_handler(lambda c: c.data == 'talk_operator') + async def process_talk_operator(callback_query: types.CallbackQuery): + await callback_query.answer() + await callback_query.message.answer("Разговор с оператором начат.") + log_action(callback_query.from_user.id, 'talk_operator') + + @dp.callback_query_handler(lambda c: c.data == 'back_to_main') + async def process_back_to_main(callback_query: types.CallbackQuery): + await callback_query.answer() + await callback_query.message.answer("Главное меню:", reply_markup=main_menu_keyboard()) + log_action(callback_query.from_user.id, 'back_to_main') + + @dp.message_handler(state=OrderForm.waiting_for_name, content_types=types.ContentTypes.TEXT) + async def process_name(message: types.Message, state: FSMContext): + async with state.proxy() as data: + data['name'] = message.text + await message.answer("Введите ваш номер телефона:") + await OrderForm.waiting_for_phone.set() + + @dp.message_handler(state=OrderForm.waiting_for_phone, content_types=types.ContentTypes.TEXT) + async def process_phone(message: types.Message, state: FSMContext): + async with state.proxy() as data: + data['phone'] = message.text + await message.answer("Введите адрес для уборки:") + await OrderForm.waiting_for_address.set() + + @dp.message_handler(state=OrderForm.waiting_for_address, content_types=types.ContentTypes.TEXT) + async def process_order_address(message: types.Message, state: FSMContext): + async with state.proxy() as data: + data['address'] = message.text + await message.answer("Выберите время для уборки (утро/день/вечер):") + await OrderForm.waiting_for_cleaning_time.set() + + @dp.message_handler(state=OrderForm.waiting_for_cleaning_time, content_types=types.ContentTypes.TEXT) + async def process_cleaning_time(message: types.Message, state: FSMContext): + async with state.proxy() as data: + data['cleaning_time'] = message.text + await message.answer("Выберите тип уборки (влажная/сухая/генеральная):") + await OrderForm.waiting_for_cleaning_type.set() + + @dp.message_handler(state=OrderForm.waiting_for_cleaning_type, content_types=types.ContentTypes.TEXT) + async def process_cleaning_type(message: types.Message, state: FSMContext): + async with state.proxy() as data: + data['cleaning_type'] = message.text + await message.answer("Выберите способ оплаты (картой/наличными):") + await OrderForm.waiting_for_payment_method.set() + + @dp.message_handler(state=OrderForm.waiting_for_payment_method, content_types=types.ContentTypes.TEXT) + async def process_payment_method(message: types.Message, state: FSMContext): + async with state.proxy() as data: + data['payment_method'] = message.text + + await message.answer("Подтвердите заказ:\n" + f"ФИО: {data['name']}\n" + f"Номер телефона: {data['phone']}\n" + f"Адрес: {data['address']}\n" + f"Время уборки: {data['cleaning_time']}\n" + f"Тип уборки: {data['cleaning_type']}\n" + f"Способ оплаты: {data['payment_method']}\n" + "Если все верно, нажмите 'Подтвердить'. В противном случае, измените нужные данные.", + reply_markup=order_confirmation_keyboard()) + await OrderForm.confirmation.set() + + @dp.callback_query_handler(lambda c: c.data == 'confirm_order', state=OrderForm.confirmation) + async def process_confirm_order(callback_query: types.CallbackQuery, state: FSMContext): + await callback_query.answer() + async with state.proxy() as data: + order_details = (f"Новый заказ:\n" + f"ФИО: {data['name']}\n" + f"Номер телефона: {data['phone']}\n" + f"Адрес: {data['address']}\n" + f"Время уборки: {data['cleaning_time']}\n" + f"Тип уборки: {data['cleaning_type']}\n" + f"Способ оплаты: {data['payment_method']}") + await bot.send_message(OPERATORS_GROUP_ID, order_details) + add_order(data['name'], data['phone'], data['address'], data['cleaning_time'], data['cleaning_type'], data['payment_method']) + + await bot.send_message(callback_query.from_user.id, "Ваш заказ был подтвержден и отправлен операторам.") + await state.finish() diff --git a/logger.py b/logger.py new file mode 100644 index 0000000..f683fcf --- /dev/null +++ b/logger.py @@ -0,0 +1,6 @@ +import logging + +logging.basicConfig(level=logging.INFO) + +def log_action(user_id, action): + logging.info(f"User {user_id} performed action: {action}") diff --git a/main.py b/main.py index 2c54d5f..6d51354 100644 --- a/main.py +++ b/main.py @@ -1,188 +1,31 @@ import logging -import sqlite3 -import asyncio from aiogram import Bot, Dispatcher, types from aiogram.contrib.middlewares.logging import LoggingMiddleware -from aiogram.types import ReplyKeyboardMarkup, KeyboardButton, InlineKeyboardMarkup, InlineKeyboardButton +from aiogram.utils import executor +from aiogram.dispatcher import FSMContext +from aiogram.dispatcher.filters.state import State, StatesGroup +from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton +from dotenv import load_dotenv +import os + +from handlers import register_handlers +from database import create_tables + +# Загрузка переменных окружения из .env файла +load_dotenv() + +API_TOKEN = os.getenv('BOT_API_TOKEN') +OPERATORS_GROUP_ID = int(os.getenv('OPERATORS_GROUP_ID')) +ADMIN_GROUP_ID = int(os.getenv('ADMIN_GROUP_ID')) -# Устанавливаем уровень логов logging.basicConfig(level=logging.INFO) -# Подключаемся к базе данных SQLite -conn = sqlite3.connect("answers.db") -cursor = conn.cursor() - -# Создание таблицы для хранения ответов -cursor.execute(""" -CREATE TABLE IF NOT EXISTS answers ( - user_id INTEGER, - question_id INTEGER, - answer TEXT -) -""") -conn.commit() - -# Заменить на свой токен -API_TOKEN = '7472030348:AAGI53nX-ON-WBmEhd_qBC6EnZsHOqp_2kE' -GROUP_ID = '-1001961537659' - -# Инициализация бота и диспетчера bot = Bot(token=API_TOKEN) dp = Dispatcher(bot) dp.middleware.setup(LoggingMiddleware()) -# Клавиатура для подтверждения ответов -confirm_keyboard = ReplyKeyboardMarkup(resize_keyboard=True).add(KeyboardButton('Подтвердить')) - -# Словарь для хранения вопросов и ответов -questions = { - 1: "Как вас зовут?", - 2: "Укажите номер телефона дл связи", - 3: "Укажите район, улицу дом", - 4: "Какая уборка нужна, влажная ли сухая?", - 5: "На какое время?", - 6: "Оплата наличными или картой?" -} - -# Обработчик команды /start -@dp.message_handler(commands=['start']) -async def start(message: types.Message): - await message.answer("Привет! Я задам тебе 6 вопросов. Давай начнем.") - await ask_question(message.chat.id, 1) - - -# Функция для задания вопроса -async def ask_question(user_id, question_id): - #question_text = questions[question_id] - #await bot.send_message(user_id, text=question_text, reply_markup=confirm_keyboard) - if question_id == 4: - keyboard = InlineKeyboardMarkup(inline_keyboard=[ - [ - InlineKeyboardButton(text="Влажная", callback_data="wet_cleaning"), - InlineKeyboardButton(text="Сухая", callback_data="dry_cleaning") - ] - ]) - question_text = questions[question_id] - await bot.send_message(user_id, text=question_text, reply_markup=keyboard) - elif question_id == 5: - keyboard = InlineKeyboardMarkup(inline_keyboard=[ - [ - InlineKeyboardButton(text="Утро", callback_data="morning_time"), - InlineKeyboardButton(text="День", callback_data="day_time"), - InlineKeyboardButton(text="Вечер", callback_data="evening_time") - ] - ]) - question_text = questions[question_id] - await bot.send_message(user_id, text=question_text, reply_markup=keyboard) - elif question_id == 6: - keyboard = InlineKeyboardMarkup(inline_keyboard=[ - [ - InlineKeyboardButton(text="Наличные", callback_data="cash_payment"), - InlineKeyboardButton(text="Карта", callback_data="card_payment") - ] - ]) - question_text = questions[question_id] - await bot.send_message(user_id, text=question_text, reply_markup=keyboard) - else: - question_text = questions[question_id] - await bot.send_message(user_id, text=question_text, reply_markup=confirm_keyboard) - - -# Обработчик callback-кнопок -@dp.callback_query_handler(lambda query: query.data in ['wet_cleaning', 'dry_cleaning', 'morning_time', 'day_time', 'evening_time', 'cash_payment', 'card_payment']) -async def handle_callback_answer(query: types.CallbackQuery): - answer = { - 'wet_cleaning': 'Влажная уборка', - 'dry_cleaning': 'Сухая уборка', - 'morning_time': 'Утро', - 'day_time': 'День', - 'evening_time': 'Вечер', - 'cash_payment': 'Наличные', - 'card_payment': 'Карта' - } - await save_answer(query.from_user.id, answer[query.data]) - await ask_question(query.from_user.id, query.message.message_id + 1) - -# Функция для сохранения ответа в базе данных -async def save_answer(user_id, answer): - cursor.execute("INSERT INTO answers (user_id, question_id, answer) VALUES (?, ?, ?)", (user_id, cursor.rowcount + 1, answer)) - conn.commit() - -# Обработчик ответов с текстовым полем -@dp.message_handler(lambda message: message.text != 'Подтвердить') -async def handle_text_answer(message: types.Message): - user_id = message.chat.id - cursor.execute("SELECT MAX(question_id) FROM answers WHERE user_id=?", (user_id,)) - prev_question_id = cursor.fetchone()[0] - - if prev_question_id is None: - question_id = 1 - else: - question_id = prev_question_id + 1 - answer = message.text - - cursor.execute("INSERT INTO answers (user_id, question_id, answer) VALUES (?, ?, ?)", - (user_id, question_id, answer)) - conn.commit() - - if question_id < 6: - await ask_question(user_id, question_id + 1) - else: - await bot.send_message(user_id, "Ответы записаны. Подтверди перед отправкой.", reply_markup=confirm_keyboard) - - -# Обработчик ответов с inline кнопкой -@dp.callback_query_handler() -async def handle_callback_answer(query: types.CallbackQuery): - user_id = query.from_user.id - answer = query.data - - cursor.execute("SELECT MAX(question_id) FROM answers WHERE user_id=?", (user_id,)) - prev_question_id = cursor.fetchone()[0] - - if prev_question_id is None: - question_id = 1 - else: - question_id = prev_question_id + 1 - - cursor.execute("INSERT INTO answers (user_id, question_id, answer) VALUES (?, ?, ?)", - (user_id, question_id, answer)) - conn.commit() - - if question_id < 6: - await ask_question(user_id, question_id + 1) - else: - await bot.send_message(user_id, "Ответы записаны. Подтверди перед отправкой.", reply_markup=confirm_keyboard) -# Функция для подтверждения ответов и отправки в группу -@dp.message_handler(lambda message: message.text == 'Подтвердить') -async def confirm_answers(message: types.Message): - user_id = message.chat.id - cursor.execute("SELECT * FROM answers WHERE user_id=?", (user_id,)) - answers = cursor.fetchall() - - if answers: - group_id = GROUP_ID # Заменить на ID вашей группы - answer_text = '\n'.join([f"{questions[ans[1]]}: {ans[2]}" for ans in answers]) - - # Очищаем таблицу с ответами - cursor.execute("DELETE FROM answers WHERE user_id=?", (user_id,)) - conn.commit() - - # Отправляем ответы в группу с помощью реплая - sent_message = await bot.send_message(group_id, answer_text) - await bot.send_message(user_id, - f"Ответы отправлены в группу. Можете посмотреть их [здесь](https://t.me/{sent_message.chat.username}/{sent_message.message_id})", - parse_mode='Markdown') - else: - await bot.send_message(user_id, "Ответов нет") - - +# Основное приложение if __name__ == '__main__': - loop = asyncio.get_event_loop() - try: - loop.create_task(dp.start_polling()) - loop.run_forever() - except KeyboardInterrupt: - pass - finally: - conn.close() + create_tables() + register_handlers(dp, OPERATORS_GROUP_ID) + executor.start_polling(dp, skip_updates=True) diff --git a/answers.db b/old/answers.db similarity index 93% rename from answers.db rename to old/answers.db index 771431feaf389fd6b0568260d5647ba030590647..31b806441dbb5e1112fa946f2c88cbf66e29117f 100644 GIT binary patch delta 338 zcmZp0XmFSy%{X(Sj5FiRjR{NmjU>omU5LSR zfu`)fu;XI;g}oQMFKh*xm&_;&l42FUFy+ElplA)A<>3?r$zJRiU}0fp6#p-_t-!vOB_+8yC0U3WC?X9JVJ=Q7D^5u( zmSzHq=|aSqQqnRN3et+w3KY^ak}9k6Bp6v(IW-}Y7xrIlxUd809@hSgO&9h709N~i AjQ{`u delta 309 zcmZp0XmFSy&1gDN#+lJ{W5N=CIY$0x4E)dd88IQ>3%(Z{3y<;D^YgN>FiJ-7^r^F5 z*n45ah20DcjO>is5j>*YKnYc_#KrCln=Up&NCpOmbBwwmVWtanLFzB;xY&MSFHmwT zP--)yB1CG|g$)-QE;e1*02G`DF@_b*n07|l2p&z4Ia4ld1)9(UR9XTO>r-bzvMrI( z8EoX_IC;4sYl!*G7d8Q{2H`zGO=^tdU=_wDCdMW}z8ELi*%zC^t_G75j4Z62n*YVN V71+04*nhF%!VaK?{XqBa0|4S}a+Cl7 diff --git a/old/bot(OLD).py b/old/bot(OLD).py new file mode 100644 index 0000000..1325944 --- /dev/null +++ b/old/bot(OLD).py @@ -0,0 +1,103 @@ +import os +import logging +from aiogram import Bot, Dispatcher, types +from aiogram.contrib.middlewares.logging import LoggingMiddleware +from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton +from aiogram.utils import executor +from aiogram.dispatcher.filters import Text +from database import create_tables +from logger import log_action +from dotenv import load_dotenv + +# Загрузка переменных окружения из .env файла +load_dotenv() + +API_TOKEN = os.getenv('BOT_API_TOKEN') +OPERATORS_GROUP_ID = os.getenv('OPERATORS_GROUP_ID') +ADMIN_GROUP_ID = os.getenv('ADMIN_GROUP_ID') + +logging.basicConfig(level=logging.INFO) + +bot = Bot(token=API_TOKEN) +dp = Dispatcher(bot) +dp.middleware.setup(LoggingMiddleware()) + +# Inline клавиатуры +def main_menu_keyboard(): + keyboard = InlineKeyboardMarkup() + keyboard.add(InlineKeyboardButton('Учетные данные', callback_data='account_data')) + keyboard.add(InlineKeyboardButton('Сделать заказ', callback_data='make_order')) + keyboard.add(InlineKeyboardButton('История заказов', callback_data='order_history')) + keyboard.add(InlineKeyboardButton('Заказать звонок', callback_data='request_call')) + keyboard.add(InlineKeyboardButton('Начать разговор с оператором', callback_data='talk_operator')) + return keyboard + +def account_data_keyboard(): + keyboard = InlineKeyboardMarkup() + keyboard.add(InlineKeyboardButton('Изменить ФИО', callback_data='change_name')) + keyboard.add(InlineKeyboardButton('Изменить номер телефона', callback_data='change_phone')) + keyboard.add(InlineKeyboardButton('Добавить адрес', callback_data='add_address')) + keyboard.add(InlineKeyboardButton('Удалить адрес', callback_data='delete_address')) + keyboard.add(InlineKeyboardButton('Поделиться контактом', callback_data='share_contact')) + keyboard.add(InlineKeyboardButton('Назад', callback_data='back_to_main')) + return keyboard + +def order_keyboard(): + keyboard = InlineKeyboardMarkup() + keyboard.add(InlineKeyboardButton('Добавить учетные данные', callback_data='add_account_data')) + keyboard.add(InlineKeyboardButton('Выбрать адрес', callback_data='select_address')) + keyboard.add(InlineKeyboardButton('Выбрать время для уборки', callback_data='select_time')) + keyboard.add(InlineKeyboardButton('Выбрать тип уборки', callback_data='select_cleaning_type')) + keyboard.add(InlineKeyboardButton('Выбрать способ оплаты', callback_data='select_payment_method')) + keyboard.add(InlineKeyboardButton('Подтвердить заказ', callback_data='confirm_order')) + keyboard.add(InlineKeyboardButton('Назад', callback_data='back_to_main')) + return keyboard + +# Обработчики команд +@dp.message_handler(commands=['start']) +async def send_welcome(message: types.Message): + await message.answer("Добро пожаловать в BOTKlining!", reply_markup=main_menu_keyboard()) + log_action(message.from_user.id, 'start') + +@dp.callback_query_handler(lambda c: c.data == 'account_data') +async def process_account_data(callback_query: types.CallbackQuery): + await bot.answer_callback_query(callback_query.id) + await bot.send_message(callback_query.from_user.id, "Учетные данные:", reply_markup=account_data_keyboard()) + log_action(callback_query.from_user.id, 'account_data') + +@dp.callback_query_handler(lambda c: c.data == 'make_order') +async def process_make_order(callback_query: types.CallbackQuery): + await bot.answer_callback_query(callback_query.id) + await bot.send_message(callback_query.from_user.id, "Сделать заказ:", reply_markup=order_keyboard()) + log_action(callback_query.from_user.id, 'make_order') + +@dp.callback_query_handler(lambda c: c.data == 'order_history') +async def process_order_history(callback_query: types.CallbackQuery): + await bot.answer_callback_query(callback_query.id) + # Добавьте логику для просмотра истории заказов + await bot.send_message(callback_query.from_user.id, "История заказов:") + log_action(callback_query.from_user.id, 'order_history') + +@dp.callback_query_handler(lambda c: c.data == 'request_call') +async def process_request_call(callback_query: types.CallbackQuery): + await bot.answer_callback_query(callback_query.id) + # Добавьте логику для заказа звонка + await bot.send_message(callback_query.from_user.id, "Заказ звонка оформлен. Ожидайте звонок в течение 30 минут.") + log_action(callback_query.from_user.id, 'request_call') + +@dp.callback_query_handler(lambda c: c.data == 'talk_operator') +async def process_talk_operator(callback_query: types.CallbackQuery): + await bot.answer_callback_query(callback_query.id) + # Добавьте логику для начала разговора с оператором + await bot.send_message(callback_query.from_user.id, "Разговор с оператором начат.") + log_action(callback_query.from_user.id, 'talk_operator') + +@dp.callback_query_handler(lambda c: c.data == 'back_to_main') +async def process_back_to_main(callback_query: types.CallbackQuery): + await bot.answer_callback_query(callback_query.id) + await bot.send_message(callback_query.from_user.id, "Главное меню:", reply_markup=main_menu_keyboard()) + log_action(callback_query.from_user.id, 'back_to_main') + +if __name__ == '__main__': + create_tables() + executor.start_polling(dp, skip_updates=True) diff --git a/bot.db b/old/bot.db similarity index 100% rename from bot.db rename to old/bot.db diff --git a/old/bot.py b/old/bot.py new file mode 100644 index 0000000..491d866 --- /dev/null +++ b/old/bot.py @@ -0,0 +1,254 @@ +import logging +import sqlite3 +from aiogram import types +from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton +from aiogram.dispatcher import FSMContext +from aiogram.dispatcher.filters.state import State, StatesGroup +from aiogram.contrib.middlewares.logging import LoggingMiddleware +from aiogram.utils import executor +from aiogram import Bot, Dispatcher +from aiogram.dispatcher.filters import Text +from database import create_tables, add_user, update_user_name, update_user_phone, add_address, delete_address +from logger import log_action +from dotenv import load_dotenv +import os + +# Загрузка переменных окружения из .env файла +load_dotenv() + +API_TOKEN = os.getenv('BOT_API_TOKEN') +OPERATORS_GROUP_ID = int(os.getenv('OPERATORS_GROUP_ID')) +ADMIN_GROUP_ID = int(os.getenv('ADMIN_GROUP_ID')) + +logging.basicConfig(level=logging.INFO) + +bot = Bot(token=API_TOKEN) +dp = Dispatcher(bot) +dp.middleware.setup(LoggingMiddleware()) + +# Состояния +class OrderForm(StatesGroup): + waiting_for_name = State() + waiting_for_phone = State() + waiting_for_address = State() + waiting_for_cleaning_time = State() + waiting_for_cleaning_type = State() + waiting_for_payment_method = State() + confirmation = State() + +class CallRequest(StatesGroup): + waiting_for_name = State() + waiting_for_phone = State() + +class OperatorChat(StatesGroup): + in_chat = State() + +# Inline клавиатуры +def main_menu_keyboard(): + keyboard = InlineKeyboardMarkup() + keyboard.add(InlineKeyboardButton('Учетные данные', callback_data='account_data')) + keyboard.add(InlineKeyboardButton('Сделать заказ', callback_data='make_order')) + keyboard.add(InlineKeyboardButton('История заказов', callback_data='order_history')) + keyboard.add(InlineKeyboardButton('Заказать звонок', callback_data='request_call')) + keyboard.add(InlineKeyboardButton('Начать разговор с оператором', callback_data='talk_operator')) + return keyboard + +def account_data_keyboard(): + keyboard = InlineKeyboardMarkup() + keyboard.add(InlineKeyboardButton('Изменить ФИО', callback_data='change_name')) + keyboard.add(InlineKeyboardButton('Изменить номер телефона', callback_data='change_phone')) + keyboard.add(InlineKeyboardButton('Добавить адрес', callback_data='add_address')) + keyboard.add(InlineKeyboardButton('Удалить адрес', callback_data='delete_address')) + keyboard.add(InlineKeyboardButton('Поделиться контактом', callback_data='share_contact')) + keyboard.add(InlineKeyboardButton('Назад', callback_data='back_to_main')) + return keyboard + +def order_keyboard(): + keyboard = InlineKeyboardMarkup() + keyboard.add(InlineKeyboardButton('Добавить учетные данные', callback_data='add_account_data')) + keyboard.add(InlineKeyboardButton('Выбрать адрес', callback_data='select_address')) + keyboard.add(InlineKeyboardButton('Выбрать время для уборки', callback_data='select_time')) + keyboard.add(InlineKeyboardButton('Выбрать тип уборки', callback_data='select_cleaning_type')) + keyboard.add(InlineKeyboardButton('Выбрать способ оплаты', callback_data='select_payment_method')) + keyboard.add(InlineKeyboardButton('Подтвердить заказ', callback_data='confirm_order')) + keyboard.add(InlineKeyboardButton('Назад', callback_data='back_to_main')) + return keyboard + +# Основные команды +@dp.message_handler(commands=['start']) +async def send_welcome(message: types.Message): + await message.answer("Добро пожаловать в BOTKlining!", reply_markup=main_menu_keyboard()) + log_action(message.from_user.id, 'start') + +@dp.callback_query_handler(lambda c: c.data == 'account_data') +async def process_account_data(callback_query: types.CallbackQuery): + await bot.answer_callback_query(callback_query.id) + await bot.send_message(callback_query.from_user.id, "Учетные данные:", reply_markup=account_data_keyboard()) + log_action(callback_query.from_user.id, 'account_data') + +@dp.callback_query_handler(lambda c: c.data == 'make_order') +async def process_make_order(callback_query: types.CallbackQuery): + await bot.answer_callback_query(callback_query.id) + await bot.send_message(callback_query.from_user.id, "Сделать заказ:", reply_markup=order_keyboard()) + log_action(callback_query.from_user.id, 'make_order') + +@dp.callback_query_handler(lambda c: c.data == 'order_history') +async def process_order_history(callback_query: types.CallbackQuery): + await bot.answer_callback_query(callback_query.id) + # Добавьте логику для просмотра истории заказов + await bot.send_message(callback_query.from_user.id, "История заказов:") + log_action(callback_query.from_user.id, 'order_history') + +@dp.callback_query_handler(lambda c: c.data == 'request_call') +async def process_request_call(callback_query: types.CallbackQuery): + await bot.answer_callback_query(callback_query.id) + # Добавьте логику для заказа звонка + await bot.send_message(callback_query.from_user.id, "Заказ звонка оформлен. Ожидайте звонок в течение 30 минут.") + log_action(callback_query.from_user.id, 'request_call') + +@dp.callback_query_handler(lambda c: c.data == 'talk_operator') +async def process_talk_operator(callback_query: types.CallbackQuery): + await bot.answer_callback_query(callback_query.id) + # Добавьте логику для начала разговора с оператором + await bot.send_message(callback_query.from_user.id, "Разговор с оператором начат.") + log_action(callback_query.from_user.id, 'talk_operator') + +@dp.callback_query_handler(lambda c: c.data == 'back_to_main') +async def process_back_to_main(callback_query: types.CallbackQuery): + await bot.answer_callback_query(callback_query.id) + await bot.send_message(callback_query.from_user.id, "Главное меню:", reply_markup=main_menu_keyboard()) + log_action(callback_query.from_user.id, 'back_to_main') + +# Добавление учетных данных +@dp.callback_query_handler(lambda c: c.data == 'add_account_data') +async def process_add_account_data(callback_query: types.CallbackQuery): + await bot.answer_callback_query(callback_query.id) + await bot.send_message(callback_query.from_user.id, "Введите ваше ФИО:") + await OrderForm.waiting_for_name.set() + +@dp.message_handler(state=OrderForm.waiting_for_name, content_types=types.ContentTypes.TEXT) +async def process_name(message: types.Message, state: FSMContext): + async with state.proxy() as data: + data['name'] = message.text + await message.answer("Введите ваш номер телефона:") + await OrderForm.waiting_for_phone.set() + +@dp.message_handler(state=OrderForm.waiting_for_phone, content_types=types.ContentTypes.TEXT) +async def process_phone(message: types.Message, state: FSMContext): + async with state.proxy() as data: + data['phone'] = message.text + user_id = message.from_user.id + name = data['name'] + phone = data['phone'] + add_user(user_id, name, phone) + await message.answer("Ваши данные успешно сохранены!") + await state.finish() + +# Изменение учетных данных +@dp.callback_query_handler(lambda c: c.data == 'change_name') +async def process_change_name(callback_query: types.CallbackQuery): + await bot.answer_callback_query(callback_query.id) + await bot.send_message(callback_query.from_user.id, "Введите новое ФИО:") + await OrderForm.waiting_for_name.set() + +@dp.callback_query_handler(lambda c: c.data == 'change_phone') +async def process_change_phone(callback_query: types.CallbackQuery): + await bot.answer_callback_query(callback_query.id) + await bot.send_message(callback_query.from_user.id, "Введите новый номер телефона:") + await OrderForm.waiting_for_phone.set() + +# Добавление адреса +@dp.callback_query_handler(lambda c: c.data == 'add_address') +async def process_add_address(callback_query: types.CallbackQuery): + await bot.answer_callback_query(callback_query.id) + await bot.send_message(callback_query.from_user.id, "Введите адрес для добавления:") + await OrderForm.waiting_for_address.set() + +@dp.message_handler(state=OrderForm.waiting_for_address, content_types=types.ContentTypes.TEXT) +async def process_add_address_step(message: types.Message, state: FSMContext): + user_id = message.from_user.id + address = message.text + add_address(user_id, address) + await message.answer("Адрес успешно добавлен!") + await state.finish() + +# Удаление адреса +@dp.callback_query_handler(lambda c: c.data == 'delete_address') +async def process_delete_address(callback_query: types.CallbackQuery): + await bot.answer_callback_query(callback_query.id) + await bot.send_message(callback_query.from_user.id, "Введите адрес для удаления:") + await OrderForm.waiting_for_address.set() + +@dp.message_handler(state=OrderForm.waiting_for_address, content_types=types.ContentTypes.TEXT) +async def process_delete_address_step(message: types.Message, state: FSMContext): + user_id = message.from_user.id + address = message.text + delete_address(user_id, address) + await message.answer("Адрес успешно удален!") + await state.finish() + +# Обработка заказа +@dp.callback_query_handler(lambda c: c.data == 'select_address') +async def process_select_address(callback_query: types.CallbackQuery): + await bot.answer_callback_query(callback_query.id) + await bot.send_message(callback_query.from_user.id, "Введите адрес для уборки:") + await OrderForm.waiting_for_address.set() + +@dp.message_handler(state=OrderForm.waiting_for_address, content_types=types.ContentTypes.TEXT) +async def process_order_address(message: types.Message, state: FSMContext): + async with state.proxy() as data: + data['address'] = message.text + await message.answer("Выберите время для уборки (утро/день/вечер):") + await OrderForm.waiting_for_cleaning_time.set() + +@dp.message_handler(state=OrderForm.waiting_for_cleaning_time, content_types=types.ContentTypes.TEXT) +async def process_cleaning_time(message: types.Message, state: FSMContext): + async with state.proxy() as data: + data['cleaning_time'] = message.text + await message.answer("Выберите тип уборки (влажная/сухая/генеральная):") + await OrderForm.waiting_for_cleaning_type.set() + +@dp.message_handler(state=OrderForm.waiting_for_cleaning_type, content_types=types.ContentTypes.TEXT) +async def process_cleaning_type(message: types.Message, state: FSMContext): + async with state.proxy() as data: + data['cleaning_type'] = message.text + await message.answer("Выберите способ оплаты (картой/наличными):") + await OrderForm.waiting_for_payment_method.set() + +@dp.message_handler(state=OrderForm.waiting_for_payment_method, content_types=types.ContentTypes.TEXT) +async def process_payment_method(message: types.Message, state: FSMContext): + async with state.proxy() as data: + data['payment_method'] = message.text + + # Отправка подтверждения заказа + await message.answer("Подтвердите заказ:\n" + f"Адрес: {data['address']}\n" + f"Время уборки: {data['cleaning_time']}\n" + f"Тип уборки: {data['cleaning_type']}\n" + f"Способ оплаты: {data['payment_method']}\n" + "Если все верно, нажмите 'Подтвердить'. В противном случае, измените нужные данные.", + reply_markup=InlineKeyboardMarkup().add(InlineKeyboardButton('Подтвердить', callback_data='confirm_order'))) + await OrderForm.confirmation.set() + +@dp.callback_query_handler(lambda c: c.data == 'confirm_order', state=OrderForm.confirmation) +async def process_confirm_order(callback_query: types.CallbackQuery, state: FSMContext): + await bot.answer_callback_query(callback_query.id) + async with state.proxy() as data: + order_details = (f"Новый заказ:\n" + f"ФИО: {data['name']}\n" + f"Номер телефона: {data['phone']}\n" + f"Адрес: {data['address']}\n" + f"Время уборки: {data['cleaning_time']}\n" + f"Тип уборки: {data['cleaning_type']}\n" + f"Способ оплаты: {data['payment_method']}") + + await bot.send_message(OPERATORS_GROUP_ID, order_details) + log_action(callback_query.from_user.id, 'confirm_order') + + await bot.send_message(callback_query.from_user.id, "Ваш заказ был подтвержден и отправлен операторам.") + await state.finish() + +# Основное приложение +if __name__ == '__main__': + create_tables() + executor.start_polling(dp, skip_updates=True) diff --git a/old/database.py b/old/database.py new file mode 100644 index 0000000..0ce6d10 --- /dev/null +++ b/old/database.py @@ -0,0 +1,89 @@ +import sqlite3 + + +def create_tables(): + conn = sqlite3.connect('bot_klining.db') + cursor = conn.cursor() + + cursor.execute(''' + CREATE TABLE IF NOT EXISTS users ( + id INTEGER PRIMARY KEY, + telegram_id INTEGER UNIQUE, + name TEXT, + phone TEXT + ) + ''') + + cursor.execute(''' + CREATE TABLE IF NOT EXISTS addresses ( + id INTEGER PRIMARY KEY, + user_id INTEGER, + address TEXT, + FOREIGN KEY(user_id) REFERENCES users(id) + ) + ''') + + cursor.execute(''' + CREATE TABLE IF NOT EXISTS orders ( + id INTEGER PRIMARY KEY, + user_id INTEGER, + address TEXT, + cleaning_time TEXT, + cleaning_type TEXT, + payment_method TEXT, + order_id TEXT UNIQUE, + FOREIGN KEY(user_id) REFERENCES users(id) + ) + ''') + + cursor.execute(''' + CREATE TABLE IF NOT EXISTS logs ( + id INTEGER PRIMARY KEY, + user_id INTEGER, + action TEXT, + timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY(user_id) REFERENCES users(id) + ) + ''') + + conn.commit() + conn.close() + +def add_user(telegram_id, name, phone): + conn = sqlite3.connect('bot_klining.db') + cursor = conn.cursor() + cursor.execute('INSERT OR IGNORE INTO users (telegram_id, name, phone) VALUES (?, ?, ?)', (telegram_id, name, phone)) + conn.commit() + conn.close() + +def update_user_name(telegram_id, name): + conn = sqlite3.connect('bot_klining.db') + cursor = conn.cursor() + cursor.execute('UPDATE users SET name = ? WHERE telegram_id = ?', (name, telegram_id)) + conn.commit() + conn.close() + +def update_user_phone(telegram_id, phone): + conn = sqlite3.connect('bot_klining.db') + cursor = conn.cursor() + cursor.execute('UPDATE users SET phone = ? WHERE telegram_id = ?', (phone, telegram_id)) + conn.commit() + conn.close() + +def add_address(telegram_id, address): + conn = sqlite3.connect('bot_klining.db') + cursor = conn.cursor() + cursor.execute('SELECT id FROM users WHERE telegram_id = ?', (telegram_id,)) + user_id = cursor.fetchone()[0] + cursor.execute('INSERT INTO addresses (user_id, address) VALUES (?, ?)', (user_id, address)) + conn.commit() + conn.close() + +def delete_address(telegram_id, address): + conn = sqlite3.connect('bot_klining.db') + cursor = conn.cursor() + cursor.execute('SELECT id FROM users WHERE telegram_id = ?', (telegram_id,)) + user_id = cursor.fetchone()[0] + cursor.execute('DELETE FROM addresses WHERE user_id = ? AND address = ?', (user_id, address)) + conn.commit() + conn.close() \ No newline at end of file diff --git a/old/handlers.py b/old/handlers.py new file mode 100644 index 0000000..dce24e5 --- /dev/null +++ b/old/handlers.py @@ -0,0 +1,183 @@ +import logging +import sqlite3 +from aiogram import types +from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton +from aiogram.dispatcher import FSMContext +from aiogram.dispatcher.filters.state import State, StatesGroup +from aiogram.contrib.middlewares.logging import LoggingMiddleware +from aiogram.utils import executor +from aiogram import Bot, Dispatcher +from aiogram.dispatcher.filters import Text +from database import create_tables, add_user, update_user_name, update_user_phone, add_address, delete_address, add_order +from logger import log_action +from dotenv import load_dotenv +import os + +# Загрузка переменных окружения из .env файла +load_dotenv() + +API_TOKEN = os.getenv('BOT_API_TOKEN') +OPERATORS_GROUP_ID = int(os.getenv('OPERATORS_GROUP_ID')) +ADMIN_GROUP_ID = int(os.getenv('ADMIN_GROUP_ID')) + +logging.basicConfig(level=logging.INFO) + +bot = Bot(token=API_TOKEN) +dp = Dispatcher(bot) +dp.middleware.setup(LoggingMiddleware()) + +# Состояния для заказа +class OrderForm(StatesGroup): + waiting_for_name = State() + waiting_for_phone = State() + waiting_for_address = State() + waiting_for_cleaning_time = State() + waiting_for_cleaning_type = State() + waiting_for_payment_method = State() + confirmation = State() + +# Inline клавиатуры +def main_menu_keyboard(): + keyboard = InlineKeyboardMarkup() + keyboard.add(InlineKeyboardButton('Учетные данные', callback_data='account_data')) + keyboard.add(InlineKeyboardButton('Сделать заказ', callback_data='make_order')) + keyboard.add(InlineKeyboardButton('История заказов', callback_data='order_history')) + keyboard.add(InlineKeyboardButton('Заказать звонок', callback_data='request_call')) + keyboard.add(InlineKeyboardButton('Начать разговор с оператором', callback_data='talk_operator')) + return keyboard + +def account_data_keyboard(): + keyboard = InlineKeyboardMarkup() + keyboard.add(InlineKeyboardButton('Изменить ФИО', callback_data='change_name')) + keyboard.add(InlineKeyboardButton('Изменить номер телефона', callback_data='change_phone')) + keyboard.add(InlineKeyboardButton('Добавить адрес', callback_data='add_address')) + keyboard.add(InlineKeyboardButton('Удалить адрес', callback_data='delete_address')) + keyboard.add(InlineKeyboardButton('Поделиться контактом', callback_data='share_contact')) + keyboard.add(InlineKeyboardButton('Назад', callback_data='back_to_main')) + return keyboard + +# Основные команды +@dp.message_handler(commands=['start']) +async def send_welcome(message: types.Message): + await message.answer("Добро пожаловать в BOTKlining!", reply_markup=main_menu_keyboard()) + log_action(message.from_user.id, 'start') + +@dp.callback_query_handler(lambda c: c.data == 'account_data') +async def process_account_data(callback_query: types.CallbackQuery): + await bot.answer_callback_query(callback_query.id) + await bot.send_message(callback_query.from_user.id, "Учетные данные:", reply_markup=account_data_keyboard()) + log_action(callback_query.from_user.id, 'account_data') + +@dp.callback_query_handler(lambda c: c.data == 'make_order') +async def process_make_order(callback_query: types.CallbackQuery, state: FSMContext): + await bot.answer_callback_query(callback_query.id) + await bot.send_message(callback_query.from_user.id, "Начнем с ваших учетных данных. Введите ваше ФИО:") + await OrderForm.waiting_for_name.set() + log_action(callback_query.from_user.id, 'make_order') + +@dp.callback_query_handler(lambda c: c.data == 'order_history') +async def process_order_history(callback_query: types.CallbackQuery): + await bot.answer_callback_query(callback_query.id) + # Добавьте логику для просмотра истории заказов + await bot.send_message(callback_query.from_user.id, "История заказов:") + log_action(callback_query.from_user.id, 'order_history') + +@dp.callback_query_handler(lambda c: c.data == 'request_call') +async def process_request_call(callback_query: types.CallbackQuery): + await bot.answer_callback_query(callback_query.id) + # Добавьте логику для заказа звонка + await bot.send_message(callback_query.from_user.id, "Заказ звонка оформлен. Ожидайте звонок в течение 30 минут.") + log_action(callback_query.from_user.id, 'request_call') + +@dp.callback_query_handler(lambda c: c.data == 'talk_operator') +async def process_talk_operator(callback_query: types.CallbackQuery): + await bot.answer_callback_query(callback_query.id) + # Добавьте логику для начала разговора с оператором + await bot.send_message(callback_query.from_user.id, "Разговор с оператором начат.") + log_action(callback_query.from_user.id, 'talk_operator') + +@dp.callback_query_handler(lambda c: c.data == 'back_to_main') +async def process_back_to_main(callback_query: types.CallbackQuery): + await bot.answer_callback_query(callback_query.id) + await bot.send_message(callback_query.from_user.id, "Главное меню:", reply_markup=main_menu_keyboard()) + log_action(callback_query.from_user.id, 'back_to_main') + +# Обработка шагов заказа +@dp.message_handler(state=OrderForm.waiting_for_name, content_types=types.ContentTypes.TEXT) +async def process_name(message: types.Message, state: FSMContext): + async with state.proxy() as data: + data['name'] = message.text + await message.answer("Введите ваш номер телефона:") + await OrderForm.waiting_for_phone.set() + +@dp.message_handler(state=OrderForm.waiting_for_phone, content_types=types.ContentTypes.TEXT) +async def process_phone(message: types.Message, state: FSMContext): + async with state.proxy() as data: + data['phone'] = message.text + await message.answer("Введите адрес для уборки:") + await OrderForm.waiting_for_address.set() + +@dp.message_handler(state=OrderForm.waiting_for_address, content_types=types.ContentTypes.TEXT) +async def process_order_address(message: types.Message, state: FSMContext): + async with state.proxy() as data: + data['address'] = message.text + await message.answer("Выберите время для уборки (утро/день/вечер):") + await OrderForm.waiting_for_cleaning_time.set() + +@dp.message_handler(state=OrderForm.waiting_for_cleaning_time, content_types=types.ContentTypes.TEXT) +async def process_cleaning_time(message: types.Message, state: FSMContext): + async with state.proxy() as data: + data['cleaning_time'] = message.text + await message.answer("Выберите тип уборки (влажная/сухая/генеральная):") + await OrderForm.waiting_for_cleaning_type.set() + +@dp.message_handler(state=OrderForm.waiting_for_cleaning_type, content_types=types.ContentTypes.TEXT) +async def process_cleaning_type(message: types.Message, state: FSMContext): + async with state.proxy() as data: + data['cleaning_type'] = message.text + await message.answer("Выберите способ оплаты (картой/наличными):") + await OrderForm.waiting_for_payment_method.set() + +@dp.message_handler(state=OrderForm.waiting_for_payment_method, content_types=types.ContentTypes.TEXT) +async def process_payment_method(message: types.Message, state: FSMContext): + async with state.proxy() as data: + data['payment_method'] = message.text + + # Отправка подтверждения заказа + await message.answer("Подтвердите заказ:\n" + f"ФИО: {data['name']}\n" + f"Номер телефона: {data['phone']}\n" + f"Адрес: {data['address']}\n" + f"Время уборки: {data['cleaning_time']}\n" + f"Тип уборки: {data['cleaning_type']}\n" + f"Способ оплаты: {data['payment_method']}\n" + "Если все верно, нажмите 'Подтвердить'. В противном случае, измените нужные данные.", + reply_markup=InlineKeyboardMarkup().add(InlineKeyboardButton('Подтвердить', callback_data='confirm_order'))) + await OrderForm.confirmation.set() + +@dp.callback_query_handler(lambda c: c.data == 'confirm_order', state=OrderForm.confirmation) +async def process_confirm_order(callback_query: types.CallbackQuery, state: FSMContext): + await bot.answer_callback_query(callback_query.id) + async with state.proxy() as data: + order_details = (f"Новый заказ:\n" + f"ФИО: {data['name']}\n" + f"Номер телефона: {data['phone']}\n" + f"Адрес: {data['address']}\n" + f"Время уборки: {data['cleaning_time']}\n" + f"Тип уборки: {data['cleaning_type']}\n" + f"Способ оплаты: {data['payment_method']}") + + # Отправка заказа операторам + await bot.send_message(OPERATORS_GROUP_ID, order_details) + log_action(callback_query.from_user.id, 'confirm_order') + + # Сохранение заказа в базе данных + add_order(data['name'], data['phone'], data['address'], data['cleaning_time'], data['cleaning_type'], data['payment_method']) + + await bot.send_message(callback_query.from_user.id, "Ваш заказ был подтвержден и отправлен операторам.") + await state.finish() + +# Основное приложение +if __name__ == '__main__': + create_tables() + executor.start_polling(dp, skip_updates=True) diff --git a/old/klining_order.py b/old/klining_order.py new file mode 100644 index 0000000..0fdc074 --- /dev/null +++ b/old/klining_order.py @@ -0,0 +1,185 @@ +import logging +import sqlite3 +import asyncio +from aiogram import Bot, Dispatcher, types +from aiogram.contrib.middlewares.logging import LoggingMiddleware +from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton + +# Устанавливаем уровень логов +logging.basicConfig(level=logging.INFO) + +# Подключаемся к базе данных SQLite +conn = sqlite3.connect("answers.db") +cursor = conn.cursor() + +# Создание таблицы для хранения ответов +cursor.execute(""" +CREATE TABLE IF NOT EXISTS answers ( + user_id INTEGER, + question_id INTEGER, + answer TEXT +) +""") +conn.commit() + +# Заменить на свой токен +API_TOKEN = '7472030348:AAGI53nX-ON-WBmEhd_qBC6EnZsHOqp_2kE' +GROUP_ID = '-1001961537659' + +# Инициализация бота и диспетчера +bot = Bot(token=API_TOKEN) +dp = Dispatcher(bot) +dp.middleware.setup(LoggingMiddleware()) + +# Словарь для хранения вопросов и ответов +questions = { + 1: "Как вас зовут?", + 2: "Укажите номер телефона для связи", + 3: "Укажите район, улицу, дом", + 4: "Какая уборка нужна, влажная или сухая?", + 5: "На какое время?", + 6: "Оплата наличными или картой?" +} + +answer_map = { + 'wet_cleaning': 'Влажная уборка', + 'dry_cleaning': 'Сухая уборка', + 'morning_time': 'Утро', + 'day_time': 'День', + 'evening_time': 'Вечер', + 'cash_payment': 'Наличные', + 'card_payment': 'Карта' +} + +# Обработчик команды /start +@dp.message_handler(commands=['start']) +async def start(message: types.Message): + await message.answer("Привет! Я задам тебе 6 вопросов. Давай начнем.") + await ask_question(message.chat.id, 1) + +# Функция для задания вопроса +async def ask_question(user_id, question_id): + if question_id in [4, 5, 6]: + if question_id == 4: + keyboard = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="Влажная", callback_data="wet_cleaning")], + [InlineKeyboardButton(text="Сухая", callback_data="dry_cleaning")] + ]) + elif question_id == 5: + keyboard = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="Утро", callback_data="morning_time")], + [InlineKeyboardButton(text="День", callback_data="day_time")], + [InlineKeyboardButton(text="Вечер", callback_data="evening_time")] + ]) + elif question_id == 6: + keyboard = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="Наличные", callback_data="cash_payment")], + [InlineKeyboardButton(text="Карта", callback_data="card_payment")] + ]) + await bot.send_message(user_id, text=questions[question_id], reply_markup=keyboard) + else: + await bot.send_message(user_id, text=questions[question_id]) + +# Обработчик текстовых ответов на первые три вопроса +@dp.message_handler(lambda message: message.text not in ["Переписать", "Отправить"]) +async def handle_text_answer(message: types.Message): + user_id = message.chat.id + cursor.execute("SELECT MAX(question_id) FROM answers WHERE user_id=?", (user_id,)) + prev_question_id = cursor.fetchone()[0] + + if prev_question_id is None: + question_id = 1 + else: + question_id = prev_question_id + 1 + answer = message.text + + await save_answer(user_id, question_id, answer) + + if question_id < 6: + await ask_question(user_id, question_id + 1) + else: + await show_confirmation_options(user_id) + +# Обработчик inline-кнопок +@dp.callback_query_handler(lambda query: query.data in answer_map.keys()) +async def handle_callback_answer(query: types.CallbackQuery): + user_id = query.from_user.id + cursor.execute("SELECT MAX(question_id) FROM answers WHERE user_id=?", (user_id,)) + prev_question_id = cursor.fetchone()[0] + + if prev_question_id is None: + question_id = 1 + else: + question_id = prev_question_id + 1 + + await save_answer(user_id, question_id, answer_map[query.data]) + await query.answer() + + if question_id < 6: + await ask_question(user_id, question_id + 1) + else: + await show_confirmation_options(user_id) + +# Функция для сохранения ответа в базе данных +async def save_answer(user_id, question_id, answer): + cursor.execute("INSERT INTO answers (user_id, question_id, answer) VALUES (?, ?, ?)", (user_id, question_id, answer)) + conn.commit() + +# Функция для отображения опций подтверждения +async def show_confirmation_options(user_id): + cursor.execute("SELECT answer FROM answers WHERE user_id=? ORDER BY question_id", (user_id,)) + answers = cursor.fetchall() + answer_text = "\n".join([f"{questions[i+1]}: {answers[i][0]}" for i in range(6)]) + await bot.send_message(user_id, text=f"Ваши ответы:\n\n{answer_text}") + + keyboard = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="Отправить", callback_data="send_answers")], + [InlineKeyboardButton(text="Переписать", callback_data="rewrite_answers")] + ]) + await bot.send_message(user_id, "Проверьте свои ответы. Выберите действие:", reply_markup=keyboard) + +# Обработчик выбора действия подтверждения +@dp.callback_query_handler(lambda query: query.data in ['send_answers', 'rewrite_answers']) +async def handle_confirmation(query: types.CallbackQuery): + user_id = query.from_user.id + if query.data == "send_answers": + await send_answers_to_group(user_id) + elif query.data == "rewrite_answers": + await rewrite_answers(user_id) + +# Функция для отправки ответов в группу +async def send_answers_to_group(user_id): + cursor.execute("SELECT * FROM answers WHERE user_id=?", (user_id,)) + answers = cursor.fetchall() + + if answers: + answer_text = '\n'.join([f"{questions[ans[1]]}: {ans[2]}" for ans in answers]) + + # Очищаем таблицу с ответами + cursor.execute("DELETE FROM answers WHERE user_id=?", (user_id,)) + conn.commit() + + # Отправляем ответы в группу + await bot.send_message(GROUP_ID, answer_text) + await bot.send_message(user_id, "Ваши ответы отправлены.") + else: + await bot.send_message(user_id, "Ответов нет") + +# Функция для переписывания ответов +async def rewrite_answers(user_id): + # Очищаем таблицу с ответами + cursor.execute("DELETE FROM answers WHERE user_id=?", (user_id,)) + conn.commit() + + await bot.send_message(user_id, "Ваши ответы удалены. Начнем сначала.") + await ask_question(user_id, 1) + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + try: + loop.create_task(dp.start_polling()) + loop.run_forever() + except KeyboardInterrupt: + pass + finally: + conn.close() diff --git a/old/logger.py b/old/logger.py new file mode 100644 index 0000000..64bf2c3 --- /dev/null +++ b/old/logger.py @@ -0,0 +1,17 @@ +import logging +import sqlite3 + +# Настройка логирования +logging.basicConfig(filename='bot.log', level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') + +def log_action(user_id, action, details=""): + logging.info(f"User ID: {user_id} - Action: {action} - Details: {details}") + + +def log_action(user_id, action): + conn = sqlite3.connect('bot_klining.db') + cursor = conn.cursor() + cursor.execute('INSERT INTO logs (user_id, action) VALUES ((SELECT id FROM users WHERE telegram_id = ?), ?)', (user_id, action)) + conn.commit() + conn.close() diff --git a/old/main(OLD).py b/old/main(OLD).py new file mode 100644 index 0000000..a62850e --- /dev/null +++ b/old/main(OLD).py @@ -0,0 +1,213 @@ +import logging +import sqlite3 +import asyncio +from aiogram import Bot, Dispatcher, types +from aiogram.contrib.middlewares.logging import LoggingMiddleware +from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton + +# Устанавливаем уровень логов +logging.basicConfig(level=logging.INFO) + +# Подключаемся к базе данных SQLite +conn = sqlite3.connect("answers.db") +cursor = conn.cursor() + +# Создание таблицы для хранения ответов +cursor.execute(""" +CREATE TABLE IF NOT EXISTS answers ( + user_id INTEGER, + question_id INTEGER, + answer TEXT +) +""") +conn.commit() + +# Заменить на свой токен +API_TOKEN = '7472030348:AAGI53nX-ON-WBmEhd_qBC6EnZsHOqp_2kE' +GROUP_ID = '-1001961537659' + +# Инициализация бота и диспетчера +bot = Bot(token=API_TOKEN) +dp = Dispatcher(bot) +dp.middleware.setup(LoggingMiddleware()) + +# Словарь для хранения вопросов и ответов +questions = { + 1: "Как вас зовут?", + 2: "Укажите номер телефона для связи", + 3: "Укажите район, улицу, дом", + 4: "Какая уборка нужна, влажная или сухая?", + 5: "На какое время?", + 6: "Оплата наличными или картой?" +} + +answer_map = { + 'wet_cleaning': 'Влажная уборка', + 'dry_cleaning': 'Сухая уборка', + 'morning_time': 'Утро', + 'day_time': 'День', + 'evening_time': 'Вечер', + 'cash_payment': 'Наличные', + 'card_payment': 'Карта' +} + +# Обработчик команды /start +@dp.message_handler(commands=['start']) +async def start(message: types.Message): + if message.chat.id != int(GROUP_ID): + await message.answer("Привет! Я задам тебе 6 вопросов. Давай начнем.") + await ask_question(message.chat.id, 1) + +# Функция для задания вопроса +async def ask_question(user_id, question_id): + if question_id in [4, 5, 6]: + if question_id == 4: + keyboard = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="Влажная", callback_data="wet_cleaning")], + [InlineKeyboardButton(text="Сухая", callback_data="dry_cleaning")] + ]) + elif question_id == 5: + keyboard = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="Утро", callback_data="morning_time")], + [InlineKeyboardButton(text="День", callback_data="day_time")], + [InlineKeyboardButton(text="Вечер", callback_data="evening_time")] + ]) + elif question_id == 6: + keyboard = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="Наличные", callback_data="cash_payment")], + [InlineKeyboardButton(text="Карта", callback_data="card_payment")] + ]) + await bot.send_message(user_id, text=questions[question_id], reply_markup=keyboard) + else: + await bot.send_message(user_id, text=questions[question_id]) + +# Обработчик текстовых ответов на первые три вопроса +@dp.message_handler(lambda message: message.text not in ["Переписать", "Отправить"]) +async def handle_text_answer(message: types.Message): + if message.chat.id != int(GROUP_ID): + user_id = message.chat.id + cursor.execute("SELECT MAX(question_id) FROM answers WHERE user_id=?", (user_id,)) + prev_question_id = cursor.fetchone()[0] + + if prev_question_id is None: + question_id = 1 + else: + question_id = prev_question_id + 1 + answer = message.text + + await save_answer(user_id, question_id, answer) + + if question_id < 6: + await ask_question(user_id, question_id + 1) + else: + await show_confirmation_options(user_id) + +# Обработчик inline-кнопок +@dp.callback_query_handler(lambda query: query.data in answer_map.keys()) +async def handle_callback_answer(query: types.CallbackQuery): + user_id = query.from_user.id + cursor.execute("SELECT MAX(question_id) FROM answers WHERE user_id=?", (user_id,)) + prev_question_id = cursor.fetchone()[0] + + if prev_question_id is None: + question_id = 1 + else: + question_id = prev_question_id + 1 + + await save_answer(user_id, question_id, answer_map[query.data]) + await query.answer() + + if question_id < 6: + await ask_question(user_id, question_id + 1) + else: + await show_confirmation_options(user_id) + +# Функция для сохранения ответа в базе данных +async def save_answer(user_id, question_id, answer): + cursor.execute("INSERT INTO answers (user_id, question_id, answer) VALUES (?, ?, ?)", (user_id, question_id, answer)) + conn.commit() + +# Функция для отображения опций подтверждения +async def show_confirmation_options(user_id): + cursor.execute("SELECT answer FROM answers WHERE user_id=? ORDER BY question_id", (user_id,)) + answers = cursor.fetchall() + answer_text = "\n".join([f"{questions[i+1]}: {answers[i][0]}" for i in range(6)]) + await bot.send_message(user_id, text=f"Ваши ответы:\n\n{answer_text}") + + keyboard = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="Отправить", callback_data="send_answers")], + [InlineKeyboardButton(text="Переписать", callback_data="rewrite_answers")] + ]) + await bot.send_message(user_id, "Проверьте свои ответы. Выберите действие:", reply_markup=keyboard) + +# Обработчик выбора действия подтверждения +@dp.callback_query_handler(lambda query: query.data in ['send_answers', 'rewrite_answers']) +async def handle_confirmation(query: types.CallbackQuery): + user_id = query.from_user.id + if query.data == "send_answers": + await send_answers_to_group(user_id) + elif query.data == "rewrite_answers": + await rewrite_answers(user_id) + +# Функция для отправки ответов в группу +async def send_answers_to_group(user_id): + cursor.execute("SELECT * FROM answers WHERE user_id=?", (user_id,)) + answers = cursor.fetchall() + + if answers: + answer_text = '\n'.join([f"{questions[ans[1]]}: {ans[2]}" for ans in answers]) + + # Очищаем таблицу с ответами + cursor.execute("DELETE FROM answers WHERE user_id=?", (user_id,)) + conn.commit() + + # Отправляем ответы в группу и добавляем ID пользователя + sent_message = await bot.send_message(GROUP_ID, f"Ответы от пользователя {user_id}:\n\n{answer_text}") + await bot.send_message(user_id, f"Ваши ответы отправлены. Можете посмотреть их [здесь](https://t.me/{sent_message.chat.username}/{sent_message.message_id})", + parse_mode='Markdown') + else: + await bot.send_message(user_id, "Ответов нет") + +# Функция для переписывания ответов +async def rewrite_answers(user_id): + # Очищаем таблицу с ответами + cursor.execute("DELETE FROM answers WHERE user_id=?", (user_id,)) + conn.commit() + + await bot.send_message(user_id, "Ваши ответы удалены. Начнем сначала.") + await ask_question(user_id, 1) + +# Функция для обработки сообщений из группы и пересылки их пользователю +@dp.message_handler(lambda message: message.chat.id == int(GROUP_ID) and message.reply_to_message) +async def handle_group_reply(message: types.Message): + # Проверяем, что сообщение является ответом на сообщение бота + if message.reply_to_message.from_user.id == bot.id: + # Извлекаем ID пользователя из текста сообщения + try: + user_id = int(message.reply_to_message.text.split()[2].strip(':')) + await bot.send_message(user_id, f"Сообщение от администратора:\n\n{message.text}") + # Сохраняем ответ пользователя для пересылки обратно в группу + cursor.execute("INSERT INTO admin_user_conversation (user_id, admin_message_id) VALUES (?, ?)", + (user_id, message.message_id)) + conn.commit() + except (IndexError, ValueError): + await message.reply("Не удалось определить ID пользователя для ответа.") + +# Обработчик сообщений от пользователя в ответ на администратора +@dp.message_handler(lambda message: message.chat.id != int(GROUP_ID)) +async def handle_user_reply(message: types.Message): + user_id = message.chat.id + cursor.execute("SELECT admin_message_id FROM admin_user_conversation WHERE user_id=? ORDER BY admin_message_id DESC LIMIT 1", (user_id,)) + admin_message_id = cursor.fetchone() + if admin_message_id: + await bot.send_message(GROUP_ID, f"Сообщение от пользователя {user_id}:\n\n{message.text}", reply_to_message_id=admin_message_id[0]) + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + try: + loop.create_task(dp.start_polling()) + loop.run_forever() + except KeyboardInterrupt: + pass + finally: + conn.close() diff --git a/old/main.py b/old/main.py new file mode 100644 index 0000000..15412d1 --- /dev/null +++ b/old/main.py @@ -0,0 +1,221 @@ +import logging +import sqlite3 +import asyncio +from aiogram import Bot, Dispatcher, types +from aiogram.contrib.middlewares.logging import LoggingMiddleware +from aiogram.dispatcher.filters import Command +from aiogram.dispatcher import FSMContext +from aiogram.dispatcher.filters.state import State, StatesGroup +from aiogram.types import ReplyKeyboardMarkup, KeyboardButton, InlineKeyboardMarkup, InlineKeyboardButton + +# Устанавливаем уровень логов +logging.basicConfig(level=logging.INFO) + +# Подключаемся к базе данных SQLite +conn = sqlite3.connect("answers.db") +cursor = conn.cursor() + +# Создание таблицы для хранения ответов +cursor.execute(""" +CREATE TABLE IF NOT EXISTS answers ( + user_id INTEGER, + question_id INTEGER, + answer TEXT +) +""") +conn.commit() + +# Заменить на свой токен +API_TOKEN = '7472030348:AAGI53nX-ON-WBmEhd_qBC6EnZsHOqp_2kE' +GROUP_ID = '-1001961537659' + +# Инициализация бота и диспетчера +bot = Bot(token=API_TOKEN) +dp = Dispatcher(bot) +dp.middleware.setup(LoggingMiddleware()) + +# Словарь для хранения вопросов и ответов +questions = { + 1: "Как вас зовут?", + 2: "Укажите номер телефона для связи", + 3: "Укажите район, улицу, дом", + 4: "Какая уборка нужна, влажная или сухая?", + 5: "На какое время?", + 6: "Оплата наличными или картой?" +} + +answer_map = { + 'wet_cleaning': 'Влажная уборка', + 'dry_cleaning': 'Сухая уборка', + 'morning_time': 'Утро', + 'day_time': 'День', + 'evening_time': 'Вечер', + 'cash_payment': 'Наличные', + 'card_payment': 'Карта' +} + +# Обработчик команды /start +@dp.message_handler(commands=['start']) +async def start(message: types.Message): + if message.chat.id != int(GROUP_ID): + await message.answer("Привет! Я задам тебе 6 вопросов Чтобы создать заказ. Давай начнем.") + await ask_question(message.chat.id, 1) + +@dp.message_handler(Command("start")) +async def show_menu(message: types.Message): + await message.reply("Выбери действие:", reply_markup=ReplyKeyboardMarkup( + resize_keyboard=True).add(KeyboardButton("Создать заказ"))) + +# Функция для задания вопроса +async def ask_question(user_id, question_id): + if question_id in [4, 5, 6]: + if question_id == 4: + keyboard = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="Влажная", callback_data="wet_cleaning")], + [InlineKeyboardButton(text="Сухая", callback_data="dry_cleaning")] + ]) + elif question_id == 5: + keyboard = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="Утро", callback_data="morning_time")], + [InlineKeyboardButton(text="День", callback_data="day_time")], + [InlineKeyboardButton(text="Вечер", callback_data="evening_time")] + ]) + elif question_id == 6: + keyboard = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="Наличные", callback_data="cash_payment")], + [InlineKeyboardButton(text="Карта", callback_data="card_payment")] + ]) + await bot.send_message(user_id, text=questions[question_id], reply_markup=keyboard) + else: + await bot.send_message(user_id, text=questions[question_id]) + +# Обработчик текстовых ответов на первые три вопроса +@dp.message_handler(lambda message: message.text not in ["Переписать", "Отправить"]) +async def handle_text_answer(message: types.Message): + if message.chat.id != int(GROUP_ID): + user_id = message.chat.id + cursor.execute("SELECT MAX(question_id) FROM answers WHERE user_id=?", (user_id,)) + prev_question_id = cursor.fetchone()[0] + + if prev_question_id is None: + question_id = 1 + else: + question_id = prev_question_id + 1 + answer = message.text + + await save_answer(user_id, question_id, answer) + + if question_id < 6: + await ask_question(user_id, question_id + 1) + else: + await show_confirmation_options(user_id) + +# Обработчик inline-кнопок +@dp.callback_query_handler(lambda query: query.data in answer_map.keys()) +async def handle_callback_answer(query: types.CallbackQuery): + user_id = query.from_user.id + cursor.execute("SELECT MAX(question_id) FROM answers WHERE user_id=?", (user_id,)) + prev_question_id = cursor.fetchone()[0] + + if prev_question_id is None: + question_id = 1 + else: + question_id = prev_question_id + 1 + + await save_answer(user_id, question_id, answer_map[query.data]) + await query.answer() + + if question_id < 6: + await ask_question(user_id, question_id + 1) + else: + await show_confirmation_options(user_id) + +# Функция для сохранения ответа в базе данных +async def save_answer(user_id, question_id, answer): + cursor.execute("INSERT INTO answers (user_id, question_id, answer) VALUES (?, ?, ?)", (user_id, question_id, answer)) + conn.commit() + +# Функция для отображения опций подтверждения +async def show_confirmation_options(user_id): + cursor.execute("SELECT answer FROM answers WHERE user_id=? ORDER BY question_id", (user_id,)) + answers = cursor.fetchall() + answer_text = "\n".join([f"{questions[i+1]}: {answers[i][0]}" for i in range(6)]) + await bot.send_message(user_id, text=f"Ваши ответы:\n\n{answer_text}") + + keyboard = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="Отправить", callback_data="send_answers")], + [InlineKeyboardButton(text="Переписать", callback_data="rewrite_answers")] + ]) + await bot.send_message(user_id, "Проверьте свои ответы. Выберите действие:", reply_markup=keyboard) + +# Обработчик выбора действия подтверждения +@dp.callback_query_handler(lambda query: query.data in ['send_answers', 'rewrite_answers']) +async def handle_confirmation(query: types.CallbackQuery): + user_id = query.from_user.id + if query.data == "send_answers": + await send_answers_to_group(user_id) + elif query.data == "rewrite_answers": + await rewrite_answers(user_id) + +# Функция для отправки ответов в группу +async def send_answers_to_group(user_id): + cursor.execute("SELECT * FROM answers WHERE user_id=?", (user_id,)) + answers = cursor.fetchall() + + if answers: + answer_text = '\n'.join([f"{questions[ans[1]]}: {ans[2]}" for ans in answers]) + + # Очищаем таблицу с ответами + cursor.execute("DELETE FROM answers WHERE user_id=?", (user_id,)) + conn.commit() + + # Отправляем ответы в группу и добавляем ID пользователя + sent_message = await bot.send_message(GROUP_ID, f"Ответы от пользователя {user_id}:\n\n{answer_text}") + await bot.send_message(user_id, f"Ваши ответы отправлены. Оператор с вами свяжится)", + parse_mode='Markdown') + else: + await bot.send_message(user_id, "Ответов нет") + +# Функция для переписывания ответов +async def rewrite_answers(user_id): + # Очищаем таблицу с ответами + cursor.execute("DELETE FROM answers WHERE user_id=?", (user_id,)) + conn.commit() + + await bot.send_message(user_id, "Ваши ответы удалены. Начнем сначала.") + await ask_question(user_id, 1) + +# Функция для обработки сообщений из группы и пересылки их пользователю +@dp.message_handler(lambda message: message.chat.id == int(GROUP_ID) and message.reply_to_message) +async def handle_group_reply(message: types.Message): + # Проверяем, что сообщение является ответом на сообщение бота + if message.reply_to_message.from_user.id == bot.id: + # Извлекаем ID пользователя из текста сообщения + try: + user_id = int(message.reply_to_message.text.split()[2].strip(':')) + await bot.send_message(user_id, f"Сообщение от администратора:\n\n{message.text}") + # Сохраняем ответ пользователя для пересылки обратно в группу + cursor.execute("INSERT INTO admin_user_conversation (user_id, admin_message_id) VALUES (?, ?)", + (user_id, message.message_id)) + conn.commit() + except (IndexError, ValueError): + await message.reply("Не удалось определить ID пользователя для ответа.") + +# Обработчик сообщений от пользователя в ответ на администратора +@dp.message_handler(lambda message: message.chat.id != int(GROUP_ID)) +async def handle_user_reply(message: types.Message): + user_id = message.chat.id + cursor.execute("SELECT admin_message_id FROM admin_user_conversation WHERE user_id=? ORDER BY admin_message_id DESC LIMIT 1", (user_id,)) + admin_message_id = cursor.fetchone() + if admin_message_id: + await bot.send_message(GROUP_ID, f"Сообщение от пользователя {user_id}:\n\n{message.text}", reply_to_message_id=admin_message_id[0]) + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + try: + loop.create_task(dp.start_polling()) + loop.run_forever() + except KeyboardInterrupt: + pass + finally: + conn.close() diff --git a/old/remain.py b/old/remain.py new file mode 100644 index 0000000..f73befe --- /dev/null +++ b/old/remain.py @@ -0,0 +1,76 @@ +import logging +from aiogram import Bot, Dispatcher, types +from aiogram.contrib.middlewares.logging import LoggingMiddleware +from aiogram.dispatcher import FSMContext +from aiogram.dispatcher.filters import Command +from aiogram.dispatcher.filters.state import State, StatesGroup +from aiogram.types import ReplyKeyboardMarkup, KeyboardButton, InlineKeyboardMarkup, InlineKeyboardButton + +API_TOKEN = '7472030348:AAGI53nX-ON-WBmEhd_qBC6EnZsHOqp_2kE' +GROUP_ID = '-1001961537659' + +logging.basicConfig(level=logging.INFO) + +bot = Bot(token=API_TOKEN) +dp = Dispatcher(bot) +dp.middleware.setup(LoggingMiddleware()) + +# Define states +class OrderForm(StatesGroup): + question_1 = State() + question_2 = State() + question_3 = State() + question_4 = State() + question_5 = State() + question_6 = State() + +@dp.message_handler(Command("start")) +async def cmd_start(message: types.Message): + await message.reply("Привет! Чтобы создать заказ, нажми на кнопку 'Создать заказ' внизу.", reply_markup=ReplyKeyboardMarkup( + resize_keyboard=True).add(KeyboardButton("Создать заказ"))) + +@dp.message_handler(Command("menu")) +async def show_menu(message: types.Message): + await message.reply("Выбери действие:", reply_markup=ReplyKeyboardMarkup( + resize_keyboard=True).add(KeyboardButton("Создать заказ"))) + +@dp.message_handler(Command("create_order")) +async def cmd_create_order(message: types.Message): + await OrderForm.question_1.set() + await message.reply("Ответьте на первый вопрос:") + +@dp.message_handler(state=OrderForm.question_1) +async def process_question_1(message: types.Message, state: FSMContext): + async with state.proxy() as data: + data['question_1'] = message.text + await OrderForm.next() + await message.reply("Ответьте на второй вопрос:") + +# Аналогично для остальных вопросов + +@dp.message_handler(state=OrderForm.question_6) +async def process_question_6(message: types.Message, state: FSMContext): + async with state.proxy() as data: + data['question_6'] = message.text + await message.reply("Отлично! Ваши ответы:") + async with state.proxy() as data: + for key, value in data.items(): + await message.reply(f"{key}: {value}") + + # Предложить отправить или переписать ответы + keyboard = InlineKeyboardMarkup().add(InlineKeyboardButton("Отправить", callback_data="send_order")).add(InlineKeyboardButton("Переписать", callback_data="rewrite_order")) + await message.reply("Хотите отправить эти ответы или переписать?", reply_markup=keyboard) + +@dp.callback_query_handler(text="send_order", state="*") +async def send_order(callback_query: types.CallbackQuery, state: FSMContext): + async with state.proxy() as data: + for key, value in data.items(): + await bot.send_message(callback_query.from_user.id, f"{key}: {value}") + +@dp.callback_query_handler(text="rewrite_order", state="*") +async def rewrite_order(callback_query: types.CallbackQuery): + await cmd_create_order(callback_query.message) + +if __name__ == '__main__': + from aiogram import executor + executor.start_polling(dp, skip_updates=True)