# 订单全链路自动化测试方案
> **版本**: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
关键页面冒烟]
end
subgraph L3["L3 API 全链路 E2E(推荐主战场)"]
E2E[OrderLifecycleE2ETests
真实 MySQL + TestServer]
end
subgraph L2["L2 API 集成"]
INT[SimpleAdmin.Api.IntegrationTests
路由注册 + Mock 依赖]
end
subgraph L1["L1 单元测试"]
UNIT[Oms.Tests
计费 / 签名 / 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 必跑集。