Moves total_payments() to Invoice model; adds balance_due()
This commit is contained in:
		
							parent
							
								
									fc81f107ed
								
							
						
					
					
						commit
						4a50d69936
					
				
					 5 changed files with 43 additions and 40 deletions
				
			
		|  | @ -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() | ||||
|  |  | |||
|  | @ -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() | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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): | ||||
|  |  | |||
|  | @ -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", | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Christopher Neugebauer
						Christopher Neugebauer