mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-01-20 03:40:26 +00:00
Revert "Add API to update referrer commission percent"
This commit is contained in:
@@ -15,7 +15,6 @@ from .routes import (
|
||||
main_menu_buttons,
|
||||
media,
|
||||
miniapp,
|
||||
partners,
|
||||
polls,
|
||||
promocodes,
|
||||
promo_groups,
|
||||
@@ -107,10 +106,6 @@ OPENAPI_TAGS = [
|
||||
"name": "miniapp",
|
||||
"description": "Endpoint для Telegram Mini App с информацией о подписке пользователя.",
|
||||
},
|
||||
{
|
||||
"name": "partners",
|
||||
"description": "Просмотр участников реферальной программы, их доходов и рефералов.",
|
||||
},
|
||||
{
|
||||
"name": "polls",
|
||||
"description": "Создание опросов, удаление, статистика и ответы пользователей.",
|
||||
@@ -178,7 +173,6 @@ def create_web_api_app() -> FastAPI:
|
||||
app.include_router(remnawave.router, prefix="/remnawave", tags=["remnawave"])
|
||||
app.include_router(media.router, tags=["media"])
|
||||
app.include_router(miniapp.router, prefix="/miniapp", tags=["miniapp"])
|
||||
app.include_router(partners.router, prefix="/partners", tags=["partners"])
|
||||
app.include_router(polls.router, prefix="/polls", tags=["polls"])
|
||||
app.include_router(logs.router, prefix="/logs", tags=["logs"])
|
||||
app.include_router(
|
||||
|
||||
@@ -4,7 +4,6 @@ from . import (
|
||||
main_menu_buttons,
|
||||
media,
|
||||
miniapp,
|
||||
partners,
|
||||
polls,
|
||||
promo_offers,
|
||||
pages,
|
||||
@@ -27,7 +26,6 @@ __all__ = [
|
||||
"main_menu_buttons",
|
||||
"media",
|
||||
"miniapp",
|
||||
"partners",
|
||||
"polls",
|
||||
"promo_offers",
|
||||
"pages",
|
||||
|
||||
@@ -1,189 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, Security, status
|
||||
from sqlalchemy import func, or_, select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import selectinload
|
||||
|
||||
from app.database.crud.referral import get_detailed_referral_list, get_user_referral_stats
|
||||
from app.database.crud.user import get_user_by_id, get_user_by_telegram_id
|
||||
from app.database.models import User
|
||||
from app.utils.user_utils import get_effective_referral_commission_percent
|
||||
|
||||
from ..dependencies import get_db_session, require_api_token
|
||||
from ..schemas.partners import (
|
||||
PartnerReferralItem,
|
||||
PartnerReferralList,
|
||||
PartnerReferrerCommissionUpdateRequest,
|
||||
PartnerReferrerDetail,
|
||||
PartnerReferrerItem,
|
||||
PartnerReferrerListResponse,
|
||||
)
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
def _apply_search_filter(query, search: str):
|
||||
search_lower = f"%{search.lower()}%"
|
||||
conditions = [
|
||||
func.lower(User.username).like(search_lower),
|
||||
func.lower(User.first_name).like(search_lower),
|
||||
func.lower(User.last_name).like(search_lower),
|
||||
func.lower(User.referral_code).like(search_lower),
|
||||
]
|
||||
|
||||
if search.isdigit():
|
||||
conditions.append(User.telegram_id == int(search))
|
||||
conditions.append(User.id == int(search))
|
||||
|
||||
return query.where(or_(*conditions))
|
||||
|
||||
|
||||
def _serialize_referrer(user: User, stats: dict) -> PartnerReferrerItem:
|
||||
total_earned_kopeks = int(stats.get("total_earned_kopeks") or 0)
|
||||
month_earned_kopeks = int(stats.get("month_earned_kopeks") or 0)
|
||||
|
||||
return PartnerReferrerItem(
|
||||
id=user.id,
|
||||
telegram_id=user.telegram_id,
|
||||
username=user.username,
|
||||
first_name=user.first_name,
|
||||
last_name=user.last_name,
|
||||
referral_code=user.referral_code,
|
||||
referral_commission_percent=getattr(user, "referral_commission_percent", None),
|
||||
effective_referral_commission_percent=get_effective_referral_commission_percent(user),
|
||||
invited_count=int(stats.get("invited_count") or 0),
|
||||
active_referrals=int(stats.get("active_referrals") or 0),
|
||||
total_earned_kopeks=total_earned_kopeks,
|
||||
total_earned_rubles=round(total_earned_kopeks / 100, 2),
|
||||
month_earned_kopeks=month_earned_kopeks,
|
||||
month_earned_rubles=round(month_earned_kopeks / 100, 2),
|
||||
created_at=user.created_at,
|
||||
last_activity=user.last_activity,
|
||||
)
|
||||
|
||||
|
||||
def _serialize_referral_item(referral: dict) -> PartnerReferralItem:
|
||||
balance_kopeks = int(referral.get("balance_kopeks") or 0)
|
||||
total_earned_kopeks = int(referral.get("total_earned_kopeks") or 0)
|
||||
|
||||
return PartnerReferralItem(
|
||||
id=int(referral.get("id")),
|
||||
telegram_id=int(referral.get("telegram_id")),
|
||||
full_name=str(referral.get("full_name")),
|
||||
username=referral.get("username"),
|
||||
created_at=referral.get("created_at"),
|
||||
last_activity=referral.get("last_activity"),
|
||||
has_made_first_topup=bool(referral.get("has_made_first_topup", False)),
|
||||
balance_kopeks=balance_kopeks,
|
||||
balance_rubles=round(balance_kopeks / 100, 2),
|
||||
total_earned_kopeks=total_earned_kopeks,
|
||||
total_earned_rubles=round(total_earned_kopeks / 100, 2),
|
||||
topups_count=int(referral.get("topups_count") or 0),
|
||||
days_since_registration=int(referral.get("days_since_registration") or 0),
|
||||
days_since_activity=referral.get("days_since_activity"),
|
||||
status=str(referral.get("status") or "inactive"),
|
||||
)
|
||||
|
||||
|
||||
@router.get("/referrers", response_model=PartnerReferrerListResponse)
|
||||
async def list_referrers(
|
||||
_: Any = Security(require_api_token),
|
||||
db: AsyncSession = Depends(get_db_session),
|
||||
limit: int = Query(50, ge=1, le=200),
|
||||
offset: int = Query(0, ge=0),
|
||||
search: Optional[str] = Query(default=None),
|
||||
) -> PartnerReferrerListResponse:
|
||||
base_query = select(User).options(selectinload(User.referrer)).where(
|
||||
or_(User.referral_code.isnot(None), User.referrals.any())
|
||||
)
|
||||
|
||||
if search:
|
||||
base_query = _apply_search_filter(base_query, search)
|
||||
|
||||
total_query = base_query.with_only_columns(func.count()).order_by(None)
|
||||
total = await db.scalar(total_query) or 0
|
||||
|
||||
result = await db.execute(
|
||||
base_query.order_by(User.created_at.desc()).offset(offset).limit(limit)
|
||||
)
|
||||
referrers = result.scalars().unique().all()
|
||||
|
||||
items: list[PartnerReferrerItem] = []
|
||||
for referrer in referrers:
|
||||
stats = await get_user_referral_stats(db, referrer.id)
|
||||
items.append(_serialize_referrer(referrer, stats))
|
||||
|
||||
return PartnerReferrerListResponse(
|
||||
items=items,
|
||||
total=int(total),
|
||||
limit=limit,
|
||||
offset=offset,
|
||||
)
|
||||
|
||||
|
||||
@router.get("/referrers/{user_id}", response_model=PartnerReferrerDetail)
|
||||
async def get_referrer_detail(
|
||||
user_id: int,
|
||||
_: Any = Security(require_api_token),
|
||||
db: AsyncSession = Depends(get_db_session),
|
||||
limit: int = Query(50, ge=1, le=200),
|
||||
offset: int = Query(0, ge=0),
|
||||
) -> PartnerReferrerDetail:
|
||||
user = await get_user_by_telegram_id(db, user_id)
|
||||
if not user:
|
||||
user = await get_user_by_id(db, user_id)
|
||||
|
||||
if not user:
|
||||
raise HTTPException(status.HTTP_404_NOT_FOUND, "User not found")
|
||||
|
||||
stats = await get_user_referral_stats(db, user.id)
|
||||
referrer_item = _serialize_referrer(user, stats)
|
||||
|
||||
referrals_data = await get_detailed_referral_list(db, user.id, limit=limit, offset=offset)
|
||||
referral_items = [
|
||||
_serialize_referral_item(referral) for referral in referrals_data.get("referrals", [])
|
||||
]
|
||||
|
||||
referrals_list = PartnerReferralList(
|
||||
items=referral_items,
|
||||
total=int(referrals_data.get("total_count") or 0),
|
||||
limit=limit,
|
||||
offset=offset,
|
||||
has_next=bool(referrals_data.get("has_next")),
|
||||
has_prev=bool(referrals_data.get("has_prev")),
|
||||
current_page=int(referrals_data.get("current_page") or 1),
|
||||
total_pages=int(referrals_data.get("total_pages") or 1),
|
||||
)
|
||||
|
||||
return PartnerReferrerDetail(referrer=referrer_item, referrals=referrals_list)
|
||||
|
||||
|
||||
@router.put(
|
||||
"/referrers/{user_id}/commission",
|
||||
response_model=PartnerReferrerItem,
|
||||
)
|
||||
async def update_referrer_commission(
|
||||
user_id: int,
|
||||
payload: PartnerReferrerCommissionUpdateRequest,
|
||||
_: Any = Security(require_api_token),
|
||||
db: AsyncSession = Depends(get_db_session),
|
||||
) -> PartnerReferrerItem:
|
||||
user = await get_user_by_telegram_id(db, user_id)
|
||||
if not user:
|
||||
user = await get_user_by_id(db, user_id)
|
||||
|
||||
if not user:
|
||||
raise HTTPException(status.HTTP_404_NOT_FOUND, "User not found")
|
||||
|
||||
user.referral_commission_percent = payload.percent
|
||||
user.updated_at = datetime.utcnow()
|
||||
|
||||
await db.commit()
|
||||
await db.refresh(user)
|
||||
|
||||
stats = await get_user_referral_stats(db, user.id)
|
||||
return _serialize_referrer(user, stats)
|
||||
@@ -1,78 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class PartnerReferrerItem(BaseModel):
|
||||
id: int
|
||||
telegram_id: int
|
||||
username: Optional[str] = None
|
||||
first_name: Optional[str] = None
|
||||
last_name: Optional[str] = None
|
||||
referral_code: Optional[str] = None
|
||||
referral_commission_percent: Optional[int] = None
|
||||
effective_referral_commission_percent: int
|
||||
invited_count: int
|
||||
active_referrals: int
|
||||
total_earned_kopeks: int
|
||||
total_earned_rubles: float
|
||||
month_earned_kopeks: int
|
||||
month_earned_rubles: float
|
||||
created_at: datetime
|
||||
last_activity: Optional[datetime] = None
|
||||
|
||||
|
||||
class PartnerReferrerListResponse(BaseModel):
|
||||
items: List[PartnerReferrerItem] = Field(default_factory=list)
|
||||
total: int
|
||||
limit: int
|
||||
offset: int
|
||||
|
||||
|
||||
class PartnerReferralItem(BaseModel):
|
||||
id: int
|
||||
telegram_id: int
|
||||
full_name: str
|
||||
username: Optional[str] = None
|
||||
created_at: datetime
|
||||
last_activity: Optional[datetime] = None
|
||||
has_made_first_topup: bool
|
||||
balance_kopeks: int
|
||||
balance_rubles: float
|
||||
total_earned_kopeks: int
|
||||
total_earned_rubles: float
|
||||
topups_count: int
|
||||
days_since_registration: int
|
||||
days_since_activity: Optional[int] = None
|
||||
status: str
|
||||
|
||||
|
||||
class PartnerReferralList(BaseModel):
|
||||
items: List[PartnerReferralItem] = Field(default_factory=list)
|
||||
total: int
|
||||
limit: int
|
||||
offset: int
|
||||
has_next: bool
|
||||
has_prev: bool
|
||||
current_page: int
|
||||
total_pages: int
|
||||
|
||||
|
||||
class PartnerReferrerDetail(BaseModel):
|
||||
referrer: PartnerReferrerItem
|
||||
referrals: PartnerReferralList
|
||||
|
||||
|
||||
class PartnerReferrerCommissionUpdateRequest(BaseModel):
|
||||
percent: Optional[int] = Field(
|
||||
default=None,
|
||||
ge=0,
|
||||
le=100,
|
||||
description=(
|
||||
"Индивидуальный процент комиссии реферала. Значение None сбрасывает на "
|
||||
"стандартный процент из настроек."
|
||||
),
|
||||
)
|
||||
Reference in New Issue
Block a user