Allow referral commissions on any top-up amount

This commit is contained in:
Egor
2025-11-01 01:19:31 +03:00
parent d259bcf169
commit 54fc1c029c
2 changed files with 146 additions and 34 deletions

View File

@@ -89,16 +89,64 @@ async def process_referral_topup(
logger.info(f"Пользователь {user_id} не является рефералом")
return True
if topup_amount_kopeks < settings.REFERRAL_MINIMUM_TOPUP_KOPEKS:
logger.info(f"Пополнение {user_id} на {topup_amount_kopeks/100}₽ меньше минимума")
return True
referrer = await get_user_by_id(db, user.referred_by_id)
if not referrer:
logger.error(f"Реферер {user.referred_by_id} не найден")
return False
qualifies_for_first_bonus = (
topup_amount_kopeks >= settings.REFERRAL_MINIMUM_TOPUP_KOPEKS
)
commission_amount = 0
if settings.REFERRAL_COMMISSION_PERCENT > 0:
commission_amount = int(
topup_amount_kopeks * settings.REFERRAL_COMMISSION_PERCENT / 100
)
if not user.has_made_first_topup:
if not qualifies_for_first_bonus:
logger.info(
"Пополнение %s на %s₽ меньше минимума для первого бонуса, но комиссия будет начислена",
user_id,
topup_amount_kopeks / 100,
)
if commission_amount > 0:
await add_user_balance(
db,
referrer,
commission_amount,
f"Комиссия {settings.REFERRAL_COMMISSION_PERCENT}% с пополнения {user.full_name}",
bot=bot,
)
await create_referral_earning(
db=db,
user_id=referrer.id,
referral_id=user.id,
amount_kopeks=commission_amount,
reason="referral_commission_topup",
)
logger.info(
"💰 Комиссия с пополнения: %s получил %s₽ (до первого бонуса)",
referrer.telegram_id,
commission_amount / 100,
)
if bot:
commission_notification = (
f"💰 <b>Реферальная комиссия!</b>\n\n"
f"Ваш реферал <b>{user.full_name}</b> пополнил баланс на "
f"{settings.format_price(topup_amount_kopeks)}\n\n"
f"🎁 Ваша комиссия ({settings.REFERRAL_COMMISSION_PERCENT}%): "
f"{settings.format_price(commission_amount)}\n\n"
f"💎 Средства зачислены на ваш баланс."
)
await send_referral_notification(bot, referrer.telegram_id, commission_notification)
return True
user.has_made_first_topup = True
await db.commit()
@@ -161,36 +209,33 @@ async def process_referral_topup(
await send_referral_notification(bot, referrer.telegram_id, inviter_bonus_notification)
else:
if settings.REFERRAL_COMMISSION_PERCENT > 0:
commission_amount = int(topup_amount_kopeks * settings.REFERRAL_COMMISSION_PERCENT / 100)
if commission_amount > 0:
await add_user_balance(
db, referrer, commission_amount,
f"Комиссия {settings.REFERRAL_COMMISSION_PERCENT}% с пополнения {user.full_name}",
bot=bot
if commission_amount > 0:
await add_user_balance(
db, referrer, commission_amount,
f"Комиссия {settings.REFERRAL_COMMISSION_PERCENT}% с пополнения {user.full_name}",
bot=bot
)
await create_referral_earning(
db=db,
user_id=referrer.id,
referral_id=user.id,
amount_kopeks=commission_amount,
reason="referral_commission_topup"
)
logger.info(f"💰 Комиссия с пополнения: {referrer.telegram_id} получил {commission_amount/100}")
if bot:
commission_notification = (
f"💰 <b>Реферальная комиссия!</b>\n\n"
f"Ваш реферал <b>{user.full_name}</b> пополнил баланс на "
f"{settings.format_price(topup_amount_kopeks)}\n\n"
f"🎁 Ваша комиссия ({settings.REFERRAL_COMMISSION_PERCENT}%): "
f"{settings.format_price(commission_amount)}\n\n"
f"💎 Средства зачислены на ваш баланс."
)
await create_referral_earning(
db=db,
user_id=referrer.id,
referral_id=user.id,
amount_kopeks=commission_amount,
reason="referral_commission_topup"
)
logger.info(f"💰 Комиссия с пополнения: {referrer.telegram_id} получил {commission_amount/100}")
if bot:
commission_notification = (
f"💰 <b>Реферальная комиссия!</b>\n\n"
f"Ваш реферал <b>{user.full_name}</b> пополнил баланс на "
f"{settings.format_price(topup_amount_kopeks)}\n\n"
f"🎁 Ваша комиссия ({settings.REFERRAL_COMMISSION_PERCENT}%): "
f"{settings.format_price(commission_amount)}\n\n"
f"💎 Средства зачислены на ваш баланс."
)
await send_referral_notification(bot, referrer.telegram_id, commission_notification)
await send_referral_notification(bot, referrer.telegram_id, commission_notification)
return True

View File

@@ -0,0 +1,67 @@
from pathlib import Path
import sys
from types import SimpleNamespace
from unittest.mock import AsyncMock
import pytest
ROOT_DIR = Path(__file__).resolve().parents[2]
if str(ROOT_DIR) not in sys.path:
sys.path.insert(0, str(ROOT_DIR))
from app.services import referral_service # noqa: E402
@pytest.mark.asyncio
async def test_commission_accrues_before_minimum_first_topup(monkeypatch):
user = SimpleNamespace(
id=1,
telegram_id=101,
full_name="Test User",
referred_by_id=2,
has_made_first_topup=False,
)
referrer = SimpleNamespace(
id=2,
telegram_id=202,
full_name="Referrer",
)
db = SimpleNamespace(
commit=AsyncMock(),
execute=AsyncMock(),
)
get_user_mock = AsyncMock(side_effect=[user, referrer])
monkeypatch.setattr(referral_service, "get_user_by_id", get_user_mock)
add_user_balance_mock = AsyncMock()
monkeypatch.setattr(referral_service, "add_user_balance", add_user_balance_mock)
create_referral_earning_mock = AsyncMock()
monkeypatch.setattr(referral_service, "create_referral_earning", create_referral_earning_mock)
monkeypatch.setattr(referral_service.settings, "REFERRAL_MINIMUM_TOPUP_KOPEKS", 20000)
monkeypatch.setattr(referral_service.settings, "REFERRAL_FIRST_TOPUP_BONUS_KOPEKS", 5000)
monkeypatch.setattr(referral_service.settings, "REFERRAL_INVITER_BONUS_KOPEKS", 10000)
monkeypatch.setattr(referral_service.settings, "REFERRAL_COMMISSION_PERCENT", 25)
topup_amount = 15000
result = await referral_service.process_referral_topup(db, user.id, topup_amount)
assert result is True
assert user.has_made_first_topup is False
add_user_balance_mock.assert_awaited_once()
add_call = add_user_balance_mock.await_args
assert add_call.args[1] is referrer
assert add_call.args[2] == 3750
assert "Комиссия" in add_call.args[3]
assert add_call.kwargs.get("bot") is None
create_referral_earning_mock.assert_awaited_once()
earning_call = create_referral_earning_mock.await_args
assert earning_call.kwargs["amount_kopeks"] == 3750
assert earning_call.kwargs["reason"] == "referral_commission_topup"
db.commit.assert_not_awaited()
db.execute.assert_not_awaited()