diff --git a/yudao-module-mall/yudao-module-promotion-biz/pom.xml b/yudao-module-mall/yudao-module-promotion-biz/pom.xml
index 44d0e8967..c9a544c06 100644
--- a/yudao-module-mall/yudao-module-promotion-biz/pom.xml
+++ b/yudao-module-mall/yudao-module-promotion-biz/pom.xml
@@ -45,6 +45,10 @@
cn.iocoder.boot
yudao-spring-boot-starter-biz-operatelog
+
+ cn.iocoder.boot
+ yudao-spring-boot-starter-biz-tenant
+
cn.iocoder.boot
yudao-spring-boot-starter-biz-weixin
diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java
index 20852852f..dc909b4c6 100755
--- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java
+++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java
@@ -13,6 +13,7 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.yulichang.toolkit.MPJWrappers;
import org.apache.ibatis.annotations.Mapper;
+import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;
@@ -94,4 +95,11 @@ public interface CouponMapper extends BaseMapperX {
.or(ww -> ww.eq(CouponDO::getProductScope, PromotionProductScopeEnum.CATEGORY.getScope())
.apply(productScopeValuesFindInSetFunc.apply(categoryIds)))));
}
+
+ default List selectListByStatusAndValidEndTimeLe(Integer status, LocalDateTime validEndTime) {
+ return selectList(new LambdaQueryWrapperX()
+ .eq(CouponDO::getStatus, status)
+ .le(CouponDO::getValidEndTime, validEndTime)
+ );
+ }
}
diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/job/CouponExpireJob.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/job/CouponExpireJob.java
new file mode 100644
index 000000000..0526d1a72
--- /dev/null
+++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/job/CouponExpireJob.java
@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.module.promotion.job;
+
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
+import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
+import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * 优惠券过期 Job
+ *
+ * @author owen
+ */
+@Component
+@TenantJob
+public class CouponExpireJob implements JobHandler {
+
+ @Resource
+ private CouponService couponService;
+
+ @Override
+ public String execute(String param) {
+ int count = couponService.expireCoupon();
+ return StrUtil.format("过期优惠券 {} 个", count);
+ }
+
+}
diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java
index 1ee2096ef..a85ac31a9 100644
--- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java
+++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java
@@ -157,4 +157,11 @@ public interface CouponService {
* @return 优惠券列表
*/
List getMatchCouponList(Long userId, AppCouponMatchReqVO matchReqVO);
+
+ /**
+ * 过期优惠券
+ *
+ * @return 过期数量
+ */
+ int expireCoupon();
}
diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
index acb1028c4..be2370c1a 100644
--- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
+++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
@@ -6,6 +6,7 @@ import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
@@ -21,6 +22,7 @@ import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum;
import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum;
import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum;
import cn.iocoder.yudao.module.promotion.service.coupon.bo.CouponTakeCountBO;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
@@ -43,6 +45,7 @@ import static java.util.Arrays.asList;
*
* @author 芋道源码
*/
+@Slf4j
@Service
@Validated
public class CouponServiceImpl implements CouponService {
@@ -193,6 +196,43 @@ public class CouponServiceImpl implements CouponService {
matchReqVO.getPrice(), matchReqVO.getSpuIds(), matchReqVO.getCategoryIds());
}
+ @Override
+ public int expireCoupon() {
+ // 1. 查询待过期的优惠券
+ List list = couponMapper.selectListByStatusAndValidEndTimeLe(
+ CouponStatusEnum.UNUSED.getStatus(), LocalDateTime.now());
+ if (CollUtil.isEmpty(list)) {
+ return 0;
+ }
+
+ // 2. 遍历执行
+ int count = 0;
+ for (CouponDO coupon : list) {
+ try {
+ boolean success = getSelf().expireCoupon(coupon);
+ if (success) {
+ count++;
+ }
+ } catch (Exception e) {
+ log.error("[expireCoupon][coupon({}) 更新为已过期失败]", coupon.getId(), e);
+ }
+ }
+ return count;
+ }
+
+ private boolean expireCoupon(CouponDO coupon) {
+ // 更新记录状态
+ CouponDO updateObj = new CouponDO().setStatus(CouponStatusEnum.EXPIRE.getStatus());
+ int updateRows = couponMapper.updateByIdAndStatus(coupon.getId(), CouponStatusEnum.UNUSED.getStatus(), updateObj);
+ if (updateRows == 0) {
+ log.error("[expireCoupon][coupon({}) 更新为已过期失败]", coupon.getId());
+ return false;
+ }
+
+ log.info("[expireCoupon][coupon({}) 更新为已过期成功]", coupon.getId());
+ return true;
+ }
+
/**
* 校验优惠券是否可以领取
*
@@ -246,4 +286,12 @@ public class CouponServiceImpl implements CouponService {
userIds.removeIf(userId -> MapUtil.getInt(userTakeCountMap, userId, 0) >= couponTemplate.getTakeLimitCount());
}
+ /**
+ * 获得自身的代理对象,解决 AOP 生效问题
+ *
+ * @return 自己
+ */
+ private CouponServiceImpl getSelf() {
+ return SpringUtil.getBean(getClass());
+ }
}