公司首個外包項目的退換貨流程的退款操作是走原路返回的寂纪,而我有幸負(fù)責(zé)這個功能模塊開發(fā)湃番,在實踐中總結(jié)了一些經(jīng)驗夭织,特此分享出來。
一牵辣、支付寶退款摔癣。
支付寶提供了有密以及普通退款接口奴饮,兩者的區(qū)別就是前者不需要申請即時到賬支付而后者需要纬向,本文使用了有密退款接口;支付寶四要素:PID(合作者id)戴卜,private_key(私鑰逾条,我使用的是RSA加密方式生成的)、alipay_public_key(公鑰投剥,支付寶提供的)以及支付賬號师脂。
1.1先看配置文件:
// 合作身份者ID,簽約賬號江锨,以2088開頭由16位純數(shù)字組成的字符串
public static String partner = "";
// 收款支付寶賬號吃警,以2088開頭由16位純數(shù)字組成的字符串,一般情況下收款賬號就是簽約賬號public static String seller_user_id = partner;
// 商戶的私鑰,需要PKCS8格式啄育,RSA公私鑰生成
public static String private_key = "";
// 支付寶公鑰
public static String alipay_public_key = "";
// 服務(wù)器異步通知頁面路徑 需http://格式的完整路徑酌心,不能加?id=123這類自定義參數(shù),必須外網(wǎng)可以正常訪問
public static String notify_url = "http://xxx.xxxx.com/api/refund/refundBack_001";
1.2關(guān)鍵代碼:
/** * 退款操作(請求) * @param response * @return * @throws Exception * trade_no 支付寶返回的交易號 * money 退款金額 */
public String aliRefund(HttpServletRequest request, HttpServletResponse response, String trade_no, String money,String refundId,String batch_no) throws Exception {PrintWriter out = ControllerUtils.getPrintWriter(response, logger, "------------AlipayRefundActionMultiController.aliRefund start------------");
//服務(wù)器異步通知頁面路徑
String notify_url;
String sHtmlText = "";
try {MapsParaTemp = new HashMap();
//退款詳細(xì)數(shù)據(jù)挑豌,必填安券,格式(支付寶交易號^退款金額^備注),多筆請用#隔開
String detail_data = trade_no + "^" + money + "^退款";
sParaTemp.put("detail_data", detail_data);//退款詳情
sParaTemp.put("service", AlipayConfig.service);//
sParaTemp.put("partner", AlipayConfig.partner);//合作者id
sParaTemp.put("_input_charset", AlipayConfig.input_charset);//字符集格式
sParaTemp.put("notify_url", AlipayConfig.notify_url);//回調(diào)地址
sParaTemp.put("seller_email", "商家賬號");//賬號
sParaTemp.put("refund_date", UtilDate.getDateFormatter());//退款時間
sParaTemp.put("batch_no", batch_no);//批次號氓英,必填侯勉,格式:當(dāng)天日期[8位]+序列號[3至24位],如:201603081000001
sParaTemp.put("batch_num", "1"); //退款筆數(shù)铝阐,必填址貌,參數(shù)detail_data的值中,“#”字符出現(xiàn)的數(shù)量加1徘键,最大支持1000筆(即“#”字符出現(xiàn)的數(shù)量999個)
sHtmlText = AlipaySubmit.buildRequest(sParaTemp, "get", "確認(rèn)");
} catch (Exception e) {
e.printStackTrace();
}
return sHtmlText;
}```
***注意:***此處的交易號必須是你支付時保存的交易號练对,以及退款金額不能大于實付金額且不能<=0隘擎,否則無法調(diào)起支付二鳄。我是將退款信息用一個form表單封裝起來然后以流的方式輸出,前端頁面只需要拿到該信息然后填充到一個div中垄琐。
**1.3表單封裝:**
/** * 建立請求赠制,以表單HTML形式構(gòu)造(默認(rèn)) * @param sParaTemp 請求參數(shù)數(shù)組 * @param strMethod 提交方式赂摆。兩個值可選:post挟憔、get * @param strButtonName 確認(rèn)按鈕顯示文字 * @return 提交表單HTML文本 */
public static String buildRequest(Map < String, String > sParaTemp, String strMethod, String strButtonName){ //待請求參數(shù)數(shù)組
Map < String, String > sPara = buildRequestPara(sParaTemp);
List < String > keys = new ArrayList < String > (sPara.keySet());
StringBuffer sbHtml = new StringBuffer();
sbHtml.append("");
for (int i = 0; i < keys.size(); i++) {
String name = (String)keys.get(i);
String value = (String)sPara.get(name);
sbHtml.append("");
}
//submit按鈕控件請不要含有name屬性
sbHtml.append("");
sbHtml.append("document.forms['alipaysubmit'].submit();");
return sbHtml.toString();}
**1.4前端頁面拿到信息后進(jìn)行填充:**
![div.png](http://upload-images.jianshu.io/upload_images/2536237-738fbd47bcc6454a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](http://upload-images.jianshu.io/upload_images/2536237-26d747c282f25dfc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
**1.5效果展示:**
****
[圖片上傳中。烟号。绊谭。(4)]
![](http://upload-images.jianshu.io/upload_images/2536237-1cb4826902fb8fb6.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
***二、微信退款汪拥。***
***2.1配置文件***
******
![](http://upload-images.jianshu.io/upload_images/2536237-efcd58ddf33ad42b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
**2.2退款前提條件:**
商戶必須開通微信支付功能达传,開發(fā)人員要拿到賬號以及**證書**(重點),退款金額不能大于實付價迫筑、小于等于0宪赶,并且傳入的實際支付價必須跟微信那邊保持一致,否則無法完成退款操作脯燃。
2.2關(guān)鍵代碼:
private String doRefundByWX(String money, String bankSerialNumber, long numberCount, String no,String sumAmout) throws UnrecoverableKeyException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, IOException{
String result="";
String appid=WeiXinUtil.appid;//應(yīng)用ID
String mch_id=WeiXinUtil.mch_id;//商戶號
String nonce_str=WeiXinUtil.CreateNoncestr();//隨機(jī)字符串
String transaction_id=bankSerialNumber;//微信訂單號
String out_refund_no=no;//商戶退款單號
Double total_fee=0d;
try {
total_fee = StringUtil.getDouble(sumAmout);
} catch (NumberFormatException e)
{e.printStackTrace();}
catch (Exception e) {
e.printStackTrace();
}
long totalAmount = new BigDecimal(total_fee * 100d).longValue();//總金額以分為單位Double refund_fee=Double.parseDouble(money);
long Amount = new BigDecimal(refund_fee * 100d).longValue();//退款金額以分為單位
String op_user_id=WeiXinUtil.mch_id;//操作員帳號, 默認(rèn)為商戶號 /簽名算法SortedMapSortedMap = new TreeMap();
SortedMap.put("appid", appid);
SortedMap.put("mch_id",mch_id);
SortedMap.put("nonce_str",nonce_str);
SortedMap.put("transaction_id", transaction_id);
SortedMap.put("out_refund_no", out_refund_no);
SortedMap.put("total_fee",String.valueOf(totalAmount));
SortedMap.put("refund_fee", String.valueOf(Amount));
SortedMap.put("op_user_id", op_user_id);
String sign=WeiXinUtil.createSign("UTF-8",SortedMap);
//獲取最終待發(fā)送的數(shù)據(jù)
String requestXml=WeiXinUtil.getRequestXml(SortedMap);
//(2)建立連接并發(fā)送數(shù)據(jù)
result=WeixinSendPost(requestXml);
return result;
}```
2.3退款操作:
先申明一點:微信退款沒有提供跳轉(zhuǎn)頁面搂妻,也就是一點擊退款,只要信息正確就會自動打錢到退款賬戶辕棚。
三欲主、關(guān)于保存微信支付、支付寶交易號作為退款字段的代碼圖(訂單支付的回調(diào)方法):
備注:由于時間問題就不上全部代碼逝嚎,如若要具體代碼請關(guān)注我扁瓢,如果響應(yīng)激烈我將會將代碼放到GitHub。