{t("wa_referral_bonus_depends_on_tariff")}
+ {:else if periodBonusDetails.length}{t("wa_referral_bonus_paid_intro")}
{/if} - {#each referralBonusDetails as bonus, index (bonus.id || `${bonus.tariff_key || "legacy"}:${bonus.months || index}`)} -
+
+ {tariffBonus.title || tariffBonus.tariff_name}
+
+ {t("wa_referral_bonus_you_range", {
+ range: daysRange(tariffBonus.inviter_min_days, tariffBonus.inviter_max_days),
+ })}
+
+
+ {t("wa_referral_bonus_friend_range", {
+ range: daysRange(tariffBonus.friend_min_days, tariffBonus.friend_max_days),
+ })}
+
+
+
+
+ {referral_link}{webapp_link_section}\n\n💰 Invitation bonuses:\n{bonus_details}\n\n📢 Share the link with friends and get bonuses!",
"referral_bonus_per_period": "\n\n🎁 For a friend's {months}-month subscription:\n ➢ You: {inviter_bonus_days} days\n ➢ Friend: {referee_bonus_days} days",
+ "referral_bonus_days_range": "from {min_days} to {max_days} days",
+ "referral_bonus_tariff_range": "\n\n🎁 {tariff_name}:\n ➢ You: {inviter_bonus_range}\n ➢ Friend: {referee_bonus_range}",
"referral_not_available_for_traffic": "Referral bonuses are not available for traffic packages.",
"referral_share_message_button": "📩 Message for friend",
"referral_friend_message": "🚀 Hey! Try this service - it's fast, reliable and affordable!\n\n🎁 Use my link to get bonus days with your subscription!\n\n{referral_link}",
@@ -778,8 +780,12 @@
"wa_referral_bonus_once_note": "Bonus is granted only once per invited user after their first payment.",
"wa_referral_bonus_registration_title": "For registration via referral link",
"wa_referral_bonus_paid_intro": "If a friend pays for a subscription:",
+ "wa_referral_bonus_depends_on_tariff": "Bonus depends on the tariff and payment period your friend chooses",
+ "wa_referral_bonus_range_days": "from {min} to {max} days",
"wa_referral_bonus_you_days": "You: +{days} days",
"wa_referral_bonus_friend_days": "Friend: +{days} days",
+ "wa_referral_bonus_you_range": "You: {range}",
+ "wa_referral_bonus_friend_range": "Friend: {range}",
"wa_referral_bonus_not_configured": "Referral bonuses are not configured",
"wa_promo_enter": "Enter promo code",
"wa_promo_activated_until": "Promo code activated. Subscription until {date}",
diff --git a/locales/ru.json b/locales/ru.json
index 72397cd..aaf7564 100644
--- a/locales/ru.json
+++ b/locales/ru.json
@@ -97,6 +97,8 @@
"no_button": "Нет",
"referral_program_info_new": "🎁 Реферальная программа\n\n📊 Твоя статистика:\n👥 Приглашено друзей: {invited_count}\n💳 Купили подписку: {purchased_count}\n\n🔗 Telegram ссылка:\n{referral_link}{webapp_link_section}\n\n💰 Бонусы за приглашения:\n{bonus_details}\n\n📢 Поделись ссылкой с друзьями и получай бонусы!",
"referral_bonus_per_period": "\n\n🎁 За {months}-мес. подписку друга:\n ➢ Вы: {inviter_bonus_days} дн.\n ➢ Друг: {referee_bonus_days} дн.",
+ "referral_bonus_days_range": "от {min_days} до {max_days} дн.",
+ "referral_bonus_tariff_range": "\n\n🎁 {tariff_name}:\n ➢ Вы: {inviter_bonus_range}\n ➢ Друг: {referee_bonus_range}",
"referral_not_available_for_traffic": "Для пакетов трафика реферальные бонусы не начисляются.",
"referral_share_message_button": "📩 Сообщение для друга",
"referral_friend_message": "🚀 Привет! Попробуй этот сервис - быстрый, надёжный и доступный!\n\n🎁 По моей ссылке тебе дадут бонусные дни к подписке!\n\n{referral_link}",
@@ -778,8 +780,12 @@
"wa_referral_bonus_once_note": "Бонус за приглашённого начисляется только один раз, после его первой оплаты.",
"wa_referral_bonus_registration_title": "За регистрацию по реферальной ссылке",
"wa_referral_bonus_paid_intro": "Если друг оплатит подписку:",
+ "wa_referral_bonus_depends_on_tariff": "Бонус зависит от тарифа и периода оплаты друга",
+ "wa_referral_bonus_range_days": "от {min} до {max} дней",
"wa_referral_bonus_you_days": "Вам: +{days} дней",
"wa_referral_bonus_friend_days": "Другу: +{days} дней",
+ "wa_referral_bonus_you_range": "Вам: {range}",
+ "wa_referral_bonus_friend_range": "Другу: {range}",
"wa_referral_bonus_not_configured": "Реферальные бонусы не настроены",
"wa_promo_enter": "Введите промокод",
"wa_promo_activated_until": "Промокод активирован. Подписка до {date}",
diff --git a/tests/test_user_bot_menu.py b/tests/test_user_bot_menu.py
index 0f50f84..17789f0 100644
--- a/tests/test_user_bot_menu.py
+++ b/tests/test_user_bot_menu.py
@@ -20,6 +20,7 @@ from bot.keyboards.inline.user_keyboards import (
payment_methods_back_callback,
payment_options_back_callback,
)
+from config.tariffs_config import TariffsConfig
class JsonI18nStub:
@@ -304,3 +305,95 @@ class UserBotMenuTests(unittest.TestCase):
self.assertLess(text.index("Telegram link:"), text.index("Web link:"))
self.assertLess(text.index("Web link:"), text.index("Invitation bonuses:"))
+
+ def test_single_tariff_referral_text_uses_period_rows_without_tariff_name(self):
+ settings = SimpleNamespace(
+ tariffs_config=TariffsConfig.model_validate(
+ {
+ "default_tariff": "standard",
+ "tariffs": [
+ {
+ "key": "standard",
+ "names": {"en": "Standard"},
+ "descriptions": {},
+ "squad_uuids": ["standard"],
+ "billing_model": "period",
+ "monthly_gb": 100,
+ "prices_rub": {"2": 400, "4": 800},
+ "prices_stars": {},
+ "referral_bonus_days_inviter": {"2": 5, "4": 10},
+ "referral_bonus_days_referee": {"2": 1, "4": 2},
+ "enabled_periods": [2, 4],
+ "enabled": True,
+ }
+ ],
+ }
+ ),
+ subscription_options={},
+ referral_bonus_inviter={},
+ referral_bonus_referee={},
+ )
+
+ text = referral._build_referral_bonus_details_text(
+ settings,
+ lambda key, **kwargs: self.i18n.gettext("en", key, **kwargs),
+ "en",
+ )
+
+ self.assertIn("For a friend's 2-month subscription", text)
+ self.assertIn("For a friend's 4-month subscription", text)
+ self.assertNotIn("Standard", text)
+
+ def test_multiple_tariff_referral_text_uses_tariff_ranges(self):
+ settings = SimpleNamespace(
+ tariffs_config=TariffsConfig.model_validate(
+ {
+ "default_tariff": "standard",
+ "tariffs": [
+ {
+ "key": "standard",
+ "names": {"en": "Standard"},
+ "descriptions": {},
+ "squad_uuids": ["standard"],
+ "billing_model": "period",
+ "monthly_gb": 100,
+ "prices_rub": {"2": 400, "4": 800},
+ "prices_stars": {},
+ "referral_bonus_days_inviter": {"2": 5, "4": 10},
+ "referral_bonus_days_referee": {"2": 1, "4": 2},
+ "enabled_periods": [2, 4],
+ "enabled": True,
+ },
+ {
+ "key": "premium",
+ "names": {"en": "Premium"},
+ "descriptions": {},
+ "squad_uuids": ["premium"],
+ "billing_model": "period",
+ "monthly_gb": 500,
+ "prices_rub": {"1": 700, "3": 1800},
+ "prices_stars": {},
+ "referral_bonus_days_inviter": {"1": 8, "3": 24},
+ "referral_bonus_days_referee": {"1": 3, "3": 9},
+ "enabled_periods": [1, 3],
+ "enabled": True,
+ },
+ ],
+ }
+ ),
+ subscription_options={},
+ referral_bonus_inviter={},
+ referral_bonus_referee={},
+ )
+
+ text = referral._build_referral_bonus_details_text(
+ settings,
+ lambda key, **kwargs: self.i18n.gettext("en", key, **kwargs),
+ "en",
+ )
+
+ self.assertIn("Standard", text)
+ self.assertIn("Premium", text)
+ self.assertIn("from 5 to 10 days", text)
+ self.assertIn("from 8 to 24 days", text)
+ self.assertNotIn("2-month subscription", text)
diff --git a/tests/test_webapp_assets.py b/tests/test_webapp_assets.py
index ab44f22..3f6548a 100644
--- a/tests/test_webapp_assets.py
+++ b/tests/test_webapp_assets.py
@@ -141,7 +141,7 @@ class WebAppAssetTests(unittest.IsolatedAsyncioTestCase):
"tariff_key": "standard",
"tariff_name": "Standard",
"months": 2,
- "title": "Standard - 2 months",
+ "title": "2 months",
"inviter_days": 5,
"friend_days": 1,
},
@@ -150,7 +150,7 @@ class WebAppAssetTests(unittest.IsolatedAsyncioTestCase):
"tariff_key": "standard",
"tariff_name": "Standard",
"months": 4,
- "title": "Standard - 4 months",
+ "title": "4 months",
"inviter_days": 10,
"friend_days": 2,
},
@@ -159,7 +159,7 @@ class WebAppAssetTests(unittest.IsolatedAsyncioTestCase):
"tariff_key": "standard",
"tariff_name": "Standard",
"months": 8,
- "title": "Standard - 8 months",
+ "title": "8 months",
"inviter_days": 0,
"friend_days": 4,
},
@@ -168,13 +168,78 @@ class WebAppAssetTests(unittest.IsolatedAsyncioTestCase):
"tariff_key": "standard",
"tariff_name": "Standard",
"months": 16,
- "title": "Standard - 16 months",
+ "title": "16 months",
"inviter_days": 40,
"friend_days": 0,
},
],
)
+ def test_referral_bonus_details_group_multiple_tariffs(self):
+ with tempfile.TemporaryDirectory() as tmpdir:
+ path = Path(tmpdir) / "tariffs.json"
+ path.write_text(
+ json.dumps(
+ {
+ "default_tariff": "standard",
+ "tariffs": [
+ {
+ "key": "standard",
+ "names": {"en": "Standard"},
+ "descriptions": {},
+ "squad_uuids": ["standard"],
+ "billing_model": "period",
+ "monthly_gb": 100,
+ "prices_rub": {"2": 400, "4": 800},
+ "prices_stars": {},
+ "referral_bonus_days_inviter": {"2": 5, "4": 10},
+ "referral_bonus_days_referee": {"2": 1, "4": 2},
+ "enabled_periods": [2, 4],
+ "enabled": True,
+ },
+ {
+ "key": "premium",
+ "names": {"en": "Premium"},
+ "descriptions": {},
+ "squad_uuids": ["premium"],
+ "billing_model": "period",
+ "monthly_gb": 500,
+ "prices_rub": {"1": 700, "3": 1800},
+ "prices_stars": {},
+ "referral_bonus_days_inviter": {"1": 8, "3": 24},
+ "referral_bonus_days_referee": {"1": 3, "3": 9},
+ "enabled_periods": [1, 3],
+ "enabled": True,
+ },
+ ],
+ }
+ ),
+ encoding="utf-8",
+ )
+ settings = Settings(
+ _env_file=None,
+ BOT_TOKEN="token",
+ POSTGRES_USER="app_user",
+ POSTGRES_PASSWORD="app_password",
+ TARIFFS_CONFIG_PATH=str(path),
+ )
+
+ details = subscription_webapp._serialize_referral_bonus_details(settings, "en")
+
+ self.assertEqual([item["type"] for item in details], ["tariff_summary", "tariff_summary"])
+ self.assertEqual(details[0]["title"], "Standard")
+ self.assertEqual(details[0]["inviter_min_days"], 5)
+ self.assertEqual(details[0]["inviter_max_days"], 10)
+ self.assertEqual(details[0]["friend_min_days"], 1)
+ self.assertEqual(details[0]["friend_max_days"], 2)
+ self.assertEqual(
+ [item["title"] for item in details[0]["details"]],
+ ["2 months", "4 months"],
+ )
+ self.assertEqual(details[1]["title"], "Premium")
+ self.assertEqual(details[1]["inviter_min_days"], 8)
+ self.assertEqual(details[1]["inviter_max_days"], 24)
+
def test_subscription_template_does_not_block_on_telegram_sdk(self):
html = subscription_webapp.TEMPLATE_PATH.read_text(encoding="utf-8")