Je kunt niet meer dan 25 onderwerpen selecteren Onderwerpen moeten beginnen met een letter of nummer, kunnen streepjes bevatten ('-') en kunnen maximaal 35 tekens lang zijn.

682 regels
26 KiB
PHP

<?php
/* 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/. */
/**
* 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();
}
/**
* Redirects back to the page ID in $_POST/$_GET['source'] with the given message ID.
* The message will be displayed by the app.
* @param string $msg message ID (see lang/messages.php)
* @param string $arg If set, replaces "{arg}" in the message string when displayed to the user.
*/
function returnToSender($msg, $arg = "") {
global $VARS;
if ($arg == "") {
header("Location: app.php?page=" . urlencode($VARS['source']) . "&msg=" . $msg);
} else {
header("Location: app.php?page=" . urlencode($VARS['source']) . "&msg=$msg&arg=$arg");
}
die();
}
switch ($VARS['action']) {
case "finish_transaction":
header("Content-Type: application/json");
$error = null;
$oktx = null;
$database->action(function ($database) {
global $VARS, $binstack, $error, $oktx;
$items = $VARS['items'];
$payments = $VARS['payments'];
$customer = $VARS['customer'];
$register = $VARS['register'];
$discountpercent = $VARS['discountpercent'];
$cashid = null;
$editing = false;
if (isset($VARS['txid']) && $database->has('transactions', ['txid' => $VARS['txid']])) {
$editing = true;
$txid = $VARS['txid'];
$cashid = $database->get('transactions', 'cashid', ['txid' => $txid]);
if (!$database->has('cash_drawer', ['AND' => ['cashid' => $cashid, 'close' => null]])) {
$error = lang("cash already closed", false);
return false;
}
// Nuke the payments to make room for their replacements
// Delete payments
$oldpayments = $database->select('payments', ['payid', 'amount', 'type', 'certid'], ['txid' => $txid]);
foreach ($oldpayments as $p) {
// Reset gift card balances
if (!is_null($p['certid'])) {
$database->update('certificates', ['amount[+]' => $p['amount']], ['certid' => $p['certid']]);
}
$database->delete('payments', ['payid' => $p['payid']]);
}
}
if ($customer != "" && !$database->has('customers', ['customerid' => $customer])) {
$error = lang("invalid customer", false);
return false;
}
if ($register != "" && !$database->has('registers', ['registerid' => $register])) {
$error = lang("invalid register", false);
return false;
}
if ($register != "" && !$database->has('cash_drawer', ['AND' => ['registerid' => $register, 'close' => null]])) {
$error = lang("cash not open", false);
return false;
}
if ($register != "" && $editing === false) {
$cashid = $database->get('cash_drawer', 'cashid', ['AND' => ['registerid' => $register, 'close' => null]]);
}
$totalcharge = 0.00;
$totalpaid = 0.00;
$change = 0.0;
foreach ($items as $i) {
$totalcharge += $i['each'] * $i['qty'];
if (!$binstack->has('items', ['itemid' => $i['id']])) {
$error = lang("invalid item", false);
return false;
}
}
foreach ($payments as $p) {
if (!$database->has('payment_types', ['typename' => $p['type']])) {
$error = lang("invalid payment type", false);
return false;
}
$totalpaid += $p['amount'];
if ($p['type'] == "giftcard") {
if (!$database->has('certificates', ['AND' => ['amount[>=]' => $p['amount'], 'deleted[!]' => 1, 'certcode' => $p['code']]])) {
$error = lang("invalid giftcard", false);
return false;
}
}
}
if (is_numeric($discountpercent) && $discountpercent > 0 && $discountpercent < 100) {
$discountpercent = $discountpercent * 1.0;
$totalcharge *= 1.0 - ($discountpercent / 100.0);
} else {
$discountpercent = 0.0;
}
if ($totalcharge > $totalpaid) {
$error = lang("insufficient payment", false);
return false;
}
if ($editing === true) {
$database->update('transactions', [
'txdate' => date('Y-m-d H:i:s'),
'customerid' => ($customer != "" ? $customer : null),
'type' => 1,
'cashier' => $_SESSION['uid'],
'cashid' => $cashid,
'discountpercent' => $discountpercent
], [
'txid' => $txid
]);
} else {
$database->insert('transactions', [
'txdate' => date('Y-m-d H:i:s'),
'customerid' => ($customer != "" ? $customer : null),
'type' => 1,
'cashier' => $_SESSION['uid'],
'cashid' => $cashid,
'discountpercent' => $discountpercent
]);
$txid = $database->id();
}
$olditems = $database->select('lines', ['itemid (id)', 'qty', 'lineid'], ['txid' => $txid]);
foreach ($items as $i) {
$item = $binstack->get('items', ['name', 'qty'], ['itemid' => $i['id']]);
$database->insert('lines', [
'txid' => $txid,
'amount' => $i['each'],
'name' => $item['name'],
'itemid' => $i['id'],
'qty' => $i['qty']
]);
$binstack->update('items', [
'qty[-]' => $i['qty']
], [
'itemid' => $i['id']
]);
}
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
]);
}
if ($totalcharge < $totalpaid) {
$change = $totalpaid - $totalcharge;
$database->insert('payments', [
'amount' => $change * -1.0,
'data' => '',
'type' => 1,
'txid' => $txid,
'certid' => null
]);
}
foreach ($olditems as $i) {
$database->delete('lines', ['lineid' => $i['lineid']]);
$binstack->update('items', [
'qty[+]' => $i['qty']
], [
'itemid' => $i['id']
]);
}
$oktx = $txid;
return true;
});
if (!is_null($error)) {
exit(json_encode(["status" => "ERROR", "message" => $error]));
} else {
exit(json_encode(["status" => "OK", "txid" => $oktx]));
}
break;
case "finish_return":
header("Content-Type: application/json");
$error = null;
$oktx = null;
$database->action(function ($database) {
global $VARS, $binstack, $error, $oktx;
$items = $VARS['items'];
$payments = $VARS['payments'];
$customer = $VARS['customer'];
$register = $VARS['register'];
$cashid = null;
if ($customer != "" && !$database->has('customers', ['customerid' => $customer])) {
$error = lang("invalid customer", false);
return false;
}
if ($register != "" && !$database->has('registers', ['registerid' => $register])) {
$error = lang("invalid register", false);
return false;
}
if ($register != "" && !$database->has('cash_drawer', ['AND' => ['registerid' => $register, 'close' => null]])) {
$error = lang("cash not open", false);
return false;
}
if ($register != "") {
$cashid = $database->get('cash_drawer', 'cashid', ['AND' => ['registerid' => $register, 'close' => null]]);
}
$totaldue = 0.00;
$totalrefund = 0.00;
foreach ($items as $i) {
$totaldue += $i['each'] * $i['qty'];
if (!$binstack->has('items', ['itemid' => $i['id']])) {
$error = lang("invalid item", false);
return false;
}
}
foreach ($payments as $p) {
if (!$database->has('payment_types', ['typename' => $p['type']])) {
$error = lang("invalid payment type", false);
return false;
}
$totalrefund += $p['amount'];
if ($p['type'] == "giftcard") {
if (!$database->has('certificates', ['AND' => ['amount[>=]' => $p['amount'], 'deleted[!]' => 1, 'certcode' => $p['code']]])) {
$error = lang("invalid giftcard", false);
return false;
}
}
}
$database->insert('transactions', [
'txdate' => date('Y-m-d H:i:s'),
'customerid' => ($customer != "" ? $customer : null),
'type' => 2,
'cashier' => $_SESSION['uid'],
'cashid' => $cashid,
'discountpercent' => 0.0
]);
$txid = $database->id();
foreach ($items as $i) {
$item = $binstack->get('items', ['name', 'qty'], ['itemid' => $i['id']]);
$database->insert('lines', [
'txid' => $txid,
'amount' => $i['each'],
'name' => $item['name'],
'itemid' => $i['id'],
'qty' => $i['qty'] * -1.0
]);
}
foreach ($payments as $p) {
$certid = null;
if ($p['type'] == "giftcard") {
$certid = $database->get('certificates', 'certid', ['certcode' => $p['code']]);
$database->update('certificates', ['amount[+]' => $p['amount']], ['certid' => $certid]);
}
$type = $database->get('payment_types', 'typeid', ['typename' => $p['type']]);
$database->insert('payments', [
'amount' => $p['amount'] * -1.0,
'data' => '',
'type' => $type,
'txid' => $txid,
'certid' => $certid
]);
}
$oktx = $txid;
return true;
});
if (!is_null($error)) {
exit(json_encode(["status" => "ERROR", "message" => $error]));
} else {
exit(json_encode(["status" => "OK", "txid" => $oktx]));
}
break;
case "getreceipt":
require_once __DIR__ . "/lib/generatereceipt.php";
$format = "html";
$width = 64;
if (isset($VARS['width']) && preg_match("/[0-9]+/", $VARS['width']) && (int) $VARS['width'] > 0) {
$width = (int) $VARS['width'];
}
if (isset($VARS['format'])) {
$format = $VARS['format'];
}
if (!$database->has('transactions', ['txid' => $VARS['txid']])) {
header("Content-Type: application/json");
exit(json_encode(["status" => "ERROR", "txid" => null]));
}
$receipt = GenerateReceipt::getReceipt(GenerateReceipt::RECEIPT_TYPE_TRANSACTION, $VARS['txid']);
exit(GenerateReceipt::outputReceipt($receipt, $format, $width, "Tx. #" . $VARS['txid']));
break;
case "transactionsearch":
header("Content-Type: application/json");
if (!is_empty($VARS['q'])) {
$where["AND"]["OR"] = [
"txid" => $VARS['q'],
"name[~]" => $VARS['q'],
"email[~]" => $VARS['q'],
"phone[~]" => $VARS['q']
];
} else {
exit(json_encode(["status" => "ERROR", "transactions" => false]));
}
$where["LIMIT"] = 50;
$transactions = $database->select('transactions', [
'[>]customers' => 'customerid',
'[>]cash_drawer' => 'cashid',
'[>]registers' => ['cash_drawer.registerid' => 'registerid'],
], [
'txid',
'txdate',
'type',
'cashier (cashierid)',
'transactions.cashid',
'cash_drawer.registerid',
'registers.registername',
'cash_drawer.open',
'cash_drawer.close',
'customerid',
'customer' => [
'name',
'email',
'phone',
'address'
]], $where);
for ($i = 0; $i < count($transactions); $i++) {
if (is_null($transactions[$i]['close']) && !is_null($transactions[$i]['open'])) {
$transactions[$i]['editable'] = true;
} else {
$transactions[$i]['editable'] = false;
}
if (!is_null($transactions[$i]['cashierid'])) {
$cashier = getUserByID($transactions[$i]['cashierid']);
$transactions[$i]['cashier'] = [
"name" => $cashier['name'],
"username" => $cashier['username']
];
}
}
$transactions = (count($transactions) > 0 ? $transactions : false);
exit(json_encode(["status" => "OK", "transactions" => $transactions]));
case "itemsearch":
header("Content-Type: application/json");
if (!is_empty($VARS['q'])) {
$where["AND"]["OR"] = [
"name[~]" => $VARS['q'],
"code1[~]" => $VARS['q'],
"code2[~]" => $VARS['q']
];
} else {
exit(json_encode(["status" => "ERROR", "items" => false]));
}
$items = $binstack->select('items', [
'itemid (id)',
'name',
'code1',
'code2',
'cost',
'price'
], $where);
if (!empty($VARS['customer']) && $database->has('customers', ['customerid' => $VARS['customer']])) {
for ($n = 0; $n < count($items); $n++) {
$i = $items[$n];
if ($database->has('customer_pricing', ['AND' => ['itemid' => $i['id'], 'customerid' => $VARS['customer']]])) {
$items[$n]['price'] = $database->get('customer_pricing', 'price', ['AND' => ['itemid' => $i['id'], 'customerid' => $VARS['customer']]]);
}
}
}
$items = (count($items) > 0 ? $items : false);
exit(json_encode(["status" => "OK", "items" => $items]));
case "getgriditems":
header("Content-Type: application/json");
$items = $binstack->select('items', [
'itemid (id)', 'name', 'price', 'code1', 'code2'
], [
'AND' => ['price[!]' => null, 'price[!]' => 0]
]);
if (!empty($VARS['customer']) && $database->has('customers', ['customerid' => $VARS['customer']])) {
for ($n = 0; $n < count($items); $n++) {
$i = $items[$n];
if ($database->has('customer_pricing', ['AND' => ['itemid' => $i['id'], 'customerid' => $VARS['customer']]])) {
$items[$n]['price'] = $database->get('customer_pricing', 'price', ['AND' => ['itemid' => $i['id'], 'customerid' => $VARS['customer']]]);
}
}
}
for ($n = 0; $n < count($items); $n++) {
if ($items[$n]['code1'] != "") {
$items[$n]['code'] = $items[$n]["code1"];
} else if ($items[$n]['code1'] == "" && $items[$n]['code1'] != "") {
$items[$n]['code'] = $items[$n]["code2"];
} else if (code == "") {
$items[$n]['code'] = "---";
}
}
$items = (count($items) > 0 ? $items : false);
exit(json_encode(["status" => "OK", "items" => $items]));
case "customersearch":
header("Content-Type: application/json");
if (!is_empty($VARS['q'])) {
$where["AND"]["OR"] = [
"customerid" => $VARS['q'],
"name[~]" => $VARS['q'],
"email[~]" => $VARS['q'],
"phone[~]" => $VARS['q']
];
} else {
exit(json_encode(["status" => "ERROR", "customers" => false]));
}
$where["LIMIT"] = 10;
$customers = $database->select('customers', [
'customerid (id)',
'name',
'email',
'phone',
'address',
'notes'
], $where);
$customers = (count($customers) > 0 ? $customers : false);
exit(json_encode(["status" => "OK", "customers" => $customers]));
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 "editcustomer":
$insert = true;
if (is_empty($VARS['id'])) {
$insert = true;
} else {
if ($database->has('customers', ['customerid' => $VARS['id']])) {
$insert = false;
} else {
returnToSender("invalid_customerid");
}
}
if (is_empty($VARS['name'])) {
returnToSender('invalid_parameters');
}
$data = [
'name' => $VARS['name'],
'email' => $VARS['email'],
'phone' => $VARS['phone'],
'address' => $VARS['address'],
'notes' => $VARS['notes']
];
$customerid = null;
if ($insert) {
$database->insert('customers', $data);
$customerid = $database->id();
} else {
$database->update('customers', $data, ['customerid' => $VARS['id']]);
$customerid = $VARS['id'];
}
if (!is_null($customerid)) {
$custprices = $VARS['pricing'];
$newcustprices = [];
$oldcustprices = $database->select('customer_pricing', ['itemid (item)', 'price'], ['customerid' => $customerid]);
foreach ($custprices as $cp) {
if (!$binstack->has('items', ['itemid' => $cp['item']])) {
continue;
}
if (!is_numeric($cp['price'])) {
continue;
}
$newcustprices[] = $cp;
$oldcustprices = array_filter($oldcustprices, function ($var) {
if ($cp['item'] == $var['item']) {
return false;
}
return true;
});
}
foreach ($oldcustprices as $cp) {
$database->delete('customer_pricing', ['AND' => ['itemid' => $cp['item'], 'customerid' => $customerid]]);
}
foreach ($newcustprices as $cp) {
if ($database->has('customer_pricing', ['AND' => ['itemid' => $cp['item'], 'customerid' => $customerid]])) {
$database->update('customer_pricing', ['price' => $cp['price']], ['AND' => ['itemid' => $cp['item'], 'customerid' => $customerid]]);
} else {
$database->insert('customer_pricing', ['price' => $cp['price'], 'itemid' => $cp['item'], 'customerid' => $customerid]);
}
}
}
returnToSender("customer_saved");
case "set_register":
$regid = $VARS['register'];
if (!$database->has('registers', ['registerid' => $regid])) {
returnToSender("invalid_parameters");
}
if (!$database->has('cash_drawer', ['AND' => ['registerid' => $regid, 'close' => null]])) {
returnToSender("cash_not_open");
}
$cashid = $database->get('cash_drawer', 'cashid', ['AND' => ['registerid' => $regid, 'close' => null]]);
$_SESSION['register'] = (int) $regid;
returnToSender("register_set");
break;
case "opencash":
$regid = $VARS['register'];
$start = $VARS['startamount'];
if (!$database->has('registers', ['registerid' => $regid])) {
returnToSender("invalid_parameters");
}
if ($database->has('cash_drawer', ['AND' => ['registerid' => $regid, 'close' => null]])) {
returnToSender("cash_already_open");
}
if (!is_numeric($start) || (float) $start < 0) {
$start = 0.0;
}
$database->insert('cash_drawer', [
'registerid' => $regid,
'open' => date('Y-m-d H:i:s'),
'close' => null,
'start_amount' => $start,
'end_amount' => null
]);
returnToSender("cash_opened");
break;
case "closecash":
$regid = $VARS['register'];
if (!$database->has('registers', ['registerid' => $regid])) {
returnToSender("invalid_parameters");
}
if (!$database->has('cash_drawer', ['AND' => ['registerid' => $regid, 'close' => null]])) {
returnToSender("cash_not_open");
}
$cash = $database->get('cash_drawer', ['cashid', 'start_amount'], ['AND' => ['registerid' => $regid, 'close' => null]]);
$balance = (float) $cash['start_amount'];
$rows = $database->select("payments", [
"[>]transactions" => ['txid' => 'txid']
], 'amount', [
'AND' => [
'transactions.cashid' => $cash['cashid'],
'payments.type' => 1
]
]);
foreach ($rows as $row) {
$balance += $row;
}
$database->update('cash_drawer', [
'close' => date('Y-m-d H:i:s'),
'end_amount' => $balance
], [
'cashid' => $cash['cashid']
]);
returnToSender("cash_closed");
break;
case "editregister":
$insert = true;
if (empty($VARS['id'])) {
$insert = true;
} else {
if ($database->has('registers', ['registerid' => $VARS['id']])) {
$insert = false;
} else {
returnToSender("invalid_parameters");
}
}
if (is_empty($VARS['name'])) {
returnToSender('invalid_parameters');
}
if ($database->has('registers', ['AND' => ['registerid[!]' => $VARS['id'], 'registername' => $VARS['name']]])) {
returnToSender("register_name_taken");
}
$data = [
'registername' => $VARS['name']
];
if ($insert) {
$database->insert('registers', $data);
} else {
$database->update('registers', $data, ['registerid' => $VARS['id']]);
}
returnToSender("register_saved");
case "xreport":
require_once __DIR__ . "/lib/generatereceipt.php";
$format = "html";
$width = 64;
if (isset($VARS['width']) && preg_match("/[0-9]+/", $VARS['width']) && (int) $VARS['width'] > 0) {
$width = (int) $VARS['width'];
}
if (isset($VARS['format'])) {
$format = $VARS['format'];
}
if (!$database->has('cash_drawer', ['AND' => ['registerid' => $VARS['register'], 'open[!]' => null, 'close' => null]])) {
header("Content-Type: application/json");
exit(json_encode(["status" => "ERROR"]));
}
$receipt = GenerateReceipt::getReceipt(GenerateReceipt::RECEIPT_TYPE_X, $VARS['register']);
exit(GenerateReceipt::outputReceipt($receipt, $format, $width, "X Report"));
break;
case "zreport":
require_once __DIR__ . "/lib/generatereceipt.php";
$format = "html";
$width = 64;
if (isset($VARS['width']) && preg_match("/[0-9]+/", $VARS['width']) && (int) $VARS['width'] > 0) {
$width = (int) $VARS['width'];
}
if (isset($VARS['format'])) {
$format = $VARS['format'];
}
if (!$database->has('cash_drawer', ['AND' => ['open[!]' => null, 'close[!]' => null, 'cashid' => $VARS['cash']]])) {
header("Content-Type: application/json");
exit(json_encode(["status" => "ERROR"]));
}
$receipt = GenerateReceipt::getReceipt(GenerateReceipt::RECEIPT_TYPE_Z, $VARS['cash']);
exit(GenerateReceipt::outputReceipt($receipt, $format, $width, "Z Report"));
break;
case "session_keepalive":
header("Content-Type: application/json");
exit(json_encode(["status" => "OK"]));
case "signout":
session_destroy();
header('Location: index.php');
die("Logged out.");
}