feat(用户余额): 新增用户余额管理功能

实现用户余额的增删改查、增加余额、减少余额等核心功能
添加相关DTO、Command、Query、Model等类
提供完整的API接口供前端调用
This commit is contained in:
dzq 2025-11-24 16:07:01 +08:00
parent 419cab9048
commit 0e262bd324
16 changed files with 1080 additions and 1 deletions

View File

@ -37,7 +37,9 @@
"Bash(./mvnw clean compile -pl agileboot-api -am -DskipTests)",
"Bash(./mvnw clean compile -pl agileboot-api,agileboot-domain -am -DskipTests)",
"Bash(./mvnw clean compile -pl agileboot-domain -am -DskipTests)",
"Bash(./mvnw:*)"
"Bash(./mvnw:*)",
"Bash(tree:*)",
"Bash(cat:*)"
],
"deny": [],
"ask": []

View File

@ -0,0 +1,123 @@
package com.agileboot.admin.controller.ab98;
import com.agileboot.admin.customize.aop.accessLog.AccessLog;
import com.agileboot.common.core.base.BaseController;
import com.agileboot.common.core.dto.ResponseDTO;
import com.agileboot.common.core.page.PageDTO;
import com.agileboot.common.enums.common.BusinessTypeEnum;
import com.agileboot.domain.ab98.user_balance.command.AddBalanceCommand;
import com.agileboot.domain.ab98.user_balance.command.AddUserBalanceCommand;
import com.agileboot.domain.ab98.user_balance.command.SubtractBalanceCommand;
import com.agileboot.domain.ab98.user_balance.command.UpdateUserBalanceCommand;
import com.agileboot.domain.ab98.user_balance.db.UserBalanceEntity;
import com.agileboot.domain.ab98.user_balance.dto.UserBalanceDTO;
import com.agileboot.domain.ab98.user_balance.query.SearchUserBalanceQuery;
import com.agileboot.domain.ab98.user_balance.UserBalanceApplicationService;
import com.agileboot.domain.common.command.BulkOperationCommand;
import io.swagger.v3.oas.annotations.Operation;
import java.util.List;
import javax.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/ab98/balance")
@RequiredArgsConstructor
@Validated
public class UserBalanceController extends BaseController {
private final UserBalanceApplicationService userBalanceApplicationService;
@Operation(summary = "用户余额列表")
@GetMapping
public ResponseDTO<PageDTO<UserBalanceDTO>> list(SearchUserBalanceQuery query) {
PageDTO<UserBalanceDTO> page = userBalanceApplicationService.getList(query);
return ResponseDTO.ok(page);
}
@Operation(summary = "用户余额详情")
@GetMapping("/{id}")
public ResponseDTO<UserBalanceDTO> detail(@PathVariable Long id) {
UserBalanceDTO userBalanceDTO = userBalanceApplicationService.getById(id);
return ResponseDTO.ok(userBalanceDTO);
}
@Operation(summary = "根据企业微信ID和汇邦云用户ID查询用户余额")
@GetMapping("/by-corpid-ab98")
public ResponseDTO<UserBalanceDTO> getByCorpidAndAb98UserId(String corpid, Long ab98UserId) {
UserBalanceDTO userBalanceDTO = userBalanceApplicationService.getByCorpidAndAb98UserId(corpid, ab98UserId);
return ResponseDTO.ok(userBalanceDTO);
}
@Operation(summary = "根据openid查询用户余额")
@GetMapping("/by-openid")
public ResponseDTO<UserBalanceDTO> getByOpenid(String openid) {
UserBalanceDTO userBalanceDTO = userBalanceApplicationService.getByOpenid(openid);
return ResponseDTO.ok(userBalanceDTO);
}
@Operation(summary = "新增用户余额")
@AccessLog(title = "用户余额管理", businessType = BusinessTypeEnum.ADD)
@PostMapping
public ResponseDTO<UserBalanceDTO> add(@Validated @RequestBody AddUserBalanceCommand command) {
UserBalanceDTO userBalanceDTO = userBalanceApplicationService.add(command);
return ResponseDTO.ok(userBalanceDTO);
}
@Operation(summary = "修改用户余额")
@AccessLog(title = "用户余额管理", businessType = BusinessTypeEnum.MODIFY)
@PutMapping("/{id}")
public ResponseDTO<UserBalanceDTO> edit(@PathVariable Long id, @Validated @RequestBody UpdateUserBalanceCommand command) {
command.setUserBalanceId(id);
UserBalanceDTO userBalanceDTO = userBalanceApplicationService.update(command);
return ResponseDTO.ok(userBalanceDTO);
}
@Operation(summary = "删除用户余额")
@AccessLog(title = "用户余额管理", businessType = BusinessTypeEnum.DELETE)
@DeleteMapping("/{id}")
public ResponseDTO<Void> remove(@PathVariable Long id) {
userBalanceApplicationService.delete(id);
return ResponseDTO.ok();
}
@Operation(summary = "批量删除用户余额")
@AccessLog(title = "用户余额管理", businessType = BusinessTypeEnum.DELETE)
@DeleteMapping("/batch/{ids}")
public ResponseDTO<Void> batchRemove(@PathVariable @NotNull List<Long> ids) {
userBalanceApplicationService.batchDelete(ids);
return ResponseDTO.ok();
}
@Operation(summary = "增加用户余额")
@AccessLog(title = "用户余额管理", businessType = BusinessTypeEnum.MODIFY)
@PostMapping("/add-balance")
public ResponseDTO<String> addBalance(@Validated @RequestBody AddBalanceCommand command) {
boolean success = userBalanceApplicationService.addBalance(command);
return success ? ResponseDTO.ok("增加用户余额成功") : ResponseDTO.fail("增加用户余额失败");
}
@Operation(summary = "减少用户余额")
@AccessLog(title = "用户余额管理", businessType = BusinessTypeEnum.MODIFY)
@PostMapping("/subtract-balance")
public ResponseDTO<String> subtractBalance(@Validated @RequestBody SubtractBalanceCommand command) {
boolean success = userBalanceApplicationService.subtractBalance(command);
return success ? ResponseDTO.ok("减少用户余额成功") : ResponseDTO.fail("减少用户余额失败");
}
@Operation(summary = "插入或更新用户余额")
@AccessLog(title = "用户余额管理", businessType = BusinessTypeEnum.MODIFY)
@PostMapping("/insert-or-update")
public ResponseDTO<UserBalanceDTO> insertOrUpdate(@Validated @RequestBody AddUserBalanceCommand command) {
UserBalanceDTO userBalanceDTO = userBalanceApplicationService.insertOrUpdate(command);
return ResponseDTO.ok(userBalanceDTO);
}
}

View File

@ -205,6 +205,10 @@ public enum ErrorCode implements ErrorCodeInterface {
USER_ADMIN_CAN_NOT_BE_MODIFY(10515, "管理员不允许做任何修改", "Business.USER_ADMIN_CAN_NOT_BE_MODIFY"),
COMMON_BAD_REQUEST(10516, "请求参数错误", "Business.COMMON_BAD_REQUEST"),
/**
* 余额金额无效
*/
BALANCE_AMOUNT_INVALID(11006, "余额金额无效", "Business.BALANCE_AMOUNT_INVALID"),
;

View File

@ -0,0 +1,242 @@
package com.agileboot.domain.ab98.user_balance;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.agileboot.common.core.page.PageDTO;
import com.agileboot.domain.ab98.user_balance.command.AddBalanceCommand;
import com.agileboot.domain.ab98.user_balance.command.AddUserBalanceCommand;
import com.agileboot.domain.ab98.user_balance.command.SubtractBalanceCommand;
import com.agileboot.domain.ab98.user_balance.command.UpdateUserBalanceCommand;
import com.agileboot.domain.ab98.user_balance.db.UserBalanceEntity;
import com.agileboot.domain.ab98.user_balance.db.UserBalanceService;
import com.agileboot.domain.ab98.user_balance.dto.UserBalanceDTO;
import com.agileboot.domain.ab98.user_balance.model.UserBalanceModel;
import com.agileboot.domain.ab98.user_balance.model.UserBalanceModelFactory;
import com.agileboot.domain.ab98.user_balance.query.SearchUserBalanceQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.stream.Collectors;
/**
* <p>
* 用户余额应用服务
* </p>
*
* @author valarchie
* @since 2025-11-24
*/
@Service
@RequiredArgsConstructor
public class UserBalanceApplicationService {
private final UserBalanceService userBalanceService;
private final UserBalanceModelFactory userBalanceModelFactory;
/**
* 新增用户余额
*
* @param command 新增命令
* @return 用户余额DTO
*/
@Transactional(rollbackFor = Exception.class)
public UserBalanceDTO add(AddUserBalanceCommand command) {
UserBalanceModel model = userBalanceModelFactory.create(command);
boolean success = model.save();
if (!success) {
throw new RuntimeException("新增用户余额失败");
}
return new UserBalanceDTO(model);
}
/**
* 更新用户余额
*
* @param command 更新命令
* @return 用户余额DTO
*/
@Transactional(rollbackFor = Exception.class)
public UserBalanceDTO update(UpdateUserBalanceCommand command) {
UserBalanceModel model = userBalanceModelFactory.create(command);
boolean success = model.update();
if (!success) {
throw new RuntimeException("更新用户余额失败");
}
return new UserBalanceDTO(model);
}
/**
* 根据ID删除用户余额
*
* @param userBalanceId 主键ID
*/
@Transactional(rollbackFor = Exception.class)
public void delete(Long userBalanceId) {
if (userBalanceId == null) {
throw new IllegalArgumentException("用户余额ID不能为空");
}
boolean success = userBalanceService.removeById(userBalanceId);
if (!success) {
throw new RuntimeException("删除用户余额失败");
}
}
/**
* 根据ID查询用户余额
*
* @param userBalanceId 主键ID
* @return 用户余额DTO
*/
public UserBalanceDTO getById(Long userBalanceId) {
if (userBalanceId == null) {
return null;
}
UserBalanceEntity entity = userBalanceService.getById(userBalanceId);
return entity != null ? new UserBalanceDTO(entity) : null;
}
/**
* 根据企业微信ID和汇邦云用户ID查询用户余额
*
* @param corpid 企业微信ID
* @param ab98UserId 汇邦云用户ID
* @return 用户余额DTO
*/
public UserBalanceDTO getByCorpidAndAb98UserId(String corpid, Long ab98UserId) {
if (corpid == null || ab98UserId == null) {
return null;
}
UserBalanceEntity entity = userBalanceService.getByCorpidAndAb98UserId(corpid, ab98UserId);
return entity != null ? new UserBalanceDTO(entity) : null;
}
/**
* 根据openid查询用户余额
*
* @param openid openid
* @return 用户余额DTO
*/
public UserBalanceDTO getByOpenid(String openid) {
if (openid == null) {
return null;
}
UserBalanceEntity entity = userBalanceService.getByOpenid(openid);
return entity != null ? new UserBalanceDTO(entity) : null;
}
/**
* 查询用户余额列表
*
* @param query 查询参数
* @return 用户余额分页DTO
*/
public PageDTO<UserBalanceDTO> getList(SearchUserBalanceQuery query) {
// 构建查询条件
Page<UserBalanceEntity> page = query.toPage();
UserBalanceEntity entity = new UserBalanceEntity();
BeanUtil.copyProperties(query, entity);
// 执行查询
List<UserBalanceEntity> entityList = userBalanceService.page(page, query.addQueryCondition()).getRecords();
// 转换为DTO
List<UserBalanceDTO> dtoList = entityList.stream()
.map(UserBalanceDTO::new)
.collect(Collectors.toList());
// 获取总数
Long total = page.getTotal();
return new PageDTO<>(dtoList, total);
}
/**
* 批量删除用户余额
*
* @param userBalanceIds 主键ID列表
*/
@Transactional(rollbackFor = Exception.class)
public void batchDelete(List<Long> userBalanceIds) {
if (CollUtil.isEmpty(userBalanceIds)) {
throw new IllegalArgumentException("用户余额ID列表不能为空");
}
boolean success = userBalanceService.removeByIds(userBalanceIds);
if (!success) {
throw new RuntimeException("批量删除用户余额失败");
}
}
/**
* 增加用户余额
*
* @param corpid 企业微信ID
* @param ab98UserId 汇邦云用户ID
* @param amount 增加的金额单位
* @return 是否成功
*/
@Transactional(rollbackFor = Exception.class)
public boolean addBalance(String corpid, Long ab98UserId, Long amount) {
return userBalanceService.addBalance(corpid, ab98UserId, amount);
}
/**
* 减少用户余额
*
* @param corpid 企业微信ID
* @param ab98UserId 汇邦云用户ID
* @param amount 减少的金额单位
* @return 是否成功
*/
@Transactional(rollbackFor = Exception.class)
public boolean subtractBalance(String corpid, Long ab98UserId, Long amount) {
return userBalanceService.subtractBalance(corpid, ab98UserId, amount);
}
/**
* 插入或更新用户余额
*
* @param command 用户余额命令
* @return 用户余额DTO
*/
@Transactional(rollbackFor = Exception.class)
public UserBalanceDTO insertOrUpdate(AddUserBalanceCommand command) {
UserBalanceEntity entity = new UserBalanceEntity();
BeanUtil.copyProperties(command, entity);
boolean success = userBalanceService.insertOrUpdate(entity);
if (!success) {
throw new RuntimeException("插入或更新用户余额失败");
}
return new UserBalanceDTO(entity);
}
/**
* 增加用户余额使用命令类
*
* @param command 增加余额命令
* @return 是否成功
*/
@Transactional(rollbackFor = Exception.class)
public boolean addBalance(AddBalanceCommand command) {
return userBalanceService.addBalance(command.getCorpid(), command.getAb98UserId(), command.getAmount());
}
/**
* 减少用户余额使用命令类
*
* @param command 减少余额命令
* @return 是否成功
*/
@Transactional(rollbackFor = Exception.class)
public boolean subtractBalance(SubtractBalanceCommand command) {
return userBalanceService.subtractBalance(command.getCorpid(), command.getAb98UserId(), command.getAmount());
}
}

View File

@ -0,0 +1,28 @@
package com.agileboot.domain.ab98.user_balance.command;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* <p>
* 增加用户余额命令
* </p>
*
* @author valarchie
* @since 2025-11-24
*/
@Data
public class AddBalanceCommand {
@NotBlank(message = "企业微信ID不能为空")
private String corpid;
@NotNull(message = "汇邦云用户ID不能为空")
private Long ab98UserId;
@NotNull(message = "金额不能为空")
private Long amount;
}

View File

@ -0,0 +1,38 @@
package com.agileboot.domain.ab98.user_balance.command;
import com.agileboot.domain.ab98.user_balance.db.UserBalanceEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* <p>
* 新增用户余额命令
* </p>
*
* @author valarchie
* @since 2025-11-24
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class AddUserBalanceCommand extends UserBalanceEntity {
@NotBlank(message = "企业微信ID不能为空")
private String corpid;
private String openid;
@NotNull(message = "汇邦云用户ID不能为空")
private Long ab98UserId;
private Long qyUserId;
private Long balance;
private Long useBalance;
private Long balanceLimit;
}

View File

@ -0,0 +1,28 @@
package com.agileboot.domain.ab98.user_balance.command;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* <p>
* 减少用户余额命令
* </p>
*
* @author valarchie
* @since 2025-11-24
*/
@Data
public class SubtractBalanceCommand {
@NotBlank(message = "企业微信ID不能为空")
private String corpid;
@NotNull(message = "汇邦云用户ID不能为空")
private Long ab98UserId;
@NotNull(message = "金额不能为空")
private Long amount;
}

View File

@ -0,0 +1,41 @@
package com.agileboot.domain.ab98.user_balance.command;
import com.agileboot.domain.ab98.user_balance.db.UserBalanceEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* <p>
* 更新用户余额命令
* </p>
*
* @author valarchie
* @since 2025-11-24
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class UpdateUserBalanceCommand extends AddUserBalanceCommand {
@NotNull(message = "主键ID不能为空")
private Long userBalanceId;
@NotBlank(message = "企业微信ID不能为空")
private String corpid;
private String openid;
@NotNull(message = "汇邦云用户ID不能为空")
private Long ab98UserId;
private Long qyUserId;
private Long balance;
private Long useBalance;
private Long balanceLimit;
}

View File

@ -0,0 +1,75 @@
package com.agileboot.domain.ab98.user_balance.db;
import com.agileboot.common.core.base.BaseEntity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
/**
* <p>
* 用户余额表
* </p>
*
* @author valarchie
* @since 2025-11-24
*/
@Getter
@Setter
@TableName("user_balance")
@ApiModel(value = "UserBalanceEntity对象", description = "用户余额表")
public class UserBalanceEntity extends BaseEntity<UserBalanceEntity> {
private static final long serialVersionUID = 1L;
@ApiModelProperty("主键ID")
@TableId(value = "user_balance_id", type = IdType.AUTO)
private Long userBalanceId;
@ApiModelProperty("企业微信id")
@TableField("corpid")
private String corpid;
@ApiModelProperty("openid")
@TableField("openid")
private String openid;
@ApiModelProperty("汇邦云用户ID")
@TableField("ab98_user_id")
private Long ab98UserId;
@ApiModelProperty("企业用户id")
@TableField("qy_user_id")
private Long qyUserId;
@ApiModelProperty("用户余额(单位:分)")
@TableField("balance")
private Long balance;
@ApiModelProperty("用户余额(单位:分)")
@TableField("use_balance")
private Long useBalance;
@ApiModelProperty("用户余额(单位:分)")
@TableField("balance_limit")
private Long balanceLimit;
@ApiModelProperty("创建者ID")
@TableField("creator_id")
private Long creatorId;
@ApiModelProperty("更新者ID")
@TableField("updater_id")
private Long updaterId;
@Override
public Serializable pkVal() {
return this.userBalanceId;
}
}

View File

@ -0,0 +1,38 @@
package com.agileboot.domain.ab98.user_balance.db;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
/**
* <p>
* 用户余额表 Mapper 接口
* </p>
*
* @author valarchie
* @since 2025-11-24
*/
@Mapper
public interface UserBalanceMapper extends BaseMapper<UserBalanceEntity> {
/**
* 根据企业微信ID和汇邦云用户ID查询用户余额
*
* @param corpid 企业微信ID
* @param ab98UserId 汇邦云用户ID
* @return 用户余额信息
*/
@Select("SELECT * FROM user_balance WHERE corpid = #{corpid} AND ab98_user_id = #{ab98UserId}")
UserBalanceEntity selectByCorpidAndAb98UserId(@Param("corpid") String corpid, @Param("ab98UserId") Long ab98UserId);
/**
* 根据openid查询用户余额
*
* @param openid openid
* @return 用户余额信息
*/
@Select("SELECT * FROM user_balance WHERE openid = #{openid}")
UserBalanceEntity selectByOpenid(@Param("openid") String openid);
}

View File

@ -0,0 +1,60 @@
package com.agileboot.domain.ab98.user_balance.db;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 用户余额表 服务类
* </p>
*
* @author valarchie
* @since 2025-11-24
*/
public interface UserBalanceService extends IService<UserBalanceEntity> {
/**
* 根据企业微信ID和汇邦云用户ID查询用户余额
*
* @param corpid 企业微信ID
* @param ab98UserId 汇邦云用户ID
* @return 用户余额信息
*/
UserBalanceEntity getByCorpidAndAb98UserId(String corpid, Long ab98UserId);
/**
* 根据openid查询用户余额
*
* @param openid openid
* @return 用户余额信息
*/
UserBalanceEntity getByOpenid(String openid);
/**
* 插入或更新用户余额
*
* @param entity 用户余额实体
* @return 是否成功
*/
boolean insertOrUpdate(UserBalanceEntity entity);
/**
* 增加用户余额
*
* @param corpid 企业微信ID
* @param ab98UserId 汇邦云用户ID
* @param amount 增加的金额单位
* @return 是否成功
*/
boolean addBalance(String corpid, Long ab98UserId, Long amount);
/**
* 减少用户余额
*
* @param corpid 企业微信ID
* @param ab98UserId 汇邦云用户ID
* @param amount 减少的金额单位
* @return 是否成功
*/
boolean subtractBalance(String corpid, Long ab98UserId, Long amount);
}

View File

@ -0,0 +1,86 @@
package com.agileboot.domain.ab98.user_balance.db;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
/**
* <p>
* 用户余额表 服务实现类
* </p>
*
* @author valarchie
* @since 2025-11-24
*/
@Service
@RequiredArgsConstructor
public class UserBalanceServiceImpl extends ServiceImpl<UserBalanceMapper, UserBalanceEntity> implements UserBalanceService {
private final UserBalanceMapper userBalanceMapper;
@Override
public UserBalanceEntity getByCorpidAndAb98UserId(String corpid, Long ab98UserId) {
return userBalanceMapper.selectByCorpidAndAb98UserId(corpid, ab98UserId);
}
@Override
public UserBalanceEntity getByOpenid(String openid) {
return userBalanceMapper.selectByOpenid(openid);
}
@Override
public boolean insertOrUpdate(UserBalanceEntity entity) {
if (entity == null) {
return false;
}
// 检查是否已存在
UserBalanceEntity existing = userBalanceMapper.selectByCorpidAndAb98UserId(entity.getCorpid(), entity.getAb98UserId());
if (existing != null) {
// 更新
entity.setUserBalanceId(existing.getUserBalanceId());
return updateById(entity);
} else {
// 插入
return save(entity);
}
}
@Override
public boolean addBalance(String corpid, Long ab98UserId, Long amount) {
UserBalanceEntity entity = userBalanceMapper.selectByCorpidAndAb98UserId(corpid, ab98UserId);
if (entity == null) {
// 如果不存在则创建
entity = new UserBalanceEntity();
entity.setCorpid(corpid);
entity.setAb98UserId(ab98UserId);
entity.setBalance(amount);
entity.setUseBalance(0L);
entity.setBalanceLimit(0L);
return save(entity);
}
// 更新余额
Long newBalance = (entity.getBalance() == null ? 0 : entity.getBalance()) + amount;
entity.setBalance(newBalance);
return updateById(entity);
}
@Override
public boolean subtractBalance(String corpid, Long ab98UserId, Long amount) {
UserBalanceEntity entity = userBalanceMapper.selectByCorpidAndAb98UserId(corpid, ab98UserId);
if (entity == null || entity.getBalance() == null) {
return false;
}
Long currentBalance = entity.getBalance();
if (currentBalance < amount) {
return false;
}
// 更新余额
Long newBalance = currentBalance - amount;
entity.setBalance(newBalance);
return updateById(entity);
}
}

View File

@ -0,0 +1,59 @@
package com.agileboot.domain.ab98.user_balance.dto;
import cn.hutool.core.bean.BeanUtil;
import com.agileboot.common.annotation.ExcelColumn;
import com.agileboot.common.annotation.ExcelSheet;
import com.agileboot.domain.ab98.user_balance.db.UserBalanceEntity;
import lombok.Data;
/**
* <p>
* 用户余额DTO
* </p>
*
* @author valarchie
* @since 2025-11-24
*/
@ExcelSheet(name = "用户余额")
@Data
public class UserBalanceDTO {
public UserBalanceDTO() {}
public UserBalanceDTO(UserBalanceEntity entity) {
if (entity != null) {
BeanUtil.copyProperties(entity, this);
}
}
@ExcelColumn(name = "主键ID")
private Long userBalanceId;
@ExcelColumn(name = "企业微信ID")
private String corpid;
@ExcelColumn(name = "openid")
private String openid;
@ExcelColumn(name = "汇邦云用户ID")
private Long ab98UserId;
@ExcelColumn(name = "企业用户ID")
private Long qyUserId;
@ExcelColumn(name = "用户余额(分)")
private Long balance;
@ExcelColumn(name = "可用余额(分)")
private Long useBalance;
@ExcelColumn(name = "余额限制(分)")
private Long balanceLimit;
@ExcelColumn(name = "创建者ID")
private Long creatorId;
@ExcelColumn(name = "更新者ID")
private Long updaterId;
}

View File

@ -0,0 +1,138 @@
package com.agileboot.domain.ab98.user_balance.model;
import cn.hutool.core.bean.BeanUtil;
import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode;
import com.agileboot.domain.ab98.user_balance.command.AddUserBalanceCommand;
import com.agileboot.domain.ab98.user_balance.command.UpdateUserBalanceCommand;
import com.agileboot.domain.ab98.user_balance.db.UserBalanceEntity;
import com.agileboot.domain.ab98.user_balance.db.UserBalanceService;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
* 用户余额领域模型
* </p>
*
* @author valarchie
* @since 2025-11-24
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class UserBalanceModel extends UserBalanceEntity {
private UserBalanceService userBalanceService;
public UserBalanceModel() {}
public UserBalanceModel(UserBalanceEntity entity, UserBalanceService userBalanceService) {
this.userBalanceService = userBalanceService;
if (entity != null) {
BeanUtil.copyProperties(entity, this);
}
}
public UserBalanceModel(UserBalanceService userBalanceService) {
this.userBalanceService = userBalanceService;
}
/**
* 从新增命令加载数据
*
* @param command 新增命令
*/
public void loadAddCommand(AddUserBalanceCommand command) {
if (command != null) {
BeanUtil.copyProperties(command, this, "userBalanceId");
}
}
/**
* 从更新命令加载数据
*
* @param command 更新命令
*/
public void loadUpdateCommand(UpdateUserBalanceCommand command) {
if (command != null) {
loadAddCommand(command);
if (command.getUserBalanceId() != null) {
this.setUserBalanceId(command.getUserBalanceId());
}
}
}
/**
* 验证余额是否足够
*
* @param amount 需要验证的金额单位
* @throws ApiException 余额不足异常
*/
public void validateBalance(Long amount) {
if (amount == null || amount <= 0) {
throw new ApiException(ErrorCode.Business.BALANCE_AMOUNT_INVALID);
}
if (this.getBalance() == null || this.getBalance() < amount) {
throw new ApiException(ErrorCode.Business.BALANCE_AMOUNT_INVALID);
}
}
/**
* 增加余额
*
* @param amount 增加的金额单位
*/
public void addBalance(Long amount) {
if (amount == null || amount <= 0) {
return;
}
Long currentBalance = this.getBalance() == null ? 0 : this.getBalance();
this.setBalance(currentBalance + amount);
}
/**
* 减少余额
*
* @param amount 减少的金额单位
*/
public void subtractBalance(Long amount) {
if (amount == null || amount <= 0) {
return;
}
validateBalance(amount);
Long currentBalance = this.getBalance() == null ? 0 : this.getBalance();
this.setBalance(currentBalance - amount);
}
/**
* 保存到数据库
*
* @return 是否成功
*/
public boolean save() {
return userBalanceService.save(this);
}
/**
* 更新到数据库
*
* @return 是否成功
*/
public boolean update() {
return userBalanceService.updateById(this);
}
/**
* 从数据库删除
*
* @return 是否成功
*/
public boolean remove() {
return userBalanceService.removeById(this.getUserBalanceId());
}
}

View File

@ -0,0 +1,67 @@
package com.agileboot.domain.ab98.user_balance.model;
import com.agileboot.domain.ab98.user_balance.command.AddUserBalanceCommand;
import com.agileboot.domain.ab98.user_balance.command.UpdateUserBalanceCommand;
import com.agileboot.domain.ab98.user_balance.db.UserBalanceEntity;
import com.agileboot.domain.ab98.user_balance.db.UserBalanceService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
/**
* <p>
* 用户余额模型工厂
* </p>
*
* @author valarchie
* @since 2025-11-24
*/
@Component
@RequiredArgsConstructor
public class UserBalanceModelFactory {
private final UserBalanceService userBalanceService;
/**
* 创建新的用户余额模型
*
* @return 用户余额模型
*/
public UserBalanceModel create() {
return new UserBalanceModel(userBalanceService);
}
/**
* 从实体创建用户余额模型
*
* @param entity 实体
* @return 用户余额模型
*/
public UserBalanceModel create(UserBalanceEntity entity) {
return new UserBalanceModel(entity, userBalanceService);
}
/**
* 从新增命令创建用户余额模型
*
* @param command 新增命令
* @return 用户余额模型
*/
public UserBalanceModel create(AddUserBalanceCommand command) {
UserBalanceModel model = new UserBalanceModel(userBalanceService);
model.loadAddCommand(command);
return model;
}
/**
* 从更新命令创建用户余额模型
*
* @param command 更新命令
* @return 用户余额模型
*/
public UserBalanceModel create(UpdateUserBalanceCommand command) {
UserBalanceModel model = new UserBalanceModel(userBalanceService);
model.loadUpdateCommand(command);
return model;
}
}

View File

@ -0,0 +1,50 @@
package com.agileboot.domain.ab98.user_balance.query;
import cn.hutool.core.util.StrUtil;
import com.agileboot.common.core.page.AbstractPageQuery;
import com.agileboot.domain.ab98.user_balance.db.UserBalanceEntity;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
* 用户余额查询参数
* </p>
*
* @author valarchie
* @since 2025-11-24
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class SearchUserBalanceQuery extends AbstractPageQuery<UserBalanceEntity> {
@ApiModelProperty("企业微信ID")
private String corpid;
@ApiModelProperty("openid")
private String openid;
@ApiModelProperty("汇邦云用户ID")
private Long ab98UserId;
@ApiModelProperty("企业用户ID")
private Long qyUserId;
@Override
public QueryWrapper<UserBalanceEntity> addQueryCondition() {
QueryWrapper<UserBalanceEntity> queryWrapper = new QueryWrapper<>();
queryWrapper
.eq(StrUtil.isNotEmpty(corpid), "corpid", corpid)
.eq(StrUtil.isNotEmpty(openid), "openid", openid)
.eq(ab98UserId != null, "ab98_user_id", ab98UserId)
.eq(qyUserId != null, "qy_user_id", qyUserId);
this.timeRangeColumn = "create_time";
return queryWrapper;
}
}