| | |
| | | package com.mzl.flower.service.impl.coupon; |
| | | |
| | | import cn.hutool.core.util.IdUtil; |
| | | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | |
| | | import com.mzl.flower.mapper.customer.CustomerMapper; |
| | | import com.mzl.flower.service.coupon.CouponRecordService; |
| | | import com.mzl.flower.service.coupon.CouponTemplateService2; |
| | | import com.mzl.flower.service.customer.CustomerService; |
| | | import com.mzl.flower.service.system.UserService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.commons.collections4.CollectionUtils; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.redisson.api.RLock; |
| | | import org.redisson.api.RedissonClient; |
| | | import org.springframework.beans.BeanUtils; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | |
| | | import java.time.LocalDateTime; |
| | | import java.time.temporal.TemporalAdjusters; |
| | | import java.util.List; |
| | | import java.util.concurrent.TimeUnit; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | |
| | | @Autowired |
| | | private CustomerMapper customerMapper; |
| | | |
| | | @Autowired |
| | | private CustomerService customerService; |
| | | |
| | | |
| | | |
| | | @Override |
| | | public List<CouponRecordVO> getList(QueryCouponRecordDTO dto) { |
| | | return couponRecordMapperCustom.getList(dto); |
| | | } |
| | | |
| | | @Autowired |
| | | RedissonClient redissonClient; |
| | | |
| | | private static final String COUPON_KEY="com:mzl:flower:service:impl:coupon:%s"; |
| | | |
| | | @Transactional |
| | | @Override |
| | | public boolean createCouponRecord(CreateCouponRecordDTO dto) { |
| | | |
| | | // TODO 需要控制超领 |
| | | |
| | | final Customer customer = customerMapper.selectById(dto.getCustomerId()); |
| | | if(null==customer){ |
| | | throw new ValidationException("商户信息不存在"); |
| | | } |
| | | |
| | | final CouponTemplateDO couponTemplateDO = couponTemplateService.getById(dto.getCouponId()); |
| | | if(couponTemplateDO==null){ |
| | | throw new ValidationException("优惠券不存在"); |
| | | } |
| | | |
| | | // 活动优惠券和积分优惠券需要根据库存来控制- 根据优惠券的发放数量来控制有没有超发 |
| | | if(StringUtils.isNotBlank(couponTemplateDO.getCategory()) && ( |
| | | couponTemplateDO.getCategory().equals(CouponCategoryEnum.ACTIVITY.getStatus()) || couponTemplateDO.getCategory().equals(CouponCategoryEnum.POINT.getStatus()) |
| | | )){ |
| | | // 获取当前优惠券已经领取的数量 |
| | | final Integer gainTotal = getExistGainCouponRecordAmountById(couponTemplateDO.getId()); |
| | | if(couponTemplateDO.getCouponAmount().compareTo(gainTotal)<=0){ |
| | | throw new ValidationException("当前优惠券已经领完!"); |
| | | } |
| | | final Customer customer = customerMapper.selectById(dto.getCustomerId()); |
| | | if(null==customer){ |
| | | throw new ValidationException("商户信息不存在"); |
| | | } |
| | | |
| | | // 根据用户领取设置的getLimit 查看当前用户是否已经超领优惠券 |
| | | if(StringUtils.isNotBlank(couponTemplateDO.getCategory()) && couponTemplateDO.getCategory().equals(CouponCategoryEnum.ACTIVITY.getStatus()) ){ |
| | | // 查看当前优惠券的领取时间在不在设置的领取时间范围类 |
| | | LocalDateTime now = LocalDateTime.now(); |
| | | // 判断当前时间是否在领取时间范围内 |
| | | if (!(now.isAfter(couponTemplateDO.getGetStartDate()) && now.isBefore(couponTemplateDO.getGetEndDate()))) { |
| | | throw new ValidationException("当前时间不在优惠券的领取时间范围内,无法操作!"); |
| | | } |
| | | RLock lock = redissonClient.getLock(String.format(COUPON_KEY, couponTemplateDO.getId())); |
| | | try { |
| | | // 获取锁,最多等待 10 秒,锁自动释放时间 30 秒 |
| | | if (lock.tryLock(10, 30, TimeUnit.SECONDS)) { |
| | | try { |
| | | // 活动优惠券和积分优惠券需要根据库存来控制- 根据优惠券的发放数量来控制有没有超发 |
| | | if(StringUtils.isNotBlank(couponTemplateDO.getCategory()) && ( |
| | | couponTemplateDO.getCategory().equals(CouponCategoryEnum.ACTIVITY.getStatus()) || couponTemplateDO.getCategory().equals(CouponCategoryEnum.POINT.getStatus()) |
| | | )){ |
| | | // 获取当前优惠券已经领取的数量 |
| | | final Integer gainTotal = getExistGainCouponRecordAmountById(couponTemplateDO.getId()); |
| | | if(couponTemplateDO.getCouponAmount().compareTo(gainTotal)<=0){ |
| | | throw new ValidationException("当前优惠券已经领完!"); |
| | | } |
| | | } |
| | | |
| | | // 获取当前优惠券已经领取的数量 |
| | | final Integer customGainTotal = getUserGainCouponRecordAmountById(couponTemplateDO.getId(),customer.getId()); |
| | | if(couponTemplateDO.getGetLimit().compareTo(customGainTotal)<=0){ |
| | | throw new ValidationException("超出个人领取限制,每人限领"+couponTemplateDO.getGetLimit()+"张!"); |
| | | // 根据用户领取设置的getLimit 查看当前用户是否已经超领优惠券 |
| | | if(StringUtils.isNotBlank(couponTemplateDO.getCategory()) && couponTemplateDO.getCategory().equals(CouponCategoryEnum.ACTIVITY.getStatus()) ){ |
| | | // 查看当前优惠券的领取时间在不在设置的领取时间范围类 |
| | | LocalDateTime now = LocalDateTime.now(); |
| | | // 判断当前时间是否在领取时间范围内 |
| | | if (!(now.isAfter(couponTemplateDO.getGetStartDate()) && now.isBefore(couponTemplateDO.getGetEndDate()))) { |
| | | throw new ValidationException("当前时间不在优惠券的领取时间范围内,无法操作!"); |
| | | } |
| | | |
| | | // 获取当前优惠券已经领取的数量 |
| | | final Integer customGainTotal = getUserGainCouponRecordAmountById(couponTemplateDO.getId(),customer.getId()); |
| | | if(couponTemplateDO.getGetLimit().compareTo(customGainTotal)<=0){ |
| | | throw new ValidationException("超出个人领取限制,每人限领"+couponTemplateDO.getGetLimit()+"张!"); |
| | | } |
| | | } |
| | | |
| | | |
| | | CouponRecordDO couponRecordDO=new CouponRecordDO(); |
| | | BeanUtils.copyProperties(dto,couponRecordDO); |
| | | couponRecordDO.create(SecurityUtils.getUserId()); |
| | | // 设置为待使用状态 |
| | | couponRecordDO.setStatus(CouponUsedStatusEnum.UNUSED.getType()); |
| | | |
| | | // 根据商户设置用户id |
| | | if(StringUtils.isBlank(dto.getUserId()) && StringUtils.isNotBlank(customer.getUserId())){ |
| | | couponRecordDO.setUserId(customer.getUserId()); |
| | | } |
| | | |
| | | // 优惠券字段冗余 |
| | | couponRecordDO.setCategory(couponTemplateDO.getGetUserType()); |
| | | couponRecordDO.setCouponCode(couponTemplateDO.getCouponCode()); |
| | | couponRecordDO.setCouponName(couponTemplateDO.getCouponName()); |
| | | couponRecordDO.setCouponDiscountValue(couponTemplateDO.getCouponDiscountValue()); |
| | | couponRecordDO.setMinOrderAmount(couponTemplateDO.getMinOrderAmount()); |
| | | couponRecordDO.setGetType(couponTemplateDO.getGetType()); |
| | | couponRecordDO.setCouponDiscountType(couponTemplateDO.getCouponDiscountType()); |
| | | couponRecordDO.setGetUserType(couponTemplateDO.getGetUserType()); |
| | | couponRecordDO.setPoint(couponTemplateDO.getPoint()); |
| | | couponRecordDO.setMemberId(couponRecordDO.getMemberId()); |
| | | |
| | | |
| | | // 根据优惠券模板来计算优惠券的生效开始时间和结束时间 |
| | | if(StringUtils.isNotBlank(couponTemplateDO.getCategory()) && couponTemplateDO.getCategory().equals(CouponCategoryEnum.MEMBER.getStatus())){ |
| | | // 如果是会员优惠券的话,则设置为优惠券的使用条件为优惠券的时间 |
| | | couponRecordDO.setEffectiveStart(couponTemplateDO.getUsageStartDate()); |
| | | couponRecordDO.setEffectiveEnd(couponTemplateDO.getUsageEndDate()); |
| | | }else{ |
| | | // 非会员的根据领取时间类型来计算优惠券的时间 |
| | | if(StringUtils.isNotBlank(couponTemplateDO.getUsageType()) && couponTemplateDO.getUsageType().equals(CouponUsageTypeEnum.GET.getType())){ |
| | | // 与领取时间一致 |
| | | couponRecordDO.setEffectiveStart(couponTemplateDO.getGetStartDate()); |
| | | couponRecordDO.setEffectiveEnd(couponTemplateDO.getGetEndDate()); |
| | | } |
| | | if(StringUtils.isNotBlank(couponTemplateDO.getUsageType()) && couponTemplateDO.getUsageType().equals(CouponUsageTypeEnum.FIXED.getType())){ |
| | | // 固定时间 |
| | | couponRecordDO.setEffectiveStart(couponTemplateDO.getUsageStartDate()); |
| | | couponRecordDO.setEffectiveEnd(couponTemplateDO.getUsageEndDate()); |
| | | } |
| | | if(StringUtils.isNotBlank(couponTemplateDO.getUsageType()) && couponTemplateDO.getUsageType().equals(CouponUsageTypeEnum.GET_AFTER_TIME.getType())){ |
| | | // 领取后有段时间 领取后有效时间 |
| | | // 根据发放后有效期来设置时间 |
| | | if (couponTemplateDO.getUsageTimeNum() == null || couponTemplateDO.getUsageTimeNum() <= 0) { |
| | | throw new IllegalArgumentException("使用时间数量必须为正整数"); |
| | | } |
| | | LocalDateTime currentTime = LocalDateTime.now(); |
| | | couponRecordDO.setEffectiveStart(currentTime); |
| | | if (couponTemplateDO.getUsageTimeType().equals(CouponUsageTimeTypeEnum.DAY.getType())) { |
| | | // 天 |
| | | couponRecordDO.setEffectiveEnd(currentTime.plusDays(couponTemplateDO.getUsageTimeNum())); |
| | | } |
| | | if (couponTemplateDO.getUsageTimeType().equals(CouponUsageTimeTypeEnum.HOUR.getType())) { |
| | | // 小时 |
| | | couponRecordDO.setEffectiveEnd(currentTime.plusHours(couponTemplateDO.getUsageTimeNum())); |
| | | } |
| | | if (couponTemplateDO.getUsageTimeType().equals(CouponUsageTimeTypeEnum.MINUTE.getType())) { |
| | | // 分钟 |
| | | couponRecordDO.setEffectiveEnd(currentTime.plusMinutes(couponTemplateDO.getUsageTimeNum())); |
| | | } |
| | | |
| | | } |
| | | } |
| | | |
| | | return baseMapper.insert(couponRecordDO)>0; |
| | | |
| | | } finally { |
| | | lock.unlock(); |
| | | } |
| | | } |
| | | } catch (InterruptedException e) { |
| | | Thread.currentThread().interrupt(); |
| | | // 处理异常 |
| | | } |
| | | |
| | | return false; |
| | | |
| | | CouponRecordDO couponRecordDO=new CouponRecordDO(); |
| | | BeanUtils.copyProperties(dto,couponRecordDO); |
| | | couponRecordDO.create(SecurityUtils.getUserId()); |
| | | // 设置为待使用状态 |
| | | couponRecordDO.setStatus(CouponUsedStatusEnum.UNUSED.getType()); |
| | | |
| | | // 根据商户设置用户id |
| | | if(StringUtils.isBlank(dto.getUserId()) && StringUtils.isNotBlank(customer.getUserId())){ |
| | | couponRecordDO.setUserId(customer.getUserId()); |
| | | } |
| | | |
| | | // 优惠券字段冗余 |
| | | couponRecordDO.setCategory(couponTemplateDO.getGetUserType()); |
| | | couponRecordDO.setCouponCode(couponTemplateDO.getCouponCode()); |
| | | couponRecordDO.setCouponName(couponTemplateDO.getCouponName()); |
| | | couponRecordDO.setCouponDiscountValue(couponTemplateDO.getCouponDiscountValue()); |
| | | couponRecordDO.setMinOrderAmount(couponTemplateDO.getMinOrderAmount()); |
| | | couponRecordDO.setGetType(couponTemplateDO.getGetType()); |
| | | couponRecordDO.setCouponDiscountType(couponTemplateDO.getCouponDiscountType()); |
| | | couponRecordDO.setGetUserType(couponTemplateDO.getGetUserType()); |
| | | couponRecordDO.setPoint(couponTemplateDO.getPoint()); |
| | | couponRecordDO.setMemberId(couponRecordDO.getMemberId()); |
| | | |
| | | |
| | | // 根据优惠券模板来计算优惠券的生效开始时间和结束时间 |
| | | if(StringUtils.isNotBlank(couponTemplateDO.getCategory()) && couponTemplateDO.getCategory().equals(CouponCategoryEnum.MEMBER.getStatus())){ |
| | | // 如果是会员优惠券的话,则设置为优惠券的使用条件为优惠券的时间 |
| | | couponRecordDO.setEffectiveStart(couponTemplateDO.getUsageStartDate()); |
| | | couponRecordDO.setEffectiveEnd(couponTemplateDO.getUsageEndDate()); |
| | | }else{ |
| | | // 非会员的根据领取时间类型来计算优惠券的时间 |
| | | if(StringUtils.isNotBlank(couponTemplateDO.getUsageType()) && couponTemplateDO.getUsageType().equals(CouponUsageTypeEnum.GET.getType())){ |
| | | // 与领取时间一致 |
| | | couponRecordDO.setEffectiveStart(couponTemplateDO.getGetStartDate()); |
| | | couponRecordDO.setEffectiveEnd(couponTemplateDO.getGetEndDate()); |
| | | } |
| | | if(StringUtils.isNotBlank(couponTemplateDO.getUsageType()) && couponTemplateDO.getUsageType().equals(CouponUsageTypeEnum.FIXED.getType())){ |
| | | // 固定时间 |
| | | couponRecordDO.setEffectiveStart(couponTemplateDO.getUsageStartDate()); |
| | | couponRecordDO.setEffectiveEnd(couponTemplateDO.getUsageEndDate()); |
| | | } |
| | | if(StringUtils.isNotBlank(couponTemplateDO.getUsageType()) && couponTemplateDO.getUsageType().equals(CouponUsageTypeEnum.GET_AFTER_TIME.getType())){ |
| | | // 领取后有段时间 领取后有效时间 |
| | | // 根据发放后有效期来设置时间 |
| | | if (couponTemplateDO.getUsageTimeNum() == null || couponTemplateDO.getUsageTimeNum() <= 0) { |
| | | throw new IllegalArgumentException("使用时间数量必须为正整数"); |
| | | } |
| | | LocalDateTime currentTime = LocalDateTime.now(); |
| | | couponRecordDO.setEffectiveStart(currentTime); |
| | | if (couponTemplateDO.getUsageTimeType().equals(CouponUsageTimeTypeEnum.DAY.getType())) { |
| | | // 天 |
| | | couponRecordDO.setEffectiveEnd(currentTime.plusDays(couponTemplateDO.getUsageTimeNum())); |
| | | } |
| | | if (couponTemplateDO.getUsageTimeType().equals(CouponUsageTimeTypeEnum.HOUR.getType())) { |
| | | // 小时 |
| | | couponRecordDO.setEffectiveEnd(currentTime.plusHours(couponTemplateDO.getUsageTimeNum())); |
| | | } |
| | | if (couponTemplateDO.getUsageTimeType().equals(CouponUsageTimeTypeEnum.MINUTE.getType())) { |
| | | // 分钟 |
| | | couponRecordDO.setEffectiveEnd(currentTime.plusMinutes(couponTemplateDO.getUsageTimeNum())); |
| | | } |
| | | |
| | | } |
| | | } |
| | | |
| | | return baseMapper.insert(couponRecordDO)>0; |
| | | } |
| | | |
| | | @Override |
| | |
| | | @Override |
| | | public boolean grantVipCouponRecordList() { |
| | | |
| | | // TODO 会员等级修改 |
| | | // try{ |
| | | // LocalDateTime now = LocalDateTime.now(); |
| | | // LocalDateTime firstDayStart = now.with(TemporalAdjusters.firstDayOfMonth()).withHour(0).withMinute(0).withSecond(0).withNano(0); |
| | | // LocalDateTime lastDayEnd = now.with(TemporalAdjusters.lastDayOfMonth()).withHour(23).withMinute(59).withSecond(59).withNano(0); |
| | | // |
| | | // // 获取所有会员模版列表 |
| | | // List<CouponTemplateDO> vipTemplateList= couponTemplateService.getVipCouponTemplate(); |
| | | // |
| | | // // 遍历所有相同等级用户信息,并根据优惠券设置的规则构造优惠券 |
| | | // final List<CouponTemplateDO> updateCouponTemplateList = vipTemplateList.stream().map(couponTemplateDO -> { |
| | | // final List<User> vipGradeUserList = userService.getVipGradeUserList(couponTemplateDO.getVipGrade()); |
| | | // final List<CouponRecordDO> gradeCouponRecordList = vipGradeUserList.stream().map(user -> { |
| | | // CouponRecordDO couponRecordDO = new CouponRecordDO(); |
| | | // BeanUtils.copyProperties(couponTemplateDO, couponRecordDO); |
| | | // couponRecordDO.setId(IdUtil.simpleUUID()); |
| | | // couponRecordDO.setCouponId(couponTemplateDO.getId()); |
| | | // couponRecordDO.setUserId(user.getId()); |
| | | // couponRecordDO.setStatus(CouponUsedStatusEnum.UNUSED.getType()); |
| | | // couponRecordDO.setEffectiveStart(firstDayStart); |
| | | // couponRecordDO.setEffectiveEnd(lastDayEnd); |
| | | // |
| | | // // 创建信息 |
| | | // couponRecordDO.create(); |
| | | // return couponRecordDO; |
| | | // }).collect(Collectors.toList()); |
| | | // |
| | | // // 批量保存等级下的优惠券信息 |
| | | // saveBatch(gradeCouponRecordList); |
| | | // |
| | | // couponTemplateDO.setUsageStartDate(firstDayStart); |
| | | // couponTemplateDO.setUsageEndDate(lastDayEnd); |
| | | // couponTemplateDO.setGetStartDate(firstDayStart); |
| | | // couponTemplateDO.setGetEndDate(lastDayEnd); |
| | | // |
| | | // // 设置默认类型固定 |
| | | // couponTemplateDO.setUsageType(CouponUsageTypeEnum.FIXED.getType()); |
| | | // |
| | | // return couponTemplateDO; |
| | | // |
| | | // }).collect(Collectors.toList()); |
| | | // |
| | | // // 批量更新原模版时间 |
| | | // couponTemplateService.updateBatchById(updateCouponTemplateList); |
| | | // |
| | | // return true; |
| | | // }catch (Exception e){ |
| | | // // 报错日志信息报错 |
| | | // log.error(e.getMessage()); |
| | | // return false; |
| | | // } |
| | | return false; |
| | | try{ |
| | | LocalDateTime now = LocalDateTime.now(); |
| | | LocalDateTime firstDayStart = now.with(TemporalAdjusters.firstDayOfMonth()).withHour(0).withMinute(0).withSecond(0).withNano(0); |
| | | LocalDateTime lastDayEnd = now.with(TemporalAdjusters.lastDayOfMonth()).withHour(23).withMinute(59).withSecond(59).withNano(0); |
| | | |
| | | // 获取所有会员模版列表 |
| | | List<CouponTemplateDO> vipTemplateList= couponTemplateService.getVipCouponTemplate(); |
| | | |
| | | // 遍历所有相同等级用户信息,并根据优惠券设置的规则构造优惠券 |
| | | final List<CouponTemplateDO> updateCouponTemplateList = vipTemplateList.stream().map(couponTemplateDO -> { |
| | | // 获取当前等级下的所有用户 |
| | | final List<Customer> customerList = customerService.getCustomerListByLevelId(couponTemplateDO.getMemberId()); |
| | | |
| | | final List<CouponRecordDO> gradeCouponRecordList = customerList.stream().map(customer -> { |
| | | CouponRecordDO couponRecordDO = new CouponRecordDO(); |
| | | BeanUtils.copyProperties(couponTemplateDO, couponRecordDO); |
| | | couponRecordDO.setId(IdUtil.simpleUUID()); |
| | | couponRecordDO.setCouponId(couponTemplateDO.getId()); |
| | | couponRecordDO.setUserId(customer.getUserId()); |
| | | couponRecordDO.setCustomerId(customer.getId()); |
| | | couponRecordDO.setStatus(CouponUsedStatusEnum.UNUSED.getType()); |
| | | couponRecordDO.setEffectiveStart(firstDayStart); |
| | | couponRecordDO.setEffectiveEnd(lastDayEnd); |
| | | couponRecordDO.setMemberId(couponTemplateDO.getMemberId()); |
| | | |
| | | // 创建信息 |
| | | couponRecordDO.create(); |
| | | return couponRecordDO; |
| | | }).collect(Collectors.toList()); |
| | | |
| | | // 批量保存等级下的优惠券信息 |
| | | saveBatch(gradeCouponRecordList); |
| | | |
| | | couponTemplateDO.setUsageStartDate(firstDayStart); |
| | | couponTemplateDO.setUsageEndDate(lastDayEnd); |
| | | couponTemplateDO.setGetStartDate(firstDayStart); |
| | | couponTemplateDO.setGetEndDate(lastDayEnd); |
| | | |
| | | // 设置默认类型固定 |
| | | couponTemplateDO.setUsageType(CouponUsageTypeEnum.FIXED.getType()); |
| | | |
| | | return couponTemplateDO; |
| | | |
| | | }).collect(Collectors.toList()); |
| | | |
| | | // 批量更新原模版时间 |
| | | couponTemplateService.updateBatchById(updateCouponTemplateList); |
| | | |
| | | return true; |
| | | }catch (Exception e){ |
| | | // 报错日志信息报错 |
| | | log.error(e.getMessage()); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | |
| | | @Override |
| | | public List<CouponRecordVO> getMineCouponRecordList(QueryMineCouponRecordDTO dto) { |
| | | checkCouponExpired(dto); |
| | | return couponRecordMapperCustom.getMineCouponRecordList(dto); |
| | | } |
| | | |
| | | @Override |
| | | public void checkCouponExpired(QueryMineCouponRecordDTO dto) { |
| | | if(StringUtils.isBlank(dto.getUserId())){ |
| | | dto.setUserId(SecurityUtils.getUserId()); |
| | | } |
| | | // 将未使用的优惠券直接过期 |
| | | couponRecordMapperCustom.checkCouponExpired(dto); |
| | | } |
| | | } |