diff --git a/app/database/crud/promo_offer_template.py b/app/database/crud/promo_offer_template.py index 9ebdd5fd..3f289b78 100644 --- a/app/database/crud/promo_offer_template.py +++ b/app/database/crud/promo_offer_template.py @@ -10,6 +10,36 @@ from app.config import settings from app.database.models import PromoOfferTemplate +UPDATED_TEMPLATE_MESSAGES = { + "extend_discount": ( + "πŸ’Ž Экономия {discount_percent}% ΠΏΡ€ΠΈ ΠΏΡ€ΠΎΠ΄Π»Π΅Π½ΠΈΠΈ\n\n" + "Π‘ΠΊΠΈΠ΄ΠΊΠ° суммируСтся с ΠΏΡ€ΠΎΠΌΠΎΠ³Ρ€ΡƒΠΏΠΏΠΎΠΉ ΠΈ дСйствуСт ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π·.\n" + "Π‘Ρ€ΠΎΠΊ дСйствия прСдлоТСния β€” {valid_hours} Ρ‡." + ), + "purchase_discount": ( + "🎯 Π’Π΅Ρ€Π½ΠΈΡ‚Π΅ΡΡŒ со скидкой {discount_percent}%\n\n" + "Π‘ΠΊΠΈΠ΄ΠΊΠ° суммируСтся с ΠΏΡ€ΠΎΠΌΠΎΠ³Ρ€ΡƒΠΏΠΏΠΎΠΉ ΠΈ дСйствуСт ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π·.\n" + "ΠŸΡ€Π΅Π΄Π»ΠΎΠΆΠ΅Π½ΠΈΠ΅ дСйствуСт {valid_hours} Ρ‡." + ), +} + + +LEGACY_TEMPLATE_MESSAGES = { + "extend_discount": ( + "πŸ’Ž Экономия {discount_percent}% ΠΏΡ€ΠΈ ΠΏΡ€ΠΎΠ΄Π»Π΅Π½ΠΈΠΈ\n\n" + "АктивируйтС ΠΏΡ€Π΅Π΄Π»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚Π΅ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΡƒΡŽ скидку Π½Π° ΠΎΠΏΠ»Π°Ρ‚Ρƒ продлСния. " + "Она суммируСтся с вашими ΠΏΡ€ΠΎΠΌΠΎΠ³Ρ€ΡƒΠΏΠΏΠΎΠ²Ρ‹ΠΌΠΈ скидками ΠΈ дСйствуСт ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π·.\n" + "Π‘Ρ€ΠΎΠΊ дСйствия прСдлоТСния β€” {valid_hours} Ρ‡." + ), + "purchase_discount": ( + "🎯 Π’Π΅Ρ€Π½ΠΈΡ‚Π΅ΡΡŒ со скидкой {discount_percent}%\n\n" + "ПослС Π°ΠΊΡ‚ΠΈΠ²Π°Ρ†ΠΈΠΈ ΠΌΡ‹ ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΠΌ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΡƒΡŽ скидку ΠΊ вашСй ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ ΠΎΠΏΠ»Π°Ρ‚Π΅ подписки. " + "Π‘ΠΊΠΈΠ΄ΠΊΠ° суммируСтся с ΠΏΡ€ΠΎΠΌΠΎΠ³Ρ€ΡƒΠΏΠΏΠΎΠΉ ΠΈ дСйствуСт ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π·.\n" + "ΠŸΡ€Π΅Π΄Π»ΠΎΠΆΠ΅Π½ΠΈΠ΅ дСйствуСт {valid_hours} Ρ‡." + ), +} + + DEFAULT_TEMPLATES: tuple[dict, ...] = ( { "offer_type": "test_access", @@ -29,12 +59,7 @@ DEFAULT_TEMPLATES: tuple[dict, ...] = ( { "offer_type": "extend_discount", "name": "Π‘ΠΊΠΈΠ΄ΠΊΠ° Π½Π° ΠΏΡ€ΠΎΠ΄Π»Π΅Π½ΠΈΠ΅", - "message_text": ( - "πŸ’Ž Экономия {discount_percent}% ΠΏΡ€ΠΈ ΠΏΡ€ΠΎΠ΄Π»Π΅Π½ΠΈΠΈ\n\n" - "АктивируйтС ΠΏΡ€Π΅Π΄Π»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚Π΅ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΡƒΡŽ скидку Π½Π° ΠΎΠΏΠ»Π°Ρ‚Ρƒ продлСния. " - "Она суммируСтся с вашими ΠΏΡ€ΠΎΠΌΠΎΠ³Ρ€ΡƒΠΏΠΏΠΎΠ²Ρ‹ΠΌΠΈ скидками ΠΈ дСйствуСт ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π·.\n" - "Π‘Ρ€ΠΎΠΊ дСйствия прСдлоТСния β€” {valid_hours} Ρ‡." - ), + "message_text": UPDATED_TEMPLATE_MESSAGES["extend_discount"], "button_text": "🎁 ΠŸΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ скидку", "valid_hours": 24, "discount_percent": 20, @@ -45,12 +70,7 @@ DEFAULT_TEMPLATES: tuple[dict, ...] = ( { "offer_type": "purchase_discount", "name": "Π‘ΠΊΠΈΠ΄ΠΊΠ° Π½Π° ΠΏΠΎΠΊΡƒΠΏΠΊΡƒ", - "message_text": ( - "🎯 Π’Π΅Ρ€Π½ΠΈΡ‚Π΅ΡΡŒ со скидкой {discount_percent}%\n\n" - "ПослС Π°ΠΊΡ‚ΠΈΠ²Π°Ρ†ΠΈΠΈ ΠΌΡ‹ ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΠΌ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΡƒΡŽ скидку ΠΊ вашСй ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ ΠΎΠΏΠ»Π°Ρ‚Π΅ подписки. " - "Π‘ΠΊΠΈΠ΄ΠΊΠ° суммируСтся с ΠΏΡ€ΠΎΠΌΠΎΠ³Ρ€ΡƒΠΏΠΏΠΎΠΉ ΠΈ дСйствуСт ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π·.\n" - "ΠŸΡ€Π΅Π΄Π»ΠΎΠΆΠ΅Π½ΠΈΠ΅ дСйствуСт {valid_hours} Ρ‡." - ), + "message_text": UPDATED_TEMPLATE_MESSAGES["purchase_discount"], "button_text": "🎁 Π—Π°Π±Ρ€Π°Ρ‚ΡŒ скидку", "valid_hours": 48, "discount_percent": 25, @@ -80,6 +100,21 @@ async def ensure_default_templates(db: AsyncSession, *, created_by: Optional[int ) existing = result.scalars().first() if existing: + new_message = UPDATED_TEMPLATE_MESSAGES.get(template_data["offer_type"]) + legacy_message = LEGACY_TEMPLATE_MESSAGES.get(template_data["offer_type"]) + should_update = False + + if new_message and legacy_message and existing.message_text == legacy_message: + should_update = True + elif new_message and ( + "{bonus_amount" in existing.message_text or "ΠœΡ‹ начислим" in existing.message_text + ): + should_update = True + + if should_update and new_message: + existing.message_text = new_message + existing.updated_at = datetime.utcnow() + await db.flush() templates.append(existing) continue diff --git a/app/database/crud/user.py b/app/database/crud/user.py index 147c8fd3..9dacb13b 100644 --- a/app/database/crud/user.py +++ b/app/database/crud/user.py @@ -273,6 +273,8 @@ async def subtract_user_balance( description: str, create_transaction: bool = False, payment_method: Optional[PaymentMethod] = None, + *, + consume_promo_offer: bool = False, ) -> bool: logger.error(f"πŸ’Έ ΠžΠ’Π›ΠΠ”ΠšΠ subtract_user_balance:") logger.error(f" πŸ‘€ User ID: {user.id} (TG: {user.telegram_id})") @@ -287,6 +289,11 @@ async def subtract_user_balance( try: old_balance = user.balance_kopeks user.balance_kopeks -= amount_kopeks + + if consume_promo_offer and getattr(user, "promo_offer_discount_percent", 0): + user.promo_offer_discount_percent = 0 + user.promo_offer_discount_source = None + user.updated_at = datetime.utcnow() await db.commit() diff --git a/app/handlers/admin/promo_offers.py b/app/handlers/admin/promo_offers.py index bac92821..1f308312 100644 --- a/app/handlers/admin/promo_offers.py +++ b/app/handlers/admin/promo_offers.py @@ -113,7 +113,7 @@ def _build_offer_detail_keyboard(template: PromoOfferTemplate, language: str) -> InlineKeyboardButton(text="πŸ“¬ ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ", callback_data=f"promo_offer_send_menu_{template.id}"), ]) rows.append([ - InlineKeyboardButton(text=texts.BACK, callback_data="admin_messages"), + InlineKeyboardButton(text=texts.BACK, callback_data="admin_promo_offers"), ]) return InlineKeyboardMarkup(inline_keyboard=rows) diff --git a/app/handlers/subscription.py b/app/handlers/subscription.py index ec511aac..2e5280bd 100644 --- a/app/handlers/subscription.py +++ b/app/handlers/subscription.py @@ -133,18 +133,6 @@ def _apply_promo_offer_discount(user: Optional[User], amount: int) -> Dict[str, return {"discounted": discounted, "discount": discount_value, "percent": percent} -async def _consume_promo_offer_discount(db: AsyncSession, user: User) -> None: - if _get_promo_offer_discount_percent(user) <= 0: - return - - user.promo_offer_discount_percent = 0 - user.promo_offer_discount_source = None - user.updated_at = datetime.utcnow() - - await db.commit() - await db.refresh(user) - - def _get_period_hint_from_subscription(subscription: Optional[Subscription]) -> Optional[int]: if not subscription: return None @@ -2891,8 +2879,11 @@ async def confirm_extend_subscription( try: success = await subtract_user_balance( - db, db_user, price, - f"ΠŸΡ€ΠΎΠ΄Π»Π΅Π½ΠΈΠ΅ подписки Π½Π° {days} Π΄Π½Π΅ΠΉ" + db, + db_user, + price, + f"ΠŸΡ€ΠΎΠ΄Π»Π΅Π½ΠΈΠ΅ подписки Π½Π° {days} Π΄Π½Π΅ΠΉ", + consume_promo_offer=promo_component["discount"] > 0, ) if not success: @@ -2989,9 +2980,6 @@ async def confirm_extend_subscription( f" -{texts.format_price(promo_component['discount'])})" ) - if promo_component["discount"] > 0: - await _consume_promo_offer_discount(db, db_user) - await callback.message.edit_text( success_message, reply_markup=get_back_keyboard(db_user.language) @@ -3760,8 +3748,11 @@ async def confirm_purchase( try: success = await subtract_user_balance( - db, db_user, final_price, - f"ΠŸΠΎΠΊΡƒΠΏΠΊΠ° подписки Π½Π° {data['period_days']} Π΄Π½Π΅ΠΉ" + db, + db_user, + final_price, + f"ΠŸΠΎΠΊΡƒΠΏΠΊΠ° подписки Π½Π° {data['period_days']} Π΄Π½Π΅ΠΉ", + consume_promo_offer=promo_offer_discount_value > 0, ) if not success: @@ -4043,9 +4034,6 @@ async def confirm_purchase( callback_data="back_to_menu")], ]) - if promo_offer_discount_value > 0: - await _consume_promo_offer_discount(db, db_user) - await callback.message.edit_text( success_text, reply_markup=connect_keyboard, @@ -4055,9 +4043,6 @@ async def confirm_purchase( purchase_text = texts.SUBSCRIPTION_PURCHASED if discount_note: purchase_text = f"{purchase_text}\n\n{discount_note}" - if promo_offer_discount_value > 0: - await _consume_promo_offer_discount(db, db_user) - await callback.message.edit_text( texts.t( "SUBSCRIPTION_LINK_GENERATING_NOTICE",