from __future__ import annotations from datetime import datetime from typing import Iterable, List, Optional from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.config import settings from app.database.models import PromoOfferTemplate UPDATED_TEMPLATE_MESSAGES = { "extend_discount": ( "πŸ’Ž Экономия {discount_percent}% ΠΏΡ€ΠΈ ΠΏΡ€ΠΎΠ΄Π»Π΅Π½ΠΈΠΈ\n\n" "Π‘ΠΊΠΈΠ΄ΠΊΠ° суммируСтся с ΠΏΡ€ΠΎΠΌΠΎΠ³Ρ€ΡƒΠΏΠΏΠΎΠΉ ΠΈ дСйствуСт ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π·.\n" "Π‘Ρ€ΠΎΠΊ дСйствия прСдлоТСния β€” {valid_hours} Ρ‡.\n" "ПослС Π°ΠΊΡ‚ΠΈΠ²Π°Ρ†ΠΈΠΈ скидка дСйствуСт {active_discount_hours} Ρ‡." ), "purchase_discount": ( "🎯 Π’Π΅Ρ€Π½ΠΈΡ‚Π΅ΡΡŒ со скидкой {discount_percent}%\n\n" "Π‘ΠΊΠΈΠ΄ΠΊΠ° суммируСтся с ΠΏΡ€ΠΎΠΌΠΎΠ³Ρ€ΡƒΠΏΠΏΠΎΠΉ ΠΈ дСйствуСт ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π·.\n" "ΠŸΡ€Π΅Π΄Π»ΠΎΠΆΠ΅Π½ΠΈΠ΅ дСйствуСт {valid_hours} Ρ‡.\n" "ПослС Π°ΠΊΡ‚ΠΈΠ²Π°Ρ†ΠΈΠΈ скидка дСйствуСт {active_discount_hours} Ρ‡." ), } LEGACY_TEMPLATE_MESSAGES = { "extend_discount": ( "πŸ’Ž Экономия {discount_percent}% ΠΏΡ€ΠΈ ΠΏΡ€ΠΎΠ΄Π»Π΅Π½ΠΈΠΈ\n\n" "АктивируйтС ΠΏΡ€Π΅Π΄Π»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚Π΅ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΡƒΡŽ скидку Π½Π° ΠΎΠΏΠ»Π°Ρ‚Ρƒ продлСния. " "Она суммируСтся с вашими ΠΏΡ€ΠΎΠΌΠΎΠ³Ρ€ΡƒΠΏΠΏΠΎΠ²Ρ‹ΠΌΠΈ скидками ΠΈ дСйствуСт ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π·.\n" "Π‘Ρ€ΠΎΠΊ дСйствия прСдлоТСния β€” {valid_hours} Ρ‡.\n" "ПослС Π°ΠΊΡ‚ΠΈΠ²Π°Ρ†ΠΈΠΈ скидка дСйствуСт {active_discount_hours} Ρ‡." ), "purchase_discount": ( "🎯 Π’Π΅Ρ€Π½ΠΈΡ‚Π΅ΡΡŒ со скидкой {discount_percent}%\n\n" "ПослС Π°ΠΊΡ‚ΠΈΠ²Π°Ρ†ΠΈΠΈ ΠΌΡ‹ ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΠΌ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΡƒΡŽ скидку ΠΊ вашСй ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ ΠΎΠΏΠ»Π°Ρ‚Π΅ подписки. " "Π‘ΠΊΠΈΠ΄ΠΊΠ° суммируСтся с ΠΏΡ€ΠΎΠΌΠΎΠ³Ρ€ΡƒΠΏΠΏΠΎΠΉ ΠΈ дСйствуСт ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π·.\n" "ΠŸΡ€Π΅Π΄Π»ΠΎΠΆΠ΅Π½ΠΈΠ΅ дСйствуСт {valid_hours} Ρ‡.\n" "ПослС Π°ΠΊΡ‚ΠΈΠ²Π°Ρ†ΠΈΠΈ скидка дСйствуСт {active_discount_hours} Ρ‡." ), } DEFAULT_TEMPLATES: tuple[dict, ...] = ( { "offer_type": "test_access", "name": "ВСстовыС сСрвСра", "message_text": ( "πŸ”₯ Π˜ΡΠΏΡ‹Ρ‚Π°ΠΉΡ‚Π΅ Π½ΠΎΠ²Ρ‹Π΅ сСрвСра\n\n" "АктивируйтС ΠΏΡ€Π΅Π΄Π»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚Π΅ Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΉ доступ ΠΊ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌ сквадам Π½Π° {test_duration_hours} Ρ‡.\n" "ΠŸΡ€Π΅Π΄Π»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π΄Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ {valid_hours} Ρ‡." ), "button_text": "πŸš€ ΠŸΠΎΠΏΡ€ΠΎΠ±ΠΎΠ²Π°Ρ‚ΡŒ сСрвСры", "valid_hours": 24, "discount_percent": 0, "bonus_amount_kopeks": 0, "active_discount_hours": None, "test_duration_hours": 24, "test_squad_uuids": [], }, { "offer_type": "extend_discount", "name": "Π‘ΠΊΠΈΠ΄ΠΊΠ° Π½Π° ΠΏΡ€ΠΎΠ΄Π»Π΅Π½ΠΈΠ΅", "message_text": UPDATED_TEMPLATE_MESSAGES["extend_discount"], "button_text": "🎁 ΠŸΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ скидку", "valid_hours": 24, "discount_percent": 20, "bonus_amount_kopeks": 0, "active_discount_hours": 24, "test_duration_hours": None, "test_squad_uuids": [], }, { "offer_type": "purchase_discount", "name": "Π‘ΠΊΠΈΠ΄ΠΊΠ° Π½Π° ΠΏΠΎΠΊΡƒΠΏΠΊΡƒ", "message_text": UPDATED_TEMPLATE_MESSAGES["purchase_discount"], "button_text": "🎁 Π—Π°Π±Ρ€Π°Ρ‚ΡŒ скидку", "valid_hours": 48, "discount_percent": 25, "bonus_amount_kopeks": 0, "active_discount_hours": 48, "test_duration_hours": None, "test_squad_uuids": [], }, ) def _format_template_fields(payload: dict) -> dict: data = dict(payload) data.setdefault("valid_hours", 24) data.setdefault("discount_percent", 0) data.setdefault("bonus_amount_kopeks", 0) data.setdefault("active_discount_hours", None) data.setdefault("test_duration_hours", None) data.setdefault("test_squad_uuids", []) return data async def ensure_default_templates(db: AsyncSession, *, created_by: Optional[int] = None) -> List[PromoOfferTemplate]: templates: List[PromoOfferTemplate] = [] for template_data in DEFAULT_TEMPLATES: result = await db.execute( select(PromoOfferTemplate).where(PromoOfferTemplate.offer_type == template_data["offer_type"]) ) 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() target_active_hours = template_data.get("active_discount_hours") if ( target_active_hours is not None and target_active_hours > 0 and not existing.active_discount_hours ): existing.active_discount_hours = target_active_hours existing.updated_at = datetime.utcnow() await db.flush() templates.append(existing) continue payload = _format_template_fields(template_data) template = PromoOfferTemplate( name=payload["name"], offer_type=payload["offer_type"], message_text=payload["message_text"], button_text=payload["button_text"], valid_hours=payload["valid_hours"], discount_percent=payload["discount_percent"], bonus_amount_kopeks=payload["bonus_amount_kopeks"], active_discount_hours=payload["active_discount_hours"], test_duration_hours=payload["test_duration_hours"], test_squad_uuids=payload["test_squad_uuids"], is_active=True, created_by=created_by, ) db.add(template) await db.flush() templates.append(template) await db.commit() return templates async def list_promo_offer_templates(db: AsyncSession) -> List[PromoOfferTemplate]: result = await db.execute( select(PromoOfferTemplate).order_by(PromoOfferTemplate.offer_type, PromoOfferTemplate.id) ) return result.scalars().all() async def get_promo_offer_template_by_id(db: AsyncSession, template_id: int) -> Optional[PromoOfferTemplate]: result = await db.execute( select(PromoOfferTemplate).where(PromoOfferTemplate.id == template_id) ) return result.scalar_one_or_none() async def get_promo_offer_template_by_type(db: AsyncSession, offer_type: str) -> Optional[PromoOfferTemplate]: result = await db.execute( select(PromoOfferTemplate).where(PromoOfferTemplate.offer_type == offer_type) ) return result.scalar_one_or_none() async def update_promo_offer_template( db: AsyncSession, template: PromoOfferTemplate, *, name: Optional[str] = None, message_text: Optional[str] = None, button_text: Optional[str] = None, valid_hours: Optional[int] = None, discount_percent: Optional[int] = None, bonus_amount_kopeks: Optional[int] = None, active_discount_hours: Optional[int] = None, test_duration_hours: Optional[int] = None, test_squad_uuids: Optional[Iterable[str]] = None, is_active: Optional[bool] = None, ) -> PromoOfferTemplate: if name is not None: template.name = name if message_text is not None: template.message_text = message_text if button_text is not None: template.button_text = button_text if valid_hours is not None: template.valid_hours = valid_hours if discount_percent is not None: template.discount_percent = discount_percent if bonus_amount_kopeks is not None: template.bonus_amount_kopeks = bonus_amount_kopeks if active_discount_hours is not None: template.active_discount_hours = active_discount_hours if test_duration_hours is not None: template.test_duration_hours = test_duration_hours if test_squad_uuids is not None: template.test_squad_uuids = list(test_squad_uuids) if is_active is not None: template.is_active = is_active template.updated_at = datetime.utcnow() await db.commit() await db.refresh(template) return template