VirtualWithdrawal.java 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. package com.ydtech.modules.ttqf.xxx;
  2. import cn.hutool.core.collection.CollectionUtil;
  3. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  4. import com.ydtech.core.page.HttpResult;
  5. import com.ydtech.modules.admin.model.po.SysUserBankCard;
  6. import com.ydtech.modules.admin.service.SysUserBankCardService;
  7. import com.ydtech.modules.ttqf.dao.PartTtqfRecordMapper;
  8. import com.ydtech.modules.ttqf.entity.PartTtqfRecord;
  9. import com.ydtech.modules.ttqf.entity.vo.UserWithdrawal;
  10. import com.ydtech.modules.ttqf.service.TtqfService;
  11. import com.ydtech.utils.StringUtils;
  12. import org.slf4j.Logger;
  13. import org.slf4j.LoggerFactory;
  14. import org.springframework.beans.factory.annotation.Autowired;
  15. import org.springframework.data.redis.core.RedisTemplate;
  16. import org.springframework.scheduling.annotation.Async;
  17. import org.springframework.stereotype.Component;
  18. import java.math.BigDecimal;
  19. import java.util.ArrayList;
  20. import java.util.Date;
  21. import java.util.List;
  22. import java.util.Objects;
  23. @Component
  24. public class VirtualWithdrawal {
  25. private static final Logger log = LoggerFactory.getLogger(VirtualWithdrawal.class);
  26. private static final BigDecimal MIN_WITHDRAWAL_AMOUNT = new BigDecimal("40000");
  27. private static final BigDecimal COMMISSION = new BigDecimal("0.075");
  28. @Autowired
  29. private SysUserBankCardService sysUserBankCardService;
  30. @Autowired
  31. private TtqfService ttqfService;
  32. @Autowired
  33. private RedisTemplate<String, String> redisTemplate;
  34. @Autowired
  35. private PartTtqfRecordMapper partTtqfRecordMapper;
  36. @Autowired
  37. private RoundRobinService roundRobinService;
  38. @Autowired
  39. private InitializeInternalWithdrawalId initializeInternalWithdrawalId;
  40. // 虚拟提现
  41. @Async
  42. public void virtualWithdrawal(String userId, BigDecimal amount) {
  43. PartTtqfRecord record = new PartTtqfRecord();
  44. record.setCreateTime(new Date());
  45. try {
  46. initializeInternalWithdrawalId.initialize();
  47. List<String> list = new ArrayList<>();
  48. List<String> redisList = redisTemplate.opsForList().range(RoundRobinService.LIST_KEY, 0, -1);
  49. if (CollectionUtil.isEmpty(redisList)) {
  50. redisList = new ArrayList<>(0);
  51. }
  52. String virtualUserId = getVirtualUserId(amount, list, redisList);
  53. record.setVirtualUserId(virtualUserId);
  54. String bankNumber = "";
  55. if (StringUtils.isNotEmpty(virtualUserId)) {
  56. LambdaQueryWrapper<SysUserBankCard> queryWrapper = new LambdaQueryWrapper<>();
  57. queryWrapper.eq(SysUserBankCard::getUserId, virtualUserId);
  58. queryWrapper.eq(SysUserBankCard::getIsDefault, 1);
  59. queryWrapper.orderByDesc(SysUserBankCard::getCreateTime);
  60. queryWrapper.last("limit 1");
  61. SysUserBankCard one = sysUserBankCardService.getOne(queryWrapper);
  62. if (Objects.isNull(one)) {
  63. record.setMessage("请先绑定银行卡");
  64. } else {
  65. bankNumber = one.getBankNumber();
  66. }
  67. }
  68. record.setUserId(userId);
  69. record.setBankCard(bankNumber);
  70. record.setFeeAmount(BigDecimal.ZERO);
  71. record.setAmount(amount);
  72. if (StringUtils.isNotEmpty(virtualUserId) && StringUtils.isNotEmpty(bankNumber)) {
  73. UserWithdrawal withdrawal = new UserWithdrawal();
  74. withdrawal.setUserId(virtualUserId);
  75. withdrawal.setAmount(amount);
  76. withdrawal.setBankNumber(bankNumber);
  77. HttpResult httpResult = ttqfService.userCashOut(withdrawal);
  78. if (httpResult.getCode() == 200) {
  79. String value = String.valueOf(httpResult.getData());
  80. if (StringUtils.equals("true", value)){
  81. record.setIsStatus(1);
  82. }else {
  83. record.setMessage("虚拟用户提现失败");
  84. }
  85. } else {
  86. record.setMessage(httpResult.getMsg());
  87. }
  88. } else {
  89. record.setMessage("虚拟用户userId=" + virtualUserId + ",银行卡号=" + bankNumber);
  90. }
  91. } catch (Exception e) {
  92. log.error("虚拟提现发生异常", e);
  93. record.setMessage(e.getMessage());
  94. } finally {
  95. partTtqfRecordMapper.insert(record);
  96. }
  97. }
  98. public String getVirtualUserId(BigDecimal amount, List<String> list, List<String> redisList) {
  99. int attemptCount = 0;
  100. final int maxAttempts = redisList.size() * 2;
  101. while (attemptCount++ < maxAttempts) {
  102. String virtualUserId = roundRobinService.getNextWithLua();
  103. list.add(virtualUserId);
  104. if (!verifyWithdrawalAmount(virtualUserId, amount)) {
  105. return virtualUserId;
  106. }
  107. if (list.size() >= redisList.size()) {
  108. break;
  109. }
  110. }
  111. return null;
  112. }
  113. public boolean verifyWithdrawalAmount(String userId, BigDecimal amount) {
  114. BigDecimal balance = partTtqfRecordMapper.verifyWithdrawalAmount(userId);
  115. if (balance == null) {
  116. return false;
  117. }
  118. BigDecimal totalNeed = amount.multiply(BigDecimal.ONE.add(COMMISSION));
  119. return totalNeed.compareTo(MIN_WITHDRAWAL_AMOUNT.subtract(balance)) > 0;
  120. }
  121. }