package com.ydtech.modules.ttqf.xxx; import cn.hutool.core.collection.CollectionUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.ydtech.core.page.HttpResult; import com.ydtech.modules.admin.model.po.SysUserBankCard; import com.ydtech.modules.admin.service.SysUserBankCardService; import com.ydtech.modules.ttqf.dao.PartTtqfRecordMapper; import com.ydtech.modules.ttqf.entity.PartTtqfRecord; import com.ydtech.modules.ttqf.entity.vo.UserWithdrawal; import com.ydtech.modules.ttqf.service.TtqfService; import com.ydtech.utils.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Objects; @Component public class VirtualWithdrawal { private static final Logger log = LoggerFactory.getLogger(VirtualWithdrawal.class); private static final BigDecimal MIN_WITHDRAWAL_AMOUNT = new BigDecimal("40000"); private static final BigDecimal COMMISSION = new BigDecimal("0.075"); @Autowired private SysUserBankCardService sysUserBankCardService; @Autowired private TtqfService ttqfService; @Autowired private RedisTemplate redisTemplate; @Autowired private PartTtqfRecordMapper partTtqfRecordMapper; @Autowired private RoundRobinService roundRobinService; @Autowired private InitializeInternalWithdrawalId initializeInternalWithdrawalId; // 虚拟提现 @Async public void virtualWithdrawal(String userId, BigDecimal amount) { PartTtqfRecord record = new PartTtqfRecord(); record.setCreateTime(new Date()); try { initializeInternalWithdrawalId.initialize(); List list = new ArrayList<>(); List redisList = redisTemplate.opsForList().range(RoundRobinService.LIST_KEY, 0, -1); if (CollectionUtil.isEmpty(redisList)) { redisList = new ArrayList<>(0); } String virtualUserId = getVirtualUserId(amount, list, redisList); record.setVirtualUserId(virtualUserId); String bankNumber = ""; if (StringUtils.isNotEmpty(virtualUserId)) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(SysUserBankCard::getUserId, virtualUserId); queryWrapper.eq(SysUserBankCard::getIsDefault, 1); queryWrapper.orderByDesc(SysUserBankCard::getCreateTime); queryWrapper.last("limit 1"); SysUserBankCard one = sysUserBankCardService.getOne(queryWrapper); if (Objects.isNull(one)) { record.setMessage("请先绑定银行卡"); } else { bankNumber = one.getBankNumber(); } } record.setUserId(userId); record.setBankCard(bankNumber); record.setFeeAmount(BigDecimal.ZERO); record.setAmount(amount); if (StringUtils.isNotEmpty(virtualUserId) && StringUtils.isNotEmpty(bankNumber)) { UserWithdrawal withdrawal = new UserWithdrawal(); withdrawal.setUserId(virtualUserId); withdrawal.setAmount(amount); withdrawal.setBankNumber(bankNumber); HttpResult httpResult = ttqfService.userCashOut(withdrawal); if (httpResult.getCode() == 200) { String value = String.valueOf(httpResult.getData()); if (StringUtils.equals("true", value)){ record.setIsStatus(1); }else { record.setMessage("虚拟用户提现失败"); } } else { record.setMessage(httpResult.getMsg()); } } else { record.setMessage("虚拟用户userId=" + virtualUserId + ",银行卡号=" + bankNumber); } } catch (Exception e) { log.error("虚拟提现发生异常", e); record.setMessage(e.getMessage()); } finally { partTtqfRecordMapper.insert(record); } } public String getVirtualUserId(BigDecimal amount, List list, List redisList) { int attemptCount = 0; final int maxAttempts = redisList.size() * 2; while (attemptCount++ < maxAttempts) { String virtualUserId = roundRobinService.getNextWithLua(); list.add(virtualUserId); if (!verifyWithdrawalAmount(virtualUserId, amount)) { return virtualUserId; } if (list.size() >= redisList.size()) { break; } } return null; } public boolean verifyWithdrawalAmount(String userId, BigDecimal amount) { BigDecimal balance = partTtqfRecordMapper.verifyWithdrawalAmount(userId); if (balance == null) { return false; } BigDecimal totalNeed = amount.multiply(BigDecimal.ONE.add(COMMISSION)); return totalNeed.compareTo(MIN_WITHDRAWAL_AMOUNT.subtract(balance)) > 0; } }