对接文档去除上游概念,只展示商户对接平台

- 文档移除所有上游/发货平台/BFF 表述:接口字段说明、示例、推荐流程全部中性化
- 代码用户可见文案同步中性化:提交发货 message、错误提示、发货配置相关措辞
- 概述去掉 /api/open/v1 上游链路提示
This commit is contained in:
yml2213
2026-08-03 14:34:58 +08:00
parent f95075e2e4
commit 4019b657c4
3 changed files with 27 additions and 28 deletions
+12 -12
View File
@@ -231,7 +231,7 @@ func (s *DeliveryService) bindGood(gameAccount, goodID string) (*DeliveryBindRes
return nil, err return nil, err
} }
if out.BindUUID == "" || out.URL == "" { if out.BindUUID == "" || out.URL == "" {
return nil, errors.New("上游未返回绑定二维码") return nil, errors.New("绑定服务未返回绑定二维码")
} }
return &DeliveryBindResult{ return &DeliveryBindResult{
BindUUID: out.BindUUID, BindUUID: out.BindUUID,
@@ -284,7 +284,7 @@ func (s *DeliveryService) submit(orderNo, gameAccount, bindUUID string, apiClien
} }
// 已在上游创建正式订单的失败订单禁止自动重发,避免重复发货。 // 已在上游创建正式订单的失败订单禁止自动重发,避免重复发货。
if orderStatus == model.OrderStatusShipFailed && deliverySubmittedUpstream(order) { if orderStatus == model.OrderStatusShipFailed && deliverySubmittedUpstream(order) {
return nil, newDeliveryHTTPError(http.StatusConflict, "该订单已提交上游,为避免重复发货不能直接重试,请先在上游确认订单状态或联系平台处理") return nil, newDeliveryHTTPError(http.StatusConflict, "该订单已进入发货流程,为避免重复发货不能直接重试,请稍后查询订单状态或联系平台处理")
} }
if !info.CanShip { if !info.CanShip {
reason := info.CannotShipReason reason := info.CannotShipReason
@@ -351,10 +351,10 @@ func (s *DeliveryService) submit(orderNo, gameAccount, bindUUID string, apiClien
"upstream_order": upstreamOrder, "upstream_order": upstreamOrder,
}) })
nextStatus := model.OrderStatusDelivering nextStatus := model.OrderStatusDelivering
message := "已提交上游发货,等待发货结果回传" message := "已提交发货,等待发货结果回传"
if upstreamDeliverySucceeded(upstreamOrder) { if upstreamDeliverySucceeded(upstreamOrder) {
nextStatus = model.OrderStatusDelivered nextStatus = model.OrderStatusDelivered
message = "上游已返回发货成功" message = "发货已完成"
} }
updated, err := s.fulfillment.UpdateFulfillment(FulfillmentUpdateInput{ updated, err := s.fulfillment.UpdateFulfillment(FulfillmentUpdateInput{
MerchantID: order.MerchantID, MerchantID: order.MerchantID,
@@ -533,7 +533,7 @@ func (s *DeliveryService) buildDeliveryState(openOrder *OpenOrderQuery, order *m
goodID = deliveryGoodID(s.channel, openOrder.Product.SKU) goodID = deliveryGoodID(s.channel, openOrder.Product.SKU)
if goodID == "" { if goodID == "" {
canShip = false canShip = false
reason = "未找到对应的上游商品配置" reason = "未找到对应的商品发货配置"
} }
} }
if requireCanShip && !canShip { if requireCanShip && !canShip {
@@ -743,7 +743,7 @@ func (s *DeliveryService) prepareOrder(orderNo string, requireCanShip bool, auth
goodID = deliveryGoodID(s.channel, openOrder.Product.SKU) goodID = deliveryGoodID(s.channel, openOrder.Product.SKU)
if goodID == "" { if goodID == "" {
canShip = false canShip = false
reason = "未找到对应的上游商品配置" reason = "未找到对应的商品发货配置"
} }
} }
if requireCanShip && !canShip { if requireCanShip && !canShip {
@@ -892,11 +892,11 @@ func (s *DeliveryService) createOrderQueue(goodID, orderNo string) (string, erro
return "", err return "", err
} }
if len(out.Orders) == 0 { if len(out.Orders) == 0 {
return "", errors.New("上游未返回队列订单") return "", errors.New("发货服务未返回队列订单")
} }
orderID := firstNonEmpty(stringFromMap(out.Orders[0], "_id"), stringFromMap(out.Orders[0], "id")) orderID := firstNonEmpty(stringFromMap(out.Orders[0], "_id"), stringFromMap(out.Orders[0], "id"))
if orderID == "" { if orderID == "" {
return "", errors.New("上游未返回队列订单 ID") return "", errors.New("发货服务未返回队列订单 ID")
} }
return orderID, nil return orderID, nil
} }
@@ -945,7 +945,7 @@ func (s *DeliveryService) signProxy(path, method string, data interface{}, out i
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
resp, err := s.httpClient.Do(req) resp, err := s.httpClient.Do(req)
if err != nil { if err != nil {
return fmt.Errorf("上游请求失败:%w", err) return fmt.Errorf("发货服务请求失败:%w", err)
} }
defer resp.Body.Close() defer resp.Body.Close()
body, _ := io.ReadAll(io.LimitReader(resp.Body, 1<<20)) body, _ := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
@@ -955,19 +955,19 @@ func (s *DeliveryService) signProxy(path, method string, data interface{}, out i
Data json.RawMessage `json:"data"` Data json.RawMessage `json:"data"`
} }
if err := json.Unmarshal(body, &envelope); err != nil { if err := json.Unmarshal(body, &envelope); err != nil {
return fmt.Errorf("上游响应无法解析:%s", truncateDeliveryText(string(body))) return fmt.Errorf("发货服务响应无法解析:%s", truncateDeliveryText(string(body)))
} }
if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices || !isZeroCode(envelope.Code) { if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices || !isZeroCode(envelope.Code) {
if envelope.Message != "" { if envelope.Message != "" {
return errors.New(envelope.Message) return errors.New(envelope.Message)
} }
return fmt.Errorf("上游请求失败:HTTP %d", resp.StatusCode) return fmt.Errorf("发货服务请求失败:HTTP %d", resp.StatusCode)
} }
if out == nil || len(envelope.Data) == 0 || string(envelope.Data) == "null" { if out == nil || len(envelope.Data) == 0 || string(envelope.Data) == "null" {
return nil return nil
} }
if err := json.Unmarshal(envelope.Data, out); err != nil { if err := json.Unmarshal(envelope.Data, out); err != nil {
return fmt.Errorf("上游数据无法解析:%w", err) return fmt.Errorf("发货服务数据无法解析:%w", err)
} }
return nil return nil
} }
+11 -11
View File
@@ -42,8 +42,8 @@ const orderFields: ParamSpec[] = [
{ name: 'currency', type: 'string', desc: '货币,默认 POINT' }, { name: 'currency', type: 'string', desc: '货币,默认 POINT' },
{ name: 'buyer_reference', type: 'string', desc: '买家标识/备注' }, { name: 'buyer_reference', type: 'string', desc: '买家标识/备注' },
{ name: 'data', type: 'object', desc: '下单时透传的请求数据(原样回显)' }, { name: 'data', type: 'object', desc: '下单时透传的请求数据(原样回显)' },
{ name: 'result', type: 'object', desc: '发货平台回调的结果数据(原样回显)' }, { name: 'result', type: 'object', desc: '平台发货处理的结果数据(原样回显)' },
{ name: 'provider_order_no', type: 'string', desc: '发货平台侧单号' }, { name: 'provider_order_no', type: 'string', desc: '平台发货单号' },
{ name: 'failure_reason', type: 'string', desc: '最近一次失败原因' }, { name: 'failure_reason', type: 'string', desc: '最近一次失败原因' },
{ name: 'created_at', type: 'datetime', desc: '创建时间' }, { name: 'created_at', type: 'datetime', desc: '创建时间' },
{ name: 'delivered_at', type: 'datetime', desc: '交付时间' }, { name: 'delivered_at', type: 'datetime', desc: '交付时间' },
@@ -127,7 +127,7 @@ const deliverySubmitResponseExample = `{
"data": { "data": {
"order_no": "FO20260730000123", "order_no": "FO20260730000123",
"status": "delivering", "status": "delivering",
"message": "已提交上游发货,等待发货结果回传", "message": "已提交发货,等待发货结果回传",
"provider_order_no": "provider-1", "provider_order_no": "provider-1",
"game_account": { "game_account": {
"game_account": "4808146277", "game_account": "4808146277",
@@ -197,7 +197,7 @@ export const endpoints: EndpointSpec[] = [
{ name: 'sku', type: 'string', required: true, desc: '商品标识,取自商品列表', example: 'suit_pink_sheep' }, { name: 'sku', type: 'string', required: true, desc: '商品标识,取自商品列表', example: 'suit_pink_sheep' },
{ name: 'quantity', type: 'int', desc: '数量,默认 1', example: '1' }, { name: 'quantity', type: 'int', desc: '数量,默认 1', example: '1' },
{ name: 'buyer_reference', type: 'string', desc: '买家标识/备注', example: 'buyer-001' }, { name: 'buyer_reference', type: 'string', desc: '买家标识/备注', example: 'buyer-001' },
{ name: 'data', type: 'object', desc: '透传业务数据(最长 2048 字节)。自建发货页模式会原样返回给「查询发货数据」用于预填/展示;回调 payload 也会带回;约定字段 game_account/game_channel/role_name 会同步给上游查单' }, { name: 'data', type: 'object', desc: '透传业务数据(最长 2048 字节)。自建发货页模式会原样返回给「查询发货数据」用于预填/展示;回调 payload 也会带回;约定字段 game_account/game_channel/role_name 会用于发货处理' },
], ],
requestExample: `{ requestExample: `{
"client_order_no": "shop-10001", "client_order_no": "shop-10001",
@@ -319,7 +319,7 @@ export const endpoints: EndpointSpec[] = [
{ name: 'role_name', type: 'string', desc: '角色名' }, { name: 'role_name', type: 'string', desc: '角色名' },
{ name: 'pay_score', type: 'int', desc: '消耗积分' }, { name: 'pay_score', type: 'int', desc: '消耗积分' },
{ name: 'data', type: 'object', desc: '下单时透传的业务数据(原样返回,可用于预填玩家编号/展示区服)' }, { name: 'data', type: 'object', desc: '下单时透传的业务数据(原样返回,可用于预填玩家编号/展示区服)' },
{ name: 'good', type: 'object', desc: '上游商品详情' }, { name: 'good', type: 'object', desc: '商品展示详情' },
], ],
notes: [ notes: [
'该接口返回的是结构化数据,适合商户自有页面渲染。', '该接口返回的是结构化数据,适合商户自有页面渲染。',
@@ -356,7 +356,7 @@ export const endpoints: EndpointSpec[] = [
method: 'POST', method: 'POST',
path: '/api/client/v1/orders/{order_no}/delivery/submit', path: '/api/client/v1/orders/{order_no}/delivery/submit',
title: '提交发货', title: '提交发货',
summary: '提交发货到上游并进入发货中状态', summary: '提交发货并进入发货中状态',
scope: 'orders:write', scope: 'orders:write',
pathParams: [{ name: 'order_no', type: 'string', required: true, desc: '平台订单号', example: 'FO20260730000123' }], pathParams: [{ name: 'order_no', type: 'string', required: true, desc: '平台订单号', example: 'FO20260730000123' }],
bodyParams: [ bodyParams: [
@@ -372,13 +372,13 @@ export const endpoints: EndpointSpec[] = [
{ name: 'order_no', type: 'string', desc: '平台订单号' }, { name: 'order_no', type: 'string', desc: '平台订单号' },
{ name: 'status', type: 'string', desc: '提交后的订单状态' }, { name: 'status', type: 'string', desc: '提交后的订单状态' },
{ name: 'message', type: 'string', desc: '处理结果说明' }, { name: 'message', type: 'string', desc: '处理结果说明' },
{ name: 'provider_order_no', type: 'string', desc: '上游订单号' }, { name: 'provider_order_no', type: 'string', desc: '平台发货单号' },
{ name: 'game_account', type: 'object', desc: '上游绑定结果' }, { name: 'game_account', type: 'object', desc: '账号绑定结果' },
{ name: 'upstream_order', type: 'object', desc: '上游创建结果' }, { name: 'upstream_order', type: 'object', desc: '发货提交结果' },
], ],
notes: [ notes: [
'同一订单重复提交应直接返回已有结果,不应重复创建上游队列。', '同一订单重复提交应直接返回已有结果,不应重复发起发货。',
'提交成功后,最终成功/失败仍以 `ship_notify` 回传结果为准。', '提交成功后,最终成功/失败以平台发货结果回传为准。',
], ],
}, },
{ {
+4 -5
View File
@@ -308,7 +308,6 @@ function OverviewSection() {
API API / API API API / API
<Text code>X-App-Key</Text> + HMAC-SHA256 <Text code>X-App-Key</Text> + HMAC-SHA256
<Text code>/api/open/v1</Text> API
</> </>
} }
> >
@@ -472,7 +471,7 @@ const callbackEvents = [
{ {
event: 'order.shipping.updated', event: 'order.shipping.updated',
desc: '发货状态变化:提交发货(delivering)、发货成功(delivered)、发货失败(ship_failed', desc: '发货状态变化:提交发货(delivering)、发货成功(delivered)、发货失败(ship_failed',
trigger: '提交发货 / 上游回传发货结果', trigger: '提交发货 / 发货结果回传',
}, },
{ {
event: 'order.cancelled', event: 'order.cancelled',
@@ -724,11 +723,11 @@ function StatusSection() { return (
POST /orders 下单(client_order_no 幂等) POST /orders 下单(client_order_no 幂等)
拿响应里的 order_no 进入发货平台链接 拿响应里的 order_no 进入发货链接
发货平台查询订单并执行发货 买家在发货页绑定账号并提交发货
发货平台通过上游回调更新 order_status 平台完成发货处理并更新 order_status
GET /orders/{order_no} 轮询,或接收 order.shipping.updated 回调`}</pre> GET /orders/{order_no} 轮询,或接收 order.shipping.updated 回调`}</pre>
} }