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


    上篇文章谈了谈工银聚富通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();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    相关参数填写下就可以进行测试了,以下是我填写信息后进行的测试,如下图所示:
    因为我这个订单已经退款成功了,所以会返回退款已成功,请勿重复提交的提示.
    在这里插入图片描述

    项目中的使用

    在项目中的使用我这边加了一些判断,就是说在代理商审核通过,同意退款后,向工行发起退款请求之前做了以下判断
    根据订单号查询订单信息中的代理商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));
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    在这里说明下为啥没有走回调,因为工行退款不是实时到账的,它会在T+1退到账户,走不走回调意义不是很大,其实回调也可以走的,不过测试的时候只能在线上进行测试,若果有啥问题会影响用户的使用,它不像支付一样,支付如果走主动查询工行订单状态,会多发一次请求,而在退款里不会多发请求,也就是说,门店App同意退款了,就会向工行发送退款请求,根据返回的响应信息就可以判断是否受理成功,成功工行那边会自行进行退款操作,只是退款到账的时间的无法确定.

  • 相关阅读:
    七夕特别篇 | 浪漫的Bug
    设计模式(一)——单例模式(Singleton)
    【可视化大屏】用该软件,无代码,更易用
    Impala中replace和translate的用法和区别
    目前无法建立VS2013与Qt的连接???
    Docker学习-Docker底层原理和常用命令
    我转行做版图工程师,还是IC验证好呢?怎么选!一文秒懂
    Vue路由使用(router)
    JAVA毕业设计课程与成绩管理计算机源码+lw文档+系统+调试部署+数据库
    金九银十求职季:分享90%以上你可能会遇到的经典面试题(测试人必备)
  • 原文地址:https://blog.csdn.net/qq_41934990/article/details/126268325