@ashray.mehta/statement-converter 1.4.4-alpha.2 → 1.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/StatementConverter.d.ts +7 -0
- package/StatementConverter.js +45 -0
- package/adapters/ABNAdapter.d.ts +7 -0
- package/adapters/ABNAdapter.js +55 -0
- package/adapters/AxisAdapter.d.ts +7 -0
- package/adapters/AxisAdapter.js +53 -0
- package/adapters/ICICIAdapter.d.ts +8 -0
- package/adapters/ICICIAdapter.js +56 -0
- package/adapters/ICICICreditCardAdapter.d.ts +8 -0
- package/adapters/ICICICreditCardAdapter.js +56 -0
- package/adapters/MT940Adapter.d.ts +7 -0
- package/adapters/MT940Adapter.js +56 -0
- package/adapters/N26Adapter.d.ts +7 -0
- package/adapters/N26Adapter.js +56 -0
- package/adapters/StandardCharteredAdapter.d.ts +7 -0
- package/adapters/StandardCharteredAdapter.js +52 -0
- package/adapters/TransactionAdapter.d.ts +6 -0
- package/adapters/TransactionAdapter.js +6 -0
- package/adapters/TransactionsQifConverter.d.ts +5 -0
- package/adapters/TransactionsQifConverter.js +31 -0
- package/helpers/NumberUtil.d.ts +4 -0
- package/helpers/NumberUtil.js +28 -0
- package/helpers/XLSXUtil.d.ts +6 -0
- package/helpers/XLSXUtil.js +41 -0
- package/{src/index.ts → index.d.ts} +1 -1
- package/index.js +18 -0
- package/models/Bank.d.ts +9 -0
- package/models/Bank.js +13 -0
- package/{src/models/Transaction.ts → models/Transaction.d.ts} +1 -1
- package/models/Transaction.js +2 -0
- package/package.json +7 -7
- package/.github/dependabot.yml +0 -7
- package/.github/workflows/node.js.yml +0 -24
- package/.github/workflows/npm-publish.yml +0 -35
- package/.mocharc.json +0 -5
- package/README.md +0 -1
- package/src/StatementConverter.ts +0 -32
- package/src/adapters/ABNAdapter.ts +0 -45
- package/src/adapters/AxisAdapter.ts +0 -42
- package/src/adapters/ICICIAdapter.ts +0 -50
- package/src/adapters/ICICICreditCardAdapter.ts +0 -50
- package/src/adapters/MT940Adapter.ts +0 -49
- package/src/adapters/N26Adapter.ts +0 -45
- package/src/adapters/StandardCharteredAdapter.ts +0 -46
- package/src/adapters/TransactionAdapter.ts +0 -8
- package/src/adapters/TransactionsQifConverter.ts +0 -28
- package/src/helpers/NumberUtil.ts +0 -27
- package/src/helpers/XLSXUtil.ts +0 -38
- package/src/models/Bank.ts +0 -9
- package/test/AxisBankStatement.xls +0 -0
- package/test/ICICIBankStatement.xls +0 -0
- package/test/N26Statement.csv +0 -29
- package/test/NumberUtil.spec.js +0 -32
- package/test/StatementConverter.spec.js +0 -34
- package/tsconfig.json +0 -17
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.StatementConverter = void 0;
|
|
13
|
+
const N26Adapter_1 = require("./adapters/N26Adapter");
|
|
14
|
+
const ABNAdapter_1 = require("./adapters/ABNAdapter");
|
|
15
|
+
const AxisAdapter_1 = require("./adapters/AxisAdapter");
|
|
16
|
+
const ICICIAdapter_1 = require("./adapters/ICICIAdapter");
|
|
17
|
+
const ICICICreditCardAdapter_1 = require("./adapters/ICICICreditCardAdapter");
|
|
18
|
+
const StandardCharteredAdapter_1 = require("./adapters/StandardCharteredAdapter");
|
|
19
|
+
const TransactionsQifConverter_1 = require("./adapters/TransactionsQifConverter");
|
|
20
|
+
const MT940Adapter_1 = require("./adapters/MT940Adapter");
|
|
21
|
+
class StatementConverter {
|
|
22
|
+
constructor() {
|
|
23
|
+
this.transactionsToQif = new TransactionsQifConverter_1.TransactionsQifConverter();
|
|
24
|
+
this.allAdapters = [
|
|
25
|
+
new AxisAdapter_1.AxisAdapter(),
|
|
26
|
+
new ICICIAdapter_1.ICICIAdapter(),
|
|
27
|
+
new ICICICreditCardAdapter_1.ICICICreditCardAdapter(),
|
|
28
|
+
new StandardCharteredAdapter_1.StandardCharteredAdapter(),
|
|
29
|
+
new ABNAdapter_1.ABNAdapter(),
|
|
30
|
+
new N26Adapter_1.N26Adapter(),
|
|
31
|
+
new MT940Adapter_1.MT940Adapter(),
|
|
32
|
+
];
|
|
33
|
+
}
|
|
34
|
+
convert(bank, fileData) {
|
|
35
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
36
|
+
const adapter = this.allAdapters.find((adapter) => adapter.supports(bank));
|
|
37
|
+
if (!adapter) {
|
|
38
|
+
throw new Error(`No adapter found for bank [${bank}]`);
|
|
39
|
+
}
|
|
40
|
+
const transactions = yield adapter.convert(fileData);
|
|
41
|
+
return this.transactionsToQif.convert(transactions);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.StatementConverter = StatementConverter;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Bank } from '..';
|
|
2
|
+
import { Transaction } from '../models/Transaction';
|
|
3
|
+
import { TransactionAdapter } from './TransactionAdapter';
|
|
4
|
+
export declare class ABNAdapter extends TransactionAdapter {
|
|
5
|
+
convert(xlsxData: ArrayBuffer): Promise<Transaction[]>;
|
|
6
|
+
supports(bank: Bank): boolean;
|
|
7
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.ABNAdapter = void 0;
|
|
13
|
+
const __1 = require("..");
|
|
14
|
+
const XLSXUtil_1 = require("../helpers/XLSXUtil");
|
|
15
|
+
const TransactionAdapter_1 = require("./TransactionAdapter");
|
|
16
|
+
const XLSX = require("xlsx");
|
|
17
|
+
const moment = require("moment");
|
|
18
|
+
class ABNAdapter extends TransactionAdapter_1.TransactionAdapter {
|
|
19
|
+
convert(xlsxData) {
|
|
20
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
21
|
+
const workBook = XLSX.read(xlsxData, { raw: true, type: 'array' });
|
|
22
|
+
const sheet = workBook.Sheets[workBook.SheetNames[0]];
|
|
23
|
+
const addressForTransactionDate = XLSXUtil_1.XLSXUtil.findText(sheet, "transactiondate");
|
|
24
|
+
const addressForDescription = XLSXUtil_1.XLSXUtil.findText(sheet, "description");
|
|
25
|
+
const addressForAmount = XLSXUtil_1.XLSXUtil.findText(sheet, "amount");
|
|
26
|
+
const startingRow = addressForTransactionDate.r + 1;
|
|
27
|
+
const range = XLSX.utils.decode_range(sheet['!ref']);
|
|
28
|
+
const rangeEnd = range.e;
|
|
29
|
+
const lastRow = rangeEnd.r;
|
|
30
|
+
const rows = [...Array(1 + lastRow - startingRow).keys()].map(v => startingRow + v);
|
|
31
|
+
return rows.map(row => {
|
|
32
|
+
const parsedDate = moment(XLSXUtil_1.XLSXUtil.getCellValue(sheet, row, addressForTransactionDate.c), 'YYYYMMDD');
|
|
33
|
+
if (!parsedDate.isValid())
|
|
34
|
+
return undefined;
|
|
35
|
+
const date = parsedDate.toDate();
|
|
36
|
+
const amount = XLSXUtil_1.XLSXUtil.getNumberInCell(sheet, row, addressForAmount.c);
|
|
37
|
+
const outflow = amount < 0 ? Math.abs(amount) : 0;
|
|
38
|
+
const inflow = amount >= 0 ? amount : 0;
|
|
39
|
+
const memo = XLSXUtil_1.XLSXUtil.getCellValue(sheet, row, addressForDescription.c);
|
|
40
|
+
return {
|
|
41
|
+
Payee: memo,
|
|
42
|
+
Outflow: outflow,
|
|
43
|
+
Inflow: inflow,
|
|
44
|
+
Date: date,
|
|
45
|
+
Memo: memo,
|
|
46
|
+
Category: null
|
|
47
|
+
};
|
|
48
|
+
}).filter(row => !!row);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
supports(bank) {
|
|
52
|
+
return bank === __1.Bank.ABN;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
exports.ABNAdapter = ABNAdapter;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Bank } from '..';
|
|
2
|
+
import { Transaction } from '../models/Transaction';
|
|
3
|
+
import { TransactionAdapter } from './TransactionAdapter';
|
|
4
|
+
export declare class AxisAdapter extends TransactionAdapter {
|
|
5
|
+
convert(xlsxData: ArrayBuffer): Promise<Transaction[]>;
|
|
6
|
+
supports(bank: Bank): boolean;
|
|
7
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.AxisAdapter = void 0;
|
|
13
|
+
const __1 = require("..");
|
|
14
|
+
const XLSXUtil_1 = require("../helpers/XLSXUtil");
|
|
15
|
+
const TransactionAdapter_1 = require("./TransactionAdapter");
|
|
16
|
+
const XLSX = require("xlsx");
|
|
17
|
+
const moment = require("moment");
|
|
18
|
+
class AxisAdapter extends TransactionAdapter_1.TransactionAdapter {
|
|
19
|
+
convert(xlsxData) {
|
|
20
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
21
|
+
const workBook = XLSX.read(xlsxData, { raw: true, type: 'array' });
|
|
22
|
+
const sheet = workBook.Sheets[workBook.SheetNames[0]];
|
|
23
|
+
const addressForTransactionDate = XLSXUtil_1.XLSXUtil.findText(sheet, "Tran Date");
|
|
24
|
+
const addressForDetails = XLSXUtil_1.XLSXUtil.findText(sheet, "PARTICULARS");
|
|
25
|
+
const addressForDepositAmount = XLSXUtil_1.XLSXUtil.findText(sheet, "CR");
|
|
26
|
+
const addressForWithdrawalAmount = XLSXUtil_1.XLSXUtil.findText(sheet, "DR");
|
|
27
|
+
const startingRow = addressForTransactionDate.r + 1;
|
|
28
|
+
const range = XLSX.utils.decode_range(sheet['!ref']);
|
|
29
|
+
const rangeEnd = range.e;
|
|
30
|
+
const lastRow = rangeEnd.r;
|
|
31
|
+
const rows = [...Array(1 + lastRow - startingRow).keys()].map(v => startingRow + v);
|
|
32
|
+
return rows.map(row => {
|
|
33
|
+
const parsedDate = moment(XLSXUtil_1.XLSXUtil.getCellValue(sheet, row, addressForTransactionDate.c), 'DD-MM-YYYY');
|
|
34
|
+
if (!parsedDate.isValid())
|
|
35
|
+
return undefined;
|
|
36
|
+
const date = parsedDate.toDate();
|
|
37
|
+
const payee = XLSXUtil_1.XLSXUtil.getCellValue(sheet, row, addressForDetails.c);
|
|
38
|
+
return {
|
|
39
|
+
Payee: payee,
|
|
40
|
+
Outflow: XLSXUtil_1.XLSXUtil.getNumberInCell(sheet, row, addressForWithdrawalAmount.c),
|
|
41
|
+
Inflow: XLSXUtil_1.XLSXUtil.getNumberInCell(sheet, row, addressForDepositAmount.c),
|
|
42
|
+
Date: date,
|
|
43
|
+
Memo: payee,
|
|
44
|
+
Category: null
|
|
45
|
+
};
|
|
46
|
+
}).filter(row => !!row);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
supports(bank) {
|
|
50
|
+
return bank === __1.Bank.Axis;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.AxisAdapter = AxisAdapter;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Bank } from '..';
|
|
2
|
+
import { Transaction } from '../models/Transaction';
|
|
3
|
+
import { TransactionAdapter } from './TransactionAdapter';
|
|
4
|
+
export declare class ICICIAdapter extends TransactionAdapter {
|
|
5
|
+
convert(xlsxData: ArrayBuffer): Promise<Transaction[]>;
|
|
6
|
+
private isOutflow;
|
|
7
|
+
supports(bank: Bank): boolean;
|
|
8
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.ICICIAdapter = void 0;
|
|
13
|
+
const XLSX = require("xlsx");
|
|
14
|
+
const __1 = require("..");
|
|
15
|
+
const XLSXUtil_1 = require("../helpers/XLSXUtil");
|
|
16
|
+
const TransactionAdapter_1 = require("./TransactionAdapter");
|
|
17
|
+
const moment = require("moment");
|
|
18
|
+
class ICICIAdapter extends TransactionAdapter_1.TransactionAdapter {
|
|
19
|
+
convert(xlsxData) {
|
|
20
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
21
|
+
const workBook = XLSX.read(xlsxData, { raw: true, type: 'array' });
|
|
22
|
+
const sheet = workBook.Sheets[workBook.SheetNames[0]];
|
|
23
|
+
const addressForTransactionDate = XLSXUtil_1.XLSXUtil.findText(sheet, "Transaction Date");
|
|
24
|
+
const addressForDetails = XLSXUtil_1.XLSXUtil.findText(sheet, "Transaction Remark");
|
|
25
|
+
const addressForAmount = XLSXUtil_1.XLSXUtil.findText(sheet, "Amount (INR)");
|
|
26
|
+
const addressForCreditOrDebit = XLSXUtil_1.XLSXUtil.findText(sheet, "CR/DR");
|
|
27
|
+
const addressForLegend = XLSXUtil_1.XLSXUtil.findText(sheet, "Legends Used in Account Statement");
|
|
28
|
+
const startingRow = addressForTransactionDate.r + 1;
|
|
29
|
+
const lastRow = addressForLegend.r - 1;
|
|
30
|
+
const rows = [...Array(1 + lastRow - startingRow).keys()].map(v => startingRow + v);
|
|
31
|
+
return rows.map(row => {
|
|
32
|
+
const isOutflow = this.isOutflow(sheet, row, addressForCreditOrDebit.c);
|
|
33
|
+
const amount = XLSXUtil_1.XLSXUtil.getNumberInCell(sheet, row, addressForAmount.c);
|
|
34
|
+
const date = moment(XLSXUtil_1.XLSXUtil.getCellValue(sheet, row, addressForTransactionDate.c), 'DD/MM/YYYY').toDate();
|
|
35
|
+
const payee = XLSXUtil_1.XLSXUtil.getCellValue(sheet, row, addressForDetails.c);
|
|
36
|
+
return {
|
|
37
|
+
Payee: payee,
|
|
38
|
+
Outflow: isOutflow ? amount : 0,
|
|
39
|
+
Inflow: !isOutflow ? amount : 0,
|
|
40
|
+
Date: date,
|
|
41
|
+
Memo: payee,
|
|
42
|
+
Category: null
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
isOutflow(sheet, row, column) {
|
|
48
|
+
const cellValue = XLSXUtil_1.XLSXUtil.getCellValue(sheet, row, column);
|
|
49
|
+
return cellValue.includes("Dr.");
|
|
50
|
+
}
|
|
51
|
+
;
|
|
52
|
+
supports(bank) {
|
|
53
|
+
return bank === __1.Bank.ICICI;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.ICICIAdapter = ICICIAdapter;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Bank } from '..';
|
|
2
|
+
import { Transaction } from '../models/Transaction';
|
|
3
|
+
import { TransactionAdapter } from './TransactionAdapter';
|
|
4
|
+
export declare class ICICICreditCardAdapter extends TransactionAdapter {
|
|
5
|
+
convert(xlsxData: ArrayBuffer): Promise<Transaction[]>;
|
|
6
|
+
private determineDebitOrCredit;
|
|
7
|
+
supports(bank: Bank): boolean;
|
|
8
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.ICICICreditCardAdapter = void 0;
|
|
13
|
+
const XLSX = require("xlsx");
|
|
14
|
+
const __1 = require("..");
|
|
15
|
+
const XLSXUtil_1 = require("../helpers/XLSXUtil");
|
|
16
|
+
const TransactionAdapter_1 = require("./TransactionAdapter");
|
|
17
|
+
const moment = require("moment");
|
|
18
|
+
class ICICICreditCardAdapter extends TransactionAdapter_1.TransactionAdapter {
|
|
19
|
+
convert(xlsxData) {
|
|
20
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
21
|
+
const workBook = XLSX.read(xlsxData, { raw: true, type: 'array' });
|
|
22
|
+
const sheet = workBook.Sheets[workBook.SheetNames[0]];
|
|
23
|
+
const addressForTransactionDate = XLSXUtil_1.XLSXUtil.findText(sheet, "Transaction Date");
|
|
24
|
+
const addressForDetails = XLSXUtil_1.XLSXUtil.findText(sheet, "Details");
|
|
25
|
+
const addressForAmount = XLSXUtil_1.XLSXUtil.findText(sheet, "Amount (INR)");
|
|
26
|
+
const addressForReferenceNumber = XLSXUtil_1.XLSXUtil.findText(sheet, "Reference Number");
|
|
27
|
+
const startingRow = addressForTransactionDate.r + 1;
|
|
28
|
+
const range = XLSX.utils.decode_range(sheet['!ref']);
|
|
29
|
+
const rangeEnd = range.e;
|
|
30
|
+
const lastRow = rangeEnd.r;
|
|
31
|
+
const rows = [...Array(1 + lastRow - startingRow).keys()].map(v => startingRow + v);
|
|
32
|
+
return rows.map(row => {
|
|
33
|
+
const { isOutflow, amount } = this.determineDebitOrCredit(sheet, row, addressForAmount.c);
|
|
34
|
+
const date = moment(XLSXUtil_1.XLSXUtil.getCellValue(sheet, row, addressForTransactionDate.c), 'DD/MM/YYYY').toDate();
|
|
35
|
+
return {
|
|
36
|
+
Payee: XLSXUtil_1.XLSXUtil.getCellValue(sheet, row, addressForDetails.c),
|
|
37
|
+
Outflow: isOutflow ? amount : 0,
|
|
38
|
+
Inflow: !isOutflow ? amount : 0,
|
|
39
|
+
Date: date,
|
|
40
|
+
Memo: XLSXUtil_1.XLSXUtil.getCellValue(sheet, row, addressForReferenceNumber.c),
|
|
41
|
+
Category: null
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
determineDebitOrCredit(sheet, row, column) {
|
|
47
|
+
const cellValue = XLSXUtil_1.XLSXUtil.getCellValue(sheet, row, column);
|
|
48
|
+
// TODO - Replace parsing with Globalize
|
|
49
|
+
return { isOutflow: cellValue.includes("Dr."), amount: parseFloat(cellValue.replace(/,/g, '')) };
|
|
50
|
+
}
|
|
51
|
+
;
|
|
52
|
+
supports(bank) {
|
|
53
|
+
return bank === __1.Bank.ICICICreditCard;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.ICICICreditCardAdapter = ICICICreditCardAdapter;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Bank } from '..';
|
|
2
|
+
import { Transaction } from '../models/Transaction';
|
|
3
|
+
import { TransactionAdapter } from './TransactionAdapter';
|
|
4
|
+
export declare class MT940Adapter extends TransactionAdapter {
|
|
5
|
+
convert(data: ArrayBuffer): Promise<Transaction[]>;
|
|
6
|
+
supports(bank: Bank): boolean;
|
|
7
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.MT940Adapter = void 0;
|
|
13
|
+
const __1 = require("..");
|
|
14
|
+
const TransactionAdapter_1 = require("./TransactionAdapter");
|
|
15
|
+
const stitch_swiftmessageparser_1 = require("stitch-swiftmessageparser");
|
|
16
|
+
const lodash_1 = require("lodash");
|
|
17
|
+
const moment = require("moment");
|
|
18
|
+
class MT940Adapter extends TransactionAdapter_1.TransactionAdapter {
|
|
19
|
+
convert(data) {
|
|
20
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
21
|
+
const rows = stitch_swiftmessageparser_1.default.parse({
|
|
22
|
+
data: new TextDecoder().decode(data),
|
|
23
|
+
type: "mt940",
|
|
24
|
+
});
|
|
25
|
+
return (0, lodash_1.flatMap)(rows, row => row.transactions)
|
|
26
|
+
.map((row) => {
|
|
27
|
+
const parsedDate = moment(row.date);
|
|
28
|
+
const date = parsedDate.toDate();
|
|
29
|
+
const amount = row.amount;
|
|
30
|
+
const outflow = amount.isNegative() ? amount.abs().toNumber() : 0;
|
|
31
|
+
const inflow = amount.isPositive() ? amount.toNumber() : 0;
|
|
32
|
+
const memo = (0, lodash_1.filter)([
|
|
33
|
+
row.bankReference,
|
|
34
|
+
row.details,
|
|
35
|
+
row.extraDetails,
|
|
36
|
+
row.reference,
|
|
37
|
+
(0, lodash_1.filter)(row.detailSegments, (0, lodash_1.negate)(lodash_1.isEmpty)).join(" - ")
|
|
38
|
+
], (0, lodash_1.negate)(lodash_1.isEmpty))
|
|
39
|
+
.join(" - ")
|
|
40
|
+
.trim();
|
|
41
|
+
return {
|
|
42
|
+
Payee: memo,
|
|
43
|
+
Outflow: outflow,
|
|
44
|
+
Inflow: inflow,
|
|
45
|
+
Date: date,
|
|
46
|
+
Memo: memo,
|
|
47
|
+
Category: null
|
|
48
|
+
};
|
|
49
|
+
}).filter(row => !!row);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
supports(bank) {
|
|
53
|
+
return bank === __1.Bank.GenericMT940;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.MT940Adapter = MT940Adapter;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Bank } from '..';
|
|
2
|
+
import { Transaction } from '../models/Transaction';
|
|
3
|
+
import { TransactionAdapter } from './TransactionAdapter';
|
|
4
|
+
export declare class N26Adapter extends TransactionAdapter {
|
|
5
|
+
convert(xlsxData: ArrayBuffer): Promise<Transaction[]>;
|
|
6
|
+
supports(bank: Bank): boolean;
|
|
7
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.N26Adapter = void 0;
|
|
13
|
+
const __1 = require("..");
|
|
14
|
+
const XLSXUtil_1 = require("../helpers/XLSXUtil");
|
|
15
|
+
const TransactionAdapter_1 = require("./TransactionAdapter");
|
|
16
|
+
const XLSX = require("xlsx");
|
|
17
|
+
const moment = require("moment");
|
|
18
|
+
class N26Adapter extends TransactionAdapter_1.TransactionAdapter {
|
|
19
|
+
convert(xlsxData) {
|
|
20
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
21
|
+
const workBook = XLSX.read(xlsxData, { raw: true, type: 'array' });
|
|
22
|
+
const sheet = workBook.Sheets[workBook.SheetNames[0]];
|
|
23
|
+
const addressForTransactionDate = XLSXUtil_1.XLSXUtil.findText(sheet, "Date");
|
|
24
|
+
const addressForDescription = XLSXUtil_1.XLSXUtil.findText(sheet, "Payment reference");
|
|
25
|
+
const addressForAmount = XLSXUtil_1.XLSXUtil.findText(sheet, "Amount (EUR)");
|
|
26
|
+
const addressForPayee = XLSXUtil_1.XLSXUtil.findText(sheet, "Payee");
|
|
27
|
+
const addressForCategory = XLSXUtil_1.XLSXUtil.findText(sheet, "Transaction type");
|
|
28
|
+
const startingRow = addressForTransactionDate.r + 1;
|
|
29
|
+
const range = XLSX.utils.decode_range(sheet['!ref']);
|
|
30
|
+
const rangeEnd = range.e;
|
|
31
|
+
const lastRow = rangeEnd.r;
|
|
32
|
+
const rows = [...Array(1 + lastRow - startingRow).keys()].map(v => startingRow + v);
|
|
33
|
+
return rows.map(row => {
|
|
34
|
+
const parsedDate = moment(XLSXUtil_1.XLSXUtil.getCellValue(sheet, row, addressForTransactionDate.c), 'YYYYMMDD');
|
|
35
|
+
if (!parsedDate.isValid())
|
|
36
|
+
return undefined;
|
|
37
|
+
const date = parsedDate.toDate();
|
|
38
|
+
const amount = XLSXUtil_1.XLSXUtil.getNumberInCell(sheet, row, addressForAmount.c);
|
|
39
|
+
const outflow = amount < 0 ? Math.abs(amount) : 0;
|
|
40
|
+
const inflow = amount >= 0 ? amount : 0;
|
|
41
|
+
return {
|
|
42
|
+
Payee: XLSXUtil_1.XLSXUtil.getCellValue(sheet, row, addressForPayee.c),
|
|
43
|
+
Outflow: outflow,
|
|
44
|
+
Inflow: inflow,
|
|
45
|
+
Date: date,
|
|
46
|
+
Memo: XLSXUtil_1.XLSXUtil.getCellValue(sheet, row, addressForDescription.c),
|
|
47
|
+
Category: XLSXUtil_1.XLSXUtil.getCellValue(sheet, row, addressForCategory.c)
|
|
48
|
+
};
|
|
49
|
+
}).filter(row => !!row);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
supports(bank) {
|
|
53
|
+
return bank === __1.Bank.N26;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.N26Adapter = N26Adapter;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Bank } from '..';
|
|
2
|
+
import { Transaction } from '../models/Transaction';
|
|
3
|
+
import { TransactionAdapter } from './TransactionAdapter';
|
|
4
|
+
export declare class StandardCharteredAdapter extends TransactionAdapter {
|
|
5
|
+
convert(xlsxData: ArrayBuffer): Promise<Transaction[]>;
|
|
6
|
+
supports(bank: Bank): boolean;
|
|
7
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.StandardCharteredAdapter = void 0;
|
|
13
|
+
const __1 = require("..");
|
|
14
|
+
const XLSXUtil_1 = require("../helpers/XLSXUtil");
|
|
15
|
+
const TransactionAdapter_1 = require("./TransactionAdapter");
|
|
16
|
+
const XLSX = require("xlsx");
|
|
17
|
+
const moment = require("moment");
|
|
18
|
+
class StandardCharteredAdapter extends TransactionAdapter_1.TransactionAdapter {
|
|
19
|
+
convert(xlsxData) {
|
|
20
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
21
|
+
const workBook = XLSX.read(xlsxData, { raw: true, type: 'array' });
|
|
22
|
+
const sheet = workBook.Sheets[workBook.SheetNames[0]];
|
|
23
|
+
const addressForTransactionDate = XLSXUtil_1.XLSXUtil.findText(sheet, "Date");
|
|
24
|
+
const addressForDetails = XLSXUtil_1.XLSXUtil.findText(sheet, "Transaction");
|
|
25
|
+
const addressForDepositAmount = XLSXUtil_1.XLSXUtil.findText(sheet, "Deposit");
|
|
26
|
+
const addressForWithdrawalAmount = XLSXUtil_1.XLSXUtil.findText(sheet, "Withdrawal");
|
|
27
|
+
const startingRow = addressForTransactionDate.r + 1;
|
|
28
|
+
const range = XLSX.utils.decode_range(sheet['!ref']);
|
|
29
|
+
const rangeEnd = range.e;
|
|
30
|
+
const lastRow = rangeEnd.r;
|
|
31
|
+
const rows = [...Array(1 + lastRow - startingRow).keys()].map(v => startingRow + v);
|
|
32
|
+
return rows.map(row => {
|
|
33
|
+
const date = moment(XLSXUtil_1.XLSXUtil.getCellValue(sheet, row, addressForTransactionDate.c), 'DD/MM/YYYY').toDate();
|
|
34
|
+
const outflow = XLSXUtil_1.XLSXUtil.getNumberInCell(sheet, row, addressForWithdrawalAmount.c);
|
|
35
|
+
const inflow = XLSXUtil_1.XLSXUtil.getNumberInCell(sheet, row, addressForDepositAmount.c);
|
|
36
|
+
const payee = XLSXUtil_1.XLSXUtil.getCellValue(sheet, row, addressForDetails.c);
|
|
37
|
+
return {
|
|
38
|
+
Payee: payee,
|
|
39
|
+
Outflow: outflow,
|
|
40
|
+
Inflow: inflow,
|
|
41
|
+
Date: date,
|
|
42
|
+
Memo: payee,
|
|
43
|
+
Category: null
|
|
44
|
+
};
|
|
45
|
+
}).filter(datum => moment(datum.Date).isValid());
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
supports(bank) {
|
|
49
|
+
return bank === __1.Bank.StandardChartered;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.StandardCharteredAdapter = StandardCharteredAdapter;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.TransactionsQifConverter = void 0;
|
|
13
|
+
const qif = require("qif");
|
|
14
|
+
const moment = require("moment");
|
|
15
|
+
class TransactionsQifConverter {
|
|
16
|
+
convert(transactions) {
|
|
17
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
18
|
+
const qifTransactions = transactions.map(t => {
|
|
19
|
+
return {
|
|
20
|
+
date: moment(t.Date).format('D/M/YYYY'),
|
|
21
|
+
amount: t.Inflow ? t.Inflow : -t.Outflow,
|
|
22
|
+
payee: t.Payee,
|
|
23
|
+
memo: t.Memo,
|
|
24
|
+
category: t.Category
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
return qif.write({ cash: qifTransactions });
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.TransactionsQifConverter = TransactionsQifConverter;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NumberUtil = void 0;
|
|
4
|
+
const multi_number_parse_1 = require("multi-number-parse");
|
|
5
|
+
class NumberUtil {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.commonSeparators = [",", "."];
|
|
8
|
+
}
|
|
9
|
+
parseNumber(text) {
|
|
10
|
+
if (!text) {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
const trimmedText = text.trim();
|
|
14
|
+
if (!trimmedText) {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
// Remove additional separators as the library seems to fail if they're present. Eg: 2,00,000.00
|
|
18
|
+
var parsableText = trimmedText;
|
|
19
|
+
for (const separator of this.commonSeparators) {
|
|
20
|
+
if (trimmedText.split(separator).length > 2) {
|
|
21
|
+
parsableText = trimmedText.replace(separator, '');
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return (0, multi_number_parse_1.default)(parsableText);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.NumberUtil = NumberUtil;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { CellAddress, WorkSheet } from 'xlsx';
|
|
2
|
+
export declare class XLSXUtil {
|
|
3
|
+
static findText(sheet: WorkSheet, text: string): CellAddress;
|
|
4
|
+
static getCellValue(sheet: WorkSheet, row: number, column: number): string | number | boolean;
|
|
5
|
+
static getNumberInCell(sheet: WorkSheet, row: number, column: number): number;
|
|
6
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.XLSXUtil = void 0;
|
|
4
|
+
const lodash_1 = require("lodash");
|
|
5
|
+
const NumberUtil_1 = require("./NumberUtil");
|
|
6
|
+
const xlsx_1 = require("xlsx");
|
|
7
|
+
class XLSXUtil {
|
|
8
|
+
static findText(sheet, text) {
|
|
9
|
+
const range = xlsx_1.utils.decode_range(sheet['!ref']);
|
|
10
|
+
const rangeEnd = range.e;
|
|
11
|
+
const rangeStart = range.s;
|
|
12
|
+
for (let R = rangeStart.r; R <= rangeEnd.r; ++R) {
|
|
13
|
+
for (let C = rangeStart.c; C <= rangeEnd.c; ++C) {
|
|
14
|
+
const cellAddress = xlsx_1.utils.encode_cell({ c: C, r: R });
|
|
15
|
+
if (!sheet[cellAddress])
|
|
16
|
+
continue;
|
|
17
|
+
const cell = sheet[cellAddress];
|
|
18
|
+
if (!(cell.t == 's' || cell.t == 'str'))
|
|
19
|
+
continue;
|
|
20
|
+
if ((0, lodash_1.trim)(cell.v) === (0, lodash_1.trim)(text))
|
|
21
|
+
return xlsx_1.utils.decode_cell(cellAddress);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
static getCellValue(sheet, row, column) {
|
|
26
|
+
const cellAddress = xlsx_1.utils.encode_cell({ c: column, r: row });
|
|
27
|
+
return !sheet[cellAddress] ? null : sheet[cellAddress].v;
|
|
28
|
+
}
|
|
29
|
+
static getNumberInCell(sheet, row, column) {
|
|
30
|
+
const cellAddress = xlsx_1.utils.encode_cell({ c: column, r: row });
|
|
31
|
+
if (!sheet[cellAddress])
|
|
32
|
+
return null;
|
|
33
|
+
const value = sheet[cellAddress].v;
|
|
34
|
+
if ((0, lodash_1.isNumber)(value)) {
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
const number = new NumberUtil_1.NumberUtil().parseNumber(value);
|
|
38
|
+
return number === null || number === void 0 ? void 0 : number.valueOf();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
exports.XLSXUtil = XLSXUtil;
|