|
@@ -2,12 +2,14 @@ package com.yonge.cooleshow.biz.dal.service.impl;
|
|
|
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
import com.yonge.cooleshow.biz.dal.dto.UserAccountRecordDto;
|
|
|
import com.yonge.cooleshow.biz.dal.dto.req.TotalReq;
|
|
|
import com.yonge.cooleshow.biz.dal.entity.UserAccountRecord;
|
|
|
import com.yonge.cooleshow.biz.dal.entity.UserOrder;
|
|
|
+import com.yonge.cooleshow.biz.dal.enums.AccountBizTypeEnum;
|
|
|
import com.yonge.cooleshow.biz.dal.enums.InOrOutEnum;
|
|
|
import com.yonge.cooleshow.biz.dal.service.UserOrderService;
|
|
|
import com.yonge.cooleshow.biz.dal.vo.UserAccountRecordVo;
|
|
@@ -20,10 +22,12 @@ import com.yonge.cooleshow.common.entity.HttpResponseResult;
|
|
|
import com.yonge.cooleshow.common.enums.PostStatusEnum;
|
|
|
import com.yonge.toolset.base.exception.BizException;
|
|
|
import com.yonge.toolset.payment.util.DistributedLock;
|
|
|
+import com.yonge.toolset.utils.collection.ListUtil;
|
|
|
import org.redisson.api.RLock;
|
|
|
import org.redisson.api.RedissonClient;
|
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.beans.BeanUtils;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import com.yonge.cooleshow.biz.dal.entity.UserAccount;
|
|
@@ -35,10 +39,9 @@ import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
import java.math.BigDecimal;
|
|
|
import java.math.RoundingMode;
|
|
|
-import java.util.Date;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Objects;
|
|
|
+import java.util.*;
|
|
|
import java.util.concurrent.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
@Service
|
|
@@ -67,66 +70,133 @@ public class UserAccountServiceImpl extends ServiceImpl<UserAccountDao, UserAcco
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public HttpResponseResult<UserAccountRecord> accountRecord(UserAccountRecordDto accountRecordDto) {
|
|
|
- if (null == accountRecordDto.getInOrOut()
|
|
|
- || null == accountRecordDto.getPostStatus()
|
|
|
- || (!PostStatusEnum.WAIT.equals(accountRecordDto.getPostStatus()) && !PostStatusEnum.FROZEN.equals(accountRecordDto.getPostStatus()))
|
|
|
- ) {
|
|
|
- throw new BizException("记录入账-入账状态异常: param is {}", JSONObject.toJSONString(accountRecordDto));
|
|
|
- }
|
|
|
+ public HttpResponseResult accountRecord(UserAccountRecordDto accountRecordDto) {
|
|
|
+ return accountRecord(Arrays.asList(accountRecordDto));
|
|
|
+ }
|
|
|
|
|
|
- if (null == accountRecordDto.getTransAmount() || null == accountRecordDto.getBizId()
|
|
|
- || null == accountRecordDto.getBizType()) {
|
|
|
- throw new BizException("记录入账-缺少入账参数: param is {}", JSONObject.toJSONString(accountRecordDto));
|
|
|
+ @Override
|
|
|
+ public HttpResponseResult accountRecord(List<UserAccountRecordDto> accountRecordDtos) {
|
|
|
+ if (CollectionUtils.isEmpty(accountRecordDtos)) {
|
|
|
+ return HttpResponseResult.succeed();
|
|
|
}
|
|
|
- if (BigDecimal.ZERO.compareTo(accountRecordDto.getTransAmount()) < 0) {
|
|
|
- throw new BizException("记录入账-变动金额不能为负数: param is {}", JSONObject.toJSONString(accountRecordDto));
|
|
|
+
|
|
|
+ for (UserAccountRecordDto accountRecordDto : accountRecordDtos) {
|
|
|
+ if (null == accountRecordDto.getInOrOut()
|
|
|
+ || null == accountRecordDto.getPostStatus()
|
|
|
+ || (!PostStatusEnum.WAIT.equals(accountRecordDto.getPostStatus()) && !PostStatusEnum.FROZEN.equals(accountRecordDto.getPostStatus()))
|
|
|
+ ) {
|
|
|
+ throw new BizException("记录入账-入账状态异常: param is {}", JSONObject.toJSONString(accountRecordDto));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (null == accountRecordDto.getTransAmount() || null == accountRecordDto.getBizId()
|
|
|
+ || null == accountRecordDto.getBizType()) {
|
|
|
+ throw new BizException("记录入账-缺少入账参数: param is {}", JSONObject.toJSONString(accountRecordDto));
|
|
|
+ }
|
|
|
+ if (BigDecimal.ZERO.compareTo(accountRecordDto.getTransAmount()) < 0) {
|
|
|
+ throw new BizException("记录入账-变动金额不能为负数: param is {}", JSONObject.toJSONString(accountRecordDto));
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ Map<Long, List<UserAccountRecordDto>> accountMap = accountRecordDtos.stream().collect(Collectors.groupingBy(UserAccountRecordDto::getAccountId));
|
|
|
+ Set<Long> accountIds = accountMap.keySet();
|
|
|
|
|
|
- HttpResponseResult<UserAccountRecord> res = DistributedLock.of(redissonClient)
|
|
|
- .runIfLockToFunction(CacheNameEnum.LOCK_RECORD_ACCOUNT.getRedisKey(accountRecordDto.getAccountId())
|
|
|
- , this::doAccountRecord, accountRecordDto, 10L);
|
|
|
- if (null != res) {
|
|
|
- return res;
|
|
|
- } else {
|
|
|
- throw new BizException("记录入账-插入账户记录失败: param is {}", JSONObject.toJSONString(accountRecordDto));
|
|
|
+ for (Long accountId : accountIds) {
|
|
|
+ List<UserAccountRecordDto> userAccountRecordDtos = accountMap.get(accountId);
|
|
|
+ HttpResponseResult<UserAccountRecord> res = DistributedLock.of(redissonClient)
|
|
|
+ .runIfLockToFunction(CacheNameEnum.LOCK_RECORD_ACCOUNT.getRedisKey(accountId)
|
|
|
+ , this::doAccountRecords, userAccountRecordDtos, 10L);
|
|
|
+ if (null != res) {
|
|
|
+ return res;
|
|
|
+ } else {
|
|
|
+ throw new BizException("记录入账-插入账户记录失败: param is {}", JSONObject.toJSONString(userAccountRecordDtos));
|
|
|
+ }
|
|
|
}
|
|
|
+ return HttpResponseResult.succeed();
|
|
|
}
|
|
|
|
|
|
+
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
- HttpResponseResult<UserAccountRecord> doAccountRecord(UserAccountRecordDto accountRecordDto) {
|
|
|
-
|
|
|
- if (InOrOutEnum.IN.equals(accountRecordDto.getInOrOut())) {
|
|
|
- UserOrder userOrder = orderService.getOne(Wrappers.<UserOrder>lambdaQuery()
|
|
|
- .eq(UserOrder::getOrderNo, accountRecordDto.getOrderNo()));
|
|
|
- if (null == userOrder) {
|
|
|
- throw new BizException("记录入账-未找到入账对应订单信息: param is {}", JSONObject.toJSONString(accountRecordDto));
|
|
|
- }
|
|
|
-
|
|
|
- BigDecimal totalTransAmount = baseMapper.totalTransAmount(accountRecordDto);
|
|
|
- if (null == totalTransAmount) {
|
|
|
- totalTransAmount = BigDecimal.ZERO;
|
|
|
+ HttpResponseResult doAccountRecords(List<UserAccountRecordDto> accountRecordDtos) {
|
|
|
+ if (CollectionUtils.isEmpty(accountRecordDtos)) {
|
|
|
+ return HttpResponseResult.succeed();
|
|
|
+ }
|
|
|
+ Long accountId = accountRecordDtos.get(0).getAccountId();
|
|
|
+
|
|
|
+ List<UserAccountRecordDto> collectIn = accountRecordDtos.stream().filter(dto -> InOrOutEnum.IN.equals(dto.getInOrOut())).collect(Collectors.toList());
|
|
|
+
|
|
|
+ List<UserAccountRecordDto> collectOut = accountRecordDtos.stream().filter(dto -> InOrOutEnum.OUT.equals(dto.getInOrOut())).collect(Collectors.toList());
|
|
|
+
|
|
|
+
|
|
|
+ if (!CollectionUtils.isEmpty(collectIn)) {
|
|
|
+
|
|
|
+ Map<AccountBizTypeEnum, Map<String, List<UserAccountRecordDto>>> collectInMap = collectIn.stream().collect(
|
|
|
+ Collectors.groupingBy(UserAccountRecordDto::getBizType,
|
|
|
+ Collectors.groupingBy(UserAccountRecordDto::getOrderNo)
|
|
|
+ )
|
|
|
+ );
|
|
|
+
|
|
|
+ for (AccountBizTypeEnum bizType : collectInMap.keySet()) {
|
|
|
+ Map<String, List<UserAccountRecordDto>> collectBizTypeMap = collectInMap.get(bizType);
|
|
|
+ for (String orderNo : collectBizTypeMap.keySet()) {
|
|
|
+ List<UserAccountRecordDto> userAccountRecords = collectBizTypeMap.get(orderNo);
|
|
|
+
|
|
|
+ BigDecimal transAmount = BigDecimal.ZERO;
|
|
|
+
|
|
|
+ BigDecimal frozenTransAmount = BigDecimal.ZERO;
|
|
|
+
|
|
|
+ for (UserAccountRecordDto o : userAccountRecords) {
|
|
|
+ transAmount = transAmount.add(o.getTransAmount());
|
|
|
+ if (PostStatusEnum.FROZEN.equals(o.getPostStatus())) {
|
|
|
+ frozenTransAmount = frozenTransAmount.add(o.getTransAmount());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!checkInOrderAmount(bizType, orderNo, transAmount)) {
|
|
|
+ log.error("记录入账-订单入账金额异常: bizType is {} ,orderNo is {} , transAmount is {} ", bizType.getCode(), orderNo, transAmount);
|
|
|
+ throw new BizException("记录入账-订单入账金额有误");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (frozenTransAmount.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
+
|
|
|
+ baseMapper.frozenChangeAccount(accountId, frozenTransAmount, InOrOutEnum.IN.getCode());
|
|
|
+ }
|
|
|
+
|
|
|
+ List<UserAccountRecord> records = ListUtil.convertList(userAccountRecords, UserAccountRecord.class);
|
|
|
+ userAccountRecordService.saveBatch(records);
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
- if (null == userOrder || totalTransAmount.add(accountRecordDto.getTransAmount()).compareTo(userOrder.getActualPrice()) > 0) {
|
|
|
- log.error("记录入账-订单入账总金额大于购买金额: param is {}" + JSONObject.toJSONString(accountRecordDto));
|
|
|
- accountRecordDto.setErrFlag(1);
|
|
|
- accountRecordDto.setErrMsg("账户变更异常,订单入账总金额大于购买金额,订单号:" + accountRecordDto.getOrderNo());
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (!CollectionUtils.isEmpty(collectOut)) {
|
|
|
+
|
|
|
+ BigDecimal outTransAmount = BigDecimal.ZERO;
|
|
|
+
|
|
|
+ BigDecimal frozenTransAmount = BigDecimal.ZERO;
|
|
|
+
|
|
|
+ for (UserAccountRecordDto o : collectOut) {
|
|
|
+ outTransAmount = outTransAmount.add(o.getTransAmount());
|
|
|
+ if (PostStatusEnum.FROZEN.equals(o.getPostStatus())) {
|
|
|
+ frozenTransAmount = frozenTransAmount.add(o.getTransAmount());
|
|
|
+ }
|
|
|
}
|
|
|
- } else {
|
|
|
+
|
|
|
|
|
|
- UserAccountVo detail = baseMapper.detail(accountRecordDto.getAccountId());
|
|
|
- if (detail.getAmountUsable().compareTo(accountRecordDto.getTransAmount()) < 0) {
|
|
|
- throw new BizException("记录入账-账户余额不足: param is {}", JSONObject.toJSONString(accountRecordDto));
|
|
|
+ UserAccountVo detail = baseMapper.detail(accountId);
|
|
|
+
|
|
|
+ if (detail.getAmountUsable().compareTo(outTransAmount) < 0) {
|
|
|
+ log.error("记录入账-订单入账金额异常: param is {} ", JSONObject.toJSONString(collectOut));
|
|
|
+ throw new BizException("记录入账-账户余额不足");
|
|
|
}
|
|
|
+
|
|
|
+ if (frozenTransAmount.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
+
|
|
|
+ baseMapper.frozenChangeAccount(accountId, frozenTransAmount, InOrOutEnum.OUT.getCode());
|
|
|
+ }
|
|
|
+
|
|
|
+ List<UserAccountRecord> records = ListUtil.convertList(collectOut, UserAccountRecord.class);
|
|
|
+ userAccountRecordService.saveBatch(records);
|
|
|
}
|
|
|
-
|
|
|
- if (PostStatusEnum.FROZEN.equals(accountRecordDto.getPostStatus()) && accountRecordDto.getErrFlag() == 0) {
|
|
|
- baseMapper.frozenChangeAccount(accountRecordDto.getAccountId(), accountRecordDto.getTransAmount(), accountRecordDto.getInOrOut().getCode());
|
|
|
- }
|
|
|
-
|
|
|
- userAccountRecordService.save(accountRecordDto);
|
|
|
- return HttpResponseResult.succeed(accountRecordDto);
|
|
|
+ return HttpResponseResult.succeed();
|
|
|
}
|
|
|
|
|
|
@Override
|
|
@@ -154,6 +224,10 @@ public class UserAccountServiceImpl extends ServiceImpl<UserAccountDao, UserAcco
|
|
|
if (null == detail) {
|
|
|
throw new BizException("入账状态变更, 未找到记录信息: recordId is {} postStatus is {}", param.getId(), param.getPostStatus().getCode());
|
|
|
}
|
|
|
+ if (!PostStatusEnum.WAIT.equals(detail.getPostStatus())
|
|
|
+ && !PostStatusEnum.FROZEN.equals(detail.getPostStatus())) {
|
|
|
+ return HttpResponseResult.succeed();
|
|
|
+ }
|
|
|
detail.setPostStatus(param.getPostStatus());
|
|
|
|
|
|
if (PostStatusEnum.WAIT.equals(detail.getPostStatus())) {
|
|
@@ -279,5 +353,37 @@ public class UserAccountServiceImpl extends ServiceImpl<UserAccountDao, UserAcco
|
|
|
return HttpResponseResult.succeed(total);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ * 判断是否可以入账
|
|
|
+ *
|
|
|
+ * @param bizType 入账类型
|
|
|
+ * @param orderNo 该笔入账对应订单号
|
|
|
+ * @param transAmount 入账金额
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Boolean checkInOrderAmount(AccountBizTypeEnum bizType, String orderNo, BigDecimal transAmount) {
|
|
|
+ BigDecimal orderExpectPrice = BigDecimal.ZERO;
|
|
|
+ if (AccountBizTypeEnum.MALL_SHARE.equals(bizType)) {
|
|
|
+
|
|
|
+ } else {
|
|
|
+ UserOrder userOrder = orderService.getOne(Wrappers.<UserOrder>lambdaQuery()
|
|
|
+ .eq(UserOrder::getOrderNo, orderNo));
|
|
|
+ if (null == userOrder) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ orderExpectPrice = userOrder.getExpectPrice();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ BigDecimal totalTransAmount = baseMapper.totalTransAmountByOrderNo(orderNo);
|
|
|
+ if (null == totalTransAmount) {
|
|
|
+ totalTransAmount = BigDecimal.ZERO;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (totalTransAmount.add(transAmount).compareTo(orderExpectPrice) > 0) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
|
|
|
}
|