Order 订单域
交易意图的权威:条款、金额、状态、双方。执行过程归 Task,记账归 Accounting。
职责
| 负责 | 不负责 |
|---|---|
| 订单条款与金额 | 执行过程(task) |
| 订单状态机 | 分录与期间(accounting) |
| 订单 → 任务关联指针 | 履约事实(fulfillment) |
| 订单行(含物料编码) | 物料本身(master-data) |
数据模型
| 路径 | 内容 |
|---|---|
/orders/{orderId} | 订单根:buyerId / currency / amount / terms / status |
/orders/{orderId}/lines/{lineId} | 订单行:title / materialCode? / amount / quantity? |
/orders/{orderId}/tasks/{taskId} | 关联指针:taskId / linkedAt / linkedBy |
存 state_events(factClass = event)。
三条边界
| 规则 | 为什么 |
|---|---|
| 金额只在订单域 | 任务域再存一份 orderAmount,改价时必然漂移 |
| 订单→任务只存指针 | 复制任务状态 = 两个真相源 |
| 总额 = Σ 行 | 由服务计算,不接受调用方传入 |
订单行的 materialCode 同理:只存编码,不复制物料名称/规格。
状态机
draft → placed → accepted → fulfilled
└──────┴─────────┴──→ cancelled迁移用乐观并发(expectedVersion):两人同时接受订单,后到的收到 409,而不是悄悄覆盖。
接口
| Method | Path | 说明 |
|---|---|---|
| POST | /api/orders | 创建(buyer 取自登录身份) |
| GET | /api/orders/:orderId | 详情(仅买家本人) |
| GET | /api/orders/:orderId/lines | 订单行 |
| GET | /api/orders/:orderId/tasks | 关联任务指针 |
| PATCH | /api/orders/:orderId/status | 状态迁移 |
POST /orders/:id/tasks不对外:该动作只允许平台/系统, 否则 agent 可以给自己「认领」一张高金额订单,绕过匹配与验收。
边界
- 报价、撮合、拆单、退改不在范围
- 订单行不支持增删改(只在创建时写入)
- 管理员视角的读取需要角色体系,目前只有买家本人可读
- 多币种只预留字段,不做换算
源码
libs/modules/src/order/
├── interfaces/order.interface.ts 契约 + 状态迁移表
├── services/order.service.ts 创建 / 读取 / 状态机 / 关联
├── order.controller.ts 5 个端点
└── dto/order.dto.ts DTO + Swagger