From befbf57e4112d07003bff18102f556a1e5a154de Mon Sep 17 00:00:00 2001
From: zj <1772600164@qq.com>
Date: Wed, 22 Apr 2026 10:53:37 +0800
Subject: [PATCH] 1
---
trading-order-service/src/main/java/com/yami/trading/service/trader/impl/TraderFollowUserServiceImpl.java | 391 +++++++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 331 insertions(+), 60 deletions(-)
diff --git a/trading-order-service/src/main/java/com/yami/trading/service/trader/impl/TraderFollowUserServiceImpl.java b/trading-order-service/src/main/java/com/yami/trading/service/trader/impl/TraderFollowUserServiceImpl.java
index 9b68706..b38bdae 100644
--- a/trading-order-service/src/main/java/com/yami/trading/service/trader/impl/TraderFollowUserServiceImpl.java
+++ b/trading-order-service/src/main/java/com/yami/trading/service/trader/impl/TraderFollowUserServiceImpl.java
@@ -1,24 +1,45 @@
package com.yami.trading.service.trader.impl;
+import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yami.trading.bean.trader.domain.Trader;
import com.yami.trading.bean.trader.domain.TraderFollowUser;
+import com.yami.trading.bean.trader.domain.TraderFollowUserOrder;
+import com.yami.trading.common.constants.Constants;
import com.yami.trading.common.exception.BusinessException;
import com.yami.trading.common.util.Arith;
+import com.yami.trading.common.util.StringUtils;
import com.yami.trading.dao.trader.TraderFollowUserMapper;
+import com.yami.trading.dao.trader.TraderFollowUserOrderMapper;
+import com.yami.trading.service.FollowWalletService;
+import com.yami.trading.service.WalletService;
+import com.yami.trading.service.trader.FollowCommissionService;
+import com.yami.trading.service.trader.TraderFollowUserOrderService;
import com.yami.trading.service.trader.TraderFollowUserService;
import com.yami.trading.service.trader.TraderService;
import com.yami.trading.service.trader.TraderUserService;
+import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.time.Instant;
import java.math.RoundingMode;
import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
@Service
public class TraderFollowUserServiceImpl implements TraderFollowUserService {
+ private static final ExecutorService STOP_FOLLOW_EXECUTOR = Executors.newFixedThreadPool(4);
+
+ private final Set<String> stoppingTasks = ConcurrentHashMap.newKeySet();
+
@Resource
private TraderService traderService;
@Resource
@@ -27,25 +48,26 @@
@Resource
private TraderFollowUserMapper traderFollowUserMapper;
+ @Resource
+ private TraderFollowUserOrderMapper traderFollowUserOrderMapper;
+ @Resource
+ private FollowWalletService followWalletService;
+ @Resource
+ private WalletService walletService;
+
+ @Resource
+ private FollowCommissionService followCommissionService;
+
+ @Lazy
+ @Resource
+ private TraderFollowUserOrderService traderFollowUserOrderService;
+
public List<Map<String, Object>> getPaged(Page pageparam, String partyId, String profit) {
-
-// StringBuffer queryString = new StringBuffer("");
-// queryString.append(" SELECT * FROM ");
-// queryString.append(" T_TRADER_FOLLOW_USER ");
-// queryString.append(" where 1=1 ");
-//
-// Map<String, Object> parameters = new HashMap();
-//
-// queryString.append(" and TRADER_PARTY_ID = :partyId");
-// parameters.put("partyId", partyId);
-
-// if (!StringUtils.isNullOrEmpty(profit)) {
-// queryString.append(" and PROFIT >= 0 ");
-// }
-//
-// queryString.append(" order by PROFIT desc ");
- Page page = traderFollowUserMapper.selectPage(pageparam, Wrappers.<TraderFollowUser>lambdaQuery().eq(TraderFollowUser::getTraderPartyId, partyId).ge(TraderFollowUser::getProfit, 0).orderByDesc(TraderFollowUser::getProfit));
-// Page page = this.pagedQueryDao.pagedQuerySQL(pageNo, pageSize, queryString.toString(), parameters);
+ Page<TraderFollowUser> page = traderFollowUserMapper.selectPage(pageparam,
+ Wrappers.<TraderFollowUser>lambdaQuery()
+ .eq(TraderFollowUser::getTraderPartyId, partyId)
+ .orderByDesc(TraderFollowUser::getCreateTime)
+ .orderByDesc(TraderFollowUser::getUuid));
List<Map<String, Object>> data = this.bulidData(page.getRecords());
return data;
}
@@ -54,15 +76,30 @@
List<Map<String, Object>> result_traders = new ArrayList();
DecimalFormat df2 = new DecimalFormat("#.##");
df2.setRoundingMode(RoundingMode.FLOOR);// 向下取整
+ SimpleDateFormat tsFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
if (traderFollowUsers == null) {
return result_traders;
}
for (int i = 0; i < traderFollowUsers.size(); i++) {
Map<String, Object> map = new HashMap<String, Object>();
TraderFollowUser entity = traderFollowUsers.get(i);
+ map.put("id", entity.getUuid());
map.put("name", entity.getUsername());
map.put("profit", df2.format(entity.getProfit()));
map.put("amount_sum", df2.format(entity.getAmountSum()));
+ map.put("followState", entity.getState());
+ map.put("symbol", entity.getSymbol());
+ map.put("volume", df2.format(entity.getVolume()));
+ map.put("volumeMax", df2.format(entity.getVolumeMax()));
+ map.put("lever_rate", entity.getLeverRate() > 0 ? df2.format(entity.getLeverRate()) : "");
+ map.put("followFailReason", entity.getFailReason() != null ? entity.getFailReason() : "");
+ if (entity.getCreateTime() != null) {
+ map.put("follow_start_time", tsFmt.format(entity.getCreateTime()));
+ } else {
+ map.put("follow_start_time", "");
+ }
+ map.put("follow_stop_time", formatEpochSecond(entity.getStopFinishTime(), tsFmt));
+ map.put("follow_fail_time", formatEpochSecond(entity.getLastFailTime(), tsFmt));
result_traders.add(map);
}
@@ -71,17 +108,17 @@
}
+ private static String formatEpochSecond(Long sec, SimpleDateFormat tsFmt) {
+ if (sec == null || sec <= 0L) {
+ return "";
+ }
+ return tsFmt.format(new Date(sec * 1000L));
+ }
+
@Override
+ @Transactional(rollbackFor = Exception.class)
public void save(TraderFollowUser entity, String trader_id) {
- if (entity.getVolume() % 1 != 0 || entity.getVolume() <= 0 || entity.getVolumeMax() % 1 != 0) {
- throw new BusinessException(1, "跟单参数输入错误");
- }
- if (entity.getFollowType() == "1" && (entity.getVolume() > 3000 || entity.getVolume() < 1)) {
- throw new BusinessException(1, "跟单参数输入错误");
- }
- if (entity.getFollowType() == "2" && (entity.getVolume() > 5 || entity.getVolume() < 1)) {
- throw new BusinessException(1, "跟单倍数输入错误");
- }
+ validateFollowConfig(entity);
Trader trader = this.traderService.findById(trader_id);
if (trader == null) {
throw new BusinessException(1, "交易员不存在");
@@ -89,68 +126,104 @@
if ("0".equals(trader.getState())) {
throw new BusinessException(1, "交易员未开启带单");
}
- if (findByStateAndPartyId(entity.getPartyId(), trader.getPartyId(), "1") != null) {
- throw new BusinessException(1, "用户已跟随交易员");
- }
- if (Arith.sub(trader.getFollowerMax(), trader.getFollowerNow()) < 1) {
- throw new BusinessException(1, "交易员跟随人数已满");
+ if (trader.getChecked() != 1) {
+ throw new BusinessException(1, "交易员审核未通过");
}
if (entity.getPartyId().equals(trader.getPartyId())) {
throw new BusinessException(1, "交易员不能跟随自己");
}
+ validateFollowSymbol(entity.getSymbol(), trader.getSymbols());
Trader trader_user = this.traderService.findByPartyId(entity.getPartyId());
- if (trader_user != null) {
+ if (trader_user != null && trader_user.getChecked() == 1) {
throw new BusinessException(1, "交易员无法跟随另一个交易员");
}
- // 跟单固定张数/固定比例---选择 1,固定张数,2,固定比例
- if (trader.getFollowVolumnMin() > 0) {
- switch (entity.getFollowType()) {
- case "1":
- if (entity.getVolume() < trader.getFollowVolumnMin()) {
- throw new BusinessException(1, "跟单参数输入错误");
- }
- if (entity.getVolumeMax() < trader.getFollowVolumnMin()) {
- throw new BusinessException(1, "跟单参数输入错误");
- }
- break;
- case "2":
- throw new BusinessException(1, "交易员已设置最小下单数,无法通过固定比例跟单");
- default:
- break;
+ BigDecimal followMin = trader.getFollowVolumnMin();
+ if (followMin != null && followMin.compareTo(BigDecimal.ZERO) > 0) {
+ double minVol = followMin.doubleValue();
+ if (entity.getVolume() < minVol || entity.getVolumeMax() < minVol) {
+ throw new BusinessException(1, "跟单币数量不能低于交易员设置的最小值");
}
+ }
+
+ TraderFollowUser latest = findByPartyIdAndTrader_partyId(entity.getPartyId(), trader.getPartyId());
+ if (latest != null
+ && (TraderFollowUser.STATE_FOLLOWING.equals(latest.getState())
+ || TraderFollowUser.STATE_STOPPING.equals(latest.getState()))) {
+ throw new BusinessException(1, "用户已跟随交易员");
+ }
+ try {
+ followCommissionService.applyMonthlyFeeIfNeeded(trader, latest, entity);
+ } catch (BusinessException e) {
+ if (isInsufficientBalanceError(e)) {
+ recordFollowFailed(entity, trader, e.getMessage(), latest);
+ }
+ throw e;
}
entity.setTraderPartyId(trader.getPartyId());
entity.setCreateTime(new Date());
+ entity.setFollowType(TraderFollowUser.FOLLOW_TYPE_FIXED);
+ entity.setState(TraderFollowUser.STATE_FOLLOWING);
+ entity.setInvestAmount(BigDecimal.valueOf(entity.getVolume()));
+ entity.setStopRequestTime(null);
+ entity.setStopFinishTime(null);
+ entity.setFailReason(null);
+ entity.setLastFailTime(null);
+ long priorSessions = traderFollowUserMapper.selectCount(Wrappers.<TraderFollowUser>lambdaQuery()
+ .eq(TraderFollowUser::getTraderPartyId, trader.getPartyId())
+ .eq(TraderFollowUser::getPartyId, entity.getPartyId())
+ .in(TraderFollowUser::getState, TraderFollowUser.STATE_FOLLOWING, TraderFollowUser.STATE_STOPPING,
+ TraderFollowUser.STATE_STOPPED));
+ if (priorSessions == 0L) {
+ trader.setFollowerSum((int) Arith.add(trader.getFollowerSum(), 1));
+ }
trader.setFollowerNow((int) Arith.add(trader.getFollowerNow(), 1));
- trader.setFollowerSum((int) Arith.add(trader.getFollowerSum(), 1));
traderService.update(trader);
/**
* 创建累计用户跟随累计表
*/
traderUserService.saveTraderUserByPartyId(entity.getPartyId());
-// ApplicationUtil.executeSaveOrUpdate(entity);
+ if (latest != null) {
+ entity.setProfit(latest.getProfit());
+ entity.setAmountSum(latest.getAmountSum());
+ if (entity.getMonthlyFeePaidPeriod() == null) {
+ entity.setMonthlyFeePaidPeriod(latest.getMonthlyFeePaidPeriod());
+ }
+ }
+ entity.setUuid(null);
traderFollowUserMapper.insert(entity);
+ /**
+ * 纠正历史脏数据:手动停止跟单时跟单方 saveClose 未同步 T_TRADER_FOLLOW_USER_ORDER 状态,
+ * 再次跟单前应把「合约已平仓仍为 submitted」的映射置为 created,否则会占满 volumeMax。
+ */
+ traderFollowUserOrderService.reconcileStaleSubmittedMappings(entity.getPartyId(), entity.getTraderPartyId());
}
@Override
public void save(TraderFollowUser entity) {
+ if (entity.getFollowType() == null) {
+ entity.setFollowType(TraderFollowUser.FOLLOW_TYPE_FIXED);
+ }
+ if (entity.getState() == null) {
+ entity.setState(TraderFollowUser.STATE_FOLLOWING);
+ }
traderFollowUserMapper.insert(entity);
}
@Override
public void update(TraderFollowUser entity) {
- if (entity.getVolume() % 1 != 0 || entity.getVolume() <= 0 || entity.getVolumeMax() % 1 != 0) {
- throw new BusinessException(1, "跟单参数输入错误");
- }
- if (entity.getFollowType() == "1" && (entity.getVolume() > 3000 || entity.getVolume() < 1)) {
- throw new BusinessException(1, "跟单参数输入错误");
- }
- if (entity.getFollowType() == "2" && (entity.getVolume() > 5 || entity.getVolume() < 1)) {
- throw new BusinessException(1, "跟单倍数输入错误");
+ validateFollowConfig(entity);
+ entity.setFollowType(TraderFollowUser.FOLLOW_TYPE_FIXED);
+ entity.setInvestAmount(BigDecimal.valueOf(entity.getVolume()));
+ TraderFollowUser old = traderFollowUserMapper.selectById(entity.getUuid());
+ if (old != null) {
+ Trader trader = this.traderService.findByPartyId(old.getTraderPartyId());
+ if (trader != null) {
+ validateFollowSymbol(entity.getSymbol(), trader.getSymbols());
+ }
}
// ApplicationUtil.executeUpdate(entity);
@@ -160,6 +233,9 @@
@Override
public void deleteCancel(String id) {
TraderFollowUser entity = findById(id);
+ if (entity == null) {
+ return;
+ }
/**
* 将旧的交易员跟随用户-1
*/
@@ -169,9 +245,51 @@
if (entity != null) {
// ApplicationUtil.executeDelete(entity);
- traderFollowUserMapper.deleteById(entity);
+ traderFollowUserMapper.deleteById(entity.getUuid());
}
+ }
+
+ @Override
+ public void cancelFollowAsync(String id, com.yami.trading.service.contract.ContractOrderService contractOrderService) {
+ TraderFollowUser entity = findById(id);
+ if (entity == null || TraderFollowUser.STATE_STOPPED.equals(entity.getState())) {
+ return;
+ }
+ if (TraderFollowUser.STATE_STOPPING.equals(entity.getState()) || !stoppingTasks.add(entity.getUuid())) {
+ return;
+ }
+ entity.setState(TraderFollowUser.STATE_STOPPING);
+ entity.setStopRequestTime(Instant.now().getEpochSecond());
+ traderFollowUserMapper.updateById(entity);
+ STOP_FOLLOW_EXECUTOR.submit(() -> {
+ try {
+ List<TraderFollowUserOrder> openOrders = traderFollowUserOrderMapper.selectList(
+ Wrappers.<TraderFollowUserOrder>lambdaQuery()
+ .eq(TraderFollowUserOrder::getPartyId, entity.getPartyId())
+ .eq(TraderFollowUserOrder::getTraderPartyId, entity.getTraderPartyId())
+ .eq(TraderFollowUserOrder::getState, TraderFollowUserOrder.STATE_SUBMITTED));
+ if (openOrders != null) {
+ for (TraderFollowUserOrder openOrder : openOrders) {
+ contractOrderService.saveClose(entity.getPartyId(), openOrder.getUserOrderNo());
+ }
+ }
+ TraderFollowUser latest = findById(id);
+ if (latest != null) {
+ latest.setState(TraderFollowUser.STATE_STOPPED);
+ latest.setStopFinishTime(Instant.now().getEpochSecond());
+ traderFollowUserMapper.updateById(latest);
+ refundFollowWalletToMainWallet(latest.getPartyId());
+ Trader trader = this.traderService.findByPartyId(latest.getTraderPartyId());
+ if (trader != null && trader.getFollowerNow() > 0) {
+ trader.setFollowerNow((int) Arith.sub(trader.getFollowerNow(), 1));
+ this.traderService.update(trader);
+ }
+ }
+ } finally {
+ stoppingTasks.remove(entity.getUuid());
+ }
+ });
}
public List<TraderFollowUser> findByStateAndPartyId(String partyId, String trader_partyId, String state) {
@@ -193,6 +311,17 @@
return null;
}
+ @Override
+ public List<TraderFollowUser> findActiveByTraderPartyId(String trader_partyId) {
+ List<TraderFollowUser> list = traderFollowUserMapper.selectList(Wrappers.<TraderFollowUser>lambdaQuery()
+ .eq(TraderFollowUser::getTraderPartyId, trader_partyId)
+ .eq(TraderFollowUser::getState, TraderFollowUser.STATE_FOLLOWING));
+ if (list.size() > 0) {
+ return list;
+ }
+ return null;
+ }
+
public List<TraderFollowUser> findByPartyId(String partyId) {
List<TraderFollowUser> list = traderFollowUserMapper.selectList(Wrappers.<TraderFollowUser>lambdaQuery().eq(TraderFollowUser::getPartyId, partyId));
// List<TraderFollowUser> list = ApplicationUtil.executeSelect(TraderFollowUser.class, " WHERE PARTY_ID = ? ",
@@ -202,8 +331,33 @@
return null;
}
+ @Override
+ public long countByPartyId(String partyId) {
+ if (StringUtils.isNullOrEmpty(partyId)) {
+ return 0L;
+ }
+ Long c = traderFollowUserMapper.selectCount(Wrappers.<TraderFollowUser>lambdaQuery()
+ .eq(TraderFollowUser::getPartyId, partyId));
+ return c == null ? 0L : c.longValue();
+ }
+
+ @Override
+ public IPage<TraderFollowUser> pageByPartyId(Page<TraderFollowUser> page, String partyId) {
+ if (page == null || StringUtils.isNullOrEmpty(partyId)) {
+ return page;
+ }
+ return traderFollowUserMapper.selectPage(page, Wrappers.<TraderFollowUser>lambdaQuery()
+ .eq(TraderFollowUser::getPartyId, partyId)
+ .orderByDesc(TraderFollowUser::getUpdateTime)
+ .orderByDesc(TraderFollowUser::getCreateTime));
+ }
+
public TraderFollowUser findByPartyIdAndTrader_partyId(String partyId, String trader_partyId) {
- List<TraderFollowUser> list = traderFollowUserMapper.selectList(Wrappers.<TraderFollowUser>lambdaQuery().eq(TraderFollowUser::getPartyId, partyId).eq(TraderFollowUser::getTraderPartyId, trader_partyId));
+ List<TraderFollowUser> list = traderFollowUserMapper.selectList(Wrappers.<TraderFollowUser>lambdaQuery()
+ .eq(TraderFollowUser::getPartyId, partyId)
+ .eq(TraderFollowUser::getTraderPartyId, trader_partyId)
+ .orderByDesc(TraderFollowUser::getCreateTime)
+ .orderByDesc(TraderFollowUser::getUuid));
// List<TraderFollowUser> list = ApplicationUtil.executeSelect(TraderFollowUser.class,
// " WHERE PARTY_ID= ? and TRADER_PARTY_ID = ? ",
// new Object[] { partyId, trader_partyId });
@@ -212,10 +366,127 @@
return null;
}
+ private boolean isInsufficientBalanceError(BusinessException e) {
+ if (e == null || e.getMessage() == null) {
+ return false;
+ }
+ return e.getMessage().contains("余额不足");
+ }
+
+ private void recordFollowFailed(TraderFollowUser entity, Trader trader, String reason, TraderFollowUser latest) {
+ TraderFollowUser failed = new TraderFollowUser();
+ failed.setPartyId(entity.getPartyId());
+ failed.setUsername(entity.getUsername());
+ failed.setTraderPartyId(trader.getPartyId());
+ failed.setSymbol(entity.getSymbol());
+ failed.setFollowType(TraderFollowUser.FOLLOW_TYPE_FIXED);
+ failed.setVolume(entity.getVolume());
+ failed.setVolumeMax(entity.getVolumeMax());
+ failed.setInvestAmount(BigDecimal.valueOf(entity.getVolume()));
+ failed.setStopLoss(0D);
+ failed.setStopProfit(0D);
+ failed.setState(TraderFollowUser.STATE_FAILED);
+ failed.setFailReason(reason);
+ failed.setLastFailTime(Instant.now().getEpochSecond());
+ failed.setCreateTime(new Date());
+ if (latest != null && TraderFollowUser.STATE_FAILED.equals(latest.getState())) {
+ failed.setUuid(latest.getUuid());
+ failed.setProfit(latest.getProfit());
+ failed.setAmountSum(latest.getAmountSum());
+ failed.setMonthlyFeePaidPeriod(latest.getMonthlyFeePaidPeriod());
+ traderFollowUserMapper.updateById(failed);
+ return;
+ }
+ traderFollowUserMapper.insert(failed);
+ }
+
public TraderFollowUser findById(String id) {
// return ApplicationUtil.executeGet(id, TraderFollowUser.class);
TraderFollowUser traderFollowUser = traderFollowUserMapper.selectById(id);
return traderFollowUser;
}
+ private void validateFollowConfig(TraderFollowUser entity) {
+ entity.setFollowType(TraderFollowUser.FOLLOW_TYPE_FIXED);
+ if (entity.getVolume() <= 0 || entity.getVolumeMax() <= 0) {
+ throw new BusinessException(1, "跟单参数输入错误");
+ }
+ if (entity.getVolumeMax() < entity.getVolume()) {
+ throw new BusinessException(1, "最大跟单币数量不能小于最小跟单币数量");
+ }
+ if (entity.getStopLoss() < 0 || entity.getStopProfit() < 0) {
+ throw new BusinessException(1, "止盈止损参数输入错误");
+ }
+ if (entity.getLeverRate() <= 0) {
+ throw new BusinessException(1, "杠杆倍数必须大于0");
+ }
+ }
+
+ private void validateFollowSymbol(String followSymbol, String traderSymbolsRaw) {
+ if (followSymbol == null || followSymbol.trim().isEmpty()) {
+ throw new BusinessException(1, "请选择跟单币种");
+ }
+ String follow = followSymbol.trim();
+ String raw = traderSymbolsRaw == null ? "" : traderSymbolsRaw.trim();
+ if (raw.isEmpty()) {
+ throw new BusinessException(1, "交易员未配置带单币种");
+ }
+ String[] arr = raw.split("[;;,,]+");
+ for (String one : arr) {
+ if (follow.equalsIgnoreCase(one == null ? "" : one.trim())) {
+ return;
+ }
+ }
+ throw new BusinessException(1, "只能选择交易员带单币种中的一种进行跟单");
+ }
+
+ private void refundFollowWalletToMainWallet(String partyId) {
+ if (partyId == null || partyId.trim().isEmpty()) {
+ return;
+ }
+ com.yami.trading.bean.model.FollowWallet followWallet = followWalletService.saveWalletByPartyId(partyId);
+ if (followWallet == null || followWallet.getMoney() == null || followWallet.getMoney().compareTo(BigDecimal.ZERO) <= 0) {
+ return;
+ }
+ BigDecimal refund = followWallet.getMoney();
+ walletService.updateMoney("USDT", partyId, refund, BigDecimal.ZERO,
+ Constants.MONEYLOG_CATEGORY_CONTRACT, Constants.WALLET_USDT, Constants.MONEYLOG_CONTENT_CONTRACT_CLOSE,
+ "停止跟单返还独立跟单账户资金");
+ followWalletService.updateMoney("USDT", partyId, refund.negate(), BigDecimal.ZERO,
+ Constants.MONEYLOG_CATEGORY_CONTRACT, Constants.WALLET_USDT, Constants.MONEYLOG_CONTENT_CONTRACT_CLOSE,
+ "停止跟单划转资金到主钱包");
+ }
+
+ @Override
+ public void markFollowOpenFailed(String partyId, String traderPartyId, String reason) {
+ if (partyId == null || partyId.trim().isEmpty() || traderPartyId == null || traderPartyId.trim().isEmpty()) {
+ return;
+ }
+ List<TraderFollowUser> list = traderFollowUserMapper.selectList(Wrappers.<TraderFollowUser>lambdaQuery()
+ .eq(TraderFollowUser::getPartyId, partyId)
+ .eq(TraderFollowUser::getTraderPartyId, traderPartyId)
+ .eq(TraderFollowUser::getState, TraderFollowUser.STATE_FOLLOWING)
+ .orderByDesc(TraderFollowUser::getCreateTime)
+ .last("LIMIT 1"));
+ if (list == null || list.isEmpty()) {
+ return;
+ }
+ TraderFollowUser u = list.get(0);
+ String msg = reason == null ? "" : reason.trim();
+ if (msg.length() > 900) {
+ msg = msg.substring(0, 900) + "…";
+ }
+ long nowSec = Instant.now().getEpochSecond();
+ u.setState(TraderFollowUser.STATE_FAILED);
+ u.setFailReason(msg);
+ u.setLastFailTime(nowSec);
+ u.setStopFinishTime(nowSec);
+ traderFollowUserMapper.updateById(u);
+ Trader trader = this.traderService.findByPartyId(traderPartyId);
+ if (trader != null && trader.getFollowerNow() > 0) {
+ trader.setFollowerNow((int) Arith.sub(trader.getFollowerNow(), 1));
+ this.traderService.update(trader);
+ }
+ }
+
}
--
Gitblit v1.9.3