fix: изолировать stored_amount от downstream consumers в create_transaction

- stored_amount используется только для БД записи, оригинальный
  amount_kopeks передаётся в event emitter и contest service через abs()
- Добавлен func.abs() в leaderboard конкурсов (referral_contest.py)
- Предотвращает негативные суммы в событиях и рейтинге конкурсов
This commit is contained in:
Fringg
2026-03-05 09:05:55 +03:00
parent 6da61d7951
commit b87535ad48
2 changed files with 8 additions and 8 deletions
+1 -1
View File
@@ -197,7 +197,7 @@ async def get_contest_leaderboard(
select(
User,
func.count(ReferralContestEvent.id).label('referral_count'),
func.coalesce(func.sum(ReferralContestEvent.amount_kopeks), 0).label('total_amount'),
func.coalesce(func.sum(func.abs(ReferralContestEvent.amount_kopeks)), 0).label('total_amount'),
)
.join(User, User.id == ReferralContestEvent.referrer_id)
.where(
+7 -7
View File
@@ -40,13 +40,13 @@ async def create_transaction(
created_at: datetime | None = None,
) -> Transaction:
# SUBSCRIPTION_PAYMENT — always store as negative (debit from user balance)
if type == TransactionType.SUBSCRIPTION_PAYMENT and amount_kopeks > 0:
amount_kopeks = -amount_kopeks
# Keep original for downstream consumers (events, contests)
stored_amount = -amount_kopeks if type == TransactionType.SUBSCRIPTION_PAYMENT and amount_kopeks > 0 else amount_kopeks
transaction = Transaction(
user_id=user_id,
type=type.value,
amount_kopeks=amount_kopeks,
amount_kopeks=stored_amount,
description=description,
payment_method=payment_method.value if payment_method else None,
external_id=external_id,
@@ -62,7 +62,7 @@ async def create_transaction(
logger.info(
'💳 Создана транзакция: на ₽ для пользователя',
type_value=type.value,
amount_kopeks=amount_kopeks / 100,
amount_kopeks=stored_amount / 100,
user_id=user_id,
)
@@ -76,8 +76,8 @@ async def create_transaction(
'transaction_id': transaction.id,
'user_id': user_id,
'type': type.value,
'amount_kopeks': amount_kopeks,
'amount_rubles': amount_kopeks / 100,
'amount_kopeks': abs(amount_kopeks),
'amount_rubles': abs(amount_kopeks) / 100,
'payment_method': payment_method.value if payment_method else None,
'external_id': external_id,
'is_completed': is_completed,
@@ -103,7 +103,7 @@ async def create_transaction(
await referral_contest_service.on_subscription_payment(
db,
user_id,
amount_kopeks,
abs(amount_kopeks),
)
except Exception as exc:
logger.debug('Не удалось записать событие конкурса для пользователя', user_id=user_id, exc=exc)