# 运单事件代码

根据当前环境的 `tracking` 字典表（有哪些状态码、客户是否可见）、TrackingEvent 键与本地化 `tracking.*` 描述文案在 https://api.superlabel.ca/api/documentation/tracking-events?lang=chs 实时生成，始终与本环境数据库一致。

## 事件侧别，不是订单类型

本字典**不是**订单类型列表。同一笔订单可以同时产生取件侧与配送侧事件——例如带取件环节的配送、点对点（双段）、多段转运、仓配交接等。即时配送使用单独字典（本页不列）。每条运单事件会打上**侧别**（取件侧或配送侧），用于匹配对应状态的描述文案与可见性。数值 `status_id` 与稳定 `key` 对应 API / Webhook 中的 `tracking_event_status_id` / `tracking_event_key`；请基于这些字段（以及需要时看侧别）做分支，不要用订单类型，也不要依赖本地化描述文本。

## 客户可见性（`tracking.visible`）

公开运单页与公开运单 API 仅展示字典行 `tracking.visible = 1` 的事件，并按状态码**与**事件侧别（与运单事件上标记的侧别一致）关联。下方标记为 **否** 的状态仍存在于系统中（Webhook、操作历史、内部工具），但不会出现在客户可见时间线。可见性从本部署的 `tracking` 表实时读取。

## 配送侧事件

运单事件落在行程**配送侧**（派送 / 末端段）时使用的状态。适用于纯配送、点对点的配送段、先取后派、多段转运等，**不限于**“纯配送订单”。**客户可见** 为本侧该状态的 `tracking.visible`。

| status_id | key | otep | otep phase | 客户可见 | description |
|---|---|---|---|---|---|
| 100 | `information_submitted` | `information_submitted` | `pre_shipment` | 是 | 您的寄件信息已提交。 |
| 110 | `booking_confirmed` | `booking_confirmed` | `pre_shipment` | 是 | 您的寄件已确认。 |
| 120 | `awaiting_pickup` | `awaiting_pickup` | `pre_shipment` | 是 | 您的包裹正在等待揽收。 |
| 200 | `pushed_successful` | — | — | 否 | 您的订单已提交路线规划。 |
| 201 | `pushed_failed` | — | — | 否 | 您的订单未能提交路线规划，将重试或重新安排。 |
| 300 | `received` | `received` | `inbound` | 是 | 您的包裹已安全抵达 {warehouse_name}。 |
| 301 | `arrival_scan` | `arrival_scan` | `inbound` | 是 | 您的包裹已完成揽收，并送达 {warehouse_name}。 |
| 400 | `planned` | `in_transit` | `transit` | 否 | 您的包裹已装车，准备派送。 |
| 401 | `removed_from_route` | `removed_from_route` | `exception` | 否 | 您的配送计划即将重新安排，请等待更新通知。 |
| 402 | `route_cancelled` | `route_cancelled` | `exception` | 否 | 您的配送状态即将更新，请稍候。 |
| 430 | `in_transit` | `in_transit` | `transit` | 是 | 您的包裹正在运输途中。 |
| 431 | `on_hold` | `in_transit` | `transit` | 是 | 您的包裹暂时滞留,恢复运输后我们会第一时间更新。 |
| 432 | `customs_clearance` | `in_transit` | `transit` | 是 | 您的包裹正在清关中。 |
| 433 | `loaded` | `package_outbound` | `transit` | 是 | 您的包裹已装车,即将发出。 |
| 434 | `collection_on_hold` | `awaiting_pickup` | `pre_shipment` | 是 | 您的包裹揽收暂时受阻,我们会尽快更新。 |
| 435 | `facility_received` | `in_transit` | `transit` | 是 | 您的包裹已被中转站点接收。 |
| 436 | `arrived_at_facility` | `in_transit` | `transit` | 是 | 您的包裹已到达中转站点。 |
| 450 | `start_delivery` | `out_for_delivery` | `out_for_delivery` | 是 | 您的包裹正在派送途中。 |
| 470 | `at_device` | `awaiting_pickup` | `pre_shipment` | 是 | 您的包裹已放入自助柜，等待您取件。 |
| 471 | `device_picked_up` | `delivered` | `delivered` | 是 | 您的包裹已从自助柜取出。 |
| 472 | `device_expired` | `awaiting_pickup` | `pre_shipment` | 是 | 您的包裹未在截止时间前取出，仍在自助柜中。 |
| 473 | `device_removed` | `received` | `inbound` | 是 | 您的包裹已由工作人员从自助柜中取出。 |
| 500 | `deliver_success` | `delivered` | `delivered` | 是 | 您的包裹已成功送达，感谢您的使用！ |
| 501 | `need_rescheduled` | `delivery_rescheduled` | `exception` | 是 | 很抱歉，我们未能成功派送您的包裹。 |
| 502 | `redelivered_later` | `delivery_rescheduled` | `exception` | 是 | 很抱歉，我们未能成功派送您的包裹。 |
| 503 | `not_delivered` | `delivery_failed` | `exception` | 是 | 您的配送过程中出现问题，请联系客服解决。 |
| 504 | `partial_deliver_success` | — | — | 是 | 本包裹已送达，其余包裹仍在派送途中。 |
| 510 | `pickuped` | `picked_up` | `pickup` | 是 | 包裹已被我们的快递员成功取走。 |
| 800 | `package_outbound` | `package_outbound` | `transit` | 是 | 您的包裹已从 {warehouse_name} 出库。 |

## 取件侧事件

运单事件落在行程**取件侧**（揽收 / 取件段）时使用的状态。适用于纯取件、点对点的取件段、先取后派、多段转运等，**不限于**“纯取件订单”。**客户可见** 为本侧该状态的 `tracking.visible`。

| status_id | key | otep | otep phase | 客户可见 | description |
|---|---|---|---|---|---|
| 100 | `information_submitted` | `information_submitted` | `pre_shipment` | 是 | 您的寄件请求已成功提交。 |
| 110 | `booking_confirmed` | `booking_confirmed` | `pre_shipment` | 是 | 您的取件请求已确认。 |
| 120 | `awaiting_pickup` | `awaiting_pickup` | `pre_shipment` | 是 | 您的包裹正在等待揽收。 |
| 200 | `pushed_successful` | — | — | 否 | 您的取件订单已提交路线规划。 |
| 201 | `pushed_failed` | — | — | 否 | 您的取件订单未能提交路线规划，将重试或重新安排。 |
| 300 | `received` | `received` | `inbound` | 是 | 您的包裹已成功入库。 |
| 301 | `arrival_scan` | `arrival_scan` | `inbound` | 是 | Order a-scan |
| 400 | `planned` | `in_transit` | `transit` | 否 | 您的包裹正在处理中。 |
| 401 | `removed_from_route` | `removed_from_route` | `exception` | 否 | 您的取件计划即将重新安排，请等待通知。 |
| 402 | `route_cancelled` | `route_cancelled` | `exception` | 否 | 您的取件状态即将更新，请稍候。 |
| 430 | `in_transit` | `in_transit` | `transit` | 是 | 您的包裹正在运输途中。 |
| 431 | `on_hold` | `in_transit` | `transit` | 是 | 您的包裹暂时滞留,恢复运输后我们会第一时间更新。 |
| 432 | `customs_clearance` | `in_transit` | `transit` | 是 | 您的包裹正在清关中。 |
| 433 | `loaded` | `package_outbound` | `transit` | 是 | 您的包裹已装车,即将发出。 |
| 434 | `collection_on_hold` | `awaiting_pickup` | `pre_shipment` | 是 | 您的包裹揽收暂时受阻,我们会尽快更新。 |
| 435 | `facility_received` | `in_transit` | `transit` | 是 | 您的包裹已被中转站点接收。 |
| 436 | `arrived_at_facility` | `in_transit` | `transit` | 是 | 您的包裹已到达中转站点。 |
| 450 | `start_delivery` | `out_for_delivery` | `out_for_delivery` | 是 | 快递员正在前往取件，请准备好您的包裹。 |
| 470 | `at_device` | `awaiting_pickup` | `pre_shipment` | 是 | 您的包裹已放入自助柜，等待您取件。 |
| 471 | `device_picked_up` | `delivered` | `delivered` | 是 | 您的包裹已从自助柜取出。 |
| 472 | `device_expired` | `awaiting_pickup` | `pre_shipment` | 是 | 您的包裹未在截止时间前取出，仍在自助柜中。 |
| 473 | `device_removed` | `received` | `inbound` | 是 | 您的包裹已由工作人员从自助柜中取出。 |
| 500 | `deliver_success` | `delivered` | `delivered` | 是 | 您的包裹已成功取件。 |
| 501 | `need_rescheduled` | `delivery_rescheduled` | `exception` | 是 | 您的取件已重新安排，我们稍后将通知您新的取件时间。 |
| 502 | `redelivered_later` | `delivery_rescheduled` | `exception` | 是 | 您的取件已重新安排，我们稍后将通知您新的取件时间。 |
| 503 | `not_delivered` | `delivery_failed` | `exception` | 是 | 您的包裹出现问题，请联系客服解决。 |
| 504 | `partial_deliver_success` | — | — | 是 | 本包裹已取件，其余包裹仍在等待取件。 |
| 510 | `pickuped` | `picked_up` | `pickup` | 是 | 您的包裹已成功取件。 |
| 800 | `package_outbound` | `package_outbound` | `transit` | 是 | 您的包裹已从 {warehouse_name} 出库。 |

**otep** / **otep phase** 列由 `OTEPStatusInput::FROM_TRACKING_EVENT` 与 `PHASES` 实时生成——与公开运单 API 在事件上写入的 `otep_status` 同源。破折号（—）表示该内部状态在 parcel 配置文件中无对应 OTEP 代码（例如路线推送 200/201）；事件仍会落库，且在 `visible = 1` 时仍可能对客户可见。

## 用公开运单 API 自建跟踪页

使用**公开运单查询 API** 即可在自己的网站或 App 上做品牌化跟踪页——无需登录、无需 API Token。同一接口支撑内置跟踪页与 GraphQL `trackingPublic`。请结合本页的状态字典（代码、可见性、OTEP）与下方流转规律使用。

### 1. 调用公开接口

按运单号一次 GET 即可。可查 Superroute 运单号、外部运单号，以及部分未绑定第三方服务商的三方运单号。

```
GET https://api.superlabel.ca/api/v1/tracking/{tracking_number}
```

- No authentication — public, rate-limited with the rest of the API.
- Path parameter: the Superroute tracking number, external tracking number, or (when applicable) third-party tracking number without a third-party provider id.
- HTTP **200** with `"result": true` when found; **404** with `"result": false` when not found or the order is cancelled.

### 2. 选择描述语言

事件的 `description` 文案随请求语言变化，通过 `Accept-Language` 请求头设置（API 语言中间件）。可发送项目语言码如 `en`、`chs`、`cht`、`de` 等，或常见别名如 `zh-CN` → 简体中文。未提供或无法识别时使用默认语言。

```
Accept-Language: chs
Accept-Language: zh-CN
Accept-Language: de
```

### 3. 需要渲染的响应字段

仅返回公开面数据——**不包含**寄件人/收件人完整地址（那些只在需登录的内部跟踪接口中出现）。

| field | meaning |
|---|---|
| `result` | `true` when a live order was found |
| `data` | Event timeline (newest first) |
| `data[].tracking_event_status_id` | Numeric code — match the dictionary on this page |
| `data[].otep_status` | Open tracking code when mapped (same bridge as the **otep** column) |
| `data[].description` | Localized customer text for this event |
| `data[].updated_at` / `timestamp` / `updated_at_localized` | When it happened (UTC string, unix, local clock) |
| `data[].location_*` / `operation_location` | Where it happened, when known |
| `data[].reason` | Public return/failure reason text when present |
| `deliveried` / `returntosender` / `rejectedbyrecipient` | Coarse final-state flags for header chips |
| `postcode` | Normalized delivery postcode (for POD gate on your side if you need it) |
| `proofs[]` | Signature / photo files (`url`, `full_url`, `signed_url`, `type`, `file_id`) |
| `is_third_party_tracking` / `third_party_info` | Present when a label/carrier timeline was merged in |

### 4. 推荐界面流程

1. 从访客处取得运单号，调用公开 GET 接口（可选带 `Accept-Language`）。
2. 若 `result` 为 false 或 HTTP 为 404，展示未找到并结束。
3. 用 `data[0]`（最新事件）做页眉状态：人类可读文案优先用 `description`；图标/进度逻辑用 `tracking_event_status_id` 或 `otep_status`。
4. 将完整 `data` 列表渲染为时间线（已是新→旧）。仅在必要时分组或过滤——不要编造未发生的节点。
5. 若 `proofs` 非空且最新状态为成功节点（通常 500 或 510），提供“查看签收证明”；需要时效链接用 `signed_url`，需要本站永久路径用 `full_url`。

### 5. 进度条 / 步骤条

**不要**为所有包裹写死同一条链路。请对照本页字典与流转规律：多数末端配送为 100 → 300/301 → 450 → 500；双段行程会先出现取件侧 460 → 510。请按 `otep_status`（稳定开放代码）或 `tracking_event_status_id` 分支；出现异常或纠正时以最新事件为准。

### 6. 签收证明

`proofs[]` 在可用时携带照片/签名元数据。你的页面仍可选择用邮编校验后再展示（内置跟踪页为保护隐私会这样做）；接口返回规范化的 `postcode` 字段供此用途。切勿在完全公开的页面上展示完整收件街道地址——本接口有意省略这些字段。

### 7. 相关公开接口

按技术栈选择合适入口。除非 API 文档另有说明，下列均为公开接口（无需 Token）。

| surface | when to use |
|---|---|
| `GET https://api.superlabel.ca/api/v1/tracking/{tracking_number}` | Default branded tracking page (this guide) |
| GraphQL `trackingPublic(trackingNumber: …)` at `https://api.superlabel.ca/graphql` | Same payload when your stack is GraphQL-first |
| `GET https://api.superlabel.ca/api/v1/otep/trackings/{tracking_number}` | Vendor-neutral OTEP timeline / EPCIS / ONE Record / UN-CEFACT projections |

### 8. 最小示例

```bash
curl -sS -H "Accept-Language: en" \
  "https://api.superlabel.ca/api/v1/tracking/SR1234567890"
```

```javascript
const res = await fetch(`https://api.superlabel.ca/api/v1/tracking/${encodeURIComponent(tn)}`, {
  headers: { "Accept-Language": "chs" },
});
const body = await res.json();
if (!body.result) {
  // show "not found"
} else {
  const events = body.data || [];          // newest first
  const latest = events[0];
  const proofs = body.proofs || [];
  // render latest.description, map latest.tracking_event_status_id or otep_status for the stepper
}
```

## 常见运单流转规律

以下是**典型路径**，不是强制状态机。真实时间线会跳过步骤（例如无入库扫描）、插入异常，或在同一订单上交错出现取件侧与配送侧事件。数字为 `tracking_event_status_id`；公开时间线仅展示 `tracking.visible = 1` 的行（见上方表格）。集成请按 `status_id` / `key` 分支，并以最新事件（id 最大）为准。

### 入仓 → 末端配送

最常见的自有运力路径：下单 → 包裹入仓 → 司机开始派送 → 成功或配送异常。规划类代码如 400/401/402 可能在字典中存在，但通常**不对客户可见**。

```mermaid
flowchart LR
  s100["100 information_submitted"] --> s300["300 received / 301 arrival_scan"]
  s300 --> s450["450 start_delivery"]
  s450 --> s500["500 deliver_success"]
  s450 --> s501["501 need_rescheduled"]
  s450 --> s502["502 redelivered_later"]
  s450 --> s503["503 not_delivered"]
  s450 --> s700["700 rejected_by_recipient"]
  s501 --> s450
  s502 --> s450
```

### 揽收 / 纯取件段

司机外出取件，记录取件成功（可带签收证明）或取件异常。纯取件订单停留在取件侧；双段行程在 510 之后进入配送侧序列。

```mermaid
flowchart LR
  s100["100 information_submitted"] --> s460["460 start_pickup"]
  s460 --> s510["510 pickuped"]
  s460 --> s512["512 repickup_later"]
  s460 --> s513["513 not_pickuped"]
  s512 --> s460
```

### 双段行程（先取后派）

适用于一次行程既有揽收又有送达——例如带取件的配送、点对点、以及多数多段转运。时间线通常先出现**取件侧**节点（460 → 510），再出现**配送侧**节点（450 → 500）。描述文案由事件侧别选择，不是由订单类型选择。

```mermaid
flowchart LR
  s100["100 information_submitted"] --> pickup["Pickup-side: 460 → 510"]
  pickup --> delivery["Delivery-side: 450 → 500"]
  pickup --> pFail["Pickup exception: 512 / 513"]
  delivery --> dFail["Delivery exception: 501 / 502 / 503 / 700"]
```

### 第三方 / 承运商履约

承运商下单可能产生 110/120；产品策略将其在公开时间线**隐藏**，使第三方与自营体验一致。之后可见节点与仓配+末端一致（300/301 → 800 出库 → 450 → 500）。承运商终态取消使用 403（不是 402；402 仅用于自营改派/路线取消）。

```mermaid
flowchart LR
  s100["100 information_submitted"] --> s110["110 / 120 hidden on public timeline"]
  s110 --> s300["300 / 301 warehouse"]
  s300 --> s800["800 package_outbound"]
  s800 --> s450["450 start_delivery"]
  s450 --> s500["500 deliver_success"]
  s450 --> sFail["501 / 503 / 600 / 700"]
```

### 即时配送（任务调度）

使用独立字典（不在上方取件/配送侧表中列出）。主路径：已提交 → 分配骑手 → 前往取件 → 已取件 → 派送中 → 已送达。改派（411）与分配取消（412）可在开跑前循环；失败后的改期使用 501。

```mermaid
flowchart LR
  s100["100 information_submitted"] --> s410["410 rider_assigned"]
  s410 --> s411["411 reassigned optional"]
  s410 --> s412["412 assignment_cancelled"]
  s412 --> s410
  s410 --> s460["460 start_pickup"]
  s460 --> s510["510 pickuped"]
  s510 --> s450["450 start_delivery"]
  s450 --> s500["500 deliver_success"]
  s450 --> s501["501 need_rescheduled"]
```

### 异常与终态代码（速查）

| status_id | key | 常见含义 |\n|---|---|---|\n| 501 | need_rescheduled | 配送失败，需重新计划 |\n| 502 | redelivered_later | 同路线稍后重试 |\n| 503 | not_delivered | 配送异常 / 投递失败 |\n| 512 | repickup_later | 取件失败，稍后重试 |\n| 513 | not_pickuped | 取件异常 |\n| 600 | return_to_sender | 退回寄件人 |\n| 700 | rejected_by_recipient | 收件人拒收 |\n| 403 | cancelled | 终态取消（区别于 402 路线取消） |\n| 402 | route_cancelled | 路线取消 / 改派（通常不对客户可见） |

### 集成方经验法则

1. 客户最关心的主路径锚点：**100** 已创建、**300/301** 已入仓、**450** 派送中、**500** 已送达；揽收段为 **460** 外出取件、**510** 已取件。
2. 不要假设固定完整链条——入库扫描可选、第三方中转（800）、双段侧别切换都很常见。
3. 异常（501–503、512–513、600、700）可出现在「外出…」之后；重新计划后订单可能再次进入 450/460。
4. 公开页忽略不可见字典行；Webhook 与内部工具仍可能收到。纠正或撤销先前成功时，始终以最新事件 id 为准。

诸如 `{warehouse_name}` 的占位符会在运行时替换为真实仓库或地点名称。新字典行与可见性变更通过迁移发布；本页每次请求重新读取表，不会相对本环境过期。