diff --git a/registrasion/controllers/cart.py b/registrasion/controllers/cart.py index 97e17594..f8cbd0f5 100644 --- a/registrasion/controllers/cart.py +++ b/registrasion/controllers/cart.py @@ -251,6 +251,37 @@ class CartController(object): if errors: raise(ValidationError(ve)) + def _test_required_categories(self): + ''' Makes sure that the owner of this cart has satisfied all of the + required category constraints in the inventory (be it in this cart + or others). ''' + + required = set(inventory.Category.objects.filter(required=True)) + + items = commerce.ProductItem.objects.filter( + product__category__required=True, + cart__user=self.cart.user, + ).exclude( + cart__status=commerce.Cart.STATUS_RELEASED, + ) + + for item in items: + print item + required.remove(item.product.category) + + errors = [] + for category in required: + msg = "You must have at least one item from: %s" % category + errors.append((None, msg)) + + if errors: + raise ValidationError(errors) + + def _append_errors(self, errors, ve): + for error in ve.error_list: + print error.message + errors.append(error.message[1]) + def validate_cart(self): ''' Determines whether the status of the current cart is valid; this is normally called before generating or paying an invoice ''' @@ -270,8 +301,12 @@ class CartController(object): try: self._test_limits(product_quantities) except ValidationError as ve: - for error in ve.error_list: - errors.append(error.message[1]) + self._append_errors(errors, ve) + + try: + self._test_required_categories() + except ValidationError as ve: + self._append_errors(errors, ve) # Validate the discounts discount_items = commerce.DiscountItem.objects.filter(cart=cart) diff --git a/registrasion/tests/test_invoice.py b/registrasion/tests/test_invoice.py index 1b687c0c..9e5b55cf 100644 --- a/registrasion/tests/test_invoice.py +++ b/registrasion/tests/test_invoice.py @@ -499,3 +499,37 @@ class InvoiceTestCase(RegistrationCartTestCase): invoice.pay("Paying into the void.", val, pre_validate=False) cn = self._credit_note_for_invoice(invoice.invoice) self.assertEqual(val, cn.credit_note.value) + + def test_required_category_constraints_prevent_invoicing(self): + self.CAT_1.required = True + self.CAT_1.save() + + cart = TestingCartController.for_user(self.USER_1) + cart.add_to_cart(self.PROD_3, 1) + + # CAT_1 is required, we don't have CAT_1 yet + with self.assertRaises(ValidationError): + invoice = TestingInvoiceController.for_cart(cart.cart) + + # Now that we have CAT_1, we can check out the cart + cart.add_to_cart(self.PROD_1, 1) + invoice = TestingInvoiceController.for_cart(cart.cart) + + # Paying for the invoice should work fine + invoice.pay("Boop", invoice.invoice.value) + + # We have an item in the first cart, so should be able to invoice + # for the second cart, even without CAT_1 in it. + cart = TestingCartController.for_user(self.USER_1) + cart.add_to_cart(self.PROD_3, 1) + + invoice2 = TestingInvoiceController.for_cart(cart.cart) + + # Void invoice2, and release the first cart + # now we don't have any CAT_1 + invoice2.void() + invoice.refund() + + # Now that we don't have CAT_1, we can't checkout this cart + with self.assertRaises(ValidationError): + invoice = TestingInvoiceController.for_cart(cart.cart)