Laravel and AngularJS payments with Stripe

Laravel and AngularJS payments with Stripe

In this part of the tutorial series we will see how to create a page where, after the reservation has been made, the customer can pay it. Laravel itself come with a module to directly integrate with Stripe, it’s name is Cashier. Stripe is an online credit card payment system where, after a simple registration, you can start receiving payment via credit card using some exposed API and pay a little commission to it.

The good about this system is that all the information relative to the customer credit card will never touch your servers. This is very helpful for privacy and security and give you the possibility to avoid heavy code implementation to secure data relative to the payment process.

The frontend is made with AngularJS so we need a way to interact with Stripe from the Angular frontend and make our backend only ask for the charge using a provided token. Token in stripe represent the association with a credit card and a customer where you can charge for money.

To use Stripe with Angular there is more then one module. In this tutorial we will use angular- payments

Start with the installation of the module; after moving to the public folder of the project download the module using bower : bower install angular-payments

Now that the module is installed in our application we need to load it in the index.html file. Add the lines below in the index.html file :

<script type="text/javascript" src="https://js.stripe.com/v2/"></script>

<script type="text/javascript">
  Stripe.setPublishableKey('pk_test_p0QQDCeJQA7W9X9y0VP7QOz5');
</script>

<script src="bower_components/angular-payments/lib/angular-payments.js"></script>

We loaded the module and also the Stripe.com library also initializing it passing the public key provided by it dashboard.

Another modification to the index.html is about loading the AngularJS module we are going to create, so other another line is needed :

<script src="payment/pay.js"></script>

In the app folder of the AngularJS application we can create a new folder payment and inside it 2 new files pay.js and pay.html like show in the picture.

In the pay.html file we are going to code the form needed to collect all the information about the credit card and a row with the response message hidden by ng-if.


<div class="row" ng-if="!paid">
    <div class="col s12 m4 offset-m4">
        <div class="card-panel">
            <form stripe-form="handleStripe" name="myForm">
                <div class="row">
                    <div class="input-field col s12">
                        <label for="name">Name on card </label>
                        <input type="text" id="name">
                    </div></div>
                <div class="row">
                    <div class="input-field col s12">
                        <label for="cardn">Card number</label>
                        <input type="text" name="number" id="cardn"  ng-model="number" payments-validate="card" payments-format="card" payments-type-model="type" ng-class="myForm.number.$card.type"/>
                    </div>
                </div>
                <div class="row">
                    <div class="input-field col s6">
                        <label for="exp">Expiry</label>
                        <input type="text" id="exp" ng-model="expiry" payments-validate="expiry" payments-format="expiry" />
                    </div>
                    <div class="input-field col s6">
                        <label for="cvc">CVC</label>
                        <input type="text" id="cvc" ng-model="cvc" payments-validate="cvc" payments-format="cvc" payments-type-model="type"/>
                    </div>
                </div>
                <div class="row">
                    <div class="input-field col s12">
                        <button ng-if='loaded==true &amp;&amp; paid==false' type="submit" class="btn btn-primary btn-large">Pay {{reservation_info.total_price}}</button>
                    </div>
                </div>
            </form>
        </div>
    </div>
</div>
<div class="row"  ng-if="paid">
    <div class="col s12 m4 offset-m4">
        <div class="card-panel">
    <h2><p>{{message}}</p></h2>
        </div>
    </div>
</div>


As you can see the form is not a standard one. We used an attribute at the begin stripe-form where we specified also the function to callback once Stripe.com reply to us with the token. Also some fields like the number of the credit card and the expire date have some useful attribute for validation and format used for the input. All this custom attributes come from the angular-payments module.

Last thing to notice on the form is about the pay button. We used a ng-if directive to hide it before the reservation information is loaded. We will see better this once the controller code is implemented.

The other file pay.js content is shown below :


'use strict';

angular.module('myApp.pay', ['ngRoute','ui.materialize'])

    .config(['$routeProvider', function($routeProvider) {
        $routeProvider.when('/pay/:reserv_id', {
            templateUrl: 'payment/pay.html',
            controller: 'PayController'
        });
    }])

    .controller('PayController', function($scope,$http,reservationData,$location,$routeParams) {

        $scope.res_id = $routeParams.reserv_id;
        $scope.paid = false;

        $scope.handleStripe = function(status, response){
            if(response.error) {
                $scope.paid= false;
                $scope.message = "Error from Stripe.com"
            } else {
                var $payInfo = {
                    'token' : response.id,
                    'customer_id' : $scope.reservation_info.customer_id,
                    'total':$scope.reservation_info.total_price
                };

                $http.post('/api/payreservation', $payInfo).success(function(data){
                    if(data.status=="OK"){
                        $scope.paid= true;
                        $scope.message = data.message;
                    }else{
                        $scope.paid= false;
                        $scope.message = data.message;
                    }
                });

            }
        };

        $scope.init = function(){
            $scope.loaded = false;
            
            $http.get('/api/reservation/'+$scope.res_id).success(function(data){
                $scope.reservation_info = data;
                $scope.loaded=true;
            });
        };

        $scope.init();

    }
);


The first function executed on the controller is the init() function where all the information about the reservation to be paid is loaded by calling the Laravel backend API.

The other, and most important, function is the callback function handleStripe called after a response from Stripe is received. If the response is an error we set the message according, otherwise, using the id in the response and some other information taken from the reservation_info we call the Laravel API to proceed with the payment.

To access the payment page we use a button added on the reservation confirmation page (finalize.html)


<div class="row">
    <div class="col s12 m4 offset-m4" ng-if="reser_done">
        <div class="card blue darken-2">
            <div class="card-content white-text">
                <span class="card-title"> <h2>Reservation</h2></span>
                <h4>Customer info</h4>
                <p>Name : {{reservation_info.customer.first_name}}</p>
                <p>Last name : {{reservation_info.customer.last_name}}</p>
                <p>Email : {{reservation_info.customer.email}}</p>
                <h4>Reservation info</h4>
                <p>Check-in : {{reservation_info.checkin}}</p>
                <p>Check-out : {{reservation_info.checkout}}</p>
                <p>Adults : {{reservation_info.occupancy}}</p>
                <p>Total Price : {{reservation_info.total_price}}</p>
                <h4>Nights info</h4>
                <p ng-repeat="night in reservation_info.nights">
                    Day {{night.day}}  -  Rate : {{night.rate}}
                </p>
                <a href="#/pay/{{reservation_info.id}}" style="text-align: center"><button class="btn">Pay ${{reservation_info.total_price}}</button></a>
            </div>
        </div>
    </div>
</div>


That’s all about the Angular side. We received a token from Stripe and we can proceed to charge the customer for the reservation amount via the Laravel backend.

Laravel and Stripe

First of all we need to setup Cashier in Laravel starting by adding it using composer. In the composer.json add :


  "require-dev": {
        "fzaninotto/faker": "~1.4",
        "mockery/mockery": "0.9.*",
        "phpunit/phpunit": "~4.0",
        "phpspec/phpspec": "~2.1",
        "laravel/cashier": "~5.0"
    },


and run composer update from the command line.

After the module is downloaded we have to set the API keys provided by Stripe in the service.php file adding this lines :


   'stripe' => [
        'model'  => App\Customer::class,
        'key'    => 'pk_test_p0XXXXXXXXXXXX0VP7QOz5',
        'secret' => 'sk_test_vkLyXXXXXXXXXXa2r90up',
    ],


Now that Laravel is ready to use Cashier and Stripe we have to modify existing application to add some API needed and load some implementation on the Customer model.

Change the previously created model file Customer.php pasting the code below


<?php

namespace App;
use Laravel\Cashier\Billable;
use Laravel\Cashier\Contracts\Billable as BillableContract;

use Illuminate\Database\Eloquent\Model;

class Customer extends Model implements BillableContract
{
    use Billable;

    protected $fillable = ['first_name', 'last_name','email'];

}


As you can see from the code we included the Cachier library in the file and made our class implementing BillableContract.

The other file we need to modify is the ReservationController. In the AngularJS side we called the REST API to retrieve all the information about the reservation but we never implemented it. Will be enough to add the line below to the controller to provide this functionality


    public function show($id){
        return  Reservation::find($id);
    }


In the routes.php in the api group add the line below to make the function accessible


Route::get('reservation/{id}', '[email protected]');


To maintain separation by concept, as we made till now in this tutorial we need a new controller where all the payments relative API will be coded. From the command line using artisan create then a PaymentController.

php artisan make:controller PaymentController

The code for the controller is show below


<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Customer;

class PaymentController extends Controller
{

    public function pay(Request $request){

        $token  = $request['token'];
        $cutomer_id  =$request['customer_id'];
        $total_price  =$request['total']*100;

        $customer = Customer::find($cutomer_id);

        if($customer->charge($total_price,
            [
            'source' => $token,
             'receipt_email' => $customer->email
            ]))
        {
            $mess = ['status' => "OK","message" =>"Payment ok"];
            return $mess;
        }else{
            $mess = ['status' => "ERROR","message" =>"Error submitting payment"];
            return $mess;
        }
    }

}


The controller code is pretty easy to understand. There is only one function to process the payment. In the first part of it we retrieve all the information from the request. The total price of the reservation is multiplied by 100 because Stripe want the amount in cents.

After all the information are retrieved the Customer who made the reservation is retrieved from the database and the charge method is called on it passing the token acquired by Angular and the customer email. The charge() method will return true if the payment is ok and false if something where wrong. The response of the function in both case will be an HTTP 200 but the message and status is different.

All is ready to receive payments from our customer. Just add the line below in the routes.php file and you are done.

Route::post('payreservation', '[email protected]');

Conclusion

In this tutorial we have seen how to integrate a powerful system like Stripe.com with our AngularJS and Laravel application. Now the application can accept payments without knowing anything about the credit card of the customer. The tutorial is

The basic configuration of the stripe account and how to retrieve the API keys is very well explained on the stripe.com site. All other code about this tutorial can be found as always on the Github repository.

Cheerss! Happy Coding!

Adam Brown
Please follow and like us:

Leave a Comment