CouponReceiveServiceImpl.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. package com.ylx.massage.service.impl;
  2. import cn.hutool.core.collection.CollectionUtil;
  3. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  4. import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
  5. import com.baomidou.mybatisplus.core.toolkit.IdWorker;
  6. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  7. import com.ylx.common.core.domain.R;
  8. import com.ylx.common.core.domain.model.WxLoginUser;
  9. import com.ylx.massage.domain.Coupon;
  10. import com.ylx.massage.domain.UserCouponRelation;
  11. import com.ylx.massage.domain.vo.ClaimCouponRequestVO;
  12. import com.ylx.massage.domain.vo.CouponReceiveVo;
  13. import com.ylx.massage.domain.vo.CouponReceivesVO;
  14. import com.ylx.massage.mapper.CouponReceiveMapper;
  15. import com.ylx.massage.domain.CouponReceive;
  16. import com.ylx.massage.mapper.UserCouponRelationMapper;
  17. import com.ylx.massage.service.CouponReceiveService;
  18. import com.ylx.massage.service.CouponService;
  19. import com.ylx.massage.utils.DateTimeUtils;
  20. import lombok.extern.slf4j.Slf4j;
  21. import org.apache.commons.compress.utils.Lists;
  22. import org.springframework.beans.factory.annotation.Autowired;
  23. import org.springframework.data.redis.core.StringRedisTemplate;
  24. import org.springframework.stereotype.Service;
  25. import org.springframework.transaction.annotation.Transactional;
  26. import javax.annotation.Resource;
  27. import java.math.BigDecimal;
  28. import java.math.RoundingMode;
  29. import java.time.LocalDateTime;
  30. import java.util.*;
  31. import java.util.concurrent.TimeUnit;
  32. import java.util.stream.Collectors;
  33. import static com.ylx.common.utils.SecurityUtils.getWxLoginUser;
  34. /**
  35. * 优惠券领取表(CouponReceive)表服务实现类
  36. *
  37. * @author makejava
  38. * @since 2024-05-14 11:25:45
  39. */
  40. @Slf4j
  41. @Service("couponReceiveService")
  42. public class CouponReceiveServiceImpl extends ServiceImpl<CouponReceiveMapper, CouponReceive> implements CouponReceiveService {
  43. private static final String SHARE_LOCK_KEY = "coupon_center:receiveCoupon:lock:";
  44. private static final long LOCK_EXPIRE_TIME = 2L; // 锁过期时间2秒
  45. @Resource
  46. private CouponService couponService;
  47. @Resource
  48. private CouponReceiveMapper couponReceiveMapper;
  49. @Resource
  50. private UserCouponRelationMapper userCouponRelationMapper;
  51. @Autowired
  52. private StringRedisTemplate redisTemplate;
  53. @Override
  54. public Coupon submit(CouponReceive couponReceive) {
  55. Coupon coupon = couponService.getById(couponReceive.getCouponId());
  56. if (coupon == null) {
  57. return null;
  58. }
  59. LambdaQueryWrapper<CouponReceive> queryWrapper = new LambdaQueryWrapper<>();
  60. queryWrapper.eq(CouponReceive::getReceiveOpenId, couponReceive.getReceiveOpenId()).eq(CouponReceive::getCouponId, couponReceive.getCouponId());
  61. //限制领取数量
  62. List<CouponReceive> one = this.list(queryWrapper);
  63. if (coupon.getUserLimit() <= one.size()) {
  64. return null;
  65. }
  66. couponReceive.setExpirationTime(DateTimeUtils.addDays(new Date(), coupon.getTermDays()));
  67. this.save(couponReceive);
  68. return coupon;
  69. }
  70. @Override
  71. @Transactional(rollbackFor = Exception.class)
  72. public Integer submits(CouponReceivesVO couponReceive) {
  73. LambdaQueryWrapper<Coupon> queryWrapper = new LambdaQueryWrapper<>();
  74. queryWrapper.in(Coupon::getId, couponReceive.getCouponIds());
  75. List<Coupon> list = couponService.list(queryWrapper);
  76. if (CollectionUtil.isEmpty(list)) {
  77. log.info("优惠卷不存在");
  78. return null;
  79. }
  80. ArrayList<CouponReceive> couponReceives = Lists.newArrayList();
  81. list.forEach(coupon -> {
  82. CouponReceive couponRec = new CouponReceive();
  83. couponRec.setId(Long.toString(IdWorker.getId(couponRec)));
  84. couponRec.setCouponId(coupon.getId());
  85. couponRec.setReceiveOpenId(couponReceive.getOpenId());
  86. /*couponRec.setDeptId(coupon.getDeptId());
  87. couponRec.setDeptName(coupon.getDeptName());*/
  88. couponRec.setCouponStatus(0);
  89. couponRec.setExpirationTime(DateTimeUtils.addDays(new Date(), coupon.getTermDays()));
  90. couponReceives.add(couponRec);
  91. });
  92. return couponReceiveMapper.insertBatch(couponReceives);
  93. }
  94. @Override
  95. @Transactional(rollbackFor = Exception.class)
  96. public R<?> receiveVolution(ClaimCouponRequestVO claimCouponRequestVO) {
  97. // 1、查询用户信息
  98. WxLoginUser wxLoginUser = getWxLoginUser();
  99. String openid = wxLoginUser.getCOpenid();
  100. log.info("当前用户的openId:{}", openid);
  101. //2、保存优惠券信息到coupon_receive表
  102. // 构建防重复提交的key:用户openId + 优惠卷id
  103. String lockKey = SHARE_LOCK_KEY + wxLoginUser.getCOpenid() + ":" + claimCouponRequestVO.getTemplateId();
  104. // 尝试获取锁,防止重复提交
  105. Boolean lockResult = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", LOCK_EXPIRE_TIME, TimeUnit.SECONDS);
  106. if (Boolean.FALSE.equals(lockResult)) {
  107. return R.fail("操作过于频繁,请稍后再试");
  108. }
  109. CouponReceive couponReceive = new CouponReceive();
  110. couponReceive.setIssuerCouponId(claimCouponRequestVO.getUserId());
  111. couponReceive.setCouponId(claimCouponRequestVO.getTemplateId());
  112. couponReceive.setCouponType(Integer.parseInt(claimCouponRequestVO.getType()));
  113. couponReceive.setReceiveOpenId(wxLoginUser.getCOpenid());
  114. couponReceive.setReceiveTime(LocalDateTime.now());
  115. //设置领取人手机号
  116. couponReceive.setReceiveUserPhone(wxLoginUser.getCPhone());
  117. //获取当前有效期类型
  118. String validityType = claimCouponRequestVO.getValidityType();
  119. switch (validityType) {
  120. // 固定日期范围
  121. case "1":
  122. couponReceive.setValidityType(1);
  123. couponReceive.setValidStartTime(claimCouponRequestVO.getValidStartTime());
  124. couponReceive.setExpirationTime(claimCouponRequestVO.getValidEndTime());
  125. break;
  126. //领券后N天有效
  127. case "2":
  128. couponReceive.setValidityType(2);
  129. couponReceive.setValidDays(Integer.parseInt(claimCouponRequestVO.getValidDays()));
  130. break;
  131. //长期有效
  132. case "3":
  133. couponReceive.setValidityType(3);
  134. break;
  135. default:
  136. throw new IllegalArgumentException("有效期类型错误");
  137. }
  138. // 设置使用状态:待使用
  139. couponReceive.setCouponStatus(0);
  140. int insert = couponReceiveMapper.insert(couponReceive);
  141. if (insert == 0) {
  142. return R.fail("优惠券领取失败");
  143. }
  144. // 3、将优惠券id和用户id做绑定插入用户优惠券关联表
  145. UserCouponRelation userCouponRelation = new UserCouponRelation();
  146. userCouponRelation.setOpenId(wxLoginUser.getCOpenid());
  147. userCouponRelation.setCouponId(claimCouponRequestVO.getTemplateId());
  148. userCouponRelation.setCouponName(claimCouponRequestVO.getName());
  149. userCouponRelation.setImageUrl(claimCouponRequestVO.getImageUrl());
  150. userCouponRelation.setCouponType(Integer.parseInt(claimCouponRequestVO.getType()));
  151. //设置状态为未使用
  152. userCouponRelation.setCouponStatus(0);
  153. switch (validityType) {
  154. // 固定日期范围
  155. case "1":
  156. userCouponRelation.setValidityType(Integer.parseInt(validityType));
  157. couponReceive.setValidStartTime(claimCouponRequestVO.getValidStartTime());
  158. couponReceive.setExpirationTime(claimCouponRequestVO.getValidEndTime());
  159. break;
  160. //领券后N天有效
  161. case "2":
  162. userCouponRelation.setValidityType(Integer.parseInt(validityType));
  163. couponReceive.setValidDays(Integer.parseInt(claimCouponRequestVO.getValidDays()));
  164. break;
  165. //长期有效
  166. case "3":
  167. userCouponRelation.setValidityType(Integer.parseInt(validityType));
  168. break;
  169. default:
  170. throw new IllegalArgumentException("有效期类型错误");
  171. }
  172. //市场售价
  173. BigDecimal marketPrice = BigDecimal.ZERO;
  174. //2-折扣券
  175. if ("2".equals(claimCouponRequestVO.getType())) {
  176. marketPrice = claimCouponRequestVO.getRuleMinSpendAmount().multiply(claimCouponRequestVO.getRuleDiscountRate())
  177. .divide(new BigDecimal("10")).setScale(2, RoundingMode.HALF_UP);
  178. } else if ("3".equals(claimCouponRequestVO.getType())) {
  179. //满减券
  180. marketPrice = claimCouponRequestVO.getRuleReductionAmount();
  181. } else if ("1".equals(claimCouponRequestVO.getType())) {
  182. //兑换券
  183. marketPrice = claimCouponRequestVO.getCostPrice();
  184. }
  185. userCouponRelation.setMarketPrice(marketPrice);
  186. // 设置券来源 0:券中心
  187. userCouponRelation.setTicketSource(0);
  188. userCouponRelation.setCountry(claimCouponRequestVO.getCountry());
  189. userCouponRelation.setCountryAll(claimCouponRequestVO.getCountryAll());
  190. userCouponRelation.setLocality(claimCouponRequestVO.getLocality());
  191. userCouponRelation.setMerchantId(claimCouponRequestVO.getMerchantId());
  192. userCouponRelation.setStoreName(claimCouponRequestVO.getStoreName());
  193. userCouponRelation.setCenterShareUserId(claimCouponRequestVO.getUserId());
  194. userCouponRelation.setRuleMinSpendAmount(claimCouponRequestVO.getRuleMinSpendAmount());
  195. userCouponRelation.setRuleDiscountRate(claimCouponRequestVO.getRuleDiscountRate());
  196. userCouponRelation.setRuleDiscountCapAmount(claimCouponRequestVO.getRuleDiscountCapAmount());
  197. userCouponRelation.setRuleReductionAmount(claimCouponRequestVO.getRuleReductionAmount());
  198. userCouponRelation.setReceiveTime(LocalDateTime.now());
  199. userCouponRelationMapper.insert(userCouponRelation);
  200. return R.ok("领取成功");
  201. }
  202. @Override
  203. public List<CouponReceiveVo> getByOpenId(String openid) {
  204. List<CouponReceiveVo> CouponReceiveVos = couponReceiveMapper.getByOpenId(openid);
  205. CouponReceiveVos.forEach(couponReceiveVo -> {
  206. if(couponReceiveVo.getExpirationTime() == null){
  207. couponReceiveVo.setExpirationTimeString("长期有效");
  208. }else{
  209. couponReceiveVo.setExpirationTimeString(DateTimeUtils.formatDate(couponReceiveVo.getExpirationTime(), DateTimeUtils.DATE_FORMAT));
  210. }
  211. });
  212. return CouponReceiveVos;
  213. }
  214. @Override
  215. @Transactional(rollbackFor = Exception.class)
  216. public void removeCoupons(List<CouponReceiveVo> coupons) {
  217. boolean b = this.removeByIds(coupons.stream().map(CouponReceiveVo::getId).collect(Collectors.toList()));
  218. //使用数量+1
  219. coupons.forEach(coup -> {
  220. UpdateWrapper<Coupon> wrapper = new UpdateWrapper<>();
  221. wrapper.lambda().eq(Coupon::getId, coup.getCouponId());
  222. wrapper.setSql(" used_num = used_num + " + 1);
  223. couponService.update(wrapper);
  224. });
  225. }
  226. @Override
  227. public List<Coupon> couponWindows(CouponReceive couponReceive) {
  228. //判断是否领过优惠卷
  229. //查询领取优惠卷
  230. LambdaQueryWrapper<CouponReceive> query = new LambdaQueryWrapper<>();
  231. query.eq(CouponReceive::getReceiveOpenId, couponReceive.getReceiveOpenId());
  232. List<CouponReceive> couponReceive1 = this.list(query);
  233. //如果没有领取优惠卷
  234. if (CollectionUtil.isEmpty(couponReceive1)) {
  235. //查询优惠卷
  236. LambdaQueryWrapper<Coupon> couponLambdaQueryWrapper = new LambdaQueryWrapper<>();
  237. couponLambdaQueryWrapper.eq(Coupon::getStatus, 1);
  238. //couponLambdaQueryWrapper.eq(Coupon::getStatus, 1).like(Coupon::getDeptName, couponReceive.getDeptName());
  239. //返回新人优惠卷列表
  240. return couponService.list(couponLambdaQueryWrapper);
  241. } else {
  242. return Collections.emptyList();
  243. }
  244. }
  245. @Override
  246. public Map<String, Object> selectCouponDetailForCalc(String couponId, String openId) {
  247. return this.baseMapper.selectCouponDetailForCalc(couponId, openId);
  248. }
  249. @Override
  250. public int useCouponOptimisticLock(String couponId, String openId, Long orderId, Integer orderType, LocalDateTime now) {
  251. return this.baseMapper.useCouponOptimisticLock(couponId, openId, orderId, orderType, now);
  252. }
  253. @Override
  254. public int incrementUsedNum(String couponId) {
  255. return this.baseMapper.incrementUsedNum(couponId);
  256. }
  257. @Override
  258. public int returnCouponOptimisticLock(String couponId, String openId, Long orderId) {
  259. return this.baseMapper.returnCouponOptimisticLock(couponId,openId,orderId);
  260. }
  261. @Override
  262. public void decrementUsedNum(String couponId) {
  263. this.baseMapper.decrementUsedNum(couponId);
  264. }
  265. }