17 KiB
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
[ApiController]
[Route("api")]
public class OrderController : ControllerBase
{
// 一番赏订单金额计算
[HttpPost("ordermoney")]
Task<ApiResponse<OrderCalculationDto>> CalculateOrderMoney(OrderMoneyRequest request);
// 一番赏订单创建
[HttpPost("orderbuy")]
Task<ApiResponse<OrderBuyResponseDto>> CreateOrder(OrderBuyRequest request);
// 无限赏订单金额计算
[HttpPost("infinite_ordermoney")]
Task<ApiResponse<OrderCalculationDto>> CalculateInfiniteOrderMoney(InfiniteOrderMoneyRequest request);
// 无限赏订单创建
[HttpPost("infinite_orderbuy")]
Task<ApiResponse<OrderBuyResponseDto>> CreateInfiniteOrder(InfiniteOrderBuyRequest request);
// 商城订单金额计算
[HttpPost("mall_ordermoney")]
Task<ApiResponse<OrderCalculationDto>> CalculateMallOrderMoney(MallOrderMoneyRequest request);
// 订单列表
[HttpPost("order_list")]
Task<ApiResponse<PageResponse<OrderListDto>>> GetOrderList(OrderListRequest request);
// 订单详情
[HttpPost("order_detail")]
Task<ApiResponse<OrderDetailDto>> GetOrderDetail(OrderDetailRequest request);
// 一番赏抽奖结果
[HttpPost("prizeorderlog")]
Task<ApiResponse<List<PrizeOrderLogDto>>> GetPrizeOrderLog(PrizeOrderLogRequest request);
// 无限赏抽奖结果
[HttpPost("infinite_prizeorderlog")]
Task<ApiResponse<List<PrizeOrderLogDto>>> GetInfinitePrizeOrderLog(PrizeOrderLogRequest request);
}
2. WarehouseController
[ApiController]
[Route("api")]
public class WarehouseController : ControllerBase
{
// 仓库首页
[HttpPost("warehouse_index")]
Task<ApiResponse<PageResponse<WarehouseItemDto>>> GetWarehouseIndex(WarehouseIndexRequest request);
// 奖品回收
[HttpPost("warehouse_recovery")]
Task<ApiResponse<RecoveryResultDto>> RecoveryPrizes(RecoveryRequest request);
// 奖品发货
[HttpPost("warehouse_send")]
Task<ApiResponse<SendResultDto>> SendPrizes(SendRequest request);
// 确认发货
[HttpPost("warehouse_send_confirm")]
Task<ApiResponse> ConfirmSend(ConfirmSendRequest request);
// 发货记录
[HttpPost("warehouse_send_record")]
Task<ApiResponse<PageResponse<SendRecordDto>>> GetSendRecords(SendRecordRequest request);
// 发货记录详情
[HttpPost("warehouse_send_record_detail")]
Task<ApiResponse<SendRecordDetailDto>> GetSendRecordDetail(SendRecordDetailRequest request);
// 回收记录
[HttpPost("warehouse_recovery_record")]
Task<ApiResponse<PageResponse<RecoveryRecordDto>>> GetRecoveryRecords(RecoveryRecordRequest request);
// 物流信息
[HttpPost("warehouse_order_logistics")]
Task<ApiResponse<LogisticsDto>> GetLogistics(LogisticsRequest request);
}
3. IOrderService
public interface IOrderService
{
// 订单金额计算
Task<OrderCalculationDto> CalculateOrderMoneyAsync(int userId, OrderMoneyRequest request);
Task<OrderCalculationDto> CalculateInfiniteOrderMoneyAsync(int userId, InfiniteOrderMoneyRequest request);
Task<OrderCalculationDto> CalculateMallOrderMoneyAsync(int userId, MallOrderMoneyRequest request);
// 订单创建
Task<OrderBuyResponseDto> CreateOrderAsync(int userId, OrderBuyRequest request);
Task<OrderBuyResponseDto> CreateInfiniteOrderAsync(int userId, InfiniteOrderBuyRequest request);
// 订单查询
Task<PageResponse<OrderListDto>> GetOrderListAsync(int userId, OrderListRequest request);
Task<OrderDetailDto> GetOrderDetailAsync(int userId, string orderNum);
// 抽奖结果
Task<List<PrizeOrderLogDto>> GetPrizeOrderLogAsync(int userId, string orderNum);
Task<List<PrizeOrderLogDto>> GetInfinitePrizeOrderLogAsync(int userId, string orderNum);
}
4. IWarehouseService
public interface IWarehouseService
{
// 仓库查询
Task<PageResponse<WarehouseItemDto>> GetWarehouseIndexAsync(int userId, int page, int status);
// 奖品回收
Task<RecoveryResultDto> RecoveryPrizesAsync(int userId, string orderListIds);
// 奖品发货
Task<SendResultDto> SendPrizesAsync(int userId, SendRequest request);
Task<bool> ConfirmSendAsync(int userId, int id);
// 记录查询
Task<PageResponse<SendRecordDto>> GetSendRecordsAsync(int userId, int page);
Task<SendRecordDetailDto> GetSendRecordDetailAsync(int userId, int id);
Task<PageResponse<RecoveryRecordDto>> GetRecoveryRecordsAsync(int userId, int page);
// 物流查询
Task<LogisticsDto> GetLogisticsAsync(int userId, int id);
}
Data Models
Request Models
// 一番赏订单金额计算请求
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
// 订单金额计算响应
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响应格式兼容性