Skip to content

Commit 89bc547

Browse files
committed
v7.0: Add support for bulk orders
1 parent 7b74108 commit 89bc547

File tree

5 files changed

+176
-57
lines changed

5 files changed

+176
-57
lines changed

PrinterPiExtension/js/background.js

Lines changed: 86 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,45 +16,76 @@
1616
* You should have received a copy of the GNU General Public License
1717
* along with this program. If not, see <https://www.gnu.org/licenses/>.
1818
*/
19+
{
20+
let parseEbayRegular = () => {
21+
let address = document.querySelector("#shipToAddress").innerText;
22+
let shipping = document.querySelectorAll("._1nhS6BoY")[3].children[1].innerText;
23+
shipping = parseFloat(shipping.substring(shipping.indexOf("$")+1)); //Shipping as a float
24+
let grandTotal = document.querySelectorAll("._1nhS6BoY")[2].children[1].innerText; //Shipping+items+tax
25+
grandTotal = parseFloat(grandTotal.substring(grandTotal.indexOf("$")+1));
26+
let itemTotal = 0; //Total cost of items
27+
let items = document.querySelectorAll(".-CkHbnvR");
28+
let item_arr = [];
29+
for (let i=0; i<items.length; i++) { //Iterate through the items
30+
let itm = items[i].children[1];
31+
let price = itm.children[3].innerText;
32+
price = parseFloat(price.substring(price.indexOf("$")+1));
33+
itemTotal += price;
34+
item_arr.push({
35+
desc: itm.children[0].innerText,
36+
sku: itm.children[1].innerText.slice(5),
37+
qty: itm.children[2].innerText.slice(5),
38+
price: price
39+
});
40+
}
41+
return {
42+
to: address,
43+
shipping: shipping,
44+
subtotal: itemTotal,
45+
tax: grandTotal-(shipping+itemTotal),
46+
items: item_arr
47+
}
48+
}
1949

20-
try { //Try eBay
21-
let address = document.querySelector("#shipToAddress").innerText;
22-
let shipping = document.querySelectorAll("._1nhS6BoY")[3].children[1].innerText;
23-
shipping = parseFloat(shipping.substring(shipping.indexOf("$")+1)); //Shipping as a float
24-
let grandTotal = document.querySelectorAll("._1nhS6BoY")[2].children[1].innerText; //Shipping+items+tax
25-
grandTotal = parseFloat(grandTotal.substring(grandTotal.indexOf("$")+1));
26-
let itemTotal = 0; //Total cost of items
27-
let items = document.querySelectorAll(".-CkHbnvR");
28-
let item_arr = [];
29-
for (let i=0; i<items.length; i++) { //Iterate through the items
30-
let itm = items[i].children[1];
31-
let price = itm.children[3].innerText;
32-
price = parseFloat(price.substring(price.indexOf("$")+1));
33-
itemTotal += price;
34-
item_arr.push({
35-
desc: itm.children[0].innerText,
36-
sku: itm.children[1].innerText.slice(5),
37-
qty: itm.children[2].innerText.slice(5),
38-
price: price
50+
const parseEbayBulk = () => {
51+
let orders = [];
52+
document.querySelectorAll(".orders-list__item__details").forEach((order) => {
53+
let address = order.querySelector("address").innerText;
54+
let items = [];
55+
order.querySelectorAll(".item__description").forEach(item => {
56+
items.push({
57+
desc: item.children[0].innerText,
58+
sku: item.querySelector(".item__details").children[0].innerText.slice(5),
59+
qty: item.querySelector(".item__details").children[1].innerText.slice(5),
60+
price: parseFloat(item.querySelector(".item__details").children[2].innerText.slice(11))
61+
});
62+
});
63+
let shipping = order.querySelector(".buyer-paid-service").children[0].innerText.slice(1);
64+
65+
let itemTotal = items.length > 1 ? items.reduce((a, b) => (a .price|| a) + (b.price || b)) : items[0].price;
66+
67+
orders.push({
68+
to: address,
69+
shipping: shipping,
70+
subtotal: itemTotal,
71+
tax: 0, //No tax field available
72+
items: items
73+
})
3974
});
75+
if (orders.length == 0) {
76+
throw new Error("No orders found");
77+
}
78+
return orders;
4079
}
41-
chrome.runtime.sendMessage({ //Send the first data
42-
to: address,
43-
shipping: shipping,
44-
subtotal: itemTotal,
45-
tax: grandTotal-(shipping+itemTotal),
46-
items: item_arr
47-
});
48-
} catch (errA) {
49-
try { //Otherwise, try PayPal
5080

81+
let parsePayPalRegular = () => {
5182
//Get the items
5283
let transaction = document.querySelector("#td_purchaseDetailsSeller").parentElement; //The main transaction purchase details
5384
let items_arr = [];
5485
let items = document.querySelectorAll(".item");
5586
for (let i=1; i<items.length; i++) {
5687
try {
57-
console.log(items[i])
88+
console.log(items[i])
5889
let desc = items[i].children[0].children[0].innerText; //Description is first field
5990
let price = items[i].children[0].children[1].innerText; //Price is second field
6091
items_arr.push({
@@ -102,15 +133,36 @@
102133
let addr_block = document.querySelector("#td_sellerShipAddress").parentElement;
103134
let addr = addr_block.children[1].innerText + "\n" + addr_block.children[2].children[1].innerText; //Combine the name and address
104135

105-
chrome.runtime.sendMessage({
136+
return {
106137
to: addr,
107138
shipping: shipping,
108139
tax: tax,
109140
subtotal: total,
110141
items: items_arr
142+
}
143+
}
144+
console.log("[PrinterPi] Parsing data...");
145+
try { //Try eBay Regular
146+
let data = parseEbayRegular();
147+
chrome.runtime.sendMessage({
148+
orders: [data]
111149
});
112-
} catch (errB) {
113-
console.log("Error while trying to parse both eBay and PayPal pages. eBay:", errA, "PayPal:", errB);
114-
chrome.runtime.sendMessage({error: "Not a valid page to parse", errMsg: [errA, errB]});
150+
} catch (errA) {
151+
try { //Otherwise, try eBay Bulk
152+
let orders = parseEbayBulk();
153+
chrome.runtime.sendMessage({
154+
orders: orders
155+
});
156+
} catch (errB) { //Finally, try PayPal
157+
try {
158+
let data = parsePayPalRegular();
159+
chrome.runtime.sendMessage({
160+
orders: [data]
161+
});
162+
} catch (errC) {
163+
console.log("[PrinterPi] Error while trying to parse both all pages. eBay Regular:", errA, "eBay Bulk:", errB, "PayPal Regular:", errC);
164+
chrome.runtime.sendMessage({error: "Not a valid page to parse", errMsg: [errA, errB, errC]});
165+
}
166+
}
115167
}
116-
}
168+
}

PrinterPiExtension/js/main.js

Lines changed: 78 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@
6464
* @param {string} resError Response error (if any)
6565
*/
6666

67-
const VERSION_NO = 6.0; //Current version
67+
const VERSION_NO = 7.0; //Current version
68+
69+
let orders = []; //Orders received from background script
6870

6971
/*
7072
Data format to send to PrinterPi (NOTE: item descs and skus MUST NOT CONTAIN ~ and NO EXTRA SPACES ARE ALLOWED before/after parameters):
@@ -88,9 +90,11 @@ const VERSION_NO = 6.0; //Current version
8890
* @param {onFinish} onFinish On finish callback
8991
*/
9092
let readStorageData = (onFinish) => {
91-
chrome.storage.local.get(["data"], (res) => {
92-
if (res.data) {
93-
setData(res.data);
93+
chrome.storage.local.get(["orders"], (res) => {
94+
if (res.orders) {
95+
orders = res.orders;
96+
showOrders();
97+
selectOrder(0);
9498
document.getElementById("more-info").innerHTML = "Data read from storage";
9599
} else {
96100
document.getElementById("more-info").innerHTML = "No data in storage";
@@ -109,7 +113,7 @@ let readStorageData = (onFinish) => {
109113
*/
110114
let setStorageData = () => {
111115
if (validateInputs()) {
112-
chrome.storage.local.set({data: getData()}, () => {
116+
chrome.storage.local.set({orders: orders}, () => {
113117
document.getElementById("more-info").innerHTML = "Data saved";
114118
});
115119
}
@@ -329,6 +333,46 @@ let getData = () => { //Read the data from the HTML page
329333
return data;
330334
}
331335

336+
/**
337+
* Show a (global) order based on it's index
338+
*
339+
* @param {number} orderIndex
340+
*/
341+
let selectOrder = (orderIndex) => {
342+
console.log(orders);
343+
setData({
344+
to: orders[orderIndex]?.to || "",
345+
shipping: orders[orderIndex]?.shipping || "0",
346+
tax: orders[orderIndex]?.tax || "0",
347+
subtotal: orders[orderIndex]?.subtotal || "0",
348+
items: orders[orderIndex]?.items || [],
349+
});
350+
validateInputs();
351+
}
352+
353+
/**
354+
* Remove the current order (from global orders)
355+
*/
356+
const removeCurrentOrder = () => {
357+
orders.splice(document.getElementById("order-select").value, 1);
358+
showOrders();
359+
selectOrder(0);
360+
}
361+
362+
/**
363+
* Show the (global) orders in the select
364+
*/
365+
const showOrders = () => {
366+
document.getElementById('order-select').innerHTML = "";
367+
orders.forEach((_, i) => {
368+
let opt = document.createElement("OPTION");
369+
opt.value = i;
370+
opt.innerHTML = `Order ${i+1}`;
371+
opt.selected = i==0;
372+
document.getElementById('order-select').appendChild(opt);
373+
});
374+
}
375+
332376
/**
333377
* Get the complete data Packet
334378
*
@@ -456,12 +500,14 @@ let validateInputs = () => {
456500

457501
if (err_msg) { //Display any errors and disable the submit button
458502
document.getElementById("print-button").disabled = true;
503+
document.getElementById("print-all-button").disabled = true;
459504
let done_msg = document.getElementById("done-msg");
460505
done_msg.innerHTML = err_msg;
461506
done_msg.classList = "text-danger";
462507
return false;
463508
} else { //No errors - remove any lock on the submit button
464509
document.getElementById("print-button").disabled = false;
510+
document.getElementById("print-all-button").disabled = false;
465511
let done_msg = document.getElementById("done-msg");
466512
done_msg.innerHTML = "Not connected";
467513
done_msg.classList = "text-info";
@@ -552,14 +598,16 @@ let parseFile = (ev) => {
552598
if (data.version >= 6.0) { //Tax support added in version 6.0
553599
tax = data.tax
554600
}
555-
setData({ //Set the data packet
601+
orders = [];
602+
orders.push({ //Set the data packet
556603
to: data.to,
557604
shipping: data.shipping,
558605
tax: tax,
559606
subtotal: data.subtotal,
560607
items: data.items,
561608
});
562-
validateInputs();
609+
showOrders();
610+
selectOrder(0);
563611
document.getElementById("more-info").innerHTML = "Data loaded from file"; //Show the error message
564612
}
565613
reader.readAsText(files[0]);
@@ -574,6 +622,13 @@ window.onload = () => { //Add event listeners, etc.
574622
let pkt = getPacket(settings);
575623
if (pkt) sendData(pkt);
576624
});
625+
document.getElementById('print-all-button').addEventListener('click', () => { //Get the data packet and send it
626+
for (let orderIndex in orders) {
627+
selectOrder(orderIndex);
628+
let pkt = getPacket(settings);
629+
if (pkt) sendData(pkt);
630+
}
631+
});
577632
document.getElementById('envelope-button').addEventListener('click', () => { //Get the data packet and print it
578633
let pkt = getPacket(settings);
579634
if (pkt) printEnvelope(pkt);
@@ -590,6 +645,8 @@ window.onload = () => { //Add event listeners, etc.
590645
done_msg.innerHTML = "Please configure the printer settings in the Setting page (via the button PrinterPi Settings below)";
591646
done_msg.classList = "text-danger";
592647
});
648+
document.getElementById('order-select').addEventListener("change", (e) => selectOrder(e.target.value));
649+
document.getElementById('remove-button').addEventListener("click", removeCurrentOrder);
593650
document.getElementById('save-button').addEventListener('click', setStorageData);
594651
document.getElementById('parse-button').addEventListener('click', parsePage); //Execute the background parsing script
595652
document.getElementById('file-button').addEventListener('click', () => document.getElementById('file-dialog').click()); //Parse a file for the receipt
@@ -611,14 +668,18 @@ chrome.runtime.onMessage.addListener((msg) => { //Listen for messages and set th
611668
document.getElementById("more-info").innerHTML += ". Not a valid page to parse."; //Show the error message
612669
});
613670
document.getElementById('parse-button').disabled = true;
614-
} else {
615-
setData({ //Set the data packet
616-
to: msg.to,
617-
shipping: msg.shipping,
618-
tax: msg.tax,
619-
subtotal: msg.subtotal,
620-
items: msg.items,
621-
});
622-
validateInputs();
671+
} else if (msg.orders) {
672+
if (msg.orders.length >= 1) {
673+
setData({ //Set the data packet
674+
to: msg.orders[0].to,
675+
shipping: msg.orders[0].shipping,
676+
tax: msg.orders[0].tax,
677+
subtotal: msg.orders[0].subtotal,
678+
items: msg.orders[0].items,
679+
});
680+
orders = msg.orders;
681+
showOrders();
682+
validateInputs();
683+
}
623684
}
624-
});
685+
});

PrinterPiExtension/main.html

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@ <h5 class="text-center h5">
1616
</h5>
1717
<hr class="py-1 my-1">
1818
<h6 class="text-info text-center" id="more-info"></h6>
19-
<div class="px-5 py-1 row">
20-
<button class="btn btn-primary col mx-4" id='print-button'>Print Receipt</button>
19+
<div class="px-3 py-1 row">
20+
<button class="btn btn-primary col mx-2" id='print-button'>Print Receipt</button>
21+
<button class="btn btn-primary col mx-2" id='print-all-button'>Print All Receipts</button>
2122
</div>
22-
<div class="px-5 py-1 row">
23-
<button class="btn btn-sm btn-primary col mx-4" id='envelope-button'>Print Envelope</button>
23+
<div class="px-3 py-1 row">
24+
<button class="btn btn-sm btn-primary col mx-2" id='envelope-button'>Print Envelope</button>
2425
</div>
2526
<div class="px-3 pt-2 pb-1 row">
2627
<button class="btn btn-sm btn-warning col mx-2" id='parse-button'>Parse Page</button>
@@ -31,6 +32,11 @@ <h6 class="text-info text-center" id="more-info"></h6>
3132
</div>
3233
<input type="file" style="display: none" id="file-dialog" accept=".json" />
3334

35+
<hr class="py-1 my-1">
36+
<h5 class="text-center p-0 pt-1 m-0">Current Order</h5>
37+
<select class="form-control" id="order-select">
38+
</select>
39+
<button class="btn btn-sm btn-warning col mx-2" id='remove-button'>Remove order</button>
3440
<hr class="py-1 my-1">
3541
<h5 class="text-center p-0 pt-1 m-0">Address</h5>
3642
<textarea class="form-control h-100" rows="4" id="Address"></textarea>

PrinterPiExtension/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"manifest_version": 2,
33
"name": "PrinterPi",
4-
"version": "6.2",
4+
"version": "7.0",
55
"description": "Parse eBay Print Shipping Label or PayPal Activity pages and send the data to an application that controls a receipt printer",
66

77
"options_page": "options.html",

PrinterPiExtension/options.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<form class="container py-2" style="max-width: 450px" id="settings-form">
99
<h3 class="title text-center font-weight-bold">PrinterPi Settings</h2>
1010
<hr class="py-1 my-1">
11-
<h6 class="text-center text-muted">Version: 6.0</h6>
11+
<h6 class="text-center text-muted">Version: 7.0</h6>
1212
<hr class="py-1 my-1">
1313
<h6 class="text-center"><span id="info-msg">Loading...</span></h6>
1414
<hr class="py-1 my-1">

0 commit comments

Comments
 (0)