200 lines
6.8 KiB
Markdown
200 lines
6.8 KiB
Markdown
|
<!-- Space: qifu -->
|
|||
|
<!-- Parent: 后端技术&知识&规范 -->
|
|||
|
<!-- Parent: 技术方案 -->
|
|||
|
<!-- Parent: 基建 -->
|
|||
|
<!-- Parent: 03-接入指南 -->
|
|||
|
<!-- Parent: 0301-电商接入指南 -->
|
|||
|
<!-- Title: 20250515-电商订单对接指南 -->
|
|||
|
|
|||
|
<!-- Macro: :anchor\((.*)\):
|
|||
|
Template: ac:anchor
|
|||
|
Anchor: ${1} -->
|
|||
|
<!-- Macro: \!\[.*\]\((.+)\)\<\!\-\- width=(.*) \-\-\>
|
|||
|
Template: ac:image
|
|||
|
Url: ${1}
|
|||
|
Width: ${2} -->
|
|||
|
<!-- Macro: \<\!\-\- :toc: \-\-\>
|
|||
|
Template: ac:toc
|
|||
|
Printable: 'false'
|
|||
|
MinLevel: 2
|
|||
|
MaxLevel: 4 -->
|
|||
|
<!-- Include: 杂项/声明文件.md -->
|
|||
|
|
|||
|
<!-- :toc: -->
|
|||
|
|
|||
|
# 电商订单对接指南
|
|||
|
|
|||
|
- eBay 接入指南可以查看:http://confluence.qifu.com/pages/viewpage.action?pageId=38511846
|
|||
|
- TikTok 接入指南可以查看:http://confluence.qifu.com/pages/viewpage.action?pageId=38512736
|
|||
|
- Amazon 接入指南可以查看:http://confluence.qifu.com/pages/viewpage.action?pageId=38512738
|
|||
|
- Lazada 接入指南可以查看:http://confluence.qifu.com/pages/viewpage.action?pageId=38512740
|
|||
|
|
|||
|
## 使用南北流量网关对接电商平台
|
|||
|
|
|||
|
### 接口交互流程
|
|||
|
|
|||
|
#### 电商用户授权流程
|
|||
|
|
|||
|

|
|||
|
|
|||
|
#### 接口交互流程
|
|||
|
|
|||
|

|
|||
|
|
|||
|
### 添加依赖
|
|||
|
|
|||
|
```xml
|
|||
|
|
|||
|
<dependencys>
|
|||
|
<!-- RPC接口 -->
|
|||
|
<dependency>
|
|||
|
<groupId>com.yuanmeng.qifu</groupId>
|
|||
|
<artifactId>qifu-saas-eg-client</artifactId>
|
|||
|
<version>1.0.13</version>
|
|||
|
</dependency>
|
|||
|
|
|||
|
<!-- SPI接收订单同步信息 -->
|
|||
|
<dependency>
|
|||
|
<groupId>com.yuanmeng.qifu</groupId>
|
|||
|
<artifactId>qifu-saas-eg-spi</artifactId>
|
|||
|
<version>1.0.13</version>
|
|||
|
</dependency>
|
|||
|
</dependencys>
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
### 注册SPI服务(注册之后才会有 webhook 请求)
|
|||
|
|
|||
|
#### spi包中包含的自动注册
|
|||
|
|
|||
|
- qifu-saas-eg-spi 已经整合了自动注册功能。
|
|||
|
- 默认以 spring.application.name 作为服务名在程序启动时发起注册
|
|||
|
- 可以做特殊配置:
|
|||
|
- ```yaml
|
|||
|
qifu:
|
|||
|
eg:
|
|||
|
spi:
|
|||
|
enable: true
|
|||
|
enable-spi-register: true
|
|||
|
spi-infos:
|
|||
|
- type: 1
|
|||
|
server-code: ${spring.application.name}
|
|||
|
server-name: ${spring.application.name}
|
|||
|
server-description: '测试服务'
|
|||
|
```
|
|||
|
- type:1=订单同步SPI
|
|||
|
- server-code:唯一标识,卖家授权的时候使用
|
|||
|
- server-name:服务名称,SPI feign调用服务名
|
|||
|
|
|||
|
#### 手动注册
|
|||
|
|
|||
|
- 使用 `RemoteSpiService.addSpi` 来进行注册
|
|||
|
- 可以关闭自动注册
|
|||
|
- ```yaml
|
|||
|
qifu:
|
|||
|
eg:
|
|||
|
spi:
|
|||
|
enable-spi-register: false
|
|||
|
```
|
|||
|
|
|||
|
### 卖家授权(必须)
|
|||
|
|
|||
|
#### 第一步:关联卖家授权应用(必须)
|
|||
|
|
|||
|
- `RemoteOrderService.linkApp(channel, sellerId, region, orderAppId, spiServerCodes)`
|
|||
|
- channel`(required)`: 渠道,参考 `OrderChannelEnum` code字段
|
|||
|
- sellerId`(required)`:卖家id,卖家唯一标识,业务自定义
|
|||
|
- region`(required)`:所属区域,请看 `RemoteOrderService.linkApp()` 接口文档注释
|
|||
|
- orderAppId`(optional)`:关联的授权应用,没传由系统负载获取
|
|||
|
- spiServerCodes`(optional)`:spi回调应用编码,多个用, 分割,没有时不会做 webhook
|
|||
|
- **示例:**
|
|||
|
- ```shell
|
|||
|
curl -X POST --location "http://localhost:8933/order/app/link?channel=4&sellerId=keyfil001®ion=Vietnam" \
|
|||
|
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYmYiOjE3MzEzODIxNzksInRlbmFudElkIjo3LCJuaWNrbmFtZSI6IuWImOaZk-WNjiIsImV4cCI6MTczMTQyNTM3OSwiaWF0IjoxNzMxMzgyMTc5LCJ1c2VySWQiOjEzODM3MjksImp0aSI6ImYyMzQ1NDgxNWQ0NTRkNzk4MGQ2ZjQwMGQ2NWFlMzBkIn0.QjFcqlGACbR9VZXEyQhmuP-JTJTT7ILmP8FeNdGJcJI"
|
|||
|
```
|
|||
|
|
|||
|
#### 获取授权链接(必须)
|
|||
|
|
|||
|
- `RemoteOrderService.authAuthorizeUrl(Integer channel, String sellerId)`
|
|||
|
- **示例:**
|
|||
|
- ```shell
|
|||
|
curl -X GET --location "http://localhost:8933/order/oauth/authorize?channel=4&sellerId=keyfil001" \
|
|||
|
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYmYiOjE3MzEzODIxNzksInRlbmFudElkIjo3LCJuaWNrbmFtZSI6IuWImOaZk-WNjiIsImV4cCI6MTczMTQyNTM3OSwiaWF0IjoxNzMxMzgyMTc5LCJ1c2VySWQiOjEzODM3MjksImp0aSI6ImYyMzQ1NDgxNWQ0NTRkNzk4MGQ2ZjQwMGQ2NWFlMzBkIn0.QjFcqlGACbR9VZXEyQhmuP-JTJTT7ILmP8FeNdGJcJI"
|
|||
|
```
|
|||
|
|
|||
|
#### 获取accessToken(回调链接为业务链接时必须)
|
|||
|
|
|||
|
-
|
|||
|
`RemoteOrderService.authAccessToken(Integer channel, String appName, String code, String spapiOauthCode, String shopId, String mainAccountId, String state)`
|
|||
|
- **示例:**
|
|||
|
- ```shell
|
|||
|
curl -X GET --location "http://localhost:8933/open/order/oauth/callback/4?code=0_132783_8fmfr7mGBVhjyFt7aycC8R784464&state=1922598474703364098"
|
|||
|
```
|
|||
|
|
|||
|
#### 授权状态(必须)(快过期时提醒用户重新授权)
|
|||
|
|
|||
|
- **在授权后需要查询授权状态,授权状态快过期时需要提醒用户重新授权**
|
|||
|
- `RemoteOrderService.oauthStatus(Integer channel, String sellerId)`
|
|||
|
- **示例:**
|
|||
|
- ```shell
|
|||
|
curl -X GET --location "http://localhost:8933/order/oauth/status?channel=4&sellerId=keyfil001"
|
|||
|
```
|
|||
|
|
|||
|
#### 手动同步(可选)
|
|||
|
|
|||
|
- 手动触发订单同步操作
|
|||
|
- `RemoteOrderService.syncOrder(OrderSyncReq req)`
|
|||
|
- **示例:**
|
|||
|
- ```shell
|
|||
|
curl -X POST --location "http://localhost:8933/order/sync" \
|
|||
|
-H "Content-Type: application/json" \
|
|||
|
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYmYiOjE3MzEzODIxNzksInRlbmFudElkIjo3LCJuaWNrbmFtZSI6IuWImOaZk-WNjiIsImV4cCI6MTczMTQyNTM3OSwiaWF0IjoxNzMxMzgyMTc5LCJ1c2VySWQiOjEzODM3MjksImp0aSI6ImYyMzQ1NDgxNWQ0NTRkNzk4MGQ2ZjQwMGQ2NWFlMzBkIn0.QjFcqlGACbR9VZXEyQhmuP-JTJTT7ILmP8FeNdGJcJI" \
|
|||
|
-d '{
|
|||
|
"channel": 4,
|
|||
|
"sellerId": "keyfil001",
|
|||
|
"startTimeMillis": 1742529814000
|
|||
|
}'
|
|||
|
```
|
|||
|
|
|||
|
#### 自动同步
|
|||
|
|
|||
|
- 每一个小时会进行一次订单同步。cron:`0 0 0/1 * * ?`
|
|||
|
|
|||
|
### 编写SPI处理逻辑
|
|||
|
|
|||
|
#### 开放接口
|
|||
|
|
|||
|
- SPI通过自动注册接口 `/sync/order/change` 来实现 webhook 请求接收
|
|||
|
- 需要程序开放 `/sync/order/change` 接口供 `qifu-saas-eg` 回调使用
|
|||
|
|
|||
|
#### 编写回调信息处理逻辑
|
|||
|
|
|||
|
- 实现 `OrderSyncHandler`
|
|||
|
- **示例:**
|
|||
|
- ```java
|
|||
|
@Slf4j
|
|||
|
@Component
|
|||
|
public class OrderSyncHandlerImpl implements OrderSyncHandler {
|
|||
|
|
|||
|
@Override
|
|||
|
public Boolean handle(SpiOrderReq req) {
|
|||
|
log.info("channel: {}", req.getChannel());
|
|||
|
log.info("sellerId: {}", req.getSellerId());
|
|||
|
log.info("orders: {}", req.getSpiOrders());
|
|||
|
|
|||
|
for (SpiOrderReq.SpiOrder spiOrder : req.getSpiOrders()) {
|
|||
|
if (spiOrder.getOldOrder() == null) {
|
|||
|
// TODO 新订单处理逻辑
|
|||
|
log.info("new order handler: order info: {}", spiOrder.getNewOrder());
|
|||
|
|
|||
|
} else {
|
|||
|
// TODO 更新订单逻辑
|
|||
|
log.info("update order handler: old order info: {}", spiOrder.getOldOrder());
|
|||
|
log.info("update order handler: new order info: {}", spiOrder.getNewOrder());
|
|||
|
}
|
|||
|
}
|
|||
|
return Boolean.TRUE;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
```
|