We are going to receive payments from two sources: PayPal and credit/debit cards. We are going to use the Braintree services to collect payments from both sources. For that, we are going to use braintree-angular
. Let's install it:
bower install braintree-angular#1.3.1 --save
Then add it to our app dependencies:
angular.module('meanshopApp', [
'ngCookies',
'ngResource',
'ngSanitize',
'btford.socket-io',
'ui.router',
'ui.bootstrap',
'ngFileUpload',
'ngCart',
'braintree-angular'
])
Now that we have the route, let's create the template and the controller. The following is the content for the template:
<!-- client/app/products/templates/products-checkout.html -->
<navbar></navbar>
<div class="container">
<div class="row">
<h1>Cart</h1>
<ngcart-cart template-url="components/ngcart/cart.html"></ngcart-cart>
</div>
<div class="row">
<h1>Choose a payment method</h1>
<p class="help-block">{{ errors }}</p><br>
<div class="col-md-6">
<form>
<braintree-dropin options="paymentOptions">Loading...</braintree-dropin>
<input type="submit" value="Purchase" />
</form>
</div>
</div>
</div>
<footer></footer>
We are using the braintree-dropin
directive to render the default card forms and the PayPal button. This form is going to take care of the validations and security.
Braintree has a workflow different from the other payment platforms. This is how it is going to work in our app:
Refer to https://developers.braintreepayments.com/javascript+node/start/overview for more detailed information.
All the Angular steps are going to be added in products.controller.js
:
/* client/app/products/products.controller.js:35 */ .constant('clientTokenPath', '/api/braintree/client_token') .controller('ProductCheckoutCtrl', function($scope, $http, $state, ngCart){ $scope.errors = ''; $scope.paymentOptions = { onPaymentMethodReceived: function(payload) { angular.merge(payload, ngCart.toObject()); payload.total = payload.totalCost; console.error(payload); $http.post('/api/orders', payload) .then(function success () { ngCart.empty(true); $state.go('products'); }, function error (res) { $scope.errors = res; }); } }; });
We add a constant with the path to get the client token. We are going to create that controller in our backend later.
In the scope, we defined a couple of things that we are already using in the checkout page such as errors
and paymentOptions
. In paymentOptions
, we are adding a callback that is going to be executed when the user provides his/her credit card number or PayPal authorization. If the authorization is successful, the payload parameter gets a nonce parameter, which will be used to execute the payment on the NodeJS side. Notice that we are also serializing the shopping cart, and adding/merging it to the payload. Finally, we create an order in our backend using the payload information. If we are able to collect the payment in the backend, we redirect the user to the marketplace and empty the cart; otherwise, we present an error message.
If you run the application (grunt serve
), you will notice that we can add and remove items from the shopping cart. However, when we enter our card data, we are unable to complete the transaction, as the route /api/orders
is not created yet. Let's move to the backend and work on that next.
18.117.142.248