Просмотр исходного кода

完善闪送 App 接口文档

补充调整后的下单契约、报价必填字段、统一时段运价、预约取件、物品信息、费用计算和报价变化响应,并修正示例数据的一致性。
qmj 30 минут с этого момента
Родитель
Сommit
57d8cc90ae
1 измененных файлов с 86 добавлено и 20 удалено
  1. 86 20
      docs/flash-delivery-app-api.md

+ 86 - 20
docs/flash-delivery-app-api.md

@@ -4,6 +4,13 @@
 
 > 更新时间:2026-09-07。当前口径已对齐下单设计稿:帮送/帮取与普通/加急正交、统一分时段运价、完整物品信息、费用明细及创建订单报价校验;闪送仍不接入支付。
 
+本次调整后的下单契约要点:
+
+- `serviceType` 只区分 `HELP_SEND`(帮送)和 `HELP_PICKUP`(帮取),不再使用 `URGENT` 作为服务类型。
+- 是否加急由独立字段 `deliveryType=NORMAL/URGENT` 表达;帮送和帮取使用同一套分时段基础运价。
+- 报价和创建订单都必须提交取件方式、物品类别、数量、总重量、规格说明和骑手小费;立即取件使用 `deliveryMode=NOW`,预约取件使用 `deliveryMode=SCHEDULED` 并提交取件时间段。
+- App 必须先报价,再把报价 ID、版本及四个费用字段原样回传创建订单接口。后端重新计算不一致时不会创建订单,而会返回最新报价。
+
 ## 1. 功能范围
 
 当前闪送支持:
@@ -417,12 +424,26 @@ GET /system/flashDelivery/home
       "minimumUrgentFee": 15,
       "pricingVersion": 1,
       "currency": "TWD"
+    },
+    {
+      "serviceType": "HELP_PICKUP",
+      "pricingId": 1,
+      "startTime": "00:00",
+      "endTime": "08:00",
+      "startingDistance": 3.00,
+      "startingFare": 60,
+      "distance": 1.00,
+      "freight": 10,
+      "urgentRate": 20.00,
+      "minimumUrgentFee": 15,
+      "pricingVersion": 1,
+      "currency": "TWD"
     }
   ]
 }
 ```
 
-帮送和帮取会返回同一份当前运价摘要。`startTime` 包含、`endTime` 不包含,均为业务当地时间的 `HH:mm`;`24:00` 只会作为结束时间。`services` 为空表示当前时刻没有匹配的统一运价。
+帮送和帮取会返回两条业务场景数据,但两条数据引用同一个 `pricingId`、`pricingVersion` 和费用配置。`startTime` 包含、`endTime` 不包含,均为台北时区的 `HH:mm`;`24:00` 只会作为结束时间。`services` 为空表示当前时刻没有匹配的统一运价。
 
 ### 7.2 获取实时报价
 
@@ -469,6 +490,25 @@ POST /system/flashDelivery/quote
 }
 ```
 
+报价请求字段:
+
+| 字段 | 类型 | 必填 | 规则 |
+|---|---|---:|---|
+| `serviceType` | string | 是 | `HELP_SEND` 或 `HELP_PICKUP` |
+| `deliveryType` | string | 是 | `NORMAL` 或 `URGENT` |
+| `deliveryMode` | string | 否 | `NOW` 或 `SCHEDULED`,不传按 `NOW` 处理 |
+| `scheduledPickupStartAt` | datetime | 预约时是 | `SCHEDULED` 时为未来三天内的预约开始时间;`NOW` 时不得传 |
+| `scheduledPickupEndAt` | datetime | 预约时是 | 必须比开始时间晚 30 分钟;`NOW` 时不得传 |
+| `packageType` | string | 是 | 取值见 3.3 |
+| `quantity` | integer | 是 | 大于 0 的整数 |
+| `totalWeightKg` | number | 是 | 大于 0 且不超过 20,最多两位小数 |
+| `specification` | string | 否 | 体积或规格说明,去除首尾空格后最长 255 字符 |
+| `tipAmount` | integer | 是 | 骑手小费,非负整数 TWD;没有小费时传 `0` |
+| `pickup` | object | 是 | 完整取件信息,结构和规则见 6.1 |
+| `delivery` | object | 是 | 完整收件信息,结构和规则见 6.1 |
+
+只要业务场景、配送等级、取件时间、物品信息、小费或取送地址发生变化,App 都必须重新调用报价接口,不能继续使用变化前的报价。
+
 响应 `data`:
 
 ```json
@@ -479,8 +519,8 @@ POST /system/flashDelivery/quote
   "scheduledPickupStartAt": "2026-09-08T16:30:00+08:00",
   "scheduledPickupEndAt": "2026-09-08T17:00:00+08:00",
   "pricingId": 1,
-  "startTime": "00:00",
-  "endTime": "08:00",
+  "startTime": "16:00",
+  "endTime": "18:00",
   "distanceMeters": 4200,
   "distanceSource": "ROUTE",
   "estimatedDurationSeconds": 900,
@@ -503,7 +543,9 @@ POST /system/flashDelivery/quote
 
 距离规则与现有外卖订单一致:先用路线公里数减去 `startingDistance`;超出不足 `0.5` 公里时 `billableDistance` 为 `0`,达到 `0.5` 但不足 `1` 公里时按 `1` 公里,达到 `1` 公里后按实际超出距离。`distanceFee = roundHalfUp(billableDistance / distance × freight)`,`baseDeliveryFee = startingFare + distanceFee`。普通配送的 `urgentFee=0`;加急配送的 `urgentFee=max(minimumUrgentFee, roundHalfUp(baseDeliveryFee × urgentRate / 100))`;`amount=baseDeliveryFee+urgentFee+tipAmount`。小费不参与加急费计算,预计时长也不参与计价。
 
-立即配送按报价时刻匹配运价,预约配送按 `scheduledPickupStartAt` 的当地时间匹配运价。创建订单必须回传本次报价;后端会重新计算并逐项精确校验,任何变化都不会创建订单,而是返回最新报价供用户重新确认。
+注意:`baseDeliveryFee` 是已经包含 `distanceFee` 的基础配送费小计。费用合计时不要再次把 `distanceFee` 加入总金额;`distanceFee` 仅用于向用户解释基础配送费中有多少是距离附加费。
+
+立即配送按报价时刻匹配运价,预约配送按 `scheduledPickupStartAt` 的台北时间匹配运价。创建订单必须回传本次报价;后端会重新计算并逐项精确校验,任何变化都不会创建订单,而是返回最新报价供用户重新确认。
 
 ### 7.3 创建闪送订单
 
@@ -511,23 +553,11 @@ POST /system/flashDelivery/quote
 POST /system/flashDelivery/orders
 ```
 
-请求体在报价请求字段基础上增加
+创建请求必须完整包含 7.2 的所有报价请求字段,并在同一个 JSON 对象中增加以下字段。下例只展示新增部分,实际请求不能省略 7.2 中的业务场景、配送等级、取件方式、适用的预约时间段、物品、小费和完整取送地址
 
 ```json
 {
-  "serviceType": "HELP_SEND",
-  "deliveryType": "URGENT",
-  "packageType": "DOCUMENT",
-  "quantity": 1,
-  "totalWeightKg": 3.50,
-  "specification": "30 x 20 x 10 cm",
-  "tipAmount": 5,
-  "pickup": {},
-  "delivery": {},
-  "clientRequestId": "FD-20260901-USER1001-0001",
-  "deliveryMode": "SCHEDULED",
-  "scheduledPickupStartAt": "2026-09-02T10:00:00+08:00",
-  "scheduledPickupEndAt": "2026-09-02T10:30:00+08:00",
+  "clientRequestId": "FD-20260908-USER1001-0001",
   "pricingId": 1,
   "pricingVersion": 1,
   "quotedBaseDeliveryFee": 72,
@@ -561,6 +591,42 @@ POST /system/flashDelivery/orders
 
 若运价版本、路线或费用发生变化,响应 `code=500`、`msg=报价已变化,请重新确认最新费用`,并在 `data` 返回与报价接口相同的完整最新报价。App 必须更新费用明细并要求用户再次确认,不能自动用旧报价重试。
 
+报价变化响应示例:
+
+```json
+{
+  "code": 500,
+  "msg": "报价已变化,请重新确认最新费用",
+  "data": {
+    "serviceType": "HELP_SEND",
+    "deliveryType": "URGENT",
+    "deliveryMode": "SCHEDULED",
+    "scheduledPickupStartAt": "2026-09-08T16:30:00+08:00",
+    "scheduledPickupEndAt": "2026-09-08T17:00:00+08:00",
+    "pricingId": 2,
+    "startTime": "16:00",
+    "endTime": "18:00",
+    "distanceMeters": 4200,
+    "distanceSource": "ROUTE",
+    "estimatedDurationSeconds": 900,
+    "startingDistance": 3.00,
+    "startingFare": 60,
+    "distance": 1.00,
+    "freight": 10,
+    "urgentRate": 25.00,
+    "minimumUrgentFee": 15,
+    "billableDistance": 1.20,
+    "distanceFee": 12,
+    "baseDeliveryFee": 72,
+    "urgentFee": 18,
+    "tipAmount": 5,
+    "amount": 95,
+    "currency": "TWD",
+    "pricingVersion": 2
+  }
+}
+```
+
 创建时,后端会移除收件手机号中的空白、`+`、`-`、`(`、`)` 后,匹配有效且未删除的普通用户账号。仅在恰好匹配一个账号时把该账号固化为收件人;无匹配或重复匹配均不绑定。此绑定只执行一次,历史订单不会因收件人之后注册或修改手机号而自动认领。
 
 ### 7.4 查询用户订单列表
@@ -842,7 +908,7 @@ POST /system/address/{id}/top
 | token 已过期 | 登录态失效 | 清理登录态并重新登录 |
 | 对应取件时段暂无可用运价 | 立即时刻或预约开始时刻没有匹配统一运价 | 重新选择取件时间或稍后重试 |
 | 报价已变化,请重新确认最新费用 | 运价版本、路线或费用与创建请求回传值不一致 | 用响应 `data` 刷新费用并让用户再次确认 |
-| 物品数量、总重量或规格信息不正确 | 数量非正整数、重量不在 0 至 20kg 或规格过长 | 返回物品信息页修正 |
+| 物品数量、总重量或规格信息不正确 | 数量非正整数、重量不大于 0、超过 20kg、小数超过两位或规格过长 | 返回物品信息页修正 |
 | 取件地址和收件地址不能相同 | 地址文本相同或经纬度完全相同 | 要求用户修改地址 |
 | 配送距离不能超过 40 公里 | 服务端路线距离超限 | 提示当前路线不可下单 |
 | 预约取件时段无效 | 时间已过、超过三天或不是 30 分钟 | 重新选择预约时段 |
@@ -859,7 +925,7 @@ POST /system/address/{id}/top
 - 首页只展示 `/home` 返回的当前时段可用服务,不在 App 中维护启停状态或默认价格。
 - 报价和创建订单都提交 `serviceType`、`deliveryType`、配送方式、完整物品信息、骑手小费及取送坐标。
 - 创建订单原样回传报价的配置 ID、版本、基础配送费、距离费、加急费和总金额;报价变化时展示最新明细并重新确认。
-- 金额按整数 TWD 展示,并分别显示基础配送费、距离费、加急费、骑手小费和总金额;不显示支付成功、骑手收入、时长费或尖峰费用。
+- 金额按整数 TWD 展示;`baseDeliveryFee` 已包含 `distanceFee`,距离费只作为基础配送费的明细展示,总金额只按 `baseDeliveryFee + urgentFee + tipAmount` 计算;不显示支付成功、骑手收入、时长费或尖峰费用。
 - 创建订单具备稳定的 `clientRequestId` 重试策略。
 - 预约时间满足未来三天内、固定 30 分钟的约束。
 - App 使用响应体 `code` 判断成功或失败。