5

私はPaypalの適応型支払いシステムを使用しています。サンドボックスアカウントを使用して、PayRequestを作成し、Paypalに転送して支払いを行うことができました。その場合、次のようになります。

リクエスト=

2012年4月24日午後10時35分46秒com.paypal.adaptive.api.requests.PayRequest実行情報:PayRequestの送信:requestEnvelope.errorLanguage = en_US&actionType = PAY&receiverList.receiver(0).email = Seller_1334320690_biz%40email.org&ReceiverList.receiver(0).amount = 5.0&currencyCode = EUR&feesPayer = SENDER&cancelUrl = https%3A%2F%2Flocalhost%3A8443&returnUrl = http%3A%2F%2Flocalhost%2F&ipnNotificationUrl = http%3A%2F%2Flocalhostu%2Ffinishdeposit&

応答=

2012年4月24日午後10時35分48秒com.paypal.adaptive.api.requests.PayPalBaseRequestmakeRequest情報:受信した応答:responseEnvelope.timestamp = 2012-04-24T13%3A35%3A48.587-07%3A00&responseEnvelope.ack = Success&responseEnvelope.correlationId = c8dee8023cca6&responseEnvelope.build = 2756816&payKey = AP-1UF57245CJ360523K&paymentExecStatus = CREATED

私は今、どのように確認できるかを理解しようとしています、支払いは正常に完了しました。そこで、サンドボックスツールを使用して動作するipnシステムを実装しようとしました。しかし、2つを接続する方法がわかりません。つまり、支払いが行われるとき、おそらく保留中/作成済みとして、このユーザーが支払いを行ったというレコードをデータベースに作成する必要があると思いますか?次に、ipnが戻って支払いが行われたことを通知するのを待ち、データベーステーブルを更新して完了しますか?PayRequestをIPN-Notificationに関連付けるにはどうすればよいですか?Paypalから取得しますか?PaypalはIPNでいくつかの情報を送信しているだけです-通知は次のようになります:

  • item_number = AK-1234
  • Residence_country = US
  • verify_sign = ArcmaOINNZx08uC3iQY0zhEQN3IZAz70ynRk93Or8ixRi23bb4rGNIrd
  • address_country=アメリカ合衆国
  • address_city=サンノゼ
  • address_status=未確認
  • payment_status=完了
  • business=seller@paypalsandbox.com
  • payer_id = TESTBUYERID01
  • first_name = John
  • 送料=3.04
  • payer_email=buyer@paypalsandbox.com
  • mc_fee = 0.44
  • txn_id = 484221854
  • 数量=1
  • Receiver_email=seller@paypalsandbox.com
  • notify_version = 2.1
  • txn_type = web_accept
  • test_ipn = 1
  • payer_status = verified
  • mc_currency = USD
  • mc_gross = 12.34
  • custom = xyz123
  • mc_gross_1 = 9.34
  • payment_date = 11:54:482012年4月22日PDT
  • charset = windows-1252
  • address_country_code = US
  • address_zip = 95131
  • address_state = CA
  • 税金=2.02
  • item_name = something
  • address_name = John Smith
  • last_name = Smith
  • 支払いタイプ=インスタント
  • address_street = 123、任意のストリート
  • Receiver_id = TESTSELLERID1

そのIPN-Notifcationで使用できるものが見つかりません。最良の方法は、支払い応答ですでに取得したIPN通知と同じ相関IDを取得できる場合です。したがって、response-correlation-idをデータベースに保存してから、同じcorrelation-idでIPN-Notificationを受信したかどうかを確認できます。

4

3 に答える 3

14

彼らがサンドボックスであなたに与えるテストIPNはひどいです。実際のコールバック(テストでさえ)にトリガーされた実際のコールバックを見ると、payKeyが定義されていることがわかります。これはあなたがそれを調べるために使うものです。

IPNコールバックにはポート80が必要であることに注意してください(ただし、これはどこにも文書化されていません)。

これが実際のIPN通知です(JSONに変換され、私のアプリに固有の情報が編集されました):

{"payment_request_date":"Sun Jun 24 06:12:20 PDT 2012",
"return_url":"http://redacted/paypal/transactions/3?status=completed",
"fees_payer":"EACHRECEIVER",
"ipn_notification_url":"http://redacted/paypal/notifications",
"sender_email":"redacted",
"verify_sign":"AFcWxVredacted",
"test_ipn":"1",
"transaction[0].id_for_sender_txn":"redacted",
"transaction[0].receiver":"redacted",
"cancel_url":"http://redacted/paypal/transactions/3?status=canceled",
"transaction[0].is_primary_receiver":"false",
"pay_key":"AP-redacted",
"action_type":"PAY",
"transaction[0].id":"redacted",
"transaction[0].status":"Completed",
"transaction[0].paymentType":"SERVICE",
"transaction[0].status_for_sender_txn":"Completed",
"transaction[0].pending_reason":"NONE",
"transaction_type":"Adaptive Payment PAY",
"transaction[0].amount":"USD 1.00",
"status":"COMPLETED",
"log_default_shipping_address_in_transaction":"false",
"charset":"windows-1252",
"notify_version":"UNVERSIONED",
"reverse_all_parallel_payments_on_error":"true"}

PAYリクエストでreverse_all_parallel_payments_on_errorを手動で設定する必要があることに注意してください。彼らがそうすることを勧めているとしても(そしてそれはおそらくあなたの不安を救うでしょう)、それはデフォルトでは誤りです。

また、IPNを見逃した場合は、PaymentDetailsを使用してすべて同じ情報を直接取得できます。

@ swade1987が何を見ているのかわかりませんが、私のIPNには料金の金額に関する情報が含まれていません。(それが実際に私がこの投稿を見つけた方法です。理由を理解しようとしています。PPAPIドキュメントは恐ろしいです。)

追加のドキュメントはここにありますhttps://developer.paypal.com/docs/classic/adaptive-payments/integration-guide/APIPN/

于 2012-06-24T19:03:24.457 に答える
3

少し遅れましたが、検索エンジンからここに出くわした人のために...

最近、自分で Paypal API を扱い始めました。OP が引用している IPN メッセージは、販売者プロファイルで定義された IPN 通知 URL で配信されるメッセージです。対照的に、@sai によって引用された IPN は、Pay、ExecutePaypement、または Preapproval API 要求で定義された ipnNotificationUrl に配信されるアダプティブ ペイメント IPN です。

これらは 2 つの異なるタイプの IPN メッセージであり、文書化されています。支払い情報変数と支払い/事前承認メッセージ変数を探してください。両方を選択すると、両方のタイプの IPN を取得できます。

OP によって引用された IPN メッセージに関しては、txn_id フィールドの値を使用して、transactionId で PaymentDetails を取得できます。transactionId は、完了した支払いを参照するための payKey と同じです。

于 2014-11-20T09:51:42.960 に答える
2

これは大いに役立つはずです。

namespace Gateway
{
    public class MerchantSellerIPNService : IMerchantSellerIPNService
    {
        /// <summary>
        /// This is the method which is hit when using the URL in the PAY request to PayPal.
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public string ProcessIPN(Stream stream)
        {
            // Declare locally used variables.
            byte[] requestArray = null;
            string requestString = null;
            string responseString = null;
            StreamReader IPNReturnReader;
            StreamWriter streamWriter;
            MemoryStream responseStream = new MemoryStream();
            HttpWebRequest payPalRequest;
            System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();

            // Get the URL to send the IPN received back to PayPal (use either of the two below depending on the environment.)
            <add key="PAYPAL_IPN_URL" value="https://www.sandbox.paypal.com/cgi-bin/webscr" />
            <add key="PAYPAL_IPN_URL" value="https://www.paypal.com/cgi-bin/webscr"/>

            string IPNReturnURL = ConfigurationManager.AppSettings["PAYPAL_IPN_URL"];

            // Read in the data provided from PayPal
            StreamReader streamReader = new StreamReader(stream);

            // Obtain the email address and pre-approval key passed to use via PayPal for later use.
            string strPayPalMessage = streamReader.ReadToEnd();

            // Initalize the POST web request we are going to send to PayPal to valid the IPN we received from them.
            payPalRequest = (HttpWebRequest)WebRequest.Create(IPNReturnURL);
            payPalRequest.Method = "POST";
            payPalRequest.ContentType = "application/x-www-form-urlencoded";

            // Create an array containing the IPN message PayPal sent to us.
            requestArray = encoding.GetBytes(strPayPalMessage);

            // Then add the necessary string to the back to use for verfication.
            requestString = Encoding.ASCII.GetString(requestArray);
            requestString += "&cmd=_notify-validate";
            payPalRequest.ContentLength = requestString.Length;

            // Now write the updated IPN message back to PayPal for verification.
            streamWriter = new StreamWriter(payPalRequest.GetRequestStream(), System.Text.Encoding.ASCII);
            streamWriter.Write(requestString);
            streamWriter.Close();

            // Read the response from PayPal and process it.
            IPNReturnReader = new StreamReader(payPalRequest.GetResponse().GetResponseStream());
            responseString = IPNReturnReader.ReadToEnd();
            IPNReturnReader.Close();

            if (responseString == "VERIFIED")
            {
                try
                {
                    if (strPayPalMessage.Contains("payment_status=Completed"))
                    {
                        if (ProcessPaymentIPNMessage(strPayPalMessage))
                            PayPalInStore.Utils.ErrorHandler.LogError(new Exception("ProcessPaymentIPNMessage - Able to create new payment Transaction Detail Record"), "DEBUG");
                        else
                            PayPalInStore.Utils.ErrorHandler.LogError(new Exception("ProcessPaymentIPNMessage - Unable to create new payment Transaction Detail Record"), "DEBUG");
                    }
                    else if (strPayPalMessage.Contains("payment_status=Refunded"))
                    {
                        if (ProcessRefundIPNMessage(strPayPalMessage))
                            PayPalInStore.Utils.ErrorHandler.LogError(new Exception("ProcessRefundIPNMessage - Able to create new refund Transaction Detail Record"), "DEBUG");
                        else
                            PayPalInStore.Utils.ErrorHandler.LogError(new Exception("ProcessRefundIPNMessage - Unable to create new refund Transaction Detail Record"), "DEBUG");
                    }
                    else
                    {
                        PayPalInStore.Utils.ErrorHandler.LogError(new Exception("MerchantSellerIPNService - ProcessIPN - Unknown message type"), "DEBUG");
                    }
                }
                catch (Exception ex)
                {
                    PayPalInStore.Utils.ErrorHandler.LogError(new Exception("MerchantSellerIPNService - ProcessIPN failed"), "DEBUG");
                }
            }
            else if (responseString == "INVALID")
            {
                PayPalInStore.Utils.ErrorHandler.LogError(new Exception("MerchantSellerIPNService - Invalid IPN Message Received: "), "DEBUG");
            }
            else
            {
                PayPalInStore.Utils.ErrorHandler.LogError(new Exception("MerchantSellerIPNService - Fatal IPN Message Received: "), "DEBUG");
            }

            return "MerchantSellerIPNService Completed";
        }

        /// <summary>
        /// Method used to process the Payment IPN notification message and update the database as required.
        /// </summary>
        /// <returns></returns>
        private bool ProcessPaymentIPNMessage(string PayPalIPNMessage)
        {
            // Firstly, we need to split the IPN message into sections based on the & sign.
            string[] PayPalMessageElemetsArray = PayPalIPNMessage.Split('&');

            // Now obtain the list of information (from the message) we require to make the TransactionDetail record.
            string merchantTransactionId = Array.Find(PayPalMessageElemetsArray, element => element.StartsWith("txn_id=", StringComparison.Ordinal));
            string feeAmount = Array.Find(PayPalMessageElemetsArray, element => element.StartsWith("mc_fee=", StringComparison.Ordinal));
            string grossAmount = Array.Find(PayPalMessageElemetsArray, element => element.StartsWith("mc_gross=", StringComparison.Ordinal));

            // TODO: REMOVE THIS ITS FOR DEBUGGING PURPOSES
            string errorMessage2 = String.Format("ProcessPaymentIPNMessage - merchantTransactionId: {0}, feeAmount: {1}, grossAmount: {2}", merchantTransactionId, feeAmount, grossAmount);
            PayPalInStore.Utils.ErrorHandler.LogError(new Exception(errorMessage2), "DEBUG");

            try
            {
                // We now need to remove the variable name and '=' from the elements so we only have the necessary information.
                merchantTransactionId = merchantTransactionId.Replace("txn_id=", "");
                feeAmount = feeAmount.Replace("mc_fee=", "");
                grossAmount = grossAmount.Replace("mc_gross=", "");

                // Now convert the values obtained from the IPN message and calculate the net amount.
                decimal dFeeAmount = Convert.ToDecimal(feeAmount);
                decimal dGrossAmount = Convert.ToDecimal(grossAmount);
                decimal dNetAmount = Math.Round((dGrossAmount - dFeeAmount), 2);

                try
                {
                    // Finally create the new transaction fee record.
                    TransactionDetail transactionDetail = new TransactionDetail();
                    transactionDetail.MerchantTransactionId = merchantTransactionId;
                    transactionDetail.Gross = dGrossAmount;
                    transactionDetail.Fee = Decimal.Negate(dFeeAmount);
                    transactionDetail.Net = dNetAmount;
                    transactionDetail.TransactionType = (int)TransactionDetailTransactionType.InStorePayment;
                    transactionDetail.Save();
                }
                catch (Exception ex)
                {
                    string errorMessage = String.Format("ProcessPaymentIPNMessage - Unable to create new TransactionDetail record for Merchant Transaction ID: {0}", merchantTransactionId);
                    PayPalInStore.Utils.ErrorHandler.LogError(new Exception(errorMessage), "DEBUG");
                    return false;
                }

                return true;
            }
            catch (Exception ex)
            {
                string errorMessage = String.Format("ProcessPaymentIPNMessage - Unable to create new TransactionDetail record for Merchant Transaction ID: {0}", merchantTransactionId);
                PayPalInStore.Utils.ErrorHandler.LogError(new Exception(errorMessage), "DEBUG");
                return false;
            }
        }

        /// <summary>
        /// Method used to process the Refund IPN notification message and update the database as required.
        /// </summary>
        /// <returns></returns>
        private bool ProcessRefundIPNMessage(string PayPalIPNMessage)
        {
            // Firstly, we need to split the IPN message into sections based on the & sign.
            string[] PayPalMessageElemetsArray = PayPalIPNMessage.Split('&');

            // Now obtain the list of information (from the message) we require to make the TransactionDetail record.
            string merchantTransactionId = Array.Find(PayPalMessageElemetsArray, element => element.StartsWith("txn_id=", StringComparison.Ordinal));
            string parentTransactionId = Array.Find(PayPalMessageElemetsArray, element => element.StartsWith("parent_txn_id=", StringComparison.Ordinal));
            string feeAmount = Array.Find(PayPalMessageElemetsArray, element => element.StartsWith("mc_fee=", StringComparison.Ordinal));
            string grossAmount = Array.Find(PayPalMessageElemetsArray, element => element.StartsWith("mc_gross=", StringComparison.Ordinal));

            try
            {
                // We now need to remove the variable name and '=' from the elements so we only have the necessary information.
                merchantTransactionId = merchantTransactionId.Replace("txn_id=", "");
                parentTransactionId = parentTransactionId.Replace("parent_txn_id=", "");
                feeAmount = feeAmount.Replace("mc_fee=", "").Replace("-", "");
                grossAmount = grossAmount.Replace("mc_gross=", "").Replace("-", "");

                // Now convert the values obtained from the IPN message and calculate the net amount.
                decimal dFeeAmount = Convert.ToDecimal(feeAmount);
                decimal dGrossAmount = Convert.ToDecimal(grossAmount);
                decimal dNetAmount = Math.Round((dGrossAmount - dFeeAmount), 2);

                // Now create the new transaction fee record.
                try
                {
                    // Finally create the new transaction fee record.
                    TransactionDetail transactionDetail = new TransactionDetail();
                    transactionDetail.MerchantTransactionId = merchantTransactionId;
                    transactionDetail.Gross = dGrossAmount;
                    transactionDetail.Fee = Decimal.Negate(dFeeAmount);
                    transactionDetail.Net = dNetAmount;
                    transactionDetail.TransactionType = (int)TransactionDetailTransactionType.InStoreRefund;
                    transactionDetail.Save();
                }
                catch (Exception ex)
                {
                    string errorMessage = String.Format("ProcessPaymentIPNMessage - Unable to create new TransactionDetail record for Merchant Transaction ID: {0}", merchantTransactionId);
                    PayPalInStore.Utils.ErrorHandler.LogError(new Exception(errorMessage), "DEBUG");
                    return false;
                }

                // Finally update the PurchaseRefund record with the Parent Transaction Id (used as a backup incase the API IPN message for the payment wasn't received).
                try
                {
                    PurchaseRefund refund = PurchaseRefund.SingleOrDefault(x => x.RefundTransactionId == merchantTransactionId);
                    if (refund != null)
                    {
                        refund.ParentTransactionId = parentTransactionId;
                        refund.Save();
                    }
                }
                catch (Exception ex)
                {
                    string errorMessage = String.Format("ProcessPaymentIPNMessage - Unable to update PurchaseRefund record (Transaction ID: {0}) with Parent Transaction Id: {1}", merchantTransactionId, parentTransactionId);
                    PayPalInStore.Utils.ErrorHandler.LogError(new Exception(errorMessage), "DEBUG");
                    return false;
                }

                // If all is succesful we can return true.
                return true;
            }
            catch (Exception ex)
            {
                string errorMessage = String.Format("ProcessPaymentIPNMessage - Unable to create new TransactionDetail record for Merchant Transaction ID: {0}", merchantTransactionId);
                PayPalInStore.Utils.ErrorHandler.LogError(new Exception(errorMessage), "DEBUG");
                return false;
            }
        }
    }
}
于 2012-04-27T13:47:18.423 に答える