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.
Related
I have to integrate PayPal payments in Flutter and the only plugin that seems to have this kind of functionality is flutter_braintree. But the documentation there is not so detailed, so I am kind of confused how to use this plugin to have real payments. My mission is to have this kind of flow: click on a PayPal button in the app and then proceed with PayPal paying to a predefined IBAN. I tried to examine the PayPal and Braintree documentations, but since there is nothing mentioned for Flutter, I am a little bit confused.
Please help me what's the right direction to go in order to fulfil my requirements. I have the following questions:
How to use this plugin and make real payments? What do I need - a client token as far as I see, but I am going to generate this in Flutter?
Where should I put the IBAN that I want the money to be transferred to?
Am I supposed to use some kind of webviews for the PayPal, or this plugin is enough?
Thank you in advance, I am really stuck on this topic and can't find a solution.
Generate clientToken in php | nodejs see: https://developers.braintreepayments.com/reference/request/client-token/generate/php
$clientToken = $gateway->clientToken()->generate([
"customerId" => '21534539348326'//create customer in panel
]);`
Generate paymentNonce in app flutter:
BraintreePayment braintreePayment = new BraintreePayment();
var data = await braintreePayment.showDropIn(
nonce: clientNonce,
amount: "2.0",
inSandbox: true,
);
print("Response of the payment $data");
// exe: Generate transaction in php | nodejs see: https://github.com/braintree/braintree_php
$result = $gateway->transaction()->sale([
'amount' => '1000.00',
'paymentMethodNonce' => 'nonceFromTheClient',
'options' => [ 'submitForSettlement' => true ]
]);
How can I trigger PayPal Checkout button click?
We have a website were beside the Credit Cards we are going to accept also PayPal payments and I have decided to put radio buttons for the customers to choose which way the customer is going to pay and also PayPal Checkout button:
PayPal Checkout button click itself opens the PayPal secure window and the rest works fine. When customer click the 1st radio button I want again open PayPal secure window i.e. trigger click on PayPal checkout button.
How can I do that if the button itself appearing in iframe and I am not able to trigger click event of that button cross domain? Is there any way to trigger checkout button click?
Here is the HTML code:
<html>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script src="https://www.paypalobjects.com/api/checkout.js"></script>
<script type="text/javascript" src="paypal.js">
</script>
<body>
<div>
<span style="vertical-align: 50%"><input id="rd" name="aaa" type="radio"/></span>
<div id="paypal-button-container" style="display: inline-block"></div><hr/>
<input id="rd1" name="aaa" type="radio"/>
</div>
</body>
</html>
And Javascript code:
// paypal.js
// Render the PayPal button
$(function(){
paypal.Button.render({
// Set your environment
//TODO: Dynamically provide sandbox or production
env: 'sandbox', // sandbox | production
// PayPal Client IDs - replace with your own
// Create a PayPal app: https://developer.paypal.com/developer/applications/create
//TODO: Dynamically provide clientID
client: {
sandbox: 'ZZZZZZ',
production: '//TODO: Provide this later'
},
// Wait for the PayPal button to be clicked
payment: function() {
// Make a client-side call to the REST api to create the payment
return paypal.rest.payment.create(this.props.env, this.props.client, {
transactions: [
{
amount: { total: '13.10', currency: 'USD' }
}
]
});
},
// Wait for the payment to be authorized by the customer
onAuthorize: function(data, actions) {
return actions.payment.get().then(function(paymentData) {
$('#paypal-button-container').style.display = 'none'; //hide button
//TODO: Show user payment details
//TODO: Create input hidden fields and set payerID, paymentID, etc..for later authoriza/capture
});
},
onClick: function(){
$('#rd').trigger('click');
},
}, '#paypal-button-container');
});
EDIT: As a working example I would suggest this site, but this is little bit different what I need https://developer.paypal.com/demo/checkout/#/pattern/mark
This isn't something that's supported by the PayPal button right now. The official policy is, only a click on the button itself should open a checkout window.
I guess I am a little bit late, but I hope this will help people who faced this problem, just like me.
You can set paypal's button opacity to 0 and put it over your own checkout button. Then you can set it's display to 'none' or 'block' depending on radio button value.
In my case, I just wanted to use a completely customized button for space reasons. In the end, I hid the paypal button until it on mouse over wrapped in an overflow:hidden div. It looks ok - like a square paypal button without left/right padding..
Background: Paypal's current express checkout documentation says they only support buttons at 80px minimum size, but playing with CSS, seems like the real minimimum on desktop is appx 120px wide.
First of it need to clear what you are using.
Checkout js then checkout with checkout.js. Valid before February 2019.
JavaScript sdk then there is no official announcement from paypal, if anyone do reverse engineering then would be possible.
It's literally not supported. You can't programmatically click on paypal button.
Please visit for more clarification: https://github.com/paypal/paypal-checkout-components/issues/512
I've implemented Website Payments Pro Hosted on my website. I can pay using the PayPal log in and it gives me the link to return to my store which is fine as I then display my order confirmation page to the user.
When the user decides to pay via credit card:
They are then redirected to a confirmation page I don't seem to have any control over:
What I've tried:
Setting auto return on in my preferences and setting a return url (both via the Profile and in my initial API call when generating the button.
Changing the Web Payments Pro confirmation page setting to On my sites confirmation page.
When the payment is taken via credit card, I'd like to redirect the user to my actual payment confirmation page. Is this possible?
It turns out that showHostedThankyouPage=true was causing this issue.
I am using the .NET button API to generate the request for the iFrame like so:
var service = new PayPalAPIInterfaceServiceService(GetConfig(request));
var createButtonResponse = service.BMCreateButton(new BMCreateButtonReq
{
BMCreateButtonRequest = new BMCreateButtonRequestType
{
ButtonType = ButtonTypeType.PAYMENT,
ButtonCode = ButtonCodeType.TOKEN,
ButtonCountry = countryCodeType,
ButtonVar = new List<string>
{
String.Format("subtotal={0}", _salesOrderPriceService.GetGrossTotal(request.Order)),
String.Format("notify_url={0}", request.NotifyUrl),
String.Format("return={0}", request.ReturnUrl),
String.Format("invoice={0}", request.Order.Id),
String.Format("currency_code={0}", request.Order.Currency.Code),
String.Format("cancel_return={0}", request.CancelReturnUrl),
"billing_first_name=test",
"billing_last_name=tset",
"billing_address1=test",
"billing_city=test",
"billing_state=tes",
"billing_zip=test",
"billing_country=GB",
"template=templateD",
"paymentaction=sale",
"business=tset"
}
}
});
I had showHostedThankyouPage=true included in the name value pairs which was causing the issue. Removing it sorted it out.
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
MVC 3 VB.NET applicaiton... Using express checkout with html razor view. I have tried everything mentioned in all of the docs i could google for as well as the ones on paypal's dev network. Our Paypal account is setup to allow users to Check out as Guest without requiring paypal account creation or login. However when users are taken to the paypal site after clicking the checkout button there is no option to check out as guest. I am including my checkout view for reference. Please understand that this is a valid question and do not down vote it. If there is something not clear I will clarify it..
#modeltype xxxxxxx.orderVM
#Code
ViewData("Title") = "CheckOut"
End Code
<p style="text-align:center">Once you complete your transaction you will be redirected back to the site</p>
<p></p>
<p style="text-align:center">We will process your payment within 24 hours at which time you will recieve a confirmation email which you will need for addmission. Along with a PDF attachment in this email which is your parking permit.. Please print and follow the instructions</p>
<p></p>
<p></p>
<p></p>
<p></p>
<p style="text-align: center"> Please Click on the paypal button below to be redirected to the PayPal Site to complete the payment Transaction</p>
<form id="PayPal" name="PayPal" action="https://www.paypal.com/cgi-bin/webscr" method="post">
#Html.Hidden("cmd", "_cart")
#Html.Hidden("upload", "1")
#Html.Hidden("business", ConfigurationManager.AppSettings("PayPalMerchantEmail"))
#Html.Hidden("page_style","primary")
#Html.Hidden("custom", Model.id.ToString)
#Html.Hidden("image_url", "http://www.xxxxxxxxxx.com/content/images/xxxxxxxxLogo.jpg")
#Html.Hidden("cpp_header_image", "http://www.xxxxxxxx.com/content/images/xxxxxxxLogo.jpg")
#Html.Hidden("cpp_logo_image", "http://www.xxxxxxxxxxe.com/content/images/xxxxxxxLogo.jpg")
#Html.Hidden("return", "http://www.xxxxxxxxxx.com/")
#Html.Hidden("cancel_return", "http://www.xxxxxxxxxx.com")
#Html.Hidden("first_name", Model.first_name)
#Html.Hidden("last_name", Model.last_name)
#Html.Hidden("address1", Model.address1)
#Html.Hidden("address2", Model.address2)
#Html.Hidden("city", Model.city)
#Html.Hidden("state", Model.state)
#Html.Hidden("zip", Model.zip)
#If Not String.IsNullOrEmpty(Model.Class1) Then
#Html.Hidden("item_name_1", Model.Class1)
#Html.Hidden("amount_1", Model.fee1)
#Html.Hidden("quantity_1", ViewBag.quan)
#Html.Hidden("shipping_1", " 0.00 ")
#Html.Hidden("handling_1", " 0.00 ")
End If
<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_xpressCheckout.gif" align="middle" style="text-align:center"/>
</form>
I do not feel the code for the controller is required here since it does pass all the values correctly into the view... The only issue is I can not get check out as guest working...
Have you turned on 'Account Optional' in your PayPal Profile?
Which country is your account located in? The guest checkout functionality is not available in all countries yet.