symposion_app/registrasion/conditions.py
2016-01-22 16:19:11 +11:00

160 lines
4.9 KiB
Python

from django.db.models import F, 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)
enabling_products = rego.Product.objects.filter(
category=self.condition.enabling_category)
products = rego.ProductItem.objects.filter(cart=carts,
product=enabling_products)
return len(products) > 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)
products = rego.ProductItem.objects.filter(cart=carts,
product=self.condition.enabling_products.all())
return len(products) > 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=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 = rego.Cart.objects.filter(user=user,
vouchers=self.condition.voucher)
return len(carts) > 0