"", 'thead_open' => '', 'thead_close' => '', 'heading_row_start' => '', 'heading_row_end' => '', 'heading_cell_start' => '', 'tbody_open' => '', 'tbody_close' => '', 'row_start' => '', 'row_end' => '', 'cell_start' => '', 'row_alt_start' => '', 'row_alt_end' => '', 'cell_alt_start' => '', 'table_close' => '
', 'heading_cell_end' => '
', 'cell_end' => '
', 'cell_alt_end' => '
' ); const CSV_FIELDS = [ 'transport_provider_id', // | 2019-11-19 08:58:00 'automation_id', // | 26 'cost_raw', // | SGD 13.00 'cost', // | 13.00 'created', // | 2019-05-07 10:52:52 'completed', // | 2019-05-07 10:52:54 'travel_date', // | 2019-05-07 04:52:54 'member_id', // | 22 'location_start_id', // | 7276 'location_end_id', // | 7277 'quote_group_id', // | 851 'location_start_address', // | 65 Jurong West Central 3, Singapore, 648332 'location_start_lat', // | 1.339345 'location_start_lng', // | 103.705984 'location_start_postal', // | 'location_start_country', // | SG 'location_start_description', // | 'location_start_tz', // | Asia/Singapore 'location_end_address', // | 3 Engineering Drive 3, Singapore, 117582 'location_end_lat', // | 1.299255 'location_end_lng', // | 103.772206 'location_end_postal', // | 'location_end_country', // | SG 'location_end_description', // | 'location_end_tz' // | Asia/Singapore ]; public function index() { $this->load->helper('url'); $data = array(); $this->load->library('table'); $this->table->set_template($this->template); $data['backoffice_users'] = ""; $mysql = "SELECT '' AS edit,firstname,lastname,email,username,status,last_login,loc FROM bko_users ORDER by id ASC"; $query = $this->read_replica->query($mysql); //$this->table->set_heading( array('data' => 'ID', 'style' => 'width:50px'),'Email', 'Firstname', 'Lastname','Last Login','Location', array('data' => 'ACTION', 'style' => 'width:40px'), array('data' => 'Select', 'style' => 'width:40px')); $data['backoffice_users'] = $this->table->generate($query); $this->renderAdminPage('view_admin_users', $data); // echo 'Ameye Olu'; } protected function renderAdminPage($page_name, $data) { $this->load->view('admin/view_admin_header', $data); $this->load->view('admin/' . $page_name, $data); $this->load->view('admin/view_admin_footer', $data); } public function cardimages() { global $savvyext; $data = array(); $data['storage'] = $savvyext->cfgReadChar('system.storage_url'); //$data['js'] = array('https://maps.googleapis.com/maps/api/js?key=AIzaSyDvjiRTxngOQyBP4zpqFlZuiquc0ROvo9c&callback=initMap'); $this->renderAdminPage('cardimages', $data); } public function getValueCombo($val) { $status_value = range(0, 1); return in_array($val, $status_value) ? $val : ''; } public function setComboForDecisionStatus($params) { $this->load->model('combo_model'); $combo['card_status'] = $this->combo_model->getStatusComboWithAll( 'card_status', $params['status'] ); return $combo; } public function setFormRuleForDecisionStatus() { $this->form_validation->set_rules('from_order', 'Lorder', 'integer'); $this->form_validation->set_rules('to_order', 'Lorder', 'integer'); $this->form_validation->set_rules('status', 'Status', 'integer'); } public function getValueOfDecisionStatus() { return [ 'from_order' => trim($this->input->get('from_order')), 'to_order' => trim($this->input->get('to_order')), 'description' => trim($this->input->get('description')), 'personalty' => trim($this->input->get('personalty')), 'key' => trim($this->input->get('key')), 'status' => trim($this->input->get('card_status') ?? ($this->input->get('status') ?? -1)), ]; } public function validateValueForDecisionStatus($params) { $this->load->library('form_validation'); $this->form_validation->set_data($params); $this->setFormRuleForDecisionStatus(); $errors = []; if ($this->form_validation->run() === FALSE) { $errors = $this->form_validation->error_array(); } return $errors; } public function grabpricing(){ $where = 'true'; $form_data = $this->input->get(); $data = []; // travel date filter if (!empty($form_data['TravelDate'])) { $TravelDate = $form_data['TravelDate']; $data['final_date_range'] = $this->grabpricing_calc_date_range($TravelDate, $form_data['TravelDateVariance']); $travelDateFrom = $TravelDate . ' 00:00:00'; $travelDateTo = $TravelDate . ' 23:59:59'; $IntervalDays = ($form_data['TravelDateVariance']) . ' days'; $where .= sprintf(" AND (a.travel_date BETWEEN TIMESTAMP '%s' - INTERVAL '%s' and TIMESTAMP '%s' + INTERVAL '%s')", $travelDateFrom, $IntervalDays, $travelDateTo, $IntervalDays); } $TravelTime = $form_data['TravelTime'] ?? '00:00'; $TravelTimeVariance = $form_data['TravelTimeVariance'] ?? 0; // travel time filter if ($TravelTime !== '00:00' || ($TravelTime === '00:00' && $TravelTimeVariance > 0)) { $time_calc_field = "(date_part('hour',a.travel_date)::TEXT||':'||date_part('minute',a.travel_date)::TEXT)::TIME"; $IntervalTravelTimeVariance = $TravelTimeVariance . ' MINUTE'; $where .= sprintf(" AND ($time_calc_field BETWEEN '%s'::TIME - INTERVAL '%s' AND '%s'::TIME + INTERVAL '%s')", $TravelTime, $IntervalTravelTimeVariance, $TravelTime, $IntervalTravelTimeVariance); $data['final_time_range'] = $this->grabpricing_calc_time_range($TravelTime, $TravelTimeVariance); } //distance filter $distance_calc_field = 'ST_Distance(ST_SetSRID(ST_MakePoint(ls.longitude,ls.latitude), 4326)::geometry,ST_SetSRID(ST_MakePoint(le.longitude,le.latitude), 4326)::geography)'; if (!empty($form_data['TravelDistance'])) { $TravelDistance = $form_data['TravelDistance'] ?? 0; $TravelDistanceVariance = $form_data['TravelDistanceVariance'] ?? 0; $where .= sprintf(" AND ($distance_calc_field BETWEEN %f and %f)", $TravelDistance - $TravelDistanceVariance, $TravelDistance + $TravelDistanceVariance); }else{ $where .= ' AND '.$distance_calc_field.'>0'; } //save view model data $data['TravelDate'] = $form_data['TravelDate'] ?? ''; $data['TravelDateVariance'] = $form_data['TravelDateVariance'] ?? ''; $data['TravelTime'] = $TravelTime; $data['TravelTimeVariance'] = $form_data['TravelTimeVariance'] ?? ''; $data['TravelDistance'] = $form_data['TravelDistance'] ?? ''; $data['TravelDistanceVariance'] = $form_data['TravelDistanceVariance'] ?? ''; $mysql = 'SELECT a."id", round(a."cost", 2) as "cost", '.$distance_calc_field.' AS distance, a.travel_date, ls.address AS location_start, le.address AS location_end FROM quotes a, address ls, address le WHERE ls.id=a.location_start_id AND le.id=a.location_end_id AND transport_provider_id=3 and a."cost">0 AND '.$where.' ORDER BY a.id DESC'; // OLD LIMIT 500 //$mysql = " SELECT id,cost,distance,travel_date,location_start,location_end FROM sample_grab WHERE cost > 0 AND distance > 0 AND $where ORDER BY id DESC"; $this->load->library('table'); $this->table->set_template($this->template_small); //$query = $this->read_replica->query($mysql); // $this->table->set_heading(array('data' => 'RM', 'style' => 'width:50px'), 'Description', array('data' => 'WT', 'style' => 'width:50px'), array('data' => 'ACT', 'style' => 'width:50px')); //$data['grap_history'] = $this->table->generate($query); $tableData = $this->returnAdminTable( [ 'count_query' => $mysql, 'query' => $mysql, ], 'bkoreport/grabpricing/', [ 'per_page' => 20, 'reuse_query_string' => TRUE, 'uri_segment' => 3, ] ); $data['grap_history'] = $tableData['output_table']; $data['links'] = $tableData['links']; $this->renderAdminPage('view_grabpricing', $data); } private function grabpricing_calc_date_range($travel_date, $date_variance) { if($date_variance==0){ return ''; } $calc_date = \DateTime::createFromFormat('Y-m-d H:i:s', $travel_date . ' 00:00:00'); $hoursToAdd = $date_variance * 24; $intervalSub = new \DateInterval("PT{$hoursToAdd}H"); $intervalSub->invert = 1; $calc_date_from = clone $calc_date; $calc_date_to = clone $calc_date; $calc_date_from->add($intervalSub); $calc_date_to->add(new \DateInterval("PT{$hoursToAdd}H")); $rs = $calc_date_from->format('Y-m-d') . ' -> ' . $calc_date_to->format('Y-m-d'); return $rs; } private function grabpricing_calc_time_range($travel_time, $time_variance) { if($time_variance==0){ return ''; } $calc_date = \DateTime::createFromFormat('Y-m-d H:i:s', (new DateTime())->format('Y-m-d') . ' ' . $travel_time . ':00'); $intervalSub = new \DateInterval("PT{$time_variance}M"); $intervalSub->invert = 1; $calc_date_from = clone $calc_date; $calc_date_to = clone $calc_date; $calc_date_from->add($intervalSub); $calc_date_to->add(new \DateInterval("PT{$time_variance}M")); $final_time_range = $calc_date_from->format('H:i') . ' -> ' . $calc_date_to->format('H:i'); return $final_time_range; } /* savvy=> \d sample_grab Table "public.sample_grab" Column | Type | Collation | Nullable | Default -------------------------+-----------------------------+-----------+----------+--------- id | integer | | | transport_provider_id | integer | | | automation_id | integer | | | cost_raw | character varying(20) | | | cost | numeric | | | created | timestamp without time zone | | | completed | timestamp without time zone | | | member_id | integer | | | location_start_id | bigint | | | location_end_id | bigint | | | quote_group_id | integer | | | prefill | boolean | | | pool | smallint | | | travel_date | timestamp with time zone | | | location_start | character varying(200) | | | location_start_lat | numeric | | | location_start_lng | numeric | | | location_start_tz | integer | | | location_geocoding_date | date | | | location_end | character varying(200) | | | location_end_lat | numeric | | | location_end_lng | numeric | | | */ public function decisionstatus() { $this->load->model('bko_report_model'); $this->load->library('table'); $this->table->set_template($this->template_small); $this->table->set_heading( array('data' => 'ID', 'style' => 'width:50px'), array('data' => 'Order', 'style' => 'width:40px'), 'Description', array('data' => 'V', 'style' => 'width:10px'), array('data' => 'Key', 'style' => 'width:40px'), array('data' => 'Next', 'style' => 'width:40px'), array('data' => 'Status', 'style' => 'width:40px'), array('data' => 'Action', 'style' => 'width:40px') ); $this->table->set_heading([ 'ID', 'Order', 'Description', 'V', 'Key', 'Next', 'Status', 'Action' ]); $params = $this->getValueOfDecisionStatus(); $data = $this->setComboForDecisionStatus($params); $params['status'] = $this->getValueCombo($params['status']); $params = array_filter($params, function($ele) { return $ele !== ""; }); $errors = $this->validateValueForDecisionStatus($params); $params = array_diff_key($params, $errors); $data = array_merge( $data, $params, $this->load_pagination( count($this->bko_report_model->get_decision_status_records($params)), $params, 'decisionstatus' ) ); $data['decision_group'] = $this->table->generate( $this->bko_report_model->get_decision_status_records( $params, $data['limit'], $data['offset'] ) ); $this->renderAdminPage('r-engine/view_recomendation', $data); } public function configuredecision() { $data = array(); $this->load->library('table'); $this->table->set_template($this->template); $decision_id = (int) $this->input->get('decision_id'); $id = (int) $this->input->get('id'); $proc = $this->input->get('proc'); $mysql = "SELECT * FROM decision_group WHERE id = $decision_id"; $query = $this->read_replica->query($mysql); $row = $query->row(); if (isset($row)) { $data["decision_group_title"] = $row->dkey; $data["decision_group_desc"] = $row->description; } // savvy=> ; // id | lorder | description | dkey | status // ----+--------+---------------------+---------+-------- // 5 | 99 | Bike/Scooters Lover | A300006 | 0 // (1 row) $mysql = "SELECT id,description, '' AS Cards FROM decision_logic"; $mysql .= " WHERE id NOT IN (SELECT decision_logic FROM group_decision_logic WHERE group_id=$decision_id AND status=1) "; $mysql .= " ORDER BY id DESC"; $query = $this->read_replica->query($mysql); $this->table->set_heading(array('data' => 'ID', 'style' => 'width:10px'), 'Description', array('data' => 'ADD', 'style' => 'width:50px')); $data['logic_list'] = $this->table->generate($query); // $this->load->library('table'); // $this->table->set_template($this->template); $mysql = "SELECT '' AS Cards, l.description AS desc,'' AS weight, '' as updt FROM group_decision_logic g LEFT JOIN decision_logic l ON l.id =g.decision_logic WHERE g.group_id=" . $decision_id . " AND g.status=1"; $mysql .= " ORDER BY l.id DESC"; $query = $this->read_replica->query($mysql); $this->table->set_heading(array('data' => 'RM', 'style' => 'width:50px'), 'Description', array('data' => 'WT', 'style' => 'width:50px'), array('data' => 'ACT', 'style' => 'width:50px')); $data['group_logic_list'] = $this->table->generate($query); $data["card_category"] = ""; $data["decision_id"] = $decision_id; /* * we have to send survey cards */ $this->load->model('combo_model'); $data["survey_list"] = $this->combo_model->getSurvelListGroupCombo("survey_list", ""); $data["location_list"] = $this->combo_model->getGPSTriggerLocationCombo("gps_location_list", ""); $this->load->view('admin/r-engine/view_recomendation_logic', $data); return 0; } public function decisioncard() { $data = array(); $this->load->library('table'); $this->table->set_template($this->template); $decision_id = (int) $this->input->get('decision_id'); $id = (int) $this->input->get('id'); $proc = $this->input->get('proc'); if ($proc == 'ADD') { if ($decision_id > 0 && $id > 0) { $q = "INSERT INTO decision_cards (decision_id,card_id) VALUES($decision_id,$id) RETURNING id"; $r = $this->db->query($q); $f = $r->result_array()[0]; if ($f["id"] > 0) { echo $f["id"]; } else { echo "Failed to add card!"; } } else { echo "Invalid decision and/or card ID"; } } else if ($proc == 'DEL') { if ($decision_id > 0 && $id > 0) { $q = "UPDATE decision_cards SET status=0 WHERE id=${id} AND decision_id=${decision_id} RETURNING status,card_id"; $r = $this->db->query($q); $f = $r->result_array()[0]; if ($f['card_id'] > 0 && $f['status'] == 0) { echo $f['card_id']; } else { echo "Failed to remove card!"; var_dump($f); } } else { echo "Invalid decision and/or card ID"; } } else { //echo '

'.$decision_id.'

'; $q = "SELECT dkey,description FROM decision_group WHERE id=${decision_id}"; $r = $this->read_replica->query($q); $f = $r->result_array()[0]; $data["decision_group_title"] = $f["dkey"] . " " . $f["description"]; $this->load->model('combo_model'); $data['card_category_vaue'] = trim($this->input->get('card_category')); $data['card_category'] = $this->combo_model->getCardCategoryCombo('card_category', $data['card_category_vaue'],'','CARDDYNAMIC'); $data['decision_id'] = $decision_id; $mysql = "SELECT ''||name||'
'||id||' - '|| title ,'' AS Addcard FROM main_cards "; $mysql .= " WHERE status=1 AND deleted IS NULL AND id NOT IN (SELECT card_id FROM decision_cards WHERE decision_id=$decision_id AND status =1) AND button1_action NOT IN ('CARDDYNAMIC')"; if ($data['card_category_vaue'] != '' && $data['card_category_vaue'] != '0') { $mysql .= " AND button1_action='" . pg_escape_string($data['card_category_vaue']) . "'"; } $mysql .= " ORDER BY id DESC"; $query = $this->read_replica->query($mysql); $this->table->set_heading("Card Title", array('data' => 'Action', 'style' => 'width:90px')); $data["card_list"] = $this->table->generate($query); $mysql = "SELECT '' AS SelCard, c.name as CardId, c.card_order FROM decision_cards d LEFT JOIN main_cards c ON c.id=d.card_id WHERE d.decision_id=$decision_id AND d.status=1 "; if ($data['card_category_vaue'] != '' && $data['card_category_vaue'] != '0') { $mysql .= " AND c.button1_action='" . pg_escape_string($data['card_category_vaue']) . "'"; } $mysql .= " ORDER BY c.card_order ASC"; $query = $this->read_replica->query($mysql); $this->table->set_heading(array('data' => 'Remove', 'style' => 'width:90px'), "Card ID", "Card Order"); $data["sel_list"] = $this->table->generate($query); $this->load->view('admin/r-engine/view_recomendation_card', $data); } } public function validateValue($params) { $this->load->library('form_validation'); $this->form_validation->set_data($params); $this->setFormRuleForLoginReportForm(); $errors = []; if ($this->form_validation->run() === FALSE) { $errors = $this->form_validation->error_array(); } return $errors; } public function setFormRuleForLoginReportForm() { $date_pattern = 'regex_match[/\d{4}-\d{2}-\d{2}/]'; $this->form_validation->set_rules( 'member_id', 'Member ID', 'numeric' ); $this->form_validation->set_rules( 'from_updated', 'Updated date', $date_pattern ); $this->form_validation->set_rules( 'to_updated', 'Updated date', $date_pattern ); $this->form_validation->set_rules( 'from_created', 'Created date', $date_pattern ); $this->form_validation->set_rules( 'to_created', 'Created date', $date_pattern ); } public function getValueOfLoginReportForm() { return [ 'username' => trim($this->input->get('username') ?? ''), 'member_id' => trim($this->input->get('member_id') ?? ''), 'from_updated' => trim($this->input->get('from_updated') ?? ''), 'to_updated' => trim($this->input->get('to_updated') ?? ''), 'from_created' => trim($this->input->get('from_created') ?? ''), 'to_created' => trim($this->input->get('to_created') ?? ''), 'loc' => trim($this->input->get('loc') ?? ''), ]; } public function setOnePastMonthForLoginReport($params) { if (empty($params['from_updated']) && empty($params['to_updated'])) { $params['from_updated'] = date("Y-m-d", strtotime("-1 months")); $params['to_updated'] = date("Y-m-d"); } return $params; } public function loginreport() { $this->load->model('login_report_model'); $this->load->library('table'); $this->table->set_template($this->template); $data["page_title"] = "Pass Reset Report"; $this->table->set_heading([ 'ID', 'Username', 'Member ID', 'Created', 'Updated', 'Loc', 'Shop' ]); $params = $this->getValueOfLoginReportForm(); $params = $this->setOnePastMonthForLoginReport($params); $params = array_filter($params, function($ele) { return $ele !== ""; }); $errors = $this->validateValue($params); $params = array_diff_key($params, $errors); $data = array_merge( $data, $params, $this->load_pagination( count($this->login_report_model->get_login_report_records($params)), $params, 'loginreport' ) ); $data['login_table'] = $this->table->generate( $this->login_report_model->get_login_report_records( $params, $data['limit'], $data['offset'] ) ); $this->renderAdminPage('view_loginreport', $data); } public function load_pagination( $count_record, $params, $action, $limit = 10 ) { // pagination $this->load->library('pagination'); $config["total_rows"] = $count_record; $config["base_url"] = base_url() . "/Bkoreport/" . $action; $config["per_page"] = $limit; $config["uri_segment"] = 3; $config["num_links"] = 5; $config["suffix"] = '?' . http_build_query($params); $config["first_url"] = "/bkoreport/{$action}/0?" . http_build_query($params); $config['full_tag_open'] = ""; $config['num_tag_open'] = '
  • '; $config['num_tag_close'] = '
  • '; $config['cur_tag_open'] = "
  • "; $config['cur_tag_close'] = "
  • "; $config['next_tag_open'] = "
  • "; $config['next_tagl_close'] = "
  • "; $config['prev_tag_open'] = "
  • "; $config['prev_tagl_close'] = "
  • "; $config['first_tag_open'] = "
  • "; $config['first_tagl_close'] = "
  • "; $config['last_tag_open'] = "
  • "; $config['last_tagl_close'] = "
  • "; $this->pagination->initialize($config); $page = ( $this->uri->segment(3) ) ? $this->uri->segment(3) : 0; $offset = is_numeric($page) ? $page : 0; return [ 'link' => $this->pagination->create_links(), 'offset' => $offset, 'limit' => $config["per_page"] ]; } public function setValueCombo($val) { $status_value = range(0, 9); return in_array($val, $status_value) ? $val : ''; } public function setComboForResetReport($params) { $this->load->model('combo_model'); $combo['card_status'] = $this->combo_model->getStatusComboFromZeroToNine( 'card_status', $params['status'] ); return $combo; } public function setFormRuleForResetReportForm() { $status_pattern = 'regex_match[/^(?:[0-9])$/]'; $date_pattern = 'regex_match[/\d{4}-\d{2}-\d{2}/]'; $this->form_validation->set_rules('member_id', 'Member ID', 'numeric'); $this->form_validation->set_rules('from_date', 'Created date', $date_pattern); $this->form_validation->set_rules('to_date', 'Created date', $date_pattern); $this->form_validation->set_rules('status', 'Status', $status_pattern); } public function getValueOfResetReportForm() { return [ 'username' => trim($this->input->get('username') ?? ''), 'member_id' => trim($this->input->get('member_id') ?? ''), 'from_date' => trim($this->input->get('from_date') ?? ''), 'to_date' => trim($this->input->get('to_date') ?? ''), 'loc' => trim($this->input->get('loc') ?? ''), 'status' => trim($this->input->get('card_status') ?? ($this->input->get('status') ?? -1)), ]; } public function setOnePastMonthForResetReport($params) { if (empty($params['from_date']) && empty($params['to_date'])) { $params['from_date'] = date("Y-m-d", strtotime("-1 months")); $params['to_date'] = date("Y-m-d"); } return $params; } public function resetreport() { $this->load->model('resetpassword_model'); $this->load->library('table'); $this->table->set_template($this->template); $data["page_title"] = "Pass Reset Report"; $this->table->set_heading([ 'ID', 'Username', 'Member ID', 'Reset Bin', 'Reset Key', 'Created', 'Expired', 'Status', 'Loc', 'Trail Count', ]); $params = $this->getValueOfResetReportForm(); $params = $this->setOnePastMonthForResetReport($params); $data = $this->setComboForResetReport($params); $params['status'] = $this->setValueCombo($params['status']); $params = array_filter($params, function($ele) { return $ele !== ""; }); $errors = $this->validateValue($params); $params = array_diff_key($params, $errors); $data = array_merge( $data, $params, $this->load_pagination( count($this->resetpassword_model->get_resetpassword_records($params)), $params, 'resetreport' ) ); $data['reset_table'] = $this->table->generate( $this->resetpassword_model->get_resetpassword_records( $params, $data['limit'], $data['offset'] ) ); $this->renderAdminPage('view_resetpass', $data); } public function decisionlogic() { $data = array(); $this->load->library('table'); $this->table->set_template($this->template); $decision_id = (int) $this->input->get('decision_id'); $id = (int) $this->input->get('id'); $proc = $this->input->get('proc'); if ($proc == 'ADD') { if ($decision_id > 0 && $id > 0) { $q = "INSERT INTO group_decision_logic (group_id,decision_logic) VALUES($decision_id,$id) RETURNING id"; $r = $this->db->query($q); $f = $r->result_array()[0]; if ($f["id"] > 0) { echo $f["id"]; } else { echo "Failed to add logic!"; } } else { echo "Invalid decision and/or logic ID"; } } else if ($proc == 'DEL') { if ($decision_id > 0 && $id > 0) { $q = "UPDATE group_decision_logic SET status=0 WHERE id=${id} AND group_id=${decision_id} RETURNING status,decision_logic"; $r = $this->db->query($q); $f = $r->result_array()[0]; if ($f['decision_logic'] > 0 && $f['status'] == 0) { echo $f['decision_logic']; } else { echo "Failed to remove logic!"; var_dump($f); } } else { echo "Invalid decision and/or logic ID"; } } else { //echo '

    '.$decision_id.'

    '; $q = "SELECT dkey,description FROM decision_group WHERE id=${decision_id}"; $r = $this->read_replica->query($q); $f = $r->result_array()[0]; $data["decision_group_title"] = $f["dkey"] . " " . $f["description"]; $data['decision_id'] = $decision_id; $mysql = "SELECT id,description, '' AS Cards FROM decision_logic"; $mysql .= " WHERE id NOT IN (SELECT decision_logic FROM group_decision_logic WHERE group_id=$decision_id AND status=1) "; $mysql .= " ORDER BY id DESC"; $query = $this->read_replica->query($mysql); $this->table->set_heading(array('data' => 'ID', 'style' => 'width:10px'), 'Description', array('data' => 'ADD', 'style' => 'width:50px')); $data['logic_list'] = $this->table->generate($query); // $this->load->library('table'); // $this->table->set_template($this->template); $mysql = "SELECT '' AS Cards, g.id, l.description AS desc FROM group_decision_logic g LEFT JOIN decision_logic l ON l.id =g.decision_logic WHERE g.group_id=" . $decision_id . " AND g.status=1"; $mysql .= " ORDER BY l.id DESC"; $query = $this->read_replica->query($mysql); $this->table->set_heading(array('data' => 'RM', 'style' => 'width:50px'), array('data' => 'ID', 'style' => 'width:10px'), 'Description'); $data['group_logic_list'] = $this->table->generate($query); $this->load->view('admin/r-engine/view_recomendation_logic', $data); } } public function devices() { $this->load->helper('url'); $data = array(); $this->load->library('table'); $this->table->set_template($this->template); $mysql = "select a.*,case when platform='' then 'Unknown' else b.platform end as platform from (select platform_id,count(*) as count from members_devices group by platform_id) as a left join members_device_platforms b on (b.id=a.platform_id) order by a.count desc"; $query = $this->read_replica->query($mysql); //$this->table->set_heading( array('data' => 'ID', 'style' => 'width:50px'),'Email', 'Firstname', 'Lastname','Last Login','Location', array('data' => 'ACTION', 'style' => 'width:40px'), array('data' => 'Select', 'style' => 'width:40px')); $data['device_platforms'] = $this->table->generate($query); list($data['device_platforms_labels'], $data['device_platforms_values']) = $this->getDevicePie($mysql); $mysql = "select a.*,case when model='' then 'Unknown' else b.model end as model from (select model_id,count(*) as count from members_devices group by model_id) as a left join members_device_models b on (b.id=a.model_id) order by a.count desc"; $query = $this->read_replica->query($mysql); //$this->table->set_heading( array('data' => 'ID', 'style' => 'width:50px'),'Email', 'Firstname', 'Lastname','Last Login','Location', array('data' => 'ACTION', 'style' => 'width:40px'), array('data' => 'Select', 'style' => 'width:40px')); $data['device_models'] = $this->table->generate($query); list($data['device_models_labels'], $data['device_models_values']) = $this->getDevicePie($mysql); $mysql = "select a.*,case when manufacturer='' then 'Unknown' else b.manufacturer end as manufacturer from (select manufacturer_id,count(*) as count from members_devices group by manufacturer_id) as a left join members_device_manufacturers b on (b.id=a.manufacturer_id) order by a.count desc"; $query = $this->read_replica->query($mysql); //$this->table->set_heading( array('data' => 'ID', 'style' => 'width:50px'),'Email', 'Firstname', 'Lastname','Last Login','Location', array('data' => 'ACTION', 'style' => 'width:40px'), array('data' => 'Select', 'style' => 'width:40px')); $data['device_manufacturers'] = $this->table->generate($query); list($data['device_manufacturers_labels'], $data['device_manufacturers_values']) = $this->getDevicePie($mysql); $this->renderAdminPage('report/view_report_devices', $data); // echo 'Ameye Olu'; } private function getDevicePie($mysql) { $labels = []; $values = []; $query = $this->read_replica->query($mysql); foreach ($query->result() as $row) { $record = array_values((array) $row); $labels[] = $record[2]; $values[] = $record[1]; } return [$labels, $values]; } public function trips() { $this->load->helper('url'); $data = array(); $this->load->library('table'); $this->table->set_template($this->template); $mysql = "SELECT b.id,a.count,CASE WHEN name IS NULL THEN 'Unknown' ELSE b.name END AS name FROM (SELECT transport_provider_id,count(*) AS count,sum(cost) AS cost FROM parsedemail_item GROUP BY transport_provider_id) AS a LEFT JOIN transport_providers b ON (b.id=a.transport_provider_id) ORDER by a.count DESC"; $query = $this->read_replica->query($mysql); //$this->table->set_heading( array('data' => 'ID', 'style' => 'width:50px'),'Email', 'Firstname', 'Lastname','Last Login','Location', array('data' => 'ACTION', 'style' => 'width:40px'), array('data' => 'Select', 'style' => 'width:40px')); $data['vendor_count'] = $this->table->generate($query); list($data['vendor_count_labels'], $data['vendor_count_values']) = $this->getDevicePie($mysql); $mysql = "SELECT b.id,a.cost,CASE WHEN name IS NULL THEN 'Unknown' ELSE b.name END AS name FROM (SELECT transport_provider_id,count(*) AS count,sum(cost) AS cost FROM parsedemail_item GROUP BY transport_provider_id) AS a LEFT JOIN transport_providers b ON (b.id=a.transport_provider_id) ORDER by a.count DESC"; $query = $this->read_replica->query($mysql); //$this->table->set_heading( array('data' => 'ID', 'style' => 'width:50px'),'Email', 'Firstname', 'Lastname','Last Login','Location', array('data' => 'ACTION', 'style' => 'width:40px'), array('data' => 'Select', 'style' => 'width:40px')); $data['vendor_cost'] = $this->table->generate($query); list($data['vendor_cost_labels'], $data['vendor_cost_values']) = $this->getDevicePie($mysql); $mysql = "SELECT c.transport_provider_id AS id,count(*) AS count,d.name FROM (SELECT a.transport_provider_id,b.member_id,count(*) AS count FROM parsedemail_item a, trackedemail_item b WHERE b.id=a.trackedemail_item_id GROUP BY a.transport_provider_id,b.member_id) AS c LEFT JOIN transport_providers d ON (d.id=c.transport_provider_id) GROUP BY c.transport_provider_id,d.name ORDER BY count(*) DESC"; $query = $this->read_replica->query($mysql); //$this->table->set_heading( array('data' => 'ID', 'style' => 'width:50px'),'Email', 'Firstname', 'Lastname','Last Login','Location', array('data' => 'ACTION', 'style' => 'width:40px'), array('data' => 'Select', 'style' => 'width:40px')); $data['vendor_members'] = $this->table->generate($query); list($data['vendor_members_labels'], $data['vendor_members_values']) = $this->getDevicePie($mysql); $this->renderAdminPage('report/view_report_trips', $data); // echo 'Ameye Olu'; } public function oauth2pulls() { $this->load->library('table'); $this->table->set_template($this->template); $member_id = (int) $this->input->get('member_id'); $oauth2_token_id = (int) $this->input->get('oauth2_token_id'); $params = $this->getOauth2PullsValue(); $params['oauth2_pulls_params'] = array_filter($params['oauth2_pulls_params']); $errors = $this->validateForOauth2Pulls($params['oauth2_pulls_params']); $data = $params; $condition_query = $this->generateWhereConditionForOauth2Pulls($params['oauth2_pulls_params'], $errors); $oauth2_provider_id = 1; // gmail $mysql = " SELECT count(tmp.email) AS all_count FROM ( SELECT e.email, d.member_id, d.last_run, round(((extract(epoch from now())-extract(epoch from d.last_run))/3600)::numeric,2) AS elapsed, d.oauth2_token_id FROM ( SELECT a.id AS member_id, ( SELECT max(b.created) FROM oauth2_pull_jobs b WHERE b.member_id=a.id AND b.created IS NOT NULL ) AS last_run, ( SELECT c.id FROM oauth2_tokens c WHERE c.member_id=a.id AND c.oauth2_provider_id=${oauth2_provider_id} ORDER BY c.updated DESC LIMIT 1 ) AS oauth2_token_id FROM members a WHERE a.id>0 ) AS d, members e WHERE d.oauth2_token_id>0 AND e.id=d.member_id ) tmp "; $mysql .= $condition_query; $query = $this->read_replica->query($mysql); // pagination $this->load->library('pagination'); $config["total_rows"] = $query->result_array()[0]['all_count']; $config["base_url"] = base_url() . "/bkoreport/oauth2pulls"; $config["suffix"] = '?' . http_build_query($params['oauth2_pulls_params']); $config["first_url"] = '/bkoreport/oauth2pulls/0?' . http_build_query($params['oauth2_pulls_params']); $config["per_page"] = 10; $config["uri_segment"] = 3; $config["num_links"] = 5; $config['full_tag_open'] = ""; $config['num_tag_open'] = '
  • '; $config['num_tag_close'] = '
  • '; $config['cur_tag_open'] = "
  • "; $config['cur_tag_close'] = "
  • "; $config['next_tag_open'] = "
  • "; $config['next_tagl_close'] = "
  • "; $config['prev_tag_open'] = "
  • "; $config['prev_tagl_close'] = "
  • "; $config['first_tag_open'] = "
  • "; $config['first_tagl_close'] = "
  • "; $config['last_tag_open'] = "
  • "; $config['last_tagl_close'] = "
  • "; $this->pagination->initialize($config); $page = ( $this->uri->segment(3) ) ? $this->uri->segment(3) : 0; $page = is_numeric($page) ? $page : 0; // pagination $mysql = "SELECT '' AS Member, '' AS View, CONCAT(firstname,' ',lastname,' (',CASE WHEN email='' THEN username ELSE email END,')') AS name, member_id, last_run, round(((extract(epoch from now())-extract(epoch from last_run))/3600)::numeric,2) AS elapsed, oauth2_token_id FROM ( SELECT e.email, e.firstname, e.lastname, e.username, d.member_id, d.last_run, round(((extract(epoch from now())-extract(epoch from d.last_run))/3600)::numeric,2) AS elapsed, d.oauth2_token_id FROM ( SELECT a.id AS member_id, ( SELECT max(b.created) FROM oauth2_pull_jobs b WHERE b.member_id=a.id AND b.created IS NOT NULL ) AS last_run, ( SELECT c.id FROM oauth2_tokens c WHERE c.member_id=a.id AND c.oauth2_provider_id=${oauth2_provider_id} ORDER BY c.updated DESC LIMIT 1 ) AS oauth2_token_id FROM members a WHERE a.id>0 ) AS d, members e WHERE d.oauth2_token_id>0 AND e.id=d.member_id ) tmp " . $condition_query . "ORDER BY last_run LIMIT " . $config["per_page"] . " OFFSET " . $page . " "; $query = $this->read_replica->query($mysql); //$this->table->set_heading( array('data' => 'ID', 'style' => 'width:50px'),'Email', 'Firstname', 'Lastname','Last Login','Location', array('data' => 'ACTION', 'style' => 'width:40px'), array('data' => 'Select', 'style' => 'width:40px')); $data['oauth2_pulls'] = $this->table->generate($query); $data["oauth2_pulls_links"] = $this->pagination->create_links(); if ($member_id < 1) { $query = $this->read_replica->query($mysql); $rows = $query->result(); if ($rows && count($rows) > 0) { $record = array_values((array) $rows[0]); $member_id = $record[0]; $oauth2_token_id = $record[3]; } } if ($member_id > 0 && $oauth2_token_id > 0) { $q = "SELECT CONCAT(firstname,' ',lastname,' (',CASE WHEN email='' THEN username ELSE email END,')') AS member FROM members WHERE id=${member_id}"; $r = $this->read_replica->query($q); $data["member"] = $r->row_array(); $q = "SELECT round(extract(epoch from completed)::numeric-extract(epoch from started)::numeric,2) as duration,item_count,CONCAT(search_term,' ',search_from) AS vendor FROM oauth2_pull_job_threads WHERE oauth2_pull_job_id=(SELECT id FROM oauth2_pull_jobs WHERE member_id=${member_id} AND oauth2_token_id=${oauth2_token_id} AND completed IS NOT NULL ORDER BY completed DESC limit 1)"; $r = $this->read_replica->query($q); $data['oauth2_threads'] = $this->table->generate($r); list($data['oauth2_threads_duration_labels'], $data['oauth2_threads_duration_values']) = $this->getPullPie($q, 2, 0); list($data['oauth2_threads_count_labels'], $data['oauth2_threads_count_values']) = $this->getPullPie($q, 2, 1); } $data['member_id'] = $member_id; $this->renderAdminPage('report/view_report_pulls', $data); } private function getPullPie($mysql, $i, $j) { $labels = []; $values = []; $query = $this->read_replica->query($mysql); foreach ($query->result() as $row) { $record = array_values((array) $row); $labels[] = $record[$i]; $values[] = $record[$j]; } return [$labels, $values]; } public function addresssearch() { $response = []; $search = $this->input->post('search'); if (strlen($search) > 3) { $q = "SELECT * FROM address WHERE lower(address) LIKE '%" . pg_escape_string(strtolower($search)) . "%'"; $r = $this->read_replica->query($q); foreach ($r->result() as $row) { $response[] = array("value" => $row->id, "label" => $row->address); } } echo json_encode($response); } public function cards_clicked_report(){ $this->load->model('combo_model'); // POST data $data['report'] = []; $data['card_category'] = $this->combo_model->getCardCategoryCombo('card_category', ''); $this->renderAdminPage('report/view_report_cards_clicked_report', $data); } public function cards_clicked_report_datatables(){ $data = $this->get_biz_report_data($this->input->post(),'search'); header('Content-Type: application/json'); echo json_encode( $data ); } public function cards_clicked_report_export_csv(){ $this->load->library('session'); $postData = $this->session->userdata("BIZ_PARAM"); if($postData){ $this->get_biz_report_data($postData,'export_csv'); }else{ echo 'not found!'; } } /** * Report list signup email * @return mixed */ public function signup_email_report( $data = array() ) { $this->load->helper('url'); $params = $this->input->get(); $subject = 'Float - How it Works'; $sql = sprintf(" SELECT count(e), e.created_at::date as Day from emails e where subject like '%s' ", $subject ); if ( isset( $params['startdate'] ) and isset( $params['enddate'] ) ) { $sql .= sprintf("and e.created_at between '%s' and '%s'", $params['startdate'], $params['enddate']); } else { $sql .= sprintf("and e.created_at >= date_trunc('month', CURRENT_DATE - interval '1' month)"); } // group and order $sql .= sprintf("group by Day order by Day desc"); $results = $this->read_replica->query( $sql )->result_array(); // $reports = array(); // if ( $results ) { // foreach ( $results as $value => $result ) { // $email = explode( ',', preg_replace( '/.*?(\{)|(\})/m', '', $result['email'] ) ); // $reports[ $result['day'] ]['email'][] = $email; // } // } $data['signup_emails'] = $results; $this->renderAdminPage('report/view_signup_emails', $data); } /** * Signup Email - view details by date * @return json */ public function signup_email_report_details() { $payload = $this->input->get(); $page = $payload['page'] ?? $this->uri->segment(3); $limit = 20; $sql = sprintf(" SELECT row_number() OVER () as no, to_emails as email from emails where created_at::date = '%s' ", $payload['date']); $results = $this->read_replica->query( $sql )->result_array(); // load table $this->load->library( 'table' ); $this->table->set_template( $this->template ); $this->table->set_heading([ 'No.', 'Email' ]); $link = $this->load_pagination( count( $results ), array( 'date' => $payload['date'] ), 'signup_email_report_details', $limit ); $sql .= sprintf("limit %d offset %d", $limit, (int) $page); $results = $this->read_replica->query( $sql )->result_array(); // remove {} character $content = array(); array_map( function($var) use (&$content) { $var['email'] = preg_replace( '/.*?(\{)|(\})/m', '', $var['email'] ); array_push( $content, array( 'no' => $var['no'], 'email' => $var['email'] ) ); }, $results ); $content = $this->table->generate( $content ); header( 'Content-Type: application/json' ); echo json_encode( array( 'pagination' => $link, 'results' => $content ) ); } public function get_biz_report_data($postData, $mode = 'search'){ $this->load->library('session'); $this->session->set_userdata("BIZ_PARAM", $postData); ## Read value $from = DateTime::createFromFormat('m/d/Y', '1/1/1970'); $to = (new DateTime()); $date_range = $postData['date_range']??''; if(!empty($date_range)){ $date_range_part = array_map('trim',explode('-',$date_range)); $from = DateTime::createFromFormat('m/d/Y', $date_range_part[0]); $to = DateTime::createFromFormat('m/d/Y', $date_range_part[1]); } $draw = $postData['draw']??0; $start = $postData['start']; $rowperpage = $postData['length']; // Rows display per page $columnIndex = $postData['order'][0]['column']??0; // Column index $columnName = $postData['columns'][$columnIndex]['data']??''; // Column name $columnSortOrder = $postData['order'][0]['dir']; // asc or desc $order_by = " ORDER BY $columnName $columnSortOrder"; $searchValue = $postData['search']['value']??''; // Search value # where $where = "date(m.added) >='".$from->format('Y-m-d')."' and date(m.added)<='".$to->format('Y-m-d')."'"; if(!empty($postData['card_category'])){ $where.= " AND c.button1_action = '".pg_escape_string($postData['card_category'])."'"; } if(!empty($searchValue)){ $where.= " AND c.title like '%".pg_escape_string($searchValue)."%'"; } $limit = ''; if($mode == 'search'){ $limit = " LIMIT $rowperpage OFFSET $start"; } $mysql = "SELECT c.title, m.card_id, COUNT(m.card_id) AS cards_total FROM members_cardclicktrack m LEFT JOIN main_cards c ON c.id=m.card_id WHERE $where GROUP BY c.title,m.card_id $order_by $limit"; $data = []; ## Response if($mode == 'export_csv'){ $report = $this->read_replica->query($mysql); $this->biz_export_csv($report); exit; }else{ $report = $this->read_replica->query($mysql)->result_array(); } $mysql_count = "SELECT COUNT(grouped) as count from (SELECT COUNT(m.card_id) FROM members_cardclicktrack m LEFT JOIN main_cards c ON c.id=m.card_id WHERE $where GROUP BY c.title,m.card_id) as grouped"; $totalRecords = $this->read_replica->query($mysql_count)->row_array()['count']; $totalRecordwithFilter = $totalRecords; $response = array( "draw" => intval($draw), "iTotalRecords" => $totalRecords, "iTotalDisplayRecords" => $totalRecordwithFilter, "aaData" => $report ); return $response; } public function biz_export_csv($rs){ set_time_limit(0); header('Content-Type: application/vnd.ms-excel'); header('Content-Disposition: attachment;filename=cards-clicked-report-' . date("Y-m-d") . '.csv'); header('Cache-Control: max-age=0'); if (ob_get_contents()) ob_end_clean(); $fp = fopen('php://output', 'w'); $i = 0; while ($row = $rs->unbuffered_row()) { // header if ($i == 0) { fputcsv($fp, array_keys((array) $row)); } // records fputcsv($fp, (array) $row); $i++; } fclose($fp); exit; } public function totalquotes() { global $savvyext; $data = []; $data["days"] = 1; $data["result"] = [["ID", "Name", "Total", "Success", "Failure"]]; if ($this->input->post()) { $data["days"] = $this->input->post('days'); $httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token'); $api_url = "http://automation.float.sg"; $url = $api_url . "/api/statistics/" . ((int) $data["days"]); $ch = curl_init($url); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_VERBOSE, false); curl_setopt($ch, CURLOPT_HTTPHEADER, array( 'Content-Type: application/json', 'Authorization: Server-Token ' . $httpAuthToken) ); $body = curl_exec($ch); $data["result"] = array_merge($data["result"], json_decode($body, true)); } $this->load->library('table'); $this->table->set_template($this->template); $data["total_quotes_table"] = $this->table->generate($data["result"]); $this->renderAdminPage('report/view_report_totalquotes', $data); } public function quotes() { $data = []; $this->load->model('combo_model'); $data["autofrom"] = ""; $data["from"] = 0; $data["autoto"] = ""; $data["to"] = 0; $data["from_country"] = ""; $data["to_country"] = ""; $data["from_postal"] = ""; $data["to_postal"] = ""; if ($this->input->post()) { $data["autofrom"] = $this->input->post('autofrom'); $data["from"] = (int) $this->input->post('from'); $data["autoto"] = $this->input->post('autoto'); $data["to"] = (int) $this->input->post('to'); $data["from_country"] = $this->input->post('card_from_country'); $data["to_country"] = $this->input->post('card_to_country'); $data["from_postal"] = $this->input->post('from_postal'); $data["to_postal"] = $this->input->post('to_postal'); } $data["card_from_country"] = $this->combo_model->getCountryCombo("card_from_country", $data["from_country"]); $data["card_to_country"] = $this->combo_model->getCountryCombo("card_to_country", $data["to_country"]); $this->load->library('pagination'); $this->load->library('table'); $this->table->set_template($this->template); $q = " SELECT count(*) AS count FROM ( SELECT count(*), q.location_start_id, q.location_end_id FROM quotes q JOIN address location_start ON location_start.id = q.location_start_id JOIN address location_end ON location_end.id = q.location_end_id WHERE cost > 0 "; if ($data["from"] > 0) { $q .= " AND q.location_start_id = " . $data["from"]; } if ($data["to"] > 0) { $q .= " AND q.location_end_id = " . $data["to"]; } if ( ! empty($data["from_country"])) { $q .= " AND lower(location_start.country) = '" . strtolower(pg_escape_string($data["from_country"])) . "'"; } if ( ! empty($data["to_country"])) { $q .= " AND lower(location_end.country) = '" . strtolower(pg_escape_string($data["to_country"])) . "'"; } if ( ! empty($data["from_postal"])) { $q .= " AND location_start.postal LIKE '%" . pg_escape_string($data["from_postal"]) . "%'"; } if ( ! empty($data["to_postal"])) { $q .= " AND location_end.postal LIKE '%" . pg_escape_string($data["to_postal"]) . "%'"; } $q .= " GROUP BY q.location_start_id, q.location_end_id) AS a"; $r = $this->read_replica->query($q); $f = $r->result_array()[0]; $config = array(); $config["total_rows"] = $f["count"]; $config["base_url"] = base_url() . "/bkoreport/quotes"; $config["per_page"] = 50; $config["uri_segment"] = 3; $config["num_links"] = 5; $config['full_tag_open'] = ""; $config['num_tag_open'] = '
  • '; $config['num_tag_close'] = '
  • '; $config['cur_tag_open'] = "
  • "; $config['cur_tag_close'] = "
  • "; $config['next_tag_open'] = "
  • "; $config['next_tagl_close'] = "
  • "; $config['prev_tag_open'] = "
  • "; $config['prev_tagl_close'] = "
  • "; $config['first_tag_open'] = "
  • "; $config['first_tagl_close'] = "
  • "; $config['last_tag_open'] = "
  • "; $config['last_tagl_close'] = "
  • "; $this->pagination->initialize($config); $page = ( $this->uri->segment(3) ) ? $this->uri->segment(3) : 0; $page = is_numeric($page) ? $page : 0; //"SELECT count(*),location_start_id,location_end_id FROM quotes GROUP BY location_start_id,location_end_id;" $q = "SELECT count(*) AS \"Quotes\",'' AS \"View\","; $q .= " b.address AS \"Origin\", c.address AS \"Destination\", b.country AS \"Origin Country\", b.postal AS \"Origin Postal\","; $q .= " c.country AS \"Dest.Country\", c.postal AS \"Dest.Postal\""; $q .= " FROM quotes a "; $q .= " LEFT JOIN address b ON (b.id=a.location_start_id)"; $q .= " LEFT JOIN address c ON (c.id=a.location_end_id)"; $q .= " WHERE a.cost>0 "; if ($data["from"] > 0) { $q .= " AND a.location_start_id=" . $data["from"]; } if ($data["to"] > 0) { $q .= " AND a.location_end_id=" . $data["to"]; } if ( ! empty($data["from_country"])) { $q .= " AND lower(b.country) = '" . strtolower(pg_escape_string($data["from_country"])) . "'"; } if ( ! empty($data["to_country"])) { $q .= " AND lower(c.country) = '" . strtolower(pg_escape_string($data["to_country"])) . "'"; } if ( ! empty($data["from_postal"])) { $q .= " AND b.postal LIKE '%" . pg_escape_string($data["from_postal"]) . "%'"; } if ( ! empty($data["to_postal"])) { $q .= " AND c.postal LIKE '%" . pg_escape_string($data["to_postal"]) . "%'"; } $q .= " GROUP BY a.location_start_id,a.location_end_id,"; $q .= " b.address,b.country,b.postal,"; $q .= " c.address,c.country,c.postal "; $q .= " LIMIT " . $config["per_page"] . " OFFSET " . $page . " "; //echo ''; $r = $this->read_replica->query($q); $data["quotes_table"] = $this->table->generate($r); $data["links"] = $this->pagination->create_links(); $q = "SELECT id,address FROM address ORDER BY address"; $query = $this->read_replica->query($q); $address = []; $address[0] = '<<All>>'; foreach ($query->result() as $row) { $address[$row->{"id"}] = $row->{"address"} == '' ? 'Empty address' : $row->{"address"}; } $data["address"] = $address; $this->renderAdminPage('report/view_report_quotes', $data); } public function setFormRuleForQuote() { $this->form_validation->set_rules('transport_provider', 'Transport Provider', 'integer'); $this->form_validation->set_rules('from', 'from', 'integer'); $this->form_validation->set_rules('to', 'to', 'integer'); $this->form_validation->set_rules('prefill', 'Prefill', 'regex_match[/^(?:[0-1])$/]'); } public function getValueOfQuote() { return [ 'country' => trim($this->input->get('card_country') ?? $this->input->get('country')), 'transport_provider' => trim($this->input->get('card_transport_provider') ?? $this->input->get('transport_provider')), 'from' => trim($this->input->get('from')), 'address_from' => trim($this->input->get('address_from')), 'to' => trim($this->input->get('to')), 'address_to' => trim($this->input->get('address_to')), 'prefill' => trim($this->input->get('card_prefill') ?? $this->input->get('prefill')), 'quote' => trim($this->input->get('quote')), 'address_to' => trim($this->input->get('address_to')), 'export' => trim($this->input->get('export')), 'sql_raw' => trim($this->input->get('sql_raw')), 'message' => trim($this->input->get('message')), ]; } public function validateValueForQuote($params) { $this->load->library('form_validation'); $this->form_validation->set_data($params); $this->setFormRuleForQuote(); $errors = []; if ($this->form_validation->run() === FALSE) { $errors = $this->form_validation->error_array(); } return $errors; } public function setComboForQuote($params) { $this->load->model('combo_model'); $combo['card_country'] = $this ->combo_model ->getCountryCombo('card_country', $params['country']); $combo['card_transport_provider'] = $this ->combo_model ->getTransportProvidersCombo( 'card_transport_provider', $params['transport_provider'] ); $combo['card_prefill'] = $this ->combo_model ->getQuoteSourceCombo( 'card_prefill', $params['prefill'] ); return $combo; } public function quote() { $this->load->model('bko_report_model'); $this->load->library('table'); $this->table->set_template($this->template_small); $this->table->set_heading( 'Check Quote', 'Created', 'Completed', 'Travel Date', 'Cost Raw', 'Cost', 'Data Source', 'Transport Provider', 'Origin', 'Destination', 'Origin Country', 'Origin Postal' ); $params = $this->getValueOfQuote(); $data = $this->setComboForQuote($params); if (($params['quote']) !== '') { $params['message'] = $this->runQuote($params); } if (isset($params['address_from'])) { $params['location_start_id'] = $this->get_address($params['address_from']); } if (isset($params['address_to'])) { $params['location_end_id'] = $this->get_address($params['address_to']); } $params = array_filter($params, function($val) { return $val !== ""; }); $errors = $this->validateValueForQuote($params); $params = array_diff_key($params, $errors); $quote_records = $this->bko_report_model->count_quote_records($params); // remove from param url if (isset($params['location_start_id'])) { unset($params['location_start_id']); } if (isset($params['location_end_id'])) { unset($params['location_end_id']); } $data = array_merge( $data, $params, $this->load_pagination( $quote_records, $params, 'quote' ) ); $data['quotes_table'] = $this->table->generate( $this->bko_report_model->get_quote_records( $params, $data['limit'], $data['offset'] ) ); $this->renderAdminPage('report/view_report_quote', $data); } public function exportCSV() { $this->load->model('bko_report_model'); $this->load->helper('export_csv'); $params = $this->getValueOfQuote(); if ( ! empty($params['address_from'])) { $params['location_start_ids'] = $this->get_address($params['address_from']); } if ( ! empty($params['address_to'])) { $params['location_end_ids'] = $this->get_address($params['address_to']); } $params = array_filter($params, function($val, $key) { return $val !== "" || $key === 'message'; }, ARRAY_FILTER_USE_BOTH); $errors = $this->validateValueForQuote($params); $params = array_diff_key($params, $errors); $query = $this->bko_report_model->get_query_export_quote_records( $params ); $r = $this->read_replica->query($query); if ($r->result_array()[0]['all_count'] === '0') { $params['message'] = 'Data Not Found !!!'; redirect('/bkoreport/quote/?' . http_build_query($params) ); return; } $r = $this->read_replica->query( $this->bko_report_model->get_query_export_quote_records( $params, self::NONE_COUNT_RECORD ) ); export($r); } public function checkQuote() { $id = (int) $this->input->get('id'); if ($id < 1) { echo "Invalid ID"; return; } $q = "SELECT * FROM quotes WHERE id=" . $id; $r = $this->read_replica->query($q); if ($r->num_rows()) { // OK } else { echo "Quote not found"; return; } list($payload, $decrypted, $result, $body) = $this->main_api_get('/trips/api/quote/', $id); if (is_array($payload) && array_key_exists('id', $payload) && $payload['id'] > 0) { if (array_key_exists('cost', $payload) && $payload['cost'] > 0) { echo 'Quote is ' . sprintf("%0.02f", $payload['cost']); return; } if (array_key_exists('completed', $payload) && $payload['completed'] != '') { echo "
    ";
                    var_dump($payload);
                    echo "
    "; echo "Quote service check failed"; return; } } else { echo "Quote check failed"; return; } echo "N/A"; } protected function runQuote($data) { $message = 'Unhandled exception'; if ($data['country'] == '' || $data['transport_provider'] < 1 || $data['address_from'] == '' || $data['address_to'] == '') { return 'Invalid input'; } if ($data['country'] == 'SG') { if ($data['transport_provider'] < 4 || $data['transport_provider'] > 5) { return 'Unsupported transport provider'; } } else if ($data['country'] == 'US') { if ($data['transport_provider'] < 1 || $data['transport_provider'] > 2) { return 'Unsupported transport provider'; } } else { return 'Unsupported country'; } // Step 1: Geocode addresses $params = [ "address" => $data['address_from'], "member_id" => 0, "country" => $data['country'] ]; $input = http_build_query($params); list($payload, $decrypted, $result, $body) = $this->main_api_get('/trips/api/geocode/?', $input); if (!is_array($payload) || !array_key_exists('geocode', $payload) || !is_array($payload['geocode']) || !array_key_exists('id', $payload['geocode']) || $payload['geocode']['id'] < 1) { return 'Failed to geocode address from'; } $location_start = $payload['geocode']['address']; $location_start_id = $payload['geocode']['id']; $params["address"] = $data['address_to']; $input = http_build_query($params); list($payload, $decrypted, $result, $body) = $this->main_api_get('/trips/api/geocode/?', $input); if (!is_array($payload) || !array_key_exists('geocode', $payload) || !is_array($payload['geocode']) || !array_key_exists('id', $payload['geocode']) || $payload['geocode']['id'] < 1) { return 'Failed to geocode address to'; } $location_end = $payload['geocode']['address']; $location_end_id = $payload['geocode']['id']; // Step 2: Run quote $endpoint = '/trips/api/quote'; $payload = "{ \"origin\":\"" . $location_start . "\", \"destination\":\"" . $location_end . "\", \"member_id\":13, \"transport_provider_id\":" . $data['transport_provider'] . ", \"trackedemail_item_id\":0, \"country\":\"" . $data['country'] . "\", \"group_quote_id\":0, \"prefill\":\"t\" }"; list($payload, $decrypted, $result, $body) = $this->main_api_post($endpoint, $payload); if (is_array($payload) && array_key_exists('id', $payload) && $payload['id'] > 0) { if (array_key_exists('cost', $payload) && $payload['cost'] > 0) { return 'Quote is ' . $payload['cost']; } if (array_key_exists('completed', $payload) && $payload['completed'] != '') { return "Quote service failed"; } $startTime = time(); $sleeps = [1, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]; // 43 + 11 ~ 54 foreach ($sleeps as $sec) { sleep($sec); list($payload, $decrypted, $result, $body) = $this->main_api_get('/trips/api/quote/', $payload['id']); if (is_array($payload) && array_key_exists('id', $payload) && $payload['id'] > 0) { if (array_key_exists('cost', $payload) && $payload['cost'] > 0) { return 'Quote is ' . $payload['cost']; } if (array_key_exists('completed', $payload) && $payload['completed'] != '') { return "Quote service check failed"; } } else { return "Quote check failed"; } } $message = "Quote check timed out"; } else { $message = 'Failed to schedule quote'; } return $message; } protected function get_address($address) { $result = []; $q = "SELECT id FROM address WHERE address ILIKE '%" . pg_escape_string($address) . "%'"; $r = $this->read_replica->query($q); foreach ($r->result() as $row) { $result[] = $row->id; } return $result; } public function heatmap() { $q = "SELECT SUM(num) AS total, lat, lng FROM ( "; $q .= "SELECT COUNT(*) AS num, ROUND(b.latitude,2) AS lat, ROUND(b.longitude,2) AS lng FROM parsedemail_item a LEFT JOIN address b ON b.id=a.location_start_id WHERE b.timezone=1 AND a.private='f' AND a.updated>'2019-11-13 00:00' GROUP BY b.latitude, b.longitude "; $q .= " UNION "; $q .= "SELECT COUNT(*) AS num, ROUND(c.latitude,2) AS lat, ROUND(c.longitude,2) AS lng FROM parsedemail_item a LEFT JOIN address c ON c.id=a.location_end_id WHERE c.timezone=1 AND a.private='f' AND a.updated>'2019-11-13 00:00' GROUP BY c.latitude, c.longitude "; $q .= " ) AS foo GROUP BY foo.lat,foo.lng ORDER BY total DESC"; $r = $this->read_replica->query($q); foreach ($r->result() as $row) { $item = (array) $row; if ($item["lat"]==='' || $item["lng"]==='') continue; if ($item["lat"]==0 && $item["lng"]==0) continue; $top_locations[] = $item; } $data["top_locations"] = $top_locations; $data["center_lat"] = 1.351616; $data["center_lng"] = 103.808053; $data["googleKey"] = "AIzaSyDvjiRTxngOQyBP4zpqFlZuiquc0ROvo9c"; $this->renderAdminPage('report/view_report_heatmap', $data); } public function surgereport() { $data['page_title'] = "Surge Report"; $data['report_parsedemail'] = ''; $data['pagination_link'] = ''; $params = $this->input->get(); if (!empty($params)) { $this->form_validation->set_data($params); $this->setSurgereportSearchRules(); if ($this->form_validation->run() == false) { $this->renderAdminPage('report/view_report_parsedemail', $data); return; } } $this->load->model('parsedEmailItem_model'); $query = $this->parsedEmailItem_model->getSureReportQuery($params); $this->load->library('table'); $this->table->set_heading( ['data' => 'ID', 'style' => 'width:10px'], 'ID', 'Email', 'Travel Date', 'Duration', 'Cost Raw', 'Email ID', 'Cost', 'Update', 'Distance', 'Surge', 'Alternative', 'Insights' ); $tableData = $this->returnAdminTable( [ 'count_query' => $query, 'query' => $query, ], 'bkoreport/surgereport', [ 'per_page' => 100, 'reuse_query_string' => TRUE, ] ); $data['report_parsedemail'] = $tableData['output_table']; $data['pagination_link'] = $tableData['links']; $this->renderAdminPage('report/view_report_parsedemail', $data); } public function tripinsights() { global $savvyext; $data = []; $id = $this->input->get('id'); $member_id = $this->input->get('member_id'); $httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token'); $encryptionAlg = $savvyext->cfgReadChar('encryption.algorithm'); $encryptionKey = $savvyext->cfgReadChar('encryption.key'); $encryptionIV = $savvyext->cfgReadChar('encryption.iv'); $baseURL = $savvyext->cfgReadChar('system.api_url'); $payload = "{\"trackedemail_item_id\":9518790,\"member_id\":13}"; $payload = "{\"trackedemail_item_id\":${id},\"member_id\":${member_id}}"; $encrypted_payload = bin2hex( openssl_encrypt( $payload, $encryptionAlg, $encryptionKey, OPENSSL_RAW_DATA, $encryptionIV )); $postdata = "{\"encrypted_payload\": \"${encrypted_payload}\"}"; $url = $baseURL . "/trips/api/tripinsights"; $ch = curl_init($url); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_VERBOSE, false); curl_setopt($ch, CURLOPT_HTTPHEADER, array( 'Content-Type: application/json', 'Content-Length: ' . strlen($postdata), 'Authorization: Server-Token ' . $httpAuthToken, "client_id: BackOffice" ) ); $body = curl_exec($ch); $result = json_decode($body, true); $payload = openssl_decrypt( hex2bin( $result['payload'] ), $encryptionAlg, $encryptionKey, OPENSSL_RAW_DATA, $encryptionIV ); $data["payload"] = json_decode($payload, true); if ($this->input->is_ajax_request()) { $this->load->view('admin/report/view_report_trip_insights', $data); }else{ $this->renderAdminPage('report/view_report_trip_insights', $data); } } // oauth2 pulls public function validateForOauth2Pulls($params) { $this->load->library('form_validation'); $this->form_validation->set_data($params); $this->setFormRuleForOauth2Pulls(); $errors = []; if ($this->form_validation->run() === FALSE) { $errors = $this->form_validation->error_array(); } return $errors; } public function setFormRuleForOauth2Pulls() { // $date_pattern = 'regex_match[/([0-9]{1,2}\-\[0-9]{1,2}\-\[0-9]{4})?/]'; $date_pattern = 'regex_match[/\d{4}-\d{2}-\d{2}/]'; $this->form_validation->set_rules('from_last_run', 'Start Date', $date_pattern); $this->form_validation->set_rules('to_last_run', 'End Date', $date_pattern); $this->form_validation->set_rules('from_elapsed', 'Elapsed', 'numeric'); $this->form_validation->set_rules('to_elapsed', 'Elapsed', 'numeric'); $this->form_validation->set_rules('oauth2_token_id', 'Oauth2 Token ID', 'numeric'); $this->form_validation->set_rules('member_id', 'Member ID', 'numeric'); } public function getOauth2PullsValue() { return [ 'oauth2_pulls_params' => [ 'from_last_run' => $this->getValueOfParam('from_last_run'), 'to_last_run' => $this->getValueOfParam('to_last_run'), 'from_elapsed' => $this->getValueOfParam('from_elapsed'), 'to_elapsed' => $this->getValueOfParam('to_elapsed'), 'oauth2_token_id' => $this->getValueOfParam('oauth2_token_id'), 'member_id' => $this->getValueOfParam('member_id'), 'email' => $this->getValueOfParam('email'), ] ]; } public function getValueOfParam($param) { return trim(empty($this->input->post($param)) ? $this->input->get($param) : $this->input->post($param)); } public function generateWhereConditionForOauth2Pulls($params, $errors) { foreach($params as $key => $value) { if (array_key_exists($key, $errors)) { continue; } $key = strpos($key, 'last_run') !== FALSE ? "DATE(${key})" : $key; if (strpos($key, 'from_') !== FALSE) { $key = str_replace('from_', '', $key); $this->read_replica->where($key . '>=', $value); } else if (strpos($key, 'to_')!== FALSE) { $key = str_replace('to_', '', $key); $this->read_replica->where($key . '<=', $value); } else if (strpos($key, 'email')!== FALSE) { $this->read_replica->like('lower('. $key . ')', strtolower($value)); } else { $this->read_replica->where($key, $value); } } return str_replace('SELECT *', '', $this->read_replica->get_compiled_select()); } private function setSurgereportSearchRules() { $config = [ [ 'field' => 'travel_date', 'label' => 'Travel date', 'rules' => 'trim', ], [ 'field' => 'duration_from', 'label' => 'Duration from', 'rules' => 'trim|numeric', ], [ 'field' => 'duration_to', 'label' => 'Duration to', 'rules' => 'trim|numeric', ], [ 'field' => 'distance_from', 'label' => 'Distance from', 'rules' => 'trim|numeric', ], [ 'field' => 'distance_to', 'label' => 'Distance to', 'rules' => 'trim|numeric', ], [ 'field' => 'cost_from', 'label' => 'Cost from', 'rules' => 'trim|numeric', ], [ 'field' => 'cost_to', 'label' => 'Cost to', 'rules' => 'trim|numeric', ], [ 'field' => 'email', 'label' => 'Email', 'rules' => 'trim|valid_emails', ], ]; $this->form_validation->set_rules($config); } public function upload() { $this->load->helper('upload_file'); upload_file(); } public function importCSV() { $this->load->helper('directory'); $row = 0; $file_path = $_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . self::TEMP_DIRECTORY_UPLOAD; $file_name = scandir($file_path); if ( ! $file_name) { echo json_encode([ 'code' => '404', 'message' => 'File Not Found !!!' ]); } if (($handle = fopen($file_path . '/' . $file_name[2], "r")) !== FALSE) { deleteDir($file_path); while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) { //if ($row>2) break; $num = count($data); $f = []; for ($c=0; $c < $num; $c++) { $f[self::CSV_FIELDS[$c]] = $data[$c]; } if ($row>0) { $this->save_record($f); } $row++; } fclose($handle); } echo json_encode([ 'code' => '201', 'message' => 'Imported Successfully !!!' ]); } function save_record($f) { $member_id = $this->input->post()['member_id']; $location_start_id = $this->insert_and_get_address($f,'start'); $location_end_id = $this->insert_and_get_address($f,'end'); if ($location_start_id<1 || $location_end_id<1) { echo "Invalid address\n"; return NULL; } $q = "INSERT INTO quotes ( transport_provider_id, automation_id, cost_raw, cost, created, completed, travel_date, member_id, quote_group_id, location_start_id, location_end_id, prefill ) VALUES ("; $q.= $this->formatInteger($f["transport_provider_id"]) . ","; $q.= $this->formatInteger($f["automation_id"]) . ","; $q.= $this->formatString($f["cost_raw"]) . ","; $q.= $this->formatFloat($f["cost"]) . ","; $q.= $this->formatDate($f["created"]) . ","; $q.= $this->formatDate($f["completed"]) . ","; $q.= $this->formatDate($f["travel_date"]) . ","; $q.= $member_id . ","; /* formatInteger($f["member_id"]) . ","; */ $q.= "NULL,"; /* formatInteger($f["quote_group_id"]) . ","; */ $q.= $location_start_id . "," . $location_end_id; $q.= ",'t' ) RETURNING id"; $r = $this->db->query($q)->result_array(); if (count($r) === 0) { echo $q."\n"; return; } } function insert_and_get_address($f,$what) { $tzid = $this->get_timezone($f,$what); $q = " SELECT * FROM address WHERE lower(address)=lower(".$this->formatString($f["location_${what}_address"]).") "; $q.= " AND latitude = " . $this->formatFloat($f["location_${what}_lat"]) ; $q.= " AND longitude = " . $this->formatFloat($f["location_${what}_lng"]); $r = $this->read_replica->query($q)->result_array(); if (count($r)) { return $r[0]['id']; } /* id | bigint | | not null | nextval('address_id_seq'::regclass) address | character varying(200) | | | latitude | numeric | | | longitude | numeric | | | timezone | integer | | | geocoding_date | date | | | postal | character varying(40) | | | country | character varying(2) | | | 'SG'::character varying geometry | geography(Point,4326) | | | description | character varying(100) | | | */ $q = "INSERT INTO address (address,latitude,longitude,timezone,geocoding_date,postal,country,geometry,description) VALUES("; $q.= $this->formatString($f["location_${what}_address"]) . ","; $q.= $this->formatFloat($f["location_${what}_lat"]) . ","; $q.= $this->formatFloat($f["location_${what}_lng"]) . ","; $q.= $tzid . ","; $q.= "NOW()" . ","; $q.= $this->formatString($f["location_${what}_postal"]) . ","; $q.= $this->formatString($f["location_${what}_country"]) . ","; $q.= "st_setsrid(st_point(".$f["location_${what}_lng"] . ","; $q.= $f["location_${what}_lat"]."), 4326)" . ","; $q.= $this->formatString($f["location_${what}_description"]); $q.= ") RETURNING id"; $r = $this->db->query($q)->result_array(); if (count($r)) { return $r[0]['id']; } else { echo $q . "\n"; } return NULL; } function get_timezone($f,$what) { $q = "SELECT * FROM address_timezone WHERE lower(timezone)=lower(".$this->formatString($f["location_${what}_tz"]).")"; $r = $this->read_replica->query($q)->result_array(); if (count($r)) { return $r[0]['id']; } $q = "INSERT INTO address_timezone (timezone) VALUES(".$this->formatString($f["location_${what}_tz"]).") RETURNING id"; $r = $this->db->query($q)->result_array(); if (count($r)) { return $r[0]['id']; } return NULL; } function formatDate($value) { return empty($value) ? "NULL" : "'".pg_escape_string($value)."'"; } function formatInteger($value) { return empty($value) ? "NULL" : (int)$value; } function formatFloat($value) { return empty($value) ? "NULL" : floatval($value); } function formatString($value) { return trim($value)===""?"NULL":("'" . pg_escape_string($value) . "'"); } }