Changeset - c2400c4695ae
[Not reviewed]
4 6 5
Christopher Neugebauer - 9 years ago 2016-01-22 05:29:41
chrisjrn@gmail.com
Moves the controller modules into their own subpackage. There's going to be a lot of stuff in there.
11 files changed with 8 insertions and 8 deletions:
0 comments (0 inline, 0 general)
registrasion/controllers/__init__.py
Show inline comments
 
new file 100644
registrasion/controllers/cart.py
Show inline comments
 
file renamed from registrasion/cart.py to registrasion/controllers/cart.py
 
import datetime
 
import itertools
 

	
 
from django.core.exceptions import ObjectDoesNotExist
 
from django.core.exceptions import ValidationError
 
from django.db.models import Avg, Min, Max, Sum
 
from django.utils import timezone
 

	
 
from registrasion import models as rego
 

	
 
from conditions import ConditionController
 
from controllers import ProductController
 
from product import ProductController
 

	
 

	
 
class CartController(object):
 

	
 
    def __init__(self, cart):
 
        self.cart = cart
 

	
 
    @staticmethod
 
    def for_user(user):
 
        ''' Returns the user's current cart, or creates a new cart
 
        if there isn't one ready yet. '''
 

	
 
        try:
 
            existing = rego.Cart.objects.get(user=user, active=True)
 
        except ObjectDoesNotExist:
 
            existing = rego.Cart.objects.create(
 
                user=user,
 
                time_last_updated=timezone.now(),
 
                reservation_duration=datetime.timedelta(),
 
                 )
 
            existing.save()
 
        return CartController(existing)
 

	
 

	
 
    def extend_reservation(self):
 
        ''' Updates the cart's time last updated value, which is used to
 
        determine whether the cart has reserved the items and discounts it
 
        holds. '''
 

	
 
        reservations = [datetime.timedelta()]
 

	
 
        # If we have vouchers, we're entitled to an hour at minimum.
 
        if len(self.cart.vouchers.all()) >= 1:
 
            reservations.append(rego.Voucher.RESERVATION_DURATION)
 

	
 
        # Else, it's the maximum of the included products
 
        items = rego.ProductItem.objects.filter(cart=self.cart)
 
        agg = items.aggregate(Max("product__reservation_duration"))
 
        product_max = agg["product__reservation_duration__max"]
 

	
 
        if product_max is not None:
 
            reservations.append(product_max)
 

	
 
        self.cart.time_last_updated = timezone.now()
 
        self.cart.reservation_duration = max(reservations)
 

	
 

	
 
    def add_to_cart(self, product, quantity):
 
        ''' Adds _quantity_ of the given _product_ to the cart. Raises
 
        ValidationError if constraints are violated.'''
 

	
 
        prod = ProductController(product)
 

	
 
        # TODO: Check enabling conditions for product for user
 

	
 
        if not prod.can_add_with_enabling_conditions(self.cart.user, quantity):
 
            raise ValidationError("Not enough of that product left (ec)")
 

	
 
        if not prod.user_can_add_within_limit(self.cart.user, quantity):
 
            raise ValidationError("Not enough of that product left (user)")
 

	
 
        try:
 
            # Try to update an existing item within this cart if possible.
 
            product_item = rego.ProductItem.objects.get(
 
                cart=self.cart,
 
                product=product)
 
            product_item.quantity += quantity
 
        except ObjectDoesNotExist:
 
            product_item = rego.ProductItem.objects.create(
 
                cart=self.cart,
 
                product=product,
 
                quantity=quantity,
 
            )
 
        product_item.save()
 

	
 
        self.recalculate_discounts()
 

	
 
        self.extend_reservation()
 
        self.cart.revision += 1
 
        self.cart.save()
 

	
 

	
 
    def apply_voucher(self, voucher):
 
        ''' Applies the given voucher to this cart. '''
 

	
 
        # TODO: is it valid for a cart to re-add a voucher that they have?
 

	
 
        # Is voucher exhausted?
 
        active_carts = rego.Cart.reserved_carts()
 
        carts_with_voucher = active_carts.filter(vouchers=voucher)
 
        if len(carts_with_voucher) >= voucher.limit:
 
            raise ValidationError("This voucher is no longer available")
 

	
 
        # If successful...
 
        self.cart.vouchers.add(voucher)
 

	
registrasion/controllers/conditions.py
Show inline comments
 
file renamed from registrasion/conditions.py to registrasion/controllers/conditions.py
registrasion/controllers/invoice.py
Show inline comments
 
file renamed from registrasion/invoice.py to registrasion/controllers/invoice.py
registrasion/controllers/product.py
Show inline comments
 
file renamed from registrasion/controllers.py to registrasion/controllers/product.py
registrasion/tests/test_cart.py
Show inline comments
 
import datetime
 
import pytz
 

	
 
from decimal import Decimal
 
from django.contrib.auth.models import User
 
from django.core.exceptions import ValidationError
 
from django.test import TestCase
 
from django.utils import timezone
 

	
 
from registrasion import models as rego
 
from registrasion.cart import CartController
 
from registrasion.controllers.cart import CartController
 

	
 
from patch_datetime import SetTimeMixin
 

	
 
UTC = pytz.timezone('UTC')
 

	
 
class RegistrationCartTestCase(SetTimeMixin, TestCase):
 

	
 
    def setUp(self):
 
        super(RegistrationCartTestCase, self).setUp()
 

	
 
    @classmethod
 
    def setUpTestData(cls):
 
        cls.USER_1 = User.objects.create_user(username='testuser',
 
            email='test@example.com', password='top_secret')
 

	
 
        cls.USER_2 = User.objects.create_user(username='testuser2',
 
            email='test2@example.com', password='top_secret')
 

	
 
        cls.CAT_1 = rego.Category.objects.create(
 
            name="Category 1",
 
            description="This is a test category",
 
            order=10,
 
            render_type=rego.Category.RENDER_TYPE_RADIO,
 
        )
 
        cls.CAT_1.save()
 

	
 
        cls.CAT_2 = rego.Category.objects.create(
 
            name="Category 2",
 
            description="This is a test category",
 
            order=10,
 
            render_type=rego.Category.RENDER_TYPE_RADIO,
 
        )
 
        cls.CAT_2.save()
 

	
 
        cls.RESERVATION = datetime.timedelta(hours=1)
 

	
 
        cls.PROD_1 = rego.Product.objects.create(
 
            name="Product 1",
 
            description= "This is a test product. It costs $10. " \
 
                "A user may have 10 of them.",
 
            category=cls.CAT_1,
 
            price=Decimal("10.00"),
 
            reservation_duration=cls.RESERVATION,
 
            limit_per_user=10,
 
            order=10,
 
        )
 
        cls.PROD_1.save()
 

	
 
        cls.PROD_2 = rego.Product.objects.create(
 
            name="Product 2",
 
            description= "This is a test product. It costs $10. " \
 
                "A user may have 10 of them.",
 
            category=cls.CAT_1,
 
            price=Decimal("10.00"),
 
            limit_per_user=10,
 
            order=10,
 
        )
 
        cls.PROD_2.save()
 

	
 
        cls.PROD_3 = rego.Product.objects.create(
 
            name="Product 3",
 
            description= "This is a test product. It costs $10. " \
 
                "A user may have 10 of them.",
 
            category=cls.CAT_2,
 
            price=Decimal("10.00"),
 
            limit_per_user=10,
 
            order=10,
 
        )
 
        cls.PROD_2.save()
 

	
 

	
 
    @classmethod
 
    def make_ceiling(cls, name, limit=None, start_time=None, end_time=None):
 
        limit_ceiling = rego.TimeOrStockLimitEnablingCondition.objects.create(
 
            description=name,
 
            mandatory=True,
 
            limit=limit,
 
            start_time=start_time,
 
            end_time=end_time
 
        )
 
        limit_ceiling.save()
 
        limit_ceiling.products.add(cls.PROD_1, cls.PROD_2)
 
        limit_ceiling.save()
 

	
 

	
 
    @classmethod
 
    def make_category_ceiling(cls, name, limit=None, start_time=None, end_time=None):
 
        limit_ceiling = rego.TimeOrStockLimitEnablingCondition.objects.create(
 
            description=name,
 
            mandatory=True,
 
            limit=limit,
 
            start_time=start_time,
 
            end_time=end_time
 
        )
 
        limit_ceiling.save()
 
        limit_ceiling.categories.add(cls.CAT_1)
registrasion/tests/test_ceilings.py
Show inline comments
 
import datetime
 
import pytz
 

	
 
from decimal import Decimal
 
from django.contrib.auth.models import User
 
from django.core.exceptions import ValidationError
 
from django.test import TestCase
 
from django.utils import timezone
 

	
 
from registrasion import models as rego
 
from registrasion.cart import CartController
 
from registrasion.controllers.cart import CartController
 

	
 
from test_cart import RegistrationCartTestCase
 

	
 
UTC = pytz.timezone('UTC')
 

	
 
class CeilingsTestCases(RegistrationCartTestCase):
 

	
 
    def test_add_to_cart_ceiling_limit(self):
 
        self.make_ceiling("Limit ceiling", limit=9)
 
        self.__add_to_cart_test()
 

	
 
    def test_add_to_cart_ceiling_category_limit(self):
 
        self.make_category_ceiling("Limit ceiling", limit=9)
 
        self.__add_to_cart_test()
 

	
 
    def __add_to_cart_test(self):
 

	
 
        current_cart = CartController.for_user(self.USER_1)
 

	
 
        # User should not be able to add 10 of PROD_1 to the current cart
 
        # because it is affected by limit_ceiling
 
        with self.assertRaises(ValidationError):
 
            current_cart.add_to_cart(self.PROD_2, 10)
 

	
 
        # User should be able to add 5 of PROD_1 to the current cart
 
        current_cart.add_to_cart(self.PROD_1, 5)
 

	
 
        # User should not be able to add 6 of PROD_2 to the current cart
 
        # because it is affected by CEIL_1
 
        with self.assertRaises(ValidationError):
 
            current_cart.add_to_cart(self.PROD_2, 6)
 

	
 
        # User should be able to add 5 of PROD_2 to the current cart
 
        current_cart.add_to_cart(self.PROD_2, 4)
 

	
 

	
 
    def test_add_to_cart_ceiling_date_range(self):
 
        self.make_ceiling("date range ceiling",
 
            start_time=datetime.datetime(2015, 01, 01, tzinfo=UTC),
 
            end_time=datetime.datetime(2015, 02, 01, tzinfo=UTC)
 
        )
 

	
 
        current_cart = CartController.for_user(self.USER_1)
 

	
 
        # User should not be able to add whilst we're before start_time
 
        self.set_time(datetime.datetime(2014, 01, 01, tzinfo=UTC))
 
        with self.assertRaises(ValidationError):
 
            current_cart.add_to_cart(self.PROD_1, 1)
 

	
 
        # User should be able to add whilst we're during date range
 
        # On edge of start
 
        self.set_time(datetime.datetime(2015, 01, 01, tzinfo=UTC))
 
        current_cart.add_to_cart(self.PROD_1, 1)
 
        # In middle
 
        self.set_time(datetime.datetime(2015, 01, 15, tzinfo=UTC))
 
        current_cart.add_to_cart(self.PROD_1, 1)
 
        # On edge of end
 
        self.set_time(datetime.datetime(2015, 02, 01, tzinfo=UTC))
 
        current_cart.add_to_cart(self.PROD_1, 1)
 

	
 
        # User should not be able to add whilst we're after date range
 
        self.set_time(datetime.datetime(2014, 01, 01, minute=01, tzinfo=UTC))
 
        with self.assertRaises(ValidationError):
 
            current_cart.add_to_cart(self.PROD_1, 1)
 

	
 

	
 
    def test_add_to_cart_ceiling_limit_reserved_carts(self):
 
        self.make_ceiling("Limit ceiling", limit=1)
 

	
 
        self.set_time(datetime.datetime(2015, 01, 01, tzinfo=UTC))
 

	
 
        first_cart = CartController.for_user(self.USER_1)
 
        second_cart = CartController.for_user(self.USER_2)
 

	
 
        first_cart.add_to_cart(self.PROD_1, 1)
 

	
 
        # User 2 should not be able to add item to their cart
 
        # because user 1 has item reserved, exhausting the ceiling
 
        with self.assertRaises(ValidationError):
 
            second_cart.add_to_cart(self.PROD_1, 1)
 

	
 
        # User 2 should be able to add item to their cart once the
 
        # reservation duration is elapsed
 
        self.add_timedelta(self.RESERVATION + datetime.timedelta(seconds=1))
 
        second_cart.add_to_cart(self.PROD_1, 1)
 

	
 
        # User 2 pays for their cart
 
        second_cart.cart.active = False
 
        second_cart.cart.save()
 

	
 
        # User 1 should not be able to add item to their cart
 
        # because user 2 has paid for their reserved item, exhausting
 
        # the ceiling, regardless of the reservation time.
 
        self.add_timedelta(self.RESERVATION * 20)
 
        with self.assertRaises(ValidationError):
 
            first_cart.add_to_cart(self.PROD_1, 1)
registrasion/tests/test_discount.py
Show inline comments
 
import datetime
 
import pytz
 

	
 
from decimal import Decimal
 
from django.contrib.auth.models import User
 
from django.core.exceptions import ValidationError
 
from django.test import TestCase
 
from django.utils import timezone
 

	
 
from registrasion import models as rego
 
from registrasion.cart import CartController
 
from registrasion.controllers.cart import CartController
 

	
 
from test_cart import RegistrationCartTestCase
 

	
 
UTC = pytz.timezone('UTC')
 

	
 
class DiscountTestCase(RegistrationCartTestCase):
 

	
 
    @classmethod
 
    def add_discount_prod_1_includes_prod_2(cls, amount=Decimal(100)):
 
        discount = rego.IncludedProductDiscount.objects.create(
 
            description="PROD_1 includes PROD_2 " + str(amount) + "%",
 
        )
 
        discount.save()
 
        discount.enabling_products.add(cls.PROD_1)
 
        discount.save()
 
        rego.DiscountForProduct.objects.create(
 
            discount=discount,
 
            product=cls.PROD_2,
 
            percentage=amount,
 
            quantity=2
 
        ).save()
 
        return discount
 

	
 

	
 
    @classmethod
 
    def add_discount_prod_1_includes_cat_2(cls, amount=Decimal(100)):
 
        discount = rego.IncludedProductDiscount.objects.create(
 
            description="PROD_1 includes CAT_2 " + str(amount) + "%",
 
        )
 
        discount.save()
 
        discount.enabling_products.add(cls.PROD_1)
 
        discount.save()
 
        rego.DiscountForCategory.objects.create(
 
            discount=discount,
 
            category=cls.CAT_2,
 
            percentage=amount,
 
            quantity=2
 
        ).save()
 
        return discount
 

	
 

	
 
    def test_discount_is_applied(self):
 
        discount = self.add_discount_prod_1_includes_prod_2()
 

	
 
        cart = CartController.for_user(self.USER_1)
 
        cart.add_to_cart(self.PROD_1, 1)
 
        cart.add_to_cart(self.PROD_2, 1)
 

	
 
        # Discounts should be applied at this point...
 
        self.assertEqual(1, len(cart.cart.discountitem_set.all()))
 

	
 

	
 
    def test_discount_is_applied_for_category(self):
 
        discount = self.add_discount_prod_1_includes_cat_2()
 

	
 
        cart = CartController.for_user(self.USER_1)
 
        cart.add_to_cart(self.PROD_1, 1)
 
        cart.add_to_cart(self.PROD_3, 1)
 

	
 
        # Discounts should be applied at this point...
 
        self.assertEqual(1, len(cart.cart.discountitem_set.all()))
 

	
 

	
 
    def test_discount_does_not_apply_if_not_met(self):
 
        discount = self.add_discount_prod_1_includes_prod_2()
 

	
 
        cart = CartController.for_user(self.USER_1)
 
        cart.add_to_cart(self.PROD_2, 1)
 

	
 
        # No discount should be applied as the condition is not met
 
        self.assertEqual(0, len(cart.cart.discountitem_set.all()))
 

	
 

	
 
    def test_discount_applied_out_of_order(self):
 
        discount = self.add_discount_prod_1_includes_prod_2()
 

	
 
        cart = CartController.for_user(self.USER_1)
 
        cart.add_to_cart(self.PROD_2, 1)
 
        cart.add_to_cart(self.PROD_1, 1)
 

	
 
        # No discount should be applied as the condition is not met
 
        self.assertEqual(1, len(cart.cart.discountitem_set.all()))
 

	
 

	
 
    def test_discounts_collapse(self):
 
        discount = self.add_discount_prod_1_includes_prod_2()
 

	
 
        cart = CartController.for_user(self.USER_1)
 
        cart.add_to_cart(self.PROD_1, 1)
 
        cart.add_to_cart(self.PROD_2, 1)
 
        cart.add_to_cart(self.PROD_2, 1)
 

	
 
        # Discounts should be applied and collapsed at this point...
 
        self.assertEqual(1, len(cart.cart.discountitem_set.all()))
 

	
 

	
registrasion/tests/test_enabling_condition.py
Show inline comments
 
import datetime
 
import pytz
 

	
 
from decimal import Decimal
 
from django.contrib.auth.models import User
 
from django.core.exceptions import ValidationError
 
from django.test import TestCase
 
from django.utils import timezone
 

	
 
from registrasion import models as rego
 
from registrasion.cart import CartController
 
from registrasion.controllers.cart import CartController
 

	
 
from test_cart import RegistrationCartTestCase
 

	
 
UTC = pytz.timezone('UTC')
 

	
 
class EnablingConditionTestCases(RegistrationCartTestCase):
 

	
 
    @classmethod
 
    def add_product_enabling_condition(cls, mandatory=False):
 
        ''' Adds a product enabling condition: adding PROD_1 to a cart is
 
        predicated on adding PROD_2 beforehand. '''
 
        enabling_condition = rego.ProductEnablingCondition.objects.create(
 
            description="Product condition",
 
            mandatory=mandatory,
 
        )
 
        enabling_condition.save()
 
        enabling_condition.products.add(cls.PROD_1)
 
        enabling_condition.enabling_products.add(cls.PROD_2)
 
        enabling_condition.save()
 

	
 

	
 
    @classmethod
 
    def add_product_enabling_condition_on_category(cls, mandatory=False):
 
        ''' Adds a product enabling condition that operates on a category:
 
        adding an item from CAT_1 is predicated on adding PROD_3 beforehand '''
 
        enabling_condition = rego.ProductEnablingCondition.objects.create(
 
            description="Product condition",
 
            mandatory=mandatory,
 
        )
 
        enabling_condition.save()
 
        enabling_condition.categories.add(cls.CAT_1)
 
        enabling_condition.enabling_products.add(cls.PROD_3)
 
        enabling_condition.save()
 

	
 

	
 
    def add_category_enabling_condition(cls, mandatory=False):
 
        ''' Adds a category enabling condition: adding PROD_1 to a cart is
 
        predicated on adding an item from CAT_2 beforehand.'''
 
        enabling_condition = rego.CategoryEnablingCondition.objects.create(
 
            description="Category condition",
 
            mandatory=mandatory,
 
            enabling_category=cls.CAT_2,
 
        )
 
        enabling_condition.save()
 
        enabling_condition.products.add(cls.PROD_1)
 
        enabling_condition.save()
 

	
 

	
 
    def test_product_enabling_condition_enables_product(self):
 
        self.add_product_enabling_condition()
 

	
 
        # Cannot buy PROD_1 without buying PROD_2
 
        current_cart = CartController.for_user(self.USER_1)
 
        with self.assertRaises(ValidationError):
 
            current_cart.add_to_cart(self.PROD_1, 1)
 

	
 
        current_cart.add_to_cart(self.PROD_2, 1)
 
        current_cart.add_to_cart(self.PROD_1, 1)
 

	
 

	
 
    def test_product_enabled_by_product_in_previous_cart(self):
 
        self.add_product_enabling_condition()
 

	
 
        current_cart = CartController.for_user(self.USER_1)
 
        current_cart.add_to_cart(self.PROD_2, 1)
 
        current_cart.cart.active = False
 
        current_cart.cart.save()
 

	
 
        # Create new cart and try to add PROD_1
 
        current_cart = CartController.for_user(self.USER_1)
 
        current_cart.add_to_cart(self.PROD_1, 1)
 

	
 

	
 
    def test_product_enabling_condition_enables_category(self):
 
        self.add_product_enabling_condition_on_category()
 

	
 
        # Cannot buy PROD_1 without buying item from CAT_2
 
        current_cart = CartController.for_user(self.USER_1)
 
        with self.assertRaises(ValidationError):
 
            current_cart.add_to_cart(self.PROD_1, 1)
 

	
 
        current_cart.add_to_cart(self.PROD_3, 1)
 
        current_cart.add_to_cart(self.PROD_1, 1)
 

	
 

	
 
    def test_category_enabling_condition_enables_product(self):
 
        self.add_category_enabling_condition()
 

	
 
        # Cannot buy PROD_1 without buying PROD_2
 
        current_cart = CartController.for_user(self.USER_1)
 
        with self.assertRaises(ValidationError):
 
            current_cart.add_to_cart(self.PROD_1, 1)
 

	
 
        # PROD_3 is in CAT_2
 
        current_cart.add_to_cart(self.PROD_3, 1)
 
        current_cart.add_to_cart(self.PROD_1, 1)
registrasion/tests/test_invoice.py
Show inline comments
 
import datetime
 
import pytz
 

	
 
from decimal import Decimal
 
from django.contrib.auth.models import User
 
from django.core.exceptions import ValidationError
 
from django.test import TestCase
 
from django.utils import timezone
 

	
 
from registrasion import models as rego
 
from registrasion.cart import CartController
 
from registrasion.invoice import InvoiceController
 
from registrasion.controllers.cart import CartController
 
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 = CartController.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 void all active invoices and 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)
 
        # 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 = CartController.for_user(self.USER_1)
 
        current_cart.add_to_cart(self.PROD_1, 1)
 

	
 
        self.add_timedelta(self.RESERVATION * 2)
 
        cart_2 = CartController.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 = CartController.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 = CartController.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 = CartController.for_user(self.USER_1)
 
        current_cart.apply_voucher(voucher)
 

	
 
        # 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)
registrasion/tests/test_voucher.py
Show inline comments
 
import datetime
 
import pytz
 

	
 
from decimal import Decimal
 
from django.contrib.auth.models import User
 
from django.core.exceptions import ValidationError
 
from django.test import TestCase
 
from django.utils import timezone
 

	
 
from registrasion import models as rego
 
from registrasion.cart import CartController
 
from registrasion.controllers.cart import CartController
 

	
 
from test_cart import RegistrationCartTestCase
 

	
 
UTC = pytz.timezone('UTC')
 

	
 

	
 
class VoucherTestCases(RegistrationCartTestCase):
 

	
 
    @classmethod
 
    def new_voucher(self):
 
        voucher = rego.Voucher.objects.create(
 
            recipient="Voucher recipient",
 
            code="VOUCHER",
 
            limit=1
 
        )
 
        voucher.save()
 
        return voucher
 

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

	
 
        self.set_time(datetime.datetime(2015, 01, 01, tzinfo=UTC))
 

	
 
        cart_1 = CartController.for_user(self.USER_1)
 
        cart_1.apply_voucher(voucher)
 
        self.assertIn(voucher, cart_1.cart.vouchers.all())
 

	
 
        # Second user should not be able to apply this voucher (it's exhausted)
 
        cart_2 = CartController.for_user(self.USER_2)
 
        with self.assertRaises(ValidationError):
 
            cart_2.apply_voucher(voucher)
 

	
 
        # 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)
 
        cart_2.cart.active = False
 
        cart_2.cart.save()
 

	
 
        # After the reservation duration, user 1 should not be able to apply
 
        # voucher, as user 2 has paid for their cart.
 
        self.add_timedelta(rego.Voucher.RESERVATION_DURATION * 2)
 
        with self.assertRaises(ValidationError):
 
            cart_1.apply_voucher(voucher)
 

	
 
    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 = CartController.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)
 
        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 = CartController.for_user(self.USER_1)
 
        current_cart.apply_voucher(voucher)
 
        current_cart.add_to_cart(self.PROD_1, 1)
 
        self.assertEqual(1, len(current_cart.cart.discountitem_set.all()))
0 comments (0 inline, 0 general)