Fix addon discount calculations and server availability

This commit is contained in:
Egor
2025-09-25 14:06:18 +03:00
parent 147cbfa625
commit fbecf5bf7a
2 changed files with 458 additions and 80 deletions

View File

@@ -62,6 +62,7 @@ from app.utils.pricing_utils import (
calculate_prorated_price,
validate_pricing_calculation,
format_period_description,
apply_percentage_discount,
)
from app.utils.pagination import paginate_list
from app.utils.subscription_utils import (
@@ -74,13 +75,59 @@ logger = logging.getLogger(__name__)
TRAFFIC_PRICES = get_traffic_prices()
def _get_addon_discount_percent_for_user(
user: Optional[User],
category: str,
period_days_hint: Optional[int] = None,
) -> int:
if user is None:
return 0
promo_group = 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_hint)
except AttributeError:
return 0
def _apply_addon_discount(
user: Optional[User],
category: str,
amount: int,
period_days_hint: Optional[int] = None,
) -> Dict[str, int]:
percent = _get_addon_discount_percent_for_user(user, category, period_days_hint)
discounted_amount, discount_value = apply_percentage_discount(amount, percent)
return {
"discounted": discounted_amount,
"discount": discount_value,
"percent": percent,
}
def _get_period_hint_from_subscription(subscription: Optional[Subscription]) -> Optional[int]:
if not subscription:
return None
months_remaining = get_remaining_months(subscription.end_date)
if months_remaining <= 0:
return None
return months_remaining * 30
def _apply_discount_to_monthly_component(
amount_per_month: int,
percent: int,
months: int,
) -> Dict[str, int]:
from app.utils.pricing_utils import apply_percentage_discount
discounted_per_month, discount_per_month = apply_percentage_discount(amount_per_month, percent)
return {
@@ -1110,13 +1157,20 @@ async def handle_add_countries(
texts = get_texts(db_user.language)
subscription = db_user.subscription
if not subscription or subscription.is_trial:
await callback.answer("⚠ Эта функция доступна только для платных подписок", show_alert=True)
return
countries = await _get_available_countries(db_user.promo_group_id)
current_countries = subscription.connected_squads
period_hint_days = _get_period_hint_from_subscription(subscription)
servers_discount_percent = _get_addon_discount_percent_for_user(
db_user,
"servers",
period_hint_days,
)
current_countries_names = []
for country in countries:
@@ -1142,11 +1196,12 @@ async def handle_add_countries(
await callback.message.edit_text(
text,
reply_markup=get_manage_countries_keyboard(
countries,
current_countries.copy(),
current_countries,
countries,
current_countries.copy(),
current_countries,
db_user.language,
subscription.end_date
subscription.end_date,
servers_discount_percent,
),
parse_mode="HTML"
)
@@ -1228,14 +1283,22 @@ async def handle_manage_country(
await state.update_data(countries=current_selected)
period_hint_days = _get_period_hint_from_subscription(subscription)
servers_discount_percent = _get_addon_discount_percent_for_user(
db_user,
"servers",
period_hint_days,
)
try:
await callback.message.edit_reply_markup(
reply_markup=get_manage_countries_keyboard(
countries,
current_selected,
subscription.connected_squads,
current_selected,
subscription.connected_squads,
db_user.language,
subscription.end_date
subscription.end_date,
servers_discount_percent,
)
)
logger.info(f"✅ Клавиатура обновлена")
@@ -1288,30 +1351,62 @@ async def apply_countries_changes(
logger.info(f"🔧 Добавлено: {added}, Удалено: {removed}")
months_to_pay = get_remaining_months(subscription.end_date)
period_hint_days = months_to_pay * 30 if months_to_pay > 0 else None
servers_discount_percent = _get_addon_discount_percent_for_user(
db_user,
"servers",
period_hint_days,
)
cost_per_month = 0
added_names = []
removed_names = []
added_server_prices = []
added_server_components: List[Dict[str, int]] = []
for country in countries:
if not country.get('is_available', True):
continue
if country['uuid'] in added:
server_price_per_month = country['price_kopeks']
cost_per_month += server_price_per_month
discounted_per_month, discount_per_month = apply_percentage_discount(
server_price_per_month,
servers_discount_percent,
)
cost_per_month += discounted_per_month
added_names.append(country['name'])
added_server_components.append(
{
"discounted_per_month": discounted_per_month,
"discount_per_month": discount_per_month,
"original_per_month": server_price_per_month,
}
)
if country['uuid'] in removed:
removed_names.append(country['name'])
total_cost, charged_months = calculate_prorated_price(cost_per_month, subscription.end_date)
for country in countries:
if country['uuid'] in added:
server_price_per_month = country['price_kopeks']
server_total_price = server_price_per_month * charged_months
added_server_prices.append(server_total_price)
logger.info(f"Стоимость новых серверов: {cost_per_month/100}₽/мес × {charged_months} мес = {total_cost/100}")
added_server_prices = [
component["discounted_per_month"] * charged_months
for component in added_server_components
]
total_discount = sum(
component["discount_per_month"] * charged_months
for component in added_server_components
)
if added_names:
logger.info(
"Стоимость новых серверов: %.2f₽/мес × %s мес = %.2f₽ (скидка %.2f₽)",
cost_per_month / 100,
charged_months,
total_cost / 100,
total_discount / 100,
)
if total_cost > 0 and db_user.balance_kopeks < total_cost:
missing_kopeks = total_cost - db_user.balance_kopeks
@@ -1398,6 +1493,11 @@ async def apply_countries_changes(
success_text += "\n".join(f"{name}" for name in added_names)
if total_cost > 0:
success_text += f"\n💰 Списано: {texts.format_price(total_cost)} (за {charged_months} мес)"
if total_discount > 0:
success_text += (
f" (скидка {servers_discount_percent}%:"
f" -{texts.format_price(total_discount)})"
)
success_text += "\n"
if removed_names:
@@ -1449,12 +1549,22 @@ async def handle_add_traffic(
return
current_traffic = subscription.traffic_limit_gb
period_hint_days = _get_period_hint_from_subscription(subscription)
traffic_discount_percent = _get_addon_discount_percent_for_user(
db_user,
"traffic",
period_hint_days,
)
await callback.message.edit_text(
f"📈 <b>Добавить трафик к подписке</b>\n\n"
f"Текущий лимит: {texts.format_traffic(current_traffic)}\n"
f"Выберите дополнительный трафик:",
reply_markup=get_add_traffic_keyboard(db_user.language, subscription.end_date),
reply_markup=get_add_traffic_keyboard(
db_user.language,
subscription.end_date,
traffic_discount_percent,
),
parse_mode="HTML"
)
@@ -1474,7 +1584,14 @@ async def handle_change_devices(
return
current_devices = subscription.device_limit
period_hint_days = _get_period_hint_from_subscription(subscription)
devices_discount_percent = _get_addon_discount_percent_for_user(
db_user,
"devices",
period_hint_days,
)
await callback.message.edit_text(
f"📱 <b>Изменение количества устройств</b>\n\n"
f"Текущий лимит: {current_devices} устройств\n"
@@ -1482,7 +1599,12 @@ async def handle_change_devices(
f"💡 <b>Важно:</b>\n"
f"• При увеличении - доплата пропорционально оставшемуся времени\n"
f"• При уменьшении - возврат средств не производится",
reply_markup=get_change_devices_keyboard(current_devices, db_user.language, subscription.end_date),
reply_markup=get_change_devices_keyboard(
current_devices,
db_user.language,
subscription.end_date,
devices_discount_percent,
),
parse_mode="HTML"
)
@@ -1524,7 +1646,22 @@ async def confirm_change_devices(
chargeable_devices = additional_devices
devices_price_per_month = chargeable_devices * settings.PRICE_PER_DEVICE
price, charged_months = calculate_prorated_price(devices_price_per_month, subscription.end_date)
months_hint = get_remaining_months(subscription.end_date)
period_hint_days = months_hint * 30 if months_hint > 0 else None
devices_discount_percent = _get_addon_discount_percent_for_user(
db_user,
"devices",
period_hint_days,
)
discounted_per_month, discount_per_month = apply_percentage_discount(
devices_price_per_month,
devices_discount_percent,
)
price, charged_months = calculate_prorated_price(
discounted_per_month,
subscription.end_date,
)
total_discount = discount_per_month * charged_months
if price > 0 and db_user.balance_kopeks < price:
missing_kopeks = price - db_user.balance_kopeks
@@ -1556,7 +1693,15 @@ async def confirm_change_devices(
return
action_text = f"увеличить до {new_devices_count}"
cost_text = f"Доплата: {texts.format_price(price)} (за {charged_months} мес)" if price > 0 else "Бесплатно"
if price > 0:
cost_text = f"Доплата: {texts.format_price(price)} (за {charged_months} мес)"
if total_discount > 0:
cost_text += (
f" (скидка {devices_discount_percent}%:"
f" -{texts.format_price(total_discount)})"
)
else:
cost_text = "Бесплатно"
else:
price = 0
@@ -2139,9 +2284,31 @@ async def confirm_add_devices(
return
devices_price_per_month = devices_count * settings.PRICE_PER_DEVICE
price, charged_months = calculate_prorated_price(devices_price_per_month, subscription.end_date)
logger.info(f"Добавление {devices_count} устройств: {devices_price_per_month/100}₽/мес × {charged_months} мес = {price/100}")
months_hint = get_remaining_months(subscription.end_date)
period_hint_days = months_hint * 30 if months_hint > 0 else None
devices_discount_percent = _get_addon_discount_percent_for_user(
db_user,
"devices",
period_hint_days,
)
discounted_per_month, discount_per_month = apply_percentage_discount(
devices_price_per_month,
devices_discount_percent,
)
price, charged_months = calculate_prorated_price(
discounted_per_month,
subscription.end_date,
)
total_discount = discount_per_month * charged_months
logger.info(
"Добавление %s устройств: %.2f₽/мес × %s мес = %.2f₽ (скидка %.2f₽)",
devices_count,
discounted_per_month / 100,
charged_months,
price / 100,
total_discount / 100,
)
if db_user.balance_kopeks < price:
missing_kopeks = price - db_user.balance_kopeks
@@ -2200,11 +2367,20 @@ async def confirm_add_devices(
await db.refresh(db_user)
await db.refresh(subscription)
await callback.message.edit_text(
f"✅ Устройства успешно добавлены!\n\n"
success_text = (
"✅ Устройства успешно добавлены!\n\n"
f"📱 Добавлено: {devices_count} устройств\n"
f"Новый лимит: {subscription.device_limit} устройств\n"
f"💰 Списано: {texts.format_price(price)} (за {charged_months} мес)",
)
success_text += f"💰 Списано: {texts.format_price(price)} (за {charged_months} мес)"
if total_discount > 0:
success_text += (
f" (скидка {devices_discount_percent}%:"
f" -{texts.format_price(total_discount)})"
)
await callback.message.edit_text(
success_text,
reply_markup=get_back_keyboard(db_user.language)
)
@@ -3501,12 +3677,34 @@ async def add_traffic(
texts = get_texts(db_user.language)
subscription = db_user.subscription
price = settings.get_traffic_price(traffic_gb)
if price == 0 and traffic_gb != 0:
base_price = settings.get_traffic_price(traffic_gb)
if base_price == 0 and traffic_gb != 0:
await callback.answer("⚠️ Цена для этого пакета не настроена", show_alert=True)
return
period_hint_days = _get_period_hint_from_subscription(subscription)
discount_result = _apply_addon_discount(
db_user,
"traffic",
base_price,
period_hint_days,
)
discounted_per_month = discount_result["discounted"]
discount_per_month = discount_result["discount"]
charged_months = 1
if subscription:
price, charged_months = calculate_prorated_price(
discounted_per_month,
subscription.end_date,
)
else:
price = discounted_per_month
total_discount_value = discount_per_month * charged_months
if db_user.balance_kopeks < price:
missing_kopeks = price - db_user.balance_kopeks
message_text = texts.t(
@@ -3537,8 +3735,10 @@ async def add_traffic(
try:
success = await subtract_user_balance(
db, db_user, price,
f"Добавление {traffic_gb} ГБ трафика"
db,
db_user,
price,
f"Добавление {traffic_gb} ГБ трафика",
)
if not success:
@@ -3558,7 +3758,7 @@ async def add_traffic(
user_id=db_user.id,
type=TransactionType.SUBSCRIPTION_PAYMENT,
amount_kopeks=price,
description=f"Добавление {traffic_gb} ГБ трафика"
description=f"Добавление {traffic_gb} ГБ трафика",
)
@@ -3571,7 +3771,15 @@ async def add_traffic(
else:
success_text += f"📈 Добавлено: {traffic_gb} ГБ\n"
success_text += f"Новый лимит: {texts.format_traffic(subscription.traffic_limit_gb)}"
if price > 0:
success_text += f"\n💰 Списано: {texts.format_price(price)}"
if total_discount_value > 0:
success_text += (
f" (скидка {discount_result['percent']}%:"
f" -{texts.format_price(total_discount_value)})"
)
await callback.message.edit_text(
success_text,
reply_markup=get_back_keyboard(db_user.language)
@@ -3830,7 +4038,15 @@ async def _get_available_countries(promo_group_id: Optional[int] = None):
available_servers = await get_available_server_squads(
db, promo_group_id=promo_group_id
)
if promo_group_id is not None and not available_servers:
logger.info(
"Промогруппа %s не имеет доступных серверов, возврат пустого списка",
promo_group_id,
)
await cache.set(cache_key_value, [], 60)
return []
countries = []
for server in available_servers:
countries.append({
@@ -3926,21 +4142,50 @@ async def handle_add_country_to_subscription(
logger.info(f"🔍 Добавлена страна: {country_uuid}")
total_price = 0
subscription = db_user.subscription
period_hint_days = _get_period_hint_from_subscription(subscription)
servers_discount_percent = _get_addon_discount_percent_for_user(
db_user,
"servers",
period_hint_days,
)
for country in countries:
if country['uuid'] in selected_countries and country['uuid'] not in db_user.subscription.connected_squads:
total_price += country['price_kopeks']
if not country.get('is_available', True):
continue
if (
country['uuid'] in selected_countries
and country['uuid'] not in subscription.connected_squads
):
server_price = country['price_kopeks']
if servers_discount_percent > 0 and server_price > 0:
discounted_price, _ = apply_percentage_discount(
server_price,
servers_discount_percent,
)
else:
discounted_price = server_price
total_price += discounted_price
data['countries'] = selected_countries
data['total_price'] = total_price
await state.set_data(data)
logger.info(f"🔍 Новые выбранные страны: {selected_countries}")
logger.info(f"🔍 Общая стоимость: {total_price}")
try:
from app.keyboards.inline import get_manage_countries_keyboard
await callback.message.edit_reply_markup(
reply_markup=get_manage_countries_keyboard(countries, selected_countries, db_user.subscription.connected_squads, db_user.language)
reply_markup=get_manage_countries_keyboard(
countries,
selected_countries,
subscription.connected_squads,
db_user.language,
subscription.end_date,
servers_discount_percent,
)
)
logger.info(f"✅ Клавиатура обновлена")
except Exception as e:
@@ -3992,10 +4237,37 @@ async def confirm_add_countries_to_subscription(
total_price = 0
new_countries_names = []
removed_countries_names = []
period_hint_days = _get_period_hint_from_subscription(subscription)
servers_discount_percent = _get_addon_discount_percent_for_user(
db_user,
"servers",
period_hint_days,
)
total_discount_value = 0
for country in countries:
if not country.get('is_available', True):
continue
if country['uuid'] in new_countries:
total_price += country['price_kopeks']
server_price = country['price_kopeks']
if servers_discount_percent > 0 and server_price > 0:
discounted_per_month, discount_per_month = apply_percentage_discount(
server_price,
servers_discount_percent,
)
else:
discounted_per_month = server_price
discount_per_month = 0
charged_price, charged_months = calculate_prorated_price(
discounted_per_month,
subscription.end_date,
)
total_price += charged_price
total_discount_value += discount_per_month * charged_months
new_countries_names.append(country['name'])
if country['uuid'] in removed_countries:
removed_countries_names.append(country['name'])
@@ -4051,7 +4323,7 @@ async def confirm_add_countries_to_subscription(
subscription.connected_squads = selected_countries
subscription.updated_at = datetime.utcnow()
await db.commit()
subscription_service = SubscriptionService()
await subscription_service.update_remnawave_user(db, subscription)
@@ -4063,7 +4335,13 @@ async def confirm_add_countries_to_subscription(
if new_countries_names:
success_text += f" Добавлены страны:\n{chr(10).join(f'{name}' for name in new_countries_names)}\n"
if total_price > 0:
success_text += f"💰 Списано: {texts.format_price(total_price)}\n"
success_text += f"💰 Списано: {texts.format_price(total_price)}"
if total_discount_value > 0:
success_text += (
f" (скидка {servers_discount_percent}%:"
f" -{texts.format_price(total_discount_value)})"
)
success_text += "\n"
if removed_countries_names:
success_text += f"\n Отключены страны:\n{chr(10).join(f'{name}' for name in removed_countries_names)}\n"
@@ -4880,7 +5158,13 @@ async def handle_switch_traffic(
return
current_traffic = subscription.traffic_limit_gb
period_hint_days = _get_period_hint_from_subscription(subscription)
traffic_discount_percent = _get_addon_discount_percent_for_user(
db_user,
"traffic",
period_hint_days,
)
await callback.message.edit_text(
f"🔄 <b>Переключение лимита трафика</b>\n\n"
f"Текущий лимит: {texts.format_traffic(current_traffic)}\n"
@@ -4888,7 +5172,12 @@ async def handle_switch_traffic(
f"💡 <b>Важно:</b>\n"
f"• При увеличении - доплата за разницу\n"
f"• При уменьшении - возврат средств не производится",
reply_markup=get_traffic_switch_keyboard(current_traffic, db_user.language, subscription.end_date),
reply_markup=get_traffic_switch_keyboard(
current_traffic,
db_user.language,
subscription.end_date,
traffic_discount_percent,
),
parse_mode="HTML"
)
@@ -4914,13 +5203,31 @@ async def confirm_switch_traffic(
old_price_per_month = settings.get_traffic_price(current_traffic)
new_price_per_month = settings.get_traffic_price(new_traffic_gb)
months_remaining = get_remaining_months(subscription.end_date)
price_difference_per_month = new_price_per_month - old_price_per_month
period_hint_days = months_remaining * 30 if months_remaining > 0 else None
traffic_discount_percent = _get_addon_discount_percent_for_user(
db_user,
"traffic",
period_hint_days,
)
discounted_old_per_month, _ = apply_percentage_discount(
old_price_per_month,
traffic_discount_percent,
)
discounted_new_per_month, _ = apply_percentage_discount(
new_price_per_month,
traffic_discount_percent,
)
price_difference_per_month = discounted_new_per_month - discounted_old_per_month
discount_savings_per_month = (
(new_price_per_month - old_price_per_month) - price_difference_per_month
)
if price_difference_per_month > 0:
total_price_difference = price_difference_per_month * months_remaining
if db_user.balance_kopeks < total_price_difference:
missing_kopeks = total_price_difference - db_user.balance_kopeks
message_text = texts.t(
@@ -4951,6 +5258,12 @@ async def confirm_switch_traffic(
action_text = f"увеличить до {texts.format_traffic(new_traffic_gb)}"
cost_text = f"Доплата: {texts.format_price(total_price_difference)} (за {months_remaining} мес)"
if discount_savings_per_month > 0:
total_discount_savings = discount_savings_per_month * months_remaining
cost_text += (
f" (скидка {traffic_discount_percent}%:"
f" -{texts.format_price(total_discount_savings)})"
)
else:
total_price_difference = 0
action_text = f"уменьшить до {texts.format_traffic(new_traffic_gb)}"
@@ -5070,9 +5383,10 @@ async def execute_switch_traffic(
def get_traffic_switch_keyboard(
current_traffic_gb: int,
language: str = "ru",
subscription_end_date: datetime = None
current_traffic_gb: int,
language: str = "ru",
subscription_end_date: datetime = None,
discount_percent: int = 0,
) -> InlineKeyboardMarkup:
from app.utils.pricing_utils import get_remaining_months
from app.config import settings
@@ -5088,16 +5402,24 @@ def get_traffic_switch_keyboard(
enabled_packages = [pkg for pkg in packages if pkg['enabled']]
current_price_per_month = settings.get_traffic_price(current_traffic_gb)
discounted_current_per_month, _ = apply_percentage_discount(
current_price_per_month,
discount_percent,
)
buttons = []
for package in enabled_packages:
gb = package['gb']
price_per_month = package['price']
price_diff_per_month = price_per_month - current_price_per_month
discounted_price_per_month, _ = apply_percentage_discount(
price_per_month,
discount_percent,
)
price_diff_per_month = discounted_price_per_month - discounted_current_per_month
total_price_diff = price_diff_per_month * months_multiplier
if gb == current_traffic_gb:
emoji = ""
action_text = " (текущий)"
@@ -5106,6 +5428,13 @@ def get_traffic_switch_keyboard(
emoji = "⬆️"
action_text = ""
price_text = f" (+{total_price_diff//100}{period_text})"
if discount_percent > 0:
discount_total = (
(price_per_month - current_price_per_month) * months_multiplier
- total_price_diff
)
if discount_total > 0:
price_text += f" (скидка {discount_percent}%: -{discount_total//100}₽)"
elif total_price_diff < 0:
emoji = "⬇️"
action_text = ""

View File

@@ -8,7 +8,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
from app.config import settings, PERIOD_PRICES, TRAFFIC_PRICES
from app.localization.loader import DEFAULT_LANGUAGE
from app.localization.texts import get_texts
from app.utils.pricing_utils import format_period_description
from app.utils.pricing_utils import format_period_description, apply_percentage_discount
from app.utils.subscription_utils import (
get_display_subscription_link,
get_happ_cryptolink_redirect_link,
@@ -1123,7 +1123,11 @@ def get_extend_subscription_keyboard(language: str = DEFAULT_LANGUAGE) -> Inline
return InlineKeyboardMarkup(inline_keyboard=keyboard)
def get_add_traffic_keyboard(language: str = DEFAULT_LANGUAGE, subscription_end_date: datetime = None) -> InlineKeyboardMarkup:
def get_add_traffic_keyboard(
language: str = DEFAULT_LANGUAGE,
subscription_end_date: datetime = None,
discount_percent: int = 0,
) -> InlineKeyboardMarkup:
from app.utils.pricing_utils import get_remaining_months
from app.config import settings
texts = get_texts(language)
@@ -1155,8 +1159,13 @@ def get_add_traffic_keyboard(language: str = DEFAULT_LANGUAGE, subscription_end_
for package in enabled_packages:
gb = package['gb']
price_per_month = package['price']
total_price = price_per_month * months_multiplier
discounted_per_month, discount_per_month = apply_percentage_discount(
price_per_month,
discount_percent,
)
total_price = discounted_per_month * months_multiplier
total_discount = discount_per_month * months_multiplier
if gb == 0:
if language == "ru":
text = f"♾️ Безлимитный трафик - {total_price//100}{period_text}"
@@ -1167,7 +1176,10 @@ def get_add_traffic_keyboard(language: str = DEFAULT_LANGUAGE, subscription_end_
text = f"📊 +{gb} ГБ трафика - {total_price//100}{period_text}"
else:
text = f"📊 +{gb} GB traffic - {total_price//100}{period_text}"
if discount_percent > 0 and total_discount > 0:
text += f" (скидка {discount_percent}%: -{total_discount//100}₽)"
buttons.append([
InlineKeyboardButton(text=text, callback_data=f"add_traffic_{gb}")
])
@@ -1181,7 +1193,12 @@ def get_add_traffic_keyboard(language: str = DEFAULT_LANGUAGE, subscription_end_
return InlineKeyboardMarkup(inline_keyboard=buttons)
def get_change_devices_keyboard(current_devices: int, language: str = DEFAULT_LANGUAGE, subscription_end_date: datetime = None) -> InlineKeyboardMarkup:
def get_change_devices_keyboard(
current_devices: int,
language: str = DEFAULT_LANGUAGE,
subscription_end_date: datetime = None,
discount_percent: int = 0,
) -> InlineKeyboardMarkup:
from app.utils.pricing_utils import get_remaining_months
from app.config import settings
texts = get_texts(language)
@@ -1218,8 +1235,17 @@ def get_change_devices_keyboard(current_devices: int, language: str = DEFAULT_LA
if chargeable_devices > 0:
price_per_month = chargeable_devices * device_price_per_month
total_price = price_per_month * months_multiplier
discounted_per_month, discount_per_month = apply_percentage_discount(
price_per_month,
discount_percent,
)
total_price = discounted_per_month * months_multiplier
price_text = f" (+{total_price//100}{period_text})"
if discount_percent > 0 and discount_per_month * months_multiplier > 0:
price_text += (
f" (скидка {discount_percent}%:"
f" -{(discount_per_month * months_multiplier)//100}₽)"
)
action_text = ""
else:
price_text = " (бесплатно)"
@@ -1296,7 +1322,8 @@ def get_manage_countries_keyboard(
selected: List[str],
current_subscription_countries: List[str],
language: str = DEFAULT_LANGUAGE,
subscription_end_date: datetime = None
subscription_end_date: datetime = None,
discount_percent: int = 0,
) -> InlineKeyboardMarkup:
from app.utils.pricing_utils import get_remaining_months
@@ -1311,10 +1338,18 @@ def get_manage_countries_keyboard(
total_cost = 0
for country in countries:
if not country.get('is_available', True):
continue
uuid = country['uuid']
name = country['name']
price_per_month = country['price_kopeks']
discounted_per_month, discount_per_month = apply_percentage_discount(
price_per_month,
discount_percent,
)
if uuid in current_subscription_countries:
if uuid in selected:
icon = ""
@@ -1323,17 +1358,31 @@ def get_manage_countries_keyboard(
else:
if uuid in selected:
icon = ""
total_cost += price_per_month * months_multiplier
total_cost += discounted_per_month * months_multiplier
else:
icon = ""
if uuid not in current_subscription_countries and uuid in selected:
total_price = price_per_month * months_multiplier
total_price = discounted_per_month * months_multiplier
if months_multiplier > 1:
price_text = f" ({price_per_month//100}₽/мес × {months_multiplier} = {total_price//100}₽)"
logger.info(f"🔍 Сервер {name}: {price_per_month/100}₽/мес × {months_multiplier} мес = {total_price/100}")
price_text = (
f" ({discounted_per_month//100}₽/мес × {months_multiplier} = {total_price//100})"
)
logger.info(
"🔍 Сервер %s: %.2f₽/мес × %s мес = %.2f₽ (скидка %.2f₽)",
name,
discounted_per_month / 100,
months_multiplier,
total_price / 100,
(discount_per_month * months_multiplier) / 100,
)
else:
price_text = f" ({total_price//100}₽)"
if discount_percent > 0 and discount_per_month * months_multiplier > 0:
price_text += (
f" (скидка {discount_percent}%:"
f" -{(discount_per_month * months_multiplier)//100}₽)"
)
display_name = f"{icon} {name}{price_text}"
else:
display_name = f"{icon} {name}"