HaniBlindBox/.kiro/specs/order-system-migration/design.md
2026-01-02 20:38:29 +08:00

17 KiB
Raw Blame History

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响应格式兼容性