Files
wechat_wc/docs/routes/route-r3-order-pay.md
T

133 lines
6.7 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.
# R3 订单闭环 + 支付接口占位(feat/r3-order-pay
**Goal:** 打通“设计清单 → 结算确认 → 创建订单 → 订单列表/详情 → 状态流转”的服务端闭环,
微信支付只留接口与配置位,不填真实密钥;支付不可用时流程能明确回到“待付款/支付未配置”。
**Architecture:** 前端 `api/order.ts` 承接下单与查询,`checkout/orders/orderDetail` 三个页面
改为服务端数据源;后端订单创建在事务内重算金额、快照地址、生成幂等的订单号并创建 PENDING
支付记录;`payments` 在密钥未配置时返回显式占位响应,不做假成功。
**Tech Stack:** Taro 3.6 + React 18 + TypeScriptNestJS 11 + Prisma/PostgreSQL + Redis/BullMQ(可选)。
## 1. 本分支要开发的内容
### 前端 `wechat_wc`
| 文件 | 职责 |
|---|---|
| `src/utils/api/order.ts` | `createOrder/fetchOrders/fetchOrderDetail/payOrder`;请求只带商品项、地址 id、designListId,不带金额 |
| `src/types/index.ts` | 服务端 Order 类型:`orderNo/status/totalAmount/items/addressSnapshot/createdAt/paidAt` |
| `src/pages/checkout/index.tsx` | 从服务端读设计清单,选择地址(用 R2 的地址接口),提交下单;展示服务端总价;支付未配置时提示后回订单列表 |
| `src/pages/orders/index.tsx` | 订单列表按状态 Tab 拉取;付款/确认收货等按钮调用对应接口或显示未配置 |
| `src/pages/orderDetail/index.tsx` | 按订单 id 拉详情;地址快照、商品、状态条、物流占位 |
| `src/utils/store/order.ts` | 标记 deprecated,仅保留为本地兜底,不再被 checkout 主流程调用 |
| `src/pages/profile/index.tsx` | 状态统计改为基于服务端订单列表(R2/R3 合入后统一收尾) |
### 后端 `wxmp_backend`
| 模块 | 内容 |
|---|---|
| `orders` | `POST /api/orders`:服务端按 Product/design-list 重算金额、事务创建订单+items+Payment、生成唯一 orderNo、快照地址 |
| `orders` 查询 | `GET /api/orders`(状态筛选/分页)、`GET /api/orders/:id`(仅本人)、`PATCH /api/orders/:id/confirm``POST /api/orders/:id/cancel`(按需) |
| `payments` | `POST /api/payments/:orderId/pay``POST /api/payments/notify` 保留签名;密钥为空时返回 `{ configured:false, message:'支付未配置' }` |
| `wechat` | `createUnifiedOrder/verifyPayNotify` 保持占位,不填入假商户参数 |
| `queue` | 可选:订单创建后入队定制任务,处理器先只更新 `CustomizationTask` 状态 |
| `docs/api-contract-v1.md` | 订单创建请求/响应、状态机、金额字段精度、错误码、幂等键 |
### 词云项目 `wordcloud`
不参与本分支。
## 2. 订单状态机
服务端 `OrderStatus` 与前端展示映射:
| 后端 | 前端 Tab | 说明 |
|---|---|---|
| PENDING | 待付款 | 允许取消;支付未配置时长期停留 |
| PAID | 待发货 | 由支付回调推进,占位期不出现 |
| PROCESSING | 待发货 | 定制生产中 |
| SHIPPED | 待收货 | 需要发货/物流数据,本分支可展示占位 |
| COMPLETED | 已完成 | 用户确认收货推进 |
| CANCELLED | 已取消 | 待付款状态用户取消 |
前端只读状态数组,不做状态转移判断;转移一律走后端接口或支付回调。
## 3. 接口设计要点
创建订单请求:
```ts
{
designListId: string,
addressId: string,
items: [{ productId, quantity }]
}
```
服务端响应:
```ts
{
id: string,
orderNo: string,
status: "PENDING",
totalAmount: number,
items: [],
addressSnapshot: {},
createdAt: string
}
```
## 4. 设计注意事项
### DO
- DO 订单金额、单价、总价全部由服务端计算,前端提交只给 `productId + quantity`
- DO 创建订单使用 `prisma.$transaction`,订单、明细、支付记录任一步失败整体回滚。
- DO 给创建订单接口支持幂等键(客户端 `requestId``designListId` 防重复下单),双击提交只产生一单。
- DO 订单号 `orderNo` 唯一,生成规则包含日期与随机位并在冲突时重试。
- DO 收货地址在创建订单时直接快照到 `addressSnapshot`,订单创建后不再跟随地址变更。
- DO 支付占位返回结构化 `configured:false`,前端据此显示“暂不支持支付”而不是错误弹窗。
- DO 后端从配置读取微信支付密钥,密钥缺失时支付接口直接返回占位,不使用默认值或硬编码。
- DO 订单列表/详情都校验当前用户 openid,越权访问返回 403。
- DO 金额相关字段用 Decimal 精确类型持久化,序列化时统一成字符串或 number,避免浮点误差。
### DON'T
- DON'T 信任前端传的 `totalAmount`/`price`,即使前端为了展示计算过也一律忽略。
- DON'T 让客户端参数直接决定 `status`,状态只能由服务端接口和支付回调推进。
- DON'T 在代码里填占位商户号、密钥、证书路径;密钥缺失是合法运行状态而非 bug。
- DON'T 模拟支付成功,包括开发环境;未配置就是未配置,避免上线前“假流程”掩盖问题。
- DON'T 支付回调先解锁订单再验签;本分支只留入口,不实现任何未验签的落库逻辑。
- DON'T 在本分支删除 `store/order.ts`,把它标记 deprecated 即可,本地兜底退出要留到全链路验证后。
- DON'T 修改 R2 的地址/设计清单接口签名,R3 只消费。
## 5. 补充内容
### 验收标准
- 指定一个已登录用户,从设计清单进入结算页,选地址后创建订单;服务端返回的 `totalAmount` 与商品单价×数量一致。
- 双击提交只生成一单,订单号唯一。
- 订单列表/详情展示服务端数据,越权用户拿不到他人订单。
- 支付按钮在密钥未配置时返回 `configured:false` 并给出明确文案,不调用微信、不写成功记录。
- 后端 `npm run build`、前端 `npm run build:weapp` 通过。
### 合并与依赖
- 分支名:前端与后端均为 `feat/r3-order-pay`
- 依赖 R1 的商品表和 R2 的地址/设计清单接口,合并顺序放在 R1、R2 之后。
- 支付实现作为一个独立后续里程碑,不阻塞本分支交付。
### 风险
- 微信小程序对订单支付有场景与类目要求,目前未备案时不要尝试真支付,容易触发审核风险。
- 物流信息当前为假数据,SHIPPED/COMPLETED 的物流时间轴要标注占位。
- 若 R2 未按约定提供地址接口,checkout 集成会被卡住;R3 开发时先按 `api-contract-v1.md` 编写,联调阶段再对齐实现。
### 测试要求
- 后端:订单创建事务、金额重算、重复提交幂等、越权查询、状态流转、支付未配置占位响应。
- 前端:结算页创建订单、双击防抖、订单空态、状态 Tab 筛选、越权场景提示、支付未配置提示。