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.php 13KB

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