Не получается создать заказ в боте, после заполнения названия фирмы ничего не происходит не появляется запрос о вводе адреса клиента
Вот код который получился
import logging
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import (
Application,
CommandHandler,
CallbackQueryHandler,
ContextTypes,
ConversationHandler,
MessageHandler,
filters,
)
from datetime import datetime
import sqlite3
# Включаем логирование
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)
logger = logging.getLogger(__name__)
# Состояния диалога
(
CREATE_ORDER_NAME,
SELECT_ADDRESS,
CREATE_ORDER_ADDRESS,
SELECT_CONTACT,
CREATE_ORDER_CONTACT,
CREATE_ORDER_LOCATION,
EDIT_ORDER,
SELECT_ORDER,
CONFIRM_ORDER,
CHANGE_STATUS,
CANCEL_ORDER_REASON,
ASSIGN_ROLE_ID,
ASSIGN_ROLE_TYPE,
) = range(13)
# ID администраторов (замените на реальные ID администраторов)
ADMIN_IDS = [987654321]
# ID всех курьеров (замените на реальные ID курьеров)
COURIER_IDS = [111111111]
# Подключение к базе данных
def init_db():
conn = sqlite3.connect('courier_service.db')
cursor = conn.cursor()
# Создание таблицы пользователей
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
user_id INTEGER PRIMARY KEY,
role TEXT NOT NULL
)
''')
# Создание таблицы заказов
cursor.execute('''
CREATE TABLE IF NOT EXISTS orders (
order_id INTEGER PRIMARY KEY AUTOINCREMENT,
company_name TEXT NOT NULL,
address TEXT NOT NULL,
contact_person TEXT NOT NULL,
location TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'available',
assigned_to INTEGER,
created_at TEXT NOT NULL,
completed_at TEXT,
cancelled_reason TEXT,
FOREIGN KEY(assigned_to) REFERENCES users(user_id)
)
''')
conn.commit()
conn.close()
# Главное меню
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
user_id = update.effective_user.id
role = get_user_role(user_id)
if not role:
add_user(user_id, "courier") # По умолчанию новый пользователь считается курьером
role = "courier"
if user_id in ADMIN_IDS or role == "admin": # Меню администратора
keyboard = [
[InlineKeyboardButton("Создать заказ", callback_data="create_order")],
[InlineKeyboardButton("Просмотреть заказы", callback_data="view_orders")],
[InlineKeyboardButton("Редактировать заказ", callback_data="edit_order")],
[InlineKeyboardButton("Отменить заказ", callback_data="cancel_order")],
[InlineKeyboardButton("Назначить роль", callback_data="assign_role")],
]
else: # Меню курьера
keyboard = [
[InlineKeyboardButton("Выбрать заказ", callback_data="select_order")],
[InlineKeyboardButton("Изменить статус заказа", callback_data="change_status")],
[InlineKeyboardButton("Отменить заказ", callback_data="cancel_order")],
]
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_text('Добро пожаловать! Выберите действие:', reply_markup=reply_markup)
# Обработка выбора кнопки
async def button(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
query = update.callback_query
await query.answer()
if query.data == "create_order":
await create_order_start(query, context)
elif query.data == "view_orders":
await view_orders(query, context)
elif query.data == "select_order":
await list_orders_for_courier(query, context)
elif query.data == "change_status":
await change_status_menu(query, context)
elif query.data == "edit_order":
await edit_order_menu(query, context)
elif query.data == "cancel_order":
await cancel_order_menu(query, context)
elif query.data.startswith("assign_"):
if query.data == "assign_role": # Если нажата кнопка "Назначить роль"
await assign_role_start(query, context)
else: # Если нажата кнопка назначения заказа
await assign_order(query, context)
elif query.data.startswith("edit_"):
await edit_selected_order(query, context)
elif query.data.startswith("status_"):
await update_order_status(query, context)
elif query.data.startswith("address_"):
await save_address_from_list(query, context)
elif query.data.startswith("contact_"):
await save_contact_from_list(query, context)
elif query.data.startswith("location_"):
await save_location(query, context)
elif query.data.startswith("reason_"):
await confirm_cancel_order(query, context)
# Начало создания заказа
async def create_order_start(query: Update.callback_query, context: ContextTypes.DEFAULT_TYPE) -> int:
await query.message.reply_text("Введите название фирмы:")
return CREATE_ORDER_NAME
# Шаг 1: Сохранение названия фирмы
async def save_company_name(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
company_name = update.message.text.strip()
if not company_name:
await update.message.reply_text("Название фирмы не может быть пустым. Попробуйте снова.")
return CREATE_ORDER_NAME
context.user_data["company_name"] = company_name
# Получение последних 5 адресов для этой фирмы
addresses = get_last_addresses_for_company(company_name)
if addresses:
keyboard = [[InlineKeyboardButton(addr, callback_data=f"address_{addr}")] for addr in addresses]
keyboard.append([InlineKeyboardButton("Ввести другой адрес", callback_data="address_new")])
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_text("Выберите адрес из списка или введите новый:", reply_markup=reply_markup)
return SELECT_ADDRESS
else:
await update.message.reply_text("Введите адрес:")
return CREATE_ORDER_ADDRESS
# Шаг 2: Сохранение адреса
async def save_address(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
address = update.message.text.strip()
if not address:
await update.message.reply_text("Адрес не может быть пустым. Попробуйте снова.")
return CREATE_ORDER_ADDRESS
context.user_data["address"] = address
# Получение последних 5 контактов для этой фирмы
company_name = context.user_data["company_name"]
contacts = get_last_contacts_for_company(company_name)
if contacts:
keyboard = [[InlineKeyboardButton(contact, callback_data=f"contact_{contact}")] for contact in contacts]
keyboard.append([InlineKeyboardButton("Ввести другое контактное лицо", callback_data="contact_new")])
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_text("Выберите контактное лицо из списка или введите новое:", reply_markup=reply_markup)
return SELECT_CONTACT
else:
await update.message.reply_text("Введите контактное лицо:")
return CREATE_ORDER_CONTACT
# Шаг 3: Сохранение контактного лица
async def save_contact_person(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
contact_person = update.message.text.strip()
if not contact_person:
await update.message.reply_text("Контактное лицо не может быть пустым. Попробуйте снова.")
return CREATE_ORDER_CONTACT
context.user_data["contact_person"] = contact_person
# Предложение выбрать локацию
keyboard = [
[InlineKeyboardButton("Москва", callback_data="location_Moscow")],
[InlineKeyboardButton("Россия", callback_data="location_Russia")],
]
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_text("Выберите локацию:", reply_markup=reply_markup)
return CREATE_ORDER_LOCATION
# Шаг 4: Сохранение локации
async def save_location(query: Update.callback_query, context: ContextTypes.DEFAULT_TYPE) -> int:
location = query.data.split("_")[1]
context.user_data["location"] = location
# Сохранение заказа в базу данных
company_name = context.user_data["company_name"]
address = context.user_data["address"]
contact_person = context.user_data["contact_person"]
conn = sqlite3.connect('courier_service.db')
cursor = conn.cursor()
created_at = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
cursor.execute(
'INSERT INTO orders (company_name, address, contact_person, location, created_at) VALUES (?, ?, ?, ?, ?)',
(company_name, address, contact_person, location, created_at),
)
order_id = cursor.lastrowid # Получаем ID только что созданного заказа
conn.commit()
conn.close()
# Уведомляем всех курьеров о новом заказе
for courier_id in COURIER_IDS:
await query.bot.send_message(
chat_id=courier_id,
text=f"Новый заказ доступен!\n"
f"Фирма: {company_name}\n"
f"Адрес: {address}\n"
f"Контактное лицо: {contact_person}\n"
f"Локация: {location}",
)
await query.edit_message_text(f"Заказ №{order_id} создан:\n"
f"Фирма: {company_name}\n"
f"Адрес: {address}\n"
f"Контактное лицо: {contact_person}\n"
f"Локация: {location}")
return ConversationHandler.END
# Функция для отображения списка доступных заказов для курьера
async def list_orders_for_courier(query: Update.callback_query, context: ContextTypes.DEFAULT_TYPE) -> None:
user_id = query.from_user.id
# Получение доступных заказов для выбора (только с status = "available")
orders = get_available_orders()
if not orders:
await query.message.reply_text("Нет доступных заказов для выбора.")
return ConversationHandler.END
keyboard = []
for order in orders:
keyboard.append([InlineKeyboardButton(f"Заказ {order['order_id']}", callback_data=f"assign_{order['order_id']}")])
reply_markup = InlineKeyboardMarkup(keyboard)
await query.message.reply_text("Выберите заказ для назначения:", reply_markup=reply_markup)
# Функция для получения доступных заказов
def get_available_orders() -> list:
conn = sqlite3.connect('courier_service.db')
cursor = conn.cursor()
cursor.execute('SELECT order_id, company_name, address FROM orders WHERE status = ?', ('available',))
rows = cursor.fetchall()
conn.close()
return [{"order_id": row[0], "company_name": row[1], "address": row[2]} for row in rows]
# Функция для назначения заказа курьеру
async def assign_order(query: Update.callback_query, context: ContextTypes.DEFAULT_TYPE) -> None:
try:
order_id = int(query.data.split("_")[1]) # Извлекаем ID заказа
except ValueError:
await query.edit_message_text("Произошла ошибка при назначении заказа.")
return
user_id = query.from_user.id
# Проверяем, доступен ли заказ для назначения
if not is_order_available(order_id):
await query.edit_message_text("Этот заказ уже назначен или выполнен.")
return
# Назначаем заказ курьеру
assign_order_to_courier(order_id, user_id)
await query.edit_message_text(f"Вы взяли заказ №{order_id}.")
# Проверка, доступен ли заказ для назначения
def is_order_available(order_id: int) -> bool:
conn = sqlite3.connect('courier_service.db')
cursor = conn.cursor()
cursor.execute('SELECT status FROM orders WHERE order_id = ?', (order_id,))
result = cursor.fetchone()
conn.close()
return result and result[0] == "available"
# Назначение заказа курьеру
def assign_order_to_courier(order_id: int, user_id: int):
conn = sqlite3.connect('courier_service.db')
cursor = conn.cursor()
cursor.execute(
'UPDATE orders SET status = ?, assigned_to = ? WHERE order_id = ?', ('assigned', user_id, order_id)
)
conn.commit()
conn.close()
# Отмена действия
async def cancel(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
await update.message.reply_text("Действие отменено. Вы можете вернуться в главное меню, нажав /start.")
return ConversationHandler.END
# Базовые функции для работы с базой данных
def add_user(user_id: int, role: str):
conn = sqlite3.connect('courier_service.db')
cursor = conn.cursor()
cursor.execute('INSERT OR IGNORE INTO users (user_id, role) VALUES (?, ?)', (user_id, role))
conn.commit()
conn.close()
def get_user_role(user_id: int) -> str:
conn = sqlite3.connect('courier_service.db')
cursor = conn.cursor()
cursor.execute('SELECT role FROM users WHERE user_id = ?', (user_id,))
result = cursor.fetchone()
conn.close()
return result[0] if result else None
# Функции для получения заказов
def get_all_orders() -> list:
conn = sqlite3.connect('courier_service.db')
cursor = conn.cursor()
cursor.execute('SELECT order_id, company_name, status FROM orders WHERE status != ?', ('completed',))
rows = cursor.fetchall()
conn.close()
return [{"order_id": row[0], "company_name": row[1], "status": row[2]} for row in rows]
def get_orders_for_courier(user_id: int) -> list:
conn = sqlite3.connect('courier_service.db')
cursor = conn.cursor()
cursor.execute('SELECT order_id, company_name, status FROM orders WHERE assigned_to = ? AND status != ?', (user_id, 'completed'))
rows = cursor.fetchall()
conn.close()
return [{"order_id": row[0], "company_name": row[1], "status": row[2]} for row in rows]
# Функции для получения последних адресов и контактов
def get_last_addresses_for_company(company_name: str) -> list:
conn = sqlite3.connect('courier_service.db')
cursor = conn.cursor()
cursor.execute('SELECT DISTINCT address FROM orders WHERE company_name = ? ORDER BY created_at DESC LIMIT 5', (company_name,))
rows = cursor.fetchall()
conn.close()
return [row[0] for row in rows]
def get_last_contacts_for_company(company_name: str) -> list:
conn = sqlite3.connect('courier_service.db')
cursor = conn.cursor()
cursor.execute('SELECT DISTINCT contact_person FROM orders WHERE company_name = ? ORDER BY created_at DESC LIMIT 5', (company_name,))
rows = cursor.fetchall()
conn.close()
return [row[0] for row in rows]
# Функция для выбора заказа для редактирования
async def edit_order_menu(query: Update.callback_query, context: ContextTypes.DEFAULT_TYPE) -> int:
# Получение доступных заказов для редактирования (все заказы, кроме завершенных)
orders = get_all_orders()
if not orders:
await query.message.reply_text("Нет заказов для редактирования.")
return ConversationHandler.END
keyboard = []
for order in orders:
keyboard.append([InlineKeyboardButton(f"Заказ {order['order_id']}", callback_data=f"edit_{order['order_id']}")])
reply_markup = InlineKeyboardMarkup(keyboard)
await query.message.reply_text("Выберите заказ для редактирования:", reply_markup=reply_markup)
return EDIT_ORDER
# Редактирование выбранного заказа
async def edit_selected_order(query: Update.callback_query, context: ContextTypes.DEFAULT_TYPE) -> int:
order_id = int(query.data.split("_")[1])
context.user_data["editing_order_id"] = order_id
await query.message.reply_text("Введите новое описание заказа:")
return EDIT_ORDER
# Сохранение изменений заказа
async def save_edited_order(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
new_description = update.message.text.strip()
if not new_description:
await update.message.reply_text("Описание заказа не может быть пустым. Попробуйте снова.")
return EDIT_ORDER
order_id = context.user_data.get("editing_order_id")
if order_id:
edit_order(order_id, new_description)
await update.message.reply_text(f"Заказ №{order_id} успешно отредактирован. Новое описание: {new_description}")
else:
await update.message.reply_text("Произошла ошибка при редактировании заказа.")
return ConversationHandler.END
# Функция для редактирования заказа в базе данных
def edit_order(order_id: int, new_description: str):
conn = sqlite3.connect('courier_service.db')
cursor = conn.cursor()
cursor.execute('UPDATE orders SET description = ? WHERE order_id = ?', (new_description, order_id))
conn.commit()
conn.close()
# Главная функция
def main() -> None:
init_db()
# Замените 'YOUR_TOKEN' на токен вашего бота
application = Application.builder().token("YOUR_TOKEN").build()
# Добавление обработчиков
conv_handler = ConversationHandler(
entry_points=[CommandHandler("start", start)],
states={
CREATE_ORDER_NAME: [MessageHandler(filters.TEXT & ~filters.COMMAND, save_company_name)],
SELECT_ADDRESS: [CallbackQueryHandler(save_address_from_list)],
CREATE_ORDER_ADDRESS: [MessageHandler(filters.TEXT & ~filters.COMMAND, save_address)],
SELECT_CONTACT: [CallbackQueryHandler(save_contact_from_list)],
CREATE_ORDER_CONTACT: [MessageHandler(filters.TEXT & ~filters.COMMAND, save_contact_person)],
CREATE_ORDER_LOCATION: [CallbackQueryHandler(save_location)],
CANCEL_ORDER_REASON: [
CallbackQueryHandler(select_cancel_reason),
MessageHandler(filters.TEXT & ~filters.COMMAND, save_custom_reason),
],
EDIT_ORDER: [
CallbackQueryHandler(edit_selected_order),
MessageHandler(filters.TEXT & ~filters.COMMAND, save_edited_order),
],
ASSIGN_ROLE_ID: [MessageHandler(filters.TEXT & ~filters.COMMAND, save_user_id)],
ASSIGN_ROLE_TYPE: [MessageHandler(filters.TEXT & ~filters.COMMAND, save_user_role)],
},
fallbacks=[CommandHandler("cancel", cancel)],
)
application.add_handler(conv_handler)
application.add_handler(CallbackQueryHandler(button))
# Запуск бота
application.run_polling()
if __name__ == "__main__":
main()