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变更导致订单详情丢失
......
...@@ -2,6 +2,7 @@ package com.luhu.computility.module.compute.service.resourceorder; ...@@ -2,6 +2,7 @@ package com.luhu.computility.module.compute.service.resourceorder;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import com.luhu.computility.framework.common.exception.ServiceException; import com.luhu.computility.framework.common.exception.ServiceException;
import com.luhu.computility.framework.common.pojo.PageResult; import com.luhu.computility.framework.common.pojo.PageResult;
...@@ -9,6 +10,7 @@ import com.luhu.computility.framework.common.util.json.JsonUtils; ...@@ -9,6 +10,7 @@ import com.luhu.computility.framework.common.util.json.JsonUtils;
import com.luhu.computility.framework.common.util.object.BeanUtils; import com.luhu.computility.framework.common.util.object.BeanUtils;
import com.luhu.computility.framework.common.util.string.StrUtils; import com.luhu.computility.framework.common.util.string.StrUtils;
import com.luhu.computility.module.compute.config.ResourceOrderProperties; import com.luhu.computility.module.compute.config.ResourceOrderProperties;
import com.luhu.computility.module.compute.controller.admin.resourceorder.vo.ResourceOrderDeliverReqVO;
import com.luhu.computility.module.compute.controller.admin.resourceorder.vo.ResourceOrderPageReqVO; import com.luhu.computility.module.compute.controller.admin.resourceorder.vo.ResourceOrderPageReqVO;
import com.luhu.computility.module.compute.controller.admin.resourceorder.vo.ResourceOrderRespVO; 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.admin.resourceorder.vo.ResourceOrderSaveReqVO;
...@@ -18,15 +20,13 @@ import com.luhu.computility.module.compute.controller.app.resourceordersnapshot. ...@@ -18,15 +20,13 @@ import com.luhu.computility.module.compute.controller.app.resourceordersnapshot.
import com.luhu.computility.module.compute.dal.dataobject.resourceconfig.ResourceConfigDO; import com.luhu.computility.module.compute.dal.dataobject.resourceconfig.ResourceConfigDO;
import com.luhu.computility.module.compute.dal.dataobject.resourceorder.ResourceOrderDO; 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.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.dataobject.resourceordersnapshot.ResourceOrderSnapshotDO;
import com.luhu.computility.module.compute.dal.dataobject.resourcespuspecvalue.ResourceSpuSpecValueDO; import com.luhu.computility.module.compute.dal.dataobject.resourcespuspecvalue.ResourceSpuSpecValueDO;
import com.luhu.computility.module.compute.dal.mysql.resourceorder.ResourceOrderMapper; 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.dal.redis.no.ResourceOrderNoRedisDAO;
import com.luhu.computility.module.compute.enums.ResourceOrderInvoiceStatus; import com.luhu.computility.module.compute.enums.ResourceOrderInvoiceStatus;
import com.luhu.computility.module.compute.enums.ResourceOrderRefundStatus;
import com.luhu.computility.module.compute.enums.ResourceOrderStatus; import com.luhu.computility.module.compute.enums.ResourceOrderStatus;
import com.luhu.computility.module.compute.enums.ResourceSkuStatus;
import com.luhu.computility.module.compute.enums.ResourceSpuStatus;
import com.luhu.computility.module.compute.service.resourcecategory.ResourceCategoryService; import com.luhu.computility.module.compute.service.resourcecategory.ResourceCategoryService;
import com.luhu.computility.module.compute.service.resourceconfig.ResourceConfigService; import com.luhu.computility.module.compute.service.resourceconfig.ResourceConfigService;
import com.luhu.computility.module.compute.service.resourcesku.ResourceSkuService; import com.luhu.computility.module.compute.service.resourcesku.ResourceSkuService;
...@@ -48,8 +48,8 @@ import com.luhu.computility.module.pay.enums.OrderBusinessTypeEnum; ...@@ -48,8 +48,8 @@ import com.luhu.computility.module.pay.enums.OrderBusinessTypeEnum;
import com.luhu.computility.module.pay.enums.order.PayOrderStatusEnum; import com.luhu.computility.module.pay.enums.order.PayOrderStatusEnum;
import com.luhu.computility.module.pay.framework.pay.core.client.impl.wpgj.WpgjPayProperties; import com.luhu.computility.module.pay.framework.pay.core.client.impl.wpgj.WpgjPayProperties;
import com.luhu.computility.module.pay.service.order.PayOrderService; import com.luhu.computility.module.pay.service.order.PayOrderService;
import com.luhu.computility.module.compute.dal.mysql.resourcespu.ResourceSpuMapper; import com.luhu.computility.module.system.api.user.AdminUserApi;
import com.luhu.computility.module.compute.dal.mysql.resourcesku.ResourceSkuMapper; import com.luhu.computility.module.system.api.user.dto.AdminUserRespDTO;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
...@@ -115,12 +115,6 @@ public class ResourceOrderServiceImpl implements ResourceOrderService { ...@@ -115,12 +115,6 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
private WpgjPayProperties wpgjPayProperties; private WpgjPayProperties wpgjPayProperties;
@Resource @Resource
private ResourceSpuMapper resourceSpuMapper;
@Resource
private ResourceSkuMapper resourceSkuMapper;
@Resource
private ResourceOrderSnapshotService resourceOrderSnapshotService; private ResourceOrderSnapshotService resourceOrderSnapshotService;
@Resource @Resource
...@@ -129,6 +123,9 @@ public class ResourceOrderServiceImpl implements ResourceOrderService { ...@@ -129,6 +123,9 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
@Resource @Resource
private ResourceConfigService resourceConfigService; private ResourceConfigService resourceConfigService;
@Resource
private AdminUserApi adminUserApi;
@Override @Override
public Long createResourceOrder(ResourceOrderSaveReqVO createReqVO) { public Long createResourceOrder(ResourceOrderSaveReqVO createReqVO) {
// 插入 // 插入
...@@ -231,9 +228,9 @@ public class ResourceOrderServiceImpl implements ResourceOrderService { ...@@ -231,9 +228,9 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
order.setRefundStatus(NOT_REFUND.getValue()); order.setRefundStatus(NOT_REFUND.getValue());
order.setInvoiceStatus(UNINVOICE.getValue()); order.setInvoiceStatus(UNINVOICE.getValue());
order.setUserIp(getClientIP()); order.setUserIp(getClientIP());
order.setRentStartTime(LocalDateTime.now()); // 阶段 B:租赁开始/结束时间在发货时设置(阶段 C),下单时置 null
// 设置租赁结束时间 order.setRentStartTime(null);
order.setRentEndTime(LocalDateTime.now().plusDays(sku.getDurationDays())); order.setRentEndTime(null);
return order; return order;
} }
...@@ -271,7 +268,7 @@ public class ResourceOrderServiceImpl implements ResourceOrderService { ...@@ -271,7 +268,7 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
// 1.1 校验算力资源订单是否存在 // 1.1 校验算力资源订单是否存在
ResourceOrderDO order = validateResourceOrderExists(orderId); ResourceOrderDO order = validateResourceOrderExists(orderId);
// 1.2 校验算力资源订单已支付 // 1.2 校验算力资源订单已支付
if (ResourceOrderStatus.PAID.getValue() == order.getStatus()) { if (ResourceOrderStatus.PENDING_DELIVERY.getValue() == order.getStatus()) {
// 特殊:支付单号相同,直接返回,说明重复回调 // 特殊:支付单号相同,直接返回,说明重复回调
if (Objects.equals(order.getPayOrderId(), payOrderId)) { if (Objects.equals(order.getPayOrderId(), payOrderId)) {
log.warn("[updateOrderPaid][order({}) 已支付,且支付单号相同({}),直接返回]", order, payOrderId); log.warn("[updateOrderPaid][order({}) 已支付,且支付单号相同({}),直接返回]", order, payOrderId);
...@@ -287,7 +284,7 @@ public class ResourceOrderServiceImpl implements ResourceOrderService { ...@@ -287,7 +284,7 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
// 3. 更新算力资源订单状态为已支付 // 3. 更新算力资源订单状态为已支付
ResourceOrderDO updateOrder = new ResourceOrderDO(); ResourceOrderDO updateOrder = new ResourceOrderDO();
updateOrder.setId(orderId); updateOrder.setId(orderId);
updateOrder.setStatus(ResourceOrderStatus.PAID.getValue()); updateOrder.setStatus(ResourceOrderStatus.PENDING_DELIVERY.getValue());
updateOrder.setPayTime(LocalDateTime.now()); updateOrder.setPayTime(LocalDateTime.now());
resourceOrderMapper.updateById(updateOrder); resourceOrderMapper.updateById(updateOrder);
...@@ -306,20 +303,60 @@ public class ResourceOrderServiceImpl implements ResourceOrderService { ...@@ -306,20 +303,60 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
throw exception(RESOURCE_ORDER_NOT_BELONGS_TO_USER); throw exception(RESOURCE_ORDER_NOT_BELONGS_TO_USER);
} }
// 校验订单状态 // 校验订单状态:UNPAID / PENDING_DELIVERY 可取消
if (!order.getStatus().equals(ResourceOrderStatus.UNPAID.getValue())) { Integer status = order.getStatus();
throw exception(RESOURCE_ORDER_STATUS_NOT_UNPAID); boolean isUnpaid = Objects.equals(status, ResourceOrderStatus.UNPAID.getValue());
boolean isPendingDelivery = Objects.equals(status, ResourceOrderStatus.PENDING_DELIVERY.getValue());
if (!isUnpaid && !isPendingDelivery) {
throw exception(RESOURCE_ORDER_STATUS_NOT_CANCELABLE);
} }
// 更新订单状态 // 更新订单状态:
// UNPAID 取消 → CANCELED(3)(无支付,无需退款)
// PENDING_DELIVERY 取消 → PENDING_REFUND(7)(已支付,等待客服人工退款)
ResourceOrderDO updateOrder = new ResourceOrderDO(); ResourceOrderDO updateOrder = new ResourceOrderDO();
updateOrder.setId(orderId); updateOrder.setId(orderId);
updateOrder.setStatus(ResourceOrderStatus.CANCELED.getValue()); updateOrder.setStatus(isPendingDelivery
? ResourceOrderStatus.PENDING_REFUND.getValue()
: ResourceOrderStatus.CANCELED.getValue());
updateOrder.setCancelTime(LocalDateTime.now()); updateOrder.setCancelTime(LocalDateTime.now());
// refund_status 字段保持 NOT_REFUND(0),等客服标"已退款"时才改 REFUNDED
resourceOrderMapper.updateById(updateOrder); resourceOrderMapper.updateById(updateOrder);
} }
@Override
public AppResourceOrderDeliveryInfoRespVO getDeliveryInfoForApp(Long userId, Long orderId) {
// 1. 校验订单存在
ResourceOrderDO order = resourceOrderMapper.selectById(orderId);
if (order == null) {
throw exception(RESOURCE_ORDER_NOT_EXISTS);
}
// 2. 校验订单属于该用户
if (!Objects.equals(order.getUserId(), userId)) {
throw exception(RESOURCE_ORDER_NOT_BELONGS_TO_USER);
}
// 3. 组装响应(非 DELIVERED 状态仅返回订单基础信息,发货字段为 null)
AppResourceOrderDeliveryInfoRespVO respVO = new AppResourceOrderDeliveryInfoRespVO();
respVO.setOrderId(order.getId());
respVO.setOrderNo(order.getOrderNo());
respVO.setStatus(order.getStatus());
respVO.setRentStartTime(order.getRentStartTime());
respVO.setRentEndTime(order.getRentEndTime());
// 4. 仅当订单已发货才下发敏感字段
if (Objects.equals(order.getStatus(), ResourceOrderStatus.DELIVERED.getValue())) {
respVO.setDeliveryIp(order.getDeliveryIp());
respVO.setDeliveryUsername(order.getDeliveryUsername());
respVO.setDeliveryPassword(order.getDeliveryPassword());
respVO.setDeliveredTime(order.getDeliveredTime());
respVO.setDeliverOperatorName(order.getDeliverOperatorName());
}
return respVO;
}
/** /**
* 生成订单编号 * 生成订单编号
*/ */
...@@ -381,14 +418,13 @@ public class ResourceOrderServiceImpl implements ResourceOrderService { ...@@ -381,14 +418,13 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
ResourceOrderSnapshotDO snapshot = resourceOrderSnapshotService.getOrderSnapshotByOrderId(order.getId()); ResourceOrderSnapshotDO snapshot = resourceOrderSnapshotService.getOrderSnapshotByOrderId(order.getId());
if (snapshot != null) { if (snapshot != null) {
// 从快照中读取硬件配置(优先级更高) // 从快照中读取硬件配置(优先级更高)
respVO.setSpuName(snapshot.getSpuName()); respVO.setSpuName(snapshot.getSpuName());
respVO.setPaymentPrice(snapshot.getPaymentPrice()); respVO.setPaymentPrice(snapshot.getPaymentPrice());
respVO.setIp(snapshot.getIp()); // 读快照 JSON 解析为 specMap
// 读快照 JSON 解析为 specMap if (snapshot.getSpecSnapshot() != null) {
if (snapshot.getSpecSnapshot() != null) { respVO.setSpecMap(JSONUtil.toBean(snapshot.getSpecSnapshot(), Map.class));
respVO.setSpecMap(JSONUtil.toBean(snapshot.getSpecSnapshot(), Map.class)); }
} respVO.setSkuName(snapshot.getSpuName() + " - " + snapshot.getDurationDays() + "天");
respVO.setSkuName(snapshot.getSpuName() + " - " + snapshot.getDurationDays() + "天");
// 快照中没有的字段(分类、位置)需要从SPU获取 // 快照中没有的字段(分类、位置)需要从SPU获取
ResourceSkuDO sku = resourceSkuService.getResourceSku(order.getSkuId()); ResourceSkuDO sku = resourceSkuService.getResourceSku(order.getSkuId());
...@@ -452,9 +488,6 @@ public class ResourceOrderServiceImpl implements ResourceOrderService { ...@@ -452,9 +488,6 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
if (snapshot != null) { if (snapshot != null) {
// 从快照中读取硬件配置(优先级更高) // 从快照中读取硬件配置(优先级更高)
respVO.setSpuName(snapshot.getSpuName()); respVO.setSpuName(snapshot.getSpuName());
respVO.setIp(snapshot.getIp());
respVO.setInitUsername(snapshot.getInitUsername());
respVO.setInitPassword(snapshot.getInitPassword());
// 读快照 JSON 解析为 specMap // 读快照 JSON 解析为 specMap
if (snapshot.getSpecSnapshot() != null) { if (snapshot.getSpecSnapshot() != null) {
respVO.setSpecMap(JSONUtil.toBean(snapshot.getSpecSnapshot(), Map.class)); respVO.setSpecMap(JSONUtil.toBean(snapshot.getSpecSnapshot(), Map.class));
...@@ -502,8 +535,8 @@ public class ResourceOrderServiceImpl implements ResourceOrderService { ...@@ -502,8 +535,8 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
@Override @Override
public boolean updateInvoice(ResourceOrderSaveReqVO saveVO) { public boolean updateInvoice(ResourceOrderSaveReqVO saveVO) {
ResourceOrderDO order = resourceOrderMapper.selectById(saveVO.getId()); ResourceOrderDO order = resourceOrderMapper.selectById(saveVO.getId());
if (!Objects.equals(order.getStatus(), ResourceOrderStatus.PAID.getValue())) { if (!Objects.equals(order.getStatus(), ResourceOrderStatus.DELIVERED.getValue())) {
throw new ServiceException("只有已支付的订单可以开票!"); throw new ServiceException("只有已发货的订单可以开票!");
} }
order.setInvoiceStatus(ResourceOrderInvoiceStatus.INVOICED.getValue()); order.setInvoiceStatus(ResourceOrderInvoiceStatus.INVOICED.getValue());
order.setInvoiceUrl(saveVO.getInvoiceUrl()); order.setInvoiceUrl(saveVO.getInvoiceUrl());
...@@ -637,7 +670,7 @@ public class ResourceOrderServiceImpl implements ResourceOrderService { ...@@ -637,7 +670,7 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
ResourceOrderDO order = validateResourceOrderExists(orderId); ResourceOrderDO order = validateResourceOrderExists(orderId);
// 2. 校验订单状态,避免重复处理 // 2. 校验订单状态,避免重复处理
if (ResourceOrderStatus.PAID.getValue() == order.getStatus()) { if (ResourceOrderStatus.PENDING_DELIVERY.getValue() == order.getStatus()) {
log.warn("[updateOrderPaidByWpgj] 订单已经是支付状态,订单ID: {}", orderId); log.warn("[updateOrderPaidByWpgj] 订单已经是支付状态,订单ID: {}", orderId);
return; return;
} }
...@@ -663,7 +696,7 @@ public class ResourceOrderServiceImpl implements ResourceOrderService { ...@@ -663,7 +696,7 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
// 4. 更新算力资源订单状态为已支付 // 4. 更新算力资源订单状态为已支付
ResourceOrderDO updateResourceOrder = new ResourceOrderDO(); ResourceOrderDO updateResourceOrder = new ResourceOrderDO();
updateResourceOrder.setId(orderId); updateResourceOrder.setId(orderId);
updateResourceOrder.setStatus(ResourceOrderStatus.PAID.getValue()); updateResourceOrder.setStatus(ResourceOrderStatus.PENDING_DELIVERY.getValue());
updateResourceOrder.setPayTime(LocalDateTime.now()); updateResourceOrder.setPayTime(LocalDateTime.now());
//更新支付订单状态为已支付 //更新支付订单状态为已支付
...@@ -676,13 +709,7 @@ public class ResourceOrderServiceImpl implements ResourceOrderService { ...@@ -676,13 +709,7 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
resourceOrderMapper.updateById(updateResourceOrder); resourceOrderMapper.updateById(updateResourceOrder);
payOrderWpgjMapper.updateById(updatePayOrder); payOrderWpgjMapper.updateById(updatePayOrder);
// 5. SPU被购买后,自动下架该SPU下的所有SKU并增加销量 // 阶段 B:支付成功后不再自动下架 SPU/SKU(资源按需采购,订单履约不影响商品上下架)
try {
handleSpuPurchaseAfterPayment(order);
} 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()); orderId, notifyDTO.getOrderId());
...@@ -694,43 +721,6 @@ public class ResourceOrderServiceImpl implements ResourceOrderService { ...@@ -694,43 +721,6 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
} }
} }
/**
* SPU被购买后,自动下架该SPU下的所有SKU并增加销量
*/
private void handleSpuPurchaseAfterPayment(ResourceOrderDO order) {
// 仅当订单包含 SKU 时才处理
if (order.getSkuId() == null) {
return;
}
ResourceSkuDO sku = resourceSkuService.getResourceSku(order.getSkuId());
if (sku == null) {
log.warn("[handleSpuPurchaseAfterPayment] SKU 不存在, skuId={}", order.getSkuId());
return;
}
Long spuId = sku.getSpuId();
if (spuId == null) {
log.warn("[handleSpuPurchaseAfterPayment] SKU 未绑定 SPU, skuId={}", sku.getId());
return;
}
// 下架该 SPU 下所有 SKU
resourceSkuMapper.updateStatusBySpuId(spuId, ResourceSkuStatus.OFFLINE.getValue());
// 增加SPU销量
ResourceSpuRespVO spu = resourceSpuService.getResourceSpu(spuId);
if (spu != null) {
ResourceSpuDO updateSpu = new ResourceSpuDO();
updateSpu.setId(spuId);
updateSpu.setSales((spu.getSales() != null ? spu.getSales() : 0) + 1);
resourceSpuMapper.updateById(updateSpu);
}
log.info("[handleSpuPurchaseAfterPayment] SPU被购买后,已下架该SPU下的所有SKU并增加销量,spuId={}", spuId);
}
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void updateOrderFailedByWpgj(Long orderId, WpgjPayNotifyDTO notifyDTO) { public void updateOrderFailedByWpgj(Long orderId, WpgjPayNotifyDTO notifyDTO) {
...@@ -778,7 +768,7 @@ public class ResourceOrderServiceImpl implements ResourceOrderService { ...@@ -778,7 +768,7 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
// 查询指定时间范围内到期的已支付订单 // 查询指定时间范围内到期的已支付订单
List<ResourceOrderDO> expiredOrders = resourceOrderMapper.selectListByRentEndTimeBetweenAndStatus( List<ResourceOrderDO> expiredOrders = resourceOrderMapper.selectListByRentEndTimeBetweenAndStatus(
startTime, endTime, ResourceOrderStatus.PAID.getValue()); startTime, endTime, ResourceOrderStatus.DELIVERED.getValue());
if (CollUtil.isEmpty(expiredOrders)) { if (CollUtil.isEmpty(expiredOrders)) {
log.info("[expireFinishedOrders] 没有找到到期的算力资源订单"); log.info("[expireFinishedOrders] 没有找到到期的算力资源订单");
...@@ -796,20 +786,7 @@ public class ResourceOrderServiceImpl implements ResourceOrderService { ...@@ -796,20 +786,7 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
int updateCount = resourceOrderMapper.updateById(updateOrder); int updateCount = resourceOrderMapper.updateById(updateOrder);
if (updateCount > 0) { if (updateCount > 0) {
count++; count++;
// 阶段 B:到期不再联动 SPU 状态(资源按需采购,订单到期不影响商品上下架)
// 同时更新对应的SPU状态为回收
if (order.getSkuId() != null) {
ResourceSkuDO sku = resourceSkuService.getResourceSku(order.getSkuId());
if (sku != null && sku.getSpuId() != null) {
try {
resourceSpuService.updateResourceSpuStatus(sku.getSpuId(), ResourceSpuStatus.RECYCLE.getValue());
log.info("[expireFinishedOrders] SPU状态更新为回收,SPU ID: {}", sku.getSpuId());
} catch (Exception spuEx) {
log.error("[expireFinishedOrders] SPU状态更新失败,SPU ID: {}", sku.getSpuId(), spuEx);
}
}
}
log.info("[expireFinishedOrders] 算力资源订单到期处理成功,订单ID: {}, 订单号: {}", log.info("[expireFinishedOrders] 算力资源订单到期处理成功,订单ID: {}, 订单号: {}",
order.getId(), order.getOrderNo()); order.getId(), order.getOrderNo());
} else { } else {
...@@ -882,4 +859,164 @@ public class ResourceOrderServiceImpl implements ResourceOrderService { ...@@ -882,4 +859,164 @@ public class ResourceOrderServiceImpl implements ResourceOrderService {
} }
} }
@Override
@Transactional(rollbackFor = Exception.class)
public void deliverOrder(Long operatorId, ResourceOrderDeliverReqVO reqVO) {
// 1. 校验订单
ResourceOrderDO order = validateResourceOrderExists(reqVO.getOrderId());
if (!Objects.equals(order.getStatus(), ResourceOrderStatus.PENDING_DELIVERY.getValue())) {
throw exception(RESOURCE_ORDER_STATUS_NOT_PENDING_DELIVERY);
}
if (StrUtil.hasBlank(reqVO.getDeliveryIp(), reqVO.getDeliveryUsername(), reqVO.getDeliveryPassword())) {
throw exception(RESOURCE_ORDER_DELIVERY_FIELDS_REQUIRED);
}
// 2. 取租赁天数
Integer durationDays = getDurationDaysFromSku(order.getSkuId());
if (durationDays == null) {
throw exception(RESOURCE_ORDER_SKU_NOT_EXISTS);
}
// 3. 算租赁时间
LocalDateTime now = LocalDateTime.now();
// 4. 写订单
ResourceOrderDO updateOrder = new ResourceOrderDO();
updateOrder.setId(order.getId());
updateOrder.setStatus(ResourceOrderStatus.DELIVERED.getValue());
updateOrder.setDeliveryIp(reqVO.getDeliveryIp());
updateOrder.setDeliveryUsername(reqVO.getDeliveryUsername());
updateOrder.setDeliveryPassword(reqVO.getDeliveryPassword());
updateOrder.setDeliveredTime(now);
updateOrder.setRentStartTime(now);
updateOrder.setRentEndTime(now.plusDays(durationDays));
updateOrder.setDeliverOperatorId(operatorId);
updateOrder.setDeliverOperatorName(getOperatorName(operatorId));
resourceOrderMapper.updateById(updateOrder);
// 5. 写/更新快照(如果快照不存在则创建)
upsertOrderSnapshotOnDelivery(order, updateOrder);
// 6. 触发短信通知(Part 3 实现,本期先 TODO)
// smsNotifyService.notifyDelivery(order, updateOrder);
log.info("[deliverOrder] 发货成功 orderId={}, ip={}, durationDays={}",
order.getId(), reqVO.getDeliveryIp(), durationDays);
}
/**
* 发货时 upsert 订单快照:首次发货则创建,否则更新发货字段
*/
private void upsertOrderSnapshotOnDelivery(ResourceOrderDO order, ResourceOrderDO updateOrder) {
ResourceOrderSnapshotDO snapshot = resourceOrderSnapshotService.getOrderSnapshotByOrderId(order.getId());
if (snapshot == null) {
// 快照不存在(极端情况:支付成功但快照创建失败),这里按 order 已有信息补建一份
AppResourceOrderSnapshotSaveReqVO createReqVO = new AppResourceOrderSnapshotSaveReqVO();
createReqVO.setOrderId(order.getId());
createReqVO.setUserId(order.getUserId());
createReqVO.setPayOrderId(order.getPayOrderId());
createReqVO.setDeliveryIp(updateOrder.getDeliveryIp());
createReqVO.setDeliveryUsername(updateOrder.getDeliveryUsername());
createReqVO.setDeliveryPassword(updateOrder.getDeliveryPassword());
createReqVO.setDeliveredTime(updateOrder.getDeliveredTime());
createReqVO.setRentStartTime(updateOrder.getRentStartTime());
createReqVO.setRentEndTime(updateOrder.getRentEndTime());
createReqVO.setPaymentPrice(order.getPaymentPrice());
createReqVO.setMarketPrice(order.getMarketPrice());
createReqVO.setSpuName(order.getSpuName());
// 走 SKU 拿 durationDays(location 不再进库,VO 端也去掉了 @NotBlank)
ResourceSkuDO sku = resourceSkuService.getResourceSku(order.getSkuId());
if (sku != null) {
createReqVO.setDurationDays(sku.getDurationDays());
}
resourceOrderSnapshotService.createOrderSnapshot(createReqVO);
} else {
// 快照已存在,仅更新发货相关字段。
// 注意:不能用 updateOrderSnapshot(AppResourceOrderSnapshotSaveReqVO),因为 @Valid 会校验
// orderId/userId/durationDays/paymentPrice/marketPrice 等必填字段,update 场景根本不需要传这些。
// 改用专门的 updateSnapshotOnDelivery 方法(不写 @Valid),仅更新发货字段。
resourceOrderSnapshotService.updateSnapshotOnDelivery(
snapshot.getId(),
updateOrder.getDeliveryIp(),
updateOrder.getDeliveryUsername(),
updateOrder.getDeliveryPassword(),
updateOrder.getDeliveredTime(),
updateOrder.getRentStartTime(),
updateOrder.getRentEndTime());
}
}
/**
* 读取操作员昵称
*/
private String getOperatorName(Long operatorId) {
if (operatorId == null) {
return "未知操作员";
}
try {
AdminUserRespDTO user = adminUserApi.getUser(operatorId);
return user != null ? user.getNickname() : "未知操作员";
} catch (Exception e) {
log.warn("[getOperatorName] 读取操作员昵称失败 operatorId={}", operatorId, e);
return "未知操作员";
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void adminCancelOrder(Long operatorId, Long orderId, String reason) {
// 1. 校验订单
ResourceOrderDO order = validateResourceOrderExists(orderId);
if (!Objects.equals(order.getStatus(), ResourceOrderStatus.PENDING_DELIVERY.getValue())) {
throw exception(RESOURCE_ORDER_STATUS_NOT_PENDING_DELIVERY);
}
if (StrUtil.hasBlank(reason)) {
throw exception(RESOURCE_ORDER_ADMIN_CANCEL_REASON_REQUIRED);
}
// 2. 写订单:PENDING_DELIVERY → PENDING_REFUND,备注写取消原因
ResourceOrderDO updateOrder = new ResourceOrderDO();
updateOrder.setId(orderId);
updateOrder.setStatus(ResourceOrderStatus.PENDING_REFUND.getValue());
updateOrder.setCancelTime(LocalDateTime.now());
updateOrder.setRemark(reason);
resourceOrderMapper.updateById(updateOrder);
log.info("[adminCancelOrder] 客服取消订单 orderId={}, operatorId={}, reason={}",
orderId, operatorId, reason);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void markRefunded(Long operatorId, Long orderId, Long refundPrice, String refundRemark) {
// 1. 校验订单
ResourceOrderDO order = validateResourceOrderExists(orderId);
if (!Objects.equals(order.getStatus(), ResourceOrderStatus.PENDING_REFUND.getValue())) {
throw exception(RESOURCE_ORDER_STATUS_NOT_PENDING_REFUND);
}
// refundPrice 可选:null / 0 表示默认按订单支付金额全额退款
Long finalRefundPrice = (refundPrice == null || refundPrice == 0) ? order.getPaymentPrice() : refundPrice;
if (finalRefundPrice == null || finalRefundPrice < 0) {
throw exception(RESOURCE_ORDER_REFUND_PRICE_INVALID);
}
// 2. 写订单:PENDING_REFUND → REFUNDED
ResourceOrderDO updateOrder = new ResourceOrderDO();
updateOrder.setId(orderId);
updateOrder.setStatus(ResourceOrderStatus.REFUNDED.getValue());
updateOrder.setRefundStatus(ResourceOrderRefundStatus.REFUNDED.getValue());
updateOrder.setRefundPrice(String.valueOf(finalRefundPrice));
updateOrder.setRefundTime(LocalDateTime.now());
if (StrUtil.isNotBlank(refundRemark)) {
// 退款备注追加到 remark 字段(用「;」分隔,避免覆盖客服取消原因)
String oldRemark = order.getRemark();
String newRemark = StrUtil.isBlank(oldRemark) ? refundRemark : oldRemark + ";" + refundRemark;
updateOrder.setRemark(newRemark);
}
resourceOrderMapper.updateById(updateOrder);
log.info("[markRefunded] 客服标记已退款 orderId={}, operatorId={}, refundPrice={}",
orderId, operatorId, finalRefundPrice);
}
} }
...@@ -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