提现等

This commit is contained in:
磷叶 2025-04-08 08:46:02 +08:00
parent fe2c97cfae
commit 2b513cdf11
23 changed files with 406 additions and 58 deletions

View File

@ -44,7 +44,7 @@ public class BankValidUtils {
try { try {
HttpResponse res = AliHttpUtils.doPost(host, path, method, headers, querys, bodys); HttpResponse res = AliHttpUtils.doPost(host, path, method, headers, querys, bodys);
BankValidResponseBody body = JSON.parseObject(EntityUtils.toString(res.getEntity()), BankValidResponseBody.class); BankValidResponseBody body = JSON.parseObject(EntityUtils.toString(res.getEntity()), BankValidResponseBody.class);
ServiceUtil.assertion(body == null, "调用三要素API失败返回值为空");
ServiceUtil.assertion(body.getErrorCode() != 0 || body.getResult() == null, "调用三要素API查询失败"); ServiceUtil.assertion(body.getErrorCode() != 0 || body.getResult() == null, "调用三要素API查询失败");
ServiceUtil.assertion(!Objects.equals(body.getResult().getRespCode(), "0"), body.getResult().getRespMsg()); ServiceUtil.assertion(!Objects.equals(body.getResult().getRespCode(), "0"), body.getResult().getRespMsg());

View File

@ -1,8 +1,12 @@
package com.ruoyi.bst.account.domain.enums; package com.ruoyi.bst.account.domain.enums;
import com.ruoyi.common.utils.collection.CollectionUtils;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import java.nio.charset.Charset;
import java.util.List;
/** /**
* @author wjh * @author wjh
* 2025/4/7 * 2025/4/7
@ -17,4 +21,14 @@ public enum AccountType {
private final String code; private final String code;
private final String name; private final String name;
// 离线列表
public static List<String> offline() {
return CollectionUtils.map(AccountType::getCode, BANK, QR);
}
// 在线列表
public static List<String> online() {
return CollectionUtils.map(AccountType::getCode, WX, ALI);
}
} }

View File

@ -21,6 +21,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
ba.bank_type, ba.bank_type,
ba.create_time, ba.create_time,
ba.deleted, ba.deleted,
su.nick_name as user_name,
su.is_real as user_is_real, su.is_real as user_is_real,
su.real_phone as user_real_phone, su.real_phone as user_real_phone,
su.real_id_card as user_real_id_card, su.real_id_card as user_real_id_card,

View File

@ -9,7 +9,8 @@ import lombok.Getter;
@AllArgsConstructor @AllArgsConstructor
public enum BalanceLogBstType { public enum BalanceLogBstType {
ORDER("ORDER", "订单"),; ORDER("ORDER", "订单"),
WITHDRAW("WITHDRAW", "提现");
private final String code; private final String code;
private final String name; private final String name;
@ -21,5 +22,5 @@ public enum BalanceLogBstType {
return null; return null;
} }
} }

View File

@ -13,8 +13,11 @@ public class BonusStatVO {
@ApiModelProperty("分成数量") @ApiModelProperty("分成数量")
private Integer count; private Integer count;
@ApiModelProperty("分成总金额") @ApiModelProperty("分成总金额")
private BigDecimal amount; private BigDecimal amount;
@ApiModelProperty("未入账金额")
private BigDecimal waitDivideAmount;
} }

View File

@ -144,4 +144,10 @@ public interface BonusMapper
*/ */
List<BonusDailyStatVO> selectDailyStat(@Param("query") BonusQuery query, @Param("keys") List<String> keys); List<BonusDailyStatVO> selectDailyStat(@Param("query") BonusQuery query, @Param("keys") List<String> keys);
/**
* 查询待分成金额
* @param query
* @return
*/
BigDecimal selectSumOfWaitAmount(@Param("query") BonusQuery query);
} }

View File

@ -334,4 +334,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
group by `date` group by `date`
</select> </select>
<select id="selectSumOfWaitAmount" resultType="java.math.BigDecimal">
select sum(bb.wait_amount)
from <include refid="searchTables"/>
<where>
<include refid="searchCondition"/>
</where>
</select>
</mapper> </mapper>

View File

@ -1,5 +1,6 @@
package com.ruoyi.bst.bonus.service.impl; package com.ruoyi.bst.bonus.service.impl;
import java.math.BigDecimal;
import java.util.List; import java.util.List;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -28,6 +29,9 @@ public class BonusDashboardImpl implements BonusDashboard {
if (keys.contains(StatKeys.BONUS_AMOUNT)) { if (keys.contains(StatKeys.BONUS_AMOUNT)) {
vo.setAmount(MathUtils.dv(bonusMapper.selectSumOfAmount(query))); vo.setAmount(MathUtils.dv(bonusMapper.selectSumOfAmount(query)));
} }
if (keys.contains(StatKeys.BONUS_WAIT_DIVIDE_AMOUNT)) {
vo.setWaitDivideAmount(MathUtils.dv(bonusMapper.selectSumOfWaitAmount(query)));
}
return vo; return vo;
} }
@ -35,5 +39,5 @@ public class BonusDashboardImpl implements BonusDashboard {
public List<BonusDailyStatVO> selectDailyStat(BonusQuery query, List<String> keys) { public List<BonusDailyStatVO> selectDailyStat(BonusQuery query, List<String> keys) {
return bonusMapper.selectDailyStat(query, keys); return bonusMapper.selectDailyStat(query, keys);
} }
} }

View File

@ -30,10 +30,17 @@ public class Withdraw extends BaseEntity
private Long id; private Long id;
@Excel(name = "提现单号")
private String no;
@Excel(name = "申请用户ID") @Excel(name = "申请用户ID")
@ApiModelProperty("申请用户ID") @ApiModelProperty("申请用户ID")
private Long userId; private Long userId;
@Excel(name = "提现状态")
@ApiModelProperty("提现状态")
private String status;
@Excel(name = "账户ID") @Excel(name = "账户ID")
@ApiModelProperty("账户ID") @ApiModelProperty("账户ID")
@NotBlank(message = "账户ID不允许为空", groups = {ValidGroup.Create.class}) @NotBlank(message = "账户ID不允许为空", groups = {ValidGroup.Create.class})
@ -41,27 +48,22 @@ public class Withdraw extends BaseEntity
@Excel(name = "账户类型") @Excel(name = "账户类型")
@ApiModelProperty("账户类型") @ApiModelProperty("账户类型")
@NotBlank(message = "账户类型不允许为空", groups = {ValidGroup.Create.class})
private String accountType; private String accountType;
@Excel(name = "账号") @Excel(name = "账号")
@ApiModelProperty("账号") @ApiModelProperty("账号")
@NotBlank(message = "账号不允许为空", groups = {ValidGroup.Create.class})
private String accountNo; private String accountNo;
@Excel(name = "账号姓名") @Excel(name = "账号姓名")
@ApiModelProperty("账号姓名") @ApiModelProperty("账号姓名")
@NotBlank(message = "账号姓名不允许为空", groups = {ValidGroup.Create.class})
private String accountName; private String accountName;
@Excel(name = "账户手机号") @Excel(name = "账户手机号")
@ApiModelProperty("账户手机号") @ApiModelProperty("账户手机号")
@NotBlank(message = "账户手机号不允许为空", groups = {ValidGroup.Create.class})
private String accountMobile; private String accountMobile;
@Excel(name = "账户身份证号") @Excel(name = "账户身份证号")
@ApiModelProperty("账户身份证号") @ApiModelProperty("账户身份证号")
@NotBlank(message = "账户身份证号不允许为空", groups = {ValidGroup.Create.class})
private String accountIdCard; private String accountIdCard;
@Excel(name = "银行名称") @Excel(name = "银行名称")

View File

@ -1,11 +1,17 @@
package com.ruoyi.bst.withdraw.domain; package com.ruoyi.bst.withdraw.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import java.util.List;
/** /**
* @author wjh * @author wjh
* 2025/4/7 * 2025/4/7
*/ */
@Data @Data
public class WithdrawQuery extends WithdrawVO { public class WithdrawQuery extends WithdrawVO {
@ApiModelProperty("状态列表")
private List<String> statusList;
} }

View File

@ -0,0 +1,33 @@
package com.ruoyi.bst.withdraw.domain.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
/**
* @author wjh
* 2025/4/7
*/
@Data
public class WithdrawVerifyDTO {
@ApiModelProperty("提现ID")
@NotNull(message = "提现ID不允许为空")
private Long id;
@ApiModelProperty("是否通过")
@NotNull(message = "是否通过不允许为空")
private Boolean pass;
@ApiModelProperty("审核意见")
@Size(max = 200, message = "审核意见不允许超过200个字符")
private String remark;
@ApiModelProperty("审核人ID")
private Long verifyId;
}

View File

@ -0,0 +1,29 @@
package com.ruoyi.bst.withdraw.domain.enums;
import com.ruoyi.common.utils.collection.CollectionUtils;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.List;
/**
* @author wjh
* 2025/4/7
*/
@Getter
@AllArgsConstructor
public enum WithdrawStatus {
WAIT_VERIFY("WAIT_VERIFY", "审核中"),
PAYING("PAYING", "打款中"),
SUCCESS("SUCCESS", "已打款"),
REJECTED("REJECTED", "驳回"),
FAILED("FAILED", "打款失败");
private final String code;
private final String name;
public static List<String> canVerify() {
return CollectionUtils.map(WithdrawStatus::getCode, WAIT_VERIFY);
}
}

View File

@ -15,9 +15,18 @@ public class WithdrawAmountVO {
@ApiModelProperty("服务费类型") @ApiModelProperty("服务费类型")
private String type; private String type;
@ApiModelProperty("服务费金额") @ApiModelProperty("到账金额")
private BigDecimal amount; private BigDecimal amount;
@ApiModelProperty("服务费金额")
private BigDecimal serviceCharge;
@ApiModelProperty("服务费比例") @ApiModelProperty("服务费比例")
private BigDecimal point; private BigDecimal point;
@ApiModelProperty("最低提现金额")
private BigDecimal minAmount;
@ApiModelProperty("最高提现金额")
private BigDecimal maxAmount;
} }

View File

@ -38,15 +38,6 @@ public interface WithdrawMapper
*/ */
int insertWithdraw(Withdraw withdraw); int insertWithdraw(Withdraw withdraw);
/**
* 批量新增提现
*/
int batchInsert(@Param("list") List<? extends Withdraw> list);
/**
* 批量修改提现
*/
int batchUpdate(@Param("list") List<? extends Withdraw> list);
/** /**
* 修改提现 * 修改提现
@ -71,4 +62,9 @@ public interface WithdrawMapper
* @return 结果 * @return 结果
*/ */
public int deleteWithdrawByIds(Long[] ids); public int deleteWithdrawByIds(Long[] ids);
/**
* 根据条件更新
*/
int updateByQuery(@Param("data") Withdraw data, @Param("query") WithdrawQuery query);
} }

View File

@ -28,6 +28,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
bw.service_point, bw.service_point,
bw.amount, bw.amount,
bw.arrival_amount, bw.arrival_amount,
bw.status,
bw.no,
su.nick_name as user_name, su.nick_name as user_name,
suv.nick_name as verify_user_name suv.nick_name as verify_user_name
from bst_withdraw bw from bst_withdraw bw
@ -40,7 +42,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="query.userId != null "> and bw.user_id = #{query.userId}</if> <if test="query.userId != null "> and bw.user_id = #{query.userId}</if>
<if test="query.accountId != null "> and bw.account_id = #{query.accountId}</if> <if test="query.accountId != null "> and bw.account_id = #{query.accountId}</if>
<if test="query.accountType != null and query.accountType != ''"> and bw.account_type = #{query.accountType}</if> <if test="query.accountType != null and query.accountType != ''"> and bw.account_type = #{query.accountType}</if>
<if test="query.status != null and query.status != ''"> and bw.status = #{query.status}</if>
<if test="query.accountNo != null and query.accountNo != ''"> and bw.account_no like concat('%', #{query.accountNo}, '%')</if> <if test="query.accountNo != null and query.accountNo != ''"> and bw.account_no like concat('%', #{query.accountNo}, '%')</if>
<if test="query.no != null and query.no != ''"> and bw.no like concat('%', #{query.no}, '%')</if>
<if test="query.accountName != null and query.accountName != ''"> and bw.account_name like concat('%', #{query.accountName}, '%')</if> <if test="query.accountName != null and query.accountName != ''"> and bw.account_name like concat('%', #{query.accountName}, '%')</if>
<if test="query.accountMobile != null and query.accountMobile != ''"> and bw.account_mobile like concat('%', #{query.accountMobile}, '%')</if> <if test="query.accountMobile != null and query.accountMobile != ''"> and bw.account_mobile like concat('%', #{query.accountMobile}, '%')</if>
<if test="query.accountIdCard != null and query.accountIdCard != ''"> and bw.account_id_card like concat('%', #{query.accountIdCard}, '%')</if> <if test="query.accountIdCard != null and query.accountIdCard != ''"> and bw.account_id_card like concat('%', #{query.accountIdCard}, '%')</if>
@ -52,6 +56,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="query.userName != null and query.userName != ''"> and su.nick_name like concat('%', #{query.userName}, '%')</if> <if test="query.userName != null and query.userName != ''"> and su.nick_name like concat('%', #{query.userName}, '%')</if>
<if test="query.verifyUserName != null and query.verifyUserName != ''"> and suv.nick_name like concat('%', #{query.verifyUserName}, '%')</if> <if test="query.verifyUserName != null and query.verifyUserName != ''"> and suv.nick_name like concat('%', #{query.verifyUserName}, '%')</if>
<if test="query.serviceType != null and query.serviceType != ''"> and bw.service_type = #{query.serviceType}</if> <if test="query.serviceType != null and query.serviceType != ''"> and bw.service_type = #{query.serviceType}</if>
<if test="query.statusList != null and query.statusList.size() > 0">
and bw.status in
<foreach collection="query.statusList" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</if>
${query.params.dataScope} ${query.params.dataScope}
</sql> </sql>
@ -89,6 +99,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="servicePoint != null">service_point,</if> <if test="servicePoint != null">service_point,</if>
<if test="amount != null">amount,</if> <if test="amount != null">amount,</if>
<if test="arrivalAmount != null">arrival_amount,</if> <if test="arrivalAmount != null">arrival_amount,</if>
<if test="status != null">status,</if>
<if test="no != null">no,</if>
</trim> </trim>
<trim prefix="values (" suffix=")" suffixOverrides=","> <trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="userId != null">#{userId},</if> <if test="userId != null">#{userId},</if>
@ -110,6 +122,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="servicePoint != null">#{servicePoint},</if> <if test="servicePoint != null">#{servicePoint},</if>
<if test="amount != null">#{amount},</if> <if test="amount != null">#{amount},</if>
<if test="arrivalAmount != null">#{arrivalAmount},</if> <if test="arrivalAmount != null">#{arrivalAmount},</if>
<if test="status != null">#{status},</if>
<if test="no != null">#{no},</if>
</trim> </trim>
</insert> </insert>
@ -121,6 +135,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where id = #{data.id} where id = #{data.id}
</update> </update>
<update id="updateByQuery">
update bst_withdraw bw
<trim prefix="SET" suffixOverrides=",">
<include refid="updateColumns"/>
</trim>
<where>
<include refid="searchCondition"/>
</where>
</update>
<sql id="updateColumns"> <sql id="updateColumns">
<if test="data.userId != null">user_id = #{data.userId},</if> <if test="data.userId != null">user_id = #{data.userId},</if>
<if test="data.accountId != null">account_id = #{data.accountId},</if> <if test="data.accountId != null">account_id = #{data.accountId},</if>
@ -141,6 +165,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="data.servicePoint != null">service_point = #{data.servicePoint},</if> <if test="data.servicePoint != null">service_point = #{data.servicePoint},</if>
<if test="data.amount != null">amount = #{data.amount},</if> <if test="data.amount != null">amount = #{data.amount},</if>
<if test="data.arrivalAmount != null">arrival_amount = #{data.arrivalAmount},</if> <if test="data.arrivalAmount != null">arrival_amount = #{data.arrivalAmount},</if>
<if test="data.status != null">status = #{data.status},</if>
<if test="data.no != null">no = #{data.no},</if>
</sql> </sql>
<delete id="deleteWithdrawById" parameterType="Long"> <delete id="deleteWithdrawById" parameterType="Long">

View File

@ -0,0 +1,16 @@
package com.ruoyi.bst.withdraw.service;
import com.ruoyi.bst.withdraw.domain.vo.WithdrawAmountVO;
import com.ruoyi.common.core.domain.vo.UserVO;
import lombok.Data;
import java.math.BigDecimal;
/**
* @author wjh
* 2025/4/7
*/
public interface WithdrawConverter {
WithdrawAmountVO calcAmount(UserVO user, BigDecimal amount);
}

View File

@ -4,6 +4,7 @@ import java.util.List;
import com.ruoyi.bst.withdraw.domain.Withdraw; import com.ruoyi.bst.withdraw.domain.Withdraw;
import com.ruoyi.bst.withdraw.domain.WithdrawVO; import com.ruoyi.bst.withdraw.domain.WithdrawVO;
import com.ruoyi.bst.withdraw.domain.WithdrawQuery; import com.ruoyi.bst.withdraw.domain.WithdrawQuery;
import com.ruoyi.bst.withdraw.domain.dto.WithdrawVerifyDTO;
/** /**
* 提现Service接口 * 提现Service接口
@ -60,4 +61,9 @@ public interface WithdrawService
* @return 结果 * @return 结果
*/ */
public int deleteWithdrawById(Long id); public int deleteWithdrawById(Long id);
/**
* 提现审核
*/
int verify(WithdrawVerifyDTO dto);
} }

View File

@ -0,0 +1,65 @@
package com.ruoyi.bst.withdraw.service.impl;
import com.ruoyi.bst.withdraw.domain.enums.WithdrawServiceType;
import com.ruoyi.bst.withdraw.domain.vo.WithdrawAmountVO;
import com.ruoyi.bst.withdraw.service.WithdrawConverter;
import com.ruoyi.common.constants.ConfigKeys;
import com.ruoyi.common.core.domain.vo.UserVO;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.MathUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.system.config.service.ConfigService;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
/**
* @author wjh
* 2025/4/7
*/
@Service
public class WithdrawConverterImpl implements WithdrawConverter {
@Autowired
private ConfigService configService;
/**
* 查询提现服务费
*/
@Override
public WithdrawAmountVO calcAmount(UserVO user, BigDecimal amount) {
if (user == null || amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
return null;
}
String type = user.getWithdrawServiceType();
BigDecimal value = user.getWithdrawServiceValue();
ServiceUtil.assertion(StringUtils.isBlank(type), "提现服务费方式为空");
ServiceUtil.assertion(value == null, "提现服务费为空");
BigDecimal minAmount = configService.getDecimal(ConfigKeys.WITHDRAW_MIN_AMOUNT);
BigDecimal maxAmount = configService.getDecimal(ConfigKeys.WITHDRAW_MAX_AMOUNT);
WithdrawAmountVO vo = new WithdrawAmountVO();
vo.setType(type);
vo.setMinAmount(minAmount);
vo.setMaxAmount(maxAmount);
if (WithdrawServiceType.POINT.getCode().equals(type)) {
vo.setPoint(value);
BigDecimal serviceChange = value.multiply(amount).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
vo.setServiceCharge(serviceChange);
} else if(WithdrawServiceType.FIXED.getCode().equals(type)) {
vo.setServiceCharge(value);
} else {
throw new ServiceException("暂不支持类型为" + type + "的提现服务费方式");
}
vo.setAmount(MathUtils.subtractDecimal(amount, vo.getServiceCharge()));
return vo;
}
}

View File

@ -1,7 +1,25 @@
package com.ruoyi.bst.withdraw.service.impl; package com.ruoyi.bst.withdraw.service.impl;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Objects;
import com.ruoyi.bst.account.domain.AccountVO;
import com.ruoyi.bst.account.domain.enums.AccountType;
import com.ruoyi.bst.account.service.AccountService;
import com.ruoyi.bst.balanceLog.domain.enums.BalanceLogBstType;
import com.ruoyi.bst.withdraw.domain.dto.WithdrawVerifyDTO;
import com.ruoyi.bst.withdraw.domain.enums.WithdrawStatus;
import com.ruoyi.bst.withdraw.domain.vo.WithdrawAmountVO;
import com.ruoyi.bst.withdraw.service.WithdrawConverter;
import com.ruoyi.bst.withdraw.utils.WithdrawUtil;
import com.ruoyi.common.core.domain.vo.UserVO;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.MathUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.SnowFlakeUtil;
import com.ruoyi.system.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.ruoyi.bst.withdraw.mapper.WithdrawMapper; import com.ruoyi.bst.withdraw.mapper.WithdrawMapper;
@ -9,6 +27,7 @@ import com.ruoyi.bst.withdraw.domain.Withdraw;
import com.ruoyi.bst.withdraw.domain.WithdrawVO; import com.ruoyi.bst.withdraw.domain.WithdrawVO;
import com.ruoyi.bst.withdraw.domain.WithdrawQuery; import com.ruoyi.bst.withdraw.domain.WithdrawQuery;
import com.ruoyi.bst.withdraw.service.WithdrawService; import com.ruoyi.bst.withdraw.service.WithdrawService;
import org.springframework.transaction.support.TransactionTemplate;
/** /**
* 提现Service业务层处理 * 提现Service业务层处理
@ -22,6 +41,17 @@ public class WithdrawServiceImpl implements WithdrawService
@Autowired @Autowired
private WithdrawMapper withdrawMapper; private WithdrawMapper withdrawMapper;
@Autowired
private UserService userService;
@Autowired
private WithdrawConverter withdrawConverter;
@Autowired
private AccountService accountService;
@Autowired
private TransactionTemplate transactionTemplate;
/** /**
* 查询提现 * 查询提现
* *
@ -53,10 +83,59 @@ public class WithdrawServiceImpl implements WithdrawService
* @return 结果 * @return 结果
*/ */
@Override @Override
public int insertWithdraw(Withdraw withdraw) public int insertWithdraw(Withdraw withdraw) {
{ // 获取用户信息
withdraw.setCreateTime(DateUtils.getNowDate()); UserVO user = userService.selectUserById(withdraw.getUserId());
return withdrawMapper.insertWithdraw(withdraw); ServiceUtil.assertion(user == null, "ID为%s的用户不存在", withdraw.getUserId());
// 获取账户信息
AccountVO account = accountService.selectAccountById(withdraw.getAccountId());
ServiceUtil.assertion(account == null, "ID为%s的收款账户不存在", withdraw.getAccountId());
// 获取金额
WithdrawAmountVO amountVo = withdrawConverter.calcAmount(user, withdraw.getAmount());
ServiceUtil.assertion(amountVo == null, "计算金额出错");
// 校验金额
ServiceUtil.assertion(!MathUtils.equals(amountVo.getServiceCharge(), withdraw.getServiceCharge()), "服务费金额发生变化,请刷新后重试");
ServiceUtil.assertion(!MathUtils.equals(amountVo.getAmount(), withdraw.getArrivalAmount()), "到账金额发生变化,请刷新后重试");
ServiceUtil.assertion(MathUtils.smallerThan(withdraw.getAmount(), amountVo.getMinAmount()), "提现金额不允许小于最低金额:%s", amountVo.getMinAmount());
ServiceUtil.assertion(MathUtils.biggerThan(withdraw.getAmount(), amountVo.getMaxAmount()), "提现金额不允许大于最高金额:%s", amountVo.getMaxAmount());
// 组装提现数据
Withdraw data = new Withdraw();
// 基础
data.setUserId(withdraw.getUserId());
data.setCreateTime(DateUtils.getNowDate());
data.setNo(String.valueOf(SnowFlakeUtil.newId()));
data.setStatus(WithdrawStatus.WAIT_VERIFY.getCode());
// 账户
data.setAccountId(withdraw.getAccountId());
data.setAccountType(account.getType());
data.setAccountNo(account.getNo());
data.setAccountName(account.getName());
data.setAccountMobile(account.getMobile());
data.setAccountIdCard(account.getIdCard());
data.setBankName(account.getBankName());
data.setBankCardName(account.getBankCardName());
data.setBankType(account.getBankType());
// 金额
data.setServiceType(amountVo.getType());
data.setServiceCharge(amountVo.getServiceCharge());
data.setServicePoint(amountVo.getPoint());
data.setAmount(withdraw.getAmount());
data.setArrivalAmount(amountVo.getAmount());
Integer result = transactionTemplate.execute(status -> {
int rows = withdrawMapper.insertWithdraw(data);
if (rows > 0) {
// 扣减用户余额
int sub = userService.subtractBalance(data.getUserId(), data.getAmount(), BalanceLogBstType.WITHDRAW, data.getId(), "提现申请:" + data.getNo(), true);
ServiceUtil.assertion(sub != 1, "扣减用户余额失败,请检查余额是否充足");
}
return rows;
});
return result == null ? 0 : result;
} }
/** /**
@ -94,4 +173,55 @@ public class WithdrawServiceImpl implements WithdrawService
{ {
return withdrawMapper.deleteWithdrawById(id); return withdrawMapper.deleteWithdrawById(id);
} }
@Override
public int verify(WithdrawVerifyDTO dto) {
WithdrawVO withdraw = selectWithdrawById(dto.getId());
ServiceUtil.assertion(withdraw == null, "待审核的提现不存在");
ServiceUtil.assertion(!WithdrawStatus.canVerify().contains(withdraw.getStatus()), "ID为%s的提现当前状态不允许审核", dto.getId());
boolean pass = dto.getPass() != null && dto.getPass();
Integer result = transactionTemplate.execute(status -> {
Withdraw data = new Withdraw();
if (pass) {
if (AccountType.offline().contains(withdraw.getAccountType())) {
data.setStatus(WithdrawStatus.SUCCESS.getCode());
} else {
data.setStatus(WithdrawStatus.PAYING.getCode());
}
} else {
data.setStatus(WithdrawStatus.REJECTED.getCode());
}
data.setVerifyUserId(dto.getVerifyId());
data.setVerifyTime(LocalDateTime.now());
data.setVerifyRemark(dto.getRemark());
WithdrawQuery query = new WithdrawQuery();
query.setId(dto.getId());
query.setStatusList(WithdrawStatus.canVerify());
int rows = withdrawMapper.updateByQuery(data, query);
if (rows > 0 ) {
if (WithdrawStatus.PAYING.getCode().equals(data.getStatus())) {
// TODO 支付中线上提现打款
throw new ServiceException("暂未开通线上提现打款");
} else if (WithdrawStatus.REJECTED.getCode().equals(data.getStatus())) {
// 驳回恢复用户余额
int add = userService.addBalance(
withdraw.getUserId(),
withdraw.getAmount(),
BalanceLogBstType.WITHDRAW,
withdraw.getId(),
"提现驳回:" + withdraw.getNo()
);
ServiceUtil.assertion(add != 1, "恢复用户余额失败");
}
}
return rows;
});
return result == null ? 0 : result;
}
} }

View File

@ -16,34 +16,4 @@ import java.math.BigDecimal;
*/ */
public class WithdrawUtil { public class WithdrawUtil {
/**
* 查询提现服务费
*/
public static WithdrawAmountVO calcAmount(UserVO user, BigDecimal amount) {
if (user == null || amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
return null;
}
String type = user.getWithdrawServiceType();
BigDecimal value = user.getWithdrawServiceValue();
ServiceUtil.assertion(StringUtils.isBlank(type), "提现服务费方式为空");
ServiceUtil.assertion(value == null, "提现服务费为空");
WithdrawAmountVO vo = new WithdrawAmountVO();
vo.setType(type);
if (WithdrawServiceType.POINT.getCode().equals(type)) {
vo.setPoint(value);
BigDecimal serviceAmount = value.multiply(amount).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
vo.setAmount(serviceAmount);
} else if(WithdrawServiceType.FIXED.getCode().equals(type)) {
vo.setAmount(value);
} else {
throw new ServiceException("暂不支持类型为" + type + "的提现服务费方式");
}
return vo;
}
} }

View File

@ -10,4 +10,8 @@ public class ConfigKeys {
public static final String USER_DEFAULT_WITHDRAW_SERVICE_TYPE = "user.default.withdraw.service.type"; public static final String USER_DEFAULT_WITHDRAW_SERVICE_TYPE = "user.default.withdraw.service.type";
// 用户默认服务费值 // 用户默认服务费值
public static final String USER_DEFAULT_WITHDRAW_SERVICE_VALUE = "user.default.withdraw.service.value"; public static final String USER_DEFAULT_WITHDRAW_SERVICE_VALUE = "user.default.withdraw.service.value";
// 最低提现金额
public static final String WITHDRAW_MIN_AMOUNT = "withdraw.min.amount";
// 最高提现金额
public static final String WITHDRAW_MAX_AMOUNT = "withdraw.max.amount";
} }

View File

@ -13,7 +13,7 @@ public class StatKeys {
public static final String ORDER_COUNT = "order_count"; public static final String ORDER_COUNT = "order_count";
// 订单支付金额 // 订单支付金额
public static final String ORDER_PAY_AMOUNT = "order_pay_amount"; public static final String ORDER_PAY_AMOUNT = "order_pay_amount";
// 订单退款金额 // 订单退款金额
public static final String ORDER_REFUND_AMOUNT = "order_refund_amount"; public static final String ORDER_REFUND_AMOUNT = "order_refund_amount";
// 分成数量 // 分成数量
@ -22,6 +22,8 @@ public class StatKeys {
public static final String BONUS_AMOUNT = "bonus_amount"; public static final String BONUS_AMOUNT = "bonus_amount";
// 分成总退款 // 分成总退款
public static final String BONUS_REFUND_AMOUNT = "bonus_refund_amount"; public static final String BONUS_REFUND_AMOUNT = "bonus_refund_amount";
// 分成未入账金额
public static final String BONUS_WAIT_DIVIDE_AMOUNT = "bonus_wait_divide_amount";
// 用户数量 // 用户数量
public static final String USER_COUNT = "user_count"; public static final String USER_COUNT = "user_count";

View File

@ -4,6 +4,8 @@ import java.math.BigDecimal;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import com.ruoyi.bst.withdraw.domain.dto.WithdrawVerifyDTO;
import com.ruoyi.bst.withdraw.service.WithdrawConverter;
import com.ruoyi.bst.withdraw.utils.WithdrawUtil; import com.ruoyi.bst.withdraw.utils.WithdrawUtil;
import com.ruoyi.common.core.domain.vo.UserVO; import com.ruoyi.common.core.domain.vo.UserVO;
import com.ruoyi.system.user.service.UserService; import com.ruoyi.system.user.service.UserService;
@ -38,6 +40,9 @@ public class WithdrawController extends BaseController
@Autowired @Autowired
private UserService userService; private UserService userService;
@Autowired
private WithdrawConverter withdrawConverter;
/** /**
* 查询提现列表 * 查询提现列表
*/ */
@ -78,9 +83,13 @@ public class WithdrawController extends BaseController
* 申请提现 * 申请提现
*/ */
@PreAuthorize("@ss.hasPermi('bst:withdraw:add')") @PreAuthorize("@ss.hasPermi('bst:withdraw:add')")
@Log(title = "提现", businessType = BusinessType.INSERT) @Log(title = "申请提现", businessType = BusinessType.INSERT)
@PostMapping @PostMapping
public AjaxResult add(@RequestBody @Validated Withdraw withdraw) { public AjaxResult add(@RequestBody @Validated Withdraw withdraw) {
// 若是不是系统管理员则无权给他人提现
if (!isSysAdmin() || withdraw.getUserId() == null) {
withdraw.setUserId(getUserId());
}
return toAjax(withdrawService.insertWithdraw(withdraw)); return toAjax(withdrawService.insertWithdraw(withdraw));
} }
@ -93,7 +102,15 @@ public class WithdrawController extends BaseController
userId = getUserId(); userId = getUserId();
} }
UserVO user = userService.selectUserById(userId); UserVO user = userService.selectUserById(userId);
return success(WithdrawUtil.calcAmount(user, amount)); return success(withdrawConverter.calcAmount(user, amount));
}
@PreAuthorize("@ss.hasPermi('bst:withdraw:verify')")
@Log(title = "提现审核", businessType = BusinessType.VERIFY)
@PutMapping("/verify")
public AjaxResult verify(@RequestBody @Validated WithdrawVerifyDTO dto) {
dto.setVerifyId(getUserId());
return toAjax(withdrawService.verify(dto));
} }
} }