0
votes

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

  1. The user opens the first browser tab of the website and starts a payment process to the first seller.
  2. PayPal's lightbox with Login button appears.
  3. The user opens the second browser tab of the website and starts a payment process to the second seller.
  4. Again, PyaPal's lightbox with Login button appears.
  5. The user returns to the first browser tab and login to PayPal.
  6. After login to PayPal in the first browser tab the user sees payment details to the second seller.
  7. 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:

  1. The user clicks on Buy button on the website. The client makes AJAX request which handled by payment controller in Ruby on Rails.
  2. In the controller the app makes Pay request to PayPal API using paypal_adaptive gem and receives a PayKey (see the code below).
  3. 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

  1. I'm sure that the data for Pay request is different on the server side in the test scenario listed above.
  2. 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!

1

1 Answers

1
votes

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.