超详细教程!手把手教你如何在轻流内实现支付宝扫码支付、银企直联

❓每次打款前,你都要核对三四遍卡号金额,生怕输错账户,打错款目

❓繁杂的付款工作占用大部分的工作时间,财务产出的整体价值不高

❓依靠人工手动从银端获取回款,不仅耗时长,而且效率低

用轻流,这些烦恼都可以统统甩开!

通过丰富的 open api 接口和强大的 q-linker、webhook数据传输能力,直接在轻流系统内就可以实现支付宝收款/退款、银行卡转账并查询流水和电子回单啦!

(⚠️银企直联目前仅支持中国银行)

口说无凭,一起来看看实现效果吧👇

🌟实现步骤

教程目录:

⚠️tips:

因步骤十分详尽所以较长,耐心些,按步骤操作就可以实现视频中的同款效果

(如果你还不是轻流用户,快点击👉👈,体验试用吧~)

 

支付宝扫码支付 教程

 

1、准备工作

  • 点击登录👉👈
  • 进入后台,创建网页应用

  • 绑定产品——【当面付】,并进行开通

  • 接口加签方式设置

 

2、获取调用接口所需具体公共参数

以扫码付接口为例:

  • appid:应用id

其余参数根据文档要求来进行获取

3、表单设计

1. 支付宝订单预创建并支付

其中【生成支付链接】与【确认支付状态】为代码块,【生成支付二维码】为q-linker字段

1.1. 生成支付链接

1.1.1. 代码注释

具体调用接口文档:

⚠️注意:所生成的二维码有效时间为2小时

app_id:需要替换成具体调用的应用id

qf_field.{商品列表信息$$17b54dd0c$$},为表单中商品列表信息表格字段

其中以 field_169208787 为例,表示商品列表信息表格中商品数量子字段 id

field_id 获取方式 

qf_field.{商户订单号$$17b54dd0a$$},为表单中商户订单号字段

qf_field.{订单总金额(单位为元)$$17b54dd0b$$},为表单中订单总金额(单位为元)字段

qf_field.{订单标题$$17b44c092$$},为表单中订单标题字段

应用私钥:只需要替换成具体调用的应用私钥


生成支付链接:

const axios = require(‘axios’);
const crypto = require(‘crypto’);
const { format } = require(‘date-fns’);const currentdate = new date();
const formatteddate = format(currentdate, ‘yyyy-mm-dd hh:mm:ss’);
// 原始数据
const data = {
“timestamp”:formatteddate,
“method”: “alipay.trade.precreate”,
“app_id”: “2021003155650***”,
“sign_type”: “rsa2”,
“version”: “1.0”,
“charset”: “utf-8”
};
const table = qf_field.{商品列表信息$$17b54dd0c$$};const goodsdetail = table.map(item => {
const newitem = {
“quantity”: item.field_169208787,
“goods_name”: item.field_169208786,
“goods_id”: item.field_169208785,
“price”: item.field_169208788
};
return newitem;
});//将新的 goods_detail 赋值给 data 中的 biz_content
data.biz_content =`{“out_trade_no”: qf_field.{商户订单号$$17b54dd0a$$},”total_amount”:qf_field.{订单总金额(单位为元)$$17b54dd0b$$},”subject”:qf_field.{订单标题$$17b44c092$$},”goods_detail”:${json.stringify(goodsdetail)}}`;// 第一步:剔除sign字段
const { sign, …datawithoutsign } = data;// 第二步:剔除值为空的参数
const filtereddata = object.fromentries(object.entries(datawithoutsign).filter(([key, value]) => value !== ”));// 第三步:按键的ascii码值递增排序
const sortedparams = object.keys(filtereddata).sort();// 第四步:将排序后的参数与其对应的值按照”参数=参数值”的格式组合起来
const concatenatedparams = sortedparams.map(key => `${key}=${filtereddata[key]}`).join(‘&’);// 第五步:生成待签名字符串
const signstring = concatenatedparams;// 使用私钥对待签名字符串进行加密
const privatekey = `—–begin private key—–
mi****danbgkqhkig9w0baqefaascbkcwggsjageaa……………
—–end private key—–`;const signer = crypto.createsign(‘rsa-sha256’);
signer.update(signstring, ‘utf8’);
const signature = signer.sign(privatekey);
const sig=signature.tostring(‘base64’);
const encodedsig = encodeuricomponent(sig);let config = {
method: ‘get’,
maxbodylength: infinity,
url: `https://openapi.alipay.com/gateway.do?timestamp=${formatteddate}&method=${data.method}&app_id=${data.app_id}&sign_type=${data.sign_type}&sign=${encodedsig}&version=${data.version}&charset=${data.charset}&biz_content=${data.biz_content}`
};axios(config).then(function (res) {
qf_output={‘data’:res.data}
});

 

1.1.2. 代码测试
1.1.3. 解析配置
1.1.4. 字段接收配置
1.2. 生成支付二维码

该字段为q_linker,调用接口将支付链接转为支付二维码(具体接口文档:)

  • 需要点击申请appid,去获取对应的app_id和app_srcret

1.2.1. q-linker 配置

  • url:https://www.mxnzp.com/api/qrcode/create/single
  • queryparam:

  • method:get
  • json path:

  • 字段接收配置

 

1.3. 确认支付状态

1.3.1. 代码注释具体调用接口文档:

app_id:需要替换成具体调用的应用id

qf_field.{商户订单号$$17b54dd0a$$},为表单中商户订单号字段

应用私钥:只需要替换成具体调用的应用私钥

 

确认支付状态:

const axios = require(‘axios’);
const crypto = require(‘crypto’);
const { format } = require(‘date-fns’);const currentdate = new date();
const formatteddate = format(currentdate, ‘yyyy-mm-dd hh:mm:ss’);
// 原始数据
const data = {
“timestamp”:formatteddate,
“method”: “alipay.trade.query”,
“app_id”: “2021003155650***”,
“sign_type”: “rsa2”,
“version”: “1.0”,
“charset”: “utf-8”
};
data.biz_content =`{“out_trade_no”: qf_field.{商户订单号$$17b54dd0a$$}}`;
// 第一步:剔除sign字段
const { sign, …datawithoutsign } = data;

// 第二步:剔除值为空的参数
const filtereddata = object.fromentries(object.entries(datawithoutsign).filter(([key, value]) => value !== ”));// 第三步:按键的ascii码值递增排序
const sortedparams = object.keys(filtereddata).sort();// 第四步:将排序后的参数与其对应的值按照”参数=参数值”的格式组合起来
const concatenatedparams = sortedparams.map(key => `${key}=${filtereddata[key]}`).join(‘&’);// 第五步:生成待签名字符串
const signstring = concatenatedparams;// 使用私钥对待签名字符串进行加密
const privatekey = `—–begin private key—–
mii****bgkqhkig9w0baqefaascbkcwggsjageaa………………….
—–end private key—–`;const signer = crypto.createsign(‘rsa-sha256’);
signer.update(signstring, ‘utf8’);
const signature = signer.sign(privatekey);
const sig=signature.tostring(‘base64’);
const encodedsig = encodeuricomponent(sig);
let config = {
method: ‘get’,
maxbodylength: infinity,
url: `https://openapi.alipay.com/gateway.do?timestamp=${formatteddate}&method=${data.method}&app_id=${data.app_id}&sign_type=${data.sign_type}&sign=${encodedsig}&version=${data.version}&charset=${data.charset}&biz_content=${data.biz_content}`
};
axios(config).then(function (res) {
qf_output={‘data’:res.data}
});

1.3.2. 代码测试
1.3.3. 解析配置
1.3.4. 字段接收配置

1.4. 流程配置

1.4.1. 申请人节点配置
1.4.2. 确认支付信息并扫码支付
1.4.3. 告知用户

1.4.4. webhook节点

具体接口文档:
  • accesstoken:轻商城——拓展插件——openapi

  • 节点id获取方式
可以调用接口来进行获取:

2. 支付宝申请订单退款

2.1. 商户订单号

2.2. 订单总金额

 

2.3. 退款

2.3.1. 代码注释具体调用接口文档:

⚠️注意:交易超过约定时间(签约时设置的可退款时间)的订单无法进行退款。

app_id:需要替换成具体调用的应用id

qf_field.{商户订单号$$17b598970$$}:表单中商户订单号字段

qf_field.{退款金额$$17b598089$$}:表单中退款金额字段

qf_field.{退款原因说明$$17b59808a$$}:表单中退款原因说明字段

应用私钥:只需要替换成具体调用的应用私钥

退款:

const axios = require(‘axios’);
const crypto = require(‘crypto’);
const { format } = require(‘date-fns’);const currentdate = new date();
const formatteddate = format(currentdate, ‘yyyy-mm-dd hh:mm:ss’);
// 原始数据
const data = {
“timestamp”:formatteddate,
“method”: “alipay.trade.refund”,
“app_id”: “2021003155650***”,
“sign_type”: “rsa2”,
“version”: “1.0”,
“charset”: “utf-8”
};
data.biz_content =`{“out_trade_no”:qf_field.{商户订单号$$17b598970$$},”refund_amount”:qf_field.{退款金额$$17b598089$$},”refund_reason”:qf_field.{退款原因说明$$17b59808a$$}}`;
// 第一步:剔除sign字段
const { sign, …datawithoutsign } = data;

// 第二步:剔除值为空的参数
const filtereddata = object.fromentries(object.entries(datawithoutsign).filter(([key, value]) => value !== ”));// 第三步:按键的ascii码值递增排序
const sortedparams = object.keys(filtereddata).sort();// 第四步:将排序后的参数与其对应的值按照”参数=参数值”的格式组合起来
const concatenatedparams = sortedparams.map(key => `${key}=${filtereddata[key]}`).join(‘&’);// 第五步:生成待签名字符串
const signstring = concatenatedparams;// 使用私钥对待签名字符串进行加密
const privatekey = `—–begin private key—–
mii*****nbgkqhkig9w0baqefaascbkcwggsjageaa……………………
—–end private key—–`;const signer = crypto.createsign(‘rsa-sha256’);
signer.update(signstring, ‘utf8’);
const signature = signer.sign(privatekey);
const sig=signature.tostring(‘base64’);
const encodedsig = encodeuricomponent(sig);
let config = {
method: ‘get’,
maxbodylength: infinity,
url: `https://openapi.alipay.com/gateway.do?timestamp=${formatteddate}&method=${data.method}&app_id=${data.app_id}&sign_type=${data.sign_type}&sign=${encodedsig}&version=${data.version}&charset=${data.charset}&biz_content=${data.biz_content}`
};axios(config).then(function (res) {
qf_output={‘data’:res.data}});

2.3.2. 解析配置
2.3.3. 字段接收配置

 

 

银企直联(中国银行)教程

在实现中国银行的公对公转账公对私转账,查询流水,获取电子回执单功能

1、落地方案

需要二次开发,由中间件根据中国银行银企对接接口规范要求,封装以下四个接口:

    1. 公对公转账
    2. 公对私转账
    3. 查询流水
    4. 电子回单查询

1.1 转账

转账效果有两种:直接转出不提示,需要在中国银行app上确认,两种方式需要在银行柜台做变更

转账时序图

📚方案简述:

    • 在轻流发起转账,通过webhook携带三个参数访问中间件;
    • 中间件根据参数访问对应的前置机接口,前置机执行对应操作将转账消息加入银行队列
    • 根据转账的表现,银行执行转账操作时,会给中国银行app发送确认消息(或者直接转账成功,具体表现需要银行柜台进行修改)

 

1.2 查询流水

查询流水时序图

📚方案简述:

    • 查询银行流水为定时任务,根据业务需要可设置多久拉取一次
    • 拉取昨天和今天的流水数据,并在中间件解析成符合轻流要求的格式
    • 中间件通过qs被动将数据推送至轻流应用中,并比对更新

 

1.3 电子回单查询

电子回单查询时序图

📚方案简述:

  • 中间件访问回单下载接口后,前置机返回回单文件的名称
  • 银行生成请求时间段内的回单,回单为pdf文件,统一放在压缩文件内。
  • 中间件轮询是否已经生成回单文件,生成后将文件上传至对象存储服务,并返回文件的路径;
  • 中间件将返回的文件路径推送至轻流,并匹配至轻流上传附件字段。

🎉最终效果

  • 在轻流实现转账服务
  • 可在轻流应用中查询到流水和电子回单

⚠️备注

  • 银企直联属于银行系统,每年需要付款使用
  • 银行会提供前置机架构,所有对银行的请求都会先到前置机处理
  • 只有windows的系统,不能云部署
  • 访问中国银行银企对接接口需要先签到,签到有效期为15分钟,可缓存登录状态

 

 

轻流

发表评论

电子邮件地址不会被公开。