diff --git a/config/constants.php b/config/constants.php new file mode 100644 index 0000000..3d02c2b --- /dev/null +++ b/config/constants.php @@ -0,0 +1,157 @@ +router->fetch_method(); + if (in_array($method_name, array('cmd_101', 'cmd_102'))) + { + ob_end_clean(); + ignore_user_abort(); + ob_start(); + header('Connection: close'); + header('Content-Length: ' . ob_get_length()); + ob_end_flush(); + flush(); + } + + ignore_user_abort(); // 接受client斷線, 繼續run + + $this->vars['date_time'] = date('Y-m-d H:i:s'); // 格式化時間(2015-10-12 14:36:21) + $this->vars['time_num'] = str_replace(array('-', ':', ' '), '', $this->vars['date_time']); //數字化時間(20151012143621) + $this->vars['date_num'] = substr($this->vars['time_num'], 0, 8); // 數字化日期(20151012) + $this->vars['station_no'] = STATION_NO; // 本站編號 + + // session_id(ip2long($_SERVER['REMOTE_ADDR'])); // 設定同一device為同一個session + session_start(); + + // ----- 程式開發階段log設定 ----- + if (@ENVIRONMENT == 'development') + { + ini_set('display_errors', '1'); + //error_reporting(E_ALL ^ E_NOTICE); + error_reporting(E_ALL); + } + set_error_handler(array($this, 'error_handler'), E_ALL); // 資料庫異動需做log + + $this->load->model('acer_service_model'); + $this->acer_service_model->init($this->vars); + + // 阻檔未知的 IP + if(!in_array($_SERVER['HTTP_X_REAL_IP'], array('127.0.0.1'))) + { + trigger_error('refused://from:'.$_SERVER['HTTP_X_REAL_IP'].'..refused..'); + exit; + } + } + + + // 發生錯誤時集中在此處理 + public function error_handler($errno, $errstr, $errfile, $errline, $errcontext) + { + $log_msg = explode('://', $errstr); + if (count($log_msg) > 1) + { + $log_file = $log_msg[0]; + $str = date('H:i:s')."|{$log_msg[1]}|{$errfile}|{$errline}|{$errno}\n"; + } + else + { + $log_file = APP_NAME; + $str = date('H:i:s')."|{$errstr}|{$errfile}|{$errline}|{$errno}\n"; + } + + error_log($str, 3, LOG_PATH.$log_file . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + } + + + // 顯示logs + public function show_logs() + { + $lines = $this->uri->segment(3); // 顯示行數 + if (empty($lines)) $lines = 100; // 無行數參數, 預設為40行 + + // echo '
'; + echo ''; + + passthru('/usr/bin/tail -n ' . $lines . ' ' . LOG_PATH.APP_NAME . '.' . date('Ymd').'.log.txt'); // 利用linux指令顯示倒數幾行的logs內容 + echo "\n----- " . LOG_PATH.APP_NAME . '.' . date('Ymd').'.log.txt' . ' -----'; + echo ''; + } + + + // 票卡入場訊號,供 ALTOB 登記 + public function cmd_001() + { + $card_no = $this->input->post('card_no', true); + $cario_no = $this->input->post('cario_no', true); + $card_type = $this->input->post('card_type', true); + + trigger_error(__FUNCTION__ . ", card_no:{$card_no}, cario_no:{$cario_no}, card_type:{$card_type}"); + + $data = $this->acer_service_model->cmd_001($card_no, $cario_no, $card_type); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 票卡離場訊號,供 ALTOB 登記 + public function cmd_002() + { + $card_no = $this->input->post('card_no', true); + $pay_time = $this->input->post('pay_time', true); + $card_type = $this->input->post('card_type', true); + + trigger_error(__FUNCTION__ . ", card_no:{$card_no}, pay_time:{$pay_time}, card_type:{$card_type}"); + + $data = $this->acer_service_model->cmd_002($card_no, $pay_time, $card_type); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 票號離場訊號,回傳若成功觸發 ACER 開門 + public function cmd_003() + { + $ticket_no = $this->input->post('ticket_no', true); + + trigger_error(__FUNCTION__ . ", ticket_no:{$ticket_no}"); + + $data = $this->acer_service_model->cmd_003($ticket_no); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 車辨入場訊號,觸發 ACER 開門 + public function cmd_101() + { + $cario_no = $this->input->post('cario_no', true); + $in_time = $this->input->post('in_time', true); + $ticket_no = $this->input->post('ticket_no', true); + $lpr = $this->input->post('lpr', true); + $ivs_no = $this->input->post('ivs_no', true); + + trigger_error(__FUNCTION__ . ", cario_no:{$cario_no}, in_time:{$in_time}, ticket_no:{$ticket_no}, lpr:{$lpr}, ivs_no:{$ivs_no}"); + + $data = $this->acer_service_model->cmd_101($cario_no, $in_time, $ticket_no, $lpr, $ivs_no); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 車辨離場訊號,觸發 ACER 開門 (若入場編號為 0, 表示車辨失敗) + public function cmd_102() + { + $cario_no = $this->input->post('cario_no', true); + $ivs_no = $this->input->post('ivs_no', true); + $msg_code = $this->input->post('msg_code', true); + + /* msg_code: + 1 離場車辨失敗 + 2 離場會員鎖車 + 5 會員車離場 + 6 臨停車離場 (時間內離場, 已繳費) + 7 臨停車離場 (超過離場時限, 歐pa卡繳費) + 8 臨停車未付款 (時間內離場, 無繳費) + 9 臨停車未付款 (超過離場時限, 非歐pa卡會員) + 10 會員車離場 (無入場資料) + 12 臨停車未付款 (超過離場時限, 歐pa卡餘額不足) + 13 無入場記錄 + 16 時段月租戶超時(月租) + */ + + trigger_error(__FUNCTION__ . ", cario_no:{$cario_no}, ivs_no:{$ivs_no}, msg_code:{$msg_code}"); + + $data = $this->acer_service_model->cmd_102($cario_no, $ivs_no, $msg_code); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + + + + + + + + // 測試 acer cmd 101 + public function test_acer_cmd_101() + { + // input + $cario_no = '1234567890'; // 入場編號: 10 碼 + $in_time = '2017-04-25 15:15:15'; // 入場時間: 19碼 + $ticket_no = '123456'; // 六碼數字 + $lpr = 'ABC123'; + $ivsno = 1; // 車道編號 + + $data = $this->acer_service_model->cmd_101($cario_no, $in_time, $ticket_no, $lpr, $ivsno); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 測試 acer cmd 102 + public function test_acer_cmd_102() + { + // input + $cario_no = '1234567890'; // 入場編號: 10 碼 + $ivsno = 1; // 車道編號 + + $data = $this->acer_service_model->cmd_102($cario_no, $ivsno); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + +} diff --git a/controllers/Admins_station.php b/controllers/Admins_station.php new file mode 100644 index 0000000..f69579e --- /dev/null +++ b/controllers/Admins_station.php @@ -0,0 +1,1102 @@ +vars['mcache'] = new Memcache; + $this->vars['mcache']->connect(MEMCACHE_HOST, MEMCACHE_PORT) or die ('Could not connect memcache'); + + // mqtt subscribe + $this->vars['mqtt'] = new phpMQTT(MQ_HOST, MQ_PORT, uniqid()); + + if(!$this->vars['mqtt']->connect()){ die ('Could not connect mqtt'); } + + // 中控 + $this->load->model('admins_station_model'); + $this->admins_station_model->init($this->vars); + + // 臨停 + $this->load->model('carpayment_model'); + $this->carpayment_model->init($this->vars); + + // 費率 + $this->load->model('txdata_model'); + + // 報表 + $this->load->model('excel_model'); + $this->excel_model->init($this->vars); + } + + + // 發生錯誤時集中在此處理 + public function error_handler($errno, $errstr, $errfile, $errline, $errcontext) + { + // ex: car_err://message.... + $log_msg = explode('://', $errstr); + if (count($log_msg) > 1) + { + $log_file = LOG_PATH.$log_msg[0]; + $str = date('H:i:s')."|{$log_msg[1]}|{$errfile}|{$errline}|{$errno}\n"; + } + else + { + $log_file = LOG_PATH.APP_NAME; + $str = date('H:i:s')."|{$errstr}|{$errfile}|{$errline}|{$errno}\n"; + } + + //$str = date('H:i:s')."|{$errstr}|{$errfile}|{$errline}|{$errno}\n"; + error_log($str, 3, $log_file . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + } + + + // 顯示靜態網頁(html檔) + protected function show_page($page_name, &$data = null) + { + $page_file = PAGE_PATH.$page_name.'.php'; + $last_modified_time = filemtime($page_file); + + /* + // Cross-Origin Resource Sharing Header(允許跨網域連線) + header('Access-Control-Allow-Origin: ' . SERVER_URL); + header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS'); + header('Access-Control-Allow-Headers: X-Requested-With, Content-Type, Accept'); + */ + + // 若檔案修改時間沒有異動, 或版本無異動, 通知瀏覽器使用cache, 不再下傳網頁 + // header('Cache-Control:max-age='.MAX_AGE); // cache 1個月 + header('Last-Modified: '.gmdate('D, d M Y H:i:s', $last_modified_time).' GMT'); + header('Etag: '. APP_VERSION); + header('Cache-Control: public'); + + if (!empty($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == APP_VERSION && @strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time) + { + header('HTTP/1.1 304 Not Modified'); + } + else + { + $this->load->view(APP_NAME.'/'.$page_name, $data); + } + } + + + public function index() + { + // 20170505 改由遠端中控 + echo '已停用'; + exit; + + $this->show_page('main_page'); + } + + + // 送出html code + public function get_html() + { + $data = array + ( + 'company_no' => $this->input->post('company_no', true), // 場站統編 + 'hq_company_no' => '80682490' + ); + $this->load->view(APP_NAME.'/'.$this->input->post('tag_name', true), $data); + } + + // 登入帳密檢查 + public function login_verify() + { + $login_name = $this->input->post('login_name', true); + $login_pswd = $this->input->post('login_pswd', true); + + $ok = $this->admins_station_model->login_verify($login_name, $login_pswd); + if ($ok) // 帳密正確 + { + $_SESSION['login_ck'] = uniqid(); + $data = array('rcode' => 'OK', 'ck' => $_SESSION['login_ck']); + } + else + { + $_SESSION['login_ck'] = 'NOLOGIN'; + $data = array('rcode' => 'NOLOGIN', 'ck' => $_SESSION['login_ck']); + } + + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 設定javascript初始值 + public function js_vars() + { + $data = $this->admins_station_model->get_init_vars(); + echo $data; + } + + // 費率清單 + public function price_plan_query_all() + { + $data = $this->txdata_model->get_all_valid_price_plan(STATION_NO); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 會員清單 + public function member_query_all() + { + $data = $this->admins_station_model->member_query_all(); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 待審核清單 + public function member_tx_check_query() + { + $data = $this->admins_station_model->member_tx_check_query(); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 已退款清單 + public function member_tx_refund_query() + { + $station_no = $this->input->post('station_no', true); + $q_item = $this->input->post('q_item', true); + $q_str = $this->input->post('q_str', true); + + $data = $this->admins_station_model->member_tx_refund_query($station_no, $q_item, $q_str); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 取得轉租資訊 + public function member_refund_transfer_data_query() + { + $station_no = $this->input->post('station_no', true); + $member_no = $this->input->post('member_no', true); + $member_refund_id = $this->input->post('member_refund_id', true); + + $data = $this->admins_station_model->member_refund_transfer_data_query($station_no, $member_no, $member_refund_id); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 押金保留,結清其它金額 (退租後) + public function member_refund_keep_deposit() + { + $parms = array(); + $parms['station_no'] = $this->input->post('station_no', true); // 場站編號 + $parms['member_refund_id'] = $this->input->post('member_refund_id', true); // 退租編號 + + if(empty($parms['member_refund_id']) || empty($parms['station_no'])) + { + echo '資料異常'; + exit; + } + + echo $this->admins_station_model->member_refund_keep_deposit($parms); + } + + // 結清所有金額 (退租後) + public function member_refund_dismiss_all() + { + $parms = array(); + $parms['station_no'] = $this->input->post('station_no', true); // 場站編號 + $parms['member_refund_id'] = $this->input->post('member_refund_id', true); // 退租編號 + + if(empty($parms['member_refund_id']) || empty($parms['station_no'])) + { + echo '資料異常'; + exit; + } + + echo $this->admins_station_model->member_refund_dismiss_all($parms); + } + + // 發票折讓 (退租後) + public function refund_invoice_allowance() + { + $parms = array(); + $parms['station_no'] = $this->input->post('station_no', true); // 場站編號 + $parms['member_no'] = $this->input->post('member_no', true); // 會員編號 + $parms['tx_bill_no'] = $this->input->post('tx_bill_no', true); // 帳單編號 + $parms['refund_amt'] = $this->input->post('refund_amt', true); // 折讓金額 + $parms['tx_no'] = $this->input->post('tx_no', true); // 交易編號 + $parms['company_no'] = $this->input->post('company_no', true); // 賣方統編 + + if(empty($parms['member_no']) || empty($parms['station_no']) || empty($parms['tx_bill_no']) || empty($parms['tx_no'])) + { + echo '資料異常'; + exit; + } + + // 若賣方統編未設定, 預設拿場站統編 + if(empty($parms['company_no'])) + { + $st_info = $this->vars['mcache']->get('st_info'); + $parms['company_no'] = $st_info['company_no']; + } + + echo $this->admins_station_model->refund_invoice_allowance($parms); + } + + // 臨停未結確認完成 + public function cario_temp_confirmed() + { + $parms = array(); + $parms['station_no'] = $this->input->post('station_no', true); // 場站編號 + $parms['cario_no'] = $this->input->post('cario_no', true); // 進出編號 + $parms['remarks'] = $this->input->post('remarks', true); // 備註 + echo $this->admins_station_model->cario_temp_confirmed($parms); + } + + // 審核完成 + public function member_tx_confirmed() + { + $parms = array(); + $parms['station_no'] = $this->input->post('station_no', true); // 場站編號 + $parms['tx_no'] = $this->input->post('tx_no', true); // 交易編號 + $parms['verify_state'] = $this->input->post('verify_state', true); // 0:未審核, 1:人工審核完成 + //$parms['valid_time'] = $this->input->post('valid_time', true); // 有效期限 + $parms['remarks'] = $this->input->post('remarks', true); // 備註 + echo $this->admins_station_model->member_tx_confirmed($parms); + } + + // 交易取消 + public function member_tx_cancel() + { + $parms = array(); + $parms['station_no'] = $this->input->post('station_no', true); // 場站編號 + $parms['member_no'] = $this->input->post('member_no', true); // 會員編號 + $parms['tx_no'] = $this->input->post('tx_no', true); // 交易編號 + echo $this->admins_station_model->member_tx_cancel($parms); + } + + // 會員查詢 + public function member_query() + { + $station_no = $this->input->post('station_no', true); + $q_item = $this->input->post('q_item', true); + $q_str = $this->input->post('q_str', true); + + $data = $this->admins_station_model->member_query($station_no, $q_item, $q_str); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 交易查詢 + public function member_tx_query() + { + $station_no = $this->input->post('station_no', true); + $member_no = $this->input->post('member_no', true); + + $data = $this->admins_station_model->member_tx_query($station_no, $member_no); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 發票查詢 + public function member_tx_bill_query() + { + $station_no = $this->input->post('station_no', true); + $tx_no = $this->input->post('tx_no', true); + $verify_state_str = $this->input->post('verify_state_str', true); + $invoice_state_str = $this->input->post('invoice_state_str', true); + $tx_state_str = $this->input->post('tx_state_str', true); + $tx_bill_no = $this->input->post('tx_bill_no', true); + $member_refund_id = $this->input->post('member_refund_id', true); + + $data = $this->admins_station_model->member_tx_bill_query( + $station_no, $tx_no, $verify_state_str, $invoice_state_str, $tx_state_str, $tx_bill_no, $member_refund_id); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 退租發票查詢 + public function member_refund_bill_query() + { + $station_no = $this->input->post('station_no', true); + $tx_no = $this->input->post('tx_no', true); + $verify_state_str = $this->input->post('verify_state_str', true); + $invoice_state_str = $this->input->post('invoice_state_str', true); + $tx_state_str = $this->input->post('tx_state_str', true); + $tx_bill_no = $this->input->post('tx_bill_no', true); + $member_refund_id = $this->input->post('member_refund_id', true); + + $data = $this->admins_station_model->member_refund_bill_query( + $station_no, $tx_no, $verify_state_str, $invoice_state_str, $tx_state_str, $tx_bill_no, $member_refund_id); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 臨停未結清單 + public function cario_temp_not_finished_query_all() + { + $station_no = $this->input->post('station_no', true); + $q_item = $this->input->post('q_item', true); + $q_str = $this->input->post('q_str', true); + + $data = $this->carpayment_model->cario_temp_not_finished_query_all($station_no, $q_item, $q_str); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + + // response http + protected function http_return($return_code, $type) + { + if ($type == 'text') echo $return_code; + else echo json_encode($return_code, JSON_UNESCAPED_UNICODE); + } + + + + // 讀取cookie內容 + protected function get_cookie($cookie_name) + { + if (empty($_COOKIE[$cookie_name])) return array(); + return(json_decode($_COOKIE[$cookie_name], true)); + } + + + // 儲存cookie內容 + protected function save_cookie($cookie_name, $cookie_info) + { + return setcookie($cookie_name, json_encode($cookie_info, JSON_UNESCAPED_UNICODE), 0, '/'); + } + + + // 月租資料同步 + /* + public function rent_sync() + { + $station_no = $this->input->post('station_no', true); + $start_date = $this->input->post('start_date', true); + $end_date = $this->input->post('end_date', true); + + // $data = $this->admins_station_model->rent_sync($station_no, $start_date, $end_date); + + // print_r($data); + } + */ + + // 顯示logs + public function show_logs() + { + $lines = $this->uri->segment(3); // 顯示行數 + if (empty($lines)) $lines = 40; // 無行數參數, 預設為40行 + + // echo ''; + echo ''; + passthru('/usr/bin/tail -n ' . $lines . ' ' . LOG_FILE); // 利用linux指令顯示倒數幾行的logs內容 + echo "\n----- " . LOG_FILE . ' -----'; + echo ''; + } + + + // 將設定檔存入記憶體 + public function info2mem() + { + $data = $this->admins_station_model->get_info(); + foreach($data as $var => $values) + { + $this->mcache->set('i_'.$var, $values); + } + + echo 'OK !'; + } + + + // 將設定檔存入記憶體 + public function get_info() + { + echo $this->mcache->get('i_station_no'); + } + + + // 新增月租資料 + public function member_add() + { + $start_date = $this->input->post('start_date', true); + if(empty($start_date)) + { + $start_date = $this->input->post('start_date_done', true); + } + + $end_date = $this->input->post('end_date', true); + if(empty($end_date)) + { + $end_date = $this->input->post('end_date_done', true); + } + + $demonth_start_date = $this->input->post('demonth_start_date', true); + if(empty($demonth_start_date)) + { + $demonth_start_date = $this->input->post('demonth_start_date_done', true); + } + + $demonth_end_date = $this->input->post('demonth_end_date', true); + if(empty($demonth_end_date)) + { + $demonth_end_date = $this->input->post('demonth_end_date_done', true); + } + + $data = array + ( + 'member_no' => $this->input->post('member_no', true), + 'station_no' => $this->input->post('station_no', true), + 'lpr' => strtoupper($this->input->post('lpr', true)), + 'old_lpr' => strtoupper($this->input->post('old_lpr', true)), + 'etag' => strtoupper($this->input->post('etag', true)), + 'start_date' => $start_date, + 'end_date' => $end_date, + 'park_time' => $this->input->post('park_time', true), + 'member_name' => $this->input->post('member_name', true), + 'member_nick_name' => $this->input->post('member_name', true), + 'mobile_no' => $this->input->post('mobile_no', true), + 'member_id' => $this->input->post('member_id', true), + 'contract_no' => $this->input->post('contract_no', true), // 總公司 only ?? + 'member_company_no' => $this->input->post('member_company_no', true), // 買方統編(會員統編) + 'company_no' => $this->input->post('company_no', true), // 賣方統編 + 'amt' => $this->input->post('amt', true), + 'tel_h' => $this->input->post('tel_h', true), + 'tel_o' => $this->input->post('tel_o', true), + 'addr' => $this->input->post('addr', true), + 'demonth_start_date' => $demonth_start_date, + 'demonth_end_date' => $demonth_end_date, + 'member_attr' => $this->input->post('member_attr', true), + 'fee_period1' => $this->input->post('fee_period1', true), + 'fee_period' => $this->input->post('fee_period', true), + 'amt1' => $this->input->post('amt1', true), + 'deposit' => $this->input->post('deposit', true), + 'amt_tot' => $this->input->post('amt_tot', true), + 'amt_accrued' => $this->input->post('amt_accrued', true), + 'refund_transfer_id' => $this->input->post('refund_transfer_id', true), // 轉租來源編號 + 'refund_transfer_discount' => $this->input->post('refund_transfer_discount', true) // 轉租折扺金額 + ); + + if( empty($data['station_no']) || empty($data['lpr'])) + { + echo '資料異常'; + exit; + } + + trigger_error("add:".print_r($data, true)); + //if ($data['member_no'] == 0 || $data['old_lpr'] != $data['lpr']) + if ($data['member_no'] == 0) + { + // 本次操作為新增車牌, 開始驗証是否能繼續 + + if( empty($data['start_date']) || empty($data['end_date']) || + empty($data['demonth_start_date']) || empty($data['demonth_end_date'])) + { + echo '日期資料異常'; + exit; + } + + if (!empty($data['refund_transfer_id'])) + { + // 轉租戶 (直接進入新增流程, 新資料蓋掉舊資料) + } + else + { + // 一般戶, 再確認一次退租名單是否重複 + if ($this->admins_station_model->check_refund_lpr($data['lpr']) > 0) + { + echo '此車牌尚有押金未轉移,請進行轉租'; + exit; + } + + // 已退租且互不相欠的一般戶 (直接進入新增流程, 新資料蓋掉舊資料) + } + } + else + { + // 本次操作為修改記錄, 開始驗証是否能繼續 + + // 一般戶, 確認是否存在未處理的退租金額 + if ($this->admins_station_model->check_refund_member_no($data['member_no']) > 0) + { + echo '此會員尚有押金未轉移,請進行轉租'; + exit; + } + } + + // 取得月租費率設定 + $rents_arr = $this->get_rents_arr(); + + echo json_encode($this->admins_station_model->member_add($data, $rents_arr), JSON_UNESCAPED_UNICODE); + } + + // 刪除月租資料 + /* + public function member_delete() + { + $member_no = $this->input->post('member_no', true); + $station_no = $this->input->post('station_no', true); + if(empty($member_no) || empty($station_no)) + { + echo '資料異常'; + exit; + } + echo $this->admins_station_model->member_delete($station_no, $member_no); + } + */ + + + + // 顯示圖檔(http://url/carpark.html/pics/lpr_ABY8873_O_0_0_C_20150919210022) + public function pics() + { + // ??? + readfile(CAR_PIC.$this->uri->segment(3).'/'.str_replace('/', '', $this->uri->segment(4)).'.jpg'); + } + + + + // 說明: 手開發票 + public function hand_first_rents_payment() + { + $parms = array(); + $parms['tx_no'] = $this->input->post('tx_no', true); // 交易編號 + $parms['station_no'] = $this->input->post('station_no', true); // 場站編號 + $parms['member_no'] = $this->input->post('member_no', true); // 會員編號 + $parms['member_company_no'] = $this->input->post('member_company_no', true); // 買方統編 + $parms['company_no'] = $this->input->post('company_no', true); // 賣方統編 + $parms['amt1'] = $this->input->post('amt1', true); // 首期租金 + $parms['amt'] = $this->input->post('amt', true); // 本期租金 + $parms['invoice_track'] = $this->input->post('invoice_track', true); // * 發票字軌 + $parms['invoice_no'] = $this->input->post('invoice_no', true); // * 發票號碼 + $parms['invoice_type'] = 1; // 手開發票 + + $parms['invoice_amt'] = $this->input->post('invoice_amt', true); // * 發票金額 + $parms['tx_bill_no'] = $this->input->post('tx_bill_no', true); // 帳單編號 + + if(empty($parms['tx_bill_no']) || empty($parms['tx_no']) || empty($parms['member_no']) || empty($parms['station_no']) ) + { + echo '資料異常'; + exit; + } + + if(empty($parms['invoice_track']) || empty($parms['invoice_no'])) + { + echo '查無發票資訊'; + exit; + } + + if(empty($parms['invoice_amt'])) + { + echo '查無金額資訊'; + exit; + } + + // 若賣方統編未設定, 預設拿場站統編 + if(empty($parms['company_no'])) + { + $st_info = $this->vars['mcache']->get('st_info'); + $parms['company_no'] = $st_info['company_no']; + } + + // 確認是否存在退租記錄 + if ($this->admins_station_model->check_refund_member_no_exist($parms['member_no']) > 0) + { + echo '此會員已退租'; + exit; + } + + echo $this->admins_station_model->first_rents_payment($parms); + } + + // 說明: 1.新建立直接列印發票、 2.列印發票 (TODO: 待接上歐付寶) + public function first_rents_payment() + { + $parms = array(); + $parms['tx_no'] = $this->input->post('tx_no', true); // 交易編號 + $parms['station_no'] = $this->input->post('station_no', true); // 場站編號 + $parms['member_no'] = $this->input->post('member_no', true); // 會員編號 + $parms['member_attr'] = $this->input->post('member_attr', true); // 會員身份 + $parms['member_company_no'] = $this->input->post('member_company_no', true); // 買方統編 + $parms['company_no'] = $this->input->post('company_no', true); // 賣方統編 + $parms['amt1'] = $this->input->post('amt1', true); // 首期租金 + $parms['amt'] = $this->input->post('amt', true); // 本期租金 + + $parms['invoice_amt'] = $this->input->post('invoice_amt', true); // * 發票金額 + $parms['tx_bill_no'] = $this->input->post('tx_bill_no', true); // 帳單編號 + + $parms['email'] = $this->input->post('email', true); // 發票通知信箱 + $parms['mobile'] = $this->input->post('mobile', true); // 發票通知簡訊 + + if(empty($parms['tx_bill_no']) || empty($parms['tx_no']) || empty($parms['member_no']) || empty($parms['station_no'])) + { + echo '資料異常'; + exit; + } + + if(empty($parms['invoice_amt'])) + { + echo '查無金額資訊'; + exit; + } + + // 若賣方統編未設定, 預設拿場站統編 + if(empty($parms['company_no'])) + { + $st_info = $this->vars['mcache']->get('st_info'); + $parms['company_no'] = $st_info['company_no']; + } + + // 若發票通知信箱未設定 + if(empty($parms['email'])) + { + $parms['email'] = 'altob.rd@gmail.com'; // 預設信箱 + } + + // 若發票通知簡訊未設定 + if(empty($parms['mobile'])) + { + $parms['mobile'] = ''; // 預設手機 + } + + // 確認是否存在退租記錄 + if ($this->admins_station_model->check_refund_member_no_exist($parms['member_no']) > 0) + { + echo '此會員已退租'; + exit; + } + + echo $this->admins_station_model->first_rents_payment($parms); + } + + // 說明: 繳租 + public function rents_payment() + { + $parms = array(); + $parms['station_no'] = $this->input->post('station_no', true); // 場站編號 + $parms['member_no'] = $this->input->post('member_no', true); // 會員編號 + $parms['member_attr'] = $this->input->post('member_attr', true); // 會員身份 + $parms['lpr'] = $this->input->post('lpr', true); // 車牌號碼 + $parms['member_company_no'] = $this->input->post('member_company_no', true); // 買方統編 + $parms['company_no'] = $this->input->post('company_no', true); // 賣方統編 + $parms['fee_period'] = $this->input->post('fee_period', true); // 本期繳期 + $parms['fee_period_last'] = $this->input->post('fee_period_last', true); // 上期繳期 + $parms['amt'] = $this->input->post('amt', true); // 本期租金 + $parms['amt_last'] = $this->input->post('amt_last', true); // 上期租金 + $parms['end_date'] = $this->input->post('end_date', true); // 本期截止日 + $parms['start_date_last'] = $this->input->post('start_date_last', true); // 上期截止日 + $parms['end_date_last'] = $this->input->post('end_date_last', true); // 上期截止日 + + if(empty($parms['member_no']) || empty($parms['station_no'])) + { + echo '資料異常'; + exit; + } + + if(empty($parms['end_date'])) + { + echo '截止日異常'; + exit; + } + + // 若賣方統編未設定, 預設拿場站統編 + if(empty($parms['company_no'])) + { + $st_info = $this->vars['mcache']->get('st_info'); + $parms['company_no'] = $st_info['company_no']; + } + + // 確認是否存在退租記錄 + if ($this->admins_station_model->check_refund_member_no_exist($parms['member_no']) > 0) + { + echo '此會員已退租'; + exit; + } + + $rents_arr = $this->get_rents_arr(); // 費率設定 + echo $this->admins_station_model->rents_payment($parms, $rents_arr); + } + + // 退租 + public function stop_rents_payment() + { + $parms = array(); + $parms['station_no'] = $this->input->post('station_no', true); // 場站編號 + $parms['member_no'] = $this->input->post('member_no', true); // 會員編號 + $parms['stop_date'] = $this->input->post('stop_date', true); // 結束日 + $parms['tot_amt'] = $this->input->post('tot_amt', true); // 總金額 + + if(empty($parms['member_no']) || empty($parms['station_no']) || empty($parms['stop_date'])) + { + echo '資料異常'; + exit; + } + + // 確認是否存在退租記錄 + if ($this->admins_station_model->check_refund_member_no_exist($parms['member_no']) > 0) + { + echo '此會員已退租'; + exit; + } + + $rents_arr = $this->get_rents_arr(); // 費率設定 + echo $this->admins_station_model->stop_rents_payment($parms, $rents_arr); + } + + // 接續開立發票 + public function next_tx_bill() + { + $parms = array(); + $parms['station_no'] = $this->input->post('station_no', true); // 場站編號 + $parms['member_no'] = $this->input->post('member_no', true); // 會員編號 + $parms['tx_bill_no'] = $this->input->post('tx_bill_no', true); // 帳單編號 + $parms['remain_amt'] = $this->input->post('remain_amt', true); // 剩餘金額 + $parms['tx_no'] = $this->input->post('tx_no', true); // 交易編號 + $parms['company_no'] = $this->input->post('company_no', true); // 賣方統編 + + if(empty($parms['member_no']) || empty($parms['station_no']) || empty($parms['tx_bill_no']) || empty($parms['tx_no'])) + { + echo '資料異常'; + exit; + } + + // 若賣方統編未設定, 預設拿場站統編 + if(empty($parms['company_no'])) + { + $st_info = $this->vars['mcache']->get('st_info'); + $parms['company_no'] = $st_info['company_no']; + } + + // 確認是否存在退租記錄 + if ($this->admins_station_model->check_refund_member_no_exist($parms['member_no']) > 0) + { + echo '此會員已退租'; + exit; + } + + $rents_arr = $this->get_rents_arr(); // 費率設定 + echo $this->admins_station_model->next_tx_bill($parms, $rents_arr); + } + + // 停權或啟動 + public function suspended() + { + $parms = array(); + $parms['station_no'] = $this->input->post('station_no', true); // 會員編號 + $parms['member_no'] = $this->input->post('member_no', true); // 會員編號 + $parms['suspended'] = $this->input->post('suspended', true); // 0:啟用, 1:停權 + echo $this->admins_station_model->suspended($parms); + } + + // 取得費率設定 + public function get_rents_json() + { + echo json_encode($this->get_rents_arr(), JSON_UNESCAPED_UNICODE); + } + + // 取得費率設定 + function get_rents_arr() + { + $rents_arr = array(); + $txdata_result = $this->txdata_model->get_price_plan(STATION_NO, 1); + //trigger_error('tx: '. print_r(json_decode($txdata_result[0]['price_plan'], true), true)); + + if(!empty($txdata_result[0]['price_plan'])) + { + foreach (json_decode($txdata_result[0]['price_plan'], true) as $key => $val) + { + $p_keys = explode('_', $key); + if(!array_key_exists($p_keys[0], $rents_arr)) + { + $rents_arr[$p_keys[0]] = array(); + } + $rents_arr[$p_keys[0]][$p_keys[1]] = $val; + } + } + + return $rents_arr; + } + + // 同步場站費率 + public function sync_price_plan() + { + echo $this->txdata_model->sync_price_plan(); + } + + // 計算退租金額 + public function calculate_stop_rents_amt() + { + $parms = array(); + $parms['station_no'] = $this->input->post('station_no', true); // 場站編號 + $parms['member_no'] = $this->input->post('member_no', true); // 會員編號 + $parms['stop_date'] = $this->input->post('stop_date', true); // 結束日 + $rents_arr = $this->get_rents_arr(); // 費率設定 + + // 根據會員現況算出所有可退金額 + $data = $this->admins_station_model->calculate_stop_rents_amt($parms, $rents_arr); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 計算月租金額 + public function calculate_rents_amt() + { + $rents_arr = $this->get_rents_arr(); // 費率設定 + $station_no = $this->input->post('station_no', true); // 場站編號 + $demonth_start_date = $this->input->post('demonth_start_date', true); // 不足月起租日 + $member_attr = $this->input->post('member_attr', true); // 會員身份類別 + $period_1 = $this->input->post('period_1', true); // 首期繳期 + $period_2 = $this->input->post('period_2', true); // 例行繳期 + + // 當傳入不足月開始日為當月第一天時,視為一個足月 2017-02-15 updated + if(date_parse_from_format("Y-m-d", $demonth_start_date)['day'] == 1) + { + $demonth_end_date = $demonth_start_date; // 不足月結束日 (跳過不足月) + $start_date = $demonth_start_date; // 足月起租日 (跳過不足月) + } + else + { + $demonth_end_date = (new DateTime($demonth_start_date))->format('Y-m-t'); // 不足月結束日 + $start_date = date('Y-m-d', strtotime("+1 days", strtotime($demonth_end_date))); // 足月起租日 + } + + // 第二版: 繳期直接算 2017-04-13 updated + $period_month_bias = ($period_2 < 1) ? 0 : $period_2 - 1; + $end_date = date('Y-m-t', strtotime("+{$period_month_bias} months", strtotime($start_date))); + + /* + // 第一版: 根據繳期算出所有參數 + $start_date_year = date_parse_from_format("Y-m-d", $start_date)['year']; + $start_date_month = date_parse_from_format("Y-m-d", $start_date)['month']; + for($month = 0 ; $month <= 12 ; $month += $period_2) + { + $end_date = null; + if($month >= $start_date_month) + { + $end_date = (new DateTime($start_date_year.'-'.$month))->format('Y-m-t'); // 足月結束日 + break; + } + } + + if(empty($end_date)) + { + // 若有異常繳期, 拿當月最後一天為終止日 + $end_date = (new DateTime($start_date_year.'-' . $start_date_month))->format('Y-m-t'); + } + */ + + if ($member_attr == 250) + { + $amt1 = 0; // 不足月 (VIP) + $amt2 = 0; // 足月 (VIP) + } + else + { + // 不足月計算 + $date1 = new DateTime($demonth_start_date); + $date2 = new DateTime($demonth_end_date); + + // 當傳入不足月開始日為當月第一天時,視為一個足月 2017-02-15 updated + if(date_parse_from_format("Y-m-d", $demonth_start_date)['day'] == 1) + { + $demonth_days = 0; + } + else + { + $demonth_days = $date2->diff($date1)->format("%a") + 1; // 不足月天數 + } + + $demonth_amt = $rents_arr[$period_1][$member_attr]; + $amt1 = round($demonth_amt * $demonth_days / $rents_arr[$period_1][0]); + $amt1 = ($amt1 > $demonth_amt) ? $demonth_amt : $amt1; + trigger_error("days:{$demonth_days}|de_amt:{$demonth_amt}|amt1:{$amt1}"); + + // 起始日若為空, 就自動回填 + //$demonth_start_date = $date1->format('Y-m-d'); + + // 足月計算 + $date1a = new DateTime($start_date); + $date2a = new DateTime($end_date); + $amonth_days = $date2a->diff($date1a)->format("%a") + 1; // 足月天數 + + $amonth_amt = $rents_arr[$period_2][$member_attr]; + + // 第一版: 依天數拆分 + //$amt2 = round($amonth_amt * $amonth_days / $rents_arr[$period_2][0]); + //$amt2 = ($amt2 > $amonth_amt) ? $amonth_amt : $amt2; + + //$amonth_months = $date2a->diff($date1a)->format("%m"); // 足月月數 (gg: 測試後有問題) + + // 第二版: 依月數拆分 2017-02-13 updated + //$date1a_month = $date1a->format("m"); + //$date2a_month = $date2a->format("m"); + //$amonth_months = $date2a_month - $date1a_month + 1; + + // 第三版: 繳期直接算 2017-04-13 updated + $amonth_months = $period_2; + $amt2 = round($amonth_amt * $amonth_months / $period_2); + $amt2 = ($amt2 > $amonth_amt) ? $amonth_amt : $amt2; + + trigger_error("days:{$amonth_days}|a_amt:{$amonth_amt}|amt2:{$amt2}"); + } + + // 回傳參數 + $amt_arr['rents_deposit'] = $rents_arr[0][0]; // 押金 + $amt_arr['demonth_start_date'] = $demonth_start_date; // 不足月起租日 + $amt_arr['demonth_end_date'] = $demonth_end_date; // 不足月結束日 + $amt_arr['start_date'] = $start_date; // 足月起租日 + $amt_arr['end_date'] = $end_date; // 足月結束日 + $amt_arr['rents_amt1'] = $amt1; // 不足月:租金 + $amt_arr['demonth_amt'] = $demonth_amt; // 不足月:繳期總額 + $amt_arr['demonth_days'] = $demonth_days; // 不足月:天數 + $amt_arr['demonth_days_total'] = $rents_arr[$period_1][0]; // 不足月:總天數 + $amt_arr['rents_amt2'] = $amt2; // 足月:租金 + $amt_arr['amonth_amt'] = $amonth_amt; // 足月:繳期總額 + $amt_arr['amonth_days'] = $amonth_days; // 足月:天數 + $amt_arr['amonth_days_total'] = $rents_arr[$period_2][0]; // 足月:總天數 + $amt_arr['amonth_months'] = $amonth_months; // 足月:月數 2017-02-13 updated + $amt_arr['amonth_months_total'] = $period_2; // 足月:總月數 2017-02-13 updated + echo json_encode($amt_arr, JSON_UNESCAPED_UNICODE); + } + + // 設定關帳時間點 + public function set_check_point() + { + $parms = array(); + $parms['station_no'] = $this->input->post('station_no', true); // 場站編號 + $parms['check_time'] = $this->input->post('check_point_time', true); // 時間 + $parms['remarks'] = $this->input->post('remarks', true); // 備註 + echo $this->admins_station_model->set_check_point($parms); + } + + // 關帳查詢 + public function check_point_query() + { + $parms = array(); + $parms['station_no'] = $this->input->post('station_no', true); // 場站編號 + $parms['check_point_time_from'] = $this->input->post('check_point_time_from', true); // 開始時間 + $parms['check_point_time_to'] = $this->input->post('check_point_time_to', true); // 結束時間 + + $data = $this->admins_station_model->check_point_query($parms); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 關帳查詢(明細) + public function check_point_detail_query() + { + $parms = array(); + $parms['station_no'] = $this->input->post('station_no', true); // 場站編號 + $parms['check_time_no'] = $this->input->post('check_time_no', true); // + $parms['check_time_last_no'] = $this->input->post('check_time_last_no', true); // + + $data = $this->admins_station_model->check_point_detail_query($parms); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 電子發票查詢 + public function member_invoice_query() + { + $parms = array(); + $parms['station_no'] = $this->input->post('station_no', true); // 場站編號 + $parms['member_invoice_time_from'] = $this->input->post('member_invoice_time_from', true); // 開始時間 + $parms['member_invoice_time_to'] = $this->input->post('member_invoice_time_to', true); // 結束時間 + + $data = $this->admins_station_model->member_invoice_query($parms); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 電子發票作廢 + public function member_invoice_void() + { + $parms = array(); + $parms['station_no'] = $this->input->post('station_no', true); // 場站編號 + $parms['invoice_no'] = $this->input->post('invoice_no', true); // 發票號碼 + $parms['order_no'] = $this->input->post('order_no', true); // 訂單編號 + + echo $this->admins_station_model->member_invoice_void($parms); + } + + // 批次延時 + public function member_tx_check_list_confirm_batch() + { + $parms = array(); + $parms['station_no'] = $this->input->post('station_no', true); // 場站編號 + $parms['tx_no_str'] = $this->input->post('tx_no_str', true); // 交易代號字串 + $parms['member_no_str'] = $this->input->post('member_no_str', true); // 會員代號字串 + $parms['day'] = $this->input->post('day', true); // 延期天數 + + echo $this->admins_station_model->member_tx_check_list_confirm_batch($parms); + } + + // 切換賣方統編 + public function switch_company_no() + { + $parms = array(); + $parms['station_no'] = $this->input->post('station_no', true); // 場站編號 + $parms['tx_bill_no'] = $this->input->post('tx_bill_no', true); // 帳單編號 + $parms['company_no'] = $this->input->post('company_no', true); // 賣方統編 + + echo $this->admins_station_model->switch_company_no($parms); + } + + // 取得停車時段字串 + public function get_parktime_str() + { + $data = $this->admins_station_model->get_parktime_str(); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 取得未同步資料筆數 + public function get_un_synced_count() + { + $data = $this->admins_station_model->get_un_synced_count(STATION_NO); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + public function do_sync_batch_100() + { + $this->admins_station_model->try_sync_batch(STATION_NO, 100); + } + + // 手動 sync + public function do_sync_batch() + { + $this->admins_station_model->try_sync_batch(STATION_NO, 1); + echo STATION_NO .'..ok'; + } + + // 報表:匯出會員資料 + public function export_members() + { + $this->excel_model->export_members(); + } + + public function test() + { + echo 'zzz'; + } + + public function test_check_refund_lpr() + { + $lpr = $this->uri->segment(3); + echo json_encode($this->admins_station_model->check_refund_lpr($lpr), JSON_UNESCAPED_UNICODE); + } +} diff --git a/controllers/Allpa_service.php b/controllers/Allpa_service.php new file mode 100644 index 0000000..84be17f --- /dev/null +++ b/controllers/Allpa_service.php @@ -0,0 +1,574 @@ +router->fetch_method(); + if ($method_name == 'allpa_consume_handler') + { + ob_end_clean(); + ignore_user_abort(); + ob_start(); + header('Connection: close'); + header('Content-Length: ' . ob_get_length()); + ob_end_flush(); + flush(); + } + + // ----- 程式開發階段log設定 ----- + if (@ENVIRONMENT == 'development') + { + ini_set('display_errors', '1'); + //error_reporting(E_ALL ^ E_NOTICE); + error_reporting(E_ALL); + } + set_error_handler(array($this, 'error_handler'), E_ALL); // 資料庫異動需做log + + /* + // 共用記憶體 + $this->vars['mcache'] = new Memcache; + $this->vars['mcache']->connect(MEMCACHE_HOST, MEMCACHE_PORT) or die ('Could not connect memcache'); + + // mqtt subscribe + $this->vars['mqtt'] = new phpMQTT(MQ_HOST, MQ_PORT, uniqid()); + + if(!$this->vars['mqtt']->connect()){ die ('Could not connect mqtt'); } + */ + + // ----- 定義常數(路徑, cache秒數) ----- + define('APP_VERSION', '100'); // 版本號 + + define('MAX_AGE', 604800); // cache秒數, 此定義1個月 + define('APP_NAME', 'allpa_service'); // 應用系統名稱 + + define('PAGE_PATH', APP_BASE.'ci_application/views/'.APP_NAME.'/'); // path of views + + define('SERVER_URL', 'http://'.(isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost').'/'); // URL + define('APP_URL', SERVER_URL.APP_NAME.'.html/'); // controller路徑 + define('WEB_URL', SERVER_URL.APP_NAME.'/'); // 網頁路徑 + define('WEB_LIB', SERVER_URL.'libs/'); // 網頁lib + define('BOOTSTRAPS', WEB_LIB.'bootstrap_sb/'); // bootstrap lib + define('LOG_PATH', FILE_BASE.APP_NAME.'/logs/'); // log path + + $this->load->model('allpa_service_model'); // 歐Pa卡 + $this->load->model('allpay_invoice_model'); // 歐付寶電子發票 + + // ----- 中國信託金流 ----- + $this->load->model('ctbcbank_model'); // 中國信託金流 + define('CTBC_AuthResURL', APP_URL."return_ok/"); // 從收單行端取得授權碼後,要導回的網址,請勿填入特殊字元@、#、%、?、&等。 + // ----- 中國信託金流 (end) ----- + + // ----- 頁面 ----- + define('MAIN_PAGE', "main_page"); + define('RESULT_PAGE', "result_page"); + define('ERROR_PAGE', "error_page"); + define('ADMIN_PAGE', "admin_page"); + define('ADMIN_LOGIN_PAGE', "admin_login_page"); + define('ADMIN_RESULT_PAGE', "admin_result_page"); + // ----- 頁面 ----- + + + + // [START] 2016/06/08 登入 + $this->load->model('user_model'); + // load library + $this->load->library(array('form_validation','session')); + // load helpers + $this->load->helper(array('form')); + // ajax code + define('RESULT_SUCCESS', 'ok'); + define('RESULT_FORM_VALIDATION_FAIL', '-1'); + define('RESULE_FAIL', 'gg'); + // [END] 2016/06/08 登入 + } + + // 發生錯誤時集中在此處理 + public function error_handler($errno, $errstr, $errfile, $errline, $errcontext) + { + $str = date('H:i:s')."|{$errstr}|{$errfile}|{$errline}|{$errno}\n"; + //error_log($str, 3, $log_file . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + + //echo "whoami: ".`whoami`; + //echo "
".$str; + + error_log($str, 3, LOG_PATH.APP_NAME . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + } + + + // 顯示靜態網頁(html檔) + protected function show_page($page_name, &$data = null) + { + $page_file = PAGE_PATH.$page_name.'.php'; + $last_modified_time = filemtime($page_file); + + // 若檔案修改時間沒有異動, 或版本無異動, 通知瀏覽器使用cache, 不再下傳網頁 + // header('Cache-Control:max-age='.MAX_AGE); // cache 1個月 + header('Last-Modified: '.gmdate('D, d M Y H:i:s', $last_modified_time).' GMT'); + header('Etag: '. APP_VERSION); + header('Cache-Control: public'); + + if (!empty($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == APP_VERSION && @strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time) + { + header('HTTP/1.1 304 Not Modified'); + } + else + { + $this->load->view(APP_NAME.'/'.$page_name, $data); + } + } + + + + + + + // [START] 2016/06/08 + + // ADMIN.1 管理者頁面 + public function admin() + { + if($this->session->userdata('logged_in')) + { + $session_data = $this->session->userdata('logged_in'); + $data['username'] = $session_data['username']; + $data['type'] = $session_data['type']; + + if($data['type'] == 'admin') + { + $this->show_page('NOT_READY___', $data); // 進階管理者介面 (TODO) + } + else + { + $this->show_page(ADMIN_PAGE, $data); // 一般 + } + } + else + { + $this->show_page(ADMIN_LOGIN_PAGE); + } + } + + // ADMIN.2.a 管理者頁面登入 + public function user_login() + { + // form_validation + $this->form_validation->set_rules('login_name', 'login_name', 'trim|required'); + $this->form_validation->set_rules('pswd', 'pswd', 'trim|required'); + + if($this->form_validation->run() == FALSE) + { + return RESULT_FORM_VALIDATION_FAIL; + } + + // go model + $data = array + ( + 'login_name' => $this->input->post('login_name', true), + 'pswd' => $this->input->post('pswd', true) + ); + + $result = $this->user_model->user_login($data); + + if($result) + { + $sess_array = array(); + foreach($result as $row) + { + $sess_array = array + ( + 'username' => $row->login_name , + 'type' => $row->user_type + ); + $this->session->set_userdata('logged_in', $sess_array); + } + echo RESULT_SUCCESS; + } + else + { + return RESULE_FAIL; + } + } + + // ADMIN.2.b 管理者頁面登出 + public function user_logout() + { + if(!$this->session->userdata('logged_in')){echo json_encode(null, JSON_UNESCAPED_UNICODE);return;} // 沒登入就回傳null + + $this->session->unset_userdata('logged_in'); + session_destroy(); + return RESULT_SUCCESS; + } + + // ADMIN.3.a 管理者產品列表 + // http://203.75.167.89/allpa_service.html/get_allpa_admin_products + public function get_allpa_admin_products() + { + if(!$this->session->userdata('logged_in')){echo json_encode(null, JSON_UNESCAPED_UNICODE);return;} // 沒登入就回傳null + + $data = $this->allpa_service_model->get_allpa_admin_products(); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // ADMIN.3.b 產品列表 - 購買管理者產品 + public function purchase_admin_products() + { + if(!$this->session->userdata('logged_in')){echo json_encode(null, JSON_UNESCAPED_UNICODE);return;} // 沒登入就回傳null + + $product_id = $this->input->post('product_id', true); + $data = $this->allpa_service_model->create_admin_bill($product_id); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // ADMIN.3.c 管理者結帳 + public function transfer_money_admin() + { + if(!$this->session->userdata('logged_in')){echo json_encode(null, JSON_UNESCAPED_UNICODE);return;} // 沒登入就回傳null + + $lpr = strtoupper($this->uri->segment(3)); // 車牌號碼 + $order_no = strtoupper($this->uri->segment(4)); // 交易序號 + $invoice_receiver = urldecode($this->uri->segment(5)); // 載具編號 (可有可無) + $company_no = urldecode($this->uri->segment(6)); // 載具編號 (可有可無) + $email_base64 = $this->uri->segment(7); // 電子信箱 + $mobile = $this->uri->segment(8); // 手機號碼 + + // decode email + if(strlen($email_base64) > 0){ + $email = base64_decode($email_base64.'='); // base64字串尾端的'='還原 + }else{ + $email = email_base64; + } + + $data = $this->allpa_service_model->pay_bill($lpr, $order_no, $invoice_receiver, $company_no, $email, $mobile); // 記錄訂單設定 + + // 管理員結帳流程 + if (!empty($data)){ + $data = $this->allpa_service_model->get_product_bill($order_no); + + if (!empty($data)){ + $order_no = $data['order_no']; + $lpr = $data['lpr']; + $amt = $data['amt']; + $status = $data['status']; + + switch($status){ + case 100: // 狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中, 101: 交易失敗, 111:產品已領取 + // 先記錄 + $this->allpa_service_model->transfer_money_done($order_no); + + // 開立歐付寶電子發票 + $this->allpay_invoice_model->invoice_issue_for_product_bill($order_no, $amt); + + // 直接開卡 + $this->allpa_service_model->activate_bill_for_new_register($order_no); + + // 交易成功 + $this->show_page(ADMIN_RESULT_PAGE); + break; + default: + // 對方多傳一次時?? + trigger_error(__FUNCTION__.', order_no=>' . $order_no.'
'.'status != 100'); + } + } + } + } + + // [END] 2016/06/08 + + + + + + + + + + + + + + + + + + + // 首頁 + public function index() + { + $this->show_page(MAIN_PAGE); + } + + // 管理 + /* + public function admin() + { + $this->show_page(ADMIN_PAGE); + } + */ + + // A.1 查詢, 用戶歐Pa卡資訊 + // http://203.75.167.89/allpa_service.html/get_allpa_info + public function get_allpa_info() + { + $user_lpr = strtoupper($this->input->post('user_lpr', true)); + $data = $this->allpa_service_model->get_allpa_info($user_lpr); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // A.2 卡片查詢 (API) + public function get_barcode_info() + { + $barcode = $this->input->post('barcode', true); + $result = $this->allpa_service_model->get_barcode_info($barcode); + echo json_encode($result, JSON_UNESCAPED_UNICODE); + } + + // A.3 卡片記名 (API) + public function card_register() + { + $lpr = strtoupper($this->input->post('lpr', true)); + $barcode = $this->input->post('barcode', true); + $result = $this->allpa_service_model->card_register($lpr, $barcode); + echo json_encode($result, JSON_UNESCAPED_UNICODE); + } + + // B.1 啟用, 產品 + public function activate_bill() + { + $order_no = $this->input->post('order_no', true); + $data = $this->allpa_service_model->activate_bill($order_no); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // B.2 儲值 + public function allpa_reload() + { + $order_no = $this->input->post('order_no', true); + $reload_pin = $this->input->post('reload_pin', true); + $pin_check_id = $this->input->post('pin_check_id', true); + $data = $this->allpa_service_model->allpa_reload($order_no, $reload_pin, $pin_check_id); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // B.3 扣款 + public function allpa_pay_bill() + { + $order_no = $this->input->post('order_no', true); + $data = $this->allpa_service_model->allpa_pay_bill($order_no); + if(! $data["result_code"]){ + $data = $this->allpa_service_model->get_allpa_info($data["lpr"]); + } + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // C.1 產品列表 + // http://203.75.167.89/allpa_service.html/get_allpa_products + public function get_allpa_products() + { + $data = $this->allpa_service_model->get_allpa_products(); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // C.2 產品列表 - 購買 + public function purchase() + { + $product_id = $this->input->post('product_id', true); + $data = $this->allpa_service_model->create_bill($product_id); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // C.3 付款 + public function transfer_money() + { + $lpr = strtoupper($this->uri->segment(3)); // 車牌號碼 + $order_no = strtoupper($this->uri->segment(4)); // 交易序號 + $invoice_receiver = urldecode($this->uri->segment(5)); // 載具編號 (可有可無) + $company_no = urldecode($this->uri->segment(6)); // 載具編號 (可有可無) + $email_base64 = $this->uri->segment(7); // 電子信箱 + $mobile = $this->uri->segment(8); // 手機號碼 + + // decode email + if(strlen($email_base64) > 0){ + $email = base64_decode($email_base64.'='); // base64字串尾端的'='還原 + }else{ + $email = email_base64; + } + + $data = $this->allpa_service_model->pay_bill($lpr, $order_no, $invoice_receiver, $company_no, $email, $mobile); // 記錄訂單設定 + + if (!empty($data)){ + $this->ctbcbank_model->transfer_money_ctbc($data, CTBC_AuthResURL); // 中國信託 + } + } + + // C.4 收單行端取得授權碼後,要導回的網址 (call by CTBC) + public function return_ok() + { + /** + =======ALL_REQUEST====== + URLResEnc: AF2100C51A9E844A1E820B953EA512BE49286403253FF9373474F6AE4A5877B084DD4D9B20F03AF0F34DB3D42A9C583938FE5DC1B60C53384864D9581EE997F92552A2F516B04F2FB2FE3E5C10D61CE84C5B63B87379F1048E16AC430AE94989724D8B0087734F73BF40CE904A05D555F526E5A93462C42931A0A7EC1E6AFF8BC39E641A8F5EE8882BD5B02F838BC217A87533AB9FE98CE1DD558B3CC345FC77D06C1783067F75DF94C58B55A826CD33B32355439BF3C9F17A4596138942B4457B66EB8FA09749C246D5B91799FB3942EC90138033272D89861B8698398FF4F3010628C0D11C7D88FB7A5F85CC59717D9F8D5CADBA5A1231E0396AE344B1DA139BA84F9D477E53A73A376BFCC92B52619E3B396BB28ABE7C4CEE3D3ED2CA1BEEF466F2D645C5CBF1C678C5747BA2A048F2F0FC2B86CAE379DE7A7F144D07C31A + merID: 10063 + ----------------------------END + */ + // 取得回傳資訊 + foreach ($_REQUEST as $key => $value) { + switch ($key){ + case "URLResEnc": $resenc = $value; break; + case "merID": $merid = $value; break; + } + } + + if(! empty($resenc)){ + $return_data = $this->ctbcbank_model->ctbcbank_return_handler($resenc, $merid); + $ctbc_lidm = $return_data['lidm']; + $ctbc_authamt = $return_data['authamt']; + $ctbc_status = $return_data['status']; + + if($ctbc_status != 0){ + // 金流處理失敗 + $this->allpa_service_model->transfer_money_done_with_tx_error($order_no); + + }else if(! empty($ctbc_lidm)) { + $data = $this->allpa_service_model->get_product_bill($ctbc_lidm); + + if (! empty($data)) { + $order_no = $data['order_no']; + $lpr = $data['lpr']; + $amt = $data['amt']; + $status = $data['status']; + switch($status){ + case 100: // 狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中, 101: 交易失敗, 111:產品已領取 + // 印發票流程 + if($ctbc_authamt == $amt){ + // 先記錄 + $this->allpa_service_model->transfer_money_done($order_no); + + // 開立歐付寶電子發票 + $this->allpay_invoice_model->invoice_issue_for_product_bill($order_no, $amt); + + // 直接開卡 + $this->allpa_service_model->activate_bill_for_new_register($order_no); + + // 交易成功 + $this->show_page(RESULT_PAGE); + return; + + }else{ + // 錢沒對上 + $this->allpa_service_model->transfer_money_done_with_amt_error($order_no); + } + break; + default: + // 對方多傳一次時?? + trigger_error(__FUNCTION__.', order_no=>' . $order_no.'
'.'status != 100'); + } + }else{ + // 我們自己找不到記錄時?? + trigger_error(__FUNCTION__.', order_no=>' . $order_no.'
'.' NOT FOUND !!'); + } + + }else{ + // 回傳沒有資料 lidm + trigger_error(__FUNCTION__.', ERROR ..lidm=>' . $ctbc_lidm); + } + + }else{ + // 回傳沒有資料 resenc + trigger_error(__FUNCTION__.', ERROR ..resenc=>' . $resenc); + } + + // 交易失敗 + $this->show_page(ERROR_PAGE); + } + + + // L.1 歐Pa卡 - 開門 (限制存取) + // http://203.75.167.89/allpa_service.html/allpa_go/1458699630/QQQ/12112/5dfe0856f3cdf67772710c3e7e805b80 + // http://203.75.167.89/allpa_service.html/allpa_go/1458714030/EEE/12112/19dd4f6692057ad897dc4e0290183a58 + // http://203.75.167.89/allpa_service.html/allpa_go/1458714030/YYY/12112/efb076ad1c1d615e6db8c718c116d2d2 + // http://203.75.167.89/allpa_service.html/allpa_go/1458714030/MMM/12112/4da21617852b4b43b86f8ac36f9db3e5 + // http://203.75.167.89/allpa_service.html/allpa_go/1458714030/BBB/12112/335f61a2a90ba3277cfe0f4cd1a07e26 // KO + // http://203.75.167.89/allpa_service.html/allpa_go/1458897030/KKK/12112/b72332e2939a1a3152aa9d31ef945952 + // http://203.75.167.89/allpa_service.html/allpa_go/1459078230/SAYLXXX/12112/5dd8036423fa8eeb7115cd4249327e08 + public function allpa_go() + { + $in_time = $this->uri->segment(3); // 進場時間 + $lpr = $this->uri->segment(4); // 車牌號碼 + $station_no = $this->uri->segment(5); // 場站編號 + $check_mac = $this->uri->segment(6); // 驗証欄位 + + ob_end_clean(); + ignore_user_abort(); + ob_start(); + + $data = $this->allpa_service_model->allpa_go($in_time, $lpr, $station_no, $check_mac); // 開門 + echo json_encode($data, JSON_UNESCAPED_UNICODE); + + header('Connection: close'); + header('Content-Length: ' . ob_get_length()); + ob_end_flush(); + flush(); + + // 呼叫: 非同步扣款流程 + if(!$data["result_code"]){ + file_get_contents(APP_URL."allpa_consume_handler/{$data["order_no"]}"); + } + } + + // L.2 歐Pa卡 - 非同步扣款 (限制存取) + public function allpa_consume_handler() + { + $order_no = $this->uri->segment(3); // 訂單編號 + $this->allpa_service_model->allpa_pay_bill($order_no); // 扣款 + + //sleep(5); // test delay + exit(); + } + + // L.3 歐Pa卡 - 判斷有效用戶 (限制存取) + public function get_allpa_valid_user() + { + $lpr = $this->uri->segment(3); // 車牌號碼 + $check_mac = $this->uri->segment(4); // 驗証欄位 + + ob_end_clean(); + ignore_user_abort(); + ob_start(); + + $data = $this->allpa_service_model->get_allpa_valid_user($lpr, $check_mac); // check user + echo json_encode($data, JSON_UNESCAPED_UNICODE); + + header('Connection: close'); + header('Content-Length: ' . ob_get_length()); + ob_end_flush(); + flush(); + } + + // only test + public function gen_test_link() + { + $in_time = strtotime("2016-03-29 16:50:00"); + $lpr = "SAYLXXX"; + $station_no = "12112"; + + echo "TEST: ".APP_URL."allpa_go/{$in_time}/{$lpr}/{$station_no}/".md5($in_time.$lpr.$station_no); + echo "
"; + echo "TEST: ".APP_URL."get_allpa_valid_user/{$lpr}/".md5($lpr); + + header('Connection: close'); + header('Content-Length: ' . ob_get_length()); + ob_end_flush(); + flush(); + + + } + +} diff --git a/controllers/Allpay_invoice.php b/controllers/Allpay_invoice.php new file mode 100644 index 0000000..d23b94b --- /dev/null +++ b/controllers/Allpay_invoice.php @@ -0,0 +1,260 @@ +load->model('allpay_invoice_model'); + } + + // 發生錯誤時集中在此處理 + public function error_handler($errno, $errstr, $errfile, $errline, $errcontext) + { + // ex: car_err://message.... + $log_msg = explode('://', $errstr); + if (count($log_msg) > 1) + { + $log_file = LOG_PATH.$log_msg[0]; + $str = date('H:i:s')."|{$log_msg[1]}|{$errfile}|{$errline}|{$errno}\n"; + } + else + { + $log_file = LOG_PATH.APP_NAME; + $str = date('H:i:s')."|{$errstr}|{$errfile}|{$errline}|{$errno}\n"; + } + + $str = date('H:i:s')."|{$errstr}|{$errfile}|{$errline}|{$errno}\n"; + error_log($str, 3, $log_file . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + } + + + // 顯示靜態網頁(html檔) + protected function show_page($page_name, &$data = null) + { + $page_file = PAGE_PATH.$page_name.'.php'; + $last_modified_time = filemtime($page_file); + + /* + // Cross-Origin Resource Sharing Header(允許跨網域連線) + header('Access-Control-Allow-Origin: ' . SERVER_URL); + header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS'); + header('Access-Control-Allow-Headers: X-Requested-With, Content-Type, Accept'); + */ + + // 若檔案修改時間沒有異動, 或版本無異動, 通知瀏覽器使用cache, 不再下傳網頁 + // header('Cache-Control:max-age='.MAX_AGE); // cache 1個月 + header('Last-Modified: '.gmdate('D, d M Y H:i:s', $last_modified_time).' GMT'); + header('Etag: '. APP_VERSION); + header('Cache-Control: public'); + + if (!empty($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == APP_VERSION && @strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time) + { + header('HTTP/1.1 304 Not Modified'); + } + else + { + $this->load->view(APP_NAME.'/'.$page_name, $data); + } + } + + + public function index() + { + $this->show_page('main_page'); + } + + /* + // step 1: 建立待開記錄 + public function test_step1() + { + $station_no = 54321; + $tx_bill_no = 12; + $amt = 1600; + $data = $this->allpay_invoice_model->test_step1_init_bill($station_no, $tx_bill_no, $amt); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // step 2: 開立發票參數 + public function test_step2() + { + $order_no = '14906858560000000012'; + $company_no = 0; + $email = 'saylxxx@gmail.com'; + $mobile = '0953034986'; + $invoice_receiver = 0; + $data = $this->allpay_invoice_model->test_step2_submit_purchase($order_no, $company_no, $email, $mobile, $invoice_receiver); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // step 1: 建立待開記錄與參數 + public function test_step1_step2_submit() + { + $station_no = 54321; + $tx_bill_no = 12; + $amt = 1600; + $company_no = 0; + $email = 'saylxxx@gmail.com'; + $mobile = '0953034986'; + $invoice_receiver = 0; + $data = $this->allpay_invoice_model->test_step1_step2_submit( + $station_no, $tx_bill_no, $amt, + $company_no, $email, $mobile, $invoice_receiver); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // step 3: 開立發票 + public function test_step3() + { + $order_no = '14906866680000000012'; + $amt = 1600; + $data = $this->allpay_invoice_model->invoice_issue_for_tx_bill_ats($order_no, $amt); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 測試:M.1 建立月租系統發票待開記錄 + public function test_create_member_tx_bill_record() + { + $station_no = 54321; + $tx_bill_no = 12; + $amt = 1600; + $company_no = 0; + $email = 'saylxxx@gmail.com'; + $mobile = '0953034986'; + $data = $this->allpay_invoice_model->create_member_tx_bill_record($station_no, $tx_bill_no, $amt, $company_no, $email, $mobile); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + + // 回傳, 要記下 order_no + // {"invoice_remark":"停車費用帳單","order_no":"14906884740000000012","station_no":54321,"amt":1600,"email":"saylxxx@gmail.com","mobile":"0953034986","status":1,"tx_time":"2017\/03\/28 16:07:54","tx_type":100} + } + + // 測試:M.2 開立月租系統待開發票 + public function test_create_member_tx_bill_invoice() + { + $order_no = '14906884740000000012'; + $amt = 1600; + $data = $this->allpay_invoice_model->create_member_tx_bill_invoice($order_no, $amt); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + + // 回傳 + // {"invoice_no":"TM00012802","result_code":"OK","result_msg":"成功"} + } + + // 測試:作廢發票 + public function test_invoice_void() + { + $invoice_no = 'TM00012665'; + $reason_str = 'test'; + $data = $this->allpay_invoice_model->invoice_void($invoice_no, $reason_str); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 測試:作廢月租系統發票 + public function test_void_member_tx_bill_invoice() + { + $station_no = "54321"; + $order_no = "14906958880000000025"; + $invoice_no = "TM00012805"; + $data = $this->allpay_invoice_model->void_member_tx_bill_invoice($station_no, $order_no, $invoice_no); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 測試:開立折讓 + public function test_invoice_allowance() + { + $invoice_no = 'TM00012665'; + $allowance_amt = 1600; + $data = $this->allpay_invoice_model->invoice_allowance($invoice_no, $allowance_amt); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + */ + + public function test_curl() + { + $station_no = 54321; + $tx_bill_no = 25; + $amt = 2640; + $company_no = 0; + $email = 'saylxxx@gmail.com'; + $mobile = '0953034986'; + + $data = $this->allpay_invoice_model->test_curl($station_no, $tx_bill_no, $amt, $company_no, $email, $mobile); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 開立月租系統發票 + public function create_member_tx_bill_invoice() + { + $station_no = $this->input->post('station_no', true); // 場站編號 + $tx_bill_no = $this->input->post('tx_bill_no', true); // 會員交易帳單代號 + $amt = $this->input->post('amt', true); // 金額 + $member_company_no = $this->input->post('member_company_no', true); // 買方統編 + $company_no = $this->input->post('company_no', true); // 賣方統編 + $email = $this->input->post('email', true); // 通知信箱 + $mobile = $this->input->post('mobile', true); // 通知簡訊 + $lpr = $this->input->post('lpr', true); // 車牌號碼 + $data = $this->allpay_invoice_model->create_member_tx_bill_invoice($station_no, $tx_bill_no, $amt, $member_company_no, $company_no, $email, $mobile, $lpr); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 作廢月租系統發票 + public function void_member_tx_bill_invoice() + { + $station_no = $this->input->post('station_no', true); // 場站編號 + $order_no = $this->input->post('order_no', true); // 訂單編號 + $invoice_no = $this->input->post('invoice_no', true); // 發票號碼 + $data = $this->allpay_invoice_model->void_member_tx_bill_invoice($station_no, $order_no, $invoice_no); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 折讓月租系統發票 + public function allowance_member_tx_bill_invoice() + { + $station_no = $this->input->post('station_no', true); // 場站編號 + $invoice_no = $this->input->post('invoice_no', true); // 發票號碼 + $allowance_amt = $this->input->post('allowance_amt', true); // 折讓金額 + $data = $this->allpay_invoice_model->allowance_member_tx_bill_invoice($station_no, $invoice_no, $allowance_amt); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + + // 測試:作廢折讓 + public function test_allowance_void() + { + $invoice_no = 'TM00012665'; + $allowance_no = '2017032814257398'; + $reason_str = 'test'; + $data = $this->allpay_invoice_model->allowance_void($invoice_no, $allowance_no, $reason_str); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } +} diff --git a/controllers/Allpay_payment.php b/controllers/Allpay_payment.php new file mode 100644 index 0000000..3ca0ead --- /dev/null +++ b/controllers/Allpay_payment.php @@ -0,0 +1,413 @@ +load->model('allpay_payment_model'); + $this->load->model('payment_model'); // 一般臨停帳單 (tx_bill) + $this->load->model('payment_ats_model'); // 月租繳費機帳單 (tx_bill_ats) + + /* + // ----- 正式環境 ----- + define('ALLPAY_ServiceURL', "https://payment.ecpay.com.tw/Cashier/AioCheckOut"); // 您要呼叫的服務位址 (綠界) + //define('ALLPAY_ServiceURL', "https://payment.allpay.com.tw/Cashier/AioCheckOut"); // 您要呼叫的服務位址 + define('ALLPAY_HashKey', "tLBnwUiKlbB0e6sS"); // AllPay提供給您的Hash Key + define('ALLPAY_HashIV', "bMhtNluToYSYoJBw"); // AllPay提供給您的Hash IV + define('ALLPAY_MerchantID', "1148391"); // AllPay提供給您的特店編號 + // ----- 正式環境(end) ----- + */ + + // ----- 測試環境 ----- + define('ALLPAY_ServiceURL', "http://payment-stage.allpay.com.tw/Cashier/AioCheckOut"); // 您要呼叫的服務位址 + define('ALLPAY_HashKey', "5294y06JbISpM5x9"); // AllPay提供給您的Hash Key + define('ALLPAY_HashIV', "v77hoKGq4kWxNNIS"); // AllPay提供給您的Hash IV + define('ALLPAY_MerchantID', "2000132"); // AllPay提供給您的特店編號 + // ----- 測試環境(end) ----- + } + + // 發生錯誤時集中在此處理 + public function error_handler($errno, $errstr, $errfile, $errline, $errcontext) + { + $str = date('H:i:s')."|{$errstr}|{$errfile}|{$errline}|{$errno}\n"; + //error_log($str, 3, $log_file . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + error_log($str, 3, LOG_PATH.APP_NAME . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + } + + // 付款 (tx_bill) + public function transfer_money_tx_bill() + { + $order_no = $this->uri->segment(3); // 序號 + try{ + // 0. check tx_bill + $data = $this->payment_model->get_tx_bill($order_no); + + if (! empty($data)) + { + $status = $data['status']; + switch($status){ + case 100: // 狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中 + $oPayment = new AllInOne(); + $oPayment->ServiceURL = ALLPAY_ServiceURL; + $oPayment->HashKey = ALLPAY_HashKey; + $oPayment->HashIV = ALLPAY_HashIV; + $oPayment->MerchantID = ALLPAY_MerchantID; + /* 基本參數 */ + $oPayment->Send['ReturnURL'] = STATION_URL.APP_NAME.'.html/tx_bill_finished/'; // 您要收到付款完成通知的伺服器端網址(server) + $oPayment->Send['ClientBackURL'] = $data['client_back_url']; // 您要歐付寶返回按鈕導向的瀏覽器端網址"; + $oPayment->Send['OrderResultURL'] = $data['order_result_url']; // 您要收到付款完成通知的瀏覽器端網址(browser) ps. WebATM大部份銀行都回不來; + $oPayment->Send['MerchantTradeNo'] = $data['order_no']; // 您此筆訂單交易編號 + $oPayment->Send['MerchantTradeDate'] = date('Y/m/d H:i:s', strtotime($data['tx_time'])); // 交易時間 + $oPayment->Send['TotalAmount'] = (int) $data['amt']; // 您此筆訂單的交易總金額 + $oPayment->Send['TradeDesc'] = $data['invoice_remark']; // 您該筆訂單的描述 + $oPayment->Send['ChoosePayment'] = PaymentMethod::ALL; // PaymentMethod::WebATM; + $oPayment->Send['Remark'] = ""; + $oPayment->Send['ChooseSubPayment'] = PaymentMethodItem::None; + $oPayment->Send['NeedExtraPaidInfo'] = ExtraPaymentInfo::No; + $oPayment->Send['DeviceSource'] = DeviceType::Mobile; //DeviceType::PC; + //$oPayment->Send['IgnorePayment'] = "Alipay#Tenpay"; //"<<您不要顯示的付款方式>>"; // 例(排除支付寶與財富通): Alipay#Tenpay + + // 加入選購商品資料。 + array_push($oPayment->Send['Items'], + array( + 'Name' => "結算", + 'Price' => (int)$data['amt'], + 'Currency' => "元", + 'Quantity' => (int) "1", + 'URL' => "http://www.altob.com.tw" // 網址是做什麼用的 ? + ) + ); + + /* 產生訂單 */ + $oPayment->CheckOut(); + /* 產生訂單 Html Code 的方法 */ + $szHtml = $oPayment->CheckOutString(); + + default: + $sMsg = 'status != 100'; + trigger_error(APP_NAME.', '._FUNCTION_.', order_no=>' . $order_no.'
'.$sMsg); + echo $sMsg; + } + } + + }catch (Exception $e){ + // 例外錯誤處理。 + $sMsg = $e->getMessage(); + trigger_error(APP_NAME.', '._FUNCTION_.', order_no=>' . $order_no.'
'.$sMsg); + echo $sMsg; + } + } + + // 付款 (tx_bill_ats) + public function transfer_money_tx_bill_ats() + { + $order_no = $this->uri->segment(3); // 序號 + try{ + // 0. check tx_bill + $data = $this->payment_ats_model->get_tx_bill($order_no); + + if (! empty($data)) + { + $status = $data['status']; + switch($status){ + case 100: // 狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中 + $oPayment = new AllInOne(); + $oPayment->ServiceURL = ALLPAY_ServiceURL; + $oPayment->HashKey = ALLPAY_HashKey; + $oPayment->HashIV = ALLPAY_HashIV; + $oPayment->MerchantID = ALLPAY_MerchantID; + /* 基本參數 */ + $oPayment->Send['ReturnURL'] = STATION_URL.APP_NAME.'.html/tx_bill_ats_finished/'; // 您要收到付款完成通知的伺服器端網址(server) + $oPayment->Send['ClientBackURL'] = $data['client_back_url']; // 您要歐付寶返回按鈕導向的瀏覽器端網址"; + $oPayment->Send['OrderResultURL'] = $data['order_result_url']; // 您要收到付款完成通知的瀏覽器端網址(browser) ps. WebATM大部份銀行都回不來; + $oPayment->Send['MerchantTradeNo'] = $data['order_no']; // 您此筆訂單交易編號 + $oPayment->Send['MerchantTradeDate'] = date('Y/m/d H:i:s', strtotime($data['tx_time'])); // 交易時間 + $oPayment->Send['TotalAmount'] = (int) $data['amt']; // 您此筆訂單的交易總金額 + $oPayment->Send['TradeDesc'] = $data['invoice_remark']; // 您該筆訂單的描述 + $oPayment->Send['ChoosePayment'] = PaymentMethod::WebATM; //PaymentMethod::ALL;; + $oPayment->Send['Remark'] = ""; + $oPayment->Send['ChooseSubPayment'] = PaymentMethodItem::None; + $oPayment->Send['NeedExtraPaidInfo'] = ExtraPaymentInfo::No; + $oPayment->Send['DeviceSource'] = DeviceType::PC; //DeviceType::Mobile; + //$oPayment->Send['IgnorePayment'] = "Alipay#Tenpay"; //"<<您不要顯示的付款方式>>"; // 例(排除支付寶與財富通): Alipay#Tenpay + + // 加入選購商品資料。 + array_push($oPayment->Send['Items'], + array( + 'Name' => "結算", + 'Price' => (int)$data['amt'], + 'Currency' => "元", + 'Quantity' => (int) "1", + 'URL' => "http://www.altob.com.tw" // 網址是做什麼用的 ? + ) + ); + + /* 產生訂單 */ + $oPayment->CheckOut(); + /* 產生訂單 Html Code 的方法 */ + $szHtml = $oPayment->CheckOutString(); + + default: + $sMsg = 'status != 100'; + trigger_error(APP_NAME.', '._FUNCTION_.', order_no=>' . $order_no.'
'.$sMsg); + echo $sMsg; + } + } + + }catch (Exception $e){ + // 例外錯誤處理。 + $sMsg = $e->getMessage(); + trigger_error(APP_NAME.', '._FUNCTION_.', order_no=>' . $order_no.'
'.$sMsg); + echo $sMsg; + } + } + + // 付款完成 (tx_bill) + public function tx_bill_finished() + { + ob_end_clean(); + ignore_user_abort(); + ob_start(); + + try{ + $oPayment = new AllInOne(); + /* 服務參數 */ + $oPayment->HashKey = ALLPAY_HashKey; + $oPayment->HashIV = ALLPAY_HashIV; + $oPayment->MerchantID = ALLPAY_MerchantID; + /* 取得回傳參數 */ + $arFeedback = $oPayment->CheckOutFeedback(); + /* 檢核與變更訂單狀態 */ + if (sizeof($arFeedback) > 0){ + foreach ($arFeedback as $key => $value){ + switch ($key){ + /* 支付後的回傳的基本參數 */ + case "MerchantID": $szMerchantID = $value; break; + case "MerchantTradeNo": $szMerchantTradeNo = $value; break; + case "PaymentDate": $szPaymentDate = $value; break; + case "PaymentType": $szPaymentType = $value; break; + case "PaymentTypeChargeFee": $szPaymentTypeChargeFee = $value; break; + case "RtnCode": $szRtnCode = $value; break; + case "RtnMsg": $szRtnMsg = $value; break; + case "SimulatePaid": $szSimulatePaid = $value; break; + case "TradeAmt": $szTradeAmt = $value; break; + case "TradeDate": $szTradeDate = $value; break; + case "TradeNo": $szTradeNo = $value; break; + default: break; + } + } + // 一律記錄log。 + $data = array( + 'merchant_id' => $szMerchantID, + 'merchant_trade_no' => $szMerchantTradeNo, + 'payment_date' => $szPaymentDate, + 'payment_type' => $szPaymentType, + 'payment_type_charge_fee' => $szPaymentTypeChargeFee, + 'rtn_code' => $szRtnCode, + 'rtn_msg' => $szRtnMsg, + 'simulate_paid' => $szSimulatePaid, + 'trade_amt' => $szTradeAmt, + 'trade_date' => $szTradeDate, + 'trade_no' => $szTradeNo + ); + $this->allpay_payment_model->create_allpay_feedback_log($data); + + print '1|OK'; //先回傳ok + + header('Connection: close'); + header('Content-Length: ' . ob_get_length()); + ob_end_flush(); + flush(); + + // 此筆交易為成功 + if($szRtnCode == '1') + { + $data = $this->payment_model->get_tx_bill($szMerchantTradeNo); + if (! empty($data)) + { + $order_no = $data['order_no']; + $amt = $data['amt']; + $status = $data['status']; + switch($status){ + case 100: // 狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中 + // 印發票流程 + if($szTradeAmt == $amt){ + // 先記錄 + $this->payment_model->transfer_money_done($order_no); + + if(! empty($data["service_url"])){ + file_get_contents($data["service_url"]."/{$order_no}"); // 執行指定的結帳呼叫 + + }else{ + // 找不到付款成功服務位址 + trigger_error(APP_NAME.', '._FUNCTION_.', order_no=>' . $order_no.'
'.'service_url not found..'); + } + + }else{ + // 錢沒對上 + $this->payment_model->transfer_money_done_with_amt_error($szMerchantTradeNo); + } + break; + default: + // 對方多傳一次時?? + trigger_error(APP_NAME.', '._FUNCTION_.', order_no=>' . $order_no.'
'.'tx_bill.status != 100'); + } + }else{ + // 我們自己找不到記錄時?? + trigger_error(APP_NAME.', '._FUNCTION_.', order_no=>' . $order_no.'
'.'tx_bill NOT FOUND !!'); + } + } + + }else{ + print '0|Fail'; + } + + }catch (Exception $e){ + // 例外錯誤處理。 + print '0|' . $e->getMessage(); + } + + exit(); + } + + // 付款完成 (tx_bill_ats) + public function tx_bill_ats_finished() + { + ob_end_clean(); + ignore_user_abort(); + ob_start(); + + try{ + $oPayment = new AllInOne(); + /* 服務參數 */ + $oPayment->HashKey = ALLPAY_HashKey; + $oPayment->HashIV = ALLPAY_HashIV; + $oPayment->MerchantID = ALLPAY_MerchantID; + /* 取得回傳參數 */ + $arFeedback = $oPayment->CheckOutFeedback(); + /* 檢核與變更訂單狀態 */ + if (sizeof($arFeedback) > 0){ + foreach ($arFeedback as $key => $value){ + switch ($key){ + /* 支付後的回傳的基本參數 */ + case "MerchantID": $szMerchantID = $value; break; + case "MerchantTradeNo": $szMerchantTradeNo = $value; break; + case "PaymentDate": $szPaymentDate = $value; break; + case "PaymentType": $szPaymentType = $value; break; + case "PaymentTypeChargeFee": $szPaymentTypeChargeFee = $value; break; + case "RtnCode": $szRtnCode = $value; break; + case "RtnMsg": $szRtnMsg = $value; break; + case "SimulatePaid": $szSimulatePaid = $value; break; + case "TradeAmt": $szTradeAmt = $value; break; + case "TradeDate": $szTradeDate = $value; break; + case "TradeNo": $szTradeNo = $value; break; + default: break; + } + } + // 一律記錄log。 + $data = array( + 'merchant_id' => $szMerchantID, + 'merchant_trade_no' => $szMerchantTradeNo, + 'payment_date' => $szPaymentDate, + 'payment_type' => $szPaymentType, + 'payment_type_charge_fee' => $szPaymentTypeChargeFee, + 'rtn_code' => $szRtnCode, + 'rtn_msg' => $szRtnMsg, + 'simulate_paid' => $szSimulatePaid, + 'trade_amt' => $szTradeAmt, + 'trade_date' => $szTradeDate, + 'trade_no' => $szTradeNo + ); + $this->allpay_payment_model->create_allpay_feedback_log($data); + + print '1|OK'; //先回傳ok + + header('Connection: close'); + header('Content-Length: ' . ob_get_length()); + ob_end_flush(); + flush(); + + // 此筆交易為成功 + if($szRtnCode == '1') + { + $data = $this->payment_ats_model->get_tx_bill($szMerchantTradeNo); + if (! empty($data)) + { + $order_no = $data['order_no']; + $amt = $data['amt']; + $status = $data['status']; + switch($status){ + case 100: // 狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中 + // 印發票流程 + if($szTradeAmt == $amt){ + // 先記錄 + $this->payment_ats_model->transfer_money_done($order_no); + + if(! empty($data["service_url"])){ + file_get_contents($data["service_url"]."/{$order_no}"); // 執行指定的結帳呼叫 + + }else{ + // 找不到付款成功服務位址 + trigger_error(APP_NAME.', '._FUNCTION_.', order_no=>' . $order_no.'
'.' service_url not found..'); + } + + }else{ + // 錢沒對上 + $this->payment_ats_model->transfer_money_done_with_amt_error($szMerchantTradeNo); + } + break; + default: + // 對方多傳一次時?? + trigger_error(APP_NAME.', '._FUNCTION_.', order_no=>' . $order_no.'
'.' status != 100'); + } + }else{ + // 我們自己找不到記錄時?? + trigger_error(APP_NAME.', '._FUNCTION_.', order_no=>' . $order_no.'
'.' NOT FOUND !!'); + } + } + + }else{ + print '0|Fail'; + } + + }catch (Exception $e){ + // 例外錯誤處理。 + print '0|' . $e->getMessage(); + } + + exit(); + } + +} diff --git a/controllers/Carpark.php b/controllers/Carpark.php new file mode 100644 index 0000000..798b3d0 --- /dev/null +++ b/controllers/Carpark.php @@ -0,0 +1,872 @@ +vars['mcache'] = new Memcache; + $this->vars['mcache']->connect(MEMCACHE_HOST, MEMCACHE_PORT) or die ('Could not connect memcache'); + + // mqtt subscribe + $this->vars['mqtt'] = new phpMQTT(MQ_HOST, MQ_PORT, uniqid()); + //if(!$this->vars['mqtt']->connect()){ die ('Could not connect mqtt'); } + $this->vars['mqtt']->connect(); + + $this->load->model('carpark_model'); + $this->carpark_model->init($this->vars); + + // 微調剩餘車位數 + $this->load->model('sync_data_model'); + $this->sync_data_model->init($this->vars); + + // 產生 excel 報表 + $this->load->model('excel_model'); + $this->excel_model->init($this->vars); + + // [START] 2016/06/03 登入 + $this->load->model('user_model'); + // load library + $this->load->library(array('form_validation','session')); + // load helpers + $this->load->helper(array('form')); + // ajax code + define('RESULT_SUCCESS', 'ok'); + define('RESULT_FORM_VALIDATION_FAIL', '-1'); + define('RESULE_FAIL', 'gg'); + // [START] 2016/06/03 登入 + } + + + // 發生錯誤時集中在此處理 + public function error_handler($errno, $errstr, $errfile, $errline, $errcontext) + { + // ex: car_err://message.... + $log_msg = explode('://', $errstr); + if (count($log_msg) > 1) + { + $log_file = LOG_PATH.$log_msg[0]; + $str = date('H:i:s')."|{$log_msg[1]}|{$errfile}|{$errline}|{$errno}\n"; + } + else + { + $log_file = LOG_PATH.APP_NAME; + $str = date('H:i:s')."|{$errstr}|{$errfile}|{$errline}|{$errno}\n"; + } + + //$str = date('H:i:s')."|{$errstr}|{$errfile}|{$errline}|{$errno}\n"; + error_log($str, 3, $log_file . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + } + + + // 顯示靜態網頁(html檔) + protected function show_page($page_name, &$data = null) + { + $page_file = PAGE_PATH.$page_name.'.php'; + $last_modified_time = filemtime($page_file); + + // 若檔案修改時間沒有異動, 或版本無異動, 通知瀏覽器使用cache, 不再下傳網頁 + // header('Cache-Control:max-age='.MAX_AGE); // cache 1個月 + header('Last-Modified: '.gmdate('D, d M Y H:i:s', $last_modified_time).' GMT'); + header('Etag: '. APP_VERSION); + header('Cache-Control: public'); + + // 20170921 + header("cache-Control: no-store, no-cache, must-revalidate"); + header("cache-Control: post-check=0, pre-check=0", false); + header("Pragma: no-cache"); + header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); + + if (!empty($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == APP_VERSION && @strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time) + { + header('HTTP/1.1 304 Not Modified'); + } + else + { + $this->load->view(APP_NAME.'/'.$page_name, $data); + } + } + + + + + + + // ------------------------------------------------ + // + // 接收端 (START) + // + // ------------------------------------------------ + + // [設定檔] 取得設定 + public function station_setting_query() + { + $reload = $this->input->post('reload', true); + + if(isset($reload) && $reload > 0) + { + $station_setting = $this->sync_data_model->station_setting_query(true); // 強制重新載入 + trigger_error(__FUNCTION__ . '..station_setting: '. print_r($station_setting, true)); + + if(!$station_setting) + { + echo json_encode('fail', JSON_UNESCAPED_UNICODE); + exit; // 中斷 + } + + $info = array('station_no_arr' => $station_setting['station_no']); + + usleep(300000); // 0.3 sec delay + + // 費率資料同步 + $result = $this->sync_data_model->sync_price_plan($info); + trigger_error(__FUNCTION__ . '..sync_price_plan: '. $result); + + usleep(300000); // 0.3 sec delay + + // 會員資料同步 + $result = $this->sync_data_model->sync_members($info); + trigger_error(__FUNCTION__ . '..sync_members: '. $result); + + usleep(300000); // 0.3 sec delay + + // 在席資料同步 + $result = $this->sync_data_model->sync_pks_groups_reload($station_setting); + trigger_error(__FUNCTION__ . '..sync_pks_groups_reload: '. $result); + } + else + { + $station_setting = $this->sync_data_model->station_setting_query(false); + + if(!$station_setting) + { + echo json_encode('fail', JSON_UNESCAPED_UNICODE); + exit; // 中斷 + } + } + echo json_encode($station_setting, JSON_UNESCAPED_UNICODE); + } + + // [排程 or 強制] 同步場站資訊 + public function sync_station_data() + { + trigger_error(__FUNCTION__ . '..from..'. $this->my_ip() .'..network..'); // IP 會浮動? + + $switch_lpr_arr = array(); // 換車牌 + + $meta = $this->input->post('meta', true); + if(!empty($meta)) + { + trigger_error( __FUNCTION__ . '..meta_arr..' . $meta); + + $meta_arr = explode('@@@', $meta); + + foreach($meta_arr as $raw) + { + if(empty($raw)) + continue; + + $data = json_decode($raw, true); + + if($data['key'] == 'switch_lpr') + { + array_push($switch_lpr_arr, $data['value']); + } + } + } + + // 0. 取得場站設定 + $station_setting = $this->sync_data_model->station_setting_query(false); + trigger_error(__FUNCTION__ . '..station_setting: '. print_r($station_setting, true)); + + $station_no_arr = array('station_no_arr' => $station_setting['station_no']); + + // 1. 月租系統 + $result = $this->sync_data_model->sync_members($station_no_arr); + trigger_error(__FUNCTION__ . '..sync_members: '. $result); + + // 2. 同步車牌更換 + if(!empty($switch_lpr_arr)) + { + $this->sync_data_model->sync_switch_lpr($switch_lpr_arr); + } + + } + + // [API] 取得最新未結清 + public function get_last_unbalanced_cario() + { + trigger_error(__FUNCTION__ . '..from..'. $this->my_ip() .'..network..'); // IP 會浮動? + + $lpr = $this->input->post('lpr', true); + $station_no = $this->input->post('station_no', true); + $c_s = $this->input->post('c_s', true); + + // 確認正確性 + if(empty($c_s) || $c_s != md5('altob'.$lpr.'botla'.$station_no)) + { + trigger_error(__FUNCTION__ . "..{$lpr}|".$station_no."|{$c_s}..check fail.."); + echo 'fail'; + exit; + } + + $data = $this->carpark_model->get_last_unbalanced_cario($lpr, $station_no); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // [API] 更新未結清 (行動支付) + public function sync_m2payed() + { + trigger_error(__FUNCTION__ . '..from..'. $this->my_ip() .'..network..'); // IP 會浮動? + + $lpr = $this->input->post('lpr', true); + $amt = $this->input->post('amt', true); + $station_no = $this->input->post('station_no', true); + $cario_no = $this->input->post('cario_no', true); + $c_s = $this->input->post('c_s', true); + + // 確認正確性 + if(empty($c_s) || $c_s != md5($lpr.$amt.'altob'.$station_no.'botla'.$cario_no)) + { + trigger_error(__FUNCTION__ . "..{$lpr}|{$amt}|{$station_no}|{$cario_no}|{$c_s}..check fail.."); + echo 'fail'; + exit; + } + + // 臨停繳費 + $this->load->model('carpayment_model'); + echo $this->carpayment_model->p2payed(array('seqno' => $cario_no, 'lpr' => $lpr, 'amt' => $amt), true); + exit; + //echo 'ok'; + } + + // 驗証 IP + function is_ip_valid() + { + $client_ip = $this->my_ip(); + if(!in_array($client_ip, array('61.219.172.11', '61.219.172.82'))) + { + trigger_error('..block..from:'.$client_ip.'..unknown network..'); + return false; + } + return true; + } + + // 取得 IP + function my_ip() + { + if (getenv('HTTP_X_FORWARDED_FOR')) + { + $ip = getenv('HTTP_X_FORWARDED_FOR'); + } + elseif (getenv('HTTP_X_REAL_IP')) + { + $ip = getenv('HTTP_X_REAL_IP'); + } + else { + $ip = $_SERVER['REMOTE_ADDR']; + } + + return $ip; + } + + // 同步 (由排程呼叫) + public function sync_minutely() + { + $this->sync_data_model->sync_pks_groups(); // 同步在席現況 + } + + // 20170816 手動新增入場資料 + public function gen_carin() + { + trigger_error(__FUNCTION__ . '..from..'. $this->my_ip() .'..network..'); // IP 會浮動? + + $lpr = $this->input->post('lpr', true); + $station_no = $this->input->post('station_no', true); + $c_s = $this->input->post('c_s', true); + + // 確認正確性 + if(empty($c_s) || $c_s != md5($lpr.'altob'.$station_no.'botla'. __FUNCTION__ )) + { + trigger_error(__FUNCTION__ . "..{$lpr}|{$station_no}|{$c_s}..check fail.."); + echo 'fail'; + exit; + } + + $parms = array( + 'sno' => $station_no, + 'lpr' => $lpr, + 'etag' => 'NONE', + 'io' => 'CI', + 'ivsno' => 0 + ); + + $this->carpark_model->gen_carin($parms); + echo 'ok'; + } + + // ------------------------------------------------ + // + // 接收端 (END) + // + // ------------------------------------------------ + + + + + // [START] 2016/06/03 登入 + + public function index() + { + if($this->session->userdata('logged_in')) + { + $session_data = $this->session->userdata('logged_in'); + $data['username'] = $session_data['username']; + $data['type'] = $session_data['type']; + + if($data['type'] == 'admin') + { + $this->show_page('admin_page', $data); // 進階管理者介面 + } + else + { + $this->show_page('main_page', $data); // 一般 + } + } + else + { + //If no session, redirect to login page + //redirect('login', 'refresh'); + $this->show_page('login_page'); + } + } + + // 登入 + public function user_login() + { + // form_validation + $this->form_validation->set_rules('login_name', 'login_name', 'trim|required'); + $this->form_validation->set_rules('pswd', 'pswd', 'trim|required'); + + if($this->form_validation->run() == FALSE) + { + return RESULT_FORM_VALIDATION_FAIL; + } + + // go model + $data = array + ( + 'login_name' => $this->input->post('login_name', true), + 'pswd' => $this->input->post('pswd', true) + ); + + $result = $this->user_model->user_login($data); + + if($result) + { + $sess_array = array(); + foreach($result as $row) + { + $sess_array = array + ( + 'username' => $row->login_name , + 'type' => $row->user_type + ); + $this->session->set_userdata('logged_in', $sess_array); + } + echo RESULT_SUCCESS; + } + else + { + return RESULE_FAIL; + } + } + + // 登出 + public function user_logout() + { + $this->session->unset_userdata('logged_in'); + session_destroy(); + return RESULT_SUCCESS; + } + + // [END] 2016/06/03 登入 + + + + + + // response http + protected function http_return($return_code, $type) + { + if ($type == 'text') echo $return_code; + else echo json_encode($return_code, JSON_UNESCAPED_UNICODE); + + } + + // 送出html code + public function get_html() + { + /* + $data = array + ( + 'company_no' => $this->input->post('company_no', true), // 場站統編 + 'hq_company_no' => '80682490' + ); + $this->load->view(APP_NAME.'/'.$this->input->post('tag_name', true), $data); + */ + $this->load->view(APP_NAME.'/'.$this->input->post('tag_name', true), array()); + } + + // 讀取cookie內容 + protected function get_cookie($cookie_name) + { + if (empty($_COOKIE[$cookie_name])) return array(); + return(json_decode($_COOKIE[$cookie_name], true)); + } + + + // 儲存cookie內容 + protected function save_cookie($cookie_name, $cookie_info) + { + return setcookie($cookie_name, json_encode($cookie_info, JSON_UNESCAPED_UNICODE), 0, '/'); + } + + + // 月租資料同步 + public function rent_sync() + { + $station_no = $this->input->post('station_no', true); + $start_date = $this->input->post('start_date', true); + $end_date = $this->input->post('end_date', true); + + // $data = $this->carpark_model->rent_sync($station_no, $start_date, $end_date); + + // print_r($data); + } + // 重設剩餘車位數 + public function available_set() + { + $data = $this->carpark_model->available_set(); + $this->http_return($data, 'json'); + } + + + // 剩餘車位數更新 + public function available_update() + { + $station_no = $this->input->get_post('station_no', true); + $data['name'] = $this->input->get_post('st_name', true); + $data['tot_pkg'] = $this->input->get_post('tot_pkg', true); + $data['ava_pkg'] = $this->input->get_post('ava_pkg', true); + + $this->http_return($this->carpark_model->available_update($station_no, $data), 'json'); + } + + + // 剩餘車位數查核 + public function available_check() + { + $time_point = $this->input->get_post('time_point', true); + + $this->http_return($this->carpark_model->available_check($time_point), 'json'); + } + + // 顯示logs + public function show_logs() + { + $lines = $this->uri->segment(3); // 顯示行數 + if (empty($lines)) $lines = 140; // 無行數參數, 預設為40行 + if($lines > 1000) $lines = 1000; // 最多 1000行 + + // echo ''; + echo ''; + + passthru('/usr/bin/tail -n ' . $lines . ' ' . LOG_PATH.APP_NAME . '.' . date('Ymd').'.log.txt'); // 利用linux指令顯示倒數幾行的logs內容 + echo "\n----- " . LOG_PATH.APP_NAME . '.' . date('Ymd').'.log.txt' . ' -----'; + echo ''; + } + + // 顯示logs (cars grep 888) + public function show_888_logs() + { + $lines = $this->uri->segment(3); // 顯示行數 + if (empty($lines)) $lines = 1000; // 無行數參數, 預設為1000行 + if($lines > 20000) $lines = 20000; // 最多 20000行 + + $grep_str = ' |grep 888'; + $target_str = LOG_PATH.APP_NAME . '.' . date('Ymd').'.log.txt'. $grep_str; + + // echo ''; + echo ''; + + passthru('/usr/bin/tail -n ' . $lines . ' ' . $target_str); // 利用linux指令顯示倒數幾行的logs內容 + echo "\n----- " . $target_str . ' -----'; + echo ''; + } + + // 新增月租資料 + public function member_add() + { + $data = array + ( + 'member_no' => $this->input->post('member_no', true), + 'station_no' => $this->input->post('station_no', true), + 'lpr' => strtoupper($this->input->post('lpr', true)), + 'old_lpr' => strtoupper($this->input->post('old_lpr', true)), + 'etag' => strtoupper($this->input->post('etag', true)), + 'start_date' => $this->input->post('start_date', true), + 'end_date' => $this->input->post('end_date', true), + 'member_name' => $this->input->post('member_name', true), + 'member_nick_name' => $this->input->post('member_name', true), + 'mobile_no' => $this->input->post('mobile_no', true), + 'member_id' => $this->input->post('member_id', true), + 'contract_no' => $this->input->post('contract_no', true), + 'amt' => $this->input->post('amt', true), + 'tel_h' => $this->input->post('tel_h', true), + 'tel_o' => $this->input->post('tel_o', true), + 'addr' => $this->input->post('addr', true) + ); + + trigger_error("add:".print_r($data, true)); + if ($data['member_no'] == 0 || $data['old_lpr'] != $data['lpr']) + { + if ($this->carpark_model->check_lpr($data['lpr']) > 0) + { + echo '車牌重複, 請查明再輸入'; + exit; + } + } + + $this->carpark_model->member_add($data); + echo 'ok'; + } + + + // 查詢月租資料 + public function member_query() + { + $data = $this->carpark_model->member_query(); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + + // 刪除月租資料 + public function member_delete() + { + $member_no = $this->input->post('member_no', true); + $this->carpark_model->member_delete($member_no); + echo 'ok'; + } + + + // 進出場現況表 + public function cario_list() + { + $data = $this->carpark_model->cario_list(); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + + // 進出場事件即時顯示 + public function cario_event() + { + set_time_limit(0); + while(true) + { + + } + } + + + // 顯示圖檔(http://url/carpark.html/pics/lpr_ABY8873_O_0_0_C_20150919210022) + public function pics() + { + // ??? + readfile(CAR_PIC.$this->uri->segment(3).'/'.str_replace('/', '', $this->uri->segment(4)).'.jpg'); + } + + + // 汽車開門 + public function opendoors() + { + $ivsno = $this->uri->segment(3); + $lanes = array + ( + 0 => array ('devno' => 0, 'temp' => 0, 'member' => 1), // 1號入口, temp:臨停, member:月租 +// 1 => array ('devno' => 0, 'temp' => 2, 'member' => 3), // 2號調撥入口 + 1 => array ('devno' => 1, 'temp' => 0, 'member' => 1), // 3號調撥出口 + 2 => array ('devno' => 1, 'temp' => 0, 'member' => 1), // 3號調撥出口 + 3 => array ('devno' => 1, 'temp' => 2, 'member' => 3) // 4號出口 + ); + + $url = 'http://admin:99999999@192.168.10.53/cgi-bin/basic_setting.cgi?ID=1&'; + $member_tag = 'member'; // member:月租會員 + + // 短路開柵欄 + @get_headers("{$url}OUTDEV={$lanes[$ivsno]['devno']}&OUTCH={$lanes[$ivsno][$member_tag]}&OUTSTATUS=1"); + + usleep(400000); // 暫停0.4秒 + + // 斷路, 車過關柵欄 + @get_headers("{$url}OUTDEV={$lanes[$ivsno]['devno']}&OUTCH={$lanes[$ivsno][$member_tag]}&OUTSTATUS=0"); + } + + + + // 調撥車道查詢 + public function reversible_lane_query() + { + $max_lane = 4; // 共幾個車道數 + for ($idx = 0; $idx < $max_lane; ++$idx) + { + $data[$idx] = file_get_contents("http://192.168.10.51:8090/cgi-bin/switcher.cgi?id={$idx}&action=9"); + } + // $data = array(1, 1, 0, 1); + echo json_encode($data); + } + + + // 車號入場查詢 + public function carin_lpr_query() + { + $lpr = $this->uri->segment(3); + $data = $this->carpark_model->carin_lpr_query($lpr); + echo json_encode($data); + } + + + // 以時間查詢入場資訊 + public function carin_time_query() + { + $time_query = $this->input->post('time_query', true); + $minutes_range = $this->input->post('minutes_range', true); + + $data = $this->carpark_model->carin_time_query($time_query, $minutes_range); + echo json_encode($data); + } + + // 調撥車道設定 + public function reversible_lane_set() + { + $lane_no = $this->input->post('lane_no', true); + $actions = $this->input->post('actions', true); + $data = file_get_contents("http://192.168.10.51:8090/cgi-bin/switcher.cgi?id={$lane_no}&action={$actions}"); + + echo "{$lane_no}|{$actions}|{$data}"; + } + + + // 在席車位檢查未有入場資料清單 + public function pks_check_list() + { + $max_rows = $this->uri->segment(3, 100); // 一次讀取筆數, 預設為100筆 + $data = $this->carpark_model->pks_check_list($max_rows); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + + // 重設在席查核 + public function reset_pks_check() + { + $data = $this->carpark_model->reset_pks_check(); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + + // 更正在席車號 + public function correct_pks_lpr() + { + $pksno = $this->uri->segment(3, 0); // 車格號碼 + $lpr = $this->uri->segment(4, 'NONE'); // 車號 + + if ($pksno == 0 || $lpr == 'NONE') + { + echo json_encode(array('err' => 1, 'cario_no' => 0), JSON_UNESCAPED_UNICODE); + } + else + { + $data = $this->carpark_model->correct_pks_lpr($pksno, $lpr); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + } + + + // 入場車號查核在席無資料清單 + public function carin_check_list() + { + $max_rows = $this->uri->segment(3, 20); // 一次讀取筆數, 預設為100筆 + $data = $this->carpark_model->carin_check_list($max_rows); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 更正入場車號 + public function correct_carin_lpr() + { + $cario_no = $this->uri->segment(3, 0); // 車格號碼 + $lpr = $this->uri->segment(4, 'NONE'); // 車號 + $in_time = urldecode($this->uri->segment(5, '')); // 入場時間 + + $data = $this->carpark_model->correct_carin_lpr($cario_no, $lpr, $in_time); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 查詢行動支付記錄 + public function tx_bill_query() + { + $data = $this->carpark_model->tx_bill_query(); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 查詢月租繳款機記錄 + public function tx_bill_ats_query() + { + $data = $this->carpark_model->tx_bill_ats_query(); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 查詢樓層在席群組 + public function pks_group_query() + { + $data = $this->carpark_model->pks_group_query(); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 微調剩餘車位數 + public function pks_availables_update() + { + $group_id = $this->uri->segment(3); // id + $value = $this->uri->segment(4, 0); // value + $station_no = $this->uri->segment(5); // station_no + $data = $this->sync_data_model->pks_availables_update($group_id, $value, true, $station_no); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 進出場觸發 888 呼叫 + /* + public function sync_888() + { + $io = $this->uri->segment(3); // CI, CO, MI, MO + + if(empty($io)) + { + echo 'io_not_found'; + exit; + } + + $parms = array('io' => $io, 'etag' => __FUNCTION__, 'lpr' => __FUNCTION__); + echo $this->sync_data_model->sync_888($parms); + exit; + } + */ + + public function test() + { + //echo `whoami`; + //echo phpinfo(); + } + + // 博辰測試用 + // http://localhost/carpark.html/test_8068_002/APK7310 + public function test_8068_002() + { + $lpr_in = $this->uri->segment(3); + + $seqno = '00001'; + $cmd = '002'; + $token = '000000000'; + $lpr = str_pad($lpr_in, 7, '%', STR_PAD_LEFT); + $in_time = '2000/01/01 00:00:00'; + + $error_str = ''; + $service_port = 8068; + $address = "192.168.10.201"; + + /* Create a TCP/IP socket. */ + $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); + if ($socket === false) { + echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n"; + $error_str .= "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n"; + } else { + echo "OK.\n"; + } + + echo "Attempting to connect to '{$address}' on port '{$service_port}'..."; + $result = socket_connect($socket, $address, $service_port); + if ($result === false) { + echo "socket_connect() failed.\nReason: ({$result}) " . socket_strerror(socket_last_error($socket)) . "\n"; + $error_str .= "socket_connect() failed: reason: " . socket_strerror(socket_last_error($socket)) . "\n"; + } else { + echo "OK.\n"; + } + + $in = pack('Ca5Ca3Ca9Ca7Ca19', 0x1c, $seqno, 0x1c, $cmd, 0x1c, + $token, 0x1f, $lpr, 0x1f, $in_time + ); + $out = ''; + echo "socket_write:"; + echo "{$in}
"; + + if(!socket_write($socket, $in, strlen($in))) + { + echo('Write failed
'); + $error_str .= "socket_write() failed: reason: " . socket_strerror(socket_last_error($socket)) . "\n"; + } + echo "socket_write..OK.."; + + echo "
socket_read:"; + $out = socket_read($socket, 2048) or die("Could not read server responsen"); + //while ($out = socket_read($socket, 2048)) { + // echo $out; + //} + echo "{$out}
"; + + echo "Closing socket..."; + socket_close($socket); + echo "OK.\n\n"; + + trigger_error($error_str); + exit; + } + + // test + public function test_phpexcel() + { + $query_year = 2017; + $query_month = 3; + + //$this->excel_model->export_cario_data($query_year, $query_month); + $this->excel_model->export_members(); + } + +} diff --git a/controllers/Carpayment.php b/controllers/Carpayment.php new file mode 100644 index 0000000..40ec137 --- /dev/null +++ b/controllers/Carpayment.php @@ -0,0 +1,238 @@ +time_start = microtime(true); + parent::__construct(); + + ignore_user_abort(); // 接受client斷線, 繼續run + + $this->vars['date_time'] = date('Y-m-d H:i:s'); // 格式化時間(2015-10-12 14:36:21) + $this->vars['time_num'] = str_replace(array('-', ':', ' '), '', $this->vars['date_time']); //數字化時間(20151012143621) + $this->vars['date_num'] = substr($this->vars['time_num'], 0, 8); // 數字化日期(20151012) + //$this->vars['station_no'] = STATION_NO; // 本站編號 + + // session_id(ip2long($_SERVER['REMOTE_ADDR'])); // 設定同一device為同一個session + session_start(); + + // ----- 程式開發階段log設定 ----- + if (@ENVIRONMENT == 'development') + { + ini_set('display_errors', '1'); + //error_reporting(E_ALL ^ E_NOTICE); + error_reporting(E_ALL); + } + set_error_handler(array($this, 'error_handler'), E_ALL); // 資料庫異動需做log + + /* + // 共用記憶體 + $this->vars['mcache'] = new Memcache; + $this->vars['mcache']->pconnect(MEMCACHE_HOST, MEMCACHE_POST) or die ('Could not connect memcache'); + + // mqtt subscribe + $this->vars['mqtt'] = new phpMQTT(MQ_HOST, MQ_PORT, uniqid()); + if(!$this->vars['mqtt']->connect()){ die ('Could not connect mqtt'); } + + */ + $this->load->model('carpayment_model'); + $this->carpayment_model->init($this->vars); + } + + + // 發生錯誤時集中在此處理 + public function error_handler($errno, $errstr, $errfile, $errline, $errcontext) + { + $log_msg = explode('://', $errstr); + if (count($log_msg) > 1) + { + $log_file = $log_msg[0]; + $str = date('H:i:s')."|{$log_msg[1]}|{$errfile}|{$errline}|{$errno}\n"; + } + else + { + $log_file = APP_NAME; + $str = date('H:i:s')."|{$errstr}|{$errfile}|{$errline}|{$errno}\n"; + } + + error_log($str, 3, LOG_PATH.$log_file . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + } + + + // 顯示logs + public function show_logs() + { + $lines = $this->uri->segment(3); // 顯示行數 + if (empty($lines)) $lines = 100; // 無行數參數, 預設為40行 + + // echo ''; + echo ''; + + passthru('/usr/bin/tail -n ' . $lines . ' ' . LOG_PATH.APP_NAME . '.' . date('Ymd').'.log.txt'); // 利用linux指令顯示倒數幾行的logs內容 + echo "\n----- " . LOG_PATH.APP_NAME . '.' . date('Ymd').'.log.txt' . ' -----'; + echo ''; + } + + + // http://localhost/carpayment.html/p2payed/ (post method) + // 可用$this->input->is_cli_request()判斷是否在cli之下執行 + // 博辰aps已付款 + public function p2payed() + { + $parms['ticket_no'] = $this->input->post('ticket_no', true); + $parms['lpr'] = trim($this->input->post('lpr', true)); + $parms['in_time'] = $this->input->post('in_time', true); + $parms['pay_time'] = $this->input->post('pay_time', true); + $parms['pay_type'] = $this->input->post('pay_type', true); + trigger_error('博辰付款參數:' . print_r($parms, true)); + + $this->carpayment_model->p2payed($parms); + } + + /* + 月租繳款完成 + http://203.75.167.89/carpayment.html/memberpayed/12345/ABC1234/120/12112/1/2016-01-31/1f3870be274f6c49b3e31a0c6728957f + http://203.75.167.89/carpayment.html/memberpayed/會員號碼/車牌/金額/場站編號/月繳/本期到期日/md5 + md5(會員號碼.車牌.金額.場站編號.月繳.本期到期日) + public function memberpayed() + { + $parms['member_no'] = $lines = $this->uri->segment(3); + $parms['lpr'] = $lines = $this->uri->segment(4); + $parms['amt'] = $lines = $this->uri->segment(5); + $parms['station_no'] = $lines = $this->uri->segment(6); + $parms['period_type'] = $lines = $this->uri->segment(7); + $parms['expire_date'] = $lines = $this->uri->segment(8); + $md5 = $this->uri->segment(9); + if (md5($parms['member_no'].$parms['lpr'].$parms['amt'].$parms['station_no'].$parms['seqno'].$parms['period_type'].$parms['expire_date']) === $md5) + { + $this->carpayment_model->memberpayed($parms); + } + } + */ + + // 繳費機告知已付款 (new 2016/07/15) + // http://localhost/carpayment.html/ats2payed/車牌/金額/場站編號/序號/MD5 + // md5(車牌.金額.場站編號.序號) + public function ats2payed() + { + $result = []; + $parms['lpr'] = $lines = $this->uri->segment(3); + $parms['amt'] = $lines = $this->uri->segment(4); + $parms['station_no'] = $lines = $this->uri->segment(5); + $parms['order_no'] = $lines = $this->uri->segment(6); + $md5 = $this->uri->segment(7); + if (md5($parms['lpr'].$parms['amt'].$parms['station_no'].$parms['order_no']) === $md5) + { + $this->carpayment_model->ats2payed($parms); + } + } + + // 行動支付, 手機告知已付款 + // http://203.75.167.89/carpayment.html/m2payed/ABC1234/120/12112/12345/1f3870be274f6c49b3e31a0c6728957f + // http://203.75.167.89/carpayment.html/m2payed/車牌/金額/場站編號/序號/MD5 + // md5(車牌.金額.場站編號.序號) + public function m2payed() + { + $parms['lpr'] = $lines = $this->uri->segment(3); + $parms['amt'] = $lines = $this->uri->segment(4); + $parms['station_no'] = $lines = $this->uri->segment(5); + $parms['seqno'] = $lines = $this->uri->segment(6); + $md5 = $this->uri->segment(7); + echo $this->carpayment_model->m2payed($parms); + + /* + $seqno = !empty($_SESSION['seqno']) ? $_SESSION['seqno'] : 0; + unset($_SESSION['seqno']); + + if ($parms['seqno'] != 0 && $parms['seqno'] == $seqno && md5($parms['lpr'].$parms['amt'].$parms['station_no'].$parms['seqno']) === $md5) + { + echo $this->carpayment_model->m2payed($parms); + } + else + echo 'fail'; + */ + } + + + // 查詢入場時間 + public function query_in() + { + $lpr = $this->input->post('lpr', true); + + $data = $this->carpayment_model->query_in($lpr); + echo json_encode($data); + } + + // 查詢入場時間 (fuzzy) + public function query_in_fuzzy() + { + $lpr = $this->input->post('lpr', true); + + $data = $this->carpayment_model->query_in_fuzzy($lpr); + echo json_encode($data); + } + + + // 行動設備查詢入場時間 + // http://203.75.167.89/carpayment.html/m2query_in/ABC1234/12112/1f3870be274f6c49b3e31a0c6728957f + // http://203.75.167.89/carpayment.html/m2query_in/車牌/場站編號/MD5 + // 回傳0: 失敗, 成功: 12345,60(第一欄位非0數字代表成功, 第二欄位為金額), 此值在付款時必需傳回, 否則視為非法 + public function m2query_in() + { + + $parms['lpr'] = $lines = $this->uri->segment(3); + $parms['station_no'] = $lines = $this->uri->segment(4); + $md5 = $this->uri->segment(5); + + // 驗證md5 + if (md5($parms['lpr'].$parms['station_no']) === $md5) + { + $data = $this->carpayment_model->m2query_in($parms); + } + else + { + $data = 0; + } + + $_SESSEION['seqno'] = $data; + echo $data; + } + + // 測試:回傳 seat_no + // http://192.168.0.199/carpayment.html/test_seat_no/B2/123 + public function test_seat_no() + { + $rows['group_id'] = $this->uri->segment(3); + $rows['pksno'] = $this->uri->segment(4); + + //echo substr($rows['group_id'], 0, 1); + echo (substr($rows['group_id'], 0, 1) == 'B' ? '-' : '0') . substr($rows['group_id'], 1, 1) . '_' . substr($rows['pksno'], -3); + } +} diff --git a/controllers/Cars.php b/controllers/Cars.php new file mode 100644 index 0000000..227a5f8 --- /dev/null +++ b/controllers/Cars.php @@ -0,0 +1,234 @@ + +response: +var ip='66.249.82.183';var clientid='565162cb67dfb';var mqtt_ip='192.168.51.11'; + +*/ + +// ----- 定義常數(路徑, cache秒數) ----- + define('APP_VERSION', '100'); // 版本號 + + define('MAX_AGE', 604800); // cache秒數, 此定義1個月 + define('APP_NAME', 'cars'); // 應用系統名稱 + + define('PAGE_PATH', APP_BASE.'ci_application/views/'.APP_NAME.'/'); // path of views + + define('SERVER_URL', 'http://'.(isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost').'/'); // URL + define('APP_URL', SERVER_URL.APP_NAME.'.html/'); // controller路徑 + define('WEB_URL', SERVER_URL.APP_NAME.'/'); // 網頁路徑 + define('WEB_LIB', SERVER_URL.'/libs/'); // 網頁lib + define('BOOTSTRAPS', WEB_LIB.'bootstrap_sb/'); // bootstrap lib + define('LOG_PATH', FILE_BASE.APP_NAME.'/logs/'); // log path name + define('LOG_FILE', FILE_BASE.APP_NAME.'/logs/cario.'); // log file name + +require_once(MQ_CLASS_FILE); + +class Cars extends CI_Controller +{ + var $vars = array(); + + function __construct() + { + // $this->time_start = microtime(true); + parent::__construct(); + + ignore_user_abort(); // 接受client斷線, 繼續run + + $method_name = $this->router->fetch_method(); + if ($method_name == 'ipcam' || $method_name == 'check_lpr_etag') + { + ob_end_clean(); + ignore_user_abort(); + ob_start(); + header('Connection: close'); + header('Content-Length: ' . ob_get_length()); + ob_end_flush(); + flush(); + } + else if($method_name == 'opendoor') + { + ob_end_clean(); + ignore_user_abort(); + ob_start(); + + echo 'ok'; + + header('Connection: close'); + header('Content-Length: ' . ob_get_length()); + ob_end_flush(); + flush(); + } + + $this->vars['date_time'] = date('Y-m-d H:i:s'); // 格式化時間(2015-10-12 14:36:21) + $this->vars['time_num'] = str_replace(array('-', ':', ' '), '', $this->vars['date_time']); //數字化時間(20151012143621) + $this->vars['date_num'] = substr($this->vars['time_num'], 0, 8); // 數字化日期(20151012) + //$this->vars['station_no'] = STATION_NO; // 本站編號 + + session_id(ip2long($_SERVER['REMOTE_ADDR'])); // 設定同一device為同一個session + session_start(); + + // ----- 程式開發階段log設定 ----- + if (@ENVIRONMENT == 'development') + { + ini_set('display_errors', '1'); + //error_reporting(E_ALL ^ E_NOTICE); + error_reporting(E_ALL); + } + set_error_handler(array($this, 'error_handler'), E_ALL); // 資料庫異動需做log + + // 共用記憶體 + $this->vars['mcache'] = new Memcache; + $this->vars['mcache']->pconnect(MEMCACHE_HOST, MEMCACHE_PORT) or die ('Could not connect memcache'); + + // mqtt subscribe + $this->vars['mqtt'] = new phpMQTT(MQ_HOST, MQ_PORT, uniqid()); + //if(!$this->vars['mqtt']->connect()){ die ('Could not connect mqtt'); } + if(!$this->vars['mqtt']->connect()){ trigger_error('..Could not connect mqtt..go on..'); } + + $this->load->model('cars_model'); + $this->cars_model->init($this->vars); + } + + + // 發生錯誤時集中在此處理 + public function error_handler($errno, $errstr, $errfile, $errline, $errcontext) + { + $log_msg = explode('://', $errstr); + if (count($log_msg) > 1) + { + $log_file = $log_msg[0]; + $str = date('H:i:s')."|{$log_msg[1]}|{$errfile}|{$errline}|{$errno}\n"; + } + else + { + $log_file = APP_NAME; + $str = date('H:i:s')."|{$errstr}|{$errfile}|{$errline}|{$errno}\n"; + } + + error_log($str, 3, LOG_PATH.$log_file . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + } + + + // 顯示logs + public function show_logs() + { + $lines = $this->uri->segment(3); // 顯示行數 + if (empty($lines)) $lines = 140; // 無行數參數, 預設為40行 + + // echo ''; + echo ''; + + passthru('/usr/bin/tail -n ' . $lines . ' ' . LOG_PATH.APP_NAME . '.' . date('Ymd').'.log.txt'); // 利用linux指令顯示倒數幾行的logs內容 + echo "\n----- " . LOG_PATH.APP_NAME . '.' . date('Ymd').'.log.txt' . ' -----'; + echo ''; + } + + /* + 出入口 + + 說明: 與ipcam相同判斷邏輯, 但不做任何資料更改 + */ + public function opendoor() + { + $parms = $this->uri->uri_to_assoc(3); + $parms['lpr'] = urldecode($parms['lpr']); // 中文車牌 + $this->cars_model->opendoor_lprio($parms); + } + + // IVS -> 車號, 影像 + /* + 鼎高IVS傳送車號及影像檔 +http://192.168.10.201/cars.html/ipcam/sno/12119/ivsno/0/io/O/type/C/lpr/4750YC/color/NULL/sq/0/ts/1441051995/sq2/0/etag/ABCD123456789/ant/1 + sno: 場站編號(光興國小:12119) + ivsno: ivs編號, 每一支都是獨立編號(序號) + io: i:進場, o:出場 + type: C:汽車, H:重機, M:機車 + lpr: ABC-1234(車號) + color: red(紅色), 若無請用NULL(4個字) + sq: 序號(參考用) + sq2: 暫不用 + etag: eTag ID + ant: eTag + + http設定說明: + method: POST + 上傳圖檔名英數字, 副檔名為gif/jpg/png均可 + 上傳圖檔欄位名稱為cars + */ + public function ipcam() + { + $parms = $this->uri->uri_to_assoc(3); + $parms['lpr'] = urldecode($parms['lpr']); // 中文車牌 + + // 同步並送出一次出入口 888 + $this->load->model('sync_data_model'); + $this->sync_data_model->init($this->vars); + $this->sync_data_model->sync_888($parms); + + $pic_folder = CAR_PIC.$this->vars['date_num'].'/'; // 今日資料夾名(yyyymmdd) + if (!file_exists($pic_folder)) mkdir($pic_folder); // 如果資料夾不存在, 建立日期資料夾 + + $config['upload_path'] = $pic_folder; + // $config['allowed_types'] = 'gif|jpg|png'; + $config['allowed_types'] = '*'; + // ex. lpr_1625AB_I_1_152_C_1_2015080526.jpg -> car_交易序號_進出_順序_車號_時間.jpg + $config['file_name'] = "lpr-{$parms['lpr']}-{$parms['io']}-{$parms['ivsno']}-{$parms['sq']}-{$parms['type']}-{$parms['sq2']}-{$this->vars['time_num']}.jpg"; + + if (!isset($_FILES['cars'])) + { + $status = 'error'; // 顯示上傳錯誤 + trigger_error('[ERROR] cars not found: ' . print_r($_FILES, true)); + } + else + { + $this->load->library('upload', $config); + + if(!$this->upload->do_upload('cars')){ + $status = 'error'; // 顯示上傳錯誤 + trigger_error($this->upload->display_errors()); + } + else + { + // 若無錯誤,則上傳檔案 + $file = $this->upload->data('cars'); + $status = 'ok'; + } + } + + $parms['obj_type'] = 1; // 車牌類 + $parms['curr_time_str'] = $this->vars['date_time']; // 現在時間, 例2015-09-21 15:36:47 + $parms['pic_name'] = $config['file_name']; // 圖片檔名 + + $this->cars_model->lprio($parms); // 測試eTag + } + + // 用車牌與eTag, 檢查資料庫 + public function check_lpr_etag() + { + $lpr = $this->uri->segment(3); + $etag = $this->uri->segment(4); + + $this->cars_model->check_lpr_etag($lpr, $etag); + exit; + } + + public function test_now() + { + echo date('Y-m-d H:i:s'); + } + + public function test_phpinfo() + { + phpinfo(); + } + +} diff --git a/controllers/Ctbcbank.php b/controllers/Ctbcbank.php new file mode 100644 index 0000000..f1a33e2 --- /dev/null +++ b/controllers/Ctbcbank.php @@ -0,0 +1,218 @@ +vars['mcache'] = new Memcache; + $this->vars['mcache']->connect(MEMCACHE_HOST, MEMCACHE_PORT) or die ('Could not connect memcache'); + + // mqtt subscribe + $this->vars['mqtt'] = new phpMQTT(MQ_HOST, MQ_PORT, uniqid()); + + if(!$this->vars['mqtt']->connect()){ die ('Could not connect mqtt'); } + */ + + // ----- 定義常數(路徑, cache秒數) ----- + define('APP_VERSION', '100'); // 版本號 + + define('MAX_AGE', 604800); // cache秒數, 此定義1個月 + define('APP_NAME', 'ctbcbank'); // 應用系統名稱 + + define('PAGE_PATH', APP_BASE.'ci_application/views/'.APP_NAME.'/'); // path of views + + define('SERVER_URL', 'http://'.(isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost').'/'); // URL + define('APP_URL', SERVER_URL.APP_NAME.'.html/'); // controller路徑 + define('WEB_URL', SERVER_URL.APP_NAME.'/'); // 網頁路徑 + define('WEB_LIB', SERVER_URL.'libs/'); // 網頁lib + define('BOOTSTRAPS', WEB_LIB.'bootstrap_sb/'); // bootstrap lib + define('LOG_PATH', FILE_BASE.APP_NAME.'/logs/'); // log path + + //$this->load->model('twgc_model'); + // $this->parkingquery_model->init($this->vars); + + $this->load->model('payment_model'); // 帳單 + $this->load->model('ctbcbank_model');// 中國信託金流 + $this->load->model('allpay_invoice_model'); // 歐付寶電子發票 + + define('CTBC_AuthResURL', APP_URL."return_ok/"); // 從收單行端取得授權碼後,要導回的網址,請勿填入特殊字元@、#、%、?、&等。 + + define('MAIN_PAGE', "main_page"); + define('RESULT_PAGE', "result_page"); + define('ERROR_PAGE', "error_page"); + + // ----- 回傳訊息 ----- + define('RESULT_CODE_OK', "OK"); + define('RESULT_CODE_UNKNOWN_ERROR', "-99"); + define('RESULT_MSG_UNKNOWN_ERROR', "發生未預期錯誤"); + // ----- 回傳訊息 (END) ----- + } + + // 發生錯誤時集中在此處理 + public function error_handler($errno, $errstr, $errfile, $errline, $errcontext) + { + $str = date('H:i:s')."|{$errstr}|{$errfile}|{$errline}|{$errno}\n"; + //error_log($str, 3, $log_file . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + + //echo $str; + + error_log($str, 3, LOG_PATH.APP_NAME . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + } + + + // 顯示靜態網頁(html檔) + protected function show_page($page_name, &$data = null) + { + $page_file = PAGE_PATH.$page_name.'.php'; + $last_modified_time = filemtime($page_file); + + // 若檔案修改時間沒有異動, 或版本無異動, 通知瀏覽器使用cache, 不再下傳網頁 + // header('Cache-Control:max-age='.MAX_AGE); // cache 1個月 + header('Last-Modified: '.gmdate('D, d M Y H:i:s', $last_modified_time).' GMT'); + header('Etag: '. APP_VERSION); + header('Cache-Control: public'); + + if (!empty($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == APP_VERSION && @strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time) + { + header('HTTP/1.1 304 Not Modified'); + } + else + { + $this->load->view(APP_NAME.'/'.$page_name, $data); + } + } + + // 首頁 + public function index() + { + $this->show_page(MAIN_PAGE); // http://203.75.167.89/ctbcbank.html + } + + // 查車付款 - 1.查車拿帳單 + public function payment_lpr() + { + $payment_lpr = $this->input->post('payment_lpr', true); + $data = $this->payment_model->create_cario_bill($payment_lpr); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + + // 查車付款 - 2.確定繳交帳單 + public function transfer_money() + { + $order_no = strtoupper($this->uri->segment(3)); // 交易序號 + $invoice_receiver = urldecode($this->uri->segment(4)); // 載具編號 (可有可無) + $company_no = urldecode($this->uri->segment(5)); // 載具編號 (可有可無) + $email_base64 = $this->uri->segment(6); // 電子信箱 + $mobile = $this->uri->segment(7); // 手機號碼 + + // decode email + if(strlen($email_base64) > 0){ + $email = base64_decode($email_base64.'='); // base64字串尾端的'='還原 + }else{ + $email = email_base64; + } + + $data = $this->payment_model->pay_bill($order_no, $invoice_receiver, $company_no, $email, $mobile); // 繳交帳單 + + if (!empty($data)){ + $this->ctbcbank_model->transfer_money_ctbc($data, CTBC_AuthResURL); // 中國信託 + } + } + + // C.4 收單行端取得授權碼後,要導回的網址 (call by CTBC) + public function return_ok() + { + /** + =======ALL_REQUEST====== + URLResEnc: AF2100C51A9E844A1E820B953EA512BE49286403253FF9373474F6AE4A5877B084DD4D9B20F03AF0F34DB3D42A9C583938FE5DC1B60C53384864D9581EE997F92552A2F516B04F2FB2FE3E5C10D61CE84C5B63B87379F1048E16AC430AE94989724D8B0087734F73BF40CE904A05D555F526E5A93462C42931A0A7EC1E6AFF8BC39E641A8F5EE8882BD5B02F838BC217A87533AB9FE98CE1DD558B3CC345FC77D06C1783067F75DF94C58B55A826CD33B32355439BF3C9F17A4596138942B4457B66EB8FA09749C246D5B91799FB3942EC90138033272D89861B8698398FF4F3010628C0D11C7D88FB7A5F85CC59717D9F8D5CADBA5A1231E0396AE344B1DA139BA84F9D477E53A73A376BFCC92B52619E3B396BB28ABE7C4CEE3D3ED2CA1BEEF466F2D645C5CBF1C678C5747BA2A048F2F0FC2B86CAE379DE7A7F144D07C31A + merID: 10063 + ----------------------------END + */ + // 取得回傳資訊 + foreach ($_REQUEST as $key => $value) { + switch ($key){ + case "URLResEnc": $resenc = $value; break; + case "merID": $merid = $value; break; + } + } + + if(! empty($resenc)){ + $return_data = $this->ctbcbank_model->ctbcbank_return_handler($resenc, $merid); + $ctbc_lidm = $return_data['lidm']; + $ctbc_authamt = $return_data['authamt']; + $ctbc_status = $return_data['status']; + + if($ctbc_status != 0){ + // 金流處理失敗 + trigger_error(__FUNCTION__.', ctbc_status GG ..lidm=>' . $ctbc_lidm); + + }else if(! empty($ctbc_lidm)) { + $data = $this->payment_model->get_tx_bill($ctbc_lidm); + + if (! empty($data)) { + $order_no = $data['order_no']; + $lpr = $data['lpr']; + $amt = $data['amt']; + $status = $data['status']; + switch($status){ + case 100: // 狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中, 101: 交易失敗, 111:產品已領取 + // 印發票流程 + if($ctbc_authamt == $amt){ + // 先記錄 + $this->payment_model->transfer_money_done($order_no); + + // 開立歐付寶電子發票 + //$this->allpay_invoice_model->invoice_issue_for_product_bill($order_no, $amt); + + // 交易成功 + $this->show_page(RESULT_PAGE); + return; + + }else{ + // 錢沒對上 + $this->payment_model->transfer_money_done_with_error_2($order_no); + } + break; + default: + // 對方多傳一次時?? + trigger_error(__FUNCTION__.', order_no=>' . $order_no.'
'.'status != 100'); + } + }else{ + // 我們自己找不到記錄時?? + trigger_error(__FUNCTION__.', order_no=>' . $order_no.'
'.' NOT FOUND !!'); + } + + }else{ + // 回傳沒有資料 lidm + trigger_error(__FUNCTION__.', ERROR ..lidm=>' . $ctbc_lidm); + } + + }else{ + // 回傳沒有資料 resenc + trigger_error(__FUNCTION__.', ERROR ..resenc=>' . $resenc); + } + + // 交易失敗 + $this->show_page(ERROR_PAGE); + } + +} diff --git a/controllers/Parkingquery.php b/controllers/Parkingquery.php new file mode 100644 index 0000000..17052f3 --- /dev/null +++ b/controllers/Parkingquery.php @@ -0,0 +1,163 @@ +vars['mcache'] = new Memcache; + $this->vars['mcache']->connect(MEMCACHE_HOST, MEMCACHE_PORT) or die ('Could not connect memcache'); + + // mqtt subscribe + $this->vars['mqtt'] = new phpMQTT(MQ_HOST, MQ_PORT, uniqid()); + + if(!$this->vars['mqtt']->connect()){ die ('Could not connect mqtt'); } + */ + + // ----- 定義常數(路徑, cache秒數) ----- + define('APP_VERSION', '100'); // 版本號 + + define('MAX_AGE', 604800); // cache秒數, 此定義1個月 + define('APP_NAME', 'parkingquery'); // 應用系統名稱 + + define('PAGE_PATH', APP_BASE.'ci_application/views/'.APP_NAME.'/'); // path of views + + define('SERVER_URL', 'http://'.(isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost').'/'); // URL + define('APP_URL', SERVER_URL.APP_NAME.'.html/'); // controller路徑 + define('WEB_URL', SERVER_URL.APP_NAME.'/'); // 網頁路徑 + define('WEB_LIB', SERVER_URL.'libs/'); // 網頁lib + define('BOOTSTRAPS', WEB_LIB.'bootstrap_sb/'); // bootstrap lib + define('LOG_PATH', FILE_BASE.APP_NAME.'/logs/'); // log path + + $this->load->model('parkingquery_model'); + $this->load->model('security_model'); // 鎖車 + // $this->parkingquery_model->init($this->vars); + } + + + + // 發生錯誤時集中在此處理 + public function error_handler($errno, $errstr, $errfile, $errline, $errcontext) + { + $str = date('H:i:s')."|{$errstr}|{$errfile}|{$errline}|{$errno}\n"; + //error_log($str, 3, $log_file . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + error_log($str, 3, LOG_PATH.APP_NAME . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + } + + + // 顯示靜態網頁(html檔) + protected function show_page($page_name, &$data = null) + { + $page_file = PAGE_PATH.$page_name.'.php'; + $last_modified_time = filemtime($page_file); + + // 若檔案修改時間沒有異動, 或版本無異動, 通知瀏覽器使用cache, 不再下傳網頁 + header('Cache-Control:max-age='.MAX_AGE); // cache 1個月 + header('Last-Modified: '.gmdate('D, d M Y H:i:s', $last_modified_time).' GMT'); + header('Etag: '. APP_VERSION); + header('Cache-Control: public'); + + if (!empty($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == APP_VERSION && @strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time) + { + header('HTTP/1.1 304 Not Modified'); + } + else + { + $this->load->view(APP_NAME.'/'.$page_name, $data); + } + } + + + + // response http + protected function http_return($return_code, $type) + { + if ($type == 'text') echo $return_code; + else echo json_encode($return_code, JSON_UNESCAPED_UNICODE); + + } + + + + // 查詢各樓層剩餘車位 + // http://203.75.167.89/parkingquery.html/check_space/12345 + public function check_space() + { + $seqno = $this->uri->segment(3); + $data = $this->parkingquery_model->check_space($seqno); + $data['result']['num'] = $seqno; + $data['result_code'] = 'OK'; + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + + // 停車位置查詢(板橋好停車) + // http://203.75.167.89/parkingquery.html/check_location/ABC1234 + public function check_location() + { + $lpr = $this->uri->segment(3); + $data = $this->parkingquery_model->check_location($lpr); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + + // 空車位導引 + // http://203.75.167.89/parkingquery.html/get_valid_seat + public function get_valid_seat() + { + $pksno = $this->uri->segment(3, 0); // 從某一個車位開始, 若無則設0 + $data = $this->parkingquery_model->get_valid_seat($pksno); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + + // 緊急求救 + // http://203.75.167.89/parkingquery.html/send_sos/B2/111/123 + public function send_sos() + { + $floor = $this->uri->segment(3); + $x = $this->uri->segment(4); + $y = $this->uri->segment(5); + get_headers("http://localhost/sos/set_sos.php?floor={$floor}&x={$x}&y={$y}"); + $data = $this->parkingquery_model->send_sos($floor, $x, $y); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + + // 防盜鎖車 + // http://203.75.167.89/parkingquery.html/security_action/ABC1234/pswd/2 + public function security_action() + { + $lpr = $this->uri->segment(3); + $pswd = $this->uri->segment(4); + $action = $this->uri->segment(5); + $data = $this->security_model->security_action($lpr, $pswd, $action); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 警急求救地圖 + public function floor_map() + { + $this->show_page("floor_map"); + } + +} diff --git a/controllers/Payment.php b/controllers/Payment.php new file mode 100644 index 0000000..875bdc3 --- /dev/null +++ b/controllers/Payment.php @@ -0,0 +1,204 @@ +load->model('payment_model'); // 臨停繳費 + $this->load->model('allpay_invoice_model'); // 歐付寶電子發票 + $this->load->model('security_model'); // 鎖車 + + define('MAIN_PAGE', "main_page"); + define('RESULT_PAGE', "result_page"); + + // ----- 行動支付, 手機告知已付款 ----- + define('ALTOB_M2PAYED', "http://localhost/carpayment.html/m2payed"); + // ----- 行動支付, 手機告知已付款 (end) ----- + + // ----- 歐付寶金流 ----- + define('ALLPAY_PAYMENT_TX_BILL', SERVER_URL."allpay_payment.html/transfer_money_tx_bill"); // 歐付寶付款系統連結 + define('ALLPAY_ClientBackURL', APP_URL."client_back/"); // 您要歐付寶返回按鈕導向的瀏覽器端網址"; + define('ALLPAY_OrderResultURL', APP_URL."order_result/"); // 您要收到付款完成通知的瀏覽器端網址(browser) ps. WebATM大部份銀行都回不來; + define('ALLPAY_AltobServiceURL', APP_URL."payment_completed_handler/"); // 付款完成後被通知的位址 + // ----- 歐付寶金流 (end) ----- + } + + + // 發生錯誤時集中在此處理 + public function error_handler($errno, $errstr, $errfile, $errline, $errcontext) + { + $str = date('H:i:s')."|{$errstr}|{$errfile}|{$errline}|{$errno}\n"; + //error_log($str, 3, $log_file . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + error_log($str, 3, LOG_PATH.APP_NAME . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + } + + + // 顯示靜態網頁(html檔) + protected function show_page($page_name, $data = null) + { + $page_file = PAGE_PATH.$page_name.'.php'; + $last_modified_time = filemtime($page_file); + + // 若檔案修改時間沒有異動, 或版本無異動, 通知瀏覽器使用cache, 不再下傳網頁 + // header('Cache-Control:max-age='.MAX_AGE); // cache 1個月 + header('Last-Modified: '.gmdate('D, d M Y H:i:s', $last_modified_time).' GMT'); + header('Etag: '. APP_VERSION); + header('Cache-Control: public'); + + if (!empty($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == APP_VERSION && @strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time) + { + header('HTTP/1.1 304 Not Modified'); + } + else + { + $this->load->view(APP_NAME.'/'.$page_name, $data); + } + } + + // 首頁 + public function index() + { + $this->show_page(MAIN_PAGE); + } + + // 查車付款 - 1.查車拿帳單 + public function payment_lpr() + { + $payment_lpr = $this->input->post('payment_lpr', true); + $data = $this->payment_model->create_cario_bill($payment_lpr); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 查車付款 - 2.確定繳交帳單 + public function transfer_money() + { + $order_no = strtoupper($this->uri->segment(3)); // 交易序號 + $invoice_receiver = urldecode($this->uri->segment(4)); // 載具編號 (可有可無) + $company_no = urldecode($this->uri->segment(5)); // 公司統編 (可有可無) + $email_base64 = $this->uri->segment(6); // 電子信箱 + $mobile = $this->uri->segment(7); // 手機號碼 + + // decode email + if(strlen($email_base64) > 0){ + $email = base64_decode($email_base64.'='); // base64字串尾端的'='還原 + }else{ + $email = email_base64; + } + + $this->payment_model-> // 開始進行繳交帳單 + pay_bill($order_no, $invoice_receiver, $company_no, $email, $mobile, + ALLPAY_ClientBackURL, + ALLPAY_OrderResultURL, + ALLPAY_AltobServiceURL, + 50); // 交易種類: 0:未定義, 1:現金, 40:博辰人工模組, 41:博辰自動繳費機, 50:歐付寶轉址刷卡, 51:歐付寶APP, 52:歐付寶轉址WebATM, 60:中國信託刷卡轉址 + + // 轉址歐付寶付款系統 + echo file_get_contents(ALLPAY_PAYMENT_TX_BILL."/{$order_no}"); + } + + // L.1 付款完成 (限制存取) + public function payment_completed_handler() + { + $order_no = $this->uri->segment(3); // 交易序號 + + $data = $this->payment_model->get_tx_bill($order_no); + if (! empty($data)) + { + $cario_no = $data['cario_no']; + $station_no = $data['station_no']; + $lpr = $data['lpr']; + $amt = $data['amt']; + $status = $data['status']; + switch($status){ + case 1: // 狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中, 111:產品已領取 + + // 開立歐付寶電子發票 + $this->allpay_invoice_model->invoice_issue_for_tx_bill($order_no, $amt); + + // 記錄為已領取 + $this->payment_model->transfer_money_done_and_finished($order_no); + + // 行動支付, 手機告知已付款 + // http://203.75.167.89/carpayment.html/m2payed/車牌/金額/場站編號/序號/MD5 + // md5(車牌.金額.場站編號.序號) + $md5 = md5($lpr.$amt.$station_no.$cario_no); + file_get_contents(ALTOB_M2PAYED."/{$lpr}/{$amt}/{$station_no}/{$cario_no}/{$md5}"); + + default: + // 尚未結帳完成, 或是已領取 + trigger_error(APP_NAME.', '.__FUNCTION__.', order_no=>' . $order_no.'
'.'tx_bill.status != 1'); + } + } + } + + // 歐付寶返回按鈕導向的瀏覽器端網址 + public function client_back() + { + $this->show_page(MAIN_PAGE); + } + + // 收到付款完成通知的瀏覽器端網址(browser) ps. WebATM大部份銀行都回不來 + public function order_result() + { + $this->show_page(RESULT_PAGE); + } + + + + + // 其它功能 1: 更改會員密碼 + public function change_pswd() + { + $lpr = $this->input->post('lpr', true); + $new_pswd = $this->input->post('new_pswd', true); + $data = $this->security_model->change_pswd($lpr, $new_pswd); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 其它功能 2: 防盜鎖車 + public function security_action() + { + $lpr = $this->uri->segment(3); + $pswd = $this->uri->segment(4); + $action = $this->uri->segment(5); + $data = $this->security_model->security_action($lpr, $pswd, $action); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // show image + public function pics() + { + readfile(PKS_PIC. $this->uri->segment(3).'.jpg'); + } +} diff --git a/controllers/Payment_ats.php b/controllers/Payment_ats.php new file mode 100644 index 0000000..7ae2c9a --- /dev/null +++ b/controllers/Payment_ats.php @@ -0,0 +1,198 @@ +load->model('payment_ats_model'); // 臨停繳費 + $this->load->model('allpay_invoice_model'); // 歐付寶電子發票 + + define('MAIN_PAGE', "main_page"); + define('RESULT_PAGE', "result_page"); + + // ----- 行動支付, 繳費機告知已付款 ----- + define('ALTOB_ATS2PAYED', "http://localhost/carpayment.html/ats2payed"); + // ----- 行動支付, 繳費機告知已付款 (end) ----- + + // ----- 歐付寶金流 ----- + define('ALLPAY_PAYMENT_TX_BILL_ATS', SERVER_URL."allpay_payment.html/transfer_money_tx_bill_ats"); // 歐付寶付款系統連結 + define('ALLPAY_ClientBackURL', APP_URL."client_back/"); // 您要歐付寶返回按鈕導向的瀏覽器端網址"; + define('ALLPAY_OrderResultURL', APP_URL."order_result/"); // 您要收到付款完成通知的瀏覽器端網址(browser) ps. WebATM大部份銀行都回不來; + define('ALLPAY_AltobServiceURL', APP_URL."payment_completed_handler/"); // 付款完成後被通知的位址 + // ----- 歐付寶金流 (end) ----- + } + + + // 發生錯誤時集中在此處理 + public function error_handler($errno, $errstr, $errfile, $errline, $errcontext) + { + $str = date('H:i:s')."|{$errstr}|{$errfile}|{$errline}|{$errno}\n"; + //error_log($str, 3, $log_file . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + error_log($str, 3, LOG_PATH.APP_NAME . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + } + + + // 顯示靜態網頁(html檔) + protected function show_page($page_name, $data = null) + { + $page_file = PAGE_PATH.$page_name.'.php'; + $last_modified_time = filemtime($page_file); + + // 若檔案修改時間沒有異動, 或版本無異動, 通知瀏覽器使用cache, 不再下傳網頁 + // header('Cache-Control:max-age='.MAX_AGE); // cache 1個月 + header('Last-Modified: '.gmdate('D, d M Y H:i:s', $last_modified_time).' GMT'); + header('Etag: '. APP_VERSION); + header('Cache-Control: public'); + + if (!empty($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == APP_VERSION && @strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time) + { + header('HTTP/1.1 304 Not Modified'); + } + else + { + $this->load->view(APP_NAME.'/'.$page_name, $data); + } + } + + // 首頁 + public function index() + { + $this->show_page(MAIN_PAGE); + } + + // 查車付款 - 1.查車拿帳單 + public function payment_lpr() + { + $payment_lpr = $this->input->post('payment_lpr', true); + $data = $this->payment_ats_model->create_member_bill($payment_lpr); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 查車付款 - 2.確定繳交帳單 + public function transfer_money() + { + $order_no = strtoupper($this->uri->segment(3)); // 交易序號 + $invoice_receiver = urldecode($this->uri->segment(4)); // 載具編號 (可有可無) + $company_no = urldecode($this->uri->segment(5)); // 公司統編 (可有可無) + $email_base64 = $this->uri->segment(6); // 電子信箱 + $mobile = $this->uri->segment(7); // 手機號碼 + + // decode email + if(strlen($email_base64) > 0){ + $email = base64_decode($email_base64.'='); // base64字串尾端的'='還原 + }else{ + $email = email_base64; + } + + $this->payment_ats_model-> // 開始進行繳交帳單 + pay_bill($order_no, $invoice_receiver, $company_no, $email, $mobile, + ALLPAY_ClientBackURL, + ALLPAY_OrderResultURL, + ALLPAY_AltobServiceURL, + 50); // 交易種類: 0:未定義, 1:現金, 40:博辰人工模組, 41:博辰自動繳費機, 50:歐付寶轉址刷卡, 51:歐付寶APP, 52:歐付寶轉址WebATM, 60:中國信託刷卡轉址 + + // 轉址歐付寶付款系統 + echo file_get_contents(ALLPAY_PAYMENT_TX_BILL_ATS."/{$order_no}"); + } + + // L.1 付款完成 (限制存取) + public function payment_completed_handler() + { + $order_no = $this->uri->segment(3); // 交易序號 + + $data = $this->payment_ats_model->get_tx_bill($order_no); + if (! empty($data)) + { + $order_no = $data['order_no']; + $station_no = $data['station_no']; + $lpr = $data['lpr']; + $amt = $data['amt']; + $status = $data['status']; + switch($status){ + case 1: // 狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中, 111:產品已領取 + + // 開立歐付寶電子發票 + $this->allpay_invoice_model->invoice_issue_for_tx_bill_ats($order_no, $amt); + + // 記錄為已領取 + $this->payment_ats_model->transfer_money_done_and_finished($order_no); + + // 繳費機告知已付款 + // http://localhost/carpayment.html/ats2payed/車牌/金額/場站編號/序號/MD5 + // md5(車牌.金額.場站編號.序號) + $md5 = md5($lpr.$amt.$station_no.$order_no); + file_get_contents(ALTOB_ATS2PAYED."/{$lpr}/{$amt}/{$station_no}/{$order_no}/{$md5}"); + + default: + // 尚未結帳完成, 或是已領取 + trigger_error(APP_NAME.', '.__FUNCTION__.', order_no=>' . $order_no.'
'.' status != 1'); + } + } + } + + // 歐付寶返回按鈕導向的瀏覽器端網址 + public function client_back() + { + $this->show_page(MAIN_PAGE); + } + + // 收到付款完成通知的瀏覽器端網址(browser) ps. WebATM大部份銀行都回不來 + public function order_result() + { + $this->show_page(RESULT_PAGE); + } + + + + + // 其它功能 1: 更改會員密碼 + public function change_pswd() + { + $lpr = $this->input->post('lpr', true); + $new_pswd = $this->input->post('new_pswd', true); + $data = $this->security_model->change_pswd($lpr, $new_pswd); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 其它功能 2: 防盜鎖車 + public function security_action() + { + $lpr = $this->uri->segment(3); + $pswd = $this->uri->segment(4); + $action = $this->uri->segment(5); + $data = $this->security_model->security_action($lpr, $pswd, $action); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + +} diff --git a/controllers/Pks.php b/controllers/Pks.php new file mode 100644 index 0000000..5198d6f --- /dev/null +++ b/controllers/Pks.php @@ -0,0 +1,268 @@ + 車號, 影像 +鼎高IVS傳送車號及影像檔 +http://203.75.167.89/pks.html/cameras/sno/12112/ivsno/3/pksno/2016/io/KI/type/C/lpr/ABC1234/color/red/sq/5236 +http://203.75.167.89/pks.html/cameras/sno/12119/ivsno/3/pksno/195/io/KO/type/C/lpr/NONE/color/red/sq/5236 +sno: 場站編號(新北市圖書館:12118) +ivsno: ivs編號, 每一支都是獨立編號(序號) +pksno: 車位編號 +io: KI:進車格, KO:出車格, KL:車牌 +type: C:汽車, H:重機, M:機車 +lpr: ABC1234(車號), 無:NONE +color: red(紅色), 若無請用NONE(4個字) +sq: 序號(查詢時參考用) + +http設定說明: +method: POST +上傳圖檔名英數字, 副檔名為gif/jpg/png均可 +上傳圖檔欄位名稱為cars +*/ + +require_once(MQ_CLASS_FILE); + +class Pks extends CI_Controller +{ + var $vars = array(); // 共用變數 + + function __construct() + { + // $this->time_start = microtime(true); + parent::__construct(); + + ignore_user_abort(); // 接受client斷線, 繼續run + + $method_name = $this->router->fetch_method(); + if ($method_name == 'cameras') + { + ob_end_clean(); + ignore_user_abort(); + ob_start(); + header('Connection: close'); + header('Content-Length: ' . ob_get_length()); + ob_end_flush(); + flush(); + } + + $this->vars['date_time'] = date('Y-m-d H:i:s'); // 格式化時間(2015-10-12 14:36:21) + $this->vars['time_num'] = str_replace(array('-', ':', ' '), '', $this->vars['date_time']); //數字化時間(20151012143621) + $this->vars['date_num'] = substr($this->vars['time_num'], 0, 8); // 數字化日期(20151012) + $this->vars['station_no'] = STATION_NO; // 本站編號 + + // ----- 程式開發階段log設定 ----- + if (@ENVIRONMENT == 'development') + { + ini_set('display_errors', '1'); + //error_reporting(E_ALL ^ E_NOTICE); + error_reporting(E_ALL); + } + set_error_handler(array($this, 'error_handler'), E_ALL); // 資料庫異動需做log + + // mqtt subscribe + $this->vars['mqtt'] = new phpMQTT(MQ_HOST, MQ_PORT, uniqid()); + + if(!$this->vars['mqtt']->connect()){ die ('Could not connect mqtt'); } + + // ----- 定義常數(路徑, cache秒數) ----- + define('APP_VERSION', '100'); // 版本號 + + define('MAX_AGE', 604800); // cache秒數, 此定義1個月 + define('APP_NAME', 'pks'); // 應用系統名稱 + + define('PAGE_PATH', APP_BASE.'ci_application/views/'.APP_NAME.'/'); // path of views + + define('SERVER_URL', 'http://'.(isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost').'/'); // URL + define('APP_URL', SERVER_URL.APP_NAME.'.html/'); // controller路徑 + define('WEB_URL', SERVER_URL.APP_NAME.'/'); // 網頁路徑 + define('WEB_LIB', SERVER_URL.'/libs/'); // 網頁lib + define('BOOTSTRAPS', WEB_LIB.'bootstrap_sb/'); // bootstrap lib + define('LOG_PATH', FILE_BASE.APP_NAME.'/logs/'); // log path name + define('LOG_FILE', FILE_BASE.APP_NAME.'/logs/pks.'); // log file name + + $this->load->model('pks_model'); + $this->pks_model->init($this->vars); + } + + + + // 發生錯誤時集中在此處理 + public function error_handler($errno, $errstr, $errfile, $errline, $errcontext) + { + $log_msg = explode('://', $errstr); + if (count($log_msg) > 1) + { + $log_file = $log_msg[0]; + $str = date('H:i:s')."|{$log_msg[1]}|{$errfile}|{$errline}|{$errno}\n"; + } + else + { + $log_file = APP_NAME; + $str = date('H:i:s')."|{$errstr}|{$errfile}|{$errline}|{$errno}\n"; + } + + error_log($str, 3, LOG_PATH.$log_file . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + } + + + // 顯示靜態網頁(html檔) + protected function show_page($page_name, &$data = null) + { + $page_file = PAGE_PATH.$page_name.'.php'; + $last_modified_time = filemtime($page_file); + + // 若檔案修改時間沒有異動, 或版本無異動, 通知瀏覽器使用cache, 不再下傳網頁 + // header('Cache-Control:max-age='.MAX_AGE); // cache 1個月 + header('Last-Modified: '.gmdate('D, d M Y H:i:s', $last_modified_time).' GMT'); + header('Etag: '. APP_VERSION); + header('Cache-Control: public'); + + if (!empty($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == APP_VERSION && @strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time) + { + header('HTTP/1.1 304 Not Modified'); + } + else + { + $this->load->view(APP_NAME.'/'.$page_name, $data); + } + } + + + public function parked() + { + $data['group_id'] = $this->uri->segment(3); + $data['init_value'] = $this->uri->segment(4); + // $data['client_id'] = uniqid(); + // $data['mqtt_ip'] = '192.168.10.201'; + // $data['port_no'] = 8000; + $this->load->view(APP_NAME.'/parked', $data); + } + + // 樓層平面圖 + // http://203.75.167.89/parkingquery.html/floor_map + public function floor_map() + { + /* + header('Access-Control-Allow-Origin: *'); + header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS'); + header('Access-Control-Allow-Headers: X-Requested-With, Content-Type, Accept'); + */ + + $this->load->view("parkingquery/floor_map"); + } + + + // response http + protected function http_return($return_code, $type) + { + if ($type == 'text') echo $return_code; + else echo json_encode($return_code, JSON_UNESCAPED_UNICODE); + } + + // 顯示logs + public function show_logs() + { + $lines = $this->uri->segment(3); // 顯示行數 + if (empty($lines)) $lines = 40; // 無行數參數, 預設為40行 + + // echo ''; + echo ''; + if (PHP_OS == 'Linux') + passthru('/usr/bin/tail -n ' . $lines . ' ' . LOG_FILE); // 利用linux指令顯示倒數幾行的logs內容 + else + passthru('d:/afiles/bin/unix_cmd/tail.exe -n ' . $lines . ' ' . LOG_FILE); + echo "\n----- " . LOG_FILE . ' -----'; + echo ''; + } + + + // IVS -> 車號, 影像 + /* + IVS -> 車號, 影像 + 鼎高IVS傳送車號及影像檔 + http://203.75.167.89/pks.html/cameras/sno/12119/ivsno/3/pksno/102/io/KI/type/C/lpr/ABC1234/color/red/sq/5236 + sno: 場站編號(新北市圖書館:12118) + ivsno: ivs編號, 每一支都是獨立編號(序號) + pksno: 車位編號 + io: KI:進車格, KO:出車格, KL:車牌辨識 + type: C:汽車, H:重機, M:機車 + lpr: ABC1234(車號) + color: red(紅色), 若無請用NONE(4個字) + sq: 序號(查詢時參考用) + + http設定說明: + method: POST + 上傳圖檔名英數字, 副檔名為gif/jpg/png均可 + 上傳圖檔欄位名稱為cars + */ + public function cameras() + { + $parms = $this->uri->uri_to_assoc(3); + trigger_error('在席參數傳入:'.print_r($parms, true)); + + // array_map('unlink', glob(PKS_PIC."pks-{$parms['pksno']}-*")); + + /* + // 車入格後的車牌辨識(lpr), 傅送圖檔 + if ($parms['io'] == 'KL') + { + array_map('unlink', glob(PKS_PIC."pks-{$parms['pksno']}-*.jpg")); // 刪除舊照片 + $config['upload_path'] = PKS_PIC; + $config['allowed_types'] = 'gif|jpg|png'; + // ex. pks-2016-1625AB-1-2015080526.jpg -> pks-車位編號-車號-設備編號-時間.jpg + $config['file_name'] = "pks-{$parms['pksno']}-{$parms['lpr']}-{$parms['ivsno']}-{$this->vars['time_num']}.jpg"; + $this->load->library('upload', $config); + + $parms['pic_name'] = $config['file_name']; + if($this->upload->do_upload('cars')) + { + // 若無錯誤,則上傳檔案 + $file = $this->upload->data('cars'); + } + else + { + trigger_error('入席傳檔錯誤:'. print_r($parms, true)); + } + } + */ + $this->pks_model->pksio($parms); // 車輛進出車格資料庫處理 + exit; + } + + + // 重新計算 + // http://203.75.167.89/pks.html/reculc/ + public function reculc() + { + $this->pks_model->reculc(); + } + + + + // 取得所有車位狀態資訊 + // http://203.75.167.89/pks.html/query_station_status/12112 + public function query_station_status() + { + $station_no = $this->uri->segment(3); + $data = $this->pks_model->query_station_status($station_no); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 取得車位資訊 + // http://203.75.167.89/pks.html/query_station_pks/12112/2021 + public function query_station_pks(){ + $station_no = $this->uri->segment(3); + $pksno = $this->uri->segment(4); + $data = $this->pks_model->query_station_pks($station_no, $pksno); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 車位狀態資訊圖 + // http://203.75.167.89/pks.html/status_map + public function status_map() + { + $this->show_page("status_map"); + } + +} diff --git a/controllers/Qcar.php b/controllers/Qcar.php new file mode 100644 index 0000000..a3528b6 --- /dev/null +++ b/controllers/Qcar.php @@ -0,0 +1,242 @@ +vars['mcache'] = new Memcache; + $this->vars['mcache']->connect(MEMCACHE_HOST, MEMCACHE_POST) or die ('Could not connect memcache'); + + // mqtt subscribe + $this->vars['mqtt'] = new phpMQTT(MQ_HOST, MQ_POST, 'cario'); + + if(!$this->vars['mqtt']->connect()){ die ('Could not connect mqtt'); } + */ + // ----- 定義常數(路徑, cache秒數) ----- + define('APP_VERSION', '100'); // 版本號 + + define('MAX_AGE', 604800); // cache秒數, 此定義1個月 + define('APP_NAME', 'qcar'); // 應用系統名稱 + + define('PAGE_PATH', APP_BASE.'ci_application/views/'.APP_NAME.'/'); // path of views + + define('SERVER_URL', 'http://'.(isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost').'/'); // URL + define('APP_URL', SERVER_URL.APP_NAME.'.html/'); // controller路徑 + define('WEB_URL', SERVER_URL.APP_NAME.'/'); // 網頁路徑 + define('WEB_LIB', SERVER_URL.'libs/'); // 網頁lib + define('BOOTSTRAPS', WEB_LIB.'bootstrap_sb/'); // bootstrap lib + define('LOG_PATH', FILE_BASE.APP_NAME.'/logs/'); // log path + + $this->load->model('qcar_model'); + $this->load->model('payment_ats_model'); // 繳費 + $this->load->model('allpay_invoice_model'); // 歐付寶電子發票 + + define('MAIN_PAGE', "main_page"); + define('RESULT_PAGE', "result_page"); + + // ----- 行動支付, 繳費機告知已付款 ----- + define('ALTOB_ATS2PAYED', "http://localhost/carpayment.html/ats2payed"); + // ----- 行動支付, 繳費機告知已付款 (end) ----- + + // ----- 歐付寶金流 ----- + define('ALLPAY_PAYMENT_TX_BILL_ATS', SERVER_URL."allpay_payment.html/transfer_money_tx_bill_ats"); // 歐付寶付款系統連結 + define('ALLPAY_ClientBackURL', APP_URL."client_back/"); // 您要歐付寶返回按鈕導向的瀏覽器端網址"; + define('ALLPAY_OrderResultURL', APP_URL."order_result/"); // 您要收到付款完成通知的瀏覽器端網址(browser) ps. WebATM大部份銀行都回不來; + define('ALLPAY_AltobServiceURL', APP_URL."payment_completed_handler/"); // 付款完成後被通知的位址 + // ----- 歐付寶金流 (end) ----- + } + + + + // 發生錯誤時集中在此處理 + public function error_handler($errno, $errstr, $errfile, $errline, $errcontext) + { + // ex: car_err://message.... + //$log_msg = explode('://', $errstr); + /* + if (count($log_msg) > 1) + { + $log_file = LOG_PATH.$log_msg[0]; + $str = date('H:i:s')."|{$log_msg[1]}|{$errfile}|{$errline}|{$errno}\n"; + } + else + { + $log_file = LOG_PATH.APP_NAME; + $str = date('H:i:s')."|{$errstr}|{$errfile}|{$errline}|{$errno}\n"; + } + */ + + $str = date('H:i:s')."|{$errstr}|{$errfile}|{$errline}|{$errno}\n"; + //error_log($str, 3, $log_file . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + error_log($str, 3, LOG_PATH.APP_NAME . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + } + + + // 顯示靜態網頁(html檔) + protected function show_page($page_name, $data = null) + { + $page_file = PAGE_PATH.$page_name.'.php'; + $last_modified_time = filemtime($page_file); + + // 若檔案修改時間沒有異動, 或版本無異動, 通知瀏覽器使用cache, 不再下傳網頁 + header('Cache-Control:max-age='.MAX_AGE); // cache 1個月 + header('Last-Modified: '.gmdate('D, d M Y H:i:s', $last_modified_time).' GMT'); + header('Etag: '. APP_VERSION); + header('Cache-Control: public'); + + if (!empty($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == APP_VERSION && @strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time) + { + header('HTTP/1.1 304 Not Modified'); + } + else + { + $this->load->view(APP_NAME.'/'.$page_name, $data); + } + } + + public function index() + { + $this->show_page('main_page'); + } + + // 顯示logs + public function show_logs() + { + $lines = $this->uri->segment(3); // 顯示行數 + if (empty($lines)) $lines = 40; // 無行數參數, 預設為40行 + + // echo ''; + echo ''; + passthru('/usr/bin/tail -n ' . $lines . ' ' . LOG_FILE); // 利用linux指令顯示倒數幾行的logs內容 + echo "\n----- " . LOG_FILE . ' -----'; + echo ''; + } + + + + + + // 付款 - 1.繳月租 + public function payment_lpr() + { + $payment_lpr = $this->input->post('payment_lpr', true); + $data = $this->payment_ats_model->create_member_bill($payment_lpr); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 付款 - 2.確定繳費 + public function transfer_money() + { + $order_no = strtoupper($this->uri->segment(3)); // 交易序號 + $invoice_receiver = urldecode($this->uri->segment(4)); // 載具編號 (可有可無) + $company_no = urldecode($this->uri->segment(5)); // 公司統編 (可有可無) + $email_base64 = $this->uri->segment(6); // 電子信箱 + $mobile = $this->uri->segment(7); // 手機號碼 + + // decode email + if(strlen($email_base64) > 0){ + $email = base64_decode($email_base64.'='); // base64字串尾端的'='還原 + }else{ + $email = email_base64; + } + + $this->payment_ats_model-> // 開始進行繳交帳單 + pay_bill($order_no, $invoice_receiver, $company_no, $email, $mobile, + ALLPAY_ClientBackURL, + ALLPAY_OrderResultURL, + ALLPAY_AltobServiceURL, + 52); // 交易種類: 0:未定義, 1:現金, 40:博辰人工模組, 41:博辰自動繳費機, 50:歐付寶轉址刷卡, 51:歐付寶APP, 52:歐付寶轉址WebATM, 60:中國信託刷卡轉址 + + // 轉址歐付寶付款系統 + echo file_get_contents(ALLPAY_PAYMENT_TX_BILL_ATS."/{$order_no}"); + } + + // L.1 付款完成 (限制存取) + public function payment_completed_handler() + { + $order_no = $this->uri->segment(3); // 交易序號 + + $data = $this->payment_ats_model->get_tx_bill($order_no); + if (! empty($data)) + { + $order_no = $data['order_no']; + $station_no = $data['station_no']; + $lpr = $data['lpr']; + $amt = $data['amt']; + $status = $data['status']; + switch($status){ + case 1: // 狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中, 111:產品已領取 + + // 開立歐付寶電子發票 + $this->allpay_invoice_model->invoice_issue_for_tx_bill_ats($order_no, $amt); + + // 記錄為已領取 + $this->payment_ats_model->transfer_money_done_and_finished($order_no); + + // 繳費機告知已付款 + // http://localhost/carpayment.html/ats2payed/車牌/金額/場站編號/序號/MD5 + // md5(車牌.金額.場站編號.序號) + $md5 = md5($lpr.$amt.$station_no.$order_no); + file_get_contents(ALTOB_ATS2PAYED."/{$lpr}/{$amt}/{$station_no}/{$order_no}/{$md5}"); + + default: + // 尚未結帳完成, 或是已領取 + trigger_error(APP_NAME.', '.__FUNCTION__.', order_no=>' . $order_no.'
'.' status != 1'); + } + } + } + + // 歐付寶返回按鈕導向的瀏覽器端網址 + public function client_back() + { + $this->show_page(MAIN_PAGE); + } + + // 收到付款完成通知的瀏覽器端網址(browser) ps. WebATM大部份銀行都回不來 + public function order_result() + { + $this->show_page(RESULT_PAGE); + } + + + + + + + // 車位查詢 + public function q_pks() + { + $lpr = $this->input->post('lpr', true); + $data = $this->qcar_model->q_pks($lpr); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 取得進場資訊 (模糊比對) + public function q_fuzzy_pks() + { + $input = $this->input->post('fuzzy_input', true); + $data = $this->qcar_model->q_fuzzy_pks($input); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + + +} diff --git a/controllers/Txdata.php b/controllers/Txdata.php new file mode 100644 index 0000000..88afe8a --- /dev/null +++ b/controllers/Txdata.php @@ -0,0 +1,104 @@ +vars['mcache'] = new Memcache; + $this->vars['mcache']->connect(MEMCACHE_HOST, MEMCACHE_PORT) or die ('Could not connect memcache'); + + // mqtt subscribe + $this->vars['mqtt'] = new phpMQTT(MQ_HOST, MQ_PORT, uniqid()); + + if(!$this->vars['mqtt']->connect()){ die ('Could not connect mqtt'); } + */ + + // ----- 定義常數(路徑, cache秒數) ----- + define('APP_VERSION', '100'); // 版本號 + + define('MAX_AGE', 604800); // cache秒數, 此定義1個月 + define('APP_NAME', 'txdata'); // 應用系統名稱 + + define('PAGE_PATH', APP_BASE.'ci_application/views/'.APP_NAME.'/'); // path of views + + define('SERVER_URL', 'http://'.(isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost').'/'); // URL + define('APP_URL', SERVER_URL.APP_NAME.'.html/'); // controller路徑 + define('WEB_URL', SERVER_URL.APP_NAME.'/'); // 網頁路徑 + define('WEB_LIB', SERVER_URL.'libs/'); // 網頁lib + define('BOOTSTRAPS', WEB_LIB.'bootstrap_sb/'); // bootstrap lib + define('LOG_PATH', FILE_BASE.APP_NAME.'/logs/'); // log path + + $this->load->model('txdata_model'); + // $this->parkingquery_model->init($this->vars); + } + + // 發生錯誤時集中在此處理 + public function error_handler($errno, $errstr, $errfile, $errline, $errcontext) + { + $str = date('H:i:s')."|{$errstr}|{$errfile}|{$errline}|{$errno}\n"; + //error_log($str, 3, $log_file . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + error_log($str, 3, LOG_PATH.APP_NAME . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + } + + + // 顯示靜態網頁(html檔) + protected function show_page($page_name, &$data = null) + { + $page_file = PAGE_PATH.$page_name.'.php'; + $last_modified_time = filemtime($page_file); + + // 若檔案修改時間沒有異動, 或版本無異動, 通知瀏覽器使用cache, 不再下傳網頁 + // header('Cache-Control:max-age='.MAX_AGE); // cache 1個月 + header('Last-Modified: '.gmdate('D, d M Y H:i:s', $last_modified_time).' GMT'); + header('Etag: '. APP_VERSION); + header('Cache-Control: public'); + + if (!empty($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == APP_VERSION && @strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time) + { + header('HTTP/1.1 304 Not Modified'); + } + else + { + $this->load->view(APP_NAME.'/'.$page_name, $data); + } + } + + // 取得場站費率設定 + // http://203.75.167.89/txdata.html/get_price_plan/12112/0 + public function get_price_plan() + { + $station_no = $this->uri->segment(3); + $tx_type = $this->uri->segment(4); + $data = $this->txdata_model->get_price_plan($station_no, $tx_type); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + // 取得特殊日期設定 + // http://203.75.167.89/txdata.html/get_date_plan/12345678/23456789 + public function get_date_plan() + { + $inTime = $this->uri->segment(3); + $balanceTime = $this->uri->segment(4); + $data = $this->txdata_model->get_date_plan($inTime, $balanceTime); + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + +} diff --git a/controllers/Vip.php b/controllers/Vip.php new file mode 100644 index 0000000..d876c2c --- /dev/null +++ b/controllers/Vip.php @@ -0,0 +1,353 @@ +vars['mcache'] = new Memcache; + $this->vars['mcache']->connect(MEMCACHE_HOST, MEMCACHE_POST) or die ('Could not connect memcache'); + + // mqtt subscribe + $this->vars['mqtt'] = new phpMQTT(MQ_HOST, MQ_POST, 'cario'); + + if(!$this->vars['mqtt']->connect()){ die ('Could not connect mqtt'); } + **/ + + // ----- 定義常數(路徑, cache秒數) ----- + define('APP_VERSION', '100'); // 版本號 + + define('MAX_AGE', 604800); // cache秒數, 此定義1個月 + define('APP_NAME', 'vip'); // 應用系統名稱 + + define('PAGE_PATH', APP_BASE.'ci_application/views/'.APP_NAME.'/'); // path of views + + define('SERVER_URL', 'http://'.(isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost').'/'); // URL + define('APP_URL', SERVER_URL.APP_NAME.'.html/'); // controller路徑 + define('WEB_URL', SERVER_URL.APP_NAME.'/'); // 網頁路徑 + define('WEB_LIB', SERVER_URL.'libs/'); // 網頁lib + define('BOOTSTRAPS', WEB_LIB.'bootstrap_sb/'); // bootstrap lib + define('LOG_PATH', FILE_BASE.APP_NAME.'/logs/'); // log path + + + $this->load->model('vip_model'); + $this->vip_model->init($this->vars); + + // load library + $this->load->library(array('form_validation','session')); + // load helpers + $this->load->helper(array('form')); + // ajax code + define('RESULT_SUCCESS', 'ok'); + define('RESULT_FORM_VALIDATION_FAIL', '-1'); + define('RESULE_FAIL', 'gg'); + } + + + + // 發生錯誤時集中在此處理 + public function error_handler($errno, $errstr, $errfile, $errline, $errcontext) + { + // ex: car_err://message.... + //$log_msg = explode('://', $errstr); + /* + if (count($log_msg) > 1) + { + $log_file = LOG_PATH.$log_msg[0]; + $str = date('H:i:s')."|{$log_msg[1]}|{$errfile}|{$errline}|{$errno}\n"; + } + else + { + $log_file = LOG_PATH.APP_NAME; + $str = date('H:i:s')."|{$errstr}|{$errfile}|{$errline}|{$errno}\n"; + } + */ + + $str = date('H:i:s')."|{$errstr}|{$errfile}|{$errline}|{$errno}\n"; + //error_log($str, 3, $log_file . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + error_log($str, 3, LOG_PATH.APP_NAME . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + } + + + + // 顯示靜態網頁(html檔) + protected function show_page($page_name, &$data = null) + { + $page_file = PAGE_PATH.$page_name.'.php'; + $last_modified_time = filemtime($page_file); + + // 若檔案修改時間沒有異動, 或版本無異動, 通知瀏覽器使用cache, 不再下傳網頁 + // header('Cache-Control:max-age='.MAX_AGE); // cache 1個月 + header('Last-Modified: '.gmdate('D, d M Y H:i:s', $last_modified_time).' GMT'); + header('Etag: '. APP_VERSION); + header('Cache-Control: public'); + + if (!empty($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == APP_VERSION && @strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time) + { + header('HTTP/1.1 304 Not Modified'); + } + else + { + $this->load->view(APP_NAME.'/'.$page_name, $data); + } + } + + public function index() + { + if($this->session->userdata('logged_in')) + { + $session_data = $this->session->userdata('logged_in'); + $data['username'] = $session_data['username']; + $data['type'] = $session_data['type']; + + if($data['type'] == 'ma') + { + $this->show_page('admin_page', $data); // 進階管理者介面 + } + else + { + $this->show_page('main_page', $data); // 一般管理者介面 + } + } + else + { + //If no session, redirect to login page + //redirect('login', 'refresh'); + $this->show_page('login_page'); + } + } + + // 登入 + public function user_login() + { + // form_validation + $this->form_validation->set_rules('login_name', 'login_name', 'trim|required|xss_clean'); + $this->form_validation->set_rules('pswd', 'pswd', 'trim|required|xss_clean'); + + if($this->form_validation->run() == FALSE) + { + return RESULT_FORM_VALIDATION_FAIL; + } + + // go model + $data = array + ( + 'login_name' => $this->input->post('login_name', true), + 'pswd' => $this->input->post('pswd', true) + ); + + $result = $this->vip_model->user_login($data); + + if($result) + { + $sess_array = array(); + foreach($result as $row) + { + $sess_array = array + ( + 'username' => $row->login_name , + 'type' => $row->type + ); + $this->session->set_userdata('logged_in', $sess_array); + } + echo RESULT_SUCCESS; + } + else + { + return RESULE_FAIL; + } + } + + // 登出 + public function user_logout() + { + $this->session->unset_userdata('logged_in'); + session_destroy(); + return RESULT_SUCCESS; + } + + // 新增與修改 + public function member_add() + { + // form_validation (required) + $this->form_validation->set_rules('member_no', 'member_no', 'trim|required|xss_clean'); + $this->form_validation->set_rules('station_no', 'station_no', 'trim|required|xss_clean'); + $this->form_validation->set_rules('lpr', 'lpr', 'trim|required|xss_clean|alpha_numeric'); + $this->form_validation->set_rules('start_date', 'start_date', 'trim|required|xss_clean'); + $this->form_validation->set_rules('end_date', 'end_date', 'trim|required|xss_clean'); + $this->form_validation->set_rules('member_name', 'member_name', 'trim|required|xss_clean'); + $this->form_validation->set_rules('mobile_no', 'mobile_no', 'trim|required|xss_clean'); + // form_validation (basic) + $this->form_validation->set_rules('remarks', 'remarks', 'trim|xss_clean'); + + if($this->form_validation->run() == FALSE) + { + return RESULT_FORM_VALIDATION_FAIL; + } + + // go model + $data = array + ( + 'member_no' => $this->input->post('member_no', true), + 'station_no' => $this->input->post('station_no', true), + 'lpr' => strtoupper($this->input->post('lpr', true)), + 'start_date' => $this->input->post('start_date', true), + 'end_date' => $this->input->post('end_date', true), + 'member_name' => $this->input->post('member_name', true), + 'member_nick_name' => $this->input->post('member_name', true), + 'mobile_no' => $this->input->post('mobile_no', true), + 'remarks' => $this->input->post('remarks', true) + ); + + $this->vip_model->vip_add($data); + echo RESULT_SUCCESS; + } + + + // 查詢 + public function member_query() + { + $data = $this->vip_model->vip_query(); + + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + + // 刪除 + public function member_delete() + { + // form_validation + $this->form_validation->set_rules('member_no', 'member_no', 'trim|required|xss_clean'); + + if($this->form_validation->run() == FALSE) + { + return RESULE_FAIL; + } + + // go model + $member_no = $this->input->post('member_no', true); + $this->vip_model->member_delete($member_no); + echo RESULT_SUCCESS; + } + + // 管理者新增與修改 + public function user_add() + { + // 判斷target_name分流insert or update + $this->form_validation->set_rules('target_name', 'target_name', 'trim|xss_clean'); + // form_validation (basic) + $this->form_validation->set_rules('type', 'type', 'trim|required|xss_clean'); + $this->form_validation->set_rules('user_name', 'user_name', 'trim|xss_clean'); + $this->form_validation->set_rules('email', 'email', 'trim|xss_clean'); + $this->form_validation->set_rules('mobile_no', 'mobile_no', 'trim|xss_clean'); + $this->form_validation->set_rules('tel', 'tel', 'trim|xss_clean'); + $this->form_validation->set_rules('car_plate', 'car_plate', 'trim|xss_clean'); + + if($this->form_validation->run() == FALSE) + { + return RESULT_FORM_VALIDATION_FAIL; + } + + $target_name = $this->input->post('target_name', true); + + if($target_name == '') + { + // insert 流程 + + // form_validation (required) + $this->form_validation->set_rules('login_name', 'login_name', 'trim|required|xss_clean'); + $this->form_validation->set_rules('pswd', 'pswd', 'trim|required|xss_clean'); + + if($this->form_validation->run() == FALSE) + { + return RESULT_FORM_VALIDATION_FAIL; + } + + // go model + $data = array + ( + 'type' => $this->input->post('type', true), + 'login_name' => $this->input->post('login_name', true), + 'pswd' => MD5($this->input->post('pswd', true)), + 'user_name' => $this->input->post('user_name', true), + 'email' => $this->input->post('email', true), + 'mobile_no' => $this->input->post('mobile_no', true), + 'tel' => $this->input->post('tel', true), + 'car_plate' => strtoupper($this->input->post('car_plate', true)) + ); + + $this->vip_model->user_insert($data); + echo RESULT_SUCCESS; + } + else + { + // update 流程 + + // go model + $data = array + ( + 'type' => $this->input->post('type', true), + 'user_name' => $this->input->post('user_name', true), + 'email' => $this->input->post('email', true), + 'mobile_no' => $this->input->post('mobile_no', true), + 'tel' => $this->input->post('tel', true), + 'car_plate' => strtoupper($this->input->post('car_plate', true)) + ); + + $this->vip_model->user_update($data, $target_name); + echo RESULT_SUCCESS; + } + + + } + + + // 管理者查詢 + public function user_query() + { + $data = $this->vip_model->user_query(); + + echo json_encode($data, JSON_UNESCAPED_UNICODE); + } + + + // 管理者刪除 + public function user_delete() + { + // form_validation + $this->form_validation->set_rules('login_name', 'login_name', 'trim|required|xss_clean'); + + if($this->form_validation->run() == FALSE) + { + return RESULE_FAIL; + } + + // go model + $login_name = $this->input->post('login_name', true); + $this->vip_model->user_delete($login_name); + echo RESULT_SUCCESS; + } + +} diff --git a/controllers/Vip_parked.php b/controllers/Vip_parked.php new file mode 100644 index 0000000..32bb4ac --- /dev/null +++ b/controllers/Vip_parked.php @@ -0,0 +1,109 @@ +vars['date_time'] = date('Y-m-d H:i:s'); // 格式化時間(2015-10-12 14:36:21) + $this->vars['time_num'] = str_replace(array('-', ':', ' '), '', $this->vars['date_time']); //數字化時間(20151012143621) + $this->vars['date_num'] = substr($this->vars['time_num'], 0, 8); // 數字化日期(20151012) + $this->vars['station_no'] = STATION_NO; // 本站編號 + + /* + // cameras or etagio直接release連線(即斷線), 但繼續處理邏輯 + $method_name = $this->router->fetch_method(); + if ($method_name == 'cameras' || $method_name == 'etagio') + { + ob_end_clean(); + ignore_user_abort(); + ob_start(); + header('Connection: close'); + header('Content-Length: ' . ob_get_length()); + ob_end_flush(); + flush(); + } + */ + + // ----- 程式開發階段log設定 ----- + if (@ENVIRONMENT == 'development') + { + ini_set('display_errors', '1'); + //error_reporting(E_ALL ^ E_NOTICE); + error_reporting(E_ALL); + } + set_error_handler(array($this, 'error_handler'), E_ALL); // 資料庫異動需做log + + // mqtt subscribe + $this->vars['mqtt'] = new phpMQTT(MQ_HOST, MQ_PORT, uniqid()); + if(!$this->vars['mqtt']->connect()){ die ('Could not connect mqtt'); } + + // ----- 定義常數(路徑, cache秒數) ----- + define('APP_VERSION', '100'); // 版本號 + + define('MAX_AGE', 604800); // cache秒數, 此定義1個月 + define('APP_NAME', 'vip_parked'); // 應用系統名稱 + + define('PAGE_PATH', APP_BASE.'ci_application/views/'.APP_NAME.'/'); // path of views + + define('SERVER_URL', 'http://'.(isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost').'/'); // URL + define('APP_URL', SERVER_URL.APP_NAME.'.html/'); // controller路徑 + define('WEB_URL', SERVER_URL.APP_NAME.'/'); // 網頁路徑 + define('WEB_LIB', SERVER_URL.'/libs/'); // 網頁lib + define('BOOTSTRAPS', WEB_LIB.'bootstrap_sb/'); // bootstrap lib + define('LOG_PATH', FILE_BASE.APP_NAME.'/logs/'); // log path name + define('LOG_FILE', FILE_BASE.APP_NAME.'/logs/cario.'); // log file name + } + + + // 發生錯誤時集中在此處理 + public function error_handler($errno, $errstr, $errfile, $errline, $errcontext) + { + $log_msg = explode('://', $errstr); + if (count($log_msg) > 1) + { + $log_file = $log_msg[0]; + $str = date('H:i:s')."|{$log_msg[1]}|{$errfile}|{$errline}|{$errno}\n"; + } + else + { + $log_file = APP_NAME; + $str = date('H:i:s')."|{$errstr}|{$errfile}|{$errline}|{$errno}\n"; + } + + error_log($str, 3, LOG_PATH.$log_file . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 + } + + + public function pages() + { + $data['vip_no'] = $this->uri->segment(3); // vip no + $data['mqtt_ip'] = '192.168.51.11'; + $this->load->view(APP_NAME.'/main_page', $data); + } + + + public function vip_welcome() + { + $this->load->view(APP_NAME.'/vip_welcome'); + } + + + public function parked() + { + $this->load->view(APP_NAME.'/vip_welcome'); + } +} diff --git a/controllers/index.html b/controllers/index.html new file mode 100644 index 0000000..b48b490 --- /dev/null +++ b/controllers/index.html @@ -0,0 +1,11 @@ + + + +403 Forbidden + + + +Directory access is forbidden.
+ + + diff --git a/coworker/acer2server.php b/coworker/acer2server.php new file mode 100644 index 0000000..53ca103 --- /dev/null +++ b/coworker/acer2server.php @@ -0,0 +1,250 @@ +count = 4; + +$tcp_worker->onConnect = function($connection) +{ + echo "New Connection\n"; +}; + +$tcp_worker->onClose = function($connection) +{ + echo "Connection closed\n"; +}; + +// 當用戶端發來數據(主程式) +$tcp_worker->onMessage = function($connection, $tcp_in) +{ + global $ch; + + $explode_tcp_in = explode(chr(28), $tcp_in); // 0x1C tcp欄位分隔 + $send_data = null; + + if(empty($explode_tcp_in) || count($explode_tcp_in) != 5) + { + trigger_error(".. unknown tcp_in|". print_r($explode_tcp_in, true) .'|'); + $send_data = gen_error_result(ALTOB_ERROR_CODE_UNKNOWN_INPUT); + } + else + { + list(, $seq, $cmd, $data, ) = $explode_tcp_in; + + $seq = 1; + + switch($cmd) + { + // 票卡入場訊號,供 ALTOB 登記 + case '001': + //(傳入:卡號、入場編號、是否月租卡; 回傳:成功、入場編號) + list($card_no, $cario_no, $card_type) = explode(chr(31), $data); // 0x1F data欄位分隔 + trigger_error("cmd:{$cmd}, card_no:{$card_no}, cario_no:{$cario_no}, card_type:{$card_type}"); + + // 呼叫 cmd_001 + $data = array('card_no' => $card_no, 'cario_no' => $cario_no, 'card_type' => $card_type); + curl_setopt($ch, CURLOPT_URL, 'http://localhost/acer_service.html/cmd_001/'); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); + $jdata = curl_exec($ch); + $result = json_decode($jdata, true); + + trigger_error("{$cmd}|{$card_no}|{$cario_no}|{$card_type}|result|" . print_r($result, true)); + + $send_data = gen_cario_result($seq, $cmd, + $result['result_code'], + $result['result']['cario_no'], + $result['result']['error_code']); + break; + + // 票卡離場訊號,供 ALTOB 登記 + case '002': + //(傳入:卡號、繳費時間、是否月租卡; 回傳:成功、入場編號) + list($card_no, $pay_time, $card_type) = explode(chr(31), $data); // 0x1F data欄位分隔 + trigger_error("cmd:{$cmd}, card_no:{$card_no}, pay_time:{$pay_time}, card_type:{$card_type}"); + + // 呼叫 cmd_002 + $data = array('card_no' => $card_no, 'pay_time' => $pay_time, 'card_type' => $card_type); + curl_setopt($ch, CURLOPT_URL, 'http://localhost/acer_service.html/cmd_002/'); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); + $jdata = curl_exec($ch); + $result = json_decode($jdata, true); + + trigger_error("{$cmd}|{$card_no}|{$pay_time}|{$card_type}|result|" . print_r($result, true)); + + $send_data = gen_cario_result($seq, $cmd, + $result['result_code'], + $result['result']['cario_no'], + $result['result']['error_code']); + break; + + // 票號離場訊號,回傳若成功觸發 ACER 開門 + case '003': + // (傳入:6 碼數字; 回傳:入場編號、成功與否代號) + list($ticket_no) = explode(chr(31), $data); // 0x1F data欄位分隔 + trigger_error("cmd:{$cmd}, ticket_no:{$ticket_no}"); + + // 呼叫 cmd_003 + $data = array('ticket_no' => $ticket_no); + curl_setopt($ch, CURLOPT_URL, 'http://localhost/acer_service.html/cmd_003/'); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); + $jdata = curl_exec($ch); + $result = json_decode($jdata, true); + + trigger_error("{$cmd}|{$ticket_no}|result|" . print_r($result, true)); + + $send_data = gen_cario_result($seq, $cmd, + $result['result_code'], + $result['result']['cario_no'], + $result['result']['error_code'], + $result['result']['msg_code']); + break; + + default: + trigger_error(".. unknown cmd | {$seq}, {$cmd}, {$data}|"); + $send_data = gen_error_result(ALTOB_ERROR_CODE_UNKNOWN_CMD); + break; + } + } + + // 未定義的錯誤 + if(empty($send_data)) + { + $send_data = gen_error_result(ALTOB_ERROR_CODE_UNDEFINED); + } + + $connection->close($send_data); +}; + +// 執行worker +Worker::runAll(); + +// 產生錯誤回傳 +function gen_error_result($error_code) +{ + return gen_cario_result(0, 0, ALTOB_RESULT_CODE_FAIL, 0, $error_code); +} + +// 產生 cario_no 回傳 +function gen_cario_result($seq, $cmd, $result_code, $cario_no, $error_code, $msg_code=0) +{ + $send_data = ''; + + $seq_pad = str_pad($seq, 5, '0', STR_PAD_LEFT); // 序號: 5 碼 (左邊補 0) + $cmd_pad = str_pad($cmd, 3, '0', STR_PAD_LEFT); // 指令: 3 碼 (左邊補 0) + $cario_no_pad = str_pad($cario_no, 10, '0', STR_PAD_LEFT); // 入場編號: 10 碼 (左邊補 0) + $error_code_pad = str_pad($error_code, 4, '0', STR_PAD_LEFT); // 錯誤碼: 4 碼 (左邊補 0) + $msg_code_pad = str_pad($msg_code, 5, '0', STR_PAD_LEFT); // 離場代碼: 5 碼 (左邊補 0) + + trigger_error(__FUNCTION__ . "..{$seq_pad}|{$cmd_pad}|{$cario_no_pad}|{$error_code_pad}|{$msg_code_pad}.."); + + if(empty($msg_code)) + { + $packformat = "a2Ca10Ca4"; + $data = pack($packformat, + // Data:內容除分隔符號為0x1F,其他全為ASCII碼0x20 ~ 0x7F內 + $result_code, 0x1f, $cario_no_pad, 0x1f, $error_code_pad + ); + $data_len = strlen($data); + $socket_len = $data_len + 16; + + //trigger_error(".. TEST socket_len | {$socket_len}, {$data_len}|". intval($socket_len / 0x0100). '_'. intval($socket_len % 0x0100)); + + $send_data = pack("Ca2Ca5Ca3C{$packformat}CCC", + 0x02, // STX:封包起始碼(0x02) + $socket_len, 0x1c, // 封包長度:從STX到ETX的位元數 + $seq_pad, 0x1c, // 封包流水號:5碼ASCII數字(不足5碼時左補”0”補滿5碼) + $cmd_pad, 0x1c, // CmdID:命令ID + + // Data:內容除分隔符號為0x1F,其他全為ASCII碼0x20 ~ 0x7F內 + $result_code, 0x1f, $cario_no_pad, 0x1f, $error_code_pad, + + 0x1c, + 0x80, // CRC:封包檢查碼 + 0x03 // ETX:封包結束碼(0x03) + ); + } + else + { + $packformat = "a2Ca10Ca4Ca5"; + $data = pack($packformat, + // Data:內容除分隔符號為0x1F,其他全為ASCII碼0x20 ~ 0x7F內 + $result_code, 0x1f, $cario_no_pad, 0x1f, $error_code_pad, 0x1f, $msg_code_pad + ); + $data_len = strlen($data); + $socket_len = $data_len + 16; + + //trigger_error(".. TEST socket_len | {$socket_len}, {$data_len}|". intval($socket_len / 0x0100). '_'. intval($socket_len % 0x0100)); + + $send_data = pack("Ca2Ca5Ca3C{$packformat}CCC", + 0x02, // STX:封包起始碼(0x02) + $socket_len, 0x1c, // 封包長度:從STX到ETX的位元數 + $seq_pad, 0x1c, // 封包流水號:5碼ASCII數字(不足5碼時左補”0”補滿5碼) + $cmd_pad, 0x1c, // CmdID:命令ID + + // Data:內容除分隔符號為0x1F,其他全為ASCII碼0x20 ~ 0x7F內 + $result_code, 0x1f, $cario_no_pad, 0x1f, $error_code_pad, 0x1f, $msg_code_pad, + + 0x1c, + 0x80, // CRC:封包檢查碼 + 0x03 // ETX:封包結束碼(0x03) + ); + } + + return $send_data; +} + +// 發生錯誤時集中在此處理 +function error_handler($errno, $errstr, $errfile, $errline, $errcontext) +{ + $str = date('H:i:s')."|{$errstr}|{$errfile}|{$errline}|{$errno}\n"; + error_log($str, 3, LOG_PATH.APP_NAME . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 +} diff --git a/coworker/parktron2server_fuzzy.php b/coworker/parktron2server_fuzzy.php new file mode 100644 index 0000000..ecf1683 --- /dev/null +++ b/coworker/parktron2server_fuzzy.php @@ -0,0 +1,322 @@ +count = 6; + +$tcp_worker->onConnect = function($connection) +{ + echo "New Connection\n"; +}; + +$tcp_worker->onClose = function($connection) +{ + echo "Connection closed\n"; +}; + +// 當用戶端發來數據(主程式) +$tcp_worker->onMessage = function($connection, $tcp_in) +{ + global $ch, $last_lpr; + + // echo 'start time:'.date('Y-m-d H:i:s'); + + list(, $seq, $cmd, $data) = explode(chr(28), $tcp_in); // 0x1C tcp欄位分隔 + // echo "data_in:[{$seq}|{$cmd}|{$data}|]\n"; + + switch($cmd) + { + case '001': // 車輛入場 + list($devno, $token, $lpr, $in_time, $last_field) = explode(chr(31), $data); // 0x1F data欄位分隔 + $type = substr($last_field, 0, -2); + echo "{$devno}|{$token}|{$lpr}|{$in_time}|{$type}|\n"; + $connection->send('OK'); + break; + + case '002': // APS詢問車牌入場時間 + list($token, $lpr, $last_field) = explode(chr(31), $data); // 0x1F data欄位分隔 + $lpr = str_replace('%', '', $lpr); + $last_lpr = $lpr; + $in_time = substr($last_field, 0, -2); + // echo "cmd_002:[{$token}|{$lpr}|{$in_time}|]/n"; + + $data = array('lpr' => $lpr); + curl_setopt($ch, CURLOPT_URL, 'http://localhost/carpayment.html/query_in_fuzzy/'); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); + $jdata = curl_exec($ch); + $results = json_decode($jdata, true); + + $connection->send(tcp_data_fuzzy($results['count'], $results['results'], '001', '002')); + break; + + case '003': // 繳費完成 + list($ticket_no, $lpr, $in_time, $pay_time, $last_field) = explode(chr(31), $data); // 0x1F data欄位分隔 + $pay_type = substr($last_field, 0, -2); + // echo "{$ticket_no}|{$lpr}|{$in_time}|{$pay_time}|{$pay_type}|/n"; + $connection->send('OK'); + + //if ($lpr == '*******') {$lpr = $last_lpr; $err_lpr = '***';} + if ($lpr == '*******') {$err_lpr = '***';} + else + { $err_lpr = '+++';} + + // 傳送繳費資料 + $data = array + ( + 'ticket_no' => $ticket_no, // 票卡號碼 + 'lpr' => $lpr, // 車號 + 'in_time' => $in_time, // 入場時間 + 'pay_time' => $pay_time, // 繳款時間 + 'pay_type' => $pay_type // 繳款方式(0:現金, 1:月票, 2:多卡通) + ); + + curl_setopt($ch, CURLOPT_URL, 'http://localhost/carpayment.html/p2payed/'); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); + $results = curl_exec($ch); + + file_put_contents('/tmp/aps.log.txt', date('Y-m-d H:i:s').":{$err_lpr}\n".print_r($data, true)."\n\n", FILE_APPEND); + + break; + } + + // echo 'end_time:'.date('Y-m-d H:i:s'); +}; + +function tcp_data_fuzzy($records_count, $records, $seq, $cmdid) +{ + $seq = '00001'; + $cmdid = '002'; + $packformat = 'aC'; + + // 0 筆 + if($records_count == 0) + { + $count = 0; + $data = pack($packformat, + "{$count}", 0x1f + ); + + $data_len = strlen($data); + $socket_len = $data_len + 16; + + $send_data = pack("CCCCa5Ca3C{$packformat}CC", + 0x02, + $socket_len / 0x0100, $socket_len % 0x0100, 0x1c, $seq, 0x1c, $cmdid, 0x1c, + "{$count}", 0x1f, + 0x80, 0x03); + return $send_data; + } + + // 1. create data + foreach ($records as $idx => $rows) + { + $pathlen = strlen($rows['in_pic_name']); + $packformat = $packformat."A7Ca7CaCa19Ca{$pathlen}Ca19Ca10Ca10Ca5Ca5C"; + } + + if(count($records) == 1) + { + $count = 1; + $data = pack($packformat, + "{$count}", 0x1f, + $records[0]['lpr'], 0x1f, $records[0]['seat_no'], 0x1f, $records[0]['ticket'], 0x1f, $records[0]['in_time'], 0x1f, $records[0]['in_pic_name'], 0x1f, $records[0]['pay_time'], 0x1f, $records[0]['start_date'], 0x1f, $records[0]['end_date'], 0x1f, $records[0]['start_time'], 0x1f, $records[0]['end_time'], 0x1f + ); + + $data_len = strlen($data); + $socket_len = $data_len + 16; + + $send_data = pack("CCCCa5Ca3C{$packformat}CC", + 0x02, + $socket_len / 0x0100, $socket_len % 0x0100, 0x1c, $seq, 0x1c, $cmdid, 0x1c, + "{$count}", 0x1f, + $records[0]['lpr'], 0x1f, $records[0]['seat_no'], 0x1f, $records[0]['ticket'], 0x1f, $records[0]['in_time'], 0x1f, $records[0]['in_pic_name'], 0x1f, $records[0]['pay_time'], 0x1f, $records[0]['start_date'], 0x1f, $records[0]['end_date'], 0x1f, $records[0]['start_time'], 0x1f, $records[0]['end_time'], 0x1f, + 0x80, 0x03); + } + else if(count($records) == 2) + { + $count = 2; + $data = pack($packformat, + "{$count}", 0x1f, + $records[0]['lpr'], 0x1f, $records[0]['seat_no'], 0x1f, $records[0]['ticket'], 0x1f, $records[0]['in_time'], 0x1f, $records[0]['in_pic_name'], 0x1f, $records[0]['pay_time'], 0x1f, $records[0]['start_date'], 0x1f, $records[0]['end_date'], 0x1f, $records[0]['start_time'], 0x1f, $records[0]['end_time'], 0x1f, + $records[1]['lpr'], 0x1f, $records[1]['seat_no'], 0x1f, $records[1]['ticket'], 0x1f, $records[1]['in_time'], 0x1f, $records[1]['in_pic_name'], 0x1f, $records[1]['pay_time'], 0x1f, $records[1]['start_date'], 0x1f, $records[1]['end_date'], 0x1f, $records[1]['start_time'], 0x1f, $records[1]['end_time'], 0x1f + ); + + $data_len = strlen($data); + $socket_len = $data_len + 16; + + $send_data = pack("CCCCa5Ca3C{$packformat}CC", + 0x02, + $socket_len / 0x0100, $socket_len % 0x0100, 0x1c, $seq, 0x1c, $cmdid, 0x1c, + "{$count}", 0x1f, + $records[0]['lpr'], 0x1f, $records[0]['seat_no'], 0x1f, $records[0]['ticket'], 0x1f, $records[0]['in_time'], 0x1f, $records[0]['in_pic_name'], 0x1f, $records[0]['pay_time'], 0x1f, $records[0]['start_date'], 0x1f, $records[0]['end_date'], 0x1f, $records[0]['start_time'], 0x1f, $records[0]['end_time'], 0x1f, + $records[1]['lpr'], 0x1f, $records[1]['seat_no'], 0x1f, $records[1]['ticket'], 0x1f, $records[1]['in_time'], 0x1f, $records[1]['in_pic_name'], 0x1f, $records[1]['pay_time'], 0x1f, $records[1]['start_date'], 0x1f, $records[1]['end_date'], 0x1f, $records[1]['start_time'], 0x1f, $records[1]['end_time'], 0x1f, + 0x80, 0x03); + } + else if(count($records) == 3) + { + $count = 3; + $data = pack($packformat, + "{$count}", 0x1f, + $records[0]['lpr'], 0x1f, $records[0]['seat_no'], 0x1f, $records[0]['ticket'], 0x1f, $records[0]['in_time'], 0x1f, $records[0]['in_pic_name'], 0x1f, $records[0]['pay_time'], 0x1f, $records[0]['start_date'], 0x1f, $records[0]['end_date'], 0x1f, $records[0]['start_time'], 0x1f, $records[0]['end_time'], 0x1f, + $records[1]['lpr'], 0x1f, $records[1]['seat_no'], 0x1f, $records[1]['ticket'], 0x1f, $records[1]['in_time'], 0x1f, $records[1]['in_pic_name'], 0x1f, $records[1]['pay_time'], 0x1f, $records[1]['start_date'], 0x1f, $records[1]['end_date'], 0x1f, $records[1]['start_time'], 0x1f, $records[1]['end_time'], 0x1f, + $records[2]['lpr'], 0x1f, $records[2]['seat_no'], 0x1f, $records[2]['ticket'], 0x1f, $records[2]['in_time'], 0x1f, $records[2]['in_pic_name'], 0x1f, $records[2]['pay_time'], 0x1f, $records[2]['start_date'], 0x1f, $records[2]['end_date'], 0x1f, $records[2]['start_time'], 0x1f, $records[2]['end_time'], 0x1f + ); + + $data_len = strlen($data); + $socket_len = $data_len + 16; + + $send_data = pack("CCCCa5Ca3C{$packformat}CC", + 0x02, + $socket_len / 0x0100, $socket_len % 0x0100, 0x1c, $seq, 0x1c, $cmdid, 0x1c, + "{$count}", 0x1f, + $records[0]['lpr'], 0x1f, $records[0]['seat_no'], 0x1f, $records[0]['ticket'], 0x1f, $records[0]['in_time'], 0x1f, $records[0]['in_pic_name'], 0x1f, $records[0]['pay_time'], 0x1f, $records[0]['start_date'], 0x1f, $records[0]['end_date'], 0x1f, $records[0]['start_time'], 0x1f, $records[0]['end_time'], 0x1f, + $records[1]['lpr'], 0x1f, $records[1]['seat_no'], 0x1f, $records[1]['ticket'], 0x1f, $records[1]['in_time'], 0x1f, $records[1]['in_pic_name'], 0x1f, $records[1]['pay_time'], 0x1f, $records[1]['start_date'], 0x1f, $records[1]['end_date'], 0x1f, $records[1]['start_time'], 0x1f, $records[1]['end_time'], 0x1f, + $records[2]['lpr'], 0x1f, $records[2]['seat_no'], 0x1f, $records[2]['ticket'], 0x1f, $records[2]['in_time'], 0x1f, $records[2]['in_pic_name'], 0x1f, $records[2]['pay_time'], 0x1f, $records[2]['start_date'], 0x1f, $records[2]['end_date'], 0x1f, $records[2]['start_time'], 0x1f, $records[2]['end_time'], 0x1f, + 0x80, 0x03); + } + else if(count($records) == 4) + { + $count = 4; + $data = pack($packformat, + "{$count}", 0x1f, + $records[0]['lpr'], 0x1f, $records[0]['seat_no'], 0x1f, $records[0]['ticket'], 0x1f, $records[0]['in_time'], 0x1f, $records[0]['in_pic_name'], 0x1f, $records[0]['pay_time'], 0x1f, $records[0]['start_date'], 0x1f, $records[0]['end_date'], 0x1f, $records[0]['start_time'], 0x1f, $records[0]['end_time'], 0x1f, + $records[1]['lpr'], 0x1f, $records[1]['seat_no'], 0x1f, $records[1]['ticket'], 0x1f, $records[1]['in_time'], 0x1f, $records[1]['in_pic_name'], 0x1f, $records[1]['pay_time'], 0x1f, $records[1]['start_date'], 0x1f, $records[1]['end_date'], 0x1f, $records[1]['start_time'], 0x1f, $records[1]['end_time'], 0x1f, + $records[2]['lpr'], 0x1f, $records[2]['seat_no'], 0x1f, $records[2]['ticket'], 0x1f, $records[2]['in_time'], 0x1f, $records[2]['in_pic_name'], 0x1f, $records[2]['pay_time'], 0x1f, $records[2]['start_date'], 0x1f, $records[2]['end_date'], 0x1f, $records[2]['start_time'], 0x1f, $records[2]['end_time'], 0x1f, + $records[3]['lpr'], 0x1f, $records[3]['seat_no'], 0x1f, $records[3]['ticket'], 0x1f, $records[3]['in_time'], 0x1f, $records[3]['in_pic_name'], 0x1f, $records[3]['pay_time'], 0x1f, $records[3]['start_date'], 0x1f, $records[3]['end_date'], 0x1f, $records[3]['start_time'], 0x1f, $records[3]['end_time'], 0x1f + ); + + $data_len = strlen($data); + $socket_len = $data_len + 16; + + $send_data = pack("CCCCa5Ca3C{$packformat}CC", + 0x02, + $socket_len / 0x0100, $socket_len % 0x0100, 0x1c, $seq, 0x1c, $cmdid, 0x1c, + "{$count}", 0x1f, + $records[0]['lpr'], 0x1f, $records[0]['seat_no'], 0x1f, $records[0]['ticket'], 0x1f, $records[0]['in_time'], 0x1f, $records[0]['in_pic_name'], 0x1f, $records[0]['pay_time'], 0x1f, $records[0]['start_date'], 0x1f, $records[0]['end_date'], 0x1f, $records[0]['start_time'], 0x1f, $records[0]['end_time'], 0x1f, + $records[1]['lpr'], 0x1f, $records[1]['seat_no'], 0x1f, $records[1]['ticket'], 0x1f, $records[1]['in_time'], 0x1f, $records[1]['in_pic_name'], 0x1f, $records[1]['pay_time'], 0x1f, $records[1]['start_date'], 0x1f, $records[1]['end_date'], 0x1f, $records[1]['start_time'], 0x1f, $records[1]['end_time'], 0x1f, + $records[2]['lpr'], 0x1f, $records[2]['seat_no'], 0x1f, $records[2]['ticket'], 0x1f, $records[2]['in_time'], 0x1f, $records[2]['in_pic_name'], 0x1f, $records[2]['pay_time'], 0x1f, $records[2]['start_date'], 0x1f, $records[2]['end_date'], 0x1f, $records[2]['start_time'], 0x1f, $records[2]['end_time'], 0x1f, + $records[3]['lpr'], 0x1f, $records[3]['seat_no'], 0x1f, $records[3]['ticket'], 0x1f, $records[3]['in_time'], 0x1f, $records[3]['in_pic_name'], 0x1f, $records[3]['pay_time'], 0x1f, $records[3]['start_date'], 0x1f, $records[3]['end_date'], 0x1f, $records[3]['start_time'], 0x1f, $records[3]['end_time'], 0x1f, + 0x80, 0x03); + } + else if(count($records) == 5) + { + $count = 5; + $data = pack($packformat, + "{$count}", 0x1f, + $records[0]['lpr'], 0x1f, $records[0]['seat_no'], 0x1f, $records[0]['ticket'], 0x1f, $records[0]['in_time'], 0x1f, $records[0]['in_pic_name'], 0x1f, $records[0]['pay_time'], 0x1f, $records[0]['start_date'], 0x1f, $records[0]['end_date'], 0x1f, $records[0]['start_time'], 0x1f, $records[0]['end_time'], 0x1f, + $records[1]['lpr'], 0x1f, $records[1]['seat_no'], 0x1f, $records[1]['ticket'], 0x1f, $records[1]['in_time'], 0x1f, $records[1]['in_pic_name'], 0x1f, $records[1]['pay_time'], 0x1f, $records[1]['start_date'], 0x1f, $records[1]['end_date'], 0x1f, $records[1]['start_time'], 0x1f, $records[1]['end_time'], 0x1f, + $records[2]['lpr'], 0x1f, $records[2]['seat_no'], 0x1f, $records[2]['ticket'], 0x1f, $records[2]['in_time'], 0x1f, $records[2]['in_pic_name'], 0x1f, $records[2]['pay_time'], 0x1f, $records[2]['start_date'], 0x1f, $records[2]['end_date'], 0x1f, $records[2]['start_time'], 0x1f, $records[2]['end_time'], 0x1f, + $records[3]['lpr'], 0x1f, $records[3]['seat_no'], 0x1f, $records[3]['ticket'], 0x1f, $records[3]['in_time'], 0x1f, $records[3]['in_pic_name'], 0x1f, $records[3]['pay_time'], 0x1f, $records[3]['start_date'], 0x1f, $records[3]['end_date'], 0x1f, $records[3]['start_time'], 0x1f, $records[3]['end_time'], 0x1f, + $records[4]['lpr'], 0x1f, $records[4]['seat_no'], 0x1f, $records[4]['ticket'], 0x1f, $records[4]['in_time'], 0x1f, $records[4]['in_pic_name'], 0x1f, $records[4]['pay_time'], 0x1f, $records[4]['start_date'], 0x1f, $records[4]['end_date'], 0x1f, $records[4]['start_time'], 0x1f, $records[4]['end_time'], 0x1f + ); + + $data_len = strlen($data); + $socket_len = $data_len + 16; + + $send_data = pack("CCCCa5Ca3C{$packformat}CC", + 0x02, + $socket_len / 0x0100, $socket_len % 0x0100, 0x1c, $seq, 0x1c, $cmdid, 0x1c, + "{$count}", 0x1f, + $records[0]['lpr'], 0x1f, $records[0]['seat_no'], 0x1f, $records[0]['ticket'], 0x1f, $records[0]['in_time'], 0x1f, $records[0]['in_pic_name'], 0x1f, $records[0]['pay_time'], 0x1f, $records[0]['start_date'], 0x1f, $records[0]['end_date'], 0x1f, $records[0]['start_time'], 0x1f, $records[0]['end_time'], 0x1f, + $records[1]['lpr'], 0x1f, $records[1]['seat_no'], 0x1f, $records[1]['ticket'], 0x1f, $records[1]['in_time'], 0x1f, $records[1]['in_pic_name'], 0x1f, $records[1]['pay_time'], 0x1f, $records[1]['start_date'], 0x1f, $records[1]['end_date'], 0x1f, $records[1]['start_time'], 0x1f, $records[1]['end_time'], 0x1f, + $records[2]['lpr'], 0x1f, $records[2]['seat_no'], 0x1f, $records[2]['ticket'], 0x1f, $records[2]['in_time'], 0x1f, $records[2]['in_pic_name'], 0x1f, $records[2]['pay_time'], 0x1f, $records[2]['start_date'], 0x1f, $records[2]['end_date'], 0x1f, $records[2]['start_time'], 0x1f, $records[2]['end_time'], 0x1f, + $records[3]['lpr'], 0x1f, $records[3]['seat_no'], 0x1f, $records[3]['ticket'], 0x1f, $records[3]['in_time'], 0x1f, $records[3]['in_pic_name'], 0x1f, $records[3]['pay_time'], 0x1f, $records[3]['start_date'], 0x1f, $records[3]['end_date'], 0x1f, $records[3]['start_time'], 0x1f, $records[3]['end_time'], 0x1f, + $records[4]['lpr'], 0x1f, $records[4]['seat_no'], 0x1f, $records[4]['ticket'], 0x1f, $records[4]['in_time'], 0x1f, $records[4]['in_pic_name'], 0x1f, $records[4]['pay_time'], 0x1f, $records[4]['start_date'], 0x1f, $records[4]['end_date'], 0x1f, $records[4]['start_time'], 0x1f, $records[4]['end_time'], 0x1f, + 0x80, 0x03); + } + else if(count($records) == 6) + { + $count = 6; + $data = pack($packformat, + "{$count}", 0x1f, + $records[0]['lpr'], 0x1f, $records[0]['seat_no'], 0x1f, $records[0]['ticket'], 0x1f, $records[0]['in_time'], 0x1f, $records[0]['in_pic_name'], 0x1f, $records[0]['pay_time'], 0x1f, $records[0]['start_date'], 0x1f, $records[0]['end_date'], 0x1f, $records[0]['start_time'], 0x1f, $records[0]['end_time'], 0x1f, + $records[1]['lpr'], 0x1f, $records[1]['seat_no'], 0x1f, $records[1]['ticket'], 0x1f, $records[1]['in_time'], 0x1f, $records[1]['in_pic_name'], 0x1f, $records[1]['pay_time'], 0x1f, $records[1]['start_date'], 0x1f, $records[1]['end_date'], 0x1f, $records[1]['start_time'], 0x1f, $records[1]['end_time'], 0x1f, + $records[2]['lpr'], 0x1f, $records[2]['seat_no'], 0x1f, $records[2]['ticket'], 0x1f, $records[2]['in_time'], 0x1f, $records[2]['in_pic_name'], 0x1f, $records[2]['pay_time'], 0x1f, $records[2]['start_date'], 0x1f, $records[2]['end_date'], 0x1f, $records[2]['start_time'], 0x1f, $records[2]['end_time'], 0x1f, + $records[3]['lpr'], 0x1f, $records[3]['seat_no'], 0x1f, $records[3]['ticket'], 0x1f, $records[3]['in_time'], 0x1f, $records[3]['in_pic_name'], 0x1f, $records[3]['pay_time'], 0x1f, $records[3]['start_date'], 0x1f, $records[3]['end_date'], 0x1f, $records[3]['start_time'], 0x1f, $records[3]['end_time'], 0x1f, + $records[4]['lpr'], 0x1f, $records[4]['seat_no'], 0x1f, $records[4]['ticket'], 0x1f, $records[4]['in_time'], 0x1f, $records[4]['in_pic_name'], 0x1f, $records[4]['pay_time'], 0x1f, $records[4]['start_date'], 0x1f, $records[4]['end_date'], 0x1f, $records[4]['start_time'], 0x1f, $records[4]['end_time'], 0x1f, + $records[5]['lpr'], 0x1f, $records[5]['seat_no'], 0x1f, $records[5]['ticket'], 0x1f, $records[5]['in_time'], 0x1f, $records[5]['in_pic_name'], 0x1f, $records[5]['pay_time'], 0x1f, $records[5]['start_date'], 0x1f, $records[5]['end_date'], 0x1f, $records[5]['start_time'], 0x1f, $records[5]['end_time'], 0x1f + ); + + $data_len = strlen($data); + $socket_len = $data_len + 16; + + $send_data = pack("CCCCa5Ca3C{$packformat}CC", + 0x02, + $socket_len / 0x0100, $socket_len % 0x0100, 0x1c, $seq, 0x1c, $cmdid, 0x1c, + "{$count}", 0x1f, + $records[0]['lpr'], 0x1f, $records[0]['seat_no'], 0x1f, $records[0]['ticket'], 0x1f, $records[0]['in_time'], 0x1f, $records[0]['in_pic_name'], 0x1f, $records[0]['pay_time'], 0x1f, $records[0]['start_date'], 0x1f, $records[0]['end_date'], 0x1f, $records[0]['start_time'], 0x1f, $records[0]['end_time'], 0x1f, + $records[1]['lpr'], 0x1f, $records[1]['seat_no'], 0x1f, $records[1]['ticket'], 0x1f, $records[1]['in_time'], 0x1f, $records[1]['in_pic_name'], 0x1f, $records[1]['pay_time'], 0x1f, $records[1]['start_date'], 0x1f, $records[1]['end_date'], 0x1f, $records[1]['start_time'], 0x1f, $records[1]['end_time'], 0x1f, + $records[2]['lpr'], 0x1f, $records[2]['seat_no'], 0x1f, $records[2]['ticket'], 0x1f, $records[2]['in_time'], 0x1f, $records[2]['in_pic_name'], 0x1f, $records[2]['pay_time'], 0x1f, $records[2]['start_date'], 0x1f, $records[2]['end_date'], 0x1f, $records[2]['start_time'], 0x1f, $records[2]['end_time'], 0x1f, + $records[3]['lpr'], 0x1f, $records[3]['seat_no'], 0x1f, $records[3]['ticket'], 0x1f, $records[3]['in_time'], 0x1f, $records[3]['in_pic_name'], 0x1f, $records[3]['pay_time'], 0x1f, $records[3]['start_date'], 0x1f, $records[3]['end_date'], 0x1f, $records[3]['start_time'], 0x1f, $records[3]['end_time'], 0x1f, + $records[4]['lpr'], 0x1f, $records[4]['seat_no'], 0x1f, $records[4]['ticket'], 0x1f, $records[4]['in_time'], 0x1f, $records[4]['in_pic_name'], 0x1f, $records[4]['pay_time'], 0x1f, $records[4]['start_date'], 0x1f, $records[4]['end_date'], 0x1f, $records[4]['start_time'], 0x1f, $records[4]['end_time'], 0x1f, + $records[5]['lpr'], 0x1f, $records[5]['seat_no'], 0x1f, $records[5]['ticket'], 0x1f, $records[5]['in_time'], 0x1f, $records[5]['in_pic_name'], 0x1f, $records[5]['pay_time'], 0x1f, $records[5]['start_date'], 0x1f, $records[5]['end_date'], 0x1f, $records[5]['start_time'], 0x1f, $records[5]['end_time'], 0x1f, + 0x80, 0x03); + } + + return $send_data; +} + +function tcp_data($arr, $seq, $cmdid) +{ + $crc = pack('C', 'X'); // 起始值 + $seq = '00001'; + $cmdid = '002'; + $pathlen = strlen($arr['pic_name']); + $packformat = "aCA7Ca7CaCa19Ca{$pathlen}Ca19Ca10Ca10Ca5Ca5C"; + // $packformat = "aCA7Ca7CaCa19Ca71Ca19Ca10Ca10Ca5Ca5C"; + $data = pack($packformat, + $arr['nth'], 0x1f, + $arr['lpr'], 0x1f, + $arr['seat_no'], 0x1f, + $arr['ticket'], 0x1f, + $arr['start_time'], 0x1f, + $arr['pic_name'], 0x1f, + $arr['pay_time'], 0x1f, + $arr['ticket_start_date'], 0x1f, + $arr['ticket_end_date'], 0x1f, + $arr['ticket_start_time'], 0x1f, + $arr['ticket_end_time'], 0x1f); + + $data_len = strlen($data); + $socket_len = $data_len + 16; + // echo "len data[{$data_len}] socket[{$socket_len}] data[{$data}]"; + + $send_data = pack("CCCCa5Ca3C{$packformat}CC", + 0x02, + $socket_len / 0x0100, $socket_len % 0x0100, 0x1c, $seq, 0x1c, $cmdid, 0x1c, + $arr['nth'], 0x1f, + $arr['lpr'], 0x1f, + $arr['seat_no'], 0x1f, + $arr['ticket'], 0x1f, + $arr['start_time'], 0x1f, + $arr['pic_name'], 0x1f, + $arr['pay_time'], 0x1f, + $arr['ticket_start_date'], 0x1f, + $arr['ticket_end_date'], 0x1f, + $arr['ticket_start_time'], 0x1f, + $arr['ticket_end_time'], 0x1f, + 0x80, 0x03); + + // echo 'len:[' . $socket_len. '] send_data:['. $send_data .']'; + // file_put_contents('/tmp/aps.log.txt', date('Y-m-d H:i:s')."\n".$send_data ."\n\n", FILE_APPEND); + return $send_data; +} + + +// 執行worker +Worker::runAll(); diff --git a/coworker/station.config.php b/coworker/station.config.php new file mode 100644 index 0000000..4e2f77d --- /dev/null +++ b/coworker/station.config.php @@ -0,0 +1,15 @@ + 31, + 2 => 28, + 3 => 31, + 4 => 30, + 5 => 31, + 6 => 30, + 7 => 31, + 8 => 31, + 9 => 30, + 10 => 31, + 11 => 30, + 12 => 31 +); + +$xvars = array(); // 共用變數 + +// 共用記憶體 +$mem = new Memcache; +if (! $mem->pconnect(MEMCACHE_HOST, MEMCACHE_PORT)) +{ + echo 'Could not connect memcache'; + Worker::stopAll(); +} + +// 連接總管理處資料庫 +$pdo = new PDO($dbs['dsn'], $dbs['user_name'], $dbs['password']); + +// 讀取info場站共用資訊 +$sql_info = 'select station_no, station_name, station_full_name, company_no, station_ip, hq_url, origin_url, period_name, park_time,member_attr_list, period_list from info where seqno = 1'; +$info_arr = $pdo->query($sql_info)->fetch(PDO::FETCH_ASSOC); + +// global variable +$pdo = null; +$query_syncs = null; +$query_sync2hq_ok = null; + +// 未同步者批次同步至總管理處 +$sql_syncs = 'select st_sync_no, station_no, act, hq_tname, st_tname, st_seqno, sync_data from syncs where synced = 0 and st_sync_no = ?'; +// $query_syncs = $pdo->prepare($sql_syncs); + +// 同步成功 +$sql_sync2hq_ok = 'update syncs set synced = 1, hq_sync_no = ? where st_sync_no = ?'; +// $query_sync2hq_ok = $pdo->prepare($sql_sync2hq_ok); + +// 預設curl參數 +$curl_ch = curl_init(); +$curl_options = array +( + CURLOPT_URL => $info_arr['hq_url'], + CURLOPT_HEADER => 0, + CURLOPT_RETURNTRANSFER => 1, // 返回值不顯示, 只做變數用 + CURLOPT_POST => 1, + CURLOPT_CONNECTTIMEOUT => 5, + CURLOPT_TIMEOUT => 5 +); + +init_station_xvars(); + +// 建立一個Worker監聽60133埠,不使用任何應用層協定 +$worker = new Worker("http://0.0.0.0:60133"); + +// 啟動N個進程對外提供服務 +$worker->count = 4; + +// ----- program start ----- + +// 當用戶端發來數據(主程式) +$worker->onMessage = function($connection, $msg_in) +{ + global $dbs, $pdo, $sql_syncs, $sql_sync2hq_ok, $query_syncs, $query_sync2hq_ok; + + // 無連線或status != Localhost via UNIX socket, 重連線之 + if (empty($pdo) || preg_match('/socket$/', $pdo->getAttribute(PDO::ATTR_CONNECTION_STATUS)) != 1 ) + { + $pdo = new PDO($dbs['dsn'], $dbs['user_name'], $dbs['password'], array(PDO::ATTR_PERSISTENT => true)); + $query_syncs = $pdo->prepare($sql_syncs); + $query_sync2hq_ok = $pdo->prepare($sql_sync2hq_ok); + trigger_error('new pdo'); + } + + if (!empty($_REQUEST['cmd'])) + { + trigger_error('worker.onMessage: ' . print_r($_REQUEST, true)); + $funcs = @$_REQUEST['cmd']; + $funcs($connection); + } +}; + +// 執行worker +Worker::runAll(); + +// ----- end of program ----- + + +// 同步化, 場站 -> 總管理處 , 參數: +// http://hq_ip:60133/?cmd=st_syncs&station_no=12110&act=U&tname=members&key=member_no&kval=12110101&jdata=json_str&ck=str32 +function st_syncs($connection) +{ + global $pdo_hq, $query_hq_sync; + // 暫不驗證 + $syncs_sql = parms2sql($_REQUEST); + + // exec:傳回筆數, query:傳回資料 + $rows_affected = $pdo_hq->exec($syncs_sql); + // 如果新增資料, 回傳insert ID + if ($_REQUEST['act'] == 'A') $rows_affected = $pdo_hq->lastInsertId(); + + @$connection->send($rows_affected); // 回應當前序號或筆數 + + $confirms = $rows_affected > 0 ? 1 : 0; + + $query_hq_sync->execute(array($_REQUEST['station_no'], $_REQUEST['act'], $_REQUEST['tname'], $_REQUEST['data'], $confirms)); +} + + +// 讀取序號 +// http://localhost:60133/?cmd=seqno&seqname=members&init_no=1025 +function seqno($connection) +{ + $seqno_fname = SEQNO_PATH . "{$_REQUEST['seqname']}.txt"; + $fp = fopen($seqno_fname, 'r+'); + + // lock, 讀入序號, 加1寫回, close + if ($fp) + { + flock($fp, LOCK_EX); + $seqno = fread($fp, 80); + $next_no = $seqno + 1; + rewind($fp); + fwrite($fp, $next_no); + flock($fp, LOCK_UN); + fclose($fp); + } + else // 如無此序號檔, 新建之, 並傳回初始值 + { + $seqno = empty($_REQUEST['init_no']) ? 1 : $_REQUEST['init_no']; + $next_no = $seqno + 1; + file_put_contents($seqno_fname, $next_no, FILE_APPEND); + } + @$connection->send($seqno); // 回應當前序號 +} + + +// 檢查是否有連線 ? +function check_connect($connection) +{ + $connected = @fsockopen($_REQUEST['ip'], $_REQUEST['port'], $errno, $errstr, $_REQUEST['timeout']); + + if ($connected) + { + fclose($connected); + $is_connected = 1; //action when connected + } + else + { + $is_connected = 0; //action in connection failure + } + + return $is_connected; +} + + +// 取得下一租期期最後一日 +function last_date_next($connection) +{ + @cross_header(); + @$connection->send(last_date_next_period($_REQUEST['last_date_curr'], $_REQUEST['fee_period'])); // 參數:本期截止日,繳期 +} + + +// 取得下一租期期最後一日, 參數: 本期截止日, 繳期 +function last_date_next_period($last_date_curr, $fee_period) +{ + global $last_date_month; + $arr = explode('-', $last_date_curr); + $yy = (int) $arr[0]; // 取年份 + $mm = (int) $arr[1]; // 取月份 + + $mm += $fee_period; + if ($mm > 12) // 超過12月, 年度+1, 折算明年度月份 + { + ++$yy; + $mm -= 12; + } + + $dd = $mm == 2 && ($yy % 4) == 0 ? 29 : $last_date_month[$mm]; + if ($mm < 10) $mm = "0{$mm}"; // 個位數前面補0 + return "{$yy}-{$mm}-{$dd}"; +} + +// web跨網域header設定 +function cross_header() +{ + global $info_arr; + + \Workerman\Protocols\Http::header('Access-Control-Allow-Origin: ' . "{$info_arr['origin_url']}"); + \Workerman\Protocols\Http::header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS'); + \Workerman\Protocols\Http::header('Access-Control-Allow-Headers: X-Requested-With, Content-Type, Accept'); +} + +// 將參數轉成sql命令字串 +function parms2sql($parms) +{ + $act = $parms['act']; + switch($act) + { + case 'U': // 更新場站資料庫 ???? + $sql = "update {$parms['tname']} set {$parms['data']} where {$parms['key']} = '{$parms['kval']}';"; + break; + + case 'A': // 新增資料 + $fields_str = implode(',', array_keys($data)); + $values_str = "'".implode("',", array_values($data))."'"; + $sql = "insert into {$parms['tname']} ({$fields_str}) values({$values_str});"; + break; + + case 'D': // 刪除資料 + $sql = "delete {$parms['tname']} where {$parms['key']} = '{$parms['kval']}';"; + break; + } +} + +// 場站初始化參數 +function init_station_xvars() +{ + global $mem, $info_arr, $xvars; + + $data = array + ( + 'cmd' => 'init_station', + 'station_no' => $info_arr['station_no'], + 'park_time' => $info_arr['park_time'] + ); + + $jdata = worker_tx($data); + + if(empty($jdata)) + { + trigger_error('中控已斷線, 建立預設值..'.print_r($jdata, true)); + + // 中控已斷線, 建立預設值 + $xvars = array(); + $xvars['info']['period_name'] = array(1 => "月繳", 2 => "雙月繳", 3 => "季繳", 6 => "雙季繳", 12 => "四季繳"); + $xvars['info']['member_attr'] = array(1 => "一般", 2 => "里民", 3 => "身障", 4 => "員工", 5 => "里長", 250 => "VIP"); + $xvars['pt'] = + array( + 'RE' => array( + 'seqno' => 1000, + 'timex' => array( + '0' => array('type' => 1, 'w_start' => 0, 'w_end' => 6, 'time_start' => '00:00:00', 'time_end' => '23:59:59') + ), + 'remarks' => '全天全時段' + ), + 'NF' => array( + 'seqno' => 1010, + 'timex' => array( + '0' => array('type' => 1, 'w_start' => 1, 'w_end' => 5, 'time_start' => '18:00:00', 'time_end' => '23:59:59'), + '1' => array('type' => 1, 'w_start' => 1, 'w_end' => 5, 'time_start' => '00:00:00', 'time_end' => '07:59:59') + ), + 'remarks' => '週一至週五: 00:00:00 - 07:59:59
週一至週五: 18:00:00 - 23:59:59' + ), + 'WK66' => array( + 'seqno' => 1026, + 'timex' => array( + '0' => array('type' => 1, 'w_start' => 1, 'w_end' => 5, 'time_start' => '06:00:00', 'time_end' => '17:59:59') + ), + 'remarks' => '週一至週五: 06:00:00 - 17:59:59' + ), + 'WK' => array( + 'seqno' => 1020, + 'timex' => array( + '0' => array('type' => 1, 'w_start' => 1, 'w_end' => 5, 'time_start' => '07:30:00', 'time_end' => '18:29:59') + ), + 'remarks' => '週一至週五: 07:30:00 - 18:29:59' + ), + 'HO' => array( + 'seqno' => 1030, + 'timex' => array( + '0' => array('type' => 1, 'w_start' => 6, 'w_end' => 6, 'time_start' => '00:00:00', 'time_end' => '23:59:59'), + '1' => array('type' => 1, 'w_start' => 0, 'w_end' => 0, 'time_start' => '00:00:00', 'time_end' => '23:59:59') + ), + 'remarks' => '週六日全時段' + ) + ); + } + else + { + $xvars = json_decode($jdata, true); + + // 篩選繳期名稱 + $arr = array(); + $arr_list = explode(',', $info_arr['period_list']); + foreach($arr_list as $idx) $arr[$idx] = $xvars['info']['period_name'][$idx]; + $xvars['info']['period_name'] = $arr; + + // 篩選會員身份 + $arr = array(); + $arr_list = explode(',', $info_arr['member_attr_list']); + foreach($arr_list as $idx) $arr[$idx] = $xvars['info']['member_attr'][$idx]; + $xvars['info']['member_attr'] = $arr; + } + + $mem->set('st_info', $info_arr); + $mem->set('info', $xvars['info']); + $mem->set('pt', $xvars['pt']); + + trigger_error('st_info: '.print_r($info_arr, true)); + trigger_error('xvars: '.print_r($xvars, true)); +} + + +// 顯示場站初始化參數 +function show_all_vars($connection) +{ + global $info_arr, $xvars; + $connection->send(json_encode($xvars, JSON_UNESCAPED_UNICODE)); +} + + +// 場站初始化參數 +function get_var($connection) +{ + global $xvars; + + $str = gettype($xvars[$_REQUEST['var']]) == 'array' ? json_encode($xvars[$_REQUEST['var']], JSON_UNESCAPED_UNICODE) : $xvars[$_REQUEST['var']]; + + $connection->send($str); +} + + +// 顯示場站初始化參數 +function set_var($connection) +{ + global $xvars; + + $xvars[$_REQUEST['var']] = $_REQUEST['val']; + + $connection->send('1'); +} + +// 批次同步資料表至總管理處 +function sync_batch($connection) +{ + global $query_syncs, $query_sync2hq_ok; + + //trigger_error(__FUNCTION__ . '..start..'); + + $connection->close(); // 先斷線再繼續處理 + + foreach(explode(',', $_REQUEST['sync_seqnos']) as $st_sync_no) + { + if(empty($st_sync_no)) continue; + + $query_syncs->execute(array($st_sync_no)); + $rows_syncs = $query_syncs->fetch(PDO::FETCH_ASSOC); + $tx = $rows_syncs; + + if(empty($tx)) continue; + + $tx['cmd'] = 'sync_st2hq'; // 場站同步至總管理處 + $hq_sync_no = worker_tx($tx); + + //trigger_error(__FUNCTION__ . '| 1. st_sync_no: ' . $st_sync_no . ', 2. rows_syncs: ' . $rows_syncs . ', 3. hq_sync_no: ' . $hq_sync_no); + + // 同步成功, 記錄之 ( note: 總管理處的 hq_sync 記錄完成就視為完成,各場站 sync.synced = 1 ) + if ($hq_sync_no > 0) + { + $query_sync2hq_ok->execute(array($hq_sync_no, $st_sync_no)); + } + else + { + trigger_error('sync err:'.json_encode($tx, JSON_UNESCAPED_UNICODE)); // TODO: sync 失敗的處理方式 + } + } + //trigger_error(__FUNCTION__ . '..end..'); +} + +// 月租金額計算 +function calculate_rents_amt($connection) +{ + $_REQUEST['rents_amt1'] = 100; + $_REQUEST['rents_amt2'] = 200; + cross_header(); + $connection->send(json_encode($_REQUEST, JSON_UNESCAPED_UNICODE)); +} + +// worker connect至總管理處 +function worker_tx($data) +{ + global $curl_ch, $curl_options; + + $curl_options[CURLOPT_POSTFIELDS] = $data; + trigger_error('curl:'. print_r($curl_options, true)); + curl_setopt_array($curl_ch, $curl_options); + return(curl_exec($curl_ch)); +} + +// 發生錯誤時集中在此處理 +function error_handler($errno, $errstr, $errfile, $errline, $errcontext) +{ + $str = date('H:i:s')."|{$errstr}|{$errfile}|{$errline}|{$errno}\n"; + error_log($str, 3, LOG_PATH.APP_NAME . '.' . date('Ymd').'.log.txt'); // 3代表參考後面的檔名 +} + \ No newline at end of file diff --git a/coworker/sync_hq_daily.php b/coworker/sync_hq_daily.php new file mode 100644 index 0000000..e079ac7 --- /dev/null +++ b/coworker/sync_hq_daily.php @@ -0,0 +1,38 @@ +getMessage()); +} + +trigger_error('..completed..'); \ No newline at end of file diff --git a/coworker/sync_minutely.php b/coworker/sync_minutely.php new file mode 100644 index 0000000..861fa49 --- /dev/null +++ b/coworker/sync_minutely.php @@ -0,0 +1,38 @@ +getMessage()); +} + +trigger_error('..completed..'); \ No newline at end of file diff --git a/models/Acer_service_model.php b/models/Acer_service_model.php new file mode 100644 index 0000000..d367057 --- /dev/null +++ b/models/Acer_service_model.php @@ -0,0 +1,342 @@ +load->database(); + $this->now_str = date('Y-m-d H:i:s'); + + // ACER 連線設定 (測試環境) + //define('ACER_SERVICE_IP', '220.130.199.142'); + //define('ACER_SERVICE_PORT', 60833); + + // ACER 連線設定 (測試環境 - 現場呼叫) + //define('ACER_SERVICE_IP', '220.130.199.142'); + //define('ACER_SERVICE_PORT', 8033); + + // ACER 連線設定 (正式環境 - 現場呼叫) + define('ACER_SERVICE_IP', '192.168.10.221'); + define('ACER_SERVICE_PORT', 8033); + + // 結果代碼 + define('ALTOB_RESULT_CODE_SUCCESS', 'OK'); // 成功 + define('ALTOB_RESULT_CODE_FAIL', 'GG'); // 失敗 + + // 錯誤碼 + define('ALTOB_ERROR_CODE_NONE', '0000'); // 預設值 (成功帶這個) + define('ALTOB_ERROR_CODE_UNKNOWN_INPUT', '1001'); // 未知的 輸入 + define('ALTOB_ERROR_CODE_UNKNOWN_CMD', '1002'); // 未知的 CMD + define('ALTOB_ERROR_CODE_NOT_FOUND', '1003'); // 查無記錄 + define('ALTOB_ERROR_CODE_ERROR', '1004'); // 交易失敗 + define('ALTOB_ERROR_CODE_UNDEFINED', '9999'); // 未定義的錯誤 + define('ALTOB_ERROR_CODE_ACER_RESULT_FAIL', '2001'); // ACER 回傳處理錯誤 + } + + // acer socket + function acer_socket($in) + { + trigger_error(__FUNCTION__ . "..socket input|{$in}"); + + $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); + if ($socket === false) { + trigger_error(__FUNCTION__ . "..socket_create() failed: reason: " . socket_strerror(socket_last_error())); + } + + $result = socket_connect($socket, ACER_SERVICE_IP, ACER_SERVICE_PORT); + if ($result === false) { + trigger_error(__FUNCTION__ . "..socket_connect() failed.\nReason: ({$result}) " . socket_strerror(socket_last_error($socket))); + return false; // 中斷 + } + + if(!socket_write($socket, $in, strlen($in))) + { + trigger_error(__FUNCTION__ . '..Write failed..'); + } + + $out = socket_read($socket, 64); + socket_shutdown($socket); + socket_close($socket); + trigger_error(__FUNCTION__ . "..socket output|{$out}"); + + return $out; + } + + public function init($vars) + { + $this->vars = $vars; + } + + // 票卡入場訊號,供 ALTOB 登記 + //(傳入:卡號、入場編號、是否月租卡; 回傳:結果代碼、入場編號、錯誤碼) + public function cmd_001($card_no, $cario_no, $card_type) + { + // 票號查詢最近一筆入場資料 + $rows_cario = $this->db + ->select('cario_no, lpr, in_time, pay_time, out_before_time') + ->from('cario') + ->where(array( + 'in_out' => 'CI', 'err' => 0, 'finished' => 0, + 'cario_no' => $cario_no, + 'in_time > DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 1 DAY)' => null)) + ->limit(1) + ->get() + ->row_array(); + + trigger_error(__FUNCTION__ . '..cario..' . print_r($rows_cario, true)); + + $cario_no = 0; // 進出碼 + $error_code = ALTOB_ERROR_CODE_NONE; // 錯誤碼 + + if (!empty($rows_cario['cario_no'])) + { + $cario_no = $rows_cario['cario_no']; + + // 更新入場資訊 + $this->db->where(array('cario_no' => $cario_no))->update('cario', array('remarks' => "{$card_no}")); + if (!$this->db->affected_rows()) + { + trigger_error(__FUNCTION__ . '..fail..' . $this->db->last_query()); + $error_code = ALTOB_ERROR_CODE_ERROR; + } + } + else + { + // 查無入場記錄 + $error_code = ALTOB_ERROR_CODE_NOT_FOUND; + } + + $data = array(); + $data['result_code'] = ALTOB_RESULT_CODE_SUCCESS; + $data['result']['cario_no'] = $cario_no; + $data['result']['error_code'] = $error_code; + return $data; + } + + // 票卡離場訊號,供 ALTOB 登記 + //(傳入:卡號、繳費時間、是否月租卡; 回傳:結果代碼、入場編號、錯誤碼) + public function cmd_002($card_no, $pay_time, $card_type) + { + // 卡號查詢最近一筆入場資料 + $rows_cario = $this->db + ->select('cario_no, lpr, in_time, pay_time, out_before_time') + ->from('cario') + ->where(array( + 'in_out' => 'CI', 'err' => 0, 'finished' => 0, + 'remarks' => $card_no, + 'in_time > DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 5 DAY)' => null)) + ->order_by('cario_no', 'desc') + ->limit(1) + ->get() + ->row_array(); + + trigger_error(__FUNCTION__ . '..cario..' . print_r($rows_cario, true)); + + $cario_no = 0; // 進出碼 + $error_code = ALTOB_ERROR_CODE_NONE; // 錯誤碼 + + if (!empty($rows_cario['cario_no'])) + { + $cario_no = $rows_cario['cario_no']; + + // 暫不處理 + } + else + { + // 查無入場記錄 + $error_code = ALTOB_ERROR_CODE_NOT_FOUND; + } + + $data = array(); + $data['result_code'] = ALTOB_RESULT_CODE_SUCCESS; + $data['result']['cario_no'] = $cario_no; + $data['result']['error_code'] = $error_code; + return $data; + } + + // 票號離場訊號,回傳若成功觸發 ACER 開門 + // (傳入:6 碼數字; 回傳:結果代碼、入場編號、錯誤碼、離場代碼) + public function cmd_003($ticket_no) + { + // 票號查詢最近一筆入場資料 (只能查 5天 內) + $rows_cario = $this->db + ->select('cario_no, payed, in_time, pay_time, out_before_time') + ->from('cario') + ->where(array( + 'ticket_no' => $ticket_no, 'err' => 0, + 'in_time > DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 5 DAY)' => null) + ) + ->order_by('cario_no', 'desc') + ->limit(1) + ->get() + ->row_array(); + + trigger_error(__FUNCTION__ . '..cario..' . print_r($rows_cario, true)); + + $cario_no = 0; // 進出碼 + $error_code = ALTOB_ERROR_CODE_NONE; // 錯誤碼 + $msg_code = 0; // 離場碼 + + if (!empty($rows_cario['cario_no'])) + { + $cario_no = $rows_cario['cario_no']; + + if(strtotime($rows_cario['out_before_time']) >= time()) + { + if ($rows_cario['payed']) + { + // CO.B.1 臨停車已付款 + $msg_code = 6; + } + else + { + // CO.B.2 臨停車未付款 + $msg_code = 8; + } + } + else + { + // CO.C.1 其它付款方式 + $msg_code = 9; + } + } + else + { + // CO.Z.Z 無入場資料 + $cario_no = 0; + $msg_code = 13; + } + + $data = array(); + $data['result_code'] = ALTOB_RESULT_CODE_SUCCESS; + $data['result']['cario_no'] = $cario_no; + $data['result']['error_code'] = $error_code; + $data['result']['msg_code'] = $msg_code; + return $data; + } + + // 呼叫 acer (cmd: 101) + // (傳入:入場編號、進場時間、 6 碼數字、車牌號碼、出入口編號; 回傳:結果代碼、入場編號、錯誤碼) + public function cmd_101($cario_no, $in_time, $ticket_no, $lpr, $ivs_no) + { + $seq = '00001'; + $cmd = '101'; + $cario_no_pad = str_pad($cario_no, 10, '0', STR_PAD_LEFT); // 入場編號: 10 碼 (左邊補 0) + $lpr_pad = str_pad($lpr, 10, '*', STR_PAD_LEFT); // 車牌號碼: 10 碼 (左邊補 *) + $ivs_no_pad = str_pad($ivs_no, 2, '0', STR_PAD_LEFT); // 車道編號: 2 碼 (左邊補 0) + + // 建立封包 + $packformat = "a10Ca19Ca6Ca10Ca2"; + $data = pack($packformat, + // Data:內容除分隔符號為0x1F,其他全為ASCII碼0x20 ~ 0x7F內 + $cario_no_pad, 0x1f, $in_time, 0x1f, $ticket_no, 0x1f, $lpr_pad, 0x1f, $ivs_no_pad + ); + $data_len = strlen($data); + $socket_len = $data_len + 16; + + $in = pack("Ca2Ca5Ca3C{$packformat}CCC", + 0x02, // STX:封包起始碼(0x02) + $socket_len, 0x1c, // 封包長度:從STX到ETX的位元數 + $seq, 0x1c, // 封包流水號:5碼ASCII數字(不足5碼時左補”0”補滿5碼) + $cmd, 0x1c, // CmdID:命令ID + + // Data:內容除分隔符號為0x1F,其他全為ASCII碼0x20 ~ 0x7F內 + $cario_no_pad, 0x1f, $in_time, 0x1f, $ticket_no, 0x1f, $lpr_pad, 0x1f, $ivs_no_pad, + + 0x1c, + 0x80, // CRC:封包檢查碼 + 0x03 // ETX:封包結束碼(0x03) + ); + + // 連線 + $out = $this->acer_socket($in); + + if(!empty($out)) + { + list($front, $seq, $cmd, $data) = explode(chr(28), $out); + list($result_code, $cario_no, $error_code) = explode(chr(31), $data); + trigger_error(__FUNCTION__ . "..socket return explode|{$front}, {$seq}, {$cmd}, {$result_code}, {$cario_no}, {$error_code}"); + + if(!empty($result_code) && ALTOB_RESULT_CODE_SUCCESS == $result_code) + { + $data = array(); + $data['result_code'] = ALTOB_RESULT_CODE_SUCCESS; + $data['result']['cario_no'] = $cario_no; + return $data; + } + } + + $data = array(); + $data['result_code'] = ALTOB_RESULT_CODE_FAIL; + $data['result']['error_code'] = ALTOB_ERROR_CODE_ACER_RESULT_FAIL; + return $data; + } + + // 呼叫 acer (cmd: 102) + // (傳入:入場編號、出入口編號、離場代碼; 回傳:結果代碼、入場編號、錯誤碼) + public function cmd_102($cario_no, $ivs_no, $msg_code) + { + $seq = '00001'; + $cmd = '102'; + + $cario_no_pad = str_pad($cario_no, 10, '0', STR_PAD_LEFT); // 入場編號: 10 碼 (左邊補 0) + $ivs_no_pad = str_pad($ivs_no, 2, '0', STR_PAD_LEFT); // 車道編號: 2 碼 (左邊補 0) + $msg_code_pad = str_pad($msg_code, 5, '0', STR_PAD_LEFT); // 離場代碼: 5 碼 (左邊補 0) + + // 建立封包 + $packformat = "a10Ca2Ca5"; + $data = pack($packformat, + // Data:內容除分隔符號為0x1F,其他全為ASCII碼0x20 ~ 0x7F內 + $cario_no_pad, 0x1f, $ivs_no_pad, 0x1f, $msg_code_pad + ); + $data_len = strlen($data); + $socket_len = $data_len + 16; + + $in = pack("Ca2Ca5Ca3C{$packformat}CCC", + 0x02, // STX:封包起始碼(0x02) + $socket_len, 0x1c, // 封包長度:從STX到ETX的位元數 + $seq, 0x1c, // 封包流水號:5碼ASCII數字(不足5碼時左補”0”補滿5碼) + $cmd, 0x1c, // CmdID:命令ID + + // Data:內容除分隔符號為0x1F,其他全為ASCII碼0x20 ~ 0x7F內 + $cario_no_pad, 0x1f, $ivs_no_pad, 0x1f, $msg_code_pad, + + 0x1c, + 0x80, // CRC:封包檢查碼 + 0x03 // ETX:封包結束碼(0x03) + ); + + // 連線 + $out = $this->acer_socket($in); + + if(!empty($out)) + { + list($front, $seq, $cmd, $data) = explode(chr(28), $out); + list($result_code, $cario_no, $error_code) = explode(chr(31), $data); + trigger_error(__FUNCTION__ . "..socket return explode|{$front}, {$seq}, {$cmd}, {$result_code}, {$cario_no}, {$error_code}"); + + if(!empty($result_code) && ALTOB_RESULT_CODE_SUCCESS == $result_code) + { + $data = array(); + $data['result_code'] = ALTOB_RESULT_CODE_SUCCESS; + $data['result']['cario_no'] = $cario_no; + return $data; + } + } + + $data = array(); + $data['result_code'] = ALTOB_RESULT_CODE_FAIL; + $data['result']['error_code'] = ALTOB_ERROR_CODE_ACER_RESULT_FAIL; + return $data; + } + + + +} diff --git a/models/Admins_model.php b/models/Admins_model.php new file mode 100644 index 0000000..4edbc38 --- /dev/null +++ b/models/Admins_model.php @@ -0,0 +1,896 @@ +load->database(); + + $this->now_str = date('Y-m-d H:i:s'); + $this->default_valid_time = date('Y-m-d H:i:s', strtotime("{$this->now_str} + 2 days")); // 2016/12/15 新增有效期限 (預設為兩天) + } + + public function init($vars) + { + $this->vars = $vars; + } + + // 付款 + public function login_verify($login_name, $login_pswd) + { + $rows = $this->db->select('count(*) as ok') + ->from('staffs') + ->where(array('login_name' => $login_name, 'pswd' => md5($login_pswd))) + ->get() + ->row_array(); + + return $rows['ok']; + } + + + // 讀出各初始值至web + public function get_init_vars() + { + $st_info = $this->vars['mcache']->get('st_info'); + // 路徑初始值 + $str = "var APP_URL = '". APP_URL . "';\n". + "var WEB_LIB = '" . WEB_LIB . "';\n". + "var BOOTSTRAPS = '" . BOOTSTRAPS . "';\n". + "var WEB_SERVICE = '" . WEB_SERVICE . "';\n". + "var station_no ={$st_info['station_no']};\n". + "var company_no = {$st_info['company_no']};\n". + "var xvars = new Array();\n". + "xvars['ck'] = 'NOLOGIN';\n"; + + // 讀出場站資訊 + $str .= "var st = new Array();\n"; + $str .= "st[" . STATION_NO . "]=\"" . STATION_NAME . "\";\n"; + /* + $results = $this->db->select('station_no, short_name') + ->from('stations') + ->order_by('station_no', 'asc') + ->get() + ->result_array(); + $str .= "var st = new Array();\n"; + foreach($results as $rows) + { + $str .= "st[{$rows['station_no']}]=\"{$rows['short_name']}\";\n"; + } + */ + + // 讀出時段表資訊 + $str .= "var pt = new Array();\n"; // park_time + foreach($this->vars['mcache']->get('pt') as $key => $rows) + { + $str .= "pt['{$key}']={'seqno':{$rows['seqno']},'remarks':'{$rows['remarks']}'};\n"; + } + + /* + // 讀取繳期名稱 + $rows = $this->db->select('period_name') + ->from('info') + ->where('seqno', 1) + ->get() + ->row_array(); + $str .= "var period_name=Array();\nperiod_name={$rows['period_name']};\n"; + */ + + + + // 篩選會員身份及繳期資訊 + $info = $this->vars['mcache']->get('info'); + + $str .= "var period_name=Array();\n"; + foreach($info['period_name'] as $idx => $rows) + { + $str .= "period_name[{$idx}]=\"{$rows}\";\n"; + } + + $str .= "var mem_attr = new Array();\n"; + foreach($info['member_attr'] as $idx => $rows) + { + $str .= "mem_attr[{$idx}]=\"{$rows}\";\n"; + } + return $str; + } + + /* + // 停車時段資訊 + public function park_time() + { + $data = array(); + $idx = 0; + // $results = $this->db->select('time_id, seqno, park_type, week_start, week_end, daytime_start, daytime_end, remarks') + $results = $this->db->select('time_id, seqno, timex, remarks') + ->from('park_time') + ->order_by('seqno', 'asc') + ->get() + ->result_array(); + foreach($results as $rows) + { + $data[$idx] = array + ( + 'time_id' => $rows['time_id'], + 'seqno' => $rows['time_id'], + 'remarks' => $rows['remarks'] + ); + ++$idx; + } + return $results; + } + + + // 停車時段資訊單筆刪除 + public function park_time_delete($time_id) + { + $this->db->delete('park_time', array('time_id' => $time_id)); + + return true; + } + */ + + // 會員清單 + public function member_query_all() + { + $sql = " + SELECT + MIN(CONCAT(member_tx.tx_no, member_tx.verify_state)) as tx_order, + members.member_no, + members.lpr, + members.etag, + members.member_name, + members.mobile_no, + members.start_date, + members.end_date, + members.fee_period, + members.member_attr, + members.suspended, + members.contract_no, + members.amt, + member_tx.tx_no, + member_tx.verify_state, + member_tx.valid_time, + member_tx.remarks + FROM member_tx + LEFT JOIN members ON member_tx.member_no = members.member_no + WHERE + members.member_no IS NOT NULL + GROUP BY member_tx.member_no + ORDER BY members.lpr ASC + "; + $results = $this->db->query($sql)->result_array(); + return $results; + } + + // 待審核清單 + public function member_tx_check() + { + $sql = " + SELECT + members.lpr as current_lpr, + member_tx.lpr, + member_tx.tx_no, + member_tx.station_no, + member_tx.member_no, + member_tx.fee_period, + member_tx.fee_period_last, + member_tx.amt1, + member_tx.amt, + member_tx.amt_last, + member_tx.deposit, + date_format(member_tx.start_date,'%Y-%m-%d') as start_date, + date_format(member_tx.end_date,'%Y-%m-%d') as end_date, + date_format(member_tx.start_date_last,'%Y-%m-%d') as start_date_last, + date_format(member_tx.end_date_last,'%Y-%m-%d') as end_date_last, + member_tx.member_company_no, + member_tx.company_no, + member_tx.acc_date, + member_tx.invoice_no, + member_tx.invoice_amt, + member_tx.invoice_track, + member_tx.invoice_time, + member_tx.invoice_type, + member_tx.verify_state, + member_tx.valid_time, + member_tx.remarks + FROM member_tx + LEFT JOIN members ON (member_tx.member_no = members.member_no AND members.station_no = member_tx.station_no) + WHERE member_tx.verify_state != 1 + ORDER BY member_tx.valid_time ASC + "; + + $results = $this->db->query($sql)->result_array(); + return $results; + } + + // 會員查詢 + public function member_query($station_no, $q_item, $q_str) + { + $where_station = $station_no == 0 ? '' : " station_no = {$station_no} and "; // 如為0, 則全部塲站讀取 + + switch($q_item) + { + case 'end_date': + $items = "{$q_item} <="; + $q_str .= ' 23:59:59'; + break; + case 'lpr': + $items = "{$q_item} like "; + $q_str = strtoupper($q_str).'%'; + break; + default: + $items = "{$q_item} like "; + $q_str .= '%'; + break; + } + + $sql = "select + station_no, + member_no, + lpr, + member_name, + mobile_no, + date_format(demonth_start_date,'%Y-%m-%d') as demonth_start_date, + date_format(demonth_end_date,'%Y-%m-%d') as demonth_end_date, + date_format(start_date,'%Y-%m-%d') as start_date, + date_format(end_date,'%Y-%m-%d') as end_date, + date_format(rent_start_date,'%Y-%m-%d') as rent_start_date, + contract_no, + coalesce(etag, '') as etag, + fee_period1, + fee_period, + amt1, + amt, + if(member_company_no > 0, member_company_no, '') as member_company_no, + if(company_no > 0, company_no, '') as company_no, + coalesce(member_attr, 1) as member_attr, + deposit, + park_time, + coalesce(member_id, '') as member_id, + coalesce(tel_o, '') as tel_o, + coalesce(tel_h, '') as tel_h, + coalesce(addr, '') as addr, + suspended + from members + where {$where_station} {$items} '{$q_str}'"; + + $results = $this->db->query($sql)->result_array(); + + return $results; + } + + // 交易查詢 + public function member_tx_query($station_no, $member_no) + { + $sql = "select + tx_no, station_no, + member_no, + lpr, + fee_period, + fee_period_last, + amt1, + amt, + amt_last, + deposit, + date_format(start_date,'%Y-%m-%d') as start_date, + date_format(end_date,'%Y-%m-%d') as end_date, + date_format(start_date_last,'%Y-%m-%d') as start_date_last, + date_format(end_date_last,'%Y-%m-%d') as end_date_last, + member_company_no, + company_no, + acc_date, + invoice_no, + invoice_amt, + invoice_track, + invoice_time, + invoice_type, + verify_state, + valid_time, + remarks + from member_tx + where station_no = {$station_no} and member_no = {$member_no} + order by tx_no desc"; + + $results = $this->db->query($sql)->result_array(); + + return $results; + } + + // 審核完成 + public function member_tx_confirmed($parms) + { + $this->try_sync_batch($parms['station_no']); // 同步未同步記錄 + + $altob_admin_submit = $this->input->post('altob_admin_submit', true); // 取得 admin 參數 + if($altob_admin_submit !== $this->gen_admin_ck($parms['station_no'])) + { + trigger_error(__FUNCTION__ . '..altob_admin_submit error..' . print_r($parms, true)); + return 'admin_error'; // 中斷 + } + + $data_tx = array('verify_state' => $parms['verify_state'], 'valid_time' => $parms['valid_time'], 'remarks' => $parms['remarks']); + + // [A.開始] + $this->db->trans_start(); + $this->db->update('member_tx', $data_tx, array('station_no' => $parms['station_no'], 'tx_no' => $parms['tx_no'])); // t1. 更新 member_tx.verify_state, member_tx.valid_time, member_tx.remarks + // [B.建立同步檔] + $sync_seqnos = $this->prepare_sync2hq('U', $parms['station_no'], 'member_tx', $parms['tx_no'], $data_tx); // t2. 準備同步檔 (member_tx) + // [C.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(__FUNCTION__ . '|'.print_r($data_tx, true) . '..trans_error..'); + return 'fail'; // 中斷 + } + + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + return 'ok'; + } + + + // 刪除月租會員 + public function member_delete($station_no, $member_no) + { + $this->try_sync_batch($station_no); // 同步未同步記錄 + + // [A.開始] + $this->db->trans_start(); + $this->db->delete('members', array('station_no' => $station_no, 'member_no' => $member_no, 'suspended' => 0)); // t1. 刪除 members + $this->db->delete('member_car', array('station_no' => $station_no, 'member_no' => $member_no)); // t2. 刪除 member_car + // [B.建立同步檔] + $sync_seqnos = $this->prepare_sync2hq('D', $station_no, 'members', $member_no, array()); // t3. 準備同步檔 (members) + // [C.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(__FUNCTION__ . ": {$station_no}, {$member_no}, trans_error.."); + return 'trans_error'; + } + + // 同步至總管理處 + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + return 'ok'; + } + + // 月租會員加入 + public function member_add($data) + { + $data['lpr'] = preg_replace('/\s+/', '', $data['lpr']); // 移除空白 + + $check_member_no = $data['member_no']; + $station_no = $data['station_no']; + $tx_no = 0; + + $this->try_sync_batch($station_no); // 同步未同步記錄 + + // 會員車輛基本資料檔 + $start_date = (empty($data['demonth_start_date']) ? $data['start_date'] : $data['demonth_start_date']); + $data['rent_start_date'] = $data['start_date']; + $data['rent_end_date'] = $data['end_date']; + $data['start_date'] = "{$start_date} 00:00:00"; + $data['end_date'] = "{$data['end_date']} 23:59:59"; + $old_lpr = $data['old_lpr']; + unset($data['old_lpr']); + $data_car = array + ( + 'lpr' => $data['lpr'], + 'lpr_correct' => $data['lpr'], + 'etag' => $data['etag'], + 'station_no' => $station_no, + 'start_time' => $data['start_date'], + 'end_time' => $data['end_date'] + ); + + if ($check_member_no == 0) // 新增一筆會員資料 + { + unset($data['member_no']); + $data['payed_date'] = substr($this->now_str, 0, 10); + $data['login_id'] = $data['lpr']; + $data['passwd'] = $data['lpr']; + $action_code = 'A'; + + // [A.開始] + $this->db->trans_start(); + $this->db->insert('members', $data); // t1 新增 members + $members_insert_id = $this->db->insert_id(); + $data_car['member_no'] = $members_insert_id; // t2. 新增 member_car + $this->db->insert('member_car', $data_car); + $data['member_no'] = $members_insert_id; + $data_bill = array( + 'member_no' => $members_insert_id, // 會員編號 + 'station_no' => $station_no, // 場站編號 + + 'lpr' => $data['lpr'], // 車牌號碼 + + 'amt_accrued' => $data['amt_accrued'], // 應收租金 + 'amt_tot' => $data['amt_tot'], // 實收租金 + 'deposit' => $data['deposit'], // 押金 + + 'amt' => $data['amt'], // 本期租金 + 'fee_period' => $data['fee_period'], // 本期繳期 + 'start_date' => $data['rent_start_date'], // 本期開始日 + 'end_date' => $data['rent_end_date'], // 本期結束日 + + 'amt1' => $data['amt1'], // 首期租金 + 'amt_last' => $data['amt1'], // 上期租金 + 'fee_period_last' => $data['fee_period1'], // 上期繳期 + 'start_date_last' => $data['demonth_start_date'], // 上期開始日 + 'end_date_last' => $data['demonth_end_date'] // 上期結束日 + ); + $this->db->insert('member_bill', $data_bill); // t3 新增 member_bill + $bill_no = $this->db->insert_id(); // 帳單序號 + $data_tx = array( + 'bill_no' => $bill_no, // 帳單序號 + 'member_no' => $members_insert_id, // 會員編號 + 'station_no' => $station_no, // 場站編號 + 'sync_no' => 0, // 預設同步編號 + 'lpr' => $data['lpr'], // 車牌號碼 + + 'amt_accrued' => $data['amt_accrued'], // 應收租金 + 'amt_tot' => $data['amt_tot'], // 實收租金 + 'deposit' => $data['deposit'], // 押金 + + 'amt' => $data['amt'], // 本期租金 + + // todo: 2016/12/23 只要超過季繳金額就拆開, 後續再由待開發票開立 + + 'fee_period' => $data['fee_period'], // 本期繳期 + 'start_date' => $data['rent_start_date'], // 本期開始日 + 'end_date' => $data['rent_end_date'], // 本期結束日 + + 'amt1' => $data['amt1'], // 首期租金 + 'amt_last' => $data['amt1'], // 上期租金 + 'fee_period_last' => $data['fee_period1'], // 上期繳期 + 'start_date_last' => $data['demonth_start_date'], // 上期開始日 + 'end_date_last' => $data['demonth_end_date'], // 上期結束日 + + 'member_company_no' => $data['member_company_no'], // 買方統編 + 'company_no' => $data['company_no'], // 賣方統編 + + 'acc_date' => $data['payed_date'], // 入帳日(暫定) + + 'valid_time' => $this->default_valid_time // 有效期限 + ); + $this->db->insert('member_tx', $data_tx); // t4 新增 member_tx + $tx_no = $this->db->insert_id(); // 交易序號 + $data_tx['tx_no'] = $tx_no; + + // [B.建立同步檔] + $sync_seqnos = $this->prepare_sync2hq($action_code, $station_no, 'members', $members_insert_id, $data); // t5 準備同步檔 (members) + $sync_seqnos .= ',' . $this->prepare_sync2hq($action_code, $station_no, 'member_bill', $bill_no, $data_bill); // t6 準備同步檔 (member_bill) + $sync_seqnos .= ',' . $this->prepare_sync2hq($action_code, $station_no, 'member_tx', $tx_no, $data_tx); // t7 準備同步檔 (member_tx) + + // [C.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(__FUNCTION__ . '..trans_error..' . print_r($data, true)); + return 'trans_error'; + } + + // 同步至總管理處 + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + } + else + { + $altob_admin_submit = $this->input->post('altob_admin_submit', true); // 取得 admin 參數 + if($altob_admin_submit == $this->gen_admin_ck($station_no)) + { + trigger_error("admin: " + $altob_admin_submit); + //unset($data['contract_no']); // 合約號 + //unset($data['park_time']); // 停車時段 + unset($data['rent_start_date']); + unset($data['rent_end_date']); + unset($data['start_date']); + unset($data['end_date']); + unset($data['demonth_start_date']); + unset($data['demonth_end_date']); + unset($data['member_attr']); + unset($data['deposit']); + unset($data['amt_tot']); + unset($data['amt_accrued']); + unset($data['fee_period1']); + unset($data['amt1']); + //unset($data['fee_period']); // 例行繳期 + //unset($data['amt']); // 例行租金 + } + else + { + // 一般情況下, 時段與費率都不能在這個流程修改 + //unset($data['contract_no']); // 合約號 + unset($data['park_time']); + unset($data['rent_start_date']); + unset($data['rent_end_date']); + unset($data['start_date']); + unset($data['end_date']); + unset($data['demonth_start_date']); + unset($data['demonth_end_date']); + unset($data['member_attr']); + unset($data['deposit']); + unset($data['amt_tot']); + unset($data['amt_accrued']); + unset($data['fee_period1']); + unset($data['amt1']); + unset($data['fee_period']); + unset($data['amt']); + } + $action_code = 'U'; + + // [A.開始] + $this->db->trans_start(); + $this->db->update('members', $data, array('station_no' => $station_no, 'member_no' => $check_member_no)); // t1. 更新 members + + // 沒有異動到車牌, 使用update, 否則重建一筆 + if ($old_lpr == $data['lpr']) // t2. 更新 member_car + { + unset($data_car['lpr']); + unset($data_car['lpr_correct']); + $this->db->update('member_car', $data_car, array('station_no' => $station_no, 'member_no' => $check_member_no)); + } + else + { + $this->db->delete('member_car', array('station_no' => $station_no, 'member_no' => $check_member_no)); + $data_car['member_no'] = $check_member_no; + $this->db->insert('member_car', $data_car); + } + + // [B.建立同步檔] + $sync_seqnos = $this->prepare_sync2hq($action_code, $station_no, 'members', $check_member_no, $data); // t3. 準備同步檔 (members) + + // [C.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(__FUNCTION__ . '..trans_error..' . print_r($data, true)); + return 'trans_error'; + } + + // 同步至總管理處 + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + } + + return array( + 'station_no' => $station_no, + 'company_no' => $data['company_no'], + 'member_no' => $data['member_no'], + 'start_date' => $start_date, + 'msg' => 'ok', + 'action_code' => $action_code, + 'tx_no' => $tx_no); + } + + + // 查詢車牌是否重複 + public function check_lpr($lpr) + { + $rows = $this->db->select('count(*) as counts') + ->from('members') + ->where(array('lpr' => $lpr)) + ->get() + ->row_array(); + + return $rows['counts']; + } + + // 取得交易發票 + public function get_tx_invoice_no($tx_no) + { + $rows = $this->db->select('invoice_no') + ->from('member_tx') + ->where(array('tx_no' => $tx_no)) + ->get() + ->row_array(); + + return $rows['invoice_no']; + } + + // 更新月租發票記錄 + public function set_tx_invoice_no($parms) + { + $data = array + ( + 'member_company_no' => $parms['member_company_no'], + 'company_no' => $parms['company_no'], + 'invoice_track' => $parms['invoice_track'], + 'invoice_no' => $parms['invoice_no'], + 'invoice_amt' => $parms['invoice_amt'], + 'invoice_time' => $parms['invoice_time'] + ); + + if(array_key_exists('invoice_type', $parms)) + { + $data['invoice_type'] = $parms['invoice_type']; // 發票種類 + } + + // [A.開始] + $this->db->trans_start(); + $this->db->update('member_tx', $data, array('station_no' => $parms['station_no'], 'tx_no' => $parms['tx_no'])); // t1. 更新 member_tx + // [B.建立同步檔] + $sync_seqnos = $this->prepare_sync2hq('U', $parms['station_no'], 'member_tx', $parms['tx_no'], $data); // t2. 準備同步檔 + // [C.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(__FUNCTION__ . '|'.print_r($data, true) . '..trans_error..'); + return 'fail'; // 中斷 + } + + // 同步至總管理處 + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + return 'ok'; + } + + // 首期月租付款交易 + public function first_rents_payment($parms) + { + $this->try_sync_batch($parms['station_no']); // 同步未同步記錄 + + // 確認交易記錄 + $rows = $this->db->select('count(*) as counts') + ->from('member_tx') + ->where(array('tx_no' => $parms['tx_no'], + 'station_no' => $parms['station_no'], 'member_no' => $parms['member_no'], + 'amt' => $parms['amt'], 'amt1' => $parms['amt1'])) + ->get() + ->row_array(); + + if(empty($rows) || $rows['counts'] != 1) + { + trigger_error(__FUNCTION__ . '..tx gg..' . print_r($parms, true)); + return 'tx_error'; // 中斷 + } + + // 印發票 + $parms['invoice_amt'] = $parms['amt'] + $parms['amt1']; // 例行租金 + 首期租金 + + if(array_key_exists('invoice_track', $parms) && array_key_exists('invoice_no', $parms)) + { + $parms['invoice_time'] = date('Y-m-d H:i:s'); // 目前時間 + } + else + { + $invoice_result = $this->print_invoice($parms); + if(!empty($invoice_result) && array_key_exists('einvoice_no', $invoice_result)) + { + $parms['invoice_track'] = $invoice_result['einvoice_track']; // 發票字軌 + $parms['invoice_no'] = $invoice_result['einvoice_no']; // 發票號碼 + $parms['invoice_time'] = date('Y-m-d H:i:s'); // 目前時間 + } + } + + + if(empty($parms['invoice_no']) || empty($parms['invoice_track'])) + { + trigger_error(__FUNCTION__ . '..invoice gg..' . print_r($parms, true)); + return 'invoice_fail'; // 中斷 + } + + // 更新月租發票記錄 + echo $this->set_tx_invoice_no($parms); + } + + // 新增月租付款交易 + public function rents_payment($parms) + { + $this->try_sync_batch($parms['station_no']); // 同步未同步記錄 + + //$parms['start_date'] = $parms['start_date_last']; + + // 印發票 + $parms['invoice_amt'] = $parms['amt']; // 例行租金 + if(array_key_exists('invoice_track', $parms) && array_key_exists('invoice_no', $parms)) + { + $parms['invoice_time'] = date('Y-m-d H:i:s'); // 目前時間 + } + else + { + $invoice_result = $this->print_invoice($parms); + if(!empty($invoice_result) && array_key_exists('einvoice_no', $invoice_result)) + { + $parms['invoice_track'] = $invoice_result['einvoice_track']; // 發票字軌 + $parms['invoice_no'] = $invoice_result['einvoice_no']; // 發票號碼 + $parms['invoice_time'] = date('Y-m-d H:i:s'); // 目前時間 + } + + if(empty($parms['invoice_no']) || empty($parms['invoice_track'])) + { + trigger_error(__FUNCTION__ . '..invoice gg..' . print_r($parms, true)); + //return 'invoice_fail'; + } + } + $parms['sync_no'] = 0; // 預設同步編號 + $parms['fee_period_last'] = $parms['fee_period']; // 上期繳期 + $parms['start_date'] = date('Y-m-d', strtotime("{$parms['end_date_last']} first day of next month")); // 本期開始日:上期結束日之次月首日 + $parms['acc_date'] = date('Y-m-d'); // 入帳日(暫定) + $parms['valid_time'] = $this->default_valid_time; // 有效期限 + + // [A.開始] + $this->db->trans_start(); + $this->db->insert('member_tx', $parms); // t1. 新增 member_tx + $tx_no = $this->db->insert_id(); // 交易序號 + $data = $parms; + $data['tx_no'] = $tx_no; + $data_member = array( + 'fee_period' => $parms['fee_period'], + 'payed_date' => substr($parms['invoice_time'], 0, 10), + 'start_date' => "{$parms['start_date_last']} 00:00:00", // 開始日:由上期繼續延續下去 + 'end_date' => "{$parms['end_date']} 23:59:59" // 結束日 + ); + $this->db->update('members', $data_member, array('station_no' => $parms['station_no'], 'member_no' => $parms['member_no'])); // t2. 更新 members + $this->db->update('member_car', // t5. 更新 member_car + array('start_time' => "{$data_member['start_date']} 00:00:00", 'end_time' => "{$data_member['end_date']} 23:59:59"), + array('station_no' => $parms['station_no'], 'member_no' => $parms['member_no'])); + + // [B.準備同步檔] + $sync_seqnos = $this->prepare_sync2hq('A', $parms['station_no'], 'member_tx', $tx_no, $data); // t2. 準備同步檔 + $sync_seqnos .= ',' . $this->prepare_sync2hq('U', $parms['station_no'], 'members', $parms['member_no'], $data_member); // t4. 準備同步檔 + + // [c.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(__FUNCTION__ . '|'.print_r($data, true) . '..trans_error..'); + return 'fail'; // 中斷 + } + + // 同步至總管理處 + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + return 'ok'; + } + + // 停權或啟動 + public function suspended($parms) + { + $this->try_sync_batch($parms['station_no']); // 同步未同步記錄 + + $altob_admin_submit = $this->input->post('altob_admin_submit', true); // 取得 admin 參數 + if($altob_admin_submit !== $this->gen_admin_ck($parms['station_no'])) + { + trigger_error(__FUNCTION__ . '..altob_admin_submit error..' . print_r($parms, true)); + return 'admin_error'; // 中斷 + } + + $data = array('suspended' => $parms['suspended']); + + // [A.開始] + $this->db->trans_start(); + $this->db->update('members', $data, array('station_no' => $parms['station_no'], 'member_no' => $parms['member_no'])); // t1. 更新 member.suspended + // [B.準備同步檔] + $sync_seqnos = $this->prepare_sync2hq('U', $parms['station_no'], 'members', $parms['member_no'], $data); // t2. 準備同步檔 + // [C.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(__FUNCTION__ . '|'.print_r($data, true) . '..trans_error..'); + return 'fail'; // 中斷 + } + + // 同步至總管理處 + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + return 'ok'; + } + + // 同步未同步記錄 + public function try_sync_batch($station_no, $limit=5) + { + $sql = "select st_sync_no + from syncs + where synced = 0 and erred = 0 and station_no = {$station_no} + order by st_sync_no ASC + limit {$limit}"; + $results = $this->db->query($sql)->result_array(); + + if(empty($results)) return false; // do nothing + + $sync_seqnos = ''; + foreach($results as $rows) + { + $sync_seqnos .= ',' . $rows['st_sync_no']; + } + $sync_seqnos = ltrim($sync_seqnos, ','); + trigger_error(__FUNCTION__ . '|' . $sync_seqnos); + + // 同步至總管理處 + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + } + + // 同步至總公司 + function prepare_sync2hq($act, $station_no, $st_tname, $st_seqno, $data) + { + $data_syncs = array + ( + 'station_no' => $station_no, + 'synced' => 0, // 尚未同步 + 'erred' => 0, + 'act' => $act, // A:新增, U:修改, D:刪除 + 'hq_tname' => 'hq_'.$st_tname, + 'st_tname' => $st_tname, // 場站資料表 + 'st_seqno' => $st_seqno, // 場站交易序號 + 'sync_data' => json_encode($data, JSON_UNESCAPED_UNICODE) + ); + $this->db->insert('syncs', $data_syncs); + return $this->db->insert_id(); + } + + // curl送收資料 + function worker_tx($cmd, $data) + { + try + { + $ch = curl_init(); + $curl_options = array + ( + CURLOPT_URL => "http://localhost:60133/?cmd={$cmd}", + CURLOPT_HEADER => 0, + CURLOPT_RETURNTRANSFER => 1, // 返回值不顯示, 只做變數用 + CURLOPT_POST => 1, + CURLOPT_POSTFIELDS => $data + ); + curl_setopt_array($ch, $curl_options); + curl_exec($ch); + curl_close($ch); + } + catch (Exception $e) + { + trigger_error("{$cmd} error: ".$e->getMessage()); + } + } + + // 管理員參數 + function gen_admin_ck($station_no) + { + return md5(date("m \a\l\t\o\b d").$station_no.date("i \z\z\z H")); + } + + // 印發票 + public function print_invoice($parms) + { + $result = array(); + try + { + // 印發票 + $ch = curl_init(); + $curl_options = array + ( + CURLOPT_URL => "http://localhost:60134/", + CURLOPT_HEADER => 0, + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_CONNECTTIMEOUT => 2, + CURLOPT_TIMEOUT => 2, + CURLOPT_POST => 1, + CURLOPT_POSTFIELDS => array( + 'cmd' => 'printInvoice', + 'company_no' => $parms['company_no'], + 'vCUS_COMP_CODE'=> $parms['member_company_no'], + 'vAmount' => $parms['invoice_amt'], + 'vPLU_MEMO' => 'parking:50:3', + 'vTAIL_MESSAGE' => 'Rental' + ) + ); + curl_setopt_array($ch, $curl_options); + $ch_response = curl_exec($ch); + + trigger_error(__FUNCTION__ . '|' . print_r($ch_response, true)); + + curl_close($ch); + + $result = json_decode($ch_response, true); + } + catch (Exception $e) + { + trigger_error(__FUNCTION__ .$e->getMessage()); + } + + //測試用 + //$result['einvoice_track'] = 'AB'; // 發票字軌 + //$result['einvoice_no'] = '12345678'; // 發票號碼 + + return $result; + } +} diff --git a/models/Admins_station_model.php b/models/Admins_station_model.php new file mode 100644 index 0000000..7586653 --- /dev/null +++ b/models/Admins_station_model.php @@ -0,0 +1,3041 @@ +load->database(); + + $this->now_str = date('Y-m-d H:i:s'); + $this->default_valid_time = date('Y-m-d H:i:s', strtotime("{$this->now_str} + 2 days")); // 2016/12/15 新增有效期限 (預設為兩天) + } + + public function init($vars) + { + $this->vars = $vars; + } + + // 付款 + public function login_verify($login_name, $login_pswd) + { + $rows = $this->db->select('count(*) as ok') + ->from('staffs') + ->where(array('login_name' => $login_name, 'pswd' => md5($login_pswd))) + ->get() + ->row_array(); + + return $rows['ok']; + } + + + // 讀出各初始值至web + public function get_init_vars() + { + $st_info = $this->vars['mcache']->get('st_info'); + // 路徑初始值 + $str = "var APP_URL = '". APP_URL . "';\n". + "var WEB_LIB = '" . WEB_LIB . "';\n". + "var BOOTSTRAPS = '" . BOOTSTRAPS . "';\n". + "var WEB_SERVICE = '" . WEB_SERVICE . "';\n". + "var station_no ={$st_info['station_no']};\n". + "var company_no = {$st_info['company_no']};\n". + "var xvars = new Array();\n". + "xvars['ck'] = 'NOLOGIN';\n"; + + // 讀出場站資訊 + $str .= "var st = new Array();\n"; + $str .= "st[" . STATION_NO . "]=\"" . STATION_NAME . "\";\n"; + /* + $results = $this->db->select('station_no, short_name') + ->from('stations') + ->order_by('station_no', 'asc') + ->get() + ->result_array(); + $str .= "var st = new Array();\n"; + foreach($results as $rows) + { + $str .= "st[{$rows['station_no']}]=\"{$rows['short_name']}\";\n"; + } + */ + + // 讀出時段表資訊 + $str .= "var pt = new Array();\n"; // park_time + foreach($this->vars['mcache']->get('pt') as $key => $rows) + { + $str .= "pt['{$key}']={'seqno':{$rows['seqno']},'remarks':'{$rows['remarks']}'};\n"; + } + + /* + // 讀取繳期名稱 + $rows = $this->db->select('period_name') + ->from('info') + ->where('seqno', 1) + ->get() + ->row_array(); + $str .= "var period_name=Array();\nperiod_name={$rows['period_name']};\n"; + */ + + + + // 篩選會員身份及繳期資訊 + $info = $this->vars['mcache']->get('info'); + + $str .= "var period_name=Array();\n"; + foreach($info['period_name'] as $idx => $rows) + { + $str .= "period_name[{$idx}]=\"{$rows}\";\n"; + } + + $str .= "var mem_attr = new Array();\n"; + foreach($info['member_attr'] as $idx => $rows) + { + $str .= "mem_attr[{$idx}]=\"{$rows}\";\n"; + } + return $str; + } + + // 取得停車時段資訊 + public function get_parktime_str() + { + return $this->vars['mcache']->get('pt'); + } + + /* + // 停車時段資訊 + public function park_time() + { + $data = array(); + $idx = 0; + // $results = $this->db->select('time_id, seqno, park_type, week_start, week_end, daytime_start, daytime_end, remarks') + $results = $this->db->select('time_id, seqno, timex, remarks') + ->from('park_time') + ->order_by('seqno', 'asc') + ->get() + ->result_array(); + foreach($results as $rows) + { + $data[$idx] = array + ( + 'time_id' => $rows['time_id'], + 'seqno' => $rows['time_id'], + 'remarks' => $rows['remarks'] + ); + ++$idx; + } + return $results; + } + + + // 停車時段資訊單筆刪除 + public function park_time_delete($time_id) + { + $this->db->delete('park_time', array('time_id' => $time_id)); + + return true; + } + */ + + // 會員清單 + public function member_query_all() + { + $sql = " + SELECT + members.member_no, + members.lpr, + members.etag, + members.member_name, + members.mobile_no, + members.start_date, + members.end_date, + members.fee_period, + members.member_attr, + members.suspended, + members.contract_no, + members.amt, + COALESCE(members.valid_time, members.end_date) as valid_time + FROM members + ORDER BY members.member_no DESC + "; + $results = $this->db->query($sql)->result_array(); + return $results; + } + + // 待審核清單 + public function member_tx_check_query() + { + $sql = " + SELECT + members.lpr as current_lpr, + member_tx.lpr, + member_tx.tx_no, + member_tx.station_no, + member_tx.member_no, + member_tx.fee_period, + member_tx.fee_period_last, + member_tx.amt1, + member_tx.amt, + member_tx.amt_last, + member_tx.deposit, + date_format(member_tx.start_date,'%Y-%m-%d') as start_date, + date_format(member_tx.end_date,'%Y-%m-%d') as end_date, + date_format(member_tx.start_date_last,'%Y-%m-%d') as start_date_last, + date_format(member_tx.end_date_last,'%Y-%m-%d') as end_date_last, + member_tx.member_company_no, + member_tx.company_no, + member_tx.acc_date, + member_tx.invoice_no, + member_tx.invoice_amt, + member_tx.invoice_track, + member_tx.invoice_time, + member_tx.invoice_type, + member_tx.verify_state, + member_tx.valid_time, + member_tx.remarks, + member_tx.tx_state + FROM member_tx + LEFT JOIN members ON (member_tx.member_no = members.member_no AND members.station_no = member_tx.station_no) + WHERE + member_tx.verify_state in (0, 99) and members.member_no is not null + + and member_tx.valid_time > 0 -- 20170131 added + + ORDER BY member_tx.valid_time ASC + "; + + $results = $this->db->query($sql)->result_array(); + return $results; + } + + // 已退租交易清單 + public function member_tx_refund_query($station_no, $q_item, $q_str) + { + $where_station = $station_no == 0 ? '' : " member_refund.station_no = {$station_no} and "; // 如為0, 則全部場站讀取 + + switch($q_item) + { + case 'lpr': + $items = "member_log.{$q_item} like "; + $q_str = strtoupper($q_str).'%'; + break; + default: + $items = "member_log.{$q_item} like "; + $q_str .= '%'; + break; + } + + $sql = " + SELECT + member_refund.member_refund_id, + member_refund.station_no, + member_refund.member_no, + member_log.lpr, + member_log.member_name, + member_log.company_no, + member_log.member_company_no, + member_refund.refund_amt, + member_refund.refund_deposit, + member_refund.refund_tot_amt, + member_refund.refund_time, + member_refund.refund_state, + member_refund.create_time, + member_refund.dismiss_state + + FROM member_refund + LEFT JOIN member_log ON ( member_log.member_log_id = member_refund.member_log_id and member_log.station_no = member_refund.station_no ) + + WHERE {$where_station} {$items} '{$q_str}' + ORDER BY member_refund.create_time DESC + "; + + //trigger_error("test: {$sql}"); + + $results = $this->db->query($sql)->result_array(); + return $results; + } + + // 取得轉租資訊 + public function member_refund_transfer_data_query($station_no, $member_no, $member_refund_id) + { + $rows = $this->db->select(' + member_log.member_id, + member_log.member_no, + member_log.member_name, + member_log.member_nick_name, + member_log.member_attr, + member_log.fee_period, + member_log.contract_no, + member_log.lpr, + member_log.etag, + member_log.member_company_no, + member_log.mobile_no, + member_log.tel_o, + member_log.tel_h, + member_log.addr, + member_log.park_time, + member_refund.refund_deposit, + member_refund.refund_amt, + member_refund.refund_state, + member_refund.dismiss_state, + member_refund.refund_time + ') + ->from('member_refund') + ->join('member_log', 'member_log.member_log_id = member_refund.member_log_id', 'left') + ->where(array( + 'member_refund.member_refund_id' => $member_refund_id, + 'member_refund.station_no' => $station_no, + 'member_refund.member_no' => $member_no + )) + ->get() + ->row_array(); + + $data = array(); + if(empty($rows) || empty($rows['member_no'])) + { + $data['result_code'] = 'NOT_FOUND'; + } + else + { + $data['result_code'] = 'OK'; + $data['result'] = $rows; + } + return $data; + } + + // 會員查詢 + public function member_query($station_no, $q_item, $q_str) + { + $where_station = $station_no == 0 ? '' : " station_no = {$station_no} and "; // 如為0, 則全部場站讀取 + + switch($q_item) + { + case 'end_date': + $items = "{$q_item} <="; + $q_str .= ' 23:59:59'; + break; + case 'lpr': + $items = "{$q_item} like "; + $q_str = strtoupper($q_str).'%'; + break; + default: + $items = "{$q_item} like "; + $q_str .= '%'; + break; + } + + $sql = "select + station_no, + member_no, + lpr, + member_name, + mobile_no, + date_format(demonth_start_date,'%Y-%m-%d') as demonth_start_date, + date_format(demonth_end_date,'%Y-%m-%d') as demonth_end_date, + date_format(start_date,'%Y-%m-%d') as start_date, + date_format(end_date,'%Y-%m-%d') as end_date, + date_format(rent_start_date,'%Y-%m-%d') as rent_start_date, + contract_no, + coalesce(etag, '') as etag, + fee_period1, + fee_period, + amt1, + amt, + if(member_company_no > 0, member_company_no, '') as member_company_no, + if(company_no > 0, company_no, '') as company_no, + coalesce(member_attr, 1) as member_attr, + deposit, + park_time, + coalesce(member_id, '') as member_id, + coalesce(tel_o, '') as tel_o, + coalesce(tel_h, '') as tel_h, + coalesce(addr, '') as addr, + suspended + from members + where {$where_station} {$items} '{$q_str}'"; + + $results = $this->db->query($sql)->result_array(); + + return $results; + } + + // 交易查詢 + public function member_tx_query($station_no, $member_no) + { + $sql = "select + tx_no, station_no, + member_no, + lpr, + fee_period, + fee_period_last, + amt1, + amt, + amt_last, + deposit, + date_format(start_date,'%Y-%m-%d') as start_date, + date_format(end_date,'%Y-%m-%d') as end_date, + date_format(start_date_last,'%Y-%m-%d') as start_date_last, + date_format(end_date_last,'%Y-%m-%d') as end_date_last, + member_company_no, + company_no, + acc_date, + invoice_no, + invoice_amt, + invoice_track, + invoice_time, + invoice_type, + verify_state, + valid_time, + remarks, + tx_state + from member_tx + where station_no = {$station_no} and member_no = {$member_no} + order by tx_no desc"; + + // and tx_state = ".MEMBER_TX_TX_STATE_NONE." + + $results = $this->db->query($sql)->result_array(); + + return $results; + } + + // 發票查詢 + public function member_tx_bill_query($station_no, $tx_no=0, $verify_state_str='', $invoice_state_str='', $tx_state_str='', $tx_bill_no=0) + { + $tx_no_statement = !empty($tx_no) ? " and member_tx_bill.tx_no = {$tx_no} " : ""; + $tx_bill_no_statement = !empty($tx_bill_no) ? " and member_tx_bill.tx_bill_no = {$tx_no} " : ""; + + // 審核狀態 + $verify_state_statement = !empty($verify_state_str) ? " and member_tx.verify_state in ( {$verify_state_str} )" : ""; + + // 發票狀態 + $invoice_statement = ''; + if($invoice_state_str == '0') // 限定:未開立發票 + { + $invoice_statement = " and member_tx_bill.invoice_no <= 0 "; + } + if($invoice_state_str == '1') // 限定:未開立發票, 或是 有餘額未開立 (且為 待補開發票) + { + $invoice_statement = " and member_tx_bill.invoice_state = 1 and ( member_tx_bill.invoice_no <= 0 OR member_tx_bill.remain_amt > 0 ) "; + } + else if($invoice_state_str == '2') // 限定:待折讓發票 + { + $invoice_statement = " and member_tx_bill.invoice_state = 2"; + } + else if($invoice_state_str == '100') // 限定:未開立發票, 或是 有餘額未開立 + { + $invoice_statement = " and ( member_tx_bill.invoice_no <= 0 OR member_tx_bill.remain_amt > 0 ) "; + } + + // 交易狀態 + $tx_state_statement = ($tx_state_str != '') ? " and member_tx.tx_state in ( {$tx_state_str} )" : " and member_tx.tx_state in (0,4,44) "; + + $sql = "select + member_tx.tx_no, + member_tx.station_no, + member_tx.member_no, + member_tx.lpr, + member_tx.fee_period, + member_tx.fee_period_last, + member_tx.amt1, + member_tx.amt, + member_tx.amt_last, + member_tx.deposit, + date_format(member_tx.start_date,'%Y-%m-%d') as start_date, + date_format(member_tx.end_date,'%Y-%m-%d') as end_date, + date_format(member_tx.start_date_last,'%Y-%m-%d') as start_date_last, + date_format(member_tx.end_date_last,'%Y-%m-%d') as end_date_last, + member_tx_bill.tx_bill_no, + member_tx_bill.member_company_no, + member_tx_bill.company_no, + member_tx_bill.acc_date, + LPAD(member_tx_bill.invoice_no, 8, '0') as invoice_no, -- 發票號碼補零到8碼 + member_tx_bill.invoice_amt, + member_tx_bill.invoice_track, + member_tx_bill.invoice_time, + member_tx_bill.invoice_type, + member_tx_bill.remain_amt, + member_tx_bill.invoice_state, -- 發票狀態 + member_tx_bill.refund_amt, -- 折讓金額 + member_tx.verify_state, + member_tx.valid_time, + member_tx.remarks, + member_tx.tx_state + from member_tx_bill + left join member_tx on ( member_tx.tx_no = member_tx_bill.tx_no and member_tx.station_no = member_tx_bill.station_no ) + where member_tx_bill.station_no = {$station_no} + {$tx_no_statement} {$tx_bill_no_statement} + {$verify_state_statement} {$invoice_statement} {$tx_state_statement} + order by member_tx_bill.tx_bill_no desc"; + + //trigger_error("test: {$sql}"); + + $results = $this->db->query($sql)->result_array(); + + return $results; + } + + // 發票查詢 + public function member_refund_bill_query($station_no, $tx_no=0, $verify_state_str='', $invoice_state_str='', $tx_state_str='', + $tx_bill_no=0, $member_refund_id=0) + { + $tx_no_statement = !empty($tx_no) ? " and member_tx_bill.tx_no = {$tx_no} " : ""; + $tx_bill_no_statement = !empty($tx_bill_no) ? " and member_tx_bill.tx_bill_no = {$tx_no} " : ""; + $member_refund_id_statement = !empty($member_refund_id) ? " and member_refund.member_refund_id = {$member_refund_id} " : ""; + + // 審核狀態 + $verify_state_statement = !empty($verify_state_str) ? " and member_tx.verify_state in ( {$verify_state_str} )" : ""; + + // 發票狀態 + $invoice_statement = ''; + if($invoice_state_str == '0') // 限定:未開立發票 + { + $invoice_statement = " and member_tx_bill.invoice_no <= 0 "; + } + if($invoice_state_str == '1') // 限定:未開立發票, 或是 有餘額未開立 (且為 待補開發票) + { + $invoice_statement = " and member_tx_bill.invoice_state = 1 and ( member_tx_bill.invoice_no <= 0 OR member_tx_bill.remain_amt > 0 ) "; + } + else if($invoice_state_str == '2') // 限定:待折讓發票 + { + $invoice_statement = " and member_tx_bill.invoice_state = 2"; + } + else if($invoice_state_str == '100') // 限定:未開立發票, 或是 有餘額未開立 + { + $invoice_statement = " and ( member_tx_bill.invoice_no <= 0 OR member_tx_bill.remain_amt > 0 ) "; + } + + // 交易狀態 + $tx_state_statement = !empty($tx_state_str) ? " and member_tx.tx_state in ( {$tx_state_str} )" : " and member_tx.tx_state = 0 "; + + $sql = "select + member_tx.tx_no, + member_tx.station_no, + member_tx.member_no, + member_tx.lpr, + member_tx.fee_period, + member_tx.fee_period_last, + member_tx.amt1, + member_tx.amt, + member_tx.amt_last, + member_tx.deposit, + date_format(member_tx.start_date,'%Y-%m-%d') as start_date, + date_format(member_tx.end_date,'%Y-%m-%d') as end_date, + date_format(member_tx.start_date_last,'%Y-%m-%d') as start_date_last, + date_format(member_tx.end_date_last,'%Y-%m-%d') as end_date_last, + member_tx_bill.tx_bill_no, + member_tx_bill.member_company_no, + member_tx_bill.company_no, + member_tx_bill.acc_date, + LPAD(member_tx_bill.invoice_no, 8, '0') as invoice_no, -- 發票號碼補零到8碼 + member_tx_bill.invoice_amt, + member_tx_bill.invoice_track, + member_tx_bill.invoice_time, + member_tx_bill.invoice_type, + member_tx_bill.remain_amt, + member_tx_bill.invoice_state, -- 發票狀態 + member_tx_bill.refund_amt, -- 折讓金額 + member_tx.verify_state, + member_tx.valid_time, + member_tx.remarks, + member_tx.tx_state + from member_tx_bill + left join member_tx on ( member_tx.tx_no = member_tx_bill.tx_no and member_tx.station_no = member_tx_bill.station_no ) + left join member_refund on ( member_refund.member_no = member_tx_bill.member_no and member_refund.station_no = member_tx_bill.station_no ) + where member_tx_bill.station_no = {$station_no} + {$tx_no_statement} {$tx_bill_no_statement} {$member_refund_id_statement} + {$verify_state_statement} {$invoice_statement} {$tx_state_statement} + order by member_tx_bill.tx_bill_no desc"; + + //trigger_error("test: {$sql}"); + + $results = $this->db->query($sql)->result_array(); + + return $results; + } + + // 臨停未結確認完成 + public function cario_temp_confirmed($parms) + { + $this->try_sync_batch($parms['station_no']); // 同步未同步記錄 + + trigger_error(ADMIN_LOG_TITLE.'臨停未結確認完成:' . print_r($parms, true)); + + // 取得交易資料 + $cario_info = $this->db->select('cario_no, in_time, out_time') + ->from('cario') + ->where(array('station_no' => $parms['station_no'], 'cario_no' => $parms['cario_no'])) + ->get() + ->row_array(); + + if(empty($cario_info)) + { + trigger_error(__FUNCTION__ . '..cario not found..' . print_r($parms, true)); + return 'tx_error_not_found'; // 中斷 + } + + $data_cario = array('confirms' => 1, 'remarks' => $parms['remarks']); + + // [A.開始] + $this->db->trans_start(); + $this->db->update('cario', $data_cario, array('station_no' => $parms['station_no'], 'cario_no' => $parms['cario_no'])); // t1. 更新 cario_no.confirms, cario.remarks + + // [B.建立同步檔] (略) + + // [C.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(__FUNCTION__ . '..trans_error..data:' . print_r($data_cario, true). '| last_query: ' . $this->db->last_query()); + return 'fail'; // 中斷 + } + + return 'ok'; + } + + // 審核完成 + public function member_tx_confirmed($parms) + { + $this->try_sync_batch($parms['station_no']); // 同步未同步記錄 + + trigger_error(ADMIN_LOG_TITLE.'審核完成:' . print_r($parms, true)); + + $altob_admin_submit = $this->input->post('altob_admin_submit', true); // 取得 admin 參數 + + //trigger_error(__FUNCTION__ . '..admin:' . print_r($altob_admin_submit, true)); + //trigger_error(__FUNCTION__ . '..check:' . print_r($this->gen_admin_ck($parms['station_no']), true)); + + if($altob_admin_submit !== $this->gen_admin_ck($parms['station_no'])) + { + trigger_error(__FUNCTION__ . '..altob_admin_submit error..' . print_r($parms, true)); + return 'admin_error'; // 中斷 + } + + // 取得交易資料 + $tx_info = $this->db->select('member_no, end_date') + ->from('member_tx') + ->where(array('station_no' => $parms['station_no'], 'tx_no' => $parms['tx_no'])) + ->get() + ->row_array(); + + if(empty($tx_info)) + { + trigger_error(__FUNCTION__ . '..member_tx not found..' . print_r($parms, true)); + return 'tx_error_not_found'; // 中斷 + } + + $member_no = $tx_info['member_no']; + + // [ 可能的 BUG ] : 直接針對較新的交易審核過關, 會讓會員直接跳過較舊的交易有效期限 + + $data_member = array(); // 若不為空會觸發同步 members + $data_tx = array('verify_state' => $parms['verify_state'], 'remarks' => $parms['remarks']); + + // [A.開始] + $this->db->trans_start(); + $this->db->update('member_tx', $data_tx, array('station_no' => $parms['station_no'], 'tx_no' => $parms['tx_no'])); // t1. 更新 member_tx.verify_state, member_tx.valid_time, member_tx.remarks + $this->gen_member_tx_log($data_tx, $parms['station_no'], $parms['tx_no']); // t.log. 建立 member_tx_log + + if($data_tx['verify_state'] == MEMBER_TX_VERIFY_STATE_OK) + { + $next_valid_time = $tx_info['end_date']. ' 23:59:59'; // 交易若通過, 可取得的新有效期限 + + // 取得會員資料 + $member_info = $this->db->select('valid_time') + ->from('members') + ->where(array('station_no' => $parms['station_no'], 'member_no' => $member_no)) + ->get() + ->row_array(); + + if(empty($member_info)) + { + trigger_error(__FUNCTION__ . '..member not found..' . print_r($parms, true)); + } + else + { + if(strtotime($member_info['valid_time']) >= strtotime($next_valid_time) ) + { + trigger_error(__FUNCTION__ . '..member already got valid_time..' . print_r($parms, true)); + } + else + { + $data_member = array('valid_time' => $next_valid_time); + $this->db->update('members', $data_member, array('station_no' => $parms['station_no'], 'member_no' => $member_no)); // t2. 更新 members.valid_time + $this->gen_member_log($data_member, $parms['station_no'], $member_no); // t.log. 建立 member_log + } + } + // 若審核完成, 更新 members 有效期限 + } + + // [B.建立同步檔] + $sync_seqnos = $this->prepare_sync2hq('U', $parms['station_no'], 'member_tx', $parms['tx_no'], $data_tx); // t3.a. 準備同步檔 (member_tx) + if(!empty($data_member)) + { + $sync_seqnos .= ',' . $this->prepare_sync2hq('U', $parms['station_no'], 'members', $member_no, $data_member); // t3.b. 準備同步檔 (members) + } + + // [C.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(__FUNCTION__ . '..trans_error..data:' . print_r($data_tx, true). '| last_query: ' . $this->db->last_query()); + return 'fail'; // 中斷 + } + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + return 'ok'; + } + + + // 切換賣方統編 + public function switch_company_no($parms) + { + $this->try_sync_batch($parms['station_no']); // 同步未同步記錄 + + trigger_error(ADMIN_LOG_TITLE.'切換賣方統編:' . print_r($parms, true)); + + // 取得交易資料 + $tx_info = $this->db->select('company_no, invoice_no') + ->from('member_tx_bill') + ->where(array('station_no' => $parms['station_no'], 'tx_bill_no' => $parms['tx_bill_no'])) + ->get() + ->row_array(); + + if(empty($tx_info)) + { + trigger_error(__FUNCTION__ . '..tx_error_not_found..' . print_r($parms, true)); + return 'tx_error_not_found'; // 中斷 + } + + if(!empty($tx_info['invoice_no'])) + { + trigger_error(__FUNCTION__ . '..invoice_exist..' . print_r($parms, true)); + return 'invoice_exist'; // 中斷 + } + + $st_info = $this->vars['mcache']->get('st_info'); + $next_company_no = $st_info['company_no']; // 場站統編 + + if($parms['company_no'] == $next_company_no) + { + $next_company_no = '80682490'; // 總公司統編 + } + + if($tx_info['company_no'] == $next_company_no) + { + trigger_error(__FUNCTION__ . '..not_changed..' . print_r($parms, true)); + return 'not_changed'; // 中斷 + } + + $data_tx_bill = array('company_no' => $next_company_no); + + // [A.開始] + $this->db->trans_start(); + $this->db->update('member_tx_bill', $data_tx_bill, array('station_no' => $parms['station_no'], 'tx_bill_no' => $parms['tx_bill_no'])); // t1. 更新 member_tx_bill.company_no + + // [B.建立同步檔] + $sync_seqnos = $this->prepare_sync2hq('U', $parms['station_no'], 'member_tx_bill', $parms['tx_bill_no'], $data_tx_bill); // t2. 準備同步檔 (member_tx_bill) + + // [C.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(__FUNCTION__ . '..trans_error..data:' . print_r($data_tx_bill, true). '| last_query: ' . $this->db->last_query()); + return 'fail'; // 中斷 + } + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + return 'ok'; + } + + // 刪除月租會員 + /* + public function member_delete($station_no, $member_no) + { + $this->try_sync_batch($station_no); // 同步未同步記錄 + + // [A.開始] + $this->db->trans_start(); + $this->db->delete('members', array('station_no' => $station_no, 'member_no' => $member_no, 'suspended' => 0)); // t1. 刪除 members + $this->db->delete('member_car', array('station_no' => $station_no, 'member_no' => $member_no)); // t2. 刪除 member_car + // [B.建立同步檔] + $sync_seqnos = $this->prepare_sync2hq('D', $station_no, 'members', $member_no, array()); // t3. 準備同步檔 (members) + // [C.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(__FUNCTION__ . '..trans_error..data:' . "{$station_no}, {$member_no}". '| last_query: ' . $this->db->last_query()); + return 'trans_error'; + } + + // 同步至總管理處 + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + return 'ok'; + } + */ + + // 月租會員加入 + public function member_add($data, $rents_arr) + { + $data['lpr'] = preg_replace('/\s+/', '', $data['lpr']); // 移除空白 + + $check_member_no = $data['member_no']; + $station_no = $data['station_no']; + $tx_no = 0; + + $this->try_sync_batch($station_no); // 同步未同步記錄 + + // 預設值 (修改會員時, 將直接填入) + $tx_bill_no = 0; + $invoice_amt = 0; + $remain_amt = 0; + $period_max_amt = 0; + + // 會員車輛基本資料檔 + $start_date = (empty($data['demonth_start_date']) ? $data['start_date'] : $data['demonth_start_date']); + $data['rent_start_date'] = $data['start_date']; + $data['rent_end_date'] = $data['end_date']; + $data['start_date'] = "{$start_date} 00:00:00"; + $data['end_date'] = "{$data['end_date']} 23:59:59"; + $old_lpr = $data['old_lpr']; + unset($data['old_lpr']); + $data_car = array + ( + 'lpr' => $data['lpr'], + 'lpr_correct' => $data['lpr'], + 'etag' => $data['etag'], + 'station_no' => $station_no, + 'start_time' => $data['start_date'], + 'end_time' => $data['end_date'] + ); + + // 取出會員轉租資訊 + $refund_transfer_id = empty($data['refund_transfer_id']) ? 0 : $data['refund_transfer_id']; + $amt_discount = empty($data['refund_transfer_discount']) ? 0 : $data['refund_transfer_discount']; + unset($data['refund_transfer_id']); + unset($data['refund_transfer_discount']); + + if ($check_member_no == 0) // 新增一筆會員資料 + { + unset($data['member_no']); + $data['payed_date'] = substr($this->now_str, 0, 10); + $data['login_id'] = $data['lpr']; + $data['passwd'] = $data['lpr']; + $data['valid_time']= $this->default_valid_time; // 有效期限 2017/01/15 added + if($refund_transfer_id > 0) + { + $data['refund_transfer_id'] = $refund_transfer_id; // 轉租來源編號 2017/02/24 added + } + $action_code = 'A'; + + // [A.開始] + $this->db->trans_start(); + /* + 2017/03/16 統一新增流程 + + $this->db->insert('members', $data); + $members_insert_id = $this->db->insert_id(); + + $data_car['member_no'] = $members_insert_id; + $this->db->insert('member_car', $data_car); + */ + $members_insert_id = $this->gen_members($data); // t1 新增 members + + $data_car['member_no'] = $members_insert_id; + $this->gen_member_car($data_car); // t2.a 新增 member_car + + $data['member_no'] = $members_insert_id; + + $this->gen_member_log($data); // t.log. 建立 member_log + + trigger_error(MEMBER_LOG_TITLE.'新增:' . print_r($data, true) . ", from: {$old_lpr}"); + + $invoice_count = $this->gen_invoice_count($data['fee_period']); // 試算發票張數 + + $data_tx = array( + 'member_no' => $members_insert_id, // 會員編號 + 'station_no' => $station_no, // 場站編號 + 'sync_no' => 0, // 預設同步編號 + 'lpr' => $data['lpr'], // 車牌號碼 + + 'member_attr' => $data['member_attr'], // 會員身份 + + 'amt_accrued' => $data['amt_accrued'], // 應收租金 + 'amt_tot' => $data['amt_tot'], // 實收租金 + 'deposit' => $data['deposit'], // 押金 + + 'amt' => $data['amt'], // 本期租金 + 'fee_period' => $data['fee_period'], // 本期繳期 + 'start_date' => $data['rent_start_date'], // 本期開始日 + 'end_date' => $data['rent_end_date'], // 本期結束日 + + 'amt1' => $data['amt1'], // 首期租金 + 'amt_last' => $data['amt1'], // 上期租金 + 'fee_period_last' => $data['fee_period1'], // 上期繳期 + 'start_date_last' => $data['demonth_start_date'], // 上期開始日 + 'end_date_last' => $data['demonth_end_date'], // 上期結束日 + + 'member_company_no' => $data['member_company_no'], // 買方統編 + 'company_no' => $data['company_no'], // 賣方統編 + + 'invoice_count' => $invoice_count, // 預計發票張數 + + 'acc_date' => $data['payed_date'], // 入帳日(暫定) + + 'acc_time' => $this->now_str, // 入帳時間 2017/02/15 added + + 'valid_time' => $data['valid_time'], // 有效期限 + + 'amt_discount' => $amt_discount // 設定轉租折扺 2017/02/24 added + ); + + $this->db->insert('member_tx', $data_tx); // t3 新增 member_tx + $tx_no = $this->db->insert_id(); // 訂單序號 + $data_tx['tx_no'] = $tx_no; + + $this->gen_member_tx_log($data_tx); // t.log. 建立 member_tx_log + + // 建立首期發票開立記錄 (公式 A: 首期租金 + 拆分第一期金額) + $total_amt = $data['amt'] + $data['amt1']; + $period_max_amt = $this->gen_invoice_count_amt($data['amt'], $invoice_count); + $invoice_amt = $data['amt1'] + $period_max_amt; + $remain_amt = ($total_amt - $invoice_amt > 0) ? $total_amt - $invoice_amt : 0; + trigger_error(__FUNCTION__ . ', period_max_amt: ' . $period_max_amt . ', amt:'. $data['amt']. ', amt1:'. $data['amt1'] . ', invoice_amt:' .$invoice_amt . ', remain_amt:' . $remain_amt); + + /* + // 建立首期發票開立記錄 (公式 B: 首期租金 + 最多一季金額) // 2017/01/11 更換 + $total_amt = $data['amt'] + $data['amt1']; + $period_3_amt = $rents_arr[3][$data['member_attr']]; + $invoice_amt = ($data['amt'] > $period_3_amt) ? $period_3_amt + $data['amt1'] : $total_amt; + $remain_amt = ($total_amt - $invoice_amt > 0) ? $total_amt - $invoice_amt : 0; + trigger_error('period_3_amt: ' . $period_3_amt . ', amt:'. $data['amt']. ', amt1:'. $data['amt1'] . ', invoice_amt:' .$invoice_amt . ', remain_amt:' . $remain_amt); + */ + + $data_tx_bill = array( + 'tx_no' => $tx_no, // 訂單序號 + + 'member_no' => $members_insert_id, // 會員編號 + 'station_no' => $station_no, // 場站編號 + 'sync_no' => 0, // 預設同步編號 + 'lpr' => $data['lpr'], // 車牌號碼 + + 'member_company_no' => $data['member_company_no'], // 買方統編 + 'company_no' => $data['company_no'], // 賣方統編 + + 'acc_date' => $data['payed_date'], // 入帳日(暫定) + + 'invoice_amt' => $invoice_amt, // 本次發票金額 + 'remain_amt' => $remain_amt, // 剩餘未開立金額 + + 'invoice_count' => $invoice_count // 預計發票張數 + ); + + if($invoice_count > 1) + { + $data_tx_bill['invoice_next_date'] = $this->gen_invoice_next_date($data['rent_start_date']); // 預計下一張發票開立日 + } + + $this->db->insert('member_tx_bill', $data_tx_bill); // t4 新增 member_tx_bill + $tx_bill_no = $this->db->insert_id(); // 帳單序號 + $data_tx_bill['tx_bill_no'] = $tx_bill_no; + + // [B.建立同步檔] + $sync_seqnos = $this->prepare_sync2hq($action_code, $station_no, 'members', $members_insert_id, $data); // t5 準備同步檔 (members) + + $sync_seqnos .= ',' . $this->prepare_sync2hq($action_code, $station_no, 'member_tx', $tx_no, $data_tx); // t6 準備同步檔 (member_tx) + + $sync_seqnos .= ',' . $this->prepare_sync2hq($action_code, $station_no, 'member_tx_bill', $tx_bill_no, $data_tx_bill); // t7 準備同步檔 (member_tx_bill) + + if($refund_transfer_id > 0) + { + // 更新退租記錄 + $data_refund = array('dismiss_state' => MEMBER_REFUND_DISMISS_STATE_TRANSFERRED); + + $this->db->update('member_refund', $data_refund, array('station_no' => $station_no, 'member_refund_id' => $refund_transfer_id)); // t8.1 更新 member_refund + + $this->gen_member_refund_log($data_refund, $station_no, $refund_transfer_id); // t.log. 建立 member_refund_log + + $sync_seqnos .= ',' . $this->prepare_sync2hq('U', $station_no, 'member_refund', $refund_transfer_id, $data_refund); // t8. 準備同步檔 (member_refund) + + // 清除 etag 記錄 + if ($old_lpr !== $data['lpr']) + { + $this->db->delete('etag_lpr', array('lpr' => $old_lpr)); + trigger_error(MEMBER_LOG_TITLE."{$old_lpr} 清除 etag 記錄a"); + } + } + + // [C.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(MEMBER_LOG_TITLE.'..trans_error..last_query:' . $this->db->last_query()); + trigger_error(__FUNCTION__ . '..trans_error..data:' . print_r($data, true). ', data_tx:'. print_r($data_tx, true) .'| last_query: ' . $this->db->last_query()); + return 'trans_error'; + } + + // 同步至總管理處 + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + } + else + { + $altob_admin_submit = $this->input->post('altob_admin_submit', true); // 取得 admin 參數 + if($altob_admin_submit == $this->gen_admin_ck($station_no)) + { + trigger_error("admin: " + $altob_admin_submit); + //unset($data['contract_no']); // 合約號 + //unset($data['park_time']); // 停車時段 + unset($data['rent_start_date']); + unset($data['rent_end_date']); + unset($data['start_date']); + unset($data['end_date']); + unset($data['demonth_start_date']); + unset($data['demonth_end_date']); + //unset($data['member_attr']); // 會員身份 + unset($data['deposit']); + unset($data['amt_tot']); + unset($data['amt_accrued']); + unset($data['fee_period1']); + unset($data['amt1']); + //unset($data['fee_period']); // 例行繳期 + //unset($data['amt']); // 例行租金 + trigger_error(MEMBER_LOG_TITLE.'修改 (admin):' . print_r($data, true). ", from: {$old_lpr}"); + } + else + { + // 一般情況下, 時段與費率都不能在這個流程修改 + //unset($data['contract_no']); // 合約號 + unset($data['park_time']); + unset($data['rent_start_date']); + unset($data['rent_end_date']); + unset($data['start_date']); + unset($data['end_date']); + unset($data['demonth_start_date']); + unset($data['demonth_end_date']); + unset($data['member_attr']); + unset($data['deposit']); + unset($data['amt_tot']); + unset($data['amt_accrued']); + unset($data['fee_period1']); + unset($data['amt1']); + unset($data['fee_period']); + unset($data['amt']); + trigger_error(MEMBER_LOG_TITLE.'修改 (normal):' . print_r($data, true). ", from: {$old_lpr}"); + } + $action_code = 'U'; + + // [A.開始] + $this->db->trans_start(); + $this->db->update('members', $data, array('station_no' => $station_no, 'member_no' => $check_member_no)); // t1. 更新 members + + $this->gen_member_log($data, $station_no, $check_member_no); // t.log. 建立 member_log + + // 沒有異動到車牌, 使用update, 否則重建一筆 + if ($old_lpr == $data['lpr']) // t2.a 更新 member_car + { + unset($data_car['lpr']); + unset($data_car['lpr_correct']); + $this->db->update('member_car', $data_car, array('station_no' => $station_no, 'member_no' => $check_member_no)); + } + else + { + /* + 2017/03/16 更換為統一建立流程 + + $this->db->delete('member_car', array('station_no' => $station_no, 'member_no' => $check_member_no)); + $data_car['member_no'] = $check_member_no; + $this->db->insert('member_car', $data_car); + */ + $data_car['member_no'] = $check_member_no; + $this->gen_member_car($data_car); + + // 清除 etag 記錄 + $this->db->delete('etag_lpr', array('lpr' => $old_lpr)); + trigger_error(MEMBER_LOG_TITLE."{$old_lpr} 清除 etag 記錄b"); + } + + // [B.建立同步檔] + $sync_seqnos = $this->prepare_sync2hq($action_code, $station_no, 'members', $check_member_no, $data); // t3. 準備同步檔 (members) + + // [C.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(MEMBER_LOG_TITLE.'..trans_error..last_query:' . $this->db->last_query()); + trigger_error(__FUNCTION__ . '..trans_error..data:' . print_r($data, true). '| last_query: ' . $this->db->last_query()); + return 'trans_error'; + } + + // 同步至總管理處 + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + } + + return array( + 'station_no' => $station_no, + 'company_no' => $data['company_no'], + 'member_no' => $data['member_no'], + 'start_date' => $start_date, + 'msg' => 'ok', + 'action_code' => $action_code, + 'tx_no' => $tx_no, + 'tx_bill_no' => $tx_bill_no, + 'invoice_amt' => $invoice_amt, + 'remain_amt' => $remain_amt, + 'period_3_amt' => $period_max_amt, + 'amt_discount' => $amt_discount + ); + } + + + // 查詢車牌是否重複 (查詢會員車牌) + public function check_lpr($lpr) + { + $rows = $this->db->select('count(*) as counts') + ->from('members') + ->where(array('lpr' => $lpr)) + ->get() + ->row_array(); + + return $rows['counts']; + } + + // 查詢車牌是否重複 (查詢尚未處理退租金額的退租車牌) + public function check_refund_lpr($lpr) + { + $rows = $this->db->select('count(*) as counts') + ->from('member_refund') + ->join('member_log', 'member_refund.member_log_id = member_log.member_log_id', 'left') + ->where(array('member_log.lpr' => $lpr)) + ->where_in('member_refund.dismiss_state', array( + MEMBER_REFUND_DISMISS_STATE_NONE, // 0: 無 (尚未處理退租金額, 視為退租中) + MEMBER_REFUND_DISMISS_STATE_KEEP_DEPOSIT // 10: 押金未退 (已處理退租金額, 但押金未退, 視為退租中) + //MEMBER_REFUND_DISMISS_STATE_TRANSFERRED, // 1: 已轉租 (金額已結清, 視為新車牌, 忽略) + //MEMBER_REFUND_DISMISS_STATE_DONE // 100: 已結清 (金額已結清, 視為新車牌, 忽略) + )) + ->get() + ->row_array(); + + return $rows['counts']; + } + + // 查詢車牌是否重複 (查詢尚未處理退租金額的退租會員) + public function check_refund_member_no($member_no) + { + $rows = $this->db->select('count(*) as counts') + ->from('member_refund') + ->join('member_log', 'member_refund.member_log_id = member_log.member_log_id', 'left') + ->where(array('member_log.member_no' => $member_no)) + ->where_in('member_refund.dismiss_state', array( + MEMBER_REFUND_DISMISS_STATE_NONE, // 0: 無 (尚未處理退租金額, 視為退租中) + MEMBER_REFUND_DISMISS_STATE_KEEP_DEPOSIT // 10: 押金未退 (已處理退租金額, 但押金未退, 視為退租中) + //MEMBER_REFUND_DISMISS_STATE_TRANSFERRED, // 1: 已轉租 (金額已結清, 視為新車牌, 忽略) + //MEMBER_REFUND_DISMISS_STATE_DONE, // 100: 已結清 (金額已結清, 視為新車牌, 忽略) + )) + ->get() + ->row_array(); + + return $rows['counts']; + } + + // 查詢車牌是否重複 (查詢已進行過退租的會員) + public function check_refund_member_no_exist($member_no) + { + $rows = $this->db->select('count(*) as counts') + ->from('member_refund') + ->join('member_log', 'member_refund.member_log_id = member_log.member_log_id', 'left') + ->where(array('member_log.member_no' => $member_no)) + ->get() + ->row_array(); + + return $rows['counts']; + } + + // 取得交易發票 + public function get_tx_invoice_no($tx_no) + { + $rows = $this->db->select('invoice_no') + ->from('member_tx') + ->where(array('tx_no' => $tx_no)) + ->get() + ->row_array(); + + return $rows['invoice_no']; + } + + // 更新月租發票記錄 + function set_tx_invoice_no($parms) + { + $data = array + ( + 'member_company_no' => $parms['member_company_no'], + 'company_no' => $parms['company_no'], + 'invoice_track' => $parms['invoice_track'], + 'invoice_no' => $parms['invoice_no'], + 'invoice_time' => $parms['invoice_time'] + ); + + if(array_key_exists('invoice_type', $parms)) + { + $data['invoice_type'] = $parms['invoice_type']; // 發票種類 + } + + // [A.開始] + $this->db->trans_start(); + $this->db->update('member_tx_bill', $data, array('station_no' => $parms['station_no'], 'tx_bill_no' => $parms['tx_bill_no'])); // t1. 更新 member_tx_bill + + trigger_error(TX_LOG_TITLE.'更新發票記錄:' . print_r($data, true). ', tx_bill_no: '. $tx_bill_no); + + // [B.建立同步檔] + $sync_seqnos = $this->prepare_sync2hq('U', $parms['station_no'], 'member_tx_bill', $parms['tx_bill_no'], $data); // t2. 準備同步檔 (member_tx_bill) + + // 判斷是否為補開發票 + $sql = "select member_refund.member_refund_id, member_refund.member_no, member_refund.member_log_id + from member_tx_bill + LEFT JOIN member_refund ON ( member_refund.member_no = member_tx_bill.member_no and member_refund.station_no = member_tx_bill.station_no ) + WHERE + member_tx_bill.station_no = {$parms['station_no']} and + member_tx_bill.tx_bill_no = {$parms['tx_bill_no']} and + member_tx_bill.invoice_count = 1 and + member_tx_bill.remain_amt = 0 and + member_tx_bill.invoice_state = ".MEMBER_TX_BILL_INVOICE_STATE_MORE + ; + + $rows = $this->db->query($sql)->result_array(); + + //trigger_error('test xxx:'.$sql. ', member_refund_id: ' . $rows[0]['member_refund_id']); + + if(!empty($rows[0]) && array_key_exists('member_refund_id', $rows[0])) + { + $data_refund = array('refund_state' => MEMBER_REFUND_STATE_DONE); // 完結 + $this->db->update('member_refund', $data_refund, + array('station_no' => $parms['station_no'], 'member_refund_id' => $rows[0]['member_refund_id'])); // t3. 更新 member_refund.refund_state + + $this->gen_member_refund_log($data_refund, $parms['station_no'], $rows[0]['member_refund_id']); // t.log. 建立 member_refund_log + + $sync_seqnos .= ',' . $this->prepare_sync2hq('U', $parms['station_no'], 'member_refund', $rows[0]['member_refund_id'], $data_refund); // t4. 準備同步檔 (member_refund) + } + + // [C.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(TX_LOG_TITLE.'..trans_error..last_query:' . $this->db->last_query()); + trigger_error(__FUNCTION__ . '..trans_error..data:' . print_r($data, true). '| last_query: ' . $this->db->last_query()); + return 'fail'; // 中斷 + } + + // 同步至總管理處 + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + return 'ok'; + } + + // 首期月租付款交易 + public function first_rents_payment($parms) + { + $this->try_sync_batch($parms['station_no']); // 同步未同步記錄 + + trigger_error(TX_LOG_TITLE.'列印發票:' . print_r($parms, true)); + + // 確認交易記錄 + $rows = $this->db->select('count(*) as counts, lpr') + ->from('member_tx_bill') + ->where(array( + 'tx_bill_no' => $parms['tx_bill_no'], 'tx_no' => $parms['tx_no'], + 'station_no' => $parms['station_no'], 'member_no' => $parms['member_no'], + 'invoice_amt' => $parms['invoice_amt'], 'invoice_no' => '' + )) + ->get() + ->row_array(); + + if(empty($rows) || $rows['counts'] != 1) + { + trigger_error(__FUNCTION__ . '..member_tx_bill not found..' . print_r($parms, true) . $this->db->last_query()); + return 'tx_error'; // 中斷 + } + + // 印發票 + if(array_key_exists('invoice_track', $parms) && array_key_exists('invoice_no', $parms)) + { + $parms['invoice_time'] = $this->now_str; // 目前時間 + } + else + { + $invoice_parms = array( + 'station_no' => $parms['station_no'], + 'tx_bill_no' => $parms['tx_bill_no'], + 'amt' => $parms['invoice_amt'], + 'member_company_no' => $parms['member_company_no'], + 'company_no' => $parms['company_no'], + 'email' => $parms['email'], + 'mobile' => $parms['mobile'], + 'lpr' => $rows['lpr'] + ); + + $invoice_result = $this->print_invoice($invoice_parms); + if(!empty($invoice_result) && array_key_exists('einvoice_no', $invoice_result)) + { + $parms['invoice_track'] = $invoice_result['einvoice_track']; // 發票字軌 + $parms['invoice_no'] = $invoice_result['einvoice_no']; // 發票號碼 + $parms['invoice_time'] = $this->now_str; // 目前時間 + } + } + + if(empty($parms['invoice_no']) || empty($parms['invoice_track'])) + { + trigger_error(__FUNCTION__ . '..invoice gg..' . print_r($parms, true)); + return 'invoice_fail'; // 中斷 + } + + // 更新月租發票記錄 + echo $this->set_tx_invoice_no($parms); + } + + // 新增月租付款交易 + public function rents_payment($parms, $rents_arr) + { + $this->try_sync_batch($parms['station_no']); // 同步未同步記錄 + + trigger_error(TX_LOG_TITLE.'繳租:' . print_r($parms, true). print_r($rents_arr, true)); + + $invoice_count = $this->gen_invoice_count($parms['fee_period']); // 試算發票張數 + + // 先不印發票 + $parms['sync_no'] = 0; // 預設同步編號 + $parms['fee_period_last'] = $parms['fee_period']; // 上期繳期 + $parms['start_date'] = date('Y-m-d', strtotime("{$parms['end_date_last']} first day of next month")); // 本期開始日:上期結束日之次月首日 + $parms['acc_date'] = date('Y-m-d'); // 入帳日(暫定) + $parms['valid_time'] = $this->default_valid_time; // 有效期限 + $parms['invoice_count'] = $invoice_count; // 預計發票張數 + $parms['acc_time'] = $this->now_str; // 入帳時間 2017/02/15 added + + // [A.開始] + $this->db->trans_start(); + $data_tx = $parms; + $this->db->insert('member_tx', $data_tx); // t1 新增 member_tx + $tx_no = $this->db->insert_id(); // 交易序號 + $data_tx['tx_no'] = $tx_no; + + $this->gen_member_tx_log($data_tx); // t.log. 建立 member_tx_log + + // 接續發票開立記錄 (公式: 拆分第一期金額) + $invoice_amt = $this->gen_invoice_count_amt($parms['amt'], $invoice_count); + $remain_amt = $parms['amt'] - $invoice_amt; + trigger_error(__FUNCTION__ . ', amt:'. $parms['amt']. ', invoice_amt:' .$invoice_amt . ', remain_amt:' . $remain_amt); + + /* + // 接續發票開立記錄 (公式: 最多一季金額) // 2017/01/11 更換 + $period_3_amt = ($rents_arr[3][$parms['member_attr']] > 2000) ? $rents_arr[3][$parms['member_attr']] : 2000; // 至少 $2000 + $invoice_amt = ($parms['amt'] > $period_3_amt) ? $period_3_amt : $parms['amt']; + $remain_amt = $parms['amt'] - $invoice_amt; + trigger_error('period_3_amt: ' . $period_3_amt . ', amt:'. $parms['amt']. ', invoice_amt:' .$invoice_amt . ', remain_amt:' . $remain_amt); + */ + + $data_tx_bill = array( + 'tx_no' => $tx_no, // 交易編號 + + 'member_no' => $parms['member_no'], // 會員編號 + 'station_no' => $parms['station_no'], // 場站編號 + 'sync_no' => 0, // 預設同步編號 + + 'lpr' => $parms['lpr'], // 車牌號碼 + + 'member_company_no' => $parms['member_company_no'], // 買方統編 + 'company_no' => $parms['company_no'], // 賣方統編 + + 'acc_date' => $parms['acc_date'], // 入帳日(延用) + + 'invoice_amt' => $invoice_amt, // 本次發票金額 + 'remain_amt' => $remain_amt, // 剩餘未開立金額 + + 'invoice_count' => $invoice_count // 預計發票張數 + ); + + if($invoice_count > 1) + { + $data_tx_bill['invoice_next_date'] = $this->gen_invoice_next_date($parms['start_date']); // 預計下一張發票開立日 + } + + $this->db->insert('member_tx_bill', $data_tx_bill); // t2 新增 member_tx_bill + $tx_bill_no = $this->db->insert_id(); // 帳單序號 + $data_tx_bill['tx_bill_no'] = $tx_bill_no; + + $data_member = array( + 'fee_period' => $parms['fee_period'], + 'payed_date' => $parms['acc_date'], // 付款日 + 'start_date' => "{$parms['start_date_last']} 00:00:00", // 開始日:由上期繼續延續下去 + 'end_date' => "{$parms['end_date']} 23:59:59", // 結束日 + 'valid_time' => $this->default_valid_time // 有效期限 (更新寬限期) // 2017/02/15 updated + ); + $this->db->update('members', $data_member, array('station_no' => $parms['station_no'], 'member_no' => $parms['member_no'])); // t3. 更新 members + + $this->gen_member_log($data_member, $parms['station_no'], $parms['member_no']); // t.log. 建立 member_log + + $this->db->update('member_car', // t4. 更新 member_car + array('start_time' => "{$data_member['start_date']} 00:00:00", 'end_time' => "{$data_member['end_date']} 23:59:59"), + array('station_no' => $parms['station_no'], 'member_no' => $parms['member_no'])); + + // [B.準備同步檔] + $sync_seqnos = $this->prepare_sync2hq('A', $parms['station_no'], 'member_tx', $tx_no, $data_tx); // t5. 準備同步檔 (member_tx) + $sync_seqnos .= ',' . $this->prepare_sync2hq('A', $parms['station_no'], 'member_tx_bill', $tx_bill_no, $data_tx_bill); // t6. 準備同步檔 (member_tx_bill) + $sync_seqnos .= ',' . $this->prepare_sync2hq('U', $parms['station_no'], 'members', $parms['member_no'], $data_member); // t7. 準備同步檔 (members) + + // [c.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(__FUNCTION__ . '..trans_error..data:' . print_r($data_tx, true). '| last_query: ' . $this->db->last_query()); + return 'fail'; // 中斷 + } + + // 同步至總管理處 + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + return 'ok'; + } + + // 退租 + public function stop_rents_payment($parms, $rents_arr) + { + $this->try_sync_batch($parms['station_no']); // 同步未同步記錄 + + trigger_error(MEMBER_LOG_TITLE.'開始退租流程:' . print_r($parms, true). print_r($rents_arr, true)); + + // 1. 取得退租資訊 + $result = $this->calculate_stop_rents_amt($parms, $rents_arr); + + // 2. 確認審核狀態 + if(!$result['verify_state']) + { + $altob_admin_submit = $this->input->post('altob_admin_submit', true); // 取得 admin 參數 + if($altob_admin_submit == $this->gen_admin_ck($parms['station_no'])) + { + $parms['tot_amt'] = $result['return_amt'] + $result['return_deposit']; + trigger_error(ADMIN_LOG_TITLE.'強制退租:' . print_r($parms, true). print_r($rents_arr, true)); + trigger_error("force refund by admin: " + $altob_admin_submit + " | set tot_amt: " + $parms['tot_amt']); + } + else + { + trigger_error(__FUNCTION__ . '..verify_state_error..' . print_r($parms, true). print_r($result, true)); + return 'verify_state_error'; // 尚未審核完成 + } + } + + // 3. 確認金額正確性 + $tot_amt = $result['return_amt'] + $result['return_deposit']; + if($tot_amt != $parms['tot_amt']) + { + trigger_error(__FUNCTION__ . '..tot_amt_error..' . print_r($parms, true). print_r($result, true)); + return 'tot_amt_error'; // 金額有誤 + } + + // 4. 確認會員資料 + $data_member = $this->db->select('*')->from('members') + ->where(array('station_no' => $parms['station_no'], 'member_no' => $parms['member_no'])) + ->get() + ->row_array(); + + if(empty($data_member)) + { + trigger_error(__FUNCTION__ . '..member_not_found..' . print_r($parms, true)); + return 'member_not_found'; // 中斷 + } + + // 5. 退租 + + // TODO: 審核流程? + $result['return_state'] = ($result['return_state'] == MEMBER_REFUND_STATE_NONE) ? MEMBER_REFUND_STATE_DONE : $result['return_state']; // 自動完成 + + // [A.開始] + $this->db->trans_start(); + + /* + 2017/03/16: 改成不刪除記錄, 但變更時間區間 + + $this->db->delete('members', array('station_no' => $parms['station_no'], 'member_no' => $parms['member_no'])); // t1. 刪除 members + */ + $data_member_end_date = array('end_date' => $parms['stop_date']. ' 23:59:59'); + $this->db->update('members', $data_member_end_date, array('station_no' => $parms['station_no'], 'member_no' => $parms['member_no'])); // t1.a 更新 members + + $data_member['end_date'] = $data_member_end_date['end_date']; + $member_log_id = $this->gen_member_log($data_member, $parms['station_no'], $parms['member_no']); // t.log. 建立 member_log + + $data_refund = array( + 'member_no' => $parms['member_no'], + 'station_no' => $parms['station_no'], + 'member_log_id' => $member_log_id, + 'refund_amt' => $result['return_amt'], + 'refund_deposit' => $result['return_deposit'], + 'refund_tot_amt' => $tot_amt, + 'refund_state' => $result['return_state'], + 'refund_time' => $data_member_end_date['end_date'] + ); + $this->db->insert('member_refund', $data_refund); // t1.b 建立 member_refund + $refund_id = $this->db->insert_id(); + $data_refund['member_refund_id'] = $refund_id; + + trigger_error(__FUNCTION__ . '..data_refund..' . print_r($data_refund, true)); + + $this->gen_member_refund_log($data_refund, $parms['station_no']); // t.log. 建立 member_refund_log + + /* + 2017/03/16: 改成不刪除記錄, 但變更時間區間 + + $this->db->delete('member_car', array('station_no' => $parms['station_no'], 'member_no' => $parms['member_no'])); + */ + $this->db->update('member_car', // t2. 更新 member_car + array('end_time' => "{$data_refund['refund_time']}"), + array('station_no' => $parms['station_no'], 'member_no' => $parms['member_no'])); + + // [B.建立同步檔] + + /* + 2017/03/16: 改成不刪除記錄, 但變更時間區間 + + $sync_seqnos = $this->prepare_sync2hq('D', $parms['station_no'], 'members', $parms['member_no'], array()); // t3. 準備同步檔 (members) + */ + $sync_seqnos = $this->prepare_sync2hq('U', $parms['station_no'], 'members', $parms['member_no'], $data_member_end_date); // t3.a 準備同步檔 (members) + $sync_seqnos .= ',' . $this->prepare_sync2hq('A', $parms['station_no'], 'member_refund', $refund_id, $data_refund); // t3.b 準備同步檔 (member_refund) + + foreach($result['results'] as $key => $val) + { + $tx_no = $key; + $data_tx = array('tx_state' => MEMBER_TX_TX_STATE_STOP); // 已退租 + $this->db->update('member_tx', $data_tx, + array('station_no' => $parms['station_no'], 'member_no' => $parms['member_no'], 'tx_no' => $tx_no)); // t4. 更新 member_tx.tx_state + + $this->gen_member_tx_log($data_tx, $parms['station_no'], $tx_no); // t.log. 建立 member_tx_log + + // [B.建立同步檔] + $sync_seqnos .= ',' . $this->prepare_sync2hq('U', $parms['station_no'], 'member_tx', $tx_no, $data_tx); // t5. 準備同步檔 (member_tx) + } + + foreach($result['results_i'] as $key => $val) + { + $tx_bill_no = $key; + $data_tx_bill = array('invoice_state' => MEMBER_TX_BILL_INVOICE_STATE_ALLOWANCE, 'refund_amt' => $val['refund_amt']); // 待折讓 + $this->db->update('member_tx_bill', $data_tx_bill, + array('station_no' => $parms['station_no'], 'member_no' => $parms['member_no'], 'tx_bill_no' => $tx_bill_no)); // t6. 更新 member_tx_bill.invoice_state + + // [B.建立同步檔] + $sync_seqnos .= ',' . $this->prepare_sync2hq('U', $parms['station_no'], 'member_tx_bill', $tx_bill_no, $data_tx_bill); // t7. 準備同步檔 (member_tx_bill) + } + + if($result['return_state'] == MEMBER_REFUND_STATE_MORE_INVOICE) + { + // 補開 + $invoice_tot_amt = -$tot_amt; + $invoice_count = $this->gen_invoice_count($data_member['fee_period']); // 試算發票張數 + $invoice_amt = $this->gen_invoice_count_amt($invoice_tot_amt, $invoice_count); + $remain_amt = $invoice_tot_amt - $invoice_amt; + trigger_error(__FUNCTION__ . ', invoice_tot_amt:'. $invoice_tot_amt. ', invoice_amt:' .$invoice_amt . ', remain_amt:' . $remain_amt); + + $parms['sync_no'] = 0; // 預設同步編號 + $parms['acc_date'] = date('Y-m-d'); // 入帳日(暫定) + $parms['invoice_count'] = $invoice_count; // 預計發票張數 + + $data_tx = array( + 'member_no' => $parms['member_no'], // 會員編號 + 'station_no' => $parms['station_no'], // 場站編號 + 'sync_no' => 0, // 預設同步編號 + + 'lpr' => $data_member['lpr'], // 車牌號碼 + + 'end_date' => $data_refund['refund_time'], // 結束日 + + 'member_company_no' => $data_member['member_company_no'], // 買方統編 + 'company_no' => $data_member['company_no'], // 賣方統編 + 'acc_date' => $parms['acc_date'], // 入帳日(暫定) + + 'amt' => $invoice_tot_amt, // 本次發票金額 + 'invoice_count' => $invoice_count, // 預計發票張數 + + 'tx_state' => MEMBER_TX_TX_STATE_STOP // 已退租 + ); + $this->db->insert('member_tx', $data_tx); // t8. 新增 member_tx + $tx_no = $this->db->insert_id(); // 訂單序號 + $data_tx['tx_no'] = $tx_no; + + $this->gen_member_tx_log($data_tx); // t.log. 建立 member_tx_log + + $data_tx_bill = array( + 'tx_no' => $tx_no, // 交易編號 + + 'member_no' => $parms['member_no'], // 會員編號 + 'station_no' => $parms['station_no'], // 場站編號 + 'sync_no' => 0, // 預設同步編號 + + 'lpr' => $data_member['lpr'], // 車牌號碼 + + 'member_company_no' => $data_member['member_company_no'], // 買方統編 + 'company_no' => $data_member['company_no'], // 賣方統編 + 'acc_date' => $parms['acc_date'], // 入帳日(延用) + + 'invoice_amt' => $invoice_amt, // 本次發票金額 + 'remain_amt' => $remain_amt, // 剩餘未開立金額 + + 'invoice_count' => $invoice_count, // 預計發票張數 + + 'invoice_state' => MEMBER_TX_BILL_INVOICE_STATE_MORE // 待補開 + ); + + if($invoice_count > 1) + { + $data_tx_bill['invoice_next_date'] = $this->gen_invoice_next_date($parms['acc_date']); // 預計下一張發票開立日 + } + + $this->db->insert('member_tx_bill', $data_tx_bill); // t9. 新增 member_tx_bill + $tx_bill_no = $this->db->insert_id(); // 帳單序號 + $data_tx_bill['tx_bill_no'] = $tx_bill_no; + + $sync_seqnos .= ',' . $this->prepare_sync2hq('A', $parms['station_no'], 'member_tx', $tx_no, $data_tx); // t10. 準備同步檔 (member_tx) + $sync_seqnos .= ',' . $this->prepare_sync2hq('A', $parms['station_no'], 'member_tx_bill', $tx_bill_no, $data_tx_bill); // t11. 準備同步檔 (member_tx_bill) + } + + // [c.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(__FUNCTION__ . '..trans_error..data:' . print_r($parms, true). print_r($result, true). '| last_query: ' . $this->db->last_query()); + return 'fail'; // 中斷 + } + + // 同步至總管理處 + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + return 'ok'; + } + + // 計算退租金額 + public function calculate_stop_rents_amt($parms, $rents_arr) + { + $result = array(); + $result['results'] = array(); // 交易 + $result['verify_state'] = true; // 審核 + $result['results_i'] = array(); // 發票 + + // 取得所有已開立發票記錄 + $result_tx = array(); // 發票記錄 A (tx_no) + $result_tx_bill = array(); // 發票記錄 B (tx_bill_no) + $sql = "select + member_tx_bill.tx_no, member_tx_bill.tx_bill_no, + member_tx_bill.invoice_amt, member_tx_bill.invoice_no, member_tx_bill.invoice_track, member_tx_bill.invoice_time + from member_tx_bill + left join member_tx on (member_tx.tx_no = member_tx_bill.tx_no and member_tx.station_no = member_tx_bill.station_no) + where + member_tx_bill.station_no = {$parms['station_no']} and + member_tx_bill.member_no = {$parms['member_no']} and + member_tx_bill.invoice_no != 0 and + member_tx.tx_state not in (". MEMBER_TX_TX_STATE_CANCEL .", ". MEMBER_TX_TX_STATE_STOP .") + order by member_tx_bill.invoice_time asc"; + + $invoice_results = $this->db->query($sql)->result_array(); + + if(!empty($invoice_results)) + { + foreach($invoice_results as $rows) + { + $tx_no = $rows['tx_no']; + if(!array_key_exists($tx_no, $result_tx)) + { + $result_tx[$tx_no] = array(); + } + $result_tx[$tx_no][$rows['tx_bill_no']] = $rows; // 發票記錄 A (tx_no) + //array_push($result_tx[$tx_no], $rows); // 發票記錄 A (tx_no) + + $result_tx_bill[$rows['tx_bill_no']] = $rows; // 發票記錄 B (tx_bill_no) + } + } + + // TEST + //$result['test_rents_arr'] = json_encode($rents_arr, true); + //$result['results_A'] = $result_tx; + //$result['results_B'] = $result_tx_bill; + + // 取得所有交易記錄 + $sql = "select + tx_no, start_date, end_date, start_date_last, end_date_last, + member_attr, fee_period, fee_period_last, amt, amt1, amt_last, deposit, amt_tot, verify_state, remarks + from member_tx + where + member_tx.station_no = {$parms['station_no']} and + member_tx.member_no = {$parms['member_no']} and + member_tx.tx_state not in (". MEMBER_TX_TX_STATE_CANCEL .", ". MEMBER_TX_TX_STATE_STOP .") + order by tx_no asc"; + + $member_tx_results = $this->db->query($sql)->result_array(); + + if(!empty($member_tx_results)) + { + // A. 取得待退金額與相關依據 + $total_amt = 0; + $return_amt = 0; + $return_deposit = 0; + $last_end_date = $parms['stop_date']; + $stop_date_value = strtotime($parms['stop_date']); + $stop_date_time = new DateTime($parms['stop_date']); + foreach($member_tx_results as $rows) + { + $last_end_date = $rows['end_date']; // 暫存最後一筆結束時間 + + // 更新審核狀態 + if($rows['verify_state'] != MEMBER_TX_VERIFY_STATE_OK) + { + $result['verify_state'] = false; // 任何一筆未審核就 gg + } + + $start_date = $rows['start_date']; // 本期開始日 + $end_date = $rows['end_date']; // 本期結束日 + $member_attr = $rows['member_attr']; // 本期身份 + $fee_period = $rows['fee_period']; // 本期繳期 + $deposit = $rows['deposit']; // 首期押金 + $amt1 = $rows['amt1']; // 首期租金 + $amt = $rows['amt']; // 本期租金 + + $stop_used_days_last = 0; // f.1. 首期已使用天數 + $stop_rents_period_amt_last = $amt1; // f.2. 首期繳期金額 + $stop_rents_used_amt_last = 0; // f.3. 首期已消耗金額 + $stop_rents_period = $fee_period; // a.0. 本期試算繳期 + $stop_used_days = 0; // a.1. 本期已使用天數 + $stop_rents_period_amt = $amt; // a.2. 本期繳期金額 + $stop_rents_used_amt = 0; // a.3. 本期已消耗金額 + + // F. 首期金額 + if($amt1 > 0) + { + $start_date_last = $rows['start_date_last']; // 上期開始日 + $end_date_last = $rows['end_date_last']; // 上期結束日 + $fee_period_last = $rows['fee_period_last']; // 上期繳期 + + $start_date_last_time = new DateTime($start_date_last); + if($start_date_last_time > $stop_date_time) + { + // F.1. 首期金額, 沒用過, 完全退費 (預設值) + } + else + { + // 首期開始日早於退租日 + $stop_used_days_last = $stop_date_time->diff($start_date_last_time)->format("%a") + 1; // f.1. 首期已使用天數 + $stop_rents_period_amt_last = $amt1; // f.2. 首期繳期金額 + if(strtotime($end_date_last) < $stop_date_value) + { + // F.2. 首期金額, 完全用盡 + $stop_rents_used_amt_last = $stop_rents_period_amt_last; // f.3. 首期已消耗金額 + } + else + { + // F.3. 首期金額, 尚未用盡, 臨停金額換算 + $in_time = $start_date_last.' 00:00:00'; + $balance_time = $parms['stop_date']. ' 23:59:59'; + $stop_rents_used_amt_last = $this->get_bill($in_time, $balance_time, $parms['station_no']); + } + } + } + + // A. 本期金額 + if(strtotime($start_date) > $stop_date_value) + { + // A.1. 本期金額, 沒用過, 完全退費 (預設值) + } + else if(strtotime($end_date) <= $stop_date_value) + { + // A.3. 本期金額, 完全用盡 + $stop_used_days = $rents_arr[$stop_rents_period][0]; // a.1. 本期已使用天數 + $stop_rents_period_amt = $amt; // a.2. 本期繳期金額 + $stop_rents_used_amt = $stop_rents_period_amt; // a.3. 本期已消耗金額 + } + else + { + // A.2. 本期金額, 用過一部份 + $start_date_time = new DateTime($start_date); + $stop_used_days = $stop_date_time->diff($start_date_time)->format("%a") + 1; // a.1. 本期已使用天數 + if($fee_period > 1) + { + // A.2.a. 使用上一階繳期 + for(; $fee_period >= 1 ; $fee_period--) + { + if(array_key_exists($fee_period, $rents_arr) && $stop_used_days >= $rents_arr[$fee_period][0]) + { + $stop_rents_period = $fee_period; // a.0. 本期試算繳期 + $stop_rents_period_amt = $rents_arr[$stop_rents_period][$member_attr]; // a.2. 本期繳期金額 (根據上一階繳期) + $stop_rents_used_amt = round($stop_rents_period_amt * $stop_used_days / $rents_arr[$stop_rents_period][0]); // a.3. 本期已消耗金額 (根據上一階繳期) + break; + } + } + } + + // A.2.b. 查無適用繳期, 改用臨停金額換算 + if($stop_rents_used_amt == 0) + { + $stop_rents_period = 0; // a.0. 本期試算繳期 (臨停) + $in_time = $start_date.' 00:00:00'; + $balance_time = $parms['stop_date']. ' 23:59:59'; + $stop_rents_period_amt = $this->get_bill($in_time, $balance_time, $parms['station_no']); // a.2. 本期繳期金額 (臨停) + $stop_rents_used_amt = $stop_rents_period_amt; // a.3. 本期已消耗金額 (臨停) + } + } + + $data = $rows; + $data['stop_rents_tot_amt'] = $amt + $amt1; // y. 交易總金額 + $data['stop_rents_return_amt'] = $amt + $amt1 - $stop_rents_used_amt - $stop_rents_used_amt_last; // z. 可退還金額 + $data['stop_used_days_last'] = $stop_used_days_last; // f.1. 首期已使用天數 + $data['stop_rents_period_amt_last'] = $stop_rents_period_amt_last; // f.2. 首期繳期金額 + $data['stop_rents_used_amt_last'] = $stop_rents_used_amt_last; // f.3. 首期已消耗金額 + $data['stop_rents_period'] = $stop_rents_period; // a.0. 本期試算繳期 + $data['stop_used_days'] = $stop_used_days; // a.1. 本期已使用天數 + $data['stop_rents_period_amt'] = $stop_rents_period_amt; // a.2. 本期繳期金額 + $data['stop_rents_used_amt'] = $stop_rents_used_amt; // a.3. 本期已消耗金額 + + // i.1.發票 + $data['stop_rents_invoices'] = array_key_exists($data['tx_no'], $result_tx) ? $result_tx[$data['tx_no']] : array(); + + // R.1. 明細 + $result['results'][$data['tx_no']] = $data; + + $total_amt += $data['stop_rents_tot_amt']; + $return_amt += $data['stop_rents_return_amt']; + $return_deposit += $data['deposit']; + } + + // B. 無待退金額, 補繳臨停金額 + if($return_amt == 0) + { + $in_time = date('Y-m-d', strtotime("+1 days", strtotime($last_end_date))). ' 00:00:00'; // 最後一天開始算臨停 + $balance_time = $parms['stop_date']. ' 23:59:59'; + $return_amt = - $this->get_bill($in_time, $balance_time, $parms['station_no']); + } + + $result['total_amt'] = $total_amt; // R.2. 累計交易總金額 + $result['return_amt'] = $return_amt; // R.3. 累計可退還金額 + + // 2017/04/06 若無首期押金記錄, 由會員身份查詢押金 + if($return_deposit == 0) + { + $member_info = $this->db->select('deposit') + ->from('members') + ->where(array('member_no' => $parms['member_no'])) + ->get() + ->row_array(); + + if(!empty($member_info['deposit'])) + { + trigger_error(__FUNCTION__ . '..get return_deposit 1..' . print_r($parms, true) . ' deposit: ' . $member_info['deposit']); + $return_deposit = $member_info['deposit']; + } + } + + $result['return_deposit'] = $return_deposit; // R.4. 總押金 + + // C. 發票, 折讓或補印 + $result['return_state'] = MEMBER_REFUND_STATE_NONE; // 預設 0 + $result['return_tot_amt'] = $return_amt + $return_deposit; // 總金額 + if($result['return_amt'] > 0) + { + $tmp_amt = $result['return_amt']; // 僅折讓非押金的部份 + + // C.1. 需退還金額 (折讓發票) + foreach($result_tx_bill as $tx_bill_no => $tx_invoice) + { + $refund_amt = 0; + + if($tmp_amt > $tx_invoice['invoice_amt']) + { + // 尚有待折讓金額 + $refund_amt = $tx_invoice['invoice_amt']; + $tmp_amt -= $tx_invoice['invoice_amt']; + } + else + { + // 已無待折讓金額 + $refund_amt = $tmp_amt; + $tmp_amt = 0; + } + //trigger_error("{$tx_bill_no} : {$tmp_amt}, {$refund_amt}"); + $result['results'][$tx_invoice['tx_no']]['stop_rents_invoices'][$tx_bill_no]['refund_amt'] = $refund_amt; + + // 記錄發票折讓資訊 + $result['results_i'][$tx_bill_no] = $result['results'][$tx_invoice['tx_no']]['stop_rents_invoices'][$tx_bill_no]; + + $result['return_state'] = MEMBER_REFUND_STATE_LESS_INVOICE; // 只要有就設為需要折讓 + } + } + else if($result['return_tot_amt'] < 0) + { + // C.2. 需補繳金額 (補印發票) + $result['return_state'] = MEMBER_REFUND_STATE_MORE_INVOICE; + } + + + } + else + { + // Z. 異常 + $result['return_state'] = MEMBER_REFUND_STATE_NONE; // 預設 0 + $result['total_amt'] = 0; // R.2. 累計交易總金額 + $result['return_amt'] = 0; // R.3. 累計可退還金額 + //$result['return_deposit'] = 0; // R.4. 總押金 + + // 2017/04/06 若無首期押金記錄, 由會員身份查詢押金 + $member_info = $this->db->select('deposit') + ->from('members') + ->where(array('member_no' => $parms['member_no'])) + ->get() + ->row_array(); + + if(!empty($member_info['deposit'])) + { + trigger_error(__FUNCTION__ . '..gen return_deposit 2..' . print_r($parms, true) . ' deposit: ' . $member_info['deposit']); + $result['return_deposit'] = $member_info['deposit']; // R.4. 總押金 + $result['return_tot_amt'] = $result['return_deposit']; // 總金額 + } + } + + return $result; + } + + // 押金保留,結清其它金額 (退租後) + public function member_refund_keep_deposit($parms) + { + trigger_error(TX_LOG_TITLE.'押金保留,結清其它金額:' . print_r($parms, true)); + + return $this->do_member_refund_dismiss($parms, MEMBER_REFUND_DISMISS_STATE_KEEP_DEPOSIT); + } + + // 結清所有金額 (退租後) + public function member_refund_dismiss_all($parms) + { + trigger_error(TX_LOG_TITLE.'結清所有金額:' . print_r($parms, true)); + + return $this->do_member_refund_dismiss($parms, MEMBER_REFUND_DISMISS_STATE_DONE); + } + + // [共用] 退租結清共用操作 (退租後) + function do_member_refund_dismiss($parms, $dismiss_state) + { + $this->try_sync_batch($parms['station_no']); // 同步未同步記錄 + + $data = array('dismiss_state' => $dismiss_state); + + // [A.開始] + $this->db->trans_start(); + $this->db->update('member_refund', $data, array('station_no' => $parms['station_no'], 'member_refund_id' => $parms['member_refund_id'])); // t1. 更新 member_refund + + $this->gen_member_refund_log($data, $parms['station_no'], $parms['member_refund_id']); // t.log. 建立 member_refund_log + + // [B.準備同步檔] + $sync_seqnos = $this->prepare_sync2hq('U', $parms['station_no'], 'member_refund', $parms['member_refund_id'], $data); // t2. 準備同步檔 + + // [C.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(__FUNCTION__ . '..trans_error..data:' . print_r($data, true). '| last_query: ' . $this->db->last_query()); + return 'fail'; // 中斷 + } + + // 同步至總管理處 + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + return 'ok'; + } + + // 發票折讓 (退租後) + public function refund_invoice_allowance($parms) + { + $this->try_sync_batch($parms['station_no']); // 同步未同步記錄 + + trigger_error(TX_LOG_TITLE.'發票折讓:' . print_r($parms, true)); + + // 確認 member_tx_bill + $sql = "select + member_tx_bill.tx_bill_no, + member_tx_bill.invoice_track, + member_tx_bill.invoice_no, + member_tx_bill.lpr, + member_tx_bill.member_company_no, + member_tx_bill.company_no, + member_tx_bill.acc_date, + member_tx_bill.refund_amt as amt, + member_tx_bill.invoice_count, + member_tx_bill.invoice_next_date, + member_refund.member_refund_id + from member_tx_bill + LEFT JOIN member_refund ON ( member_refund.member_no = member_tx_bill.member_no and member_refund.station_no = member_tx_bill.station_no ) + WHERE + member_tx_bill.station_no = {$parms['station_no']} and + member_tx_bill.member_no = {$parms['member_no']} and + member_tx_bill.invoice_state = ".MEMBER_TX_BILL_INVOICE_STATE_ALLOWANCE + ; + + $results = $this->db->query($sql)->result_array(); + //trigger_error('test: '. $sql); + + $refund_info = array(); + $count = 0; + foreach($results as $rows) + { + if($rows['tx_bill_no'] == $parms['tx_bill_no']) + { + $refund_info = $rows; + } + $count++; + } + + if(empty($refund_info)) + { + trigger_error(__FUNCTION__ . '..member_tx_bill not found..' . print_r($parms, true)); + return 'tx_error_not_found'; // 中斷 + } + + if($refund_info['invoice_no'] <= 0) + { + trigger_error(__FUNCTION__ . '..member_tx_bill not ready..' . print_r($parms, true)); + return 'tx_error_not_ready'; // 中斷(本期的還沒開立) + } + + // 電子發票折讓介接 + $allowance_parms = array( + 'station_no' => $parms['station_no'], + 'invoice_no' => $refund_info['invoice_track'].str_pad($refund_info['invoice_no'], 8, '0', STR_PAD_LEFT), + 'allowance_amt' => $refund_info['amt'] + ); + $allowance_result = $this->allowance_invoice($allowance_parms); + + if($allowance_result['result_code'] == 'OK') + { + // [A.開始] + $this->db->trans_start(); + + $data_tx_bill = array('invoice_state' => MEMBER_TX_BILL_INVOICE_STATE_ALLOWANCE_DONE); // 折讓完成 + $this->db->update('member_tx_bill', $data_tx_bill, + array('station_no' => $parms['station_no'], 'member_no' => $parms['member_no'], 'tx_bill_no' => $parms['tx_bill_no'])); // t1. 更新 member_tx_bill.invoice_state + + // [B.建立同步檔] + $sync_seqnos = $this->prepare_sync2hq('U', $parms['station_no'], 'member_tx_bill', $parms['tx_bill_no'], $data_tx_bill); // t2. 準備同步檔 (member_tx_bill) + + if($count <= 1) + { + $data_refund = array('refund_state' => MEMBER_REFUND_STATE_DONE); // 完結退租 + $this->db->update('member_refund', $data_refund, + array('station_no' => $parms['station_no'], 'member_refund_id' => $refund_info['member_refund_id'])); // t3. 更新 member_refund.refund_state + + $this->gen_member_refund_log($data_refund, $parms['station_no'], $refund_info['member_refund_id']); // t.log. 建立 member_refund_log + + $sync_seqnos .= ',' . $this->prepare_sync2hq('U', $parms['station_no'], 'member_refund', $refund_info['member_refund_id'], $data_refund); // t4. 準備同步檔 (member_refund) + } + + // [c.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(__FUNCTION__ . '..trans_error..data:' . print_r($data_tx_bill, true). '| last_query: ' . $this->db->last_query()); + return 'fail'; // 中斷 + } + + // 同步至總管理處 + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + return 'ok'; + } + else if(!empty($allowance_result['result_msg'])) + { + return $allowance_result['result_msg']; // 折讓發票失敗 + } + else + { + return '未知的錯誤'; + } + } + + // 交易取消 + public function member_tx_cancel($parms) + { + $this->try_sync_batch($parms['station_no']); // 同步未同步記錄 + + trigger_error(TX_LOG_TITLE.'交易取消:' . print_r($parms, true)); + + // A. 確認交易記錄 + $sql = "select + tx_no, start_date, end_date, start_date_last, end_date_last, fee_period, verify_state, deposit + from member_tx + where station_no = {$parms['station_no']} and member_no = {$parms['member_no']} and tx_state = ".MEMBER_TX_TX_STATE_NONE." + order by tx_no DESC limit 2"; + + $member_tx_results = $this->db->query($sql)->result_array(); + + if(empty($member_tx_results)) + { + trigger_error(__FUNCTION__ . '..tx_error_not_found..' . print_r($parms, true)); + return 'tx_error_not_found'; // 查無記錄 + } + + $member_last_tx = $member_tx_results[0]; // 最後一筆交易 + $member_restore_tx = $member_tx_results[1]; // 倒數一筆交易 + + if($member_last_tx['tx_no'] != $parms['tx_no']) + { + trigger_error(__FUNCTION__ . '..tx_error_not_last..' . print_r($parms, true) . print_r($member_last_tx, true)); + return 'tx_error_not_last'; // 拒絕 (只能由最後一筆記錄開始取消) + } + + $data_member = $this->db->select('*')->from('members') + ->where(array('station_no' => $parms['station_no'], 'member_no' => $parms['member_no'])) + ->get() + ->row_array(); + + if(empty($data_member)) + { + trigger_error(__FUNCTION__ . '..member_not_found..' . print_r($parms, true)); + return 'member_not_found'; // 中斷 + } + + // [A.開始] + $this->db->trans_start(); + + $sync_seqnos = ""; + + if(!empty($member_restore_tx)) + { + // A. 一般取消流程 + $data_member = array( + 'fee_period' => $member_restore_tx['fee_period'], + 'payed_date' => $member_restore_tx['acc_date'], // 付款日 + 'start_date' => "{$member_restore_tx['start_date_last']} 00:00:00", // 開始日 + 'end_date' => "{$member_restore_tx['end_date']} 23:59:59" // 結束日 + ); + $this->db->update('members', $data_member, array('station_no' => $parms['station_no'], 'member_no' => $parms['member_no'])); // t.1a. 更新 members + $this->gen_member_log($data_member, $parms['station_no'], $parms['member_no']); // t.log. 建立 member_log + $this->db->update('member_car', // t.2a. 更新 member_car + array('start_time' => "{$data_member['start_date']} 00:00:00", 'end_time' => "{$data_member['end_date']} 23:59:59"), + array('station_no' => $parms['station_no'], 'member_no' => $parms['member_no'])); + + // [B.建立同步檔] + $sync_seqnos = $this->prepare_sync2hq('U', $parms['station_no'], 'members', $parms['member_no'], $data_member); // t.3a. 準備同步檔 (members) + + $data_tx = array('tx_state' => MEMBER_TX_TX_STATE_CANCEL); // 交易取消 + + $this->db->update('member_tx', $data_tx, + array('station_no' => $parms['station_no'], 'member_no' => $parms['member_no'], 'tx_no' => $parms['tx_no'])); // t4. 更新 member_tx.tx_state + + $this->gen_member_tx_log($data_tx, $parms['station_no'], $parms['tx_no']); // t.log. 建立 member_tx_log + + $sync_seqnos .= ',' . $this->prepare_sync2hq('U', $parms['station_no'], 'member_tx', $parms['tx_no'], $data_tx); // t.5. 準備同步檔 (member_tx) + } + else + { + // 僅有一筆交易,且交易尚未審核 + if($member_last_tx['verify_state'] == MEMBER_TX_VERIFY_STATE_NONE) + { + $data_tx = array('tx_state' => MEMBER_TX_TX_STATE_CANCEL); // 交易取消 + + $this->db->update('member_tx', $data_tx, + array('station_no' => $parms['station_no'], 'member_no' => $parms['member_no'], 'tx_no' => $parms['tx_no'])); // t4. 更新 member_tx.tx_state + + $this->gen_member_tx_log($data_tx, $parms['station_no'], $parms['tx_no']); // t.log. 建立 member_tx_log + + $sync_seqnos = $this->prepare_sync2hq('U', $parms['station_no'], 'member_tx', $parms['tx_no'], $data_tx); // t.5. 準備同步檔 (member_tx) + + // 若此交易有壓金,判定為取消新增會員,進入刪除會員流程 2017/04/16 added + if($member_last_tx['deposit'] > 0) + { + trigger_error(TX_LOG_TITLE.' DELETE members, member_car:' . print_r($parms, true)); + + // B. 第一筆交易, 金額尚未審核, 直接進行刪除流程 + $this->db->delete('members', array('station_no' => $parms['station_no'], 'member_no' => $parms['member_no'])); // t.1b. 刪除 members + $this->gen_member_log($data_member, $parms['station_no'], $parms['member_no']); // t.log. 建立 member_log + $this->db->delete('member_car', array('station_no' => $parms['station_no'], 'member_no' => $parms['member_no'])); // t.2b. 刪除 member_car + + // [B.建立同步檔] + $sync_seqnos.= ',' .$this->prepare_sync2hq('D', $parms['station_no'], 'members', $parms['member_no'], array()); // t.3b. 準備同步檔 (members) + } + + // 若此交易為轉租,判定為取消會員轉租,還原原退租記錄 (TODO: 預設都是全額押金轉租,如果有變化就要改成還原上一個狀態) + if($data_member['refund_transfer_id'] > 0) + { + trigger_error(TX_LOG_TITLE.' RESTORE member_refund' . print_r($data_member, true)); + + $data_refund = array('dismiss_state' => MEMBER_REFUND_DISMISS_STATE_KEEP_DEPOSIT); + $station_no = $data_member['station_no']; + $refund_transfer_id = $data_member['refund_transfer_id']; + + $this->db->update('member_refund', $data_refund, array('station_no' => $station_no, 'member_refund_id' => $refund_transfer_id)); // t8.1 更新 member_refund + + $this->gen_member_refund_log($data_refund, $station_no, $refund_transfer_id); // t.log. 建立 member_refund_log + + $sync_seqnos .= ',' . $this->prepare_sync2hq('U', $station_no, 'member_refund', $refund_transfer_id, $data_refund); // t8. 準備同步檔 (member_refund) + } + + } + else + { + $this->db->trans_complete(); + trigger_error(__FUNCTION__ . '..tx_error_refuse..' . print_r($parms, true)); + return 'tx_error_refuse'; // 中斷 + } + } + + // [c.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(__FUNCTION__ . '..trans_error..data:' . print_r($parms, true). '| last_query: ' . $this->db->last_query()); + return 'fail'; // 中斷 + } + + // 同步至總管理處 + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + return 'ok'; + } + + // 接續開立發票 + public function next_tx_bill($parms, $rents_arr) + { + $this->try_sync_batch($parms['station_no']); // 同步未同步記錄 + + trigger_error(TX_LOG_TITLE.'接續開立發票:' . print_r($parms, true). print_r($rents_arr, true)); + + // 確認上一筆 member_tx_bill + $rows = $this->db->select(' + member_tx_bill.tx_bill_no, + member_tx_bill.invoice_no, + member_tx_bill.lpr, + member_tx_bill.member_company_no, + member_tx_bill.company_no, + member_tx_bill.acc_date, + member_tx_bill.remain_amt as amt, + COALESCE(members.member_attr, 1) as member_attr, + member_tx_bill.invoice_count, + member_tx_bill.invoice_next_date, + member_tx_bill.invoice_state + ') + ->from('member_tx_bill') + ->join('members', 'members.member_no = member_tx_bill.member_no', 'left') + ->where(array( + 'member_tx_bill.tx_bill_no' => $parms['tx_bill_no'], 'member_tx_bill.tx_no' => $parms['tx_no'], + 'member_tx_bill.station_no' => $parms['station_no'], 'member_tx_bill.member_no' => $parms['member_no'], + 'member_tx_bill.remain_amt' => $parms['remain_amt'] + )) + ->get() + ->row_array(); + + if(empty($rows)) + { + trigger_error(__FUNCTION__ . '..member_tx_bill not found..' . print_r($parms, true)); + return 'tx_error_not_found'; // 中斷 + } + + if($rows['invoice_no'] <= 0) + { + trigger_error(__FUNCTION__ . '..member_tx_bill not ready..' . print_r($parms, true)); + return 'tx_error_not_ready'; // 中斷(本期的還沒開立) + } + + if($rows['invoice_count'] <= 1 || empty($rows['invoice_next_date'])) + { + trigger_error(__FUNCTION__ . '..member_tx_bill no next..' . print_r($parms, true)); + return 'tx_error_next'; // 中斷(無下一張資訊) + } + + if(strtotime($rows['invoice_next_date']) > time()) + { + trigger_error(__FUNCTION__ . '..member_tx_bill not yet..' . "next_date:{$rows['invoice_next_date']}" . print_r($parms, true)); + return $rows['invoice_next_date']; // 中斷(時間還沒到) + } + + $next_invoice_count = ($rows['invoice_count'] > 1) ? $rows['invoice_count'] - 1 : 1; + + // 接續發票開立記錄 (公式: 拆分第一期金額) + $invoice_amt = $this->gen_invoice_count_amt($rows['amt'], $next_invoice_count); + $remain_amt = $rows['amt'] - $invoice_amt; + trigger_error(__FUNCTION__ . ', amt:'. $rows['amt']. ', invoice_amt:' .$invoice_amt . ', remain_amt:' . $remain_amt); + + /* + // 接續發票開立記錄 (公式 B: 最多一季金額) + $period_3_amt = ($rents_arr[3][$rows['member_attr']] > 2000) ? $rents_arr[3][$rows['member_attr']] : 2000; // 至少 $2000 + $invoice_amt = ($rows['amt'] > $period_3_amt) ? $period_3_amt : $rows['amt']; + $remain_amt = $rows['amt'] - $invoice_amt; + trigger_error('period_3_amt: ' . $period_3_amt . ', amt:'. $rows['amt']. ', invoice_amt:' .$invoice_amt . ', remain_amt:' . $remain_amt); + */ + + // [A.開始] + $this->db->trans_start(); + $data_tx_bill = array( + 'tx_no' => $parms['tx_no'], // 交易編號 + + 'member_no' => $parms['member_no'], // 會員編號 + 'station_no' => $parms['station_no'], // 場站編號 + 'sync_no' => 0, // 預設同步編號 + + 'lpr' => $rows['lpr'], // 車牌號碼 + + 'member_company_no' => $rows['member_company_no'], // 買方統編 + 'company_no' => $rows['company_no'], // 賣方統編 + + 'acc_date' => $rows['acc_date'], // 入帳日(延用) + + 'invoice_amt' => $invoice_amt, // 本次發票金額 + 'remain_amt' => $remain_amt, // 剩餘未開立金額 + + 'invoice_count' => $next_invoice_count, // 預計發票張數 + + 'invoice_state' => $rows['invoice_state'] // 發票狀態 + ); + + if($next_invoice_count > 1 && !empty($rows['invoice_next_date'])) + { + $data_tx_bill['invoice_next_date'] = $this->gen_invoice_next_date($rows['invoice_next_date']); // 預計下一張發票開立日 + } + + $this->db->insert('member_tx_bill', $data_tx_bill); // t1 新增 member_tx_bill + $tx_bill_no = $this->db->insert_id(); // 帳單序號 + $data_tx_bill['tx_bill_no'] = $tx_bill_no; + + $tx_bill_no_reset = $rows['tx_bill_no']; + $data_tx_bill_reset = array('remain_amt' => 0, 'invoice_count' => 1); + $this->db->update('member_tx_bill', $data_tx_bill_reset, + array('station_no' => $parms['station_no'], 'tx_bill_no' => $tx_bill_no_reset)); // t1.a. 更新 member_tx_bill.remain_amt 為 0 + + // [B.準備同步檔] + $sync_seqnos = $this->prepare_sync2hq('A', $parms['station_no'], 'member_tx_bill', $tx_bill_no, $data_tx_bill); // t2 準備同步檔 (member_tx_bill) + $sync_seqnos .= ',' . $this->prepare_sync2hq('U', $parms['station_no'], 'member_tx_bill', $tx_bill_no_reset, $data_tx_bill_reset); // t2.a 準備同步檔 (member_tx_bill) + + // [c.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(__FUNCTION__ . '..trans_error..data:' . print_r($data_tx_bill, true). '| last_query: ' . $this->db->last_query()); + return 'fail'; // 中斷 + } + + // 同步至總管理處 + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + return 'ok'; + } + + // 停權或啟動 + public function suspended($parms) + { + $this->try_sync_batch($parms['station_no']); // 同步未同步記錄 + + trigger_error(ADMIN_LOG_TITLE.'停權或啟動:' . print_r($parms, true)); + + $altob_admin_submit = $this->input->post('altob_admin_submit', true); // 取得 admin 參數 + if($altob_admin_submit !== $this->gen_admin_ck($parms['station_no'])) + { + trigger_error(__FUNCTION__ . '..altob_admin_submit error..' . print_r($parms, true)); + return 'admin_error'; // 中斷 + } + + $data = array('suspended' => $parms['suspended']); + + // [A.開始] + $this->db->trans_start(); + $this->db->update('members', $data, array('station_no' => $parms['station_no'], 'member_no' => $parms['member_no'])); // t1. 更新 member.suspended + + $this->gen_member_log($data, $parms['station_no'], $parms['member_no']); // t.log. 建立 member_log + + // [B.準備同步檔] + $sync_seqnos = $this->prepare_sync2hq('U', $parms['station_no'], 'members', $parms['member_no'], $data); // t2. 準備同步檔 + // [C.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(__FUNCTION__ . '..trans_error..data:' . print_r($data, true). '| last_query: ' . $this->db->last_query()); + return 'fail'; // 中斷 + } + + // 同步至總管理處 + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + return 'ok'; + } + + // 批次延時 + public function member_tx_check_list_confirm_batch($parms) + { + $this->try_sync_batch($parms['station_no']); // 同步未同步記錄 + + trigger_error(ADMIN_LOG_TITLE.'批次延時:' . print_r($parms, true)); + + $altob_admin_submit = $this->input->post('altob_admin_submit', true); // 取得 admin 參數 + if($altob_admin_submit !== $this->gen_admin_ck($parms['station_no'])) + { + trigger_error(__FUNCTION__ . '..altob_admin_submit error..' . print_r($parms, true)); + return 'admin_error'; // 中斷 + } + + // 建立延時資訊 + if($parms['day'] > 0) + { + $new_valid_time = date('Y-m-d 23:59:59', strtotime("{$this->now_str} + {$parms['day']} days")); + } + else + { + $new_valid_time = date('Y-m-d 23:59:59', strtotime("{$this->now_str} + 1 days")); + } + + trigger_error(__FUNCTION__ . '..start..' . print_r($parms, true) . ', new_valid_time: '. $new_valid_time); + + // [A.開始] + $this->db->trans_start(); + $sync_seqnos = ''; + + // 更新有效期限: 交易記錄 + $tx_no_array = explode(',', $parms['tx_no_str']); + foreach($tx_no_array as $idx => $tx_no) + { + $data_tx = array('valid_time' => $new_valid_time); + $this->db->update('member_tx', $data_tx, array('station_no' => $parms['station_no'], 'tx_no' => $tx_no)); // t1. 更新 member_tx.valid_time + $this->gen_member_tx_log($data_tx, $parms['station_no'], $tx_no); // t.log. 建立 member_tx_log + + if($idx > 0) + { + $sync_seqnos .= ','; + } + + $sync_seqnos .= $this->prepare_sync2hq('U', $parms['station_no'], 'member_tx', $tx_no, $data_tx); // t2. 準備同步檔 (member_tx) + } + + // 更新有效期限: 會員 + $member_no_array = explode(',', $parms['member_no_str']); + foreach($member_no_array as $idx => $member_no) + { + // 取得會員資料 + $member_info = $this->db->select('member_no, valid_time') + ->from('members') + ->where(array('station_no' => $parms['station_no'], 'member_no' => $member_no)) + ->get() + ->row_array(); + + if(empty($member_info)) + { + trigger_error(__FUNCTION__ . '..member not found..' . print_r($parms, true)); + } + else + { + if(strtotime($member_info['valid_time']) >= strtotime($new_valid_time) ) + { + trigger_error(__FUNCTION__ . '..member already got valid_time..' . print_r($member_info, true)); + } + else + { + $data_member = array('valid_time' => $new_valid_time); + $this->db->update('members', $data_member, array('station_no' => $parms['station_no'], 'member_no' => $member_no)); // t3. 更新 members.valid_time + $this->gen_member_log($data_member, $parms['station_no'], $member_no); // t.log. 建立 member_log + + $sync_seqnos .= ',' . $this->prepare_sync2hq('U', $parms['station_no'], 'members', $member_no, $data_member); // t4. 準備同步檔 (members) + } + } + } + + // [C.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(__FUNCTION__ . '..trans_error..data:' . print_r($data, true). '| last_query: ' . $this->db->last_query()); + return 'fail'; // 中斷 + } + + // 同步至總管理處 + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + return 'ok'; + } + + // 設定關帳時間點 + public function set_check_point($parms) + { + $this->try_sync_batch($parms['station_no']); // 同步未同步記錄 + + trigger_error(TX_LOG_TITLE.'設定關帳時間點:' . print_r($parms, true)); + + // 取得上一關帳時間點 + $check_time_last_result = $this->db->select('check_time as check_time_last, check_time_no as check_time_last_no') + ->from('check_points') + ->where(array('station_no' => $parms['station_no'])) + ->order_by("check_time", "desc") + ->get() + ->row_array(); + + $check_time_last = !empty($check_time_last_result['check_time_last']) ? $check_time_last_result['check_time_last'] : '2017-01-01 00:00:00'; + $check_time_last_no = !empty($check_time_last_result['check_time_last_no']) ? $check_time_last_result['check_time_last_no'] : 0; + + // 取得本次關帳時間對應交易編號 + $member_tx_last_result = $this->db->select('tx_no as check_time_no') + ->from('member_tx') + ->where(array( + 'acc_time <= ' => $parms['check_time'], + 'tx_no > ' => $check_time_last_no, + 'station_no' => $parms['station_no'], + 'tx_state' => MEMBER_TX_TX_STATE_NONE + )) + ->order_by("tx_no", "desc") + ->get() + ->row_array(); + + $check_time_no = !empty($member_tx_last_result['check_time_no']) ? $member_tx_last_result['check_time_no'] : 0; + + // 取得上一關帳時間點至本次時間點,金額加總等資訊 + $member_tx_result = $this->db->select('SUM(member_tx.amt) as amt, SUM(member_tx.amt1) as amt1, SUM(member_tx.deposit) as deposit') + ->from('member_tx') + ->where(array( + 'tx_no <= ' => $check_time_no, + 'tx_no > ' => $check_time_last_no, + 'station_no' => $parms['station_no'], + 'tx_state' => MEMBER_TX_TX_STATE_NONE + )) + ->get() + ->row_array(); + + $check_amt = $member_tx_result['amt'] + $member_tx_result['amt1']; + $check_deposit = $member_tx_result['deposit']; + + // 確認金額是否異常 + if(empty($check_amt) && empty($check_deposit)) + { + trigger_error(__FUNCTION__ . '..error_amt..parms:' . print_r($parms, true). '| last_query: ' . $this->db->last_query()); + return 'error_amt'; // 中斷 + } + + trigger_error(__FUNCTION__ . ', check_amt:'. $check_amt. ', check_deposit:' .$check_deposit . + ', check_time:' . $parms['check_time'] . ', check_time_last:' . $check_time_last . + ', check_time_no:' . $check_time_no . ', check_time_last_no:' . $check_time_last_no + ); + + $data_check_point = array( + 'station_no' => $parms['station_no'], + 'check_time' => $parms['check_time'], + 'check_time_no' => $check_time_no, + 'check_time_last' => $check_time_last, + 'check_time_last_no' => $check_time_last_no, + 'check_type' => 1, // 手動關帳 + 'check_amt' => $check_amt, // 總金額 + 'check_deposit' => $check_deposit, // 總押金 + 'remarks' => $parms['remarks'] + ); + + // [A.開始] + $this->db->trans_start(); + $this->db->insert('check_points', $data_check_point); // t1. 新增 check_points + $check_no = $this->db->insert_id(); + $data_check_point['check_no'] = $check_no; + + // [B.準備同步檔] + $sync_seqnos = $this->prepare_sync2hq('A', $parms['station_no'], 'check_points', $data_check_point['check_no'], $data_check_point); // t2. 準備同步檔 + // [C.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(__FUNCTION__ . '..trans_error..data_check_point:' . print_r($data_check_point, true). '| last_query: ' . $this->db->last_query()); + return 'fail'; // 中斷 + } + + // 同步至總管理處 + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + return 'ok'; + } + + // 關帳查詢 + public function check_point_query($parms) + { + $station_no = $parms['station_no']; + $check_point_time_from = $parms['check_point_time_from']; + $check_point_time_to = $parms['check_point_time_to']; + + $sql = "select + check_no, station_no, check_time, check_time_no, check_time_last, check_time_last_no, + check_amt, check_deposit, check_type, remarks, create_time + from check_points + where + station_no = {$station_no} and + check_time >= '{$check_point_time_from}' and + check_time <= '{$check_point_time_to}' + order by check_no desc + "; + + $results = $this->db->query($sql)->result_array(); + + return $results; + } + + // 關帳查詢(明細) + public function check_point_detail_query($parms) + { + $station_no = $parms['station_no']; + $check_time_no = $parms['check_time_no']; + $check_time_last_no = $parms['check_time_last_no']; + + $sql = " + SELECT + members.lpr as current_lpr, + member_tx.lpr, + member_tx.tx_no, + member_tx.station_no, + member_tx.member_no, + member_tx.fee_period, + member_tx.fee_period_last, + member_tx.amt1, + member_tx.amt, + member_tx.amt_last, + member_tx.deposit, + date_format(member_tx.start_date,'%Y-%m-%d') as start_date, + date_format(member_tx.end_date,'%Y-%m-%d') as end_date, + date_format(member_tx.start_date_last,'%Y-%m-%d') as start_date_last, + date_format(member_tx.end_date_last,'%Y-%m-%d') as end_date_last, + member_tx.member_company_no, + member_tx.company_no, + member_tx.acc_date, + member_tx.invoice_no, + member_tx.invoice_amt, + member_tx.invoice_track, + member_tx.invoice_time, + member_tx.invoice_type, + member_tx.verify_state, + member_tx.valid_time, + member_tx.remarks, + member_tx.tx_state + FROM member_tx + LEFT JOIN members ON (member_tx.member_no = members.member_no AND members.station_no = member_tx.station_no) + WHERE + member_tx.station_no = {$station_no} and + member_tx.tx_no <= {$check_time_no} and + member_tx.tx_no > {$check_time_last_no} + ORDER BY member_tx.valid_time ASC + "; + + $results = $this->db->query($sql)->result_array(); + return $results; + } + + // 電子發票查詢 + public function member_invoice_query($parms) + { + $station_no = $parms['station_no']; + $member_invoice_time_from = $parms['member_invoice_time_from']; + $member_invoice_time_to = $parms['member_invoice_time_to']; + + $sql = "select + order_no, amt, station_no, tx_time, tx_type, email, mobile, invoice_no, invoice_remark, status, lpr + from tx_bill_ats + where + station_no = {$station_no} and + tx_time >= '{$member_invoice_time_from}' and + tx_time <= '{$member_invoice_time_to}' and + invoice_no is not NULL + order by tx_time desc + "; + + $results = $this->db->query($sql)->result_array(); + + return $results; + } + + // 電子發票作廢 + public function member_invoice_void($parms) + { + $this->try_sync_batch($parms['station_no']); // 同步未同步記錄 + + trigger_error(TX_LOG_TITLE.'電子發票作廢:' . print_r($parms, true)); + + $void_result = $this->void_invoice($parms); // 作廢發票 + + if($void_result['result_code'] == 'OK') + { + $tx_bill_no = $void_result['tx_bill_no']; + + $data = array + ( + 'member_company_no' => 0, + 'invoice_track' => '', + 'invoice_no' => 0, + 'invoice_time' => NULL, + 'invoice_type' => 0 + ); + + // [A.開始] + $this->db->trans_start(); + $this->db->update('member_tx_bill', $data, array('station_no' => $parms['station_no'], 'tx_bill_no' => $tx_bill_no)); // t1. 更新 member_tx_bill + + trigger_error(TX_LOG_TITLE.'更新發票記錄:' . print_r($data, true) . ', tx_bill_no: '. $tx_bill_no); + + // [B.建立同步檔] + $sync_seqnos = $this->prepare_sync2hq('U', $parms['station_no'], 'member_tx_bill', $tx_bill_no, $data); // t2. 準備同步檔 (member_tx_bill) + + // [C.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(TX_LOG_TITLE.'..trans_error..last_query:' . $this->db->last_query()); + trigger_error(__FUNCTION__ . '..trans_error..data:' . print_r($data, true). '| last_query: ' . $this->db->last_query()); + return 'fail'; // 中斷 + } + + // 同步至總管理處 + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + return 'ok'; + } + else if(!empty($void_result['result_msg'])) + { + return $void_result['result_msg']; // 作廢發票失敗 + } + else + { + return '未知的錯誤'; + } + } + + // 取得未同步資料筆數 + public function get_un_synced_count($station_no) + { + $sql = "select COUNT(*) as count from syncs where synced = 0 and erred = 0 and station_no = {$station_no}"; + $result = $this->db->query($sql)->result_array(); + + if(!empty($result[0])) + return $result[0]; + else + return 0; + } + + // 同步未同步記錄 + public function try_sync_batch($station_no, $limit=5) + { + $sql = "select st_sync_no + from syncs + where synced = 0 and erred = 0 and station_no = {$station_no} + order by st_sync_no ASC + limit {$limit}"; + $results = $this->db->query($sql)->result_array(); + + if(empty($results)) return false; // do nothing + + $sync_seqnos = ''; + foreach($results as $rows) + { + $sync_seqnos .= ',' . $rows['st_sync_no']; + } + $sync_seqnos = ltrim($sync_seqnos, ','); + trigger_error(__FUNCTION__ . '|' . $sync_seqnos); + + // 同步至總管理處 + $this->worker_tx('sync_batch', array('sync_seqnos' => $sync_seqnos)); + } + + // 取得 : 預計下一張發票開立日 + function gen_invoice_next_date($this_date) + { + return date('Y-m-d', strtotime("+3 months", strtotime($this_date))); + } + + // 取得 : 發票拆分金額 + function gen_invoice_count_amt($amt, $count) + { + return round($amt / $count); // 四捨五入 + } + + // 取得 : 預計發票張數 + function gen_invoice_count($fee_period) + { + return ceil($fee_period / 3); + } + + // 產生會員記錄 + function gen_members($data) + { + $this->db->delete('members', array('station_no' => $data['station_no'], 'lpr' => $data['lpr'])); + trigger_error(__FUNCTION__ . ', remove members by lpr: ' . $data['lpr']); + + $this->db->insert('members', $data); + trigger_error(__FUNCTION__ . ', new members: ' . print_r($data, true)); + + return $this->db->insert_id(); + } + + // 產生會員車記錄 + function gen_member_car($data) + { + $this->db->delete('member_car', array('station_no' => $data['station_no'], 'lpr' => $data['lpr'])); + trigger_error(__FUNCTION__ . ', remove member_car by lpr: ' . $data['lpr']); + + $this->db->delete('member_car', array('station_no' => $data['station_no'], 'member_no' => $data['member_no'])); + trigger_error(__FUNCTION__ . ', remove member_car by member_no: ' . $data['member_no']); + + $this->db->insert('member_car', $data); + trigger_error(__FUNCTION__ . ', new member_car: ' . print_r($data, true)); + + return $this->db->insert_id(); + } + + // 產生會員檔記錄 + function gen_member_log($data, $station_no=0, $member_no=0) + { + $data_log = $data; + + if(!empty($station_no)) + $data_log['station_no'] = $station_no; + + if(!empty($member_no)) + $data_log['member_no'] = $member_no; + + $this->db->insert('member_log', $data_log); + return $this->db->insert_id(); + } + + // 產生交易檔記錄 + function gen_member_tx_log($data, $station_no=0, $tx_no=0) + { + $data_log = $data; + + if(!empty($station_no)) + $data_log['station_no'] = $station_no; + + if(!empty($tx_no)) + $data_log['tx_no'] = $tx_no; + + $this->db->insert('member_tx_log', $data_log); + return $this->db->insert_id(); + } + + // 產生退租檔記錄 + function gen_member_refund_log($data, $station_no=0, $member_refund_id=0) + { + $data_log = $data; + + if(!empty($station_no)) + $data_log['station_no'] = $station_no; + + if(!empty($member_refund_id)) + $data_log['member_refund_id'] = $member_refund_id; + + $this->db->insert('member_refund_log', $data_log); + return $this->db->insert_id(); + } + + // 同步至總公司 + function prepare_sync2hq($act, $station_no, $st_tname, $st_seqno, $data) + { + $data_syncs = array + ( + 'station_no' => $station_no, + 'synced' => 0, // 尚未同步 + 'erred' => 0, + 'act' => $act, // A:新增, U:修改, D:刪除 + 'hq_tname' => 'hq_'.$st_tname, + 'st_tname' => $st_tname, // 場站資料表 + 'st_seqno' => $st_seqno, // 場站交易序號 + 'sync_data' => json_encode($data, JSON_UNESCAPED_UNICODE) + ); + $this->db->insert('syncs', $data_syncs); + return $this->db->insert_id(); + } + + // curl送收資料 + function worker_tx($cmd, $data) + { + try + { + $ch = curl_init(); + $curl_options = array + ( + CURLOPT_URL => "http://localhost:60133/?cmd={$cmd}", + CURLOPT_HEADER => 0, + CURLOPT_RETURNTRANSFER => 1, // 返回值不顯示, 只做變數用 + CURLOPT_POST => 1, + CURLOPT_POSTFIELDS => $data + ); + curl_setopt_array($ch, $curl_options); + curl_exec($ch); + curl_close($ch); + } + catch (Exception $e) + { + trigger_error("{$cmd} error: ".$e->getMessage()); + } + } + + // 管理員參數 + function gen_admin_ck($station_no) + { + return md5(date("m \a\l\t\o\b d").$station_no.date("i \z\z\z H")); + } + + // 試算臨停費用 + function get_bill($in_time, $balance_time, $station_no) + { + require_once(ALTOB_BILL_FILE); // 臨停費率 + $oPayment = new AltobPayment(); + $oPayment->ServiceURL = ALTOB_PAYMENT_TXDATA_URL; + + $bill = $oPayment->getBill($in_time, $balance_time, $station_no); + $price = $bill[BillResultKey::price]; + trigger_error(__FUNCTION__ . "|{$station_no}|{$in_time}|{$balance_time}|price:{$price}"); + + return $price; + } + + + // 印發票 + function print_invoice($parms) + { + try{ + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, 'http://localhost/allpay_invoice.html/create_member_tx_bill_invoice'); + curl_setopt($ch, CURLOPT_HEADER, FALSE); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); + curl_setopt($ch, CURLOPT_POST, TRUE); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT ,30); + curl_setopt($ch, CURLOPT_TIMEOUT, 30); //timeout in seconds + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($parms)); + $data = curl_exec($ch); + + if(curl_errno($ch)) + { + trigger_error(__FUNCTION__ . ', curl error: '. curl_error($ch)); + } + + curl_close($ch); + + if(!empty($data)) + { + $data_decode = json_decode($data, true); + + if($data_decode['result_code'] == 'OK') + { + $result = array(); + $result['einvoice_track'] = substr($data_decode['invoice_no'], 0, 2); // 發票字軌 + $result['einvoice_no'] = substr($data_decode['invoice_no'], 2, 8); // 發票號碼 + return $result; + } + } + + }catch (Exception $e){ + trigger_error(__FUNCTION__ . 'error:'.$e->getMessage()); + } + + $result = array(); + $result['einvoice_track'] = ''; // 發票字軌 + $result['einvoice_no'] = ''; // 發票號碼 + return $result; + } + + // 作廢發票 + function void_invoice($parms) + { + try{ + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, 'http://localhost/allpay_invoice.html/void_member_tx_bill_invoice'); + curl_setopt($ch, CURLOPT_HEADER, FALSE); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); + curl_setopt($ch, CURLOPT_POST, TRUE); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT ,30); + curl_setopt($ch, CURLOPT_TIMEOUT, 30); //timeout in seconds + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($parms)); + $data = curl_exec($ch); + + if(curl_errno($ch)) + { + trigger_error(__FUNCTION__ . ', curl error: '. curl_error($ch)); + } + + curl_close($ch); + + if(!empty($data)) + { + $data_decode = json_decode($data, true); + + return $data_decode; + } + + }catch (Exception $e){ + trigger_error(__FUNCTION__ . 'error:'.$e->getMessage()); + } + + return 0; + } + + // 折讓發票 + function allowance_invoice($parms) + { + try{ + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, 'http://localhost/allpay_invoice.html/allowance_member_tx_bill_invoice'); + curl_setopt($ch, CURLOPT_HEADER, FALSE); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); + curl_setopt($ch, CURLOPT_POST, TRUE); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT ,30); + curl_setopt($ch, CURLOPT_TIMEOUT, 30); //timeout in seconds + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($parms)); + $data = curl_exec($ch); + + if(curl_errno($ch)) + { + trigger_error(__FUNCTION__ . ', curl error: '. curl_error($ch)); + } + + curl_close($ch); + + if(!empty($data)) + { + $data_decode = json_decode($data, true); + + return $data_decode; + } + + }catch (Exception $e){ + trigger_error(__FUNCTION__ . 'error:'.$e->getMessage()); + } + + return 0; + } + + /* + // 印發票 + public function print_invoice($parms) + { + $result = array(); + try + { + // 印發票 + $ch = curl_init(); + $curl_options = array + ( + CURLOPT_URL => "http://localhost:60134/", + CURLOPT_HEADER => 0, + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_CONNECTTIMEOUT => 2, + CURLOPT_TIMEOUT => 2, + CURLOPT_POST => 1, + CURLOPT_POSTFIELDS => array( + 'cmd' => 'printInvoice', + 'company_no' => $parms['company_no'], + 'vCUS_COMP_CODE'=> $parms['member_company_no'], + 'vAmount' => $parms['invoice_amt'], + 'vPLU_MEMO' => 'parking:50:3', + 'vTAIL_MESSAGE' => 'Rental' + ) + ); + curl_setopt_array($ch, $curl_options); + $ch_response = curl_exec($ch); + + trigger_error(__FUNCTION__ . '|' . print_r($ch_response, true)); + + curl_close($ch); + + $result = json_decode($ch_response, true); + } + catch (Exception $e) + { + trigger_error(__FUNCTION__ .$e->getMessage()); + } + + //測試用 + //$result['einvoice_track'] = 'AB'; // 發票字軌 + //$result['einvoice_no'] = '12345678'; // 發票號碼 + + return $result; + } + */ + + + + + + +} diff --git a/models/Allpa_service_model.php b/models/Allpa_service_model.php new file mode 100644 index 0000000..ccca4e2 --- /dev/null +++ b/models/Allpa_service_model.php @@ -0,0 +1,1606 @@ +load->database(); + + define('PRODUCT_CODE', "allpa"); // 產品代碼: 歐Pa卡 + define('ADMIN_PRODUCT_CODE', "allpa_admin"); // 產品代碼: 歐Pa卡 (管理者) + + /* + // ----- TWGC 測試環境 ----- + define('TWGC_issuerIdentity', "52856206"); // 發行商認證碼8碼 (測試環境填52856206) + define('TWGC_IssuerID', "20016"); // 發行商代碼,依禮物卡公司與各發行商的約定設定其值 (測試環境填20016) + define('TWGC_StoreID', "001"); // 店號,依禮物卡公司與各發行商的約定設定其值 (測試環境填001) + define('TWGC_POSID', "1"); // 機號,依禮物卡公司與各發行商的約定設定其值 (測試環境填1) + define('TWGC_ServiceURL', "https://issuer-test.twgiftcard.com/TWNGC/WebServices/DataProcessor.asmx"); + // ----- TWGC 測試環境 (END) ----- + */ + + // ----- TWGC 正式環境 ----- + define('TWGC_issuerIdentity', "70876800"); // 發行商認證碼8碼 (測試環境填52856206) + define('TWGC_IssuerID', "20016"); // 發行商代碼,依禮物卡公司與各發行商的約定設定其值 (測試環境填20016) + define('TWGC_StoreID', "A046"); // 店號,依禮物卡公司與各發行商的約定設定其值 (測試環境填001) + define('TWGC_POSID', "1"); // 機號,依禮物卡公司與各發行商的約定設定其值 (測試環境填1) + define('TWGC_ServiceURL', "https://ws.twgiftcard.com/TWNGC/Webservices/DataProcessor.asmx"); + // ----- TWGC 正式環境 (END) ----- + + + // ----- 回傳訊息 ----- + define('ALLPA_RESULT_CODE_OK', "OK"); + define('ALLPA_RESULT_MSG_OK', "成功"); + define('ALLPA_RESULT_CODE_NOT_FOUND', "-1"); + define('ALLPA_RESULT_MSG_NOT_FOUND', "找不到資料"); + define('ALLPA_RESULT_CODE_NOT_DEFINED', "-2"); + define('ALLPA_RESULT_MSG_NOT_DEFINED', "產品資料未定義"); + define('ALLPA_RESULT_CODE_LPR_NOT_FOUND', "-3"); + define('ALLPA_RESULT_MSG_LPR_NOT_FOUND', "找不到車牌"); + define('ALLPA_RESULT_CODE_UNKNOWN_ERROR', "-99"); + define('ALLPA_RESULT_MSG_UNKNOWN_ERROR', "發生未預期錯誤"); + define('ALLPA_RESULT_CODE_ERROR_virtual_card_activation', "-100"); + define('ALLPA_RESULT_CODE_ERROR_get_otpin', "-101"); + define('ALLPA_RESULT_CODE_ERROR_balance_inquiry', "-102"); + define('ALLPA_RESULT_CODE_ERROR_pin_reload', "-103"); + define('ALLPA_RESULT_CODE_ERROR_allpa_register', "-104"); + define('ALLPA_RESULT_CODE_INVALID_CARD', "-200"); + define('ALLPA_RESULT_MSG_INVALID_CARD', "卡片未開通"); + define('ALLPA_RESULT_CODE_INVALID_LPR', "-201"); + define('ALLPA_RESULT_MSG_INVALID_LPR', "車牌已註冊, 是否轉移點數?"); + // -- 內部代碼 -- + define('ALLPA_GO_RESULT_CODE_OK', 0); + define('ALLPA_GO_RESULT_MSG_OK', "成功"); + define('ALLPA_GO_RESULT_CODE_CK_ERROR', 10); + define('ALLPA_GO_RESULT_MSG_CK_ERROR', "CK ERROR"); + define('ALLPA_GO_RESULT_CODE_USER_NOT_FOUND', 11); + define('ALLPA_GO_RESULT_MSG_USER_NOT_FOUND', "查無歐Pa卡用戶"); + define('ALLPA_GO_RESULT_CODE_NO_MONEY', 12); + define('ALLPA_GO_RESULT_MSG_NO_MONEY', "餘額不足"); + define('ALLPA_GO_RESULT_CODE_CONSUME_ERROR', 13); + define('ALLPA_GO_RESULT_MSG_CONSUME_ERROR', "扣款失敗"); + define('ALLPA_GO_RESULT_CODE_DEBT', 14); + define('ALLPA_GO_RESULT_MSG_DEBT', "有欠款"); + define('ALLPA_GO_RESULT_CODE_BILL_NOT_FOUND', 15); + define('ALLPA_GO_RESULT_MSG_BILL_NOT_FOUND', "查無歐Pa卡帳單"); + // ----- 回傳訊息 (END) ----- + } + + // 產生交易序號 + private function gen_trx_no() + { + return time().rand(10000,99999); + } + + // TWGC 回傳字串轉換為值 + private function parse_twgc_number($value) + { + return str_replace( ',', '', (string) $value); + } + + // 判斷錢是否夠扣 + private function is_money_enough($balance, $bonus, $price) + { + return ($balance >= $price || $bonus >= $price || ($balance + $bonus) >= $price); // 點數一律一比一 + } + + // 異常卡片處理 + private function twgc_notfound_handler($result_code, $lpr, $barcode) + { + if($result_code == "-11"){ + // 找不到禮物卡資料 + $data = array(); + $data['status'] = 44; // '狀態: 0:剛建立, 1:啟用中, 2:啟用記名失敗, 4:手動關閉, 44:異常停用, 99:已停用' + $this->db->update('allpa_user', $data, array('lpr' => $lpr, 'barcode' => $barcode)); + } + } + + // TWGC: 消費 + public function allpa_consume($lpr, $barcode, $amount, $order_no) + { + $result = array(); + + // 產生交易序號 + $custTrxNo = $this->gen_trx_no(); + $result["cust_trx_no"] = $custTrxNo; + + // 使用TWGCAgent + $oTWGCAgent = new TWGCAgent(); + $oTWGCAgent->issuerIdentity = TWGC_issuerIdentity; + $oTWGCAgent->IssuerID = TWGC_IssuerID; + $oTWGCAgent->StoreID = TWGC_StoreID; + $oTWGCAgent->POSID = TWGC_POSID; + $oTWGCAgent->ServiceURL = TWGC_ServiceURL; + + try{ + $data = array( + 'CustTrxNo' => $custTrxNo, + 'BarCode' => $barcode, + 'MemberID' => $lpr, + 'Amount' => $amount + ); + + $resultXml = $oTWGCAgent->BalanceMaintenance3($data, TRUE); // 使用紅利點數 + + if($resultXml->RespCode == "00"){ + $result["result_code"] = ALLPA_RESULT_CODE_OK; + $result["result_msg"] = ALLPA_RESULT_MSG_OK; + $result["barcode"] = (string) $resultXml->Barcode; + $result["prev_balance"] = $this->parse_twgc_number($resultXml->PrevBalance);//str_replace( ',', '', (string) $resultXml->PrevBalance); + $result["balance"] = $this->parse_twgc_number($resultXml->Balance);//str_replace( ',', '', (string) $resultXml->Balance); + $result["auth_code"] = (string) $resultXml->AuthCode; + $result["amount_due"] = (string) $resultXml->AmountDue; + $result["bonus"] = $this->parse_twgc_number($resultXml->Bonus);//str_replace( ',', '', (string) $resultXml->Bonus); + + }else{ + $result["result_code"] = (string) $resultXml->RespCode; + $result["result_msg"] = (string) $resultXml->ErrorMessage; + $result["auth_code"] = (string) $resultXml->AuthCodeForInsufficientFund; + } + + }catch (Exception $e){ + trigger_error(__FUNCTION__.', CustTrxNo=>' . $custTrxNo.'
'.$e->getMessage()); + $result["result_code"] = ALLPA_RESULT_CODE_UNKNOWN_ERROR; + $result["result_msg"] = ALLPA_RESULT_MSG_UNKNOWN_ERROR; + $result["auth_code"] = ""; + } + + // API LOG + $data = array(); + $data['cust_trx_no'] = $custTrxNo; + $data['api_no'] = TWGC_API_NO::BalanceMaintenance3; + $data['result_code'] = $result["result_code"]; + $data['result_msg'] = $result["result_msg"]; + $data['auth_code'] = $result["auth_code"]; + $data['barcode'] = $barcode; + $data['order_no'] = $order_no; + $this->db->insert('twgc_api_log', $data); + + return $result; + } + + // TWGC: 卡片綁定 + public function allpa_register($lpr, $barcode) + { + $result = array(); + + // 產生交易序號 + $custTrxNo = $this->gen_trx_no(); + $result["cust_trx_no"] = $custTrxNo; + + // 使用TWGCAgent + $oTWGCAgent = new TWGCAgent(); + $oTWGCAgent->issuerIdentity = TWGC_issuerIdentity; + $oTWGCAgent->IssuerID = TWGC_IssuerID; + $oTWGCAgent->StoreID = TWGC_StoreID; + $oTWGCAgent->POSID = TWGC_POSID; + $oTWGCAgent->ServiceURL = TWGC_ServiceURL; + + try{ + $data = array( + 'CustTrxNo' => $custTrxNo, + 'BarCode' => $barcode, + 'UserID' => $lpr + ); + + $resultXml = $oTWGCAgent->Register($data); + + if($resultXml->RespCode == "00"){ + $result["result_code"] = ALLPA_RESULT_CODE_OK; + $result["result_msg"] = "卡片綁定完成"; + $result["register_barcode"] = $barcode; + $result["register_lpr"] = $lpr; + $result["register_no"] = $custTrxNo; + + }else{ + $result["result_code"] = (string) $resultXml->RespCode; + $result["result_msg"] = (string) $resultXml->ErrorMessage; + } + + }catch (Exception $e){ + trigger_error(__FUNCTION__.', CustTrxNo=>' . $custTrxNo.'
'.$e->getMessage()); + $result["result_code"] = ALLPA_RESULT_CODE_UNKNOWN_ERROR; + $result["result_msg"] = ALLPA_RESULT_MSG_UNKNOWN_ERROR; + } + + // API LOG + $data = array(); + $data['cust_trx_no'] = $custTrxNo; + $data['api_no'] = TWGC_API_NO::Register; + $data['result_code'] = $result["result_code"]; + $data['result_msg'] = $result["result_msg"]; + $data['barcode'] = $barcode; + $this->db->insert('twgc_api_log', $data); + + return $result; + } + + // TWGC: 虛擬卡開卡 + public function virtual_card_activation($cardEAN, $amount, $order_no) + { + $result = array(); + + // 產生交易序號 + $custTrxNo = $this->gen_trx_no(); + $result["cust_trx_no"] = $custTrxNo; + + // 使用TWGCAgent + $oTWGCAgent = new TWGCAgent(); + $oTWGCAgent->issuerIdentity = TWGC_issuerIdentity; + $oTWGCAgent->IssuerID = TWGC_IssuerID; + $oTWGCAgent->StoreID = TWGC_StoreID; + $oTWGCAgent->POSID = TWGC_POSID; + $oTWGCAgent->ServiceURL = TWGC_ServiceURL; + + try{ + $data = array( + 'CustTrxNo' => $custTrxNo, + 'EAN' => $cardEAN, + 'Amount' => $amount + ); + + $resultXml = $oTWGCAgent->VirtualCardActivation($data); + + if($resultXml->Detail->Card->RespCode == "00"){ // 白目的結構 + $result["result_code"] = ALLPA_RESULT_CODE_OK; + $result["result_msg"] = "開卡完成"; + $result["barcode"] = (string) $resultXml->Detail->Card->Barcode; + $result["amount"] = $this->parse_twgc_number($resultXml->Detail->Card->Amount);//str_replace( ',', '', (string) $resultXml->Detail->Card->Amount); + + }else{ + $result["result_code"] = (string) $resultXml->RespCode; + $result["result_msg"] = (string) $resultXml->ErrorMessage; + } + + }catch (Exception $e){ + trigger_error(__FUNCTION__.', CustTrxNo=>' . $custTrxNo.'
'.$e->getMessage()); + $result["result_code"] = ALLPA_RESULT_CODE_UNKNOWN_ERROR; + $result["result_msg"] = ALLPA_RESULT_MSG_UNKNOWN_ERROR; + } + + // API LOG + $data = array(); + $data['cust_trx_no'] = $custTrxNo; + $data['api_no'] = TWGC_API_NO::VirtualCardActivation; + $data['result_code'] = $result["result_code"]; + $data['result_msg'] = $result["result_msg"]; + $data['order_no'] = $order_no; + $this->db->insert('twgc_api_log', $data); + + return $result; + } + + // TWGC: 取得儲值的PIN碼 + public function get_otpin($barcode, $order_no) + { + $result = array(); + + // 產生交易序號 + $custTrxNo = $this->gen_trx_no(); + $result["cust_trx_no"] = $custTrxNo; + + // 使用TWGCAgent + $oTWGCAgent = new TWGCAgent(); + $oTWGCAgent->issuerIdentity = TWGC_issuerIdentity; + $oTWGCAgent->IssuerID = TWGC_IssuerID; + $oTWGCAgent->StoreID = TWGC_StoreID; + $oTWGCAgent->POSID = TWGC_POSID; + $oTWGCAgent->ServiceURL = TWGC_ServiceURL; + + try{ + $data = array( + 'BarCode' => $barcode, + 'Size' => 'S' // *Size:回傳圖檔大小 (L/M/S) + ); + + $resultXml = $oTWGCAgent->GetOTPin2($data); + + if($resultXml->RespCode == "00"){ + $result["result_code"] = ALLPA_RESULT_CODE_OK; + $result["result_msg"] = ALLPA_RESULT_MSG_OK; + $result["password_type"] = (string) $resultXml->PasswordType; // PasswordType:不處理 + $result["encoded_pic"] = (string) $resultXml->EncodedPIC; // EncodedPIC:密碼圖檔,以base64編碼 (文件少一個 d) + $result["valid_time"] = (string) $resultXml->ValidTime; // ValidTime:密碼有效時間 (分) + $result["valid_before"] = date('Y-m-d H:i:s', strtotime((string) $resultXml->ValidBefore)); // ValidBefore:相對於上傳的本機時間, 密碼到期時間 + + }else{ + $result["result_code"] = (string) $resultXml->RespCode; + $result["result_msg"] = (string) $resultXml->ErrorMessage; + } + + }catch (Exception $e){ + trigger_error(__FUNCTION__.', barcode=>' . $barcode.'
'.$e->getMessage()); + $result["result_code"] = ALLPA_RESULT_CODE_UNKNOWN_ERROR; + $result["result_msg"] = ALLPA_RESULT_MSG_UNKNOWN_ERROR; + } + + // API LOG + $data = array(); + $data['cust_trx_no'] = $custTrxNo; + $data['api_no'] = TWGC_API_NO::GetOTPin2; + $data['result_code'] = $result["result_code"]; + $data['result_msg'] = $result["result_msg"]; + $data['order_no'] = $order_no; + $data['barcode'] = $barcode; + $this->db->insert('twgc_api_log', $data); + + return $result; + } + + // TWGC: PIN 儲值 + public function pin_reload($pin, $amount, $order_no, $barcode) + { + $result = array(); + + // 產生交易序號 + $custTrxNo = $this->gen_trx_no(); + $result["cust_trx_no"] = $custTrxNo; + + // 使用TWGCAgent + $oTWGCAgent = new TWGCAgent(); + $oTWGCAgent->issuerIdentity = TWGC_issuerIdentity; + $oTWGCAgent->IssuerID = TWGC_IssuerID; + $oTWGCAgent->StoreID = TWGC_StoreID; + $oTWGCAgent->POSID = TWGC_POSID; + $oTWGCAgent->ServiceURL = TWGC_ServiceURL; + + try{ + $data = array( + 'CustTrxNo' => $custTrxNo, + 'Amount' => $amount, + 'PIN' => $pin + ); + + $resultXml = $oTWGCAgent->Reload2($data); + + if($resultXml->RespCode == "00"){ + $result["result_code"] = ALLPA_RESULT_CODE_OK; + $result["result_msg"] = ALLPA_RESULT_MSG_OK; + $result["auth_code"] = (string) $resultXml->AuthCode; // 授權碼 + $result["prev_balance"] = $this->parse_twgc_number($resultXml->PrevBalance);//str_replace( ',', '', (string) $resultXml->PrevBalance); // 卡片儲值前餘額 + $result["balance"] = $this->parse_twgc_number($resultXml->Balance);//str_replace( ',', '', (string) $resultXml->Balance); // 卡片儲值後新餘額 + + }else{ + $result["result_code"] = (string) $resultXml->ErrorCode; + $result["result_msg"] = (string) $resultXml->ErrorMessage; + $result["auth_code"] = ""; + } + + }catch (Exception $e){ + trigger_error(__FUNCTION__.', custTrxNo=>' . $custTrxNo.'
'.$e->getMessage()); + $result["result_code"] = ALLPA_RESULT_CODE_UNKNOWN_ERROR; + $result["result_msg"] = ALLPA_RESULT_MSG_UNKNOWN_ERROR; + $result["auth_code"] = ""; + } + + // API LOG + $data = array(); + $data['cust_trx_no'] = $custTrxNo; + $data['api_no'] = TWGC_API_NO::Reload2; + $data['result_code'] = $result["result_code"]; + $data['result_msg'] = $result["result_msg"]; + $data['auth_code'] = $result["auth_code"]; + $data['order_no'] = $order_no; + $data['barcode'] = $barcode; + $this->db->insert('twgc_api_log', $data); + + return $result; + } + + // TWGC: 查詢 barcode + public function balance_inquiry($barcode, $order_no=NULL) + { + $result = array(); + + // 產生交易序號 + $custTrxNo = $this->gen_trx_no(); + $result["cust_trx_no"] = $custTrxNo; + + // 使用TWGCAgent + $oTWGCAgent = new TWGCAgent(); + $oTWGCAgent->issuerIdentity = TWGC_issuerIdentity; + $oTWGCAgent->IssuerID = TWGC_IssuerID; + $oTWGCAgent->StoreID = TWGC_StoreID; + $oTWGCAgent->POSID = TWGC_POSID; + $oTWGCAgent->ServiceURL = TWGC_ServiceURL; + + try{ + $data = array( + 'CustTrxNo' => $custTrxNo, + 'BarCode' => $barcode + ); + + $resultXml = $oTWGCAgent->BalanceInquiry($data); + + if($resultXml->RespCode == "00"){ + $result["result_code"] = ALLPA_RESULT_CODE_OK; + $result["result_msg"] = ALLPA_RESULT_MSG_OK; + $result["van19"] = (string) $resultXml->Detail->Card->VAN19; + $result["balance"] = $this->parse_twgc_number($resultXml->Detail->Card->Balance);//str_replace( ',', '', (string) $resultXml->Detail->Card->Balance); + $result["status_code"] = (string) $resultXml->Detail->Card->StatusCode; + $result["card_status"] = (string) $resultXml->Detail->Card->CardStatus; + $result["bonus"] = $this->parse_twgc_number($resultXml->Detail->Card->Bonus);//str_replace( ',', '', (string) $resultXml->Detail->Card->Bonus); + $result["cash_per_point"] = (string) $resultXml->Detail->Card->CashPerPoint; + + }else{ + $result["result_code"] = (string) $resultXml->RespCode; + $result["result_msg"] = (string) $resultXml->ErrorMessage; + } + + }catch (Exception $e){ + trigger_error(__FUNCTION__.', custTrxNo=>' . $custTrxNo.'
'.$e->getMessage()); + $result["result_code"] = ALLPA_RESULT_CODE_UNKNOWN_ERROR; + $result["result_msg"] = ALLPA_RESULT_MSG_UNKNOWN_ERROR; + } + + // API LOG + $data = array(); + $data['cust_trx_no'] = $custTrxNo; + $data['api_no'] = TWGC_API_NO::BalanceInquiry; + $data['result_code'] = $result["result_code"]; + $data['result_msg'] = $result["result_msg"]; + $data['order_no'] = $order_no; + $data['barcode'] = $barcode; + $this->db->insert('twgc_api_log', $data); + + return $result; + } + + // 新增卡片使用記錄 (開卡) + public function create_allpa_init_log($cust_trx_no, $lpr, $barcode, $order_no) + { + $this->create_allpa_log($cust_trx_no, $lpr, $barcode, "01", 0, 0, $order_no, 0); // 訂單種類: 0:開卡, 1:儲值, 2:扣款, 10:實體卡記名, 44:未知 + } + + // 新增卡片使用記錄 (儲值) + public function create_allpa_reload_log($cust_trx_no, $lpr, $barcode, $pre_status_code, $pre_balance, $pre_bonus, $order_no) + { + $this->create_allpa_log($cust_trx_no, $lpr, $barcode, $pre_status_code, $pre_balance, $pre_bonus, $order_no, 1); // 訂單種類: 0:開卡, 1:儲值, 2:扣款, 10:實體卡記名, 44:未知 + } + + // 新增卡片使用記錄 (扣款) + public function create_allpa_consume_log($cust_trx_no, $lpr, $barcode, $pre_status_code, $pre_balance, $pre_bonus, $order_no) + { + $this->create_allpa_log($cust_trx_no, $lpr, $barcode, $pre_status_code, $pre_balance, $pre_bonus, $order_no, 2); // 訂單種類: 0:開卡, 1:儲值, 2:扣款, 10:實體卡記名, 44:未知 + } + + // 新增卡片使用記錄 (實體卡記名) + public function create_allpa_card_register_log($cust_trx_no, $lpr, $barcode) + { + $this->create_allpa_log($cust_trx_no, $lpr, $barcode, "01", 0, 0, 0, 10); // 訂單種類: 0:開卡, 1:儲值, 2:扣款, 10:實體卡記名, 44:未知 + } + + // 新增卡片使用記錄 (未知) + public function create_allpa_unknown_log($cust_trx_no, $lpr, $barcode, $pre_status_code, $pre_balance, $pre_bonus, $order_no) + { + $this->create_allpa_log($cust_trx_no, $lpr, $barcode, $pre_status_code, $pre_balance, $pre_bonus, $order_no, 44); // 訂單種類: 0:開卡, 1:儲值, 2:扣款, 10:實體卡記名, 44:未知 + } + + // 新增卡片使用記錄 + private function create_allpa_log($cust_trx_no, $lpr, $barcode, $pre_status_code, $pre_balance, $pre_bonus, $order_no, $order_type) + { + $data = array(); + // 重新查詢一次 + $balance_inquiry_result = $this->balance_inquiry($barcode); + if($balance_inquiry_result["result_code"] == ALLPA_RESULT_CODE_OK){ + $data['status_code'] = $balance_inquiry_result["status_code"]; + $data['balance'] = $balance_inquiry_result["balance"]; + $data['bonus'] = $balance_inquiry_result["bonus"]; + }else{ + $data['status_code'] = $pre_status_code; + $data['balance'] = $pre_balance; + $data['bonus'] = $pre_bonus; + } + // 更新用戶資訊 + $this->db->update('allpa_user', $data, array('lpr' => $lpr, 'barcode' => $barcode)); + + // 更新使用記錄 + $data["cust_trx_no"] = $cust_trx_no; + $data['lpr'] = $lpr; + $data['barcode'] = $barcode; + $data['pre_status_code'] = $pre_status_code; + $data['pre_balance'] = $pre_balance; + $data['pre_bonus'] = $pre_bonus; + $data['order_no'] = $order_no; + $data['order_type'] = $order_type; + $this->db->insert('allpa_balance_log', $data); + } + + // 儲值 + public function allpa_reload($order_no, $pin, $pin_check_id) + { + $check_result = $this->db->select('allpa_pin_check.lpr as lpr, allpa_pin_check.barcode as barcode, product_bill.product_plan as product_plan') + ->from('allpa_pin_check') + ->join('product_bill', 'allpa_pin_check.order_no = product_bill.order_no', 'left') + ->where(array( + 'allpa_pin_check.allpa_pin_check_id' => $pin_check_id, + 'allpa_pin_check.order_no' => $order_no, + 'product_bill.status' => 1)) // '狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中, 111:產品已領取' + ->limit(1) + ->get() + ->row_array(); + + // 查無結帳記錄 + if(empty($check_result)){ + $result = array(); + $result["result_code"] = ALLPA_RESULT_CODE_NOT_FOUND; + $result["result_msg"] = ALLPA_RESULT_MSG_NOT_FOUND; + return $result; // NOT FOUND + } + + // 產品內容未定義 + if (empty($check_result['product_plan'])) + { + $result = array(); + $result["result_code"] = ALLPA_RESULT_CODE_NOT_DEFINED; + $result["result_msg"] = ALLPA_RESULT_MSG_NOT_DEFINED; + return $result; // NOT DEFINED + } + + $lpr = $check_result['lpr']; + $barcode = $check_result['barcode']; + $product_plan = json_decode($check_result['product_plan'], true); + $cardEAN = $product_plan["EAN"]; + $cardAmount = $product_plan["Amount"]; + + // 查遠端餘額 + $pre_status_code = ""; + $pre_balance = 0; + $pre_bonus = 0; + $balance_inquiry_result = $this->balance_inquiry($barcode); + if($balance_inquiry_result["result_code"] == ALLPA_RESULT_CODE_OK){ + $pre_status_code = $balance_inquiry_result["status_code"]; + $pre_balance = $balance_inquiry_result["balance"]; + $pre_bonus = $balance_inquiry_result["bonus"]; + }else{ + // 未知卡片處理 + $this->twgc_notfound_handler($balance_inquiry_result["result_code"], $lpr, $barcode); + + // 查詢barcode失敗 + $result = array(); + $result["result_code"] = ALLPA_RESULT_CODE_ERROR_balance_inquiry; + $result["result_msg"] = $balance_inquiry_result["result_msg"]; + return $result; + } + + // 查本地餘額 + $recent_balance_log = $this->db->select('status_code, balance, bonus') + ->from('allpa_balance_log') + ->where(array('lpr' => $lpr, 'barcode' => $barcode)) + ->order_by("create_time", "desc") + ->limit(1) + ->get() + ->row_array(); + + // 檢記錄是否出現未知斷層 + if( $pre_status_code != $recent_balance_log["status_code"] || + $pre_balance != $recent_balance_log["balance"] || + $pre_bonus != $recent_balance_log["bonus"]) { + $unknown_trx_no = $this->gen_trx_no(); + // 產生一筆未知的balance_log + $this->create_allpa_unknown_log( + $unknown_trx_no, $lpr, $barcode, + $recent_balance_log["status_code"], $recent_balance_log["balance"], $recent_balance_log["bonus"], + $order_no); + } + + // 開始儲值 + $pin_reload_result = $this->pin_reload($pin, $cardAmount, $order_no, $barcode); + + if($pin_reload_result["result_code"] == ALLPA_RESULT_CODE_OK){ + // 已領取 + $this->transfer_money_done_and_finished($order_no); + + // 新增卡片使用記錄 + $this->create_allpa_reload_log( + $pin_reload_result["cust_trx_no"], $lpr, $barcode, + $pre_status_code, $pre_balance, $pre_bonus, + $order_no); + + // 跳到顯示個資的流程?? + return $this->get_allpa_info($lpr); + + }else{ + // 儲值barcode失敗 + $result = array(); + $result["result_code"] = ALLPA_RESULT_CODE_ERROR_pin_reload; + $result["result_msg"] = $pin_reload_result["result_msg"]; + return $result; + } + } + + // 卡片記名 + public function card_register($lpr, $barcode) + { + $user = $this->get_valid_user($lpr); + + if(empty($user)){ + // 新開立 + $allpa_register_result = $this->allpa_register($lpr, $barcode); + + if($allpa_register_result["result_code"] == ALLPA_RESULT_CODE_OK){ + $data = array(); + $data['lpr'] = $lpr; + $data['barcode'] = $barcode; + $data['status'] = 1; // '狀態: 0:剛建立, 1:啟用中, 2:啟用記名失敗, 99:已停用' + $this->db->insert('allpa_user', $data); + + // 新增卡片記名記錄 + $this->create_allpa_card_register_log($allpa_register_result["cust_trx_no"], $lpr, $barcode); + + // 跳到顯示個資的流程?? + return $this->get_allpa_info($lpr); + + }else{ + // 記名失敗 + $result = array(); + $result["result_code"] = ALLPA_RESULT_CODE_ERROR_allpa_register; + $result["result_msg"] = $allpa_register_result["result_msg"]; + return $result; + } + + }else{ + // 車牌已註冊, 詢問點數移轉 + $result = array(); + $result["result_code"] = ALLPA_RESULT_CODE_INVALID_LPR; + $result["result_msg"] = ALLPA_RESULT_MSG_INVALID_LPR; + return $result; + } + } + + // 領貨 (新帳號, 開卡, 記名) + public function activate_bill_for_new_register($order_no) + { + $bill = $this->db->select('order_no, lpr, product_bill.product_plan as product_plan, tx_time, product_name, product_desc, remarks') + ->from('product_bill') + ->join('products', 'products.product_id = product_bill.product_id', 'left') + ->where(array('order_no' => $order_no, 'status' => 1)) // '狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中, 111:產品已領取' + ->limit(1) + ->get() + ->row_array(); + + if(empty($bill)) + { + $result = array(); + $result["result_code"] = ALLPA_RESULT_CODE_NOT_FOUND; + $result["result_msg"] = ALLPA_RESULT_MSG_NOT_FOUND; + return $result; // NOT FOUND + } + + if (empty($bill['product_plan'])) + { + $result = array(); + $result["result_code"] = ALLPA_RESULT_CODE_NOT_DEFINED; + $result["result_msg"] = ALLPA_RESULT_MSG_NOT_DEFINED; + return $result; // NOT DEFINED + } + + if (empty($bill['lpr'])) + { + $result = array(); + $result["result_code"] = ALLPA_RESULT_CODE_LPR_NOT_FOUND; + $result["result_msg"] = ALLPA_RESULT_MSG_LPR_NOT_FOUND; + return $result; // 車牌 NOT FOUND + } + + $lpr = $bill['lpr']; + $product_name = $bill['product_name']; + $product_desc = $bill['product_desc']; + $remarks = $bill['remarks']; + $product_plan = json_decode($bill['product_plan'], true); + $cardEAN = $product_plan["EAN"]; + $cardAmount = $product_plan["Amount"]; + $userAmount = 0; + + // 取得有效用戶 + $user = $this->get_valid_user($lpr); + + if(empty($user)){ + // A. 新帳號, 開卡 + $virtual_card_activation_result = $this->virtual_card_activation($cardEAN, $cardAmount, $order_no); + + if($virtual_card_activation_result["result_code"] == ALLPA_RESULT_CODE_OK){ + // 開卡完成 + $barcode = $virtual_card_activation_result["barcode"]; + $amount = $virtual_card_activation_result["amount"]; + $custTrxNo = $virtual_card_activation_result["cust_trx_no"]; + + // 卡片記名 + $allpa_register_result = $this->allpa_register($lpr, $barcode); + + if($allpa_register_result["result_code"] == ALLPA_RESULT_CODE_OK){ + $data = array(); + $data['lpr'] = $lpr; + $data['barcode'] = $barcode; + $data['status'] = 1; // '狀態: 0:剛建立, 1:啟用中, 2:啟用記名失敗, 99:已停用' + $this->db->insert('allpa_user', $data); + }else{ + $data = array(); + $data['lpr'] = $lpr; + $data['barcode'] = $barcode; + $data['status'] = 2; // '狀態: 0:剛建立, 1:啟用中, 2:啟用記名失敗, 99:已停用' + $this->db->insert('allpa_user', $data); + } + + // 訂單編號, 已領取 + $this->transfer_money_done_and_finished($order_no); + + // 新增卡片使用記錄 + $this->create_allpa_init_log($custTrxNo, $lpr, $barcode, $order_no); + + // 成功 + $result = array(); + $result["result_code"] = ALLPA_RESULT_CODE_OK; + $result["result_msg"] = ALLPA_RESULT_MSG_OK; + return $result; + + }else{ + // 開卡失敗 + $result = array(); + $result["result_code"] = ALLPA_RESULT_CODE_ERROR_virtual_card_activation; + $result["result_msg"] = $virtual_card_activation_result["result_msg"]; + return $result; + } + + }else{ + // 車牌已註冊, 詢問點數移轉 + $result = array(); + $result["result_code"] = ALLPA_RESULT_CODE_INVALID_LPR; + $result["result_msg"] = ALLPA_RESULT_MSG_INVALID_LPR; + return $result; + } + } + + // 領貨 (通用) + public function activate_bill($order_no) + { + $bill = $this->db->select('order_no, lpr, product_bill.product_plan as product_plan, tx_time, product_name, product_desc, remarks') + ->from('product_bill') + ->join('products', 'products.product_id = product_bill.product_id', 'left') + ->where(array('order_no' => $order_no, 'status' => 1)) // '狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中, 111:產品已領取' + ->limit(1) + ->get() + ->row_array(); + + if(empty($bill)){ + $result = array(); + $result["result_code"] = ALLPA_RESULT_CODE_NOT_FOUND; + $result["result_msg"] = ALLPA_RESULT_MSG_NOT_FOUND; + return $result; // NOT FOUND + } + + if (empty($bill['product_plan'])) + { + $result = array(); + $result["result_code"] = ALLPA_RESULT_CODE_NOT_DEFINED; + $result["result_msg"] = ALLPA_RESULT_MSG_NOT_DEFINED; + return $result; // NOT DEFINED + } + + if (empty($bill['lpr'])) + { + $result = array(); + $result["result_code"] = ALLPA_RESULT_CODE_LPR_NOT_FOUND; + $result["result_msg"] = ALLPA_RESULT_MSG_LPR_NOT_FOUND; + return $result; // 車牌 NOT FOUND + } + + $lpr = $bill['lpr']; + $product_name = $bill['product_name']; + $product_desc = $bill['product_desc']; + $remarks = $bill['remarks']; + $product_plan = json_decode($bill['product_plan'], true); + $cardEAN = $product_plan["EAN"]; + $cardAmount = $product_plan["Amount"]; + $userAmount = 0; + + // 取得有效用戶 + $user = $this->get_valid_user($lpr); + + if(empty($user)){ + // A. 新帳號, 開卡 + $virtual_card_activation_result = $this->virtual_card_activation($cardEAN, $cardAmount, $order_no); + + if($virtual_card_activation_result["result_code"] == ALLPA_RESULT_CODE_OK){ + // 開卡完成 + $barcode = $virtual_card_activation_result["barcode"]; + $amount = $virtual_card_activation_result["amount"]; + $custTrxNo = $virtual_card_activation_result["cust_trx_no"]; + + // 卡片記名 + $allpa_register_result = $this->allpa_register($lpr, $barcode); + + if($allpa_register_result["result_code"] == ALLPA_RESULT_CODE_OK){ + $data = array(); + $data['lpr'] = $lpr; + $data['barcode'] = $barcode; + $data['status'] = 1; // '狀態: 0:剛建立, 1:啟用中, 2:啟用記名失敗, 99:已停用' + $this->db->insert('allpa_user', $data); + }else{ + $data = array(); + $data['lpr'] = $lpr; + $data['barcode'] = $barcode; + $data['status'] = 2; // '狀態: 0:剛建立, 1:啟用中, 2:啟用記名失敗, 99:已停用' + $this->db->insert('allpa_user', $data); + } + + // 訂單編號, 已領取 + $this->transfer_money_done_and_finished($order_no); + + // 新增卡片使用記錄 + $this->create_allpa_init_log($custTrxNo, $lpr, $barcode, $order_no); + + // 跳到顯示個資的流程?? + return $this->get_allpa_info($lpr); + + }else{ + // 開卡失敗 + $result = array(); + $result["result_code"] = ALLPA_RESULT_CODE_ERROR_virtual_card_activation; + $result["result_msg"] = $virtual_card_activation_result["result_msg"]; + return $result; + } + + }else{ + $barcode = $user["barcode"]; + + // B.1 查詢barcode + $balance_inquiry_result = $this->balance_inquiry($barcode, $order_no); + + if($balance_inquiry_result["result_code"] == ALLPA_RESULT_CODE_OK){ + if($balance_inquiry_result["status_code"] == "01"){ + $userAmount = $balance_inquiry_result["balance"]; // 目前卡片餘額 + + }else{ + // 卡片未開通 + $result = array(); + $result["result_code"] = ALLPA_RESULT_CODE_INVALID_CARD; + $result["result_msg"] = ALLPA_RESULT_MSG_INVALID_CARD." : ".$result["card_status"]; + return $result; + } + + }else{ + // 未知卡片處理 + $this->twgc_notfound_handler($balance_inquiry_result["result_code"], $lpr, $barcode); + + // 查詢barcode失敗 + $result = array(); + $result["result_code"] = ALLPA_RESULT_CODE_ERROR_balance_inquiry; + $result["result_msg"] = $balance_inquiry_result["result_msg"]; + return $result; + } + + // B.2 取得儲值的PIN碼 + $get_otpin_result = $this->get_otpin($barcode, $order_no); + + if($get_otpin_result["result_code"] == ALLPA_RESULT_CODE_OK){ + $password_type = $get_otpin_result["password_type"]; // PasswordType:不處理 + $encoded_pic = $get_otpin_result["encoded_pic"]; // EncodedPIC:密碼圖檔,以base64編碼 (文件少一個 d); + $valid_time = $get_otpin_result["valid_time"]; // ValidTime:密碼有效時間 (分) + $valid_before = $get_otpin_result["valid_before"]; // ValidBefore:相對於上傳的本機時間, 密碼到期時間 + + // 建立PIN CHECK + $data = array(); + $data['lpr'] = $lpr; + $data['barcode'] = $barcode; + $data['order_no'] = $order_no; + $data['password_type'] = $password_type; + $data['valid_time'] = $valid_time; + $data['valid_before'] = $valid_before; + $this->db->insert('allpa_pin_check', $data); + $pin_check_id = $this->db->insert_id(); + + // 回傳 + $result = array(); + $result['pin_check_id'] = $pin_check_id; + $result['lpr'] = $lpr; + $result['barcode'] = $barcode; + $result['order_no'] = $order_no; + $result['product_name'] = $product_name; + $result['product_desc'] = $product_desc; + $result['remarks'] = $remarks; + $result["amount_before"] = $userAmount; + $result['amt'] = $cardAmount; + $result["encoded_pic"] = $encoded_pic; + $result["valid_before"] = $valid_before; + $result["result_code"] = ALLPA_RESULT_CODE_OK; + $result["result_msg"] = ALLPA_RESULT_MSG_OK; + return $result; + + }else{ + // 取得儲值的PIN碼失敗 + $result = array(); + $result["result_code"] = ALLPA_RESULT_CODE_ERROR_get_otpin; + $result["result_msg"] = $get_otpin_result["result_msg"]; + return $result; + } + } + + } + + // 查詢, 卡片資訊 + public function get_barcode_info($barcode) + { + $data = array(); + + // A. 取得卡片資訊 + $results = $this->db->select('lpr, barcode, status') + ->from('allpa_user') + ->where('barcode', $barcode) + ->get() + ->result_array(); + + foreach($results as $idx => $rows) + { + switch($rows['status']){ + case 1: // 啟用中 + + // 跳到顯示個資的流程?? + return $this->get_allpa_info($rows['lpr']); + + break; + default: // 其它 + $data['result']['allpa_other'][$idx] = array + ( + 'lpr' => $rows['lpr'], + 'status' => $rows['status'] + ); + } + } + + // B.1 查詢barcode + $balance_inquiry_result = $this->balance_inquiry($barcode); + + if($balance_inquiry_result["result_code"] == ALLPA_RESULT_CODE_OK){ + $data["balance"] = $balance_inquiry_result["balance"]; + $data["card_status"] = $balance_inquiry_result["card_status"]; + $data["bonus"] = $balance_inquiry_result["bonus"]; + + }else{ + // 查詢barcode失敗 + $result = array(); + $result["result_code"] = ALLPA_RESULT_CODE_ERROR_balance_inquiry; + $result["result_msg"] = $balance_inquiry_result["result_msg"]; + return $result; + } + + $data["barcode"] = $barcode; + $data["result_code"] = ALLPA_RESULT_CODE_OK; + $data["result_msg"] = ALLPA_RESULT_MSG_OK; + return $data; + } + + + // 查詢, 歐Pa卡資訊 + public function get_allpa_info($user_lpr) + { + $data = array(); + + // A. 取得卡片資訊 + $results = $this->db->select('lpr, barcode, status') + ->from('allpa_user') + ->where('lpr', $user_lpr) + ->get() + ->result_array(); + + foreach($results as $idx => $rows) + { + switch($rows['status']){ + case 1: // 啟用中 + + // B.1 查詢barcode + $barcode = $rows['barcode']; + $balance_inquiry_result = $this->balance_inquiry($barcode); + $balance = 0; + $bonus = 0; + if($balance_inquiry_result["result_code"] == ALLPA_RESULT_CODE_OK){ + $balance = $balance_inquiry_result["balance"]; // 卡片餘額 + $bonus = $balance_inquiry_result["bonus"]; // 卡片紅利點數 + + if($balance_inquiry_result["status_code"] == "01"){ + // 唯一, 有效 + $data['result']['allpa_current'] = array + ( + 'lpr' => $user_lpr, + 'barcode' => $barcode, + 'balance' => $balance, + 'bonus' => $bonus, + 'card_status' => $balance_inquiry_result["card_status"] + ); + + }else{ + // 卡片未開通 + $data['result']['allpa_invalid'] = array + ( + 'lpr' => $user_lpr, + 'barcode' => $barcode, + 'balance' => $balance, + 'bonus' => $bonus, + 'card_status' => $balance_inquiry_result["card_status"] + ); + } + + }else{ + // 未知卡片處理 + $this->twgc_notfound_handler($balance_inquiry_result["result_code"], $user_lpr, $barcode); + + // 查詢barcode失敗 + $data['result']['allpa_error'][$idx] = array + ( + 'lpr' => $user_lpr, + 'barcode' => $barcode, + 'result_code' => $balance_inquiry_result["result_code"], + 'result_msg' => $balance_inquiry_result["result_msg"] + ); + } + + break; + default: // 其它 + $data['result']['allpa_other'][$idx] = array + ( + 'lpr' => $user_lpr, + 'barcode' => $rows['barcode'], + 'status' => $rows['status'] + ); + } + } + + // B. 取得帳單資訊 + $results = $this->db->select('order_no, product_bill.amt as amt, product_bill.product_plan as product_plan, tx_time, status, product_name, product_desc') + ->from('product_bill') + ->join('products', 'products.product_id = product_bill.product_id', 'left') + ->where('product_bill.lpr', $user_lpr) + //->where('product_bill.product_code', PRODUCT_CODE) + ->where_in('product_bill.status', array(1, 111)) + ->order_by("status ASC, update_time DESC") + ->limit(3) + ->get() + ->result_array(); + + foreach($results as $idx => $rows) + { + switch($rows['status']){ // '狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中, 111:產品已領取' + case 1: // 結帳完成 + $data['result']['bill_ready'][$idx] = array + ( + 'order_no' => $rows['order_no'], + 'amt' => $rows['amt'], + 'product_plan' => $rows['product_plan'] , + 'product_name' => $rows['product_name'] , + 'product_desc' => $rows['product_desc'] , + 'tx_time' => $rows['tx_time'] , + 'status' => $rows['status'] + ); + break; + case 111: // 產品已領取 + $data['result']['bill_finished'][$idx] = array + ( + 'order_no' => $rows['order_no'], + 'amt' => $rows['amt'], + 'product_plan' => $rows['product_plan'] , + 'product_name' => $rows['product_name'] , + 'product_desc' => $rows['product_desc'] , + 'tx_time' => $rows['tx_time'] , + 'status' => $rows['status'] + ); + break; + } + } + + // C. 取得歐Pa卡用戶帳單資訊 + $results = $this->db->select('order_no, barcode, station_no, in_time, balance_time, amt, status') + ->from('allpa_user_bill') + ->where(array('lpr' => $user_lpr)) + ->order_by("balance_time DESC") + ->limit(3) + ->get() + ->result_array(); + + foreach($results as $idx => $rows) + { + switch($rows['status']){ // 狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:交易失敗 + case 1: // 結帳完成 + $data['result']['allpa_user_bill_finished'][$idx] = array + ( + 'order_no' => $rows['order_no'], + 'barcode' => $rows['barcode'], + 'station_no' => $rows['station_no'], + 'in_time' => $rows['in_time'], + 'balance_time' => $rows['balance_time'], + 'amt' => $rows['amt'], + 'status' => $rows['status'] + ); + break; + case 2: // 錢沒對上 + $data['result']['allpa_user_bill_gg'][$idx] = array + ( + 'order_no' => $rows['order_no'], + 'barcode' => $rows['barcode'], + 'station_no' => $rows['station_no'], + 'in_time' => $rows['in_time'], + 'balance_time' => $rows['balance_time'], + 'amt' => $rows['amt'], + 'status' => $rows['status'] + ); + break; + default: // 未付款 + $data['result']['allpa_user_bill_debt'][$idx] = array + ( + 'order_no' => $rows['order_no'], + 'barcode' => $rows['barcode'], + 'station_no' => $rows['station_no'], + 'in_time' => $rows['in_time'], + 'balance_time' => $rows['balance_time'], + 'amt' => $rows['amt'], + 'status' => $rows['status'] + ); + break; + } + } + + // 判斷是否有資料 + if(empty($data)){ + $result = array(); + $result["result_code"] = ALLPA_RESULT_CODE_NOT_FOUND; + $result["result_msg"] = ALLPA_RESULT_MSG_NOT_FOUND; + return $result; // NOT FOUND + } + + $data["result_code"] = ALLPA_RESULT_CODE_OK; + $data["result_msg"] = ALLPA_RESULT_MSG_OK; + return $data; + } + + // 取得歐Pa卡產品清單 (管理者專用) + public function get_allpa_admin_products() + { + return $this->get_allpa_products(ADMIN_PRODUCT_CODE); + } + + // 取得歐Pa卡產品清單 + public function get_allpa_products($product_code=PRODUCT_CODE) + { + $data = array(); + $now = date('Y/m/d H:i:s'); + $result = $this->db->select('product_id, product_name, product_desc, amt, remarks') + ->from('products') + ->where(array( + 'start_time <= ' => $now, + 'valid_time > ' => $now, + 'product_code' => $product_code + )) + ->get() + ->result_array(); + return $result; + } + + // 建立歐Pa卡帳單 (管理者專用) + public function create_admin_bill($product_id) + { + return $this->create_bill($product_id, ADMIN_PRODUCT_CODE); + } + + // 建立歐Pa卡帳單 + public function create_bill($product_id, $product_code=PRODUCT_CODE) + { + $now = date('Y/m/d H:i:s'); + $product = $this->db->select('product_id, product_name, product_desc, amt, remarks, product_code, product_plan') + ->from('products') + ->where(array( + 'product_id' => $product_id, + 'start_time <= ' => $now, + 'valid_time > ' => $now, + 'product_code' => $product_code + )) + ->limit(1) + ->get() + ->row_array(); + + if(empty($product)){ + $result = array(); + $result["result_code"] = ALLPA_RESULT_CODE_NOT_FOUND; + $result["result_msg"] = ALLPA_RESULT_MSG_NOT_FOUND; + return $result; // NOT FOUND + } + + // create product_bill + $data = array(); + $data['order_no'] = $this->gen_trx_no(); + $data['product_id'] = $product["product_id"]; + $data['product_code'] = $product["product_code"]; + $data['product_plan'] = $product["product_plan"]; + $data['invoice_remark'] = $product["product_name"]; + $data['amt'] = $product["amt"]; + $data['valid_time'] = date('Y-m-d H:i:s', strtotime($now) + 60 * 15); // 15 min + $this->db->insert('product_bill', $data); + + $data['product_name'] = $product["product_name"]; + $data['product_desc'] = $product["product_desc"]; + $data['remarks'] = $product["remarks"]; + $data["result_code"] = ALLPA_RESULT_CODE_OK; + $data["result_msg"] = ALLPA_RESULT_MSG_OK; + return $data; + } + + // 建立產品帳單 (限定 CTBC) + public function pay_bill($lpr, $order_no, $invoice_receiver, $company_no, $email, $mobile) + { + $data = $this->db + ->from('product_bill') + ->where(array('order_no' => $order_no)) + ->limit(1) + ->get() + ->row_array(); + + if (!empty($data['valid_time'])) + { + $data['lpr'] = $lpr; // 車牌號碼 + + if(strlen($invoice_receiver) >= 7){ // 手機載具編號 + $data['invoice_receiver'] = '/'.$invoice_receiver; + } + if(strlen($company_no) >= 8){ // 公司統編 + $data['company_no'] = $company_no; + $data['company_receiver'] = "公司名稱"; + $data['company_address'] = "公司地址"; + } + if(strlen($email) >= 5){ // a@b.c + $data['email'] = $email; + } + if(strlen($mobile) >= 10){ // 手機 + $data['mobile'] = $mobile; + } + $txTime = time(); // 產生交易時間 + if(strtotime($data['valid_time']) - $txTime > 0){ + $data['status'] = 100; //狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中, 101: 交易失敗, 111:產品已領取 + $data['tx_time'] = date('Y/m/d H:i:s', $txTime); + $data['tx_type'] = 60; // 交易種類: 0:未定義, 1:現金, 40:博辰人工模組, 41:博辰自動繳費機, 50:歐付寶轉址刷卡, 51:歐付寶APP, 52:歐付寶轉址WebATM, 60:中國信託刷卡轉址 + $this->db->update('product_bill', $data, array('order_no' => $order_no)); + return $data; + } + $data['status'] = 99; //狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中, 101: 交易失敗, 111:產品已領取 + $this->db->update('product_bill', $data, array('order_no' => $order_no)); + return null; + } + + trigger_error(__FUNCTION__."|{$order_no}|無資料"); + } + + // 取得產品帳單 + public function get_product_bill($order_no) + { + $result = $this->db->from('product_bill') + ->where(array('order_no' => $order_no)) + ->limit(1) + ->get() + ->row_array(); + return $result; + } + + // 取得使用中的歐Pa用戶 + public function get_valid_user($lpr) + { + $user = $this->db->select('lpr, status_code, balance, barcode, bonus') + ->from('allpa_user') + ->where(array('lpr' => $lpr, 'status' => 1)) // '狀態: 0:剛建立, 1:啟用中, 2:啟用記名失敗, 99:已停用' + ->limit(1) + ->get() + ->row_array(); + return $user; + } + + // 狀態: 產品已領取 + public function transfer_money_done_and_finished($order_no) + { + $data = array(); + $data['status'] = 111; // 狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中, 101: 交易失敗, 111:產品已領取 + $this->db->update('product_bill', $data, array('order_no' => $order_no)); + return true; + } + + // 狀態: 結帳完成 + public function transfer_money_done($order_no) + { + $data = array(); + $data['status'] = 1; // 狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中, 101: 交易失敗, 111:產品已領取 + $this->db->update('product_bill', $data, array('order_no' => $order_no)); + return true; + } + + // 狀態: 錢沒對上 + public function transfer_money_done_with_amt_error($order_no) + { + $data = array(); + $data['status'] = 2; // 狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中, 101: 交易失敗, 111:產品已領取 + $this->db->update('product_bill', $data, array('order_no' => $order_no)); + return true; + } + + // 狀態: 交易失敗 + public function transfer_money_done_with_tx_error($order_no) + { + $data = array(); + $data['status'] = 101; // 狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中, 101: 交易失敗, 111:產品已領取 + $this->db->update('product_bill', $data, array('order_no' => $order_no)); + return true; + } + + // 狀態: 發票沒建立 + public function transfer_money_set_invoice_error($order_no) + { + $data = array(); + $data['status'] = 3; // 狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中, 101: 交易失敗, 111:產品已領取 + $this->db->update('product_bill', $data, array('order_no' => $order_no)); + return true; + } + + // [公司內部呼叫] 歐Pa卡 - 開門 + public function allpa_go($in_time, $lpr, $station_no, $check_mac) + { + if(empty($check_mac) || md5($in_time.$lpr.$station_no) != $check_mac){ + // check mac fail + $result = array(); + $result["result_code"] = ALLPA_GO_RESULT_CODE_CK_ERROR; + $result["result_msg"] = ALLPA_GO_RESULT_MSG_CK_ERROR; + return $result; // CK ERROR + } + + require_once(ALTOB_BILL_FILE); // 臨停費率 + + $oPayment = new AltobPayment(); + $oPayment->ServiceURL = "http://localhost/txdata.html"; + $in_time = date('Y-m-d H:i:s', $in_time); + $balance_time = date('Y-m-d H:i:s'); + $bill = $oPayment->getBill($in_time, $balance_time, $station_no); + $price = $bill[BillResultKey::price]; + + // 查有效用戶 + $user = $this->get_valid_user($lpr); + $barcode = $user["barcode"]; + + if(empty($user)){ + $result = array(); + $result["result_code"] = ALLPA_GO_RESULT_CODE_USER_NOT_FOUND; + $result["result_msg"] = ALLPA_GO_RESULT_MSG_USER_NOT_FOUND; + return $result; // USER NOT FOUND + } + + // 查欠款 + $allpa_user_bill = $this->db->select('station_no, amt') + ->from('allpa_user_bill') + ->where(array('lpr' => $lpr)) + ->where_not_in('status', 1) // '狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:交易失敗' + ->limit(1) + ->get() + ->row_array(); + + if(! empty($allpa_user_bill)){ + $result = array(); + $result["result_code"] = ALLPA_GO_RESULT_CODE_DEBT; + $result["result_msg"] = ALLPA_GO_RESULT_MSG_DEBT; + return $result; // DEBT + } + + // 檢查扣款條件 + if(! $this->is_money_enough($user["balance"], $user["bonus"], $price)){ + $result = array(); + $result["result_code"] = ALLPA_GO_RESULT_CODE_NO_MONEY; + $result["result_msg"] = ALLPA_GO_RESULT_MSG_NO_MONEY; + $result["amt"] = $price; + return $result; // NO MONEY + } + /* 2016/03/28 不查log了 + $recent_balance_log = $this->db->select('balance, bonus') + ->from('allpa_balance_log') + ->where(array('lpr' => $lpr, 'barcode' => $barcode)) + ->order_by("create_time", "desc") + ->limit(1) + ->get() + ->row_array(); + // 檢查扣款條件 + if(! $this->is_money_enough($recent_balance_log["balance"], $recent_balance_log["bonus"], $price)){ + $result = array(); + $result["result_code"] = ALLPA_GO_RESULT_CODE_NO_MONEY; + $result["result_msg"] = ALLPA_GO_RESULT_MSG_NO_MONEY; + $result["amt"] = $price; + return $result; // NO MONEY + } + */ + + // 產生交易序號 + $order_no = $this->gen_trx_no(); + + // 產生用戶帳單 + $data = array(); + $data['order_no'] = $order_no; + $data['barcode'] = $barcode; + $data['lpr'] = $lpr; + $data['station_no'] = $station_no; + $data['in_time'] = $in_time; + $data['balance_time'] = $balance_time; + $data['amt'] = $price; + $this->db->insert('allpa_user_bill', $data); + + // 可以開門了 + $result = array(); + $result["result_code"] = ALLPA_GO_RESULT_CODE_OK; + $result["result_msg"] = ALLPA_GO_RESULT_MSG_OK; + $result["order_no"] = $order_no; + $result["amt"] = $price; + return $result; + } + + // 歐Pa卡帳單 - 扣款 + public function allpa_pay_bill($order_no) + { + // 取得歐Pa卡帳單 + $allpa_user_bill = $this->db->select('lpr, barcode, amt') + ->from('allpa_user_bill') + ->where(array('order_no' => $order_no)) + ->where_not_in('status', 1) // '狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:交易失敗' + ->limit(1) + ->get() + ->row_array(); + + if(empty($allpa_user_bill)){ + $result = array(); + $result["result_code"] = ALLPA_GO_RESULT_CODE_BILL_NOT_FOUND; + $result["result_msg"] = ALLPA_GO_RESULT_MSG_BILL_NOT_FOUND; + return $result; // BILL NOT FOUND + } + + $lpr = $allpa_user_bill["lpr"]; + $order_barcode = $allpa_user_bill["barcode"]; // 當時產生帳單時的barcode (規則是要唯一, 但意外可能發生) + $price = $allpa_user_bill["amt"]; + + // 查有效用戶 + $user = $this->get_valid_user($lpr); + $barcode = $user["barcode"]; + + if(empty($user)){ + $result = array(); + $result["result_code"] = ALLPA_GO_RESULT_CODE_USER_NOT_FOUND; + $result["result_msg"] = ALLPA_GO_RESULT_MSG_USER_NOT_FOUND; + return $result; // USER NOT FOUND + } + + // 查遠端餘額 + $pre_status_code = ""; + $pre_balance = 0; + $pre_bonus = 0; + $balance_inquiry_result = $this->balance_inquiry($barcode); + if($balance_inquiry_result["result_code"] == ALLPA_RESULT_CODE_OK){ + $pre_status_code = $balance_inquiry_result["status_code"]; + $pre_balance = $balance_inquiry_result["balance"]; + $pre_bonus = $balance_inquiry_result["bonus"]; + }else{ + // 未知卡片處理 + $this->twgc_notfound_handler($balance_inquiry_result["result_code"], $lpr, $barcode); + + // 查詢barcode失敗 + $result = array(); + $result["result_code"] = ALLPA_RESULT_CODE_ERROR_balance_inquiry; + $result["result_msg"] = $balance_inquiry_result["result_msg"]; + return $result; + } + + // 記錄是否出現未知斷層 + if( $pre_status_code != $user["status_code"] || + $pre_balance != $user["balance"] || + $pre_bonus != $user["bonus"]) { + $unknown_trx_no = $this->gen_trx_no(); + // 產生一筆未知的balance_log + $this->create_allpa_unknown_log( + $unknown_trx_no, $lpr, $barcode, + $user["status_code"], $user["balance"], $user["bonus"], + $order_no); + } + + /* 2016/03/28 不查log了 + $recent_balance_log = $this->db->select('status_code, balance, bonus') + ->from('allpa_balance_log') + ->where(array('lpr' => $lpr, 'barcode' => $barcode)) + ->order_by("create_time", "desc") + ->limit(1) + ->get() + ->row_array(); + + // 記錄是否出現未知斷層 + if( $pre_status_code != $recent_balance_log["status_code"] || + $pre_balance != $recent_balance_log["balance"] || + $pre_bonus != $recent_balance_log["bonus"]) { + $unknown_trx_no = $this->gen_trx_no(); + // 產生一筆未知的balance_log + $this->create_allpa_unknown_log( + $unknown_trx_no, $lpr, $barcode, + $recent_balance_log["status_code"], $recent_balance_log["balance"], $recent_balance_log["bonus"], + $order_no); + }*/ + + // 檢查扣款條件 + if(! $this->is_money_enough($pre_balance, $pre_bonus, $price)){ + $result = array(); + $result["result_code"] = ALLPA_GO_RESULT_CODE_NO_MONEY; + $result["result_msg"] = ALLPA_GO_RESULT_MSG_NO_MONEY; + return $result; // NO MONEY + } + + // 扣款 + $allpa_consume_result = $this->allpa_consume($lpr, $barcode, $price, $order_no); + + if($allpa_consume_result["result_code"] == ALLPA_RESULT_CODE_OK){ + // 新增卡片使用記錄 + $this->create_allpa_consume_log( + $allpa_consume_result["cust_trx_no"], $lpr, $barcode, + $pre_status_code, $pre_balance, $pre_bonus, + $order_no); + + // 更新帳單資訊 + if($pre_balance + $pre_bonus == $allpa_consume_result["balance"] + $allpa_consume_result["bonus"] + $price){ + $data = array(); + $data['status'] = 1; // '狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:交易失敗' + $this->db->update('allpa_user_bill', $data, array('order_no' => $order_no)); + }else{ + $data = array(); + $data['status'] = 2; // '狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:交易失敗' + $this->db->update('allpa_user_bill', $data, array('order_no' => $order_no)); + } + + $result = array(); + $result["result_code"] = ALLPA_GO_RESULT_CODE_OK; + $result["result_msg"] = ALLPA_GO_RESULT_MSG_OK; + $result["lpr"] = $lpr; + return $result; + + }else{ + // 更新帳單資訊 + $data = array(); + $data['status'] = 3; // '狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:交易失敗' + $this->db->update('allpa_user_bill', $data, array('order_no' => $order_no)); + + $result = array(); + $result["result_code"] = ALLPA_GO_RESULT_CODE_CONSUME_ERROR; + $result["result_msg"] = $allpa_consume_result["result_msg"]; + return $result; // CONSUME ERROR + } + + } + + + // 歐Pa卡 - 判斷有效用戶 + public function get_allpa_valid_user($lpr, $check_mac) + { + if(empty($check_mac) || md5($lpr) != $check_mac){ + // check mac fail + $result = array(); + $result["result_code"] = ALLPA_GO_RESULT_CODE_CK_ERROR; + $result["result_msg"] = ALLPA_GO_RESULT_MSG_CK_ERROR; + return $result; // CK ERROR + } + + // 查有效用戶 + $user = $this->get_valid_user($lpr); + + if(empty($user)){ + $result = array(); + $result["result_code"] = ALLPA_GO_RESULT_CODE_USER_NOT_FOUND; + $result["result_msg"] = ALLPA_GO_RESULT_MSG_USER_NOT_FOUND; + return $result; // USER NOT FOUND + } + + $result = array(); + $result["result_code"] = ALLPA_GO_RESULT_CODE_OK; + $result["result_msg"] = ALLPA_GO_RESULT_MSG_OK; + $result["lpr"] = $user["lpr"]; + $result["barcode"] = $user["barcode"]; + $result["balance"] = $user["balance"]; + $result["bonus"] = $user["bonus"]; + return $result; + } + +} diff --git a/models/Allpay_invoice_model.php b/models/Allpay_invoice_model.php new file mode 100644 index 0000000..b66b535 --- /dev/null +++ b/models/Allpay_invoice_model.php @@ -0,0 +1,1058 @@ +load->database(); + + // ----- 測試環境設定 ----- + define('ALLPAY_INVOICE_TEST_MerchantID', "2000132"); + define('ALLPAY_INVOICE_TEST_HashKey', "ejCk326UnaZWKisg"); + define('ALLPAY_INVOICE_TEST_HashIV', "q9jcZX8Ib9LM8wYk"); + define('ALLPAY_INVOICE_TEST_SERVICE_PATH', "https://einvoice-stage.allpay.com.tw"); + // ----- 測試環境設定(end) ----- + + // ----- 正式環境設定 (總公司) ----- + define('ALLPAY_INVOICE_80682490_MerchantID', "1148391"); // 80682490 + define('ALLPAY_INVOICE_80682490_HashKey', "Pjkm8Tun7neLqTtj"); + define('ALLPAY_INVOICE_80682490_HashIV', "eLKm6GgvetijrRcc"); + define('ALLPAY_INVOICE_80682490_SERVICE_PATH', "https://einvoice.allpay.com.tw/"); + // ----- 正式環境設定(end) ----- + + // ----- 正式環境設定 (場站) ----- + define('ALLPAY_INVOICE_MerchantID', "1148391"); // 80682490 (待切換為對應場站) + define('ALLPAY_INVOICE_HashKey', "Pjkm8Tun7neLqTtj"); + define('ALLPAY_INVOICE_HashIV', "eLKm6GgvetijrRcc"); + define('ALLPAY_INVOICE_SERVICE_PATH', "https://einvoice.allpay.com.tw/"); + // ----- 正式環境設定(end) ----- + + + // 切換 FLAG + define('ALLPAY_INVOICE_TEST_FLAG', "test"); + define('ALLPAY_INVOICE_MAIN_FLAG', "80682490"); + define('ALLPAY_INVOICE_STATION_FLAG', "station"); + + + // 5.一般開立發票 API + define('ALLPAY_INVOICE_Invoice_Issue_Method', "INVOICE"); + define('ALLPAY_INVOICE_Invoice_Issue_Url', "/Invoice/Issue"); + // 7.開立折讓 API + define('ALLPAY_INVOICE_Allowance_Method', "ALLOWANCE"); + define('ALLPAY_INVOICE_Allowance_Url', "/Invoice/Allowance"); + // 8.發票作廢 API + define('ALLPAY_INVOICE_Invoice_Void_Method', "INVOICE_VOID"); + define('ALLPAY_INVOICE_Invoice_Void_Url', "/Invoice/IssueInvalid"); + // 10.折讓作廢 API + define('ALLPAY_INVOICE_Allowance_Void_Method', "ALLOWANCE_VOID"); + define('ALLPAY_INVOICE_Allowance_Void_Url', "/Invoice/AllowanceInvalid"); + // 14.通知 API + define('ALLPAY_INVOICE_Invoice_Notify_Method', "INVOICE_NOTIFY"); + define('ALLPAY_INVOICE_Invoice_Notify_Url', "/Notify/InvoiceNotify"); + + // ----- 回傳訊息 ----- + define('ALLPAY_INVOICE_RESULT_CODE_OK', "OK"); + define('ALLPAY_INVOICE_RESULT_MSG_OK', "成功"); + define('ALLPAY_INVOICE_RESULT_CODE_NOT_FOUND', "-1"); + define('ALLPAY_INVOICE_RESULT_MSG_NOT_FOUND', "找不到資料"); + define('ALLPAY_INVOICE_RESULT_CODE_INVOICE_ERROR', "-2"); + define('ALLPAY_INVOICE_RESULT_MSG_INVOICE_ERROR', "錯誤回傳"); + define('ALLPAY_INVOICE_RESULT_CODE_COMPANY_NO_ERROR', "-10"); + define('ALLPAY_INVOICE_RESULT_MSG_COMPANY_NO_ERROR', "統編有誤"); + define('ALLPAY_INVOICE_RESULT_CODE_GG', "-99"); + define('ALLPAY_INVOICE_RESULT_MSG_GG', "異常"); + // ----- 回傳訊息 (END) ----- + } + + // 載入歐付寶電子發票 + function load_allpay_invoice_by_flag($flag) + { + // 1.載入 SDK 程式 + $allpay_invoice = new AllInvoice ; + $allpay_invoice->MerchantID = $this->get_allpay_merchant_id($flag) ; + + // 2.寫入基本介接參數 + switch($flag) + { + case ALLPAY_INVOICE_TEST_FLAG: // 測試環境 + $allpay_invoice->HashKey = ALLPAY_INVOICE_TEST_HashKey ; + $allpay_invoice->HashIV = ALLPAY_INVOICE_TEST_HashIV ; + break; + case ALLPAY_INVOICE_MAIN_FLAG: // 總公司 + $allpay_invoice->HashKey = ALLPAY_INVOICE_80682490_HashKey ; + $allpay_invoice->HashIV = ALLPAY_INVOICE_80682490_HashIV ; + break; + default: // 場站 + $allpay_invoice->HashKey = ALLPAY_INVOICE_HashKey ; + $allpay_invoice->HashIV = ALLPAY_INVOICE_HashIV ; + break; + } + return $allpay_invoice; + } + + // 載入歐付寶電子發票 (由歐付寶廠商編號) + function load_allpay_invoice_by_merchant_id($merchant_id) + { + // 1.載入 SDK 程式 + $allpay_invoice = new AllInvoice ; + $allpay_invoice->MerchantID = $merchant_id; + + // 2.寫入基本介接參數 + switch($merchant_id) + { + case ALLPAY_INVOICE_TEST_MerchantID: // 測試環境 + $allpay_invoice->HashKey = ALLPAY_INVOICE_TEST_HashKey ; + $allpay_invoice->HashIV = ALLPAY_INVOICE_TEST_HashIV ; + break; + case ALLPAY_INVOICE_80682490_MerchantID: // 總公司 + $allpay_invoice->HashKey = ALLPAY_INVOICE_80682490_HashKey ; + $allpay_invoice->HashIV = ALLPAY_INVOICE_80682490_HashIV ; + break; + default: // 場站 + $allpay_invoice->HashKey = ALLPAY_INVOICE_HashKey ; + $allpay_invoice->HashIV = ALLPAY_INVOICE_HashIV ; + break; + } + return $allpay_invoice; + } + + // 取得歐付寶店家編號 + function get_allpay_merchant_id($flag) + { + $id = 0; + switch($flag) + { + case ALLPAY_INVOICE_TEST_FLAG: // 測試環境 + $id = ALLPAY_INVOICE_TEST_MerchantID ; + break; + case ALLPAY_INVOICE_MAIN_FLAG: // 總公司 + $id = ALLPAY_INVOICE_80682490_MerchantID ; + break; + default: // 場站 + $id = ALLPAY_INVOICE_MerchantID ; + break; + } + return $id; + } + + // Z.1 產生交易編號 + function gen_tx_bill_ats_order_no($tx_bill_no) + { + return time().str_pad($tx_bill_no, 10, '0', STR_PAD_LEFT); + } + + // Z.2 由交易編號取得會員交易編號 + function get_tx_bill_no_from_order_no($order_no) + { + return intval(substr($order_no, -10)); + } + + // M.1 開立月租系統發票 (情境: 1. 新增會員開立, 2. 繳租開立, 3. 退租戶補開立, 4. 拆分的金額接續開立) + public function create_member_tx_bill_invoice($station_no, $tx_bill_no, $amt, $member_company_no, $company_no, $email, $mobile, $lpr='') + { + + // 暫不開放 + $result = array(); + $result["result_code"] = ALLPAY_INVOICE_RESULT_CODE_GG; + $result["result_msg"] = ALLPAY_INVOICE_RESULT_MSG_GG; + return $result; + + + // 統編不能一樣 + if($member_company_no == $company_no) + { + $result = array(); + $result["result_code"] = ALLPAY_INVOICE_RESULT_CODE_COMPANY_NO_ERROR; + $result["result_msg"] = ALLPAY_INVOICE_RESULT_MSG_COMPANY_NO_ERROR; + return $result; + } + + $order_no = $this->gen_tx_bill_ats_order_no($tx_bill_no); // 交易編號 + + $invoice_flag = ($company_no == '80682490') ? ALLPAY_INVOICE_MAIN_FLAG : ALLPAY_INVOICE_STATION_FLAG; // 賣方統編切換 (總公司或場站) + $company_no = $member_company_no; // 買方統編 + + $this->db->trans_start(); + + // 1. 建立交易記錄 + $this->create_bill_handler('tx_bill_ats', $station_no, $order_no, $amt, + $company_no, $email, $mobile, $lpr, 'TODO', '停車費用帳單', 100); + + // 2. 列印歐付寶電子發票 + $result = $this->invoice_issue_handler('tx_bill_ats', $order_no, $amt, $invoice_flag); + + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(__FUNCTION__ . '..trans_error..data:' . "{$station_no}, {$tx_bill_no}". '| last_query: ' . $this->db->last_query()); + + $result = array(); + $result["result_code"] = ALLPAY_INVOICE_RESULT_CODE_GG; + $result["result_msg"] = ALLPAY_INVOICE_RESULT_MSG_GG; + } + + return $result; + } + + // M.2 作廢月租系統發票 (tx_bill_ats) + public function void_member_tx_bill_invoice($station_no, $order_no, $invoice_no) + { + // 檢查 + $bill = $this->db + ->select('invoice_no, status') + ->from('tx_bill_ats') + ->where(array('invoice_no' => $invoice_no, 'order_no' => $order_no, 'station_no' => $station_no)) + ->limit(1) + ->get() + ->row_array(); + + if (empty($bill)) + { + $result = array(); + $result["result_code"] = ALLPAY_INVOICE_RESULT_CODE_NOT_FOUND; + $result["result_msg"] = ALLPAY_INVOICE_RESULT_MSG_NOT_FOUND; + return $result; + } + else if($bill['status'] != TX_BILL_ATS_STATUS_PAID) + { + $result = array(); + $result["result_code"] = ALLPAY_INVOICE_RESULT_CODE_INVOICE_ERROR; + $result["result_msg"] = ALLPAY_INVOICE_RESULT_MSG_INVOICE_ERROR; + return $result; + } + + $result = $this->invoice_void($invoice_no, '月租發票作廢'); + + if($result["result_code"] == ALLPAY_INVOICE_RESULT_CODE_OK) + { + $this->db->trans_start(); + + // 於 tx_bill_ats 註記 + $this->db->update('tx_bill_ats', array('status' => TX_BILL_ATS_STATUS_INVOICE_VOID), array('station_no' => $station_no, 'invoice_no' => $invoice_no)); + + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(__FUNCTION__ . '..trans_error..data:' . "{$station_no}, {$order_no}, {$invoice_no}". '| last_query: ' . $this->db->last_query()); + + $result = array(); + $result["result_code"] = ALLPAY_INVOICE_RESULT_CODE_GG; + $result["result_msg"] = ALLPAY_INVOICE_RESULT_MSG_GG; + } + else + { + $result['tx_bill_no'] = $this->get_tx_bill_no_from_order_no($order_no); // 帶上 tx_bill_no + } + } + + return $result; + } + + // M.3 折讓月租系統發票 (tx_bill_ats) + public function allowance_member_tx_bill_invoice($station_no, $invoice_no, $allowance_amt) + { + // 檢查 + $bill = $this->db + ->select('invoice_no, status') + ->from('tx_bill_ats') + ->where(array('invoice_no' => $invoice_no, 'station_no' => $station_no)) + ->limit(1) + ->get() + ->row_array(); + + if (empty($bill)) + { + $result = array(); + $result["result_code"] = ALLPAY_INVOICE_RESULT_CODE_NOT_FOUND; + $result["result_msg"] = ALLPAY_INVOICE_RESULT_MSG_NOT_FOUND; + return $result; + } + else if($bill['status'] != TX_BILL_ATS_STATUS_PAID) + { + $result = array(); + $result["result_code"] = ALLPAY_INVOICE_RESULT_CODE_INVOICE_ERROR; + $result["result_msg"] = ALLPAY_INVOICE_RESULT_MSG_INVOICE_ERROR; + return $result; + } + + $result = $this->invoice_allowance($invoice_no, $allowance_amt, "折讓月租發票"); + + if($result["result_code"] == ALLPAY_INVOICE_RESULT_CODE_OK) + { + $this->db->trans_start(); + + // 於 tx_bill_ats 註記 + $this->db->update('tx_bill_ats', array('status' => TX_BILL_ATS_STATUS_INVOICE_ALLOWANCE), array('station_no' => $station_no, 'invoice_no' => $invoice_no)); + + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(__FUNCTION__ . '..trans_error..data:' . "{$station_no}, {$invoice_no}, {$allowance_amt}". '| last_query: ' . $this->db->last_query()); + + $result = array(); + $result["result_code"] = ALLPAY_INVOICE_RESULT_CODE_GG; + $result["result_msg"] = ALLPAY_INVOICE_RESULT_MSG_GG; + } + } + + return $result; + } + + /* + 建立消費記錄 + */ + function create_bill_handler($target_table_name, $station_no, $order_no, $amt, + $company_no, $email, $mobile, $lpr, $invoice_receiver, $invoice_remark, $tx_type) + { + $txTime = time(); // 產生交易時間 + + $data = array(); + $data['invoice_remark'] = $invoice_remark; + $data['order_no'] = $order_no; + $data['station_no'] = $station_no; // 場站編號 + $data['amt'] = $amt; // 金額 + $data['lpr'] = $lpr; // 車牌號碼 + + if(strlen($invoice_receiver) >= 7){ // 手機載具編號 + $data['invoice_receiver'] = '/'.$invoice_receiver; + } + if(strlen($company_no) >= 8){ // 公司統編 + $data['company_no'] = $company_no; + $data['company_receiver'] = "公司名稱"; + $data['company_address'] = "公司地址"; + } + if(strlen($email) >= 5){ // a@b.c + $data['email'] = $email; + } + if(strlen($mobile) >= 10){ // 手機 + $data['mobile'] = $mobile; + } + + $data['status'] = TX_BILL_ATS_STATUS_PAID; //狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中 + $data['tx_time'] = date('Y/m/d H:i:s', $txTime); + $data['tx_type'] = $tx_type; // 交易種類: 0:未定義, 1:現金, 40:博辰人工模組, 41:博辰自動繳費機, 50:歐付寶轉址刷卡, 51:歐付寶APP, 52:歐付寶轉址WebATM, 60:中國信託刷卡轉址, 100:月租系統開立歐付寶發票 + + $this->db->insert($target_table_name, $data); + return $data; + } + + // A.1 開立歐Pa卡發票 (product_bill) + public function invoice_issue_for_product_bill($order_no, $amt) + { + return $this->invoice_issue_handler('product_bill', $order_no, $amt); + } + + // A.2 開立臨停發票 (tx_bill) + public function invoice_issue_for_tx_bill($order_no, $amt) + { + return $this->invoice_issue_handler('tx_bill', $order_no, $amt); + } + + // A.3 開立繳款機發票 (tx_bill_ats) + public function invoice_issue_for_tx_bill_ats($order_no, $amt) + { + return $this->invoice_issue_handler('tx_bill_ats', $order_no, $amt); + } + + /* + 開立發票處理入口 + + $bill 總之要包含這些欄位 + + order_no 交易編號 + status 交易狀態 + amt 金額 + company_no 公司統編 + company_receiver 公司收件人 + company_address 公司地址 + mobile 手機號碼 + email 信箱 + mobile_receiver 手機載具編號 + natural_receiver 自然人憑證條碼 + love_code 愛心碼 + invoice_remark 備註 + invoice_no 發票號碼 + */ + protected function invoice_issue_handler($target_table_name, $order_no, $amt, $invoice_flag=ALLPAY_INVOICE_STATION_FLAG) + { + try{ + $bill = $this->db + ->select(' + order_no, status, amt, + company_no, company_receiver, company_address, + mobile, email, mobile_receiver, natural_receiver, love_code, + invoice_remark, invoice_no + ') + ->from($target_table_name) + ->where(array('order_no' => $order_no, 'amt' => $amt)) + ->limit(1) + ->get() + ->row_array(); + + if (! empty($bill)) + { + $invoice_issue_result = ''; + + switch($bill['status']) + { + case 1: // 狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中 + + // 印發票流程 + if(empty($bill['invoice_no'])) + { + $invoice_issue_result = $this->invoice_issue($bill, $bill["invoice_remark"], $invoice_flag); + } + else + { + $sMsg = ' invoice_no is not NULL?? : '.$bill['invoice_no']; + trigger_error(__FUNCTION__ .', order_no=>' . $order_no.'
'.$sMsg); + } + break; + + default: + // 對方多傳一次時?? + $sMsg = ' status != 1'; + trigger_error(__FUNCTION__ .', order_no=>' . $order_no.'
'.$sMsg); + } + + if(strlen($invoice_issue_result) == 10) + { + $data = array(); + $data['invoice_no'] = $invoice_issue_result; + $this->db->update($target_table_name, $data, array('order_no' => $order_no)); + + $result = array(); + $result["invoice_no"] = $invoice_issue_result; + $result["result_code"] = ALLPAY_INVOICE_RESULT_CODE_OK; + $result["result_msg"] = ALLPAY_INVOICE_RESULT_MSG_OK; + return $result; + } + else + { + $result = array(); + $result["result_code"] = ALLPAY_INVOICE_RESULT_CODE_INVOICE_ERROR; + $result["result_msg"] = ALLPAY_INVOICE_RESULT_MSG_INVOICE_ERROR; + return $result; + } + } + else + { + $result = array(); + $result["result_code"] = ALLPAY_INVOICE_RESULT_CODE_NOT_FOUND; + $result["result_msg"] = ALLPAY_INVOICE_RESULT_MSG_NOT_FOUND; + return $result; + } + } + catch (Exception $e) + { + // 例外錯誤處理。 + $sMsg = $e->getMessage(); + trigger_error(__FUNCTION__ .', order_no=>' . $order_no .'
'.$sMsg); + + $result = array(); + $result["result_code"] = ALLPAY_INVOICE_RESULT_CODE_GG; + $result["result_msg"] = ALLPAY_INVOICE_RESULT_MSG_GG; + return $result; + } + } + + // 5.一般開立發票 API + protected function invoice_issue($data, $invoice_remark, $invoice_flag) + { + $order_no = $data['order_no']; + $amt = $data['amt']; + + // 1.載入 SDK 程式 + $allpay_invoice = $this->load_allpay_invoice_by_flag($invoice_flag); + // 2.寫入基本介接參數 + $allpay_invoice->Invoice_Method = ALLPAY_INVOICE_Invoice_Issue_Method ; + $allpay_invoice->Invoice_Url = ALLPAY_INVOICE_SERVICE_PATH.ALLPAY_INVOICE_Invoice_Issue_Url ; + + // 3.寫入發票傳送資訊 + $aItems = array(); + array_push( + $allpay_invoice->Send['Items'], + array( + 'ItemName' => $invoice_remark, + 'ItemCount' => 1, + 'ItemWord' => '筆', + 'ItemPrice' => $amt, + 'ItemTaxType' => 1, + 'ItemAmount' => $amt + ) + ); + + $company_no = ''; + $mobile = ''; + $email = ''; + $company_receiver = ''; + $company_address = ''; + $mobile_receiver = ''; + $natural_receiver = ''; + $love_code = ''; + + if(strlen($data['company_no']) == 8){ + $company_no = $data['company_no']; + } + if(strlen($data['mobile']) > 0){ + $mobile = $data['mobile']; + } + if(strlen($data['email']) > 0){ + $email = $data['email']; + } + if(strlen($data['company_receiver']) > 0){ + $company_receiver = $data['company_receiver']; + } + if(strlen($data['company_address']) > 0){ + $company_address = $data['company_address']; + } + if(strlen($data['mobile_receiver']) > 0){ + $mobile_receiver = $data['mobile_receiver']; + } + if(strlen($data['natural_receiver']) > 0){ + $natural_receiver = $data['natural_receiver']; + } + if(strlen($data['love_code']) > 0){ + $love_code = $data['love_code']; + } + + $donation = '2' ; // 捐贈註記 1.捐贈 2.不捐贈 + $print = '0'; // 列印註記 0.不列印 1.列印 + $carruer_type = ''; // 載具類別 + $carruer_num = ''; + + if(strlen($company_no) > 0){ + // 打統編 + $print = '1'; + + }else if(strlen($love_code) > 0){ + // 捐贈 + $donation = '1'; + + }else if(strlen($natural_receiver) > 0){ + // 載具類別: 自然人憑證 + $carruer_type = '2'; + $carruer_num = $natural_receiver; + + }else if(strlen($mobile_receiver) > 0){ + // 載具類別: 手機條碼 + $carruer_type = '3'; + $carruer_num = $mobile_receiver; + //$carruer_num = str_replace ('+', ' ', $mobile_receiver); // 如果有+可能會出錯 + } + + $allpay_invoice->Send['RelateNumber'] = $order_no ; // 廠商自訂編號 + $allpay_invoice->Send['CustomerID'] = '' ; // 客戶代號 + $allpay_invoice->Send['CustomerIdentifier'] = $company_no ; // 統一編號 + $allpay_invoice->Send['CustomerName'] = $company_receiver ; // 客戶名稱 + $allpay_invoice->Send['CustomerAddr'] = $company_address ; // 客戶地址 + $allpay_invoice->Send['CustomerPhone'] = $mobile ; // 客戶手機號碼 + $allpay_invoice->Send['CustomerEmail'] = $email ; // 客戶電子信箱 + $allpay_invoice->Send['ClearanceMark'] = '' ; // 通關方式 + $allpay_invoice->Send['Print'] = $print; // 列印註記 0.不列印 1.列印 + $allpay_invoice->Send['Donation'] = $donation ; // 捐贈註記 1.捐贈 2.不捐贈 + $allpay_invoice->Send['LoveCode'] = $love_code ;// 愛心碼 + $allpay_invoice->Send['CarruerType'] = $carruer_type ; // 載具類別 + $allpay_invoice->Send['CarruerNum'] = $carruer_num; // 載具編號 + $allpay_invoice->Send['TaxType'] = 1 ; // 課稅類別 1.應稅 2.零稅率 3.免稅 + $allpay_invoice->Send['SalesAmount'] = $amt ; // 發票金額 + $allpay_invoice->Send['InvoiceRemark'] = $invoice_remark ; // 備註 + $allpay_invoice->Send['InvType'] = '07' ; // 字軌類別 07.一般稅額 08.特種稅額 + $allpay_invoice->Send['InvCreateDate'] = '' ; // 發票開立時間 + $allpay_invoice->Send['vat'] = '' ; // 商品單價是否含稅 + + trigger_error(__FUNCTION__. ' $allpay_invoice->Send : ' . print_r($allpay_invoice->Send, true)); + + $aReturn_Info = $allpay_invoice->Check_Out(); + + $sMsg = ''; + foreach ($aReturn_Info as $key => $value){ + $sMsg .= $key . ' => ' . $value . '
' ; + switch ($key){ + case "RelateNumber": $eRelateNumber = $value; break; + case "InvoiceDate": $eInvoiceDate = $value; break; + case "InvoiceNumber": $eInvoiceNumber = $value; break; + case "RandomNumber": $eRandomNumber = $value; break; + case "RtnCode": $eRtnCode = $value; break; + case "RtnMsg": $eRtnMsg = $value; break; + case "CheckMacValue": $eCheckMacValue = $value; break; + default: break; + } + } + + trigger_error(__FUNCTION__ .', return: '.$sMsg); + + $invoice_data = array( + 'order_no' => $order_no, + //'relate_number' => $eRelateNumber, // ?? 沒拿到 + 'invoice_date' => $eInvoiceDate, + 'invoice_number' => $eInvoiceNumber, + 'random_number' => $eRandomNumber, + 'rtn_code' => $eRtnCode, + 'rtn_msg' => $eRtnMsg, + 'check_mac_value' => $eCheckMacValue, + 'merchant_id' => $this->get_allpay_merchant_id($invoice_flag) + ); + + // 建立log + $this->db->insert('allpay_invoice_log', $invoice_data); + + // eInvoiceNumber記到tx_bill + if($eRtnCode == '1'){ + // 發送通知 + /* (歐付寶後台有提供對應設定, 無需自行手動送出?? But, 測試環境設定後無效 ??) + if(strlen($email) > 0 && strlen($mobile) > 0){ + $this->invoice_notify($eInvoiceNumber, 'A', 'I', 'C', $email, $mobile); + }else if(strlen($mobile) > 0){ + $this->invoice_notify($eInvoiceNumber, 'S', 'I', 'C', $email, $mobile); + }else if(strlen($email) > 0){ + $this->invoice_notify($eInvoiceNumber, 'E', 'I', 'C', $email, $mobile); + }else{ + $sMsg = 'empty tx_bill.mobile && tx_bill.email can not send notify'; + trigger_error(APP_NAME.'[allpay_invoice_issue] order_no=>' . $order_no.'
'.$sMsg); + }*/ + + // 回傳發票號碼 + return $eInvoiceNumber; + + }else{ + trigger_error(__FUNCTION__ .', order_no=>' . $order_no.'
'.$sMsg); + } + + return ''; // 不是發票號碼就是空字串 + } + + // 7.開立折讓 API + public function invoice_allowance($invoice_no, $allowance_amt, $item_name="停車費用帳單") + { + // 取得開立記錄 + $invoice_log = $this->db + ->select('merchant_id') + ->from('allpay_invoice_log') + ->where(array('invoice_number' => $invoice_no)) + ->limit(1) + ->get() + ->row_array(); + + if (empty($invoice_log)) + { + $result = array(); + $result["result_code"] = ALLPAY_INVOICE_RESULT_CODE_NOT_FOUND; + $result["result_msg"] = ALLPAY_INVOICE_RESULT_MSG_NOT_FOUND; + return $result; + } + else if(empty($invoice_log['merchant_id'])) + { + $result = array(); + $result["result_code"] = ALLPAY_INVOICE_RESULT_CODE_INVOICE_ERROR; + $result["result_msg"] = ALLPAY_INVOICE_RESULT_MSG_INVOICE_ERROR; + return $result; + } + else + { + trigger_error(__FUNCTION__ .', invoice_no: ' . $invoice_no.', merchant_id: ' . $invoice_log['merchant_id'] . '..start..'); + } + + try { + $sMsg = '' ; + + $merchant_id = $invoice_log['merchant_id']; + // 1.載入 SDK 程式 + $allpay_invoice = $this->load_allpay_invoice_by_merchant_id($merchant_id); + // 2.寫入基本介接參數 + $allpay_invoice->Invoice_Method = ALLPAY_INVOICE_Allowance_Method ; + $allpay_invoice->Invoice_Url = ALLPAY_INVOICE_SERVICE_PATH.ALLPAY_INVOICE_Allowance_Url ; + + // 3.寫入發票傳送資訊 + array_push($allpay_invoice->Send['Items'], // 商品資訊 + array( + 'ItemName' => $item_name, 'ItemTaxType' => 1, 'ItemCount' => 1, 'ItemWord' => '筆', + 'ItemPrice' => $allowance_amt, 'ItemAmount' => $allowance_amt) + ); + $allpay_invoice->Send['CustomerName'] = '' ; // 買受人姓名 + $allpay_invoice->Send['InvoiceNo'] = $invoice_no; // 發票號碼 + $allpay_invoice->Send['AllowanceNotify'] = 'N'; // 通知類別 S.簡訊 E.電子郵件 A.皆通知 N.皆不通知 + //$allpay_invoice->Send['NotifyMail'] = $notify_mail; // 通知電子信箱 + //$allpay_invoice->Send['NotifyPhone'] = $notify_phone; // 通知手機號碼 + $allpay_invoice->Send['AllowanceAmount'] = $allowance_amt; // 含稅總金額 + + // 4.送出 + $aReturn_Info = $allpay_invoice->Check_Out(); + + // 5.返回 + foreach($aReturn_Info as $key => $value){ + $sMsg .= $key . ' => ' . $value . '
' ; + switch ($key){ + case "RtnCode": $rtn_code = $value; break; + case "RtnMsg": $rtn_msg = $value; break; + case "CheckMacValue": $check_mac_value = $value; break; // 驗證碼 + case "IA_Allow_No": $allowance_no = $value; break; // 折讓單號 + case "IA_Invoice_No": $allowance_invoice_no = $value; break; // 折讓發票號碼 + case "IA_Date": $allowance_date = $value; break; // 折讓時間 + case "IA_Remain_Allowance_Amt": $allowance_remain_amt = $value; break; // 折讓剩餘金額 + default: break; + } + } + + trigger_error(__FUNCTION__ .', invoice_no: ' . $invoice_no.', allowance_amt: ' . $allowance_amt. + ', item_name: ' . $item_name.'| return: '.$sMsg); + + if($rtn_code == '1') + { + $allowance_data = array( + 'allowance_no' => $allowance_no, + 'invoice_no' => $allowance_invoice_no, + 'allowance_date' => $allowance_date, + 'allowance_remain_amt' => $allowance_remain_amt, + 'check_mac_value' => $check_mac_value, + 'merchant_id' => $merchant_id + ); + + // 建立log + $this->db->insert('allpay_allowance_log', $allowance_data); + + $result = array(); + $result['result_code'] = ALLPAY_INVOICE_RESULT_CODE_OK; + $result['result_msg'] = $rtn_msg; + $result['check_mac_value'] = $check_mac_value; + $result['allowance_no'] = $allowance_no; + $result['allowance_invoice_no'] = $allowance_invoice_no; + $result['allowance_date'] = $allowance_date; + $result['allowance_remain_amt'] = $allowance_remain_amt; + return $result; + } + else + { + $result = array(); + $result['result_code'] = ALLPAY_INVOICE_RESULT_CODE_GG; + $result['result_msg'] = $rtn_msg; + return $result; + } + + }catch (Exception $e){ + // 例外錯誤處理。 + $sMsg = $e->getMessage(); + trigger_error(__FUNCTION__ .', invoice_no: ' . $invoice_no.', allowance_amt: ' . $allowance_amt. + ', item_name: ' . $item_name.'| return: '.$sMsg); + } + + $result = array(); + $result['result_code'] = ALLPAY_INVOICE_RESULT_CODE_GG; + $result['result_msg'] = ALLPAY_INVOICE_RESULT_MSG_GG; + return $result; + } + + // 8.發票作廢 API + protected function invoice_void($invoice_no, $reason_str) + { + // 取得開立記錄 + $invoice_log = $this->db + ->select('merchant_id') + ->from('allpay_invoice_log') + ->where(array('invoice_number' => $invoice_no)) + ->limit(1) + ->get() + ->row_array(); + + if (empty($invoice_log)) + { + $result = array(); + $result["result_code"] = ALLPAY_INVOICE_RESULT_CODE_NOT_FOUND; + $result["result_msg"] = ALLPAY_INVOICE_RESULT_MSG_NOT_FOUND; + return $result; + } + else if(empty($invoice_log['merchant_id'])) + { + $result = array(); + $result["result_code"] = ALLPAY_INVOICE_RESULT_CODE_INVOICE_ERROR; + $result["result_msg"] = ALLPAY_INVOICE_RESULT_MSG_INVOICE_ERROR; + return $result; + } + else + { + trigger_error(__FUNCTION__ .', invoice_no: ' . $invoice_no.', merchant_id: ' . $invoice_log['merchant_id'] . '..start..'); + } + + try { + $sMsg = '' ; + + $merchant_id = $invoice_log['merchant_id']; + // 1.載入 SDK 程式 + $allpay_invoice = $this->load_allpay_invoice_by_merchant_id($merchant_id); + // 2.寫入基本介接參數 + $allpay_invoice->Invoice_Method = ALLPAY_INVOICE_Invoice_Void_Method ; + $allpay_invoice->Invoice_Url = ALLPAY_INVOICE_SERVICE_PATH.ALLPAY_INVOICE_Invoice_Void_Url ; + + // 3.寫入發票傳送資訊 + $allpay_invoice->Send['InvoiceNumber'] = $invoice_no; // 發票號碼 + $allpay_invoice->Send['Reason'] = $reason_str; // 原因 + + // 4.送出 + $aReturn_Info = $allpay_invoice->Check_Out(); + + // 5.返回 + foreach($aReturn_Info as $key => $value){ + $sMsg .= $key . ' => ' . $value . '
' ; + switch ($key){ + case "RtnCode": $rtn_code = $value; break; + case "RtnMsg": $rtn_msg = $value; break; + case "CheckMacValue": $check_mac_value = $value; break; // 驗證碼 + case "InvoiceNumber": $invoice_number = $value; break; // 發票號碼 + default: break; + } + } + + trigger_error(__FUNCTION__.', invoice_no: ' . $invoice_no.', reason_str: ' . $reason_str.'| return: '.$sMsg); + + if($rtn_code == '1') + { + $result = array(); + $result['result_code'] = ALLPAY_INVOICE_RESULT_CODE_OK; + $result['result_msg'] = $rtn_msg; + $result['check_mac_value'] = $check_mac_value; + $result['invoice_number'] = $invoice_number; + return $result; + } + else + { + $result = array(); + $result['result_code'] = ALLPAY_INVOICE_RESULT_CODE_GG; + $result['result_msg'] = $rtn_msg; + return $result; + } + + }catch (Exception $e){ + // 例外錯誤處理。 + $sMsg = $e->getMessage(); + trigger_error(__FUNCTION__ .', invoice_no: ' . $invoice_no.', reason_str: ' . $reason_str.'| error: '.$sMsg); + } + + $result = array(); + $result['result_code'] = ALLPAY_INVOICE_RESULT_CODE_GG; + $result['result_msg'] = ALLPAY_INVOICE_RESULT_MSG_GG; + return $result; + } + + // 10.折讓作廢 API + public function allowance_void($invoice_no, $allowance_no, $reason_str) + { + // 取得折讓記錄 + $invoice_log = $this->db + ->select('merchant_id') + ->from('allpay_allowance_log') + ->where(array('invoice_no' => $invoice_no, 'allowance_no' => $allowance_no)) + ->limit(1) + ->get() + ->row_array(); + + if (empty($invoice_log)) + { + $result = array(); + $result["result_code"] = ALLPAY_INVOICE_RESULT_CODE_NOT_FOUND; + $result["result_msg"] = ALLPAY_INVOICE_RESULT_MSG_NOT_FOUND; + return $result; + } + else if(empty($invoice_log['merchant_id'])) + { + $result = array(); + $result["result_code"] = ALLPAY_INVOICE_RESULT_CODE_INVOICE_ERROR; + $result["result_msg"] = ALLPAY_INVOICE_RESULT_MSG_INVOICE_ERROR; + return $result; + } + else + { + trigger_error(__FUNCTION__ .', invoice_no: ' . $invoice_no.', merchant_id: ' . $invoice_log['merchant_id'] . '..start..'); + } + + try { + $sMsg = '' ; + + $merchant_id = $invoice_log['merchant_id']; + // 1.載入 SDK 程式 + $allpay_invoice = $this->load_allpay_invoice_by_merchant_id($merchant_id); + // 2.寫入基本介接參數 + $allpay_invoice->Invoice_Method = ALLPAY_INVOICE_Allowance_Void_Method ; + $allpay_invoice->Invoice_Url = ALLPAY_INVOICE_SERVICE_PATH.ALLPAY_INVOICE_Allowance_Void_Url ; + + /* + // 1.載入 SDK 程式 + $allpay_invoice = new AllInvoice ; + // 2.寫入基本介接參數 + $allpay_invoice->Invoice_Method = ALLPAY_INVOICE_Allowance_Void_Method ; + $allpay_invoice->Invoice_Url = ALLPAY_INVOICE_SERVICE_PATH.ALLPAY_INVOICE_Allowance_Void_Url ; + $allpay_invoice->MerchantID = ALLPAY_INVOICE_MerchantID ; + $allpay_invoice->HashKey = ALLPAY_INVOICE_HashKey ; + $allpay_invoice->HashIV = ALLPAY_INVOICE_HashIV ; + */ + + // 3.寫入發票傳送資訊 + $allpay_invoice->Send['InvoiceNo'] = $invoice_no; // 發票號碼 + $allpay_invoice->Send['AllowanceNo'] = $allowance_no; // 折讓編號 + $allpay_invoice->Send['Reason'] = $reason_str; // 作廢原因 + + // 4.送出 + $aReturn_Info = $allpay_invoice->Check_Out(); + + // 5.返回 + foreach($aReturn_Info as $key => $value){ + $sMsg .= $key . ' => ' . $value . '
' ; + switch ($key){ + case "RtnCode": $rtn_code = $value; break; + case "RtnMsg": $rtn_msg = $value; break; + case "CheckMacValue": $check_mac_value = $value; break; // 驗證碼 + case "IA_Invoice_No": $invoice_number = $value; break; // 發票號碼 + default: break; + } + } + + trigger_error(__FUNCTION__ .', invoice_no: ' . $invoice_no.', allowance_no: ' . $allowance_no. + ', reason_str: ' . $reason_str.'| return: '.$sMsg); + + if($rtn_code == '1') + { + $result = array(); + $result['result_code'] = ALLPAY_INVOICE_RESULT_CODE_OK; + $result['result_msg'] = $rtn_msg; + $result['check_mac_value'] = $check_mac_value; + $result['invoice_number'] = $invoice_number; + return $result; + } + else + { + $result = array(); + $result['result_code'] = ALLPAY_INVOICE_RESULT_CODE_GG; + $result['result_msg'] = $rtn_msg; + return $result; + } + + }catch (Exception $e){ + // 例外錯誤處理。 + $sMsg = $e->getMessage(); + trigger_error(__FUNCTION__ .', invoice_no: ' . $invoice_no.', allowance_no: ' . $allowance_no. + ', reason_str: ' . $reason_str.'| return: '.$sMsg); + } + + $result = array(); + $result['result_code'] = ALLPAY_INVOICE_RESULT_CODE_GG; + $result['result_msg'] = ALLPAY_INVOICE_RESULT_MSG_GG; + return $result; + } + + /* + // 通知 + protected function invoice_notify($eInvoiceNo, $eNotify, $eInvoiceTag, $eNotified, $eNotifyMail, $ePhone) + { + //$eInvoiceNo = $this->uri->segment(3); // 發票號碼 + //$eNotify = $this->uri->segment(4); // 發送方式 S.簡訊 E.電子郵件 A.皆通知 + //$eInvoiceTag = $this->uri->segment(5); // 發送類型 I.開立 II.作廢 A.折讓 AI.折讓作廢 AW.發票中獎 + //$eNotified = $this->uri->segment(6); // 發送對象 C.客戶 M.廠商 A.皆通知 + //$eNotifyMail = $this->uri->segment(7); // 發送電子信箱 + //$ePhone = $this->uri->segment(8); // 發送手機號碼 + + try { + $sMsg = '' ; + + // 1.載入 SDK 程式 + $allpay_invoice = new AllInvoice ; + // 2.寫入基本介接參數 + $allpay_invoice->Invoice_Method = ALLPAY_INVOICE_Invoice_Notify_Method ; + $allpay_invoice->Invoice_Url = ALLPAY_INVOICE_SERVICE_PATH.ALLPAY_INVOICE_Invoice_Notify_Url ; + $allpay_invoice->MerchantID = ALLPAY_INVOICE_MerchantID ; + $allpay_invoice->HashKey = ALLPAY_INVOICE_HashKey ; + $allpay_invoice->HashIV = ALLPAY_INVOICE_HashIV ; + + // 3.寫入發票傳送資訊 + $allpay_invoice->Send['InvoiceNo'] = $eInvoiceNo; // 發票號碼 + $allpay_invoice->Send ['Notify'] = $eNotify; // 發送方式 S.簡訊 E.電子郵件 A.皆通知 + $allpay_invoice->Send['InvoiceTag'] = $eInvoiceTag; // 發送類型 I.開立 II.作廢 A.折讓 AI.折讓作廢 AW.發票中獎 + $allpay_invoice->Send ['Notified'] = $eNotified; // 發送對象 C.客戶 M.廠商 A.皆通知 + $allpay_invoice->Send['NotifyMail'] = $eNotifyMail; // 發送電子信箱 + $allpay_invoice->Send['Phone'] = $ePhone; // 發送手機號碼 + + // 4.送出 + $aReturn_Info = $allpay_invoice->Check_Out(); + + // 5.返回 + foreach($aReturn_Info as $key => $value){ + $sMsg .= $key . ' => ' . $value . '
' ; + switch ($key){ + case "RtnCode": $eRtnCode = $value; break; + case "RtnMsg": $eRtnMsg = $value; break; + case "MerchantID": $eMerchantID = $value; break; + default: break; + } + } + + // error log + if($eRtnCode == '1'){ + // do nothing + }else{ + trigger_error(__FUNCTION__.', eInvoiceNo=>' . $eInvoiceNo.'
'.$sMsg); + } + + }catch (Exception $e){ + // 例外錯誤處理。 + $sMsg = $e->getMessage(); + trigger_error(__FUNCTION__.', eInvoiceNo=>' . $eInvoiceNo.'
'.$sMsg.'
email: '.$eNotifyMail.', mobile: '.$ePhone); + } + } + */ + + + // 測試遠端呼叫 + public function test_curl($station_no, $tx_bill_no, $amt, $company_no, $email, $mobile) + { + try{ + $param = array( + 'station_no' => $station_no, + 'tx_bill_no' => $tx_bill_no, + 'amt' => $amt, + 'company_no' => $company_no, + 'email' => $email, + 'mobile' => $mobile + ); + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, 'http://localhost/allpay_invoice.html/create_member_tx_bill_invoice'); + curl_setopt($ch, CURLOPT_HEADER, FALSE); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); + curl_setopt($ch, CURLOPT_POST, TRUE); + //curl_setopt($ch, CURLOPT_CONNECTTIMEOUT ,10); + //curl_setopt($ch, CURLOPT_TIMEOUT, 10); //timeout in seconds + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($param)); + $data = curl_exec($ch); + curl_close($ch); + + if(!empty($data)) + { + $data_decode = json_decode($data, true); + + if($data_decode['result_code'] == 'OK') + { + $result = array(); + $result['einvoice_track'] = substr($data_decode['invoice_no'], 0, 2); // 發票字軌 + $result['einvoice_no'] = substr($data_decode['invoice_no'], 2, 8); // 發票號碼 + return $result; + } + + //trigger_error(__FUNCTION__ . ', test 2: '. print_r($data_decode, true)); + } + + }catch (Exception $e){ + trigger_error(__FUNCTION__ . 'error:'.$e->getMessage()); + } + + $result = array(); + $result['einvoice_track'] = ''; // 發票字軌 + $result['einvoice_no'] = ''; // 發票號碼 + return $result; + } + + +} diff --git a/models/Allpay_payment_model.php b/models/Allpay_payment_model.php new file mode 100644 index 0000000..afe7218 --- /dev/null +++ b/models/Allpay_payment_model.php @@ -0,0 +1,20 @@ +load->database(); + } + + // 記錄 (歐付寶付費) + public function create_allpay_feedback_log($data) + { + $this->db->insert('allpay_feedback_log', $data); + return true; + } +} diff --git a/models/Carpark_model.php b/models/Carpark_model.php new file mode 100644 index 0000000..211ede3 --- /dev/null +++ b/models/Carpark_model.php @@ -0,0 +1,596 @@ +load->database(); + } + + public function init($vars) + { + $this->vars = $vars; + } + + // 月租會員加入 + public function member_add($data) + { + // 會員車輛基本資料檔 + // $data['start_date'] = "{$data['start_date']} 00:00:00"; + // $data['end_date'] = "{$data['end_date']} 23:59:59"; + $old_lpr = $data['old_lpr']; + unset($data['old_lpr']); + $data_car = array + ( + 'lpr' => $data['lpr'], + 'lpr_correct' => $data['lpr'], + 'etag' => $data['etag'], + 'station_no' => $data['station_no'], + 'start_time' => $data['start_date'], + 'end_time' => $data['end_date'] + ); + + $check_member_no = $data['member_no']; + unset($data['member_no']); + trigger_error("members:".print_r($data, true)."car:".print_r($data_car, true)); + if ($check_member_no == 0) // 新增一筆會員資料 + { + $this->db->insert('members', $data); + $data_car['member_no'] = $this->db->insert_id(); + $this->db->insert('member_car', $data_car); + } + else // update會員資料 + { + $this->db->update('members', $data, array('member_no' => $check_member_no)); + if ($old_lpr == $data['lpr']) // 沒有異動到車牌, 使用update, 否則重建一筆 + { + unset($data_car['lpr']); + unset($data_car['lpr_correct']); + + $this->db->update('member_car', $data_car, array('member_no' => $check_member_no)); + } + else + { + $this->db->delete('member_car', array('member_no' => $check_member_no)); + $data_car['member_no'] = $check_member_no; + $this->db->insert('member_car', $data_car); + } + } + + return true; + } + + + // 查詢車牌是否重複 + public function check_lpr($lpr) + { + $rows = $this->db->select('count(*) as counts') + ->from('members') + ->where(array('lpr' => $lpr)) + ->get() + ->row_array(); + + return $rows['counts']; + } + + + // 月租會員查詢 + public function member_query() + { + $results = $this->db->select('member_no, lpr, etag, member_name, mobile_no, start_date, end_date, contract_no, amt, member_id, tel_h, tel_o, addr, valid_time, station_no') + ->from('members') + ->order_by('station_no, lpr', 'asc') + ->get() + ->result_array(); + + return $results; + } + + + // 刪除月租會員 + public function member_delete($member_no) + { + $this->db->delete('members', array('member_no' => $member_no)); + $this->db->delete('member_car', array('member_no' => $member_no)); + + return true; + } + + + // 進出場現況表 + public function cario_list() + { + /* + $data_cario = $this->db + ->select('c.cario_no, c.in_out, in_lane, out_lane, c.in_time, c.out_time, c.minutes, c.obj_id as lpr, c.etag, c.in_pic_name, c.out_pic_name, m.member_name as owner') + ->from('cario c') + ->join('members m', 'c.member_no = m.member_no', 'left') + ->where(array('c.err' => 0)) + ->order_by('c.update_time', 'desc') + ->limit(10) + ->get() + ->result_array(); + */ + $sql = '(select c.cario_no, c.in_out, in_lane, out_lane, c.in_time, c.out_time, c.minutes, c.obj_id as lpr, c.etag, c.in_pic_name, c.out_pic_name, m.member_name as owner, c.in_time as time_order + from cario c left join members m on c.obj_id = m.lpr + where c.err = 0 and c.out_time is null) + union + (select c.cario_no, c.in_out, in_lane, out_lane, c.in_time, c.out_time, c.minutes, c.obj_id as lpr, c.etag, c.in_pic_name, c.out_pic_name, m.member_name as owner, c.out_time as time_order + from cario c left join members m on c.obj_id = m.lpr + where c.err = 0 and c.out_time is not null) + order by time_order desc limit 10;'; + $data_cario = $this->db->query($sql)->result_array(); + + // $lane_arr = array(0 => '入1', 1 => '入2', 3 => '出3', 3 => '出4'); + $idx = 0; + foreach($data_cario as $rows) + { + ++$rows['in_lane']; + ++$rows['out_lane']; + + //$lane_no = $rows['in_out'] == 'CI' ? "入{$rows['in_lane']}" : "入{$rows['in_lane']} -> 出{$rows['out_lane']}"; + $lane_no = empty($rows['out_time']) ? "入{$rows['in_lane']}" : "入{$rows['in_lane']} -> 出{$rows['out_lane']}"; // 2016/08/22 有離場時間就顯示 + + $pic_name = str_replace('.jpg', '', empty($rows['out_pic_name']) ? $rows['in_pic_name'] : $rows['out_pic_name']); + $arr = explode('-', $pic_name); + $pic_path = APP_URL.'pics/'.substr($arr[7], 0, 8).'/'.$pic_name; + + $data[$idx] = array + ( + // 'io_name' => $io_name[$rows['in_out']], + 'io_name' => $lane_no, + 'lpr' => $rows['lpr'], + // 'etag' => $rows['etag'], + 'etag' => $rows['etag'], + 'owner' => $rows['owner'], + 'io_time' => empty($rows['out_time']) ? $rows['in_time'] : "{$rows['in_time']}(入)
{$rows['out_time']}(出)
{$rows['minutes']}分(停留時間)", + 'pic_name' => $pic_path + ); + ++$idx; + } + + return $data; + } + + // 模糊比對 + function getLevenshteinSQLStatement($word, $target) + { + $words = array(); + + if(strlen($word) >= 5) + { + for ($i = 0; $i < strlen($word); $i++) { + // insertions + $words[] = substr($word, 0, $i) . '_' . substr($word, $i); + // deletions + $words[] = substr($word, 0, $i) . substr($word, $i + 1); + // substitutions + //$words[] = substr($word, 0, $i) . '_' . substr($word, $i + 1); + } + } + else + { + for ($i = 0; $i < strlen($word); $i++) { + // insertions + $words[] = substr($word, 0, $i) . '_' . substr($word, $i); + } + } + + // last insertion + $words[] = $word . '_'; + //return $words; + + $fuzzy_statement = ' ('; + foreach ($words as $idx => $word) + { + $fuzzy_statement .= " {$target} LIKE '%{$word}%' OR "; + } + $last_or_pos = strrpos($fuzzy_statement, 'OR'); + if($last_or_pos !== false) + { + $fuzzy_statement = substr_replace($fuzzy_statement, ')', $last_or_pos, strlen('OR')); + } + + return $fuzzy_statement; + } + + // 車號入場查詢 + public function carin_lpr_query($word) + { + // updated 2016/09/09 fuzzy search + if(empty($word) || strlen($word) < 4 || strlen($word) > 10) + { + return array(); + } + $fuzzy_statement = $this->getLevenshteinSQLStatement($word, 'c.obj_id'); + trigger_error("模糊比對 {$word} where: {$fuzzy_statement}"); + + $sql = "SELECT c.cario_no, c.in_out, in_lane, out_lane, c.in_time, c.out_time, c.minutes, c.obj_id as lpr, c.etag, c.in_pic_name, c.out_pic_name, m.member_name as owner + FROM cario c + LEFT JOIN members m ON c.obj_id = m.lpr + WHERE {$fuzzy_statement} AND c.err = 0 AND c.obj_type = 1 + ORDER BY c.update_time DESC + LIMIT 50"; + $data_cario = $this->db->query($sql)->result_array(); + + /* + $data_cario = $this->db + ->select('c.cario_no, c.in_out, in_lane, out_lane, c.in_time, c.out_time, c.minutes, c.obj_id as lpr, c.etag, c.in_pic_name, c.out_pic_name, m.member_name as owner') + ->from('cario c') + ->join('members m', 'c.member_no = m.member_no', 'left') + ->where(array('c.obj_type' => 1, 'obj_id' => $lpr)) + ->order_by('c.update_time', 'desc') + ->get() + ->result_array(); + */ + + $data = array(); + $idx = 0; + foreach($data_cario as $rows) + { + ++$rows['in_lane']; + ++$rows['out_lane']; + + $lane_no = empty($rows['out_time']) ? "入{$rows['in_lane']}" : "入{$rows['in_lane']} -> 出{$rows['out_lane']}"; + $io_time = empty($rows['out_time']) ? $rows['in_time'] : "{$rows['in_time']}(入)
{$rows['out_time']}(出)
{$rows['minutes']}分(停留時間)"; + + $pic_name = str_replace('.jpg', '', empty($rows['out_pic_name']) ? $rows['in_pic_name'] : $rows['out_pic_name']); + $arr = explode('-', $pic_name); + $pic_path = APP_URL.'pics/'.substr($arr[7], 0, 8).'/'.$pic_name; + + $data[$idx++] = array + ( + 'io_name' => $lane_no, + 'lpr' => $rows['lpr'], + 'etag' => $rows['etag'], + 'owner' => empty($rows['owner']) ? '' : $rows['owner'], + 'io_time' => $io_time, + 'pic_name' => $pic_path + ); + } + + return $data; + } + + + + // 車號入場查詢 + public function carin_time_query($time_query, $minutes_range) + { + $curr_time = date('Y-m-d H:i:s'); + + $start_time = date('Y-m-d H:i:s', strtotime("{$time_query} - {$minutes_range} minutes")); + $end_time = date('Y-m-d H:i:s', strtotime("{$time_query} + {$minutes_range} minutes")); + + $data_cario = $this->db + ->select('c.cario_no, c.in_out, in_lane, out_lane, c.in_time, c.out_time, c.minutes, c.obj_id as lpr, c.etag, c.in_pic_name, c.out_pic_name, m.member_name as owner') + ->from('cario c') + ->join('members m', 'c.obj_id = m.lpr', 'left') + ->where(array('c.obj_type' => 1, 'c.in_time >=' => $start_time, 'c.in_time <=' => $end_time)) + ->order_by('c.update_time', 'desc') + ->get() + ->result_array(); + + $data = array(); + $idx = 0; + foreach($data_cario as $rows) + { + ++$rows['in_lane']; + ++$rows['out_lane']; + + $lane_no = empty($rows['out_time']) ? "入{$rows['in_lane']}" : "入{$rows['in_lane']} -> 出{$rows['out_lane']}"; + $io_time = empty($rows['out_time']) ? $rows['in_time'] : "{$rows['in_time']}(入)
{$rows['out_time']}(出)
{$rows['minutes']}分(停留時間)"; + + $pic_name = str_replace('.jpg', '', empty($rows['out_pic_name']) ? $rows['in_pic_name'] : $rows['out_pic_name']); + $arr = explode('-', $pic_name); + $pic_path = APP_URL.'pics/'.substr($arr[7], 0, 8).'/'.$pic_name; + + $data[$idx++] = array + ( + 'io_name' => $lane_no, + 'lpr' => $rows['lpr'], + 'etag' => $rows['etag'], + 'owner' => empty($rows['owner']) ? '' : $rows['owner'], + 'io_time' => $io_time, + 'pic_name' => $pic_path + ); + } + + return $data; + } + + // 時間長度轉成日時分秒 + public function time2str($d1, $d2) + { + $time = strtotime($d2) - strtotime($d1); + + $day_str = floor($time/3600/24); + $day_str = $day_str ? $day_str .= '天 ' : ''; + + $hour_str = floor($time%(24*3600)/3600); + $hour_str = $hour_str ? $hour_str .= '小時 ' : ''; + + $minute_str = floor($time%3600/60); + $minute_str = $minute_str ? $minute_str .= '分' : ''; + + /* + $second_str = $time%3600%60; + $second_str = $second_str ? $second_str .= ' seconds ' : ''; + + $n_time = floor($time/3600/24)."days".floor($time%(24*3600)/3600)."Hour".floor($time%3600/60)."Minute".($time%3600%60)."Second"; + */ + + $n_time = $day_str . $hour_str . $minute_str; + return $n_time; + } + + + // 在席車位檢查未有入場資料清單 + public function pks_check_list($max_rows) + { + $data = array(); + $data = $this->db + ->select('pksno, lpr, in_time, pic_name') + ->from('pks') + ->where(array('status' => 'LR', 'cario_no' => 0, 'confirms' => 0, 'station_no' => STATION_NO)) + ->order_by('in_time', 'desc') + ->limit($max_rows) + ->get() + ->result_array(); + return $data; + } + + + // 重設在席查核 + public function reset_pks_check() + { + // 讀出未查核過的資料 + $data_pks = $this->db + ->select('pksno, lpr, in_time') + ->from('pks') + ->where(array('status' => 'LR', 'cario_no' => 0, 'station_no' => STATION_NO)) + ->get() + ->result_array(); + + // $tot = $this->db->num_rows(); // 總筆數 + $tot = count($data_pks); // 總筆數 + + $num_cario = 0; // 入場資料筆數 + foreach($data_pks as $rows) + { + $lpr = $rows['lpr']; + if ($lpr == 'NONE') continue; // 車辨失敗者不處理 + + $pksno = $rows['pksno']; + $pks_in_time = $rows['in_time']; + // 讀取進場時間, 如讀不到資料, 以目前時間取代(add by TZUSS 2016-02-23) + $rows_cario = $this->db + ->select('cario_no, in_time') + ->from('cario') + ->where(array('in_out' => 'CI', 'obj_id' => $lpr, 'finished' => 0, 'err' => 0, 'station_no' => STATION_NO)) + ->order_by('cario_no', 'desc') + ->limit(1) + ->get() + ->row_array(); + // if ($this->db->num_rows() == 1) // 有入場資料 + if (!empty($rows_cario['cario_no'])) // 有入cario_no場資料 + { + $cario_no = $rows_cario['cario_no']; // 入場序號 + $in_time = $rows_cario['in_time']; + // 在席與入場資料相符, 分別在cario與pks記錄之 + $data = array + ( + 'pksno' => $pksno, + 'pks_time' => $pks_in_time + ); + $this->db->update('cario', $data, array('cario_no' => $cario_no, 'station_no' => STATION_NO)); + $data = array + ( + 'cario_no' => $cario_no, + 'in_time' => $in_time + ); + // 車號及照片檔名填入資料庫內 + $this->db->update('pks', $data, array('pksno' => $pksno, 'station_no' => STATION_NO)); + ++$num_cario; + } + + } + return array('tot' => $tot, 'tot_correct' => $num_cario); + } + + + // 更正在席車號 + public function correct_pks_lpr($pksno, $lpr) + { + + // 讀取進場時間, 如讀不到資料, 以目前時間取代(add by TZUSS 2016-02-23) + $rows_cario = $this->db + ->select('cario_no, in_time') + ->from('cario') + ->where(array('in_out' => 'CI', 'obj_id' => $lpr, 'finished' => 0, 'err' => 0, 'station_no' => STATION_NO)) + ->order_by('cario_no', 'desc') + ->limit(1) + ->get() + ->row_array(); + + if (!empty($rows_cario['cario_no'])) // 有cario_no入場資料 + { + $cario_no = $rows_cario['cario_no']; // 入場序號 + $in_time = $rows_cario['in_time']; + // 在席與入場資料相符, 分別在cario與pks記錄之 + $data = array + ( + 'pksno' => $pksno, + 'pks_time' => $in_time + ); + $this->db->update('cario', $data, array('cario_no' => $cario_no, 'station_no' => STATION_NO)); + $data = array + ( + 'confirms' => 1, + 'cario_no' => $cario_no, + 'lpr' => $lpr, + 'in_time' => $in_time + ); + // 車號及照片檔名填入資料庫內 + $this->db->update('pks', $data, array('pksno' => $pksno, 'station_no' => STATION_NO)); + $results = array + ( + 'err' => 0, + 'cario_no' => $cario_no + ); + } + else // 無入場資料 + { + $data = array + ( + 'confirms' => 1, + 'lpr' => $lpr + ); + + $this->db->update('pks', $data, array('pksno' => $pksno, 'station_no' => STATION_NO)); + $results = array + ( + 'err' => 0, + 'cario_no' => 0 // 車號查無入場資料 + ); + } + + return $results; + } + + + // 入場車號查核在席無資料清單 + public function carin_check_list($max_rows) + { + $data = array(); + $rows_cario = $this->db + ->select('cario_no, obj_id as lpr, in_time, member_no, in_pic_name') + ->from('cario') + ->where('in_out', 'CI') + ->where(array('pksno' => 0, 'finished' => 0, 'err' => 0, 'confirms' => 0, 'station_no' => STATION_NO, 'in_time <=' => 'date_sub(now(), interval 20 minute)'), null, false) + ->order_by('cario_no', 'desc') + ->limit($max_rows) + ->get() + ->result_array(); + + $idx = 0; + foreach($rows_cario as $rows) + { + $data[$idx++] = array + ( + 'cario_no' => $rows['cario_no'], + 'lpr' => $rows['lpr'], + 'in_time' => $rows['in_time'], + 'type' => $rows['member_no'] == 0 ? '' : '月租', + 'pic_name' => str_replace('-', '', substr($rows['in_time'], 0, 10)) . '/' . $rows['in_pic_name'] + ); + } + return $data; + } + + + + // 更正入場車號 + public function correct_carin_lpr($cario_no, $lpr, $in_time) + { + $rows = $this->db + ->select('pksno, cario_no, in_time') + ->from('pks') + ->where(array('status' => 'LR', 'lpr' => $lpr, 'confirms' => 0, 'station_no' => STATION_NO)) + ->limit(1) + ->get() + ->row_array(); + // 如果在席資料相符 + if (!empty($rows['pksno'])) + { + $pksno = $rows['pksno']; + + $data = array + ( + 'cario_no' => $cario_no, + 'in_time' => $in_time + ); + + $this->db->update('pks', $data, array('pksno' => $pksno, 'station_no' => STATION_NO)); + + $data_cario = array + ( + 'obj_id' => $lpr, + 'pksno' => $pksno, + 'pks_time' => $in_time, + 'confirms' => 1 + ); + } + else // 無在席資料 + { + $data_cario = array + ( + 'obj_id' => $lpr, + 'pksno' => 0, + 'confirms' => 1 + ); + } + + $this->db->update('cario', $data_cario, array('cario_no' => $cario_no, 'station_no' => STATION_NO)); + + return(array('pksno' => $data_cario['pksno'])); + } + + // 查詢行動支付記錄 + public function tx_bill_query() + { + $sql = "SELECT + tx_bill.order_no as order_no, tx_bill.lpr as lpr, tx_bill.invoice_no as invoice_no, tx_bill.in_time as in_time, tx_bill.balance_time as balance_time, tx_bill.company_no as company_no, tx_bill.email as email, tx_bill.mobile as mobile, tx_bill.amt as amt, tx_bill.tx_time as tx_time, + allpay_feedback_log.rtn_msg as rtn_msg, allpay_feedback_log.payment_type as payment_type, + cario.out_before_time as out_before_time + FROM tx_bill + LEFT JOIN cario ON tx_bill.cario_no = cario.cario_no + LEFT JOIN allpay_feedback_log ON tx_bill.order_no = allpay_feedback_log.merchant_trade_no + WHERE tx_bill.status = 111 + ORDER BY tx_bill.tx_time DESC"; + + return $this->db->query($sql)->result_array(); + } + + // 查詢月租繳款機記錄 + public function tx_bill_ats_query() + { + $sql = "SELECT + tx_bill_ats.order_no as order_no, tx_bill_ats.lpr as lpr, tx_bill_ats.invoice_no as invoice_no, + tx_bill_ats.end_time as end_time, tx_bill_ats.next_start_time as next_start_time, tx_bill_ats.next_end_time as next_end_time, + tx_bill_ats.company_no as company_no, tx_bill_ats.email as email, tx_bill_ats.mobile as mobile, tx_bill_ats.amt as amt, + tx_bill_ats.remarks as remarks, tx_bill_ats.member_name as member_name, tx_bill_ats.tx_time as tx_time, + allpay_feedback_log.rtn_msg as rtn_msg, allpay_feedback_log.payment_type as payment_type + FROM tx_bill_ats + LEFT JOIN allpay_feedback_log ON tx_bill_ats.order_no = allpay_feedback_log.merchant_trade_no + WHERE tx_bill_ats.status = 111 + ORDER BY tx_bill_ats.tx_time DESC"; + + return $this->db->query($sql)->result_array(); + } + + // 查詢樓層在席群組 + public function pks_group_query() + { + $sql = "SELECT + pks_groups.station_no, pks_groups.group_name as group_name, pks_groups.tot as tot, pks_groups.parked as parked, pks_groups.availables as availables, pks_groups.group_id as group_id, pks_groups.renum as renum + FROM pks_groups + ORDER BY pks_groups.group_id DESC"; + + return $this->db->query($sql)->result_array(); + } + + // 送出至message queue(目前用mqtt) + public function mq_send($topic, $msg) + { + $this->vars['mqtt']->publish($topic, $msg, 0); + trigger_error("mqtt:{$topic}|{$msg}"); + } + +} diff --git a/models/Carpayment_model.php b/models/Carpayment_model.php new file mode 100644 index 0000000..dbd6f5a --- /dev/null +++ b/models/Carpayment_model.php @@ -0,0 +1,653 @@ + '車入', 'O' => '車出', 'MI' => '機入', 'MO' => '機出', 'FI' => '樓入', 'FO' => '樓出'); + var $now_str; + + function __construct() + { + parent::__construct(); + $this->load->database(); + $this->now_str = date('Y-m-d H:i:s'); + } + + public function init($vars) + { + $this->vars = $vars; + } + + // 博辰通知付款完成 + public function p2payed($parms, $opay=false) + { + $result = $this->db->select("in_time, cario_no, station_no") + ->from('cario') + ->where(array('obj_type' => 1, 'obj_id' => $parms['lpr'], 'finished' => 0, 'err' => 0)) + ->order_by('cario_no', 'desc') + ->limit(1) + ->get() + ->row_array(); + + // 查不到車號才找備援碼 + if(!isset($result['in_time']) && is_numeric($parms['lpr']) && strlen($parms['lpr']) == 6) + { + $result = $this->db->select("in_time, cario_no, station_no") + ->from('cario') + ->where(array('obj_type' => 1, 'ticket_no' => $parms['lpr'], 'finished' => 0, 'err' => 0)) + ->order_by('cario_no', 'desc') + ->limit(1) + ->get() + ->row_array(); + + // 找不到記錄 + if(!isset($result['in_time'])) + { + trigger_error(__FUNCTION__ . '..not found..' . print_r($parms, true)); + return false; + } + + $in_time = new DateTime($result['in_time']); + $pay_time = new DateTime($parms['pay_time']); + + // 若間隔小於 15 分鐘, 拿現在時間來當付款時間 + $parms['pay_time'] = (($pay_time->getTimestamp() - $in_time->getTimestamp()) / 60 < 15) ? $this->now_str : $parms['pay_time']; + + if($opay) + { + // A. (備援碼)歐付寶 + $parms2 = array('seqno' => $result['cario_no'], 'amt' => $parms['amt'], 'lpr' => $parms['lpr']); + return $this->m2payed($parms2); + + } + else + { + // B. (備援碼)一般繳費機 + $data = array + ( + 'out_before_time' => date('Y-m-d H:i:s', strtotime("{$parms['pay_time']} + 15 minutes")), + 'pay_time' => $parms['pay_time'], + 'pay_type' => $parms['pay_type'], + 'payed' => 1 + ); + + $this->db->where(array('cario_no' => $result['cario_no']))->update('cario', $data); + + if (!$this->db->affected_rows()) + { + trigger_error("(備援碼) 付款失敗:{$parms['lpr']}|{$data['out_before_time']}"); + return 'fail'; + } + + trigger_error("(備援碼) 付款後更新時間:{$parms['lpr']}|{$data['out_before_time']}"); + return 'ok'; + } + } + + // A. 歐付寶 + if($opay) + { + $parms2 = array('seqno' => $result['cario_no'], 'amt' => $parms['amt'], 'lpr' => $parms['lpr']); + $result = $this->m2payed($parms2); + + if($result != 'ok') + return $result; + } + else + { + // B. 一般繳費機 + $in_time = new DateTime($result['in_time']); + $pay_time = new DateTime($parms['pay_time']); + + // 若間隔小於 15 分鐘, 拿現在時間來當付款時間 + $parms['pay_time'] = (($pay_time->getTimestamp() - $in_time->getTimestamp()) / 60 < 15) ? $this->now_str : $parms['pay_time']; + + $data = array + ( + 'out_before_time' => date('Y-m-d H:i:s', strtotime("{$parms['pay_time']} + 15 minutes")), + 'pay_time' => $parms['pay_time'], + 'pay_type' => $parms['pay_type'], + 'payed' => 1 + ); + + $this->db + ->where(array('obj_type' => 1, 'obj_id' => $parms['lpr'], 'finished' => 0, 'err' => 0)) + ->update('cario', $data); + + if (!$this->db->affected_rows()) + { + trigger_error("付款失敗:{$parms['lpr']}|{$data['out_before_time']}"); + return 'fail'; + } + + trigger_error("付款後更新時間:{$parms['lpr']}|{$data['out_before_time']}"); + } + + // 傳送付款更新記錄 + $sync_agent = new AltobSyncAgent(); + $sync_agent->init($result['station_no'], $result['in_time']); + $sync_agent->cario_no = $result['cario_no']; // 進出編號 + $sync_result = $sync_agent->sync_st_pay($parms['lpr'], $parms['pay_time'], $parms['pay_type'], + date('Y-m-d H:i:s', strtotime("{$parms['pay_time']} + 15 minutes"))); + trigger_error( "..sync_st_pay.." . $sync_result); + + return 'ok'; + } + + + // 繳費機告知已付款 (new 2016/07/15) + // http://localhost/carpayment.html/ats2payed/車牌/金額/場站編號/序號/MD5 + // md5(車牌.金額.場站編號.序號) + public function ats2payed($parms) + { + $order_no = $parms['order_no']; + $bill_result = $this->db->from('tx_bill_ats') + ->where(array('order_no' => $order_no, 'status' => 111)) + ->limit(1) + ->get() + ->row_array(); + + if(!empty($bill_result)){ + $member_no = $bill_result['member_no']; + $station_no = $bill_result['station_no']; + $next_start_time = $bill_result['next_start_time']; + $next_end_time = $bill_result['next_end_time']; + + $data = array( + 'end_date' => $bill_result['next_end_time'] // TODO: 有被任何一筆序號蓋資料的可能 + ); + + $this->db + ->where(array('member_no' => $member_no, 'station_no' => $station_no)) + ->update('members', $data); + if ($this->db->affected_rows()) + { + trigger_error("繳費機更新會員資料完成,{$parms['lpr']},金額:{$parms['amt']},序號:{$parms['order_no']}"); + return 'ok'; + } + else + { + trigger_error("繳費機更新會員資料失敗,{$parms['lpr']},金額:{$parms['amt']},序號:{$parms['order_no']}"); + return 'fail'; + } + } + } + + + // 行動支付, 手機告知已付款 + // http://203.75.167.89/carpayment.html/m2payed/ABC1234/120/12112/12345/1f3870be274f6c49b3e31a0c6728957f + // http://203.75.167.89/carpayment.html/m2payed/車牌/金額/場站編號/序號/MD5 + // md5(車牌.金額.場站編號.序號) + public function m2payed($parms) + { + $data = array + ( + 'out_before_time' => date('Y-m-d H:i:s', strtotime(" + 15 minutes")), + 'pay_time' => date('Y-m-d H:i:s'), + 'pay_type' => 4, // 歐付寶行動支付 + 'payed' => 1 + ); + + $this->db + ->where(array('cario_no' => $parms['seqno'])) + ->update('cario', $data); + if ($this->db->affected_rows()) + { + trigger_error("歐付寶行動支付成功,{$parms['lpr']}金額:{$parms['amt']},序號:{$parms['seqno']}"); + return 'ok'; + } + else + { + trigger_error("歐付寶行動支付失敗,{$parms['lpr']}金額:{$parms['amt']},序號:{$parms['seqno']}"); + return 'fail'; + } + } + + + + /* + 月租繳款完成 + http://203.75.167.89/carpayment.html/memberpayed/12345/ABC1234/120/12112/1/2016-01-31/1f3870be274f6c49b3e31a0c6728957f + http://203.75.167.89/carpayment.html/memberpayed/會員號碼/車牌/金額/場站編號/月繳/本期到期日/md5 + md5(會員號碼.車牌.金額.場站編號.月繳.本期到期日) + + public function memberpayed($parms) + { + // update members (???) + } + */ + + // 模糊比對 + function getLevenshteinSQLStatement($word, $target) + { + $words = array(); + + if(strlen($word) >= 5) + { + for ($i = 0; $i < strlen($word); $i++) { + // insertions + $words[] = substr($word, 0, $i) . '_' . substr($word, $i); + // deletions + $words[] = substr($word, 0, $i) . substr($word, $i + 1); + // substitutions + //$words[] = substr($word, 0, $i) . '_' . substr($word, $i + 1); + } + } + else + { + for ($i = 0; $i < strlen($word); $i++) { + // insertions + $words[] = substr($word, 0, $i) . '_' . substr($word, $i); + } + } + + // last insertion + $words[] = $word . '_'; + //return $words; + + $fuzzy_statement = ' ('; + foreach ($words as $idx => $word) + { + $fuzzy_statement .= " {$target} LIKE '%{$word}%' OR "; + } + $last_or_pos = strrpos($fuzzy_statement, 'OR'); + if($last_or_pos !== false) + { + $fuzzy_statement = substr_replace($fuzzy_statement, ')', $last_or_pos, strlen('OR')); + } + + return $fuzzy_statement; + } + + // 取得進場資訊 (模糊比對) + function q_fuzzy_pks($word) + { + if(empty($word) || strlen($word) < 4 || strlen($word) > 10) + { + return null; + } + // 備援數字使用 + else if(is_numeric($word) && strlen($word) == 6) + { + trigger_error(__FUNCTION__ . '..備援查詢: ' . $word); + + $sql = "SELECT obj_id as lpr, ticket_no + FROM cario + WHERE finished = 0 AND err = 0 + AND out_before_time > DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 5 DAY) + AND ticket_no = {$word} + ORDER BY out_before_time DESC"; + $retults = $this->db->query($sql)->result_array(); + return $retults; + } + $fuzzy_statement = $this->getLevenshteinSQLStatement($word, 'obj_id'); + //trigger_error("模糊比對 {$word} where: {$fuzzy_statement}"); + + $sql = "SELECT obj_id as lpr, ticket_no + FROM cario + WHERE {$fuzzy_statement} AND finished = 0 AND err = 0 + AND out_before_time > DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 5 DAY) + GROUP BY obj_id + ORDER BY out_before_time DESC"; + $retults = $this->db->query($sql)->result_array(); + return $retults; + } + + // 建立博辰查詢入場時間資料 (by ticket_no) + function gen_query_data_type4($ticket_no) + { + $data = array(); + + // s2. 完整車牌號碼: 右邊補空格補滿7碼 + $data['lpr'] = $ticket_no; + + // s3. 塔號_車格號碼: 該車牌相關車輛所停車的停車塔號或樓層號碼, + // 地下室部分為負值例如B1為-1,平面停車場為1,二樓為2 (左邊補 ‘0’ 補滿2碼), + // 停車格號4碼(左邊補 ‘0’ 補滿4碼), + // 樓層和停車格號中間以 ‘_’ 分隔,例如:”01_0101” + $data['seat_no'] = 'XX_XXXX'; + $data['ticket'] = 0; + $data['start_date'] = '2000/01/01'; + $data['end_date'] = '2000/01/01'; + $data['start_time'] = '00:00'; + $data['end_time'] = '00:00'; + + $result = $this->db->select("in_time, date_format(pay_time, '%Y/%m/%d %T') as pay_time, in_pic_name, member_no") + ->from('cario') + ->where(array('obj_type' => 1, 'ticket_no' => $ticket_no, 'finished' => 0, 'err' => 0)) + ->order_by('cario_no', 'desc') + ->limit(1) + ->get() + ->row_array(); + + if (!empty($result['in_time'])) + { + // s5. 入場時間: 格式為"yyyy/MM/dd HH:mm:ss",時間為24小時制,若無紀錄秒數秒數部分可填”00” + $data['in_time'] = $result['in_time']; + // s6. 入場車牌圖片路徑: 貴公司的絕對路徑,我方使用網路芳鄰或FTP下載 + $pic_name_arr = explode('-', $result['in_pic_name']); + $date_num = substr($pic_name_arr[7], 0, 8); + $data['in_pic_name'] = "\\\\192.168.10.201\\pics\\{$date_num}\\{$result['in_pic_name']}"; + // s7. 繳費時間: 無繳費時間時為"2000/01/01 00:00:00",格式為"yyyy/MM/dd HH:mm:ss",時間為24小時制,若無紀錄秒數秒數部分可填”00” + $data['pay_time'] = !empty($result['pay_time']) ? $result['pay_time'] : '2000/01/01 00:00:00'; + } + else + { + $data['in_time'] = ''; + $data['in_pic_name'] = ''; + $data['pay_time'] = '2000/01/01 00:00:00'; + } + + return $data; + } + + // 建立博辰查詢入場時間資料 + function gen_query_data($lpr) + { + $data = array(); + + // s2. 完整車牌號碼: 右邊補空格補滿7碼 + $data['lpr'] = $lpr; //str_pad($lpr, 7, ' ', STR_PAD_RIGHT); + + // s3. 塔號_車格號碼: 該車牌相關車輛所停車的停車塔號或樓層號碼, + // 地下室部分為負值例如B1為-1,平面停車場為1,二樓為2 (左邊補 ‘0’ 補滿2碼), + // 停車格號4碼(左邊補 ‘0’ 補滿4碼), + // 樓層和停車格號中間以 ‘_’ 分隔,例如:”01_0101” + $sql = "select p.pksno, m.group_id + from pks p, pks_group_member m, pks_groups g + where p.pksno = m.pksno + and m.group_id = g.group_id + and g.group_type = 1 + and p.lpr = '{$lpr}' + limit 1"; + $rows = $this->db->query($sql)->row_array(); + if (!empty($rows['pksno'])) + { + $data['seat_no'] = ($rows['group_id'] == 'B1' ? '-1' : '0' . substr($rows['group_id'], -1)) . '_0' . substr($rows['pksno'], -3); + } + else + { + $data['seat_no'] = 'XX_XXXX'; // '-1_0028'; + } + + // 查詢是否月租會員 + $result = $this->db->select("date_format(start_date, '%Y/%m/%d') as start_date, date_format(end_date,'%Y/%m/%d') as end_date") + ->from('members') + ->where(array( + 'lpr' => $lpr, + 'start_date <' => $this->vars['date_time'], + 'end_date >=' => $this->vars['date_time']) + , false) + ->limit(1) + ->get() + ->row_array(); + if (!empty($result['start_date'])) // 月租會員 + { + $data['ticket'] = 1; // s4. 是否為月票: 0:非月票, 1:月票 + $data['start_date'] = $result['start_date'];// s8. 有效起始時間: 非月票時為"2000/01/01", 格式為"yyyy/MM/dd" + $data['end_date'] = $result['end_date']; // s9. 有效截止日期: 非月票時為"2000/01/01", 格式為"yyyy/MM/dd" + $data['start_time'] = '00:00'; // s10. 使用起始時段: 非月票時為"00:00", 格式為"HH:mm" + $data['end_time'] = '23:59'; // s11. 使用結束時段: 非月票時為"00:00", 格式為"HH:mm" + } + else // 臨停車 + { + $data['ticket'] = 0; + $data['start_date'] = '2000/01/01'; + $data['end_date'] = '2000/01/01'; + $data['start_time'] = '00:00'; + $data['end_time'] = '00:00'; + } + + $result = $this->db->select("in_time, date_format(pay_time, '%Y/%m/%d %T') as pay_time, in_pic_name, member_no") + ->from('cario') + ->where(array('obj_type' => 1, 'obj_id' => $lpr, 'finished' => 0, 'err' => 0)) + ->order_by('cario_no', 'desc') + ->limit(1) + ->get() + ->row_array(); + + if (!empty($result['in_time'])) + { + // s5. 入場時間: 格式為"yyyy/MM/dd HH:mm:ss",時間為24小時制,若無紀錄秒數秒數部分可填”00” + $data['in_time'] = $result['in_time']; + // s6. 入場車牌圖片路徑: 貴公司的絕對路徑,我方使用網路芳鄰或FTP下載 + $pic_name_arr = explode('-', $result['in_pic_name']); + $date_num = substr($pic_name_arr[7], 0, 8); + $data['in_pic_name'] = "\\\\192.168.10.201\\pics\\{$date_num}\\{$result['in_pic_name']}"; + // s7. 繳費時間: 無繳費時間時為"2000/01/01 00:00:00",格式為"yyyy/MM/dd HH:mm:ss",時間為24小時制,若無紀錄秒數秒數部分可填”00” + $data['pay_time'] = !empty($result['pay_time']) ? $result['pay_time'] : '2000/01/01 00:00:00'; + } + else + { + $data['in_time'] = ''; + $data['in_pic_name'] = ''; + $data['pay_time'] = '2000/01/01 00:00:00'; + } + + return $data; + } + + // 博辰查詢入場時間 (fuzzy) + public function query_in_fuzzy($lpr) + { + $fuzzy_result = $this->q_fuzzy_pks($lpr); + + if(!empty($fuzzy_result) && count($fuzzy_result) > 0) + { + $data = array(); + // s2 ~ s11 的資料會因模糊比對筆數增加或減少而增減 + foreach ($fuzzy_result as $idx => $rows) + { + $lpr = $rows['lpr']; + $ticket_no = $rows['ticket_no']; + + if($lpr == 'NONE') + { + $tmp_data = $this->gen_query_data_type4($ticket_no); // 備緩搜尋 + } + else + { + $tmp_data = $this->gen_query_data($lpr); // 模糊搜尋 + } + + if($tmp_data['in_time'] == '') + { + // 若查無入場時間, 直接乎略這筆 + trigger_error("查無入場時間, 直接乎略這筆[{$lpr}]:".print_r($rows, true)); + } + else + { + $data['results'][$idx] = $tmp_data; + } + + } + $data['count'] = count($fuzzy_result); + } + else + { + $data_0 = array(); + $data_0['lpr'] = str_pad($lpr, 7, ' ', STR_PAD_RIGHT); + $data_0['seat_no'] = 'XX_XXXX'; + $data_0['ticket'] = 0; + $data_0['start_date'] = '2000/01/01'; + $data_0['end_date'] = '2000/01/01'; + $data_0['start_time'] = '00:00'; + $data_0['end_time'] = '00:00'; + $data_0['in_time'] = ''; + $data_0['pay_time'] = '2000/01/01 00:00:00'; + $data_0['in_pic_name'] = ''; + + $data = array(); + $data['results'][0] = $data_0; + $data['count'] = 0; + } + + trigger_error("fuzzy aps查詢入場時間[{$lpr}]:".print_r($data, true)); + + return $data; + } + + // 博辰查詢入場時間 + public function query_in($lpr) + { + $data = array(); + + // 讀取樓層數, group_type = 2為樓層 + $sql = "select p.pksno, m.group_id + from pks p, pks_group_member m, pks_groups g + where p.pksno = m.pksno + and m.group_id = g.group_id + and g.group_type = 1 + and p.lpr = '{$lpr}' + limit 1"; + $rows = $this->db->query($sql)->row_array(); + if (!empty($rows['pksno'])) + { + $data['seat_no'] = ($rows['group_id'] == 'B1' ? '-1' : '0' . substr($rows['group_id'], -1)) . '_' . substr($rows['pksno'], -3); + } + else + { + $data['seat_no'] = 'XX_XXXX'; + } + + // 查詢是否月租會員 + $result = $this->db->select("date_format(start_date, '%Y/%m/%d') as start_date, date_format(end_date,'%Y/%m/%d') as end_date") + ->from('members') + ->where(array('lpr' => $lpr, 'end_date >=' => $this->vars['date_time']), false) + ->limit(1) + ->get() + ->row_array(); + if (!empty($result['start_date'])) // 月租會員 + { + $data['ticket'] = 1; + $data['start_date'] = $result['start_date']; + $data['end_date'] = $result['end_date']; + $data['start_time'] = '00:00'; + $data['end_time'] = '23:59'; + } + else // 臨停車 + { + $data['ticket'] = 0; + $data['start_date'] = '2000/01/01'; + $data['end_date'] = '2000/01/01'; + $data['start_time'] = '00:00'; + $data['end_time'] = '00:00'; + } + + $result = $this->db->select("in_time, date_format(pay_time, '%Y/%m/%d %T') as pay_time, in_pic_name, member_no") + ->from('cario') + ->where(array('obj_type' => 1, 'obj_id' => $lpr, 'finished' => 0, 'err' => 0)) + ->order_by('cario_no', 'desc') + ->limit(1) + ->get() + ->row_array(); + + if (!empty($result['in_time'])) + { + trigger_error("aps查詢入場時間|{$lpr}|{$result['in_time']}|{$result['in_pic_name']}"); + $data['in_time'] = $result['in_time']; + $data['pay_time'] = !empty($result['pay_time']) ? $result['pay_time'] : '2000/01/01 00:00:00'; + $pic_name_arr = explode('-', $result['in_pic_name']); + $date_num = substr($pic_name_arr[7], 0, 8); + //$data['in_pic_name'] = "\\\\192.168.10.201\\pics\\{$date_num}\\{$result['in_pic_name']}"; // 2016/07/25 update + //$data['in_pic_name'] = "D:/altob/home/data/parkings/cars/pics/{$date_num}/{$result['in_pic_name']}"; // 2016/07/25 update + $data['in_pic_name'] = "\\\\192.168.10.201\\pics\\{$date_num}\\{$result['in_pic_name']}"; // 2016/07/25 update + // $data['in_pic_name'] = "{$date_num}/{$result['in_pic_name']}"; + $data['records'] = 1; + } + else + { + $data['in_time'] = ''; + $data['pay_time'] = '2000/01/01 00:00:00'; + $data['in_pic_name'] = ''; + $data['records'] = 0; + } + + trigger_error("aps查詢入場時間[{$lpr}]:".print_r($data, true)); + // return array('in_time' => '', 'in_pic_name' => '', 'records' => 0, 'ticket' => 0, 'seat_no' => 'XX_XXXX'); + return $data; + } + + + // 行動設備查詢入場時間 + // http://203.75.167.89/carpayment.html/m2query_in/ABC1234/12112/1f3870be274f6c49b3e31a0c6728957f + // http://203.75.167.89/carpayment.html/m2query_in/車牌/場站編號/MD5 + // 回傳0: 失敗, 成功: 12345,60(第一欄位非0數字代表成功, 第二欄位為金額), 此值在付款時必需傳回, 否則視為非法 + public function m2query_in($parms) + { + $result = $this->db->select('cario_no, out_before_time') + ->from('cario') + ->where(array('obj_type' => 1, 'obj_id' => $parms['lpr'], 'station_no' => $parms['station_no'], 'finished' => 0, 'err' => 0)) + ->order_by('cario_no', 'desc') + ->limit(1) + ->get() + ->row_array(); + + if (!empty($result['cario_no'])) + { + trigger_error("行動設備查詢入場時間成功|{$lpr}|{$result['cario_no']}|{$result['in_time']}"); + // call計費模組 + $amt = 10; + } + else + { + $result['cario_no'] = 0; + $amt = 0; + trigger_error('行動設備查詢入場時間失敗'.print_r($parms, true)); + } + + return "{$result['cario_no']},{$amt}"; + } + + + // 臨停未結清單 + public function cario_temp_not_finished_query_all($station_no, $q_item, $q_str) + { + $where_station = $station_no == 0 ? '' : " station_no = {$station_no} and "; // 如為0, 則全部場站讀取 + + switch($q_item) + { + case 'in_time': + $items = "{$q_item} >="; + $q_str .= ' 23:59:59'; + break; + case 'lpr': + $items = "{$q_item} like "; + $q_str = strtoupper($q_str).'%'; + break; + default: + $items = "{$q_item} like "; + $q_str .= '%'; + break; + } + + $sql = " + SELECT + cario_no, + station_no, + obj_id as lpr, + in_time, + out_before_time, + pay_time + FROM cario + WHERE + {$where_station} {$items} '{$q_str}' + and obj_type = 1 and finished = 0 and err = 0 and confirms = 0 + and member_no = 0 + and out_time is null + ORDER BY cario.cario_no asc + "; + + //trigger_error(__FUNCTION__ . "test sql: {$sql}"); + + $results = $this->db->query($sql)->result_array(); + + return $results; + } + +} diff --git a/models/Cars_model.php b/models/Cars_model.php new file mode 100644 index 0000000..2175694 --- /dev/null +++ b/models/Cars_model.php @@ -0,0 +1,1281 @@ + '車入', 'O' => '車出', 'MI' => '機入', 'MO' => '機出', 'FI' => '樓入', 'FO' => '樓出'); + var $now_str; + + function __construct() + { + parent::__construct(); + $this->load->database(); + $this->now_str = date('Y-m-d H:i:s'); + } + + public function init($vars) + { + $this->vars = $vars; + } + + // 車輛進出傳入車牌號碼 (2016/07/27) + public function opendoor_lprio($parms) + { + $parms['lpr'] = urldecode($parms['lpr']); + + $rows = array(); + // $parms['ts'] = date('Y-m-d H:i:s', $parms['ts']); + trigger_error(__FUNCTION__ . '|車牌傳入:' . print_r($parms, true)); + + if ($parms['etag'] != 'NONE') + { + if ($parms['lpr'] != 'NONE') + { + // do nothing + } + else // 車辨失敗但有eTag, 查詢是否有車號 + { + //$parms['lpr'] = $this->etag2lpr_2($parms['etag']); // 2017/01/10 預設都不用 ETAG 找車牌 + } + } + + $rows = $this->get_member($parms['lpr']); + + $this->save_db_io($parms, $rows, true); + return true; + } + + // 車輛進出傳入車牌號碼 + public function lprio($parms) + { + //$parms['lpr'] = urldecode($parms['lpr']); + + $rows = array(); + // $parms['ts'] = date('Y-m-d H:i:s', $parms['ts']); + trigger_error('車牌傳入:' . print_r($parms, true)); + + if ($parms['etag'] != 'NONE') + { + if ($parms['lpr'] != 'NONE') + { + // 有車牌有eTag, 檢查資料庫是否double驗證 + //get_headers("http://192.168.10.201/cars.html/check_lpr_etag/{$parms['lpr']}/{$parms['etag']}"); + get_headers("http://localhost/cars.html/check_lpr_etag/{$parms['lpr']}/{$parms['etag']}"); // update 2016/07/26 + } + else // 車辨失敗但有eTag, 查詢是否有車號 + { + // $parms['lpr'] = $this->etag2lpr_2($parms['etag']); // 2017/01/10 預設都不用 ETAG 找車牌 + } + } + + $rows = $this->get_member($parms['lpr']); + + $this->save_db_io($parms, $rows); + return true; + } + + + // 入出口異動cario + public function save_db_io($parms, $rows, $opendoor=false) + { + if (!empty($rows['lpr_correct'])) $parms['lpr'] = $rows['lpr_correct']; + + // [START] 擋重覆 20170912 前端不止一筆 opendoor 送來時, 只處理第一個 (限 2 sec 內) + if($opendoor) + { + $skip_or_not = false; + $new_cars_tmp = array + ( + 'timestamp' => time(), + 'sno_io' => $parms['sno'] . $parms['io'], + 'lpr' => $parms['lpr'] + ); + $cars_tmp_arr = array(); + $cars_tmp_log_arr = $this->vars['mcache']->get(CARS_TMP_LOG); + if(!empty($cars_tmp_log_arr)) + { + foreach($cars_tmp_log_arr as $tmp) + { + if(isset($tmp['timestamp']) && $tmp['timestamp'] > time() - 2) // 時限內才判斷 + { + array_push($cars_tmp_arr, $tmp); + } + } + } + + // 判斷是否繼續 + foreach($cars_tmp_arr as $tmp) + { + if( $new_cars_tmp['lpr'] == $tmp['lpr'] && + $new_cars_tmp['sno_io'] == $tmp['sno_io']) + { + $skip_or_not = true; + } + } + + // 更新 + array_push($cars_tmp_arr, $new_cars_tmp); + $this->vars['mcache']->set(CARS_TMP_LOG, $cars_tmp_arr); + trigger_error(__FUNCTION__ . '..new ' . CARS_TMP_LOG . " |s:{$skip_or_not}|" . print_r($cars_tmp_arr, true)); + + // 跳過 + if($skip_or_not) + { + trigger_error(__FUNCTION__ . '..skip..'); + return false; + } + } + // [END] 擋重覆 + + // 車辨失敗, 結束 + if ($parms['lpr'] == 'NONE') + { + if($opendoor) + { + $this->mq_send(MQ_TOPIC_ALTOB, MQ_ALTOB_MSG.",1,{$parms['ivsno']}".MQ_ALTOB_MSG_END_TAG); + // $this->mq_send(MQ_TOPIC_SUBTEXT, "{$parms['ivsno']},車辨失敗"); + + if(substr($parms['io'], -strlen('O')) === 'O') + { + // [acer] cmd:102 離場車辨失敗流程 START + $this->call_acer('102', array('cario_no' => 0, 'ivs_no' => $parms['ivsno'], 'msg_code' => 1)); + // [acer] cmd:102 離場車辨失敗流程 END + } + } + else + { + if(substr($parms['io'], -strlen('I')) === 'I') + { + // [acer] cmd:101 入場車辨失敗流程 START + $ticket_no = $this->gen_pass_code(); + + $data = array + ( + 'station_no' => $parms['sno'], + 'obj_type' => 1, + 'obj_id' => $parms['lpr'], + 'etag' => $parms['etag'] == 'NONE' ? '' : $parms['etag'], + 'in_out' => $parms['io'], + 'member_no' => 0, + 'finished' => 0, + 'in_time' => $this->now_str, + 'in_lane' => $parms['ivsno'], + 'in_pic_name' => empty($parms['pic_name']) ? '' : $parms['pic_name'], + 'out_before_time' => date("Y-m-d H:i:s"), + 'ticket_no' => $ticket_no + ); + $this->db->insert('cario', $data); + trigger_error("[車辨失敗] 新增入場資料:".print_r($parms, true)); + + $acer_parms = array + ( + 'cario_no' => $this->db->insert_id(), + 'in_time' => $this->now_str, + 'ticket_no' => $ticket_no, + 'lpr' => '', + 'ivs_no' => $parms['ivsno'] + ); + $this->call_acer('101', $acer_parms); + // [acer] cmd:101 入場車辨失敗流程 END + } + } + return false; + } + + $msg = $rows['member_no'] != 0 ? "{$parms['lpr']}." : $parms['lpr']; // 月租車號加.符號 + + // 月租鎖車, 結束 + //if (($parms['io'] == 'CO' || $parms['io'] == 'MO') && $rows['member_no'] != 0 && !empty($rows['locked']) && $rows['locked'] == 1) + if ((substr($parms['io'], -strlen('O')) === 'O') && $rows['member_no'] != 0 && !empty($rows['locked']) && $rows['locked'] == 1) + { + if($opendoor){ + //// $this->mq_send(MQ_TOPIC_SUBTEXT, "{$parms['ivsno']},{$msg}已鎖車!"); + $this->mq_send(MQ_TOPIC_ALTOB, MQ_ALTOB_MSG.",2,{$parms['ivsno']},{$parms['lpr']}".MQ_ALTOB_MSG_END_TAG); + // $this->mq_send(MQ_TOPIC_SUBTEXT, "{$parms['ivsno']},{$msg}禁止離場請後退"); + + // [acer] cmd:102 離場車辨已鎖車 START + $this->call_acer('102', array('cario_no' => 0, 'ivs_no' => $parms['ivsno'], 'msg_code' => 2)); + // [acer] cmd:102 離場車辨已鎖車 END + } + return false; + } + + // 取得會員資訊 + $parms['member_no'] = $rows['member_no']; + + switch($parms['io']) + { + case 'CI': + case 'MI': + + if($opendoor){ + // 開門 + /* + if ($rows['member_no'] != 0) + { + $this->member_opendoors($parms); + } + else + { + $this->temp_opendoors($parms); + } + */ + + // 取得出入口 888 資訊 + $pks_888_arr = $this->get_888_info($parms); + if ($pks_888_arr['availables'] == 0) + { + if ($rows['member_no'] == 0) + { + // 滿車訊號 (臨停) + $this->mq_send(MQ_TOPIC_ALTOB, MQ_ALTOB_MSG.",14,{$parms['ivsno']},{$parms['lpr']}".MQ_ALTOB_MSG_END_TAG); + // 開門訊號 (臨停) + $this->temp_opendoors($parms); + return false; + } + else + { + // 滿車訊號 (會員) + $this->mq_send(MQ_TOPIC_ALTOB, MQ_ALTOB_MSG.",15,{$parms['ivsno']},{$parms['lpr']}".MQ_ALTOB_MSG_END_TAG); + } + } + + // 空車位導引 + $pks_arr = $this->get_valid_seat(); + if ($pks_arr['result']['location_no'] != 0) + { + $pks_loc_name = $pks_arr['loc_name']; + $pks_loc_no = $pks_arr['result']['location_no']; + $pks_floors = $pks_arr['floors']; + } + else + { + $pks_loc_name = 0; + $pks_loc_no = 0; + $pks_floors = 0; + } + + // 訊息 + if ($rows['member_no'] == 0) + { + $ck = md5($parms['lpr']); + $jdata = file_get_contents("http://localhost/allpa_service.html/get_allpa_valid_user/{$parms['lpr']}/{$ck}"); + $results = json_decode($jdata, true); + if($results['result_code'] == 0) + { + // 歐pa, 開門 + $this->member_opendoors($parms); + + // 歐pa, 進場 + $this->mq_send(MQ_TOPIC_ALTOB, MQ_ALTOB_MSG.",3,{$parms['ivsno']},{$parms['lpr']},{$pks_floors},{$pks_loc_no}".MQ_ALTOB_MSG_END_TAG); + + // old msg + // $this->mq_send(MQ_TOPIC_SUBTEXT, "{$parms['ivsno']},{$msg},歐pa卡用戶您好:請停{$pks_loc_name}{$pks_loc_no}車位"); + } + else + { + // 臨停車, 開門 (同會員) + $this->temp_opendoors($parms); + + // 臨停車, 進場 + $this->mq_send(MQ_TOPIC_ALTOB, MQ_ALTOB_MSG.",11,{$parms['ivsno']},{$parms['lpr']},{$pks_floors},{$pks_loc_no}".MQ_ALTOB_MSG_END_TAG); + + // old msg + // $this->mq_send(MQ_TOPIC_SUBTEXT, "{$parms['ivsno']},{$msg}請停{$pks_loc_name}{$pks_loc_no}車位"); + } + } + else + { + // 會員, 開門 + $this->member_opendoors($parms); + + // 會員, 進場 + $this->mq_send(MQ_TOPIC_ALTOB, MQ_ALTOB_MSG.",4,{$parms['ivsno']},{$parms['lpr']},{$pks_floors},{$pks_loc_no}".MQ_ALTOB_MSG_END_TAG); + + // old msg + // $this->mq_send(MQ_TOPIC_SUBTEXT, "{$parms['ivsno']},{$msg},月租戶請進場:請停{$pks_loc_name}{$pks_loc_no}車位"); + } + + + }else{ + // 資料流 + + if ($parms['lpr'] != 'NONE') + { + $data = array + ( + 'err' => 1, + 'finished' => 1 + ); + // 原有歷史記錄, 設定錯誤碼為1(入場不應該有歷史記錄) + $this->db->update('cario', $data, array('obj_id' => $parms['lpr'], 'finished' => 0, 'err' => 0, 'obj_type' => 1)); + + $affect_rows = $this->db->affected_rows(); + + if ($affect_rows > 0) + { + trigger_error("err://入場郤已有歷史進場記錄[{$affect_rows}]筆,已設成錯誤並結清記錄".print_r($parms, true)); + } + } + + // [acer] cmd:101 入場車辨成功流程 START + $ticket_no = $this->gen_pass_code(); + + $data = array + ( + 'station_no' => $parms['sno'], + 'obj_type' => 1, + 'obj_id' => $parms['lpr'], + 'etag' => $parms['etag'] == 'NONE' ? '' : $parms['etag'], + 'in_out' => $parms['io'], + 'member_no' => $rows['member_no'], + 'finished' => 0, + 'in_time' => $this->now_str, + 'in_lane' => $parms['ivsno'], + 'in_pic_name' => empty($parms['pic_name']) ? '' : $parms['pic_name'], + 'out_before_time' => date("Y-m-d H:i:s"), + 'ticket_no' => $ticket_no + ); + $this->db->insert('cario', $data); + trigger_error("新增入場資料:".print_r($parms, true)); + + $acer_parms = array + ( + 'cario_no' => $this->db->insert_id(), + 'in_time' => $this->now_str, + 'ticket_no' => $ticket_no, + 'lpr' => $parms['lpr'], + 'ivs_no' => $parms['ivsno'] + ); + $this->call_acer('101', $acer_parms); + // [acer] cmd:101 入場車辨成功流程 END + + // 傳送進場記錄 + $sync_agent = new AltobSyncAgent(); + $sync_agent->init($parms['sno'], $this->now_str); + $sync_agent->cario_no = $this->db->insert_id(); // 進出編號 + $sync_agent->member_no = $rows['member_no']; // 會員編號 + $sync_result = $sync_agent->sync_st_in($parms); + trigger_error( "..sync_st_in.." . $sync_result); + + } + + break; + + // 出場 + case 'CO': + case 'MO': + + // 讀取最近一筆入場資料 + $rows_cario = $this->db + ->select('cario_no, payed, in_time, pay_time, out_before_time') + ->from('cario') + //->where(array('in_out' => 'CI', 'obj_id' => $parms['lpr'], 'finished' => 0, 'err' => 0)) + ->where(array('obj_id' => $parms['lpr'], 'err' => 0)) + ->order_by('cario_no', 'desc') + ->limit(1) + ->get() + ->row_array(); + + trigger_error("opendoor={$opendoor}| 出場讀到資料:{$rows['member_no']}|".time().'|'.print_r($rows_cario, true)); + + if (!empty($rows_cario['cario_no'])) // 在限時內可出場 + { + $co_time_minutes = floor((strtotime($this->now_str) - strtotime($rows_cario['in_time'])) / 60); // 停車時數 (分鐘) + + // 合規定者開門放行 + switch(true) + { + case $rows['member_no'] != 0: + // CO.A.1 會員車 + + // 判斷時段租是否超時 (超過 12 小時) + if($rows['park_time'] != 'RE' && $co_time_minutes > 720) + { + if($opendoor) + { + // 時段租超時字幕 + $this->mq_send(MQ_TOPIC_ALTOB, MQ_ALTOB_MSG.",16,{$parms['ivsno']},{$parms['lpr']}".MQ_ALTOB_MSG_END_TAG); + + // [acer] cmd:102 離場車辨成功流程 START + $this->call_acer('102', array('cario_no' => $rows_cario['cario_no'], 'ivs_no' => $parms['ivsno'], 'msg_code' => 16)); + // [acer] cmd:102 離場車辨成功流程 END + } + else + { + $data = array + ( + 'out_time' => $this->now_str, + 'out_lane' => $parms['ivsno'], + 'minutes' => $co_time_minutes, + 'out_pic_name' => $parms['pic_name'] + ); + $this->db->update('cario', $data, array('cario_no' => $rows_cario['cario_no'])); // 記錄出場 + trigger_error("{$parms['lpr']}|時段租超時" . print_r($rows_cario, true)); + + // 傳送離場記錄 + $sync_agent = new AltobSyncAgent(); + $sync_agent->init($parms['sno'], $this->now_str); + $sync_agent->cario_no = $rows_cario['cario_no']; // 進出編號 + $sync_agent->member_no = $rows['member_no']; // 會員編號 + $sync_agent->in_time = $rows_cario['in_time']; // 入場時間 + $sync_result = $sync_agent->sync_st_out($parms); + trigger_error( "..sync_st_out.." . $sync_result); + } + return false; + } + + if($opendoor) + { + // 會員開門 + $this->member_opendoors($parms); + // 會員字幕 + $this->mq_send(MQ_TOPIC_ALTOB, MQ_ALTOB_MSG.",5,{$parms['ivsno']},{$parms['lpr']}".MQ_ALTOB_MSG_END_TAG); + // $this->mq_send(MQ_TOPIC_SUBTEXT, "{$parms['ivsno']},{$msg}謝謝光臨"); + + // [acer] cmd:102 離場車辨成功流程 START + $this->call_acer('102', array('cario_no' => $rows_cario['cario_no'], 'ivs_no' => $parms['ivsno'], 'msg_code' => 5)); + // [acer] cmd:102 離場車辨成功流程 END + } + else + { + $data = array + ( + 'in_out' => $parms['io'], + 'finished' => 1, + 'out_time' => $this->now_str, + 'out_lane' => $parms['ivsno'], + 'minutes' => $co_time_minutes, + 'out_pic_name' => $parms['pic_name'] + ); + $this->db->update('cario', $data, array('cario_no' => $rows_cario['cario_no'])); + trigger_error('會員車離場:' . print_r($rows, true)); + + // 傳送離場記錄 + $sync_agent = new AltobSyncAgent(); + $sync_agent->init($parms['sno'], $this->now_str); + $sync_agent->cario_no = $rows_cario['cario_no']; // 進出編號 + $sync_agent->member_no = $rows['member_no']; // 會員編號 + $sync_agent->in_time = $rows_cario['in_time']; // 入場時間 + $sync_agent->finished = 1; // 已離場 + $sync_result = $sync_agent->sync_st_out($parms); + trigger_error( "..sync_st_out.." . $sync_result); + } + + break; + + case strtotime($rows_cario['out_before_time']) >= time(): + + if ($rows_cario['payed']) + { + // CO.B.1 臨停車已付款 + if($opendoor) + { + // 臨停開門 + $this->temp_opendoors($parms); + // 臨停字幕 + $this->mq_send(MQ_TOPIC_ALTOB, MQ_ALTOB_MSG.",6,{$parms['ivsno']},{$parms['lpr']}".MQ_ALTOB_MSG_END_TAG); + //// $this->mq_send(MQ_TOPIC_SUBTEXT, "{$parms['ivsno']},{$msg}付款確認請 離 場謝謝光臨"); + // $this->mq_send(MQ_TOPIC_SUBTEXT, "{$parms['ivsno']},{$msg}謝謝光臨"); + + // [acer] cmd:102 離場車辨成功流程 START + $this->call_acer('102', array('cario_no' => $rows_cario['cario_no'], 'ivs_no' => $parms['ivsno'], 'msg_code' => 6)); + // [acer] cmd:102 離場車辨成功流程 END + } + else + { + $data = array + ( + 'in_out' => $parms['io'], + 'finished' => 1, + 'out_time' => $this->now_str, + 'out_lane' => $parms['ivsno'], + 'minutes' => $co_time_minutes, + 'out_pic_name' => $parms['pic_name'] + ); + $this->db->update('cario', $data, array('cario_no' => $rows_cario['cario_no'])); + trigger_error('臨停車已付款:' . print_r($rows, true)); + + // 傳送離場記錄 + $sync_agent = new AltobSyncAgent(); + $sync_agent->init($parms['sno'], $this->now_str); + $sync_agent->cario_no = $rows_cario['cario_no']; // 進出編號 + $sync_agent->in_time = $rows_cario['in_time']; // 入場時間 + $sync_agent->finished = 1; // 已離場 + $sync_result = $sync_agent->sync_st_out($parms); + trigger_error( "..sync_st_out.." . $sync_result); + } + } + else + { + // CO.B.2 臨停車未付款 + if($opendoor) + { + // 臨停字幕 + $this->mq_send(MQ_TOPIC_ALTOB, MQ_ALTOB_MSG.",8,{$parms['ivsno']},{$parms['lpr']}".MQ_ALTOB_MSG_END_TAG); + // $this->mq_send(MQ_TOPIC_SUBTEXT, "{$parms['ivsno']},{$msg}臨時車請投票卡或刷卡出場"); + + // [acer] cmd:102 離場車辨成功流程 START + $this->call_acer('102', array('cario_no' => $rows_cario['cario_no'], 'ivs_no' => $parms['ivsno'], 'msg_code' => 8)); + // [acer] cmd:102 離場車辨成功流程 END + } + else + { + // TODO: 歐pa卡離場記錄和臨停未付款一樣, 待更正 + $data = array + ( + 'out_time' => $this->now_str, + 'out_lane' => $parms['ivsno'], + 'minutes' => $co_time_minutes, + 'out_pic_name' => $parms['pic_name'] + ); + $this->db->update('cario', $data, array('cario_no' => $rows_cario['cario_no'])); // 記錄出場 + trigger_error('臨停未付款:' . print_r($rows, true)); + + // 傳送離場記錄 + $sync_agent = new AltobSyncAgent(); + $sync_agent->init($parms['sno'], $this->now_str); + $sync_agent->cario_no = $rows_cario['cario_no']; // 進出編號 + $sync_agent->in_time = $rows_cario['in_time']; // 入場時間 + $sync_result = $sync_agent->sync_st_out($parms); + trigger_error( "..sync_st_out.." . $sync_result); + } + } + break; + + default: + // CO.C.1 其它付款方式 + if($opendoor) + { + $in_time = strtotime($rows_cario['out_before_time']); + $ck = md5($in_time. $parms['lpr'] . $parms['sno']); + $jdata = file_get_contents("http://localhost/allpa_service.html/allpa_go/{$in_time}/{$parms['lpr']}/{$parms['sno']}/{$ck}"); + trigger_error("allpa回傳:{$jdata}|{$in_time}/{$parms['lpr']}/{$parms['sno']}/{$ck}"); + $results = json_decode($jdata, true); + trigger_error("+++".print_r($results, true)); + if ($results['result_code'] == 0) // 歐pa卡, 點數足夠扣 + { + // 臨停開門 + $this->temp_opendoors($parms); + // 歐pa卡, 字幕 + $this->mq_send(MQ_TOPIC_ALTOB, MQ_ALTOB_MSG.",7,{$parms['ivsno']},{$parms['lpr']},{$results['amt']}".MQ_ALTOB_MSG_END_TAG); + // // $this->mq_send(MQ_TOPIC_SUBTEXT, "{$parms['ivsno']},{$msg}扣{$results['amt']}點請離場"); + // $this->mq_send(MQ_TOPIC_SUBTEXT, "{$parms['ivsno']},{$msg}請離場歐pa卡扣:{$results['amt']}點謝謝光臨"); + // updated 2016/09/01 + $data = array( + 'out_before_time' => date('Y-m-d H:i:s', strtotime(" + 15 minutes")), + 'pay_time' => $this->now_str, + 'pay_type' => 9, // 歐pa卡 + 'payed' => 1 + ); + $this->db->update('cario', $data, array('cario_no' => $rows_cario['cario_no'])); // 記錄出場 + + // [acer] cmd:102 離場車辨成功流程 START + $this->call_acer('102', array('cario_no' => $rows_cario['cario_no'], 'ivs_no' => $parms['ivsno'], 'msg_code' => 7)); + // [acer] cmd:102 離場車辨成功流程 END + } + else if ($results['result_code'] == 12) // 歐pa卡, 餘額不足 + { + // 臨停字幕 + $this->mq_send(MQ_TOPIC_ALTOB, MQ_ALTOB_MSG.",12,{$parms['ivsno']},{$parms['lpr']}".MQ_ALTOB_MSG_END_TAG); + + // [acer] cmd:102 離場車辨成功流程 START + $this->call_acer('102', array('cario_no' => $rows_cario['cario_no'], 'ivs_no' => $parms['ivsno'], 'msg_code' => 12)); + // [acer] cmd:102 離場車辨成功流程 END + } + else if ($results['result_code'] == 11) // 歐pa卡, 查無會員 + { + // 臨停字幕 + $this->mq_send(MQ_TOPIC_ALTOB, MQ_ALTOB_MSG.",9,{$parms['ivsno']},{$parms['lpr']}".MQ_ALTOB_MSG_END_TAG); + //// $this->mq_send(MQ_TOPIC_SUBTEXT, "{$parms['ivsno']},{$msg}其它付款方式"); + // $this->mq_send(MQ_TOPIC_SUBTEXT, "{$parms['ivsno']},{$msg}臨時車請投票卡或刷卡出場"); + + // [acer] cmd:102 離場車辨成功流程 START + $this->call_acer('102', array('cario_no' => $rows_cario['cario_no'], 'ivs_no' => $parms['ivsno'], 'msg_code' => 9)); + // [acer] cmd:102 離場車辨成功流程 END + } + else + { + // 臨停字幕 + $this->mq_send(MQ_TOPIC_ALTOB, MQ_ALTOB_MSG.",9,{$parms['ivsno']},{$parms['lpr']}".MQ_ALTOB_MSG_END_TAG); + + // [acer] cmd:102 離場車辨成功流程 START + $this->call_acer('102', array('cario_no' => $rows_cario['cario_no'], 'ivs_no' => $parms['ivsno'], 'msg_code' => 9)); + // [acer] cmd:102 離場車辨成功流程 END + } + } + else + { + $data = array + ( + 'out_time' => $this->now_str, + 'out_lane' => $parms['ivsno'], + 'minutes' => $co_time_minutes, + 'out_pic_name' => $parms['pic_name'] + ); + $this->db->update('cario', $data, array('cario_no' => $rows_cario['cario_no'])); // 記錄出場 + trigger_error("{$parms['lpr']}|其它付款方式:" . print_r($rows_cario, true)); + + // 傳送離場記錄 + $sync_agent = new AltobSyncAgent(); + $sync_agent->init($parms['sno'], $this->now_str); + $sync_agent->cario_no = $rows_cario['cario_no']; // 進出編號 + $sync_agent->in_time = $rows_cario['in_time']; // 入場時間 + $sync_result = $sync_agent->sync_st_out($parms); + trigger_error( "..sync_st_out.." . $sync_result); + } + break; + } + + } + else if ($rows['member_no'] != 0) + { + // CO.Z.1 月租車無入場資料 + if($opendoor) + { + // 會員開門 + $this->member_opendoors($parms); + // 會員字幕 + $this->mq_send(MQ_TOPIC_ALTOB, MQ_ALTOB_MSG.",10,{$parms['ivsno']},{$parms['lpr']}".MQ_ALTOB_MSG_END_TAG); + // $this->mq_send(MQ_TOPIC_SUBTEXT, "{$parms['ivsno']},{$msg}月租戶請離場謝謝光臨"); + + // [acer] cmd:102 離場車辨成功流程 START + $this->call_acer('102', array('cario_no' => $rows_cario['cario_no'], 'ivs_no' => $parms['ivsno'], 'msg_code' => 10)); + // [acer] cmd:102 離場車辨成功流程 END + } + else + { + trigger_error('月租車無入場資料:' . print_r($rows, true)); + + // 傳送離場記錄 + $sync_agent = new AltobSyncAgent(); + $sync_agent->init($parms['sno'], $this->now_str); + $sync_agent->member_no = $rows['member_no']; // 會員編號 + $sync_agent->finished = 1; // 已離場 + $sync_result = $sync_agent->sync_st_out($parms); + trigger_error( "..sync_st_out.." . $sync_result); + } + } + else + { + // CO.Z.Z 無入場資料 + if($opendoor) + { + $this->mq_send(MQ_TOPIC_ALTOB, MQ_ALTOB_MSG.",13,{$parms['ivsno']},{$parms['lpr']}".MQ_ALTOB_MSG_END_TAG); + + // [acer] cmd:102 離場車辨成功流程 START + $this->call_acer('102', array('cario_no' => 0, 'ivs_no' => $parms['ivsno'], 'msg_code' => 13)); + // [acer] cmd:102 離場車辨成功流程 END + } + else + { + trigger_error('無入場資料:' . print_r($rows, true)); + + // 傳送離場記錄 + $sync_agent = new AltobSyncAgent(); + $sync_agent->init($parms['sno'], $this->now_str); + $sync_result = $sync_agent->sync_st_out($parms); + trigger_error( "..sync_st_out.." . $sync_result); + } + } + break; + } + + } + + + // 檢查是否合法會員或VIP資料 + public function get_member($lpr) + { + $where_arr = array + ( + 'c.lpr' => $lpr, + 'c.start_time <=' => $this->now_str, + 'c.end_time >=' => $this->now_str + ); + + $sql = "select + c.lpr_correct, + c.member_no, + m.member_name, + m.member_type, + m.locked, + m.remarks, + m.park_time, + m.suspended, + m.valid_time, + c.etag, + c.start_time, + c.end_time + from member_car c, members m + where c.member_no = m.member_no + and c.start_time <= '{$this->now_str}' + and c.end_time >= '{$this->now_str}' + and c.lpr = '{$lpr}' + limit 1"; + + $rows = $this->db->query($sql)->row_array(); + + // 新增 park_time_check 2016/11/11 + $park_time_check = 0; + if (!empty($rows['lpr_correct'])) + { + $park_time = $rows['park_time']; + $pt_arr = $this->vars['mcache']->get('pt'); + + if(empty($pt_arr) || empty($park_time)) + { + // ERROR: 無法驗証時段, 跳過時段限制判斷 + trigger_error("[ERROR] mcache.pt is empty !!"); + $park_time_check = 1; + } + else + { + $now_time = substr($this->now_str, 11); // 日期字串只取最後時間字串(13:25:32) + $week_no = date('w',strtotime($this->now_str)); // 取星期幾 + $park_time_array = explode(',', $park_time); // 用 , 格開 + foreach($park_time_array as $idx => $park_time_value) + { + foreach($pt_arr[$park_time_value]['timex'] as $idx => $pt_rows) + { + if ($week_no >= $pt_rows['w_start'] && + $week_no <= $pt_rows['w_end'] && + $now_time >= $pt_rows['time_start'] && + $now_time <= $pt_rows['time_end']) + { + $park_time_check = 2; + + trigger_error("時段代碼:{$park_time_value} 星期:{$week_no}"); + break; + } + } + } + } + } + + if (empty($rows['lpr_correct'])) // A. 非月租車 + { + $rows = array + ( + 'lpr_correct' => '', + 'member_no' => 0, + 'member_name' => '', + 'member_type' => 9, + 'etag' => '', + 'start_time' => '', + 'end_time' => '', + ); + } + else if(empty($park_time_check)) // B. 月租車, 時段無效 + { + trigger_error("無效的時段!! " . print_r($rows, true)); + + $rows = array + ( + 'lpr_correct' => '', + 'member_no' => 0, + 'member_name' => '', + 'member_type' => 9, + 'etag' => '', + 'start_time' => '', + 'end_time' => '', + ); + } + else if(!empty($rows['suspended'])) // C. 月租車, 停權中 + { + trigger_error("停權中!! " . print_r($rows, true)); + + $rows = array + ( + 'lpr_correct' => '', + 'member_no' => 0, + 'member_name' => '', + 'member_type' => 9, + 'etag' => '', + 'start_time' => '', + 'end_time' => '', + ); + } + else if(!empty($rows['valid_time']) && $rows['valid_time'] < $this->now_str) // D. 月租車, 已無效 (審核未通過) + { + trigger_error("已無效!! " . print_r($rows, true)); + + $rows = array + ( + 'lpr_correct' => '', + 'member_no' => 0, + 'member_name' => '', + 'member_type' => 9, + 'etag' => '', + 'start_time' => '', + 'end_time' => '', + ); + } + + trigger_error('讀取會員:' . print_r($rows, true) . ", park_time_check: {$park_time_check}"); + return $rows; + } + + // 開門 (月租) + public function member_opendoors($parms) + { + $this->mq_send(MQ_TOPIC_OPEN_DOOR, "DO{$parms['ivsno']},OPEN,{$parms['lpr']}"); + return true; + } + + // 開門 (臨停) + public function temp_opendoors($parms) + { + $this->mq_send(MQ_TOPIC_OPEN_DOOR, "DO{$parms['ivsno']},TICKET,{$parms['lpr']}"); + return true; + } + + + // 用eTag讀出車號 + public function etag2lpr_2($etag) + { + // 用讀取eTag記錄(有double驗證過) + $rows = $this->db->select('lpr') + ->from('etag_lpr') + ->where(array('etag' => $etag, 'confirms >' => 0)) + ->limit(1) + ->get() + ->row_array(); + + // 讀出eTag資料 + if (!empty($rows['lpr'])) + { + trigger_error("+++車牌NONE,以eTag讀入車牌:{$etag}|{$rows['lpr']}"); + return $rows['lpr']; + } + + return 'NONE'; + } + + + // 有車牌與eTag, 檢查資料庫 (2017/03/22 new) + public function check_lpr_etag($lpr, $etag) + { + $ETAG_LOG_TITLE = 'etag://'; + $ETAG_WARMIN_TITLE = 'etag-warning://'; + trigger_error($ETAG_LOG_TITLE. "輸入: {$lpr},{$etag}"); + + // 手動值上下限 + $max_admin_confirms_value = 99; + $min_admin_confirms_value = 50; + // 自動值上下限 + $max_system_confirms_value = 33; + $min_system_confirms_value = 0; + // 判斷對應加權 + $etag_confirms_bias_plus = 11; // etag 找 車牌, 對上一次可扺 11次 + $etag_confirms_bias_minus = -1; + $lpr_confirms_bias_plus = 3; // 車牌 找 etag, 對上一次可扺 3次 + $lpr_confirms_bias_minus = -1; + + // eTag 找 車牌 + $lpr_info_from_etag = $this->db->select('lpr, confirms') + ->from('etag_lpr') + ->where(array('etag' => $etag)) + ->limit(1) + ->get() + ->row_array(); + + if (!empty($lpr_info_from_etag['lpr'])) + { + // B. etag 有找到 車牌 + + if ($lpr_info_from_etag['lpr'] == $lpr) + { + // B.1. etag 有找到 車牌, 且 車牌 相符, confirms 上升 + $confirms_bias = $etag_confirms_bias_plus; + } + else + { + // B.2. etag 有找到 車牌, 但 車牌 不符, confirms 下降 + $confirms_bias = $etag_confirms_bias_minus; + trigger_error($ETAG_WARMIN_TITLE . "etag 找 lpr | lpr error : {$lpr},{$etag} | query:" . print_r($lpr_info_from_etag, true)); + } + + $next_confirms_value = $lpr_info_from_etag['confirms'] + $confirms_bias; + trigger_error($ETAG_LOG_TITLE . "etag 找 lpr | {$lpr},{$etag}, next_confirms: {$next_confirms_value}, bias:{$confirms_bias}"); + + // 更新 confirms 資訊 + if($next_confirms_value > $max_admin_confirms_value) + { + // B.3.0 confirms 超過 max_admin_confirms_value, skip + //trigger_error($ETAG_LOG_TITLE . "etag 找 lpr | {$lpr},{$etag} next_confirms_value > max_admin_confirms_value : {$max_admin_confirms_value}"); + } + else if ($next_confirms_value >= $min_admin_confirms_value) + { + // B.3.1 人工確認過的記錄, 誤判多次後會停留在 min_admin_confirms_value, 或加到 max_admin_confirms_value + $this->db->where('etag', $etag)->update('etag_lpr', array('confirms' => $next_confirms_value)); + } + else if ($next_confirms_value > $max_system_confirms_value) + { + // B.3.2 confirms 超過 max_system_confirms_value, skip + //trigger_error($ETAG_LOG_TITLE . "etag 找 lpr | {$lpr},{$etag} next_confirms_value > max_system_confirms_value : {$max_system_confirms_value}"); + } + else if ($next_confirms_value <= $max_system_confirms_value && $next_confirms_value >= $min_system_confirms_value) + { + // B.3.3 confirms 不到 max_system_confirms_value 為系統生成記錄, 誤判多次後 confirms 會扣到 min_system_confirms_value + $this->db->where('etag', $etag)->update('etag_lpr', array('confirms' => $next_confirms_value)); + } + else + { + // B.3.4 若低於 min_system_confirms_value,刪除 + $this->db->delete('etag_lpr', array('etag' => $etag)); + trigger_error($ETAG_LOG_TITLE . "etag 找 lpr | etag confirms fail and removed : {$lpr_info_from_etag['lpr']}, {$etag}"); + trigger_error($ETAG_WARMIN_TITLE . "etag 找 lpr | etag confirms fail and removed : {$lpr_info_from_etag['lpr']}, {$etag}"); + } + } + else + { + // 車牌 找 etag + $etag_info_form_lpr = $this->db->select('etag, confirms, member_no') + ->from('etag_lpr') + ->where(array('lpr' => $lpr)) + ->limit(1) + ->get() + ->row_array(); + + if (!empty($etag_info_form_lpr['etag'])) + { + // A. 車牌 有找到 etag + + if ($etag_info_form_lpr['etag'] == $etag) + { + // A.1. 車牌 有找到 etag, 且 etag 相符, confirms 上升 + $confirms_bias = $lpr_confirms_bias_plus; + + // 若尚未登記為會員 + if(empty($etag_info_form_lpr['member_no'])) + { + // 檢查是否會員 + $member_info_from_lpr = $this->db->select('member_no, member_name') + ->from('members') + ->where(array('lpr' => $lpr)) + ->limit(1) + ->get() + ->row_array(); + + // 確認為會員, 建立 eTag 資訊 + if (!empty($member_info_from_lpr['member_no'])) + { + $data['member_no'] = $member_info_from_lpr['member_no']; + $data['member_name'] = $member_info_from_lpr['member_name']; + $this->db->where('member_no', $member_info_from_lpr['member_no'])->update('member_car', array('etag' => $etag)); + $this->db->where('member_no', $member_info_from_lpr['member_no'])->update('members', array('etag' => $etag)); + + // 更新 etag_lpr + $this->db->where('etag', $etag)->update('etag_lpr', $data); + } + } + } + else + { + // A.2. 車牌 有找到 etag, 但 etag 不符, confirms 下降 + $confirms_bias = $lpr_confirms_bias_minus; + trigger_error($ETAG_WARMIN_TITLE . "lpr 找 etag | etag error : {$lpr},{$etag} | query:" . print_r($etag_info_form_lpr, true)); + } + + $next_confirms_value = $lpr_info_from_etag['confirms'] + $confirms_bias; + trigger_error($ETAG_LOG_TITLE . "lpr 找 etag | {$lpr},{$etag}, next_confirms: {$next_confirms_value}, bias:{$confirms_bias}"); + + // 更新 confirms 資訊 + if($next_confirms_value > $max_admin_confirms_value) + { + // A.3.0 confirms 超過 max_admin_confirms_value, skip + //trigger_error($ETAG_LOG_TITLE . "lpr 找 etag | {$lpr},{$etag} next_confirms_value > max_admin_confirms_value : {$max_admin_confirms_value}"); + } + else if ($next_confirms_value >= $min_admin_confirms_value) + { + // A.3.1 人工確認過的記錄, 誤判多次後會停留在 min_admin_confirms_value, 或加到 max_admin_confirms_value + $this->db->where('lpr', $lpr)->update('etag_lpr', array('confirms' => $next_confirms_value)); + } + else if ($next_confirms_value > $max_system_confirms_value) + { + // A.3.2 confirms 超過 max_system_confirms_value, skip + //trigger_error($ETAG_LOG_TITLE . "lpr 找 etag | {$lpr},{$etag} next_confirms_value > max_system_confirms_value : {$max_system_confirms_value}"); + } + else if ($next_confirms_value <= $max_system_confirms_value && $next_confirms_value >= $min_system_confirms_value) + { + // A.3.3 confirms 不到 max_system_confirms_value 為系統生成記錄, 誤判多次後 confirms 會扣到 min_system_confirms_value + $this->db->where('lpr', $lpr)->update('etag_lpr', array('confirms' => $next_confirms_value)); + } + else + { + // A.3.4 若低於 min_system_confirms_value,刪除 + $this->db->delete('etag_lpr', array('lpr' => $lpr)); + trigger_error($ETAG_LOG_TITLE . "lpr 找 etag | lpr confirms fail and removed : {$lpr}, {$etag_info_form_lpr['etag']}"); + trigger_error($ETAG_WARMIN_TITLE . "lpr 找 etag | lpr confirms fail and removed : {$lpr}, {$etag_info_form_lpr['etag']}"); + } + } + else + { + // C. 車牌 與 etag 都找不到記錄 + $data = array + ( + 'lpr' => $lpr, + 'lpr_correct' => $lpr, + 'etag' => $etag + ); + + // 檢查是否會員 + $member_info_from_lpr = $this->db->select('member_no, member_name') + ->from('members') + ->where(array('lpr' => $lpr)) + ->limit(1) + ->get() + ->row_array(); + + // 會員者, 將eTag update回去 + if (!empty($member_info_from_lpr['member_no'])) + { + $data['member_no'] = $member_info_from_lpr['member_no']; + $data['member_name'] = $member_info_from_lpr['member_name']; + + $this->db->where('member_no', $member_info_from_lpr['member_no'])->update('member_car', array('etag' => $etag)); + $this->db->where('member_no', $member_info_from_lpr['member_no'])->update('members', array('etag' => $etag)); + } + + // 建立第一筆記錄 + $this->db->insert('etag_lpr', $data); + $etag_lpr_seqno = $this->db->insert_id(); + + trigger_error($ETAG_LOG_TITLE . "create | insert seqno = {$etag_lpr_seqno}". print_r($data, true)); + } + } + } + + /* + // 有車牌與eTag, 檢查資料庫 + public function check_lpr_etag($lpr, $etag) + { + // 用讀取eTag記錄(有double驗證過) + $rows = $this->db->select('etag, confirms') + ->from('etag_lpr') + ->where(array('lpr' => $lpr)) + ->limit(1) + ->get() + ->row_array(); + + // 讀出eTag資料 + if (!empty($rows['etag'])) + { + // 車牌與eTag皆相符, 檢查是否confirms欄位若為0, 設成1(double驗證) + if ($rows['etag'] == $etag) + { + if ($rows['confirms'] == 0) $this->db->where('lpr', $lpr)->update('etag_lpr', array('confirms' => 1)); + } + else // eTag不相符 + { + if ($rows['confirms'] == 1) + { + $this->db->where('lpr', $lpr)->update('etag_lpr', array('confirms' => 0)); + } + else // 原confirms為0者, 刪除之 + { + $this->db->delete('etag_lpr', array('lpr' => $lpr)); + } + } + } + else // 無資料, 新增一筆 + { + // 再檢查一次是否有eTag ? + $rows_etag = $this->db->select('lpr, confirms') + ->from('etag_lpr') + ->where(array('etag' => $etag)) + ->limit(1) + ->get() + ->row_array(); + if (empty($rows_etag['lpr'])) // 無資料 + { + $data = array + ( + 'lpr' => $lpr, + 'lpr_correct' => $lpr, + 'etag' => $etag + ); + + // 檢查是否會員 + $rows_members = $this->db->select('member_no, member_name') + ->from('members') + ->where(array('lpr' => $lpr)) + ->limit(1) + ->get() + ->row_array(); + + // 會員者, 將eTag update回去 + if (!empty($rows_members['member_no'])) + { + $data['member_no'] = $rows_members['member_no']; + $data['member_name'] = $rows_members['member_name']; + + $this->db->where('member_no', $rows_members['member_no'])->update('member_car', array('etag' => $etag)); + $this->db->where('member_no', $rows_members['member_no'])->update('members', array('etag' => $etag)); + } + + $this->db->insert('etag_lpr', $data); + } + else + { + if ($rows_etag['confirms'] == 1) + { + $this->db->where('etag', $etag)->update('etag_lpr', array('confirms' => 0)); + } + else // 原confirms為0者, 刪除之 + { + $this->db->delete('etag_lpr', array('etag' => $etag)); + } + } + } + } + */ + + + // 送出至message queue(目前用mqtt) + public function mq_send($topic, $msg) + { + $this->vars['mqtt']->publish($topic, $msg, 0); + trigger_error("mqtt:{$topic}|{$msg}"); + } + + + // 指派車位 + // http://203.75.167.89/parkingquery.html/get_valid_seat + // 註記現在時間, 並保留10分鐘 + public function get_valid_seat() + { + $data = array(); + //$data['result']['location_no'] = '0'; + //$data['result_code'] = 'FAIL'; + //return $data; + + // 撈 roger db + /* + $sql = " + SELECT ParkingNum AS pksno FROM table_carpark + WHERE LPR = '' AND DisableSeat = 0 AND + (SELECT COUNT(*) FROM table_carpark WHERE LPR = '' AND DisableSeat = 0) <= 10 + ORDER BY RAND() LIMIT 1 FOR UPDATE; + "; + $dsn_old_db = $this->load->database('old_db', true); + + // 2016/12/14 roger_db 掛了的可能 + if ($dsn_old_db->initialize()) + { + $retults = $dsn_old_db->query($sql)->result_array(); + } + + if(!empty($retults[0])) + { + $data['result']['location_no'] = substr($retults[0]['pksno'], 1); + $data['result_code'] = 'OK'; + $data['loc_name'] = 'B'.substr($retults[0]['pksno'], 0, 1); + $data['floors'] = 'B'.substr($retults[0]['pksno'], 0, 1); + } + else + { + $data['result']['location_no'] = '0'; + $data['result_code'] = 'FAIL'; + } + */ + + $this->db->trans_start(); + $sql = "select pksno from pks where status = 'VA' and prioritys != 0 and (book_time is null or book_time <= now()) order by prioritys asc limit 1 for update;"; + $rows = $this->db->query($sql)->row_array(); + if (!empty($rows['pksno'])) + { + $data['result']['location_no'] = substr($rows['pksno'], -3); + $data['result_code'] = 'OK'; + $sql = "update pks set book_time = addtime(now(), '00:10:00') where pksno = {$rows['pksno']};"; + $this->db->query($sql); + $sql = "select g.group_name, g.floors from pks_groups g, pks_group_member m where m.pksno = {$rows['pksno']} and g.group_id = m.group_id and g.group_type = 1 limit 1"; + $rows = $this->db->query($sql)->row_array(); + $data['loc_name'] = $rows['group_name']; + $data['floors'] = $rows['floors']; + } + else + { + $data['result']['location_no'] = '0'; + $data['result_code'] = 'FAIL'; + } + $this->db->trans_complete(); + + return $data; + } + + // 取得出入口 888 資訊 + public function get_888_info($parms) + { + $data = array(); + $sql = "select availables as availables, tot as tot from pks_groups where group_id = 'C888' and station_no = {$parms['sno']}"; + $rows = $this->db->query($sql)->row_array(); + if (!empty($rows) && array_key_exists('availables', $rows)) + { + $data['result_code'] = 'OK'; + $data['availables'] = $rows['availables']; + $data['tot'] = $rows['tot']; + } + else + { + trigger_error(__FUNCTION__ . "..not found..".print_r($parms, true)); + $data['result_code'] = 'FAIL'; + $data['availables'] = 9999; // 如果拿不到就忽略這個流程 + $data['tot'] = 0; + } + return $data; + } + + + + // =============================================== + // acer cmd + // =============================================== + + // 產生通行碼 + function gen_pass_code() + { + return rand(100000,999999); + } + + // 呼叫acer + function call_acer($cmd, $parms) + { + //return false; // 尚未啟用 + + try{ + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, 'http://localhost/acer_service.html/cmd_'. $cmd); + curl_setopt($ch, CURLOPT_HEADER, FALSE); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); + curl_setopt($ch, CURLOPT_POST, TRUE); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT ,3); + curl_setopt($ch, CURLOPT_TIMEOUT, 3); //timeout in seconds + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($parms)); + $data = curl_exec($ch); + + if(curl_errno($ch)) + { + trigger_error(__FUNCTION__ . ', curl error: '. curl_error($ch)); + } + + curl_close($ch); + + trigger_error(__FUNCTION__ . '..'. $data); + + }catch (Exception $e){ + trigger_error(__FUNCTION__ . 'error:'.$e->getMessage()); + } + } + + +} diff --git a/models/Ctbcbank_model.php b/models/Ctbcbank_model.php new file mode 100644 index 0000000..9fa5b27 --- /dev/null +++ b/models/Ctbcbank_model.php @@ -0,0 +1,185 @@ +load->database(); + + /* + // ----- 中國信託 - 測試環境 ----- + define('CTBC_SSLAuthUI', "https://testepos.ctbcbank.com/auth/SSLAuthUI.jsp"); // URL授權介面 + define('CTBC_TYPE1_merID', "10063"); // 特店編號 (交易類型:一般授權) + define('CTBC_TYPE1_MerchantID', "8220276806667"); // 銀行所授與的特店代號,純數字,固定 13 碼。 + define('CTBC_TYPE1_TerminalID', "90008466"); // 銀行所授與的終端機代號,純數字,固定 8 碼。 + define('CTBC_TYPE1_Key', "ZQFsGRIzb7NqsPcWOLKOL3sj"); // 壓碼 (可由後台重新產生) + + define('CTBC_TYPE2_merID', "10064"); // 特店編號 (交易類型:分期付款) + define('CTBC_TYPE2_MerchantID', "8220878791047"); + define('CTBC_TYPE2_TerminalID', "91001008"); + + define('CTBC_TYPE3_merID', "10065"); // 特店編號 (交易類型:紅利折抵) + define('CTBC_TYPE3_MerchantID', "8220800211437"); + define('CTBC_TYPE3_TerminalID', "92000235"); + // ----- 中國信託 - 測試環境 (END) ----- + */ + + // ----- 中國信託 - 正式環境 ----- + define('CTBC_SSLAuthUI', "https://epos.chinatrust.com.tw/auth/SSLAuthUI.jsp"); // URL授權介面 + define('CTBC_TYPE1_merID', "10012"); // 特店編號 (交易類型:一般授權) + define('CTBC_TYPE1_MerchantID', "8220131400023"); // 銀行所授與的特店代號,純數字,固定 13 碼。 + define('CTBC_TYPE1_TerminalID', "99810789"); // 銀行所授與的終端機代號,純數字,固定 8 碼。 + define('CTBC_TYPE1_Key', "4qH0cNXhsmk6jKdTT4hjwYCX"); // 壓碼 (可由後台重新產生) + // ----- 中國信託 - 正式環境 (END) ----- + + } + + // 3.中國信託 + public function transfer_money_ctbc($data, $return_url) + { + try{ + $lidm = $data['order_no']; // 訂單編號 (<=19 碼) + $purchAmt = $data['amt']; + $txType = "0"; // 交易方式,長度為一碼數字。(一般交易:0, 分期交易:1, 紅利折抵一般交易:2, 紅利折抵分期交易:4) + $debug = "0"; // 預設(進行交易時)請填0,偵錯時請填1。 + + // 使用 CTBCAgent + include_once(ALTOB_CTBC_FILE); + $oCTBCAgent = new CTBCAgent(); + $oCTBCAgent->MerchantID = CTBC_TYPE1_MerchantID; + $oCTBCAgent->TerminalID = CTBC_TYPE1_TerminalID; + $oCTBCAgent->AuthResURL = $return_url;// 從收單行端取得授權碼後,要導回的網址,請勿填入特殊字元@、#、%、?、&等。 + $oCTBCAgent->SSLAuthUI = CTBC_SSLAuthUI; // URL授權介面 + $oCTBCAgent->Option = "1"; // 一般交易請填「1」。 , 分期交易請填一到兩碼的分期期數。, 紅利交易請填固定兩碼的產品代碼。, 紅利分期交易請填第一至二碼固定為產品代碼,第三碼或三至四碼為分期期數。 + $oCTBCAgent->Key = CTBC_TYPE1_Key; + $oCTBCAgent->MerchantName = iconv("UTF-8", "big5", "歐特儀停車場"); + $oCTBCAgent->OrderDetail = iconv("UTF-8", "big5", "歐Pa卡"); + $oCTBCAgent->AutoCap = "1"; // (0–不自動請款, 1–自動請款) + $oCTBCAgent->Customize = "1"; // 設定刷卡頁顯示特定語系或客制化頁面。(1–繁體中文, 2–簡體中文, 3–英文, 5–客制化頁面) + + $data = array( + 'merID' => CTBC_TYPE1_merID, + 'lidm' => $lidm, + 'purchAmt' => $purchAmt, + 'txType' => $txType, + 'debug' => $debug, + 'target' => "_self" + ); + + $oCTBCAgent->CheckOut($data); + + }catch (Exception $e){ + // 例外錯誤處理。 + throw $e; + } + } + + // 3.中國信託 - 回傳 + public function ctbcbank_return_handler($resenc, $merid) + { + try{ + // 使用 CTBCAgent + include_once(ALTOB_CTBC_FILE); + $oCTBCAgent = new CTBCAgent(); + $oCTBCAgent->Key = CTBC_TYPE1_Key; + $debug = "0"; + + // 解密 + $data = array( + 'encRes' => $resenc, + 'debug' => $debug + ); + $EncArray = $oCTBCAgent->Decrypt($data); + + /* + foreach($EncArray AS $name => $val){ + echo $name ."=>". urlencode(trim($val,"\x00..\x08")) ."\n"; + } + */ + + $errdesc = isset($EncArray['errdesc']) ? $EncArray['errdesc'] : ""; + $authresurl = isset($EncArray['authresurl']) ? $EncArray['authresurl'] : ""; + $xid = isset($EncArray['xid']) ? $EncArray['xid'] : ""; + $awardedpoint = isset($EncArray['awardedpoint']) ? $EncArray['awardedpoint'] : ""; + $status = isset($EncArray['status']) ? $EncArray['status'] : ""; + $errcode = isset($EncArray['errcode']) ? $EncArray['errcode'] : ""; + $authcode = isset($EncArray['authcode']) ? $EncArray['authcode'] : ""; + $authamt = isset($EncArray['authamt']) ? $EncArray['authamt'] : ""; + $lidm = isset($EncArray['lidm']) ? $EncArray['lidm'] : ""; + $offsetamt = isset($EncArray['offsetamt']) ? $EncArray['offsetamt'] : ""; + $originalamt = isset($EncArray['originalamt']) ? $EncArray['originalamt'] : ""; + $utilizedpoint = isset($EncArray['utilizedpoint']) ? $EncArray['utilizedpoint'] : ""; + $numberofpay = isset($EncArray['numberofpay']) ? $EncArray['numberofpay'] : ""; // option: 一般交易, 分期交易 + $prodcode = isset($EncArray['prodcode']) ? $EncArray['prodcode'] : ""; // option: 紅利交易 + $last4digitpan = isset($EncArray['last4digitpan']) ? $EncArray['last4digitpan'] : ""; + $pidresult= isset($EncArray['pidresult']) ? $EncArray['pidresult'] : ""; + $cardnumber = isset($EncArray['cardnumber']) ? $EncArray['cardnumber'] : ""; + $outmac = isset($EncArray['outmac']) ? $EncArray['outmac'] : ""; + + $data = array( + 'status' => $status, + 'errcode' => $errcode, + 'authcode' => $authcode, + 'authamt' => $authamt, + 'lidm' => $lidm, + 'offsetamt' => $offsetamt, + 'originalamt' => $originalamt, + 'utilizedpoint' => $utilizedpoint, + 'numberofpay' => $numberofpay, + 'prodcode' => $prodcode, + 'last4digitpan' => $last4digitpan, + 'debug' => $debug + ); + + // 取得 check mac + $MACString = $oCTBCAgent->CheckMac($data); + + //echo "checkm=$MACString\n"; + //echo "outmac=$outmac\n"; + + // 驗証內容正確性 + if(strcmp($MACString, $outmac) == 0){ + $data = array( + 'errdesc' => $errdesc, + 'authresurl' => $authresurl, + 'xid' => $xid, + 'awardedpoint' => $awardedpoint, + 'prodcode' => $prodcode, + 'merid' => $merid, + 'status' => $status, + 'errcode' => $errcode, + 'authcode' => $authcode, + 'authamt' => $authamt, + 'lidm' => $lidm, + 'offsetamt' => $offsetamt, + 'originalamt' => $originalamt, + 'utilizedpoint' => $utilizedpoint, + 'numberofpay' => $numberofpay, + 'last4digitpan' => $last4digitpan, + 'pidresult' => $pidresult, + 'cardnumber' => $cardnumber, + 'outmac' => $outmac + ); + }else{ + // CHECK MAC FAIL + $data = array( + 'errdesc' => "[CHECK MAC FAIL] MACString=$MACString", + 'merid' => $merid, + 'outmac' => $outmac + ); + } + + $this->db->insert('ctbc_feedback_log', $data); // 記錄 log + return $data; + + }catch (Exception $e){ + // 例外錯誤處理。 + trigger_error(__FUNCTION__.$e->getMessage()); + } + } + +} diff --git a/models/Excel_model.php b/models/Excel_model.php new file mode 100644 index 0000000..49d68b8 --- /dev/null +++ b/models/Excel_model.php @@ -0,0 +1,265 @@ +load->database(); + + $this->now_str = date('Y-m-d H:i:s'); + + ini_set('max_execution_time','300'); + ini_set('memory_limit','512M'); + } + + public function init($vars) + { + $this->vars = $vars; + } + + // 會員名單報表 + public function export_members() + { + trigger_error(EXPORT_LOG_TITLE. '..start..' . __FUNCTION__); + + // 讀入廠站資料 + $sql = " + select + members.member_name as member_name, + members.lpr as lpr, + members.contract_no as contract_no, + members.start_date as start_date, + members.end_date as end_date, + members.amt as amt, + members.update_time as update_time, + members.member_attr, + members.fee_period, + members.mobile_no, + members.deposit, + members.suspended, + members.locked, + members.valid_time + from members + ORDER BY update_time DESC + "; + + $results = $this->db->query($sql)->result_array(); + + if(empty($results)) + { + trigger_error(EXPORT_LOG_TITLE.'..no data..' . $this->db->last_query()); + return false; + } + + //$total_count = $this->db->query($sql)->num_rows(); + + // 產生 Excel + $this->load->library('excel'); + $objPHPExcel = new PHPExcel(); + $objPHPExcel->setActiveSheetIndex(0); + $col_A_mapping = array('col_name' => 'A', 'col_title' => '會員名稱', 'col_type' => PHPExcel_Cell_DataType::TYPE_STRING); + $col_B_mapping = array('col_name' => 'B', 'col_title' => '車牌號碼', 'col_type' => PHPExcel_Cell_DataType::TYPE_STRING); + $col_C_mapping = array('col_name' => 'C', 'col_title' => '合約代碼', 'col_type' => PHPExcel_Cell_DataType::TYPE_STRING); + $col_D_mapping = array('col_name' => 'D', 'col_title' => '開始時間', 'col_type' => PHPExcel_Cell_DataType::TYPE_STRING); + $col_E_mapping = array('col_name' => 'E', 'col_title' => '結束時間', 'col_type' => PHPExcel_Cell_DataType::TYPE_STRING); + $col_F_mapping = array('col_name' => 'F', 'col_title' => '租金', 'col_type' => PHPExcel_Cell_DataType::TYPE_STRING); + $col_G_mapping = array('col_name' => 'G', 'col_title' => '最後更新時間', 'col_type' => PHPExcel_Cell_DataType::TYPE_STRING); + $col_H_mapping = array('col_name' => 'H', 'col_title' => '身份', 'col_type' => PHPExcel_Cell_DataType::TYPE_STRING); + $col_I_mapping = array('col_name' => 'I', 'col_title' => '繳期', 'col_type' => PHPExcel_Cell_DataType::TYPE_STRING); + $col_J_mapping = array('col_name' => 'J', 'col_title' => '電話', 'col_type' => PHPExcel_Cell_DataType::TYPE_STRING); + $col_K_mapping = array('col_name' => 'K', 'col_title' => '押金', 'col_type' => PHPExcel_Cell_DataType::TYPE_STRING); + $col_L_mapping = array('col_name' => 'L', 'col_title' => '停權 (營管操作)', 'col_type' => PHPExcel_Cell_DataType::TYPE_STRING); + $col_M_mapping = array('col_name' => 'M', 'col_title' => '鎖車 (會員操作)', 'col_type' => PHPExcel_Cell_DataType::TYPE_STRING); + $col_N_mapping = array('col_name' => 'N', 'col_title' => '有效期限 (審核後更新)', 'col_type' => PHPExcel_Cell_DataType::TYPE_STRING); + + $raw_index = 1; + $objPHPExcel->getActiveSheet()->setTitle('下載'); + $objPHPExcel->getActiveSheet()->setCellValue($col_A_mapping['col_name'].$raw_index, $col_A_mapping['col_title']); + $objPHPExcel->getActiveSheet()->setCellValue($col_B_mapping['col_name'].$raw_index, $col_B_mapping['col_title']); + $objPHPExcel->getActiveSheet()->setCellValue($col_C_mapping['col_name'].$raw_index, $col_C_mapping['col_title']); + $objPHPExcel->getActiveSheet()->setCellValue($col_D_mapping['col_name'].$raw_index, $col_D_mapping['col_title']); + $objPHPExcel->getActiveSheet()->setCellValue($col_E_mapping['col_name'].$raw_index, $col_E_mapping['col_title']); + $objPHPExcel->getActiveSheet()->setCellValue($col_F_mapping['col_name'].$raw_index, $col_F_mapping['col_title']); + $objPHPExcel->getActiveSheet()->setCellValue($col_G_mapping['col_name'].$raw_index, $col_G_mapping['col_title']); + $objPHPExcel->getActiveSheet()->setCellValue($col_H_mapping['col_name'].$raw_index, $col_H_mapping['col_title']); + $objPHPExcel->getActiveSheet()->setCellValue($col_I_mapping['col_name'].$raw_index, $col_I_mapping['col_title']); + $objPHPExcel->getActiveSheet()->setCellValue($col_J_mapping['col_name'].$raw_index, $col_J_mapping['col_title']); + $objPHPExcel->getActiveSheet()->setCellValue($col_K_mapping['col_name'].$raw_index, $col_K_mapping['col_title']); + $objPHPExcel->getActiveSheet()->setCellValue($col_L_mapping['col_name'].$raw_index, $col_L_mapping['col_title']); + $objPHPExcel->getActiveSheet()->setCellValue($col_M_mapping['col_name'].$raw_index, $col_M_mapping['col_title']); + $objPHPExcel->getActiveSheet()->setCellValue($col_N_mapping['col_name'].$raw_index, $col_N_mapping['col_title']); + + $warning_style = array( + //'alignment' => array('horizontal' => PHPExcel_Style_Alignment::HORIZONTAL_CENTER), + 'font' => array( + 'bold' => true, + 'color' => array('rgb' => 'FF0000'), + 'size' => 16, + 'name' => 'Verdana' + ) + ); + + $hq_info = $this->vars['mcache']->get('info'); + + $count = 0; + foreach($results as $rows) + { + $raw_index += 1; + + $member_name = $rows['member_name']; + $lpr = $rows['lpr']; + $contract_no = $rows['contract_no'] ? $rows['contract_no'] : ''; + $start_date = $rows['start_date']; + $end_date = $rows['end_date']; + $amt = $rows['amt'] ? $rows['amt'] : '0'; + $update_time = $rows['update_time']; + $member_attr = ( empty($hq_info['member_attr']) || empty($rows['member_attr']) || empty($hq_info['member_attr'][$rows['member_attr']]) ) ? '無' : $hq_info['member_attr'][$rows['member_attr']]; + $fee_period = ( empty($hq_info['period_name']) || empty($rows['fee_period']) || empty($hq_info['period_name'][$rows['fee_period']]) ) ? '無' : $hq_info['period_name'][$rows['fee_period']]; + $mobile_no = $rows['mobile_no']; + $deposit = $rows['deposit']; + $suspended = (empty($rows['suspended'])) ? '無' : '已停權'; + $locked = (empty($rows['locked'])) ? '無' : '已鎖車'; + $valid_time = $rows['valid_time']; + + $count++; + + $objPHPExcel->getActiveSheet()->setCellValueExplicit($col_A_mapping['col_name'].$raw_index, $member_name, $col_A_mapping['col_type']); + $objPHPExcel->getActiveSheet()->setCellValueExplicit($col_B_mapping['col_name'].$raw_index, $lpr, $col_B_mapping['col_type']); + $objPHPExcel->getActiveSheet()->setCellValueExplicit($col_C_mapping['col_name'].$raw_index, $contract_no, $col_C_mapping['col_type']); + $objPHPExcel->getActiveSheet()->setCellValueExplicit($col_D_mapping['col_name'].$raw_index, $start_date, $col_D_mapping['col_type']); + $objPHPExcel->getActiveSheet()->setCellValueExplicit($col_E_mapping['col_name'].$raw_index, $end_date, $col_E_mapping['col_type']); + $objPHPExcel->getActiveSheet()->setCellValueExplicit($col_F_mapping['col_name'].$raw_index, $amt, $col_F_mapping['col_type']); + $objPHPExcel->getActiveSheet()->setCellValueExplicit($col_G_mapping['col_name'].$raw_index, $update_time, $col_G_mapping['col_type']); + $objPHPExcel->getActiveSheet()->setCellValueExplicit($col_H_mapping['col_name'].$raw_index, $member_attr, $col_H_mapping['col_type']); + $objPHPExcel->getActiveSheet()->setCellValueExplicit($col_I_mapping['col_name'].$raw_index, $fee_period, $col_I_mapping['col_type']); + $objPHPExcel->getActiveSheet()->setCellValueExplicit($col_J_mapping['col_name'].$raw_index, $mobile_no, $col_J_mapping['col_type']); + $objPHPExcel->getActiveSheet()->setCellValueExplicit($col_K_mapping['col_name'].$raw_index, $deposit, $col_K_mapping['col_type']); + $objPHPExcel->getActiveSheet()->setCellValueExplicit($col_L_mapping['col_name'].$raw_index, $suspended, $col_L_mapping['col_type']); + $objPHPExcel->getActiveSheet()->setCellValueExplicit($col_M_mapping['col_name'].$raw_index, $locked, $col_M_mapping['col_type']); + $objPHPExcel->getActiveSheet()->setCellValueExplicit($col_N_mapping['col_name'].$raw_index, $valid_time, $col_N_mapping['col_type']); + + // 設定 style + if($valid_time != $end_date) + { + $objPHPExcel->getActiveSheet()->getStyle($col_N_mapping['col_name'].$raw_index)->applyFromArray($warning_style); + } + } + + // 網站下載 + $filename_prefix = iconv('UTF-8', 'Big5', '會員資料 - '. STATION_NAME); + $filename_postfix = iconv('UTF-8', 'Big5', '(現況)'); + $objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007'); + header('Content-Type: application/vnd.ms-excel'); + header('Content-Disposition: attachment;filename="' . $filename_prefix. ' - ' . $filename_postfix . '.xlsx'); + header('Cache-Control: max-age=0'); + $objWriter->save('php://output'); + + trigger_error(EXPORT_LOG_TITLE . '..completed..' . __FUNCTION__ . '|count:' . $count); + + return true; + } + + + // 進出記錄報表 + public function export_cario_data($query_year, $query_month) + { + ini_set('max_execution_time','300'); + ini_set('memory_limit','512M'); + + trigger_error(EXPORT_LOG_TITLE. '..start..' . __FUNCTION__ . "|{$query_year},{$query_month}"); + + // 讀入廠站資料 + $sql = " + SELECT + cario.obj_id AS plate_no, + cario.in_time as in_time, + cario.out_time as out_time, + members.member_name as member_name, + CONCAT( FLOOR(HOUR(TIMEDIFF(cario.in_time, cario.out_time)) / 24), ' 日 ', + MOD(HOUR(TIMEDIFF(cario.in_time, cario.out_time)), 24), ' 時 ', + MINUTE(TIMEDIFF(cario.in_time, cario.out_time)), ' 分') as time_period + FROM cario + left join members on cario.member_no = members.member_no + WHERE cario.err = 0 and cario.obj_id != 'NONE' + and YEAR(cario.in_time) = {$query_year} and MONTH(cario.in_time) = {$query_month} + and cario.out_time is not null + ORDER BY cario.in_time ASC + "; + + $results = $this->db->query($sql)->result_array(); + + if(empty($results)) + { + trigger_error(EXPORT_LOG_TITLE.'..no data..' . $this->db->last_query()); + return false; + } + + //$total_count = $this->db->query($sql)->num_rows(); + + // 產生 Excel + $this->load->library('excel'); + $objPHPExcel = new PHPExcel(); + $objPHPExcel->setActiveSheetIndex(0); + $col_A_mapping = array('col_name' => 'A', 'col_title' => '車牌號碼', 'col_type' => PHPExcel_Cell_DataType::TYPE_STRING); + $col_B_mapping = array('col_name' => 'B', 'col_title' => '進場時間', 'col_type' => PHPExcel_Cell_DataType::TYPE_STRING); + $col_C_mapping = array('col_name' => 'C', 'col_title' => '離場日期', 'col_type' => PHPExcel_Cell_DataType::TYPE_STRING); + $col_D_mapping = array('col_name' => 'D', 'col_title' => '停車時數', 'col_type' => PHPExcel_Cell_DataType::TYPE_STRING); + $col_E_mapping = array('col_name' => 'E', 'col_title' => '場站名稱', 'col_type' => PHPExcel_Cell_DataType::TYPE_STRING); + $col_F_mapping = array('col_name' => 'F', 'col_title' => '會員名稱', 'col_type' => PHPExcel_Cell_DataType::TYPE_STRING); + $raw_index = 1; + $objPHPExcel->getActiveSheet()->setTitle('下載'); + $objPHPExcel->getActiveSheet()->setCellValue($col_A_mapping['col_name'].$raw_index, $col_A_mapping['col_title']); + $objPHPExcel->getActiveSheet()->setCellValue($col_B_mapping['col_name'].$raw_index, $col_B_mapping['col_title']); + $objPHPExcel->getActiveSheet()->setCellValue($col_C_mapping['col_name'].$raw_index, $col_C_mapping['col_title']); + $objPHPExcel->getActiveSheet()->setCellValue($col_D_mapping['col_name'].$raw_index, $col_D_mapping['col_title']); + $objPHPExcel->getActiveSheet()->setCellValue($col_E_mapping['col_name'].$raw_index, $col_E_mapping['col_title']); + $objPHPExcel->getActiveSheet()->setCellValue($col_F_mapping['col_name'].$raw_index, $col_F_mapping['col_title']); + + $count = 0; + foreach($results as $rows) + { + $raw_index += 1; + + $plate_no = $rows['plate_no']; + $in_time = $rows['in_time']; + $out_time = $rows['out_time']; + $time_period = $rows['time_period']; + $member_name = $rows['member_name'] ? $rows['member_name'] : '臨停'; + + $count++; + + $objPHPExcel->getActiveSheet()->setCellValueExplicit($col_A_mapping['col_name'].$raw_index, $plate_no, $col_A_mapping['col_type']); + $objPHPExcel->getActiveSheet()->setCellValueExplicit($col_B_mapping['col_name'].$raw_index, $in_time, $col_B_mapping['col_type']); + $objPHPExcel->getActiveSheet()->setCellValueExplicit($col_C_mapping['col_name'].$raw_index, $out_time, $col_C_mapping['col_type']); + $objPHPExcel->getActiveSheet()->setCellValueExplicit($col_D_mapping['col_name'].$raw_index, $time_period, $col_D_mapping['col_type']); + $objPHPExcel->getActiveSheet()->setCellValueExplicit($col_E_mapping['col_name'].$raw_index, STATION_NAME, $col_E_mapping['col_type']); + $objPHPExcel->getActiveSheet()->setCellValueExplicit($col_F_mapping['col_name'].$raw_index, $member_name, $col_F_mapping['col_type']); + } + + // 儲存檔案 + /* + $filename_prefix = iconv('UTF-8', 'Big5', '車牌號碼進出記錄 - '. STATION_NAME); + $filename_postfix = iconv('UTF-8', 'Big5', $query_year . '年' .$query_month.'月份'); + $objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007'); + $objWriter->save(EXPORT_BASE.$filename_prefix.' - '.$filename_postfix.'.xlsx'); + */ + + // 網站下載 + $filename_prefix = iconv('UTF-8', 'Big5', '車牌號碼進出記錄 - '. STATION_NAME); + $filename_postfix = iconv('UTF-8', 'Big5', $query_year . '年' .$query_month.'月份'); + $objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007'); + header('Content-Type: application/vnd.ms-excel'); + header('Content-Disposition: attachment;filename="' . $filename_prefix. ' - ' . $filename_postfix . '.xlsx'); + header('Cache-Control: max-age=0'); + $objWriter->save('php://output'); + + trigger_error(EXPORT_LOG_TITLE . '..completed..' . __FUNCTION__ . '|count:' . $count); + + return true; + } + + +} diff --git a/models/Landb_model.php b/models/Landb_model.php new file mode 100644 index 0000000..dea69c7 --- /dev/null +++ b/models/Landb_model.php @@ -0,0 +1,60 @@ +dsn_old_db = $this->load->database($dsn_old_db, true); + + $this->now_str = date('Y-m-d H:i:s'); + } + + // test + public function test($lpr) + { + $result = $lpr.' @ '. $this->now_str.' @ '; + + $sql = "SELECT ParkingNum as pksno, LPR as lpr + FROM table_carpark where lpr = 'xxx'"; + + $dsn_old_db = $this->load->database('old_db', true); + + /* + $config['hostname'] = '192.168.0.2'; + $config['port'] = "3306"; + $config['username'] = 'root'; + $config['password'] = 'HISHARP'; + $config['database'] = 'parking'; + $config['dbdriver'] = 'mysqli'; + $config['dbprefix'] = ''; + $config['pconnect'] = FALSE; + $config['db_debug'] = TRUE; + $config['cache_on'] = FALSE; + $config['cachedir'] = ''; + $config['char_set'] = 'utf8'; + $config['dbcollat'] = 'utf8_general_ci'; + $dsn_old_db = $this->load->database($config, true); + */ + + $retults = $dsn_old_db->query($sql)->result_array(); + + //$retults = $this->dsn_old_db->query($sql)->result_array(); + $seat_no = ''; + if(!empty($retults[0])) + { + $seat_no = '-'.substr($retults[0]['pksno'], 0, 1).'_'.substr($retults[0]['pksno'], 1); + } + + return + 'result >>>>>' . $result . '@' . '
'. + $sql . '
'. + json_encode($retults, true).'
'. + $seat_no; + } +} diff --git a/models/Parkingquery_model.php b/models/Parkingquery_model.php new file mode 100644 index 0000000..22a9bb8 --- /dev/null +++ b/models/Parkingquery_model.php @@ -0,0 +1,194 @@ +load->database(); + } + + public function init($vars) + { + // do nothing + } + + + + // 查詢各樓層剩餘車位 + // http://203.75.167.89/parkingquery.html/check_space/12345 + public function check_space($seqno) + { + $data = array(); + $results = $this->db->select('group_id, availables, tot') + ->from('pks_groups') + ->where('group_type', 1) + ->get() + ->result_array(); + + foreach($results as $idx => $rows) + { + $data['result']['floor'][$idx] = array + ( + 'floor_name' => $rows['group_id'], + 'valid_count' => $rows['availables'], + 'total_count' => $rows['tot'] + ); + } + return $data; + } + + // 停車位置查詢(板橋好停車) + // http://203.75.167.89/parkingquery.html/check_location/ABC1234 + public function check_location($lpr) + { + $lpr = strtoupper($lpr); // 一律轉大寫 + $data = array(); + $rows = $this->db->select('pksno, pic_name') + ->from('pks') + ->where('lpr', $lpr) + ->limit(1) + ->get() + ->row_array(); + if (!empty($rows['pksno'])) + { + $data['result']['num'] = $lpr; + $data['result']['location_no'] = "{$rows['pksno']}"; + $data['result_code'] = 'OK'; + $data['result']['pic_name'] = $rows['pic_name']; + } + else // 查無資料, 啟用模糊比對 + { + // 讀取最近一筆入場資料 + $rows_cario = $this->db + ->select('cario_no') + ->from('cario') + ->where(array('in_out' => 'CI', 'obj_id' => $lpr, 'finished' => 0, 'err' => 0, 'out_time IS NULL' => null)) + ->order_by('cario_no', 'desc') + ->limit(1) + ->get() + ->row_array(); + + // 有入場記錄, 直接猜在頂樓 + if (!empty($rows_cario['cario_no'])) + { + $data['result']['num'] = $lpr; + $data['result']['location_no'] = "7000"; + $data['result_code'] = 'OK'; + } + else + { + $data['result']['num'] = $lpr; + $data['result']['location_no'] = '0'; + $data['result_code'] = 'FAIL'; + } + } + return $data; + } + + // 空車位導引 + // http://203.75.167.89/parkingquery.html/get_valid_seat + // 註記現在時間, 並保留10分鐘 + public function get_valid_seat($pksno) + { + $data = array(); + $this->db->trans_start(); + if ($pksno > 0) // 限制從某一個車位開始指派車位 + { + $sql = "select pksno from pks where status = 'VA' and pksno >= {$pksno} and prioritys != 0 and (book_time is null or book_time <= now()) order by prioritys asc limit 1 for update;"; + } + else + { + $sql = "select pksno from pks where status = 'VA' and prioritys != 0 and (book_time is null or book_time <= now()) order by prioritys asc limit 1 for update;"; + } + + $rows = $this->db->query($sql)->row_array(); + if (!empty($rows['pksno'])) + { + $data['result']['location_no'] = "{$rows['pksno']}"; + $data['result_code'] = 'OK'; + $sql = "update pks set book_time = addtime(now(), '00:10:00') where pksno = {$rows['pksno']};"; + $this->db->query($sql); + } + else + { + $data['result']['location_no'] = '0'; + $data['result_code'] = 'FAIL'; + } + $this->db->trans_complete(); + return $data; + } + + + // 緊急求救 + // http://203.75.167.89/parkingquery.html/send_sos/B2/111/123 + public function send_sos($floor, $x, $y) + { + $data = array + ( + 'result' => array('send_from' => array('floor' => $floor, 'x' => $x, 'y' => $y)), + 'result_code' => 'OK' + ); + return $data; + } + + + // 防盜鎖車 + // http://203.75.167.89/parkingquery.html/security_action/ABC1234/pswd/2 + public function security_action($lpr, $pswd, $action) + { + $data = array(); + /* + $rows = $this->db->select('member_no, passwd, locked') + ->from('members') + ->where(array('lpr' => $lpr, 'passwd' => $pswd)) + ->limit(1) + ->get() + ->row_array(); + trigger_error('防盜鎖車:'.$this->db->last_query()); + + // 無資料或密碼錯誤 + if (empty($rows['member_no'])) + { + $data['result_code'] = 'FAIL'; + return($data); + } + */ + + $rows = $this->db->select('member_no, passwd, locked') + ->from('members') + ->where(array('lpr' => $lpr)) + ->limit(1) + ->get() + ->row_array(); + trigger_error('防盜鎖車:'.$this->db->last_query()); + + // 無資料或密碼錯誤 + if (empty($rows['member_no']) || md5($rows['passwd']) != $pswd) + { + $data['result_code'] = 'FAIL'; + return($data); + } + + $data['result_code'] = 'OK'; + // 查詢防盜狀態 + if ($action == 2) + { + $data['result']['action'] = 'CHECK_SECURITY'; + $data['result'][0]['num'] = $lpr; + $data['result'][0]['result'] = $rows['locked'] ? 'ON' : 'OFF'; + return $data; + } + + $this->db + ->where('member_no', $rows['member_no']) + ->update('members', array('locked' => $action)); + + $data['result']['action'] = $action == 1 ? 'ON' : 'OFF'; + return $data; + } +} diff --git a/models/Payment_ats_model.php b/models/Payment_ats_model.php new file mode 100644 index 0000000..2c4e548 --- /dev/null +++ b/models/Payment_ats_model.php @@ -0,0 +1,167 @@ +load->database(); + + define('PAYMENT_ATS_INVOICE_REMARK', '繳費機帳單'); + define('TABLE_NAME_TX_BILL_ATS', 'tx_bill_ats'); + } + + // 狀態: 結帳完成 + public function transfer_money_done($order_no) + { + $data = array(); + $data['status'] = 1; // 狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中, 101: 交易失敗, 111:產品已領取 + $this->db->update(TABLE_NAME_TX_BILL_ATS, $data, array('order_no' => $order_no)); + return true; + } + + // 狀態: 錢沒對上 + public function transfer_money_done_with_amt_error($order_no) + { + $data = array(); + $data['status'] = 2; // 狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中, 101: 交易失敗, 111:產品已領取 + $this->db->update(TABLE_NAME_TX_BILL_ATS, $data, array('order_no' => $order_no)); + return true; + } + + // 狀態: 發票沒建立 + public function transfer_money_set_invoice_error($order_no) + { + $data = array(); + $data['status'] = 3; // 狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中, 101: 交易失敗, 111:產品已領取 + $this->db->update(TABLE_NAME_TX_BILL_ATS, $data, array('order_no' => $order_no)); + return true; + } + + // 狀態: 訂單逾期作廢 + public function transfer_money_timeout($order_no) + { + $data = array(); + $data['status'] = 99; // 狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中, 101: 交易失敗, 111:產品已領取 + $this->db->update(TABLE_NAME_TX_BILL_ATS, $data, array('order_no' => $order_no)); + return true; + } + + // 狀態: 交易失敗 + public function transfer_money_done_with_tx_error($order_no) + { + $data = array(); + $data['status'] = 101; // 狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中, 101: 交易失敗, 111:產品已領取 + $this->db->update(TABLE_NAME_TX_BILL_ATS, $data, array('order_no' => $order_no)); + return true; + } + + // 狀態: 產品已領取 + public function transfer_money_done_and_finished($order_no) + { + $data = array(); + $data['status'] = 111; // 狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中, 101: 交易失敗, 111:產品已領取 + $this->db->update(TABLE_NAME_TX_BILL_ATS, $data, array('order_no' => $order_no)); + return true; + } + + // 建立帳單 (會員) + public function create_member_bill($lpr) + { + $result = $this->db->select("station_no, member_no, member_name, date_format(end_date, '%Y-%m-%d') as end_date, amt, remarks, + date_add(date_format(end_date, '%Y-%m-%d'), INTERVAL 1 day) as next_start, + date_add(date_format(end_date, '%Y-%m-%d'), INTERVAL 1 MONTH) as next_end", false) + ->from('members') + ->where('lpr', $lpr) + ->get() + ->row_array(); + + if(empty($result['member_no'])){ + // 查無會員資料 + $data = array(); + $data['member_no'] = 0; + return $data; + } + else + { + // 建立會員帳單 + $data = array(); + $data['invoice_remark'] = PAYMENT_ATS_INVOICE_REMARK; + $data['order_no'] = $result['member_no'].time(); // 交易序號 + $data['station_no'] = $result['station_no']; // 場站編號 + $data['member_no'] = $result['member_no']; // 會員編號 + $data['member_name'] = $result['member_name']; // 車主姓名 + //$data['amt'] = 10; // 租金金額 (test only) + $data['amt'] = $result['amt']; // 租金金額 + $data['remarks'] = $result['remarks']; // 備註 + $data['end_time'] = $result['end_date'] . ' 23:59:59'; // 到期日 + $data['next_start_time'] = $result['next_start']. ' 00:00:00'; // 次期起始日 + $data['next_end_time'] = $result['next_end'] . ' 23:59:59'; // 次期到期日 + $data['lpr'] = strtoupper($lpr); // 車牌號碼 + $data['balance_time_limit'] = date("Y-m-d H:i:s", strtotime('+ 15 minutes')); // 帳單有效期限 15 min + $this->db->insert(TABLE_NAME_TX_BILL_ATS, $data); + return $data; + } + trigger_error(APP_NAME.', '.__FUNCTION__.', order_no=>' . $order_no."|{$lpr}|無資料"); + } + + // 繳交帳單 (帳單) + public function pay_bill($order_no, $invoice_receiver, $company_no, $email, $mobile, $clientBackUrl, $orderResultUrl, $serviceUrl, $tx_type=0) + { + $data = $this->get_tx_bill($order_no); + + if (!empty($data)) + { + if($data['status'] != 0){ + trigger_error(APP_NAME.', '.__FUNCTION__.', order_no=>' . $order_no."|error status: ". $data['status']); + return null; + } + + if(strlen($invoice_receiver) >= 7){ // 手機載具編號 + $data['invoice_receiver'] = '/'.$invoice_receiver; + } + if(strlen($company_no) >= 8){ // 公司統編 + $data['company_no'] = $company_no; + $data['company_receiver'] = "公司名稱"; + $data['company_address'] = "公司地址"; + } + if(strlen($email) >= 5){ // a@b.c + $data['email'] = $email; + } + if(strlen($mobile) >= 10){ // 手機 + $data['mobile'] = $mobile; + } + + $txTime = time(); // 產生交易時間 + if(strtotime($data['balance_time_limit']) - $txTime > 0){ + $data['status'] = 100; //狀態: 0:剛建立, 1:結帳完成, 2:錢沒對上, 3:發票沒建立, 4:手動調整, 99:訂單逾期作廢, 100:交易進行中 + $data['tx_time'] = date('Y/m/d H:i:s', $txTime); + $data['tx_type'] = $tx_type; // 交易種類: 0:未定義, 1:現金, 40:博辰人工模組, 41:博辰自動繳費機, 50:歐付寶轉址刷卡, 51:歐付寶APP, 52:歐付寶轉址WebATM, 60:中國信託刷卡轉址 + $data['client_back_url'] = $clientBackUrl; + $data['order_result_url'] = $orderResultUrl; + $data['service_url'] = $serviceUrl; + $this->db->update(TABLE_NAME_TX_BILL_ATS, $data, array('order_no' => $order_no)); + return $data; + } + + $this->transfer_money_timeout($order_no); // 訂單逾期作廢 + return null; + } + + trigger_error(APP_NAME.', '.__FUNCTION__.', order_no=>' . $order_no."|無帳單資料"); + } + + // 取得帳單資料 + public function get_tx_bill($order_no) + { + $result = $this->db + ->from(TABLE_NAME_TX_BILL_ATS) + ->where(array('order_no' => $order_no)) + ->limit(1) + ->get() + ->row_array(); + return $result; + } +} diff --git a/models/Payment_model.php b/models/Payment_model.php new file mode 100644 index 0000000..191f140 --- /dev/null +++ b/models/Payment_model.php @@ -0,0 +1,185 @@ +load->database(); + + define("PAYMENT_INVOICE_REMARK", "臨停繳交帳單"); + } + + // 狀態: 結帳完成 + public function transfer_money_done($order_no) + { + $data = array(); + $data['status'] = TX_BILL_STATUS_PAID; + $this->db->update('tx_bill', $data, array('order_no' => $order_no)); + return true; + } + + // 狀態: 錢沒對上 + public function transfer_money_done_with_amt_error($order_no) + { + $data = array(); + $data['status'] = TX_BILL_STATUS_ERROR_AMT; + $this->db->update('tx_bill', $data, array('order_no' => $order_no)); + return true; + } + + // 狀態: 發票沒建立 + public function transfer_money_set_invoice_error($order_no) + { + $data = array(); + $data['status'] = TX_BILL_STATUS_ERROR_INVOICE; + $this->db->update('tx_bill', $data, array('order_no' => $order_no)); + return true; + } + + // 狀態: 訂單逾期作廢 + public function transfer_money_timeout($order_no) + { + $data = array(); + $data['status'] = TX_BILL_STATUS_TIME_OUT; + $this->db->update('tx_bill', $data, array('order_no' => $order_no)); + return true; + } + + // 狀態: 交易失敗 + public function transfer_money_done_with_tx_error($order_no) + { + $data = array(); + $data['status'] = TX_BILL_STATUS_FAIL; + $this->db->update('tx_bill', $data, array('order_no' => $order_no)); + return true; + } + + // 狀態: 產品已領取 + public function transfer_money_done_and_finished($order_no) + { + $data = array(); + $data['status'] = TX_BILL_STATUS_DONE; + $this->db->update('tx_bill', $data, array('order_no' => $order_no)); + return true; + } + + // 建立帳單 (臨停) + public function create_cario_bill($lpr) + { + $result = $this->db->select('station_no, cario_no, in_time, pay_time, out_time, out_before_time, member_no') + ->from('cario') + ->where(array('obj_type' => 1, 'obj_id' => $lpr, 'finished' => 0, 'err' => 0)) + ->order_by('cario_no', 'desc') + ->limit(1) + ->get() + ->row_array(); + + if(!empty($result['member_no'])){ + // 會員不算臨停帳單 + $data = array(); + $data['member_no'] = $result['member_no']; + return $data; + } + else if (!empty($result['out_before_time'])) + { + $inTime = $result['out_before_time']; // 進場時間認這個欄位 + $balanceTime = date('Y-m-d H:i:s'); + $stationNo = $result['station_no']; + + require_once(ALTOB_BILL_FILE); // 臨停費率 + + $oPayment = new AltobPayment(); + $oPayment->ServiceURL = ALTOB_PAYMENT_TXDATA_URL; + $bill = $oPayment->getBill($inTime, $balanceTime, $stationNo); + + // create tx_bill + $data = array(); + $data['invoice_remark'] = PAYMENT_INVOICE_REMARK; + $data['order_no'] = $result['cario_no'].time(); // 交易序號 + $data['cario_no'] = $result['cario_no']; // 進出場序號 (金流結束後開門使用) + //$data['amt'] = ($bill[BillResultKey::price] > 0) ? 10 : 0; // 測試用 + $data['amt'] = $bill[BillResultKey::price]; + $data['balance_time_limit'] = date("Y-m-d H:i:s", strtotime('+ 15 minutes')); // 15 min + $data['balance_time'] = $balanceTime; + $data['in_time'] = $inTime; + $data['lpr'] = strtoupper($lpr); + $data['station_no'] = $stationNo; + + if($bill[BillResultKey::price] > 0){ + // 有費用才建立到tx_bill + $this->db->insert('tx_bill', $data); + }else{ + trigger_error(APP_NAME.', '.__FUNCTION__.', order_no=>' . $order_no."|{$lpr}|尚未產生款項"); + } + + // return data + $data['bill_days'] = $bill[BillResultKey::days]; + $data['bill_hours'] = $bill[BillResultKey::hours]; + $data['bill_mins'] = $bill[BillResultKey::mins]; + $data['price_detail'] = $bill[BillResultKey::price_detail]; + return $data; + } + trigger_error(APP_NAME.', '.__FUNCTION__.', order_no=>' . $order_no."|{$lpr}|無車牌帳單資料"); + } + + // 繳交帳單 (帳單) + public function pay_bill($order_no, $invoice_receiver, $company_no, $email, $mobile, $clientBackUrl, $orderResultUrl, $serviceUrl, $tx_type=0) + { + $data = $this->get_tx_bill($order_no); + + if (!empty($data)) + { + if($data['status'] != 0){ + trigger_error(APP_NAME.', '.__FUNCTION__.', order_no=>' . $order_no."|error status: ". $data['status']); + return null; + } + + if(strlen($invoice_receiver) >= 7){ // 手機載具編號 + $data['invoice_receiver'] = '/'.$invoice_receiver; + } + if(strlen($company_no) >= 8){ // 公司統編 + $data['company_no'] = $company_no; + $data['company_receiver'] = "公司名稱"; + $data['company_address'] = "公司地址"; + } + if(strlen($email) >= 5){ // a@b.c + $data['email'] = $email; + } + if(strlen($mobile) >= 10){ // 手機 + $data['mobile'] = $mobile; + } + + $txTime = time(); // 產生交易時間 + if(strtotime($data['balance_time_limit']) - $txTime > 0){ + $data['status'] = TX_BILL_STATUS_PROCESSING; + $data['tx_time'] = date('Y/m/d H:i:s', $txTime); + $data['tx_type'] = $tx_type; // 交易種類: 0:未定義, 1:現金, 40:博辰人工模組, 41:博辰自動繳費機, 50:歐付寶轉址刷卡, 51:歐付寶APP, 52:歐付寶轉址WebATM, 60:中國信託刷卡轉址 + $data['client_back_url'] = $clientBackUrl; + $data['order_result_url'] = $orderResultUrl; + $data['service_url'] = $serviceUrl; + $this->db->update('tx_bill', $data, array('order_no' => $order_no)); + return $data; + } + + $this->transfer_money_timeout($order_no); // 訂單逾期作廢 + return null; + } + + trigger_error(APP_NAME.', '.__FUNCTION__.', order_no=>' . $order_no."|無帳單資料"); + } + + // 取得臨停帳單資料 + public function get_tx_bill($order_no) + { + $result = $this->db + ->from('tx_bill') + ->where(array('order_no' => $order_no)) + ->limit(1) + ->get() + ->row_array(); + return $result; + } +} diff --git a/models/Pks_model.php b/models/Pks_model.php new file mode 100644 index 0000000..585897e --- /dev/null +++ b/models/Pks_model.php @@ -0,0 +1,356 @@ +load->database(); + } + + public function init($vars) + { + $this->vars = $vars; + } + + + // 車輛進出傳入車牌號碼 + public function pksio($parms) + { + switch($parms['io']) + { + case 'KL': // 車輛入席車辨(lpr)及圖檔 + if ($parms['lpr'] == 'NONE') // 在席車辨失敗, 不處理 + { + trigger_error('在席車辨失敗' . print_r($parms, true)); + return false; + } + + // 讀取在席資料(pks) + $rows_pks = $this->db + ->select('cario_no, lpr, status, confirms') + ->from('pks') + ->where(array('pksno' => $parms['pksno'], 'station_no' => $this->vars['station_no'])) + ->limit(1) + ->get() + ->row_array(); + + trigger_error('KL read pks:'.print_r($rows_pks, true)); + + // 如果已經人工確認或之前已比對有入場資料者, 則重覆再送來的車辨不予理會 + if ($rows_pks['confirms'] == 1 || $rows_pks['lpr'] == $parms['lpr']) + { + trigger_error('KL ignored:'.$rows_pks['lpr']); + return false; + } + /* + if ($rows_pks['cario_no'] != 0 || $rows_pks['confirms'] == 1 || $rows_pks['lpr'] == $parms['lpr']) + { + trigger_error('人工已確認或車號相同不更新pks:'.$rows_pks['lpr']); + return false; + } + */ + + // 讀取進場時間, 如讀不到資料, 以目前時間取代(add by TZUSS 2016-02-23) + $rows_cario = $this->db + ->select('cario_no, in_time') + ->from('cario') + ->where(array('in_out' => 'CI', 'obj_id' => $parms['lpr'], 'finished' => 0, 'err' => 0, 'station_no' => $this->vars['station_no'])) + ->order_by('cario_no', 'desc') + ->limit(1) + ->get() + ->row_array(); + if (!empty($rows_cario['cario_no'])) // 有入場資料 + { + $cario_no = $rows_cario['cario_no']; // 入場序號 + $in_time = $rows_cario['in_time']; + // 在席與入場資料相符, 分別在cario與pks記錄之 + $data_cario = array + ( + 'pksno' => $parms['pksno'], + 'pks_time' => date('Y-m-d H:i:s') + ); + $this->db->update('cario', $data_cario, array('cario_no' => $cario_no, 'station_no' => $this->vars['station_no'])); + } + else // 查無入場資料, 即時通知 + { + $cario_no = 0; + $in_time = date('Y-m-d H:i:s'); + $jdata = json_encode(array + ( + 'pksno' => $parms['pksno'], + 'lpr' => $parms['lpr'], + 'in_time' => $in_time, + 'pic_name' => $parms['pic_name'] + ), JSON_UNESCAPED_UNICODE); + // $this->vars['mqtt']-lish('PKS_WITHOUT_IN', "{$jdata}", 0); // 待web完成 ??? + trigger_error('在席無進場資料:'. print_r($parms, true)); + } + + // 車入格後的車牌辨識(lpr), 傅送圖檔 + array_map('unlink', glob(PKS_PIC."pks-{$parms['pksno']}-*.jpg")); // 刪除舊照片 + $config['upload_path'] = PKS_PIC; + $config['allowed_types'] = 'gif|jpg|png'; + // ex. pks-2016-1625AB-1-2015080526.jpg -> pks-車位編號-車號-設備編號-時間.jpg + $config['file_name'] = "pks-{$parms['pksno']}-{$parms['lpr']}-{$parms['ivsno']}-{$this->vars['time_num']}.jpg"; + $this->load->library('upload', $config); + + $parms['pic_name'] = $config['file_name']; + if($this->upload->do_upload('cars')) + { + // 若無錯誤,則上傳檔案 + $file = $this->upload->data('cars'); + } + else + { + trigger_error('入席傳檔錯誤:'. print_r($parms, true)); + } + + $data = array + ( + 'cario_no' => $cario_no, + 'lpr' => $parms['lpr'], + 'status' => 'LR', // 車格佔用並有車號 + 'confirms' => 0, // 預設人工未確認 + 'pic_name' => $parms['pic_name'], + 'in_time' => $in_time + ); + // 車號及照片檔名填入資料庫內 + $this->db->update('pks', $data, array('pksno' => $parms['pksno'], 'station_no' => $this->vars['station_no'])); + break; + + case 'KI': // 車輛入席, 各區空車位與佔位各加減1 + $rows = $this->db->select('status') + ->from('pks') + ->where(array('pksno' => $parms['pksno'], 'station_no' => $this->vars['station_no'])) + ->get() + ->row_array(); + // if (!empty($rows['status']) && $rows['status'] == 'LR') break; // 仍有車在席, 不應再有KI, ignore + if (!empty($rows['status']) && $rows['status'] == 'LR') return true; // 仍有車在席, 不應再有KI, ignore + + $data = array + ( + 'cario_no' => 0, + 'lpr' => '', + 'status' => 'OC', // 車格佔用但尚無車號 + 'confirms' => 0, + 'pic_name' => '', + 'in_time' => null + ); + $this->db->update('pks', $data, array('pksno' => $parms['pksno'], 'station_no' => $this->vars['station_no'])); + break; + + case 'KO': // 車輛離席, 各區空車位與佔位各加減1 + $data = array + ( + 'cario_no' => 0, + 'lpr' => '', + 'status' => 'VA', // 車格佔用但尚無車號 + 'confirms' => 0, + 'pic_name' => '', + 'in_time' => null + ); + $this->db->update('pks', $data, array('pksno' => $parms['pksno'], 'station_no' => $this->vars['station_no'])); + break; + } + + /* + // 找出與與此車位相關的群組 + $sql = "select group_id, tot, renum + from pks_groups + where group_id in + (select group_id from pks_group_member where station_no = {$this->vars['station_no']} and pksno = {$parms['pksno']})"; + + $retults = $this->db->query($sql)->result_array(); + + foreach ($retults as $rows) + { + // 計算群組異動後的空車位數, 先讀出已停車位數 + $sql = "select count(*) as parked from pks where status != 'VA' and pksno in (select pksno from pks_group_member where group_id = '{$rows['group_id']}')"; + $row_group = $this->db->query($sql)->row_array(); + $group_va = $rows['tot'] + $rows['renum'] - $row_group['parked']; // 群組空車位數 + $this->db->update('pks_groups', array('parked' => $row_group['parked'], 'availables' => $group_va), array('group_id' => $rows['group_id'])); + + get_headers("http://192.168.51.15/set_num.php?group_id={$rows['group_id']}&num={$group_va}"); + // $this->vars['mqtt']->publish("VA-{$rows['group_id']}", "{$group_va}", 0); // 送出剩餘車位數給字幕機 + // 總車位數暫無需處理 + } + */ + // 找出與與此車位相關的群組 + $sql = "select group_id, tot, renum, availables + from pks_groups + where group_id in + (select group_id from pks_group_member where station_no = {$this->vars['station_no']} and pksno = {$parms['pksno']})"; + + $retults = $this->db->query($sql)->result_array(); + + foreach ($retults as $rows) + { + // 計算群組異動後的空車位數, 先讀出已停車位數 + $sql = "select count(*) as parked from pks where status != 'VA' and pksno in (select pksno from pks_group_member where group_id = '{$rows['group_id']}')"; + $row_group = $this->db->query($sql)->row_array(); + $group_va = $rows['tot'] + $rows['renum'] - $row_group['parked']; // 群組空車位數 + + // 有變動才處理更新 + if($rows['availables'] != $group_va) + { + // 防止負值 + if($group_va < 0){ + $group_va = 0; + } + + $group_va_pad = str_pad($group_va, 3, '0', STR_PAD_LEFT); // 補零 + $this->db->update('pks_groups', array('parked' => $row_group['parked'], 'availables' => $group_va), array('group_id' => $rows['group_id'])); + + $this->vars['mqtt']->publish(MQ_TOPIC_SUBLEVEL, "{$rows['group_id']},{$group_va_pad}", 0); // 送出剩餘車位數給字幕機 + // 總車位數暫無需處理 + + // 七樓無在席, 手動或用猜的 + /* + $f7_total = 74; + $sql = "select renum from pks_groups where group_id = 'F7'"; + $row_group = $this->db->query($sql)->row_array(); + $f7_renum = $row_group['renum']; + $total_parked_sql = "select count(cario_no) as parked + from cario where + cario.in_time > DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 5 DAY) + and cario.finished = 0 + and cario.err = 0 + and cario.in_out = 'CI' + and cario.out_time is null"; + $total_parked_row_group = $this->db->query($total_parked_sql)->row_array(); + $sql = "select count(pksno) as parked from pks where status != 'VA'"; + $row_group = $this->db->query($sql)->row_array(); + $f7_mqtt = $total_parked_row_group['parked'] - $row_group['parked']; + if($f7_mqtt > $f7_total){ + $f7_mqtt = $f7_total; + }else if($f7_mqtt <= 0){ + $f7_mqtt = 0; + } + $this->db->update('pks_groups', array('parked' => $f7_mqtt, 'availables' => $f7_total - $f7_mqtt + $f7_renum), array('group_id' => 'F7')); + $f7_mqtt_pad = str_pad($f7_total - $f7_mqtt + $f7_renum, 3, '0', STR_PAD_LEFT); + + $this->vars['mqtt']->publish(MQ_TOPIC_SUBLEVEL, "F7,{$f7_mqtt_pad}", 0); // F7 MQTT + */ + } + } + } + + + // 重新計算 + public function reculc() + { + // 找出與與此車位相關的群組 + $sql = "select group_id, tot, renum + from pks_groups"; + + $retults = $this->db->query($sql)->result_array(); + + foreach ($retults as $rows) + { + // 計算群組異動後的空車位數, 先讀出已停車位數 + $sql = "select count(*) as parked from pks where status != 'VA' and pksno in (select pksno from pks_group_member where group_id = '{$rows['group_id']}')"; + $row_group = $this->db->query($sql)->row_array(); + $group_va = $rows['tot'] + $rows['renum'] - $row_group['parked']; // 群組空車位數 + $this->db->update('pks_groups', array('parked' => $row_group['parked'], 'availables' => $group_va), array('group_id' => $rows['group_id'])); + + // $this->vars['mqtt']->publish("VA-{$rows['group_id']}", "{$group_va}", 0); // 送出剩餘車位數給字幕機 + + get_headers("http://192.168.51.15/set_num.php?group_id={$rows['group_id']}&num={$group_va}"); + + echo "group_id:{$rows['group_id']}, tot:{$rows['tot']}, availables:{$group_va}, parked:{$row_group['parked']}, renum:{$rows['renum']}
"; + } + } + + // 取得所有車位使用狀態 + public function query_station_status($station_no) + { + /* 沒有group_id, pks不能直接用, 要多撈兩張表 + + $sql = "select pksno, posx, posy, in_time + FROM pks + WHERE station_no = '".$station_no."' and lpr != ''"; + */ + $sql = "SELECT pks.pksno AS pksno, pks.posx AS posx, pks.posy AS posy, pks.in_time AS in_time, + pks_groups.group_id AS group_id + FROM pks + LEFT JOIN pks_group_member ON pks.pksno = pks_group_member.pksno AND pks.station_no = pks_group_member.station_no + LEFT JOIN pks_groups ON pks_group_member.group_id = pks_groups.group_id + WHERE pks.lpr != '' AND pks.station_no = '".$station_no."' AND pks_groups.group_type = '1' "; + + $retults = $this->db->query($sql)->result_array(); + + $currentTime = new DateTime("now"); + foreach ($retults as $idx => $rows) + { + $startTime = new DateTime($rows['in_time']); // 進場時間 + $interval = $startTime->diff($currentTime); + $status = $this->gen_pks_s($interval); // 一般:0, 隔日:1, 超過3日:3, 隔週:7, 隔20日:20 + + $data['result'][$idx] = array + ( + 'g'=> $rows['group_id'], + 'id'=> $rows['pksno'], + 'x' => $rows['posx'], + 'y' => $rows['posy'], + 's' => $status + ); + } + return $data; + } + + // 取得車位狀態 + private function gen_pks_s($interval) + { + $status = 0; // 一般:0, 隔日:1, 超過3日:3, 隔週:7, 隔20日:20 + if($interval->y > 0 || $interval->m > 0 || $interval->d >= 20){ + $status = 20; + }else if($interval->d >= 7){ + $status = 7; + }else if($interval->d >= 3){ + $status = 3; + }else if($interval->d >= 1){ + $status = 1; + } + return $status; + } + + // 取得指定車位使用狀態 + public function query_station_pks($station_no, $pksno) + { + $sql = "SELECT pks.pksno AS pksno, pks.lpr AS lpr, pks.in_time AS in_time, pks.station_no AS station_no, + pks_groups.group_id AS group_id, pks_groups.group_name AS group_name, pks_groups.group_type AS type + FROM pks + LEFT JOIN pks_group_member ON pks.pksno = pks_group_member.pksno AND pks.station_no = pks_group_member.station_no + LEFT JOIN pks_groups ON pks_group_member.group_id = pks_groups.group_id + WHERE pks.pksno = '".$pksno."' AND pks.station_no = '".$station_no."' AND pks_groups.group_type = '1' "; + + $retults = $this->db->query($sql)->result_array(); + + $currentTime = new DateTime("now"); + foreach ($retults as $idx => $rows) + { + $startTime = new DateTime($rows['in_time']); // 進場時間 + $interval = $startTime->diff($currentTime); + $status = $this->gen_pks_s($interval); // 一般:0, 隔日:1, 超過3日:3, 隔週:7, 隔20日:20 + + $data['result'][$idx] = array + ( + 'pksno'=> $rows['pksno'], + 'lpr' => $rows['lpr'], + 'time' => $rows['in_time'], + 'station_no' => $rows['station_no'], + 'group_id' => $rows['group_id'], + 'group_name' => $rows['group_name'], + 'status' => $status + ); + } + return $data; + } + +} diff --git a/models/Qcar_model.php b/models/Qcar_model.php new file mode 100644 index 0000000..83e3069 --- /dev/null +++ b/models/Qcar_model.php @@ -0,0 +1,349 @@ +load->database(); + } + + // 查車 + public function q_pks($lpr) + { + $sql = "select p.pksno, p.pic_name, p.update_time, p.in_time, p.posx, p.posy, m.group_id, g.group_name, g.floors + from pks p, pks_group_member m, pks_groups g + where p.pksno = m.pksno + and m.group_id = g.group_id + and g.group_type = 1 + and p.lpr = '{$lpr}' + limit 1"; + $rows = $this->db->query($sql)->row_array(); + + /* + if (!empty($rows['pic_name'])) + { + // $rows['pic_name'] = str_replace('.jpg', '', $rows['pic_name']); + $rows['pic_name'] = $rows['pic_name']; + } + else // 查無資料, 啟用模糊比對 + { + $len = strlen($lpr); + if ($len >= 5) // 檢查車牌號碼長度 + { + $arr = explode(';', file_get_contents("http://192.168.11.253:8090/cgi-bin/parking_status.cgi?CMD=QUERY_SEAT&LPR={$lpr}")); + $pksno = $arr[0]; + } + else + { + $pksno = 0; // 車牌號碼長度錯誤 + } + + trigger_error("電腦查詢模糊比對:[{$lpr}]:" . print_r($arr, true)); + if ($pksno != 0) // 模糊比對成功 + { + $sql = "select p.pic_name, p.update_time, p.in_time, p.posx, p.posy, m.group_id, g.group_name, g.floors + from pks p, pks_group_member m, pks_groups g + where p.pksno = m.pksno + and m.group_id = g.group_id + and g.group_type = 1 + and p.pksno = {$pksno} + limit 1"; + $rows_pks = $this->db->query($sql)->row_array(); + + $rows['pksno'] = $pksno; + // $rows['pic_name'] = str_replace('.jpg', '', $rows_pks['pic_name']); + $rows['pic_name'] = $rows_pks['pic_name']; + $rows['update_time'] = $rows_pks['update_time']; + $rows['in_time'] = $rows_pks['in_time']; + $rows['floors'] = $rows_pks['floors']; + $rows['posx'] = $rows_pks['posx']; + $rows['posy'] = $rows_pks['posy']; + $rows['group_id'] = $rows_pks['group_id']; + $rows['group_name'] = $rows_pks['group_name']; + } + else // 模糊比對仍是失敗 + { + $rows['pksno'] = '0'; // 無該筆資料 + } + + } + */ + + return $rows; + } + + + // 月租會員加入 + public function q_rents($lpr) + { + $rows = $this->db->select("station_no, member_no, member_name, date_format(end_date, '%Y-%m-%d') as end_date, amt , date_add(date_format(end_date, '%Y-%m-%d'), INTERVAL 1 day) as next_start, date_add(date_format(end_date, '%Y-%m-%d'), INTERVAL 1 MONTH) as next_end", false) + ->from('members') + ->where('lpr', $lpr) + ->get() + ->row_array(); + if (empty($rows['member_no'])) $rows['member_no'] = 0; // 無此資料 + + return $rows; + } + + // 新增月租轉帳資料 + public function transfer_money_create($data) + { + $this->db->insert('tx_money', $data); + } + + // 更新月租轉帳資料 (已結帳) + public function transfer_money_done($order_no) + { + $data = array(); + $data['status'] = 1; //狀態,0:剛建立, 1:已結帳, 2:錢沒對上 + $this->db->update('tx_money', $data, array('order_no' => $order_no)); + return true; + } + + // 更新發票號碼 + public function transfer_money_set_invoice($order_no, $invoice_no) + { + $data = array(); + $data['invoice_no'] = $invoice_no; + $this->db->update('tx_money', $data, array('order_no' => $order_no)); + return true; + } + + // 找不到POS機 + public function transfer_money_done_with_error_10($order_no) + { + $data = array(); + $data['status'] = 10; //狀態,0:剛建立, 1:已結帳, 2:錢沒對上, 3:發票沒拿到, 4:手動調整, 10:找不到POS機 + $this->db->update('tx_money', $data, array('order_no' => $order_no)); + return true; + } + + // 更新發票號碼失敗 + public function transfer_money_set_invoice_error_4($order_no) + { + $data = array(); + $data['status'] = 3; //狀態,0:剛建立, 1:已結帳, 2:錢沒對上, 3:發票沒拿到 + $this->db->update('tx_money', $data, array('order_no' => $order_no)); + return true; + } + + // 更新月租轉帳資料 (錢沒對上) + public function transfer_money_done_with_error_2($order_no) + { + $data = array(); + $data['status'] = 2; //狀態,0:剛建立, 1:已結帳, 2:錢沒對上 + $this->db->update('tx_money', $data, array('order_no' => $order_no)); + return true; + } + + // 取得月租轉帳資料 + public function get_tx_money($order_no) + { + $result = $this->db + ->from('tx_money') + ->where(array('order_no' => $order_no)) + ->get() + ->result_array(); + return $result; + } + + // 歐付寶記錄 + public function create_allpay_feedback_log($data) + { + $this->db->insert('allpay_feedback_log', $data); + return true; + } + + // 將發票號碼加入資料庫 + public function update_invoice_no($order_no, $invoice_no) + { + $this->db->where(array('order_no' => $order_no)) + ->update('tx_money', array('invoice_no' => $invoice_no)); + } + + // 新增發票記錄 + public function invoice_log_create($data) + { + $this->db->insert('tx_invoice_log', $data); + } + + // 新增發票記錄回傳 + public function invoice_log_set_response($response_code, $invoice_no, $seqno) + { + $data = array(); + $data['response_code'] = $response_code; + $this->db->update('tx_invoice_log', $data, array('invoice_no' => $invoice_no, 'seqno' => $seqno)); + return true; + } + + // 取得POS機資訊 + public function get_tx_pos($pos_id) + { + $result = $this->db + ->from('tx_pos') + ->where(array('pos_id' => $pos_id)) + ->get() + ->result_array(); + return $result; + } + + // 取得POS機資訊 by lan_ip + public function get_tx_pos_by_lan_ip($lan_ip) + { + $result = $this->db + ->from('tx_pos') + ->where(array('lan_ip' => $lan_ip)) + ->get() + ->result_array(); + return $result; + } + + + + + + + // 模糊比對 + function getLevenshteinSQLStatement($word, $target) + { + $words = array(); + + if(strlen($word) >= 5) + { + for ($i = 0; $i < strlen($word); $i++) { + // insertions + $words[] = substr($word, 0, $i) . '_' . substr($word, $i); + // deletions + $words[] = substr($word, 0, $i) . substr($word, $i + 1); + // substitutions + //$words[] = substr($word, 0, $i) . '_' . substr($word, $i + 1); + } + } + else + { + for ($i = 0; $i < strlen($word); $i++) { + // insertions + $words[] = substr($word, 0, $i) . '_' . substr($word, $i); + } + } + + // last insertion + $words[] = $word . '_'; + //return $words; + + $fuzzy_statement = ' ('; + foreach ($words as $idx => $word) + { + $fuzzy_statement .= " {$target} LIKE '%{$word}%' OR "; + } + $last_or_pos = strrpos($fuzzy_statement, 'OR'); + if($last_or_pos !== false) + { + $fuzzy_statement = substr_replace($fuzzy_statement, ')', $last_or_pos, strlen('OR')); + } + + return $fuzzy_statement; + } + + // 取得進場資訊 (模糊比對) + public function q_fuzzy_pks($word) + { + if(empty($word) || strlen($word) <= 0 || strlen($word) > 10) + { + return null; + } + + $sql = "SELECT station_no, lpr, in_time, pic_name as pks_pic_name + FROM pks + WHERE {$this->getLevenshteinSQLStatement($word, 'lpr')} + ORDER BY lpr ASC"; + $retults = $this->db->query($sql)->result_array(); + + if(count($retults) > 0) + { + foreach ($retults as $idx => $rows) + { + $pks_pic_path = ''; + if(!empty($rows['pks_pic_name'])) + { + //$pks_pic_path = APP_URL.'pks_pics/'.str_replace('.jpg', '', $rows['pks_pic_name']); + $pks_pic_path = SERVER_URL.'pkspic/'.$rows['pks_pic_name']; + } + + $data['result'][$idx] = array + ( + 'lpr'=> $rows['lpr'], + 'pks_pic_path' => $pks_pic_path, + 'station_no' => $rows['station_no'], + 'in_time' => $rows['in_time'] + ); + } + } + else + { + // 讀取入場資料 + $sql = "SELECT cario.station_no as station_no, cario.obj_id as lpr, cario.in_time as in_time, cario.in_pic_name as pks_pic_name + FROM cario + WHERE {$this->getLevenshteinSQLStatement($word, 'obj_id')} + AND in_out = 'CI' AND finished = 0 AND err = 0 AND out_time IS NULL + ORDER BY lpr ASC"; + // AND in_time > DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 5 DAY) + $retults = $this->db->query($sql)->result_array(); + + if(count($retults) > 0) + { + foreach ($retults as $idx => $rows) + { + $pks_pic_path = ''; + if(!empty($rows['pks_pic_name'])) + { + $pic_name = str_replace('.jpg', '', $rows['pks_pic_name']); + $arr = explode('-', $pic_name); + $pks_pic_path = SERVER_URL.'carspic/'.substr($arr[7], 0, 8).'/'.$pic_name.'.jpg'; + } + + $data['result'][$idx] = array + ( + 'lpr'=> $rows['lpr'], + 'pks_pic_path' => $pks_pic_path, + 'station_no' => $rows['station_no'], + 'in_time' => $rows['in_time'] + ); + } + } + } + return $data; + + /* + foreach ($retults as $idx => $rows) + { + $pks_pic_path = ''; + if(!empty($rows['pks_pic_name'])) + { + //$pks_pic_path = APP_URL.'pks_pics/'.str_replace('.jpg', '', $rows['pks_pic_name']); + $pks_pic_path = SERVER_URL.'pkspic/'.$rows['pks_pic_name']; + } + + $data['result'][$idx] = array + ( + 'lpr'=> $rows['lpr'], + 'pks_pic_path' => $pks_pic_path, + 'station_no' => $rows['station_no'], + 'in_time' => $rows['in_time'] + ); + } + */ + } + + + + + + + +} diff --git a/models/Security_model.php b/models/Security_model.php new file mode 100644 index 0000000..57f2498 --- /dev/null +++ b/models/Security_model.php @@ -0,0 +1,84 @@ +load->database(); + } + + // 更改會員密碼 + public function change_pswd($lpr, $new_pswd) + { + $data = array('passwd' => $new_pswd); + $this->db->update('members', $data, array('lpr' => $lpr)); + return 'ok'; + } + + // 防盜鎖車 + // http://203.75.167.89/parkingquery.html/security_action/ABC1234/pswd/2 + public function security_action($lpr, $pswd, $action) + { + $data = array(); + /* + $rows = $this->db->select('member_no, passwd, locked') + ->from('members') + ->where(array('lpr' => $lpr, 'passwd' => $pswd)) + ->limit(1) + ->get() + ->row_array(); + trigger_error('防盜鎖車:'.$this->db->last_query()); + + // 無資料或密碼錯誤 + if (empty($rows['member_no'])) + { + $data['result_code'] = 'FAIL'; + return($data); + } + */ + + $rows = $this->db->select('member_no, passwd, locked, lpr') + ->from('members') + ->where(array('lpr' => $lpr)) + ->limit(1) + ->get() + ->row_array(); + trigger_error('防盜鎖車:'.$this->db->last_query()); + + // 無資料或密碼錯誤 + if (empty($rows['member_no']) || md5($rows['passwd']) != $pswd) + { + // 密碼未設定且輸入密碼為車牌號碼 + if(empty($rows['passwd']) && md5($rows['lpr']) == $pswd){ + // do nothing + }else{ + $data['result_code'] = 'FAIL'; + return($data); + } + } + + $data['result_code'] = 'OK'; + // 查詢防盜狀態 + if ($action == 2) + { + $data['result']['action'] = 'CHECK_SECURITY'; + $data['result'][0]['num'] = $lpr; + $data['result'][0]['result'] = $rows['locked'] ? 'ON' : 'OFF'; + return $data; + } + + $this->db + ->where('member_no', $rows['member_no']) + ->update('members', array('locked' => $action)); + + $data['result']['action'] = $action == 1 ? 'ON' : 'OFF'; + return $data; + } + + +} diff --git a/models/Sync_data_model.php b/models/Sync_data_model.php new file mode 100644 index 0000000..a53ccfb --- /dev/null +++ b/models/Sync_data_model.php @@ -0,0 +1,715 @@ +load->database(); + } + + public function init($vars) + { + $this->vars = $vars; + } + + // 送出至message queue(目前用mqtt) + public function mq_send($topic, $msg) + { + $this->vars['mqtt']->publish($topic, $msg, 0); + trigger_error("mqtt:{$topic}|{$msg}"); + } + + // ------------------------------------------------ + // + // 在席系統同步 (START) + // + // ------------------------------------------------ + + // 同步 888 + public function sync_888($parms) + { + $result = -888; + + if(!isset($parms['lpr']) || !isset($parms['etag']) || !isset($parms['io']) || + ($parms['lpr'] == 'NONE' && $parms['etag'] == 'NONE') + ) + { + trigger_error(__FUNCTION__ . '..NONE..'. print_r($parms, true)); + return $result; + } + + trigger_error(__FUNCTION__ . "..{$parms['sno']}|{$parms['io']}|{$parms['lpr']}|{$parms['etag']}.."); + + // [START] 擋相同車號進出 + $skip_or_not = false; + $new_cars_tmp = array + ( + 'timestamp' => time(), + 'sno_io' => $parms['sno'] . $parms['io'], + 'lpr' => $parms['lpr'], + 'etag' => $parms['etag'] + ); + $cars_tmp_log_arr = $this->vars['mcache']->get(MCACHE_SYNC_888_TMP_LOG); + if(empty($cars_tmp_log_arr)) + { + $cars_tmp_log_arr = array(); + } + + if(isset($cars_tmp_log_arr[$new_cars_tmp['sno_io']])) + { + $last_cars_tmp = $cars_tmp_log_arr[$new_cars_tmp['sno_io']]; + + // 判斷是否跳過 (記錄於一小時內, 相同場站進出 lpr 或 etag) + if( ( ($last_cars_tmp['lpr'] == $new_cars_tmp['lpr'] && $last_cars_tmp['lpr'] != 'NONE') || + ($last_cars_tmp['etag'] == $new_cars_tmp['etag'] && $last_cars_tmp['etag'] != 'NONE') ) && $last_cars_tmp['timestamp'] > $new_cars_tmp['timestamp'] - 3600 + ) + $skip_or_not = true; + } + + // 更新 + $cars_tmp_log_arr[$new_cars_tmp['sno_io']] = $new_cars_tmp; + $this->vars['mcache']->set(MCACHE_SYNC_888_TMP_LOG, $cars_tmp_log_arr); + trigger_error(__FUNCTION__ . '..upd ' . MCACHE_SYNC_888_TMP_LOG . " |s:{$skip_or_not}|" . print_r($cars_tmp_log_arr, true)); + + // 跳過 + if($skip_or_not) + { + trigger_error(__FUNCTION__ . '..skip..'); + return false; + } + // [END] 擋相同車號進出 + + switch($parms['io']) + { + // 入場 + case 'CI': + $result = $this->pks_availables_update(SYNC_PKS_GROUP_ID_CI, -1, false, $parms['sno']); + break; + case 'MI': + $result = $this->pks_availables_update(SYNC_PKS_GROUP_ID_MI, -1, false, $parms['sno']); + break; + // 出場 + case 'CO': + $result = $this->pks_availables_update(SYNC_PKS_GROUP_ID_CI, 1, false, $parms['sno']); + break; + case 'MO': + $result = $this->pks_availables_update(SYNC_PKS_GROUP_ID_MI, 1, false, $parms['sno']); + break; + } + + return $result; + } + + // 微調剩餘車位數 + public function pks_availables_update($group_id, $value, $is_renum=true, $station_no=STATION_NO) + { + $where_group_arr = array('group_id' => $group_id, 'station_no' => $station_no); + + $rows = $this->db->select('renum, parked, tot') + ->from('pks_groups') + ->where($where_group_arr) + ->limit(1) + ->get() + ->row_array(); + + $renum = $rows['renum']; + $parked = $rows['parked']; + $tot = $rows['tot']; + + trigger_error("更新車位數|{$group_id}|{$value}|{$is_renum}|".print_r($rows, true)); + + if($is_renum) + { + // 一般微調 + if($value == 0) + { + $this->db->where($where_group_arr) + ->update('pks_groups', array('renum' => 0, 'parked' => 0, 'availables' => $tot)); + trigger_error(__FUNCTION__ . '..reset everything and exit..'); + return true; // 中斷 + } + else if($value >= 1) + { + // 增加 + $renum = $renum + 1; + } + else + { + // 減少 + $renum = $renum - 1; + } + + $availables = $tot - $parked + $renum; + + // 防止負值 + if($availables <= 0) + { + $availables = 0; + $parked = $tot; + $renum = 0; + trigger_error(__FUNCTION__ . '..ava < 0..auto set (ava = 0, parked = tot, renum = 0)..'); + } + else if($availables >= $tot) + { + $availables = $tot; + $parked = 0; + $renum = 0; + trigger_error(__FUNCTION__ . '..ava > tot..auto set (ava = tot, parked = 0, renum = 0)..'); + } + + // 更新 db + $this->db->where($where_group_arr) + ->update('pks_groups', array('parked' => $parked, 'availables' => $availables, 'renum' => $renum)); + } + else + { + // 進出場 + if($value == 0) + { + trigger_error(__FUNCTION__ . '..??? exit..'); + return true; // 中斷 + } + else if($value >= 1) + { + // 已停車位數減少, 空車位數增加 + $parked = $parked - 1; + } + else + { + // 已停車位數增加, 空車位數減少 + $parked = $parked + 1; + } + + /* + // 防止負值 + if($parked < 0) + { + $parked = 0; + $renum = 0; // 自動重設 renum + trigger_error(__FUNCTION__ . '..parked < 0..set (parked = 0, renum = 0)..'); + } + else if($parked >= $tot) + { + $parked = $tot; + $renum = 0; // 自動重設 renum + trigger_error(__FUNCTION__ . '..parked > tot.. = tot..set (parked = tot, renum = 0)..'); + } + */ + + $availables = $tot - $parked + $renum; + + // 防止負值 + if($availables <= 0) + { + $availables = 0; + $parked = $tot; + $renum = 0; + trigger_error(__FUNCTION__ . '..ava < 0..auto set (ava = 0, parked = tot, renum = 0)..'); + } + else if($availables >= $tot) + { + $availables = $tot; + $parked = 0; + $renum = 0; + trigger_error(__FUNCTION__ . '..ava > tot..auto set (ava = tot, parked = 0, renum = 0)..'); + } + + // 更新 db + $this->db->where($where_group_arr) + ->update('pks_groups', array('parked' => $parked, 'availables' => $availables, 'renum' => $renum)); + } + + // 送出即時訊號 + if($group_id == SYNC_PKS_GROUP_ID_CI) + { + $this->mq_send(MQ_TOPIC_ALTOB, MQ_ALTOB_888 . ",1,{$availables}" . MQ_ALTOB_888_END_TAG); // 送出 888 (汽車) + } + else if($group_id == SYNC_PKS_GROUP_ID_MI) + { + $this->mq_send(MQ_TOPIC_ALTOB, MQ_ALTOB_888 . ",2,{$availables}" . MQ_ALTOB_888_END_TAG); // 送出 888 (機車) + } + else + { + $availables_pad = str_pad($availables, 3, '0', STR_PAD_LEFT); // 補零 + $this->mq_send(MQ_TOPIC_SUBLEVEL, "{$group_id},{$availables_pad}"); // 送出剩餘車位數給字幕機 + } + + return $this->db->affected_rows(); + } + + // ------------------------------------------------ + // + // 在席系統同步 (END) + // + // ------------------------------------------------ + + // ------------------------------------------------ + // + // 中控接收端 (START) + // + // ------------------------------------------------ + + // 同步場站會員 (功能: 會員同步) + public function sync_members($info_arr=array('station_no_arr' => STATION_NO)) + { + $data_member_arr = array(); + $data_car_arr = array(); + + try{ + // 查現況 + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, SYNC_API_URL . 'member_query_all_in_one'); + curl_setopt($ch, CURLOPT_HEADER, FALSE); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); + curl_setopt($ch, CURLOPT_POST, TRUE); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT ,10); + curl_setopt($ch, CURLOPT_TIMEOUT, 10); //timeout in seconds + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($info_arr)); + $data = curl_exec($ch); + curl_close($ch); + + }catch (Exception $e){ + trigger_error('error msg:'.$e->getMessage()); + trigger_error(SYNC_DATA_LOG_TITLE . $e->getMessage()); + } + + $data_member_arr = json_decode($data, true); + + if (sizeof($data_member_arr) <= 0) + { + trigger_error(SYNC_DATA_LOG_TITLE . '.. empty ..'); // 忽略完全沒會員的情況 + return 'empty'; + } + else + { + foreach($data_member_arr as $data) + { + // create member_car + $data_car = array + ( + 'station_no' => $data['station_no'], + 'member_no' => $data['member_no'], + 'lpr' => $data['lpr'], + 'lpr_correct' => $data['lpr'], + 'etag' => $data['etag'], + 'start_time' => $data['start_date'], + 'end_time' => $data['end_date'] + ); + array_push($data_car_arr, $data_car); + } + } + + //trigger_error(SYNC_DATA_LOG_TITLE . '.. test ..' . print_r($data_member_arr, true)); + + $this->db->trans_start(); + // 清空 + $this->db->empty_table('members'); + $this->db->empty_table('member_car'); + // 建立 members + $this->db->insert_batch('members', $data_member_arr); + // 建立 member_car + $this->db->insert_batch('member_car', $data_car_arr); + + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(SYNC_DATA_LOG_TITLE . '.. sync fail ..'. '| last_query: ' . $this->db->last_query()); + return 'fail'; + } + + trigger_error(SYNC_DATA_LOG_TITLE . '.. sync completed ..'); + return 'ok'; + } + + // 同步車牌更換 (功能: 換車牌同步) + public function sync_switch_lpr($switch_lpr_arr) + { + trigger_error( __FUNCTION__ . '..' . print_r($switch_lpr_arr, true)); + + $this->db->trans_start(); + + foreach($switch_lpr_arr as $data) + { + $station_no = $data['station_no']; + $member_no = $data['member_no']; + $old_lpr = $data['old_lpr']; + $new_lpr = $data['new_lpr']; + + + $new_data = array('lpr' => $new_lpr, 'lpr_correct' => $new_lpr, 'member_no' => $member_no); + $this->db->update('etag_lpr', $new_data, array('lpr_correct' => $old_lpr)); + + $affect_rows = $this->db->affected_rows(); + trigger_error(SYNC_DATA_LOG_TITLE . "換車牌更新 etag_lpr 共[{$affect_rows}]筆..".print_r($data, true)); + + /* + if($station_no == STATION_NO) + { + $new_data = array('lpr' => $new_lpr, 'lpr_correct' => $new_lpr, 'member_no' => $member_no); + $this->db->update('etag_lpr', $new_data, array('lpr_correct' => $old_lpr)); + + $affect_rows = $this->db->affected_rows(); + trigger_error(SYNC_DATA_LOG_TITLE . "換車牌更新 etag_lpr 共[{$affect_rows}]筆..".print_r($data, true)); + } + else + { + trigger_error(SYNC_DATA_LOG_TITLE . __FUNCTION__ . "..資料異常..".print_r($data, true)); + } + */ + } + + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(SYNC_DATA_LOG_TITLE . '.. sync fail ..'. '| last_query: ' . $this->db->last_query()); + return 'fail'; + } + + trigger_error(SYNC_DATA_LOG_TITLE . '.. sync completed ..'); + return 'ok'; + } + + // 同步場站費率 + public function sync_price_plan($info_arr=array('station_no_arr' => STATION_NO)) + { + try{ + // 查另一台主機 + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, SYNC_API_URL . 'price_plan_query_all_in_one'); + curl_setopt($ch, CURLOPT_HEADER, FALSE); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); + curl_setopt($ch, CURLOPT_POST, TRUE); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT ,5); + curl_setopt($ch, CURLOPT_TIMEOUT, 5); //timeout in seconds + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($info_arr)); + $data = curl_exec($ch); + curl_close($ch); + + }catch (Exception $e){ + trigger_error('error msg:'.$e->getMessage()); + } + + $decode_result = json_decode($data, true); + + if (sizeof($decode_result) <= 0) return "empty"; + + $this->db->trans_start(); + foreach ($decode_result as $key => $value) + { + $station_no = $value["station_no"]; + $tx_price_plan_id = $value["txid"]; + $tx_type = $value["tx_type"]; + + $price_plan_data = array + ( + 'station_no' => $station_no, + 'tx_type' => $tx_type, + 'remarks' => $value['remarks'], + 'price_plan' => $value['price_plan'], + 'start_time' => $value['start_time'], + 'valid_time' => $value['valid_time'] + ); + + // 刪除 + $this->db->delete('tx_price_plan', array('station_no' => $station_no, 'tx_type' => $tx_type)); + + // 新增 + $this->db->insert('tx_price_plan', $price_plan_data); + } + $this->db->trans_complete(); + + return "ok"; + } + + // 取得最新未結清 (功能: 行動支付) + public function get_last_unbalanced_cario($lpr) + { + $sql = "SELECT station_no, cario_no, in_time, pay_time, out_time, out_before_time, member_no + FROM cario + WHERE + obj_id = '{$lpr}' AND finished = 0 AND err = 0 + ORDER BY cario_no DESC + LIMIT 1 + "; + + $results = $this->db->query($sql)->result_array(); + + if(isset($results[0])) + return $results[0]; + return false; + } + + // 同步車位現況 (功能: 888 同步, 在席同步) + public function sync_pks_groups_reload($station_setting) + { + $info = array(); + $station_no_arr = explode(SYNC_DELIMITER_ST_NO, $station_setting['station_no']); + $station_name_arr = explode(SYNC_DELIMITER_ST_NAME, $station_setting['station_name']); + $station_888_arr = explode(SYNC_DELIMITER_ST_INFO, $station_setting['station_888']); + foreach($station_no_arr as $key => $station_no) + { + if($station_888_arr[$key] == 1) // 啟用 + array_push($info, array('station_no' => $station_no_arr[$key], 'station_name' => $station_name_arr[$key])); + else if($station_888_arr[$key] == 4) // 關閉 + { + // 清除 888 + $this->db->delete('pks_groups', array('station_no' => $station_no_arr[$key])); + } + else + { + trigger_error(__FUNCTION__ . '..unknown station_888:' . $station_888_arr[$key]); + } + } + + if(empty($info)) + return 'none'; + + return $this->sync_pks_groups($info, true); + } + + // 同步車位現況 (功能: 888 同步, 在席同步) + public function sync_pks_groups($info_arr=array(array('station_no' => STATION_NO, 'station_name' => STATION_NAME)), $reload=false) + { + if($reload) + { + // 確認應該要有的 pks_groups + $pks_groups_arr = array(); + $pks_groups_name_arr = array(); + foreach($info_arr as $data) + { + $pks_key = $data['station_no'] . SYNC_DELIMITER_ST_INFO . SYNC_PKS_GROUP_ID_CI; + array_push($pks_groups_arr, $pks_key); // 汽車 888 + + $pks_key = $data['station_no'] . SYNC_DELIMITER_ST_INFO . SYNC_PKS_GROUP_ID_MI; + array_push($pks_groups_arr, $pks_key); // 機車 888 + + $pks_groups_name_arr[$data['station_no']] = $data['station_name']. '(888)'; // 群組名稱 + } + + // 過濾已存在的部份 + $sql = "SELECT station_no, group_id FROM pks_groups"; + $current_pks_group = $this->db->query($sql)->result_array(); + foreach($current_pks_group as $data) + { + $pks_key = $data['station_no'] . SYNC_DELIMITER_ST_INFO . $data['group_id']; + $key = array_search($pks_key, $pks_groups_arr); + if($key !== false) + unset($pks_groups_arr[$key]); + } + + // 建立缺少的部份 + if(!empty($pks_groups_arr)) + { + // [A.開始] + $this->db->trans_start(); + + foreach($pks_groups_arr as $new_data) + { + $pks_info = explode(SYNC_DELIMITER_ST_INFO, $new_data); + $new_pks_groups_data = array( + 'station_no' => $pks_info[0], + 'group_id' => $pks_info[1], + 'tot' => 100, // 預設車位數 + 'availables' => 100, // 預設車位數 + 'floors' => 'TOT', + 'group_name' => $pks_groups_name_arr[$pks_info[0]] + ); + $this->db->insert('pks_groups', $new_pks_groups_data); + trigger_error(__FUNCTION__ . '..insert pks_groups..'. print_r($new_pks_groups_data, true)); + } + + // [C.完成] + $this->db->trans_complete(); + if ($this->db->trans_status() === FALSE) + { + trigger_error(__FUNCTION__ . '..trans_error..' . '| last_query: ' . $this->db->last_query()); + return 'fail'; // 中斷 + } + } + } + + $sql = "SELECT pks_groups.station_no, + pks_groups.group_name as group_name, pks_groups.tot as tot, pks_groups.parked as parked, pks_groups.availables as availables, pks_groups.group_id as group_id, pks_groups.renum as renum + FROM pks_groups + ORDER BY pks_groups.group_id DESC"; + $pks_group_query_data = $this->db->query($sql)->result_array(); + //trigger_error(__FUNCTION__ . '..sync..' . print_r($pks_group_query_data, true)); + + // 同步 + require_once(ALTOB_SYNC_FILE); + $sync_agent = new AltobSyncAgent(); + $sync_agent->init(STATION_NO); // 已帶上的資料場站編號為主 + $sync_result = $sync_agent->upd_pks_groups(json_encode($pks_group_query_data, JSON_UNESCAPED_UNICODE)); + trigger_error( SYNC_DATA_LOG_TITLE . '..'. __FUNCTION__ . "..upd_pks_groups.." . $sync_result); + } + + // 重新載入場站設定 + public function reload_station_setting() + { + try{ + // 查現況 + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, SYNC_API_URL . 'station_setting_query'); + curl_setopt($ch, CURLOPT_HEADER, FALSE); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); + curl_setopt($ch, CURLOPT_POST, TRUE); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT ,10); + curl_setopt($ch, CURLOPT_TIMEOUT, 10); //timeout in seconds + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array())); + $return_result = curl_exec($ch); + curl_close($ch); + + }catch (Exception $e){ + trigger_error('error msg:'.$e->getMessage()); + } + + $station_setting_result = json_decode($return_result, true); + + if(!isset($station_setting_result['results']) || sizeof($station_setting_result['results']) <= 0) + { + trigger_error(__FUNCTION__ . '..fail..' . print_r($return_result, true)); + return 'fail'; + } + + $station_ip_str = $station_setting_result['station_ip']; // 場站目前對外IP + + $station_setting_arr = $station_setting_result['results']; + $station_no_arr = array(); + $station_name_arr = array(); + $station_888_arr = array(); + foreach($station_setting_arr as $data) + { + array_push($station_no_arr, $data['station_no']); + array_push($station_name_arr, $data['short_name']); + array_push($station_888_arr, $data['station_888']); + } + $station_no_str = implode(SYNC_DELIMITER_ST_NO, $station_no_arr); // 取值時會用到 + $station_name_str = implode(SYNC_DELIMITER_ST_NAME, $station_name_arr); // 純顯示 + $station_888_str = implode(SYNC_DELIMITER_ST_INFO, $station_888_arr); // 場站888設定 + + // 設定到 mcache + $this->vars['mcache']->set(MCACHE_STATION_NO_STR, $station_no_str); + $this->vars['mcache']->set(MCACHE_STATION_NAME_STR, $station_name_str); + $this->vars['mcache']->set(MCACHE_STATION_IP_STR, $station_ip_str); + $this->vars['mcache']->set(MCACHE_STATION_888_STR, $station_888_str); + return 'ok'; + } + + // 取得目前場站設定 + public function station_setting_query($reload=false) + { + $station_no_str = $this->vars['mcache']->get(MCACHE_STATION_NO_STR); + $station_name_str = $this->vars['mcache']->get(MCACHE_STATION_NAME_STR); + $station_ip_str = $this->vars['mcache']->get(MCACHE_STATION_IP_STR); + $station_888_str = $this->vars['mcache']->get(MCACHE_STATION_888_STR); + + if($reload || empty($station_no_str) || empty($station_name_str) || empty($station_ip_str) || empty($station_888_str)) + { + $result = $this->reload_station_setting(); + + if($result == 'ok') + { + $station_no_str = $this->vars['mcache']->get(MCACHE_STATION_NO_STR); + $station_name_str = $this->vars['mcache']->get(MCACHE_STATION_NAME_STR); + $station_ip_str = $this->vars['mcache']->get(MCACHE_STATION_IP_STR); + $station_888_str = $this->vars['mcache']->get(MCACHE_STATION_888_STR); + } + else + { + /* + $station_setting = array(); + $station_setting['station_no'] = STATION_NO; + $station_setting['station_name'] = STATION_NAME; + $station_setting['station_ip'] = STATION_IP; + return $station_setting; + */ + return false; + } + } + + $station_setting = array(); + $station_setting['station_no'] = $station_no_str; + $station_setting['station_name'] = $station_name_str; + $station_setting['station_ip'] = $station_ip_str; + $station_setting['station_888'] = $station_888_str; + return $station_setting; + } + + // ------------------------------------------------ + // + // 中控接收端 (END) + // + // ------------------------------------------------ + + + + + + // ------------------------------------------------ + // + // 其它 (START) + // + // ------------------------------------------------ + + // 手動新增入場資料 + public function gen_carin($parms) + { + $in_time = date('Y-m-d H:i:s'); + + $data = array( + 'station_no' => $parms['sno'], + 'obj_type' => 1, + 'obj_id' => $parms['lpr'], + 'etag' => '', + 'in_out' => $parms['io'], + 'finished' => 0, + 'in_time' => $in_time, + 'in_lane' => $parms['ivsno'], + 'out_before_time' => $in_time + ); + $this->db->insert('cario', $data); + trigger_error("新增入場資料:".print_r($parms, true)); + + require_once(ALTOB_SYNC_FILE); + // 傳送進場記錄 + $sync_agent = new AltobSyncAgent(); + $sync_agent->init($parms['sno'], $in_time); + $sync_agent->cario_no = $this->db->insert_id(); // 進出編號 + $sync_result = $sync_agent->sync_st_in($parms); + trigger_error( SYNC_DATA_LOG_TITLE . '..'. __FUNCTION__ . "..sync_st_in.." . $sync_result); + } + + // ------------------------------------------------ + // + // 其它 (END) + // + // ------------------------------------------------ + +} diff --git a/models/Txdata_model.php b/models/Txdata_model.php new file mode 100644 index 0000000..c1be591 --- /dev/null +++ b/models/Txdata_model.php @@ -0,0 +1,127 @@ +load->database(); + + $this->now_str = date('Y-m-d H:i:s'); + } + + public function init($vars) + { + $this->mcache = $vars['mcache']; + $this->mqtt = $vars['mqtt']; + } + + // 取得所有場站有效費率 + public function get_all_valid_price_plan($station_no) + { + $result = $this->db->select('tx_price_plan_id as txid, tx_type, station_no, remarks, price_plan, start_time, valid_time, create_time') + ->from('tx_price_plan') + ->where(array( + 'start_time <= ' => $this->now_str, + 'valid_time > ' => $this->now_str, + 'station_no' => $station_no + )) + ->get() + ->result_array(); + return $result; + } + + // 取得場站費率設定 + // http://203.75.167.89/txdata.html/get_price_plan/12112/0 + public function get_price_plan($station_no, $tx_type) + { + $result = $this->db->select('price_plan') + ->from('tx_price_plan') + ->where(array( + 'start_time <= ' => $this->now_str, + 'valid_time > ' => $this->now_str, + 'station_no' => $station_no, + 'tx_type' => $tx_type + )) + ->get() + ->result_array(); + return $result; + } + + // 取得特殊日期設定 + // http://203.75.167.89/txdata.html/get_date_plan/12345678/23456789 + public function get_date_plan($inTime, $balanceTime) + { + $inDateTimestamp = strtotime(date("Y-m-d", $inTime)); + $balanceDateTimestamp = strtotime(date("Y-m-d", $balanceTime)); + + $result = $this->db->select('p_type, p_date') + ->from('tx_date_plan') + ->where("p_date BETWEEN FROM_UNIXTIME({$inDateTimestamp}) AND FROM_UNIXTIME({$balanceDateTimestamp})") + //->where("p_date BETWEEN '{$inDate}' AND '{$outDate}'") + ->get() + ->result_array(); + return $result; + } + + // 同步場站費率 + public function sync_price_plan() + { + try{ + $param = array('station_no' => STATION_NO); + // 查另一台主機 + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, 'http://61.219.172.11:60123/admins.html/price_plan_query'); + curl_setopt($ch, CURLOPT_HEADER, FALSE); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); + curl_setopt($ch, CURLOPT_POST, TRUE); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT ,5); + curl_setopt($ch, CURLOPT_TIMEOUT, 5); //timeout in seconds + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($param)); + $data = curl_exec($ch); + curl_close($ch); + + }catch (Exception $e){ + trigger_error('error msg:'.$e->getMessage()); + } + + $decode_result = json_decode($data, true); + + if (sizeof($decode_result) <= 0) return "empty"; + + $this->db->trans_start(); + foreach ($decode_result as $key => $value) + { + $station_no = $value["station_no"]; + $tx_price_plan_id = $value["txid"]; + $tx_type = $value["tx_type"]; + + $price_plan_data = array + ( + 'station_no' => $station_no, + 'tx_type' => $tx_type, + 'remarks' => $value['remarks'], + 'price_plan' => $value['price_plan'], + 'start_time' => $value['start_time'], + 'valid_time' => $value['valid_time'] + ); + + // 刪除 + $this->db->delete('tx_price_plan', array('station_no' => $station_no, 'tx_type' => $tx_type)); + + // 新增 + $this->db->insert('tx_price_plan', $price_plan_data); + } + $this->db->trans_complete(); + + return "ok"; + } +} diff --git a/models/User_model.php b/models/User_model.php new file mode 100644 index 0000000..c083cff --- /dev/null +++ b/models/User_model.php @@ -0,0 +1,76 @@ +load->database(); + } + + // 登入 + public function user_login($data) + { + $login_name = $data['login_name']; + $pswd = $data['pswd']; + + $this -> db -> select('login_name, user_type, status'); + $this -> db -> from('users'); + $this -> db -> where('login_name', $login_name); + $this -> db -> where('pswd', MD5($pswd)); + $this -> db -> where('status', 1); // '狀態, 1:正常, 2:暫時停權, 3:永久停權' + $this -> db -> limit(1); + $query = $this -> db -> get(); + + if($query -> num_rows() == 1) + { + return $query->result(); + } + else + { + return false; + } + } + + // 新增 + public function user_insert($data) + { + $data['status'] = 1; // '狀態, 1:正常, 2:暫時停權, 3:永久停權' + $this->db->insert('users', $data); + + return true; + } + + // 修改 + public function user_update($data, $target_name) + { + $this->db->update('users', $data, array('login_name' => $target_name)); + + return true; + } + + // 查詢 + public function user_query() + { + $results = $this->db->select('login_name, user_name, status, modify_time, user_type') + ->from('users') + ->where(array('user_type' => 'user')) // 'admin:最高管理者, user:用戶' + ->order_by('modify_time', 'desc') + ->get() + ->result_array(); + + return $results; + } + + // 刪除 + public function user_delete($login_name) + { + $this->db->delete('users', array('login_name' => $login_name)); + + return true; + } +} diff --git a/models/index.html b/models/index.html new file mode 100644 index 0000000..b48b490 --- /dev/null +++ b/models/index.html @@ -0,0 +1,11 @@ + + + +403 Forbidden + + + +Directory access is forbidden.
+ + +