├── README.md
├── package.json
└── pay.js
/README.md:
--------------------------------------------------------------------------------
1 | # Wechaty Pay - 让线上没有难做的生意
2 |
3 | ## TLDR
4 | 本文主要面对没有营业执照,想使用微信或支付宝在线收款的中小企业或者个人开发者,日收入在5K以下(菠菜类或者想偷税者请绕道)。
5 |
6 | 自从使用了Wechaty,资金及时到账,收款后立即通知。即开即用,高并发,超稳定不掉单。
7 |
8 |
9 |
10 |
11 |
12 | ## 背景
13 | 随处可见微信和支付宝的支付二维码,已经让超市水果店和煎饼果子摊贩没有难做的生意。然而在线支付可就没那么容易了。接口大部分需要企业资质认证,或者需要备案域名以及开通权限,对于中小型商户门槛非常高。大部分人会在收到款后,手动确认订单,经常出现订单延误或者遗漏。然而市面上的解决方案都差强人意。那么这个线上支付的流程如何利用Wechaty优化一下呢?
14 |
15 | 
16 |
17 | ## 技术实现
18 |
19 | 整个收款过程分为3步:
20 | 1. 用户选择支付金额后,付款页面打开对应的付款码(支付宝可自定义金额),用户扫码付款
21 | 2. 确认收款后(```onMessage```),跟后端发送回调收款金额及收款时间(```sendPayment```)
22 | 3. 后台根据金额以及时间,把对应的订单自动标记
23 |
24 | 下面的例子以第2步为例,如何在后台确认收款,以及跟后端发送回调。
25 |
26 | ```
27 | // Wechaty 经典启动
28 | const bot = new Wechaty()
29 | bot.on('scan', onScan)
30 | bot.on('login', onLogin)
31 | bot.on('message', onMessage)
32 | bot.start()
33 |
34 | // 微信收款的消息提示
35 | async function onMessage (msg) {
36 | if ( msg.type() !== bot.Message.Type.Attachment && !msg.self()
37 | || contact.name() !== '微信支付') {
38 | return
39 | }
40 | const strs = msg.text().split('元')
41 | if (strs.length >= 1) {
42 | const prices = strs[0].split('微信支付收款')
43 | if (prices.length >= 1) {
44 | const priceStr = prices[1]
45 | sendPayment(parseFloat(priceStr), msg.date().getTime())
46 | }
47 | }
48 | }
49 |
50 | // 收到金额之后,进行确认订单回调
51 | function sendPayment (priceAmount, timestamp) {
52 | const options = {
53 | method: 'POST',
54 | url: 'https://api.callbackaddress.com/api/admin/callback',
55 | headers: { 'content-type': 'application/json', 'token': 'XXXXXX'},
56 | body: {'amount': priceAmount, 'timestamp': timestamp },
57 | json: true
58 | };
59 | request(options, function (error, response, body) {
60 | if (error) throw new Error(error);
61 | });
62 | }
63 | ```
64 |
65 | 支付宝道理类似,不过目前产品包装没有Wechaty这么优秀的代码库。半自动操作如下:
66 | 1. 扫码登录支付宝账号,在Headers中获取Cookie。操作类似于``` bot.on('scan', onScan) ```
67 | 2. 轮询获取订单列表,如果有新支付订单,,跟后端发送回调收款金额及收款时间(```sendPayment```)
68 | 3. 由于此处使用了轮询的方式,为了防止频繁访问被支付宝风控,仅当有待支付订单才会高频访问订单接口。
69 |
70 |
71 | ## 效果预览
72 |
73 | 终于可以一站式的管理所有微信和支付宝的订单了!每笔订单的时间,金额,还有每天收入统计一览无余。
74 |
75 | 
76 |
77 | ## 产品实现
78 |
79 | 如果还是觉得步骤有点繁琐?那可以试一下这款基于[桔子互动](https://www.botorange.com/)的云端服务哦。
80 |
81 | * 支持微信扫码托管(基于桔子互动服务)
82 | * 支持支付宝扫码托管
83 | * 保障安全性,不记录个人账户密码
84 | * 资金实时到账,不经过第三方
85 |
86 |
87 |
88 |
89 | 本文仅供技术产品交流参考,建议使用官方认证接口。请勿使用此项目做违反微信、支付宝规定或者其他违法事情!
90 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "wechatpay",
3 | "version": "0.1.0",
4 | "description": "Personal Payment Solution",
5 | "main": "pay.js",
6 | "engines": {
7 | "node": ">= 10"
8 | },
9 | "scripts": {
10 | "postinstall": "check-node-version --node \">= 10\"",
11 | "start": "node pay.js"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "git+https://github.com/coderwhocode/wechaty-pay.git"
16 | },
17 | "keywords": [],
18 | "author": "Huan LI ",
19 | "license": "ISC",
20 | "bugs": {
21 | "url": "https://github.com/coderwhocode/wechaty-pay/issues"
22 | },
23 | "homepage": "https://github.com/coderwhocode/wechaty-pay#readme",
24 | "dependencies": {
25 | "qrcode-terminal": "^0.12.0",
26 | "request": "^2.88.0",
27 | "wechaty": "^0.22.6"
28 | },
29 | "devDependencies": {
30 | "check-node-version": "^3.2.0"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/pay.js:
--------------------------------------------------------------------------------
1 | const { Wechaty } = require('wechaty')
2 | const request = require("request")
3 |
4 | function onScan (qrcode, status) {
5 | require('qrcode-terminal').generate(qrcode, { small: true }) // show qrcode on console
6 |
7 | const qrcodeImageUrl = [
8 | 'https://api.qrserver.com/v1/create-qr-code/?data=',
9 | encodeURIComponent(qrcode),
10 | ].join('')
11 |
12 | console.log(qrcodeImageUrl)
13 | }
14 |
15 | function onLogin (user) {
16 | console.log(`${user} login`)
17 | }
18 |
19 | function onLogout(user) {
20 | console.log(`${user} logout`)
21 | }
22 |
23 | // sendPayment(0.01, 1562577831000)
24 | function sendPayment (priceAmount, timestamp) {
25 | console.log(priceAmount, timestamp);
26 |
27 | // const options = {
28 | // method: 'POST',
29 | // url: 'https://api.callbackurl.com/callback',
30 | // headers:
31 | // {
32 | // 'content-type': 'application/json',
33 | // token: 'usertoken-callback' },
34 | // body: {
35 | // price_amount: priceAmount,
36 | // timestamp: timestamp
37 | // },
38 | // json: true
39 | // };
40 |
41 | // request(options, function (error, response, body) {
42 | // if (error) throw new Error(error);
43 | // });
44 | }
45 |
46 | // 消息来自 “微信支付”,信息格式为“微信支付收款0.01元”
47 | async function onMessage (msg) {
48 | if (msg.age() > 300) {
49 | // console.log('Message discarded because its TOO OLD(than 5 minute)')
50 | return
51 | }
52 |
53 | const contact = msg.from()
54 | const text = msg.text()
55 | const msgDate = msg.date()
56 |
57 | if ( msg.type() !== bot.Message.Type.Attachment
58 | && !msg.self()
59 | ) {
60 | // console.log('Message discarded because it does not match Payment Attachment')
61 | return
62 | }
63 |
64 | if ( contact.name() !== '微信支付'
65 | ) {
66 | // console.log('Message is not from wechat pay - from ', contact.name())
67 | return
68 | }
69 |
70 | const strs = text.split('元')
71 | if (strs.length >= 1) {
72 | const str= strs[0]
73 | const strs2 = str.split('微信支付收款')
74 | if (strs2.length >= 1) {
75 | const priceStr = strs2[1]
76 | sendPayment(parseFloat(priceStr), msgDate.getTime())
77 | }
78 | }
79 | }
80 |
81 | const bot = new Wechaty()
82 |
83 | bot.on('scan', onScan)
84 | bot.on('login', onLogin)
85 | bot.on('logout', onLogout)
86 | bot.on('message', onMessage)
87 |
88 | bot.start()
89 | .then(() => console.log('Starter Bot Started.'))
90 | .catch(e => console.error(e))
91 |
--------------------------------------------------------------------------------