Changeset - 8ad265a65a08
[Not reviewed]
0 4 0
Christopher Neugebauer - 8 years ago 2016-04-06 07:19:09
chrisjrn@gmail.com
Fixes tests now that $0 invoices pay themselves
4 files changed with 46 insertions and 16 deletions:
0 comments (0 inline, 0 general)
registrasion/controllers/invoice.py
Show inline comments
 
from decimal import Decimal
 
from django.core.exceptions import ObjectDoesNotExist
 
from django.core.exceptions import ValidationError
 
from django.db import transaction
 
from django.db.models import Sum
 

	
 
from registrasion import models as rego
 

	
 
from cart import CartController
 

	
 

	
 
class InvoiceController(object):
 

	
 
    def __init__(self, invoice):
 
        self.invoice = invoice
 
        self.update_validity()  # Make sure this invoice is up-to-date
 

	
 
    @classmethod
 
    def for_cart(cls, cart):
 
        ''' Returns an invoice object for a given cart at its current revision.
 
        If such an invoice does not exist, the cart is validated, and if valid,
 
        an invoice is generated.'''
 

	
 
        try:
 
            invoice = rego.Invoice.objects.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)
 

	
 
            invoice = cls._generate(cart)
 

	
 
        return InvoiceController(invoice)
 

	
 
    @classmethod
 
    def resolve_discount_value(cls, item):
 
        try:
 
            condition = rego.DiscountForProduct.objects.get(
 
                discount=item.discount,
 
                product=item.product
 
            )
 
        except ObjectDoesNotExist:
 
            condition = rego.DiscountForCategory.objects.get(
 
                discount=item.discount,
 
                category=item.product.category
 
            )
 
        if condition.percentage is not None:
 
            value = item.product.price * (condition.percentage / 100)
 
        else:
 
            value = condition.price
 
        return value
 

	
 
    @classmethod
 
    @transaction.atomic
 
    def _generate(cls, cart):
 
        ''' Generates an invoice for the given cart. '''
 
        invoice = rego.Invoice.objects.create(
 
            user=cart.user,
 
            cart=cart,
 
            cart_revision=cart.revision,
 
            value=Decimal()
 
        )
 
        invoice.save()
 

	
 
        product_items = rego.ProductItem.objects.filter(cart=cart)
 

	
 
        if len(product_items) == 0:
 
            raise ValidationError("Your cart is empty.")
 

	
 
        product_items = product_items.order_by(
 
            "product__category__order", "product__order"
 
        )
 
        discount_items = rego.DiscountItem.objects.filter(cart=cart)
 
        invoice_value = Decimal()
 
        for item in product_items:
 
            product = item.product
 
            line_item = rego.LineItem.objects.create(
 
                invoice=invoice,
 
                description="%s - %s" % (product.category.name, product.name),
 
                quantity=item.quantity,
 
                price=product.price,
 
            )
 
            line_item.save()
 
            invoice_value += line_item.quantity * line_item.price
 

	
 
        for item in discount_items:
 
            line_item = rego.LineItem.objects.create(
 
                invoice=invoice,
 
                description=item.discount.description,
 
                quantity=item.quantity,
 
                price=cls.resolve_discount_value(item) * -1,
 
            )
 
            line_item.save()
 
            invoice_value += line_item.quantity * line_item.price
 

	
 
        # TODO: calculate line items from discounts
 
        invoice.value = invoice_value
 

	
 
        if invoice.value == 0:
 
            invoice.paid = True
 

	
 
        invoice.save()
 

	
 
        return invoice
 

	
 
    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()
 

	
 
    def void(self):
 
        ''' Voids the invoice if it is valid to do so. '''
 
        if self.invoice.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()
 

	
 
    @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.
 
        '''
 

	
 
        if self.invoice.void:
 
            raise ValidationError("Void invoices cannot be refunded")
 

	
 
        ''' Adds a payment '''
 
        payment = rego.Payment.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()
registrasion/tests/test_discount.py
Show inline comments
...
 
@@ -253,163 +253,161 @@ class DiscountTestCase(RegistrationCartTestCase):
 
    def test_enumerate_no_discounts_for_no_input(self):
 
        discounts = discount.available_discounts(self.USER_1, [], [])
 
        self.assertEqual(0, len(discounts))
 

	
 
    def test_enumerate_no_discounts_if_condition_not_met(self):
 
        self.add_discount_prod_1_includes_cat_2(quantity=1)
 

	
 
        discounts = discount.available_discounts(
 
            self.USER_1,
 
            [],
 
            [self.PROD_3],
 
        )
 
        self.assertEqual(0, len(discounts))
 

	
 
        discounts = discount.available_discounts(self.USER_1, [self.CAT_2], [])
 
        self.assertEqual(0, len(discounts))
 

	
 
    def test_category_discount_appears_once_if_met_twice(self):
 
        self.add_discount_prod_1_includes_cat_2(quantity=1)
 

	
 
        cart = TestingCartController.for_user(self.USER_1)
 
        cart.add_to_cart(self.PROD_1, 1)  # Enable the discount
 

	
 
        discounts = discount.available_discounts(
 
            self.USER_1,
 
            [self.CAT_2],
 
            [self.PROD_3],
 
        )
 
        self.assertEqual(1, len(discounts))
 

	
 
    def test_category_discount_appears_with_category(self):
 
        self.add_discount_prod_1_includes_cat_2(quantity=1)
 

	
 
        cart = TestingCartController.for_user(self.USER_1)
 
        cart.add_to_cart(self.PROD_1, 1)  # Enable the discount
 

	
 
        discounts = discount.available_discounts(self.USER_1, [self.CAT_2], [])
 
        self.assertEqual(1, len(discounts))
 

	
 
    def test_category_discount_appears_with_product(self):
 
        self.add_discount_prod_1_includes_cat_2(quantity=1)
 

	
 
        cart = TestingCartController.for_user(self.USER_1)
 
        cart.add_to_cart(self.PROD_1, 1)  # Enable the discount
 

	
 
        discounts = discount.available_discounts(
 
            self.USER_1,
 
            [],
 
            [self.PROD_3],
 
        )
 
        self.assertEqual(1, len(discounts))
 

	
 
    def test_category_discount_appears_once_with_two_valid_product(self):
 
        self.add_discount_prod_1_includes_cat_2(quantity=1)
 

	
 
        cart = TestingCartController.for_user(self.USER_1)
 
        cart.add_to_cart(self.PROD_1, 1)  # Enable the discount
 

	
 
        discounts = discount.available_discounts(
 
            self.USER_1,
 
            [],
 
            [self.PROD_3, self.PROD_4]
 
        )
 
        self.assertEqual(1, len(discounts))
 

	
 
    def test_product_discount_appears_with_product(self):
 
        self.add_discount_prod_1_includes_prod_2(quantity=1)
 

	
 
        cart = TestingCartController.for_user(self.USER_1)
 
        cart.add_to_cart(self.PROD_1, 1)  # Enable the discount
 

	
 
        discounts = discount.available_discounts(
 
            self.USER_1,
 
            [],
 
            [self.PROD_2],
 
        )
 
        self.assertEqual(1, len(discounts))
 

	
 
    def test_product_discount_does_not_appear_with_category(self):
 
        self.add_discount_prod_1_includes_prod_2(quantity=1)
 

	
 
        cart = TestingCartController.for_user(self.USER_1)
 
        cart.add_to_cart(self.PROD_1, 1)  # Enable the discount
 

	
 
        discounts = discount.available_discounts(self.USER_1, [self.CAT_1], [])
 
        self.assertEqual(0, len(discounts))
 

	
 
    def test_discount_quantity_is_correct_before_first_purchase(self):
 
        self.add_discount_prod_1_includes_cat_2(quantity=2)
 

	
 
        cart = TestingCartController.for_user(self.USER_1)
 
        cart.add_to_cart(self.PROD_1, 1)  # Enable the discount
 
        cart.add_to_cart(self.PROD_3, 1)  # Exhaust the quantity
 

	
 
        discounts = discount.available_discounts(self.USER_1, [self.CAT_2], [])
 
        self.assertEqual(2, discounts[0].quantity)
 
        inv = InvoiceController.for_cart(cart.cart)
 
        inv.pay("Dummy reference", inv.invoice.value)
 
        self.assertTrue(inv.invoice.paid)
 
        cart.cart.active = False
 
        cart.cart.save()
 

	
 
    def test_discount_quantity_is_correct_after_first_purchase(self):
 
        self.test_discount_quantity_is_correct_before_first_purchase()
 

	
 
        cart = TestingCartController.for_user(self.USER_1)
 
        cart.add_to_cart(self.PROD_3, 1)  # Exhaust the quantity
 

	
 
        discounts = discount.available_discounts(self.USER_1, [self.CAT_2], [])
 
        self.assertEqual(1, discounts[0].quantity)
 
        inv = InvoiceController.for_cart(cart.cart)
 
        inv.pay("Dummy reference", inv.invoice.value)
 
        self.assertTrue(inv.invoice.paid)
 
        cart.cart.active = False
 
        cart.cart.save()
 

	
 
    def test_discount_is_gone_after_quantity_exhausted(self):
 
        self.test_discount_quantity_is_correct_after_first_purchase()
 
        discounts = discount.available_discounts(self.USER_1, [self.CAT_2], [])
 
        self.assertEqual(0, len(discounts))
 

	
 
    def test_product_discount_enabled_twice_appears_twice(self):
 
        self.add_discount_prod_1_includes_prod_3_and_prod_4(quantity=2)
 
        cart = TestingCartController.for_user(self.USER_1)
 
        cart.add_to_cart(self.PROD_1, 1)  # Enable the discount
 
        discounts = discount.available_discounts(
 
            self.USER_1,
 
            [],
 
            [self.PROD_3, self.PROD_4],
 
        )
 
        self.assertEqual(2, len(discounts))
 

	
 
    def test_discounts_are_released_by_refunds(self):
 
        self.add_discount_prod_1_includes_prod_2(quantity=2)
 
        cart = TestingCartController.for_user(self.USER_1)
 
        cart.add_to_cart(self.PROD_1, 1)  # Enable the discount
 
        discounts = discount.available_discounts(
 
            self.USER_1,
 
            [],
 
            [self.PROD_2],
 
        )
 
        self.assertEqual(1, len(discounts))
 

	
 
        cart.cart.active = False  # Keep discount enabled
 
        cart.cart.save()
 

	
 
        cart = TestingCartController.for_user(self.USER_1)
 
        cart.add_to_cart(self.PROD_2, 2)  # The discount will be exhausted
 
        cart.cart.active = False
 
        cart.cart.save()
 

	
 
        discounts = discount.available_discounts(
 
            self.USER_1,
 
            [],
 
            [self.PROD_2],
 
        )
 
        self.assertEqual(0, len(discounts))
 

	
 
        cart.cart.released = True
 
        cart.cart.save()
 

	
 
        discounts = discount.available_discounts(
 
            self.USER_1,
 
            [],
 
            [self.PROD_2],
 
        )
 
        self.assertEqual(1, len(discounts))
registrasion/tests/test_invoice.py
Show inline comments
 
import datetime
 
import pytz
 

	
 
from decimal import Decimal
 
from django.core.exceptions import ValidationError
 

	
 
from registrasion import models as rego
 
from cart_controller_helper import TestingCartController
 
from registrasion.controllers.invoice import InvoiceController
 

	
 
from test_cart import RegistrationCartTestCase
 

	
 
UTC = pytz.timezone('UTC')
 

	
 

	
 
class InvoiceTestCase(RegistrationCartTestCase):
 

	
 
    def test_create_invoice(self):
 
        current_cart = TestingCartController.for_user(self.USER_1)
 

	
 
        # Should be able to create an invoice after the product is added
 
        current_cart.add_to_cart(self.PROD_1, 1)
 
        invoice_1 = InvoiceController.for_cart(current_cart.cart)
 
        # That invoice should have a single line item
 
        line_items = rego.LineItem.objects.filter(invoice=invoice_1.invoice)
 
        self.assertEqual(1, len(line_items))
 
        # That invoice should have a value equal to cost of PROD_1
 
        self.assertEqual(self.PROD_1.price, invoice_1.invoice.value)
 

	
 
        # Adding item to cart should produce a new invoice
 
        current_cart.add_to_cart(self.PROD_2, 1)
 
        invoice_2 = InvoiceController.for_cart(current_cart.cart)
 
        self.assertNotEqual(invoice_1.invoice, invoice_2.invoice)
 

	
 
        # 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)
 

	
 
        # Invoice should have two line items
 
        line_items = rego.LineItem.objects.filter(invoice=invoice_2.invoice)
 
        self.assertEqual(2, len(line_items))
 
        # Invoice should have a value equal to cost of PROD_1 and PROD_2
 
        self.assertEqual(
 
            self.PROD_1.price + self.PROD_2.price,
 
            invoice_2.invoice.value)
 

	
 
    def test_create_invoice_fails_if_cart_invalid(self):
 
        self.make_ceiling("Limit ceiling", limit=1)
 
        self.set_time(datetime.datetime(2015, 01, 01, tzinfo=UTC))
 
        current_cart = TestingCartController.for_user(self.USER_1)
 
        current_cart.add_to_cart(self.PROD_1, 1)
 

	
 
        self.add_timedelta(self.RESERVATION * 2)
 
        cart_2 = TestingCartController.for_user(self.USER_2)
 
        cart_2.add_to_cart(self.PROD_1, 1)
 

	
 
        # Now try to invoice the first user
 
        with self.assertRaises(ValidationError):
 
            InvoiceController.for_cart(current_cart.cart)
 

	
 
    def test_paying_invoice_makes_new_cart(self):
 
        current_cart = TestingCartController.for_user(self.USER_1)
 
        current_cart.add_to_cart(self.PROD_1, 1)
 

	
 
        invoice = InvoiceController.for_cart(current_cart.cart)
 
        invoice.pay("A payment!", invoice.invoice.value)
 

	
 
        # This payment is for the correct amount invoice should be paid.
 
        self.assertTrue(invoice.invoice.paid)
 

	
 
        # Cart should not be active
 
        self.assertFalse(invoice.invoice.cart.active)
 

	
 
        # Asking for a cart should generate a new one
 
        new_cart = TestingCartController.for_user(self.USER_1)
 
        self.assertNotEqual(current_cart.cart, new_cart.cart)
 

	
 
    def test_invoice_includes_discounts(self):
 
        voucher = rego.Voucher.objects.create(
 
            recipient="Voucher recipient",
 
            code="VOUCHER",
 
            limit=1
 
        )
 
        voucher.save()
 
        discount = rego.VoucherDiscount.objects.create(
 
            description="VOUCHER RECIPIENT",
 
            voucher=voucher,
 
        )
 
        discount.save()
 
        rego.DiscountForProduct.objects.create(
 
            discount=discount,
 
            product=self.PROD_1,
 
            percentage=Decimal(50),
 
            quantity=1
 
        ).save()
 
        )
 

	
 
        current_cart = TestingCartController.for_user(self.USER_1)
 
        current_cart.apply_voucher(voucher.code)
 

	
 
        # Should be able to create an invoice after the product is added
 
        current_cart.add_to_cart(self.PROD_1, 1)
 
        invoice_1 = InvoiceController.for_cart(current_cart.cart)
 

	
 
        # That invoice should have two line items
 
        line_items = rego.LineItem.objects.filter(invoice=invoice_1.invoice)
 
        self.assertEqual(2, len(line_items))
 
        # That invoice should have a value equal to 50% of the cost of PROD_1
 
        self.assertEqual(
 
            self.PROD_1.price * Decimal("0.5"),
 
            invoice_1.invoice.value)
 

	
 
    def test_zero_value_invoice_is_automatically_paid(self):
 
        voucher = rego.Voucher.objects.create(
 
            recipient="Voucher recipient",
 
            code="VOUCHER",
 
            limit=1
 
        )
 
        discount = rego.VoucherDiscount.objects.create(
 
            description="VOUCHER RECIPIENT",
 
            voucher=voucher,
 
        )
 
        rego.DiscountForProduct.objects.create(
 
            discount=discount,
 
            product=self.PROD_1,
 
            percentage=Decimal(100),
 
            quantity=1
 
        )
 

	
 
        current_cart = TestingCartController.for_user(self.USER_1)
 
        current_cart.apply_voucher(voucher.code)
 

	
 
        # Should be able to create an invoice after the product is added
 
        current_cart.add_to_cart(self.PROD_1, 1)
 
        invoice_1 = InvoiceController.for_cart(current_cart.cart)
 

	
 
        self.assertTrue(invoice_1.invoice.paid)
 

	
 
    def test_invoice_voids_self_if_cart_is_invalid(self):
 
        current_cart = TestingCartController.for_user(self.USER_1)
 

	
 
        # Should be able to create an invoice after the product is added
 
        current_cart.add_to_cart(self.PROD_1, 1)
 
        invoice_1 = InvoiceController.for_cart(current_cart.cart)
 

	
 
        self.assertFalse(invoice_1.invoice.void)
 

	
 
        # Adding item to cart should produce a new invoice
 
        current_cart.add_to_cart(self.PROD_2, 1)
 
        invoice_2 = InvoiceController.for_cart(current_cart.cart)
 
        self.assertNotEqual(invoice_1.invoice, invoice_2.invoice)
 

	
 
        # Viewing invoice_1's invoice should show it as void
 
        invoice_1_new = InvoiceController(invoice_1.invoice)
 
        self.assertTrue(invoice_1_new.invoice.void)
 

	
 
        # Viewing invoice_2's invoice should *not* show it as void
 
        invoice_2_new = InvoiceController(invoice_2.invoice)
 
        self.assertFalse(invoice_2_new.invoice.void)
 

	
 
    def test_voiding_invoice_creates_new_invoice(self):
 
        current_cart = TestingCartController.for_user(self.USER_1)
 

	
 
        # Should be able to create an invoice after the product is added
 
        current_cart.add_to_cart(self.PROD_1, 1)
 
        invoice_1 = InvoiceController.for_cart(current_cart.cart)
 

	
 
        self.assertFalse(invoice_1.invoice.void)
 
        invoice_1.void()
 

	
 
        invoice_2 = InvoiceController.for_cart(current_cart.cart)
 
        self.assertNotEqual(invoice_1.invoice, invoice_2.invoice)
 

	
 
    def test_cannot_pay_void_invoice(self):
 
        current_cart = TestingCartController.for_user(self.USER_1)
 

	
 
        # Should be able to create an invoice after the product is added
 
        current_cart.add_to_cart(self.PROD_1, 1)
 
        invoice_1 = InvoiceController.for_cart(current_cart.cart)
 

	
 
        invoice_1.void()
 

	
 
        with self.assertRaises(ValidationError):
 
            invoice_1.pay("Reference", invoice_1.invoice.value)
 

	
 
    def test_cannot_void_paid_invoice(self):
 
        current_cart = TestingCartController.for_user(self.USER_1)
 

	
 
        # Should be able to create an invoice after the product is added
 
        current_cart.add_to_cart(self.PROD_1, 1)
 
        invoice_1 = InvoiceController.for_cart(current_cart.cart)
 

	
 
        invoice_1.pay("Reference", invoice_1.invoice.value)
 

	
 
        with self.assertRaises(ValidationError):
 
            invoice_1.void()
 

	
 
    def test_cannot_generate_blank_invoice(self):
 
        current_cart = TestingCartController.for_user(self.USER_1)
 
        with self.assertRaises(ValidationError):
 
            invoice_1 = InvoiceController.for_cart(current_cart.cart)
registrasion/tests/test_voucher.py
Show inline comments
...
 
@@ -32,128 +32,130 @@ class VoucherTestCases(RegistrationCartTestCase):
 

	
 
        # After the reservation duration
 
        # user 2 should be able to apply voucher
 
        self.add_timedelta(rego.Voucher.RESERVATION_DURATION * 2)
 
        cart_2.apply_voucher(voucher.code)
 
        cart_2.cart.active = False
 
        cart_2.cart.save()
 

	
 
        # After the reservation duration, even though the voucher has applied,
 
        # it exceeds the number of vouchers available.
 
        self.add_timedelta(rego.Voucher.RESERVATION_DURATION * 2)
 
        with self.assertRaises(ValidationError):
 
            cart_1.validate_cart()
 

	
 
    def test_fix_simple_errors_resolves_unavailable_voucher(self):
 
        self.test_apply_voucher()
 

	
 
        # User has an exhausted voucher leftover from test_apply_voucher
 
        cart_1 = TestingCartController.for_user(self.USER_1)
 
        with self.assertRaises(ValidationError):
 
            cart_1.validate_cart()
 

	
 
        cart_1.fix_simple_errors()
 
        # This should work now.
 
        cart_1.validate_cart()
 

	
 
    def test_voucher_enables_item(self):
 
        voucher = self.new_voucher()
 

	
 
        enabling_condition = rego.VoucherEnablingCondition.objects.create(
 
            description="Voucher condition",
 
            voucher=voucher,
 
            mandatory=False,
 
        )
 
        enabling_condition.save()
 
        enabling_condition.products.add(self.PROD_1)
 
        enabling_condition.save()
 

	
 
        # Adding the product without a voucher will not work
 
        current_cart = TestingCartController.for_user(self.USER_1)
 
        with self.assertRaises(ValidationError):
 
            current_cart.add_to_cart(self.PROD_1, 1)
 

	
 
        # Apply the voucher
 
        current_cart.apply_voucher(voucher.code)
 
        current_cart.add_to_cart(self.PROD_1, 1)
 

	
 
    def test_voucher_enables_discount(self):
 
        voucher = self.new_voucher()
 

	
 
        discount = rego.VoucherDiscount.objects.create(
 
            description="VOUCHER RECIPIENT",
 
            voucher=voucher,
 
        )
 
        discount.save()
 
        rego.DiscountForProduct.objects.create(
 
            discount=discount,
 
            product=self.PROD_1,
 
            percentage=Decimal(100),
 
            quantity=1
 
        ).save()
 

	
 
        # Having PROD_1 in place should add a discount
 
        current_cart = TestingCartController.for_user(self.USER_1)
 
        current_cart.apply_voucher(voucher.code)
 
        current_cart.add_to_cart(self.PROD_1, 1)
 
        self.assertEqual(1, len(current_cart.cart.discountitem_set.all()))
 

	
 
    def test_voucher_codes_unique(self):
 
        self.new_voucher(code="VOUCHER")
 
        with self.assertRaises(IntegrityError):
 
            self.new_voucher(code="VOUCHER")
 

	
 
    def test_multiple_vouchers_work(self):
 
        self.new_voucher(code="VOUCHER1")
 
        self.new_voucher(code="VOUCHER2")
 

	
 
    def test_vouchers_case_insensitive(self):
 
        voucher = self.new_voucher(code="VOUCHeR")
 
        current_cart = TestingCartController.for_user(self.USER_1)
 
        current_cart.apply_voucher(voucher.code.lower())
 

	
 
    def test_voucher_can_only_be_applied_once(self):
 
        voucher = self.new_voucher(limit=2)
 
        current_cart = TestingCartController.for_user(self.USER_1)
 
        current_cart.apply_voucher(voucher.code)
 
        current_cart.apply_voucher(voucher.code)
 

	
 
        # You can apply the code twice, but it will only add to the cart once.
 
        self.assertEqual(1, current_cart.cart.vouchers.count())
 

	
 
    def test_voucher_can_only_be_applied_once_across_multiple_carts(self):
 
        voucher = self.new_voucher(limit=2)
 
        current_cart = TestingCartController.for_user(self.USER_1)
 
        current_cart.apply_voucher(voucher.code)
 

	
 
        inv = InvoiceController.for_cart(current_cart.cart)
 
        inv.pay("Hello!", inv.invoice.value)
 
        current_cart.cart.active = False
 
        current_cart.cart.save()
 

	
 
        current_cart = TestingCartController.for_user(self.USER_1)
 

	
 
        with self.assertRaises(ValidationError):
 
            current_cart.apply_voucher(voucher.code)
 

	
 
        return current_cart
 

	
 
    def test_refund_releases_used_vouchers(self):
 
        voucher = self.new_voucher(limit=2)
 
        current_cart = TestingCartController.for_user(self.USER_1)
 
        current_cart.apply_voucher(voucher.code)
 
        current_cart.add_to_cart(self.PROD_1, 1)
 

	
 
        inv = InvoiceController.for_cart(current_cart.cart)
 
        inv.pay("Hello!", inv.invoice.value)
 
        if not inv.invoice.paid:
 
            inv.pay("Hello!", inv.invoice.value)
 

	
 
        current_cart = TestingCartController.for_user(self.USER_1)
 
        with self.assertRaises(ValidationError):
 
            current_cart.apply_voucher(voucher.code)
 

	
 
        inv.refund("Hello!", inv.invoice.value)
 
        current_cart.apply_voucher(voucher.code)
 

	
 
    def test_fix_simple_errors_does_not_remove_limited_voucher(self):
 
        voucher = self.new_voucher(code="VOUCHER")
 
        current_cart = TestingCartController.for_user(self.USER_1)
 
        current_cart.apply_voucher(voucher.code)
 

	
 
        current_cart.fix_simple_errors()
 
        self.assertEqual(1, current_cart.cart.vouchers.count())
0 comments (0 inline, 0 general)