import asyncio import os from pathlib import Path import re from aiogram import Router, Bot, F from aiogram.filters import CommandStart, Command from aiogram.types import Message, CallbackQuery, FSInputFile, InputMediaPhoto, InputMediaVideo from aiogram.exceptions import AiogramError from aiogram.fsm.state import State, StatesGroup from aiogram.fsm.context import FSMContext from sqlalchemy import select, insert from loguru import logger from filters import IsAdmin from keyboards import create_inline_kb, commands, button_create from database import async_session_, Order, Worker orders_router = Router() # orders_router.message.filter() order_operation_base = {"add_order_photo": "Добавить фото", "get_order_photo": "Получить фото", "get_order_components": "Получить список комплектующих", "get_order_documentation": "Получить документацию" } order_operation_update = {"add_order_documentation": "Добавить документацию"} order_main = {"find_orders": "Найти заказ"} order_main_update = {"create_order": "Создать заказ"} find_order_params = {"search_by_name": "Поиск по названию", "search_by_description": "Поиск по описанию ", "search_by_id": "Поиск по номеру заказа", "search_by_customer": "Поиск по заказчику"} class SearchForm(StatesGroup): search_option = State() data_to_search = State() search_result = State() class OrderForm(StatesGroup): id = State() worker_id = State() status_id = State() counterparty = State() customer = State() commencement_work = State() end_work = State() description = State() @orders_router.message(Command(commands="orders")) async def orders_menu(message: Message): order_main_upd = order_main_update if await IsAdmin()(message) else {} await message.answer(text="Доступные действия с заказами:", reply_markup=create_inline_kb(width=1, **order_main, **order_main_upd)) @orders_router.callback_query(lambda x: x.data.startswith("create_order")) async def get_order_worker_id(callback: CallbackQuery, state: FSMContext): await state.set_state(OrderForm.worker_id) await callback.message.answer("Введите id сборщика который будет собирать заказ:", reply_markup=create_inline_kb(**{f"{callback.from_user.id}": "Ввести мой id"})) await callback.message.delete() @orders_router.callback_query(OrderForm.worker_id) async def get_order_counterparty(message: Message | CallbackQuery, state: FSMContext): if isinstance(message, Message): worker_id = int(message.text) msg = message else: worker_id = int(message.data) msg = message.message await msg.answer("Введите данные заказчика ") await msg.delete() await state.update_data(worker_id=worker_id) await state.set_state(OrderForm.customer) # @orders_router.callback_query(OrderForm.counterparty) # async def get_order_customer(message: Message, state: FSMContext): # @orders_router.message(OrderForm.customer) async def create_order(message: Message, state: FSMContext): await message.answer("Введите описание заказа в виде ключевых слов (АВР, ПСС, НКУ и т.д.) )") await state.update_data(customer=message.text) await state.set_state(OrderForm.description) @orders_router.message(OrderForm.description) async def create_order(message: Message, state: FSMContext): await state.update_data(description=message.text) order_ = await state.get_data() async with async_session_() as session: async with session.begin(): session.add(Order(**order_)) await state.clear() await message.answer("Заказ успешно создан ") @orders_router.callback_query(lambda x: x.data == "find_orders") async def find_orders_menu(callback: CallbackQuery, state: FSMContext): await callback.message.edit_text(text="Выберите параметры поиска:") await callback.message.edit_reply_markup(reply_markup=create_inline_kb(width=1, **find_order_params)) await state.set_state(SearchForm.search_option) @orders_router.callback_query(SearchForm.search_option) async def search_by_item(callback: CallbackQuery, state: FSMContext): search_option = re.search(r"^search_by_(\w+)", callback.data).group(1) await state.update_data(search_option=search_option) await state.set_state(SearchForm.data_to_search) await callback.message.answer(text="🔍 Введите данные для поиска") await callback.message.delete() @orders_router.message(SearchForm.data_to_search) async def search_by_item(message: Message, state: FSMContext): async with async_session_() as local_session: search_opt = await state.get_value("search_option") col = getattr(Order, search_opt) await message.answer(message.text) result = await local_session.execute( select(Order).where(col.ilike(f"%{message.text}%") if search_opt != "id" else col == int(message.text))) selected_orders = result.scalars().all() if selected_orders: await message.answer(text="Список заказов", reply_markup=create_inline_kb(width=1, **dict( (f"show_order_{order.id}", order.description or "Отсутствует") for order in selected_orders))) await state.update_data(search_result=selected_orders) await state.set_state(SearchForm.search_result) else: await message.answer(text="Заказов по вашему запросу не найдено") await state.clear() @orders_router.callback_query(SearchForm.search_result) async def show_order(callback: CallbackQuery, state: FSMContext): order_id = int(re.search(r"(\d+)", callback.data).group()) try: async with async_session_() as local_session: result = await local_session.execute(select(Order).filter(Order.id == order_id)) order = result.scalars().first() except Exception as err: logger.warning(err) order_operation_upd = order_operation_update if await IsAdmin()(callback) else {} if order: await callback.message.answer(text=f"Номер заказа: {order.id}\n" f"Заказчик: {order.customer}\n" f"Статус: {order.status_id}\n" f"Дата начала работ: {order.commencement_work}\n" f"Дата отгрузки: {order.end_work}\n" f"Дата создания: {order.created_at}\n" f"Описание: {order.description}", reply_markup=create_inline_kb(width=2, **dict( (f"{clbk}_{order.id}", text) for clbk, text in order_operation_base.items())) ) await callback.message.delete() await state.clear() @orders_router.callback_query(lambda x: x.data.startswith("get_order_photo")) async def send_order_photos(callback: CallbackQuery, bot: Bot): order_id = callback.data.split("_")[-1] media_item: Path media_group = [] os.makedirs(Path(f"./photos/{order_id}/"), exist_ok=True) media_path = Path(f"./photos/{order_id}/").iterdir() if not (media_item := next(media_path, None)): text = f"Фото по заказу \"{order_id}\" отсутствуют " else: text = (f"Заказ: №{order_id}\n" f"") await bot.send_message(chat_id=callback.from_user.id, text=text) while media_item or media_group: if len(media_group) == 10 or (media_group and not media_item): await bot.send_media_group(chat_id=callback.from_user.id, media=media_group) media_group.clear() if media_item: try: input_type = InputMediaPhoto if media_item.suffix == ".jpg" else InputMediaVideo media_group.append(input_type(media=FSInputFile(media_item))) except Exception as err: logger.error(f"Ошибка при обработке {media_path}: {err}") media_item = next(media_path, None) await asyncio.sleep(600) await callback.message.delete() @orders_router.callback_query(lambda x: x.data.startswith("add_order_photo")) async def reply_for_photo(callback: CallbackQuery, bot: Bot): await bot.send_message(text=f"Заказ: {callback.data.split("_")[-1]}\n" "Прикрепите файлы ответив на это сообщение сдвинув его влево, либо выберите 'ответить'", chat_id=callback.from_user.id) await callback.message.delete() @orders_router.message( F.reply_to_message) async def add_order_photo(message: Message, bot: Bot): order_id = re.search(r"(\d+)", message.reply_to_message.text).group() order_photos_path = f"/app/photos/{order_id}/" os.makedirs(order_photos_path, exist_ok=True) item = message.video or message.photo[-1] file_extension = "jpg" if message.photo else "mp4" try: file = await bot.get_file(item.file_id) await bot.download_file(file.file_path, destination=f"{order_photos_path}/{file.file_id}.{file_extension}", timeout=3600) await message.answer(f"Медиа файл {file.file_id[:10]} успешно прикреплен к заказу №{order_id}") except AiogramError as err: logger.error(err) await message.delete() try: await bot.delete_message(chat_id=message.chat.id, message_id=message.reply_to_message.message_id) except: pass