update 租赁系统11-14 一订单对应多个卖家需求完成

This commit is contained in:
yyb
2025-11-14 11:41:39 +08:00
parent 0fff57492e
commit 20fcfa778e
83 changed files with 2610 additions and 1030 deletions

View File

@@ -0,0 +1,64 @@
package com.m2pool.common.security.interceptor;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.util.stream.Collectors;
public class AuthRequestWrapper extends HttpServletRequestWrapper {
private String body;
public AuthRequestWrapper(HttpServletRequest request) {
super(request);
try(BufferedReader reader = request.getReader()){
body= reader.lines().collect(Collectors.joining());
}catch (Exception e){
System.out.println("!!-- read request from requestbody error"+e.getMessage());
}
}
@Override
public BufferedReader getReader() {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream byteArrayIns = new ByteArrayInputStream(body.getBytes());
ServletInputStream servletIns = new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() {
return byteArrayIns.read();
}
};
return servletIns;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
}

View File

@@ -0,0 +1,66 @@
package com.m2pool.common.security.interceptor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
@Component
public class CoinInterceptor implements HandlerInterceptor {
private final ObjectMapper objectMapper = new ObjectMapper();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("调用Coin拦截器1:" + request);
// 仅处理 POST、PUT 等有请求体的请求方法
if ("POST".equalsIgnoreCase(request.getMethod()) || "PUT".equalsIgnoreCase(request.getMethod())) {
try {
// 读取请求体内容
if (request instanceof AuthRequestWrapper){
//BufferedReader reader = request.getReader();
//System.out.println("调用Coin拦截器2:" + reader);
//
//if (!requestBody.isEmpty()) {
// // 反序列化请求体为 RequestObject 对象
// RequestObject requestObject = objectMapper.readValue(requestBody, RequestObject.class);
// System.out.println("调用Coin拦截器3:" + requestObject.toString());
// String coin = requestObject.getCoin();
// System.out.println("调用Coin拦截器4:" + coin);
// if ("enx".equals(coin)) {
// response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
// response.getWriter().write("enx币种已下架");
// return false;
// }
//}
}
} catch (Exception e) {
// 处理反序列化异常
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.getWriter().write("请求体解析失败");
return false;
}
}
return true;
}
/**
* 读取请求体内容
*/
private String readRequestBody(HttpServletRequest request) throws IOException {
StringBuilder stringBuilder = new StringBuilder();
try (BufferedReader reader = request.getReader()) {
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
}
}
return stringBuilder.toString();
}
}

View File

@@ -0,0 +1,27 @@
package com.m2pool.common.security.interceptor;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
@Component
@WebFilter("/*")
public class RequestBodyFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
request = new AuthRequestWrapper(request);
filterChain.doFilter(request,response);
}
}

View File

@@ -0,0 +1,16 @@
package com.m2pool.common.security.interceptor;
import com.fasterxml.jackson.annotation.JsonProperty;
public class RequestObject {
private String coin;
// 添加 getter 和 setter 方法
public String getCoin() {
return coin;
}
public void setCoin(String coin) {
this.coin = coin;
}
}

View File

@@ -14,6 +14,7 @@ import java.util.List;
public enum CoinCharge {
ETH_USDT("ETH","USDT", BigDecimal.valueOf(1)),
ETH_ETH("ETH","USDT", BigDecimal.valueOf(0.0001)),
TRON_USDT("TRON","USDT", BigDecimal.valueOf(1)),
TRON_NEXA("TRON","NEXA", BigDecimal.valueOf(1000));

View File

@@ -28,9 +28,9 @@ public class PowerUnit {
HashMap<String, BigDecimal> map = new HashMap<>();
map.put(KH_UNIT, BigDecimal.valueOf(1000));
map.put(MH_UNIT, BigDecimal.valueOf(1000 * 1000));
map.put(GH_UNIT, BigDecimal.valueOf(1000L * 1000 * 1000 * 1000));
map.put(TH_UNIT, BigDecimal.valueOf(1000L * 1000 * 1000 * 1000 * 1000));
map.put(PH_UNIT, BigDecimal.valueOf(1000L * 1000 * 1000 * 1000 * 1000 * 1000));
map.put(GH_UNIT, BigDecimal.valueOf(1000L * 1000 * 1000));
map.put(TH_UNIT, BigDecimal.valueOf(1000L * 1000 * 1000 * 1000 ));
map.put(PH_UNIT, BigDecimal.valueOf(1000L * 1000 * 1000 * 1000 * 1000));
UNIT_MAP = Collections.unmodifiableMap(map);
}

View File

@@ -4,10 +4,7 @@ package com.m2pool.lease.controller;
import com.m2pool.lease.dto.*;
import com.m2pool.lease.service.LeaseProductService;
import com.m2pool.lease.service.LeaseUserOwnedProductService;
import com.m2pool.lease.vo.BaseVo;
import com.m2pool.lease.vo.ProductPageVo;
import com.m2pool.lease.vo.ProductURDVo;
import com.m2pool.lease.vo.UserOwnedProductVo;
import com.m2pool.lease.vo.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
@@ -17,6 +14,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
/**
* <p>
@@ -56,8 +54,14 @@ public class LeaseProductController {
@ApiOperation("查询单个商品详情(包含商品对应的售卖机器详情列表)")
@PostMapping("/getMachineInfo")
public Result<ProductMachineInfoDto> getProductMachineInfo(@RequestBody BaseVo BaseVo) {
return leaseProductService.getProductMachineInfo(BaseVo.getId());
public PageResult<ProductMachineDto> getProductMachineInfo(@RequestBody ProductMachineVo productMachineVo) {
return leaseProductService.getProductMachineInfo(productMachineVo);
}
@ApiOperation("单个商品矿机列表页面---获取支付方式")
@PostMapping("/getPayTypes")
public Result<List<PayConfigDto>> getPayTypes() {
return leaseProductService.getPayTypes();
}
@@ -96,5 +100,26 @@ public class LeaseProductController {
public Result<UserOwnedProductDto> getOwnedById(@RequestBody BaseVo baseVo) {
return leaseUserOwnedProductService.getOwnedById(baseVo);
}
@ApiOperation("查询用户店铺支持的支付方式")
@PostMapping("/getSupportPayType")
@Deprecated
public Result<List<PayTypeDto>> getSupportPayType() {
return leaseProductService.getSupportPayType();
}
@ApiOperation("获取店铺商品列表用于新增绑定店铺钱包")
@PostMapping("/getProductListForShopWalletConfig")
public Result<List<ProductForWalletConfigDto>> getProductListForShopWalletConfig() {
return leaseProductService.getProductListForShopWalletConfig();
}
@ApiOperation("新增绑定店铺钱包并设置店铺下面每个矿机该钱包币种的售价 + 钱包绑定")
@PostMapping("/updateProductListForShopWalletConfig")
public Result<String> updateProductListForShopWalletConfig(@RequestBody ProductMachineForWalletConfigVo productMachineForWalletConfigVo) {
return leaseProductService.updateProductListForShopWalletConfig(productMachineForWalletConfigVo);
}
}

View File

@@ -1,8 +1,10 @@
package com.m2pool.lease.controller;
import com.m2pool.common.security.annotation.RequiresLogin;
import com.m2pool.lease.dto.*;
import com.m2pool.lease.dto.PageResult;
import com.m2pool.lease.dto.ProductUpdateMachineDto;
import com.m2pool.lease.dto.Result;
import com.m2pool.lease.dto.UserMinerDto;
import com.m2pool.lease.service.LeaseProductMachineService;
import com.m2pool.lease.vo.*;
import io.swagger.annotations.Api;

View File

@@ -121,8 +121,9 @@ public class LeaseShopController {
* @param shopConfigVo 商铺配置信息
* @return 操作结果
*/
@ApiOperation("钱包配置---新增商铺收款钱包绑定配置")
@ApiOperation("钱包配置---新增商铺收款钱包绑定配置(弃用,业务移到/product/updateProductListForShopWalletConfig 接口)")
@PostMapping("/addShopConfig")
@Deprecated
public Result<String> addShopConfig(@RequestBody ShopConfigVo shopConfigVo) {
return leaseShopService.addShopConfig(shopConfigVo);
}

View File

@@ -0,0 +1,58 @@
package com.m2pool.lease.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.util.Objects;
/**
* <p>
* 余额提现请求对象
* </p>
*
* @author yyb
* @since 2025-07-23
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ChainAndCoinDto {
private String coin;
private String chain;
private Long shopId;
public ChainAndCoinDto( String coin,String chain) {
this.chain = chain;
this.coin = coin;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ChainAndCoinDto that = (ChainAndCoinDto) o;
return Objects.equals(coin, that.coin) && Objects.equals(chain, that.chain) && Objects.equals(shopId, that.shopId);
}
@Override
public int hashCode() {
return Objects.hash(coin, chain,shopId);
}
@Override
public String toString() {
return "ChainAndCoinDto{" +
"coin='" + coin + '\'' +
", chain='" + chain + '\'' +
", shopId='" + shopId + '\'' +
'}';
}
}

View File

@@ -0,0 +1,41 @@
package com.m2pool.lease.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* <p>
* 矿机售价配置返回对象
* </p>
*
* @author yyb
* @since 2025-07-23
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "矿机售价配置返回对象",value = "MachinePayTypeDto" )
public class MachinePayTypeDto {
@ApiModelProperty(value = "矿机币种售价配置id")
private Long payTypeId;
@ApiModelProperty(value = "矿机id忽略")
private Long productMachineId;
@ApiModelProperty(value = "售价")
private BigDecimal price;
@ApiModelProperty(value = "")
private String chain;
@ApiModelProperty(value = "售价单位币种")
private String coin;
}

View File

@@ -0,0 +1,34 @@
package com.m2pool.lease.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
* <p>
* 矿机售价配置返回对象
* </p>
*
* @author yyb
* @since 2025-07-23
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "购物车矿机总价返回对象",value = "MachineTotalPriceDto" )
public class MachineTotalPriceDto {
@ApiModelProperty(value = "售价")
private BigDecimal price;
@ApiModelProperty(value = "")
private String chain;
@ApiModelProperty(value = "售价单位币种")
private String coin;
}

View File

@@ -0,0 +1,37 @@
package com.m2pool.lease.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @Description 店铺支持的支付方式
* @Date 2024/6/14 15:57
* @Author dy
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "店铺支持的支付方式",value = "PayTypeDto")
public class PayTypeDto {
@ApiModelProperty(value = "店铺id(不展示)")
private Long shopId;
@ApiModelProperty(value = "")
private String chain;
@ApiModelProperty(value = "支付币种")
private String coin;
@ApiModelProperty(value = "支付币种图标")
private String image;
}

View File

@@ -27,14 +27,15 @@ public class ProductDto {
@ApiModelProperty(value = "商品id")
private Long id;
/**
* 店铺id
*/
@ApiModelProperty(value = "店铺id")
private Long shopId;
@ApiModelProperty(value = "店铺名称")
private String shopName;
/**
* 商品名称
*/
@@ -59,19 +60,18 @@ public class ProductDto {
@ApiModelProperty(value = "上下架状态0 上架1 下架")
private Integer state;
/**
* 商品机器单机算力(卖方手动填写)
*/
//@ApiModelProperty(value = "商品机器单机理论算力(卖方手动填写)")
//private BigDecimal power;
/**
* 库存中机器价格范围
*/
@ApiModelProperty(value = "价格范围")
@Deprecated
private String priceRange;
@ApiModelProperty(value = "店铺支持的支付方式")
private List<PayTypeDto> payTypes;
/**
* 算法
*/
@@ -83,34 +83,6 @@ public class ProductDto {
*/
@ApiModelProperty(value = "商品描述")
private String description;
/**
* 功耗 单位kw/h
*/
//@ApiModelProperty(value = "功耗 单位kw/h")
//private BigDecimal powerDissipation;
/**
* 电费 单位 $/度
*/
//@ApiModelProperty(value = "电费 单位 $/度")
//private BigDecimal electricityBill;
/**
* 收益率 单位 %
*/
//@ApiModelProperty(value = "收益率 单位 %")
//private BigDecimal incomeRate;
/**
* 机器成本价格单位$ [ 功耗 * 电费 * 24 * (1 + 收益率) ]
*/
//@ApiModelProperty(value = "机器成本价格单位$ [ 功耗 * 电费 * 24 * (1 + 收益率) ]")
// private BigDecimal cost;
/**
* 矿机挖矿币种 nexa rxd dgbo dgbq dgbs alph enx grs mona
*/

View File

@@ -0,0 +1,71 @@
package com.m2pool.lease.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* <p>
* 钱包配置修改商品支付方式返回对象
* </p>
*
* @author yyb
* @since 2025-07-23
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "钱包配置修改商品支付方式返回对象",value = "ProductForWalletConfigDto" )
public class ProductForWalletConfigDto {
@ApiModelProperty(value = "商品id")
private Long productId;
/**
* 商品名称
*/
@ApiModelProperty(value = "商品名称")
private String name;
/**
* 商品图片路径
*/
@ApiModelProperty(value = "商品图片路径")
private String image;
/**
* 上下架状态0 上架1 下架
*/
@ApiModelProperty(value = "上下架状态0 上架1 下架")
private Integer state;
/**
* 算法
*/
@ApiModelProperty(value = "算法")
private String algorithm;
/**
* 商品描述
*/
@ApiModelProperty(value = "商品描述")
private String description;
/**
* 矿机挖矿币种 nexa rxd dgbo dgbq dgbs alph enx grs mona
*/
@ApiModelProperty(value = "矿机挖矿币种 nexa rxd dgbo dgbq dgbs alph enx grs mona")
private String coin;
/**
* 总矿机数
*/
@ApiModelProperty(value = "总矿机数(已售 + 未售出矿机)")
private Integer totalMachineNumber;
@ApiModelProperty(value = "矿机列表")
private List<ProductMachineForWalletConfigDto> machineList;
}

View File

@@ -9,6 +9,7 @@ import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
/**
* <p>
@@ -56,7 +57,6 @@ public class ProductMachineDto {
@ApiModelProperty(value = "挖矿机器编号")
private String miner;
/**
* 单价
*/
@@ -109,12 +109,6 @@ public class ProductMachineDto {
@ApiModelProperty(value = "租赁天数")
private Integer leaseTime;
/**
* 单机预估实际收入
*/
//@ApiModelProperty(value = "单机预估实际收入(每日)")
//private BigDecimal actualIncome;
@ApiModelProperty(value = "算法")
private String algorithm;
@@ -124,7 +118,7 @@ public class ProductMachineDto {
@ApiModelProperty(value = "最大可租借天数(默认七天)",example = "7")
private Integer maxLeaseDays;
@ApiModelProperty(value = "币种")
@ApiModelProperty(value = "挖矿机器挖矿币种")
private String coin;
@ApiModelProperty(value = "商品名称")
@@ -132,4 +126,11 @@ public class ProductMachineDto {
@ApiModelProperty(value = "是否删除 0否 1是")
private Integer del;
@ApiModelProperty(value = "支付币种")
private String payCoin;
@ApiModelProperty(value = "售价集合")
private List<MachinePayTypeDto> priceList;
}

View File

@@ -0,0 +1,105 @@
package com.m2pool.lease.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* <p>
* 商品对应实际商品返回对象
* </p>
*
* @author yyb
* @since 2025-07-23
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "钱包配置修改矿机支付方式返回对象",value = "ProductMachineForWalletConfigDto" )
public class ProductMachineForWalletConfigDto {
@ApiModelProperty(value = "矿机ID")
private Long productMachineId;
@ApiModelProperty(value = "商品ID")
private Long productId;
/**
* 挖矿机器 对应的矿工账号
*/
@ApiModelProperty(value = "挖矿机器 对应的矿工账号")
private String user;
/**
* 挖矿机器型号
*/
@ApiModelProperty(value = "挖矿机器型号")
private String type;
/**
* 挖矿机器编号
*/
@ApiModelProperty(value = "挖矿机器编号")
private String miner;
@ApiModelProperty(value = "挖矿币种")
private String coin;
///**
// * 实际算力(计算得到,商家不能够自己添加和修改)
// */
//@ApiModelProperty(value = "3天算力平均大小---实际实时算力(计算得到,商家不能够自己添加和修改)")
//private BigDecimal computingPower;
@ApiModelProperty(value = "算力单位")
private String unit;
/**
* 上下架状态0 上架1 下架
*/
@ApiModelProperty(value = "上下架状态0 上架1 下架")
private Integer state;
/**
* 售出状态 0未售出 1已售出 2售出中
*/
@ApiModelProperty(value = "售出状态 0未售出 1已售出 2售出中")
private Integer saleState;
/**
* 理论算力
*/
@ApiModelProperty(value = "理论算力(卖方手动填写)")
private BigDecimal theoryPower;
@ApiModelProperty(value = "单机理论收入(每日) 单位币种")
private BigDecimal theoryIncome;
@ApiModelProperty(value = "单机理论收入(每日) 单位USDT")
private BigDecimal theoryUsdtIncome;
@ApiModelProperty(value = "功耗 单位kw/h",example = "10")
private BigDecimal powerDissipation;
/**
* 单价
*/
@ApiModelProperty(value = "单价")
private BigDecimal price;
@ApiModelProperty(value = "支付链")
private BigDecimal chain;
@ApiModelProperty(value = "支付币种")
private BigDecimal symbol;
}

View File

@@ -0,0 +1,50 @@
package com.m2pool.lease.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.util.List;
/**
* <p>
* 商品对应实际商品返回对象
* </p>
*
* @author yyb
* @since 2025-07-23
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "钱包配置修改矿机支付方式请求对象",value = "ProductMachineForWalletConfigVo" )
public class ProductMachineForWalletConfigVo {
@ApiModelProperty(value = "钱包地址")
private String payAddress;
@ApiModelProperty(value = "支付链")
private String chain;
@ApiModelProperty(value = "支付币种,可以多个以逗号隔开")
private String symbol;
@ApiModelProperty(value = "价格列表")
private List<PriceVo> productMachineForWalletConfigVoList;
@Data
@ApiModel(description = "币(二级) 下拉列表返回对象",value = "PriceVo")
public static class PriceVo{
@ApiModelProperty(value = "矿机ID")
private Long productMachineId;
@ApiModelProperty(value = "单价,可以多个以逗号隔开")
private String price;
}
}

View File

@@ -31,4 +31,6 @@ public class ProductMachineInfoDto {
@ApiModelProperty(value = "矿机范围及矿机详情返回对象")
private List<ProductMachineRangeInfoDto> machineRangeInfoList;
}

View File

@@ -9,6 +9,7 @@ import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
/**
* <p>
@@ -50,8 +51,8 @@ public class ProductUpdateMachineDto {
/**
* 单价
*/
@ApiModelProperty(value = "单价")
private BigDecimal price;
@ApiModelProperty(value = "售价集合")
private List<MachinePayTypeDto> priceList;
/**
* 实际算力(计算得到,商家不能够自己添加和修改)
@@ -59,7 +60,6 @@ public class ProductUpdateMachineDto {
@ApiModelProperty(value = "3天算力平均大小---实际实时算力(计算得到,商家不能够自己添加和修改)")
private BigDecimal computingPower;
/**
* 理论算力
*/

View File

@@ -38,12 +38,12 @@ public class ShopCartDto {
@ApiModelProperty(value = "店铺下机器总数")
private Integer totalMachine;
@ApiModelProperty(value = "总价集合")
private List<MachineTotalPriceDto> totalPriceList;
@ApiModelProperty(value = "商品支持的支付地址")
private List<PayConfigDto> payConfigList;
//@ApiModelProperty(value = "购物车二层商品列表返回对象")
//List<ShoppingCartInfoDto> shoppingCartInfoDtoList;
@ApiModelProperty(value = "商品机器列表")
List<ProductMachineDto> productMachineDtoList;
}

View File

@@ -21,52 +21,20 @@ import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "购物车二层商品列表返回对象",value = "ShoppingCartInfoDto" )
@ApiModel(description = "购物车二层商品列表返回对象(不再使用)",value = "ShoppingCartInfoDto" )
public class ShoppingCartInfoDto {
/**
* ID
*/
//@ApiModelProperty(value = "购物车详情ID")
//private Long id;
@ApiModelProperty(value = "店铺ID",example = "8")
private Long shopId;
/**
* 商品 ID
*/
@ApiModelProperty(value = "商品 ID")
private Long productId;
/**
* 商品机器ID
*/
@ApiModelProperty(value = "商品机器ID")
private Long productMachineId;
/**
* 商品名称
* 租期
*/
@ApiModelProperty(value = "商品名称")
private String name;
/**
* 商品上下架状态0 上架1 下架
*/
@ApiModelProperty(value = "商品上下架状态0 上架1 下架")
private Integer productState;
@ApiModelProperty(value = "矿机挖矿币种 nexa rxd dgbo dgbq dgbs alph enx grs mona",example = "nexa")
private String coin;
@ApiModelProperty(value = "商品图片路径")
private String image;
@ApiModelProperty(value = "商品机器列表")
List<ProductMachineDto> productMachineDtoList;
private Integer leaseTime;
}

View File

@@ -0,0 +1,46 @@
package com.m2pool.lease.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.*;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* <p>
* 订单手续费表
* </p>
*
* @author yyb
* @since 2025-07-23
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class LeaseOrderFee implements Serializable {
private static final long serialVersionUID=1L;
/**
* 订单 ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
private Long orderId;
private BigDecimal fee;
private String toAddress;
private Boolean status;
}

View File

@@ -1,6 +1,7 @@
package com.m2pool.lease.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.*;
@@ -65,5 +66,12 @@ public class LeaseOrderInfo implements Serializable {
*/
private Boolean del;
/**
* 手续费
*/
private BigDecimal fee;
@TableField(exist = false)
private String chainAndCoinKey;
}

View File

@@ -153,6 +153,21 @@ public class LeaseOrderItem implements Serializable {
*/
private String image;
/**
* 已支付金额
*/
private BigDecimal alreadyPayAmount;
/**
* 已支付金额(真实)
*/
private BigDecimal alreadyPayRealAmount;
/**
* 当日待支付确认金额
*/
private BigDecimal settlePayRealAmount;
/**
* 商品类型 0 矿机 1 算力
*/

View File

@@ -92,4 +92,14 @@ public class LeasePayRechargeMessage implements Serializable {
*/
private Boolean del;
/**
* 区块高度
*/
private Long blockHeight;
/**
* 充值来源地址(用户自己的钱包
*/
private String fromAddress;
}

View File

@@ -46,6 +46,12 @@ public class LeasePayRecordMessage implements Serializable {
*/
private String toAddress;
/**
* 订单id
*/
private String orderId;
/**
* 订单号
*/
@@ -108,10 +114,6 @@ public class LeasePayRecordMessage implements Serializable {
private Long blockHeight;
/**
* 订单id
*/
private String orderId;
/**
* 支付时间

View File

@@ -102,4 +102,9 @@ public class LeasePayWithdrawMessage implements Serializable {
*/
private Boolean del;
/**
* 区块高度
*/
private Long blockHeight;
}

View File

@@ -1,6 +1,7 @@
package com.m2pool.lease.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
@@ -8,6 +9,7 @@ import lombok.*;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.concurrent.atomic.AtomicInteger;
/**
* <p>
@@ -142,4 +144,7 @@ public class LeaseProductMachine implements Serializable {
private BigDecimal incomeRate;
private Integer maxLeaseDays;
@TableField(exist = false)
private Integer updateCount;
}

View File

@@ -0,0 +1,41 @@
package com.m2pool.lease.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.*;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* <p>
* 商品表对应的物品机器表
* </p>
*
* @author yyb
* @since 2025-07-23
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class LeaseProductMachinePrice implements Serializable {
private static final long serialVersionUID=1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
private Long productMachineId;
private BigDecimal price;
private String coin;
private String chain;
}

View File

@@ -30,6 +30,7 @@ public class LeaseShoppingCartInfo implements Serializable {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 购物车ID
*/

View File

@@ -0,0 +1,26 @@
package com.m2pool.lease.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.m2pool.lease.dto.OrderStatusDto;
import com.m2pool.lease.entity.LeaseOrderFee;
import com.m2pool.lease.entity.LeaseOrderItem;
import com.m2pool.lease.entity.LeasePaymentRecord;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Set;
/**
* <p>
* 订单明细表 Mapper 接口
* </p>
*
* @author yyb
* @since 2025-07-23
*/
@Mapper
public interface LeaseOrderFeeMapper extends BaseMapper<LeaseOrderFee> {
}

View File

@@ -4,9 +4,11 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.m2pool.lease.dto.OrderStatusDto;
import com.m2pool.lease.entity.LeaseOrderItem;
import com.m2pool.lease.entity.LeasePaymentRecord;
import com.m2pool.lease.mq.message.RabbitmqPayAutoReturnInfoMessage;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.transaction.Transaction;
import java.util.List;
import java.util.Map;
@@ -51,4 +53,22 @@ public interface LeaseOrderItemMapper extends BaseMapper<LeaseOrderItem> {
*/
List<Long> selectOrderInfoIds(@Param("itemIds") Set<Long> itemIds);
/**
* 获取需要更新已实际支付总金额的订单详情
* @param address
* @param transaction
* @return
*/
List<LeaseOrderItem> getNeedUpdateOrderItem(@Param("orderId") Long orderId);
/**
* 通过订单id找到订单详情
* @param orderIds
* @return
*/
List<LeaseOrderItem> getOrderItemByOrderIds(@Param("orderIds") Set<Long> orderIds);
}

View File

@@ -64,19 +64,19 @@ public interface LeasePayRecordMessageMapper extends BaseMapper<LeasePayRecordMe
List<RecentlyTransactionDto> getRecentlyTransaction(@Param("walletList") List<LeaseUserWalletData> walletList);
/**
* 根据订单id 查询当天支付状态
* @param orderInfoIds
* @return
*/
@MapKey("orderId")
Map<Long,LeasePayRecordMessage> selectOrderInfoMap(@Param("orderInfoIds") Set<Long> orderInfoIds);
/**
* 保存或者更新根据txHash
* @param leasePayRecordMessage
* @return
*/
int updateByTxHash(@Param("leasePayRecordMessage") LeasePayRecordMessage leasePayRecordMessage,@Param("txHash") String txHash);
/**
* 根据订单id获取队列id
* @param infoIds
* @return
*/
@MapKey("orderId")
Map<Long,LeasePayRecordMessage> getQueueIdByInfoIds(@Param("infoIds") List<Long> infoIds);
}

View File

@@ -3,10 +3,9 @@ package com.m2pool.lease.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.m2pool.common.datasource.annotation.HashRateDB;
import com.m2pool.common.datasource.annotation.Pool2DB;
import com.m2pool.lease.dto.PriceDto;
import com.m2pool.lease.dto.ProductMachineDto;
import com.m2pool.lease.dto.UserMinerDto;
import com.m2pool.lease.dto.*;
import com.m2pool.lease.entity.LeaseProductMachine;
import com.m2pool.lease.vo.ProductMachineVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@@ -102,4 +101,47 @@ public interface LeaseProductMachineMapper extends BaseMapper<LeaseProductMachin
/**
* 获取机器售价列表
*
* @param machineIds 机器ID集合
* @return 机器价格列表
*/
List<MachinePayTypeDto> getPriceList(@Param("list")List<Long> machineIds);
/**
* 查询绑定新钱包后,已存在的商品矿机
*
* @param shopId 店铺id
* @return 商品列表
*/
List<ProductMachineForWalletConfigDto> getProductListForShopWalletConfig(@Param("shopId")Long shopId);
/**
* 获取商品对应的机器ID集合
*
* @param productId 商品ID
* @return 机器ID集合
*/
List<Long> getIdsForProductId(@Param("productId")Long productId);
/**
* 根据价格范围,功耗范围,算力范围 获取商品对应的机器
*
* @param productMachineVo 商品参数
* @return 机器列表
*/
List<ProductMachineDto> getMachinesByPriceAndPowerAndDissipation(@Param("productMachineVo") ProductMachineVo productMachineVo,@Param("coin") String coin);
/**
* 批量插入机器算力数据
*
* @param list 机器算力数据
* @return 插入结果
*/
int batchInsertPowers(@Param("coin")String coin,@Param("list")List<ProductMachineDto> list);
}

View File

@@ -0,0 +1,46 @@
package com.m2pool.lease.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.m2pool.common.datasource.annotation.Pool2DB;
import com.m2pool.lease.dto.*;
import com.m2pool.lease.entity.LeaseOrderItem;
import com.m2pool.lease.entity.LeaseProductMachine;
import com.m2pool.lease.entity.LeaseProductMachinePrice;
import com.m2pool.lease.vo.OrderInfoVo;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* <p>
* 商品表对应的物品机器表 Mapper 接口
* </p>
*
* @author yyb
* @since 2025-07-23
*/
@Mapper
public interface LeaseProductMachinePriceMapper extends BaseMapper<LeaseProductMachinePrice> {
/**
* 获取订单总金额 按照chain 和 分组 coin
* @param orderInfoVoList
* @return
*/
@MapKey("productMachineId")
Map<Long,LeaseProductMachinePrice> getOrderTotalPriceGroupByChainAndCoin(@Param("list") List<OrderInfoVo> orderInfoVoList);
/**
* 获取机器价格通过id
* @param machineIds
* @return
*/
List<MachinePayTypeDto> getMachinePriceByMachineIds(@Param("list") List<Long> machineIds);
@MapKey("productMachineId")
Map<Long,LeaseProductMachinePrice> getPriceByOrderItems(@Param("list") List<LeaseOrderItem> orderInfoVoList);
}

View File

@@ -2,7 +2,10 @@ package com.m2pool.lease.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.m2pool.common.datasource.annotation.Pool2DB;
import com.m2pool.lease.dto.MachinePayTypeDto;
import com.m2pool.lease.dto.PayTypeDto;
import com.m2pool.lease.dto.ProductDto;
import com.m2pool.lease.dto.ProductForWalletConfigDto;
import com.m2pool.lease.entity.LeaseProduct;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@@ -55,5 +58,20 @@ public interface LeaseProductMapper extends BaseMapper<LeaseProduct> {
* @param shopId 用于个人中心商品列表
* @return
*/
List<LeaseProduct> getProductListForShopAndUserCenter(@Param("coin") String coin , @Param("algorithm") String algorithm,@Param("shopId") Long shopId);
List<ProductDto> getProductListForShopAndUserCenter(@Param("coin") String coin , @Param("algorithm") String algorithm,@Param("shopId") Long shopId);
/**
* 获取支持的支付方式
* @param shopId
* @return
*/
List<PayTypeDto> getSupportPayType(@Param("shopId")Long shopId);
/**
* 获取商品列表(用于钱包配置)
* @param shopId
* @return
*/
List<ProductForWalletConfigDto> getProductListForShopWalletConfig(@Param("shopId")Long shopId);
}

View File

@@ -39,4 +39,11 @@ public interface LeaseShopConfigMapper extends BaseMapper<LeaseShopConfig> {
*/
List<ShopConfigDelDto> selectShopConfigByShopIdAndSymbolAndChain(@Param("list") List<ShopChainAndCoinDto> list);
/**
* 获取店铺支持的支付方式
* @param shopIds
* @return
*/
List<PayTypeDto> getPayType(@Param("list") List<Long> shopIds);
}

View File

@@ -1,17 +1,20 @@
package com.m2pool.lease.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.m2pool.lease.dto.ChainAndCoinDto;
import com.m2pool.lease.dto.PayConfigDto;
import com.m2pool.lease.entity.LeaseProductMachine;
import com.m2pool.lease.entity.LeaseShop;
import com.m2pool.lease.entity.LeaseShopConfig;
import com.m2pool.lease.vo.OrderInfoVo;
import com.m2pool.lease.vo.OrderItemVo;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
@@ -27,12 +30,10 @@ public interface LeaseShopMapper extends BaseMapper<LeaseShop> {
/**
* 获取买家自定义的支付地址和支付币种和链
* @param shopIds
* @param coin
* @param chain
* @param chainAndCoinSet
* @return
*/
List<LeaseShopConfig> getPayAddressAndPayCoin(@Param("shopIds") Set<Long> shopIds,@Param("coin") String coin,@Param("chain") String chain);
List<LeaseShopConfig> getPayAddressAndPayCoin(@Param("chainAndCoinSet") Set<ChainAndCoinDto> chainAndCoinSet);
/**
@@ -49,4 +50,20 @@ public interface LeaseShopMapper extends BaseMapper<LeaseShop> {
* @return
*/
List<PayConfigDto> getShopWalletInfoList(@Param("shopIds") List<Long> shopIds);
/**
* 根据商品id集合获取店铺id集合
* @param productIds
* @return
*/
List<Long> getShopIdsByProductIds(@Param("productIds") List<Long> productIds);
/**
* 根据店铺id集合获取店铺名称
* @param shopIds
* @return
*/
@MapKey("id")
Map<Long,LeaseShop> getShopNameMapByIds(@Param("shopIds") List<Long> shopIds);
}

View File

@@ -24,7 +24,7 @@ public interface LeaseShoppingCartInfoMapper extends BaseMapper<LeaseShoppingCar
* 查询购物车详情列表
* @return
*/
List<ShoppingCartInfoDto> getCartInfoList(@Param("cartId") Long cartId);
List<ShoppingCartInfoDto> getProductAndMachineIds(@Param("cartId") Long cartId);

View File

@@ -1,6 +1,7 @@
package com.m2pool.lease.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.m2pool.lease.dto.ChainAndCoinDto;
import com.m2pool.lease.dto.UserWalletDataDto;
import com.m2pool.lease.entity.LeaseUserWalletData;
import org.apache.ibatis.annotations.Mapper;
@@ -8,6 +9,7 @@ import org.apache.ibatis.annotations.Param;
import java.math.BigDecimal;
import java.util.List;
import java.util.Set;
@Mapper
public interface LeaseUserWalletDataMapper extends BaseMapper<LeaseUserWalletData> {
@@ -40,4 +42,11 @@ public interface LeaseUserWalletDataMapper extends BaseMapper<LeaseUserWalletDat
* @return 钱包地址
*/
List<LeaseUserWalletData> getWalletForBalanceIsZero(@Param("list") List<UserWalletDataDto> addressList);
/**
* 根据链和币种查询钱包信息
* @param chainAndCoinSet 链和币种
* @return 钱包信息
*/
List<LeaseUserWalletData> selectWalletByChainAndCoinAndUsername(@Param("list") Set<ChainAndCoinDto> chainAndCoinSet,@Param("username") String username);
}

View File

@@ -9,6 +9,7 @@ import com.m2pool.lease.entity.*;
import com.m2pool.lease.exception.PayRechargeException;
import com.m2pool.lease.mapper.*;
import com.m2pool.lease.mq.message.*;
import com.m2pool.lease.service.LeaseOrderItemService;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.messaging.handler.annotation.Payload;
@@ -18,6 +19,8 @@ import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
@@ -36,6 +39,10 @@ public class MessageReceiver {
private LeasePayRecordMessageMapper leasePayRecordMessageMapper;
@Resource
private LeaseAutoAddressMapper leaseAutoAddressMapper;
@Resource
private LeaseOrderItemMapper leaseOrderItemMapper;
@Resource
private LeaseOrderItemService leaseOrderItemService;
@Resource
private RabbitTemplate rabbitTemplate;
@@ -85,31 +92,32 @@ public class MessageReceiver {
@Transactional(rollbackFor = Exception.class)
public void listenerPayBalanceStatusQueueMessage(@Payload RabbitmqPayAutoReturnMessage payAutoReturnMessage) {
System.out.println("支付消费者"+JSONUtil.toJsonPrettyStr(payAutoReturnMessage));
//查找到数据库对应的充值记录
List<LeasePayRecordMessage> leasePayRecordMessages = leasePayRecordMessageMapper.
selectList(new LambdaQueryWrapper<LeasePayRecordMessage>()
//查找到数据库对应的支付记录
List<LeasePayRecordMessage> leasePayRecordMessages = leasePayRecordMessageMapper.selectList(new LambdaQueryWrapper<LeasePayRecordMessage>()
.eq(LeasePayRecordMessage::getQueueId, payAutoReturnMessage.getQueue_id()));
Map<String, LeasePayRecordMessage> collect = leasePayRecordMessages.stream()
.collect(Collectors.toMap(LeasePayRecordMessage::getOrderId, Function.identity()));
Map<String, List<LeasePayRecordMessage>> recordMap = leasePayRecordMessages.stream()
.collect(Collectors.groupingBy(item -> item.getToAddress() + "-" + item.getToChain()));
//买家钱包
List<RabbitmqPayAutoReturnInfoMessage> transactions = payAutoReturnMessage.getTransactions();
RabbitmqPayAutoReturnInfoMessage rabbitmqPayAutoReturnInfoMessage = transactions.get(0);
Map<String,RabbitmqPayAutoReturnInfoMessage> transactions = payAutoReturnMessage.getTransactions();
LeasePayRecordMessage leasePayRecordMessage1 = leasePayRecordMessages.get(0);
LeaseUserWalletData buyer = leaseUserWalletDataMapper.selectOne(new LambdaQueryWrapper<LeaseUserWalletData>()
.eq(LeaseUserWalletData::getFromAddress,rabbitmqPayAutoReturnInfoMessage.getFrom_address())
.eq(LeaseUserWalletData::getFromChain, rabbitmqPayAutoReturnInfoMessage.getChain())
.eq(LeaseUserWalletData::getFromSymbol, rabbitmqPayAutoReturnInfoMessage.getSymbol())
.eq(LeaseUserWalletData::getFromAddress,leasePayRecordMessage1.getFromAddress())
.eq(LeaseUserWalletData::getFromChain, leasePayRecordMessage1.getFromChain())
.eq(LeaseUserWalletData::getFromSymbol, leasePayRecordMessage1.getFromSymbol())
.eq(LeaseUserWalletData::getDel, false)
);
//获取初始余额和冻结余额
BigDecimal initBalance = buyer.getBalance();
BigDecimal initBlockBalance = buyer.getBlockedBalance();
transactions.forEach(transaction -> {
LeasePayRecordMessage leasePayRecordMessage = collect.get(transaction.getOrder_id());
if (leasePayRecordMessage != null){
//支付成功修改order_item表实际支付金额
transactions.forEach((key,transaction) -> {
String key1 = transaction.getTo_address() + "-" + payAutoReturnMessage.getChain();
List<LeasePayRecordMessage> leasePayRecordMessageList = recordMap.get(key1);
if (leasePayRecordMessageList != null){
for (LeasePayRecordMessage leasePayRecordMessage : leasePayRecordMessageList) {
BigDecimal balance = buyer.getBalance().subtract(transaction.getAmount());
BigDecimal blockBalance = buyer.getBlockedBalance().subtract(leasePayRecordMessage.getBlockAmount());
BigDecimal blockBalance = buyer.getBlockedBalance().subtract(leasePayRecordMessage.getBlockAmount())
.subtract(leasePayRecordMessage.getNeedAmount());
leasePayRecordMessage.setUpdateTime(LocalDateTime.now());
leasePayRecordMessage.setBlockHeight(transaction.getBlock_height());
@@ -117,23 +125,37 @@ public class MessageReceiver {
//当天已存在支付的信息
leasePayRecordMessage.setStatus(transaction.getStatus());
leasePayRecordMessage.setTxHash(transaction.getTx_hash());
List<LeaseOrderItem> needUpdateOrderItem = leaseOrderItemMapper.getNeedUpdateOrderItem(Long.valueOf(leasePayRecordMessage.getOrderId()));
if(transaction.getStatus() == 1){
//支付成功 买家 钱包总余额 + 冻结余额 减少 卖家 钱包总余额增加
buyer.setBalance(balance);
buyer.setBlockedBalance(blockBalance);
needUpdateOrderItem = needUpdateOrderItem.stream().peek(item ->{
item.setAlreadyPayRealAmount(item.getAlreadyPayRealAmount().add(item.getSettlePayRealAmount()));
item.setSettlePayRealAmount(BigDecimal.ZERO);
}).collect(Collectors.toList());
}
if (transaction.getStatus() == 0){
buyer.setBlockedBalance(blockBalance);
needUpdateOrderItem = needUpdateOrderItem.stream().peek(item ->{
item.setSettlePayRealAmount(BigDecimal.ZERO);
}).collect(Collectors.toList());
}
//修改支付记录状态
//int i = leasePayRecordMessageMapper.updateByTxHash(leasePayRecordMessage,transaction.getTx_hash());
System.out.println("支付成功"+JSONUtil.toJsonPrettyStr(leasePayRecordMessage) + transaction.getTx_hash());
System.out.println("支付成功1"+JSONUtil.toJsonPrettyStr(leasePayRecordMessage));
int i = leasePayRecordMessageMapper.updateById(leasePayRecordMessage);
if (i < 1){
//支付成功修改order_item表实际支付金额
System.out.println("支付成功2"+JSONUtil.toJsonPrettyStr(needUpdateOrderItem));
boolean b = leaseOrderItemService.updateBatchById(needUpdateOrderItem);
System.out.println("支付成功修改order_item表实际支付金额"+ b +"----"+ i);
if (i < 1 || !b){
throw new PayRechargeException("支付失败,该支付记录已修改,消息重试!!!");
}
}
}
});
//使用乐观锁防止余额少减少
int update = leaseUserWalletDataMapper.update(buyer, new LambdaQueryWrapper<LeaseUserWalletData>()
@@ -156,7 +178,6 @@ public class MessageReceiver {
@Transactional(rollbackFor = Exception.class)
public void listenerPayRechargeStatusQueueMessage(@Payload RabbitmqPayRechargeReturnMessage payRechargeReturnMessage) {
System.out.println("充值消费者---"+JSONUtil.toJsonPrettyStr(payRechargeReturnMessage));
//获取到需要操作的钱包
List<LeaseUserWalletData> leaseUserWalletDataList = leaseUserWalletDataMapper.selectList(new LambdaQueryWrapper<LeaseUserWalletData>()
.eq(LeaseUserWalletData::getFromAddress, payRechargeReturnMessage.getAddress())
@@ -195,6 +216,8 @@ public class MessageReceiver {
LeasePayRechargeMessage build = LeasePayRechargeMessage.builder()
.queueId(payRechargeReturnMessage.getQueue_id())
.chain(payRechargeReturnMessage.getChain())
.blockHeight(payRechargeReturnMessage.getBlock_height())
.fromAddress(payRechargeReturnMessage.getFromAddress())
.symbol(payRechargeReturnMessage.getSymbol())
.amount(payRechargeReturnMessage.getAmount())
.address(payRechargeReturnMessage.getAddress())
@@ -279,6 +302,7 @@ public class MessageReceiver {
.id(leasePayWithdrawMessage.getId())
.amount(payWithdrawReturnMessage.getAmount().add(payWithdrawReturnMessage.getFee()))
.status(payWithdrawReturnMessage.getStatus())
.blockHeight(payWithdrawReturnMessage.getBlock_height())
.txHash(payWithdrawReturnMessage.getTx_hash())
.build());
}
@@ -385,33 +409,34 @@ public class MessageReceiver {
//测试 开发环境 支付回调测试
//@RabbitListener(queues = RabbitmqConstant.PAY_AUTO_QUEUE,containerFactory ="rabbitListenerContainerFactory")
//@Transactional(rollbackFor = Exception.class)
//public void listenerPayBalanceStatusQueueMessage(@Payload RabbitmqPayAutoMessage payAutoReturnMessage) {
// //消费消息
// System.out.println("自动支付功能queueId"+payAutoReturnMessage.getQueue_id());
// List<RabbitmqPayAutoReturnInfoMessage> collect = payAutoReturnMessage.getTransactions().stream()
// .map(transaction -> RabbitmqPayAutoReturnInfoMessage.builder()
// .order_id(transaction.getOrder_id())
// .from_address(payAutoReturnMessage.getFrom_address())
// .to_address(transaction.getTo_address())
// .chain(payAutoReturnMessage.getChain())
// .symbol(payAutoReturnMessage.getSymbol())
// .amount(transaction.getAmount())
// .tx_hash(payAutoReturnMessage.getQueue_id()+"第一笔")
// .block_height(10000L)
// .status(1)
// .build()).collect(Collectors.toList());
//
// RabbitmqPayAutoReturnMessage rabbitmqPayAutoReturnMessage = RabbitmqPayAutoReturnMessage.builder()
// .queue_id(payAutoReturnMessage.getQueue_id())
// .pay_status(1)
// .fromAddress(payAutoReturnMessage.getFrom_address())
// .transactions(collect)
// .build();
//
// rabbitTemplate.convertAndSend(RabbitmqConstant.PAY_AUTO_RETURN_QUEUE,rabbitmqPayAutoReturnMessage);
//}
@RabbitListener(queues = RabbitmqConstant.PAY_AUTO_QUEUE,containerFactory ="rabbitListenerContainerFactory")
@Transactional(rollbackFor = Exception.class)
public void listenerPayBalanceStatusQueueMessage(@Payload RabbitmqPayAutoMessage payAutoReturnMessage) {
//消费消息
System.out.println("自动支付功能queueId"+payAutoReturnMessage.getQueue_id());
Map<String, RabbitmqPayAutoInfoMessage> transactions = payAutoReturnMessage.getTransactions();
Map<String,RabbitmqPayAutoReturnInfoMessage> collect = new HashMap<>();
transactions.forEach((k, transaction) -> {
collect.put(k,RabbitmqPayAutoReturnInfoMessage.builder()
.to_address(transaction.getTo_address())
.amount(transaction.getAmount())
.tx_hash(payAutoReturnMessage.getQueue_id()+"第一笔")
.block_height(10000L)
.status(1)
.build());
});
RabbitmqPayAutoReturnMessage rabbitmqPayAutoReturnMessage = RabbitmqPayAutoReturnMessage.builder()
.queue_id(payAutoReturnMessage.getQueue_id())
.from_address(payAutoReturnMessage.getFrom_address())
.pay_status(1)
.chain(payAutoReturnMessage.getChain())
.symbol(payAutoReturnMessage.getSymbol())
.transactions(collect)
.build();
rabbitTemplate.convertAndSend(RabbitmqConstant.PAY_AUTO_RETURN_QUEUE,rabbitmqPayAutoReturnMessage);
}
////测试 开发环境 充值测试
//@RabbitListener(queues = RabbitmqConstant.PAY_RECHARGE_QUEUE,containerFactory ="rabbitListenerContainerFactory")

View File

@@ -18,6 +18,11 @@ import java.math.BigDecimal;
@AllArgsConstructor
public class RabbitmqPayAutoInfoMessage {
/**
* 订单号(该字段不再传递 一个fromAddress 可以对应多个订单)
*/
private String order_id;
/**
* 卖家充值地址
*/
@@ -28,12 +33,21 @@ public class RabbitmqPayAutoInfoMessage {
*/
private BigDecimal amount;
/**
* 订单号
* 手续费
*/
private String order_id;
private BigDecimal fee;
/**
* 交易ID
*/
private String tx_hash;
/**
* 块高
*/
private Long block_height;
//下面五个不需要传输,只存数据库
@@ -46,6 +60,7 @@ public class RabbitmqPayAutoInfoMessage {
* 实际应支付金额
*/
private BigDecimal needAmount;
/**
* 店铺ID
*/
@@ -56,5 +71,4 @@ public class RabbitmqPayAutoInfoMessage {
*/
private String userId;
private BigDecimal fee;
}

View File

@@ -44,21 +44,24 @@ public class RabbitmqPayAutoMessage {
*/
private BigDecimal total_amount;
/**
* 订单总手续费
*/
private BigDecimal total_fee;
/**
* 时间戳
*/
private Long timestamp;
/**
* 签名 时间戳+m2pool
*/
private String sign;
private BigDecimal totalFee;
/**
* 收款方信息
*/
private List<RabbitmqPayAutoInfoMessage> transactions;
private Map<String,RabbitmqPayAutoInfoMessage> transactions;
}

View File

@@ -24,31 +24,22 @@ public class RabbitmqPayAutoReturnInfoMessage {
private String order_id;
/**
* 买家
*/
private String from_address;
/**
* 卖家
*/
private String to_address;
/**
* 链名称
*/
private String chain;
/**
* 币种
*/
private String symbol;
/**
* 支付金额
*/
private BigDecimal amount;
/**
* 手续费
*/
private BigDecimal fee;
/**
* 支付结果
*/
@@ -59,8 +50,15 @@ public class RabbitmqPayAutoReturnInfoMessage {
*/
private String tx_hash;
/**
* 块高
*/
private Long block_height;
}

View File

@@ -9,6 +9,7 @@ import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
/**
* @Description rabbitmq 支付 消费者
@@ -34,10 +35,19 @@ public class RabbitmqPayAutoReturnMessage{
/**
* 买家支付地址
*/
private String fromAddress;
private String from_address;
/**
* 链名称
*/
private String chain;
/**
* 币种
*/
private String symbol;
/**
* 收款方信息
*/
private List<RabbitmqPayAutoReturnInfoMessage> transactions;
private Map<String,RabbitmqPayAutoReturnInfoMessage> transactions;
}

View File

@@ -16,13 +16,14 @@ import lombok.NoArgsConstructor;
@AllArgsConstructor
public class RabbitmqPayRechargeMessage {
/**
* 交易id
*/
private String queue_id;
/**
* 链名称
*/
private String chain;
private String queue_id;
/**
* 币种
*/

View File

@@ -23,11 +23,18 @@ public class RabbitmqPayRechargeReturnMessage {
private String queue_id;
/**
* 充值地址
*/
private String address;
/**
* 来源地址(用户自己的钱包)
*/
private String fromAddress;
/**
* 充值是否成功
*/
@@ -53,4 +60,9 @@ public class RabbitmqPayRechargeReturnMessage {
*/
private String tx_hash;
/**
* 区块高度
*/
private Long block_height;
}

View File

@@ -38,6 +38,11 @@ public class RabbitmqPayWithdrawMessage {
*/
private BigDecimal amount;
/**
* 手续费
*/
private BigDecimal fee;
/**
* 链名称
@@ -60,9 +65,6 @@ public class RabbitmqPayWithdrawMessage {
*/
private String sign;
/**
* 手续费
*/
private BigDecimal fee;
}

View File

@@ -22,6 +22,16 @@ public class RabbitmqPayWithdrawReturnMessage {
*/
private String queue_id;
/**
* 链名称
*/
private String chain;
/**
* 币种
*/
private String symbol;
/**
* 提现结果
@@ -34,25 +44,29 @@ public class RabbitmqPayWithdrawReturnMessage {
*/
private BigDecimal amount;
/**
* 链名称
*/
private String chain;
/**
* 币种
*/
private String symbol;
/**
* 交易ID
*/
private String tx_hash;
/**
* 手续费
*/
private BigDecimal fee;
/**
* 交易hash
*/
private String tx_hash;
/**
* 块高
*/
private Long block_height;
///**
// * 来源地址
// */
//private String from_address;
//
///**
// * 收款地址
// */
//private String to_address;
}

View File

@@ -0,0 +1,17 @@
package com.m2pool.lease.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.m2pool.lease.entity.LeaseProductMachinePrice;
/**
* <p>
* 商品表对应的物品机器表 服务类
* </p>
*
* @author yyb
* @since 2025-07-23
*/
public interface LeaseProductMachinePriceService extends IService<LeaseProductMachinePrice> {
}

View File

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
import com.m2pool.lease.dto.*;
import com.m2pool.lease.entity.LeaseProduct;
import com.m2pool.lease.vo.BaseVo;
import com.m2pool.lease.vo.ProductMachineVo;
import com.m2pool.lease.vo.ProductPageVo;
import com.m2pool.lease.vo.ProductURDVo;
import org.springframework.web.bind.annotation.RequestBody;
@@ -41,8 +42,14 @@ public interface LeaseProductService extends IService<LeaseProduct> {
* @param productId 商品 ID
* @return Result<ProductDto> 封装后的商品 DTO
*/
Result<ProductMachineInfoDto> getProductMachineInfo(Long productId);
PageResult<ProductMachineDto> getProductMachineInfo(ProductMachineVo productMachineVo);
/**
* 单个商品矿机列表页面---获取支付方式
* @return
*/
Result<List<PayConfigDto>> getPayTypes();
/**
* 新增商品
*
@@ -66,4 +73,24 @@ public interface LeaseProductService extends IService<LeaseProduct> {
* @return
*/
Result<String> deleteProduct(Long id);
/**
* 查询用户店铺支持的支付方式
* @return
*/
Result<List<PayTypeDto>> getSupportPayType();
/**
* 获取商品列表用于店铺钱包配置
* @return
*/
Result<List<ProductForWalletConfigDto>> getProductListForShopWalletConfig();
/**
* 修改商品列表用于店铺钱包配置
* @return
*/
Result<String> updateProductListForShopWalletConfig(ProductMachineForWalletConfigVo productMachineForWalletConfigVo);
}

View File

@@ -1,10 +1,9 @@
package com.m2pool.lease.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.m2pool.lease.dto.ShopCartDto;
import com.m2pool.lease.dto.ShoppingCartInfoDto;
import com.m2pool.lease.dto.PageResult;
import com.m2pool.lease.dto.Result;
import com.m2pool.lease.dto.ShopCartDto;
import com.m2pool.lease.entity.LeaseShoppingCart;
import com.m2pool.lease.vo.BaseVo;
import com.m2pool.lease.vo.PageVo;

View File

@@ -10,6 +10,7 @@ import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.m2pool.common.redis.service.RedisService;
import com.m2pool.common.security.utils.SecurityUtils;
import com.m2pool.lease.constant.CoinCharge;
import com.m2pool.lease.constant.RedisKey;
import com.m2pool.lease.dto.*;
import com.m2pool.lease.entity.*;
@@ -71,15 +72,6 @@ public class LeaseOrderInfoServiceImpl extends ServiceImpl<LeaseOrderInfoMapper,
@Resource
private LeaseProductService leaseProductService;
@Resource
private LeasePaymentRecordService leasePaymentRecordService;
@Resource
private LeaseShopAddressConfigMapper leaseShopAddressConfigMapper;
@Resource
private LeaseAutoAddressMapper leaseAutoAddressMapper;
@Resource
private LeaseUserWalletDataMapper leaseUserWalletDataMapper;
@@ -90,150 +82,19 @@ public class LeaseOrderInfoServiceImpl extends ServiceImpl<LeaseOrderInfoMapper,
private LeaseUserMapper leaseUserMapper;
@Resource
private LeasePayRecordMessageMapper leasePayRecordMessageMapper;
private LeaseProductMachinePriceMapper leaseProductMachinePriceMapper;
/**
* 计算订单总价格
* @param orderInfoVoList 订单信息
* @param machinesList 订单对应的矿机信息这里面获取的价格单位固定是usdt
* @return
*/
public BigDecimal calculateOrderPrice(List<OrderInfoVo> orderInfoVoList,List<LeaseProductMachine> machinesList){
Map<Long, LeaseProductMachine> machineListMap = machinesList.stream()
.collect(Collectors.toMap(LeaseProductMachine::getId, Function.identity()));
return orderInfoVoList.stream()
.map(orderInfoVo -> {
LeaseProductMachine machine = machineListMap.get(orderInfoVo.getMachineId());
return (machine != null) ?
machine.getPrice().multiply(BigDecimal.valueOf(orderInfoVo.getLeaseTime())) :
BigDecimal.ZERO;
})
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
@Resource
private LeaseOrderFeeMapper leaseOrderFeeMapper;
/**
* 修改订单支付地址,目前测试环境适用于自营(后续可能删除)
* @param shopConfigMap
*/
public void updatePayAddressForSelf( Map<Long, LeaseShopConfig> shopConfigMap){
List<LeaseShopAddressConfig> leaseShopAddressConfigs = leaseShopAddressConfigMapper.selectList(
new LambdaQueryWrapper<LeaseShopAddressConfig>()
.eq(LeaseShopAddressConfig::getUserId, SecurityUtils.getUsername()));
Map<Long, LeaseShopAddressConfig> shopAddressConfigMap = leaseShopAddressConfigs.stream().collect(Collectors.toMap(LeaseShopAddressConfig::getShopId, Function.identity()));
for (Long shopId : shopConfigMap.keySet()) {
if (!shopAddressConfigMap.containsKey(shopId)) {
LeaseAutoAddress oneStatusIsNoUse = leaseAutoAddressMapper.getOneStatusIsNoUse();
if (oneStatusIsNoUse == null) {
throw new OrderException("订单生成失败,该商家可用的地址已使用完");
}
String address = oneStatusIsNoUse.getAddress();
String qrcode = QrCodeUtils.creatRrCode(address,200,200);
LeaseShopAddressConfig build = LeaseShopAddressConfig.builder()
.address(address)
.userId(SecurityUtils.getUsername())
.shopId(shopId)
.qrcode(qrcode)
.build();
leaseShopAddressConfigMapper.insert(build);
LeaseShopConfig leaseShopConfig = shopConfigMap.get(shopId);
leaseShopConfig.setQrcode(qrcode);
leaseShopConfig.setPayAddress(address);
} else {
LeaseShopAddressConfig leaseShopAddressConfig = shopAddressConfigMap.get(shopId);
LeaseShopConfig leaseShopConfig = shopConfigMap.get(shopId);
leaseShopConfig.setQrcode(leaseShopAddressConfig.getQrcode());
leaseShopConfig.setPayAddress(leaseShopAddressConfig.getAddress());
}
}
}
/**
* 获取本次订单需总支付金额
*
* @param leaseOrderItems
* @return
*/
public BigDecimal createPaymentOrders(List<LeaseOrderItem> leaseOrderItems,Map<Long, LeaseShopConfig> shopConfigMap,LocalDateTime now,LeaseOrderInfo build){
//按店铺id分组
Map<Long, List<LeaseOrderItem>> shopMap = leaseOrderItems.stream().collect(Collectors.groupingBy(LeaseOrderItem::getShopId));
List<PaymentRecordDto> paymentRecordDTOs = new ArrayList<>();
List<LeasePaymentRecord> paymentRecords = shopMap.values().stream()
.map(items -> {
LeaseOrderItem firstItem = items.get(0);
LeaseShopConfig leaseShopConfig = shopConfigMap.get(firstItem.getShopId());
BigDecimal totalAmount = BigDecimal.ZERO;
for (LeaseOrderItem item : items) {
totalAmount = totalAmount.add(item.getPrice().multiply(BigDecimal.valueOf(item.getLeaseTime())));
}
Long orderId = build.getId();
Long productId = firstItem.getProductId();
String payCoin = firstItem.getPayCoin();
String address = firstItem.getAddress();
paymentRecordDTOs.add(PaymentRecordDto.builder()
.payCoin(payCoin)
.amount(totalAmount)
.payAddress(address)
.img(leaseShopConfig.getQrcode())
.build());
return LeasePaymentRecord.builder()
.orderId(orderId)
.shopId(firstItem.getShopId())
.productId(productId)
.payCoin(payCoin)
.amount(totalAmount)
.payAddress(address)
.qrcode(leaseShopConfig.getQrcode())
.createTime(now)
.build();
})
.collect(Collectors.toList());
//4.保存支付订单
//boolean saved = leasePaymentRecordService.saveBatch(paymentRecords);
//List<RabbitmqOrderMessage> rabbitmqOrderMessageList = paymentRecords.stream()
// .map(paymentRecord -> RabbitmqOrderMessage.builder().orderId(paymentRecord.getOrderId()).shopId(paymentRecord.getShopId()).build())
// .collect(Collectors.toList());
//
////5.发送订单mq超时消息
//rabbitTemplate.convertAndSend(
// ORDER_OVERTIME_EXCHANGE_NAME,
// ORDER_OVERTIME_ROUTING_KEY,
// rabbitmqOrderMessageList);
//返回总支付金额
return paymentRecordDTOs.stream().map(PaymentRecordDto::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
//throw new PaymentException("添加支付订单失败");
}
@Override
@DSTransactional
public Result<String> addOrders(OrderAndCodeVo orderAndCodeVo ) {
BigDecimal price = orderAndCodeVo.getPrice();
if (price.compareTo(BigDecimal.ZERO) <= 0){
return Result.fail("获取的支付币种币价失败");
}
List<OrderInfoVo> orderInfoVoList = orderAndCodeVo.getOrderInfoVoList();
GoogleInfo googleInfo = leaseUserMapper.getGoogleInfoByEmail(SecurityUtils.getUsername());
//校验当前用户是否存在该币种的钱包
LeaseUserWalletData walletData = leaseUserWalletDataMapper.selectOne(new LambdaQueryWrapper<LeaseUserWalletData>()
.eq(LeaseUserWalletData::getUserId, SecurityUtils.getUsername())
.eq(LeaseUserWalletData::getFromChain, orderAndCodeVo.getChain())
.eq(LeaseUserWalletData::getFromSymbol, orderAndCodeVo.getCoin())
.eq(LeaseUserWalletData::getDel, false)
);
if (walletData == null){
return Result.fail("余额不足,无法下单!您还没有绑定该链和币种钱包!");
}
String userEmail = SecurityUtils.getUsername();
GoogleInfo googleInfo = leaseUserMapper.getGoogleInfoByEmail(userEmail);
//TODO 开发环境
//if(googleInfo == null || StringUtils.isBlank(googleInfo.getSecret())){
// //未绑定定谷歌验证器
@@ -243,77 +104,138 @@ public class LeaseOrderInfoServiceImpl extends ServiceImpl<LeaseOrderInfoMapper,
// return Result.fail("谷歌验证码错误");
//}
if ("usdt".equalsIgnoreCase(orderAndCodeVo.getCoin())){
orderAndCodeVo.setPrice(BigDecimal.ONE);
}
List<OrderInfoVo> orderInfoVoList = orderAndCodeVo.getOrderInfoVoList();
//存储根据chain和coin去重后的set集合
Set<ChainAndCoinDto> chainAndCoinSet = new HashSet<>();
Set<ChainAndCoinDto> chainAndCoinAndShopIdSet = new HashSet<>();
//存储相同链和币种的map集合
Map<String, Map<String, List<OrderInfoVo>>> chainAndCoinMap = new HashMap<>();
Map<Long, LeaseProductMachinePrice> orderTotalPriceGroupByChainAndCoin = leaseProductMachinePriceMapper.getOrderTotalPriceGroupByChainAndCoin(orderInfoVoList);
//chain + coin 钱包 对应的总价
Map<String, BigDecimal> totalPriceMap = new HashMap<>();
//其他
Map<Long, OrderInfoVo> machineMap = new HashMap<>();
LocalDateTime now = LocalDateTime.now();
List<Long> machineIds = new ArrayList<>();
Set<Long> shopIds = new HashSet<>();
Set<Long> productIds = new HashSet<>();
for (OrderInfoVo vo : orderInfoVoList) {
String chain = vo.getChain();
String coin = vo.getCoin();
String key = chain +"-"+ coin;
chainAndCoinSet.add(new ChainAndCoinDto(coin, chain));
chainAndCoinAndShopIdSet.add(new ChainAndCoinDto(coin, chain,vo.getShopId()));
chainAndCoinMap.computeIfAbsent(chain, k -> new HashMap<>());
Map<String, List<OrderInfoVo>> innerMap = chainAndCoinMap.get(chain);
innerMap.computeIfAbsent(coin, k -> new ArrayList<>()).add(vo);
// 获取对应买方本次链和币对应需要支付的总金额
totalPriceMap.compute(key, (k, v) -> {
if (v == null) {
v = BigDecimal.ZERO;
}
LeaseProductMachinePrice priceInfo = orderTotalPriceGroupByChainAndCoin.get(vo.getMachineId());
if (priceInfo != null) {
v = v.add(priceInfo.getPrice().multiply(BigDecimal.valueOf(vo.getLeaseTime())));
}
return v;
});
machineMap.put(vo.getMachineId(), vo);
machineIds.add(vo.getMachineId());
shopIds.add(vo.getShopId());
productIds.add(vo.getProductId());
}
//查询需要生成订单的矿机信息
//获取买家需要进行支付的几个钱包
List<LeaseUserWalletData> walletDataList = leaseUserWalletDataMapper.selectWalletByChainAndCoinAndUsername(chainAndCoinSet, userEmail);
if (walletDataList.size() != chainAndCoinSet.size()){
return Result.fail("下单失败!订单选择的支付方式中对应钱包您还未绑定并充值!");
}
//删除购物车中矿机
LeaseShoppingCart leaseShoppingCart = leaseShoppingCartMapper.selectOne(new LambdaQueryWrapper<LeaseShoppingCart>()
.eq(LeaseShoppingCart::getUserId, SecurityUtils.getUsername()));
int delete = leaseShoppingCartInfoMapper.delete(new LambdaUpdateWrapper<LeaseShoppingCartInfo>()
.eq(LeaseShoppingCartInfo::getCartId, leaseShoppingCart.getId())
.in(LeaseShoppingCartInfo::getProductMachineId, machineIds));
if (delete < 1){
throw new OrderException("生成订单失败,购物车中不存在矿机商品");
}
//查找矿机详情信息
List<LeaseProductMachine> machinesList = leaseProductMachineMapper.selectBatchIds(machineIds);
for (LeaseProductMachine leaseProductMachine : machinesList) {
if (leaseProductMachine.getState() == 1 || leaseProductMachine.getDel()){
throw new OrderException("生成订单失败,订单矿机中存在已下架矿机");
}
}
//删除购物车中矿机
int delete = leaseShoppingCartInfoMapper.delete(new LambdaUpdateWrapper<LeaseShoppingCartInfo>()
.eq(LeaseShoppingCartInfo::getCartId, leaseShoppingCart.getId()).in(LeaseShoppingCartInfo::getProductMachineId, machineIds));
if (delete < 1){
throw new OrderException("生成订单失败,购物车中不存在该矿机商品");
// 获取卖家店铺钱包配置
List<LeaseShopConfig> payAddressAndPayCoin = leaseShopMapper.getPayAddressAndPayCoin(chainAndCoinAndShopIdSet);
Map<String, LeaseShopConfig> configMap = new HashMap<>();
Map<String, Set<String>> feeMap = new HashMap<>();
for (LeaseShopConfig leaseShopConfig : payAddressAndPayCoin) {
String key = leaseShopConfig.getChain() + "-" + leaseShopConfig.getPayCoin() +"-"+leaseShopConfig.getShopId();
configMap.put(key, leaseShopConfig);
feeMap.computeIfAbsent(leaseShopConfig.getChain() + "-" + leaseShopConfig.getPayCoin(), k -> new HashSet<>()).add(leaseShopConfig.getPayAddress());
}
//获取本次生成订单中所有矿机的总价单位固定usdt
BigDecimal totalPrice = calculateOrderPrice(orderInfoVoList, machinesList);
// 获取卖家店铺钱包配置(注意:目前同时只能结算一个店铺的,这里多个防止后续改成可以结算多个)
List<LeaseShopConfig> payAddressAndPayCoin = leaseShopMapper.getPayAddressAndPayCoin(shopIds,orderAndCodeVo.getCoin(),orderAndCodeVo.getChain());
Map<Long, LeaseShopConfig> shopConfigMap = payAddressAndPayCoin.stream()
.collect(Collectors.toMap(LeaseShopConfig::getShopId, Function.identity()));
//订单主信息新增
String userEmail = SecurityUtils.getUsername();
//根据买方钱包的 chain和coin 设置要生成订单个数 以及对应的订单总价
List<LeaseOrderInfo> leaseOrderInfoList = new ArrayList<>();
Map<String, BigDecimal> totalFeeMap = new HashMap<>();
Map<String, LeaseUserWalletData> walletDataMap = new HashMap<>();
for (LeaseUserWalletData leaseUserWalletData : walletDataList) {
String key = leaseUserWalletData.getFromChain() + "-" + leaseUserWalletData.getFromSymbol();
BigDecimal totalAmount = totalPriceMap.get(key);
String orderNumber = UuidGeneratorUtil.generateUuidWithoutHyphen();
LeaseOrderInfo build = LeaseOrderInfo.builder()
Set<String> toAddressList = feeMap.get(key);
int size = toAddressList.size();
BigDecimal charge = CoinCharge.getChargeByChainAndCoin(leaseUserWalletData.getFromChain(), leaseUserWalletData.getFromSymbol());
BigDecimal fee = charge.multiply(BigDecimal.valueOf(size));
leaseOrderInfoList.add(LeaseOrderInfo.builder()
.chainAndCoinKey(key)
.orderNumber(orderNumber)
.userId(userEmail)
.totalPrice(totalPrice)
.fee(fee)
.totalPrice(totalAmount)
.createTime(now)
.build();
boolean save = save(build);
if (!save){
throw new OrderException("订单生成失败");
.build());
totalFeeMap.put(key, fee);
walletDataMap.put(key, leaseUserWalletData);
}
Map<Long, OrderInfoVo> machineMap = orderInfoVoList.stream().collect(Collectors.toMap(OrderInfoVo::getMachineId, Function.identity()));
boolean save = saveBatch(leaseOrderInfoList);
if (!save){
return Result.fail("生成订单失败");
}
for (LeaseOrderInfo leaseOrderInfo : leaseOrderInfoList) {
}
Map<String, LeaseOrderInfo> orderInfoMap = leaseOrderInfoList.stream()
.collect(Collectors.toMap(LeaseOrderInfo::getChainAndCoinKey, Function.identity()));
//订单详情表业务
List<LeaseProduct> leaseProducts = leaseProductMapper.selectBatchIds(productIds);
Map<Long, LeaseProduct> productMap = leaseProducts.stream().collect(Collectors.toMap(LeaseProduct::getId, Function.identity()));
List<LeaseOrderItem> leaseOrderItems = new ArrayList<>();
//创建订单明细
for (LeaseProductMachine leaseProductMachine : machinesList) {
LeaseShopConfig leaseShopConfig = shopConfigMap.get(leaseProductMachine.getShopId());
Long machineId = leaseProductMachine.getId();
OrderInfoVo orderInfoVo = machineMap.get(machineId);
String chain = orderInfoVo.getChain();
String coin = orderInfoVo.getCoin();
Long shopId = orderInfoVo.getShopId();
LeaseProductMachinePrice leaseProductMachinePrice = orderTotalPriceGroupByChainAndCoin.get(machineId);
LeaseShopConfig leaseShopConfig = configMap.get(chain + "-" +coin +"-"+ shopId);
LeaseUserWalletData walletInfo = walletDataMap.get(chain + "-" + coin);
if (leaseShopConfig == null){
throw new OrderException("卖方未绑定钱包");
throw new OrderException("选择的卖家收款钱包不存在,请重行选择支付方法");
}
OrderInfoVo orderInfoVo = machineMap.get(leaseProductMachine.getId());
LeaseOrderInfo leaseOrderInfo = orderInfoMap.get(chain + "-" + coin);
//设置销售数量
LeaseProduct leaseProduct = productMap.get(leaseProductMachine.getProductId());
leaseProduct.setSaleNumber(leaseProduct.getSaleNumber() + 1);
leaseOrderItems.add( LeaseOrderItem.builder()
.userId(userEmail)
.orderId(build.getId())
.orderId(leaseOrderInfo.getId())
.productId(leaseProductMachine.getProductId())
.productMachineId(leaseProductMachine.getId())
//这里需要实时计算支付币种的个数
.price(leaseProductMachine.getPrice().divide(orderAndCodeVo.getPrice(),6, RoundingMode.HALF_UP))
.price(leaseProductMachinePrice.getPrice())
.user(leaseProductMachine.getUser())
.miner(leaseProductMachine.getMiner())
//TODO 这里的理论收益是商家新增机器时通过实时算力计算得来
.theoryIncome(leaseProductMachine.getTheoryIncome().multiply(BigDecimal.valueOf(orderInfoVo.getLeaseTime())))
.coin(leaseProduct.getCoin())
.leaseTime(orderInfoVo.getLeaseTime())
@@ -324,9 +246,9 @@ public class LeaseOrderInfoServiceImpl extends ServiceImpl<LeaseOrderInfoMapper,
.name(leaseProduct.getName())
.image(leaseProduct.getImage())
.shopId(leaseProductMachine.getShopId())
.fromAddress(walletData.getFromAddress())
.fromChain(walletData.getFromChain())
.fromSymbol(walletData.getFromSymbol())
.fromAddress(walletInfo.getFromAddress())
.fromChain(walletInfo.getFromChain())
.fromSymbol(walletInfo.getFromSymbol())
.type(leaseProduct.getType())
.build());
}
@@ -338,24 +260,106 @@ public class LeaseOrderInfoServiceImpl extends ServiceImpl<LeaseOrderInfoMapper,
//开始生成支付订单并返回
if (a && b && c){
BigDecimal totalPay = createPaymentOrders(leaseOrderItems, shopConfigMap, now, build);
BigDecimal subtract = totalPay.subtract(walletData.getBalance().subtract(walletData.getBlockedBalance()));
if (subtract.compareTo(BigDecimal.ZERO) <= 0 ){
checkBalanceAndSetBlockBalance(walletDataMap,totalPriceMap,totalFeeMap);
//修改商品矿机售出状态 以商品机器sale_state作为乐观锁
int i = leaseProductMachineMapper.updateLockState(machineIds);
walletData.setBlockedBalance(walletData.getBlockedBalance().add(totalPay));
leaseUserWalletDataMapper.updateById(walletData);
if (i != machineIds.size()){
throw new OrderException("订单中已有商品售出,请刷新购物车删除已售出商品,重新结算生成订单");
}
return Result.success("订单生成成功");
}else{
throw new OrderException("订单生成失败:未冻结余额不足,缺少" + subtract +"UDST 满足支付需求");
}
}
throw new OrderException("订单生成失败");
}
/**
* 检测钱包余额是否充足 余额充足则将余额冻结
* @return
*/
public void checkBalanceAndSetBlockBalance(Map<String, LeaseUserWalletData> walletDataMap,Map<String, BigDecimal> totalPriceMap,Map<String, BigDecimal> feeMap){
totalPriceMap.forEach((chainAndCoinKey, totalAmount) -> {
LeaseUserWalletData walletData = walletDataMap.get(chainAndCoinKey);
BigDecimal fee = feeMap.get(chainAndCoinKey);
if (walletData == null){
throw new OrderException("下单失败,买家不存在"+chainAndCoinKey+"类型钱包");
}
if (walletData.getBalance().subtract(walletData.getBlockedBalance()).compareTo(totalAmount) < 0){
throw new OrderException("下单失败,买家"+chainAndCoinKey+"钱包余额不足,缺少" + (totalAmount.subtract(walletData.getBalance().subtract(walletData.getBlockedBalance()))) +"满足支付需求");
}
walletData.setBlockedBalance(walletData.getBlockedBalance().add(totalAmount).add(fee));
leaseUserWalletDataMapper.updateById(walletData);
});
}
///**
// * 获取本次订单需总支付金额
// *
// * @param leaseOrderItems
// * @return
// */
//public BigDecimal createPaymentOrders(List<LeaseOrderItem> leaseOrderItems,Map<Long, LeaseShopConfig> shopConfigMap,LocalDateTime now,LeaseOrderInfo build){
// //按店铺id分组
// Map<Long, List<LeaseOrderItem>> shopMap = leaseOrderItems.stream().collect(Collectors.groupingBy(LeaseOrderItem::getShopId));
// List<PaymentRecordDto> paymentRecordDTOs = new ArrayList<>();
// List<LeasePaymentRecord> paymentRecords = shopMap.values().stream()
// .map(items -> {
// LeaseOrderItem firstItem = items.get(0);
// LeaseShopConfig leaseShopConfig = shopConfigMap.get(firstItem.getShopId());
// BigDecimal totalAmount = BigDecimal.ZERO;
// for (LeaseOrderItem item : items) {
// totalAmount = totalAmount.add(item.getPrice().multiply(BigDecimal.valueOf(item.getLeaseTime())));
// }
// Long orderId = build.getId();
// Long productId = firstItem.getProductId();
// String payCoin = firstItem.getPayCoin();
// String address = firstItem.getAddress();
//
//
// paymentRecordDTOs.add(PaymentRecordDto.builder()
// .payCoin(payCoin)
// .amount(totalAmount)
// .payAddress(address)
// .img(leaseShopConfig.getQrcode())
// .build());
//
// return LeasePaymentRecord.builder()
// .orderId(orderId)
// .shopId(firstItem.getShopId())
// .productId(productId)
// .payCoin(payCoin)
// .amount(totalAmount)
// .payAddress(address)
// .qrcode(leaseShopConfig.getQrcode())
// .createTime(now)
// .build();
// })
// .collect(Collectors.toList());
//
//
// //4.保存支付订单
// //boolean saved = leasePaymentRecordService.saveBatch(paymentRecords);
// //List<RabbitmqOrderMessage> rabbitmqOrderMessageList = paymentRecords.stream()
// // .map(paymentRecord -> RabbitmqOrderMessage.builder().orderId(paymentRecord.getOrderId()).shopId(paymentRecord.getShopId()).build())
// // .collect(Collectors.toList());
// //
// ////5.发送订单mq超时消息
// //rabbitTemplate.convertAndSend(
// // ORDER_OVERTIME_EXCHANGE_NAME,
// // ORDER_OVERTIME_ROUTING_KEY,
// // rabbitmqOrderMessageList);
//
//
//
//
// //返回总支付金额
// return paymentRecordDTOs.stream().map(PaymentRecordDto::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
//
// //throw new PaymentException("添加支付订单失败");
//}
@Override
public Result<List<PaymentRecordDto>> buyAgain(List<OrderInfoVo> orderInfoVoList) {
//LocalDateTime now = LocalDateTime.now();
@@ -480,9 +484,18 @@ public class LeaseOrderInfoServiceImpl extends ServiceImpl<LeaseOrderInfoMapper,
}
/**
* 遍历订单详情集合。统计 已支付金额,待支付金额
* @param leaseOrderItems
* @param ordersByStatus
* @param ids
*/
public void setPayAmountAndItems(List<LeaseOrderItem> leaseOrderItems,List<OrderInfoDto> ordersByStatus,List<Long> ids){
Map<Long, List<OrderItemDto>> collect = leaseOrderItems.stream().map(leaseOrderItem ->
OrderItemDto.builder()
Map<Long, BigDecimal> hasPayAmountMap = new HashMap<>();
Map<Long, BigDecimal> hasPayRealAmountMap = new HashMap<>();
Map<Long, List<OrderItemDto>> orderItemDtoMap = new HashMap<>();
for (LeaseOrderItem leaseOrderItem : leaseOrderItems) {
orderItemDtoMap.computeIfAbsent(leaseOrderItem.getOrderId(), k -> new ArrayList<>()).add( OrderItemDto.builder()
.shopId(leaseOrderItem.getShopId())
.orderId(leaseOrderItem.getOrderId())
.productId(leaseOrderItem.getProductId())
@@ -493,34 +506,20 @@ public class LeaseOrderInfoServiceImpl extends ServiceImpl<LeaseOrderInfoMapper,
.name(leaseOrderItem.getName())
.price(leaseOrderItem.getPrice())
.image(leaseOrderItem.getImage())
.build()
).collect(Collectors.groupingBy(OrderItemDto::getOrderId));
//获取订单已支付 和待支付金额
List<LeasePayRecordMessage> leasePayRecordMessages = leasePayRecordMessageMapper.selectList(new LambdaQueryWrapper<LeasePayRecordMessage>().in(LeasePayRecordMessage::getOrderId, ids));
Map<String, HasPayTotalDto> collect1 = new HashMap<>();
leasePayRecordMessages.forEach(leasePayRecordMessage -> {
HasPayTotalDto hasPayTotalDto = collect1.get(leasePayRecordMessage.getOrderId());
if (hasPayTotalDto == null){
collect1.put(leasePayRecordMessage.getOrderId(),HasPayTotalDto.builder()
.totalAmount(leasePayRecordMessage.getAmount())
.totalRealAmount(leasePayRecordMessage.getRealAmount())
.build());
}else{
hasPayTotalDto.setTotalAmount(hasPayTotalDto.getTotalAmount().add(leasePayRecordMessage.getAmount()));
hasPayTotalDto.setTotalRealAmount(hasPayTotalDto.getTotalRealAmount().add(leasePayRecordMessage.getRealAmount()));
collect1.put(leasePayRecordMessage.getOrderId(),hasPayTotalDto);
// 累加支付金额
hasPayAmountMap.merge(leaseOrderItem.getOrderId(), leaseOrderItem.getAlreadyPayAmount(), BigDecimal::add);
// 累加实际支付金额
hasPayRealAmountMap.merge(leaseOrderItem.getOrderId(), leaseOrderItem.getAlreadyPayRealAmount(), BigDecimal::add);
}
});
ordersByStatus.forEach(orderInfoDto -> {
List<OrderItemDto> orderItems = collect.get(orderInfoDto.getId());
HasPayTotalDto hasPayTotalDto = collect1.get(orderInfoDto.getId().toString());
BigDecimal hasPayAmount = hasPayTotalDto == null ? BigDecimal.ZERO: hasPayTotalDto.getTotalAmount();
BigDecimal hasPayRealAmount = hasPayTotalDto == null ? BigDecimal.ZERO: hasPayTotalDto.getTotalRealAmount();
OrderItemDto orderItemDto = orderItems.get(0);
List<OrderItemDto> orderItems = orderItemDtoMap.get(orderInfoDto.getId());
BigDecimal hasPayAmount = hasPayAmountMap.get(orderInfoDto.getId());
BigDecimal hasPayRealAmount = hasPayRealAmountMap.get(orderInfoDto.getId());
orderInfoDto.setOrderItemDtoList(orderItems);
orderInfoDto.setShopId(orderItemDto.getShopId());
//orderInfoDto.setShopId(orderItems.get(0).getShopId());
orderInfoDto.setNoPayAmount(orderInfoDto.getTotalPrice().subtract(hasPayAmount).doubleValue());
orderInfoDto.setPayAmount(hasPayRealAmount.doubleValue()+"/"+hasPayAmount.doubleValue());
});

View File

@@ -0,0 +1,21 @@
package com.m2pool.lease.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.m2pool.lease.entity.LeaseProductMachinePrice;
import com.m2pool.lease.mapper.LeaseProductMachinePriceMapper;
import com.m2pool.lease.service.LeaseProductMachinePriceService;
import org.springframework.stereotype.Service;
/**
* <p>
* 商品表对应的物品机器表 服务实现类
* </p>
*
* @author yyb
* @since 2025-07-23
*/
@Service
public class LeaseProductMachinePriceServiceImpl extends ServiceImpl<LeaseProductMachinePriceMapper, LeaseProductMachinePrice> implements LeaseProductMachinePriceService {
}

View File

@@ -1,7 +1,9 @@
package com.m2pool.lease.service.impl;
import cn.hutool.json.JSONUtil;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
@@ -13,10 +15,14 @@ import com.m2pool.lease.constant.RedisKey;
import com.m2pool.lease.dto.*;
import com.m2pool.lease.entity.LeaseProduct;
import com.m2pool.lease.entity.LeaseProductMachine;
import com.m2pool.lease.entity.LeaseProductMachinePrice;
import com.m2pool.lease.mapper.LeaseNexaMachinePowerMapper;
import com.m2pool.lease.mapper.LeaseProductMachineMapper;
import com.m2pool.lease.mapper.LeaseProductMachinePriceMapper;
import com.m2pool.lease.mapper.LeaseProductMapper;
import com.m2pool.lease.service.LeaseProductMachinePriceService;
import com.m2pool.lease.service.LeaseProductMachineService;
import com.m2pool.lease.service.LeaseProductService;
import com.m2pool.lease.utils.PowerUnitUtils;
import com.m2pool.lease.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
@@ -28,8 +34,10 @@ import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/**
@@ -45,22 +53,19 @@ public class LeaseProductMachineServiceImpl extends ServiceImpl<LeaseProductMach
@Resource
private LeaseProductMachineMapper leaseProductMachineMapper;
@Resource
private LeaseProductMapper leaseProductMapper;
@Resource
private ApplicationContext applicationContext;
@Resource
private RedisService redisService;
@Resource
private LeaseProductMachinePriceService leaseProductMachinePriceService;
@Autowired
private ApplicationContext applicationContext;
@Override
public Result<Map<String, List<UserMinerDto>> > getUserMinersList(UserMinerVo userMinerVo) {
String userId = SecurityUtils.getUsername();
//测试 挖矿账号
//开发环境
//userId = "Eudora.law@outlook.com";
List<UserMinerDto> userMinersList = leaseProductMachineMapper.getUserMinersList(userId,userMinerVo.getCoin());
Map<String, List<UserMinerDto>> collect = userMinersList.stream().collect(Collectors.groupingBy(UserMinerDto::getCoin));
@@ -90,6 +95,13 @@ public class LeaseProductMachineServiceImpl extends ServiceImpl<LeaseProductMach
List<LeaseProductMachine> leaseProductMachines = leaseProductMachineMapper.selectList(new LambdaQueryWrapper<LeaseProductMachine>()
.eq(LeaseProductMachine::getProductId, productForUpdateMachineVo.getId()).eq(LeaseProductMachine::getDel,false));
PageInfo<LeaseProductMachine> pageInfo = new PageInfo<>(leaseProductMachines);
if (leaseProductMachines.isEmpty()){
return PageResult.fail(new ArrayList<>(), "不存在租售的矿机");
}
//获取矿机对应的币价
List<Long> machineIds = leaseProductMachines.stream().map(LeaseProductMachine::getId).collect(Collectors.toList());
List<MachinePayTypeDto> priceList = leaseProductMachineMapper.getPriceList(machineIds);
Map<Long, List<MachinePayTypeDto>> collect = priceList.stream().collect(Collectors.groupingBy(MachinePayTypeDto::getProductMachineId));
List<ProductUpdateMachineDto> productUpdateMachineDtos = leaseProductMachines.stream().map(leaseProductMachine ->
ProductUpdateMachineDto.builder()
@@ -97,7 +109,7 @@ public class LeaseProductMachineServiceImpl extends ServiceImpl<LeaseProductMach
.user(leaseProductMachine.getUser())
.type(leaseProductMachine.getType())
.miner(leaseProductMachine.getMiner())
.price(leaseProductMachine.getPrice())
.priceList(collect.get(leaseProductMachine.getId()))
.computingPower(leaseProductMachine.getComputingPower().setScale(2, RoundingMode.HALF_UP))
.theoryPower(leaseProductMachine.getTheoryPower())
.unit(leaseProductMachine.getUnit())
@@ -127,15 +139,19 @@ public class LeaseProductMachineServiceImpl extends ServiceImpl<LeaseProductMach
List<LeaseProductMachine> leaseProductMachines = new ArrayList<>();
List<ProductMachineURDVo> productMachineURDVos = productMachineParamsVo.getProductMachineURDVos();
Map<Integer,List<LeaseProductMachinePrice>> payTypeMap = new HashMap<>();
AtomicInteger index = new AtomicInteger(1);
productMachineURDVos.forEach(machine -> {
int andIncrement = index.getAndIncrement();
leaseProductMachines.add(LeaseProductMachine.builder()
.updateCount(andIncrement)
.shopId(product.getShopId())
.productId(productMachineParamsVo.getProductId())
.type(machine.getType() == null ? productMachineParamsVo.getType() : machine.getType())
.theoryPower(machine.getTheoryPower() == null ? productMachineParamsVo.getTheoryPower() : machine.getTheoryPower())
.powerDissipation(productMachineParamsVo.getPowerDissipation())
.cost(productMachineParamsVo.getCost())
.price(machine.getPrice() == null ? productMachineParamsVo.getCost() : machine.getPrice())
.price(BigDecimal.ZERO)
.incomeRate(BigDecimal.ZERO)
.maxLeaseDays(machine.getMaxLeaseDays() == null ? productMachineParamsVo.getMaxLeaseDays() : machine.getMaxLeaseDays())
.unit(machine.getUnit() == null ? productMachineParamsVo.getUnit() : machine.getUnit())
@@ -147,6 +163,14 @@ public class LeaseProductMachineServiceImpl extends ServiceImpl<LeaseProductMach
.del( false)
.saleState(0)
.build());
payTypeMap.put(andIncrement,machine.getPriceList().stream()
.map(payType -> LeaseProductMachinePrice.builder()
.price(payType.getPrice())
.coin(payType.getCoin())
.chain(payType.getChain())
.build())
.collect(Collectors.toList()));
});
@@ -209,11 +233,24 @@ public class LeaseProductMachineServiceImpl extends ServiceImpl<LeaseProductMach
productMachineURDVo.setComputingPower(computingPower);
productMachineURDVo.setTheoryIncome(singleTheoryMachineIncome);
}).collect(Collectors.toList());
//新增矿机
int i = leaseProductMachineMapper.saveOrUpdateBatchs(collect);
if (i >= 1){
//新增矿机 索引改为普通联合索引
LeaseProductMachineServiceImpl service = applicationContext.getBean(LeaseProductMachineServiceImpl.class);
//TODO 修改,还是得用唯一索引
//leaseProductMachineMapper.saveOrUpdateBatchs(collect);
boolean b = service.saveBatch(collect);
if (b){
//修改商品的价格范围 及商品下机器库存数量
updatePriceRange(product.getId());
List<LeaseProductMachinePrice> list = new ArrayList<>();
for (LeaseProductMachine leaseProductMachine : collect) {
List<LeaseProductMachinePrice> leaseProductMachinePrices = payTypeMap.get(leaseProductMachine.getUpdateCount());
list.addAll(leaseProductMachinePrices.stream()
.peek(leaseProductMachinePrice -> leaseProductMachinePrice.setProductMachineId(leaseProductMachine.getId()))
.collect(Collectors.toList()));
}
//修改机器配置
leaseProductMachinePriceService.saveBatch(list);
return Result.success("添加成功,添加矿机数:"+collect.size());
}
return Result.fail("添加失败");
@@ -225,6 +262,7 @@ public class LeaseProductMachineServiceImpl extends ServiceImpl<LeaseProductMach
List<Long> ids = new ArrayList<>();
List<LeaseProductMachine> leaseProductMachines = new ArrayList<>();
List<LeaseProductMachinePrice> list = new ArrayList<>();
productUpdateMachineVoList.forEach(machine -> {
leaseProductMachines.add( LeaseProductMachine.builder()
.id(machine.getId())
@@ -240,13 +278,21 @@ public class LeaseProductMachineServiceImpl extends ServiceImpl<LeaseProductMach
.miner(machine.getMiner())
.state(machine.getState())
.build());
list.addAll(machine.getPriceList().stream()
.map(payType -> LeaseProductMachinePrice.builder()
.id(payType.getPayTypeId())
.price(payType.getPrice())
.chain(payType.getChain())
.build())
.collect(Collectors.toList()));
if (machine.getState() == 1){
ids.add(machine.getId());
}
});
if (!ids.isEmpty()){
List<LeaseProductMachine> leaseProductMachines1 = leaseProductMachineMapper.selectBatchIds(ids);
long count = leaseProductMachines1.stream().filter(leaseProductMachine -> leaseProductMachine.getSaleState() == 1).count();
long count = leaseProductMachines1.stream()
.filter(leaseProductMachine -> leaseProductMachine.getSaleState() == 1).count();
if (count >= 1){
return Result.fail("商品修改失败,部分矿机租约已存在,不能下架");
}
@@ -259,6 +305,7 @@ public class LeaseProductMachineServiceImpl extends ServiceImpl<LeaseProductMach
LeaseProductMachine leaseProductMachine = leaseProductMachineMapper.selectById(productUpdateMachineVoList.get(0).getId());
//修改商品的价格范围
updatePriceRange(leaseProductMachine.getProductId());
leaseProductMachinePriceService.updateBatchById(list);
return Result.success("修改成功");
}
return Result.fail("修改失败");
@@ -277,6 +324,8 @@ public class LeaseProductMachineServiceImpl extends ServiceImpl<LeaseProductMach
boolean b = updateById(LeaseProductMachine.builder().id(baseVo.getId()).del(true).build());
if (b){
updatePriceRange(leaseProductMachine.getProductId());
//删除售价
leaseProductMachinePriceService.removeById(baseVo.getId());
return Result.success("删除成功");
}
return Result.fail("删除失败");

View File

@@ -1,26 +1,29 @@
package com.m2pool.lease.service.impl;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.m2pool.common.core.utils.StringUtils;
import com.m2pool.common.redis.service.RedisService;
import com.m2pool.common.security.utils.SecurityUtils;
import com.m2pool.lease.constant.Algorithm;
import com.m2pool.lease.constant.BlockInterval;
import com.m2pool.lease.constant.RedisKey;
import com.m2pool.lease.dto.*;
import com.m2pool.lease.entity.LeaseProduct;
import com.m2pool.lease.entity.LeaseProductMachine;
import com.m2pool.lease.entity.LeaseShop;
import com.m2pool.lease.entity.LeaseShopConfig;
import com.m2pool.lease.entity.*;
import com.m2pool.lease.exception.ProductSoldOutException;
import com.m2pool.lease.mapper.LeaseProductMachineMapper;
import com.m2pool.lease.mapper.LeaseProductMapper;
import com.m2pool.lease.mapper.LeaseShopConfigMapper;
import com.m2pool.lease.mapper.LeaseShopMapper;
import com.m2pool.lease.mapper.*;
import com.m2pool.lease.service.LeaseProductMachinePriceService;
import com.m2pool.lease.service.LeaseProductService;
import com.m2pool.lease.service.LeaseShopConfigService;
import com.m2pool.lease.utils.PowerUnitUtils;
import com.m2pool.lease.utils.QrCodeUtils;
import com.m2pool.lease.utils.WalletRuleCheckUtils;
import com.m2pool.lease.vo.BaseVo;
import com.m2pool.lease.vo.ProductMachineVo;
import com.m2pool.lease.vo.ProductPageVo;
import com.m2pool.lease.vo.ProductURDVo;
import org.springframework.stereotype.Service;
@@ -31,6 +34,7 @@ import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
@@ -60,62 +64,45 @@ public class LeaseProductServiceImpl extends ServiceImpl<LeaseProductMapper, Lea
@Resource
private LeaseShopConfigMapper leaseShopConfigMapper;
@Resource
private LeaseProductMachinePriceService leaseProductMachinePriceService;
@Resource
private LeaseShopConfigService leaseShopConfigService;
@Resource
private LeaseProductMachinePriceMapper leaseProductMachinePriceMapper;
@Override
public PageResult<ProductDto> getProductList(ProductPageVo productPageVo) {
LambdaQueryWrapper<LeaseProduct> wrapper = new LambdaQueryWrapper<LeaseProduct>().eq(LeaseProduct::getDel, false);
Long shopId = 0L;
System.out.println("用户邮箱参数:"+productPageVo.getUserEmail());
//1.用户邮箱参数不为空,则表示个人中心的商品列表。这个时候能看到下架的商品
if (productPageVo.getUserEmail() != null && !productPageVo.getUserEmail().isEmpty()){
if (!StringUtils.isEmpty(productPageVo.getUserEmail())){
LeaseShop leaseShop = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>()
.eq(LeaseShop::getUserEmail, productPageVo.getUserEmail()));
if (leaseShop != null){
shopId = leaseShop.getId();
}else{
throw new ProductSoldOutException("不存在出售商品");
return PageResult.fail(new ArrayList<>(), "不存在出售商品");
}
}
PageHelper.startPage(productPageVo.getPageNum(), productPageVo.getPageSize());
List<LeaseProduct> leaseProducts = leaseProductMapper.getProductListForShopAndUserCenter(productPageVo.getCoin(), productPageVo.getAlgorithm(), shopId);
PageInfo<LeaseProduct> pageInfo = new PageInfo<>(leaseProducts);
List<ProductDto> leaseProducts = leaseProductMapper.getProductListForShopAndUserCenter(productPageVo.getCoin(), productPageVo.getAlgorithm(), shopId);
PageInfo<ProductDto> pageInfo = new PageInfo<>(leaseProducts);
if(leaseProducts.isEmpty()){
throw new ProductSoldOutException("不存在出售商品");
return PageResult.fail(new ArrayList<>(), "不存在出售商品");
}
//获取商品列表
List<ProductDto> collect = new ArrayList<>();
Set<Long> shopIds = new HashSet<>();
for (LeaseProduct product : leaseProducts) {
collect.add( ProductDto.builder()
.id(product.getId())
.name(product.getName())
.image(product.getImage())
.type(product.getType())
.state(product.getState())
.priceRange(product.getMaxPrice().equals(product.getMinPrice()) ?
product.getMaxPrice().toString() :
(product.getMinPrice().toString() +"-"+product.getMaxPrice().toString()))
.description(product.getDescription())
.algorithm(product.getAlgorithm())
.shopId(product.getShopId())
.coinFullName(product.getCoinFullName())
.saleNumber(product.getSaleNumber())
.totalMachineNumber(product.getTotalMachineNumber())
.coin(product.getCoin())
.build());
shopIds.add(product.getShopId());
//获取店铺对应的支付方式
List<Long> shopIds = leaseProducts.stream().map(ProductDto::getShopId).distinct().collect(Collectors.toList());
List<PayTypeDto> payType = leaseShopConfigMapper.getPayType(shopIds);
Map<Long, List<PayTypeDto>> payTypeMap = payType.stream().collect(Collectors.groupingBy(PayTypeDto::getShopId));
//配置支付列表
for (ProductDto productDto : leaseProducts) {
productDto.setPayTypes(payTypeMap.get(productDto.getShopId()));
}
List<LeaseShop> leaseShops = leaseShopMapper.selectList(new LambdaQueryWrapper<LeaseShop>().eq(LeaseShop::getState, 1).in(LeaseShop::getId, shopIds));
Map<Long, List<LeaseShop>> idMapShop = leaseShops.stream().collect(Collectors.groupingBy(LeaseShop::getId));
List<ProductDto> result = new ArrayList<>();
for (ProductDto productDto : collect) {
if (idMapShop.containsKey(productDto.getShopId())){
result.add(productDto);
}
}
PageResult<ProductDto> success = PageResult.success(result);
PageResult<ProductDto> success = PageResult.success(leaseProducts);
success.setTotal(pageInfo.getTotal());
success.setTotalPage(pageInfo.getPages());
PageHelper.clearPage();
@@ -147,30 +134,22 @@ public class LeaseProductServiceImpl extends ServiceImpl<LeaseProductMapper, Lea
}
@Override
public Result<ProductMachineInfoDto> getProductMachineInfo(Long productId) {
public PageResult<ProductMachineDto> getProductMachineInfo(ProductMachineVo productMachineVo) {
Long productId = productMachineVo.getId();
LeaseProduct product = getById(productId);
ProductMachineInfoDto productMachineInfoDto = new ProductMachineInfoDto();
//0.查询商品对应的收款钱包配置
List<PayConfigDto> shopWalletInfo = leaseShopMapper.getShopWalletInfo(product.getShopId());
productMachineInfoDto.setPayConfigList(shopWalletInfo);
//1.查询商品对应处于上架状态 以及未售出的 机器集合
List<LeaseProductMachine> leaseProductMachines = leaseProductMachineMapper.selectList(
new LambdaQueryWrapper<LeaseProductMachine>().eq(LeaseProductMachine::getProductId, productId)
.eq(LeaseProductMachine::getDel,false)
//.eq(LeaseProductMachine::getSaleState, 0)
.eq(LeaseProductMachine::getState, 0)
.orderByDesc(LeaseProductMachine::getSaleState)
);
if (leaseProductMachines.isEmpty()){
return Result.fail("该商品暂时没有可出售矿机");
PayConfigDto payConfigDto = shopWalletInfo.get(0);
PageHelper.startPage(productMachineVo.getPageNum(), productMachineVo.getPageSize());
if (StringUtils.isEmpty(productMachineVo.getChain()) && StringUtils.isEmpty(productMachineVo.getCoin())){
productMachineVo.setChain(payConfigDto.getPayChain());
productMachineVo.setCoin(payConfigDto.getPayCoin());
}
List<ProductMachineDto> productMachineDtoList = leaseProductMachineMapper.getMachinesByPriceAndPowerAndDissipation(productMachineVo, product.getCoin());
PageInfo<ProductMachineDto> pageInfo = new PageInfo<>(productMachineDtoList);
//2.理论收益 = 矿机算力/全网算力 * 24h 秒数 /出块间隔秒数 * 单块奖励redis中nexa:reward
//查询矿机一天范围内的实际平均算力 单位为MH/S
List<ProductMachineDto> nexaMinersv2 = leaseProductMachineMapper.getRecentlyFiveMinutesData(leaseProductMachines, product.getCoin());
if (productMachineDtoList.isEmpty()){
return PageResult.fail(new ArrayList<>(),"不存在矿机");
}
//币价 单位usdt
BigDecimal price = redisService.getCacheBigDecimal(RedisKey.getPiceKey(product.getCoin())) == null ? BigDecimal.ZERO : redisService.getCacheBigDecimal(RedisKey.getPiceKey(product.getCoin()));
//报块奖励
@@ -178,84 +157,73 @@ public class LeaseProductServiceImpl extends ServiceImpl<LeaseProductMapper, Lea
//全网算力单位是MH/s
BigDecimal mhs = redisService.getCacheBigDecimal(RedisKey.getMhsKey(product.getCoin())) == null ? BigDecimal.ZERO : redisService.getCacheBigDecimal(RedisKey.getMhsKey(product.getCoin()));
// 创建一个 Map 用于存储 user 和 miner 组合对应的 ProductMachineDto 对象
Map<String, ProductMachineDto> machineDtoMap = nexaMinersv2.stream()
.collect(Collectors.toMap(
dto -> dto.getUser() + "-" + dto.getMiner(),
dto -> dto
));
List<ProductMachineDto> productMachines = leaseProductMachines.stream()
.map(leaseProductMachine -> {
String key = leaseProductMachine.getUser() + "-" + leaseProductMachine.getMiner();
ProductMachineDto productMachineDto = machineDtoMap.get(key);
List<ProductMachineDto> productMachines = productMachineDtoList.stream()
.peek(productMachineDto -> {
//理论收益
BigDecimal singleTheoryMachineIncome = BigDecimal.ZERO;
BigDecimal computingPower = BigDecimal.ZERO;
if (productMachineDto != null) {
// 矿机算力单位转换 + 计算单矿机平均算力(ComputingPower coin_mhs30m 平均算力)
computingPower = PowerUnitUtils.getPower(leaseProductMachine.getUnit(),
productMachineDto.getComputingPower()
.multiply(BigDecimal.valueOf(1000 * 1000))
productMachineDto.setAlgorithm(product.getAlgorithm());
// 矿机算力单位转换 + 计算单矿机平均算力(ComputingPower coin_real_power 24小时总算力)
BigDecimal computingPower = PowerUnitUtils.getPower(productMachineDto.getUnit(), productMachineDto.getComputingPower().multiply(BigDecimal.valueOf(1000 * 1000))
.divide(BigDecimal.valueOf(24 * 60 * 60),2,RoundingMode.HALF_UP));
if (mhs == null || reward == null || price == null){
singleTheoryMachineIncome = leaseProductMachine.getTheoryIncome();
}else{
//全网算力单位转换
BigDecimal power = PowerUnitUtils.getPower(leaseProductMachine.getUnit(), mhs.multiply(BigDecimal.valueOf(1000 * 1000)));
BigDecimal power = PowerUnitUtils.getPower(productMachineDto.getUnit(), mhs.multiply(BigDecimal.valueOf(1000 * 1000)));
//(理论收益 = 矿机算力/全网算力 * 24h /出块间隔秒数 * 单块奖励redis中nexa:reward
singleTheoryMachineIncome = computingPower.divide( power,6, RoundingMode.HALF_UP)
.multiply(BigDecimal.valueOf(24 * 60 * 60)
.divide(BlockInterval.getBlockCountByCoinName(product.getCoin()), 6, RoundingMode.HALF_UP))
.multiply(reward);
productMachineDto.setComputingPower(computingPower);
productMachineDto.setTheoryIncome(singleTheoryMachineIncome);
productMachineDto.setTheoryUsdtIncome(singleTheoryMachineIncome.multiply(price));
})
.collect(Collectors.toList());
//分页内排序
productMachines = sorted(productMachines,productMachineVo);
PageResult<ProductMachineDto> success = PageResult.success(productMachines);
success.setTotal(pageInfo.getTotal());
success.setTotalPage(pageInfo.getPages());
PageHelper.clearPage();
return success;
}
public List<ProductMachineDto> sorted(List<ProductMachineDto> productMachineDtoList,ProductMachineVo productMachineVo){
if (productMachineVo.getPriceSort() != null) {
Comparator<ProductMachineDto> priceComparator = productMachineVo.getPriceSort() ?
Comparator.comparing(ProductMachineDto::getPrice) :
Comparator.comparing(ProductMachineDto::getPrice).reversed();
return productMachineDtoList.stream()
.sorted(priceComparator)
.collect(Collectors.toList());
} else if (productMachineVo.getPowerSort() != null) {
Comparator<ProductMachineDto> powerComparator = productMachineVo.getPowerSort() ?
Comparator.comparing(ProductMachineDto::getComputingPower) :
Comparator.comparing(ProductMachineDto::getComputingPower).reversed();
return productMachineDtoList.stream()
.sorted(powerComparator)
.collect(Collectors.toList());
} else if (productMachineVo.getPowerDissipationSort() != null) {
Comparator<ProductMachineDto> powerDissipationComparator = productMachineVo.getPowerDissipationSort() ?
Comparator.comparing(ProductMachineDto::getPowerDissipation) :
Comparator.comparing(ProductMachineDto::getPowerDissipation).reversed();
return productMachineDtoList.stream()
.sorted(powerDissipationComparator)
.collect(Collectors.toList());
} else {
return productMachineDtoList;
}
}
return ProductMachineDto.builder()
.id(leaseProductMachine.getId())
.user(leaseProductMachine.getUser())
.miner(leaseProductMachine.getMiner())
.price(leaseProductMachine.getPrice())
.type(leaseProductMachine.getType())
.algorithm(product.getAlgorithm())
.theoryPower(leaseProductMachine.getTheoryPower())
.computingPower(computingPower)
.maxLeaseDays(leaseProductMachine.getMaxLeaseDays())
.unit(leaseProductMachine.getUnit())
.saleState(leaseProductMachine.getSaleState())
.state(leaseProductMachine.getState())
.powerDissipation(leaseProductMachine.getPowerDissipation())
.theoryIncome(singleTheoryMachineIncome)
.theoryUsdtIncome(singleTheoryMachineIncome.multiply( price))
.coin(leaseProductMachine.getCoin())
.build();
})
//.filter(Objects::nonNull)
//.sorted(Comparator.comparing(ProductMachineDto::getPrice))
.collect(Collectors.toList());
//所有机器按价格分组
Map<BigDecimal, List<ProductMachineDto>> productMachineDtoMap = productMachines.stream()
.sorted(Comparator.comparing(ProductMachineDto::getSaleState))
.collect(Collectors.groupingBy(ProductMachineDto::getPrice));
@Override
public Result<List<PayConfigDto>> getPayTypes() {
LeaseShop leaseShop = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>()
.select(LeaseShop::getId)
.eq(LeaseShop::getUserEmail, SecurityUtils.getUsername())
.eq(LeaseShop::getDel, false));
//计算实际,理论算力功耗等范围值
Map<BigDecimal, ProductMachineRangeGroupDto> bigDecimalProductMachineRangeDtoMap = calculateRanges(productMachineDtoMap);
List<ProductMachineRangeInfoDto> collect = bigDecimalProductMachineRangeDtoMap.entrySet().stream()
.map(entry -> {
BigDecimal key = entry.getKey();
ProductMachineRangeGroupDto rangeDto = entry.getValue();
List<ProductMachineDto> machines = productMachineDtoMap.get(key);
return ProductMachineRangeInfoDto.builder()
.productMachineRangeGroupDto(rangeDto)
.productMachines(machines)
.build();
})
// 按照 rangeDto 的 price 字段降序排序
.sorted(Comparator.comparing(info -> info.getProductMachineRangeGroupDto().getPrice()))
.collect(Collectors.toList());
productMachineInfoDto.setMachineRangeInfoList( collect);
return Result.success(productMachineInfoDto);
List<PayConfigDto> shopWalletInfo = leaseShopMapper.getShopWalletInfo(leaseShop.getId());
return Result.success(shopWalletInfo);
}
/**
@@ -296,7 +264,6 @@ public class LeaseProductServiceImpl extends ServiceImpl<LeaseProductMapper, Lea
.orElse(BigDecimal.ZERO);
String theoryPowerRange = minTheoryPower.equals(maxTheoryPower) ? String.valueOf(minTheoryPower) : minTheoryPower + " - " + maxTheoryPower;
// 计算实际算力范围
BigDecimal minComputingPower = productMachines.stream()
.map(ProductMachineDto::getComputingPower)
@@ -390,95 +357,6 @@ public class LeaseProductServiceImpl extends ServiceImpl<LeaseProductMapper, Lea
return Result.success("修改商品成功");
}
return Result.fail("修改商品失败");
////修改商品对应库存矿机表
//List<LeaseProductMachine> collect = new ArrayList<>();
//if (!BigDecimal.ZERO.equals(productURDVo.getPower())){
// //如果修改了算力power 就需要对应修改该商品下的算力
// List<LeaseProductMachine> leaseProductMachines = leaseProductMachineMapper.selectList(
// new LambdaQueryWrapper<LeaseProductMachine>().eq(LeaseProductMachine::getProductId, productURDVo.getId())
// .eq(LeaseProductMachine::getDel,false));
//
// //计算对应user+miner 近3天算力总和
// List<ProductMachineDto> nexaMinersv2 = leaseNexaMachinePowerMapper.getRecentlyFiveMinutesData(leaseProductMachines, productURDVo.getCoin());
// // 创建一个 Map 用于存储 user 和 miner 组合对应的 ProductMachineDto 对象
// Map<String, ProductMachineDto> machineDtoMap = nexaMinersv2.stream()
// .collect(Collectors.toMap(
// dto -> dto.getUser() + "-" + dto.getMiner(),
// dto -> dto
// ));
//
// BigDecimal price = redisService.getCacheObject(RedisKey.getPiceKey(product.getCoin()));
// BigDecimal reward = redisService.getCacheObject(RedisKey.getRewardKey(product.getCoin()));
// //全网算力单位是MH/s
// BigDecimal mhs = redisService.getCacheObject(RedisKey.getMhsKey(product.getCoin()));
// if (price == null){
// return Result.fail("修改商品失败,未获取到"+product.getCoin()+"币的币价,请稍后重试");
// }
// if (reward == null){
// return Result.fail("修改商品失败,未获取到"+product.getCoin()+"币的报快奖励,请稍后重试");
// }
// if (mhs == null){
// return Result.fail("修改商品失败,未获取到"+product.getCoin()+"币的全网算力,请稍后重试");
// }
//
//
// ////得到3天内的全网算力平均值
// //BigDecimal netPower = leaseProductMapper.getCoinNetPower(productURDVo.getCoin());
// //
// ////获取近三天全网实际报块数
// //BigDecimal actualNetBlocks = leaseProductMapper.getNetBlocks(productURDVo.getCoin());
// //
// ////获取全网理论报块
// //BigDecimal theoryNetBlocks = DailyBlockOutputConstant.getBlockCountByCoinName(productURDVo.getCoin());
// //
// ////计算单机理论收益(商品对应的同类型机器都是这个固定值)
// //BigDecimal singleTheoryMachineIncome = productURDVo.getPower()
// // .divide(netPower, 8, RoundingMode.HALF_UP)
// // .multiply(theoryNetBlocks);
//
// collect = leaseProductMachines.stream().peek(productMachine-> {
// //获取单机实际算力
// String key = productMachine.getUser() + "-" + productMachine.getMiner();
// ProductMachineDto productMachineDto = machineDtoMap.get(key);
//
// BigDecimal singleActualMachineIncome = BigDecimal.ZERO;
// BigDecimal singleTheoryMachineIncome = BigDecimal.ZERO;
// if (productMachineDto != null){
// //// 将 LocalDateTime 转换为 Instant 并使用 Duration 计算毫秒差
// //Instant startInstant = productMachineDto.getStartTime().atZone(ZoneId.systemDefault()).toInstant();
// //Instant endInstant = productMachineDto.getEndTime().atZone(ZoneId.systemDefault()).toInstant();
// //Duration duration = Duration.between(startInstant, endInstant);
// //long millis = duration.toMillis();
// //// 计算单矿机3天内平均算力
// //BigDecimal actualPower = productMachineDto.getComputingPower()
// // .multiply(BigDecimal.valueOf(Math.pow(2, 32)))
// // //这里计算的是3天内
// // .divide(BigDecimal.valueOf(millis), 2, RoundingMode.HALF_UP);
// ////计算预估实际收益
// //singleActualMachineIncome = actualPower
// // .divide(netPower, 8, RoundingMode.HALF_UP)
// // .multiply(actualNetBlocks);
//
// //理论收益 = 矿机算力/全网算力 * 24h /出块间隔秒数 * 单块奖励redis中nexa:reward
// singleTheoryMachineIncome = mhs.divide( productMachineDto.getComputingPower(),6, RoundingMode.HALF_UP)
// .multiply(BigDecimal.valueOf(24 * 60 * 60).divide(BlockInterval.getBlockCountByCoinName(product.getCoin()), 6, RoundingMode.HALF_UP))
// .multiply(reward);
//
// }
// //productMachine.setActualIncome(singleActualMachineIncome);
// productMachine.setTheoryIncome(singleTheoryMachineIncome);
// }).collect(Collectors.toList());
//
//}
//if (collect.isEmpty() && b1){
// return Result.success("修改成功");
//}
//boolean b = leaseProductMachineService.updateBatchById(collect);
//if (b && b1){
// return Result.success("修改成功");
//}
//return Result.fail("修改失败");
}
@Override
@@ -488,15 +366,137 @@ public class LeaseProductServiceImpl extends ServiceImpl<LeaseProductMapper, Lea
if(i >= 1){
return Result.fail("删除失败,该商品存在租约中的机器");
}
boolean updateFather = updateById(LeaseProduct.builder().id(id).del(true).build());
//int delete = leaseProductMachineMapper.delete(new LambdaQueryWrapper<LeaseProductMachine>().eq(LeaseProductMachine::getProductId, id));
int update = leaseProductMachineMapper.update(LeaseProductMachine.builder().del(true).build(),
new LambdaQueryWrapper<LeaseProductMachine>().eq(LeaseProductMachine::getProductId, id));
List<Long> machineIds = leaseProductMachineMapper.getIdsForProductId(id);
if (updateFather){
if (!machineIds.isEmpty()){
leaseProductMachineMapper.update(LeaseProductMachine.builder().del(true).build(),
new LambdaQueryWrapper<LeaseProductMachine>().in(LeaseProductMachine::getId, machineIds));
//删除矿机对应的售价
leaseProductMachinePriceService.remove(new LambdaUpdateWrapper<LeaseProductMachinePrice>()
.in(LeaseProductMachinePrice::getProductMachineId, machineIds));
}
if (updateFather || update > 0){
return Result.success("删除成功");
}
return Result.fail("删除失败");
}
@Override
public Result<List<PayTypeDto>> getSupportPayType() {
Long shopId = getShopIdByProductId();
List<PayTypeDto> supportPayType = leaseProductMapper.getSupportPayType(shopId);
return Result.success(supportPayType);
}
@Override
public Result<List<ProductForWalletConfigDto>> getProductListForShopWalletConfig() {
Long shopId = getShopIdByProductId();
//1.获取商品列表
List<ProductForWalletConfigDto> productForShopWalletConfigDtoList = leaseProductMapper.getProductListForShopWalletConfig(shopId);
if (productForShopWalletConfigDtoList.isEmpty()){
return Result.success(productForShopWalletConfigDtoList);
}
//2.获取商品对应矿机
List<ProductMachineForWalletConfigDto> productMachineForWalletConfigDtoList = leaseProductMachineMapper.getProductListForShopWalletConfig(shopId);
BigDecimal usdtPrice = redisService.getCacheBigDecimal(RedisKey.getPiceKey(productForShopWalletConfigDtoList.get(0).getCoin()));
Map<Long, List<ProductMachineForWalletConfigDto>> collect = productMachineForWalletConfigDtoList.stream()
.peek(productMachineForWalletConfigDto -> {
productMachineForWalletConfigDto.setTheoryUsdtIncome(productMachineForWalletConfigDto.getTheoryIncome()
.multiply(usdtPrice));
})
.collect(Collectors.groupingBy(ProductMachineForWalletConfigDto::getProductId));
for (ProductForWalletConfigDto productForWalletConfigDto : productForShopWalletConfigDtoList) {
List<ProductMachineForWalletConfigDto> list = collect.get(productForWalletConfigDto.getProductId());
if (list.isEmpty()){
productForShopWalletConfigDtoList.remove(productForWalletConfigDto);
}
productForWalletConfigDto.setMachineList(list);
}
return Result.success(productForShopWalletConfigDtoList);
}
public Long getShopIdByProductId(){
LeaseShop leaseShop = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>()
.select(LeaseShop::getId)
.eq(LeaseShop::getUserEmail, SecurityUtils.getUsername())
.eq(LeaseShop::getDel, false));
return leaseShop.getId();
}
@Override
@Transactional
public Result<String> updateProductListForShopWalletConfig(ProductMachineForWalletConfigVo productMachineForWalletConfigVo) {
List<String> payCoinsList = new ArrayList<>(Arrays.asList(productMachineForWalletConfigVo.getSymbol().split(",")));
String chain = productMachineForWalletConfigVo.getChain();
String address = productMachineForWalletConfigVo.getPayAddress();
LeaseShop leaseShop = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>()
.eq(LeaseShop::getUserEmail, SecurityUtils.getUsername()));
boolean check = checkHashWalletInfo(leaseShop.getId(),chain,address, payCoinsList);
if (!check){
return Result.fail("绑定钱包失败,钱包格式不正确或该链和币种钱包已绑定过");
}
String[] symbolList = productMachineForWalletConfigVo.getSymbol().split(",");
List<ProductMachineForWalletConfigVo.PriceVo> priceAndIdList = productMachineForWalletConfigVo.getProductMachineForWalletConfigVoList();
List<LeaseProductMachinePrice> leaseProductMachinePriceList = new ArrayList<>();
for (ProductMachineForWalletConfigVo.PriceVo priceVo : priceAndIdList) {
String[] priceList = priceVo.getPrice().split(",");
if (priceList.length != symbolList.length){
return Result.fail("绑定钱包失败,存在商品矿机未设置新钱包售价");
}
for (int i = 0; i < priceList.length; i++) {
leaseProductMachinePriceList.add(LeaseProductMachinePrice.builder()
.productMachineId(priceVo.getProductMachineId())
.price(new BigDecimal(priceList[i]))
.coin(symbolList[i])
.chain(chain)
.build());
}
}
boolean b = leaseProductMachinePriceService.saveBatch(leaseProductMachinePriceList);
if (b || leaseProductMachinePriceList.isEmpty()){
//绑定钱包新钱包
List<LeaseShopConfig> shopConfigList = leaseShopConfigMapper.getCoinIconByChainAndCoin(chain, payCoinsList);
String qrCode = QrCodeUtils.creatRrCode(address, 200, 200);
for (LeaseShopConfig leaseShopConfig : shopConfigList) {
leaseShopConfig.setShopId(leaseShop.getId());
leaseShopConfig.setChain(chain);
leaseShopConfig.setPayAddress(address);
leaseShopConfig.setQrcode(qrCode);
}
boolean insetWallet = leaseShopConfigService.saveBatch(shopConfigList);
if (insetWallet){
return Result.success("绑定钱包成功");
}
throw new ProductSoldOutException ("钱包绑定失败");
}
throw new ProductSoldOutException ("新币种钱包商品售价新增失败");
}
/**
* 钱包格式校验,以及判断该链和币种钱包是否已存在
* @param chain
* @param address
* @param coinList
* @return
*/
public boolean checkHashWalletInfo(Long shopId,String chain,String address,List<String> coinList){
if (!WalletRuleCheckUtils.checkAddress(chain,address)){
return false;
}
List<LeaseShopConfig> configList = leaseShopConfigMapper.selectList(new LambdaQueryWrapper<LeaseShopConfig>()
.eq(LeaseShopConfig::getShopId, shopId)
.eq(LeaseShopConfig::getChain, chain)
.in(LeaseShopConfig::getPayCoin, coinList)
.eq(LeaseShopConfig::getDel, false)
);
if (!configList.isEmpty()){
return false;
}
return true;
}
}

View File

@@ -241,7 +241,7 @@ public class LeaseShopServiceImpl extends ServiceImpl<LeaseShopMapper, LeaseShop
//钱包地址校验
if (!WalletRuleCheckUtils.checkAddress(shopConfigVo.getChain(),shopConfigVo.getPayAddress())){
return Result.fail("提现地址格式不符合"+shopConfigVo.getChain()+"节点");
return Result.fail("钱包地址格式错误");
}
LeaseShop leaseShop = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>()
.eq(LeaseShop::getUserEmail, SecurityUtils.getUsername()));

View File

@@ -1,5 +1,6 @@
package com.m2pool.lease.service.impl;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -7,6 +8,7 @@ import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.m2pool.common.redis.service.RedisService;
import com.m2pool.common.security.utils.SecurityUtils;
import com.m2pool.lease.constant.BlockInterval;
import com.m2pool.lease.constant.PowerUnit;
import com.m2pool.lease.constant.RedisKey;
import com.m2pool.lease.dto.*;
@@ -24,6 +26,7 @@ import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
@@ -59,10 +62,10 @@ public class LeaseShoppingCartServiceImpl extends ServiceImpl<LeaseShoppingCartM
private LeaseProductMachineMapper leaseProductMachineMapper;
@Resource
private LeaseUserOwnedProductMapper leaseUserOwnedProductMapper;
private LeaseShopMapper leaseShopMapper;
@Resource
private LeaseShopMapper leaseShopMapper;
private LeaseProductMachinePriceMapper leaseProductMachinePriceMapper;
@Resource
private RedisService redisService;
@@ -166,88 +169,117 @@ public class LeaseShoppingCartServiceImpl extends ServiceImpl<LeaseShoppingCartM
}
@Override
public PageResult<ShopCartDto> getGoodsList(PageVo pageVo) {
//1.获取用户购物车
String userId = SecurityUtils.getUsername();
//检查购物车中是否存在商品
LeaseShoppingCart leaseShoppingCart = leaseShoppingCartMapper.selectOne(new LambdaQueryWrapper<LeaseShoppingCart>()
.eq(LeaseShoppingCart::getUserId, userId));
if (leaseShoppingCart == null){
return PageResult.fail(null,"购物车中不存在商品");
return PageResult.success(new ArrayList<>());
}
//获取商品相关信息
List<ShoppingCartInfoDto> cartInfoList = leaseShoppingCartInfoMapper.getCartInfoList(leaseShoppingCart.getId());
PageInfo<ShoppingCartInfoDto> pageInfo = new PageInfo<>(cartInfoList);
List<ShoppingCartInfoDto> cartInfoList = leaseShoppingCartInfoMapper.getProductAndMachineIds(leaseShoppingCart.getId());
if (cartInfoList.isEmpty()){
return PageResult.fail(null,"购物车中不存在商品");
return PageResult.success(new ArrayList<>());
}
List<Long> productIds = new ArrayList<>();
List<Long> machineIds = new ArrayList<>();
Map<Long, Integer> machineMap = new HashMap<>();
for (ShoppingCartInfoDto shoppingCartInfoDto : cartInfoList) {
productIds.add(shoppingCartInfoDto.getProductId());
machineIds.add(shoppingCartInfoDto.getProductMachineId());
machineMap.put(shoppingCartInfoDto.getProductMachineId(), shoppingCartInfoDto.getLeaseTime());
}
List<Long> shopIds = leaseShopMapper.getShopIdsByProductIds(productIds);
PageHelper.startPage(pageVo.getPageNum(), pageVo.getPageSize());
//查询购物车中店铺信息
Map<Long, List<ShoppingCartInfoDto>> shopGroupMap = cartInfoList.stream().collect(Collectors.groupingBy(ShoppingCartInfoDto::getShopId));
List<LeaseShop> leaseShops = leaseShopMapper.selectList(new LambdaQueryWrapper<LeaseShop>().in(LeaseShop::getId, shopGroupMap.keySet()));
//查询购物车中店铺信息(一层)
List<LeaseShop> leaseShops = leaseShopMapper.selectList(new LambdaQueryWrapper<LeaseShop>().in(LeaseShop::getId, shopIds));
//获取商品下机器id集合
List<Long> machineIds = cartInfoList.stream().map(ShoppingCartInfoDto::getProductMachineId).collect(Collectors.toList());
//获取机器id 为key 机器详情集合为value 的map
List<LeaseShoppingCartInfo> leaseShoppingCartInfos = leaseShoppingCartInfoMapper.selectList(new LambdaQueryWrapper<LeaseShoppingCartInfo>()
.eq(LeaseShoppingCartInfo::getCartId, leaseShoppingCart.getId()));
Map<Long, LeaseShoppingCartInfo> machineMap = leaseShoppingCartInfos.stream().collect(Collectors.toMap(LeaseShoppingCartInfo::getProductMachineId, Function.identity()));
//查询商品中机器详情 + 按照币种分组
//获取商品售价
List<MachinePayTypeDto> machinePriceByMachineIds = leaseProductMachinePriceMapper.getMachinePriceByMachineIds(machineIds);
Map<Long, List<MachinePayTypeDto>> machinePriceMap = machinePriceByMachineIds.stream().collect(Collectors.groupingBy(MachinePayTypeDto::getProductMachineId));
//查询商品中机器详情 + 按照币种分组 (二层)
List<ProductMachineDto> leaseProductMachines = leaseProductMachineMapper.getMachinesByIds(machineIds);
Map<String, List<UserMinerDto>> userAndMinerList = leaseProductMachines.stream().map(
//获取实时币价
List<String> coins = leaseProductMachines.stream().map(ProductMachineDto::getCoin).distinct().collect(Collectors.toList());
Map<String, BigDecimal> coinPriceMap = new HashMap<>();
Map<String, BigDecimal> coinRewardMap = new HashMap<>();
Map<String, BigDecimal> coinMhsMap = new HashMap<>();
for (String coin : coins) {
BigDecimal price = redisService.getCacheBigDecimal(RedisKey.getPiceKey(coin));
BigDecimal reward =redisService.getCacheBigDecimal(RedisKey.getRewardKey(coin));
BigDecimal mhs = redisService.getCacheBigDecimal(RedisKey.getMhsKey(coin));
coinMhsMap.put(coin, mhs);
coinRewardMap.put(coin, reward);
coinPriceMap.put(coin, price);
}
//按币种查询每个矿机的最近一次30分钟的实时算力(后续修改为24小时平均算力)
List<ProductMachineDto> userMinerPowerList = new ArrayList<>();
Map<String, List<LeaseProductMachine>> userAndMinerList = leaseProductMachines.stream().map(
ProductMachineDto ->
UserMinerDto.builder()
LeaseProductMachine.builder()
.user(ProductMachineDto.getUser())
.miner(ProductMachineDto.getMiner())
.coin(ProductMachineDto.getCoin())
.build()
).collect(Collectors.groupingBy(UserMinerDto::getCoin));
).collect(Collectors.groupingBy(LeaseProductMachine::getCoin));
//获取实时币价
List<String> coins = leaseProductMachines.stream().map(ProductMachineDto::getCoin).distinct().collect(Collectors.toList());
Map<String, BigDecimal> coinPriceMap = new HashMap<>();
for (String coin : coins) {
BigDecimal price = redisService.getCacheBigDecimal(RedisKey.getPiceKey(coin));
if (price == null){
price = BigDecimal.ZERO;
}
coinPriceMap.put(coin, price);
}
//按币种查询每个矿机的最近一次30分钟的实时算力(后续修改为24小时平均算力)
List<UserMinerPowerDto> userMinerPowerList = new ArrayList<>();
userAndMinerList.forEach((coin, userMinerDtos) -> {
userMinerPowerList.addAll(leaseUserOwnedProductMapper.getUserMinerPower(userMinerDtos, coin));
List<ProductMachineDto> recentlyFiveMinutesData = leaseProductMachineMapper.getRecentlyFiveMinutesData(userMinerDtos, coin);
List<ProductMachineDto> collect = recentlyFiveMinutesData.stream().peek(dto -> {
dto.setCoin(coin);
}).collect(Collectors.toList());
userMinerPowerList.addAll(collect);
});
Map<String, UserMinerPowerDto> realPowerList = userMinerPowerList.stream()
Map<String, ProductMachineDto> realPowerList = userMinerPowerList.stream()
.collect(Collectors.toMap(
dto -> dto.getUser() + "-" + dto.getMiner() + "-" + dto.getCoin(),
dto -> dto
));
//为每个矿机设置实时的算力 + 按店铺分组
Map<Long, List<ProductMachineDto>> shopIdAndMachineInfoMap = leaseProductMachines.stream().peek(productMachineDto -> {
UserMinerPowerDto userMinerPowerDto = realPowerList.get(productMachineDto.getUser() + "-" + productMachineDto.getMiner() + "-" + productMachineDto.getCoin());
ProductMachineDto userMinerPowerDto = realPowerList.get(productMachineDto.getUser() + "-" + productMachineDto.getMiner() + "-" + productMachineDto.getCoin());
List<MachinePayTypeDto> machinePayTypeDtoList = machinePriceMap.get(productMachineDto.getId());
productMachineDto.setPriceList(machinePayTypeDtoList);
//理论收益
BigDecimal singleTheoryMachineIncome;
BigDecimal computingPower;
BigDecimal singleTheoryUSDTMachineIncome;
if (userMinerPowerDto != null) {
// 矿机算力单位转换 + 计算单矿机平均算力(ComputingPower coin_mhs30m 平均算力)
computingPower = PowerUnitUtils.getPower(productMachineDto.getUnit(),
userMinerPowerDto.getComputingPower()
.multiply(BigDecimal.valueOf(1000 * 1000))
.divide(BigDecimal.valueOf(24 * 60 * 60 ), 2, RoundingMode.HALF_UP));
BigDecimal mhs = coinMhsMap.get(productMachineDto.getCoin());
BigDecimal reward = coinRewardMap.get(productMachineDto.getCoin());
BigDecimal price = coinPriceMap.get(productMachineDto.getCoin());
if (mhs == null || reward == null || price == null){
singleTheoryMachineIncome = productMachineDto.getTheoryIncome();
singleTheoryUSDTMachineIncome = singleTheoryMachineIncome.multiply(price);
}else{
//全网算力单位转换
BigDecimal power = PowerUnitUtils.getPower(productMachineDto.getUnit(),mhs).multiply(BigDecimal.valueOf(1000 * 1000));
//(理论收益 = 矿机算力/全网算力 * 24h /出块间隔秒数 * 单块奖励redis中nexa:reward
singleTheoryMachineIncome = computingPower.divide( power,6, RoundingMode.HALF_UP)
.multiply(BigDecimal.valueOf(24 * 60 * 60)
.divide(BlockInterval.getBlockCountByCoinName(productMachineDto.getCoin()), 6, RoundingMode.HALF_UP)).multiply(reward);
singleTheoryUSDTMachineIncome = singleTheoryMachineIncome.multiply(price);
}
//单位为MH/s 需要转换成 矿机设定的单位
BigDecimal value = userMinerPowerDto.getPower().multiply(PowerUnit.getPower(MH_UNIT));
productMachineDto.setComputingPower(PowerUnitUtils.getPower(productMachineDto.getUnit(),value));
productMachineDto.setTheoryUsdtIncome(productMachineDto.getTheoryIncome().multiply(coinPriceMap.get(productMachineDto.getCoin())));
productMachineDto.setStartTime(userMinerPowerDto.getStartTime());
productMachineDto.setEndTime(LocalDateTime.now());
productMachineDto.setComputingPower(computingPower);
productMachineDto.setTheoryIncome(singleTheoryMachineIncome);
productMachineDto.setTheoryUsdtIncome(singleTheoryUSDTMachineIncome);
}
}).collect(Collectors.groupingBy(ProductMachineDto::getShopId));
//获取商铺钱包配置信息
List<Long> shopIds = leaseShops.stream().map(LeaseShop::getId).collect(Collectors.toList());
List<PayConfigDto> shopWalletInfo = leaseShopMapper.getShopWalletInfoList(shopIds);
Map<Long, List<PayConfigDto>> payConfigMap = shopWalletInfo.stream().collect(Collectors.groupingBy(PayConfigDto::getShopId));
//组合返回对象
List<ShopCartDto> shopCartList = leaseShops.stream().map(leaseShop -> {
List<ProductMachineDto> productMachineList = shopIdAndMachineInfoMap.get(leaseShop.getId());
return ShopCartDto.builder()
.id(leaseShop.getId())
@@ -258,33 +290,39 @@ public class LeaseShoppingCartServiceImpl extends ServiceImpl<LeaseShoppingCartM
.build();
}).collect(Collectors.toList());
//结算总价计算
//计算不同链和币种对应的总售价
for (ShopCartDto shopCartDto : shopCartList) {
BigDecimal totalPrice = BigDecimal.ZERO;
//遍历每个商铺下的矿机
List<ProductMachineDto> productMachineDtoList = shopCartDto.getProductMachineDtoList();
if ( productMachineDtoList!= null) {
Map<String, BigDecimal> totalPriceMap = new HashMap<>();
Map<String, MachineTotalPriceDto> totalPriceDtoMap = new HashMap<>();
for (ProductMachineDto productMachineDto : productMachineDtoList) {
LeaseShoppingCartInfo cartInfo = machineMap.get(productMachineDto.getId());
if (cartInfo != null ) {
Integer leaseTime = cartInfo.getLeaseTime();
Integer leaseTime = machineMap.get(productMachineDto.getId());
productMachineDto.setLeaseTime(leaseTime);
// 处理空指针情况
BigDecimal price = productMachineDto.getPrice();
if (price != null && leaseTime != null) {
BigDecimal itemPrice = price.multiply(new BigDecimal(leaseTime));
totalPrice = totalPrice.add(itemPrice);
List<MachinePayTypeDto> priceList = productMachineDto.getPriceList();
for (MachinePayTypeDto machinePayTypeDto : priceList) {
BigDecimal itemPrice = machinePayTypeDto.getPrice().multiply(new BigDecimal(leaseTime));
String key = machinePayTypeDto.getCoin()+"-"+machinePayTypeDto.getChain();
totalPriceMap.merge(key, itemPrice, BigDecimal::add);
totalPriceDtoMap.put(key,new MachineTotalPriceDto(BigDecimal.ZERO, machinePayTypeDto.getChain(), machinePayTypeDto.getCoin()));
}
}
;
totalPriceDtoMap.forEach((key, value) -> {
value.setPrice(totalPriceMap.get(key));
});
shopCartDto.setTotalPriceList(new ArrayList<>(totalPriceDtoMap.values()));
}
}
shopCartDto.setTotalPrice(totalPrice);
}
PageInfo<ShopCartDto> pageInfo = new PageInfo<>(shopCartList);
PageResult<ShopCartDto> success = PageResult.success(shopCartList);
success.setTotal(pageInfo.getTotal());
success.setTotalPage(pageInfo.getPages());
PageHelper.clearPage();
return success;
}

View File

@@ -1,116 +0,0 @@
package com.m2pool.lease.task;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.m2pool.lease.dto.ProductMachineDto;
import com.m2pool.lease.entity.LeaseNexaMachineAvgPower;
import com.m2pool.lease.entity.LeaseNexaMachinePower;
import com.m2pool.lease.entity.LeaseProductMachine;
import com.m2pool.lease.mapper.LeaseNexaMachineAvgPowerMapper;
import com.m2pool.lease.mapper.LeaseNexaMachinePowerMapper;
import com.m2pool.lease.mapper.LeaseProductMachineMapper;
import com.m2pool.lease.mapper.LeaseUserOwnedProductMapper;
import com.m2pool.lease.service.LeaseNexaMachinePowerService;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
/**
* @Description 后台管理系统 定时任务 (没有用到后续可能删除)
* @Date 2025/7/15 15:45
* @Author yyb
*/
@Configuration
@EnableScheduling
@Deprecated
public class MachineTask {
//
//@Resource
//private LeaseNexaMachinePowerMapper leaseNexaMachinePowerMapper;
//
//@Resource
//private LeaseUserOwnedProductMapper leaseUserOwnedProductMapper;
//
//@Resource
//private LeaseProductMachineMapper leaseProductMachineMapper;
//
//
//@Resource
//private LeaseNexaMachinePowerService leaseNexaMachinePowerService;
//
//@Resource
//private LeaseNexaMachineAvgPowerMapper leaseNexaMachineAvgPowerMapper;
//
///**
// * 每五分钟更新一次已经出售的机器的算力(所有币种数据)
// */
//@Scheduled(cron = "0 0/5 * * * ?")
//public void insertMachinePowerTask(){
// // 获取五分钟前的时间
// Calendar calendar = Calendar.getInstance();
// calendar.set(Calendar.SECOND, 0);
// calendar.set(Calendar.MILLISECOND, 0);
// calendar.add(Calendar.MINUTE, -5);
// Date pointDate = calendar.getTime();
// //获取当天零点时间
// DateTime dateTime = DateUtil.beginOfDay(DateTime.now());
// //1.查询已购生效机器ids集合
// List<Long> productMachineIds = leaseUserOwnedProductMapper.getProductMachineIds(dateTime);
// if (productMachineIds.isEmpty()){
// System.out.println("没有存在租赁期机器");
// return;
// }
// // 2. 先查询已购表中的在有效期内的机器user 和 miner
// List<LeaseProductMachine> leaseProductMachines = leaseProductMachineMapper.selectList(new LambdaQueryWrapper<LeaseProductMachine>().in(LeaseProductMachine::getId, productMachineIds));
// // 3.根据这个user 和 miner 从hashrate库中获取对应的实时算力 TODO 这里可能不需要记录实时算力 并且这个定时任务也不需要了。这个实时算力没多大用 后续用收益代替
// List<LeaseNexaMachinePower> nexaMinersv2 = leaseNexaMachinePowerMapper.getMachinePowerInHashRateById(leaseProductMachines,pointDate, "nexa_minersv2");
// //4.向数据库写入数据
// boolean b = leaseNexaMachinePowerService.saveBatch(nexaMinersv2);
// System.out.println("矿工算力入库状态(true 成功 false 失败)" + b);
//}
//
///**
// * 每半小时更新一次m2pool中nexa的所有机器的实时平均算力3天平均算力
// */
//@Scheduled(cron = "0 0/30 * * * ?")
//public void insertNexaMachineAvgPowerTask(){
// //每半小时更新一次
// List<ProductMachineDto> nexaMinersv2 = leaseNexaMachinePowerMapper.getMachineThreePower(null, "nexa");
//
// if (nexaMinersv2.isEmpty()) {
// return;
// }
// List<LeaseNexaMachineAvgPower> collect = nexaMinersv2.stream().map(productMachineDto -> {
// // 将 LocalDateTime 转换为 Instant
// Instant startInstant = productMachineDto.getStartTime().atZone(ZoneId.systemDefault()).toInstant();
// Instant endInstant = productMachineDto.getEndTime().atZone(ZoneId.systemDefault()).toInstant();
// // 使用 Duration 计算毫秒差
// Duration duration = Duration.between(startInstant, endInstant);
// long millis = duration.toMillis();
// return LeaseNexaMachineAvgPower.builder()
// .user(productMachineDto.getUser())
// .miner(productMachineDto.getMiner())
// .startTime(productMachineDto.getStartTime())
// .endTime(productMachineDto.getEndTime())
// .realAvgPower(productMachineDto.getComputingPower()
// .multiply(BigDecimal.valueOf(Math.pow(2, 32)))
// .divide(BigDecimal.valueOf(millis), 2, RoundingMode.HALF_UP))
// .build();
// }).collect(Collectors.toList());
//
// boolean b = leaseNexaMachineAvgPowerMapper.insertBatchDatas(collect);
//}
}

View File

@@ -2,6 +2,7 @@ package com.m2pool.lease.task;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.m2pool.lease.constant.PowerUnit;
@@ -25,6 +26,8 @@ import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -71,6 +74,8 @@ public class OrderAndPayTask {
@Resource
private LeaseOrderItemService leaseOrderItemService;
/**
* 检查钱包半年内是否有 支付,充值,提现操作
*/
@@ -105,7 +110,7 @@ public class OrderAndPayTask {
long l = System.currentTimeMillis()/1000L;
RabbitmqDeleteWalletMessage build = RabbitmqDeleteWalletMessage.builder()
.msg_type(0)
.queue_id(userWalletDataDto.getQueueId().toString())
.queue_id(userWalletDataDto.getQueueId())
.chain(userWalletDataDto.getFromChain())
.symbol(userWalletDataDto.getFromSymbol())
.address(userWalletDataDto.getFromAddress())
@@ -123,8 +128,8 @@ public class OrderAndPayTask {
* 支付 定时任务
*/
//@Scheduled(cron = "0 5 0 * * ? ")
@Scheduled(cron = "0 0/5 * * * ? ")
@Transactional
@Scheduled(cron = "0 0/1 * * * ? ")
@DSTransactional
public void paymentTask(){
// 获取当天 0 点的 时间
LocalDateTime now = LocalDateTime.now();
@@ -135,14 +140,20 @@ public class OrderAndPayTask {
System.out.println("没有进行中的订单");
return;
}
Map<Long, String> orderNumberMap = needPayOrderList.stream().collect(Collectors.toMap(LeaseOrderInfo::getId, LeaseOrderInfo::getOrderNumber));
//2.根据订单号找到对应的订单详情(不包含租约到期) ,并根据这些订单详情找到每个矿机的信息
List<Long> infoIds = needPayOrderList.stream().map(LeaseOrderInfo::getId).collect(Collectors.toList());
List<Long> infoIds = new ArrayList<>();
Map<Long, LeaseOrderInfo> queueIdMap = new HashMap<>();
for (LeaseOrderInfo leaseOrderInfo : needPayOrderList) {
queueIdMap.put(leaseOrderInfo.getId(), leaseOrderInfo);
infoIds.add(leaseOrderInfo.getId());
}
//2.根据订单号找到对应的订单详情(状态为1 租约生效中) ,并根据这些订单详情找到每个矿机的信息
List<LeaseOrderItem> leaseOrderItems = leaseOrderItemMapper.selectList(new LambdaQueryWrapper<LeaseOrderItem>()
.eq(LeaseOrderItem::getStatus,1)
.in(LeaseOrderItem::getOrderId, infoIds));
//因卖方收款钱包修改后,改变订单收款地址
//订单进行过程中,卖方可能修改收款地址。所以每天支付前,需要修改旧收款地址为新地址
leaseOrderItems = updateOrderItemSellerWalletAddress(leaseOrderItems);
List<Long> machineIdList = leaseOrderItems.stream().map(LeaseOrderItem::getProductMachineId).collect(Collectors.toList());
List<LeaseProductMachine> leaseProductMachines = leaseProductMachineMapper.selectBatchIds(machineIdList);
@@ -161,59 +172,58 @@ public class OrderAndPayTask {
dto -> dto
));
//2.2 订单详情集合 按照 买方地址 + 链名称分组
Map<String, List<LeaseOrderItem>> userMapItem = leaseOrderItems.stream()
.collect(Collectors.groupingBy(
item-> item.getAddress() + "-" + item.getChain()
));
Map<Long, List<LeaseOrderItem>> userMapItem = leaseOrderItems.stream()
.collect(Collectors.groupingBy(LeaseOrderItem::getOrderId));
//.collect(Collectors.groupingBy(
// item-> item.getFromAddress() + "-" + item.getChain()+"-" + item.getSymbol()
//));
//3.筛选出租期到期的商品
List<LeaseOrderItem> expireProductList = new ArrayList<>();
List<RabbitmqPayAutoMessage> rabbitmqPayAutoMessages = new ArrayList<>();
Map<Long,Boolean> orderInfoIdAndIsComplete = new HashMap<>();
userMapItem.forEach((addressAndChain, items) -> {
List<LeaseOrderItem> saleIngList = new ArrayList<>();
// 按照订单分组
userMapItem.forEach((orderId, items) -> {
LeaseOrderItem leaseOrderItem = items.get(0);
List<LeaseOrderItem> expire = new ArrayList<>();
//因为生成订单时会冻结整个订单的金额,所以这里不用再去判断
String queueId = UuidGeneratorUtil.generateUuidWithoutHyphen();
long timestamp = System.currentTimeMillis()/1000;
//因为同一个订单的queueId相同所以这里直接使用订单id
LeaseOrderInfo orderInfo = queueIdMap.get(leaseOrderItem.getOrderId());
String queueId =orderInfo.getOrderNumber();
//买方信息
RabbitmqPayAutoMessage build = RabbitmqPayAutoMessage.builder()
.queue_id(queueId)
.chain(leaseOrderItem.getChain())
.symbol(leaseOrderItem.getSymbol())
.total_amount(BigDecimal.ZERO)
.total_fee(orderInfo.getFee())
.from_address(leaseOrderItem.getFromAddress())
.total_amount(BigDecimal.ZERO)
.timestamp(timestamp)
.sign(HashUtils.sha256(timestamp))
.build();
//封装卖方收款信息
List<RabbitmqPayAutoInfoMessage> sellerPayInfoMessages = new ArrayList<>();
Map<String,RabbitmqPayAutoInfoMessage> sellerPayInfoMessages = new HashMap<>();
//买方收款信息 相同订单最后整合成一个卖方信息
Map<Long, List<LeaseOrderItem>> orderIdMap = items.stream().collect(Collectors.groupingBy(LeaseOrderItem::getOrderId));
orderIdMap.forEach((orderId, orderItemList) -> {
LeaseOrderItem orderInfo = orderItemList.get(0);
Map<String, List<LeaseOrderItem>> orderIdsMap = items.stream().collect(Collectors.groupingBy(LeaseOrderItem::getAddress));
orderIdsMap.forEach((toAddress, orderItemList) -> {
LeaseOrderItem orderItem = orderItemList.get(0);
RabbitmqPayAutoInfoMessage sellInfo = RabbitmqPayAutoInfoMessage.builder()
.to_address(orderInfo.getAddress())
.order_id(orderItem.getOrderId().toString())
.to_address(toAddress)
.amount(BigDecimal.ZERO)
.blockAmount(BigDecimal.ZERO)
.needAmount(BigDecimal.ZERO)
.order_id(orderInfo.getOrderId().toString())
.shopId(orderInfo.getShopId())
.userId(orderInfo.getUserId())
.shopId(orderItem.getShopId())
.userId(orderItem.getUserId())
.build();
for (LeaseOrderItem item : orderItemList) {
orderInfoIdAndIsComplete.putIfAbsent(item.getOrderId(), true);
LocalDateTime expireTime = item.getCreateTime().plusDays(1).toLocalDate().atStartOfDay().plusDays(item.getLeaseTime());
//开发环境
List<LeasePayRecordMessage> list = leasePayRecordMessageService.list(new LambdaQueryWrapper<LeasePayRecordMessage>()
.eq(LeasePayRecordMessage::getOrderId, item.getOrderId()));
LocalDateTime a = item.getCreateTime().plusMinutes(item.getLeaseTime());
// 租期已过
if (startOfDay.isAfter(expireTime) /**开发环境*/|| list.size() == item.getLeaseTime()) {
if (startOfDay.isAfter(expireTime) /**开发环境*/|| now.isAfter(a)) {
item.setStatus(0);
expire.add(item);
}else{
@@ -225,38 +235,42 @@ public class OrderAndPayTask {
sellInfo.setNeedAmount(sellInfo.getNeedAmount().add(item.getPrice()));
sellInfo.setBlockAmount(sellInfo.getBlockAmount().add(item.getPrice()));
if (productMachineDto != null){
//理论算力
BigDecimal theoryPower = machine.getTheoryPower().multiply(PowerUnit.getPower(machine.getUnit()))
.divide(BigDecimal.valueOf(1000 * 1000),2,RoundingMode.HALF_UP);
//实际算力
BigDecimal realPower = productMachineDto.getComputingPower()
.divide(BigDecimal.valueOf(24 * 60 * 60), 2, RoundingMode.HALF_UP);
.divide(BigDecimal.valueOf(24 * 60 * 60), 6, RoundingMode.HALF_UP);
//设置实际支付金额
BigDecimal divide = theoryPower.subtract(realPower).divide(theoryPower, 10, RoundingMode.HALF_UP);
//设置实际需要发送消息去支付的各订单金额和总金额
if (divide.compareTo(BigDecimal.valueOf(0.05)) > 0){
sellInfo.setAmount(sellInfo.getAmount().add(item.getPrice().multiply(BigDecimal.ONE.subtract(divide))));
build.setTotal_amount(build.getTotal_amount().add(item.getPrice().multiply(BigDecimal.ONE.subtract(divide))));
BigDecimal add = item.getPrice().multiply(BigDecimal.ONE.subtract(divide));
item.setSettlePayRealAmount(add);
sellInfo.setAmount(sellInfo.getAmount().add(add));
build.setTotal_amount(build.getTotal_amount().add(add));
}else{
build.setTotal_amount(build.getTotal_amount().add(item.getPrice()));
sellInfo.setAmount(sellInfo.getAmount().add(item.getPrice()));
BigDecimal add = item.getPrice();
item.setSettlePayRealAmount(add);
build.setTotal_amount(build.getTotal_amount().add(add));
sellInfo.setAmount(sellInfo.getAmount().add(add));
}
}
item.setAlreadyPayAmount(item.getAlreadyPayAmount().add(item.getPrice()));
saleIngList.add(item);
}
}
sellerPayInfoMessages.add(sellInfo);
sellerPayInfoMessages.put(sellInfo.getTo_address(), sellInfo);
});
build.setTransactions(sellerPayInfoMessages);
//if 开发环境
if (build.getTotal_amount().compareTo(BigDecimal.ZERO) > 0){
rabbitmqPayAutoMessages.add(build);
}
expireProductList.addAll(expire);
});
//4.租约到期相关信息修改
if (!expireProductList.isEmpty()){
List<Long> itemIds = new ArrayList<>();
@@ -284,30 +298,36 @@ public class OrderAndPayTask {
});
leaseProductService.updateBatchById(leaseProducts);
//4.5 找到详情表所有状态为0 租约已过期 并且订单info表订单状态为7 进行中的订单 并改为状态8 订单已完成
//4.5 找到详情表所有状态为0 租约已过期 并且订单info表订单状态为7 进行中的订单 并改为状态8 订单已完成 并且发送支付消息
List<Long> orderIds = orderInfoIdAndIsComplete.entrySet().stream()
.filter(entry -> Boolean.TRUE.equals(entry.getValue()))
.map(Map.Entry::getKey)
.collect(Collectors.toList());
if(!orderIds.isEmpty()){
leaseOrderInfoMapper.update(LeaseOrderInfo.builder().status(8).build(),
new LambdaQueryWrapper<LeaseOrderInfo>().in(LeaseOrderInfo::getId, orderIds));
//订单状态改为已完成
leaseOrderInfoMapper.update(LeaseOrderInfo.builder().status(8).build(), new LambdaQueryWrapper<LeaseOrderInfo>().in(LeaseOrderInfo::getId, orderIds));
// TODO 发送支付消息
sendMessageToMq(orderIds);
}
}
//5.根据这些订单发送今天的支付消息到mq
//5.正在售出中矿机已支付金额
leaseOrderItemService.updateBatchById(saleIngList);
//6.根据这些订单发送今天的支付消息到mq
if (!rabbitmqPayAutoMessages.isEmpty()){
List<LeasePayRecordMessage> collect = new ArrayList<>();
for (RabbitmqPayAutoMessage rabbitmqPayAutoMessage : rabbitmqPayAutoMessages) {
List<LeasePayRecordMessage> list = new ArrayList<>();
for (RabbitmqPayAutoInfoMessage transaction : rabbitmqPayAutoMessage.getTransactions()) {
for (RabbitmqPayAutoInfoMessage transaction : rabbitmqPayAutoMessage.getTransactions().values()) {
list.add(LeasePayRecordMessage.builder()
.orderId(transaction.getOrder_id())
.orderNumber(rabbitmqPayAutoMessage.getQueue_id())
.queueId(rabbitmqPayAutoMessage.getQueue_id())
.fromAddress(rabbitmqPayAutoMessage.getFrom_address())
.orderId(transaction.getOrder_id())
.orderNumber(orderNumberMap.get(Long.parseLong(transaction.getOrder_id())))
.toAddress(transaction.getTo_address())
.amount(transaction.getNeedAmount())
.realAmount(transaction.getAmount())
.needAmount(transaction.getAmount())
.fromChain(rabbitmqPayAutoMessage.getChain())
.fromSymbol(rabbitmqPayAutoMessage.getSymbol())
@@ -318,16 +338,18 @@ public class OrderAndPayTask {
.toSymbol(rabbitmqPayAutoMessage.getSymbol())
.build());
}
try{
rabbitTemplate.convertAndSend(PAY_AUTO_QUEUE, rabbitmqPayAutoMessage);
System.out.println("支付消息发送成功:"+rabbitmqPayAutoMessage);
}catch (Exception e){
//一般出现在rabbitmq服务出现故障时出现状态改为三状态为三后续消息重试
list = list.stream().peek(item->item.setStatus(3)).collect(Collectors.toList());
System.out.println("消息发送失败:"+e.getMessage());
}finally {
collect.addAll(list);
}
//TODO 订单金额
//try{
// rabbitTemplate.convertAndSend(PAY_AUTO_QUEUE, rabbitmqPayAutoMessage);
// System.out.println("支付消息发送成功:"+rabbitmqPayAutoMessage);
//}catch (Exception e){
// //一般出现在rabbitmq服务出现故障时出现状态改为三状态为三后续消息重试
// list = list.stream().peek(item->item.setStatus(3)).collect(Collectors.toList());
// System.out.println("消息发送失败:"+e.getMessage());
//}finally {
//
//}
}
leasePayRecordMessageService.saveBatch(collect);
}
@@ -368,11 +390,61 @@ public class OrderAndPayTask {
}
/**
* 订单完成后---发送支付消息到mq
* @param orderIds
*/
public void sendMessageToMq(List<Long> orderIds){
List<LeasePayRecordMessage> leasePayRecordMessages = leasePayRecordMessageMapper.selectList(new LambdaQueryWrapper<LeasePayRecordMessage>()
.in(LeasePayRecordMessage::getOrderId, orderIds));
Map<String, Map<String, List<LeasePayRecordMessage>>> collect = leasePayRecordMessages.stream()
.collect(Collectors.groupingBy(LeasePayRecordMessage::getOrderId, Collectors.groupingBy(LeasePayRecordMessage::getToAddress)));
//遍历按订单id分组后的map
collect.forEach((orderId, payRecordMessagesMap) -> {
long timestamp = System.currentTimeMillis()/1000;
List<LeasePayRecordMessage> orDefault = payRecordMessagesMap.getOrDefault(payRecordMessagesMap.keySet().iterator().next(), new ArrayList<>());
LeasePayRecordMessage initForm = orDefault.get(0);
RabbitmqPayAutoMessage build = RabbitmqPayAutoMessage.builder()
.queue_id(initForm.getQueueId())
.from_address(initForm.getFromAddress())
.chain(initForm.getFromChain())
.symbol(initForm.getFromSymbol())
.total_amount(BigDecimal.ZERO)
.timestamp(timestamp)
.sign(HashUtils.sha256(timestamp))
.build();
Map<String, RabbitmqPayAutoInfoMessage> transactions = new HashMap<>();
//遍历按toAddress 分组后的map
payRecordMessagesMap.forEach((toAddress,payRecordMessageList) -> {
LeasePayRecordMessage init = payRecordMessageList.get(0);
RabbitmqPayAutoInfoMessage sellInfo = RabbitmqPayAutoInfoMessage.builder()
.to_address(init.getToAddress())
.amount(BigDecimal.ZERO)
.blockAmount(BigDecimal.ZERO)
.needAmount(BigDecimal.ZERO)
.shopId(init.getShopId())
.userId(init.getUserId())
.build();
for (LeasePayRecordMessage leasePayRecordMessage : payRecordMessageList) {
sellInfo.setAmount(sellInfo.getAmount().add(leasePayRecordMessage.getRealAmount()));
sellInfo.setBlockAmount(sellInfo.getBlockAmount().add(leasePayRecordMessage.getBlockAmount()));
sellInfo.setNeedAmount(sellInfo.getNeedAmount().add(leasePayRecordMessage.getNeedAmount()));
}
build.setTotal_amount(build.getTotal_amount().add(sellInfo.getAmount()));
transactions.put(toAddress,sellInfo);
});
build.setTransactions(transactions);
rabbitTemplate.convertAndSend(PAY_AUTO_QUEUE, build);
});
}
/**
* 一些校验失败的支付消息需要重新发送
*/
@Scheduled(cron = "0 0/5 * * * ? ")
@Scheduled(cron = "0 0 0/1 * * ? ")
@Transactional
public void checkPushFailPayMessage(){
//查找出状态为三 消息发送失败的订单 再次发送支付消息。直到成功为止
@@ -393,16 +465,16 @@ public class OrderAndPayTask {
.sign(HashUtils.sha256(l))
.timestamp(l)
.build();
List<RabbitmqPayAutoInfoMessage> transactions = itemList.stream()
Map<String, RabbitmqPayAutoInfoMessage> payMap = itemList.stream()
.map(orderInfo -> RabbitmqPayAutoInfoMessage.builder()
.order_id(orderInfo.getOrderId())
.to_address(orderInfo.getToAddress())
.amount(orderInfo.getAmount())
.blockAmount(orderInfo.getBlockAmount())
.shopId(orderInfo.getShopId())
.userId(orderInfo.getUserId())
.build())
.collect(Collectors.toList());
build.setTransactions(transactions);
.collect(Collectors.toMap(RabbitmqPayAutoInfoMessage::getTo_address, Function.identity()));
build.setTransactions(payMap);
try {
rabbitTemplate.convertAndSend(PAY_AUTO_QUEUE, build);
List<LeasePayRecordMessage> updates = itemList.stream().peek(record -> record.setStatus(2)).collect(Collectors.toList());

View File

@@ -28,6 +28,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.m2pool.lease.constant.RabbitmqConstant.POOL_PROXY_QUEUE_NAME;
@@ -138,7 +139,7 @@ public class OwnProductTask {
//@Scheduled(cron = "0 35 0/1 * * ? ")
@Scheduled(cron = "0 0/5 * * * ? ")
@Scheduled(cron = "30 0/5 * * * ? ")
@DSTransactional
public void updateNexaIncomeTask(){
List<LeaseUserOwnedProduct> updateList = computeIncome("nexa");
@@ -148,7 +149,7 @@ public class OwnProductTask {
}
//@Scheduled(cron = "10 35 0/1 * * ? ")
@Scheduled(cron = "0 0/5 * * * ? ")
@Scheduled(cron = "30 0/5 * * * ? ")
@DSTransactional
public void updateGrsIncomeTask(){
List<LeaseUserOwnedProduct> updateList = computeIncome("grs");
@@ -157,7 +158,7 @@ public class OwnProductTask {
}
//@Scheduled(cron = "20 35 0/1 * * ? ")
@Scheduled(cron = "0 0/5 * * * ? ")
@Scheduled(cron = "30 0/5 * * * ? ")
@DSTransactional
public void updateRxdIncomeTask(){
List<LeaseUserOwnedProduct> updateList = computeIncome("rxd");
@@ -166,7 +167,7 @@ public class OwnProductTask {
}
//@Scheduled(cron = "30 35 0/1 * * ? ")
@Scheduled(cron = "0 0/5 * * * ? ")
@Scheduled(cron = "30 0/5 * * * ? ")
@DSTransactional
public void updateMonaIncomeTask(){
List<LeaseUserOwnedProduct> updateList = computeIncome("mona");
@@ -189,30 +190,32 @@ public class OwnProductTask {
//1. 查询在有效期内的已购机器
LambdaQueryWrapper<LeaseUserOwnedProduct> wrapper = new LambdaQueryWrapper<LeaseUserOwnedProduct>()
.eq(LeaseUserOwnedProduct::getCoin, coin)
.le(LeaseUserOwnedProduct::getStartTime, startOfDay)
.gt(LeaseUserOwnedProduct::getEndTime, startOfDay);
.eq(LeaseUserOwnedProduct::getStatus, 0);
List<LeaseUserOwnedProduct> leaseUserOwnedProducts = leaseUserOwnedProductMapper.selectList(wrapper);
System.out.println("个人收益--矿机: " + JSONUtil.toJsonPrettyStr(leaseUserOwnedProducts));
//2.获取近一个小时矿机的收益 + 并计算实时收益
List<LeaseUserOwnedProduct> updateList = new ArrayList<>();
if (!leaseUserOwnedProducts.isEmpty()){
Map<String, LeaseUserOwnedProduct> collect = new HashMap<>();
Set<Long> orderInfoIds = new HashSet<>();
for (LeaseUserOwnedProduct item : leaseUserOwnedProducts) {
collect.put(item.getUser() + "_" + item.getMiner() + "-" + item.getCoin(), item);
collect.put(item.getUser() + "-" + item.getMiner() + "-" + item.getCoin(), item);
orderInfoIds.add(item.getOrderId());
}
//2.1 查询当天已支付订单
Map<Long, LeasePayRecordMessage> recordStatus = leasePayRecordMessageMapper.selectOrderInfoMap(orderInfoIds);
//查询订单详情对应的信息formAddress + fromChain + fromSymbol + toAddress + toChain + toSymbol
List<LeaseOrderItem> leaseOrderItems = leaseOrderItemMapper.getOrderItemByOrderIds(orderInfoIds);
Map<String, LeaseOrderItem> collect1 = leaseOrderItems.stream().collect(Collectors.toMap(item -> item.getUser() + "-" + item.getMiner() + "-" + item.getCoin(), Function.identity()));
List<HourIncomeDto> incomeDtos = leaseUserOwnedProductMapper.getHourIncomeList(leaseUserOwnedProducts,coin, start, end);
for (HourIncomeDto hourIncomeDto : incomeDtos) {
LeaseUserOwnedProduct leaseUserOwnedProduct = collect.get(hourIncomeDto.getUser() + "_" + hourIncomeDto.getMiner()+ "-" + coin) ;
LeasePayRecordMessage leasePayRecordMessage = recordStatus.get(leaseUserOwnedProduct.getOrderId());
if (leasePayRecordMessage != null && leasePayRecordMessage.getStatus() == 1){
String key = hourIncomeDto.getUser() + "-" + hourIncomeDto.getMiner()+ "-" + coin;
System.out.println("个人收益--矿机详情: " + key);
LeaseUserOwnedProduct leaseUserOwnedProduct = collect.get(key) ;
LeaseOrderItem leaseOrderItem = collect1.get(key);
System.out.println("个人收益--订单详情: " + JSONUtil.toJsonPrettyStr(leaseOrderItem));
if (leaseOrderItem != null && leaseOrderItem.getStatus() == 1){
BigDecimal coinIncome = hourIncomeDto.getIncome().add(leaseUserOwnedProduct.getCurrentIncome());
BigDecimal usdtIncome = hourIncomeDto.getUsdtIncome().add(leaseUserOwnedProduct.getCurrentUsdtIncome());
//当日待结算收益不为0把待结算收益加到当前收益中
@@ -229,6 +232,11 @@ public class OwnProductTask {
leaseUserOwnedProduct.setSettleIncome(hourIncomeDto.getIncome().add(leaseUserOwnedProduct.getSettleIncome()));
leaseUserOwnedProduct.setSettleUsdtIncome(hourIncomeDto.getUsdtIncome().add(leaseUserOwnedProduct.getSettleUsdtIncome()));
}
if (now.equals(startOfDay)){
leaseUserOwnedProduct.setSettleIncome(BigDecimal.ZERO);
leaseUserOwnedProduct.setSettleUsdtIncome(BigDecimal.ZERO) ;
}
updateList.add(leaseUserOwnedProduct);
}
}

View File

@@ -0,0 +1,109 @@
package com.m2pool.lease.task;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.m2pool.lease.dto.ProductMachineDto;
import com.m2pool.lease.entity.LeaseProductMachine;
import com.m2pool.lease.mapper.LeaseProductMachineMapper;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;
/**
* @Description TODO
* @Date 2025/11/7 14:16
* @Author yyb
*/
@Configuration
@EnableScheduling
public class RealPowerInsetTask {
@Resource
private LeaseProductMachineMapper leaseProductMachineMapper;
private static final int BATCH_SIZE = 1000;
private static final int THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors();
private final ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
public void batchInsert(String coin,List<ProductMachineDto> recentlyFiveMinutesData) {
// 用于记录执行过程中的异常
AtomicReference<Exception> exceptionRef = new AtomicReference<>();
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (int i = 0; i < recentlyFiveMinutesData.size(); i += BATCH_SIZE) {
int toIndex = Math.min(i + BATCH_SIZE, recentlyFiveMinutesData.size());
List<ProductMachineDto> subList = recentlyFiveMinutesData.subList(i, toIndex);
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
leaseProductMachineMapper.batchInsertPowers(coin, subList);
} catch (Exception e) {
exceptionRef.set(e);
throw new RuntimeException(e);
}
}, executorService);
futures.add(future);
}
// 等待所有任务完成
CompletableFuture<Void> allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
try {
allFutures.get();
} catch (InterruptedException | ExecutionException e) {
// 如果有异常,将异常信息设置到 exceptionRef 中
exceptionRef.set(e);
}
// 如果有异常,抛出异常触发事务回滚
if (exceptionRef.get() != null) {
System.out.println("批量插入数据实时算力数据出错"+exceptionRef.get());
throw new RuntimeException("批量插入数据实时算力数据出错", exceptionRef.get());
}
}
public List<ProductMachineDto> getRealPower(String coin){
List<LeaseProductMachine> leaseProductMachines = leaseProductMachineMapper.selectList(new LambdaQueryWrapper<LeaseProductMachine>()
.eq(LeaseProductMachine::getDel, false));
return leaseProductMachineMapper.getRecentlyFiveMinutesData(leaseProductMachines, coin);
}
@Scheduled(cron = "0 0/5 * * * ? ")
@DSTransactional
public void nexaRealPowerInset(){
List<ProductMachineDto> nexaPower = getRealPower("nexa");
batchInsert("nexa",nexaPower);
}
@Scheduled(cron = "0 0/5 * * * ? ")
@DSTransactional
public void monaRealPowerInset(){
List<ProductMachineDto> monaPower = getRealPower("mona");
batchInsert("mona",monaPower);
}
@Scheduled(cron = "0 0/5 * * * ? ")
@DSTransactional
public void rxdRealPowerInset(){
List<ProductMachineDto> rxdPower = getRealPower("mona");
batchInsert("rxd",rxdPower);
}
@Scheduled(cron = "0 0/5 * * * ? ")
@DSTransactional
public void grsRealPowerInset(){
List<ProductMachineDto> rxdPower = getRealPower("grs");
batchInsert("grs",rxdPower);
}
}

View File

@@ -13,6 +13,8 @@ import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Hashtable;
/**
@@ -89,7 +91,7 @@ public class QrCodeUtils {
}
public static void main(String[] args) {
System.out.println(creatRrCode("0x1c3d5d2a0eeb78476bcefadb44fbf24d29eeb964", 200,200));
//System.out.println(creatRrCode("0x1c3d5d2a0eeb78476bcefadb44fbf24d29eeb964", 200,200));
}

View File

@@ -20,14 +20,6 @@ import java.util.List;
@ApiModel(description = "订单结算及谷歌验证码请求对象",value = "OrderAndCodeVo" )
public class OrderAndCodeVo {
@ApiModelProperty(value = "支付币种",required = true)
private String coin;
@ApiModelProperty(value = "链名称",required = true)
private String chain;
@ApiModelProperty(value = "币价",required = true)
private BigDecimal price;
@ApiModelProperty(value = "谷歌验证码",required = true)
private Long code;

View File

@@ -37,4 +37,13 @@ public class OrderInfoVo extends BaseVo{
@ApiModelProperty(value = "租赁时长",example = "1")
private Integer leaseTime;
@ApiModelProperty(value = "支付币种",required = true)
private String coin;
@ApiModelProperty(value = "链名称",required = true)
private String chain;
//@ApiModelProperty(value = "币价",required = true)
//private BigDecimal price;
}

View File

@@ -43,11 +43,6 @@ public class ProductMachineParamsVo{
@ApiModelProperty(value = "机器成本价格单位$ [ 功耗 * 电费 * 24 * (1 + 收益率) ]",example = "0.01")
private BigDecimal cost;
//@ApiModelProperty(value = "电费",example = "0.01")
//private BigDecimal electricityBill;
//@ApiModelProperty(value = "收益率",example = "0.01")
//private BigDecimal incomeRate;
@ApiModelProperty(value = "最大可租借天数(默认七天)",example = "7")
private Integer maxLeaseDays;

View File

@@ -1,5 +1,6 @@
package com.m2pool.lease.vo;
import com.m2pool.lease.dto.MachinePayTypeDto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
@@ -8,6 +9,7 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.util.List;
/**
* <p>
@@ -63,4 +65,6 @@ public class ProductMachineURDVo extends BaseVo{
@ApiModelProperty(value = "功耗",example = "0.01")
private BigDecimal powerDissipation;
@ApiModelProperty(value = "币种价格配置")
private List<MachinePayTypeDto> priceList;
}

View File

@@ -0,0 +1,67 @@
package com.m2pool.lease.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* <p>
* 首页商品详情页矿机列表请求对象
* </p>
*
* @author yyb
* @since 2025-07-23
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "首页商品详情页矿机列表请求对象",value = "ProductMachineVo" )
public class ProductMachineVo extends PageVo{
@ApiModelProperty(value = "商品 ID")
private Long id;
@ApiModelProperty(value = "最大实际算力")
private BigDecimal maxPower;
@ApiModelProperty(value = "最小实际算力")
private BigDecimal minPower;
@ApiModelProperty(value = "最大功耗 单位kw/h",example = "10")
private BigDecimal maxPowerDissipation;
@ApiModelProperty(value = "最小功耗 单位kw/h",example = "10")
private BigDecimal minPowerDissipation;
@ApiModelProperty(value = "最大单价")
private BigDecimal maxPrice;
@ApiModelProperty(value = "最小单价")
private BigDecimal minPrice;
@ApiModelProperty(value = "币种")
private String coin;
@ApiModelProperty(value = "")
private String chain;
@ApiModelProperty(value = "价格排序方式 true:降序 false:升序")
private Boolean priceSort;
@ApiModelProperty(value = "实际算力排序方式 true:降序 false:升序")
private Boolean powerSort;
@ApiModelProperty(value = "功耗排序方式 true:降序 false:升序")
private Boolean powerDissipationSort;
}

View File

@@ -1,5 +1,6 @@
package com.m2pool.lease.vo;
import com.m2pool.lease.dto.MachinePayTypeDto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
@@ -64,6 +65,10 @@ public class ProductUpdateMachineVo {
@ApiModelProperty(value = "实际价格(同一个商品下的矿机单价默认为商品表的cost字段值= 功耗 * 电费 $/度 * 24h * (1+收益率) 用户可以自定义该价格)",example = "2760.00")
private BigDecimal price;
@ApiModelProperty(value = "币种价格配置")
private List<MachinePayTypeDto> priceList;
/**
* 上下架状态0 上架1 下架
*/

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.m2pool.lease.mapper.LeaseOrderFeeMapper">
</mapper>

View File

@@ -67,6 +67,40 @@
GROUP BY
order_id;
</select>
<select id="getNeedUpdateOrderItem" resultType="com.m2pool.lease.entity.LeaseOrderItem">
SELECT
id,
already_pay_real_amount AS alreadyPayRealAmount,
settle_pay_real_amount AS settlePayRealAmount,
del
FROM
`lease_order_item`
WHERE
order_id = #{orderId}
</select>
<select id="getOrderItemByOrderIds" resultType="com.m2pool.lease.entity.LeaseOrderItem">
SELECT
oi.user,
oi.miner,
oi.coin,
oi.from_address AS fromAddress,
oi.from_chain AS fromChain,
oi.from_symbol AS fromSymbol,
oi.address AS address,
oi.chain AS chain,
oi.symbol AS symbol,
COALESCE(prm.status,0) AS status
FROM
`lease_order_item` oi
LEFT JOIN lease_pay_record_message prm ON
oi.from_address = prm.from_address AND oi.from_chain = prm.from_chain AND oi.from_symbol = prm.from_symbol
AND oi.address = prm.to_address AND oi.chain = prm.to_chain AND oi.symbol = prm.to_symbol AND DATE(prm.create_time) = CURRENT_DATE
WHERE
oi.order_id IN
<foreach item="id" collection="orderIds" open="(" separator="," close=")">
#{id}
</foreach>
</select>
</mapper>

View File

@@ -39,7 +39,7 @@ from lease_pay_recharge_message
FROM lease_pay_recharge_message
WHERE address = #{fromAddress} AND create_time >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 6 MONTH) AND del = 0;
</select>
<select id="checkRechargeOperatorBatch" resultType="java.util.Map">
<select id="checkRechargeOperatorBatch" resultType="com.m2pool.lease.dto.CheckAddressDto">
SELECT DISTINCT address as fromAddress,chain as fromChain,symbol as fromSymbol, true AS hasOperator
FROM lease_pay_recharge_message
WHERE

View File

@@ -30,7 +30,7 @@
FROM lease_pay_record_message
WHERE from_address = #{fromAddress} AND create_time >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 6 MONTH) AND del = 0;
</select>
<select id="checkPayOperatorBatch" resultType="java.util.Map">
<select id="checkPayOperatorBatch" resultType="com.m2pool.lease.dto.CheckAddressDto">
SELECT DISTINCT from_address as fromAddress,from_chain as fromChain,from_symbol as fromSymbol, true AS hasOperator
FROM lease_pay_record_message
WHERE
@@ -110,15 +110,13 @@
</where>
order by update_time desc limit 5
</select>
<select id="selectOrderInfoMap" resultType="java.util.Map">
<select id="getQueueIdByInfoIds" resultType="java.util.Map">
select
order_id as orderId,
status
from
lease_pay_record_message
where
DATE(create_time) = DATE(NOW()) AND order_id in
<foreach item="item" index="index" collection="orderInfoIds" open="(" separator="," close=")">
DISTINCT order_id as orderId,
queue_id as queueId
from lease_pay_record_message
where order_id in
<foreach item="item" index="index" collection="infoIds" open="(" close=")" separator=",">
#{item}
</foreach>
</select>

View File

@@ -55,7 +55,7 @@ FROM lease_pay_withdraw_message
FROM lease_pay_withdraw_message
WHERE from_address = #{fromAddress} AND create_time >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 6 MONTH) AND del = 0;
</select>
<select id="checkWithdrawOperatorBatch" resultType="java.util.Map">
<select id="checkWithdrawOperatorBatch" resultType="com.m2pool.lease.dto.CheckAddressDto">
SELECT DISTINCT from_address as fromAddress,from_chain as fromChain,from_symbol as fromSymbol, true AS hasOperator
FROM lease_pay_withdraw_message
WHERE

View File

@@ -85,9 +85,7 @@
SELECT
`user`,
miner,
SUM(mhs * 30 * 60) as computingPower,
MAX(`date`) as endTime,
MIN(`date`) as startTime
SUM(mhs * 30 * 60) as computingPower
FROM
${coin}_mhs30m
WHERE
@@ -106,7 +104,7 @@
</select>
<insert id="saveOrUpdateBatchs">
<insert id="saveOrUpdateBatchs" useGeneratedKeys="true" keyProperty="id">
INSERT INTO lease_product_machine (
shop_id, product_id, user, type, coin, miner, theory_power,
computing_power, theory_income, unit,
@@ -138,6 +136,21 @@
del = VALUES(del),
max_lease_days = VALUES(max_lease_days)
</insert>
<insert id="batchInsertPowers">
INSERT INTO ${coin}_real_power (user,miner,power,`date`)
VALUES
<foreach item="item" index="index" collection="list" separator=",">
(
#{item.user},
#{item.miner},
#{item.computingPower},
now()
)
</foreach>
ON DUPLICATE KEY UPDATE
power = VALUES(power),
`date` = VALUES(`date`)
</insert>
<select id="checkHasSaleMachineByShopId" resultType="java.lang.Integer">
@@ -160,4 +173,131 @@
and `sale_state` = 1
and `del` = 0
</select>
<select id="getPriceList" resultType="com.m2pool.lease.dto.MachinePayTypeDto">
SELECT
id as payTypeId, product_machine_id as productMachineId, price, coin,chain
FROM
lease_product_machine_price
WHERE
product_machine_id IN
<foreach item="id" collection="list" open="(" separator="," close=")">
#{id}
</foreach>
</select>
<select id="getProductListForShopWalletConfig" resultType="com.m2pool.lease.dto.ProductMachineForWalletConfigDto">
SELECT
lpm.id as productMachineId,
lpm.product_id as productId,
lpm.`user`,
lpm.type,
lpm.miner,
lpm.unit,
lpm.state,
lpm.coin,
lpm.sale_state as saleState,
lpm.theory_power as theoryPower,
lpm.theory_income as theoryIncome,
lpm.power_dissipation as powerDissipation
FROM
lease_product_machine lpm
WHERE
del = false AND lpm.shop_id = #{shopId}
</select>
<select id="getIdsForProductId" resultType="java.lang.Long">
SELECT
id
FROM
lease_product_machine
WHERE
product_id = #{productId}
and `del` = 0
</select>
<select id="getMachinesByPriceAndPowerAndDissipation" resultType="com.m2pool.lease.dto.ProductMachineDto">
SELECT
pm.id,
pm.shop_id as shopId,
pm.product_id as productId,
pm.`user`,
pm.type,
pm.miner,
pm.theory_power as theoryPower,
pm.theory_income as theoryIncome,
pm.unit,
pm.power_dissipation as powerDissipation,
pm.income_rate as incomeRate,
pm.cost,
pm.sale_state as saleState,
pm.state,
pm.del,
pm.max_lease_days as maxLeaseDays,
COALESCE(pmp.price,0) as price,
pm.coin,
pmp.coin as payCoin,
COALESCE(rp.power,0) as computingPower
FROM
lease_product_machine pm
LEFT JOIN lease_product_machine_price pmp
ON pm.id = pmp.product_machine_id AND pmp.coin = #{productMachineVo.coin} AND pmp.chain = #{productMachineVo.chain}
LEFT JOIN ${coin}_real_power rp
ON pm.user = rp.user AND rp.miner = pm.miner
WHERE
pm.del = false AND pm.`state` = 0 AND pm.product_id = #{productMachineVo.id}
<!-- 实际算力范围筛选 -->
<if test="productMachineVo.minPower != null">
AND rp.power >= #{productMachineVo.minPower}
</if>
<if test="productMachineVo.maxPower != null">
AND rp.power <![CDATA[<=]]> #{productMachineVo.maxPower}
</if>
<!-- 功耗范围筛选 -->
<if test="productMachineVo.minPowerDissipation != null">
AND power_dissipation >= #{productMachineVo.minPowerDissipation}
</if>
<if test="productMachineVo.maxPowerDissipation != null">
AND power_dissipation <![CDATA[<=]]> #{productMachineVo.maxPowerDissipation}
</if>
<!-- 单价范围筛选 -->
<if test="productMachineVo.minPrice != null">
AND pmp.price >= #{productMachineVo.minPrice}
</if>
<if test="productMachineVo.maxPrice != null">
AND pmp.price <![CDATA[<=]]> #{productMachineVo.maxPrice}
</if>
<!-- <if test="productMachineVo.priceSort != null">-->
<!-- ORDER BY-->
<!-- <choose>-->
<!-- &lt;!&ndash; 价格排序 &ndash;&gt;-->
<!-- <when test="productMachineVo.priceSort">-->
<!-- pmp.price ASC-->
<!-- </when>-->
<!-- <otherwise>-->
<!-- pmp.price DESC-->
<!-- </otherwise>-->
<!-- </choose>-->
<!-- </if>-->
<!-- <if test="productMachineVo.powerSort != null">-->
<!-- ORDER BY-->
<!-- <choose>-->
<!-- &lt;!&ndash; 实际算力排序 &ndash;&gt;-->
<!-- <when test="productMachineVo.powerSort">-->
<!-- rp.power ASC-->
<!-- </when>-->
<!-- <otherwise>-->
<!-- rp.power DESC-->
<!-- </otherwise>-->
<!-- </choose>-->
<!-- </if>-->
<!-- <if test="productMachineVo.powerDissipationSort != null">-->
<!-- ORDER BY-->
<!-- <choose>-->
<!-- &lt;!&ndash; 功耗排序 &ndash;&gt;-->
<!-- <when test="productMachineVo.powerDissipationSort">-->
<!-- power_dissipation ASC-->
<!-- </when>-->
<!-- <otherwise>-->
<!-- power_dissipation DESC-->
<!-- </otherwise>-->
<!-- </choose>-->
<!-- </if>-->
</select>
</mapper>

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.m2pool.lease.mapper.LeaseProductMachinePriceMapper">
<select id="getOrderTotalPriceGroupByChainAndCoin"
resultType="com.m2pool.lease.entity.LeaseProductMachinePrice">
select
product_machine_id as productMachineId,
price as price
from lease_product_machine_price
where
<foreach collection="list" item="item" separator="OR">
(`product_machine_id` = #{item.machineId} AND coin = #{item.coin} AND chain = #{item.chain})
</foreach>
</select>
<select id="getMachinePriceByMachineIds" resultType="com.m2pool.lease.dto.MachinePayTypeDto">
select
product_machine_id as productMachineId,
price as price,
coin as coin,
chain as chain
from lease_product_machine_price
where
<foreach collection="list" item="item" separator="OR">
(`product_machine_id` = #{item})
</foreach>
</select>
<select id="getPriceByOrderItems" resultType="java.util.Map">
select
product_machine_id as productMachineId,
price as price
from lease_product_machine_price
where
<foreach collection="list" item="item" separator="OR">
(`product_machine_id` = #{item.productMachineId} AND coin = #{item.symbol} AND chain = #{item.chain})
</foreach>
</select>
</mapper>

View File

@@ -74,37 +74,68 @@
</choose>
</where>
</select>
<select id="getProductListForShopAndUserCenter" resultType="com.m2pool.lease.entity.LeaseProduct">
SELECT *
FROM lease_product
WHERE del = false
<select id="getProductListForShopAndUserCenter" resultType="com.m2pool.lease.dto.ProductDto">
SELECT
lp.id,
lp.shop_id AS shopId,
lp.name,
lp.image,
lp.type,
lp.state,
lp.description,
lp.algorithm,
lp.shop_id AS shopId,
lp.coin_full_name AS coinFullName,
lp.coin,
lp.sale_number AS saleNumber,
lp.total_machine_number AS totalMachineNumber,
ls.name AS shopName
FROM lease_product lp RIGHT JOIN lease_shop ls ON lp.shop_id = ls.id and ls.state = 1
WHERE lp.del = false
<choose>
<when test="shopId != 0">
AND shop_id = #{shopId}
AND lp.shop_id = #{shopId}
</when>
<otherwise>
AND state = 0 AND total_machine_number != 0
AND lp.state = 0 AND lp.total_machine_number != 0
</otherwise>
</choose>
<choose>
<when test="coin != null and coin != ''">
AND (
(
coin LIKE CONCAT('%', #{coin}, '%')
OR coin_full_name LIKE CONCAT('%', #{coin}, '%')
lp.coin LIKE CONCAT('%', #{coin}, '%')
OR lp.coin_full_name LIKE CONCAT('%', #{coin}, '%')
)
<if test="algorithm != null and algorithm != ''">
AND algorithm LIKE CONCAT('%', #{algorithm}, '%')
AND lp.algorithm LIKE CONCAT('%', #{algorithm}, '%')
</if>
)
</when>
<otherwise>
<if test="algorithm != null and algorithm != ''">
AND algorithm LIKE CONCAT('%', #{algorithm}, '%')
AND lp.algorithm LIKE CONCAT('%', #{algorithm}, '%')
</if>
</otherwise>
</choose>
order by sale_number desc,create_time desc
order by lp.sale_number desc,lp.create_time desc
</select>
<select id="getSupportPayType" resultType="com.m2pool.lease.dto.PayTypeDto">
select pay_coin as coin,chain from lease_shop_config where shop_id = 3 and del = 0;
</select>
<select id="getProductListForShopWalletConfig" resultType="com.m2pool.lease.dto.ProductForWalletConfigDto">
SELECT
id as productId,
name,
image,
state,
description,
algorithm,
coin,
total_machine_number AS totalMachineNumber
FROM
lease_product
WHERE del = false and shop_id = #{shopId}
</select>
</mapper>

View File

@@ -52,6 +52,14 @@
</foreach>
)
</select>
<select id="getPayType" resultType="com.m2pool.lease.dto.PayTypeDto">
select chain,pay_coin as coin,pay_coin_image as image,shop_id as shopId
from lease_shop_config
where del = false AND shop_id IN
<foreach item="item" collection="list" separator="," open="(" close=")">
#{item}
</foreach>
</select>
</mapper>

View File

@@ -20,8 +20,7 @@
</sql>
<select id="getPayAddressAndPayCoin" resultType="com.m2pool.lease.entity.LeaseShopConfig">
SELECT
shop_id as shopId,
product_id as productId,
`shop_id` as shopId,
`pay_address` as payAddress,
`pay_coin` as payCoin,
`qrcode`,
@@ -29,10 +28,9 @@
FROM
lease_shop_config
WHERE
pay_coin = #{coin} AND chain = #{chain} and del = 0
AND `shop_id` IN
<foreach collection="shopIds" item="shopId" open="(" separator="," close=")">
#{shopId}
del = false AND
<foreach collection="chainAndCoinSet" item="item" separator="OR">
(pay_coin = #{item.coin} AND chain = #{item.chain} AND shop_id = #{item.shopId})
</foreach>
</select>
<select id="getShopWalletInfo" resultType="com.m2pool.lease.dto.PayConfigDto">
@@ -60,5 +58,31 @@
</foreach>
and del = 0
</select>
<select id="getShopIdsByProductIds" resultType="java.lang.Long">
SELECT
DISTINCT shop_id as shopId
FROM
lease_product
WHERE
product_id IN
<foreach collection="productIds" item="productId" open="(" separator="," close=")">
#{productId}
</foreach>
and del = 0
</select>
<select id="getShopNameMapByIds" resultType="com.m2pool.lease.entity.LeaseShop">
SELECT
id ,
name
FROM
lease_shop
WHERE
id IN
<foreach collection="shopIds" item="shopId" open="(" separator="," close=")">
#{shopId}
</foreach>
and del = 0
</select>
</mapper>

View File

@@ -17,9 +17,11 @@
id, cart_id, product_id, product_machine_id, create_time, update_time
</sql>
<select id="getCartInfoList" resultType="com.m2pool.lease.dto.ShoppingCartInfoDto">
select lsci.product_machine_id as productMachineId,lsci.cart_id as cartId, lsci.product_id as productId,lp.image,lp.shop_id as shopId,lp.coin,lp.name, lp.state as productState
from lease_shopping_cart_info lsci left join lease_product lp on lsci.product_id = lp.id
<select id="getProductAndMachineIds" resultType="com.m2pool.lease.dto.ShoppingCartInfoDto">
select product_machine_id as productMachineId,
product_id as productId,
lease_time as leaseTime
from lease_shopping_cart_info
where cart_id = #{cartId}
</select>

View File

@@ -89,6 +89,30 @@
(`from_address` = #{item.fromAddress} AND from_symbol = #{item.fromSymbol} AND from_chain = #{item.fromChain})
</foreach>)
</select>
<select id="selectWalletByChainAndCoinAndUsername" resultType="com.m2pool.lease.entity.LeaseUserWalletData">
SELECT
id,
-- user_id as userId,
from_address as fromAddress,
balance,
blocked_balance as blockedBalance,
from_symbol as fromSymbol,
from_chain as fromChain
-- qrcode,
-- to_address as toAddress,
-- to_symbol as toSymbol,
-- to_chain as toChain,
-- create_time as createTime,
-- queue_id as queueId
FROM lease_user_wallet_data
WHERE del = 0 AND user_id = #{username} AND (
<foreach collection="list" item="item" separator="OR">
(from_chain = #{item.chain} AND from_symbol = #{item.coin} )
</foreach>
)
</select>
</mapper>

View File

@@ -0,0 +1,40 @@
package com.m2pool.manage.utils;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.util.Date;
/**
* @Description 支付接口请求参数
* @Date 2025/8/8 13:44
* @Author yyb
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PayParams {
/**
* 币种(USDC ,USDT)
*/
private String coin;
/**
* 收款地址
*/
private String address;
/**
* 收款金额
*/
private BigDecimal amount;
/**
* 下单时间
*/
private Long ts;
}