statement-parser-fab
Version:
Parse bank and credit card statements. Updated fork with FAB (First Abu Dhabi Bank) support and maintained dependencies.
105 lines (104 loc) • 4.45 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.chasePrimeVisaCreditCardParser = exports.defaultChaseCreditCardParserOptions = void 0;
const augment_vir_1 = require("augment-vir");
const date_1 = require("../../augments/date");
const statement_parser_1 = require("../statement-parser");
var State;
(function (State) {
State["Header"] = "header";
State["Payment"] = "payment";
State["Purchase"] = "purchase";
State["End"] = "end";
})(State || (State = {}));
const ChaseParsingTriggers = {
Payments: 'payments and other credits',
Purchase: /^\s*purchase\s*$/i,
Purchases: /^\s*purchases\s*$/i,
Totals: 'totals year-to-date',
AccountNumber: 'account number:',
OpeningClosingDate: 'opening/closing date',
};
const accountNumberRegExp = new RegExp(`${ChaseParsingTriggers.AccountNumber} .+(\\d{1,4})$`, 'i');
const closingDateRegExp = new RegExp(`${ChaseParsingTriggers.OpeningClosingDate}\\s+(\\d{1,2}/\\d{1,2}/\\d{1,2})\\s+-\\s+(\\d{1,2}/\\d{1,2}/\\d{1,2})`, 'i');
exports.defaultChaseCreditCardParserOptions = {
includeMultiLineDescriptions: true,
};
exports.chasePrimeVisaCreditCardParser = (0, statement_parser_1.createStatementParser)({
action: performStateAction,
next: nextState,
initialState: State.Header,
endState: State.End,
defaultParserOptions: exports.defaultChaseCreditCardParserOptions,
parserKeywords: Object.values(ChaseParsingTriggers),
});
function processTransactionLine(line, startDate, endDate) {
const [, date, description, amount,] = (0, augment_vir_1.safeMatch)(line, /^(\d{1,2}\/\d{1,2})\s+(\S.+?)\s+([\.\d,\-]+)$/);
if (date && description && amount) {
const [month, day,] = date.split('/');
return {
amount: Number((0, augment_vir_1.removeCommasFromNumberString)(amount)),
description,
date: (0, date_1.dateWithinRange)(startDate, endDate, Number(month), Number(day)),
originalText: [line],
};
}
else {
return line;
}
}
function performStateAction(currentState, line, output, parserOptions) {
if (currentState === State.Header) {
const [, startDateString, endDateString,] = (0, augment_vir_1.safeMatch)(line, closingDateRegExp);
const [, accountNumber,] = (0, augment_vir_1.safeMatch)(line, accountNumberRegExp);
if (startDateString && endDateString) {
const startDate = (0, augment_vir_1.createDateFromSlashFormat)(startDateString, parserOptions.yearPrefix);
const endDate = (0, augment_vir_1.createDateFromSlashFormat)(endDateString, parserOptions.yearPrefix);
// Chase statements sometimes include transactions a few days outside of the statement range.
startDate.setDate(startDate.getDate() - 3);
endDate.setDate(endDate.getDate() + 3);
output.startDate = startDate;
output.endDate = endDate;
}
else if (accountNumber && !output.accountSuffix) {
output.accountSuffix = accountNumber;
}
}
else if (currentState === State.Payment || currentState === State.Purchase) {
if (!output.endDate || !output.startDate) {
throw new Error('Started reading transactions but got no start or end dates.');
}
const array = currentState === State.Payment ? output.incomes : output.expenses;
const result = processTransactionLine(line, output.startDate, output.endDate);
if (typeof result !== 'string') {
array.push(result);
}
}
return output;
}
function nextState(currentState, line) {
line = line.toLowerCase();
switch (currentState) {
case State.Header:
if (line === ChaseParsingTriggers.Payments) {
return State.Payment;
}
else if (line.match(ChaseParsingTriggers.Purchase) ||
line.match(ChaseParsingTriggers.Purchases)) {
return State.Purchase;
}
break;
case State.Payment:
if (line.match(ChaseParsingTriggers.Purchase) ||
line.match(ChaseParsingTriggers.Purchases)) {
return State.Purchase;
}
break;
case State.Purchase:
if (line.includes(ChaseParsingTriggers.Totals)) {
return State.End;
}
break;
}
return currentState;
}