Files
malenia/services/user_service.py
hexdev d98383285e feat: implement billing system with Pally integration
- Added billing models and repository for handling bills.
- Introduced BillingService to manage payment initiation and bill creation.
- Updated user service to remove ticket-related functionality.
- Refactored settings to include new billing-related fields.
- Removed ticket-related handlers and schemas.
- Added new billing handlers for processing payments.
- Updated database schema with new bills table and status enum.
- Enhanced utility functions to calculate prices considering discounts.
- Introduced prehandling for non-private messages.
- Updated main application to initialize new billing services and repositories.
2026-04-23 19:55:51 +07:00

100 lines
3.1 KiB
Python

import logging
from aiogram.types import Message
from remnawave import RemnawaveSDK
from sqlalchemy.ext.asyncio import AsyncSession
from db.models.users import User
from misc import utils
from repositories import UserRepository
from schemas.users import NewUserDTO
from services.rw import RWUserInfo, get_user_by_telegram_id
from texts import (
NO_SUBSCRIPTION,
NOTHING_PLACEHOLDER,
SUBSCRIPTION_INFORMATION,
)
logger = logging.getLogger(__name__)
class UserServiceError(Exception): ...
class UserService:
def __init__(self, user_repository: UserRepository) -> None:
self.user_repository = user_repository
@staticmethod
def format_subscription_message(
rw_user: RWUserInfo | None,
link: str | None = None,
):
if rw_user is None:
# Пользователь не найден в Remnawave
return NO_SUBSCRIPTION
status_icon, status_text = utils.format_status(rw_user.status)
expire_date = rw_user.expire_at.strftime("%d.%m.%Y")
days_left = utils.format_days_left(rw_user.expire_at)
used_traffic = utils.format_traffic(rw_user.used_traffic_bytes, rw_user.traffic_limit_bytes)
hwid_limit = utils.format_hwid_limit(rw_user.hwid_device_limit)
link = link or NOTHING_PLACEHOLDER
return SUBSCRIPTION_INFORMATION.format(
status_icon=status_icon,
status=status_text,
expire_date=expire_date,
days_left=days_left,
used_traffic=used_traffic,
hwid_limit=hwid_limit,
link=link,
)
async def add_user(
self,
session: AsyncSession,
user_id: int,
rw_sdk: RemnawaveSDK,
referal: int | None = None,
) -> User:
user = await self.user_repository.get_user_by_id(session, user_id)
if user:
return user
rw_user = await get_user_by_telegram_id(rw_sdk, user_id)
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)
async def update_user_link(
self, session: AsyncSession, user_id: int, rw_sdk: RemnawaveSDK
) -> User | None:
rw_user = await get_user_by_telegram_id(rw_sdk, user_id)
user = await self.user_repository.get_user_by_id(session, user_id)
if not rw_user:
return user
link = utils.get_subscription_link(rw_user.short_uuid)
user = await self.user_repository.update_user_link(session, user_id, link)
return user
async def send_promotion_to_users(self, session: AsyncSession, msg: Message) -> list[User]:
users = await self.user_repository.get_users(session)
sent: list[User] = []
for user in users:
try:
await msg.copy_to(user.id)
sent.append(user)
except Exception:
logger.critical("failed to send a message to user %d.", user.id, exc_info=True)
return sent