front/docs/订单全链路自动化测试方案.md
zzh 5191d1981f feat: 仓储模块前端、菜单同步扩展及相关页面优化
新增仓储模块页面与 API、店铺授权/店铺订单页面及路由权限目录;
扩展菜单管理同步能力支持二级子菜单与三级按钮;优化公告、仓库地址、下单等页面。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-11 15:19:35 +08:00

603 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 订单全链路自动化测试方案
> **版本**:v1.0
> **日期**:2026-07-08
> **适用范围**:OMS 订单从创建 → 预报 → 入库 → 支付 → 出库 → 轨迹 → 签收(设计态)
> **关联文档**:`oms系统设计-050801.md` §4、§6、§10.3;`物流下单协议.md`;`订单批量处理与异步队列方案0707.md`
---
## 1. 目标与范围
### 1.1 目标
建立一套**可重复执行、可接入 CI** 的自动化测试流程,覆盖订单主 happy path:
```
下单预报 → 入库收货 → 客户支付 → 出库发货 → 轨迹同步 → 签收完成
```
并验证各阶段:
- **订单状态**(`OrderStatus`)与时间字段(`ReceiveTime` / `PayTime` / `ShipTime` / `SignTime`)
- **费用**(预报 / 入库 / 出库阶段 `t_order_fee`)
- **客户余额与流水**(`t_customer.Balance`、`t_customer_account_flow`)
- **仓储操作记录**(`t_inbound_record` / `t_outbound_record`)
- **轨迹服务联动**(UpsertSmallBag,可 mock)
- **权限与数据范围**(客户只能看到自己的订单)
### 1.2 当前实现边界(必读)
| 阶段 | 状态码 | 后端是否已实现 | 自动化策略 |
|------|--------|----------------|------------|
| 小包创建 + 预报计费 | `predeclared` | ✅ | API 断言 |
| 入库扫描 | `pendingPayment` | ✅ | API 断言 |
| 支付 | `pendingShip` | ✅ | API + 余额断言 |
| 出库扫描 | `pendingOnline` | ✅ | API 断言 |
| 运输中 | `shipping` | ❌ 无写入逻辑 | **Phase 2**:mock 轨迹回调或手工 DB 置态 |
| 派送成功(签收) | `deliverySuccess` + `SignTime` | ❌ 无写入逻辑 | **Phase 2**:同上;或 Track 服务 `UpdateOrderStatus` |
| 问题件 / 理赔件 | `problematic` / `claimed` | ✅ | 分支用例 |
> **结论**:Phase 1 自动化覆盖到 **`pendingOnline`(待上网)** 为「OMS 内闭环」;签收段在 OMS 回写接口落地前,用 **Track 侧断言 + 预留 OMS 状态同步测试桩** 衔接。
---
## 2. 测试分层架构
```mermaid
flowchart TB
subgraph L4["L4 可选 UI E2E"]
UI[Playwright / Cypress<br/>关键页面冒烟]
end
subgraph L3["L3 API 全链路 E2E(推荐主战场)"]
E2E[OrderLifecycleE2ETests<br/>真实 MySQL + TestServer]
end
subgraph L2["L2 API 集成"]
INT[SimpleAdmin.Api.IntegrationTests<br/>路由注册 + Mock 依赖]
end
subgraph L1["L1 单元测试"]
UNIT[Oms.Tests<br/>计费 / 签名 / Batch 治理]
end
L1 --> L2 --> L3
L3 -.-> L4
```
| 层级 | 项目位置 | 依赖 | 运行频率 |
|------|----------|------|----------|
| L1 单元 | `oms0414-back/src/Oms.Tests` | 无 DB | 每次 PR |
| L2 集成 | `oms0414-back/src/SimpleAdmin.Api.IntegrationTests` | TestServer + 内存 RBAC | 每次 PR |
| L3 API E2E | **待建** `Oms.E2E.Tests` 或扩展现有 IntegrationTests | Docker MySQL + 可选 RabbitMQ/WireMock | 每日 / 合并前 |
| L4 UI E2E | **待建** `oms0414/e2e/` | 前端 dev + 后端 API | 发版前手动 / 夜间 |
---
## 3. 测试环境与配置
### 3.1 基础服务
| 组件 | 用途 | 本地 / CI 建议 |
|------|------|----------------|
| MySQL 8.x | 业务库 `oms_test` | `docker compose` 独立库,每次 E2E 前 migrate |
| SimpleAdmin.Api | OMS 后端 | `ASPNETCORE_ENVIRONMENT=Testing` |
| 前端 Vite | UI E2E 可选 | `localhost:5173` |
| RabbitMQ | 批量任务 E2E | 默认 **关闭**;批量专项用例单独 job 开启 |
| WireMock / MockServer | Track、itfx 下游 | E2E 默认 mock,避免外网依赖 |
### 3.2 后端配置项(`appsettings.Testing.json` 或环境变量)
```json
{
"ConnectionStrings": { "Default": "Server=127.0.0.1;Port=3306;Database=oms_test;..." },
"OrderBatch": {
"RabbitMq": { "Enabled": false }
},
"Oms": {
"TrackService": {
"Enabled": true,
"BaseUrl": "http://127.0.0.1:9090",
"AppKey": "TEST_KEY",
"AppSecret": "TEST_SECRET",
"TimeoutSeconds": 5
},
"Itfx": {
"BaseUrl": "http://127.0.0.1:9091",
"TimeoutSeconds": 5
}
},
"App": { "SendStartupNotification": false }
}
```
| 配置节 | 测试关注点 | Mock 策略 |
|--------|------------|-----------|
| `Oms:TrackService` | 创建订单后异步 `UpsertSmallBag` | WireMock 返回 200 + 固定 body |
| `Oms:Itfx` | 下游预报转发(可选步骤) | WireMock 或跳过 |
| `OrderBatch:RabbitMq` | 批量支付/入库等 | 主链路用同步 API;批量单独用例开启 |
### 3.3 数据库初始化顺序
```text
1. db.sql # 全量表结构
2. sql/migrate_*.sql # 增量迁移(issue_template、xhs 等按需)
3. scripts/order_batch_job_tables.sql
4. sql/seed_e2e_order_lifecycle.sql # 【待建】E2E 专用主数据(见 §4)
```
---
## 4. 主数据 Fixture(测试前置条件)
自动化执行前,库中须存在以下**稳定可引用**的数据。建议新增 `sql/seed_e2e_order_lifecycle.sql`,所有 E2E 用例共用同一套编码。
### 4.1 主数据清单
| 类别 | 表 / 模块 | 测试用固定值 | 说明 |
|------|-----------|--------------|------|
| 国家 | `t_country` | `US` / `CN` | 收件国用于分区计价 |
| 客户 | `t_customer` | `customerCode=E2E001`,`Balance >= 10000` | 支付前须余额充足 |
| RBAC 用户 | `user` | 客户主账号,绑定 `E2E001` | 登录拿 JWT |
| 仓库 | `t_warehouse_address` | `warehouseId=9001` | 下单、扫描共用 |
| 销售产品 | `t_sales_product` | `productCode=E2E-SP-01` | 已发布、已绑定规则/价格快照 |
| 服务渠道 | `t_service_channel` | `channelCode=E2E-CH-01` | 排货后可写入订单 |
| 价格 / 分区 | `t_sales_product_price*`、`t_kpi_area*` | 覆盖 US 分区 | 否则创建订单会 `draft` + `PredeclareFailReason` |
| 计重 / 进位 | `t_weight_rule`、`t_weight_rounding` | 匹配 1kg 标准件 | 入库/outbound 计费依赖 |
| 数据权限 | 数据范围 | 测试用户可见 E2E 客户 | 否则列表为空 |
### 4.2 登录与请求头
```http
POST /admin/auth/login
Content-Type: application/json
{ "userName": "e2e_customer", "password": "..." }
```
后续请求:
```http
Authorization: Bearer {accessToken}
```
客户会话下单时 **不传 `customerId`**(由 `OmsSessionHelper` 解析);内部运营账号测入库/出库时用 **运营 RBAC 账号**。
### 4.3 推荐双角色
| 角色 | 用途 | 权限前缀 |
|------|------|----------|
| `e2e_customer` | 下单、支付、查单 | `Order.PlaceOrder.*`、`Order.MyOrders.*` |
| `e2e_operator` | 入库、出库扫描 | `Operation.InboundScan.*`、`Operation.OutboundScan.*` |
---
## 5. 主流程用例设计(Happy Path)
### 5.1 流程总览
```mermaid
sequenceDiagram
participant C as 客户 API
participant O as OMS OrderService
participant W as 仓储 Operation
participant F as Finance
participant T as Track(Mock)
C->>O: POST /order/parcel/create
O-->>C: predeclared + serviceNo
O->>T: UpsertSmallBag (async)
C->>W: POST /operation/inbound/create
W->>O: ApplyReceiveBilling
W-->>C: pendingPayment + ReceiveTime
C->>O: POST /order/pay
O->>F: DebitOrderPay
O-->>C: pendingShip + PayTime
C->>W: POST /operation/outbound/create
W->>O: ApplyShipBilling
W-->>C: pendingOnline + ShipTime
Note over C,T: Phase 2 签收
T-->>O: (待实现) 状态回写
O-->>C: deliverySuccess + SignTime
```
### 5.2 分步用例表
| 步骤 | API | 方法 | 关键入参 | 期望 `OrderStatus` | 期望副作用 |
|------|-----|------|----------|-------------------|------------|
| 0 可选试算 | `/order/price-check` | POST | `productCode`, 件重尺, 收件国 | — | 返回价格 > 0 |
| 1 创建订单 | `/order/parcel/create` | POST | 见 §5.3 | `predeclared` | `t_order_fee` 预报应收;`ServiceNo` 生成 |
| 2 查详情 | `/order/detail` | GET | `id` | `predeclared` | 发件人/收件人/申报齐全 |
| 3 入库 | `/operation/inbound/create` | POST | `waybillNo`, 实重尺 | `pendingPayment` | `ReceiveTime` 非空;入库费 `ChargingStage=inbound` |
| 4 支付 | `/order/pay` | POST | `{ "id": orderId }` | `pendingShip` | `IsPaid=1`, `PayTime`;余额减少;`account_flow` |
| 5 出库 | `/operation/outbound/create` | POST | `waybillNo`, 实重尺 | `pendingOnline` | `ShipTime` 非空;出库费 |
| 6 列表 | `/order/list` | POST | `status=pendingOnline` | — | 包含该 `serviceNo` |
| 7 轨迹 | Mock 校验 | — | — | — | UpsertSmallBag 被调用 1 次 |
| 8 签收 | **Phase 2** | — | — | `deliverySuccess` | `SignTime` 非空 |
### 5.3 创建订单请求模板(E2E Fixture)
```json
{
"requestId": "e2e-{uuid}",
"clientNo": "E2E-CLIENT-{timestamp}",
"productCode": "E2E-SP-01",
"cargoAttribute": "general",
"warehouseId": 9001,
"length": 30,
"width": 20,
"height": 10,
"actualWeight": 1.2,
"quantity": 1,
"receiver": {
"name": "E2E Receiver",
"phone": "13800000001",
"countryCode": "US",
"state": "CA",
"city": "Los Angeles",
"address": "100 Test St",
"postcode": "90001"
},
"sender": {
"name": "E2E Sender",
"phone": "13900000001",
"countryCode": "CN",
"city": "Shenzhen",
"address": "Test Warehouse"
},
"items": [
{
"nameEn": "Test Goods",
"nameCn": "测试商品",
"quantity": 1,
"unitPrice": 10,
"weight": 1.2,
"hsCode": "6109100021"
}
]
}
```
### 5.4 入库 / 出库请求模板
```json
// POST /operation/inbound/create
{
"waybillNo": "{serviceNo}",
"weight": 1.2,
"length": 30,
"width": 20,
"height": 10,
"warehouseId": 9001
}
// POST /operation/outbound/create
{
"waybillNo": "{serviceNo}",
"weight": 1.2,
"length": 30,
"width": 20,
"height": 10,
"warehouseId": 9001
}
```
---
## 6. 功能模块与 API 映射
| 业务阶段 | 后端 Service | 前端模块 | 路由 | 权限(`pageButtonCatalog`) |
|----------|--------------|----------|------|---------------------------|
| 试算 / 下单 | `OrderService` | 物流下单 | `/order/placeOrder` | `Order.PlaceOrder.*` |
| 订单管理 | `OrderService` | 我的订单 | `/order/myOrders` | `Order.MyOrders.*` |
| 入库 | `InboundRecordService` | 入库扫描 | `/operation/inboundScan` | `Operation.InboundScan.Inbound` |
| 出库 | `OutboundRecordService` | 出库扫描 | `/operation/outboundScan` | `Operation.OutboundScan.Outbound` |
| 客户余额 | `CustomerBalanceMutator` | 客户管理 / 充值 | `/user/customer` | `User.Customer.*` |
| 应收应付 | `FinanceService` | 应收应付 | `/finance/receivablePayable` | `Finance.ReceivablePayable.Query` |
| 账户流水 | `CustomerAccountFlowService` | — | API | — |
| 渠道配置 | `SalesProductService` 等 | 销售产品 / 服务渠道 | `/channel/*` | 各模块 Query/Edit |
| 轨迹推送 | `SmallBagTrackOrderNotifier` | 我的订单-创建轨迹 | — | `Order.MyOrders.CreateTrackOrder` |
| 下游预报 | `OrderService.DownstreamForward` | 转发下游 | — | `Order.MyOrders.ForwardDownstreamCreate` |
| 批量任务 | `OrderBatchJobCoordinator` | 批量任务 | `/order/batchJobs` | `Order.BatchJobs.*` |
---
## 7. 断言检查点(每层必验)
### 7.1 HTTP 层
- 状态码 200(业务错误时 Fake 框架返回统一错误体,需断言 `message` 为空或 success 标志)
- 响应 JSON 关键字段类型与枚举值
### 7.2 订单主表 `t_order`
```sql
SELECT OrderStatus, IsPaid, ReceiveTime, PayTime, ShipTime, SignTime,
PredeclareFailReason, ChannelCode, ChargeableWeight
FROM t_order WHERE ServiceNo = @serviceNo;
```
| 步骤后 | OrderStatus | IsPaid | 时间字段 |
|--------|-------------|--------|----------|
| 创建 | `predeclared` | 0 | 全 NULL |
| 入库 | `pendingPayment` | 0 | ReceiveTime 有值 |
| 支付 | `pendingShip` | 1 | PayTime 有值 |
| 出库 | `pendingOnline` | 1 | ShipTime 有值 |
| 签收 | `deliverySuccess` | 1 | SignTime 有值 |
### 7.3 费用 `t_order_fee`
- 预报后:存在 `Type=receivable` 且 `ChargingStage` 含 forecast/predeclare
- 入库后:新增 `ChargingStage=inbound` 行(若产品配置入库计费)
- 出库后:新增 `ChargingStage=outbound` 行
- 支付金额 = 当前应收合计
### 7.4 客户财务
```sql
SELECT Balance FROM t_customer WHERE Id = @customerId;
SELECT * FROM t_customer_account_flow
WHERE BizType = 'orderPay' AND BizId = @orderId;
```
- 支付后:`Balance` 减少额 = 订单应收合计
- 流水 `Amount` 为负,`BalanceBefore/After` 连贯
### 7.5 仓储记录
```sql
SELECT * FROM t_inbound_record WHERE WaybillNo = @serviceNo;
SELECT * FROM t_outbound_record WHERE WaybillNo = @serviceNo;
```
### 7.6 轨迹 Mock
- WireMock 收到 `POST /OrderV2/UpsertSmallBag`
- 请求头含 `appKey`、`timestamp`、`sign`(签名算法见 `SmallBagTrackSignHelperTests`)
---
## 8. 负向与分支用例(摘要)
| 编号 | 场景 | 触发 | 期望 |
|------|------|------|------|
| N01 | 余额不足支付 | 客户 Balance < 应收 | `账户余额不足` |
| N02 | 未入库支付 | 跳过步骤 3 直接 pay | `当前订单状态不可支付` |
| N03 | 未支付出库 | 跳过步骤 4 直接 outbound | `订单未付款,禁止出库` |
| N04 | 重复支付 | pay 两次 | `订单已支付` |
| N05 | 价格未配置 | 错误 productCode | `draft` + `PredeclareFailReason` |
| N06 | 黑名单国家/客户 | 命中黑名单 | 创建失败,不落库或 draft |
| N07 | 拦截单出库 | intercept 后 outbound | 按业务规则拒绝或警告 |
| B01 | 问题件流程 | mark-problematic | `problematic` + `handleStatus=pending` |
| B02 | 处理完成 | handle-status/update | `handleStatus=processed` |
| B03 | 批量支付 | `/order/batch/pay` + RabbitMQ | Job 全部 success(独立 job) |
---
## 9. 自动化实现建议
### 9.1 推荐新建项目结构(后端)
```text
oms0414-back/
src/
Oms.E2E.Tests/ # 新建
Fixtures/
OrderLifecycleFixture.cs # 登录、种子数据、清理
WireMockTrackServer.cs
Scenarios/
OrderLifecycleHappyPathTests.cs
OrderLifecycleNegativeTests.cs
sql/
seed_e2e_order_lifecycle.sql
assert_order_state.sql
appsettings.E2E.json
```
### 9.2 技术选型
| 能力 | 库 |
|------|-----|
| API 宿主 | 复用 `SimpleAdminApiTestHost` 或 `WebApplicationFactory` + 真实 MySQL |
| DB 断言 | `Dapper` / 直接 `SqlSugar` 查询 |
| HTTP 客户端 | `HttpClient` + `System.Text.Json` |
| Mock 外服 | `WireMock.Net` |
| 测试框架 | xUnit + FluentAssertions(与现有一致) |
### 9.3 示例测试类骨架(伪代码)
```csharp
[Collection("OrderLifecycle")]
public class OrderLifecycleHappyPathTests
{
[Fact]
public async Task Step01_To_Step05_PendingOnline_ShouldSucceed()
{
var token = await Fixture.LoginAsCustomerAsync();
var create = await Fixture.Api.PostJsonAsync("/admin/order/parcel/create", body, token);
create.OrderStatus.Should().Be("predeclared");
var serviceNo = create.ServiceNo;
await Fixture.Api.PostJsonAsync("/admin/operation/inbound/create", inboundBody, operatorToken);
await Fixture.AssertOrderStatusAsync(serviceNo, "pendingPayment");
await Fixture.Api.PostJsonAsync("/admin/order/pay", new { id = create.Id }, token);
await Fixture.AssertOrderStatusAsync(serviceNo, "pendingShip");
await Fixture.AssertBalanceDebitedAsync(create.CustomerId, create.Id);
await Fixture.Api.PostJsonAsync("/admin/operation/outbound/create", outboundBody, operatorToken);
await Fixture.AssertOrderStatusAsync(serviceNo, "pendingOnline");
Fixture.TrackMock.VerifyUpsertCalledOnce(serviceNo);
}
}
```
### 9.4 数据隔离策略
| 策略 | 做法 |
|------|------|
| **A 每用例独立 clientNo** | `E2E-{guid}`,不删库,靠唯一键隔离(推荐) |
| **B 事务回滚** | SqlSugar 难包裹跨 HTTP 请求,不推荐 |
| **C 每 job 重建库** | CI 慢但最干净;夜间全量 E2E 使用 |
---
## 10. CI/CD 流水线设计
```mermaid
flowchart LR
PR[PR / Push] --> L1[dotnet test Oms.Tests]
L1 --> L2[dotnet test IntegrationTests]
L2 --> E2E{main 分支?}
E2E -->|是| Docker[启动 MySQL + WireMock]
Docker --> Seed[执行 seed_e2e_order_lifecycle.sql]
Seed --> L3[dotnet test Oms.E2E.Tests]
L3 --> Report[测试报告 / 飞书通知]
```
### 10.1 GitHub Actions 示例(片段)
```yaml
jobs:
unit-and-integration:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: dotnet test src/Oms.Tests
- run: dotnet test src/SimpleAdmin.Api.IntegrationTests
order-lifecycle-e2e:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: test
MYSQL_DATABASE: oms_test
steps:
- run: mysql -h 127.0.0.1 -uroot -ptest oms_test < db.sql
- run: mysql -h 127.0.0.1 -uroot -ptest oms_test < sql/seed_e2e_order_lifecycle.sql
- run: dotnet test src/Oms.E2E.Tests --filter Category=E2E
```
### 10.2 本地一键脚本(建议 `scripts/run-order-e2e.ps1`)
```powershell
docker compose -f docker-compose.e2e.yml up -d
dotnet test src/Oms.E2E.Tests
docker compose -f docker-compose.e2e.yml down
```
---
## 11. Phase 2:签收段衔接方案
OMS 尚未实现 `shipping` → `deliverySuccess` 回写时,任选其一:
| 方案 | 说明 | 适用 |
|------|------|------|
| **P2-A Track 侧完成** | 调 `trackApi/Track/Order/UpdateOrderStatus` 置 `isCompleted=true` | 验证轨迹系统闭环 |
| **P2-B 测试专用 API** | 新增 `[TestingOnly] POST /order/test/mark-delivered` | 仅 Testing 环境注册 |
| **P2-C SQL 置态** | E2E 直接 `UPDATE t_order SET OrderStatus='deliverySuccess', SignTime=NOW()` | 临时;不验 API |
| **P2-D 实现正式回调** | Track Webhook → OMS Consumer | 生产方案,纳入同一 E2E |
**推荐路径**:先 **P2-B** unblock E2E,上线前替换为 **P2-D** 并删除测试 API。
---
## 12. 实施路线图
| 阶段 | 交付物 | 工时估 |
|------|--------|--------|
| **P0** | 本文档 + `seed_e2e_order_lifecycle.sql` | 1d |
| **P1** | `Oms.E2E.Tests` Happy Path(至 pendingOnline) | 2–3d |
| **P1** | WireMock Track + 负向用例 N01–N04 | 1d |
| **P2** | 签收置态 / Webhook + 完整端到签收 | 2d |
| **P3** | Playwright 冒烟(下单页 + 扫描页) | 2d |
| **P3** | CI nightly + 测试报告 | 1d |
---
## 13. 关键代码与文档索引
### 后端
| 路径 | 说明 |
|------|------|
| `Oms.Domain/OrdersAggregate/Consts/OrderStatusCodes.cs` | 订单状态枚举 |
| `Oms.Application/Services/Orders/OrderService.ParcelBilling.cs` | 创建、入库/出库计费 |
| `Oms.Application/Services/Orders/OrderService.cs` | 支付、列表 |
| `Oms.Application/Services/Operations/InboundRecordService.cs` | 入库 |
| `Oms.Application/Services/Operations/OutboundRecordService.cs` | 出库 |
| `Oms.Application/Shared/CustomerBalanceMutator.cs` | 支付扣款 |
| `Oms.Application/Integrations/SmallBagTrack/` | 轨迹推送 |
| `SimpleAdmin.Api.IntegrationTests/Support/SimpleAdminApiTestHost.cs` | 集成测试宿主 |
| `Oms.Tests/ParcelBillingCalculatorTests.cs` | 计费单元测试 |
### 前端
| 路径 | 说明 |
|------|------|
| `src/constants/orderStatus.ts` | 状态常量 |
| `src/api/order/index.ts` | 订单 API |
| `src/api/operation/index.ts` | 仓储 API |
| `src/views/order/placeOrder/index.vue` | 下单页 |
| `src/views/operation/inboundScan/index.vue` | 入库 |
| `src/views/operation/outboundScan/index.vue` | 出库 |
### 文档
| 路径 | 说明 |
|------|------|
| `docs/oms系统设计-050801.md` | 主设计(§4 订单、§6 操作、§10.3 状态码) |
| `docs/物流下单协议.md` | parcel/create 协议 |
| `docs/订单批量处理与异步队列方案0707.md` | 批量异步 |
---
## 14. 附录:手动冒烟检查清单(5 分钟)
自动化未就绪时,可按此手工验证主链路:
- [ ] 客户登录,余额 ≥ 100
- [ ] 销售产品 `E2E-SP-01` 已发布且 US 有价格
- [ ] `POST /order/parcel/create` → 返回 `predeclared`
- [ ] `POST /operation/inbound/create` → 订单变 `pendingPayment`
- [ ] `POST /order/pay` → `pendingShip`,余额减少
- [ ] `POST /operation/outbound/create` → `pendingOnline`
- [ ] `GET /order/detail` → `ReceiveTime`、`PayTime`、`ShipTime` 均有值
- [ ] (可选)Track Mock 日志有 UpsertSmallBag
---
## 15. 已落地实现(2026-07-08)
| 交付物 | 路径 |
|--------|------|
| E2E 主数据种子 | `oms0414-back/sql/seed_e2e_order_lifecycle.sql` |
| E2E 测试项目 | `oms0414-back/src/Oms.E2E.Tests/` |
| Happy Path 用例 | `Scenarios/OrderLifecycleHappyPathTests.cs` |
| 一键脚本 | `oms0414-back/scripts/run-order-e2e.ps1` |
**运行方式:**
```powershell
$env:OMS_E2E_ENABLED = "1"
$env:OMS_E2E_CONNECTION = "Server=127.0.0.1;Port=3306;Database=oms;Uid=root;Pwd=你的密码;CharSet=utf8mb4;"
cd oms0414-back
.\scripts\run-order-e2e.ps1
```
未设置 `OMS_E2E_ENABLED` 时,E2E 用例自动跳过(不失败)。
---
**维护说明**:OMS 实现签收回写后,更新 §1.2 边界表、§5 步骤 8、§11,并将 Phase 2 用例并入 P1 必跑集。