diff --git a/bot/handlers/user/payment.py b/bot/handlers/user/payment.py
index 54b097c..b4a4ba1 100644
--- a/bot/handlers/user/payment.py
+++ b/bot/handlers/user/payment.py
@@ -58,6 +58,7 @@ async def process_successful_payment(session: AsyncSession, bot: Bot,
subscription_months = int(subscription_months_str)
payment_db_id = int(
payment_db_id_str) if payment_db_id_str and payment_db_id_str.isdigit() else None
+ is_auto_renew = bool(auto_renew_subscription_id_str and not payment_db_id)
promo_code_id = int(
promo_code_id_str
) if promo_code_id_str and promo_code_id_str.isdigit() else None
@@ -199,53 +200,62 @@ async def process_successful_payment(session: AsyncSession, bot: Bot,
user_lang = db_user.language_code if db_user and db_user.language_code else settings.DEFAULT_LANGUAGE
_ = lambda key, **kwargs: i18n.gettext(user_lang, key, **kwargs)
- config_link = activation_details.get("subscription_url") or _(
- "config_link_not_available"
- )
-
- if applied_referee_bonus_days_from_referral and final_end_date_for_user:
- inviter_name_display = _("friend_placeholder")
- if db_user and db_user.referred_by_id:
- inviter = await user_dal.get_user_by_id(
- session, db_user.referred_by_id)
- if inviter and inviter.first_name:
- inviter_name_display = inviter.first_name
- elif inviter and inviter.username:
- inviter_name_display = f"@{inviter.username}"
-
+ # For auto-renew charges, avoid re-sending config link; send concise message
+ if is_auto_renew and final_end_date_for_user:
details_message = _(
- "payment_successful_with_referral_bonus_full",
- months=subscription_months,
- base_end_date=base_subscription_end_date.strftime('%Y-%m-%d'),
- bonus_days=applied_referee_bonus_days_from_referral,
- final_end_date=final_end_date_for_user.strftime('%Y-%m-%d'),
- inviter_name=inviter_name_display,
- config_link=config_link,
- )
- elif applied_promo_bonus_days > 0 and final_end_date_for_user:
- details_message = _(
- "payment_successful_with_promo_full",
- months=subscription_months,
- bonus_days=applied_promo_bonus_days,
- end_date=final_end_date_for_user.strftime('%Y-%m-%d'),
- config_link=config_link,
- )
- elif final_end_date_for_user:
- details_message = _(
- "payment_successful_full",
+ "yookassa_auto_renewal",
months=subscription_months,
end_date=final_end_date_for_user.strftime('%Y-%m-%d'),
- config_link=config_link,
)
+ details_markup = None
else:
- logging.error(
- f"Critical error: final_end_date_for_user is None for user {user_id} after successful payment logic."
+ config_link = activation_details.get("subscription_url") or _(
+ "config_link_not_available"
)
- details_message = _("payment_successful_error_details")
- details_markup = get_connect_and_main_keyboard(
- user_lang, i18n, settings, config_link
- )
+ if applied_referee_bonus_days_from_referral and final_end_date_for_user:
+ inviter_name_display = _("friend_placeholder")
+ if db_user and db_user.referred_by_id:
+ inviter = await user_dal.get_user_by_id(
+ session, db_user.referred_by_id)
+ if inviter and inviter.first_name:
+ inviter_name_display = inviter.first_name
+ elif inviter and inviter.username:
+ inviter_name_display = f"@{inviter.username}"
+
+ details_message = _(
+ "payment_successful_with_referral_bonus_full",
+ months=subscription_months,
+ base_end_date=base_subscription_end_date.strftime('%Y-%m-%d'),
+ bonus_days=applied_referee_bonus_days_from_referral,
+ final_end_date=final_end_date_for_user.strftime('%Y-%m-%d'),
+ inviter_name=inviter_name_display,
+ config_link=config_link,
+ )
+ elif applied_promo_bonus_days > 0 and final_end_date_for_user:
+ details_message = _(
+ "payment_successful_with_promo_full",
+ months=subscription_months,
+ bonus_days=applied_promo_bonus_days,
+ end_date=final_end_date_for_user.strftime('%Y-%m-%d'),
+ config_link=config_link,
+ )
+ elif final_end_date_for_user:
+ details_message = _(
+ "payment_successful_full",
+ months=subscription_months,
+ end_date=final_end_date_for_user.strftime('%Y-%m-%d'),
+ config_link=config_link,
+ )
+ else:
+ logging.error(
+ f"Critical error: final_end_date_for_user is None for user {user_id} after successful payment logic."
+ )
+ details_message = _("payment_successful_error_details")
+
+ details_markup = get_connect_and_main_keyboard(
+ user_lang, i18n, settings, config_link
+ )
try:
await bot.send_message(
user_id,
diff --git a/bot/services/panel_webhook_service.py b/bot/services/panel_webhook_service.py
index fcef89a..c2ec807 100644
--- a/bot/services/panel_webhook_service.py
+++ b/bot/services/panel_webhook_service.py
@@ -196,8 +196,10 @@ class PanelWebhookService:
if sub and sub.auto_renew_enabled and sub.provider != 'tribute':
try:
ok = await subscription_service.charge_subscription_renewal(session, sub)
+ # If initiation succeeded, suppress the 24h reminder by returning early
if ok:
await session.commit()
+ return
else:
await session.rollback()
except Exception:
diff --git a/locales/en.json b/locales/en.json
index cec81e0..53a63f4 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -211,6 +211,7 @@
"subscription_expired_yesterday_notification": "π Hi, {user_name}!\n\nβ³ Your VPN subscription expired yesterday ({end_date}).\n\nPlease renew it using the button below.",
"tribute_subscription_cancelled": "π¨ Subscription Cancelled\n\nYour Tribute subscription has been cancelled. You have 24 hours to restore access, after which the subscription will be blocked.\n\nTo renew your subscription, press the button below.",
"tribute_auto_renewal": "π Subscription Auto-Renewed\n\nYour Tribute subscription has been automatically renewed for {months} months.\nNew expiration date: {end_date}",
+ "yookassa_auto_renewal": "π Subscription Auto-Renewed\n\nYour subscription was automatically renewed for {months} month(s).\nNew expiration date: {end_date}",
"admin_user_management_prompt": "π€ User Management\n\nEnter user ID or @username to search:",
"admin_user_subscription_info": "Subscription Information:",
"admin_user_reset_trial_button": "π Reset Trial",
diff --git a/locales/ru.json b/locales/ru.json
index fe28c90..651b26d 100644
--- a/locales/ru.json
+++ b/locales/ru.json
@@ -140,6 +140,7 @@
"subscription_expired_notification": "π ΠΡΠΈΠ²Π΅Ρ, {user_name}!\n\nβ Π‘ΡΠΎΠΊ Π²Π°ΡΠ΅ΠΉ ΠΏΠΎΠ΄ΠΏΠΈΡΠΊΠΈ Π½Π° VPN ΠΈΡΡΠ΅ΠΊ ({end_date}).\n\nΠΡΠΎΠ΄Π»ΠΈΡΠ΅ Π΅Ρ ΠΏΠΎ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π½ΠΈΠΆΠ΅.",
"subscription_expired_yesterday_notification": "π ΠΡΠΈΠ²Π΅Ρ, {user_name}!\n\nβ³ ΠΠ°ΡΠ° ΠΏΠΎΠ΄ΠΏΠΈΡΠΊΠ° Π½Π° VPN ΠΈΡΡΠ΅ΠΊΠ»Π° ΡΡΡΠΊΠΈ Π½Π°Π·Π°Π΄ ({end_date}).\n\nΠΡΠΎΠ΄Π»ΠΈΡΠ΅ Π΅Ρ ΠΏΠΎ ΠΊΠ½ΠΎΠΏΠΊΠ΅ Π½ΠΈΠΆΠ΅.",
"tribute_subscription_cancelled": "π¨ ΠΠΎΠ΄ΠΏΠΈΡΠΊΠ° ΠΎΡΠΌΠ΅Π½Π΅Π½Π°\n\nΠΠ°ΡΠ° ΠΏΠΎΠ΄ΠΏΠΈΡΠΊΠ° Tribute Π±ΡΠ»Π° ΠΎΡΠΌΠ΅Π½Π΅Π½Π°. Π£ Π²Π°Ρ Π΅ΡΡΡ 24 ΡΠ°ΡΠ° Π΄Π»Ρ Π²ΠΎΡΡΡΠ°Π½ΠΎΠ²Π»Π΅Π½ΠΈΡ Π΄ΠΎΡΡΡΠΏΠ°, ΠΏΠΎΡΠ»Π΅ ΡΠ΅Π³ΠΎ ΠΏΠΎΠ΄ΠΏΠΈΡΠΊΠ° Π±ΡΠ΄Π΅Ρ Π·Π°Π±Π»ΠΎΠΊΠΈΡΠΎΠ²Π°Π½Π°.\n\nΠΠ»Ρ ΠΏΡΠΎΠ΄Π»Π΅Π½ΠΈΡ ΠΏΠΎΠ΄ΠΏΠΈΡΠΊΠΈ Π½Π°ΠΆΠΌΠΈΡΠ΅ ΠΊΠ½ΠΎΠΏΠΊΡ Π½ΠΈΠΆΠ΅.",
+ "yookassa_auto_renewal": "π ΠΠΎΠ΄ΠΏΠΈΡΠΊΠ° Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ ΠΏΡΠΎΠ΄Π»Π΅Π½Π°\n\nΠΠ°ΡΠ° ΠΏΠΎΠ΄ΠΏΠΈΡΠΊΠ° Π±ΡΠ»Π° Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ ΠΏΡΠΎΠ΄Π»Π΅Π½Π° Π½Π° {months} ΠΌΠ΅Ρ.\nΠΠΎΠ²Π°Ρ Π΄Π°ΡΠ° ΠΎΠΊΠΎΠ½ΡΠ°Π½ΠΈΡ: {end_date}",
"admin_promo_set_validity_days": "β° Π£ΡΡΠ°Π½ΠΎΠ²ΠΈΡΡ ΡΡΠΎΠΊ (Π΄Π½ΠΈ)",
"admin_back_to_panel": "β¬
οΈ Π ΠΏΠ°Π½Π΅Π»Ρ",
"admin_promo_unlimited": "βΎοΈ ΠΠ΅ΠΎΠ³ΡΠ°Π½ΠΈΡΠ΅Π½Π½ΠΎ",