feat:优惠券中间业务代码开发

This commit is contained in:
dongtiandexue 2021-08-01 17:11:09 +08:00
parent 4b091b20dd
commit c1203de39f
42 changed files with 1256 additions and 204 deletions

View File

@ -7,8 +7,10 @@ spring:
cloud:
nacos:
discovery:
server-addr: http://localhost:8848
server-addr: http://47.104.214.204:8848
namespace: dev_namespace_id
config:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
file-extension: yaml
namespace: dev_namespace_id

View File

@ -7,10 +7,12 @@ spring:
cloud:
nacos:
discovery:
server-addr: http://localhost:8848
server-addr: http://47.104.214.204:8848
namespace: dev_namespace_id
config:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
file-extension: yaml
namespace: dev_namespace_id

View File

@ -0,0 +1,105 @@
package com.youlai.mall.sms.pojo.domain;
import com.youlai.mall.sms.pojo.enums.UserTypeEnum;
import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author xinyi
* @desc优惠券使用规则
* @date 2021/7/19
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CouponTemplateRule {
private UserLimit userLimit;
/**
* 优惠券过期规则
*/
private Expiration expiration;
/**
* 优惠券折扣规则
*/
private Discount discount;
private List<String> goodsCategories;
/**
* 权重可以和哪些优惠券叠加使用同一类的优惠券一定不能叠加
*/
private List<String> weight;
private String targetUrl;
/**
* 有效期规则定义
*/
@ApiModel("有效期规则定义模型")
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Expiration {
/**
* 有效期规则对应 PeriodType code 字段
*/
private Integer period;
private Long startTime;
private Long endTime;
/**
* 有效间隔只对变动性有效期有效
*/
private Integer gap;
}
/**
* 折扣的规则
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Discount {
/**
* 额度满减20折扣85立减10
*/
private Long quota;
/**
* 基准需要满多少才可用
*/
private Long base;
/**
* 最大优惠金额
*/
private Long maxDiscount;
}
/**
* 用户领取限制
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class UserLimit {
private UserTypeEnum userType;
private Integer limit;
}
}

View File

@ -1,9 +1,6 @@
package com.youlai.mall.sms.pojo.domain;
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.baomidou.mybatisplus.annotation.*;
import com.youlai.mall.sms.pojo.enums.CouponStateEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
@ -20,6 +17,7 @@ import java.util.Date;
@AllArgsConstructor
@TableName("sms_coupon")
public class SmsCoupon {
/**
* 用户优惠券ID
*/
@ -36,6 +34,11 @@ public class SmsCoupon {
*/
private Long userId;
/**
* 用户昵称冗余字段
*/
private String userName;
/**
* 优惠券码
*/
@ -46,21 +49,38 @@ public class SmsCoupon {
*/
private CouponStateEnum state;
/**
* 优惠券生效起始时间
*/
private Long availableStartTime;
/**
* 优惠券生效起始时间
*/
private Long availableEndTime;
/**
* 关联订单 ID
*/
private Long orderId;
/**
* 使用时间
*/
private Date useTime;
private Long useTime;
/**
* 创建时间
*/
@TableField(fill = FieldFill.INSERT)
private Date gmtCreate;
/**
* 修改时间
*/
@TableField(fill = FieldFill.INSERT)
private String gmtCreatedBy;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date gmtModified;
@TableField(fill = FieldFill.INSERT_UPDATE)
private String gmtModifiedBy;
@TableField(exist = false)
private SmsCouponTemplate template;

View File

@ -1,10 +1,11 @@
package com.youlai.mall.sms.pojo.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.youlai.mall.sms.pojo.enums.CouponCategoryEnum;
import com.youlai.mall.sms.pojo.enums.CouponTemplateStateEnum;
import com.youlai.mall.sms.pojo.enums.DistributeTargetEnum;
import com.youlai.mall.sms.pojo.vo.TemplateRuleVO;
import com.youlai.mall.sms.pojo.enums.CouponOfferStateEnum;
import com.youlai.mall.sms.pojo.enums.CouponUsedStateEnum;
import com.youlai.mall.sms.pojo.enums.CouponVerifyStateEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -21,19 +22,15 @@ import java.util.Date;
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName(value = "sms_coupon_template",autoResultMap = true)
public class SmsCouponTemplate {
/**
* 主键自增ID
*/
@TableId
@TableId(type = IdType.AUTO)
private Long id;
/**
* 优惠券模板状态(0:待审核1:进行中2:已过期)
*/
private CouponTemplateStateEnum state;
/**
* 优惠券名称
*/
@ -54,6 +51,50 @@ public class SmsCouponTemplate {
*/
private CouponCategoryEnum category;
/**
* 优惠券审核状态
* 0: 待审核
* 1: 已审核
*/
private CouponVerifyStateEnum verifyState;
/**
* 优惠券发放状态
* (已审核且在允许发放时间之内才允许发放)
* 0: 未开始
* 1: 进行中
* 2: 已结束
*/
private CouponOfferStateEnum offerState;
/**
* 优惠券发放最早时间
*/
private Long offerStartTime;
/**
* 优惠券发放最晚时间
*/
private Long offerEndTime;
/**
* 优惠券使用状态
* 0未生效未审核未到最早使用时间
* 1生效中已审核正在使用时间中
* 2已结束超过最晚使用时间
*/
private CouponUsedStateEnum usedState;
/**
* 优惠券最早使用时间
*/
private Long usedStartTime;
/**
* 优惠券最晚使用时间
*/
private Long usedEndTime;
/**
* 总数
*/
@ -62,23 +103,23 @@ public class SmsCouponTemplate {
/**
* 优惠券模板编码
*/
private String code;
/**
* 目标用户
*/
private DistributeTargetEnum target;
private String code;
/**
* 优惠券规则
*/
private TemplateRuleVO rule;
@TableField(typeHandler = JacksonTypeHandler.class)
private CouponTemplateRule rule;
@TableField(fill = FieldFill.INSERT)
private Date gmtCreate;
@TableField(fill = FieldFill.INSERT)
private String gmtCreatedBy;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date gmtModified;
@TableField(fill = FieldFill.INSERT_UPDATE)
private String gmtModifiedBy;
}

View File

@ -0,0 +1,44 @@
package com.youlai.mall.sms.pojo.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Objects;
import java.util.stream.Stream;
/**
* @author huawei
* @desc用户优惠券状态
* @email huawei_code@163.com
* @date 2021/2/28
*/
@Getter
@AllArgsConstructor
public enum CouponOfferStateEnum {
INIT("未开始", 0),
GOING("生效中",1),
FINISH("已结束",2);
/**
* 用户优惠券状态描述
*/
@JsonValue
private String desc;
/**
* 用户优惠券状态码
*/
@EnumValue
private Integer code;
public static CouponOfferStateEnum of(Integer code) {
Objects.requireNonNull(code);
return Stream.of(values())
.filter(bean -> bean.code.equals(code))
.findAny()
.orElseThrow(() -> new IllegalArgumentException(code + " Not Exist"));
}
}

View File

@ -16,7 +16,7 @@ import java.util.stream.Stream;
*/
@Getter
@AllArgsConstructor
public enum CouponStateEnum {
public enum CouponStateEnum {
USABLE("可用", 1),
USED("已使用", 5),

View File

@ -18,6 +18,9 @@ import java.util.stream.Stream;
public enum CouponTemplateStateEnum {
INIT("待审核", 0),
VERIFY("已审核",1),
OFFER("发放中",2),
USED("进行中", 1),
FINISH("已过期(活动结束)", 2);

View File

@ -0,0 +1,44 @@
package com.youlai.mall.sms.pojo.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Objects;
import java.util.stream.Stream;
/**
* @author huawei
* @desc用户优惠券状态
* @email huawei_code@163.com
* @date 2021/2/28
*/
@Getter
@AllArgsConstructor
public enum CouponUsedStateEnum {
INIT("未生效", 0),
GOING("进行中",1),
FINISH("已结束",2);
/**
* 用户优惠券状态描述
*/
@JsonValue
private String desc;
/**
* 用户优惠券状态码
*/
@EnumValue
private Integer code;
public static CouponUsedStateEnum of(Integer code) {
Objects.requireNonNull(code);
return Stream.of(values())
.filter(bean -> bean.code.equals(code))
.findAny()
.orElseThrow(() -> new IllegalArgumentException(code + " Not Exist"));
}
}

View File

@ -0,0 +1,43 @@
package com.youlai.mall.sms.pojo.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Objects;
import java.util.stream.Stream;
/**
* @author huawei
* @desc用户优惠券状态
* @email huawei_code@163.com
* @date 2021/2/28
*/
@Getter
@AllArgsConstructor
public enum CouponVerifyStateEnum {
INIT("待审核", 0),
VERIFY("已审核",1);
/**
* 用户优惠券状态描述
*/
@JsonValue
private String desc;
/**
* 用户优惠券状态码
*/
@EnumValue
private Integer code;
public static CouponVerifyStateEnum of(Integer code) {
Objects.requireNonNull(code);
return Stream.of(values())
.filter(bean -> bean.code.equals(code))
.findAny()
.orElseThrow(() -> new IllegalArgumentException(code + " Not Exist"));
}
}

View File

@ -0,0 +1,46 @@
package com.youlai.mall.sms.pojo.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Objects;
import java.util.stream.Stream;
/**
* @author huawei
* @desc用户优惠券状态
* @email huawei_code@163.com
* @date 2021/2/28
*/
@Getter
@AllArgsConstructor
public enum UserTypeEnum {
ALL("全部用户", 0),
NEW("新用户", 1),
OLD("老用户", 2),
VIP("会员", 2),
;
/**
* 用户优惠券状态描述
*/
@JsonValue
private String desc;
/**
* 用户优惠券状态码
*/
@EnumValue
private Integer code;
public static UserTypeEnum of(Integer code) {
Objects.requireNonNull(code);
return Stream.of(values())
.filter(bean -> bean.code.equals(code))
.findAny()
.orElseThrow(() -> new IllegalArgumentException(code + " Not Exist"));
}
}

View File

@ -55,7 +55,7 @@ public class CouponTemplateForm {
*/
@ApiModelProperty("优惠券分类(满减券、折扣券、立减券 ...)")
@NotBlank(message = "请选择优惠券分类")
private String category;
private String categoryCode;
/**
* 优惠券总数量
@ -63,14 +63,16 @@ public class CouponTemplateForm {
@ApiModelProperty("优惠券总数量(范围1到65535)")
@NotNull(message = "请输入优惠券总数量")
@Min(value = 1, message = "优惠券数量必须大于1")
@Max(value = Integer.MAX_VALUE, message = "优惠券数量不能大于 " + Integer.MAX_VALUE)
@Max(value = 100000, message = "优惠券数量不能大于 " + 100000)
private Integer total;
/**
* 目标用户
*/
@ApiModelProperty("目标用户(单用户、多用户)")
private Integer target;
@ApiModelProperty("优惠券发放时间范围")
@NotNull(message = "优惠券使用时间范围不能为空")
private Long[] offerTime;
@ApiModelProperty("优惠券使用时间范围")
@NotNull(message = "优惠券使用时间范围不能为空")
private Long[] usedTime;
/**
* 优惠券规则
@ -78,4 +80,6 @@ public class CouponTemplateForm {
@ApiModelProperty("优惠券规则")
@NotNull(message = "优惠券规则不能为空")
private TemplateRuleVO rule;
}

View File

@ -40,6 +40,4 @@ public class CouponTemplatePageQuery extends BasePageQuery {
@ApiModelProperty("优惠券模板创建范围结束时间")
private Date endTime;
}

View File

@ -45,11 +45,11 @@ public class CouponClassify {
Date time = new Date();
coupons.forEach(coupon -> {
boolean isTimeExpire;
boolean isTimeExpire = false;
SmsCouponTemplate template = coupon.getTemplate();
// 判断优惠券是否过期
if (template.getRule().getExpiration().getPeriod().equals(PeriodTypeEnum.REGULAR.getCode())) {
isTimeExpire = template.getRule().getExpiration().getDeadline() <= time.getTime();
// isTimeExpire = template.getRule().getExpiration().getDeadline() <= time.getTime();
} else {
isTimeExpire = DateUtils.addDays(coupon.getGmtCreate(), template.getRule().getExpiration().getGap()).getTime() <= time.getTime();
}

View File

@ -0,0 +1,120 @@
package com.youlai.mall.sms.pojo.vo;
import com.youlai.mall.sms.pojo.enums.UserTypeEnum;
import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
/**
* @author xinyi
* @desc优惠券使用规则
* @date 2021/7/19
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CouponTemplateRuleInfoVO {
private UserLimit userLimit;
/**
* 优惠券过期规则
*/
private Expiration expiration;
/**
* 优惠券折扣规则
*/
private Discount discount;
private List<String> goodsCategories;
/**
* 权重可以和哪些优惠券叠加使用同一类的优惠券一定不能叠加
*/
private List<String> weight;
private String targetUrl;
/**
* 有效期规则定义
*/
@ApiModel("有效期规则定义模型")
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Expiration {
/**
* 有效期规则对应 PeriodType code 字段
*/
private Integer period;
private Long startTime;
private Long endTime;
private List<Long> time;
/**
* 有效间隔只对变动性有效期有效
*/
private Integer gap;
public List<Long> getTime() {
List<Long> time = new ArrayList<>();
time.add(this.startTime);
time.add(this.endTime);
return time;
}
}
/**
* 折扣的规则
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Discount {
/**
* 额度满减20折扣85立减10
*/
private Long quota;
/**
* 基准需要满多少才可用
*/
private Long base;
/**
* 最大优惠金额
*/
private Long maxDiscount;
}
/**
* 用户领取限制
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class UserLimit {
private UserTypeEnum userType;
private Integer userTypeCode;
private Integer limit;
public Integer getUserTypeCode() {
return this.userType.getCode();
}
}
}

View File

@ -0,0 +1,105 @@
package com.youlai.mall.sms.pojo.vo;
import com.youlai.mall.sms.pojo.enums.UserTypeEnum;
import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author xinyi
* @desc优惠券使用规则
* @date 2021/7/19
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CouponTemplateRuleVO {
private UserLimit userLimit;
/**
* 优惠券过期规则
*/
private Expiration expiration;
/**
* 优惠券折扣规则
*/
private Discount discount;
private List<String> goodsCategories;
/**
* 权重可以和哪些优惠券叠加使用同一类的优惠券一定不能叠加
*/
private List<String> weight;
private String targetUrl;
/**
* 有效期规则定义
*/
@ApiModel("有效期规则定义模型")
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Expiration {
/**
* 有效期规则对应 PeriodType code 字段
*/
private Integer period;
private Long startTime;
private Long endTime;
/**
* 有效间隔只对变动性有效期有效
*/
private Integer gap;
}
/**
* 折扣的规则
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Discount {
/**
* 额度满减20折扣85立减10
*/
private Long quota;
/**
* 基准需要满多少才可用
*/
private Long base;
/**
* 最大优惠金额
*/
private Long maxDiscount;
}
/**
* 用户领取限制
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class UserLimit {
private UserTypeEnum userType;
private Integer limit;
}
}

View File

@ -0,0 +1,151 @@
package com.youlai.mall.sms.pojo.vo;
import com.youlai.mall.sms.pojo.enums.CouponCategoryEnum;
import com.youlai.mall.sms.pojo.enums.CouponOfferStateEnum;
import com.youlai.mall.sms.pojo.enums.CouponUsedStateEnum;
import com.youlai.mall.sms.pojo.enums.CouponVerifyStateEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
/**
* @author xinyi
* @desc: 优惠券模板实体类基础属性 + 规则属性
* @date 2021/6/26
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SmsCouponTemplateInfoVO {
/**
* 主键自增ID
*/
private Long id;
/**
* 优惠券名称
*/
private String name;
/**
* 优惠券logo
*/
private String logo;
/**
* 优惠券描述
*/
private String description;
/**
* 优惠券分类
*/
private CouponCategoryEnum category;
private String categoryCode;
private CouponVerifyStateEnum verifyState;
/**
* 优惠券审核状态
* 0: 待审核
* 1: 已审核
*/
private Integer verifyStateCode;
private CouponOfferStateEnum offerState;
/**
* 优惠券发放状态
* (已审核且在允许发放时间之内才允许发放)
* 0: 未开始
* 1: 进行中
* 2: 已结束
*/
private Integer offerStateCode;
/**
* 优惠券发放最早时间
*/
private Long offerStartTime;
/**
* 优惠券发放最晚时间
*/
private Long offerEndTime;
private List<Long> offerTime;
private CouponUsedStateEnum usedState;
/**
* 优惠券使用状态
* 0未生效未审核未到最早使用时间
* 1生效中已审核正在使用时间中
* 2已结束超过最晚使用时间
*/
private Integer usedStateCode;
/**
* 优惠券最早使用时间
*/
private Long usedStartTime;
/**
* 优惠券最晚使用时间
*/
private Long usedEndTime;
private List<Long> usedTime;
/**
* 总数
*/
private Integer total;
/**
* 优惠券模板编码
*/
private String code;
/**
* 优惠券规则
*/
private CouponTemplateRuleInfoVO rule;
public List<Long> getOfferTime() {
List<Long> offerTime = new ArrayList<>(2);
offerTime.add(this.offerStartTime);
offerTime.add(this.offerEndTime);
return offerTime;
}
public List<Long> getUsedTime() {
List<Long> usedTime = new ArrayList<>(2);
usedTime.add(this.usedStartTime);
usedTime.add(this.usedEndTime);
return usedTime;
}
public Integer getVerifyStateCode() {
return this.verifyState.getCode();
}
public Integer getUsedStateCode() {
return this.usedState.getCode();
}
public Integer getOfferStateCode() {
return this.offerState.getCode();
}
public String getCategoryCode() {
return this.category.getCode();
}
}

View File

@ -0,0 +1,106 @@
package com.youlai.mall.sms.pojo.vo;
import com.youlai.mall.sms.pojo.enums.CouponCategoryEnum;
import com.youlai.mall.sms.pojo.enums.CouponOfferStateEnum;
import com.youlai.mall.sms.pojo.enums.CouponVerifyStateEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author xinyi
* @desc: 优惠券模板实体类基础属性 + 规则属性
* @date 2021/6/26
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SmsCouponTemplateVO {
/**
* 主键自增ID
*/
private Long id;
/**
* 优惠券名称
*/
private String name;
/**
* 优惠券logo
*/
private String logo;
/**
* 优惠券描述
*/
private String description;
/**
* 优惠券分类
*/
private CouponCategoryEnum category;
/**
* 优惠券审核状态
* 0: 待审核
* 1: 已审核
*/
private CouponVerifyStateEnum verifyState;
/**
* 优惠券发放状态
* (已审核且在允许发放时间之内才允许发放)
* 0: 未开始
* 1: 进行中
* 2: 已结束
*/
private CouponOfferStateEnum offerState;
/**
* 优惠券发放最早时间
*/
private Long offerStartTime;
/**
* 优惠券发放最晚时间
*/
private Long offerEndTime;
/**
* 优惠券使用状态
* 0未生效未审核未到最早使用时间
* 1生效中已审核正在使用时间中
* 2已结束超过最晚使用时间
*/
private CouponOfferStateEnum usedState;
/**
* 优惠券最早使用时间
*/
private Long usedStartTime;
/**
* 优惠券最晚使用时间
*/
private Long usedEndTime;
/**
* 总数
*/
private Integer total;
/**
* 优惠券模板编码
*/
private String code;
/**
* 优惠券规则
*/
private CouponTemplateRuleVO rule;
}

View File

@ -1,6 +1,5 @@
package com.youlai.mall.sms.pojo.vo;
import com.youlai.mall.sms.pojo.enums.PeriodTypeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
@ -22,6 +21,10 @@ import java.util.List;
@AllArgsConstructor
public class TemplateRuleVO {
@ApiModelProperty("用户领取优惠券限制")
@NotNull(message = "领取优惠券目标用户不能为空")
private UserLimit userLimit;
/**
* 优惠券过期规则
*/
@ -36,25 +39,18 @@ public class TemplateRuleVO {
@NotNull(message = "优惠券折扣规则不能为空")
private Discount discount;
/**
* 单个限领张数限制
*/
@ApiModelProperty("单个限领张数限制")
@Min(value = 1,message = "单个限领张数限制不能小于1")
private Integer limitation;
/**
* 优惠券使用范围规则
* 使用范围地域 + 商品类型
*/
@ApiModelProperty("优惠券使用范围规则")
private Usage usage;
@ApiModelProperty("优惠券限制是由商品分类")
private List<String> goodsCategories;
/**
* 权重可以和哪些优惠券叠加使用同一类的优惠券一定不能叠加
*/
@ApiModelProperty("优惠券使用权重规则")
private String weight;
@ApiModelProperty("可叠加使用优惠券列表")
private List<String> weight;
@ApiModelProperty("优惠券跳转链接")
private String targetUrl;
/**
* 有效期规则定义
@ -72,24 +68,16 @@ public class TemplateRuleVO {
@NotNull(message = "有效期规则不能为空")
private Integer period;
@ApiModelProperty("固定有效开始时间")
private List<Long> time;
/**
* 有效间隔只对变动性有效期有效
*/
@ApiModelProperty("有效间隔(单位小时,只对变动性有效期有效)")
@Min(value = 0,message = "有效期间隔不能小于0(单位小时)")
@Min(value = 1, message = "有效期间隔不能小于1 (单位天)")
private Integer gap;
/**
* 优惠券模板的失效日期两类规则都有效
*/
@ApiModelProperty("优惠券模板的失效日期(两类规则都有效)")
@Min(value = 0,message = "失效日期不能小于0(时间毫秒值)")
private Long deadline;
boolean validate() {
// 最简化校验
return null != PeriodTypeEnum.of(period) && gap > 0;
}
}
/**
@ -105,14 +93,14 @@ public class TemplateRuleVO {
* 额度满减20折扣85立减10
*/
@ApiModelProperty("额度满减20折扣85立减10")
@Min(value = 0,message = "折扣额度最小值为0")
@Min(value = 0, message = "折扣额度最小值为0")
private Long quota;
/**
* 基准需要满多少才可用
*/
@ApiModelProperty("折扣基准(需要满多少才可用,为0表示无基准)")
@Min(value = 0,message = "折扣基准最小值为0")
@Min(value = 0, message = "折扣基准最小值为0")
private Long base;
}
@ -134,4 +122,23 @@ public class TemplateRuleVO {
private List<String> goodsType;
}
/**
* 用户领取限制
*/
@ApiModel("用户领取限制")
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class UserLimit {
@ApiModelProperty("用户类型(0:全部用户,1:新用户,2:老用户)")
@NotNull(message = "用户类型不能为空")
private Integer userType;
@ApiModelProperty("单个用户限领张数")
@Min(value = 1L, message = "单个用户限领张数最小为1")
@Min(value = 10L, message = "单个用户限领张数最大为10")
private Integer limit;
}
}

View File

@ -1,9 +1,6 @@
package com.youlai.mall.sms.controller.admin;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.youlai.common.base.BasePageQuery;
import com.youlai.common.result.Result;
import com.youlai.mall.sms.pojo.domain.SmsCoupon;
import com.youlai.mall.sms.pojo.form.CouponForm;
import com.youlai.mall.sms.service.ISmsCouponService;
import io.swagger.annotations.Api;
@ -27,12 +24,12 @@ public class CouponController {
@Autowired
private ISmsCouponService couponService;
@ApiOperation("优惠券分页列表查询")
@GetMapping("/page")
public Result page(@ApiParam("条件分页请求入参") BasePageQuery query) {
Page<SmsCoupon> page = new Page<>(query.getPageNum(), query.getPageSize());
return Result.success(couponService.pageQuery(page, query));
}
// @ApiOperation("优惠券分页列表查询")
// @GetMapping("/page")
// public Result page(@ApiParam("条件分页请求入参") BasePageQuery query) {
// Page<SmsCoupon> page = new Page<>(query.getPageNum(), query.getPageSize());
// return Result.success(couponService.pageQuery(page, query));
// }
@ApiOperation("查询优惠券详情")
@RequestMapping("/{couponId}/detail")

View File

@ -3,17 +3,14 @@ package com.youlai.mall.sms.controller.admin;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.youlai.common.result.Result;
import com.youlai.mall.sms.pojo.domain.SmsCoupon;
import com.youlai.mall.sms.pojo.domain.SmsCouponTemplate;
import com.youlai.mall.sms.pojo.form.CouponTemplateForm;
import com.youlai.mall.sms.pojo.query.CouponPageQuery;
import com.youlai.mall.sms.pojo.query.CouponTemplatePageQuery;
import com.youlai.mall.sms.pojo.vo.CouponTemplateVO;
import com.youlai.mall.sms.pojo.vo.SmsCouponTemplateInfoVO;
import com.youlai.mall.sms.pojo.vo.SmsCouponTemplateVO;
import com.youlai.mall.sms.service.ISmsCouponService;
import com.youlai.mall.sms.service.ISmsCouponTemplateService;
import com.youlai.mall.sms.service.ITemplateBaseService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
@ -24,10 +21,10 @@ import org.springframework.web.bind.annotation.*;
* @desc优惠券模板(管理台API接口)
* @date 2021/6/26
*/
@Slf4j
@Api(tags = "优惠券模板(管理台API接口)")
@RestController
@RequestMapping("/api/v1/coupon_template")
@Slf4j
public class CouponTemplateController {
@Autowired
@ -39,10 +36,15 @@ public class CouponTemplateController {
@Autowired
private ISmsCouponService couponService;
@ApiOperation(value = "优惠券模板条件分页查询")
@GetMapping("/template/page")
public Result page(@ApiParam(value = "优惠券模板条件分页查询") CouponTemplatePageQuery query) {
IPage<SmsCouponTemplate> pageResult = couponTemplateService.pageQuery(query);
@ApiOperation(value = "列表分页")
@ApiImplicitParams({
@ApiImplicitParam(name = "page", value = "页码", paramType = "query", dataType = "Long"),
@ApiImplicitParam(name = "limit", value = "每页数量", paramType = "query", dataType = "Long"),
@ApiImplicitParam(name = "name", value = "广告名称", paramType = "query", dataType = "String")
})
@GetMapping
public Result page(Integer page, Integer limit, String name) {
IPage<SmsCouponTemplateVO> pageResult = couponTemplateService.pageQuery(page, limit, name);
return Result.success(pageResult.getRecords(), pageResult.getTotal());
}
@ -57,12 +59,12 @@ public class CouponTemplateController {
* @return result
*/
@ApiOperation(value = "创建优惠券模板")
@PostMapping("/template")
@PostMapping()
public Result<Object> createTemplate(@ApiParam(value = "优惠券模板构建表单")
@Validated
@RequestBody CouponTemplateForm form) {
log.info("Create Coupon Template , form:{}", form);
log.info("Create Coupon Template , Form:{}", form);
couponTemplateService.createTemplate(form);
return Result.success();
}
@ -102,12 +104,20 @@ public class CouponTemplateController {
@ApiOperation(value = "获取优惠券模板详情")
@GetMapping("/template/info")
public Result<CouponTemplateVO> info(@ApiParam(value = "优惠券模板ID", defaultValue = "1")
public Result<SmsCouponTemplateInfoVO> info(@ApiParam(value = "优惠券模板ID", defaultValue = "1")
@RequestParam("id") String id) {
CouponTemplateVO templateVO = couponTemplateService.info(id);
SmsCouponTemplateInfoVO templateVO = couponTemplateService.info(id);
return Result.success(templateVO);
}
@ApiOperation(value = "删除优惠券模板详情")
@DeleteMapping
public Result deleteTemplate(@ApiParam(value = "优惠券模板ID", defaultValue = "1")
@RequestParam("id") String id) {
couponTemplateService.deleteTemplate(id);
return Result.success();
}
@ApiOperation(value = "优惠券领取使用条件分页查询")
@GetMapping("/template/coupon/page")
public Result couponPage(@ApiParam(value = "优惠券领取使用条件分页查询") CouponPageQuery query) {

View File

@ -4,7 +4,6 @@ import com.youlai.common.result.Result;
import com.youlai.common.web.util.BeanMapperUtils;
import com.youlai.common.web.util.JwtUtils;
import com.youlai.mall.sms.pojo.domain.SmsCoupon;
import com.youlai.mall.sms.pojo.enums.CouponStateEnum;
import com.youlai.mall.sms.pojo.vo.CouponTemplateVO;
import com.youlai.mall.sms.pojo.vo.SmsCouponVO;
import com.youlai.mall.sms.service.ISmsCouponService;
@ -30,7 +29,7 @@ import java.util.List;
@RestController
@RequestMapping("/api-app/v1/coupon/")
@Slf4j
public class CouponController {
public class AppCouponController {
@Autowired
private ISmsCouponService couponService;
@ -41,12 +40,12 @@ public class CouponController {
@ApiOperation("查看可领取优惠券模板列表")
@GetMapping("/template")
public Result<List<CouponTemplateVO>> findAvailableTemplate() {
couponService.findAvailableTemplate(JwtUtils.getUserId());
return Result.success();
List<CouponTemplateVO> availableTemplate = couponService.findAvailableTemplate(JwtUtils.getUserId());
return Result.success(availableTemplate);
}
@ApiOperation("用户领取优惠券")
@GetMapping("receive")
@GetMapping("/receive")
public Result receive(@ApiParam(value = "优惠券模板ID")
@RequestParam("templateId") String templateId) {
couponService.receive(JwtUtils.getUserId(), templateId);
@ -55,8 +54,9 @@ public class CouponController {
@ApiOperation("查询用户已领取优惠券列表")
@GetMapping("/list")
public Result<List<SmsCouponVO>> list() {
List<SmsCoupon> coupons = couponService.findCouponsByState(JwtUtils.getUserId(), CouponStateEnum.USABLE.getCode());
public Result<List<SmsCouponVO>> list(@ApiParam(value = "优惠券模板ID", defaultValue = "1")
@RequestParam(value = "state", required = false) Integer state) {
List<SmsCoupon> coupons = couponService.findCouponsByState(JwtUtils.getUserId(), state);
return Result.success(BeanMapperUtils.mapList(coupons, SmsCouponVO.class));
}

View File

@ -1,7 +1,6 @@
package com.youlai.mall.sms.executor;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.youlai.mall.sms.pojo.vo.SettlementInfoVO;
import org.apache.commons.collections.CollectionUtils;
@ -26,7 +25,7 @@ public class AbstractExecutor {
*/
protected boolean isGoodsTypeSatisfy(SettlementInfoVO settlement) {
List<String> goodsType = settlement.getGoodsInfos().stream().map(SettlementInfoVO.GoodsInfo::getType).collect(Collectors.toList());
List<String> templateGoodsType = settlement.getCouponAndTemplateInfos().get(0).getTemplate().getRule().getUsage().getGoodsType();
List<String> templateGoodsType = settlement.getCouponAndTemplateInfos().get(0).getTemplate().getRule().getGoodsCategories();
if (CollUtil.isEmpty(templateGoodsType)){
return true;
}
@ -63,11 +62,11 @@ public class AbstractExecutor {
List<String> allSharedKeysForC1 = new ArrayList<>();
allSharedKeysForC1.add(c1Key);
allSharedKeysForC1.addAll(JSON.parseObject(c1.getTemplate().getRule().getWeight(), List.class));
// allSharedKeysForC1.addAll(JSON.parseObject(c1.getTemplate().getRule().getWeight(), List.class));
List<String> allSharedKeysForC2 = new ArrayList<>();
allSharedKeysForC2.add(c2Key);
allSharedKeysForC2.addAll(JSON.parseObject(c2.getTemplate().getRule().getWeight(), List.class));
// allSharedKeysForC2.addAll(JSON.parseObject(c2.getTemplate().getRule().getWeight(), List.class));
return CollectionUtils.isSubCollection(Arrays.asList(c1Key, c2Key), allSharedKeysForC1)
|| CollectionUtils.isSubCollection(Arrays.asList(c1Key, c2Key), allSharedKeysForC2);

View File

@ -34,7 +34,7 @@ public class ManJianZheKouExecutor extends AbstractExecutor implements RuleExecu
List<String> templateGoodsType = new ArrayList<>();
for (SettlementInfoVO.CouponAndTemplateInfo couponAndTemplateInfo : settlement.getCouponAndTemplateInfos()) {
List<String> type = couponAndTemplateInfo.getTemplate().getRule().getUsage().getGoodsType();
List<String> type = couponAndTemplateInfo.getTemplate().getRule().getGoodsCategories();
templateGoodsType.addAll(type);
}

View File

@ -32,7 +32,7 @@ public interface ICouponRedisService {
* @param templateId 优惠券模板ID
* @return 优惠券码
*/
String tryToAcquireCouponCodeFromCache(Long templateId);
String tryToAcquireCouponCodeFromCache(String templateId);
/**
* 向缓存中添加用户可用优惠券

View File

@ -4,10 +4,11 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.youlai.mall.sms.pojo.domain.SmsCouponTemplate;
import com.youlai.mall.sms.pojo.form.CouponTemplateForm;
import com.youlai.mall.sms.pojo.query.CouponTemplatePageQuery;
import com.youlai.mall.sms.pojo.vo.CouponTemplateVO;
import com.youlai.mall.sms.pojo.vo.SmsCouponTemplateInfoVO;
import com.youlai.mall.sms.pojo.vo.SmsCouponTemplateVO;
import java.util.List;
import java.util.Set;
/**
* @author xinyi
@ -17,7 +18,7 @@ import java.util.List;
public interface ISmsCouponTemplateService extends IService<SmsCouponTemplate> {
IPage<SmsCouponTemplate> pageQuery(CouponTemplatePageQuery query);
IPage<SmsCouponTemplateVO> pageQuery(Integer page, Integer limit, String name);
/**
* 创建优惠券模板
@ -30,14 +31,24 @@ public interface ISmsCouponTemplateService extends IService<SmsCouponTemplate> {
/**
* 修改优惠券模板
*
* @param form {@link CouponTemplateForm} 模板信息请求对象
* @return {@link SmsCouponTemplate} 优惠券模板实体类
*/
SmsCouponTemplate updateTemplate(CouponTemplateForm form);
/**
* 删除优惠券模板
*
* @param id 优惠券模板ID
*/
void deleteTemplate(String id);
/**
* 优惠券模板审核
*
* @param id
*/
void confirmTemplate(String id);
@ -54,15 +65,32 @@ public interface ISmsCouponTemplateService extends IService<SmsCouponTemplate> {
/**
* 查询未过期的优惠券模板列表
*
* @param expired 是否过期
* @param verifyStateCode 是否已审核
* @param usedStateCode 是否在使用有效期范围内
* @return 优惠券模板列表
*/
List<SmsCouponTemplate> findAllNotExpiredTemplate(Integer expired);
List<SmsCouponTemplate> findAllNotExpiredTemplate(Integer verifyStateCode, Integer usedStateCode);
/**
* 查询优惠券模板详情
*
* @param id 优惠券模板ID
* @return 优惠券模板详情
*/
CouponTemplateVO info(String id);
SmsCouponTemplateInfoVO info(String id);
/**
* 查询所有正在发放中的优惠券模板
*
* @param userTypes 用户类型
* @return 优惠券模板列表
*/
List<SmsCouponTemplate> findAllOfferingTemplate(Set<Integer> userTypes);
/**
* 查询优惠券模板
* @param id
* @return
*/
SmsCouponTemplate findByTemplateId(String id);
}

View File

@ -1,6 +1,5 @@
package com.youlai.mall.sms.service.impl;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.common.web.exception.BizException;
@ -8,7 +7,6 @@ import com.youlai.common.web.util.JwtUtils;
import com.youlai.mall.sms.mapper.SmsCouponRecordMapper;
import com.youlai.mall.sms.pojo.domain.SmsCoupon;
import com.youlai.mall.sms.pojo.domain.SmsCouponRecord;
import com.youlai.mall.sms.pojo.enums.CouponStateEnum;
import com.youlai.mall.sms.service.ICouponRecordService;
import com.youlai.mall.sms.service.ISmsCouponService;
import lombok.extern.slf4j.Slf4j;
@ -51,8 +49,8 @@ public class CouponRecordServiceImpl extends ServiceImpl<SmsCouponRecordMapper,
SmsCouponRecord couponRecord = new SmsCouponRecord();
BeanUtils.copyProperties(coupon, couponRecord);
couponRecord.setStartTime(new Date());
couponRecord.setEndTime(DateUtil.offsetDay(new Date(), coupon.getValidDays()));
couponRecord.setUseState(CouponStateEnum.NEW.name());
// couponRecord.setEndTime(DateUtil.offsetDay(new Date(), coupon.getValidDays()));
// couponRecord.setUseState(CouponStateEnum.NEW.name());
couponRecord.setUserId(JwtUtils.getUserId());
couponRecord.setUserName(JwtUtils.getUsername());
couponRecord.setCouponId(coupon.getId());
@ -86,23 +84,23 @@ public class CouponRecordServiceImpl extends ServiceImpl<SmsCouponRecordMapper,
throw new BizException("优惠券不存在");
}
//库存不足
if ((couponEntity.getPublishCount() - couponEntity.getTakeCount()) <= 0) {
throw new BizException("优惠券已经被领光了");
}
// if ((couponEntity.getPublishCount() - couponEntity.getTakeCount()) <= 0) {
// throw new BizException("优惠券已经被领光了");
// }
//是否在领取时间范围
long time = System.currentTimeMillis();
long start = couponEntity.getStartTime().getTime();
long end = couponEntity.getEndTime().getTime();
if (time < start || time > end) {
throw new BizException("优惠券不在领券时间范围内");
}
// long time = System.currentTimeMillis();
// long start = couponEntity.getStartTime().getTime();
// long end = couponEntity.getEndTime().getTime();
// if (time < start || time > end) {
// throw new BizException("优惠券不在领券时间范围内");
// }
//用户是否超过限制
int recordNum = this.count(new QueryWrapper<SmsCouponRecord>()
.eq("coupon_id", couponEntity.getId())
.eq("user_id", userId));
if (recordNum >= couponEntity.getLimitCount()) {
throw new BizException("优惠券已经达到领券次数限制");
}
// if (recordNum >= couponEntity.getLimitCount()) {
// throw new BizException("优惠券已经达到领券次数限制");
// }
}
}

View File

@ -74,7 +74,7 @@ public class CouponRedisServiceImpl implements ICouponRedisService {
}
@Override
public String tryToAcquireCouponCodeFromCache(Long templateId) {
public String tryToAcquireCouponCodeFromCache(String templateId) {
String redisKey = String.format("%s%s", SMS_COUPON_TEMPLATE_CODE_KEY, templateId);
String couponCode = (String) redisTemplate.opsForList().leftPop(redisKey);
log.info("Acquire Coupon Code, {} {} {}", templateId, redisKey, couponCode);

View File

@ -1,16 +1,23 @@
package com.youlai.mall.sms.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.common.web.exception.BizException;
import com.youlai.common.web.util.BeanMapperUtils;
import com.youlai.common.web.util.JwtUtils;
import com.youlai.mall.sms.mapper.SmsCouponMapper;
import com.youlai.mall.sms.pojo.domain.CouponTemplateRule;
import com.youlai.mall.sms.pojo.domain.SmsCoupon;
import com.youlai.mall.sms.pojo.domain.SmsCouponTemplate;
import com.youlai.mall.sms.pojo.enums.CouponOfferStateEnum;
import com.youlai.mall.sms.pojo.enums.CouponStateEnum;
import com.youlai.mall.sms.pojo.enums.UserTypeEnum;
import com.youlai.mall.sms.pojo.form.CouponForm;
import com.youlai.mall.sms.pojo.query.CouponPageQuery;
import com.youlai.mall.sms.pojo.vo.CouponClassify;
@ -23,10 +30,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -49,27 +53,23 @@ public class SmsCouponServiceImpl extends ServiceImpl<SmsCouponMapper, SmsCoupon
@Override
public List<CouponTemplateVO> findAvailableTemplate(Long userId) {
// 1查询所有可用优惠券模板
List<SmsCouponTemplate> templates = couponTemplateService.findAllUsableTemplate(1, 1);
Date nowTime = new Date();
templates = templates.stream()
.filter(template -> template.getRule().getExpiration().getDeadline() < nowTime.getTime())
.collect(Collectors.toList());
Set<Integer> userTypes = new HashSet<>();
userTypes.add(UserTypeEnum.ALL.getCode());
// 1正在发放中的优惠券模板
List<SmsCouponTemplate> templates = couponTemplateService.findAllOfferingTemplate(userTypes);
if (CollUtil.isEmpty(templates)) {
log.info("All Usable Template is Empty.");
return new ArrayList<>();
}
log.info("All Usable Coupon Template Size={}", templates.size());
// 2查询用户已领取优惠券数量
// 2过滤用户已领取,并且领取数量等于限制的优惠券模板
log.info("All Usable Coupon Template Size={}", templates.size());
List<SmsCoupon> coupons = findCouponsByState(userId, 0);
Map<Long, List<SmsCoupon>> couponMap = coupons.stream().collect(Collectors.groupingBy(SmsCoupon::getTemplateId));
log.info("All User Receive Coupon Template Size={}", couponMap.size());
// 3过滤用户已领取优惠券模板
templates = templates.stream().filter(template -> {
List<SmsCoupon> receivedCoupons = couponMap.getOrDefault(template.getId(), new ArrayList<>());
return template.getRule().getLimitation() > receivedCoupons.size();
return template.getRule().getUserLimit().getLimit() > receivedCoupons.size();
}).collect(Collectors.toList());
log.info("Find All Available Template Size={}", templates.size());
@ -78,9 +78,31 @@ public class SmsCouponServiceImpl extends ServiceImpl<SmsCouponMapper, SmsCoupon
@Override
public void receive(Long userId, String templateId) {
// 1校验优惠券发放状态
SmsCouponTemplate template = couponTemplateService.findByTemplateId(templateId);
long nowTime = System.currentTimeMillis();
if (template.getOfferState() != CouponOfferStateEnum.GOING || nowTime > template.getOfferEndTime()) {
throw new BizException("当前优惠券不在领取时间范围");
}
// 2校验用户领取状态
List<SmsCoupon> coupons = this.findByTemplateId(userId, templateId);
if (template.getRule().getUserLimit().getLimit() <= coupons.size()) {
log.warn("Cannot Receive Coupon Template, Max Limit, UserId={}", userId);
throw new BizException("已达到领取优惠券最大限制");
}
// 3查看该优惠券剩余优惠券码
String couponCode = couponRedisService.tryToAcquireCouponCodeFromCache(templateId);
if (StrUtil.isEmpty(couponCode)) {
throw new BizException("优惠券已抢光");
}
// 4生成优惠券领取记录
saveCouponRecord(template, couponCode);
}
@Override
public List<SmsCoupon> findCouponsByState(Long userId, Integer state) {
log.info("根据查询优惠券列表UserId={}, State={}", userId, state);
@ -161,4 +183,47 @@ public class SmsCouponServiceImpl extends ServiceImpl<SmsCouponMapper, SmsCoupon
public int updateTakeStock(String couponId) {
return this.updateTakeStock(couponId);
}
/**
* 生成优惠券模板领取记录
*
* @param template
* @param couponCode
*/
private boolean saveCouponRecord(SmsCouponTemplate template, String couponCode) {
log.info("Create Coupon Records, TemplateId={}, CouponCode={}", template.getId(), couponCode);
SmsCoupon coupon = new SmsCoupon();
coupon.setTemplateId(template.getId());
coupon.setCouponCode(couponCode);
coupon.setUserId(JwtUtils.getUserId());
coupon.setUserName(JwtUtils.getUsername());
coupon.setState(CouponStateEnum.USABLE);
CouponTemplateRule.Expiration expiration = template.getRule().getExpiration();
if (expiration.getPeriod() == 1) {
coupon.setAvailableStartTime(expiration.getStartTime());
coupon.setAvailableStartTime(expiration.getEndTime());
} else {
// 如果以领取之日起几天内有效需注意最大有效天数不能大于优惠券模板过期时间
DateTime today = DateUtil.beginOfDay(new Date());
coupon.setAvailableStartTime(today.getTime());
DateTime dateTime = DateUtil.offsetDay(today, expiration.getGap());
coupon.setAvailableEndTime(dateTime.getTime() < template.getUsedEndTime() ? dateTime.getTime() : template.getUsedEndTime());
}
return save(coupon);
}
/**
* 查询优惠券领取记录
*
* @param userId 用户ID
* @param templateId 优惠券模板ID
* @return
*/
private List<SmsCoupon> findByTemplateId(Long userId, String templateId) {
QueryWrapper<SmsCoupon> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id", userId);
queryWrapper.eq("template_id", templateId);
return list(queryWrapper);
}
}

View File

@ -1,21 +1,26 @@
package com.youlai.mall.sms.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.common.mybatis.utils.PageMapperUtils;
import com.youlai.common.web.exception.BizException;
import com.youlai.common.web.util.BeanMapperUtils;
import com.youlai.mall.sms.mapper.SmsCouponTemplateMapper;
import com.youlai.mall.sms.pojo.domain.CouponTemplateRule;
import com.youlai.mall.sms.pojo.domain.SmsCouponTemplate;
import com.youlai.mall.sms.pojo.enums.CouponCategoryEnum;
import com.youlai.mall.sms.pojo.enums.CouponTemplateStateEnum;
import com.youlai.mall.sms.pojo.enums.DistributeTargetEnum;
import com.youlai.mall.sms.pojo.enums.CouponOfferStateEnum;
import com.youlai.mall.sms.pojo.enums.CouponVerifyStateEnum;
import com.youlai.mall.sms.pojo.enums.UserTypeEnum;
import com.youlai.mall.sms.pojo.form.CouponTemplateForm;
import com.youlai.mall.sms.pojo.query.CouponTemplatePageQuery;
import com.youlai.mall.sms.pojo.vo.CouponTemplateVO;
import com.youlai.mall.sms.pojo.vo.SmsCouponTemplateInfoVO;
import com.youlai.mall.sms.pojo.vo.SmsCouponTemplateVO;
import com.youlai.mall.sms.service.IAsyncService;
import com.youlai.mall.sms.service.ISmsCouponTemplateService;
import lombok.extern.slf4j.Slf4j;
@ -24,6 +29,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author xinyi
@ -39,16 +46,12 @@ public class SmsCouponTemplateServiceImpl extends ServiceImpl<SmsCouponTemplateM
private IAsyncService asyncService;
@Override
public IPage<SmsCouponTemplate> pageQuery(CouponTemplatePageQuery query) {
Page<SmsCouponTemplate> page = new Page<>(query.getPageNum(), query.getPageSize());
public IPage<SmsCouponTemplateVO> pageQuery(Integer pageNum, Integer limit, String name) {
Page<SmsCouponTemplate> page = new Page<>(pageNum, limit);
QueryWrapper<SmsCouponTemplate> queryWrapper = new QueryWrapper<>();
queryWrapper.like(StrUtil.isNotBlank(query.getName()), "name", query.getName());
queryWrapper.eq(query.getCategory() != null, "category", query.getCategory());
queryWrapper.eq(query.getState() != null, "state", query.getState());
queryWrapper.eq(query.getTarget() != null, "target", query.getTarget());
queryWrapper.gt(query.getEndTime() != null, "gmt_create", query.getEndTime());
queryWrapper.gt(query.getStartTime() != null, "gmt_create", query.getStartTime());
return this.page(page, queryWrapper);
queryWrapper.like(StrUtil.isNotBlank(name), "name", name);
Page<SmsCouponTemplate> pageResult = this.page(page, queryWrapper);
return PageMapperUtils.mapPage(pageResult, SmsCouponTemplateVO.class);
}
@Override
@ -62,7 +65,6 @@ public class SmsCouponTemplateServiceImpl extends ServiceImpl<SmsCouponTemplateM
// 构造 CouponTemplate 并保存到数据库
SmsCouponTemplate template = formToTemplate(form);
this.save(template);
return template;
}
@ -71,9 +73,9 @@ public class SmsCouponTemplateServiceImpl extends ServiceImpl<SmsCouponTemplateM
log.info("Update Coupon Template, ID={}, form={}", form.getId(), form);
// 1判断优惠券的名称有没有变化
SmsCouponTemplate template = findByTemplateId(form.getId());
if (CouponTemplateStateEnum.INIT != template.getState()) {
throw new BizException("Coupon Template State Not Init");
}
// if (CouponTemplateStateEnum.INIT != template.getState()) {
// throw new BizException("Coupon Template State Not Init");
// }
if (!StringUtils.equals(template.getName(), form.getName())) {
// 如果form提交的名称不一致需要判断名称是否重复
if (null != findByCouponTemplateName(form.getName())) {
@ -88,17 +90,28 @@ public class SmsCouponTemplateServiceImpl extends ServiceImpl<SmsCouponTemplateM
return template;
}
@Override
public void deleteTemplate(String id) {
log.info("Delete Coupon Template, ID={}", id);
// 1判断优惠券的名称有没有变化
SmsCouponTemplate template = findByTemplateId(id);
if (template.getVerifyState() != CouponVerifyStateEnum.INIT) {
throw new BizException("当前优惠券模板记录已生效,无法删除!");
}
this.removeById(id);
}
@Override
public void confirmTemplate(String id) {
// 1校验优惠券状态
SmsCouponTemplate template = findByTemplateId(id);
if (CouponTemplateStateEnum.INIT != template.getState()) {
log.info("Finish Confirm Coupon Template State Not Init, TemplateID={}.", id);
return;
}
// if (CouponTemplateStateEnum.INIT != template.getState()) {
// log.info("Finish Confirm Coupon Template State Not Init, TemplateID={}.", id);
// return;
// }
// 2修改优惠券模板状态生成优惠券模板编码
template.setState(CouponTemplateStateEnum.USED);
// template.setState(CouponTemplateStateEnum.USED);
template.setCode(template.getCategory() +
DateUtil.today().replace("-", "") +
template.getId());
@ -119,16 +132,33 @@ public class SmsCouponTemplateServiceImpl extends ServiceImpl<SmsCouponTemplateM
}
@Override
public List<SmsCouponTemplate> findAllNotExpiredTemplate(Integer expired) {
public List<SmsCouponTemplate> findAllNotExpiredTemplate(Integer verifyStateCode, Integer usedStateCode) {
QueryWrapper<SmsCouponTemplate> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("expired", expired);
queryWrapper.eq("verify_state", verifyStateCode);
queryWrapper.lt("used_state", usedStateCode);
return this.list(queryWrapper);
}
@Override
public CouponTemplateVO info(String id) {
public SmsCouponTemplateInfoVO info(String id) {
log.info("Query Coupon Template Info,ID={}", id);
SmsCouponTemplate template = findByTemplateId(id);
return BeanMapperUtils.map(template,CouponTemplateVO.class);
return BeanMapperUtils.map(template, SmsCouponTemplateInfoVO.class);
}
@Override
public List<SmsCouponTemplate> findAllOfferingTemplate(Set<Integer> userTypes) {
log.info("Find All Offering Coupon Template, userTypes", JSON.toJSONString(userTypes));
// TODO 优惠券模板是实际业务中请求量比较大的业务建议将这部分数据放入 Redis
QueryWrapper<SmsCouponTemplate> queryWrapper = new QueryWrapper<>();
queryWrapper.in("offer_state", CouponOfferStateEnum.GOING.getCode());
List<SmsCouponTemplate> templates = list(queryWrapper);
long nowTime = System.currentTimeMillis();
return templates.stream()
.filter(template -> template.getOfferEndTime().compareTo(nowTime) > 0 &&
userTypes.contains(template.getRule().getUserLimit().getUserType().getCode()
))
.collect(Collectors.toList());
}
/**
@ -137,7 +167,8 @@ public class SmsCouponTemplateServiceImpl extends ServiceImpl<SmsCouponTemplateM
* @param id 优惠券模板ID
* @return 优惠券模板
*/
private SmsCouponTemplate findByTemplateId(String id) {
@Override
public SmsCouponTemplate findByTemplateId(String id) {
SmsCouponTemplate template = this.getById(id);
if (template == null) {
throw new BizException("Template Not Exist, ID=" + id);
@ -161,11 +192,38 @@ public class SmsCouponTemplateServiceImpl extends ServiceImpl<SmsCouponTemplateM
SmsCouponTemplate template = new SmsCouponTemplate();
template.setName(form.getName());
template.setLogo(form.getLogo());
template.setCategory(CouponCategoryEnum.of(form.getCategory()));
template.setCategory(CouponCategoryEnum.of(form.getCategoryCode()));
template.setTotal(form.getTotal());
template.setTarget(DistributeTargetEnum.of(form.getTarget()));
template.setRule(form.getRule());
template.setState(CouponTemplateStateEnum.INIT);
template.setDescription(form.getDescription());
template.setOfferStartTime(form.getOfferTime()[0]);
template.setOfferEndTime(form.getOfferTime()[1]);
template.setUsedStartTime(form.getUsedTime()[0]);
template.setUsedEndTime(form.getUsedTime()[1]);
CouponTemplateRule rule = new CouponTemplateRule();
CouponTemplateRule.Discount discount = new CouponTemplateRule.Discount();
discount.setBase(form.getRule().getDiscount().getBase());
discount.setQuota(form.getRule().getDiscount().getQuota());
rule.setDiscount(discount);
CouponTemplateRule.Expiration expiration = new CouponTemplateRule.Expiration();
expiration.setGap(form.getRule().getExpiration().getGap());
expiration.setPeriod(form.getRule().getExpiration().getPeriod());
if (CollUtil.isNotEmpty(form.getRule().getExpiration().getTime()) && form.getRule().getExpiration().getTime().size() == 2) {
expiration.setStartTime(form.getRule().getExpiration().getTime().get(0));
expiration.setEndTime(form.getRule().getExpiration().getTime().get(1));
}
rule.setExpiration(expiration);
CouponTemplateRule.UserLimit userLimit = new CouponTemplateRule.UserLimit();
userLimit.setUserType(UserTypeEnum.of(form.getRule().getUserLimit().getUserType()));
userLimit.setLimit(form.getRule().getUserLimit().getLimit());
rule.setUserLimit(userLimit);
rule.setWeight(form.getRule().getWeight());
rule.setGoodsCategories(form.getRule().getGoodsCategories());
template.setRule(rule);
return template;
}
}

View File

@ -39,7 +39,7 @@ public class TemplateBaseServiceImpl implements ITemplateBaseService {
@Override
public List<SmsCouponTemplate> findAllUsableTemplate() {
return couponTemplateService.findAllUsableTemplate(true, false);
return couponTemplateService.findAllUsableTemplate(1, 0);
}
@Override

View File

@ -2,7 +2,9 @@ package com.youlai.mall.sms.shedule;
import cn.hutool.core.collection.CollUtil;
import com.youlai.mall.sms.pojo.domain.SmsCouponTemplate;
import com.youlai.mall.sms.pojo.vo.TemplateRuleVO;
import com.youlai.mall.sms.pojo.enums.CouponOfferStateEnum;
import com.youlai.mall.sms.pojo.enums.CouponUsedStateEnum;
import com.youlai.mall.sms.pojo.enums.CouponVerifyStateEnum;
import com.youlai.mall.sms.service.ISmsCouponTemplateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@ -10,7 +12,6 @@ import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
@ -26,27 +27,40 @@ public class ScheduleTask {
private ISmsCouponTemplateService couponTemplateService;
/**
* 下线已过期的优惠券模板
* 更新所有优惠券发放状态使用状态
*/
@Scheduled(fixedRate = 60 * 60 * 1000)
public void offlineCouponTemplate() {
log.info("Start To Expired CouponTemplate.");
// 查询未过期的优惠券模板
List<SmsCouponTemplate> templates = couponTemplateService.findAllNotExpiredTemplate(1);
// 查询所有已审核使用状态未结束的优惠券模板
List<SmsCouponTemplate> templates = couponTemplateService.findAllNotExpiredTemplate(CouponVerifyStateEnum.VERIFY.getCode(),CouponUsedStateEnum.FINISH.getCode());
if (CollUtil.isEmpty(templates)) {
log.info("Done To Expired CouponTemplate.");
return;
}
Date nowTime = new Date();
Long nowTime = System.currentTimeMillis();
List<SmsCouponTemplate> expiredTemplates = new ArrayList<>(templates.size());
for (SmsCouponTemplate template : templates) {
TemplateRuleVO rule = template.getRule();
if (rule.getExpiration().getDeadline() < nowTime.getTime()) {
template.setExpired(0);
expiredTemplates.add(template);
if (template.getOfferState().getCode() < CouponOfferStateEnum.FINISH.getCode()) {
if (nowTime.compareTo(template.getOfferEndTime()) > 0) {
template.setOfferState(CouponOfferStateEnum.FINISH);
} else if (nowTime.compareTo(template.getOfferStartTime()) > 0) {
template.setOfferState(CouponOfferStateEnum.GOING);
// TODO 发送rabbitmq消息批量生成优惠券码发放优惠券
}
}
if (template.getUsedState().getCode() < CouponUsedStateEnum.FINISH.getCode()) {
if (nowTime.compareTo(template.getUsedEndTime()) > 0) {
template.setUsedState(CouponUsedStateEnum.FINISH);
// TODO 发送rabbitmq消息批量更新用户已领取未使用优惠券状态为已过期
} else if (nowTime.compareTo(template.getUsedStartTime()) > 0) {
template.setUsedState(CouponUsedStateEnum.GOING);
}
}
}
couponTemplateService.updateBatchById(expiredTemplates);
log.info("Update Expired CouponTemplate Num:{}", expiredTemplates.size());
log.info("Done To Expired CouponTemplate.");

View File

@ -7,7 +7,9 @@ spring:
cloud:
nacos:
discovery:
server-addr: http://localhost:8848
server-addr: http://47.104.214.204:8848
namespace: dev_namespace_id
config:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
file-extension: yaml
namespace: dev_namespace_id

View File

@ -7,7 +7,9 @@ spring:
cloud:
nacos:
discovery:
server-addr: http://localhost:8848
server-addr: http://47.104.214.204:8848
namespace: dev_namespace_id
config:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
file-extension: yaml
namespace: dev_namespace_id

View File

@ -7,7 +7,9 @@ spring:
cloud:
nacos:
discovery:
server-addr: http://localhost:8848
server-addr: http://47.104.214.204:8848
namespace: dev_namespace_id
config:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
file-extension: yaml
namespace: dev_namespace_id

View File

@ -7,10 +7,9 @@ spring:
cloud:
nacos:
discovery:
server-addr: http://localhost:8848
server-addr: http://47.104.214.204:8848
namespace: dev_namespace_id
config:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
file-extension: yaml
group: DEFAULT_GROUP
namespace: dev_namespace_id

View File

@ -12,6 +12,12 @@
<artifactId>common-mybatis</artifactId>
<dependencies>
<dependency>
<groupId>com.youlai</groupId>
<artifactId>common-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>

View File

@ -15,11 +15,14 @@ public class FieldFillHandler implements MetaObjectHandler {
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
this.setFieldValByName("gmtCreate", new Date(), metaObject);
this.setFieldValByName("gmtModified", new Date(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime", new Date(), metaObject);
this.setFieldValByName("gmtModified", new Date(), metaObject);
}
}

View File

@ -0,0 +1,28 @@
package com.youlai.common.mybatis.utils;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.youlai.common.web.util.BeanMapperUtils;
/**
* @author xinyi
* @desc mybatis 分页类型转换
* @date 2021/7/31
*/
public class PageMapperUtils {
public static <S, D> IPage<D> mapPage(final IPage<S> source, final Class<D> destType) {
final IPage<D> dest = new Page<>();
if (source == null ) {
return dest;
}
dest.setCurrent(source.getCurrent());
dest.setPages(source.getPages());
dest.setSize(source.getSize());
dest.setTotal(source.getTotal());
dest.setRecords(BeanMapperUtils.mapList(source.getRecords(),destType));
return dest;
}
}

View File

@ -40,6 +40,8 @@ public class BeanMapperUtils {
return dest;
}
public static <S, D> Collection<D> mapCollection(final Collection<S> source, final Class<D> destType) {
final Collection<D> dest = new ArrayList<>();
if (source == null || source.size() == 0) {

View File

@ -42,7 +42,7 @@ public class ResourceServerManager implements ReactiveAuthorizationManager<Autho
private final UrlPermRolesLocalCache urlPermRolesLocalCache;
// 是否开启本地缓存
@Value("${local-cache.enabled}")
@Value("${local-cache.enabled:true}")
private Boolean localCacheEnabled;
@Override

View File

@ -2,18 +2,16 @@ server:
port: 9999
spring:
main:
allow-bean-definition-overriding: true
application:
name: youlai-gateway
cloud:
nacos:
# 注册中心
discovery:
server-addr: http://localhost:8848
# 配置中心
server-addr: http://47.104.214.204:8848
namespace: dev_namespace_id
config:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
file-extension: yaml
namespace: dev_namespace_id