Merge branch 'Development' into master

This commit is contained in:
iBNu Maksum 2024-03-28 18:41:33 +07:00 committed by GitHub
commit 6865b388d0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
53 changed files with 7932 additions and 704 deletions

View File

@ -7,3 +7,8 @@
Order Allow,Deny Order Allow,Deny
Allow from all Allow from all
</Files> </Files>
<Files update.php>
Order Allow,Deny
Allow from all
</Files>

View File

@ -2,6 +2,26 @@
# CHANGELOG # CHANGELOG
## 2024.3.26
- Change paginator, to make easy customization using pagination.tpl
## 2024.3.25
- Fix maps on HTTP
- Fix Cancel payment
## 2024.3.23
- Maps full height
- Show Get Directions instead Coordinates
- Maps Label always show
## 2024.3.22
- Fix Broadcast Message by @Focuslinkstech
- Add Location Picker
## 2024.3.20 ## 2024.3.20
- Fixing some bugs - Fixing some bugs

View File

@ -21,7 +21,7 @@ CREATE TABLE `tbl_customers` (
`id` int(10) NOT NULL, `id` int(10) NOT NULL,
`username` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `username` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`password` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `password` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`pppoe_password` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1' COMMENT 'For PPPOE Login', `pppoe_password` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login',
`fullname` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `fullname` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`address` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci, `address` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
`phonenumber` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0', `phonenumber` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0',

View File

@ -5,6 +5,12 @@
* by https://t.me/ibnux * by https://t.me/ibnux
**/ **/
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\SMTP;
require $root_path . 'system/autoload/mail/Exception.php';
require $root_path . 'system/autoload/mail/PHPMailer.php';
require $root_path . 'system/autoload/mail/SMTP.php';
class Message class Message
{ {
@ -66,6 +72,44 @@ class Message
} }
} }
public static function sendEmail($to, $subject, $body)
{
global $config;
run_hook('send_email'); #HOOK
if (empty($config['smtp_host'])) {
$attr = "";
if (!empty($config['mail_from'])) {
$attr .= "From: " . $config['mail_from'] . "\r\n";
}
if (!empty($config['mail_reply_to'])) {
$attr .= "Reply-To: " . $config['mail_reply_to'] . "\r\n";
}
mail($to, $subject, $body, $attr);
} else {
$mail = new PHPMailer();
$mail->isSMTP();
$mail->SMTPDebug = SMTP::DEBUG_SERVER;
$mail->Host = $config['smtp_host'];
$mail->SMTPAuth = true;
$mail->Username = $config['smtp_user'];
$mail->Password = $config['smtp_pass'];
$mail->SMTPSecure = $config['smtp_ssltls'];
$mail->Port = $config['smtp_port'];
if (!empty($config['mail_from'])) {
$mail->setFrom($config['mail_from']);
}
if (!empty($config['mail_reply_to'])) {
$mail->addReplyTo($config['mail_reply_to']);
}
$mail->isHTML(false);
$mail->addAddress($to);
$mail->Subject = $subject;
$mail->Body = $body;
$mail->send();
die();
}
}
public static function sendPackageNotification($customer, $package, $price, $message, $via) public static function sendPackageNotification($customer, $package, $price, $message, $via)
{ {
global $u; global $u;

View File

@ -44,6 +44,7 @@ class Package
foreach ($bills as $k => $v) { foreach ($bills as $k => $v) {
$note .= $k . " : " . Lang::moneyFormat($v) . "\n"; $note .= $k . " : " . Lang::moneyFormat($v) . "\n";
} }
$note .= $p['name_plan'] . " : " . Lang::moneyFormat($p['price']) . "\n";
} }
} }
@ -286,7 +287,7 @@ class Package
"\nRouter: " . $router_name . "\nRouter: " . $router_name .
"\nGateway: " . $gateway . "\nGateway: " . $gateway .
"\nChannel: " . $channel . "\nChannel: " . $channel .
"\nPrice: " . Lang::moneyFormat($p['price']) . "\nPrice: " . Lang::moneyFormat($p['price'] + $add_cost) .
"\nNote:\n" . $note); "\nNote:\n" . $note);
} else { } else {
if ($p['is_radius']) { if ($p['is_radius']) {
@ -374,7 +375,7 @@ class Package
"\nRouter: " . $router_name . "\nRouter: " . $router_name .
"\nGateway: " . $gateway . "\nGateway: " . $gateway .
"\nChannel: " . $channel . "\nChannel: " . $channel .
"\nPrice: " . Lang::moneyFormat($p['price']) . "\nPrice: " . Lang::moneyFormat($p['price'] + $add_cost) .
"\nNote:\n" . $note); "\nNote:\n" . $note);
} }
} else { } else {
@ -481,7 +482,7 @@ class Package
"\nRouter: " . $router_name . "\nRouter: " . $router_name .
"\nGateway: " . $gateway . "\nGateway: " . $gateway .
"\nChannel: " . $channel . "\nChannel: " . $channel .
"\nPrice: " . Lang::moneyFormat($p['price']) . "\nPrice: " . Lang::moneyFormat($p['price'] + $add_cost) .
"\nNote:\n" . $note); "\nNote:\n" . $note);
} else { } else {
if ($p['is_radius']) { if ($p['is_radius']) {
@ -520,7 +521,9 @@ class Package
$t->plan_name = $p['name_plan']; $t->plan_name = $p['name_plan'];
if ($p['validity_unit'] == 'Period') { if ($p['validity_unit'] == 'Period') {
// Postpaid price always zero for first time // Postpaid price always zero for first time
$t->price = 0 + $add_cost; $note = '';
$bills = [];
$t->price = 0;
} else { } else {
$t->price = $p['price'] + $add_cost; $t->price = $p['price'] + $add_cost;
} }
@ -569,7 +572,7 @@ class Package
"\nRouter: " . $router_name . "\nRouter: " . $router_name .
"\nGateway: " . $gateway . "\nGateway: " . $gateway .
"\nChannel: " . $channel . "\nChannel: " . $channel .
"\nPrice: " . Lang::moneyFormat($p['price']) . "\nPrice: " . Lang::moneyFormat($p['price'] + $add_cost) .
"\nNote:\n" . $note); "\nNote:\n" . $note);
} }
} }

View File

@ -1,13 +1,81 @@
<?php <?php
/** /**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/) * PHP Mikrotik Billing (https://github.com/SiberTech/)
* by https://t.me/ibnux * by https://t.me/ibnux
**/ **/
class Paginator class Paginator
{ {
public static function findMany($query, $search = [], $per_page = '10')
{
global $routes, $ui;
$adjacents = "2";
$page = _get('p', 1);
$page = (empty($page) ? 1 : $page);
$url = U . implode('/', $routes);
if (count($search) > 0) {
$url .= '&' . http_build_query($search);
}
$url .= '&p=';
$totalReq = $query->count();
$next = $page + 1;
$lastpage = ceil($totalReq / $per_page);
$lpm1 = $lastpage - 1;
$limit = $per_page;
$startpoint = ($page * $limit) - $limit;
if ($lastpage >= 1) {
$pages = [];
if ($lastpage < 7 + ($adjacents * 2)) {
for ($counter = 1; $counter <= $lastpage; $counter++) {
$pages[] = $counter;
}
} elseif ($lastpage > 5 + ($adjacents * 2)) {
if ($page < 1 + ($adjacents * 2)) {
for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++) {
$pages[] = $counter;
}
$pages[] = "...";
$pages[] = $lpm1;
$pages[] = $lastpage;
} elseif ($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2)) {
$pages[] = "1";
$pages[] = "2";
$pages[] = "...";
for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++) {
$pages[] = $counter;
}
$pages[] = "...";
$pages[] = $lpm1;
$pages[] = $lastpage;
} else {
$pages[] = "1";
$pages[] = "2";
$pages[] = "...";
for ($counter = $lastpage - (2 + ($adjacents * 2)); $counter <= $lastpage; $counter++) {
$pages[] = $counter;
}
}
}
$result = [
'count' => $lastpage,
'limit' => $per_page,
'startpoint' => $startpoint,
'url' => $url,
'page' => $page,
'pages' => $pages,
'prev' => ($page > 0) ? ($page - 1) : "0",
'next' => ($page >= $lastpage) ? $lastpage : $page + 1
];
if ($ui) {
$ui->assign('paginator', $result);
}
return $query->offset($startpoint)->limit($per_page)->find_many();
}
}
public static function build($table, $colVal = [], $query = '', $per_page = '10') public static function build($table, $colVal = [], $query = '', $per_page = '10')
{ {
global $routes; global $routes;
@ -36,60 +104,60 @@ class Paginator
$limit = $per_page; $limit = $per_page;
$startpoint = ($page * $limit) - $limit; $startpoint = ($page * $limit) - $limit;
if ($lastpage >= 1) { if ($lastpage >= 1) {
$pagination .= '<ul class="pagination pagination-sm">'; $pagination .= '<ul class="pagination">';
if ($lastpage < 7 + ($adjacents * 2)) { if ($lastpage < 7 + ($adjacents * 2)) {
for ($counter = 1; $counter <= $lastpage; $counter++) { for ($counter = 1; $counter <= $lastpage; $counter++) {
if ($counter == $page) if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>"; $pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else else
$pagination .= "<li><a href='{$url}&p=$counter&q=$query'>$counter</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$counter&q=$query'>$counter</a></li>";
} }
} elseif ($lastpage > 5 + ($adjacents * 2)) { } elseif ($lastpage > 5 + ($adjacents * 2)) {
if ($page < 1 + ($adjacents * 2)) { if ($page < 1 + ($adjacents * 2)) {
for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++) { for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++) {
if ($counter == $page) if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>"; $pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else else
$pagination .= "<li><a href='{$url}&p=$counter&q=$query'>$counter</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$counter&q=$query'>$counter</a></li>";
} }
$pagination .= "<li class='disabled'><a href='#'>...</a></li>"; $pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
$pagination .= "<li><a href='{$url}&p=$lpm1&q=$query'>$lpm1</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$lpm1&q=$query'>$lpm1</a></li>";
$pagination .= "<li><a href='{$url}&p=$lastpage&q=$query'>$lastpage</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$lastpage&q=$query'>$lastpage</a></li>";
} elseif ($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2)) { } elseif ($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2)) {
$pagination .= "<li><a href='{$url}&p=1&q=$query'>1</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=1&q=$query'>1</a></li>";
$pagination .= "<li><a href='{$url}&p=2&q=$query'>2</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=2&q=$query'>2</a></li>";
$pagination .= "<li class='disabled'><a href='#'>...</a></li>"; $pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++) { for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++) {
if ($counter == $page) if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>"; $pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else else
$pagination .= "<li><a href='{$url}&p=$counter&q=$query'>$counter</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$counter&q=$query'>$counter</a></li>";
} }
$pagination .= "<li class='disabled'><a href='#'>...</a></li>"; $pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
$pagination .= "<li><a href='{$url}&p=$lpm1&q=$query'>$lpm1</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$lpm1&q=$query'>$lpm1</a></li>";
$pagination .= "<li><a href='{$url}&p=$lastpage&q=$query'>$lastpage</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$lastpage&q=$query'>$lastpage</a></li>";
} else { } else {
$pagination .= "<li><a href='{$url}&p=1&q=$query'>1</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=1&q=$query'>1</a></li>";
$pagination .= "<li><a href='{$url}&p=2&q=$query'>2</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=2&q=$query'>2</a></li>";
$pagination .= "<li><a href='#'>...</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='#'>...</a></li>";
for ($counter = $lastpage - (2 + ($adjacents * 2)); $counter <= $lastpage; $counter++) { for ($counter = $lastpage - (2 + ($adjacents * 2)); $counter <= $lastpage; $counter++) {
if ($counter == $page) if ($counter == $page)
$pagination .= "<li class='active'><a class='disabled'>$counter</a></li>"; $pagination .= "<li class='page-item'><a class='page-link disabled'>$counter</a></li>";
else else
$pagination .= "<li><a href='{$url}&p=$counter&q=$query'>$counter</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$counter&q=$query'>$counter</a></li>";
} }
} }
} }
if ($page < $counter - 1) { if ($page < $counter - 1) {
$pagination .= "<li><a href='{$url}&p=$next&q=$query'>" . Lang::T('Next') . "</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$next&q=$query'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li><a href='{$url}&p=$lastpage&q=$query'>" . Lang::T('Last') . "</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$lastpage&q=$query'>" . Lang::T('Last') . "</a></li>";
} else { } else {
$pagination .= "<li class='disabled'><a class='disabled'>" . Lang::T('Next') . "</a></li>"; $pagination .= "<li class='page-item disabled'><a class='page-link disabled'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li class='disabled'><a class='disabled'>" . Lang::T('Last') . "</a></li>"; $pagination .= "<li class='page-item disabled'><a class='page-link disabled'>" . Lang::T('Last') . "</a></li>";
} }
$pagination .= "</ul>"; $pagination .= "</ul>";
$pagination = '<nav>' . $pagination . '</nav>';
return array("startpoint" => $startpoint, "limit" => $limit, "found" => $totalReq, "page" => $page, "lastpage" => $lastpage, "contents" => $pagination); return array("startpoint" => $startpoint, "limit" => $limit, "found" => $totalReq, "page" => $page, "lastpage" => $lastpage, "contents" => $pagination);
} }
} }
@ -142,59 +210,60 @@ class Paginator
$startpoint = ($page * $limit) - $limit; $startpoint = ($page * $limit) - $limit;
if ($lastpage >= 1) { if ($lastpage >= 1) {
$pagination .= '<ul class="pagination pagination-sm">'; $pagination .= '<ul class="pagination">';
if ($lastpage < 7 + ($adjacents * 2)) { if ($lastpage < 7 + ($adjacents * 2)) {
for ($counter = 1; $counter <= $lastpage; $counter++) { for ($counter = 1; $counter <= $lastpage; $counter++) {
if ($counter == $page) if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>"; $pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}$counter'>$counter</a></li>";
} }
} elseif ($lastpage > 5 + ($adjacents * 2)) { } elseif ($lastpage > 5 + ($adjacents * 2)) {
if ($page < 1 + ($adjacents * 2)) { if ($page < 1 + ($adjacents * 2)) {
for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++) { for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++) {
if ($counter == $page) if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>"; $pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}$counter'>$counter</a></li>";
} }
$pagination .= "<li class='disabled'><a href='#'>...</a></li>"; $pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
$pagination .= "<li><a href='{$url}$lpm1'>$lpm1</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lpm1'>$lpm1</a></li>";
$pagination .= "<li><a href='{$url}$lastpage'>$lastpage</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lastpage'>$lastpage</a></li>";
} elseif ($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2)) { } elseif ($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2)) {
$pagination .= "<li><a href='{$url}1'>1</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}1'>1</a></li>";
$pagination .= "<li><a href='{$url}2'>2</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}2'>2</a></li>";
$pagination .= "<li class='disabled'><a href='#'>...</a></li>"; $pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++) { for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++) {
if ($counter == $page) if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>"; $pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}$counter'>$counter</a></li>";
} }
$pagination .= "<li class='disabled'><a href='#'>...</a></li>"; $pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
$pagination .= "<li><a href='{$url}$lpm1'>$lpm1</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lpm1'>$lpm1</a></li>";
$pagination .= "<li><a href='{$url}$lastpage'>$lastpage</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lastpage'>$lastpage</a></li>";
} else { } else {
$pagination .= "<li><a href='{$url}1'>1</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}1'>1</a></li>";
$pagination .= "<li><a href='{$url}2'>2</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}2'>2</a></li>";
$pagination .= "<li><a href='#'>...</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='#'>...</a></li>";
for ($counter = $lastpage - (2 + ($adjacents * 2)); $counter <= $lastpage; $counter++) { for ($counter = $lastpage - (2 + ($adjacents * 2)); $counter <= $lastpage; $counter++) {
if ($counter == $page) if ($counter == $page)
$pagination .= "<li class='active'><a class='disabled'>$counter</a></li>"; $pagination .= "<li class='page-item'><a class='page-link disabled'>$counter</a></li>";
else else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}$counter'>$counter</a></li>";
} }
} }
} }
if ($page < $counter - 1) { if ($page < $counter - 1) {
$pagination .= "<li><a href='{$url}$next'>" . Lang::T('Next') . "</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}$next'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li><a href='{$url}$lastpage'>" . Lang::T('Last') . "</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lastpage'>" . Lang::T('Last') . "</a></li>";
} else { } else {
$pagination .= "<li class='disabled'><a class='disabled'>" . Lang::T('Next') . "</a></li>"; $pagination .= "<li class='page-item disabled'><a class='page-link disabled'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li class='disabled'><a class='disabled'>" . Lang::T('Last') . "</a></li>"; $pagination .= "<li class='page-item disabled'><a class='page-link disabled'>" . Lang::T('Last') . "</a></li>";
} }
$pagination .= "</ul>"; $pagination .= "</ul>";
$pagination = '<nav>' . $pagination . '</nav>';
$gen = array("startpoint" => $startpoint, "limit" => $limit, "found" => $totalReq, "page" => $page, "lastpage" => $lastpage, "contents" => $pagination); $gen = array("startpoint" => $startpoint, "limit" => $limit, "found" => $totalReq, "page" => $page, "lastpage" => $lastpage, "contents" => $pagination);
return $gen; return $gen;
@ -236,59 +305,60 @@ class Paginator
$startpoint = ($page * $limit) - $limit; $startpoint = ($page * $limit) - $limit;
if ($lastpage >= 1) { if ($lastpage >= 1) {
$pagination .= '<ul class="pagination pagination-sm">'; $pagination .= '<ul class="pagination">';
if ($lastpage < 7 + ($adjacents * 2)) { if ($lastpage < 7 + ($adjacents * 2)) {
for ($counter = 1; $counter <= $lastpage; $counter++) { for ($counter = 1; $counter <= $lastpage; $counter++) {
if ($counter == $page) if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>"; $pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}$counter'>$counter</a></li>";
} }
} elseif ($lastpage > 5 + ($adjacents * 2)) { } elseif ($lastpage > 5 + ($adjacents * 2)) {
if ($page < 1 + ($adjacents * 2)) { if ($page < 1 + ($adjacents * 2)) {
for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++) { for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++) {
if ($counter == $page) if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>"; $pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}$counter'>$counter</a></li>";
} }
$pagination .= "<li class='disabled'><a href='#'>...</a></li>"; $pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
$pagination .= "<li><a href='{$url}$lpm1'>$lpm1</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lpm1'>$lpm1</a></li>";
$pagination .= "<li><a href='{$url}$lastpage'>$lastpage</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lastpage'>$lastpage</a></li>";
} elseif ($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2)) { } elseif ($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2)) {
$pagination .= "<li><a href='{$url}1'>1</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}1'>1</a></li>";
$pagination .= "<li><a href='{$url}2'>2</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}2'>2</a></li>";
$pagination .= "<li class='disabled'><a href='#'>...</a></li>"; $pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++) { for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++) {
if ($counter == $page) if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>"; $pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}$counter'>$counter</a></li>";
} }
$pagination .= "<li class='disabled'><a href='#'>...</a></li>"; $pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
$pagination .= "<li><a href='{$url}$lpm1'>$lpm1</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lpm1'>$lpm1</a></li>";
$pagination .= "<li><a href='{$url}$lastpage'>$lastpage</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lastpage'>$lastpage</a></li>";
} else { } else {
$pagination .= "<li><a href='{$url}1'>1</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}1'>1</a></li>";
$pagination .= "<li><a href='{$url}2'>2</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}2'>2</a></li>";
$pagination .= "<li><a href='#'>...</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='#'>...</a></li>";
for ($counter = $lastpage - (2 + ($adjacents * 2)); $counter <= $lastpage; $counter++) { for ($counter = $lastpage - (2 + ($adjacents * 2)); $counter <= $lastpage; $counter++) {
if ($counter == $page) if ($counter == $page)
$pagination .= "<li class='active'><a class='disabled'>$counter</a></li>"; $pagination .= "<li class='page-item active'><a class='page-item disabled'>$counter</a></li>";
else else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}$counter'>$counter</a></li>";
} }
} }
} }
if ($page < $counter - 1) { if ($page < $counter - 1) {
$pagination .= "<li><a href='{$url}$next'>" . Lang::T('Next') . "</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}$next'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li><a href='{$url}$lastpage'>" . Lang::T('Last') . "</a></li>"; $pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lastpage'>" . Lang::T('Last') . "</a></li>";
} else { } else {
$pagination .= "<li class='disabled'><a class='disabled'>" . Lang::T('Next') . "</a></li>"; $pagination .= "<li class='page-item disabled'><a class='page-item disabled'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li class='disabled'><a class='disabled'>" . Lang::T('Last') . "</a></li>"; $pagination .= "<li class='page-item disabled'><a class='page-item disabled'>" . Lang::T('Last') . "</a></li>";
} }
$pagination .= "</ul>"; $pagination .= "</ul>";
$pagination = '<nav>' . $pagination . '</nav>';
$gen = array("startpoint" => $startpoint, "limit" => $limit, "found" => $totalReq, "page" => $page, "lastpage" => $lastpage, "contents" => $pagination); $gen = array("startpoint" => $startpoint, "limit" => $limit, "found" => $totalReq, "page" => $page, "lastpage" => $lastpage, "contents" => $pagination);
return $gen; return $gen;

View File

@ -0,0 +1,40 @@
<?php
/**
* PHPMailer Exception class.
* PHP Version 5.5.
*
* @see https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
*
* @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
* @author Jim Jagielski (jimjag) <jimjag@gmail.com>
* @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
* @author Brent R. Matzelle (original founder)
* @copyright 2012 - 2020 Marcus Bointon
* @copyright 2010 - 2012 Jim Jagielski
* @copyright 2004 - 2009 Andy Prevost
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
* @note This program is distributed in the hope that it will be useful - WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*/
namespace PHPMailer\PHPMailer;
/**
* PHPMailer exception handler.
*
* @author Marcus Bointon <phpmailer@synchromedia.co.uk>
*/
class Exception extends \Exception
{
/**
* Prettify error message output.
*
* @return string
*/
public function errorMessage()
{
return '<strong>' . htmlspecialchars($this->getMessage(), ENT_COMPAT | ENT_HTML401) . "</strong><br />\n";
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
<?php <?php
/** /**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/) * PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
* by https://t.me/ibnux * by https://t.me/ibnux
@ -21,15 +22,14 @@ switch ($action) {
run_hook('view_list_bandwidth'); #HOOK run_hook('view_list_bandwidth'); #HOOK
$name = _post('name'); $name = _post('name');
if ($name != '') { if ($name != '') {
$paginator = Paginator::build(ORM::for_table('tbl_bandwidth'), ['name_bw' => '%' . $name . '%'], $name); $query = ORM::for_table('tbl_bandwidth')->where_like('name_bw', '%' . $name . '%')->order_by_desc('id');
$d = ORM::for_table('tbl_bandwidth')->where_like('name_bw','%'.$name.'%')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many(); $d = Paginator::findMany($query, ['name' => $name]);
} else { } else {
$paginator = Paginator::build(ORM::for_table('tbl_bandwidth')); $query = ORM::for_table('tbl_bandwidth')->order_by_desc('id');
$d = ORM::for_table('tbl_bandwidth')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many(); $d = Paginator::findMany($query);
} }
$ui->assign('d', $d); $ui->assign('d', $d);
$ui->assign('paginator',$paginator);
$ui->display('bandwidth.tpl'); $ui->display('bandwidth.tpl');
break; break;
@ -97,8 +97,16 @@ switch ($action) {
$msg .= 'Name should be between 5 to 15 characters' . '<br>'; $msg .= 'Name should be between 5 to 15 characters' . '<br>';
} }
if($rate_down_unit == 'Kbps'){ $unit_rate_down = $rate_down * 1024; }else{ $unit_rate_down = $rate_down * 1048576; } if ($rate_down_unit == 'Kbps') {
if($rate_up_unit == 'Kbps'){ $unit_rate_up = $min_up * 1024; }else{ $unit_rate_up = $min_up * 1048576; } $unit_rate_down = $rate_down * 1024;
} else {
$unit_rate_down = $rate_down * 1048576;
}
if ($rate_up_unit == 'Kbps') {
$unit_rate_up = $min_up * 1024;
} else {
$unit_rate_up = $min_up * 1048576;
}
$d = ORM::for_table('tbl_bandwidth')->where('name_bw', $name)->find_one(); $d = ORM::for_table('tbl_bandwidth')->where('name_bw', $name)->find_one();
if ($d) { if ($d) {

View File

@ -16,36 +16,11 @@ if (empty ($action)) {
$action = 'list'; $action = 'list';
} }
$leafletpickerHeader = <<<EOT
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css">
EOT;
switch ($action) { switch ($action) {
case 'list':
$search = _post('search');
run_hook('list_customers'); #HOOK
if ($search != '') {
$paginator = Paginator::build(ORM::for_table('tbl_customers'), [
'username' => '%' . $search . '%',
'fullname' => '%' . $search . '%',
'phonenumber' => '%' . $search . '%',
'email' => '%' . $search . '%',
'service_type' => '%' . $search . '%'
], $search);
$d = ORM::for_table('tbl_customers')
->where_raw("(`username` LIKE '%$search%' OR `fullname` LIKE '%$search%' OR `phonenumber` LIKE '%$search%' OR `email` LIKE '%$search%')")
->offset($paginator['startpoint'])
->limit($paginator['limit'])
->order_by_asc('username')
->find_many();
} else {
$paginator = Paginator::build(ORM::for_table('tbl_customers'));
$d = ORM::for_table('tbl_customers')
->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many();
}
$ui->assign('search', htmlspecialchars($search));
$ui->assign('d', $d);
$ui->assign('paginator', $paginator);
$ui->display('customers.tpl');
break;
case 'csv': case 'csv':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) { if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard"); _alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
@ -89,6 +64,7 @@ switch ($action) {
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) { if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard"); _alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
} }
$ui->assign('xheader', $leafletpickerHeader);
run_hook('view_add_customer'); #HOOK run_hook('view_add_customer'); #HOOK
$ui->display('customers-add.tpl'); $ui->display('customers-add.tpl');
break; break;
@ -210,37 +186,25 @@ switch ($action) {
$customFields = ORM::for_table('tbl_customers_fields') $customFields = ORM::for_table('tbl_customers_fields')
->where('customer_id', $customer['id']) ->where('customer_id', $customer['id'])
->find_many(); ->find_many();
$v = $routes['3']; $v = $routes['3'];
if (empty($v)) { if (empty($v)) {
$v = 'activation'; $v = 'activation';
} }
if ($v == 'order') { if ($v == 'order') {
$v = 'order'; $v = 'order';
$paginator = Paginator::build(ORM::for_table('tbl_payment_gateway'), ['username' => $customer['username']]); $query = ORM::for_table('tbl_transactions')->where('username', $customer['username'])->order_by_desc('id');
$order = ORM::for_table('tbl_payment_gateway') $order = Paginator::findMany($query);
->where('username', $customer['username'])
->offset($paginator['startpoint'])
->limit($paginator['limit'])
->order_by_desc('id')
->find_many();
$ui->assign('paginator', $paginator);
$ui->assign('order', $order); $ui->assign('order', $order);
} else if ($v == 'activation') { } else if ($v == 'activation') {
$paginator = Paginator::build(ORM::for_table('tbl_transactions'), ['username' => $customer['username']]); $query = ORM::for_table('tbl_transactions')->where('username', $customer['username'])->order_by_desc('id');
$activation = ORM::for_table('tbl_transactions') $activation = Paginator::findMany($query);
->where('username', $customer['username'])
->offset($paginator['startpoint'])
->limit($paginator['limit'])
->order_by_desc('id')
->find_many();
$ui->assign('paginator', $paginator);
$ui->assign('activation', $activation); $ui->assign('activation', $activation);
} }
$ui->assign('packages', User::_billing($customer['id'])); $ui->assign('packages', User::_billing($customer['id']));
$ui->assign('v', $v); $ui->assign('v', $v);
$ui->assign('d', $customer); $ui->assign('d', $customer);
$ui->assign('customFields', $customFields); $ui->assign('customFields', $customFields);
$ui->assign('xheader', $leafletpickerHeader);
$ui->display('customers-view.tpl'); $ui->display('customers-view.tpl');
} else { } else {
r2(U . 'customers/list', 'e', $_L['Account_Not_Found']); r2(U . 'customers/list', 'e', $_L['Account_Not_Found']);
@ -260,6 +224,7 @@ switch ($action) {
if ($d) { if ($d) {
$ui->assign('d', $d); $ui->assign('d', $d);
$ui->assign('customFields', $customFields); $ui->assign('customFields', $customFields);
$ui->assign('xheader', $leafletpickerHeader);
$ui->display('customers-edit.tpl'); $ui->display('customers-edit.tpl');
} else { } else {
r2(U . 'customers/list', 'e', $_L['Account_Not_Found']); r2(U . 'customers/list', 'e', $_L['Account_Not_Found']);
@ -547,5 +512,20 @@ switch ($action) {
break; break;
default: default:
r2(U . 'customers/list', 'e', 'action not defined'); $search = _post('search');
run_hook('list_customers'); #HOOK
if ($search != '') {
$query = ORM::for_table('tbl_customers')
->where_raw("(`username` LIKE '%$search%' OR `fullname` LIKE '%$search%' OR `phonenumber` LIKE '%$search%' OR `email` LIKE '%$search%')")
->order_by_asc('username');
$d = Paginator::findMany($query, ['search' => $search]);
} else {
$query = ORM::for_table('tbl_customers')->order_by_asc('username');
$d = Paginator::findMany($query);
}
$ui->assign('search', htmlspecialchars($search));
$ui->assign('d', $d);
$ui->display('customers.tpl');
break;
} }

View File

@ -54,13 +54,10 @@ $ui->assign('c_all', $c_all);
if ($config['hide_uet'] != 'yes') { if ($config['hide_uet'] != 'yes') {
//user expire //user expire
$paginator = Paginator::build(ORM::for_table('tbl_user_recharges')); $query = ORM::for_table('tbl_user_recharges')
$expire = ORM::for_table('tbl_user_recharges')
->where_lte('expiration', $mdate) ->where_lte('expiration', $mdate)
->offset($paginator['startpoint']) ->order_by_desc('expiration');
->limit($paginator['limit']) $expire = Paginator::findMany($query);
->order_by_desc('expiration')
->find_many();
// Get the total count of expired records for pagination // Get the total count of expired records for pagination
$totalCount = ORM::for_table('tbl_user_recharges') $totalCount = ORM::for_table('tbl_user_recharges')
@ -71,7 +68,6 @@ if ($config['hide_uet'] != 'yes') {
$paginator['total_count'] = $totalCount; $paginator['total_count'] = $totalCount;
// Assign the pagination HTML to the template variable // Assign the pagination HTML to the template variable
$ui->assign('paginator', $paginator);
$ui->assign('expire', $expire); $ui->assign('expire', $expire);
} }

View File

@ -26,16 +26,15 @@ switch ($action) {
r2(U . "logs/list/", 's', "Delete logs older than $keep days"); r2(U . "logs/list/", 's', "Delete logs older than $keep days");
} }
if ($q != '') { if ($q != '') {
$paginator = Paginator::build(ORM::for_table('tbl_logs'), ['description' => '%' . $q . '%'], $q); $query = ORM::for_table('tbl_logs')->where_like('description', '%' . $q . '%')->order_by_desc('id');
$d = ORM::for_table('tbl_logs')->where_like('description', '%' . $q . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many(); $d = Paginator::findMany($query, ['q' => $q]);
} else { } else {
$paginator = Paginator::build(ORM::for_table('tbl_logs')); $query = ORM::for_table('tbl_logs')->order_by_desc('id');
$d = ORM::for_table('tbl_logs')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many(); $d = Paginator::findMany($query);
} }
$ui->assign('d', $d); $ui->assign('d', $d);
$ui->assign('q', $q); $ui->assign('q', $q);
$ui->assign('paginator', $paginator);
$ui->display('logs.tpl'); $ui->display('logs.tpl');
break; break;
case 'radius': case 'radius':
@ -46,16 +45,15 @@ switch ($action) {
r2(U . "logs/radius/", 's', "Delete logs older than $keep days"); r2(U . "logs/radius/", 's', "Delete logs older than $keep days");
} }
if ($q != '') { if ($q != '') {
$paginator = Paginator::build(ORM::for_table('radpostauth', 'radius'), ['username' => '%' . $q . '%'], $q); $query = ORM::for_table('radpostauth', 'radius')->where_like('username', '%' . $q . '%')->order_by_desc('id');
$d = ORM::for_table('radpostauth', 'radius')->where_like('username', '%' . $q . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many(); $d = Paginator::findMany($query, ['q' => $q]);
} else { } else {
$paginator = Paginator::build(ORM::for_table('radpostauth', 'radius')); $query = ORM::for_table('radpostauth', 'radius')->order_by_desc('id');
$d = ORM::for_table('radpostauth', 'radius')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many(); $d = Paginator::findMany($query);
} }
$ui->assign('d', $d); $ui->assign('d', $d);
$ui->assign('q', $q); $ui->assign('q', $q);
$ui->assign('paginator', $paginator);
$ui->display('logs-radius.tpl'); $ui->display('logs-radius.tpl');
break; break;

View File

@ -28,6 +28,7 @@ switch ($action) {
'name' => $customer->fullname, 'name' => $customer->fullname,
'balance' => $customer->balance, 'balance' => $customer->balance,
'address' => $customer->address, '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, '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 . ']', 'coordinates' => '[' . $customer->coordinates . ']',
]; ];
@ -38,7 +39,7 @@ switch ($action) {
$ui->assign('xheader', '<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css">'); $ui->assign('xheader', '<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css">');
$ui->assign('_title', Lang::T('Customer Geo Location Information')); $ui->assign('_title', Lang::T('Customer Geo Location Information'));
$ui->assign('xfooter', '<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>'); $ui->assign('xfooter', '<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>');
$ui->display('map-customer.tpl'); $ui->display('customers-map.tpl');
break; break;
default: default:

View File

@ -95,35 +95,33 @@ EOT;
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) { if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard"); _alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
} }
$ui->display('message-bulk.tpl');
break;
case 'send_bulk-post':
// Check user permissions
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 // Get form data
$group = $_POST['group']; $group = $_POST['group'];
$message = $_POST['message']; $message = $_POST['message'];
$via = $_POST['via']; $via = $_POST['via'];
$test = isset($_POST['test']) && $_POST['test'] === 'on' ? 'yes' : 'no';
$batch = $_POST['batch'];
$delay = $_POST['delay'];
// Initialize counters // Initialize counters
$successCount = 0; $totalSMSSent = 0;
$failCount = 0; $totalSMSFailed = 0;
$successMessages = []; $totalWhatsappSent = 0;
$failMessages = []; $totalWhatsappFailed = 0;
$batchStatus = [];
if (_req('send') == 'now') {
// Check if fields are empty // Check if fields are empty
if ($group == '' or $message == '' or $via == '') { if ($group == '' || $message == '' || $via == '') {
r2(U . 'message/send_bulk', 'e', Lang::T('All fields are required')); r2(U . 'message/send_bulk', 'e', Lang::T('All fields are required'));
} else { } else {
// Get customer details from the database based on the selected group // Get customer details from the database based on the selected group
if ($group == 'all') { if ($group == 'all') {
$customers = ORM::for_table('tbl_customers')->find_many(); $customers = ORM::for_table('tbl_customers')->find_many()->as_array();
} elseif ($group == 'new') { } elseif ($group == 'new') {
// Get customers created just a month ago // 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(); $customers = ORM::for_table('tbl_customers')->where_raw("DATE(created_at) >= DATE_SUB(CURDATE(), INTERVAL 1 MONTH)")->find_many()->as_array();
} elseif ($group == 'expired') { } elseif ($group == 'expired') {
// Get expired user recharges where status is 'off' // Get expired user recharges where status is 'off'
$expired = ORM::for_table('tbl_user_recharges')->where('status', 'off')->find_many(); $expired = ORM::for_table('tbl_user_recharges')->where('status', 'off')->find_many();
@ -131,7 +129,7 @@ EOT;
foreach ($expired as $recharge) { foreach ($expired as $recharge) {
$customer_ids[] = $recharge->customer_id; $customer_ids[] = $recharge->customer_id;
} }
$customers = ORM::for_table('tbl_customers')->where_in('id', $customer_ids)->find_many(); $customers = ORM::for_table('tbl_customers')->where_in('id', $customer_ids)->find_many()->as_array();
} elseif ($group == 'active') { } elseif ($group == 'active') {
// Get active user recharges where status is 'on' // Get active user recharges where status is 'on'
$active = ORM::for_table('tbl_user_recharges')->where('status', 'on')->find_many(); $active = ORM::for_table('tbl_user_recharges')->where('status', 'on')->find_many();
@ -139,80 +137,102 @@ EOT;
foreach ($active as $recharge) { foreach ($active as $recharge) {
$customer_ids[] = $recharge->customer_id; $customer_ids[] = $recharge->customer_id;
} }
$customers = ORM::for_table('tbl_customers')->where_in('id', $customer_ids)->find_many(); $customers = ORM::for_table('tbl_customers')->where_in('id', $customer_ids)->find_many()->as_array();
} }
// Loop through customers and send messages // Set the batch size
foreach ($customers as $customer) { $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 // Create a copy of the original message for each customer and save it as currentMessage
$currentMessage = $message; $currentMessage = $message;
// Replace placeholders in the message with actual values for each customer
$currentMessage = str_replace('[[name]]', $customer['fullname'], $currentMessage); $currentMessage = str_replace('[[name]]', $customer['fullname'], $currentMessage);
$currentMessage = str_replace('[[user_name]]', $customer['username'], $currentMessage); $currentMessage = str_replace('[[user_name]]', $customer['username'], $currentMessage);
$currentMessage = str_replace('[[phone]]', $customer['phonenumber'], $currentMessage); $currentMessage = str_replace('[[phone]]', $customer['phonenumber'], $currentMessage);
$currentMessage = str_replace('[[company_name]]', $config['CompanyName'], $currentMessage); $currentMessage = str_replace('[[company_name]]', $config['CompanyName'], $currentMessage);
// Send the message based on the selected method // 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') { if ($via == 'sms' || $via == 'both') {
$smsSent = Message::sendSMS($customer['phonenumber'], $currentMessage); $smsSent = Message::sendSMS($customer['phonenumber'], $currentMessage);
if ($smsSent) { if ($smsSent) {
$successCount++; $totalSMSSent++;
$successMessages[] = "SMS sent to {$customer['fullname']}: {$customer['phonenumber']}"; $batchStatus[] = [
'name' => $customer['fullname'],
'phone' => $customer['phonenumber'],
'message' => $currentMessage,
'status' => 'SMS Message Sent'
];
} else { } else {
$failCount++; $totalSMSFailed++;
$failMessages[] = "Failed to send SMS to {$customer['fullname']}: {$customer['phonenumber']}"; $batchStatus[] = [
'name' => $customer['fullname'],
'phone' => $customer['phonenumber'],
'message' => $currentMessage,
'status' => 'SMS Message Failed'
];
} }
// Introduce a delay of 5 seconds between each SMS
sleep(5);
} }
if ($via == 'wa' || $via == 'both') { if ($via == 'wa' || $via == 'both') {
$waSent = Message::sendWhatsapp($customer['phonenumber'], $currentMessage); $waSent = Message::sendWhatsapp($customer['phonenumber'], $currentMessage);
if ($waSent) { if ($waSent) {
$successCount++; $totalWhatsappSent++;
$successMessages[] = "WhatsApp message sent to {$customer['fullname']}: {$customer['phonenumber']}"; $batchStatus[] = [
'name' => $customer['fullname'],
'phone' => $customer['phonenumber'],
'message' => $currentMessage,
'status' => 'WhatsApp Message Sent'
];
} else { } else {
$failCount++; $totalWhatsappFailed++;
$failMessages[] = "Failed to send WhatsApp message to {$customer['fullname']}: {$customer['phonenumber']}"; $batchStatus[] = [
'name' => $customer['fullname'],
'phone' => $customer['phonenumber'],
'message' => $currentMessage,
'status' => 'WhatsApp Message Failed'
];
}
} }
// Introduce a delay of 5 seconds between each WhatsApp message
sleep(5);
} }
} }
$responseMessage = ''; // Introduce a delay between each batch
if ($batchIndex < $totalBatches - 1) {
if ($successCount > 0) { sleep($delay);
$responseMessage .= "Messages Sent Successfully: {$successCount}<br>";
$responseMessage .= "<ul>";
foreach ($successMessages as $successMessage) {
$responseMessage .= "<li>{$successMessage}</li>";
}
$responseMessage .= "</ul>";
}
if ($failCount > 0) {
$responseMessage .= "Failed to send messages: {$failCount}<br>";
$responseMessage .= "<ul>";
foreach ($failMessages as $failMessage) {
$responseMessage .= "<li>{$failMessage}</li>";
}
$responseMessage .= "</ul>";
}
if ($responseMessage != '') {
r2(U . 'message/send_bulk', 's', $responseMessage);
} else {
r2(U . 'message/send_bulk', 'e', Lang::T('No messages sent'));
} }
} }
}
}
$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; break;
default: default:
r2(U . 'message/send_sms', 'e', 'action not defined'); r2(U . 'message/send_sms', 'e', 'action not defined');
} }

View File

@ -19,13 +19,8 @@ switch ($action) {
break; break;
case 'history': case 'history':
$ui->assign('_system_menu', 'history'); $ui->assign('_system_menu', 'history');
$paginator = Paginator::build(ORM::for_table('tbl_payment_gateway'), ['username' => $user['username']]); $query = ORM::for_table('tbl_payment_gateway')->where('username', $user['username'])->order_by_desc('id');
$d = ORM::for_table('tbl_payment_gateway') $d = Paginator::findMany($query);
->where('username', $user['username'])
->order_by_desc('id')
->offset($paginator['startpoint'])->limit($paginator['limit'])
->find_many();
$ui->assign('paginator', $paginator);
$ui->assign('d', $d); $ui->assign('d', $d);
$ui->assign('_title', Lang::T('Order History')); $ui->assign('_title', Lang::T('Order History'));
run_hook('customer_view_order_history'); #HOOK run_hook('customer_view_order_history'); #HOOK
@ -107,8 +102,8 @@ switch ($action) {
if (empty ($trx)) { if (empty ($trx)) {
r2(U . "order/package", 'w', Lang::T("Payment not found")); r2(U . "order/package", 'w', Lang::T("Payment not found"));
} }
// jika url kosong, balikin ke buy // jika url kosong, balikin ke buy, kecuali cancel
if (empty ($trx['pg_url_payment'])) { if (empty ($trx['pg_url_payment']) && $routes['3'] != 'cancel') {
r2(U . "order/buy/" . (($trx['routers_id'] == 0) ? $trx['routers'] : $trx['routers_id']) . '/' . $trx['plan_id'], 'w', Lang::T("Checking payment")); r2(U . "order/buy/" . (($trx['routers_id'] == 0) ? $trx['routers'] : $trx['routers_id']) . '/' . $trx['plan_id'], 'w', Lang::T("Checking payment"));
} }
if ($routes['3'] == 'check') { if ($routes['3'] == 'check') {

View File

@ -68,11 +68,11 @@ switch ($action) {
$ui->assign('_title', Lang::T('Customer')); $ui->assign('_title', Lang::T('Customer'));
$search = _post('search'); $search = _post('search');
if ($search != '') { if ($search != '') {
$paginator = Paginator::build(ORM::for_table('tbl_user_recharges'), ['username' => '%' . $search . '%'], $search); $query = ORM::for_table('tbl_user_recharges')->where_like('username', '%' . $search . '%')->order_by_desc('id');
$d = ORM::for_table('tbl_user_recharges')->where_like('username', '%' . $search . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many(); $d = Paginator::findMany($query, ['search' => $search]);
} else { } else {
$paginator = Paginator::build(ORM::for_table('tbl_user_recharges')); $query = ORM::for_table('tbl_user_recharges')->order_by_desc('id');
$d = ORM::for_table('tbl_user_recharges')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_array(); $d = Paginator::findMany($query);
} }
run_hook('view_list_billing'); #HOOK run_hook('view_list_billing'); #HOOK
if ($isApi) { if ($isApi) {
@ -80,7 +80,6 @@ switch ($action) {
} }
$ui->assign('d', $d); $ui->assign('d', $d);
$ui->assign('search', $search); $ui->assign('search', $search);
$ui->assign('paginator', $paginator);
$ui->display('plan.tpl'); $ui->display('plan.tpl');
break; break;

View File

@ -23,15 +23,14 @@ switch ($action) {
$name = _post('name'); $name = _post('name');
if ($name != '') { if ($name != '') {
$paginator = Paginator::build(ORM::for_table('tbl_pool'), ['pool_name' => '%' . $name . '%'], $name); $query = ORM::for_table('tbl_pool')->where_like('pool_name', '%' . $name . '%')->order_by_desc('id');
$d = ORM::for_table('tbl_pool')->where_like('pool_name', '%' . $name . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many(); $d = Paginator::findMany($query, ['name' => $name]);
} else { } else {
$paginator = Paginator::build(ORM::for_table('tbl_pool')); $query = ORM::for_table('tbl_pool')->order_by_desc('id');
$d = ORM::for_table('tbl_pool')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many(); $d = Paginator::findMany($query);
} }
$ui->assign('d', $d); $ui->assign('d', $d);
$ui->assign('paginator', $paginator);
run_hook('view_pool'); #HOOK run_hook('view_pool'); #HOOK
$ui->display('pool.tpl'); $ui->display('pool.tpl');
break; break;

View File

@ -1,4 +1,5 @@
<?php <?php
/** /**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/) * PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
* by https://t.me/ibnux * by https://t.me/ibnux
@ -134,22 +135,15 @@ switch ($action) {
$ui->assign('_title', "Network Access Server"); $ui->assign('_title', "Network Access Server");
$name = _post('name'); $name = _post('name');
if (empty($name)) { if (empty($name)) {
$paginator = Paginator::build(ORM::for_table('nas', 'radius')); $query = ORM::for_table('nas', 'radius');
$nas = ORM::for_table('nas', 'radius')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many(); $nas = Paginator::findMany($query);
} else { } else {
$paginator = Paginator::build(ORM::for_table('nas', 'radius'), [ $query = ORM::for_table('nas', 'radius')
'nasname' => '%'.$search.'%',
'shortname' => '%'.$search.'%',
'description' => '%'.$search.'%'
]);
$nas = ORM::for_table('nas', 'radius')
->where_like('nasname', $search) ->where_like('nasname', $search)
->where_like('shortname', $search) ->where_like('shortname', $search)
->where_like('description', $search) ->where_like('description', $search);
->offset($paginator['startpoint'])->limit($paginator['limit']) $nas = Paginator::findMany($query, ['name' => $name]);
->find_many();
} }
$ui->assign('paginator', $paginator);
$ui->assign('name', $name); $ui->assign('name', $name);
$ui->assign('nas', $nas); $ui->assign('nas', $nas);
$ui->display('radius-nas.tpl'); $ui->display('radius-nas.tpl');

View File

@ -30,28 +30,26 @@ switch ($action) {
r2(U . "logs/list/", 's', "Delete logs older than $keep days"); r2(U . "logs/list/", 's', "Delete logs older than $keep days");
} }
if ($q != '') { if ($q != '') {
$paginator = Paginator::build(ORM::for_table('tbl_transactions'), ['invoice' => '%' . $q . '%'], $q); $query = ORM::for_table('tbl_transactions')->where_like('invoice', '%' . $q . '%')->order_by_desc('id');
$d = ORM::for_table('tbl_transactions')->where_like('invoice', '%' . $q . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many(); $d = Paginator::findMany($query, ['q' => $q]);
} else { } else {
$paginator = Paginator::build(ORM::for_table('tbl_transactions')); $query = ORM::for_table('tbl_transactions')->order_by_desc('id');
$d = ORM::for_table('tbl_transactions')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many(); $d = Paginator::findMany($query);
} }
$ui->assign('activation', $d); $ui->assign('activation', $d);
$ui->assign('q', $q); $ui->assign('q', $q);
$ui->assign('paginator', $paginator);
$ui->display('reports-activation.tpl'); $ui->display('reports-activation.tpl');
break; break;
case 'daily-report': case 'daily-report':
$paginator = Paginator::build(ORM::for_table('tbl_transactions'), ['recharged_on' => $mdate]); $query = ORM::for_table('tbl_transactions')->where('recharged_on', $mdate)->order_by_desc('id');
$d = ORM::for_table('tbl_transactions')->where('recharged_on', $mdate)->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many(); $d = Paginator::findMany($query);
$dr = ORM::for_table('tbl_transactions')->where('recharged_on', $mdate)->sum('price'); $dr = $query->sum('price');
$ui->assign('d', $d); $ui->assign('d', $d);
$ui->assign('dr', $dr); $ui->assign('dr', $dr);
$ui->assign('mdate', $mdate); $ui->assign('mdate', $mdate);
$ui->assign('mtime', $mtime); $ui->assign('mtime', $mtime);
$ui->assign('paginator', $paginator);
run_hook('view_daily_reports'); #HOOK run_hook('view_daily_reports'); #HOOK
$ui->display('reports-daily.tpl'); $ui->display('reports-daily.tpl');
break; break;

View File

@ -26,15 +26,14 @@ switch ($action) {
$name = _post('name'); $name = _post('name');
if ($name != '') { if ($name != '') {
$paginator = Paginator::build(ORM::for_table('tbl_routers'), ['name' => '%' . $name . '%'], $name); $query = ORM::for_table('tbl_routers')->where_like('name', '%' . $name . '%')->order_by_desc('id');
$d = ORM::for_table('tbl_routers')->where_like('name', '%' . $name . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many(); $d = Paginator::findMany($query, ['name' => $name]);
} else { } else {
$paginator = Paginator::build(ORM::for_table('tbl_routers')); $query = ORM::for_table('tbl_routers')->order_by_desc('id');
$d = ORM::for_table('tbl_routers')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many(); $d = Paginator::findMany($query);
} }
$ui->assign('d', $d); $ui->assign('d', $d);
$ui->assign('paginator', $paginator);
run_hook('view_list_routers'); #HOOK run_hook('view_list_routers'); #HOOK
$ui->display('routers.tpl'); $ui->display('routers.tpl');
break; break;

View File

@ -119,15 +119,14 @@ switch ($action) {
$name = _post('name'); $name = _post('name');
if ($name != '') { if ($name != '') {
$paginator = Paginator::build(ORM::for_table('tbl_plans'), ['name_plan' => '%' . $name . '%', 'type' => 'Hotspot'], $name); $query = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'Hotspot')->where_like('tbl_plans.name_plan', '%' . $name . '%');
$d = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'Hotspot')->where_like('tbl_plans.name_plan', '%' . $name . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many(); $d = Paginator::findMany($query, ['name'=> $name]);
} else { } else {
$paginator = Paginator::build(ORM::for_table('tbl_plans'), ['type' => 'Hotspot']); $query = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'Hotspot');
$d = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'Hotspot')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many(); $d = Paginator::findMany($query);
} }
$ui->assign('d', $d); $ui->assign('d', $d);
$ui->assign('paginator', $paginator);
run_hook('view_list_plans'); #HOOK run_hook('view_list_plans'); #HOOK
$ui->display('hotspot.tpl'); $ui->display('hotspot.tpl');
break; break;
@ -393,15 +392,14 @@ switch ($action) {
$name = _post('name'); $name = _post('name');
if ($name != '') { if ($name != '') {
$paginator = Paginator::build(ORM::for_table('tbl_plans'), ['name_plan' => '%' . $name . '%', 'type' => 'PPPOE'], $name); $query = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'PPPOE')->where_like('tbl_plans.name_plan', '%' . $name . '%');
$d = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'PPPOE')->where_like('tbl_plans.name_plan', '%' . $name . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many(); $d = Paginator::findMany($query, ['name' => $name]);
} else { } else {
$paginator = Paginator::build(ORM::for_table('tbl_plans'), ['type' => 'PPPOE'], $name); $query = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'PPPOE');
$d = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'PPPOE')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many(); $d = Paginator::findMany($query);
} }
$ui->assign('d', $d); $ui->assign('d', $d);
$ui->assign('paginator', $paginator);
run_hook('view_list_ppoe'); #HOOK run_hook('view_list_ppoe'); #HOOK
$ui->display('pppoe.tpl'); $ui->display('pppoe.tpl');
break; break;
@ -646,15 +644,14 @@ switch ($action) {
$ui->assign('_title', Lang::T('Balance Plans')); $ui->assign('_title', Lang::T('Balance Plans'));
$name = _post('name'); $name = _post('name');
if ($name != '') { if ($name != '') {
$paginator = Paginator::build(ORM::for_table('tbl_plans'), ['name_plan' => '%' . $name . '%', 'type' => 'Balance'], $name); $query = ORM::for_table('tbl_plans')->where('tbl_plans.type', 'Balance')->where_like('tbl_plans.name_plan', '%' . $name . '%');
$d = ORM::for_table('tbl_plans')->where('tbl_plans.type', 'Balance')->where_like('tbl_plans.name_plan', '%' . $name . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many(); $d = Paginator::findMany($query, ['name' => $name]);
} else { } else {
$paginator = Paginator::build(ORM::for_table('tbl_plans'), ['type' => 'Balance'], $name); $query = ORM::for_table('tbl_plans')->where('tbl_plans.type', 'Balance');
$d = ORM::for_table('tbl_plans')->where('tbl_plans.type', 'Balance')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many(); $d = Paginator::findMany($query);
} }
$ui->assign('d', $d); $ui->assign('d', $d);
$ui->assign('paginator', $paginator);
run_hook('view_list_balance'); #HOOK run_hook('view_list_balance'); #HOOK
$ui->display('balance.tpl'); $ui->display('balance.tpl');
break; break;

View File

@ -25,6 +25,10 @@ switch ($action) {
$result = Message::sendSMS(_get('testSms'), 'PHPNuxBill Test SMS'); $result = Message::sendSMS(_get('testSms'), 'PHPNuxBill Test SMS');
r2(U . "settings/app", 's', 'Test SMS has been send<br>Result: ' . $result); r2(U . "settings/app", 's', 'Test SMS has been send<br>Result: ' . $result);
} }
if (!empty(_get('testEmail'))) {
Message::sendEmail(_get('testEmail'), 'PHPNuxBill Test Email', 'PHPNuxBill Test Email Body');
r2(U . "settings/app", 's', 'Test Email has been send');
}
if (!empty(_get('testTg'))) { if (!empty(_get('testTg'))) {
$result = Message::sendTelegram('PHPNuxBill Test Telegram'); $result = Message::sendTelegram('PHPNuxBill Test Telegram');
r2(U . "settings/app", 's', 'Test Telegram has been send<br>Result: ' . $result); r2(U . "settings/app", 's', 'Test Telegram has been send<br>Result: ' . $result);
@ -276,60 +280,47 @@ switch ($action) {
$search = _req('search'); $search = _req('search');
if ($search != '') { if ($search != '') {
if ($admin['user_type'] == 'SuperAdmin') { if ($admin['user_type'] == 'SuperAdmin') {
$paginator = Paginator::build(ORM::for_table('tbl_users'), ['username' => '%' . $search . '%'], $search); $query = ORM::for_table('tbl_users')
$d = ORM::for_table('tbl_users')
->where_like('username', '%' . $search . '%') ->where_like('username', '%' . $search . '%')
->offset($paginator['startpoint']) ->order_by_asc('id');
->limit($paginator['limit'])->order_by_asc('id')->findArray(); $d = Paginator::findMany($query, ['search' => $search]);
} else if ($admin['user_type'] == 'Admin') { } else if ($admin['user_type'] == 'Admin') {
$paginator = Paginator::build(ORM::for_table('tbl_users'), [ $query = ORM::for_table('tbl_users')
'username' => '%' . $search . '%', ->where_like('username', '%' . $search . '%')->where_any_is([
['user_type' => 'Report'], ['user_type' => 'Report'],
['user_type' => 'Agent'], ['user_type' => 'Agent'],
['user_type' => 'Sales'], ['user_type' => 'Sales'],
['id' => $admin['id']] ['id' => $admin['id']]
], $search); ])->order_by_asc('id');
$d = ORM::for_table('tbl_users') $d = Paginator::findMany($query, ['search' => $search]);
->where_like('username', '%' . $search . '%')
->where_any_is([
['user_type' => 'Report'],
['user_type' => 'Agent'],
['user_type' => 'Sales'],
['id' => $admin['id']]
])
->offset($paginator['startpoint'])
->limit($paginator['limit'])->order_by_asc('id')->findArray();
} else { } else {
$paginator = Paginator::build(ORM::for_table('tbl_users'), ['username' => '%' . $search . '%'], $search); $query = ORM::for_table('tbl_users')
$d = ORM::for_table('tbl_users')
->where_like('username', '%' . $search . '%') ->where_like('username', '%' . $search . '%')
->where_any_is([ ->where_any_is([
['id' => $admin['id']], ['id' => $admin['id']],
['root' => $admin['id']] ['root' => $admin['id']]
]) ])->order_by_asc('id');
->offset($paginator['startpoint']) $d = Paginator::findMany($query, ['search' => $search]);
->limit($paginator['limit'])->order_by_asc('id')->findArray();
} }
} else { } else {
if ($admin['user_type'] == 'SuperAdmin') { if ($admin['user_type'] == 'SuperAdmin') {
$paginator = Paginator::build(ORM::for_table('tbl_users')); $query = ORM::for_table('tbl_users')->order_by_asc('id');
$d = ORM::for_table('tbl_users')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_asc('id')->findArray(); $d = Paginator::findMany($query);
} else if ($admin['user_type'] == 'Admin') { } else if ($admin['user_type'] == 'Admin') {
$paginator = Paginator::build(ORM::for_table('tbl_users')); $query = ORM::for_table('tbl_users')->where_any_is([
$d = ORM::for_table('tbl_users')->where_any_is([
['user_type' => 'Report'], ['user_type' => 'Report'],
['user_type' => 'Agent'], ['user_type' => 'Agent'],
['user_type' => 'Sales'], ['user_type' => 'Sales'],
['id' => $admin['id']] ['id' => $admin['id']]
])->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_asc('id')->findArray(); ])->order_by_asc('id');
$d = Paginator::findMany($query);
} else { } else {
$paginator = Paginator::build(ORM::for_table('tbl_users')); $query = ORM::for_table('tbl_users')
$d = ORM::for_table('tbl_users')
->where_any_is([ ->where_any_is([
['id' => $admin['id']], ['id' => $admin['id']],
['root' => $admin['id']] ['root' => $admin['id']]
]) ])->order_by_asc('id');
->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_asc('id')->findArray(); $d = Paginator::findMany($query);
} }
} }
$admins = []; $admins = [];
@ -354,7 +345,6 @@ switch ($action) {
$ui->assign('admins', $admins); $ui->assign('admins', $admins);
$ui->assign('d', $d); $ui->assign('d', $d);
$ui->assign('search', $search); $ui->assign('search', $search);
$ui->assign('paginator', $paginator);
run_hook('view_list_admin'); #HOOK run_hook('view_list_admin'); #HOOK
$ui->display('users.tpl'); $ui->display('users.tpl');
break; break;

View File

@ -40,11 +40,10 @@ switch ($action) {
case 'list-activated': case 'list-activated':
$ui->assign('_system_menu', 'list-activated'); $ui->assign('_system_menu', 'list-activated');
$paginator = Paginator::build(ORM::for_table('tbl_transactions'), ['username' => $user['username']]); $query = ORM::for_table('tbl_transactions')->where('username', $user['username'])->order_by_asc('id');
$d = ORM::for_table('tbl_transactions')->where('username', $user['username'])->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many(); $d = Paginator::findMany($query);
$ui->assign('d', $d); $ui->assign('d', $d);
$ui->assign('paginator', $paginator);
run_hook('customer_view_activation_list'); #HOOK run_hook('customer_view_activation_list'); #HOOK
$ui->display('user-activation-list.tpl'); $ui->display('user-activation-list.tpl');

View File

@ -26,6 +26,7 @@
"hebrew": "iw", "hebrew": "iw",
"hindi": "hi", "hindi": "hi",
"hungarian": "hu", "hungarian": "hu",
"iran": "ir",
"icelandic": "is", "icelandic": "is",
"italian": "it", "italian": "it",
"japanese": "ja", "japanese": "ja",

View File

@ -515,5 +515,26 @@
"List": "List", "List": "List",
"Lists": "Lists", "Lists": "Lists",
"Single_Customer": "Single Customer", "Single_Customer": "Single Customer",
"Bulk_Customers": "Bulk Customers" "Bulk_Customers": "Bulk Customers",
"Message_per_time": "Message per time",
"5_Messages": "5 Messages",
"10_Messages": "10 Messages",
"15_Messages": "15 Messages",
"20_Messages": "20 Messages",
"30_Messages": "30 Messages",
"40_Messages": "40 Messages",
"50_Messages": "50 Messages",
"60_Messages": "60 Messages",
"Use_20_and_above_if_you_are_sending_to_all_customers_to_avoid_server_time_out": "Use 20 and above if you are sending to all customers to avoid server time out",
"Delay": "Delay",
"No_Delay": "No Delay",
"5_Seconds": "5 Seconds",
"10_Seconds": "10 Seconds",
"15_Seconds": "15 Seconds",
"20_Seconds": "20 Seconds",
"Use_at_least_5_secs_if_you_are_sending_to_all_customers_to_avoid_being_banned_by_your_message_provider": "Use at least 5 secs if you are sending to all customers to avoid being banned by your message provider",
"Testing__if_checked_no_real_message_is_sent_": "Testing [if checked no real message is sent]",
"All_fields_are_required": "All fields are required",
"Personal": "Personal",
"Email_Notification": "Email Notification"
} }

View File

@ -6,13 +6,13 @@
"ALTER TABLE `tbl_customers_meta` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;" "ALTER TABLE `tbl_customers_meta` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;"
], ],
"2023.8.14": [ "2023.8.14": [
"ALTER TABLE `tbl_customers` ADD `pppoe_password` varchar(45) NOT NULL DEFAULT '1' COMMENT 'For PPPOE Login' AFTER `password`;", "ALTER TABLE `tbl_customers` ADD `pppoe_password` varchar(45) NOT NULL DEFAULT '' COMMENT 'For PPPOE Login' AFTER `password`;",
"ALTER TABLE `tbl_plans` CHANGE `type` `type` ENUM('Hotspot','PPPOE','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;", "ALTER TABLE `tbl_plans` CHANGE `type` `type` ENUM('Hotspot','PPPOE','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;",
"ALTER TABLE `tbl_transactions` CHANGE `type` `type` ENUM('Hotspot','PPPOE','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;", "ALTER TABLE `tbl_transactions` CHANGE `type` `type` ENUM('Hotspot','PPPOE','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;",
"ALTER TABLE `tbl_customers` ADD `auto_renewal` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Auto renewall using balance' AFTER `balance`;" "ALTER TABLE `tbl_customers` ADD `auto_renewal` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Auto renewall using balance' AFTER `balance`;"
], ],
"2023.8.23": [ "2023.8.23": [
"ALTER TABLE `tbl_customers` CHANGE `pppoe_password` `pppoe_password` VARCHAR(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '0' COMMENT 'For PPPOE Login';" "ALTER TABLE `tbl_customers` CHANGE `pppoe_password` `pppoe_password` VARCHAR(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login';"
], ],
"2023.8.28": [ "2023.8.28": [
"ALTER TABLE `tbl_user_recharges` ADD `recharged_time` time NOT NULL DEFAULT '00:00:00' AFTER `recharged_on`;", "ALTER TABLE `tbl_user_recharges` ADD `recharged_time` time NOT NULL DEFAULT '00:00:00' AFTER `recharged_on`;",
@ -87,5 +87,8 @@
], ],
"2024.3.19.2" : [ "2024.3.19.2" : [
"ALTER TABLE `tbl_plans` ADD `plan_type` ENUM('Business', 'Personal') DEFAULT 'Personal' COMMENT 'For selecting account type' ;" "ALTER TABLE `tbl_plans` ADD `plan_type` ENUM('Business', 'Personal') DEFAULT 'Personal' COMMENT 'For selecting account type' ;"
],
"2023.3.20": [
"ALTER TABLE `tbl_customers` CHANGE `pppoe_password` `pppoe_password` VARCHAR(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login';"
] ]
} }

View File

@ -340,6 +340,68 @@
<small id="emailHelp" class="form-text text-muted">You can use WhatsApp in here too. <a <small id="emailHelp" class="form-text text-muted">You can use WhatsApp in here too. <a
href="https://wa.nux.my.id/login" target="_blank">Free Server</a></small> href="https://wa.nux.my.id/login" target="_blank">Free Server</a></small>
</div> </div>
<div class="panel-heading">
<div class="btn-group pull-right">
<a class="btn btn-success btn-xs" style="color: black;" href="javascript:testEmail()">Test Email</a>
<button class="btn btn-primary btn-xs" title="save" type="submit"><span
class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span></button>
</div>
{Lang::T('Email Notification')}
</div>
<div class="panel-body">
<div class="form-group">
<label class="col-md-2 control-label">SMTP Host : port</label>
<div class="col-md-4">
<input type="text" class="form-control" id="smtp_host" name="smtp_host" value="{$_c['smtp_host']}"
placeholder="smtp.host.tld">
</div>
<div class="col-md-2">
<input type="number" class="form-control" id="smtp_port" name="smtp_port" value="{$_c['smtp_port']}"
placeholder="465 587 port">
</div>
<p class="help-block col-md-4">Empty this to use internal mail() PHP</p>
</div>
<div class="form-group">
<label class="col-md-2 control-label">SMTP username</label>
<div class="col-md-6">
<input type="text" class="form-control" id="smtp_user" name="smtp_user" value="{$_c['smtp_user']}"
placeholder="user@host.tld">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">SMTP Password</label>
<div class="col-md-6">
<input type="password" class="form-control" id="smtp_pass" name="smtp_pass" value="{$_c['smtp_pass']}"
onmouseleave="this.type = 'password'" onmouseenter="this.type = 'text'">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">SMTP Security</label>
<div class="col-md-6">
<select name="smtp_ssltls" id="smtp_ssltls" class="form-control">
<option value="" {if $_c['smtp_ssltls']=='' }selected="selected" {/if}>Not Secure</option>
<option value="ssl" {if $_c['smtp_ssltls']=='ssl' }selected="selected" {/if}>SSL</option>
<option value="tls" {if $_c['smtp_ssltls']=='tls' }selected="selected" {/if}>TLS</option>
</select>
</div>
<p class="help-block col-md-4">UPPERCASE lowercase RaNdoM</p>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Mail From</label>
<div class="col-md-6">
<input type="text" class="form-control" id="mail_from" name="mail_from" value="{$_c['mail_from']}"
placeholder="noreply@host.tld">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Mail Reply To</label>
<div class="col-md-6">
<input type="text" class="form-control" id="mail_reply_to" name="mail_reply_to" value="{$_c['mail_reply_to']}"
placeholder="support@host.tld">
</div>
<p class="help-block col-md-4">Customer will reply email to this address, empty if you want to use From Address</p>
</div>
</div>
<div class="panel-heading"> <div class="panel-heading">
<div class="btn-group pull-right"> <div class="btn-group pull-right">
<button class="btn btn-primary btn-xs" title="save" type="submit"><span <button class="btn btn-primary btn-xs" title="save" type="submit"><span
@ -561,6 +623,14 @@ add dst-host=*.{$_domain}</pre>
} }
} }
function testEmail() {
var target = prompt("Email\nSave First before Test", "");
if (target != null) {
window.location.href = '{$_url}settings/app&testEmail=' + target;
}
}
function testTg() { function testTg() {
window.location.href = '{$_url}settings/app&testTg=test'; window.location.href = '{$_url}settings/app&testTg=test';
} }

View File

@ -46,7 +46,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
{$paginator['contents']} {include file="pagination.tpl"}
</div> </div>
</div> </div>

View File

@ -48,7 +48,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
{$paginator['contents']} {include file="pagination.tpl"}
</div> </div>
</div> </div>
</div> </div>

View File

@ -73,17 +73,6 @@
<textarea name="address" id="address" class="form-control"></textarea> <textarea name="address" id="address" class="form-control"></textarea>
</div> </div>
</div> </div>
<div class="form-group">
<label class="col-md-3 control-label">{Lang::T('Coordinates')}</label>
<div class="col-md-9">
<input name="coordinates" id="coordinates" class="form-control" value=""
placeholder="6.465422, 3.406448">
<span class="help-block">
<small>{Lang::T('Latitude and Longitude coordinates for map must be separate with comma
","')}</small>
</span>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label class="col-md-3 control-label">{Lang::T('Service Type')}</label> <label class="col-md-3 control-label">{Lang::T('Service Type')}</label>
<div class="col-md-9"> <div class="col-md-9">
@ -105,6 +94,14 @@
</select> </select>
</div> </div>
</div> </div>
<div class="form-group">
<label class="col-md-3 control-label">{Lang::T('Coordinates')}</label>
<div class="col-md-9">
<input name="coordinates" id="coordinates" class="form-control" value=""
placeholder="6.465422, 3.406448">
<div id="map" style="width: '100%'; height: 200px; min-height: 150px;"></div>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -163,6 +160,42 @@
}); });
}); });
</script> </script>
<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>
<script>
function getLocation() {
if (window.location.protocol == "https:" && navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition);
} else {
setupMap(51.505, -0.09);
}
}
function showPosition(position) {
setupMap(position.coords.latitude, position.coords.longitude);
}
function setupMap(lat, lon) {
var map = L.map('map').setView([lat, lon], 13);
L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/light_all/{z}/{x}/{y}.png', {
attribution:
'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',
subdomains: 'abcd',
maxZoom: 20
}).addTo(map);
var marker = L.marker([lat, lon]).addTo(map);
map.on('click', function(e){
var coord = e.latlng;
var lat = coord.lat;
var lng = coord.lng;
var newLatLng = new L.LatLng(lat, lng);
marker.setLatLng(newLatLng);
$('#coordinates').val(lat + ',' + lng);
});
}
window.onload = function() {
getLocation();
}
</script>
{/literal} {/literal}

View File

@ -77,16 +77,6 @@
<textarea name="address" id="address" class="form-control">{$d['address']}</textarea> <textarea name="address" id="address" class="form-control">{$d['address']}</textarea>
</div> </div>
</div> </div>
<div class="form-group">
<label class="col-md-3 control-label">{Lang::T('Coordinates')}</label>
<div class="col-md-9">
<input name="coordinates" id="coordinates" class="form-control" value="{$d['coordinates']}">
<span class="help-block">
<small>{Lang::T('Latitude and Longitude coordinates for map must be separate with comma
","')}</small>
</span>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label class="col-md-3 control-label">{Lang::T('Service Type')}</label> <label class="col-md-3 control-label">{Lang::T('Service Type')}</label>
<div class="col-md-9"> <div class="col-md-9">
@ -98,17 +88,25 @@
</select> </select>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-md-3 control-label">{Lang::T('Account Type')}</label> <label class="col-md-3 control-label">{Lang::T('Account Type')}</label>
<div class="col-md-9"> <div class="col-md-9">
<select class="form-control" id="account_type" name="account_type"> <select class="form-control" id="account_type" name="account_type">
<option value="Personal" {if $d['account_type'] eq 'Personal' }selected{/if}>Personal <option value="Personal" {if $d['account_type'] eq 'Personal' }selected{/if}>Personal
</option> </option>
<option value="Business" {if $d['account_type'] eq 'Business' }selected{/if}>Business</option> <option value="Business" {if $d['account_type'] eq 'Business' }selected{/if}>Business
</option>
</select> </select>
</div> </div>
</div> </div>
<div class="form-group">
<label class="col-md-3 control-label">{Lang::T('Coordinates')}</label>
<div class="col-md-9">
<input name="coordinates" id="coordinates" class="form-control" value="{$d['coordinates']}"
placeholder="6.465422, 3.406448">
<div id="map" style="width: '100%'; height: 200px; min-height: 150px;"></div>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -186,6 +184,47 @@
}); });
}); });
</script> </script>
<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>
<script>
function getLocation() {
if (window.location.protocol == "https:" && navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition);
} else {
setupMap(51.505, -0.09);
}
}
function showPosition(position) {
setupMap(position.coords.latitude, position.coords.longitude);
}
function setupMap(lat, lon) {
var map = L.map('map').setView([lat, lon], 13);
L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/light_all/{z}/{x}/{y}.png', {
attribution:
'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',
subdomains: 'abcd',
maxZoom: 20
}).addTo(map);
var marker = L.marker([lat, lon]).addTo(map);
map.on('click', function(e) {
var coord = e.latlng;
var lat = coord.lat;
var lng = coord.lng;
var newLatLng = new L.LatLng(lat, lng);
marker.setLatLng(newLatLng);
$('#coordinates').val(lat + ',' + lng);
});
}
window.onload = function() {
{/literal}{if $d['coordinates']}
setupMap({$d['coordinates']});
{else}
getLocation();
{/if}{literal}
}
</script>
{/literal} {/literal}
{include file="sections/footer.tpl"} {include file="sections/footer.tpl"}

63
ui/ui/customers-map.tpl Normal file
View File

@ -0,0 +1,63 @@
{include file="sections/header.tpl"}
<!-- Map container div -->
<div id="map" class="well" style="width: '100%'; height: 78vh; margin: 20px auto"></div>
{literal}
<script>
function getLocation() {
if (window.location.protocol == "https:" && navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition);
} else {
setupMap(51.505, -0.09);
}
}
function showPosition(position) {
setupMap(position.coords.latitude, position.coords.longitude);
}
function setupMap(lat, lon) {
var map = L.map('map').setView([lat, lon], 13);
var group = L.featureGroup().addTo(map);
var customers = {/literal}{$customers|json_encode}{literal};
L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/light_all/{z}/{x}/{y}.png', {
attribution:
'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',
subdomains: 'abcd',
maxZoom: 20
}).addTo(map);
customers.forEach(function(customer) {
var name = customer.id;
var name = customer.name;
var info = customer.info;
var direction = customer.direction;
var coordinates = customer.coordinates;
var balance = customer.balance;
var address = customer.address;
// Create a popup for the marker
var popupContent = "<strong>Name</strong>: " + name + "<br>" +
"<strong>Info</strong>: " + info + "<br>" +
"<strong>Balance</strong>: " + balance + "<br>" +
"<strong>Address</strong>: " + address + "<br>" +
"<a href='{/literal}{$_url}{literal}customers/view/"+ customer.id +"'>More Info</a> &bull; " +
"<a href='https://www.google.com/maps/dir//" + direction + "' target='maps'>Get Direction</a><br>";
// Add marker to map
var marker = L.marker(JSON.parse(coordinates)).addTo(group);
marker.bindTooltip(name, { permanent: true }).bindPopup(popupContent);
});
map.fitBounds(group.getBounds());
}
window.onload = function() {
getLocation();
}
</script>
{/literal}
{include file="sections/footer.tpl"}

View File

@ -37,9 +37,6 @@
onclick="this.select()"> onclick="this.select()">
</li> </li>
{/if} {/if}
<li class="list-group-item">
<b>{Lang::T('Coordinates')}</b> <span class="pull-right">{Lang::T($d['coordinates'])}</span>
</li>
<!--Customers Attributes view start --> <!--Customers Attributes view start -->
{if $customFields} {if $customFields}
{foreach $customFields as $customField} {foreach $customFields as $customField}
@ -77,6 +74,16 @@
<b>{Lang::T('Last Login')}</b> <span <b>{Lang::T('Last Login')}</b> <span
class="pull-right">{Lang::dateTimeFormat($d['last_login'])}</span> class="pull-right">{Lang::dateTimeFormat($d['last_login'])}</span>
</li> </li>
{if $d['coordinates']}
<li class="list-group-item">
<b>{Lang::T('Coordinates')}</b> <span class="pull-right">
<i class="glyphicon glyphicon-road"></i> <a style="color: black;"
href="https://www.google.com/maps/dir//{$d['coordinates']}/" target="_blank">Get
Directions</a>
</span>
<div id="map" style="width: '100%'; height: 100px;"></div>
</li>
{/if}
</ul> </ul>
<div class="row"> <div class="row">
<div class="col-xs-4"> <div class="col-xs-4">
@ -110,8 +117,7 @@
class="pull-right">{Lang::dateAndTimeFormat($package['recharged_on'],$package['recharged_time'])}</span> class="pull-right">{Lang::dateAndTimeFormat($package['recharged_on'],$package['recharged_time'])}</span>
</li> </li>
<li class="list-group-item"> <li class="list-group-item">
{Lang::T('Expires On')} <span {Lang::T('Expires On')} <span class="pull-right">{Lang::dateAndTimeFormat($package['expiration'],
class="pull-right">{Lang::dateAndTimeFormat($package['expiration'],
$package['time'])}</span> $package['time'])}</span>
</li> </li>
<li class="list-group-item"> <li class="list-group-item">
@ -222,8 +228,28 @@
{/if} {/if}
</table> </table>
</div> </div>
{$paginator['contents']} {include file="pagination.tpl"}
</div> </div>
</div> </div>
{if $d['coordinates']}
{literal}
<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>
<script>
function setupMap(lat, lon) {
var map = L.map('map').setView([lat, lon], 17);
L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/light_all/{z}/{x}/{y}.png', {
attribution:
'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',
subdomains: 'abcd',
maxZoom: 20
}).addTo(map);
var marker = L.marker([lat, lon]).addTo(map);
}
window.onload = function() {
{/literal}setupMap({$d['coordinates']});{literal}
}
</script>
{/literal}
{/if}
{include file="sections/footer.tpl"} {include file="sections/footer.tpl"}

View File

@ -16,10 +16,10 @@
<div class="panel-body"> <div class="panel-body">
<div class="md-whiteframe-z1 mb20 text-center" style="padding: 15px"> <div class="md-whiteframe-z1 mb20 text-center" style="padding: 15px">
<div class="col-md-8"> <div class="col-md-8">
<form id="site-search" method="post" action="{$_url}customers/list/"> <form id="site-search" method="post" action="{$_url}customers/">
<div class="input-group"> <div class="input-group">
<input type="text" id="search-input" name="search" value="{$search}" class="form-control" <input type="text" id="search-input" name="search" value="{$search}"
placeholder="{Lang::T('Search')}..."> class="form-control" placeholder="{Lang::T('Search')}...">
<div class="input-group-btn"> <div class="input-group-btn">
<button class="btn btn-success" type="submit"><span <button class="btn btn-success" type="submit"><span
class="fa fa-search"></span></button> class="fa fa-search"></span></button>
@ -28,8 +28,8 @@
</form> </form>
</div> </div>
<div class="col-md-4"> <div class="col-md-4">
<a href="{$_url}customers/add" class="btn btn-primary btn-block"><i <a href="{$_url}customers/add" class="btn btn-primary btn-block"><i class="ion ion-android-add">
class="ion ion-android-add"> </i> {Lang::T('Add New Contact')}</a> </i> {Lang::T('Add New Contact')}</a>
</div>&nbsp; </div>&nbsp;
</div> </div>
<div class="table-responsive table_mobile"> <div class="table-responsive table_mobile">
@ -40,8 +40,7 @@
<th>{Lang::T('Account Type')}</th> <th>{Lang::T('Account Type')}</th>
<th>{Lang::T('Full Name')}</th> <th>{Lang::T('Full Name')}</th>
<th>{Lang::T('Balance')}</th> <th>{Lang::T('Balance')}</th>
<th>{Lang::T('Phone Number')}</th> <th width="120px"></th>
<th>{Lang::T('Email')}</th>
<th>{Lang::T('Package')}</th> <th>{Lang::T('Package')}</th>
<th>{Lang::T('Service Type')}</th> <th>{Lang::T('Service Type')}</th>
<th>{Lang::T('Created On')}</th> <th>{Lang::T('Created On')}</th>
@ -57,16 +56,32 @@
<td onclick="window.location.href = '{$_url}customers/view/{$ds['id']}'" <td onclick="window.location.href = '{$_url}customers/view/{$ds['id']}'"
style="cursor: pointer;">{$ds['fullname']}</td> style="cursor: pointer;">{$ds['fullname']}</td>
<td>{Lang::moneyFormat($ds['balance'])}</td> <td>{Lang::moneyFormat($ds['balance'])}</td>
<td>{$ds['phonenumber']}</td> <td align="center">
<td>{$ds['email']}</td> {if $ds['phonenumber']}
<a href="tel:{$ds['phonenumber']}" class="btn btn-default btn-xs"
title="{$ds['phonenumber']}"><i class="glyphicon glyphicon-earphone"></i></a>
{/if}
{if $ds['email']}
<a href="mailto:{$ds['email']}" class="btn btn-default btn-xs"
title="{$ds['email']}"><i class="glyphicon glyphicon-envelope"></i></a>
{/if}
{if $ds['coordinates']}
<a href="https://www.google.com/maps/dir//{$ds['coordinates']}/" target="_blank" class="btn btn-default btn-xs"
title="{$ds['coordinates']}"><i class="glyphicon glyphicon-map-marker"></i></a>
{/if}
</td>
<td align="center" api-get-text="{$_url}autoload/customer_is_active/{$ds['id']}"> <td align="center" api-get-text="{$_url}autoload/customer_is_active/{$ds['id']}">
<span class="label label-default">&bull;</span> <span class="label label-default">&bull;</span>
</td> </td>
<td>{$ds['service_type']}</td> <td>{$ds['service_type']}</td>
<td>{Lang::dateTimeFormat($ds['created_at'])}</td> <td>{Lang::dateTimeFormat($ds['created_at'])}</td>
<td align="center"> <td align="center">
<a href="{$_url}customers/view/{$ds['id']}" id="{$ds['id']}" style="margin: 0px;" <a href="{$_url}customers/view/{$ds['id']}" id="{$ds['id']}"
style="margin: 0px; color:black"
class="btn btn-success btn-xs">&nbsp;&nbsp;{Lang::T('View')}&nbsp;&nbsp;</a> class="btn btn-success btn-xs">&nbsp;&nbsp;{Lang::T('View')}&nbsp;&nbsp;</a>
<a href="{$_url}customers/edit/{$ds['id']}" id="{$ds['id']}"
style="margin: 0px; color:black"
class="btn btn-info btn-xs">&nbsp;&nbsp;{Lang::T('Edit')}&nbsp;&nbsp;</a>
<a href="{$_url}plan/recharge/{$ds['id']}" id="{$ds['id']}" style="margin: 0px;" <a href="{$_url}plan/recharge/{$ds['id']}" id="{$ds['id']}" style="margin: 0px;"
class="btn btn-primary btn-xs">{Lang::T('Recharge')}</a> class="btn btn-primary btn-xs">{Lang::T('Recharge')}</a>
</td> </td>
@ -75,7 +90,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
{$paginator['contents']} {include file="pagination.tpl"}
</div> </div>
</div> </div>
</div> </div>

View File

@ -163,7 +163,7 @@
{/foreach} {/foreach}
</table> </table>
</div> </div>
&nbsp; {$paginator['contents']} &nbsp; {include file="pagination.tpl"}
</div> </div>
{/if} {/if}
</div> </div>

View File

@ -85,8 +85,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
{$paginator['contents']} {include file="pagination.tpl"}
</div> </div>
</div> </div>
</div> </div>

View File

@ -53,7 +53,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
{$paginator['contents']} {include file="pagination.tpl"}
</div> </div>
</div> </div>
</div> </div>

View File

@ -50,7 +50,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
{$paginator['contents']} {include file="pagination.tpl"}
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,45 +0,0 @@
{include file="sections/header.tpl"}
<!-- Map container div -->
<div id="map" style="width: '100%'; height: 600px; margin: 20px auto"></div>
{literal}
<script>
window.onload = function() {
var map = L.map('map').setView([51.505, -0.09], 13);
var group = L.featureGroup().addTo(map);
var customers = {/literal}{$customers|json_encode}{literal};
L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/light_all/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',
subdomains: 'abcd',
maxZoom: 20
}).addTo(map);
customers.forEach(function(customer) {
var name = customer.id;
var name = customer.name;
var info = customer.info;
var coordinates = customer.coordinates;
var balance = customer.balance;
var address = customer.address;
// Create a popup for the marker
var popupContent = "<strong>Customer Name</strong>: " + name + "<br>" +
"<strong>Customer Info</strong>: " + info + "<br>" +
"<strong>Customer Balance</strong>: " + balance + "<br>" +
"<strong>Address</strong>: " + address + "<br>" +
"<strong>Coordinates</strong>: " + coordinates + "<br>" +
"<a href='{/literal}{$_url}{literal}customers/view/"+ customer.id +"'>More Info</a><br>";
// Add marker to map
var marker = L.marker(JSON.parse(coordinates)).addTo(group);
marker.bindTooltip(name).bindPopup(popupContent);
});
map.fitBounds(group.getBounds());
}
</script>
{/literal}
{include file="sections/footer.tpl"}

View File

@ -1,11 +1,13 @@
{include file="sections/header.tpl"} {include file="sections/header.tpl"}
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.11.3/css/jquery.dataTables.min.css">
<div class="row"> <div class="row">
<div class="col-sm-12 col-md-12"> <div class="col-sm-12 col-md-12">
<div class="panel panel-primary panel-hovered panel-stacked mb30"> <div class="panel panel-primary panel-hovered panel-stacked mb30">
<div class="panel-heading">{Lang::T('Send Bulk Message')}</div> <div class="panel-heading">{Lang::T('Send Bulk Message')}</div>
<div class="panel-body"> <div class="panel-body">
<form class="form-horizontal" method="post" role="form" action="{$_url}message/send_bulk-post"> <form class="form-horizontal" method="post" role="form" id="bulkMessageForm" action="">
<div class="form-group"> <div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Group')}</label> <label class="col-md-2 control-label">{Lang::T('Group')}</label>
<div class="col-md-6"> <div class="col-md-6">
@ -27,11 +29,39 @@
</select> </select>
</div> </div>
</div> </div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Message per time')}</label>
<div class="col-md-6">
<select class="form-control" name="batch" id="batch">
<option value="5">{Lang::T('5 Messages')}</option>
<option value="10" selected>{Lang::T('10 Messages')}</option>
<option value="15">{Lang::T('15 Messages')}</option>
<option value="20">{Lang::T('20 Messages')}</option>
<option value="20">{Lang::T('30 Messages')}</option>
<option value="20">{Lang::T('40 Messages')}</option>
<option value="20">{Lang::T('50 Messages')}</option>
<option value="20">{Lang::T('60 Messages')}</option>
</select>{Lang::T('Use 20 and above if you are sending to all customers to avoid server time out')}
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Delay')}</label>
<div class="col-md-6">
<select class="form-control" name="delay" id="delay">
<option value="0" selected>{Lang::T('No Delay')}</option>
<option value="5">{Lang::T('5 Seconds')}</option>
<option value="10">{Lang::T('10 Seconds')}</option>
<option value="15">{Lang::T('15 Seconds')}</option>
<option value="20">{Lang::T('20 Seconds')}</option>
</select>{Lang::T('Use at least 5 secs if you are sending to all customers to avoid being banned by your message provider')}
</div>
</div>
<div class="form-group"> <div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Message')}</label> <label class="col-md-2 control-label">{Lang::T('Message')}</label>
<div class="col-md-6"> <div class="col-md-6">
<textarea class="form-control" id="message" name="message" <textarea class="form-control" id="message" name="message"
placeholder="{Lang::T('Compose your message...')}" rows="5"></textarea> placeholder="{Lang::T('Compose your message...')}" rows="5"></textarea>
<input name="test" type="checkbox"> {Lang::T('Testing [if checked no real message is sent]')}
</div> </div>
<p class="help-block col-md-4"> <p class="help-block col-md-4">
{Lang::T('Use placeholders:')} {Lang::T('Use placeholders:')}
@ -45,10 +75,10 @@
<b>[[company_name]]</b> - {Lang::T('Your Company Name')} <b>[[company_name]]</b> - {Lang::T('Your Company Name')}
</p> </p>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="col-lg-offset-2 col-lg-10"> <div class="col-lg-offset-2 col-lg-10">
<button class="btn btn-success" type="submit">{Lang::T('Send Message')}</button> <button class="btn btn-success" type="submit" name=send value=now>
{Lang::T('Send Message')}</button>
<a href="{$_url}dashboard" class="btn btn-default">{Lang::T('Cancel')}</a> <a href="{$_url}dashboard" class="btn btn-default">{Lang::T('Cancel')}</a>
</div> </div>
</div> </div>
@ -59,5 +89,54 @@
</div> </div>
</div> </div>
{if $batchStatus}
<p><span class="label label-success">Total SMS Sent: {$totalSMSSent}</span> <span class="label label-danger">Total SMS
Failed: {$totalSMSFailed}</span> <span class="label label-success">Total WhatsApp Sent:
{$totalWhatsappSent}</span> <span class="label label-danger">Total WhatsApp Failed:
{$totalWhatsappFailed}</span></p>
{/if}
<div class="box">
<div class="box-header">
<h3 class="box-title">Message Results</h3>
</div>
<!-- /.box-header -->
<div class="box-body">
<table id="messageResultsTable" class="table table-bordered table-striped table-condensed">
<thead>
<tr>
<th>Name</th>
<th>Phone</th>
<th>Message</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{foreach $batchStatus as $customer}
<tr>
<td>{$customer.name}</td>
<td>{$customer.phone}</td>
<td>{$customer.message}</td>
<td>{$customer.status}</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
<!-- /.box-body -->
</div>
<!-- /.box -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.datatables.net/1.11.3/js/jquery.dataTables.min.js"></script>
<script>
var $j = jQuery.noConflict();
$j(document).ready(function () {
$j('#messageResultsTable').DataTable();
});
</script>
{include file="sections/footer.tpl"} {include file="sections/footer.tpl"}

20
ui/ui/pagination.tpl Normal file
View File

@ -0,0 +1,20 @@
{if $paginator}
<nav aria-label="Page navigation pagination-sm">
<ul class="pagination">
<li {if empty($paginator['prev'])}class="disabled" {/if}>
<a href="{$paginator['url']}{$paginator['prev']}" aria-label="Previous">
<span aria-hidden="true">{Lang::T('Prev')}</span>
</a>
</li>
{foreach $paginator['pages'] as $page}
<li class="{if $paginator['page'] == $page}active{elseif $page == '...'}disabled{/if}"><a
href="{$paginator['url']}{$page}">{$page}</a></li>
{/foreach}
<li {if $paginator['page']>=$paginator['count']}class="disabled" {/if}>
<a href="{$paginator['url']}{$paginator['next']}" aria-label="Next">
<span aria-hidden="true">{Lang::T('Next')}</span>
</a>
</li>
</ul>
</nav>
{/if}

View File

@ -79,7 +79,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
{$paginator['contents']} {include file="pagination.tpl"}
</div> </div>
</div> </div>
</div> </div>

View File

@ -61,7 +61,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
{$paginator['contents']} {include file="pagination.tpl"}
</div> </div>
</div> </div>
</div> </div>

View File

@ -82,7 +82,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
{$paginator['contents']} {include file="pagination.tpl"}
</div> </div>
</div> </div>
</div> </div>

View File

@ -64,7 +64,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
{$paginator['contents']} {include file="pagination.tpl"}
</div> </div>
</div> </div>
</div> </div>

View File

@ -61,7 +61,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
{$paginator['contents']} {include file="pagination.tpl"}
</div> </div>
</div> </div>
</div> </div>

View File

@ -51,7 +51,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
{$paginator['contents']} {include file="pagination.tpl"}
<div class="clearfix text-right total-sum mb10"> <div class="clearfix text-right total-sum mb10">
<h4 class="text-uppercase text-bold">{Lang::T('Total Income')}:</h4> <h4 class="text-uppercase text-bold">{Lang::T('Total Income')}:</h4>

View File

@ -61,7 +61,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
{$paginator['contents']} {include file="pagination.tpl"}
</div> </div>
</div> </div>
</div> </div>

View File

@ -34,7 +34,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
{$paginator['contents']} {include file="pagination.tpl"}
</div> </div>
</div> </div>
</div> </div>

View File

@ -46,7 +46,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
{$paginator['contents']} {include file="pagination.tpl"}
</div> </div>
</div> </div>
</div> </div>

View File

@ -71,7 +71,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
{$paginator['contents']} {include file="pagination.tpl"}
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,3 +1,3 @@
{ {
"version": "2024.3.20" "version": "2024.3.26"
} }