最近在對接PayPal,告一段落,總結一下。
說一下PayPal Express Checkout的支付流程。
現在去https://www.sandbox.paypal.com/home,注冊兩個賬號,一個是個人賬號,一個是商家賬號。用來付款測試。商家賬號需要獲取API許可,如下圖:
這里用ExpressCheckout對接,先添加WCF地址:https://www.paypal.com/wsdl/PayPalSvc.wsdl,這里要添加Web引用,不要添加服務引用。
一切准備就緒,現在來一步一步的完成這個流程。
先看SetExpressCheckout,這是創建支付的方法。
public static SetExpressCheckoutResponseType SetExpressCheckout() { //配置服務信息 //API憑證 string APIAccountName = "*********_api1.qq.com"; string APIAccountPassword = "**********"; string Signature = "**********************************************"; //API憑證 CustomSecurityHeaderType header = new CustomSecurityHeaderType { Credentials = new UserIdPasswordType { Username = APIAccountName, Password = APIAccountPassword, Signature = Signature } }; PayPalAPIAASoapBinding service = new PayPalAPIAASoapBinding(); service.Url = "https://api-3t.sandbox.paypal.com/nvp"; //這里是測試地址 service.RequesterCredentials = header; //配置服務信息 //配置請求信息 SetExpressCheckoutReq req = new SetExpressCheckoutReq(); //商品詳情 var cartItems = new List<PaymentDetailsItemType>(); cartItems.Add(new PaymentDetailsItemType { Name ="ProductName", Quantity = "3", Amount = new BasicAmountType { currencyID = CurrencyCodeType.USD, Value ="2" }, Description = "ProductName" }); cartItems.Add(new PaymentDetailsItemType { Name = "ProductName2", Quantity = "4", Amount = new BasicAmountType { currencyID = CurrencyCodeType.USD, Value = "4" }, Description = "ProductName2" }); cartItems.Add(new PaymentDetailsItemType { Name = "Discount", Quantity = "1", Amount = new BasicAmountType { currencyID = CurrencyCodeType.USD, Value = "-12" }, Description = "Discount" }); //商品詳情 req.SetExpressCheckoutRequest = new SetExpressCheckoutRequestType { Version = "98.0", //版本 SetExpressCheckoutRequestDetails = new SetExpressCheckoutRequestDetailsType { PaymentAction = PaymentActionCodeType.Sale, ReturnURL = "http://www.hao123.com/", //返回url CancelURL = "http://www.hao123.com/", //取消url //付款詳情 PaymentDetails=new PaymentDetailsType[]{ new PaymentDetailsType{ ItemTotal = new BasicAmountType { currencyID = CurrencyCodeType.USD, Value ="10" }, ShippingTotal = new BasicAmountType { currencyID = CurrencyCodeType.USD, Value = "5" }, TaxTotal = new BasicAmountType { currencyID = CurrencyCodeType.USD, Value = "2" }, OrderTotal = new BasicAmountType { currencyID = CurrencyCodeType.USD, Value = "17" }, PaymentDetailsItem = cartItems.ToArray() } } } }; //配置請求信息 SetExpressCheckoutResponseType response = service.SetExpressCheckout(req); return response; }
這里有幾個地方要說一下:
第一:折扣信息是和商品寫在一起的。
第二:價格這里,ItemTotal=商品價格+折扣價格,OrderTotal=ItemTotal+ShippingTotal+TaxTotal。這兩個價格不能出錯。
第三:這里還可以把自己的地址加進去,在detail下將AddressOverride設置成1,然后就可以在Address中添加自己想要傳給PayPal的信息了。這里要注意的是,地址信息不能亂寫,PayPal會驗證下。這里還有個問題就是我的Name和Phone怎么也傳不回
來,希望可以有人幫我解決一下,謝謝。
第四:這里的ReturnUrl和CancelUrl,只用Url.Action()不行,會報錯,要全地址,帶http的,這里提供兩中方法。
1. string baseUrl = Request.Url.Scheme + "://" + Request.Url.Authority;
string ReturnUrl=baseUrl+Url.Action("ReturnUrl");
2. Url.Action("ReturnUrl", "Test", null, "http")
AddressOverride = "1", Address = new AddressType { }
獲取到response后,就可以取其中的Token來跳轉到PayPal去了,找不到Token的看問題一。這里還是測試地址:"https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=" + response.Token。
輸入賬號信息,支付,調回網站,調用GetExpressCheckout方法。
public static GetExpressCheckoutDetailsResponseType GetExpressCheckout(string token) { GetExpressCheckoutDetailsReq req = new GetExpressCheckoutDetailsReq(); req.GetExpressCheckoutDetailsRequest = new GetExpressCheckoutDetailsRequestType { Token = token, Version = APIVersion }; GetExpressCheckoutDetailsResponseType response = service.GetExpressCheckoutDetails(req); return response; }
這里將Service和APIVersion移出去,方便每一個方法調用。
public static PayPalAPIAASoapBinding service { get { return new PayPalAPIAASoapBinding { Url = "https://api-3t.sandbox.paypal.com/nvp", RequesterCredentials = new CustomSecurityHeaderType { Credentials = new UserIdPasswordType { Username = "**********_api1.qq.com", Password = "*********", Signature = "************************" } } }; } } public static string APIVersion { get { return "98.0"; } }
最后將GetExpressCheckout的返回值作為DoExpressCheckout的參數,用來獲取付款。
public static DoExpressCheckoutPaymentResponseType DoExpressCheckout(GetExpressCheckoutDetailsResponseType responseGet) { PayerInfoType paymentInfo = responseGet.GetExpressCheckoutDetailsResponseDetails.PayerInfo; DoExpressCheckoutPaymentReq req = new DoExpressCheckoutPaymentReq(); req.DoExpressCheckoutPaymentRequest = new DoExpressCheckoutPaymentRequestType { Version = APIVersion, DoExpressCheckoutPaymentRequestDetails = new DoExpressCheckoutPaymentRequestDetailsType { PaymentAction = PaymentActionCodeType.Sale, PaymentActionSpecified = true, Token = responseGet.GetExpressCheckoutDetailsResponseDetails.Token, PayerID = paymentInfo.PayerID, PaymentDetails = new PaymentDetailsType[] { new PaymentDetailsType{ OrderTotal = new BasicAmountType{ Value = responseGet.GetExpressCheckoutDetailsResponseDetails.PaymentDetails[0].OrderTotal.Value, currencyID = CurrencyCodeType.USD }, Custom = "123", ButtonSource = "nopCommerceCart" } } } }; DoExpressCheckoutPaymentResponseType response = service.DoExpressCheckoutPayment(req); return response; }
這樣,付款就完成了,這是一個大概的流程,中間還有一些判斷錯誤,返回錯誤到頁面的代碼,沒有寫,自己加。
退款
這里需要新添加一個服務對象,參數社么的都與service一樣,類型不同:PayPalAPISoapBinding service2
public static RefundTransactionResponseType RefundOrder(string transactionID) { RefundTransactionReq req = new RefundTransactionReq(); req.RefundTransactionRequest = new RefundTransactionRequestType { RefundType = RefundType.Partial, //退款類型,是部分退款 還是 全額退款 //退款金額,全額退款的話不需要這個參數 Amount = new BasicAmountType{ currencyID = CurrencyCodeType.USD, Value = "100" }, RefundTypeSpecified = true, Version = APIVersion, //付款單的 transactionID TransactionID = transactionID }; RefundTransactionResponseType response = service2.RefundTransaction(req); return response; }
信用卡付款
這里不是很清楚,大概說一下,有待改進。信用卡付款這里,不需要跳轉到PayPal支付頁面去登錄,在本站就可以進行付款。這里用的是PayPal Direct Payment API。
public static DoDirectPaymentResponseType DirectPayment() { DoDirectPaymentRequestDetailsType details = new DoDirectPaymentRequestDetailsType { //IPAddress 這里填什么?? IPAddress = "127.0.0.1", //信用卡信息 CreditCard = new CreditCardDetailsType { CreditCardNumber = "****96548042****", CreditCardType = CreditCardTypeType.Visa, ExpMonthSpecified = true, ExpMonth = 2, ExpYearSpecified = true, ExpYear = 2018, CVV2 = "234", CreditCardTypeSpecified = true, CardOwner = new PayerInfoType { PayerCountry = CountryCodeType.US, Address = new AddressType { CountrySpecified = true, Street1 = "Street1", Street2 = "Street2", CityName = "City", StateOrProvince = "CA", Country = CountryCodeType.US, PostalCode = "Zip" }, Payer = "", PayerName = new PersonNameType { FirstName = "FirstName", LastName = "LastName" } } }, //支付 詳情 PaymentDetails = new PaymentDetailsType { OrderTotal = new BasicAmountType { Value = "100", currencyID = CurrencyCodeType.USD }, Custom = "123", ButtonSource = "nopCommerceCart", ShipToAddress = new AddressType { Name = "Name", Street1 = "Street1", CityName = "City", StateOrProvince = "State", PostalCode = "Zip", Country = CountryCodeType.US, CountrySpecified = true } }, PaymentAction=PaymentActionCodeType.Sale }; DoDirectPaymentReq req = new DoDirectPaymentReq(); req.DoDirectPaymentRequest = new DoDirectPaymentRequestType { Version = APIVersion, DoDirectPaymentRequestDetails = details }; DoDirectPaymentResponseType response = service.DoDirectPayment(req); return response; }
問題一:
SetExpressCheckout下執行后的SetExpressCheckoutResponseType response,response.Token沒有值。
Answer:找到wcf引用中的下面代碼:
[System.Xml.Serialization.XmlElementAttribute(Order=6)]
public System.Xml.XmlElement Any {
get {
return this.anyField;
}
set {
this.anyField = value;
this.RaisePropertyChanged("Any");
}
}
將[System.Xml.Serialization.XmlElementAttribute(Order=6)]替換成[System.Xml.Serialization.XmlIgnoreAttribute()]
API開發網址:http://www.paypalobjects.com/en_US/ebook/PP_APIReference/dcc.html