diff --git a/app/database/crud/promocode.py b/app/database/crud/promocode.py index d67415bb..d765d655 100644 --- a/app/database/crud/promocode.py +++ b/app/database/crud/promocode.py @@ -22,6 +22,22 @@ async def get_promocode_by_code(db: AsyncSession, code: str) -> Optional[PromoCo return result.scalar_one_or_none() +async def get_promocode_by_id(db: AsyncSession, promo_id: int) -> Optional[PromoCode]: + """ + Получает промокод по ID с eager loading всех связанных данных. + Используется для избежания lazy loading в async контексте. + """ + result = await db.execute( + select(PromoCode) + .options( + selectinload(PromoCode.uses), + selectinload(PromoCode.promo_group) + ) + .where(PromoCode.id == promo_id) + ) + return result.scalar_one_or_none() + + async def check_promocode_validity(db: AsyncSession, code: str) -> dict: """ Проверяет существование и валидность промокода без активации. @@ -80,9 +96,9 @@ async def use_promocode( promocode_id: int, user_id: int ) -> bool: - + try: - promocode = await db.get(PromoCode, promocode_id) + promocode = await get_promocode_by_id(db, promocode_id) if not promocode: return False diff --git a/app/handlers/admin/promocodes.py b/app/handlers/admin/promocodes.py index e6d0e7aa..73aef95c 100644 --- a/app/handlers/admin/promocodes.py +++ b/app/handlers/admin/promocodes.py @@ -15,7 +15,7 @@ from app.localization.texts import get_texts from app.database.crud.promocode import ( get_promocodes_list, get_promocodes_count, create_promocode, get_promocode_statistics, get_promocode_by_code, update_promocode, - delete_promocode + delete_promocode, get_promocode_by_id ) from app.database.crud.promo_group import get_promo_group_by_id, get_promo_groups_with_counts from app.utils.decorators import admin_required, error_handler @@ -138,8 +138,8 @@ async def show_promocode_management( db: AsyncSession ): promo_id = int(callback.data.split('_')[-1]) - - promo = await db.get(PromoCode, promo_id) + + promo = await get_promocode_by_id(db, promo_id) if not promo: await callback.answer("❌ Промокод не найден", show_alert=True) return @@ -219,8 +219,8 @@ async def show_promocode_edit_menu( except (ValueError, IndexError): await callback.answer("❌ Ошибка получения ID промокода", show_alert=True) return - - promo = await db.get(PromoCode, promo_id) + + promo = await get_promocode_by_id(db, promo_id) if not promo: await callback.answer("❌ Промокод не найден", show_alert=True) return @@ -648,8 +648,8 @@ async def handle_edit_value( data = await state.get_data() promo_id = data.get('editing_promo_id') edit_action = data.get('edit_action') - - promo = await db.get(PromoCode, promo_id) + + promo = await get_promocode_by_id(db, promo_id) if not promo: await message.answer("❌ Промокод не найден") await state.clear() @@ -734,8 +734,8 @@ async def handle_edit_uses( ): data = await state.get_data() promo_id = data.get('editing_promo_id') - - promo = await db.get(PromoCode, promo_id) + + promo = await get_promocode_by_id(db, promo_id) if not promo: await message.answer("❌ Промокод не найден") await state.clear() @@ -873,8 +873,8 @@ async def handle_edit_expiry( ): data = await state.get_data() promo_id = data.get('editing_promo_id') - - promo = await db.get(PromoCode, promo_id) + + promo = await get_promocode_by_id(db, promo_id) if not promo: await message.answer("❌ Промокод не найден") await state.clear() @@ -920,8 +920,8 @@ async def toggle_promocode_status( db: AsyncSession ): promo_id = int(callback.data.split('_')[-1]) - - promo = await db.get(PromoCode, promo_id) + + promo = await get_promocode_by_id(db, promo_id) if not promo: await callback.answer("❌ Промокод не найден", show_alert=True) return @@ -947,8 +947,8 @@ async def confirm_delete_promocode( except (ValueError, IndexError): await callback.answer("❌ Ошибка получения ID промокода", show_alert=True) return - - promo = await db.get(PromoCode, promo_id) + + promo = await get_promocode_by_id(db, promo_id) if not promo: await callback.answer("❌ Промокод не найден", show_alert=True) return @@ -995,8 +995,8 @@ async def delete_promocode_confirmed( except (ValueError, IndexError): await callback.answer("❌ Ошибка получения ID промокода", show_alert=True) return - - promo = await db.get(PromoCode, promo_id) + + promo = await get_promocode_by_id(db, promo_id) if not promo: await callback.answer("❌ Промокод не найден", show_alert=True) return @@ -1019,8 +1019,8 @@ async def show_promocode_stats( db: AsyncSession ): promo_id = int(callback.data.split('_')[-1]) - - promo = await db.get(PromoCode, promo_id) + + promo = await get_promocode_by_id(db, promo_id) if not promo: await callback.answer("❌ Промокод не найден", show_alert=True) return diff --git a/app/webapi/routes/promocodes.py b/app/webapi/routes/promocodes.py index a39c70b0..11e4e312 100644 --- a/app/webapi/routes/promocodes.py +++ b/app/webapi/routes/promocodes.py @@ -10,6 +10,7 @@ from app.database.crud.promocode import ( create_promocode, delete_promocode, get_promocode_by_code, + get_promocode_by_id, get_promocode_statistics, get_promocodes_count, get_promocodes_list, @@ -163,7 +164,7 @@ async def get_promocode( _: Any = Depends(require_api_token), db: AsyncSession = Depends(get_db_session), ) -> PromoCodeDetailResponse: - promocode = await db.get(PromoCode, promocode_id) + promocode = await get_promocode_by_id(db, promocode_id) if not promocode: raise HTTPException(status.HTTP_404_NOT_FOUND, "Promo code not found") @@ -236,7 +237,7 @@ async def update_promocode_endpoint( _: Any = Depends(require_api_token), db: AsyncSession = Depends(get_db_session), ) -> PromoCodeResponse: - promocode = await db.get(PromoCode, promocode_id) + promocode = await get_promocode_by_id(db, promocode_id) if not promocode: raise HTTPException(status.HTTP_404_NOT_FOUND, "Promo code not found") @@ -290,7 +291,7 @@ async def delete_promocode_endpoint( _: Any = Depends(require_api_token), db: AsyncSession = Depends(get_db_session), ) -> Response: - promocode = await db.get(PromoCode, promocode_id) + promocode = await get_promocode_by_id(db, promocode_id) if not promocode: raise HTTPException(status.HTTP_404_NOT_FOUND, "Promo code not found")