Commit 474b5189 by Jony.L

实现订单快照功能

parent 0533ddfb
......@@ -24,5 +24,9 @@ public interface ErrorCodeConstants {
ErrorCode RESOURCE_ORDER_PAY_ORDER_ID_MISMATCH = new ErrorCode(1_030_007_000, "支付订单ID不匹配");
ErrorCode RESOURCE_ORDER_NOT_BELONGS_TO_USER = new ErrorCode(1_030_008_000, "算力资源订单不属于当前用户");
ErrorCode RESOURCE_SPU_STOCK_INSUFFICIENT = new ErrorCode(1_030_009_000, "算力资源SPU库存不足");
ErrorCode RESOURCE_ORDER_SNAPSHOT_NOT_EXISTS = new ErrorCode(1_030_009_999, "算力资源订单快照不存在");
ErrorCode RESOURCE_ORDER_SNAPSHOT_CREATE_FAILED = new ErrorCode(1_030_010_000, "创建订单快照失败");
ErrorCode RESOURCE_ORDER_SNAPSHOT_QUERY_FAILED = new ErrorCode(1_030_010_001, "查询订单快照失败");
ErrorCode RESOURCE_ORDER_SNAPSHOT_DELETE_FAILED = new ErrorCode(1_030_010_002, "删除订单快照失败");
}
\ No newline at end of file
......@@ -61,6 +61,7 @@ public class AppResourceOrderController {
public CommonResult<PageResult<AppResourceOrderRespVO>> getUserResourceOrderPage(@Valid AppResourceOrderPageReqVO pageReqVO) {
Long userId = getLoginUserId();
pageReqVO.setUserId(userId);
// 订单状态从订单表获取,硬件配置优先从快照表获取
PageResult<AppResourceOrderRespVO> pageResult = resourceOrderService.getUserResourceOrderPage(pageReqVO);
return success(pageResult);
}
......@@ -70,6 +71,7 @@ public class AppResourceOrderController {
@Parameter(name = "id", description = "编号", required = true)
public CommonResult<AppResourceOrderRespVO> getUserResourceOrder(@RequestParam("id") Long id) {
Long userId = getLoginUserId();
// 订单状态从订单表获取,硬件配置优先从快照表获取
AppResourceOrderRespVO orderDetail = resourceOrderService.getUserResourceOrder(userId, id);
return success(orderDetail);
}
......
package com.luhu.computility.module.compute.controller.app.resourceordersnapshot.vo;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import com.luhu.computility.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static com.luhu.computility.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "用户 APP - 算力资源订单快照分页 Request VO")
@Data
public class AppResourceOrderSnapshotPageReqVO extends PageParam {
@Schema(description = "用户ID", example = "1024")
private Long userId;
@Schema(description = "订单ID", example = "15798")
private Long orderId;
@Schema(description = "支付订单ID", example = "15799")
private Long payOrderId;
@Schema(description = "SPU名称", example = "GPU服务器A型")
private String spuName;
@Schema(description = "CPU配置", example = "Intel Xeon E5-2680 v4")
private String cpu;
@Schema(description = "GPU配置", example = "NVIDIA RTX 4090")
private String gpu;
@Schema(description = "内存配置", example = "64GB DDR4")
private String ram;
@Schema(description = "存储配置", example = "2TB NVMe SSD")
private String storage;
@Schema(description = "电源配置", example = "3500W")
private String powerSupply;
@Schema(description = "网卡配置", example = "2Gbps")
private String nic;
@Schema(description = "服务器IP", example = "192.168.1.100")
private String ip;
@Schema(description = "租赁天数", example = "7")
private Integer durationDays;
@Schema(description = "支付价格(分)", example = "30624")
private Long paymentPrice;
@Schema(description = "市场价格(分)", example = "31709")
private Long marketPrice;
@Schema(description = "租赁开始时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] rentStartTime;
@Schema(description = "租赁结束时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] rentEndTime;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}
\ No newline at end of file
package com.luhu.computility.module.compute.controller.app.resourceordersnapshot.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "用户 APP - 算力资源订单快照 Response VO")
@Data
public class AppResourceOrderSnapshotRespVO {
@Schema(description = "快照ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id;
@Schema(description = "关联订单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long orderId;
@Schema(description = "用户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long userId;
@Schema(description = "用户昵称", example = "张三")
private String nickname;
@Schema(description = "用户手机号", example = "13800138000")
private String mobile;
@Schema(description = "支付订单ID", example = "1024")
private Long payOrderId;
@Schema(description = "CPU配置", example = "Intel Xeon E5-2680 v4")
private String cpu;
@Schema(description = "GPU配置", example = "NVIDIA RTX 4090")
private String gpu;
@Schema(description = "内存配置", example = "64GB DDR4")
private String ram;
@Schema(description = "存储配置", example = "2TB NVMe SSD")
private String storage;
@Schema(description = "电源配置", example = "3500W")
private String powerSupply;
@Schema(description = "网卡配置", example = "2Gbps")
private String nic;
@Schema(description = "服务器IP", example = "192.168.1.100")
private String ip;
@Schema(description = "SPU名称", example = "GPU服务器A型")
private String spuName;
@Schema(description = "租赁天数", example = "7")
private Integer durationDays;
@Schema(description = "租赁开始时间")
private LocalDateTime rentStartTime;
@Schema(description = "租赁结束时间")
private LocalDateTime rentEndTime;
@Schema(description = "支付价格(分)", example = "30624")
private Long paymentPrice;
@Schema(description = "市场价格(分)", example = "31709")
private Long marketPrice;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
@Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime updateTime;
}
\ No newline at end of file
package com.luhu.computility.module.compute.controller.app.resourceordersnapshot.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
@Schema(description = "用户 APP - 算力资源订单快照新增/修改 Request VO")
@Data
public class AppResourceOrderSnapshotSaveReqVO {
@Schema(description = "快照ID", example = "1024")
private Long id;
@Schema(description = "关联订单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "关联订单ID不能为空")
private Long orderId;
@Schema(description = "用户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "用户ID不能为空")
private Long userId;
@Schema(description = "支付订单ID", example = "1024")
private Long payOrderId;
@Schema(description = "CPU配置", requiredMode = Schema.RequiredMode.REQUIRED, example = "Intel Xeon E5-2680 v4")
@NotBlank(message = "CPU配置不能为空")
private String cpu;
@Schema(description = "GPU配置", example = "NVIDIA RTX 4090")
private String gpu;
@Schema(description = "内存配置", requiredMode = Schema.RequiredMode.REQUIRED, example = "64GB DDR4")
@NotBlank(message = "内存配置不能为空")
private String ram;
@Schema(description = "存储配置", requiredMode = Schema.RequiredMode.REQUIRED, example = "2TB NVMe SSD")
@NotBlank(message = "存储配置不能为空")
private String storage;
@Schema(description = "电源配置", requiredMode = Schema.RequiredMode.REQUIRED, example = "3500W")
@NotBlank(message = "电源配置不能为空")
private String powerSupply;
@Schema(description = "网卡配置", requiredMode = Schema.RequiredMode.REQUIRED, example = "2Gbps")
@NotBlank(message = "网卡配置不能为空")
private String nic;
@Schema(description = "服务器IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "192.168.1.100")
@NotBlank(message = "服务器IP不能为空")
private String ip;
@Schema(description = "SPU名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "GPU服务器A型")
@NotBlank(message = "SPU名称不能为空")
private String spuName;
@Schema(description = "租赁天数", requiredMode = Schema.RequiredMode.REQUIRED, example = "7")
@NotNull(message = "租赁天数不能为空")
private Integer durationDays;
@Schema(description = "租赁开始时间")
private LocalDateTime rentStartTime;
@Schema(description = "租赁结束时间")
private LocalDateTime rentEndTime;
@Schema(description = "支付价格(分)", requiredMode = Schema.RequiredMode.REQUIRED, example = "30624")
@NotNull(message = "支付价格不能为空")
private Long paymentPrice;
@Schema(description = "市场价格(分)", requiredMode = Schema.RequiredMode.REQUIRED, example = "31709")
@NotNull(message = "市场价格不能为空")
private Long marketPrice;
}
\ No newline at end of file
package com.luhu.computility.module.compute.dal.dataobject.resourceordersnapshot;
import lombok.*;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.*;
import com.luhu.computility.framework.mybatis.core.dataobject.BaseDO;
/**
* 算力资源订单硬件配置快照 DO
*
* 用于保存订单创建时的硬件配置信息,避免后续SKU/SPU删除或修改导致订单详情丢失
*
* @author jony
*/
@TableName("compute_resource_order_snapshot")
@KeySequence("compute_resource_order_snapshot_seq")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ResourceOrderSnapshotDO extends BaseDO {
/**
* 快照ID
*/
@TableId
private Long id;
/**
* 关联的订单ID
*/
private Long orderId;
/**
* 用户ID快照
*/
private Long userId;
/**
* 支付订单ID
*/
private Long payOrderId;
/**
* CPU配置快照
*/
private String cpu;
/**
* GPU配置快照
*/
private String gpu;
/**
* 内存配置快照
*/
private String ram;
/**
* 存储配置快照
*/
private String storage;
/**
* 电源配置快照
*/
private String powerSupply;
/**
* 网卡配置快照
*/
private String nic;
/**
* 服务器IP地址快照
*/
private String ip;
/**
* SPU名称快照
*/
private String spuName;
/**
* 租赁天数快照
*/
private Integer durationDays;
/**
* 租赁开始时间快照
*/
private LocalDateTime rentStartTime;
/**
* 租赁结束时间快照
*/
private LocalDateTime rentEndTime;
/**
* 支付价格快照(分)
*/
private Long paymentPrice;
/**
* 市场价格快照(分)
*/
private Long marketPrice;
}
\ No newline at end of file
package com.luhu.computility.module.compute.dal.mysql.resourceordersnapshot;
import java.time.LocalDateTime;
import java.util.*;
import com.luhu.computility.framework.common.pojo.PageResult;
import com.luhu.computility.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.luhu.computility.framework.mybatis.core.query.MPJLambdaWrapperX;
import com.luhu.computility.framework.mybatis.core.mapper.BaseMapperX;
import com.luhu.computility.module.compute.dal.dataobject.resourceordersnapshot.ResourceOrderSnapshotDO;
import com.luhu.computility.module.compute.controller.app.resourceordersnapshot.vo.AppResourceOrderSnapshotRespVO;
import com.luhu.computility.module.compute.controller.app.resourceordersnapshot.vo.AppResourceOrderSnapshotPageReqVO;
import com.luhu.computility.module.member.dal.dataobject.user.MemberUserDO;
import org.apache.ibatis.annotations.Mapper;
/**
* 算力资源订单硬件配置快照 Mapper
*
* @author jony
*/
@Mapper
public interface ResourceOrderSnapshotMapper extends BaseMapperX<ResourceOrderSnapshotDO> {
default PageResult<AppResourceOrderSnapshotRespVO> selectPage(AppResourceOrderSnapshotPageReqVO reqVO) {
return selectJoinPage(reqVO, AppResourceOrderSnapshotRespVO.class, new MPJLambdaWrapperX<ResourceOrderSnapshotDO>()
.selectAll(ResourceOrderSnapshotDO.class)
.selectAs(MemberUserDO::getNickname, AppResourceOrderSnapshotRespVO::getNickname)
.selectAs(MemberUserDO::getMobile, AppResourceOrderSnapshotRespVO::getMobile)
.leftJoin(MemberUserDO.class, MemberUserDO::getId, ResourceOrderSnapshotDO::getUserId)
.eqIfPresent(ResourceOrderSnapshotDO::getUserId, reqVO.getUserId())
.eqIfPresent(ResourceOrderSnapshotDO::getOrderId, reqVO.getOrderId())
.eqIfPresent(ResourceOrderSnapshotDO::getPayOrderId, reqVO.getPayOrderId())
.likeIfPresent(ResourceOrderSnapshotDO::getSpuName, reqVO.getSpuName())
.eqIfPresent(ResourceOrderSnapshotDO::getCpu, reqVO.getCpu())
.eqIfPresent(ResourceOrderSnapshotDO::getGpu, reqVO.getGpu())
.eqIfPresent(ResourceOrderSnapshotDO::getRam, reqVO.getRam())
.eqIfPresent(ResourceOrderSnapshotDO::getStorage, reqVO.getStorage())
.eqIfPresent(ResourceOrderSnapshotDO::getPowerSupply, reqVO.getPowerSupply())
.eqIfPresent(ResourceOrderSnapshotDO::getNic, reqVO.getNic())
.eqIfPresent(ResourceOrderSnapshotDO::getIp, reqVO.getIp())
.eqIfPresent(ResourceOrderSnapshotDO::getDurationDays, reqVO.getDurationDays())
.eqIfPresent(ResourceOrderSnapshotDO::getPaymentPrice, reqVO.getPaymentPrice())
.eqIfPresent(ResourceOrderSnapshotDO::getMarketPrice, reqVO.getMarketPrice())
.betweenIfPresent(ResourceOrderSnapshotDO::getRentStartTime, reqVO.getRentStartTime())
.betweenIfPresent(ResourceOrderSnapshotDO::getRentEndTime, reqVO.getRentEndTime())
.betweenIfPresent(ResourceOrderSnapshotDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(ResourceOrderSnapshotDO::getId));
}
default ResourceOrderSnapshotDO selectByOrderId(Long orderId) {
return selectOne(new LambdaQueryWrapperX<ResourceOrderSnapshotDO>()
.eq(ResourceOrderSnapshotDO::getOrderId, orderId)
.eq(ResourceOrderSnapshotDO::getDeleted, false));
}
default List<ResourceOrderSnapshotDO> selectListByOrderIds(Collection<Long> orderIds) {
if (orderIds == null || orderIds.isEmpty()) {
return Collections.emptyList();
}
return selectList(new LambdaQueryWrapperX<ResourceOrderSnapshotDO>()
.in(ResourceOrderSnapshotDO::getOrderId, orderIds)
.eq(ResourceOrderSnapshotDO::getDeleted, false));
}
default int deleteByOrderId(Long orderId) {
return delete(new LambdaQueryWrapperX<ResourceOrderSnapshotDO>()
.eq(ResourceOrderSnapshotDO::getOrderId, orderId));
}
}
\ No newline at end of file
......@@ -12,6 +12,8 @@ import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppRe
import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppWpgjPayOrderSubmitRespVO;
import com.luhu.computility.module.pay.controller.admin.notify.vo.WpgjPayNotifyDTO;
import com.luhu.computility.module.compute.dal.dataobject.resourceorder.ResourceOrderDO;
import com.luhu.computility.module.compute.dal.dataobject.resourcesku.ResourceSkuDO;
import com.luhu.computility.module.compute.dal.dataobject.resourcespu.ResourceSpuDO;
import com.luhu.computility.framework.common.pojo.PageResult;
import com.luhu.computility.framework.common.pojo.PageParam;
......@@ -167,4 +169,16 @@ public interface ResourceOrderService {
*/
int expireFinishedOrders(LocalDateTime startTime, LocalDateTime endTime);
/**
* 创建订单硬件配置快照
*
* 在支付成功后调用,保存当时的硬件配置信息,避免后续SKU/SPU变更导致订单详情丢失
*
* @param order 订单信息
* @param sku SKU信息
* @param spu SPU信息
* @return 快照ID
*/
Long createOrderHardwareSnapshot(ResourceOrderDO order, ResourceSkuDO sku, ResourceSpuDO spu);
}
\ No newline at end of file
......@@ -12,9 +12,11 @@ import com.luhu.computility.module.compute.controller.admin.resourceorder.vo.Res
import com.luhu.computility.module.compute.controller.admin.resourceorder.vo.ResourceOrderRespVO;
import com.luhu.computility.module.compute.controller.admin.resourceorder.vo.ResourceOrderSaveReqVO;
import com.luhu.computility.module.compute.controller.app.resourceorder.vo.*;
import com.luhu.computility.module.compute.controller.app.resourceordersnapshot.vo.AppResourceOrderSnapshotSaveReqVO;
import com.luhu.computility.module.compute.dal.dataobject.resourceorder.ResourceOrderDO;
import com.luhu.computility.module.compute.dal.dataobject.resourcesku.ResourceSkuDO;
import com.luhu.computility.module.compute.dal.dataobject.resourcespu.ResourceSpuDO;
import com.luhu.computility.module.compute.dal.dataobject.resourceordersnapshot.ResourceOrderSnapshotDO;
import com.luhu.computility.module.compute.dal.mysql.resourceorder.ResourceOrderMapper;
import com.luhu.computility.module.compute.dal.redis.no.ResourceOrderNoRedisDAO;
import com.luhu.computility.module.compute.enums.ResourceOrderInvoiceStatus;
......@@ -24,6 +26,7 @@ import com.luhu.computility.module.compute.enums.ResourceSpuStatus;
import com.luhu.computility.module.compute.service.resourcecategory.ResourceCategoryService;
import com.luhu.computility.module.compute.service.resourcesku.ResourceSkuService;
import com.luhu.computility.module.compute.service.resourcespu.ResourceSpuService;
import com.luhu.computility.module.compute.service.resourceordersnapshot.ResourceOrderSnapshotService;
import com.luhu.computility.module.pay.api.order.PayOrderApi;
import com.luhu.computility.module.pay.api.order.dto.PayOrderCreateReqDTO;
import com.luhu.computility.module.pay.api.order.dto.PayOrderRespDTO;
......@@ -108,6 +111,9 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
@Resource
private ResourceSkuMapper resourceSkuMapper;
@Resource
private ResourceOrderSnapshotService resourceOrderSnapshotService;
@Override
public Long createResourceOrder(ResourceOrderSaveReqVO createReqVO) {
// 插入
......@@ -356,33 +362,61 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
List<AppResourceOrderRespVO> respList = convertList(pageResult.getList(), order -> {
AppResourceOrderRespVO respVO = BeanUtils.toBean(order, AppResourceOrderRespVO.class);
// 获取SKU和SPU信息
ResourceSkuDO sku = resourceSkuService.getResourceSku(order.getSkuId());
if (sku != null) {
ResourceSpuDO spu = resourceSpuService.getResourceSpu(sku.getSpuId());
if (spu != null) {
respVO.setSpuId(spu.getId());
respVO.setSpuName(spu.getName());
respVO.setCategoryId(spu.getCategoryId());
respVO.setCpu(spu.getCpu());
respVO.setGpu(spu.getGpu());
respVO.setRam(spu.getRam());
respVO.setStorage(spu.getStorage());
respVO.setPowerSupply(spu.getPowerSupply());
respVO.setNic(spu.getNic());
respVO.setIp(spu.getIp());
respVO.setLocation(spu.getLocation());
respVO.setSkuName(spu.getName() + " - " + sku.getDurationDays() + "天");
// 设置分类名称
if (spu.getCategoryId() != null) {
respVO.setCategoryName(resourceCategoryService.getResourceCategory(spu.getCategoryId()).getName());
// 优先从快照读取硬件配置信息,避免SKU/SPU变化影响历史订单
ResourceOrderSnapshotDO snapshot = resourceOrderSnapshotService.getOrderSnapshotByOrderId(order.getId());
if (snapshot != null) {
// 从快照中读取硬件配置(优先级更高)
respVO.setSpuName(snapshot.getSpuName());
respVO.setCpu(snapshot.getCpu());
respVO.setGpu(snapshot.getGpu());
respVO.setRam(snapshot.getRam());
respVO.setStorage(snapshot.getStorage());
respVO.setPowerSupply(snapshot.getPowerSupply());
respVO.setNic(snapshot.getNic());
respVO.setIp(snapshot.getIp());
respVO.setSkuName(snapshot.getSpuName() + " - " + snapshot.getDurationDays() + "天");
// 快照中没有的字段(分类、位置)需要从SPU获取
ResourceSkuDO sku = resourceSkuService.getResourceSku(order.getSkuId());
if (sku != null) {
ResourceSpuDO spu = resourceSpuService.getResourceSpu(sku.getSpuId());
if (spu != null) {
respVO.setSpuId(spu.getId());
respVO.setCategoryId(spu.getCategoryId());
respVO.setLocation(spu.getLocation());
// 设置分类名称
if (spu.getCategoryId() != null) {
respVO.setCategoryName(resourceCategoryService.getResourceCategory(spu.getCategoryId()).getName());
}
}
}
} else {
// 快照不存在,从SKU和SPU信息读取(兼容老订单)
ResourceSkuDO sku = resourceSkuService.getResourceSku(order.getSkuId());
if (sku != null) {
ResourceSpuDO spu = resourceSpuService.getResourceSpu(sku.getSpuId());
if (spu != null) {
respVO.setSpuId(spu.getId());
respVO.setSpuName(spu.getName());
respVO.setCategoryId(spu.getCategoryId());
respVO.setCpu(spu.getCpu());
respVO.setGpu(spu.getGpu());
respVO.setRam(spu.getRam());
respVO.setStorage(spu.getStorage());
respVO.setPowerSupply(spu.getPowerSupply());
respVO.setNic(spu.getNic());
respVO.setIp(spu.getIp());
respVO.setLocation(spu.getLocation());
respVO.setSkuName(spu.getName() + " - " + sku.getDurationDays() + "天");
// 设置分类名称
if (spu.getCategoryId() != null) {
respVO.setCategoryName(resourceCategoryService.getResourceCategory(spu.getCategoryId()).getName());
}
}
}
// feeInfo不需要设置,直接在前端显示 sku.getDurationDays() + "天"
}
return respVO;
......@@ -407,30 +441,60 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
// 组装响应数据
AppResourceOrderRespVO respVO = BeanUtils.toBean(order, AppResourceOrderRespVO.class);
// 获取SKU和SPU信息
ResourceSkuDO sku = resourceSkuService.getResourceSku(order.getSkuId());
if (sku != null) {
ResourceSpuDO spu = resourceSpuService.getResourceSpu(sku.getSpuId());
if (spu != null) {
respVO.setSpuId(spu.getId());
respVO.setSpuName(spu.getName());
respVO.setCategoryId(spu.getCategoryId());
respVO.setCpu(spu.getCpu());
respVO.setGpu(spu.getGpu());
respVO.setRam(spu.getRam());
respVO.setStorage(spu.getStorage());
respVO.setIp(spu.getIp());
respVO.setLocation(spu.getLocation());
respVO.setSkuName(spu.getName() + " - " + sku.getDurationDays() + "天");
// 设置分类名称
if (spu.getCategoryId() != null) {
respVO.setCategoryName(resourceCategoryService.getResourceCategory(spu.getCategoryId()).getName());
// 优先从快照读取硬件配置信息,避免SKU/SPU变化影响历史订单
ResourceOrderSnapshotDO snapshot = resourceOrderSnapshotService.getOrderSnapshotByOrderId(order.getId());
if (snapshot != null) {
// 从快照中读取硬件配置(优先级更高)
respVO.setSpuName(snapshot.getSpuName());
respVO.setCpu(snapshot.getCpu());
respVO.setGpu(snapshot.getGpu());
respVO.setRam(snapshot.getRam());
respVO.setStorage(snapshot.getStorage());
respVO.setPowerSupply(snapshot.getPowerSupply());
respVO.setNic(snapshot.getNic());
respVO.setIp(snapshot.getIp());
respVO.setSkuName(snapshot.getSpuName() + " - " + snapshot.getDurationDays() + "天");
// 快照中没有的字段(分类、位置)需要从SPU获取
ResourceSkuDO sku = resourceSkuService.getResourceSku(order.getSkuId());
if (sku != null) {
ResourceSpuDO spu = resourceSpuService.getResourceSpu(sku.getSpuId());
if (spu != null) {
respVO.setSpuId(spu.getId());
respVO.setCategoryId(spu.getCategoryId());
respVO.setLocation(spu.getLocation());
// 设置分类名称
if (spu.getCategoryId() != null) {
respVO.setCategoryName(resourceCategoryService.getResourceCategory(spu.getCategoryId()).getName());
}
}
}
} else {
// 快照不存在,从SKU和SPU信息读取(兼容老订单)
ResourceSkuDO sku = resourceSkuService.getResourceSku(order.getSkuId());
if (sku != null) {
ResourceSpuDO spu = resourceSpuService.getResourceSpu(sku.getSpuId());
if (spu != null) {
respVO.setSpuId(spu.getId());
respVO.setSpuName(spu.getName());
respVO.setCategoryId(spu.getCategoryId());
respVO.setCpu(spu.getCpu());
respVO.setGpu(spu.getGpu());
respVO.setRam(spu.getRam());
respVO.setStorage(spu.getStorage());
respVO.setPowerSupply(spu.getPowerSupply());
respVO.setNic(spu.getNic());
respVO.setIp(spu.getIp());
respVO.setLocation(spu.getLocation());
respVO.setSkuName(spu.getName() + " - " + sku.getDurationDays() + "天");
// feeInfo不需要设置,直接在前端显示 sku.getDurationDays() + "天"
// 设置分类名称
if (spu.getCategoryId() != null) {
respVO.setCategoryName(resourceCategoryService.getResourceCategory(spu.getCategoryId()).getName());
}
}
}
}
return respVO;
......@@ -483,6 +547,28 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
payRespVO = new AppWpgjPayOrderSubmitRespVO();
payRespVO.setId(order.getId()); // 价格为0时没有WPGJ订单ID,使用资源订单ID
payRespVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
// 价格为0时,用订单ID作为payOrderId
order.setPayOrderId(order.getId());
}
// 4. 创建订单硬件配置快照,保存下单时的配置信息
// 快照表作用:保存下单时的硬件配置,避免后续SKU/SPU变化影响历史订单显示
try {
ResourceSkuDO sku = resourceSkuService.getResourceSku(order.getSkuId());
if (sku != null) {
ResourceSpuDO spu = resourceSpuService.getResourceSpu(sku.getSpuId());
if (spu != null) {
createOrderHardwareSnapshot(order, sku, spu);
log.info("[createUserResourceOrderWithWpgj] 订单硬件配置快照创建完成,订单ID: {}", order.getId());
} else {
log.warn("[createUserResourceOrderWithWpgj] SPU不存在,无法创建快照,订单ID: {}, SPU_ID: {}", order.getId(), sku.getSpuId());
}
} else {
log.warn("[createUserResourceOrderWithWpgj] SKU不存在,无法创建快照,订单ID: {}, SKU_ID: {}", order.getId(), order.getSkuId());
}
} catch (Exception snapshotEx) {
log.error("[createUserResourceOrderWithWpgj] 创建订单硬件配置快照失败,订单ID: {}", order.getId(), snapshotEx);
// 快照创建失败不应该影响主流程,只记录日志
}
return payRespVO;
......@@ -566,7 +652,7 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
orderId, wpgjOrderAmt, resourceOrderAmt);
return;
}
log.error("[updateOrderPaidByWpgj] WPGJ金额: {}, 订单金额: {}",
log.info("[updateOrderPaidByWpgj] 支付金额校验通过,订单ID: {}, WPGJ金额: {}, 订单金额: {}",
orderId, wpgjOrderAmt, resourceOrderAmt);
// 4. 更新算力资源订单状态为已支付
......@@ -591,7 +677,8 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
} catch (Exception ex) {
log.error("[updateOrderPaidByWpgj] SPU购买后处理失败, orderId={}", orderId, ex);
}
log.info("[updateOrderPaidByWpgj] WPGJ支付成功回调处理完成,订单ID: {}, WPGJ订单号: {}",
log.info("[updateOrderPaidByWpgj] WPGJ支付成功回调处理完成,订单ID: {}, WPGJ订单号: {}",
orderId, notifyDTO.getOrderId());
......@@ -738,4 +825,42 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
}
}
@Override
public Long createOrderHardwareSnapshot(ResourceOrderDO order, ResourceSkuDO sku, ResourceSpuDO spu) {
try {
log.info("[createOrderHardwareSnapshot] 开始创建订单硬件配置快照,订单ID: {}, SPU名称: {}, SKU租赁天数: {}",
order.getId(), spu.getName(), sku.getDurationDays());
// 构建快照创建请求
AppResourceOrderSnapshotSaveReqVO createReqVO = new AppResourceOrderSnapshotSaveReqVO();
createReqVO.setOrderId(order.getId());
createReqVO.setUserId(order.getUserId());
createReqVO.setPayOrderId(order.getPayOrderId());
createReqVO.setCpu(spu.getCpu());
createReqVO.setGpu(spu.getGpu());
createReqVO.setRam(spu.getRam());
createReqVO.setStorage(spu.getStorage());
createReqVO.setPowerSupply(spu.getPowerSupply());
createReqVO.setNic(spu.getNic());
createReqVO.setIp(spu.getIp());
createReqVO.setSpuName(spu.getName());
createReqVO.setDurationDays(sku.getDurationDays());
createReqVO.setRentStartTime(order.getRentStartTime());
createReqVO.setRentEndTime(order.getRentEndTime());
createReqVO.setPaymentPrice(order.getPaymentPrice());
createReqVO.setMarketPrice(order.getMarketPrice());
// 调用快照服务创建快照
Long snapshotId = resourceOrderSnapshotService.createOrderSnapshot(createReqVO);
log.info("[createOrderHardwareSnapshot] 订单硬件配置快照创建成功,订单ID: {}, 快照ID: {}", order.getId(), snapshotId);
return snapshotId;
} catch (Exception e) {
log.error("[createOrderHardwareSnapshot] 创建订单硬件配置快照失败,订单ID: {}", order.getId(), e);
// 快照创建失败不应该影响主流程,只记录日志
return null;
}
}
}
\ No newline at end of file
package com.luhu.computility.module.compute.service.resourceordersnapshot;
import com.luhu.computility.framework.common.pojo.PageResult;
import com.luhu.computility.module.compute.controller.app.resourceordersnapshot.vo.AppResourceOrderSnapshotSaveReqVO;
import com.luhu.computility.module.compute.controller.app.resourceordersnapshot.vo.AppResourceOrderSnapshotRespVO;
import com.luhu.computility.module.compute.controller.app.resourceordersnapshot.vo.AppResourceOrderSnapshotPageReqVO;
import com.luhu.computility.module.compute.dal.dataobject.resourceordersnapshot.ResourceOrderSnapshotDO;
import javax.validation.Valid;
import java.util.List;
import java.util.Collection;
/**
* 算力资源订单硬件配置快照 Service 接口
*
* 提供订单硬件配置快照的创建、查询、管理功能,确保订单详情的持久化存储
*
* @author jony
*/
public interface ResourceOrderSnapshotService {
/**
* 创建订单硬件配置快照
*
* @param createReqVO 创建信息
* @return 快照ID
*/
Long createOrderSnapshot(@Valid AppResourceOrderSnapshotSaveReqVO createReqVO);
/**
* 更新订单硬件配置快照
*
* @param updateReqVO 更新信息
*/
void updateOrderSnapshot(@Valid AppResourceOrderSnapshotSaveReqVO updateReqVO);
/**
* 删除订单硬件配置快照
*
* @param id 编号
*/
void deleteOrderSnapshot(Long id);
/**
* 获得订单硬件配置快照
*
* @param id 编号
* @return 订单硬件配置快照
*/
AppResourceOrderSnapshotRespVO getOrderSnapshot(Long id);
/**
* 获得订单硬件配置快照分页
*
* @param pageReqVO 分页查询
* @return 订单硬件配置快照分页
*/
PageResult<AppResourceOrderSnapshotRespVO> getOrderSnapshotPage(AppResourceOrderSnapshotPageReqVO pageReqVO);
/**
* 根据订单ID获取硬件配置快照
*
* @param orderId 订单ID
* @return 快照信息
*/
ResourceOrderSnapshotDO getOrderSnapshotByOrderId(Long orderId);
/**
* 根据订单ID列表批量查询快照
*
* @param orderIds 订单ID列表
* @return 快照列表
*/
List<ResourceOrderSnapshotDO> getOrderSnapshotListByOrderIds(Collection<Long> orderIds);
/**
* 校验订单硬件配置快照是否存在
*
* @param id 编号
*/
void validateOrderSnapshotExists(Long id);
}
\ No newline at end of file
package com.luhu.computility.module.compute.service.resourceordersnapshot.impl;
import cn.hutool.core.collection.CollUtil;
import com.luhu.computility.framework.common.pojo.PageResult;
import com.luhu.computility.framework.common.util.object.BeanUtils;
import com.luhu.computility.module.compute.controller.app.resourceordersnapshot.vo.AppResourceOrderSnapshotSaveReqVO;
import com.luhu.computility.module.compute.controller.app.resourceordersnapshot.vo.AppResourceOrderSnapshotRespVO;
import com.luhu.computility.module.compute.controller.app.resourceordersnapshot.vo.AppResourceOrderSnapshotPageReqVO;
import com.luhu.computility.module.compute.dal.dataobject.resourceordersnapshot.ResourceOrderSnapshotDO;
import com.luhu.computility.module.compute.dal.mysql.resourceordersnapshot.ResourceOrderSnapshotMapper;
import com.luhu.computility.module.compute.service.resourceordersnapshot.ResourceOrderSnapshotService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Collection;
import static com.luhu.computility.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.luhu.computility.module.compute.enums.ErrorCodeConstants.*;
/**
* 算力资源订单硬件配置快照 Service 实现类
*
* @author jony
*/
@Service
@Validated
@Slf4j
public class ResourceOrderSnapshotServiceImpl implements ResourceOrderSnapshotService {
@Resource
private ResourceOrderSnapshotMapper resourceOrderSnapshotMapper;
@Override
public Long createOrderSnapshot(AppResourceOrderSnapshotSaveReqVO createReqVO) {
// 插入
ResourceOrderSnapshotDO resourceOrderSnapshot = BeanUtils.toBean(createReqVO, ResourceOrderSnapshotDO.class);
resourceOrderSnapshotMapper.insert(resourceOrderSnapshot);
// 返回
return resourceOrderSnapshot.getId();
}
@Override
public void updateOrderSnapshot(AppResourceOrderSnapshotSaveReqVO updateReqVO) {
// 校验存在
validateOrderSnapshotExists(updateReqVO.getId());
// 更新
ResourceOrderSnapshotDO updateObj = BeanUtils.toBean(updateReqVO, ResourceOrderSnapshotDO.class);
resourceOrderSnapshotMapper.updateById(updateObj);
}
@Override
public void deleteOrderSnapshot(Long id) {
// 校验存在
validateOrderSnapshotExists(id);
// 删除
resourceOrderSnapshotMapper.deleteById(id);
}
@Override
public AppResourceOrderSnapshotRespVO getOrderSnapshot(Long id) {
ResourceOrderSnapshotDO snapshotDO = resourceOrderSnapshotMapper.selectById(id);
return BeanUtils.toBean(snapshotDO, AppResourceOrderSnapshotRespVO.class);
}
@Override
public PageResult<AppResourceOrderSnapshotRespVO> getOrderSnapshotPage(AppResourceOrderSnapshotPageReqVO pageReqVO) {
return resourceOrderSnapshotMapper.selectPage(pageReqVO);
}
@Override
public ResourceOrderSnapshotDO getOrderSnapshotByOrderId(Long orderId) {
return resourceOrderSnapshotMapper.selectByOrderId(orderId);
}
@Override
public List<ResourceOrderSnapshotDO> getOrderSnapshotListByOrderIds(Collection<Long> orderIds) {
if (CollUtil.isEmpty(orderIds)) {
return Collections.emptyList();
}
return resourceOrderSnapshotMapper.selectListByOrderIds(orderIds);
}
@Override
public void validateOrderSnapshotExists(Long id) {
if (resourceOrderSnapshotMapper.selectById(id) == null) {
throw exception(RESOURCE_ORDER_SNAPSHOT_NOT_EXISTS);
}
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment