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 51c4b4e..0400ada 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 @@ -209,6 +209,11 @@ public enum ErrorCode implements ErrorCodeInterface { * 余额金额无效 */ BALANCE_AMOUNT_INVALID(11006, "余额金额无效", "Business.BALANCE_AMOUNT_INVALID"), + + /** + * 该值不允许为空 + */ + VALUE_NOT_ALLOWED(11007, "该值不允许为空", "Business.VALUE_NOT_ALLOWED"), ; diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/UserBalanceLogApplicationService.java b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/UserBalanceLogApplicationService.java new file mode 100644 index 0000000..ab72963 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/UserBalanceLogApplicationService.java @@ -0,0 +1,249 @@ +package com.agileboot.domain.ab98.user_balance_log; + +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_log.command.AddUserBalanceLogCommand; +import com.agileboot.domain.ab98.user_balance_log.command.UpdateUserBalanceLogCommand; +import com.agileboot.domain.ab98.user_balance_log.db.UserBalanceLogEntity; +import com.agileboot.domain.ab98.user_balance_log.db.UserBalanceLogService; +import com.agileboot.domain.ab98.user_balance_log.dto.UserBalanceLogDTO; +import com.agileboot.domain.ab98.user_balance_log.model.UserBalanceLogModel; +import com.agileboot.domain.ab98.user_balance_log.model.UserBalanceLogModelFactory; +import com.agileboot.domain.ab98.user_balance_log.query.SearchUserBalanceLogQuery; +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-12-06 + */ +@Service +@RequiredArgsConstructor +public class UserBalanceLogApplicationService { + + private final UserBalanceLogService userBalanceLogService; + private final UserBalanceLogModelFactory userBalanceLogModelFactory; + + /** + * 新增用户余额变更日志 + * + * @param command 新增命令 + * @return 用户余额变更日志DTO + */ + @Transactional(rollbackFor = Exception.class) + public UserBalanceLogDTO add(AddUserBalanceLogCommand command) { + UserBalanceLogModel model = userBalanceLogModelFactory.create(command); + boolean success = model.save(); + if (!success) { + throw new RuntimeException("新增用户余额变更日志失败"); + } + return new UserBalanceLogDTO(model); + } + + /** + * 更新用户余额变更日志 + * + * @param command 更新命令 + * @return 用户余额变更日志DTO + */ + @Transactional(rollbackFor = Exception.class) + public UserBalanceLogDTO update(UpdateUserBalanceLogCommand command) { + UserBalanceLogModel model = userBalanceLogModelFactory.create(command); + boolean success = model.update(); + if (!success) { + throw new RuntimeException("更新用户余额变更日志失败"); + } + return new UserBalanceLogDTO(model); + } + + /** + * 根据ID删除用户余额变更日志 + * + * @param logId 主键ID + */ + @Transactional(rollbackFor = Exception.class) + public void delete(Long logId) { + if (logId == null) { + throw new IllegalArgumentException("日志ID不能为空"); + } + + boolean success = userBalanceLogService.removeById(logId); + if (!success) { + throw new RuntimeException("删除用户余额变更日志失败"); + } + } + + /** + * 根据ID查询用户余额变更日志 + * + * @param logId 主键ID + * @return 用户余额变更日志DTO + */ + public UserBalanceLogDTO getById(Long logId) { + if (logId == null) { + return null; + } + + UserBalanceLogEntity entity = userBalanceLogService.getById(logId); + return entity != null ? new UserBalanceLogDTO(entity) : null; + } + + /** + * 查询用户余额变更日志列表 + * + * @param query 查询参数 + * @return 用户余额变更日志分页DTO + */ + public PageDTO getList(SearchUserBalanceLogQuery query) { + // 构建查询条件 + Page page = query.toPage(); + UserBalanceLogEntity entity = new UserBalanceLogEntity(); + BeanUtil.copyProperties(query, entity); + + // 执行查询 + List entityList = userBalanceLogService.page(page, query.addQueryCondition()).getRecords(); + + // 转换为DTO + List dtoList = entityList.stream() + .map(UserBalanceLogDTO::new) + .collect(Collectors.toList()); + + // 获取总数 + Long total = page.getTotal(); + + return new PageDTO<>(dtoList, total); + } + + /** + * 批量删除用户余额变更日志 + * + * @param logIds 主键ID列表 + */ + @Transactional(rollbackFor = Exception.class) + public void batchDelete(List logIds) { + if (CollUtil.isEmpty(logIds)) { + throw new IllegalArgumentException("日志ID列表不能为空"); + } + + boolean success = userBalanceLogService.removeByIds(logIds); + if (!success) { + throw new RuntimeException("批量删除用户余额变更日志失败"); + } + } + + /** + * 根据用户余额ID查询变更日志列表 + * + * @param userBalanceId 用户余额ID + * @return 用户余额变更日志DTO列表 + */ + public List getByUserBalanceId(Long userBalanceId) { + if (userBalanceId == null) { + return null; + } + + List entityList = userBalanceLogService.getByUserBalanceId(userBalanceId); + if (CollUtil.isEmpty(entityList)) { + return null; + } + + return entityList.stream() + .map(UserBalanceLogDTO::new) + .collect(Collectors.toList()); + } + + /** + * 根据订单ID查询变更日志列表 + * + * @param orderId 订单ID + * @return 用户余额变更日志DTO列表 + */ + public List getByOrderId(Long orderId) { + if (orderId == null) { + return null; + } + + List entityList = userBalanceLogService.getByOrderId(orderId); + if (CollUtil.isEmpty(entityList)) { + return null; + } + + return entityList.stream() + .map(UserBalanceLogDTO::new) + .collect(Collectors.toList()); + } + + /** + * 根据审批ID查询变更日志列表 + * + * @param approvalId 审批ID + * @return 用户余额变更日志DTO列表 + */ + public List getByApprovalId(Long approvalId) { + if (approvalId == null) { + return null; + } + + List entityList = userBalanceLogService.getByApprovalId(approvalId); + if (CollUtil.isEmpty(entityList)) { + return null; + } + + return entityList.stream() + .map(UserBalanceLogDTO::new) + .collect(Collectors.toList()); + } + + /** + * 根据订单商品ID查询变更日志列表 + * + * @param orderGoodsId 订单商品ID + * @return 用户余额变更日志DTO列表 + */ + public List getByOrderGoodsId(Long orderGoodsId) { + if (orderGoodsId == null) { + return null; + } + + List entityList = userBalanceLogService.getByOrderGoodsId(orderGoodsId); + if (CollUtil.isEmpty(entityList)) { + return null; + } + + return entityList.stream() + .map(UserBalanceLogDTO::new) + .collect(Collectors.toList()); + } + + /** + * 根据变更类型查询变更日志列表 + * + * @param changeType 变更类型 + * @return 用户余额变更日志DTO列表 + */ + public List getByChangeType(Integer changeType) { + if (changeType == null) { + return null; + } + + List entityList = userBalanceLogService.getByChangeType(changeType); + if (CollUtil.isEmpty(entityList)) { + return null; + } + + return entityList.stream() + .map(UserBalanceLogDTO::new) + .collect(Collectors.toList()); + } + +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/command/AddUserBalanceLogCommand.java b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/command/AddUserBalanceLogCommand.java new file mode 100644 index 0000000..ca09e36 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/command/AddUserBalanceLogCommand.java @@ -0,0 +1,45 @@ +package com.agileboot.domain.ab98.user_balance_log.command; + +import com.agileboot.domain.ab98.user_balance_log.db.UserBalanceLogEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotNull; + +/** + *

+ * 新增用户余额变更日志命令 + *

+ * + * @author valarchie + * @since 2025-12-06 + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class AddUserBalanceLogCommand extends UserBalanceLogEntity { + + @NotNull(message = "用户余额ID不能为空") + private Long userBalanceId; + + @NotNull(message = "变更类型不能为空") + private Integer changeType; + + @NotNull(message = "变更金额不能为空") + private Long changeAmount; + + @NotNull(message = "变更前已用余额不能为空") + private Long useBalanceBefore; + + @NotNull(message = "变更后已用余额不能为空") + private Long useBalanceAfter; + + private Long orderId; + + private Long approvalId; + + private Long orderGoodsId; + + @NotNull(message = "创建者ID不能为空") + private Long creatorId; + +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/command/UpdateUserBalanceLogCommand.java b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/command/UpdateUserBalanceLogCommand.java new file mode 100644 index 0000000..a0145e6 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/command/UpdateUserBalanceLogCommand.java @@ -0,0 +1,24 @@ +package com.agileboot.domain.ab98.user_balance_log.command; + +import com.agileboot.domain.ab98.user_balance_log.db.UserBalanceLogEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotNull; + +/** + *

+ * 更新用户余额变更日志命令 + *

+ * + * @author valarchie + * @since 2025-12-06 + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class UpdateUserBalanceLogCommand extends AddUserBalanceLogCommand { + + @NotNull(message = "日志ID不能为空") + private Long logId; + +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/db/UserBalanceLogEntity.java b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/db/UserBalanceLogEntity.java new file mode 100644 index 0000000..040c5ca --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/db/UserBalanceLogEntity.java @@ -0,0 +1,79 @@ +package com.agileboot.domain.ab98.user_balance_log.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-12-06 + */ +@Getter +@Setter +@TableName("user_balance_log") +@ApiModel(value = "UserBalanceLogEntity对象", description = "用户余额变更日志表") +public class UserBalanceLogEntity extends BaseEntity { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("主键ID") + @TableId(value = "log_id", type = IdType.AUTO) + private Long logId; + + @ApiModelProperty("用户余额ID") + @TableField("user_balance_id") + private Long userBalanceId; + + @ApiModelProperty("变更类型(1-消费 2-审批归还 3-系统调整)") + @TableField("change_type") + private Integer changeType; + + @ApiModelProperty("变更金额(单位:分,正数表示增加,负数表示减少)") + @TableField("change_amount") + private Long changeAmount; + + @ApiModelProperty("变更前已用余额") + @TableField("use_balance_before") + private Long useBalanceBefore; + + @ApiModelProperty("变更后已用余额") + @TableField("use_balance_after") + private Long useBalanceAfter; + + @ApiModelProperty("关联订单ID") + @TableField("order_id") + private Long orderId; + + @ApiModelProperty("关联审批ID") + @TableField("approval_id") + private Long approvalId; + + @ApiModelProperty("关联订单商品ID") + @TableField("order_goods_id") + private Long orderGoodsId; + + @ApiModelProperty("创建者ID") + @TableField("creator_id") + private Long creatorId; + + @ApiModelProperty("更新者ID") + @TableField("updater_id") + private Long updaterId; + + + @Override + public Serializable pkVal() { + return this.logId; + } +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/db/UserBalanceLogMapper.java b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/db/UserBalanceLogMapper.java new file mode 100644 index 0000000..a3902a8 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/db/UserBalanceLogMapper.java @@ -0,0 +1,48 @@ +package com.agileboot.domain.ab98.user_balance_log.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; + +import java.util.List; + +/** + *

+ * 用户余额变更日志表 Mapper 接口 + *

+ * + * @author valarchie + * @since 2025-12-06 + */ +@Mapper +public interface UserBalanceLogMapper extends BaseMapper { + + /** + * 根据用户余额ID查询变更日志列表 + * + * @param userBalanceId 用户余额ID + * @return 变更日志列表 + */ + @Select("SELECT * FROM user_balance_log WHERE user_balance_id = #{userBalanceId} ORDER BY create_time DESC") + List selectByUserBalanceId(@Param("userBalanceId") Long userBalanceId); + + /** + * 根据订单ID查询变更日志列表 + * + * @param orderId 订单ID + * @return 变更日志列表 + */ + @Select("SELECT * FROM user_balance_log WHERE order_id = #{orderId} ORDER BY create_time DESC") + List selectByOrderId(@Param("orderId") Long orderId); + + /** + * 根据审批ID查询变更日志列表 + * + * @param approvalId 审批ID + * @return 变更日志列表 + */ + @Select("SELECT * FROM user_balance_log WHERE approval_id = #{approvalId} ORDER BY create_time DESC") + List selectByApprovalId(@Param("approvalId") Long approvalId); + +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/db/UserBalanceLogService.java b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/db/UserBalanceLogService.java new file mode 100644 index 0000000..0b105e9 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/db/UserBalanceLogService.java @@ -0,0 +1,57 @@ +package com.agileboot.domain.ab98.user_balance_log.db; + +import com.baomidou.mybatisplus.extension.service.IService; + +import java.util.List; + +/** + *

+ * 用户余额变更日志表 服务类 + *

+ * + * @author valarchie + * @since 2025-12-06 + */ +public interface UserBalanceLogService extends IService { + + /** + * 根据用户余额ID查询变更日志列表 + * + * @param userBalanceId 用户余额ID + * @return 变更日志列表 + */ + List getByUserBalanceId(Long userBalanceId); + + /** + * 根据订单ID查询变更日志列表 + * + * @param orderId 订单ID + * @return 变更日志列表 + */ + List getByOrderId(Long orderId); + + /** + * 根据审批ID查询变更日志列表 + * + * @param approvalId 审批ID + * @return 变更日志列表 + */ + List getByApprovalId(Long approvalId); + + /** + * 根据订单商品ID查询变更日志列表 + * + * @param orderGoodsId 订单商品ID + * @return 变更日志列表 + */ + List getByOrderGoodsId(Long orderGoodsId); + + /** + * 根据变更类型查询变更日志列表 + * + * @param changeType 变更类型 + * @return 变更日志列表 + */ + List getByChangeType(Integer changeType); + +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/db/UserBalanceLogServiceImpl.java b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/db/UserBalanceLogServiceImpl.java new file mode 100644 index 0000000..4b71dab --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/db/UserBalanceLogServiceImpl.java @@ -0,0 +1,95 @@ +package com.agileboot.domain.ab98.user_balance_log.db; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + *

+ * 用户余额变更日志表 服务实现类 + *

+ * + * @author valarchie + * @since 2025-12-06 + */ +@Service +public class UserBalanceLogServiceImpl extends ServiceImpl implements UserBalanceLogService { + + /** + * 根据用户余额ID查询变更日志列表 + * + * @param userBalanceId 用户余额ID + * @return 变更日志列表 + */ + @Override + public List getByUserBalanceId(Long userBalanceId) { + if (userBalanceId == null) { + return null; + } + return baseMapper.selectByUserBalanceId(userBalanceId); + } + + /** + * 根据订单ID查询变更日志列表 + * + * @param orderId 订单ID + * @return 变更日志列表 + */ + @Override + public List getByOrderId(Long orderId) { + if (orderId == null) { + return null; + } + return baseMapper.selectByOrderId(orderId); + } + + /** + * 根据审批ID查询变更日志列表 + * + * @param approvalId 审批ID + * @return 变更日志列表 + */ + @Override + public List getByApprovalId(Long approvalId) { + if (approvalId == null) { + return null; + } + return baseMapper.selectByApprovalId(approvalId); + } + + /** + * 根据订单商品ID查询变更日志列表 + * + * @param orderGoodsId 订单商品ID + * @return 变更日志列表 + */ + @Override + public List getByOrderGoodsId(Long orderGoodsId) { + if (orderGoodsId == null) { + return null; + } + return lambdaQuery() + .eq(UserBalanceLogEntity::getOrderGoodsId, orderGoodsId) + .orderByDesc(UserBalanceLogEntity::getCreateTime) + .list(); + } + + /** + * 根据变更类型查询变更日志列表 + * + * @param changeType 变更类型 + * @return 变更日志列表 + */ + @Override + public List getByChangeType(Integer changeType) { + if (changeType == null) { + return null; + } + return lambdaQuery() + .eq(UserBalanceLogEntity::getChangeType, changeType) + .orderByDesc(UserBalanceLogEntity::getCreateTime) + .list(); + } + +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/dto/UserBalanceLogDTO.java b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/dto/UserBalanceLogDTO.java new file mode 100644 index 0000000..f553f6b --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/dto/UserBalanceLogDTO.java @@ -0,0 +1,71 @@ +package com.agileboot.domain.ab98.user_balance_log.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_log.db.UserBalanceLogEntity; +import lombok.Data; + +/** + *

+ * 用户余额变更日志DTO + *

+ * + * @author valarchie + * @since 2025-12-06 + */ +@ExcelSheet(name = "用户余额变更日志") +@Data +public class UserBalanceLogDTO { + + public UserBalanceLogDTO() {} + + public UserBalanceLogDTO(UserBalanceLogEntity entity) { + if (entity != null) { + BeanUtil.copyProperties(entity, this); + } + } + + @ExcelColumn(name = "主键ID") + private Long logId; + + @ExcelColumn(name = "用户余额ID") + private Long userBalanceId; + + @ExcelColumn(name = "变更类型(1-消费,2-审批归还,3-系统调整)") + private Integer changeType; + + @ExcelColumn(name = "变更金额(分)") + private Long changeAmount; + + @ExcelColumn(name = "变更前已用余额(分)") + private Long useBalanceBefore; + + @ExcelColumn(name = "变更后已用余额(分)") + private Long useBalanceAfter; + + @ExcelColumn(name = "关联订单ID") + private Long orderId; + + @ExcelColumn(name = "关联审批ID") + private Long approvalId; + + @ExcelColumn(name = "关联订单商品ID") + private Long orderGoodsId; + + @ExcelColumn(name = "创建者ID") + private Long creatorId; + + @ExcelColumn(name = "创建时间") + private String createTime; + + @ExcelColumn(name = "更新者ID") + private Long updaterId; + + @ExcelColumn(name = "更新时间") + private String updateTime; + + @ExcelColumn(name = "删除标志") + private Boolean deleted; + +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/model/UserBalanceLogModel.java b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/model/UserBalanceLogModel.java new file mode 100644 index 0000000..55df430 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/model/UserBalanceLogModel.java @@ -0,0 +1,133 @@ +package com.agileboot.domain.ab98.user_balance_log.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_log.command.AddUserBalanceLogCommand; +import com.agileboot.domain.ab98.user_balance_log.command.UpdateUserBalanceLogCommand; +import com.agileboot.domain.ab98.user_balance_log.db.UserBalanceLogEntity; +import com.agileboot.domain.ab98.user_balance_log.db.UserBalanceLogService; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + *

+ * 用户余额变更日志领域模型 + *

+ * + * @author valarchie + * @since 2025-12-06 + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class UserBalanceLogModel extends UserBalanceLogEntity { + + private UserBalanceLogService userBalanceLogService; + + public UserBalanceLogModel() {} + + public UserBalanceLogModel(UserBalanceLogEntity entity, UserBalanceLogService userBalanceLogService) { + this.userBalanceLogService = userBalanceLogService; + if (entity != null) { + BeanUtil.copyProperties(entity, this); + } + } + + public UserBalanceLogModel(UserBalanceLogService userBalanceLogService) { + this.userBalanceLogService = userBalanceLogService; + } + + /** + * 从新增命令加载数据 + * + * @param command 新增命令 + */ + public void loadAddCommand(AddUserBalanceLogCommand command) { + if (command != null) { + BeanUtil.copyProperties(command, this, "logId"); + } + } + + /** + * 从更新命令加载数据 + * + * @param command 更新命令 + */ + public void loadUpdateCommand(UpdateUserBalanceLogCommand command) { + if (command != null) { + loadAddCommand(command); + if (command.getLogId() != null) { + this.setLogId(command.getLogId()); + } + } + } + + /** + * 验证变更类型是否有效 + * + * @param changeType 变更类型 + * @throws ApiException 无效变更类型异常 + */ + public void validateChangeType(Integer changeType) { + if (changeType == null || changeType < 1 || changeType > 3) { + throw new ApiException(ErrorCode.Business.VALUE_NOT_ALLOWED, "变更类型", "1-消费, 2-审批归还, 3-系统调整"); + } + } + + /** + * 验证变更金额是否有效 + * + * @param changeAmount 变更金额 + * @throws ApiException 无效变更金额异常 + */ + public void validateChangeAmount(Long changeAmount) { + if (changeAmount == null) { + throw new ApiException(ErrorCode.Business.VALUE_NOT_ALLOWED, "变更金额", "不能为空"); + } + } + + /** + * 验证变更前后的已用余额 + * + * @param useBalanceBefore 变更前已用余额 + * @param useBalanceAfter 变更后已用余额 + * @throws ApiException 已用余额异常 + */ + public void validateUseBalance(Long useBalanceBefore, Long useBalanceAfter) { + if (useBalanceBefore == null || useBalanceBefore < 0) { + throw new ApiException(ErrorCode.Business.VALUE_NOT_ALLOWED, "变更前已用余额", "不能为空且不能为负数"); + } + + if (useBalanceAfter == null || useBalanceAfter < 0) { + throw new ApiException(ErrorCode.Business.VALUE_NOT_ALLOWED, "变更后已用余额", "不能为空且不能为负数"); + } + } + + /** + * 保存到数据库 + * + * @return 是否成功 + */ + public boolean save() { + return userBalanceLogService.save(this); + } + + /** + * 更新到数据库 + * + * @return 是否成功 + */ + public boolean update() { + return userBalanceLogService.updateById(this); + } + + /** + * 从数据库删除 + * + * @return 是否成功 + */ + public boolean remove() { + return userBalanceLogService.removeById(this.getLogId()); + } + +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/model/UserBalanceLogModelFactory.java b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/model/UserBalanceLogModelFactory.java new file mode 100644 index 0000000..b3b741c --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/model/UserBalanceLogModelFactory.java @@ -0,0 +1,67 @@ +package com.agileboot.domain.ab98.user_balance_log.model; + +import com.agileboot.domain.ab98.user_balance_log.command.AddUserBalanceLogCommand; +import com.agileboot.domain.ab98.user_balance_log.command.UpdateUserBalanceLogCommand; +import com.agileboot.domain.ab98.user_balance_log.db.UserBalanceLogEntity; +import com.agileboot.domain.ab98.user_balance_log.db.UserBalanceLogService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +/** + *

+ * 用户余额变更日志领域模型工厂 + *

+ * + * @author valarchie + * @since 2025-12-06 + */ +@Component +@RequiredArgsConstructor +public class UserBalanceLogModelFactory { + + private final UserBalanceLogService userBalanceLogService; + + /** + * 创建空的用户余额变更日志模型 + * + * @return 用户余额变更日志模型 + */ + public UserBalanceLogModel create() { + return new UserBalanceLogModel(userBalanceLogService); + } + + /** + * 根据新增命令创建用户余额变更日志模型 + * + * @param command 新增命令 + * @return 用户余额变更日志模型 + */ + public UserBalanceLogModel create(AddUserBalanceLogCommand command) { + UserBalanceLogModel model = create(); + model.loadAddCommand(command); + return model; + } + + /** + * 根据更新命令创建用户余额变更日志模型 + * + * @param command 更新命令 + * @return 用户余额变更日志模型 + */ + public UserBalanceLogModel create(UpdateUserBalanceLogCommand command) { + UserBalanceLogModel model = create(); + model.loadUpdateCommand(command); + return model; + } + + /** + * 根据实体创建用户余额变更日志模型 + * + * @param entity 实体 + * @return 用户余额变更日志模型 + */ + public UserBalanceLogModel create(UserBalanceLogEntity entity) { + return new UserBalanceLogModel(entity, userBalanceLogService); + } + +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/query/SearchUserBalanceLogQuery.java b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/query/SearchUserBalanceLogQuery.java new file mode 100644 index 0000000..2041dc6 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user_balance_log/query/SearchUserBalanceLogQuery.java @@ -0,0 +1,59 @@ +package com.agileboot.domain.ab98.user_balance_log.query; + +import cn.hutool.core.util.StrUtil; +import com.agileboot.common.core.page.AbstractPageQuery; +import com.agileboot.domain.ab98.user_balance_log.db.UserBalanceLogEntity; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + *

+ * 用户余额变更日志查询参数 + *

+ * + * @author valarchie + * @since 2025-12-06 + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class SearchUserBalanceLogQuery extends AbstractPageQuery { + + @ApiModelProperty("用户余额ID") + private Long userBalanceId; + + @ApiModelProperty("变更类型(1-消费, 2-审批归还, 3-系统调整)") + private Integer changeType; + + @ApiModelProperty("关联订单ID") + private Long orderId; + + @ApiModelProperty("关联审批ID") + private Long approvalId; + + @ApiModelProperty("关联订单商品ID") + private Long orderGoodsId; + + @ApiModelProperty("创建者ID") + private Long creatorId; + + @Override + public QueryWrapper addQueryCondition() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + + queryWrapper + .eq(userBalanceId != null, "user_balance_id", userBalanceId) + .eq(changeType != null, "change_type", changeType) + .eq(orderId != null, "order_id", orderId) + .eq(approvalId != null, "approval_id", approvalId) + .eq(orderGoodsId != null, "order_goods_id", orderGoodsId) + .eq(creatorId != null, "creator_id", creatorId) + .eq("deleted", false); + + this.timeRangeColumn = "create_time"; + + return queryWrapper; + } + +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/shop/approval/ReturnApprovalApplicationService.java b/agileboot-domain/src/main/java/com/agileboot/domain/shop/approval/ReturnApprovalApplicationService.java index 3d52737..875ab48 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/shop/approval/ReturnApprovalApplicationService.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/shop/approval/ReturnApprovalApplicationService.java @@ -7,6 +7,9 @@ import com.agileboot.common.utils.MoneyUtil; 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_log.command.AddUserBalanceLogCommand; +import com.agileboot.domain.ab98.user_balance_log.model.UserBalanceLogModelFactory; + import org.springframework.beans.factory.annotation.Autowired; import com.agileboot.common.constant.UrlConstants; import com.agileboot.common.constant.WeixinConstants; @@ -117,6 +120,7 @@ public class ReturnApprovalApplicationService { private final CabinetCellOperationModelFactory cabinetCellOperationModelFactory; private final MqttService mqttService; private final UserBalanceService userBalanceService; + private final UserBalanceLogModelFactory userBalanceLogModelFactory; @Autowired private WxshopConfig wxshopConfig; @@ -281,9 +285,33 @@ public class ReturnApprovalApplicationService { if (null == userBalance) { throw new IllegalArgumentException("用户余额不存在"); } - userBalance.setBalance(userBalance.getBalance() + MoneyUtil.yuanToFen(command.getReturnAmount())); - userBalance.setUseBalance(userBalance.getUseBalance() - MoneyUtil.yuanToFen(command.getReturnAmount())); + + // 记录变更前的余额信息 + Long useBalanceBefore = userBalance.getUseBalance(); + Long changeAmountFen = MoneyUtil.yuanToFen(command.getReturnAmount()); + + // 更新余额 + userBalance.setBalance(userBalance.getBalance() + changeAmountFen); + userBalance.setUseBalance(userBalance.getUseBalance() - changeAmountFen); userBalance.updateById(); + + try { + // 记录余额变更日志 + AddUserBalanceLogCommand logCommand = new AddUserBalanceLogCommand(); + logCommand.setUserBalanceId(userBalance.getUserBalanceId()); + logCommand.setChangeType(2); // 2-审批归还 + logCommand.setChangeAmount(-changeAmountFen); // 审批归还为负数 + logCommand.setUseBalanceBefore(useBalanceBefore); + logCommand.setUseBalanceAfter(userBalance.getUseBalance()); + logCommand.setOrderId(orderModel.getOrderId()); + logCommand.setApprovalId(model.getApprovalId()); + logCommand.setOrderGoodsId(orderGoodsModel.getOrderGoodsId()); + logCommand.initBaseEntity(); + + userBalanceLogModelFactory.create(logCommand).insert(); + } catch (Exception e) { + log.error("记录余额变更日志失败", e); + } /*if (null != qyUser) { qyUser.setBalance(qyUser.getBalance().add(command.getReturnAmount())); qyUser.setUseBalance(qyUser.getUseBalance().subtract(command.getReturnAmount())); diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/shop/order/OrderApplicationService.java b/agileboot-domain/src/main/java/com/agileboot/domain/shop/order/OrderApplicationService.java index c527a3e..26278b4 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/shop/order/OrderApplicationService.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/shop/order/OrderApplicationService.java @@ -7,6 +7,8 @@ import com.agileboot.common.utils.MoneyUtil; 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_log.command.AddUserBalanceLogCommand; +import com.agileboot.domain.ab98.user_balance_log.model.UserBalanceLogModelFactory; import org.springframework.beans.factory.annotation.Autowired; import com.agileboot.common.core.page.PageDTO; import com.agileboot.common.exception.ApiException; @@ -105,6 +107,7 @@ public class OrderApplicationService { private final Ab98UserService ab98UserService; private final WxUserService wxUserService; private final UserBalanceService userBalanceService; + private final UserBalanceLogModelFactory userBalanceLogModelFactory; @Autowired private WxshopConfig wxshopConfig; @@ -260,9 +263,28 @@ public class OrderApplicationService { if (userBalance.getBalance().compareTo(MoneyUtil.yuanToFen(orderModel.getTotalAmount())) < 0) { throw new ApiException(ErrorCode.Client.COMMON_REQUEST_PARAMETERS_INVALID, "余额不足"); } else { - userBalance.setBalance(userBalance.getBalance() - MoneyUtil.yuanToFen(orderModel.getTotalAmount())); - userBalance.setUseBalance(userBalance.getUseBalance() + MoneyUtil.yuanToFen(orderModel.getTotalAmount())); + // 记录变更前的余额信息 + Long useBalanceBefore = userBalance.getUseBalance(); + Long changeAmount = MoneyUtil.yuanToFen(orderModel.getTotalAmount()); + + userBalance.setBalance(userBalance.getBalance() - changeAmount); + userBalance.setUseBalance(userBalance.getUseBalance() + changeAmount); userBalanceService.updateById(userBalance); + + try { + // 记录余额变动日志 + AddUserBalanceLogCommand logCommand = new AddUserBalanceLogCommand(); + logCommand.setUserBalanceId(userBalance.getUserBalanceId()); + logCommand.setChangeType(1); // 1-消费 + logCommand.setChangeAmount(changeAmount); // 消费为正数 + logCommand.setUseBalanceBefore(useBalanceBefore); + logCommand.setUseBalanceAfter(userBalance.getUseBalance()); + logCommand.setOrderId(orderModel.getOrderId()); + logCommand.setCreatorId(orderModel.getCreatorId()); + userBalanceLogModelFactory.create(logCommand).save(); + } catch (Exception e) { + log.error("记录余额变动日志失败", e); + } } // 金额转换(元转分)并四舍五入 diff --git a/sql/20251206_user_balance_log.sql b/sql/20251206_user_balance_log.sql new file mode 100644 index 0000000..1d7aee5 --- /dev/null +++ b/sql/20251206_user_balance_log.sql @@ -0,0 +1,30 @@ +CREATE TABLE `user_balance_log` ( + `log_id` bigint NOT NULL AUTO_INCREMENT COMMENT '日志ID', + `user_balance_id` bigint NOT NULL COMMENT '用户余额ID', + + -- 余额变更信息 + `change_type` tinyint NOT NULL COMMENT '变更类型(1-消费 2-审批归还 3-系统调整)', + `change_amount` bigint NOT NULL COMMENT '变更金额(单位:分,正数表示增加,负数表示减少)', + `use_balance_before` bigint NOT NULL COMMENT '变更前已用余额', + `use_balance_after` bigint NOT NULL COMMENT '变更后已用余额', + + -- 关联表信息 + `order_id` bigint DEFAULT NULL COMMENT '关联订单ID', + `approval_id` bigint DEFAULT NULL COMMENT '关联审批ID', + `order_goods_id` bigint DEFAULT NULL COMMENT '关联订单商品ID', + + -- 系统字段 + `creator_id` bigint NOT NULL DEFAULT 0 COMMENT '创建者ID', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater_id` bigint NOT NULL DEFAULT 0 COMMENT '更新者ID', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` tinyint(1) NOT NULL DEFAULT 0 COMMENT '删除标志(0存在 1删除)', + + PRIMARY KEY (`log_id`), + KEY `idx_user_balance` (`user_balance_id`), + KEY `idx_order` (`order_id`), + KEY `idx_approval` (`approval_id`), + KEY `idx_change_type` (`change_type`), + KEY `idx_create_time` (`create_time`), + KEY `idx_order_goods` (`order_goods_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户余额变更日志表';