diff --git a/system/controllers/logout.php b/system/controllers/logout.php new file mode 100644 index 0000000..3db002b --- /dev/null +++ b/system/controllers/logout.php @@ -0,0 +1,12 @@ +assign('_title', 'PHPNuxBill Logs'); +$ui->assign('_system_menu', 'logs'); + +$action = $routes['1']; +$ui->assign('_admin', $admin); + +if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) { + _alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard"); +} + + +switch ($action) { + case 'list-csv': + $logs = ORM::for_table('tbl_logs') + ->select('id') + ->select('date') + ->select('type') + ->select('description') + ->select('userid') + ->select('ip') + ->order_by_asc('id')->find_array(); + $h = false; + set_time_limit(-1); + header('Pragma: public'); + header('Expires: 0'); + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header("Content-type: text/csv"); + header('Content-Disposition: attachment;filename="activity-logs_' . date('Y-m-d_H_i') . '.csv"'); + header('Content-Transfer-Encoding: binary'); + foreach ($logs as $log) { + $ks = []; + $vs = []; + foreach ($log as $k => $v) { + $ks[] = $k; + $vs[] = $v; + } + if (!$h) { + echo '"' . implode('";"', $ks) . "\"\n"; + $h = true; + } + echo '"' . implode('";"', $vs) . "\"\n"; + } + break; + case 'radius-csv': + $logs = ORM::for_table('radpostauth') + ->select('id') + ->select('username') + ->select('pass') + ->select('reply') + ->select('authdate') + ->order_by_asc('id')->find_array(); + $h = false; + set_time_limit(-1); + header('Pragma: public'); + header('Expires: 0'); + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header("Content-type: text/csv"); + header('Content-Disposition: attachment;filename="radius-logs_' . date('Y-m-d_H_i') . '.csv"'); + header('Content-Transfer-Encoding: binary'); + foreach ($logs as $log) { + $ks = []; + $vs = []; + foreach ($log as $k => $v) { + $ks[] = $k; + $vs[] = $v; + } + if (!$h) { + echo '"' . implode('";"', $ks) . "\"\n"; + $h = true; + } + echo '"' . implode('";"', $vs) . "\"\n"; + } + break; + + case 'list': + $q = (_post('q') ? _post('q') : _get('q')); + $keep = _post('keep'); + if (!empty($keep)) { + ORM::raw_execute("DELETE FROM tbl_logs WHERE UNIX_TIMESTAMP(date) < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL $keep DAY))"); + r2(U . "logs/list/", 's', "Delete logs older than $keep days"); + } + if ($q != '') { + $query = ORM::for_table('tbl_logs')->where_like('description', '%' . $q . '%')->order_by_desc('id'); + $d = Paginator::findMany($query, ['q' => $q]); + } else { + $query = ORM::for_table('tbl_logs')->order_by_desc('id'); + $d = Paginator::findMany($query); + } + + $ui->assign('d', $d); + $ui->assign('q', $q); + $ui->display('logs.tpl'); + break; + case 'radius': + $q = (_post('q') ? _post('q') : _get('q')); + $keep = _post('keep'); + if (!empty($keep)) { + ORM::raw_execute("DELETE FROM radpostauth WHERE UNIX_TIMESTAMP(authdate) < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL $keep DAY))", [], 'radius'); + r2(U . "logs/radius/", 's', "Delete logs older than $keep days"); + } + if ($q != '') { + $query = ORM::for_table('radpostauth', 'radius')->where_like('username', '%' . $q . '%')->order_by_desc('id'); + $d = Paginator::findMany($query, ['q' => $q]); + } else { + $query = ORM::for_table('radpostauth', 'radius')->order_by_desc('id'); + $d = Paginator::findMany($query); + } + + $ui->assign('d', $d); + $ui->assign('q', $q); + $ui->display('logs-radius.tpl'); + break; + + + default: + r2(U . 'logs/list/', 's', ''); +} diff --git a/system/controllers/map.php b/system/controllers/map.php new file mode 100644 index 0000000..9ef0827 --- /dev/null +++ b/system/controllers/map.php @@ -0,0 +1,54 @@ +assign('_system_menu', 'map'); + +$action = $routes['1']; +$ui->assign('_admin', $admin); + +if (empty($action)) { + $action = 'customer'; +} + +switch ($action) { + case 'customer': + if(!empty(_req('search'))){ + $search = _req('search'); + $query = ORM::for_table('tbl_customers')->whereRaw("coordinates != '' AND fullname LIKE '%$search%' OR username LIKE '%$search%' OR email LIKE '%$search%' OR phonenumber LIKE '%$search%'")->order_by_desc('fullname'); + $c = Paginator::findMany($query, ['search' => $search], 50); + }else{ + $query = ORM::for_table('tbl_customers')->where_not_equal('coordinates',''); + $c = Paginator::findMany($query, ['search'=>''], 50); + } + $customerData = []; + + foreach ($c as $customer) { + if (!empty($customer->coordinates)) { + $customerData[] = [ + 'id' => $customer->id, + 'name' => $customer->fullname, + 'balance' => $customer->balance, + 'address' => $customer->address, + 'direction' => $customer->coordinates, + 'info' => Lang::T("Username") . ": " . $customer->username . " - " . Lang::T("Full Name") . ": " . $customer->fullname . " - " . Lang::T("Email") . ": " . $customer->email . " - " . Lang::T("Phone") . ": " . $customer->phonenumber . " - " . Lang::T("Service Type") . ": " . $customer->service_type, + 'coordinates' => '[' . $customer->coordinates . ']', + ]; + } + } + $ui->assign('search', $search); + $ui->assign('customers', $customerData); + $ui->assign('xheader', ''); + $ui->assign('_title', Lang::T('Customer Geo Location Information')); + $ui->assign('xfooter', ''); + $ui->display('customers-map.tpl'); + break; + + default: + r2(U . 'map/customer', 'e', 'action not defined'); + break; +} diff --git a/system/controllers/message.php b/system/controllers/message.php new file mode 100644 index 0000000..c0daae4 --- /dev/null +++ b/system/controllers/message.php @@ -0,0 +1,242 @@ +assign('_title', Lang::T('Send Message')); +$ui->assign('_system_menu', 'message'); + +$action = $routes['1']; +$ui->assign('_admin', $admin); + +if (empty($action)) { + $action = 'send'; +} + +switch ($action) { + case 'send': + if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) { + _alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard"); + } + + $select2_customer = << +document.addEventListener("DOMContentLoaded", function(event) { + $('#personSelect').select2({ + theme: "bootstrap", + ajax: { + url: function(params) { + if(params.term != undefined){ + return './index.php?_route=autoload/customer_select2&s='+params.term; + }else{ + return './index.php?_route=autoload/customer_select2'; + } + } + } + }); +}); + +EOT; + if (isset($routes['2']) && !empty($routes['2'])) { + $ui->assign('cust', ORM::for_table('tbl_customers')->find_one($routes['2'])); + } + $id = $routes['2']; + $ui->assign('id', $id); + $ui->assign('xfooter', $select2_customer); + $ui->display('message.tpl'); + break; + + case 'send-post': + if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) { + _alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard"); + } + + // Get form data + $id_customer = $_POST['id_customer']; + $message = $_POST['message']; + $via = $_POST['via']; + + // Check if fields are empty + if ($id_customer == '' or $message == '' or $via == '') { + r2(U . 'message/send', 'e', Lang::T('All field is required')); + } else { + // Get customer details from the database + $c = ORM::for_table('tbl_customers')->find_one($id_customer); + + // Replace placeholders in the message with actual values + $message = str_replace('[[name]]', $c['fullname'], $message); + $message = str_replace('[[user_name]]', $c['username'], $message); + $message = str_replace('[[phone]]', $c['phonenumber'], $message); + $message = str_replace('[[company_name]]', $config['CompanyName'], $message); + + // Send the message + if ($via == 'sms' || $via == 'both') { + $smsSent = Message::sendSMS($c['phonenumber'], $message); + } + + if ($via == 'wa' || $via == 'both') { + $waSent = Message::sendWhatsapp($c['phonenumber'], $message); + } + + if (isset($smsSent) || isset($waSent)) { + r2(U . 'message/send', 's', Lang::T('Message Sent Successfully')); + } else { + r2(U . 'message/send', 'e', Lang::T('Failed to send message')); + } + } + break; + + case 'send_bulk': + if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) { + _alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard"); + } + + // Get form data + $group = $_POST['group']; + $message = $_POST['message']; + $via = $_POST['via']; + $test = isset($_POST['test']) && $_POST['test'] === 'on' ? 'yes' : 'no'; + $batch = $_POST['batch']; + $delay = $_POST['delay']; + + // Initialize counters + $totalSMSSent = 0; + $totalSMSFailed = 0; + $totalWhatsappSent = 0; + $totalWhatsappFailed = 0; + $batchStatus = []; + + if (_req('send') == 'now') { + // Check if fields are empty + if ($group == '' || $message == '' || $via == '') { + r2(U . 'message/send_bulk', 'e', Lang::T('All fields are required')); + } else { + // Get customer details from the database based on the selected group + if ($group == 'all') { + $customers = ORM::for_table('tbl_customers')->find_many()->as_array(); + } elseif ($group == 'new') { + // Get customers created just a month ago + $customers = ORM::for_table('tbl_customers')->where_raw("DATE(created_at) >= DATE_SUB(CURDATE(), INTERVAL 1 MONTH)")->find_many()->as_array(); + } elseif ($group == 'expired') { + // Get expired user recharges where status is 'off' + $expired = ORM::for_table('tbl_user_recharges')->where('status', 'off')->find_many(); + $customer_ids = []; + foreach ($expired as $recharge) { + $customer_ids[] = $recharge->customer_id; + } + $customers = ORM::for_table('tbl_customers')->where_in('id', $customer_ids)->find_many()->as_array(); + } elseif ($group == 'active') { + // Get active user recharges where status is 'on' + $active = ORM::for_table('tbl_user_recharges')->where('status', 'on')->find_many(); + $customer_ids = []; + foreach ($active as $recharge) { + $customer_ids[] = $recharge->customer_id; + } + $customers = ORM::for_table('tbl_customers')->where_in('id', $customer_ids)->find_many()->as_array(); + } elseif ($group == 'pppoe') { + // Get customers with PPPoE service type + $customers = ORM::for_table('tbl_customers')->where('service_type', 'PPPoE')->find_many()->as_array(); + } elseif ($group == 'hotspot') { + // Get customers with Hotspot service type + $customers = ORM::for_table('tbl_customers')->where('service_type', 'Hotspot')->find_many()->as_array(); + } + + // Set the batch size + $batchSize = $batch; + + // Calculate the number of batches + $totalCustomers = count($customers); + $totalBatches = ceil($totalCustomers / $batchSize); + + // Loop through batches + for ($batchIndex = 0; $batchIndex < $totalBatches; $batchIndex++) { + // Get the starting and ending index for the current batch + $start = $batchIndex * $batchSize; + $end = min(($batchIndex + 1) * $batchSize, $totalCustomers); + $batchCustomers = array_slice($customers, $start, $end - $start); + + // Loop through customers in the current batch and send messages + foreach ($batchCustomers as $customer) { + // Create a copy of the original message for each customer and save it as currentMessage + $currentMessage = $message; + $currentMessage = str_replace('[[name]]', $customer['fullname'], $currentMessage); + $currentMessage = str_replace('[[user_name]]', $customer['username'], $currentMessage); + $currentMessage = str_replace('[[phone]]', $customer['phonenumber'], $currentMessage); + $currentMessage = str_replace('[[company_name]]', $config['CompanyName'], $currentMessage); + + // Send the message based on the selected method + if ($test === 'yes') { + // Only for testing, do not send messages to customers + $batchStatus[] = [ + 'name' => $customer['fullname'], + 'phone' => $customer['phonenumber'], + 'message' => $currentMessage, + 'status' => 'Test Mode - Message not sent' + ]; + } else { + // Send the actual messages + if ($via == 'sms' || $via == 'both') { + $smsSent = Message::sendSMS($customer['phonenumber'], $currentMessage); + if ($smsSent) { + $totalSMSSent++; + $batchStatus[] = [ + 'name' => $customer['fullname'], + 'phone' => $customer['phonenumber'], + 'message' => $currentMessage, + 'status' => 'SMS Message Sent' + ]; + } else { + $totalSMSFailed++; + $batchStatus[] = [ + 'name' => $customer['fullname'], + 'phone' => $customer['phonenumber'], + 'message' => $currentMessage, + 'status' => 'SMS Message Failed' + ]; + } + } + + if ($via == 'wa' || $via == 'both') { + $waSent = Message::sendWhatsapp($customer['phonenumber'], $currentMessage); + if ($waSent) { + $totalWhatsappSent++; + $batchStatus[] = [ + 'name' => $customer['fullname'], + 'phone' => $customer['phonenumber'], + 'message' => $currentMessage, + 'status' => 'WhatsApp Message Sent' + ]; + } else { + $totalWhatsappFailed++; + $batchStatus[] = [ + 'name' => $customer['fullname'], + 'phone' => $customer['phonenumber'], + 'message' => $currentMessage, + 'status' => 'WhatsApp Message Failed' + ]; + } + } + } + } + + // Introduce a delay between each batch + if ($batchIndex < $totalBatches - 1) { + sleep($delay); + } + } + } + } + $ui->assign('batchStatus', $batchStatus); + $ui->assign('totalSMSSent', $totalSMSSent); + $ui->assign('totalSMSFailed', $totalSMSFailed); + $ui->assign('totalWhatsappSent', $totalWhatsappSent); + $ui->assign('totalWhatsappFailed', $totalWhatsappFailed); + $ui->display('message-bulk.tpl'); + break; + + default: + r2(U . 'message/send_sms', 'e', 'action not defined'); +} diff --git a/system/controllers/messages.php b/system/controllers/messages.php new file mode 100644 index 0000000..3042f8d --- /dev/null +++ b/system/controllers/messages.php @@ -0,0 +1,22 @@ +assign('_title', Lang::T('Messages')); +$ui->assign('_system_menu', 'messages'); + +$action = $routes['1']; +$ui->assign('_admin', $admin); + +// Fetch all messages +$msgs = ORM::for_table('tbl_message') + ->order_by_desc('date') + ->find_array(); + +$ui->assign('messages', $msgs); +$ui->display('message-list.tpl'); + +?>