diff --git a/bot/handlers/user/payment.py b/bot/handlers/user/payment.py index 0dcfba8..204d4e8 100644 --- a/bot/handlers/user/payment.py +++ b/bot/handlers/user/payment.py @@ -139,7 +139,7 @@ async def process_successful_payment(session: AsyncSession, bot: Bot, # Try to capture and save payment method for future charges if available try: payment_method = payment_info_from_webhook.get("payment_method") - if getattr(settings, 'YOOKASSA_AUTOPAYMENTS_ENABLED', False) and isinstance(payment_method, dict) and payment_method.get("saved", False): + if settings.yookassa_autopayments_active and isinstance(payment_method, dict) and payment_method.get("saved", False): pm_id = payment_method.get("id") pm_type = payment_method.get("type") title = payment_method.get("title") @@ -499,7 +499,7 @@ async def yookassa_webhook_route(request: web.Request): elif notification_object.event == YOOKASSA_EVENT_PAYMENT_WAITING_FOR_CAPTURE: # Bind-only flow: save method and cancel auth if metadata has bind_only metadata = payment_dict_for_processing.get("metadata", {}) or {} - if getattr(settings, 'YOOKASSA_AUTOPAYMENTS_ENABLED', False) and metadata.get("bind_only") == "1": + if settings.yookassa_autopayments_active and metadata.get("bind_only") == "1": try: user_id_str = metadata.get("user_id") if user_id_str and user_id_str.isdigit(): diff --git a/bot/handlers/user/subscription/core.py b/bot/handlers/user/subscription/core.py index 2d6d9df..3cec154 100644 --- a/bot/handlers/user/subscription/core.py +++ b/bot/handlers/user/subscription/core.py @@ -225,7 +225,7 @@ async def my_subscription_command_handler( ]) # 2) Auto-renew toggle (if supported and not tribute) - if local_sub and local_sub.provider != "tribute" and getattr(settings, 'YOOKASSA_AUTOPAYMENTS_ENABLED', False): + if local_sub and local_sub.provider != "tribute" and settings.yookassa_autopayments_active: toggle_text = ( get_text("autorenew_disable_button") if local_sub.auto_renew_enabled else get_text("autorenew_enable_button") ) @@ -237,7 +237,7 @@ async def my_subscription_command_handler( ]) # 3) Payment methods management (when autopayments enabled) - if getattr(settings, 'YOOKASSA_AUTOPAYMENTS_ENABLED', False): + if settings.yookassa_autopayments_active: prepend_rows.append([ InlineKeyboardButton(text=get_text("payment_methods_manage_button"), callback_data="pm:manage") ]) diff --git a/bot/handlers/user/subscription/payment_methods.py b/bot/handlers/user/subscription/payment_methods.py index 5dec974..3962b55 100644 --- a/bot/handlers/user/subscription/payment_methods.py +++ b/bot/handlers/user/subscription/payment_methods.py @@ -22,7 +22,7 @@ router = Router(name="user_subscription_payment_methods_router") async def payment_methods_manage(callback: types.CallbackQuery, settings: Settings, i18n_data: dict, session: AsyncSession): current_lang = i18n_data.get("current_language", settings.DEFAULT_LANGUAGE) i18n: Optional[JsonI18n] = i18n_data.get("i18n_instance") - if not getattr(settings, 'YOOKASSA_AUTOPAYMENTS_ENABLED', False): + if not settings.yookassa_autopayments_active: try: _ = lambda key, **kwargs: i18n.gettext(current_lang, key, **kwargs) if i18n else key await callback.answer(_("error_service_unavailable"), show_alert=True) @@ -75,7 +75,7 @@ async def payment_methods_manage(callback: types.CallbackQuery, settings: Settin async def payment_method_bind(callback: types.CallbackQuery, settings: Settings, i18n_data: dict, session: AsyncSession, yookassa_service: YooKassaService): current_lang = i18n_data.get("current_language", settings.DEFAULT_LANGUAGE) i18n: Optional[JsonI18n] = i18n_data.get("i18n_instance") - if not getattr(settings, 'YOOKASSA_AUTOPAYMENTS_ENABLED', False): + if not settings.yookassa_autopayments_active: try: _ = lambda key, **kwargs: i18n.gettext(current_lang, key, **kwargs) if i18n else key await callback.answer(_("error_service_unavailable"), show_alert=True) @@ -109,7 +109,7 @@ async def payment_method_bind(callback: types.CallbackQuery, settings: Settings, async def payment_method_delete_confirm(callback: types.CallbackQuery, settings: Settings, i18n_data: dict): current_lang = i18n_data.get("current_language", settings.DEFAULT_LANGUAGE) i18n: Optional[JsonI18n] = i18n_data.get("i18n_instance") - if not getattr(settings, 'YOOKASSA_AUTOPAYMENTS_ENABLED', False): + if not settings.yookassa_autopayments_active: try: _ = lambda key, **kwargs: i18n.gettext(current_lang, key, **kwargs) if i18n else key await callback.answer(_("error_service_unavailable"), show_alert=True) @@ -130,7 +130,7 @@ async def payment_method_delete_confirm(callback: types.CallbackQuery, settings: async def payment_method_delete(callback: types.CallbackQuery, settings: Settings, i18n_data: dict, session: AsyncSession): current_lang = i18n_data.get("current_language", settings.DEFAULT_LANGUAGE) i18n: Optional[JsonI18n] = i18n_data.get("i18n_instance") - if not getattr(settings, 'YOOKASSA_AUTOPAYMENTS_ENABLED', False): + if not settings.yookassa_autopayments_active: try: _ = lambda key, **kwargs: i18n.gettext(current_lang, key, **kwargs) if i18n else key await callback.answer(_("error_service_unavailable"), show_alert=True) @@ -204,7 +204,7 @@ async def payment_method_delete(callback: types.CallbackQuery, settings: Setting async def payment_method_view(callback: types.CallbackQuery, settings: Settings, i18n_data: dict, session: AsyncSession): current_lang = i18n_data.get("current_language", settings.DEFAULT_LANGUAGE) i18n: Optional[JsonI18n] = i18n_data.get("i18n_instance") - if not getattr(settings, 'YOOKASSA_AUTOPAYMENTS_ENABLED', False): + if not settings.yookassa_autopayments_active: try: _ = lambda key, **kwargs: i18n.gettext(current_lang, key, **kwargs) if i18n else key await callback.answer(_("error_service_unavailable"), show_alert=True) @@ -325,7 +325,7 @@ async def payment_method_view(callback: types.CallbackQuery, settings: Settings, async def payment_method_history(callback: types.CallbackQuery, settings: Settings, i18n_data: dict, session: AsyncSession, yookassa_service: YooKassaService): current_lang = i18n_data.get("current_language", settings.DEFAULT_LANGUAGE) i18n: Optional[JsonI18n] = i18n_data.get("i18n_instance") - if not getattr(settings, 'YOOKASSA_AUTOPAYMENTS_ENABLED', False): + if not settings.yookassa_autopayments_active: try: _ = lambda key, **kwargs: i18n.gettext(current_lang, key, **kwargs) if i18n else key await callback.answer(_("error_service_unavailable"), show_alert=True) diff --git a/bot/handlers/user/subscription/payments_yookassa.py b/bot/handlers/user/subscription/payments_yookassa.py index e1ed517..c586143 100644 --- a/bot/handlers/user/subscription/payments_yookassa.py +++ b/bot/handlers/user/subscription/payments_yookassa.py @@ -340,7 +340,7 @@ async def pay_yk_callback_handler(callback: types.CallbackQuery, settings: Setti months, price_rub = parsed user_id = callback.from_user.id currency_code_for_yk = "RUB" - autopay_enabled = bool(getattr(settings, 'YOOKASSA_AUTOPAYMENTS_ENABLED', False)) + autopay_enabled = bool(settings.yookassa_autopayments_active) autopay_require_binding = bool( getattr(settings, 'YOOKASSA_AUTOPAYMENTS_REQUIRE_CARD_BINDING', True) ) @@ -455,7 +455,7 @@ async def pay_yk_new_card_handler(callback: types.CallbackQuery, settings: Setti months, price_rub = parsed user_id = callback.from_user.id currency_code_for_yk = "RUB" - autopay_enabled = bool(getattr(settings, 'YOOKASSA_AUTOPAYMENTS_ENABLED', False)) + autopay_enabled = bool(settings.yookassa_autopayments_active) autopay_require_binding = bool( getattr(settings, 'YOOKASSA_AUTOPAYMENTS_REQUIRE_CARD_BINDING', True) ) @@ -494,7 +494,7 @@ async def pay_yk_saved_list_handler(callback: types.CallbackQuery, settings: Set pass return - autopay_enabled = bool(getattr(settings, 'YOOKASSA_AUTOPAYMENTS_ENABLED', False)) + autopay_enabled = bool(settings.yookassa_autopayments_active) if not autopay_enabled: try: await callback.answer(get_text("error_try_again"), show_alert=True) @@ -633,7 +633,7 @@ async def pay_yk_use_saved_handler(callback: types.CallbackQuery, settings: Sett pass return - autopay_enabled = bool(getattr(settings, 'YOOKASSA_AUTOPAYMENTS_ENABLED', False)) + autopay_enabled = bool(settings.yookassa_autopayments_active) if not autopay_enabled: try: await callback.answer(get_text("error_try_again"), show_alert=True) diff --git a/bot/services/subscription_service.py b/bot/services/subscription_service.py index 8b7b1c7..8cd0cba 100644 --- a/bot/services/subscription_service.py +++ b/bot/services/subscription_service.py @@ -501,10 +501,7 @@ class SubscriptionService: ) auto_renew_should_enable = False - if ( - provider == "yookassa" - and getattr(self.settings, "YOOKASSA_AUTOPAYMENTS_ENABLED", False) - ): + if provider == "yookassa" and self.settings.yookassa_autopayments_active: auto_renew_should_enable = await user_billing_dal.user_has_saved_payment_method( session, user_id ) @@ -829,7 +826,7 @@ class SubscriptionService: if not sub.auto_renew_enabled: return True # If autopayments are disabled globally, skip charging attempts - if not getattr(self.settings, 'YOOKASSA_AUTOPAYMENTS_ENABLED', False): + if not self.settings.yookassa_autopayments_active: return True if sub.provider == "tribute": # Tribute is paid externally; we do not auto-charge here diff --git a/bot/services/yookassa_service.py b/bot/services/yookassa_service.py index 6df92af..f837faf 100644 --- a/bot/services/yookassa_service.py +++ b/bot/services/yookassa_service.py @@ -21,7 +21,10 @@ class YooKassaService: self.settings = settings_obj - if not shop_id or not secret_key: + if self.settings and not self.settings.YOOKASSA_ENABLED: + logging.warning("YooKassa is disabled via YOOKASSA_ENABLED flag. Payment functionality will be DISABLED.") + self.configured = False + elif not shop_id or not secret_key: logging.warning( "YooKassa SHOP_ID or SECRET_KEY not configured in settings. " "Payment functionality will be DISABLED.") diff --git a/config/settings.py b/config/settings.py index 319fcbe..5700d3c 100644 --- a/config/settings.py +++ b/config/settings.py @@ -427,6 +427,12 @@ class Settings(BaseSettings): bonuses[12] = self.REFERRAL_BONUS_DAYS_REFEREE_12_MONTHS return bonuses + @computed_field + @property + def yookassa_autopayments_active(self) -> bool: + """Autopay features are available only when YooKassa itself is enabled.""" + return bool(self.YOOKASSA_ENABLED and self.YOOKASSA_AUTOPAYMENTS_ENABLED) + @computed_field @property def payment_methods_order(self) -> List[str]: