From ad03fa070ab1d159969dbf576a105523c763f32b Mon Sep 17 00:00:00 2001 From: Egor Date: Thu, 30 Oct 2025 03:06:16 +0300 Subject: [PATCH] Hide zero price in subscription period options --- app/keyboards/inline.py | 13 ++++++++----- app/localization/texts.py | 25 +++++++++++++------------ app/utils/pricing_utils.py | 15 +++++++++++++++ 3 files changed, 36 insertions(+), 17 deletions(-) diff --git a/app/keyboards/inline.py b/app/keyboards/inline.py index 46a64f05..2656392f 100644 --- a/app/keyboards/inline.py +++ b/app/keyboards/inline.py @@ -9,7 +9,10 @@ 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.miniapp_buttons import build_miniapp_or_callback_button -from app.utils.pricing_utils import format_period_description, apply_percentage_discount +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, @@ -1407,10 +1410,10 @@ def get_extend_subscription_keyboard(language: str = DEFAULT_LANGUAGE) -> Inline keyboard = [] periods = [ - (14, f"📅 14 дней - {settings.format_price(settings.PRICE_14_DAYS)}"), - (30, f"📅 30 дней - {settings.format_price(settings.PRICE_30_DAYS)}"), - (60, f"📅 60 дней - {settings.format_price(settings.PRICE_60_DAYS)}"), - (90, f"📅 90 дней - {settings.format_price(settings.PRICE_90_DAYS)}") + (14, texts.PERIOD_14_DAYS), + (30, texts.PERIOD_30_DAYS), + (60, texts.PERIOD_60_DAYS), + (90, texts.PERIOD_90_DAYS) ] for days, text in periods: diff --git a/app/localization/texts.py b/app/localization/texts.py index ccd8eff1..b0d05652 100644 --- a/app/localization/texts.py +++ b/app/localization/texts.py @@ -5,6 +5,7 @@ import logging from typing import Any, Dict from app.config import settings +from app.utils.pricing_utils import format_period_option_label from app.localization.loader import ( DEFAULT_LANGUAGE, clear_locale_cache, @@ -30,12 +31,12 @@ def _build_dynamic_values(language: str) -> Dict[str, Any]: if language_code == "ru": return { - "PERIOD_14_DAYS": f"📅 14 дней - {settings.format_price(settings.PRICE_14_DAYS)}", - "PERIOD_30_DAYS": f"📅 30 дней - {settings.format_price(settings.PRICE_30_DAYS)}", - "PERIOD_60_DAYS": f"📅 60 дней - {settings.format_price(settings.PRICE_60_DAYS)}", - "PERIOD_90_DAYS": f"📅 90 дней - {settings.format_price(settings.PRICE_90_DAYS)}", - "PERIOD_180_DAYS": f"📅 180 дней - {settings.format_price(settings.PRICE_180_DAYS)}", - "PERIOD_360_DAYS": f"📅 360 дней - {settings.format_price(settings.PRICE_360_DAYS)}", + "PERIOD_14_DAYS": format_period_option_label("📅 14 дней", settings.PRICE_14_DAYS), + "PERIOD_30_DAYS": format_period_option_label("📅 30 дней", settings.PRICE_30_DAYS), + "PERIOD_60_DAYS": format_period_option_label("📅 60 дней", settings.PRICE_60_DAYS), + "PERIOD_90_DAYS": format_period_option_label("📅 90 дней", settings.PRICE_90_DAYS), + "PERIOD_180_DAYS": format_period_option_label("📅 180 дней", settings.PRICE_180_DAYS), + "PERIOD_360_DAYS": format_period_option_label("📅 360 дней", settings.PRICE_360_DAYS), "TRAFFIC_5GB": f"📊 5 ГБ - {settings.format_price(settings.PRICE_TRAFFIC_5GB)}", "TRAFFIC_10GB": f"📊 10 ГБ - {settings.format_price(settings.PRICE_TRAFFIC_10GB)}", "TRAFFIC_25GB": f"📊 25 ГБ - {settings.format_price(settings.PRICE_TRAFFIC_25GB)}", @@ -55,12 +56,12 @@ def _build_dynamic_values(language: str) -> Dict[str, Any]: if language_code == "en": return { - "PERIOD_14_DAYS": f"📅 14 days - {settings.format_price(settings.PRICE_14_DAYS)}", - "PERIOD_30_DAYS": f"📅 30 days - {settings.format_price(settings.PRICE_30_DAYS)}", - "PERIOD_60_DAYS": f"📅 60 days - {settings.format_price(settings.PRICE_60_DAYS)}", - "PERIOD_90_DAYS": f"📅 90 days - {settings.format_price(settings.PRICE_90_DAYS)}", - "PERIOD_180_DAYS": f"📅 180 days - {settings.format_price(settings.PRICE_180_DAYS)}", - "PERIOD_360_DAYS": f"📅 360 days - {settings.format_price(settings.PRICE_360_DAYS)}", + "PERIOD_14_DAYS": format_period_option_label("📅 14 days", settings.PRICE_14_DAYS), + "PERIOD_30_DAYS": format_period_option_label("📅 30 days", settings.PRICE_30_DAYS), + "PERIOD_60_DAYS": format_period_option_label("📅 60 days", settings.PRICE_60_DAYS), + "PERIOD_90_DAYS": format_period_option_label("📅 90 days", settings.PRICE_90_DAYS), + "PERIOD_180_DAYS": format_period_option_label("📅 180 days", settings.PRICE_180_DAYS), + "PERIOD_360_DAYS": format_period_option_label("📅 360 days", settings.PRICE_360_DAYS), "TRAFFIC_5GB": f"📊 5 GB - {settings.format_price(settings.PRICE_TRAFFIC_5GB)}", "TRAFFIC_10GB": f"📊 10 GB - {settings.format_price(settings.PRICE_TRAFFIC_10GB)}", "TRAFFIC_25GB": f"📊 25 GB - {settings.format_price(settings.PRICE_TRAFFIC_25GB)}", diff --git a/app/utils/pricing_utils.py b/app/utils/pricing_utils.py index 5ec1abf5..88c9602e 100644 --- a/app/utils/pricing_utils.py +++ b/app/utils/pricing_utils.py @@ -313,6 +313,21 @@ def format_period_description(days: int, language: str = "ru") -> str: return f"{days} days ({months} {month_word})" +def format_period_option_label(label: str, price: int) -> str: + """Return a period option label with price when it's greater than zero. + + When the price is zero or negative, the price suffix is omitted so that the + option does not misleadingly show "0" as the cost of the period. This keeps + the UI consistent when pricing is calculated dynamically based on other + parameters such as servers or devices. + """ + + if price and price > 0: + return f"{label} - {settings.format_price(price)}" + + return label + + def validate_pricing_calculation( base_price: int, monthly_additions: int,