Credit notes are now generated when invoices are overpaid, or invoices are paid into void or refunded invoices. Closes #37.
This commit is contained in:
parent
9a4574ef2c
commit
12e04c248f
3 changed files with 64 additions and 18 deletions
|
@ -13,6 +13,7 @@ from cart import CartController
|
|||
from credit_note import CreditNoteController
|
||||
from for_id import ForId
|
||||
|
||||
|
||||
class InvoiceController(ForId, object):
|
||||
|
||||
__MODEL__ = commerce.Invoice
|
||||
|
@ -195,11 +196,6 @@ class InvoiceController(ForId, object):
|
|||
# Invoice no longer has amount owing
|
||||
self._mark_paid()
|
||||
|
||||
if remainder < 0:
|
||||
CreditNoteController.generate_from_invoice(
|
||||
self.invoice,
|
||||
0 - remainder,
|
||||
)
|
||||
elif total_paid == 0 and num_payments > 0:
|
||||
# Invoice has multiple payments totalling zero
|
||||
self._mark_void()
|
||||
|
@ -215,6 +211,17 @@ class InvoiceController(ForId, object):
|
|||
# Should not ever change from here
|
||||
pass
|
||||
|
||||
# Generate credit notes from residual payments
|
||||
residual = 0
|
||||
if self.invoice.is_paid:
|
||||
if remainder < 0:
|
||||
residual = 0 - remainder
|
||||
elif self.invoice.is_void or self.invoice.is_refunded:
|
||||
residual = total_paid
|
||||
|
||||
if residual != 0:
|
||||
CreditNoteController.generate_from_invoice(self.invoice, residual)
|
||||
|
||||
def _mark_paid(self):
|
||||
''' Marks the invoice as paid, and updates the attached cart if
|
||||
necessary. '''
|
||||
|
|
|
@ -34,11 +34,14 @@ class TestingCartController(CartController):
|
|||
|
||||
class TestingInvoiceController(InvoiceController):
|
||||
|
||||
def pay(self, reference, amount):
|
||||
def pay(self, reference, amount, pre_validate=True):
|
||||
''' Testing method for simulating an invoice paymenht by the given
|
||||
amount. '''
|
||||
|
||||
self.validate_allowed_to_pay()
|
||||
if pre_validate:
|
||||
# Manual payments don't pre-validate; we should test that things
|
||||
# still work if we do silly things.
|
||||
self.validate_allowed_to_pay()
|
||||
|
||||
''' Adds a payment '''
|
||||
commerce.ManualPayment.objects.create(
|
||||
|
|
|
@ -24,6 +24,10 @@ class InvoiceTestCase(RegistrationCartTestCase):
|
|||
|
||||
return TestingInvoiceController.for_cart(self.reget(cart.cart))
|
||||
|
||||
def _credit_note_for_invoice(self, invoice):
|
||||
note = commerce.CreditNote.objects.get(invoice=invoice)
|
||||
return TestingCreditNoteController(note)
|
||||
|
||||
def test_create_invoice(self):
|
||||
current_cart = TestingCartController.for_user(self.USER_1)
|
||||
|
||||
|
@ -314,8 +318,7 @@ class InvoiceTestCase(RegistrationCartTestCase):
|
|||
invoice.refund()
|
||||
|
||||
# There should be one credit note generated out of the invoice.
|
||||
credit_note = commerce.CreditNote.objects.get(invoice=invoice.invoice)
|
||||
cn = TestingCreditNoteController(credit_note)
|
||||
cn = self._credit_note_for_invoice(invoice.invoice)
|
||||
|
||||
# That credit note should be in the unclaimed pile
|
||||
self.assertEquals(1, commerce.CreditNote.unclaimed().count())
|
||||
|
@ -342,8 +345,7 @@ class InvoiceTestCase(RegistrationCartTestCase):
|
|||
invoice.refund()
|
||||
|
||||
# There should be one credit note generated out of the invoice.
|
||||
credit_note = commerce.CreditNote.objects.get(invoice=invoice.invoice)
|
||||
cn = TestingCreditNoteController(credit_note)
|
||||
cn = self._credit_note_for_invoice(invoice.invoice)
|
||||
|
||||
self.assertEquals(1, commerce.CreditNote.unclaimed().count())
|
||||
|
||||
|
@ -381,8 +383,7 @@ class InvoiceTestCase(RegistrationCartTestCase):
|
|||
invoice.refund()
|
||||
|
||||
# There should be one credit note generated out of the invoice.
|
||||
credit_note = commerce.CreditNote.objects.get(invoice=invoice.invoice)
|
||||
cn = TestingCreditNoteController(credit_note)
|
||||
cn = self._credit_note_for_invoice(invoice.invoice)
|
||||
|
||||
# Create a new cart with invoice, pay it
|
||||
invoice_2 = self._invoice_containing_prod_1(1)
|
||||
|
@ -415,9 +416,8 @@ class InvoiceTestCase(RegistrationCartTestCase):
|
|||
|
||||
self.assertEquals(1, commerce.CreditNote.unclaimed().count())
|
||||
|
||||
credit_note = commerce.CreditNote.objects.get(invoice=invoice.invoice)
|
||||
cn = self._credit_note_for_invoice(invoice.invoice)
|
||||
|
||||
cn = TestingCreditNoteController(credit_note)
|
||||
cn.refund()
|
||||
|
||||
# Refunding a credit note should mark it as claimed
|
||||
|
@ -444,9 +444,7 @@ class InvoiceTestCase(RegistrationCartTestCase):
|
|||
|
||||
self.assertEquals(1, commerce.CreditNote.unclaimed().count())
|
||||
|
||||
credit_note = commerce.CreditNote.objects.get(invoice=invoice.invoice)
|
||||
|
||||
cn = TestingCreditNoteController(credit_note)
|
||||
cn = self._credit_note_for_invoice(invoice.invoice)
|
||||
|
||||
# Create a new cart with invoice
|
||||
cart = TestingCartController.for_user(self.USER_1)
|
||||
|
@ -460,3 +458,41 @@ class InvoiceTestCase(RegistrationCartTestCase):
|
|||
# Cannot refund this credit note as it is already applied.
|
||||
with self.assertRaises(ValidationError):
|
||||
cn.refund()
|
||||
|
||||
def test_money_into_void_invoice_generates_credit_note(self):
|
||||
invoice = self._invoice_containing_prod_1(1)
|
||||
invoice.void()
|
||||
|
||||
val = invoice.invoice.value
|
||||
|
||||
invoice.pay("Paying into the void.", val, pre_validate=False)
|
||||
cn = self._credit_note_for_invoice(invoice.invoice)
|
||||
self.assertEqual(val, cn.credit_note.value)
|
||||
|
||||
def test_money_into_refunded_invoice_generates_credit_note(self):
|
||||
invoice = self._invoice_containing_prod_1(1)
|
||||
|
||||
val = invoice.invoice.value
|
||||
|
||||
invoice.pay("Paying the first time.", val)
|
||||
invoice.refund()
|
||||
|
||||
cnval = val - 1
|
||||
invoice.pay("Paying into the void.", cnval, pre_validate=False)
|
||||
|
||||
notes = commerce.CreditNote.objects.filter(invoice=invoice.invoice)
|
||||
notes = sorted(notes, key = lambda note: note.value)
|
||||
|
||||
self.assertEqual(cnval, notes[0].value)
|
||||
self.assertEqual(val, notes[1].value)
|
||||
|
||||
def test_money_into_paid_invoice_generates_credit_note(self):
|
||||
invoice = self._invoice_containing_prod_1(1)
|
||||
|
||||
val = invoice.invoice.value
|
||||
|
||||
invoice.pay("Paying the first time.", val)
|
||||
|
||||
invoice.pay("Paying into the void.", val, pre_validate=False)
|
||||
cn = self._credit_note_for_invoice(invoice.invoice)
|
||||
self.assertEqual(val, cn.credit_note.value)
|
||||
|
|
Loading…
Reference in a new issue