Makes EnablingConditionBase a minimal reification of an abstract base model FlagBase, replaces enablingconditionbase with flagbase where possible, and fixes method names and documentation
This commit is contained in:
parent
638ec26126
commit
c24b9ee213
6 changed files with 65 additions and 33 deletions
|
@ -118,7 +118,7 @@ class CartController(object):
|
||||||
|
|
||||||
def _test_limits(self, product_quantities):
|
def _test_limits(self, product_quantities):
|
||||||
''' Tests that the quantity changes we intend to make do not violate
|
''' Tests that the quantity changes we intend to make do not violate
|
||||||
the limits and enabling conditions imposed on the products. '''
|
the limits and flag conditions imposed on the products. '''
|
||||||
|
|
||||||
errors = []
|
errors = []
|
||||||
|
|
||||||
|
@ -159,8 +159,8 @@ class CartController(object):
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
|
|
||||||
# Test the enabling conditions
|
# Test the flag conditions
|
||||||
errs = ConditionController.test_enabling_conditions(
|
errs = ConditionController.test_flags(
|
||||||
self.cart.user,
|
self.cart.user,
|
||||||
product_quantities=product_quantities,
|
product_quantities=product_quantities,
|
||||||
)
|
)
|
||||||
|
|
|
@ -65,16 +65,16 @@ class ConditionController(object):
|
||||||
}
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def test_enabling_conditions(
|
def test_flags(
|
||||||
cls, user, products=None, product_quantities=None):
|
cls, user, products=None, product_quantities=None):
|
||||||
''' Evaluates all of the enabling conditions on the given products.
|
''' Evaluates all of the flag conditions on the given products.
|
||||||
|
|
||||||
If `product_quantities` is supplied, the condition is only met if it
|
If `product_quantities` is supplied, the condition is only met if it
|
||||||
will permit the sum of the product quantities for all of the products
|
will permit the sum of the product quantities for all of the products
|
||||||
it covers. Otherwise, it will be met if at least one item can be
|
it covers. Otherwise, it will be met if at least one item can be
|
||||||
accepted.
|
accepted.
|
||||||
|
|
||||||
If all enabling conditions pass, an empty list is returned, otherwise
|
If all flag conditions pass, an empty list is returned, otherwise
|
||||||
a list is returned containing all of the products that are *not
|
a list is returned containing all of the products that are *not
|
||||||
enabled*. '''
|
enabled*. '''
|
||||||
|
|
||||||
|
@ -90,14 +90,13 @@ class ConditionController(object):
|
||||||
quantities = {}
|
quantities = {}
|
||||||
|
|
||||||
# Get the conditions covered by the products themselves
|
# Get the conditions covered by the products themselves
|
||||||
|
|
||||||
prods = (
|
prods = (
|
||||||
product.enablingconditionbase_set.select_subclasses()
|
product.flagbase_set.select_subclasses()
|
||||||
for product in products
|
for product in products
|
||||||
)
|
)
|
||||||
# Get the conditions covered by their categories
|
# Get the conditions covered by their categories
|
||||||
cats = (
|
cats = (
|
||||||
category.enablingconditionbase_set.select_subclasses()
|
category.flagbase_set.select_subclasses()
|
||||||
for category in set(product.category for product in products)
|
for category in set(product.category for product in products)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -172,7 +171,7 @@ class ConditionController(object):
|
||||||
return error_fields
|
return error_fields
|
||||||
|
|
||||||
def user_quantity_remaining(self, user):
|
def user_quantity_remaining(self, user):
|
||||||
''' Returns the number of items covered by this enabling condition the
|
''' Returns the number of items covered by this flag condition the
|
||||||
user can add to the current cart. This default implementation returns
|
user can add to the current cart. This default implementation returns
|
||||||
a big number if is_met() is true, otherwise 0.
|
a big number if is_met() is true, otherwise 0.
|
||||||
|
|
||||||
|
@ -182,7 +181,7 @@ class ConditionController(object):
|
||||||
return 99999999 if self.is_met(user) else 0
|
return 99999999 if self.is_met(user) else 0
|
||||||
|
|
||||||
def is_met(self, user):
|
def is_met(self, user):
|
||||||
''' Returns True if this enabling condition is met, otherwise returns
|
''' Returns True if this flag condition is met, otherwise returns
|
||||||
False.
|
False.
|
||||||
|
|
||||||
Either this method, or user_quantity_remaining() must be overridden
|
Either this method, or user_quantity_remaining() must be overridden
|
||||||
|
|
|
@ -15,9 +15,9 @@ class ProductController(object):
|
||||||
@classmethod
|
@classmethod
|
||||||
def available_products(cls, user, category=None, products=None):
|
def available_products(cls, user, category=None, products=None):
|
||||||
''' Returns a list of all of the products that are available per
|
''' Returns a list of all of the products that are available per
|
||||||
enabling conditions from the given categories.
|
flag conditions from the given categories.
|
||||||
TODO: refactor so that all conditions are tested here and
|
TODO: refactor so that all conditions are tested here and
|
||||||
can_add_with_enabling_conditions calls this method. '''
|
can_add_with_flags calls this method. '''
|
||||||
if category is None and products is None:
|
if category is None and products is None:
|
||||||
raise ValueError("You must provide products or a category")
|
raise ValueError("You must provide products or a category")
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ class ProductController(object):
|
||||||
if cls(product).user_quantity_remaining(user) > 0
|
if cls(product).user_quantity_remaining(user) > 0
|
||||||
)
|
)
|
||||||
|
|
||||||
failed_and_messages = ConditionController.test_enabling_conditions(
|
failed_and_messages = ConditionController.test_flags(
|
||||||
user, products=passed_limits
|
user, products=passed_limits
|
||||||
)
|
)
|
||||||
failed_conditions = set(i[0] for i in failed_and_messages)
|
failed_conditions = set(i[0] for i in failed_and_messages)
|
||||||
|
|
25
registrasion/migrations/0024_auto_20160411_2230.py
Normal file
25
registrasion/migrations/0024_auto_20160411_2230.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.9.2 on 2016-04-11 22:30
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('registrasion', '0023_auto_20160411_1001_squashed_0024_auto_20160411_1002'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='enablingconditionbase',
|
||||||
|
name='categories',
|
||||||
|
field=models.ManyToManyField(blank=True, help_text="Categories whose products are affected by this flag's condition.", related_name='flagbase_set', to='registrasion.Category'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='enablingconditionbase',
|
||||||
|
name='products',
|
||||||
|
field=models.ManyToManyField(blank=True, help_text="Products affected by this flag's condition.", related_name='flagbase_set', to='registrasion.Product'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -366,15 +366,8 @@ class RoleDiscount(object):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class FlagBase(object):
|
|
||||||
''' This will replace EnablingConditionBase once it's ready. '''
|
|
||||||
|
|
||||||
DISABLE_IF_FALSE = 1
|
|
||||||
ENABLE_IF_TRUE = 2
|
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class EnablingConditionBase(models.Model):
|
class FlagBase(models.Model):
|
||||||
''' This defines a condition which allows products or categories to
|
''' This defines a condition which allows products or categories to
|
||||||
be made visible, or be prevented from being visible.
|
be made visible, or be prevented from being visible.
|
||||||
|
|
||||||
|
@ -387,10 +380,14 @@ class EnablingConditionBase(models.Model):
|
||||||
|
|
||||||
If both types of conditions exist on a product, both of these rules apply.
|
If both types of conditions exist on a product, both of these rules apply.
|
||||||
'''
|
'''
|
||||||
# TODO: rename to FlagBase once
|
|
||||||
# https://code.djangoproject.com/ticket/26488 is solved.
|
|
||||||
|
|
||||||
objects = InheritanceManager()
|
class Meta:
|
||||||
|
# TODO: make concrete once https://code.djangoproject.com/ticket/26488
|
||||||
|
# is solved.
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
DISABLE_IF_FALSE = 1
|
||||||
|
ENABLE_IF_TRUE = 2
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.description
|
return self.description
|
||||||
|
@ -409,10 +406,10 @@ class EnablingConditionBase(models.Model):
|
||||||
|
|
||||||
description = models.CharField(max_length=255)
|
description = models.CharField(max_length=255)
|
||||||
condition = models.IntegerField(
|
condition = models.IntegerField(
|
||||||
default=FlagBase.ENABLE_IF_TRUE,
|
default=ENABLE_IF_TRUE,
|
||||||
choices=(
|
choices=(
|
||||||
(FlagBase.DISABLE_IF_FALSE, _("Disable if false")),
|
(DISABLE_IF_FALSE, _("Disable if false")),
|
||||||
(FlagBase.ENABLE_IF_TRUE, _("Enable if true")),
|
(ENABLE_IF_TRUE, _("Enable if true")),
|
||||||
),
|
),
|
||||||
help_text=_("If there is at least one 'disable if false' flag "
|
help_text=_("If there is at least one 'disable if false' flag "
|
||||||
"defined on a product or category, all such flag "
|
"defined on a product or category, all such flag "
|
||||||
|
@ -426,6 +423,7 @@ class EnablingConditionBase(models.Model):
|
||||||
Product,
|
Product,
|
||||||
blank=True,
|
blank=True,
|
||||||
help_text=_("Products affected by this flag's condition."),
|
help_text=_("Products affected by this flag's condition."),
|
||||||
|
related_name="flagbase_set",
|
||||||
)
|
)
|
||||||
categories = models.ManyToManyField(
|
categories = models.ManyToManyField(
|
||||||
Category,
|
Category,
|
||||||
|
@ -433,9 +431,19 @@ class EnablingConditionBase(models.Model):
|
||||||
help_text=_("Categories whose products are affected by this flag's "
|
help_text=_("Categories whose products are affected by this flag's "
|
||||||
"condition."
|
"condition."
|
||||||
),
|
),
|
||||||
|
related_name="flagbase_set",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class EnablingConditionBase(FlagBase):
|
||||||
|
''' Reifies the abstract FlagBase. This is necessary because django
|
||||||
|
prevents renaming base classes in migrations. '''
|
||||||
|
# TODO: remove this, and make subclasses subclass FlagBase once
|
||||||
|
# https://code.djangoproject.com/ticket/26488 is solved.
|
||||||
|
|
||||||
|
objects = InheritanceManager()
|
||||||
|
|
||||||
|
|
||||||
class TimeOrStockLimitFlag(EnablingConditionBase):
|
class TimeOrStockLimitFlag(EnablingConditionBase):
|
||||||
''' Registration product ceilings '''
|
''' Registration product ceilings '''
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ class FlagTestCases(RegistrationCartTestCase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def add_product_flag(cls, condition=rego.FlagBase.ENABLE_IF_TRUE):
|
def add_product_flag(cls, condition=rego.FlagBase.ENABLE_IF_TRUE):
|
||||||
''' Adds a product enabling condition: adding PROD_1 to a cart is
|
''' Adds a product flag condition: adding PROD_1 to a cart is
|
||||||
predicated on adding PROD_2 beforehand. '''
|
predicated on adding PROD_2 beforehand. '''
|
||||||
flag = rego.ProductFlag.objects.create(
|
flag = rego.ProductFlag.objects.create(
|
||||||
description="Product condition",
|
description="Product condition",
|
||||||
|
@ -29,7 +29,7 @@ class FlagTestCases(RegistrationCartTestCase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def add_product_flag_on_category(cls, condition=rego.FlagBase.ENABLE_IF_TRUE):
|
def add_product_flag_on_category(cls, condition=rego.FlagBase.ENABLE_IF_TRUE):
|
||||||
''' Adds a product enabling condition that operates on a category:
|
''' Adds a product flag condition that operates on a category:
|
||||||
adding an item from CAT_1 is predicated on adding PROD_3 beforehand '''
|
adding an item from CAT_1 is predicated on adding PROD_3 beforehand '''
|
||||||
flag = rego.ProductFlag.objects.create(
|
flag = rego.ProductFlag.objects.create(
|
||||||
description="Product condition",
|
description="Product condition",
|
||||||
|
@ -41,7 +41,7 @@ class FlagTestCases(RegistrationCartTestCase):
|
||||||
flag.save()
|
flag.save()
|
||||||
|
|
||||||
def add_category_flag(cls, condition=rego.FlagBase.ENABLE_IF_TRUE):
|
def add_category_flag(cls, condition=rego.FlagBase.ENABLE_IF_TRUE):
|
||||||
''' Adds a category enabling condition: adding PROD_1 to a cart is
|
''' Adds a category flag condition: adding PROD_1 to a cart is
|
||||||
predicated on adding an item from CAT_2 beforehand.'''
|
predicated on adding an item from CAT_2 beforehand.'''
|
||||||
flag = rego.CategoryFlag.objects.create(
|
flag = rego.CategoryFlag.objects.create(
|
||||||
description="Category condition",
|
description="Category condition",
|
||||||
|
@ -114,7 +114,7 @@ class FlagTestCases(RegistrationCartTestCase):
|
||||||
self.add_product_flag()
|
self.add_product_flag()
|
||||||
self.add_category_flag()
|
self.add_category_flag()
|
||||||
|
|
||||||
# User 1 is testing the product enabling condition
|
# User 1 is testing the product flag condition
|
||||||
cart_1 = TestingCartController.for_user(self.USER_1)
|
cart_1 = TestingCartController.for_user(self.USER_1)
|
||||||
# Cannot add PROD_1 until a condition is met
|
# Cannot add PROD_1 until a condition is met
|
||||||
with self.assertRaises(ValidationError):
|
with self.assertRaises(ValidationError):
|
||||||
|
@ -122,7 +122,7 @@ class FlagTestCases(RegistrationCartTestCase):
|
||||||
cart_1.add_to_cart(self.PROD_2, 1)
|
cart_1.add_to_cart(self.PROD_2, 1)
|
||||||
cart_1.add_to_cart(self.PROD_1, 1)
|
cart_1.add_to_cart(self.PROD_1, 1)
|
||||||
|
|
||||||
# User 2 is testing the category enabling condition
|
# User 2 is testing the category flag condition
|
||||||
cart_2 = TestingCartController.for_user(self.USER_2)
|
cart_2 = TestingCartController.for_user(self.USER_2)
|
||||||
# Cannot add PROD_1 until a condition is met
|
# Cannot add PROD_1 until a condition is met
|
||||||
with self.assertRaises(ValidationError):
|
with self.assertRaises(ValidationError):
|
||||||
|
|
Loading…
Reference in a new issue