An easy point of sale system with automatic inventory tracking. https://netsyms.biz/apps/nickelbox/
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

action.php 30KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  1. <?php
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. /**
  6. * Make things happen when buttons are pressed and forms submitted.
  7. */
  8. require_once __DIR__ . "/required.php";
  9. require_once __DIR__ . "/lib/userinfo.php";
  10. if ($VARS['action'] !== "signout") {
  11. dieifnotloggedin();
  12. }
  13. /**
  14. * Redirects back to the page ID in $_POST/$_GET['source'] with the given message ID.
  15. * The message will be displayed by the app.
  16. * @param string $msg message ID (see lang/messages.php)
  17. * @param string $arg If set, replaces "{arg}" in the message string when displayed to the user.
  18. */
  19. function returnToSender($msg, $arg = "") {
  20. global $VARS;
  21. if ($arg == "") {
  22. header("Location: app.php?page=" . urlencode($VARS['source']) . "&msg=" . $msg);
  23. } else {
  24. header("Location: app.php?page=" . urlencode($VARS['source']) . "&msg=$msg&arg=$arg");
  25. }
  26. die();
  27. }
  28. switch ($VARS['action']) {
  29. case "finish_transaction":
  30. header("Content-Type: application/json");
  31. $error = null;
  32. $oktx = null;
  33. $database->action(function ($database) {
  34. global $VARS, $binstack, $error, $oktx;
  35. if (empty($VARS['items'])) {
  36. $error = lang("no items", false);
  37. return false;
  38. }
  39. $items = $VARS['items'];
  40. $payments = $VARS['payments'];
  41. $customer = $VARS['customer'];
  42. $register = $VARS['register'];
  43. $discountpercent = $VARS['discountpercent'];
  44. $cashid = null;
  45. $editing = false;
  46. if (isset($VARS['txid']) && $database->has('transactions', ['txid' => $VARS['txid']])) {
  47. $editing = true;
  48. $txid = $VARS['txid'];
  49. $cashid = $database->get('transactions', 'cashid', ['txid' => $txid]);
  50. if (!$database->has('cash_drawer', ['AND' => ['cashid' => $cashid, 'close' => null]])) {
  51. $error = lang("cash already closed", false);
  52. return false;
  53. }
  54. // Nuke the payments to make room for their replacements
  55. // Delete payments
  56. $oldpayments = $database->select('payments', ['payid', 'amount', 'type', 'certid'], ['txid' => $txid]);
  57. foreach ($oldpayments as $p) {
  58. // Reset gift card balances
  59. if (!is_null($p['certid'])) {
  60. $database->update('certificates', ['amount[+]' => $p['amount']], ['certid' => $p['certid']]);
  61. }
  62. $database->delete('payments', ['payid' => $p['payid']]);
  63. }
  64. }
  65. if ($customer != "" && !$database->has('customers', ['customerid' => $customer])) {
  66. $error = lang("invalid customer", false);
  67. return false;
  68. }
  69. if ($register != "" && !$database->has('registers', ['registerid' => $register])) {
  70. $error = lang("invalid register", false);
  71. return false;
  72. }
  73. if ($register != "" && !$database->has('cash_drawer', ['AND' => ['registerid' => $register, 'close' => null]])) {
  74. $error = lang("cash not open", false);
  75. return false;
  76. }
  77. if ($register != "" && $editing === false) {
  78. $cashid = $database->get('cash_drawer', 'cashid', ['AND' => ['registerid' => $register, 'close' => null]]);
  79. }
  80. $totalcharge = 0.00;
  81. $totalpaid = 0.00;
  82. $change = 0.0;
  83. foreach ($items as $i) {
  84. $totalcharge += $i['each'] * $i['qty'];
  85. if (!$binstack->has('items', ['itemid' => $i['id']])) {
  86. $error = lang("invalid item", false);
  87. return false;
  88. }
  89. }
  90. foreach ($payments as $p) {
  91. if (!$database->has('payment_types', ['typename' => $p['type']])) {
  92. $error = lang("invalid payment type", false);
  93. return false;
  94. }
  95. $totalpaid += $p['amount'];
  96. if ($p['type'] == "giftcard") {
  97. if (!$database->has('certificates', ['AND' => ['amount[>=]' => $p['amount'], 'deleted[!]' => 1, 'certcode' => $p['code']]])) {
  98. $error = lang("invalid giftcard", false);
  99. return false;
  100. }
  101. }
  102. }
  103. if (is_numeric($discountpercent) && $discountpercent > 0 && $discountpercent < 100) {
  104. $discountpercent = $discountpercent * 1.0;
  105. $totalcharge *= 1.0 - ($discountpercent / 100.0);
  106. } else {
  107. $discountpercent = 0.0;
  108. }
  109. if ($totalcharge > $totalpaid) {
  110. $error = lang("insufficient payment", false);
  111. return false;
  112. }
  113. if ($editing === true) {
  114. $database->update('transactions', [
  115. 'txdate' => date('Y-m-d H:i:s'),
  116. 'customerid' => ($customer != "" ? $customer : null),
  117. 'type' => 1,
  118. 'cashier' => $_SESSION['uid'],
  119. 'cashid' => $cashid,
  120. 'discountpercent' => $discountpercent
  121. ], [
  122. 'txid' => $txid
  123. ]);
  124. } else {
  125. $database->insert('transactions', [
  126. 'txdate' => date('Y-m-d H:i:s'),
  127. 'customerid' => ($customer != "" ? $customer : null),
  128. 'type' => 1,
  129. 'cashier' => $_SESSION['uid'],
  130. 'cashid' => $cashid,
  131. 'discountpercent' => $discountpercent
  132. ]);
  133. $txid = $database->id();
  134. }
  135. $olditems = $database->select('lines', ['itemid (id)', 'qty', 'lineid'], ['txid' => $txid]);
  136. foreach ($items as $i) {
  137. $item = $binstack->get('items', ['name', 'qty'], ['itemid' => $i['id']]);
  138. $database->insert('lines', [
  139. 'txid' => $txid,
  140. 'amount' => $i['each'],
  141. 'name' => $item['name'],
  142. 'itemid' => $i['id'],
  143. 'qty' => $i['qty']
  144. ]);
  145. $binstack->update('items', [
  146. 'qty[-]' => $i['qty']
  147. ], [
  148. 'itemid' => $i['id']
  149. ]);
  150. }
  151. foreach ($payments as $p) {
  152. $certid = null;
  153. if ($p['type'] == "giftcard") {
  154. $certid = $database->get('certificates', 'certid', ['certcode' => $p['code']]);
  155. }
  156. $type = $database->get('payment_types', 'typeid', ['typename' => $p['type']]);
  157. $database->insert('payments', [
  158. 'amount' => $p['amount'],
  159. 'data' => '',
  160. 'type' => $type,
  161. 'txid' => $txid,
  162. 'certid' => $certid
  163. ]);
  164. }
  165. if ($totalcharge < $totalpaid) {
  166. $change = $totalpaid - $totalcharge;
  167. $database->insert('payments', [
  168. 'amount' => $change * -1.0,
  169. 'data' => '',
  170. 'type' => 1,
  171. 'txid' => $txid,
  172. 'certid' => null
  173. ]);
  174. }
  175. foreach ($olditems as $i) {
  176. $database->delete('lines', ['lineid' => $i['lineid']]);
  177. $binstack->update('items', [
  178. 'qty[+]' => $i['qty']
  179. ], [
  180. 'itemid' => $i['id']
  181. ]);
  182. }
  183. $oktx = $txid;
  184. return true;
  185. });
  186. if (!is_null($error)) {
  187. exit(json_encode(["status" => "ERROR", "message" => $error]));
  188. } else {
  189. exit(json_encode(["status" => "OK", "txid" => $oktx]));
  190. }
  191. break;
  192. case "finish_return":
  193. header("Content-Type: application/json");
  194. $error = null;
  195. $oktx = null;
  196. $database->action(function ($database) {
  197. global $VARS, $binstack, $error, $oktx;
  198. $items = $VARS['items'];
  199. $payments = $VARS['payments'];
  200. $customer = $VARS['customer'];
  201. $register = $VARS['register'];
  202. $cashid = null;
  203. if ($customer != "" && !$database->has('customers', ['customerid' => $customer])) {
  204. $error = lang("invalid customer", false);
  205. return false;
  206. }
  207. if ($register != "" && !$database->has('registers', ['registerid' => $register])) {
  208. $error = lang("invalid register", false);
  209. return false;
  210. }
  211. if ($register != "" && !$database->has('cash_drawer', ['AND' => ['registerid' => $register, 'close' => null]])) {
  212. $error = lang("cash not open", false);
  213. return false;
  214. }
  215. if ($register != "") {
  216. $cashid = $database->get('cash_drawer', 'cashid', ['AND' => ['registerid' => $register, 'close' => null]]);
  217. }
  218. $totaldue = 0.00;
  219. $totalrefund = 0.00;
  220. foreach ($items as $i) {
  221. $totaldue += $i['each'] * $i['qty'];
  222. if (!$binstack->has('items', ['itemid' => $i['id']])) {
  223. $error = lang("invalid item", false);
  224. return false;
  225. }
  226. }
  227. foreach ($payments as $p) {
  228. if (!$database->has('payment_types', ['typename' => $p['type']])) {
  229. $error = lang("invalid payment type", false);
  230. return false;
  231. }
  232. $totalrefund += $p['amount'];
  233. if ($p['type'] == "giftcard") {
  234. if (!$database->has('certificates', ['AND' => ['amount[>=]' => $p['amount'], 'deleted[!]' => 1, 'certcode' => $p['code']]])) {
  235. $error = lang("invalid giftcard", false);
  236. return false;
  237. }
  238. }
  239. }
  240. $database->insert('transactions', [
  241. 'txdate' => date('Y-m-d H:i:s'),
  242. 'customerid' => ($customer != "" ? $customer : null),
  243. 'type' => 2,
  244. 'cashier' => $_SESSION['uid'],
  245. 'cashid' => $cashid,
  246. 'discountpercent' => 0.0
  247. ]);
  248. $txid = $database->id();
  249. foreach ($items as $i) {
  250. $item = $binstack->get('items', ['name', 'qty'], ['itemid' => $i['id']]);
  251. $database->insert('lines', [
  252. 'txid' => $txid,
  253. 'amount' => $i['each'],
  254. 'name' => $item['name'],
  255. 'itemid' => $i['id'],
  256. 'qty' => $i['qty'] * -1.0
  257. ]);
  258. }
  259. foreach ($payments as $p) {
  260. $certid = null;
  261. if ($p['type'] == "giftcard") {
  262. $certid = $database->get('certificates', 'certid', ['certcode' => $p['code']]);
  263. $database->update('certificates', ['amount[+]' => $p['amount']], ['certid' => $certid]);
  264. }
  265. $type = $database->get('payment_types', 'typeid', ['typename' => $p['type']]);
  266. $database->insert('payments', [
  267. 'amount' => $p['amount'] * -1.0,
  268. 'data' => '',
  269. 'type' => $type,
  270. 'txid' => $txid,
  271. 'certid' => $certid
  272. ]);
  273. }
  274. $oktx = $txid;
  275. return true;
  276. });
  277. if (!is_null($error)) {
  278. exit(json_encode(["status" => "ERROR", "message" => $error]));
  279. } else {
  280. exit(json_encode(["status" => "OK", "txid" => $oktx]));
  281. }
  282. break;
  283. case "delete_transaction":
  284. header("Content-Type: application/json");
  285. $error = null;
  286. if (isset($VARS['txid']) && $database->has('transactions', ['txid' => $VARS['txid']])) {
  287. $txid = $VARS['txid'];
  288. $cashid = $database->get('transactions', 'cashid', ['txid' => $txid]);
  289. if (!$database->has('cash_drawer', ['AND' => ['cashid' => $cashid, 'close' => null]])) {
  290. $error = lang("cash already closed", false);
  291. }
  292. $database->action(function ($database) {
  293. global $VARS, $binstack, $error, $txid;
  294. // Delete payments
  295. $payments = $database->select('payments', ['payid', 'amount', 'type', 'certid'], ['txid' => $txid]);
  296. foreach ($payments as $p) {
  297. // Reset gift card balances
  298. if (!is_null($p['certid'])) {
  299. $database->update('certificates', ['amount[+]' => $p['amount']], ['certid' => $p['certid']]);
  300. }
  301. $database->delete('payments', ['payid' => $p['payid']]);
  302. }
  303. // Delete items/lines
  304. $items = $database->select('lines', ['itemid (id)', 'qty', 'lineid'], ['txid' => $txid]);
  305. foreach ($items as $i) {
  306. $database->delete('lines', ['lineid' => $i['lineid']]);
  307. $binstack->update('items', [
  308. 'qty[+]' => $i['qty']
  309. ], [
  310. 'itemid' => $i['id']
  311. ]);
  312. }
  313. // Delete transaction
  314. $database->delete('transactions', ['txid' => $txid, 'LIMIT' => 1]);
  315. });
  316. } else {
  317. $error = lang("invalid parameters", false);
  318. }
  319. if (!is_null($error)) {
  320. exit(json_encode(["status" => "ERROR", "message" => $error]));
  321. } else {
  322. exit(json_encode(["status" => "OK"]));
  323. }
  324. break;
  325. case "getreceipt":
  326. require_once __DIR__ . "/lib/generatereceipt.php";
  327. $format = "html";
  328. $width = 48;
  329. if (isset($VARS['width']) && preg_match("/[0-9]+/", $VARS['width']) && (int) $VARS['width'] > 0) {
  330. $width = (int) $VARS['width'];
  331. }
  332. if (isset($VARS['format'])) {
  333. $format = $VARS['format'];
  334. }
  335. if (!$database->has('transactions', ['txid' => $VARS['txid']])) {
  336. header("Content-Type: application/json");
  337. exit(json_encode(["status" => "ERROR", "txid" => null]));
  338. }
  339. $receipt = GenerateReceipt::getReceipt(GenerateReceipt::RECEIPT_TYPE_TRANSACTION, $VARS['txid']);
  340. exit(GenerateReceipt::outputReceipt($receipt, $format, $width, "Tx. #" . $VARS['txid']));
  341. break;
  342. case "transactionsearch":
  343. header("Content-Type: application/json");
  344. $where = [];
  345. if (!empty($VARS['q'])) {
  346. $where["AND"]["OR"] = [
  347. "txid" => $VARS['q'],
  348. "name[~]" => $VARS['q'],
  349. "email[~]" => $VARS['q'],
  350. "phone[~]" => $VARS['q']
  351. ];
  352. }
  353. $start = date('Y-m-d H:i:s', 946684800); // Jan 1 2000
  354. $end = date('Y-m-d H:i:s');
  355. if (!empty($VARS['start']) && strtotime($VARS['start']) !== FALSE) {
  356. $start = date('Y-m-d H:i:s', strtotime($VARS['start']));
  357. }
  358. if (!empty($VARS['end']) && strtotime($VARS['end']) !== FALSE) {
  359. $end = date('Y-m-d H:i:s', strtotime($VARS['end']));
  360. }
  361. $where["AND"]['txdate[>=]'] = $start;
  362. $where["AND"]['txdate[<=]'] = $end;
  363. $where["LIMIT"] = 50;
  364. $transactions = $database->select('transactions', [
  365. '[>]customers' => 'customerid',
  366. '[>]cash_drawer' => 'cashid',
  367. '[>]registers' => ['cash_drawer.registerid' => 'registerid'],
  368. ], [
  369. 'txid',
  370. 'txdate',
  371. 'type',
  372. 'cashier (cashierid)',
  373. 'transactions.cashid',
  374. 'cash_drawer.registerid',
  375. 'registers.registername',
  376. 'cash_drawer.open',
  377. 'cash_drawer.close',
  378. 'customerid',
  379. 'customer' => [
  380. 'name',
  381. 'email',
  382. 'phone',
  383. 'address'
  384. ]], $where);
  385. for ($i = 0; $i < count($transactions); $i++) {
  386. if (is_null($transactions[$i]['close']) && !is_null($transactions[$i]['open'])) {
  387. $transactions[$i]['editable'] = true;
  388. } else {
  389. $transactions[$i]['editable'] = false;
  390. }
  391. if (!is_null($transactions[$i]['cashierid'])) {
  392. $cashier = getUserByID($transactions[$i]['cashierid']);
  393. $transactions[$i]['cashier'] = [
  394. "name" => $cashier['name'],
  395. "username" => $cashier['username']
  396. ];
  397. }
  398. }
  399. $transactions = (count($transactions) > 0 ? $transactions : false);
  400. exit(json_encode(["status" => "OK", "transactions" => $transactions]));
  401. case "itemsearch":
  402. header("Content-Type: application/json");
  403. if (!is_empty($VARS['q'])) {
  404. $where["AND"]["OR"] = [
  405. "name[~]" => $VARS['q'],
  406. "code1[~]" => $VARS['q'],
  407. "code2[~]" => $VARS['q']
  408. ];
  409. } else {
  410. exit(json_encode(["status" => "ERROR", "items" => false]));
  411. }
  412. $items = $binstack->select('items', [
  413. 'itemid (id)',
  414. 'name',
  415. 'code1',
  416. 'code2',
  417. 'cost',
  418. 'price'
  419. ], $where);
  420. if (!empty($VARS['customer']) && $database->has('customers', ['customerid' => $VARS['customer']])) {
  421. for ($n = 0; $n < count($items); $n++) {
  422. $i = $items[$n];
  423. if ($database->has('customer_pricing', ['AND' => ['itemid' => $i['id'], 'customerid' => $VARS['customer']]])) {
  424. $items[$n]['price'] = $database->get('customer_pricing', 'price', ['AND' => ['itemid' => $i['id'], 'customerid' => $VARS['customer']]]);
  425. }
  426. }
  427. }
  428. $items = (count($items) > 0 ? $items : false);
  429. exit(json_encode(["status" => "OK", "items" => $items]));
  430. case "getgriditems":
  431. header("Content-Type: application/json");
  432. $items = $binstack->select('items', [
  433. 'itemid (id)', 'name', 'price', 'code1', 'code2'
  434. ], [
  435. 'AND' => ['price[!]' => null, 'price[!]' => 0]
  436. ]);
  437. if (!empty($VARS['customer']) && $database->has('customers', ['customerid' => $VARS['customer']])) {
  438. for ($n = 0; $n < count($items); $n++) {
  439. $i = $items[$n];
  440. if ($database->has('customer_pricing', ['AND' => ['itemid' => $i['id'], 'customerid' => $VARS['customer']]])) {
  441. $items[$n]['price'] = $database->get('customer_pricing', 'price', ['AND' => ['itemid' => $i['id'], 'customerid' => $VARS['customer']]]);
  442. }
  443. }
  444. }
  445. for ($n = 0; $n < count($items); $n++) {
  446. if ($items[$n]['code1'] != "") {
  447. $items[$n]['code'] = $items[$n]["code1"];
  448. } else if ($items[$n]['code1'] == "" && $items[$n]['code1'] != "") {
  449. $items[$n]['code'] = $items[$n]["code2"];
  450. } else if (code == "") {
  451. $items[$n]['code'] = "---";
  452. }
  453. }
  454. $items = (count($items) > 0 ? $items : false);
  455. exit(json_encode(["status" => "OK", "items" => $items]));
  456. case "customersearch":
  457. header("Content-Type: application/json");
  458. if (!is_empty($VARS['q'])) {
  459. $where["AND"]["OR"] = [
  460. "customerid" => $VARS['q'],
  461. "name[~]" => $VARS['q'],
  462. "email[~]" => $VARS['q'],
  463. "phone[~]" => $VARS['q']
  464. ];
  465. } else {
  466. exit(json_encode(["status" => "ERROR", "customers" => false]));
  467. }
  468. $where["LIMIT"] = 10;
  469. $customers = $database->select('customers', [
  470. 'customerid (id)',
  471. 'name',
  472. 'email',
  473. 'phone',
  474. 'address',
  475. 'notes'
  476. ], $where);
  477. $customers = (count($customers) > 0 ? $customers : false);
  478. exit(json_encode(["status" => "OK", "customers" => $customers]));
  479. case "giftcard_lookup":
  480. header("Content-Type: application/json");
  481. $code = $VARS['code'];
  482. if (empty($code)) {
  483. exit(json_encode(["status" => "ERROR", "cards" => []]));
  484. }
  485. $cards = $database->select('certificates', ['certid (id)', 'certcode (code)', 'amount (balance)', 'start_amount (amount)'], ['certcode' => $code]);
  486. exit(json_encode(["status" => "OK", "cards" => $cards]));
  487. break;
  488. case "editcustomer":
  489. $insert = true;
  490. if (is_empty($VARS['id'])) {
  491. $insert = true;
  492. } else {
  493. if ($database->has('customers', ['customerid' => $VARS['id']])) {
  494. $insert = false;
  495. } else {
  496. returnToSender("invalid_customerid");
  497. }
  498. }
  499. if (is_empty($VARS['name'])) {
  500. returnToSender('invalid_parameters');
  501. }
  502. $data = [
  503. 'name' => $VARS['name'],
  504. 'email' => $VARS['email'],
  505. 'phone' => $VARS['phone'],
  506. 'address' => $VARS['address'],
  507. 'notes' => $VARS['notes']
  508. ];
  509. $customerid = null;
  510. if ($insert) {
  511. $database->insert('customers', $data);
  512. $customerid = $database->id();
  513. } else {
  514. $database->update('customers', $data, ['customerid' => $VARS['id']]);
  515. $customerid = $VARS['id'];
  516. }
  517. if (!is_null($customerid)) {
  518. $custprices = $VARS['pricing'];
  519. $newcustprices = [];
  520. $oldcustprices = $database->select('customer_pricing', ['itemid (item)', 'price'], ['customerid' => $customerid]);
  521. foreach ($custprices as $cp) {
  522. if (!$binstack->has('items', ['itemid' => $cp['item']])) {
  523. continue;
  524. }
  525. if (!is_numeric($cp['price'])) {
  526. continue;
  527. }
  528. $newcustprices[] = $cp;
  529. $oldcustprices = array_filter($oldcustprices, function ($var) {
  530. if ($cp['item'] == $var['item']) {
  531. return false;
  532. }
  533. return true;
  534. });
  535. }
  536. foreach ($oldcustprices as $cp) {
  537. $database->delete('customer_pricing', ['AND' => ['itemid' => $cp['item'], 'customerid' => $customerid]]);
  538. }
  539. foreach ($newcustprices as $cp) {
  540. if ($database->has('customer_pricing', ['AND' => ['itemid' => $cp['item'], 'customerid' => $customerid]])) {
  541. $database->update('customer_pricing', ['price' => $cp['price']], ['AND' => ['itemid' => $cp['item'], 'customerid' => $customerid]]);
  542. } else {
  543. $database->insert('customer_pricing', ['price' => $cp['price'], 'itemid' => $cp['item'], 'customerid' => $customerid]);
  544. }
  545. }
  546. }
  547. returnToSender("customer_saved");
  548. case "set_register":
  549. $regid = $VARS['register'];
  550. if (!$database->has('registers', ['registerid' => $regid])) {
  551. returnToSender("invalid_parameters");
  552. }
  553. if (!$database->has('cash_drawer', ['AND' => ['registerid' => $regid, 'close' => null]])) {
  554. returnToSender("cash_not_open");
  555. }
  556. $cashid = $database->get('cash_drawer', 'cashid', ['AND' => ['registerid' => $regid, 'close' => null]]);
  557. $_SESSION['register'] = (int) $regid;
  558. returnToSender("register_set");
  559. break;
  560. case "opencash":
  561. $regid = $VARS['register'];
  562. $start = $VARS['startamount'];
  563. if (!$database->has('registers', ['registerid' => $regid])) {
  564. returnToSender("invalid_parameters");
  565. }
  566. if ($database->has('cash_drawer', ['AND' => ['registerid' => $regid, 'close' => null]])) {
  567. returnToSender("cash_already_open");
  568. }
  569. if (!is_numeric($start) || (float) $start < 0) {
  570. $start = 0.0;
  571. }
  572. $database->insert('cash_drawer', [
  573. 'registerid' => $regid,
  574. 'open' => date('Y-m-d H:i:s'),
  575. 'close' => null,
  576. 'start_amount' => $start,
  577. 'end_amount' => null
  578. ]);
  579. returnToSender("cash_opened");
  580. break;
  581. case "closecash":
  582. $regid = $VARS['register'];
  583. if (!$database->has('registers', ['registerid' => $regid])) {
  584. returnToSender("invalid_parameters");
  585. }
  586. if (!$database->has('cash_drawer', ['AND' => ['registerid' => $regid, 'close' => null]])) {
  587. returnToSender("cash_not_open");
  588. }
  589. $cash = $database->get('cash_drawer', ['cashid', 'start_amount'], ['AND' => ['registerid' => $regid, 'close' => null]]);
  590. $balance = (float) $cash['start_amount'];
  591. $rows = $database->select("payments", [
  592. "[>]transactions" => ['txid' => 'txid']
  593. ], 'amount', [
  594. 'AND' => [
  595. 'transactions.cashid' => $cash['cashid'],
  596. 'payments.type' => 1
  597. ]
  598. ]);
  599. foreach ($rows as $row) {
  600. $balance += $row;
  601. }
  602. $database->update('cash_drawer', [
  603. 'close' => date('Y-m-d H:i:s'),
  604. 'end_amount' => $balance
  605. ], [
  606. 'cashid' => $cash['cashid']
  607. ]);
  608. returnToSender("cash_closed");
  609. break;
  610. case "editregister":
  611. $insert = true;
  612. if (empty($VARS['id'])) {
  613. $insert = true;
  614. } else {
  615. if ($database->has('registers', ['registerid' => $VARS['id']])) {
  616. $insert = false;
  617. } else {
  618. returnToSender("invalid_parameters");
  619. }
  620. }
  621. if (is_empty($VARS['name'])) {
  622. returnToSender('invalid_parameters');
  623. }
  624. if ($database->has('registers', ['AND' => ['registerid[!]' => $VARS['id'], 'registername' => $VARS['name']]])) {
  625. returnToSender("register_name_taken");
  626. }
  627. $data = [
  628. 'registername' => $VARS['name']
  629. ];
  630. if ($insert) {
  631. $database->insert('registers', $data);
  632. } else {
  633. $database->update('registers', $data, ['registerid' => $VARS['id']]);
  634. }
  635. returnToSender("register_saved");
  636. case "xreport":
  637. require_once __DIR__ . "/lib/generatereceipt.php";
  638. $format = "html";
  639. $width = 64;
  640. if (isset($VARS['width']) && preg_match("/[0-9]+/", $VARS['width']) && (int) $VARS['width'] > 0) {
  641. $width = (int) $VARS['width'];
  642. }
  643. if (isset($VARS['format'])) {
  644. $format = $VARS['format'];
  645. }
  646. if (!$database->has('cash_drawer', ['AND' => ['registerid' => $VARS['register'], 'open[!]' => null, 'close' => null]])) {
  647. header("Content-Type: application/json");
  648. exit(json_encode(["status" => "ERROR"]));
  649. }
  650. $receipt = GenerateReceipt::getReceipt(GenerateReceipt::RECEIPT_TYPE_X, $VARS['register']);
  651. exit(GenerateReceipt::outputReceipt($receipt, $format, $width, "X Report"));
  652. break;
  653. case "zreport":
  654. require_once __DIR__ . "/lib/generatereceipt.php";
  655. $format = "html";
  656. $width = 64;
  657. if (isset($VARS['width']) && preg_match("/[0-9]+/", $VARS['width']) && (int) $VARS['width'] > 0) {
  658. $width = (int) $VARS['width'];
  659. }
  660. if (isset($VARS['format'])) {
  661. $format = $VARS['format'];
  662. }
  663. if (!$database->has('cash_drawer', ['AND' => ['open[!]' => null, 'close[!]' => null, 'cashid' => $VARS['cash']]])) {
  664. header("Content-Type: application/json");
  665. exit(json_encode(["status" => "ERROR"]));
  666. }
  667. $receipt = GenerateReceipt::getReceipt(GenerateReceipt::RECEIPT_TYPE_Z, $VARS['cash']);
  668. exit(GenerateReceipt::outputReceipt($receipt, $format, $width, "Z Report"));
  669. break;
  670. case "editcertificate":
  671. $insert = true;
  672. $code = $VARS['code'];
  673. $amount = $VARS['balance'];
  674. if (empty($VARS['id'])) {
  675. $insert = true;
  676. } else {
  677. if ($database->has('certificates', ['certid' => $VARS['id']])) {
  678. $insert = false;
  679. } else {
  680. returnToSender("invalid_parameters");
  681. }
  682. }
  683. if ($insert && (is_empty($code) || $database->has('certificates', ['certcode' => $code]))) {
  684. do {
  685. $code = random_int(100000000000, 999999999999);
  686. } while ($database->has('certificates', ['certcode' => $code]));
  687. }
  688. if (!is_numeric($amount)) {
  689. returnToSender("invalid_parameters");
  690. }
  691. if ($insert) {
  692. $database->insert('certificates', [
  693. 'certcode' => $code,
  694. 'amount' => $amount,
  695. 'start_amount' => $amount,
  696. 'issued' => date('Y-m-d H:i:s'),
  697. 'deleted' => 0]);
  698. returnToSender("card_x_added", $code);
  699. } else {
  700. $database->update('certificates', [
  701. 'certcode' => $code,
  702. 'amount' => $amount
  703. ], [
  704. 'certid' => $VARS['id']
  705. ]);
  706. returnToSender("card_x_saved", $code);
  707. }
  708. break;
  709. case "session_keepalive":
  710. header("Content-Type: application/json");
  711. exit(json_encode(["status" => "OK"]));
  712. case "signout":
  713. session_destroy();
  714. header('Location: index.php');
  715. die("Logged out.");
  716. }