def create_auction(self, item_id: int, bidding_strategy_identifier: str, **kwargs): uhi = UserHasItem.objects.get(user_id=self.id, item_id=item_id, is_sold=False) runtime_manager.create_auction( uhi=uhi, bidding_strategy_identifier=bidding_strategy_identifier, **kwargs) return uhi.id
def post(self, request, *args, **kwargs): pk = kwargs['pk'] item = get_object_or_404(Item, pk=pk) uhi = get_object_or_404(UserHasItem, item=item, user=request.user, is_sold=False) bidding_strategy = request.POST.get('bidding_strategy') form_class = self.FORMS.get(bidding_strategy, CreateIncrementAuctionForm) form = form_class(request.POST) if form.is_valid(): try: auction = runtime_manager.create_auction( uhi=uhi, bidding_strategy_identifier=bidding_strategy, **form.cleaned_data, ) except ItemAlreadyOnSale as e: messages.add_message(request, messages.ERROR, str(e)) else: messages.add_message( request, messages.SUCCESS, 'Created the auction! If the below details look correct to you, hit start and let the games begin!', ) return redirect( reverse('auction-details', kwargs={'pk': auction.id})) return render( request, 'core/create_auction_confirm.html', { 'form': form, 'bidding_strategy': bidding_strategy, 'item': item }, )
def test_highest_contribution_bidding_maximum_price(self): john = RuntimeUser( username="******", email="*****@*****.**", password_raw="11441144", first_name="John", last_name="Sims", ) jimmy = RuntimeUser( username="******", email="*****@*****.**", password_raw="12345678", first_name="James", last_name="Hetfield", ) jack = RuntimeUser( username="******", email="*****@*****.**", password_raw="i_secretly_like_johnny_walker", first_name="Jack", last_name="Daniels", ) john.persist() jimmy.persist() jack.persist() john.connect() jimmy.connect() jack.connect() john.add_balance_transaction(Decimal(150.00)) jimmy.add_balance_transaction(Decimal(140.00)) jack.add_balance_transaction(Decimal(130.00)) scarf = Item.objects.create(title="Scarf", description="A really cool scarf", item_type="Clothing") jimmy_has_scarf = UserHasItem.objects.create( item=scarf, user=jimmy.persistent_user) auction = runtime_manager.create_auction( uhi=jimmy_has_scarf, bidding_strategy_identifier="highest_contribution", minimum_bid_amount=Decimal(2.00), maximum_price=Decimal(100), ) auction.start() auction.bid(jack, Decimal(30.00)) auction.bid(john, Decimal(50.00)) auction.bid(jack, Decimal(30.00)) print(auction.auction_report) print(auction.auction_history) john.persistent_user.refresh_from_db() jimmy.persistent_user.refresh_from_db() jack.persistent_user.refresh_from_db() jimmy_has_scarf.refresh_from_db() john.disconnect() jimmy.disconnect() jack.disconnect() self.assertTrue(jimmy_has_scarf.is_sold) self.assertEqual(john.initial_balance, Decimal(100)) self.assertEqual(jimmy.initial_balance, Decimal(250)) self.assertEqual(jack.initial_balance, Decimal(70)) self.assertEqual(john.persistent_user.balance, Decimal(100)) self.assertEqual(jimmy.persistent_user.balance, Decimal(250)) self.assertEqual(jack.persistent_user.balance, Decimal(70))
def test_decrement_bidding_with_no_winners(self): pass john = RuntimeUser( username="******", email="*****@*****.**", password_raw="11441144", first_name="John", last_name="Sims", ) jimmy = RuntimeUser( username="******", email="*****@*****.**", password_raw="12345678", first_name="James", last_name="Hetfield", ) john.persist() jimmy.persist() john.connect() jimmy.connect() john.add_balance_transaction(Decimal(100.00)) jimmy.add_balance_transaction(Decimal(40.00)) scarf = Item.objects.create(title="Scarf", description="A really cool scarf", item_type="Clothing") jimmy_has_scarf = UserHasItem.objects.create( item=scarf, user=jimmy.persistent_user) auction = runtime_manager.create_auction( uhi=jimmy_has_scarf, bidding_strategy_identifier="decrement", initial_price=Decimal(150.00), price_decrement_rate=Decimal(50.00), tick_ms=20, ) auction.start() self.assertEqual(auction.bidding_strategy.get_current_price(), Decimal(150.00)) sleep(25 / 1000) self.assertEqual(auction.bidding_strategy.get_current_price(), Decimal(100.00)) sleep(25 / 1000) self.assertEqual(auction.bidding_strategy.get_current_price(), Decimal(50.00)) sleep(25 / 1000) self.assertEqual(auction.bidding_strategy.get_current_price(), Decimal(0.00)) sleep(250 / 1000) print(auction.auction_report) print(auction.auction_history) john.persistent_user.refresh_from_db() jimmy.persistent_user.refresh_from_db() jimmy_has_scarf.refresh_from_db() john.disconnect() jimmy.disconnect() self.assertFalse(jimmy_has_scarf.is_sold) self.assertEqual(john.initial_balance, Decimal(100)) self.assertEqual(jimmy.initial_balance, Decimal(40)) self.assertEqual(john.persistent_user.balance, Decimal(100)) self.assertEqual(jimmy.persistent_user.balance, Decimal(40))
def test_decrement_bidding_and_auction_watching(self): john = RuntimeUser( username="******", email="*****@*****.**", password_raw="11441144", first_name="John", last_name="Sims", ) jimmy = RuntimeUser( username="******", email="*****@*****.**", password_raw="12345678", first_name="James", last_name="Hetfield", ) jimmy.watch_method = lambda *args, **kwargs: None patcher = patch.object(jimmy, "watch_method") m_jimmy_watch_method = patcher.start() john.persist() jimmy.persist() john.connect() jimmy.connect() john.add_balance_transaction(Decimal(100.00)) jimmy.add_balance_transaction(Decimal(40.00)) scarf = Item.objects.create(title="Scarf", description="A really cool scarf", item_type="Clothing") jimmy_has_scarf = UserHasItem.objects.create( item=scarf, user=jimmy.persistent_user) auction = runtime_manager.create_auction( uhi=jimmy_has_scarf, bidding_strategy_identifier="decrement", initial_price=Decimal(150.00), price_decrement_rate=Decimal(25.00), tick_ms=200, ) auction.register_user_to_updates(jimmy.watch_method) # this is mocked auction.start() self.assertEqual(auction.bidding_strategy.get_current_price(), Decimal(150.00)) with self.assertRaises(InsufficientBalanceError): auction.bid( john ) # no amount means that user is bidding to the current price sleep(250 / 1000) self.assertEqual(auction.bidding_strategy.get_current_price(), Decimal(125.00)) sleep(250 / 1000) self.assertEqual(auction.bidding_strategy.get_current_price(), Decimal(100.00)) auction.bid(john) # this terminates the auction m_jimmy_watch_method.assert_has_calls([ call(event_type="auction_started"), call(event_type="price_decremented", new_price=Decimal(125.00)), call(event_type="price_decremented", new_price=Decimal(100.00)), call(event_type="bid_received"), # TODO Fix this some day call(event_type="price_decremented", new_price=Decimal(75.00)), call(event_type="auction_stopped"), ]) print(auction.auction_report) print(auction.auction_history) john.persistent_user.refresh_from_db() jimmy.persistent_user.refresh_from_db() jimmy_has_scarf.refresh_from_db() john.disconnect() jimmy.disconnect() self.assertTrue(jimmy_has_scarf.is_sold) self.assertEqual(john.initial_balance, Decimal(0)) self.assertEqual(jimmy.initial_balance, Decimal(140)) self.assertEqual(john.persistent_user.balance, Decimal(0)) self.assertEqual(jimmy.persistent_user.balance, Decimal(140)) patcher.stop()
def test_increment_bidding_exceptions(self): john = RuntimeUser( username="******", email="*****@*****.**", password_raw="11441144", first_name="John", last_name="Sims", ) jimmy = RuntimeUser( username="******", email="*****@*****.**", password_raw="12345678", first_name="James", last_name="Hetfield", ) jack = RuntimeUser( username="******", email="*****@*****.**", password_raw="i_secretly_like_johnny_walker", first_name="Jack", last_name="Daniels", ) john.persist() jimmy.persist() jack.persist() john.connect() jimmy.connect() jack.connect() john.add_balance_transaction(Decimal(50.00)) jimmy.add_balance_transaction(Decimal(40.00)) jack.add_balance_transaction(Decimal(30.00)) scarf = Item.objects.create(title="Scarf", description="A really cool scarf", item_type="Clothing") jimmy_has_scarf = UserHasItem.objects.create( item=scarf, user=jimmy.persistent_user) auction = runtime_manager.create_auction( uhi=jimmy_has_scarf, bidding_strategy_identifier="increment", initial_price=Decimal(5.00), minimum_increment=Decimal(2.00), maximum_price=Decimal(15.00), ) # Cannot bid while auction is closed with self.assertRaises(BiddingNotAllowed) as cm: auction.bid(john, Decimal(123.00)) self.assertEqual(cm.exception.reason, BiddingErrorReason.AuctionClosed) auction.start() # Cannot bid in own auction with self.assertRaises(BiddingNotAllowed) as cm: auction.bid(jimmy, Decimal(1.00)) self.assertEqual(cm.exception.reason, BiddingErrorReason.OwnAuction) # Lower than initial price with self.assertRaises(BiddingNotAllowed) as cm: auction.bid(john, Decimal(1.00)) self.assertEqual(cm.exception.reason, BiddingErrorReason.InsufficientAmount) # Lower than minimum increment with self.assertRaises(BiddingNotAllowed) as cm: auction.bid(john, Decimal(6.00)) self.assertEqual(cm.exception.reason, BiddingErrorReason.InsufficientAmount) # Higher than reservable balance with self.assertRaises(InsufficientBalanceError): auction.bid(john, Decimal(666.00)) # Happy path auction.bid(john, Decimal(7.00)) self.assertEqual(john.reservable_balance, Decimal(43.00)) auction.bid(john, Decimal(50.00)) # This closes the auction. self.assertEqual(john.reservable_balance, Decimal(0.00)) print(auction.auction_report) print(auction.auction_history) # Cannot bid while auction is closed with self.assertRaises(BiddingNotAllowed) as cm: auction.bid(john, Decimal(123.00)) self.assertEqual(cm.exception.reason, BiddingErrorReason.AuctionClosed) john.persistent_user.refresh_from_db() jimmy.persistent_user.refresh_from_db() jack.persistent_user.refresh_from_db() jimmy_has_scarf.refresh_from_db() john.disconnect() jimmy.disconnect() jack.disconnect() self.assertTrue(jimmy_has_scarf.is_sold) self.assertEqual(john.initial_balance, Decimal(0)) self.assertEqual(jimmy.initial_balance, Decimal(90)) self.assertEqual(jack.initial_balance, Decimal(30)) self.assertEqual(john.persistent_user.balance, Decimal(0)) self.assertEqual(jimmy.persistent_user.balance, Decimal(90)) self.assertEqual(jack.persistent_user.balance, Decimal(30))