UNPKG

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
"use strict"; 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; }