从零玩转系列之微信支付实战PC端支付微信退款接口搭建2

简介: 从零玩转系列之微信支付实战PC端支付微信退款接口搭建

二、步入正题

修改 WechatNativeController 编写申请退款接口

/**
     * 申请退款
     * @param orderNo 订单号
     * @param refundsNo 退款单号(交易订单号)
     * @param reason 退款原因
     */
    @PostMapping("/refunds/{orderNo}/{refundsNo}/{reason}")
    public R refunds(@PathVariable String orderNo, @PathVariable String refundsNo, @PathVariable String reason) {
        log.info("申请退款");
        wxPayService.refund(orderNo, reason, refundsNo);
        return R.ok();
    }

修改 wxPayService 创建 refund 方法

/**
     * 申请退款
     *
     * @param orderNo   订单号
     * @param reason    退款原因
     * @param refundsNo 退款单号
     */
    @SneakyThrows
    public void refund(String orderNo, String reason, String refundsNo) {
        // ............
    }

前面思考提到的需要查询该订单是否存在和状态要支付成功的

log.info("校验开始");
    PaymentInfo paymentInfo = paymentInfoService.lambdaQuery().eq(PaymentInfo::getOrderNo, orderNo)
            .eq(PaymentInfo::getTradeState, WxTradeState.SUCCESS.getType()).one();
    if (null == paymentInfo) {
        throw new RuntimeException("未查询到该订单,请稍后再试!");
    }

在校验客户输入的交易订单号是否正确我这里就判断后四位咯

// 判断是否是本人的订单
String transactionNo = paymentInfo.getTransactionId().substring(paymentInfo.getTransactionId().length() - 4);
        if (!transactionNo.equals(refundsNo)) {
        throw new RuntimeException("这笔可能不是你的订单哦.请核实支付成功后微信通知当中的交易订单号后四位!");
        }

搞定后我们还需要思考一下,支付这么重要的退款环节我们是不是得要记录一下? 退款啊我直接裂开没赚到钱~


8da7bead_5151444.png

那么我们就查看一下之前文章提到的退款记录表,有同学可能直接懵逼直达车前往第三章从零玩转系列之微信支付实战基础框架搭建当中的创建三层结构所提到过

CREATE TABLE `t_refund_info` (
                                 `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '款单id',
                                 `order_no` varchar(50) DEFAULT NULL COMMENT '商户订单编号',
                                 `refund_no` varchar(50) DEFAULT NULL COMMENT '商户退款单编号',
                                 `refund_id` varchar(50) DEFAULT NULL COMMENT '支付系统退款单号',
                                 `total_fee` int(11) DEFAULT NULL COMMENT '原订单金额(分)',
                                 `refund` int(11) DEFAULT NULL COMMENT '退款金额(分)',
                                 `reason` varchar(50) DEFAULT NULL COMMENT '退款原因',
                                 `refund_status` varchar(10) DEFAULT NULL COMMENT '退款状态',
                                 `content_return` text COMMENT '申请退款返回参数',
                                 `content_notify` text COMMENT '退款结果通知参数',
                                 `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
                                 `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
                                 PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;

搞定后我们就处理创建退款单记录并且保存到数据库当中

修改 refundInfoService 创建 createRefundByOrderNo 方法

log.info("创建退款单记录");
//根据订单编号创建退款单
        RefundInfo refundsInfo = refundInfoService.createRefundByOrderNo(orderNo, reason);
        log.info("调用退款API");

b0b66ba4_5151444.png

处理创建退款单逻辑

// 根据订单号生成退款订单
 RefundInfo refundInfo = new RefundInfo();
         refundInfo.setOrderNo(orderNo);//订单编号
         refundInfo.setRefundNo(OrderNoUtils.getRefundNo());//退款单编号
         refundInfo.setTotalFee();//原订单金额(分)
         refundInfo.setRefund();//退款金额(分)
         refundInfo.setReason(reason);//退款原因

创建实体把参数注入进去剩下的我们还缺少订单金额 我们传递了个参数是订单编号 那么我们想想看这个在哪里搞?

调用订单服务获取金额信息💰

注入订单服务IOC

/**
 * 订单信息服务
 */
private final OrderInfoService orderInfoService;

发起查询订单信息接口

// 根据订单号获取订单信息
OrderInfo orderInfo = orderInfoService.lambdaQuery().eq(OrderInfo::getOrderNo, orderNo).one();

最终插入数据库

/**
 * 创建退款订单根据订单号
 *
 * @param orderNo 订单号
 * @param reason  退款原因
 * @return {@link RefundInfo}
 */
public RefundInfo createRefundByOrderNo(String orderNo, String reason) {
        // 根据订单号获取订单信息
        OrderInfo orderInfo = orderInfoService.lambdaQuery().eq(OrderInfo::getOrderNo, orderNo).one();
        // 根据订单号生成退款订单
        RefundInfo refundInfo = new RefundInfo();
        refundInfo.setOrderNo(orderNo);//订单编号
        refundInfo.setRefundNo(OrderNoUtils.getRefundNo());//退款单编号
        refundInfo.setTotalFee(orderInfo.getTotalFee());//原订单金额(分)
        refundInfo.setRefund(orderInfo.getTotalFee());//退款金额(分)
        refundInfo.setReason(reason);//退款原因
        //保存退款订单
        baseMapper.insert(refundInfo);
        return refundInfo;
        }

调用退款API

**请求URL:**https://api.mch.weixin.qq.com/v3/refund/domestic/refunds

**请求方式:**POST

请求参数:

参数名 变量 类型[长度限制] 必填 描述

微信支付订单号 transaction_id string[1, 32] 二选一 body原支付交易对应的微信订单号 示例值:1217752501201407033233368018

商户订单号 out_trade_no string[6, 32] 二选一 body原支付交易对应的商户订单号 示例值:1217752501201407033233368018

商户退款单号 out_refund_no string[1, 64] 是 body商户系统内部的退款单号,商户系统内部唯一,只能是数字、大小写字母_-|*@ ,同一退款单号多次请求只退一笔。 示例值:1217752501201407033233368018

退款原因 reason string[1, 64] 否 不一定要填写

金额信息 amount object 是 body订单金额信息

* 退款金额 refund int 是 退款金额,单位为分,只能为整数,不能超过原订单支付金额。示例值:888

* 原订单金额 total int 是 原支付交易的订单总金额,单位为分,只能为整数。示例值:888

发起API前言

  1. 组装调用API
  2. 组装请求参数
  3. 解析返回的响应数据
  4. 更新订单状态和更新退款单将本次的返回json保存
  5. 根据前面提到的退款完成后微信会发起一个退款回调信息的处理

WxApiType 请求API 枚举 基础项目搭建的内容不要忘记咯

// 调用统一下单API
String url = wxPayConfig.getDomain().concat(WxApiType.DOMESTIC_REFUNDS.getType());
        HttpPost httpPost = new HttpPost(url);
// 请求body参数
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("out_trade_no", orderNo);//订单编号
        paramsMap.put("out_refund_no", refundsInfo.getRefundNo());//退款单编号
        paramsMap.put("reason", reason);//退款原因
        paramsMap.put("notify_url", wxPayConfig.getNotifyDomain().concat(WxNotifyType.REFUND_NOTIFY.getType()));//退款通知地址
        Map<String, Object> amountMap = new HashMap<>();
        amountMap.put("refund", refundsInfo.getRefund());// 退款金额
        amountMap.put("total", refundsInfo.getTotalFee());// 原订单金额
        amountMap.put("currency", "CNY");// 退款币种
        paramsMap.put("amount", amountMap);
//将参数转换成json字符串
        String jsonParams = JSONUtil.toJsonStr(paramsMap);
        log.info("请求参数 ===> {}", jsonParams);
        StringEntity entity = new StringEntity(jsonParams, "utf-8");
        entity.setContentType("application/json");//设置请求报文格式
        httpPost.setEntity(entity);//将请求报文放入请求对象
        httpPost.setHeader("Accept", "application/json");//设置响应报文格式

组装完毕执行请求

// 完成签名并执行请求,并完成验签
try (CloseableHttpResponse response = wxPayClient.execute(httpPost)) {
        //解析响应结果
        JSONObject resultMap = buildBodyParams(response, JSONObject.class);
        log.info("退款返回结果 ===> {}", resultMap);
        // 更新订单状态
        orderInfoService.lambdaUpdate().eq(OrderInfo::getOrderNo, orderNo).set(OrderInfo::getOrderStatus, OrderStatus.REFUND_PROCESSING.getType()).update();
        // 更新退款单
        refundInfoService.updateRefund(resultMap);
        }

修改 refundInfoService 创建 updateRefund 方法保存本次退款响应的部分重要信息

退款返回参数:

7d77eb0d_5151444.png

更新逻辑

  1. 根据我们创建的退款单的退款单号为条件
  2. 填充数据库对应字段参数
  3. 判断当前是否为退款返回的响应而不是退款回调的响应参数
  4. 执行更新语句

首先说一下 序号三的问题

3266906c_5151444.png

可以看到申请退款接口返回的响应状态字段是 status

29c40b21_5151444.png

可以看到退款回调接口返回的响应状态字段是 refund_status

由此可以看出来我们需要做不同的处理因为到时候要调用我们这个更新退款单的方法代码逻辑都是一样的直接共用即可

完整的处理逻辑

/**
 * 更新退款单
 *
 * @param resultMap 退款响应结果
 */
public void updateRefund(JSONObject resultMap) {
        // 根据退款单编号修改退款单
        QueryWrapper<RefundInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("refund_no", resultMap.getStr("out_refund_no"));
        // 设置要修改的字段
        RefundInfo refundInfo = new RefundInfo();
        refundInfo.setRefundId(resultMap.getStr("refund_id"));//微信支付退款单号
        // 查询退款和申请退款中的返回参数
        if (resultMap.get("status") != null) {
        refundInfo.setRefundStatus(resultMap.getStr("status"));//退款状态
        refundInfo.setContentReturn(resultMap.toString());//将全部响应结果存入数据库的content字段
        }
        // 退款回调中的回调参数
        if (resultMap.get("refund_status") != null) {
        refundInfo.setRefundStatus(resultMap.getStr("refund_status"));//退款状态
        refundInfo.setContentNotify(resultMap.toString());//将全部响应结果存入数据库的content字段
        }
        //更新退款单
        baseMapper.update(refundInfo, queryWrapper);
        }
相关文章
|
2月前
|
移动开发 小程序 开发工具
揭秘微信/支付宝6大支付方式:从扫码到刷脸,谁在偷偷赚你的手续费?优雅草卓伊凡
揭秘微信/支付宝6大支付方式:从扫码到刷脸,谁在偷偷赚你的手续费?优雅草卓伊凡
246 0
揭秘微信/支付宝6大支付方式:从扫码到刷脸,谁在偷偷赚你的手续费?优雅草卓伊凡
|
2月前
|
移动开发 算法 安全
快应用如何去申请微信支付商户?-快应用申请微信支付-优雅草卓伊凡
快应用如何去申请微信支付商户?-快应用申请微信支付-优雅草卓伊凡
71 0
快应用如何去申请微信支付商户?-快应用申请微信支付-优雅草卓伊凡
|
4月前
|
JSON 监控 小程序
微信百度字节小程序包过大解决方案(实战经验总结)-优雅草卓伊凡|果果|小无
微信百度字节小程序包过大解决方案(实战经验总结)-优雅草卓伊凡|果果|小无
245 14
微信百度字节小程序包过大解决方案(实战经验总结)-优雅草卓伊凡|果果|小无
|
6月前
|
安全 算法 小程序
【03】微信支付商户申请下户到配置完整流程-微信开放平台创建APP应用-填写上传基础资料-生成安卓证书-获取Apk签名-申请+配置完整流程-优雅草卓伊凡
【03】微信支付商户申请下户到配置完整流程-微信开放平台创建APP应用-填写上传基础资料-生成安卓证书-获取Apk签名-申请+配置完整流程-优雅草卓伊凡
352 28
【03】微信支付商户申请下户到配置完整流程-微信开放平台创建APP应用-填写上传基础资料-生成安卓证书-获取Apk签名-申请+配置完整流程-优雅草卓伊凡
|
6月前
|
小程序
【04】微信支付商户申请下户到配置完整流程-微信开放平台移动APP应用通过-微信商户继续申请-微信开户函-视频声明-以及对公打款验证-申请+配置完整流程-优雅草卓伊凡
【04】微信支付商户申请下户到配置完整流程-微信开放平台移动APP应用通过-微信商户继续申请-微信开户函-视频声明-以及对公打款验证-申请+配置完整流程-优雅草卓伊凡
427 1
【04】微信支付商户申请下户到配置完整流程-微信开放平台移动APP应用通过-微信商户继续申请-微信开户函-视频声明-以及对公打款验证-申请+配置完整流程-优雅草卓伊凡
|
7月前
|
小程序
【01】微信支付商户申请下户到配置完整流程-微信商户申请-资料准备以及提交-微信商户密钥申请-申请+配置完整流程-优雅草卓伊凡
【01】微信支付商户申请下户到配置完整流程-微信商户申请-资料准备以及提交-微信商户密钥申请-申请+配置完整流程-优雅草卓伊凡
200 2
【01】微信支付商户申请下户到配置完整流程-微信商户申请-资料准备以及提交-微信商户密钥申请-申请+配置完整流程-优雅草卓伊凡
|
7月前
|
小程序 数据安全/隐私保护 开发者
【02】微信支付商户申请下户到配置完整流程-微信开放平台申请APP应用-微信商户支付绑定appid-公众号和小程序分别申请appid-申请+配置完整流程-优雅草卓伊凡
【02】微信支付商户申请下户到配置完整流程-微信开放平台申请APP应用-微信商户支付绑定appid-公众号和小程序分别申请appid-申请+配置完整流程-优雅草卓伊凡
356 3
|
7月前
|
小程序 测试技术 数据安全/隐私保护
微信公众号接口测试实战指南
微信公众号接口测试是确保系统稳定性和功能完整性的重要环节。本文详细介绍了测试全流程,包括准备、工具选择(如Postman、JMeter)、用例设计与执行,以及常见问题的解决方法。通过全面测试,可以提前发现潜在问题,优化用户体验,确保公众号上线后稳定运行。内容涵盖基础接口、高级接口、微信支付和数据统计接口的测试,强调了功能验证、性能优化、安全保护及用户体验的重要性。未来,随着微信生态的发展,接口测试将面临更多挑战和机遇,如小程序融合、AI应用和国际化拓展。
|
9月前
|
API 开发者
微信native支付对接案例详解
本文详细介绍了微信Native支付的对接流程,包括效果展示、产品介绍、接入前准备、开发指引、API列表、支付通知等,并强调了只有通过微信认证的服务号才能对接微信支付。每年需支付300元认证费用。
369 3
|
7月前
|
自然语言处理 搜索推荐 小程序
微信公众号接口:解锁公众号开发的无限可能
微信公众号接口是微信官方提供的API,支持开发者通过编程与公众号交互,实现自动回复、消息管理、用户管理和数据分析等功能。本文深入探讨接口的定义、类型、优势及应用场景,如智能客服、内容分发、电商闭环等,并介绍开发流程和工具,帮助运营者提升用户体验和效率。未来,随着微信生态的发展,公众号接口将带来更多机遇,如小程序融合、AI应用等。

热门文章

最新文章