2012-04-24 44 views
5

Tôi đang sử dụng hệ thống thanh toán thích ứng từ Paypal. Sử dụng tài khoản sandbox, tôi đã có thể thực hiện một PayRequest và được chuyển tiếp đến Paypal để thực hiện thanh toán. Đó là sau đó trông như:Làm thế nào để sử dụng các khoản thanh toán thích ứng Paypal với IPN?

Yêu cầu =

24 tháng 4 năm 2012 22:35:46 com.paypal.adaptive.api.requests.PayRequest thực hiện INFO: Gửi PayRequest với: requestEnvelope. errorLanguage = en_US & actionType = TRẢ & 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 &

đáp ứng =

Tháng Tư 24, 2012 22:35:48 com.paypal.adaptive.api.requests.PayPalBaseRequest makeRequest INFO: Nhận đáp ứng: responseEnvelope.timestamp = 2012-04-24T13% 3A35% 3A48.587-07% 3A00 & responseEnvelope. ack = Success & responseEnvelope.correlationId = c8dee8023cca6 & responseEnvelope.build = 2.756.816 & payKey = AP-1UF57245CJ360523K & paymentExecStatus = TẠO

tôi bây giờ cố gắng tìm ra, làm thế nào tôi có thể kiểm tra, t thanh toán của anh ấy đã được hoàn tất thành công. Vì vậy, tôi đã cố gắng triển khai hệ thống ipn, hoạt động bằng cách sử dụng các công cụ sandbox. Tuy nhiên, tôi không biết cách kết nối 2 với nhau. tức là khi thanh toán được thực hiện, tôi giả sử tôi cần tạo bản ghi trong cơ sở dữ liệu mà người dùng này đã thực hiện thanh toán, có thể là đang chờ xử lý/đã tạo? Sau đó, chờ IPN quay lại để thông báo cho tôi biết rằng thanh toán được thực hiện và cập nhật bảng cơ sở dữ liệu để hoàn thành? Làm cách nào tôi có thể liên hệ với PayRequest với Thông báo IPN, tôi sẽ nhận được từ paypal?Paypal chỉ gửi một vài thông tin với IPN-Notification như:

  • ITEM_NUMBER = AK-1234
  • residence_country = US
  • verify_sign = ArcmaOINNZx08uC3iQY0zhEQN3IZAz70ynRk93Or8ixRi23bb4rGNIrd
  • address_country = Hoa Kỳ
  • address_city = San Jose
  • address_status = unconfirmed
  • payment_status = Đã hoàn thành
  • [email protected]
  • payer_id = TESTBUYERID01
  • first_name = John
  • vận chuyển = 3,04
  • [email protected]
  • mc_fee = 0,44
  • txn_id = 484.221.854
  • số lượng = 1
  • [email protected]
  • notify_version = 2.1
  • txn_type = web_accept
  • test_ipn = 1
  • payer_status = xác
  • mc_currency = USD
  • mc_gross = 12,34
  • tùy chỉnh = xyz123
  • mc_gross_1 = 9,34
  • PAYMENT_DATE = 11: 54: 48 ngày 22 tháng 4 năm 2012 PDT
  • charset = windows-1252
  • address_country_code = US
  • address_zip = 95131
  • address_state = CA
  • thuế = 2,02
  • ITEM_NAME = cái gì đó
  • ADDRESS_NAME = John Smith
  • last_name = Smith
  • payment_type = tan
  • address_street = 123, bất kỳ đường phố
  • receiver_i d = TESTSELLERID1

Tôi không thể tìm thấy thứ gì đó có thể sử dụng trong IPN-Notifcation. Điều tốt nhất là nếu tôi có thể nhận được cùng một tương quan-id với Thông báo IPN mà tôi đã nhận được với phản hồi trả tiền. Vì vậy, tôi có thể lưu phản hồi-tương quan-id trên cơ sở dữ liệu của tôi và sau đó kiểm tra chống lại nó nếu tôi nhận được thông báo IPN với cùng một tương quan-id.

+0

Vì vậy, để làm rõ bạn muốn sử dụng phương thức Thanh toán thích ứng (PAY) để nhận thanh toán và sau đó là thông báo IPN để xác minh thành công? – swade1987

+0

Đúng và tôi muốn tương quan thanh toán cho người dùng đã thanh toán. – lazydaemon

Trả lời

2

Điều này sẽ giúp bạn ồ ạt.

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; 
      } 
     } 
    } 
} 
13

IPN kiểm tra mà họ cung cấp cho bạn trong hộp cát thật khủng khiếp.Nhìn vào một thực tế được kích hoạt để gọi lại thực tế của bạn (ngay cả một thử nghiệm), và bạn sẽ thấy nó có paykey được xác định; đây là những gì bạn sử dụng để tìm kiếm.

Lưu ý rằng chúng yêu cầu cổng 80 cho cuộc gọi lại IPN (mặc dù không được ghi lại ở bất kỳ đâu).

Dưới đây là một thông báo thực IPN (dịch sang JSON, thông tin cụ thể để ứng dụng của tôi redacted):

{"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"} 

Lưu ý rằng bạn phải thiết lập reverse_all_parallel_payments_on_error trong yêu cầu PAY bằng tay. Mặc dù họ khuyên bạn nên làm như vậy (và nó có thể sẽ giúp bạn tiết kiệm hơn) mặc định là sai.

Ngoài ra, bạn có thể sử dụng PaymentDetails để nhận tất cả thông tin tương tự trực tiếp nếu bạn bỏ lỡ IPN.

Tôi không biết những gì @ swade1987 đang xem xét, nhưng IPN của tôi không bao gồm bất kỳ thông tin nào về khoản phí. (Đó là thực sự như thế nào tôi tìm thấy bài này;.. Cố gắng tìm ra lý do tại sao Tài liệu PP API là khủng)

Tài liệu bổ sung có thể được tìm thấy ở đây https://developer.paypal.com/docs/classic/adaptive-payments/integration-guide/APIPN/

+8

giây là "horrid" –

+2

vui vì tôi đã tìm thấy bài đăng này. Tôi đã nhầm lẫn tại sao thông báo ipbox sandbox lại khác với một khoản thanh toán thực sự. rất vui vì tôi đã dành thời gian xây dựng các bảng và các tệp lớp để xử lý ipn kiểm tra khi thực tế không có gì giống như nó. cảm ơn paypal bạn cai trị! – sapatos

+1

Giống như OP, tôi đã bối rối với khái niệm rằng paykey không được chuyển lại cho kịch bản của tôi. Cảm ơn bạn đã chia sẻ điều này! –

3

Một hơi muộn nhưng đối với bất cứ ai đã đâm sầm vào đây từ một tìm kiếm động cơ ...

Tôi mới bắt đầu xử lý các API Paypal gần đây nhất. Thông báo IPN OP được trích dẫn là thông báo được gửi tại URL thông báo IPN được xác định trong hồ sơ người bán. Ngược lại, IPN được trích dẫn bởi @sai, là IPN thanh toán thích ứng, được phân phối tới ipnNotificationUrl được xác định trong các yêu cầu API trả tiền, ExecutePaypement hoặc Preapproval API.

Chúng là hai loại thông báo IPN khác nhau và là documented, hãy tìm Biến thông tin thanh toán và Biến thông báo trả tiền/phê duyệt trước. Bạn có thể nhận cả hai loại IPN nếu bạn chọn cả hai loại.

Liên quan đến thông báo IPN được OP trích dẫn, bạn có thể sử dụng giá trị của trường txn_id để nhận PaymentDetails theo transactionId. TransationId là tốt như payKey để tham khảo một khoản thanh toán hoàn thành.

Các vấn đề liên quan