Commit d0d82123 by renyizhao

算力资源改造完成

parent 97fc1928
package com.luhu.computility.framework.websocket.core.sender.kafka; package com.luhu.computility.framework.websocket.core.sender.kafka;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors;
/** /**
* Kafka 广播 WebSocket 的消息 * Kafka 广播 WebSocket 的消息
...@@ -8,6 +9,7 @@ import lombok.Data; ...@@ -8,6 +9,7 @@ import lombok.Data;
* @author 芋道源码 * @author 芋道源码
*/ */
@Data @Data
@Accessors(chain = true)
public class KafkaWebSocketMessage { public class KafkaWebSocketMessage {
/** /**
......
...@@ -262,8 +262,8 @@ public class HomeIndexServiceImpl implements HomeIndexService { ...@@ -262,8 +262,8 @@ public class HomeIndexServiceImpl implements HomeIndexService {
todayLocalDateTime[1] = today.atTime(23, 59, 59, 999_999_999); todayLocalDateTime[1] = today.atTime(23, 59, 59, 999_999_999);
MemberUserPageReqVO queryVO = new MemberUserPageReqVO(); MemberUserPageReqVO queryVO = new MemberUserPageReqVO();
MemberUserPageReqVO memberUserPageReqVO = queryVO.setCreateTime(todayLocalDateTime); queryVO.setCreateTime(todayLocalDateTime);
List<MemberUserDO> userList = memberUserService.getUserList(memberUserPageReqVO); List<MemberUserDO> userList = memberUserService.getUserList(queryVO);
// 获取今日已完成的算力资源订单统计 // 获取今日已完成的算力资源订单统计
ComputeOrderStatisticsDTO computeStatistics = computeOrderStatisticsApi.getTodayOrderStatistics(todayLocalDateTime); ComputeOrderStatisticsDTO computeStatistics = computeOrderStatisticsApi.getTodayOrderStatistics(todayLocalDateTime);
......
...@@ -37,4 +37,15 @@ public interface ErrorCodeConstants { ...@@ -37,4 +37,15 @@ public interface ErrorCodeConstants {
ErrorCode RESOURCE_SPU_IMPORT_CATEGORY_INVALID = new ErrorCode(1_030_012_002, "商品分类不存在或已禁用"); ErrorCode RESOURCE_SPU_IMPORT_CATEGORY_INVALID = new ErrorCode(1_030_012_002, "商品分类不存在或已禁用");
ErrorCode RESOURCE_SPU_IMPORT_HEADER_INVALID = new ErrorCode(1_030_012_003, "导入文件表头不合法"); ErrorCode RESOURCE_SPU_IMPORT_HEADER_INVALID = new ErrorCode(1_030_012_003, "导入文件表头不合法");
// ========== 阶段 C - 商家发货相关错误码 ==========
ErrorCode RESOURCE_ORDER_STATUS_NOT_PENDING_DELIVERY = new ErrorCode(1_030_013_000, "算力资源订单状态不是待发货,无法发货");
ErrorCode RESOURCE_ORDER_DELIVERY_FIELDS_REQUIRED = new ErrorCode(1_030_013_001, "服务器IP、初始用户名、初始密码不能为空");
ErrorCode RESOURCE_ORDER_ALREADY_DELIVERED = new ErrorCode(1_030_013_002, "算力资源订单已发货");
// ========== 阶段 D - 取消 + 客服人工退款相关错误码 ==========
ErrorCode RESOURCE_ORDER_STATUS_NOT_CANCELABLE = new ErrorCode(1_030_014_003, "算力资源订单当前状态不可取消");
ErrorCode RESOURCE_ORDER_ADMIN_CANCEL_REASON_REQUIRED = new ErrorCode(1_030_014_000, "客服取消订单需填写原因");
ErrorCode RESOURCE_ORDER_STATUS_NOT_PENDING_REFUND = new ErrorCode(1_030_014_001, "算力资源订单状态不是待退款,无法标记已退款");
ErrorCode RESOURCE_ORDER_REFUND_PRICE_INVALID = new ErrorCode(1_030_014_002, "退款金额不合法");
} }
\ No newline at end of file
...@@ -13,9 +13,11 @@ import lombok.Getter; ...@@ -13,9 +13,11 @@ import lombok.Getter;
public enum ResourceOrderStatus { public enum ResourceOrderStatus {
UNPAID(0, "待支付"), UNPAID(0, "待支付"),
PAID(1, "已支付"), PENDING_DELIVERY(5, "待发货"),
DELIVERED(6, "已发货"),
FINISHED(2, "已结束"), FINISHED(2, "已结束"),
CANCELED(3, "已取消"), CANCELED(3, "已取消"),
PENDING_REFUND(7, "待退款"),
REFUNDED(4, "已退款"); REFUNDED(4, "已退款");
private final Integer value; private final Integer value;
......
...@@ -37,6 +37,7 @@ import javax.validation.Valid; ...@@ -37,6 +37,7 @@ import javax.validation.Valid;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import static com.luhu.computility.framework.common.pojo.CommonResult.success; import static com.luhu.computility.framework.common.pojo.CommonResult.success;
import static com.luhu.computility.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import com.luhu.computility.framework.common.util.object.BeanUtils; import com.luhu.computility.framework.common.util.object.BeanUtils;
import com.luhu.computility.framework.tenant.core.aop.TenantIgnore; import com.luhu.computility.framework.tenant.core.aop.TenantIgnore;
import com.luhu.computility.module.compute.dal.mysql.resourceorder.ResourceOrderMapper; import com.luhu.computility.module.compute.dal.mysql.resourceorder.ResourceOrderMapper;
...@@ -147,11 +148,34 @@ public class ResourceOrderController { ...@@ -147,11 +148,34 @@ public class ResourceOrderController {
if(order == null){ if(order == null){
throw new ServiceException("订单不存在!"); throw new ServiceException("订单不存在!");
} }
if(!order.getStatus().equals(ResourceOrderStatus.PAID.getValue())){ if(!order.getStatus().equals(ResourceOrderStatus.DELIVERED.getValue())){
throw new ServiceException("只有已支付的订单可以开票!"); throw new ServiceException("只有已发货的订单可以开票!");
} }
return success(resourceOrderService.updateInvoice(saveVO)); return success(resourceOrderService.updateInvoice(saveVO));
} }
@PostMapping("/deliver")
@Operation(summary = "商家发货:填写 IP/用户名/密码,开始计时")
@PreAuthorize("@ss.hasPermission('compute:resource-order:deliver')")
public CommonResult<Boolean> deliverResourceOrder(@Valid @RequestBody ResourceOrderDeliverReqVO reqVO) {
resourceOrderService.deliverOrder(getLoginUserId(), reqVO);
return success(true);
}
@PostMapping("/admin-cancel")
@Operation(summary = "客服取消待发货订单(→ 待退款)")
@PreAuthorize("@ss.hasPermission('compute:resource-order:admin-cancel')")
public CommonResult<Boolean> adminCancelResourceOrder(@Valid @RequestBody ResourceOrderAdminCancelReqVO reqVO) {
resourceOrderService.adminCancelOrder(getLoginUserId(), reqVO.getOrderId(), reqVO.getReason());
return success(true);
}
@PostMapping("/mark-refunded")
@Operation(summary = "客服标记已退款(待退款 → 已退款)")
@PreAuthorize("@ss.hasPermission('compute:resource-order:mark-refunded')")
public CommonResult<Boolean> markRefunded(@Valid @RequestBody ResourceOrderMarkRefundedReqVO reqVO) {
resourceOrderService.markRefunded(getLoginUserId(), reqVO.getOrderId(), reqVO.getRefundPrice(), reqVO.getRefundRemark());
return success(true);
}
} }
\ No newline at end of file
package com.luhu.computility.module.compute.controller.admin.resourceorder.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@Schema(description = "管理后台 - 算力资源订单客服取消 Request VO")
@Data
public class ResourceOrderAdminCancelReqVO {
@Schema(description = "订单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "订单ID不能为空")
private Long orderId;
@Schema(description = "客服取消原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "商家断货,无法发货")
@NotEmpty(message = "客服取消原因不能为空")
private String reason;
}
package com.luhu.computility.module.compute.controller.admin.resourceorder.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@Schema(description = "管理后台 - 算力资源订单发货 Request VO")
@Data
public class ResourceOrderDeliverReqVO {
@Schema(description = "订单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "订单ID不能为空")
private Long orderId;
@Schema(description = "服务器 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "192.168.1.100")
@NotEmpty(message = "服务器IP不能为空")
private String deliveryIp;
@Schema(description = "初始用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "root")
@NotEmpty(message = "初始用户名不能为空")
private String deliveryUsername;
@Schema(description = "初始密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "P@ssw0rd123")
@NotEmpty(message = "初始密码不能为空")
private String deliveryPassword;
@Schema(description = "发货备注(可选)", example = "已为客户预装 CentOS 7.9")
private String deliverRemark;
}
package com.luhu.computility.module.compute.controller.admin.resourceorder.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.PositiveOrZero;
@Schema(description = "管理后台 - 算力资源订单标记已退款 Request VO")
@Data
public class ResourceOrderMarkRefundedReqVO {
@Schema(description = "订单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "订单ID不能为空")
private Long orderId;
@Schema(description = "退款金额(分,可选;0 或 null 表示全额按订单支付金额)", example = "30624")
@PositiveOrZero(message = "退款金额不能为负数")
private Long refundPrice;
@Schema(description = "退款备注(可选)", example = "已通过 WPGJ 对账退款")
private String refundRemark;
}
...@@ -64,6 +64,30 @@ public class ResourceOrderRespVO { ...@@ -64,6 +64,30 @@ public class ResourceOrderRespVO {
@ExcelProperty("支付渠道") @ExcelProperty("支付渠道")
private String payChannelCode; private String payChannelCode;
@Schema(description = "发货 IP(商家发货时填写)")
@ExcelProperty("发货IP")
private String deliveryIp;
@Schema(description = "发货初始用户名")
@ExcelProperty("发货用户名")
private String deliveryUsername;
@Schema(description = "发货初始密码")
@ExcelProperty("发货密码")
private String deliveryPassword;
@Schema(description = "发货时间(也是租赁开始时间)")
@ExcelProperty("发货时间")
private LocalDateTime deliveredTime;
@Schema(description = "发货操作人 ID")
@ExcelProperty("发货操作人ID")
private Long deliverOperatorId;
@Schema(description = "发货操作人姓名(冗余)")
@ExcelProperty("发货操作人")
private String deliverOperatorName;
@Schema(description = "租赁开始时间") @Schema(description = "租赁开始时间")
@ExcelProperty("租赁开始时间") @ExcelProperty("租赁开始时间")
private LocalDateTime rentStartTime; private LocalDateTime rentStartTime;
...@@ -88,6 +112,10 @@ public class ResourceOrderRespVO { ...@@ -88,6 +112,10 @@ public class ResourceOrderRespVO {
@ExcelProperty("退款金额") @ExcelProperty("退款金额")
private String refundPrice; private String refundPrice;
@Schema(description = "退款时间(阶段 D 客服标已退款时填写)")
@ExcelProperty("退款时间")
private LocalDateTime refundTime;
@Schema(description = "开票状态:[0]未开 [1]开票中 [2]已开票", example = "1") @Schema(description = "开票状态:[0]未开 [1]开票中 [2]已开票", example = "1")
@ExcelProperty("开票状态:[0]未开 [1]开票中 [2]已开票") @ExcelProperty("开票状态:[0]未开 [1]开票中 [2]已开票")
private Integer invoiceStatus; private Integer invoiceStatus;
......
...@@ -49,6 +49,24 @@ public class ResourceOrderSaveReqVO { ...@@ -49,6 +49,24 @@ public class ResourceOrderSaveReqVO {
@Schema(description = "支付渠道") @Schema(description = "支付渠道")
private String payChannelCode; private String payChannelCode;
@Schema(description = "发货 IP(商家发货时填写)")
private String deliveryIp;
@Schema(description = "发货初始用户名")
private String deliveryUsername;
@Schema(description = "发货初始密码")
private String deliveryPassword;
@Schema(description = "发货时间(也是租赁开始时间)")
private LocalDateTime deliveredTime;
@Schema(description = "发货操作人 ID")
private Long deliverOperatorId;
@Schema(description = "发货操作人姓名(冗余)")
private String deliverOperatorName;
@Schema(description = "租赁开始时间") @Schema(description = "租赁开始时间")
private LocalDateTime rentStartTime; private LocalDateTime rentStartTime;
......
...@@ -4,6 +4,7 @@ import com.luhu.computility.framework.common.pojo.CommonResult; ...@@ -4,6 +4,7 @@ import com.luhu.computility.framework.common.pojo.CommonResult;
import com.luhu.computility.framework.common.pojo.PageResult; import com.luhu.computility.framework.common.pojo.PageResult;
import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderCreateReqVO; import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderCreateReqVO;
import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderCreateRespVO; import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderCreateRespVO;
import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderDeliveryInfoRespVO;
import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderPageReqVO; import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderPageReqVO;
import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderRespVO; import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderRespVO;
import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderInvoiceReqVO; import com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderInvoiceReqVO;
...@@ -76,6 +77,21 @@ public class AppResourceOrderController { ...@@ -76,6 +77,21 @@ public class AppResourceOrderController {
return success(orderDetail); return success(orderDetail);
} }
/**
* 阶段 F:独立获取订单发货信息(IP / 用户名 / 密码)
* <p>
* 设计目的:主订单详情接口 AppResourceOrderRespVO 不下发敏感字段(避免传输放大),
* 客户端需要展示发货凭证时调用此接口,订单必须属于当前用户。
*/
@GetMapping("/get-delivery-info")
@Operation(summary = "获得算力资源订单发货信息(仅本人订单)")
@Parameter(name = "id", description = "订单编号", required = true)
public CommonResult<AppResourceOrderDeliveryInfoRespVO> getUserResourceOrderDeliveryInfo(@RequestParam("id") Long id) {
Long userId = getLoginUserId();
AppResourceOrderDeliveryInfoRespVO deliveryInfo = resourceOrderService.getDeliveryInfoForApp(userId, id);
return success(deliveryInfo);
}
@PostMapping("/invoice-request") @PostMapping("/invoice-request")
@Operation(summary = "申请开票") @Operation(summary = "申请开票")
public CommonResult<Boolean> invoiceRequest(@RequestBody AppResourceOrderInvoiceReqVO reqVO) { public CommonResult<Boolean> invoiceRequest(@RequestBody AppResourceOrderInvoiceReqVO reqVO) {
......
package com.luhu.computility.module.compute.controller.app.resourceorder.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "用户 APP - 算力资源订单发货信息 Response VO(独立接口,避免在主订单接口下发敏感字段)")
@Data
public class AppResourceOrderDeliveryInfoRespVO {
@Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long orderId;
@Schema(description = "订单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "X202410110001")
private String orderNo;
@Schema(description = "服务器 IP")
private String deliveryIp;
@Schema(description = "初始用户名")
private String deliveryUsername;
@Schema(description = "初始密码")
private String deliveryPassword;
@Schema(description = "发货时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime deliveredTime;
@Schema(description = "发货操作人姓名", example = "张三")
private String deliverOperatorName;
@Schema(description = "租赁开始时间")
private LocalDateTime rentStartTime;
@Schema(description = "租赁结束时间")
private LocalDateTime rentEndTime;
@Schema(description = "订单状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "6")
private Integer status;
}
...@@ -61,17 +61,14 @@ public class AppResourceOrderRespVO { ...@@ -61,17 +61,14 @@ public class AppResourceOrderRespVO {
@Schema(description = "商品规格 Map(key=configCategory, value=configOption)") @Schema(description = "商品规格 Map(key=configCategory, value=configOption)")
private Map<String, String> specMap; private Map<String, String> specMap;
@Schema(description = "服务器IP", example = "192.168.1.100")
private String ip;
@Schema(description = "服务器所在地", example = "深圳") @Schema(description = "服务器所在地", example = "深圳")
private String location; private String location;
@Schema(description = "服务器用户名", example = "root") @Schema(description = "发货时间")
private String initUsername; private LocalDateTime deliveredTime;
@Schema(description = "服务器密码", example = "password123") @Schema(description = "退款时间(阶段 D 客服标已退款时填写)")
private String initPassword; private LocalDateTime refundTime;
@Schema(description = "备注", example = "高性能GPU服务器,适合AI训练") @Schema(description = "备注", example = "高性能GPU服务器,适合AI训练")
private String remark; private String remark;
......
...@@ -25,8 +25,8 @@ public class AppResourceOrderSnapshotPageReqVO extends PageParam { ...@@ -25,8 +25,8 @@ public class AppResourceOrderSnapshotPageReqVO extends PageParam {
@Schema(description = "SPU名称", example = "GPU服务器A型") @Schema(description = "SPU名称", example = "GPU服务器A型")
private String spuName; private String spuName;
@Schema(description = "服务器IP", example = "192.168.1.100") @Schema(description = "发货 IP(重命名自 ip)", example = "192.168.1.100")
private String ip; private String deliveryIp;
@Schema(description = "租赁天数", example = "7") @Schema(description = "租赁天数", example = "7")
private Integer durationDays; private Integer durationDays;
......
...@@ -30,8 +30,8 @@ public class AppResourceOrderSnapshotRespVO { ...@@ -30,8 +30,8 @@ public class AppResourceOrderSnapshotRespVO {
@Schema(description = "下单时商品规格快照(Map<configCategory, configOption>,JSON 字符串)") @Schema(description = "下单时商品规格快照(Map<configCategory, configOption>,JSON 字符串)")
private String specSnapshot; private String specSnapshot;
@Schema(description = "服务器IP", example = "192.168.1.100") @Schema(description = "发货 IP(重命名自 ip)", example = "192.168.1.100")
private String ip; private String deliveryIp;
@Schema(description = "SPU名称", example = "GPU服务器A型") @Schema(description = "SPU名称", example = "GPU服务器A型")
private String spuName; private String spuName;
......
...@@ -28,21 +28,26 @@ public class AppResourceOrderSnapshotSaveReqVO { ...@@ -28,21 +28,26 @@ public class AppResourceOrderSnapshotSaveReqVO {
@Schema(description = "下单时商品规格快照(Map<configCategory, configOption>,JSON 字符串)") @Schema(description = "下单时商品规格快照(Map<configCategory, configOption>,JSON 字符串)")
private String specSnapshot; private String specSnapshot;
@Schema(description = "服务器位置", requiredMode = Schema.RequiredMode.REQUIRED, example = "长沙") @Schema(description = "服务器位置(不入库,仅用于兼容老 VO 结构)", example = "长沙")
@NotBlank(message = "服务器位置不能为空")
private String location; private String location;
@Schema(description = "服务器IP", example = "192.168.1.100") @Schema(description = "发货 IP(重命名自 ip)", example = "192.168.1.100")
private String ip; private String deliveryIp;
@Schema(description = "服务器初始用户名", example = "root") @Schema(description = "发货用户名(重命名自 initUsername)", example = "root")
private String initUsername; private String deliveryUsername;
@Schema(description = "服务器初始密码", example = "password123") @Schema(description = "发货密码(重命名自 initPassword)", example = "password123")
private String initPassword; private String deliveryPassword;
@Schema(description = "SPU名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "GPU服务器A型") @Schema(description = "发货时间")
@NotBlank(message = "SPU名称不能为空") private LocalDateTime deliveredTime;
@Schema(description = "SPU名称", example = "GPU服务器A型")
// 注意:阶段 C 起不再强制必填。原因:发货时 upsertOrderSnapshotOnDelivery(ResourceOrderServiceImpl#upsertOrderSnapshotOnDelivery)
// - if 分支从 order.spuName 赋值,若老订单该字段为 null 也不应阻塞发货
// - else 分支仅 set 发货字段,spuName 保留 snapshot 原值
// - 数据库 spu_name 列允许 NULL
private String spuName; private String spuName;
@Schema(description = "租赁天数", requiredMode = Schema.RequiredMode.REQUIRED, example = "7") @Schema(description = "租赁天数", requiredMode = Schema.RequiredMode.REQUIRED, example = "7")
......
...@@ -76,6 +76,30 @@ public class ResourceOrderDO extends BaseDO { ...@@ -76,6 +76,30 @@ public class ResourceOrderDO extends BaseDO {
*/ */
private String payChannelCode; private String payChannelCode;
/** /**
* 发货 IP(商家发货时填写)
*/
private String deliveryIp;
/**
* 发货初始用户名
*/
private String deliveryUsername;
/**
* 发货初始密码
*/
private String deliveryPassword;
/**
* 发货时间(也是租赁开始时间)
*/
private LocalDateTime deliveredTime;
/**
* 发货操作人 ID
*/
private Long deliverOperatorId;
/**
* 发货操作人姓名(冗余)
*/
private String deliverOperatorName;
/**
* 租赁开始时间 * 租赁开始时间
*/ */
private LocalDateTime rentStartTime; private LocalDateTime rentStartTime;
...@@ -100,6 +124,10 @@ public class ResourceOrderDO extends BaseDO { ...@@ -100,6 +124,10 @@ public class ResourceOrderDO extends BaseDO {
*/ */
private String refundPrice; private String refundPrice;
/** /**
* 退款时间(客服标已退款时填写,阶段 D 新增)
*/
private LocalDateTime refundTime;
/**
* 开票状态:[0]未开 [1]开票中 [2]已开票 * 开票状态:[0]未开 [1]开票中 [2]已开票
*/ */
private Integer invoiceStatus; private Integer invoiceStatus;
......
...@@ -49,19 +49,24 @@ public class ResourceOrderSnapshotDO extends BaseDO { ...@@ -49,19 +49,24 @@ public class ResourceOrderSnapshotDO extends BaseDO {
private String specSnapshot; private String specSnapshot;
/** /**
* 服务器IP地址快照 * 发货 IP(快照,重命名自 ip)
*/ */
private String ip; private String deliveryIp;
/** /**
* 服务器初始用户名快照 * 发货用户名(快照,重命名自 init_username)
*/ */
private String initUsername; private String deliveryUsername;
/** /**
* 服务器初始密码快照 * 发货密码(快照,重命名自 init_password)
*/ */
private String initPassword; private String deliveryPassword;
/**
* 发货时间(快照)
*/
private LocalDateTime deliveredTime;
/** /**
* SPU名称快照 * SPU名称快照
......
...@@ -14,7 +14,7 @@ import com.luhu.computility.module.member.dal.dataobject.user.MemberUserDO; ...@@ -14,7 +14,7 @@ import com.luhu.computility.module.member.dal.dataobject.user.MemberUserDO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import com.luhu.computility.module.compute.controller.admin.resourceorder.vo.*; import com.luhu.computility.module.compute.controller.admin.resourceorder.vo.*;
import static com.luhu.computility.module.compute.enums.ResourceOrderStatus.PAID; import static com.luhu.computility.module.compute.enums.ResourceOrderStatus.PENDING_DELIVERY;
/** /**
* 算力资源订单 Mapper * 算力资源订单 Mapper
...@@ -103,7 +103,7 @@ public interface ResourceOrderMapper extends BaseMapperX<ResourceOrderDO> { ...@@ -103,7 +103,7 @@ public interface ResourceOrderMapper extends BaseMapperX<ResourceOrderDO> {
default List<ResourceOrderRespDTO> getPaidOrderList(LocalDateTime[] timeRange) { default List<ResourceOrderRespDTO> getPaidOrderList(LocalDateTime[] timeRange) {
List<ResourceOrderDO> list = selectList(new LambdaQueryWrapperX<ResourceOrderDO>() List<ResourceOrderDO> list = selectList(new LambdaQueryWrapperX<ResourceOrderDO>()
.eq(ResourceOrderDO::getStatus, PAID.getValue()) .eq(ResourceOrderDO::getStatus, PENDING_DELIVERY.getValue())
.betweenIfPresent(ResourceOrderDO::getCreateTime, timeRange)); .betweenIfPresent(ResourceOrderDO::getCreateTime, timeRange));
return BeanUtil.copyToList(list, ResourceOrderRespDTO.class); return BeanUtil.copyToList(list, ResourceOrderRespDTO.class);
} }
......
...@@ -32,7 +32,7 @@ public interface ResourceOrderSnapshotMapper extends BaseMapperX<ResourceOrderSn ...@@ -32,7 +32,7 @@ public interface ResourceOrderSnapshotMapper extends BaseMapperX<ResourceOrderSn
.eqIfPresent(ResourceOrderSnapshotDO::getOrderId, reqVO.getOrderId()) .eqIfPresent(ResourceOrderSnapshotDO::getOrderId, reqVO.getOrderId())
.eqIfPresent(ResourceOrderSnapshotDO::getPayOrderId, reqVO.getPayOrderId()) .eqIfPresent(ResourceOrderSnapshotDO::getPayOrderId, reqVO.getPayOrderId())
.likeIfPresent(ResourceOrderSnapshotDO::getSpuName, reqVO.getSpuName()) .likeIfPresent(ResourceOrderSnapshotDO::getSpuName, reqVO.getSpuName())
.eqIfPresent(ResourceOrderSnapshotDO::getIp, reqVO.getIp()) .eqIfPresent(ResourceOrderSnapshotDO::getDeliveryIp, reqVO.getDeliveryIp())
.eqIfPresent(ResourceOrderSnapshotDO::getDurationDays, reqVO.getDurationDays()) .eqIfPresent(ResourceOrderSnapshotDO::getDurationDays, reqVO.getDurationDays())
.eqIfPresent(ResourceOrderSnapshotDO::getPaymentPrice, reqVO.getPaymentPrice()) .eqIfPresent(ResourceOrderSnapshotDO::getPaymentPrice, reqVO.getPaymentPrice())
.eqIfPresent(ResourceOrderSnapshotDO::getMarketPrice, reqVO.getMarketPrice()) .eqIfPresent(ResourceOrderSnapshotDO::getMarketPrice, reqVO.getMarketPrice())
......
...@@ -29,7 +29,7 @@ public class ComputeOrderStatisticsApiImpl implements ComputeOrderStatisticsApi ...@@ -29,7 +29,7 @@ public class ComputeOrderStatisticsApiImpl implements ComputeOrderStatisticsApi
public ComputeOrderStatisticsDTO getTodayOrderStatistics(LocalDateTime[] timeRange) { public ComputeOrderStatisticsDTO getTodayOrderStatistics(LocalDateTime[] timeRange) {
try { try {
List<ResourceOrderDO> orders = resourceOrderMapper.selectListByStatusAndCreateTime( List<ResourceOrderDO> orders = resourceOrderMapper.selectListByStatusAndCreateTime(
ResourceOrderStatus.PAID.getValue(), ResourceOrderStatus.PENDING_DELIVERY.getValue(),
timeRange timeRange
); );
......
...@@ -122,6 +122,17 @@ public interface ResourceOrderService { ...@@ -122,6 +122,17 @@ public interface ResourceOrderService {
AppResourceOrderRespVO getUserResourceOrder(Long userId, Long id); AppResourceOrderRespVO getUserResourceOrder(Long userId, Long id);
/** /**
* 获得用户算力资源订单发货信息(阶段 F:独立接口,避免在主订单接口下发敏感字段)
* <p>
* 订单必须属于当前用户;订单状态必须为 DELIVERED;其他状态返回空字段集。
*
* @param userId 用户ID
* @param id 订单ID
* @return 算力资源订单发货信息
*/
com.luhu.computility.module.compute.controller.app.resourceorder.vo.AppResourceOrderDeliveryInfoRespVO getDeliveryInfoForApp(Long userId, Long id);
/**
* 更新开票状态 * 更新开票状态
* *
* @param saveVO 保存信息 * @param saveVO 保存信息
...@@ -171,6 +182,33 @@ public interface ResourceOrderService { ...@@ -171,6 +182,33 @@ public interface ResourceOrderService {
int expireFinishedOrders(LocalDateTime startTime, LocalDateTime endTime); int expireFinishedOrders(LocalDateTime startTime, LocalDateTime endTime);
/** /**
* 商家发货:填写 IP/用户名/密码,订单状态置 DELIVERED,租赁时间生效
*
* @param operatorId 发货操作人 ID
* @param reqVO 发货请求
*/
void deliverOrder(Long operatorId, com.luhu.computility.module.compute.controller.admin.resourceorder.vo.ResourceOrderDeliverReqVO reqVO);
/**
* 客服取消待发货订单(→ PENDING_REFUND)
*
* @param operatorId 客服操作人 ID
* @param orderId 订单 ID
* @param reason 取消原因
*/
void adminCancelOrder(Long operatorId, Long orderId, String reason);
/**
* 客服标记已退款(待退款 → 已退款)
*
* @param operatorId 客服操作人 ID
* @param orderId 订单 ID
* @param refundPrice 退款金额(分,可选;null 表示默认全额 = order.paymentPrice)
* @param refundRemark 退款备注(可选)
*/
void markRefunded(Long operatorId, Long orderId, Long refundPrice, String refundRemark);
/**
* 创建订单硬件配置快照 * 创建订单硬件配置快照
* *
* 在支付成功后调用,保存当时的硬件配置信息,避免后续SKU/SPU变更导致订单详情丢失 * 在支付成功后调用,保存当时的硬件配置信息,避免后续SKU/SPU变更导致订单详情丢失
......
...@@ -7,8 +7,9 @@ import com.luhu.computility.module.compute.controller.app.resourceordersnapshot. ...@@ -7,8 +7,9 @@ import com.luhu.computility.module.compute.controller.app.resourceordersnapshot.
import com.luhu.computility.module.compute.dal.dataobject.resourceordersnapshot.ResourceOrderSnapshotDO; import com.luhu.computility.module.compute.dal.dataobject.resourceordersnapshot.ResourceOrderSnapshotDO;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.List; import java.time.LocalDateTime;
import java.util.Collection; import java.util.Collection;
import java.util.List;
/** /**
* 算力资源订单硬件配置快照 Service 接口 * 算力资源订单硬件配置快照 Service 接口
...@@ -35,6 +36,28 @@ public interface ResourceOrderSnapshotService { ...@@ -35,6 +36,28 @@ public interface ResourceOrderSnapshotService {
void updateOrderSnapshot(@Valid AppResourceOrderSnapshotSaveReqVO updateReqVO); void updateOrderSnapshot(@Valid AppResourceOrderSnapshotSaveReqVO updateReqVO);
/** /**
* 发货时更新订单快照(仅更新发货相关字段,不校验非发货字段)
* <p>
* 与 {@link #updateOrderSnapshot} 的区别:本方法不接收 {@code @Valid} 校验,
* 避免发货时因为其他非发货必填字段(如 orderId/userId/durationDays/paymentPrice/marketPrice)缺失而失败。
*
* @param snapshotId 快照 ID
* @param deliveryIp 服务器 IP
* @param deliveryUsername 初始用户名
* @param deliveryPassword 初始密码
* @param deliveredTime 发货时间
* @param rentStartTime 租赁开始时间
* @param rentEndTime 租赁结束时间
*/
void updateSnapshotOnDelivery(Long snapshotId,
String deliveryIp,
String deliveryUsername,
String deliveryPassword,
LocalDateTime deliveredTime,
LocalDateTime rentStartTime,
LocalDateTime rentEndTime);
/**
* 删除订单硬件配置快照 * 删除订单硬件配置快照
* *
* @param id 编号 * @param id 编号
......
...@@ -14,6 +14,7 @@ import org.springframework.stereotype.Service; ...@@ -14,6 +14,7 @@ import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Collection; import java.util.Collection;
...@@ -54,6 +55,28 @@ public class ResourceOrderSnapshotServiceImpl implements ResourceOrderSnapshotSe ...@@ -54,6 +55,28 @@ public class ResourceOrderSnapshotServiceImpl implements ResourceOrderSnapshotSe
} }
@Override @Override
public void updateSnapshotOnDelivery(Long snapshotId,
String deliveryIp,
String deliveryUsername,
String deliveryPassword,
LocalDateTime deliveredTime,
LocalDateTime rentStartTime,
LocalDateTime rentEndTime) {
// 校验存在
validateOrderSnapshotExists(snapshotId);
// 仅更新发货相关字段(不加 @Valid 校验,避开 orderId/userId/durationDays 等非发货必填字段)
ResourceOrderSnapshotDO updateObj = new ResourceOrderSnapshotDO();
updateObj.setId(snapshotId);
updateObj.setDeliveryIp(deliveryIp);
updateObj.setDeliveryUsername(deliveryUsername);
updateObj.setDeliveryPassword(deliveryPassword);
updateObj.setDeliveredTime(deliveredTime);
updateObj.setRentStartTime(rentStartTime);
updateObj.setRentEndTime(rentEndTime);
resourceOrderSnapshotMapper.updateById(updateObj);
}
@Override
public void deleteOrderSnapshot(Long id) { public void deleteOrderSnapshot(Long id) {
// 校验存在 // 校验存在
validateOrderSnapshotExists(id); validateOrderSnapshotExists(id);
......
...@@ -245,8 +245,8 @@ computility: ...@@ -245,8 +245,8 @@ computility:
-----BEGIN PRIVATE KEY----- -----BEGIN PRIVATE KEY-----
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
-----END PRIVATE KEY----- -----END PRIVATE KEY-----
notify-url-compute: https://ric.admin.lijinqi.com/admin-api/compute/wpgj/notify # 算力资源模块WPGJ回调地址 notify-url-compute: https://favoring-bobtail-jugular.ngrok-free.dev/admin-api/compute/wpgj/notify # 算力资源模块WPGJ回调地址
notify-url-api: https://ric.admin.lijinqi.com/admin-api/apihub/wpgj/notify # APIHub模块WPGJ回调地址 notify-url-api: https://favoring-bobtail-jugular.ngrok-free.dev/admin-api/apihub/wpgj/notify # APIHub模块WPGJ回调地址
notify-url-member: https://favoring-bobtail-jugular.ngrok-free.dev/admin-api/member/wpgj/notify # 会员充值模块WPGJ回调地址 notify-url-member: https://favoring-bobtail-jugular.ngrok-free.dev/admin-api/member/wpgj/notify # 会员充值模块WPGJ回调地址
access-log: # 访问日志的配置项 access-log: # 访问日志的配置项
enable: false enable: false
......
-- 算力资源订单 - 商家发货流程(阶段 A)
-- 库:new_computility
-- 目标:
-- 1. compute_resource_order 加 6 个发货字段
-- 2. compute_resource_order_snapshot 重命名 ip/init_username/init_password 为 delivery_*,
-- 并新增 delivered_time(因旧列对新订单本来就 null,等同冗余,直接重命名避免双套字段)
USE `new_computility`;
-- 1. 订单表加发货字段
ALTER TABLE `compute_resource_order`
ADD COLUMN `delivery_ip` VARCHAR(64) DEFAULT NULL
COMMENT '发货 IP(商家发货时填写)'
AFTER `pay_channel_code`,
ADD COLUMN `delivery_username` VARCHAR(64) DEFAULT NULL
COMMENT '发货初始用户名' AFTER `delivery_ip`,
ADD COLUMN `delivery_password` VARCHAR(128) DEFAULT NULL
COMMENT '发货初始密码' AFTER `delivery_username`,
ADD COLUMN `delivered_time` DATETIME DEFAULT NULL
COMMENT '发货时间(也是租赁开始时间)' AFTER `delivery_password`,
ADD COLUMN `deliver_operator_id` BIGINT DEFAULT NULL
COMMENT '发货操作人 ID' AFTER `delivered_time`,
ADD COLUMN `deliver_operator_name` VARCHAR(64) DEFAULT NULL
COMMENT '发货操作人姓名(冗余)' AFTER `deliver_operator_id`;
-- 2. 订单快照表:重命名旧列 + 新增发货时间
ALTER TABLE `compute_resource_order_snapshot`
CHANGE COLUMN `ip` `delivery_ip` VARCHAR(64) DEFAULT NULL
COMMENT '发货 IP(快照,重命名自 ip)',
CHANGE COLUMN `init_username` `delivery_username` VARCHAR(64) DEFAULT NULL
COMMENT '发货用户名(快照,重命名自 init_username)',
CHANGE COLUMN `init_password` `delivery_password` VARCHAR(128) DEFAULT NULL
COMMENT '发货密码(快照,重命名自 init_password)',
ADD COLUMN `delivered_time` DATETIME DEFAULT NULL
COMMENT '发货时间(快照)' AFTER `delivery_password`;
-- 3. 验证
-- SHOW COLUMNS FROM `compute_resource_order` LIKE 'delivery_%';
-- SHOW COLUMNS FROM `compute_resource_order` LIKE 'deliver%';
-- SHOW COLUMNS FROM `compute_resource_order_snapshot`;
-- 算力资源订单 - 客服人工退款(阶段 D)
-- 库:new_computility
-- 目标:
-- 1. compute_resource_order 加 refund_time 字段(客服标已退款时填写)
-- 2. 字典维护:compute_resource_order_status 加 "待退款=7"(手工维护)
USE `new_computility`;
-- 1. 订单表加 refund_time 字段
ALTER TABLE `compute_resource_order`
ADD COLUMN `refund_time` DATETIME DEFAULT NULL
COMMENT '退款时间(客服标已退款时填写)' AFTER `refund_price`;
-- 2. 验证
-- SHOW COLUMNS FROM `compute_resource_order` LIKE 'refund%';
-- 3. 字典(手工执行)
-- INSERT INTO `system_dict_data` (`dict_type`, `dict_label`, `dict_value`, `sort`, `status`, `remark`)
-- VALUES ('compute_resource_order_status', '待退款', '7', 5, 0, 'PENDING_DELIVERY 取消后等待客服人工退款')
-- ON DUPLICATE KEY UPDATE `dict_label` = VALUES(`dict_label`);
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