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)