Files
remnawave-minishop/backend/bot/services/subscription_service_impl/renewal.py
T

82 lines
3.5 KiB
Python

# ruff: noqa: F401,F403,F405,I001
from ._runtime import * # noqa: F403,F405
class RenewalMixin:
async def charge_subscription_renewal(
self,
session: AsyncSession,
sub: Subscription,
) -> bool:
"""Attempt to charge user using saved payment method. Return True on initiated/handled, False on failure.""" # noqa: E501
if getattr(self.settings, "traffic_sale_mode", False):
logging.info("Auto-renew skipped: traffic sale mode enabled")
return True
if not sub.auto_renew_enabled:
return True
# If autopayments are disabled globally, skip charging attempts
if not self.settings.yookassa_autopayments_active:
return True
if sub.provider != "yookassa":
logging.info(
"Auto-renew skipped: provider %s does not support auto-renew", sub.provider
)
return True
from db.dal.user_billing_dal import get_user_default_payment_method
default_pm = await get_user_default_payment_method(session, sub.user_id)
if not default_pm:
logging.info(f"Auto-renew skipped: no saved payment method for user {sub.user_id}")
return False
# ``yookassa_service`` is wired onto the subscription service via
# ``build_core_services`` (setattr). Read it directly — the previous
# ``from .yookassa_service import …`` pointed at a non-existent module
# inside this package, the ImportError got swallowed, and every
# auto-renew silently returned False.
yk = getattr(self, "yookassa_service", None)
if not yk or not getattr(yk, "configured", False):
logging.warning("YooKassa unavailable for auto-renew")
return False
months = sub.duration_months or 1
currency = default_payment_currency_code_for_settings(self.settings)
amount = None
tariffs_config = self._tariffs_config() if callable(getattr(self, "_tariffs_config", None)) else None
if tariffs_config and callable(getattr(self, "_resolve_tariff", None)):
try:
tariff = self._resolve_tariff(getattr(sub, "tariff_key", None))
except Exception:
tariff = None
if tariff and tariff.billing_model == "period":
amount = tariff.period_price(
months,
default_currency_key_for_settings(self.settings),
)
if amount is None:
amount = self.settings.subscription_options.get(months)
if not amount:
logging.error(f"Auto-renew price missing for {months} months")
return False
metadata = {
"user_id": str(sub.user_id),
"auto_renew_for_subscription_id": str(sub.subscription_id),
"subscription_months": str(months),
}
resp = await yk.create_payment(
amount=float(amount),
currency=currency,
description=f"Auto-renewal for {months} months",
metadata=metadata,
payment_method_id=default_pm.provider_payment_method_id,
save_payment_method=False,
capture=True,
)
if not resp or resp.get("status") not in {"pending", "waiting_for_capture", "succeeded"}:
logging.error(f"Auto-renew create_payment failed: {resp}")
return False
logging.info(f"Auto-renew initiated for user {sub.user_id} payment_id={resp.get('id')}")
return True