def test_proposal_cancelled_disables_condition(self): self._create_proposals() self._create_flag_for_primary_speaker() # USER_1 cannot see PROD_1 until proposal is promoted. available = ProductController.available_products( self.USER_1, products=[self.PROD_1], ) self.assertNotIn(self.PROD_1, available) # promote proposal_1 so that USER_1 becomes a speaker promote_proposal(self.PROPOSAL_1) presentation = schedule_models.Presentation.objects.get( proposal_base=self.PROPOSAL_1 ) presentation.cancelled = True presentation.save() # USER_1 can *NOT* see PROD_1 because proposal_1 has been cancelled available_after_cancelled = ProductController.available_products( self.USER_1, products=[self.PROD_1], ) self.assertNotIn(self.PROD_1, available_after_cancelled)
def test_additional_speaker_enables_item(self): self._create_proposals() self._create_flag_for_additional_speaker() # USER_2 cannot see PROD_1 until proposal is promoted. available = ProductController.available_products( self.USER_2, products=[self.PROD_1], ) self.assertNotIn(self.PROD_1, available) # promote proposal_1 so that USER_2 becomes an additional speaker promote_proposal(self.PROPOSAL_1) # USER_2 can see PROD_1 available_2 = ProductController.available_products( self.USER_2, products=[self.PROD_1], ) self.assertIn(self.PROD_1, available_2) # USER_1 can *NOT* see PROD_1 because they're a presenter available_1 = ProductController.available_products( self.USER_1, products=[self.PROD_1], ) self.assertNotIn(self.PROD_1, available_1)
def test_available_products_works_with_no_conditions_set(self): prods = ProductController.available_products( self.USER_1, category=self.CAT_1, ) self.assertTrue(self.PROD_1 in prods) self.assertTrue(self.PROD_2 in prods) prods = ProductController.available_products( self.USER_1, category=self.CAT_2, ) self.assertTrue(self.PROD_3 in prods) self.assertTrue(self.PROD_4 in prods) prods = ProductController.available_products( self.USER_1, products=[self.PROD_1, self.PROD_2, self.PROD_3, self.PROD_4], ) self.assertTrue(self.PROD_1 in prods) self.assertTrue(self.PROD_2 in prods) self.assertTrue(self.PROD_3 in prods) self.assertTrue(self.PROD_4 in prods)
def test_available_products_on_products_works_when_condition_not_met(self): self.add_product_flag(condition=conditions.FlagBase.ENABLE_IF_TRUE) prods = ProductController.available_products( self.USER_1, products=[self.PROD_1, self.PROD_2], ) self.assertTrue(self.PROD_1 not in prods) self.assertTrue(self.PROD_2 in prods)
def test_speaker_on_different_proposal_kind_does_not_enable_item(self): self._create_proposals() self._create_flag_for_primary_speaker() # USER_1 cannot see PROD_1 until proposal is promoted. available = ProductController.available_products( self.USER_1, products=[self.PROD_1], ) self.assertNotIn(self.PROD_1, available) # promote proposal_2 so that USER_1 becomes a speaker, but of # KIND_2, which is not covered by this condition promote_proposal(self.PROPOSAL_2) # USER_1 cannot see PROD_1 available_1 = ProductController.available_products( self.USER_1, products=[self.PROD_1], ) self.assertNotIn(self.PROD_1, available_1)
def test_available_products_on_products_works_when_condition_is_met(self): self.add_product_flag(condition=conditions.FlagBase.ENABLE_IF_TRUE) cart_1 = TestingCartController.for_user(self.USER_1) cart_1.add_to_cart(self.PROD_2, 1) prods = ProductController.available_products( self.USER_1, products=[self.PROD_1, self.PROD_2], ) self.assertTrue(self.PROD_1 in prods) self.assertTrue(self.PROD_2 in prods)
def test_flag_ceiling_aggregates_products(self): # Create two carts, add 1xprod_1 to each. Ceiling should disappear # after second. self.make_ceiling("Multi-product limit ceiling", limit=2) for i in xrange(2): cart = TestingCartController.for_user(self.USER_1) cart.add_to_cart(self.PROD_1, 1) cart.next_cart() products = ProductController.available_products( self.USER_1, products=[self.PROD_1], ) self.assertEqual(0, len(products))
def product_category(request, category_id): ''' Registration selections form for a specific category of items. ''' PRODUCTS_FORM_PREFIX = "products" VOUCHERS_FORM_PREFIX = "vouchers" # Handle the voucher form *before* listing products. # Products can change as vouchers are entered. v = handle_voucher(request, VOUCHERS_FORM_PREFIX) voucher_form, voucher_handled = v category_id = int(category_id) # Routing is [0-9]+ category = inventory.Category.objects.get(pk=category_id) products = ProductController.available_products( request.user, 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 = { "category": category, "discounts": discounts, "form": products_form, "voucher_form": voucher_form, } return render(request, "registrasion/product_category.html", data)
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. ''' # STOPGAP -- this needs to be elsewhere tbqh from registrasion.controllers.product import ProductController if products is AllProducts: products = inventory.Product.objects.all().select_related( "category", ) available = ProductController.available_products( user, products=products, ) return set(i.category for i in available)
def staff_products_form_factory(user): ''' Creates a StaffProductsForm that restricts the available products to those that are available to a user. ''' products = inventory.Product.objects.all() products = ProductController.available_products(user, products=products) product_ids = [product.id for product in products] product_set = inventory.Product.objects.filter(id__in=product_ids) class StaffProductsForm(forms.Form): ''' Form for allowing staff to add an item to a user's cart. ''' product = forms.ModelChoiceField( widget=forms.Select, queryset=product_set, ) quantity = forms.IntegerField(min_value=0, ) return StaffProductsForm
def guided_registration(request): ''' Goes through the registration process in order, making sure user sees all valid categories. The user must be logged in to see this view. Returns: render: Renders ``registrasion/guided_registration.html``, with the following data:: { "current_step": int(), # The current step in the # registration "sections": sections, # A list of # GuidedRegistrationSections "title": str(), # The title of the page "total_steps": int(), # The total number of steps } ''' SESSION_KEY = "guided_registration_categories" ASK_FOR_PROFILE = 777 # Magic number. Meh. next_step = redirect("guided_registration") sections = [] attendee = people.Attendee.get_instance(request.user) if attendee.completed_registration: return redirect(review) # Step 1: Fill in a badge and collect a voucher code try: profile = attendee.attendeeprofilebase except ObjectDoesNotExist: profile = None # Figure out if we need to show the profile form and the voucher form show_profile_and_voucher = False if SESSION_KEY not in request.session: if not profile: show_profile_and_voucher = True else: if request.session[SESSION_KEY] == ASK_FOR_PROFILE: show_profile_and_voucher = True if show_profile_and_voucher: # Keep asking for the profile until everything passes. request.session[SESSION_KEY] = ASK_FOR_PROFILE voucher_form, voucher_handled = _handle_voucher(request, "voucher") profile_form, profile_handled = _handle_profile(request, "profile") voucher_section = GuidedRegistrationSection( title="Voucher Code", form=voucher_form, ) profile_section = GuidedRegistrationSection( title="Profile and Personal Information", form=profile_form, ) title = "Attendee information" current_step = 1 sections.append(voucher_section) sections.append(profile_section) else: # We're selling products starting = attendee.guided_categories_complete.count() == 0 # Get the next category cats = inventory.Category.objects if SESSION_KEY in request.session: _cats = request.session[SESSION_KEY] cats = cats.filter(id__in=_cats) else: cats = cats.exclude( id__in=attendee.guided_categories_complete.all(), ) cats = cats.order_by("order") request.session[SESSION_KEY] = [] if starting: # Only display the first Category title = "Select ticket type" current_step = 2 cats = [cats[0]] else: # Set title appropriately for remaining categories current_step = 3 title = "Additional items" all_products = inventory.Product.objects.filter( category__in=cats, ).select_related("category") with BatchController.batch(request.user): available_products = set(ProductController.available_products( request.user, products=all_products, )) if len(available_products) == 0: # We've filled in every category attendee.completed_registration = True attendee.save() return next_step for category in cats: products = [ i for i in available_products if i.category == category ] prefix = "category_" + str(category.id) p = _handle_products(request, category, products, prefix) products_form, discounts, products_handled = p section = GuidedRegistrationSection( title=category.name, description=category.description, discounts=discounts, form=products_form, ) if products: # This product category has items to show. sections.append(section) # Add this to the list of things to show if the form # errors. request.session[SESSION_KEY].append(category.id) if request.method == "POST" and not products_form.errors: # This is only saved if we pass each form with no # errors, and if the form actually has products. attendee.guided_categories_complete.add(category) if sections and request.method == "POST": for section in sections: if section.form.errors: break else: attendee.save() if SESSION_KEY in request.session: del request.session[SESSION_KEY] # We've successfully processed everything return next_step data = { "current_step": current_step, "sections": sections, "title": title, "total_steps": 3, } return render(request, "registrasion/guided_registration.html", data)
def product_category(request, category_id): ''' Form for selecting products from an individual product category. Arguments: category_id (castable to int): The id of the category to display. Returns: redirect or render: If the form has been sucessfully submitted, redirect to ``dashboard``. Otherwise, render ``registrasion/product_category.html`` with data:: { "category": category, # An inventory.Category for # category_id "discounts": discounts, # A list of # DiscountAndQuantity "form": products_form, # A form for selecting # products "voucher_form": voucher_form, # A form for entering a # voucher code } ''' PRODUCTS_FORM_PREFIX = "products" VOUCHERS_FORM_PREFIX = "vouchers" # Handle the voucher form *before* listing products. # Products can change as vouchers are entered. v = _handle_voucher(request, VOUCHERS_FORM_PREFIX) voucher_form, voucher_handled = v category_id = int(category_id) # Routing is [0-9]+ category = inventory.Category.objects.get(pk=category_id) with BatchController.batch(request.user): products = ProductController.available_products( request.user, 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 if products_form.has_changed(): messages.success( request, "Your reservations have been updated.", ) return redirect(review) data = { "category": category, "discounts": discounts, "form": products_form, "voucher_form": voucher_form, } return render(request, "registrasion/product_category.html", data)
def get_prods(): return ProductController.available_products( self.USER_1, products=[self.PROD_2, self.PROD_3, self.PROD_4], )
def product_category(request, category_id): ''' Form for selecting products from an individual product category. Arguments: category_id (castable to int): The id of the category to display. Returns: redirect or render: If the form has been sucessfully submitted, redirect to ``dashboard``. Otherwise, render ``registrasion/product_category.html`` with data:: { "category": category, # An inventory.Category for # category_id "discounts": discounts, # A list of # DiscountAndQuantity "form": products_form, # A form for selecting # products "voucher_form": voucher_form, # A form for entering a # voucher code } ''' PRODUCTS_FORM_PREFIX = "products" VOUCHERS_FORM_PREFIX = "vouchers" # Handle the voucher form *before* listing products. # Products can change as vouchers are entered. v = _handle_voucher(request, VOUCHERS_FORM_PREFIX) voucher_form, voucher_handled = v category_id = int(category_id) # Routing is [0-9]+ category = inventory.Category.objects.get(pk=category_id) with BatchController.batch(request.user): products = ProductController.available_products( request.user, 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 = { "category": category, "discounts": discounts, "form": products_form, "voucher_form": voucher_form, } return render(request, "registrasion/product_category.html", data)
def guided_registration(request, page_id=0): ''' Goes through the registration process in order, making sure user sees all valid categories. WORK IN PROGRESS: the finalised version of this view will allow grouping of categories into a specific page. Currently, it just goes through each category one by one ''' SESSION_KEY = "guided_registration_categories" ASK_FOR_PROFILE = 777 # Magic number. Meh. next_step = redirect("guided_registration") sections = [] attendee = people.Attendee.get_instance(request.user) if attendee.completed_registration: return render( request, "registrasion/guided_registration_complete.html", {}, ) # Step 1: Fill in a badge and collect a voucher code try: profile = attendee.attendeeprofilebase except ObjectDoesNotExist: profile = None # Figure out if we need to show the profile form and the voucher form show_profile_and_voucher = False if SESSION_KEY not in request.session: if not profile: show_profile_and_voucher = True else: if request.session[SESSION_KEY] == ASK_FOR_PROFILE: show_profile_and_voucher = True if show_profile_and_voucher: # Keep asking for the profile until everything passes. request.session[SESSION_KEY] = ASK_FOR_PROFILE voucher_form, voucher_handled = handle_voucher(request, "voucher") profile_form, profile_handled = handle_profile(request, "profile") voucher_section = GuidedRegistrationSection( title="Voucher Code", form=voucher_form, ) profile_section = GuidedRegistrationSection( title="Profile and Personal Information", form=profile_form, ) title = "Attendee information" current_step = 1 sections.append(voucher_section) sections.append(profile_section) else: # We're selling products starting = attendee.guided_categories_complete.count() == 0 # Get the next category cats = inventory.Category.objects if SESSION_KEY in request.session: _cats = request.session[SESSION_KEY] cats = cats.filter(id__in=_cats) else: cats = cats.exclude( id__in=attendee.guided_categories_complete.all(), ) cats = cats.order_by("order") request.session[SESSION_KEY] = [] if starting: # Only display the first Category title = "Select ticket type" current_step = 2 cats = [cats[0]] else: # Set title appropriately for remaining categories current_step = 3 title = "Additional items" all_products = inventory.Product.objects.filter( category__in=cats, ).select_related("category") available_products = set(ProductController.available_products( request.user, products=all_products, )) if len(available_products) == 0: # We've filled in every category attendee.completed_registration = True attendee.save() return next_step for category in cats: products = [ i for i in available_products if i.category == category ] prefix = "category_" + str(category.id) p = handle_products(request, category, products, prefix) products_form, discounts, products_handled = p section = GuidedRegistrationSection( title=category.name, description=category.description, discounts=discounts, form=products_form, ) if products: # This product category has items to show. sections.append(section) # Add this to the list of things to show if the form errors. request.session[SESSION_KEY].append(category.id) if request.method == "POST" and not products_form.errors: # This is only saved if we pass each form with no errors, # and if the form actually has products. attendee.guided_categories_complete.add(category) if sections and request.method == "POST": for section in sections: if section.form.errors: break else: attendee.save() if SESSION_KEY in request.session: del request.session[SESSION_KEY] # We've successfully processed everything return next_step data = { "current_step": current_step, "sections": sections, "title": title, "total_steps": 3, } return render(request, "registrasion/guided_registration.html", data)