Skip to content

Instantly share code, notes, and snippets.

@gabrieljoelc
Last active August 11, 2017 21:34
Show Gist options
  • Save gabrieljoelc/1bd6f04d70e9038e8b667479b660a982 to your computer and use it in GitHub Desktop.
Save gabrieljoelc/1bd6f04d70e9038e8b667479b660a982 to your computer and use it in GitHub Desktop.
Dumps a Heroku invoice into a CSV
// app,type(dyno,addon),name,dyno_type(if applicable),period,rate,total
// console.log(appTitle + ',addon,' + tr.find('.period').text() + ',' + tr.find('.rate').text() + ',' + tr.find('.total').text())
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/gm, '');
}
var RowBuilder = function(tr) {
this.nameElem = function() {
if (tr.find('.process').length > 0) {
return tr.find('.process');
} else {
return tr.find('.name');
}
}.bind(this);
this.dynoType = function() {
if (this.nameElem().find('em').length > 0) {
return this.nameElem().find('em').text().trim();
}
return null;
}.bind(this);
this.name = function() {
var dynoType = this.dynoType();
var name = this.nameElem().text();
var regex;
if (dynoType) {
regex = new RegExp(dynoType, 'gm');
name = name.replace(regex, '');
}
return name.trim();
}.bind(this);
this.period = function() {
return tr.find('.period').text().trim();
};
this.rate = function() {
// have to get the second to last one instead of using a class because addons don't have the .rate class...
return tr.find('td').last().prev().text().trim();
};
this.total = function() {
// have to get the last one instead of using a class because addons don't have the .total class...
return tr.find('td').last().text().trim();
};
return {
name: this.name(),
dynoType: this.dynoType(),
create: function(type, runDynoType) {
return [type, this.name(), runDynoType || this.dynoType(), this.period(), this.rate(), this.total()]
}.bind(this)
};
};
var csv = []
var CsvBuilder = function($, RowBuilder) {
this.csvArray = [];
this.appendAllToCsv = function(appElem, type) {
var appTitle = appElem.find('.app-title .title').text();
appElem.find('.' + type + 's tbody tr').not('.resource-graph').not('.credit').not('.run-detail').each(function(index, tr) {
tr = $(tr)
var row;
var rowBuilder = new RowBuilder(tr, this);
if (RowBuilder.name == 'run') {
tr.next('.run-detail-run-' + RowBuilder.dynoType).each(function(index, runTr) {
row = new RowBuilder($(runTr), this).create(type + '/run', RowBuilder.dynoType);
}.bind(this));
} else {
row = rowBuilder.create(type);
}
row.splice(0, 0, appTitle);
this.csvArray.push(row);
}.bind(this));
}.bind(this);
this.buildForApp = function(index, appElem) {
appElem = $(appElem);
this.appendAllToCsv(appElem, 'dyno');
this.appendAllToCsv(appElem, 'addon');
}.bind(this);
this.createString = function() {
var csvContent = "data:text/csv;charset=utf-8,";
this.csvArray.splice(0, 0, ['app', 'type(dyno,addon)', 'name', 'dyno_type(if applicable)', 'period', 'rate', 'total']);
this.csvArray.forEach(function(infoArray, index){
dataString = infoArray.join(",");
csvContent += index < this.csvArray.length ? dataString+ "\n" : dataString;
}.bind(this));
return csvContent;
}.bind(this);
this.buildArray = function() {
if (this.csvArray.length > 0) {
return;
}
$('.app').each(this.buildForApp);
}.bind(this);
this.rebuildArray = function() {
this.csvArray = [];
$('.app').each(this.buildForApp);
}.bind(this);
return {
buildArray: function() {
this.buildArray();
}.bind(this),
rebuildArray: function() {
this.rebuildArray();
}.bind(this),
createString: function() {
this.buildArray();
return this.createString();
}.bind(this),
download: function() {
this.buildArray();
var encodedUri = encodeURI(this.createString());
window.open(encodedUri);
}.bind(this)
};
};
new CsvBuilder(jQuery, RowBuilder).download();
@gabrieljoelc
Copy link
Author

I need to add another column that copies the invoice-period class content on every row:

<span class="invoice-period">
  Jun 01 - Jul 01, 2017
</span>

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