diff --git a/registrasion/controllers.py b/registrasion/controllers.py new file mode 100644 index 0000000000000000000000000000000000000000..795c2d48abbbdc1f690dd1578dfbb265393c1748 --- /dev/null +++ b/registrasion/controllers.py @@ -0,0 +1,99 @@ +import itertools + +from collections import namedtuple + +from django.db.models import F, Q +from registrasion import models as rego + +from conditions import ConditionController + +DiscountEnabler = namedtuple("DiscountEnabler", ("discount", "condition", "value")) + +class ProductController(object): + + def __init__(self, product): + self.product = product + + def user_can_add_within_limit(self, user, quantity): + ''' Return true if the user is able to add _quantity_ to their count of + this Product without exceeding _limit_per_user_.''' + + carts = rego.Cart.objects.filter(user=user) + items = rego.ProductItem.objects.filter(product=self.product, cart=carts) + + count = 0 + for item in items: + count += item.quantity + + if quantity + count > self.product.limit_per_user: + return False + else: + return True + + def can_add_with_enabling_conditions(self, user, quantity): + ''' Returns true if the user is able to add _quantity_ to their count + of this Product without exceeding the ceilings the product is attached + to. ''' + + conditions = rego.EnablingConditionBase.objects.filter( + Q(products=self.product) | Q(categories=self.product.category) + ).select_subclasses() + + mandatory_violated = False + non_mandatory_met = False + + for condition in conditions: + cond = ConditionController.for_condition(condition) + met = cond.is_met(user, quantity) + + if condition.mandatory and not met: + mandatory_violated = True + break + if met: + non_mandatory_met = True + + if mandatory_violated: + # All mandatory conditions must be met + return False + + if len(conditions) > 0 and not non_mandatory_met: + # If there's any non-mandatory conditions, one must be met + return False + + return True + + + def get_enabler(self, condition): + if condition.percentage is not None: + value = condition.percentage * self.product.price + else: + value = condition.price + return DiscountEnabler( + discount=condition.discount, + condition=condition, + value=value + ) + + def available_discounts(self, user): + ''' Returns the set of available discounts for this user, for this + product. ''' + + product_discounts = rego.DiscountForProduct.objects.filter( + product=self.product) + category_discounts = rego.DiscountForCategory.objects.filter( + category=self.product.category + ) + + potential_discounts = set(itertools.chain( + (self.get_enabler(i) for i in product_discounts), + (self.get_enabler(i) for i in category_discounts), + )) + + discounts = [] + for discount in potential_discounts: + real_discount = rego.DiscountBase.objects.get_subclass(pk=discount.discount.pk) + cond = ConditionController.for_condition(real_discount) + if cond.is_met(user, 0): + discounts.append(discount) + + return discounts