mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-02-28 23:35:59 +00:00
Merge pull request #2530 from BEDOLAGA-DEV/fix/cabinet-promo-discounts
fix(cabinet): apply promo group discounts to addons and tariff switch
This commit is contained in:
@@ -63,6 +63,71 @@ logger = logging.getLogger(__name__)
|
||||
router = APIRouter(prefix='/subscription', tags=['Cabinet Subscription'])
|
||||
|
||||
|
||||
def _get_addon_discount_percent(
|
||||
user: User,
|
||||
category: str,
|
||||
period_days: int | None = None,
|
||||
) -> int:
|
||||
"""Get addon discount percent for user from promo group.
|
||||
|
||||
Mirrors logic from app/handlers/subscription/common.py:_get_addon_discount_percent_for_user
|
||||
"""
|
||||
promo_group = (
|
||||
user.get_primary_promo_group()
|
||||
if hasattr(user, 'get_primary_promo_group')
|
||||
else getattr(user, 'promo_group', None)
|
||||
)
|
||||
if promo_group is None:
|
||||
return 0
|
||||
|
||||
if not getattr(promo_group, 'apply_discounts_to_addons', True):
|
||||
return 0
|
||||
|
||||
try:
|
||||
return user.get_promo_discount(category, period_days)
|
||||
except AttributeError:
|
||||
return 0
|
||||
|
||||
|
||||
def _apply_addon_discount(
|
||||
user: User,
|
||||
category: str,
|
||||
amount: int,
|
||||
period_days: int | None = None,
|
||||
) -> dict[str, int]:
|
||||
"""Apply addon discount to amount.
|
||||
|
||||
Returns dict with keys: discounted, discount, percent
|
||||
"""
|
||||
percent = _get_addon_discount_percent(user, category, period_days)
|
||||
if percent <= 0 or amount <= 0:
|
||||
return {'discounted': amount, 'discount': 0, 'percent': 0}
|
||||
|
||||
discount_value = int(amount * percent / 100)
|
||||
discounted_amount = amount - discount_value
|
||||
return {
|
||||
'discounted': discounted_amount,
|
||||
'discount': discount_value,
|
||||
'percent': percent,
|
||||
}
|
||||
|
||||
|
||||
def _get_period_discount_percent(user: User, period_days: int | None = None) -> int:
|
||||
"""Get period discount percent for tariff switch calculations."""
|
||||
promo_group = (
|
||||
user.get_primary_promo_group()
|
||||
if hasattr(user, 'get_primary_promo_group')
|
||||
else getattr(user, 'promo_group', None)
|
||||
)
|
||||
if promo_group is None:
|
||||
return 0
|
||||
|
||||
try:
|
||||
return user.get_promo_discount('period', period_days)
|
||||
except AttributeError:
|
||||
return 0
|
||||
|
||||
|
||||
def _subscription_to_response(
|
||||
subscription: Subscription,
|
||||
servers: list[ServerInfo] | None = None,
|
||||
@@ -668,33 +733,29 @@ async def purchase_traffic(
|
||||
)
|
||||
base_price_kopeks = matching_pkg['price']
|
||||
|
||||
# Применяем скидку промогруппы
|
||||
traffic_discount_percent = 0
|
||||
promo_group = (
|
||||
user.get_primary_promo_group()
|
||||
if hasattr(user, 'get_primary_promo_group')
|
||||
else getattr(user, 'promo_group', None)
|
||||
)
|
||||
if promo_group:
|
||||
apply_to_addons = getattr(promo_group, 'apply_discounts_to_addons', True)
|
||||
if apply_to_addons:
|
||||
traffic_discount_percent = max(0, min(100, int(getattr(promo_group, 'traffic_discount_percent', 0) or 0)))
|
||||
|
||||
if traffic_discount_percent > 0:
|
||||
base_price_kopeks = int(base_price_kopeks * (100 - traffic_discount_percent) / 100)
|
||||
|
||||
# На тарифах пакеты трафика покупаются на 1 месяц (30 дней),
|
||||
# цена в тарифе уже месячная — не умножаем на оставшиеся месяцы подписки.
|
||||
# Пропорциональный расчёт применяем только в классическом режиме.
|
||||
if is_tariff_mode:
|
||||
final_price = base_price_kopeks
|
||||
prorated_price = base_price_kopeks
|
||||
months_charged = 1
|
||||
else:
|
||||
final_price, months_charged = calculate_prorated_price(
|
||||
prorated_price, months_charged = calculate_prorated_price(
|
||||
base_price_kopeks,
|
||||
subscription.end_date,
|
||||
)
|
||||
|
||||
# Apply discount from promo group using proper method
|
||||
period_hint_days = months_charged * 30 if months_charged > 0 else 30
|
||||
discount_result = _apply_addon_discount(user, 'traffic', prorated_price, period_hint_days)
|
||||
final_price = discount_result['discounted']
|
||||
traffic_discount_percent = discount_result['percent']
|
||||
discount_value = discount_result['discount']
|
||||
|
||||
# Ensure minimum price after discount (except for 100% discount)
|
||||
if traffic_discount_percent < 100 and final_price > 0:
|
||||
final_price = max(100, final_price)
|
||||
|
||||
# Проверяем баланс
|
||||
if user.balance_kopeks < final_price:
|
||||
missing = final_price - user.balance_kopeks
|
||||
@@ -705,7 +766,7 @@ async def purchase_traffic(
|
||||
'subscription_id': subscription.id,
|
||||
'traffic_gb': request.gb,
|
||||
'price_kopeks': final_price,
|
||||
'base_price_kopeks': base_price_kopeks,
|
||||
'base_price_kopeks': prorated_price,
|
||||
'discount_percent': traffic_discount_percent,
|
||||
'source': 'cabinet',
|
||||
'description': f'Докупка {request.gb} ГБ трафика',
|
||||
@@ -713,7 +774,10 @@ async def purchase_traffic(
|
||||
|
||||
try:
|
||||
await user_cart_service.save_user_cart(user.id, cart_data)
|
||||
logger.info(f'Cart saved for traffic purchase (cabinet) user {user.id}: +{request.gb} GB')
|
||||
logger.info(
|
||||
f'Cart saved for traffic purchase (cabinet) user {user.id}: '
|
||||
f'+{request.gb} GB, discount {traffic_discount_percent}%'
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f'Error saving cart for traffic purchase (cabinet): {e}')
|
||||
|
||||
@@ -806,24 +870,33 @@ async def purchase_traffic(
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to send admin notification for traffic purchase: {e}')
|
||||
|
||||
return {
|
||||
response = {
|
||||
'success': True,
|
||||
'message': 'Traffic purchased successfully',
|
||||
'gb_added': request.gb,
|
||||
'new_traffic_limit_gb': subscription.traffic_limit_gb,
|
||||
'amount_paid_kopeks': final_price,
|
||||
'discount_percent': traffic_discount_percent,
|
||||
'new_balance_kopeks': user.balance_kopeks,
|
||||
}
|
||||
|
||||
if traffic_discount_percent > 0:
|
||||
response['discount_percent'] = traffic_discount_percent
|
||||
response['discount_kopeks'] = discount_value
|
||||
response['base_price_kopeks'] = prorated_price
|
||||
|
||||
return response
|
||||
|
||||
|
||||
@router.post('/devices')
|
||||
async def purchase_devices(
|
||||
async def purchase_devices_legacy(
|
||||
request: DevicePurchaseRequest,
|
||||
user: User = Depends(get_current_cabinet_user),
|
||||
db: AsyncSession = Depends(get_cabinet_db),
|
||||
):
|
||||
"""Purchase additional device slots."""
|
||||
"""Purchase additional device slots (legacy endpoint without tariff support).
|
||||
|
||||
DEPRECATED: Use /devices/purchase instead for full tariff and discount support.
|
||||
"""
|
||||
await db.refresh(user, ['subscription'])
|
||||
|
||||
if not user.subscription:
|
||||
@@ -833,7 +906,16 @@ async def purchase_devices(
|
||||
)
|
||||
|
||||
price_per_device = settings.PRICE_PER_DEVICE
|
||||
total_price = price_per_device * request.devices
|
||||
base_total_price = price_per_device * request.devices
|
||||
|
||||
# Apply discount from promo group
|
||||
discount_result = _apply_addon_discount(user, 'devices', base_total_price, 30)
|
||||
total_price = discount_result['discounted']
|
||||
devices_discount_percent = discount_result['percent']
|
||||
|
||||
# Ensure minimum price after discount (except for 100% discount)
|
||||
if devices_discount_percent < 100 and total_price > 0:
|
||||
total_price = max(100, total_price)
|
||||
|
||||
# Check balance
|
||||
if user.balance_kopeks < total_price:
|
||||
@@ -845,6 +927,8 @@ async def purchase_devices(
|
||||
'cart_mode': 'add_devices',
|
||||
'devices_to_add': request.devices,
|
||||
'price_kopeks': total_price,
|
||||
'base_price_kopeks': base_total_price,
|
||||
'discount_percent': devices_discount_percent,
|
||||
'source': 'cabinet',
|
||||
}
|
||||
await user_cart_service.save_user_cart(user.id, cart_data)
|
||||
@@ -879,11 +963,17 @@ async def purchase_devices(
|
||||
from app.database.crud.user import subtract_user_balance
|
||||
from app.database.models import PaymentMethod
|
||||
|
||||
# Build description with discount info
|
||||
if devices_discount_percent > 0:
|
||||
description = f'Покупка {request.devices} доп. устройств (скидка {devices_discount_percent}%)'
|
||||
else:
|
||||
description = f'Покупка {request.devices} доп. устройств'
|
||||
|
||||
await subtract_user_balance(
|
||||
db=db,
|
||||
user=user,
|
||||
amount_kopeks=total_price,
|
||||
description=f'Покупка {request.devices} доп. устройств',
|
||||
description=description,
|
||||
create_transaction=True,
|
||||
payment_method=PaymentMethod.BALANCE,
|
||||
)
|
||||
@@ -918,13 +1008,20 @@ async def purchase_devices(
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to send admin notification for device purchase: {e}')
|
||||
|
||||
return {
|
||||
response = {
|
||||
'message': 'Devices added successfully',
|
||||
'devices_added': request.devices,
|
||||
'new_device_limit': new_devices,
|
||||
'amount_paid_kopeks': total_price,
|
||||
}
|
||||
|
||||
if devices_discount_percent > 0:
|
||||
response['discount_percent'] = devices_discount_percent
|
||||
response['discount_kopeks'] = discount_result['discount']
|
||||
response['base_price_kopeks'] = base_total_price
|
||||
|
||||
return response
|
||||
|
||||
|
||||
@router.patch('/autopay')
|
||||
async def update_autopay(
|
||||
@@ -2065,9 +2162,21 @@ async def purchase_devices(
|
||||
days_left = max(1, (end_date - now).days)
|
||||
total_days = 30 # Base period for device price calculation
|
||||
|
||||
# Price = device_price * devices * (days_left / 30)
|
||||
price_kopeks = int(device_price * request.devices * days_left / total_days)
|
||||
price_kopeks = max(100, price_kopeks) # Minimum 1 ruble
|
||||
# Calculate base price before discount
|
||||
base_price_per_month = device_price * request.devices
|
||||
base_price_prorated = int(base_price_per_month * days_left / total_days)
|
||||
base_price_prorated = max(100, base_price_prorated) # Minimum 1 ruble
|
||||
|
||||
# Apply discount from promo group
|
||||
period_hint_days = days_left
|
||||
discount_result = _apply_addon_discount(user, 'devices', base_price_prorated, period_hint_days)
|
||||
price_kopeks = discount_result['discounted']
|
||||
devices_discount_percent = discount_result['percent']
|
||||
discount_value = discount_result['discount']
|
||||
|
||||
# Ensure minimum price after discount (except for 100% discount)
|
||||
if devices_discount_percent < 100:
|
||||
price_kopeks = max(100, price_kopeks)
|
||||
|
||||
# Check balance
|
||||
if user.balance_kopeks < price_kopeks:
|
||||
@@ -2079,10 +2188,15 @@ async def purchase_devices(
|
||||
'cart_mode': 'add_devices',
|
||||
'devices_to_add': request.devices,
|
||||
'price_kopeks': price_kopeks,
|
||||
'base_price_kopeks': base_price_prorated,
|
||||
'discount_percent': devices_discount_percent,
|
||||
'source': 'cabinet',
|
||||
}
|
||||
await user_cart_service.save_user_cart(user.id, cart_data)
|
||||
logger.info(f'Cart saved for device purchase (cabinet) user {user.id}: +{request.devices} devices')
|
||||
logger.info(
|
||||
f'Cart saved for device purchase (cabinet) user {user.id}: '
|
||||
f'+{request.devices} devices, discount {devices_discount_percent}%'
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f'Error saving cart for device purchase (cabinet): {e}')
|
||||
|
||||
@@ -2102,11 +2216,17 @@ async def purchase_devices(
|
||||
from app.database.crud.user import subtract_user_balance
|
||||
from app.database.models import PaymentMethod
|
||||
|
||||
# Build description with discount info
|
||||
if devices_discount_percent > 0:
|
||||
description = f'Покупка {request.devices} доп. устройств (скидка {devices_discount_percent}%)'
|
||||
else:
|
||||
description = f'Покупка {request.devices} доп. устройств'
|
||||
|
||||
await subtract_user_balance(
|
||||
db=db,
|
||||
user=user,
|
||||
amount_kopeks=price_kopeks,
|
||||
description=f'Покупка {request.devices} доп. устройств',
|
||||
description=description,
|
||||
create_transaction=True,
|
||||
payment_method=PaymentMethod.BALANCE,
|
||||
)
|
||||
@@ -2128,7 +2248,13 @@ async def purchase_devices(
|
||||
|
||||
await db.refresh(user)
|
||||
|
||||
logger.info(f'User {user.id} purchased {request.devices} devices for {price_kopeks} kopeks')
|
||||
if devices_discount_percent > 0:
|
||||
logger.info(
|
||||
f'User {user.id} purchased {request.devices} devices for {price_kopeks} kopeks '
|
||||
f'(discount {devices_discount_percent}%, saved {discount_value} kopeks)'
|
||||
)
|
||||
else:
|
||||
logger.info(f'User {user.id} purchased {request.devices} devices for {price_kopeks} kopeks')
|
||||
|
||||
# Отправляем уведомление админам
|
||||
try:
|
||||
@@ -2154,7 +2280,7 @@ async def purchase_devices(
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to send admin notification for device purchase: {e}')
|
||||
|
||||
return {
|
||||
response = {
|
||||
'success': True,
|
||||
'message': f'Добавлено {request.devices} устройств',
|
||||
'devices_added': request.devices,
|
||||
@@ -2165,6 +2291,13 @@ async def purchase_devices(
|
||||
'balance_label': settings.format_price(user.balance_kopeks),
|
||||
}
|
||||
|
||||
if devices_discount_percent > 0:
|
||||
response['discount_percent'] = devices_discount_percent
|
||||
response['discount_kopeks'] = discount_value
|
||||
response['base_price_kopeks'] = base_price_prorated
|
||||
|
||||
return response
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
@@ -2435,11 +2568,24 @@ async def get_device_price(
|
||||
days_left = max(1, (end_date - now).days)
|
||||
total_days = 30
|
||||
|
||||
price_per_device_kopeks = int(device_price * days_left / total_days)
|
||||
price_per_device_kopeks = max(100, price_per_device_kopeks)
|
||||
total_price_kopeks = price_per_device_kopeks * devices
|
||||
# Calculate base price before discount
|
||||
base_price_per_device = int(device_price * days_left / total_days)
|
||||
base_price_per_device = max(100, base_price_per_device)
|
||||
base_total_price = base_price_per_device * devices
|
||||
|
||||
return {
|
||||
# Apply discount from promo group
|
||||
period_hint_days = days_left
|
||||
discount_result = _apply_addon_discount(user, 'devices', base_total_price, period_hint_days)
|
||||
total_price_kopeks = discount_result['discounted']
|
||||
devices_discount_percent = discount_result['percent']
|
||||
discount_value = discount_result['discount']
|
||||
|
||||
# Calculate per-device price after discount
|
||||
if devices_discount_percent < 100 and total_price_kopeks > 0:
|
||||
total_price_kopeks = max(100, total_price_kopeks)
|
||||
price_per_device_kopeks = total_price_kopeks // devices if devices > 0 else 0
|
||||
|
||||
response = {
|
||||
'available': True,
|
||||
'devices': devices,
|
||||
'price_per_device_kopeks': price_per_device_kopeks,
|
||||
@@ -2453,6 +2599,14 @@ async def get_device_price(
|
||||
'base_device_price_kopeks': device_price,
|
||||
}
|
||||
|
||||
# Add discount info if applicable
|
||||
if devices_discount_percent > 0:
|
||||
response['discount_percent'] = devices_discount_percent
|
||||
response['discount_kopeks'] = discount_value
|
||||
response['base_total_price_kopeks'] = base_total_price
|
||||
|
||||
return response
|
||||
|
||||
|
||||
# ============ App Config for Connection ============
|
||||
|
||||
@@ -3723,18 +3877,35 @@ async def preview_tariff_switch(
|
||||
return int(min_price * 30 / min_period)
|
||||
return 0
|
||||
|
||||
# Get period discount percent for cost calculation
|
||||
period_discount_percent = _get_period_discount_percent(user, remaining_days if remaining_days > 0 else 30)
|
||||
base_upgrade_cost = 0
|
||||
discount_value = 0
|
||||
|
||||
if switching_to_daily:
|
||||
# Switching TO daily - pay first day price
|
||||
daily_price = getattr(new_tariff, 'daily_price_kopeks', 0)
|
||||
upgrade_cost = daily_price
|
||||
is_upgrade = daily_price > 0
|
||||
base_upgrade_cost = daily_price
|
||||
# Apply discount to daily price
|
||||
if period_discount_percent > 0 and base_upgrade_cost > 0:
|
||||
discount_value = int(base_upgrade_cost * period_discount_percent / 100)
|
||||
upgrade_cost = base_upgrade_cost - discount_value
|
||||
else:
|
||||
upgrade_cost = base_upgrade_cost
|
||||
is_upgrade = upgrade_cost > 0
|
||||
elif switching_from_daily:
|
||||
# Switching FROM daily TO periodic - full payment for new tariff
|
||||
min_period_price = 0
|
||||
if new_tariff.period_prices:
|
||||
min_period_price = min(new_tariff.period_prices.values())
|
||||
upgrade_cost = min_period_price
|
||||
is_upgrade = min_period_price > 0
|
||||
base_upgrade_cost = min_period_price
|
||||
# Apply discount
|
||||
if period_discount_percent > 0 and base_upgrade_cost > 0:
|
||||
discount_value = int(base_upgrade_cost * period_discount_percent / 100)
|
||||
upgrade_cost = base_upgrade_cost - discount_value
|
||||
else:
|
||||
upgrade_cost = base_upgrade_cost
|
||||
is_upgrade = upgrade_cost > 0
|
||||
else:
|
||||
# Calculate proportional cost difference using monthly prices
|
||||
current_monthly = get_monthly_price(current_tariff)
|
||||
@@ -3744,18 +3915,25 @@ async def preview_tariff_switch(
|
||||
|
||||
if price_diff > 0:
|
||||
# Upgrade - pay proportional difference
|
||||
upgrade_cost = int(price_diff * remaining_days / 30)
|
||||
base_upgrade_cost = int(price_diff * remaining_days / 30)
|
||||
# Apply discount to upgrade cost
|
||||
if period_discount_percent > 0 and base_upgrade_cost > 0:
|
||||
discount_value = int(base_upgrade_cost * period_discount_percent / 100)
|
||||
upgrade_cost = base_upgrade_cost - discount_value
|
||||
else:
|
||||
upgrade_cost = base_upgrade_cost
|
||||
is_upgrade = True
|
||||
else:
|
||||
# Downgrade or same - free
|
||||
upgrade_cost = 0
|
||||
base_upgrade_cost = 0
|
||||
is_upgrade = False
|
||||
|
||||
balance = user.balance_kopeks or 0
|
||||
has_enough = balance >= upgrade_cost
|
||||
missing = max(0, upgrade_cost - balance) if not has_enough else 0
|
||||
|
||||
return {
|
||||
response = {
|
||||
'can_switch': has_enough,
|
||||
'current_tariff_id': current_tariff.id if current_tariff else None,
|
||||
'current_tariff_name': current_tariff.name if current_tariff else None,
|
||||
@@ -3772,6 +3950,14 @@ async def preview_tariff_switch(
|
||||
'is_upgrade': is_upgrade,
|
||||
}
|
||||
|
||||
# Add discount info if applicable
|
||||
if period_discount_percent > 0 and discount_value > 0:
|
||||
response['discount_percent'] = period_discount_percent
|
||||
response['discount_kopeks'] = discount_value
|
||||
response['base_upgrade_cost_kopeks'] = base_upgrade_cost
|
||||
|
||||
return response
|
||||
|
||||
|
||||
@router.post('/tariff/switch')
|
||||
async def switch_tariff(
|
||||
@@ -3857,6 +4043,11 @@ async def switch_tariff(
|
||||
switching_from_daily = current_is_daily and not new_is_daily
|
||||
switching_to_daily = not current_is_daily and new_is_daily
|
||||
|
||||
# Get period discount percent for cost calculation
|
||||
period_discount_percent = _get_period_discount_percent(user, remaining_days if remaining_days > 0 else 30)
|
||||
base_upgrade_cost = 0
|
||||
discount_value = 0
|
||||
|
||||
if switching_to_daily:
|
||||
# Switching TO daily tariff - charge first day price
|
||||
daily_price = getattr(new_tariff, 'daily_price_kopeks', 0)
|
||||
@@ -3865,7 +4056,13 @@ async def switch_tariff(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail='Daily tariff has invalid price',
|
||||
)
|
||||
upgrade_cost = daily_price
|
||||
base_upgrade_cost = daily_price
|
||||
# Apply discount
|
||||
if period_discount_percent > 0 and base_upgrade_cost > 0:
|
||||
discount_value = int(base_upgrade_cost * period_discount_percent / 100)
|
||||
upgrade_cost = base_upgrade_cost - discount_value
|
||||
else:
|
||||
upgrade_cost = base_upgrade_cost
|
||||
new_period_days = 1 # Daily tariff starts with 1 day
|
||||
elif switching_from_daily:
|
||||
# Switch FROM daily to regular tariff - pay for minimum period
|
||||
@@ -3874,7 +4071,13 @@ async def switch_tariff(
|
||||
if new_tariff.period_prices:
|
||||
min_period_days = min(int(k) for k in new_tariff.period_prices.keys())
|
||||
min_period_price = new_tariff.period_prices.get(str(min_period_days), 0)
|
||||
upgrade_cost = min_period_price
|
||||
base_upgrade_cost = min_period_price
|
||||
# Apply discount
|
||||
if period_discount_percent > 0 and base_upgrade_cost > 0:
|
||||
discount_value = int(base_upgrade_cost * period_discount_percent / 100)
|
||||
upgrade_cost = base_upgrade_cost - discount_value
|
||||
else:
|
||||
upgrade_cost = base_upgrade_cost
|
||||
new_period_days = min_period_days
|
||||
else:
|
||||
# Regular tariff switch - calculate proportional cost difference using monthly prices
|
||||
@@ -3899,9 +4102,16 @@ async def switch_tariff(
|
||||
price_diff = new_monthly - current_monthly
|
||||
|
||||
if price_diff > 0:
|
||||
upgrade_cost = int(price_diff * remaining_days / 30)
|
||||
base_upgrade_cost = int(price_diff * remaining_days / 30)
|
||||
# Apply discount
|
||||
if period_discount_percent > 0 and base_upgrade_cost > 0:
|
||||
discount_value = int(base_upgrade_cost * period_discount_percent / 100)
|
||||
upgrade_cost = base_upgrade_cost - discount_value
|
||||
else:
|
||||
upgrade_cost = base_upgrade_cost
|
||||
else:
|
||||
upgrade_cost = 0
|
||||
base_upgrade_cost = 0
|
||||
new_period_days = 0
|
||||
|
||||
# Charge if upgrade
|
||||
@@ -3924,6 +4134,10 @@ async def switch_tariff(
|
||||
else:
|
||||
description = f"Переход на тариф '{new_tariff.name}' (доплата за {remaining_days} дней)"
|
||||
|
||||
# Add discount info to description if applicable
|
||||
if period_discount_percent > 0 and discount_value > 0:
|
||||
description += f' (скидка {period_discount_percent}%)'
|
||||
|
||||
success = await subtract_user_balance(db, user, upgrade_cost, description)
|
||||
if not success:
|
||||
raise HTTPException(
|
||||
@@ -4018,7 +4232,7 @@ async def switch_tariff(
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to send admin notification for tariff switch: {e}')
|
||||
|
||||
return {
|
||||
response = {
|
||||
'success': True,
|
||||
'message': f"Switched from '{old_tariff_name}' to '{new_tariff.name}'"
|
||||
+ (' (devices reset)' if devices_reset else ''),
|
||||
@@ -4031,6 +4245,14 @@ async def switch_tariff(
|
||||
'balance_label': settings.format_price(user.balance_kopeks),
|
||||
}
|
||||
|
||||
# Add discount info if applicable
|
||||
if period_discount_percent > 0 and discount_value > 0:
|
||||
response['discount_percent'] = period_discount_percent
|
||||
response['discount_kopeks'] = discount_value
|
||||
response['base_charged_kopeks'] = base_upgrade_cost
|
||||
|
||||
return response
|
||||
|
||||
|
||||
# ============ Daily Subscription Pause ============
|
||||
|
||||
|
||||
Reference in New Issue
Block a user