import logging from sqlalchemy.ext.asyncio import AsyncSession from typing import Optional, Tuple, Dict from aiogram import Bot from config.settings import Settings from db.dal import promo_code_dal, user_dal, subscription_dal from db.models import PromoCode, User from .subscription_service import SubscriptionService from bot.middlewares.i18n import JsonI18n class PromoCodeService: def __init__(self, settings: Settings, subscription_service: SubscriptionService, bot: Bot, i18n: JsonI18n): self.settings = settings self.subscription_service = subscription_service self.bot = bot self.i18n = i18n async def apply_promo_code(self, session: AsyncSession, user_id: int, code_input: str, user_lang: str) -> Tuple[bool, str]: _ = lambda k, **kw: self.i18n.gettext(user_lang, k, **kw) code_input_upper = code_input.strip().upper() promo_data = await promo_code_dal.get_active_promo_code_by_code_str( session, code_input_upper) if not promo_data: return False, _("promo_code_not_found", code=code_input_upper) existing_activation = await promo_code_dal.get_user_activation_for_promo( session, promo_data.promo_code_id, user_id) if existing_activation: return False, _("promo_code_already_used_by_user", code=code_input_upper) active_sub = await subscription_dal.get_active_subscription_by_user_id( session, user_id) if not active_sub: return False, _("promo_code_no_active_subscription") bonus_days = promo_data.bonus_days new_end_date = await self.subscription_service.extend_active_subscription_days( session=session, user_id=user_id, bonus_days=bonus_days, reason=f"promo code {code_input_upper}") if new_end_date: activation_recorded = await promo_code_dal.record_promo_activation( session, promo_data.promo_code_id, user_id, payment_id=None) promo_incremented = await promo_code_dal.increment_promo_code_usage( session, promo_data.promo_code_id) if activation_recorded and promo_incremented: return True, _("promo_code_applied_success", code=code_input_upper, bonus_days=bonus_days, new_end_date=new_end_date.strftime('%Y-%m-%d')) else: logging.error( f"Failed to record activation or increment usage for promo {promo_data.code} by user {user_id}" ) return False, _("error_applying_promo_bonus") else: return False, _("error_applying_promo_bonus")