2026-06-26 20b96473f2520590a0dca6b775b81e3ea06a77a0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package cn.iocoder.yudao.module.promotion.service.bargain;
 
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.help.BargainHelpPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.help.AppBargainHelpCreateReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainHelpDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainRecordDO;
import cn.iocoder.yudao.module.promotion.dal.mysql.bargain.BargainHelpMapper;
import cn.iocoder.yudao.module.promotion.enums.bargain.BargainRecordStatusEnum;
import jodd.util.MathUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
 
import jakarta.annotation.Resource;
 
import java.util.Collection;
import java.util.List;
import java.util.Map;
 
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
 
/**
 * 砍价助力 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class BargainHelpServiceImpl implements BargainHelpService {
 
    @Resource
    private BargainHelpMapper bargainHelpMapper;
 
    @Resource
    private BargainRecordService bargainRecordService;
    @Resource
    private BargainActivityService bargainActivityService;
 
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BargainHelpDO createBargainHelp(Long userId, AppBargainHelpCreateReqVO reqVO) {
        // 1.1 校验砍价记录存在,并且处于进行中
        BargainRecordDO record = bargainRecordService.getBargainRecord(reqVO.getRecordId());
        if (record == null) {
            throw exception(BARGAIN_RECORD_NOT_EXISTS);
        }
        if (ObjUtil.notEqual(record.getStatus(), BargainRecordStatusEnum.IN_PROGRESS.getStatus())) {
            throw exception(BARGAIN_HELP_CREATE_FAIL_RECORD_NOT_IN_PROCESS);
        }
        // 1.2 不能自己给自己砍价
        if (ObjUtil.equal(record.getUserId(), userId)) {
            throw exception(BARGAIN_HELP_CREATE_FAIL_RECORD_SELF);
        }
 
        // 2.1 校验砍价活动
        BargainActivityDO activity = bargainActivityService.getBargainActivity(record.getActivityId());
        // 2.2 校验自己是否助力次数上限
        if (bargainHelpMapper.selectCountByUserIdAndActivityId(userId, activity.getId())
                >= activity.getBargainCount()) {
            throw exception(BARGAIN_HELP_CREATE_FAIL_LIMIT);
        }
        // 2.3 特殊情况:砍价已经砍到最低价,不能再砍了
        if (record.getBargainPrice() <= activity.getBargainMinPrice()) {
            throw exception(BARGAIN_HELP_CREATE_FAIL_RECORD_NOT_IN_PROCESS);
        }
 
        // 3. 已经助力
        if (bargainHelpMapper.selectByUserIdAndRecordId(userId, record.getId()) != null) {
            throw exception(BARGAIN_HELP_CREATE_FAIL_HELP_EXISTS);
        }
 
        // 4.1 计算砍价金额
        Integer reducePrice = calculateReducePrice(activity, record);
        Assert.isTrue(reducePrice > 0, "砍价金额必须大于 0 元");
        // 4.2 创建助力记录
        BargainHelpDO help = BargainHelpDO.builder().userId(userId).activityId(activity.getId())
                .recordId(record.getId()).reducePrice(reducePrice).build();
        bargainHelpMapper.insert(help);
 
        // 5. 判断砍价记录是否完成
        Boolean success = record.getBargainPrice() - reducePrice <= activity.getBargainMinPrice() // 情况一:砍价已经砍到最低价
                || bargainHelpMapper.selectUserCountMapByRecordId(reqVO.getRecordId()) >= activity.getHelpMaxCount(); // 情况二:砍价助力已经达到上限
        if (!bargainRecordService.updateBargainRecordBargainPrice(
                record.getId(), record.getBargainPrice(), reducePrice, success)) {
            // 多人一起砍价,需要重试
            throw exception(BARGAIN_HELP_CREATE_FAIL_CONFLICT);
        }
        return help;
    }
 
    // TODO 芋艿:优化点:实现一个更随机的逻辑,可以按照你自己的业务;
    private Integer calculateReducePrice(BargainActivityDO activity, BargainRecordDO record) {
        // 1. 随机金额
        Integer reducePrice = MathUtil.randomInt(activity.getBargainMinPrice(),
                activity.getRandomMaxPrice() + 1); // + 1 的原因是,randomInt 默认不包含第二个参数
        // 2. 校验是否超过砍价上限
        if (record.getBargainPrice() - reducePrice < activity.getBargainMinPrice()) {
            reducePrice = record.getBargainPrice() - activity.getBargainMinPrice();
        }
        return reducePrice;
    }
 
    @Override
    public Map<Long, Integer> getBargainHelpUserCountMapByActivity(Collection<Long> activityIds) {
        return bargainHelpMapper.selectUserCountMapByActivityId(activityIds);
    }
 
    @Override
    public Map<Long, Integer> getBargainHelpUserCountMapByRecord(Collection<Long> recordIds) {
        return bargainHelpMapper.selectUserCountMapByRecordId(recordIds);
    }
 
    @Override
    public Long getBargainHelpCountByActivity(Long activityId, Long userId) {
        return bargainHelpMapper.selectCountByUserIdAndActivityId(userId, activityId);
    }
 
    @Override
    public PageResult<BargainHelpDO> getBargainHelpPage(BargainHelpPageReqVO pageReqVO) {
        return bargainHelpMapper.selectPage(pageReqVO);
    }
 
    @Override
    public List<BargainHelpDO> getBargainHelpListByRecordId(Long recordId) {
        return bargainHelpMapper.selectListByRecordId(recordId);
    }
 
    @Override
    public BargainHelpDO getBargainHelp(Long recordId, Long userId) {
        return bargainHelpMapper.selectByUserIdAndRecordId(userId, recordId);
    }
 
}