I'm trying to integrate a Braintree Payments drop-in into an Ionic mobile app. Based on the Braintree documentation and some code examples i was able to find online, the following code is what I've managed to come up with so far but it doesn't seem to work:
controller.js
.controller('CheckoutForm', function($scope, $window) {
$scope.clientToken = "<token generated by the server>"
$scope.renderCheckout = function() {
braintree.setup($scope.clientToken, "dropin", {
container: "payment-form"
});
}
})
template.html
<div>
Payment details:
<form id="checkout">
<div id="payment-form" onLoad="renderCheckout()"></div>
</form>
</div>
I also included the following line in the index.html:
<script src="https://js.braintreegateway.com/js/braintree-2.23.0.min.js"></script>
I'm quite new to Ionic and HTML5/JS development in general so any help would be much appreciated.
Forget about the onload function. Just do this in your controller.
var clientToken = "eyJ2ZXJzaW9uIjoyLCJhdXRob3JpemF0aW9uRmluZ2VycHJpbnQiOiIyMTUwYzJiOWYyODdlMmZmMzUyZWQxZmMyMDFiNjY3ZDE5OGNhMjEwNjAyYmYzNzI1NmVmNDIzMWY0Yjg3OGNmfGNyZWF0ZWRfYXQ9MjAxNi0wNC0yOFQwNjoyODo1My43NjM0MjY0MzYrMDAwMFx1MDAyNm1lcmNoYW50X2lkPTM0OHBrOWNnZjNiZ3l3MmJcdTAwMjZwdWJsaWNfa2V5PTJuMjQ3ZHY4OWJxOXZtcHIiLCJjb25maWdVcmwiOiJodHRwczovL2FwaS5zYW5kYm94LmJyYWludHJlZWdhdGV3YXkuY29tOjQ0My9tZXJjaGFudHMvMzQ4cGs5Y2dmM2JneXcyYi9jbGllbnRfYXBpL3YxL2NvbmZpZ3VyYXRpb24iLCJjaGFsbGVuZ2VzIjpbXSwiZW52aXJvbm1lbnQiOiJzYW5kYm94IiwiY2xpZW50QXBpVXJsIjoiaHR0cHM6Ly9hcGkuc2FuZGJveC5icmFpbnRyZWVnYXRld2F5LmNvbTo0NDMvbWVyY2hhbnRzLzM0OHBrOWNnZjNiZ3l3MmIvY2xpZW50X2FwaSIsImFzc2V0c1VybCI6Imh0dHBzOi8vYXNzZXRzLmJyYWludHJlZWdhdGV3YXkuY29tIiwiYXV0aFVybCI6Imh0dHBzOi8vYXV0aC52ZW5tby5zYW5kYm94LmJyYWludHJlZWdhdGV3YXkuY29tIiwiYW5hbHl0aWNzIjp7InVybCI6Imh0dHBzOi8vY2xpZW50LWFuYWx5dGljcy5zYW5kYm94LmJyYWludHJlZWdhdGV3YXkuY29tLzM0OHBrOWNnZjNiZ3l3MmIifSwidGhyZWVEU2VjdXJlRW5hYmxlZCI6dHJ1ZSwicGF5cGFsRW5hYmxlZCI6dHJ1ZSwicGF5cGFsIjp7ImRpc3BsYXlOYW1lIjoiQWNtZSBXaWRnZXRzLCBMdGQuIChTYW5kYm94KSIsImNsaWVudElkIjpudWxsLCJwcml2YWN5VXJsIjoiaHR0cDovL2V4YW1wbGUuY29tL3BwIiwidXNlckFncmVlbWVudFVybCI6Imh0dHA6Ly9leGFtcGxlLmNvbS90b3MiLCJiYXNlVXJsIjoiaHR0cHM6Ly9hc3NldHMuYnJhaW50cmVlZ2F0ZXdheS5jb20iLCJhc3NldHNVcmwiOiJodHRwczovL2NoZWNrb3V0LnBheXBhbC5jb20iLCJkaXJlY3RCYXNlVXJsIjpudWxsLCJhbGxvd0h0dHAiOnRydWUsImVudmlyb25tZW50Tm9OZXR3b3JrIjp0cnVlLCJlbnZpcm9ubWVudCI6Im9mZmxpbmUiLCJ1bnZldHRlZE1lcmNoYW50IjpmYWxzZSwiYnJhaW50cmVlQ2xpZW50SWQiOiJtYXN0ZXJjbGllbnQzIiwiYmlsbGluZ0FncmVlbWVudHNFbmFibGVkIjp0cnVlLCJtZXJjaGFudEFjY291bnRJZCI6ImFjbWV3aWRnZXRzbHRkc2FuZGJveCIsImN1cnJlbmN5SXNvQ29kZSI6IlVTRCJ9LCJjb2luYmFzZUVuYWJsZWQiOmZhbHNlLCJtZXJjaGFudElkIjoiMzQ4cGs5Y2dmM2JneXcyYiIsInZlbm1vIjoib2ZmIn0=";
// Client token above is just for testing and provided by Braintree for testing purposes
braintree.setup(clientToken, "dropin", {
container: "payment-form"
});
Then in your html:
<form id="checkout">
<div id="payment-form"></div>
</form>
For mobile remember to add proper Content security policy and whitelists with the cordova-whitelist-plugin.
Documentation for CSP: https://developers.braintreepayments.com/reference/client-reference/javascript/v2/best-practices#using-braintree.js-with-a-content-security-policy
Documentation for Cordova whitelist plugin:
https://cordova.apache.org/docs/en/latest/guide/appdev/whitelist/index.html
What 'thepio' suggested is for testing only. But proper way might be to generate the Client Token on you server. Then your Ionic app will POST and get the Client Token from your server. And then once payment nonce is generated, you can POST your payment data to your server to process the payment.
Check this sample implementation.
https://github.com/demianborba/braintree-cordova-angular-node
Related
I'm searching for example of implementation for Recurlyjs normal Paypal checkout flow. I suppose to request Billing info from the user besides Paypal token but it's not clear how do I merge them together to use.
Here are docs mentioning normal workflow but no details: https://docs.recurly.com/docs/paypal-payments
Here is example of Paypal express flow:
https://github.com/recurly/recurly-js-examples/blob/master/public/paypal/index.html . It looks like I need to add [additional-fields] to the form and merge_token_fields, but I can not find appropriate function.
<section>
<form method="post" action="/api/subscriptions/new">
<button id="subscribe">Subscribe with PayPal</button>
<div name="recurly-[additional-fields]></div> // TODO: fix this
<input type="hidden" id="recurly-token" name="recurly-token">
</form>
<script>
var form = $('form');
recurly.configure('PUBLIC_KEY');
var paypal = recurly.PayPal({
display: { displayName: 'My product' }
});
paypal.on('token', function (token) {
$('#recurly-token').val(token.id);
merge_token_fields(); // TODO: fix this
form[0].submit();
});
form.on('submit', function (event) {
event.preventDefault();
paypal.start();
});
</script>
</section>
The steps you'd want to follow:
1) Get Paypal token
2) Collect billing address (can be done on the recurly.js form and passed to the API)
3) From API, pass the Paypal billing agreement to the account
4) A subsequent request to pass billing address to account as a billing info update
I use PayPal Adaptive Payments (parallel) on my website and I've encountered a strange problem with two payments in two different browser tabs from the same sender. The similar question was asked before, but nobody answered there.
The scenario which reproduces the problem
The user opens the first browser tab of the website and starts a payment process to the first seller.
PayPal's lightbox with Login button appears.
The user opens the second browser tab of the website and starts a payment process to the second seller.
Again, PyaPal's lightbox with Login button appears.
The user returns to the first browser tab and login to PayPal.
After login to PayPal in the first browser tab the user sees payment details to the second seller.
After login to PayPal in the second browser tab the user sees payment details to the second seller.
It seems that PayPal Adaptive Payments support only one transaction from one sender.
How it works
The website works with Ruby on Rails and I use paypal_adaptive gem for payments with PayPal. The payment flow is quite simple:
The user clicks on Buy button on the website. The client makes AJAX request which handled by payment controller in Ruby on Rails.
In the controller the app makes Pay request to PayPal API using paypal_adaptive gem and receives a PayKey (see the code below).
The server responds to the client with the PayKey and the client uses it in PayPal form to start payment process through PayPal's lightbox (see the code below).
That's it. After that I do not control anything (the payment process goes through PayPal's external webpage).
Additional notes
I'm sure that the data for Pay request is different on the server side in the test scenario listed above.
I've tried different PayPal's dialog options besides PayPal's lightbox: mini-browser and popup. These options doesn't affect on this bug and it is still reproducable.
The client code
<script src="https://www.paypalobjects.com/js/external/dg.js" type="text/javascript"></script>
<form action="https://www.sandbox.paypal.com/webapps/adaptivepayment/flow/pay" class="paypal-hidden-form" target="PPDGFrame">
<button id="paypal-submit"></button>
<input id="type" type="hidden" name="expType" value="light">
<!-- Insert PayKey here and click on the form's submit button using jQuery after server's response. -->
<input id="paypal-key" type="hidden" name="paykey" value="">
</form>
<!-- Paypal -->
<script type="text/javascript" charset="utf-8">
var dgFlow = new PAYPAL.apps.DGFlow({ trigger: "paypal-submit", expType: "light" });
function MyEmbeddedFlow(embeddedFlow) {
this.embeddedPPObj = embeddedFlow;
this.paymentSuccess = function(paymentStatus) {
this.embeddedPPObj.closeFlow();
// More UI code here...
};
this.paymentCanceled = function() {
this.embeddedPPObj.closeFlow();
// More UI code here...
};
}
var myEmbeddedPaymentFlow = new MyEmbeddedFlow(dgFlow);
</script>
The server code
# Make a Pay request to PayPal API.
paypal_payment_thread = Thread.new do
# Some preparation code goes here...
pay_request = PaypalAdaptive::Request.new
process_guid = SecureRandom.uuid
# Construct Pay API request data.
data = {
:returnUrl => "#{PAYPAL_RETURN_URL}?process_guid=#{process_guid}",
:cancelUrl => "#{PAYPAL_CANCEL_URL}?process_guid=#{process_guid}",
:requestEnvelope => {
:errorLanguage => "en_US"
},
:currencyCode => "USD",
:receiverList => {
:receiver => [{
# seller_paypal value is different for two payments.
# But in fact we do the last payment for both payments.
:email => seller_paypal,
:amount => ORDER_SELLER_AMOUNT,
:paymentType => "DIGITALGOODS"
}, {
:email => PAYPAL_MARKETPLACE_EMAIL,
:amount => ORDER_MARKETPLACE_AMOUNT,
:paymentType => "DIGITALGOODS"
}]
},
:actionType => "PAY",
:ipnNotificationUrl => PAYPAL_NOTIFY_URL,
:reverseAllParallelPaymentsOnError => "true",
:trackingId => process_guid
}
# Make a Pay API request.
pay_response = pay_request.pay(data)
if pay_response.success?
# Everything is ok. Update database here...
else
raise Exceptions::PaypalPaymentError
end
end
I've removed some unimportant code just to be clear, how it really works.
Thanks in advance for the help!
Looks like it is by design. I've tried the same test here on the website of one of PayPal's employees and it is reproducible there.
PayPal's support answered me that the problem in using Lightbox. However I've tried Mini-Browser and Popup options as I described in my post without no effect.
Also, PayPal's support answered me that this is by design and adviced me to contact with Technical Support. Maybe it will be useful for someone else.
Hi Michael, Thanks, yes I was able to reproduce it as well. However
it’s important to understand that PayPal is not made for handling 2
payment flows at the same time. If you want to get further on that,
you can contact our Technical Support : https://ppmts.custhelp.com/
They have other tools to debug and may be able to give you a better
understanding of the technical problem.
Finally I've blocked simultaneous payments using a special flag in HTML5 Local Storage and dgFlow.isOpen() method of PAYPAL.apps.DGFlow object to detect PayPal window. On window close I reset this flag using onunload and onbeforeunload events of window.
I close this question. Thanks.
Two windows (one lightbox window and another paypal main page window) simultaneously open up when I click Continue to paypal in my website (Please Note: at this time I have Token from paypal and onclicking this button I redirect user to:
Response.Redirect("https://www.sandbox.paypal.com/incontext?token=" + resp.Token+"&useraction=commit");
and I call javascript function as:
<script type="text/javascript">
$(document).ready(function () {
var dg = new PAYPAL.apps.DGFlow({ trigger: "PP_btn", expType: "mini" });
});
</script>
The paypal window opening shows error: "Dispatch Error, please check logfile for more information"
Don't understand what the problem is. Let me know what should I do?
To open the PayPal lightbox window, here is the simplest way:
<form action='checkout.php' METHOD='POST'>
<input type='image' name='paypal_submit' id='paypal_submit' src='https://www.paypal.com/en_US/i/btn/btn_dg_pay_w_paypal.gif' border='0' align='top' alt='Pay with PayPal'/>
</form>
<!-- Add Digital goods in-context experience. Ensure that this script is added before the closing of html body tag -->
<script src='https://www.paypalobjects.com/js/external/dg.js' type='text/javascript'></script>
<script>
var dg = new PAYPAL.apps.DGFlow(
{
trigger: 'paypal_submit',
expType: 'instant'
//PayPal will decide the experience type for the buyer based on his/her 'Remember me on your computer' option.
});
</script>
Is it possible to launch the payflow entirely inline (a la Express Checkout)? How?
We're using chained payments and everything works on non-iOS-mobile devices (and in Chrome for iOS), but we're making a web app, so we need this to work on phones. Testing on the iPhone, we have this problem with PayPal's code that I've already asked about, as well as the fact that when I get around that bug by doing a location.replace with the URL to PayPal (or loading it in a lightbox of my own design), iOS and mobile Safari kill the "Log In" popup (without giving the user an opportunity to view it if they so choose).
In short, is there any way I can use Adaptive Payments without ridiculous 1990s-era popups???
Here's what I'm doing to use PayPal's mobile web flow. I'm testing on Android and it's working well. The only hang up is the callbackFunction is not firing in mobile browsers and works fine in desktop browsers. (I'm still working on this part. Let me know if you solve it.) Here's an example on how to do it using expType=mini to launch the PayPal mini browser experience.
First include the Javascript for the Mini flow:
<script src="http://www.paypalobjects.com/js/external/apdg.js"></script>
Then a link to launch the redirect:
<a id="payPalRedirect" href="https://www.sandbox.paypal.com/webapps/adaptivepayment/flow/pay?paykey={paykey}&expType=mini" target="_blank">Complete PayPal Payment</a>
<br /><br />
<div id="resultDiv"></div>
And some Javascript to initiate the Mini Flow process and the callbackFunction:
var returnFromPayPal = function () {
alert("Returned from PayPal");
var div = document.getElementById('resultDiv');
div.innerHTML = "Returned from PayPal!";
// Here you would need to pass on the payKey to your server side handle to call the PaymentDetails API to make sure Payment has been successful or not
// based on the payment status- redirect to your success or cancel/failed urls
}
var dgFlowMini = new PAYPAL.apps.DGFlowMini({ trigger: 'payPalRedirect', expType: 'mini', callbackFunction: 'returnFromPayPal' });
More insights and solution options to this issue can be found here:
Paypal Embedded Flow not using returnUrl or cancelUrl
I'm having an issue connecting to Facebook through the Javascript Client Library in Adobe AIR. It works fine in the browser but in Adobe AIR it seems to not be able to find the Facebook functions. Here is some code I copied from the Facebook website: (Oh and I have the xd_receiver.htm file in the correct path too)
<textarea style="width: 1000px; height: 300px;" id="_traceTextBox">
</textarea>
<script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php" type="text/javascript"></script>
//
var api = FB.Facebook.apiClient;
// require user to login
api.requireLogin(function(exception){
FB.FBDebug.logLevel=1;
FB.FBDebug.dump("Current user id is " + api.get_session().uid);
// Get friends list
//5-14-09: this code below is broken, correct code follows
//api.friends_get(null, function(result){
// Debug.dump(result, 'friendsResult from non-batch execution ');
// });
api.friends_get(new Array(), function(result, exception){
FB.FBDebug.dump(result, 'friendsResult from non-batch execution ');
});
});
});
//]]>
</script>
It's not that simple actually man, the problem with loading external script files from the application sandbox is that it's not supported. Technically, by using iframes, you should be able to do this and it works but it's still impossible to use XFBML in the root document after from my experience. After two days of trial and error, the easiest way to do use Facebook Connect in an html/ajax adobe air application is to download the actionscript library and include it as such:
<script type="application/x-shockwave-flash" src="lib/facebook.swf"></script>
<script type="text/javascript">
var FB = window.runtime.com.facebook;
var fb = new FB.Facebook();
var session = new FB.utils.DesktopSessionHelper();
//etc...
</script>
then just refer to the documentation. my only problem now it that I still haven't found an efficient enough way of using XFBML in adobe air, simply adding the facebook namespace to the html tag doesn't do the trick unfortunately. If any knows, please do share thanks
you also need to change xml namespace (main html tag) to this:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:fb="http://www.facebook.com/2008/fbml" xml:lang="en-gb" lang="en-gb">