product management, unification of kb and so on.

This commit is contained in:
2026-02-24 20:47:52 +07:00
parent 36ffca460f
commit 035170e46f
23 changed files with 470 additions and 130 deletions

View File

@@ -1,12 +1,26 @@
from typing import Optional
from typing import Optional, Callable
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
from aiogram.utils.keyboard import InlineKeyboardBuilder
placeholder_kb = InlineKeyboardBuilder(
[[InlineKeyboardButton(text="🍃", callback_data="...")]]
main_menu: InlineKeyboardMarkup = InlineKeyboardBuilder(
[
[InlineKeyboardButton(text="📦 Изменить товары", callback_data="cat:root")],
[
InlineKeyboardButton(
text="📜 Изменить категории", callback_data="edit:categories"
)
],
# [InlineKeyboardButton(text="", callback_data="")],
]
).as_markup()
def back_to_product_kb(product_id: int, *, cb_factory: Callable[[int], str]):
return InlineKeyboardBuilder(
[[InlineKeyboardButton(text="⬅️", callback_data=cb_factory(product_id))]]
).as_markup()
def customer_contacts(
user_id: int, has_mention: bool, mention: Optional[str] = None
) -> InlineKeyboardMarkup:
@@ -44,3 +58,26 @@ def verify_payment(invoice_id: int):
]
]
).as_markup()
def edit_product(product_id: int, category_id: int):
prefix = f"edit_product:{product_id}"
return InlineKeyboardBuilder(
[
[
InlineKeyboardButton(
text="✍️ Название", callback_data=f"{prefix}:name"
),
InlineKeyboardButton(
text="✍️ Описание",
callback_data=f"{prefix}:description",
),
],
[InlineKeyboardButton(text="💸 Цена", callback_data=f"{prefix}:price")],
[
InlineKeyboardButton(text="👁️", callback_data=f"{prefix}:hide"),
InlineKeyboardButton(text="", callback_data=f"{prefix}:delete"),
],
[InlineKeyboardButton(text="⬅️", callback_data=f"cat:{category_id}")],
]
).as_markup()

View File

@@ -1,4 +1,4 @@
from typing import Optional
from typing import Optional, Callable
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
from aiogram.utils.keyboard import InlineKeyboardBuilder
@@ -6,10 +6,6 @@ from aiogram.utils.keyboard import InlineKeyboardBuilder
from db.models import Category, Product
from dto.cart import CartItemDTO
return_menu = InlineKeyboardBuilder(
[[InlineKeyboardButton(text="⬅️ В меню", callback_data="menu:main")]]
).as_markup()
def pagination_row(
*,
@@ -61,11 +57,13 @@ def render_category(
children: list[Category],
parent_id: Optional[int] = None,
show_menu: bool = False,
*,
category_cb_factory: Callable[[Category], str],
) -> InlineKeyboardMarkup:
btns = [
InlineKeyboardButton(
text=category.name,
callback_data=f"cat:{category.id}",
callback_data=category_cb_factory(category),
)
for category in children
]
@@ -88,35 +86,37 @@ def render_category(
def render_products(
products: list[Product],
*,
parent_id: int,
cat_id: int,
page: int = 0,
show_prev: Optional[bool] = False,
show_next: Optional[bool] = False,
product_cb_factory: Callable[[Product], str],
back_cb: Optional[str] = None,
prev_cb: Optional[str] = None,
next_cb: Optional[str] = None,
columns: int = 2,
) -> InlineKeyboardMarkup:
btns = [
InlineKeyboardButton(text=product.name, callback_data=f"product:{product.id}")
for product in products
]
builder = InlineKeyboardBuilder()
nav = pagination_row(
page=page,
prev_cb=f"products:{cat_id}:{page - 1}" if show_prev else None,
next_cb=f"products:{cat_id}:{page + 1}" if show_next else None,
)
if back_cb:
builder.row(InlineKeyboardButton(text="⬅️ Назад", callback_data=back_cb))
return InlineKeyboardBuilder(
[
[
InlineKeyboardButton(
text="⬅️ Назад",
callback_data=f"cat:{parent_id}",
)
]
for i in range(0, len(products), columns):
row = [
InlineKeyboardButton(
text=p.name,
callback_data=product_cb_factory(p),
)
for p in products[i : i + columns]
]
+ [btns[i : i + 2] for i in range(0, len(products), 2)]
+ [nav]
).as_markup()
builder.row(*row)
nav_buttons = []
if prev_cb:
nav_buttons.append(InlineKeyboardButton(text="◀️", callback_data=prev_cb))
if next_cb:
nav_buttons.append(InlineKeyboardButton(text="▶️", callback_data=next_cb))
if nav_buttons:
builder.row(*nav_buttons)
return builder.as_markup()
def render_product_interactions(
@@ -165,6 +165,7 @@ def render_cart(
page: int = 0,
show_prev: Optional[bool] = False,
show_next: Optional[bool] = False,
show_purchase: Optional[bool] = False,
) -> InlineKeyboardMarkup:
btns = [
InlineKeyboardButton(
@@ -180,19 +181,25 @@ def render_cart(
next_cb=f"cart:{page + 1}" if show_next else None,
)
return InlineKeyboardBuilder(
markup: list[list[InlineKeyboardButton]] = (
[
[
InlineKeyboardButton(
text="⬅️ Назад",
callback_data="menu:main",
)
]
],
]
+ [btns[i : i + 2] for i in range(0, len(cart_items), 2)]
+ [nav]
+ [[InlineKeyboardButton(text="🔷 Оформить заказ", callback_data="checkout")]]
).as_markup()
)
if show_purchase:
markup.append(
[InlineKeyboardButton(text="🔷 Оформить заказ", callback_data="checkout")]
)
return InlineKeyboardBuilder(markup).as_markup()
def order_confirmation(order_id: int) -> InlineKeyboardMarkup:

10
misc/kb/common.py Normal file
View File

@@ -0,0 +1,10 @@
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
from aiogram.utils.keyboard import InlineKeyboardBuilder
placeholder_kb: InlineKeyboardMarkup = InlineKeyboardBuilder(
[[InlineKeyboardButton(text="🍃", callback_data="...")]]
).as_markup()
return_menu: InlineKeyboardMarkup = InlineKeyboardBuilder(
[[InlineKeyboardButton(text="⬅️ В меню", callback_data="menu:main")]]
).as_markup()

View File

@@ -10,3 +10,11 @@ class CheckoutStorage(StatesGroup):
class PaymentStorage(StatesGroup):
refresh = State()
class SearchStorage(StatesGroup):
query = State()
class AdminControlStorage(StatesGroup):
edit_product = State()

View File

@@ -1,11 +1,17 @@
from db.models import Product
from dto.cart import CartDTO
product_editing_mapping = {
"name": "новое название",
"description": "новое описание",
"price": "новую цену",
}
def get_product_description(product: Product) -> str:
output = f"📦 <b>{product.name}</b>\n\n<b><i>🏷️ {product.price}₽</i></b>"
output = f"📦 <b>{product.name}</b>\n\n<b>🏷️ {product.price}₽</b>"
if product.description:
output += f"\n\n📜 {product.description}"
output += f"\n\n📜 <b><i>{product.description}</i></b>"
return output