/
ValeriaEr
/
bot
Обзор
Документация
Войти
/
ValeriaEr
/
bot
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
bots.py
369 строк
15 KB
ValeriaEr
update bots.py
11 дек 2025, 16:12
11 дек 2025, 16:12
a26b65d
Код
Авторство
О чём код?
import logging import re import time from typing import Dict, List, Optional, Any from database.models import Category, Product, Order, User from services.yandex_images import YandexImagesAPI from services.order_service import OrderService from keyboards import ( get_main_menu, get_category_menu, get_product_menu, get_order_menu ) # Импортируем конфигурацию from config import STORE_NAME, STORE_ADDRESS, WORK_HOURS logger = logging.getLogger(__name__) class IStoreBotCore: def __init__(self): self.yandex_images = YandexImagesAPI() self.current_state = {} def process_start(self, user_id: int, platform: str) -> Dict: user, created = User.get_or_create( user_id=user_id, platform=platform, defaults={'username': f'user_{user_id}'} ) welcome_message = ( f"🏪 *Добро пожаловать в {STORE_NAME}!*\n\n" f"Официальный магазин Apple в вашем городе.\n" f"📍 {STORE_ADDRESS}\n" f"🕐 {WORK_HOURS}\n\n" f"Выберите категорию товаров или ознакомьтесь с нашим магазином:" ) return { 'text': welcome_message, 'keyboard': get_main_menu(), 'parse_mode': 'Markdown' } def get_categories(self) -> List[Category]: categories = Category.select().where(Category.is_active == True) return list(categories) def show_category(self, category_id: int, user_id: int) -> Dict: try: category = Category.get(Category.id == category_id) products = Product.select().where( Product.category == category, Product.stock > 0, Product.is_active == True ).limit(20) self.current_state[user_id] = { 'category_id': category_id, 'product_index': 0 } if not products: return { 'text': f"📦 В категории '{category.name}' пока нет товаров", 'keyboard': get_main_menu() } return self.show_product(category_id, 0, user_id) except Category.DoesNotExist: return { 'text': "❌ Категория не найдена", 'keyboard': get_main_menu() } def show_product(self, category_id: int, product_index: int, user_id: int) -> Dict: try: category = Category.get(Category.id == category_id) products = list(Product.select().where( Product.category == category, Product.stock > 0 )) if not products: return { 'text': "📭 В этой категории товаров нет", 'keyboard': get_main_menu() } product = products[product_index % len(products)] message = f"{category.icon} *{product.name}*\n\n" message += f"💰 Цена: {product.price}₽\n" message += f"📦 В наличии: {product.stock} шт.\n\n" if product.description: message += f"📝 {product.description}\n\n" message += f"Товар {product_index + 1} из {len(products)}" self.current_state[user_id].update({ 'current_product_id': product.id, 'current_product_name': product.name, 'current_product_price': str(product.price), 'product_index': product_index }) image_url = None if product.image_url: image_url = product.image_url elif hasattr(product, 'image_path') and product.image_path: image_url = product.get_image_url() else: images = self.yandex_images.find_product_images( product.name, category.name ) if images: image_url = images[0]['url'] product.image_url = image_url product.save() return { 'text': message, 'image_url': image_url, 'keyboard': get_product_menu(len(products), product_index), 'parse_mode': 'Markdown' } except Exception as e: logger.error(f"Ошибка показа товара: {e}") return { 'text': "❌ Ошибка при загрузке товара", 'keyboard': get_main_menu() } def next_product(self, user_id: int) -> Dict: if user_id not in self.current_state: return self.process_start(user_id, 'telegram') state = self.current_state[user_id] category_id = state.get('category_id') product_index = state.get('product_index', 0) products_count = Product.select().where( Product.category_id == category_id, Product.stock > 0 ).count() if product_index + 1 < products_count: new_index = product_index + 1 else: new_index = 0 return self.show_product(category_id, new_index, user_id) def start_order(self, user_id: int) -> Dict: if user_id not in self.current_state: return { 'text': "❌ Сначала выберите товар", 'keyboard': get_main_menu() } state = self.current_state[user_id] product_id = state.get('current_product_id') if not product_id: return { 'text': "❌ Товар не выбран", 'keyboard': get_main_menu() } try: product = Product.get(Product.id == product_id) if product.stock <= 0: return { 'text': "😔 Извините, этот товар закончился", 'keyboard': get_category_menu(product.category_id) } message = ( f"🛒 *Оформление заказа*\n\n" f"Товар: {product.name}\n" f"Цена: {product.price}₽\n\n" f"Для оформления заказа введите ваше имя:" ) self.current_state[user_id]['order_step'] = 'waiting_name' return { 'text': message, 'keyboard': {'inline_keyboard': [[ {'text': '❌ Отменить', 'callback_data': 'cancel_order'} ]]}, 'parse_mode': 'Markdown' } except Product.DoesNotExist: return { 'text': "❌ Товар не найден", 'keyboard': get_main_menu() } def process_order_step(self, user_id: int, text: str) -> Dict: if user_id not in self.current_state: return { 'text': "❌ Сессия истекла, начните заново", 'keyboard': get_main_menu() } state = self.current_state[user_id] step = state.get('order_step') if step == 'waiting_name': if len(text) < 2: return { 'text': "❌ Имя слишком короткое. Введите ваше имя:", 'keyboard': {'inline_keyboard': [[ {'text': '❌ Отменить', 'callback_data': 'cancel_order'} ]]} } self.current_state[user_id]['customer_name'] = text self.current_state[user_id]['order_step'] = 'waiting_phone' return { 'text': "📱 Введите ваш телефон (в формате +7XXXXXXXXXX):", 'keyboard': {'inline_keyboard': [[ {'text': '❌ Отменить', 'callback_data': 'cancel_order'} ]]} } elif step == 'waiting_phone': phone_pattern = r'^(\+7|8)?[\s\-]?\(?[0-9]{3}\)?[\s\-]?[0-9]{3}[\s\-]?[0-9]{2}[\s\-]?[0-9]{2}$' if not re.match(phone_pattern, text.replace(' ', '')): return { 'text': "❌ Неверный формат телефона. Введите в формате +7XXXXXXXXXX:", 'keyboard': {'inline_keyboard': [[ {'text': '❌ Отменить', 'callback_data': 'cancel_order'} ]]} } phone = text.replace(' ', '').replace('-', '').replace('(', '').replace(')', '') if phone.startswith('8'): phone = '+7' + phone[1:] elif not phone.startswith('+7'): phone = '+7' + phone self.current_state[user_id]['customer_phone'] = phone self.current_state[user_id]['order_step'] = 'waiting_email' return { 'text': "📧 Введите вашу почту (не обязательно):", 'keyboard': { 'inline_keyboard': [ [{'text': '❌ Отменить', 'callback_data': 'cancel_order'}], [{'text': '🚀 Пропустить', 'callback_data': 'skip_email'}] ] } } elif step == 'waiting_email': if text.lower() in ['пропустить', 'skip', 'нет']: email = '' else: email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' if text and not re.match(email_pattern, text): return { 'text': "❌ Неверный формат email. Введите корректный email или 'пропустить':", 'keyboard': { 'inline_keyboard': [ [{'text': '❌ Отменить', 'callback_data': 'cancel_order'}], [{'text': '🚀 Пропустить', 'callback_data': 'skip_email'}] ] } } email = text return self.finalize_order(user_id, email) def finalize_order(self, user_id: int, email: str = '') -> Dict: state = self.current_state.get(user_id, {}) required_fields = ['customer_name', 'customer_phone', 'current_product_id'] for field in required_fields: if field not in state: return { 'text': "❌ Недостаточно данных для заказа", 'keyboard': get_main_menu() } product_id = state['current_product_id'] lock_key = f"order_lock_{product_id}" if OrderService.is_locked(lock_key): return { 'text': "⏳ Система занята. Попробуйте через минуту.", 'keyboard': get_main_menu() } try: OrderService.lock(lock_key, timeout=20) product = Product.get(Product.id == product_id) if product.stock <= 0: OrderService.unlock(lock_key) return { 'text': "😔 Извините, этот товар закончился.", 'keyboard': get_category_menu(product.category_id) } product.stock -= 1 product.save() order = Order.create( customer_name=state['customer_name'], customer_phone=state['customer_phone'], customer_email=email, product_name=state['current_product_name'], product_price=state['current_product_price'], status='Новый', user_id=user_id ) success_message = ( f"✅ *Заказ оформлен!*\n\n" f"📦 Номер заказа: #{order.id}\n" f"🎯 Товар: {state['current_product_name']}\n" f"💰 Цена: {state['current_product_price']}₽\n" f"👤 Имя: {state['customer_name']}\n" f"📱 Телефон: {state['customer_phone']}\n" f"📦 Остаток на складе: {product.stock} шт.\n\n" f"⏰ Менеджер свяжется с вами в течение 15 минут.\n" f"📍 Адрес магазина: {STORE_ADDRESS}\n\n" f"Спасибо за покупку! 🛍️" ) if email: try: from services.email_service import send_order_confirmation send_order_confirmation(order, email) except ImportError: logger.warning("Email сервис не доступен") if user_id in self.current_state: del self.current_state[user_id] return { 'text': success_message, 'keyboard': get_main_menu(), 'parse_mode': 'Markdown' } except Exception as e: logger.error(f"Ошибка оформления заказа: {e}") OrderService.unlock(lock_key) return { 'text': f"❌ Ошибка при оформлении: {str(e)}", 'keyboard': get_main_menu() } finally: OrderService.unlock(lock_key)