From 1b78f2ba36c42371f9ac0f67014390bdfa69f81d Mon Sep 17 00:00:00 2001 From: hexdev Date: Thu, 13 Aug 2026 11:30:04 +0700 Subject: [PATCH] chore: clean up texts --- handlers/admins/product_mgmt.py | 90 +++++++++++++++++++++++++++++++++ handlers/client/cart.py | 3 +- handlers/client/menu.py | 2 +- handlers/client/products.py | 6 +-- misc/kb/admins.py | 3 ++ misc/states.py | 1 + repositories/products.py | 11 ++++ 7 files changed, 111 insertions(+), 5 deletions(-) diff --git a/handlers/admins/product_mgmt.py b/handlers/admins/product_mgmt.py index ec2c649..af912f9 100644 --- a/handlers/admins/product_mgmt.py +++ b/handlers/admins/product_mgmt.py @@ -13,6 +13,7 @@ from misc.kb.admins import back_to_product_kb from misc.kb.client import get_back_to_catalogue from misc.mapper import parse_cat_id from misc.states import AdminControlStorage +from misc.texts import get_product_description from misc.texts import product_editing_mapping from repositories.categories import CategoriesRepository from repositories.products import ProductRepository @@ -120,6 +121,95 @@ async def toggle_product_visibility( await cb.message.edit_reply_markup(reply_markup=admins.edit_product(product)) +@router.callback_query(IsVerified(), F.data.startswith("edit_product:"), F.data.endswith(":photo")) +async def request_product_photo(cb: CallbackQuery, state: FSMContext): + await state.clear() + + product_id = int(cb.data.split(":")[1]) + + if cb.message.photo: + await cb.message.delete() + msg = await cb.message.answer( + "📷 Отправьте фотографию товара.", + reply_markup=back_to_product_kb(product_id, cb_factory=lambda p: f"product:{p}"), + ) + else: + msg = cb.message + await cb.message.edit_text( + "📷 Отправьте фотографию товара.", + reply_markup=back_to_product_kb(product_id, cb_factory=lambda p: f"product:{p}"), + ) + + await state.set_state(AdminControlStorage.edit_product_photo) + await state.set_data({"ctx": EditProductContext(product_id, "photo", msg)}) + + +@router.message(AdminControlStorage.edit_product_photo) +async def upload_product_photo( + msg: Message, + state: FSMContext, + session: AsyncSession, + products_repo: ProductRepository, +): + data = await state.get_data() + ctx: EditProductContext = data.get("ctx", EditProductContext) + kb = back_to_product_kb(ctx.product_id, cb_factory=lambda p: f"product:{p}") + + if not msg.photo: + await msg.delete() + await ctx.msg.edit_text("❌ Отправьте именно фотографию.", reply_markup=kb) + await state.set_state(AdminControlStorage.edit_product_photo) + await state.set_data({"ctx": ctx}) + return + + await state.clear() + await msg.delete() + + try: + await ctx.msg.edit_text("⏳") + await products_repo.add_product_file_id( + session, ctx.product_id, file_id=msg.photo[-1].file_id + ) + await ctx.msg.edit_text("✅ Фотография обновлена.", reply_markup=kb) + except Exception as e: + logger.exception(e) + await ctx.msg.edit_text("‼️ Что-то пошло не так.", reply_markup=kb) + + +@router.callback_query( + IsVerified(), F.data.startswith("edit_product:"), F.data.endswith(":delete_photo") +) +async def delete_product_photo( + cb: CallbackQuery, + state: FSMContext, + session: AsyncSession, + products_repo: ProductRepository, +): + await state.clear() + + product_id = int(cb.data.split(":")[1]) + product = await products_repo.clear_product_photo(session, product_id) + if not product: + await cb.answer("Товар не найден.", show_alert=True) + return + + await cb.answer("Фото удалено.") + + text = get_product_description(product) + reply_markup = admins.edit_product(product) + + if cb.message.photo: + await cb.message.delete() + await cb.message.answer(text, reply_markup=reply_markup) + return + + if cb.message.caption: + await cb.message.edit_text(text, reply_markup=reply_markup) + return + + await cb.message.edit_reply_markup(reply_markup=reply_markup) + + @router.callback_query(F.data.startswith("edit:")) async def edit_entry(cb: CallbackQuery, state: FSMContext): await state.clear() diff --git a/handlers/client/cart.py b/handlers/client/cart.py index ae6a1fa..4d4e1d9 100644 --- a/handlers/client/cart.py +++ b/handlers/client/cart.py @@ -53,7 +53,8 @@ async def cart_cmd( return await msg.answer( - f"total: {cart.total}₽", + "🌸 Убедитесь в том, что все желаемые позиции есть в заказе ниже!\n\n" + f"Сумма: {cart.total}₽", reply_markup=render_cart( cart.items[:PAGE_SIZE], show_next=len(cart.items) > PAGE_SIZE, diff --git a/handlers/client/menu.py b/handlers/client/menu.py index 3de67d9..81aef7c 100644 --- a/handlers/client/menu.py +++ b/handlers/client/menu.py @@ -6,7 +6,7 @@ from aiogram.fsm.context import FSMContext from aiogram.types import CallbackQuery, Message from sqlalchemy.ext.asyncio import AsyncSession -from misc.kb import main_menu_kb +from misc.kb.client import main_menu_kb from repositories.order_items import OrderItemRepository from services.orders import OrderService diff --git a/handlers/client/products.py b/handlers/client/products.py index cbcfd70..2201b78 100644 --- a/handlers/client/products.py +++ b/handlers/client/products.py @@ -64,7 +64,7 @@ async def product_card( product = await products_repo.get_product_by_id(session, product_id, include_hidden=is_admin) if not product: - await cb.answer("Товар недоступен.", show_alert=True) + await cb.answer("❌ Товар недоступен.", show_alert=True) return if is_admin: @@ -108,7 +108,7 @@ async def product_card( if not msg.photo: logger.warning("didnt get a photo back wahhh :(") - return # TODO: Add logging + return await products_repo.add_product_file_id(session, product_id, file_id=msg.photo[-1].file_id) @@ -129,7 +129,7 @@ async def cart_action( product = await products_repo.get_product_by_id(session, product_id, include_hidden=is_admin) if not product: - await cb.answer("Товар недоступен.", show_alert=True) + await cb.answer("❌ Товар недоступен.", show_alert=True) return show_cart = True diff --git a/misc/kb/admins.py b/misc/kb/admins.py index 76a8b1c..fb8ebb7 100644 --- a/misc/kb/admins.py +++ b/misc/kb/admins.py @@ -58,6 +58,8 @@ def edit_product(product: Product): product_id = product.id prefix = f"edit_product:{product_id}" visibility_btn = "🙈 Скрыт" if product.is_hidden else "👁️ Видим" + photo_btn = "🗑️ Удалить фото" if product.file_id or product.img_path else "📷 Добавить фото" + photo_action = "delete_photo" if product.file_id or product.img_path else "photo" return InlineKeyboardBuilder( [ @@ -69,6 +71,7 @@ def edit_product(product: Product): ), ], [InlineKeyboardButton(text="💸 Цена", callback_data=f"{prefix}:price")], + [InlineKeyboardButton(text=photo_btn, callback_data=f"{prefix}:{photo_action}")], [ InlineKeyboardButton(text=visibility_btn, callback_data=f"{prefix}:hide"), InlineKeyboardButton(text="❌", callback_data=f"{prefix}:delete"), diff --git a/misc/states.py b/misc/states.py index b5f324e..a3810fc 100644 --- a/misc/states.py +++ b/misc/states.py @@ -18,5 +18,6 @@ class SearchStorage(StatesGroup): class AdminControlStorage(StatesGroup): edit_product = State() + edit_product_photo = State() edit_category = State() new_category = State() diff --git a/repositories/products.py b/repositories/products.py index 7c343b5..e68ecd2 100644 --- a/repositories/products.py +++ b/repositories/products.py @@ -43,6 +43,17 @@ class ProductRepository: await session.commit() + async def clear_product_photo(self, session: AsyncSession, product_id: int) -> Product | None: + product = await self.get_product_by_id(session, product_id) + if not product: + return None + + product.file_id = None + product.img_path = None + + await session.commit() + return product + async def search( self, session: AsyncSession,