def tickets_reserved(flow=None, currency=None): if current_user.is_anonymous: return redirect(url_for('users.login', next=url_for('.tickets_reserved', flow=flow))) basket = Basket(current_user, get_user_currency()) basket.load_purchases_from_db() basket.save_to_session() if currency in CURRENCY_SYMBOLS: set_user_currency(currency) return redirect(url_for('tickets.pay', flow=flow))
def tickets_reserved(flow=None, currency=None): if current_user.is_anonymous: return redirect( url_for("users.login", next=url_for(".tickets_reserved", flow=flow)) ) basket = Basket(current_user, get_user_currency()) basket.load_purchases_from_db() basket.save_to_session() if currency in CURRENCY_SYMBOLS: set_user_currency(currency) return redirect(url_for("tickets.pay", flow=flow))
def handle_ticket_selection(form, view: ProductView, flow: str, basket: Basket): """ For consistency and to avoid surprises, we try to ensure a few things here: - if the user successfully submits a form with no errors, their basket is updated - if they don't, the basket is left untouched - the basket is updated to match what was submitted, even if they added tickets in another tab - if they already have tickets in their basket, only reserve the extra tickets as necessary - don't unreserve surplus tickets until the payment is created - if the user hasn't submitted anything, we use their current reserved ticket counts - if the user has reserved tickets from exhausted tiers on this view, we still show them - if the user has reserved tickets from other views, don't show and don't mess with them - this means the user can combine tickets from multiple views into a single basket - show the sold-out/unavailable states only when the user doesn't have reserved tickets We currently don't deal with multiple price tiers being available around the same time. Reserved tickets from a previous tier should be cancelled before activating a new one. """ if form.currency_code.data != get_user_currency(): set_user_currency(form.currency_code.data) # Commit so we don't lose the currency change if an error occurs db.session.commit() # Reload the basket because set_user_currency has changed it under us basket = Basket.from_session(current_user, get_user_currency()) form.add_to_basket(basket) if not any(basket.values()): empty_baskets.inc() if view.type == "tickets": flash("Please select at least one ticket to buy.") elif view.type == "hire": flash("Please select at least one item to hire.") else: flash("Please select at least one item to buy.") basket.save_to_session() return redirect(url_for("tickets.main", flow=flow)) # Ensure this purchase is valid for this voucher. voucher = Voucher.get_by_code(basket.voucher) if voucher and not voucher.check_capacity(basket): basket.save_to_session() if voucher.is_used: flash("Your voucher has been used by someone else.") else: flash(f"You can only purchase {voucher.tickets_remaining} adult " "tickets with this voucher. Please select fewer tickets.") return redirect(url_for("tickets.main", flow=flow)) app.logger.info("Saving basket %s", basket) try: # Convert the user's basket into a purchase. basket.create_purchases() basket.ensure_purchase_capacity() db.session.commit() except CapacityException as e: # Damn, capacity's gone since we created the purchases # Redirect back to show what's currently in the basket db.session.rollback() no_capacity.inc() app.logger.warn("Limit exceeded creating tickets: %s", e) flash( "We're very sorry, but there is not enough capacity available to " "allocate these tickets. You may be able to try again with a smaller amount." ) return redirect(url_for("tickets.main", flow=flow)) basket.save_to_session() if basket.total != 0: # Send the user off to pay return redirect(url_for("tickets.pay", flow=flow)) else: return handle_free_tickets(flow, view, basket)