Mercari sales - Generating tax form
Posted: Tue Feb 09, 2021 6:25 am
Hey all, I feel this is pretty specific but in case it helps someone I'll link it here. So I sell quite a lot on Mercari, and my accountant has asked me to generate an excel spreadsheet with all of my sales data. Anyone who has used Mercari knows their UI is terrible, there's no way to download this data, and you essentially have to load each transaction separately which can take hours even if you have as few sales as me (<100).
To help with this, I created a quick simple script that will generate a table with all your sales (item name, ID, sales price, etc) in an Excel-pastable format. If you sell on Mercari, you may want to try it out if you are filing taxes.
Notes: I quickly whipped this up, it's not pretty but it does the job (for me at least). I'll clean it up and make it more useful (date searching, and some other features) when I have time. Also, will post to my GitHub to track it, but for now will just dump the code. This will probably work in Firefox as well, but only tested in Chrome.
Steps
Hope someone can find this useful If not, I needed it anyway haha
To help with this, I created a quick simple script that will generate a table with all your sales (item name, ID, sales price, etc) in an Excel-pastable format. If you sell on Mercari, you may want to try it out if you are filing taxes.
Notes: I quickly whipped this up, it's not pretty but it does the job (for me at least). I'll clean it up and make it more useful (date searching, and some other features) when I have time. Also, will post to my GitHub to track it, but for now will just dump the code. This will probably work in Firefox as well, but only tested in Chrome.
Steps
- Go to your sold items page (出品した商品)
- In the browser, open up the developer tools
- Click the console tab if it's not already open. If there are errors and warnings here, you can ignore them
- Paste the code below and hit "Enter"
- Open up Excel and "paste"
Code: Select all
class Mercari {
constructor() {
this.items = {};
this.finished = false;
this.page = $("body");
this.page_number = 1;
this.load_page();
}
static order = [
"商品",
"商品ID",
"商品金額",
"販売手数料",
"配送料",
"販売利益",
"購入日時"
];
load_page() {
if(!this.are_there_more_items()) {
console.log("Extraction complete - no more items on this page exist.");
this.all_items_loaded();
} else {
console.log("Extracting items on page " + this.page_number);
this.load_items_on_page();
}
return null;
}
are_there_more_items() {
return !this.page.find("li.mypage-item-not-found.bold").length;
}
load_items_on_page() {
var item_links = this.page.find("#mypage-tab-transaction-old li.js-mypage-item a.mypage-item-link.has-button");
var no_of_items = item_links.length;
var item_link, url, timestamp;
var that = this;
var items_on_this_page = {};
for(var i = 0; i < no_of_items; i++) {
item_link = item_links.eq(i);
url = item_link.attr("href");
timestamp = item_link.parent().data("timestamp");
$.get(url, (function(timestamp) {
return function(data) {
items_on_this_page[timestamp] = that.get_item_data($(data));
var loaded_items = Object.keys(items_on_this_page).length;
if(loaded_items == no_of_items) {
console.log("-> Loaded all items on this page");
that.items = $.extend(that.items, items_on_this_page);
that.get_next_page();
} else {
console.log("-> Loaded item #" + loaded_items + "/" + no_of_items);
}
};
})(timestamp));
}
}
get_next_page() {
this.page_number += 1;
var next_page_button = this.page.find("ul.mypage-history.pager li.pager-next.pager-cell a");
if(next_page_button.length) {
var that = this;
var href = next_page_button.first().attr("href");
console.log("Loading page " + this.page_number);
$.get(href, function(data) {
console.log("-> Page loaded");
that.page = $(data);
that.load_page();
});
} else {
console.log("Extraction process complete - no more pages");
this.all_items_loaded();
}
}
get_item_data(data) {
var item = {};
data.find("ul.transact-info-table > li").each(function(){
var that = $(this);
var header = that.find("span").first().text().trim();
var content = that.find("ul li");
var text;
switch(header) {
case "商品":
text = content.find("div.transact-info-item.bold").first().html().split("<br>")[0].trim();
break;
case "送料":
return;
case "販売手数料":
case "配送料":
case "販売利益":
text = +(Mercari.to_raw_num(content.first().text().trim()));
break;
case "購入日時":
case "商品ID":
text = content.first().text().trim();
break;
default:
console.log("Error " + header);
return;
}
item[header] = text;
});
item["商品金額"] = item["販売利益"] + item["配送料"] + item["販売手数料"];
var ordered_item = [];
for(var order_id in Mercari.order) {
ordered_item.push(item[Mercari.order[order_id]]);
}
return ordered_item;
}
static to_raw_num(price) {
price = price.replace("¥", "");
price = price.replace(/,/g, "");
return price;
}
all_items_loaded() {
if(this.finished) {
throw Error("Already finished!");
}
// Ensure this code only gets run once.
this.finished = true;
console.log(Object.keys(this.items).length + " items extracted.");
// Put each item into tab format
this.tab_items();
// reorder items
this.sort_items();
// copy to clipboard
Mercari.copy_to_clipboard(this.items.join("\r\n"));
console.log("Items copied to clipboard.");
}
tab_items() {
var tabbed_items = {};
for(var item_id in this.items) {
tabbed_items[item_id] = this.items[item_id].join("\t")
}
this.items = tabbed_items;
}
sort_items() {
var keys = Object.keys(this.items).sort();
var sorted_items = [];
for(const key of keys){
sorted_items.push(this.items[key]);
}
this.items = sorted_items;
}
static copy_to_clipboard(content) {
var $temp = $("<textarea>");
$("body").append($temp);
$temp.val(content).select();
document.execCommand("copy");
$temp.remove();
}
}
var mercari = new Mercari();