Makes invoice model, controller, and test changes to match issue #15 design doc
This commit is contained in:
parent
5633554854
commit
38cdb8aa63
7 changed files with 313 additions and 99 deletions
|
@ -3,6 +3,7 @@ from django.core.exceptions import ObjectDoesNotExist
|
|||
from django.core.exceptions import ValidationError
|
||||
from django.db import transaction
|
||||
from django.db.models import Sum
|
||||
from django.utils import timezone
|
||||
|
||||
from registrasion import models as rego
|
||||
|
||||
|
@ -13,6 +14,7 @@ class InvoiceController(object):
|
|||
|
||||
def __init__(self, invoice):
|
||||
self.invoice = invoice
|
||||
self.update_status()
|
||||
self.update_validity() # Make sure this invoice is up-to-date
|
||||
|
||||
@classmethod
|
||||
|
@ -22,21 +24,26 @@ class InvoiceController(object):
|
|||
an invoice is generated.'''
|
||||
|
||||
try:
|
||||
invoice = rego.Invoice.objects.get(
|
||||
invoice = rego.Invoice.objects.exclude(
|
||||
status=rego.Invoice.STATUS_VOID,
|
||||
).get(
|
||||
cart=cart,
|
||||
cart_revision=cart.revision,
|
||||
void=False,
|
||||
)
|
||||
except ObjectDoesNotExist:
|
||||
cart_controller = CartController(cart)
|
||||
cart_controller.validate_cart() # Raises ValidationError on fail.
|
||||
|
||||
# Void past invoices for this cart
|
||||
rego.Invoice.objects.filter(cart=cart).update(void=True)
|
||||
|
||||
cls.void_all_invoices(cart)
|
||||
invoice = cls._generate(cart)
|
||||
|
||||
return InvoiceController(invoice)
|
||||
return cls(invoice)
|
||||
|
||||
@classmethod
|
||||
def void_all_invoices(cls, cart):
|
||||
invoices = rego.Invoice.objects.filter(cart=cart).all()
|
||||
for invoice in invoices:
|
||||
cls(invoice).void()
|
||||
|
||||
@classmethod
|
||||
def resolve_discount_value(cls, item):
|
||||
|
@ -60,11 +67,21 @@ class InvoiceController(object):
|
|||
@transaction.atomic
|
||||
def _generate(cls, cart):
|
||||
''' Generates an invoice for the given cart. '''
|
||||
|
||||
issued = timezone.now()
|
||||
reservation_limit = cart.reservation_duration + cart.time_last_updated
|
||||
# Never generate a due time that is before the issue time
|
||||
due = max(issued, reservation_limit)
|
||||
|
||||
invoice = rego.Invoice.objects.create(
|
||||
user=cart.user,
|
||||
cart=cart,
|
||||
cart_revision=cart.revision,
|
||||
value=Decimal()
|
||||
status=rego.Invoice.STATUS_UNPAID,
|
||||
value=Decimal(),
|
||||
issue_time=issued,
|
||||
due_time=due,
|
||||
recipient="BOB_THOMAS", # TODO: add recipient generating code
|
||||
)
|
||||
|
||||
product_items = rego.ProductItem.objects.filter(cart=cart)
|
||||
|
@ -84,6 +101,7 @@ class InvoiceController(object):
|
|||
description="%s - %s" % (product.category.name, product.name),
|
||||
quantity=item.quantity,
|
||||
price=product.price,
|
||||
product=product,
|
||||
)
|
||||
invoice_value += line_item.quantity * line_item.price
|
||||
|
||||
|
@ -93,94 +111,121 @@ class InvoiceController(object):
|
|||
description=item.discount.description,
|
||||
quantity=item.quantity,
|
||||
price=cls.resolve_discount_value(item) * -1,
|
||||
product=item.product,
|
||||
)
|
||||
invoice_value += line_item.quantity * line_item.price
|
||||
|
||||
invoice.value = invoice_value
|
||||
|
||||
if invoice.value == 0:
|
||||
invoice.paid = True
|
||||
|
||||
invoice.save()
|
||||
|
||||
return invoice
|
||||
|
||||
def total_payments(self):
|
||||
''' Returns the total amount paid towards this invoice. '''
|
||||
|
||||
payments = rego.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()
|
||||
num_payments = rego.PaymentBase.objects.filter(
|
||||
invoice=self.invoice,
|
||||
).count()
|
||||
remainder = self.invoice.value - total_paid
|
||||
|
||||
if old_status == rego.Invoice.STATUS_UNPAID:
|
||||
# Invoice had an amount owing
|
||||
if remainder <= 0:
|
||||
# Invoice no longer has amount owing
|
||||
self._mark_paid()
|
||||
elif total_paid == 0 and num_payments > 0:
|
||||
# Invoice has multiple payments totalling zero
|
||||
self._mark_void()
|
||||
elif old_status == rego.Invoice.STATUS_PAID:
|
||||
if remainder > 0:
|
||||
# Invoice went from having a remainder of zero or less
|
||||
# to having a positive remainder -- must be a refund
|
||||
self._mark_refunded()
|
||||
elif old_status == rego.Invoice.STATUS_REFUNDED:
|
||||
# Should not ever change from here
|
||||
pass
|
||||
elif old_status == rego.Invoice.STATUS_VOID:
|
||||
# Should not ever change from here
|
||||
pass
|
||||
|
||||
def _mark_paid(self):
|
||||
''' Marks the invoice as paid, and updates the attached cart if
|
||||
necessary. '''
|
||||
cart = self.invoice.cart
|
||||
if cart:
|
||||
cart.active = False
|
||||
cart.save()
|
||||
self.invoice.status = rego.Invoice.STATUS_PAID
|
||||
self.invoice.save()
|
||||
|
||||
def _mark_refunded(self):
|
||||
''' Marks the invoice as refunded, and updates the attached cart if
|
||||
necessary. '''
|
||||
cart = self.invoice.cart
|
||||
if cart:
|
||||
cart.active = False
|
||||
cart.released = True
|
||||
cart.save()
|
||||
self.invoice.status = rego.Invoice.STATUS_REFUNDED
|
||||
self.invoice.save()
|
||||
|
||||
def _mark_void(self):
|
||||
''' Marks the invoice as refunded, and updates the attached cart if
|
||||
necessary. '''
|
||||
self.invoice.status = rego.Invoice.STATUS_VOID
|
||||
self.invoice.save()
|
||||
|
||||
def _invoice_matches_cart(self):
|
||||
''' Returns true if there is no cart, or if the revision of this
|
||||
invoice matches the current revision of the cart. '''
|
||||
cart = self.invoice.cart
|
||||
if not cart:
|
||||
return True
|
||||
|
||||
return cart.revision == self.invoice.cart_revision
|
||||
|
||||
def update_validity(self):
|
||||
''' Updates the validity of this invoice if the cart it is attached to
|
||||
has updated. '''
|
||||
if self.invoice.cart is not None:
|
||||
if self.invoice.cart.revision != self.invoice.cart_revision:
|
||||
self.void()
|
||||
''' Voids this invoice if the cart it is attached to has updated. '''
|
||||
if not self._invoice_matches_cart():
|
||||
self.void()
|
||||
|
||||
def void(self):
|
||||
''' Voids the invoice if it is valid to do so. '''
|
||||
if self.invoice.paid:
|
||||
if self.invoice.status == rego.Invoice.STATUS_PAID:
|
||||
raise ValidationError("Paid invoices cannot be voided, "
|
||||
"only refunded.")
|
||||
self.invoice.void = True
|
||||
self.invoice.save()
|
||||
|
||||
@transaction.atomic
|
||||
def pay(self, reference, amount):
|
||||
''' Pays the invoice by the given amount. If the payment
|
||||
equals the total on the invoice, finalise the invoice.
|
||||
(NB should be transactional.)
|
||||
'''
|
||||
if self.invoice.cart:
|
||||
cart = CartController(self.invoice.cart)
|
||||
cart.validate_cart() # Raises ValidationError if invalid
|
||||
|
||||
if self.invoice.void:
|
||||
raise ValidationError("Void invoices cannot be paid")
|
||||
|
||||
if self.invoice.paid:
|
||||
raise ValidationError("Paid invoices cannot be paid again")
|
||||
|
||||
''' Adds a payment '''
|
||||
payment = rego.Payment.objects.create(
|
||||
invoice=self.invoice,
|
||||
reference=reference,
|
||||
amount=amount,
|
||||
)
|
||||
payment.save()
|
||||
|
||||
payments = rego.Payment.objects.filter(invoice=self.invoice)
|
||||
agg = payments.aggregate(Sum("amount"))
|
||||
total = agg["amount__sum"]
|
||||
|
||||
if total == self.invoice.value:
|
||||
self.invoice.paid = True
|
||||
|
||||
if self.invoice.cart:
|
||||
cart = self.invoice.cart
|
||||
cart.active = False
|
||||
cart.save()
|
||||
|
||||
self.invoice.save()
|
||||
self._mark_void()
|
||||
|
||||
@transaction.atomic
|
||||
def refund(self, reference, amount):
|
||||
''' Refunds the invoice by the given amount. The invoice is
|
||||
marked as unpaid, and the underlying cart is marked as released.
|
||||
''' Refunds the invoice by the given amount.
|
||||
|
||||
The invoice is marked as refunded, and the underlying cart is marked
|
||||
as released.
|
||||
|
||||
TODO: replace with credit notes work instead.
|
||||
'''
|
||||
|
||||
if self.invoice.void:
|
||||
if self.invoice.is_void:
|
||||
raise ValidationError("Void invoices cannot be refunded")
|
||||
|
||||
''' Adds a payment '''
|
||||
payment = rego.Payment.objects.create(
|
||||
# Adds a payment
|
||||
# TODO: replace by creating a credit note instead
|
||||
rego.ManualPayment.objects.create(
|
||||
invoice=self.invoice,
|
||||
reference=reference,
|
||||
amount=0 - amount,
|
||||
)
|
||||
payment.save()
|
||||
|
||||
self.invoice.paid = False
|
||||
self.invoice.void = True
|
||||
|
||||
if self.invoice.cart:
|
||||
cart = self.invoice.cart
|
||||
cart.released = True
|
||||
cart.save()
|
||||
|
||||
self.invoice.save()
|
||||
self.update_status()
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.2 on 2016-04-07 03:13
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
replaces = [('registrasion', '0013_auto_20160406_2228'), ('registrasion', '0014_auto_20160406_1847'), ('registrasion', '0015_auto_20160406_1942')]
|
||||
|
||||
dependencies = [
|
||||
('registrasion', '0012_auto_20160406_1212'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='PaymentBase',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('time', models.DateTimeField(default=django.utils.timezone.now)),
|
||||
('reference', models.CharField(max_length=255)),
|
||||
('amount', models.DecimalField(decimal_places=2, max_digits=8)),
|
||||
],
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='payment',
|
||||
name='invoice',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='invoice',
|
||||
name='paid',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='invoice',
|
||||
name='void',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='invoice',
|
||||
name='due_time',
|
||||
field=models.DateTimeField(default=django.utils.timezone.now),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='invoice',
|
||||
name='issue_time',
|
||||
field=models.DateTimeField(default=django.utils.timezone.now),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='invoice',
|
||||
name='recipient',
|
||||
field=models.CharField(default='Lol', max_length=1024),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='invoice',
|
||||
name='status',
|
||||
field=models.IntegerField(choices=[(1, 'Unpaid'), (2, 'Paid'), (3, 'Refunded'), (4, 'VOID')], db_index=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='lineitem',
|
||||
name='product',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='registrasion.Product'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ManualPayment',
|
||||
fields=[
|
||||
('paymentbase_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='registrasion.PaymentBase')),
|
||||
],
|
||||
bases=('registrasion.paymentbase',),
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Payment',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='paymentbase',
|
||||
name='invoice',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='registrasion.Invoice'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='invoice',
|
||||
name='cart_revision',
|
||||
field=models.IntegerField(db_index=True, null=True),
|
||||
),
|
||||
]
|
|
@ -3,6 +3,7 @@ from __future__ import unicode_literals
|
|||
import datetime
|
||||
import itertools
|
||||
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.contrib.auth.models import User
|
||||
from django.db import models
|
||||
|
@ -26,13 +27,10 @@ class Attendee(models.Model):
|
|||
def get_instance(user):
|
||||
''' Returns the instance of attendee for the given user, or creates
|
||||
a new one. '''
|
||||
attendees = Attendee.objects.filter(user=user)
|
||||
if len(attendees) > 0:
|
||||
return attendees[0]
|
||||
else:
|
||||
attendee = Attendee(user=user)
|
||||
attendee.save()
|
||||
return attendee
|
||||
try:
|
||||
return Attendee.objects.get(user=user)
|
||||
except ObjectDoesNotExist:
|
||||
return Attendee.objects.create(user=user)
|
||||
|
||||
user = models.OneToOneField(User, on_delete=models.CASCADE)
|
||||
# Badge/profile is linked
|
||||
|
@ -54,6 +52,19 @@ class AttendeeProfileBase(models.Model):
|
|||
speaker profile. If it's None, that functionality is disabled. '''
|
||||
return None
|
||||
|
||||
def invoice_recipient(self):
|
||||
''' Returns a representation of this attendee profile for the purpose
|
||||
of rendering to an invoice. Override in subclasses. '''
|
||||
|
||||
# Manual dispatch to subclass. Fleh.
|
||||
slf = AttendeeProfileBase.objects.get_subclass(id=self.id)
|
||||
# Actually compare the functions.
|
||||
if type(slf).invoice_recipient != type(self).invoice_recipient:
|
||||
return type(slf).invoice_recipient(slf)
|
||||
|
||||
# Return a default
|
||||
return slf.attendee.user.username
|
||||
|
||||
attendee = models.OneToOneField(Attendee, on_delete=models.CASCADE)
|
||||
|
||||
|
||||
|
@ -533,6 +544,18 @@ class Invoice(models.Model):
|
|||
''' An invoice. Invoices can be automatically generated when checking out
|
||||
a Cart, in which case, it is attached to a given revision of a Cart. '''
|
||||
|
||||
STATUS_UNPAID = 1
|
||||
STATUS_PAID = 2
|
||||
STATUS_REFUNDED = 3
|
||||
STATUS_VOID = 4
|
||||
|
||||
STATUS_TYPES = [
|
||||
(STATUS_UNPAID, _("Unpaid")),
|
||||
(STATUS_PAID, _("Paid")),
|
||||
(STATUS_REFUNDED, _("Refunded")),
|
||||
(STATUS_VOID, _("VOID")),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return "Invoice #%d" % self.id
|
||||
|
||||
|
@ -541,13 +564,37 @@ class Invoice(models.Model):
|
|||
raise ValidationError(
|
||||
"If this is a cart invoice, it must have a revision")
|
||||
|
||||
@property
|
||||
def is_unpaid(self):
|
||||
return self.status == self.STATUS_UNPAID
|
||||
|
||||
@property
|
||||
def is_void(self):
|
||||
return self.status == self.STATUS_VOID
|
||||
|
||||
@property
|
||||
def is_paid(self):
|
||||
return self.status == self.STATUS_PAID
|
||||
|
||||
@property
|
||||
def is_refunded(self):
|
||||
return self.status == self.STATUS_REFUNDED
|
||||
|
||||
# Invoice Number
|
||||
user = models.ForeignKey(User)
|
||||
cart = models.ForeignKey(Cart, null=True)
|
||||
cart_revision = models.IntegerField(null=True)
|
||||
cart_revision = models.IntegerField(
|
||||
null=True,
|
||||
db_index=True,
|
||||
)
|
||||
# Line Items (foreign key)
|
||||
void = models.BooleanField(default=False)
|
||||
paid = models.BooleanField(default=False)
|
||||
status = models.IntegerField(
|
||||
choices=STATUS_TYPES,
|
||||
db_index=True,
|
||||
)
|
||||
recipient = models.CharField(max_length=1024)
|
||||
issue_time = models.DateTimeField()
|
||||
due_time = models.DateTimeField()
|
||||
value = models.DecimalField(max_digits=8, decimal_places=2)
|
||||
|
||||
|
||||
|
@ -565,17 +612,25 @@ class LineItem(models.Model):
|
|||
description = models.CharField(max_length=255)
|
||||
quantity = models.PositiveIntegerField()
|
||||
price = models.DecimalField(max_digits=8, decimal_places=2)
|
||||
product = models.ForeignKey(Product, null=True, blank=True)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Payment(models.Model):
|
||||
''' A payment for an invoice. Each invoice can have multiple payments
|
||||
attached to it.'''
|
||||
class PaymentBase(models.Model):
|
||||
''' The base payment type for invoices. Payment apps should subclass this
|
||||
class to handle implementation-specific issues. '''
|
||||
|
||||
objects = InheritanceManager()
|
||||
|
||||
def __str__(self):
|
||||
return "Payment: ref=%s amount=%s" % (self.reference, self.amount)
|
||||
|
||||
invoice = models.ForeignKey(Invoice)
|
||||
time = models.DateTimeField(default=timezone.now)
|
||||
reference = models.CharField(max_length=64)
|
||||
reference = models.CharField(max_length=255)
|
||||
amount = models.DecimalField(max_digits=8, decimal_places=2)
|
||||
|
||||
|
||||
class ManualPayment(PaymentBase):
|
||||
''' Payments that are manually entered by staff. '''
|
||||
pass
|
||||
|
|
|
@ -3,6 +3,7 @@ from registrasion.controllers.invoice import InvoiceController
|
|||
from registrasion import models as rego
|
||||
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
|
||||
class TestingCartController(CartController):
|
||||
|
@ -32,4 +33,27 @@ class TestingCartController(CartController):
|
|||
|
||||
|
||||
class TestingInvoiceController(InvoiceController):
|
||||
pass
|
||||
|
||||
def pay(self, reference, amount):
|
||||
''' Testing method for simulating an invoice paymenht by the given
|
||||
amount. '''
|
||||
if self.invoice.cart:
|
||||
cart = CartController(self.invoice.cart)
|
||||
cart.validate_cart() # Raises ValidationError if invalid
|
||||
|
||||
status = self.invoice.status
|
||||
if status == rego.Invoice.STATUS_VOID:
|
||||
raise ValidationError("Void invoices cannot be paid")
|
||||
elif status == rego.Invoice.STATUS_PAID:
|
||||
raise ValidationError("Paid invoices cannot be paid again")
|
||||
elif status == rego.Invoice.STATUS_REFUNDED:
|
||||
raise ValidationError("Refunded invoices cannot be paid")
|
||||
|
||||
''' Adds a payment '''
|
||||
payment = rego.ManualPayment.objects.create(
|
||||
invoice=self.invoice,
|
||||
reference=reference,
|
||||
amount=amount,
|
||||
)
|
||||
|
||||
self.update_status()
|
||||
|
|
|
@ -35,8 +35,8 @@ class InvoiceTestCase(RegistrationCartTestCase):
|
|||
# The old invoice should automatically be voided
|
||||
invoice_1_new = rego.Invoice.objects.get(pk=invoice_1.invoice.id)
|
||||
invoice_2_new = rego.Invoice.objects.get(pk=invoice_2.invoice.id)
|
||||
self.assertTrue(invoice_1_new.void)
|
||||
self.assertFalse(invoice_2_new.void)
|
||||
self.assertTrue(invoice_1_new.is_void)
|
||||
self.assertFalse(invoice_2_new.is_void)
|
||||
|
||||
# Invoice should have two line items
|
||||
line_items = rego.LineItem.objects.filter(invoice=invoice_2.invoice)
|
||||
|
@ -68,7 +68,7 @@ class InvoiceTestCase(RegistrationCartTestCase):
|
|||
invoice.pay("A payment!", invoice.invoice.value)
|
||||
|
||||
# This payment is for the correct amount invoice should be paid.
|
||||
self.assertTrue(invoice.invoice.paid)
|
||||
self.assertTrue(invoice.invoice.is_paid)
|
||||
|
||||
# Cart should not be active
|
||||
self.assertFalse(invoice.invoice.cart.active)
|
||||
|
@ -133,7 +133,7 @@ class InvoiceTestCase(RegistrationCartTestCase):
|
|||
current_cart.add_to_cart(self.PROD_1, 1)
|
||||
invoice_1 = TestingInvoiceController.for_cart(current_cart.cart)
|
||||
|
||||
self.assertTrue(invoice_1.invoice.paid)
|
||||
self.assertTrue(invoice_1.invoice.is_paid)
|
||||
|
||||
def test_invoice_voids_self_if_cart_is_invalid(self):
|
||||
current_cart = TestingCartController.for_user(self.USER_1)
|
||||
|
@ -142,7 +142,7 @@ class InvoiceTestCase(RegistrationCartTestCase):
|
|||
current_cart.add_to_cart(self.PROD_1, 1)
|
||||
invoice_1 = TestingInvoiceController.for_cart(current_cart.cart)
|
||||
|
||||
self.assertFalse(invoice_1.invoice.void)
|
||||
self.assertFalse(invoice_1.invoice.is_void)
|
||||
|
||||
# Adding item to cart should produce a new invoice
|
||||
current_cart.add_to_cart(self.PROD_2, 1)
|
||||
|
@ -151,11 +151,11 @@ class InvoiceTestCase(RegistrationCartTestCase):
|
|||
|
||||
# Viewing invoice_1's invoice should show it as void
|
||||
invoice_1_new = TestingInvoiceController(invoice_1.invoice)
|
||||
self.assertTrue(invoice_1_new.invoice.void)
|
||||
self.assertTrue(invoice_1_new.invoice.is_void)
|
||||
|
||||
# Viewing invoice_2's invoice should *not* show it as void
|
||||
invoice_2_new = TestingInvoiceController(invoice_2.invoice)
|
||||
self.assertFalse(invoice_2_new.invoice.void)
|
||||
self.assertFalse(invoice_2_new.invoice.is_void)
|
||||
|
||||
def test_voiding_invoice_creates_new_invoice(self):
|
||||
current_cart = TestingCartController.for_user(self.USER_1)
|
||||
|
@ -164,7 +164,7 @@ class InvoiceTestCase(RegistrationCartTestCase):
|
|||
current_cart.add_to_cart(self.PROD_1, 1)
|
||||
invoice_1 = TestingInvoiceController.for_cart(current_cart.cart)
|
||||
|
||||
self.assertFalse(invoice_1.invoice.void)
|
||||
self.assertFalse(invoice_1.invoice.is_void)
|
||||
invoice_1.void()
|
||||
|
||||
invoice_2 = TestingInvoiceController.for_cart(current_cart.cart)
|
||||
|
|
|
@ -18,11 +18,13 @@ class RefundTestCase(RegistrationCartTestCase):
|
|||
invoice = TestingInvoiceController.for_cart(current_cart.cart)
|
||||
|
||||
invoice.pay("A Payment!", invoice.invoice.value)
|
||||
self.assertFalse(invoice.invoice.void)
|
||||
self.assertTrue(invoice.invoice.paid)
|
||||
self.assertFalse(invoice.invoice.is_void)
|
||||
self.assertTrue(invoice.invoice.is_paid)
|
||||
self.assertFalse(invoice.invoice.is_refunded)
|
||||
self.assertFalse(invoice.invoice.cart.released)
|
||||
|
||||
invoice.refund("A Refund!", invoice.invoice.value)
|
||||
self.assertTrue(invoice.invoice.void)
|
||||
self.assertFalse(invoice.invoice.paid)
|
||||
self.assertFalse(invoice.invoice.is_void)
|
||||
self.assertFalse(invoice.invoice.is_paid)
|
||||
self.assertTrue(invoice.invoice.is_refunded)
|
||||
self.assertTrue(invoice.invoice.cart.released)
|
||||
|
|
|
@ -141,7 +141,7 @@ class VoucherTestCases(RegistrationCartTestCase):
|
|||
current_cart.add_to_cart(self.PROD_1, 1)
|
||||
|
||||
inv = TestingInvoiceController.for_cart(current_cart.cart)
|
||||
if not inv.invoice.paid:
|
||||
if not inv.invoice.is_paid:
|
||||
inv.pay("Hello!", inv.invoice.value)
|
||||
|
||||
current_cart = TestingCartController.for_user(self.USER_1)
|
||||
|
|
Loading…
Reference in a new issue