src/main/java/com/nq/controller/PayApiController.java
@@ -29,6 +29,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; @Controller @@ -162,4 +164,29 @@ log.error("fly notify error Msg = {}", serverResponse.getMsg()); } } @RequestMapping(value = {"ococnReturn.do"}, method = {RequestMethod.GET, RequestMethod.POST}) public void ococnReturn(HttpServletRequest request, HttpServletResponse response) throws IOException { String redirectUrl = this.iPayService.ococnReturn(request); response.setContentType("text/html;charset=UTF-8"); response.setCharacterEncoding("UTF-8"); String safeUrl = redirectUrl.replace("\\", "\\\\").replace("'", "\\'"); response.getWriter().write( "<!DOCTYPE html><html><head><meta charset=\"UTF-8\"><title>跳转中</title>" + "<script>window.location.replace('" + safeUrl + "');</script>" + "</head><body></body></html>" ); } @RequestMapping(value = {"ococnNotify.do"}, method = {RequestMethod.GET, RequestMethod.POST}) @ResponseBody public void ococnNotify(HttpServletRequest request, HttpServletResponse response) throws IOException { ServerResponse serverResponse = this.iPayService.ococnNotify(request); if (serverResponse.isSuccess()) { response.getWriter().write("success"); log.info("ococn 支付渠道异步通知处理成功"); } else { log.error("ococn notify error Msg = {}", serverResponse.getMsg()); } } } src/main/java/com/nq/controller/protol/UserController.java
@@ -125,6 +125,20 @@ } return serverResponse; } //撤销委托单 @RequestMapping({"cancelOrder.do"}) @ResponseBody public ServerResponse cancelOrder(HttpServletRequest request, @RequestParam("positionSn") String positionSn) { ServerResponse serverResponse = null; try { serverResponse = this.iUserPositionService.cancelOrder(positionSn, request); } catch (Exception e) { log.error("用户撤单操作 = {}", e); serverResponse = ServerResponse.createByErrorMsg("撤单失败"); } return serverResponse; } //用户平仓操作 @RequestMapping({"sell.do"}) @ResponseBody src/main/java/com/nq/controller/protol/UserPayController.java
@@ -49,4 +49,11 @@ return this.iPayService.flyPay(payType, payAmt, currency, request); } @RequestMapping({"ococnPay.do"}) @ResponseBody public ServerResponse ococnPay(@RequestParam("payType") String payType, @RequestParam("payAmt") String payAmt, HttpServletRequest request) { log.info("发起 ococn 线上支付 payType = {} payAmt = {}", payType, payAmt); return this.iPayService.ococnPay(payType, payAmt, request); } } src/main/java/com/nq/service/IPayService.java
@@ -20,4 +20,10 @@ ServerResponse flyPay(String paramString1, String paramString2, String paramString3, HttpServletRequest paramHttpServletRequest); ServerResponse flyNotify(HttpServletRequest paramHttpServletRequest); ServerResponse ococnPay(String payType, String payAmt, HttpServletRequest request); ServerResponse ococnNotify(HttpServletRequest request); String ococnReturn(HttpServletRequest request); } src/main/java/com/nq/service/IUserPositionService.java
@@ -16,6 +16,8 @@ ServerResponse pending(Integer paramInteger1, Integer paramInteger2, Integer paramInteger3, Integer paramInteger4,BigDecimal paramInteger5,BigDecimal paramInteger6, HttpServletRequest paramHttpServletRequest) throws Exception; ServerResponse cancelOrder(String positionSn, HttpServletRequest request) throws Exception; ServerResponse sell(String paramString, int paramInt) throws Exception; ServerResponse calendar(String paramString,HttpServletRequest request) throws Exception; src/main/java/com/nq/service/IUserService.java
@@ -92,6 +92,7 @@ void updateUserAmt(Double amt, Integer user_id); /** 将数据库中最新的用户资金写回登录缓存 */ void syncUserCache(HttpServletRequest request); } src/main/java/com/nq/service/impl/PayServiceImpl.java
@@ -12,8 +12,10 @@ import com.nq.utils.PropertiesUtil; import com.nq.utils.pay.CmcPayOuterRequestUtil; import com.nq.utils.pay.CmcPayTool; import com.nq.utils.pay.OcocnPayUtil; import com.nq.vo.pay.FlyPayVO; import com.nq.vo.pay.GuoPayVO; import com.nq.vo.pay.OcocnPayVO; import java.io.UnsupportedEncodingException; import java.math.BigDecimal; @@ -22,6 +24,7 @@ import java.security.NoSuchAlgorithmException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; import java.util.Random; import javax.servlet.http.HttpServletRequest; @@ -375,6 +378,139 @@ } @Override public ServerResponse ococnPay(String payType, String payAmt, HttpServletRequest request) { if (StringUtils.isBlank(payType) || StringUtils.isBlank(payAmt)) { return ServerResponse.createByErrorMsg("参数不能为空"); } BigDecimal payAmtBig = new BigDecimal(payAmt); if (payAmtBig.compareTo(BigDecimal.ZERO) <= 0) { return ServerResponse.createByErrorMsg("支付金额必须大于0"); } User user = this.iUserService.getCurrentRefreshUser(request); if (user == null) { return ServerResponse.createByErrorMsg("请先登录"); } String ordersn = KeyUtils.getRechargeOrderSn(); String money = payAmtBig.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString(); String pid = PropertiesUtil.getProperty("ococn.pay.pid"); String key = PropertiesUtil.getProperty("ococn.pay.key"); String submitUrl = PropertiesUtil.getProperty("ococn.pay.url"); String apiDomain = trimTrailingSlash(PropertiesUtil.getProperty("website.domain.url")); if (StringUtils.isAnyBlank(pid, key, submitUrl, apiDomain)) { return ServerResponse.createByErrorMsg("支付配置不完整,请联系管理员"); } String notifyUrl = apiDomain + "/api/pay/ococnNotify.do"; String returnUrl = apiDomain + "/api/pay/ococnReturn.do"; String sitename = StringUtils.defaultString(PropertiesUtil.getProperty("ococn.pay.sitename", ""), ""); String productName = PropertiesUtil.getProperty("ococn.pay.name", "账户充值"); UserRecharge userRecharge = new UserRecharge(); userRecharge.setUserId(user.getId()); userRecharge.setNickName(user.getRealName()); userRecharge.setAgentId(user.getAgentId()); userRecharge.setOrderSn(ordersn); userRecharge.setPayChannel(getOcocnChannelName(payType)); userRecharge.setPayAmt(payAmtBig); userRecharge.setOrderStatus(Integer.valueOf(0)); userRecharge.setAddTime(new Date()); int insertCount = this.userRechargeMapper.insert(userRecharge); if (insertCount <= 0) { return ServerResponse.createByErrorMsg("创建支付订单失败"); } String sign = OcocnPayUtil.buildSubmitSign(money, productName, notifyUrl, ordersn, pid, returnUrl, sitename, payType, key); log.info("ococn支付 notifyUrl={} returnUrl={}", notifyUrl, returnUrl); StringBuilder payUrlBuilder = new StringBuilder(submitUrl).append("?"); payUrlBuilder.append("pid=").append(pid) .append("&type=").append(payType) .append("&out_trade_no=").append(ordersn) .append("¬ify_url=").append(OcocnPayUtil.encode(notifyUrl)) .append("&return_url=").append(OcocnPayUtil.encode(returnUrl)) .append("&name=").append(OcocnPayUtil.encode(productName)) .append("&money=").append(money); if (StringUtils.isNotBlank(sitename)) { payUrlBuilder.append("&sitename=").append(OcocnPayUtil.encode(sitename)); } payUrlBuilder.append("&sign=").append(sign).append("&sign_type=MD5"); String payUrl = payUrlBuilder.toString(); OcocnPayVO ococnPayVO = new OcocnPayVO(); ococnPayVO.setPayUrl(payUrl); log.info("ococn支付,创建订单成功 orderSn={}", ordersn); return ServerResponse.createBySuccess(ococnPayVO); } @Override public ServerResponse ococnNotify(HttpServletRequest request) { Map<String, String> params = OcocnPayUtil.parseRequestParams(request); log.info("ococn支付通知参数: {}", params); String outTradeNo = params.get("out_trade_no"); String tradeNo = params.get("trade_no"); String money = params.get("money"); String tradeStatus = params.get("trade_status"); String sign = params.get("sign"); if (StringUtils.isAnyBlank(outTradeNo, tradeNo, money, tradeStatus, sign)) { return ServerResponse.createByErrorMsg("回调参数不完整"); } String key = PropertiesUtil.getProperty("ococn.pay.key"); if (!OcocnPayUtil.verifyNotifySign(params, key)) { log.error("ococn支付通知签名校验失败, remoteSign={}, params={}", sign, params); return ServerResponse.createByErrorMsg("签名校验失败"); } if (!"TRADE_SUCCESS".equals(tradeStatus)) { return ServerResponse.createByErrorMsg("支付未成功"); } UserRecharge existing = this.userRechargeMapper.findUserRechargeByOrderSn(outTradeNo); if (existing != null && existing.getOrderStatus().intValue() != 0) { return ServerResponse.createBySuccessMsg("订单已处理"); } return doSuccess(outTradeNo, money); } @Override public String ococnReturn(HttpServletRequest request) { Map<String, String> params = OcocnPayUtil.parseRequestParams(request); log.info("ococn支付同步跳转: {}", params); String frontendUrl = StringUtils.defaultIfBlank( PropertiesUtil.getProperty("ococn.pay.frontend_redirect"), trimTrailingSlash(PropertiesUtil.getProperty("frontend.domain.url", "")) + "/#/user" ); return frontendUrl; } private String getOcocnChannelName(String payType) { if ("alipay".equals(payType)) { return "支付宝-线上"; } if ("wxpay".equals(payType)) { return "微信-线上"; } if ("qqpay".equals(payType)) { return "QQ钱包-线上"; } if ("tenpay".equals(payType)) { return "财付通-线上"; } return "线上支付"; } private String trimTrailingSlash(String url) { if (url == null) { return null; } return url.endsWith("/") ? url.substring(0, url.length() - 1) : url; } @Override public ServerResponse juhenewpayNotify(HttpServletRequest request) throws UnsupportedEncodingException { LinkedMap map = new LinkedMap(); String out_trade_no = request.getParameter("out_trade_no"); src/main/java/com/nq/service/impl/SiteSettingServiceImpl.java
@@ -9,6 +9,7 @@ import com.nq.pojo.SiteSetting; import com.nq.service.ISiteSettingService; import com.nq.utils.TradeFeeUtil; import java.util.List; @@ -34,6 +35,7 @@ if (list.size() > 0) { siteSetting = (SiteSetting) list.get(0); siteSetting.setBuyFee(TradeFeeUtil.BUY_FEE_RATE); } return siteSetting; @@ -48,6 +50,7 @@ if (siteSetting == null) { return ServerResponse.createByErrorMsg("查不到设置记录"); } setting.setBuyFee(TradeFeeUtil.BUY_FEE_RATE); int updateCount = this.siteSettingMapper.updateByPrimaryKeySelective(setting); src/main/java/com/nq/service/impl/StockOptionServiceImpl.java
@@ -71,9 +71,14 @@ List<StockOptionListVO> stockOptionListVOS = Lists.newArrayList(); for (StockOption option : stockOptions) { StockOptionListVO stockOptionListVO = assembleStockOptionListVO(option); stockOptionListVO.setIsOption("1"); stockOptionListVOS.add(stockOptionListVO); try { StockOptionListVO stockOptionListVO = assembleStockOptionListVO(option); stockOptionListVO.setIsOption("1"); stockOptionListVOS.add(stockOptionListVO); } catch (Exception e) { log.error("自选列表单条行情组装失败, gid={}, code={}", option.getStockGid(), option.getStockCode(), e); stockOptionListVOS.add(buildFallbackOptionVO(option)); } } PageInfo pageInfo = new PageInfo(stockOptions); @@ -133,24 +138,42 @@ stockVO = SinaStockApi.assembleStockVO(SinaStockApi.getSinaStock(option.getStockGid())); } } stockOptionListVO.setNowPrice(stockVO.getNowPrice()); if (stockVO == null) { stockVO = new StockVO(); } stockOptionListVO.setNowPrice(stockVO.getNowPrice() == null ? "0" : stockVO.getNowPrice()); stockOptionListVO.setHcrate(stockVO.getHcrate().toString()); stockOptionListVO.setHcrate(stockVO.getHcrate() == null ? "0" : stockVO.getHcrate().toString()); stockOptionListVO.setPreclose_px(stockVO.getPreclose_px()); stockOptionListVO.setPreclose_px(stockVO.getPreclose_px() == null ? "0" : stockVO.getPreclose_px()); stockOptionListVO.setOpen_px(stockVO.getOpen_px()); stockOptionListVO.setOpen_px(stockVO.getOpen_px() == null ? "0" : stockVO.getOpen_px()); stockOptionListVO.setType(stockVO.getType()); Stock stock = this.stockMapper.selectByPrimaryKey(option.getStockId()); stockOptionListVO.setStock_plate(stock.getStockPlate()==null?"":stock.getStockPlate()); if (stock != null) { stockOptionListVO.setStock_plate(stock.getStockPlate()==null?"":stock.getStockPlate()); stockOptionListVO.setStock_type(stock.getStockType()); } return stockOptionListVO; } private StockOptionListVO buildFallbackOptionVO(StockOption option) { StockOptionListVO vo = new StockOptionListVO(); vo.setId(option.getId().intValue()); vo.setStockName(option.getStockName()); vo.setStockCode(option.getStockCode()); vo.setStockGid(option.getStockGid()); vo.setNowPrice("0"); vo.setHcrate("0"); vo.setPreclose_px("0"); vo.setOpen_px("0"); vo.setIsOption("1"); return vo; } } src/main/java/com/nq/service/impl/StockServiceImpl.java
@@ -116,34 +116,49 @@ PageHelper.startPage(pageNum, pageSize); User user = iUserService.getCurrentUser(request); List<Stock> stockList = this.stockMapper.findStockListByKeyWords(keyWords, stockPlate, stockType, Integer.valueOf(0)); boolean quickSearch = org.apache.commons.lang3.StringUtils.isNotBlank(keyWords); List<StockListVO> stockListVOS = Lists.newArrayList(); if (stockList.size() > 0) for (Stock stock : stockList) { StockListVO stockListVO = new StockListVO(); stockListVO=SinaStockApi.assembleLideStockListVO(LiDeDataUtils.getStock(stock.getStockCode())); if(ObjectUtils.isEmpty(stockListVO)){ stockListVO = SinaStockApi.assembleStockListVO(SinaStockApi.getSinaStock(stock.getStockGid())); } stockListVO.setCode(stock.getStockCode()); stockListVO.setSpell(stock.getStockSpell()); stockListVO.setGid(stock.getStockGid()); BigDecimal day3Rate = (BigDecimal)selectRateByDaysAndStockCode(stock.getStockCode(), 3).getData(); stockListVO.setDay3Rate(day3Rate); stockListVO.setStock_plate(stock.getStockPlate()); stockListVO.setStock_type(stock.getStockType()); //是否添加自选 if(user == null){ stockListVO.setIsOption("0"); } else { stockListVO.setIsOption(iStockOptionService.isMyOption(user.getId(), stock.getStockCode())); } stockListVOS.add(stockListVO); } if (stockList.size() > 0) { Integer userId = user != null ? user.getId() : null; stockListVOS = stockList.parallelStream().map(stock -> assembleStockListItem(stock, userId, quickSearch)) .collect(java.util.stream.Collectors.toList()); } PageInfo pageInfo = new PageInfo(stockList); pageInfo.setList(stockListVOS); return ServerResponse.createBySuccess(pageInfo); } /** 搜索列表组装行情:关键词搜索走轻量路径,跳过三日涨幅等慢查询 */ private StockListVO assembleStockListItem(Stock stock, Integer userId, boolean quickSearch) { StockListVO stockListVO = SinaStockApi.assembleLideStockListVO(LiDeDataUtils.getStock(stock.getStockCode())); if (ObjectUtils.isEmpty(stockListVO)) { stockListVO = SinaStockApi.assembleStockListVO(SinaStockApi.getSinaStock(stock.getStockGid())); } if (stockListVO == null) { stockListVO = new StockListVO(); stockListVO.setName(stock.getStockName()); stockListVO.setNowPrice("0"); stockListVO.setHcrate(java.math.BigDecimal.ZERO); } stockListVO.setCode(stock.getStockCode()); stockListVO.setSpell(stock.getStockSpell()); stockListVO.setGid(stock.getStockGid()); if (!quickSearch) { BigDecimal day3Rate = (BigDecimal) selectRateByDaysAndStockCode(stock.getStockCode(), 3).getData(); stockListVO.setDay3Rate(day3Rate); } stockListVO.setStock_plate(stock.getStockPlate()); stockListVO.setStock_type(stock.getStockType()); if (userId == null) { stockListVO.setIsOption("0"); } else if (quickSearch) { stockListVO.setIsOption("0"); } else { stockListVO.setIsOption(iStockOptionService.isMyOption(userId, stock.getStockCode())); } return stockListVO; } public void z1() { this.stockPoll.z1(); } src/main/java/com/nq/service/impl/UserFundsPositionServiceImpl.java
@@ -341,7 +341,7 @@ userPosition.setIsLock(Integer.valueOf(0)); userPosition.setOrderLever(lever); userPosition.setOrderTotalPrice(buy_amt); BigDecimal buy_fee_amt = buy_amt.multiply(siteSetting.getBuyFee()).setScale(2, 4); BigDecimal buy_fee_amt = com.nq.utils.TradeFeeUtil.calcBuyFee(buy_amt); log.info("用户购买手续费(配资后总资金 * 百分比) = {}", buy_fee_amt); userPosition.setOrderFee(buy_fee_amt); src/main/java/com/nq/service/impl/UserPositionServiceImpl.java
@@ -11,6 +11,8 @@ import com.google.common.collect.Lists; import com.nq.common.ServerResponse; import com.nq.utils.*; import com.nq.utils.TradeFeeUtil; import com.nq.utils.redis.JsonUtil; import com.nq.utils.redis.RedisShardedPoolUtils; import com.nq.utils.stock.BuyAndSellUtils; import com.nq.utils.stock.GeneratePosition; @@ -111,6 +113,7 @@ StockDzMapper stockDzMapper; @Override @Transactional public ServerResponse buy(Integer stockId, Integer buyNum, Integer buyType, Integer lever, BigDecimal profitTarget, BigDecimal stopTarget, HttpServletRequest request) throws Exception { @@ -385,11 +388,12 @@ } int compareUserAmtInt = user_enable_amt.compareTo(buy_amt_autual); log.info("用户可用金额 = {} 实际购买金额 = {}", user_enable_amt, buy_amt_autual); log.info("比较 用户金额 和 实际 购买金额 = {}", Integer.valueOf(compareUserAmtInt)); BigDecimal buy_fee_amt = TradeFeeUtil.calcBuyFee(buy_amt); BigDecimal buy_debit = TradeFeeUtil.calcBuyDebit(buy_amt_autual, buy_fee_amt); int compareUserAmtInt = user_enable_amt.compareTo(buy_debit); log.info("用户可用金额 = {} 下单扣款(保证金+手续费) = {}", user_enable_amt, buy_debit); if (compareUserAmtInt == -1) { return ServerResponse.createByErrorMsg("下单失败,融资可用金额小于" + buy_amt_autual + "元"); return ServerResponse.createByErrorMsg("下单失败,融资可用金额小于" + buy_debit + "元(含保证金及手续费)"); } if (user.getUserIndexAmt().compareTo(new BigDecimal("0")) == -1) { @@ -445,7 +449,6 @@ userPosition.setOrderStayDays(1); BigDecimal buy_fee_amt = buy_amt.multiply(siteSetting.getBuyFee()).setScale(2, 4); log.info("用户购买手续费(配资后总资金 * 百分比) = {}", buy_fee_amt); userPosition.setOrderFee(buy_fee_amt); @@ -477,33 +480,11 @@ userPosition.setOrderStayDays(Integer.valueOf(0)); userPosition.setOrderStayFee(new BigDecimal("0")); int insertPositionCount = 0; this.userPositionMapper.insert(userPosition); insertPositionCount = userPosition.getId(); if (insertPositionCount > 0) { //修改用户可用余额= 当前余额-下单金额-买入手续费-印花税-点差费 //BigDecimal reckon_enable = user_enable_amt.subtract(buy_amt_autual).subtract(buy_fee_amt).subtract(buy_yhs_amt).subtract(spread_rate_amt); //修改用户可用余额= 当前余额-下单总金额 BigDecimal reckon_enable = user_enable_amt.subtract(buy_amt_autual); //修改用户可取余额=当前可取余额-下单总金额 int compareUserWithdrawAmtInt = user_enable_withdraw_amt.compareTo(buy_amt_autual); if (compareUserWithdrawAmtInt == -1) { //若可取余额小于下单总额,但是可用余额充足,令可取余额为0 user.setEnaleWithdrawAmt(BigDecimal.ZERO); } else { user_enable_withdraw_amt = user_enable_withdraw_amt.subtract(buy_amt_autual); user.setEnaleWithdrawAmt(user_enable_withdraw_amt); } user.setEnableAmt(reckon_enable); int updateUserCount = this.userMapper.updateByPrimaryKeySelective(user); if (updateUserCount > 0) { log.info("【用户交易下单】修改用户金额成功"); } else { log.error("用户交易下单】修改用户金额出错"); throw new Exception("用户交易下单】修改用户金额出错"); } //核算代理收入-入仓手续费 if (userPosition.getId() != null && userPosition.getId() > 0) { deductUserEnableOnBuy(user, buy_debit, buy_amt_autual, buy_fee_amt, userPosition); iAgentAgencyFeeService.AgencyFeeIncome(1, userPosition.getPositionSn()); syncUserCacheAfterTrade(request); log.info("【用户交易下单】保存持仓记录成功"); } else { log.error("用户交易下单】保存持仓记录出错"); @@ -514,12 +495,111 @@ } public ServerResponse fee(Integer buyNum,BigDecimal nowPrice){ @Override public ServerResponse fee(Integer buyNum, BigDecimal nowPrice) { BigDecimal buy_amt = nowPrice.multiply(new BigDecimal(buyNum.intValue())); SiteSetting siteSetting = this.iSiteSettingService.getSiteSetting(); BigDecimal buy_fee_amt = buy_amt.multiply(siteSetting.getBuyFee()).setScale(2, 4); BigDecimal buy_fee_amt = TradeFeeUtil.calcBuyFee(buy_amt).setScale(2, 4); return ServerResponse.createBySuccess(buy_fee_amt); } /** 下单从两融可用资金扣除:保证金 + 买入手续费 */ private void deductUserEnableOnBuy(User user, BigDecimal buyDebit, BigDecimal margin, BigDecimal fee, UserPosition position) throws Exception { User fresh = this.userMapper.selectByPrimaryKey(user.getId()); if (fresh == null) { throw new Exception("用户不存在"); } BigDecimal enableAmt = fresh.getEnableAmt() == null ? BigDecimal.ZERO : fresh.getEnableAmt(); if (enableAmt.compareTo(buyDebit) < 0) { throw new Exception("扣除可用资金失败(保证金+手续费=" + buyDebit + "元),余额不足"); } fresh.setEnableAmt(enableAmt.subtract(buyDebit)); BigDecimal withdrawAmt = fresh.getEnaleWithdrawAmt() == null ? BigDecimal.ZERO : fresh.getEnaleWithdrawAmt(); if (withdrawAmt.compareTo(buyDebit) < 0) { fresh.setEnaleWithdrawAmt(BigDecimal.ZERO); } else { fresh.setEnaleWithdrawAmt(withdrawAmt.subtract(buyDebit)); } BigDecimal userAmt = fresh.getUserAmt() == null ? BigDecimal.ZERO : fresh.getUserAmt(); fresh.setUserAmt(userAmt.subtract(buyDebit)); int rows = this.userMapper.updateByPrimaryKeySelective(fresh); if (rows <= 0) { throw new Exception("扣除可用资金失败(保证金+手续费=" + buyDebit + "元)"); } saveBuyDebitCashDetail(user, position, margin, fee, buyDebit); log.info("【用户交易下单】扣款成功,用户={},保证金={},手续费={},合计={}", user.getId(), margin, fee, buyDebit); } private void refundUserEnableOnCancel(User user, BigDecimal refundAmt, UserPosition position) throws Exception { User fresh = this.userMapper.selectByPrimaryKey(user.getId()); if (fresh == null) { throw new Exception("用户不存在"); } BigDecimal enableAmt = fresh.getEnableAmt() == null ? BigDecimal.ZERO : fresh.getEnableAmt(); BigDecimal withdrawAmt = fresh.getEnaleWithdrawAmt() == null ? BigDecimal.ZERO : fresh.getEnaleWithdrawAmt(); BigDecimal userAmt = fresh.getUserAmt() == null ? BigDecimal.ZERO : fresh.getUserAmt(); fresh.setEnableAmt(enableAmt.add(refundAmt)); fresh.setEnaleWithdrawAmt(withdrawAmt.add(refundAmt)); fresh.setUserAmt(userAmt.add(refundAmt)); int rows = this.userMapper.updateByPrimaryKeySelective(fresh); if (rows <= 0) { throw new Exception("撤单退款失败"); } UserCashDetail ucd = new UserCashDetail(); ucd.setPositionId(position.getId()); ucd.setAgentId(user.getAgentId()); ucd.setAgentName(user.getAgentName()); ucd.setUserId(user.getId()); ucd.setUserName(user.getRealName()); ucd.setDeType("撤单退款"); ucd.setDeAmt(refundAmt); ucd.setDeSummary("撤销委托," + position.getStockCode() + "/" + position.getStockName() + ",退还保证金+手续费:" + refundAmt); ucd.setAddTime(new Date()); ucd.setIsRead(Integer.valueOf(0)); this.userCashDetailMapper.insert(ucd); log.info("【用户撤单】退款成功,用户={},金额={}", user.getId(), refundAmt); } private void saveBuyDebitCashDetail(User user, UserPosition position, BigDecimal margin, BigDecimal fee, BigDecimal buyDebit) { UserCashDetail ucd = new UserCashDetail(); ucd.setPositionId(position.getId()); ucd.setAgentId(user.getAgentId()); ucd.setAgentName(user.getAgentName()); ucd.setUserId(user.getId()); ucd.setUserName(user.getRealName()); ucd.setDeType("买入扣款"); ucd.setDeAmt(buyDebit.negate()); ucd.setDeSummary("委托买入," + position.getStockCode() + "/" + position.getStockName() + ",保证金:" + margin + ",手续费:" + fee + ",合计扣款:" + buyDebit); ucd.setAddTime(new Date()); ucd.setIsRead(Integer.valueOf(0)); this.userCashDetailMapper.insert(ucd); } /** 下单/撤单后刷新 Redis 中的用户资金,避免页面仍显示旧可用余额 */ private void syncUserCacheAfterTrade(HttpServletRequest request) { if (request == null) { return; } String cookieName = PropertiesUtil.getProperty("user.cookie.name"); String loginToken = request.getHeader(cookieName); if (StringUtils.isBlank(loginToken)) { return; } String userJson = RedisShardedPoolUtils.get(loginToken); User cached = (User) JsonUtil.string2Obj(userJson, User.class); if (cached == null || cached.getId() == null) { return; } User dbUser = this.userMapper.selectByPrimaryKey(cached.getId()); if (dbUser != null) { RedisShardedPoolUtils.setEx(loginToken, JsonUtil.obj2String(dbUser), 9999); } } @Override @Transactional public ServerResponse pending(Integer stockId, Integer buyNum, Integer buyType, Integer lever, BigDecimal profitTarget, BigDecimal stopTarget, HttpServletRequest request) throws Exception { @@ -708,11 +788,10 @@ .getBuyMaxAmtPercent().multiply(new BigDecimal("100")) + "%"); } int compareUserAmtInt = user_enable_amt.compareTo(buy_amt_autual); log.info("用户可用金额 = {} 实际购买金额 = {}", user_enable_amt, buy_amt_autual); log.info("比较 用户金额 和 实际 购买金额 = {}", Integer.valueOf(compareUserAmtInt)); if (compareUserAmtInt == -1) { return ServerResponse.createByErrorMsg("挂单失败,融资可用金额小于" + buy_amt_autual + "元"); BigDecimal buy_fee_amt = TradeFeeUtil.calcBuyFee(buy_amt); BigDecimal buy_debit = TradeFeeUtil.calcBuyDebit(buy_amt_autual, buy_fee_amt); if (user_enable_amt.compareTo(buy_debit) == -1) { return ServerResponse.createByErrorMsg("挂单失败,融资可用金额小于" + buy_debit + "元(含保证金及手续费)"); } if (user.getUserIndexAmt().compareTo(new BigDecimal("0")) == -1) { return ServerResponse.createByErrorMsg("失败,指数总资金小于0"); @@ -751,7 +830,6 @@ BigDecimal allStayFee = stayFee.multiply(new BigDecimal(1)); userPosition.setOrderStayFee(allStayFee); userPosition.setOrderStayDays(1); BigDecimal buy_fee_amt = buy_amt.multiply(siteSetting.getBuyFee()).setScale(2, 4); log.info("用户购买手续费(配资后总资金 * 百分比) = {}", buy_fee_amt); userPosition.setOrderFee(buy_fee_amt); BigDecimal buy_yhs_amt = buy_amt.multiply(siteSetting.getDutyFee()).setScale(2, 4); @@ -772,40 +850,60 @@ userPosition.setAllProfitAndLose(all_profit_and_lose); userPosition.setOrderStayDays(Integer.valueOf(0)); userPosition.setOrderStayFee(new BigDecimal("0")); int insertPositionCount = 0; this.userPositionMapper.insert(userPosition); insertPositionCount = userPosition.getId(); if (insertPositionCount > 0) { //修改用户可用余额= 当前余额-下单金额-买入手续费-印花税-点差费 //BigDecimal reckon_enable = user_enable_amt.subtract(buy_amt_autual).subtract(buy_fee_amt).subtract(buy_yhs_amt).subtract(spread_rate_amt); //修改用户可用余额= 当前余额-下单总金额 BigDecimal reckon_enable = user_enable_amt.subtract(buy_amt_autual); //修改用户可取余额=当前可取余额-下单总金额 int compareUserWithdrawAmtInt = user_enable_withdraw_amt.compareTo(buy_amt_autual); if (compareUserWithdrawAmtInt == -1) { //若可取余额小于下单总额,但是可用余额充足,令可取余额为0 user.setEnaleWithdrawAmt(BigDecimal.ZERO); } else { user_enable_withdraw_amt = user_enable_withdraw_amt.subtract(buy_amt_autual); user.setEnaleWithdrawAmt(user_enable_withdraw_amt); } user.setEnableAmt(reckon_enable); // user.setDjzj(user.getDjzj().subtract(buy_amt_autual)); int updateUserCount = this.userMapper.updateByPrimaryKeySelective(user); if (updateUserCount > 0) { log.info("【用户交易下单】修改用户金额成功"); } else { log.error("用户交易下单】修改用户金额出错"); throw new Exception("用户交易下单】修改用户金额出错"); } //核算代理收入-入仓手续费 // iAgentAgencyFeeService.AgencyFeeIncome(1, userPosition.getPositionSn()); if (userPosition.getId() != null && userPosition.getId() > 0) { deductUserEnableOnBuy(user, buy_debit, buy_amt_autual, buy_fee_amt, userPosition); syncUserCacheAfterTrade(request); log.info("【用户交易下单】保存持仓记录成功"); } else { log.error("用户交易下单】保存持仓记录出错"); throw new Exception("用户交易下单】保存持仓记录出错"); } return ServerResponse.createBySuccess("挂单成功"); } /** * 撤销委托单(status=0),退还保证金+买入手续费 */ @Override @Transactional(rollbackFor = Exception.class) public ServerResponse cancelOrder(String positionSn, HttpServletRequest request) throws Exception { if (StringUtils.isBlank(positionSn)) { return ServerResponse.createByErrorMsg("参数错误"); } User user = this.iUserService.getCurrentRefreshUser(request); if (user == null) { return ServerResponse.createByErrorMsg("请先登录"); } UserPosition userPosition = this.userPositionMapper.findPositionBySn(positionSn); if (userPosition == null) { return ServerResponse.createByErrorMsg("委托不存在"); } if (!user.getId().equals(userPosition.getUserId())) { return ServerResponse.createByErrorMsg("无权操作该委托"); } if (userPosition.getStatus() == null || userPosition.getStatus().intValue() != 0) { return ServerResponse.createByErrorMsg("当前订单不可撤单"); } if (userPosition.getSellOrderId() != null) { return ServerResponse.createByErrorMsg("当前订单不可撤单"); } BigDecimal buyAmtActual = userPosition.getOrderTotalPrice() .divide(new BigDecimal(userPosition.getOrderLever()), 2, 4); BigDecimal buyFee = userPosition.getOrderFee() != null ? userPosition.getOrderFee() : BigDecimal.ZERO; BigDecimal refundAmt = TradeFeeUtil.calcBuyDebit(buyAmtActual, buyFee); User freshUser = this.userMapper.selectByPrimaryKey(user.getId()); if (freshUser == null) { throw new Exception("用户不存在"); } refundUserEnableOnCancel(freshUser, refundAmt, userPosition); int delCount = this.userPositionMapper.deleteByPrimaryKey(userPosition.getId()); if (delCount <= 0) { throw new Exception("撤单失败,删除委托记录失败"); } syncUserCacheAfterTrade(request); log.info("【用户撤单】positionSn={} 退还保证金+手续费={}", positionSn, refundAmt); return ServerResponse.createBySuccessMsg("撤单成功"); } @@ -1055,8 +1153,8 @@ BigDecimal sell_fee_amt = all_sell_amt.multiply(siteSetting.getSellFee()).setScale(2, 4); log.info("卖出手续费 = {}", sell_fee_amt); //總手續費= 買入手續費+賣出手續費+印花稅+遞延費+點差費 BigDecimal all_fee_amt = buy_fee_amt.add(sell_fee_amt).add(orderSpread).add(orderStayFee).add(spreadRatePrice); // 买入手续费已在下单时扣除,平仓只结算卖出侧费用 BigDecimal all_fee_amt = sell_fee_amt.add(orderSpread).add(orderStayFee).add(spreadRatePrice); log.info("总的手续费费用 = {}", all_fee_amt); userPosition.setSellOrderId(GeneratePosition.getPositionId()); @@ -1266,7 +1364,7 @@ BigDecimal user_enable_amt = user.getEnableAmt(); log.info("用戶原本總資金 = {} , 可用 = {}", user_all_amt, user_enable_amt); BigDecimal buy_fee_amt = all_buy_amt.multiply(siteSetting.getBuyFee()).setScale(2,4); BigDecimal buy_fee_amt = TradeFeeUtil.calcBuyFee(all_buy_amt); log.info("買入手續費 = {}", buy_fee_amt); BigDecimal orderSpread = all_buy_amt.multiply(siteSetting.getDutyFee()).setScale(2, 4); @@ -1281,9 +1379,8 @@ BigDecimal sell_fee_amt = all_sell_amt.multiply(siteSetting.getSellFee()).setScale(2, 4); log.info("賣出手續費 = {}", sell_fee_amt); //總手續費= 買入手續費+賣出手續費+印花稅+遞延費+點差費 // BigDecimal all_fee_amt = buy_fee_amt.add(sell_fee_amt).add(orderSpread).add(orderStayFee).add(spreadRatePrice); BigDecimal all_fee_amt = buy_fee_amt.add(sell_fee_amt).add(orderSpread); // 买入手续费已在下单时扣除 BigDecimal all_fee_amt = sell_fee_amt.add(orderSpread); log.info("總的手續費費用 = {}", all_fee_amt); //复制一条新订单 UserPosition userPositionNew = new UserPosition(); @@ -1425,7 +1522,8 @@ } userPosition.setMarginAdd(userPosition.getMarginAdd().add(marginAdd)); BigDecimal existMarginAdd = userPosition.getMarginAdd() == null ? BigDecimal.ZERO : userPosition.getMarginAdd(); userPosition.setMarginAdd(existMarginAdd.add(marginAdd)); int updatePositionCount = this.userPositionMapper.updateByPrimaryKeySelective(userPosition); if (updatePositionCount > 0) { @@ -1823,13 +1921,11 @@ BigDecimal buy_amt_autual = buy_amt.divide(new BigDecimal(lever.intValue()), 2, 4); int compareUserAmtInt = user_enable_amt.compareTo(buy_amt_autual); log.info("用户可用金额 = {} 实际购买金额 = {}", user_enable_amt, buy_amt_autual); log.info("比较 用户金额 和 实际 购买金额 = {}", Integer.valueOf(compareUserAmtInt)); if (compareUserAmtInt == -1) { log.info("下单失败,用户可用金额小于" + buy_amt_autual + "元"); return ServerResponse.createByErrorMsg("下单失败,用户可用金额小于" + buy_amt_autual + "元"); BigDecimal buy_fee_amt_check = TradeFeeUtil.calcBuyFee(buy_amt); BigDecimal buy_debit_check = TradeFeeUtil.calcBuyDebit(buy_amt_autual, buy_fee_amt_check); if (user_enable_amt.compareTo(buy_debit_check) < 0) { log.info("下单失败,用户可用金额小于{}元(含保证金及手续费)", buy_debit_check); return ServerResponse.createByErrorMsg("下单失败,用户可用金额小于" + buy_debit_check + "元(含保证金及手续费)"); } if (user.getUserIndexAmt().compareTo(new BigDecimal("0")) == -1) { @@ -1886,7 +1982,7 @@ userPosition.setOrderStayDays(1); BigDecimal buy_fee_amt = buy_amt.multiply(siteSetting.getBuyFee()).setScale(2, 4); BigDecimal buy_fee_amt = TradeFeeUtil.calcBuyFee(buy_amt).setScale(2, 4); log.info("创建模拟持仓 手续费(配资后总资金 * 百分比) = {}", buy_fee_amt); userPosition.setOrderFee(buy_fee_amt); @@ -1931,20 +2027,19 @@ userPosition.setOrderStayFee(new BigDecimal("0")); userPosition.setSpreadRatePrice(new BigDecimal("0")); int insertPositionCount = this.userPositionMapper.insert(userPosition); if (insertPositionCount > 0) { log.info("【创建持仓】保存记录成功"); } else { this.userPositionMapper.insert(userPosition); if (userPosition.getId() == null || userPosition.getId() <= 0) { log.error("【创建持仓】保存记录出错"); return ServerResponse.createByErrorMsg("生成持仓失败"); } BigDecimal reckon_enable = user_enable_amt.subtract(buy_amt_autual); user.setEnableAmt(reckon_enable); int updateUserCount = this.userMapper.updateByPrimaryKeySelective(user); if (updateUserCount > 0) { log.info("【用户交易下单】修改用户金额成功"); } else { log.error("用户交易下单】修改用户金额出错"); log.info("【创建持仓】保存记录成功"); BigDecimal buy_debit = TradeFeeUtil.calcBuyDebit(buy_amt_autual, buy_fee_amt); try { deductUserEnableOnBuy(user, buy_debit, buy_amt_autual, buy_fee_amt, userPosition); } catch (Exception e) { this.userPositionMapper.deleteByPrimaryKey(userPosition.getId()); log.error("【创建持仓】扣款失败,已回滚持仓记录", e); return ServerResponse.createByErrorMsg("生成持仓失败:" + e.getMessage()); } iAgentAgencyFeeService.AgencyFeeIncome(1, userPosition.getPositionSn()); return ServerResponse.createBySuccess("生成持仓成功"); @@ -2375,7 +2470,7 @@ userPosition.setOrderStayDays(1); userPosition.setOrderTotalPrice(userStockSubscribe.getBond()); // BigDecimal buy_fee_amt = buy_amt.multiply(siteSetting.getBuyFee()).setScale(2, 4); // BigDecimal buy_fee_amt = TradeFeeUtil.calcBuyFee(buy_amt).setScale(2, 4); BigDecimal buy_fee_amt = new BigDecimal(0); log.info("用戶購買手續費(配資後總資金 * 百分比) = {}", buy_fee_amt); userPosition.setOrderFee(buy_fee_amt); @@ -2649,11 +2744,10 @@ } int compareUserAmtInt = user_enable_amt.compareTo(buy_amt_autual); log.info("用戶可用金額 = {} 實際購買金額 = {}", user_enable_amt, buy_amt_autual); log.info("比較 用戶金額 和 實際 購買金額 = {}", Integer.valueOf(compareUserAmtInt)); if (compareUserAmtInt == -1) { return ServerResponse.createByErrorMsg("下单失败,融资可用金额小于" + buy_amt_autual + "元"); BigDecimal buy_fee_amt_dz = TradeFeeUtil.calcBuyFee(buy_amt); BigDecimal buy_debit_dz = TradeFeeUtil.calcBuyDebit(buy_amt_autual, buy_fee_amt_dz); if (user_enable_amt.compareTo(buy_debit_dz) == -1) { return ServerResponse.createByErrorMsg("下单失败,融资可用金额小于" + buy_debit_dz + "元(含保证金及手续费)"); } // if (user.getUserIndexAmt().compareTo(new BigDecimal("0")) == -1) { @@ -2690,7 +2784,7 @@ userPosition.setOrderStayDays(1); BigDecimal buy_fee_amt = buy_amt.multiply(siteSetting.getBuyFee()).setScale(2, 4); BigDecimal buy_fee_amt = buy_fee_amt_dz; log.info("用戶購買手續費(配資後總資金 * 百分比) = {}", buy_fee_amt); userPosition.setOrderFee(buy_fee_amt); @@ -2723,36 +2817,14 @@ log.info("--------------购买逻辑股票数据 buyDz stock------" + new Gson().toJson(userPosition)); int insertPositionCount = 0; this.userPositionMapper.insert(userPosition); insertPositionCount = userPosition.getId(); if (insertPositionCount > 0) { if (userPosition.getId() != null && userPosition.getId() > 0) { //修改大宗剩余 stockDz.setStockShare(stockDz.getStockShare() - num); stockDz.setStockSurplus(stockDz.getStockSurplus() + num); stockDzMapper.updateById(stockDz); //修改用戶可用余額= 當前余額-下單金額-買入手續費-印花稅-點差費 //BigDecimal reckon_enable = user_enable_amt.subtract(buy_amt_autual).subtract(buy_fee_amt).subtract(buy_yhs_amt).subtract(spread_rate_amt); //修改用戶可用余額= 當前余額-下單總金額 BigDecimal reckon_enable = user_enable_amt.subtract(buy_amt_autual); //修改用戶可取余額=當前可取余額-下單總金額 int compareUserWithdrawAmtInt = user_enable_withdraw_amt.compareTo(buy_amt_autual); if (compareUserWithdrawAmtInt == -1) { //若可取余額小於下單總額,但是可用余額充足,令可取余額為0 user.setEnaleWithdrawAmt(BigDecimal.ZERO); } else { user_enable_withdraw_amt = user_enable_withdraw_amt.subtract(buy_amt_autual); user.setEnaleWithdrawAmt(user_enable_withdraw_amt); } user.setEnableAmt(reckon_enable); int updateUserCount = this.userMapper.updateByPrimaryKeySelective(user); if (updateUserCount > 0) { log.info("【用戶交易下單】修改用戶金額成功"); } else { log.error("用戶交易下單】修改用戶金額出錯"); throw new Exception("用戶交易下單】修改用戶金額出錯"); } //核算代理收入-入倉手續費 deductUserEnableOnBuy(user, buy_debit_dz, buy_amt_autual, buy_fee_amt_dz, userPosition); syncUserCacheAfterTrade(request); iAgentAgencyFeeService.AgencyFeeIncome(1, userPosition.getPositionSn()); log.info("【用戶交易下單】保存持倉記錄成功"); } else { @@ -2980,11 +3052,10 @@ } int compareUserAmtInt = user_enable_amt.compareTo(buy_amt_autual); log.info("用戶可用金額 = {} 實際購買金額 = {}", user_enable_amt, buy_amt_autual); log.info("比較 用戶金額 和 實際 購買金額 = {}", Integer.valueOf(compareUserAmtInt)); if (compareUserAmtInt == -1) { return ServerResponse.createByErrorMsg("下單失敗,可用金額小於" + buy_amt_autual + "元"); BigDecimal buy_fee_amt = TradeFeeUtil.calcBuyFee(buy_amt); BigDecimal buy_debit = TradeFeeUtil.calcBuyDebit(buy_amt_autual, buy_fee_amt); if (user_enable_amt.compareTo(buy_debit) == -1) { return ServerResponse.createByErrorMsg("下單失敗,可用金額小於" + buy_debit + "元(含保证金及手续费)"); } // if (user.getUserIndexAmt().compareTo(new BigDecimal("0")) == -1) { @@ -3038,7 +3109,6 @@ userPosition.setOrderStayDays(1); BigDecimal buy_fee_amt = buy_amt.multiply(siteSetting.getBuyFee()).setScale(2, 4); log.info("用戶購買手續費(配資後總資金 * 百分比) = {}", buy_fee_amt); userPosition.setOrderFee(buy_fee_amt); @@ -3072,31 +3142,10 @@ log.info("--------------购买逻辑股票数据 buyVipQc stock------" + new Gson().toJson(userPosition)); int insertPositionCount = 0; this.userPositionMapper.insert(userPosition); insertPositionCount = userPosition.getId(); if (insertPositionCount > 0) { //修改用戶可用余額= 當前余額-下單金額-買入手續費-印花稅-點差費 //BigDecimal reckon_enable = user_enable_amt.subtract(buy_amt_autual).subtract(buy_fee_amt).subtract(buy_yhs_amt).subtract(spread_rate_amt); //修改用戶可用余額= 當前余額-下單總金額 BigDecimal reckon_enable = user_enable_amt.subtract(buy_amt_autual); //修改用戶可取余額=當前可取余額-下單總金額 int compareUserWithdrawAmtInt = user_enable_withdraw_amt.compareTo(buy_amt_autual); if (compareUserWithdrawAmtInt < 0) { //若可取余額小於下單總額,但是可用余額充足,令可取余額為0 user.setEnaleWithdrawAmt(BigDecimal.ZERO); } else { user_enable_withdraw_amt = user_enable_withdraw_amt.subtract(buy_amt_autual); user.setEnaleWithdrawAmt(user_enable_withdraw_amt); } user.setEnableAmt(reckon_enable); int updateUserCount = this.userMapper.updateByPrimaryKeySelective(user); if (updateUserCount > 0) { log.info("【用戶交易下單】修改用戶金額成功"); } else { log.error("用戶交易下單】修改用戶金額出錯"); throw new Exception("用戶交易下單】修改用戶金額出錯"); } if (userPosition.getId() != null && userPosition.getId() > 0) { deductUserEnableOnBuy(user, buy_debit, buy_amt_autual, buy_fee_amt, userPosition); syncUserCacheAfterTrade(request); //核算代理收入-入倉手續費 //iAgentAgencyFeeService.AgencyFeeIncome(1, userPosition.getPositionSn()); log.info("【用戶交易下單】保存持倉記錄成功"); src/main/java/com/nq/service/impl/UserServiceImpl.java
@@ -310,18 +310,11 @@ stock.setStockName(stockFutures.getFuturesName()); stock.setIsLock(0); } } else if(code.contains("sh") || code.contains("sz")){ return ServerResponse.createByErrorMsg("添加失败,指数不支持自选"); // StockIndex stockIndex = this.stockIndexMapper.selectIndexByCode(stockcode); // if(stockIndex != null){ // stock.setId(stockIndex.getId()); // stock.setStockCode(stockIndex.getIndexCode()); // stock.setStockGid(stockIndex.getIndexGid()+"zs"); // stock.setStockName(stockIndex.getIndexName()); // stock.setIsLock(0); // } } else { stock = this.stockMapper.findStockByCode(code); stock = this.stockMapper.findStockByCode(stockcode); if (stock == null && !code.equals(stockcode)) { stock = this.stockMapper.findStockByCode(code); } } if (stock == null) { return ServerResponse.createByErrorMsg("添加失败,股票不存在"); @@ -400,6 +393,26 @@ return ServerResponse.createBySuccess(userInfoVO); } @Override public void syncUserCache(HttpServletRequest request) { if (request == null) { return; } String cookieName = PropertiesUtil.getProperty("user.cookie.name"); String loginToken = request.getHeader(cookieName); if (StringUtils.isBlank(loginToken)) { return; } String userJson = RedisShardedPoolUtils.get(loginToken); User cached = (User) JsonUtil.string2Obj(userJson, User.class); if (cached == null || cached.getId() == null) { return; } User dbUser = this.userMapper.selectByPrimaryKey(cached.getId()); if (dbUser != null) { RedisShardedPoolUtils.setEx(loginToken, JsonUtil.obj2String(dbUser), 9999); } } public ServerResponse updatePwd(String oldPwd, String newPwd, HttpServletRequest request) { if (StringUtils.isBlank(oldPwd) || StringUtils.isBlank(newPwd)) { @@ -1874,10 +1887,20 @@ BigDecimal allProfitAndLose = positionVO.getAllProfitAndLose(); userInfoVO.setAllProfitAndLose(allProfitAndLose); // BigDecimal userAllAmt = user.getUserAmt(); BigDecimal userAllAmt = user.getEnableAmt(); userAllAmt = userAllAmt.add(allProfitAndLose); // 账户总资产 = 两融可用 + 冻结保证金 + 浮动盈亏 // 浮动盈亏里已扣过买入手续费,而买入手续费下单时已从 enableAmt 扣除,此处加回 openBuyFees 避免总资产「少扣手续费」 BigDecimal allFreezAmt = positionVO.getAllFreezAmt() == null ? BigDecimal.ZERO : positionVO.getAllFreezAmt(); BigDecimal enableAmt = user.getEnableAmt() == null ? BigDecimal.ZERO : user.getEnableAmt(); BigDecimal openBuyFees = BigDecimal.ZERO; List<UserPosition> openPositions = this.iUserPositionService.findPositionByUserIdAndSellIdIsNull(user.getId()); if (openPositions != null) { for (UserPosition position : openPositions) { if (position.getOrderFee() != null) { openBuyFees = openBuyFees.add(position.getOrderFee()); } } } BigDecimal userAllAmt = enableAmt.add(allFreezAmt).add(allProfitAndLose).add(openBuyFees); userInfoVO.setEnableIndexAmt(user.getEnableIndexAmt()); userInfoVO.setEnaleWithdrawAmt(user.getEnaleWithdrawAmt()); @@ -1897,8 +1920,7 @@ } } userInfoVO.setBuyAmtAutual(buyAmtAutual); userAllAmt = userAllAmt.add(buyAmtAutual); userInfoVO.setUserAmt(userAllAmt); userInfoVO.setUserAmt(userAllAmt.setScale(2, RoundingMode.HALF_UP)); List<UserPosition> userPositions = this.userPositionMapper.findMyPositionByCodeAndSpell(user.getId(), "", "", 2); src/main/java/com/nq/service/impl/UserStockSubscribeServiceImpl.java
@@ -814,7 +814,7 @@ userPosition.setOrderStayDays(1); BigDecimal buy_fee_amt = buy_amt.multiply(siteSetting.getBuyFee()).setScale(2, 4); BigDecimal buy_fee_amt = com.nq.utils.TradeFeeUtil.calcBuyFee(buy_amt); log.info("创建模拟持仓 手续费(配资后总资金 * 百分比) = {}", buy_fee_amt); userPosition.setOrderFee(buy_fee_amt); src/main/java/com/nq/utils/stock/sina/SinaStockApi.java
@@ -37,17 +37,25 @@ public static String getSinaStock(String stockGid) { String sina_result = ""; try { // System.out.println(sina_url + stockGid); // sina_result = HttpClientRequest.doGet(sina_url + stockGid); // System.out.println("请求返回:"+sina_result); System.out.println(PropertiesUtil.getProperty("sina.single.stock.proxy.url") + stockGid); sina_result = HttpClientRequest.doGet(PropertiesUtil.getProperty("sina.single.stock.proxy.url") + stockGid); System.out.println("请求返回:"+sina_result); // sina_result = "var hq_str_sz300270=\"中威电子,0.000,11.710,0.000,0.000,0.000,0.000,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,2025-12-03,09:10:06,00\";"; System.out.println("请求返回:" + sina_result); } catch (Exception e) { log.error("获取股票行情出错,错误信息 = {}", e); log.error("获取股票行情出错,gid={},错误信息 = {}", stockGid, e); } return sina_result.substring(sina_result.indexOf("=") + 2); if (StringUtils.isBlank(sina_result) || !sina_result.contains("=")) { log.warn("新浪行情返回为空或格式异常, gid={}, raw={}", stockGid, StringUtils.abbreviate(sina_result, 200)); return ""; } String body = sina_result.substring(sina_result.indexOf("=") + 2); return body.replace("\"", "").replace(";", "").trim(); } private static String hqField(String[] hqarr, int index) { if (hqarr == null || index < 0 || index >= hqarr.length) { return "0"; } return StringUtils.defaultIfBlank(hqarr[index], "0"); } @@ -198,57 +206,57 @@ public static StockVO assembleStockVO(String sinaResult) { StockVO stockVO = new StockVO(); if (StringUtils.isBlank(sinaResult)) { return stockVO; } String[] hqarr = sinaResult.split(","); if (hqarr.length < 4) { log.warn("新浪行情字段不足,无法解析,length={}, raw={}", hqarr.length, StringUtils.abbreviate(sinaResult, 200)); return stockVO; } stockVO.setName(hqarr[0]); stockVO.setNowPrice(hqarr[3]); stockVO.setName(hqField(hqarr, 0)); stockVO.setNowPrice(hqField(hqarr, 3)); BigDecimal chang_rate = new BigDecimal("0"); if ((new BigDecimal(hqarr[2])).compareTo(new BigDecimal("0")) != 0 && new BigDecimal(hqarr[3]).compareTo(new BigDecimal("0")) != 0) { chang_rate = (new BigDecimal(hqarr[3])).subtract(new BigDecimal(hqarr[2])); chang_rate = chang_rate.multiply(new BigDecimal("100")).divide(new BigDecimal(hqarr[2]), 2, RoundingMode.HALF_UP); BigDecimal preclose = new BigDecimal(hqField(hqarr, 2)); BigDecimal now = new BigDecimal(hqField(hqarr, 3)); if (preclose.compareTo(BigDecimal.ZERO) != 0 && now.compareTo(BigDecimal.ZERO) != 0) { chang_rate = now.subtract(preclose); chang_rate = chang_rate.multiply(new BigDecimal("100")).divide(preclose, 2, RoundingMode.HALF_UP); } stockVO.setHcrate(chang_rate); stockVO.setToday_max(hqarr[4]); stockVO.setToday_max(hqField(hqarr, 4)); stockVO.setToday_min(hqField(hqarr, 5)); stockVO.setBusiness_amount(hqField(hqarr, 8)); stockVO.setBusiness_balance(hqField(hqarr, 9)); stockVO.setPreclose_px(hqField(hqarr, 2)); stockVO.setOpen_px(hqField(hqarr, 1)); stockVO.setToday_min(hqarr[5]); stockVO.setBuy1(hqField(hqarr, 6)); stockVO.setBuy2(hqField(hqarr, 13)); stockVO.setBuy3(hqField(hqarr, 15)); stockVO.setBuy4(hqField(hqarr, 17)); stockVO.setBuy5(hqField(hqarr, 19)); stockVO.setBusiness_amount(hqarr[8]); stockVO.setSell1(hqField(hqarr, 7)); stockVO.setSell2(hqField(hqarr, 23)); stockVO.setSell3(hqField(hqarr, 25)); stockVO.setSell4(hqField(hqarr, 27)); stockVO.setSell5(hqField(hqarr, 29)); stockVO.setBusiness_balance(hqarr[9]); stockVO.setBuy1_num(hqField(hqarr, 10)); stockVO.setBuy2_num(hqField(hqarr, 12)); stockVO.setBuy3_num(hqField(hqarr, 14)); stockVO.setBuy4_num(hqField(hqarr, 16)); stockVO.setBuy5_num(hqField(hqarr, 18)); stockVO.setPreclose_px(hqarr[2]); stockVO.setOpen_px(hqarr[1]); stockVO.setBuy1(hqarr[6]); stockVO.setBuy2(hqarr[13]); stockVO.setBuy3(hqarr[15]); stockVO.setBuy4(hqarr[17]); stockVO.setBuy5(hqarr[19]); stockVO.setSell1(hqarr[7]); stockVO.setSell2(hqarr[23]); stockVO.setSell3(hqarr[25]); stockVO.setSell4(hqarr[27]); stockVO.setSell5(hqarr[29]); stockVO.setBuy1_num(hqarr[10]); stockVO.setBuy2_num(hqarr[12]); stockVO.setBuy3_num(hqarr[14]); stockVO.setBuy4_num(hqarr[16]); stockVO.setBuy5_num(hqarr[18]); stockVO.setSell1_num(hqarr[20]); stockVO.setSell2_num(hqarr[22]); stockVO.setSell3_num(hqarr[24]); stockVO.setSell4_num(hqarr[26]); stockVO.setSell5_num(hqarr[28]); stockVO.setSell1_num(hqField(hqarr, 20)); stockVO.setSell2_num(hqField(hqarr, 22)); stockVO.setSell3_num(hqField(hqarr, 24)); stockVO.setSell4_num(hqField(hqarr, 26)); stockVO.setSell5_num(hqField(hqarr, 28)); return stockVO; } src/main/resources/application.properties
@@ -217,7 +217,16 @@ #????? website.domain.url=http://www.huijuwang888.com # Ococn ?? ococn.pay.pid=185583446 ococn.pay.key=JcMJIbNUAcq0GyMf ococn.pay.url=https://pay.ococn.cn/submit.php ococn.pay.sitename= ococn.pay.name=账户充值 ococn.pay.frontend_redirect=https://www.zhonghenginvest.com/#/user website.domain.url=https://api.zhonghenginvest.com frontend.domain.url=https://www.zhonghenginvest.com website.token=0DC8F78384C7AAFF3192A9C60A473FEE7F89C62888689616B98A06910E86B510 #?????