Wizard Clear Advantage to OFX/CSV

By Fred[dy] Last update Sep 19, 2008 — Installed 42 times. Daily Installs: 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0

There are 1 previous version of this script.

// ==UserScript==
// Version         0.2 - 19/09/2008
// @name           Wizard Clear Advantage to OFX/CSV
// @namespace      vagabond
// @description    Exports Wizard Clear Advantage Credit Card statement to OFX/CSV formats
// @include        https://service.gemoney.com.au/*?page=trans-hist*
// ==/UserScript==
//N.B. Many thanks to Chris B. whose script (http://userscripts.org/scripts/show/6976) inspired me to write this one and has also been a source of shameless copy-paste.

var statement;
var busy = false;
var initialised = false;

function init() {
	if (initialised) return;
	initialised = true;
//	alert("Initialising...");
	createControls();
}


function createControls() {
	createButton('Export to OFX', function(e) { writeStatement(caStatementBuilder, ofxStatementFormatter); });
	createButton('Export to CSV', function(e) { writeStatement(caStatementBuilder, csvStatementFormatter); });
}

function createButton(title, listener) {
//	alert("Creating button: " + title);
	var optsBox = document.getElementById('optsbox');
	var buttonList = optsBox.getElementsByTagName('ul')[0];
	var button = document.createElement('li');
	var link = document.createElement('a');
	link.title = title;
	link.href = '#';
	link.addEventListener('click', listener, false);
	link.innerHTML = title;
	button.appendChild(link);
	buttonList.appendChild(button);
}

function writeStatement(builder, formatter) {
//	alert('Click');
	if (busy == true) return;
	busy = true;
	if (statement == null) {
//		alert('Building statement');
		builder();
	}
//	alert('Formatting OFX');
	var text = formatter();
	OpenWindow=window.open("", "newwin", "height=700, width=500,resizable=yes,scrollbars=yes,toolbar=no,menubar=yes");
	OpenWindow.document.open("text/plain", "replace");
	OpenWindow.document.write(text)
	OpenWindow.document.close();
	busy = false;
}

var caStatementBuilder = function() {
	statement = new Object();
	statement.accountId = 'Wizard CA ' + document.getElementById('main').getElementsByTagName('div')[0].getElementsByTagName('p')[1].textContent.match(new RegExp(/\d{4}/))[0];
	statement.currency = 'AUD';
	var tables = document.getElementById('main').getElementsByTagName('table');
	var dataTable = tables[tables.length - 1];
	var tranMap = new Object();
	for (i = 1; i < dataTable.tBodies[0].rows.length; i++) {
		row = dataTable.tBodies[0].rows[i];
//		alert('Processing row: ' + row);
		var tranId = row.cells[2].textContent;
		var t = tranMap[tranId];
		if (!t) {
//			alert('Creating new transaction: ' + tranId);
			t = new Object();
			tranMap[tranId] = t;
			t.reference = tranId;
			t.date = new Date(trimString(row.cells[0].textContent));
			t.memo = trimString(row.cells[1].textContent);
		}
		var amount = row.cells[4].textContent.slice(1);
		if (amount == '0.00') {
			t.origcurrency = new Object();
			var foreignData = trimString(row.cells[3].textContent).split(' ');
			t.origcurrency.amount = parseFloat(foreignData[0].replace(',', '', 'g'));
			t.origcurrency.symbol = foreignData[1];
			t.memo += '. ' + trimString(row.cells[3].textContent);
		} else {
			amount = amount.replace(',', '', 'g');
			if (amount.substr(-2) == 'CR') {
				amount = amount.substring(0, amount.length - 2);
				t.amount = -parseFloat(amount);
			} else {
				t.amount = parseFloat(amount);
			}
			t.description = trimString(row.cells[3].textContent);
			if (t.amount != null && t.origcurrency != null) {
				t.origcurrency.rate = Math.abs(t.origcurrency.amount / t.amount);
			}
		}
		if (statement.startDate == null || statement.startDate > t.date) {
			statement.startDate = t.date;
		}
		if (statement.endDate == null || statement.endDate < t.date) {
			statement.endDate = t.date;
		}
	}
	statement.transactions = new Array();
	for each (var t in tranMap) {
		statement.transactions.push(t);
	}
}



var ofxStatementFormatter = function() {
	var OFX = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n';
	OFX += '<?OFX OFXHEADER="200" VERSION="211" SECURITY="NONE" OLDFILEUID="NONE" NEWFILEUID="NONE"?>\n';
	OFX += '<OFX>\n';
	OFX += '<SIGNONMSGSRSV1><SONRS>'
		+ '<STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY></STATUS>'
		+ '<DTSERVER>' + formatDateForOFX(new Date()) + '</DTSERVER>'
		+ '<LANGUAGE>ENG</LANGUAGE></SONRS></SIGNONMSGSRSV1>\n';
	OFX += '<CCSTMTTRNRS><TRNUID>0</TRNUID>'
		+ '<STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY></STATUS>'
		+ '<CCSTMTRS>'
		+ '<CURDEF>' + statement.currency + '</CURDEF>'
		+ '<CCACCTFROM><ACCTID>' + statement.accountId + '</ACCTID></CCACCTFROM>'
		+ '<BANKTRANLIST>'
		+ '<DTSTART>' + formatDateForOFX(statement.startDate) + '</DTSTART>'
		+ '<DTEND>' + formatDateForOFX(statement.endDate) + '</DTEND>\n';

	for (i = 0; i < statement.transactions.length; i++) {
		var t = statement.transactions[i];
		OFX += ofxTransactionFormatter(t);
	}
	OFX += '</BANKTRANLIST></CCSTMTRS></CCSTMTTRNRS>';
	OFX += '</OFX>';
	return OFX;
}

var ofxTransactionFormatter = function(t) {
	var result = 
		tag('STMTTRN',
			  tag('TRNTYPE', t.amount > 0 ? 'CREDIT' : 'DEBIT')
			+ tag('DTPOSTED', formatDateForOFX(t.date))
			+ tag('TRNAMT', t.amount)
			+ tag('FITID', t.reference)
			+ tag('NAME', t.description)
			+ (t.memo ? tag('MEMO', t.memo) : '')
			+ (t.origcurrency ? tag('ORIGCURRENCY', tag('CURRATE', t.origcurrency.rate) + tag('CURSYM', t.origcurrency.symbol)) : '')
		) + '\n';
	return result;
}

var csvStatementFormatter = function() {
	var CSV = "date,refnumber,description,credit,debit,foreign currency,foreign amount, FX rate\n";
	for (i = 0; i < statement.transactions.length; i++) {
		var t = statement.transactions[i];
		CSV += formatDateForCSV(t.date) + ',' + t.reference + ',"' + t.description + '",' + (t.amount > 0 ? t.amount : '') + ',' + (t.amount < 0 ? -t.amount : '');
		if (t.origcurrency) {
			CSV += ', ' + t.origcurrency.symbol + ', ' + t.origcurrency.amount + ', ' + t.origcurrency.rate;
		}
		CSV += '\n';
	}
	return CSV;
}

function tag(name, body) {
	return '<' + name + '>' + body + '</' + name + '>';
}


// trim whitespace at the beginning, end and multiple occurences in the middle
function trimString(str) 
{
	str = str.replace(new RegExp(/^\s+/),""); // START WHITESPACES
	str = str.replace(new RegExp(/\s+$/),""); // END WHITESPACES
	str = str.replace(new RegExp(/\s+\s+/g)," "); // MIDDLE MULTIPLE WHITESPACES
	return str;
}

function prettyPrint(t) {
	var result = 'Transaction[';
	for (var prop in t) {
		result += prop + ': ' + t[prop] + ', ';
	}
	result += ']';
	return result;
}

function formatDateForCSV(d) {
	var result = d.toLocaleFormat('%d/%m/%Y');
	return result;
}

function formatDateForOFX(d) {
	if (d == null) return null;
	var result = d.toLocaleFormat('%Y%m%d%H%M%S');
	return result;
}

function parseAmount(element) {
	var text = element.textContent;
	if (text == null) return null;
	var matches = text.match(new RegExp(/\d*\.\d*/));
	if (matches == null) return null;
	text = matches[0];
	var value = parseFloat(text);
	value = value ? value : 0;
	return value;
}

init();