From 5debbb2ac82ea885cd230d3182fc0bc4c8fec7bc 2016-04-06 07:41:08 From: Christopher Neugebauer Date: 2016-04-06 07:41:08 Subject: [PATCH] Merge branch 'random_fixes' --- diff --git a/registrasion/controllers/invoice.py b/registrasion/controllers/invoice.py index fdea324bfd3ac14ac000ff8c5265e5212512a917..264049c86486febb699d343c16e667b7797cf774 100644 --- a/registrasion/controllers/invoice.py +++ b/registrasion/controllers/invoice.py @@ -57,6 +57,7 @@ class InvoiceController(object): return value @classmethod + @transaction.atomic def _generate(cls, cart): ''' Generates an invoice for the given cart. ''' invoice = rego.Invoice.objects.create( @@ -65,10 +66,12 @@ class InvoiceController(object): cart_revision=cart.revision, value=Decimal() ) - invoice.save() - # TODO: calculate line items. product_items = rego.ProductItem.objects.filter(cart=cart) + + if len(product_items) == 0: + raise ValidationError("Your cart is empty.") + product_items = product_items.order_by( "product__category__order", "product__order" ) @@ -82,7 +85,6 @@ class InvoiceController(object): quantity=item.quantity, price=product.price, ) - line_item.save() invoice_value += line_item.quantity * line_item.price for item in discount_items: @@ -92,11 +94,13 @@ class InvoiceController(object): quantity=item.quantity, price=cls.resolve_discount_value(item) * -1, ) - line_item.save() invoice_value += line_item.quantity * line_item.price - # TODO: calculate line items from discounts invoice.value = invoice_value + + if invoice.value == 0: + invoice.paid = True + invoice.save() return invoice diff --git a/registrasion/forms.py b/registrasion/forms.py index f1527aa5aa5caf5cde755fcb9037bc0c21342e4d..7a1e1f12dbd23668dce9985b848baf50bd70a026 100644 --- a/registrasion/forms.py +++ b/registrasion/forms.py @@ -47,7 +47,10 @@ class _QuantityBoxProductsForm(_ProductsForm): @classmethod def set_fields(cls, category, products): for product in products: - help_text = "$%d -- %s" % (product.price, product.description) + if product.description: + help_text = "$%d each -- %s" % (product.price, product.description) + else: + help_text = "$%d each" % product.price field = forms.IntegerField( label=product.name, diff --git a/registrasion/templatetags/registrasion_tags.py b/registrasion/templatetags/registrasion_tags.py index 6de13e74cf1fe7f95f557c3fadf2b033059fac30..63a2bc245d0a1fe70e525449e358a99b15e8eec7 100644 --- a/registrasion/templatetags/registrasion_tags.py +++ b/registrasion/templatetags/registrasion_tags.py @@ -35,14 +35,18 @@ def items_pending(context): @register.assignment_tag(takes_context=True) -def items_purchased(context): - ''' Returns all of the items that this user has purchased ''' +def items_purchased(context, category=None): + ''' Returns all of the items that this user has purchased, optionally + from the given category. ''' all_items = rego.ProductItem.objects.filter( cart__user=context.request.user, cart__active=False, ) + if category: + all_items = all_items.filter(product__category=category) + products = set(item.product for item in all_items) out = [] for product in products: diff --git a/registrasion/tests/cart_controller_helper.py b/registrasion/tests/cart_controller_helper.py index 0578229755a93ea39e49b76ed6e8f75fe1477dfd..9e4191f0018ad162da52fce2427a26dee8f810f0 100644 --- a/registrasion/tests/cart_controller_helper.py +++ b/registrasion/tests/cart_controller_helper.py @@ -24,3 +24,7 @@ class TestingCartController(CartController): except ObjectDoesNotExist: old_quantity = 0 self.set_quantity(product, old_quantity + quantity) + + def next_cart(self): + self.cart.active = False + self.cart.save() diff --git a/registrasion/tests/test_cart.py b/registrasion/tests/test_cart.py index 1de72bc90c4c923ebb4e5c59fd1a3908e56b64f5..df5e290fe23a94bbf0a3edb873a23b7321d7ec8b 100644 --- a/registrasion/tests/test_cart.py +++ b/registrasion/tests/test_cart.py @@ -74,12 +74,12 @@ class RegistrationCartTestCase(SetTimeMixin, TestCase): # Burn through some carts -- this made some past EC tests fail current_cart = TestingCartController.for_user(cls.USER_1) - current_cart.cart.active = False - current_cart.cart.save() + + current_cart.next_cart() current_cart = TestingCartController.for_user(cls.USER_2) - current_cart.cart.active = False - current_cart.cart.save() + + current_cart.next_cart() @classmethod def make_ceiling(cls, name, limit=None, start_time=None, end_time=None): @@ -142,8 +142,8 @@ class BasicCartTests(RegistrationCartTestCase): def test_get_cart(self): current_cart = TestingCartController.for_user(self.USER_1) - current_cart.cart.active = False - current_cart.cart.save() + + current_cart.next_cart() old_cart = current_cart @@ -214,8 +214,8 @@ class BasicCartTests(RegistrationCartTestCase): with self.assertRaises(ValidationError): current_cart.add_to_cart(self.PROD_1, 10) - current_cart.cart.active = False - current_cart.cart.save() + + current_cart.next_cart() current_cart = TestingCartController.for_user(self.USER_1) # User should not be able to add 10 of PROD_1 to the current cart now, @@ -272,8 +272,8 @@ class BasicCartTests(RegistrationCartTestCase): with self.assertRaises(ValidationError): current_cart.add_to_cart(self.PROD_3, 1) - current_cart.cart.active = False - current_cart.cart.save() + + current_cart.next_cart() current_cart = TestingCartController.for_user(self.USER_1) # The category limit should extend across carts @@ -298,8 +298,8 @@ class BasicCartTests(RegistrationCartTestCase): current_cart.add_to_cart(self.PROD_4, 1) # The limits should extend across carts... - current_cart.cart.active = False - current_cart.cart.save() + + current_cart.next_cart() current_cart = TestingCartController.for_user(self.USER_1) current_cart.set_quantity(self.PROD_3, 4) @@ -325,8 +325,8 @@ class BasicCartTests(RegistrationCartTestCase): current_cart.add_to_cart(item, quantity) self.assertTrue(item in prods) - current_cart.cart.active = False - current_cart.cart.save() + + current_cart.next_cart() current_cart = TestingCartController.for_user(self.USER_1) diff --git a/registrasion/tests/test_ceilings.py b/registrasion/tests/test_ceilings.py index 94b1c311bf739043f04f449d92a16c482dcc29ad..cc333c2992155966210925c8d88852632e826b49 100644 --- a/registrasion/tests/test_ceilings.py +++ b/registrasion/tests/test_ceilings.py @@ -91,8 +91,8 @@ class CeilingsTestCases(RegistrationCartTestCase): second_cart.add_to_cart(self.PROD_1, 1) # User 2 pays for their cart - second_cart.cart.active = False - second_cart.cart.save() + + second_cart.next_cart() # User 1 should not be able to add item to their cart # because user 2 has paid for their reserved item, exhausting @@ -128,8 +128,8 @@ class CeilingsTestCases(RegistrationCartTestCase): first_cart.validate_cart() # Paid cart outside the reservation window - second_cart.cart.active = False - second_cart.cart.save() + + second_cart.next_cart() self.add_timedelta(self.RESERVATION + datetime.timedelta(seconds=1)) with self.assertRaises(ValidationError): first_cart.validate_cart() @@ -140,15 +140,15 @@ class CeilingsTestCases(RegistrationCartTestCase): first_cart = TestingCartController.for_user(self.USER_1) first_cart.add_to_cart(self.PROD_1, 1) - first_cart.cart.active = False - first_cart.cart.save() + + first_cart.next_cart() second_cart = TestingCartController.for_user(self.USER_2) with self.assertRaises(ValidationError): second_cart.add_to_cart(self.PROD_1, 1) first_cart.cart.released = True - first_cart.cart.save() + first_cart.next_cart() second_cart.add_to_cart(self.PROD_1, 1) @@ -176,8 +176,8 @@ class CeilingsTestCases(RegistrationCartTestCase): cart.add_to_cart(self.PROD_1, 1) self.assertEqual(1, len(cart.cart.discountitem_set.all())) - cart.cart.active = False - cart.cart.save() + + cart.next_cart() # The second cart has no voucher attached, so should apply the # ceiling discount diff --git a/registrasion/tests/test_discount.py b/registrasion/tests/test_discount.py index 1fb4225d7674fc018cf593febd26ee202c4a0fbd..c4211c0fe4d7fb866a07df416f942ff7d2a07596 100644 --- a/registrasion/tests/test_discount.py +++ b/registrasion/tests/test_discount.py @@ -168,8 +168,8 @@ class DiscountTestCase(RegistrationCartTestCase): # Enable the discount during the first cart. cart = TestingCartController.for_user(self.USER_1) cart.add_to_cart(self.PROD_1, 1) - cart.cart.active = False - cart.cart.save() + + cart.next_cart() # Use the discount in the second cart cart = TestingCartController.for_user(self.USER_1) @@ -177,8 +177,8 @@ class DiscountTestCase(RegistrationCartTestCase): # The discount should be applied. self.assertEqual(1, len(cart.cart.discountitem_set.all())) - cart.cart.active = False - cart.cart.save() + + cart.next_cart() # The discount should respect the total quantity across all # of the user's carts. @@ -197,8 +197,8 @@ class DiscountTestCase(RegistrationCartTestCase): cart.add_to_cart(self.PROD_1, 1) # This would exhaust discount if present cart.add_to_cart(self.PROD_2, 2) - cart.cart.active = False - cart.cart.save() + + cart.next_cart() self.add_discount_prod_1_includes_prod_2() cart = TestingCartController.for_user(self.USER_1) @@ -346,9 +346,8 @@ class DiscountTestCase(RegistrationCartTestCase): discounts = discount.available_discounts(self.USER_1, [self.CAT_2], []) self.assertEqual(2, discounts[0].quantity) - inv = InvoiceController.for_cart(cart.cart) - inv.pay("Dummy reference", inv.invoice.value) - self.assertTrue(inv.invoice.paid) + + cart.next_cart() def test_discount_quantity_is_correct_after_first_purchase(self): self.test_discount_quantity_is_correct_before_first_purchase() @@ -358,9 +357,8 @@ class DiscountTestCase(RegistrationCartTestCase): discounts = discount.available_discounts(self.USER_1, [self.CAT_2], []) self.assertEqual(1, discounts[0].quantity) - inv = InvoiceController.for_cart(cart.cart) - inv.pay("Dummy reference", inv.invoice.value) - self.assertTrue(inv.invoice.paid) + + cart.next_cart() def test_discount_is_gone_after_quantity_exhausted(self): self.test_discount_quantity_is_correct_after_first_purchase() @@ -390,12 +388,12 @@ class DiscountTestCase(RegistrationCartTestCase): self.assertEqual(1, len(discounts)) cart.cart.active = False # Keep discount enabled - cart.cart.save() + cart.next_cart() cart = TestingCartController.for_user(self.USER_1) cart.add_to_cart(self.PROD_2, 2) # The discount will be exhausted - cart.cart.active = False - cart.cart.save() + + cart.next_cart() discounts = discount.available_discounts( self.USER_1, @@ -405,7 +403,7 @@ class DiscountTestCase(RegistrationCartTestCase): self.assertEqual(0, len(discounts)) cart.cart.released = True - cart.cart.save() + cart.next_cart() discounts = discount.available_discounts( self.USER_1, diff --git a/registrasion/tests/test_enabling_condition.py b/registrasion/tests/test_enabling_condition.py index 6dd3d10219bf83e9afb24c5b85dd533fa436c86e..bedb6c864548414affd759ce0f7b283112801aa0 100644 --- a/registrasion/tests/test_enabling_condition.py +++ b/registrasion/tests/test_enabling_condition.py @@ -68,8 +68,8 @@ class EnablingConditionTestCases(RegistrationCartTestCase): current_cart = TestingCartController.for_user(self.USER_1) current_cart.add_to_cart(self.PROD_2, 1) - current_cart.cart.active = False - current_cart.cart.save() + + current_cart.next_cart() # Create new cart and try to add PROD_1 current_cart = TestingCartController.for_user(self.USER_1) @@ -103,8 +103,8 @@ class EnablingConditionTestCases(RegistrationCartTestCase): current_cart = TestingCartController.for_user(self.USER_1) current_cart.add_to_cart(self.PROD_3, 1) - current_cart.cart.active = False - current_cart.cart.save() + + current_cart.next_cart() # Create new cart and try to add PROD_1 current_cart = TestingCartController.for_user(self.USER_1) @@ -241,15 +241,15 @@ class EnablingConditionTestCases(RegistrationCartTestCase): cart = TestingCartController.for_user(self.USER_1) cart.add_to_cart(self.PROD_3, 1) - cart.cart.active = False - cart.cart.save() + + cart.next_cart() cart_2 = TestingCartController.for_user(self.USER_1) cart_2.add_to_cart(self.PROD_1, 1) cart_2.set_quantity(self.PROD_1, 0) cart.cart.released = True - cart.cart.save() + cart.next_cart() with self.assertRaises(ValidationError): cart_2.set_quantity(self.PROD_1, 1) @@ -260,15 +260,15 @@ class EnablingConditionTestCases(RegistrationCartTestCase): cart = TestingCartController.for_user(self.USER_1) cart.add_to_cart(self.PROD_2, 1) - cart.cart.active = False - cart.cart.save() + + cart.next_cart() cart_2 = TestingCartController.for_user(self.USER_1) cart_2.add_to_cart(self.PROD_1, 1) cart_2.set_quantity(self.PROD_1, 0) cart.cart.released = True - cart.cart.save() + cart.next_cart() with self.assertRaises(ValidationError): cart_2.set_quantity(self.PROD_1, 1) diff --git a/registrasion/tests/test_invoice.py b/registrasion/tests/test_invoice.py index fd6c9cfb670a513567a546c4dcfac2843384620b..5dc1559b658433b1380a7e5a7264def0627001bf 100644 --- a/registrasion/tests/test_invoice.py +++ b/registrasion/tests/test_invoice.py @@ -83,18 +83,16 @@ class InvoiceTestCase(RegistrationCartTestCase): code="VOUCHER", limit=1 ) - voucher.save() discount = rego.VoucherDiscount.objects.create( description="VOUCHER RECIPIENT", voucher=voucher, ) - discount.save() rego.DiscountForProduct.objects.create( discount=discount, product=self.PROD_1, percentage=Decimal(50), quantity=1 - ).save() + ) current_cart = TestingCartController.for_user(self.USER_1) current_cart.apply_voucher(voucher.code) @@ -111,6 +109,32 @@ class InvoiceTestCase(RegistrationCartTestCase): self.PROD_1.price * Decimal("0.5"), invoice_1.invoice.value) + def test_zero_value_invoice_is_automatically_paid(self): + voucher = rego.Voucher.objects.create( + recipient="Voucher recipient", + code="VOUCHER", + limit=1 + ) + discount = rego.VoucherDiscount.objects.create( + description="VOUCHER RECIPIENT", + voucher=voucher, + ) + rego.DiscountForProduct.objects.create( + discount=discount, + product=self.PROD_1, + percentage=Decimal(100), + quantity=1 + ) + + current_cart = TestingCartController.for_user(self.USER_1) + current_cart.apply_voucher(voucher.code) + + # Should be able to create an invoice after the product is added + current_cart.add_to_cart(self.PROD_1, 1) + invoice_1 = InvoiceController.for_cart(current_cart.cart) + + self.assertTrue(invoice_1.invoice.paid) + def test_invoice_voids_self_if_cart_is_invalid(self): current_cart = TestingCartController.for_user(self.USER_1) @@ -169,3 +193,8 @@ class InvoiceTestCase(RegistrationCartTestCase): with self.assertRaises(ValidationError): invoice_1.void() + + def test_cannot_generate_blank_invoice(self): + current_cart = TestingCartController.for_user(self.USER_1) + with self.assertRaises(ValidationError): + invoice_1 = InvoiceController.for_cart(current_cart.cart) diff --git a/registrasion/tests/test_voucher.py b/registrasion/tests/test_voucher.py index e3ac0d0d3699e3007926a5d0b562154067372f09..a8686fb1d7c3535edad075be0c0e0b5788318e77 100644 --- a/registrasion/tests/test_voucher.py +++ b/registrasion/tests/test_voucher.py @@ -34,8 +34,8 @@ class VoucherTestCases(RegistrationCartTestCase): # user 2 should be able to apply voucher self.add_timedelta(rego.Voucher.RESERVATION_DURATION * 2) cart_2.apply_voucher(voucher.code) - cart_2.cart.active = False - cart_2.cart.save() + + cart_2.next_cart() # After the reservation duration, even though the voucher has applied, # it exceeds the number of vouchers available. @@ -125,8 +125,8 @@ class VoucherTestCases(RegistrationCartTestCase): current_cart = TestingCartController.for_user(self.USER_1) current_cart.apply_voucher(voucher.code) - inv = InvoiceController.for_cart(current_cart.cart) - inv.pay("Hello!", inv.invoice.value) + + current_cart.next_cart() current_cart = TestingCartController.for_user(self.USER_1) @@ -139,9 +139,11 @@ class VoucherTestCases(RegistrationCartTestCase): voucher = self.new_voucher(limit=2) current_cart = TestingCartController.for_user(self.USER_1) current_cart.apply_voucher(voucher.code) + current_cart.add_to_cart(self.PROD_1, 1) inv = InvoiceController.for_cart(current_cart.cart) - inv.pay("Hello!", inv.invoice.value) + if not inv.invoice.paid: + inv.pay("Hello!", inv.invoice.value) current_cart = TestingCartController.for_user(self.USER_1) with self.assertRaises(ValidationError):