UNPKG

statement-parser-fab

Version:

Parse bank and credit card statements. Updated fork with FAB (First Abu Dhabi Bank) support and maintained dependencies.

140 lines (139 loc) 5.82 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.usaaBankAccountStatementParser = 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["PageHeader"] = "header"; State["StatementPeriod"] = "statement-period"; State["DepositHeaders"] = "deposit-headers"; State["Deposit"] = "deposit"; State["DebitHeaders"] = "debit-headers"; State["Debit"] = "debit"; State["Filler"] = "filler"; State["End"] = "end"; })(State || (State = {})); var ParsingTriggers; (function (ParsingTriggers) { ParsingTriggers["OtherDebits"] = "other debits"; })(ParsingTriggers || (ParsingTriggers = {})); const otherDebitsRegExp = /^\s+other debits$/; const accountSummaryRegExp = /^\s+account balance summary$/i; const accountNumberHeaderRegExp = /account number\s+account type\s+statement period/i; const depositsRegExp = /^\s+deposits and other credits$/i; const fromRegExp = /^\s{2,}FROM\s+/; exports.usaaBankAccountStatementParser = (0, statement_parser_1.createStatementParser)({ action: performStateAction, next: nextState, initialState: State.PageHeader, endState: State.End, parserKeywords: [ ...(0, augment_vir_1.getEnumTypedValues)(ParsingTriggers), otherDebitsRegExp, accountSummaryRegExp, accountNumberHeaderRegExp, depositsRegExp, fromRegExp, ], }); const validTransactionLineRegex = /(?:^\d{1,2}\/\d{1,2}\s+|^\s{2,})/; function performStateAction(currentState, line, output, parserOptions) { if (currentState === State.StatementPeriod && line !== '') { const [, accountSuffix, startDateString, endDateString,] = (0, augment_vir_1.safeMatch)(line, /([\d-]+)\s+.+?(\d{1,2}\/\d{1,2}\/\d{1,2}).+?(\d{1,2}\/\d{1,2}\/\d{1,2})/); if (accountSuffix && startDateString && endDateString) { output.accountSuffix = accountSuffix.replace(/-/g, '').slice(-4); if (!output.accountSuffix.match(/\d+/)) { throw new Error(`Invalid account suffix: "${output.accountSuffix}"`); } output.startDate = (0, augment_vir_1.createDateFromSlashFormat)(startDateString, parserOptions.yearPrefix); output.endDate = (0, augment_vir_1.createDateFromSlashFormat)(endDateString, parserOptions.yearPrefix); } else { throw new Error(`Start and end date were not found in line for "${State.StatementPeriod}" state: "${line}"`); } } else if ((currentState === State.Debit || currentState === State.Deposit) && line.match(validTransactionLineRegex)) { const array = currentState === State.Debit ? output.expenses : output.incomes; const [, dateString, amountString, descriptionString,] = (0, augment_vir_1.safeMatch)(line, /^(\d{1,2}\/\d{1,2})\s+((?:\d+|,|\.)+)\s+(.*)$/); const currentDebit = array[array.length - 1]; if (dateString && amountString && descriptionString) { if (!output.startDate || !output.endDate) { throw new Error(`Missing start/end date: ${JSON.stringify({ start: output.startDate, end: output.endDate, })}`); } // start line of debit const parts = dateString.split('/'); const date = (0, date_1.dateWithinRange)(output.startDate, output.endDate, Number(parts[0]), Number(parts[1])); array.push({ date: date, amount: Number((0, augment_vir_1.removeCommasFromNumberString)(amountString)), description: (0, augment_vir_1.collapseSpaces)(descriptionString).trim(), from: undefined, originalText: [line], }); } else if (currentDebit) { /* * Assume that the current line is the last line for the current debit. * "from" is always the last line, so shift the current "from" to "method" since it wasn't the last line. */ currentDebit.description += '\n' + (0, augment_vir_1.collapseSpaces)(line).trim(); if (line.match(fromRegExp)) { currentDebit.from = (0, augment_vir_1.collapseSpaces)(line.replace(fromRegExp, '')).trim(); } currentDebit.originalText.push(line); } } return output; } function nextState(currentState, line) { line = line.toLowerCase(); if (line.match(accountSummaryRegExp)) { return State.End; } switch (currentState) { case State.PageHeader: if (line.match(accountNumberHeaderRegExp)) { return State.StatementPeriod; } else if (line.match(depositsRegExp)) { return State.DepositHeaders; } break; case State.StatementPeriod: if (line !== '') { return State.PageHeader; } break; case State.DepositHeaders: return State.Deposit; case State.Deposit: if (line === '') { return State.Filler; } else if (line.match(otherDebitsRegExp)) { return State.DebitHeaders; } break; case State.DebitHeaders: return State.Debit; case State.Debit: if (line === '') { return State.Filler; } break; case State.Filler: if (line.match(otherDebitsRegExp)) { return State.DebitHeaders; } break; case State.End: break; } return currentState; }