symposion_app/registrasion/controllers/conditions.py
2016-04-02 18:17:18 +11:00

162 lines
5 KiB
Python

from django.db.models import Q
from django.db.models import Sum
from django.utils import timezone
from registrasion import models as rego
class ConditionController(object):
''' Base class for testing conditions that activate EnablingCondition
or Discount objects. '''
def __init__(self):
pass
@staticmethod
def for_condition(condition):
CONTROLLERS = {
rego.CategoryEnablingCondition: CategoryConditionController,
rego.IncludedProductDiscount: ProductConditionController,
rego.ProductEnablingCondition: ProductConditionController,
rego.TimeOrStockLimitDiscount:
TimeOrStockLimitConditionController,
rego.TimeOrStockLimitEnablingCondition:
TimeOrStockLimitConditionController,
rego.VoucherDiscount: VoucherConditionController,
rego.VoucherEnablingCondition: VoucherConditionController,
}
try:
return CONTROLLERS[type(condition)](condition)
except KeyError:
return ConditionController()
def is_met(self, user, quantity):
return True
class CategoryConditionController(ConditionController):
def __init__(self, condition):
self.condition = condition
def is_met(self, user, quantity):
''' returns True if the user has a product from a category that invokes
this condition in one of their carts '''
carts = rego.Cart.objects.filter(user=user, released=False)
enabling_products = rego.Product.objects.filter(
category=self.condition.enabling_category,
)
products_count = rego.ProductItem.objects.filter(
cart=carts,
product__in=enabling_products,
).count()
return products_count > 0
class ProductConditionController(ConditionController):
''' Condition tests for ProductEnablingCondition and
IncludedProductDiscount. '''
def __init__(self, condition):
self.condition = condition
def is_met(self, user, quantity):
''' returns True if the user has a product that invokes this
condition in one of their carts '''
carts = rego.Cart.objects.filter(user=user, released=False)
products_count = rego.ProductItem.objects.filter(
cart=carts,
product__in=self.condition.enabling_products.all(),
).count()
return products_count > 0
class TimeOrStockLimitConditionController(ConditionController):
''' Condition tests for TimeOrStockLimit EnablingCondition and
Discount.'''
def __init__(self, ceiling):
self.ceiling = ceiling
def is_met(self, user, quantity):
''' returns True if adding _quantity_ of _product_ will not vioilate
this ceiling. '''
# Test date range
if not self.test_date_range():
return False
# Test limits
if not self.test_limits(quantity):
return False
# All limits have been met
return True
def test_date_range(self):
now = timezone.now()
if self.ceiling.start_time is not None:
if now < self.ceiling.start_time:
return False
if self.ceiling.end_time is not None:
if now > self.ceiling.end_time:
return False
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=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=categories.all())
)
def test_limits(self, quantity):
if self.ceiling.limit is None:
return True
reserved_carts = rego.Cart.reserved_carts()
product_items = rego.ProductItem.objects.filter(
product__in=self._products().all(),
)
product_items = product_items.filter(cart=reserved_carts)
agg = product_items.aggregate(Sum("quantity"))
count = agg["quantity__sum"]
if count is None:
count = 0
if count + quantity > self.ceiling.limit:
return False
return True
class VoucherConditionController(ConditionController):
''' Condition test for VoucherEnablingCondition and VoucherDiscount.'''
def __init__(self, condition):
self.condition = condition
def is_met(self, user, quantity):
''' returns True if the user has the given voucher attached. '''
carts_count = rego.Cart.objects.filter(
user=user,
vouchers=self.condition.voucher,
).count()
return carts_count > 0