Compare commits

...

49 Commits

Author SHA1 Message Date
de85d30a9e Fix view order if it not unpaid 2024-08-02 16:03:20 +07:00
82904b9302 check master or main 2024-08-02 15:48:31 +07:00
face1dfa57 send expired date to telegram when customer recharge 2024-08-02 10:28:34 +07:00
7e5a718ba8 balance send to email 2024-08-02 10:24:24 +07:00
c2fffdab88 plugin manager detect old installation file 2024-08-02 10:24:11 +07:00
9578006e11 add required field for installation 2024-08-02 09:42:09 +07:00
828ad7f880 Fix locked out bug 2024-08-01 21:25:14 +07:00
ed4bd4861a Fix sync Bug 2024-08-01 20:21:58 +07:00
b64e841bde Payment Gateway Audit page 2024-08-01 17:55:58 +07:00
efdb0fc6bc show paid plugin 2024-08-01 13:39:40 +07:00
0b5c24239d Customer can sync plan 2024-08-01 11:08:01 +07:00
a5971bfff3 show bandwidth plan 2024-08-01 11:05:40 +07:00
aac8306d7b disconnect PPPOE when plan change 2024-08-01 10:12:54 +07:00
721ef32e12 continue activate package, when it cannot connect to Device, let admin sync it manual 2024-08-01 09:25:13 +07:00
67e383375e still error, why 2024-07-31 22:09:46 +07:00
4434e7d217 session_timeout_duration make crash when no data 2024-07-31 22:04:28 +07:00
fc6cd59ea0 critical fix operand when save settings 2024-07-31 22:01:01 +07:00
608c9e5b6f Merge pull request #227 from Focuslinkstech/master
add url to default welcome message
2024-07-31 16:07:46 +07:00
d494df3321 Merge branch 'hotspotbilling:master' into master 2024-07-31 10:00:05 +01:00
9ec0148800 Update notifications.default.json 2024-07-31 09:59:06 +01:00
deb6cceeb9 Merge branch 'Development' 2024-07-31 15:57:51 +07:00
210178be84 Fix Show additional Bill when customer order 2024-07-31 15:57:43 +07:00
063ae834bc update tbl_payment_gateway to support Stripe 2024-07-31 15:56:00 +07:00
4c65248823 Show Additional bills when select gateway 2024-07-31 15:55:59 +07:00
c417fe63e2 update tbl_payment_gateway to support Stripe 2024-07-31 15:55:15 +07:00
6ca5054fe8 Merge pull request #226 from Focuslinkstech/master
Add send welcome message
2024-07-31 15:54:40 +07:00
0bcac10eec Merge branch 'master' of https://github.com/Focuslinkstech/phpnuxbill 2024-07-31 09:50:03 +01:00
ada529ce97 Show Additional bills when select gateway 2024-07-31 13:42:19 +07:00
8e55330bcb Add send welcome message
send welcome message to new  registered customers.

Goto settings -> User Notification -> Welcome Message to setup message
2024-07-31 00:57:53 +01:00
eca40e0faf if trx status already 2, don't proceed 2024-07-29 16:21:01 +07:00
8e1d608e5f fix compability 2024-07-29 16:20:27 +07:00
50b4db1723 update docs 2024-07-29 14:28:03 +07:00
b3e97ecf6d fix inactive customer and check enable_balance 2024-07-29 14:12:26 +07:00
a85e9ee95a Merge branch 'Development' 2024-07-29 11:18:45 +07:00
fa154b007f change $db_password to $db_pass 2024-07-29 09:06:27 +07:00
3b9c5d16f8 2024.7.27
fix logic bug
2024-07-29 08:59:39 +07:00
dd7f9dc94e let the device decide again 2024-07-29 08:59:39 +07:00
2a9b50e015 Merge pull request #225 from Focuslinkstech/master
Add session expiration settings
2024-07-29 08:59:12 +07:00
1c0ff671a5 Merge pull request #224 from Focuslinkstech/master
Update Radius.php
2024-07-29 08:57:49 +07:00
bd48bb0591 2024.7.27
fix logic bug
2024-07-27 23:47:38 +07:00
278def959b let the device decide again 2024-07-27 22:57:45 +07:00
5a47da013b Add session expiration settings
You can now set session expiration in settings -> General Settings -> Miscellaneous

if admin is Idles for more than minutes set, he will required to login again, just for account security concerns.

you can enable or disable
2024-07-27 00:56:48 +01:00
282bf6190c Update Radius.php
Fix Radius Delete Plan
2024-07-26 18:21:48 +01:00
2f1ee0cfbf Merge pull request #223 from Focuslinkstech/master
Update Package.php and devices/Radius.php
2024-07-26 16:07:30 +07:00
5783ea05f9 show Total Customer Balance 2024-07-26 15:55:17 +07:00
5ca81ea92e hide and unhide github token 2024-07-26 15:55:01 +07:00
6496f49df6 Report only show to admin and report user 2024-07-26 15:54:39 +07:00
7d3afa091f Bugs Fix
lots has been done that i cant even recalled, but i think all identify bugs is fix, i urge you all to give it test and report any issues arising.
2024-07-26 09:49:52 +01:00
cc68770f51 remove check change plan, let the device decide 2024-07-25 17:13:18 +07:00
41 changed files with 1225 additions and 412 deletions

View File

@ -2,6 +2,11 @@
# CHANGELOG
## 2024.8.1
- Show Bandwidth Plan in the customer dashboard
- Show
## 2024.7.23
- add Voucher Used Date

View File

@ -1,16 +1,18 @@
<?php
$db_host = "localhost"; # Database Host
$db_port = ""; # Database Port. Keep it blank if you are un sure.
$db_user = "root"; # Database Username
$db_password = ""; # Database Password
$db_name = "phpnuxbill"; # Database Name
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
$host = $_SERVER['HTTP_HOST'];
$baseDir = rtrim(dirname($_SERVER['SCRIPT_NAME']), '/\\');
define('APP_URL', $protocol . $host . $baseDir);
#Please include http and do not use trailing slash after the url. For example use in this format- http://www.example.com Or http://www.example.com/finance
$_app_stage = 'Live'; # Do not change this
$db_host = "localhost"; # Database Host
$db_port = ""; # Database Port. Keep it blank if you are un sure.
$db_user = "root"; # Database Username
$db_pass = ""; # Database Password
$db_name = "phpnuxbill"; # Database Name

File diff suppressed because one or more lines are too long

View File

@ -67,10 +67,14 @@ require_once $root_path . File::pathFixer('system/orm.php');
require_once $root_path . File::pathFixer('system/autoload/PEAR2/Autoload.php');
include $root_path . File::pathFixer('system/autoload/Hookers.php');
if(!empty($db_password)){
if($db_password != null && ($db_pass == null || empty($db_pass))){
// compability for old version
$db_pass = $db_password;
}
if($db_pass != null){
// compability for old version
$db_password = $db_pass;
}
ORM::configure("mysql:host=$db_host;dbname=$db_name");
ORM::configure('username', $db_user);
ORM::configure('password', $db_pass);
@ -329,7 +333,7 @@ function _alert($text, $type = 'success', $url = "home", $time = 3)
if (!isset($api_secret)) {
$api_secret = $db_password;
$api_secret = $db_pass;
}
function displayMaintenanceMessage(): void

View File

@ -70,13 +70,13 @@ CREATE TABLE `tbl_payment_gateway` (
`id` int NOT NULL,
`username` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`gateway` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'xendit | midtrans',
`gateway_trx_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`gateway_trx_id` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`plan_id` int NOT NULL,
`plan_name` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`routers_id` int NOT NULL,
`routers` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`price` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`pg_url_payment` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`pg_url_payment` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`payment_method` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`payment_channel` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`pg_request` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,

View File

@ -42,20 +42,20 @@
</div>
<div class="form-group">
<label for="dbhost">Database Host</label>
<input type="text" class="form-control" id="dbhost" name="dbhost">
<input type="text" class="form-control" id="dbhost" required name="dbhost">
</div>
<div class="form-group">
<label for="dbuser">Database Username</label>
<input type="text" class="form-control" id="dbuser" name="dbuser">
<input type="text" class="form-control" id="dbuser" required name="dbuser">
</div>
<div class="form-group">
<label for="dbpass">Database Password</label>
<input type="text" class="form-control" id="dbpass" name="dbpass">
<input type="text" class="form-control" id="dbpass" required name="dbpass">
</div>
<div class="form-group">
<label for="dbname">Database Name</label>
<input type="text" class="form-control" id="dbname" name="dbname">
<input type="text" class="form-control" id="dbname" required name="dbname">
</div>
<div class="form-group">

View File

@ -9,14 +9,14 @@
$appurl = $_POST['appurl'];
$db_host = $_POST['dbhost'];
$db_user = $_POST['dbuser'];
$db_password = $_POST['dbpass'];
$db_pass = $_POST['dbpass'];
$db_name = $_POST['dbname'];
$cn = '0';
try {
$dbh = new pdo(
"mysql:host=$db_host;dbname=$db_name",
"$db_user",
"$db_password",
"$db_pass",
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)
);
$cn = '1';
@ -39,13 +39,13 @@ $_app_stage = "Live";
// Database PHPNuxBill
$db_host = "' . $db_host . '";
$db_user = "' . $db_user . '";
$db_pass = "' . $db_password . '";
$db_pass = "' . $db_pass . '";
$db_name = "' . $db_name . '";
// Database Radius
$radius_host = "' . $db_host . '";
$radius_user = "' . $db_user . '";
$radius_pass = "' . $db_password . '";
$radius_pass = "' . $db_pass . '";
$radius_name = "' . $db_name . '";
if($_app_stage!="Live"){
@ -70,7 +70,7 @@ $_app_stage = "Live";
// Database PHPNuxBill
$db_host = "' . $db_host . '";
$db_user = "' . $db_user . '";
$db_pass = "' . $db_password . '";
$db_pass = "' . $db_pass . '";
$db_name = "' . $db_name . '";
if($_app_stage!="Live"){

View File

@ -26,7 +26,7 @@
try{
$dbh = new pdo( "mysql:host=$db_host;dbname=$db_name",
"$db_user",
"$db_password",
"$db_pass",
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
echo "CREATE TABLE `tbl_payment_gateway` (

View File

@ -11,35 +11,64 @@ class Admin
public static function getID()
{
global $db_password;
if (isset($_SESSION['aid'])) {
global $db_pass, $config;
$enable_session_timeout = $config['enable_session_timeout'];
if ($enable_session_timeout) {
$timeout = 60;
if ($config['session_timeout_duration']) {
$timeout = intval($config['session_timeout_duration']);
}
$session_timeout_duration = $timeout * 60; // Convert minutes to seconds
}
if (isset($_SESSION['aid']) && isset($_SESSION['aid_expiration']) && $_SESSION['aid_expiration'] > time()) {
return $_SESSION['aid'];
} else if (isset($_COOKIE['aid'])) {
} elseif ($enable_session_timeout && isset($_SESSION['aid']) && isset($_SESSION['aid_expiration']) && $_SESSION['aid_expiration'] <= time()) {
self::removeCookie();
session_destroy();
_alert(Lang::T('Session has expired. Please log in again.'), 'danger', "admin");
return 0;
}
// Check if cookie is set and valid
elseif (isset($_COOKIE['aid'])) {
// id.time.sha1
$tmp = explode('.', $_COOKIE['aid']);
if (sha1($tmp[0] . '.' . $tmp[1] . '.' . $db_password) == $tmp[2]) {
if (sha1($tmp[0] . '.' . $tmp[1] . '.' . $db_pass) == $tmp[2]) {
if (time() - $tmp[1] < 86400 * 7) {
$_SESSION['aid'] = $tmp[0];
if ($enable_session_timeout) {
$_SESSION['aid_expiration'] = time() + $session_timeout_duration;
}
return $tmp[0];
}
}
}
return 0;
}
public static function setCookie($aid)
{
global $db_password;
global $db_pass, $config;
$enable_session_timeout = $config['enable_session_timeout'];
if (isset($aid)) {
$time = time();
$token = $aid . '.' . $time . '.' . sha1($aid . '.' . $time . '.' . $db_password);
$token = $aid . '.' . $time . '.' . sha1($aid . '.' . $time . '.' . $db_pass);
setcookie('aid', $token, time() + 86400 * 7);
$_SESSION['aid'] = $aid;
if ($enable_session_timeout) {
$timeout = 60;
if ($config['session_timeout_duration']) {
$timeout = intval($config['session_timeout_duration']);
}
$session_timeout_duration = $timeout * 60; // Convert minutes to seconds
$_SESSION['aid_expiration'] = $time + $session_timeout_duration;
}
return $token;
}
return '';
}
public static function removeCookie()
{
if (isset($_COOKIE['aid'])) {

View File

@ -11,7 +11,7 @@ class Lang
public static function T($key)
{
global $_L, $lan_file, $config;
if(is_array($_SESSION['Lang'])){
if (is_array($_SESSION['Lang'])) {
$_L = array_merge($_L, $_SESSION['Lang']);
}
$key = preg_replace('/\s+/', ' ', $key);
@ -124,20 +124,20 @@ class Lang
}
}
$when = "";
if(time()>strtotime($datetime)){
if (time() > strtotime($datetime)) {
$when = Lang::T('ago');
}else{
} else {
$when = '';
}
if (!$full)
$string = array_slice($string, 0, 1);
if($string){
if(empty($when)){
return '<b>'. implode(', ', $string) .'</b>';
}else{
return implode(', ', $string) .' '. $when;
if ($string) {
if (empty($when)) {
return '<b>' . implode(', ', $string) . '</b>';
} else {
return implode(', ', $string) . ' ' . $when;
}
}else{
} else {
return Lang::T('just now');
}
}
@ -245,16 +245,30 @@ class Lang
return $txt;
}
public static function maskText($text){
public static function maskText($text)
{
$len = strlen($text);
if($len < 3){
if ($len < 3) {
return "***";
}else if($len<5){
return substr($text,0,1)."***".substr($text,-1,1);
}else if($len<8){
return substr($text,0,2)."***".substr($text,-2,2);
}else{
return substr($text,0,4)."******".substr($text,-3,3);
} else if ($len < 5) {
return substr($text, 0, 1) . "***" . substr($text, -1, 1);
} else if ($len < 8) {
return substr($text, 0, 2) . "***" . substr($text, -2, 2);
} else {
return substr($text, 0, 4) . "******" . substr($text, -3, 3);
}
}
// echo Json array to text
public static function jsonArray2text($array, $start = '', $result = '')
{
foreach ($array as $k => $v) {
if (is_array($v)) {
$result .= self::jsonArray2text($v, "$start$k.", '');
} else {
$result .= "$start$k = " . strval($v) . "\n";
}
}
return $result;
}
}

View File

@ -20,7 +20,7 @@ class Package
*/
public static function rechargeUser($id_customer, $router_name, $plan_id, $gateway, $channel, $note = '')
{
global $config, $admin, $c, $p, $b, $t, $d, $zero, $trx, $_app_stage;
global $config, $admin, $c, $p, $b, $t, $d, $zero, $trx, $_app_stage, $isChangePlan;
$date_now = date("Y-m-d H:i:s");
$date_only = date("Y-m-d");
$time_only = date("H:i:s");
@ -29,21 +29,26 @@ class Package
$isVoucher = false;
$c = [];
if ($trx && $trx['status'] == 2) {
// if its already paid, return it
return;
}
if ($id_customer == '' or $router_name == '' or $plan_id == '') {
return false;
}
if(trim($gateway) == 'Voucher' && $id_customer == 0){
if (trim($gateway) == 'Voucher' && $id_customer == 0) {
$isVoucher = true;
}
$p = ORM::for_table('tbl_plans')->where('id', $plan_id)->find_one();
if(!$isVoucher){
if (!$isVoucher) {
$c = ORM::for_table('tbl_customers')->where('id', $id_customer)->find_one();
if ($c['status'] != 'Active') {
_alert(Lang::T('This account status') . ' : ' . Lang::T($c['status']), 'danger', "");
}
}else{
} else {
$c = [
'fullname' => $gateway,
'email' => '',
@ -82,7 +87,7 @@ class Package
// if customer has attribute Expired Date use it
$day_exp = User::getAttribute("Expired Date", $c['id']);
if (!$day_exp) {
// if customer no attribute Expired Date use plan expired date
// if customer no attribute Expired Date use plan expired date
$day_exp = 20;
if ($p['prepaid'] == 'no') {
$day_exp = $p['expired_date'];
@ -142,6 +147,8 @@ class Package
Message::sendSMS($c['phonenumber'], $textInvoice);
} else if ($config['user_notification_payment'] == 'wa') {
Message::sendWhatsapp($c['phonenumber'], $textInvoice);
} else if ($config['user_notification_payment'] == 'email') {
Message::sendEmail($c['email'], '[' . $config['CompanyName'] . '] ' . Lang::T("Invoice") . ' ' . $inv ,$textInvoice);
}
return true;
@ -173,9 +180,9 @@ class Package
# because 1 customer can have 1 PPPOE and 1 Hotspot Plan in mikrotik
//->where('prepaid', $p['prepaid'])
->left_outer_join('tbl_plans', array('tbl_plans.id', '=', 'tbl_user_recharges.plan_id'));
if($isVoucher){
if ($isVoucher) {
$query->where('username', $c['username']);
}else{
} else {
$query->where('customer_id', $id_customer);
}
$b = $query->find_one();
@ -209,13 +216,10 @@ class Package
$date_exp = $datetime[0];
$time = $datetime[1];
}
$isChangePlan = false;
if ($b) {
// plan exists
if ($plan_id != $b['plan_id']) {
$isChangePlan = true;
}
$lastExpired = Lang::dateAndTimeFormat($b['expiration'], $b['time']);
$isChangePlan = false;
if ($config['extend_expiry'] != 'no') {
if ($b['namebp'] == $p['name_plan'] && $b['status'] == 'on') {
// if it same internet plan, expired will extend
@ -237,20 +241,42 @@ class Package
$date_exp = $datetime[0];
$time = $datetime[1];
}
} else {
$isChangePlan = true;
}
}
if ($isChangePlan || $b['status'] == 'off') {
$dvc = Package::getDevice($p);
if ($_app_stage != 'demo') {
//if ($b['status'] == 'on') {
$dvc = Package::getDevice($p);
if ($_app_stage != 'demo') {
try {
if (file_exists($dvc)) {
require_once $dvc;
(new $p['device'])->add_customer($c, $p);
} else {
new Exception(Lang::T("Devices Not Found"));
}
} catch (Throwable $e) {
Message::sendTelegram(
"Sistem Error. When activate Package. You need to sync manually\n" .
"Router: $router_name\n" .
"Customer: u$c[username]\n" .
"Plan: p$p[name_plan]\n" .
$e->getMessage() . "\n" .
$e->getTraceAsString()
);
} catch (Exception $e) {
Message::sendTelegram(
"Sistem Error. When activate Package. You need to sync manually\n" .
"Router: $router_name\n" .
"Customer: u$c[username]\n" .
"Plan: p$p[name_plan]\n" .
$e->getMessage() . "\n" .
$e->getTraceAsString()
);
}
}
//}
$b->customer_id = $id_customer;
$b->username = $c['username'];
@ -322,17 +348,39 @@ class Package
"\nRouter: " . $router_name .
"\nGateway: " . $gateway .
"\nChannel: " . $channel .
"\nLast Expired: $lastExpired" .
"\nNew Expired: " . Lang::dateAndTimeFormat($date_exp, $time).
"\nPrice: " . Lang::moneyFormat($p['price'] + $add_cost) .
"\nNote:\n" . $note);
} else {
// active plan not exists
$dvc = Package::getDevice($p);
if ($_app_stage != 'demo') {
if (file_exists($dvc)) {
require_once $dvc;
(new $p['device'])->add_customer($c, $p);
} else {
new Exception(Lang::T("Devices Not Found"));
try {
if (file_exists($dvc)) {
require_once $dvc;
(new $p['device'])->add_customer($c, $p);
} else {
new Exception(Lang::T("Devices Not Found"));
}
} catch (Throwable $e) {
Message::sendTelegram(
"Sistem Error. When activate Package. You need to sync manually\n" .
"Router: $router_name\n" .
"Customer: u$c[username]\n" .
"Plan: p$p[name_plan]\n" .
$e->getMessage() . "\n" .
$e->getTraceAsString()
);
} catch (Exception $e) {
Message::sendTelegram(
"Sistem Error. When activate Package. You need to sync manually\n" .
"Router: $router_name\n" .
"Customer: u$c[username]\n" .
"Plan: p$p[name_plan]\n" .
$e->getMessage() . "\n" .
$e->getTraceAsString()
);
}
}
@ -414,6 +462,7 @@ class Package
"\nRouter: " . $router_name .
"\nGateway: " . $gateway .
"\nChannel: " . $channel .
"\nExpired: " . Lang::dateAndTimeFormat($date_exp, $time).
"\nPrice: " . Lang::moneyFormat($p['price'] + $add_cost) .
"\nNote:\n" . $note);
}
@ -558,10 +607,10 @@ class Package
public static function getDevice($plan)
{
global $DEVICE_PATH;
if($plan === false){
if ($plan === false) {
return "none";
}
if(!isset($plan['device'])){
if (!isset($plan['device'])) {
return "none";
}
if (!empty($plan['device'])) {

View File

@ -10,13 +10,13 @@ class User
{
public static function getID()
{
global $db_password;
global $db_pass;
if (isset($_SESSION['uid']) && !empty($_SESSION['uid'])) {
return $_SESSION['uid'];
} else if (isset($_COOKIE['uid'])) {
// id.time.sha1
$tmp = explode('.', $_COOKIE['uid']);
if (sha1($tmp[0] . '.' . $tmp[1] . '.' . $db_password) == $tmp[2]) {
if (sha1($tmp[0] . '.' . $tmp[1] . '.' . $db_pass) == $tmp[2]) {
if (time() - $tmp[1] < 86400 * 30) {
$_SESSION['uid'] = $tmp[0];
return $tmp[0];
@ -159,10 +159,10 @@ class User
public static function setCookie($uid)
{
global $db_password;
global $db_pass;
if (isset($uid)) {
$time = time();
setcookie('uid', $uid . '.' . $time . '.' . sha1($uid . '.' . $time . '.' . $db_password), time() + 86400 * 30);
setcookie('uid', $uid . '.' . $time . '.' . sha1($uid . '.' . $time . '.' . $db_pass), time() + 86400 * 30);
}
}
@ -205,13 +205,14 @@ class User
->select('tbl_user_recharges.id', 'id')
->selects([
'customer_id', 'username', 'plan_id', 'namebp', 'recharged_on', 'recharged_time', 'expiration', 'time',
'status', 'method', 'plan_type',
'status', 'method', 'plan_type', 'name_bw',
['tbl_user_recharges.routers', 'routers'],
['tbl_user_recharges.type', 'type'],
'admin_id', 'prepaid'
])
->where('customer_id', $id)
->left_outer_join('tbl_plans', array('tbl_plans.id', '=', 'tbl_user_recharges.plan_id'))
->left_outer_join('tbl_bandwidth', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))
->find_many();
return $d;
}

View File

@ -149,8 +149,8 @@ switch ($action) {
mkdir($otpPath);
touch($otpPath . 'index.html');
}
$otpFile = $otpPath . sha1($username . $db_password) . ".txt";
$phoneFile = $otpPath . sha1($username . $db_password) . "_phone.txt";
$otpFile = $otpPath . sha1($username . $db_pass) . ".txt";
$phoneFile = $otpPath . sha1($username . $db_pass) . "_phone.txt";
// expired 10 minutes
if (file_exists($otpFile) && time() - filemtime($otpFile) < 1200) {
@ -189,8 +189,8 @@ switch ($action) {
}
if (!empty($config['sms_url'])) {
$otpFile = $otpPath . sha1($username . $db_password) . ".txt";
$phoneFile = $otpPath . sha1($username . $db_password) . "_phone.txt";
$otpFile = $otpPath . sha1($username . $db_pass) . ".txt";
$phoneFile = $otpPath . sha1($username . $db_pass) . "_phone.txt";
// Check if OTP file exists
if (!file_exists($otpFile)) {

View File

@ -21,21 +21,26 @@ switch ($action) {
$p = ORM::for_table('tbl_plans')->find_one($bill['plan_id']);
$dvc = Package::getDevice($p);
if ($_app_stage != 'demo') {
if (file_exists($dvc)) {
require_once $dvc;
if ((new $p['device'])->online_customer($user, $bill['routers'])) {
die('<a href="' . U . 'home&mikrotik=logout&id=' . $bill['id'] . '" onclick="return confirm(\'' . Lang::T('Disconnect Internet?') . '\')" class="btn btn-success btn-xs btn-block">' . Lang::T('You are Online, Logout?') . '</a>');
} else {
if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'])) {
die('<a href="' . U . 'home&mikrotik=login&id=' . $bill['id'] . '" onclick="return confirm(\'' . Lang::T('Connect to Internet?') . '\')" class="btn btn-danger btn-xs btn-block">' . Lang::T('Not Online, Login now?') . '</a>');
try{
if (file_exists($dvc)) {
require_once $dvc;
if ((new $p['device'])->online_customer($user, $bill['routers'])) {
die('<a href="' . U . 'home&mikrotik=logout&id=' . $bill['id'] . '" onclick="return confirm(\'' . Lang::T('Disconnect Internet?') . '\')" class="btn btn-success btn-xs btn-block">' . Lang::T('You are Online, Logout?') . '</a>');
} else {
die(Lang::T('-'));
if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'])) {
die('<a href="' . U . 'home&mikrotik=login&id=' . $bill['id'] . '" onclick="return confirm(\'' . Lang::T('Connect to Internet?') . '\')" class="btn btn-danger btn-xs btn-block">' . Lang::T('Not Online, Login now?') . '</a>');
} else {
die(Lang::T('-'));
}
}
} else {
die(Lang::T('-'));
}
} else {
new Exception(Lang::T("Devices Not Found"));
}catch (Exception $e) {
die(Lang::T('Failed to connect to device'));
}
}
die(Lang::T('-'));
} else {
die('--');
}

View File

@ -432,6 +432,47 @@ switch ($action) {
}
}
}
// Send welcome message
if (isset($_POST['send_welcome_message']) && $_POST['send_welcome_message'] == true) {
$welcomeMessage = Lang::getNotifText('welcome_message');
$welcomeMessage = str_replace('[[company_name]]', $config['CompanyName'], $welcomeMessage);
$welcomeMessage = str_replace('[[name]]', $d['fullname'], $welcomeMessage);
$welcomeMessage = str_replace('[[username]]', $d['username'], $welcomeMessage);
$welcomeMessage = str_replace('[[password]]', $d['password'], $welcomeMessage);
$welcomeMessage = str_replace('[[url]]', APP_URL . '/index.php?_route=login', $welcomeMessage);
$emailSubject = "Welcome to " . $config['CompanyName'];
$channels = [
'sms' => [
'enabled' => isset($_POST['sms']),
'method' => 'sendSMS',
'args' => [$d['phonenumber'], $welcomeMessage]
],
'whatsapp' => [
'enabled' => isset($_POST['wa']) && $_POST['wa'] == 'wa',
'method' => 'sendWhatsapp',
'args' => [$d['phonenumber'], $welcomeMessage]
],
'email' => [
'enabled' => isset($_POST['email']),
'method' => 'Message::sendEmail',
'args' => [$d['email'], $emailSubject, $welcomeMessage, $d['email']]
]
];
foreach ($channels as $channel => $message) {
if ($message['enabled']) {
try {
call_user_func_array($message['method'], $message['args']);
} catch (Exception $e) {
// Log the error and handle the failure
_log("Failed to send welcome message via $channel: " . $e->getMessage());
}
}
}
}
r2(U . 'customers/list', 's', Lang::T('Account Created Successfully'));
} else {
r2(U . 'customers/add', 'e', $msg);

View File

@ -55,6 +55,11 @@ if ($imonth == '') {
}
$ui->assign('imonth', $imonth);
if ($config['enable_balance'] == 'yes'){
$cb = ORM::for_table('tbl_customers')->whereGte('balance', 0)->sum('balance');
$ui->assign('cb', $cb);
}
$u_act = ORM::for_table('tbl_user_recharges')->where('status', 'on')->count();
if (empty($u_act)) {
$u_act = '0';

View File

@ -94,8 +94,37 @@ if (_post('send') == 'balance') {
}
r2(U . 'home', 'w', Lang::T('Your friend do not have active package'));
}
$_bill = User::_billing();
$ui->assign('_bills', $_bill);
$ui->assign('_bills', User::_billing());
// Sync plan to router
if (isset($_GET['sync']) && !empty($_GET['sync'])) {
foreach ($_bill as $tur) {
if($tur['status'] == 'on'){
$p = ORM::for_table('tbl_plans')->findOne($tur['plan_id']);
if ($p) {
$c = ORM::for_table('tbl_customers')->findOne($tur['customer_id']);
if ($c) {
$dvc = Package::getDevice($p);
if ($_app_stage != 'demo') {
if (file_exists($dvc)) {
require_once $dvc;
(new $p['device'])->add_customer($c, $p);
} else {
new Exception(Lang::T("Devices Not Found"));
}
}
$log .= "DONE : $ptur[namebp], $tur[type], $tur[routers]<br>";
} else {
$log .= "Customer NOT FOUND : $tur[namebp], $tur[type], $tur[routers]<br>";
}
} else {
$log .= "PLAN NOT FOUND : $tur[namebp], $tur[type], $tur[routers]<br>";
}
}
}
r2(U . 'home', 's', $log);
}
if (isset($_GET['recharge']) && !empty($_GET['recharge'])) {
if ($user['status'] != 'Active') {

View File

@ -103,7 +103,7 @@ switch ($action) {
r2(U . "order/package", 'w', Lang::T("Payment not found"));
}
// jika url kosong, balikin ke buy, kecuali cancel
if (empty($trx['pg_url_payment']) && $routes['3'] != 'cancel') {
if ($trx['status'] == 1 && 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"));
}
if ($routes['3'] == 'check') {
@ -345,7 +345,11 @@ switch ($action) {
$tax_rate = $tax_rate_setting;
}
$plan = ORM::for_table('tbl_plans')->find_one($routes['3']);
$tax = Package::tax($plan['price'], $tax_rate);
$add_cost = 0;
if ($router['name'] != 'balance') {
list($bills, $add_cost) = User::getBills($id_customer);
}
$tax = Package::tax($plan['price'] + $add_cost, $tax_rate);
$pgs = array_values(explode(',', $config['payment_gateway']));
if (count($pgs) == 0) {
sendTelegram("Payment Gateway not set, please set it in Settings");
@ -359,6 +363,8 @@ switch ($action) {
}
$ui->assign('route2', $routes[2]);
$ui->assign('route3', $routes[3]);
$ui->assign('add_cost', $add_cost);
$ui->assign('bills', $bills);
$ui->assign('plan', $plan);
$ui->display('user-selectGateway.tpl');
break;
@ -454,7 +460,6 @@ switch ($action) {
} else {
$d->price = ($plan['price'] + $add_cost + $tax);
}
//$d->price = ($plan['price'] + $add_cost);
$d->created_date = date('Y-m-d H:i:s');
$d->status = 1;
$d->save();

View File

@ -19,6 +19,36 @@ if ($action == 'delete') {
r2(U . 'paymentgateway', 's', Lang::T('Payment Gateway Deleted'));
}
if ($action == 'audit') {
$pg = alphanumeric($routes[2]);
$q = alphanumeric(_req('q'),'-._ ');
$query = ORM::for_table('tbl_payment_gateway')->order_by_desc("id");
$query->selects('id', 'username', 'gateway', 'gateway_trx_id', 'plan_id', 'plan_name', 'routers_id', 'routers', 'price', 'pg_url_payment', 'payment_method', 'payment_channel', 'expired_date', 'created_date', 'paid_date', 'trx_invoice', 'status');
$query->where('gateway', $pg);
if(!empty($q)) {
$query->whereRaw("(gateway_trx_id LIKE '%$q%' OR username LIKE '%$q%' OR routers LIKE '%$q%' OR plan_name LIKE '%$q%')");
$append_url = 'q='. urlencode($q);
}
$pgs = Paginator::findMany($query, ["search" => $search], 50, $append_url);
$ui->assign('_title', 'Payment Gateway Audit');
$ui->assign('pgs', $pgs);
$ui->assign('pg', $pg);
$ui->assign('q', $q);
$ui->display('paymentgateway-audit.tpl');
die();
}
if ($action == 'auditview') {
$pg = alphanumeric($routes[2]);
$d = ORM::for_table('tbl_payment_gateway')->find_one($pg);
$ui->assign('_title', 'Payment Gateway Audit View');
$ui->assign('pg', $d);
$ui->display('paymentgateway-audit-view.tpl');
die();
}
if (_post('save') == 'actives') {
$pgs = '';
if(is_array($_POST['pgs'])){

View File

@ -38,7 +38,7 @@ switch ($action) {
r2(U . "pluginmanager", 's', 'Refresh success');
break;
case 'dlinstall':
if($_app_stage == 'demo'){
if ($_app_stage == 'demo') {
r2(U . "pluginmanager", 'e', 'Demo Mode cannot install as it Security risk');
}
if (!is_writeable($CACHE_PATH)) {
@ -62,27 +62,46 @@ switch ($action) {
$zip->open($_FILES['zip_plugin']['tmp_name']);
$zip->extractTo($cache);
$zip->close();
$plugin = basename($_FILES['zip_plugin']['name']);
unlink($_FILES['zip_plugin']['tmp_name']);
$success = 0;
//moving
if (file_exists($cache . 'plugin')) {
File::copyFolder($cache . 'plugin' . DIRECTORY_SEPARATOR, $PLUGIN_PATH . DIRECTORY_SEPARATOR);
$success++;
}
if (file_exists($cache . 'paymentgateway')) {
File::copyFolder($cache . 'paymentgateway' . DIRECTORY_SEPARATOR, $PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR);
$success++;
}
if (file_exists($cache . 'theme')) {
File::copyFolder($cache . 'theme' . DIRECTORY_SEPARATOR, $UI_PATH . DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR);
$success++;
}
if (file_exists($cache . 'device')) {
File::copyFolder($cache . 'device' . DIRECTORY_SEPARATOR, $DEVICE_PATH . DIRECTORY_SEPARATOR);
$success++;
}
if ($success == 0) {
// old plugin and theme using this
$check = strtolower($ghUrl);
if (strpos($check, 'plugin') !== false) {
File::copyFolder($folder, $PLUGIN_PATH . DIRECTORY_SEPARATOR);
} else if (strpos($check, 'payment') !== false) {
File::copyFolder($folder, $PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR);
} else if (strpos($check, 'theme') !== false) {
rename($folder, $UI_PATH . DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR . $plugin);
} else if (strpos($check, 'device') !== false) {
File::copyFolder($folder, $DEVICE_PATH . DIRECTORY_SEPARATOR);
}
}
//Cleaning
File::deleteFolder($cache);
r2(U . "pluginmanager", 's', 'Installation success');
} else if (_post('gh_url', '') != '') {
$ghUrl = _post('gh_url', '');
if(!empty($config['github_token']) && !empty($config['github_username'])) {
$ghUrl = str_replace('https://github.com', 'https://'.$config['github_username'].':'.$config['github_token'].'@github.com', $ghUrl);
if (!empty($config['github_token']) && !empty($config['github_username'])) {
$ghUrl = str_replace('https://github.com', 'https://' . $config['github_username'] . ':' . $config['github_token'] . '@github.com', $ghUrl);
}
$plugin = basename($ghUrl);
$file = $cache . $plugin . '.zip';
@ -102,17 +121,38 @@ switch ($action) {
$zip->extractTo($cache);
$zip->close();
$folder = $cache . DIRECTORY_SEPARATOR . $plugin . '-main' . DIRECTORY_SEPARATOR;
if(!file_exists($folder)) {
$folder = $cache . DIRECTORY_SEPARATOR . $plugin . '-master' . DIRECTORY_SEPARATOR;
}
$success = 0;
if (file_exists($folder . 'plugin')) {
File::copyFolder($folder . 'plugin' . DIRECTORY_SEPARATOR, $PLUGIN_PATH . DIRECTORY_SEPARATOR);
$success++;
}
if (file_exists($folder . 'paymentgateway')) {
File::copyFolder($folder . 'paymentgateway' . DIRECTORY_SEPARATOR, $PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR);
$success++;
}
if (file_exists($folder . 'theme')) {
File::copyFolder($folder . 'theme' . DIRECTORY_SEPARATOR, $UI_PATH . DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR);
$success++;
}
if (file_exists($folder . 'device')) {
File::copyFolder($folder . 'device' . DIRECTORY_SEPARATOR, $DEVICE_PATH . DIRECTORY_SEPARATOR);
$success++;
}
if ($success == 0) {
// old plugin and theme using this
$check = strtolower($ghUrl);
if (strpos($check, 'plugin') !== false) {
File::copyFolder($folder, $PLUGIN_PATH . DIRECTORY_SEPARATOR);
} else if (strpos($check, 'payment') !== false) {
File::copyFolder($folder, $PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR);
} else if (strpos($check, 'theme') !== false) {
rename($folder, $UI_PATH . DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR . $plugin);
} else if (strpos($check, 'device') !== false) {
File::copyFolder($folder, $DEVICE_PATH . DIRECTORY_SEPARATOR);
}
}
File::deleteFolder($cache);
r2(U . "pluginmanager", 's', 'Installation success');
@ -135,8 +175,8 @@ switch ($action) {
if ($tipe == 'plugin') {
foreach ($json['plugins'] as $plg) {
if ($plg['id'] == $plugin) {
if(!empty($config['github_token']) && !empty($config['github_username'])) {
$plg['github'] = str_replace('https://github.com', 'https://'.$config['github_username'].':'.$config['github_token'].'@github.com', $plg['github']);
if (!empty($config['github_token']) && !empty($config['github_username'])) {
$plg['github'] = str_replace('https://github.com', 'https://' . $config['github_username'] . ':' . $config['github_token'] . '@github.com', $plg['github']);
}
$fp = fopen($file, 'w+');
$ch = curl_init($plg['github'] . '/archive/refs/heads/master.zip');
@ -186,8 +226,8 @@ switch ($action) {
if ($tipe == 'plugin') {
foreach ($json['plugins'] as $plg) {
if ($plg['id'] == $plugin) {
if(!empty($config['github_token']) && !empty($config['github_username'])) {
$plg['github'] = str_replace('https://github.com', 'https://'.$config['github_username'].':'.$config['github_token'].'@github.com', $plg['github']);
if (!empty($config['github_token']) && !empty($config['github_username'])) {
$plg['github'] = str_replace('https://github.com', 'https://' . $config['github_username'] . ':' . $config['github_token'] . '@github.com', $plg['github']);
}
$fp = fopen($file, 'w+');
$ch = curl_init($plg['github'] . '/archive/refs/heads/master.zip');
@ -223,8 +263,8 @@ switch ($action) {
} else if ($tipe == 'payment') {
foreach ($json['payment_gateway'] as $plg) {
if ($plg['id'] == $plugin) {
if(!empty($config['github_token']) && !empty($config['github_username'])) {
$plg['github'] = str_replace('https://github.com', 'https://'.$config['github_username'].':'.$config['github_token'].'@github.com', $plg['github']);
if (!empty($config['github_token']) && !empty($config['github_username'])) {
$plg['github'] = str_replace('https://github.com', 'https://' . $config['github_username'] . ':' . $config['github_token'] . '@github.com', $plg['github']);
}
$fp = fopen($file, 'w+');
$ch = curl_init($plg['github'] . '/archive/refs/heads/master.zip');
@ -257,6 +297,43 @@ switch ($action) {
}
}
break;
} else if ($tipe == 'device') {
foreach ($json['devices'] as $d) {
if ($d['id'] == $plugin) {
if (!empty($config['github_token']) && !empty($config['github_username'])) {
$d['github'] = str_replace('https://github.com', 'https://' . $config['github_username'] . ':' . $config['github_token'] . '@github.com', $d['github']);
}
$fp = fopen($file, 'w+');
$ch = curl_init($d['github'] . '/archive/refs/heads/master.zip');
curl_setopt($ch, CURLOPT_POST, 0);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_exec($ch);
curl_close($ch);
fclose($fp);
$zip = new ZipArchive();
$zip->open($file);
$zip->extractTo($CACHE_PATH);
$zip->close();
$folder = $CACHE_PATH . File::pathFixer('/' . $plugin . '-main/');
if (!file_exists($folder)) {
$folder = $CACHE_PATH . File::pathFixer('/' . $plugin . '-master/');
}
if (!file_exists($folder)) {
r2(U . "pluginmanager", 'e', 'Extracted Folder is unknown');
}
File::copyFolder($folder, $DEVICE_PATH . DIRECTORY_SEPARATOR, ['README.md', 'LICENSE']);
File::deleteFolder($folder);
unlink($file);
r2(U . "paymentgateway", 's', 'Payment Gateway ' . $plugin . ' has been installed');
break;
}
}
break;
}
default:
if (class_exists('ZipArchive')) {

View File

@ -46,7 +46,7 @@ switch ($do) {
}
if (!empty($config['sms_url'])) {
$otpPath .= sha1($username . $db_password) . ".txt";
$otpPath .= sha1($username . $db_pass) . ".txt";
run_hook('validate_otp'); #HOOK
//expired 10 minutes
if (file_exists($otpPath) && time() - filemtime($otpPath) > 1200) {
@ -122,7 +122,7 @@ switch ($do) {
mkdir($otpPath);
touch($otpPath . 'index.html');
}
$otpPath .= sha1($username . $db_password) . ".txt";
$otpPath .= sha1($username . $db_pass) . ".txt";
//expired 10 minutes
if (file_exists($otpPath) && time() - filemtime($otpPath) < 1200) {
$ui->assign('username', $username);

View File

@ -155,7 +155,9 @@ switch ($action) {
die();
}
}
// Save all settings including tax system
// Save all settings including tax system
$enable_session_timeout = isset($_POST['enable_session_timeout']) ? 1 : 0;
$_POST['enable_session_timeout'] = $enable_session_timeout;
foreach ($_POST as $key => $value) {
$d = ORM::for_table('tbl_appconfig')->where('setting', $key)->find_one();
if ($d) {
@ -699,7 +701,7 @@ switch ($action) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
$dbc = new mysqli($db_host, $db_user, $db_password, $db_name);
$dbc = new mysqli($db_host, $db_user, $db_pass, $db_name);
if ($result = $dbc->query('SHOW TABLE STATUS')) {
$tables = array();
while ($row = $result->fetch_array()) {

View File

@ -29,6 +29,7 @@ class MikrotikPppoe
function add_customer($customer, $plan)
{
global $isChangePlan;
$mikrotik = $this->info($plan['routers']);
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
//check if customer exists
@ -51,7 +52,9 @@ class MikrotikPppoe
$setRequest->setArgument('password', $pass);
$client->sendSync($setRequest);
//disconnect then
//$this->removePpoeActive($client, $customer['username']);
if(isset($isChangePlan) && $isChangePlan){
$this->removePpoeActive($client, $customer['username']);
}
}
}

View File

@ -28,14 +28,56 @@ class Radius
function add_customer($customer, $plan)
{
$b = ORM::for_table('tbl_user_recharges')
->where('customer_id', $customer['id'])
->where('plan_id', $plan['id'])
->where('status', 'on')
->findMany();
$p = ORM::for_table('tbl_plans')
->where('id', $plan['id'])
->findOne();
if($b){
$this->customerAddPlan($customer, $plan, $b['expiration'] . ' ' . $b['time']);
$date_only = date("Y-m-d");
if ($p['validity_unit'] == 'Period') {
// if customer has attribute Expired Date use it
$day_exp = User::getAttribute("Expired Date", $customer['id']);
if (!$day_exp) {
// if customer no attribute Expired Date use plan expired date
$day_exp = 20;
if ($p['prepaid'] == 'no') {
$day_exp = $p['expired_date'];
}
if (empty($day_exp)) {
$day_exp = 20;
}
}
}
if ($p['validity_unit'] == 'Months') {
$date_exp = date("Y-m-d", strtotime('+' . $p['validity'] . ' month'));
} else if ($p['validity_unit'] == 'Period') {
$date_tmp = date("Y-m-$day_exp", strtotime('+' . $p['validity'] . ' month'));
$dt1 = new DateTime("$date_only");
$dt2 = new DateTime("$date_tmp");
$diff = $dt2->diff($dt1);
$sum = $diff->format("%a"); // => 453
if ($sum >= 35 * $p['validity']) {
$date_exp = date("Y-m-$day_exp", strtotime('+0 month'));
} else {
$date_exp = date("Y-m-$day_exp", strtotime('+' . $p['validity'] . ' month'));
};
$time = date("23:59:00");
} else if ($p['validity_unit'] == 'Days') {
$datetime = explode(' ', date("Y-m-d H:i:s", strtotime('+' . $p['validity'] . ' day')));
$date_exp = $datetime[0];
$time = $datetime[1];
} else if ($p['validity_unit'] == 'Hrs') {
$datetime = explode(' ', date("Y-m-d H:i:s", strtotime('+' . $p['validity'] . ' hour')));
$date_exp = $datetime[0];
$time = $datetime[1];
} else if ($p['validity_unit'] == 'Mins') {
$datetime = explode(' ', date("Y-m-d H:i:s", strtotime('+' . $p['validity'] . ' minute')));
$date_exp = $datetime[0];
$time = $datetime[1];
}
if ($p) {
$this->customerAddPlan($customer, $plan, $date_exp . ' ' . $time);
}
}
@ -108,7 +150,7 @@ class Radius
function remove_plan($plan)
{
// Delete Plan
$this->getTablePackage()->where_equal('plan_id', "plan_" . $plan['id'])->delete_many();
$this->getTablePackage()->where_equal('plan_id', $plan['id'])->delete_many();
// Reset User Plan
$c = $this->getTableUserPackage()->where_equal('groupname', "plan_" . $plan['id'])->findMany();
if ($c) {
@ -219,16 +261,23 @@ class Radius
/**
* When add a plan to Customer, use this
*/
public function customerAddPlan($customer, $plan, $expired = null)
public function customerAddPlan($customer, $plan, $expired = '')
{
global $config;
if ($this->customerUpsert($customer, $plan)) {
$p = $this->getTableUserPackage()->where_equal('username', $customer['username'])->findOne();
if ($p) {
// if exists
// session timeout [it reset everyday, am still making my research] we can use it for something like 1H/Day - since it reset daily, and Max-All-Session clear everything
//$this->delAtribute($customer['username'], 'Session-Timeout', 3600); // 3600 = 1 hour
$this->delAtribute($this->getTableCustomer(), 'Max-All-Session', 'username', $customer['username']);
$this->delAtribute($this->getTableCustomer(), 'Max-Volume', 'username', $customer['username']);
$this->delAtribute($this->getTableCustomer(), 'Max-Data', 'username', $customer['username']);
$this->delAtribute($this->getTableCustomer(), 'Mikrotik-Rate-Limit', 'username', $customer['username']);
$this->delAtribute($this->getTableCustomer(), 'WISPr-Session-Terminate-Time', 'username', $customer['username']);
//$this->delAtribute($this->getTableCustomer(), 'Ascend-Data-Rate', 'username', $customer['username']);
//we are removing the below in the next two updates, some users may have that attribute, it will remove them before we remove it
$this->delAtribute($this->getTableCustomer(), 'access-period', 'username', $customer['username']);
$this->delAtribute($this->getTableCustomer(), 'Max-Volume', 'username', $customer['username']);
$p->groupname = "plan_" . $plan['id'];
$p->save();
} else {
@ -238,53 +287,63 @@ class Radius
$p->priority = 1;
$p->save();
}
$this->addBandwidth($customer, $plan);
if ($plan['type'] == 'Hotspot' && $plan['typebp'] == "Limited") {
if ($plan['limit_type'] == "Time_Limit") {
if ($plan['time_unit'] == 'Hrs')
$timelimit = $plan['time_limit'] * 60 * 60;
else
$timelimit = $plan['time_limit'] * 60;
// session timeout [it reset everyday, am still making my research] we can use it for something like 1H/Day - since it reset daily, and Max-All-Session clear everything
//$this->upsertCustomer($customer['username'], 'Session-Timeout', 3600); // 3600 = 1 hour
$this->upsertCustomer($customer['username'], 'Max-All-Session', $timelimit);
$this->upsertCustomer($customer['username'], 'Expire-After', $timelimit);
} else if ($plan['limit_type'] == "Data_Limit") {
if ($plan['data_unit'] == 'GB')
$datalimit = $plan['data_limit'] . "000000000";
else
$datalimit = $plan['data_limit'] . "000000";
//$this->upsertCustomer($customer['username'], 'Max-Volume', $datalimit);
// Mikrotik Spesific
$this->upsertCustomer($customer['username'], 'Max-Data', $datalimit);
//$this->upsertCustomer($customer['username'], 'Mikrotik-Total-Limit', $datalimit);
} else if ($plan['limit_type'] == "Both_Limit") {
if ($plan['time_unit'] == 'Hrs')
$timelimit = $plan['time_limit'] * 60 * 60;
else
$timelimit = $plan['time_limit'] * 60;
// session timeout [it reset everyday, am still making my research] we can use it for something like 1H/Day - since it reset daily, and Max-All-Session clear everything
//$this->upsertCustomer($customer['username'], 'Session-Timeout', 3600); // 3600 = 1 hour
$this->upsertCustomer($customer['username'], 'Max-All-Session', $timelimit);
if ($plan['data_unit'] == 'GB')
$datalimit = $plan['data_limit'] . "000000000";
else
$datalimit = $plan['data_limit'] . "000000";
//$this->upsertCustomer($customer['username'], 'Max-Volume', $datalimit);
$this->upsertCustomer($customer['username'], 'Max-All-Session', $timelimit);
// Mikrotik Spesific
$this->upsertCustomer($customer['username'], 'Max-Data', $datalimit);
//$this->upsertCustomer($customer['username'], 'Mikrotik-Total-Limit', $datalimit);
}
} else {
//$this->delAtribute($this->getTableCustomer(), 'Max-Volume', 'username', $customer['username']);
// session timeout [it reset everyday, am still making my research] we can use it for something like 1H/Day - since it reset daily, and Max-All-Session clear everything
//$this->delAtribute($customer['username'], 'Session-Timeout', 3600); // 3600 = 1 hour
$this->delAtribute($this->getTableCustomer(), 'Max-All-Session', 'username', $customer['username']);
$this->delAtribute($this->getTableCustomer(), 'Max-Data', 'username', $customer['username']);
$this->delAtribute($this->getTableCustomer(), 'Mikrotik-Rate-Limit', 'username', $customer['username']);
$this->delAtribute($this->getTableCustomer(), 'WISPr-Session-Terminate-Time', 'username', $customer['username']);
//we are removing the below in the next two updates, some users may have that attribute, it will remove them before we remove it
$this->delAtribute($this->getTableCustomer(), 'access-period', 'username', $customer['username']);
$this->delAtribute($this->getTableCustomer(), 'Max-Volume', 'username', $customer['username']);
}
$this->disconnectCustomer($customer['username']);
$this->getTableAcct()->where_equal('username', $customer['username'])->delete_many();
// expired user
if ($expired != null) {
//$this->upsertCustomer($customer['username'], 'access-period', strtotime($expired) - time());
$this->upsertCustomer($customer['username'], 'Max-All-Session', strtotime($expired) - time());
$this->upsertCustomer($customer['username'], 'expiration', date('d M Y H:i:s', strtotime($expired)));
if ($expired != '') {
//extend session time only if the plan are the same
if ($plan['plan_id'] == $p['plan_id'] && $config['extend_expiry'] != 'no') {
// session timeout [it reset everyday, am still making my research] we can use it for something like 1H/Day - since it reset daily, and Max-All-Session clear everything
//$this->upsertCustomer($customer['username'], 'Session-Timeout', 3600); // 3600 = 1 hour
$this->upsertCustomer($customer['username'], 'Max-All-Session', strtotime($expired) - time());
$this->upsertCustomer($customer['username'], 'Expiration', date('d M Y H:i:s', strtotime($expired)));
}
// Mikrotik Spesific
$this->upsertCustomer(
$customer['username'],
@ -293,8 +352,11 @@ class Radius
);
} else {
$this->delAtribute($this->getTableCustomer(), 'Max-All-Session', 'username', $customer['username']);
//$this->delAtribute($this->getTableCustomer(), 'access-period', 'username', $customer['username']);
$this->delAtribute($this->getTableCustomer(), 'expiration', 'username', $customer['username']);
$this->delAtribute($this->getTableCustomer(), 'Expiration', 'username', $customer['username']);
$this->delAtribute($this->getTableCustomer(), 'Mikrotik-Rate-Limit', 'username', $customer['username']);
$this->delAtribute($this->getTableCustomer(), 'WISPr-Session-Terminate-Time', 'username', $customer['username']);
//we are removing the below in the next two updates, some users may have that attribute, it will remove them before we remove it
$this->delAtribute($this->getTableCustomer(), 'access-period', 'username', $customer['username']);
}
if ($plan['type'] == 'PPPOE') {
@ -307,7 +369,8 @@ class Radius
return false;
}
public function customerUpsert($customer, $plan)
public function customerUpsert($customer, $plan) //Update or Insert customer plan
{
if ($plan['type'] == 'PPPOE') {
$this->upsertCustomer($customer['username'], 'Cleartext-Password', (empty($customer['pppoe_password'])) ? $customer['password'] : $customer['pppoe_password']);
@ -321,9 +384,9 @@ class Radius
return true;
}
private function delAtribute($tabel, $attribute, $key, $value)
private function delAtribute($table, $attribute, $key, $value)
{
$r = $tabel->where_equal($key, $value)->whereEqual('attribute', $attribute)->findOne();
$r = $table->where_equal($key, $value)->whereEqual('attribute', $attribute)->findOne();
if ($r) $r->delete();
}
@ -357,7 +420,8 @@ class Radius
$r->attribute = $attr;
$r->op = $op;
$r->value = $value;
return $r->save();
$r->save();
return true;
}
/**
* To insert or update existing customer Attribute
@ -398,4 +462,31 @@ class Radius
}
return $result;
}
public function addBandwidth($customer, $plan)
{
$bw = ORM::for_table("tbl_bandwidth")->find_one($plan['id_bw']);
$unitdown = ($bw['rate_down_unit'] == 'Kbps') ? 'K' : 'M';
$unitup = ($bw['rate_up_unit'] == 'Kbps') ? 'K' : 'M';
// TODO Burst mode [ 2M/1M 256K/128K 128K/64K 1s 1 64K/32K]
if (!empty(trim($bw['burst']))) {
// burst format: 2M/1M 256K/128K 128K/64K 1s 1 64K/32K
$pattern = '/(\d+[KM])\/(\d+[KM]) (\d+[KM])\/(\d+[KM]) (\d+) (\d+) (\d+[KM])\/(\d+[KM])/';
preg_match($pattern, $bw['burst'], $matches);
if (count($matches) == 9) {
$burst = $bw['rate_up'] . $unitup . "/" . $bw['rate_down'] . $unitdown . ' ' . $matches[1] . '/' . $matches[2] . ' ' . $matches[3] . '/' . $matches[4] . ' ' . $matches[5] . ' ' . $matches[6] . ' ' . $matches[7] . '/' . $matches[8];
$this->upsertCustomer($customer['username'], 'Mikrotik-Rate-Limit', $burst);
} else {
_log("Unexpected burst format for customer " . $customer['username']);
}
} else {
//$this->upsertCustomer($customer['username'], 'Ascend-Data-Rate', $this->stringToInteger($bw['rate_up'] . $unitup) . "/" . $this->stringToInteger($bw['rate_down'] . $unitdown));
$this->upsertCustomer($customer['username'], 'Mikrotik-Rate-Limit', $bw['rate_up'] . $unitup . "/" . $bw['rate_down'] . $unitdown);
}
return true;
}
}

View File

@ -673,5 +673,18 @@
"End_Date": "End Date",
"New_Version_Notification": "New Version Notification",
"Enabled": "Enabled",
"This_is_to_notify_you_when_new_updates_is_available": "This is to notify you when new updates is available"
"This_is_to_notify_you_when_new_updates_is_available": "This is to notify you when new updates is available",
"Enable_Session_Timeout": "Enable Session Timeout",
"Logout_Admin_if_not_Available_Online_a_period_of_time": "Logout Admin if not Available\/Online a period of time",
"Timeout_Duration": "Timeout Duration",
"Enter_the_session_timeout_duration__minutes_": "Enter the session timeout duration (minutes)",
"Idle_Timeout__Logout_Admin_if_Idle_for_xx_minutes": "Idle Timeout, Logout Admin if Idle for xx minutes",
"Failed_to_create_transaction__please_tell_seller_": "Failed to create transaction, please tell seller.",
"paid_off": "paid off",
"Sync_account_if_you_failed_login_to_internet": "Sync account if you failed login to internet",
"Channel": "Channel",
"Payment_Link": "Payment Link",
"Created": "Created",
"2": "2",
"_": "-"
}

View File

@ -129,5 +129,9 @@
"2024.7.24" : [
"ALTER TABLE `tbl_voucher` ADD `used_date` DATETIME NULL DEFAULT NULL AFTER `status`;",
"UPDATE `tbl_voucher` SET `used_date`=now() WHERE `status`=1;"
],
"2024.8.1" : [
"ALTER TABLE `tbl_payment_gateway` CHANGE `gateway_trx_id` `gateway_trx_id` VARCHAR(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '';",
"ALTER TABLE `tbl_payment_gateway` CHANGE `pg_url_payment` `pg_url_payment` VARCHAR(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '';"
]
}

View File

@ -6,5 +6,7 @@
"reminder_3_day": "Hello *[[name]]*, \r\nyour internet package *[[package]]* will be expired in 3 days.",
"reminder_1_day": "Hello *[[name]]*,\r\n your internet package *[[package]]* will be expired tomorrow.",
"invoice_paid": "*[[company_name]]*\r\n[[address]]\r\n[[phone]]\r\n\r\n\r\nINVOICE: *[[invoice]]*\r\nDate : [[date]]\r\n[[payment_gateway]] [[payment_channel]]\r\n\r\n\r\nType : *[[type]]*\r\nPackage : *[[plan_name]]*\r\nPrice : *[[plan_price]]*\r\n\r\nUsername : *[[user_name]]*\r\nPassword : ***********\r\n\r\nExpired : *[[expired_date]]*\r\n\r\n====================\r\n[[footer]]",
"invoice_balance": "*[[company_name]]*\r\n[[address]]\r\n[[phone]]\r\n\r\n\r\nINVOICE: *[[invoice]]*\r\nDate : [[date]]\r\n[[payment_gateway]] [[payment_channel]]\r\n\r\n\r\nType : *[[type]]*\r\nPackage : *[[plan_name]]*\r\nPrice : *[[plan_price]]*\r\n\r\n====================\r\n[[footer]]"
"invoice_balance": "*[[company_name]]*\r\n[[address]]\r\n[[phone]]\r\n\r\n\r\nINVOICE: *[[invoice]]*\r\nDate : [[date]]\r\n[[payment_gateway]] [[payment_channel]]\r\n\r\n\r\nType : *[[type]]*\r\nPackage : *[[plan_name]]*\r\nPrice : *[[plan_price]]*\r\n\r\n====================\r\n[[footer]]",
"welcome_message": "Welcome aboard, [[name]]! \r\nWe're excited to have you as a new [[company]] customer. \r\nYour account is all set up and ready to go.\r\n\r\nHere's a quick overview:\r\n\r\nPortal: [[url]]\r\nYour login is [[Username]]\r\nYour temporary password is [[Password]] (please change this on your first login)\r\n\r\nNeed help? Reach out to our support team at anytime.\r\n\r\nWe're here to ensure you have an amazing experience with our services. Let us know how we can best support you.\r\n\r\nWelcome to the [[company]] family!"
}

View File

@ -136,6 +136,22 @@
</p>
</div>
</div>
<div class="panel-body">
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Welcome Message')}</label>
<div class="col-md-6">
<textarea class="form-control" id="welcome_message" name="welcome_message"
rows="4">{Lang::htmlspecialchars($_json['welcome_message'])}</textarea>
</div>
<p class="help-block col-md-4">
<b>[[name]]</b> - {Lang::T('will be replaced with Customer Name')}.<br>
<b>[[username]]</b> - {Lang::T('will be replaced with Customer username')}.<br>
<b>[[password]]</b> - {Lang::T('will be replaced with Customer password')}.<br>
<b>[[url]]</b> - {Lang::T('will be replaced with Customer Portal URL')}.<br>
<b>[[company]]</b> - {Lang::T('will be replaced with Company Name')}.<br>
</p>
</div>
</div>
{if $_c['enable_balance'] == 'yes'}
<div class="panel-body">
<div class="form-group">

View File

@ -242,8 +242,8 @@
<label class="col-md-2 control-label">{Lang::T('Allow Extend')}</label>
<div class="col-md-6">
<select name="extend_expired" id="extend_expired" class="form-control text-muted">
<option value="0">No</option>
<option value="1" {if $_c['extend_expired']}selected="selected" {/if}>Yes</option>
<option value="0">No</option>
</select>
</div>
<p class="help-block col-md-4">Customer can request to extend expirations</p>
@ -586,6 +586,24 @@
{Lang::T('Miscellaneous')}
</div>
<div class="panel-body">
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Enable Session Timeout')}</label>
<div class="col-md-6">
<label class="switch">
<input type="checkbox" id="enable_session_timeout" value="1" name="enable_session_timeout" {if $_c['enable_session_timeout']==1}checked{/if}>
<span class="slider"></span>
</label>
</div>
<p class="help-block col-md-4">{Lang::T('Logout Admin if not Available/Online a period of time')}</p>
</div>
<div class="form-group" id="timeout_duration_input" style="display: none;">
<label class="col-md-2 control-label">{Lang::T('Timeout Duration')}</label>
<div class="col-md-6">
<input type="number" value="{$_c['session_timeout_duration']}" class="form-control" name="session_timeout_duration" id="session_timeout_duration"
placeholder="{Lang::T('Enter the session timeout duration (minutes)')}" min="1">
</div>
<p class="help-block col-md-4">{Lang::T('Idle Timeout, Logout Admin if Idle for xx minutes')}</p>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('New Version Notification')}</label>
<div class="col-md-6">
@ -747,7 +765,8 @@
<label class="col-md-2 control-label">Github Token</label>
<div class="col-md-6">
<input type="password" class="form-control" id="github_token" name="github_token"
value="{$_c['github_token']}" placeholder="ghp_........">
value="{$_c['github_token']}" placeholder="ghp_........"
onmouseleave="this.type = 'password'" onmouseenter="this.type = 'text'">
</div>
<span class="help-block col-md-4"><a href="https://github.com/settings/tokens/new"
target="_blank">Create GitHub personal access token (classic)</a>, only need repo scope</span>
@ -785,6 +804,38 @@ add dst-host=*.{$_domain}</pre>
</div>
</div>
</form>
<script>
document.addEventListener('DOMContentLoaded', function() {
var sectionTimeoutCheckbox = document.getElementById('enable_session_timeout');
var timeoutDurationInput = document.getElementById('timeout_duration_input');
var timeoutDurationField = document.getElementById('session_timeout_duration');
if (sectionTimeoutCheckbox.checked) {
timeoutDurationInput.style.display = 'block';
timeoutDurationField.required = true;
}
sectionTimeoutCheckbox.addEventListener('change', function() {
if (this.checked) {
timeoutDurationInput.style.display = 'block';
timeoutDurationField.required = true;
} else {
timeoutDurationInput.style.display = 'none';
timeoutDurationField.required = false;
}
});
document.querySelector('form').addEventListener('submit', function(event) {
if (sectionTimeoutCheckbox.checked && (!timeoutDurationField.value || isNaN(timeoutDurationField.value))) {
event.preventDefault();
alert('Please enter a valid session timeout duration.');
timeoutDurationField.focus();
}
});
});
</script>
<script>
function testWa() {
var target = prompt("Phone number\nSave First before Test", "");

View File

@ -103,6 +103,21 @@
<div id="map" style="width: '100%'; height: 200px; min-height: 150px;"></div>
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">{Lang::T('Send Welcome Message')}</label>
<div class="col-md-9">
<label class="switch">
<input type="checkbox" id="send_welcome_message" value="1" name="send_welcome_message">
<span class="slider"></span>
</label>
</div>
</div>
<div class="form-group" id="method" style="display: none;">
<label class="col-md-3 control-label">{Lang::T('Method')}</label>
<label class="col-md-3 control-label"><input type="checkbox" name="sms" value="1"> {Lang::T('SMS')}</label>
<label class="col-md-2 control-label"><input type="checkbox" name="wa" value="1"> {Lang::T('WA')}</label>
<label class="col-md-2 control-label"><input type="checkbox" name="email" value="1"> {Lang::T('Email')}</label>
</div>
</div>
</div>
</div>
@ -175,6 +190,38 @@
</center>
</form>
{literal}
<script>
document.addEventListener('DOMContentLoaded', function() {
var sendWelcomeCheckbox = document.getElementById('send_welcome_message');
var methodSection = document.getElementById('method');
function toggleMethodSection() {
if (sendWelcomeCheckbox.checked) {
methodSection.style.display = 'block';
} else {
methodSection.style.display = 'none';
}
}
toggleMethodSection();
sendWelcomeCheckbox.addEventListener('change', toggleMethodSection);
document.querySelector('form').addEventListener('submit', function(event) {
if (sendWelcomeCheckbox.checked) {
var methodCheckboxes = methodSection.querySelectorAll('input[type="checkbox"]');
var oneChecked = Array.from(methodCheckboxes).some(function(checkbox) {
return checkbox.checked;
});
if (!oneChecked) {
event.preventDefault();
alert('Please choose at least one method.');
methodSection.focus();
}
}
});
});
</script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function() {
var customFieldsContainer = document.getElementById('custom-fields-container');

View File

@ -1,67 +1,64 @@
{include file="sections/header.tpl"}
<div class="row">
<div class="col-lg-3 col-xs-6">
<div class="small-box bg-aqua">
<div class="inner">
<h4><sup>{$_c['currency_code']}</sup>
{number_format($iday,0,$_c['dec_point'],$_c['thousands_sep'])}</h4>
<p>{Lang::T('Income Today')}</p>
{if in_array($_admin['user_type'],['SuperAdmin','Admin', 'Report'])}
<div class="col-lg-3 col-xs-6">
<div class="small-box bg-aqua">
<div class="inner">
<h4 class="text-bold" style="font-size: large;"><sup>{$_c['currency_code']}</sup>
{number_format($iday,0,$_c['dec_point'],$_c['thousands_sep'])}</h4>
</div>
<div class="icon">
<i class="ion ion-clock"></i>
</div>
<a href="{$_url}reports/by-date" class="small-box-footer">{Lang::T('Income Today')}</a>
</div>
<div class="icon">
<i class="ion ion-bag"></i>
</div>
<a href="{$_url}reports/by-date" class="small-box-footer">{Lang::T('View Reports')} <i
class="fa fa-arrow-circle-right"></i></a>
</div>
</div>
<div class="col-lg-3 col-xs-6">
<div class="small-box bg-green">
<div class="inner">
<h4><sup>{$_c['currency_code']}</sup>
{number_format($imonth,0,$_c['dec_point'],$_c['thousands_sep'])}</h4>
<p>{Lang::T('Income This Month')}</p>
<div class="col-lg-3 col-xs-6">
<div class="small-box bg-green">
<div class="inner">
<h4 class="text-bold" style="font-size: large;"><sup>{$_c['currency_code']}</sup>
{number_format($imonth,0,$_c['dec_point'],$_c['thousands_sep'])}</h4>
</div>
<div class="icon">
<i class="ion ion-android-calendar"></i>
</div>
<a href="{$_url}reports/by-period" class="small-box-footer">{Lang::T('Income This Month')}</a>
</div>
<div class="icon">
<i class="ion ion-stats-bars"></i>
</div>
<a href="{$_url}reports/by-period" class="small-box-footer">{Lang::T('View Reports')} <i
class="fa fa-arrow-circle-right"></i></a>
</div>
</div>
{/if}
<div class="col-lg-3 col-xs-6">
<div class="small-box bg-yellow">
<div class="inner">
<h4>{$u_act}/{$u_all}</h4>
<p>{Lang::T('Users Active')}</p>
<h4 class="text-bold" style="font-size: large;">{$u_act}/{$u_all-$u_act}</h4>
</div>
<div class="icon">
<i class="ion ion-person"></i>
</div>
<a href="{$_url}plan/list" class="small-box-footer">{Lang::T('View All')} <i
class="fa fa-arrow-circle-right"></i></a>
<a href="{$_url}plan/list" class="small-box-footer">{Lang::T('Active')}/{Lang::T('Expired')}</a>
</div>
</div>
<div class="col-lg-3 col-xs-6">
<div class="small-box bg-red">
<div class="inner">
<h4>{$c_all}</h4>
<p>{Lang::T('Total Users')}</p>
<h4 class="text-bold" style="font-size: large;">{$c_all}</h4>
</div>
<div class="icon">
<i class="fa fa-users"></i>
<i class="ion ion-android-people"></i>
</div>
<a href="{$_url}customers/list" class="small-box-footer">{Lang::T('View All')} <i
class="fa fa-arrow-circle-right"></i></a>
<a href="{$_url}customers/list" class="small-box-footer">{Lang::T('Customers')}</a>
</div>
</div>
</div>
<ol class="breadcrumb">
<li>{Lang::dateFormat($start_date)}</li>
<li>{Lang::dateFormat($current_date)}</li>
{if $_c['enable_balance'] == 'yes' && in_array($_admin['user_type'],['SuperAdmin','Admin', 'Report'])}
<li>
{Lang::T('Customer Balance')} <sup>{$_c['currency_code']}</sup>
<b>{number_format($cb,0,$_c['dec_point'],$_c['thousands_sep'])}</b>
</li>
{/if}
</ol>
<div class="row">
<div class="col-md-7">
@ -180,7 +177,8 @@
<div class="col-md-5">
{if $_c['hide_pg'] != 'yes'}
<div class="panel panel-success panel-hovered mb20 activities">
<div class="panel-heading">{Lang::T('Payment Gateway')}: {str_replace(',',', ',$_c['payment_gateway'])}</div>
<div class="panel-heading">{Lang::T('Payment Gateway')}: {str_replace(',',', ',$_c['payment_gateway'])}
</div>
</div>
{/if}
{if $_c['hide_aui'] != 'yes'}
@ -339,6 +337,9 @@
//lets calculate the inactive users as reported
var expired = u_all - u_act;
var inactive = c_all - u_all;
if(inactive < 0){
inactive = 0;
}
// Create the chart data
var data = {
labels: ['Active Users', 'Expired Users', 'Inactive Users'],

View File

@ -0,0 +1,79 @@
{include file="sections/header.tpl"}
<div class="row">
<div class="col-sm-5">
<div class="panel panel-hovered mb20 panel-primary">
<div class="panel-heading">
{$pg['gateway_trx_id']}
</div>
<div class="panel-body">
<ul class="list-group list-group-unbordered">
<li class="list-group-item">
<b>TRX ID</b> <span class="pull-right">&nbsp;{$pg['id']}&nbsp;</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Invoice')}</b> <span class="pull-right">&nbsp;
<a href="{$_url}reports/activation&q={$pg['trx_invoice']}" class="text-black">{$pg['trx_invoice']}</a>
&nbsp;</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Status')}</b> <span
class="pull-right">&nbsp;{if $pg['status'] == 1}UNPAID{elseif $pg['status'] == 2}PAID{elseif $pg['status'] == 3}FAILED{else}CANCELED{/if}&nbsp;</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Username')}</b>
<span class="pull-right">&nbsp;<a href="{$_url}customers/viewu/{$pg['username']}" class="text-black">{$pg['username']}</a>&nbsp;</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Plan Name')}</b> <span class="pull-right">&nbsp;{$pg['plan_name']}&nbsp;</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Routers')}</b> <span class="pull-right">&nbsp;{$pg['routers']}&nbsp;</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Price')}</b> <span
class="pull-right">&nbsp;{Lang::moneyFormat($pg['price'])}&nbsp;</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Payment Link')}</b> <span class="pull-right">&nbsp;{if $pg['pg_url_payment']}
<a href="{$pg['pg_url_payment']}" target="_blank" class="btn btn-xs btn-default"
rel="noopener noreferrer">open</a>
{/if}&nbsp;</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Channel')}</b> <span class="pull-right">&nbsp;{$pg['payment_method']} -
{$pg['payment_channel']}&nbsp;</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Created')}</b> <span
class="pull-right">&nbsp;{if $pg['created_date'] != null}{Lang::dateTimeFormat($pg['created_date'])}{/if}&nbsp;</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Expired')}</b> <span
class="pull-right">&nbsp;{if $pg['expired_date'] != null}{Lang::dateTimeFormat($pg['expired_date'])}{/if}&nbsp;</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Paid')}</b> <span
class="pull-right">&nbsp;{if $pg['paid_date'] != null}{Lang::dateTimeFormat($pg['paid_date'])}{/if}&nbsp;</span>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="panel panel-hovered mb20 panel-primary">
<div class="panel-heading">
Response when request payment
</div>
<pre class="panel-body p-1">{if $pg['pg_request'] != null}{Lang::jsonArray2text(json_decode($pg['pg_request'], true))}{/if}</pre>
</div>
<div class="panel panel-hovered mb20 panel-primary">
<div class="panel-heading">
Response when payment PAID
</div>
<pre class="panel-body p-1">{if $pg['pg_request'] != null}{Lang::jsonArray2text(json_decode($pg['pg_paid_response'], true))}{/if}</pre>
</div>
{include file="sections/footer.tpl"}

View File

@ -0,0 +1,71 @@
{include file="sections/header.tpl"}
<div class="panel panel-hovered mb20 panel-primary">
<div class="panel-heading">
{ucwords($pg)}
</div>
<div class="panel-body">
<form id="site-search" method="post" action="{$_url}paymentgateway/audit/{$pg}">
<div class="input-group">
<input type="text" name="q" class="form-control" placeholder="{Lang::T('Search')}..."
value="{$q}">
<div class="input-group-btn">
<button type="submit" class="btn btn-danger" title="Clear Search Query"
href="{$_url}plan/list"><span class="glyphicon glyphicon-search"></span></button>
</div>
</div>
</form>
<div class="table-responsive">
<table class="table table-bordered table-striped table-condensed">
<thead>
<tr>
<th>TRX ID</th>
<th>PG ID</th>
<th>{Lang::T('Username')}</th>
<th>{Lang::T('Plan Name')}</th>
<th>{Lang::T('Routers')}</th>
<th>{Lang::T('Price')}</th>
<th>{Lang::T('Payment Link')}</th>
<th>{Lang::T('Channel')}</th>
<th>{Lang::T('Created')}</th>
<th>{Lang::T('Expired')}</th>
<th>{Lang::T('Paid')}</th>
<th>{Lang::T('Invoice')}</th>
<th>{Lang::T('Status')}</th>
</tr>
</thead>
<tbody>
{foreach $pgs as $pg}
<tr class="{if $pg['status'] == 1}warning{elseif $pg['status'] == 2}success{else}danger{/if}">
<td>{$pg['id']}</td>
<td><a href="{$_url}paymentgateway/audit-view/{$pg['id']}"
class="text-black">{$pg['gateway_trx_id']}</a></td>
<td><a href="{$_url}customers/viewu/{$pg['username']}" class="text-black">{$pg['username']}</a>
</td>
<td>{$pg['plan_name']}</td>
<td>{$pg['routers']}</td>
<td>{Lang::moneyFormat($pg['price'])}</td>
<td>
{if $pg['pg_url_payment']}
<a href="{$pg['pg_url_payment']}" target="_blank" class="btn btn-xs btn-default btn-block"
rel="noopener noreferrer">open</a>
{/if}
</td>
<td>{$pg['payment_method']} - {$pg['payment_channel']}</td>
<td>{if $pg['created_date'] != null}{Lang::dateTimeFormat($pg['created_date'])}{/if}</td>
<td>{if $pg['expired_date'] != null}{Lang::dateTimeFormat($pg['expired_date'])}{/if}</td>
<td>{if $pg['paid_date'] != null}{Lang::dateTimeFormat($pg['paid_date'])}{/if}</td>
<td>{if $pg['trx_invoice']}<a href="{$_url}reports/activation&q={$pg['trx_invoice']}"
class="text-black">{$pg['trx_invoice']}</a>{/if}</td>
<td>{if $pg['status'] == 1}UNPAID{elseif $pg['status'] == 2}PAID{elseif $pg['status'] == 3}FAILED{else}CANCELED{/if}
</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
{include file="pagination.tpl"}
<a href="{$_url}paymentgateway/" class="btn btn-default btn-xs">kembali</a>
</div>
</div>
{include file="sections/footer.tpl"}

View File

@ -14,9 +14,19 @@
<td><a href="{$_url}paymentgateway/{$pg}"
class="btn btn-block btn-{if in_array($pg, $actives)}info{else}default{/if} text-left">{ucwords($pg)}</a>
</td>
<td width="10"><a href="{$_url}paymentgateway/delete/{$pg}"
onclick="return confirm('{Lang::T('Delete')} {$pg}?')" class="btn btn-danger"><i
class="glyphicon glyphicon-trash"></i></a></td>
<td width="114">
<div class="btn-group" role="group" aria-label="...">
<div class="btn-group" role="group">
<a href="{$_url}paymentgateway/audit/{$pg}"
class="btn btn-success text-black">Audit</a>
</div>
<div class="btn-group" role="group">
<a href="{$_url}paymentgateway/delete/{$pg}"
onclick="return confirm('{Lang::T('Delete')} {$pg}?')"
class="btn btn-danger"><i class="glyphicon glyphicon-trash"></i></a>
</div>
</div>
</td>
</tr>
{/foreach}
</tbody>

View File

@ -30,7 +30,8 @@
</div>
</form>
<p class="help-block">To download from private/paid repository, <a href="{$_url}settings/app#Github_Authentication">Set your Github Authentication first</a></p>
<p class="help-block">To download from private/paid repository, <a href="{$_url}settings/app#Github_Authentication">Set
your Github Authentication first</a></p>
<div class="panel panel-primary panel-hovered">
<div class="panel-heading">{Lang::T('Plugin')}
@ -53,8 +54,8 @@
<center><small><i>@{$plugin['author']} Last update: {$plugin['last_update']}</i></small>
</center>
<div class="btn-group btn-group-justified" role="group" aria-label="...">
<a href="{$plugin['url']}" target="_blank" style="color: black;" class="btn btn-primary"><i
class="glyphicon glyphicon-globe"></i> Web</a>
<a href="{$plugin['url']}" target="_blank" style="color: black;" class="btn btn-{if $plugin['ispaid']}warning{else}primary{/if}"><i
class="glyphicon glyphicon-globe"></i> {if $plugin['ispaid']}Buy{else}Web{/if}</a>
<a href="{$plugin['github']}" target="_blank" style="color: black;" class="btn btn-info"><i
class="glyphicon glyphicon-align-left"></i> Source</a>
</div>
@ -90,8 +91,11 @@
<div class="box-footer ">
<center><small><i>@{$pg['author']} Last update: {$pg['last_update']}</i></small></center>
<div class="btn-group btn-group-justified" role="group" aria-label="...">
<a href="{$pg['url']}" target="_blank" style="color: black;" class="btn btn-primary"><i
class="glyphicon glyphicon-globe"></i> Web</a>
<a href="{$pg['url']}" target="_blank" style="color: black;"
class="btn btn-{if $pg['ispaid']}warning{else}primary{/if}"><i
class="glyphicon glyphicon-globe"></i>
{if $pg['ispaid']}Buy{else}Web{/if}
</a>
<a href="{$pg['github']}" target="_blank" style="color: black;" class="btn btn-info"><i
class="glyphicon glyphicon-align-left"></i> Source</a>
<a {if $zipExt } href="{$_url}pluginmanager/install/payment/{$pg['id']}"

View File

@ -189,9 +189,65 @@
.bs-callout-info h4 {
color: #1b809e
}
/* Checkbox container */
.switch {
position: relative;
display: inline-block;
width: 50px;
height: 24px;
}
/* Hidden checkbox */
.switch input {
opacity: 0;
width: 0;
height: 0;
}
/* Slider */
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
border-radius: 24px;
}
.slider:before {
position: absolute;
content: "";
height: 18px;
width: 18px;
left: 3px;
bottom: 3px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
border-radius: 50%;
}
input:checked+.slider {
background-color: #2196F3;
}
input:focus+.slider {
box-shadow: 0 0 1px #2196F3;
}
input:checked+.slider:before {
-webkit-transform: translateX(26px);
-ms-transform: translateX(26px);
transform: translateX(26px);
}
</style>
{if isset($xheader)}
{$xheader}
{$xheader}
{/if}
</head>
@ -261,80 +317,82 @@
</li>
{$_MENU_AFTER_DASHBOARD}
{if !in_array($_admin['user_type'],['Report'])}
<li class="{if in_array($_system_menu, ['customers', 'map'])}active{/if} treeview">
<a href="#">
<i class="fa fa-users"></i> <span>{Lang::T('Customer')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_system_menu eq 'customers' }class="active" {/if}><a
href="{$_url}customers">{Lang::T('Lists')}</a></li>
<li {if $_system_menu eq 'map' }class="active" {/if}><a
href="{$_url}map/customer">{Lang::T('Location')}</a></li>
{$_MENU_CUSTOMERS}
</ul>
</li>
{$_MENU_AFTER_CUSTOMERS}
<li class="{if $_system_menu eq 'plan'}active{/if} treeview">
<a href="#">
<i class="fa fa-ticket"></i> <span>{Lang::T('Services')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[1] eq 'list' }class="active" {/if}><a
href="{$_url}plan/list">{Lang::T('Active Users')}</a></li>
{if $_c['disable_voucher'] != 'yes'}
<li {if $_routes[1] eq 'voucher' }class="active" {/if}><a
href="{$_url}plan/voucher">{Lang::T('Vouchers')}</a></li>
<li {if $_routes[1] eq 'refill' }class="active" {/if}><a
href="{$_url}plan/refill">{Lang::T('Refill Customer')}</a></li>
{/if}
<li {if $_routes[1] eq 'recharge' }class="active" {/if}><a
href="{$_url}plan/recharge">{Lang::T('Recharge Customer')}</a></li>
{if $_c['enable_balance'] == 'yes'}
<li {if $_routes[1] eq 'deposit' }class="active" {/if}><a
href="{$_url}plan/deposit">{Lang::T('Refill Balance')}</a></li>
{/if}
{$_MENU_SERVICES}
</ul>
</li>
<li class="{if in_array($_system_menu, ['customers', 'map'])}active{/if} treeview">
<a href="#">
<i class="fa fa-users"></i> <span>{Lang::T('Customer')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_system_menu eq 'customers' }class="active" {/if}><a
href="{$_url}customers">{Lang::T('Lists')}</a></li>
<li {if $_system_menu eq 'map' }class="active" {/if}><a
href="{$_url}map/customer">{Lang::T('Location')}</a></li>
{$_MENU_CUSTOMERS}
</ul>
</li>
{$_MENU_AFTER_CUSTOMERS}
<li class="{if $_system_menu eq 'plan'}active{/if} treeview">
<a href="#">
<i class="fa fa-ticket"></i> <span>{Lang::T('Services')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[1] eq 'list' }class="active" {/if}><a
href="{$_url}plan/list">{Lang::T('Active Users')}</a></li>
{if $_c['disable_voucher'] != 'yes'}
<li {if $_routes[1] eq 'voucher' }class="active" {/if}><a
href="{$_url}plan/voucher">{Lang::T('Vouchers')}</a></li>
<li {if $_routes[1] eq 'refill' }class="active" {/if}><a
href="{$_url}plan/refill">{Lang::T('Refill Customer')}</a></li>
{/if}
<li {if $_routes[1] eq 'recharge' }class="active" {/if}><a
href="{$_url}plan/recharge">{Lang::T('Recharge Customer')}</a></li>
{if $_c['enable_balance'] == 'yes'}
<li {if $_routes[1] eq 'deposit' }class="active" {/if}><a
href="{$_url}plan/deposit">{Lang::T('Refill Balance')}</a></li>
{/if}
{$_MENU_SERVICES}
</ul>
</li>
{/if}
{$_MENU_AFTER_SERVICES}
{if in_array($_admin['user_type'],['SuperAdmin','Admin'])}
<li class="{if $_system_menu eq 'services'}active{/if} treeview">
<a href="#">
<i class="ion ion-cube"></i> <span>{Lang::T('Internet Plan')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[1] eq 'hotspot' }class="active" {/if}><a
href="{$_url}services/hotspot">Hotspot</a></li>
<li {if $_routes[1] eq 'pppoe' }class="active" {/if}><a
href="{$_url}services/pppoe">PPPOE</a></li>
<li {if $_routes[1] eq 'list' }class="active" {/if}><a
href="{$_url}bandwidth/list">{Lang::T('Bandwidth')}</a></li>
{if $_c['enable_balance'] == 'yes'}
<li {if $_routes[1] eq 'balance' }class="active" {/if}><a
href="{$_url}services/balance">{Lang::T('Customer Balance')}</a></li>
{/if}
{$_MENU_PLANS}
</ul>
</li>
<li class="{if $_system_menu eq 'services'}active{/if} treeview">
<a href="#">
<i class="ion ion-cube"></i> <span>{Lang::T('Internet Plan')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[1] eq 'hotspot' }class="active" {/if}><a
href="{$_url}services/hotspot">Hotspot</a></li>
<li {if $_routes[1] eq 'pppoe' }class="active" {/if}><a
href="{$_url}services/pppoe">PPPOE</a></li>
<li {if $_routes[1] eq 'list' }class="active" {/if}><a
href="{$_url}bandwidth/list">{Lang::T('Bandwidth')}</a></li>
{if $_c['enable_balance'] == 'yes'}
<li {if $_routes[1] eq 'balance' }class="active" {/if}><a
href="{$_url}services/balance">{Lang::T('Customer Balance')}</a></li>
{/if}
{$_MENU_PLANS}
</ul>
</li>
{/if}
{$_MENU_AFTER_PLANS}
<li class="{if $_system_menu eq 'reports'}active{/if} treeview">
{if in_array($_admin['user_type'],['SuperAdmin','Admin', 'Report'])}
<a href="#">
<i class="ion ion-clipboard"></i> <span>{Lang::T('Reports')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
{/if}
<ul class="treeview-menu">
<li {if $_system_menu eq 'reports' }class="active" {/if}><a
href="{$_url}reports">{Lang::T('Daily Reports')}</a></li>
@ -361,64 +419,64 @@
</li>
{$_MENU_AFTER_MESSAGE}
{if in_array($_admin['user_type'],['SuperAdmin','Admin'])}
<li class="{if $_system_menu eq 'network'}active{/if} treeview">
<a href="#">
<i class="ion ion-network"></i> <span>{Lang::T('Network')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[0] eq 'routers' and $_routes[1] eq 'list' }class="active" {/if}><a
href="{$_url}routers/list">{Lang::T('Routers')}</a></li>
<li {if $_routes[0] eq 'pool' and $_routes[1] eq 'list' }class="active" {/if}><a
href="{$_url}pool/list">{Lang::T('IP Pool')}</a></li>
{$_MENU_NETWORK}
</ul>
</li>
{$_MENU_AFTER_NETWORKS}
{if $_c['radius_enable']}
<li class="{if $_system_menu eq 'radius'}active{/if} treeview">
<a href="#">
<i class="fa fa-database"></i> <span>{Lang::T('Radius')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[0] eq 'radius' and $_routes[1] eq 'nas-list' }class="active" {/if}><a
href="{$_url}radius/nas-list">{Lang::T('Radius NAS')}</a></li>
{$_MENU_RADIUS}
</ul>
<li class="{if $_system_menu eq 'network'}active{/if} treeview">
<a href="#">
<i class="ion ion-network"></i> <span>{Lang::T('Network')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[0] eq 'routers' and $_routes[1] eq 'list' }class="active" {/if}><a
href="{$_url}routers/list">{Lang::T('Routers')}</a></li>
<li {if $_routes[0] eq 'pool' and $_routes[1] eq 'list' }class="active" {/if}><a
href="{$_url}pool/list">{Lang::T('IP Pool')}</a></li>
{$_MENU_NETWORK}
</ul>
</li>
{$_MENU_AFTER_NETWORKS}
{if $_c['radius_enable']}
<li class="{if $_system_menu eq 'radius'}active{/if} treeview">
<a href="#">
<i class="fa fa-database"></i> <span>{Lang::T('Radius')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[0] eq 'radius' and $_routes[1] eq 'nas-list' }class="active" {/if}><a
href="{$_url}radius/nas-list">{Lang::T('Radius NAS')}</a></li>
{$_MENU_RADIUS}
</ul>
</li>
{/if}
{$_MENU_AFTER_RADIUS}
<li class="{if $_system_menu eq 'pages'}active{/if} treeview">
<a href="#">
<i class="ion ion-document"></i> <span>{Lang::T("Static Pages")}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[1] eq 'Order_Voucher' }class="active" {/if}><a
href="{$_url}pages/Order_Voucher">{Lang::T('Order Voucher')}</a></li>
<li {if $_routes[1] eq 'Voucher' }class="active" {/if}><a
href="{$_url}pages/Voucher">{Lang::T('Voucher')} Template</a></li>
<li {if $_routes[1] eq 'Announcement' }class="active" {/if}><a
href="{$_url}pages/Announcement">{Lang::T('Announcement')}</a></li>
<li {if $_routes[1] eq 'Announcement_Customer' }class="active" {/if}><a
href="{$_url}pages/Announcement_Customer">{Lang::T('Customer Announcement')}</a>
</li>
{/if}
{$_MENU_AFTER_RADIUS}
<li class="{if $_system_menu eq 'pages'}active{/if} treeview">
<a href="#">
<i class="ion ion-document"></i> <span>{Lang::T("Static Pages")}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[1] eq 'Order_Voucher' }class="active" {/if}><a
href="{$_url}pages/Order_Voucher">{Lang::T('Order Voucher')}</a></li>
<li {if $_routes[1] eq 'Voucher' }class="active" {/if}><a
href="{$_url}pages/Voucher">{Lang::T('Voucher')} Template</a></li>
<li {if $_routes[1] eq 'Announcement' }class="active" {/if}><a
href="{$_url}pages/Announcement">{Lang::T('Announcement')}</a></li>
<li {if $_routes[1] eq 'Announcement_Customer' }class="active" {/if}><a
href="{$_url}pages/Announcement_Customer">{Lang::T('Customer Announcement')}</a>
</li>
<li {if $_routes[1] eq 'Registration_Info' }class="active" {/if}><a
href="{$_url}pages/Registration_Info">{Lang::T('Registration Info')}</a></li>
<li {if $_routes[1] eq 'Privacy_Policy' }class="active" {/if}><a
href="{$_url}pages/Privacy_Policy">{Lang::T('Privacy Policy')}</a></li>
<li {if $_routes[1] eq 'Terms_and_Conditions' }class="active" {/if}><a
href="{$_url}pages/Terms_and_Conditions">{Lang::T('Terms and Conditions')}</a></li>
{$_MENU_PAGES}
</ul>
</li>
<li {if $_routes[1] eq 'Registration_Info' }class="active" {/if}><a
href="{$_url}pages/Registration_Info">{Lang::T('Registration Info')}</a></li>
<li {if $_routes[1] eq 'Privacy_Policy' }class="active" {/if}><a
href="{$_url}pages/Privacy_Policy">{Lang::T('Privacy Policy')}</a></li>
<li {if $_routes[1] eq 'Terms_and_Conditions' }class="active" {/if}><a
href="{$_url}pages/Terms_and_Conditions">{Lang::T('Terms and Conditions')}</a></li>
{$_MENU_PAGES}
</ul>
</li>
{/if}
{$_MENU_AFTER_PAGES}
<li
@ -431,75 +489,76 @@
</a>
<ul class="treeview-menu">
{if in_array($_admin['user_type'],['SuperAdmin','Admin'])}
<li {if $_routes[1] eq 'app' }class="active" {/if}><a
href="{$_url}settings/app">{Lang::T('General Settings')}</a></li>
<li {if $_routes[1] eq 'localisation' }class="active" {/if}><a
href="{$_url}settings/localisation">{Lang::T('Localisation')}</a></li>
<li {if $_routes[1] eq 'maintenance' }class="active" {/if}><a
href="{$_url}settings/maintenance">{Lang::T('Maintenance Mode')}</a></li>
<li {if $_routes[1] eq 'notifications' }class="active" {/if}><a
href="{$_url}settings/notifications">{Lang::T('User Notification')}</a></li>
<li {if $_routes[1] eq 'devices' }class="active" {/if}><a
href="{$_url}settings/devices">{Lang::T('Devices')}</a></li>
<li {if $_routes[1] eq 'app' }class="active" {/if}><a
href="{$_url}settings/app">{Lang::T('General Settings')}</a></li>
<li {if $_routes[1] eq 'localisation' }class="active" {/if}><a
href="{$_url}settings/localisation">{Lang::T('Localisation')}</a></li>
<li {if $_routes[1] eq 'maintenance' }class="active" {/if}><a
href="{$_url}settings/maintenance">{Lang::T('Maintenance Mode')}</a></li>
<li {if $_routes[1] eq 'notifications' }class="active" {/if}><a
href="{$_url}settings/notifications">{Lang::T('User Notification')}</a></li>
<li {if $_routes[1] eq 'devices' }class="active" {/if}><a
href="{$_url}settings/devices">{Lang::T('Devices')}</a></li>
{/if}
{if in_array($_admin['user_type'],['SuperAdmin','Admin','Agent'])}
<li {if $_routes[1] eq 'users' }class="active" {/if}><a
href="{$_url}settings/users">{Lang::T('Administrator Users')}</a></li>
<li {if $_routes[1] eq 'users' }class="active" {/if}><a
href="{$_url}settings/users">{Lang::T('Administrator Users')}</a></li>
{/if}
{if in_array($_admin['user_type'],['SuperAdmin','Admin'])}
<li {if $_routes[1] eq 'dbstatus' }class="active" {/if}><a
href="{$_url}settings/dbstatus">{Lang::T('Backup/Restore')}</a></li>
<li {if $_system_menu eq 'paymentgateway' }class="active" {/if}>
<a href="{$_url}paymentgateway">
<span class="text">{Lang::T('Payment Gateway')}</span>
</a>
</li>
{$_MENU_SETTINGS}
<li {if $_routes[0] eq 'pluginmanager' }class="active" {/if}>
<a href="{$_url}pluginmanager"><i class="glyphicon glyphicon-tasks"></i>
{Lang::T('Plugin Manager')}</a>
</li>
<li {if $_routes[1] eq 'dbstatus' }class="active" {/if}><a
href="{$_url}settings/dbstatus">{Lang::T('Backup/Restore')}</a></li>
<li {if $_system_menu eq 'paymentgateway' }class="active" {/if}>
<a href="{$_url}paymentgateway">
<span class="text">{Lang::T('Payment Gateway')}</span>
</a>
</li>
{$_MENU_SETTINGS}
<li {if $_routes[0] eq 'pluginmanager' }class="active" {/if}>
<a href="{$_url}pluginmanager"><i class="glyphicon glyphicon-tasks"></i>
{Lang::T('Plugin Manager')}</a>
</li>
{/if}
</ul>
</li>
{$_MENU_AFTER_SETTINGS}
{if in_array($_admin['user_type'],['SuperAdmin','Admin'])}
<li class="{if $_system_menu eq 'logs' }active{/if} treeview">
<a href="#">
<i class="ion ion-clock"></i> <span>{Lang::T('Logs')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[1] eq 'list' }class="active" {/if}><a
href="{$_url}logs/phpnuxbill">PhpNuxBill</a></li>
{if $_c['radius_enable']}
<li {if $_routes[1] eq 'radius' }class="active" {/if}><a
href="{$_url}logs/radius">Radius</a>
</li>
{/if}
{$_MENU_LOGS}
</ul>
</li>
<li class="{if $_system_menu eq 'logs' }active{/if} treeview">
<a href="#">
<i class="ion ion-clock"></i> <span>{Lang::T('Logs')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[1] eq 'list' }class="active" {/if}><a
href="{$_url}logs/phpnuxbill">PhpNuxBill</a></li>
{if $_c['radius_enable']}
<li {if $_routes[1] eq 'radius' }class="active" {/if}><a
href="{$_url}logs/radius">Radius</a>
</li>
{/if}
{$_MENU_LOGS}
</ul>
</li>
{/if}
{$_MENU_AFTER_LOGS}
{if in_array($_admin['user_type'],['SuperAdmin','Admin'])}
<li {if $_system_menu eq 'community' }class="active" {/if}>
<li {if $_system_menu eq 'community' }class="active" {/if}>
<a href="{if $_c['docs_clicked'] != 'yes'}{$_url}settings/docs{else}./docs/{/if}">
<i class="ion ion-ios-bookmarks"></i>
<span class="text">{Lang::T('Documentation')}</span>
{if $_c['docs_clicked'] != 'yes'}
<span class="pull-right-container"><small class="label pull-right bg-green">New</small></span>
{/if}
</a>
</li>
<li {if $_system_menu eq 'community' }class="active" {/if}>
<a href="{$_url}community">
<i class="ion ion-chatboxes"></i>
<span class="text">{Lang::T('Community')}</span>
</a>
</li>
<i class="ion ion-ios-bookmarks"></i>
<span class="text">{Lang::T('Documentation')}</span>
{if $_c['docs_clicked'] != 'yes'}
<span class="pull-right-container"><small
class="label pull-right bg-green">New</small></span>
{/if}
</a>
</li>
<li {if $_system_menu eq 'community' }class="active" {/if}>
<a href="{$_url}community">
<i class="ion ion-chatboxes"></i>
<span class="text">{Lang::T('Community')}</span>
</a>
</li>
{/if}
{$_MENU_AFTER_COMMUNITY}
</ul>
@ -507,11 +566,11 @@
</aside>
{if $_c['maintenance_mode'] == 1}
<div class="notification-top-bar">
<p>{Lang::T('The website is currently in maintenance mode, this means that some or all functionality may be
<div class="notification-top-bar">
<p>{Lang::T('The website is currently in maintenance mode, this means that some or all functionality may be
unavailable to regular users during this time.')}<small> &nbsp;&nbsp;<a
href="{$_url}settings/maintenance">{Lang::T('Turn Off')}</a></small></p>
</div>
href="{$_url}settings/maintenance">{Lang::T('Turn Off')}</a></small></p>
</div>
{/if}
<div class="content-wrapper">
@ -523,19 +582,19 @@
<section class="content">
{if isset($notify)}
<script>
// Display SweetAlert toast notification
Swal.fire({
icon: '{if $notify_t == "s"}success{else}error{/if}',
title: '{$notify}',
position: 'top-end',
showConfirmButton: false,
timer: 5000,
timerProgressBar: true,
didOpen: (toast) => {
toast.addEventListener('mouseenter', Swal.stopTimer)
toast.addEventListener('mouseleave', Swal.resumeTimer)
}
});
</script>
{/if}
<script>
// Display SweetAlert toast notification
Swal.fire({
icon: '{if $notify_t == "s"}success{else}error{/if}',
title: '{$notify}',
position: 'top-end',
showConfirmButton: false,
timer: 5000,
timerProgressBar: true,
didOpen: (toast) => {
toast.addEventListener('mouseenter', Swal.stopTimer)
toast.addEventListener('mouseleave', Swal.resumeTimer)
}
});
</script>
{/if}

View File

@ -103,7 +103,9 @@
});
}
}
$(function() {
$('[data-toggle="tooltip"]').tooltip()
})
});
});
</script>

View File

@ -124,15 +124,24 @@
{else}
{assign var="exp" value=explode(':',$v)}
{Lang::moneyFormat($exp[0])}
<sup title="{$exp[1]} more times">{$exp[1]}x</sup>
{assign var="total" value=$exp[0]+$total}
<sup
title="{$exp[1]} more times">{if $exp[1]==0}{Lang::T('paid off')}{else}{$exp[1]}x{/if}</sup>
{if $exp[1]>0}
{assign var="total" value=$exp[0]+$total}
{/if}
{/if}
</td>
</tr>
{/foreach}
<tr>
<td class="small text-success text-uppercase text-normal"><b>{Lang::T('Total')}</b></td>
<td class="small mb15"><b>{Lang::moneyFormat($total)}</b></td>
<td class="small mb15"><b>
{if $total==0}
{ucwords(Lang::T('paid off'))}
{else}
{Lang::moneyFormat($total)}
{/if}
</b></td>
</tr>
</table>
{/if}
@ -166,6 +175,12 @@
{/if}
</td>
</tr>
<tr>
<td class="small text-primary text-uppercase text-normal">{Lang::T('Bandwidth')}</td>
<td class="small mb15">
{$_bill['name_bw']}
</td>
</tr>
<tr>
<td class="small text-info text-uppercase text-normal">{Lang::T('Created On')}</td>
<td class="small mb15">
@ -234,9 +249,14 @@
href="{$_url}home&extend={$_bill['id']}&stoken={App::getToken()}"
onclick="return confirm('{Text::toHex($_c['extend_confirmation'])}')">{Lang::T('Extend')}</a>
{/if}
<a class="btn btn-primary pull-right btn-sm"
<a class="btn btn-primary pull-right btn-sm"
href="{$_url}home&recharge={$_bill['id']}&stoken={App::getToken()}"
onclick="return confirm('{Lang::T('Recharge')}?')">{Lang::T('Recharge')}</a>
<a class="btn btn-warning text-black pull-right btn-sm"
href="{$_url}home&sync={$_bill['id']}&stoken={App::getToken()}"
onclick="return confirm('{Lang::T('Sync account if you failed login to internet')}?')"
data-toggle="tooltip" data-placement="top" title="{Lang::T('Sync account if you failed login to internet')}"><span
class="glyphicon glyphicon-refresh" aria-hidden="true"></span> {Lang::T('Sync')}</a>
</td>
</tr>
</table>

View File

@ -11,8 +11,8 @@
<div class="col-md-8">
<select name="gateway" id="gateway" class="form-control">
{foreach $pgs as $pg}
<option value="{$pg}">
{ucwords($pg)}</option>
<option value="{$pg}">
{ucwords($pg)}</option>
{/foreach}
</select>
</div>
@ -25,44 +25,82 @@
<b>{Lang::T('Plan Name')}</b> <span class="pull-right">{$plan['name_plan']}</span>
</li>
{if $plan['is_radius'] or $plan['routers']}
<li class="list-group-item">
<b>{Lang::T('Location')}</b> <span class="pull-right">{if
$plan['is_radius']}Radius{else}{$plan['routers']}{/if}</span>
<li class="list-group-item">
<b>{Lang::T('Location')}</b> <span class="pull-right">{if
$plan['is_radius']}Radius{else}{$plan['routers']}
{/if}</span>
</li>
{/if}
<li class="list-group-item">
<b>{Lang::T('Type')}</b> <span class="pull-right">{if $plan['prepaid'] eq
'yes'}Prepaid{else}Postpaid{/if}
'yes'}Prepaid{else}Postpaid
{/if}
{$plan['type']}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Plan Price')}</b> <span class="pull-right">{if $using eq
'zero'}{Lang::moneyFormat(0)}{else}{Lang::moneyFormat($plan['price'])}{/if}</span>
'zero'}{Lang::moneyFormat(0)}
{else}
{Lang::moneyFormat($plan['price'])}
{/if}</span>
</li>
{if $plan['validity']}
<li class="list-group-item">
<b>{Lang::T('Plan Validity')}</b> <span class="pull-right">{$plan['validity']}
{$plan['validity_unit']}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Plan Validity')}</b> <span class="pull-right">{$plan['validity']}
{$plan['validity_unit']}</span>
</li>
{/if}
</ul>
<center><b>{Lang::T('Summary')}</b></center>
<ul class="list-group list-group-unbordered">
{if $tax}
<li class="list-group-item">
<b>{Lang::T('Tax')}</b> <span
class="pull-right">{Lang::moneyFormat($tax)}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Total')}</b> <small>({Lang::T('Plan Price')} + {Lang::T('Tax')})</small><span class="pull-right"
style="font-size: large; font-weight:bolder; font-family: 'Courier New', Courier, monospace; ">{Lang::moneyFormat($plan['price']+$tax)}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Tax')}</b> <span class="pull-right">{Lang::moneyFormat($tax)}</span>
</li>
{if $add_cost>0}
{foreach $bills as $k => $v}
<li class="list-group-item">
<b>{$k}</b> <span class="pull-right">{Lang::moneyFormat($v)}</span>
</li>
{/foreach}
<li class="list-group-item">
<b>{Lang::T('Additional Cost')}</b> <span
class="pull-right">{Lang::moneyFormat($add_cost)}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Total')}</b> <small>({Lang::T('Plan Price')}
+{Lang::T('Additional Cost')})</small><span class="pull-right"
style="font-size: large; font-weight:bolder; font-family: 'Courier New', Courier, monospace; ">{Lang::moneyFormat($plan['price']+$add_cost+$tax)}</span>
</li>
{else}
<li class="list-group-item">
<b>{Lang::T('Total')}</b> <small>({Lang::T('Plan Price')} + {Lang::T('Tax')})</small><span
class="pull-right"
style="font-size: large; font-weight:bolder; font-family: 'Courier New', Courier, monospace; ">{Lang::moneyFormat($plan['price']+$tax)}</span>
</li>
{/if}
{else}
<li class="list-group-item">
<b>{Lang::T('Total')}</b> <span class="pull-right"
style="font-size: large; font-weight:bolder; font-family: 'Courier New', Courier, monospace; ">
{Lang::moneyFormat($plan['price'])}</span>
</li>
{if $add_cost>0}
{foreach $bills as $k => $v}
<li class="list-group-item">
<b>{$k}</b> <span class="pull-right">{Lang::moneyFormat($v)}</span>
</li>
{/foreach}
<li class="list-group-item">
<b>{Lang::T('Additional Cost')}</b> <span
class="pull-right">{Lang::moneyFormat($add_cost)}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Total')}</b> <small>({Lang::T('Plan Price')}
+{Lang::T('Additional Cost')})</small><span class="pull-right"
style="font-size: large; font-weight:bolder; font-family: 'Courier New', Courier, monospace; ">{Lang::moneyFormat($plan['price']+$add_cost)}</span>
</li>
{else}
<li class="list-group-item">
<b>{Lang::T('Total')}</b> <span class="pull-right"
style="font-size: large; font-weight:bolder; font-family: 'Courier New', Courier, monospace; ">{Lang::moneyFormat($plan['price'])}</span>
</li>
{/if}
{/if}
</ul>
<center>

View File

@ -8,6 +8,11 @@
session_start();
include "config.php";
if($db_password != null && ($db_pass == null || empty($db_pass))){
// compability for old version
$db_pass = $db_password;
}
if (empty($update_url)) {
$update_url = 'https://github.com/hotspotbilling/phpnuxbill/archive/refs/heads/master.zip';
}
@ -100,11 +105,10 @@ if (empty($step)) {
}
} else if ($step == 4) {
if (file_exists("system/updates.json")) {
require 'config.php';
$db = new pdo(
"mysql:host=$db_host;dbname=$db_name",
$db_user,
$db_password,
$db_pass,
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)
);

View File

@ -1,3 +1,3 @@
{
"version": "2024.7.25"
"version": "2024.8.2"
}