diff --git a/app/webapi/routes/miniapp.py b/app/webapi/routes/miniapp.py index c5de0b71..1a446032 100644 --- a/app/webapi/routes/miniapp.py +++ b/app/webapi/routes/miniapp.py @@ -9,9 +9,8 @@ from sqlalchemy.ext.asyncio import AsyncSession from app.config import settings from app.database.crud.server_squad import get_server_squad_by_uuid -from app.database.crud.transaction import get_user_total_spent_kopeks from app.database.crud.user import get_user_by_telegram_id -from app.database.models import PromoGroup, Subscription, Transaction, User +from app.database.models import Subscription, Transaction, User from app.services.remnawave_service import ( RemnaWaveConfigurationError, RemnaWaveService, @@ -27,7 +26,6 @@ from ..dependencies import get_db_session from ..schemas.miniapp import ( MiniAppConnectedServer, MiniAppDevice, - MiniAppAutoPromoLevel, MiniAppPromoGroup, MiniAppSubscriptionRequest, MiniAppSubscriptionResponse, @@ -65,25 +63,6 @@ def _format_limit_label(limit: Optional[int]) -> str: return f"{limit} GB" -def _format_price_label(value: Optional[int]) -> str: - try: - kopeks = int(value or 0) - except (TypeError, ValueError): - kopeks = 0 - - formatter = getattr(settings, "format_price", None) - if callable(formatter): - try: - return str(formatter(kopeks)) - except Exception: # pragma: no cover - defensive formatting - logger.debug("Failed to format price via settings.format_price", exc_info=True) - - symbol = getattr(settings, "CURRENCY_SYMBOL", None) or getattr(settings, "BALANCE_CURRENCY_SYMBOL", None) - symbol = (symbol or "₽").strip() - amount = kopeks / 100 - return f"{amount:.2f} {symbol}".strip() - - def _bytes_to_gb(bytes_value: Optional[int]) -> float: if not bytes_value: return 0.0 @@ -216,42 +195,6 @@ async def _load_devices_info(user: User) -> Tuple[int, List[MiniAppDevice]]: return total_devices, devices -async def _load_auto_promo_levels( - db: AsyncSession, - user: User, - promo_group: Optional[PromoGroup], -) -> Tuple[int, List[MiniAppAutoPromoLevel], Optional[str]]: - total_spent_kopeks = await get_user_total_spent_kopeks(db, user.id) or 0 - - result = await db.execute( - select(PromoGroup) - .where(PromoGroup.auto_assign_total_spent_kopeks.is_not(None)) - .where(PromoGroup.auto_assign_total_spent_kopeks > 0) - .order_by( - PromoGroup.auto_assign_total_spent_kopeks.asc(), - PromoGroup.id.asc(), - ) - ) - groups = list(result.scalars().all()) - - levels: List[MiniAppAutoPromoLevel] = [] - for group in groups: - threshold = group.auto_assign_total_spent_kopeks or 0 - levels.append( - MiniAppAutoPromoLevel( - id=group.id, - name=group.name, - threshold_kopeks=threshold, - threshold_label=_format_price_label(threshold) if threshold > 0 else None, - is_unlocked=bool(threshold and total_spent_kopeks >= threshold), - is_current=bool(promo_group and group.id == promo_group.id), - ) - ) - - total_spent_label = _format_price_label(total_spent_kopeks) if total_spent_kopeks else None - return total_spent_kopeks, levels, total_spent_label - - def _resolve_display_name(user_data: Dict[str, Any]) -> str: username = user_data.get("username") if username: @@ -393,11 +336,6 @@ async def get_subscription_details( balance_currency = balance_currency.upper() promo_group = getattr(user, "promo_group", None) - total_spent_kopeks, auto_promo_levels, total_spent_label = await _load_auto_promo_levels( - db, - user, - promo_group, - ) response_user = MiniAppSubscriptionUser( telegram_id=user.telegram_id, @@ -451,9 +389,6 @@ async def get_subscription_details( promo_group=MiniAppPromoGroup(id=promo_group.id, name=promo_group.name) if promo_group else None, - auto_promo_levels=auto_promo_levels, - total_spent_kopeks=total_spent_kopeks, - total_spent_label=total_spent_label, subscription_type="trial" if subscription.is_trial else "paid", autopay_enabled=bool(subscription.autopay_enabled), branding=settings.get_miniapp_branding(), diff --git a/app/webapi/schemas/miniapp.py b/app/webapi/schemas/miniapp.py index 7cda6463..3461e170 100644 --- a/app/webapi/schemas/miniapp.py +++ b/app/webapi/schemas/miniapp.py @@ -41,15 +41,6 @@ class MiniAppPromoGroup(BaseModel): name: str -class MiniAppAutoPromoLevel(BaseModel): - id: int - name: str - threshold_kopeks: int - threshold_label: Optional[str] = None - is_unlocked: bool = False - is_current: bool = False - - class MiniAppConnectedServer(BaseModel): uuid: str name: str @@ -99,9 +90,6 @@ class MiniAppSubscriptionResponse(BaseModel): balance_currency: Optional[str] = None transactions: List[MiniAppTransaction] = Field(default_factory=list) promo_group: Optional[MiniAppPromoGroup] = None - auto_promo_levels: List[MiniAppAutoPromoLevel] = Field(default_factory=list) - total_spent_kopeks: int = 0 - total_spent_label: Optional[str] = None subscription_type: str autopay_enabled: bool = False branding: Optional[MiniAppBranding] = None diff --git a/miniapp/index.html b/miniapp/index.html index 2a88d708..29d0c127 100644 --- a/miniapp/index.html +++ b/miniapp/index.html @@ -576,118 +576,6 @@ text-align: right; } - /* Promo Group */ - .promo-card .card-content { - padding: 20px; - display: flex; - flex-direction: column; - gap: 16px; - } - - .promo-group-row { - display: flex; - align-items: center; - justify-content: space-between; - gap: 12px; - } - - .promo-group-value { - font-weight: 700; - color: var(--text-primary); - } - - .promo-levels-title { - font-size: 13px; - font-weight: 600; - color: var(--text-secondary); - text-transform: uppercase; - letter-spacing: 0.5px; - } - - .promo-levels-list { - list-style: none; - padding: 0; - margin: 0; - display: flex; - flex-direction: column; - gap: 12px; - } - - .promo-level-item { - display: flex; - align-items: center; - justify-content: space-between; - gap: 16px; - padding: 12px 16px; - border: 1px solid var(--border-color); - border-radius: var(--radius); - background: rgba(var(--primary-rgb), 0.04); - transition: all 0.2s ease; - } - - .promo-level-item.unlocked { - border-color: rgba(16, 185, 129, 0.4); - background: rgba(16, 185, 129, 0.08); - } - - .promo-level-details { - display: flex; - flex-direction: column; - gap: 4px; - min-width: 0; - } - - .promo-level-name { - font-weight: 600; - color: var(--text-primary); - display: flex; - align-items: center; - gap: 8px; - } - - .promo-level-threshold { - font-size: 13px; - color: var(--text-secondary); - } - - .promo-level-status { - display: flex; - align-items: center; - gap: 6px; - font-size: 13px; - font-weight: 600; - color: var(--text-secondary); - } - - .promo-level-status.unlocked { - color: var(--success); - } - - .promo-level-status-icon { - font-size: 16px; - } - - .promo-level-badge { - display: inline-flex; - align-items: center; - padding: 2px 8px; - border-radius: 999px; - background: rgba(var(--primary-rgb), 0.12); - color: var(--primary); - font-size: 11px; - text-transform: uppercase; - letter-spacing: 0.4px; - } - - .promo-levels-empty { - font-size: 13px; - color: var(--text-secondary); - text-align: center; - padding: 12px; - border: 1px dashed var(--border-color); - border-radius: var(--radius); - } - /* Balance Card */ .balance-card { background: linear-gradient(135deg, rgba(var(--primary-rgb), 0.1), rgba(var(--primary-rgb), 0.05)); @@ -1322,8 +1210,7 @@ :root[data-theme="dark"] .server-item, :root[data-theme="dark"] .device-item, :root[data-theme="dark"] .app-card, - :root[data-theme="dark"] .platform-btn, - :root[data-theme="dark"] .promo-level-item { + :root[data-theme="dark"] .platform-btn { background: var(--bg-secondary); } @@ -1361,8 +1248,7 @@ :root[data-theme="dark"] .balance-card, :root[data-theme="dark"] .card.expandable, :root[data-theme="dark"] .language-select, - :root[data-theme="dark"] .theme-toggle, - :root[data-theme="dark"] .promo-card { + :root[data-theme="dark"] .theme-toggle { background: var(--bg-primary); } @@ -1371,8 +1257,7 @@ :root[data-theme="dark"] .stat-item, :root[data-theme="dark"] .server-item, :root[data-theme="dark"] .device-item, - :root[data-theme="dark"] .app-card, - :root[data-theme="dark"] .promo-level-item { + :root[data-theme="dark"] .app-card { border-color: rgba(148, 163, 184, 0.25); } @@ -1503,37 +1388,12 @@ Auto-Pay - + - - -
-
-
- - - - Promo program -
-
-
-
- Promo group - -
-
-
Auto-issued levels
-
    - -
    -
    -
    - - -
    -