今年利用业余时间搞了个web应用,在支付环节卡住了,因为支付宝和微信都不支持个人收款,必须要有公司资质,没办法,只能google下看看是否有人和我遇到相同问题,果然有很多解决方案,研究了一个多礼拜,发现个人收款都是收费的,而且还不稳定,服务也非常差,问个问题半天甚至几天后才有回答。最后没办法只能自己各种研究,搞出了一种真正免费的个人免签支付方案(不需了解Andriod,不需了解后端开发,甚至不需要写一行代码),不敢独享,现分享给大家。
基本原理
终极原理很简单,就一句话:Android端应用将收到的个人微信的收款信息通知后端服务,后端服务分析出谁支付了多少钱等信息,然后通知开发者支付完成并自动发货。
操作流程
1. 开发者上传微信的个人收款码到平台。
2. 用户发起请求支付服务。
3. 平台返回相匹配的收款二维码并展示给用户。
4. 用户完成扫码支付。
5. 安装有收款微信的Android手机收到用户完成支付的通知。
6. Android端应用将收款信息通知后端服务。
7. 后端服务分析并校验无误后,通知开发者用户已经完成支付,可以自动发货了。
下面介绍利用「冰狐智能辅助」实现免费的个人免签支付的方案,您只需要详细案以下步骤操作,不需要写一行代码即可实现免费的个人免签支付。分两部分实现,一部分是移动端,负责捕获收款信息;另一部分是后端服务,负责解析并通知开发者支付结果。在之前请先免费注册一个用户。
构建移动端
- 下载「冰狐智能辅助」APP并安装,安装完成后请登录。登录时请按提示打开所有权限,具体下载地址和详细安装配置过程请参考这里。
- 登录网页,打开web页面「移动端」/「移动端脚本」,新建一个名为“个人支付”的脚本,将如下JS脚本粘贴到这里并保存。
-
function
main(
) {
-
while (
true) {
-
}
-
}
-
-
function
cbNotification(
textList, className, packageName, event) {
-
for (
var item
of textList) {
-
if (item.
includes(
'微信支付')) {
-
var arr = item.
fetchNumber();
-
if (arr.
length >
0) {
-
var ret =
callMicroService(
'pay_notify', [rsUUID,
1, arr[arr.
length -
1]]);
-
console.
log(
'call ret:' + ret);
-
}
-
return
true;
-
}
-
}
-
return
false;
-
}
- 打开web页面「移动端」/「我的设备」,找到刚才登录的手机,然后选择“编辑”按钮,修改“默认脚本”为上面新建的“个人支付”脚本。
创建微服务脚本
微服务脚本用于实现后端的业务逻辑,比如:上传和查看支付二维码,查看支付订单,通知开发者支付结果等功能。
打开web页面「微服务」/「微服务脚本」新建如下脚本,并将对应的JS源码粘贴进去:
- pay_notify,用于处理支付信息,并通知开发者支付结果。JS源码如下:
-
function
main(
uuid, type, price) {
-
var ret =
false;
-
price =
parseInt(price*
100);
-
var key = uuid + price;
-
var orderId =
cacheGet(key);
-
if (orderId) {
-
console.
log(
'匹配到价格,可以通知了:' + orderId);
-
var data =
dbQuery(
'order',
'*', [
'id=' + orderId]);
-
if (data && data.
length ==
1) {
-
var item = data[
0];
-
// 通知 调用者
-
var bodyParams = {
outTradeNo: item.
outTradeNo,
price: item.
price /
100.0,
realPrice: item.
realPrice /
100.0};
-
var result =
2, postResult =
httpPost(item.
notifyUrl, bodyParams);
-
if (postResult && postResult.
length >
0) {
-
if (postResult.
status ==
200 || postResult.
status ==
302) {
-
result =
1;
-
}
-
}
-
-
// change status
-
ret =
dbUpdate(
'order', [
'status=' + result], [
'id=' + orderId]);
-
if (!ret) {
-
console.
error(
'更新状态失败');
-
}
-
-
cacheRemove(key);
-
}
-
}
else {
-
console.
error(
'invalidate price:' + price);
-
}
-
-
return ret;
-
}
- add_price,用于添加支付二维码,JS源码如下:
-
function
main(
payType, price, deviceId, file) {
-
price =
parseInt(price*
100);
-
var ret =
false, qrCode =
qrDecode(file.
inputStream);
-
if (qrCode !=
'') {
-
var qRet =
dbQuery(
'price',
'count(id) as count', [
`userId='${rsOpenId}'`,
`price=${price}`,
`payType=${payType}`,
`deviceId='${deviceId}'`]);
-
if (qRet[
0].
count >
0) {
-
ret =
dbUpdate(
'price', [
`qrCode='${qrCode}'`], [
`price=${price}`,
`payType=${payType}`,
`deviceId='${deviceId}'`]);
-
}
else {
-
var iRet =
dbInsert(
'price', {
userId:rsOpenId,
price:price,
payType:payType,
deviceId:deviceId,
qrCode:qrCode});
-
ret = iRet >
0;
-
}
-
}
-
return ret;
-
}
- query_price,用于查询支付二维码,JS源码如下:
-
function
main(
fetchCountOnly, conditions, startIndex, itemCount) {
-
var jsonConditions =
JSON.
parse(conditions), params = [
`userId='${rsOpenId}'`];
-
for (
var item
of jsonConditions) {
-
if (item.
name ==
'query_type') {
-
var
type =
parseInt(item.
value);
-
if (
type >
0) {
-
params.
push(
'payType=' +
type);
-
}
-
}
-
}
-
-
if (fetchCountOnly) {
-
var qRet =
dbQuery(
'price',
'count(id) as count', params);
-
return qRet[
0].
count;
-
}
else {
-
var qRet =
dbQuery(
'price',
'*', params,
'', startIndex, itemCount);
-
for (
var item
of qRet) {
-
item.
price /=
100.0;
-
if (item.
payType ==
1) {
-
item.
payType =
'微信';
-
}
else {
-
item.
payType =
'支付宝';
-
}
-
}
-
return qRet;
-
}
-
}
- query_order,用于查询订单,JS源码如下:
-
function main (fetchCountOnly, conditions, startIndex, itemCount) {
-
var jsonConditions = JSON.parse(conditions);
-
var params = [`userId= '${rsOpenId}'`];
-
for ( var item of jsonConditions) {
-
var deviceId = item.value;
-
if (item.name == 'deviceId' && deviceId != '') {
-
params.push(`deviceId= '${deviceId}'`);
-
}
-
}
-
-
if (fetchCountOnly) {
-
var qRet = dbQuery( 'order', 'count(id) as count', params);
-
return qRet[ 0].count;
-
} else {
-
var qRet = dbQuery( 'order', '*', params, 'order by time desc', startIndex, itemCount);
-
for ( var item of qRet) {
-
item.price /= 100.0;
-
item.realPrice /= 100.0;
-
-
if (item.payType == 1) {
-
item.payType = '微信';
-
} else {
-
item.payType = '支付宝';
-
}
-
-
if (item.status == 0) {
-
item.status = '等待支付';
-
} else if (item.status == 1) {
-
item.status = '交易完成';
-
} else if (item.status == 2) {
-
item.status = '通知失败';
-
} else if (item.status == - 1) {
-
item.status = '订单过期';
-
}
-
-
var datetime = new Date();
-
datetime.setTime(item.time);
-
var year = datetime.getYear();
-
var month = datetime.getMonth() + 1 < 10 ? "0" + (datetime.getMonth() + 1) : datetime.getMonth() + 1;
-
var date = datetime.getDate() < 10 ? "0" + datetime.getDate() : datetime.getDate();
-
var hour = datetime.getHours()< 10 ? "0" + datetime.getHours() : datetime.getHours();
-
var minute = datetime.getMinutes()< 10 ? "0" + datetime.getMinutes() : datetime.getMinutes();
-
var second = datetime.getSeconds()< 10 ? "0" + datetime.getSeconds() : datetime.getSeconds();
-
var t = year + "-" + month + "-" + date+ " "+hour+ ":"+minute+ ":"+second;
-
-
item.time = t;
-
}
-
return qRet;
-
}
-
}
-
- unified_order,用于开发者请求支付,返回支付二维码,JS源码如下:
-
function
main(
payType, price, outTradeNo, notifyUrl, timeout = 120000) {
-
price =
parseInt(price*
100);
-
var ret =
null, qrImage =
'', realPrice = price;
-
var maxCount =
5, i =
0, anyRet =
null, findAny =
false;
-
while (i < maxCount) {
-
realPrice = price - i;
-
var qRet =
dbQuery(
'price',
'*', [
`userId='${rsOpenId}'`,
`payType=${payType}`,
`price=${realPrice}`]);
-
if (qRet.
length <=
0) {
-
if (!findAny) {
-
anyRet =
dbQuery(
'price',
'*', [
`userId='${rsOpenId}'`,
`payType=${payType}`,
'price=0']);
-
findAny =
true;
-
}
-
qRet = anyRet;
-
}
-
if (qRet.
length >
0) {
-
for (
var item
of qRet) {
-
var key = item.
deviceId + realPrice;
-
var cache =
cacheGet(key);
-
if (
null == cache) {
-
lock(
'malloc_price');
-
cache =
cacheGet(key);
-
if (
null == cache) {
-
// 可以分配了
-
ret =
dbInsert(
'order', {
-
userId: rsOpenId,
-
price: price,
-
realPrice: realPrice,
-
outTradeNo: outTradeNo,
-
deviceId: item.
deviceId,
-
qrCode: item.
qrCode,
-
notifyUrl: notifyUrl
-
});
-
}
-
if (
null != ret) {
-
var image =
qrEncode(item.
qrCode);
-
qrImage =
base64Encode(image);
-
cachePut(key, ret,
60000);
-
}
-
unlock(
'malloc_price');
-
-
if (
null != ret) {
-
break;
-
}
-
}
-
}
-
}
-
-
if (
null != ret) {
-
break;
-
}
-
++i;
-
}
-
-
if (
null == ret) {
-
console.
error(
'unified failed');
-
}
else {
-
return {
payTye: payType,
price: price,
realPrice: realPrice,
qrImageData: qrImage,
timeout: timeout};
-
}
-
-
return {};
-
}
- common,一些通用的函数,JS源码如下:
-
function
deletePrice(
item) {
-
var id = item.
id;
-
return
dbDelete(
'price', [
`id=${id}`]);
-
}
-
-
function
deleteOrder(
item) {
-
var id = item.
id;
-
return
dbDelete(
'order', [
`id=${id}`]);
-
}
-
-
function
getDevice(
includeAll=false) {
-
var list =
deviceList(rsOpenId);
-
var result = [];
-
if (includeAll) {
-
result.
push({
name:
'全部',
value:
''});
-
}
-
for (
var item
of list) {
-
result.
push({
name: item.
name,
value: item.
uuid});
-
}
-
return result;
-
}
创建移动端接口
移动端接口用于「冰狐智能辅助」APP端脚本调用,在这里主要用于手机端通知后端服务支付相关信息。参考文档
- 打开web页面「微服务」/「移动端接口」,新建名为“pay_notify”的接口,选择“pay_notify”脚本。
创建服务端接口
服务端接口用于第三方服务调用「冰狐智能辅助」的后端功能,这里主要用于开发者在自己的后端服务中调用生成订单的接口。参考文档
- 打开web页面「微服务」/「服务端接口」,新建名为”unified_order”的接口,选择“unified_order”脚本。
创建二维码价格数据库
价格数据库用于存放开发者上传的价格二维码信息。
- 打开web页面「微服务」/「数据库」,新建名为“price”的数据库。
- 选择“模式” / “列源码”按钮,将如下列源码粘贴进去并确认修改。
-
[{
-
"type":
"tinyint",
-
"name":
"payType",
-
"default":
"1",
-
"options": [{
-
"name":
"not null",
-
"value":
false,
-
"description":
"不为空"
-
}, {
-
"name":
"unique",
-
"value":
false,
-
"description":
"不重复"
-
}, {
-
"name":
"unsigned",
-
"value":
false,
-
"description":
"无符号"
-
}]
-
}, {
-
"type":
"varchar(45)",
-
"name":
"deviceId",
-
"default":
"''",
-
"options": [{
-
"name":
"not null",
-
"value":
true,
-
"description":
"不为空"
-
}, {
-
"name":
"unique",
-
"value":
false,
-
"description":
"不重复"
-
}]
-
}, {
-
"type":
"varchar(128)",
-
"name":
"qrCode",
-
"default":
"''",
-
"options": [{
-
"name":
"not null",
-
"value":
false,
-
"description":
"不为空"
-
}, {
-
"name":
"unique",
-
"value":
false,
-
"description":
"不重复"
-
}]
-
}, {
-
"type":
"int",
-
"name":
"price",
-
"default":
"0",
-
"options": [{
-
"name":
"not null",
-
"value":
false,
-
"description":
"不为空"
-
}, {
-
"name":
"unique",
-
"value":
false,
-
"description":
"不重复"
-
}, {
-
"name":
"unsigned",
-
"value":
false,
-
"description":
"无符号"
-
}]
-
}, {
-
"type":
"varchar(45)",
-
"name":
"userId",
-
"default":
"''",
-
"options": [{
-
"name":
"not null",
-
"value":
true,
-
"description":
"不为空"
-
}, {
-
"name":
"unique",
-
"value":
false,
-
"description":
"不重复"
-
}]
-
},{
-
"name":
"支付类型",
-
"id":
"payType",
-
"type":
"select",
-
"defaultValue":
"微信:1,支付宝:2",
-
"description":
""
-
}, {
-
"name":
"价格",
-
"id":
"price",
-
"type":
"float",
-
"defaultValue":
"",
-
"description":
""
-
}, {
-
"name":
"设备",
-
"id":
"deviceId",
-
"type":
"select",
-
"defaultValue":
"{\"name\":\"get_device\", \"params\":[], \"isDev\":true}",
-
"description":
""
-
}, {
-
"name":
"二维码图片",
-
"id":
"file",
-
"type":
"file",
-
"defaultValue":
"",
-
"description":
""
-
}]
- 选择“索引”按钮,选择“索引源码”,将如下列源码粘贴进去并确认修改。
-
[
{
-
"indexName"
:
"userId"
,
-
"columnsName"
:
"userId"
-
}
]
创建订单数据库
订单数据库用于存放订单数据。
- 打开web页面「微服务」/「数据库」,新建名为“order”的数据库。
- 选择“模式”按钮,选择“列源码”,将如下列源码粘贴进去并确认修改。
-
[{
-
"type":
"char(45)",
-
"name":
"userId",
-
"default":
"''",
-
"options": [{
-
"name":
"not null",
-
"value":
true,
-
"description":
"不为空"
-
}, {
-
"name":
"unique",
-
"value":
false,
-
"description":
"不重复"
-
}]
-
}, {
-
"type":
"char(45)",
-
"name":
"deviceId",
-
"default":
"''",
-
"options": [{
-
"name":
"not null",
-
"value":
true,
-
"description":
"不为空"
-
}, {
-
"name":
"unique",
-
"value":
false,
-
"description":
"不重复"
-
}]
-
}, {
-
"type":
"char(128)",
-
"name":
"outTradeNo",
-
"default":
"''",
-
"options": [{
-
"name":
"not null",
-
"value":
false,
-
"description":
"不为空"
-
}, {
-
"name":
"unique",
-
"value":
false,
-
"description":
"不重复"
-
}]
-
}, {
-
"type":
"tinyint",
-
"name":
"payType",
-
"default":
"1",
-
"options": [{
-
"name":
"not null",
-
"value":
false,
-
"description":
"不为空"
-
}, {
-
"name":
"unique",
-
"value":
false,
-
"description":
"不重复"
-
}, {
-
"name":
"unsigned",
-
"value":
false,
-
"description":
"无符号"
-
}]
-
}, {
-
"type":
"int",
-
"name":
"price",
-
"default":
"",
-
"options": [{
-
"name":
"not null",
-
"value":
false,
-
"description":
"不为空"
-
}, {
-
"name":
"unique",
-
"value":
false,
-
"description":
"不重复"
-
}, {
-
"name":
"unsigned",
-
"value":
false,
-
"description":
"无符号"
-
}]
-
}, {
-
"type":
"int",
-
"name":
"realPrice",
-
"default":
"",
-
"options": [{
-
"name":
"not null",
-
"value":
false,
-
"description":
"不为空"
-
}, {
-
"name":
"unique",
-
"value":
false,
-
"description":
"不重复"
-
}, {
-
"name":
"unsigned",
-
"value":
false,
-
"description":
"无符号"
-
}]
-
}, {
-
"type":
"char(128)",
-
"name":
"notifyUrl",
-
"default":
"''",
-
"options": [{
-
"name":
"not null",
-
"value":
false,
-
"description":
"不为空"
-
}, {
-
"name":
"unique",
-
"value":
false,
-
"description":
"不重复"
-
}]
-
}, {
-
"type":
"char(128)",
-
"name":
"qrCode",
-
"default":
"''",
-
"options": [{
-
"name":
"not null",
-
"value":
false,
-
"description":
"不为空"
-
}, {
-
"name":
"unique",
-
"value":
false,
-
"description":
"不重复"
-
}]
-
}, {
-
"type":
"tinyint",
-
"name":
"status",
-
"default":
"0",
-
"options": [{
-
"name":
"not null",
-
"value":
false,
-
"description":
"不为空"
-
}, {
-
"name":
"unique",
-
"value":
false,
-
"description":
"不重复"
-
}, {
-
"name":
"unsigned",
-
"value":
false,
-
"description":
"无符号"
-
}]
-
}, {
-
"type":
"timestamp",
-
"name":
"time",
-
"default":
"CURRENT_TIMESTAMP",
-
"options": [{
-
"name":
"not null",
-
"value":
false,
-
"description":
"不为空"
-
}, {
-
"name":
"unique",
-
"value":
false,
-
"description":
"不重复"
-
}]
-
}]
- 选择“索引”按钮,选择“索引源码”,将如下列源码粘贴进去并确认修改。
-
[
{
-
"indexName"
:
"userId"
,
-
"columnsName"
:
"userId"
-
}
,
{
-
"indexName"
:
"deviceId"
,
-
"columnsName"
:
"deviceId"
-
}
]
创建二维码录入服务
用于开发者录入价格二维码。
- 打开web页面「微服务」/「数据录入服务」,新建名为“上传价格”的服务,选择”add_price”脚本。
- 选择“参数”按钮,选择“参数源码”,将如下参数源码粘贴进去并确认修改。
-
[{
-
"name":
"支付类型",
-
"id":
"payType",
-
"type":
"select",
-
"defaultValue":
"微信:1,支付宝:2",
-
"description":
""
-
}, {
-
"name":
"价格",
-
"id":
"price",
-
"type":
"float",
-
"defaultValue":
"",
-
"description":
""
-
}, {
-
"name":
"设备",
-
"id":
"deviceId",
-
"type":
"select",
-
"defaultValue":
"{\"scriptName\":\"common\",\"functionName\":\"getDevice\"}",
-
"description":
""
-
}, {
-
"name":
"二维码图片",
-
"id":
"file",
-
"type":
"file",
-
"defaultValue":
"",
-
"description":
""
-
}]
创建价格查询服务
用于开发者查询已经录入的价格二维码信息。
- 打开web页面「微服务」/「数据查询服务」,新建名为“查询价格”的服务,选择”query_price”脚本。
- 选择“查询参数”按钮,选择“参数源码”,将如下参数源码粘贴进去并确认修改。
-
[
{
-
"name"
:
"支付类型"
,
-
"id"
:
"query_type"
,
-
"type"
:
"select"
,
-
"defaultValue"
:
"微信:1,支付宝:2"
,
-
"description"
:
""
-
}
]
- 选择“列”按钮,选择“列源码”,将如下列源码粘贴进去并确认修改。
-
[
{
-
"name"
:
"支付类型"
,
-
"id"
:
"payType"
-
}
,
{
-
"name"
:
"价格"
,
-
"id"
:
"price"
-
}
,
{
-
"name"
:
"设备ID"
,
-
"id"
:
"deviceId"
-
}
,
{
-
"name"
:
"二维码"
,
-
"id"
:
"qrCode"
-
}
]
- 选择“数据操作”按钮,选择“操作源码”,将如下操作源码粘贴进去并确认修改。
-
[
{
-
"name"
:
"删除"
,
-
"id"
:
"delete"
,
-
"scriptId"
:
"5"
,
-
"scriptName"
:
"common"
,
-
"functionName"
:
"deletePrice"
-
}
]
创建订单查询服务
用于开发者查询历史订单信息。
- 打开web页面「微服务」/「数据查询服务」,新建名为“查询订单”的服务,选择”query_order”脚本。
- 选择“查询参数”按钮,选择“参数源码”,将如下参数源码粘贴进去并确认修改。
-
[{
-
"name":
"设备",
-
"id":
"deviceId",
-
"type":
"select",
-
"defaultValue":
"{\"scriptName\":\"common\",\"functionName\":\"getDevice\", \"params\":[true]}\t",
-
"description":
""
-
}]
- 选择“列”按钮,选择“列源码”,将如下列源码粘贴进去并确认修改。
-
[
{
-
"name"
:
"设备"
,
-
"id"
:
"deviceId"
-
}
,
{
-
"name"
:
"交易NO"
,
-
"id"
:
"outTradeNo"
-
}
,
{
-
"name"
:
"支付类型"
,
-
"id"
:
"payType"
-
}
,
{
-
"name"
:
"价格"
,
-
"id"
:
"price"
-
}
,
{
-
"name"
:
"支付价格"
,
-
"id"
:
"realPrice"
-
}
,
{
-
"name"
:
"状态"
,
-
"id"
:
"status"
-
}
,
{
-
"name"
:
"时间"
,
-
"id"
:
"time"
-
}
]
- 选择“数据操作”按钮,选择“操作源码”,将如下操作源码粘贴进去并确认修改。
-
[
{
-
"name"
:
"删除"
,
-
"id"
:
"delete"
,
-
"scriptId"
:
"5"
,
-
"scriptName"
:
"common"
,
-
"functionName"
:
"deleteOrder"
-
}
]
启动手机端程序
打开手机端「冰狐智能辅助」APP,点击“点击这里启动设备”启动设备。
上传微信支付二维码
- 打开web页面「微服务」/「数据录入服务」,找到“上传价格”服务,然后点击“执行”,在弹出的对话框中填入数据、上传微信的支付二维码图片,最后点击“执行”。
- 打开web页面「微服务」/「数据查询服务」,找到“查询价格”服务,然后点击“查询“按钮查询已经上传的价格二维码。
支付测试
- 用postman模拟第三方后端服务调用接口,生成订单。
https://aznfz.com/api/call_micro_service?clientKey=xxxxx&accessToken=yyyyy&name=unified_order&isDev=true¶ms=zzz,详细请参考文档:冰狐智能辅助 - 调用后就生成了对应的支付订单,可在「微服务」/「数据查询服务」,“订单查询”服务中,点击“查询”按钮查询订单。
- 用其他微信向收款微信支付一笔费用,完成后,再次查询订单,看看是否完成。
总结
本文介绍了一种基于「冰狐智能辅助」系统实现的、不需了解Andriod、不需了解后端开发、甚至不需要编写一行代码、免费的、个人免签支付方案和具体实现细节。有任何问题,欢迎评论留言,大家一起讨论😊!