statement-parser-fab
Version:
Parse bank and credit card statements. Updated fork with FAB (First Abu Dhabi Bank) support and maintained dependencies.
126 lines (125 loc) • 5.34 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.paypalStatementParser = void 0;
const augment_vir_1 = require("augment-vir");
const global_1 = require("../../global");
const statement_parser_1 = require("../statement-parser");
var State;
(function (State) {
State["Header"] = "header";
State["HeaderData"] = "header-data";
State["Activity"] = "activity";
State["ExpenseInside"] = "expense-inside";
State["IncomeInside"] = "income-inside";
State["ActivityHeader"] = "activity-header";
State["End"] = "end";
})(State || (State = {}));
var ParsingTriggers;
(function (ParsingTriggers) {
ParsingTriggers["Usd"] = "USD";
ParsingTriggers["MustNotify"] = "you must notify us no later than";
ParsingTriggers["Statement"] = "statement period";
})(ParsingTriggers || (ParsingTriggers = {}));
const pageEndRegExp = /^page\s+\d+$/i;
const activityHeader = /date\s+description\s+currency\s+amount\s+fees\s+total/i;
const headerDataLineRegExp = /(\w{1,3} \d{1,2},? \d{1,4})\s*-\s*(\w{1,3} \d{1,2},? \d{1,4})\s*(.+)$/;
const transactionStartRegExp = new RegExp(`^(\\d{1,2}/\\d{1,2}/\\d{1,4})\\s+(.+?)${ParsingTriggers.Usd}\\s+([-,.\\d]+)\\s+([-,.\\d]+)\\s+([-,.\\d]+)$`, 'i');
exports.paypalStatementParser = (0, statement_parser_1.createStatementParser)({
action: performStateAction,
next: nextState,
initialState: State.Header,
endState: State.End,
parserKeywords: [
...(0, augment_vir_1.getEnumTypedValues)(ParsingTriggers),
activityHeader,
pageEndRegExp,
],
});
function performStateAction(currentState, line, output) {
const lastExpense = output.expenses[output.expenses.length - 1];
const lastIncome = output.incomes[output.incomes.length - 1];
if (currentState === State.HeaderData && !output.startDate) {
const [, startDate, endDate, accountId,] = (0, augment_vir_1.safeMatch)(line, headerDataLineRegExp);
if (startDate && endDate && accountId) {
output.startDate = (0, augment_vir_1.createDateFromNamedCommaFormat)(startDate, (0, global_1.isSanitizerMode)());
output.endDate = (0, augment_vir_1.createDateFromNamedCommaFormat)(endDate, (0, global_1.isSanitizerMode)());
output.accountSuffix = accountId;
}
}
else if (currentState === State.Activity) {
const [, date, description, amountString, fees, total,] = (0, augment_vir_1.safeMatch)(line, transactionStartRegExp);
if (date && description && amountString && fees && total) {
const amount = Number((0, augment_vir_1.removeCommasFromNumberString)(amountString));
const newTransaction = {
date: (0, augment_vir_1.createDateFromSlashFormat)(date),
description: (0, augment_vir_1.collapseSpaces)(description),
// this assumption that we can always use absolute value here may be wrong
amount: Math.abs(Number((0, augment_vir_1.removeCommasFromNumberString)(total))),
fees: Math.abs(Number((0, augment_vir_1.removeCommasFromNumberString)(fees))),
baseAmount: Math.abs(amount),
originalText: [line],
};
const array = amount < 0 ? output.expenses : output.incomes;
array.push(newTransaction);
}
}
else if (currentState === State.ExpenseInside && line !== '' && lastExpense) {
lastExpense.description += '\n' + (0, augment_vir_1.collapseSpaces)(line);
lastExpense.originalText.push(line);
}
else if (currentState === State.IncomeInside && line !== '' && lastIncome) {
lastIncome.description += '\n' + (0, augment_vir_1.collapseSpaces)(line);
lastIncome.originalText.push(line);
}
return output;
}
function nextState(currentState, line) {
line = line.toLowerCase();
if (line.includes(ParsingTriggers.MustNotify)) {
return State.End;
}
switch (currentState) {
case State.Header:
if (line.includes(ParsingTriggers.Statement)) {
return State.HeaderData;
}
else if (line.match(activityHeader)) {
return State.ActivityHeader;
}
break;
case State.ActivityHeader:
if (line === '') {
return State.Activity;
}
break;
case State.HeaderData:
return State.Header;
case State.ExpenseInside:
if (line === '') {
return State.Activity;
}
break;
case State.IncomeInside:
if (line === '') {
return State.Activity;
}
break;
case State.Activity:
const amountMatch = (0, augment_vir_1.safeMatch)(line, transactionStartRegExp)[5];
if (amountMatch) {
if (Number((0, augment_vir_1.removeCommasFromNumberString)(amountMatch)) < 0) {
return State.ExpenseInside;
}
else {
return State.IncomeInside;
}
}
else if (line.match(pageEndRegExp)) {
return State.Header;
}
break;
case State.End:
break;
}
return currentState;
}