[fix]充值与提现

This commit is contained in:
王庆祥 2025-06-23 10:42:02 +08:00
parent ca99f31ebd
commit e2ef255d8f
16 changed files with 347 additions and 7 deletions

View File

@ -1,5 +1,7 @@
package org.dromara.common.core.domain.model;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.time.LocalDateTime;
@ -14,6 +16,10 @@ public class BaseAudit {
/**
* 创建时间
*/
/**
* 创建部门
*/
@TableField(fill = FieldFill.INSERT)
// @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
@ -25,6 +31,7 @@ public class BaseAudit {
/**
* 更新时间
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
// @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
}

View File

@ -5,6 +5,7 @@ import cn.hutool.http.HttpStatus;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.dromara.common.core.domain.model.BaseAudit;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.ObjectUtils;
@ -48,7 +49,11 @@ public class InjectionMetaObjectHandler implements MetaObjectHandler {
baseEntity.setCreateDept(ObjectUtils.notNull(baseEntity.getCreateDept(), loginUser.getDeptId()));
}
}
} else {
} else if(ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseAudit baseAudit) {
baseAudit.setCreateTime(LocalDateTime.now());
baseAudit.setUpdateTime(LocalDateTime.now());
}else{
Date date = new Date();
this.strictInsertFill(metaObject, "createTime", Date.class, date);
this.strictInsertFill(metaObject, "updateTime", Date.class, date);
@ -75,6 +80,8 @@ public class InjectionMetaObjectHandler implements MetaObjectHandler {
if (ObjectUtil.isNotNull(userId)) {
baseEntity.setUpdateBy(userId);
}
} else if(ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseAudit baseAudit) {
baseAudit.setUpdateTime(LocalDateTime.now());
} else {
this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
}

View File

@ -54,12 +54,11 @@ public class WithdrawController {
return R.ok(convert.toVO(service.getById(id)));
}
@Tag(name = ("处理"))
@Log(title = "修改", businessType = BusinessType.UPDATE)
@Tag(name = ("审批"))
@Log(title = "审批", businessType = BusinessType.UPDATE)
@PostMapping("/update")
public R update(@RequestBody WithdrawBO bo) {
service.save(convert.toPo(bo));
return R.ok();
return R.ok(service.audit(bo));
}

View File

@ -96,6 +96,12 @@ public class WithdrawBO extends BaseBO<Withdraw> {
@Schema(description ="审核状态")
private Integer auditStatus;
/**
* 审核原因
*/
@Schema(description ="审核原因")
private String auditReason;
@Override
public LambdaQueryWrapper<Withdraw> toWrapper() {
return super.toWrapper().eq(id!=null, Withdraw::getId, id)

View File

@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;
import org.dromara.common.core.domain.model.BaseAudit;
import org.dromara.common.excel.annotation.Excel;
@ -18,6 +19,7 @@ import java.math.BigDecimal;
@Schema(description="会员账户变动记录")
@Data
@TableName("ums_account_change_record")
@Builder(toBuilder = true)
public class MemberAccountChangeRecord extends BaseAudit {
@Schema(description ="主键")

View File

@ -1,9 +1,12 @@
package com.wzj.soopin.member.domain.po;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;
import org.dromara.common.core.domain.model.BaseAudit;
@ -19,6 +22,7 @@ import java.time.LocalDateTime;
@Schema(description="提现")
@Data
@TableName("ums_withdraw")
@Builder(toBuilder = true)
public class Withdraw extends BaseAudit {
/**
@ -69,6 +73,7 @@ public class Withdraw extends BaseAudit {
/**
* 审核时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime auditTime;
/**
@ -80,4 +85,9 @@ public class Withdraw extends BaseAudit {
* 审核状态
*/
private Integer auditStatus;
/**
* 审核原因
*/
private String auditReason;
}

View File

@ -108,4 +108,11 @@ public class WithdrawVO extends BaseAudit {
@Schema(description ="审核状态")
@ExcelProperty(value ="审核状态", order = 12)
private Integer auditStatus;
/**
* 审核原因
*/
@Schema(description ="审核原因")
@ExcelProperty(value ="审核原因", order = 13)
private String auditReason;
}

View File

@ -0,0 +1,48 @@
package com.wzj.soopin.member.domain.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import com.wzj.soopin.member.annotation.MemberFillField;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;
import org.dromara.common.core.domain.model.BaseAudit;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 易生平台账户信息
*
* @author wzj
* @date 2023-03-07
*/
@Schema(description="易生")
@Data
@Builder(toBuilder = true)
public class YishengAccountVO extends BaseAudit {
/**
* 主键
*/
@Schema(description ="主键")
@ExcelProperty(value = "主键", order = 1)
private Long id;
/**
* 会员id
*/
@Schema(description ="会员id")
@ExcelProperty(value ="会员id", order = 3)
private Long memberId;
/**
* 金额
*/
@Schema(description ="金额")
@ExcelProperty(value ="金额", order = 4)
private BigDecimal balance;
}

View File

@ -0,0 +1,26 @@
package com.wzj.soopin.member.enums;
public enum MemberAccountChangeRecordChangeTypeEnum {
WITHDRAW(1, "提现"),
CHARGE(2, "充值"),
RECHARGE(3, "充值"),
RECHARGE_REFUND(4, "充值退款"),
WITHDRAW_REFUND(5, "提现退款"),
RECHARGE_REFUND_REFUND(6, "充值退款退款"),
WITHDRAW_REFUND_REFUND(7, "提现退款退款"),
RECHARGE_REFUND_REFUND_REFUND(8, "充值退款退款退款");
private Integer code;
private String message;
MemberAccountChangeRecordChangeTypeEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
}

View File

@ -0,0 +1,23 @@
package com.wzj.soopin.member.enums;
public enum MemberAccountChangeRecordSourceEnum {
YISHENG(1, "充值"),
CHARGE(2, "提现"),
WITHDRAW(3, "经营"),
RECHARGE_REFUND_REFUND_REFUND(9, "充值退款退款退款");
private Integer code;
private String message;
MemberAccountChangeRecordSourceEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
}

View File

@ -0,0 +1,20 @@
package com.wzj.soopin.member.enums;
public enum WithdrawAuditStatus {
PENDING(0, "待审核"),
APPROVED(1, "审核通过"),
REJECTED(2, "审核拒绝");
private Integer code;
private String message;
WithdrawAuditStatus(Integer code, String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
}

View File

@ -0,0 +1,22 @@
package com.wzj.soopin.member.enums;
public enum WithdrawStatus {
WAITING(0, "等待转账"),
PENDING(1, "转账中"),
SUCCESS(2, "转账成功"),
FAIL(3, "转账失败");
private Integer code;
private String message;
WithdrawStatus(Integer code, String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
}

View File

@ -1,6 +1,7 @@
package com.wzj.soopin.member.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.wzj.soopin.member.domain.bo.WithdrawBO;
import com.wzj.soopin.member.domain.po.Feedback;
import com.wzj.soopin.member.domain.po.Withdraw;
import com.wzj.soopin.member.domain.vo.FeedbackVO;
@ -8,5 +9,7 @@ import com.wzj.soopin.member.domain.vo.FeedbackVO;
import java.io.Serializable;
public interface IWithdrawService extends IService<Withdraw> {
boolean audit(WithdrawBO bo);
boolean withdraw(Long id);
}

View File

@ -0,0 +1,19 @@
package com.wzj.soopin.member.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.wzj.soopin.member.domain.po.Withdraw;
import com.wzj.soopin.member.domain.vo.YishengAccountVO;
import java.math.BigDecimal;
/**
* 易生支付的service
*/
public interface IYishengService {
YishengAccountVO getYishengAccount(Long memberId);
boolean withdraw(Long memberId, BigDecimal money);
boolean syncMemberAccount();
}

View File

@ -1,16 +1,29 @@
package com.wzj.soopin.member.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wzj.soopin.member.domain.bo.WithdrawBO;
import com.wzj.soopin.member.domain.po.Charge;
import com.wzj.soopin.member.domain.po.MemberAccount;
import com.wzj.soopin.member.domain.po.MemberAccountChangeRecord;
import com.wzj.soopin.member.domain.po.Withdraw;
import com.wzj.soopin.member.domain.vo.YishengAccountVO;
import com.wzj.soopin.member.enums.MemberAccountChangeRecordChangeTypeEnum;
import com.wzj.soopin.member.enums.MemberAccountChangeRecordSourceEnum;
import com.wzj.soopin.member.enums.WithdrawAuditStatus;
import com.wzj.soopin.member.enums.WithdrawStatus;
import com.wzj.soopin.member.mapper.ChargeMapper;
import com.wzj.soopin.member.mapper.MemberAccountMapper;
import com.wzj.soopin.member.mapper.WithdrawMapper;
import com.wzj.soopin.member.service.IChargeService;
import com.wzj.soopin.member.service.IWithdrawService;
import com.wzj.soopin.member.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.satoken.utils.LoginHelper;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Objects;
/**
* 会员封禁
*
@ -21,4 +34,92 @@ import org.springframework.stereotype.Service;
@Slf4j
public class WithdrawServiceImpl extends ServiceImpl<WithdrawMapper, Withdraw> implements IWithdrawService {
private final IMemberAccountService memberAccountService;
/**
* 易生账户充值服务
*/
private final IYishengService yishengService;
private final IMemberAccountChangeRecordService memberAccountChangeRecordService;
@Override
public boolean audit(WithdrawBO bo) {
Withdraw withdraw = getById(bo.getId());
if (withdraw == null) {
throw new RuntimeException("提现申请不存在");
}
if (!Objects.equals(WithdrawAuditStatus.PENDING.getCode(), withdraw.getAuditStatus())) {
throw new RuntimeException("提现申请已处理");
}
withdraw = Withdraw.builder().id(bo.getId())
.auditReason(bo.getAuditReason())
.auditTime(LocalDateTime.now())
.auditStatus(bo.getAuditStatus())
.auditBy(LoginHelper.getUserId())
.build();
return this.updateById(withdraw);
}
@Override
public boolean save(Withdraw entity) {
entity.setStatus(WithdrawStatus.WAITING.getCode());
return super.save(entity);
}
public boolean withdraw(Long id) {
Withdraw withdraw = getById(id);
//获取用户余额信息
MemberAccount memberAccount = memberAccountService.getById(withdraw.getMemberId());
if (memberAccount == null) {
throw new RuntimeException("用户不存在");
}
//检查当前用于的账户余额是否充足
BigDecimal balance = memberAccount.getMoneyBalance();
if (balance.compareTo(withdraw.getMoney()) < 0) {
throw new RuntimeException("用户余额不足");
}
//调用三方支付平台获取用户余额
YishengAccountVO yishengAccountVO = yishengService.getYishengAccount(withdraw.getMemberId());
if (yishengAccountVO == null) {
throw new RuntimeException("用户余额获取失败");
}
BigDecimal yishengBalance = yishengAccountVO.getBalance();
if (yishengBalance.compareTo(withdraw.getMoney()) < 0) {
throw new RuntimeException("用户余额不足");
}
if (!yishengBalance.equals(balance)) {
throw new RuntimeException("用户余额不一致");
}
//发起提现
boolean chargeSuccess = yishengService.withdraw(withdraw.getMemberId(), withdraw.getMoney());
if (chargeSuccess) {
//提现成功后更新会员账户余额
//从易生取别用自己计算的
//// TODO: 2025/6/21 测试的时候用计算的 测试完用易生的
BigDecimal finalBalance = balance.subtract(withdraw.getMoney());
yishengAccountVO = yishengService.getYishengAccount(withdraw.getMemberId());
memberAccountService.updateById(memberAccount.toBuilder().moneyBalance(balance.subtract(finalBalance)).build());
//生成账户变动记录bh
MemberAccountChangeRecord memberAccountChangeRecord = MemberAccountChangeRecord.builder()
.memberId(withdraw.getMemberId())
.moneyBalance(finalBalance)
.beforeBalance(balance)
.afterBalance(yishengAccountVO.getBalance())
.changeType(MemberAccountChangeRecordChangeTypeEnum.WITHDRAW.getCode())
.changeDesc("提现")
.source(MemberAccountChangeRecordSourceEnum.WITHDRAW.getCode()).build();
memberAccountChangeRecordService.save(memberAccountChangeRecord);
} else {
return false;
}
return true;
}
}

View File

@ -0,0 +1,40 @@
package com.wzj.soopin.member.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wzj.soopin.member.domain.po.Charge;
import com.wzj.soopin.member.domain.vo.YishengAccountVO;
import com.wzj.soopin.member.mapper.ChargeMapper;
import com.wzj.soopin.member.service.IChargeService;
import com.wzj.soopin.member.service.IYishengService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
/**
* 会员封禁
*
* @author zcc
*/
@Service
@RequiredArgsConstructor
@Slf4j
public class YishengServiceImpl implements IYishengService {
@Override
public YishengAccountVO getYishengAccount(Long memberId) {
return YishengAccountVO.builder().balance(new BigDecimal(1000)).build();
}
@Override
public boolean withdraw(Long memberId, BigDecimal money) {
return true;
}
@Override
public boolean syncMemberAccount() {
return true;
}
}