Adding Online Payment Support in Online Event Frontend via Stripe

Open Event Frontend involves ticketing system which supports both paid and free tickets. To buy a paid ticket Open Event provides several options such as debit card, credit card, cheque, bank transfer and onsite payments. So to add support for debit and credit card payments Open Event uses stripe checkout. Using stripe users can enter their card details and pay for their ticket.

Given below are some steps which are to be followed for successfully charging a user for ticket using his/her card.

  • We get publishable key for organizer’s stripe account using OAuth. See this blog.
  • We render stripe checkout button using stripe publishable key. This helps us identify which user to credit after payment.
  • After clicking checkout button user is prompted to enter his/her card details and verify payment.
  • After user’s verification stripe generates a payment token is which is used by open event frontend to charge the user for stipulated amount.
  • We send this token to open event server which processes the token and charge the user.
  • We get error or success message from open event server as per the process outcome.

To render the stripe checkout button we use ember-cli-stripe. Below is the code which helps us to understand how stripe checkout button is rendered.

// app/templates/orders/placed.hbs 

{{stripe-checkout
    locale='auto'
    name="Open Event"
    description=paymentDescription
    amount=paymentAmount
    key=model.event.stripeAuthorization.stripePublishableKey
    onToken=(action "processStripeToken")
    onClosed=(action "checkoutClosed")
    onOpened=(action "checkoutOpened")
}}

 

Full code can be seen here.

We see that we pass different parameters to stripe button which helps stripe identify how to render the button and what information to display. We have also passed the actions onToken(), onClosed() and onOpened(). All these actions are triggered at different instances based on what event occurs.

onToken(): This action is triggered when user has verified his/her purchase and we stripe has generated the payment token. Stripe passes the token back to client (open event frontend server) to process. We have handled this error via different name “processStripeToken()”. We will see cose for these actions below.

onClosed(): This action is called when checkout prompt is closed. We have not used this action in open event frontend. But this can be used to trigger some event in case your application need some action when checkout prompt is closed.

onOpened(): This action is called when checkout prompt is opened. We have not used this action in open event frontend. But this can be used to trigger some event in case your application need some action when checkout prompt is opened.

Code for these actions are given below. Full code file can be seen here.

//  app/controllers/orders/placed.js 

processStripeToken(token) {
   // Send this token to server to process payment
   let order = this.get('model');
   let chargePayload = {
     'data': {
       'attributes': {
         'stripe'            : token.id,
         'paypal_payer_id'   : null,
         'paypal_payment_id' : null
       },
       'type': 'charge'
     }
   };
   let config = {
     skipDataTransform: true
   };
   chargePayload = JSON.stringify(chargePayload);
   return this.get('loader').post(`orders/${order.identifier}/charge`, chargePayload, config)
     .then(charge => {
       if (charge.data.attributes.status) {
         this.get('notify').success(charge.data.attributes.message);
         this.transitionToRoute('orders.view', order.identifier);
       } else {
         this.get('notify').error(charge.data.attributes.message);
       }
     });
 }

 

In above code snippet for processStipeToken() we are processing the stripe payment token received from stripe after user verifies his/her payment. We pass this token to charge endpoint of open event server. After charging the user server send a response which is displayed on frontend.

In this way we achieve the functionality of adding stripe payment support in open event frontend. Please follow the links below for further clarification and detailed overview.

Resources:
Continue Reading

Charges Layer in Open Event Server

The Open Event Server enables organizers to manage events from concerts to conferences and meetups. It offers features for events with several tracks and venues. This blog post explains how the charge layer has been implemented in the Open Event Server in order to charge the user for tickets of an event.

Schema

We currently support payments via Stripe and Paypal. As a result the schema for Charges layer consists of fields for providing the token for stripe or paypal. It also contains a read only id field.

class ChargeSchema(Schema):
    """
    ChargeSchema
    """

    class Meta:
        """
        Meta class for ChargeSchema
        """
        type_ = 'charge'
        inflect = dasherize
        self_view = 'v1.charge_list'
        self_view_kwargs = {'id': '<id>'}

    id = fields.Str(dump_only=True)
    stripe = fields.Str(allow_none=True)
    paypal = fields.Str(allow_none=True)

Resource

The ChargeList resource only supports POST requests since there is no need for other type of requests. We simply declare the schema, supported methods and the data layer. We also check for required permissions by declaring the decorators.

class ChargeList(ResourceList):
    """
    ChargeList ResourceList for ChargesLayer class
    """
    methods = ['POST', ]
    schema = ChargeSchema

    data_layer = {
        'class': ChargesLayer,
        'session': db.session
    }

    decorators = (jwt_required,)

Layer

The data layer contains a single method create_object which does all the heavy lifting of charging the user according to the payment medium and the related order. It first loads the related order from the database using the identifier.

We first check if the order contains one or more paid tickets or not. If not, then ConflictException is raised since it doesn’t make sense to charge a user without any paid ticket in the order. Next, it checks the payment mode of the order. If the payment mode is Stripe then it checks if the stripe_token is provided with the request or not. If not, an UnprocessableEntity exception is raised otherwise relevant methods are called in order to charge the user accordingly. A similar procedure is followed for payments via Paypal. Below is the full code for reference.

class ChargesLayer(BaseDataLayer):

    def create_object(self, data, view_kwargs):
        """
        create_object method for the Charges layer
        charge the user using paypal or stripe
        :param data:
        :param view_kwargs:
        :return:
        """
        order = Order.query.filter_by(id=view_kwargs['id']).first()
        if not order:
            raise ObjectNotFound({'parameter': 'id'},
                                 "Order with id: {} not found".format(view_kwargs['id']))
        elif order.status == 'cancelled' or order.status == 'expired':
            raise ConflictException({'parameter': 'id'},
                                    "You cannot charge payments on a cancelled or expired order")
        elif (not order.amount) or order.amount == 0:
            raise ConflictException({'parameter': 'id'},
                                    "You cannot charge payments on a free order")

        # charge through stripe
        if order.payment_mode == 'stripe':
            if not data.get('stripe'):
                raise UnprocessableEntity({'source': ''}, "stripe token is missing")
            success, response = TicketingManager.charge_stripe_order_payment(order, data['stripe'])
            if not success:
                raise UnprocessableEntity({'source': 'stripe_token_id'}, response)

        # charge through paypal
        elif order.payment_mode == 'paypal':
            if not data.get('paypal'):
                raise UnprocessableEntity({'source': ''}, "paypal token is missing")
            success, response = TicketingManager.charge_paypal_order_payment(order, data['paypal'])
            if not success:
                raise UnprocessableEntity({'source': 'paypal'}, response)
        return order

The charge_stripe_order_payment and charge_paypal_order_payment are helper methods defined to abstract away the complications of the procedure from the layer.

References

Continue Reading

Generating a Stripe token in the Open Event Android App

To implement the payment functionality in the Open Event Android App using credit cards we are using Stripe. Let’s see how this is being done.

We are taking the sensitive information about the user like the card details and sending it to Stripe’s servers which will return a token encrypting users information which we will use to send it to the Open Event Server to complete the payment.

We need to add the library in the build.gradle file in the dependency block.

//Stripe
implementation 'com.stripe:stripe-android:6.1.2'

 

Next we add Stripe’s Card Input Widget in our layout file. This widget is used to input card details like the card number, expiry date and CVC. It automatically validates the card details. It has a minimum width of 320 px. By default we are setting it’s visibility to gone that is it won’t be visible unless the user selects the payment option.

<com.stripe.android.view.CardInputWidget
android:id="@+id/cardInputWidget"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />

 

The visibility of the input field for card details is determined here. We want to show the Input widget only when the user selects Stripe as the mode of payment.

override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
selectedPaymentOption = paymentOptions[p2]
if (selectedPaymentOption == "Stripe")
rootView.cardInputWidget.visibility = View.VISIBLE
else
rootView.cardInputWidget.visibility = View.GONE
}

 

Next we store the user’s card details in a variable. If any of the details be it card number, expiry date or CVC isn’t correct, the value of the variable becomes null and then we show a message to the user.

val cardDetails: Card? = cardInputWidget.card

if (cardDetails == null)
Toast.makeText(context, "Invalid card data", Toast.LENGTH_LONG).show()

 

This is the most important part where we receive the Stripe token. We are sending a request in a background thread to the Stripe servers using the Stripe API_KEY. In the onSuccess method we receive the token if everything went successfully while in the onError method we display the errors to the user.

cardDetails?.let {
context?.let { contextIt ->
Stripe(contextIt).createToken(
it,
API_KEY,
object : TokenCallback {
override fun onSuccess(token: Token) {
//Send this token to server
Toast.makeText(context, "Token received from Stripe", Toast.LENGTH_LONG).show()
}

override fun onError(error: Exception) {
Toast.makeText(context, error.localizedMessage.toString(), Toast.LENGTH_LONG).show()
}
})
}
}

 

Resources

  1. Stripe Android documentation: https://stripe.com/docs/mobile/android  
  2. Stripe Documentation: https://stripe.com/docs/quickstart
  3. Stripe Android Github: https://github.com/stripe/stripe-android
Continue Reading

Integrating Stripe OAuth in Open Event Frontend

Why is Stripe Oauth needed in frontend? Open event allows organizers to add tickets and accepts payments for tickets through various modes for example, Credit card, Debit card, Netbanking and offline payments. Stripe allows users to accept payments into their linked accounts on various online platforms after they provide client secret and publishable key. So to enable online payments in open event, organizers were required to authenticate their stripe account. This is done through Stripe OAuth.

Flow of OAuth

To allow organizers to link their stripe account admin has to enable stripe under payment gateway in admin settings. Admin provides his client ID and secret key. Admin also sets the redirect URL for his app on the stripe dashboard. After enabling these settings organizer will see an option to link their stripe account to open event when they are creating an event with paid tickets.

Here is what open event frontend does when we click connect to stripe button:

  1. Opens a popup to allow organizer to fill his stripe credentials and authorize open event app to access their secret and publishable key.
  2. Once the organizer fills his credentials and authorizes open event app, open event frontend fetches organizers auth code and saves it to server.
  3. Server on receiving auth code from frontend makes a request to stripe using the auth code to retrieve the publishable key and secret key.
  4. Once these are fetched server saves this information against the event so that all payments for that event can go to the linked stripe account.

Implementing the Frontend portion:

  • Choosing the library:

After looking at various libraries that support OAuth for Ember applications we decided to use Torii. Torii is the library that allows the addition of OAuth for various social apps such as Facebook, Google and Stripe too. It allows writing a custom provider for OAuth in case we do not want to use clients for which torii provides supports by default.

  • Implementing Stripe Provider:

Default provider for stripe given by torii fetched the client ID and redirect URL from environment.js file. But since in open event we have already saved client id of admin in our database so we will extend default stripe provider and modify its client Id so that it fetches client id from server. Code for extending default provider is given here:

import stripeConnect from 'torii/providers/stripe-connect';
import { alias } from '@ember/object/computed';
import { inject } from '@ember/service';
import { configurable } from 'torii/configuration';

function currentUrl() {
 let url = [window.location.protocol,
   '//',
   window.location.host].join('');
 if (url.substr(-1) !== '/') {
   url += '/';
 }
 return url;
}

export default stripeConnect.extend({

 settings: inject(),

 clientId: alias('settings.stripeClientId'),

 redirectUri: configurable('redirectUri', function() {
   return `${currentUrl()}torii/redirect.html`;
 })

});

 

We have fetched clientId from our settings service as alias(‘settings.stripeClientId’).

We have already defined settings in our services so we just need to inject the service here to be able to use it.

By default torii provides redirect url as {currentUrl}/torii/redirect.html. But in open event frontend we allow organizers to edit information on two routes and torii suggests in its docs to use {baseUrl}/torii/redirect.html as the redirect url to avoid potential vulnerability. So we also modified the default redirect url building method.

Saving information to server

Once we get the authorization token from stripe we send it to the server and save it to stripe-authorization model. The logic for the same is given below:

connectStripe() {
     this.get('data.event.stripeAuthorization.content') ? '' : this.set('data.event.stripeAuthorization', this.store.createRecord('stripe-authorization'));
     this.get('torii').open('stripe')
       .then(authorization => {
         this.set('data.event.stripeAuthorization.stripeAuthCode', authorization.authorizationCode);
       })
       .catch(error => {
         this.get('notify').error(this.get('l10n').t(`${error.message}. Please try again`));
       });
   },

 

This action gets called when we click on connect to stripe button. This action calls the stripe provider and opens a popup to enable the organizer to authenticate his stripe account.
Full code for this can be seen here.

In this way we connect the stripe service to open event to allow the organizer to receive payments for his events.

Resources
  • Stripe : Documentation on Stripe-Connect : Link
  • Torii: Library to implement Oauth. : Link
  • Implementation: Link to PR showing its implementation : Link
Continue Reading

Stripe Authorization In Open Event API Server

The Open Event System supports payments through stripe. Stripe is a suite of APIs that powers commerce for businesses of all sizes. This blogpost covers testing of Stripe Authorization Schema and endpoints in the API Server.

The Stripe Authorization class provides the following endpoints:

'/stripe-authorization'
'/stripe-authorization/<int:id>'
'/events/<int:event_id>/stripe-authorization'
'/events/<event_identifier>/stripe-authorization'


In the pull request made for adding documentation and tests, these two endpoints were removed:

'stripe_authorization_list',
'/events/<int:event_id>/stripe-authorization',
'/events/<event_identifier>/stripe-authorization'

This is because each event can have only one stripe authorization, so there can not exist a list of stripe authorization objects related to an event.

The ‘stripe_authorization_list’ endpoint is made POST only. This is because Open Event does not allow individual resources’ list to be accessible. Since, there is no endpoint which returns a list of Stripe Authorizations the StripeAuthorizationList(ResourceListis removed.

The ResourceDetail class was modified to add a query to support  results from ‘/events/<int:event_id>/stripe-authorization’ endpoint suThe view_kwargs for the detail endpoint has to contain the resource id, so event_id from view_kwags is used to get the id for stripe authorization.

stripe_authorization = self.session.query(StripeAuthorization).filter_by(event_id=view_kwargs['event_id']).one()
view_kwargs['id'] = stripe_authorization.id

Writing Test for Documentation

(Tests for the /events/1/stripe-authorization  is described here, for others please refer to links in additional references.)

To test the  /events/1/stripe-authorization endpoint for GET, we first insert a Stripe Authorization object into the database which will then be retrieved by the GET request and then compared with the expected response body from the documentation file.

Since stripe-auth has a required relationship with event class, an event must also exist for strie auth object to be created. The event is also required because the endpoint ‘events/’ expects an event object to exist. The StripeAuthorizationFactory takes care of this with event as a RelatedFactory. So when a StripeAuthorization object is inserted, an event is created first and passed as the required relationship to stripe_list_post endpoint.

The event is related to the stripe object by setting event_id = 1 in the factory.

Adding the pre-test hook for GET:

@hooks.before("StripeAuthorization > Stripe Authorization for an Event > Get Stripe Authorization Details of an Event")
def event_stripe_authorization_get_detail(transaction):
   """
   GET /events/1/stripe-authorization
   :param transaction:
   :return:
   """
   with stash['app'].app_context():
       stripe = StripeAuthorizationFactory()
       db.session.add(stripe)
       db.session.commit()


The expected response for this request can be found
 here.

Additional References:

Continue Reading

Post Payment Charging in Open Event API Server

Order flow in Open Event API Server follows very simple process. On successfully creating a order through API server the user receives the payment-url. API server out of the box provides support for two payment gateways, stripe and paypal.
The process followed is very simple, on creating the order you will receive the payment-url. The frontend will complete the payment through that url and on completion it will hit the specific endpoint which will confirm the payment and update the order status.

Getting the payment-url

Payment Url will be sent on successfully creating the order. There are three type of payment-modes which can be provided to Order API on creating order. The three payment modes are “free”, “stripe” and “paypal”. To get the payment-url just send the payment mode as stripe or paypal.

POST Payment

After payment processing through frontend, the charges endpoint will be called so that payment verification can be done on the server end.

POST /v1/orders/<identifier>/charge

This endpoint receives the stripe token if the payment mode is stripe else no token is required to process payment for paypal.
The response will have the order details on successful verification.

Implementation

The implementation of charging is based on the custom data layer in Orga Server. The custom layer overrides the Base data layer and provide the custom implementation to “create_object” method thus, not using Alchemy layer.

def create_object(self, data, view_kwargs):
   order = Order.query.filter_by(id=view_kwargs['id']).first()
   if order.payment_mode == 'stripe':
       if data.get('stripe') is None:
           raise UnprocessableEntity({'source': ''}, "stripe token is missing")
       success, response = TicketingManager.charge_stripe_order_payment(order, data['stripe'])
       if not success:
           raise UnprocessableEntity({'source': 'stripe_token_id'}, response)

   elif order.payment_mode == 'paypal':
       success, response = TicketingManager.charge_paypal_order_payment(order)
       if not success:
           raise UnprocessableEntity({'source': ''}, response)
   return order

With the resource class as

class ChargeList(ResourceList):
   methods = ['POST', ]
   schema = ChargeSchema

   data_layer = {
       'class': ChargesLayer,
       'session': db.session
   }

Resources

  1. Paypal Payments API
    https://developer.paypal.com/docs/api/payments/
  2. Flask-json-api custom layer docs
    http://flask-rest-jsonapi.readthedocs.io/en/latest/data_layer.html#custom-data-layer
  3. Stripe Payments API
    https://stripe.com/docs/charges
Continue Reading

Integrating Stripe in the Flask web framework

{ Repost from my personal blog @ https://blog.codezero.xyz/integrating-stripe-in-flask }

Stripe is a developer and a user-friendly payment infrastructure provider. Stripe provides easy to use SDKs in different programming languages allowing us to easily collect payments on our website or mobile application.

Flask is a web microframework for Python based on Werkzeug, Jinja 2. Flask makes building web applications in python a breeze.

Make sure you have your Flask app ready. Let’s start with installing the required dependency. The Stripe python SDK. You can get it by running.

pip install stripe

Don’t forget to add the same in your requirements.txt. (if you have one that is.)

Now, head over to Stripe: Register and create a new Stripe account to get your test keys. If you don’t wish to create an account at this time, you can use the following test keys, but you’ll not be able to see the payments in the stripe dashboard.

  • Publishable Key: pk_test_6pRNASCoBOKtIshFeQd4XMUh
  • Secret Key: sk_test_BQokikJOvBiI2HlWgH4olfQ2

We’ll need to set the secret key in the SDK.

import stripe

STRIPE_PUBLISHABLE_KEY = 'pk_test_6pRNASCoBOKtIshFeQd4XMUh'  
STRIPE_SECRET_KEY = 'sk_test_BQokikJOvBiI2HlWgH4olfQ2'

stripe.api_key = STRIPE_SECRET_KEY

Let’s create a page with a form for us to handle the Stripe payment.

<!DOCTYPE html>  
<html>  
<head>  
    <title>Pay now</title>
</head>  
<body>  
    <h4>Pay $250.00 by clicking on the button below.</h4>
    <form action="/payment" method="POST">
        <script src="https://checkout.stripe.com/checkout.js" 
                class="stripe-button"
                data-key="pk_test_6pRNASCoBOKtIshFeQd4XMUh"
                data-description="A payment for the Hello World project"
                data-name="HelloWorld.com"
                data-image="/images/logo/hw_project.png"
                data-amount="25000"></script>
    </form>
</body>  
</html>

We’re using Stripe’s Checkout library to get the payment details from the user and process. Also, keep in mind that the checkout library has to be loaded directly from https://checkout.stripe.com/checkout.js. Downloading it and serving locally will not work.

The script tag, accepts a lot of parameters. A few important ones are,

  • data-key – The Publishable Key.
  • data-amount – The amount to be charged to the user in the lowest denomination of the currency. (For example, 5 USD should be represented as 500 cents)
  • data-name – The name of your site or company that will be displayed to the user.
  • data-image – The path to an image file (maybe a logo) that you’d like to be displayed to the user.

More configuration options can be seen at Stripe: Detailed Checkout Guide.

This script would automatically create a Pay with Card button which would open the stripe Checkout lightbox when clicked by the user.

Once the payment process is completed the following parameters are submitted to the form’s action endpoint (the form inside which this script is located), along with any other elements that were in the form.

  • stripeToken – The ID of the token representing the payment details
  • stripeEmail – The email address the user entered during the Checkout process

Along with the Billing address details and Shipping address details if applicable and enabled

We’ll need to write a Flask method to handle the input that were submitted by Stripe to proceed with the transaction and charge the user.

Let’s add a new Flask route to respond when submitting the form.

@app.route('/payment', methods=['POST'])
def payment_proceed():  
    # Amount in cents
    amount = 25000

    customer = stripe.Customer.create(
        email=request.form['stripeEmail'],
        source=request.form['stripeToken']
    )

    charge = stripe.Charge.create(
        amount=amount,
        currency='usd',
        customer=customer.id,
        description='A payment for the Hello World project'
    )

    return render_template('payment_complete.html')

We’re now creating a new Stripe customer along with the stripeToken as the source parameter. The card details are stored by stripe as a token. And using this token ID, Stripe will be able to retrieve it to make the charge.

We’re creating a charge object with the amount in the lowest denomination of the currency, the currency name, the customer ID, and an optional description. This will charge the customer. On a successful transaction, a charge object would be returned. Else, an exception will be thrown.

For more information regarding the Charge object and the various other APIs available fro consumption in Stripe, checkout the Stripe API Guide.

Continue Reading
Close Menu
%d bloggers like this: