diff --git a/DB/version4.2.4toMASTER.sql b/DB/version4.2.4toMASTER.sql deleted file mode 100644 index a00128f7e..000000000 --- a/DB/version4.2.4toMASTER.sql +++ /dev/null @@ -1,51 +0,0 @@ -/** 增加签到日期 **/ -ALTER TABLE li_member_sign - ADD day int DEFAULT NULL COMMENT '签到日 '; -ALTER TABLE li_member_sign - DROP INDEX uk_member_day; -ALTER TABLE li_member_sign - add unique uk_member_day (member_id, day) COMMENT 'uk_member_day'; - - - --- ---------------------------- --- Table structure for li_hot_words_history --- ---------------------------- -DROP TABLE IF EXISTS `li_hot_words_history`; -CREATE TABLE `li_hot_words_history` -( - `id` bigint NOT NULL COMMENT 'ID', - `create_time` datetime(6) DEFAULT NULL COMMENT '创建时间', - `keywords` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '热词', - `score` int DEFAULT NULL COMMENT '热词分数', - PRIMARY KEY (`id`) -) ENGINE = InnoDB DEFAULT CHARSET = utf8mb3 COLLATE = utf8_bin COMMENT '热词历史表'; - --- ---------------------------- --- Records of li_hot_words_history --- ---------------------------- - --- ---------------------------- --- Table structure for li_wholesale --- ---------------------------- -DROP TABLE IF EXISTS `li_wholesale`; -CREATE TABLE `li_wholesale` -( - `id` bigint NOT NULL, - `create_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL, - `create_time` datetime(6) DEFAULT NULL, - `delete_flag` bit(1) DEFAULT NULL, - `update_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL, - `update_time` datetime(6) DEFAULT NULL, - `price` decimal(10, 2) DEFAULT NULL COMMENT '价格', - `goods_id` bigint DEFAULT NULL COMMENT '商品id', - `sku_id` bigint DEFAULT NULL COMMENT '商品skuId', - `num` int DEFAULT NULL COMMENT '起购量', - PRIMARY KEY (`id`) -) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_bin COMMENT '批发规则表'; - -ALTER TABLE li_wholesale - ADD template_id bigint DEFAULT NULL COMMENT '商品模版id'; - -/** 店铺--默认页面是否开启**/ -ALTER TABLE li_store ADD page_show bit(1) DEFAULT NULL COMMENT '默认页面是否开启'; \ No newline at end of file diff --git a/DB/version4.2.5toMASTER.sql b/DB/version4.2.5toMASTER.sql new file mode 100644 index 000000000..d0fa67939 --- /dev/null +++ b/DB/version4.2.5toMASTER.sql @@ -0,0 +1,9 @@ +-- 会员优惠券标识 +CREATE TABLE `li_member_coupon_sign` ( + `id` bigint NOT NULL, + `coupon_activity_Id` bigint NULL DEFAULT NULL COMMENT '优惠券活动id', + `member_id` bigint NULL DEFAULT NULL COMMENT '会员id', + `invalid_time` datetime NULL DEFAULT NULL COMMENT '过期时间', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = DYNAMIC; \ No newline at end of file diff --git a/consumer/src/main/java/cn/lili/timetask/handler/impl/promotion/MemberCouponSignEverydayExecute.java b/consumer/src/main/java/cn/lili/timetask/handler/impl/promotion/MemberCouponSignEverydayExecute.java new file mode 100644 index 000000000..13a5e7a32 --- /dev/null +++ b/consumer/src/main/java/cn/lili/timetask/handler/impl/promotion/MemberCouponSignEverydayExecute.java @@ -0,0 +1,45 @@ +package cn.lili.timetask.handler.impl.promotion; + +import cn.lili.common.enums.PromotionTypeEnum; +import cn.lili.modules.promotion.entity.dos.Seckill; +import cn.lili.modules.promotion.service.MemberCouponSignService; +import cn.lili.modules.promotion.service.SeckillService; +import cn.lili.modules.promotion.tools.PromotionTools; +import cn.lili.modules.search.service.EsGoodsIndexService; +import cn.lili.modules.system.entity.dos.Setting; +import cn.lili.modules.system.entity.dto.SeckillSetting; +import cn.lili.modules.system.entity.enums.SettingEnum; +import cn.lili.modules.system.service.SettingService; +import cn.lili.timetask.handler.EveryDayExecute; +import com.google.gson.Gson; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * 促销活动每日定时器 + * + * @author Chopper + * @since 2021/3/18 3:23 下午 + */ +@Slf4j +@Component +public class MemberCouponSignEverydayExecute implements EveryDayExecute { + + @Autowired + private MemberCouponSignService memberCouponSignService; + + /** + * 将已过期的促销活动置为结束 + */ + @Override + public void execute() { + try { + memberCouponSignService.clean(); + } catch (Exception e) { + log.error("清除领取优惠券标记异常", e); + } + + } + +} diff --git a/framework/src/main/java/cn/lili/cache/CachePrefix.java b/framework/src/main/java/cn/lili/cache/CachePrefix.java index b110295c9..c1481c65f 100644 --- a/framework/src/main/java/cn/lili/cache/CachePrefix.java +++ b/framework/src/main/java/cn/lili/cache/CachePrefix.java @@ -240,6 +240,10 @@ public enum CachePrefix { * 积分商品缓存key前缀 */ STORE_ID_EXCHANGE, + /** + * 会员领取标记 + */ + MEMBER_COUPON_SIGN, //================交易================= diff --git a/framework/src/main/java/cn/lili/cache/impl/RedisCache.java b/framework/src/main/java/cn/lili/cache/impl/RedisCache.java index a5e8aeec0..ac56702b8 100644 --- a/framework/src/main/java/cn/lili/cache/impl/RedisCache.java +++ b/framework/src/main/java/cn/lili/cache/impl/RedisCache.java @@ -185,7 +185,7 @@ public class RedisCache implements Cache { public Long counter(Object key) { HyperLogLogOperations operations = redisTemplate.opsForHyperLogLog(); - //add 方法对应 PFADD 命令 + //add 方法对应 PFCOUNT 命令 return operations.size(key); } diff --git a/framework/src/main/java/cn/lili/common/utils/DateUtil.java b/framework/src/main/java/cn/lili/common/utils/DateUtil.java index ec6c5ef47..1e0a10e71 100644 --- a/framework/src/main/java/cn/lili/common/utils/DateUtil.java +++ b/framework/src/main/java/cn/lili/common/utils/DateUtil.java @@ -26,15 +26,16 @@ public class DateUtil { * @return 今天开始时间 */ public static Long getDayOfStart() { - return DateUtil.getDateline()/(60*24*60); + return DateUtil.getDateline() / (60 * 24 * 60); } + /** * 指定日的开始时间 * * @return 指定日时间 */ public static Long getDayOfStart(Date date) { - return date.getTime()/(60*24*60); + return date.getTime() / (60 * 24 * 60); } /** @@ -349,6 +350,22 @@ public class DateUtil { return getDateline(mon, STANDARD_FORMAT); } + /** + * 获取当前天的结束时间 + * + * @return 当前天的开始时间 + */ + public static Date getCurrentDayStartTime() { + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + cal.set(Calendar.SECOND, cal.get(Calendar.SECOND) - 1); + return cal.getTime(); + } + /** * 获取当前天的结束时间 * @@ -366,6 +383,21 @@ public class DateUtil { return cal.getTime(); } + /** + * 获取干净的时间 + * + * @return 时间对象 + */ + public static Calendar getCleanCalendar() { + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + return cal; + } + /** * 获取延时时间(秒) * diff --git a/framework/src/main/java/cn/lili/modules/promotion/entity/dos/CouponActivity.java b/framework/src/main/java/cn/lili/modules/promotion/entity/dos/CouponActivity.java index 96218db34..e92e24860 100644 --- a/framework/src/main/java/cn/lili/modules/promotion/entity/dos/CouponActivity.java +++ b/framework/src/main/java/cn/lili/modules/promotion/entity/dos/CouponActivity.java @@ -2,6 +2,7 @@ package cn.lili.modules.promotion.entity.dos; import cn.lili.modules.promotion.entity.enums.CouponActivitySendTypeEnum; import cn.lili.modules.promotion.entity.enums.CouponActivityTypeEnum; +import cn.lili.modules.promotion.entity.enums.CouponFrequencyEnum; import com.baomidou.mybatisplus.annotation.TableName; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -36,6 +37,12 @@ public class CouponActivity extends BasePromotions { @NotNull(message = "请选择活动范围") @ApiModelProperty(value = "活动范围", allowableValues = "ALL:全部会员,DESIGNATED:指定会员") private String activityScope; + /** + * @see CouponFrequencyEnum + */ + @NotNull(message = "领取周期") + @ApiModelProperty(value = "活动范围", allowableValues = " DAY:每天, WEEK:每周, MONTH:每月") + private String couponFrequencyEnum; @ApiModelProperty(value = "活动范围详情,只有精准发券使用") private String activityScopeInfo; diff --git a/framework/src/main/java/cn/lili/modules/promotion/entity/dos/MemberCouponSign.java b/framework/src/main/java/cn/lili/modules/promotion/entity/dos/MemberCouponSign.java new file mode 100644 index 000000000..0c7979f49 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/promotion/entity/dos/MemberCouponSign.java @@ -0,0 +1,50 @@ +package cn.lili.modules.promotion.entity.dos; + +import cn.lili.mybatis.BaseIdEntity; +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.elasticsearch.annotations.DateFormat; +import org.springframework.data.elasticsearch.annotations.Field; +import org.springframework.data.elasticsearch.annotations.FieldType; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +/** + * 会员优惠券实体类 + * + * @author Chopper + * @since 2020-03-19 10:44 上午 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@TableName("li_member_coupon_sign") +@ApiModel(value = "会员优惠券领取标记") +public class MemberCouponSign extends BaseIdEntity { + + @ApiModelProperty(value = "优惠券活动ID") + private String couponActivityId; + + @ApiModelProperty(value = "会员ID") + private String memberId; + + @ApiModelProperty(value = "失效时间,到达失效时间后自动删除,用户可以再次领取") + private Date invalidTime; + + + @CreatedDate + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @TableField(fill = FieldFill.INSERT) + @ApiModelProperty(value = "创建时间", hidden = true) + @Field(type = FieldType.Date, format = DateFormat.custom, pattern = "yyyy-MM-dd HH:mm:ss || yyyy-MM-dd || yyyy/MM/dd HH:mm:ss|| yyyy/MM/dd ||epoch_millis") + private Date createTime; + +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/promotion/entity/enums/CouponFrequencyEnum.java b/framework/src/main/java/cn/lili/modules/promotion/entity/enums/CouponFrequencyEnum.java new file mode 100644 index 000000000..f5db60073 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/promotion/entity/enums/CouponFrequencyEnum.java @@ -0,0 +1,35 @@ +package cn.lili.modules.promotion.entity.enums; + +/** + * 优惠券活动发送类型枚举 + * + * @author Bulbasaur + * @since 2021/5/20 5:47 下午 + */ +public enum CouponFrequencyEnum { + + /** + * 领取周期 + */ + DAY("每天"), WEEK("每周"), MONTH("每月"); + + private final String description; + + CouponFrequencyEnum(String str) { + this.description = str; + } + + public String description() { + return description; + } + + public static boolean exist(String name) { + try { + CouponFrequencyEnum.valueOf(name); + } catch (IllegalArgumentException e) { + return false; + } + return true; + } + +} diff --git a/framework/src/main/java/cn/lili/modules/promotion/mapper/MemberCouponSignMapper.java b/framework/src/main/java/cn/lili/modules/promotion/mapper/MemberCouponSignMapper.java new file mode 100644 index 000000000..ecb28ab96 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/promotion/mapper/MemberCouponSignMapper.java @@ -0,0 +1,17 @@ +package cn.lili.modules.promotion.mapper; + +import cn.lili.modules.promotion.entity.dos.MemberCouponSign; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * 会员优惠券领取标记 + * + * @author liushuai(liushuai711 @ gmail.com) + * @version v4.0 + * @Description: + * @since 2023/1/3 18:11 + */ +public interface MemberCouponSignMapper extends BaseMapper { + + +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/promotion/service/MemberCouponSignService.java b/framework/src/main/java/cn/lili/modules/promotion/service/MemberCouponSignService.java new file mode 100644 index 000000000..5e4c4fff7 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/promotion/service/MemberCouponSignService.java @@ -0,0 +1,33 @@ +package cn.lili.modules.promotion.service; + +import cn.lili.modules.promotion.entity.dos.MemberCouponSign; +import cn.lili.modules.promotion.entity.vos.CouponActivityVO; +import com.baomidou.mybatisplus.extension.service.IService; + +import java.util.List; + +/** + * 优惠券领取标记业务层 + * + * @author liushuai(liushuai711 @ gmail.com) + * @version v4.0 + * @Description: + * @since 2023/1/3 18:12 + */ + +public interface MemberCouponSignService extends IService { + + + /** + * 清除缓存 + * 清除失效标记 + */ + void clean(); + + + /** + * 清除缓存 + * 清除失效标记 + */ + List receiveCoupon(List couponActivity); +} \ No newline at end of file diff --git a/framework/src/main/java/cn/lili/modules/promotion/serviceimpl/CouponActivityServiceImpl.java b/framework/src/main/java/cn/lili/modules/promotion/serviceimpl/CouponActivityServiceImpl.java index 838b4e295..c818245a8 100644 --- a/framework/src/main/java/cn/lili/modules/promotion/serviceimpl/CouponActivityServiceImpl.java +++ b/framework/src/main/java/cn/lili/modules/promotion/serviceimpl/CouponActivityServiceImpl.java @@ -8,7 +8,6 @@ import cn.lili.common.enums.PromotionTypeEnum; import cn.lili.common.enums.ResultCode; import cn.lili.common.exception.ServiceException; import cn.lili.common.security.AuthUser; -import cn.lili.modules.member.entity.dos.Member; import cn.lili.modules.member.service.MemberService; import cn.lili.modules.promotion.entity.dos.Coupon; import cn.lili.modules.promotion.entity.dos.CouponActivity; @@ -20,10 +19,7 @@ import cn.lili.modules.promotion.entity.enums.*; import cn.lili.modules.promotion.entity.vos.CouponActivityItemVO; import cn.lili.modules.promotion.entity.vos.CouponActivityVO; import cn.lili.modules.promotion.mapper.CouponActivityMapper; -import cn.lili.modules.promotion.service.CouponActivityItemService; -import cn.lili.modules.promotion.service.CouponActivityService; -import cn.lili.modules.promotion.service.CouponService; -import cn.lili.modules.promotion.service.MemberCouponService; +import cn.lili.modules.promotion.service.*; import cn.lili.modules.promotion.tools.PromotionTools; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import groovy.util.logging.Slf4j; @@ -31,7 +27,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.*; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; import java.util.stream.Collectors; /** @@ -50,6 +49,11 @@ public class CouponActivityServiceImpl extends AbstractPromotionsServiceImpl couponActivities = currentCouponActivity(couponActivityTrigger.getCouponActivityTypeEnum().name()); + + /** + * 自动发送优惠券则需要补足日志 + */ + if (couponActivityTrigger.getCouponActivityTypeEnum().equals(CouponActivityTypeEnum.AUTO_COUPON)) { + couponActivities = memberCouponSignService.receiveCoupon(couponActivities); + } + //优惠券发放列表 List couponActivityItemVOS = new ArrayList<>(); @@ -191,6 +204,7 @@ public class CouponActivityServiceImpl extends AbstractPromotionsServiceImpl sendCoupon(AuthUser authUser, List couponActivityItems) { + + //最终优惠券列表 + List finalCoupons = new ArrayList<>(); + //循环优惠券赠送列表 for (CouponActivityItem couponActivityItem : couponActivityItems) { //获取优惠券 Coupon coupon = couponService.getById(couponActivityItem.getCouponId()); //判断优惠券是否存在 if (coupon != null) { - List memberCouponList = new LinkedList<>(); //循环优惠券的领取数量 int activitySendNum = couponActivityItem.getNum(); + List memberCouponList = new ArrayList<>(); for (int i = 1; i <= activitySendNum; i++) { MemberCoupon memberCoupon = new MemberCoupon(coupon); memberCoupon.setMemberId(authUser.getId()); @@ -325,6 +343,8 @@ public class CouponActivityServiceImpl extends AbstractPromotionsServiceImpl(); + if (finalCoupons.isEmpty()) { + return new ArrayList<>(); + } + return finalCoupons; } diff --git a/framework/src/main/java/cn/lili/modules/promotion/serviceimpl/MemberCouponSignServiceImpl.java b/framework/src/main/java/cn/lili/modules/promotion/serviceimpl/MemberCouponSignServiceImpl.java new file mode 100644 index 000000000..ce2bea9d3 --- /dev/null +++ b/framework/src/main/java/cn/lili/modules/promotion/serviceimpl/MemberCouponSignServiceImpl.java @@ -0,0 +1,124 @@ +package cn.lili.modules.promotion.serviceimpl; + +import cn.lili.cache.Cache; +import cn.lili.cache.CachePrefix; +import cn.lili.common.exception.ServiceException; +import cn.lili.common.security.context.UserContext; +import cn.lili.common.utils.DateUtil; +import cn.lili.modules.promotion.entity.dos.CouponActivity; +import cn.lili.modules.promotion.entity.dos.MemberCouponSign; +import cn.lili.modules.promotion.entity.enums.CouponFrequencyEnum; +import cn.lili.modules.promotion.entity.vos.CouponActivityVO; +import cn.lili.modules.promotion.mapper.MemberCouponSignMapper; +import cn.lili.modules.promotion.service.MemberCouponSignService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +/** + * 会员优惠券领取标记 + * + * @author liushuai(liushuai711 @ gmail.com) + * @version v4.0 + * @Description: + * @since 2023/1/3 18:13 + */ +@Service +public class MemberCouponSignServiceImpl extends ServiceImpl implements MemberCouponSignService { + + + @Autowired + private Cache cache; + + @Override + public void clean() { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.lt(MemberCouponSign::getInvalidTime, DateUtil.getCurrentDayStartTime()); + this.baseMapper.delete(queryWrapper); + cache.remove(CachePrefix.MEMBER_COUPON_SIGN.getPrefix()); + } + + @Override + public List receiveCoupon(List couponActivity) { + List memberCouponSigns = new ArrayList<>(); + + + //查询当前用户领取标记 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(MemberCouponSign::getMemberId, UserContext.getCurrentUser().getId()); + List oldMemberCouponSigns = this.list(queryWrapper); + + //定义生效的活动 + List assertCouponActivity = new ArrayList<>(); + + //生成标记对象 + couponActivityFor: + for (CouponActivityVO activity : couponActivity) { + //如果旧的标记中包含记号,则略过 + for (MemberCouponSign oldMemberCouponSign : oldMemberCouponSigns) { + if (oldMemberCouponSign.getCouponActivityId().equals(activity.getId())) { + continue couponActivityFor; + } + } + assertCouponActivity.add(activity); + + MemberCouponSign memberCouponSign = new MemberCouponSign(); + memberCouponSign.setMemberId(UserContext.getCurrentUser().getId()); + memberCouponSign.setCouponActivityId(activity.getId()); + memberCouponSign.setInvalidTime(getInvalidTime(activity)); + memberCouponSigns.add(memberCouponSign); + } + + this.saveBatch(memberCouponSigns); + return assertCouponActivity; + } + + /** + * 根据活动优惠券获取标记失效时间 + * + * @param activity + * @return + */ + private Date getInvalidTime(CouponActivity activity) { + + //领取周期符合预设 + if (CouponFrequencyEnum.exist(activity.getCouponFrequencyEnum())) { + + Calendar cal = DateUtil.getCleanCalendar(); + switch (CouponFrequencyEnum.valueOf(activity.getCouponFrequencyEnum())) { + case DAY: + return DateUtil.getCurrentDayEndTime(); + case WEEK: + //周一 + cal.set(Calendar.DAY_OF_WEEK, 2); + //去往下周 + cal.set(Calendar.WEEK_OF_YEAR, cal.get(Calendar.WEEK_OF_YEAR) + 1); + //减1毫秒上个星期最后一刻 + cal.set(Calendar.MILLISECOND, -1); + return cal.getTime(); + case MONTH: + //日期 1日 + cal.set(Calendar.DAY_OF_MONTH, 1); + //下个月 + cal.set(Calendar.MONTH, cal.get(Calendar.MONTH) + 1); + //减少一毫秒去上个月最后一刻 + cal.set(Calendar.MILLISECOND, -1); + + return cal.getTime(); + default: + + throw new ServiceException(); + } + } else { + throw new ServiceException(); + } + } + + +} \ No newline at end of file