// ==UserScript==
// @name AliExpress Orders to CSV
// @description With exchange rate support, first product image and properties extraction
// @icon https://ae01.alicdn.com/images/eng/wholesale/icon/aliexpress.ico
// @match https://trade.aliexpress.ru/orderList.htm*
// @grant unsafeWindow
// @grant GM_xmlhttpRequest
// @grant GM_setClipboard
// @grant GM_download
// @require https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js
// @run-at document-idle
// @version 1.2
// ==/UserScript==
// TODO: add Sheets API to create a new Sheet automatically (with merged cells)
// Configuration
const trackingBaseUrl = "https://global.cainiao.com/detail.htm?mailNoList="
var exchangeRate = 1.0;
var comaFormat = true; // prices with comas instead of dots
var pictureRes = "100" // up to 400x400
var htmlContent = '<div class="grid-col-container">' +
' <div class="me-ui-box">' +
' <form method="post">' +
' <div class="order-list-search">' +
' <div id="simple-search">' +
' <label class="first-label">' +
' <span>Exchange rate: </span>' +
' <input min="0" value="' + exchangeRate + '" type="number" step="any" id="exchange-rate">' +
' </label>' +
' <label>' +
' <span>Coma decimal separator: </span>' +
' <input type="checkbox" id="coma-sep" ' + (comaFormat ? "checked " : "") + 'style="width: auto;">' +
' </label>' +
' <label>' +
' <span>Image resolution: </span>' +
' <input min="0" max="400" value="' + pictureRes + '" type="number" step="50" id="resolution">' +
' </label>' +
' <button id="generate-btn" class="ui-button ui-button-primary search-btn" type="button">Generate CSV</button>' +
' </div>' +
' </div>' +
' </form>' +
' </div>' +
'</div>';
var $ = window.jQuery;
var data = [];
function fetchOrderDetails(id) {
var price = 0.;
let trackingNum = '';
var orderDetailBaseUrl = "https://trade.aliexpress.ru/order_detail.htm?orderId=" + id;
$.ajax({
url: orderDetailBaseUrl,
type: 'get',
dataType: 'html',
async: false,
success: function(data) {
price = $(data).find("td.pay-c1").first().text().trim().substring(5);
trackingNum = $(data).find(".logistics-num").first().text().trim();
}
});
return [parseFloat(price)/exchangeRate, trackingNum];
}
function fetchOrders() {
$(".order-item-wraper").each(async (ind, el) => {
// each order
let num = 0;
let order = {
id: $(el).find(".order-info .first-row .info-body ").text().trim(),
orderDate: new Date($(el).find(".order-info .second-row .info-body").text().trim()).toLocaleDateString(),
sellerName: $(el).find(".store-info .first-row .info-body").text().trim()
};
$(el).find(".product-sets").each((i, e) => {
// each product
let row;
if(num==0) {
row = JSON.parse(JSON.stringify(order));
} else {
row = new Array(7);
}
row.productNum = num++;
row.productTitle = $(e).find(".product-title").text().trim();
row.priceAndQty = $(e).find(".product-amount").text().trim().replace(/\s\s+/g, ' ');
row.productProps = $(e).find(".product-property").text().trim().replace(/\s\s+/g, ' ').substring(20);
row.picture = $(e).find("img").attr('src').slice(0, -9) + pictureRes + "x" + pictureRes + ".jpg";
row.url = $(e).find(".product-title a").attr('href');
data.push(row);
});
});
}
function generateCsv() {
var s = "";
fetchOrders();
Promise.all(data).then(() => {
data.forEach(e => {
// product data
if (e.productNum == 0) {
s += e.orderDate + "\t";
} else {
s += '\t';
}
s += '=HYPERLINK("https:' + e.url + '"; "' + e.productTitle + '")\t';
s += e.productProps + "\t";
s += '=IMAGE("' + e.picture + '")\t';
s += e.priceAndQty + "\t";
// order data
if (e.productNum == 0) {
let detailData = fetchOrderDetails(e.id);
s += e.id + "\t";
s += (comaFormat ? detailData[0].toFixed(2).replace(".", ",") : detailData[0]) + "\t";
s += e.sellerName + "\t";
s += '=HYPERLINK("' + trackingBaseUrl + detailData[1] + '"; "' + detailData[1] + '")\t';
} else {
s += "\t";
s += "\t";
s += '\t';
s += '\t';
}
s += "\n";
});
GM_setClipboard(s);
$("#generate-btn").text("Copied!");
});
}
function updateConfig() {
exchangeRate = $("#exchange-rate").val();
comaFormat = $("#coma-sep").is(":checked");
pictureRes = $("#resolution").val();
}
function onClickGenerate() {
updateConfig();
generateCsv();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
$("#appeal-alert").after($(htmlContent));
$("#generate-btn").click(onClickGenerate);
$('#simple-pager-page-size').append(new Option('1000/page', 1000));