Browse Source

优惠券注销后 已失效状态 开发

lutong 13 hours ago
parent
commit
23b0d3c47c

+ 1 - 1
alien-dining/src/main/java/shop/alien/dining/controller/DiningCouponController.java

@@ -47,7 +47,7 @@ public class DiningCouponController {
     @ApiImplicitParams({
             @ApiImplicitParam(name = "page", value = "分页页数", dataType = "Integer", paramType = "query", required = false),
             @ApiImplicitParam(name = "size", value = "分页条数", dataType = "Integer", paramType = "query", required = false),
-            @ApiImplicitParam(name = "tabType", value = "分页类型(0:全部(未使用),1:即将过期,2:已使用,3:已过期)", dataType = "String", paramType = "query", required = true),
+            @ApiImplicitParam(name = "tabType", value = "分页类型(0:全部(未使用),1:即将过期,2:已使用,3:已过期/已失效)", dataType = "String", paramType = "query", required = true),
             @ApiImplicitParam(name = "type", value = "券类型(不传或1:优惠券;代金券 type=4 已下线)", dataType = "Integer", paramType = "query", required = false),
             @ApiImplicitParam(name = "couponType", value = "优惠券类型:1=仅满减券,2=仅折扣券,不传=全部优惠券(可选)", dataType = "Integer", paramType = "query", required = false),
             @ApiImplicitParam(name = "storeId", value = "商铺ID,可为空,传则仅返回该商铺的优惠券", dataType = "String", paramType = "query", required = false),

+ 8 - 1
alien-entity/src/main/java/shop/alien/entity/store/LifeDiscountCoupon.java

@@ -29,6 +29,13 @@ public class LifeDiscountCoupon extends Model<LifeDiscountCoupon> {
 
     private static final long serialVersionUID = 1L;
 
+    /** 优惠券状态:草稿 */
+    public static final int COUPON_STATUS_DRAFT = 0;
+    /** 优惠券状态:正式 */
+    public static final int COUPON_STATUS_FORMAL = 1;
+    /** 优惠券状态:已失效(如店铺注销冷静期结束) */
+    public static final int COUPON_STATUS_INVALID = 2;
+
     @ApiModelProperty(value = "主键")
     @TableId(value = "id", type = IdType.AUTO)
     private Integer id;
@@ -146,7 +153,7 @@ public class LifeDiscountCoupon extends Model<LifeDiscountCoupon> {
     @TableField("claim_rule_customize_value")
     private Integer claimRuleCustomizeValue;
 
-    @ApiModelProperty(value = "优惠券状态:0:草稿,1:正式")
+    @ApiModelProperty(value = "优惠券状态:0-草稿,1-正式,2-已失效")
     @TableField("coupon_status")
     private Integer couponStatus;
 

+ 2 - 2
alien-entity/src/main/java/shop/alien/entity/store/vo/LifeDiscountCouponVo.java

@@ -96,7 +96,7 @@ public class LifeDiscountCouponVo {
     @ApiModelProperty(value = "类型   1-优惠券  2-红包")
     private Integer type;
 
-    @ApiModelProperty(value = "状态(0:进行中,1:已结束,2:未开始,3:已暂停,4:已售罄,5:草稿)")
+    @ApiModelProperty(value = "状态:商家券列表为(0进行中/1已结束/…);getUserCouponList 为用户券状态(0待使用/1已使用/2已作废)")
     private Integer status;
 
     @ApiModelProperty(value = "优惠券状态文案,用于前端展示:进行中/已结束/未开始/已暂停/已售罄/草稿")
@@ -168,7 +168,7 @@ public class LifeDiscountCouponVo {
     @ApiModelProperty(value = "结束领取时间")
     private LocalDate endGetDate;
 
-    @ApiModelProperty(value = "优惠券状态:0:草稿,1:正式")
+    @ApiModelProperty(value = "优惠券状态:0-草稿,1-正式,2-已失效")
     private Integer couponStatus;
 
     @ApiModelProperty(value = "有效期")

+ 4 - 0
alien-entity/src/main/resources/db/migration/life_discount_coupon_status_invalid.sql

@@ -0,0 +1,4 @@
+-- coupon_status 扩展:2-已失效(如店铺注销冷静期结束)
+-- 若已执行 life_discount_coupon_invalid_flag.sql,请先 DROP COLUMN invalid_flag 后再执行本脚本注释更新
+ALTER TABLE `life_discount_coupon`
+    MODIFY COLUMN `coupon_status` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '优惠券状态:0-草稿,1-正式,2-已失效';

+ 4 - 3
alien-entity/src/main/resources/mapper/LifeDiscountCouponUserMapper.xml

@@ -41,9 +41,10 @@
                 AND u.status = 1
             </when>
             <when test='tabType != null &amp;&amp; tabType.equals("3")'>
-                AND u.expiration_time &gt; #{sevenDaysAgo}
-                AND u.expiration_time &lt; #{today}
-                AND u.status = 0
+                AND (
+                    (u.status = 0 AND u.expiration_time IS NOT NULL AND u.expiration_time &lt; #{today})
+                    OR u.status = 2
+                )
             </when>
         </choose>
         <if test="couponType != null">

+ 55 - 0
alien-job/src/main/java/shop/alien/job/store/StoreMembershipCardJob.java

@@ -10,11 +10,14 @@ import shop.alien.config.redis.BaseRedisService;
 import shop.alien.entity.store.*;
 import shop.alien.job.feign.AlienStoreFeign;
 import shop.alien.mapper.*;
+import shop.alien.util.common.constant.CouponStatusEnum;
+import shop.alien.util.common.constant.DiscountCouponEnum;
 import shop.alien.util.type.LifeNoticeUtil;
 
 import java.util.Calendar;
 import java.util.Date;
 import java.util.List;
+import java.util.stream.Collectors;
 
 @Slf4j
 @Component
@@ -69,6 +72,12 @@ public class StoreMembershipCardJob {
 
     private final AlienStoreFeign alienStoreFeign;
 
+    private final LifeDiscountCouponMapper lifeDiscountCouponMapper;
+
+    private final LifeDiscountCouponUserMapper lifeDiscountCouponUserMapper;
+
+    private final LifeCouponMapper lifeCouponMapper;
+
     /**
      * 会员卡状态及会员卡订单状态变更任务
      */
@@ -178,6 +187,8 @@ public class StoreMembershipCardJob {
                     if (date.compareTo(sevenDay) >= 0) {
                         log.info("开始删除已注销超过7天的店铺: storeId={}, storeName={}, logoutTime={}", 
                                 storeInfo.getId(), storeInfo.getStoreName(), logoutTime);
+
+                        invalidateStoreCoupons(storeInfo.getId());
                         
                         // 先清理关联的商户用户注销状态,确保可以重新入驻
                         List<StoreUser> relatedStoreUsers = storeUserMapper.selectList(
@@ -304,4 +315,48 @@ public class StoreMembershipCardJob {
         calendar.add(Calendar.DAY_OF_YEAR, LOGOUT_COOLING_DAYS);
         return new Date().compareTo(calendar.getTime()) >= 0;
     }
+
+    /**
+     * 店铺注销冷静期结束:将该店铺赠出/发行的优惠券全部置为已失效
+     */
+    private void invalidateStoreCoupons(Integer storeId) {
+        if (storeId == null) {
+            return;
+        }
+        String storeIdStr = String.valueOf(storeId);
+        int voidedUserCouponStatus = Integer.parseInt(DiscountCouponEnum.HAVE_BEEN_VOIDED.getValue());
+
+        lifeDiscountCouponMapper.update(null, new LambdaUpdateWrapper<LifeDiscountCoupon>()
+                .eq(LifeDiscountCoupon::getStoreId, storeIdStr)
+                .set(LifeDiscountCoupon::getCouponStatus, LifeDiscountCoupon.COUPON_STATUS_INVALID)
+                .set(LifeDiscountCoupon::getGetStatus, 0));
+
+        List<LifeDiscountCoupon> storeCoupons = lifeDiscountCouponMapper.selectList(
+                new LambdaQueryWrapper<LifeDiscountCoupon>().eq(LifeDiscountCoupon::getStoreId, storeIdStr));
+        if (!storeCoupons.isEmpty()) {
+            List<Integer> couponIds = storeCoupons.stream().map(LifeDiscountCoupon::getId).collect(Collectors.toList());
+            lifeDiscountCouponUserMapper.update(null, new LambdaUpdateWrapper<LifeDiscountCouponUser>()
+                    .in(LifeDiscountCouponUser::getCouponId, couponIds)
+                    .eq(LifeDiscountCouponUser::getStatus, Integer.parseInt(DiscountCouponEnum.WAITING_USED.getValue()))
+                    .set(LifeDiscountCouponUser::getStatus, voidedUserCouponStatus));
+        }
+
+        lifeCouponMapper.update(null, new LambdaUpdateWrapper<LifeCoupon>()
+                .eq(LifeCoupon::getStoreId, storeIdStr)
+                .notIn(LifeCoupon::getStatus, CouponStatusEnum.ENDED.getCode(), CouponStatusEnum.INVALID.getCode())
+                .set(LifeCoupon::getStatus, CouponStatusEnum.INVALID.getCode()));
+
+        List<LifeCoupon> storeVouchers = lifeCouponMapper.selectList(
+                new LambdaQueryWrapper<LifeCoupon>().eq(LifeCoupon::getStoreId, storeIdStr));
+        if (!storeVouchers.isEmpty()) {
+            List<String> voucherIds = storeVouchers.stream().map(LifeCoupon::getId).collect(Collectors.toList());
+            lifeDiscountCouponUserMapper.update(null, new LambdaUpdateWrapper<LifeDiscountCouponUser>()
+                    .in(LifeDiscountCouponUser::getVoucherId, voucherIds)
+                    .eq(LifeDiscountCouponUser::getStatus, Integer.parseInt(DiscountCouponEnum.WAITING_USED.getValue()))
+                    .set(LifeDiscountCouponUser::getStatus, voidedUserCouponStatus));
+        }
+
+        log.info("店铺优惠券已失效处理完成: storeId={}, templateCount={}, voucherCount={}",
+                storeId, storeCoupons.size(), storeVouchers.size());
+    }
 }

+ 1 - 1
alien-store/src/main/java/shop/alien/store/controller/LifeDiscountCouponController.java

@@ -221,7 +221,7 @@ public class LifeDiscountCouponController {
     @GetMapping("/getUserCouponList")
     @ApiImplicitParams({@ApiImplicitParam(name = "page", value = "分页页数", dataType = "Integer", paramType = "query", required = false),
             @ApiImplicitParam(name = "size", value = "分页条数", dataType = "Integer", paramType = "query", required = false),
-            @ApiImplicitParam(name = "tabType", value = "分页类型(0:全部(未使用),1:即将过期,2:已使用,3:已过期)", dataType = "String", paramType = "query", required = true),
+            @ApiImplicitParam(name = "tabType", value = "分页类型(0:全部(未使用),1:即将过期,2:已使用,3:已过期/已失效)", dataType = "String", paramType = "query", required = true),
             @ApiImplicitParam(name = "type", value = "券类型(不传或传1:仅优惠券;代金券 type=4 已下线)", dataType = "Integer", paramType = "query", required = false),
             @ApiImplicitParam(name = "couponType", value = "优惠券类型:1=仅满减券,2=仅折扣券,不传=全部优惠券(可选)", dataType = "Integer", paramType = "query", required = false),
             @ApiImplicitParam(name = "storeId", value = "商铺ID,可为空,传则仅返回该商铺的优惠券", dataType = "String", paramType = "query", required = false),

+ 20 - 6
alien-store/src/main/java/shop/alien/store/service/impl/LifeDiscountCouponServiceImpl.java

@@ -865,7 +865,7 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
                 && !DiscountCouponEnum.BE_ABOUT_TO_EXPORE.getValue().equals(tabType)
                 && !DiscountCouponEnum.HAVE_ALREADY_APPLIED.getValue().equals(tabType)
                 && !DiscountCouponEnum.HAVE_EXPIRED.getValue().equals(tabType)) {
-            throw new IllegalArgumentException("分页类型参数错误,必须为0(未使用)、1(即将过期)、2(已使用)、3(已过期)");
+            throw new IllegalArgumentException("分页类型参数错误,必须为0(未使用)、1(即将过期)、2(已使用)、3(已过期/已失效)");
         }
         if (legacyTypeParam != null && legacyTypeParam == 4) {
             throw new IllegalArgumentException("不再支持代金券(type=4)");
@@ -906,6 +906,7 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
         vo.setCouponId(coupon.getId());
         vo.setVoucherId(userCoupon.getVoucherId());
         vo.setUserCouponId(userCoupon.getId());
+        vo.setStatus(userCoupon.getStatus());
         BeanUtils.copyProperties(coupon, vo);
         
         // quantityClaimed表示该券的总领取数量,在用户券列表中不设置或设置为0
@@ -971,6 +972,9 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
     /** 未配置领取起止日时,列表仍按草稿/库存/领取开关推断展示状态,避免整条记录被丢弃 */
     private Integer resolveListStatusWhenGetWindowMissing(Integer couponStatus, Integer getStatus,
                                                           Integer unlimitedQty, Integer singleQty) {
+        if (couponStatus != null && couponStatus == LifeDiscountCoupon.COUPON_STATUS_INVALID) {
+            return Integer.parseInt(DiscountCouponEnum.INVALID.getValue());
+        }
         if (couponStatus != null && couponStatus == 0) {
             return Integer.parseInt(DiscountCouponEnum.HAVE_NOT_STARTED.getValue());
         }
@@ -983,6 +987,13 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
         return Integer.parseInt(DiscountCouponEnum.UNDER_WAY.getValue());
     }
 
+    private Integer resolveInvalidStatusIfNeeded(Integer couponStatus) {
+        if (couponStatus != null && couponStatus == LifeDiscountCoupon.COUPON_STATUS_INVALID) {
+            return Integer.parseInt(DiscountCouponEnum.INVALID.getValue());
+        }
+        return null;
+    }
+
     /**
      * 获取店铺所有优惠券列表(分页)
      * 支持查询我的优惠券和好友优惠券
@@ -1078,8 +1089,8 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
                 LocalDate localNow = instant.atZone(zoneId).toLocalDate();
                 
                 // 计算优惠券状态
-                Integer calculatedStatus = null;
-                if (!StringUtils.isEmpty(lifeDiscountCoupon.getBeginGetDate()) && !StringUtils.isEmpty(lifeDiscountCoupon.getEndGetDate())) {
+                Integer calculatedStatus = resolveInvalidStatusIfNeeded(lifeDiscountCoupon.getCouponStatus());
+                if (calculatedStatus == null && !StringUtils.isEmpty(lifeDiscountCoupon.getBeginGetDate()) && !StringUtils.isEmpty(lifeDiscountCoupon.getEndGetDate())) {
                     int startResult = localNow.compareTo(lifeDiscountCoupon.getBeginGetDate());
                     int endResult = localNow.compareTo(lifeDiscountCoupon.getEndGetDate());
                     //如果当前时间小于开始时间
@@ -1233,8 +1244,8 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
                 LocalDate localNow = instant.atZone(zoneId).toLocalDate();
                 
                 // 计算优惠券状态
-                Integer calculatedStatus = null;
-                if (!StringUtils.isEmpty(record.getBeginGetDate()) && !StringUtils.isEmpty(record.getEndGetDate())) {
+                Integer calculatedStatus = resolveInvalidStatusIfNeeded(record.getCouponStatus());
+                if (calculatedStatus == null && !StringUtils.isEmpty(record.getBeginGetDate()) && !StringUtils.isEmpty(record.getEndGetDate())) {
                     int startResult = localNow.compareTo(record.getBeginGetDate());
                     int endResult = localNow.compareTo(record.getEndGetDate());
                     //如果当前时间小于开始时间
@@ -1357,7 +1368,10 @@ public class LifeDiscountCouponServiceImpl extends ServiceImpl<LifeDiscountCoupo
             Instant instant = now.toInstant();
             ZoneId zoneId = ZoneId.systemDefault();
             LocalDate localNow = instant.atZone(zoneId).toLocalDate();
-            if (!StringUtils.isEmpty(lifeDiscountCoupon.getBeginGetDate()) && !StringUtils.isEmpty(lifeDiscountCoupon.getEndGetDate())) {
+            Integer invalidStatus = resolveInvalidStatusIfNeeded(lifeDiscountCoupon.getCouponStatus());
+            if (invalidStatus != null) {
+                lifeDiscountCouponVo.setStatus(invalidStatus);
+            } else if (!StringUtils.isEmpty(lifeDiscountCoupon.getBeginGetDate()) && !StringUtils.isEmpty(lifeDiscountCoupon.getEndGetDate())) {
                 int startResult = localNow.compareTo(lifeDiscountCoupon.getBeginGetDate());
                 int endResult = localNow.compareTo(lifeDiscountCoupon.getEndGetDate());
                 if (!LifeDiscountCouponStock.hasTemplateStockRemaining(

+ 5 - 1
alien-util/src/main/java/shop/alien/util/common/constant/CouponStatusEnum.java

@@ -39,7 +39,11 @@ public enum CouponStatusEnum {
     /**
      * 已删除
      */
-    DELETED(8, "2+手动下架");
+    DELETED(8, "2+手动下架"),
+    /**
+     * 已失效(如店铺注销)
+     */
+    INVALID(9, "已失效");
     private final int code;
     private final String info;
 

+ 2 - 0
alien-util/src/main/java/shop/alien/util/common/constant/DiscountCouponEnum.java

@@ -25,6 +25,8 @@ public enum DiscountCouponEnum {
     HAVE_SOLD_OUT("4"),
     // 草稿
     DRAFT("5"),
+    // 已失效(如店铺注销)
+    INVALID("6"),
 
     /**限制使用规则*/
     //周规则限制