This repository has been archived by the owner on Jul 29, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
/
index.js
151 lines (140 loc) · 5.26 KB
/
index.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
const Telegram = require('./telegram');
const israeliBankScrapers = require('israeli-bank-scrapers');
const JsonDB = require('node-json-db');
const yargs = require('yargs');
const keytar = require('keytar');
const config = require('../config');
const Utils = require('./utils');
const consts = require('./consts');
const setup = require('./setup');
class IsraelFinanceTelegramBot {
constructor() {
this.handledTransactionsDb = new JsonDB('handledTransactions', true, false);
this.transactionsToGoThroughDb = new JsonDB('transactionsToGoThrough', true, true);
this.telegram = new Telegram(this.transactionsToGoThroughDb);
setInterval(this.run.bind(this), config.SCRAPE_SECONDS_INTERVAL * 1000);
}
static getMessageFromTransaction(transaction, cardNumber, serviceNiceName) {
let transactionName = 'זיכוי';
let amount = transaction.chargedAmount;
if (amount < 0) {
transactionName = 'חיוב';
amount *= -1;
}
const dateStr = new Date(transaction.date).toLocaleDateString('he-IL');
let currency = transaction.originalCurrency;
switch (currency) {
case 'ILS':
currency = '₪';
break;
case 'USD':
currency = '$';
break;
default:
break;
}
let status = `בסטטוס ${transaction.status} `;
if (transaction.status === 'completed') {
status = '';
}
let type = `(מסוג ${transaction.type}) `;
if (transaction.type === 'normal') {
type = '';
}
return `${serviceNiceName}: ${transactionName} - ${transaction.description} על סך ${amount}${currency} בתאריך ${dateStr} ${status}${type}בחשבון ${cardNumber}`;
}
messageSent(handledTransactionsDbPath, telegramMessageId) {
this.handledTransactionsDb.push(
handledTransactionsDbPath,
{ sent: true, telegramMessageId },
false,
);
}
handleAccount(service, account) {
account.txns.sort(Utils.transactionCompare);
account.txns.forEach((transaction) => {
// Read https://github.com/GuyLewin/israel-finance-telegram-bot/issues/1 - transaction.identifier isn't unique
// This is as unique as we can get
const identifier = `${transaction.date}-${transaction.chargedAmount}-${transaction.identifier}`;
const handledTransactionsDbPath = `/${service.companyId}/${identifier}`;
if (this.handledTransactionsDb.exists(handledTransactionsDbPath)) {
const telegramMessageId = this.handledTransactionsDb.getData(`${handledTransactionsDbPath}/telegramMessageId`);
if (!(this.transactionsToGoThroughDb.exists(`/${telegramMessageId}`))) {
this.telegram.registerReplyListener(telegramMessageId, transaction);
}
this.existingTransactionsFound += 1;
if (config.VERBOSE) {
console.log(`Found existing transaction: ${handledTransactionsDbPath}`);
}
return;
}
this.newTransactionsFound += 1;
if (config.VERBOSE) {
console.log(`Found new transaction: ${handledTransactionsDbPath}`);
}
const message = IsraelFinanceTelegramBot.getMessageFromTransaction(
transaction,
account.accountNumber,
service.niceName,
);
this.telegram.sendMessage(
message,
this.messageSent.bind(this, handledTransactionsDbPath),
transaction,
);
});
}
startRunStatistics() {
const curDate = (new Date()).toLocaleString();
console.log(`Starting periodic run on ${curDate}`);
this.existingTransactionsFound = 0;
this.newTransactionsFound = 0;
}
endRunStatistics() {
const curDate = (new Date()).toLocaleString();
console.log(`Periodic run ended on ${curDate}. ${this.existingTransactionsFound} existing transactions found, ${this.newTransactionsFound} new transactions found`);
}
async getCredentialsForService(service) {
if (service.credentials) {
// Allow defining credentials within config (without keytar)
return service.credentials;
}
return keytar.getPassword(
consts.KEYTAR_SERVICE_NAME,
service.credentialsIdentifier,
).then((keytarPassword) => {
return JSON.parse(keytarPassword);
});
}
async run() {
try {
this.startRunStatistics();
await Promise.all(config.SERVICES.map(async (service) => {
const credentials = await this.getCredentialsForService(service);
if (credentials === null) {
console.error(`"npm run setup" must be ran before running bot (failed on service ${service.niceName}`);
process.exit();
}
const options = Object.assign({ companyId: service.companyId }, config.ADDITIONAL_OPTIONS);
const scraper = israeliBankScrapers.createScraper(options);
const scrapeResult = await scraper.scrape(credentials);
if (scrapeResult.success) {
scrapeResult.accounts.forEach(this.handleAccount.bind(this, service));
} else {
console.error(`scraping failed for the following reason: ${scrapeResult.errorType}`);
}
}));
} catch (e) {
console.log('Got an error. Will try running again next interval. Error details:');
console.error(e, e.stack);
} finally {
this.endRunStatistics();
}
}
}
if (yargs.argv.setup) {
setup();
} else {
const iftb = new IsraelFinanceTelegramBot();
iftb.run();
}