VirtualWithdrawal.java 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  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. SysUserBankCard one = sysUserBankCardService.getOne(queryWrapper);
  60. if (Objects.isNull(one)) {
  61. record.setMessage("请先绑定银行卡");
  62. } else {
  63. bankNumber = one.getBankNumber();
  64. }
  65. }
  66. record.setUserId(userId);
  67. record.setBankCard(bankNumber);
  68. record.setFeeAmount(BigDecimal.ZERO);
  69. record.setAmount(amount);
  70. if (StringUtils.isNotEmpty(virtualUserId) && StringUtils.isNotEmpty(bankNumber)) {
  71. UserWithdrawal withdrawal = new UserWithdrawal();
  72. withdrawal.setUserId(virtualUserId);
  73. withdrawal.setAmount(amount);
  74. withdrawal.setBankNumber(bankNumber);
  75. HttpResult httpResult = ttqfService.userCashOut(withdrawal);
  76. if (httpResult.getCode() == 200) {
  77. record.setIsStatus(1);
  78. } else {
  79. record.setMessage(httpResult.getMsg());
  80. }
  81. } else {
  82. record.setMessage("虚拟用户userId=" + virtualUserId + ",银行卡号=" + bankNumber);
  83. }
  84. } catch (Exception e) {
  85. log.error("虚拟提现发生异常", e);
  86. record.setMessage(e.getMessage());
  87. } finally {
  88. partTtqfRecordMapper.insert(record);
  89. }
  90. }
  91. public String getVirtualUserId(BigDecimal amount, List<String> list, List<String> redisList) {
  92. int attemptCount = 0;
  93. final int maxAttempts = redisList.size() * 2;
  94. while (attemptCount++ < maxAttempts) {
  95. String virtualUserId = roundRobinService.getNextWithLua();
  96. list.add(virtualUserId);
  97. if (!verifyWithdrawalAmount(virtualUserId, amount)) {
  98. return virtualUserId;
  99. }
  100. if (list.size() >= redisList.size()) {
  101. break;
  102. }
  103. }
  104. return null;
  105. }
  106. public boolean verifyWithdrawalAmount(String userId, BigDecimal amount) {
  107. BigDecimal balance = partTtqfRecordMapper.verifyWithdrawalAmount(userId);
  108. if (balance == null) {
  109. return false;
  110. }
  111. BigDecimal totalNeed = amount.multiply(BigDecimal.ONE.add(COMMISSION));
  112. return totalNeed.compareTo(MIN_WITHDRAWAL_AMOUNT.subtract(balance)) > 0;
  113. }
  114. }