ynab-api-importer
Version:
Import bank transactions into YNAB
114 lines • 12.1 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.bnzAdapter = void 0;
const F = __importStar(require("fp-ts/function"));
const O = __importStar(require("fp-ts/Option"));
const luxon_1 = require("luxon");
const __1 = require("../../");
const login = (page) => async (accessNumber, password, retries = 0) => {
await page.setBypassCSP(true);
await page.goto("https://secure.bnz.co.nz/auth/personal-login");
await page.type("input#field-principal", accessNumber);
await page.type("input#field-credentials", password);
await page.click("button[type=submit]");
try {
const el = await Promise.race([
page.waitForSelector("span.js-main-menu-button-text"),
page.waitForSelector("input[title=Accept]"),
]);
if (el) {
await el.click();
}
await page.waitForSelector("span.js-main-menu-button-text");
}
catch (e) {
if (retries > 3) {
throw e;
}
await login(page)(accessNumber, password, retries + 1);
}
};
const request = (page) => (path, opts = {}) => page.evaluate((path, opts) => fetch(`https://www.bnz.co.nz/ib/api${path}`, {
credentials: "same-origin",
...opts,
}).then(r => r.json()), path, opts);
const getAccounts = (page) => request(page)("/accounts");
const findAccount = (list) => (accountName) => O.fromNullable(list.accountList.find(a => a.nickname === accountName));
const listTransactions = (page) => (accountID) => {
const nzTime = luxon_1.DateTime.utc().setZone("Pacific/Auckland");
const fromDate = nzTime.minus({ days: 8 }).toISODate();
const toDate = nzTime.plus({ days: 1 }).toISODate();
return request(page)(`/transactions?from=${fromDate}&to=${toDate}&account=${accountID}`);
};
const isPending = (t) => t.status.code !== "POSTED";
const isInternational = (t) => t.value.currency !== "NZD";
const isPendingInternational = (t) => isPending(t) && isInternational(t);
const filterPendingInternational = (t) => t.filter(t => !isPendingInternational(t));
const filterPending = (t) => t.filter(t => !isPending(t));
const dateTime = (timestamp) => luxon_1.DateTime.fromISO(timestamp, { zone: "Pacific/Auckland" });
const isFuture = (t) => dateTime(t.timestamp) > luxon_1.DateTime.local();
const filterFuture = (transactions) => transactions.filter(t => !isFuture(t));
const memoFromTransaction = ({ thisAccount: { details }, }) => [details.particulars, details.reference, details.code]
.filter(s => !!s)
.join(" ");
const payeeFromTransaction = (t) => F.pipe(O.fromNullable(t.otherAccount.holder.name), O.alt(() => O.fromNullable(t.thisAccount.details.particulars)), O.getOrElse(() => t.type.description));
const convertTransactions = (ynabAccountID) => (transactions) => {
// Sort oldest -> newest for import ID counters
transactions = transactions.reverse();
const importID = __1.Ynab.importID();
const convert = (t) => {
const date = dateTime(t.timestamp);
const amount = __1.Ynab.amountFromString(t.value.amount);
const import_id = importID(date, amount);
const memo = memoFromTransaction(t);
const payee_name = payeeFromTransaction(t);
return {
account_id: ynabAccountID,
amount,
date: date.toISODate(),
import_id,
memo,
payee_name,
};
};
return transactions.map(convert);
};
const ynabTransactions = (page) => (accounts) => (includePending) => (accountName, ynabAccountID) => F.pipe(findAccount(accounts)(accountName), O.fold(() => Promise.resolve([]), account => listTransactions(page)(account.id)
.then(r => r.transactions)
.then(filterFuture)
.then(includePending ? filterPendingInternational : filterPending)
.then(convertTransactions(ynabAccountID))));
const bnzAdapter = async ({ accessNumber, password, includePending = false, }) => {
const { browser, page } = await (0, __1.setupPage)();
await login(page)(accessNumber, password);
const accounts = await getAccounts(page);
return [
ynabTransactions(page)(accounts)(includePending),
() => browser.close(),
];
};
exports.bnzAdapter = bnzAdapter;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYWRhcHRlcnMvYm56L2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsa0RBQW9DO0FBQ3BDLGdEQUFrQztBQUNsQyxpQ0FBaUM7QUFHakMsOEJBQW1EO0FBR25ELE1BQU0sS0FBSyxHQUFHLENBQUMsSUFBVSxFQUFFLEVBQUUsQ0FBQyxLQUFLLEVBQ2pDLFlBQW9CLEVBQ3BCLFFBQWdCLEVBQ2hCLE9BQU8sR0FBRyxDQUFDLEVBQ1gsRUFBRTtJQUNGLE1BQU0sSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUM5QixNQUFNLElBQUksQ0FBQyxJQUFJLENBQUMsOENBQThDLENBQUMsQ0FBQztJQUNoRSxNQUFNLElBQUksQ0FBQyxJQUFJLENBQUMsdUJBQXVCLEVBQUUsWUFBWSxDQUFDLENBQUM7SUFDdkQsTUFBTSxJQUFJLENBQUMsSUFBSSxDQUFDLHlCQUF5QixFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQ3JELE1BQU0sSUFBSSxDQUFDLEtBQUssQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO0lBRXhDLElBQUk7UUFDRixNQUFNLEVBQUUsR0FBRyxNQUFNLE9BQU8sQ0FBQyxJQUFJLENBQUM7WUFDNUIsSUFBSSxDQUFDLGVBQWUsQ0FBQywrQkFBK0IsQ0FBQztZQUNyRCxJQUFJLENBQUMsZUFBZSxDQUFDLHFCQUFxQixDQUFDO1NBQzVDLENBQUMsQ0FBQztRQUVILElBQUksRUFBRSxFQUFFO1lBQ04sTUFBTSxFQUFFLENBQUMsS0FBSyxFQUFFLENBQUM7U0FDbEI7UUFDRCxNQUFNLElBQUksQ0FBQyxlQUFlLENBQUMsK0JBQStCLENBQUMsQ0FBQztLQUM3RDtJQUFDLE9BQU8sQ0FBQyxFQUFFO1FBQ1YsSUFBSSxPQUFPLEdBQUcsQ0FBQyxFQUFFO1lBQ2YsTUFBTSxDQUFDLENBQUM7U0FDVDtRQUNE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