Created
February 16, 2016 00:08
-
-
Save d-gubert/4f54d8c8a155c1fedf51 to your computer and use it in GitHub Desktop.
A script to extract your data from NuBank to a .csv file
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
(function() { | |
'use strict'; | |
class NuBankExtractor { | |
constructor() { | |
this.transactionsByDate = new Map(); | |
this.maxDate = new Date(); | |
} | |
getDataFrom(link, promiseMethods, method) { | |
let xhr = new XMLHttpRequest; | |
if (method === undefined) method = 'GET'; | |
xhr.open(method, link, true); | |
xhr.setRequestHeader('Authorization', "Bearer %bearer_token%"); | |
if (typeof promiseMethods === 'object' && typeof promiseMethods.resolve === 'function' && typeof promiseMethods.reject === 'function') { | |
xhr.onload = function() { | |
if (xhr.status === 200 && xhr.response.length > 0) { | |
promiseMethods.resolve(JSON.parse(xhr.response)); | |
} else { | |
promiseMethods.reject('Unexpected error'); | |
} | |
} | |
xhr.onerror = function() { | |
promiseMethods.reject('Network error'); | |
} | |
} | |
xhr.send(); | |
return xhr; | |
} | |
requestCustomerId() { | |
console.info("Querying customer information..."); | |
// Some problems with the strict mode's scope made me use this closure to pass variables around... | |
return new Promise((function(self) {return function(resolve, reject) { | |
self.getDataFrom('https://prod-customers.nubank.com.br/api/customers', {resolve: resolve, reject: reject}); | |
}})(this)); | |
} | |
requestEventList(customer) { | |
console.info("Querying events..."); | |
// Some problems with the strict mode's scope made me use this closure to pass variables around... | |
return new Promise((function(self, customerId) {return function(resolve, reject) { | |
self.getDataFrom('https://prod-notification.nubank.com.br/api/contacts/'+customerId+'/feed', {resolve: resolve, reject: reject}); | |
}})(this, customer.id)); | |
} | |
ensureTransactionDateExists(date) { | |
if (!this.transactionsByDate.has(date.getTime())) this.transactionsByDate.set(date.getTime(), []); | |
} | |
processEventList(eventList) { | |
console.info("Processing events..."); | |
for (var event of eventList) { | |
if (event.category !== 'transaction') continue; | |
let transactionDate = new Date(event.time.substring(0,10)); //Gets only the date portion | |
if (event.details.charges === undefined) { | |
this.processSinglePurchase(event, transactionDate); | |
} else { | |
this.processInstallmentPurchase(event, transactionDate); | |
} | |
} | |
console.log(this.transactionsByDate); | |
this.generateReport(); | |
} | |
processInstallmentPurchase(transaction, transactionDate) { | |
transaction.amount = transaction.details.charges.amount; | |
for (let i = 1, installmentDate = new Date(transactionDate), transactionDescription = transaction.description; | |
i <= transaction.details.charges.count; i++) { | |
installmentDate.setMonth(transactionDate.getMonth() + i - 1); | |
if (installmentDate > this.maxDate) break; | |
transaction.description = transactionDescription + " (Installment #" + i + ")"; | |
this.processSinglePurchase(transaction, installmentDate); | |
} | |
} | |
processSinglePurchase(transaction, transactionDate) { | |
this.ensureTransactionDateExists(transactionDate); | |
this.transactionsByDate.get(transactionDate.getTime()).push({ | |
description: transaction.description, | |
value: transaction.amount / 100, | |
category: transaction.title, | |
datetime: new Date(transaction.time), | |
nubankId: transaction.id | |
}); | |
} | |
generateReport() { | |
let report = 'nubankId,description,value,category,datetime'; | |
this.transactionsByDate.forEach(function(transactionList) { | |
for (let transaction of transactionList) { | |
report += "\n" + | |
transaction.nubankId + "," + | |
'"' + transaction.description + '",' + | |
transaction.value + "," + | |
transaction.category + "," + | |
'"' + transaction.datetime.toLocaleString() + '"'; | |
} | |
}); | |
this.downloadReport(report); | |
} | |
downloadReport(report) { | |
let anchor = document.createElement('a'); | |
anchor.setAttribute("href", "data:attachment/csv," + encodeURIComponent(report)); | |
anchor.setAttribute("download", "extrato_nubank_" + (new Date()).toLocaleDateString().replace(/\//g,'-') + ".csv"); | |
anchor.click(); | |
} | |
run() { | |
// Some problems with the strict mode's scope made me use this closure to pass variables around... | |
this.requestCustomerId().then((function(self) { | |
return function(response) { | |
console.log(response.customer); | |
return self.requestEventList(response.customer); | |
} | |
})(this)).then((function(self) { | |
return function(response) { | |
return self.processEventList(response.events); | |
} | |
})(this)); | |
} | |
}; | |
let app = new NuBankExtractor; | |
app.run(); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment