本文对接银联商务公众号+服务窗支付,实现支付下单、订单查询、订单退款、退款查询和订单关闭几个功能,使用到银联商务的公众+服务窗支付接口规范,请自行百度下载。
在上两篇支付下单和下单查询中,已经实现公众号下单支付和下单查询功能的实现和接口的封装,本篇将介绍退款接口的对接实现,并将我使用到的银联商务的请求接口和响应接口进行封装,使用测试网页输出测试信息。
一、接口及代码实现
1.订单退款接口
1.1接口规范
接口规范请查看下载的银联商务公众号+服务窗接口规范退款接口接口部分,这里不做展示。
1.2 代码实现
1.2.1 UnifieRefundController代码
/**
* 退款接口
* @param request
* @param response
* @param merOrderId
* @param refundAmount
* @return
* @throws UnsupportedEncodingException
*/
@RequestMapping(value = "/OrderRefund", method = RequestMethod.POST)
public Map<String, Object> query(HttpServletRequest request, HttpServletResponse response, @RequestBody String jsonreq) throws UnsupportedEncodingException {
Map<String,Object> map = new HashMap<String,Object>(); //接收退款请求map
Map<String,Object> reqmap = new HashMap<String,Object>(); //客户端原始请求map
Map<String,Object> datamap = new HashMap<String,Object>(); //客户端原始请求Data数据
Map<String,Object> resultmap = new HashMap<String,Object>(); //返回结果
//接收客户端请求数据并转换成map
reqmap = JsonUtils.JsonToMapObj(jsonreq);
logger.info("unifiedquery reqmap = " + reqmap);
datamap = (Map<String, Object>) reqmap.get("tradeParam"); //tradeParam请求体数据
logger.info("unifiedquery datamap = " + datamap);
//-------------------------step1 验证签名-----------------------------
String sign = (String) reqmap.get("sign"); //获取sign
String key = UnionPayConstants.GGMD5KEY; //国光MD5密钥
try {
if (!PayUtil.verifySign(datamap,key,sign)) {
resultmap.put("returnCode", "Bad_Sign");
resultmap.put("returnInfo", "签名错误");
return resultmap;
}
//-----------------------step2 验证消息类型 tradeType:refund-------------------
if (!"refund".equals(reqmap.get("tradeType"))) {
resultmap.put("returnCode", "TradeType_Error");
resultmap.put("returnInfo", "消息类型不符");
return resultmap;
}
//------------------------step3 验证传参完整性----------------------------------
//验证公共参数完整性
if(!PayUtil.verifyParameter(datamap)) {
resultmap.put("returnCode", "Common_Value_Error");
resultmap.put("returnInfo", "缺少必要公共参数");
return resultmap;
}
//验证接口参数完整性
if(datamap.get("merOrderId").equals("") || datamap.get("refundAmount").equals("")) {
resultmap.put("returnCode", "Value_Error");
resultmap.put("returnInfo", "缺少必要接口参数");
return resultmap;
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
resultmap.put("returnCode", "System_Error");
resultmap.put("returnInfo", "系统异常");
return resultmap;
}
//------------------------step4 传值并调用退款接口--------------------------------
map.put("mid", datamap.get("mid")); //商户号
map.put("tid", datamap.get("tid")); //终端号
map.put("instMid", datamap.get("instMid")); //机构商户号
map.put("msgSrc", datamap.get("msgSrc")); //消息来源
map.put("merOrderId", datamap.get("merOrderId")); //原支付订单号
map.put("refundAmount", datamap.get("refundAmount")); //退款金额
Map<String, Object> refundmap = refundserviceimpl.Refund(map);
logger.info("refundmap = " + refundmap);
if(!"200".equals(refundmap.get("statuscode"))) {
resultmap.put("returnCode", "Union_Connect_Error");
resultmap.put("returnInfo", "银联网付连接失败");
return resultmap;
}
//------------------------step5接口返回数据----------------------------------
Map<String,Object> resultdatamap = new HashMap<String,Object>(); //resultmap中data数据
resultdatamap.put("errCode", refundmap.get("errCode")); //平台错误码
resultdatamap.put("status", refundmap.get("status")); //交易状态
resultdatamap.put("totalAmount", refundmap.get("totalAmount")); //退款金额
resultdatamap.put("targetSys", refundmap.get("targetSys")); //目标平台代码(第三方代码)
resultdatamap.put("targetStatus", refundmap.get("targetStatus")); //目标平台状态
resultdatamap.put("refundStatus", refundmap.get("refundStatus")); //支付时间
resultdatamap.put("refundOrderId", refundmap.get("refundOrderId")); //平台退款订单号
resultdatamap.put("refundTargetOrderId", refundmap.get("refundTargetOrderId")); //第三方退款订单号
resultdatamap.put("messageType", refundmap.get("msgType")); //消息类型
resultmap.put("data", resultdatamap);
resultmap.put("returnCode", refundmap.get("errCode"));
//resultmap.put("returnInfo", refundmap.get("errMsg"));
return resultmap;
}
1.2.2 refundserviceimpl代码
本部分代码为银联商务公众号退款接口服务实现类。
public Map<String, Object> Refund(Map<String, Object> map) throws UnsupportedEncodingException {
// TODO Auto-generated method stub
logger.info("------------------refund--------------------------");
Map<String, Object> reqmap = new HashMap<String, Object>(); //请求map
Map<String, Object> resp = new HashMap<String, Object>(); //响应resp
reqmap.put("mid", map.get("mid").toString()); //商户号,前端传入
reqmap.put("tid", map.get("tid").toString()); //终端号
reqmap.put("instMid",map.get("instMid").toString()); //业务类型
reqmap.put("msgSrc", map.get("msgSrc").toString()); //消息来源
reqmap.put("msgId", "UnionPay_F003");
reqmap.put("msgType", "refund"); //消息类型
//报文请求时间
String aligetTime = PayUtil.aligetTime();
logger.info("请求时间aligetTime = " + aligetTime);
reqmap.put("requestTimestamp", aligetTime);
reqmap.put("merOrderId", map.get("merOrderId").toString()); //原商户交易订单号,前端传入
reqmap.put("refundAmount", map.get("refundAmount").toString()); //退款金额,前端传入
//下单时未上送分账标识,上传分账标识,需进一步讨论退款金额
reqmap.put("refundDesc", "订单退款"); //退款说明
//生成退款订单号
String refundorderid = GGitUtil.createOrderID();
StringBuffer buff = new StringBuffer();
buff.append(this.msgSrcId); //来源编号3194
buff.append(refundorderid);
reqmap.put("refundOrderId", buff.toString());
//生成待签名字符串并进行MD5加密
String builderSignStr = "";
try {
builderSignStr = PayUtil.builderSignStr(reqmap,UnionPayConstants.MD5KEY);
//signString = PayUtil.generateSignature(reqmap, UnionPayConstants.MD5KEY);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
reqmap.put("sign", builderSignStr);
logger.info("reqmap= " + reqmap);
String jsonstring = GGitUtil.MapToJson2(reqmap); //请求map转成json string
logger.info("发送refund post请求消息:" + jsonstring);
//接收银联商务返回退款map
resp = unionpayrequest.dopost(UnionPayConstants.queryURL, jsonstring);
return resp;
}
1.3测试结果
本文对所写接口写了测试网页进行测试,如图所示。封装的银联商务响应接口中,返回商户退款订单号,第三方退款订单号,消息类型、退款状态等,其中退款状态status为TRADE_SUCCESS,表示退款操作成功,此时查看微信支付记录中,可以看到退款到账信息。