|
@@ -2,23 +2,25 @@ package com.citu.module.pay.service.currency;
|
|
|
|
|
|
import cn.hutool.core.lang.Assert;
|
|
|
import com.citu.framework.common.pojo.PageResult;
|
|
|
+import com.citu.framework.common.util.date.DateUtils;
|
|
|
import com.citu.module.pay.controller.admin.currency.vo.currency.PayCurrencyPageReqVO;
|
|
|
import com.citu.module.pay.dal.dataobject.currency.PayCurrencyDO;
|
|
|
import com.citu.module.pay.dal.dataobject.currency.PayCurrencyTransactionDO;
|
|
|
import com.citu.module.pay.dal.dataobject.order.PayOrderExtensionDO;
|
|
|
import com.citu.module.pay.dal.dataobject.refund.PayRefundDO;
|
|
|
import com.citu.module.pay.dal.mysql.currency.PayCurrencyMapper;
|
|
|
+import com.citu.module.pay.dal.redis.currency.PayCurrencyLockRedisDAO;
|
|
|
import com.citu.module.pay.enums.currency.PayCurrencyBizTypeEnum;
|
|
|
import com.citu.module.pay.service.currency.bo.CurrencyTransactionCreateReqBO;
|
|
|
import com.citu.module.pay.service.order.PayOrderService;
|
|
|
import com.citu.module.pay.service.refund.PayRefundService;
|
|
|
+import lombok.SneakyThrows;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.context.annotation.Lazy;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
-import java.time.LocalDateTime;
|
|
|
|
|
|
import static com.citu.framework.common.exception.util.ServiceExceptionUtil.exception;
|
|
|
import static com.citu.module.pay.enums.ErrorCodeConstants.*;
|
|
@@ -33,9 +35,14 @@ import static com.citu.module.pay.enums.currency.PayCurrencyBizTypeEnum.PAYMENT_
|
|
|
@Service
|
|
|
@Slf4j
|
|
|
public class PayCurrencyServiceImpl implements PayCurrencyService {
|
|
|
-
|
|
|
+ /**
|
|
|
+ * 通知超时时间,单位:毫秒
|
|
|
+ */
|
|
|
+ public static final long UPDATE_TIMEOUT_MILLIS = 120 * DateUtils.SECOND_MILLIS;
|
|
|
@Resource
|
|
|
private PayCurrencyMapper currencyMapper;
|
|
|
+ @Resource
|
|
|
+ private PayCurrencyLockRedisDAO lockRedisDAO;
|
|
|
|
|
|
@Resource
|
|
|
@Lazy // 延迟加载,避免循环依赖
|
|
@@ -120,6 +127,8 @@ public class PayCurrencyServiceImpl implements PayCurrencyService {
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ @SneakyThrows
|
|
|
public PayCurrencyTransactionDO reduceCurrencyBalance(Long currencyId, Long bizId,
|
|
|
PayCurrencyBizTypeEnum bizType, Long price) {
|
|
|
// 1. 获取货币账户
|
|
@@ -128,32 +137,36 @@ public class PayCurrencyServiceImpl implements PayCurrencyService {
|
|
|
log.error("[reduceCurrencyBalance],用户货币账户({})不存在.", currencyId);
|
|
|
throw exception(WALLET_NOT_FOUND);
|
|
|
}
|
|
|
-
|
|
|
- // 2.1 扣除余额
|
|
|
- int updateCounts;
|
|
|
- switch (bizType) {
|
|
|
- case PAYMENT: {
|
|
|
- updateCounts = currencyMapper.updateWhenConsumption(payCurrency.getId(), price);
|
|
|
- break;
|
|
|
+ // 2. 加锁,更新钱包余额(目的:避免钱包流水的并发更新时,余额变化不连贯)
|
|
|
+ return lockRedisDAO.lock(currencyId, UPDATE_TIMEOUT_MILLIS, () -> {
|
|
|
+ // 扣除余额
|
|
|
+ int updateCounts;
|
|
|
+ switch (bizType) {
|
|
|
+ case PAYMENT: {
|
|
|
+ updateCounts = currencyMapper.updateWhenConsumption(payCurrency.getId(), price);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case RECHARGE_REFUND: {
|
|
|
+ updateCounts = currencyMapper.updateWhenRechargeRefund(payCurrency.getId(), price);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ default: {
|
|
|
+ // TODO 其它类型待实现
|
|
|
+ throw new UnsupportedOperationException("待实现");
|
|
|
+ }
|
|
|
}
|
|
|
- case RECHARGE_REFUND: {
|
|
|
- updateCounts = currencyMapper.updateWhenRechargeRefund(payCurrency.getId(), price);
|
|
|
- break;
|
|
|
+ if (updateCounts == 0) {
|
|
|
+ throw exception(WALLET_BALANCE_NOT_ENOUGH);
|
|
|
}
|
|
|
- default: {
|
|
|
- // TODO 其它类型待实现
|
|
|
- throw new UnsupportedOperationException("待实现");
|
|
|
- }
|
|
|
- }
|
|
|
- if (updateCounts == 0) {
|
|
|
- throw exception(WALLET_BALANCE_NOT_ENOUGH);
|
|
|
- }
|
|
|
- // 2.2 生成货币账户流水
|
|
|
- Long afterBalance = payCurrency.getBalance() - price;
|
|
|
- CurrencyTransactionCreateReqBO bo = new CurrencyTransactionCreateReqBO().setCurrencyId(payCurrency.getId())
|
|
|
- .setPrice(-price).setBalance(afterBalance).setBizId(String.valueOf(bizId))
|
|
|
- .setBizType(bizType.getType()).setTitle(bizType.getDescription());
|
|
|
- return currencyTransactionService.createCurrencyTransaction(bo);
|
|
|
+ // 2.2 生成货币账户流水
|
|
|
+ // TODO 加上payCurrency.getFreezePrice()冻结金额是因为创建退款单的时候就已经冻结的;
|
|
|
+ // 并且扣了payCurrency.getBalance(),如果这个时候不加则会导致扣除两笔钱的流水记录(但实际扣了一笔钱)
|
|
|
+ Long afterBalance = (payCurrency.getBalance() + payCurrency.getFreezePrice()) - price;
|
|
|
+ CurrencyTransactionCreateReqBO bo = new CurrencyTransactionCreateReqBO().setCurrencyId(payCurrency.getId())
|
|
|
+ .setPrice(-price).setBalance(afterBalance).setBizId(String.valueOf(bizId))
|
|
|
+ .setBizType(bizType.getType()).setTitle(bizType.getDescription());
|
|
|
+ return currencyTransactionService.createCurrencyTransaction(bo);
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
@Override
|