AllPay,http://www.allpay.com.tw/,歐付寶是臺灣知名的第三方支付公司,擁有豐富的支付模式(支援和支付寶、財付通),只需要一次對接,各種支付模式均可使用。
介面編寫SDK:http://www.allpay.com.tw/Service/API_Help?Anchor=AnchorDoc
官方提供了比較完整的SDK,裡面有豐富的程式碼,這裡只講需要注意的地方:
1.歐付寶提供若干支付模式,可以再介面中指定(不給使用者選擇的機會);也可以在介面中設定ALL,等到付款的時候讓使用者選擇
2.確定支付模式後,便可以生成訂單,然後等待支付
3.支付結果的確認是Server靜默方式通知的,非URL跳轉的方式,這點類似PayPal的Classic模式
4.提供沙箱模式http://vendor-stage.allpay.com.tw,使用者名稱StageTest,密碼Test1234,在沙箱中可以任意下訂單,模擬支付等等
5.正式模式的後臺http://vendor.allpay.com.tw同樣支援模擬付款的方式
6.支付結果接收service,注意需要驗證來源,也就是CheckMacValue,驗證方法後面給出
7.如果介面中不指定支付模式,oPayment.Send.ChoosePayment = PaymentMethod.ALL; 即使客戶不選擇支付寶支付,那麼也需要將支付寶的支付選項填入
oPayment.SendExtend.PhoneNo = ""; oPayment.SendExtend.Email = ""; oPayment.SendExtend.UserName = "";
因為這三項是必填欄位,注意是SendExtend。
8.ReturnURL 為Server 端的回應,歐付寶Server會直接將付款結果送到您指定的ReturnURL
OrderResultURL 則為 Client 端的回應,我們會將使用者的畫面轉導到您指定的OrderResultURL
ClientBackURL 主要的功能,是在交易完成的頁面中,若廠商端有設定網址,則在該頁面上會出現「返回商店」的按鈕,當消費者點選後,會導到所設定的網址。
9.MerchantTradeNo測試的時候如果兩筆都是一樣的,會導致第二次建立訂單失敗,這個要注意,每次最好用隨機數
下面是支付介面,傳入訂單編號,通過呼叫AllPay介面,會預設跳轉到AllPay去支付
public ActionResult PaymentByAllPay(Guid BillCode) { List<string> enErrors = new List<string>(); string szHtml = String.Empty; try { using (AllInOne oPayment = new AllInOne()) { /* 服務引數 */ oPayment.ServiceMethod = AllPay.Payment.Integration.HttpMethod.HttpPOST; //oPayment.ServiceURL = "http://payment-stage.allpay.com.tw/Cashier/AioCheckOut"; oPayment.ServiceURL = "https://payment.allpay.com.tw/Cashier/AioCheckOut"; oPayment.HashKey = System.Configuration.ConfigurationManager.AppSettings["APHashKey"]; oPayment.HashIV = System.Configuration.ConfigurationManager.AppSettings["APHashIV"]; oPayment.MerchantID = System.Configuration.ConfigurationManager.AppSettings["MerchantID"]; IList<COM_Bill> list = WMSFactory.COM_Bill.FindByCondition(""); if (list == null || list.Count() != 1) { throw new Exception("Error:BillCode Is Wrong!"); } COM_Bill bill = list.First(); IList<COM_BillSub> billSub = WMSFactory.COM_BillSub.FindByCondition("BillCode='" + BillCode.ToString() + "'"); /* 基本引數 */ string baseURI = Request.Url.Scheme + "://" + Request.Url.Authority + "/Order/"; //以後臺服務通知的形式傳送到該URL oPayment.Send.ReturnURL = baseURI + "AllPayResult/"+BillCode.ToString().Replace("-","_");//完成付款,注意這裡有嚴格的url限制,不能傳遞- oPayment.Send.ClientBackURL = baseURI; oPayment.Send.MerchantTradeNo = bill.Id.ToString()+DateTime.Parse(bill.CreateTime).ToString("yyyyMMddHHmmss") + new Random().Next(0, 9999).ToString(); oPayment.Send.MerchantTradeDate = DateTime.Now; oPayment.Send.TotalAmount = (int)(bill.TotalAmount + bill.ShippingFee - bill.VoucherMoney); oPayment.Send.TradeDesc = "物流費:" + bill.ShippingFee.ToString(); oPayment.Send.ChoosePayment = PaymentMethod.ALL; oPayment.Send.ChooseSubPayment = PaymentMethodItem.None; oPayment.Send.NeedExtraPaidInfo = ExtraPaymentInfo.No; oPayment.Send.DeviceSource = DeviceType.PC; //例(排除支付寶與財富通): Alipay#Tenpay oPayment.Send.IgnorePayment = ""; // 加入選購商品資料。 foreach (COM_BillSub sb in billSub) { AllPay.Payment.Integration.Item item = new AllPay.Payment.Integration.Item(); item.Name = sb.SkcName + ":" + sb.Skc.ToString() + "," + sb.ColorName + "," + sb.SizeName; item.Currency = "新臺幣"; item.Price = sb.Price; item.Quantity = sb.Num; item.URL = ""; oPayment.Send.Items.Add(item); //oPayment.SendExtend.AlipayItemCounts += sb.Num.ToString() + "#"; //oPayment.SendExtend.AlipayItemName += sb.SkcName + "#"; //oPayment.SendExtend.AlipayItemPrice += sb.Price.ToString() + "#"; }//物流費用 AllPay.Payment.Integration.Item shippingfeeitm = new AllPay.Payment.Integration.Item(); shippingfeeitm.Name = "Shipping"; shippingfeeitm.Currency = "新臺幣"; shippingfeeitm.Price = bill.ShippingFee; shippingfeeitm.Quantity = 1; oPayment.Send.Items.Add(shippingfeeitm); //oPayment.SendExtend.AlipayItemCounts += "1"; //oPayment.SendExtend.AlipayItemName += "Shipping"; //oPayment.SendExtend.AlipayItemPrice += bill.ShippingFee.ToString(); //獲取物流資訊 COM_Address address = WMSFactory.COM_Address.FindById(bill.ShippingId.ToString()); oPayment.SendExtend.PhoneNo = address.TelPhone; oPayment.SendExtend.Email = member.Email; oPayment.SendExtend.UserName = address.LastName + address.FirstName; /* 產生訂單 */ enErrors.AddRange(oPayment.CheckOut()); /* 產生產生訂單 Html Code 的方法 */ enErrors.AddRange(oPayment.CheckOutString(ref szHtml)); Session.Add(BillCode.ToString(), oPayment.Send.MerchantTradeNo); } } catch (Exception ex) { // 例外錯誤處理。 enErrors.Add(ex.Message); } finally { if (enErrors.Count() > 0) throw new Exception(String.Join("<br />", enErrors)); } //扣庫存 DataTable dt = WMSFactory.COM_BillSub.UpdateStore(BillCode, 2); if (dt != null && dt.Rows.Count > 0 && dt.Rows[0][0].ToString() != "0") { return RedirectToAction("PayResult", new { id = 3, msg = dt.Rows[0][0].ToString() }); } ViewBag.AllPayRedirect = szHtml; return View(); }
支付確認介面實現:
public void AllPayResult(string id) { List<string> enErrors = new List<string>(); Hashtable htFeedback = null; id = id.Replace("_", "-"); log.Debug("進入allpayresult,id=" + id); try { string szHashKey = System.Configuration.ConfigurationManager.AppSettings["APHashKey"]; string szHashIV = System.Configuration.ConfigurationManager.AppSettings["APHashIV"]; // 取回所有資料 if (enErrors.Count() == 0) { /* 支付後的回傳的基本引數 */ string szMerchantID = Request.Form["MerchantID"]; string szMerchantTradeNo = Request.Form["MerchantTradeNo"]; string szPaymentDate =Request.Form["PaymentDate"]; string szPaymentType = Request.Form["PaymentType"]; string szPaymentTypeChargeFee = Request.Form["PaymentTypeChargeFee"]; string szRtnCode = Request.Form["RtnCode"]; string szRtnMsg = Request.Form["RtnMsg"]; string szSimulatePaid = Request.Form["SimulatePaid"]; string szTradeAmt =Request.Form["TradeAmt"]; string szTradeDate =Request.Form["TradeDate"]; string szTradeNo = Request.Form["TradeNo"]; string szCheckMacValue = Request.Form["CheckMacValue"]; //一般回傳引數CMV(若需要其他檢查請自行增加) Dictionary<string, string> Parameters = new Dictionary<string, string>(); Parameters.Add("MerchantID", szMerchantID); Parameters.Add("MerchantTradeNo", szMerchantTradeNo); Parameters.Add("RtnCode", szRtnCode); Parameters.Add("RtnMsg", szRtnMsg); Parameters.Add("TradeNo", szTradeNo); Parameters.Add("TradeAmt", szTradeAmt); Parameters.Add("PaymentDate", szPaymentDate); Parameters.Add("PaymentType", szPaymentType); Parameters.Add("PaymentTypeChargeFee", szPaymentTypeChargeFee); Parameters.Add("TradeDate", szTradeDate); Parameters.Add("SimulatePaid", szSimulatePaid); string ParameterString = string.Join("&", Parameters.OrderBy(d => d.Key).Select(p => p.Key + "=" + p.Value)); string str = "HashKey=" + szHashKey + "&" + ParameterString + "&HashIV=" + szHashIV; log.Debug("接收到AllPay返回值=" + str); string urlEncodeStrPost = HttpUtility.UrlEncode(str); //url大寫轉小寫 string lowerUrlEncodeStrPost = urlEncodeStrPost.ToLower(); //檢查碼要使用MD5加密 MD5 md5Hasher = MD5.Create(); byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(lowerUrlEncodeStrPost)); StringBuilder sBuilder = new StringBuilder(); for (int i = 0; i < data.Length; i++) { sBuilder.Append(data[i].ToString("X2")); } string sCheckMacValue = sBuilder.ToString(); log.Debug("mine:" + sCheckMacValue + ";param:" + szCheckMacValue); if (szRtnCode == "1" && szSimulatePaid == "0" && sCheckMacValue == szCheckMacValue) { //更新訂單狀態 } } } catch (Exception ex) { // 例外錯誤處理。 enErrors.Add(ex.Message); } finally { this.Response.Clear(); // 回覆成功訊息。 if (enErrors.Count() == 0) this.Response.Write("1|OK"); // 回覆錯誤訊息。 else this.Response.Write(String.Format("0|{0}", String.Join("\\r\\n", enErrors))); this.Response.Flush(); this.Response.End(); } }