diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 6a1c655..6600cc6 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -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": [] diff --git a/agileboot-admin/src/main/java/com/agileboot/admin/controller/ab98/UserBalanceController.java b/agileboot-admin/src/main/java/com/agileboot/admin/controller/ab98/UserBalanceController.java new file mode 100644 index 0000000..b59b769 --- /dev/null +++ b/agileboot-admin/src/main/java/com/agileboot/admin/controller/ab98/UserBalanceController.java @@ -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> list(SearchUserBalanceQuery query) { + PageDTO page = userBalanceApplicationService.getList(query); + return ResponseDTO.ok(page); + } + + @Operation(summary = "用户余额详情") + @GetMapping("/{id}") + public ResponseDTO detail(@PathVariable Long id) { + UserBalanceDTO userBalanceDTO = userBalanceApplicationService.getById(id); + return ResponseDTO.ok(userBalanceDTO); + } + + @Operation(summary = "根据企业微信ID和汇邦云用户ID查询用户余额") + @GetMapping("/by-corpid-ab98") + public ResponseDTO getByCorpidAndAb98UserId(String corpid, Long ab98UserId) { + UserBalanceDTO userBalanceDTO = userBalanceApplicationService.getByCorpidAndAb98UserId(corpid, ab98UserId); + return ResponseDTO.ok(userBalanceDTO); + } + + @Operation(summary = "根据openid查询用户余额") + @GetMapping("/by-openid") + public ResponseDTO getByOpenid(String openid) { + UserBalanceDTO userBalanceDTO = userBalanceApplicationService.getByOpenid(openid); + return ResponseDTO.ok(userBalanceDTO); + } + + @Operation(summary = "新增用户余额") + @AccessLog(title = "用户余额管理", businessType = BusinessTypeEnum.ADD) + @PostMapping + public ResponseDTO 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 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 remove(@PathVariable Long id) { + userBalanceApplicationService.delete(id); + return ResponseDTO.ok(); + } + + @Operation(summary = "批量删除用户余额") + @AccessLog(title = "用户余额管理", businessType = BusinessTypeEnum.DELETE) + @DeleteMapping("/batch/{ids}") + public ResponseDTO batchRemove(@PathVariable @NotNull List ids) { + userBalanceApplicationService.batchDelete(ids); + return ResponseDTO.ok(); + } + + @Operation(summary = "增加用户余额") + @AccessLog(title = "用户余额管理", businessType = BusinessTypeEnum.MODIFY) + @PostMapping("/add-balance") + public ResponseDTO 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 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 insertOrUpdate(@Validated @RequestBody AddUserBalanceCommand command) { + UserBalanceDTO userBalanceDTO = userBalanceApplicationService.insertOrUpdate(command); + return ResponseDTO.ok(userBalanceDTO); + } +} diff --git a/agileboot-common/src/main/java/com/agileboot/common/exception/error/ErrorCode.java b/agileboot-common/src/main/java/com/agileboot/common/exception/error/ErrorCode.java index 6da6782..51c4b4e 100644 --- a/agileboot-common/src/main/java/com/agileboot/common/exception/error/ErrorCode.java +++ b/agileboot-common/src/main/java/com/agileboot/common/exception/error/ErrorCode.java @@ -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"), ; diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/UserBalanceApplicationService.java b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/UserBalanceApplicationService.java new file mode 100644 index 0000000..1724d8f --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/UserBalanceApplicationService.java @@ -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; + +/** + *

+ * 用户余额应用服务 + *

+ * + * @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 getList(SearchUserBalanceQuery query) { + // 构建查询条件 + Page page = query.toPage(); + UserBalanceEntity entity = new UserBalanceEntity(); + BeanUtil.copyProperties(query, entity); + + // 执行查询 + List entityList = userBalanceService.page(page, query.addQueryCondition()).getRecords(); + + // 转换为DTO + List 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 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()); + } + +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/command/AddBalanceCommand.java b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/command/AddBalanceCommand.java new file mode 100644 index 0000000..5c3e710 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/command/AddBalanceCommand.java @@ -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; + +/** + *

+ * 增加用户余额命令 + *

+ * + * @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; + +} \ No newline at end of file diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/command/AddUserBalanceCommand.java b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/command/AddUserBalanceCommand.java new file mode 100644 index 0000000..01bf957 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/command/AddUserBalanceCommand.java @@ -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; + +/** + *

+ * 新增用户余额命令 + *

+ * + * @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; + +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/command/SubtractBalanceCommand.java b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/command/SubtractBalanceCommand.java new file mode 100644 index 0000000..6b89e54 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/command/SubtractBalanceCommand.java @@ -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; + +/** + *

+ * 减少用户余额命令 + *

+ * + * @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; + +} \ No newline at end of file diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/command/UpdateUserBalanceCommand.java b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/command/UpdateUserBalanceCommand.java new file mode 100644 index 0000000..0c6821f --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/command/UpdateUserBalanceCommand.java @@ -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; + +/** + *

+ * 更新用户余额命令 + *

+ * + * @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; + +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/db/UserBalanceEntity.java b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/db/UserBalanceEntity.java new file mode 100644 index 0000000..8549ca0 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/db/UserBalanceEntity.java @@ -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; + +/** + *

+ * 用户余额表 + *

+ * + * @author valarchie + * @since 2025-11-24 + */ +@Getter +@Setter +@TableName("user_balance") +@ApiModel(value = "UserBalanceEntity对象", description = "用户余额表") +public class UserBalanceEntity extends BaseEntity { + + 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; + } +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/db/UserBalanceMapper.java b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/db/UserBalanceMapper.java new file mode 100644 index 0000000..91700e6 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/db/UserBalanceMapper.java @@ -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; + +/** + *

+ * 用户余额表 Mapper 接口 + *

+ * + * @author valarchie + * @since 2025-11-24 + */ +@Mapper +public interface UserBalanceMapper extends BaseMapper { + + /** + * 根据企业微信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); + +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/db/UserBalanceService.java b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/db/UserBalanceService.java new file mode 100644 index 0000000..350c4ac --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/db/UserBalanceService.java @@ -0,0 +1,60 @@ +package com.agileboot.domain.ab98.user_balance.db; + +import com.baomidou.mybatisplus.extension.service.IService; + +/** + *

+ * 用户余额表 服务类 + *

+ * + * @author valarchie + * @since 2025-11-24 + */ +public interface UserBalanceService extends IService { + + /** + * 根据企业微信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); + +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/db/UserBalanceServiceImpl.java b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/db/UserBalanceServiceImpl.java new file mode 100644 index 0000000..8bb5ebc --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/db/UserBalanceServiceImpl.java @@ -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; + +/** + *

+ * 用户余额表 服务实现类 + *

+ * + * @author valarchie + * @since 2025-11-24 + */ +@Service +@RequiredArgsConstructor +public class UserBalanceServiceImpl extends ServiceImpl 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); + } +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/dto/UserBalanceDTO.java b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/dto/UserBalanceDTO.java new file mode 100644 index 0000000..0bdf1ef --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/dto/UserBalanceDTO.java @@ -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; + +/** + *

+ * 用户余额DTO + *

+ * + * @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; + +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/model/UserBalanceModel.java b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/model/UserBalanceModel.java new file mode 100644 index 0000000..ff525ff --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/model/UserBalanceModel.java @@ -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; + +/** + *

+ * 用户余额领域模型 + *

+ * + * @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()); + } + +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/model/UserBalanceModelFactory.java b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/model/UserBalanceModelFactory.java new file mode 100644 index 0000000..605a032 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/model/UserBalanceModelFactory.java @@ -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; + +/** + *

+ * 用户余额模型工厂 + *

+ * + * @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; + } + +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/query/SearchUserBalanceQuery.java b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/query/SearchUserBalanceQuery.java new file mode 100644 index 0000000..f49ed62 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance/query/SearchUserBalanceQuery.java @@ -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; + +/** + *

+ * 用户余额查询参数 + *

+ * + * @author valarchie + * @since 2025-11-24 + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class SearchUserBalanceQuery extends AbstractPageQuery { + + @ApiModelProperty("企业微信ID") + private String corpid; + + @ApiModelProperty("openid") + private String openid; + + @ApiModelProperty("汇邦云用户ID") + private Long ab98UserId; + + @ApiModelProperty("企业用户ID") + private Long qyUserId; + + @Override + public QueryWrapper addQueryCondition() { + QueryWrapper 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; + } + +}