Initial commit: workspace files including MEMORY.md, skills, and core configs
This commit is contained in:
48
skills/irun-yidianhuo/SKILL.md
Normal file
48
skills/irun-yidianhuo/SKILL.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# 铱云易订货 OpenAPI 助手
|
||||
|
||||
## 模块索引
|
||||
|
||||
本技能分散为多个文件,按模块管理:
|
||||
|
||||
| 模块 | 文件 | 说明 |
|
||||
|------|------|------|
|
||||
| 认证与通用 | `common.md` | 获取 token、基础调用方式 |
|
||||
| 基础数据 | `basics.md` | 仓库、员工、单位、分类、品牌、区域等 |
|
||||
| 客户 | `customer.md` | 客户查询(分类、列表、收货地址) |
|
||||
| 商品 | `product.md` | 商品查询(列表、分类、品牌、授权方案) |
|
||||
| 商品搜索(新版) | `product-suite.md` | 通过商品名称/编码搜索(用于下单前的商品信息查询) |
|
||||
| 订单 | `order.md` | 订单查询(含 withDetails 参数) |
|
||||
| **创建订单** | `create-order.md` | 根据客户+商品+数量创建订单 |
|
||||
| 库存 | `inventory.md` | 库存查询 |
|
||||
|
||||
## 触发条件
|
||||
|
||||
当用户表达以下任一意图时触发:
|
||||
- "查一下客户" / "客户列表"
|
||||
- "看看有哪些订单" / "今天的新订单"
|
||||
- "库存还剩多少" / "查库存"
|
||||
- "对一下账" / "收款记录"
|
||||
- "商品列表" / "有什么商品"
|
||||
- "员工" / "仓库" 等基础数据查询
|
||||
- "搜索商品" / "查一下XXX商品" / "帮我找XXX" / "这个商品的信息" 等商品搜索意图
|
||||
- "帮我下单" / "创建订单" / "录个订单" / "我要订货" 等下单意图
|
||||
|
||||
## 前置准备
|
||||
|
||||
### 获取 API 凭证
|
||||
|
||||
联系铱云易订货客服:**lgc@77ircloud.com**
|
||||
- `client_id`: 6767358
|
||||
- `client_secret`: 1gk9ApiWV8IA2QrVDnU6Dx7uUo7CLuN2
|
||||
- `userName`: 112983083
|
||||
- `password`: 77ircloud
|
||||
- API 地址: https://openapi.77ircloud.com
|
||||
- 文档站: http://openapi-doc.77ircloud.com/
|
||||
|
||||
### 调用方式
|
||||
|
||||
1. 先获取 access_token(有效期30天)
|
||||
2. 所有请求 header 必须包含 `access_token`
|
||||
3. POST 请求还需要 `Content-Type: application/json`
|
||||
|
||||
详细见 `common.md`
|
||||
6
skills/irun-yidianhuo/_meta.json
Normal file
6
skills/irun-yidianhuo/_meta.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"ownerId": "user-luoxiaocun",
|
||||
"slug": "irun-yidianhuo",
|
||||
"version": "1.0.0",
|
||||
"publishedAt": 1743033600000
|
||||
}
|
||||
205
skills/irun-yidianhuo/basics.md
Normal file
205
skills/irun-yidianhuo/basics.md
Normal file
@@ -0,0 +1,205 @@
|
||||
# 基础数据查询接口
|
||||
|
||||
## 1. 仓库列表
|
||||
|
||||
```
|
||||
GET https://openapi.77ircloud.com/invoicing-aggregation/warehouses
|
||||
```
|
||||
|
||||
**Header:** `access_token: {token}`
|
||||
|
||||
**返回:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"totalCount": 11,
|
||||
"currentPage": 1,
|
||||
"pageSize": 20,
|
||||
"totalPage": 1,
|
||||
"items": [
|
||||
{
|
||||
"id": 2116753909958624,
|
||||
"code": "00000001",
|
||||
"name": "总部仓库",
|
||||
"type": 1,
|
||||
"status": 1,
|
||||
"orgId": 3607084,
|
||||
"orgName": "总部"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**用途:** 查询仓库列表,取 `items[].id` 作为 `warehouseId`(库存查询必填)
|
||||
|
||||
---
|
||||
|
||||
## 2. 员工列表
|
||||
|
||||
```
|
||||
POST https://openapi.77ircloud.com/organization-aggregation/employees/search
|
||||
```
|
||||
|
||||
**Header:** `access_token: {token}` + `Content-Type: application/json`
|
||||
|
||||
**Body:**
|
||||
```json
|
||||
{"pageNum": 1, "pageSize": 20}
|
||||
```
|
||||
|
||||
**返回:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"items": [
|
||||
{"id": 22652291, "name": "周总", "phone": "136xxx", "role": "MANAGER"}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 商品单位列表
|
||||
|
||||
```
|
||||
GET https://openapi.77ircloud.com/product-aggregation/units
|
||||
```
|
||||
|
||||
**Header:** `access_token: {token}`
|
||||
|
||||
**返回:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": [
|
||||
{"id": 2116753910024416, "name": "个"},
|
||||
{"id": 2116753910040800, "name": "箱"},
|
||||
{"id": 2116753910057184, "name": "件"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 商品分类列表
|
||||
|
||||
```
|
||||
GET https://openapi.77ircloud.com/product-aggregation/categories
|
||||
```
|
||||
|
||||
**Header:** `access_token: {token}`
|
||||
|
||||
**返回:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": [
|
||||
{"id": 2116753909967072, "name": "通用", "parentId": 0},
|
||||
{"id": 2116766451460320, "name": "特价活动", "parentId": 0},
|
||||
{"id": 2116766567037824, "name": "水产生品类", "parentId": 0}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 商品品牌列表
|
||||
|
||||
```
|
||||
GET https://openapi.77ircloud.com/product-aggregation/brands
|
||||
```
|
||||
|
||||
**Header:** `access_token: {token}`
|
||||
|
||||
**返回:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": [
|
||||
{"id": 2116767916034272, "name": "意食客"},
|
||||
{"id": 2116767991238144, "name": "其他品牌"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 省市区域列表
|
||||
|
||||
```
|
||||
GET https://openapi.77ircloud.com/commondata/common/data/cities?parentId=0
|
||||
```
|
||||
|
||||
**Header:** `access_token: {token}`
|
||||
|
||||
**参数:**
|
||||
- `parentId`: 父级区域ID,传 `0` 获取省份列表
|
||||
|
||||
**返回:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": [
|
||||
{"id": 1, "cityId": 110100, "provinceId": 110000, "name": "北京市"},
|
||||
{"id": 2, "cityId": 120100, "provinceId": 120000, "name": "天津市"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 物流公司列表
|
||||
|
||||
```
|
||||
GET https://openapi.77ircloud.com/commondata/common/data/logistics-company
|
||||
```
|
||||
|
||||
**Header:** `access_token: {token}`
|
||||
|
||||
**返回:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": [
|
||||
{"id": 1, "name": "共速达", "code": "gongsuda", "phone": "400-111-0005"},
|
||||
{"id": 2, "name": "邮政EMS速递", "code": "ems"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 价格等级列表
|
||||
|
||||
```
|
||||
GET https://openapi.77ircloud.com/product-aggregation/level-prices
|
||||
```
|
||||
|
||||
**Header:** `access_token: {token}`
|
||||
|
||||
**返回:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": [
|
||||
{"id": 0, "name": "基准订货价(市场价)", "levelIndex": 0},
|
||||
{"id": 2116753910947264, "name": "尊宝配送价", "levelIndex": 1}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 组织信息
|
||||
|
||||
```
|
||||
GET https://openapi.77ircloud.com/organization-aggregation/organization/info
|
||||
```
|
||||
|
||||
**Header:** `access_token: {token}`
|
||||
|
||||
**返回:** 组织基本信息
|
||||
80
skills/irun-yidianhuo/common.md
Normal file
80
skills/irun-yidianhuo/common.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# 通用:认证与调用方式
|
||||
|
||||
## 获取 Access Token
|
||||
|
||||
**重要:路径和参数都经过实际验证,注意不是 POST!**
|
||||
|
||||
```
|
||||
GET https://openapi.77ircloud.com/v2/oauth2/token
|
||||
```
|
||||
|
||||
参数直接在 URL 查询字符串中:
|
||||
|
||||
```
|
||||
https://openapi.77ircloud.com/v2/oauth2/token?userName=112983083&password=77ircloud&client_id=6767358&client_secret=1gk9ApiWV8IA2QrVDnU6Dx7uUo7CLuN2&grant_type=client_credentials&scope=basic
|
||||
```
|
||||
|
||||
返回:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"access_token": "194557f72e5594557d796f216ae9f9fe3607084",
|
||||
"expires_in": 2592000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**注意**:
|
||||
- 是 GET 请求,不是 POST
|
||||
- 有效期 30 天,可复用,不必每次调用都刷新
|
||||
- token 过期后会返回非 200,重新获取即可
|
||||
|
||||
## 调用示例(Python)
|
||||
|
||||
```python
|
||||
import requests, json
|
||||
|
||||
# 获取 token
|
||||
def get_token():
|
||||
url = "https://openapi.77ircloud.com/v2/oauth2/token"
|
||||
params = {
|
||||
"userName": "112983083",
|
||||
"password": "77ircloud",
|
||||
"client_id": "6767358",
|
||||
"client_secret": "1gk9ApiWV8IA2QrVDnU6Dx7uUo7CLuN2",
|
||||
"grant_type": "client_credentials",
|
||||
"scope": "basic"
|
||||
}
|
||||
resp = requests.get(url, params=params)
|
||||
return resp.json()["data"]["access_token"]
|
||||
|
||||
# 调用 API
|
||||
token = get_token()
|
||||
headers = {"access_token": token}
|
||||
resp = requests.post(
|
||||
"https://openapi.77ircloud.com/order-aggregation/organizations/orders/search",
|
||||
headers=headers,
|
||||
json={"pageNum": 1, "pageSize": 10, "withDetails": True}
|
||||
)
|
||||
print(resp.json())
|
||||
```
|
||||
|
||||
## 通用请求 Header
|
||||
|
||||
所有 API 调用都必须包含:
|
||||
- `access_token: {token}` — 必须
|
||||
- `Content-Type: application/json` — POST 请求必须
|
||||
|
||||
## 通用返回格式
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {},
|
||||
"message": "操作成功"
|
||||
}
|
||||
```
|
||||
|
||||
- `code=200` 表示成功
|
||||
- `code≠200` 表示失败,检查 `message` 字段
|
||||
161
skills/irun-yidianhuo/create-order.md
Normal file
161
skills/irun-yidianhuo/create-order.md
Normal file
@@ -0,0 +1,161 @@
|
||||
# 创建订单
|
||||
|
||||
> 用户提供客户信息 + 商品信息(名称、单位、数量),自动完成订单创建。
|
||||
|
||||
## 触发条件
|
||||
|
||||
用户表达以下意图时触发:
|
||||
- "帮我下单" / "创建订单" / "录个订单"
|
||||
- "我要订货" / "订一批货"
|
||||
- 提供商品名称 + 数量时(如"5件鸡肉")
|
||||
|
||||
---
|
||||
|
||||
## 第一步:查询客户
|
||||
|
||||
用户可能提供:客户名称、客户编码
|
||||
|
||||
调用客户搜索接口:
|
||||
```
|
||||
POST https://openapi.77ircloud.com/organization-aggregation/customer/search
|
||||
Header: access_token, Content-Type: application/json
|
||||
Body: {"pageNum":1,"pageSize":10,"keyword":"客户名称或编码"}
|
||||
```
|
||||
|
||||
返回结果中找到对应客户,记录 `id`(即 `buyerId`)。
|
||||
|
||||
**注意:**
|
||||
- 如果客户不存在,返回错误并告知用户
|
||||
- 如果搜索结果有多个,选择第一个(默认取第一个)
|
||||
|
||||
---
|
||||
|
||||
## 第二步:查询商品
|
||||
|
||||
用户提供:商品名称、单位名称(如"包"、"件"、"斤"、"瓶")、购买数量
|
||||
|
||||
调用商品搜索接口(见 `product-suite.md`):
|
||||
```
|
||||
GET https://suite.77ircloud.com/product-aggregation/v1/products?pageSize=30¤tPage=1&queryTag=true&queryInventories=true&loadSortingTag=true&loadSortingTagName=true&q={商品名称}
|
||||
Header: authorization={jwt}, x-exclude-login-mutex=77ircloud
|
||||
```
|
||||
|
||||
在返回结果中找对应商品,**默认取第一个**,记录:
|
||||
- `skuId` → 下单用 `productSku`
|
||||
- `multiUnitId` → 下单用 `unitId`
|
||||
- `unitName` → 与用户提供的单位核对
|
||||
|
||||
**如果商品有多单位**(如"件"和"包"),根据用户提供的单位名称匹配对应的 `multiUnitId`。
|
||||
|
||||
---
|
||||
|
||||
## 第三步:计算金额
|
||||
|
||||
- `salePrice` = `originalPrice` = 商品的 `basePrice`(第一档价格)
|
||||
- `subtotal` = `salePrice` × 购买数量
|
||||
- `productTotalAmount` = 所有商品 `subtotal` 之和
|
||||
- `orderTotalAmount` = `productTotalAmount`(无额外运费/优惠时)
|
||||
|
||||
---
|
||||
|
||||
## 第四步:组装订单参数
|
||||
|
||||
```json
|
||||
{
|
||||
"buyerId": "{客户ID}",
|
||||
"orderDetails": [{
|
||||
"productSku": "{skuId}",
|
||||
"productSpu": "{skuId}", // 用 skuId 作为 spuId
|
||||
"purchaseNumbers": {购买数量},
|
||||
"unitId": "{multiUnitId}",
|
||||
"salePrice": {单价},
|
||||
"originalPrice": {单价},
|
||||
"saleRate": 100.0,
|
||||
"subtotal": {小计金额},
|
||||
"type": "NORMAL"
|
||||
}],
|
||||
"productTotalAmount": {商品总金额},
|
||||
"orderTotalAmount": {订单总金额},
|
||||
"productDiscountAmount": 0,
|
||||
"orderDiscountAmount": 0,
|
||||
"totalFreight": 0,
|
||||
"orderSource": "APP",
|
||||
"orderStatus": "ORDER_AUDIT_PENDING",
|
||||
"deliveryMethodId": 1
|
||||
}
|
||||
```
|
||||
|
||||
**字段说明:**
|
||||
|
||||
| 字段 | 默认值 | 说明 |
|
||||
|------|--------|------|
|
||||
| `deliveryMethodId` | 1(到店自提) | 可选,用户指定则用用户值 |
|
||||
| `orderSource` | APP | 固定 |
|
||||
| `orderStatus` | ORDER_AUDIT_PENDING | 固定 |
|
||||
| `saleRate` | 100.0 | 固定 |
|
||||
| `productDiscountAmount` | 0 | 固定 |
|
||||
| `orderDiscountAmount` | 0 | 固定 |
|
||||
| `totalFreight` | 0 | 固定 |
|
||||
|
||||
**用户可能指定的额外参数:**
|
||||
- `deliveryMethodId`: 1=到店自提, 2=送货上门(需要客户有配送地址)
|
||||
|
||||
---
|
||||
|
||||
## 第五步:调用下单接口
|
||||
|
||||
```
|
||||
POST https://openapi.77ircloud.com/order-aggregation/organizations/orders
|
||||
Header: access_token, Content-Type: application/json
|
||||
Body: 见上面
|
||||
```
|
||||
|
||||
**返回格式:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "操作成功",
|
||||
"data": 2390029347669600 // 这是订单ID
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 第六步:返回订单编号
|
||||
|
||||
下单接口只返回订单 ID,不返回订单编号。需要再查一次订单详情:
|
||||
|
||||
```
|
||||
POST https://openapi.77ircloud.com/order-aggregation/organizations/orders/search
|
||||
Body: {"pageNum":1,"pageSize":100,"withDetails":true}
|
||||
```
|
||||
|
||||
在结果中用返回的订单 ID 找到对应订单,返回 `orderCode`。
|
||||
|
||||
---
|
||||
|
||||
## 完整流程示例
|
||||
|
||||
**用户输入:** "帮华誉供货链下 3 包嘉吉尚选霸王鸡肉条"
|
||||
|
||||
**执行:**
|
||||
|
||||
1. 客户搜索"华誉供货链" → buyerId: 2364948772653120(默认取第一个)
|
||||
2. 商品搜索"嘉吉尚选霸王鸡肉条" → 默认取第一个结果:skuId: 2116793372668192, multiUnitId: 2116793372668193, basePrice: 18.9
|
||||
3. 组装参数:purchaseNumbers=3, subtotal=56.7, productTotalAmount=56.7
|
||||
4. 调用下单接口 → orderId: 2390029347669600
|
||||
5. 查询订单详情 → orderCode: CA000000-260331-102428
|
||||
|
||||
**返回:** "订单创建成功!订单编号:CA000000-260331-102428"
|
||||
|
||||
---
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **用户输入可能是语音转文字**,注意处理口语化表达(如"3件"="3件"、"5斤"="5斤")
|
||||
2. **单位匹配**:商品接口返回 `unitName`,用户可能说"件"或"包",需匹配
|
||||
3. **商品多规格**:用户未指定单位时,默认用第一个单位
|
||||
4. **库存检查**:创建订单前不强制检查库存,但可以查一下 `availableAmount` 告知用户
|
||||
5. **下单失败常见原因**:
|
||||
- 客户未配置配送方式(到店自提也需配置)→ 改用 `deliveryMethodId=1`
|
||||
- 必填字段缺失 → 检查 `productSku`, `unitId`, `purchaseNumbers` 等
|
||||
93
skills/irun-yidianhuo/customer.md
Normal file
93
skills/irun-yidianhuo/customer.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# 客户查询接口
|
||||
|
||||
## 1. 客户分类列表
|
||||
|
||||
```
|
||||
GET https://openapi.77ircloud.com/organization-aggregation/organizations/customer-categories
|
||||
```
|
||||
|
||||
**Header:** `access_token: {token}`
|
||||
|
||||
**返回:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": [
|
||||
{"id": 2116753907815520, "name": "普通客户", "defaultFlag": true},
|
||||
{"id": 2116796845712896, "name": "尊宝快递", "defaultFlag": false},
|
||||
{"id": 2116796846321152, "name": "家庭客户", "defaultFlag": false}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 客户列表(查询)
|
||||
|
||||
```
|
||||
POST https://openapi.77ircloud.com/organization-aggregation/customer/search
|
||||
```
|
||||
|
||||
**Header:** `access_token: {token}` + `Content-Type: application/json`
|
||||
|
||||
**Body 参数:**
|
||||
```json
|
||||
{
|
||||
"pageNum": 1,
|
||||
"pageSize": 10,
|
||||
"keyword": "成都" // 可选,按客户名称模糊搜索
|
||||
}
|
||||
```
|
||||
|
||||
**返回:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"items": [
|
||||
{
|
||||
"id": 2139500795701856,
|
||||
"code": "0411190513901",
|
||||
"name": "成都冷鲜优选供应链公司",
|
||||
"contactName": "周总",
|
||||
"contactPhone": "136xxx",
|
||||
"categoryId": 2116753907815520,
|
||||
"categoryName": "普通客户"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**说明:** 这是查询类接口(POST 方法是业务含义上的查询,不是写操作)
|
||||
|
||||
---
|
||||
|
||||
## 3. 收货地址列表
|
||||
|
||||
```
|
||||
GET https://openapi.77ircloud.com/organization-aggregation/organizations/{orgId}/delivery-addresses
|
||||
```
|
||||
|
||||
**Header:** `access_token: {token}`
|
||||
|
||||
**路径参数:**
|
||||
- `orgId`: 客户ID(从客户列表获取)
|
||||
|
||||
**返回:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": [
|
||||
{
|
||||
"id": 2139500796169856,
|
||||
"contactName": "",
|
||||
"contactPhone": "",
|
||||
"provinceId": 510000,
|
||||
"cityId": 510100,
|
||||
"districtId": 510106,
|
||||
"address": "四川省成都市金牛区..."
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
66
skills/irun-yidianhuo/inventory.md
Normal file
66
skills/irun-yidianhuo/inventory.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# 库存查询接口
|
||||
|
||||
## 库存列表(按 SKU 查)
|
||||
|
||||
```
|
||||
POST https://openapi.77ircloud.com/invoicing-aggregation/inventories-sku/search
|
||||
```
|
||||
|
||||
**Header:** `access_token: {token}` + `Content-Type: application/json`
|
||||
|
||||
**Body 参数:**
|
||||
```json
|
||||
{
|
||||
"currentPage": 1,
|
||||
"pageSize": 10,
|
||||
"warehouseId": 2116753909958624,
|
||||
"skuIds": [2116792188293408, 2287816343303072]
|
||||
}
|
||||
```
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `warehouseId` | int | **必填** | 仓库ID,从仓库列表接口获取 |
|
||||
| `skuIds` | array | 可选 | 商品SKU ID数组,不传则返回该仓库全部库存 |
|
||||
| `currentPage` | int | 可选 | 页码,默认1 |
|
||||
| `pageSize` | int | 可选 | 每页数量,默认10 |
|
||||
|
||||
**返回:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"totalCount": 80,
|
||||
"currentPage": 1,
|
||||
"pageSize": 10,
|
||||
"items": [
|
||||
{
|
||||
"skuId": 2116792188293408,
|
||||
"spuId": 2116792188162336,
|
||||
"name": "霜火菓子(柿子+花生)",
|
||||
"code": "101-030-0008",
|
||||
"amount": 3,
|
||||
"availableAmount": 7,
|
||||
"preOrderCount": 83,
|
||||
"unitName": "件",
|
||||
"unitId": 2116753910024416,
|
||||
"status": 23
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**关键字段说明:**
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `availableAmount` | number | **可用库存**(扣减预占后的真实可用),用于判断是否充足 |
|
||||
| `amount` | number | 总库存(含预占) |
|
||||
| `preOrderCount` | number | 预占数量(被其他订单占用) |
|
||||
| `skuId` | number | 商品SKU ID,与订单中商品对应 |
|
||||
|
||||
**注意:**
|
||||
- ⚠️ **只有产生过出入库数据的商品才会出现在结果中**(无业务数据的SKU不返回)
|
||||
- `warehouseId` 必填,必须先从仓库列表获取
|
||||
- 库存判断用 `availableAmount > 3` 作为是否充足的条件
|
||||
95
skills/irun-yidianhuo/order.md
Normal file
95
skills/irun-yidianhuo/order.md
Normal file
@@ -0,0 +1,95 @@
|
||||
# 订单查询接口
|
||||
|
||||
## 订单列表
|
||||
|
||||
```
|
||||
POST https://openapi.77ircloud.com/order-aggregation/organizations/orders/search
|
||||
```
|
||||
|
||||
**Header:** `access_token: {token}` + `Content-Type: application/json`
|
||||
|
||||
**Body 参数:**
|
||||
```json
|
||||
{
|
||||
"pageNum": 1,
|
||||
"pageSize": 10,
|
||||
"withDetails": true
|
||||
}
|
||||
```
|
||||
|
||||
**关键参数说明:**
|
||||
|
||||
| 参数 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `withDetails` | boolean | **⚠️ 重要**:true=返回 `orderDetails`(商品明细),false=不返回 |
|
||||
| `pageNum` | int | 页码 |
|
||||
| `pageSize` | int | 每页数量(建议不超过100) |
|
||||
|
||||
**⚠️ 注意:`orderStatus` 参数会导致 500 错误!** 正确做法:先拉全量订单,在返回结果中用 `orderStatus` 字段过滤。
|
||||
|
||||
**订单状态枚举值(从数据中观测):**
|
||||
- `ORDER_AUDIT_PENDING` — 待订单审核(7条测试数据)
|
||||
- `FINANCE_AUDIT_PENDING` — 待财务审核
|
||||
- `AUDITED` — 已审核(34条测试数据)
|
||||
- `FINISHED` — 已完成(9条测试数据)
|
||||
- `CANCELLED` — 已作废
|
||||
|
||||
**返回字段(重要!)**:
|
||||
- 订单列表在 `data.items`(不是 `data.list`!)
|
||||
- 分页信息:`data.totalCount`、`data.currentPage`、`data.totalPage`
|
||||
|
||||
**返回示例(已审核订单):**
|
||||
```json
|
||||
{
|
||||
"id": 2374359742917152,
|
||||
"orderCode": "CA000000-260309-79705",
|
||||
"buyer": {"id": 2139500795701856, "name": "粥大师店(南宁)"},
|
||||
"orderStatus": "ORDER_AUDIT_PENDING",
|
||||
"paymentStatus": "UN_PAID",
|
||||
"createTime": 1774344996000
|
||||
}
|
||||
```
|
||||
|
||||
**`withDetails: true` 时返回的 `orderDetails` 结构:**
|
||||
```json
|
||||
{
|
||||
"id": 2385059802414657,
|
||||
"orderCode": "CA000000-260324-95463",
|
||||
"productSku": 2116792188293408,
|
||||
"productSpu": 2116792188162336,
|
||||
"productCode": "101-030-0008",
|
||||
"productName": "霜火菓子(柿子+花生)",
|
||||
"type": "NORMAL",
|
||||
"purchaseNumbers": 2.0,
|
||||
"unitName": "包",
|
||||
"salePrice": 9.3,
|
||||
"subtotal": 18.6
|
||||
}
|
||||
```
|
||||
|
||||
**关键字段:**
|
||||
- `productSku`: 商品 SKU ID(用于关联库存)
|
||||
- `purchaseNumbers`: 购买数量(判断是否 > 2 的依据)
|
||||
- `productName`: 商品名称
|
||||
|
||||
---
|
||||
|
||||
## 订单审核
|
||||
|
||||
```
|
||||
PUT https://openapi.77ircloud.com/order-aggregation/organizations/orders/order-audit
|
||||
```
|
||||
|
||||
**Header:** `access_token: {token}` + `Content-Type: application/json`
|
||||
|
||||
**Body:**
|
||||
```json
|
||||
{"ids": [2374359742917152]}
|
||||
```
|
||||
|
||||
**返回:**
|
||||
```json
|
||||
{"code": 200, "message": "操作成功"}
|
||||
```
|
||||
|
||||
**⚠️ 注意:** 部分订单(如客户结算模式为"先款后货")需要先付款才能审核,API会返回 525 错误码和具体原因,此时该订单无法自动审核。
|
||||
146
skills/irun-yidianhuo/product-suite.md
Normal file
146
skills/irun-yidianhuo/product-suite.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# 商品搜索接口(新版)
|
||||
|
||||
> 用于通过商品名称或编码查询商品关键信息,是创建订单的前置步骤。
|
||||
|
||||
## 认证流程
|
||||
|
||||
### 第一步:登录获取 JWT
|
||||
|
||||
```
|
||||
POST https://accounts.77ircloud.com/api/v2/accounts/login
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
**请求体:**
|
||||
```json
|
||||
{
|
||||
"userName": "112983083",
|
||||
"password": "77ircloud",
|
||||
"loginServerType": 4
|
||||
}
|
||||
```
|
||||
|
||||
**返回的 jwtToken 即为 authorization 值:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"jwtToken": "eyJhbGci...",
|
||||
"expires_in": 604800000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 第二步:带 JWT 请求商品接口
|
||||
|
||||
请求头:
|
||||
- `authorization`: `{jwtToken}` — **注意:没有 Bearer 前缀**
|
||||
- `x-exclude-login-mutex`: `77ircloud` — 固定值
|
||||
|
||||
## 商品搜索
|
||||
|
||||
```
|
||||
GET https://suite.77ircloud.com/product-aggregation/v1/products?pageSize=30¤tPage=1&queryTag=true&queryInventories=true&loadSortingTag=true&loadSortingTagName=true&q={关键词}
|
||||
```
|
||||
|
||||
**参数说明:**
|
||||
|
||||
| 参数 | 必填 | 说明 |
|
||||
|------|------|------|
|
||||
| `q` | ✅ | 搜索关键词(商品名称或商品编码) |
|
||||
| `pageSize` | ✅ | 每页数量 |
|
||||
| `currentPage` | ✅ | 页码(从1开始) |
|
||||
| `queryTag` | 可选 | 是否查询标签 |
|
||||
| `queryInventories` | 可选 | 是否查询库存 |
|
||||
| `loadSortingTag` | 可选 | 是否查询分拣标签 |
|
||||
| `loadSortingTagName` | 可选 | 是否查询分拣标签名称 |
|
||||
|
||||
**返回示例:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"totalCount": 4,
|
||||
"currentPage": 1,
|
||||
"pageSize": 30,
|
||||
"items": [
|
||||
{
|
||||
"name": "嘉吉尚选霸王鸡肉条1kg",
|
||||
"skuId": 2116793372668192,
|
||||
"multiUnitId": 2116793372668193,
|
||||
"unitName": "包",
|
||||
"basePrice": 18.9,
|
||||
"availableAmount": 1035.0,
|
||||
"specJson": "{\"规格\":\"包=约33片/包、件=1kg*10包\"}",
|
||||
"code": "165-009-00068",
|
||||
"levelPrices": [
|
||||
{"index": 1, "price": 18.9},
|
||||
{"index": 2, "price": 18.0},
|
||||
{"index": 3, "price": 19.5},
|
||||
{"index": 4, "price": 18.5}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 关键字段说明
|
||||
|
||||
| 字段 | 说明 | 用途 |
|
||||
|------|------|------|
|
||||
| `skuId` | 商品SKU ID | 下单时用 `productSku` |
|
||||
| `multiUnitId` | 单位ID | 下单时用 `unitId` |
|
||||
| `unitName` | 单位名称(如"包") | 展示用 |
|
||||
| `basePrice` | 参考单价 | 填写 `salePrice` 和 `originalPrice` |
|
||||
| `availableAmount` | 当前可用库存 | 判断是否充足 |
|
||||
|
||||
## 完整调用示例
|
||||
|
||||
```python
|
||||
import urllib.request, json, urllib.parse
|
||||
|
||||
# Step 1: 登录获取 JWT
|
||||
login_data = json.dumps({
|
||||
"userName": "112983083",
|
||||
"password": "77ircloud",
|
||||
"loginServerType": 4
|
||||
}).encode()
|
||||
|
||||
login_req = urllib.request.Request(
|
||||
"https://accounts.77ircloud.com/api/v2/accounts/login",
|
||||
data=login_data,
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="POST"
|
||||
)
|
||||
|
||||
with urllib.request.urlopen(login_req, timeout=10) as resp:
|
||||
jwt = json.loads(resp.read())['data']['jwtToken']
|
||||
|
||||
# Step 2: 搜索商品
|
||||
keyword = "嘉吉尚选霸王鸡肉条"
|
||||
q = urllib.parse.quote(keyword)
|
||||
url = f"https://suite.77ircloud.com/product-aggregation/v1/products?pageSize=30¤tPage=1&queryTag=true&queryInventories=true&loadSortingTag=true&loadSortingTagName=true&q={q}"
|
||||
|
||||
search_req = urllib.request.Request(url, headers={
|
||||
"authorization": jwt,
|
||||
"x-exclude-login-mutex": "77ircloud"
|
||||
})
|
||||
|
||||
with urllib.request.urlopen(search_req, timeout=15) as resp:
|
||||
data = json.loads(resp.read())
|
||||
items = data.get('data', {}).get('items', [])
|
||||
for item in items:
|
||||
print(f"商品: {item['name']}")
|
||||
print(f" skuId: {item['skuId']}")
|
||||
print(f" multiUnitId: {item['multiUnitId']}")
|
||||
print(f" 单位: {item['unitName']}")
|
||||
print(f" 库存: {item['availableAmount']}")
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **每次查询都需要重新登录获取 JWT**(有效期约7天)
|
||||
2. **authorization 没有 Bearer 前缀**,直接写 JWT 字符串
|
||||
3. **搜索关键词用 URL 编码**,中文需要 encode
|
||||
4. **搜索结果可能为空**,可尝试不同的关键词组合(如品牌名、商品简称等)
|
||||
89
skills/irun-yidianhuo/product.md
Normal file
89
skills/irun-yidianhuo/product.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# 商品查询接口
|
||||
|
||||
## 1. 商品列表(SKU)
|
||||
|
||||
```
|
||||
GET https://openapi.77ircloud.com/product-aggregation/products/sku?pageNum=1&pageSize=10
|
||||
```
|
||||
|
||||
**Header:** `access_token: {token}`
|
||||
|
||||
**Query 参数:**
|
||||
- `pageNum`: 页码
|
||||
- `pageSize`: 每页数量(建议不超过100)
|
||||
- `keyword`: 可选,按商品名称模糊搜索
|
||||
- `categoryId`: 可选,按分类ID筛选
|
||||
|
||||
**返回:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"totalCount": 1024,
|
||||
"currentPage": 1,
|
||||
"pageSize": 10,
|
||||
"items": [
|
||||
{
|
||||
"skuId": 2116792188293408,
|
||||
"spuId": 2116792188162336,
|
||||
"code": "101-030-0008",
|
||||
"name": "霜火果子(柿子+花生)",
|
||||
"categoryId": 2116766652419584,
|
||||
"categoryName": "水产生品类",
|
||||
"brandId": 2116767991238144,
|
||||
"brandName": "其他品牌",
|
||||
"unitId": 2116753910024416,
|
||||
"unitName": "个",
|
||||
"status": 23,
|
||||
"price": 9.3
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**关键字段:**
|
||||
- `skuId`: 商品SKU ID,用于库存查询
|
||||
- `status`: 商品状态
|
||||
|
||||
---
|
||||
|
||||
## 2. 商品授权方案列表
|
||||
|
||||
```
|
||||
GET https://openapi.77ircloud.com/product-aggregation/authorizations
|
||||
```
|
||||
|
||||
**Header:** `access_token: {token}`
|
||||
|
||||
**返回:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"totalCount": 4,
|
||||
"items": [
|
||||
{"id": 2116753910171872, "name": "默认授权方案"},
|
||||
{"id": 2117317654711808, "name": "南宁分公司无商品"}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. skuId 增量更新列表(注意:调用报400参数错误,暂时跳过)
|
||||
|
||||
```
|
||||
GET https://openapi.77ircloud.com/product-aggregation/sku/pull?pageNum=1&pageSize=10
|
||||
```
|
||||
|
||||
**Header:** `access_token: {token}`
|
||||
|
||||
**⚠️ 状态:调用返回 `illegal parameters!`,参数格式待进一步排查。当前可跳过此接口,用商品列表代替。**
|
||||
|
||||
---
|
||||
|
||||
## 4. 价格等级列表
|
||||
|
||||
见 `basics.md` — `/product-aggregation/level-prices`
|
||||
147
skills/irun-yidianhuo/references/api_docs.md
Normal file
147
skills/irun-yidianhuo/references/api_docs.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# 铱云易订货 OpenAPI 2.0 接口文档
|
||||
|
||||
> 文档地址:http://openapi-doc.77ircloud.com/
|
||||
> API 基础地址:https://openapi.77ircloud.com
|
||||
|
||||
## 认证流程
|
||||
|
||||
### 获取 Access Token
|
||||
|
||||
**⚠️ 重要:文档描述有误,实际接口信息如下**
|
||||
|
||||
| 项目 | 说明 |
|
||||
|------|------|
|
||||
| URL | `https://openapi.77ircloud.com/v2/oauth2/token` |
|
||||
| 方法 | **GET**(文档写的是 POST,实际是 GET) |
|
||||
| 参数位置 | URL 查询字符串 |
|
||||
|
||||
**请求参数:**
|
||||
| 参数 | 必填 | 说明 | 示例 |
|
||||
|------|------|------|------|
|
||||
| userName | ✅ | 铱云系统登录账号 | 112983083 |
|
||||
| password | ✅ | 铱云系统登录密码 | 77ircloud |
|
||||
| client_id | ✅ | API 客户端ID | 6767358 |
|
||||
| client_secret | ✅ | API 密钥 | 1gk9ApiWV8IA2QrVDnU6Dx7uUo7CLuN2 |
|
||||
| grant_type | ✅ | 授权类型,固定值 | client_credentials |
|
||||
| scope | ✅ | 作用域,固定值 | basic |
|
||||
|
||||
**响应格式:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"access_token": "b615caeda3562eece7fcf834923685ee3607084",
|
||||
"create_time": 1774593254433,
|
||||
"expires_in": 2592000,
|
||||
"refresh_token": "8caf350dc4f013201af6a10efbf3fecd",
|
||||
"scope": "basic",
|
||||
"extra": {
|
||||
"enabledPassPort": null,
|
||||
"hasMoreAccount": null,
|
||||
"userId": null,
|
||||
"userName": null,
|
||||
"userType": null
|
||||
},
|
||||
"nodeCode": ""
|
||||
},
|
||||
"message": "操作成功"
|
||||
}
|
||||
```
|
||||
|
||||
**错误响应:**
|
||||
```json
|
||||
{"code":153,"data":null,"message":"illegal client_id"}
|
||||
```
|
||||
- `illegal client_id` = client_id 未开通 API 权限
|
||||
|
||||
---
|
||||
|
||||
## 订单接口
|
||||
|
||||
### 订单审核
|
||||
|
||||
| 项目 | 说明 |
|
||||
|------|------|
|
||||
| URL | `https://openapi.77ircloud.com/order-aggregation/organizations/orders/order-audit` |
|
||||
| 方法 | **PUT** |
|
||||
| 认证 | Header: `access_token: {token}` |
|
||||
|
||||
**请求 Body:**
|
||||
```json
|
||||
{
|
||||
"ids": [2384840119003488, 2384830331153312]
|
||||
}
|
||||
```
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| ids | long[] | ✅ | 订单ID数组,可同时审核多个订单 |
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "操作成功",
|
||||
"data": []
|
||||
}
|
||||
```
|
||||
|
||||
**常见错误:**
|
||||
- `ids: must not be empty` - 未传入订单ID数组
|
||||
- `illegal parameters!` - 参数格式错误
|
||||
|
||||
---
|
||||
|
||||
## 客户接口
|
||||
|
||||
### 客户列表查询
|
||||
|
||||
| 项目 | 说明 |
|
||||
|------|------|
|
||||
| URL | `https://openapi.77ircloud.com/openapi/customer/list` |
|
||||
| 方法 | **POST** |
|
||||
| 认证 | Header: `access_token: {token}` |
|
||||
|
||||
**请求 Body:**
|
||||
```json
|
||||
{
|
||||
"pageNum": 1,
|
||||
"pageSize": 10
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **接口方法可能与文档不符**:建议先用 POST 测试,收到 400 错误再切换方法
|
||||
2. **时间参数必须成对**:startCreateTime 和 endCreateTime 要么都提供,要么都不提供
|
||||
3. **Token 有效期**:30 天,过期后重新获取
|
||||
4. **审核接口**:使用 PUT 方法,参数为订单 ID 数组
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 重要 Bug:订单查询接口的时间过滤参数不生效
|
||||
|
||||
**问题描述:**
|
||||
实测发现 `startCreateTime` / `endCreateTime` 参数完全无效——无论传入什么值,API 都返回全部数据,后端过滤逻辑未实现。
|
||||
|
||||
**验证过程:**
|
||||
- 传入精确到毫秒的时间范围(如只查1秒:startCreateTime=1773990796000, endCreateTime=1773990796001)
|
||||
- API 仍返回全部 99 条订单,totalCount 也仍是 99
|
||||
|
||||
**createTime 单位:** 确认是毫秒时间戳(13位),如 `1773990796000` = `2026-03-20 14:xx GMT+8`
|
||||
|
||||
**正确做法:**
|
||||
1. 调用 API 时不传时间过滤参数,拉取全部数据
|
||||
2. 在本地用 `createTime` 字段过滤指定日期范围
|
||||
3. 可用订单号日期编码校验(格式:`CA000000-260320-78534` → 2026-03-20)
|
||||
|
||||
**订单号日期提取方法:**
|
||||
```python
|
||||
def parse_order_date(order_code):
|
||||
# 格式: CA{yymmdd}-{seq} 例如 CA000000-260320-78534
|
||||
yymmdd = order_code.replace('CA','').split('-')[1]
|
||||
yy, mm, dd = int('20'+yymmdd[:2]), int(yymmdd[2:4]), int(yymmdd[4:6])
|
||||
return datetime.date(yy, mm, dd)
|
||||
```
|
||||
89
skills/irun-yidianhuo/references/workflow.md
Normal file
89
skills/irun-yidianhuo/references/workflow.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# 铱云易订货助手 - 工作流程
|
||||
|
||||
## 查询决策逻辑
|
||||
|
||||
### ✅ 自动执行(无需询问)
|
||||
|
||||
| 场景 | 决策 |
|
||||
|-----|------|
|
||||
| 用户只说"查客户" | 自动列出前10条客户 |
|
||||
| 用户只说"看订单" | 自动列出最近30天的订单 |
|
||||
| 用户只说"库存" | 自动列出所有仓库库存 |
|
||||
| 分页查询 | 自动处理分页,用户说"下一页"时继续 |
|
||||
|
||||
### ❓ 需要询问用户
|
||||
|
||||
| 场景 | 询问内容 |
|
||||
|-----|---------|
|
||||
| 精确查询客户 | "请提供客户名称或分类" |
|
||||
| 特定时间段 | "请提供开始和结束时间" |
|
||||
| 查看详情 | "需要查看哪条记录的详情?" |
|
||||
| 涉及操作(修改/删除)| "确认要执行此操作吗?" |
|
||||
|
||||
### 🚫 绝不自动做的事
|
||||
|
||||
- 不猜测具体客户名称
|
||||
- 不自动执行敏感操作(需用户确认)
|
||||
- 不泄露客户敏感信息
|
||||
|
||||
## 数据展示格式
|
||||
|
||||
### 客户列表展示
|
||||
|
||||
```
|
||||
## 客户列表
|
||||
|
||||
共 {total} 条记录
|
||||
|
||||
| 序号 | 客户名称 | 联系电话 | 地址 |
|
||||
|-----|---------|---------|-----|
|
||||
| 1 | {name} | {phone} | {address} |
|
||||
| 2 | ... | ... | ... |
|
||||
|
||||
第 {pageNum}/{totalPages} 页
|
||||
```
|
||||
|
||||
### 订单列表展示
|
||||
|
||||
```
|
||||
## 订单列表
|
||||
|
||||
共 {total} 条记录
|
||||
|
||||
| 订单号 | 客户名称 | 金额 | 状态 | 下单时间 |
|
||||
|-------|---------|------|------|---------|
|
||||
| {orderNo} | {customerName} | ¥{totalAmount} | {status} | {createTime} |
|
||||
```
|
||||
|
||||
### 库存列表展示
|
||||
|
||||
```
|
||||
## 库存列表
|
||||
|
||||
| 仓库 | 商品名称 | 库存数量 | 可用量 |
|
||||
|-----|---------|---------|-------|
|
||||
| {warehouseName} | {productName} | {quantity} | {availableQuantity} |
|
||||
```
|
||||
|
||||
## 时间范围默认值
|
||||
|
||||
| 查询类型 | 默认时间范围 |
|
||||
|---------|------------|
|
||||
| 订单查询 | 最近30天 |
|
||||
| 收付款查询 | 最近30天 |
|
||||
| 库存查询 | 不限 |
|
||||
| 客户查询 | 不限 |
|
||||
|
||||
## 常见问题处理
|
||||
|
||||
### 1. 无数据返回
|
||||
"未查询到数据,请检查查询条件是否正确"
|
||||
|
||||
### 2. Token过期
|
||||
提示用户需要重新获取 access_token
|
||||
|
||||
### 3. 权限不足
|
||||
"当前账号无权访问此数据,请联系管理员"
|
||||
|
||||
### 4. 网络异常
|
||||
"网络请求失败,请稍后重试"
|
||||
278
skills/irun-yidianhuo/scripts/api_client.py
Normal file
278
skills/irun-yidianhuo/scripts/api_client.py
Normal file
@@ -0,0 +1,278 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
铱云易订货 OpenAPI 2.0 Python Client
|
||||
用于查询客户、商品、订单、库存、收付款等业务数据
|
||||
"""
|
||||
|
||||
import os
|
||||
import json
|
||||
import time
|
||||
import requests
|
||||
from typing import Optional, Dict, Any, List
|
||||
|
||||
# 默认配置
|
||||
DEFAULT_BASE_URL = "https://openapi.77ircloud.com"
|
||||
DEFAULT_TIMEOUT = 30
|
||||
|
||||
|
||||
class IrunClient:
|
||||
"""铱云易订货 API 客户端"""
|
||||
|
||||
def __init__(self, client_id: str = None, client_secret: str = None,
|
||||
access_token: str = None, base_url: str = DEFAULT_BASE_URL):
|
||||
"""
|
||||
初始化客户端
|
||||
|
||||
Args:
|
||||
client_id: 开发者ID
|
||||
client_secret: 密钥
|
||||
access_token: 访问令牌(可直接传入,跳过授权步骤)
|
||||
base_url: API基础地址
|
||||
"""
|
||||
self.client_id = client_id or os.getenv("IRUN_CLIENT_ID")
|
||||
self.client_secret = client_secret or os.getenv("IRUN_CLIENT_SECRET")
|
||||
self.access_token = access_token or os.getenv("IRUN_ACCESS_TOKEN")
|
||||
self.base_url = base_url
|
||||
self._token_expires_at = 0
|
||||
|
||||
def _get_headers(self) -> Dict[str, str]:
|
||||
"""获取请求头"""
|
||||
return {
|
||||
"Content-Type": "application/json; charset=UTF-8",
|
||||
"access_token": self.access_token,
|
||||
"x-client-id": self.client_id
|
||||
}
|
||||
|
||||
def _request(self, method: str, endpoint: str, params: Dict = None,
|
||||
data: Dict = None) -> Dict[str, Any]:
|
||||
"""
|
||||
发送API请求
|
||||
|
||||
Args:
|
||||
method: 请求方法 (GET, POST, PUT, DELETE)
|
||||
endpoint: API端点
|
||||
params: URL参数
|
||||
data: 请求体数据
|
||||
|
||||
Returns:
|
||||
API响应数据
|
||||
"""
|
||||
url = f"{self.base_url}{endpoint}"
|
||||
headers = self._get_headers()
|
||||
|
||||
try:
|
||||
response = requests.request(
|
||||
method=method,
|
||||
url=url,
|
||||
headers=headers,
|
||||
params=params,
|
||||
json=data,
|
||||
timeout=DEFAULT_TIMEOUT
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
except requests.exceptions.RequestException as e:
|
||||
return {"code": 500, "message": str(e), "data": None}
|
||||
|
||||
def get_token(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取访问令牌
|
||||
|
||||
Returns:
|
||||
包含access_token的响应
|
||||
"""
|
||||
if not self.client_id or not self.client_secret:
|
||||
return {"code": 400, "message": "缺少 client_id 或 client_secret"}
|
||||
|
||||
url = f"{self.base_url}/oauth/token"
|
||||
data = {
|
||||
"grant_type": "client_credentials",
|
||||
"client_id": self.client_id,
|
||||
"client_secret": self.client_secret
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(url, json=data, timeout=DEFAULT_TIMEOUT)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
|
||||
if result.get("code") == 200:
|
||||
self.access_token = result["data"]["access_token"]
|
||||
self._token_expires_at = time.time() + result["data"].get("expires_in", 7200)
|
||||
|
||||
return result
|
||||
except requests.exceptions.RequestException as e:
|
||||
return {"code": 500, "message": str(e), "data": None}
|
||||
|
||||
# ==================== 客户管理 ====================
|
||||
|
||||
def get_customer_list(self, page_num: int = 1, page_size: int = 10,
|
||||
name: str = None, category_id: str = None) -> Dict[str, Any]:
|
||||
"""获取客户列表"""
|
||||
params = {"pageNum": page_num, "pageSize": page_size}
|
||||
if name:
|
||||
params["name"] = name
|
||||
if category_id:
|
||||
params["categoryId"] = category_id
|
||||
return self._request("GET", "/openapi/customer/list", params=params)
|
||||
|
||||
def get_customer_detail(self, customer_id: str) -> Dict[str, Any]:
|
||||
"""获取客户详情"""
|
||||
return self._request("GET", f"/openapi/customer/{customer_id}")
|
||||
|
||||
def get_customer_categories(self) -> Dict[str, Any]:
|
||||
"""获取客户分类列表"""
|
||||
return self._request("GET", "/openapi/customer/category/list")
|
||||
|
||||
# ==================== 商品管理 ====================
|
||||
|
||||
def get_product_list(self, page_num: int = 1, page_size: int = 10,
|
||||
name: str = None, category_id: str = None) -> Dict[str, Any]:
|
||||
"""获取商品列表"""
|
||||
params = {"pageNum": page_num, "pageSize": page_size}
|
||||
if name:
|
||||
params["name"] = name
|
||||
if category_id:
|
||||
params["categoryId"] = category_id
|
||||
return self._request("GET", "/openapi/product/list", params=params)
|
||||
|
||||
def get_product_detail(self, product_id: str) -> Dict[str, Any]:
|
||||
"""获取商品详情"""
|
||||
return self._request("GET", f"/openapi/product/{product_id}")
|
||||
|
||||
def get_category_list(self) -> Dict[str, Any]:
|
||||
"""获取商品分类列表"""
|
||||
return self._request("GET", "/openapi/category/list")
|
||||
|
||||
# ==================== 订单管理 ====================
|
||||
|
||||
def get_order_list(self, page_num: int = 1, page_size: int = 10,
|
||||
order_no: str = None, customer_id: str = None,
|
||||
start_time: int = None, end_time: int = None,
|
||||
status: str = None) -> Dict[str, Any]:
|
||||
"""获取订单列表"""
|
||||
params = {"pageNum": page_num, "pageSize": page_size}
|
||||
if order_no:
|
||||
params["orderNo"] = order_no
|
||||
if customer_id:
|
||||
params["customerId"] = customer_id
|
||||
if start_time:
|
||||
params["startTime"] = start_time
|
||||
if end_time:
|
||||
params["endTime"] = end_time
|
||||
if status:
|
||||
params["status"] = status
|
||||
return self._request("GET", "/openapi/order/list", params=params)
|
||||
|
||||
def get_order_detail(self, order_id: str) -> Dict[str, Any]:
|
||||
"""获取订单详情"""
|
||||
return self._request("GET", f"/openapi/order/{order_id}")
|
||||
|
||||
def get_refund_list(self, page_num: int = 1, page_size: int = 10,
|
||||
order_no: str = None, customer_id: str = None,
|
||||
start_time: int = None, end_time: int = None) -> Dict[str, Any]:
|
||||
"""获取退单列表"""
|
||||
params = {"pageNum": page_num, "pageSize": page_size}
|
||||
if order_no:
|
||||
params["orderNo"] = order_no
|
||||
if customer_id:
|
||||
params["customerId"] = customer_id
|
||||
if start_time:
|
||||
params["startTime"] = start_time
|
||||
if end_time:
|
||||
params["endTime"] = end_time
|
||||
return self._request("GET", "/openapi/refund/list", params=params)
|
||||
|
||||
def get_refund_detail(self, refund_id: str) -> Dict[str, Any]:
|
||||
"""获取退单详情"""
|
||||
return self._request("GET", f"/openapi/refund/{refund_id}")
|
||||
|
||||
# ==================== 进销存 ====================
|
||||
|
||||
def get_inventory_list(self, warehouse_id: str = None,
|
||||
product_id: str = None) -> Dict[str, Any]:
|
||||
"""查询库存列表"""
|
||||
params = {}
|
||||
if warehouse_id:
|
||||
params["warehouseId"] = warehouse_id
|
||||
if product_id:
|
||||
params["productId"] = product_id
|
||||
return self._request("GET", "/openapi/inventory/list", params=params)
|
||||
|
||||
def get_warehouse_list(self) -> Dict[str, Any]:
|
||||
"""获取仓库列表"""
|
||||
return self._request("GET", "/openapi/warehouse/list")
|
||||
|
||||
def get_storage_list(self, storage_type: str = None,
|
||||
start_time: int = None, end_time: int = None) -> Dict[str, Any]:
|
||||
"""获取出入库记录"""
|
||||
params = {}
|
||||
if storage_type:
|
||||
params["type"] = storage_type
|
||||
if start_time:
|
||||
params["startTime"] = start_time
|
||||
if end_time:
|
||||
params["endTime"] = end_time
|
||||
return self._request("GET", "/openapi/storage/list", params=params)
|
||||
|
||||
# ==================== 资金管理 ====================
|
||||
|
||||
def get_payment_list(self, page_num: int = 1, page_size: int = 10,
|
||||
payment_type: str = None, start_time: int = None,
|
||||
end_time: int = None) -> Dict[str, Any]:
|
||||
"""获取收付款记录"""
|
||||
params = {"pageNum": page_num, "pageSize": page_size}
|
||||
if payment_type:
|
||||
params["type"] = payment_type
|
||||
if start_time:
|
||||
params["startTime"] = start_time
|
||||
if end_time:
|
||||
params["endTime"] = end_time
|
||||
return self._request("GET", "/openapi/payment/list", params=params)
|
||||
|
||||
# ==================== 基础数据 ====================
|
||||
|
||||
def get_employee_list(self) -> Dict[str, Any]:
|
||||
"""获取员工列表"""
|
||||
return self._request("GET", "/openapi/employee/list")
|
||||
|
||||
def get_area_list(self) -> Dict[str, Any]:
|
||||
"""获取省市数据"""
|
||||
return self._request("GET", "/openapi/area/province")
|
||||
|
||||
def get_logistics_company_list(self) -> Dict[str, Any]:
|
||||
"""获取物流公司列表"""
|
||||
return self._request("GET", "/openapi/logistics/company")
|
||||
|
||||
|
||||
# ==================== 便捷函数 ====================
|
||||
|
||||
def create_client(client_id: str = None, client_secret: str = None,
|
||||
access_token: str = None) -> IrunClient:
|
||||
"""创建API客户端"""
|
||||
return IrunClient(client_id, client_secret, access_token)
|
||||
|
||||
|
||||
def get_timestamp(days_ago: int = 0) -> int:
|
||||
"""获取时间戳"""
|
||||
import datetime
|
||||
return int((datetime.datetime.now() - datetime.timedelta(days=days_ago)).timestamp() * 1000)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 示例用法
|
||||
client = IrunClient()
|
||||
|
||||
# 获取Token
|
||||
# result = client.get_token()
|
||||
# print(result)
|
||||
|
||||
# 查询客户
|
||||
# result = client.get_customer_list(page_num=1, page_size=10)
|
||||
# print(result)
|
||||
|
||||
# 查询订单
|
||||
# result = client.get_order_list(start_time=get_timestamp(30))
|
||||
# print(result)
|
||||
|
||||
print("铱云易订货 API 客户端示例")
|
||||
Reference in New Issue
Block a user