UNPKG

@hublaw/ofx-parser

Version:

A tool that converts financial data from OFX to JS Object.

426 lines (408 loc) 18.4 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var Xml2JsParser = require('xml2js'); var fs = require('fs'); /*! ***************************************************************************** Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. ***************************************************************************** */ function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __generator(thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } } var OfxDateUtil = (function () { function OfxDateUtil() { } OfxDateUtil.DateToOfxDate = function (date) { var year = date.getUTCFullYear(); var month = this.addLeadingZero(date.getUTCMonth()); var day = this.addLeadingZero(date.getUTCDate()); return "" + year + month + day; }; OfxDateUtil.OfxDateToDate = function (ofxDate) { if (!ofxDate) { return undefined; } var year = parseInt(ofxDate.substr(0, 4), 10); var month = parseInt(ofxDate.substr(4, 2), 10) - 1; var day = parseInt(ofxDate.substr(6, 2), 10); if (ofxDate.length === 8) { return new Date(Date.UTC(year, month, day, 0, 0, 0)); } var hour = parseInt(ofxDate.substr(8, 2), 10); var minute = parseInt(ofxDate.substr(10, 2), 10); var second = parseInt(ofxDate.substr(12, 2), 10); if (ofxDate.length === 14) { return new Date(Date.UTC(year, month, day, hour, minute, second)); } var millisecond; var indexOfDot = ofxDate.indexOf('.'); if (indexOfDot > -1) { millisecond = parseInt(ofxDate.substr(indexOfDot + 1, 3), 10); } var timezone; var indexOfBracket = ofxDate.indexOf('['); var indexOfColon = ofxDate.indexOf(':'); if (indexOfBracket > -1 && indexOfColon > -1) { timezone = ofxDate.substring(indexOfBracket + 1, indexOfColon); if (timezone === '0') { timezone = 'Z'; } else if (timezone.length === 1) { timezone = this.addLeadingZero(timezone) + "00"; } else if (timezone.length === 2) { timezone = timezone.charAt(0) + "0" + timezone.charAt(1) + "00"; } } if (millisecond !== undefined && !timezone) { return new Date(Date.UTC(year, month, day, hour, minute, second, millisecond)); } if (millisecond === undefined && timezone) { millisecond = '000'; } if (millisecond !== undefined && timezone) { var dateString = year + "-" + this.addLeadingZero(month + 1) + "-" + this.addLeadingZero(day) + ("T" + this.addLeadingZero(hour) + ":" + this.addLeadingZero(minute) + ":") + (this.addLeadingZero(second) + "." + this.addLeadingZero(millisecond, 3) + timezone); var date = new Date(dateString); return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), date.getUTCMilliseconds())); } throw new Error("bad date format [" + ofxDate + "]"); }; OfxDateUtil.addLeadingZero = function (number, targetLength) { if (targetLength === void 0) { targetLength = 2; } if (typeof number === 'number') { number = number.toString(); } while (number.length < targetLength) { number = "0" + number; } return number; }; return OfxDateUtil; }()); var OfxAccountBalanceAdapter = (function () { function OfxAccountBalanceAdapter() { } OfxAccountBalanceAdapter.convertToAccountBalance = function (balance) { return { balanceAmount: parseFloat(balance.BALAMT), balanceAsOf: OfxDateUtil.OfxDateToDate(balance.DTASOF) }; }; return OfxAccountBalanceAdapter; }()); var OfxStatementTransactionAdapter = (function () { function OfxStatementTransactionAdapter() { } OfxStatementTransactionAdapter.convertToTransaction = function (trans) { var payee; if (trans.PAYEE) { payee = { name: trans.PAYEE.NAME }; } return { transactionType: trans.TRNTYPE, amount: parseFloat(trans.TRNAMT), fitId: trans.FITID, name: trans.NAME, memo: trans.MEMO, payee: payee, extendedName: trans.EXTDNAME, datePosted: OfxDateUtil.OfxDateToDate(trans.DTPOSTED), dateAvailable: OfxDateUtil.OfxDateToDate(trans.DTAVAIL), checkNumber: trans.CHECKNUM, refNumber: trans.REFNUM, correctFitId: trans.CORRECTFITID, correctAction: trans.CORRECTACTION, serverTransactionId: trans.SRVRTID, imageData: trans.IMAGEDATA }; }; OfxStatementTransactionAdapter.convertTransactionList = function (transList) { if (!transList) { return []; } var transactions = []; if (Array.isArray(transList)) { for (var i = 0; i < transList.length; i++) { transactions.push(OfxStatementTransactionAdapter.convertToTransaction(transList[i])); } } else { transactions.push(OfxStatementTransactionAdapter.convertToTransaction(transList)); } return transactions; }; return OfxStatementTransactionAdapter; }()); var OfxBankAccountAdapter = (function () { function OfxBankAccountAdapter() { } OfxBankAccountAdapter.convertToAccount = function (accountInfo, accountFrom) { var accountNumber; var bankId; var accountType; var serviceStatus; if (accountFrom) { accountNumber = accountFrom.ACCTID; bankId = accountFrom.BANKID; accountType = accountFrom.ACCTTYPE; } else { accountNumber = accountInfo.BANKACCTINFO.BANKACCTFROM.ACCTID; accountType = accountInfo.BANKACCTINFO.BANKACCTFROM.ACCTTYPE; bankId = accountInfo.BANKACCTINFO.BANKACCTFROM.BANKID; serviceStatus = accountInfo.BANKACCTINFO.SVCSTATUS; } return { accountId: accountNumber, bankId: bankId, ofxAccountType: accountType, serviceStatus: serviceStatus }; }; return OfxBankAccountAdapter; }()); var OfxInvestmentAccountAdapter = (function () { function OfxInvestmentAccountAdapter() { } OfxInvestmentAccountAdapter.convertToAccount = function (accountInfo) { return { accountId: accountInfo.INVACCTINFO.INVACCTFROM.ACCTID, ofxAccountType: 'INVESTMENT', serviceStatus: accountInfo.INVACCTINFO.SVCSTATUS, brokerId: accountInfo.INVACCTINFO.INVACCTFROM.BROKERID }; }; return OfxInvestmentAccountAdapter; }()); var OfxCreditCardAccountAdapter = (function () { function OfxCreditCardAccountAdapter() { } OfxCreditCardAccountAdapter.convertToAccount = function (accountInfo) { return { accountId: accountInfo.CCACCTINFO.CCACCTFROM.ACCTID, serviceStatus: accountInfo.CCACCTINFO.SVCSTATUS, ofxAccountType: accountInfo.CCACCTINFO.CCACCTFROM.ACCTTYPE, bankId: accountInfo.CCACCTINFO.CCACCTFROM.BANKID }; }; return OfxCreditCardAccountAdapter; }()); var OfxAccountInfoAdapter = (function () { function OfxAccountInfoAdapter() { } OfxAccountInfoAdapter.convertToAccount = function (accountInfo) { if (accountInfo.CCACCTINFO) { return OfxCreditCardAccountAdapter.convertToAccount(accountInfo); } else if (accountInfo.INVACCTINFO) { return OfxInvestmentAccountAdapter.convertToAccount(accountInfo); } else if (accountInfo.BANKACCTINFO) { return OfxBankAccountAdapter.convertToAccount(accountInfo); } else { throw new Error("Invalid account info [" + accountInfo + "]"); } }; OfxAccountInfoAdapter.convertToAccountList = function (accountInfo) { var accountModels = []; if (Array.isArray(accountInfo)) { for (var i = 0; i < accountInfo.length; i++) { accountModels.push(OfxAccountInfoAdapter.convertToAccount(accountInfo[i])); } } else { accountModels.push(OfxAccountInfoAdapter.convertToAccount(accountInfo)); } return accountModels; }; return OfxAccountInfoAdapter; }()); var OfxStatementDateAdapter = (function () { function OfxStatementDateAdapter() { } OfxStatementDateAdapter.convertStatementDate = function (transactionsList) { return { start: OfxDateUtil.OfxDateToDate(transactionsList.DTSTART), end: OfxDateUtil.OfxDateToDate(transactionsList.DTEND) }; }; return OfxStatementDateAdapter; }()); var OfxParser = (function () { function OfxParser() { } OfxParser.prototype.carbonateAccounts = function (xml) { return __awaiter(this, void 0, void 0, function () { var body; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4, this.convertFromXML(xml)]; case 1: body = _a.sent(); return [2, OfxAccountInfoAdapter.convertToAccountList(body.OFX.SIGNUPMSGSRSV1.ACCTINFOTRNRS.ACCTINFORS.ACCTINFO)]; } }); }); }; OfxParser.prototype.readLocalFile = function (filePath) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { return [2, new Promise(function (resolve, reject) { var ofxData = ''; var readStream = fs.createReadStream(filePath); readStream .on('data', function (data) { ofxData += data; }) .on('error', function (e) { reject(e); }) .on('end', function () { resolve(ofxData); }); })]; }); }); }; OfxParser.prototype.parseStatementFile = function (filePath) { return __awaiter(this, void 0, void 0, function () { var ofxData, result, err_1; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4, this.readLocalFile(filePath)]; case 1: ofxData = _a.sent(); _a.label = 2; case 2: _a.trys.push([2, 4, , 5]); return [4, this.parseStatement(ofxData)]; case 3: result = _a.sent(); return [2, result]; case 4: err_1 = _a.sent(); console.error(err_1); return [2, err_1]; case 5: return [2]; } }); }); }; OfxParser.prototype.parseStatement = function (xml) { return __awaiter(this, void 0, void 0, function () { var body, ledgerBalance, availableBalance, transactions, positions, statementDate; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4, this.convertFromXML(xml)]; case 1: body = _a.sent(); statementDate = {}; if (body.OFX.BANKMSGSRSV1) { ledgerBalance = OfxAccountBalanceAdapter.convertToAccountBalance(body.OFX.BANKMSGSRSV1.STMTTRNRS.STMTRS.LEDGERBAL); if (body.OFX.BANKMSGSRSV1.STMTTRNRS.STMTRS.AVAILBAL) { availableBalance = OfxAccountBalanceAdapter.convertToAccountBalance(body.OFX.BANKMSGSRSV1.STMTTRNRS.STMTRS.AVAILBAL); } if (body.OFX.BANKMSGSRSV1.STMTTRNRS.STMTRS.BANKTRANLIST.DTSTART) { statementDate = OfxStatementDateAdapter.convertStatementDate(body.OFX.BANKMSGSRSV1.STMTTRNRS.STMTRS.BANKTRANLIST); } transactions = OfxStatementTransactionAdapter.convertTransactionList(body.OFX.BANKMSGSRSV1.STMTTRNRS.STMTRS.BANKTRANLIST.STMTTRN); } else { throw new Error('Extrato Bancário não identificado'); } return [2, { ledgerBalance: ledgerBalance.balanceAmount, availableBalance: availableBalance ? availableBalance.balanceAmount : undefined, balanceAsOf: ledgerBalance.balanceAsOf, startDate: statementDate.start, endDate: statementDate.end, transactions: transactions, positions: positions }]; } }); }); }; OfxParser.prototype.convertFromXML = function (ofxString) { var _this = this; return new Promise(function (resolve, reject) { if (!_this.validOfxString(ofxString)) { reject(new Error('Attempting to convert an invalid string.')); } var ofxResult = ofxString.split('<OFX>', 2); var ofxPart = "<OFX>" + ofxResult[1]; var xml = ofxPart .replace(/&/g, "&#038;") .replace(/&amp;/g, "&#038;") .replace(/>\s+</g, '><') .replace(/\s+</g, '<') .replace(/>\s+/g, '>') .replace(/<([A-Z0-9_]*)+\.+([A-Z0-9_]*)>([^<]+)(<\/\1\.\2>)?/g, '<$1$2>$3') .replace(/<(\w+?)>([^<]+)/g, '<$1>$2</<added>$1>') .replace(/<\/<added>(\w+?)>(<\/\1>)?/g, '</$1>'); var json; var parser = new Xml2JsParser.Parser({ explicitArray: false }); parser.parseString(xml, function (err, result) { if (err) { reject(err); } json = result; resolve(json); }); }); }; OfxParser.prototype.validOfxString = function (ofxString) { return ofxString.indexOf('<OFX>') > -1; }; return OfxParser; }()); exports.OfxParser = OfxParser; //# sourceMappingURL=main.js.map