@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.
Files changed (55) hide show
  1. package/StatementConverter.d.ts +7 -0
  2. package/StatementConverter.js +45 -0
  3. package/adapters/ABNAdapter.d.ts +7 -0
  4. package/adapters/ABNAdapter.js +55 -0
  5. package/adapters/AxisAdapter.d.ts +7 -0
  6. package/adapters/AxisAdapter.js +53 -0
  7. package/adapters/ICICIAdapter.d.ts +8 -0
  8. package/adapters/ICICIAdapter.js +56 -0
  9. package/adapters/ICICICreditCardAdapter.d.ts +8 -0
  10. package/adapters/ICICICreditCardAdapter.js +56 -0
  11. package/adapters/MT940Adapter.d.ts +7 -0
  12. package/adapters/MT940Adapter.js +56 -0
  13. package/adapters/N26Adapter.d.ts +7 -0
  14. package/adapters/N26Adapter.js +56 -0
  15. package/adapters/StandardCharteredAdapter.d.ts +7 -0
  16. package/adapters/StandardCharteredAdapter.js +52 -0
  17. package/adapters/TransactionAdapter.d.ts +6 -0
  18. package/adapters/TransactionAdapter.js +6 -0
  19. package/adapters/TransactionsQifConverter.d.ts +5 -0
  20. package/adapters/TransactionsQifConverter.js +31 -0
  21. package/helpers/NumberUtil.d.ts +4 -0
  22. package/helpers/NumberUtil.js +28 -0
  23. package/helpers/XLSXUtil.d.ts +6 -0
  24. package/helpers/XLSXUtil.js +41 -0
  25. package/{src/index.ts → index.d.ts} +1 -1
  26. package/index.js +18 -0
  27. package/models/Bank.d.ts +9 -0
  28. package/models/Bank.js +13 -0
  29. package/{src/models/Transaction.ts → models/Transaction.d.ts} +1 -1
  30. package/models/Transaction.js +2 -0
  31. package/package.json +7 -7
  32. package/.github/dependabot.yml +0 -7
  33. package/.github/workflows/node.js.yml +0 -24
  34. package/.github/workflows/npm-publish.yml +0 -35
  35. package/.mocharc.json +0 -5
  36. package/README.md +0 -1
  37. package/src/StatementConverter.ts +0 -32
  38. package/src/adapters/ABNAdapter.ts +0 -45
  39. package/src/adapters/AxisAdapter.ts +0 -42
  40. package/src/adapters/ICICIAdapter.ts +0 -50
  41. package/src/adapters/ICICICreditCardAdapter.ts +0 -50
  42. package/src/adapters/MT940Adapter.ts +0 -49
  43. package/src/adapters/N26Adapter.ts +0 -45
  44. package/src/adapters/StandardCharteredAdapter.ts +0 -46
  45. package/src/adapters/TransactionAdapter.ts +0 -8
  46. package/src/adapters/TransactionsQifConverter.ts +0 -28
  47. package/src/helpers/NumberUtil.ts +0 -27
  48. package/src/helpers/XLSXUtil.ts +0 -38
  49. package/src/models/Bank.ts +0 -9
  50. package/test/AxisBankStatement.xls +0 -0
  51. package/test/ICICIBankStatement.xls +0 -0
  52. package/test/N26Statement.csv +0 -29
  53. package/test/NumberUtil.spec.js +0 -32
  54. package/test/StatementConverter.spec.js +0 -34
  55. package/tsconfig.json +0 -17
@@ -0,0 +1,7 @@
1
+ /// <reference types="node" />
2
+ import { Bank } from "./models/Bank";
3
+ export declare class StatementConverter {
4
+ private readonly transactionsToQif;
5
+ private readonly allAdapters;
6
+ convert(bank: Bank, fileData: ArrayBuffer): Promise<Buffer>;
7
+ }
@@ -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,6 @@
1
+ import { Bank } from '../models/Bank';
2
+ import { Transaction } from '../models/Transaction';
3
+ export declare abstract class TransactionAdapter {
4
+ abstract convert(fileData: ArrayBuffer): Promise<Transaction[]>;
5
+ abstract supports(bank: Bank): boolean;
6
+ }
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TransactionAdapter = void 0;
4
+ class TransactionAdapter {
5
+ }
6
+ exports.TransactionAdapter = TransactionAdapter;
@@ -0,0 +1,5 @@
1
+ /// <reference types="node" />
2
+ import { Transaction } from '../models/Transaction';
3
+ export declare class TransactionsQifConverter {
4
+ convert(transactions: Transaction[]): Promise<Buffer>;
5
+ }
@@ -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,4 @@
1
+ export declare class NumberUtil {
2
+ private readonly commonSeparators;
3
+ parseNumber(text: string): Number;
4
+ }
@@ -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;