-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwechat.js
executable file
·129 lines (116 loc) · 3.73 KB
/
wechat.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
import * as fsp from "fs/promises";
import * as fs from "fs";
import { parse } from 'csv-parse/sync';
import { stringify } from 'csv-stringify/sync';
import * as readline from 'node:readline'
const ACCOUNT_MAP = JSON.parse(await fsp.readFile("account_map.json"));
function main() {
// request input file path
const query = readline.createInterface({
input: process.stdin,
output: process.stdout
});
query.question('\n***微信账单转换***\n\n\n请输入原csv文件路径:\n\n', (answer) => {
const reg = /\\/g;
mainProcess(answer.trim().replace(reg, ''));
query.close();
})
}
async function mainProcess(source) {
// read line by line
const fileStream = fs.createReadStream(source);
const rl = readline.createInterface({
input: fileStream,
});
// remove unused line of csv
let numberOfDash = 0;
let realContent = '';
for await (let input of rl) {
if (input.startsWith('--')) {
numberOfDash++;
continue;
}
if (numberOfDash > 0) {
realContent += input + '\n';
}
}
// parse the csv content to object
const records = parse(realContent, {
delimiter: ',',
columns: true,
trim: true,
});
// process all records
const transactions = [];
records.forEach(record => {
let transaction = {};
transaction['日期'] = parseDate(record['交易时间']);
transaction['描述'] = record['商品'] == "/" ? record['交易类型'] : record['商品'];
transaction['账户'] = mapAccount(record['支付方式']);
const fee = isNaN(record['金额(元)']) ? record['金额(元)'].substring(1, record['金额(元)'].length) : record['金额(元)'];
if (record['收/支'] == '其他') {
// keep alipay's transfer process, because no wechat transfer record found yet
transaction['交易对方'] = '';
transaction['分类'] = '';
transaction['转账'] = mapAccount(record['交易对方']);
if (record['商品说明'].includes("还款")) {
transaction['金额'] = (-Math.abs(fee)).toString();
} else {
transaction['金额'] = fee;
}
} else {
transaction['交易对方'] = record['交易对方'];
transaction['分类'] = record['交易类型'];
transaction['转账'] = '';
if (record['收/支'] == '支出') {
transaction['金额'] = (-Math.abs(fee)).toString();
} else if (record['收/支'] == '收入') {
transaction['金额'] = fee;
}
}
transaction['标签'] = '';
transaction['备注'] = '';
transactions.push(transaction);
});
// output to file
const output = stringify(transactions, {
header: true,
columns: ['账户', '转账', '描述', '交易对方', '分类', '日期', '备注', '标签', '金额']
})
const sourceDir = source.slice(0, source.lastIndexOf('/') + 1);
await fsp.writeFile(`${sourceDir + getOutputName()}`, output);
console.log(`\n解析完成,输出路径: ${sourceDir + getOutputName()}`);
}
function parseDate(dateStr) {
const dateObj = new Date(dateStr);
return dateObj.toLocaleString();
// const time = dateObj.toLocaleTimeString('zh-CN', {
// hourCycle: "h24",
// });
// transaction['日期'] = date;
// transaction['时间'] = time;
}
function mapAccount(recordStr) {
if (recordStr == "" || recordStr == "/") {
return "微信零钱";
}
for (const k in ACCOUNT_MAP) {
if (recordStr.includes(k)) {
return ACCOUNT_MAP[k];
}
}
return recordStr;
}
function getOutputName() {
const now = new Date();
const date = now.getFullYear() + '_' + (now.getMonth() + 1).toString() + '_' + now.getDate();
return `【生成】微信账单_${date}.csv`;
}
// main().then(
// () => process.exit(),
// (err) => {
// console.error(err);
// process.exit(-1);
// }
// );
main();