Skip to content

Instantly share code, notes, and snippets.

@xkikeg
Last active September 21, 2021 09:26
Show Gist options
  • Save xkikeg/0a759db9607e005096c625ded2174deb to your computer and use it in GitHub Desktop.
Save xkikeg/0a759db9607e005096c625ded2174deb to your computer and use it in GitHub Desktop.
Greasemonkey script to convert wise.com account to https://github.com/ledger/ledger/ format file.
// ==UserScript==
// @name Wise.com to ledger
// @version 1
// @grant GM.setClipboard
// @require https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js
// @require https://gist.github.com/raw/2625891/waitForKeyElements.js
// @match https://wise.com/user/account/*
// ==/UserScript==
function getPayee(node) {
return node.parents('.css-1t84jn').find('h5.css-7fnyde').text();
}
function handleDetailsView(node) {
var r= $('<input type="button" value="new button"/>');
node.prepend(r);
r.on('click', function() {
let typeText = node.find('.css-1d1duka h5').last().text();
var result;
if (typeText == 'お客様の銀行口座情報') {
result = runTransfer(node);
} else if (typeText == '支払い方法') {
result = runDebit(node);
} else if (typeText == '取引詳細') {
result = runExchange(node);
}
if (result) {
GM.setClipboard(result);
}
});
}
function runExchange(node) {
var code;
var srcCurrency;
var srcAmount;
var comission;
var rate;
var dstCurrency;
var dstAmount;
node.find('.css-1d1duka').each(function(i, detail) {
$(detail).find('dl').css('background-color', 'yellow');
$(detail).find('dt').each(function(i, dt) {
let dttext = $(dt).text();
let ddtext = $(dt).next().text();
if (dttext == '受取額') {
srcCurrency = getCurrency(ddtext);
srcAmount = prettyAmount(ddtext);
} else if (dttext == '当社の手数料') {
comission = prettyAmount(ddtext);
} else if (dttext == '為替レート') {
rate = ddtext;
} else if (dttext == '両替された通貨') {
dstCurrency = getCurrency(ddtext);
dstAmount = prettyAmount(ddtext);
} else if (dttext == '取引番号') {
code = ddtext;
}
});
});
return [
'',
'* (' + code + ') Wise.com',
' Assets:Wire:Wise -' + srcAmount,
' Expenses:Commissions ' + comission,
' Assets:Wire:Wise ' + dstAmount + ' @ (1/' + rate + ' ' + srcCurrency + ')',
].join('\n');
}
function runTransfer(node) {
var code;
var iban;
var swift;
var srcCurrency;
var srcAmount;
var comission;
var rate;
var dstCurrency;
var dstAmount;
let payee = getPayee(node).replace(/^受取人: /, '');
node.find('.css-1d1duka').each(function(i, detail) {
$(detail).find('dl').css('background-color', 'blue');
$(detail).find('dt').each(function(i, dt) {
let dttext = $(dt).text();
let ddtext = $(dt).next().text();
if (dttext == 'IBAN') {
iban = ddtext;
} else if (dttext == 'Bank code (BIC/SWIFT)') {
swift = ddtext;
} else if (dttext == '送金額:') {
srcCurrency = getCurrency(ddtext);
srcAmount = prettyAmount(ddtext);
} else if (dttext == '当社の手数料') {
comission = prettyAmount(ddtext);
} else if (dttext == '為替レート') {
rate = ddtext;
} else if (dttext == '受取額') {
dstCurrency = getCurrency(ddtext);
dstAmount = prettyAmount(ddtext);
} else if (dttext == '取引番号') {
code = ddtext;
}
});
});
return [
'',
'* (' + code + ') ' + payee,
' Assets:Wire:Wise -' + srcAmount,
' Expenses:Commissions ' + comission + ' ; Payee: Wise.com',
' Assets:Wire:BCGE ' + dstAmount + ' @ (1/' + rate + ' ' + srcCurrency + ')',
].join('\n');
}
class Post {
constructor(account, amount, converted=null) {
this.account = account;
this.amount = amount;
this.converted = converted;
}
print() {
var res = " " + this.account + " " + this.amount;
if (this.converted != null) {
res += " @@ " + this.converted;
}
return res;
}
}
function runDebit(node) {
var date;
var code;
var posts = [];
var comments = [];
let payee = getPayee(node).replace(/^場所: /, '');
node.find('.css-1d1duka').each(function(i, detail) {
$(detail).find('dl').each(function(i, dl) {
$(dl).css('background-color', 'red');
var amount = null;
var commission = null;
var converted = null;
$(dl).find('dt').each(function(i, dt) {
let dttext = $(dt).text();
let ddtext = $(dt).next().text();
if (dttext == "取引日") {
let match = /(\d+)年(\d+)月(\d+)日/.exec(ddtext);
if (match) {
var m = match[2];
var d = match[3];
if (m.length == 1) {
m = '0' + m;
}
if (d.length == 1) {
d = '0' + d;
}
date = match[1] + '/' + m + '/' + d;
} else {
console.warning('unexpected date format: ' + ddtext);
}
} else if (dttext == '取引場所') {
comments.push('place: ' + ddtext);
} else if (dttext == '支払額') {
posts.push(new Post('Expenses:???', prettyAmount(ddtext)));
} else if (dttext == '支払い額') {
amount = prettyAmount(ddtext);
} else if (dttext == '当社の手数料') {
commission = prettyAmount(ddtext);
} else if (dttext == '両替された通貨') {
converted = prettyAmount(ddtext);
} else if (dttext == '為替レート') {
comments.push('rate: ' + ddtext);
}
});
if (amount != null) {
if (commission == null) {
posts.push(new Post('Assets:Banks:Wise', '-'+amount));
} else {
posts.push(new Post('Assets:Banks:Wise', '-'+amount));
posts.push(new Post('Expenses:Commissions', commission));
}
}
});
let codeBox = $(detail).find('dl + span');
if (codeBox && codeBox.length >= 1) {
code = codeBox.text().replace(/^取引番号 /, '');
}
});
var lines = ['', date + ' * (' + code + ') ' + payee];
posts.forEach(post => lines.push(post.print()));
comments.forEach(comment => lines.push(' ; ' + comment));
lines.push('');
return lines.join('\n');
}
function getCurrency(x) {
let match = /[0-9,]+(?:\.[0-9]+)? ([A-Z]+)/.exec(x);
return match[1];
}
function prettyAmount(x) {
let match = /([0-9,]+)(\.[0-9]+)? ([A-Z]+)/.exec(x);
if (match[3] == "JPY") {
return x;
}
if (match[2]) {
return x;
}
return match[1]+ ".00 " + match[3];
}
window.addEventListener('load', init, false);
function init() {
waitForKeyElements("#activity-details-view-panel-0", handleDetailsView);
waitForKeyElements("#activity-details-view-panel-1", handleDetailsView);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment