跳到主要内容

轻流 x 旺店通(旗舰版)

应用场景

产品介绍:

旺店通是一款专门为电商量身定做的电商ERP系统软件,致力于提供专业的电子商务ERP解决方案,能全面覆盖线上电商、网店以及线下实体店进销存管理及wms仓储管理系统等

官网:https://www.wangdian.cn/

API文档:https://open.wangdian.cn/qjb/open/apidoc

实现目标:

通过轻流应用表单实现与旺店通(旗舰版)进行对接

Ps:

1、目前批量获取数据暂时只能存放在表格中并且只能获取部分数据,体验上会有点不好。

不过后续产品QS主动支持代码块处理即可实现定时轮训获取。如果不想要放在表格中,可以采用定制开发来实现

落地方案

原文画板

图文/视频演示

帮助文档

一、旺店通(旗舰版)接入

image.png

  • 获取必要参数,这里是测试环境测试用

image.png

  • 正式环境必要参数获取位置

image.png

注意点:

接口规范:https://open.wangdian.cn/qjb/open/guide?path=qjbguide_jkgf

  • REST风格的API,使用HTTPS协议发送POST请求调用接口。
  • HTTP请求头类型为 Content-Type: application/json 或者 Content-Type: application/xml

image.png

二、签名算法

1、签名sign介绍

image.png

image.png

2、代码块实现

以文档所举为示例,其中timestamp计算规则:秒级时间戳, 当前时间戳减去 2012-01-01 00:00:00(1325347200), 时间与服务器时间差120s内即合法。

const crypto = require('crypto');
const { differenceInSeconds } = require('date-fns');
// 当前时间
const currentDate = new Date();
// 2012-01-01 00:00:00 的时间
const startDate = new Date(2012, 0, 1, 0, 0, 0);
// 时间戳差值
const timestampDiff = differenceInSeconds(currentDate, startDate);

// 第一步:将 appsecret 分割为 secret 和 salt
const appsecret = '693f9fed686bfe13441385da98b436b6:dd488d0802b1e431e4c72cd355847853';
const [secret, salt] = appsecret.split(':');

// 第二步:定义请求参数
const params = {
key: 'czhc',
salt: salt,
method: 'wms.stockout.Sales.weighingExt',
timestamp: timestampDiff,
v: '1.0',
sid: 'wdterp30',
body: '["xc109393939393939","",1.2,0,false]'
};

// 第三步:按键名对参数进行排序
const sortedParams = Object.keys(params).sort().reduce((acc, key) => {
acc[key] = params[key];
return acc;
}, {});

// 第四步:拼接排序后的键值对
const concatenatedString = `${secret}${Object.entries(sortedParams).map(([key, value]) => `${key}${value}`).join('')}${secret}`;

// 第五步:计算 MD5 哈希值
const sign = crypto.createHash('md5').update(concatenatedString).digest('hex');

// 第六步:将 sign 参数添加到 params 对象中
params.sign = sign;

qf_output={params}

3、代码测试

image.png

三、订单查询为例

对应的接口文档:https://open.wangdian.cn/qjb/open/apidoc/doc?path=sales.TradeQuery.queryWithDetail

image.png

1、代码块实现

  • 具体查询参数内容根据接口文档去填写,填写至params中

image.png

  • appkey、appsecret以及sid需替换为咱们旺店通所提供的具体参数内容
  • 这里end_time、start_time为插入表单中的字段

image.png

这里最后代码中的处理是对于接口返回的数据进行处理,由于order是数组,每个元素中又有数组detail_list,在轻流中相当于表格行中嵌入表格,轻流并不支持,所以将数组处理进行整合。

处理逻辑是:将order每个元素的数据除了detail_list数组以外的数据放进detail_list的每个元素中,然后最后整合输出新的list数组

const { differenceInSeconds } = require('date-fns');
const crypto = require('crypto');
const axios = require('axios');

// 当前时间
const currentDate = new Date();
// 2012-01-01 00:00:00 的时间
const startDate = new Date(2012, 0, 1, 0, 0, 0);
// 时间戳差值
const timestampDiff = differenceInSeconds(currentDate, startDate);

// 第一步:将 appsecret 分割为 secret 和 salt
const appsecret = '693f9fed686bfe13441385da98b436b6:dd488d0802b1e431e4c72cd355847853';
const [secret, salt] = appsecret.split(':');

let data = JSON.stringify([
{
"start_time": qf_field.{开始日期$$18639AE02$$},
"end_time": qf_field.{结束日期$$18639AE18$$}
}
]);
let parsedData = JSON.parse(data);

// 第二步:定义请求参数
const params = {
key: 'czhc',
salt: salt,
method: 'sales.TradeQuery.queryWithDetail',
timestamp: timestampDiff,
v: '1.0',
sid: 'wdterp30',
page_size:50,
page_no:0,
body: data
};

// 第三步:按键名对参数进行排序
const sortedParams = Object.keys(params).sort().reduce((acc, key) => {
acc[key] = params[key];
return acc;
}, {});

// 第四步:拼接排序后的键值对
const concatenatedString = `${secret}${Object.entries(sortedParams).map(([key, value]) => `${key}${value}`).join('')}${secret}`;

// 第五步:计算 MD5 哈希值
const sign = crypto.createHash('md5').update(concatenatedString).digest('hex');

// 第六步:将 sign 参数添加到 params 对象中
params.sign = sign;

let config = {
method: 'post',
maxBodyLength: Infinity,
url: `http://wdt.wangdian.cn/openapi?sid=${params.sid}&key=${params.key}&salt=${params.salt}&method=${params.method}&v=${params.v}&timestamp=${params.timestamp}&sign=${params.sign}`,
headers: {
'Content-Type': 'application/json'
},
data : data
};
if(parsedData[0].start_time==null || parsedData[0].end_time==null){
qf_output={'data':null}
}else{
axios(config)
.then(function (res) {
const resdata=res.data;
const orders = resdata.data.order;
const newList = [];
//由于order中有数组detail_list,在轻流中相当于表格行中嵌入表格,轻流并不支持,所以将数组处理进行整合
orders.forEach(order => {
const detailList = order.detail_list;

detailList.forEach(detail => {
const newDetail = { ...detail, ...order };
delete newDetail.detail_list;
newList.push(newDetail);
});
});
qf_output={'list':newList}
});
}

2、字段接收配置

  • 这里只配置了部分字段,可以根据自己的需求去具体配置

image.png

image.png

四、供应商信息推送为例

对应的接口文档:https://open.wangdian.cn/qjb/open/apidoc/doc?path=setting.PurchaseProvider.push

image.png

1、代码块实现

  • 表单配置参考

image.png

  • 这里的请求参数根据具体接口文档去修改
  • qf_field.{供应商编号$$18644BC92$$} :表单中供应商编号字段,其余插入字段参考该字段

image.png

  • appkey、appsecret以及sid需替换为咱们旺店通所提供的具体参数内容
const { differenceInSeconds } = require('date-fns');
const crypto = require('crypto');
const axios = require('axios');

// 当前时间
const currentDate = new Date();
// 2012-01-01 00:00:00 的时间
const startDate = new Date(2012, 0, 1, 0, 0, 0);
// 时间戳差值
const timestampDiff = differenceInSeconds(currentDate, startDate);

// 第一步:将 appsecret 分割为 secret 和 salt
const appsecret = '693f9fed686bfe13441385da98b436b6:dd488d0802b1e431e4c72cd355847853';
const [secret, salt] = appsecret.split(':');

let data = JSON.stringify([
{
"provider_no":qf_field.{供应商编号$$18644BC92$$} ,
"provider_name": qf_field.{供应商名称$$18644BCA8$$},
"contact": qf_field.{联系人$$18644BCA9$$}
}
]);

// 第二步:定义请求参数
const params = {
key: 'czhc',
salt: salt,
method: 'setting.PurchaseProvider.push',
timestamp: timestampDiff,
v: '1.0',
sid: 'wdterp30',
body: data
};

// 第三步:按键名对参数进行排序
const sortedParams = Object.keys(params).sort().reduce((acc, key) => {
acc[key] = params[key];
return acc;
}, {});

// 第四步:拼接排序后的键值对
const concatenatedString = `${secret}${Object.entries(sortedParams).map(([key, value]) => `${key}${value}`).join('')}${secret}`;

// 第五步:计算 MD5 哈希值
const sign = crypto.createHash('md5').update(concatenatedString).digest('hex');

// 第六步:将 sign 参数添加到 params 对象中
params.sign = sign;

let config = {
method: 'post',
maxBodyLength: Infinity,
url: `http://wdt.wangdian.cn/openapi?sid=${params.sid}&key=${params.key}&salt=${params.salt}&method=${params.method}&v=${params.v}&timestamp=${params.timestamp}&sign=${params.sign}`,
headers: {
'Content-Type': 'application/json'
},
data : data
};
axios(config)
.then(function (res) {
const resdata=res.data;
qf_output={resdata}
});
字段接收配置
  • 上述配置完成后,点击代码块,推送的结果信息会推到对应字段中

image.pngimage.png

2、webhook实现

  • 通过代码块计算签名之后,提交数据进入流程触发webhook去完成调用接口

  • 注意点:生成签名后,需要在2min之内提交数据触发webhook,因为旺店通旗舰版时间与服务器时间差120s内即合法。

image.png

实现路径
  • 代码块签名
const { differenceInSeconds } = require('date-fns');
const crypto = require('crypto');
const axios = require('axios');

// 当前时间
const currentDate = new Date();
// 2012-01-01 00:00:00 的时间
const startDate = new Date(2012, 0, 1, 0, 0, 0);
// 时间戳差值
const timestampDiff = differenceInSeconds(currentDate, startDate);

// 第一步:将 appsecret 分割为 secret 和 salt
const appsecret = '693f9fed686bfe13441385da98b436b6:dd488d0802b1e431e4c72cd355847853';
const [secret, salt] = appsecret.split(':');

let data = JSON.stringify([
{
"provider_no":qf_field.{供应商编号$$18644DBE9$$},
"provider_name":qf_field.{供应商名称$$18644DBEA$$},
"contact": qf_field.{联系人$$18644DBEB$$}
}
]);

// 第二步:定义请求参数
const params = {
key: 'czhc',
salt: salt,
method: 'setting.PurchaseProvider.push',
timestamp: timestampDiff,
v: '1.0',
sid: 'wdterp30',
body: data
};

// 第三步:按键名对参数进行排序
const sortedParams = Object.keys(params).sort().reduce((acc, key) => {
acc[key] = params[key];
return acc;
}, {});

// 第四步:拼接排序后的键值对
const concatenatedString = `${secret}${Object.entries(sortedParams).map(([key, value]) => `${key}${value}`).join('')}${secret}`;

// 第五步:计算 MD5 哈希值
const sign = crypto.createHash('md5').update(concatenatedString).digest('hex');

// 第六步:将 sign 参数添加到 params 对象中
params.sign = sign;

qf_output={params}
字段接收配置

image.png

image.png

image.png

  • webhook配置
  • 只需要配置param以及body中内容即可,Method和URL是固定的

image.png

image.png