fix(market): per-event bet loss+win
This commit is contained in:
@@ -6,12 +6,19 @@ from django.db.models import Sum, Prefetch
|
||||
from django.db.models.functions import Coalesce
|
||||
from django.db import transaction
|
||||
|
||||
from market.models import Market, MarketOption, UserBet, UserPointChange
|
||||
from market.models import (
|
||||
Market,
|
||||
MarketOption,
|
||||
UserBet,
|
||||
UserPointChange,
|
||||
get_event_points,
|
||||
)
|
||||
from market.schemas import (
|
||||
MarketListSchema,
|
||||
ResolveMarketSchema,
|
||||
UserBetCreateSchema,
|
||||
UserBetSchema,
|
||||
UserPointsSchema,
|
||||
)
|
||||
|
||||
|
||||
@@ -45,6 +52,15 @@ def list_user_bets(request, event_path: str):
|
||||
)
|
||||
|
||||
|
||||
@router.get(f"{PREFIX}/user/points", response=UserPointsSchema)
|
||||
def get_user_points(request, event_path: str):
|
||||
"""Get the current user's points balance for this event."""
|
||||
if not request.user.is_authenticated:
|
||||
raise HttpError(401, "Authentication required")
|
||||
|
||||
return {"points": get_event_points(request.user, request.event)}
|
||||
|
||||
|
||||
@router.post(f"{PREFIX}/{{market_uuid}}/actions/close")
|
||||
def close_market(request, event_path: str, market_uuid: str):
|
||||
"""Close a market. Admin only."""
|
||||
@@ -76,9 +92,7 @@ def resolve_market(
|
||||
market.save(update_fields=["winning_option", "status", "updated_at"])
|
||||
|
||||
# Calculate and distribute winnings
|
||||
all_bets = list(
|
||||
UserBet.objects.filter(option__market=market).select_related("user")
|
||||
)
|
||||
all_bets = list(UserBet.objects.filter(option__market=market))
|
||||
|
||||
# Calculate total pot
|
||||
total_pot = sum(bet.amount for bet in all_bets)
|
||||
@@ -92,7 +106,6 @@ def resolve_market(
|
||||
total_winning = sum(bet.amount for bet in winning_bets)
|
||||
|
||||
point_changes = []
|
||||
users_to_update = []
|
||||
|
||||
with transaction.atomic():
|
||||
# Award payouts to winners with multiplier
|
||||
@@ -101,11 +114,9 @@ def resolve_market(
|
||||
payout = round(
|
||||
bet.amount / total_winning * total_pot * market.multiplier
|
||||
)
|
||||
bet.user.points += payout
|
||||
users_to_update.append(bet.user)
|
||||
point_changes.append(
|
||||
UserPointChange(
|
||||
user=bet.user,
|
||||
user_id=bet.user_id,
|
||||
market=market,
|
||||
amount=payout,
|
||||
reason=UserPointChange.Reason.BET_WON,
|
||||
@@ -116,17 +127,13 @@ def resolve_market(
|
||||
for bet in losing_bets:
|
||||
point_changes.append(
|
||||
UserPointChange(
|
||||
user=bet.user,
|
||||
user_id=bet.user_id,
|
||||
market=market,
|
||||
amount=-bet.amount,
|
||||
reason=UserPointChange.Reason.BET_LOST,
|
||||
)
|
||||
)
|
||||
|
||||
# Bulk update users
|
||||
for user in users_to_update:
|
||||
user.save(update_fields=["points"])
|
||||
|
||||
# Bulk create point changes
|
||||
UserPointChange.objects.bulk_create(point_changes)
|
||||
|
||||
@@ -167,8 +174,8 @@ def create_bet(
|
||||
# Calculate delta (amount to deduct from user's points)
|
||||
delta = payload.amount - (existing_bet.amount if existing_bet else 0)
|
||||
|
||||
# Check if user has enough points
|
||||
if request.user.points < delta:
|
||||
# Check if user has enough points for this event
|
||||
if get_event_points(request.user, request.event) < delta:
|
||||
raise HttpError(400, "Insufficient points for this bet")
|
||||
|
||||
user_bet, created = UserBet.objects.update_or_create(
|
||||
@@ -177,9 +184,7 @@ def create_bet(
|
||||
defaults={"amount": payload.amount},
|
||||
)
|
||||
|
||||
# Deduct points and record the change
|
||||
request.user.points -= delta
|
||||
request.user.save(update_fields=["points"])
|
||||
# Record the change (the event balance is derived from these)
|
||||
UserPointChange.objects.create(
|
||||
user=request.user,
|
||||
market=market,
|
||||
|
||||
Reference in New Issue
Block a user