commit
31d057c750
4 changed files with 78 additions and 0 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
import datetime
|
||||||
|
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
|
||||||
from registrasion.models import commerce
|
from registrasion.models import commerce
|
||||||
|
@ -53,3 +55,27 @@ class CreditNoteController(ForId, object):
|
||||||
inv.update_status()
|
inv.update_status()
|
||||||
|
|
||||||
# TODO: Add administration fee generator.
|
# TODO: Add administration fee generator.
|
||||||
|
@transaction.atomic
|
||||||
|
def cancellation_fee(self, percentage):
|
||||||
|
''' Generates an invoice with a cancellation fee, and applies
|
||||||
|
credit to the invoice.
|
||||||
|
|
||||||
|
percentage (Decimal): The percentage of the credit note to turn into
|
||||||
|
a cancellation fee. Must be 0 <= percentage <= 100.
|
||||||
|
'''
|
||||||
|
|
||||||
|
from invoice import InvoiceController # Circular imports bleh.
|
||||||
|
|
||||||
|
assert(percentage >= 0 and percentage <= 100)
|
||||||
|
|
||||||
|
cancellation_fee = self.credit_note.value * percentage / 100
|
||||||
|
due = datetime.timedelta(days=1)
|
||||||
|
item = [("Cancellation fee", cancellation_fee)]
|
||||||
|
invoice = InvoiceController.manual_invoice(
|
||||||
|
self.credit_note.invoice.user, due, item
|
||||||
|
)
|
||||||
|
|
||||||
|
if not invoice.is_paid:
|
||||||
|
self.apply_to_invoice(invoice)
|
||||||
|
|
||||||
|
return InvoiceController(invoice)
|
||||||
|
|
|
@ -3,6 +3,7 @@ from registrasion.models import commerce
|
||||||
from registrasion.models import inventory
|
from registrasion.models import inventory
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
|
||||||
|
|
||||||
class ApplyCreditNoteForm(forms.Form):
|
class ApplyCreditNoteForm(forms.Form):
|
||||||
|
@ -31,6 +32,14 @@ class ApplyCreditNoteForm(forms.Form):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CancellationFeeForm(forms.Form):
|
||||||
|
|
||||||
|
percentage = forms.DecimalField(
|
||||||
|
required=True,
|
||||||
|
min_value=0,
|
||||||
|
max_value=100,
|
||||||
|
)
|
||||||
|
|
||||||
class ManualCreditNoteRefundForm(forms.ModelForm):
|
class ManualCreditNoteRefundForm(forms.ModelForm):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -440,3 +440,28 @@ class CreditNoteTestCase(TestHelperMixin, RegistrationCartTestCase):
|
||||||
# Generate invoice that should be automatically paid
|
# Generate invoice that should be automatically paid
|
||||||
invoice2 = self._manual_invoice(1)
|
invoice2 = self._manual_invoice(1)
|
||||||
self.assertTrue(invoice2.invoice.is_paid)
|
self.assertTrue(invoice2.invoice.is_paid)
|
||||||
|
|
||||||
|
def test_cancellation_fee_is_applied(self):
|
||||||
|
|
||||||
|
invoice1 = self._manual_invoice(1)
|
||||||
|
invoice1.pay("Pay", invoice1.invoice.value)
|
||||||
|
invoice1.refund()
|
||||||
|
|
||||||
|
percentage = 15
|
||||||
|
|
||||||
|
cn = self._credit_note_for_invoice(invoice1.invoice)
|
||||||
|
canc = cn.cancellation_fee(15)
|
||||||
|
|
||||||
|
# Cancellation fee exceeds the amount for the invoice.
|
||||||
|
self.assertTrue(canc.invoice.is_paid)
|
||||||
|
|
||||||
|
# Cancellation fee is equal to 15% of credit note's value
|
||||||
|
self.assertEqual(
|
||||||
|
canc.invoice.value,
|
||||||
|
cn.credit_note.value * percentage / 100
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_cancellation_fee_is_applied_when_another_invoice_is_unpaid(self):
|
||||||
|
|
||||||
|
extra_invoice = self._manual_invoice(23)
|
||||||
|
self.test_cancellation_fee_is_applied()
|
||||||
|
|
|
@ -765,6 +765,9 @@ def credit_note(request, note_id, access_code=None):
|
||||||
# to an invoice.
|
# to an invoice.
|
||||||
"refund_form": form, # A form for applying a *manual*
|
"refund_form": form, # A form for applying a *manual*
|
||||||
# refund of the credit note.
|
# refund of the credit note.
|
||||||
|
"cancellation_fee_form" : form, # A form for generating an
|
||||||
|
# invoice with a
|
||||||
|
# cancellation fee
|
||||||
}
|
}
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
@ -783,6 +786,11 @@ def credit_note(request, note_id, access_code=None):
|
||||||
prefix="refund_note"
|
prefix="refund_note"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cancellation_fee_form = forms.CancellationFeeForm(
|
||||||
|
request.POST or None,
|
||||||
|
prefix="cancellation_fee"
|
||||||
|
)
|
||||||
|
|
||||||
if request.POST and apply_form.is_valid():
|
if request.POST and apply_form.is_valid():
|
||||||
inv_id = apply_form.cleaned_data["invoice"]
|
inv_id = apply_form.cleaned_data["invoice"]
|
||||||
invoice = commerce.Invoice.objects.get(pk=inv_id)
|
invoice = commerce.Invoice.objects.get(pk=inv_id)
|
||||||
|
@ -805,10 +813,20 @@ def credit_note(request, note_id, access_code=None):
|
||||||
prefix="refund_note",
|
prefix="refund_note",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
elif request.POST and cancellation_fee_form.is_valid():
|
||||||
|
percentage = cancellation_fee_form.cleaned_data["percentage"]
|
||||||
|
invoice = current_note.cancellation_fee(percentage)
|
||||||
|
messages.success(
|
||||||
|
request,
|
||||||
|
"Generated cancellation fee for credit note %d." % note_id,
|
||||||
|
)
|
||||||
|
return redirect("invoice", invoice.invoice.id)
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"credit_note": current_note.credit_note,
|
"credit_note": current_note.credit_note,
|
||||||
"apply_form": apply_form,
|
"apply_form": apply_form,
|
||||||
"refund_form": refund_form,
|
"refund_form": refund_form,
|
||||||
|
"cancellation_fee_form": cancellation_fee_form,
|
||||||
}
|
}
|
||||||
|
|
||||||
return render(request, "registrasion/credit_note.html", data)
|
return render(request, "registrasion/credit_note.html", data)
|
||||||
|
|
Loading…
Reference in a new issue