diff --git a/registrasion/controllers/category.py b/registrasion/controllers/category.py new file mode 100644 index 00000000..7bd08283 --- /dev/null +++ b/registrasion/controllers/category.py @@ -0,0 +1,24 @@ +from .product import ProductController + +from registrasion import models as rego + +class AllProducts(object): + pass + +class CategoryController(object): + + @classmethod + def available_categories(cls, user, products=AllProducts): + ''' Returns the categories available to the user. Specify `products` if + you want to restrict to just the categories that hold the specified + products, otherwise it'll do all. ''' + + if products is AllProducts: + products = rego.Product.objects.all() + + available = ProductController.available_products( + user, + products=products, + ) + + return set(i.category for i in available) diff --git a/registrasion/controllers/product.py b/registrasion/controllers/product.py index 235031e8..abb5947d 100644 --- a/registrasion/controllers/product.py +++ b/registrasion/controllers/product.py @@ -32,16 +32,23 @@ class ProductController(object): out = [ product for product in all_products + if cls(product).user_can_add_within_limit(user, 1, past_carts=True) if cls(product).can_add_with_enabling_conditions(user, 0) ] out.sort(key=lambda product: product.order) return out - def user_can_add_within_limit(self, user, quantity): + def user_can_add_within_limit(self, user, quantity, past_carts=False): ''' Return true if the user is able to add _quantity_ to their count of this Product without exceeding _limit_per_user_.''' - carts = rego.Cart.objects.filter(user=user) + carts = rego.Cart.objects.filter( + user=user, + released=False, + ) + if past_carts: + carts = carts.filter(active=False) + items = rego.ProductItem.objects.filter( cart__in=carts, ) @@ -52,9 +59,9 @@ class ProductController(object): prod_count = prod_items.aggregate(Sum("quantity"))["quantity__sum"] cat_count = cat_items.aggregate(Sum("quantity"))["quantity__sum"] - if prod_count == None: + if prod_count is None: prod_count = 0 - if cat_count == None: + if cat_count is None: cat_count = 0 prod_limit = self.product.limit_per_user diff --git a/registrasion/templatetags/registrasion_tags.py b/registrasion/templatetags/registrasion_tags.py index ac9fa0ca..6de13e74 100644 --- a/registrasion/templatetags/registrasion_tags.py +++ b/registrasion/templatetags/registrasion_tags.py @@ -1,4 +1,5 @@ from registrasion import models as rego +from registrasion.controllers.category import CategoryController from collections import namedtuple from django import template @@ -12,7 +13,7 @@ ProductAndQuantity = namedtuple("ProductAndQuantity", ["product", "quantity"]) @register.assignment_tag(takes_context=True) def available_categories(context): ''' Returns all of the available product categories ''' - return rego.Category.objects.all() + return CategoryController.available_categories(context.request.user) @register.assignment_tag(takes_context=True) diff --git a/registrasion/tests/test_cart.py b/registrasion/tests/test_cart.py index 03d31b54..7c51c131 100644 --- a/registrasion/tests/test_cart.py +++ b/registrasion/tests/test_cart.py @@ -9,6 +9,7 @@ from django.test import TestCase from registrasion import models as rego from registrasion.controllers.cart import CartController +from registrasion.controllers.product import ProductController from patch_datetime import SetTimeMixin @@ -288,3 +289,31 @@ class BasicCartTests(RegistrationCartTestCase): with self.assertRaises(ValidationError): current_cart.set_quantity(self.PROD_4, 1) + + def __available_products_test(self, item, quantity): + self.set_limits() + + get_prods = lambda: ProductController.available_products( + self.USER_1, + products=[self.PROD_2, self.PROD_3, self.PROD_4], + ) + + current_cart = CartController.for_user(self.USER_1) + prods = get_prods() + self.assertTrue(item in prods) + current_cart.add_to_cart(item, quantity) + self.assertTrue(item in prods) + + current_cart.cart.active = False + current_cart.cart.save() + + current_cart = CartController.for_user(self.USER_1) + + prods = get_prods() + self.assertTrue(item not in prods) + + def test_available_products_respects_category_limits(self): + self.__available_products_test(self.PROD_3, 10) + + def test_available_products_respects_product_limits(self): + self.__available_products_test(self.PROD_4, 6) diff --git a/registrasion/tests/test_enabling_condition.py b/registrasion/tests/test_enabling_condition.py index 2861e8db..aeec4708 100644 --- a/registrasion/tests/test_enabling_condition.py +++ b/registrasion/tests/test_enabling_condition.py @@ -3,6 +3,7 @@ import pytz from django.core.exceptions import ValidationError from registrasion import models as rego +from registrasion.controllers.category import CategoryController from registrasion.controllers.cart import CartController from registrasion.controllers.product import ProductController @@ -271,3 +272,24 @@ class EnablingConditionTestCases(RegistrationCartTestCase): with self.assertRaises(ValidationError): cart_2.set_quantity(self.PROD_1, 1) + + def test_available_categories(self): + self.add_product_enabling_condition_on_category(mandatory=False) + + cart_1 = CartController.for_user(self.USER_1) + + cats = CategoryController.available_categories( + self.USER_1, + ) + + self.assertFalse(self.CAT_1 in cats) + self.assertTrue(self.CAT_2 in cats) + + cart_1.add_to_cart(self.PROD_3, 1) + + cats = CategoryController.available_categories( + self.USER_1, + ) + + self.assertTrue(self.CAT_1 in cats) + self.assertTrue(self.CAT_2 in cats) diff --git a/registrasion/views.py b/registrasion/views.py index e443dc10..812689f7 100644 --- a/registrasion/views.py +++ b/registrasion/views.py @@ -121,6 +121,10 @@ def guided_registration(request, page_id=0): category=category, ) + if not products: + # This product category does not exist for this user + continue + prefix = "category_" + str(category.id) p = handle_products(request, category, products, prefix) products_form, discounts, products_handled = p @@ -160,6 +164,13 @@ def guided_registration(request, page_id=0): def edit_profile(request): form, handled = handle_profile(request, "profile") + if handled and not form.errors: + messages.success( + request, + "Your attendee profile was updated.", + ) + return redirect("dashboard") + data = { "form": form, } @@ -229,12 +240,23 @@ def product_category(request, category_id): category=category, ) + if not products: + messages.warning( + request, + "There are no products available from category: "+ category.name, + ) + return redirect("dashboard") + p = handle_products(request, category, products, PRODUCTS_FORM_PREFIX) products_form, discounts, products_handled = p if request.POST and not voucher_handled and not products_form.errors: # Only return to the dashboard if we didn't add a voucher code # and if there's no errors in the products form + messages.success( + request, + "Your reservations have been updated.", + ) return redirect("dashboard") data = {