diff --git a/action.php b/action.php index 131202e..b5fcae0 100644 --- a/action.php +++ b/action.php @@ -144,41 +144,55 @@ switch ($VARS['action']) { break; case "getreceipt": - header("Content-Type: text/html"); + require_once __DIR__ . "/lib/receipts.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'])) { + switch ($VARS['format']) { + case "text": + $format = "text"; + header("Content-Type: text/plain"); + break; + case "json": + $format = "json"; + header("Content-Type: application/json"); + break; + default: + $format = "html"; + header("Content-Type: text/html"); + } + } if (!$database->has('transactions', ['txid' => $VARS['txid']])) { + header("Content-Type: application/json"); exit(json_encode(["status" => "ERROR", "txid" => null])); } - + $receipt = new Receipt(); $tx = $database->get('transactions', ['txid', 'txdate', 'customerid', 'type', 'cashier', 'discountpercent'], ['txid' => $VARS['txid']]); - + // Info $txid = $tx['txid']; $datetime = date(DATETIME_FORMAT, strtotime($tx['txdate'])); $type = $tx['type']; $cashier = getUserByID($tx['cashier'])['name']; $customerid = $tx['customerid']; - $customerline = ""; - if (!is_null($customerid) && !empty($customerid)) { - $customerline = "
Customer: " . $database->get('customers', 'name', ['customerid' => $customerid]); - } - $itemhtml = ""; + // Items + $itemlines = []; $items = $database->select('lines', ['amount', 'name', 'itemid', 'qty'], ['txid' => $txid]); $subtotal = 0.0; $paid = 0.0; foreach ($items as $i) { - $itemhtml .= "\n"; - $itemhtml .= '
'; - $itemhtml .= '
' . $i['name'] . '
'; - $itemhtml .= '
$' . number_format($i['amount'], 2) . '
'; - $itemhtml .= '
x' . (float) $i['qty'] . '
'; - $itemhtml .= '
$' . number_format($i['qty'] * $i['amount'] * 1.0, 2) . '
'; - $itemhtml .= '
'; + $itemlines[] = new ReceiptLine( + $i['name'], (float) $i['qty'] . '@' . number_format($i['amount'], 2), '$' . number_format($i['qty'] * $i['amount'] * 1.0, 2) + ); $subtotal += $i['qty'] * $i['amount'] * 1.0; } + // Payments $total = $subtotal * (1.0 - ((float) $tx['discountpercent'] / 100)); - - $paymenthtml = ""; + $paymentlines = []; $payments = $database->select('payments', [ '[>]payment_types' => ['type' => 'typeid'] ], [ @@ -190,63 +204,54 @@ switch ($VARS['action']) { if ($p['amount'] < 0) { continue; } - $paymenthtml .= "\n"; - $paymenthtml .= '
'; - $paymenthtml .= '
' . lang($p['text'], false) . '
'; - $paymenthtml .= '
$' . number_format($p['amount'] * 1.0, 2) . '
'; - $paymenthtml .= '
'; + $paymentlines[] = new ReceiptLine(lang($p['text'], false), "", '$' . number_format($p['amount'] * 1.0, 2)); $paid += $p['amount'] * 1.0; } - $change = $paid - $total; if ($change <= 0) { $change = 0.0; } - $subtotalstr = number_format($subtotal, 2); - $paidstr = number_format($paid, 2); - $changestr = number_format($change, 2); - $totalstr = $subtotalstr; - $discountstr = ""; - if ($tx['discountpercent'] > 0) { - $discountstr = '
Discount: ' . (float) $tx['discountpercent'] . '% off
'; - $totalstr = number_format($total, 2); - } + // Totals + $subtotalline = new ReceiptLine("Subtotal:", "", '$' . number_format($subtotal, 2)); + $paidline = new ReceiptLine("Paid:", "", '$' . number_format($paid, 2), ReceiptLine::LINEFORMAT_BOLD); + $changeline = new ReceiptLine("Change:", "", '$' . number_format($change, 2), ReceiptLine::LINEFORMAT_BOLD); + $totalline = new ReceiptLine("Total:", "", '$' . number_format($subtotal, 2), ReceiptLine::LINEFORMAT_BOLD); - $html = << - - -Tx #$txid - -
-Date: $datetime
-Tx. ID: $txid
-Cashier: $cashier -$customerline -
-
-$itemhtml -
-
-
Subtotal: $$subtotalstr
-$discountstr -Total: $$totalstr -
-
-$paymenthtml -
-
-Paid: $$paidstr -Change: $$changestr -END; - exit($html); + $receipt->appendLine(new ReceiptLine("Date: $datetime")); + $receipt->appendLine(new ReceiptLine("Tx. ID: $txid")); + $receipt->appendLine(new ReceiptLine("Cashier: $cashier")); + if (!is_null($customerid) && !empty($customerid)) { + $customer = $database->get('customers', 'name', ['customerid' => $customerid]); + $receipt->appendLine(new ReceiptLine("Customer: $customer")); + } + $receipt->appendBreak(); + $receipt->appendLines($itemlines); + $receipt->appendBreak(); + $receipt->appendLine($subtotalline); + if ($tx['discountpercent'] > 0) { + $receipt->appendLine(new ReceiptLine("Discount:", "", (float) $tx['discountpercent'] . '% off')); + $totalline = new ReceiptLine("Total:", "", '$' . number_format($total, 2), ReceiptLine::LINEFORMAT_BOLD); + } + $receipt->appendLine($totalline); + $receipt->appendBreak(); + $receipt->appendLines($paymentlines); + $receipt->appendBreak(); + $receipt->appendLine($paidline); + $receipt->appendLine($changeline); + + $output = ""; + switch ($format) { + case "text": + $output = $receipt->getPlainText($width); + break; + case "json": + $output = $receipt->getJson($width); + break; + default: + $output = $receipt->getHtml("Tx. #$txid"); + } + exit($output); break; case "itemsearch": header("Content-Type: application/json"); diff --git a/lib/receipts.php b/lib/receipts.php new file mode 100644 index 0000000..1374054 --- /dev/null +++ b/lib/receipts.php @@ -0,0 +1,240 @@ +left = $l; + $this->middle = $m; + $this->right = $r; + $this->format = $f; + } + + function getLeft() { + return $this->left; + } + + function getMiddle() { + return $this->middle; + } + + function getRight() { + return $this->right; + } + + function hasFormat($format) { + return ($this->format & $format); + } + + function getHtml() { + if ($this->hasFormat($this::LINEFORMAT_HR)) { + return "
"; + } + $html = ""; + if (!empty($this->left)) { + $html .= '' . htmlspecialchars($this->left) . ' '; + } + if (!empty($this->middle)) { + $html .= '' . htmlspecialchars($this->middle) . ' '; + } + if (!empty($this->right)) { + $html .= '' . htmlspecialchars($this->right) . ''; + } + $classes = ["flex"]; + if ($this->hasFormat($this::LINEFORMAT_BOLD)) { + $classes[] = "bold"; + } + if ($this->hasFormat($this::LINEFORMAT_CENTER)) { + $classes[] = "centered"; + } + $classstr = implode(" ", $classes); + return "
$html
"; + } + + function getPlainText($width) { + if ($this->hasFormat($this::LINEFORMAT_HR)) { + return str_repeat("-", $width); + } + $left = $this->left; + $middle = $this->middle; + $right = $this->right; + $leftln = strlen($left); + $middleln = strlen($middle); + $rightln = strlen($right); + if ($middleln > 0) { + $middleln++; + $middle = " " . $middle; + } + if ($rightln > 0) { + $rightln++; + $right = " " . $right; + } + $strln = $leftln + $middleln + $rightln; + if ($strln < $width) { + if ($this->hasFormat($this::LINEFORMAT_CENTER)) { + return str_pad($left . $middle . $right, $width, " ", STR_PAD_BOTH); + } else { + $middle = str_pad($middle, $width - $leftln - $rightln, " ", STR_PAD_BOTH); + } + } else if ($strln > $width) { + $loseln = $strln - $width; + $left = substr($this->left, 0, $leftln - $loseln); + } + return $left . $middle . $right; + } + + function getArray($width = 64) { + $data = [ + "left" => $this->left, + "middle" => $this->middle, + "right" => $this->right, + "text" => $this->getPlainText($width), + "format" => [] + ]; + if ($this->hasFormat($this::LINEFORMAT_PLAIN)) { + $data['format'][] = "plain"; + } + if ($this->hasFormat($this::LINEFORMAT_BOLD)) { + $data['format'][] = "bold"; + } + if ($this->hasFormat($this::LINEFORMAT_HR)) { + $data['format'][] = "hr"; + } + if ($this->hasFormat($this::LINEFORMAT_CENTER)) { + $data['format'][] = "center"; + } + return $data; + } + +} + +class Receipt { + + private $lines = []; + private $header = []; + private $footer = []; + + function __construct() { + + } + + function appendLine(ReceiptLine $line) { + $this->lines[] = $line; + } + + function appendLines($lines) { + foreach ($lines as $l) { + $this->lines[] = $l; + } + } + + function appendHeader(ReceiptLine $line) { + $this->header[] = $line; + } + + function appendFooter(ReceiptLine $line) { + $this->footer[] = $line; + } + + function appendBreak() { + $this->lines[] = new ReceiptLine("", "", "", ReceiptLine::LINEFORMAT_HR); + } + + function getHtml($title = "") { + global $SECURE_NONCE; + $html = << + + +$title + +END; + if (count($this->header) > 0) { + foreach ($this->header as $line) { + $html .= $line->getHtml() . "\n"; + } + $html .= (new ReceiptLine("", "", "", ReceiptLine::LINEFORMAT_HR))->getHtml(); + } + foreach ($this->lines as $line) { + $html .= $line->getHtml() . "\n"; + } + if (count($this->footer) > 0) { + $html .= (new ReceiptLine("", "", "", ReceiptLine::LINEFORMAT_HR))->getHtml(); + foreach ($this->footer as $line) { + $html .= $line->getHtml() . "\n"; + } + } + return $html; + } + + function getPlainText($width) { + $lines = []; + if (count($this->header) > 0) { + foreach ($this->header as $line) { + $lines[] = $line->getPlainText($width); + } + $lines[] = (new ReceiptLine("", "", "", ReceiptLine::LINEFORMAT_HR))->getPlainText($width); + } + foreach ($this->lines as $line) { + $lines[] = $line->getPlainText($width); + } + if (count($this->footer) > 0) { + $lines[] = (new ReceiptLine("", "", "", ReceiptLine::LINEFORMAT_HR))->getPlainText($width); + foreach ($this->footer as $line) { + $lines[] = $line->getPlainText($width); + } + } + return implode("\n", $lines); + } + + function getArray($width = 64) { + $header = []; + $lines = []; + $footer = []; + foreach ($this->header as $line) { + $header[] = $line->getArray($width); + } + foreach ($this->lines as $line) { + $lines[] = $line->getArray($width); + } + foreach ($this->footer as $line) { + $footer[] = $line->getArray($width); + } + return ["header" => $header, "lines" => $lines, "footer" => $footer]; + } + + function getJson($width = 64) { + return json_encode($this->getArray($width)); + } + +}