fix: stack promo group + promo offer discounts in bot (matching cabinet)

This commit is contained in:
Fringg
2026-02-25 05:49:09 +03:00
parent 3dc0b93bdf
commit 628997fb48
2 changed files with 43 additions and 30 deletions

View File

@@ -65,16 +65,25 @@ def _apply_promo_discount(price: int, discount_percent: int) -> int:
def _get_user_period_discount(db_user: User, period_days: int) -> int:
"""Получает скидку пользователя на период из промогруппы."""
promo_group = getattr(db_user, 'promo_group', None)
if promo_group:
discount = promo_group.get_discount_percent('period', period_days)
if discount > 0:
return discount
"""Получает скидку пользователя на период из промогруппы + промо-оффер (стекинг).
Возвращает итоговый процент скидки после последовательного применения
скидки промогруппы и персональной скидки промо-оффера.
"""
promo_group = db_user.get_primary_promo_group()
group_discount = promo_group.get_discount_percent('period', period_days) if promo_group else 0
personal_discount = get_user_active_promo_discount_percent(db_user)
return personal_discount
if group_discount <= 0 and personal_discount <= 0:
return 0
# Стекинг: применяем последовательно (как в кабинете)
# price * (1 - group/100) * (1 - personal/100)
# Вычисляем эффективный общий процент
remaining = (100 - group_discount) * (100 - personal_discount)
effective_discount = 100 - remaining // 100
return effective_discount
def format_tariffs_list_text(

View File

@@ -63,35 +63,39 @@ def calculate_user_price(user: User | None, base_price: int, period_days: int, c
if not base_price or base_price <= 0:
return PriceInfo(base_price=base_price or 0, final_price=base_price or 0, discount_percent=0)
# Get discount percentage
# Step 1: Get promo group discount
if user:
# Get user's promo group discount for this category
discount_percent = user.get_promo_discount(category, period_days)
group_discount = user.get_promo_discount(category, period_days)
else:
# For None user, use base settings discount
discount_percent = settings.get_base_promo_group_period_discount(period_days)
group_discount = settings.get_base_promo_group_period_discount(period_days)
# Step 2: Get promo offer discount (stacking)
promo_offer_discount = 0
if user:
from app.utils.promo_offer import get_user_active_promo_discount_percent
promo_offer_discount = get_user_active_promo_discount_percent(user)
# Apply both discounts sequentially (same as cabinet)
final_price = base_price
if group_discount > 0:
final_price = final_price - (final_price * group_discount) // 100
if promo_offer_discount > 0:
final_price = final_price - (final_price * promo_offer_discount) // 100
# Effective combined discount percent
if final_price < base_price:
discount_percent = round((base_price - final_price) * 100 / base_price)
else:
discount_percent = 0
logger.debug(
'calculate_user_price: user=, base_price=, period_days=, category=, discount_percent',
telegram_id=user.telegram_id if user else 'None',
base_price=base_price,
period_days=period_days,
category=category,
discount_percent=discount_percent,
)
if discount_percent <= 0:
return PriceInfo(base_price=base_price, final_price=base_price, discount_percent=0)
# Calculate discounted price
discount_value = (base_price * discount_percent) // 100
final_price = base_price - discount_value
logger.debug(
'Calculated price for user -> (-%) [category=, period=]',
'calculate_user_price',
telegram_id=user.telegram_id if user else 'None',
base_price=base_price,
final_price=final_price,
group_discount=group_discount,
promo_offer_discount=promo_offer_discount,
discount_percent=discount_percent,
category=category,
period_days=period_days,