Merge pull request #176 from Fr1ngg/0h9kvj-bedolaga/display-promo-group-discounts-on-subscription-page

Show promo group discounts during subscription flow
This commit is contained in:
Egor
2025-09-21 07:56:00 +03:00
committed by GitHub
3 changed files with 131 additions and 12 deletions

View File

@@ -278,6 +278,99 @@ async def _prepare_subscription_summary(
return summary_text, summary_data
def _build_promo_group_discount_text(
db_user: User,
periods: Optional[List[int]] = None,
texts=None,
) -> str:
promo_group = getattr(db_user, "promo_group", None)
if not promo_group:
return ""
if texts is None:
texts = get_texts(db_user.language)
service_lines: List[str] = []
if promo_group.server_discount_percent > 0:
service_lines.append(
texts.PROMO_GROUP_DISCOUNT_SERVERS.format(
percent=promo_group.server_discount_percent
)
)
if promo_group.traffic_discount_percent > 0:
service_lines.append(
texts.PROMO_GROUP_DISCOUNT_TRAFFIC.format(
percent=promo_group.traffic_discount_percent
)
)
if promo_group.device_discount_percent > 0:
service_lines.append(
texts.PROMO_GROUP_DISCOUNT_DEVICES.format(
percent=promo_group.device_discount_percent
)
)
period_lines: List[str] = []
if (
promo_group.is_default
and periods
and settings.is_base_promo_group_period_discount_enabled()
):
discounts = settings.get_base_promo_group_period_discounts()
for period_days in periods:
percent = discounts.get(period_days, 0)
if percent <= 0:
continue
period_display = format_period_description(period_days, db_user.language)
period_lines.append(
texts.PROMO_GROUP_PERIOD_DISCOUNT_ITEM.format(
period=period_display,
percent=percent,
)
)
if not service_lines and not period_lines:
return ""
lines: List[str] = [texts.PROMO_GROUP_DISCOUNTS_HEADER]
if service_lines:
lines.extend(service_lines)
if period_lines:
if service_lines:
lines.append("")
lines.append(texts.PROMO_GROUP_PERIOD_DISCOUNTS_HEADER)
lines.extend(period_lines)
return "\n".join(lines)
def _build_subscription_period_prompt(db_user: User, texts) -> str:
base_text = texts.BUY_SUBSCRIPTION_START.rstrip()
promo_text = _build_promo_group_discount_text(
db_user,
settings.get_available_subscription_periods(),
texts=texts,
)
if not promo_text:
return f"{base_text}\n"
return f"{base_text}\n\n{promo_text}\n"
async def show_subscription_info(
callback: types.CallbackQuery,
db_user: User,
@@ -774,9 +867,9 @@ async def start_subscription_purchase(
db_user: User
):
texts = get_texts(db_user.language)
await callback.message.edit_text(
texts.BUY_SUBSCRIPTION_START,
_build_subscription_period_prompt(db_user, texts),
reply_markup=get_subscription_period_keyboard(db_user.language)
)
@@ -1747,14 +1840,20 @@ async def handle_extend_subscription(
return
prices_text = ""
for days in available_periods:
if days in renewal_prices:
period_display = format_period_description(days, db_user.language)
prices_text += f"📅 {period_display} - {texts.format_price(renewal_prices[days])}\n"
await callback.message.edit_text(
f"⏰ Продление подписки\n\n"
promo_discounts_text = _build_promo_group_discount_text(
db_user,
available_periods,
texts=texts,
)
message_text = (
"⏰ Продление подписки\n\n"
f"Осталось дней: {subscription.days_left}\n\n"
f"<b>Ваша текущая конфигурация:</b>\n"
f"🌍 Серверов: {len(subscription.connected_squads)}\n"
@@ -1762,7 +1861,15 @@ async def handle_extend_subscription(
f"📱 Устройств: {subscription.device_limit}\n\n"
f"<b>Выберите период продления:</b>\n"
f"{prices_text.rstrip()}\n\n"
f"💡 <i>Цена включает все ваши текущие серверы и настройки</i>",
)
if promo_discounts_text:
message_text += f"{promo_discounts_text}\n\n"
message_text += "💡 <i>Цена включает все ваши текущие серверы и настройки</i>"
await callback.message.edit_text(
message_text,
reply_markup=get_extend_subscription_keyboard_with_prices(db_user.language, renewal_prices),
parse_mode="HTML"
)
@@ -3230,11 +3337,11 @@ async def handle_subscription_config_back(
if current_state == SubscriptionStates.selecting_traffic.state:
await callback.message.edit_text(
texts.BUY_SUBSCRIPTION_START,
_build_subscription_period_prompt(db_user, texts),
reply_markup=get_subscription_period_keyboard(db_user.language)
)
await state.set_state(SubscriptionStates.selecting_period)
elif current_state == SubscriptionStates.selecting_countries.state:
if settings.is_traffic_selectable():
await callback.message.edit_text(
@@ -3244,11 +3351,11 @@ async def handle_subscription_config_back(
await state.set_state(SubscriptionStates.selecting_traffic)
else:
await callback.message.edit_text(
texts.BUY_SUBSCRIPTION_START,
_build_subscription_period_prompt(db_user, texts),
reply_markup=get_subscription_period_keyboard(db_user.language)
)
await state.set_state(SubscriptionStates.selecting_period)
elif current_state == SubscriptionStates.selecting_devices.state:
if await _should_show_countries_management():
countries = await _get_available_countries()
@@ -3268,7 +3375,7 @@ async def handle_subscription_config_back(
await state.set_state(SubscriptionStates.selecting_traffic)
else:
await callback.message.edit_text(
texts.BUY_SUBSCRIPTION_START,
_build_subscription_period_prompt(db_user, texts),
reply_markup=get_subscription_period_keyboard(db_user.language)
)
await state.set_state(SubscriptionStates.selecting_period)

View File

@@ -180,6 +180,12 @@
"CAMPAIGN_BONUS_BALANCE": "🎉 You received {amount} for registering via the \"{name}\" campaign!",
"CAMPAIGN_BONUS_SUBSCRIPTION": "🎉 Youve been granted a {days}-day subscription (traffic: {traffic}, devices: {devices}) from the \"{name}\" campaign!",
"BUY_SUBSCRIPTION_START": "\n💎 <b>Subscription setup</b>\n\nLet's configure a plan that fits you.\n\nFirst, choose the subscription period:\n",
"PROMO_GROUP_DISCOUNTS_HEADER": "🎁 <b>Your promo group discounts</b>",
"PROMO_GROUP_DISCOUNT_SERVERS": "🌍 Servers: {percent}%",
"PROMO_GROUP_DISCOUNT_TRAFFIC": "📊 Traffic: {percent}%",
"PROMO_GROUP_DISCOUNT_DEVICES": "📱 Extra devices: {percent}%",
"PROMO_GROUP_PERIOD_DISCOUNTS_HEADER": "⏳ Long-term period discounts:",
"PROMO_GROUP_PERIOD_DISCOUNT_ITEM": "{period} — {percent}%",
"CHANGE_DEVICES_CONFIRM": "\n📱 <b>Confirm change</b>\n\nCurrent amount: {current_devices} devices\nNew amount: {new_devices} devices\n\nAction: {action}\n💰 {cost}\n\nApply this change?\n",
"CHANGE_DEVICES_INFO": "\n📱 <b>Adjust device limit</b>\n\nCurrent limit: {current_devices} devices\n\nChoose the new number of devices:\n\n💡 <b>Important:</b>\n• Increasing — extra charge proportional to the remaining time\n• Decreasing — funds are not refunded\n",
"CHANGE_DEVICES_SUCCESS_DECREASE": "\n✅ Device limit decreased!\n\n📱 Was: {old_count} → Now: {new_count}\n Payments are not refunded\n",

View File

@@ -73,6 +73,12 @@
"CAMPAIGN_BONUS_BALANCE": "🎉 Вы получили {amount} за регистрацию по кампании «{name}»!",
"CAMPAIGN_BONUS_SUBSCRIPTION": "🎉 Вам выдана подписка на {days} д. (трафик: {traffic}, устройств: {devices}) по кампании «{name}»!",
"BUY_SUBSCRIPTION_START": "\n💎 <b>Настройка подписки</b>\n\nДавайте настроим вашу подписку под ваши потребности.\n\nСначала выберите период подписки:\n",
"PROMO_GROUP_DISCOUNTS_HEADER": "🎁 <b>Скидки вашей промогруппы</b>",
"PROMO_GROUP_DISCOUNT_SERVERS": "🌍 Серверы: {percent}%",
"PROMO_GROUP_DISCOUNT_TRAFFIC": "📊 Трафик: {percent}%",
"PROMO_GROUP_DISCOUNT_DEVICES": "📱 Доп. устройства: {percent}%",
"PROMO_GROUP_PERIOD_DISCOUNTS_HEADER": "⏳ Скидки за длительный период:",
"PROMO_GROUP_PERIOD_DISCOUNT_ITEM": "{period} — {percent}%",
"CANCEL": "❌ Отмена",
"CHANGE_DEVICES_BUTTON": "📱 Изменить устройства",
"CHANGE_DEVICES_CONFIRM": "\n 📱 <b>Подтверждение изменения</b>\n\n Текущее количество: {current_devices} устройств\n Новое количество: {new_devices} устройств\n\n Действие: {action}\n 💰 {cost}\n\n Подтвердить изменение?\n ",