From 04b7a7998c964c9e3793a78a695c4de8f6bcbd0c Mon Sep 17 00:00:00 2001 From: Christopher Neugebauer Date: Thu, 15 Sep 2016 10:32:22 +1000 Subject: [PATCH] Tests correct behaviour when there are multiple credit notes to be applied --- registrasion/controllers/invoice.py | 11 +++- registrasion/tests/test_credit_note.py | 81 +++++++++++++++++++++++++- 2 files changed, 86 insertions(+), 6 deletions(-) diff --git a/registrasion/controllers/invoice.py b/registrasion/controllers/invoice.py index 9fadcd11..09eb02da 100644 --- a/registrasion/controllers/invoice.py +++ b/registrasion/controllers/invoice.py @@ -208,11 +208,16 @@ class InvoiceController(ForId, object): ''' Applies the user's credit notes to the given invoice on creation. ''' - notes = commerce.CreditNote.objects.filter(invoice__user=invoice.user) - - if len(notes) == 0: + # We only automatically apply credit notes if this is the *only* + # unpaid invoice for this user. + invoices = commerce.Invoice.objects.filter( + user=invoice.user, + status=commerce.Invoice.STATUS_UNPAID, + ) + if invoices.count() > 1: return + notes = commerce.CreditNote.objects.filter(invoice__user=invoice.user) for note in notes: try: CreditNoteController(note).apply_to_invoice(invoice) diff --git a/registrasion/tests/test_credit_note.py b/registrasion/tests/test_credit_note.py index ce704652..d725048b 100644 --- a/registrasion/tests/test_credit_note.py +++ b/registrasion/tests/test_credit_note.py @@ -336,13 +336,37 @@ class CreditNoteTestCase(TestHelperMixin, RegistrationCartTestCase): invoice2 = self._invoice_containing_prod_1(1) self.assertTrue(invoice2.invoice.is_paid) + def _generate_multiple_credit_notes(self): + items = [("Item 1", 5), ("Item 2", 6)] + due = datetime.timedelta(hours=1) + inv1 = TestingInvoiceController.manual_invoice(self.USER_1, due, items) + inv2 = TestingInvoiceController.manual_invoice(self.USER_1, due, items) + invoice1 = TestingInvoiceController(inv1) + invoice1.pay("Pay", inv1.value) + invoice1.refund() + invoice2 = TestingInvoiceController(inv2) + invoice2.pay("Pay", inv2.value) + invoice2.refund() + return inv1.value + inv2.value + def test_mutiple_credit_notes_are_applied_when_generating_invoice_1(self): ''' Tests (1) that multiple credit notes are applied to new invoice. Sum of credit note values will be *LESS* than the new invoice. ''' - raise NotImplementedError() + notes_value = self._generate_multiple_credit_notes() + item = [("Item", notes_value + 1)] + due = datetime.timedelta(hours=1) + inv = TestingInvoiceController.manual_invoice(self.USER_1, due, item) + invoice = TestingInvoiceController(inv) + + self.assertEqual(notes_value, invoice.total_payments()) + self.assertTrue(invoice.invoice.is_unpaid) + + user_unclaimed = commerce.CreditNote.unclaimed() + user_unclaimed = user_unclaimed.filter(invoice__user=self.USER_1) + self.assertEqual(0, user_unclaimed.count()) def test_mutiple_credit_notes_are_applied_when_generating_invoice_2(self): ''' Tests (2) that multiple credit notes are applied to new invoice. @@ -350,8 +374,59 @@ class CreditNoteTestCase(TestHelperMixin, RegistrationCartTestCase): Sum of credit note values will be *GREATER* than the new invoice. ''' - raise NotImplementedError() + notes_value = self._generate_multiple_credit_notes() + item = [("Item", notes_value - 1)] + due = datetime.timedelta(hours=1) + inv = TestingInvoiceController.manual_invoice(self.USER_1, due, item) + invoice = TestingInvoiceController(inv) + + self.assertEqual(notes_value - 1, invoice.total_payments()) + self.assertTrue(invoice.invoice.is_paid) + + user_unclaimed = commerce.CreditNote.unclaimed().filter( + invoice__user=self.USER_1 + ) + self.assertEqual(1, user_unclaimed.count()) + + excess = self._credit_note_for_invoice(invoice.invoice) + self.assertEqual(excess.credit_note.value, 1) + + def test_credit_notes_are_left_over_if_not_all_are_needed(self): + ''' Tests that excess credit notes are untouched if they're not needed + ''' + + notes_value = self._generate_multiple_credit_notes() + notes_old = commerce.CreditNote.unclaimed().filter( + invoice__user=self.USER_1 + ) + + # Create a manual invoice whose value is smaller than any of the + # credit notes we created + item = [("Item", 1)] + due = datetime.timedelta(hours=1) + inv = TestingInvoiceController.manual_invoice(self.USER_1, due, item) + + notes_new = commerce.CreditNote.unclaimed().filter( + invoice__user=self.USER_1 + ) + + # Item is True if the note was't consumed when generating invoice. + note_was_unused = [(i in notes_old) for i in notes_new] + self.assertIn(True, note_was_unused) def test_credit_notes_are_not_applied_if_user_has_multiple_invoices(self): - raise NotImplementedError() + # Have an invoice pending with no credit notes; no payment will be made + invoice1 = self._invoice_containing_prod_1(1) + # Create some credit notes. + self._generate_multiple_credit_notes() + + item = [("Item", notes_value)] + due = datetime.timedelta(hours=1) + inv = TestingInvoiceController.manual_invoice(self.USER_1, due, item) + invoice = TestingInvoiceController(inv) + + # Because there's already an invoice open for this user + # The credit notes are not automatically applied. + self.assertEqual(0, invoice.total_payments()) + self.assertTrue(invoice.invoice.is_unpaid)