def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # Summarize all the booth sales booth_sales = Booth.objects.annotate(Sum('purchase__amount')).order_by( 'category', 'name') booths = {} for b in booth_sales: amount = b.purchase__amount__sum booths[b.name] = D(amount) # Donations without a recorded booth need to be accounted for too donations = Purchase.objects.filter(booth__isnull=True).aggregate( Sum('amount'))['amount__sum'] booths['Generic Donations'] = D(donations) # Fees fees = D(Fee.objects.all().aggregate(Sum('amount'))['amount__sum']) booths['Fees'] = fees total = D(Purchase.objects.all().aggregate( Sum('amount'))['amount__sum']) + fees context['total_sum'] = D(total) context['booth_sums'] = booths return context
def create_auction_item_purchase(cls, patron, amount, auction_item, quantity): desc = 'Auction Item "{}"'.format(auction_item.name) desc = desc + ': Quantity: {}'.format( quantity) if quantity else desc p = Purchase.objects.create(patron=patron, amount=D(amount), auction_item=auction_item, description=desc, booth=auction_item.booth, fair_market_value=auction_item.fair_market_value, quantity=quantity) auction_item.sale_time = p.transaction_time auction_item.save() return p
class Purchase(TrackedModel, models.Model): patron = models.ForeignKey(Patron, related_name='purchases', on_delete=models.CASCADE) amount = models.DecimalField(max_digits=15, decimal_places=2) transaction_time = models.DateTimeField(auto_now_add=True, blank=True, null=True) booth = models.ForeignKey('Booth', blank=True, null=True, on_delete=models.SET_NULL) quantity = models.CharField(max_length=50, blank=True, verbose_name="Quantity", help_text="2 dozen, 3 gallons, etc.") is_donation = models.BooleanField(default=False, help_text="True only when the full amount was a donation " "with nothing received by the Patron") description = models.TextField(blank=True, verbose_name="Description", help_text="A description of the purchase") auction_item = models.ForeignKey('AuctionItem', null=True, blank=True, on_delete=models.CASCADE) fair_market_value = models.DecimalField(max_digits=15, decimal_places=2, help_text="Fair Market Value", default=D(0)) def __str__(self): return "{amount} purchase by {patron}".format(amount=USD(self.amount), patron=self.patron.name) def get_absolute_url(self): return reverse('purchase_detail', kwargs={'pk': self.pk}) @property def donation_amount(self): if self.is_donation: return D(self.amount) return D(0) @classmethod def create_donation(cls, patron, amount, booth, note=None): desc = 'Donation' + ': {}'.format(note) if note else '' p = Purchase.objects.create(patron=patron, amount=D(amount), description=desc, booth=booth, is_donation=True, fair_market_value=D(0)) return p @classmethod def create_priced_purchase(cls, patron, amount, booth): desc = 'Priced Item(s)' p = Purchase.objects.create(patron=patron, amount=D(amount), description=desc, booth=booth, fair_market_value=D(amount)) return p @classmethod def create_auction_item_purchase(cls, patron, amount, auction_item, quantity): desc = 'Auction Item "{}"'.format(auction_item.name) desc = desc + ': Quantity: {}'.format( quantity) if quantity else desc p = Purchase.objects.create(patron=patron, amount=D(amount), auction_item=auction_item, description=desc, booth=auction_item.booth, fair_market_value=auction_item.fair_market_value, quantity=quantity) auction_item.sale_time = p.transaction_time auction_item.save() return p
def form_valid(self, form): purchase_total = D(self.request.session['purchase_total']) # Save the purchase for the patron p = Purchase.create_priced_purchase(patron=self.patron, amount=purchase_total, booth=self.booth) # Clear the session state del (self.request.session['purchase_total']) del (self.request.session['purchase_forms']) msg = "Completed Purchase of {amount} by {name} ({number})".format( amount=USD(purchase_total), name=self.patron.name, number=self.patron.buyer_num) messages.add_message(self.request, messages.INFO, msg, 'alert-success') return redirect('checkout_patron', booth_slug=self.booth.slug)
class AuctionItem(TrackedModel): class Meta: pass name = models.CharField(max_length=100, blank=False, help_text="Short but descriptive name of item.") long_desc = models.TextField(blank=True, verbose_name="Long Description", help_text="Enter a description, donor information, etc.") fair_market_value = models.DecimalField(max_digits=15, decimal_places=2, default=D(0), verbose_name="Fair Market Value (FMV)", help_text="Dollars, e.g. 10.00") quantity = models.CharField(max_length=50, blank=True, null=True, verbose_name="Quantity", help_text="2 dozen, 3 gallons, etc.") item_number = models.PositiveIntegerField(unique=True, db_index=True, default=item_number_generator, help_text="Leave blank to auto-generate.") scheduled_sale_time = models.DateTimeField(blank=True, null=True, verbose_name="Scheduled Sale Time", help_text="The time when the item is scheduled during the auction.") sale_time = models.DateTimeField(blank=True, null=True, verbose_name="Sale Time", help_text="When the item sold. Leave blank when creating") donor_display = models.CharField(max_length=50, blank=True, null=True, verbose_name="Displayed Donor Name", help_text="How the item's donor would be displayed to the public") donor = models.ForeignKey('Patron', null=True, blank=True, help_text="The patron/donor for tax receipt purposes.", related_name="donations", on_delete=models.SET_NULL) booth = models.ForeignKey('Booth', blank=True, null=True, on_delete=models.SET_NULL) @property def is_purchased(self): if self.purchase_set.count() > 0: return True return False def purchase_sum(self): amount = self.purchase_set.aggregate(Sum('amount'))['amount__sum'] return amount if amount else 0 def purchaser_count(self): return self.purchase_set.count() def get_absolute_url(self): return reverse('item_detail', kwargs={'item_number': self.item_number})
def test_fee_rounding_down(self): assert D('0.09') == calc_cc_fee_amount(D('3.12'))
def get_context_data(self, **kwargs): context = super(CheckoutConfirm, self).get_context_data(**kwargs) context['patron'] = self.patron context['booth'] = self.booth context['purchase_total'] = D(self.request.session['purchase_total']) return context
def int_to_dec(self, i): return D(i) / D(100)
def purchases_total(self): purchases = self.purchases.all().aggregate(models.Sum('amount'))['amount__sum'] return D(purchases)
def payments_total(self): payments = self.payments.all().aggregate(models.Sum('amount'))['amount__sum'] return D(payments)
def create_donation(cls, patron, amount, booth, note=None): desc = 'Donation' + ': {}'.format(note) if note else '' p = Purchase.objects.create(patron=patron, amount=D(amount), description=desc, booth=booth, is_donation=True, fair_market_value=D(0)) return p
def create_priced_purchase(cls, patron, amount, booth): desc = 'Priced Item(s)' p = Purchase.objects.create(patron=patron, amount=D(amount), description=desc, booth=booth, fair_market_value=D(amount)) return p
def test_fee_rounding_up(self): assert D('0.10') == calc_cc_fee_amount(D('3.17'))
def donation_amount(self): if self.is_donation: return D(self.amount) return D(0)
def in_kind_donations_sales_total(self): return D(sum([i.purchase_sum() for i in self.donations.all()]))
def in_kind_donations_total(self): return D(sum([i.fair_market_value for i in self.donations.all()]))
def account_is_settled(self): return self.outstanding_balance == D(0)
def purchase_donations_total(self): donations = self.purchases.filter(is_donation=True).aggregate(models.Sum('amount'))['amount__sum'] return D(donations)
def fees_total(self): fees = self.fees.all().aggregate(models.Sum('amount'))['amount__sum'] return D(fees)