def payment_stage_view(self): if not self.request.matchdict["ref_code"] in self.request.root.payments: return HTTPFound( location=self.request.route_path("admin_payments")) payment = self.request.root.payments[ self.request.matchdict["ref_code"]] stage_index = int(float(self.request.matchdict["stage_index"])) if stage_index < 0 or stage_index >= len(payment.history): return HTTPFound(location=self.request.route_path( "admin_single_payment", ref_code=payment.__name__)) if "action" in self.request.GET and self.request.GET[ "action"] == "delete": if len(payment.history) <= 1: self.request.session.flash( "Must have at least one payment left undeleted", "error") else: del payment.history[stage_index] # Need to work out if still paid? if payment.amount_remaining > 0: payment.completed_date = None # Check if the latest stage has been paid into yet? latest = payment.history[-1] if latest.completed: # Add a new payment stage of the same type as the latest new_stage = PaymentStage() new_stage.__parent__ = payment new_stage.method = latest.method new_stage.stage_owner = payment.owner.__name__ payment.history.append(new_stage) self.request.session.flash( "Removed payment stage successfully", "info") return HTTPFound(location=self.request.route_path( "admin_single_payment", ref_code=payment.__name__)) return {"payment": payment, "stage": payment.history[stage_index]}
def change_payment_method_view(self): payments = self.request.root.payments # Get payment if possible if not self.request.matchdict["ref_code"] in self.request.root.payments: return HTTPFound( location=self.request.route_path("admin_payments")) payment = payments[self.request.matchdict["ref_code"]] active_stage = (payment.history[len(payment.history) - 1] if (len(payment.history) > 0) else None) # Check if already marked as paid if payment.paid: return HTTPFound(location=self.request.route_path( 'admin_single_payment', ref_code=payment.__name__)) # Deal with post request if "submit" in self.request.POST: if not "method" in self.request.POST: self.request.session.flash( "Make sure to select a new payment method.", "error") else: method = self.request.POST["method"] # - First check if the active stage is the current method if active_stage.method != method: # Update payment method to match that entered active_stage = PaymentStage() active_stage.__parent__ = payment active_stage.method = method active_stage.stage_owner = payment.owner.__name__ active_stage.amount_paid = 0 active_stage.processing_charge = 0 active_stage.completed = False payment.history.append(active_stage) self.request.session.flash( "Payment details have been updated.", "info") return HTTPFound(location=self.request.route_path( 'admin_single_payment', ref_code=payment.__name__)) return { "payment": payment, "active_stage": active_stage, "methods": PROP_KEYS.getProperty(self.request, PROP_KEYS.PAYMENT_METHODS) }
def guest_info_edit_pay_view(self): # Get the ticket details user = self.user tick_id = (self.request.matchdict["tick_id"] if "tick_id" in self.request.matchdict else None) if tick_id == None: self.request.session.flash( "An error occurred whilst trying to retrieve the ticket details.", "error") return HTTPFound(location=self.request.route_path("ticket_details", tick_id=tick_id)) # Check guest details requirement is actually enabled if not self.guest_details_required: return HTTPFound(location=self.request.route_path("ticket_details", tick_id=tick_id)) # Try getting the ticket try: ticket = [x for x in user.tickets if x.__name__ == tick_id][0] except Exception: self.request.session.flash( "An error occurred whilst trying to retrieve the ticket details.", "error") return HTTPFound(location=self.request.route_path("ticket_details", tick_id=tick_id)) # Check if this ticket is locked down locked_down = ticket.tick_type.locked_down if not locked_down: # Check all addons as well for addon in ticket.addons.values(): if addon.locked_down: locked_down = True break if locked_down: self.request.session.flash( "Editing of guest details for this ticket has been disabled.", "info") return HTTPFound(location=self.request.route_path("ticket_details", tick_id=tick_id)) # Check that we haven't already paid for editing of this ticket and that we have to in the first place! if (self.details_fee_enabled and ticket.change_enabled) or not self.details_fee_enabled: return HTTPFound(location=self.request.route_path( "ticket_edit_guest", tick_id=tick_id)) # Check if the user first needs to complete payment if not ticket.payment.paid: self.request.session.flash( "You must complete payment for this ticket before editing guest details.", "info") return HTTPFound(location=self.request.route_path("ticket_details", tick_id=tick_id)) # If this is the owners ticket then don't allow them to change the details if ticket.guest_info == ticket.owner.profile: return HTTPFound( location=self.request.route_path("user_profile_edit")) # If we receive a payment then deal with it if "stripeToken" in self.request.POST: # Run Stripe payment to authorise organisation_name = self.get_payment_method('stripe').settings[ PROP_KEYS.ORGANISATION_NAME].value details_fee = PROP_KEYS.getProperty(self.request, PROP_KEYS.DETAILS_FEE) token = self.request.POST["stripeToken"] stripe.api_key = self.get_payment_method('stripe').settings[ PROP_KEYS.STRIPE_API_KEY].value charge = None error = None try: charge = stripe.Charge.create(amount=details_fee, currency="gbp", source=token, description=organisation_name) if "paid" in charge and charge["paid"] == True: # Update the ticket that a guest alteration is allowed and then forward to the editing form ticket.change_enabled = True # Append a payment stage covering the detail change charge charge_stage = PaymentStage() charge_stage.__parent__ = ticket.payment charge_stage.method_properties["last_four"] = charge[ "source"]["last4"] charge_stage.method_properties["ref_code"] = charge["id"] charge_stage.amount_paid = details_fee charge_stage.processing_charge = details_fee charge_stage.completed = charge_stage.received = charge_stage.cashed = True charge_stage.stage_owner = self.user.__name__ charge_stage.date = datetime.now() charge_stage.method = "stripe" charge_stage.transfer = True ticket.payment.history.append(charge_stage) # Forward to the page to actually edit details return HTTPFound(location=self.request.route_path( "ticket_edit_guest", tick_id=tick_id)) else: error = "The payment failed, please check your details and try again!" if "failure_message" in charge and charge[ "failure_message"] != None: error = charge["failure_message"] 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
def alter_pay_stripe_completion_do(self): # Check that we have a stripe charge object stripe_charge = self.request.session[ "stripe_charge"] if "stripe_charge" in self.request.session else None if stripe_charge == None: logging.exception( self.user.username + ": Stripe charge object was not found in session") return self.alter_pay_stripe_view( error= "During processing the Stripe transaction has been lost, please contact the ticketing officer." ) # Clear the charge object from the session self.request.session.pop("stripe_charge", None) # Retrieve the payment payment_id = self.request.matchdict[ "payment_id"] if "payment_id" in self.request.matchdict else None payment = self.request.root.payments[ payment_id] if payment_id != None else None if payment == None: logging.exception( self.user.username + ": Payment could not be located whilst trying to update payment with Stripe charge %s" % stripe_charge["id"]) self.refund_stripe_charge(stripe_charge["id"]) return self.alter_pay_stripe_view( error= "During processing a critical error occurred, please contact the ticketing officer immediately." ) # Pickup the stripe method (regardless of if disabled as we now have made a charge!) all_methods = PROP.getProperty(self.request, PROP.PAYMENT_METHODS) method = [x for x in all_methods if x.__name__ == "stripe"] method = method[0] if len(method) > 0 else None if method == None: logging.exception( self.user.username + ": Method could not be found whilst trying to update payment %s with Stripe charge %s" % (payment_id, stripe_charge["id"])) self.refund_stripe_charge(stripe_charge["id"]) return self.alter_pay_stripe_view( error= "During processing a critical error occurred, please contact the ticketing officer immediately." ) # Retrieve stripe processing values process_percentage = method.settings[ PROP.PAYMENT_PROCESSING_PERCENTAGE].value process_fee = method.settings[PROP.PAYMENT_PROCESSING_FEE].value # Calculate the amount to pay subtotal = payment.amount_remaining processing = int(ceil(subtotal * process_percentage) + process_fee) total = int(ceil(subtotal + processing)) try: # Acquire the source information charge_id = stripe_charge[ "id"] if "source" in stripe_charge else None source = stripe_charge[ "source"] if "source" in stripe_charge else None last_four = source[ "last4"] if source != None and "last4" in source else None logging.info(self.user.username + ": Constructing payment from Stripe charge %s" % charge_id) # Attach new payment stage to the payment stage = PaymentStage() stage.__parent__ = payment stage.method = "stripe" stage.method_properties["last_four"] = last_four stage.method_properties["ref_code"] = charge_id stage.amount_paid = total stage.processing_charge = processing stage.completed = True stage.received = stage.cashed = True stage.stage_owner = self.user.__name__ payment.history.append(stage) payment.completed_date = datetime.now() self.request.session["payment_id"] = payment.ref_code logging.info( self.user.username + ": Successfully updated payment %s with Stripe charge %s" % (payment.ref_code, charge_id)) return HTTPFound(location=self.request.route_path( "alter_confirm", payment_id=payment_id)) except Exception as e: logging.exception(self.user.username + ": Exception thrown in Stripe checkout: %s" % e) # We need to refund immediately as this is an error charge_id = stripe_charge[ "id"] if "source" in stripe_charge else None if not self.refund_stripe_charge(charge_id): return self.alter_pay_stripe_view( error= "An error occurred during Stripe checkout and the system could not refund you automatically: %s" % e) else: return self.alter_pay_stripe_view( error= "An error occurred during Stripe checkout but you have been automatically refunded the full amount: %s" % e) # We should never get here! logging.exception(self.user.username + ": Stripe payment completion escaped expected block") return self.alter_pay_stripe_view( error= "An unexpected error occurred during checkout, please contact the ticketing officer." )
def make_transfer(self, old_user, new_user, ticket, transfer_fee, stripe_charge=None): payment = ticket.payment # Open a new payment for the new owner, deduct the value of money associated # with this ticket from the original payment and add it to this payment, then # open a transfer payment stage and move the ticket across. If the original payment # was gifted then need to treat specially new_payment = Payment() new_payment.__parent__ = new_user new_payment.owner = new_user # Find out if it was gifted gifted = (len([x for x in payment.history if x.method == "gifted"]) > 0) # Open the finance stage finance_stage = PaymentStage() finance_stage.__parent__ = new_payment finance_stage.completed = finance_stage.received = finance_stage.cashed = True finance_stage.stage_owner = old_user.__name__ finance_stage.date = datetime.now() if gifted: finance_stage.method = "gifted" else: finance_stage.method = "banktransfer" finance_stage.amount_paid = ticket.total_cost new_payment.history.append(finance_stage) # Open the ticket transfer stage transfer_stage = PaymentStage() transfer_stage.__parent__ = new_payment transfer_stage.amount_paid = transfer_fee transfer_stage.processing_charge = transfer_fee transfer_stage.completed = transfer_stage.received = transfer_stage.cashed = True transfer_stage.stage_owner = new_user.__name__ transfer_stage.date = datetime.now() if stripe_charge != None: transfer_stage.method = "stripe" transfer_stage.method_properties["last_four"] = stripe_charge["source"]["last4"] transfer_stage.method_properties["ref_code"] = stripe_charge["id"] else: transfer_stage.method = "gifted" transfer_stage.transfer = True new_payment.history.append(transfer_stage) # Open the outgoing ticket transfer stage for the original owner out_trans_stage = PaymentStage() out_trans_stage.__parent__ = payment if not gifted: out_trans_stage.amount_paid = -ticket.total_cost # To make sure books balance! out_trans_stage.completed = out_trans_stage.received = out_trans_stage.cashed = True out_trans_stage.stage_owner = new_user.__name__ out_trans_stage.date = datetime.now() if stripe_charge != None: out_trans_stage.method = "stripe" out_trans_stage.method_properties["last_four"] = stripe_charge["source"]["last4"] out_trans_stage.method_properties["ref_code"] = stripe_charge["id"] else: out_trans_stage.method = "gifted" out_trans_stage.transfer = True payment.history.append(out_trans_stage) # Mark new payment as having been completed today new_payment.completed_date = datetime.now() # Move the ticket over to the new payment new_payment.tickets.append(ticket) payment.tickets.remove(ticket) # Move the ticket over to the new user (different to above) new_user.tickets.append(ticket) new_user.total_tickets += 1 # We increment, but don't decrement (stop scalpers) old_user.tickets.remove(ticket) ticket.__parent__ = new_user ticket.payment = new_payment ticket.owner = new_user # Register payment new_user.payments.append(new_payment) self.request.root.payments[new_payment.__name__] = new_payment # If the receiver only has one ticket, then make this their main ticket if len(new_user.tickets) == 1: ticket.guest_info = new_user.profile # Else gift one free guest detail alteration and clear existing details else: ticket.guest_info = None ticket.change_enabled = True # Transfer complete - notify GenericEmail(self.request).compose_and_send( "Ticket Transfer Complete", "The ticket %s has been successfully transferred to %s. If you did not request this change, please get in touch with us by email or phone (details at the bottom of this message)." % (ticket.__name__, new_user.profile.fullname), old_user.__name__ ) GenericEmail(self.request).compose_and_send( "Ticket Transfer from %s" % old_user.profile.fullname, "You have been transferred a ticket (%s) from %s. If you think this is a mistake, please get in touch with us by email or phone (details at the bottom of this message)." % (ticket.__name__, old_user.profile.fullname), new_user.__name__ ) self.request.session.flash("Ticket transfer successful!", "info") return HTTPFound(location=self.request.route_path("user_profile"))
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 transfer_ticket_payment_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")) tick_id = self.request.matchdict["tick_id"] ticket = None # Find ticket for tick in self.user.tickets: if tick.__name__ == tick_id: ticket = tick break # Safety if ticket == None: self.request.session.flash("Ticket does not exist.", "error") return HTTPFound(location=self.request.route_path("user_profile")) # Check that ticket is paid for elif not ticket.payment.paid: self.request.session.flash( "The payment has not been completed for this ticket, therefore you cannot transfer it.", "error") return HTTPFound(location=self.request.route_path("user_profile")) # Also check that if they are exchanging their own ticket that they don't have guests elif ticket.guest_info == ticket.owner.profile and len( self.user.tickets) > 1: self.request.session.flash( "You may not exchange your own ticket while you still have guest tickets.", "error") return HTTPFound(location=self.request.route_path("user_profile")) # Now check we have received a valid posted username if not "transfer_to" in self.request.session: self.request.session.flash( "You must enter a username to transfer the ticket to!", "error") return HTTPFound(location=self.request.route_path( "transfer_ticket", tick_id=tick_id)) elif not self.request.session["transfer_to"].lower( ) in self.request.root.users or self.request.session[ "transfer_to"].lower() == self.user.__name__: self.request.session.flash( "You must enter a valid username (someone with an account) to transfer the ticket to!", "error") return HTTPFound(location=self.request.route_path( "transfer_ticket", tick_id=tick_id)) recipient = self.request.session["transfer_to"].lower() # OK, now if we have a payment deal with it if "stripeToken" in self.request.POST: # Double check the username username = self.request.POST["username"].lower().replace(" ", "") if len(username) <= 2: self.request.session.flash( "You must enter a valid username to transfer the ticket to. You have not been charged.", "error") return HTTPFound(location=self.request.route_path( "transfer_ticket", tick_id=tick_id)) if not username in self.request.root.users: self.request.session.flash( "The username \"%s\" does not exist within the system, please check again. You have not been charged." % username, "error") return HTTPFound(location=self.request.route_path( "transfer_ticket", tick_id=tick_id)) elif self.request.root.users[ username].profile == None or not self.request.root.users[ username].profile.complete: self.request.session.flash( "The username \"%s\" does not have a complete profile, please complete it before transferring. You have not been charged." % username, "error") return HTTPFound(location=self.request.route_path( "transfer_ticket", tick_id=tick_id)) # Run Stripe payment to authorise organisation_name = self.get_payment_method('stripe').settings[ PROP_KEYS.ORGANISATION_NAME].value transfer_fee = PROP_KEYS.getProperty(self.request, PROP_KEYS.TRANSFER_FEE) token = self.request.POST["stripeToken"] stripe.api_key = self.get_payment_method('stripe').settings[ PROP_KEYS.STRIPE_API_KEY].value charge = None error = None try: charge = stripe.Charge.create( amount=transfer_fee, currency="gbp", source=token, description=organisation_name, ) if "paid" in charge and charge["paid"] == True: # Ok, now exchange new_user = self.request.root.users[username] payment = ticket.payment old_user = ticket.owner # Open a new payment for the new owner, deduct the value of money associated # with this ticket from the original payment and add it to this payment, then # open a transfer payment stage and move the ticket across. If the original payment # was gifted then need to treat specially new_payment = Payment() new_payment.__parent__ = new_user new_payment.owner = new_user # Find out if it was gifted gifted = (len([ x for x in payment.history if x.method == "gifted" ]) > 0) # Open the finance stage finance_stage = PaymentStage() finance_stage.__parent__ = new_payment finance_stage.completed = finance_stage.received = finance_stage.cashed = True finance_stage.stage_owner = old_user.__name__ finance_stage.date = datetime.now() if gifted: finance_stage.method = "gifted" else: finance_stage.method = "banktransfer" finance_stage.amount_paid = ticket.total_cost new_payment.history.append(finance_stage) # Open the ticket transfer stage transfer_stage = PaymentStage() transfer_stage.__parent__ = new_payment transfer_stage.method_properties["last_four"] = charge[ "source"]["last4"] transfer_stage.method_properties["ref_code"] = charge["id"] transfer_stage.amount_paid = transfer_fee transfer_stage.processing_charge = transfer_fee transfer_stage.completed = transfer_stage.received = transfer_stage.cashed = True transfer_stage.stage_owner = new_user.__name__ transfer_stage.date = datetime.now() transfer_stage.method = "stripe" transfer_stage.transfer = True new_payment.history.append(transfer_stage) # Open the outgoing ticket transfer stage for the original owner out_trans_stage = PaymentStage() out_trans_stage.__parent__ = payment if not gifted: out_trans_stage.amount_paid = -ticket.total_cost # To make sure books balance! out_trans_stage.completed = out_trans_stage.received = out_trans_stage.cashed = True out_trans_stage.stage_owner = new_user.__name__ out_trans_stage.date = datetime.now() out_trans_stage.method = "stripe" out_trans_stage.method_properties["last_four"] = charge[ "source"]["last4"] out_trans_stage.method_properties["ref_code"] = charge[ "id"] out_trans_stage.transfer = True payment.history.append(out_trans_stage) # Mark new payment as having been completed today new_payment.completed_date = datetime.now() # Move the ticket over to the new payment new_payment.tickets.append(ticket) payment.tickets.remove(ticket) # Move the ticket over to the new user (different to above) new_user.tickets.append(ticket) new_user.total_tickets += 1 # We increment, but don't decrement (stop scalpers) old_user.tickets.remove(ticket) ticket.__parent__ = new_user ticket.payment = new_payment ticket.owner = new_user # Register payment new_user.payments.append(new_payment) self.request.root.payments[ new_payment.__name__] = new_payment # If the receiver only has one ticket, then make this their main ticket if len(new_user.tickets) == 1: ticket.guest_info = new_user.profile # Else gift one free guest detail alteration and clear existing details else: ticket.guest_info = None ticket.change_enabled = True # Transfer complete - notify GenericEmail(self.request).compose_and_send( "Ticket Transfer Complete", "The ticket %s has been successfully transferred to %s. If you did not request this change, please get in touch with us by email or phone (details at the bottom of this message)." % (ticket.__name__, new_user.profile.fullname), old_user.__name__) GenericEmail(self.request).compose_and_send( "Ticket Transfer from %s" % old_user.profile.fullname, "You have been transferred a ticket (%s) from %s. If you think this is a mistake, please get in touch with us by email or phone (details at the bottom of this message)." % (ticket.__name__, old_user.profile.fullname), new_user.__name__) self.request.session.flash("Ticket transfer successful!", "info") return HTTPFound( location=self.request.route_path("user_profile")) else: error = "The payment failed, please check your details and try again!" if "failure_message" in charge and charge[ "failure_message"] != None: error = charge["failure_message"] 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
def enter_payment_view(self): payments = self.request.root.payments # Get payment if possible if not self.request.matchdict["ref_code"] in self.request.root.payments: return HTTPFound( location=self.request.route_path("admin_payments")) payment = payments[self.request.matchdict["ref_code"]] active_stage = (payment.history[len(payment.history) - 1] if (len(payment.history) > 0) else None) # Check if already marked as paid if payment.paid: return HTTPFound(location=self.request.route_path( 'admin_single_payment', ref_code=payment.__name__)) # Process form error = None if "submit" in self.request.POST: try: if not "amount" in self.request.POST or float( self.request.POST['amount']) <= 0: error = "An amount of money greater than zero must be specified" elif not "method" in self.request.POST or self.get_payment_method( self.request.POST["method"]) == None: error = "A valid payment method must be specified" elif not "year" in self.request.POST or not "month" in self.request.POST or not "day" in self.request.POST: error = "A valid date must be entered" elif int(self.request.POST["year"]) < 2000 or int( self.request.POST["month"]) < 1 or int( self.request.POST["month"]) > 12 or int( self.request.POST["day"]) < 1 or int( self.request.POST["day"]) > 31: error = "A valid date must be entered" # elif not "status" in self.request.POST or self.request.POST["status"] not in ["cashed", "received"]: error = "You must select a valid payment status" if not error: # Process this payment stage through amount = floor(float(self.request.POST["amount"]) * 100.0) method = self.request.POST["method"] year = int(self.request.POST["year"]) month = int(self.request.POST["month"]) day = int(self.request.POST["day"]) transaction_date = datetime(year=year, month=month, day=day) # - First check if the active stage is the current method if active_stage.method != method: # Update payment method to match that entered active_stage = PaymentStage() active_stage.__parent__ = payment active_stage.method = method active_stage.stage_owner = payment.owner.__name__ payment.history.append(active_stage) # Update amount paid active_stage.amount_paid = amount active_stage.completed = True # Doesn't mean 'fully paid' just something has happened at this stage # Check for a complete sale if active_stage.amount_remaining <= active_stage.amount_paid: payment.completed_date = transaction_date # Send payment confirmation email emailer = GenericEmail(self.request) emailer.compose_and_send( "Ticket Payment Completed", """Your ticket purchase (reference code %s) has now been confirmed as a result of your complete payment being received on %s and there is no further action required.""" % (payment.ref_code, payment.completed_date.strftime("%d/%m/%Y")), payment.owner.__name__) else: # We need to open up a new stage with the same type as the previous new_stage = PaymentStage() new_stage.__parent__ = payment new_stage.method = method new_stage.stage_owner = payment.owner.__name__ payment.history.append(new_stage) # Send partial payment confirmation email emailer = GenericEmail(self.request) emailer.compose_and_send( "Partial Ticket Payment Received", """A payment of %s for your tickets with reference code %s has now been received on %s. Please remember to complete the remainder of your payment (%s) in order for your tickets to the event to be confirmed.""" % (self.format_price(amount), payment.ref_code, transaction_date.strftime("%d/%m/%Y"), self.format_price(payment.amount_remaining)), payment.owner.__name__) logging.info( "%s: Created a new payment stage for payment %s for user %s" % (self.user.username, payment.__name__, payment.owner.username)) self.request.session.flash("Payment entered successfully", "info") return HTTPFound(location=self.request.route_path( "admin_single_payment", ref_code=payment.__name__)) except Exception: logging.exception( "%s: An error occurred adding a payment stage to payment %s" % (self.user.username, payment.__name__)) error = "An unknown error has occurred" return { "payment": payment, "date": datetime.now(), "active_stage": active_stage, "error": error }
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"
else: # Try running payment alteration charge = None try: subtotal = payment.amount_remaining processing = int( ceil(subtotal * process_percentage) + process_fee) total = int(ceil(subtotal + processing)) charge = stripe.Charge.create( amount=total, currency="gbp", source=token, description=organisation_name, ) if "paid" in charge and charge["paid"] == True: new_stage = PaymentStage() new_stage.__parent__ = payment new_stage.method = "stripe" new_stage.method_properties["last_four"] = charge[ "source"]["last4"] new_stage.method_properties["ref_code"] = charge["id"] new_stage.amount_paid = total new_stage.processing_charge = processing new_stage.received = new_stage.cashed = True new_stage.completed = True new_stage.stage_owner = user.__name__ payment.history.append(new_stage) payment.completed_date = datetime.now() logging.info( self.user.username + ": Stripe charge %s succeeded for payment %s" %
def allocate_tickets_view(self): if "submit" in self.request.POST: username = self.request.POST["username"].lower() if not username in self.request.root.users: self.request.session.flash( "The user you specified does not exist, ticket allocation failed.", "error") return {} user = self.request.root.users[username] num_tickets = int(float(self.request.POST["numtickets"])) if num_tickets <= 0: self.request.session.flash( "You must specify a number of tickets to issue, allocation failed.", "error") # Build the list of requested tickets and addons tick_types = {} for i in range(0, num_tickets): type_code = self.request.POST["ticket-%i-type" % i] addon_code = self.request.POST["ticket-%i-addon" % i] if type_code in tick_types: tick_types[type_code]["count"] += 1 if addon_code in tick_types[type_code]["addons"]: tick_types[type_code]["addons"][addon_code] += 1 else: tick_types[type_code]["addons"][addon_code] = 1 else: tick_types[type_code] = { "count": 1, "addons": { addon_code: 1 } } # Check stock of tickets and addons for type_key in tick_types: number = tick_types[type_key]["count"] addons = tick_types[type_key]["addons"] if not type_key in self.request.root.ticket_pools: self.request.session.flash( "Invalid ticket type was specified.", "error") return {} pool = self.request.root.ticket_pools[type_key] if len(pool.tickets) < number: self.request.session.flash( "There is not enough stock of '%s' to allocate the requested tickets." % pool.tick_type.name, "error") return {} #if not user.__parent__.__name__ in pool.groups: # self.request.session.flash("The user is not permitted to have tickets of the type '%s'." % pool.tick_type.name, "error") # return {} # Now check addons for addon_key in addons: if addon_key == "none": continue if not addon_key in pool.tick_type.addons: self.request.session.flash( "Invalid addon type was specified.", "error") return {} addon = pool.tick_type.addons[addon_key] num_addons = addons[addon_key] if addon.remaining < num_addons: self.request.session.flash( "There is not enough stock of the addon '%s' to allocate the requested tickets." % addon.name, "error") return {} # Issue the tickets and attach all addons requested has_ticket = (user.tickets != None and len(user.tickets) > 0 ) # Whether we need to set a ticket to be theirs all_tickets = [] for type_key in tick_types: number = tick_types[type_key]["count"] addons = tick_types[type_key]["addons"] pool = self.request.root.ticket_pools[type_key] for i in range(0, number): ticket = pool.tickets[0] user.tickets.append(ticket) pool.tickets.remove(ticket) ticket.__parent__ = user ticket.owner = user ticket.issue_date = datetime.now() ticket.change_enabled = True # Allow user to update guest details once if not has_ticket: ticket.guest_info = user.profile has_ticket = True else: blank_profile = UserProfile() blank_profile.__parent__ = ticket ticket.guest_info = blank_profile all_tickets.append(ticket) # Attach an addon if available for addon_key in addons: if addon_key == "none" or addons[addon_key] <= 0: continue addon = pool.tick_type.addons[addon_key] ticket.addons[addon.__name__] = addon addon.allocated.append(ticket) addons[addon_key] -= 1 break # Open a payment and attach all of the tickets into it gift = ("gift" in self.request.POST and self.request.POST["gift"] == "gift") payment = Payment() payment.owner = user payment.__parent__ = user payment.opened_date = datetime.now() for ticket in all_tickets: ticket.payment = payment payment.tickets.append(ticket) if gift: new_stage = PaymentStage() new_stage.__parent__ = payment new_stage.method = "gifted" new_stage.amount_paid = int(payment.amount_remaining) new_stage.processing_charge = 0 new_stage.received = new_stage.cashed = True new_stage.completed = True new_stage.stage_owner = user.__name__ payment.history.append(new_stage) payment.completed_date = datetime.now() else: new_stage = PaymentStage() new_stage.__parent__ = payment new_stage.method = "cheque" new_stage.method_change = True new_stage.stage_owner = user.__name__ payment.history.append(new_stage) # Attach the payment to the user user.payments.append(payment) user.total_tickets += len(payment.tickets) self.request.root.payments[payment.__name__] = payment # Send a information email if user.profile != None: emailer = GenericEmail(self.request) if gift: emailer.compose_and_send( "Tickets Allocated", """This is to notify you that %i ticket(s) have been allocated to your account, they have been transferred as a gift and hence no further action is required. If you want to get in touch, your ticket allocation reference is %s.""" % (len(payment.tickets), payment.ref_code), payment.owner.__name__) else: emailer.compose_and_send( "Tickets Allocated", """This is to notify you that %i ticket(s) have been allocated to your account. You are required to complete payment for your tickets, currently they are set as a default of cheque payment, however you may change this by logging into your ticket account. Your purchase reference is %s and your owed total is %s.""" % (len(payment.tickets), payment.ref_code, self.format_price(payment.total)), payment.owner.__name__) # Report all good self.request.session.flash("Ticket allocation successful!", "info") return HTTPFound(location=self.request.route_path("admin_tickets")) return {}
def setup_payments_test(self): counting = 0 for key in self.request.root.ticket_pools: pool = self.request.root.ticket_pools[key] ticks_left = len(pool.tickets) while (ticks_left > 0): # Whilst tickets are left, purchase random quantities of tickets payment = Payment() payment.owner = self.user payment.__parent__ = self.user stage = PaymentStage() stage.__parent__ = payment stage.stage_owner = self.user.__name__ stage.date = datetime.now() stage.method = [ "banktransfer", "cheque", "stripe", "collegebill" ][counting % 4] if stage.method == "stripe": stage.method_properties["last_four"] = "1234" stage.method_properties[ "ref_code"] = "TESTINGSTRIPEREFCODE" counting += 1 payment.history.append(stage) # To issue total_to_issue = randint(1, 10) if total_to_issue > ticks_left: total_to_issue = ticks_left ticks_left -= total_to_issue for i in range(0, total_to_issue): tick = pool.tickets[0] payment.tickets.append(tick) self.user.tickets.append(tick) pool.tickets.remove(tick) tick.__parent__ = tick.owner = self.user tick.guest_info = self.user.profile tick.issue_date = datetime.now() tick.payment = payment self.user.total_tickets += 1 # Enter a certain amount of payment stage.amount_paid = (counting % 3) * 0.5 * payment.total if stage.amount_paid > 0: stage.received = stage.cashed = stage.completed = True # If the payment calculates it has been paid then add date if payment.paid: payment.completed_date = datetime.now() elif stage.amount_paid > 0: # Append a second blank payment stage on stage_2 = PaymentStage() stage_2.__parent__ = payment stage_2.stage_owner = self.user.__name__ stage_2.date = datetime.now() stage_2.method = ["banktransfer", "cheque", "collegebill"][counting % 3] payment.history.append(stage_2) self.user.payments.append(payment) self.request.root.payments[payment.__name__] = payment self.request.session.flash("Test payments setup successfully!", "info") return HTTPFound(location=self.request.route_path('tests_page'))