feat(promo): Integrate promo code service into subscription options

- Enhanced the display_subscription_options and reshow_subscription_options_callback functions to accept a promo_code_service parameter for improved discount handling.
- Updated the logic to calculate and display discounted prices based on active promo codes, including support for both regular and star-based pricing.
- Modified relevant locales to include currency symbols in discount notices for better user clarity.
This commit is contained in:
kavore
2026-02-02 00:35:31 +03:00
parent 484327a032
commit 5bb8f2add0
5 changed files with 82 additions and 22 deletions
+1 -1
View File
@@ -675,7 +675,7 @@ async def main_action_callback_handler(
if action == "subscribe":
await user_subscription_handlers.display_subscription_options(
callback, i18n_data, settings, session)
callback, i18n_data, settings, session, promo_code_service=promo_code_service)
elif action == "my_subscription":
await user_subscription_handlers.my_subscription_command_handler(
callback, i18n_data, settings, panel_service, subscription_service,
+45 -5
View File
@@ -1,5 +1,6 @@
import hashlib
import logging
import math
from aiogram import Router, F, types, Bot
from aiogram.filters import Command
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup, WebAppInfo
@@ -39,7 +40,13 @@ def _hwid_callback_token(hwid: Optional[str]) -> str:
return hashlib.sha256(hwid_str.encode()).hexdigest()[:32]
async def display_subscription_options(event: Union[types.Message, types.CallbackQuery], i18n_data: dict, settings: Settings, session: AsyncSession):
async def display_subscription_options(
event: Union[types.Message, types.CallbackQuery],
i18n_data: dict,
settings: Settings,
session: AsyncSession,
promo_code_service=None,
):
current_lang = i18n_data.get("current_language", settings.DEFAULT_LANGUAGE)
i18n: Optional[JsonI18n] = i18n_data.get("i18n_instance")
@@ -61,21 +68,46 @@ async def display_subscription_options(event: Union[types.Message, types.Callbac
stars_traffic_packages = getattr(settings, "stars_traffic_packages", {}) or {}
traffic_mode = bool(getattr(settings, "traffic_sale_mode", False) or stars_traffic_packages)
options_are_stars = False
if traffic_mode:
if traffic_packages:
options = traffic_packages
elif stars_traffic_packages:
options = stars_traffic_packages
currency_symbol_val = ""
options_are_stars = True
else:
options = {}
else:
options = settings.subscription_options
if options:
display_options = options
if options and promo_code_service:
try:
active_discount_info = await promo_code_service.get_user_active_discount(
session, event.from_user.id
)
except Exception:
active_discount_info = None
if active_discount_info:
discount_pct, _promo_code = active_discount_info
discounted_options = {}
for period, price in options.items():
if price is None:
discounted_options[period] = price
else:
discounted_price, _ = promo_code_service.calculate_discounted_price(
price, discount_pct
)
if options_are_stars:
discounted_price = math.ceil(discounted_price)
discounted_options[period] = discounted_price
display_options = discounted_options
if display_options:
text_content = get_text("select_traffic_package") if traffic_mode else get_text("select_subscription_period")
reply_markup = get_subscription_options_keyboard(
options, currency_symbol_val, current_lang, i18n, traffic_mode=traffic_mode
display_options, currency_symbol_val, current_lang, i18n, traffic_mode=traffic_mode
)
else:
text_content = get_text("no_subscription_options_available")
@@ -104,8 +136,16 @@ async def display_subscription_options(event: Union[types.Message, types.Callbac
@router.callback_query(F.data == "main_action:subscribe")
async def reshow_subscription_options_callback(callback: types.CallbackQuery, i18n_data: dict, settings: Settings, session: AsyncSession):
await display_subscription_options(callback, i18n_data, settings, session)
async def reshow_subscription_options_callback(
callback: types.CallbackQuery,
i18n_data: dict,
settings: Settings,
session: AsyncSession,
promo_code_service=None,
):
await display_subscription_options(
callback, i18n_data, settings, session, promo_code_service=promo_code_service
)
async def my_subscription_command_handler(
@@ -1,4 +1,5 @@
import logging
import math
from typing import Optional
from aiogram import F, Router, types
@@ -52,26 +53,45 @@ async def select_subscription_period_callback_handler(
# Check for active discount and apply if exists
discount_text = ""
if promo_code_service and price_rub:
if promo_code_service and (price_rub is not None or stars_price is not None):
active_discount_info = await promo_code_service.get_user_active_discount(
session, callback.from_user.id
)
if active_discount_info:
discount_pct, promo_code = active_discount_info
original_price_rub = price_rub
price_rub, discount_amt = promo_code_service.calculate_discounted_price(
price_rub, discount_pct
)
discount_text = get_text(
"active_discount_notice",
code=promo_code,
discount_pct=discount_pct,
original_price=original_price_rub,
discounted_price=price_rub,
discount_amount=discount_amt
)
# Note: Stars prices typically don't get discounts (can be added if needed)
if price_rub is not None:
original_price_rub = price_rub
price_rub, discount_amt = promo_code_service.calculate_discounted_price(
price_rub, discount_pct
)
discount_text = get_text(
"active_discount_notice",
code=promo_code,
discount_pct=discount_pct,
original_price=original_price_rub,
discounted_price=price_rub,
discount_amount=discount_amt,
currency_symbol=currency_symbol_val,
)
if stars_price is not None:
original_stars_price = stars_price
discounted_stars_price, _ = promo_code_service.calculate_discounted_price(
float(stars_price), discount_pct
)
discounted_stars_price = math.ceil(discounted_stars_price)
stars_price = discounted_stars_price
if not discount_text:
discount_amt = original_stars_price - discounted_stars_price
discount_text = get_text(
"active_discount_notice",
code=promo_code,
discount_pct=discount_pct,
original_price=original_stars_price,
discounted_price=discounted_stars_price,
discount_amount=discount_amt,
currency_symbol="",
)
if price_rub is None:
if traffic_mode and not price_source and stars_price is not None: