def test_draw_prize_multiple_donors_norandom_sum(self): startRun = self.runsList[5] endRun = self.runsList[9] prize = randgen.generate_prize( self.rand, event=self.event, sumDonations=True, randomDraw=False, startRun=startRun, endRun=endRun) prize.save() donationDonors = {} for donor in self.donorList: numDonations = self.rand.getrandbits(4) redHerrings = self.rand.getrandbits(4) donationDonors[donor.id] = { 'donor': donor, 'amount': Decimal('0.00')} for i in range(0, numDonations): donation = randgen.generate_donation(self.rand, donor=donor, event=self.event, minAmount=Decimal( '0.01'), maxAmount=Decimal('100.00'), minTime=prize.start_draw_time(), maxTime=prize.end_draw_time()) donation.save() donationDonors[donor.id]['amount'] += donation.amount # toss in a few extras to keep the drawer on its toes for i in range(0, redHerrings): donation = None if self.rand.getrandbits(1) == 0: donation = randgen.generate_donation(self.rand, donor=donor, event=self.event, minAmount=Decimal( '1000.01'), maxAmount=Decimal('2000.00'), maxTime=prize.start_draw_time() - datetime.timedelta(seconds=1)) else: donation = randgen.generate_donation(self.rand, donor=donor, event=self.event, minAmount=Decimal( '1000.01'), maxAmount=prize.minimumbid - Decimal('2000.00'), minTime=prize.end_draw_time() + datetime.timedelta(seconds=1)) donation.save() maxDonor = max(donationDonors.items(), key=lambda x: x[1]['amount'])[1] eligibleDonors = prize.eligible_donors() self.assertEqual(1, len(eligibleDonors)) self.assertEqual(maxDonor['donor'].id, eligibleDonors[0]['donor']) self.assertEqual(1.0, eligibleDonors[0]['weight']) self.assertEqual(maxDonor['amount'], eligibleDonors[0]['amount']) for seed in [9524, 373, 747]: prize.prizewinner_set.all().delete() prize.save() result, message = viewutil.draw_prize(prize, seed) self.assertTrue(result) self.assertEqual(maxDonor['donor'].id, prize.get_winner().id) oldMaxDonor = maxDonor del donationDonors[oldMaxDonor['donor'].id] maxDonor = max(donationDonors.items(), key=lambda x: x[1]['amount'])[1] diff = oldMaxDonor['amount'] - maxDonor['amount'] newDonor = maxDonor['donor'] newDonation = randgen.generate_donation(self.rand, donor=newDonor, event=self.event, minAmount=diff + Decimal( '0.01'), maxAmount=diff + Decimal('100.00'), minTime=prize.start_draw_time(), maxTime=prize.end_draw_time()) newDonation.save() maxDonor['amount'] += newDonation.amount prize = models.Prize.objects.get(id=prize.id) eligibleDonors = prize.eligible_donors() self.assertEqual(1, len(eligibleDonors)) self.assertEqual(maxDonor['donor'].id, eligibleDonors[0]['donor']) self.assertEqual(1.0, eligibleDonors[0]['weight']) self.assertEqual(maxDonor['amount'], eligibleDonors[0]['amount']) for seed in [9524, 373, 747]: prize.prizewinner_set.all().delete() prize.save() result, message = viewutil.draw_prize(prize, seed) self.assertTrue(result) self.assertEqual(maxDonor['donor'].id, prize.get_winner().id)
def test_decline_prize_single(self): amount = Decimal('50.0') targetPrize = randgen.generate_prize(self.rand,event=self.event,sumDonations=False,randomDraw=False,minAmount=amount,maxAmount=amount,maxwinners=1) targetPrize.save() self.assertEqual(0, len(targetPrize.eligible_donors())) donorA = randgen.generate_donor(self.rand) donorA.save() donorB = randgen.generate_donor(self.rand) donorB.save() donationA = randgen.generate_donation(self.rand,donor=donorA,minAmount=amount,maxAmount=amount,event=self.event) donationA.save() self.assertEqual(1, len(targetPrize.eligible_donors())) self.assertEqual(donorA.id, targetPrize.eligible_donors()[0]['donor']) viewutil.draw_prize(targetPrize) self.assertEqual(donorA, targetPrize.get_winner()) self.assertEqual(0, len(targetPrize.eligible_donors())) donationB = randgen.generate_donation(self.rand,donor=donorB,minAmount=amount,maxAmount=amount,event=self.event) donationB.save() self.assertEqual(1, len(targetPrize.eligible_donors())) self.assertEqual(donorB.id, targetPrize.eligible_donors()[0]['donor']) prizeWinnerEntry = targetPrize.prizewinner_set.filter(winner=donorA)[0] prizeWinnerEntry.acceptstate = 'DECLINED'; prizeWinnerEntry.save() self.assertEqual(1, len(targetPrize.eligible_donors())) self.assertEqual(donorB.id, targetPrize.eligible_donors()[0]['donor']) viewutil.draw_prize(targetPrize) self.assertEqual(donorB, targetPrize.get_winner()) self.assertEqual(1, len(targetPrize.get_winners())) self.assertEqual(0, len(targetPrize.eligible_donors()))
def testWinMultiPrizeLowerThanMaxWin(self): donor = randgen.generate_donor(self.rand) donor.save() prize = randgen.generate_prize(self.rand) prize.event = self.event prize.maxwinners = 3 prize.maxmultiwin = 2 prize.save() models.DonorPrizeEntry.objects.create(donor=donor, prize=prize) prizeWinner = models.PrizeWinner.objects.create( winner=donor, prize=prize, pendingcount=1, declinecount=1) result, msg = viewutil.draw_prize(prize) self.assertFalse(result) donor2 = randgen.generate_donor(self.rand) donor2.save() models.DonorPrizeEntry.objects.create(donor=donor2, prize=prize) result, msg = viewutil.draw_prize(prize) self.assertTrue(result) prizeWinner = models.PrizeWinner.objects.get( winner=donor2, prize=prize) self.assertEquals(1, prizeWinner.pendingcount) result, msg = viewutil.draw_prize(prize) self.assertTrue(result) result, msg = viewutil.draw_prize(prize) self.assertFalse(result)
def test_draw_prize_multiple_donors_random_sum(self): startRun = self.runsList[41] endRun = self.runsList[46] prize = randgen.generate_prize(self.rand, event=self.event, sumDonations=True, randomDraw=True, startRun=startRun, endRun=endRun) prize.save() donationDonors = {} for donor in self.donorList: numDonations = self.rand.getrandbits(4) redHerrings = self.rand.getrandbits(4) donationDonors[donor.id] = { 'donor': donor, 'amount': Decimal('0.00') } for i in range(0, numDonations): donation = randgen.generate_donation(self.rand, donor=donor, event=self.event, minAmount=Decimal('0.01'), maxAmount=prize.minimumbid - Decimal('0.10'), minTime=prize.start_draw_time(), maxTime=prize.end_draw_time()) donation.save() donationDonors[donor.id]['amount'] += donation.amount # toss in a few extras to keep the drawer on its toes for i in range(0, redHerrings): donation = None if self.rand.getrandbits(1) == 0: donation = randgen.generate_donation(self.rand, donor=donor, event=self.event, minAmount=Decimal('0.01'), maxAmount=prize.minimumbid - Decimal('0.10'), maxTime=prize.start_draw_time() - datetime.timedelta(seconds=1)) else: donation = randgen.generate_donation(self.rand, donor=donor, event=self.event, minAmount=Decimal('0.01'), maxAmount=prize.minimumbid - Decimal('0.10'), minTime=prize.end_draw_time() + datetime.timedelta(seconds=1)) donation.save() if donationDonors[donor.id]['amount'] < prize.minimumbid: del donationDonors[donor.id] eligibleDonors = prize.eligible_donors() self.assertEqual(len(donationDonors.keys()), len(eligibleDonors)) for eligibleDonor in eligibleDonors: found = False if eligibleDonor['donor'] in donationDonors: entry = donationDonors[eligibleDonor['donor']] donor = entry['donor'] if entry['amount'] >= prize.minimumbid: donations = donor.donation_set.filter(timereceived__gte=prize.start_draw_time(), timereceived__lte=prize.end_draw_time()) countAmount = Decimal('0.00') for donation in donations: countAmount += donation.amount self.assertEqual(entry['amount'], eligibleDonor['amount']) self.assertEqual(countAmount, eligibleDonor['amount']) self.assertAlmostEqual(min(prize.maximumbid / prize.minimumbid, entry['amount'] / prize.minimumbid), Decimal(eligibleDonor['weight'])) found = True self.assertTrue(found and "Could not find the donor in the list") winners = [] for seed in [51234, 235426, 62363245]: result, message = viewutil.draw_prize(prize, seed) self.assertTrue(result) self.assertIn(prize.get_winner().id, donationDonors) winners.append(prize.get_winner()) current = prize.get_winner() prize.prizewinner_set.all().delete() prize.save() result, message = viewutil.draw_prize(prize, seed) self.assertTrue(result) self.assertEqual(current, prize.get_winner()) prize.prizewinner_set.all().delete() prize.save() self.assertNotEqual(winners[0], winners[1]) self.assertNotEqual(winners[1], winners[2]) self.assertNotEqual(winners[0], winners[2]) return
def test_draw_prize_multiple_donors_norandom_nosum(self): startRun = self.runsList[25] endRun = self.runsList[34] prize = randgen.generate_prize( self.rand, event=self.event, sumDonations=False, randomDraw=False, startRun=startRun, endRun=endRun) prize.save() largestDonor = None largestAmount = Decimal('0.00') for donor in self.donorList: numDonations = self.rand.getrandbits(4) redHerrings = self.rand.getrandbits(4) for i in range(0, numDonations): donation = randgen.generate_donation(self.rand, donor=donor, event=self.event, minAmount=Decimal( '0.01'), maxAmount=Decimal('1000.00'), minTime=prize.start_draw_time(), maxTime=prize.end_draw_time()) donation.save() if donation.amount > largestAmount: largestDonor = donor largestAmount = donation.amount # toss in a few extras to keep the drawer on its toes for i in range(0, redHerrings): donation = None if self.rand.getrandbits(1) == 0: donation = randgen.generate_donation(self.rand, donor=donor, event=self.event, minAmount=Decimal( '1000.01'), maxAmount=Decimal('2000.00'), maxTime=prize.start_draw_time() - datetime.timedelta(seconds=1)) else: donation = randgen.generate_donation(self.rand, donor=donor, event=self.event, minAmount=Decimal( '1000.01'), maxAmount=prize.minimumbid - Decimal('2000.00'), minTime=prize.end_draw_time() + datetime.timedelta(seconds=1)) donation.save() eligibleDonors = prize.eligible_donors() self.assertEqual(1, len(eligibleDonors)) self.assertEqual(largestDonor.id, eligibleDonors[0]['donor']) self.assertEqual(1.0, eligibleDonors[0]['weight']) self.assertEqual(largestAmount, eligibleDonors[0]['amount']) for seed in [9524, 373, 747]: prize.prizewinner_set.all().delete() prize.save() result, message = viewutil.draw_prize(prize, seed) self.assertTrue(result) self.assertEqual(largestDonor.id, prize.get_winner().id) newDonor = randgen.generate_donor(self.rand) newDonor.save() newDonation = randgen.generate_donation(self.rand, donor=newDonor, event=self.event, minAmount=Decimal( '1000.01'), maxAmount=Decimal('2000.00'), minTime=prize.start_draw_time(), maxTime=prize.end_draw_time()) newDonation.save() eligibleDonors = prize.eligible_donors() self.assertEqual(1, len(eligibleDonors)) self.assertEqual(newDonor.id, eligibleDonors[0]['donor']) self.assertEqual(1.0, eligibleDonors[0]['weight']) self.assertEqual(newDonation.amount, eligibleDonors[0]['amount']) for seed in [9524, 373, 747]: prize.prizewinner_set.all().delete() prize.save() result, message = viewutil.draw_prize(prize, seed) self.assertTrue(result) self.assertEqual(newDonor.id, prize.get_winner().id)
def test_draw_prize_multiple_donors_random_nosum(self): startRun = self.runsList[28] endRun = self.runsList[30] prize = randgen.generate_prize( self.rand, event=self.event, sumDonations=False, randomDraw=True, startRun=startRun, endRun=endRun) prize.save() donationDonors = {} for donor in self.donorList: if self.rand.getrandbits(1) == 0: donation = randgen.generate_donation(self.rand, donor=donor, event=self.event, minAmount=prize.minimumbid, maxAmount=prize.minimumbid + Decimal('100.00'), minTime=prize.start_draw_time(), maxTime=prize.end_draw_time()) donation.save() donationDonors[donor.id] = donor # Add a few red herrings to make sure out of range donations aren't # used donation2 = randgen.generate_donation(self.rand, donor=donor, event=self.event, minAmount=prize.minimumbid, maxAmount=prize.minimumbid + Decimal('100.00'), maxTime=prize.start_draw_time() - datetime.timedelta(seconds=1)) donation2.save() donation3 = randgen.generate_donation(self.rand, donor=donor, event=self.event, minAmount=prize.minimumbid, maxAmount=prize.minimumbid + Decimal('100.00'), minTime=prize.end_draw_time() + datetime.timedelta(seconds=1)) donation3.save() eligibleDonors = prize.eligible_donors() self.assertEqual(len(donationDonors.keys()), len(eligibleDonors)) for eligibleDonor in eligibleDonors: found = False if eligibleDonor['donor'] in donationDonors: donor = donationDonors[eligibleDonor['donor']] donation = donor.donation_set.filter(timereceived__gte=prize.start_draw_time( ), timereceived__lte=prize.end_draw_time())[0] self.assertEqual(donation.amount, eligibleDonor['amount']) self.assertEqual(1.0, eligibleDonor['weight']) found = True self.assertTrue(found and "Could not find the donor in the list") winners = [] for seed in [15634, 12512, 666]: result, message = viewutil.draw_prize(prize, seed) self.assertTrue(result) self.assertIn(prize.get_winner().id, donationDonors) winners.append(prize.get_winner()) current = prize.get_winner() prize.prizewinner_set.all().delete() prize.save() result, message = viewutil.draw_prize(prize, seed) self.assertTrue(result) self.assertEqual(current, prize.get_winner()) prize.prizewinner_set.all().delete() prize.save() self.assertNotEqual(winners[0], winners[1]) self.assertNotEqual(winners[1], winners[2]) self.assertNotEqual(winners[0], winners[2]) return
def draw_prize(self, prize): # TODO: add checks that the prize drawing time has passed status = True while status and not prize.maxed_winners(): status, data = viewutil.draw_prize(prize, seed=None) if not status: print('Error drawing prize #{0} : {1}'.format(prize.id, data['error']))
def test_draw_prize_with_tickets_no_donations(self): prize = randgen.generate_prize(self.rand, event=self.event, sumDonations=True, randomDraw=True, ticketDraw=True) prize.save() eligibleDonors = prize.eligible_donors() self.assertEqual(0, len(eligibleDonors)) result, message = viewutil.draw_prize(prize) self.assertFalse(result) self.assertEqual(None, prize.get_winner())
def test_draw_prize_one_donor(self): startRun = self.runsList[14] endRun = self.runsList[28] for useRandom in [True, False]: for useSum in [True, False]: for donationSize in ['top', 'bottom', 'above', 'below', 'within']: prize = randgen.generate_prize( self.rand, event=self.event, sumDonations=useSum, randomDraw=useRandom, startRun=startRun, endRun=endRun) prize.save() donor = randgen.pick_random_element( self.rand, self.donorList) donation = randgen.generate_donation( self.rand, donor=donor, event=self.event, minTime=prize.start_draw_time(), maxTime=prize.end_draw_time()) if donationSize == 'above': donation.amount = prize.maximumbid + Decimal('5.00') elif donationSize == 'top': donation.amount = prize.maximumbid elif donationSize == 'within': donation.amount = randgen.random_amount( self.rand, rounded=False, minAmount=prize.minimumbid, maxAmount=prize.maximumbid) elif donationSize == 'bottom': donation.amount = prize.minimumbid elif donationSize == 'below': donation.amount = max( Decimal('0.00'), prize.minimumbid - Decimal('5.00')) donation.save() eligibleDonors = prize.eligible_donors() if donationSize == 'below' and prize.randomdraw: self.assertEqual(0, len(eligibleDonors)) else: self.assertEqual(1, len(eligibleDonors)) self.assertEqual(donor.id, eligibleDonors[0]['donor']) self.assertEqual( donation.amount, eligibleDonors[0]['amount']) if prize.sumdonations and prize.randomdraw: if donationSize == 'top' or donationSize == 'above': expectedRatio = float( prize.maximumbid / prize.minimumbid) else: expectedRatio = float( donation.amount / prize.minimumbid) self.assertAlmostEqual( expectedRatio, eligibleDonors[0]['weight']) else: self.assertEqual(1.0, eligibleDonors[0]['weight']) result, message = viewutil.draw_prize(prize) if donationSize != 'below' or not prize.randomdraw: self.assertTrue(result) self.assertEqual(donor, prize.get_winner()) else: self.assertFalse(result) self.assertEqual(None, prize.get_winner()) donation.delete() prize.prizewinner_set.all().delete() prize.delete() return
def draw_prize_action(self, request, queryset): numDrawn = 0; for prize in queryset: drawn, msg = viewutil.draw_prize(prize); time.sleep(1); if not drawn: self.message_user(request, msg, level=messages.ERROR); else: prize.save(); numDrawn += 1; if numDrawn > 0: self.message_user(request, "%d prizes drawn." % numDrawn);
def draw_prize(request): try: if not request.user.has_perm('tracker.change_prize'): return HttpResponse('Access denied',status=403,content_type='text/plain;charset=utf-8') requestParams = viewutil.request_params(request) id = int(requestParams['id']) prize = Prize.objects.get(pk=id) if prize.maxed_winners(): maxWinnersMessage = "Prize: " + prize.name + " already has a winner." if prize.maxwinners == 1 else "Prize: " + prize.name + " already has the maximum number of winners allowed." return HttpResponse(json.dumps({'error': maxWinnersMessage}),status=409,content_type='application/json;charset=utf-8') skipKeyCheck = requestParams.get('skipkey', False) if not skipKeyCheck: eligible = prize.eligible_donors() if not eligible: return HttpResponse(json.dumps({'error': 'Prize has no eligible donors'}),status=409,content_type='application/json;charset=utf-8') key = hash(json.dumps(eligible)) if 'key' not in requestParams: return HttpResponse(json.dumps({'key': key}),content_type='application/json;charset=utf-8') else: try: okey = type(key)(requestParams['key']) except (ValueError,KeyError),e: return HttpResponse(json.dumps({'error': 'Key field was missing or malformed', 'exception': '%s %s' % (type(e),e)},ensure_ascii=False),status=400,content_type='application/json;charset=utf-8') if 'queries' in request.GET and request.user.has_perm('tracker.view_queries'): return HttpResponse(json.dumps(connection.queries, ensure_ascii=False, indent=1),content_type='application/json;charset=utf-8') limit = requestParams.get('limit', prize.maxwinners) if not limit: limit = prize.maxwinners currentCount = len(prize.get_winners()) status = True results = [] while status and currentCount < limit: status, data = viewutil.draw_prize(prize, seed=requestParams.get('seed',None)) if status: currentCount += 1 results.append(data) log.change(request,prize,u'Picked winner. %.2f,%.2f' % (data['sum'],data['result'])) return HttpResponse(json.dumps({'success': results}, ensure_ascii=False),content_type='application/json;charset=utf-8') else: return HttpResponse(json.dumps(data),status=400,content_type='application/json;charset=utf-8')
def test_draw_prize_with_tickets(self): prize = randgen.generate_prize(self.rand, event=self.event, sumDonations=True, randomDraw=True, ticketDraw=True) prize.maximumbid = None prize.save() donor = self.donorList[0] donation = randgen.generate_donation(self.rand, donor=donor, event=self.event, minAmount=prize.minimumbid, maxAmount=prize.minimumbid, minTime=prize.start_draw_time(), maxTime=prize.end_draw_time()) donation.save() tracker.models.PrizeTicket.objects.create(donation=donation, prize=prize, amount=donation.amount) eligibleDonors = prize.eligible_donors() self.assertEqual(1, len(eligibleDonors)) self.assertEqual(eligibleDonors[0]['donor'], donor.id) result, message = viewutil.draw_prize(prize) self.assertTrue(result) self.assertEqual(donor, prize.get_winner())
def test_draw_random_prize_no_donations(self): prizeList = randgen.generate_prizes(self.rand, self.event, 50, self.runsList) for prize in prizeList: for randomness in [True, False]: for useSum in [True, False]: prize.randomdraw = randomness prize.sumdonations = useSum prize.save() eligibleDonors = prize.eligible_donors() self.assertEqual(0, len(eligibleDonors)) result, message = viewutil.draw_prize(prize) self.assertFalse(result) self.assertEqual(0, len(prize.get_winners())) return
def draw_prize_internal(self, request, queryset, limit): numDrawn = 0 for prize in queryset: if not limit: limit = prize.maxwinners drawingError = False while not drawingError and len(prize.get_winners()) < limit: drawn, msg = viewutil.draw_prize(prize) time.sleep(1) if not drawn: self.message_user(request, msg, level=messages.ERROR) drawingError = True else: numDrawn += 1 if numDrawn > 0: self.message_user(request, "%d prizes drawn." % numDrawn)
def draw_prize_internal(self, request, queryset, limit): numDrawn = 0 for prize in queryset: if limit == None: limit = prize.maxwinners numToDraw = min(limit, prize.maxwinners - prize.current_win_count()) drawingError = False while not drawingError and numDrawn < numToDraw: drawn, msg = viewutil.draw_prize(prize) time.sleep(1) if not drawn: self.message_user(request, msg, level=messages.ERROR) drawingError = True else: numDrawn += 1 if numDrawn > 0: self.message_user(request, "%d prizes drawn." % numDrawn)
def draw_prize_winners(request): currentEvent = viewutil.get_selected_event(request) params = { 'feed': 'todraw' } if currentEvent != None: params['event'] = currentEvent.id prizes = filters.run_model_query('prize', params, user=request.user, mode='admin') if request.method == 'POST': form = forms.DrawPrizeWinnersForm(prizes=prizes, data=request.POST) if form.is_valid(): for prize in form.cleaned_data['prizes']: status = True while status and not prize.maxed_winners(): status, data = viewutil.draw_prize(prize, seed=form.cleaned_data['seed']) prize.error = data['error'] if not status else '' logutil.change(request, prize, 'Prize Drawing') return render(request, 'admin/draw_prize_winners_post.html', { 'prizes': form.cleaned_data['prizes'] }) else: form = forms.DrawPrizeWinnersForm(prizes=prizes) return render(request, 'admin/draw_prize_winners.html', { 'form': form })