From 4d134e95d70b7f2f45e729488d1e542cef14d9bd Mon Sep 17 00:00:00 2001 From: Christopher Neugebauer Date: Sun, 3 Apr 2016 12:53:36 +1000 Subject: [PATCH] Refactors discount ceiling testing to make sure that the discount ceiling only considers items where the discount was applied in determining if the discount was reached. --- registrasion/controllers/conditions.py | 55 ++++++++++++++------------ registrasion/tests/test_cart.py | 16 +++++++- registrasion/tests/test_ceilings.py | 36 ++++++++++++++++- registrasion/tests/test_voucher.py | 10 ----- 4 files changed, 78 insertions(+), 39 deletions(-) diff --git a/registrasion/controllers/conditions.py b/registrasion/controllers/conditions.py index 7243737a..731b7edc 100644 --- a/registrasion/controllers/conditions.py +++ b/registrasion/controllers/conditions.py @@ -33,9 +33,9 @@ class ConditionController(object): rego.IncludedProductDiscount: ProductConditionController, rego.ProductEnablingCondition: ProductConditionController, rego.TimeOrStockLimitDiscount: - TimeOrStockLimitConditionController, + TimeOrStockLimitDiscountController, rego.TimeOrStockLimitEnablingCondition: - TimeOrStockLimitConditionController, + TimeOrStockLimitEnablingConditionController, rego.VoucherDiscount: VoucherConditionController, rego.VoucherEnablingCondition: VoucherConditionController, } @@ -184,7 +184,7 @@ class ProductConditionController(ConditionController): class TimeOrStockLimitConditionController(ConditionController): - ''' Condition tests for TimeOrStockLimit EnablingCondition and + ''' Common condition tests for TimeOrStockLimit EnablingCondition and Discount.''' def __init__(self, ceiling): @@ -213,23 +213,6 @@ class TimeOrStockLimitConditionController(ConditionController): return True - def _products(self): - ''' Abstracts away the product list, becuase enabling conditions - list products differently to discounts. ''' - if isinstance(self.ceiling, rego.TimeOrStockLimitEnablingCondition): - category_products = rego.Product.objects.filter( - category__in=self.ceiling.categories.all(), - ) - return self.ceiling.products.all() | category_products - else: - categories = rego.Category.objects.filter( - discountforcategory__discount=self.ceiling, - ) - return rego.Product.objects.filter( - Q(discountforproduct__discount=self.ceiling) | - Q(category__in=categories.all()) - ) - def _get_remaining_stock(self, user): ''' Returns the stock that remains under this ceiling, excluding the user's current cart. ''' @@ -244,15 +227,35 @@ class TimeOrStockLimitConditionController(ConditionController): active=True, ) - product_items = rego.ProductItem.objects.filter( - product__in=self._products().all(), - ) - product_items = product_items.filter(cart__in=reserved_carts) - - count = product_items.aggregate(Sum("quantity"))["quantity__sum"] or 0 + items = self._items() + items = items.filter(cart__in=reserved_carts) + count = items.aggregate(Sum("quantity"))["quantity__sum"] or 0 return self.ceiling.limit - count +class TimeOrStockLimitEnablingConditionController( + TimeOrStockLimitConditionController): + + def _items(self): + category_products = rego.Product.objects.filter( + category__in=self.ceiling.categories.all(), + ) + products = self.ceiling.products.all() | category_products + + product_items = rego.ProductItem.objects.filter( + product__in=products.all(), + ) + return product_items + + +class TimeOrStockLimitDiscountController(TimeOrStockLimitConditionController): + + def _items(self): + discount_items = rego.DiscountItem.objects.filter( + discount=self.ceiling, + ) + return discount_items + class VoucherConditionController(ConditionController): ''' Condition test for VoucherEnablingCondition and VoucherDiscount.''' diff --git a/registrasion/tests/test_cart.py b/registrasion/tests/test_cart.py index db90a723..45c18ef0 100644 --- a/registrasion/tests/test_cart.py +++ b/registrasion/tests/test_cart.py @@ -110,7 +110,8 @@ class RegistrationCartTestCase(SetTimeMixin, TestCase): @classmethod def make_discount_ceiling( - cls, name, limit=None, start_time=None, end_time=None): + cls, name, limit=None, start_time=None, end_time=None, + percentage=100): limit_ceiling = rego.TimeOrStockLimitDiscount.objects.create( description=name, start_time=start_time, @@ -121,11 +122,22 @@ class RegistrationCartTestCase(SetTimeMixin, TestCase): rego.DiscountForProduct.objects.create( discount=limit_ceiling, product=cls.PROD_1, - percentage=100, + percentage=percentage, quantity=10, ).save() + @classmethod + def new_voucher(self, code="VOUCHER", limit=1): + voucher = rego.Voucher.objects.create( + recipient="Voucher recipient", + code=code, + limit=limit, + ) + voucher.save() + return voucher + + class BasicCartTests(RegistrationCartTestCase): def test_get_cart(self): diff --git a/registrasion/tests/test_ceilings.py b/registrasion/tests/test_ceilings.py index e65a9ecf..94b1c311 100644 --- a/registrasion/tests/test_ceilings.py +++ b/registrasion/tests/test_ceilings.py @@ -4,9 +4,10 @@ import pytz from django.core.exceptions import ValidationError from cart_controller_helper import TestingCartController - from test_cart import RegistrationCartTestCase +from registrasion import models as rego + UTC = pytz.timezone('UTC') @@ -150,3 +151,36 @@ class CeilingsTestCases(RegistrationCartTestCase): first_cart.cart.save() second_cart.add_to_cart(self.PROD_1, 1) + + def test_discount_ceiling_only_counts_items_covered_by_ceiling(self): + self.make_discount_ceiling("Limit ceiling", limit=1, percentage=50) + voucher = self.new_voucher(code="VOUCHER") + + discount = rego.VoucherDiscount.objects.create( + description="VOUCHER RECIPIENT", + voucher=voucher, + ) + discount.save() + rego.DiscountForProduct.objects.create( + discount=discount, + product=self.PROD_1, + percentage=100, + quantity=1 + ).save() + + # Buy two of PROD_1, in separate carts: + cart = TestingCartController.for_user(self.USER_1) + # the 100% discount from the voucher should apply to the first item + # and not the ceiling discount. + cart.apply_voucher("VOUCHER") + cart.add_to_cart(self.PROD_1, 1) + self.assertEqual(1, len(cart.cart.discountitem_set.all())) + + cart.cart.active = False + cart.cart.save() + + # The second cart has no voucher attached, so should apply the + # ceiling discount + cart = TestingCartController.for_user(self.USER_1) + cart.add_to_cart(self.PROD_1, 1) + self.assertEqual(1, len(cart.cart.discountitem_set.all())) diff --git a/registrasion/tests/test_voucher.py b/registrasion/tests/test_voucher.py index da12abb3..de47c864 100644 --- a/registrasion/tests/test_voucher.py +++ b/registrasion/tests/test_voucher.py @@ -16,16 +16,6 @@ UTC = pytz.timezone('UTC') class VoucherTestCases(RegistrationCartTestCase): - @classmethod - def new_voucher(self, code="VOUCHER", limit=1): - voucher = rego.Voucher.objects.create( - recipient="Voucher recipient", - code=code, - limit=limit, - ) - voucher.save() - return voucher - def test_apply_voucher(self): voucher = self.new_voucher()