From aff3a068b1a51c3740cfdd73e9440e3cc9dec3c6 Mon Sep 17 00:00:00 2001 From: Skylar Ittner Date: Wed, 23 May 2018 18:52:15 -0600 Subject: [PATCH] Implement in-person transaction flow (close #7) --- action.php | 173 ++++++++++++++++++++++++++++++++++++ database.mwb | Bin 12821 -> 15150 bytes lang/en_us.php | 15 +++- pages.php | 6 ++ pages/pos.php | 63 +++++++++++++- required.php | 4 +- settings.template.php | 3 + static/css/app.css | 14 --- static/css/pos.css | 28 ++++++ static/js/bsalert.js | 43 +++++++++ static/js/pos.js | 184 ++++++--------------------------------- static/js/pos_finish.js | 82 +++++++++++++++++ static/js/pos_items.js | 167 +++++++++++++++++++++++++++++++++++ static/js/pos_payment.js | 111 +++++++++++++++++++++++ 14 files changed, 718 insertions(+), 175 deletions(-) create mode 100644 static/css/pos.css create mode 100644 static/js/pos_finish.js create mode 100644 static/js/pos_items.js create mode 100644 static/js/pos_payment.js diff --git a/action.php b/action.php index 0a4be2c..4e2f24b 100644 --- a/action.php +++ b/action.php @@ -8,6 +8,7 @@ * Make things happen when buttons are pressed and forms submitted. */ require_once __DIR__ . "/required.php"; +require_once __DIR__ . "/lib/userinfo.php"; if ($VARS['action'] !== "signout") { dieifnotloggedin(); @@ -30,6 +31,166 @@ function returnToSender($msg, $arg = "") { } switch ($VARS['action']) { + case "finish_transaction": + header("Content-Type: application/json"); + $items = $VARS['items']; + $payments = $VARS['payments']; + $customer = $VARS['customer']; + $register = $VARS['register']; + + if ($customer != "" && !$database->has('customers', ['customerid' => $customer])) { + exit(json_encode(["status" => "ERROR", "message" => lang("invalid customer", false)])); + // exit(json_encode(["status" => "ERROR", "message" => lang("", false)])); + } + if ($register != "" && !$database->has('registers', ['registerid' => $register])) { + exit(json_encode(["status" => "ERROR", "message" => lang("invalid register", false)])); + } + if ($register != "" && !$database->has('cash_drawer', ['AND' => ['registerid' => $register, 'close' => null]])) { + exit(json_encode(["status" => "ERROR", "message" => lang("cash not open", false)])); + } + + $totalcharge = 0.00; + $totalpaid = 0.00; + foreach ($items as $i) { + $totalcharge += $i['each'] * $i['qty']; + if (!$binstack->has('items', ['itemid' => $i['id']])) { + exit(json_encode(["status" => "ERROR", "message" => lang("invalid item", false)])); + } + } + foreach ($payments as $p) { + if (!$database->has('payment_types', ['typename' => $p['type']])) { + exit(json_encode(["status" => "ERROR", "message" => lang("invalid payment type", false)])); + } + $totalpaid += $p['amount']; + if ($p['type'] == "giftcard") { + if (!$database->has('certificates', ['AND' => ['amount[>=]' => $p['amount'], 'deleted[!]' => 1, 'certcode' => $p['code']]])) { + exit(json_encode(["status" => "ERROR", "message" => lang("invalid giftcard", false)])); + } + } + } + + if ($totalcharge > $totalpaid) { + exit(json_encode(["status" => "ERROR", "message" => lang("insufficient payment", false)])); + } + + $cashid = null; + if ($register != "") { + $cashid = $database->get('cash_drawer', 'cashid', ['AND' => ['registerid' => $register, 'close' => null]]); + } + + $database->insert('transactions', [ + 'txdate' => date('Y-m-d H:i:s'), + 'customerid' => ($customer != "" ? $customer : null), + 'type' => 1, + 'cashier' => $_SESSION['uid'], + 'cashid' => $cashid + ]); + $txid = $database->id(); + + foreach ($items as $i) { + $itemname = $binstack->get('items', 'name', ['itemid' => $i['id']]); + $database->insert('lines', [ + 'txid' => $txid, + 'amount' => $i['each'], + 'name' => $itemname, + 'itemid' => $i['id'], + 'qty' => $i['qty'] + ]); + } + + foreach ($payments as $p) { + $certid = null; + if ($p['type'] == "giftcard") { + $certid = $database->get('certificates', 'certid', ['certcode' => $p['code']]); + } + $type = $database->get('payment_types', 'typeid', ['typename' => $p['type']]); + $database->insert('payments', [ + 'amount' => $p['amount'], + 'data' => '', + 'type' => $type, + 'txid' => $txid, + 'certid' => $certid + ]); + } + + exit(json_encode(["status" => "OK", "txid" => $txid])); + + break; + case "getreceipt": + header("Content-Type: text/html"); + if (!$database->has('transactions', ['txid' => $VARS['txid']])) { + exit(json_encode(["status" => "ERROR", "txid" => null])); + } + + $tx = $database->get('transactions', ['txid', 'txdate', 'customerid', 'type', 'cashier'], ['txid' => $VARS['txid']]); + + $txid = $tx['txid']; + $datetime = date(DATETIME_FORMAT, strtotime($tx['txdate'])); + $type = $tx['type']; + $cashier = getUserByID($tx['cashier'])['name']; + $customerid = $tx['customerid']; + $customerline = (is_null($customerid) ? "" : "
Customer: $customerid"); + + $itemhtml = ""; + $items = $database->select('lines', ['amount', 'name', 'itemid', 'qty'], ['txid' => $txid]); + $total = 0.0; + foreach ($items as $i) { + $itemhtml .= "\n"; + $itemhtml .= '
'; + $itemhtml .= '
' . $i['name'] . '
'; + $itemhtml .= '
$' . $i['amount'] . '
'; + $itemhtml .= '
x' . $i['qty'] . '
'; + $itemhtml .= '
$' . ($i['qty'] * $i['amount']) . '
'; + $itemhtml .= '
'; + $total += ($i['qty'] * $i['amount']); + } + + $paymenthtml = ""; + $payments = $database->select('payments', [ + '[>]payment_types' => ['type' => 'typeid'] + ], [ + 'amount', 'type', 'typename', 'text' + ], [ + 'txid' => $txid + ]); + foreach ($payments as $p) { + $paymenthtml .= "\n"; + $paymenthtml .= '
'; + $paymenthtml .= '
' . lang($p['text'], false) . '
'; + $paymenthtml .= '
$' . $p['amount'] . '
'; + $paymenthtml .= '
'; + } + + + $html = << + + +Tx #$txid + +
+Date: $datetime
+Tx. ID: $txid
+Cashier: $cashier +$customerline +
+
+$itemhtml +
+
+
+$paymenthtml +
+
+Total: $$total +END; + exit($html); + break; case "itemsearch": header("Content-Type: application/json"); if (!is_empty($VARS['q'])) { @@ -52,6 +213,18 @@ switch ($VARS['action']) { ], $where); $items = (count($items) > 0 ? $items : false); exit(json_encode(["status" => "OK", "items" => $items])); + case "giftcard_lookup": + header("Content-Type: application/json"); + $code = $VARS['code']; + if (empty($code)) { + exit(json_encode(["status" => "ERROR", "cards" => []])); + } + $cards = $database->select('certificates', ['certid (id)', 'certcode (code)', 'amount (balance)', 'start_amount (amount)'], ['certcode' => $code]); + exit(json_encode(["status" => "OK", "cards" => $cards])); + break; + case "session_keepalive": + header("Content-Type: application/json"); + exit(json_encode(["status" => "OK"])); case "signout": session_destroy(); header('Location: index.php'); diff --git a/database.mwb b/database.mwb index 5d68632c7f6eefa00d95997c71711d04ebae5087..985c57c50fa0a45e180986ff1b47741ecd0ca6da 100644 GIT binary patch literal 15150 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�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 diff --git a/lang/en_us.php b/lang/en_us.php index b03d6dc..2ef708f 100644 --- a/lang/en_us.php +++ b/lang/en_us.php @@ -31,5 +31,18 @@ define("STRINGS", [ "home" => "Home", "point of sale" => "Point of Sale", "barcode" => "Barcode", - "barcode or search" => "Barcode or Search" + "barcode or search" => "Barcode or Search", + "cash" => "Cash", + "check" => "Check", + "card" => "Card", + "crypto" => "Crypto", + "gift card" => "Gift Card", + "free" => "Free", + "paid" => "Paid", + "owed" => "Owed", + "change" => "Change", + "enter payment" => "Enter Payment", + "receipt" => "Receipt", + "close" => "Close", + "print" => "Print", ]); \ No newline at end of file diff --git a/pages.php b/pages.php index 53a85e1..8cfa00d 100644 --- a/pages.php +++ b/pages.php @@ -15,8 +15,14 @@ define("PAGES", [ "title" => "point of sale", "navbar" => true, "icon" => "far fa-money-bill-alt", + "styles" => [ + "static/css/pos.css", + ], "scripts" => [ "static/js/bsalert.js", + "static/js/pos_items.js", + "static/js/pos_payment.js", + "static/js/pos_finish.js", "static/js/pos.js", ] ], diff --git a/pages/pos.php b/pages/pos.php index 2e2adc0..fb9a70e 100644 --- a/pages/pos.php +++ b/pages/pos.php @@ -5,6 +5,26 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ?> + +
@@ -20,7 +40,7 @@
-
+
@@ -29,7 +49,46 @@
-
$0.00
+
$0.00
+
+ +
+
+
+
+ select('payment_types', ['typeid (id)', 'typename (name)', 'icon', 'text']); + foreach ($payment_methods as $data) { + ?> +
+ + +
+ +
+
+
+
+
+ $ +
+
+ $0.00 +
+
+ $0.00 +
+
+
+ +
+ +
+ +
+
\ No newline at end of file diff --git a/required.php b/required.php index 144398d..e1585ba 100644 --- a/required.php +++ b/required.php @@ -39,7 +39,7 @@ if ($_SESSION['mobile'] === TRUE) { . "object-src 'none'; " . "img-src * data:; " . "media-src 'self'; " - . "frame-src 'none'; " + . "frame-src 'self'; " . "font-src 'self'; " . "connect-src *; " . "style-src 'self' 'unsafe-inline' $captcha_server; " @@ -50,7 +50,7 @@ if ($_SESSION['mobile'] === TRUE) { . "object-src 'none'; " . "img-src * data:; " . "media-src 'self'; " - . "frame-src 'none'; " + . "frame-src 'self'; " . "font-src 'self'; " . "connect-src *; " . "style-src 'self' 'nonce-$SECURE_NONCE' $captcha_server; " diff --git a/settings.template.php b/settings.template.php index e149500..3868736 100644 --- a/settings.template.php +++ b/settings.template.php @@ -40,6 +40,9 @@ define("PORTAL_KEY", "123"); // For supported values, see http://php.net/manual/en/timezones.php define("TIMEZONE", "America/Denver"); +define("DATETIME_FORMAT", "M j Y g:i A"); // 12 hour time +#define("DATETIME_FORMAT", "M j Y G:i"); // 24 hour time + // Base URL for site links. define('URL', '.'); diff --git a/static/css/app.css b/static/css/app.css index a887292..2f6f367 100644 --- a/static/css/app.css +++ b/static/css/app.css @@ -52,18 +52,4 @@ body { .footer { margin-top: 10em; text-align: center; -} - -input[type="number"]::-webkit-outer-spin-button, -input[type="number"]::-webkit-inner-spin-button { - -webkit-appearance: none; - margin: 0; -} -input[type="number"] { - -moz-appearance: textfield; -} - -#pos-lines-box { - max-height: calc(100vh - 200px); - overflow-y: scroll; } \ No newline at end of file diff --git a/static/css/pos.css b/static/css/pos.css new file mode 100644 index 0000000..bec682a --- /dev/null +++ b/static/css/pos.css @@ -0,0 +1,28 @@ +/* +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/. +*/ + +input[type="number"]::-webkit-outer-spin-button, +input[type="number"]::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} +input[type="number"] { + -moz-appearance: textfield; +} + +#pos-lines-box { + max-height: calc(100vh - 150px); + overflow-y: auto; +} + +.payment-method-button { + cursor: pointer; +} + +#receiptframe { + height: 50vh; + border: 0; +} \ No newline at end of file diff --git a/static/js/bsalert.js b/static/js/bsalert.js index ced2c14..1df3af3 100644 --- a/static/js/bsalert.js +++ b/static/js/bsalert.js @@ -4,6 +4,49 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +function bsalert(title, message, okbtn, cancelbtn, callback) { + var html = ''; + $("body").append(html); + $("#bsalert-title").text(title); + $("#bsalert-message").text(message); + if (typeof okbtn != "string") { + okbtn = "OK"; + } + $("#bsalert-ok").text(okbtn); + if (typeof cancelbtn != "string") { + cancelbtn = "Cancel"; + } + $("#bsalert-cancel").text(cancelbtn); + $("#bsalert-ok").on("click", function () { + if (typeof callback != 'undefined') { + callback(); + } + $("#bsalert").modal("hide"); + }); + $("#bsalert").on("hidden.bs.modal", function () { + $("#bsalert").remove(); + }); + $("#bsalert").modal("show"); +} + function bsprompt(title, message, okbtn, cancelbtn, type, callback) { var html = '