上篇文章谈了谈工银聚富通H5支付,有支付就得有退款,这是一个完整的流程,下面来说下聚富通的退款,在项目中的流程是,用户在小程序里点击申请退款,有门店App那边来审核,门店App审核通过后会向工行发送退款请求,如果工行那边受理成功的话,这个退款流程就成功了,工行那边会在T+日退款到用户的账户.如果发送退款请求受理失败,会将退款失败原因返回的.
聚富通服务商申请退款接口文档
public class QueryByOederNo {
public static void main(String[] args) {
String APIGW_PUBLIC_KEY = "工行API网关公钥,请向工行联系获取";
String encryptKey ="应用方加密串";
String APP_ID = "APP的编号";
String MY_PRIVATE_KEY ="应用方私钥";
//构建client
DefaultIcbcClient client = new DefaultIcbcClient(APP_ID, IcbcConstants.SIGN_TYPE_RSA2,
MY_PRIVATE_KEY, IcbcConstants.CHARSET_UTF8, IcbcConstants.FORMAT_JSON, APIGW_PUBLIC_KEY,
IcbcConstants.ENCRYPT_TYPE_AES, encryptKey, "", "");
//构建查询请求对象
RefundAcceptRequestV1 request = new RefundAcceptRequestV1();
request.setServiceUrl("https://gw.open.icbc.com.cn/api/jft/api/pay/refund/accept/V1");
RefundAcceptRequestV1.RefundAcceptRequestV1Biz bizContent = new RefundAcceptRequestV1.RefundAcceptRequestV1Biz();
bizContent.setAppId(APP_ID);
bizContent.setVendorId("子商户标识");
bizContent.setUserId("用户表示");
//订单类型
bizContent.setPayType("01");
//原平台订单号
bizContent.setOrderId("2022080200011659431884606");
//平台退款单id
bizContent.setRefundId("20220802171803135");
//退款金额
bizContent.setRefundAmount("1");
//退款通知url
bizContent.setNotifyUrl("www.xx.com");
request.setBizContent(bizContent);
RefundAcceptResponseV1 responseInfo = null;
try {
//判断该商户是否注册成功
responseInfo = client.execute(request, System.currentTimeMillis() + "");
System.out.println(JSONObject.toJSONString(responseInfo));
// 注册失败
System.out.println(responseInfo.getSubRefunds().toString());
System.out.println(responseInfo.isSuccess());
if (responseInfo.isSuccess()){
//6、业务成功处理,请根据接口文档用response.getxxx()获取同步返回的业务数据
System.out.println("ReturnCode:"+responseInfo.getReturnCode());
System.out.println("response:" + JSONObject.toJSONString(responseInfo));
}else {
System.out.println("ReturnCode:"+responseInfo.getReturnCode());
System.out.println("ReturnMsg:"+responseInfo.getReturnMsg());
}
} catch (IcbcApiException e) {
e.printStackTrace();
}
}
}
相关参数填写下就可以进行测试了,以下是我填写信息后进行的测试,如下图所示:
因为我这个订单已经退款成功了,所以会返回退款已成功,请勿重复提交的提示.
在项目中的使用我这边加了一些判断,就是说在代理商审核通过,同意退款后,向工行发起退款请求之前做了以下判断
根据订单号查询订单信息中的代理商id,判断其是否存在
根据订单号查询用户支付成功传入的随机订单号
根据代理商id查询代理商的子商户号
如果以上判断都为true的话,我才会封装请求退款接口的参数来请求工行退款
根据返回的响应消息判断是否受理成功,失败的话修改订单的状态为退款失败,并将失败原因保存到订单中,供用户查看;成功的话,也是修改订单的状态为退款成功,并执行其下面的业务流程.
项目中的具体代码如下所示
/**
* 工行支付
* @param icbcConfig 工行参数
* @param orderNo 订单号
* @return 成功/失败
*/
private ResponseData payRefundAccept(ICBCConfig icbcConfig, String orderNo) {
//构建client
DefaultIcbcClient client = new DefaultIcbcClient(icbcConfig.getAppId(), IcbcConstants.SIGN_TYPE_RSA2,
icbcConfig.getMyPrivateKey(), IcbcConstants.CHARSET_UTF8, IcbcConstants.FORMAT_JSON, icbcConfig.getApigwPublicKey(),
IcbcConstants.ENCRYPT_TYPE_AES, icbcConfig.getEncryptKey(), "", "");
//构建查询请求对象
RefundAcceptRequestV1 request = new RefundAcceptRequestV1();
request.setServiceUrl(ICBCConfig.REFUND_URL);
RefundAcceptRequestV1.RefundAcceptRequestV1Biz bizContent = new RefundAcceptRequestV1.RefundAcceptRequestV1Biz();
bizContent.setAppId(icbcConfig.getAppId());
//查询代理商id
TdCommodityUserOrder orderCommodity = tdCommodityUserOrderService.findByOrderNo(orderNo);
if (ObjectUtils.isEmpty(orderCommodity)){
return ResponseData.fail("未查询到代理商");
}
TdCommodityUserOrderIcbcResp resp = tdCommodityUserOrderIcbcService.selectByOrderNo(orderNo);
if (ObjectUtils.isEmpty(resp)){
return ResponseData.fail("未查到传入工行的订单号");
}
SysAgentIcbcInfo icbcInfo = sysAgentIcbcInfoService.selectByAgentInfoId(orderCommodity.getAgentId());
if (ObjectUtils.isEmpty(icbcInfo)){
return ResponseData.fail("未查到子商户号");
}
bizContent.setVendorId(icbcInfo.getOutVendorId());
bizContent.setUserId(icbcInfo.getOutUserId());
//订单类型
bizContent.setPayType(IcbcParamEnum.ICBC_PARAM_ENUM.getThreeValue());
//原平台订单号
bizContent.setOrderId(resp.getIcbcOrderNo());
//平台退款单id
bizContent.setRefundId(orderNo);
//退款金额
bizContent.setRefundAmount(String.valueOf(orderCommodity.getActualAmount().divide(new BigDecimal("100")).setScale(2, RoundingMode.HALF_UP)));
//退款通知url
bizContent.setNotifyUrl("因为没有用到这个可以随意写个");
request.setBizContent(bizContent);
RefundAcceptResponseV1 responseInfo = null;
try {
log.info("发起工行退款请求 request={}",JSONObject.toJSONString(request));
responseInfo = client.execute(request, System.currentTimeMillis() + "");
log.info("判断请求结果");
} catch (IcbcApiException e) {
e.printStackTrace();
}
if (!responseInfo.isSuccess() || 0 != responseInfo.getReturnCode()){
log.info("退款请求失败,返回请求结果");
log.info("请求结果:code={},msg={},msgId={}",responseInfo.getReturnCode(),responseInfo.getReturnMsg(),responseInfo.getMsgId());
log.info("请求失败返回信息:response={}", JSONObject.toJSONString(responseInfo));
TdCommodityUserOrder tdCommodityUserOrder = new TdCommodityUserOrder();
tdCommodityUserOrder.setId(orderCommodity.getId());
tdCommodityUserOrder.setOrderNo(orderNo);
tdCommodityUserOrder.setOrderStatus((byte)6);
tdCommodityUserOrderService.updateTdCommodityUserOrder(tdCommodityUserOrder);
tdCommodityUserOrderService.updateOrderStatusByOrderNo(tdCommodityUserOrder.getOrderStatus(),orderNo,new Date());
TdCommodityUserOrderIcbc tdCommodityUserOrderIcbc = new TdCommodityUserOrderIcbc();
tdCommodityUserOrderIcbc.setId(resp.getId());
tdCommodityUserOrderIcbc.setIcbcReason(responseInfo.getReturnMsg());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
tdCommodityUserOrderIcbc.setPayRefundDateTime(sdf.format(new Date()));
tdCommodityUserOrderIcbcService.updateByPrimaryKeySelective(tdCommodityUserOrderIcbc);
return new ResponseData<>(CodeIdEnum.FAILED, JSONObject.toJSONString(responseInfo));
}
log.info("请求成功,返回请求结果");
log.info("请求结果:code={},msg={},msgId={}",responseInfo.getReturnCode(),responseInfo.getReturnMsg(),responseInfo.getMsgId());
log.info("请求成功返回信息:response={}", JSONObject.toJSONString(responseInfo));
/* TdCommodityTradeOrder tradeOrder = tdCommodityUserOrderService.findTradeOrder(orderNo);
TdCommodityTradeOrder tdCommodityTradeOrder1 = new TdCommodityTradeOrder();
tdCommodityTradeOrder1.setId(tradeOrder.getId());
for (RefundAcceptResponseV1.SubRefund subRefund : responseInfo.getSubRefunds()) {
tdCommodityTradeOrder1.setThirdOrderNo(subRefund.getRi());
}
tdCommodityUserOrderService.updateByPrimaryKeySelective(tdCommodityTradeOrder1);*/
return new ResponseData<>(CodeIdEnum.Success,JSONObject.toJSONString(responseInfo));
}
在这里说明下为啥没有走回调,因为工行退款不是实时到账的,它会在T+1退到账户,走不走回调意义不是很大,其实回调也可以走的,不过测试的时候只能在线上进行测试,若果有啥问题会影响用户的使用,它不像支付一样,支付如果走主动查询工行订单状态,会多发一次请求,而在退款里不会多发请求,也就是说,门店App同意退款了,就会向工行发送退款请求,根据返回的响应信息就可以判断是否受理成功,成功工行那边会自行进行退款操作,只是退款到账的时间的无法确定.