symposion_app/registrasion/controllers/item.py

126 lines
3.5 KiB
Python
Raw Normal View History

''' NEEDS TESTS '''
2016-09-14 03:28:15 +00:00
import operator
from registrasion.models import commerce
from registrasion.models import inventory
2016-09-14 03:28:15 +00:00
from collections import Iterable
from collections import namedtuple
from django.db.models import Case
from django.db.models import Q
from django.db.models import Sum
from django.db.models import When
from django.db.models import Value
_ProductAndQuantity = namedtuple("ProductAndQuantity", ["product", "quantity"])
class ProductAndQuantity(_ProductAndQuantity):
''' Class that holds a product and a quantity.
Attributes:
product (models.inventory.Product)
quantity (int)
'''
pass
class ItemController(object):
def __init__(self, user):
self.user = user
def _items(self, cart_status, category=None):
''' Aggregates the items that this user has purchased.
Arguments:
2016-09-14 03:28:15 +00:00
cart_status (int or Iterable(int)): etc
category (Optional[models.inventory.Category]): the category
of items to restrict to.
Returns:
[ProductAndQuantity, ...]: A list of product-quantity pairs,
aggregating like products from across multiple invoices.
'''
2016-09-14 03:28:15 +00:00
if not isinstance(cart_status, Iterable):
cart_status = [cart_status]
status_query = (
Q(productitem__cart__status=status) for status in cart_status
)
2016-09-14 03:28:15 +00:00
in_cart = Q(productitem__cart__user=self.user)
in_cart = in_cart & reduce(operator.__or__, status_query)
quantities_in_cart = When(
in_cart,
then="productitem__quantity",
)
quantities_or_zero = Case(
quantities_in_cart,
default=Value(0),
)
products = inventory.Product.objects
if category:
products = products.filter(category=category)
products = products.select_related("category")
products = products.annotate(quantity=Sum(quantities_or_zero))
products = products.filter(quantity__gt=0)
out = []
for prod in products:
out.append(ProductAndQuantity(prod, prod.quantity))
return out
2016-09-14 03:28:15 +00:00
def items_pending_or_purchased(self):
''' Returns the items that this user has purchased or has pending. '''
status = [commerce.Cart.STATUS_PAID, commerce.Cart.STATUS_ACTIVE]
return self._items(status)
def items_purchased(self, category=None):
''' Aggregates the items that this user has purchased.
Arguments:
category (Optional[models.inventory.Category]): the category
of items to restrict to.
Returns:
[ProductAndQuantity, ...]: A list of product-quantity pairs,
aggregating like products from across multiple invoices.
'''
return self._items(commerce.Cart.STATUS_PAID, category=category)
def items_pending(self):
''' Gets all of the items that the user has reserved, but has not yet
paid for.
Returns:
[ProductAndQuantity, ...]: A list of product-quantity pairs for the
items that the user has not yet paid for.
'''
return self._items(commerce.Cart.STATUS_ACTIVE)
def items_released(self):
''' Gets all of the items that the user previously paid for, but has
since refunded.
Returns:
[ProductAndQuantity, ...]: A list of product-quantity pairs for the
items that the user has not yet paid for.
'''
return self._items(commerce.Cart.STATUS_RELEASED)