chore: minor fixes and formatting

This commit is contained in:
2026-08-12 19:52:30 +07:00
parent a011b2724b
commit ca276cdd61
48 changed files with 394 additions and 354 deletions

View File

@@ -1,4 +1,4 @@
from .client import routers as client_routers
from .admins import routers as admins_routers
from .client import routers as client_routers
__all__ = ["client_routers", "admins_routers"]
__all__ = ["admins_routers", "client_routers"]

View File

@@ -1,6 +1,6 @@
from .creation import router as creation_router
from .inline_mode import router as inline_router
from .menu import router as menu_router
from .product_mgmt import router as product_router
from .creation import router as creation_router
routers = [inline_router, menu_router, product_router, creation_router]

View File

@@ -1,14 +1,14 @@
from aiogram import F, Router
from aiogram.types import CallbackQuery, Message
from aiogram.fsm.context import FSMContext
from aiogram.types import CallbackQuery, Message
from sqlalchemy.ext.asyncio import AsyncSession
from dto.catalogue import CategoryActionContext
from misc.filters import IsVerified
from misc.kb.client import created_category, get_back_to_catalogue
from misc.kb.common import return_menu
from misc.mapper import parse_cat_id
from misc.states import AdminControlStorage
from misc.kb.common import return_menu
from repositories.categories import CategoriesRepository
from services.catalogue import CatalogueService
@@ -67,6 +67,6 @@ async def create_new_category(
await ctx.msg.edit_text(
f"✅ Категория {msg.text} создана успешно.",
reply_markup=created_category(
category.id, f"🛒 {category.name}", category.parent_id
category.id, f"🛒 {category.name}", category.parent_id or "root"
),
)

View File

@@ -1,6 +1,6 @@
import logging
from aiogram import Router, F
from aiogram import F, Router
from aiogram.types import (
ChosenInlineResult,
InlineQuery,
@@ -26,9 +26,7 @@ async def send_invoice(iq: InlineQuery, amount: int):
InlineQueryResultArticle(
id=dict_to_b64({"a": amount}),
title=f"💸 Счёт на {amount}₽",
input_message_content=InputTextMessageContent(
message_text="⏳ Создаю счёт..."
),
input_message_content=InputTextMessageContent(message_text="⏳ Создаю счёт..."),
reply_markup=placeholder_kb,
description="Нажмите, чтобы создать счёт.",
),

View File

@@ -1,9 +1,9 @@
import logging
from aiogram import Router, F
from aiogram.fsm.context import FSMContext
from aiogram.types import Message, CallbackQuery
from aiogram import F, Router
from aiogram.filters import Command
from aiogram.fsm.context import FSMContext
from aiogram.types import CallbackQuery, Message
from misc.filters import IsVerified
from misc.kb.admins import main_menu

View File

@@ -1,12 +1,14 @@
import logging
from aiogram import Router, F
from aiogram.types import Message, CallbackQuery
from aiogram import F, Router
from aiogram.fsm.context import FSMContext
from aiogram.types import CallbackQuery, Message
from sqlalchemy.ext.asyncio import AsyncSession
from dto.catalogue import CategoryActionContext
from dto.control import EditProductContext
from misc.filters import IsVerified
from misc.kb import admins
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
@@ -19,7 +21,7 @@ logger = logging.getLogger(__name__)
router = Router()
@router.callback_query(IsVerified(), F.data.startswith("edit_product:"))
@router.callback_query(IsVerified(), F.data.regexp(r"^edit_product:\d+:(name|description|price)$"))
async def edit_product(cb: CallbackQuery, state: FSMContext):
await state.clear()
@@ -31,18 +33,14 @@ async def edit_product(cb: CallbackQuery, state: FSMContext):
await cb.message.delete()
msg = await cb.message.answer(
f"<b>✍️ Введите {product_editing_mapping.get(mode)}</b>",
reply_markup=back_to_product_kb(
product_id, cb_factory=lambda p: f"product:{p}"
),
reply_markup=back_to_product_kb(product_id, cb_factory=lambda p: f"product:{p}"),
)
else:
msg = cb.message
await cb.message.edit_text(
f"<b>✍️ Введите {product_editing_mapping.get(mode)}</b>",
reply_markup=back_to_product_kb(
product_id, cb_factory=lambda p: f"product:{p}"
),
reply_markup=back_to_product_kb(product_id, cb_factory=lambda p: f"product:{p}"),
)
ctx = EditProductContext(int(product_id), mode, msg)
@@ -68,13 +66,9 @@ async def edit_product_query(
try:
await ctx.msg.edit_text("⏳")
if ctx.mode == "name":
await products_repo.update_product_name_by_id(
session, ctx.product_id, msg.text
)
await products_repo.update_product_name_by_id(session, ctx.product_id, msg.text)
elif ctx.mode == "description":
await products_repo.update_product_description_by_id(
session, ctx.product_id, msg.text
)
await products_repo.update_product_description_by_id(session, ctx.product_id, msg.text)
elif ctx.mode == "price":
if msg.text.isdigit():
await products_repo.update_product_price_by_id(
@@ -99,6 +93,33 @@ async def edit_product_query(
await ctx.msg.edit_text(text="‼️ Что-то пошло не так.", reply_markup=kb)
@router.callback_query(IsVerified(), F.data.startswith("edit_product:"), F.data.endswith(":hide"))
async def toggle_product_visibility(
cb: CallbackQuery,
state: FSMContext,
session: AsyncSession,
products_repo: ProductRepository,
):
await state.clear()
product_id = int(cb.data.split(":")[1])
product = await products_repo.toggle_product_hidden_by_id(session, product_id)
if not product:
await cb.answer("Товар не найден.", show_alert=True)
return
await cb.answer("Товар скрыт." if product.is_hidden else "Товар снова виден.")
if cb.message.photo:
await cb.message.edit_caption(
caption=cb.message.caption,
reply_markup=admins.edit_product(product),
)
return
await cb.message.edit_reply_markup(reply_markup=admins.edit_product(product))
@router.callback_query(F.data.startswith("edit:"))
async def edit_entry(cb: CallbackQuery, state: FSMContext):
await state.clear()
@@ -143,6 +164,4 @@ async def edit_category(
session=session, category_id=parse_cat_id(ctx.parent_id), value=msg.text
)
await ctx.msg.edit_text(
"✅ Успешно.", reply_markup=get_back_to_catalogue(cat.parent_id)
)
await ctx.msg.edit_text("✅ Успешно.", reply_markup=get_back_to_catalogue(cat.parent_id))

View File

@@ -1,11 +1,11 @@
from .cart import router as cart_router
from .catalogue import router as catalogue_router
from .checkout import router as checkout_router
from .invoices import router as invoice_router
from .menu import router as menu_router
from .catalogue import router as catalogue_router
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
from .security import router as security_router
routers = [
invoice_router,

View File

@@ -1,7 +1,7 @@
from aiogram import Router, F
from aiogram.types import CallbackQuery, Message
from aiogram import F, Router
from aiogram.filters import Command
from aiogram.fsm.context import FSMContext
from aiogram.types import CallbackQuery, Message
from sqlalchemy.ext.asyncio import AsyncSession
from config import PAGE_SIZE
@@ -21,15 +21,14 @@ async def cart_init(
):
await state.clear()
cart = await order_service.build_pagination_cart_dto(
session, customer=cb.from_user.id
)
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}₽ | {len(cart.items)}",
"<b>🌸 Убедитесь в том, что все желаемые позиции есть в заказе ниже!</b>\n\n"
f"<b>Сумма:</b> <i>{cart.total}₽</i>",
reply_markup=render_cart(
cart.items[:PAGE_SIZE],
show_next=len(cart.items) > PAGE_SIZE,
@@ -47,9 +46,7 @@ async def cart_cmd(
):
await state.clear()
cart = await order_service.build_pagination_cart_dto(
session, customer=msg.from_user.id
)
cart = await order_service.build_pagination_cart_dto(session, customer=msg.from_user.id)
if not len(cart.items):
await msg.answer("🛒 Корзина пуста.", reply_markup=return_menu)

View File

@@ -1,6 +1,6 @@
from aiogram import Router, F
from aiogram.types import CallbackQuery
from aiogram import F, Router
from aiogram.fsm.context import FSMContext
from aiogram.types import CallbackQuery
from sqlalchemy.ext.asyncio import AsyncSession
from config import VERIFIED_ACCOUNTS
@@ -24,7 +24,7 @@ async def subcatalogue(
cat_id = cb.data.split(":")[1]
is_admin = cb.from_user.id in VERIFIED_ACCOUNTS
view = await catalogue_service.build_category_view(session, cat_id)
view = await catalogue_service.build_category_view(session, cat_id, include_hidden=is_admin)
kb = render_catalogue(view, is_admin=is_admin)
path = await catalogue_service.get_path(session, cat_id)

View File

@@ -1,8 +1,8 @@
import logging
from typing import Optional
from aiogram import Router, F
from aiogram.types import CallbackQuery, Message
from aiogram import F, Router
from aiogram.fsm.context import FSMContext
from aiogram.types import CallbackQuery, Message
from sqlalchemy.ext.asyncio import AsyncSession
from config import NOTIFICATION_CHANNEL
@@ -98,7 +98,7 @@ async def checkout_phone(msg: Message, state: FSMContext):
ctx.phone = msg.text
await ctx.orig_msg.edit_text(
f"<i>👤 Имя: {ctx.name}</i>\n<i>📱 Номер телефона: {ctx.phone}</i>\n\n<b>📍 Укажите ваш адрес (город, улица):</b>",
f"<i>👤 Имя: {ctx.name}</i>\n<i>📱 Номер телефона: {ctx.phone}</i>\n\n<b>📍 Укажите адрес ближайшего ПВЗ Ozon (город, улица):</b>",
reply_markup=return_menu,
)
await state.set_state(CheckoutStorage.address)
@@ -119,7 +119,7 @@ async def checkout_address(msg: Message, state: FSMContext):
"━━━━━━━━━━━━━━\n\n"
f"<i>👤 Имя: {ctx.name}</i>\n"
f"<i>📱 Номер телефона: {ctx.phone}</i>\n"
f"<i>📍 Ваш адрес: {ctx.address}</i>\n\n"
f"<i>📍 Адрес ближайшего ПВЗ Ozon: {ctx.address}</i>\n\n"
"━━━━━━━━━━━━━━",
reply_markup=order_specs_confirmation(ctx.order_id),
)
@@ -138,7 +138,7 @@ async def payment_create(
order_repo: OrderRepository,
):
data = await state.get_data()
ctx: Optional[CheckoutContext] = data.get("ctx")
ctx: CheckoutContext | None = data.get("ctx")
if not ctx:
await cb.message.edit_text(
"🍃 Что-то пошло не так, повторите попытку позже...",
@@ -157,16 +157,14 @@ async def payment_create(
"━━━━━━━━━━━━━━\n\n"
f"<i>👤 Имя: {ctx.name}</i>\n"
f"<i>📱 Номер телефона: {ctx.phone}</i>\n"
f"<i>📍 Адрес: {ctx.address}</i>\n\n"
f"<i>📍 Адрес ближайшего ПВЗ Ozon: {ctx.address}</i>\n\n"
"━━━━━━━━━━━━━━\n"
f"{get_order_item_list(cart)}",
reply_markup=customer_contacts(
cb.from_user.id, bool(cb.from_user.username), cb.from_user.username
),
)
await order_repo.update_order_status(
session, cart.order_id, OrderStatus.CREATED
)
await order_repo.update_order_status(session, cart.order_id, OrderStatus.CREATED)
await cb.message.edit_text(
"<b>🟢 Ваш заказ успешно отправлен!</b>\n"

View File

@@ -1,6 +1,6 @@
import logging
from aiogram import Router, F
from aiogram import F, Router
from aiogram.filters import CommandObject, CommandStart
from aiogram.fsm.context import FSMContext
from aiogram.types import (
@@ -9,12 +9,12 @@ from aiogram.types import (
)
from sqlalchemy.ext.asyncio import AsyncSession
from config import card_info
from db.models.invoices import InvoiceStatus
from misc.kb.admins import verify_payment
from misc.kb.client import confirm_payment
from misc.kb.common import return_menu
from repositories.invoices import InvoiceRepository
from config import card_info
router = Router()
logger = logging.getLogger(__name__)
@@ -33,9 +33,7 @@ async def activate_invoice(
invoice = await invoice_repo.get_invoice_by_id(session, invoice_id)
if not invoice:
await msg.answer(
"⏳ Счёт истёк. Повторите попытку позже.", reply_markup=return_menu
)
await msg.answer("⏳ Счёт истёк. Повторите попытку позже.", reply_markup=return_menu)
return
if invoice.status != InvoiceStatus.PENDING:
@@ -43,9 +41,7 @@ async def activate_invoice(
return
if not (card_info.number and card_info.holder):
await msg.answer(
"🍃 Оплата недоступна, повторите попытку позже.", reply_markup=return_menu
)
await msg.answer("🍃 Оплата недоступна, повторите попытку позже.", reply_markup=return_menu)
return
await msg.answer(

View File

@@ -1,7 +1,9 @@
from aiogram import Router, F
from aiogram.types import CallbackQuery, Message
import contextlib
from aiogram import F, Router
from aiogram.filters import Command
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
@@ -20,12 +22,11 @@ async def user_main_menu(
):
await state.clear()
cart_items = await order_items_repo.get_items_count_by_customer(
session, msg.from_user.id
)
cart_items = await order_items_repo.get_items_count_by_customer(session, msg.from_user.id)
await msg.answer(
"hii!", reply_markup=main_menu_kb(cart_items)
) # TODO: Write a welcome message
"<b>Добрый день!</b>\n" 'Нажмите "Каталог" чтобы выбрать товар или воспользуйтесь поиском.',
reply_markup=main_menu_kb(cart_items),
)
@router.callback_query(F.data.startswith("menu:"))
@@ -37,14 +38,11 @@ async def user_main_menu_cb(
):
await state.clear()
try:
with contextlib.suppress(Exception):
await cb.message.reply_to_message.delete()
except Exception:
...
cart_items = await order_items_repo.get_items_count_by_customer(
session, cb.from_user.id
)
cart_items = await order_items_repo.get_items_count_by_customer(session, cb.from_user.id)
await cb.message.edit_text(
"hii!", reply_markup=main_menu_kb(cart_items)
) # TODO: Write a welcome message
"<b>Добрый день!</b>\n" 'Нажмите "Каталог" чтобы выбрать товар или воспользуйтесь поиском.',
reply_markup=main_menu_kb(cart_items),
)

View File

@@ -1,10 +1,11 @@
import os
import contextlib
import logging
import os
from re import Match
from aiogram import Router, F
from aiogram.types import CallbackQuery, FSInputFile
from aiogram.exceptions import TelegramBadRequest
from aiogram import F, Router
from aiogram.fsm.context import FSMContext
from aiogram.types import CallbackQuery, FSInputFile
from sqlalchemy.ext.asyncio import AsyncSession
from config import VERIFIED_ACCOUNTS
@@ -23,9 +24,7 @@ logger = logging.getLogger(__name__)
@router.callback_query(
F.data.regexp(r"products:(?P<category_id>.*):(?P<page_id>\d+)").as_(
"pagination_match"
)
F.data.regexp(r"products:(?P<category_id>.*):(?P<page_id>\d+)").as_("pagination_match")
)
async def products_pagination(
cb: CallbackQuery,
@@ -39,11 +38,11 @@ async def products_pagination(
pagination_data = pagination_match.groupdict()
category_id = int(pagination_data.get("category_id"))
page_id = int(pagination_data.get("page_id", 0))
is_admin = cb.from_user.id in VERIFIED_ACCOUNTS
view = await catalogue_service.build_category_view(
session, category_id, page=page_id
session, category_id, page=page_id, include_hidden=is_admin
)
is_admin = cb.from_user.id in VERIFIED_ACCOUNTS
kb = render_catalogue(view, is_admin=is_admin)
@@ -61,10 +60,15 @@ async def product_card(
await state.clear()
product_id = int(cb.data.split(":")[1])
product = await products_repo.get_product_by_id(session, product_id)
is_admin = cb.from_user.id in VERIFIED_ACCOUNTS
product = await products_repo.get_product_by_id(session, product_id, include_hidden=is_admin)
if cb.from_user.id in VERIFIED_ACCOUNTS:
kb = admins.edit_product(product_id=product.id, category_id=product.category_id)
if not product:
await cb.answer("Товар недоступен.", show_alert=True)
return
if is_admin:
kb = admins.edit_product(product)
else:
order_item = await order_service.get_cart_product_amount(
session, customer=cb.from_user.id, product_id=product_id
@@ -76,9 +80,7 @@ async def product_card(
cart_amount=order_item,
)
if not product.file_id and not (
product.img_path and os.path.isfile(product.img_path)
):
if not product.file_id and not (product.img_path and os.path.isfile(product.img_path)):
await cb.message.edit_text(
get_product_description(product),
reply_markup=kb,
@@ -95,10 +97,8 @@ async def product_card(
)
return
try:
with contextlib.suppress(Exception):
await cb.message.edit_text("<b>⏳ Загружаем карточку товара...</b>")
except TelegramBadRequest:
...
msg = await cb.message.answer_photo(
FSInputFile(product.img_path),
@@ -110,9 +110,7 @@ async def product_card(
logger.warning("didnt get a photo back wahhh :(")
return # TODO: Add logging
await products_repo.add_product_file_id(
session, product_id, file_id=msg.photo[-1].file_id
)
await products_repo.add_product_file_id(session, product_id, file_id=msg.photo[-1].file_id)
@router.callback_query(F.data.startswith("cart_action:"))
@@ -127,7 +125,13 @@ async def cart_action(
action = cb.data.split(":")[1]
product_id = int(cb.data.split(":")[2])
product = await products_repo.get_product_by_id(session, product_id)
is_admin = cb.from_user.id in VERIFIED_ACCOUNTS
product = await products_repo.get_product_by_id(session, product_id, include_hidden=is_admin)
if not product:
await cb.answer("Товар недоступен.", show_alert=True)
return
show_cart = True
if action == "add":

View File

@@ -1,12 +1,11 @@
from typing import Optional
import hashlib
from aiogram import Router, F
from aiogram import F, Router
from aiogram.fsm.context import FSMContext
from aiogram.types import CallbackQuery, Message
from sqlalchemy.ext.asyncio import AsyncSession
from config import PAGE_SIZE
from config import PAGE_SIZE, VERIFIED_ACCOUNTS
from misc.kb.client import render_products
from misc.kb.common import return_menu
from misc.redis import RedisClient
@@ -20,7 +19,7 @@ router = Router()
async def search_trigger(cb: CallbackQuery, state: FSMContext):
await state.clear()
await cb.message.edit_text("🔍 Введите запрос:", reply_markup=return_menu)
await cb.message.edit_text("<b>🔍 Введите запрос:</b>", reply_markup=return_menu)
await state.set_state(SearchStorage.query)
await state.set_data({"msg": cb.message})
@@ -37,11 +36,13 @@ async def searching(
await state.clear()
await msg.delete()
orig_msg: Optional[Message] = data.get("msg") or await msg.answer("⏳")
orig_msg: Message | None = data.get("msg") or await msg.answer("⏳")
await orig_msg.edit_text("⏳ Поиск...")
is_admin = msg.from_user.id in VERIFIED_ACCOUNTS
results = await products_repo.search(
session,
msg.text,
include_hidden=is_admin,
)
next_cb = None
@@ -51,12 +52,13 @@ async def searching(
next_cb = f"search:{query_hash}:1"
await orig_msg.edit_text(
"here",
"<b>🗒 Результаты поиска:</b>",
reply_markup=render_products(
results[:PAGE_SIZE],
product_cb_factory=lambda p: f"product:{p.id}",
back_cb="menu:main",
next_cb=next_cb,
is_admin=is_admin,
),
)
@@ -79,7 +81,13 @@ async def search_pagination(
if not query:
await cb.message.edit_text("🍃 Попробуйте ещё раз...")
results = await products_repo.search(session, query, offset=PAGE_SIZE * page)
is_admin = cb.from_user.id in VERIFIED_ACCOUNTS
results = await products_repo.search(
session,
query,
offset=PAGE_SIZE * page,
include_hidden=is_admin,
)
await cb.message.edit_reply_markup(
reply_markup=render_products(
@@ -88,5 +96,6 @@ async def search_pagination(
back_cb="menu:main",
next_cb=f"search:{q_hash}:{page + 1}" if len(results) > PAGE_SIZE else None,
prev_cb=f"search:{q_hash}:{page - 1}" if page > 0 else None,
is_admin=is_admin,
)
)

View File

@@ -1,4 +1,4 @@
from aiogram import Router, F
from aiogram import F, Router
from aiogram.enums import MessageOriginType
from aiogram.types import Message