symposion_app/vendor/registrasion/controllers/product.py
2017-05-27 20:59:35 +10:00

92 lines
2.7 KiB
Python

import itertools
from django.db.models import Case
from django.db.models import F, Q
from django.db.models import Sum
from django.db.models import When
from django.db.models import Value
from registrasion.models import commerce
from registrasion.models import inventory
from .batch import BatchController
from .category import CategoryController
from .flag import FlagController
class ProductController(object):
def __init__(self, product):
self.product = product
@classmethod
def available_products(cls, user, category=None, products=None):
''' Returns a list of all of the products that are available per
flag conditions from the given categories. '''
if category is None and products is None:
raise ValueError("You must provide products or a category")
if category is not None:
all_products = inventory.Product.objects.filter(category=category)
all_products = all_products.select_related("category")
else:
all_products = []
if products is not None:
all_products = set(itertools.chain(all_products, products))
category_remainders = CategoryController.user_remainders(user)
product_remainders = ProductController.user_remainders(user)
passed_limits = set(
product
for product in all_products
if category_remainders[product.category.id] > 0
if product_remainders[product.id] > 0
)
failed_and_messages = FlagController.test_flags(
user, products=passed_limits
)
failed_conditions = set(i[0] for i in failed_and_messages)
out = list(passed_limits - failed_conditions)
out.sort(key=lambda product: product.order)
return out
@classmethod
@BatchController.memoise
def user_remainders(cls, user):
'''
Return:
Mapping[int->int]: A dictionary that maps the product ID to the
user's remainder for that product.
'''
products = inventory.Product.objects.all()
cart_filter = (
Q(productitem__cart__user=user) &
Q(productitem__cart__status=commerce.Cart.STATUS_PAID)
)
quantity = When(
cart_filter,
then='productitem__quantity'
)
quantity_or_zero = Case(
quantity,
default=Value(0),
)
remainder = Case(
When(limit_per_user=None, then=Value(99999999)),
default=F('limit_per_user') - Sum(quantity_or_zero),
)
products = products.annotate(remainder=remainder)
return dict((product.id, product.remainder) for product in products)