最近在对接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