def admin_queue_view(self): # Enact the kicking of customers :) if "action" in self.request.GET and self.request.GET[ "action"] == "kick": client = self.request.GET["client"] if client in self.request.root.active: Queue(self.request).remove_from_active(client) # Run a few other timeout checks Queue(self.request).check_for_timeouts() Queue(self.request).check_active() return {}
def confirmation_view(self): # Check we can be here - doesn't matter about timeouts here if not self.details_complete or len(self.user.payments) <= 0: self.request.session.flash( "You must complete all of your guest's details before continuing.", "error") return HTTPFound(location=self.request.route_path("order_details")) # Ok, all good user = self.request.root.users[self.request.session["user_id"]] if not "payment_id" in self.request.session: return HTTPFound( location=self.request.route_path("pay_for_tickets")) payments = [ x for x in user.payments if x.ref_code == self.request.session["payment_id"] ] if len(payments) <= 0: return HTTPFound( location=self.request.route_path("pay_for_tickets")) payment = payments[0] logging.info("%s: Confirm purchase of tickets - payment: %s" % (self.user.username, payment.__name__)) # Send the confirmation message try: confirm = PurchaseConfirmationEmail(self.request) if not confirm.compose_and_send(payment.ref_code): self.request.session.flash( "Could not send your order confirmation, please contact [email protected]", "error") logging.error( "%s: Failed to send order confirmation for payment %s" % (self.user.username, payment.__name__)) except Exception as e: self.request.session.flash( "Could not send your order confirmation, please contact [email protected]", "error") logging.exception( "%s: An error occurred while trying to send payment confirmation: %s" % (self.user.username, str(e))) # As we are at the end of the process - clean up if self.request.root.properties[PROP.QUEUE_ENABLED]: Queue(self.request).remove_from_active( self.request.session["active_id"]) # - Must remove payment ID or a second purchase would use the same ID! self.request.session.pop("payment_id", None) method = self.get_payment_method(payment.current_method) return { "payment": payment, "method": method, "deadlined": (method != None and method.deadlined), "stripe": (payment.method == "stripe"), "banktransfer": (payment.method == "banktransfer"), "cheque": (payment.method == "cheque"), "due_date": (payment.opened_date + timedelta(days=self.payment_window)).strftime("%d/%m/%Y"), }
def client_time_left(self, client_id): if not client_id in self.request.root.active: return "-" seconds = Queue(self.request).purchase_time_left(active_id=client_id) minutes = int(floor(seconds / 60.0)) rem_seconds = seconds - minutes * 60 str_time = "%i:%.2i" % (minutes, rem_seconds) return str_time
def pay_view(self): # Check we can be here # - First check queue/active status if Queue(self.request).timed_out(): return HTTPFound(self.request.route_path("purchase_timeout")) # Now details elif not self.details_complete: self.request.session.flash( "You must complete all of your guest's details before continuing.", "error") return HTTPFound(location=self.request.route_path("order_details")) elif "method" in self.request.GET: logging.info("%s: Chose %s as their payment method" % (self.user.username, self.request.GET["method"])) # Check this is a valid, registered payment method method = [ x for x in PROP.getProperty(self.request, PROP.PAYMENT_METHODS) if x.enabled and x.__name__.lower() == self.request.GET["method"].lower() ] if len(method) > 0: method = method[0] # Look for a route to make this payment by try: route_url = self.request.route_path("pay_" + method.__name__) return HTTPFound(location=route_url) except (KeyError): self.request.session.flash( "An error occurred with the payment method you selected, please try again.", "error") logging.info( "%s: Tried to request an unknown payment method" % self.user.username) else: self.request.session.flash( "An error occurred with the payment method you selected, please try again.", "error") logging.info("%s: Tried to request an unknown payment method" % self.user.username) # Clear any previous payment reference self.request.session.pop("payment_id", None) # Ok, all good user = self.request.root.users[self.request.session["user_id"]] tickets = [x for x in user.tickets if x.payment == None] if len(tickets) == 0: return HTTPFound(location=self.request.route_path("buy_tickets")) # Work out what payment methods are available to us enabled_methods = [ x for x in PROP.getProperty(self.request, PROP.PAYMENT_METHODS) if x.enabled and x.public ] eligible_methods = [ x for x in enabled_methods if len(x.groups) == 0 or self.user.__parent__ in x.groups ] return {"methods": eligible_methods}
def welcome_view(self): # Check whether the site is setup? if not "properties" in self.request.root.__dict__: print "Need to setup site!" return HTTPFound(location=self.request.route_path("setup")) # If queue enabled, deal with it elif not self.has_queued: return HTTPFound(location=self.request.route_path("queue")) # Check queue/active status elif Queue(self.request).timed_out(): return HTTPFound(self.request.route_path("purchase_timeout")) elif "user_id" in self.request.session and self.request.session[ "user_id"] in self.context.users: return HTTPFound(location=self.request.route_path("branch_flow")) return {}
def has_queued(self): if not self.request.root.properties[PROP.QUEUE_ENABLED]: return True elif "active_id" in self.request.session: active_id = self.request.session["active_id"] if active_id in self.request.root.active: #active = self.request.root.active[active_id] time_left = Queue( self.request).purchase_time_left(active_id=active_id) if time_left <= 0: return False else: return True else: return False else: return False
def buy_view(self): # Check agreements if not self.user.purchase_agreement: return HTTPFound( location=self.request.route_path("purchase_agreement_act")) elif not self.user.privacy_agreement: return HTTPFound( location=self.request.route_path("privacy_policy_act")) # Check we can be here # - First check queue/active status if Queue(self.request).timed_out(): return HTTPFound(self.request.route_path("purchase_timeout")) # - Check if group is currently allowed to purchase elif self.request.root.properties[ PROP. CUSTOMER_CONTROL_ENABLED] and self.group.__name__ not in self.request.root.properties[ PROP.CONTROL_GROUPS]: self.request.session.flash( "Sorry but you are currently not allowed to purchase tickets, please come back later.", "info") return HTTPFound(location=self.request.route_path("user_profile")) # - Now check user details elif not self.user_details_complete: self.request.session.flash( "You must complete all of your profile details before purchasing tickets.", "error") return HTTPFound( location=self.request.route_path("user_profile_edit")) # Ok, all good user = self.user # First ensure that the queuer object has reference to user queuer = self.queue_item if queuer != None: queuer.user_id = user.__name__ # Then return any previous order issue = Issuer(self.request.root) try: issue.returnUnpurchasedTickets(user.__name__) except Exception, e: logging.exception( "%s: Had issue returning previously unpurchased tickets: %s" % (self.user.username, str(e))) self.request.session.flash( "Had an issue returning previously unpurchased tickets, please try again.", "error")
def order_details_view(self): # Check we can be here # - First check queue/active status if Queue(self.request).timed_out(): return HTTPFound(self.request.route_path("purchase_timeout")) # - Now user details elif not self.user_details_complete: self.request.session.flash( "You must complete all of your profile details before purchasing tickets.", "error") return HTTPFound( location=self.request.route_path("user_profile_edit")) # Ok, all good user = self.request.root.users[self.request.session["user_id"]] tickets = [x for x in user.tickets if x.payment == None] if len(tickets) == 0: return HTTPFound(location=self.request.route_path("buy_tickets")) if self.guest_details_required: # If a user is only buying 1 ticket and hasn't already purchased, mark as own if len(tickets) == 1 and len( [x for x in user.tickets if x.payment != None]) == 0: tickets[0].guest_info = user.profile # Don't want to allow marking if person already has a marked ticket if "mark" in self.request.GET and self.user_ticket() == None: mark_id = self.request.GET["mark"] filter_ticks = [x for x in tickets if x.__name__ == mark_id] if len(filter_ticks) == 1: for tick in tickets: if tick.guest_info == tick.owner.profile: tick.guest_info = None to_mark = filter_ticks[0] to_mark.guest_info = user.profile else: # Mark all tickets as having the owner's profile - just simplifies compatibility issues for tick in tickets: tick.guest_info = user.profile # Check all users have the correct data and then proceed user_tick = False missing_details = False if self.guest_details_required: for tick in tickets: if tick.guest_info == None: missing_details = True # Need to more completely validate profile here break elif tick.guest_info == tick.owner.profile and user_tick == True: user_tick = False break elif tick.guest_info == tick.owner.profile: user_tick = True else: user_tick = True missing_details = False # Check if we can move forward a stage if "submit" in self.request.POST: # Report errors or allow us to continue if user_tick == False and self.user_ticket() == None: self.request.session.flash( "You must mark a ticket as your own.", "error") return {} elif missing_details: self.request.session.flash( "You haven't completed all of the information required for your guests.", "error") return {} else: return HTTPFound( location=self.request.route_path("pay_for_tickets")) # Check whether the back button should go to addons or buy view addons = False for ticket in tickets: for addon in ticket.tick_type.addons.values(): if addon.unlimited: addons = True break elif (addon.total_released - len(addon.allocated)) > 0: addons = True break return { "needs_info": ((user_tick == False and self.user_ticket() == None) or missing_details), "addons": addons }
def addons_view(self): # Check we can be here # - First check queue/active status if Queue(self.request).timed_out(): return HTTPFound(self.request.route_path("purchase_timeout")) # - Now user details elif not self.user_details_complete: self.request.session.flash( "You must complete all of your profile details before purchasing tickets.", "error") return HTTPFound( location=self.request.route_path("user_profile_edit")) # Ok, all good user = self.request.root.users[self.request.session["user_id"]] tickets = [x for x in user.tickets if x.payment == None] if len(tickets) == 0: return HTTPFound(location=self.request.route_path("buy_tickets")) # Stock check that we have some add-ons left addons = False for ticket in tickets: for addon in ticket.tick_type.addons.values(): if addon.unlimited: addons = True break elif (addon.total_released - len(addon.allocated)) > 0: addons = True break if not addons: return HTTPFound(location=self.request.route_path("order_details")) # If they submitted the form then try issuing the add-ons if "submit" in self.request.POST: try: # For each ticket we have check for selected add-ons for ticket in tickets: selected_addons = self.request.params.getall( ticket.__name__ + "_addons") ticket.release_addons() issue = Issuer(self.request.root) for addon_key in selected_addons: try: issue.issueAddon(self.user.__name__, ticket, addon_key) except InvalidOrder: logging.error( "%s: Attempted to double issue addon" % self.user.username) pass # Double issue of an add-on return HTTPFound( location=self.request.route_path("order_details")) except MultipleExclusives: self.request.session.flash( "You selected two exclusive add-ons for a single ticket, please only select one.", "error") except OutOfStock: self.request.session.flash( "Unfortunately one of the add-ons you chose is no longer available in the quantity you requested, please try again.", "error") # Make sure to release any claimed add-ons if we have gotten here (i.e. errored) for ticket in tickets: ticket.release_addons() return {}
def pay_stripe_view(self, error=None): # Check if the customer's session has timed out if Queue(self.request).timed_out(): return HTTPFound(self.request.route_path("purchase_timeout")) # Check the customer is ready to pay if not self.details_complete: self.request.session.flash( "Your guest details are incomplete, please update these before continuing.", "info") return HTTPFound(location=self.request.route_path("order_details")) # Verify stripe is enabled all_methods = PROP.getProperty(self.request, PROP.PAYMENT_METHODS) method = [ x for x in all_methods if x.__name__ == "stripe" and x.enabled == True ] method = method[0] if len(method) > 0 else None if method == None: self.request.session.flash( "An error occurred with the payment method you selected, please try another.", "error") return HTTPFound(location=self.request.route_path("order_details")) # Retrieve stripe processing values process_percentage = method.settings[ PROP.PAYMENT_PROCESSING_PERCENTAGE].value process_fee = method.settings[PROP.PAYMENT_PROCESSING_FEE].value pub_api_key = method.settings[PROP.STRIPE_PUBLIC_KEY].value organisation_name = method.settings[PROP.ORGANISATION_NAME].value contact_email = method.settings[PROP.STRIPE_CONTACT_EMAIL].value # Check what the user has to buy if len(self.session_tickets) == 0: self.request.session.flash( "No tickets were found in your shopping basket, please try again.", "error") return HTTPFound(location=self.request.route_path("user_profile")) # Calculate the amount to pay subtotal = 0 for tick in self.session_tickets: subtotal += tick.total_cost processing = int(ceil(subtotal * process_percentage) + process_fee) total = subtotal + processing # Render the payment page return { "error": error, "method": method, "subtotal": self.format_price(subtotal), "processing": self.format_price(processing), "total": self.format_price(total), "org_name": organisation_name, "contact_email": contact_email, "stripe_pub_key": pub_api_key, "penny_total": total, "pay_description": str(len(self.session_tickets)) + " Ticket(s)", "alteration": False, "payment": None }
def banktransfer_view(self): # Detect a payment alteration payment_id = None payment = None if "payment_id" in self.request.matchdict: payment_id = self.request.matchdict["payment_id"] # Check we can be here methods = PROP.getProperty(self.request, PROP.PAYMENT_METHODS) method = [x for x in methods if x.__name__ == "banktransfer" and x.enabled == True] # - First check queue/active status if payment_id == None and Queue(self.request).timed_out(): return HTTPFound(self.request.route_path("purchase_timeout")) # - Now details elif payment_id == None and not self.details_complete: self.request.session.flash("You must complete all of your guest's details before continuing.", "error") return HTTPFound(location=self.request.route_path("order_details")) # - Check that the payment method is enabled? elif len(method) <= 0: self.request.session.flash("There was an error with the payment method you selected, please try again.", "error") return HTTPFound(location=self.request.route_path("pay_for_tickets")) # - Now run some checks that this person actually should be able to pay this elif payment_id != None: if not payment_id in self.request.root.payments: self.request.session.flash("The requested payment does not exist.", "error") return HTTPFound(location=self.request.route_path("user_profile")) else: payment = self.request.root.payments[payment_id] if payment.owner != self.user: self.request.session.flash("The requested payment could not be found on your account.", "error") return HTTPFound(location=self.request.route_path("user_profile")) elif payment.paid: self.request.session.flash("The requested payment has already been completed, no need to alter the payment.", "error") return HTTPFound(location=self.request.route_path("user_profile")) # Get method, processing fee & other parameters method = method[0] process_fee = method.settings[PROP.PAYMENT_PROCESSING_FEE].value org_name = method.get_value(PROP.ORGANISATION_NAME) account_number = method.get_value(PROP.BANK_ACCOUNT) sort_code = method.get_value(PROP.BANK_SORT_CODE) if payment_id == None: tickets = [x for x in self.user.tickets if x.payment == None] if len(tickets) == 0: return HTTPFound(location=self.request.route_path("buy_tickets")) subtotal = 0 for tick in tickets: subtotal += tick.total_cost processing = process_fee total = subtotal + processing if "action" in self.request.GET and self.request.GET["action"] == "pay": if "payment_id" in self.request.session: ref_code = self.request.session["payment_id"] payment = Issuer(self.request.root).constructPayment( user_id=self.user.__name__, paid=False, ref_code=ref_code ) stage = PaymentStage() stage.__parent__ = payment stage.method = "banktransfer" stage.processing_charge = processing stage.stage_owner = self.user.__name__ payment.history.append(stage) return HTTPFound(location=self.request.route_path("pay_confirm")) if not "payment_id" in self.request.session: # NEED TO CHECK FOR UNIQUENESS self.request.session["payment_id"] = Coding().generateUniqueCode(short=True,withdash=False) return { "method": method, "subtotal": self.format_price(subtotal), "processing": self.format_price(processing), "total": self.format_price(total), "org_name": org_name, "alteration": False, "account_number": account_number, "sort_code": sort_code, "payment_id": self.request.session["payment_id"], "payment": None, "due_date": (datetime.now() + timedelta(days=self.payment_window)).strftime("%d/%m/%Y"), } else: subtotal = payment.amount_remaining processing = process_fee total = subtotal + processing if payment.current_method == "banktransfer": subtotal = payment.current_stage.amount_remaining processing = payment.current_stage.processing_charge total = subtotal + processing if "action" in self.request.GET and self.request.GET["action"] == "pay": # Don't bother adding a payment stage if we are already paying this way! if payment.current_method != "banktransfer": # Add a new stage to the payment new_stage = PaymentStage() new_stage.__parent__ = payment new_stage.method = "banktransfer" new_stage.method_change = True new_stage.processing_charge = processing new_stage.stage_owner = self.user.__name__ payment.history.append(new_stage) # Forward on to the correct place return HTTPFound(location=self.request.route_path("alter_confirm", payment_id=payment_id)) return { "method": method, "subtotal": self.format_price(subtotal), "processing": self.format_price(processing), "total": self.format_price(total), "org_name": org_name, "alteration": True, "account_number": account_number, "sort_code": sort_code, "payment_id": payment_id, "payment": payment, "due_date": (datetime.now() + timedelta(days=self.payment_window)).strftime("%d/%m/%Y"), }
def stripe_view(self): # Detect a payment alteration payment_id = None payment = None if "payment_id" in self.request.matchdict: payment_id = self.request.matchdict["payment_id"] # Check we can be here methods = PROP.getProperty(self.request, PROP.PAYMENT_METHODS) method = [ x for x in methods if x.__name__ == "stripe" and x.enabled == True ] # - First check queue/active status if payment_id == None and Queue(self.request).timed_out(): return HTTPFound(self.request.route_path("purchase_timeout")) # - Now details elif payment_id == None and not self.details_complete: self.request.session.flash( "You must complete all of your guest's details before continuing.", "error") return HTTPFound(location=self.request.route_path("order_details")) # - Check that the payment method is enabled? elif len(method) <= 0: self.request.session.flash( "There was an error with the payment method you selected, please try again.", "error") return HTTPFound( location=self.request.route_path("pay_for_tickets")) # - Now run some checks that this person actually should be able to pay this elif payment_id != None: if not payment_id in self.request.root.payments: self.request.session.flash( "The requested payment does not exist.", "error") return HTTPFound( location=self.request.route_path("user_profile")) else: payment = self.request.root.payments[payment_id] if payment.owner != self.user: self.request.session.flash( "The requested payment could not be found on your account.", "error") return HTTPFound( location=self.request.route_path("user_profile")) elif payment.paid: self.request.session.flash( "The requested payment has already been completed, no need to alter the payment.", "error") return HTTPFound( location=self.request.route_path("user_profile")) method = method[0] # Get some property values process_percentage = method.settings[ PROP.PAYMENT_PROCESSING_PERCENTAGE].value process_fee = method.settings[PROP.PAYMENT_PROCESSING_FEE].value pub_api_key = method.settings[PROP.STRIPE_PUBLIC_KEY].value organisation_name = method.settings[PROP.ORGANISATION_NAME].value contact_email = method.settings[PROP.STRIPE_CONTACT_EMAIL].value # Ok, all good user = self.request.root.users[self.request.session["user_id"]] tickets = [x for x in user.tickets if x.payment == None] if payment_id == None and len(tickets) == 0: return HTTPFound(location=self.request.route_path("buy_tickets")) subtotal = 0 for tick in tickets: subtotal += tick.total_cost # If we have submitted a Stripe purchase error = None if "stripeToken" in self.request.POST: stripe.api_key = method.settings[PROP.STRIPE_API_KEY].value token = self.request.POST["stripeToken"] if payment_id == None: # Create the holder Stripe payment first, but don't store payment = None try: payment = Issuer(self.request.root).constructPayment( user_id=self.request.session["user_id"] # ref_code is auto generated ) # Try running purchase charge = None try: processing = int( ceil(subtotal * process_percentage) + process_fee) total = int(subtotal + processing) # Create the Stripe charge charge = stripe.Charge.create( amount=total, currency="gbp", source=token, description=organisation_name, ) if "paid" in charge and charge["paid"] == True: stage = PaymentStage() stage.__parent__ = payment stage.method = "stripe" stage.method_properties["last_four"] = charge[ "source"]["last4"] stage.method_properties["ref_code"] = charge["id"] stage.amount_paid = total stage.processing_charge = processing stage.completed = True stage.stage_owner = user.__name__ payment.history.append(stage) payment.completed_date = datetime.now() self.request.session[ "payment_id"] = payment.ref_code logging.info( self.user.username + ": Stripe charge %s succeeded for payment %s" % (charge["id"], payment.__name__)) return HTTPFound(location=self.request.route_path( "pay_confirm")) else: if "failure_message" in charge and charge[ "failure_message"] != None: error = charge["failure_message"] logging.error(self.user.username + ": Stripe refused charge: %s" % error) else: logging.error(self.user.username + ": Stripe refused charge") error = "Charge was not accepted by Stripe" except stripe.error.CardError, e: logging.error( self.user.username + ": Stripe invalid card error occurred: %s" % e) error = e except stripe.error.InvalidRequestError, e: logging.error( self.user.username + ": Stripe invalid card request occurred: %s" % e) error = e except stripe.error.RateLimitError, e: logging.error(self.user.username + ": Stripe rate limit error: %s" % e) error = "Too many people are trying to pay right now, please try again in a moment" except stripe.error.AuthenticationError, e: logging.error(self.user.username + ": Stripe authentication error: %s" % e) error = "An authentication error occurred trying to connect to Stripe, please contact the committee"
def time_left(self): return Queue(self.request).purchase_time_left()