# ruff: noqa: F401,F403,F405,I001 from ._runtime import * # noqa: F403,F405 class PaymentContextMixin: # Human-readable provider names rendered in payment-success emails. # Keys are the lowercased value persisted in ``subscriptions.provider`` # (see the call sites in lifecycle.py / traffic.py); missing keys produce # no row in the email rather than raising. _PROVIDER_LABELS = { "yookassa": "YooKassa", "freekassa": "FreeKassa", "platega": "Platega", "severpay": "SeverPay", "wata": "Wata", "cryptopay": "Crypto Pay", "telegram_stars": "Telegram Stars", } async def _record_payment_context( self, session: AsyncSession, payment_db_id: int, *, sale_mode: str, tariff_key: Optional[str], purchased_gb: Optional[float] = None, purchased_hwid_devices: Optional[int] = None, hwid_valid_from: Optional[datetime] = None, hwid_valid_until: Optional[datetime] = None, hwid_pricing_period_months: Optional[int] = None, hwid_proration_ratio: Optional[float] = None, hwid_full_price: Optional[float] = None, ) -> None: payment = await payment_dal.get_payment_by_db_id(session, payment_db_id) if not payment: return payment.sale_mode = sale_mode payment.tariff_key = tariff_key payment.purchased_gb = purchased_gb if purchased_hwid_devices is not None: payment.purchased_hwid_devices = purchased_hwid_devices if hwid_valid_from is not None: payment.hwid_valid_from = hwid_valid_from if hwid_valid_until is not None: payment.hwid_valid_until = hwid_valid_until if hwid_pricing_period_months is not None: payment.hwid_pricing_period_months = hwid_pricing_period_months if hwid_proration_ratio is not None: payment.hwid_proration_ratio = hwid_proration_ratio if hwid_full_price is not None: payment.hwid_full_price = hwid_full_price await session.flush() async def get_user_language(self, session: AsyncSession, user_id: int) -> str: user_record = await user_dal.get_user_by_id(session, user_id) return ( user_record.language_code if user_record and user_record.language_code else self.settings.DEFAULT_LANGUAGE ) async def has_had_any_subscription(self, session: AsyncSession, user_id: int) -> bool: return await subscription_dal.has_any_subscription_for_user(session, user_id) async def has_trial_blocking_subscription(self, session: AsyncSession, user_id: int) -> bool: return await subscription_dal.has_trial_blocking_subscription_for_user(session, user_id) async def has_active_subscription(self, session: AsyncSession, user_id: int) -> bool: """Return True if user currently has an active subscription (end_date in future).""" try: user_record = await user_dal.get_user_by_id(session, user_id) if not user_record or not user_record.panel_user_uuid: return False active_sub = await subscription_dal.get_active_subscription_by_user_id( session, user_id, user_record.panel_user_uuid ) if not active_sub or not active_sub.end_date: return False from datetime import datetime, timezone return active_sub.is_active and active_sub.end_date > datetime.now(timezone.utc) except Exception: return False async def _send_payment_success_email( self, *, db_user: User, sale_mode: str, months: int, traffic_gb: Optional[float], payment_amount: float, end_date: Optional[datetime], provider: str, ) -> None: """Best-effort branded email confirming the payment. No-op if SMTP or the user's email aren't set. Failures are logged and swallowed so the payment flow is never blocked by mail delivery.""" if not getattr(self.settings, "email_auth_configured", False): return recipient = (db_user.email or "").strip() if db_user else "" if not recipient: return end_date_text = end_date.strftime("%Y-%m-%d") if end_date else "" try: from bot.payment_providers import provider_label_map provider_label = provider_label_map( self.settings, db_user.language_code or self.settings.DEFAULT_LANGUAGE, ).get((provider or "").lower()) except Exception: provider_label = self._PROVIDER_LABELS.get((provider or "").lower()) dashboard_url = (self.settings.SUBSCRIPTION_MINI_APP_URL or "").strip() or None i18n = getattr(self, "i18n", None) try: content = render_payment_success( self.settings, language_code=db_user.language_code or self.settings.DEFAULT_LANGUAGE, sale_mode=sale_mode, months=int(months or 0), traffic_gb=traffic_gb, amount=float(payment_amount or 0), currency=default_payment_currency_code_for_settings(self.settings), end_date_text=end_date_text, dashboard_url=dashboard_url, provider_label=provider_label, i18n=i18n, ) email_service = EmailAuthService(self.settings, i18n) await email_service.send_rendered_email(email=recipient, content=content) except Exception: logging.exception("Failed to send payment success email to user %s", db_user.user_id) async def update_last_notification_sent( self, session: AsyncSession, user_id: int, subscription_end_date: datetime ): sub_to_update = await subscription_dal.find_subscription_for_notification_update( session, user_id, subscription_end_date ) if sub_to_update: await subscription_dal.update_subscription_notification_time( session, sub_to_update.subscription_id, datetime.now(timezone.utc) ) logging.info( f"Updated last_notification_sent for user {user_id}, sub_id {sub_to_update.subscription_id}" # noqa: E501 ) else: logging.warning( f"Could not find subscription for user {user_id} ending at {subscription_end_date.isoformat()} to update notification time." # noqa: E501 )