51 lines
2.2 KiB
Python
51 lines
2.2 KiB
Python
from decimal import Decimal
|
|
from rest_framework.response import Response
|
|
from rest_framework.status import HTTP_200_OK
|
|
from rest_framework.decorators import api_view
|
|
from rest_framework.exceptions import ParseError
|
|
from django.shortcuts import get_object_or_404
|
|
from django.db import transaction
|
|
from django.db.models import F
|
|
from django.utils import timezone
|
|
from django_cte import With
|
|
from auction.models import Auction, Bet
|
|
|
|
|
|
@api_view(['POST'])
|
|
def place_bet(request, pk):
|
|
auction = get_object_or_404(Auction, pk=pk)
|
|
if not auction.is_active:
|
|
raise ParseError('Аукцион уже закончился')
|
|
bet_value = Decimal(request.query_params.get('value', 0))
|
|
if bet_value <= 0:
|
|
raise ParseError('Ставка должна быть положительная')
|
|
if bet_value < auction.min_bet_value:
|
|
raise ParseError('Ставка слишком маленькая')
|
|
tg_user = request.user.tg_user
|
|
auction_has_to_be_postponed = timezone.now() <= auction.end_time <= timezone.now() + auction.last_call_delta
|
|
with transaction.atomic():
|
|
cte = With(auction.bets.filter(_is_winning=True).distinct('user').order_by('user_id'))
|
|
winning_bets = cte.join(Bet, id=cte.col.id).with_cte(cte).order_by('-_value')
|
|
commission_value = bet_value * auction.commission
|
|
|
|
if winning_bets.filter(user_id=tg_user.pk).exists():
|
|
user_bet = winning_bets.get(user_id=tg_user.pk)
|
|
delta = bet_value - user_bet.value
|
|
user_bet.transaction.refund()
|
|
commission_value = delta * auction.commission
|
|
elif winning_bets.count() >= auction.quantity:
|
|
for bet in winning_bets[auction.quantity - 1:]:
|
|
bet.transaction.refund()
|
|
|
|
Bet.objects.create_with_transaction_and_commission(
|
|
auction=auction,
|
|
user=tg_user,
|
|
value=bet_value,
|
|
commission_value=commission_value
|
|
)
|
|
if auction_has_to_be_postponed:
|
|
auction.times_postponed = F('times_postponed') + 1
|
|
auction.save(update_fields=('times_postponed',))
|
|
tg_user.refresh_from_db()
|
|
return Response(status=HTTP_200_OK, data={'remaining_points': tg_user.points})
|