Skip to content

Instantly share code, notes, and snippets.

@renoirb
Last active August 10, 2023 01:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save renoirb/d5823a33b414f81407ebe2a26bab7027 to your computer and use it in GitHub Desktop.
Save renoirb/d5823a33b414f81407ebe2a26bab7027 to your computer and use it in GitHub Desktop.
Unfinished: Making RBC Personal Online Banking OMNI usable.

RBC Royal Bank Online Banking doesn't allow extracting CSV of transactions

This does. Just run this when you’ve selected a date range and you want those transactions as CSV

See usable snippet

;(() => {
let isCentsSeparatorPoint = false
const reportDate = new Date().toISOString().split('T')[0]
const getCentsSep = (a) => {
const amtArr = a.split('')
const centsSepIndex = amtArr.length - 3
const sep = amtArr[centsSepIndex]
if (/^[,\.]$/.test(sep) === false) {
const message = `The number "${a}" does not look like an amount of money`
throw new Error(message)
}
return sep
}
const nrml = (a) => {
const amtArr = a.split('').map((i) => (Number.isInteger(+i) ? i : ' '))
const centsSepIndex = amtArr.length - 3
if (amtArr[centsSepIndex] !== ' ') {
const amt = a.replace(/\s/g, '')
/* It is not an amount of money, so return as is, but no comas! */
return isCentsSeparatorPoint ? amt : amt.replace(',', '.')
}
const amtLeftOf = amtArr.slice(0, centsSepIndex).filter((i) => i !== ' ')
const amtRightOf = amtArr.slice(centsSepIndex + 1, amtArr.length)
return [...amtLeftOf, '.', ...amtRightOf].join('')
}
const processRow = (row) => {
const getFor = (header) =>
nrml(
row.querySelectorAll(`td[headers="${header}"]`)[0].textContent.trim(),
)
const totalValue = getFor('M5')
const unitBookCost = getFor('M2')
const units = getFor('M3')
const price = getFor('M4')
/*
console.log('testing', {
totalValue: [totalValue, nrml(totalValue)],
unitBookCost: [unitBookCost, nrml(unitBookCost)],
units: [units, nrml(units)],
price: [price, nrml(price)],
})
*/
const name = row.querySelectorAll('td[headers="M1"]')[0].textContent.trim()
return { name, unitBookCost, units, price, amount: +totalValue }
}
const grandTotal = document
.querySelector('td.dataTableHeaderText[align=right]')
.textContent.trim()
isCentsSeparatorPoint = getCentsSep(grandTotal) === '.'
const dataTable = document.querySelectorAll('.dataTableBorder')[1]
const dataTableRows = dataTable.querySelectorAll(
'.dataTableLightRow,.dataTableDarkRow',
)
const rows = [...dataTableRows].map(processRow)
const reportTitle = document.querySelector('#pagetitle').textContent.trim()
const data = {
is: reportTitle,
date: reportDate,
grandTotal: nrml(grandTotal),
rows,
}
console.table(data.rows)
console.table({
reportDate,
is: data.is,
isCentsSeparatorPoint,
grandTotal: data.grandTotal,
})
copy(JSON.stringify(data))
})()
/**
* On an account, when we use the filter, we can't use back and forward buttons.
* That's quite useful when we want to download a cheque image.
* But we can't open cheque image in new tab. We're forced to click.
* When we hit back, we're back as if we haven't have any filter.
*
* That's because OMNI development team doesn't use URL to keep state of search parameters which would give *for free* back and forward navigation.
*
* The best would be to pick
*
* This doesn't work
*/
/**
* Since we can't go back when we visualize an item, let's try to reproduce the filter state
* as if we've done it by hand.
*
* But this doesn’t work.
*
* Because in the time I've spent, I couldn't find if the code actually affect the form.
* So changing form fields values seem to not be really impacted.
* Or there's a disconnect.
*/
var setFilterStateFormForMonthYear = (form, month, year = 2022) => {
if (!/\d\d\d\d/.test(year)) {
const message = `Invalid year format "${year}", we are expecting a four digit number`
throw new Error(message)
}
if (month < 1 || month > 12) {
throw new Error(`There are no month at ${month} th index.`)
}
var dateRanges = [
['', ''],
['1 janv.', '31 janv.'],
['1 fev.', '28 fev.'],
['1 mars', '31 mars'],
['1 avr.', '30 avr.'],
['1 mai', '31 mai'],
['1 juin', '30 juin'],
['1 juil.', '31 juil.'],
['1 août', '31 août'],
['1 sept.', '30 sept.'],
['1 oct.', '31 oct.'],
['1 nov.', '30 nov.'],
['1 déc.', '31 déc.'],
]
const [from, to] = Reflect.get(dateRanges, month)
form.querySelector('#filterFromDatepicker').value = `${from} ${year}`
form.querySelector('#filterToDatepicker').value = `${to} ${year}`
form.querySelector('#CHEQUE').click()
form.querySelector('button[type=submit]').click()
}
;(() => {
var filterButton = document.querySelector(
'[data-testid="rbc-transaction-search-filter"]',
)
var filterForm = Array.from(
filterButton.querySelectorAll('form'),
).filter((f) => f.classList.contains('filter__form'))
})()
@renoirb
Copy link
Author

renoirb commented Oct 20, 2022

Follow up:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment