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

@@ -5,6 +5,7 @@ from .products import router as products_router
from .cart import router as cart_router
from .checkout import router as checkout_router
from .security import router as security_router
from .search import router as search_router
routers = [
invoice_router,
@@ -14,4 +15,5 @@ routers = [
cart_router,
checkout_router,
security_router,
search_router,
]

View File

@@ -5,9 +5,8 @@ from aiogram.fsm.context import FSMContext
from sqlalchemy.ext.asyncio import AsyncSession
from config import PAGE_SIZE
from misc.kb.client import (
render_cart,
)
from misc.kb.client import render_cart
from misc.kb.common import return_menu
from services.orders import OrderService
router = Router()
@@ -25,11 +24,16 @@ async def cart_init(
cart = await order_service.build_pagination_cart_dto(
session, customer=cb.from_user.id
)
if not len(cart.items):
await cb.message.edit_text("🛒 Корзина пуста.", reply_markup=return_menu)
return
await cb.message.edit_text(
f"total: {cart.total}",
f"total: {cart.total} | {len(cart.items)}",
reply_markup=render_cart(
cart.items[:PAGE_SIZE], show_next=len(cart.items) > PAGE_SIZE
cart.items[:PAGE_SIZE],
show_next=len(cart.items) > PAGE_SIZE,
show_purchase=bool(len(cart.items)),
),
)
@@ -47,10 +51,16 @@ async def cart_cmd(
session, customer=msg.from_user.id
)
if not len(cart.items):
await msg.answer("🛒 Корзина пуста.", reply_markup=return_menu)
return
await msg.answer(
f"total: {cart.total}",
reply_markup=render_cart(
cart.items[:PAGE_SIZE], show_next=len(cart.items) > PAGE_SIZE
cart.items[:PAGE_SIZE],
show_next=len(cart.items) > PAGE_SIZE,
show_purchase=bool(len(cart.items)),
),
)

View File

@@ -29,7 +29,9 @@ async def subcatalogue(
if cat_id == "root":
children = await categories_repo.get_categories_by_parent_id(session)
kb = render_category(children, show_menu=True)
kb = render_category(
children, show_menu=True, category_cb_factory=lambda c: f"cat:{c.id}"
)
await cb.message.edit_text(
"category selection",
reply_markup=kb,
@@ -61,11 +63,14 @@ async def subcatalogue(
"hya",
reply_markup=render_products(
products[:PAGE_SIZE],
parent_id=parent_id,
cat_id=cat_id,
page=0,
show_prev=products_len < 0,
show_next=products_len > PAGE_SIZE,
product_cb_factory=lambda p: f"product:{p.id}",
back_cb=f"cat:{parent_id}",
next_cb=(
f"products:{cat_id}:{0 + 1}"
if products_len > PAGE_SIZE
else None
),
columns=2,
),
)
return
@@ -74,16 +79,20 @@ async def subcatalogue(
"hya",
reply_markup=render_products(
products[:PAGE_SIZE],
parent_id=parent_id,
cat_id=cat_id,
page=0,
show_prev=products_len < 0,
show_next=products_len > PAGE_SIZE,
product_cb_factory=lambda p: f"product:{p.id}",
back_cb=f"cat:{parent_id}",
prev_cb=f"products:{cat_id}:{0 - 1}" if products_len < 0 else None,
next_cb=(
f"products:{cat_id}:{0 + 1}" if products_len > PAGE_SIZE else None
),
columns=2,
),
)
return
kb = render_category(children, parent_id)
kb = render_category(
children, parent_id, category_cb_factory=lambda c: f"cat:{c.id}"
)
await cb.message.edit_text(
"category selection",

View File

@@ -6,13 +6,11 @@ from aiogram.fsm.context import FSMContext
from sqlalchemy.ext.asyncio import AsyncSession
from config import NOTIFICATION_CHANNEL
from db.models.orders import OrderStatus
from dto.checkout import CheckoutContext
from misc.kb.admins import customer_contacts
from misc.kb.client import (
order_confirmation,
order_specs_confirmation,
return_menu,
)
from misc.kb.client import order_confirmation, order_specs_confirmation
from misc.kb.common import return_menu
from misc.states import CheckoutStorage
from misc.texts import get_order_item_list
from misc.utils import is_valid_phone
@@ -152,13 +150,6 @@ async def payment_create(
await state.clear()
try:
await cb.message.edit_text(
"<b>🟢 Ваш заказ успешно отправлен!</b>\n"
"<i>📦 Мы свяжемся с вами для уточнения деталей в ближайшее время.</i>\n\n"
"<b>‼️ Чтобы убедиться, что вы общаетесь с доверенным контактом ШВЕЙТЕХЦЕНТР, перешлите любое сообщение человека в этот чат.</b>",
reply_markup=return_menu,
)
cart = await order_service.build_full_cart_dto(session, cb.from_user.id)
await cb.bot.send_message(
NOTIFICATION_CHANNEL,
@@ -173,7 +164,17 @@ async def payment_create(
cb.from_user.id, bool(cb.from_user.username), cb.from_user.username
),
)
await order_repo.remove_order_by_customer(session, cb.from_user.id)
await order_repo.update_order_status(
session, cart.order_id, OrderStatus.CREATED
)
await cb.message.edit_text(
"<b>🟢 Ваш заказ успешно отправлен!</b>\n"
"<i>📦 Мы свяжемся с вами для уточнения деталей в ближайшее время.</i>\n\n"
"<b>‼️ Чтобы убедиться, что вы общаетесь с доверенным контактом ШВЕЙТЕХЦЕНТР, перешлите любое сообщение человека в этот чат.</b>",
reply_markup=return_menu,
)
except Exception as e:
await cb.message.edit_text(
"🍃 Что-то пошло не так, повторите попытку позже...",

View File

@@ -11,7 +11,8 @@ from sqlalchemy.ext.asyncio import AsyncSession
from db.models.invoices import InvoiceStatus
from misc.kb.admins import verify_payment
from misc.kb.client import confirm_payment, return_menu
from misc.kb.client import confirm_payment
from misc.kb.common import return_menu
from repositories.invoices import InvoiceRepository
from config import card_info

View File

@@ -12,7 +12,7 @@ router = Router()
@router.message(Command("start"))
async def main_menu(
async def user_main_menu(
msg: Message,
state: FSMContext,
session: AsyncSession,
@@ -29,7 +29,7 @@ async def main_menu(
@router.callback_query(F.data.startswith("menu:"))
async def main_menu_cb(
async def user_main_menu_cb(
cb: CallbackQuery,
state: FSMContext,
session: AsyncSession,

View File

@@ -5,7 +5,8 @@ from aiogram.types import CallbackQuery, FSInputFile
from aiogram.fsm.context import FSMContext
from sqlalchemy.ext.asyncio import AsyncSession
from config import PAGE_SIZE
from config import PAGE_SIZE, VERIFIED_ACCOUNTS
from misc.kb import admins
from misc.kb.client import (
render_product_interactions,
render_products,
@@ -46,11 +47,15 @@ async def products_pagination(
await cb.message.edit_reply_markup(
reply_markup=render_products(
products[:PAGE_SIZE],
parent_id=category.parent_id,
cat_id=category_id,
page=page_id,
show_prev=page_id > 0,
show_next=products_len > PAGE_SIZE,
product_cb_factory=lambda p: f"product:{p.id}",
back_cb=f"cat:{category.parent_id}",
prev_cb=(f"products:{category_id}:{page_id - 1}" if page_id > 0 else None),
next_cb=(
f"products:{category_id}:{page_id + 1}"
if products_len > PAGE_SIZE
else None
),
columns=2,
),
)
@@ -68,9 +73,18 @@ async def product_card(
product_id = int(cb.data.split(":")[1])
product = await products_repo.get_product_by_id(session, product_id)
order_item = await order_service.get_cart_product_amount(
session, customer=cb.from_user.id, product_id=product_id
)
if cb.from_user.id in VERIFIED_ACCOUNTS:
kb = admins.edit_product(product_id=product.id, category_id=product.category_id)
else:
order_item = await order_service.get_cart_product_amount(
session, customer=cb.from_user.id, product_id=product_id
)
kb = render_product_interactions(
product_id=product.id,
category_id=product.category_id,
show_cart=bool(order_item),
cart_amount=order_item,
)
if product.file_id:
await cb.message.delete()
@@ -78,24 +92,14 @@ async def product_card(
msg = await cb.message.answer_photo(
product.file_id,
caption=get_product_description(product),
reply_markup=render_product_interactions(
product_id=product.id,
category_id=product.category_id,
show_cart=bool(order_item),
cart_amount=order_item,
),
reply_markup=kb,
)
return
if not os.path.isfile(product.img_path):
await cb.message.edit_text(
get_product_description(product),
reply_markup=render_product_interactions(
product_id=product.id,
category_id=product.category_id,
show_cart=bool(order_item),
cart_amount=order_item,
),
reply_markup=kb,
)
return
@@ -103,12 +107,7 @@ async def product_card(
msg = await cb.message.answer_photo(
FSInputFile(product.img_path),
caption=get_product_description(product),
reply_markup=render_product_interactions(
product_id=product.id,
category_id=product.category_id,
show_cart=bool(order_item),
cart_amount=order_item,
),
reply_markup=kb,
)
if not msg.photo:
@@ -120,7 +119,7 @@ async def product_card(
@router.callback_query(F.data.startswith("cart_action:"))
async def add_to_cart(
async def cart_action(
cb: CallbackQuery,
state: FSMContext,
session: AsyncSession,

58
handlers/client/search.py Normal file
View File

@@ -0,0 +1,58 @@
from typing import Optional
from aiogram import Router, F
from aiogram.fsm.context import FSMContext
from aiogram.types import CallbackQuery, Message
from sqlalchemy.ext.asyncio import AsyncSession
from misc.kb.client import render_products
from misc.kb.common import return_menu
from misc.states import SearchStorage
from repositories.products import ProductRepository
router = Router()
@router.callback_query(F.data == "find")
async def search_trigger(cb: CallbackQuery, state: FSMContext):
await state.clear()
await cb.message.edit_text("🔍 Введите запрос:", reply_markup=return_menu)
await state.set_state(SearchStorage.query)
await state.set_data({"msg": cb.message})
@router.message(SearchStorage.query)
async def searching(
msg: Message,
state: FSMContext,
session: AsyncSession,
products_repo: ProductRepository,
):
data = await state.get_data()
await state.clear()
orig_msg: Optional[Message] = data.get("msg")
results = await products_repo.search(
session,
msg.text,
)
if not orig_msg:
await msg.answer(
"here",
reply_markup=render_products(
results,
product_cb_factory=lambda p: f"product:{p.id}",
back_cb="menu:main",
next_cb="",
),
)
return
await orig_msg.edit_text(
"here",
reply_markup=render_products(
results, product_cb_factory=lambda p: f"product:{p.id}", back_cb="menu:main"
),
)