This does. Just run this when you’ve selected a date range and you want those transactions as CSV
Last active
August 10, 2023 01:19
-
-
Save renoirb/d5823a33b414f81407ebe2a26bab7027 to your computer and use it in GitHub Desktop.
Unfinished: Making RBC Personal Online Banking OMNI usable.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;(() => { | |
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)) | |
})() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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')) | |
})() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Follow up: