Commit cc087e4ecaa19d68cbbc22943e13312c394ac012

Authored by YunaiV
1 parent a37427c3

promotion:增加创建砍价的接口

Showing 11 changed files with 137 additions and 63 deletions
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
... ... @@ -88,17 +88,16 @@ public interface ErrorCodeConstants {
88 88 // ========== 砍价活动 1-013-012-000 ==========
89 89 ErrorCode BARGAIN_ACTIVITY_NOT_EXISTS = new ErrorCode(1_013_012_000, "砍价活动不存在");
90 90 ErrorCode BARGAIN_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1_013_012_001, "存在商品参加了其它砍价活动");
91   - ErrorCode BARGAIN_ACTIVITY_STATUS_DISABLE = new ErrorCode(1_013_012_002, "砍价活动已关闭不能修改");
  91 + ErrorCode BARGAIN_ACTIVITY_STATUS_DISABLE = new ErrorCode(1_013_012_002, "砍价活动已关闭,不能修改");
92 92 ErrorCode BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1_013_012_003, "砍价活动未关闭或未结束,不能删除");
93   - ErrorCode BARGAIN_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1_013_012_004, "砍价失败,原因:该砍价活动库存不足");
  93 + ErrorCode BARGAIN_ACTIVITY_STOCK_NOT_ENOUGH = new ErrorCode(1_013_012_004, "砍价活动库存不足");
  94 + ErrorCode BARGAIN_ACTIVITY_STATUS_CLOSED = new ErrorCode(1_013_012_005, "砍价活动已关闭");
  95 + ErrorCode BARGAIN_ACTIVITY_TIME_END = new ErrorCode(1_013_012_006, "砍价活动已经结束");
94 96  
95 97 // ========== 砍价记录 1-013-013-000 ==========
96 98 ErrorCode BARGAIN_RECORD_NOT_EXISTS = new ErrorCode(1_013_013_000, "砍价记录不存在");
97   - ErrorCode BARGAIN_RECORD_EXISTS = new ErrorCode(1_013_013_001, "砍价失败,已参与过该砍价");
98   - ErrorCode BARGAIN_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1_013_013_002, "砍价失败,父砍价不存在");
99   - ErrorCode BARGAIN_RECORD_USER_FULL = new ErrorCode(1_013_013_003, "砍价失败,砍价人数已满");
100   - ErrorCode BARGAIN_JOIN_RECORD_NOT_IN_PROGRESS = new ErrorCode(1_013_013_004, "砍价失败,砍价记录不在进行中");
101   - ErrorCode BARGAIN_JOIN_FAILED_ACTIVITY_TIME_END = new ErrorCode(1_013_013_005, "砍价失败,活动已经结束");
102   - ErrorCode BARGAIN_JOIN_ACTIVITY_STATUS_CLOSED = new ErrorCode(1_013_013_006, "砍价失败,原因:砍价活动已关闭");
  99 + ErrorCode BARGAIN_RECORD_CREATE_FAIL_EXISTS = new ErrorCode(1_013_013_001, "参与失败,您已经参与当前砍价活动");
  100 + ErrorCode BARGAIN_RECORD_CREATE_FAIL_LIMIT = new ErrorCode(1_013_013_002, "参与失败,您已达到当前砍价活动的参与上限");
  101 + ErrorCode BARGAIN_JOIN_RECORD_NOT_SUCCESS = new ErrorCode(1_013_013_004, "下单失败,砍价未成功");
103 102  
104 103 }
... ...
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/bargain/BargainRecordStatusEnum.java
... ... @@ -17,7 +17,7 @@ public enum BargainRecordStatusEnum implements IntArrayValuable {
17 17  
18 18 IN_PROGRESS(1, "砍价中"),
19 19 SUCCESS(2, "砍价成功"),
20   - FAILED(3, "砍价失败"),
  20 + FAILED(3, "砍价失败"), // 活动到期时,会自动将到期的砍价全部设置为过期
21 21 ;
22 22  
23 23 public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BargainRecordStatusEnum::getStatus).toArray();
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/AppBargainRecordController.http 0 → 100644
  1 +### /promotion/bargain-record/create 创建砍价记录
  2 +POST {{appApi}}/promotion/bargain-record/create
  3 +Authorization: Bearer {{appToken}}
  4 +Content-Type: application/json
  5 +tenant-id: {{appTenentId}}
  6 +
  7 +{
  8 + "activityId": 1
  9 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/bargain/AppBargainRecordController.java
... ... @@ -4,19 +4,23 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageParam;
5 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 6 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
  7 +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
7 8 import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.record.AppBargainRecordCreateReqVO;
8 9 import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.record.AppBargainRecordDetailRespVO;
9 10 import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.record.AppBargainRecordRespVO;
10 11 import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.record.AppBargainRecordSummaryRespVO;
  12 +import cn.iocoder.yudao.module.promotion.service.bargain.BargainRecordService;
11 13 import io.swagger.v3.oas.annotations.Operation;
12 14 import io.swagger.v3.oas.annotations.tags.Tag;
13 15 import org.springframework.validation.annotation.Validated;
14 16 import org.springframework.web.bind.annotation.*;
15 17  
  18 +import javax.annotation.Resource;
16 19 import java.time.Duration;
17 20 import java.util.ArrayList;
18 21  
19 22 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  23 +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
20 24  
21 25 @Tag(name = "用户 App - 砍价记录")
22 26 @RestController
... ... @@ -24,6 +28,9 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
24 28 @Validated
25 29 public class AppBargainRecordController {
26 30  
  31 + @Resource
  32 + private BargainRecordService bargainRecordService;
  33 +
27 34 @GetMapping("/get-summary")
28 35 @Operation(summary = "获得砍价记录的概要信息", description = "用于小程序首页")
29 36 // TODO 芋艿:增加 @Cache 缓存,1 分钟过期
... ... @@ -137,9 +144,11 @@ public class AppBargainRecordController {
137 144 }
138 145  
139 146 @PostMapping("/create")
140   - @Operation(summary = "创建砍价记录", description = "参与拼团活动")
  147 + @Operation(summary = "创建砍价记录", description = "参与砍价活动")
  148 + @PreAuthenticated
141 149 public CommonResult<Long> createBargainRecord(@RequestBody AppBargainRecordCreateReqVO reqVO) {
142   - return success(1L);
  150 + Long recordId = bargainRecordService.createBargainRecord(getLoginUserId(), reqVO);
  151 + return success(recordId);
143 152 }
144 153  
145 154 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/bargain/BargainActivityDO.java
... ... @@ -60,24 +60,29 @@ public class BargainActivityDO extends BaseDO {
60 60 */
61 61 private Long skuId;
62 62 /**
63   - * 砍价起始价格,单位分
  63 + * 砍价起始价格,单位:分
64 64 */
65 65 private Integer bargainFirstPrice;
66 66 /**
67 67 * 砍价底价,单位:分
68 68 */
69   - private Integer bargainPrice;
  69 + private Integer bargainMinPrice;
70 70 /**
71 71 * 砍价活动库存
72 72 */
73 73 private Integer stock;
74 74  
75 75 /**
76   - * 达到该人数,才能砍到低价
  76 + * 砍价人数
  77 + *
  78 + * 需要多少人,砍价才能成功,即 {@link BargainRecordDO#getStatus()} 更新为 {@link BargainRecordDO#getStatus()} 成功状态
77 79 */
78 80 private Integer userSize;
79 81 /**
80   - * 最大帮砍次数
  82 + * 帮砍次数
  83 + *
  84 + * 单个活动,用户可以帮砍的次数。
  85 + * 例如说:帮砍次数为 1 时,A 和 B 同时将该活动链接发给 C,C 只能帮其中一个人砍价。
81 86 */
82 87 private Integer bargainCount;
83 88  
... ... @@ -93,6 +98,9 @@ public class BargainActivityDO extends BaseDO {
93 98 * 用户每次砍价的最大金额,单位:分
94 99 */
95 100 private Integer randomMaxPrice;
  101 +
  102 + // ========== 统计字段 ==========
  103 +
96 104 /**
97 105 * 砍价成功数量
98 106 */
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/bargain/BargainRecordDO.java
... ... @@ -29,18 +29,18 @@ public class BargainRecordDO extends BaseDO {
29 29 */
30 30 @TableId
31 31 private Long id;
32   -
33   - /**
34   - * 砍价活动编号
35   - */
36   - private Long activityId;
37   -
38 32 /**
39 33 * 用户编号
40 34 */
41 35 private Long userId;
42 36  
43 37 /**
  38 + * 砍价活动编号
  39 + *
  40 + * 关联 {@link BargainActivityDO#getId()} 字段
  41 + */
  42 + private Long activityId;
  43 + /**
44 44 * 商品 SPU 编号
45 45 */
46 46 private Long spuId;
... ... @@ -50,17 +50,13 @@ public class BargainRecordDO extends BaseDO {
50 50 private Long skuId;
51 51  
52 52 /**
53   - * 砍价底价,单位:分
54   - */
55   - private Integer bargainPrice;
56   - /**
57   - * 商品原价,单位:分
  53 + * 砍价起始价格,单位:分
58 54 */
59   - private Integer price;
  55 + private Integer bargainFirstPrice;
60 56 /**
61   - * 应付金额,单位:分
  57 + * 当前砍价,单位:分
62 58 */
63   - private Integer payPrice;
  59 + private Integer bargainPrice;
64 60  
65 61 /**
66 62 * 砍价状态
... ... @@ -68,22 +64,14 @@ public class BargainRecordDO extends BaseDO {
68 64 * 枚举 {@link BargainRecordStatusEnum}
69 65 */
70 66 private Integer status;
71   -
72   - /**
73   - * 订单编号
74   - */
75   - private Long orderId;
76   -
77 67 /**
78 68 * 结束时间
79 69 */
80 70 private LocalDateTime endTime;
81 71  
82 72 /**
83   - * 过期时间
84   - *
85   - * 到达该时间时,其他用户无法帮助砍价,但是还是允许下单
  73 + * 订单编号
86 74 */
87   - private LocalDateTime expireTime;
  75 + private Long orderId;
88 76  
89 77 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/bargain/BargainRecordMapper.java
... ... @@ -2,8 +2,11 @@ package cn.iocoder.yudao.module.promotion.dal.mysql.bargain;
2 2  
3 3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
4 4 import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainRecordDO;
  5 +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
5 6 import org.apache.ibatis.annotations.Mapper;
6 7  
  8 +import java.util.List;
  9 +
7 10 /**
8 11 * 砍价记录 Mapper
9 12 *
... ... @@ -17,4 +20,20 @@ public interface BargainRecordMapper extends BaseMapperX&lt;BargainRecordDO&gt; {
17 20 BargainRecordDO::getUserId, userId);
18 21 }
19 22  
  23 + default List<BargainRecordDO> selectListByUserIdAndActivityIdAndStatus(
  24 + Long userId, Long activityId, Integer status) {
  25 + return selectList(new LambdaQueryWrapper<>(BargainRecordDO.class)
  26 + .eq(BargainRecordDO::getUserId, userId)
  27 + .eq(BargainRecordDO::getActivityId, activityId)
  28 + .eq(BargainRecordDO::getStatus, status));
  29 + }
  30 +
  31 + default Long selectCountByUserIdAndActivityIdAndStatus(
  32 + Long userId, Long activityId, Integer status) {
  33 + return selectCount(new LambdaQueryWrapper<>(BargainRecordDO.class)
  34 + .eq(BargainRecordDO::getUserId, userId)
  35 + .eq(BargainRecordDO::getActivityId, activityId)
  36 + .eq(BargainRecordDO::getStatus, status));
  37 + }
  38 +
20 39 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityService.java
... ... @@ -56,6 +56,14 @@ public interface BargainActivityService {
56 56 BargainActivityDO getBargainActivity(Long id);
57 57  
58 58 /**
  59 + * 校验砍价活动,是否可以参与(发起砍价、下单、帮好友砍价)
  60 + *
  61 + * @param id 编号
  62 + * @return 砍价活动
  63 + */
  64 + BargainActivityDO validateBargainActivityCanJoin(Long id);
  65 +
  66 + /**
59 67 * 获得砍价活动分页
60 68 *
61 69 * @param pageReqVO 分页查询
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainActivityServiceImpl.java
1 1 package cn.iocoder.yudao.module.promotion.service.bargain;
2 2  
  3 +import cn.hutool.core.util.ObjUtil;
3 4 import cn.hutool.core.util.ObjectUtil;
4 5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 6 import cn.iocoder.yudao.framework.common.pojo.PageParam;
... ... @@ -82,13 +83,13 @@ public class BargainActivityServiceImpl implements BargainActivityService {
82 83 throw exception(BARGAIN_ACTIVITY_NOT_EXISTS);
83 84 }
84 85 if (count > activity.getStock()) {
85   - throw exception(BARGAIN_ACTIVITY_UPDATE_STOCK_FAIL);
  86 + throw exception(BARGAIN_ACTIVITY_STOCK_NOT_ENOUGH);
86 87 }
87 88  
88 89 // 更新砍价库存
89 90 int updateCount = bargainActivityMapper.updateStock(id, count);
90 91 if (updateCount == 0) {
91   - throw exception(BARGAIN_ACTIVITY_UPDATE_STOCK_FAIL);
  92 + throw exception(BARGAIN_ACTIVITY_STOCK_NOT_ENOUGH);
92 93 }
93 94 }
94 95  
... ... @@ -139,6 +140,21 @@ public class BargainActivityServiceImpl implements BargainActivityService {
139 140 }
140 141  
141 142 @Override
  143 + public BargainActivityDO validateBargainActivityCanJoin(Long id) {
  144 + BargainActivityDO activity = bargainActivityMapper.selectById(id);
  145 + if (activity == null) {
  146 + throw exception(BARGAIN_ACTIVITY_NOT_EXISTS);
  147 + }
  148 + if (ObjUtil.notEqual(activity.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
  149 + throw exception(BARGAIN_ACTIVITY_STATUS_CLOSED);
  150 + }
  151 + if (activity.getStock() <= 0) {
  152 + throw exception(BARGAIN_ACTIVITY_STOCK_NOT_ENOUGH);
  153 + }
  154 + return activity;
  155 + }
  156 +
  157 + @Override
142 158 public PageResult<BargainActivityDO> getBargainActivityPage(BargainActivityPageReqVO pageReqVO) {
143 159 return bargainActivityMapper.selectPage(pageReqVO);
144 160 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainRecordService.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.service.bargain;
2 2  
3 3  
4 4 import cn.iocoder.yudao.module.promotion.api.bargain.dto.BargainValidateJoinRespDTO;
  5 +import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.record.AppBargainRecordCreateReqVO;
5 6  
6 7 /**
7 8 * 砍价记录 service 接口
... ... @@ -11,6 +12,15 @@ import cn.iocoder.yudao.module.promotion.api.bargain.dto.BargainValidateJoinResp
11 12 public interface BargainRecordService {
12 13  
13 14 /**
  15 + * 【会员】创建砍价记录(参与参加活动)
  16 + *
  17 + * @param userId 用户编号
  18 + * @param reqVO 创建信息
  19 + * @return 砍价记录编号
  20 + */
  21 + Long createBargainRecord(Long userId, AppBargainRecordCreateReqVO reqVO);
  22 +
  23 + /**
14 24 * 【下单前】校验是否参与砍价活动
15 25 * <p>
16 26 * 如果校验失败,则抛出业务异常
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/bargain/BargainRecordServiceImpl.java
1 1 package cn.iocoder.yudao.module.promotion.service.bargain;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.hutool.core.lang.Assert;
4 5 import cn.hutool.core.util.ObjUtil;
5   -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
6   -import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
7 6 import cn.iocoder.yudao.module.promotion.api.bargain.dto.BargainValidateJoinRespDTO;
  7 +import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.record.AppBargainRecordCreateReqVO;
8 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
9 9 import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainRecordDO;
10 10 import cn.iocoder.yudao.module.promotion.dal.mysql.bargain.BargainRecordMapper;
... ... @@ -13,7 +13,6 @@ import org.springframework.stereotype.Service;
13 13 import org.springframework.validation.annotation.Validated;
14 14  
15 15 import javax.annotation.Resource;
16   -
17 16 import java.util.Objects;
18 17  
19 18 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
... ... @@ -34,7 +33,30 @@ public class BargainRecordServiceImpl implements BargainRecordService {
34 33 @Resource
35 34 private BargainRecordMapper bargainRecordMapper;
36 35  
37   - // TODO puhui999:create 时,需要校验下限购数量;
  36 + @Override
  37 + public Long createBargainRecord(Long userId, AppBargainRecordCreateReqVO reqVO) {
  38 + // 1. 校验砍价活动
  39 + BargainActivityDO activity = bargainActivityService.validateBargainActivityCanJoin(reqVO.getActivityId());
  40 +
  41 + // 2.1 校验当前是否已经有参与中的砍价活动
  42 + if (CollUtil.isNotEmpty(bargainRecordMapper.selectListByUserIdAndActivityIdAndStatus(
  43 + userId, reqVO.getActivityId(), BargainRecordStatusEnum.IN_PROGRESS.getStatus()))) {
  44 + throw exception(BARGAIN_RECORD_CREATE_FAIL_EXISTS);
  45 + }
  46 + // 2.2 是否超过参与的上限
  47 + if (bargainRecordMapper.selectCountByUserIdAndActivityIdAndStatus(
  48 + userId, reqVO.getActivityId(), BargainRecordStatusEnum.SUCCESS.getStatus()) >= activity.getTotalLimitCount()) {
  49 + throw exception(BARGAIN_RECORD_CREATE_FAIL_LIMIT);
  50 + }
  51 +
  52 + // 3. 创建砍价记录
  53 + BargainRecordDO record = BargainRecordDO.builder().userId(userId)
  54 + .activityId(reqVO.getActivityId()).spuId(activity.getSpuId()).skuId(activity.getSkuId())
  55 + .bargainFirstPrice(activity.getBargainFirstPrice()).bargainPrice(activity.getBargainFirstPrice())
  56 + .status(BargainRecordStatusEnum.IN_PROGRESS.getStatus()).build();
  57 + bargainRecordMapper.insert(record);
  58 + return record.getId();
  59 + }
38 60  
39 61 @Override
40 62 public BargainValidateJoinRespDTO validateJoinBargain(Long userId, Long bargainRecordId, Long skuId) {
... ... @@ -45,28 +67,14 @@ public class BargainRecordServiceImpl implements BargainRecordService {
45 67 }
46 68 // 1.2 拼团记录未在进行中
47 69 if (ObjUtil.notEqual(record.getStatus(), BargainRecordStatusEnum.IN_PROGRESS)) {
48   - throw exception(BARGAIN_JOIN_RECORD_NOT_IN_PROGRESS);
  70 + throw exception(BARGAIN_JOIN_RECORD_NOT_SUCCESS);
49 71 }
50 72  
51   - // 2.1 砍价活动不存在
52   - BargainActivityDO activity = bargainActivityService.getBargainActivity(record.getActivityId());
53   - if (activity == null) {
54   - throw exception(BARGAIN_ACTIVITY_NOT_EXISTS);
55   - }
56   - if (ObjUtil.notEqual(activity.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
57   - throw exception(BARGAIN_JOIN_ACTIVITY_STATUS_CLOSED);
58   - }
  73 + // 2. 校验砍价活动
  74 + BargainActivityDO activity = bargainActivityService.validateBargainActivityCanJoin(record.getActivityId());
59 75 Assert.isTrue(Objects.equals(skuId, activity.getSkuId()), "砍价商品不匹配"); // 防御性校验
60   - // 2.2 活动已过期
61   - if (LocalDateTimeUtils.isBetween(activity.getStartTime(), activity.getEndTime())) {
62   - throw exception(BARGAIN_JOIN_FAILED_ACTIVITY_TIME_END);
63   - }
64   - // 2.3 库存不足
65   - if (activity.getStock() <= 0) {
66   - throw exception(BARGAIN_ACTIVITY_UPDATE_STOCK_FAIL);
67   - }
68 76 return new BargainValidateJoinRespDTO().setActivityId(activity.getId()).setName(activity.getName())
69   - .setBargainPrice(record.getPayPrice());
  77 + .setBargainPrice(record.getBargainPrice());
70 78 }
71 79  
72 80 }
... ...