n8n-nodes-kuaimai 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +356 -0
- package/dist/credentials/KuaimaiCredentials.credentials.d.ts +8 -0
- package/dist/credentials/KuaimaiCredentials.credentials.js +99 -0
- package/dist/nodes/KuaimaiErp/KuaimaiErp.node.d.ts +5 -0
- package/dist/nodes/KuaimaiErp/KuaimaiErp.node.js +401 -0
- package/dist/nodes/KuaimaiErp/KuaimaiSignature.d.ts +42 -0
- package/dist/nodes/KuaimaiErp/KuaimaiSignature.js +127 -0
- package/dist/nodes/KuaimaiErp/kuaimai.svg +6 -0
- package/index.js +5 -0
- package/n8n-nodes-kuaimai-1.0.0.tgz +0 -0
- package/nodes/KuaimaiErp/kuaimai.svg +6 -0
- package/package.json +66 -0
- package/publish-npm.bat +86 -0
package/README.md
ADDED
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
# n8n-nodes-kuaimai
|
|
2
|
+
|
|
3
|
+
快麦ERP开放平台的 n8n 社区节点,实现与快麦ERP系统的API集成。
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/n8n-nodes-kuaimai)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## 📋 目录
|
|
9
|
+
|
|
10
|
+
- [特性](#特性)
|
|
11
|
+
- [安装](#安装)
|
|
12
|
+
- [快速开始](#快速开始)
|
|
13
|
+
- [配置说明](#配置说明)
|
|
14
|
+
- [支持的操作](#支持的操作)
|
|
15
|
+
- [开发指南](#开发指南)
|
|
16
|
+
- [常见问题](#常见问题)
|
|
17
|
+
- [许可证](#许可证)
|
|
18
|
+
|
|
19
|
+
## ✨ 特性
|
|
20
|
+
|
|
21
|
+
- ✅ **完整的 API 支持**:基于快麦开放平台官方文档实现
|
|
22
|
+
- 🔐 **安全认证**:支持 HMAC-MD5、MD5、HMAC-SHA256 签名算法
|
|
23
|
+
- 🔄 **会话管理**:自动处理 Token 刷新(30天有效期)
|
|
24
|
+
- 📦 **资源管理**:订单、商品、仓库、基础数据查询
|
|
25
|
+
- 🎯 **易于使用**:可视化配置,无需编写代码
|
|
26
|
+
- 🚀 **Docker 部署**:提供完整的 Docker Compose 配置
|
|
27
|
+
|
|
28
|
+
## 📦 安装
|
|
29
|
+
|
|
30
|
+
### 方式一:Docker Compose(推荐)
|
|
31
|
+
|
|
32
|
+
#### 快速开始
|
|
33
|
+
|
|
34
|
+
1. **获取 GitHub Token**
|
|
35
|
+
|
|
36
|
+
访问 [GitHub Settings](https://github.com/settings/tokens) 创建一个带有 `read:packages` 权限的 Personal Access Token。
|
|
37
|
+
|
|
38
|
+
2. **配置环境变量**
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# 复制环境变量模板
|
|
42
|
+
cp .env.example .env
|
|
43
|
+
|
|
44
|
+
# 编辑 .env 文件,填入你的 GitHub Token
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
3. **启动服务**
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# 启动 n8n 和 PostgreSQL
|
|
51
|
+
docker-compose up -d
|
|
52
|
+
|
|
53
|
+
# 查看日志
|
|
54
|
+
docker-compose logs -f n8n
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
4. **访问 n8n**
|
|
58
|
+
|
|
59
|
+
打开浏览器访问 http://localhost:5678
|
|
60
|
+
|
|
61
|
+
详细部署说明请参考 [QUICKSTART.md](./QUICKSTART.md) 和 [DOCKER_DEPLOYMENT.md](./DOCKER_DEPLOYMENT.md)。
|
|
62
|
+
|
|
63
|
+
### 方式二:npm 安装
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm install @gabrielsworld/n8n-node-kuaimai --registry=https://npm.pkg.github.com
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## 🚀 快速开始
|
|
70
|
+
|
|
71
|
+
### 1. 获取快麦 API 凭证
|
|
72
|
+
|
|
73
|
+
1. 联系快麦ERP销售或实施同学申请 API 权限
|
|
74
|
+
2. 访问 [快麦开放平台](https://open.kuaimai.com/applyApp) 填写申请表
|
|
75
|
+
3. 审核通过后,您将收到包含以下信息的邮件:
|
|
76
|
+
- **App Key**
|
|
77
|
+
- **App Secret**
|
|
78
|
+
- **Access Token**
|
|
79
|
+
- **Refresh Token**
|
|
80
|
+
|
|
81
|
+
### 2. 在 n8n 中配置凭证
|
|
82
|
+
|
|
83
|
+
1. 在 n8n 中打开 **Credentials** 页面
|
|
84
|
+
2. 点击 **New Credential**
|
|
85
|
+
3. 搜索并选择 **快麦ERP API**
|
|
86
|
+
4. 填入从邮件中获取的凭证信息:
|
|
87
|
+
|
|
88
|
+
| 字段 | 说明 | 示例 |
|
|
89
|
+
| ------------- | ---------------------- | ------------------ |
|
|
90
|
+
| App Key | 开放平台分配的应用密钥 | `123456` |
|
|
91
|
+
| App Secret | 开放平台分配的应用秘钥 | `helloworld` |
|
|
92
|
+
| Access Token | 访问令牌(session) | `xxxx-xxxx-xxxx` |
|
|
93
|
+
| Refresh Token | 刷新令牌 | `yyyy-yyyy-yyyy` |
|
|
94
|
+
| 签名方法 | 签名算法 | `HMAC-MD5`(推荐) |
|
|
95
|
+
| API 环境 | 请求环境 | `V2正式环境` |
|
|
96
|
+
|
|
97
|
+
5. 点击 **Save**
|
|
98
|
+
|
|
99
|
+
### 3. 使用节点
|
|
100
|
+
|
|
101
|
+
在工作流中添加 **快麦ERP** 节点,选择要执行的操作:
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
快麦ERP 节点
|
|
105
|
+
├── 基础
|
|
106
|
+
│ ├── 刷新会话
|
|
107
|
+
│ ├── 查询仓库列表
|
|
108
|
+
│ └── 查询店铺列表
|
|
109
|
+
├── 订单
|
|
110
|
+
│ └── 查询订单列表
|
|
111
|
+
├── 商品
|
|
112
|
+
│ └── 查询商品列表
|
|
113
|
+
└── 仓库
|
|
114
|
+
└── 查询库存
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## ⚙️ 配置说明
|
|
118
|
+
|
|
119
|
+
### 签名方法
|
|
120
|
+
|
|
121
|
+
快麦开放平台支持三种签名算法:
|
|
122
|
+
|
|
123
|
+
| 方法 | 说明 | 安全性 | 推荐 |
|
|
124
|
+
| ------------ | ------------------------- | -------- | ------- |
|
|
125
|
+
| **HMAC-MD5** | HMAC 消息认证码(MD5) | ⭐⭐⭐ | ✅ 推荐 |
|
|
126
|
+
| MD5 | 简单 MD5 摘要 | ⭐⭐ | ⚠️ |
|
|
127
|
+
| HMAC-SHA256 | HMAC 消息认证码(SHA256) | ⭐⭐⭐⭐ | ✅ 推荐 |
|
|
128
|
+
|
|
129
|
+
### 会话管理
|
|
130
|
+
|
|
131
|
+
- **有效期**:Access Token 有效期为 **30天**
|
|
132
|
+
- **刷新**:必须在会话过期前调用 **刷新会话** 操作
|
|
133
|
+
- **限制**:刷新接口每小时最多调用 1 次
|
|
134
|
+
|
|
135
|
+
⚠️ **重要**:建议每月至少刷新一次会话,避免 Token 过期。
|
|
136
|
+
|
|
137
|
+
### API 环境
|
|
138
|
+
|
|
139
|
+
| 环境 | 地址 | 说明 |
|
|
140
|
+
| ------------------ | --------------------------------- | --------------------------------- |
|
|
141
|
+
| V2正式环境(推荐) | `https://gw.superboss.cc/router` | 2022年4月1日后申请的 App Key 使用 |
|
|
142
|
+
| V2内部专用 | `https://gw3.superboss.cc/router` | 内部测试使用 |
|
|
143
|
+
|
|
144
|
+
## 🔧 支持的操作
|
|
145
|
+
|
|
146
|
+
### 基础操作
|
|
147
|
+
|
|
148
|
+
#### 刷新会话
|
|
149
|
+
|
|
150
|
+
延长 Access Token 有效期(30天)。
|
|
151
|
+
|
|
152
|
+
**输入**:无需额外参数(使用凭证中的 Refresh Token)
|
|
153
|
+
|
|
154
|
+
**输出**:
|
|
155
|
+
|
|
156
|
+
```json
|
|
157
|
+
{
|
|
158
|
+
"session": {
|
|
159
|
+
"accessToken": "新的访问令牌",
|
|
160
|
+
"refreshToken": "新的刷新令牌",
|
|
161
|
+
"expiresIn": 2592000,
|
|
162
|
+
"userId": 12345,
|
|
163
|
+
"companyId": 67890
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
#### 查询仓库列表
|
|
169
|
+
|
|
170
|
+
查询公司下的所有仓库。
|
|
171
|
+
|
|
172
|
+
**API 方法**:`erp.warehouse.query`
|
|
173
|
+
|
|
174
|
+
#### 查询店铺列表
|
|
175
|
+
|
|
176
|
+
查询公司下的所有店铺。
|
|
177
|
+
|
|
178
|
+
**API 方法**:`erp.shop.query`
|
|
179
|
+
|
|
180
|
+
### 订单操作
|
|
181
|
+
|
|
182
|
+
#### 查询订单列表
|
|
183
|
+
|
|
184
|
+
查询非淘系/拼多多订单列表。
|
|
185
|
+
|
|
186
|
+
**API 方法**:`erp.trade.list.query`
|
|
187
|
+
|
|
188
|
+
**参数**:
|
|
189
|
+
|
|
190
|
+
| 参数 | 类型 | 必填 | 说明 |
|
|
191
|
+
| -------- | -------- | ---- | -------------------------------- |
|
|
192
|
+
| 时间类型 | 选项 | ✅ | `创建时间`/`更新时间`/`付款时间` |
|
|
193
|
+
| 开始时间 | 日期时间 | ✅ | 查询起始时间 |
|
|
194
|
+
| 结束时间 | 日期时间 | ✅ | 查询结束时间 |
|
|
195
|
+
| 页码 | 数字 | ✅ | 从 1 开始 |
|
|
196
|
+
| 每页数量 | 数字 | ✅ | 1-100 |
|
|
197
|
+
|
|
198
|
+
**示例**:
|
|
199
|
+
|
|
200
|
+
```javascript
|
|
201
|
+
// 工作流配置
|
|
202
|
+
{
|
|
203
|
+
"resource": "order",
|
|
204
|
+
"operation": "queryOrders",
|
|
205
|
+
"timeType": "upd_time",
|
|
206
|
+
"startTime": "2024-01-01 00:00:00",
|
|
207
|
+
"endTime": "2024-01-31 23:59:59",
|
|
208
|
+
"pageNo": 1,
|
|
209
|
+
"pageSize": 20
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### 商品操作
|
|
214
|
+
|
|
215
|
+
#### 查询商品列表
|
|
216
|
+
|
|
217
|
+
查询商品信息。
|
|
218
|
+
|
|
219
|
+
**API 方法**:`erp.item.list.query`
|
|
220
|
+
|
|
221
|
+
### 仓库操作
|
|
222
|
+
|
|
223
|
+
#### 查询库存
|
|
224
|
+
|
|
225
|
+
查询商品库存信息。
|
|
226
|
+
|
|
227
|
+
**API 方法**:`erp.inventory.query`
|
|
228
|
+
|
|
229
|
+
## 🛠️ 开发指南
|
|
230
|
+
|
|
231
|
+
### 环境要求
|
|
232
|
+
|
|
233
|
+
- Node.js >= 18.x
|
|
234
|
+
- npm >= 8.x
|
|
235
|
+
- TypeScript >= 5.x
|
|
236
|
+
|
|
237
|
+
### 本地开发
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
# 克隆项目
|
|
241
|
+
git clone https://github.com/gabrielsworld/n8n-nodes-kuaimai.git
|
|
242
|
+
cd n8n-nodes-kuaimai
|
|
243
|
+
|
|
244
|
+
# 安装依赖
|
|
245
|
+
npm install
|
|
246
|
+
|
|
247
|
+
# 开发模式(监听文件变化)
|
|
248
|
+
npm run dev
|
|
249
|
+
|
|
250
|
+
# 构建
|
|
251
|
+
npm run build
|
|
252
|
+
|
|
253
|
+
# 运行测试
|
|
254
|
+
npm test
|
|
255
|
+
|
|
256
|
+
# 代码检查
|
|
257
|
+
npm run lint
|
|
258
|
+
|
|
259
|
+
# 格式化代码
|
|
260
|
+
npm run format
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### 项目结构
|
|
264
|
+
|
|
265
|
+
```
|
|
266
|
+
├── credentials/ # 凭证定义
|
|
267
|
+
│ └── KuaimaiCredentials.credentials.ts
|
|
268
|
+
├── nodes/ # 节点实现
|
|
269
|
+
│ └── KuaimaiErp/
|
|
270
|
+
│ ├── KuaimaiErp.node.ts # 主节点
|
|
271
|
+
│ ├── KuaimaiSignature.ts # 签名工具
|
|
272
|
+
│ └── kuaimai.svg # 图标
|
|
273
|
+
├── test/ # 测试文件
|
|
274
|
+
├── dist/ # 构建输出
|
|
275
|
+
├── docker-compose.yml # Docker 开发环境
|
|
276
|
+
├── docker-compose.prod.yml # Docker 生产环境
|
|
277
|
+
├── .env.example # 环境变量模板
|
|
278
|
+
└── package.json
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### 添加新操作
|
|
282
|
+
|
|
283
|
+
1. 在 `KuaimaiErp.node.ts` 中添加操作选项
|
|
284
|
+
2. 添加对应的参数配置
|
|
285
|
+
3. 在 `execute` 方法中实现业务逻辑
|
|
286
|
+
4. 更新文档和测试
|
|
287
|
+
|
|
288
|
+
详细开发指南请参考 [AGENTS.md](./AGENTS.md)。
|
|
289
|
+
|
|
290
|
+
## ❓ 常见问题
|
|
291
|
+
|
|
292
|
+
### 1. 节点不显示?
|
|
293
|
+
|
|
294
|
+
**解决方案**:
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
# 检查日志
|
|
298
|
+
docker-compose logs n8n | grep -i "custom"
|
|
299
|
+
|
|
300
|
+
# 重启容器
|
|
301
|
+
docker-compose restart n8n
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### 2. 会话过期怎么办?
|
|
305
|
+
|
|
306
|
+
如果 Access Token 过期(超过30天未刷新):
|
|
307
|
+
|
|
308
|
+
1. 联系快麦实施或客服
|
|
309
|
+
2. 在问题群告知业务机器人
|
|
310
|
+
3. 格式:`公司名称-开放平台刷新授权-appKey`
|
|
311
|
+
|
|
312
|
+
### 3. 签名错误?
|
|
313
|
+
|
|
314
|
+
常见原因:
|
|
315
|
+
|
|
316
|
+
- App Secret 填写错误
|
|
317
|
+
- 时间戳误差超过10分钟
|
|
318
|
+
- 参数编码问题
|
|
319
|
+
|
|
320
|
+
**调试工具**:使用 [快麦 API 测试工具](https://open.kuaimai.com/tools) 验证签名。
|
|
321
|
+
|
|
322
|
+
### 4. 如何获取拼多多订单?
|
|
323
|
+
|
|
324
|
+
拼多多订单需要单独接入自研接口,详见:
|
|
325
|
+
[拼多多自研接口接入公告](https://open.kuaimai.com/docs/question/系统公告/拼多多自研接口接入开放公告)
|
|
326
|
+
|
|
327
|
+
### 5. API 调用频率限制?
|
|
328
|
+
|
|
329
|
+
- 刷新会话接口:每小时 1 次
|
|
330
|
+
- 其他接口:具体限制请参考快麦开放平台文档
|
|
331
|
+
|
|
332
|
+
## 📚 相关文档
|
|
333
|
+
|
|
334
|
+
- [快速开始指南](./QUICKSTART.md)
|
|
335
|
+
- [Docker 部署文档](./DOCKER_DEPLOYMENT.md)
|
|
336
|
+
- [部署检查清单](./DEPLOYMENT_CHECKLIST.md)
|
|
337
|
+
- [开发指南](./AGENTS.md)
|
|
338
|
+
- [快麦开放平台官方文档](https://open.kuaimai.com/)
|
|
339
|
+
|
|
340
|
+
## 🤝 贡献
|
|
341
|
+
|
|
342
|
+
欢迎提交 Issue 和 Pull Request!
|
|
343
|
+
|
|
344
|
+
## 📄 许可证
|
|
345
|
+
|
|
346
|
+
[MIT License](LICENSE)
|
|
347
|
+
|
|
348
|
+
## 📞 支持
|
|
349
|
+
|
|
350
|
+
- 📧 Email: gabrielsworld@github.com
|
|
351
|
+
- 🐛 Issues: https://github.com/gabrielsworld/n8n-nodes-kuaimai/issues
|
|
352
|
+
- 📖 文档: https://open.kuaimai.com/
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
**Made with ❤️ by gabrielsworld**
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
|
|
2
|
+
export declare class KuaimaiCredentials implements ICredentialType {
|
|
3
|
+
name: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
documentationUrl: string;
|
|
6
|
+
properties: INodeProperties[];
|
|
7
|
+
test: ICredentialTestRequest;
|
|
8
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KuaimaiCredentials = void 0;
|
|
4
|
+
class KuaimaiCredentials {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = 'kuaimaiApi';
|
|
7
|
+
this.displayName = '快麦ERP API';
|
|
8
|
+
this.documentationUrl = 'https://open.kuaimai.com/docs/api/API对接说明/接入指南';
|
|
9
|
+
this.properties = [
|
|
10
|
+
{
|
|
11
|
+
displayName: 'App Key',
|
|
12
|
+
name: 'appKey',
|
|
13
|
+
type: 'string',
|
|
14
|
+
default: '',
|
|
15
|
+
required: true,
|
|
16
|
+
description: '快麦开放平台分配的 App Key',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
displayName: 'App Secret',
|
|
20
|
+
name: 'appSecret',
|
|
21
|
+
type: 'string',
|
|
22
|
+
typeOptions: {
|
|
23
|
+
password: true,
|
|
24
|
+
},
|
|
25
|
+
default: '',
|
|
26
|
+
required: true,
|
|
27
|
+
description: '快麦开放平台分配的 App Secret',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
displayName: 'Access Token',
|
|
31
|
+
name: 'accessToken',
|
|
32
|
+
type: 'string',
|
|
33
|
+
typeOptions: {
|
|
34
|
+
password: true,
|
|
35
|
+
},
|
|
36
|
+
default: '',
|
|
37
|
+
required: true,
|
|
38
|
+
description: '访问令牌(session),由快麦开放平台邮件提供',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
displayName: 'Refresh Token',
|
|
42
|
+
name: 'refreshToken',
|
|
43
|
+
type: 'string',
|
|
44
|
+
typeOptions: {
|
|
45
|
+
password: true,
|
|
46
|
+
},
|
|
47
|
+
default: '',
|
|
48
|
+
required: true,
|
|
49
|
+
description: '刷新令牌,用于延长会话有效期(30天)',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
displayName: '签名方法',
|
|
53
|
+
name: 'signMethod',
|
|
54
|
+
type: 'options',
|
|
55
|
+
options: [
|
|
56
|
+
{
|
|
57
|
+
name: 'HMAC-MD5',
|
|
58
|
+
value: 'hmac',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: 'MD5',
|
|
62
|
+
value: 'md5',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'HMAC-SHA256',
|
|
66
|
+
value: 'hmac-sha256',
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
default: 'hmac',
|
|
70
|
+
description: '签名摘要算法',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
displayName: 'API 环境',
|
|
74
|
+
name: 'environment',
|
|
75
|
+
type: 'options',
|
|
76
|
+
options: [
|
|
77
|
+
{
|
|
78
|
+
name: 'V2正式环境',
|
|
79
|
+
value: 'production',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: 'V2内部专用',
|
|
83
|
+
value: 'internal',
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
default: 'production',
|
|
87
|
+
description: 'API 请求环境',
|
|
88
|
+
},
|
|
89
|
+
];
|
|
90
|
+
this.test = {
|
|
91
|
+
request: {
|
|
92
|
+
baseURL: '={{$credentials.environment === "internal" ? "https://gw3.superboss.cc" : "https://gw.superboss.cc"}}',
|
|
93
|
+
url: '/router',
|
|
94
|
+
method: 'POST',
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
exports.KuaimaiCredentials = KuaimaiCredentials;
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KuaimaiErp = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const KuaimaiSignature_1 = require("./KuaimaiSignature");
|
|
6
|
+
class KuaimaiErp {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.description = {
|
|
9
|
+
displayName: '快麦ERP',
|
|
10
|
+
name: 'kuaimaiErp',
|
|
11
|
+
icon: 'file:kuaimai.svg',
|
|
12
|
+
group: ['transform'],
|
|
13
|
+
version: 1,
|
|
14
|
+
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
|
15
|
+
description: '与快麦ERP开放平台API交互,进行订单、商品和库存管理',
|
|
16
|
+
defaults: {
|
|
17
|
+
name: '快麦ERP',
|
|
18
|
+
},
|
|
19
|
+
inputs: ['main'],
|
|
20
|
+
outputs: ['main'],
|
|
21
|
+
credentials: [
|
|
22
|
+
{
|
|
23
|
+
name: 'kuaimaiApi',
|
|
24
|
+
required: true,
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
properties: [
|
|
28
|
+
{
|
|
29
|
+
displayName: '资源类型',
|
|
30
|
+
name: 'resource',
|
|
31
|
+
type: 'options',
|
|
32
|
+
noDataExpression: true,
|
|
33
|
+
options: [
|
|
34
|
+
{
|
|
35
|
+
name: '基础',
|
|
36
|
+
value: 'base',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: '订单',
|
|
40
|
+
value: 'order',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: '商品',
|
|
44
|
+
value: 'product',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: '仓库',
|
|
48
|
+
value: 'warehouse',
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
default: 'base',
|
|
52
|
+
},
|
|
53
|
+
// ==================== 基础操作 ====================
|
|
54
|
+
{
|
|
55
|
+
displayName: '操作',
|
|
56
|
+
name: 'operation',
|
|
57
|
+
type: 'options',
|
|
58
|
+
noDataExpression: true,
|
|
59
|
+
displayOptions: {
|
|
60
|
+
show: {
|
|
61
|
+
resource: ['base'],
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
options: [
|
|
65
|
+
{
|
|
66
|
+
name: '刷新会话',
|
|
67
|
+
value: 'refreshToken',
|
|
68
|
+
description: '刷新会话 Token,延长30天有效期',
|
|
69
|
+
action: 'Refresh session token',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: '查询仓库列表',
|
|
73
|
+
value: 'listWarehouses',
|
|
74
|
+
description: '查询公司下的仓库列表',
|
|
75
|
+
action: 'List warehouses',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: '查询店铺列表',
|
|
79
|
+
value: 'listShops',
|
|
80
|
+
description: '查询公司下的店铺列表',
|
|
81
|
+
action: 'List shops',
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
default: 'refreshToken',
|
|
85
|
+
},
|
|
86
|
+
// ==================== 订单操作 ====================
|
|
87
|
+
{
|
|
88
|
+
displayName: '操作',
|
|
89
|
+
name: 'operation',
|
|
90
|
+
type: 'options',
|
|
91
|
+
noDataExpression: true,
|
|
92
|
+
displayOptions: {
|
|
93
|
+
show: {
|
|
94
|
+
resource: ['order'],
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
options: [
|
|
98
|
+
{
|
|
99
|
+
name: '查询订单列表',
|
|
100
|
+
value: 'queryOrders',
|
|
101
|
+
description: '查询订单列表(非淘系/拼多多)',
|
|
102
|
+
action: 'Query orders',
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
default: 'queryOrders',
|
|
106
|
+
},
|
|
107
|
+
// 订单查询参数
|
|
108
|
+
{
|
|
109
|
+
displayName: '时间类型',
|
|
110
|
+
name: 'timeType',
|
|
111
|
+
type: 'options',
|
|
112
|
+
displayOptions: {
|
|
113
|
+
show: {
|
|
114
|
+
resource: ['order'],
|
|
115
|
+
operation: ['queryOrders'],
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
options: [
|
|
119
|
+
{
|
|
120
|
+
name: '创建时间',
|
|
121
|
+
value: 'create_time',
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
name: '更新时间',
|
|
125
|
+
value: 'upd_time',
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
name: '付款时间',
|
|
129
|
+
value: 'pay_time',
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
default: 'upd_time',
|
|
133
|
+
description: '查询订单的时间类型',
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
displayName: '开始时间',
|
|
137
|
+
name: 'startTime',
|
|
138
|
+
type: 'dateTime',
|
|
139
|
+
displayOptions: {
|
|
140
|
+
show: {
|
|
141
|
+
resource: ['order'],
|
|
142
|
+
operation: ['queryOrders'],
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
default: '',
|
|
146
|
+
required: true,
|
|
147
|
+
description: '查询开始时间',
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
displayName: '结束时间',
|
|
151
|
+
name: 'endTime',
|
|
152
|
+
type: 'dateTime',
|
|
153
|
+
displayOptions: {
|
|
154
|
+
show: {
|
|
155
|
+
resource: ['order'],
|
|
156
|
+
operation: ['queryOrders'],
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
default: '',
|
|
160
|
+
required: true,
|
|
161
|
+
description: '查询结束时间',
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
displayName: '页码',
|
|
165
|
+
name: 'pageNo',
|
|
166
|
+
type: 'number',
|
|
167
|
+
displayOptions: {
|
|
168
|
+
show: {
|
|
169
|
+
resource: ['order'],
|
|
170
|
+
operation: ['queryOrders'],
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
default: 1,
|
|
174
|
+
description: '页码,从1开始',
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
displayName: '每页数量',
|
|
178
|
+
name: 'pageSize',
|
|
179
|
+
type: 'number',
|
|
180
|
+
displayOptions: {
|
|
181
|
+
show: {
|
|
182
|
+
resource: ['order'],
|
|
183
|
+
operation: ['queryOrders'],
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
default: 20,
|
|
187
|
+
typeOptions: {
|
|
188
|
+
minValue: 1,
|
|
189
|
+
maxValue: 100,
|
|
190
|
+
},
|
|
191
|
+
description: '每页返回的记录数,最大100',
|
|
192
|
+
},
|
|
193
|
+
// ==================== 商品操作 ====================
|
|
194
|
+
{
|
|
195
|
+
displayName: '操作',
|
|
196
|
+
name: 'operation',
|
|
197
|
+
type: 'options',
|
|
198
|
+
noDataExpression: true,
|
|
199
|
+
displayOptions: {
|
|
200
|
+
show: {
|
|
201
|
+
resource: ['product'],
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
options: [
|
|
205
|
+
{
|
|
206
|
+
name: '查询商品列表',
|
|
207
|
+
value: 'queryProducts',
|
|
208
|
+
action: 'Query products',
|
|
209
|
+
},
|
|
210
|
+
],
|
|
211
|
+
default: 'queryProducts',
|
|
212
|
+
},
|
|
213
|
+
// ==================== 仓库操作 ====================
|
|
214
|
+
{
|
|
215
|
+
displayName: '操作',
|
|
216
|
+
name: 'operation',
|
|
217
|
+
type: 'options',
|
|
218
|
+
noDataExpression: true,
|
|
219
|
+
displayOptions: {
|
|
220
|
+
show: {
|
|
221
|
+
resource: ['warehouse'],
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
options: [
|
|
225
|
+
{
|
|
226
|
+
name: '查询库存',
|
|
227
|
+
value: 'queryInventory',
|
|
228
|
+
description: '查询商品库存信息',
|
|
229
|
+
action: 'Query inventory',
|
|
230
|
+
},
|
|
231
|
+
],
|
|
232
|
+
default: 'queryInventory',
|
|
233
|
+
},
|
|
234
|
+
// ==================== 附加字段 ====================
|
|
235
|
+
{
|
|
236
|
+
displayName: '附加字段',
|
|
237
|
+
name: 'additionalFields',
|
|
238
|
+
type: 'collection',
|
|
239
|
+
placeholder: '添加字段',
|
|
240
|
+
default: {},
|
|
241
|
+
options: [
|
|
242
|
+
{
|
|
243
|
+
displayName: '自定义参数',
|
|
244
|
+
name: 'customParams',
|
|
245
|
+
type: 'fixedCollection',
|
|
246
|
+
placeholder: '添加参数',
|
|
247
|
+
default: {},
|
|
248
|
+
typeOptions: {
|
|
249
|
+
multipleValues: true,
|
|
250
|
+
},
|
|
251
|
+
options: [
|
|
252
|
+
{
|
|
253
|
+
name: 'parameter',
|
|
254
|
+
displayName: '参数',
|
|
255
|
+
values: [
|
|
256
|
+
{
|
|
257
|
+
displayName: '参数名',
|
|
258
|
+
name: 'name',
|
|
259
|
+
type: 'string',
|
|
260
|
+
default: '',
|
|
261
|
+
description: '参数名称',
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
displayName: '参数值',
|
|
265
|
+
name: 'value',
|
|
266
|
+
type: 'string',
|
|
267
|
+
default: '',
|
|
268
|
+
},
|
|
269
|
+
],
|
|
270
|
+
},
|
|
271
|
+
],
|
|
272
|
+
description: '自定义请求参数',
|
|
273
|
+
},
|
|
274
|
+
],
|
|
275
|
+
},
|
|
276
|
+
],
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
async execute() {
|
|
280
|
+
const items = this.getInputData();
|
|
281
|
+
const returnData = [];
|
|
282
|
+
for (let i = 0; i < items.length; i++) {
|
|
283
|
+
try {
|
|
284
|
+
const credentials = await this.getCredentials('kuaimaiApi');
|
|
285
|
+
const resource = this.getNodeParameter('resource', i);
|
|
286
|
+
const operation = this.getNodeParameter('operation', i);
|
|
287
|
+
const appKey = credentials.appKey;
|
|
288
|
+
const appSecret = credentials.appSecret;
|
|
289
|
+
const accessToken = credentials.accessToken;
|
|
290
|
+
const refreshToken = credentials.refreshToken;
|
|
291
|
+
const signMethod = credentials.signMethod;
|
|
292
|
+
const environment = credentials.environment;
|
|
293
|
+
// 确定 API 端点
|
|
294
|
+
const baseURL = environment === 'internal' ? 'https://gw3.superboss.cc' : 'https://gw.superboss.cc';
|
|
295
|
+
let method = '';
|
|
296
|
+
const businessParams = {};
|
|
297
|
+
// 根据资源和操作确定 API 方法和参数
|
|
298
|
+
if (resource === 'base') {
|
|
299
|
+
if (operation === 'refreshToken') {
|
|
300
|
+
method = 'open.token.refresh';
|
|
301
|
+
businessParams.refreshToken = refreshToken;
|
|
302
|
+
}
|
|
303
|
+
else if (operation === 'listWarehouses') {
|
|
304
|
+
method = 'erp.warehouse.query';
|
|
305
|
+
}
|
|
306
|
+
else if (operation === 'listShops') {
|
|
307
|
+
method = 'erp.shop.query';
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
else if (resource === 'order') {
|
|
311
|
+
if (operation === 'queryOrders') {
|
|
312
|
+
method = 'erp.trade.list.query';
|
|
313
|
+
const timeType = this.getNodeParameter('timeType', i);
|
|
314
|
+
const startTime = this.getNodeParameter('startTime', i);
|
|
315
|
+
const endTime = this.getNodeParameter('endTime', i);
|
|
316
|
+
const pageNo = this.getNodeParameter('pageNo', i);
|
|
317
|
+
const pageSize = this.getNodeParameter('pageSize', i);
|
|
318
|
+
businessParams.timeType = timeType;
|
|
319
|
+
businessParams.startTime = formatDateTimeForKuaimai(new Date(startTime));
|
|
320
|
+
businessParams.endTime = formatDateTimeForKuaimai(new Date(endTime));
|
|
321
|
+
businessParams.pageNo = String(pageNo);
|
|
322
|
+
businessParams.pageSize = String(pageSize);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
else if (resource === 'product') {
|
|
326
|
+
if (operation === 'queryProducts') {
|
|
327
|
+
method = 'erp.item.list.query';
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
else if (resource === 'warehouse') {
|
|
331
|
+
if (operation === 'queryInventory') {
|
|
332
|
+
method = 'erp.inventory.query';
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
// 处理附加字段
|
|
336
|
+
const additionalFields = this.getNodeParameter('additionalFields', i, {});
|
|
337
|
+
if (additionalFields.customParams) {
|
|
338
|
+
const customParams = additionalFields.customParams;
|
|
339
|
+
if (customParams.parameter && Array.isArray(customParams.parameter)) {
|
|
340
|
+
customParams.parameter.forEach((param) => {
|
|
341
|
+
const name = param.name;
|
|
342
|
+
const value = param.value;
|
|
343
|
+
if (name && value !== undefined) {
|
|
344
|
+
businessParams[name] = value;
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
// 构建完整的请求参数(包含签名)
|
|
350
|
+
const requestParams = (0, KuaimaiSignature_1.buildKuaimaiRequestParams)(method, accessToken, appKey, appSecret, signMethod, businessParams);
|
|
351
|
+
// 发起 API 请求
|
|
352
|
+
const response = await this.helpers.request({
|
|
353
|
+
method: 'POST',
|
|
354
|
+
url: `${baseURL}/router`,
|
|
355
|
+
headers: {
|
|
356
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
357
|
+
},
|
|
358
|
+
form: requestParams,
|
|
359
|
+
json: true,
|
|
360
|
+
});
|
|
361
|
+
// 检查响应
|
|
362
|
+
if (response.success === false) {
|
|
363
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `快麦 API 错误: ${response.msg || '未知错误'} (错误码: ${response.code || 'N/A'})`, {
|
|
364
|
+
description: `Trace ID: ${response.trace_id || 'N/A'}`,
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
returnData.push({
|
|
368
|
+
json: response,
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
catch (error) {
|
|
372
|
+
if (this.continueOnFail()) {
|
|
373
|
+
returnData.push({
|
|
374
|
+
json: {
|
|
375
|
+
error: error instanceof Error ? error.message : String(error),
|
|
376
|
+
},
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
throw error;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return [returnData];
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
exports.KuaimaiErp = KuaimaiErp;
|
|
388
|
+
/**
|
|
389
|
+
* 格式化日期时间为快麦要求的格式
|
|
390
|
+
* @param date 日期对象
|
|
391
|
+
* @returns 格式化的日期时间字符串 (yyyy-MM-dd HH:mm:ss)
|
|
392
|
+
*/
|
|
393
|
+
function formatDateTimeForKuaimai(date) {
|
|
394
|
+
const year = date.getFullYear();
|
|
395
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
396
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
397
|
+
const hours = String(date.getHours()).padStart(2, '0');
|
|
398
|
+
const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
399
|
+
const seconds = String(date.getSeconds()).padStart(2, '0');
|
|
400
|
+
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
401
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { IDataObject } from 'n8n-workflow';
|
|
2
|
+
/**
|
|
3
|
+
* 快麦开放平台签名工具
|
|
4
|
+
* 参考文档: https://open.kuaimai.com/docs/api/API对接说明/API调用方法详解
|
|
5
|
+
*/
|
|
6
|
+
export interface SignatureParams {
|
|
7
|
+
[key: string]: string | number | boolean | undefined;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* 生成快麦 API 签名
|
|
11
|
+
* @param params 所有请求参数(包括公共参数和业务参数,但不包括 sign 参数)
|
|
12
|
+
* @param secret App Secret
|
|
13
|
+
* @param signMethod 签名方法:hmac | md5 | hmac-sha256
|
|
14
|
+
* @returns 签名字符串(32位大写十六进制)
|
|
15
|
+
*/
|
|
16
|
+
export declare function generateKuaimaiSignature(params: SignatureParams, secret: string, signMethod?: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* 构建快麦 API 公共参数
|
|
19
|
+
* @param method API 方法名
|
|
20
|
+
* @param session Access Token
|
|
21
|
+
* @param appKey App Key
|
|
22
|
+
* @param additionalParams 额外的公共参数
|
|
23
|
+
* @returns 公共参数对象
|
|
24
|
+
*/
|
|
25
|
+
export declare function buildKuaimaiCommonParams(method: string, session: string, appKey: string, additionalParams?: IDataObject): IDataObject;
|
|
26
|
+
/**
|
|
27
|
+
* 格式化时间为快麦要求的格式
|
|
28
|
+
* @param date 日期对象
|
|
29
|
+
* @returns 格式化的时间字符串 (yyyy-MM-dd HH:mm:ss)
|
|
30
|
+
*/
|
|
31
|
+
export declare function formatKuaimaiTimestamp(date: Date): string;
|
|
32
|
+
/**
|
|
33
|
+
* 构建完整的 API 请求参数(包含签名)
|
|
34
|
+
* @param method API 方法名
|
|
35
|
+
* @param session Access Token
|
|
36
|
+
* @param appKey App Key
|
|
37
|
+
* @param appSecret App Secret
|
|
38
|
+
* @param signMethod 签名方法
|
|
39
|
+
* @param businessParams 业务参数
|
|
40
|
+
* @returns 包含签名的完整请求参数
|
|
41
|
+
*/
|
|
42
|
+
export declare function buildKuaimaiRequestParams(method: string, session: string, appKey: string, appSecret: string, signMethod: string, businessParams?: IDataObject): IDataObject;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateKuaimaiSignature = generateKuaimaiSignature;
|
|
4
|
+
exports.buildKuaimaiCommonParams = buildKuaimaiCommonParams;
|
|
5
|
+
exports.formatKuaimaiTimestamp = formatKuaimaiTimestamp;
|
|
6
|
+
exports.buildKuaimaiRequestParams = buildKuaimaiRequestParams;
|
|
7
|
+
const crypto_1 = require("crypto");
|
|
8
|
+
/**
|
|
9
|
+
* 生成快麦 API 签名
|
|
10
|
+
* @param params 所有请求参数(包括公共参数和业务参数,但不包括 sign 参数)
|
|
11
|
+
* @param secret App Secret
|
|
12
|
+
* @param signMethod 签名方法:hmac | md5 | hmac-sha256
|
|
13
|
+
* @returns 签名字符串(32位大写十六进制)
|
|
14
|
+
*/
|
|
15
|
+
function generateKuaimaiSignature(params, secret, signMethod = 'hmac') {
|
|
16
|
+
// 1. 移除 sign 参数、null 值和 undefined 值
|
|
17
|
+
const filteredParams = {};
|
|
18
|
+
Object.keys(params).forEach((key) => {
|
|
19
|
+
const value = params[key];
|
|
20
|
+
if (key !== 'sign' && value !== null && value !== undefined) {
|
|
21
|
+
filteredParams[key] = value;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
// 2. 按照参数名 ASCII 码排序
|
|
25
|
+
const sortedKeys = Object.keys(filteredParams).sort();
|
|
26
|
+
// 3. 拼接参数名和参数值
|
|
27
|
+
let signString = '';
|
|
28
|
+
// MD5 方法需要在前后加 secret
|
|
29
|
+
if (signMethod === 'md5') {
|
|
30
|
+
signString = secret;
|
|
31
|
+
}
|
|
32
|
+
sortedKeys.forEach((key) => {
|
|
33
|
+
signString += key + String(filteredParams[key]);
|
|
34
|
+
});
|
|
35
|
+
if (signMethod === 'md5') {
|
|
36
|
+
signString += secret;
|
|
37
|
+
}
|
|
38
|
+
// 4. 生成签名
|
|
39
|
+
let signature;
|
|
40
|
+
switch (signMethod) {
|
|
41
|
+
case 'md5':
|
|
42
|
+
signature = (0, crypto_1.createHash)('md5').update(signString, 'utf8').digest('hex');
|
|
43
|
+
break;
|
|
44
|
+
case 'hmac':
|
|
45
|
+
signature = (0, crypto_1.createHmac)('md5', secret).update(signString, 'utf8').digest('hex');
|
|
46
|
+
break;
|
|
47
|
+
case 'hmac-sha256':
|
|
48
|
+
signature = (0, crypto_1.createHmac)('sha256', secret).update(signString, 'utf8').digest('hex');
|
|
49
|
+
break;
|
|
50
|
+
default:
|
|
51
|
+
throw new Error(`不支持的签名方法: ${signMethod}`);
|
|
52
|
+
}
|
|
53
|
+
// 5. 转换为大写并返回
|
|
54
|
+
return signature.toUpperCase();
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* 构建快麦 API 公共参数
|
|
58
|
+
* @param method API 方法名
|
|
59
|
+
* @param session Access Token
|
|
60
|
+
* @param appKey App Key
|
|
61
|
+
* @param additionalParams 额外的公共参数
|
|
62
|
+
* @returns 公共参数对象
|
|
63
|
+
*/
|
|
64
|
+
function buildKuaimaiCommonParams(method, session, appKey, additionalParams) {
|
|
65
|
+
const timestamp = formatKuaimaiTimestamp(new Date());
|
|
66
|
+
const commonParams = {
|
|
67
|
+
method,
|
|
68
|
+
appKey,
|
|
69
|
+
timestamp,
|
|
70
|
+
format: 'json',
|
|
71
|
+
version: '1.0',
|
|
72
|
+
sign_method: (additionalParams === null || additionalParams === void 0 ? void 0 : additionalParams.sign_method) || 'hmac',
|
|
73
|
+
session,
|
|
74
|
+
};
|
|
75
|
+
// 合并额外的参数
|
|
76
|
+
if (additionalParams) {
|
|
77
|
+
Object.assign(commonParams, additionalParams);
|
|
78
|
+
}
|
|
79
|
+
return commonParams;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* 格式化时间为快麦要求的格式
|
|
83
|
+
* @param date 日期对象
|
|
84
|
+
* @returns 格式化的时间字符串 (yyyy-MM-dd HH:mm:ss)
|
|
85
|
+
*/
|
|
86
|
+
function formatKuaimaiTimestamp(date) {
|
|
87
|
+
const year = date.getFullYear();
|
|
88
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
89
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
90
|
+
const hours = String(date.getHours()).padStart(2, '0');
|
|
91
|
+
const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
92
|
+
const seconds = String(date.getSeconds()).padStart(2, '0');
|
|
93
|
+
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* 构建完整的 API 请求参数(包含签名)
|
|
97
|
+
* @param method API 方法名
|
|
98
|
+
* @param session Access Token
|
|
99
|
+
* @param appKey App Key
|
|
100
|
+
* @param appSecret App Secret
|
|
101
|
+
* @param signMethod 签名方法
|
|
102
|
+
* @param businessParams 业务参数
|
|
103
|
+
* @returns 包含签名的完整请求参数
|
|
104
|
+
*/
|
|
105
|
+
function buildKuaimaiRequestParams(method, session, appKey, appSecret, signMethod, businessParams) {
|
|
106
|
+
// 构建公共参数
|
|
107
|
+
const commonParams = buildKuaimaiCommonParams(method, session, appKey, {
|
|
108
|
+
sign_method: signMethod,
|
|
109
|
+
});
|
|
110
|
+
// 合并业务参数
|
|
111
|
+
const allParams = { ...commonParams };
|
|
112
|
+
if (businessParams) {
|
|
113
|
+
Object.keys(businessParams).forEach((key) => {
|
|
114
|
+
const value = businessParams[key];
|
|
115
|
+
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
|
116
|
+
allParams[key] = value;
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
// 生成签名
|
|
121
|
+
const sign = generateKuaimaiSignature(allParams, appSecret, signMethod);
|
|
122
|
+
// 返回完整参数(包含签名)
|
|
123
|
+
return {
|
|
124
|
+
...allParams,
|
|
125
|
+
sign,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2
|
+
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"/>
|
|
3
|
+
<circle cx="9" cy="9" r="2"/>
|
|
4
|
+
<path d="m21 15-3.086-3.086a2 2 0 0 0-1.414-.586H13l-2.5 2.5"/>
|
|
5
|
+
<path d="M3 3l3 3 2-2 4 4"/>
|
|
6
|
+
</svg>
|
package/index.js
ADDED
|
Binary file
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2
|
+
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"/>
|
|
3
|
+
<circle cx="9" cy="9" r="2"/>
|
|
4
|
+
<path d="m21 15-3.086-3.086a2 2 0 0 0-1.414-.586H13l-2.5 2.5"/>
|
|
5
|
+
<path d="M3 3l3 3 2-2 4 4"/>
|
|
6
|
+
</svg>
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "n8n-nodes-kuaimai",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "快麦ERP开放平台的 n8n 节点 - 基于官方API实现订单、商品、库存管理",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"n8n-community-node-package",
|
|
7
|
+
"n8n",
|
|
8
|
+
"kuaimai",
|
|
9
|
+
"erp",
|
|
10
|
+
"ecommerce"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"homepage": "https://github.com/gabrielsworld/n8n-nodes-kuaimai",
|
|
14
|
+
"author": {
|
|
15
|
+
"name": "gabrielsworld",
|
|
16
|
+
"email": "gabrielsworld@github.com"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/gabrielsworld/n8n-nodes-kuaimai.git"
|
|
21
|
+
},
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"main": "index.js",
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsc && gulp build:icons",
|
|
28
|
+
"dev": "tsc --watch",
|
|
29
|
+
"format": "prettier nodes credentials --write",
|
|
30
|
+
"lint": "eslint nodes credentials --ext .ts",
|
|
31
|
+
"lintfix": "eslint nodes credentials --ext .ts --fix",
|
|
32
|
+
"prepublishOnly": "npm run build && npm run lint -s",
|
|
33
|
+
"test": "jest",
|
|
34
|
+
"test:watch": "jest --watch",
|
|
35
|
+
"test:coverage": "jest --coverage"
|
|
36
|
+
},
|
|
37
|
+
"n8n": {
|
|
38
|
+
"n8nNodesApiVersion": 1,
|
|
39
|
+
"credentials": [
|
|
40
|
+
"dist/credentials/KuaimaiCredentials.credentials.js"
|
|
41
|
+
],
|
|
42
|
+
"nodes": [
|
|
43
|
+
"dist/nodes/KuaimaiErp/KuaimaiErp.node.js"
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/jest": "^29.5.5",
|
|
48
|
+
"@types/nock": "^10.0.3",
|
|
49
|
+
"@types/node": "^18.16.16",
|
|
50
|
+
"@typescript-eslint/eslint-plugin": "^6.7.0",
|
|
51
|
+
"@typescript-eslint/parser": "^6.7.0",
|
|
52
|
+
"eslint": "^8.49.0",
|
|
53
|
+
"eslint-plugin-n8n-nodes-base": "^1.16.1",
|
|
54
|
+
"gulp": "^4.0.2",
|
|
55
|
+
"jest": "^29.7.0",
|
|
56
|
+
"n8n-workflow": "^1.15.0",
|
|
57
|
+
"nock": "^14.0.10",
|
|
58
|
+
"prettier": "^3.0.3",
|
|
59
|
+
"ts-jest": "^29.1.1",
|
|
60
|
+
"typescript": "^5.2.2"
|
|
61
|
+
},
|
|
62
|
+
"dependencies": {
|
|
63
|
+
"fast-check": "^3.13.2",
|
|
64
|
+
"n8n-core": "^1.15.0"
|
|
65
|
+
}
|
|
66
|
+
}
|
package/publish-npm.bat
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
@echo off
|
|
2
|
+
REM 发布 n8n-nodes-kuaimai 到 npm 公共 registry
|
|
3
|
+
REM 使用方法: publish-npm.bat [你的2FA代码]
|
|
4
|
+
|
|
5
|
+
echo ========================================
|
|
6
|
+
echo 发布 n8n-nodes-kuaimai 到 npm
|
|
7
|
+
echo ========================================
|
|
8
|
+
echo.
|
|
9
|
+
|
|
10
|
+
REM 检查是否提供了 2FA 代码
|
|
11
|
+
if "%1"=="" (
|
|
12
|
+
echo [错误] 请提供 2FA 代码作为参数
|
|
13
|
+
echo.
|
|
14
|
+
echo 使用方法:
|
|
15
|
+
echo publish-npm.bat 123456
|
|
16
|
+
echo.
|
|
17
|
+
echo 其中 123456 是你的 npm 2FA 应用中显示的 6 位数字代码
|
|
18
|
+
echo.
|
|
19
|
+
pause
|
|
20
|
+
exit /b 1
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
set OTP_CODE=%1
|
|
24
|
+
|
|
25
|
+
echo [1/5] 检查 npm 登录状态...
|
|
26
|
+
npm whoami
|
|
27
|
+
if errorlevel 1 (
|
|
28
|
+
echo [错误] 未登录 npm,请先运行: npm login
|
|
29
|
+
pause
|
|
30
|
+
exit /b 1
|
|
31
|
+
)
|
|
32
|
+
echo.
|
|
33
|
+
|
|
34
|
+
echo [2/5] 检查 registry 配置...
|
|
35
|
+
npm config get registry
|
|
36
|
+
echo.
|
|
37
|
+
|
|
38
|
+
echo [3/5] 运行构建和检查...
|
|
39
|
+
call npm run build
|
|
40
|
+
if errorlevel 1 (
|
|
41
|
+
echo [错误] 构建失败
|
|
42
|
+
pause
|
|
43
|
+
exit /b 1
|
|
44
|
+
)
|
|
45
|
+
echo.
|
|
46
|
+
|
|
47
|
+
echo [4/5] 正在发布到 npm...
|
|
48
|
+
echo 使用 2FA 代码: %OTP_CODE%
|
|
49
|
+
npm publish --access public --registry=https://registry.npmjs.org/ --otp=%OTP_CODE%
|
|
50
|
+
if errorlevel 1 (
|
|
51
|
+
echo.
|
|
52
|
+
echo [错误] 发布失败
|
|
53
|
+
echo.
|
|
54
|
+
echo 可能的原因:
|
|
55
|
+
echo 1. 2FA 代码已过期(每 30 秒更新一次)
|
|
56
|
+
echo 2. 版本号已存在
|
|
57
|
+
echo 3. 网络问题
|
|
58
|
+
echo.
|
|
59
|
+
echo 解决方案:
|
|
60
|
+
echo - 获取新的 2FA 代码并重新运行
|
|
61
|
+
echo - 或运行: npm version patch 更新版本号
|
|
62
|
+
echo.
|
|
63
|
+
pause
|
|
64
|
+
exit /b 1
|
|
65
|
+
)
|
|
66
|
+
echo.
|
|
67
|
+
|
|
68
|
+
echo [5/5] 验证发布结果...
|
|
69
|
+
timeout /t 5 /nobreak >nul
|
|
70
|
+
echo.
|
|
71
|
+
echo ========================================
|
|
72
|
+
echo 发布成功!
|
|
73
|
+
echo ========================================
|
|
74
|
+
echo.
|
|
75
|
+
echo 包信息:
|
|
76
|
+
npm view n8n-nodes-kuaimai version
|
|
77
|
+
echo.
|
|
78
|
+
echo 访问 npm 页面:
|
|
79
|
+
echo https://www.npmjs.com/package/n8n-nodes-kuaimai
|
|
80
|
+
echo.
|
|
81
|
+
echo 在 n8n 中安装:
|
|
82
|
+
echo 1. 打开 http://localhost:5678
|
|
83
|
+
echo 2. Settings -^> Community nodes -^> Install
|
|
84
|
+
echo 3. 输入: n8n-nodes-kuaimai
|
|
85
|
+
echo.
|
|
86
|
+
pause
|