工行(工银聚富通)-申请退款

上篇文章谈了谈工银聚富通H5支付,有支付就得有退款,这是一个完整的流程,下面来说下聚富通的退款,在项目中的流程是,用户在小程序里点击申请退款,有门店App那边来审核,门店App审核通过后会向工行发送退款请求,如果工行那边受理成功的话,这个退款流程就成功了,工行那边会在T+日退款到用户的账户.如果发送退款请求受理失败,会将退款失败原因返回的.
聚富通服务商申请退款接口文档

测试demo

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同意退款了,就会向工行发送退款请求,根据返回的响应信息就可以判断是否受理成功,成功工行那边会自行进行退款操作,只是退款到账的时间的无法确定.


版权声明:本文为qq_41934990原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。