Moves total_payments() to Invoice model; adds balance_due()

This commit is contained in:
Christopher Neugebauer 2016-09-16 09:35:12 +10:00
parent fc81f107ed
commit 4a50d69936
5 changed files with 43 additions and 40 deletions

View file

@ -269,19 +269,12 @@ class InvoiceController(ForId, object):
CartController(self.invoice.cart).validate_cart()
def total_payments(self):
''' Returns the total amount paid towards this invoice. '''
payments = commerce.PaymentBase.objects.filter(invoice=self.invoice)
total_paid = payments.aggregate(Sum("amount"))["amount__sum"] or 0
return total_paid
def update_status(self):
''' Updates the status of this invoice based upon the total
payments.'''
old_status = self.invoice.status
total_paid = self.total_payments()
total_paid = self.invoice.total_payments()
num_payments = commerce.PaymentBase.objects.filter(
invoice=self.invoice,
).count()
@ -366,7 +359,7 @@ class InvoiceController(ForId, object):
def update_validity(self):
''' Voids this invoice if the cart it is attached to has updated. '''
if not self._invoice_matches_cart():
if self.total_payments() > 0:
if self.invoice.total_payments() > 0:
# Free up the payments made to this invoice
self.refund()
else:
@ -374,7 +367,7 @@ class InvoiceController(ForId, object):
def void(self):
''' Voids the invoice if it is valid to do so. '''
if self.total_payments() > 0:
if self.invoice.total_payments() > 0:
raise ValidationError("Invoices with payments must be refunded.")
elif self.invoice.is_refunded:
raise ValidationError("Refunded invoices may not be voided.")
@ -394,7 +387,7 @@ class InvoiceController(ForId, object):
raise ValidationError("Void invoices cannot be refunded")
# Raises a credit note fot the value of the invoice.
amount = self.total_payments()
amount = self.invoice.total_payments()
if amount == 0:
self.void()

View file

@ -4,7 +4,7 @@ from . import inventory
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models import F, Q
from django.db.models import F, Q, Sum
from django.utils import timezone
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
@ -175,6 +175,17 @@ class Invoice(models.Model):
def is_refunded(self):
return self.status == self.STATUS_REFUNDED
def total_payments(self):
''' Returns the total amount paid towards this invoice. '''
payments = PaymentBase.objects.filter(invoice=self)
total_paid = payments.aggregate(Sum("amount"))["amount__sum"] or 0
return total_paid
def balance_due(self):
''' Returns the total balance remaining towards this invoice. '''
return self.value - self.total_payments()
# Invoice Number
user = models.ForeignKey(User)
cart = models.ForeignKey(Cart, null=True)
@ -224,6 +235,11 @@ class LineItem(models.Model):
return "Line: %s * %d @ %s" % (
self.description, self.quantity, self.price)
@property
def total_price(self):
''' price * quantity '''
return self.price * self.quantity
invoice = models.ForeignKey(Invoice)
description = models.CharField(max_length=255)
quantity = models.PositiveIntegerField()

View file

@ -74,24 +74,3 @@ def items_purchased(context, category=None):
return ItemController(context.request.user).items_purchased(
category=category
)
@register.filter
def multiply(value, arg):
''' Multiplies value by arg.
This is useful when displaying invoices, as it lets you multiply the
quantity by the unit value.
Arguments:
value (number)
arg (number)
Returns:
number: value * arg
'''
return value * arg

View file

@ -29,7 +29,9 @@ class CreditNoteTestCase(TestHelperMixin, RegistrationCartTestCase):
invoice.pay("Reference", to_pay)
# The total paid should be equal to the value of the invoice only
self.assertEqual(invoice.invoice.value, invoice.total_payments())
self.assertEqual(
invoice.invoice.value, invoice.invoice.total_payments()
)
self.assertTrue(invoice.invoice.is_paid)
# There should be a credit note generated out of the invoice.
@ -46,7 +48,9 @@ class CreditNoteTestCase(TestHelperMixin, RegistrationCartTestCase):
invoice.pay("Reference", invoice.invoice.value)
# The total paid should be equal to the value of the invoice only
self.assertEqual(invoice.invoice.value, invoice.total_payments())
self.assertEqual(
invoice.invoice.value, invoice.invoice.total_payments()
)
self.assertTrue(invoice.invoice.is_paid)
# There should be no credit notes
@ -64,7 +68,7 @@ class CreditNoteTestCase(TestHelperMixin, RegistrationCartTestCase):
invoice.refund()
# The total paid should be zero
self.assertEqual(0, invoice.total_payments())
self.assertEqual(0, invoice.invoice.total_payments())
self.assertTrue(invoice.invoice.is_void)
# There should be a credit note generated out of the invoice.
@ -84,7 +88,7 @@ class CreditNoteTestCase(TestHelperMixin, RegistrationCartTestCase):
invoice.refund()
# The total paid should be zero
self.assertEqual(0, invoice.total_payments())
self.assertEqual(0, invoice.invoice.total_payments())
self.assertTrue(invoice.invoice.is_refunded)
# There should be a credit note generated out of the invoice.
@ -367,7 +371,7 @@ class CreditNoteTestCase(TestHelperMixin, RegistrationCartTestCase):
notes_value = self._generate_multiple_credit_notes()
invoice = self._manual_invoice(notes_value + 1)
self.assertEqual(notes_value, invoice.total_payments())
self.assertEqual(notes_value, invoice.invoice.total_payments())
self.assertTrue(invoice.invoice.is_unpaid)
user_unclaimed = commerce.CreditNote.unclaimed()
@ -384,7 +388,7 @@ class CreditNoteTestCase(TestHelperMixin, RegistrationCartTestCase):
invoice = self._manual_invoice(notes_value - 1)
self.assertEqual(notes_value - 1, invoice.total_payments())
self.assertEqual(notes_value - 1, invoice.invoice.total_payments())
self.assertTrue(invoice.invoice.is_paid)
user_unclaimed = commerce.CreditNote.unclaimed().filter(
@ -426,7 +430,7 @@ class CreditNoteTestCase(TestHelperMixin, RegistrationCartTestCase):
# Because there's already an invoice open for this user
# The credit notes are not automatically applied.
self.assertEqual(0, invoice.total_payments())
self.assertEqual(0, invoice.invoice.total_payments())
self.assertTrue(invoice.invoice.is_unpaid)
def test_credit_notes_are_applied_even_if_some_notes_are_claimed(self):

View file

@ -97,6 +97,17 @@ class InvoiceTestCase(TestHelperMixin, RegistrationCartTestCase):
new_cart = TestingCartController.for_user(self.USER_1)
self.assertNotEqual(invoice.invoice.cart, new_cart.cart)
def test_total_payments_balance_due(self):
invoice = self._invoice_containing_prod_1(2)
for i in xrange(0, invoice.invoice.value):
self.assertTrue(
i + 1, invoice.invoice.total_payments()
)
self.assertTrue(
invoice.invoice.value - i, invoice.invoice.balance_due()
)
invoice.pay("Pay 1", 1)
def test_invoice_includes_discounts(self):
voucher = inventory.Voucher.objects.create(
recipient="Voucher recipient",