<?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;

            if (empty($VARS['items'])) {
                $error = lang("no items", false);
                return false;
            }

            $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 "delete_transaction":
        header("Content-Type: application/json");
        $error = null;
        if (isset($VARS['txid']) && $database->has('transactions', ['txid' => $VARS['txid']])) {
            $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);
            }

            $database->action(function ($database) {
                global $VARS, $binstack, $error, $txid;

                // Delete payments
                $payments = $database->select('payments', ['payid', 'amount', 'type', 'certid'], ['txid' => $txid]);
                foreach ($payments 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']]);
                }

                // Delete items/lines
                $items = $database->select('lines', ['itemid (id)', 'qty', 'lineid'], ['txid' => $txid]);
                foreach ($items as $i) {
                    $database->delete('lines', ['lineid' => $i['lineid']]);
                    $binstack->update('items', [
                        'qty[+]' => $i['qty']
                            ], [
                        'itemid' => $i['id']
                    ]);
                }

                // Delete transaction
                $database->delete('transactions', ['txid' => $txid, 'LIMIT' => 1]);
            });
        } else {
            $error = lang("invalid parameters", false);
        }
        if (!is_null($error)) {
            exit(json_encode(["status" => "ERROR", "message" => $error]));
        } else {
            exit(json_encode(["status" => "OK"]));
        }
        break;
    case "getreceipt":
        require_once __DIR__ . "/lib/generatereceipt.php";
        $format = "html";
        $width = 48;
        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");
        $where = [];
        if (!empty($VARS['q'])) {
            $where["AND"]["OR"] = [
                "txid" => $VARS['q'],
                "name[~]" => $VARS['q'],
                "email[~]" => $VARS['q'],
                "phone[~]" => $VARS['q']
            ];
        }
        $start = date('Y-m-d H:i:s', 946684800); // Jan 1 2000
        $end = date('Y-m-d H:i:s');
        if (!empty($VARS['start']) && strtotime($VARS['start']) !== FALSE) {
            $start = date('Y-m-d H:i:s', strtotime($VARS['start']));
        }
        if (!empty($VARS['end']) && strtotime($VARS['end']) !== FALSE) {
            $end = date('Y-m-d H:i:s', strtotime($VARS['end']));
        }
        $where["AND"]['txdate[>=]'] = $start;
        $where["AND"]['txdate[<=]'] = $end;
        $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 "editcertificate":
        $insert = true;
        $code = $VARS['code'];
        $amount = $VARS['balance'];
        if (empty($VARS['id'])) {
            $insert = true;
        } else {
            if ($database->has('certificates', ['certid' => $VARS['id']])) {
                $insert = false;
            } else {
                returnToSender("invalid_parameters");
            }
        }

        if ($insert && (is_empty($code) || $database->has('certificates', ['certcode' => $code]))) {
            do {
                $code = random_int(100000000000, 999999999999);
            } while ($database->has('certificates', ['certcode' => $code]));
        }

        if (!is_numeric($amount)) {
            returnToSender("invalid_parameters");
        }

        if ($insert) {
            $database->insert('certificates', [
                'certcode' => $code,
                'amount' => $amount,
                'start_amount' => $amount,
                'issued' => date('Y-m-d H:i:s'),
                'deleted' => 0]);
            returnToSender("card_x_added", $code);
        } else {
            $database->update('certificates', [
                'certcode' => $code,
                'amount' => $amount
                    ], [
                'certid' => $VARS['id']
            ]);
            returnToSender("card_x_saved", $code);
        }
        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.");
}