浏览代码

添加优惠券功能开发

qizai 1 年之前
父节点
当前提交
d22b45804a

+ 41 - 0
vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/constant/CouponRangeDay.java

@@ -0,0 +1,41 @@
+package com.chelvc.cloud.vehicle.api.constant;
+
+
+import lombok.Getter;
+
+/**
+ * 优惠券时间范围枚举
+ *
+ * @author qizai
+ * @date 2023/11/13
+ */
+@Getter
+public enum CouponRangeDay {
+
+    /**
+     * 固定时间
+     */
+    FIXEDTIME("固定时间"),
+    /**
+     * 动态时间
+     */
+    DYNAMICTIME("动态时间");
+
+    /**
+     * 类型描述
+     */
+    private final String description;
+
+    CouponRangeDay(String description) {
+        this.description = description;
+    }
+
+    public static boolean exist(String name) {
+        try {
+            CouponRangeDay.valueOf(name);
+        } catch (IllegalArgumentException e) {
+            return false;
+        }
+        return true;
+    }
+}

+ 7 - 0
vehicle-api/src/main/java/com/chelvc/cloud/vehicle/api/param/CouponModifyParam.java

@@ -83,4 +83,11 @@ public class CouponModifyParam implements Serializable {
      */
     @NotNull(message = "优惠券状态不能为空")
     private CouponStatus status;
+
+    /**
+     * 限制领取数量
+     */
+    @NotNull(message = "限制领取数量不能为空")
+    @Min(value = 0, message = "限制领取数量不能小于0")
+    private Integer limitNum;
 }

+ 32 - 11
vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/entity/Coupon.java

@@ -1,13 +1,17 @@
 package com.chelvc.cloud.vehicle.server.entity;
 
 import java.util.Date;
+import java.util.List;
 
 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 com.chelvc.cloud.vehicle.api.constant.CouponClaimType;
+import com.chelvc.cloud.vehicle.api.constant.CouponRangeDay;
 import com.chelvc.cloud.vehicle.api.constant.CouponStatus;
 import com.chelvc.cloud.vehicle.api.constant.CouponType;
+import com.chelvc.cloud.vehicle.api.constant.PromotionScopeType;
 import com.chelvc.cloud.vehicle.api.constant.PromotionStatus;
 import com.chelvc.framework.database.entity.ModifyEntity;
 import lombok.AllArgsConstructor;
@@ -29,17 +33,8 @@ import lombok.experimental.SuperBuilder;
 @AllArgsConstructor
 @ToString(callSuper = true)
 @EqualsAndHashCode(callSuper = true)
-public class Coupon extends ModifyEntity<Long> {
-    /**
-     * 主键
-     */
-    @TableId(type = IdType.ASSIGN_ID)
-    private Long id;
-
-    /**
-     * 商家ID
-     */
-    private Long merchantId;
+@TableName(autoResultMap = true)
+public class Coupon extends BasePromotion {
 
     /**
      * 优惠券类型
@@ -106,9 +101,35 @@ public class Coupon extends ModifyEntity<Long> {
      */
     private CouponClaimType claimType;
 
+    /**
+     * 时间范围类型
+     */
+    private CouponRangeDay rangeDayType;
+
+    /**
+     * 有效天数
+     */
+    private Integer effectiveDays;
+
+    /**
+     * 关联范围类型
+     */
+    private PromotionScopeType scopeType = PromotionScopeType.ALL;
+
+    /**
+     * 范围关联的id
+     */
+    private String scopeId;
+
     /**
      * 促销状态
      */
     @TableField(exist = false)
     private PromotionStatus promotionStatus;
+
+    /**
+     * 优惠券关联商品集合
+     */
+    @TableField(exist = false)
+    private List<PromotionGoods> promotionGoodsList;
 }

+ 2 - 2
vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/service/AbstractPromotionService.java

@@ -64,9 +64,9 @@ public interface AbstractPromotionService<T extends BasePromotion> extends IServ
     /**
      * 初始化促销字段
      *
-     * @param promotions 促销实体
+     * @param promotion 促销实体
      */
-    void initPromotion(T promotions);
+    void initPromotion(T promotion);
 
     /**
      * 检查促销参数

+ 4 - 4
vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/service/impl/AbstractPromotionServiceImpl.java

@@ -144,12 +144,12 @@ public abstract class AbstractPromotionServiceImpl<M extends BaseMapper<T>, T ex
     /**
      * 初始化促销字段
      *
-     * @param promotions 促销实体
+     * @param promotion 促销实体
      */
     @Override
-    public void initPromotion(T promotions) {
-        if (StringUtils.isEmpty(promotions.getScopeType())) {
-            promotions.setScopeType(PromotionScopeType.ALL);
+    public void initPromotion(T promotion) {
+        if (StringUtils.isEmpty(promotion.getScopeType())) {
+            promotion.setScopeType(PromotionScopeType.ALL);
         }
     }
 

+ 145 - 11
vehicle-server/src/main/java/com/chelvc/cloud/vehicle/server/service/impl/CouponServiceImpl.java

@@ -1,41 +1,49 @@
 package com.chelvc.cloud.vehicle.server.service.impl;
 
-import java.util.Collection;
-import java.util.List;
-import java.util.Objects;
-import java.util.stream.Collectors;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import cn.hutool.core.text.CharSequenceUtil;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.chelvc.cloud.vehicle.api.constant.PromotionStatus;
+import com.chelvc.cloud.vehicle.api.constant.CouponType;
+import com.chelvc.cloud.vehicle.api.constant.PromotionScopeType;
+import com.chelvc.cloud.vehicle.api.constant.PromotionType;
 import com.chelvc.cloud.vehicle.api.dto.CouponDTO;
 import com.chelvc.cloud.vehicle.api.param.CouponModifyParam;
 import com.chelvc.cloud.vehicle.api.param.CouponPagingParam;
 import com.chelvc.cloud.vehicle.server.copier.CouponCopier;
 import com.chelvc.cloud.vehicle.server.dao.CouponMapper;
 import com.chelvc.cloud.vehicle.server.entity.Coupon;
+import com.chelvc.cloud.vehicle.server.entity.Goods;
 import com.chelvc.cloud.vehicle.server.service.CouponService;
+import com.chelvc.cloud.vehicle.server.service.GoodsService;
 import com.chelvc.framework.base.exception.ResourceUnavailableException;
 import com.chelvc.framework.base.util.ResourceUtils;
 import com.chelvc.framework.common.model.Pagination;
-import com.chelvc.framework.database.context.DatabaseContextHolder;
+import com.chelvc.framework.common.util.DateUtils;
 import com.chelvc.framework.database.util.PagingUtils;
 import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
 import org.apache.dubbo.config.annotation.DubboService;
-import org.springframework.stereotype.Service;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.StringUtils;
 
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
 /**
  * 优惠券业务操作实现
  *
  * @author Woody
  * @date 2023/7/17
  */
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
 @DubboService(interfaceClass = com.chelvc.cloud.vehicle.api.service.CouponService.class)
-public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> implements CouponService,
+public class CouponServiceImpl extends AbstractPromotionServiceImpl<CouponMapper, Coupon> implements CouponService,
         com.chelvc.cloud.vehicle.api.service.CouponService {
+
+    private final GoodsService goodsService;
+
     @Override
     public List<CouponDTO> listUserGoodsActiveCoupons(@NonNull Long userId, Collection<Long> goodsCouponIds) {
         return this.baseMapper.listUserGoodsActiveCoupons(userId, goodsCouponIds);
@@ -44,6 +52,8 @@ public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> impleme
     @Override
     public Long addCoupon(@NonNull CouponModifyParam param) {
         Coupon coupon = CouponCopier.INSTANCE.copying(param);
+        coupon.setUsedNum(0);
+        coupon.setReceivedNum(0);
         this.save(coupon);
         return coupon.getId();
     }
@@ -115,6 +125,130 @@ public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> impleme
         }
     }
 
+    @Override
+    public boolean updatePromotion(Coupon promotions) {
+        return super.updatePromotion(promotions);
+    }
+
+    @Override
+    public boolean updateStatus(List<Long> ids, Long startTime, Long endTime) {
+        return super.updateStatus(ids, startTime, endTime);
+    }
+
+    @Override
+    public boolean removePromotion(List<Long> ids) {
+        return super.removePromotion(ids);
+    }
+
+    @Override
+    public void initPromotion(Coupon coupon) {
+        coupon.setUsedNum(0);
+        coupon.setReceivedNum(0);
+    }
+
+    @Override
+    public void checkPromotion(Coupon coupon) {
+        if (coupon.getRangeDayType() == null) {
+            super.checkPromotion(coupon);
+        }
+        //如果发行数量是0则判断领取限制数量
+        if (coupon.getPublishNum() != 0 && coupon.getLimitNum() > coupon.getPublishNum()) {
+            throw new ResourceUnavailableException("领取限制数量超出发行数量");
+        }
+        //打折优惠券大于10折
+        boolean discountCoupon = (coupon.getType().equals(CouponType.DISCOUNT)
+                && (coupon.getDiscount() < 0 || coupon.getDiscount() > 10));
+        if (discountCoupon) {
+            throw new ResourceUnavailableException("优惠券折扣必须小于10且大于0");
+        }
+
+        switch (coupon.getRangeDayType()) {
+            case FIXEDTIME:
+                //如果优惠券为固定时间,则开始结束时间不能为空
+                if (coupon.getEndTime() == null || coupon.getStartTime() == null) {
+                    throw new ResourceUnavailableException("活动起始时间和活动结束时间不能为空");
+                }
+                long nowTime = DateUtils.timestamp();
+                //固定时间的优惠券不能小于当前时间
+                if (coupon.getEndTime().getTime() < nowTime) {
+                    throw new ResourceUnavailableException("活动结束时间不能小于当前时间");
+                }
+                break;
+            case DYNAMICTIME:
+                //动态时间的优惠券不能小于当前时间
+                if (coupon.getEffectiveDays() == null || coupon.getEffectiveDays() < 0) {
+                    throw new ResourceUnavailableException("活动结束时间不能小于当前时间");
+                }
+                break;
+        }
+
+        this.checkCouponScope(coupon);
+    }
+
+    @Override
+    public void checkStatus(Coupon promotion) {
+        super.checkStatus(promotion);
+    }
+
+    @Override
+    public boolean updatePromotionsGoods(Coupon promotion) {
+        return super.updatePromotionsGoods(promotion);
+    }
+
+    @Override
+    public void updateEsGoodsIndex(Coupon promotion) {
+        super.updateEsGoodsIndex(promotion);
+    }
+
+    @Override
+    public PromotionType getPromotionType() {
+        return null;
+    }
+
+    /**
+     * 检查优惠券范围
+     *
+     * @param coupon 检查的优惠券对象
+     */
+    private void checkCouponScope(Coupon coupon) {
+        boolean portionGoodsScope = (coupon.getScopeType().equals(PromotionScopeType.PORTION_GOODS)
+                && (coupon.getPromotionGoodsList() == null || coupon.getPromotionGoodsList().isEmpty()));
+        if (portionGoodsScope) {
+            throw new ResourceUnavailableException("当前关联范围类型为指定商品时,商品列表不能为空");
+        } else if (coupon.getScopeType().equals(PromotionScopeType.PORTION_GOODS)
+                && CharSequenceUtil.isEmpty(coupon.getScopeId())) {
+            throw new ResourceUnavailableException("当前关联范围类型为指定商品时,范围关联的id不能为空");
+        } else if (coupon.getScopeType().equals(PromotionScopeType.PORTION_GOODS_CATEGORY)
+                && CharSequenceUtil.isEmpty(coupon.getScopeId())) {
+            throw new ResourceUnavailableException("当前关联范围类型为部分商品分类时,范围关联的id不能为空");
+        } else if (coupon.getScopeType().equals(PromotionScopeType.PORTION_SHOP_CATEGORY)
+                && CharSequenceUtil.isEmpty(coupon.getScopeId())) {
+            throw new ResourceUnavailableException("当前关联范围类型为部分店铺分类时,范围关联的id不能为空");
+        }
+
+        if (coupon.getScopeType().equals(PromotionScopeType.PORTION_GOODS)) {
+            this.checkCouponPortionGoods(coupon);
+        }
+    }
+
+    /**
+     * 检查指定商品
+     *
+     * @param coupon 优惠券信息
+     */
+    private void checkCouponPortionGoods(Coupon coupon) {
+        String[] split = coupon.getScopeId().split(",");
+        if (split.length == 0) {
+            throw new ResourceUnavailableException("指定商品范围关联id不能为空");
+        }
+        for (String id : split) {
+            Goods goods = goodsService.getById(id);
+            if (goods == null) {
+                throw new ResourceUnavailableException("商品不存在");
+            }
+        }
+    }
+
     /**
      * 转换优惠券信息
      *