# Design Document: 订单系统迁移 ## Overview 本设计文档描述将PHP订单系统迁移到.NET 8的技术方案。订单系统是抽奖盲盒平台的核心业务模块,涉及订单金额计算、订单创建支付、订单查询管理、仓库/盒柜管理等功能。 ## Architecture ### 系统架构 ``` ┌─────────────────────────────────────────────────────────────┐ │ API Layer │ │ ┌─────────────────┐ ┌─────────────────┐ │ │ │ OrderController │ │WarehouseController│ │ │ └────────┬────────┘ └────────┬────────┘ │ └───────────┼─────────────────────┼───────────────────────────┘ │ │ ┌───────────┼─────────────────────┼───────────────────────────┐ │ ▼ ▼ Service Layer │ │ ┌─────────────────┐ ┌─────────────────┐ │ │ │ OrderService │ │WarehouseService │ │ │ └────────┬────────┘ └────────┬────────┘ │ │ │ │ │ │ ┌────────┴────────┐ ┌────────┴────────┐ │ │ │OrderCalculation │ │ PrizeService │ │ │ │ Service │ │ │ │ │ └─────────────────┘ └─────────────────┘ │ └─────────────────────────────────────────────────────────────┘ │ │ ┌───────────┼─────────────────────┼───────────────────────────┐ │ ▼ ▼ Data Layer │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ HoneyBoxDbContext │ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌───────────┐ │ │ │ │ │ Orders │ │OrderList│ │Delivery │ │ Recovery │ │ │ │ │ └─────────┘ └─────────┘ └─────────┘ └───────────┘ │ │ │ └─────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ ``` ## Components and Interfaces ### 1. OrderController ```csharp [ApiController] [Route("api")] public class OrderController : ControllerBase { // 一番赏订单金额计算 [HttpPost("ordermoney")] Task> CalculateOrderMoney(OrderMoneyRequest request); // 一番赏订单创建 [HttpPost("orderbuy")] Task> CreateOrder(OrderBuyRequest request); // 无限赏订单金额计算 [HttpPost("infinite_ordermoney")] Task> CalculateInfiniteOrderMoney(InfiniteOrderMoneyRequest request); // 无限赏订单创建 [HttpPost("infinite_orderbuy")] Task> CreateInfiniteOrder(InfiniteOrderBuyRequest request); // 商城订单金额计算 [HttpPost("mall_ordermoney")] Task> CalculateMallOrderMoney(MallOrderMoneyRequest request); // 订单列表 [HttpPost("order_list")] Task>> GetOrderList(OrderListRequest request); // 订单详情 [HttpPost("order_detail")] Task> GetOrderDetail(OrderDetailRequest request); // 一番赏抽奖结果 [HttpPost("prizeorderlog")] Task>> GetPrizeOrderLog(PrizeOrderLogRequest request); // 无限赏抽奖结果 [HttpPost("infinite_prizeorderlog")] Task>> GetInfinitePrizeOrderLog(PrizeOrderLogRequest request); } ``` ### 2. WarehouseController ```csharp [ApiController] [Route("api")] public class WarehouseController : ControllerBase { // 仓库首页 [HttpPost("warehouse_index")] Task>> GetWarehouseIndex(WarehouseIndexRequest request); // 奖品回收 [HttpPost("warehouse_recovery")] Task> RecoveryPrizes(RecoveryRequest request); // 奖品发货 [HttpPost("warehouse_send")] Task> SendPrizes(SendRequest request); // 确认发货 [HttpPost("warehouse_send_confirm")] Task ConfirmSend(ConfirmSendRequest request); // 发货记录 [HttpPost("warehouse_send_record")] Task>> GetSendRecords(SendRecordRequest request); // 发货记录详情 [HttpPost("warehouse_send_record_detail")] Task> GetSendRecordDetail(SendRecordDetailRequest request); // 回收记录 [HttpPost("warehouse_recovery_record")] Task>> GetRecoveryRecords(RecoveryRecordRequest request); // 物流信息 [HttpPost("warehouse_order_logistics")] Task> GetLogistics(LogisticsRequest request); } ``` ### 3. IOrderService ```csharp public interface IOrderService { // 订单金额计算 Task CalculateOrderMoneyAsync(int userId, OrderMoneyRequest request); Task CalculateInfiniteOrderMoneyAsync(int userId, InfiniteOrderMoneyRequest request); Task CalculateMallOrderMoneyAsync(int userId, MallOrderMoneyRequest request); // 订单创建 Task CreateOrderAsync(int userId, OrderBuyRequest request); Task CreateInfiniteOrderAsync(int userId, InfiniteOrderBuyRequest request); // 订单查询 Task> GetOrderListAsync(int userId, OrderListRequest request); Task GetOrderDetailAsync(int userId, string orderNum); // 抽奖结果 Task> GetPrizeOrderLogAsync(int userId, string orderNum); Task> GetInfinitePrizeOrderLogAsync(int userId, string orderNum); } ``` ### 4. IWarehouseService ```csharp public interface IWarehouseService { // 仓库查询 Task> GetWarehouseIndexAsync(int userId, int page, int status); // 奖品回收 Task RecoveryPrizesAsync(int userId, string orderListIds); // 奖品发货 Task SendPrizesAsync(int userId, SendRequest request); Task ConfirmSendAsync(int userId, int id); // 记录查询 Task> GetSendRecordsAsync(int userId, int page); Task GetSendRecordDetailAsync(int userId, int id); Task> GetRecoveryRecordsAsync(int userId, int page); // 物流查询 Task GetLogisticsAsync(int userId, int id); } ``` ## Data Models ### Request Models ```csharp // 一番赏订单金额计算请求 public class OrderMoneyRequest { [JsonPropertyName("goods_id")] public int GoodsId { get; set; } [JsonPropertyName("num")] public int Num { get; set; } [JsonPropertyName("prize_num")] public int PrizeNum { get; set; } [JsonPropertyName("coupon_id")] public string? CouponId { get; set; } [JsonPropertyName("use_money_is")] public int UseMoneyIs { get; set; } = 2; [JsonPropertyName("use_integral_is")] public int UseIntegralIs { get; set; } = 2; [JsonPropertyName("use_money2_is")] public int UseMoney2Is { get; set; } = 2; } // 无限赏订单金额计算请求 public class InfiniteOrderMoneyRequest { [JsonPropertyName("goods_id")] public int GoodsId { get; set; } [JsonPropertyName("prize_num")] public int PrizeNum { get; set; } [JsonPropertyName("use_money_is")] public int UseMoneyIs { get; set; } = 2; [JsonPropertyName("use_integral_is")] public int UseIntegralIs { get; set; } = 2; [JsonPropertyName("use_money2_is")] public int UseMoney2Is { get; set; } = 2; [JsonPropertyName("coupon_id")] public string? CouponId { get; set; } } // 商城订单金额计算请求 public class MallOrderMoneyRequest { [JsonPropertyName("goods_id")] public int GoodsId { get; set; } [JsonPropertyName("prize_num")] public int PrizeNum { get; set; } [JsonPropertyName("goods_num")] public int GoodsNum { get; set; } [JsonPropertyName("use_money_is")] public int UseMoneyIs { get; set; } = 2; [JsonPropertyName("use_integral_is")] public int UseIntegralIs { get; set; } = 2; [JsonPropertyName("use_money2_is")] public int UseMoney2Is { get; set; } = 2; } // 仓库首页请求 public class WarehouseIndexRequest { [JsonPropertyName("page")] public int Page { get; set; } = 1; [JsonPropertyName("status")] public int Status { get; set; } = 0; } // 发货请求 public class SendRequest { [JsonPropertyName("order_list_ids")] public string OrderListIds { get; set; } = string.Empty; [JsonPropertyName("name")] public string Name { get; set; } = string.Empty; [JsonPropertyName("mobile")] public string Mobile { get; set; } = string.Empty; [JsonPropertyName("address")] public string Address { get; set; } = string.Empty; [JsonPropertyName("message")] public string? Message { get; set; } } ``` ### Response Models ```csharp // 订单金额计算响应 public class OrderCalculationDto { [JsonPropertyName("order_total")] public string OrderTotal { get; set; } = "0.00"; [JsonPropertyName("price")] public string Price { get; set; } = "0.00"; [JsonPropertyName("goods_info")] public GoodsInfoDto? GoodsInfo { get; set; } [JsonPropertyName("goodsExtend")] public GoodsExtendDto? GoodsExtend { get; set; } [JsonPropertyName("user_money")] public string UserMoney { get; set; } = "0.00"; [JsonPropertyName("user_integral")] public string UserIntegral { get; set; } = "0.00"; [JsonPropertyName("user_money2")] public string UserMoney2 { get; set; } = "0.00"; } // 订单创建响应 public class OrderBuyResponseDto { [JsonPropertyName("status")] public int Status { get; set; } [JsonPropertyName("order_num")] public string OrderNum { get; set; } = string.Empty; [JsonPropertyName("res")] public WechatPayParamsDto? Res { get; set; } } // 微信支付参数 public class WechatPayParamsDto { [JsonPropertyName("appId")] public string AppId { get; set; } = string.Empty; [JsonPropertyName("timeStamp")] public string TimeStamp { get; set; } = string.Empty; [JsonPropertyName("nonceStr")] public string NonceStr { get; set; } = string.Empty; [JsonPropertyName("package")] public string Package { get; set; } = string.Empty; [JsonPropertyName("signType")] public string SignType { get; set; } = "RSA"; [JsonPropertyName("paySign")] public string PaySign { get; set; } = string.Empty; } // 订单列表项 public class OrderListDto { [JsonPropertyName("id")] public int Id { get; set; } [JsonPropertyName("order_num")] public string OrderNum { get; set; } = string.Empty; [JsonPropertyName("goods_title")] public string GoodsTitle { get; set; } = string.Empty; [JsonPropertyName("goods_imgurl")] public string GoodsImgUrl { get; set; } = string.Empty; [JsonPropertyName("order_total")] public string OrderTotal { get; set; } = "0.00"; [JsonPropertyName("price")] public string Price { get; set; } = "0.00"; [JsonPropertyName("prize_num")] public int PrizeNum { get; set; } [JsonPropertyName("status")] public int Status { get; set; } [JsonPropertyName("addtime")] public long AddTime { get; set; } [JsonPropertyName("pay_time")] public long? PayTime { get; set; } } // 仓库物品 public class WarehouseItemDto { [JsonPropertyName("id")] public int Id { get; set; } [JsonPropertyName("goodslist_title")] public string GoodsListTitle { get; set; } = string.Empty; [JsonPropertyName("goodslist_imgurl")] public string GoodsListImgUrl { get; set; } = string.Empty; [JsonPropertyName("goodslist_price")] public string GoodsListPrice { get; set; } = "0.00"; [JsonPropertyName("goodslist_money")] public string GoodsListMoney { get; set; } = "0.00"; [JsonPropertyName("status")] public int Status { get; set; } [JsonPropertyName("addtime")] public long AddTime { get; set; } } ``` ## Correctness Properties *A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.* ### Property 1: 订单金额计算正确性 *For any* order calculation request with valid goods_id and prize_num, the calculated order_total should equal price * prize_num minus any applicable discounts (coupon, balance, integral, money2). **Validates: Requirements 1.1, 1.2, 1.3, 1.4, 1.5** ### Property 2: 订单创建数据完整性 *For any* successfully created order, the order record should contain all required fields (order_num, goods_id, user_id, order_total, status) and the order_num should be unique. **Validates: Requirements 2.1, 2.2** ### Property 3: 仓库物品状态一致性 *For any* warehouse item, after recovery operation, the item status should be updated to recovered (status=1) and the user's balance should increase by the recovery amount. **Validates: Requirements 11.2, 11.3** ### Property 4: 发货记录完整性 *For any* delivery request with valid order_list_ids and address info, a delivery record should be created with all items linked and status set to pending. **Validates: Requirements 12.1, 12.2, 12.3, 12.4** ### Property 5: 订单列表分页正确性 *For any* order list request, the returned data should be correctly paginated and the last_page value should accurately reflect the total number of pages. **Validates: Requirements 6.1, 6.3, 6.4** ## Error Handling ### 订单相关错误 | 错误场景 | 错误码 | 错误消息 | |---------|--------|---------| | 商品不存在 | 0 | 商品不存在 | | 库存不足 | 0 | 库存不足 | | 超出购买限制 | 0 | 超出购买限制 | | 订单不存在 | 0 | 订单不存在 | | 无权访问订单 | 0 | 无权访问该订单 | | 优惠券无效 | 0 | 优惠券无效或已过期 | ### 仓库相关错误 | 错误场景 | 错误码 | 错误消息 | |---------|--------|---------| | 奖品不存在 | 0 | 奖品不存在 | | 奖品不可回收 | 0 | 该奖品不可回收 | | 奖品不可发货 | 0 | 该奖品不可发货 | | 地址信息不完整 | 0 | 请填写完整的收货信息 | | 发货记录不存在 | 0 | 发货记录不存在 | ## Testing Strategy ### 单元测试 - 测试订单金额计算逻辑的各种场景 - 测试优惠券、余额、积分抵扣逻辑 - 测试仓库物品状态转换逻辑 - 测试分页逻辑 ### 属性测试 使用xUnit和FsCheck进行属性测试: - Property 1: 订单金额计算正确性 - Property 2: 订单创建数据完整性 - Property 3: 仓库物品状态一致性 - Property 4: 发货记录完整性 - Property 5: 订单列表分页正确性 ### 集成测试 - 测试完整的订单创建流程 - 测试仓库回收和发货流程 - 测试API响应格式兼容性