Administrator
2025-05-09 320e9165ac6cc6d90978fbef3074a8ed9add1790
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
package com.taoke.autopay.manager;
 
import com.alipay.api.AlipayApiException;
import com.taoke.autopay.dao.credit.CreditExchangeRecordMapper;
import com.taoke.autopay.dao.credit.ExchangeRateMapper;
import com.taoke.autopay.entity.credit.*;
import com.taoke.autopay.exception.UserCreditExchangeException;
import com.taoke.autopay.service.credit.*;
import com.taoke.autopay.utils.AlipayUtil;
import com.taoke.autopay.utils.TimeUtil;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
 
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;
 
@Component
public class UserCreditExchangeManager {
 
    @Resource
    private UserCreditBalanceService userCreditBalanceService;
 
    @Resource
    private CreditExchangeRecordService userCreditExchangeRecordService;
 
    @Resource
    private UserAlipayBindingService userAlipayBindingService;
 
    @Resource
    private ExchangeRateService exchangeRateService;
 
    @Resource
    private CreditSettingService creditSettingService;
 
    @Resource
    private UserCreditRecordService userCreditRecordService;
 
    @Resource
    private UserCreditManager userCreditManager;
 
    /**
     * 用户积分兑换
     *
     * @param request 兑换请求实体
     * @return 兑换记录ID
     */
    @Transactional(rollbackFor = Exception.class)
    public Long exchangeCredit(CreditExchangeRecord request) throws UserCreditExchangeException {
        Long userId = request.getUid();
        CreditExchangeRecord.ExchangeType exchangeType = request.getExchangeType();
        if (exchangeType != CreditExchangeRecord.ExchangeType.FUND_EXCHANGE) {
            throw new UserCreditExchangeException(UserCreditExchangeException.CODE_COMMON, "只支持红包兑换");
        }
 
        // 检查用户积分余额是否足够
        UserCreditBalance balance = userCreditBalanceService.getCreditBalanceByUserId(userId);
        if (balance == null || balance.getCreditBalance() < request.getConsumedCredits()) {
            throw new UserCreditExchangeException(UserCreditExchangeException.CODE_BALANCE_NOT_ENOUGH, "用户积分不足");
        }
 
 
        // 如果是红包兑换,判断用户兑换频率
        if (exchangeType == CreditExchangeRecord.ExchangeType.FUND_EXCHANGE) {
            checkRedPacketExchangeFrequency(userId);
        }
 
        // 查询用户绑定的支付宝账户
        List<UserAlipayBinding> alipayBindings = userAlipayBindingService.getBindingsByUid(userId);
        if (alipayBindings == null || alipayBindings.isEmpty()) {
            throw new UserCreditExchangeException(UserCreditExchangeException.CODE_NOT_BIND_ALIPAY_ACCOUNT, "用户未绑定支付宝账户");
        }
 
        CreditExchangeRecord exchangeRecord = new CreditExchangeRecord();
 
        if (exchangeType == CreditExchangeRecord.ExchangeType.FUND_EXCHANGE) {
            // 计算可兑换金额(如果是红包兑换)
            BigDecimal exchangeAmount = calculateExchangeAmount(request.getUid(), request.getConsumedCredits(), true);
            exchangeRecord.setExchangeValue(exchangeAmount);
        }
 
        // 记录兑换记录
        exchangeRecord.setUid(userId);
        exchangeRecord.setExchangeType(exchangeType);
        exchangeRecord.setConsumedCredits(request.getConsumedCredits());
        exchangeRecord.setCreditBalance(balance.getCreditBalance() - request.getConsumedCredits());
        exchangeRecord.setExchangeStatus(CreditExchangeRecord.STATUS_NOT_VERIFY);
        exchangeRecord.setExchangeStatusDescription("未审核");
        exchangeRecord.setExchangeInfo1(alipayBindings.get(0).getAlipayName()); // 设置支付宝账户
        exchangeRecord.setExchangeInfo2(alipayBindings.get(0).getAlipayAccount());
        exchangeRecord.setCreateTime(new Date());
        exchangeRecord.setUpdateTime(new Date());
        userCreditExchangeRecordService.addExchangeRecord(exchangeRecord);
 
        // 扣减用户积分
        userCreditManager.decreaseCredit(UserCreditRecord.builder()
                .creditAmount(request.getConsumedCredits())
                .consumptionMethod(UserCreditRecord.ConsumptionMethod.EXCHANGE_RED_PACKET)
                .direction(UserCreditRecord.DIRECTION_CONSUME)
                .identifierId(exchangeRecord.getId() + "")
                .uid(exchangeRecord.getUid())
                .description("红包兑换")
                .build());
        return exchangeRecord.getId();
    }
 
    /**
     * 通过兑换
     *
     * @param exchangeRecordId 兑换记录ID
     */
    @Transactional(rollbackFor = Exception.class)
    public void approveExchange(Long exchangeRecordId) throws UserCreditExchangeException {
        CreditExchangeRecord exchangeRecord = userCreditExchangeRecordService.getExchangeRecordByIdForUpdate(exchangeRecordId);
        if (exchangeRecord == null) {
            throw new UserCreditExchangeException(UserCreditExchangeException.CODE_NOT_BIND_ALIPAY_ACCOUNT, "兑换记录不存在");
        }
 
        if (exchangeRecord.getExchangeStatus() != CreditExchangeRecord.STATUS_NOT_VERIFY) {
            throw new UserCreditExchangeException(UserCreditExchangeException.CODE_COMMON, "兑换已处理");
        }
 
 
        // 如果是红包兑换,调用通过兑换逻辑(TODO)
        if (exchangeRecord.getExchangeType() == CreditExchangeRecord.ExchangeType.FUND_EXCHANGE) {
            try {
                AlipayUtil.transfer("credit_exchange_" + exchangeRecordId, exchangeRecord.getExchangeInfo2(), exchangeRecord.getExchangeInfo1(), exchangeRecord.getExchangeValue(), "红包兑换", "红包兑换");
            } catch (AlipayApiException e) {
                throw new UserCreditExchangeException(UserCreditExchangeException.CODE_ALIPAY_TRANSFER_FAILED, e.getErrCode() + ":" + e.getErrMsg());
            } catch (AlipayUtil.AlipayTransferException e) {
                throw new UserCreditExchangeException(UserCreditExchangeException.CODE_ALIPAY_TRANSFER_FAILED, e.getMessage());
            }
        }
 
        // 改变兑换记录状态
        userCreditExchangeRecordService.updateExchangeRecord(CreditExchangeRecord.builder()
                .id(exchangeRecordId)
                .exchangeStatus(CreditExchangeRecord.STATUS_PASSED)
                .exchangeStatusDescription("兑换已通过")
                .updateTime(new Date())
                .build());
 
    }
 
    /**
     * 驳回兑换
     *
     * @param exchangeRecordId 兑换记录ID
     */
    @Transactional(rollbackFor = Exception.class)
    public void rejectExchange(Long exchangeRecordId) throws UserCreditExchangeException {
        CreditExchangeRecord exchangeRecord = userCreditExchangeRecordService.getExchangeRecordByIdForUpdate(exchangeRecordId);
        if (exchangeRecord == null) {
            throw new UserCreditExchangeException(UserCreditExchangeException.CODE_NOT_BIND_ALIPAY_ACCOUNT, "兑换记录不存在");
        }
 
        if (exchangeRecord.getExchangeStatus() != CreditExchangeRecord.STATUS_NOT_VERIFY) {
            throw new UserCreditExchangeException(UserCreditExchangeException.CODE_COMMON, "兑换已处理");
        }
 
 
        // 退回用户积分余额
        userCreditBalanceService.increaseCreditBalance(exchangeRecord.getUid(), exchangeRecord.getConsumedCredits());
        // 添加积分记录
        userCreditRecordService.addCreditRecord(UserCreditRecord.builder()
                .uid(exchangeRecord.getUid())
                .creditAmount(exchangeRecord.getConsumedCredits())
                .direction(UserCreditRecord.DIRECTION_GAIN)
                .identifierId(exchangeRecord.getId().toString())
                .acquisitionMethod(UserCreditRecord.AcquisitionMethod.EXCHANGE_RETURN)
                .description("兑换退回")
                .createTime(new Date())
                .updateTime(new Date()).build());
        userCreditExchangeRecordService.updateExchangeRecord(CreditExchangeRecord.builder()
                .id(exchangeRecordId)
                .exchangeStatus(CreditExchangeRecord.STATUS_REJECT)
                .exchangeStatusDescription("兑换已驳回")
                .updateTime(new Date())
                .build());
    }
 
    /**
     * 检查红包兑换频率
     *
     * @param userId 用户ID
     */
    private void checkRedPacketExchangeFrequency(Long userId) throws UserCreditExchangeException {
        //实现红包兑换频率检查逻辑
        // 获取今日兑换的次数
        long nowTimeStamp = System.currentTimeMillis();
        long count = userCreditExchangeRecordService.countExchangeRecords(CreditExchangeRecordMapper.DaoQuery.builder()
                .uid(userId)
                .minCreateTime(new Date(TimeUtil.convertToTimeTemp(TimeUtil.getGernalTime(nowTimeStamp, "yyyyMMdd"), "yyyyMMdd")))
                .maxCreateTime(new Date(nowTimeStamp))
                .build());
        CreditSetting setting = creditSettingService.getSettingCacheByType(CreditSetting.CreditSettingType.DAILY_EXCHANGE_LIMIT, new Date(TimeUtil.convertToTimeTemp(TimeUtil.getGernalTime(nowTimeStamp, "yyyyMMddHHmm"), "yyyyMMddHHmm")));
        if (setting == null) {
            throw new UserCreditExchangeException(UserCreditExchangeException.CODE_EXCHANGE_FREQUENCY_LIMIT, "兑换频率未设置");
        }
        if (count >= Integer.parseInt(setting.getValue())) {
            throw new UserCreditExchangeException(UserCreditExchangeException.CODE_EXCHANGE_FREQUENCY_LIMIT, String.format("每天只能兑换%s次", setting.getValue()));
        }
    }
 
    /**
     * 计算兑换金额
     *
     * @param uid
     * @param credit
     * @return
     */
    public BigDecimal calculateExchangeAmount(Long uid, int credit, boolean forExchange) throws UserCreditExchangeException {
        long count = userCreditExchangeRecordService.countExchangeRecords(CreditExchangeRecordMapper.DaoQuery.builder()
                .uid(uid).build());
        Date nowDate = new Date(TimeUtil.convertToTimeTemp(TimeUtil.getGernalTime(System.currentTimeMillis(), "yyyyMMddHHmm"), "yyyyMMddHHmm"));
 
        BigDecimal money = null;
        if (count <= 0) {
            // 新人兑换
            List<ExchangeRate> rates = exchangeRateService.listExchangeRates(ExchangeRateMapper.DaoQuery.builder()
                    .exchangeType(ExchangeRate.ExchangeRateType.NEW_USER_EXCHANGE)
                    .maxStartTime(nowDate)
                    .minEndTime(nowDate)
                    .count(Integer.MAX_VALUE)
                    .build());
            if (rates.isEmpty()) {
                throw new UserCreditExchangeException(UserCreditExchangeException.CODE_COMMON, "新人兑换汇率未设置");
            }
            money = new BigDecimal(credit).multiply(rates.get(0).getRate()).setScale(2, RoundingMode.HALF_UP);
        } else {
            // 老用户兑换
            List<ExchangeRate> rates = exchangeRateService.listExchangeRates(ExchangeRateMapper.DaoQuery.builder()
                    .exchangeType(ExchangeRate.ExchangeRateType.GENERAL_EXCHANGE)
                    .maxStartTime(nowDate)
                    .minEndTime(nowDate)
                    .count(Integer.MAX_VALUE)
                    .build());
            if (rates.isEmpty()) {
                throw new UserCreditExchangeException(UserCreditExchangeException.CODE_COMMON, "老用户兑换汇率未设置");
            }
            money = new BigDecimal(credit).multiply(rates.get(0).getRate()).setScale(2, RoundingMode.HALF_UP);
        }
        if (forExchange) {
            CreditSetting setting = creditSettingService.getSettingCacheByType(CreditSetting.CreditSettingType.MINIMUM_EXCHANGE_AMOUNT, nowDate);
            if (setting != null && new BigDecimal(setting.getValue()).compareTo(money) > 0) {
                throw new UserCreditExchangeException(UserCreditExchangeException.CODE_COMMON, String.format("兑换金额不能低于%s元", setting.getValue()));
            }
        }
        return money;
    }
}