From 69cc2cbe29ff115e74e5d2a44f800bb98e41af50 Mon Sep 17 00:00:00 2001 From: machka pasla Date: Sun, 2 Nov 2025 15:16:27 +0300 Subject: [PATCH] upd --- bot/handlers/admin/sync_admin.py | 3 ++- bot/handlers/user/subscription/core.py | 22 +++++++++++++++++++++- bot/services/referral_service.py | 2 ++ bot/services/subscription_service.py | 12 +++++++++++- db/dal/user_billing_dal.py | 16 ++++++++++++++++ locales/en.json | 1 + locales/ru.json | 1 + 7 files changed, 54 insertions(+), 3 deletions(-) diff --git a/bot/handlers/admin/sync_admin.py b/bot/handlers/admin/sync_admin.py index 39426cb..2d51c9c 100644 --- a/bot/handlers/admin/sync_admin.py +++ b/bot/handlers/admin/sync_admin.py @@ -212,6 +212,7 @@ async def perform_sync(panel_service: PanelApiService, session: AsyncSession, "is_active": panel_status == "ACTIVE", "status_from_panel": panel_status, "traffic_limit_bytes": settings.user_traffic_limit_bytes, + "auto_renew_enabled": False, } created_sub = await subscription_dal.upsert_subscription( session, sub_payload @@ -436,4 +437,4 @@ async def sync_status_command_handler( else: response_text = _("admin_sync_status_never_run") - await message.answer(response_text, parse_mode="HTML") \ No newline at end of file + await message.answer(response_text, parse_mode="HTML") diff --git a/bot/handlers/user/subscription/core.py b/bot/handlers/user/subscription/core.py index 783ab0c..2d6d9df 100644 --- a/bot/handlers/user/subscription/core.py +++ b/bot/handlers/user/subscription/core.py @@ -16,7 +16,7 @@ from bot.keyboards.inline.user_keyboards import ( from bot.services.subscription_service import SubscriptionService from bot.services.panel_api_service import PanelApiService from bot.middlewares.i18n import JsonI18n -from db.dal import subscription_dal +from db.dal import subscription_dal, user_billing_dal from db.models import Subscription router = Router(name="user_subscription_core_router") @@ -455,6 +455,14 @@ async def toggle_autorenew_handler( if sub.provider == "tribute": await callback.answer(get_text("subscription_autorenew_not_supported_for_tribute"), show_alert=True) return + if enable: + has_saved_card = await user_billing_dal.user_has_saved_payment_method(session, callback.from_user.id) + if not has_saved_card: + try: + await callback.answer(get_text("autorenew_enable_requires_card"), show_alert=True) + except Exception: + pass + return # Show confirmation popup and inline buttons confirm_text = get_text("autorenew_confirm_enable") if enable else get_text("autorenew_confirm_disable") @@ -505,6 +513,18 @@ async def confirm_autorenew_handler( if sub.provider == "tribute": await callback.answer(get_text("subscription_autorenew_not_supported_for_tribute"), show_alert=True) return + if enable: + has_saved_card = await user_billing_dal.user_has_saved_payment_method(session, callback.from_user.id) + if not has_saved_card: + try: + await callback.answer(get_text("autorenew_enable_requires_card"), show_alert=True) + except Exception: + pass + try: + await my_subscription_command_handler(callback, i18n_data, settings, panel_service, subscription_service, session, bot) + except Exception: + pass + return await subscription_dal.update_subscription(session, sub.subscription_id, {"auto_renew_enabled": enable}) await session.commit() diff --git a/bot/services/referral_service.py b/bot/services/referral_service.py index 9e518c8..0fcaaf7 100644 --- a/bot/services/referral_service.py +++ b/bot/services/referral_service.py @@ -177,6 +177,8 @@ class ReferralService: "ACTIVE_BONUS", "traffic_limit_bytes": self.settings.user_traffic_limit_bytes, + "auto_renew_enabled": + False, } try: await subscription_dal.deactivate_other_active_subscriptions( diff --git a/bot/services/subscription_service.py b/bot/services/subscription_service.py index e569b0b..2c2862e 100644 --- a/bot/services/subscription_service.py +++ b/bot/services/subscription_service.py @@ -498,6 +498,15 @@ class SubscriptionService: session, panel_user_uuid, panel_sub_link_id ) + auto_renew_should_enable = False + if ( + provider == "yookassa" + and getattr(self.settings, "YOOKASSA_AUTOPAYMENTS_ENABLED", False) + ): + auto_renew_should_enable = await user_billing_dal.user_has_saved_payment_method( + session, user_id + ) + sub_payload = { "user_id": user_id, "panel_user_uuid": panel_user_uuid, @@ -510,7 +519,7 @@ class SubscriptionService: "traffic_limit_bytes": self.settings.user_traffic_limit_bytes, "provider": provider, "skip_notifications": provider == "tribute" and self.settings.TRIBUTE_SKIP_NOTIFICATIONS, - "auto_renew_enabled": True, + "auto_renew_enabled": auto_renew_should_enable, } try: new_or_updated_sub = await subscription_dal.upsert_subscription( @@ -616,6 +625,7 @@ class SubscriptionService: "is_active": True, "status_from_panel": "ACTIVE_BONUS", "traffic_limit_bytes": traffic_limit, + "auto_renew_enabled": False, } await subscription_dal.deactivate_other_active_subscriptions( session, panel_uuid, panel_sub_uuid diff --git a/db/dal/user_billing_dal.py b/db/dal/user_billing_dal.py index a6c1039..04e825f 100644 --- a/db/dal/user_billing_dal.py +++ b/db/dal/user_billing_dal.py @@ -162,3 +162,19 @@ async def delete_user_payment_method_by_provider_id( await session.delete(method) await session.flush() return True + + +async def user_has_saved_payment_method( + session: AsyncSession, + user_id: int, + provider: str = "yookassa", +) -> bool: + """Return True if the user has at least one saved payment method.""" + try: + methods = await list_user_payment_methods(session, user_id, provider) + if methods: + return True + billing = await get_user_billing(session, user_id) + return bool(billing and billing.yookassa_payment_method_id) + except Exception: + return False diff --git a/locales/en.json b/locales/en.json index b3ffec6..bbe5e3c 100644 --- a/locales/en.json +++ b/locales/en.json @@ -439,6 +439,7 @@ "subscription_tribute_notice": "Paid via Tribute. Renew using your Tribute link.", "subscription_tribute_notice_with_link": "Paid via Tribute. Renew: {link}", "subscription_autorenew_not_supported_for_tribute": "Auto-renew is handled by Tribute. Manage renewal in the Tribute app/link.", + "autorenew_enable_requires_card": "Link a payment card in Payment Methods before enabling auto-renew.", "subscription_not_active": "You don't have an active subscription.", "error_service_unavailable": "Service unavailable. Please try again later.", "error_payment_gateway": "Payment service error. Please try again later.", diff --git a/locales/ru.json b/locales/ru.json index a9e97d9..f9f8321 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -439,6 +439,7 @@ "subscription_tribute_notice": "Оплачено через Tribute. Продление делайте по ссылке Tribute.", "subscription_tribute_notice_with_link": "Оплачено через Tribute. Продлить: {link}", "subscription_autorenew_not_supported_for_tribute": "Автопродление управляется Tribute. Управляйте продлением в приложении/ссылке Tribute.", + "autorenew_enable_requires_card": "Прежде чем включать автоплатёж, привяжите карту в разделе «Способы оплаты».", "subscription_not_active": "У вас нет активной подписки.", "error_service_unavailable": "Сервис недоступен. Попробуйте позже.", "error_payment_gateway": "Ошибка платежного сервиса. Попробуйте позже.",