package com.izouma.nineth.service; import cn.hutool.core.util.ZipUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.fastjson.JSONObject; import com.izouma.nineth.annotations.RedisLock; import com.izouma.nineth.domain.*; import com.izouma.nineth.domain.nftdomain.DomainAsk; import com.izouma.nineth.dto.SandPaySettle; import com.izouma.nineth.dto.UserBankCard; import com.izouma.nineth.dto.UserWithdraw; import com.izouma.nineth.enums.*; import com.izouma.nineth.exception.BusinessException; import com.izouma.nineth.repo.*; import com.izouma.nineth.service.storage.StorageService; import com.izouma.nineth.utils.DateTimeUtils; import com.izouma.nineth.utils.SnowflakeIdWorker; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.WorkbookFactory; import org.apache.poi.util.TempFile; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.core.env.Environment; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import javax.transaction.Transactional; import java.io.*; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.concurrent.ExecutionException; import java.util.concurrent.ForkJoinPool; import java.util.regex.Pattern; import java.util.stream.Collectors; @Service @Slf4j public class UserBalanceService { @Autowired private UserBalanceRepo userBalanceRepo; @Autowired private BalanceRecordRepo balanceRecordRepo; @Autowired private OrderRepo orderRepo; @Autowired private AssetRepo assetRepo; @Autowired private UserBankCardRepo userBankCardRepo; @Autowired private SettleRecordRepo settleRecordRepo; @Autowired private StorageService storageService; @Autowired private ExportWithdrawRepo exportWithdrawRepo; @Autowired private AutoWithdrawRecordRepo autoWithdrawRecordRepo; @Autowired private SnowflakeIdWorker snowflakeIdWorker; @Autowired private SandPayService sandPayService; @Autowired private RedisTemplate redisTemplate; @Autowired private RechargeOrderRepo rechargeOrderRepo; @Autowired private SysConfigService sysConfigService; @Autowired private Environment env; @Lazy @Autowired private AirDropService airDropService; @Autowired private UserRepo userRepo; public void settle(LocalDate start, LocalDate end) { for (long i = 0; i <= ChronoUnit.DAYS.between(start, end); i++) { LocalDate date = start.plusDays(i); if (settleRecordRepo.findByDate(date).isPresent()) { throw new BusinessException(DateTimeUtils.format(date, "yyyy-MM-dd") + "已经结算过"); } } for (long i = 0; i <= ChronoUnit.DAYS.between(start, end); i++) { LocalDate date = start.plusDays(i); settle(date); } } public void settle(LocalDate date) { if (settleRecordRepo.findByDate(date).isPresent()) { throw new BusinessException(DateTimeUtils.format(date, "yyyy-MM-dd") + "已经结算过"); } List orders = orderRepo.findByCreatedAtBetweenAndSourceAndStatusIn(date.atStartOfDay(), date.atTime(23, 59, 59, 9999), CollectionSource.TRANSFER, Arrays.asList(OrderStatus.PROCESSING, OrderStatus.FINISH)); List assets = assetRepo.findAllById(orders.stream().map(Order::getAssetId).collect(Collectors.toSet())); BigDecimal totalAmount = BigDecimal.ZERO; BigDecimal royaltiesAmount = BigDecimal.ZERO; BigDecimal serviceChargeAmount = BigDecimal.ZERO; List balanceList = new ArrayList<>(); List recordList = new ArrayList<>(); int c = 0; for (Order order : orders) { log.info("结算订单 {}/{}, orderId={}", ++c, orders.size(), order.getId()); BalanceRecord record = balanceRecordRepo.findByOrderIdAndType(order.getId(), BalanceType.SELL); if (record != null) { continue; } Asset asset = assets.stream().filter(i -> i.getId().equals(order.getAssetId())) .findFirst() .orElseThrow(new BusinessException("藏品不存在")); UserBalance userBalance = balanceList.stream().filter(b -> b.getUserId().equals(asset.getUserId())) .findFirst().orElse(null); if (userBalance == null) { userBalance = userBalanceRepo.findById(asset.getUserId()) .orElse(new UserBalance(asset .getUserId(), BigDecimal.ZERO, BigDecimal.ZERO, false, null, null)); balanceList.add(userBalance); } BigDecimal amount = order.getTotalPrice() .subtract(order.getGasPrice()) .multiply(BigDecimal .valueOf(100 - order.getRoyalties() - order.getServiceCharge())) .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP); totalAmount = totalAmount.add(order.getTotalPrice()); royaltiesAmount = royaltiesAmount.add(order.getTotalPrice() .subtract(order.getGasPrice()) .multiply(BigDecimal.valueOf(order.getRoyalties())) .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP)); serviceChargeAmount = serviceChargeAmount.add(order.getTotalPrice() .subtract(order.getGasPrice()) .multiply(BigDecimal.valueOf(order.getServiceCharge())) .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP)); userBalance.setLastBalance(userBalance.getBalance()); userBalance.setBalance(userBalance.getBalance().add(amount)); recordList.add(BalanceRecord.builder() .time(LocalDateTime.now()) .userId(asset.getUserId()) .orderId(order.getId()) .amount(amount) .balance(userBalance.getBalance()) .lastBalance(userBalance.getLastBalance()) .type(BalanceType.SELL) .build()); } userBalanceRepo.saveAll(balanceList); balanceRecordRepo.saveAll(recordList); settleRecordRepo.save(new SettleRecord(date, orders.size(), totalAmount, royaltiesAmount, serviceChargeAmount)); } @Async @Transactional public ExportWithdraw exportWithdrawAsync(String remark) throws IOException, InvalidFormatException { return exportWithdraw(remark); } @Transactional public ExportWithdraw exportWithdraw(String remark) throws IOException, InvalidFormatException { List balanceList = userBalanceRepo.findByBalanceGreaterThan(BigDecimal.ZERO); List userBankCardList = balanceList.isEmpty() ? new ArrayList<>() : userBankCardRepo.findByUserIdIn(balanceList.stream().map(UserBalance::getUserId) .collect(Collectors.toSet())); List withdrawList = new ArrayList<>(); Iterator it = balanceList.iterator(); UserBalance ub; while (it.hasNext()) { ub = it.next(); Long userId = ub.getUserId(); log.info("查询提现银行卡userId={}", ub.getUserId()); UserBankCard ubc = userBankCardList.stream().filter(u -> u.getUserId().equals(userId)) .findFirst().orElse(null); if (ubc != null) { withdrawList.add(new UserWithdraw(userId, ubc.getRealName(), ubc.getBankNo(), ub.getBalance())); } else { it.remove(); } } File tmpDir = TempFile.createTempDirectory("export_" + RandomStringUtils.randomAlphabetic(8)); File file1 = new File(tmpDir, DateTimeUtils.format(LocalDate.now(), "yyyyMMdd") + "结算.xlsx"); File file2 = new File(tmpDir, DateTimeUtils.format(LocalDate.now(), "yyyyMMdd") + "结算导入.xls"); EasyExcel.write(file1, UserWithdraw.class) .sheet("sheet").doWrite(withdrawList); InputStream inputStream = getClass().getResourceAsStream("/批量付款到对私银行账户模板.xls"); Workbook workbook = WorkbookFactory.create(inputStream); Sheet sheet = workbook.getSheetAt(0); for (int i = 0; i < withdrawList.size(); i++) { Row row = Optional.ofNullable(sheet.getRow(i + 1)).orElse(sheet.createRow(i + 1)); Optional.ofNullable(row.getCell(1)) .orElse(row.createCell(1)) .setCellValue(withdrawList.get(i).getName()); Optional.ofNullable(row.getCell(2)) .orElse(row.createCell(2)) .setCellValue(withdrawList.get(i).getBankNo()); Optional.ofNullable(row.getCell(3)) .orElse(row.createCell(3)) .setCellValue(withdrawList.get(i).getAmount().doubleValue()); Optional.ofNullable(row.getCell(4)) .orElse(row.createCell(4)) .setCellValue(withdrawList.get(i).getUserId()); } inputStream.close(); FileOutputStream os = new FileOutputStream(file2); workbook.write(os); workbook.close(); File zipFile = ZipUtil.zip(tmpDir); String url = storageService.uploadFromInputStream(new FileInputStream(zipFile), "upload/" + DateTimeUtils.format(LocalDateTime.now(), "yyyyMMddHHmm") + "_" + RandomStringUtils .randomNumeric(8) + ".zip"); ExportWithdraw exportWithdraw = exportWithdrawRepo.save(new ExportWithdraw(url, remark, withdrawList.size(), withdrawList.stream().map(UserWithdraw::getAmount).reduce(BigDecimal::add) .orElse(BigDecimal.ZERO), "处理中")); balanceList.parallelStream().forEach(userBalance -> { log.info("提现userId={}", userBalance.getUserId()); BigDecimal amount = userBalance.getBalance(); userBalance.setLastBalance(userBalance.getBalance()); userBalance.setBalance(BigDecimal.ZERO); userBalanceRepo.saveAndFlush(userBalance); balanceRecordRepo.save(BalanceRecord.builder() .time(LocalDateTime.now()) .userId(userBalance.getUserId()) .amount(amount.negate()) .balance(BigDecimal.ZERO) .lastBalance(userBalance.getLastBalance()) .type(BalanceType.WITHDRAW) .build()); }); tmpDir.delete(); zipFile.delete(); return exportWithdraw; } @Transactional public void importFail(MultipartFile withdrawFile, MultipartFile settleFile) throws IOException { List failSettleList = EasyExcel.read(settleFile.getInputStream()) .head(SandPaySettle.class).sheet() .doReadSync(); failSettleList = failSettleList.stream() .filter(s -> "失败".equals(s.getStatus().trim())) .collect(Collectors.toList()); List withdrawList = EasyExcel.read(withdrawFile.getInputStream()) .head(UserWithdraw.class).sheet() .doReadSync(); List failWithdraw = new ArrayList<>(); for (SandPaySettle sandPaySettle : failSettleList) { List list; if (StringUtils.isNotBlank(sandPaySettle.getRemark()) && Pattern.matches("^\\d+$", sandPaySettle.getRemark() .trim())) { Long userId = Long.parseLong(sandPaySettle.getRemark().trim()); list = withdrawList.stream().filter(i -> i.getUserId().equals(userId)) .collect(Collectors.toList()); } else { list = withdrawList.stream().filter(i -> i.getBankNo().equals(sandPaySettle.getBankNo()) && i.getName().equals(sandPaySettle.getName()) && i.getAmount().compareTo(sandPaySettle.getAmount()) == 0) .collect(Collectors.toList()); } if (list.size() != 1) { throw new BusinessException("不唯一:" + sandPaySettle.getName() + "," + sandPaySettle.getBankNo()); } else { failWithdraw.add(list.get(0)); } } failWithdraw.parallelStream().forEach(withdraw -> { UserBalance userBalance = userBalanceRepo.findById(withdraw.getUserId()) .orElse(new UserBalance(withdraw .getUserId(), BigDecimal.ZERO, BigDecimal.ZERO, false, null, null)); userBalance.setLastBalance(userBalance.getBalance()); userBalance.setBalance(userBalance.getBalance().add(withdraw.getAmount())); userBalanceRepo.saveAndFlush(userBalance); balanceRecordRepo.save(BalanceRecord.builder() .time(LocalDateTime.now()) .userId(userBalance.getUserId()) .amount(withdraw.getAmount()) .balance(userBalance.getBalance()) .lastBalance(userBalance.getLastBalance()) .type(BalanceType.RETURN) .build()); }); } @Async public void autoWithdraw(LocalDate date) throws ExecutionException, InterruptedException { ForkJoinPool customThreadPool = new ForkJoinPool(5); customThreadPool.submit(() -> { autoWithdrawRecordRepo.findByDate(date).ifPresent(a -> { throw new BusinessException("今日已经提现过"); }); List list = userBalanceRepo .findByLockedFalseAndBalanceGreaterThanOrderByUserId(BigDecimal.ZERO); AutoWithdrawRecord record = AutoWithdrawRecord.builder() .date(LocalDate.now()) .status("pending") .progress(0) .total(list.size()) .build(); autoWithdrawRecordRepo.saveAndFlush(record); list.parallelStream().forEach(userBalance -> { UserBankCard userBankCard = userBankCardRepo.findByUserId(userBalance.getUserId()) .stream().findFirst().orElse(null); if (userBankCard == null) { log.info("自动提现userId={}, amount={}, 未绑卡", userBalance.getBalance(), userBalance.getUserId()); record.setProgress(record.getProgress() + 1); record.setCurrentUserId(userBalance.getUserId()); autoWithdrawRecordRepo.saveAndFlush(record); } else { log.info("自动提现userId={}, amount={}, name={}, bank={}", userBalance.getUserId(), userBalance.getBalance(), userBankCard.getRealName(), userBankCard.getBankNo()); String withdrawId = snowflakeIdWorker.nextId() + ""; BigDecimal amount = userBalance.getBalance(); userBalance.setLastBalance(userBalance.getBalance()); userBalance.setBalance(BigDecimal.ZERO); userBalanceRepo.saveAndFlush(userBalance); balanceRecordRepo.save(BalanceRecord.builder() .time(LocalDateTime.now()) .userId(userBalance.getUserId()) .amount(amount.negate()) .balance(BigDecimal.ZERO) .lastBalance(userBalance.getLastBalance()) .type(BalanceType.WITHDRAW) .withdrawId(withdrawId) .build()); boolean success = false; String msg = null; try { JSONObject res = sandPayService.transfer(withdrawId, userBankCard.getRealName(), userBankCard .getBankNo(), amount, userBankCard.getPhone()); if ("0000".equals(res.getString("respCode"))) { success = true; } else { msg = res.getString("respDesc"); } } catch (Exception e) { msg = e.getMessage(); } if (!success) { userBalance.setLastBalance(userBalance.getBalance()); userBalance.setBalance(userBalance.getBalance().add(amount)); userBalanceRepo.saveAndFlush(userBalance); balanceRecordRepo.save(BalanceRecord.builder() .time(LocalDateTime.now()) .userId(userBalance.getUserId()) .amount(amount) .balance(userBalance.getBalance()) .lastBalance(userBalance.getLastBalance()) .type(BalanceType.RETURN) .withdrawId(withdrawId) .remark(msg) .build()); } record.setProgress(record.getProgress() + 1); record.setCurrentUserId(userBalance.getUserId()); autoWithdrawRecordRepo.saveAndFlush(record); if (!success) { userBalance.setLocked(true); userBalance.setLockReason(msg); userBalance.setLockTime(LocalDateTime.now()); userBalanceRepo.saveAndFlush(userBalance); } } }); record.setStatus("finish"); autoWithdrawRecordRepo.saveAndFlush(record); }).get(); } public void revert() throws ExecutionException, InterruptedException { ForkJoinPool customThreadPool = new ForkJoinPool(200); customThreadPool.submit(() -> { LocalDate now = LocalDate.now(); userBalanceRepo.findAll().parallelStream().forEach(userBalance -> { List balanceRecords = balanceRecordRepo .findByUserIdOrderByCreatedAt(userBalance.getUserId()); List todayRecords = balanceRecords.stream() .filter(b -> b.getCreatedAt().toLocalDate() .equals(now)) .collect(Collectors.toList()); List oldRecords = balanceRecords.stream() .filter(b -> !b.getCreatedAt().toLocalDate().equals(now)) .sorted(Comparator.comparing(BaseEntity::getCreatedAt)) .collect(Collectors.toList()); if (oldRecords.size() == 0) { userBalanceRepo.delete(userBalance); } else { BalanceRecord record = oldRecords.get(oldRecords.size() - 1); userBalance.setBalance(record.getBalance()); userBalance.setLastBalance(record.getLastBalance()); userBalanceRepo.save(userBalance); } balanceRecordRepo.deleteAll(todayRecords); }); }).get(); } @RedisLock("#userId") public BalanceRecord balancePay(Long userId, BigDecimal amount, Long orderId, String remark) { UserBalance userBalance = userBalanceRepo.findById(userId).orElseThrow(new BusinessException("余额不足")); if (userBalance.getBalance().compareTo(amount) < 0) { throw new BusinessException("余额不足"); } userBalance.setLastBalance(userBalance.getBalance()); userBalance.setBalance(userBalance.getBalance().subtract(amount)); userBalanceRepo.save(userBalance); return balanceRecordRepo.save(BalanceRecord.builder() .userId(userId) .balance(userBalance.getBalance()) .lastBalance(userBalance.getLastBalance()) .type(BalanceType.PAY) .amount(amount.negate()) .time(LocalDateTime.now()) .orderId(orderId) .remark(remark) .build()); } @RedisLock("#userId") public void recharge(Long orderId, PayMethod payMethod, String transactionId) { log.info("recharge orderId={}, transactionId={}, payMethod={}", orderId, transactionId, payMethod); RechargeOrder rechargeOrder = rechargeOrderRepo.findById(orderId).orElseThrow(new BusinessException("充值订单不存在")); Long userId = rechargeOrder.getUserId(); if (OrderStatus.NOT_PAID == rechargeOrder.getStatus()) { BigDecimal amount = rechargeOrder.getAmount(); UserBalance userBalance = userBalanceRepo.findById(userId).orElse(UserBalance.builder() .userId(userId) .balance(BigDecimal.ZERO) .lastBalance(BigDecimal.ZERO) .build()); userBalance.setLastBalance(userBalance.getBalance()); userBalance.setBalance(userBalance.getBalance().add(amount)); userBalanceRepo.save(userBalance); balanceRecordRepo.save(BalanceRecord.builder() .userId(userId) .balance(userBalance.getBalance()) .lastBalance(userBalance.getLastBalance()) .type(BalanceType.RECHARGE) .amount(amount) .time(LocalDateTime.now()) .orderId(orderId) .payMethod(payMethod) .build()); rechargeOrder.setStatus(OrderStatus.FINISH); rechargeOrderRepo.save(rechargeOrder); } else if (OrderStatus.FINISH == rechargeOrder.getStatus()) { log.info("recharge orderId={} has been finished", orderId); } else { throw new BusinessException("充值订单状态异常"); } LocalDate now = LocalDate.now(); LocalDate start = LocalDate.of(2023, 1, 19); LocalDate end = LocalDate.of(2023, 1, 29); if (now.isBefore(end) & now.isAfter(start)) { try { Long checkResult = checkRechargeSum(rechargeOrder.getAmount()); if (checkResult > 0) { airDrop(rechargeOrder.getId(), rechargeOrder.getUserId(), checkResult); } } catch (Exception e) { log.info("空投藏品出错:rechargeOrderId" + rechargeOrder.getId()); } } } public void airDrop(Long orderId, Long userId, Long checkResult) { Long collectionId = Long.valueOf(sysConfigService.getString("recharge_collectionId")); User user = userRepo.findById(userId).orElseThrow(new BusinessException("暂无该用户")); airDropService.create(AirDrop.builder() .name("春节充值空投福卡") .remark("rechargeOrder:" + orderId) .type(AirDropType.asset) .userIds(Collections.singletonList(userId)) .collectionId(collectionId) .targets(Collections .singletonList(new DropTarget(user.getId(), user.getPhone(), user .getNickname(), Math.toIntExact(checkResult)))) .auto(true) .companyId(1L) .build()); } public Long checkRechargeSum(BigDecimal recharge) { BigDecimal targetNum = BigDecimal.valueOf(5000L); return recharge.divide(targetNum, 0, RoundingMode.DOWN).longValue(); } public BalanceRecord preWithdraw(Long userId, BigDecimal amount) { UserBalance userBalance = userBalanceRepo.findById(userId).orElseThrow(new BusinessException("余额不足")); if (amount.compareTo(userBalance.getBalance()) > 0) { throw new BusinessException("余额不足"); } BigDecimal minWithdrawAmount = sysConfigService.getBigDecimal("min_withdraw_amount"); if (amount.compareTo(minWithdrawAmount) < 0) { throw new BusinessException("最小提现金额为" + minWithdrawAmount); } UserBankCard userBankCard = userBankCardRepo.findByUserId(userBalance.getUserId()) .stream().findFirst().orElseThrow(new BusinessException("请先绑定银行卡")); userBalance.setLastBalance(userBalance.getBalance()); userBalance.setBalance(userBalance.getBalance().subtract(amount)); userBalanceRepo.saveAndFlush(userBalance); return balanceRecordRepo.save(BalanceRecord.builder() .time(LocalDateTime.now()) .userId(userBalance.getUserId()) .amount(amount.negate()) .balance(userBalance.getBalance()) .lastBalance(userBalance.getLastBalance()) .type(BalanceType.WITHDRAW) .build()); } @RedisLock(value = "'modifyBalance::'+#userId", behavior = RedisLock.Behavior.WAIT) public void modifyBalance(Long userId, BigDecimal amount, BalanceType type, String reason, boolean lock, String withdrawId) { UserBalance userBalance = userBalanceRepo.findById(userId).orElse(new UserBalance(userId)); userBalance.setLastBalance(userBalance.getBalance()); userBalance.setBalance(userBalance.getBalance().add(amount)); if (lock) { userBalance.setLockTime(LocalDateTime.now()); userBalance.setLocked(true); userBalance.setLockReason(reason); } userBalanceRepo.saveAndFlush(userBalance); balanceRecordRepo.save(BalanceRecord.builder() .time(LocalDateTime.now()) .userId(userId) .amount(amount) .balance(userBalance.getBalance()) .lastBalance(userBalance.getLastBalance()) .type(type) .remark(reason) .withdrawId(withdrawId) .build()); } public void realtimeSettleOrder(Order order) { if (!sysConfigService.getBoolean("realtime_settle_order")) { return; } BalanceRecord record = balanceRecordRepo.findByOrderIdAndType(order.getId(), BalanceType.SELL); if (record != null) { log.info("此订单已结算 orderId={}", order.getId()); return; } log.info("结算订单 orderId={}", order.getId()); Asset asset = assetRepo.findById(order.getAssetId()).orElse(null); UserBalance userBalance = userBalanceRepo.findById(asset.getUserId()) .orElse(new UserBalance(asset.getUserId())); BigDecimal amount = order.getTotalPrice() .subtract(order.getGasPrice()) .multiply(BigDecimal.valueOf(100 - order.getRoyalties() - order.getServiceCharge())) .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP); userBalance.setLastBalance(userBalance.getBalance()); userBalance.setBalance(userBalance.getBalance().add(amount)); userBalanceRepo.save(userBalance); balanceRecordRepo.save(BalanceRecord.builder() .time(LocalDateTime.now()) .userId(asset.getUserId()) .orderId(order.getId()) .amount(amount) .balance(userBalance.getBalance()) .lastBalance(userBalance.getLastBalance()) .type(BalanceType.SELL) .build()); } public void realtimeSettleOrder(DomainAsk domainAsk) { if (!sysConfigService.getBoolean("realtime_settle_order")) { return; } BalanceRecord record = balanceRecordRepo.findByOrderIdAndType(domainAsk.getId(), BalanceType.ASK); if (record != null) { log.info("此订单已结算 domainAskId={}", domainAsk.getId()); return; } log.info("结算订单 domainAskId={}", domainAsk.getId()); Asset asset = assetRepo.findById(domainAsk.getAssetId()).orElse(null); UserBalance userBalance = userBalanceRepo.findById(asset.getUserId()) .orElse(new UserBalance(asset.getUserId())); BigDecimal amount = domainAsk.getPrice() // .subtract(BigDecimal.valueOf(1)) .multiply(BigDecimal .valueOf(100 - domainAsk.getRoyalties() - domainAsk.getServiceCharge())) .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP); userBalance.setLastBalance(userBalance.getBalance()); userBalance.setBalance(userBalance.getBalance().add(amount)); userBalanceRepo.save(userBalance); balanceRecordRepo.save(BalanceRecord.builder() .time(LocalDateTime.now()) .userId(asset.getUserId()) .orderId(domainAsk.getId()) .amount(amount) .balance(userBalance.getBalance()) .lastBalance(userBalance.getLastBalance()) .type(BalanceType.ASK) .build()); } public void addBalance(Long userId, BigDecimal amount, Long orderId, BalanceType type) { //用户冲余额 UserBalance userBalance = userBalanceRepo.findByUserId(userId) .orElse(UserBalance.builder() .balance(BigDecimal.ZERO) .lastBalance(BigDecimal.ZERO) .userId(userId) .build()); userBalance.setLastBalance(userBalance.getBalance()); userBalance.setBalance(userBalance.getBalance().add(amount)); userBalanceRepo.save(userBalance); log.info("拍卖冲用户余额{},¥{}", userId, amount); balanceRecordRepo.save(BalanceRecord.builder() .time(LocalDateTime.now()) .userId(userId) .orderId(orderId) .amount(amount) .balance(userBalance.getBalance()) .lastBalance(userBalance.getLastBalance()) .type(type) .build()); } public boolean checkBalance(Long userId, BigDecimal balance) { UserBalance userBalance = userBalanceRepo.findById(userId).orElse(new UserBalance(userId)); return userBalance.getBalance().compareTo(balance) >= 0; } }