diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationApiImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationApiImpl.java index 6c8ac989d..30d4a5cb0 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationApiImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationApiImpl.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.api.combination; import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO; import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService; import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; @@ -12,6 +13,7 @@ import javax.annotation.Resource; * @author HUIHUI */ @Service +@Validated public class CombinationApiImpl implements CombinationApi { @Resource diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImpl.java index 1471353e8..2becc6b01 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImpl.java @@ -22,6 +22,7 @@ import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationActivi import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationProductMapper; import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -52,7 +53,9 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic private CombinationActivityMapper combinationActivityMapper; @Resource private CombinationProductMapper combinationProductMapper; + @Resource + @Lazy // TODO @puhui999:我感觉 validateCombination 可以挪到 CombinationRecordServiceImpl 中,因为它更偏向能不能创建拼团记录; private CombinationRecordService combinationRecordService; @Resource diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderOperateTypeEnum.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderOperateTypeEnum.java new file mode 100644 index 000000000..f16e35601 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderOperateTypeEnum.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.trade.enums.order; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * 订单操作类型的枚举 + * + * @author 陈賝 + * @since 2023/7/6 15:31 + */ +@RequiredArgsConstructor +@Getter +public enum TradeOrderOperateTypeEnum { + + MEMBER_CREATE(1, "用户下单"), + TEST(2, "用户({nickname})做了({thing})"), + ; + + /** + * 类型 + */ + private final Integer type; + /** + * 类型 + */ + private final String content; + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java index 4a53b6684..888a3d4df 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.trade.controller.app.order; +import cn.hutool.core.map.MapUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; @@ -11,8 +12,11 @@ import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderOperateTypeEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; +import cn.iocoder.yudao.module.trade.framework.order.core.annotations.TradeOrderLog; +import cn.iocoder.yudao.module.trade.framework.order.core.utils.TradeOrderLogUtils; import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService; @@ -61,7 +65,10 @@ public class AppTradeOrderController { @PostMapping("/create") @Operation(summary = "创建订单") @PreAuthenticated + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.TEST) public CommonResult createOrder(@RequestBody AppTradeOrderCreateReqVO createReqVO) { + TradeOrderLogUtils.setOrderInfo(10L, 1, 2, + MapUtil.builder().put("nickname", "小明").put("thing", "种土豆").build()); TradeOrderDO order = tradeOrderUpdateService.createOrder(getLoginUserId(), getClientIP(), createReqVO); return success(new AppTradeOrderCreateRespVO().setId(order.getId()).setPayOrderId(order.getPayOrderId())); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderLogDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderLogDO.java new file mode 100644 index 000000000..36022c16e --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderLogDO.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.trade.dal.dataobject.order; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderOperateTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 订单日志 DO + * + * @author 陈賝 + */ +@TableName("trade_order_log") +@KeySequence("trade_order_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TradeOrderLogDO extends BaseDO { + + /** + * 用户类型 - 系统 + * + * 例如说:Job 自动过期订单时,通过系统自动操作 + */ + public static final Integer USER_TYPE_SYSTEM = 0; + /** + * 用户编号 - 系统 + */ + public static final Long USER_ID_SYSTEM = 0L; + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 用户编号 + * + * 关联 AdminUserDO 的 id 字段、或者 MemberUserDO 的 id 字段 + */ + private Long userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + + /** + * 订单号 + * + * 关联 {@link TradeOrderDO#getId()} + */ + private Long orderId; + /** + * 操作前状态 + */ + private Integer beforeStatus; + /** + * 操作后状态 + */ + private Integer afterStatus; + + /** + * 操作类型 + * + * {@link TradeOrderOperateTypeEnum} + */ + private Integer operateType; + /** + * 订单日志信息 + */ + private String content; + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/annotations/TradeOrderLog.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/annotations/TradeOrderLog.java new file mode 100644 index 000000000..03a484b56 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/annotations/TradeOrderLog.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.trade.framework.order.core.annotations; + +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderOperateTypeEnum; + +import java.lang.annotation.*; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.METHOD; + +/** + * 交易订单的操作日志 AOP 注解 + * + * @author 陈賝 + * @since 2023/7/6 15:37 + */ +@Target({METHOD, ANNOTATION_TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface TradeOrderLog { + + /** + * 操作类型 + */ + TradeOrderOperateTypeEnum operateType(); + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/aop/TradeOrderLogAspect.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/aop/TradeOrderLogAspect.java new file mode 100644 index 000000000..e8349220f --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/aop/TradeOrderLogAspect.java @@ -0,0 +1,112 @@ +package cn.iocoder.yudao.module.trade.framework.order.core.aop; + + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderLogDO; +import cn.iocoder.yudao.module.trade.framework.order.core.annotations.TradeOrderLog; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderLogService; +import cn.iocoder.yudao.module.trade.service.order.bo.logger.TradeOrderLogCreateReqBO; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; +import static java.util.Collections.emptyMap; + +/** + * 交易订单的操作日志的记录 AOP 切面 + * + * @author 陈賝 + * @since 2023/6/13 13:54 + */ +@Component +@Aspect +@Slf4j +public class TradeOrderLogAspect { + + /** + * 订单编号 + */ + private static final ThreadLocal ORDER_ID = new ThreadLocal<>(); + /** + * 操作前的状态 + */ + private static final ThreadLocal BEFORE_STATUS = new ThreadLocal<>(); + /** + * 操作后的状态 + */ + private static final ThreadLocal AFTER_STATUS = new ThreadLocal<>(); + /** + * 拓展参数 Map,用于格式化操作内容 + */ + private static final ThreadLocal> EXTS = new ThreadLocal<>(); + + public TradeOrderLogAspect() { + System.out.println(); + } + + @Resource + private TradeOrderLogService orderLogService; + + @AfterReturning("@annotation(orderLog)") + public void doAfterReturning(JoinPoint joinPoint, TradeOrderLog orderLog) { + try { + // 1.1 操作用户 + Integer userType = getUserType(); + Long userId = getUserId(); + // 1.2 订单信息 + Long orderId = ORDER_ID.get(); + Integer beforeStatus = BEFORE_STATUS.get(); + Integer afterStatus = AFTER_STATUS.get(); + Map exts = ObjectUtil.defaultIfNull(EXTS.get(), emptyMap()); + String content = StrUtil.format(orderLog.operateType().getContent(), exts); + + // 2.1 记录日志 + TradeOrderLogCreateReqBO createBO = new TradeOrderLogCreateReqBO() + .setUserId(userId).setUserType(userType) + .setOrderId(orderId).setBeforeStatus(beforeStatus).setAfterStatus(afterStatus) + .setOperateType(orderLog.operateType().getType()).setContent(content); + orderLogService.createOrderLog(createBO); + } catch (Exception ex) { + // todo 芋艿:清理上下文 + log.error("[doAfterReturning][orderLog({}) 订单日志错误]", toJsonString(orderLog), ex); + } + } + + /** + * 获得用户类型 + * + * 如果没有,则约定为 {@link TradeOrderLogDO#getUserType()} 系统 + * + * @return 用户类型 + */ + private static Integer getUserType() { + return ObjectUtil.defaultIfNull(WebFrameworkUtils.getLoginUserType(), TradeOrderLogDO.USER_TYPE_SYSTEM); + } + + /** + * 获得用户编号 + * + * 如果没有,则约定为 {@link TradeOrderLogDO#getUserId()} 系统 + * + * @return 用户类型 + */ + private static Long getUserId() { + return ObjectUtil.defaultIfNull(WebFrameworkUtils.getLoginUserId(), TradeOrderLogDO.USER_ID_SYSTEM); + } + + public static void setOrderInfo(Long id, Integer beforeStatus, Integer afterStatus, Map exts) { + ORDER_ID.set(id); + BEFORE_STATUS.set(beforeStatus); + AFTER_STATUS.set(afterStatus); + EXTS.set(exts); + } + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/utils/TradeOrderLogUtils.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/utils/TradeOrderLogUtils.java new file mode 100644 index 000000000..0fd2a65a7 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/utils/TradeOrderLogUtils.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.trade.framework.order.core.utils; + +import cn.iocoder.yudao.module.trade.framework.order.core.aop.TradeOrderLogAspect; + +import java.util.Map; + +/** + * 交易订单的操作日志 Utils + * + * @author 芋道源码 + */ +public class TradeOrderLogUtils { + + public static void setOrderInfo(Long id, Integer beforeStatus, Integer afterStatus) { + TradeOrderLogAspect.setOrderInfo(id, beforeStatus, afterStatus, null); + } + + public static void setOrderInfo(Long id, Integer beforeStatus, Integer afterStatus, + Map exts) { + TradeOrderLogAspect.setOrderInfo(id, beforeStatus, afterStatus, exts); + } + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderLogService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderLogService.java new file mode 100644 index 000000000..d927aede0 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderLogService.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.trade.service.order; + +import cn.iocoder.yudao.module.trade.service.order.bo.logger.TradeOrderLogCreateReqBO; +import org.springframework.scheduling.annotation.Async; + +/** + * 交易下单日志 Service 接口 + * + * @author 陈賝 + * @since 2023/7/6 15:44 + */ +public interface TradeOrderLogService { + + /** + * 创建交易下单日志 + * + * @param logDTO 日志记录 + * @author 陈賝 + * @since 2023/7/6 15:45 + */ + @Async + void createOrderLog(TradeOrderLogCreateReqBO logDTO); + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderLogServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderLogServiceImpl.java new file mode 100644 index 000000000..327f92daf --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderLogServiceImpl.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.trade.service.order; + +import cn.iocoder.yudao.module.trade.service.order.bo.logger.TradeOrderLogCreateReqBO; +import org.springframework.stereotype.Service; + +/** + * 交易下单日志 Service 实现类 + * + * @author 陈賝 + * @since 2023/7/6 15:44 + */ +@Service +public class TradeOrderLogServiceImpl implements TradeOrderLogService { + + @Override + public void createOrderLog(TradeOrderLogCreateReqBO createReqBO) { + // TODO 芋艿:存储还没搞 + System.out.println(); + } + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/logger/TradeOrderLogCreateReqBO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/logger/TradeOrderLogCreateReqBO.java new file mode 100644 index 000000000..a92fec2da --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/bo/logger/TradeOrderLogCreateReqBO.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.trade.service.order.bo.logger; + +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 订单日志的创建 Request BO + * + * @author 陈賝 + * @since 2023/7/6 15:27 + */ +@Data +public class TradeOrderLogCreateReqBO { + + /** + * 用户编号 + */ + @NotNull(message = "用户编号不能为空") + private Long userId; + /** + * 用户类型 + */ + @NotNull(message = "用户类型不能为空") + private Integer userType; + + /** + * 订单编号 + */ + @NotNull(message = "订单编号") + private Long orderId; + /** + * 操作前状态 + */ + private Integer beforeStatus; + /** + * 操作后状态 + */ + @NotNull(message = "操作后的状态不能为空") + private Integer afterStatus; + + /** + * 操作类型 + */ + private Integer operateType; + /** + * 操作明细 + */ + private String content; + +}