Merge pull request #14 from hotspotbilling/Development

2023.8.24
This commit is contained in:
iBNu Maksum 2023-08-24 13:34:01 +07:00 committed by GitHub
commit 19d5daf5b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
50 changed files with 3551 additions and 3066 deletions

View File

@ -2,6 +2,18 @@
# CHANGELOG
## 2023.8.24
- Balance transfer between Customer
- Optimize Cronjob
- View Customer Info
- Ajax for select customer
## 2023.8.18
- Fix Auto Renewall Cronjob
- Add comment to Mikrotik User
## 2023.8.16
- Admin Can Add Balance to Customer

View File

@ -50,12 +50,12 @@ CREATE TABLE
`id` int(10) NOT NULL,
`username` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`password` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`pppoe_password` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1',
`pppoe_password` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`fullname` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`address` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
`phonenumber` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0',
`email` varchar(128) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1',
`balance` decimal(15,2) NOT NULL COMMENT 'For Money Deposit',
`balance` decimal(15,2) NOT NULL DEFAULT 0.00 COMMENT 'For Money Deposit',
`auto_renewal` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Auto renewal from balance',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_login` datetime DEFAULT NULL

View File

@ -18,18 +18,14 @@ class Balance
public static function transfer($id_customer, $phoneTarget, $amount)
{
global $config;
if ($config['allow_balance_transfer'] == 'yes') {
if(Balance::min($id_customer, $amount)){
if(Balance::plusByPhone($phoneTarget, $amount)){
if (Balance::min($id_customer, $amount)) {
if (Balance::plusByPhone($phoneTarget, $amount)) {
return true;
}else{
} else {
Balance::plus($id_customer, $amount);
return false;
}
}else{
return false;
}
}else{
} else {
return false;
}
}
@ -38,7 +34,7 @@ class Balance
{
$c = ORM::for_table('tbl_customers')->where('id', $id_customer)->find_one();
if ($c && $c['balance'] >= $amount) {
$c->balance = $amount - $c['balance'];
$c->balance = $c['balance'] - $amount;
$c->save();
return true;
} else {
@ -49,7 +45,7 @@ class Balance
public static function plusByPhone($phone_customer, $amount)
{
$c = ORM::for_table('tbl_customers')->where('username', $phone_customer)->find_one();
if($c){
if ($c) {
$c->balance = $amount + $c['balance'];
$c->save();
return true;
@ -61,7 +57,7 @@ class Balance
{
$c = ORM::for_table('tbl_customers')->where('username', $phone_customer)->find_one();
if ($c && $c['balance'] >= $amount) {
$c->balance = $amount - $c['balance'];
$c->balance = $c['balance'] - $amount;
$c->save();
return true;
} else {

View File

@ -31,4 +31,31 @@ class Lang
return $phone;
}
}
public static function dateFormat($date){
global $config;
return date($config['date_format'], strtotime($date));
}
public static function dateTimeFormat($date){
global $config;
return date($config['date_format']. ' H:i', strtotime($date));
}
public static function nl2br($text){
return nl2br($text);
}
public static function arrayCount($arr){
return count($arr);
}
public static function getNotifText($key){
global $_notifmsg, $_notifmsg_default;
if(isset($_notifmsg[$key])){
return $_notifmsg[$key];
}else{
return $_notifmsg_default[$key];
}
}
}

View File

@ -56,4 +56,20 @@ class Message
return "$via: $msg";
}
public static function sendBalanceNotification($phone, $name, $balance, $message, $via)
{
$msg = str_replace('[[name]]', "*$name*", $message);
$msg = str_replace('[[balance]]', "*" . Lang::moneyFormat($balance) . "*", $msg);
if (
!empty($phone) && strlen($phone) > 5
&& !empty($message) && in_array($via, ['sms', 'wa'])
) {
if ($via == 'sms') {
Message::sendSMS($phone, $msg);
} else if ($via == 'wa') {
Message::sendWhatsapp($phone, $msg);
}
}
return "$via: $msg";
}
}

View File

@ -4,8 +4,9 @@ use PEAR2\Net\RouterOS;
class Mikrotik
{
public static function info($name){
$d = ORM::for_table('tbl_routers')->where('name',$name)->find_one();
public static function info($name)
{
$d = ORM::for_table('tbl_routers')->where('name', $name)->find_one();
return $d;
}
@ -19,7 +20,8 @@ class Mikrotik
}
}
public static function isUserLogin($client, $username){
public static function isUserLogin($client, $username)
{
$printRequest = new RouterOS\Request(
'/ip hotspot active print',
RouterOS\Query::where('user', $username)
@ -27,7 +29,8 @@ class Mikrotik
return $client->sendSync($printRequest)->getProperty('.id');
}
public static function logMeIn($client, $user, $pass, $ip, $mac){
public static function logMeIn($client, $user, $pass, $ip, $mac)
{
$addRequest = new RouterOS\Request('/ip/hotspot/active/login');
$client->sendSync(
$addRequest
@ -38,7 +41,8 @@ class Mikrotik
);
}
public static function logMeOut($client, $user){
public static function logMeOut($client, $user)
{
$printRequest = new RouterOS\Request(
'/ip hotspot active print',
RouterOS\Query::where('user', $user)
@ -51,7 +55,8 @@ class Mikrotik
);
}
public static function addHotspotPlan($client, $name, $sharedusers, $rate){
public static function addHotspotPlan($client, $name, $sharedusers, $rate)
{
$addRequest = new RouterOS\Request('/ip/hotspot/user/profile/add');
$client->sendSync(
$addRequest
@ -61,7 +66,8 @@ class Mikrotik
);
}
public static function setHotspotPlan($client, $name, $sharedusers, $rate){
public static function setHotspotPlan($client, $name, $sharedusers, $rate)
{
$printRequest = new RouterOS\Request(
'/ip hotspot user profile print .proplist=name',
RouterOS\Query::where('name', $name)
@ -77,7 +83,8 @@ class Mikrotik
);
}
public static function removeHotspotPlan($client, $name){
public static function removeHotspotPlan($client, $name)
{
$printRequest = new RouterOS\Request(
'/ip hotspot user profile print .proplist=name',
RouterOS\Query::where('name', $name)
@ -119,6 +126,8 @@ class Mikrotik
->setArgument('name', $customer['username'])
->setArgument('profile', $plan['name_plan'])
->setArgument('password', $customer['password'])
->setArgument('comment', $customer['fullname'])
->setArgument('email', $customer['email'])
->setArgument('limit-uptime', $timelimit)
);
} else if ($plan['limit_type'] == "Data_Limit") {
@ -131,6 +140,8 @@ class Mikrotik
->setArgument('name', $customer['username'])
->setArgument('profile', $plan['name_plan'])
->setArgument('password', $customer['password'])
->setArgument('comment', $customer['fullname'])
->setArgument('email', $customer['email'])
->setArgument('limit-bytes-total', $datalimit)
);
} else if ($plan['limit_type'] == "Both_Limit") {
@ -147,6 +158,8 @@ class Mikrotik
->setArgument('name', $customer['username'])
->setArgument('profile', $plan['name_plan'])
->setArgument('password', $customer['password'])
->setArgument('comment', $customer['fullname'])
->setArgument('email', $customer['email'])
->setArgument('limit-uptime', $timelimit)
->setArgument('limit-bytes-total', $datalimit)
);
@ -156,12 +169,15 @@ class Mikrotik
$addRequest
->setArgument('name', $customer['username'])
->setArgument('profile', $plan['name_plan'])
->setArgument('comment', $customer['fullname'])
->setArgument('email', $customer['email'])
->setArgument('password', $customer['password'])
);
}
}
public static function setHotspotUser($client, $user, $pass, $nuser= null){
public static function setHotspotUser($client, $user, $pass, $nuser = null)
{
$printRequest = new RouterOS\Request('/ip/hotspot/user/print');
$printRequest->setArgument('.proplist', '.id');
$printRequest->setQuery(RouterOS\Query::where('name', $user));
@ -216,9 +232,9 @@ class Mikrotik
public static function addPpoeUser($client, $plan, $customer)
{
$addRequest = new RouterOS\Request('/ppp/secret/add');
if(!empty($customer['pppoe_password'])){
if (!empty($customer['pppoe_password'])) {
$pass = $customer['pppoe_password'];
}else{
} else {
$pass = $customer['password'];
}
$client->sendSync(
@ -226,11 +242,13 @@ class Mikrotik
->setArgument('name', $customer['username'])
->setArgument('service', 'pppoe')
->setArgument('profile', $plan['name_plan'])
->setArgument('comment', $customer['fullname'] . ' | ' . $customer['email'])
->setArgument('password', $pass)
);
}
public static function setPpoeUser($client, $user, $pass, $nuser= null){
public static function setPpoeUser($client, $user, $pass, $nuser = null)
{
$printRequest = new RouterOS\Request('/ppp/secret/print');
$printRequest->setArgument('.proplist', '.id');
$printRequest->setQuery(RouterOS\Query::where('name', $user));
@ -266,7 +284,8 @@ class Mikrotik
$client->sendSync($removeRequest);
}
public static function removePool($client, $name){
public static function removePool($client, $name)
{
$printRequest = new RouterOS\Request(
'/ip pool print .proplist=name',
RouterOS\Query::where('name', $name)
@ -274,29 +293,33 @@ class Mikrotik
$poolName = $client->sendSync($printRequest)->getProperty('name');
$removeRequest = new RouterOS\Request('/ip/pool/remove');
$client($removeRequest
$client(
$removeRequest
->setArgument('numbers', $poolName)
);
}
public static function addPool($client, $name, $ip_address){
public static function addPool($client, $name, $ip_address)
{
$addRequest = new RouterOS\Request('/ip/pool/add');
$client->sendSync($addRequest
$client->sendSync(
$addRequest
->setArgument('name', $name)
->setArgument('ranges', $ip_address)
);
}
public static function setPool($client, $name, $ip_address){
public static function setPool($client, $name, $ip_address)
{
$printRequest = new RouterOS\Request(
'/ip pool print .proplist=name',
RouterOS\Query::where('name', $name)
);
$poolName = $client->sendSync($printRequest)->getProperty('name');
if(empty($poolName)){
if (empty($poolName)) {
self::addPool($client, $name, $ip_address);
}else{
} else {
$setRequest = new RouterOS\Request('/ip/pool/set');
$client(
$setRequest
@ -307,7 +330,8 @@ class Mikrotik
}
public static function addPpoePlan($client, $name, $pool, $rate){
public static function addPpoePlan($client, $name, $pool, $rate)
{
$addRequest = new RouterOS\Request('/ppp/profile/add');
$client->sendSync(
$addRequest
@ -318,15 +342,16 @@ class Mikrotik
);
}
public static function setPpoePlan($client, $name, $pool, $rate){
public static function setPpoePlan($client, $name, $pool, $rate)
{
$printRequest = new RouterOS\Request(
'/ppp profile print .proplist=name',
RouterOS\Query::where('name', $name)
);
$profileName = $client->sendSync($printRequest)->getProperty('name');
if(empty($profileName)){
if (empty($profileName)) {
self::addPpoePlan($client, $name, $pool, $rate);
}else{
} else {
$setRequest = new RouterOS\Request('/ppp/profile/set');
$client(
$setRequest
@ -338,7 +363,8 @@ class Mikrotik
}
}
public static function removePpoePlan($client, $name){
public static function removePpoePlan($client, $name)
{
$printRequest = new RouterOS\Request(
'/ppp profile print .proplist=name',
RouterOS\Query::where('name', $name)

View File

@ -33,7 +33,7 @@ class Package
if ($router_name == 'balance') {
// insert table transactions
$inv = "INV-" . _raid(5);
$inv = "INV-" . Package::_raid(5);
$t = ORM::for_table('tbl_transactions')->create();
$t->invoice = $inv;
$t->username = $c['username'];
@ -49,7 +49,7 @@ class Package
Balance::plus($id_customer, $p['price']);
$textInvoice = $_notifmsg['invoice_balance'];
$textInvoice = Lang::getNotifText('invoice_balance');
$textInvoice = str_replace('[[company_name]]', $_c['CompanyName'], $textInvoice);
$textInvoice = str_replace('[[address]]', $_c['address'], $textInvoice);
$textInvoice = str_replace('[[phone]]', $_c['phone'], $textInvoice);
@ -96,6 +96,7 @@ class Package
if (!$_c['radius_mode']) {
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
Mikrotik::removeHotspotUser($client, $c['username']);
Mikrotik::removePpoeUser($client, $c['username']);
Mikrotik::addHotspotUser($client, $p, $c);
}
@ -114,7 +115,7 @@ class Package
// insert table transactions
$t = ORM::for_table('tbl_transactions')->create();
$t->invoice = "INV-" . _raid(5);
$t->invoice = "INV-" . Package::_raid(5);
$t->username = $c['username'];
$t->plan_name = $p['name_plan'];
$t->price = $p['price'];
@ -128,6 +129,7 @@ class Package
} else {
if (!$_c['radius_mode']) {
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
Mikrotik::removePpoeUser($client, $c['username']);
Mikrotik::addHotspotUser($client, $p, $c);
}
@ -147,7 +149,7 @@ class Package
// insert table transactions
$t = ORM::for_table('tbl_transactions')->create();
$t->invoice = "INV-" . _raid(5);
$t->invoice = "INV-" . Package::_raid(5);
$t->username = $c['username'];
$t->plan_name = $p['name_plan'];
$t->price = $p['price'];
@ -163,12 +165,13 @@ class Package
"\nRouter: " . $router_name .
"\nGateway: " . $gateway .
"\nChannel: " . $channel .
"\nPrice: " . $p['price']);
"\nPrice: " . Lang::moneyFormat($p['price']));
} else {
if ($b) {
if (!$_c['radius_mode']) {
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
Mikrotik::removeHotspotUser($client, $c['username']);
Mikrotik::removePpoeUser($client, $c['username']);
Mikrotik::addPpoeUser($client, $p, $c);
}
@ -188,7 +191,7 @@ class Package
// insert table transactions
$t = ORM::for_table('tbl_transactions')->create();
$t->invoice = "INV-" . _raid(5);
$t->invoice = "INV-" . Package::_raid(5);
$t->username = $c['username'];
$t->plan_name = $p['name_plan'];
$t->price = $p['price'];
@ -202,6 +205,7 @@ class Package
} else {
if (!$_c['radius_mode']) {
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
Mikrotik::removeHotspotUser($client, $c['username']);
Mikrotik::addPpoeUser($client, $p, $c);
}
@ -221,7 +225,7 @@ class Package
// insert table transactions
$t = ORM::for_table('tbl_transactions')->create();
$t->invoice = "INV-" . _raid(5);
$t->invoice = "INV-" . Package::_raid(5);
$t->username = $c['username'];
$t->plan_name = $p['name_plan'];
$t->price = $p['price'];
@ -237,12 +241,12 @@ class Package
"\nRouter: " . $router_name .
"\nGateway: " . $gateway .
"\nChannel: " . $channel .
"\nPrice: " . $p['price']);
"\nPrice: " . Lang::moneyFormat($p['price']));
}
$in = ORM::for_table('tbl_transactions')->where('username', $c['username'])->order_by_desc('id')->find_one();
$textInvoice = $_notifmsg['invoice_paid'];
$textInvoice = Lang::getNotifText('invoice_paid');
$textInvoice = str_replace('[[company_name]]', $_c['CompanyName'], $textInvoice);
$textInvoice = str_replace('[[address]]', $_c['address'], $textInvoice);
$textInvoice = str_replace('[[phone]]', $_c['phone'], $textInvoice);
@ -301,4 +305,10 @@ class Package
}
}
}
public static function _raid($l)
{
return substr(str_shuffle(str_repeat('0123456789', $l)), 0, $l);
}
}

View File

@ -1,28 +1,29 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
**/
Class Paginator
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
**/
class Paginator
{
public static function bootstrap($table, $w1='',$c1='', $w2='', $c2= '', $w3='',$c3='', $w4='', $c4= '', $per_page = '10')
public static function bootstrap($table, $w1 = '', $c1 = '', $w2 = '', $c2 = '', $w3 = '', $c3 = '', $w4 = '', $c4 = '', $per_page = '10')
{
global $routes;
global $_L;
$url = U.$routes['0'].'/'.$routes['1'].'/';
$url = U . $routes['0'] . '/' . $routes['1'] . '/';
$adjacents = "2";
$page = (int)(!isset($routes['2']) ? 1 : $routes['2']);
$pagination = "";
if($w1 != ''){
$totalReq = ORM::for_table($table)->where($w1,$c1)->count();
}elseif($w2 != ''){
$totalReq = ORM::for_table($table)->where($w1,$c1)->where($w2,$c2)->count();
}elseif($w3 != ''){
$totalReq = ORM::for_table($table)->where($w1,$c1)->where($w2,$c2)->where($w3,$c3)->count();
}elseif($w4 != ''){
$totalReq = ORM::for_table($table)->where($w1,$c1)->where($w2,$c2)->where($w3,$c3)->where($w4,$c4)->count();
}else{
if ($w1 != '') {
$totalReq = ORM::for_table($table)->where($w1, $c1)->count();
} elseif ($w2 != '') {
$totalReq = ORM::for_table($table)->where($w1, $c1)->where($w2, $c2)->count();
} elseif ($w3 != '') {
$totalReq = ORM::for_table($table)->where($w1, $c1)->where($w2, $c2)->where($w3, $c3)->count();
} elseif ($w4 != '') {
$totalReq = ORM::for_table($table)->where($w1, $c1)->where($w2, $c2)->where($w3, $c3)->where($w4, $c4)->count();
} else {
$totalReq = ORM::for_table($table)->count();
}
@ -85,11 +86,98 @@ Class Paginator
}
if ($page < $counter - 1) {
$pagination .= "<li><a href='{$url}$next'>".$_L['Next']."</a></li>";
$pagination .= "<li><a href='{$url}$lastpage'>".$_L['Last']."</a></li>";
$pagination .= "<li><a href='{$url}$next'>" . $_L['Next'] . "</a></li>";
$pagination .= "<li><a href='{$url}$lastpage'>" . $_L['Last'] . "</a></li>";
} else {
$pagination .= "<li class='disabled'><a class='disabled'>".$_L['Next']."</a></li>";
$pagination .= "<li class='disabled'><a class='disabled'>".$_L['Last']."</a></li>";
$pagination .= "<li class='disabled'><a class='disabled'>" . $_L['Next'] . "</a></li>";
$pagination .= "<li class='disabled'><a class='disabled'>" . $_L['Last'] . "</a></li>";
}
$pagination .= "</ul>";
$gen = array("startpoint" => $startpoint, "limit" => $limit, "found" => $totalReq, "page" => $page, "lastpage" => $lastpage, "contents" => $pagination);
return $gen;
}
}
public static function bootstrapRaw($table, $w1 = '', $c1 = [], $per_page = '10')
{
global $routes;
global $_L;
$url = U . $routes['0'] . '/' . $routes['1'] . '/';
$adjacents = "2";
$page = (int)(!isset($routes['2']) ? 1 : $routes['2']);
$pagination = "";
if ($w1 != '') {
$totalReq = ORM::for_table($table)->where_raw($w1, $c1)->count();
} else {
$totalReq = ORM::for_table($table)->count();
}
$i = 0;
$page = ($page == 0 ? 1 : $page);
$start = ($page - 1) * $per_page;
$prev = $page - 1;
$next = $page + 1;
$lastpage = ceil($totalReq / $per_page);
$lpm1 = $lastpage - 1;
$limit = $per_page;
$startpoint = ($page * $limit) - $limit;
if ($lastpage >= 1) {
$pagination .= '<ul class="pagination pagination-sm">';
if ($lastpage < 7 + ($adjacents * 2)) {
for ($counter = 1; $counter <= $lastpage; $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>";
}
} elseif ($lastpage > 5 + ($adjacents * 2)) {
if ($page < 1 + ($adjacents * 2)) {
for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>";
}
$pagination .= "<li class='disabled'><a href='#'>...</a></li>";
$pagination .= "<li><a href='{$url}$lpm1'>$lpm1</a></li>";
$pagination .= "<li><a href='{$url}$lastpage'>$lastpage</a></li>";
} elseif ($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2)) {
$pagination .= "<li><a href='{$url}1'>1</a></li>";
$pagination .= "<li><a href='{$url}2'>2</a></li>";
$pagination .= "<li class='disabled'><a href='#'>...</a></li>";
for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>";
}
$pagination .= "<li class='disabled'><a href='#'>...</a></li>";
$pagination .= "<li><a href='{$url}$lpm1'>$lpm1</a></li>";
$pagination .= "<li><a href='{$url}$lastpage'>$lastpage</a></li>";
} else {
$pagination .= "<li><a href='{$url}1'>1</a></li>";
$pagination .= "<li><a href='{$url}2'>2</a></li>";
$pagination .= "<li><a href='#'>...</a></li>";
for ($counter = $lastpage - (2 + ($adjacents * 2)); $counter <= $lastpage; $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a class='disabled'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>";
}
}
}
if ($page < $counter - 1) {
$pagination .= "<li><a href='{$url}$next'>" . $_L['Next'] . "</a></li>";
$pagination .= "<li><a href='{$url}$lastpage'>" . $_L['Last'] . "</a></li>";
} else {
$pagination .= "<li class='disabled'><a class='disabled'>" . $_L['Next'] . "</a></li>";
$pagination .= "<li class='disabled'><a class='disabled'>" . $_L['Last'] . "</a></li>";
}
$pagination .= "</ul>";

View File

@ -131,9 +131,8 @@ include "autoload/Hookers.php";
// notification message
if(file_exists("system/uploads/notifications.json")){
$_notifmsg =json_decode(file_get_contents('system/uploads/notifications.json'), true);
}else{
$_notifmsg = json_decode(file_get_contents('system/uploads/notifications.default.json'), true);
}
$_notifmsg_default = json_decode(file_get_contents('system/uploads/notifications.default.json'), true);
//register all plugin
foreach (glob("system/plugin/*.php") as $filename) {
@ -191,10 +190,6 @@ function _admin($login = true)
}
}
function _raid($l)
{
return substr(str_shuffle(str_repeat('0123456789', $l)), 0, $l);
}
function _log($description, $type = '', $userid = '0')
{

View File

@ -1,8 +1,9 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
* used for ajax
**/
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
* used for ajax
**/
_admin();
$ui->assign('_title', $_L['Network']);
@ -16,13 +17,13 @@ switch ($action) {
case 'pool':
$routers = _get('routers');
$d = ORM::for_table('tbl_pool')->where('routers', $routers)->find_many();
$ui->assign('d',$d);
$ui->assign('d', $d);
$ui->display('autoload-pool.tpl');
break;
case 'server':
$d = ORM::for_table('tbl_routers')->where('enabled', '1')->find_many();
$ui->assign('d',$d);
$ui->assign('d', $d);
$ui->display('autoload-server.tpl');
break;
@ -31,11 +32,28 @@ switch ($action) {
$server = _post('server');
$jenis = _post('jenis');
$d = ORM::for_table('tbl_plans')->where('routers', $server)->where('type', $jenis)->where('enabled', '1')->find_many();
$ui->assign('d',$d);
$ui->assign('d', $d);
$ui->display('autoload.tpl');
break;
case 'customer_select2':
$s = addslashes(_get('s'));
if (empty($s)) {
$c = ORM::for_table('tbl_customers')->limit(30)->find_many();
} else {
$c = ORM::for_table('tbl_customers')->where_raw("(`username` LIKE '%$s%' OR `fullname` LIKE '%$s%' OR `phonenumber` LIKE '%$s%' OR `email` LIKE '%$s%')", [$s, $s, $s, $s])->limit(30)->find_many();
}
header('Content-Type: application/json');
foreach ($c as $cust) {
$json[] = [
'id' => $cust['id'],
'text' => $cust['username'] . ' - ' . $cust['fullname'] . ' - ' . $cust['email']
];
}
echo json_encode(['results' => $json]);
die();
break;
default:
echo 'action not defined';
}

View File

@ -24,15 +24,11 @@ switch ($action) {
case 'list':
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/customers.js"></script>');
$search = _post('search');
$what = _post('what');
if(!in_array($what,['username','fullname','phonenumber','email'])){
$what = 'username';
}
run_hook('list_customers'); #HOOK
if ($search != '') {
$paginator = Paginator::bootstrap('tbl_customers', 'username', '%' . $search . '%');
$paginator = Paginator::bootstrapRaw('tbl_customers', "(`username` LIKE '%$search%' OR `fullname` LIKE '%$search%' OR `phonenumber` LIKE '%$search%' OR `email` LIKE '%$search%')", [$search, $search, $search, $search]);
$d = ORM::for_table('tbl_customers')
->where_like($what, '%' . $search . '%')
->where_raw("(`username` LIKE '%$search%' OR `fullname` LIKE '%$search%' OR `phonenumber` LIKE '%$search%' OR `email` LIKE '%$search%')", [$search, $search, $search, $search])
->offset($paginator['startpoint'])
->limit($paginator['limit'])
->order_by_desc('id')->find_many();
@ -42,7 +38,6 @@ switch ($action) {
}
$ui->assign('search', htmlspecialchars($search));
$ui->assign('what', $what);
$ui->assign('d', $d);
$ui->assign('paginator', $paginator);
$ui->display('customers.tpl');
@ -53,6 +48,48 @@ switch ($action) {
$ui->display('customers-add.tpl');
break;
case 'viewu':
$customer = ORM::for_table('tbl_customers')->where('username', $routes['2'])->find_one();
case 'view':
$id = $routes['2'];
run_hook('view_customer'); #HOOK
if(!$customer){
$customer = ORM::for_table('tbl_customers')->find_one($id);
}
if ($customer) {
$v = $routes['3'];
if (empty($v) || $v == 'order') {
$v = 'order';
// $paginator = Paginator::bootstrap('tbl_payment_gateway', 'username', $customer['username']);
// print_r($paginator);
$order = ORM::for_table('tbl_payment_gateway')
->where('username', $customer['username'])
->offset(0)
->limit(30)
->order_by_desc('id')
->find_many();
// $ui->assign('paginator', $paginator);
$ui->assign('order', $order);
} else if ($v == 'activation') {
// $paginator = Paginator::bootstrap('tbl_transactions', 'username', $customer['username']);
$activation = ORM::for_table('tbl_transactions')
->where('username', $customer['username'])
->offset(0)
->limit(30)
->order_by_desc('id')
->find_many();
// $ui->assign('paginator', $paginator);
$ui->assign('activation', $activation);
}
$package = ORM::for_table('tbl_user_recharges')->where('username',$customer['username'])->find_one();
$ui->assign('package', $package);
$ui->assign('v', $v);
$ui->assign('d', $customer);
$ui->display('customers-view.tpl');
} else {
r2(U . 'customers/list', 'e', $_L['Account_Not_Found']);
}
break;
case 'edit':
$id = $routes['2'];
run_hook('edit_customer'); #HOOK
@ -74,22 +111,22 @@ switch ($action) {
if ($c) {
$mikrotik = Mikrotik::info($c['routers']);
if ($c['type'] == 'Hotspot') {
if(!$config['radius_mode']){
if (!$config['radius_mode']) {
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
Mikrotik::removeHotspotUser($client,$c['username']);
Mikrotik::removeHotspotActiveUser($client,$user['username']);
Mikrotik::removeHotspotUser($client, $c['username']);
Mikrotik::removeHotspotActiveUser($client, $c['username']);
}
} else {
if(!$config['radius_mode']){
if (!$config['radius_mode']) {
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
Mikrotik::removePpoeUser($client,$c['username']);
Mikrotik::removePpoeActive($client,$user['username']);
Mikrotik::removePpoeUser($client, $c['username']);
Mikrotik::removePpoeActive($client, $c['username']);
}
}
try {
$d->delete();
} catch (Exception $e) {
} catch(Throwable $e){
} catch (Throwable $e) {
}
try {
$c->delete();
@ -99,12 +136,12 @@ switch ($action) {
try {
$d->delete();
} catch (Exception $e) {
} catch(Throwable $e){
} catch (Throwable $e) {
}
try {
$c->delete();
} catch (Exception $e) {
} catch(Throwable $e){
} catch (Throwable $e) {
}
}
@ -193,23 +230,23 @@ switch ($action) {
if ($c) {
$mikrotik = Mikrotik::info($c['routers']);
if ($c['type'] == 'Hotspot') {
if(!$config['radius_mode']){
if (!$config['radius_mode']) {
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
Mikrotik::setHotspotUser($client,$c['username'],$password);
Mikrotik::removeHotspotActiveUser($client,$user['username']);
Mikrotik::setHotspotUser($client, $c['username'], $password);
Mikrotik::removeHotspotActiveUser($client, $user['username']);
}
$d->password = $password;
$d->save();
} else {
if(!$config['radius_mode']){
if (!$config['radius_mode']) {
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
if(!empty($d['pppoe_password'])){
if (!empty($d['pppoe_password'])) {
Mikrotik::setPpoeUser($client, $c['username'], $d['pppoe_password']);
}else{
} else {
Mikrotik::setPpoeUser($client, $c['username'], $password);
}
Mikrotik::removePpoeActive($client,$user['username']);
Mikrotik::removePpoeActive($client, $user['username']);
}
$d->password = $password;

View File

@ -168,7 +168,7 @@ $style
$html
EOF;
$mpdf->WriteHTML($nhtml);
$mpdf->Output(date('Y-m-d') . _raid(4) . '.pdf', 'D');
$mpdf->Output(date('Y-m-d') . Package::_raid(4) . '.pdf', 'D');
} else {
echo 'No Data';
}
@ -340,7 +340,7 @@ $style
$html
EOF;
$mpdf->WriteHTML($nhtml);
$mpdf->Output(date('Y-m-d') . _raid(4) . '.pdf', 'D');
$mpdf->Output(date('Y-m-d') . Package::_raid(4) . '.pdf', 'D');
} else {
echo 'No Data';
}

View File

@ -9,11 +9,72 @@ $ui->assign('_title', $_L['Dashboard']);
$user = User::_info();
$ui->assign('_user', $user);
if(isset($_GET['renewal'])){
if (isset($_GET['renewal'])) {
$user->auto_renewal = $_GET['renewal'];
$user->save();
}
if (_post('send') == 'balance') {
if ($config['allow_balance_transfer'] == 'yes') {
$target = ORM::for_table('tbl_customers')->where('username', _post('username'))->find_one();
if (!$target) {
r2(U . 'home', 'd', Lang::T('Username not found'));
}
$username = _post('username');
$balance = _post('balance');
if ($user['balance'] < $balance) {
r2(U . 'home', 'd', Lang::T('insufficient balance'));
}
if (intval($config['minimum_transfer']) >= intval($balance)) {
r2(U . 'home', 'd', Lang::T('Minimum Transfer') . ' ' . Lang::moneyFormat($config['minimum_transfer']));
}
if ($user['username'] == $target['username']) {
r2(U . 'home', 'd', Lang::T('Cannot send to yourself'));
}
if (Balance::transfer($user['id'], $username, $balance)) {
//sender
$d = ORM::for_table('tbl_payment_gateway')->create();
$d->username = $user['username'];
$d->gateway = $target['username'];
$d->plan_id = 0;
$d->plan_name = 'Send Balance';
$d->routers_id = 0;
$d->routers = 'balance';
$d->price = $balance;
$d->payment_method = "Customer";
$d->payment_channel = "Balance";
$d->created_date = date('Y-m-d H:i:s');
$d->paid_date = date('Y-m-d H:i:s');
$d->expired_date = date('Y-m-d H:i:s');
$d->pg_url_payment = 'balance';
$d->status = 2;
$d->save();
//receiver
$d = ORM::for_table('tbl_payment_gateway')->create();
$d->username = $target['username'];
$d->gateway = $user['username'];
$d->plan_id = 0;
$d->plan_name = 'Receive Balance';
$d->routers_id = 0;
$d->routers = 'balance';
$d->payment_method = "Customer";
$d->payment_channel = "Balance";
$d->price = $balance;
$d->created_date = date('Y-m-d H:i:s');
$d->paid_date = date('Y-m-d H:i:s');
$d->expired_date = date('Y-m-d H:i:s');
$d->pg_url_payment = 'balance';
$d->status = 2;
$d->save();
Message::sendBalanceNotification($user['phonenumber'], $target['fullname'] . ' (' . $target['username'] . ')', $balance, Lang::getNotifText('balance_send'), $config['user_notification_payment']);
Message::sendBalanceNotification($target['phonenumber'], $user['fullname'] . ' (' . $user['username'] . ')', $balance, Lang::getNotifText('balance_received'), $config['user_notification_payment']);
Message::sendTelegram("#u$user[username] send balance to #u$target[username] \n" . Lang::moneyFormat($balance));
r2(U . 'home', 's', Lang::T('Sending balance success'));
}
} else {
r2(U . 'home', 'd', 'Failed, balance is not available');
}
}
//Client Page
$bill = User::_billing();
@ -27,7 +88,7 @@ if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'])) {
$c = Mikrotik::getClient($m['ip_address'], $m['username'], $m['password']);
Mikrotik::logMeIn($c, $user['username'], $user['password'], $_SESSION['nux-ip'], $_SESSION['nux-mac']);
r2(U . 'home', 's', Lang::T('Login Request successfully'));
}else if ($_GET['mikrotik'] == 'logout') {
} else if ($_GET['mikrotik'] == 'logout') {
$m = Mikrotik::info($bill['routers']);
$c = Mikrotik::getClient($m['ip_address'], $m['username'], $m['password']);
Mikrotik::logMeOut($c, $user['username']);

View File

@ -17,11 +17,12 @@ switch ($action) {
break;
case 'history':
$ui->assign('_system_menu', 'history');
$paginator = Paginator::bootstrap('tbl_payment_gateway', 'username', $user['username']);
$d = ORM::for_table('tbl_payment_gateway')
->where('username', $user['username'])
->order_by_desc('id')
->offset($paginator['startpoint'])->limit($paginator['limit'])
->find_many();
$paginator = Paginator::bootstrap('tbl_payment_gateway', 'username', $user['username']);
$ui->assign('paginator', $paginator);
$ui->assign('d', $d);
$ui->assign('_title', Lang::T('Order History'));
@ -62,7 +63,7 @@ switch ($action) {
}
break;
case 'view':
$trxid = $routes['2'] * 1;
$trxid = $routes['2'];
$trx = ORM::for_table('tbl_payment_gateway')
->where('username', $user['username'])
->find_one($trxid);
@ -97,7 +98,7 @@ switch ($action) {
}
}
if (empty($trx)) {
r2(U . "home", 'e', Lang::T("Transaction Not found"));
r2(U . "order", 'e', Lang::T("Transaction Not found"));
}
$router = ORM::for_table('tbl_routers')->find_one($trx['routers_id']);
$plan = ORM::for_table('tbl_plans')->find_one($trx['plan_id']);
@ -109,6 +110,30 @@ switch ($action) {
$ui->assign('_title', 'TRX #' . $trxid);
$ui->display('user-orderView.tpl');
break;
case 'pay':
if ($_c['enable_balance'] != 'yes'){
r2(U . "order", 'e', Lang::T("Balance not enabled"));
}
$plan = ORM::for_table('tbl_plans')->where('enabled', '1')->find_one($routes['3']);
$router = ORM::for_table('tbl_routers')->where('enabled', '1')->find_one($routes['2']);
if (empty($router) || empty($plan)) {
r2(U . "order/package", 'e', Lang::T("Plan Not found"));
}
if ($plan && $plan['enabled'] && $user['balance'] >= $plan['price']) {
if (Package::rechargeUser($user['id'], $plan['routers'], $plan['id'], 'Customer', 'Balance')) {
// if success, then get the balance
Balance::min($user['id'], $plan['price']);
r2(U . "home", 's', Lang::T("Success to buy package"));
} else {
r2(U . "order/package", 'e', Lang::T("Failed to buy package"));
Message::sendTelegram("Buy Package with Balance Failed\n\n#u$c[username] #buy \n" . $plan['name_plan'] .
"\nRouter: " . $router_name .
"\nPrice: " . $p['price']);
}
}else{
echo "no renewall | plan enabled: $p[enabled] | User balance: $c[balance] | price $p[price]\n";
}
break;
case 'buy':
if (strpos($user['email'], '@') === false) {
r2(U . 'accounts/profile', 'e', Lang::T("Please enter your email address"));

View File

@ -145,5 +145,5 @@ switch ($action) {
break;
default:
echo 'action not defined';
r2(U . 'pool/list/', 's', '');
}

View File

@ -18,7 +18,24 @@ if ($admin['user_type'] != 'Admin' and $admin['user_type'] != 'Sales') {
r2(U . "dashboard", 'e', $_L['Do_Not_Access']);
}
use PEAR2\Net\RouterOS;
$select2_customer = <<<EOT
<script>
document.addEventListener("DOMContentLoaded", function(event) {
$('#personSelect').select2({
theme: "bootstrap",
ajax: {
url: function(params) {
if(params.term != undefined){
return './index.php?_route=autoload/customer_select2&s='+params.term;
}else{
return './index.php?_route=autoload/customer_select2';
}
}
}
});
});
</script>
EOT;
require_once 'system/autoload/PEAR2/Autoload.php';
@ -43,8 +60,7 @@ switch ($action) {
break;
case 'recharge':
$c = ORM::for_table('tbl_customers')->find_many();
$ui->assign('c', $c);
$ui->assign('xfooter', $select2_customer);
$p = ORM::for_table('tbl_plans')->where('enabled', '1')->find_many();
$ui->assign('p', $p);
$r = ORM::for_table('tbl_routers')->where('enabled', '1')->find_many();
@ -81,14 +97,14 @@ switch ($action) {
}
if ($msg == '') {
if(Package::rechargeUser($id_customer, $server, $plan, "Recharge", $admin['fullname'])){
if (Package::rechargeUser($id_customer, $server, $plan, "Recharge", $admin['fullname'])) {
$c = ORM::for_table('tbl_customers')->where('id', $id_customer)->find_one();
$in = ORM::for_table('tbl_transactions')->where('username', $c['username'])->order_by_desc('id')->find_one();
$ui->assign('in', $in);
$ui->assign('date', date("Y-m-d H:i:s"));
$ui->display('invoice.tpl');
_log('[' . $admin['username'] . ']: ' . 'Recharge '.$c['username'].' ['.$in['plan_name'].']['.Lang::moneyFormat($in['price']).']', 'Admin', $admin['id']);
}else{
_log('[' . $admin['username'] . ']: ' . 'Recharge ' . $c['username'] . ' [' . $in['plan_name'] . '][' . Lang::moneyFormat($in['price']) . ']', 'Admin', $admin['id']);
} else {
r2(U . 'prepaid/recharge', 'e', "Failed to recharge account");
}
} else {
@ -129,20 +145,20 @@ switch ($action) {
if ($d) {
run_hook('delete_customer_active_plan'); #HOOK
if ($d['type'] == 'Hotspot') {
if(!$config['radius_mode']){
if (!$config['radius_mode']) {
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
Mikrotik::removeHotspotUser($client,$c['username']);
Mikrotik::removeHotspotUser($client, $c['username']);
}
$d->delete();
} else {
if(!$config['radius_mode']){
if (!$config['radius_mode']) {
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
Mikrotik::removePpoeUser($client,$c['username']);
Mikrotik::removePpoeUser($client, $c['username']);
}
$d->delete();
}
_log('[' . $admin['username'] . ']: ' . 'Delete Plan for Customer '.$c['username'].' ['.$in['plan_name'].']['.Lang::moneyFormat($in['price']).']', 'Admin', $admin['id']);
_log('[' . $admin['username'] . ']: ' . 'Delete Plan for Customer ' . $c['username'] . ' [' . $in['plan_name'] . '][' . Lang::moneyFormat($in['price']) . ']', 'Admin', $admin['id']);
r2(U . 'prepaid/list', 's', $_L['Delete_Successfully']);
}
break;
@ -167,8 +183,8 @@ switch ($action) {
$d->recharged_on = $recharged_on;
$d->expiration = $expiration;
$d->save();
Package::changeTo($username,$id_plan);
_log('[' . $admin['username'] . ']: ' . 'Edit Plan for Customer '.$d['username'].' to ['.$d['plan_name'].']['.Lang::moneyFormat($d['price']).']', 'Admin', $admin['id']);
Package::changeTo($username, $id_plan);
_log('[' . $admin['username'] . ']: ' . 'Edit Plan for Customer ' . $d['username'] . ' to [' . $d['plan_name'] . '][' . Lang::moneyFormat($d['price']) . ']', 'Admin', $admin['id']);
r2(U . 'prepaid/list', 's', $_L['Updated_Successfully']);
} else {
r2(U . 'prepaid/edit/' . $id, 'e', $msg);
@ -341,10 +357,8 @@ switch ($action) {
break;
case 'refill':
$ui->assign('xfooter', '<script type="text/javascript" src="ui/ui/scripts/form-elements.init.js"></script>');
$ui->assign('xfooter', $select2_customer);
$ui->assign('_title', $_L['Refill_Account']);
$c = ORM::for_table('tbl_customers')->find_many();
$ui->assign('c', $c);
run_hook('view_refill'); #HOOK
$ui->display('refill.tpl');
@ -358,7 +372,7 @@ switch ($action) {
run_hook('refill_customer'); #HOOK
if ($v1) {
if(Package::rechargeUser($user, $v1['routers'], $v1['id_plan'], "Refill", "Voucher")){
if (Package::rechargeUser($user, $v1['routers'], $v1['id_plan'], "Refill", "Voucher")) {
$v1->status = "1";
$v1->user = $c['username'];
$v1->save();
@ -367,7 +381,7 @@ switch ($action) {
$ui->assign('in', $in);
$ui->assign('date', date("Y-m-d H:i:s"));
$ui->display('invoice.tpl');
}else{
} else {
r2(U . 'prepaid/refill', 'e', "Failed to refill account");
}
} else {
@ -376,7 +390,7 @@ switch ($action) {
break;
case 'deposit':
$ui->assign('_title', Lang::T('Refill Balance'));
$ui->assign('c', ORM::for_table('tbl_customers')->find_many());
$ui->assign('xfooter', $select2_customer);
$ui->assign('p', ORM::for_table('tbl_plans')->where('enabled', '1')->where('type', 'Balance')->find_many());
run_hook('view_deposit'); #HOOK
$ui->display('deposit.tpl');
@ -387,13 +401,13 @@ switch ($action) {
run_hook('deposit_customer'); #HOOK
if (!empty($user) && !empty($plan)) {
if(Package::rechargeUser($user, 'balance', $plan, "Deposit", $admin['fullname'])){
if (Package::rechargeUser($user, 'balance', $plan, "Deposit", $admin['fullname'])) {
$c = ORM::for_table('tbl_customers')->where('id', $user)->find_one();
$in = ORM::for_table('tbl_transactions')->where('username', $c['username'])->order_by_desc('id')->find_one();
$ui->assign('in', $in);
$ui->assign('date', date("Y-m-d H:i:s"));
$ui->display('invoice.tpl');
}else{
} else {
r2(U . 'prepaid/refill', 'e', "Failed to refill account");
}
} else {

View File

@ -187,5 +187,5 @@ switch ($action) {
break;
default:
echo 'action not defined';
r2(U . 'routers/list/', 's', '');
}

View File

@ -213,6 +213,7 @@ switch ($action) {
$telegram_target_id = _post('telegram_target_id');
$sms_url = _post('sms_url');
$wa_url = _post('wa_url');
$minimum_transfer = _post('minimum_transfer');
$user_notification_expired = _post('user_notification_expired');
$user_notification_reminder = _post('user_notification_reminder');
$user_notification_payment = _post('user_notification_payment');
@ -281,6 +282,17 @@ switch ($action) {
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'minimum_transfer')->find_one();
if($d){
$d->value = $minimum_transfer;
$d->save();
}else{
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'minimum_transfer';
$d->value = $minimum_transfer;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'telegram_bot')->find_one();
if($d){
$d->value = $telegram_bot;
@ -502,6 +514,7 @@ switch ($action) {
}else{
$ui->assign('_json', json_decode(file_get_contents('system/uploads/notifications.default.json'), true));
}
$ui->assign('_default', json_decode(file_get_contents('system/uploads/notifications.default.json'), true));
$ui->display('app-notifications.tpl');
break;
case 'notifications-post':

View File

@ -73,7 +73,7 @@ switch ($action) {
// insert table transactions
$t = ORM::for_table('tbl_transactions')->create();
$t->invoice = "INV-" . _raid(5);
$t->invoice = "INV-" . Package::_raid(5);
$t->username = $c['username'];
$t->plan_name = $p['name_plan'];
$t->price = $p['price'];
@ -106,7 +106,7 @@ switch ($action) {
// insert table transactions
$t = ORM::for_table('tbl_transactions')->create();
$t->invoice = "INV-" . _raid(5);
$t->invoice = "INV-" . Package::_raid(5);
$t->username = $c['username'];
$t->plan_name = $p['name_plan'];
$t->price = $p['price'];
@ -150,7 +150,7 @@ switch ($action) {
// insert table transactions
$t = ORM::for_table('tbl_transactions')->create();
$t->invoice = "INV-" . _raid(5);
$t->invoice = "INV-" . Package::_raid(5);
$t->username = $c['username'];
$t->plan_name = $p['name_plan'];
$t->price = $p['price'];
@ -183,7 +183,7 @@ switch ($action) {
// insert table transactions
$t = ORM::for_table('tbl_transactions')->create();
$t->invoice = "INV-" . _raid(5);
$t->invoice = "INV-" . Package::_raid(5);
$t->username = $c['username'];
$t->plan_name = $p['name_plan'];
$t->price = $p['price'];

View File

@ -19,11 +19,10 @@ ORM::configure('logging', true);
include "autoload/Hookers.php";
// notification message
if (file_exists("uploads/notifications.json")) {
$_notifmsg = json_decode(file_get_contents('uploads/notifications.json'), true);
} else {
$_notifmsg = json_decode(file_get_contents('uploads/notifications.default.json'), true);
if(file_exists("system/uploads/notifications.json")){
$_notifmsg =json_decode(file_get_contents('system/uploads/notifications.json'), true);
}
$_notifmsg_default = json_decode(file_get_contents('system/uploads/notifications.default.json'), true);
//register all plugin
foreach (glob("plugin/*.php") as $filename) {
@ -59,12 +58,15 @@ $result = ORM::for_table('tbl_appconfig')->find_many();
foreach ($result as $value) {
$config[$value['setting']] = $value['value'];
}
$_c = $config;
date_default_timezone_set($config['timezone']);
$textExpired = $_notifmsg['expired'];
$d = ORM::for_table('tbl_user_recharges')->where('status', 'on')->find_many();
$textExpired = Lang::getNotifText('expired');
$d = ORM::for_table('tbl_user_recharges')->where('status', 'on')->where('expiration', date("Y-m-d"))->find_many();
echo "Found ".count($d)." user(s)\n";
run_hook('cronjob'); #HOOK
foreach ($d as $ds) {
@ -95,12 +97,20 @@ foreach ($d as $ds) {
if (Package::rechargeUser($ds['customer_id'], $p['routers'], $p['id'], 'Customer', 'Balance')) {
// if success, then get the balance
Balance::min($ds['customer_id'], $p['price']);
echo "plan enabled: $p[enabled] | User balance: $c[balance] | price $p[price]\n";
echo "auto renewall Success\n";
} else {
echo "plan enabled: $p[enabled] | User balance: $c[balance] | price $p[price]\n";
echo "auto renewall Failed\n";
Message::sendTelegram("FAILED RENEWAL #cron\n\n#u$c[username] #buy #Hotspot \n" . $p['name_plan'] .
"\nRouter: " . $router_name .
"\nPrice: " . $p['price']);
}
}else{
echo "no renewall | plan enabled: $p[enabled] | User balance: $c[balance] | price $p[price]\n";
}
}else{
echo "no renewall | balance $config[enable_balance] auto_renewal $c[auto_renewal]\n";
}
} else echo " : ACTIVE \r\n";
} else {
@ -131,7 +141,7 @@ foreach ($d as $ds) {
// if success, then get the balance
Balance::min($ds['customer_id'], $p['price']);
} else {
Message::sendTelegram("FAILED RENEWAL #cron\n\n#u$c[username] #buy #Hotspot \n" . $p['name_plan'] .
Message::sendTelegram("FAILED RENEWAL #cron\n\n#u$c[username] #buy #PPPOE \n" . $p['name_plan'] .
"\nRouter: " . $router_name .
"\nPrice: " . $p['price']);
}

View File

@ -22,11 +22,10 @@ ORM::configure('logging', true);
include "autoload/Hookers.php";
// notification message
if(file_exists("uploads/notifications.json")){
$_notifmsg =json_decode(file_get_contents('uploads/notifications.json'), true);
}else{
$_notifmsg = json_decode(file_get_contents('uploads/notifications.default.json'), true);
if(file_exists("system/uploads/notifications.json")){
$_notifmsg =json_decode(file_get_contents('system/uploads/notifications.json'), true);
}
$_notifmsg_default = json_decode(file_get_contents('system/uploads/notifications.default.json'), true);
//register all plugin
foreach (glob("plugin/*.php") as $filename) {
@ -74,17 +73,17 @@ run_hook('cronjob_reminder'); #HOOK
$day7 = date('Y-m-d', strtotime("+7 day"));
$day3 = date('Y-m-d', strtotime("+3 day"));
$day1 = date('Y-m-d', strtotime("+1 day"));
print_r([$day1,$day3,$day7]);
print_r([$day1, $day3, $day7]);
foreach ($d as $ds) {
if(in_array($ds['expiration'],[$day1,$day3,$day7])){
if (in_array($ds['expiration'], [$day1, $day3, $day7])) {
$u = ORM::for_table('tbl_user_recharges')->where('id', $ds['id'])->find_one();
$c = ORM::for_table('tbl_customers')->where('id', $ds['customer_id'])->find_one();
if($ds['expiration']==$day7){
echo Message::sendPackageNotification($c['phonenumber'], $c['fullname'], $u['namebp'], $_notifmsg['reminder_7_day'], $config['user_notification_reminder'])."\n";
}else if($ds['expiration']==$day3){
echo Message::sendPackageNotification($c['phonenumber'], $c['fullname'], $u['namebp'], $_notifmsg['reminder_3_day'], $config['user_notification_reminder'])."\n";
}else if($ds['expiration']==$day1){
echo Message::sendPackageNotification($c['phonenumber'], $c['fullname'], $u['namebp'], $_notifmsg['reminder_1_day'], $config['user_notification_reminder'])."\n";
if ($ds['expiration'] == $day7) {
echo Message::sendPackageNotification($c['phonenumber'], $c['fullname'], $u['namebp'], Lang::getNotifText('reminder_7_day'), $config['user_notification_reminder']) . "\n";
} else if ($ds['expiration'] == $day3) {
echo Message::sendPackageNotification($c['phonenumber'], $c['fullname'], $u['namebp'], Lang::getNotifText('reminder_3_day'), $config['user_notification_reminder']) . "\n";
} else if ($ds['expiration'] == $day1) {
echo Message::sendPackageNotification($c['phonenumber'], $c['fullname'], $u['namebp'], Lang::getNotifText('reminder_1_day'), $config['user_notification_reminder']) . "\n";
}
}
}

View File

@ -365,3 +365,22 @@ $_L['Enable_auto_renewal'] = 'Enable auto renewal?';
$_L['Auto_Renewal_Off'] = 'Auto Renewal Off';
$_L['Refill_Balance'] = 'Refill Balance';
$_L['Invoice_Footer'] = 'Invoice Footer';
$_L['Pay_With_Balance'] = 'Pay With Balance';
$_L['Pay_this_with_Balance_your_active_package_will_be_overwrite'] = 'Pay this with Balance? your active package will be overwrite';
$_L['Success_to_buy_package'] = 'Success to buy package';
$_L['Auto_Renewal'] = 'Auto Renewal';
$_L['View'] = 'View';
$_L['Back'] = 'Back';
$_L['Active'] = 'Active';
$_L['Transfer_Balance'] = 'Transfer Balance';
$_L['Send_your_balance'] = 'Send your balance?';
$_L['Send'] = 'Send';
$_L['Cannot_send_to_yourself'] = 'Cannot send to yourself';
$_L['Sending_balance_success'] = 'Sending balance success';
$_L['From'] = 'From';
$_L['To'] = 'To';
$_L['insufficient_balance'] = 'insufficient balance';
$_L['Send_Balance'] = 'Send Balance';
$_L['Received_Balance'] = 'Received Balance';
$_L['Minimum_Balance_Transfer'] = 'Minimum Balance Transfer';
$_L['Minimum_Transfer'] = 'Minimum Transfer';

View File

@ -1,6 +1,6 @@
<?php
/**
/**
*
* Idiorm
*
@ -36,9 +36,83 @@
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* The methods documented below are magic methods that conform to PSR-1.
* This documentation exposes these methods to doc generators and IDEs.
* @see http://www.php-fig.org/psr/psr-1/
*
* @method static array|string getConfig($key = null, $connection_name = self::DEFAULT_CONNECTION)
* @method static null resetConfig()
* @method static \ORM forTable($table_name, $connection_name = self::DEFAULT_CONNECTION)
* @method static null setDb($db, $connection_name = self::DEFAULT_CONNECTION)
* @method static null resetDb()
* @method static null setupLimitClauseStyle($connection_name)
* @method static \PDO getDb($connection_name = self::DEFAULT_CONNECTION)
* @method static bool rawExecute($query, $parameters = array())
* @method static \PDOStatement getLastStatement()
* @method static string getLastQuery($connection_name = null)
* @method static array getQueryLog($connection_name = self::DEFAULT_CONNECTION)
* @method array getConnectionNames()
* @method $this useIdColumn($id_column)
* @method \ORM|bool findOne($id=null)
* @method array|\IdiormResultSet findMany()
* @method \IdiormResultSet findResultSet()
* @method array findArray()
* @method $this forceAllDirty()
* @method $this rawQuery($query, $parameters = array())
* @method $this tableAlias($alias)
* @method int countNullIdColumns()
* @method $this selectExpr($expr, $alias=null)
* @method \ORM selectMany($values)
* @method \ORM selectManyExpr($values)
* @method $this rawJoin($table, $constraint, $table_alias, $parameters = array())
* @method $this innerJoin($table, $constraint, $table_alias=null)
* @method $this leftOuterJoin($table, $constraint, $table_alias=null)
* @method $this rightOuterJoin($table, $constraint, $table_alias=null)
* @method $this fullOuterJoin($table, $constraint, $table_alias=null)
* @method $this whereEqual($column_name, $value=null)
* @method $this whereNotEqual($column_name, $value=null)
* @method $this whereIdIs($id)
* @method $this whereAnyIs($values, $operator='=')
* @method array|string whereIdIn($ids)
* @method $this whereLike($column_name, $value=null)
* @method $this whereNotLike($column_name, $value=null)
* @method $this whereGt($column_name, $value=null)
* @method $this whereLt($column_name, $value=null)
* @method $this whereGte($column_name, $value=null)
* @method $this whereLte($column_name, $value=null)
* @method $this whereIn($column_name, $values)
* @method $this whereNotIn($column_name, $values)
* @method $this whereNull($column_name)
* @method $this whereNotNull($column_name)
* @method $this whereRaw($clause, $parameters=array())
* @method $this orderByDesc($column_name)
* @method $this orderByAsc($column_name)
* @method $this orderByExpr($clause)
* @method $this groupBy($column_name)
* @method $this groupByExpr($expr)
* @method $this havingEqual($column_name, $value=null)
* @method $this havingNotEqual($column_name, $value=null)
* @method $this havingIdIs($id)
* @method $this havingLike($column_name, $value=null)
* @method $this havingNotLike($column_name, $value=null)
* @method $this havingGt($column_name, $value=null)
* @method $this havingLt($column_name, $value=null)
* @method $this havingGte($column_name, $value=null)
* @method $this havingLte($column_name, $value=null)
* @method $this havingIn($column_name, $values=null)
* @method $this havingNotIn($column_name, $values=null)
* @method $this havingNull($column_name)
* @method $this havingNotNull($column_name)
* @method $this havingRaw($clause, $parameters=array())
* @method static this clearCache($table_name = null, $connection_name = self::DEFAULT_CONNECTION)
* @method array asArray()
* @method bool setExpr($key, $value = null)
* @method bool isDirty($key)
* @method bool isNew()
*/
class ORM implements ArrayAccess {
class ORM implements ArrayAccess {
// ----------------------- //
// --- CLASS CONSTANTS --- //
@ -179,7 +253,7 @@ class ORM implements ArrayAccess {
* required to use Idiorm). If you have more than one setting
* you wish to configure, another shortcut is to pass an array
* of settings (and omit the second argument).
* @param string $key
* @param string|array $key
* @param mixed $value
* @param string $connection_name Which connection to use
*/
@ -238,12 +312,6 @@ class ORM implements ArrayAccess {
return new self($table_name, array(), $connection_name);
}
public static function execute($query) {
self::_setup_db(self::DEFAULT_CONNECTION);
return self::_execute($query);
}
/**
* Set up the database connection used by the class
* @param string $connection_name Which connection to use
@ -293,9 +361,11 @@ class ORM implements ArrayAccess {
}
/**
* Delete all registered PDO objects in _db array.
* Close and delete all registered PDO objects in _db array.
*/
public static function reset_db() {
self::$_db = null;
self::$_db = array();
}
@ -462,15 +532,14 @@ class ORM implements ArrayAccess {
self::$_query_log[$connection_name] = array();
}
// Strip out any non-integer indexes from the parameters
foreach($parameters as $key => $value) {
if (!is_int($key)) unset($parameters[$key]);
}
if (count($parameters) > 0) {
if (empty($parameters)) {
$bound_query = $query;
} else {
// Escape the parameters
$parameters = array_map(array(self::get_db($connection_name), 'quote'), $parameters);
if (array_values($parameters) === $parameters) {
// ? placeholders
// Avoid %format collision for vsprintf
$query = str_replace("%", "%%", $query);
@ -484,8 +553,13 @@ class ORM implements ArrayAccess {
// Replace the question marks in the query with the parameters
$bound_query = vsprintf($query, $parameters);
} else {
// named placeholders
foreach ($parameters as $key => $val) {
$query = str_replace($key, $val, $query);
}
$bound_query = $query;
}
}
self::$_last_query = $bound_query;
self::$_query_log[$connection_name][] = $bound_query;
@ -1261,14 +1335,14 @@ class ORM implements ArrayAccess {
$data = array();
$query = array("((");
$first = true;
foreach ($values as $item) {
foreach ($values as $value) {
if ($first) {
$first = false;
} else {
$query[] = ") OR (";
}
$firstsub = true;
foreach($item as $key => $item) {
foreach($value as $key => $item) {
$op = is_string($operator) ? $operator : (isset($operator[$key]) ? $operator[$key] : '=');
if ($firstsub) {
$firstsub = false;
@ -1281,7 +1355,7 @@ class ORM implements ArrayAccess {
}
}
$query[] = "))";
return $this->where_raw(join($query, ' '), $data);
return $this->where_raw(join(' ', $query), $data);
}
/**
@ -1475,7 +1549,7 @@ class ORM implements ArrayAccess {
*/
public function having_id_is($id) {
return (is_array($this->_get_id_column_name())) ?
$this->having($this->_get_compound_id_column_values($value)) :
$this->having($this->_get_compound_id_column_values($id), null) :
$this->having($this->_get_id_column_name(), $id);
}
@ -1827,6 +1901,7 @@ class ORM implements ArrayAccess {
$cached_result = self::_check_query_cache($cache_key, $this->_table_name, $this->_connection_name);
if ($cached_result !== false) {
$this->_reset_idiorm_state();
return $cached_result;
}
}
@ -1843,12 +1918,17 @@ class ORM implements ArrayAccess {
self::_cache_query_result($cache_key, $rows, $this->_table_name, $this->_connection_name);
}
// reset Idiorm after executing the query
$this->_reset_idiorm_state();
return $rows;
}
/**
* Reset the Idiorm instance state
*/
private function _reset_idiorm_state() {
$this->_values = array();
$this->_result_columns = array('*');
$this->_using_default_result_columns = true;
return $rows;
}
/**
@ -1970,7 +2050,7 @@ class ORM implements ArrayAccess {
* object was saved.
*/
public function is_dirty($key) {
return isset($this->_dirty_fields[$key]);
return array_key_exists($key, $this->_dirty_fields);
}
/**
@ -2029,7 +2109,7 @@ class ORM implements ArrayAccess {
// if the primary key is compound, assign the last inserted id
// to the first column
if (is_array($column)) {
$column = array_slice($column, 0, 1);
$column = reset($column);
}
$this->_data[$column] = $db->lastInsertId();
}
@ -2129,14 +2209,17 @@ class ORM implements ArrayAccess {
// --- ArrayAccess --- //
// --------------------- //
#[\ReturnTypeWillChange]
public function offsetExists($key) {
return array_key_exists($key, $this->_data);
}
#[\ReturnTypeWillChange]
public function offsetGet($key) {
return $this->get($key);
}
#[\ReturnTypeWillChange]
public function offsetSet($key, $value) {
if(is_null($key)) {
throw new InvalidArgumentException('You must specify a key/array index.');
@ -2144,6 +2227,7 @@ class ORM implements ArrayAccess {
$this->set($key, $value);
}
#[\ReturnTypeWillChange]
public function offsetUnset($key) {
unset($this->_data[$key]);
unset($this->_dirty_fields[$key]);
@ -2210,9 +2294,9 @@ class ORM implements ArrayAccess {
return call_user_func_array(array('ORM', $method), $arguments);
}
}
}
/**
/**
* A class to handle str_replace operations that involve quoted strings
* @example IdiormString::str_replace_outside_quotes('?', '%s', 'columnA = "Hello?" AND columnB = ?');
* @example IdiormString::value('columnA = "Hello?" AND columnB = ?')->replace_outside_quotes('?', '%s');
@ -2220,7 +2304,7 @@ class ORM implements ArrayAccess {
* @author Simon Holywell <treffynnon@php.net>
* @link http://stackoverflow.com/a/13370709/461813 StackOverflow answer
*/
class IdiormString {
class IdiormString {
protected $subject;
protected $search;
protected $replace;
@ -2314,13 +2398,15 @@ class IdiormString {
return preg_replace('/'. preg_quote($this->search, '/') .'/',
$this->replace, $matches[2]);
}
}
}
/**
/**
* A result set class for working with collections of model instances
* @author Simon Holywell <treffynnon@php.net>
* @method null setResults(array $results)
* @method array getResults()
*/
class IdiormResultSet implements Countable, IteratorAggregate, ArrayAccess, Serializable {
class IdiormResultSet implements Countable, IteratorAggregate, ArrayAccess, Serializable {
/**
* The current result set as an array
* @var array
@ -2363,6 +2449,7 @@ class IdiormResultSet implements Countable, IteratorAggregate, ArrayAccess, Seri
* Get the number of records in the result set
* @return int
*/
#[\ReturnTypeWillChange]
public function count() {
return count($this->_results);
}
@ -2372,6 +2459,7 @@ class IdiormResultSet implements Countable, IteratorAggregate, ArrayAccess, Seri
* over the result set.
* @return \ArrayIterator
*/
#[\ReturnTypeWillChange]
public function getIterator() {
return new ArrayIterator($this->_results);
}
@ -2381,6 +2469,7 @@ class IdiormResultSet implements Countable, IteratorAggregate, ArrayAccess, Seri
* @param int|string $offset
* @return bool
*/
#[\ReturnTypeWillChange]
public function offsetExists($offset) {
return isset($this->_results[$offset]);
}
@ -2390,6 +2479,7 @@ class IdiormResultSet implements Countable, IteratorAggregate, ArrayAccess, Seri
* @param int|string $offset
* @return mixed
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset) {
return $this->_results[$offset];
}
@ -2399,6 +2489,7 @@ class IdiormResultSet implements Countable, IteratorAggregate, ArrayAccess, Seri
* @param int|string $offset
* @param mixed $value
*/
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value) {
$this->_results[$offset] = $value;
}
@ -2407,10 +2498,19 @@ class IdiormResultSet implements Countable, IteratorAggregate, ArrayAccess, Seri
* ArrayAccess
* @param int|string $offset
*/
#[\ReturnTypeWillChange]
public function offsetUnset($offset) {
unset($this->_results[$offset]);
}
public function __serialize() {
return $this->serialize();
}
public function __unserialize($data) {
$this->unserialize($data);
}
/**
* Serializable
* @return string
@ -2447,11 +2547,11 @@ class IdiormResultSet implements Countable, IteratorAggregate, ArrayAccess, Seri
}
return $this;
}
}
}
/**
/**
* A placeholder for exceptions eminating from the IdiormString class
*/
class IdiormStringException extends Exception {}
class IdiormStringException extends Exception {}
class IdiormMethodMissingException extends Exception {}
class IdiormMethodMissingException extends Exception {}

View File

@ -10,5 +10,8 @@
"ALTER TABLE `tbl_plans` CHANGE `type` `type` ENUM('Hotspot','PPPOE','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;",
"ALTER TABLE `tbl_transactions` CHANGE `type` `type` ENUM('Hotspot','PPPOE','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;",
"ALTER TABLE `tbl_customers` ADD `auto_renewal` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Auto renewall using balance' AFTER `balance`;"
],
"2023.8.23" : [
"ALTER TABLE `tbl_customers` CHANGE `pppoe_password` `pppoe_password` VARCHAR(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '0' COMMENT 'For PPPOE Login';"
]
}

View File

@ -1,5 +1,7 @@
{
"expired": "Hello [[name]], your internet package [[package]] has been expired.",
"balance_send": "You sent [[balance]] to [[name]].",
"balance_received": "You have received [[balance]] from [[name]].",
"reminder_7_day": "Hello *[[name]]*, \r\nyour internet package *[[package]]* will be expired in 7 days.",
"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.",

View File

@ -113,6 +113,32 @@
</p>
</div>
</div>
<div class="panel-body">
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Send Balance')}</label>
<div class="col-md-6">
<textarea class="form-control" id="balance_send" name="balance_send"
rows="3">{if $_json['balance_send']}{Lang::htmlspecialchars($_json['balance_send'])}{else}{Lang::htmlspecialchars($_default['balance_send'])}{/if}</textarea>
</div>
<p class="col-md-4 help-block">
<b>[[name]]</b> Receiver name.<br>
<b>[[balance]]</b> how much balance have been send.
</p>
</div>
</div>
<div class="panel-body">
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Received Balance')}</label>
<div class="col-md-6">
<textarea class="form-control" id="balance_received" name="balance_received"
rows="3">{if $_json['balance_received']}{Lang::htmlspecialchars($_json['balance_received'])}{else}{Lang::htmlspecialchars($_default['balance_received'])}{/if}</textarea>
</div>
<p class="col-md-4 help-block">
<b>[[name]]</b> Sender name.<br>
<b>[[balance]]</b> how much balance have been received.
</p>
</div>
</div>
</div>
<div class="panel-body">

View File

@ -107,6 +107,13 @@
</div>
<p class="help-block col-md-4">{Lang::T('Allow balance transfer between customers')}</p>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Minimum Balance Transfer')}</label>
<div class="col-md-6">
<input type="number" class="form-control" id="minimum_transfer" name="minimum_transfer"
value="{$_c['minimum_transfer']}">
</div>
</div>
</div>
<div class="panel-heading">
<div class="btn-group pull-right">

View File

@ -1,17 +1,22 @@
{include file="sections/header.tpl"}
<div class="row">
<div class="row">
<div class="col-sm-12 col-md-12">
<div class="panel panel-primary panel-hovered panel-stacked mb30">
<div class="panel-heading">{$_L['Add_Contact']}</div>
<div class="panel-body">
<form class="form-horizontal" method="post" role="form" action="{$_url}customers/add-post" >
<form class="form-horizontal" method="post" role="form" action="{$_url}customers/add-post">
<div class="form-group">
<label class="col-md-2 control-label">{$_L['Username']}</label>
<div class="col-md-6">
<div class="input-group">
<span class="input-group-addon">+</span>
{if $_c['country_code_phone']!= ''}
<span class="input-group-addon" id="basic-addon1">+</span>
{else}
<span class="input-group-addon" id="basic-addon1"><i
class="glyphicon glyphicon-phone-alt"></i></span>
{/if}
<input type="text" class="form-control" name="username" required
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']}{/if} {$_L['Phone_Number']}">
</div>
@ -33,7 +38,12 @@
<label class="col-md-2 control-label">{$_L['Phone_Number']}</label>
<div class="col-md-6">
<div class="input-group">
<span class="input-group-addon">+</span>
{if $_c['country_code_phone']!= ''}
<span class="input-group-addon" id="basic-addon1">+</span>
{else}
<span class="input-group-addon" id="basic-addon1"><i
class="glyphicon glyphicon-phone-alt"></i></span>
{/if}
<input type="text" class="form-control" name="phonenumber"
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']}{/if} {$_L['Phone_Number']}">
</div>
@ -42,14 +52,18 @@
<div class="form-group">
<label class="col-md-2 control-label">{$_L['Password']}</label>
<div class="col-md-6">
<input type="text" class="form-control" autocomplete="off" required id="password" name="password">
<input type="password" class="form-control" autocomplete="off" required id="password"
name="password" onmouseleave="this.type = 'password'" onmouseenter="this.type = 'text'">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('PPPOE Password')}</label>
<div class="col-md-6">
<input type="password" class="form-control" id="pppoe_password" name="pppoe_password" value="{$d['pppoe_password']}">
<span class="help-block">{Lang::T('User Cannot change this, only admin. if it Empty it will use user password')}</span>
<input type="password" class="form-control" id="pppoe_password" name="pppoe_password"
value="{$d['pppoe_password']}" onmouseleave="this.type = 'password'"
onmouseenter="this.type = 'text'">
<span
class="help-block">{Lang::T('User Cannot change this, only admin. if it Empty it will use user password')}</span>
</div>
</div>
<div class="form-group">
@ -61,7 +75,8 @@
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<button class="btn btn-primary waves-effect waves-light" type="submit">{$_L['Save']}</button>
<button class="btn btn-primary waves-effect waves-light"
type="submit">{$_L['Save']}</button>
Or <a href="{$_url}customers/list">{$_L['Cancel']}</a>
</div>
</div>
@ -69,8 +84,8 @@
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{include file="sections/footer.tpl"}

View File

@ -1,19 +1,25 @@
{include file="sections/header.tpl"}
<div class="row">
<div class="row">
<div class="col-sm-12 col-md-12">
<div class="panel panel-primary panel-hovered panel-stacked mb30">
<div class="panel-heading">{$_L['Edit_Contact']}</div>
<div class="panel-body">
<form class="form-horizontal" method="post" role="form" action="{$_url}customers/edit-post" >
<form class="form-horizontal" method="post" role="form" action="{$_url}customers/edit-post">
<input type="hidden" name="id" value="{$d['id']}">
<div class="form-group">
<label class="col-md-2 control-label">{$_L['Username']}</label>
<div class="col-md-6">
<div class="input-group">
<span class="input-group-addon">+</span>
<input type="text" class="form-control" name="username" value="{$d['username']}" required
{if $_c['country_code_phone']!= ''}
<span class="input-group-addon" id="basic-addon1">+</span>
{else}
<span class="input-group-addon" id="basic-addon1"><i
class="glyphicon glyphicon-phone-alt"></i></span>
{/if}
<input type="text" class="form-control" name="username" value="{$d['username']}"
required
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']}{/if} {$_L['Phone_Number']}">
</div>
</div>
@ -21,7 +27,8 @@
<div class="form-group">
<label class="col-md-2 control-label">{$_L['Full_Name']}</label>
<div class="col-md-6">
<input type="text" class="form-control" id="fullname" name="fullname" value="{$d['fullname']}">
<input type="text" class="form-control" id="fullname" name="fullname"
value="{$d['fullname']}">
</div>
</div>
<div class="form-group">
@ -34,7 +41,12 @@
<label class="col-md-2 control-label">{$_L['Phone_Number']}</label>
<div class="col-md-6">
<div class="input-group">
<span class="input-group-addon">+</span>
{if $_c['country_code_phone']!= ''}
<span class="input-group-addon" id="basic-addon1">+</span>
{else}
<span class="input-group-addon" id="basic-addon1"><i
class="glyphicon glyphicon-phone-alt"></i></span>
{/if}
<input type="text" class="form-control" name="phonenumber" value="{$d['phonenumber']}"
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']}{/if} {$_L['Phone_Number']}">
</div>
@ -43,15 +55,20 @@
<div class="form-group">
<label class="col-md-2 control-label">{$_L['Password']}</label>
<div class="col-md-6">
<input type="password" autocomplete="off" class="form-control" id="password" name="password" onmouseleave="this.type = 'password'" onmouseenter="this.type = 'text'" value="{$d['password']}">
<input type="password" autocomplete="off" class="form-control" id="password" name="password"
onmouseleave="this.type = 'password'" onmouseenter="this.type = 'text'"
value="{$d['password']}">
<span class="help-block">{$_L['password_change_help']}</span>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('PPPOE Password')}</label>
<div class="col-md-6">
<input type="password" autocomplete="off" class="form-control" id="pppoe_password" name="pppoe_password" value="{$d['pppoe_password']}" onmouseleave="this.type = 'password'" onmouseenter="this.type = 'text'">
<span class="help-block">{Lang::T('User Cannot change this, only admin. if it Empty it will use user password')}</span>
<input type="password" autocomplete="off" class="form-control" id="pppoe_password"
name="pppoe_password" value="{$d['pppoe_password']}"
onmouseleave="this.type = 'password'" onmouseenter="this.type = 'text'">
<span
class="help-block">{Lang::T('User Cannot change this, only admin. if it Empty it will use user password')}</span>
</div>
</div>
<div class="form-group">
@ -63,7 +80,8 @@
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<button class="btn btn-primary waves-effect waves-light" type="submit">{$_L['Save']}</button>
<button class="btn btn-primary waves-effect waves-light"
type="submit">{$_L['Save']}</button>
Or <a href="{$_url}customers/list">{$_L['Cancel']}</a>
</div>
</div>
@ -71,7 +89,7 @@
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{include file="sections/footer.tpl"}

171
ui/ui/customers-view.tpl Normal file
View File

@ -0,0 +1,171 @@
{include file="sections/header.tpl"}
<div class="row">
<div class="col-sm-4 col-md-4">
<div class="box box-primary">
<div class="box-body box-profile">
<img class="profile-user-img img-responsive img-circle"
src="https://robohash.org/{$d['id']}?set=set3&size=100x100&bgset=bg1"
onerror="this.src='system/uploads/user.default.jpg'" alt="avatar">
<h3 class="profile-username text-center">{$d['fullname']}</h3>
<ul class="list-group list-group-unbordered">
<li class="list-group-item">
<b>{$_L['Username']}</b> <span class="pull-right">{$d['username']}</span>
</li>
<li class="list-group-item">
<b>{$_L['Phone_Number']}</b> <span class="pull-right">{$d['phonenumber']}</span>
</li>
<li class="list-group-item">
<b>{$_L['Email']}</b> <span class="pull-right">{$d['email']}</span>
</li>
</ul>
<p class="text-muted">{Lang::nl2br($d['address'])}</p>
<ul class="list-group list-group-unbordered">
<li class="list-group-item">
<b>{$_L['Password']}</b> <span class="pull-right" style="background-color: black; color:black;"
onclick="this.select()">{$d['password']}</span>
</li>
{if $d['pppoe_password'] != ''}
<li class="list-group-item">
<b>PPPOE {$_L['Password']}</b> <span class="pull-right"
style="background-color: black; color:black;"
onclick="this.select()">{$d['pppoe_password']}</span>
</li>
{/if}
<li class="list-group-item">
<b>{Lang::T('Balance')}</b> <span class="pull-right">{Lang::moneyFormat($d['balance'])}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Auto Renewal')}</b> <span
class="pull-right">{if $d['auto_renewal']}yes{else}no{/if}</span>
</li>
<li class="list-group-item">
<b>{$_L['Created_On']}</b> <span
class="pull-right">{Lang::dateTimeFormat($d['created_at'])}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Last Login')}</b> <span
class="pull-right">{Lang::dateTimeFormat($d['last_login'])}</span>
</li>
</ul>
<div class="row">
<div class="col-xs-4">
<a href="{$_url}customers/delete/{$d['id']}" id="{$d['id']}"
class="btn btn-danger btn-block btn-sm" onclick="return confirm('{$_L['Delete']}?')"><span
class="fa fa-trash"></span></a>
</div>
<div class="col-xs-8">
<a href="{$_url}customers/edit/{$d['id']}"
class="btn btn-warning btn-sm btn-block">{$_L['Edit']}</a>
</div>
</div>
</div>
</div>
{if $package}
<div class="box box-{if $package['status']=='on'}success{else}danger{/if}">
<div class="box-body box-profile">
<h4 class="text-center">{$package['type']} - {$package['namebp']}</h4>
<ul class="list-group list-group-unbordered">
<li class="list-group-item">
{Lang::T('Active')} <span
class="pull-right">{if $package['status']=='on'}yes{else}no{/if}</span>
</li>
<li class="list-group-item">
{$_L['Created_On']} <span class="pull-right">{Lang::dateFormat($package['recharged_on'])}</span>
</li>
<li class="list-group-item">
{$_L['Expires_On']} <span
class="pull-right">{Lang::dateTimeFormat($package['expiration']+' '+$package['time'])}</span>
</li>
<li class="list-group-item">
{$package['routers']} <span class="pull-right">{$package['method']}</span>
</li>
</ul>
</div>
</div>
{/if}
<a href="{$_url}customers/list" class="btn btn-primary btn-sm btn-block mt-1">{Lang::T('Back')}</a><br>
</div>
<div class="col-sm-8 col-md-8">
<ul class="nav nav-tabs">
<li role="presentation" {if $v=='order'}class="active" {/if}><a
href="{$_url}customers/view/{$d['id']}/order">30 {Lang::T('Order History')}</a></li>
<li role="presentation" {if $v=='activation'}class="active" {/if}><a
href="{$_url}customers/view/{$d['id']}/activation">30 {Lang::T('Activation History')}</a></li>
</ul>
<div class="table-responsive" style="background-color: white;">
<table id="datatable" class="table table-bordered table-striped">
{if Lang::arrayCount($activation)}
<thead>
<tr>
<th>{$_L['Username']}</th>
<th>{$_L['Plan_Name']}</th>
<th>{$_L['Plan_Price']}</th>
<th>{$_L['Type']}</th>
<th>{$_L['Created_On']}</th>
<th>{$_L['Expires_On']}</th>
<th>{$_L['Method']}</th>
</tr>
</thead>
<tbody>
{foreach $activation as $ds}
<tr>
<td>{$ds['username']}</td>
<td>{$ds['plan_name']}</td>
<td>{Lang::moneyFormat($ds['price'])}</td>
<td>{$ds['type']}</td>
<td class="text-success">{date($_c['date_format'], strtotime($ds['recharged_on']))}</td>
<td class="text-danger">{date($_c['date_format'], strtotime($ds['expiration']))}
{$ds['time']}</td>
<td>{$ds['method']}</td>
</tr>
{/foreach}
</tbody>
{/if}
{if Lang::arrayCount($order)}
<thead>
<tr>
<th>{$_L['Plan_Name']}</th>
<th>{Lang::T('Gateway')}</th>
<th>{Lang::T('Routers')}</th>
<th>{$_L['Type']}</th>
<th>{$_L['Plan_Price']}</th>
<th>{$_L['Created_On']}</th>
<th>{$_L['Expires_On']}</th>
<th>{Lang::T('Date Done')}</th>
<th>{$_L['Method']}</th>
</tr>
</thead>
<tbody>
{foreach $order as $ds}
<tr>
<td>{$ds['plan_name']}</td>
<td>{$ds['gateway']}</td>
<td>{$ds['routers']}</td>
<td>{$ds['payment_channel']}</td>
<td>{Lang::moneyFormat($ds['price'])}</td>
<td class="text-primary">{date("{$_c['date_format']} H:i",
strtotime($ds['created_date']))}</td>
<td class="text-danger">{date("{$_c['date_format']} H:i",
strtotime($ds['expired_date']))}</td>
<td class="text-success">{if $ds['status']!=1}{date("{$_c['date_format']} H:i",
strtotime($ds['paid_date']))}{/if}</td>
<td>{if $ds['status']==1}{$_L['UNPAID']}
{elseif $ds['status']==2}{$_L['PAID']}
{elseif $ds['status']==3}{$_L['FAILED']}
{elseif $ds['status']==4}{$_L['CANCELED']}
{elseif $ds['status']==5}{$_L['UNKNOWN']}
{/if}</td>
</tr>
{/foreach}
</tbody>
{/if}
</table>
</div>
{$paginator['contents']}
</div>
</div>
{include file="sections/footer.tpl"}

View File

@ -9,18 +9,11 @@
<div class="col-md-8">
<form id="site-search" method="post" action="{$_url}customers/list/">
<div class="input-group">
<div class="input-group-addon no-border">
<select name="what">
<option value="username" {if $what=='username'}selected{/if}>Username</option>
<option value="fullname" {if $what=='fullname'}selected{/if}>Name</option>
<option value="phonenumber" {if $what=='phonenumber'}selected{/if}>Phone</option>
<option value="email" {if $what=='email'}selected{/if}>Email</option>
</select>
</div>
<input type="text" name="search" value="{$search}" class="form-control"
placeholder="{$_L['Search_by_Username']}...">
placeholder="{Lang::T('Search')}...">
<div class="input-group-btn">
<button class="btn btn-success" type="submit"><span class="fa fa-search"></span></button>
<button class="btn btn-success" type="submit"><span
class="fa fa-search"></span></button>
</div>
</div>
</form>
@ -34,6 +27,7 @@
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>{$_L['Manage']}</th>
<th>{$_L['Username']}</th>
<th>{$_L['Full_Name']}</th>
<th>{Lang::T('Balance')}</th>
@ -41,27 +35,23 @@
<th>{$_L['Email']}</th>
<th>{$_L['Created_On']}</th>
<th>{$_L['Recharge']}</th>
<th>{$_L['Manage']}</th>
</tr>
</thead>
<tbody>
{foreach $d as $ds}
<tr>
<td align="center">
<a href="{$_url}customers/view/{$ds['id']}" id="{$ds['id']}"
class="btn btn-success btn-sm">{Lang::T('View')}</a>
</td>
<td>{$ds['username']}</td>
<td>{$ds['fullname']}</td>
<td>{Lang::moneyFormat($ds['balance'])}</td>
<td>{$ds['phonenumber']}</td>
<td>{$ds['email']}</td>
<td>{$ds['created_at']}</td>
<td>{Lang::dateTimeFormat($ds['created_at'])}</td>
<td align="center"><a href="{$_url}prepaid/recharge-user/{$ds['id']}" id="{$ds['id']}"
class="btn btn-primary btn-sm">{$_L['Recharge']}</a></td>
<td align="center">
<a href="{$_url}customers/edit/{$ds['id']}"
class="btn btn-warning btn-sm">{$_L['Edit']}</a>
<a href="{$_url}customers/delete/{$ds['id']}" id="{$ds['id']}"
class="btn btn-danger btn-sm"
onclick="return confirm('{$_L['Delete']}?')">{$_L['Delete']}</a>
</td>
</tr>
{/foreach}
</tbody>

View File

@ -107,7 +107,7 @@
{foreach $expire as $expired}
<tr>
<td>{$no++}</td>
<td>{$expired['username']}</td>
<td><a href="{$_url}customers/viewu/{$expired['username']}">{$expired['username']}</a></td>
<td>{date($_c['date_format'], strtotime($expired['recharged_on']))}
</td>
<td>{date($_c['date_format'], strtotime($expired['expiration']))} {$expired['time']}

View File

@ -11,10 +11,6 @@
<div class="col-md-6">
<select id="personSelect" class="form-control select2" name="id_customer" style="width: 100%"
data-placeholder="{$_L['Select_Customer']}...">
<option></option>
{foreach $c as $cs}
<option value="{$cs['id']}">{$cs['username']} - {$cs['fullname']}</option>
{/foreach}
</select>
</div>
</div>

View File

@ -69,7 +69,7 @@
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{$_L['BW_Name']}</label>
<label class="col-md-2 control-label"><a href="{$_url}bandwidth/add">{$_L['BW_Name']}</a></label>
<div class="col-md-6">
<select id="id_bw" name="id_bw" class="form-control select2">
<option value="">{$_L['Select_BW']}...</option>
@ -110,7 +110,7 @@
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{$_L['Router_Name']}</label>
<label class="col-md-2 control-label"><a href="{$_url}routers/add">{$_L['Router_Name']}</a></label>
<div class="col-md-6">
<select id="routers" name="routers" class="form-control select2">
{foreach $r as $rs}

View File

@ -70,7 +70,7 @@
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{$_L['BW_Name']}</label>
<label class="col-md-2 control-label"><a href="{$_url}bandwidth/add">{$_L['BW_Name']}</a></label>
<div class="col-md-6">
<select id="id_bw" name="id_bw" class="form-control select2">
{foreach $b as $bs}
@ -109,7 +109,7 @@
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{$_L['Router_Name']}</label>
<label class="col-md-2 control-label"><a href="{$_url}routers/add">{$_L['Router_Name']}</a></label>
<div class="col-md-6">
<input type="text" class="form-control" id="routers" name="routers" value="{$d['routers']}" readonly>
</div>

View File

@ -20,7 +20,7 @@
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{$_L['Routers']}</label>
<label class="col-md-2 control-label"><a href="{$_url}routers/add">{$_L['Routers']}</a></label>
<div class="col-md-6">
<select id="routers" name="routers" class="form-control select2">
{foreach $r as $rs}

View File

@ -24,7 +24,7 @@
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{$_L['BW_Name']}</label>
<label class="col-md-2 control-label"><a href="{$_url}bandwidth/add">{$_L['BW_Name']}</a></label>
<div class="col-md-6">
<select id="id_bw" name="id_bw" class="form-control select2">
<option value="">{$_L['Select_BW']}...</option>
@ -58,7 +58,7 @@
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{$_L['Router_Name']}</label>
<label class="col-md-2 control-label"><a href="{$_url}routers/add">{$_L['Router_Name']}</a></label>
<div class="col-md-6">
<select id="routers" name="routers" class="form-control select2">
<option value=''>{$_L['Select_Routers']}</option>
@ -70,7 +70,7 @@
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{$_L['Pool']}</label>
<label class="col-md-2 control-label"><a href="{$_url}pool/add">{$_L['Pool']}</a></label>
<div class="col-md-6">
<select id="pool_name" name="pool_name" class="form-control select2">
<option value=''>{$_L['Select_Pool']}</option>

View File

@ -25,7 +25,7 @@
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{$_L['BW_Name']}</label>
<label class="col-md-2 control-label"><a href="{$_url}bandwidth/add">{$_L['BW_Name']}</a></label>
<div class="col-md-6">
<select id="id_bw" name="id_bw" class="form-control select2">
{foreach $b as $bs}
@ -58,7 +58,7 @@
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{$_L['Pool']}</label>
<label class="col-md-2 control-label"><a href="{$_url}pool/add">{$_L['Pool']}</a></label>
<div class="col-md-6">
<select id="pool_name" name="pool_name" class="form-control select2">
{foreach $p as $ps}

View File

@ -10,10 +10,6 @@
<label class="col-md-2 control-label">{$_L['Select_Account']}</label>
<div class="col-md-6">
<select id="personSelect" class="form-control select2" name="id_customer" style="width: 100%" data-placeholder="{$_L['Select_Customer']}...">
<option></option>
{foreach $c as $cs}
<option value="{$cs['id']}">{$cs['username']}</option>
{/foreach}
</select>
</div>
</div>

View File

@ -9,12 +9,8 @@
<div class="form-group">
<label class="col-md-2 control-label">{$_L['Select_Account']}</label>
<div class="col-md-6">
<select id="personSelect" class="form-control select2" name="id_customer" style="width: 100%"
data-placeholder="{$_L['Select_Customer']}...">
<option></option>
{foreach $c as $cs}
<option value="{$cs['id']}">{$cs['username']}</option>
{/foreach}
<select id="personSelect" class="form-control select2" name="id_customer"
style="width: 100%" data-placeholder="{$_L['Select_Customer']}...">
</select>
</div>
</div>
@ -39,4 +35,5 @@
</div>
</div>
{include file="sections/footer.tpl"}

View File

@ -32,6 +32,7 @@
<option value="" selected="">{$_L['All_Transactions']}</option>
<option value="Hotspot">Hotspot</option>
<option value="PPPOE">PPPOE</option>
<option value="Balance">Balance</option>
</select>
</div>
</div>

View File

@ -41,7 +41,8 @@
<div class="form-group">
<label class="col-md-2 control-label">{$_L['Router_Secret']}</label>
<div class="col-md-6">
<input type="text" class="form-control" id="password" name="password" value="{$d['password']}">
<input type="password" class="form-control" id="password" name="password" value="{$d['password']}" onmouseleave="this.type = 'password'"
onmouseenter="this.type = 'text'">
</div>
</div>
<div class="form-group">

File diff suppressed because one or more lines are too long

View File

@ -11,10 +11,8 @@
<script src="ui/ui/scripts/jquery.min.js"></script>
<script src="ui/ui/scripts/bootstrap.min.js"></script>
<script src="ui/ui/scripts/adminlte.min.js"></script>
<script src="ui/ui/scripts/plugins/select2.min.js"></script>
<script src="ui/ui/scripts/custom.js"></script>
<script src="ui/ui/scripts/select2.min.js"></script>
{if isset($xfooter)}
{$xfooter}

View File

@ -1,281 +0,0 @@
.select2-container {
box-sizing: border-box;
display: block;
margin: 0;
position: relative;
}
.select2-container .select2-selection--single {
box-sizing: border-box;
cursor: pointer;
display: block;
height: 36px;
padding: 0 5px;
user-select: none;
-webkit-user-select: none; }
.select2-container .select2-selection--single .select2-selection__rendered {
display: block;
padding-left: 8px;
padding-right: 20px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap; }
.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered {
padding-right: 8px;
padding-left: 20px; }
.select2-container .select2-selection--multiple {
cursor: pointer;
display: block;
user-select: none;
-webkit-user-select: none; }
.select2-container .select2-selection--multiple .select2-selection__rendered {
display: inline-block;
overflow: hidden;
padding-left: 8px;
text-overflow: ellipsis;
white-space: nowrap; }
.select2-container .select2-search--inline {
float: left; }
.select2-container .select2-search--inline .select2-search__field {
box-sizing: border-box;
border: none;
font-size: 100%;
margin-top: 5px; }
.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button {
-webkit-appearance: none; }
.select2-dropdown {
background-color: white;
border-radius: 0 0 2px 2px;
border: 1px solid #dedede;
box-sizing: border-box;
display: block;
position: absolute;
left: -100000px;
width: 100%;
z-index: 1051; }
.select2-results {
display: block; }
.select2-results__options {
list-style: none;
margin: 0;
padding: 0; }
.select2-results__option {
padding: 6px 10px;
user-select: none;
-webkit-user-select: none; }
.select2-results__option[aria-selected] {
cursor: pointer; }
.select2-container--open .select2-dropdown {
left: 0;
border-top: 0;
box-shadow: 0 1px 0 rgba(0,0,0,.05);
}
.select2-container--open .select2-dropdown--above {
border-bottom: none;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0; }
.select2-container--open .select2-dropdown--below {
border-top: none;
border-top-left-radius: 0;
border-top-right-radius: 0; }
.select2-search--dropdown {
display: block;
padding: 4px; }
.select2-search--dropdown .select2-search__field {
padding: 4px;
width: 100%;
box-sizing: border-box; }
.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button {
-webkit-appearance: none; }
.select2-search--dropdown.select2-search--hide {
display: none; }
.select2-close-mask {
border: 0;
margin: 0;
padding: 0;
display: block;
position: fixed;
left: 0;
top: 0;
min-height: 100%;
min-width: 100%;
height: auto;
width: auto;
opacity: 0;
z-index: 99;
background-color: #fff;
filter: alpha(opacity=0); }
.select2-hidden-accessible {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px; }
/*** Default Style ***/
.select2-container--default .select2-selection--single {
background-color: #fff;
border: 1px solid #dedede;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
border-radius:0px; }
.select2-container--default .select2-selection--single .select2-selection__rendered {
color: #333;
line-height: 36px;}
.select2-container--default .select2-selection--single .select2-selection__clear {
cursor: pointer;
float: right;
font-weight: bold; }
.select2-container--default .select2-selection--single .select2-selection__placeholder {
color: #999; }
.select2-container--default .select2-selection--single .select2-selection__arrow {
height: 26px;
position: absolute;
top: 5px;
right: 4px;
width: 20px; }
.select2-container--default .select2-selection--single .select2-selection__arrow b {
border-color: #555 transparent transparent transparent;
border-style: solid;
border-width: 5px 4px 0 4px;
height: 0;
left: 50%;
margin-left: -4px;
margin-top: -2px;
position: absolute;
top: 50%;
width: 0; }
.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear {
float: left; }
.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow {
left: 1px;
right: auto; }
.select2-container--default.select2-container--disabled .select2-selection--single {
background-color: #eee;
cursor: default; }
.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear {
display: none; }
.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b {
border-color: transparent transparent #888 transparent;
border-width: 0 4px 5px 4px; }
.select2-container--default .select2-selection--multiple {
background-color: #fff;
height: 36px;
border: none;
border-bottom: 1px solid #dedede;
cursor: text; }
.select2-container--default .select2-selection--multiple .select2-selection__rendered {
list-style: none;
margin: 0;
min-height: 36px;
padding: 0 5px;
margin-bottom: 0;
width: 100%; }
.select2-container--default .select2-selection--multiple .select2-selection__placeholder {
color: #999;
margin-top: 5px;
float: left; }
.select2-container--default .select2-selection--multiple .select2-selection__clear {
cursor: pointer;
float: right;
font-weight: bold;
margin-top: 5px;
margin-right: 10px; }
.select2-container--default .select2-selection--multiple .select2-selection__choice {
background-color: #fff;
border: 1px solid #dedede;
border-radius: 1px;
cursor: default;
float: left;
font-size: 12px;
margin-right: 5px;
margin-top: 4px;
position: relative;
top: 1px;
box-shadow: 0 1px 1px rgba(0,0,0,.1);
padding: 2px 8px; }
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
color: #999;
cursor: pointer;
display: inline-block;
font-weight: bold;
margin-right: 2px; }
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {
color: #333; }
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder {
float: right; }
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
margin-left: 5px;
margin-right: auto; }
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
margin-left: 2px;
margin-right: auto; }
.select2-container--default.select2-container--focus .select2-selection--multiple {
border: none;
border-bottom: solid #dedede 1px;
outline: 0; }
.select2-container--default.select2-container--disabled .select2-selection--multiple {
background-color: #eee;
cursor: default; }
.select2-container--default.select2-container--disabled .select2-selection__choice__remove {
display: none; }
.select2-container--default.select2-container--open.select2-container--above .select2-selection--single, .select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple {
border-top-left-radius: 0;
border-top-right-radius: 0; }
.select2-container--default.select2-container--open.select2-container--below .select2-selection--single, .select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0; }
.select2-container--default .select2-search--dropdown .select2-search__field {
border: 1px solid #eee; }
.select2-container--default .select2-search--inline .select2-search__field {
background: transparent;
border: none;
outline: 0; }
.select2-container--default .select2-results > .select2-results__options {
max-height: 200px;
overflow-y: auto; }
.select2-container--default .select2-results__option[role=group] {
padding: 0; }
.select2-container--default .select2-results__option[aria-disabled=true] {
color: #999; }
.select2-container--default .select2-results__option[aria-selected=true] {
background-color: transparent; }
.select2-container--default .select2-results__option .select2-results__option {
padding-left: 1em; }
.select2-container--default .select2-results__option .select2-results__option .select2-results__group {
padding-left: 0; }
.select2-container--default .select2-results__option .select2-results__option .select2-results__option {
margin-left: -1em;
padding-left: 2em; }
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
margin-left: -2em;
padding-left: 3em; }
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
margin-left: -3em;
padding-left: 4em; }
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
margin-left: -4em;
padding-left: 5em; }
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
margin-left: -5em;
padding-left: 6em; }
.select2-container--default .select2-results__option--highlighted[aria-selected] {
background-color:#3f51b5;
color: white; }
.select2-container--default .select2-results__group {
cursor: default;
display: block;
padding: 6px; }

View File

@ -41,7 +41,7 @@
<div class="box-header">
<h3 class="box-title">{$_L['Announcement']}</h3>
</div>
<div class="box-body" style="max-height:296px;overflow:auto;">
<div class="box-body">
{include file="$_path/../pages/Announcement.html"}
</div>
</div>
@ -138,6 +138,39 @@
}, 2000);
</script>
{/if}
{if $_c['enable_balance'] == 'yes'}
<div class="box box-primary box-solid mb30">
<div class="box-header">
<h4 class="box-title">{Lang::T("Transfer Balance")}</h4>
</div>
<div class="box-body p-0">
<form method="post" onsubmit="return askConfirm()" role="form" action="{$_url}home">
<div class="form-group">
<div class="col-sm-5">
<input type="text" id="username" name="username" class="form-control" required
placeholder="{$_L['Username']}">
</div>
<div class="col-sm-5">
<input type="number" id="balance" name="balance" autocomplete="off" class="form-control" required
placeholder="{$_L['Balance']}">
</div>
<div class="form-group col-sm-2" align="center">
<button class="btn btn-success btn-block" id="sendBtn" type="submit" name="send" value="balance"><i class="glyphicon glyphicon-send"></i></button>
</div>
</div>
</form>
<script>
function askConfirm(){
if(confirm('{Lang::T('Send your balance?')}')){
document.getElementById('sendBtn').setAttribute('disabled', '');
return true;
}
return false;
}
</script>
</div>
</div>
{/if}
<br>
{if $_c['disable_voucher'] != 'yes'}
<div class="box box-primary box-solid mb30">

View File

@ -33,6 +33,10 @@
{/foreach}
</div>
</div>
<div class="box box-solid box-success">
<div class="box-header text-center text-bold">{Lang::T('Balance')} {Lang::moneyFormat($_user['balance'])}</div>
</div>
{/if}
{foreach $routers as $router}
<div class="box box-solid box-info">
@ -69,9 +73,16 @@
</table>
</div>
<div class="box-body">
<div class="btn-group btn-group-justified" role="group" aria-label="...">
<a href="{$_url}order/buy/{$router['id']}/{$plan['id']}"
onclick="return confirm('{Lang::T('Buy this? your active package will be overwrite')}')"
class="btn btn-sm btn-block btn-primary">Buy</a>
class="btn btn-sm btn-block btn-warning text-black">Buy</a>
{if $_c['enable_balance'] == 'yes' && $_user['balance']>=$plan['price']}
<a href="{$_url}order/pay/{$router['id']}/{$plan['id']}"
onclick="return confirm('{Lang::T('Pay this with Balance? your active package will be overwrite')}')"
class="btn btn-sm btn-block btn-success">{Lang::T('Pay With Balance')}</a>
{/if}
</div>
</div>
</div>
</div>
@ -106,9 +117,16 @@
</table>
</div>
<div class="box-body">
<div class="btn-group btn-group-justified" role="group" aria-label="...">
<a href="{$_url}order/buy/{$router['id']}/{$plan['id']}"
onclick="return confirm('{Lang::T('Buy this? your active package will be overwrite')}')"
class="btn btn-sm btn-block btn-primary">Buy</a>
class="btn btn-sm btn-block btn-warning text-black">Buy</a>
{if $_c['enable_balance'] == 'yes' && $_user['balance']>=$plan['price']}
<a href="{$_url}order/pay/{$router['id']}/{$plan['id']}"
onclick="return confirm('{Lang::T('Pay this with Balance? your active package will be overwrite')}')"
class="btn btn-sm btn-block btn-success">{Lang::T('Pay With Balance')}</a>
{/if}
</div>
</div>
</div>
</div>

View File

@ -6,7 +6,7 @@
<div
class="panel mb20 {if $trx['status']==1}panel-warning{elseif $trx['status']==2}panel-success{elseif $trx['status']==3}panel-danger{elseif $trx['status']==4}panel-danger{else}panel-primary{/if} panel-hovered">
<div class="panel-footer">Transaction #{$trx['id']}</div>
{if $plan['type']!='Balance'}
{if $trx['routers']!='balance'}
<div class="panel-body">
<div class="panel panel-primary panel-hovered">
<div class="panel-heading">{$router['name']}</div>
@ -17,6 +17,33 @@
</div>
{/if}
<div class="table-responsive">
{if $trx['pg_url_payment']=='balance'}
<table class="table table-bordered table-striped table-bordered">
<tbody>
<tr>
<td>{Lang::T('Type')}</td>
<td>{$trx['plan_name']}</td>
</tr>
<tr>
<td>{Lang::T('Paid Date')}</td>
<td>{date($_c['date_format'], strtotime($trx['paid_date']))}
{date('H:i', strtotime($trx['paid_date']))} </td>
</tr>
<tr>
{if $trx['plan_name'] == 'Receive Balance'}
<td>{Lang::T('From')}</td>
{else}
<td>{Lang::T('To')}</td>
{/if}
<td>{$trx['gateway']}</td>
</tr>
<tr>
<td>{$_L['Balance']}</td>
<td>{Lang::moneyFormat($trx['price'])}</td>
</tr>
</tbody>
</table>
{else}
<table class="table table-bordered table-striped table-bordered">
<tbody>
<tr>
@ -81,6 +108,7 @@
{/if}
</tbody>
</table>
{/if}
</div>
{if $trx['status']==1}
<div class="panel-footer ">

View File

@ -12,6 +12,7 @@ if(empty($update_url)){
$update_url = 'https://github.com/hotspotbilling/phpnuxbill/archive/refs/heads/master.zip';
}
if (!isset($_SESSION['aid']) || empty($_SESSION['aid'])) {
r2("./?_route=login&You_are_not_admin", 'e', 'You are not admin');
}
@ -35,7 +36,8 @@ if (!extension_loaded('zip')) {
$file = pathFixer('system/cache/phpnuxbill.zip');
$folder = pathFixer('system/cache/phpnuxbill-master/');
$folder = pathFixer('system/cache/phpnuxbill-'.basename($update_url, ".zip").'/');
if (empty($step)) {
$step++;
} else if ($step == 1) {
@ -252,8 +254,8 @@ function deleteFolder($path)
</div>
</div>
<?php } else if ($step == 5) { ?>
<div class="panel panel-primary">
<div class="panel-success">Update Finished</div>
<div class="panel panel-success">
<div class="panel-heading">Update Finished</div>
<div class="panel-body">
PHPNuxBill has been updated to Version <b><?= $version ?></b>
</div>

View File

@ -1,3 +1,3 @@
{
"version": "2023.8.16"
"version": "2023.8.24"
}