package com.kym.service.miniapp.impl;
import cn.dev33.satoken.stp.StpUtil;
import com.github.pagehelper.PageHelper;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.kym.common.exception.BusinessException;
import com.kym.common.utils.CommUtil;
import com.kym.entity.admin.Coupon;
import com.kym.entity.admin.queryParams.CouponQueryParam;
import com.kym.entity.common.PageBean;
import com.kym.entity.common.RedisKeys;
import com.kym.entity.miniapp.OrderCoupon;
import com.kym.entity.miniapp.User;
import com.kym.entity.miniapp.UserCoupon;
import com.kym.entity.miniapp.vo.UserCouponVo;
import com.kym.entity.miniapp.vo.UserOrderCouponVo;
import com.kym.mapper.miniapp.UserCouponMapper;
import com.kym.service.admin.ActivityService;
import com.kym.service.admin.CouponService;
import com.kym.service.miniapp.UserCouponService;
import com.kym.service.miniapp.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
*
* 用户优惠券关联表 服务实现类
*
*
* @author skyline
* @since 2024-04-29
*/
@Service
public class UserCouponServiceImpl extends MPJBaseServiceImpl implements UserCouponService {
private final RedisTemplate redisTemplate;
private final ActivityService activityService;
private final UserService userService;
private final CouponService couponService;
public UserCouponServiceImpl(RedisTemplate redisTemplate, ActivityService activityService,
UserService userService, CouponService couponService) {
this.redisTemplate = redisTemplate;
this.activityService = activityService;
this.userService = userService;
this.couponService = couponService;
}
@Override
public PageBean listUserCoupons(CouponQueryParam params) {
var users = userService.lambdaQuery()
.like(CommUtil.isNotEmptyAndNull(params.getMobilePhone()), User::getMobilePhone, params.getMobilePhone())
.list();
var userId2Mobile = users.stream().collect(Collectors.toMap(User::getId, User::getMobilePhone));
var userIds = users.stream().map(User::getId).toList();
PageHelper.startPage(params.getPageNum(), params.getPageSize());
var list = lambdaQuery()
.in(CommUtil.isNotEmptyAndNull(userIds), UserCoupon::getUserId, userIds)
.eq(CommUtil.isNotEmptyAndNull(params.getActivityId()), UserCoupon::getId, params.getCouponId())
.like(CommUtil.isNotEmptyAndNull(params.getActivityName()), UserCoupon::getActivityName, params.getActivityName())
.eq(CommUtil.isNotEmptyAndNull(params.getCouponId()), UserCoupon::getId, params.getCouponId())
.like(CommUtil.isNotEmptyAndNull(params.getCouponName()), UserCoupon::getCouponName, params.getCouponName())
.eq(CommUtil.isNotEmptyAndNull(params.getCouponType()), UserCoupon::getCouponType, params.getCouponType())
.eq(CommUtil.isNotEmptyAndNull(params.getUsageStatus()), UserCoupon::getUsageStatus, params.getUsageStatus())
.orderByDesc(UserCoupon::getId)
.list();
var voList = list.stream().map(userCoupon -> {
var vo = new UserCouponVo();
BeanUtils.copyProperties(userCoupon, vo);
vo.setMobilePhone(userId2Mobile.get(userCoupon.getUserId()));
return vo;
}).toList();
var res = new PageBean<>(voList);
return new PageBean<>(voList).setList(res);
}
@Override
public void collectCoupon(Long couponId) {
// 优惠券状态校验
var coupon = couponService.lambdaQuery()
.eq(Coupon::getId, couponId)
.in(Coupon::getStatus, Coupon.STATUS_未开始, Coupon.STATUS_进行中)
.one();
if (coupon == null) {
throw new BusinessException("优惠券不存在或已失效!");
}
if (coupon.getClaimedQuantity() >= coupon.getQuantity() && coupon.getQuantity() > 0) {
throw new BusinessException("优惠券已领完!");
}
// 重复领取校验
var userId = StpUtil.getLoginIdAsLong();
var exist = redisTemplate.opsForSet().isMember(RedisKeys.COUPON_ID_TO_USERS, couponId + ":" + userId);
if (Boolean.TRUE.equals(exist)) {
throw new BusinessException("优惠券已领取,请勿重复领取!");
}
// 活动
var activity = activityService.getById(coupon.getActivityId());
// 更新优惠券已领取数量
coupon.setClaimedQuantity(coupon.getClaimedQuantity() + 1);
// 校验优惠券数量是否已领完
if (coupon.getClaimedQuantity() >= coupon.getQuantity() && coupon.getQuantity() > 0) {
coupon.setStatus(Coupon.STATUS_已结束);
}
couponService.updateById(coupon);
// 存入缓存和数据库
redisTemplate.opsForSet().add(RedisKeys.COUPON_ID_TO_USERS, couponId + ":" + userId);
var userCoupon = new UserCoupon();
userCoupon.setActivityId(coupon.getActivityId());
userCoupon.setActivityName(activity.getName());
userCoupon.setCouponId(coupon.getId());
userCoupon.setCouponName(coupon.getName());
userCoupon.setUserId(userId);
userCoupon.setStartTime(LocalDateTime.now());
userCoupon.setEndTime(LocalDateTime.now().with(LocalTime.MAX).plusDays(coupon.getValidity() - 1));
userCoupon.setValidity(coupon.getValidity());
userCoupon.setCouponType(coupon.getCouponType());
userCoupon.setDiscount(coupon.getDiscount());
userCoupon.setMinServiceMoney(coupon.getMinServiceMoney());
userCoupon.setAllowStacke(coupon.getAllowStacke());
userCoupon.setStatus(UserCoupon.STATUS_有效);
userCoupon.setRemark(coupon.getRemark());
// userCouponSender.sendMessage(userCoupon);
save(userCoupon);
// todo 优惠券活动终止时处理redis数据,优惠券失效或者使用之后该做什么操作?
}
/**
* 通过订单号查询订单使用的优惠券信息
*
* @param startChargeSeq
* @return
*/
@Override
public UserOrderCouponVo getUserOrderCoupon(String startChargeSeq) {
var userId = StpUtil.getLoginIdAsLong();
MPJLambdaWrapper wrapper = JoinWrappers.lambda(UserCoupon.class)
.selectAsClass(UserCoupon.class, UserOrderCouponVo.class)
.selectAs(OrderCoupon::getStartChargeSeq, UserOrderCouponVo::getStartChargeSeq)
.selectAs(OrderCoupon::getDiscountAmount, UserOrderCouponVo::getOrderDiscountAmount)
.rightJoin(OrderCoupon.class, on -> on.eq(OrderCoupon::getCouponId, UserCoupon::getCouponId).eq(OrderCoupon::getUserId, UserCoupon::getUserId))
.eq(OrderCoupon::getStartChargeSeq, startChargeSeq)
.eq(OrderCoupon::getUserId, userId)
.eq(OrderCoupon::getStatus, OrderCoupon.STATUS_使用成功);
return selectJoinOne(UserOrderCouponVo.class, wrapper);
}
@Override
public List listStationAvailableCoupons(Map params) {
return baseMapper.listStationAvailableCoupons(params);
}
}