# 权益平台 SDK v2

## 定位

面向合作商户的权益商城 SDK。终端用户看到的是商户自己的品牌与权益商城体验，平台方能力在后端完成产品、锁价、订单和履约支撑。

## 当前能力

- 自动城市识别
- 产品准入分层：可购买 / 可查看 / 即将开放 / 隐藏
- Flow Router：充值、门店、券码、电影、景区、加油、充电、票务等流程分流
- 后端 quote 锁价
- 创建待支付订单
- 商户会员身份透传：merchantMemberId / memberOpenId / memberMobile
- 我的订单按商户会员维度查询，不依赖浏览器本地缓存
- 订单详情与订单列表支持售后/退款状态展示与申请入口
- 跳转商户收银台：订单创建返回短期 token 化 `cashierUrl`，浏览器 URL 不暴露订单号、金额和签名
- 支持沙箱模式与正式模式开关

## 接入示例

```html
<div id="merchant-benefit-sdk"></div>
<link rel="stylesheet" href="/sdk/commercial-v2/commercial-v2.css">
<script src="/sdk/commercial-v2/commercial-v2-sdk.js"></script>
<script>
ChinaDaoCommercialV2.init({
  merchantId: '1',
  container: '#merchant-benefit-sdk',
  merchantName: '商户权益商城',
  apiBase: '/prod-api/openapi/v1',
  liveMode: true,
  merchantMemberId: '商户侧会员ID',
  memberOpenId: '微信openId/unionId，可选',
  memberMobile: '会员手机号，可选',
  memberSource: 'h5'
});
</script>
```



## 统一产品接口与智能路由

对外接入原则：下游客户只接中国道标准产品接口，不按服务通道分别适配。同一个产品即使存在多个服务通道，也保持统一请求字段、统一响应字段、统一订单状态、统一错误码和统一回调通知。

后台智能路由根据商户授权、产品配置、服务通道可用性、成本价、城市/资源覆盖、接口健康状态、履约成功率和风控策略，自动选择最合适的服务通道。下游文档不暴露服务方私有字段为必接字段，下游客户无需感知具体服务方。

| 标准产品 | 标准入口 | 后台路由能力 | 对外口径 |
| --- | --- | --- | --- |
| 电影票 | 中国道电影票标准接口 | 支持多服务通道路由 | 城市、影院、影片、场次、座位、报价、下单、查单字段保持统一；服务方差异由后台适配。 |
| 票务 | 中国道票务标准接口 | 支持当前及后续服务通道扩展 | 城市、航司/车次/票务资源、预订、查单、退款字段保持统一。 |
| 快递 | 中国道快递标准接口 | 支持当前及后续服务通道扩展 | 寄件、收件、重量、保价、价格、下单、轨迹字段保持统一。 |
| 打车 | 中国道打车标准接口 | 支持当前及后续服务通道扩展 | 起点、终点、车型、估价、下单、结算、查单字段保持统一。 |
| 生活服务 H5 | 中国道生活服务 H5 标准入口 | 支持多类生活服务通道路由 | 中国道校验商户授权后返回服务访问地址；客户只处理统一的跳转、订单、支付和回调结果。 |

内部系统可保留服务方名称用于成本、路由、运维和排障；开放平台、SDK 文档和商户接入文档统一使用“标准产品接口 / 服务通道 / 服务访问地址”等中性口径。

## H5 产品入口：返回服务访问地址

H5 类产品不是由中国道重新制作页面。标准链路是：商户服务端签名请求中国道接口，中国道校验授权、服务通道路由和服务端签名后，返回服务访问地址 `h5Url/url` 给商户。

完整商用文档请查看：[/openapi/h5-entry-guide.md](/openapi/h5-entry-guide.md)

### 服务端 OpenAPI 入口

```http
POST /openapi/v1/h5/entry
Content-Type: application/json
app_id: app_xxx
timestamp: 1783510000
nonce: random16
sign: HMAC_SHA256_BASE64URL
```

签名明文：

```text
METHOD + "
" + URI_PATH + "
" + timestamp + "
" + nonce + "
" + body
```

注意：公网请求路径带 `/prod-api`，但签名 `URI_PATH` 不带 `/prod-api`，应使用 `/openapi/v1/h5/entry`。

### 必填参数

| 字段 | 说明 |
|---|---|
| `typeCode` | 中国道产品编码 |
| `interfaceTypeCode` | 中国道接口产品编码 |
| `userId` | 商户侧用户唯一标识 |
| `phone` | 用户手机号 |

建议同时传 `outRequestNo`，便于后续用 `/openapi/v1/h5/query` 查询。

### 查询接口

```http
POST /openapi/v1/h5/query
```

`orderCreated=false` 表示用户尚未在 H5 内完成下单回调，属于正常状态。

### 常用产品编码

## 当前可申请的 H5 产品编码

| 产品 | typeCode | interfaceTypeCode | 说明 |
|---|---|---|---|
| 打车 H5 | `Taxi` | `taxi_interface` | H5 服务访问入口 |
| 叮咚买菜 H5 | `MarketDD` | `ding_dong_interface` | H5 服务访问入口 |
| 图书 H5 | `Book` | `book_v2_interface` | H5 服务访问入口 |
| 话费充值 H5 | `PrepaidRefill` | `directcharge_interface` | H5 服务访问入口 |
| 水电燃 H5 | `Weg` | `weg_interface` | H5 服务访问入口 |
| 美团外卖 H5 | `MeituanWaimai` | `mt_waimai_interface` | H5 服务访问入口 |
| 美团团购 H5 | `MeituanTuan` | `mt_canyin_interface` | H5 服务访问入口 |
| 小象超市 H5 | `FreshMart` | `mt_maicai_interface` | H5 服务访问入口 |
| 电影票 H5 | `MovieThree` | `movie_three_interface` | H5 服务访问入口 |
| 飞机票 H5 | `AirTicketH5` | `domestic_air_tickets_h5_interface` | H5 服务访问入口 |
| 火车票 H5 | `TrainH5` | `train_h5_interface` | H5 服务访问入口 |
| 京东 H5 | `MarketJDH5` | `jd_mall_h5_interface` | H5 服务访问入口 |
| 酒店 H5 | `HotelH5` | `hotel_h5_interface` | H5 服务访问入口 |

> 口径说明：以上编码表示当前开放平台 H5 入口可按商户授权申请服务访问地址；`/h5/entry` 返回地址不等于订单已创建或支付已完成。订单创建、支付确认、异步通知、退款/售后需按各产品业务链路单独验收。


## 服务通道接入状态

新增服务能力统一进入中国道后台服务通道路由池。对下游仍按中国道标准产品接口输出，不要求客户直接适配任何服务方私有字段。

- 电影票：API 标准产品，已接入城市、影院、影片、场次、座位、订单参数映射。
- 票务：API 标准产品，按中国道票务标准字段输出。
- 快递：API 标准产品，按中国道快递标准字段输出。
- 企业打车：H5 / API 标准产品，按中国道打车标准字段输出。
- 开放能力总入口：内部调试能力，仅用于内部接入验证；状态变更动作禁止通过公开查询入口直接触发。

## H5订单页获取接口

H5类权益由上游页面完成选品/下单后，商户侧仍需要能获取订单列表页和订单详情页，方便把“我的订单”“订单详情”嵌入自己的会员中心。SDK 已暴露两个 helper，底层对应开放接口：

```js
// 获取H5订单列表页
const orderPageUrl = await ChinaDaoCommercialV2.getH5OrderPageUrl({
  tenantCode: '租户编码',
  userId: '商户会员ID或手机号',
  interfaceTypeCode: 'H5对应的interfaceTypeCode',
  phone: '18988888888'
});

// 获取H5订单详情页
const orderInfoUrl = await ChinaDaoCommercialV2.getH5OrderInfoUrl({
  tenantCode: '租户编码',
  userId: '商户会员ID或手机号',
  interfaceTypeCode: 'H5对应的interfaceTypeCode',
  phone: '18988888888',
  channelOrderId: 'H5订单号'
});
```

对应服务端开放接口为 `POST /prod-api/biz/v1/getOrderPageUrl` 与 `POST /prod-api/biz/v1/getOrderInfoUrl`。`timestamp`、`nonceStr`、`sign` 由服务端按租户密钥生成；前端 SDK 不暴露密钥、不拼签名。

## 正式商用前必须完成

1. 配置商户品牌、Logo、主题色。
2. 配置商户域名白名单。
3. 配置商户收银台地址 cashierUrl；实际订单返回的 cashierUrl 只包含短期 `token=cst_xxx`，商户前端直接跳转，不解析、不拼接订单号/金额/签名参数。
4. 配置支付成功回调 notifyUrl；正式支付成功必须由商户服务端调用 `/sdk/payment/notify` 或 `/sdk/order-pay-notify` 签名确认，浏览器前端不能直接确认支付成功。
5. 关闭 sandboxMode。
6. 选定试点品类并完成真实履约验收。

## 收银台 URL 安全机制

`/sdk/order-create` 返回的 `cashierUrl` 已采用短期 token 模式，示例：

```text
/sdk/commercial-v2/merchant-cashier.html?token=cst_xxx
```

商户前端只需要跳转该地址；不要解析、保存或自行拼接 `merchantId/orderNo/quoteId/amount/timestamp/nonce/sign`。token 仅用于加载收银台展示信息，不代表支付成功。正式支付成功必须由商户服务端签名通知平台。

## 产品开放清单与准入规则

SDK 用户端只开放经过正式接口准入的权益。产品状态以 `product-admission.json` 为准，展示口径如下：

| 状态 | 用户端表现 | 开放条件 |
|---|---|---|
| 可购买 | 进入正式购买/预约/领取流程 | 已验证后端 query/quote/order-create 链路，金额以后端锁价快照为准 |
| 可查资源，暂不开放支付 | 可查看接入说明或资源状态，不进入支付 | 已有正式接口字段或资源查询，但服务通道授权、价格日历、订单履约或回调未完成 |
| 即将开放 | 仅展示能力规划，不进入购买弹窗 | 产品规划中，未进入正式联调 |
| 暂不可接入 | 展示不可接入原因，不提供临时跳转 | 缺少正式开放文档、签名/回调说明或属于非用户购买型能力 |

### 当前可购买产品

点餐外卖+到店、微信立减金、话费充值、移动充值、话费小额充值、影音会员、虚拟会员(无票版)、洗车、干洗、家政、洁牙、跑腿、途虎养车、快递、问诊、京东家政、蛋糕外卖、蛋糕、鲜花、大润发、叮咚买菜、京东、永辉超市、盒马、山姆会员商店、自营商超、自营商城2期、1688采购批发、天猫API、怡亚通、短剧、药品、积分焕彩、支付宝红包、景区门票、电影、酒店、银联支付、国际机票、团油加油。

### 当前可查/联调但暂不开放支付的产品

点餐、打车、打车V2、饿了么H5、图书、点餐(无票)、电影(无票)、电影V3、演出、丽呈酒店、锦江酒店、国际酒店、飞机票、InternationalAirTicket、火车票、TrainTicket、火车票标准版、汽车票、贵宾厅、柴油加油、永辉彩食鲜、ChargingStationOfficial、油站(中石油中石化)、油站V2、加油站、充电站、充电桩V2、充电桩API版、团油充电。

这些产品不得进入真实支付，原因包括服务通道未授权、沙箱可联调、选座/出票/履约链路待验收、价格日历或订单回调未完成。

### 即将开放产品

水电燃气、LifePayment、ShopMall、DiscountMall、MedicalCare。

### 暂不可接入产品

海底捞、美团外卖H5、美团团购H5、沃尔玛展码付、三方支付、实名、锅圈展码付、饿了么(开票版)、山姆展码付、中石化中石油展码付、夏商展码付、支付宝企业码、核销、大润发到店、小象超市H5。

这些产品缺少正式开放文档或不属于用户购买型权益，用户端不使用非正式地址、临时参数或前端伪跳转。



## 会员身份与我的订单

SDK 初始化时建议传入商户自有会员身份：

| 字段 | 说明 | 优先级 |
|---|---|---|
| `merchantMemberId` | 商户侧会员ID/用户ID | 最高 |
| `memberOpenId` | 微信 openId/unionId | 第二 |
| `memberMobile` | 会员手机号 | 兜底 |
| `memberName` | 会员昵称/姓名 | 可选 |
| `memberSource` | 来源，如 h5/wechat/miniapp/app | 可选 |

订单归属优先级：`merchantId + merchantMemberId` → `merchantId + memberOpenId` → `merchantId + memberMobile`。浏览器 `localStorage` 仅作为历史兜底，不作为正式订单归属依据。

我的订单接口示例：

```text
GET /prod-api/openapi/v1/sdk/order-list?merchantId=11&merchantMemberId=U10001
GET /prod-api/openapi/v1/sdk/order-list?merchantId=11&memberOpenId=oXxxx
GET /prod-api/openapi/v1/sdk/order-list?merchantId=11&memberMobile=13800138000
```

## 售后/退款

SDK v2 订单详情展示售后状态；符合条件的订单展示“申请退款/售后”按钮，并在提交前进行二次确认。退款申请只代表创建售后请求，实际退款需平台/商户按支付渠道、履约状态和风控规则审核处理。

## 异步通知与失败退款

平台会向商户 `notifyUrl` 推送 `ORDER_SUCCESS`、`ORDER_FAIL`、`ORDER_REFUND` 等事件。商户按 `orderNo + event` 幂等处理，重复通知不得重复发货或重复退款。

- `ORDER_FAIL + orderStatus=CLOSED + upstreamStatus=FAILED` 表示履约失败；若用户已在商户侧支付，商户需按原支付渠道退款给用户。
- `ORDER_REFUND + refundStatus=SUCCESS + refundAmount>0` 才表示退款完成。
- 单独 `orderStatus=CLOSED` 不等于退款成功，不得只凭 closed 自动退款。
- 商户返回 `SUCCESS` 或 HTTP 2xx 只代表接收通知成功，不代表用户侧退款完成。
