forked from thundernet8/AlipayOrdersSupervisor
-
Notifications
You must be signed in to change notification settings - Fork 0
/
alipay.js
233 lines (203 loc) · 8.79 KB
/
alipay.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
// # Alipay-Supervisor
process.env.UV_THREADPOOL_SIZE=64; //https://www.fedepot.com/cong-node-request-esockettimedoutcuo-wu-shuo-kai-lai/
var config = require('./config');
var logger = require('./logger');
var Email = require('./email');
var email = new Email(config.smtpHost, config.smtpPort, config.smtpUsername, config.smtpPassword);
var Push = require('./push');
var push = new Push(config.pushStateAPI, config.pushAppId, config.pushAppKey, config.pushStateSecret);
var request = require('request').defaults({headers: {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36'}});
//var FileCookieStore = require('tough-cookie-filestore');
var j = request.jar();
request = request.defaults({ jar : j }); // 开启cookies支持
var crypto = require('crypto');
var cheerio = require('cheerio');
var iconv = require('iconv-lite');
var BufferHelper = require('bufferhelper');
var fs = require('fs');
var _ = require('lodash');
// 即时Cookie
var cookies = config.alipayCookies;
// 已推送成功的订单列表
function restoreOrderList(){
var date = new Date;
var filename = 'Orders_' + date.getFullYear().toString() + '_' + (date.getMonth() + 101).toString().substr(1) + '_' + (date.getDate() + 100).toString().substr(1) + '.json';
// 先add空值确保文件存在
fs.writeFileSync('./orders/' + filename, '', {flag: 'a'});
var ordersString = fs.readFileSync('./orders/' + filename);
try {
return JSON.parse(ordersString);
} catch (error) {
return {};
}
}
function backupOrderList(){
var ordersString = JSON.stringify(orderList);
var date = new Date;
var filename = 'Orders_' + date.getFullYear().toString() + '_' + (date.getMonth() + 101).toString().substr(1) + '_' + (date.getDate() + 100).toString().substr(1) + '.json';
fs.writeFileSync('./orders/' + filename, ordersString);
}
var orderList = restoreOrderList();
// Util - 打印log添加时间前缀
function timePrefixLog(text) {
if(!config.debug) {
return;
}
var date = new Date;
var prefix = date.toLocaleString();
console.log(prefix + ' - ' + text.toString());
}
// Util - 恢复被转义的unicode字符 (\\uXXXX)
function decodeUnic(s) {
return unescape(s.replace(/\\(u[0-9a-fA-F]{4})/gm, '%$1'));
}
// 请求订单页面并获取页面HTML字符串
function checkOrderListPageHtmlString() {
timePrefixLog('Start fetch orders');
var r = request.defaults({headers: {'Cookie': cookies}});
// 先请求个人主页
r.get('https://my.alipay.com/portal/i.htm', {timeout: 1500}, function(err, response) {
// error
if (err) {
timePrefixLog(err.code);
// Email报告
if(config.enableExNotify){
email.sendMail('Alipay Supervisor Service Notice', '<b>An web request error happened in your alipay supervisor</b><br>' + err.message, config.email);
}
}
// ok
if (!err && response.statusCode == 200) {
// 再请求订单页面
var r2 = r.get('https://consumeprod.alipay.com/record/advanced.htm?fundFlow=in&_input_charset=utf-8', {timeout: 1500});
// error
r2.on('error', function(error){
timePrefixLog(error.code);
// Email报告
if(config.enableExNotify){
email.sendMail('Alipay Supervisor Service Notice', '<b>An web request error happened in your alipay supervisor</b><br>' + error.message, config.email);
}
});
// ok
r2.on('response', function(res) {
var bufferHelper = new BufferHelper();
r2.on('data', function (chunk) {
bufferHelper.concat(chunk);
});
r2.on('end',function(){
var result = iconv.decode(bufferHelper.toBuffer(),'GBK');
result = result.replace('charset="GBK"', 'charset="utf-8"');
timePrefixLog('Fetch orders page content successfully');
fs.writeFile('orders.html', result);
parseOrdersHtml(result);
});
});
}
});
}
// 解析订单页面HTML
function parseOrdersHtml(html) {
timePrefixLog('Star parse page content');
var $ = cheerio.load(html);
// 检查是否含有列表form以判断是否订单列表页(例如cookies无效时是返回登录页的内容)
var form = $('#J-submit-form');
if(form.length<1){
timePrefixLog('Response html is not valid');
// Email报告
email.sendMail('Alipay Supervisor Service Notice', '<b>An error happened in your alipay supervisor</b><br>Maybe the cookies has expired, please update it and restart the supervisor', config.email);
return false;
}
var orderTable = $('#tradeRecordsIndex>tbody');
var orderRows = orderTable.find('tr');
orderRows.each(function(index, ele){
var orderData = {};
var orderRow = $(this);
// 订单时间
var timeSel = orderRow.children('td.time').children('p');
orderData.time = _.trim(timeSel.first().text()) + ' ' + _.trim(timeSel.last().text());
// 备注
orderData.memo = _.trim(orderRow.find('.memo-info').text());
// 订单描述
orderData.description = _.trim(orderRow.children('td.name').children('p').text());
// 订单商户流水号(商户独立系统)与订单交易号(支付宝系统)
var orderNoData = orderRow.children('td.tradeNo').children('p').text().split('|');
if(orderNoData.length > 1){
orderData.orderId = _.trim(orderNoData[0].split(':')[1]);
orderData.tradeNo = _.trim(orderNoData[1].split(':')[1]);
}else{
orderData.tradeNo = _.trim(orderNoData[0].split(':')[1]);
}
// 对方支付宝用户名
orderData.username = _.trim(decodeUnic(orderRow.children('td.other').children('p').text()));
// 金额
var amountText = orderRow.children('td.amount').children('span').text().replace(' ', ''); // + 100.00 / - 100.00 / 100.00
orderData.amount = parseFloat(amountText);
// 订单状态
orderData.status = orderRow.children('td.status').children('p').text();
// 推送通知
if(orderData.amount > 0){
pushStateToServer(orderData); // 仅对收入做处理
}
});
timePrefixLog('Parse content completed');
//fs.writeFile('orders.json', JSON.stringify(orderList));
}
// 通知服务器
function pushStateToServer(orderData){
if(orderList[orderData['tradeNo']]){
timePrefixLog('Order has been handled successfully, ignore this time');
return;
}
var callback = function(resp){
if(typeof resp == 'object' && resp.isError){
// Email报告
if(config.enableExNotify){
email.sendMail('Alipay Supervisor Service Notice', '<b>An error happened in your alipay supervisor</b><br>Push state to remote server with error returned, please check your server configuration.<br>The error info is: ' + resp.code + ', ' + resp.message, config.email);
}
}
if(resp == 'success'){
orderList[orderData['tradeNo']] = orderData;
backupOrderList(); //将orderList保存到文件
// Email报告
email.sendMail('[Success]Alipay Supervisor Service Notice', '<b>A order is handled successfully in your alipay supervisor</b><br>The order info is: <pre>' + JSON.stringify(orderData) + '</pre>', config.email);
}
};
timePrefixLog('Start push order status to server');
push.pushState(orderData, callback);
}
// 每日通过邮件报告
function dailyReport(){
// Email报告
var date = new Date;
email.sendMail('Alipay Supervisor Service Daily Report(' + date.toLocaleString() + ')', '<b>Currently handled orders:</b><br><pre>' + JSON.stringify(orderList) + '</pre>', config.email);
}
// Test - 使用本地文件解析测试
// fs.readFile('orders.html','utf-8', function(err,data){
// if(err){
// console.log(err);
// }else{
// parseOrdersHtml(data);
// }
// });
// Test - logger
//logger('test content');
// Test - mailer
//email.sendMail('event notice', '<b>an event happened in your alipay supervisor</b>', config.email);
// Test - push
// var testOrderData = {
// time: "2016.11.29 21:51",
// memo: "转账",
// description: "转账",
// tradeNo: "20161129XXXXXXXXXXXXXXXXX2354351",
// username: "XXXXX",
// amount: 150,
// status: "交易成功"
// };
// var callback = function(body){
// console.log(body);
// };
// push.pushState(testOrderData, callback);
var Supervisor = {
startUp: checkOrderListPageHtmlString,
dailyReport: dailyReport
};
module.exports = Supervisor;