package cn.lili.modules.promotion.serviceimpl; import cn.hutool.core.text.CharSequenceUtil; import cn.lili.cache.Cache; import cn.lili.common.enums.ResultCode; import cn.lili.common.exception.ServiceException; import cn.lili.common.security.AuthUser; import cn.lili.common.security.context.UserContext; import cn.lili.common.vo.PageVO; import cn.lili.modules.promotion.entity.dos.Coupon; import cn.lili.modules.promotion.entity.dos.MemberCoupon; import cn.lili.modules.promotion.entity.dto.search.MemberCouponSearchParams; import cn.lili.modules.promotion.entity.enums.CouponGetEnum; import cn.lili.modules.promotion.entity.enums.MemberCouponStatusEnum; import cn.lili.modules.promotion.entity.enums.PromotionsScopeTypeEnum; import cn.lili.modules.promotion.entity.enums.PromotionsStatusEnum; import cn.lili.modules.promotion.entity.vos.MemberCouponVO; import cn.lili.modules.promotion.mapper.MemberCouponMapper; import cn.lili.modules.promotion.service.CouponService; import cn.lili.modules.promotion.service.MemberCouponService; import cn.lili.modules.promotion.tools.PromotionTools; import cn.lili.mybatis.util.PageUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.*; /** * 会员优惠券业务层实现 * * @author Chopper * @since 2020/8/21 */ @Service @CacheConfig(cacheNames = "{MemberCoupon}") public class MemberCouponServiceImpl extends ServiceImpl implements MemberCouponService { /** * 优惠券 */ @Autowired private CouponService couponService; /** * 缓存 */ @Autowired private Cache cache; @Override public void checkCouponLimit(String couponId, String memberId) { Coupon coupon = couponService.getById(couponId); LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper() .eq(MemberCoupon::getCouponId, couponId) .eq(MemberCoupon::getMemberId, memberId); long haveCoupons = this.count(queryWrapper); if (!PromotionsStatusEnum.START.name().equals(coupon.getPromotionStatus())) { throw new ServiceException(ResultCode.COUPON_RECEIVE_ERROR); } if (coupon.getPublishNum() != 0 && coupon.getReceivedNum() >= coupon.getPublishNum()) { throw new ServiceException(ResultCode.COUPON_NUM_INSUFFICIENT_ERROR); } if (!coupon.getCouponLimitNum().equals(0) && haveCoupons >= coupon.getCouponLimitNum()) { throw new ServiceException(ResultCode.COUPON_LIMIT_ERROR, "此优惠券最多领取" + coupon.getCouponLimitNum() + "张"); } } /** * 领取优惠券 * * @param couponId 优惠券编号 * @param memberId 会员 * @param memberName 会员名称 */ @Override @CacheEvict(key = "#memberId") @Transactional(rollbackFor = Exception.class) public void receiveBuyerCoupon(String couponId, String memberId, String memberName) { Coupon coupon = couponService.getById(couponId); if (coupon != null && !CouponGetEnum.FREE.name().equals(coupon.getGetType())) { throw new ServiceException(ResultCode.COUPON_DO_NOT_RECEIVER); } else if (coupon != null) { this.receiverCoupon(couponId, memberId, memberName, coupon); } } @Override @CacheEvict(key = "#memberId") @Transactional(rollbackFor = Exception.class) public void receiveCoupon(String couponId, String memberId, String memberName) { Coupon coupon = couponService.getById(couponId); if (coupon != null) { this.receiverCoupon(couponId, memberId, memberName, coupon); } else { throw new ServiceException(ResultCode.COUPON_NOT_EXIST); } } @Override public IPage getMemberCoupons(MemberCouponSearchParams param, PageVO pageVo) { QueryWrapper queryWrapper = param.queryWrapper(); Page page = this.page(PageUtil.initPage(pageVo), queryWrapper); if (page.getRecords() != null && page.getRecords().size() > 0) { if (page.getRecords().stream().anyMatch(i -> i.getEndTime().before(new Date()))) { this.expireInvalidMemberCoupon(param.getMemberId()); return this.page(PageUtil.initPage(pageVo), queryWrapper); } } return page; } /** * 获取会员优惠券列表 * * @param param 查询参数 * @return 会员优惠券列表 */ @Override public List getMemberCoupons(MemberCouponSearchParams param) { List list = this.list(param.queryWrapper()); if (list.stream().anyMatch(i -> i.getEndTime().before(new Date()))) { this.expireInvalidMemberCoupon(param.getMemberId()); return this.list(param.queryWrapper()); } return list; } /** * 获取当前用户的优惠券列表(优先读取缓存) * * @param memberId 会员id * @return 会员优惠券列表 */ @Override @Cacheable(key = "#memberId") public List getMemberCoupons(String memberId) { MemberCouponSearchParams searchParams = new MemberCouponSearchParams(); searchParams.setMemberId(Objects.requireNonNull(UserContext.getCurrentUser()).getId()); searchParams.setMemberCouponStatus(MemberCouponStatusEnum.NEW.name()); searchParams.setPromotionStatus(PromotionsStatusEnum.START.name()); return this.getMemberCoupons(searchParams); } /** * 获取会员优惠券列表 * * @param param 查询参数 * @param pageVo 分页参数 * @return 会员优惠券列表 */ @Override public IPage getMemberCouponsByCanUse(MemberCouponSearchParams param, Double totalPrice, PageVO pageVo) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); List storeIds = new ArrayList<>(Arrays.asList(param.getStoreId().split(","))); storeIds.add(PromotionTools.PLATFORM_ID); queryWrapper.in(MemberCoupon::getStoreId, storeIds); queryWrapper.eq(MemberCoupon::getMemberId, param.getMemberId()); queryWrapper.and( i -> i.like(MemberCoupon::getScopeId, param.getScopeId()) .or(j -> j.eq(MemberCoupon::getScopeType, PromotionsScopeTypeEnum.ALL.name()))); queryWrapper.eq(MemberCoupon::getMemberCouponStatus, MemberCouponStatusEnum.NEW.name()); queryWrapper.le(MemberCoupon::getConsumeThreshold, totalPrice); queryWrapper.ge(MemberCoupon::getEndTime, new Date()); return this.page(PageUtil.initPage(pageVo), queryWrapper); } /** * 获取当前会员当前商品可用的会员优惠券 * * @param memberId 会员Id * @param couponIds 优惠券id列表 * @return 会员优惠券列表 */ @Override public List getCurrentGoodsCanUse(String memberId, List couponIds, Double totalPrice) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(MemberCoupon::getMemberId, memberId); queryWrapper.eq(MemberCoupon::getMemberCouponStatus, MemberCouponStatusEnum.NEW.name()); queryWrapper.in(MemberCoupon::getCouponId, couponIds); queryWrapper.ne(MemberCoupon::getScopeType, PromotionsScopeTypeEnum.ALL.name()); queryWrapper.le(MemberCoupon::getConsumeThreshold, totalPrice); queryWrapper.ge(MemberCoupon::getEndTime, new Date()); return this.list(queryWrapper); } /** * 获取当前会员全品类优惠券 * * @param memberId 会员Id * @param storeId 店铺id * @return 会员优惠券列表 */ @Override public List getAllScopeMemberCoupon(String memberId, List storeId) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(MemberCoupon::getMemberId, memberId); queryWrapper.eq(MemberCoupon::getMemberCouponStatus, MemberCouponStatusEnum.NEW.name()); queryWrapper.eq(MemberCoupon::getScopeType, PromotionsScopeTypeEnum.ALL.name()); queryWrapper.ge(MemberCoupon::getEndTime, new Date()).and(i -> i.in(MemberCoupon::getStoreId, storeId).or(j -> j.eq(MemberCoupon::getPlatformFlag, true))); return this.list(queryWrapper); } /** * 获取当前会员全品类优惠券 * * @param param 查询参数 * @return 会员优惠券列表 */ @Override public MemberCoupon getMemberCoupon(MemberCouponSearchParams param) { return this.getOne(param.queryWrapper(), false); } @Override public long getMemberCouponsNum() { AuthUser authUser = Objects.requireNonNull(UserContext.getCurrentUser()); QueryWrapper queryWrapper = Wrappers.query(); queryWrapper.eq("member_id", authUser.getId()); queryWrapper.eq("member_coupon_status", MemberCouponStatusEnum.NEW.name()); queryWrapper.eq("delete_flag", false); return this.count(queryWrapper); } @Override @CacheEvict(key = "#memberId") @Transactional(rollbackFor = Exception.class) public void used(String memberId, List ids) { if (ids != null && !ids.isEmpty()) { List memberCoupons = this.listByIds(ids); //如果查出来的优惠券数量不一致 if (memberCoupons.size() != ids.size()) { throw new ServiceException(ResultCode.COUPON_EXPIRED); } //循环处理 memberCoupons.forEach(item -> { if (!item.getMemberCouponStatus().equals(MemberCouponStatusEnum.NEW.name())) { throw new ServiceException(ResultCode.COUPON_EXPIRED); } item.setMemberCouponStatus(MemberCouponStatusEnum.USED.name()); item.setConsumptionTime(new Date()); }); this.updateBatchById(memberCoupons); } } /** * 作废当前会员优惠券 * * @param id id */ @Override @CacheEvict(key = "#memberId") @Transactional(rollbackFor = Exception.class) public void cancellation(String memberId, String id) { LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); updateWrapper.eq(MemberCoupon::getId, id); updateWrapper.set(MemberCoupon::getMemberCouponStatus, MemberCouponStatusEnum.CLOSED.name()); this.update(updateWrapper); } /** * 关闭会员优惠券 * * @param couponIds 优惠券id集合 */ @Override @Transactional(rollbackFor = Exception.class) public void closeMemberCoupon(List couponIds) { LambdaUpdateWrapper memberCouponLambdaUpdateWrapper = new LambdaUpdateWrapper() .in(MemberCoupon::getCouponId, couponIds) .set(MemberCoupon::getMemberCouponStatus, MemberCouponStatusEnum.CLOSED.name()); this.cache.vagueDel("{MemberCoupon}"); this.update(memberCouponLambdaUpdateWrapper); } @Override public boolean recoveryMemberCoupon(List memberCouponIds) { LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); updateWrapper.in(MemberCoupon::getId, memberCouponIds); updateWrapper.set(MemberCoupon::getMemberCouponStatus, MemberCouponStatusEnum.NEW.name()); updateWrapper.set(MemberCoupon::getConsumptionTime, null); return this.update(updateWrapper); } @Override public void voidCoupon(String couponId) { LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); updateWrapper.in(MemberCoupon::getCouponId, couponId); updateWrapper.set(MemberCoupon::getMemberCouponStatus, MemberCouponStatusEnum.CLOSED.name()); updateWrapper.set(MemberCoupon::getDeleteFlag, true); this.update(updateWrapper); } @Override public Page getMemberCouponsPage(Page page, MemberCouponSearchParams param) { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq(CharSequenceUtil.isNotEmpty(param.getMemberId()), "mc.member_id", param.getMemberId()); queryWrapper.eq(CharSequenceUtil.isNotEmpty(param.getStoreId()), "c.store_id", param.getStoreId()); queryWrapper.like(CharSequenceUtil.isNotEmpty(param.getMemberName()), "mc.member_name", param.getMemberName()); queryWrapper.eq(CharSequenceUtil.isNotEmpty(param.getCouponId()), "mc.coupon_id", param.getCouponId()); queryWrapper.like(CharSequenceUtil.isNotEmpty(param.getCouponName()), "c.coupon_name", param.getCouponName()); queryWrapper.eq(CharSequenceUtil.isNotEmpty(param.getGetType()), "mc.get_type", param.getGetType()); queryWrapper.eq(CharSequenceUtil.isNotEmpty(param.getScopeType()), "mc.scope_type", param.getPromotionStatus()); queryWrapper.eq(CharSequenceUtil.isNotEmpty(param.getCouponType()), "mc.coupon_type", param.getCouponType()); queryWrapper.eq(CharSequenceUtil.isNotEmpty(param.getMemberCouponStatus()), "mc.member_coupon_status", param.getMemberCouponStatus()); if (param.getStartTime() != null) { queryWrapper.ge("mc.start_time", new Date(param.getStartTime())); } if (param.getEndTime() != null) { queryWrapper.le("mc.end_time", new Date(param.getEndTime())); } return this.baseMapper.getMemberCoupons(page, queryWrapper); } @Override public long getMemberCouponNum(String memberId, String couponId) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(MemberCoupon::getMemberId, memberId); queryWrapper.eq(MemberCoupon::getCouponId, couponId); return this.count(queryWrapper); } /** * 清除无效的会员优惠券 * * @return 是否操作成功 */ @Override @CacheEvict(key = "#memberId") public boolean expireInvalidMemberCoupon(String memberId) { //将过期优惠券变更为过期状体 LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper() .eq(CharSequenceUtil.isNotEmpty(memberId), MemberCoupon::getMemberId, memberId) .eq(MemberCoupon::getMemberCouponStatus, MemberCouponStatusEnum.NEW.name()) .le(MemberCoupon::getEndTime, new Date()) .set(MemberCoupon::getMemberCouponStatus, MemberCouponStatusEnum.EXPIRE.name()); return this.update(updateWrapper); } private void receiverCoupon(String couponId, String memberId, String memberName, Coupon coupon) { this.checkCouponLimit(couponId, memberId); MemberCoupon memberCoupon = new MemberCoupon(coupon); memberCoupon.setMemberId(memberId); memberCoupon.setMemberName(memberName); memberCoupon.setMemberCouponStatus(MemberCouponStatusEnum.NEW.name()); memberCoupon.setPlatformFlag((PromotionTools.PLATFORM_ID).equals(coupon.getStoreId())); this.save(memberCoupon); couponService.receiveCoupon(couponId, 1); } }