Skip to content

Instantly share code, notes, and snippets.

@glenndevenish
Created September 29, 2018 15:19
Show Gist options
  • Save glenndevenish/036af94a5f22f23f27c96f5ce277b3f2 to your computer and use it in GitHub Desktop.
Save glenndevenish/036af94a5f22f23f27c96f5ce277b3f2 to your computer and use it in GitHub Desktop.
Parse Xero reports from their API into a nicer format
/*
As it stands, Xero reports from their API are not very nice to use. This function will return them in a flattened format.
This takes the Report data (so, `parseXeroReport(response.Reports)` where response is the raw response from the API), and parses it.
There's two formats it could take - one where it returns simply the value, and one where it returns an array of values.
{
"Date": "30 Sep 2018",
"Sales": "12345.67",
"Total Income": "12345.67",
...
}
or
{
"Date": [
"30 Sep 2018",
"30 Sep 2017"
],
"Some Account Name": [
"234567.89",
"123456.78"
],
"Total Bank": [
"234567.89",
"123456.78"
]
...
}
You can then use things like:
const profitAndLoss = parseXeroReport(ProfitAndLossReport)
profitAndLoss["Gross Profit"] = "..."
*/
function parseXeroReport (report) {
// Internal Functions
const arrays = el => Array.isArray(el)
const turnIntoObject = (final, el) => {
if (final.hasOwnProperty(el[0])) { // don't overwrite existing properties
el[0] += ' (copy)'
}
if (el.length === 2) {
final[el[0]] = el[1]
} else if (el.length > 2) { // returns 'title': [value1, value2, ...]
final[el[0]] = [
...el.slice(1, el.length)
]
} else { // fail gracefully. set this to [] rather than '' if you are mapping the responses
final[el[0]] = ''
}
return final
}
const getHeaderValues = (header, cell) => {
cell.Value === ''
? header.push('Date') // the first one is normally blank, and is where the title goes.
: header.push(cell.Value)
return header
}
// Main Function
return [].concat(...report[0].Rows.map(row => {
if (row.RowType === 'Header') {
return [ // return it inside an array, for the reducer below
row.Cells.reduce(getHeaderValues, [])
]
} else if (row.hasOwnProperty('Rows')) {
return row.Rows.map(subRow => {
return subRow.Cells.map(cell => {
return cell.Value
})
})
}
}))
.filter(arrays) // make sure all properties are arrays, so we can reduce them
.reduce(turnIntoObject, {})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment