diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java index 414c0af7d..6bbdcc7cf 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java @@ -23,6 +23,10 @@ public class LocalDateTimeUtils { return LocalDateTime.now().plus(duration); } + public static LocalDateTime minusTime(Duration duration) { + return LocalDateTime.now().minus(duration); + } + public static boolean beforeNow(LocalDateTime date) { return date.isBefore(LocalDateTime.now()); } 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 index 9148f2f66..1d803ed6c 100644 --- 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 @@ -18,6 +18,7 @@ public enum TradeOrderOperateTypeEnum { MEMBER_RECEIVE(30, "用户已收货"), SYSTEM_RECEIVE(31, "到期未收货,系统自动确认收货"), MEMBER_COMMENT(33, "用户评价"), + SYSTEM_COMMENT(34, "到期未评价,系统自动评价"), MEMBER_CANCEL(40, "取消订单"), SYSTEM_CANCEL(41, "到期未支付,系统自动取消订单"), // 42 预留:管理员取消订单 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 dc472e58c..36292e993 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 @@ -173,7 +173,7 @@ public class AppTradeOrderController { @PostMapping("/item/create-comment") @Operation(summary = "创建交易订单项的评价") public CommonResult createOrderItemComment(@RequestBody AppTradeOrderItemCommentCreateReqVO createReqVO) { - return success(tradeOrderUpdateService.createOrderItemComment(getLoginUserId(), createReqVO)); + return success(tradeOrderUpdateService.createOrderItemCommentByMember(getLoginUserId(), createReqVO)); } } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java index e7121077b..4240c6fde 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java @@ -38,4 +38,10 @@ public interface TradeOrderItemMapper extends BaseMapperX { .eq(TradeOrderItemDO::getUserId, loginUserId)); } + default List selectListByOrderIdAndCommentStatus(Long orderId, Boolean commentStatus) { + return selectList(new LambdaQueryWrapperX() + .eq(TradeOrderItemDO::getOrderId, orderId) + .eq(TradeOrderItemDO::getCommentStatus, commentStatus)); + } + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java index 5d5ba737b..b360cfa0e 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java @@ -73,4 +73,12 @@ public interface TradeOrderMapper extends BaseMapperX { .lt(TradeOrderDO::getDeliveryTime, deliveryTime)); } + default List selectListByStatusAndReceiveTimeLt(Integer status, LocalDateTime receive, + Boolean commentStatus) { + return selectList(new LambdaUpdateWrapper() + .eq(TradeOrderDO::getStatus, status) + .lt(TradeOrderDO::getReceiveTime, receive) + .eq(TradeOrderDO::getCommentStatus, commentStatus)); + } + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/config/TradeOrderProperties.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/config/TradeOrderProperties.java index 913eb7a80..786c0004b 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/config/TradeOrderProperties.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/config/TradeOrderProperties.java @@ -36,4 +36,10 @@ public class TradeOrderProperties { @NotNull(message = "收货超时时间不能为空") private Duration receiveExpireTime; + /** + * 评论超时时间 + */ + @NotNull(message = "评论超时时间不能为空") + private Duration commentExpireTime; + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/order/TradeOrderAutoCommentJob.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/order/TradeOrderAutoCommentJob.java new file mode 100644 index 000000000..c8f2c82c7 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/order/TradeOrderAutoCommentJob.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.trade.job.order; + +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; +import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 交易订单的自动评论 Job + * + * @author 芋道源码 + */ +@Component +@TenantJob +public class TradeOrderAutoCommentJob implements JobHandler { + + @Resource + private TradeOrderUpdateService tradeOrderUpdateService; + + @Override + public String execute(String param) { + int count = tradeOrderUpdateService.createOrderItemCommentBySystem(); + return String.format("评论订单 %s 个", count); + } + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java index f612d0ca4..e9959715d 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java @@ -142,12 +142,19 @@ public interface TradeOrderUpdateService { void updateOrderItemWhenAfterSaleCancel(@NotNull Long id); /** - * 创建订单项的评论 + * 【会员】创建订单项的评论 * * @param userId 用户编号 * @param createReqVO 创建请求 * @return 得到评价 id */ - Long createOrderItemComment(Long userId, AppTradeOrderItemCommentCreateReqVO createReqVO); + Long createOrderItemCommentByMember(Long userId, AppTradeOrderItemCommentCreateReqVO createReqVO); + + /** + * 【系统】创建订单项的评论 + * + * @return 被评论的订单数 + */ + int createOrderItemCommentBySystem(); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java index 6f980594b..8c4e5d67d 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java @@ -74,7 +74,7 @@ import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.minusTime; import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; /** @@ -496,7 +496,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @Override public int receiveOrderBySystem() { // 1. 查询过期的待支付订单 - LocalDateTime expireTime = addTime(tradeOrderProperties.getReceiveExpireTime()); + LocalDateTime expireTime = minusTime(tradeOrderProperties.getReceiveExpireTime()); List orders = tradeOrderMapper.selectListByStatusAndDeliveryTimeLt( TradeOrderStatusEnum.DELIVERED.getStatus(), expireTime); if (CollUtil.isEmpty(orders)) { @@ -510,7 +510,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { getSelf().receiveOrderBySystem(order); count++; } catch (Throwable e) { - log.error("[autoReceiveOrder][order({}) 自动收货订单异常]", order.getId(), e); + log.error("[receiveOrderBySystem][order({}) 自动收货订单异常]", order.getId(), e); } } return count; @@ -587,7 +587,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @Override public int cancelOrderBySystem() { // 1. 查询过期的待支付订单 - LocalDateTime expireTime = addTime(tradeOrderProperties.getPayExpireTime()); + LocalDateTime expireTime = minusTime(tradeOrderProperties.getPayExpireTime()); List orders = tradeOrderMapper.selectListByStatusAndCreateTimeLt( TradeOrderStatusEnum.UNPAID.getStatus(), expireTime); if (CollUtil.isEmpty(orders)) { @@ -601,7 +601,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { getSelf().cancelOrderBySystem(order); count++; } catch (Throwable e) { - log.error("[autoCancelOrder][order({}) 过期订单异常]", order.getId(), e); + log.error("[cancelOrderBySystem][order({}) 过期订单异常]", order.getId(), e); } } return count; @@ -723,7 +723,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { } tradeOrderItemMapper.updateBatch(updateItems); - // 6、更新支付订单 payOrderApi.updatePayOrderPrice(order.getPayOrderId(), update.getPayPrice()); } @@ -845,41 +844,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { couponApi.returnUsedCoupon(order.getCouponId()); } - @Override - @Transactional(rollbackFor = Exception.class) - @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_COMMENT) - public Long createOrderItemComment(Long userId, AppTradeOrderItemCommentCreateReqVO createReqVO) { - // 先通过订单项 ID,查询订单项是否存在 - TradeOrderItemDO orderItem = tradeOrderItemMapper.selectByIdAndUserId(createReqVO.getOrderItemId(), userId); - if (orderItem == null) { - throw exception(ORDER_ITEM_NOT_FOUND); - } - // 校验订单相关状态 - TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(orderItem.getOrderId(), userId); - if (order == null) { - throw exception(ORDER_NOT_FOUND); - } - if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus())) { - throw exception(ORDER_COMMENT_FAIL_STATUS_NOT_COMPLETED); - } - if (ObjectUtil.notEqual(order.getCommentStatus(), Boolean.FALSE)) { - throw exception(ORDER_COMMENT_STATUS_NOT_FALSE); - } - - // 1. 创建评价 - ProductCommentCreateReqDTO productCommentCreateReqDTO = TradeOrderConvert.INSTANCE.convert04(createReqVO, orderItem); - Long comment = productCommentApi.createComment(productCommentCreateReqDTO); - - // 2. 更新订单项评价状态 - tradeOrderItemMapper.updateById(new TradeOrderItemDO().setId(orderItem.getId()).setCommentStatus(Boolean.TRUE)); - List orderItems = tradeOrderItemMapper.selectListByOrderId(order.getId()); - if (!anyMatch(orderItems, item -> Objects.equals(item.getCommentStatus(), Boolean.FALSE))) { - tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()).setCommentStatus(Boolean.TRUE)); - // 增加订单日志 - TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus()); - } - return comment; - } /** * 判断指定订单的所有订单项,是不是都售后成功 @@ -893,6 +857,114 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus())); } + @Override + @Transactional(rollbackFor = Exception.class) + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_COMMENT) + public Long createOrderItemCommentByMember(Long userId, AppTradeOrderItemCommentCreateReqVO createReqVO) { + // 1.1 先通过订单项 ID,查询订单项是否存在 + TradeOrderItemDO orderItem = tradeOrderItemMapper.selectByIdAndUserId(createReqVO.getOrderItemId(), userId); + if (orderItem == null) { + throw exception(ORDER_ITEM_NOT_FOUND); + } + // 1.2 校验订单相关状态 + TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(orderItem.getOrderId(), userId); + if (order == null) { + throw exception(ORDER_NOT_FOUND); + } + if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus())) { + throw exception(ORDER_COMMENT_FAIL_STATUS_NOT_COMPLETED); + } + if (ObjectUtil.notEqual(order.getCommentStatus(), Boolean.FALSE)) { + throw exception(ORDER_COMMENT_STATUS_NOT_FALSE); + } + + // 2. 创建评价 + Long commentId = createOrderItemComment0(orderItem, createReqVO); + + // 3. 如果订单项都评论了,则更新订单评价状态 + List orderItems = tradeOrderItemMapper.selectListByOrderId(order.getId()); + if (!anyMatch(orderItems, item -> Objects.equals(item.getCommentStatus(), Boolean.FALSE))) { + tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()).setCommentStatus(Boolean.TRUE) + .setFinishTime(LocalDateTime.now())); + // 增加订单日志。注意:只有在所有订单项都评价后,才会增加 + TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus()); + } + return commentId; + } + + @Override + public int createOrderItemCommentBySystem() { + // 1. 查询过期的待支付订单 + LocalDateTime expireTime = minusTime(tradeOrderProperties.getCommentExpireTime()); + List orders = tradeOrderMapper.selectListByStatusAndReceiveTimeLt( + TradeOrderStatusEnum.COMPLETED.getStatus(), expireTime, false); + if (CollUtil.isEmpty(orders)) { + return 0; + } + + // 2. 遍历执行,逐个取消 + int count = 0; + for (TradeOrderDO order : orders) { + try { + getSelf().createOrderItemCommentBySystemBySystem(order); + count ++; + } catch (Throwable e) { + log.error("[createOrderItemCommentBySystem][order({}) 过期订单异常]", order.getId(), e); + } + } + return count; + } + + /** + * 创建单个订单的评论 + * + * @param order 订单 + */ + @Transactional(rollbackFor = Exception.class) + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_COMMENT) + public void createOrderItemCommentBySystemBySystem(TradeOrderDO order) { + // 1. 查询未评论的订单项 + List orderItems = tradeOrderItemMapper.selectListByOrderIdAndCommentStatus(order.getId(), Boolean.FALSE); + if (CollUtil.isEmpty(orderItems)) { + return; + } + + // 2. 逐个评论 + for (TradeOrderItemDO orderItem : orderItems) { + // 2.1 创建评价 + AppTradeOrderItemCommentCreateReqVO commentCreateReqVO = new AppTradeOrderItemCommentCreateReqVO() + .setOrderItemId(orderItem.getId()).setAnonymous(false).setContent("") + .setBenefitScores(5).setDescriptionScores(5); + createOrderItemComment0(orderItem, commentCreateReqVO); + + // 2.2 更新订单项评价状态 + tradeOrderItemMapper.updateById(new TradeOrderItemDO().setId(orderItem.getId()).setCommentStatus(Boolean.TRUE)); + } + + // 3. 所有订单项都评论了,则更新订单评价状态 + tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()).setCommentStatus(Boolean.TRUE) + .setFinishTime(LocalDateTime.now())); + // 增加订单日志。注意:只有在所有订单项都评价后,才会增加 + TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus()); + } + + /** + * 创建订单项的评论的核心实现 + * + * @param orderItem 订单项 + * @param createReqVO 评论内容 + * @return 评论编号 + */ + private Long createOrderItemComment0(TradeOrderItemDO orderItem, AppTradeOrderItemCommentCreateReqVO createReqVO) { + // 1. 创建评价 + ProductCommentCreateReqDTO productCommentCreateReqDTO = TradeOrderConvert.INSTANCE.convert04(createReqVO, orderItem); + Long commentId = productCommentApi.createComment(productCommentCreateReqDTO); + + // 2. 更新订单项评价状态 + tradeOrderItemMapper.updateById(new TradeOrderItemDO().setId(orderItem.getId()).setCommentStatus(Boolean.TRUE)); + return commentId; + } + // =================== 营销相关的操作 =================== @Async diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml index a89136e42..975794f3c 100644 --- a/yudao-server/src/main/resources/application.yaml +++ b/yudao-server/src/main/resources/application.yaml @@ -205,6 +205,7 @@ yudao: app-id: 1 # 商户编号 pay-expire-time: 2h # 支付的过期时间 receive-expire-time: 14d # 收货的过期时间 + comment-expire-time: 7d # 评论的过期时间 express: client: kd_niao kd-niao: