<?php
/* 各API 需有 token_verify() token驗證function ，因各API撈取API金鑰方式不同*/
class WebAPIForMenuPage extends base_class
{


    /**
     * Leo
     * 新增收款資料
     */
    public function Create_received_info($params)
    {
        //設定寫入資料
        $s_cashier_id = (string) $params["cashier"];
        $s_received_start_datetime = (string) $params["start_at"];      //收款起始時間(起始於結束時間中不會有帳務，機台暫停交易)
        $s_received_end_datetime = (string) $params["end_at"];          //收款結束時間
        //判斷是否補入零用金 false: 需補入 true: 不須補入 (例:更換機台時清空舊機台)
        $s_no_Replenish = false;
        if (
            isset($params["no_replenish"]) &&
            trim($params["no_replenish"]) == 1
        ) {
            $s_no_Replenish = true;
        }
        //SCR 紙鈔循環機 收取數量 須轉為負值
        $n_cycle_box_500 = (int) $params["cycle_500"];
        $n_cycle_box_500 = $n_cycle_box_500 * -1;
        $n_cycle_box_100 = (int) $params["cycle_100"];
        $n_cycle_box_100 = $n_cycle_box_100 * -1;
        //硬幣機 循環箱 收取數量 須轉為負值
        $n_cycle_box_50 = (int) $params["cycle_50"];
        $n_cycle_box_50 = $n_cycle_box_50 * -1;
        $n_cycle_box_10 = (int) $params["cycle_10"];
        $n_cycle_box_10 = $n_cycle_box_10 * -1;
        $n_cycle_box_5 = (int) $params["cycle_5"];
        $n_cycle_box_5 = $n_cycle_box_5 * -1;
        $n_cycle_box_1 = (int) $params["cycle_1"];
        $n_cycle_box_1 = $n_cycle_box_1 * -1;
        //SCR 紙鈔循環機 保全箱 收取數量 須轉為負值
        $n_safe_box_1000 = (int) $params["safe_1000"];
        $n_safe_box_1000 = $n_safe_box_1000 * -1;
        $n_safe_box_500 = (int) $params["safe_500"];
        $n_safe_box_500 = $n_safe_box_500 * -1;
        $n_safe_box_100 = (int) $params["safe_100"];
        $n_safe_box_100 = $n_safe_box_100 * -1;
        //硬幣機 溢幣區(保全箱的概念) 收取數量 須轉為負值
        $n_safe_box_50 = (int) $params["safe_50"];
        $n_safe_box_50 = $n_safe_box_50 * -1;
        $n_safe_box_10 = (int) $params["safe_10"];
        $n_safe_box_10 = $n_safe_box_10 * -1;
        $n_safe_box_5 = (int) $params["safe_5"];
        $n_safe_box_5 = $n_safe_box_5 * -1;
        $n_safe_box_1 = (int) $params["safe_1"];
        $n_safe_box_1 = $n_safe_box_1 * -1;
        //LCDM出鈔機 收取數量 須轉為負值
        $n_sub_500_out = (int) $params["sub_500_out"];
        $n_sub_500_out = $n_sub_500_out * -1;
        $n_sub_100_out = (int) $params["sub_100_out"];
        $n_sub_100_out = $n_sub_100_out * -1;
        //TP70入鈔機 收取數量 須轉為負值
        $n_sub_1000_in = (int) $params["sub_1000_in"];
        $n_sub_1000_in = $n_sub_1000_in * -1;
        $n_sub_500_in = (int) $params["sub_500_in"];
        $n_sub_500_in = $n_sub_500_in * -1;
        $n_sub_100_in = (int) $params["sub_100_in"];
        $n_sub_100_in = $n_sub_100_in * -1;

        $n_operate_type = 3; //操作類型 1.溢幣 2. 純補入 3.換補(收款) 4.無交易貨幣異動(機台測試或其他操作)

        //step.1 先查詢門市零用金資訊 (換補時機台會直接補入當前資料庫內設定的零用金數量，因此需先查詢各面額零用金數量後來計算差異
        $sql = sprintf(
            "SELECT 
                    _c.store_id,
                    _s.petty_cash_500,
                    _s.petty_cash_100,
                    _s.petty_cash_50,
                    _s.petty_cash_10,
                    _s.petty_cash_5,
                    _s.petty_cash_1

			FROM 	
				[%s].[dbo].[cashier] AS _c 
                LEFT JOIN [%s].[dbo].[store] AS _s ON _s.store_id = _c.store_id
			WHERE
                _c.cashier_id = :cashier_id
			",
            $this->database_trend,
            $this->database_trend
        );
        //準備執行sql
        $sth = $this->pdo_sql->prepare($sql);
        $sth->execute([
            "cashier_id" => $s_cashier_id
        ]);
        $row = $sth->fetch(PDO::FETCH_ASSOC);
        $n_store_id = $row["store_id"];
        //各面額零用金 判斷是否為不需補入零用金 如果不用補入 則零用金數量填入0
        $n_petty_cash_500 = $s_no_Replenish ? 0 : $row["petty_cash_500"];
        $n_petty_cash_100 = $s_no_Replenish ? 0 : $row["petty_cash_100"];
        $n_petty_cash_50 = $s_no_Replenish ? 0 : $row["petty_cash_50"];
        $n_petty_cash_10 = $s_no_Replenish ? 0 : $row["petty_cash_10"];
        $n_petty_cash_5 = $s_no_Replenish ? 0 : $row["petty_cash_5"];
        $n_petty_cash_1 = $s_no_Replenish ? 0 : $row["petty_cash_1"];
        //差異量計算是根據零用金實際補入哪一個機台硬幣/紙鈔設備而定
        //目前鈔票類是補入LCDM出鈔機、硬幣類是補入硬幣循環箱
        // //差異量計算-硬幣循環箱
        // $n_cycle_box_50 = $n_petty_cash_50 + $n_cycle_box_50;
        // $n_cycle_box_10 = $n_petty_cash_10 + $n_cycle_box_10;
        // $n_cycle_box_5 = $n_petty_cash_5 + $n_cycle_box_5;
        // $n_cycle_box_1 = $n_petty_cash_1 + $n_cycle_box_1;
        // //差異量計算-LCDM出鈔機
        // $n_sub_500_out = $n_petty_cash_500 + $n_sub_500_out;
        // $n_sub_100_out = $n_petty_cash_100 + $n_sub_100_out;


        //step.2 根據收款起始時間來撈取收款區間的所有物流帳務明細序號，以利後續進行更新收款日期、收款編號、交易狀態、收款總金額
        $sql = sprintf(
            "SELECT 
                    _sts.transaction_statement_sno AS sno
                FROM
                    [%s].[dbo].[store_transaction_statement] AS _sts
                WHERE
                    _sts.store_id = :store_id
                    AND _sts.cashier_id = :cashier_id
                    AND _sts.transaction_end_at <= :received_at
                    AND _sts.received_at IS NULL",
            $this->database_trend
        );
        //準備執行sql
        $sth = $this->pdo_sql->prepare($sql);
        $sth->execute([
            "cashier_id" => $s_cashier_id,
            "store_id" => $n_store_id,
            "received_at" => $s_received_start_datetime,
        ]);
        $row = $sth->fetchAll(PDO::FETCH_ASSOC);
        //物流資料序號(用來更新的
        $a_update_transaction_statement_sno = [];
        $s_update_transaction_statement_sno = "";
        if (!empty($row)) {
            foreach ($row as $k => $v) {
                //序號
                $a_update_transaction_statement_sno[] = $v["sno"];
            }
            $s_update_transaction_statement_sno = implode(",", $a_update_transaction_statement_sno);
        }

        //建立收款編號、收款起始時間、收款結束時間
        $s_received_ledger_id = MD5(strtotime($s_received_start_datetime) + $n_store_id);
        $s_received_date = date("Y-m-d", strtotime($s_received_start_datetime));
        $s_received_start_time = date("H:i:s", strtotime($s_received_start_datetime));
        $s_received_end_time = date("H:i:s", strtotime($s_received_end_datetime));

        //step.3 取得每日收款明細資料、統計該次收款的金額 (理論上來說 收款當日不會有當日的收款明細 需另外依據收款起始時間統計當日收款明細)
        $sql = sprintf(
            "SELECT 
                    _srs.received_statement_id AS sno
                    ,_srs.logistics_amount
                    ,_srs.commodity_amount
                FROM
                    [%s].[dbo].[store_received_statement] AS _srs
                WHERE
                    _srs.store_id = :store_id
                    AND _srs.business_at <= :business_at
                    AND _srs.received_at IS NULL",
            $this->database_trend
        );
        //準備執行sql
        $sth = $this->pdo_sql->prepare($sql);
        $sth->execute([
            "store_id" => $n_store_id,
            "business_at" => $s_received_start_datetime,
        ]);
        $row = $sth->fetchAll(PDO::FETCH_ASSOC);
        //每日收款明細資料序號(用來更新的
        $a_update_received_statement_sno = [];
        $s_update_received_statement_sno = "";
        //物流總金額
        $n_logistics_amount_total = 0;
        //商品總金額
        $n_commodity_amount_total = 0;
        if (!empty($row)) { //理論上來說要有帳務才會有收款動作
            foreach ($row as $k => $v) {
                //明細序號
                $a_update_received_statement_sno[] = $v["sno"];
                //物流總金額
                $n_logistics_amount_total = bcadd($n_logistics_amount_total, $v["logistics_amount"], 0);
                //商品總金額
                $n_commodity_amount_total = bcadd($n_commodity_amount_total, $v["commodity_amount"], 0);
            }
            $s_update_received_statement_sno = implode(",", $a_update_received_statement_sno);
        }

        //取得當日收款明細的資料(當日時間00:01:00至收款開始時間之區間所有帳務)
        $sql = sprintf(
            "SELECT 
                CONVERT ( VARCHAR ( 20 ), _sts.transaction_end_at, 23 ) AS business_date
                ,SUM ( _sts.order_amount ) AS logistics_amount
                ,_sts.store_id
            FROM
                [%s].[dbo].[store_transaction_statement] AS _sts
            WHERE
                _sts.store_id = :store_id
                AND _sts.transaction_end_at BETWEEN :start_time AND :end_time
                AND _sts.received_at IS NULL
            GROUP BY
	            CONVERT ( VARCHAR ( 20 ), _sts.transaction_end_at, 23 )
                ,_sts.store_id",
            $this->database_trend
        );
        //準備執行sql
        $sth = $this->pdo_sql->prepare($sql);
        $sth->execute([
            "store_id" => $n_store_id,
            "start_time" => $s_received_date . " 00:01:00",
            "end_time" => $s_received_start_datetime,
        ]);
        $row = $sth->fetch(PDO::FETCH_ASSOC);
        //設定收款當日物總金額
        $n_today_logistics_amount = 0;
        if (!empty($row)) {
            $n_today_logistics_amount = $row["logistics_amount"];
        }
        //收款物流總金額加總
        $n_logistics_amount_total = bcadd($n_logistics_amount_total, $n_today_logistics_amount, 0);

        //先判斷收款明細與當日收款明細是否有資料 若都沒資料則異常 (依據更新物流明細序號清單與收款明細序號清單來判斷 都為空則代表沒有任何交易紀錄)
        /*if (
            $s_update_transaction_statement_sno == "" &&
            $s_update_received_statement_sno == ""
        ) {
            throw new Exception("該門市尚未有任何交易資料可供收款", 30);
        }*/

        //開始更新 beginTransaction
        $this->pdo_sql->beginTransaction();
        //收款總帳資料新增區塊 => store_received_ledger 表
        $sql = sprintf(
            "INSERT INTO [%s].[dbo].[store_received_ledger] (
                    [received_ledger_id],
                    [store_id],
                    [received_at],
                    [received_start_at],
                    [received_end_at],
                    [logistics_amount_total]
                )
                VALUES
                    (
                        :received_ledger_id,
                        :store_id,
                        :received_at,
                        :received_start_at,
                        :received_end_at,
                        :logistics_amount_total
                    );",
            $this->database_trend
        );
        $sth = $this->pdo_sql->prepare($sql);
        $sth->execute([
            "received_ledger_id" => $s_received_ledger_id,
            "store_id" => $n_store_id,
            "received_at" => $s_received_date,
            "received_start_at" => $s_received_start_time,
            "received_end_at" => $s_received_end_time,
            "logistics_amount_total" => $n_logistics_amount_total,
        ]);
        if ($sth->rowCount() == 0) {
            $this->pdo_sql->rollBack();
            throw new Exception("store_received_ledger寫入失敗", 40);
        }
        //收款當日明細資料新增區塊 => store_received_statement 表
        $sql = sprintf(
            "INSERT INTO [%s].[dbo].[store_received_statement] (
                     [received_ledger_id]
                    ,[store_id]
                    ,[logistics_amount]
                    ,[received_at]
                    ,[business_at]
                )
                VALUES
                    (
                         :received_ledger_id
                        ,:store_id
                        ,:logistics_amount
                        ,:received_at
                        ,:business_at
                    );",
            $this->database_trend
        );
        $sth = $this->pdo_sql->prepare($sql);
        $sth->execute([
            "received_ledger_id" => $s_received_ledger_id,
            "store_id" => $n_store_id,
            "logistics_amount" => $n_today_logistics_amount,
            "received_at" => $s_received_date,
            "business_at" => $s_received_date,
        ]);
        if ($sth->rowCount() == 0) {
            $this->pdo_sql->rollBack();
            throw new Exception("store_received_statement寫入失敗", 40);
        }

        //收款明細資料更新區塊 => store_received_statement 表 (不一定需要更新，有可能沒有過往的每日收款明細，例如第一天建立時測試收款)
        if ($s_update_received_statement_sno != "") {
            $sql = sprintf(
                "UPDATE [%s].[dbo].[store_received_statement] 
                        SET
                            [received_ledger_id] = :received_ledger_id
                            ,[received_at] = :received_at
                        WHERE
                            received_statement_id IN (%s);",
                $this->database_trend,
                $s_update_received_statement_sno
            );
            $sth = $this->pdo_sql->prepare($sql);
            $sth->execute([
                "received_ledger_id" => $s_received_ledger_id,
                "received_at" => $s_received_date,
            ]);
            if ($sth->rowCount() == 0) {
                $this->pdo_sql->rollBack();
                throw new Exception("store_received_statement更新失敗", 40);
            }
        }
        //物流資料更新區塊 (狀態變更已收款、寫入收款日期與收款編號 => store_transaction_statement 表
        if ($s_update_transaction_statement_sno != "") {
            $sql = sprintf(
                "UPDATE [%s].[dbo].[store_transaction_statement] 
                                SET
                                [received_ledger_id] = :received_ledger_id,
                                [trading_status] = N'已收款',
                                [received_at] = :received_start_datetime
                                WHERE
                                    [transaction_statement_sno] IN (%s)",
                $this->database_trend,
                $s_update_transaction_statement_sno
            );
            $sth = $this->pdo_sql->prepare($sql);
            $sth->execute([
                "received_ledger_id" => $s_received_ledger_id,
                "received_start_datetime" => $s_received_start_datetime,
            ]);
            if ($sth->rowCount() == 0) {
                $this->pdo_sql->rollBack();
                throw new Exception("store_transaction_statement寫入失敗", 40);
            }
        }
        //現金異動資料寫入區塊 => cashier_currency_statement 表
        //2024/04/08 調整成寫入兩筆 一筆修改前 一筆修改後
        //修改前
        $sql = sprintf(
            "INSERT INTO [%s].[dbo].[cashier_currency_statement](
                    cashier_id,
                    store_id,
                    create_at,
                    safe_box_1000,
                    safe_box_500,
                    safe_box_100,
                    safe_box_50,
                    safe_box_10,
                    safe_box_5,
                    safe_box_1,
                    cycle_box_500,
                    cycle_box_100,
                    cycle_box_50,
                    cycle_box_10,
                    cycle_box_5,
                    cycle_box_1,
                    sub_1000_in,
                    sub_500_in,
                    sub_100_in,
                    sub_500_out,
                    sub_100_out,
                    operate_type
                )
                VALUES
                (
                    :cashier_id,
                    :store_id,
                    :create_at,
                    :safe_box_1000,
                    :safe_box_500,
                    :safe_box_100,
                    :safe_box_50,
                    :safe_box_10,
                    :safe_box_5,
                    :safe_box_1,
                    :cycle_box_500,
                    :cycle_box_100,
                    :cycle_box_50,
                    :cycle_box_10,
                    :cycle_box_5,
                    :cycle_box_1,
                    :sub_1000_in,
                    :sub_500_in,
                    :sub_100_in,
                    :sub_500_out,
                    :sub_100_out,
                    :operate_type
                )
                ",
            $this->database_trend
        );
        $sth = $this->pdo_sql->prepare($sql);
        $sth->execute([
            "cashier_id" => $s_cashier_id,
            "store_id" => $n_store_id,
            "create_at" => $s_received_end_datetime,
            "safe_box_1000" => $n_safe_box_1000,
            "safe_box_500" => $n_safe_box_500,
            "safe_box_100" => $n_safe_box_100,
            "safe_box_50" => $n_safe_box_50,
            "safe_box_10" => $n_safe_box_10,
            "safe_box_5" => $n_safe_box_5,
            "safe_box_1" => $n_safe_box_1,
            "cycle_box_500" => $n_cycle_box_500,
            "cycle_box_100" => $n_cycle_box_100,
            "cycle_box_50" => $n_cycle_box_50,
            "cycle_box_10" => $n_cycle_box_10,
            "cycle_box_5" => $n_cycle_box_5,
            "cycle_box_1" => $n_cycle_box_1,
            "sub_1000_in" => $n_sub_1000_in,
            "sub_500_in" => $n_sub_500_in,
            "sub_100_in" => $n_sub_100_in,
            "sub_500_out" => $n_sub_500_out,
            "sub_100_out" => $n_sub_100_out,
            "operate_type" => $n_operate_type,
        ]);
        if ($sth->rowCount() == 0) {
            $this->pdo_sql->rollBack();
            throw new Exception("cashier_currency_statement寫入失敗", 40);
        }
        //修改後

        $sql = sprintf(
            "INSERT INTO [%s].[dbo].[cashier_currency_statement](
                        cashier_id,
                        store_id,
                        create_at,
                        cycle_box_50,
                        cycle_box_10,
                        cycle_box_5,
                        cycle_box_1,
                        sub_500_out,
                        sub_100_out,
                        operate_type
                    )
                    VALUES
                    (
                        :cashier_id,
                        :store_id,
                        :create_at,
                        :cycle_box_50,
                        :cycle_box_10,
                        :cycle_box_5,
                        :cycle_box_1,
                        :sub_500_out,
                        :sub_100_out,
                        :operate_type
                    )
                    ",
            $this->database_trend
        );
        $sth = $this->pdo_sql->prepare($sql);
        $sth->execute([
            "cashier_id" => $s_cashier_id,
            "store_id" => $n_store_id,
            "create_at" => $s_received_end_datetime,
            "cycle_box_50" => $n_petty_cash_50,
            "cycle_box_10" => $n_petty_cash_10,
            "cycle_box_5" => $n_petty_cash_5,
            "cycle_box_1" => $n_petty_cash_1,
            "sub_500_out" => $n_petty_cash_500,
            "sub_100_out" => $n_petty_cash_100,
            "operate_type" => $n_operate_type,
        ]);
        if ($sth->rowCount() == 0) {
            $this->pdo_sql->rollBack();
            throw new Exception("cashier_currency_statement寫入失敗", 40);
        }

        $this->pdo_sql->commit();
        return "OK";
    }
    /**
     * Leo
     * api 驗證
     */
    public function api_verify($token, $params)
    {
        //門市編號
        $n_store_id = (int) $params["store"];
        if ($n_store_id == 0) { //門市編號為空
            throw new Exception("store 欄位不可為空", 91000);
        } else {    //檢查門市是否存在
            $sql = sprintf(
                "SELECT 
                        _s.store_id
                FROM 	
                    [%s].[dbo].[store] AS _s 
                WHERE
                    _s.store_id = :store_id ",
                $this->database_trend
            );
            //準備執行sql
            $sth = $this->pdo_sql->prepare($sql);
            $sth->execute([
                "store_id" => $n_store_id
            ]);
            $row = $sth->fetch(PDO::FETCH_ASSOC);
            if (empty($row)) {
                throw new Exception("store 異常", 91000);
            }
        }
        //機台序號
        $s_cashier_id = (string) $params["cashier"];
        if ($s_cashier_id == "") { //機台編號為空
            throw new Exception("cashier 欄位不可為空", 91000);
        } else { //檢查機台是否存在
            $sql = sprintf(
                "SELECT 
                        _c.cashier_id
                FROM 	
                    [%s].[dbo].[cashier] AS _c
                WHERE
                    _c.cashier_id = :cashier_id ",
                $this->database_trend
            );
            //準備執行sql
            $sth = $this->pdo_sql->prepare($sql);
            $sth->execute([
                "cashier_id" => $s_cashier_id
            ]);
            $row = $sth->fetch(PDO::FETCH_ASSOC);
            if (empty($row)) {
                throw new Exception("查無機台", 91000);
            }
        }
        //時間戳(單位秒)
        $s_send_at = (string) $params["send_at"];
        if ($s_send_at == "") { //時間戳為空
            throw new Exception("send_at 欄位不可為空", 91000);
        } else if ($this->check_timestamp_format($s_send_at) != true) {
            throw new Exception("send_at 時間戳格式不正確", 91000);
        }
        //Token
        if (trim($token) == "") { //Token為空
            throw new Exception("token 欄位不可為空", 91000);
        }
        //保全箱收取數量-1000
        $n_safe_1000 = (int) $params["safe_1000"];
        if (!isset($params["safe_1000"])) { // 保全箱收取數量-1000為空
            throw new Exception("safe_1000 欄位不可為空", 91000);
        } else if ($n_safe_1000 < 0) {
            throw new Exception("safe_1000 欄位不可小於零", 91000);
        }
        //保全箱收取數量-500
        $n_safe_500 = (int) $params["safe_500"];
        if (!isset($params["safe_500"])) { // 保全箱收取數量-500為空
            throw new Exception("safe_500 欄位不可為空", 91000);
        } else if ($n_safe_500 < 0) {
            throw new Exception("safe_500 欄位不可小於零", 91000);
        }
        //保全箱收取數量-100
        $n_safe_100 = (int) $params["safe_100"];
        if (!isset($params["safe_100"])) { // 保全箱收取數量-100為空
            throw new Exception("safe_100 欄位不可為空", 91000);
        } else if ($n_safe_100 < 0) {
            throw new Exception("safe_100 欄位不可小於零", 91000);
        }
        //保全箱收取數量-50
        $n_safe_50 = (int) $params["safe_50"];
        if (!isset($params["safe_50"])) { // 保全箱收取數量-50為空
            throw new Exception("safe_50 欄位不可為空", 91000);
        } else if ($n_safe_50 < 0) {
            throw new Exception("safe_50 欄位不可小於零", 91000);
        }
        //保全箱收取數量-10
        $n_safe_10 = (int) $params["safe_10"];
        if (!isset($params["safe_10"])) { // 保全箱收取數量-10為空
            throw new Exception("safe_10 欄位不可為空", 91000);
        } else if ($n_safe_10 < 0) {
            throw new Exception("safe_10 欄位不可小於零", 91000);
        }
        //保全箱收取數量-5
        $n_safe_5 = (int) $params["safe_5"];
        if (!isset($params["safe_5"])) { // 保全箱收取數量-5為空
            throw new Exception("safe_5 欄位不可為空", 91000);
        } else if ($n_safe_5 < 0) {
            throw new Exception("safe_5 欄位不可小於零", 91000);
        }
        //保全箱收取數量-1
        $n_safe_1 = (int) $params["safe_1"];
        if (!isset($params["safe_1"])) { // 保全箱收取數量-1為空
            throw new Exception("safe_1 欄位不可為空", 91000);
        } else if ($n_safe_1 < 0) {
            throw new Exception("safe_1 欄位不可小於零", 91000);
        }
        //循環箱差異數量-500
        $n_cycle_500 = (int) $params["cycle_500"];
        if (!isset($params["cycle_500"])) { // 循環箱差異數量-500為空
            throw new Exception("cycle_500 欄位不可為空", 91000);
        } else if ($n_cycle_500 < 0) {
            throw new Exception("cycle_500 欄位不可小於零", 91000);
        }
        //循環箱差異數量-100
        $n_cycle_100 = (int) $params["cycle_100"];
        if (!isset($params["cycle_100"])) { // 循環箱差異數量-100為空
            throw new Exception("cycle_100 欄位不可為空", 91000);
        } else if ($n_cycle_100 < 0) {
            throw new Exception("cycle_100 欄位不可小於零", 91000);
        }
        //循環箱差異數量-50
        $n_cycle_50 = (int) $params["cycle_50"];
        if (!isset($params["cycle_50"])) { // 循環箱差異數量-50為空
            throw new Exception("cycle_50 欄位不可為空", 91000);
        } else if ($n_cycle_50 < 0) {
            throw new Exception("cycle_50 欄位不可小於零", 91000);
        }
        //循環箱差異數量-10
        $n_cycle_10 = (int) $params["cycle_10"];
        if (!isset($params["cycle_10"])) { // 循環箱差異數量-10為空
            throw new Exception("cycle_10 欄位不可為空", 91000);
        } else if ($n_cycle_10 < 0) {
            throw new Exception("cycle_10 欄位不可小於零", 91000);
        }
        //循環箱差異數量-5
        $n_cycle_5 = (int) $params["cycle_5"];
        if (!isset($params["cycle_5"])) { // 循環箱差異數量-5為空
            throw new Exception("cycle_5 欄位不可為空", 91000);
        } else if ($n_cycle_5 < 0) {
            throw new Exception("cycle_5 欄位不可小於零", 91000);
        }
        //循環箱差異數量-1
        $n_cycle_1 = (int) $params["cycle_1"];
        if (!isset($params["cycle_1"])) { // 循環箱差異數量-1為空
            throw new Exception("cycle_1 欄位不可為空", 91000);
        } else if ($n_cycle_1 < 0) {
            throw new Exception("cycle_1 欄位不可小於零", 91000);
        }
        //備用入鈔機-1000 收取數量 (TP70入鈔機)
        $n_sub_1000_in = (int) $params["sub_1000_in"];
        if (!isset($params["sub_1000_in"])) { // 備用入鈔機-1000 收取數量 為空
            throw new Exception("sub_1000_in 欄位不可為空", 91000);
        } else if ($n_sub_1000_in < 0) {
            throw new Exception("sub_1000_in 欄位不可小於零", 91000);
        }
        //備用入鈔機-500 收取數量 (TP70入鈔機)
        $n_sub_500_in = (int) $params["sub_500_in"];
        if (!isset($params["sub_500_in"])) { // 備用入鈔機-500 收取數量 為空
            throw new Exception("sub_500_in 欄位不可為空", 91000);
        } else if ($n_sub_500_in < 0) {
            throw new Exception("sub_500_in 欄位不可小於零", 91000);
        }
        //備用入鈔機-100 收取數量 (TP70入鈔機)
        $n_sub_100_in = (int) $params["sub_100_in"];
        if (!isset($params["sub_100_in"])) { // 備用入鈔機-100 收取數量 為空
            throw new Exception("sub_100_in 欄位不可為空", 91000);
        } else if ($n_sub_100_in < 0) {
            throw new Exception("sub_100_in 欄位不可小於零", 91000);
        }
        //備用出鈔機 收取數量-500 (LCDM出鈔機)
        $n_sub_500_out = (int) $params["sub_500_out"];
        if (!isset($params["sub_500_out"])) { // 備用出鈔機 差異數量-500 為空
            throw new Exception("sub_500_out 欄位不可為空", 91000);
        } else if ($n_sub_500_out < 0) {
            throw new Exception("sub_500_out 欄位不可小於零", 91000);
        }
        //備用出鈔機 收取數量-100 (LCDM出鈔機)
        $n_sub_100_out = (int) $params["sub_100_out"];
        if (!isset($params["sub_100_out"])) { // 備用出鈔機 差異數量-100 為空
            throw new Exception("sub_100_out 欄位不可為空", 91000);
        } else if ($n_sub_100_out < 0) {
            throw new Exception("sub_100_out 欄位不可小於零", 91000);
        }

        //收款開始時間
        $s_start_at = (string) $params["start_at"];
        if ($s_start_at == "") { // 收款開始時間為空
            throw new Exception("start_at 欄位不可為空", 91000);
        } else if ($this->check_date_format($s_start_at) != true) { //時間格式不正確
            throw new Exception("start_at 時間格式不正確", 91000);
        }
        //收款結束時間
        $s_end_at = (string) $params["end_at"];
        if ($s_end_at == "") { // 收款結束時間為空
            throw new Exception("end_at 欄位不可為空", 91000);
        } else if ($this->check_date_format($s_end_at) != true) { //時間格式不正確
            throw new Exception("end_at 時間格式不正確", 91000);
        }



        //依據資料查詢門市API金鑰來進行Token驗證
        $sql = sprintf(
            "SELECT 
                    _s.store_api_key,
                    _c.cashier_id
            FROM 	
                 [%s].[dbo].[cashier] AS _c
                 LEFT JOIN [%s].[dbo].[store] AS _s ON _s.store_id = _c.store_id
            WHERE
                _c.store_id = :store_id AND
                _c.cashier_id = :cashier_id",
            $this->database_trend,
            $this->database_trend
        );
        //準備執行sql
        $sth = $this->pdo_sql->prepare($sql);
        $sth->execute([
            "store_id" => $n_store_id,
            "cashier_id" => $s_cashier_id
        ]);
        $row = $sth->fetch(PDO::FETCH_ASSOC);
        if (!empty($row)) {
            $s_api_key = $row["store_api_key"];
            if ($this->shopee_api_token_verify($token, $s_api_key, $s_send_at) != true) {
                throw new Exception("Token 驗證失敗", 91001);
            }
        } else {
            //查詢不到該門市該機台
            throw new Exception("門市與機台尚未綁定", 91000);
        }
        //更新最後連線時間
        $this->cashier_connect_time_update($n_store_id, $s_cashier_id, $s_send_at);
    }
}
