ウェブサイトで PayPal アダプティブ ペイメント (並行) を使用していますが、同じ送信者から 2 つの異なるブラウザー タブで 2 つの支払いを行うと奇妙な問題が発生しました。同様の質問が以前に尋ねられましたが、誰もそこに答えませんでした。
問題を再現するシナリオ
- ユーザーは Web サイトの最初のブラウザー タブを開き、最初の売り手への支払いプロセスを開始します。
- ログインボタンのあるPayPalのライトボックスが表示されます。
- ユーザーは Web サイトの 2 番目のブラウザー タブを開き、2番目の販売者への支払いプロセスを開始します。
- 再び、ログインボタンのある PyaPal のライトボックスが表示されます。
- ユーザーは最初のブラウザー タブに戻り、PayPal にログインします。
- 最初のブラウザー タブで PayPal にログインすると、ユーザーは2 番目の売り手への支払いの詳細を確認します。
- 2 番目のブラウザ タブで PayPal にログインすると、ユーザーは2 番目の販売者への支払いの詳細を確認できます。
PayPal アダプティブ ペイメントは、1 つの送信者からの 1 つのトランザクションのみをサポートしているようです。
使い方
ウェブサイトは Ruby on Rails で動作し、PayPal での支払いにはpaypal_adaptive gemを使用しています。支払いの流れは非常に簡単です。
- ユーザーが Web サイトの [購入] ボタンをクリックします。クライアントは、Ruby on Rails の支払いコントローラーによって処理される AJAX 要求を行います。
- コントローラーで、アプリはpaypal_adaptive gem を使用して PayPal API にPay リクエストを行い、PayKey を受け取ります (以下のコードを参照)。
- サーバーは PayKey でクライアントに応答し、クライアントはそれを PayPal フォームで使用して、PayPal のライトボックスを介して支払いプロセスを開始します (以下のコードを参照)。
それでおしまい。その後、私は何も制御しません (支払いプロセスは PayPal の外部 Web ページを経由します)。
その他の注意事項
- 上記のテスト シナリオでは、Pay リクエストのデータがサーバー側で異なると確信しています。
- PayPal のライトボックス以外に、PayPal のさまざまなダイアログ オプションを試しました: ミニブラウザとポップアップ。これらのオプションはこのバグには影響せず、まだ再現可能です。
クライアントコード
<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>
サーバーコード
# 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
実際にどのように機能するかを明確にするために、重要でないコードをいくつか削除しました。
助けてくれてありがとう!