An easy point of sale system with automatic inventory tracking. https://netsyms.biz/apps/nickelbox/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

GenerateReceipt.lib.php 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. <?php
  2. /*
  3. * This Source Code Form is subject to the terms of the Mozilla Public
  4. * License, v. 2.0. If a copy of the MPL was not distributed with this
  5. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. */
  7. class GenerateReceipt {
  8. const RECEIPT_TYPE_TRANSACTION = 1;
  9. const RECEIPT_TYPE_X = 2;
  10. const RECEIPT_TYPE_Z = 3;
  11. private static function saleReceipt($transaction) {
  12. global $database;
  13. $receipt = new Receipt();
  14. $tx = $database->get('transactions', ['txid', 'txdate', 'customerid', 'type', 'cashier', 'discountpercent'], ['txid' => $transaction]);
  15. // Info
  16. $txid = $tx['txid'];
  17. $datetime = date(DATETIME_FORMAT, strtotime($tx['txdate']));
  18. $type = $tx['type'];
  19. $cashier = getUserByID($tx['cashier'])['name'];
  20. $customerid = $tx['customerid'];
  21. // Items
  22. $itemlines = [];
  23. $items = $database->select('lines', ['amount', 'name', 'itemid', 'qty'], ['txid' => $txid]);
  24. $subtotal = 0.0;
  25. $paid = 0.0;
  26. foreach ($items as $i) {
  27. $itemlines[] = new ReceiptLine(
  28. $i['name'], (float) $i['qty'] . '@' . number_format($i['amount'], 2), '$' . number_format($i['qty'] * $i['amount'] * 1.0, 2)
  29. );
  30. $subtotal += $i['qty'] * $i['amount'] * 1.0;
  31. }
  32. // Payments
  33. $total = $subtotal * (1.0 - ((float) $tx['discountpercent'] / 100));
  34. $paymentlines = [];
  35. $payments = $database->select('payments', [
  36. '[>]payment_types' => ['type' => 'typeid']
  37. ], [
  38. 'amount', 'type', 'typename', 'text'
  39. ], [
  40. 'txid' => $txid
  41. ]);
  42. foreach ($payments as $p) {
  43. if ($p['amount'] < 0) {
  44. continue;
  45. }
  46. $paymentlines[] = new ReceiptLine($Strings->get($p['text'], false), "", '$' . number_format($p['amount'] * 1.0, 2));
  47. $paid += $p['amount'] * 1.0;
  48. }
  49. $change = $paid - $total;
  50. if ($change <= 0) {
  51. $change = 0.0;
  52. }
  53. // Totals
  54. $subtotalline = new ReceiptLine("Subtotal:", "", '$' . number_format($subtotal, 2));
  55. $paidline = new ReceiptLine("Paid:", "", '$' . number_format($paid, 2), ReceiptLine::LINEFORMAT_BOLD);
  56. $changeline = new ReceiptLine("Change:", "", '$' . number_format($change, 2), ReceiptLine::LINEFORMAT_BOLD);
  57. $totalline = new ReceiptLine("Total:", "", '$' . number_format($subtotal, 2), ReceiptLine::LINEFORMAT_BOLD);
  58. $receipt->appendLine(new ReceiptLine("Date: $datetime"));
  59. $receipt->appendLine(new ReceiptLine("Tx. ID: $txid"));
  60. $receipt->appendLine(new ReceiptLine("Cashier: $cashier"));
  61. if (!is_null($customerid) && !empty($customerid)) {
  62. $customer = $database->get('customers', 'name', ['customerid' => $customerid]);
  63. $receipt->appendLine(new ReceiptLine("Customer: $customer"));
  64. }
  65. $receipt->appendBreak();
  66. $receipt->appendLines($itemlines);
  67. $receipt->appendBreak();
  68. $receipt->appendLine($subtotalline);
  69. if ($tx['discountpercent'] > 0) {
  70. $receipt->appendLine(new ReceiptLine("Discount:", "", (float) $tx['discountpercent'] . '% off'));
  71. $totalline = new ReceiptLine("Total:", "", '$' . number_format($total, 2), ReceiptLine::LINEFORMAT_BOLD);
  72. }
  73. $receipt->appendLine($totalline);
  74. $receipt->appendBreak();
  75. $receipt->appendLines($paymentlines);
  76. $receipt->appendBreak();
  77. $receipt->appendLine($paidline);
  78. $receipt->appendLine($changeline);
  79. return $receipt;
  80. }
  81. private static function returnReceipt($transaction) {
  82. global $database;
  83. $receipt = new Receipt();
  84. $tx = $database->get('transactions', ['txid', 'txdate', 'customerid', 'type', 'cashier', 'discountpercent'], ['txid' => $transaction]);
  85. // Info
  86. $txid = $tx['txid'];
  87. $datetime = date(DATETIME_FORMAT, strtotime($tx['txdate']));
  88. $type = $tx['type'];
  89. $cashier = getUserByID($tx['cashier'])['name'];
  90. $customerid = $tx['customerid'];
  91. // Items
  92. $itemlines = [];
  93. $items = $database->select('lines', ['amount', 'name', 'itemid', 'qty'], ['txid' => $txid]);
  94. $subtotal = 0.0;
  95. $paid = 0.0;
  96. foreach ($items as $i) {
  97. $itemlines[] = new ReceiptLine(
  98. $i['name'], (float) $i['qty'] . '@' . number_format($i['amount'], 2), '$' . number_format($i['qty'] * $i['amount'] * 1.0, 2)
  99. );
  100. $subtotal += $i['qty'] * $i['amount'] * 1.0;
  101. }
  102. // Payments
  103. $total = $subtotal * (1.0 - ((float) $tx['discountpercent'] / 100));
  104. $paymentlines = [];
  105. $payments = $database->select('payments', [
  106. '[>]payment_types' => ['type' => 'typeid']
  107. ], [
  108. 'amount', 'type', 'typename', 'text'
  109. ], [
  110. 'txid' => $txid
  111. ]);
  112. foreach ($payments as $p) {
  113. $paymentlines[] = new ReceiptLine($Strings->get($p['text'], false), "", '$' . number_format($p['amount'] * -1.0, 2));
  114. $paid += $p['amount'] * 1.0;
  115. }
  116. // Totals
  117. $subtotalline = new ReceiptLine("Subtotal:", "", '$' . number_format($subtotal, 2));
  118. $paidline = new ReceiptLine("Refund:", "", '$' . number_format($paid * -1.0, 2), ReceiptLine::LINEFORMAT_BOLD);
  119. $totalline = new ReceiptLine("Total:", "", '$' . number_format($subtotal, 2), ReceiptLine::LINEFORMAT_BOLD);
  120. $receipt->appendLine(new ReceiptLine("Date: $datetime"));
  121. $receipt->appendLine(new ReceiptLine("Tx. ID: $txid"));
  122. $receipt->appendLine(new ReceiptLine("Cashier: $cashier"));
  123. if (!is_null($customerid) && !empty($customerid)) {
  124. $customer = $database->get('customers', 'name', ['customerid' => $customerid]);
  125. $receipt->appendLine(new ReceiptLine("Customer: $customer"));
  126. }
  127. $receipt->appendBreak();
  128. $receipt->appendLines($itemlines);
  129. $receipt->appendBreak();
  130. $receipt->appendLine($subtotalline);
  131. $receipt->appendLine($totalline);
  132. $receipt->appendBreak();
  133. $receipt->appendLines($paymentlines);
  134. $receipt->appendBreak();
  135. $receipt->appendLine($paidline);
  136. return $receipt;
  137. }
  138. static function transactionReceipt($transaction) {
  139. global $database;
  140. $txtype = $database->get('transactions', 'type', ['txid' => $transaction]);
  141. switch ($txtype) {
  142. case 1:
  143. return GenerateReceipt::saleReceipt($transaction);
  144. case 2:
  145. return GenerateReceipt::returnReceipt($transaction);
  146. default:
  147. return new Receipt();
  148. }
  149. }
  150. static function xReceipt($registerid) {
  151. global $database;
  152. $receipt = new Receipt();
  153. $registername = $database->get('registers', 'registername', ['registerid' => $registerid]);
  154. $cash = $database->get('cash_drawer', ['open', 'start_amount', 'cashid'], ['AND' => ['open[!]' => null, 'close' => null, 'registerid' => $registerid]]);
  155. $balance = [];
  156. $paymenttypes = $database->select('payment_types', ['typename (type)', 'text']);
  157. $payments = $database->select("payments", [
  158. "[>]transactions" => ['txid' => 'txid'],
  159. "[>]payment_types" => ['type' => 'typeid']
  160. ], ['amount', 'typename (type)'], [
  161. 'AND' => [
  162. 'transactions.cashid' => $cash['cashid'],
  163. ]
  164. ]);
  165. $transactioncount = $database->count('transactions', ['cashid' => $cash['cashid']]);
  166. foreach ($paymenttypes as $t) {
  167. $balance[$t['type']] = 0.0;
  168. }
  169. foreach ($payments as $p) {
  170. $balance[$p['type']] += $p['amount'];
  171. }
  172. $receipt->appendHeader(new ReceiptLine($Strings->get("x report", false), "", "", ReceiptLine::LINEFORMAT_BOLD | ReceiptLine::LINEFORMAT_CENTER));
  173. $receipt->appendLine(new ReceiptLine("Printed:", "", date(DATETIME_FORMAT)));
  174. $receipt->appendLine(new ReceiptLine("Register:", "", $registername));
  175. $receipt->appendLine(new ReceiptLine("Transactions:", "", $transactioncount));
  176. $receipt->appendBlank();
  177. $receipt->appendBreak();
  178. $receipt->appendLine(new ReceiptLine("Opening", "", "", ReceiptLine::LINEFORMAT_CENTER));
  179. $receipt->appendBreak();
  180. $receipt->appendLine(new ReceiptLine("Date:", "", date(DATETIME_FORMAT, strtotime($cash['open']))));
  181. $receipt->appendLine(new ReceiptLine("Cash:", "", '$' . number_format($cash['start_amount'], 2)));
  182. $receipt->appendBlank();
  183. $receipt->appendBreak();
  184. $receipt->appendLine(new ReceiptLine("Sales", "", "", ReceiptLine::LINEFORMAT_CENTER));
  185. $receipt->appendBreak();
  186. foreach ($paymenttypes as $t) {
  187. $receipt->appendLine(new ReceiptLine($Strings->get($t['text'], false) . ":", "", '$' . number_format($balance[$t['type']], 2)));
  188. }
  189. $receipt->appendBlank();
  190. $receipt->appendBreak();
  191. $receipt->appendLine(new ReceiptLine("Balance", "", "", ReceiptLine::LINEFORMAT_CENTER));
  192. $receipt->appendBreak();
  193. $receipt->appendLine(new ReceiptLine("Cash:", "", '$' . number_format($balance['cash'] + $cash['start_amount'], 2)));
  194. return $receipt;
  195. }
  196. static function zReceipt($cashid) {
  197. global $database;
  198. $receipt = new Receipt();
  199. $cash = $database->get('cash_drawer', ['open', 'close', 'start_amount', 'end_amount', 'cashid', 'registerid'], ['cashid' => $cashid]);
  200. $registername = $database->get('registers', 'registername', ['registerid' => $cash['registerid']]);
  201. $balance = [];
  202. $paymenttypes = $database->select('payment_types', ['typename (type)', 'text']);
  203. $payments = $database->select("payments", [
  204. "[>]transactions" => ['txid' => 'txid'],
  205. "[>]payment_types" => ['type' => 'typeid']
  206. ], ['amount', 'typename (type)'], [
  207. 'AND' => [
  208. 'transactions.cashid' => $cash['cashid'],
  209. ]
  210. ]);
  211. $transactioncount = $database->count('transactions', ['cashid' => $cashid]);
  212. foreach ($paymenttypes as $t) {
  213. $balance[$t['type']] = 0.0;
  214. }
  215. foreach ($payments as $p) {
  216. $balance[$p['type']] += $p['amount'];
  217. }
  218. $receipt->appendHeader(new ReceiptLine($Strings->get("z report", false), "", "", ReceiptLine::LINEFORMAT_BOLD | ReceiptLine::LINEFORMAT_CENTER));
  219. $receipt->appendLine(new ReceiptLine("Printed:", "", date(DATETIME_FORMAT)));
  220. $receipt->appendLine(new ReceiptLine("Register:", "", $registername));
  221. $receipt->appendLine(new ReceiptLine("Transactions:", "", $transactioncount));
  222. $receipt->appendBlank();
  223. $receipt->appendBreak();
  224. $receipt->appendLine(new ReceiptLine("Opening", "", "", ReceiptLine::LINEFORMAT_CENTER));
  225. $receipt->appendBreak();
  226. $receipt->appendLine(new ReceiptLine("Date:", "", date(DATETIME_FORMAT, strtotime($cash['open']))));
  227. $receipt->appendLine(new ReceiptLine("Cash:", "", '$' . number_format($cash['start_amount'], 2)));
  228. $receipt->appendBlank();
  229. $receipt->appendBreak();
  230. $receipt->appendLine(new ReceiptLine("Closing", "", "", ReceiptLine::LINEFORMAT_CENTER));
  231. $receipt->appendBreak();
  232. $receipt->appendLine(new ReceiptLine("Date:", "", date(DATETIME_FORMAT, strtotime($cash['close']))));
  233. $receipt->appendLine(new ReceiptLine("Cash:", "", '$' . number_format($cash['end_amount'], 2)));
  234. $receipt->appendBlank();
  235. $receipt->appendBreak();
  236. $receipt->appendLine(new ReceiptLine("Sales", "", "", ReceiptLine::LINEFORMAT_CENTER));
  237. $receipt->appendBreak();
  238. foreach ($paymenttypes as $t) {
  239. $receipt->appendLine(new ReceiptLine($Strings->get($t['text'], false) . ":", "", '$' . number_format($balance[$t['type']], 2)));
  240. }
  241. return $receipt;
  242. }
  243. static function getReceipt($type, $data) {
  244. switch ($type) {
  245. case GenerateReceipt::RECEIPT_TYPE_X:
  246. return GenerateReceipt::xReceipt($data);
  247. break;
  248. case GenerateReceipt::RECEIPT_TYPE_Z:
  249. return GenerateReceipt::zReceipt($data);
  250. break;
  251. case GenerateReceipt::RECEIPT_TYPE_TRANSACTION:
  252. return GenerateReceipt::transactionReceipt($data);
  253. break;
  254. default:
  255. return new Receipt();
  256. break;
  257. }
  258. }
  259. static function outputReceipt(Receipt $receipt, $format = "html", $width = 64, $title = "") {
  260. switch ($format) {
  261. case "text":
  262. $format = "text";
  263. header("Content-Type: text/plain");
  264. break;
  265. case "json":
  266. $format = "json";
  267. header("Content-Type: application/json");
  268. break;
  269. default:
  270. $format = "html";
  271. header("Content-Type: text/html");
  272. }
  273. $output = "";
  274. switch ($format) {
  275. case "text":
  276. $output = $receipt->getPlainText($width);
  277. break;
  278. case "json":
  279. $output = $receipt->getJson($width);
  280. break;
  281. default:
  282. $output = $receipt->getHtml($title);
  283. }
  284. return $output;
  285. }
  286. }