'
diff --git a/static/js/pos.js b/static/js/pos.js
index e7cb3cf..a6214d7 100644
--- a/static/js/pos.js
+++ b/static/js/pos.js
@@ -4,121 +4,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-function addItem(name, code, price) {
- if ($(".list-group-item[data-code='" + code + "']").length) {
- updateQty($(".list-group-item[data-code='" + code + "']").find(".qty-plus"), 1);
- return;
- }
- price = (price * 1.0).toFixed(2);
- $("#pos-lines-box").append('
'
- + '
'
- + '
'
- + name
- + '
'
- + ''
- + '' + code + ''
- + ''
- + '$'
- + price
- + ''
- + ''
- + '
'
- + ''
- + '
'
- + '
');
- recalculate();
-}
-
-function findItem(q) {
- function decodeThenAddItem(item) {
- var code = item.code1;
- console.log(code);
- if (code == "" && item["code2"] != "") {
- code = item["code2"];
- } else if (code == "") {
- code = "---";
- }
- var price = item['price'];
- if (price == null || price == "" || price == 0) {
- if (!$(".list-group-item[data-code='" + code + "']").length) {
- bsprompt("Enter Price",
- "No price set. Enter a price for this item:",
- "Add Item",
- "Cancel",
- "number",
- function (result) {
- addItem(item['name'], code, result);
- });
- return;
- }
- }
- addItem(item['name'], code, price);
- }
- if (q == "") {
- return;
- }
- $.get("action.php", {
- action: "itemsearch",
- q: q
- }, function (data) {
- if (data['items'].length == 1) {
- decodeThenAddItem(data['items'][0]);
- } else if (data['items'].length > 1) {
- var options = [];
- for (var i = 0; i < data['items'].length; i++) {
- var text = data['items'][i]['name'];
- if (data['items'][i]['price'] != null) {
- text += "
$" + data['items'][i]['price'] + "";
- }
- options.push({"text": text, "val": data['items'][i]['id']});
- }
- bschoices(
- "Multiple Results",
- "More than one item match the query. Pick the correct one:",
- options,
- "Cancel",
- function (result) {
- for (var i = 0; i < data['items'].length; i++) {
- if (data['items'][i]['id'] == result) {
- decodeThenAddItem(data['items'][i]);
- break;
- }
- }
- }
- );
- }
- }).fail(function () {
- alert("Error");
- });
-}
-
-function removezero() {
- $("#pos-lines-box .list-group-item").each(function () {
- var qty = $(".item-qty", this).val() * 1.0;
- if (qty == 0) {
- $(this).remove();
- }
- });
-}
-
function recalculate() {
removezero();
var total = 0.0;
+ var paid = 0.0;
+ var remaining = 0.0;
+ var change = 0.0;
$("#pos-lines-box .list-group-item").each(function () {
var each = $(".item-price", this).val() * 1.0;
var qty = $(".item-qty", this).val() * 1.0;
@@ -128,56 +19,34 @@ function recalculate() {
console.log(each.toFixed(2));
total += line;
});
- $(".grand-total").text(total.toFixed(2));
-}
-function updateQty(btn, diff) {
- var qtybox = $(btn).parent().parent().find(".item-qty");
- var qty = parseInt(qtybox.val());
- qty += diff;
- if (qty > 0) {
- qtybox.val(qty);
- var minbtn = $(btn).parent().parent().find(".qty-minus");
- if (qty == 1) {
- minbtn.html("
");
- } else {
- minbtn.html("
");
- }
+ $("#payment-lines .list-group-item").each(function () {
+ var line = $(".payment-entry", this).val() * 1.0;
+ paid += line;
+ });
+
+ remaining = total - paid;
+ change = (total - paid) * -1.0;
+ if (remaining <= 0) {
+ remaining = 0.0;
+ $("#owed-amount").parent().removeClass("font-weight-bold");
} else {
- qtybox.closest(".list-group-item").remove();
+ $("#owed-amount").parent().addClass("font-weight-bold");
}
- recalculate();
-}
-
-$("#pos-lines-box").on("click", ".qty-minus", function () {
- updateQty(this, -1);
-});
-
-$("#pos-lines-box").on("click", ".qty-plus", function () {
- updateQty(this, 1);
-});
-
-$("#pos-lines-box").on("change", ".item-qty,.item-price", function () {
- recalculate();
-});
-$("#pos-lines-box").on("keypress", ".item-qty,.item-price", function (e) {
- if (e.which === 13) {
- recalculate();
+ if (change <= 0) {
+ change = 0.0;
+ $("#change-amount").parent().removeClass("font-weight-bold");
+ } else {
+ $("#change-amount").parent().addClass("font-weight-bold");
}
-});
-$("#barcode").on('keypress', function (e) {
- if (e.which === 13) {
- findItem($("#barcode").val());
- $("#barcode").val("");
- }
-});
+ $("#grand-total").text(total.toFixed(2));
+ $("#paid-amount").text(paid.toFixed(2));
+ $("#owed-amount").text(remaining.toFixed(2));
+ $("#change-amount").text(change.toFixed(2));
+}
-$("#barcodebtn").on("click", function () {
- findItem($("#barcode").val());
- $("#barcode").val("");
-});
$("body").on("keypress", "input[type=money],input[type=number]", function (e) {
//console.log(String.fromCharCode(e.which) + "|" + e.which);
@@ -193,4 +62,7 @@ $("body").on("keypress", "input[type=money],input[type=number]", function (e) {
}
});
-$("#barcode").focus();
\ No newline at end of file
+// Make sure the session doesn't expire
+setInterval(function () {
+ $.get("action.php", {action: "session_keepalive"});
+}, 1000 * 60);
\ No newline at end of file
diff --git a/static/js/pos_finish.js b/static/js/pos_finish.js
new file mode 100644
index 0000000..49d8ca0
--- /dev/null
+++ b/static/js/pos_finish.js
@@ -0,0 +1,82 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+function sendTransactionToServer(callback) {
+ var items = [];
+ var payments = [];
+ var customer = '';
+ var register = '';
+ $("#pos-lines-box .list-group-item").each(function () {
+ var each = $(".item-price", this).val() * 1.0;
+ var qty = $(".item-qty", this).val() * 1.0;
+ var code = $(this).data("code");
+ var id = $(this).data("itemid");
+ items.push({
+ each: each,
+ qty: qty,
+ code: code,
+ id: id
+ });
+ });
+ $("#payment-lines .list-group-item").each(function () {
+ var amount = $(".payment-entry", this).val() * 1.0;
+ var type = $(".payment-entry", this).data("type");
+ var code = '';
+ if ($(".giftcard-number", this).length) {
+ code = $(".giftcard-number", this).val();
+ }
+ payments.push({
+ amount: amount,
+ type: type,
+ code: code
+ });
+ });
+
+ $.post("action.php", {
+ action: "finish_transaction",
+ items: items,
+ payments: payments,
+ customer: customer,
+ register: register
+ }, function (data) {
+ if (data.status == "OK") {
+ callback(data);
+ } else {
+ bsalert("Error", "The transaction could not be completed:
" + data.message);
+ }
+ }).fail(function () {
+ bsalert("Error", "The transaction could not be completed due to an unknown error.");
+ });
+}
+
+function showReceipt(txid) {
+ $("#receiptframe").attr("src", 'action.php?action=getreceipt&txid=' + txid);
+ $("#receiptmodal").modal();
+}
+
+function finishTransaction() {
+ sendTransactionToServer(function (data) {
+ showReceipt(data.txid);
+ });
+}
+
+$("#finishbtn").click(function () {
+ recalculate();
+ var owed = $("#owed-amount").text() * 1.0;
+ if (owed > 0) {
+ bsalert("Incomplete Transaction", "The customer still owes $" + owed.toFixed(2) + ". Add a payment or remove items until everything is paid for.");
+ } else {
+ finishTransaction();
+ }
+});
+
+$("#receiptprintbtn").click(function () {
+ document.getElementById("receiptframe").contentWindow.print();
+})
+
+$("#receiptmodal").on("hide.bs.modal", function () {
+ window.location.reload();
+});
\ No newline at end of file
diff --git a/static/js/pos_items.js b/static/js/pos_items.js
new file mode 100644
index 0000000..b7ffed5
--- /dev/null
+++ b/static/js/pos_items.js
@@ -0,0 +1,167 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+function addItem(name, code, price, id) {
+ if ($(".list-group-item[data-code='" + code + "']").length) {
+ updateQty($(".list-group-item[data-code='" + code + "']").find(".qty-plus"), 1);
+ return;
+ }
+ price = (price * 1.0).toFixed(2);
+ $("#pos-lines-box").append('
'
+ + '
'
+ + '
'
+ + name
+ + '
'
+ + ''
+ + '' + code + ''
+ + ''
+ + '$'
+ + price
+ + ''
+ + ''
+ + '
'
+ + ''
+ + '
'
+ + '
');
+ recalculate();
+}
+
+function findItem(q) {
+ function decodeThenAddItem(item) {
+ var code = item.code1;
+ console.log(code);
+ if (code == "" && item["code2"] != "") {
+ code = item["code2"];
+ } else if (code == "") {
+ code = "---";
+ }
+ var price = item['price'];
+ if (price == null || price == "" || price == 0) {
+ if (!$(".list-group-item[data-code='" + code + "']").length) {
+ bsprompt("Enter Price",
+ "No price set. Enter a price for this item:",
+ "Add Item",
+ "Cancel",
+ "number",
+ function (result) {
+ addItem(item['name'], code, result, item['id']);
+ });
+ return;
+ }
+ }
+ addItem(item['name'], code, price, item['id']);
+ }
+ if (q == "") {
+ return;
+ }
+ $.get("action.php", {
+ action: "itemsearch",
+ q: q
+ }, function (data) {
+ if (data['items'].length == 1) {
+ decodeThenAddItem(data['items'][0]);
+ } else if (data['items'].length > 1) {
+ var options = [];
+ for (var i = 0; i < data['items'].length; i++) {
+ var text = data['items'][i]['name'];
+ if (data['items'][i]['price'] != null) {
+ text += "
$" + data['items'][i]['price'] + "";
+ }
+ options.push({"text": text, "val": data['items'][i]['id']});
+ }
+ bschoices(
+ "Multiple Results",
+ "More than one item match the query. Pick the correct one:",
+ options,
+ "Cancel",
+ function (result) {
+ for (var i = 0; i < data['items'].length; i++) {
+ if (data['items'][i]['id'] == result) {
+ decodeThenAddItem(data['items'][i]);
+ break;
+ }
+ }
+ }
+ );
+ }
+ }).fail(function () {
+ alert("Error");
+ });
+}
+
+function removezero() {
+ $("#pos-lines-box .list-group-item").each(function () {
+ var qty = $(".item-qty", this).val() * 1.0;
+ if (qty == 0) {
+ $(this).remove();
+ }
+ });
+}
+
+function updateQty(btn, diff) {
+ var qtybox = $(btn).parent().parent().find(".item-qty");
+ var qty = parseInt(qtybox.val());
+ qty += diff;
+ if (qty > 0) {
+ qtybox.val(qty);
+ var minbtn = $(btn).parent().parent().find(".qty-minus");
+ if (qty == 1) {
+ minbtn.html("
");
+ } else {
+ minbtn.html("
");
+ }
+ } else {
+ qtybox.closest(".list-group-item").remove();
+ }
+ recalculate();
+}
+
+$("#pos-lines-box").on("click", ".qty-minus", function () {
+ updateQty(this, -1);
+});
+
+$("#pos-lines-box").on("click", ".qty-plus", function () {
+ updateQty(this, 1);
+});
+
+$("#pos-lines-box").on("change blur", ".item-qty,.item-price", function () {
+ recalculate();
+});
+
+$("#pos-lines-box").on("keypress", ".item-qty,.item-price", function (e) {
+ if (e.which === 13) {
+ recalculate();
+ }
+});
+
+$("#barcode").on('keypress', function (e) {
+ if (e.which === 13) {
+ findItem($("#barcode").val());
+ $("#barcode").val("");
+ }
+});
+
+$("#barcodebtn").on("click", function () {
+ findItem($("#barcode").val());
+ $("#barcode").val("");
+});
+
+$("#barcode").focus();
\ No newline at end of file
diff --git a/static/js/pos_payment.js b/static/js/pos_payment.js
new file mode 100644
index 0000000..496b920
--- /dev/null
+++ b/static/js/pos_payment.js
@@ -0,0 +1,111 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+function addPayment(type, icon, text) {
+ var extrafield = "";
+ if (type == "giftcard") {
+ extrafield = ''
+ + '
'
+ + ' '
+ + ' #'
+ + ' '
+ + '
'
+ + '
';
+ }
+ var amount = "";
+ // Autofill the exact due amount for payment methods that are flexible like that
+ if (type == "check" || type == "card" || type == "crypto") {
+ if ($("#owed-amount").text() * 1.0 > 0) {
+ amount = ($("#owed-amount").text() * 1.0).toFixed(2);
+ }
+ }
+ $("#payment-lines").append(''
+ + '
');
+ $("#payment-lines .payment-entry").last().focus();
+}
+
+function checkGiftCardBalance() {
+ $("#payment-lines .list-group-item:has(.giftcard-number)").each(function () {
+ var paymentbox = $(".payment-entry", this);
+ var cardnumberbox = $(".giftcard-number", this);
+ var amount = paymentbox.val() * 1.0;
+ var cardnumber = cardnumberbox.val();
+ if (cardnumber == "") {
+ return;
+ }
+ $.get("action.php", {
+ action: "giftcard_lookup",
+ code: cardnumber
+ }, function (json) {
+ if (json.status == "OK") {
+ if (json.cards.length == 0) {
+ bsalert("Invalid Gift Card", "Gift card #" + cardnumber + " does not exist. Remove it to finish the transaction.");
+ cardnumberbox.addClass('is-invalid');
+ } else if (json.cards.length == 1) {
+ if (json.cards[0].balance < amount) {
+ bsalert("Insufficient Gift Card Balance", "Gift card #" + cardnumber + " does not contain enough funds. The amount has been set to the full amount remaining on the card ($" + json.cards[0].balance + ").");
+ paymentbox.val(json.cards[0].balance);
+ }
+ cardnumberbox.removeClass('is-invalid');
+ } else {
+ bsalert("Invalid Gift Card", "Unable to determine which gift card #" + cardnumber + " is referring to. Remove it to finish the transaction.");
+ cardnumberbox.addClass('is-invalid');
+ }
+ } else {
+ bsalert("Invalid Gift Card", "Unable to determine which gift card #" + cardnumber + " is referring to. Remove it to finish the transaction.");
+ cardnumberbox.addClass('is-invalid');
+ }
+ });
+ });
+}
+
+$("#payment-lines").on("change keyup blur", ".payment-entry", function () {
+ recalculate();
+});
+
+$("#payment-lines").on("blur", ".giftcard-number,.payment-entry[data-type=giftcard]", function () {
+ checkGiftCardBalance();
+});
+
+$("#payment-lines").on("keypress", ".giftcard-number,.payment-entry[data-type=giftcard]", function (e) {
+ if (e.which === 13) {
+ checkGiftCardBalance();
+ }
+});
+
+$("#payment-lines").on("click", ".remove-payment-btn", function () {
+ $(this).closest(".list-group-item").remove();
+ recalculate();
+});
+
+$("#paymentbtn").click(function () {
+ $("#paymentui").removeClass("d-none");
+});
+
+$(".payment-method-button").click(function () {
+ addPayment($(this).data("payment-method"), $(this).data("icon"), $(this).data("text"));
+});
\ No newline at end of file