无关风月
2025-04-09 cda724da35beb1ffd84955cc42bda5ab399ebbe1
Merge branch 'master' of http://120.76.84.145:10101/gitblit/r/java/JiaDianHuiShou

# Conflicts:
# ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/WithdrawServiceImpl.java
14个文件已修改
3个文件已添加
635 ■■■■ 已修改文件
ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/entity/Order.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/entity/WithdrawDetailVO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/WechatConstants.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/vo/UserDto.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/pom.xml 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/WithdrawController.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/WxChatPayCallBack.java 203 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/entity/Order.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/WithdrawServiceImpl.java 200 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/task/TaskUtil.java 68 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/vo/WithdrawDetailVO.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/vx/QuickStart.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/vx/TestWxPay.java 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/resources/mybatis-config.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-user/src/main/java/com/ruoyi/user/controller/RecoveryServeController.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-user/src/main/java/com/ruoyi/user/service/impl/WithdrawServiceImpl.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-user/src/main/java/com/ruoyi/user/vo/WithdrawOrderVO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/entity/Order.java
@@ -194,5 +194,6 @@
    @ApiModelProperty("回收单凭证(多张照片 ','隔开)")
    @TableField("paper_pic")
    private String paperPic;
    @ApiModelProperty("拉起确认收款页面参数")
    private String packageInfo;
}
ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/entity/WithdrawDetailVO.java
@@ -20,6 +20,8 @@
    @ApiModelProperty("订单编号")
    private String orderNumber;
    @ApiModelProperty("拉起确认收款参数")
    private String packageInfo;
    @ApiModelProperty("下单用户id")
    private Integer userId;
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/WechatConstants.java
@@ -57,9 +57,13 @@
    public static final String TRANSFER_DETAIL_LIST = "transfer_detail_list";
    /**
     * 微信商家转账到用户零钱接口地址(前缀)
     * 微信商家转账到用户零钱接口地址(前缀)弃用
     */
    public static final String WE_CHAT_URL_PRE = "https://api.mch.weixin.qq.com/v3/transfer/batches";
    /**
     * 微信发起转账(前缀)
     */
    public static final String WE_CHAT_PAY_URL_PRE = "https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills";
    /**
     * 微信商家转账到用户零钱接口地址(后缀)
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/vo/UserDto.java
@@ -12,4 +12,5 @@
    private String profilePicture;
    private String phone;
    private String userNo;
    private String openId;
}
ruoyi-service/ruoyi-order/pom.xml
@@ -19,7 +19,10 @@
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.github.wechatpay-apiv3</groupId>
            <artifactId>wechatpay-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/WithdrawController.java
@@ -340,6 +340,7 @@
            withdrawDetailVO.setWithdrawalState(withdraw.getState());
            withdrawDetailVO.setWithdrawalTime(withdraw.getCreateTime());
        }
        withdrawDetailVO.setPackageInfo(order.getPackageInfo());
        withdrawDetailVO.setAddress(order.getAddress());
        if (null != serveRecord) {
            withdrawDetailVO.setPhoto(serveRecord.getPhoto());
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/WxChatPayCallBack.java
New file
@@ -0,0 +1,203 @@
package com.ruoyi.order.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.constant.Constants;
import com.ruoyi.common.core.constant.WechatConstants;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.exception.GlobalException;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.vo.UserDto;
import com.ruoyi.common.security.annotation.RequiresPermissions;
import com.ruoyi.order.entity.ChangeDispatch;
import com.ruoyi.order.entity.Order;
import com.ruoyi.order.entity.Withdraw;
import com.ruoyi.order.entity.WithdrawDetail;
import com.ruoyi.order.request.ChangeDispatchRequest;
import com.ruoyi.order.service.ChangeDispatchService;
import com.ruoyi.order.service.OrderService;
import com.ruoyi.order.service.WithdrawDetailService;
import com.ruoyi.order.service.WithdrawService;
import com.ruoyi.order.vx.HttpUtil;
import com.ruoyi.system.api.RemoteUserService;
import com.ruoyi.user.api.feignClient.UserClient;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
/**
 * <p>
 * 商家转账回调
 * </p>
 *
 * @author hjl
 * @since 2024-05-31
 */
@RestController
@RequestMapping("/wx")
public class WxChatPayCallBack {
    @Autowired
    private WithdrawDetailService withdrawDetailService;
    @Resource
    private OrderService orderService;
    @Autowired
    private WithdrawService withdrawService;
    @Autowired
    private UserClient userClient;
    /**
     * 微信商户零线转账 - 回调通知
     * @Context注解  把HTTP请求上下文对象注入进来,HttpServletRequest、HttpServletResponse、UriInfo 等
     * @return
     */
    @PostMapping("/wxChatPay")
    public String wxPayCallback(HttpServletRequest request) {
        Map<String, String> map = new HashMap<>();
        Map<String,String> errMap = new HashMap<>();
        try { System.err.println("请求"+request);
            BufferedReader reader = request.getReader();
            String string1 = reader.toString();
            System.err.println("请求reader"+string1);
            StringBuilder requestBody = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                requestBody.append(line);
            }
            System.err.println("全部请求体"+requestBody);
            JSONObject jsonObject = JSONObject.parseObject(requestBody.toString());
            JSONObject resource = jsonObject.getJSONObject("resource");
            AesUtil aesUtil = new AesUtil("TA2npSNWmS0GcB0tFFRWA94rm1M0iSFs".getBytes(StandardCharsets.UTF_8));
            String decryptedData = aesUtil.decryptToString(resource.getString("associated_data").getBytes(StandardCharsets.UTF_8), resource.getString("nonce").getBytes(StandardCharsets.UTF_8),
                    resource.getString("ciphertext"));
            System.err.println("微信解密的字符串信息"+decryptedData);
            JSONObject jsonInfo = (JSONObject) JSONObject.parse(decryptedData);
            String transferBillNo = jsonInfo.getString("transfer_bill_no");
            String outBillNo = jsonInfo.getString("out_bill_no");
            String state = jsonInfo.getString("state");
            WithdrawDetail withdrawDetail = withdrawDetailService.lambdaQuery().eq(WithdrawDetail::getOutBatchNo, outBillNo).one();
            Withdraw withdraw = withdrawService.getById(withdrawDetail.getWithdrawId());
            Order order = orderService.getById(withdraw.getOrderId());
            UserDto data = userClient.getUser(order.getUserId()).getData();
            if (order.getIsWithdrawal()==3){
                return "SUCCESS";
            }
            if ("SUCCESS".equals(state)){
                order.setIsWithdrawal(3);
                withdrawDetail.setStatus("SUCCESS");
                withdrawDetailService.updateById(withdrawDetail);
                orderService.updateById(order);
            }else if ("CANCELLED".equals(state)){
                // 校验提现
                List<Withdraw> list = withdrawService.lambdaQuery().eq(Withdraw::getUserId, order.getUserId())
                        .eq(Withdraw::getOrderId, order.getId()).list();
                List<Integer> stateList = list.stream().map(Withdraw::getState).collect(Collectors.toList());
                if (stateList.contains(Constants.ONE)) {
                    throw new GlobalException("当前订单提现申请已通过!");
                }
                // 超时未收款 撤销 重新发起转账 更新packageInfo
                weChatPay(order.getOrderMoney(), data.getOpenId(),list.get(0).getId(),order.getServeName());
            }
            map.put("code", "SUCCESS");
            map.put("message", "成功");
        } catch (Exception e) {
            errMap.put("code", "FAIL");
            errMap.put("message", "服务器内部错误");
        }
        return JSON.toJSONString(map);
    }
    private boolean weChatPay(BigDecimal orderMoney, String openId, String withdrawId, String serverName) {
        if (StringUtils.isBlank(openId)) {
            return false;
        }
        BigDecimal maxTransferAmount = new BigDecimal("200000"); // 单次转账限额,单位为分
        int totalTransfers = orderMoney.multiply(new BigDecimal("100")).divide(maxTransferAmount, 0, RoundingMode.UP).intValue();
        boolean allTransfersSuccessful = true;
        for (int i = 0; i < totalTransfers; i++) {
            BigDecimal transferAmount;
            if (i < totalTransfers - 1) {
                transferAmount = maxTransferAmount;
            } else {
                // 最后一笔转账,金额为剩余金额
                transferAmount = orderMoney.multiply(new BigDecimal("100")).subtract(maxTransferAmount.multiply(new BigDecimal(i))).setScale(0, RoundingMode.DOWN);
            }
            Map<String, Object> postMap = new HashMap<>(8);
            postMap.put(WechatConstants.APP_ID, "wx98563d0ec9cf21c8");
            // 订单号
            String s = String.valueOf(UUID.randomUUID()).replaceAll("-", "");
            postMap.put("out_bill_no", s);
            System.err.println("====="+postMap.get("out_bill_no"));
            postMap.put(WechatConstants.OPEN_ID, openId);
            // 转账金额
            postMap.put("transfer_amount", transferAmount);
            // 转账备注
            postMap.put("transfer_remark", "二手回收提现确认收款");
            // 回调地址
            postMap.put("notify_url", "https://hyhsbqgc.com/api/ruoyi-order/wx/wxChatPay");
            // 转账场景报备信息
            Map<String, Object> info = new HashMap<>();
            info.put("info_type","回收商品名称");
            info.put("info_content",serverName);
            postMap.put("transfer_scene_report_infos", com.alibaba.fastjson2.JSONObject.toJSONString(info));
            String result = HttpUtil.postTransBatRequest(
                    WechatConstants.WE_CHAT_PAY_URL_PRE,
                    com.alibaba.fastjson2.JSONObject.toJSONString(postMap),
                    "7EEA04429B006E12AAA421C002EC48BBEED5BE94",
                    "1665330417",
                    "/usr/local/vx/apiclient_key.pem", WechatConstants.WE_CHAT_URL_SUF);
            com.alibaba.fastjson2.JSONObject jsonObject = com.alibaba.fastjson2.JSONObject.parseObject(result);
//            WithdrawDetail withdrawDetail = new WithdrawDetail();
//            withdrawDetail.setWithdrawId(withdrawId);
//            withdrawDetail.setMoney(transferAmount);
//            withdrawDetail.setOutBatchNo((String) postMap.get(WechatConstants.OUT_BATCH_NO));
//            withdrawDetailService.save(withdrawDetail);
            if (jsonObject.containsKey(WechatConstants.CREATE_TIME)) {
                String string = jsonObject.getString("package_info");
                Withdraw withdraw = withdrawService.getById(withdrawId);
                WithdrawDetail one = withdrawDetailService.lambdaQuery().eq(WithdrawDetail::getWithdrawId, withdrawId).last("limit 1").one();
                if (one!=null){
                    one.setOutBatchNo(s);
                    one.setStatus("FAIL");
                    withdrawDetailService.updateById(one);
                    Order order = orderService.getById(withdraw.getOrderId());
                    order.setPackageInfo(string);
                    order.setIsWithdrawal(2);
                    orderService.updateById(order);
                }
            } else {
                allTransfersSuccessful = false;
                break;
            }
        }
        return allTransfersSuccessful;
    }
}
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/entity/Order.java
@@ -61,7 +61,9 @@
    @ApiModelProperty("站点名称")
    @TableField("site_name")
    private String siteName;
    @ApiModelProperty("拉起确认收款页面参数")
    @TableField("package_info")
    private String packageInfo;
    @ApiModelProperty("回收服务id")
    @TableField("serve_id")
    private Integer serveId;
@@ -145,7 +147,7 @@
    @TableField("subsidy")
    private BigDecimal subsidy;
    @ApiModelProperty("是否已提现(0:未提现,1:已提现)")
    @ApiModelProperty("是否已提现(0:未提现,1:审核中 2审核通过 3:已确认收款)")
    @TableField("is_withdrawal")
    private Integer isWithdrawal;
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/WithdrawServiceImpl.java
@@ -138,7 +138,7 @@
            throw new GlobalException("当前订单提现申请已通过!");
        }
        return weChatPay(order.getOrderMoney(), openId,list.get(0).getId());
        return weChatPay(order.getOrderMoney(), openId,list.get(0).getId(),order.getServeName());
    }
    @Override
@@ -252,7 +252,7 @@
            // 已通过
            withdraw.setState(Constants.ONE);
            // 商家微信打款至微信零钱
            boolean update = weChatPay(order.getOrderMoney(), openId,withdraw.getId());
            boolean update = weChatPay(order.getOrderMoney(), openId,withdraw.getId(),order.getServerName());
//            if (!update) {
//                throw new GlobalException("交易提现失败,请检查是否绑定微信!");
//            }
@@ -272,15 +272,94 @@
    @Resource
    private WithdrawDetailService withdrawDetailService;
    private boolean weChatPay(BigDecimal orderMoney, String openId,String withdrawId) {
//    private boolean weChatPay(BigDecimal orderMoney, String openId,String withdrawId) {
//        if (StringUtils.isBlank(openId)) {
//            return false;
//        }
//
//        BigDecimal maxTransferAmount = new BigDecimal("20000"); // 单次转账限额,单位为分
//        int totalTransfers = orderMoney.multiply(new BigDecimal("100")).divide(maxTransferAmount, 0, RoundingMode.UP).intValue();
//        boolean allTransfersSuccessful = true;
//
//        for (int i = 0; i < totalTransfers; i++) {
//            BigDecimal transferAmount;
//            if (i < totalTransfers - 1) {
//                transferAmount = maxTransferAmount;
//            } else {
//                // 最后一笔转账,金额为剩余金额
//                transferAmount = orderMoney.multiply(new BigDecimal("100")).subtract(maxTransferAmount.multiply(new BigDecimal(i))).setScale(0, RoundingMode.DOWN);
//            }
//
//            Map<String, Object> postMap = new HashMap<>(8);
//            postMap.put(WechatConstants.APP_ID, "wx98563d0ec9cf21c8");
//            postMap.put(WechatConstants.OUT_BATCH_NO, String.valueOf(UUID.randomUUID()).replaceAll("-", ""));
//            System.err.println("====="+postMap.get(WechatConstants.OUT_BATCH_NO));
//            postMap.put(WechatConstants.BATCH_NAME, "二手回收提现");
//            postMap.put(WechatConstants.BATCH_REMARK, "二手回收提现");
//            postMap.put(WechatConstants.TOTAL_AMOUNT, transferAmount);
//            postMap.put(WechatConstants.TOTAL_NUM, Constants.ONE);
//
//            List<Map<String, Object>> list = new ArrayList<>();
//            Map<String, Object> subMap = new HashMap<>(4);
//            subMap.put(WechatConstants.OUT_DETAIL_NO, String.valueOf(SNOW_FLAKE_ID_WORKER.nextId()));
//            subMap.put(WechatConstants.TRANSFER_AMOUNT, transferAmount);
//            subMap.put(WechatConstants.TRANSFER_REMARK, "二手回收提现到账");
//            subMap.put(WechatConstants.OPEN_ID, openId);
//            list.add(subMap);
//            postMap.put(WechatConstants.TRANSFER_DETAIL_LIST, list);
//
//            // 使用类加载器获取资源 URL
////            String path = ClassLoader.getSystemResource("/usr/local/vx/apiclient_key.pem").getPath();
//
////            String result = HttpUtil.postTransBatRequest(
////                    WechatConstants.WE_CHAT_URL_PRE,
////                    JSONObject.toJSONString(postMap),
////                    "7EEA04429B006E12AAA421C002EC48BBEED5BE94",
////                    "1665330417",
////                    "/usr/local/vx/apiclient_key.pem", WechatConstants.WE_CHAT_URL_SUF);
//            String result = HttpUtil.postTransBatRequest(
//                    WechatConstants.WE_CHAT_URL_PRE,
//                    JSONObject.toJSONString(postMap),
//                    "7EEA04429B006E12AAA421C002EC48BBEED5BE94",
//                    "1665330417",
//                    "D:\\study\\JiaDianHuiShou\\ruoyi-service\\ruoyi-order\\src\\main\\java\\com\\ruoyi\\order\\vx\\apiclient_key.pem", WechatConstants.WE_CHAT_URL_SUF);
//
//            JSONObject jsonObject = JSONObject.parseObject(result);
//
//            WithdrawDetail withdrawDetail = new WithdrawDetail();
//            withdrawDetail.setWithdrawId(withdrawId);
//            withdrawDetail.setMoney(transferAmount);
//            withdrawDetail.setOutBatchNo((String) postMap.get(WechatConstants.OUT_BATCH_NO));
//            withdrawDetailService.save(withdrawDetail);
//
//            if (jsonObject.containsKey(WechatConstants.CREATE_TIME)) {
//                // 转账成功
//                //保存转账明细
////                WithdrawDetail withdrawDetail = new WithdrawDetail();
////                withdrawDetail.setWithdrawId(withdrawId);
////                withdrawDetail.setMoney(transferAmount);
////                withdrawDetail.setOutBatchNo((String) postMap.get(WechatConstants.OUT_BATCH_NO));
////                withdrawDetailService.save(withdrawDetail);
//
//
//            } else {
//                allTransfersSuccessful = false;
//                break;
//            }
//
//        }
//
//        return allTransfersSuccessful;
//    }
    // 上架打款到用户零钱接口已弃用 用新版商家转账接口
    private boolean weChatPay(BigDecimal orderMoney, String openId,String withdrawId,String serverName) {
        if (StringUtils.isBlank(openId)) {
            return false;
        }
        BigDecimal maxTransferAmount = new BigDecimal("20000"); // 单次转账限额,单位为分
        BigDecimal maxTransferAmount = new BigDecimal("200000"); // 单次转账限额,单位为分
        int totalTransfers = orderMoney.multiply(new BigDecimal("100")).divide(maxTransferAmount, 0, RoundingMode.UP).intValue();
        boolean allTransfersSuccessful = true;
        for (int i = 0; i < totalTransfers; i++) {
            BigDecimal transferAmount;
            if (i < totalTransfers - 1) {
@@ -292,54 +371,57 @@
            Map<String, Object> postMap = new HashMap<>(8);
            postMap.put(WechatConstants.APP_ID, "wx98563d0ec9cf21c8");
            postMap.put(WechatConstants.OUT_BATCH_NO, String.valueOf(UUID.randomUUID()).replaceAll("-", ""));
            System.err.println("====="+postMap.get(WechatConstants.OUT_BATCH_NO));
            postMap.put(WechatConstants.BATCH_NAME, "二手回收提现");
            postMap.put(WechatConstants.BATCH_REMARK, "二手回收提现");
            postMap.put(WechatConstants.TOTAL_AMOUNT, transferAmount);
            postMap.put(WechatConstants.TOTAL_NUM, Constants.ONE);
            // 订单号
            postMap.put("out_bill_no", String.valueOf(UUID.randomUUID()).replaceAll("-", ""));
            System.err.println("====="+postMap.get("out_bill_no"));
            postMap.put(WechatConstants.OPEN_ID, openId);
            // 转账金额
            postMap.put("transfer_amount", transferAmount);
            postMap.put("transfer_scene_id", "1010");
            // 转账备注
            postMap.put("transfer_remark", "二手回收提现确认收款");
            // 回调地址
            postMap.put("notify_url", "https://hyhsbqgc.com/api/ruoyi-order/wx/wxChatPay");
            // 转账场景报备信息
            List<Map<String, Object>> list = new ArrayList<>();
            Map<String, Object> subMap = new HashMap<>(4);
            subMap.put(WechatConstants.OUT_DETAIL_NO, String.valueOf(SNOW_FLAKE_ID_WORKER.nextId()));
            subMap.put(WechatConstants.TRANSFER_AMOUNT, transferAmount);
            subMap.put(WechatConstants.TRANSFER_REMARK, "二手回收提现到账");
            subMap.put(WechatConstants.OPEN_ID, openId);
            list.add(subMap);
            postMap.put(WechatConstants.TRANSFER_DETAIL_LIST, list);
            // 使用类加载器获取资源 URL
//            String path = ClassLoader.getSystemResource("/usr/local/vx/apiclient_key.pem").getPath();
//            String result = HttpUtil.postTransBatRequest(
//                    WechatConstants.WE_CHAT_URL_PRE,
//                    JSONObject.toJSONString(postMap),
//                    "7EEA04429B006E12AAA421C002EC48BBEED5BE94",
//                    "1665330417",
//                    "/usr/local/vx/apiclient_key.pem", WechatConstants.WE_CHAT_URL_SUF);
            Map<String, Object> info = new HashMap<>();
            info.put("info_type","回收商品名称");
            info.put("info_content",serverName);
            list.add(info);
            postMap.put("transfer_scene_report_infos", list);
            String result = HttpUtil.postTransBatRequest(
                    WechatConstants.WE_CHAT_URL_PRE,
                    WechatConstants.WE_CHAT_PAY_URL_PRE,
                    JSONObject.toJSONString(postMap),
                    "7EEA04429B006E12AAA421C002EC48BBEED5BE94",
                    "1665330417",
                    "/usr/local/vx/apiclient_key.pem", WechatConstants.WE_CHAT_URL_SUF);
                    "/usr/local/vx/apiclient_key.pem", "/v3/fund-app/mch-transfer/transfer-bills");
            JSONObject jsonObject = JSONObject.parseObject(result);
            WithdrawDetail withdrawDetail = new WithdrawDetail();
            withdrawDetail.setWithdrawId(withdrawId);
            withdrawDetail.setMoney(transferAmount);
            withdrawDetail.setOutBatchNo((String) postMap.get(WechatConstants.OUT_BATCH_NO));
            withdrawDetailService.save(withdrawDetail);
//            WithdrawDetail withdrawDetail = new WithdrawDetail();
//            withdrawDetail.setWithdrawId(withdrawId);
//            withdrawDetail.setMoney(transferAmount);
//            withdrawDetail.setOutBatchNo((String) postMap.get(WechatConstants.OUT_BATCH_NO));
//            withdrawDetailService.save(withdrawDetail);
            System.err.println(jsonObject);
//            WithdrawDetail withdrawDetail = new WithdrawDetail();
//            withdrawDetail.setWithdrawId(withdrawId);
//            withdrawDetail.setMoney(transferAmount);
//            withdrawDetail.setOutBatchNo((String) postMap.get(WechatConstants.OUT_BATCH_NO));
//            withdrawDetailService.save(withdrawDetail);
            if (jsonObject.containsKey(WechatConstants.CREATE_TIME)) {
                String string = jsonObject.getString("package_info");
                Withdraw withdraw = this.getById(withdrawId);
                Order order = orderService.getById(withdraw.getOrderId());
                order.setIsWithdrawal(2);
                order.setPackageInfo(string);
                orderService.updateById(order);
                // 转账成功
                //保存转账明细
//                WithdrawDetail withdrawDetail = new WithdrawDetail();
//                withdrawDetail.setWithdrawId(withdrawId);
//                withdrawDetail.setMoney(transferAmount);
//                withdrawDetail.setOutBatchNo((String) postMap.get(WechatConstants.OUT_BATCH_NO));
//                withdrawDetailService.save(withdrawDetail);
                WithdrawDetail withdrawDetail = new WithdrawDetail();
                withdrawDetail.setWithdrawId(withdrawId);
                withdrawDetail.setMoney(transferAmount);
                withdrawDetail.setOutBatchNo(postMap.get("out_bill_no")+"");
                withdrawDetailService.save(withdrawDetail);
            } else {
@@ -352,34 +434,6 @@
        return allTransfersSuccessful;
    }
    public static void main(String[] args) {
        Map<String, Object> postMap = new HashMap<>(8);
        postMap.put(WechatConstants.APP_ID, "wx98563d0ec9cf21c8");
        postMap.put(WechatConstants.OUT_BATCH_NO, String.valueOf(UUID.randomUUID()).replaceAll("-", ""));
        System.err.println("====="+postMap.get(WechatConstants.OUT_BATCH_NO));
        postMap.put(WechatConstants.BATCH_NAME, "二手回收提现");
        postMap.put(WechatConstants.BATCH_REMARK, "二手回收提现");
        postMap.put(WechatConstants.TOTAL_AMOUNT, 1);
        postMap.put(WechatConstants.TOTAL_NUM, Constants.ONE);
        List<Map<String, Object>> list = new ArrayList<>();
        Map<String, Object> subMap = new HashMap<>(4);
        subMap.put(WechatConstants.OUT_DETAIL_NO, String.valueOf(SNOW_FLAKE_ID_WORKER.nextId()));
        subMap.put(WechatConstants.TRANSFER_AMOUNT, 1);
        subMap.put(WechatConstants.TRANSFER_REMARK, "二手回收提现到账");
        subMap.put(WechatConstants.OPEN_ID, "ouqOk6-Bp6PnNnlHoQSV-6lzoVoU");
        list.add(subMap);
        postMap.put(WechatConstants.TRANSFER_DETAIL_LIST, list);
        String result = HttpUtil.postTransBatRequest(
                WechatConstants.WE_CHAT_URL_PRE,
                JSONObject.toJSONString(postMap),
                "7EEA04429B006E12AAA421C002EC48BBEED5BE94",
                "1665330417",
                "E:\\ershoucert\\apiclient_key.pem", WechatConstants.WE_CHAT_URL_SUF);
        JSONObject jsonObject = JSONObject.parseObject(result);
        System.err.println(jsonObject);
    }
    /**
     * 根据当前月份获取当前季度的开始月份
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/task/TaskUtil.java
@@ -22,40 +22,40 @@
    private WithdrawDetailService withdrawDetailService;
    /**
     * 每隔一分钟去处理的定时任务
     */
    @Scheduled(fixedRate = 10000 * 60)
    public void taskMinute(){
        try {
            List<WithdrawDetail> list = withdrawDetailService.lambdaQuery().ne(WithdrawDetail::getStatus, "SUCCESS").ne(WithdrawDetail::getStatus, "FAIL").list();
            for (WithdrawDetail withdrawDetail : list) {
                String s = GetTransferBatchByOutNo.checkStatus(withdrawDetail.getOutBatchNo());
                if (s.equals("SUCCESS")) {
                    withdrawDetail.setStatus("SUCCESS");
                    withdrawDetailService.updateById(withdrawDetail);
                    //执行订单提现成功,增加提现成功金额
                    //查询订单
                    //增加已提现金额
                } else if (s.equals("FAIL")) {
                    withdrawDetail.setStatus("FAIL");
                    withdrawDetailService.updateById(withdrawDetail);
                }else {
                    withdrawDetail.setStatus(s);
                    withdrawDetailService.updateById(withdrawDetail);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
//    /**
//     * 每隔一分钟去处理的定时任务
//     */
//    @Scheduled(fixedRate = 10000 * 60)
//    public void taskMinute(){
//        try {
//
//            List<WithdrawDetail> list = withdrawDetailService.lambdaQuery().ne(WithdrawDetail::getStatus, "SUCCESS").ne(WithdrawDetail::getStatus, "FAIL").list();
//
//            for (WithdrawDetail withdrawDetail : list) {
//                String s = GetTransferBatchByOutNo.checkStatus(withdrawDetail.getOutBatchNo());
//                if (s.equals("SUCCESS")) {
//                    withdrawDetail.setStatus("SUCCESS");
//                    withdrawDetailService.updateById(withdrawDetail);
//                    //执行订单提现成功,增加提现成功金额
//                    //查询订单
//
//                    //增加已提现金额
//
//
//                } else if (s.equals("FAIL")) {
//                    withdrawDetail.setStatus("FAIL");
//                    withdrawDetailService.updateById(withdrawDetail);
//                }else {
//                    withdrawDetail.setStatus(s);
//                    withdrawDetailService.updateById(withdrawDetail);
//                }
//
//            }
//
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//    }
}
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/vo/WithdrawDetailVO.java
@@ -17,7 +17,8 @@
    @ApiModelProperty("订单id")
    private String orderId;
    @ApiModelProperty("拉起确认收款参数")
    private String packageInfo;
    @ApiModelProperty("订单编号")
    private String orderNumber;
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/vx/QuickStart.java
New file
@@ -0,0 +1,45 @@
package com.ruoyi.order.vx;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.payments.nativepay.model.Amount;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse;
/** Native 支付下单为例 */
public class QuickStart {
    /** 商户号 */
    public static String merchantId = "190000****";
    /** 商户API私钥路径 */
    public static String privateKeyPath = "/Users/yourname/your/path/apiclient_key.pem";
    /** 商户证书序列号 */
    public static String merchantSerialNumber = "5157F09EFDC096DE15EBE81A47057A72********";
    /** 商户APIV3密钥 */
    public static String apiV3key = "...";
    public static void main(String[] args) {
        // 使用自动更新平台证书的RSA配置
        // 建议将 config 作为单例或全局静态对象,避免重复的下载浪费系统资源
        Config config =
                new RSAAutoCertificateConfig.Builder()
                        .merchantId(merchantId)
                        .privateKeyFromPath(privateKeyPath)
                        .merchantSerialNumber(merchantSerialNumber)
                        .apiV3Key(apiV3key)
                        .build();
        // 构建service
        NativePayService service = new NativePayService.Builder().config(config).build();
        // request.setXxx(val)设置所需参数,具体参数可见Request定义
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        amount.setTotal(100);
        request.setAmount(amount);
        request.setAppid("wxa9d9651ae******");
        request.setMchid("190000****");
        request.setDescription("测试商品标题");
        request.setNotifyUrl("https://notify_url");
        request.setOutTradeNo("out_trade_no_001");
        // 调用下单方法,得到应答
        PrepayResponse response = service.prepay(request);
        // 使用微信扫描 code_url 对应的二维码,即可体验Native支付
        System.out.println(response.getCodeUrl());
    }
}
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/vx/TestWxPay.java
New file
@@ -0,0 +1,83 @@
package com.ruoyi.order.vx;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.constant.WechatConstants;
import com.ruoyi.common.core.utils.StringUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
public class TestWxPay {
    public static void main(String[] args) {
        weChatPay(BigDecimal.valueOf(0.1), "ouqOk6xtWA3JDmpd9HpZf9ijESIs", "1", "空调挂机");
    }
    private static boolean weChatPay(BigDecimal orderMoney, String openId, String withdrawId, String serverName) {
        if (StringUtils.isBlank(openId)) {
            return false;
        }
        BigDecimal maxTransferAmount = new BigDecimal("200000"); // 单次转账限额,单位为分
        int totalTransfers = orderMoney.multiply(new BigDecimal("100")).divide(maxTransferAmount, 0, RoundingMode.UP).intValue();
        boolean allTransfersSuccessful = true;
        for (int i = 0; i < totalTransfers; i++) {
            BigDecimal transferAmount;
            if (i < totalTransfers - 1) {
                transferAmount = maxTransferAmount;
            } else {
                // 最后一笔转账,金额为剩余金额
                transferAmount = orderMoney.multiply(new BigDecimal("100")).subtract(maxTransferAmount.multiply(new BigDecimal(i))).setScale(0, RoundingMode.DOWN);
            }
            Map<String, Object> postMap = new HashMap<>(8);
            postMap.put(WechatConstants.APP_ID, "wx98563d0ec9cf21c8");
            // 订单号
            postMap.put("out_bill_no", String.valueOf(UUID.randomUUID()).replaceAll("-", ""));
            System.err.println("====="+postMap.get("out_bill_no"));
            postMap.put(WechatConstants.OPEN_ID, openId);
            // 转账金额
            postMap.put("transfer_amount", transferAmount);
            postMap.put("transfer_scene_id", "1010");
            // 转账备注
            postMap.put("transfer_remark", "二手回收提现确认收款");
            // 回调地址
            postMap.put("notify_url", "https://hyhsbqgc.com/api/ruoyi-order/wx/wxChatPay");
            // 转账场景报备信息
            List<Map<String, Object>> list = new ArrayList<>();
            Map<String, Object> info = new HashMap<>();
            info.put("info_type","回收商品名称");
            info.put("info_content",serverName);
            list.add(info);
            postMap.put("transfer_scene_report_infos", list);
            String result = HttpUtil.postTransBatRequest(
                    WechatConstants.WE_CHAT_PAY_URL_PRE,
                    JSONObject.toJSONString(postMap),
                    "7EEA04429B006E12AAA421C002EC48BBEED5BE94",
                    "1665330417",
                    "/usr/local/vx/apiclient_key.pem", "/v3/fund-app/mch-transfer/transfer-bills");
            JSONObject jsonObject = JSONObject.parseObject(result);
//            WithdrawDetail withdrawDetail = new WithdrawDetail();
//            withdrawDetail.setWithdrawId(withdrawId);
//            withdrawDetail.setMoney(transferAmount);
//            withdrawDetail.setOutBatchNo((String) postMap.get(WechatConstants.OUT_BATCH_NO));
//            withdrawDetailService.save(withdrawDetail);
            System.err.println(jsonObject);
            if (jsonObject.containsKey(WechatConstants.CREATE_TIME)) {
                // 转账成功
                //保存转账明细
//                WithdrawDetail withdrawDetail = new WithdrawDetail();
//                withdrawDetail.setWithdrawId(withdrawId);
//                withdrawDetail.setMoney(transferAmount);
//                withdrawDetail.setOutBatchNo((String) postMap.get(WechatConstants.OUT_BATCH_NO));
//                withdrawDetailService.save(withdrawDetail);
            } else {
                allTransfersSuccessful = false;
                break;
            }
        }
        return allTransfersSuccessful;
    }
}
ruoyi-service/ruoyi-order/src/main/resources/mybatis-config.xml
@@ -5,7 +5,7 @@
    <settings>
        <!-- 打印查询语句 不会写入到日志文件中-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!--<setting name="logImpl" value="LOG4J" />-->
<!--        <setting name="logImpl" value="LOG4J" />-->
        <!-- 控制全局缓存(二级缓存),按美团技术团队的说法,尽量别用缓存机制 emmmm.... -->
        <setting name="cacheEnabled" value="true"/>
        <!-- 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。默认 false  -->
ruoyi-service/ruoyi-user/src/main/java/com/ruoyi/user/controller/RecoveryServeController.java
@@ -161,7 +161,9 @@
        UserRecipient userRecipient = userRecipientService.lambdaQuery()
                .eq(UserRecipient::getIsDefault, Constants.ONE)
                .eq(UserRecipient::getUserId, loginUser.getUserid())
                .eq(UserRecipient::getIsDelete, Constants.ZERO).one();
                .eq(UserRecipient::getIsDelete, Constants.ZERO)
                .last("limit 1")
                .one();
        return R.ok(new ServeDetailVO(recoveryServe, userRecipient));
    }
ruoyi-service/ruoyi-user/src/main/java/com/ruoyi/user/service/impl/WithdrawServiceImpl.java
@@ -82,6 +82,7 @@
            withdrawOrder.setCompleteTime(order.getCreateTime());
            withdrawOrder.setIsWithdrawal(order.getIsWithdrawal());
            withdrawOrder.setMoney(order.getOrderMoney());
            withdrawOrder.setPackageInfo(order.getPackageInfo());
            if (order.getAddress()!=null) {
                withdrawOrder.setAddress(order.getReservationAddress() + order.getAddress());
            }else {
ruoyi-service/ruoyi-user/src/main/java/com/ruoyi/user/vo/WithdrawOrderVO.java
@@ -44,5 +44,7 @@
    @ApiModelProperty("订单金额")
    private BigDecimal money;
    @ApiModelProperty("拉起确认收款页面参数")
    private String packageInfo;
}