Add referral system and user balance tracking

Introduce balance field to User model with Alembic migration. Add
referral menu, admin /refpay command, and deep link sharing. Update
Dockerfile to multi-stage build and add Postgres service to compose.
Fix deep link parsing logic and conditional proxy initialization.
This commit is contained in:
2026-04-10 22:20:53 +07:00
parent 60de871e0c
commit 0ed0ad2b92
17 changed files with 337 additions and 80 deletions

View File

@@ -49,7 +49,7 @@ class UserService:
@staticmethod
async def format_admin_support_message(
ticket_number: int, user: User, rw_user: Optional[RWUserInfo]
ticket_number: int, user: User, rw_user: Optional[RWUserInfo], balance: int
):
username_display = utils.format_username(user.username)
@@ -76,6 +76,7 @@ class UserService:
full_name=user.full_name,
username_display=username_display,
telegram_id=user.id,
balance=balance,
status_icon=status_icon,
status=status_text,
expire_date=expire_date,
@@ -98,8 +99,10 @@ class UserService:
return user
rw_user = await get_user_by_telegram_id(rw_sdk, user_id)
link = utils.get_subscription_link(rw_user.short_uuid)
referal = int(referal) if str(referal).isdigit() else None
link = utils.get_subscription_link(rw_user.short_uuid) if rw_user else None
referal = (
int(referal) if str(referal).isdigit() and user_id != int(referal) else None
)
model = NewUserDTO(id=user_id, referal=referal, link=link)
return await self.user_repository.create_user(session, model)
@@ -114,6 +117,7 @@ class UserService:
ticket = await self.ticket_repository.get_available_ticket_by_user_id(
session, user.id
)
db_user = await self.user_repository.get_user_by_id(session, user.id)
if ticket:
try:
@@ -121,7 +125,11 @@ class UserService:
chat_id=settings.admin_group_id,
message_thread_id=ticket.thread_id,
text=utils.format_support_subscription(
subscription, user.full_name, user.id, user.username
subscription=subscription,
full_name=user.full_name,
user_id=user.id,
username=user.username,
balance=db_user.balance,
),
)
return
@@ -148,12 +156,17 @@ class UserService:
ticket = await self.ticket_repository.update_ticket_thread_id(
session, ticket, thread.message_thread_id
)
db_user = await self.user_repository.get_user_by_id(session, ticket.creator_id)
await bot.send_message(
chat_id=settings.admin_group_id,
message_thread_id=ticket.thread_id,
text=utils.format_support_subscription(
subscription, user.full_name, user.id, user.username
subscription=subscription,
full_name=user.full_name,
user_id=user.id,
username=user.username,
balance=db_user,
),
)
@@ -204,7 +217,10 @@ class UserService:
settings.admin_group_id,
message_thread_id=thread.message_thread_id,
text=await self.format_admin_support_message(
ticket_number=ticket.id, user=msg.from_user, rw_user=rw_user
ticket_number=ticket.id,
user=msg.from_user,
rw_user=rw_user,
balance=user.balance,
),
)
await msg.copy_to(
@@ -269,3 +285,23 @@ class UserService:
user = await self.user_repository.update_user_link(session, user_id, link)
return user
async def fetch_user_by_thread(
self, session: AsyncSession, thread_id: int
) -> Optional[User]:
ticket = await self.ticket_repository.get_ticket_by_thread_id(
session, thread_id=thread_id
)
return await self.user_repository.get_user_by_id(session, ticket.creator_id)
async def fetch_referal_by_thread(
self, session: AsyncSession, thread_id: int
) -> Optional[User]:
ticket = await self.ticket_repository.get_ticket_by_thread_id(
session, thread_id=thread_id
)
return await self.user_repository.get_referal_by_user_id(
session, ticket.creator_id
)