guomengjiao месяцев назад: 4
Родитель
Сommit
305c13b45e

+ 14 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/shop/withdrawal/WithdrawalController.java

@@ -3,6 +3,7 @@ package com.ruoyi.web.controller.shop.withdrawal;
 import cn.dev33.satoken.annotation.SaCheckPermission;
 import cn.hutool.json.JSONArray;
 import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.annotation.RepeatSubmit;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.PageQuery;
 import com.ruoyi.common.core.domain.R;
@@ -101,4 +102,17 @@ public class WithdrawalController extends BaseController {
         ExcelUtil.exportExcel(list, "提现", WithdrawalVo.class, response);
     }
 
+    /**
+     * 审核提现
+     */
+    @ApiOperation("审核提现")
+    @SaCheckPermission("withdrawal:withdrawal:audit")
+    @Log(title = "提现", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PostMapping("/audit")
+    public R<Void> audit(@Validated @RequestBody WithdrawalBo bo) {
+        bo.setAuditUserId(getUserId());
+        return toAjax(iWithdrawalService.audit(bo));
+    }
+
 }

+ 1 - 0
ruoyi-api/src/main/java/com/ruoyi/api/controller/shop/ApiSaleRightsOrderController.java

@@ -68,6 +68,7 @@ public class ApiSaleRightsOrderController extends AbstractApiController {
     @GetMapping("/page")
     public TableDataInfo<SaleRightsOrderVo> page(@Validated(QueryGroup.class) SaleRightsOrderBo bo, PageQuery pageQuery) {
         bo.setUserId(getUserId(true));
+        bo.setOrderType(OrderType.NORMAL);
         return iSaleRightsOrderService.queryPageList(bo, pageQuery);
     }
 

+ 4 - 0
ruoyi-shop/src/main/java/com/ruoyi/shop/withdrawal/domain/Withdrawal.java

@@ -86,4 +86,8 @@ public class Withdrawal extends BaseTimeEntity {
      */
     private String auditResult;
 
+    /**
+     * 第三方单号
+     */
+    private String thirdOrderId;
 }

+ 7 - 1
ruoyi-shop/src/main/java/com/ruoyi/shop/withdrawal/exception/WithdrawalExceptionEnum.java

@@ -13,7 +13,13 @@ public enum WithdrawalExceptionEnum implements IIntegerEnum {
     Withdrawal_IS_NOT_EXISTS(490001, "提现不存在"),
     WITHDRAWAL_AMOUNT_NOT_ENOUGH(490002, "提现金额不足"),
     WITHDRAWAL_AMOUNT_TOO_MUCH(490003, "提现金额超出最大限制"),
-    WITHDRAWAL_FEE_NOT_MATCH(490004, "提现手续费不匹配");
+    WITHDRAWAL_FEE_NOT_MATCH(490004, "提现手续费不匹配"),
+    WITHDRAWAL_STATUS_NOT_WAIT_AUDIT(490005, "提现状态不是待审核"),
+    WITHDRAWAL_AUDIT_STATUS_NOT_SUPPORT(490006, "提现审核状态错误"),
+    WITHDRAWAL_AUDIT_RESULT_NOT_EMPTY(490007, "提现审核结果不能为空"),
+    WITHDRAWAL_STATUS_SUCCESS(490008, "提现已到账 无法重复操作!"),
+    WITHDRAWAL_THIRD_ORDER_ID_EMPTY(490009, "第三方提现失败"),
+    ;
 
     private Integer code;
 

+ 5 - 3
ruoyi-shop/src/main/java/com/ruoyi/shop/withdrawal/service/IWithdrawalService.java

@@ -1,11 +1,11 @@
 package com.ruoyi.shop.withdrawal.service;
 
+import com.ruoyi.common.core.domain.PageQuery;
+import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.shop.withdrawal.domain.Withdrawal;
+import com.ruoyi.shop.withdrawal.domain.bo.WithdrawalBo;
 import com.ruoyi.shop.withdrawal.domain.vo.WithdrawalAmountVo;
 import com.ruoyi.shop.withdrawal.domain.vo.WithdrawalVo;
-import com.ruoyi.shop.withdrawal.domain.bo.WithdrawalBo;
-import com.ruoyi.common.core.page.TableDataInfo;
-import com.ruoyi.common.core.domain.PageQuery;
 import com.ruoyi.shop.withdrawal.enums.WithdrawalSource;
 
 import java.math.BigDecimal;
@@ -92,4 +92,6 @@ public interface IWithdrawalService {
     List<WithdrawalVo> queryWithdrawaList(WithdrawalBo bo);
 
     WithdrawalVo statistics(WithdrawalBo bo);
+
+    Boolean audit(WithdrawalBo bo);
 }

+ 125 - 1
ruoyi-shop/src/main/java/com/ruoyi/shop/withdrawal/service/impl/WithdrawalServiceImpl.java

@@ -4,10 +4,17 @@ import cn.dev33.satoken.secure.BCrypt;
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.ObjectUtil;
+import com.alipay.api.AlipayClient;
+import com.alipay.api.DefaultAlipayClient;
+import com.alipay.api.domain.AlipayFundTransUniTransferModel;
+import com.alipay.api.domain.Participant;
+import com.alipay.api.request.AlipayFundTransUniTransferRequest;
+import com.alipay.api.response.AlipayFundTransUniTransferResponse;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ruoyi.agent.domain.Agent;
+import com.ruoyi.agent.domain.bo.AgentChangeBalanceBo;
 import com.ruoyi.agent.service.IAgentService;
 import com.ruoyi.base.revenue.domain.vo.RevenueSharingConfigVo;
 import com.ruoyi.base.revenue.service.IRevenueSharingConfigService;
@@ -15,6 +22,7 @@ import com.ruoyi.common.core.domain.PageQuery;
 import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.common.enums.AuditStatus;
 import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.properties.AlipayProperties;
 import com.ruoyi.common.utils.BeanCopyUtils;
 import com.ruoyi.common.utils.MathUtils;
 import com.ruoyi.common.utils.StringUtils;
@@ -30,12 +38,19 @@ import com.ruoyi.shop.withdrawal.service.IWithdrawalService;
 import com.ruoyi.system.enums.SequencePrefixEnum;
 import com.ruoyi.system.service.ISysSequenceService;
 import com.ruoyi.user.domain.User;
+import com.ruoyi.user.domain.bo.UserChangeBalanceBo;
+import com.ruoyi.user.enums.BalanceSourceType;
 import com.ruoyi.user.service.IUserService;
 import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
-import java.util.*;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
 
 /**
  * 提现Service业务层处理
@@ -43,6 +58,7 @@ import java.util.*;
  * @author ruoyi
  * @date 2025-12-04
  */
+@Slf4j
 @RequiredArgsConstructor
 @Service
 public class WithdrawalServiceImpl implements IWithdrawalService {
@@ -52,6 +68,7 @@ public class WithdrawalServiceImpl implements IWithdrawalService {
     private final IAgentService agentService;
     private final IRevenueSharingConfigService revenueSharingConfigService;
     private final ISysSequenceService sysSequenceService;
+    private final AlipayProperties aliPayConfig;
 
     /**
      * 查询提现分页
@@ -266,4 +283,111 @@ public class WithdrawalServiceImpl implements IWithdrawalService {
         return baseMapper.statistics(bo);
     }
 
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public Boolean audit(WithdrawalBo bo) {
+        Withdrawal withdrawal = loadLockById(bo.getId());
+        if (!AuditStatus.WAIT_AUDIT.equals(withdrawal.getAuditStatus())) {
+            throw new ServiceException(WithdrawalExceptionEnum.WITHDRAWAL_STATUS_NOT_WAIT_AUDIT);
+        }
+        if (WithdrawalStatus.SUCCESS.equals(withdrawal.getStatus())) {
+            throw new ServiceException(WithdrawalExceptionEnum.WITHDRAWAL_STATUS_SUCCESS);
+        }
+        if (AuditStatus.AUDIT_PASS.equals(bo.getAuditStatus())) {
+            BigDecimal amount = withdrawal.getAmount();
+            WithdrawalAmountVo amountVo = amount(withdrawal.getWithdrawalSourceId(), withdrawal.getWithdrawalSource());
+            if (amountVo.getAbleAmount().compareTo(amount) < 0) {
+                throw new ServiceException(WithdrawalExceptionEnum.WITHDRAWAL_AMOUNT_NOT_ENOUGH);
+            }
+            BigDecimal paymentAmount = amount.subtract(withdrawal.getFee());
+            //调用支付宝 转账
+            String thirdOrderId = alipayFundTrans(withdrawal.getWithdrawalNo(), paymentAmount, "平台提现", withdrawal.getAccountInfo());
+            if (StringUtils.isEmpty(thirdOrderId)) {
+                throw new ServiceException(WithdrawalExceptionEnum.WITHDRAWAL_THIRD_ORDER_ID_EMPTY);
+            }
+            withdrawal.setThirdOrderId(thirdOrderId);
+            //扣减钱包
+            if (WithdrawalSource.USER.equals(withdrawal.getWithdrawalSource())) {
+                userService.changeUserBalance(UserChangeBalanceBo.builder()
+                    .userId(withdrawal.getWithdrawalSourceId())
+                    .entryValue(amount)
+                    .isAdd(false)
+                    .sourceType(BalanceSourceType.WITHDRAWAL)
+                    .sourceId(withdrawal.getId())
+                    .sourceCode(withdrawal.getWithdrawalNo())
+                    .remark("提现扣减")
+                    .build());
+            } else if (WithdrawalSource.AGENT.equals(withdrawal.getWithdrawalSource())) {
+                agentService.changeAgentBalance(AgentChangeBalanceBo.builder()
+                    .agentId(withdrawal.getWithdrawalSourceId())
+                    .entryValue(amount)
+                    .isAdd(false)
+                    .sourceType(com.ruoyi.agent.enums.BalanceSourceType.WITHDRAW)
+                    .sourceId(withdrawal.getId())
+                    .sourceCode(withdrawal.getWithdrawalNo())
+                    .remark("提现扣减")
+                    .build());
+            }
+            withdrawal.setStatus(WithdrawalStatus.SUCCESS);
+            withdrawal.setPaymentAmount(paymentAmount);
+            withdrawal.setPaymentTime(new Date());
+        } else if (AuditStatus.AUDIT_NOT_PASS.equals(bo.getAuditStatus())) {
+            if (StringUtils.isEmpty(bo.getAuditResult())) {
+                throw new ServiceException(WithdrawalExceptionEnum.WITHDRAWAL_AUDIT_RESULT_NOT_EMPTY);
+            }
+            withdrawal.setStatus(WithdrawalStatus.FAIL);
+        } else {
+            throw new ServiceException(WithdrawalExceptionEnum.WITHDRAWAL_AUDIT_STATUS_NOT_SUPPORT);
+        }
+        withdrawal.setAuditStatus(bo.getAuditStatus());
+        withdrawal.setAuditTime(new Date());
+        withdrawal.setAuditUserId(bo.getAuditUserId());
+        withdrawal.setAuditResult(bo.getAuditResult());
+        return baseMapper.updateById(withdrawal) > 0;
+    }
+
+    private String alipayFundTrans(String withdrawalNo, BigDecimal amount, String title, String identity) {
+        try {
+            AlipayClient alipayClient = new DefaultAlipayClient(aliPayConfig.getServerUrl(), // 支付宝网关(固定)
+                aliPayConfig.getAppId(), // APPID 即创建应用后生成
+                aliPayConfig.getAppPrivateKey(), // 开发者私钥,由开发者自己生成
+                aliPayConfig.getFormat(), // 参数返回格式,只支持json
+                aliPayConfig.getCharset(), // 编码集,支持GBK/UTF-8
+                aliPayConfig.getAlipayPublicKey(), // 支付宝公钥,由支付宝生成
+                aliPayConfig.getSignType()); // 商户生成签名字符串所使用的签名算法类型,目前支持RSA2和RSA,推荐使用RSA2
+            // 构造请求参数以调用接口
+            AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
+            AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel();
+            // 设置商家侧唯一订单号
+            model.setOutBizNo(withdrawalNo);
+            // 设置订单总金额
+            model.setTransAmount(amount.toString());
+            // 设置描述特定的业务场景
+            model.setBizScene("DIRECT_TRANSFER");
+            // 设置业务产品码
+            model.setProductCode("TRANS_ACCOUNT_NO_PWD");
+            // 设置转账业务的标题
+            model.setOrderTitle(title);
+            // 设置收款方信息
+            Participant payeeInfo = new Participant();
+            payeeInfo.setIdentity(identity);
+            payeeInfo.setIdentityType("ALIPAY_LOGON_ID");
+            model.setPayeeInfo(payeeInfo);
+            request.setBizModel(model);
+            AlipayFundTransUniTransferResponse response = alipayClient.certificateExecute(request);
+            if (response.isSuccess() && "SUCCESS".equals(response.getStatus())) {
+                return response.getOrderId();
+            } else {
+                log.info("支付宝转账失败{},{}", response.getMsg(), response.getSubMsg());
+            }
+        } catch (Exception e) {
+            log.error("支付宝转账异常", e);
+        }
+        return null;
+    }
+
+    private Withdrawal loadLockById(Long id) {
+        return baseMapper.selectOne(new LambdaQueryWrapper<Withdrawal>().eq(Withdrawal::getId, id).last("limit 1 for update"));
+    }
+
 }

+ 1 - 0
ruoyi-shop/src/main/resources/mapper/withdrawal/WithdrawalMapper.xml

@@ -22,6 +22,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="auditResult" column="audit_result"/>
         <result property="createTime" column="create_time"/>
         <result property="updateTime" column="update_time"/>
+        <result property="thirdOrderId" column="third_order_id"/>
     </resultMap>
 
     <select id="withdrawing" resultType="java.math.BigDecimal">

+ 2 - 1
ruoyi-user/src/main/java/com/ruoyi/user/enums/BalanceSourceType.java

@@ -19,7 +19,8 @@ public enum BalanceSourceType implements IIntegerEnum {
     SUBSIDY(4, "消费排队补贴"),
     SHARED_SUBSIDY(5, "消费排队均摊补贴"),
     ONLINE_ORDER_REFUND_DEDUCT(6, "在线订单退款扣除补贴"),
-    SUBSIDY_OVERFLOW_RETURN(7, "消费排队均摊补贴溢出退回")
+    SUBSIDY_OVERFLOW_RETURN(7, "消费排队均摊补贴溢出退回"),
+    WITHDRAWAL(8, "提现"),
     ;
 
     @EnumValue