Compare commits

...

111 Commits

Author SHA1 Message Date
66432eda56 2024.2.7 2024-02-07 13:35:23 +07:00
92eee8245d timeElapsed 2024-02-07 13:32:33 +07:00
f62f07d102 add Hide Dashboard Content 2024-02-07 12:02:39 +07:00
671154d146 add sub sales 2024-02-07 10:11:30 +07:00
ac84e4b235 settimezone 2024-02-07 09:39:49 +07:00
db7c6014dc Fix invoice keyword 2024-02-06 17:41:45 +07:00
21b57ef471 Fix price for logging 2024-02-06 16:54:57 +07:00
79e5c72ca2 2024.2.6 2024-02-06 16:48:59 +07:00
5921fef67e cache Voucher stocks for 5 Minutes 2024-02-06 16:46:50 +07:00
1e0b246d74 Cache for 12 hours 2024-02-06 16:43:06 +07:00
009c890ab6 Fix router_name for log 2024-02-06 16:41:41 +07:00
f3d7687cdb cache dashboard graph 2024-02-06 16:41:26 +07:00
80cecabfb0 Fix Calculation 2024-02-05 14:25:23 +07:00
00ac91903f Merge pull request #103 from Focuslinkstech/master
Dashboard Updates
2024-02-05 14:19:37 +07:00
500f3de6a9 Update dashboard.tpl
fixed inactive users in graph
2024-02-05 08:17:10 +01:00
6c2658bf03 Update dashboard.tpl
change all users to total users
2024-02-05 07:41:15 +01:00
59de353353 Merge branch 'hotspotbilling:master' into master 2024-02-05 07:33:47 +01:00
d5ea56d078 Update dashboard.tpl
change active users to All Users Insight
add All users to graph
2024-02-05 07:24:32 +01:00
7cc8034b8c 2024.2.5 2024-02-05 10:08:10 +07:00
c3a76bab90 Language add 2024-02-05 10:05:41 +07:00
8f32a7cfa9 Merge pull request #102 from Focuslinkstech/master
Dashboard update
2024-02-05 09:45:37 +07:00
cbe2602b69 Dashboard update
add monthly Sales Graph
add Monthly Registered Customers Graph
add Active Users Graph
2024-02-04 20:25:31 +01:00
771bc9d8d9 Fix edit plan for user 2024-02-02 13:40:08 +07:00
788e558171 activate plan when its on 2024-02-02 13:39:03 +07:00
4ab32bc68d Fix Edit Plan 2024-02-02 13:38:22 +07:00
bba09ca647 activate customer when edit Expired 2024-01-29 11:34:07 +07:00
adbac642ca 2024.1.24 2024-01-24 15:06:36 +07:00
7e7b70ba75 Add test SMS, WA and Telegram 2024-01-24 14:02:58 +07:00
72fbc27f97 2024.1.19 2024-01-19 09:27:22 +07:00
d386dc5eec Sell your own plugin 2024-01-19 09:24:24 +07:00
41481880ab support full package 2024-01-19 09:22:43 +07:00
f8a879dc0f paymentgateway to paymentgateway folder 2024-01-19 09:09:07 +07:00
da44e3f6da codecanyon theme install 2024-01-19 09:08:49 +07:00
afdd7edafa themes support 2024-01-19 09:07:48 +07:00
4e1a10d814 Envato Personal Token 2024-01-18 17:24:59 +07:00
7046aa5ed1 CodeCanyon integration fix 2024-01-18 17:24:21 +07:00
d81ba5d5fb codecanyon integration 2024-01-18 15:41:24 +07:00
a35506db1b 2024.1.18 2024-01-18 13:33:22 +07:00
96945ab813 Merge pull request #99 from axmad386/patch-1
fix(mikrotik): set pool $poolId always empty
2024-01-18 12:00:51 +07:00
2b8ca5fd85 fix(mikrotik): set pool $poolId always empty 2024-01-18 01:55:23 +07:00
2d095aef08 fix delete logs 2024-01-17 13:42:07 +07:00
c906d47674 minor change, for plugin, menu can have notifications 2024-01-17 10:56:39 +07:00
5dd430f9b2 Formatting code 2024-01-17 10:54:31 +07:00
7c88be8865 Merge pull request #98 from Focuslinkstech/master
Nav menu label added
2024-01-17 10:39:25 +07:00
b45f5a5587 Merge branch 'hotspotbilling:master' into master 2024-01-16 22:26:57 +01:00
10e788e9a2 update
Nav label added
2024-01-16 22:19:38 +01:00
7ceb883826 fix notifications 2024-01-16 15:16:59 +07:00
80e78d9796 Fix sendPackageNotification 2024-01-16 15:08:26 +07:00
534d62d944 2024.1.16.1 2024-01-16 11:41:25 +07:00
1857c145d1 fix print 2024-01-16 11:41:12 +07:00
12cdef4f66 remove debug 2024-01-16 10:36:55 +07:00
b4bec8964d Support thermal printer for invoice 2024-01-16 10:32:59 +07:00
64f52d6c1c add [[price]] to reminder notification 2024-01-16 09:52:12 +07:00
b504723e7c fix radius pool select 2024-01-16 09:39:20 +07:00
470c219e61 Add Yellow line for plan not allowed to purchase 2024-01-16 09:00:56 +07:00
5867a0c9ca Fix Cron for 2024-01-15 10:22:03 +07:00
f38da8d3c0 Merge pull request #95 from Focuslinkstech/master
Update cron.php
2024-01-15 10:01:29 +07:00
7e0e09f9bf Merge branch 'hotspotbilling:master' into master 2024-01-14 15:32:43 +01:00
90e6283426 urgent update
fix installation database
added plan name when editing service plan
2024-01-14 13:58:46 +01:00
24df116003 Update cron.php
stop user from auto renewing packages that has been disabled for purchase.
2024-01-13 09:41:58 +01:00
db240131e2 2024.1.11 2024-01-11 15:56:43 +07:00
2fdc3c9567 Merge pull request #94 from Focuslinkstech/master
Allow Package Purchase Option Added.
admin can now decide if clients can purchase a particular package or not.

if No option is selected the package wont display in the package list
2024-01-11 15:41:52 +07:00
a953157b68 fix plugin manager 2024-01-11 10:07:56 +07:00
4ba38485a0 New Feature Added
Allow Package Purchase Option Added.
admin can now decide if user can purchase a particular package or not.

if no option is selected the package wont display in the package list
2024-01-11 01:00:34 +01:00
dfef6807a5 Merge branch 'master' of https://github.com/Focuslinkstech/phpnuxbill 2024-01-11 00:47:38 +01:00
5ef0520c74 Update updates.json
Database : add allow purchase
2024-01-11 00:47:17 +01:00
263a1b6722 Merge branch 'hotspotbilling:master' into master 2024-01-11 00:30:28 +01:00
f4c5b6a8bb Update user-dashboard.tpl
fix typo error
2024-01-10 11:51:57 +01:00
05ed37d3d8 2024.1.9 2024-01-09 10:34:19 +07:00
055b855bc1 Delete Used Voucher which not exists in tbl recharges 2024-01-08 16:12:21 +07:00
b862a759d0 Add Prefix 2024-01-08 15:39:04 +07:00
41cc04cffb 2024.1.8 2024-01-08 15:28:13 +07:00
1d29f8111e Order Expired by Expired date 2024-01-08 15:24:35 +07:00
081dd1b1b9 add nasreload table 2024-01-02 13:51:26 +07:00
9804bcb9e8 log class 2024-01-02 13:35:06 +07:00
19e39dbefc templat bug report and Feature Request 2024-01-02 11:42:08 +07:00
b5c29f6c3d Merge remote-tracking branch 'origin/Development' into Development 2024-01-02 11:35:20 +07:00
fe94ae3011 2024.1.2 2024-01-02 11:34:23 +07:00
a25112a37f add paginator
add paginator to dashboard expire user list
2024-01-02 11:33:28 +07:00
9d1d287e9a 2024.1.2 2024-01-02 11:31:41 +07:00
4bddaf0260 Merge pull request #86 from Focuslinkstech/master
add paginator
2024-01-02 11:28:27 +07:00
43ed5e452e add paginator
add paginator to dashboard expire user list
2023-12-27 20:10:56 +01:00
12c339898c Fix header user 2023-12-21 14:00:58 +07:00
d087c9625d modern-skin-dark 2023-12-21 14:00:58 +07:00
98223c1abe no skinblue 2023-12-21 14:00:58 +07:00
402660e3e1 Modern AdminLTE 2023-12-21 14:00:58 +07:00
f42f410867 #changed the AdminLTE to Modern AdminLTE Template 2023-12-21 14:00:58 +07:00
df28e2b1c2 #changed the AdminLTE to Modern AdminLTE 2023-12-21 14:00:58 +07:00
74b5c47640 Merge pull request #83 from Focuslinkstech/master
Update user-dashboard.tpl
2023-12-21 14:00:31 +07:00
5f5213527f fix alert notify 2023-12-20 09:02:39 +07:00
5e76c3e214 detect if radius 2023-12-19 16:00:14 +07:00
e2c0fa5690 Fix title 2023-12-19 11:47:40 +07:00
3afb7b9954 Remove all used voucher codes 2023-12-19 11:45:18 +07:00
13b448da69 Disable Registration 2023-12-19 11:35:49 +07:00
017518b308 Fix Searching 2023-12-19 09:55:55 +07:00
4ae19849a1 2023.12.18 2023-12-18 16:48:23 +07:00
d666e052f4 split sms to 160 only for mikrotik 2023-12-18 16:47:08 +07:00
c1f04c17a5 Update user-dashboard.tpl
add condition to display service type
2023-12-14 10:21:27 +01:00
9c22c22f6c Update Readme 2023-12-14 11:59:50 +07:00
518fe7563e 2023.12.14 2023-12-14 11:49:48 +07:00
adc2c808e2 Added user Types for Internet Packages
ability to display packages according to the user type. Hotspot users Can now only see hotspot packages
PPPoE users can now see only PPPoE Packages
Others Can see both Hotspot and PPPoE packages
2023-12-14 11:34:28 +07:00
a7a0f84df5 add new feature "service type" Hotspot PPPoE and Others
ability to display packages according to the user type.
Hotspot users Can now see only hotspot packages
PPPoE users can now see only PPPoE Packages
Others Can see both Hotspot and PPPoE packages
2023-12-14 03:21:55 +01:00
b7c663f4ee split sms characters to 160 2023-12-12 13:36:00 +07:00
dd4329ad3d remove port=usb1 channel=2 2023-12-11 15:40:18 +07:00
41b981cb70 remove debug 2023-12-11 15:21:13 +07:00
431c971f3a selected router 2023-12-11 15:08:00 +07:00
653580722e /tool sms send port=usb1 channel=2 2023-12-11 15:06:21 +07:00
6a0ad7f178 sms using Mikrotik 2023-12-11 14:12:12 +07:00
9d79121696 cek if not radius 2023-11-21 14:41:21 +07:00
8e84c32616 fix prepaid update 2023-11-21 13:47:10 +07:00
486e22f020 fix change plan for radius 2023-11-20 09:02:33 +07:00
76 changed files with 2195 additions and 855 deletions

View File

@ -7,6 +7,9 @@ assignees: ibnux
---
Please Remember, this project is free and open source, and @ibnux don't get any money from this project, and if you post something not a bug, just you dont understand how to install it, you will get blocked from this Repository.
Post it in Discussion if you don't understand. Except you pay for $50 for support
**Describe the bug**
A clear and concise description of what the bug is. Error connecting to router is not a bug, is your router port is not accessable, ask community for help, go to discussion or telegram group

View File

@ -7,6 +7,8 @@ assignees: ''
---
Please Remember, this project is free and open source, and @ibnux don't get any money from this project, any Feature Request will cost you $50-$5000
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

1
.gitignore vendored
View File

@ -4,6 +4,7 @@ config.php
ui/compiled/*.php
ui/cache/*.php
test.php
sms.php
pages/
system/cache/**
system/plugin/*

View File

@ -2,6 +2,89 @@
# CHANGELOG
## 2024.2.7
- Hide Dashboard content
## 2024.2.6
- Cache graph for faster opening graph
## 2024.2.5
- Admin Dashboard Update
- Add Monthly Registered Customers
- Total Monthly Sales
- Active Users
## 2024.2.2
- Fix edit plan for user
## 2024.1.24
- Add Send test for SMS, Whatsapp and Telegram
## 2024.1.19
- Paid Plugin, Theme, and payment gateway marketplace using codecanyon.net
- Fix Plugin manager List
## 2024.1.18
- fix(mikrotik): set pool $poolId always empty
## 2024.1.17
- Add minor change, for plugin, menu can have notifications by @Focuslinkstech
## 2024.1.16
- Add yellow color to table for plan not allowed to purchase
- Fix Radius pool select
- add price to reminder notification
- Support thermal printer for invoice
## 2024.1.15
- Fix cron job for Plan only for admin by @Focuslinkstech
## 2024.1.11
- Add Plan only for admin by @Focuslinkstech
- Fix Plugin Manager
## 2024.1.9
- Add Prefix when generate Voucher
## 2024.1.8
- User Expired Order by Expired Date
## 2024.1.2
- Pagination User Expired by @Focuslinkstech
## 2023.12.21
- Modern AdminLTE by @sabtech254
- Update user-dashboard.tpl by @Focuslinkstech
## 2023.12.19
- Fix Search Customer
- Disable Registration, Customer just activate voucher Code, and the voucher will be their password
- Remove all used voucher codes
## 2023.12.18
- Split sms to 160 characters only for Mikrotik Modem
## 2023.12.14
- Can send SMS using Mikrotik with Modem Installed
- Add Customer Type, so Customer can only show their PPPOE or Hotspot Package or both
## 2023.11.17

View File

@ -1,12 +1,13 @@
[![ReadMeSupportPalestine](https://raw.githubusercontent.com/Safouene1/support-palestine-banner/master/banner-project.svg)](https://s.id/standwithpalestine)
# PHPNuxBill - PHP Mikrotik Billing
![PHPNuxBill](install/img/logo.png)
![StandWithPalestine](https://raw.githubusercontent.com/Safouene1/support-palestine-banner/master/StandWithPalestine.svg)
## Feature
- Voucher Generator and Print
- FreeRadius
- Self registration
- User Balance
- Auto Renewal Package using Balance
@ -14,7 +15,7 @@
- Hotspot & PPPOE
- Easy Installation
- Multi Language
- Payment Gateway Midtrans, Xendit and Tripay
- Payment Gateway
- SMS validation for login
- Whatsapp Notification to Consumer
- Telegram Notification for Admin
@ -35,7 +36,7 @@ Most current web servers with PHP & MySQL installed will be capable of running P
Minimum Requirements
- Linux or Windows OS
- PHP Version 7.4
- Minimum PHP Version 7.4
- Both PDO & MySQLi Support
- PHP-GD2 Image Library
- PHP-CURL

View File

@ -27,6 +27,7 @@ CREATE TABLE `tbl_customers` (
`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 DEFAULT '0.00' COMMENT 'For Money Deposit',
`service_type` ENUM('Hotspot','PPPoE','Others') DEFAULT 'Others' COMMENT 'For selecting user type',
`auto_renewal` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'Auto renewall using balance',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_login` datetime DEFAULT NULL
@ -103,7 +104,8 @@ CREATE TABLE `tbl_plans` (
`is_radius` tinyint(1) NOT NULL DEFAULT '0' COMMENT '1 is radius',
`pool` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`pool_expired` varchar(40) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`enabled` tinyint(1) NOT NULL DEFAULT '1' COMMENT '0 disabled\r\n'
`enabled` tinyint(1) NOT NULL DEFAULT '1' COMMENT '0 disabled\r\n',
`allow_purchase` enum('yes','no') DEFAULT 'yes' COMMENT 'allow to show package in buy package page'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
DROP TABLE IF EXISTS `tbl_pool`;
@ -186,6 +188,8 @@ CREATE TABLE `tb_languages` (
`id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
ALTER TABLE `tbl_voucher` ADD `generated_by` INT NOT NULL DEFAULT '0' COMMENT 'id admin' AFTER `status`;
ALTER TABLE `tbl_users` ADD `root` INT NOT NULL DEFAULT '0' COMMENT 'for sub account' AFTER `id`;
ALTER TABLE `tbl_appconfig`
ADD PRIMARY KEY (`id`);
@ -308,4 +312,4 @@ VALUES (
'Active',
'2022-09-06 16:09:50',
'2014-06-23 01:43:07'
);
);

View File

@ -102,6 +102,13 @@ CREATE TABLE `radusergroup` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
DROP TABLE IF EXISTS `nasreload`;
CREATE TABLE `nasreload` (
nasipaddress varchar(15) NOT NULL,
reloadtime datetime NOT NULL,
PRIMARY KEY (nasipaddress)
) ENGINE = INNODB;
ALTER TABLE `nas`
ADD PRIMARY KEY (`id`),
ADD KEY `nasname` (`nasname`);

View File

@ -16,8 +16,10 @@ $menu_registered = array();
* Admin/Sales menu: AFTER_DASHBOARD, CUSTOMERS, PREPAID, SERVICES, REPORTS, VOUCHER, AFTER_ORDER, NETWORK, SETTINGS, AFTER_PAYMENTGATEWAY
* | Customer menu: AFTER_DASHBOARD, ORDER, HISTORY, ACCOUNTS
* @param string icon from ion icon, ion-person, only for AFTER_
* @param string label for showing label or number of notification or update
* @param string color Label color
*/
function register_menu($name, $admin, $function, $position, $icon = '')
function register_menu($name, $admin, $function, $position, $icon = '', $label = '', $color = 'success')
{
global $menu_registered;
$menu_registered[] = [
@ -25,7 +27,9 @@ function register_menu($name, $admin, $function, $position, $icon = '')
"admin" => $admin,
"position" => $position,
"icon" => $icon,
"function" => $function
"function" => $function,
"label" => $label,
"color" => $color
];
}
@ -48,4 +52,3 @@ function run_hook($action){
}
}
}

View File

@ -56,6 +56,24 @@ class Lang
return date($config['date_format'] . ' H:i', strtotime("$date $time"));
}
public static function timeElapsed($time){
$s = $time%60;
$m = floor(($time%3600)/60);
$h = floor(($time%86400)/3600);
$d = floor(($time%2592000)/86400);
$M = floor($time/2592000);
$result = '';
if($M>0){
$result = $M.'m ';
}
if($d>0){
$result .= $d.'d ';
}else if($M>0){
$result .= '0d ';
}
return "$result$h:$m:$s";
}
public static function nl2br($text)
{
return nl2br($text);
@ -99,4 +117,38 @@ class Lang
}
return $result;
}
/**
* $pad_type
* 0 Left
* 1 right
* 2 center
* */
public static function pad($text, $pad_string = ' ', $pad_type = 0){
global $config;
$cols = 37;
if($config['printer_cols']){
$cols = $config['printer_cols'];
}
$text = trim($text);
$texts = explode("\n", $text);
if(count($texts)>1){
$text = '';
foreach($texts as $t){
$text.= self::pad(trim($t), $pad_string, $pad_type)."\n";
}
return $text;
}else{
return str_pad(trim($text), $cols, $pad_string, $pad_type);
}
}
public static function pads($textLeft, $textRight, $pad_string = ' '){
global $config;
$cols = 37;
if($config['printer_cols']){
$cols = $config['printer_cols'];
}
return $textLeft.str_pad($textRight, $cols-strlen($textLeft), $pad_string, 0);
}
}

32
system/autoload/Log.php Normal file
View File

@ -0,0 +1,32 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
* by https://t.me/ibnux
**/
class Log{
public static function put($type, $description, $userid = '', $username = '')
{
$d = ORM::for_table('tbl_logs')->create();
$d->date = date('Y-m-d H:i:s');
$d->type = $type;
$d->description = $description;
$d->userid = $userid;
$d->ip = (empty($username)) ? $_SERVER["REMOTE_ADDR"] : $username;
$d->save();
}
public static function arrayToText($array, $start = '', $result = '')
{
foreach ($array as $k => $v) {
if (is_array($v)) {
$result = Log::arrayToText($v, "$start$k.", $result);
} else {
$result .= $start.$k ." : ". strval($v) ."\n";
}
}
return $result;
}
}

View File

@ -14,7 +14,7 @@ class Message
global $config;
run_hook('send_telegram'); #HOOK
if (!empty($config['telegram_bot']) && !empty($config['telegram_target_id'])) {
Http::getData('https://api.telegram.org/bot' . $config['telegram_bot'] . '/sendMessage?chat_id=' . $config['telegram_target_id'] . '&text=' . urlencode($txt));
return Http::getData('https://api.telegram.org/bot' . $config['telegram_bot'] . '/sendMessage?chat_id=' . $config['telegram_target_id'] . '&text=' . urlencode($txt));
}
}
@ -24,9 +24,34 @@ class Message
global $config;
run_hook('send_sms'); #HOOK
if (!empty($config['sms_url'])) {
$smsurl = str_replace('[number]', urlencode($phone), $config['sms_url']);
$smsurl = str_replace('[text]', urlencode($txt), $smsurl);
Http::getData($smsurl);
if (strlen($config['sms_url']) > 4 && substr($config['sms_url'], 0, 4) != "http") {
if (strlen($txt) > 160) {
$txts = str_split($txt, 160);
try {
$mikrotik = Mikrotik::info($config['sms_url']);
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
foreach ($txts as $txt) {
Mikrotik::sendSMS($client, $phone, $txt);
}
} catch (Exception $e) {
// ignore, add to logs
_log("Failed to send SMS using Mikrotik.\n" . $e->getMessage(), 'SMS', 0);
}
} else {
try {
$mikrotik = Mikrotik::info($config['sms_url']);
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
Mikrotik::sendSMS($client, $phone, $txt);
} catch (Exception $e) {
// ignore, add to logs
_log("Failed to send SMS using Mikrotik.\n" . $e->getMessage(), 'SMS', 0);
}
}
} else {
$smsurl = str_replace('[number]', urlencode($phone), $config['sms_url']);
$smsurl = str_replace('[text]', urlencode($txt), $smsurl);
return Http::getData($smsurl);
}
}
}
@ -37,14 +62,15 @@ class Message
if (!empty($config['wa_url'])) {
$waurl = str_replace('[number]', urlencode($phone), $config['wa_url']);
$waurl = str_replace('[text]', urlencode($txt), $waurl);
Http::getData($waurl);
return Http::getData($waurl);
}
}
public static function sendPackageNotification($phone, $name, $package, $message, $via)
public static function sendPackageNotification($phone, $name, $package, $price, $message, $via)
{
$msg = str_replace('[[name]]', "*$name*", $message);
$msg = str_replace('[[package]]', "*$package*", $msg);
$msg = str_replace('[[name]]', $name, $message);
$msg = str_replace('[[package]]', $package, $msg);
$msg = str_replace('[[price]]', $price, $msg);
if (
!empty($phone) && strlen($phone) > 5
&& !empty($message) && in_array($via, ['sms', 'wa'])
@ -60,9 +86,9 @@ class Message
public static function sendBalanceNotification($phone, $name, $balance, $balance_now, $message, $via)
{
$msg = str_replace('[[name]]', "*$name*", $message);
$msg = str_replace('[[name]]', $name, $message);
$msg = str_replace('[[current_balance]]', Lang::moneyFormat($balance_now), $msg);
$msg = str_replace('[[balance]]', "*" . Lang::moneyFormat($balance) . "*", $msg);
$msg = str_replace('[[balance]]', Lang::moneyFormat($balance), $msg);
if (
!empty($phone) && strlen($phone) > 5
&& !empty($message) && in_array($via, ['sms', 'wa'])
@ -76,7 +102,8 @@ class Message
return "$via: $msg";
}
public static function sendInvoice($cust, $trx){
public static function sendInvoice($cust, $trx)
{
global $config;
$textInvoice = Lang::getNotifText('invoice_paid');
$textInvoice = str_replace('[[company_name]]', $config['CompanyName'], $textInvoice);
@ -84,8 +111,9 @@ class Message
$textInvoice = str_replace('[[phone]]', $config['phone'], $textInvoice);
$textInvoice = str_replace('[[invoice]]', $trx['invoice'], $textInvoice);
$textInvoice = str_replace('[[date]]', Lang::dateAndTimeFormat($trx['recharged_on'], $trx['recharged_time']), $textInvoice);
$textInvoice = str_replace('[[payment_gateway]]', $config['gateway'], $textInvoice);
$textInvoice = str_replace('[[payment_channel]]', $config['channel'], $textInvoice);
$gc = explode("-", $trx['method']);
$textInvoice = str_replace('[[payment_gateway]]', trim($gc[0]), $textInvoice);
$textInvoice = str_replace('[[payment_channel]]', trim($gc[1]), $textInvoice);
$textInvoice = str_replace('[[type]]', $trx['type'], $textInvoice);
$textInvoice = str_replace('[[plan_name]]', $trx['plan_name'], $textInvoice);
$textInvoice = str_replace('[[plan_price]]', Lang::moneyFormat($trx['price']), $textInvoice);

View File

@ -65,7 +65,7 @@ class Mikrotik
);
$id = $client->sendSync($printRequest)->getProperty('.id');
$removeRequest = new RouterOS\Request('/ip/hotspot/active/remove');
$client(
$client->sendSync(
$removeRequest
->setArgument('numbers', $id)
);
@ -101,7 +101,7 @@ class Mikrotik
Mikrotik::addHotspotPlan($client, $name, $sharedusers, $rate);
} else {
$setRequest = new RouterOS\Request('/ip/hotspot/user/profile/set');
$client(
$client->sendSync(
$setRequest
->setArgument('numbers', $profileID)
->setArgument('shared-users', $sharedusers)
@ -132,7 +132,7 @@ class Mikrotik
);
} else {
$setRequest = new RouterOS\Request('/ip/hotspot/user/profile/set');
$client(
$client->sendSync(
$setRequest
->setArgument('numbers', $profileID)
->setArgument('shared-users', 3)
@ -155,7 +155,7 @@ class Mikrotik
$profileID = $client->sendSync($printRequest)->getProperty('.id');
$removeRequest = new RouterOS\Request('/ip/hotspot/user/profile/remove');
$client(
$client->sendSync(
$removeRequest
->setArgument('numbers', $profileID)
);
@ -173,7 +173,7 @@ class Mikrotik
);
$userID = $client->sendSync($printRequest)->getProperty('.id');
$removeRequest = new RouterOS\Request('/ip/hotspot/user/remove');
$client(
$client->sendSync(
$removeRequest
->setArgument('numbers', $userID)
);
@ -397,7 +397,7 @@ class Mikrotik
$poolID = $client->sendSync($printRequest)->getProperty('.id');
$removeRequest = new RouterOS\Request('/ip/pool/remove');
$client(
$client->sendSync(
$removeRequest
->setArgument('numbers', $poolID)
);
@ -427,13 +427,13 @@ class Mikrotik
'/ip pool print .proplist=.id',
RouterOS\Query::where('name', $name)
);
$poolID = $client->sendSync($printRequest)->getProperty('id');
$poolID = $client->sendSync($printRequest)->getProperty('.id');
if (empty($poolID)) {
self::addPool($client, $name, $ip_address);
} else {
$setRequest = new RouterOS\Request('/ip/pool/set');
$client(
$client->sendSync(
$setRequest
->setArgument('numbers', $poolID)
->setArgument('ranges', $ip_address)
@ -473,7 +473,7 @@ class Mikrotik
self::addPpoePlan($client, $name, $pool, $rate);
} else {
$setRequest = new RouterOS\Request('/ppp/profile/set');
$client(
$client->sendSync(
$setRequest
->setArgument('numbers', $profileID)
->setArgument('local-address', $pool)
@ -496,9 +496,55 @@ class Mikrotik
$profileID = $client->sendSync($printRequest)->getProperty('.id');
$removeRequest = new RouterOS\Request('/ppp/profile/remove');
$client(
$client->sendSync(
$removeRequest
->setArgument('numbers', $profileID)
);
}
public static function sendSMS($client, $to, $message)
{
global $_app_stage;
if ($_app_stage == 'demo') {
return null;
}
$smsRequest = new RouterOS\Request('/tool sms send');
$smsRequest
->setArgument('phone-number', $to)
->setArgument('message', $message);
$client->sendSync($smsRequest);
}
public static function addIpToAddressList($client, $ip, $listName, $comment = '')
{
global $_app_stage;
if ($_app_stage == 'demo') {
return null;
}
$addRequest = new RouterOS\Request('/ip/firewall/address-list/add');
$client->sendSync(
$addRequest
->setArgument('address', $ip)
->setArgument('comment', $comment)
->setArgument('list', $listName)
);
}
public static function removeIpFromAddressList($client, $ip)
{
global $_app_stage;
if ($_app_stage == 'demo') {
return null;
}
$printRequest = new RouterOS\Request(
'/ip firewall address-list print .proplist=.id',
RouterOS\Query::where('address', $ip)
);
$id = $client->sendSync($printRequest)->getProperty('.id');
$removeRequest = new RouterOS\Request('/ip/firewall/address-list/remove');
$client->sendSync(
$removeRequest
->setArgument('numbers', $id)
);
}
}

View File

@ -59,8 +59,8 @@ class Package
$textInvoice = str_replace('[[phone]]', $_c['phone'], $textInvoice);
$textInvoice = str_replace('[[invoice]]', $inv, $textInvoice);
$textInvoice = str_replace('[[date]]', Lang::dateTimeFormat($date_now), $textInvoice);
$textInvoice = str_replace('[[payment_gateway]]', $_c['gateway'], $textInvoice);
$textInvoice = str_replace('[[payment_channel]]', $_c['channel'], $textInvoice);
$textInvoice = str_replace('[[payment_gateway]]', $gateway, $textInvoice);
$textInvoice = str_replace('[[payment_channel]]', $channel, $textInvoice);
$textInvoice = str_replace('[[type]]', 'Balance', $textInvoice);
$textInvoice = str_replace('[[plan_name]]', $p['name_plan'], $textInvoice);
$textInvoice = str_replace('[[plan_price]]', Lang::moneyFormat($p['price']), $textInvoice);
@ -316,8 +316,7 @@ class Package
"\nPrice: " . Lang::moneyFormat($p['price']));
}
$in = ORM::for_table('tbl_transactions')->where('username', $c['username'])->order_by_desc('id')->find_one();
Message::sendInvoice($c, $in);
Message::sendInvoice($c, $t);
return true;
}
@ -326,7 +325,7 @@ class Package
$c = ORM::for_table('tbl_customers')->where('username', $username)->find_one();
$p = ORM::for_table('tbl_plans')->where('id', $plan_id)->where('enabled', '1')->find_one();
$b = ORM::for_table('tbl_user_recharges')->find_one($from_id);
if($p['routers'] == $b['routers']){
if($p['routers'] == $b['routers'] && $b['routers'] != 'radius'){
$mikrotik = Mikrotik::info($p['routers']);
}else{
$mikrotik = Mikrotik::info($b['routers']);
@ -370,7 +369,7 @@ class Package
}
}
// call the next mikrotik
if($p['routers'] != $b['routers']){
if($p['routers'] != $b['routers'] && $p['routers'] != 'radius'){
$mikrotik = Mikrotik::info($p['routers']);
}
if ($p['type'] == 'Hotspot') {

View File

@ -20,7 +20,7 @@ class Validator
* @param array $hits
* @return void
*/
private static function textHit($string, $exclude = "")
public static function textHit($string, $exclude = "")
{
if (empty($exclude)) return false;
if (is_array($exclude)) {

View File

@ -108,6 +108,21 @@ try {
ORM::configure('driver_options', array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'), 'radius');
ORM::configure('return_result_sets', true, 'radius');
}
} catch (Throwable $e) {
$ui = new Smarty();
$ui->setTemplateDir(['custom' => File::pathFixer('ui/ui_custom/'), 'default' => File::pathFixer('ui/ui/')]);
$ui->assign('_url', APP_URL . '/index.php?_route=');
$ui->setCompileDir(File::pathFixer('ui/compiled/'));
$ui->setConfigDir(File::pathFixer('ui/conf/'));
$ui->setCacheDir(File::pathFixer('ui/cache/'));
$ui->assign("error_title", "PHPNuxBill Crash");
if (isset($_SESSION['uid'])) {
$ui->assign("error_message", $e->getMessage() . '<br>');
} else {
$ui->assign("error_message", $e->getMessage() . '<br><pre>' . $e->getTraceAsString() . '</pre>');
}
$ui->display('router-error.tpl');
die();
} catch (Exception $e) {
$ui = new Smarty();
$ui->setTemplateDir(['custom' => File::pathFixer('ui/ui_custom/'), 'default' => File::pathFixer('ui/ui/')]);
@ -118,7 +133,7 @@ try {
$ui->assign("error_title", "PHPNuxBill Crash");
if (isset($_SESSION['uid'])) {
$ui->assign("error_message", $e->getMessage() . '<br>');
}else{
} else {
$ui->assign("error_message", $e->getMessage() . '<br><pre>' . $e->getTraceAsString() . '</pre>');
}
$ui->display('router-error.tpl');
@ -130,13 +145,13 @@ function _notify($msg, $type = 'e')
$_SESSION['ntype'] = $type;
$_SESSION['notify'] = $msg;
}
if(empty($config['language'])){
if (empty($config['language'])) {
$config['language'] = 'english';
}
$lan_file = File::pathFixer('system/lan/' . $config['language'] . '/common.lan.php');
if(file_exists($lan_file)){
if (file_exists($lan_file)) {
require $lan_file;
}else{
} else {
die("$lan_file not found");
}
@ -190,7 +205,11 @@ $_notifmsg_default = json_decode(file_get_contents(File::pathFixer('system/uploa
//register all plugin
foreach (glob(File::pathFixer("system/plugin/*.php")) as $filename) {
include $filename;
try {
include $filename;
} catch (Throwable $e) {
} catch (Exception $e) {
}
}
@ -299,7 +318,8 @@ function time_elapsed_string($datetime, $full = false)
}
}
if (!$full) $string = array_slice($string, 0, 1);
if (!$full)
$string = array_slice($string, 0, 1);
return $string ? implode(', ', $string) . ' ago' : 'just now';
}
@ -312,7 +332,6 @@ if ($handler == '') {
$handler = 'default';
}
try {
$sys_render = File::pathFixer('system/controllers/' . $handler . '.php');
if (file_exists($sys_render)) {
$menus = array();
@ -327,12 +346,20 @@ try {
if (!empty($menu['icon'])) {
$menus[$menu['position']] .= '<i class="' . $menu['icon'] . '"></i>';
}
if (!empty($menu['label'])) {
$menus[$menu['position']] .= '<span class="pull-right-container">';
$menus[$menu['position']] .= '<small class="label pull-right bg-' . $menu['color'] . '">' . $menu['label'] . '</small></span>';
}
$menus[$menu['position']] .= '<span class="text">' . $menu['name'] . '</span></a></li>';
} else if (!$menu['admin'] && _auth(false)) {
$menus[$menu['position']] .= '<li' . (($routes[1] == $menu['function']) ? ' class="active"' : '') . '><a href="' . U . 'plugin/' . $menu['function'] . '">';
if (!empty($menu['icon'])) {
$menus[$menu['position']] .= '<i class="' . $menu['icon'] . '"></i>';
}
if (!empty($menu['label'])) {
$menus[$menu['position']] .= '<span class="pull-right-container">';
$menus[$menu['position']] .= '<small class="label pull-right bg-' . $menu['color'] . '">' . $menu['label'] . '</small></span>';
}
$menus[$menu['position']] .= '<span class="text">' . $menu['name'] . '</span></a></li>';
}
}
@ -344,9 +371,17 @@ try {
} else {
r2(U . 'dashboard', 'e', 'not found');
}
} catch (Throwable $e) {
if (!isset($_SESSION['aid']) || empty($_SESSION['aid'])) {
r2(U . 'home', 'e', $e->getMessage());
}
$ui->assign("error_message", $e->getMessage() . '<br><pre>' . $e->getTraceAsString() . '</pre>');
$ui->assign("error_title", "PHPNuxBill Crash");
$ui->display('router-error.tpl');
die();
} catch (Exception $e) {
if (isset($_SESSION['uid'])) {
r2(U . 'home' , 'e', $e->getMessage());
if (!isset($_SESSION['aid']) || empty($_SESSION['aid'])) {
r2(U . 'home', 'e', $e->getMessage());
}
$ui->assign("error_message", $e->getMessage() . '<br><pre>' . $e->getTraceAsString() . '</pre>');
$ui->assign("error_title", "PHPNuxBill Crash");

View File

@ -66,7 +66,7 @@ switch ($action) {
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();
$c = ORM::for_table('tbl_customers')->where_raw("(`username` LIKE '%$s%' OR `fullname` LIKE '%$s%' OR `phonenumber` LIKE '%$s%' OR `email` LIKE '%$s%')")->limit(30)->find_many();
}
header('Content-Type: application/json');
foreach ($c as $cust) {

View File

@ -0,0 +1,126 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
* by https://t.me/ibnux
**/
_admin();
$ui->assign('_title', 'CodeCanyon.net');
$ui->assign('_system_menu', 'settings');
$plugin_repository = 'https://hotspotbilling.github.io/Plugin-Repository/repository.json';
$action = $routes['1'];
$admin = Admin::_info();
$ui->assign('_admin', $admin);
$cache = File::pathFixer('system/cache/codecanyon.json');
if ($admin['user_type'] != 'Admin') {
r2(U . "dashboard", 'e', $_L['Do_Not_Access']);
}
if (empty($config['envato_token'])) {
r2(U . 'settings/app', 'w', '<a href="' . U . 'settings/app#envato' . '">Envato Personal Access Token</a> is not set');
}
switch ($action) {
case 'install':
if (!is_writeable(File::pathFixer('system/cache/'))) {
r2(U . "codecanyon", 'e', 'Folder system/cache/ is not writable');
}
if (!is_writeable(File::pathFixer('system/plugin/'))) {
r2(U . "codecanyon", 'e', 'Folder system/plugin/ is not writable');
}
if (!is_writeable(File::pathFixer('system/paymentgateway/'))) {
r2(U . "codecanyon", 'e', 'Folder system/paymentgateway/ is not writable');
}
set_time_limit(-1);
$item_id = $routes['2'];
$tipe = $routes['3'];
$result = Http::getData('https://api.envato.com/v3/market/buyer/download?item_id=' . $item_id, ['Authorization: Bearer ' . $config['envato_token']]);
$json = json_decode($result, true);
if (!isset($json['download_url'])) {
r2(U . 'codecanyon', 'e', 'Failed to get download url. ' . $json['description']);
}
$file = File::pathFixer('system/cache/codecanyon/');
if (!file_exists($file)) {
mkdir($file);
}
$file .= $item_id . '.zip';
if (file_exists($file))
unlink($file);
//download
$fp = fopen($file, 'w+');
$ch = curl_init($json['download_url']);
curl_setopt($ch, CURLOPT_POST, 0);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 120);
curl_setopt($ch, CURLOPT_TIMEOUT, 120);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_exec($ch);
curl_close($ch);
fclose($fp);
//extract
$target = File::pathFixer('system/cache/codecanyon/' . $item_id . '/');
$zip = new ZipArchive();
$zip->open($file);
$zip->extractTo($target);
$zip->close();
//moving
if (file_exists($target . 'plugin')) {
File::copyFolder($target . 'plugin', File::pathFixer('system/plugin/'));
} else if (file_exists($target . 'paymentgateway')) {
File::copyFolder($target . 'paymentgateway', File::pathFixer('system/paymentgateway/'));
} else if (file_exists($target . 'theme')) {
File::copyFolder($target . 'theme', File::pathFixer('ui/themes/'));
}
//Cleaning
File::deleteFolder($target);
unlink($file);
r2(U . "codecanyon", 's', 'Installation success');
case 'reload':
if (file_exists($cache))
unlink($cache);
default:
if (class_exists('ZipArchive')) {
$zipExt = true;
} else {
$zipExt = false;
}
$ui->assign('zipExt', $zipExt);
if (file_exists($cache) && time() - filemtime($cache) < (24 * 60 * 60)) {
$txt = file_get_contents($cache);
$plugins = json_decode($txt, true);
$ui->assign('chached_until', date($config['date_format'] . ' H:i', filemtime($cache) + (24 * 60 * 60)));
if (count($plugins) == 0) {
unlink($cache);
r2(U . 'codecanyon');
}
} else {
$plugins = [];
$page = _get('page', 1);
back:
$result = Http::getData('https://api.envato.com/v3/market/buyer/list-purchases?&page=' . $page, ['Authorization: Bearer ' . $config['envato_token']]);
$items = json_decode($result, true);
if ($items && count($items['results']) > 0) {
foreach ($items['results'] as $item) {
$name = strtolower($item['item']['name']);
if (strpos($name, 'phpnuxbill') !== false) {
$plugins[] = $item;
}
}
$page++;
goto back;
}
if (count($plugins) > 0) {
file_put_contents($cache, json_encode($plugins));
if (file_exists($cache)) {
$ui->assign('chached_until', date($config['date_format'] . ' H:i', filemtime($cache) + (24 * 60 * 60)));
}
}
}
$ui->assign('plugins', $plugins);
$ui->display('codecanyon.tpl');
}

View File

@ -28,13 +28,15 @@ switch ($action) {
'username' => '%' . $search . '%',
'fullname' => '%' . $search . '%',
'phonenumber' => '%' . $search . '%',
'email' => '%' . $search . '%'
'email' => '%' . $search . '%',
'service_type' => '%' . $search . '%'
], $search);
$d = ORM::for_table('tbl_customers')
->where_raw("(`username` LIKE '%$search%' OR `fullname` LIKE '%$search%' OR `phonenumber` LIKE '%$search%' OR `email` LIKE '%$search%')", [$search, $search, $search, $search])
->where_raw("(`username` LIKE '%$search%' OR `fullname` LIKE '%$search%' OR `phonenumber` LIKE '%$search%' OR `email` LIKE '%$search%')")
->offset($paginator['startpoint'])
->limit($paginator['limit'])
->order_by_desc('id')->find_many();
->order_by_asc('username')
->find_many();
} else {
$paginator = Paginator::build(ORM::for_table('tbl_customers'));
$d = ORM::for_table('tbl_customers')
@ -227,6 +229,7 @@ switch ($action) {
$email = _post('email');
$address = _post('address');
$phonenumber = _post('phonenumber');
$service_type = _post('service_type');
run_hook('add_customer'); #HOOK
$msg = '';
if (Validator::Length($username, 35, 2) == false) {
@ -253,6 +256,7 @@ switch ($action) {
$d->fullname = $fullname;
$d->address = $address;
$d->phonenumber = Lang::phoneFormat($phonenumber);
$d->service_type = $service_type;
$d->save();
r2(U . 'customers/list', 's', $_L['account_created_successfully']);
} else {
@ -268,6 +272,7 @@ switch ($action) {
$email = _post('email');
$address = _post('address');
$phonenumber = Lang::phoneFormat(_post('phonenumber'));
$service_type = _post('service_type');
run_hook('edit_customer'); #HOOK
$msg = '';
if (Validator::Length($username, 16, 2) == false) {
@ -320,6 +325,7 @@ switch ($action) {
$d->email = $email;
$d->address = $address;
$d->phonenumber = $phonenumber;
$d->service_type = $service_type;
$d->save();
if ($userDiff || $pppoeDiff || $passDiff) {
$c = ORM::for_table('tbl_user_recharges')->where('username', ($userDiff) ? $oldusername : $username)->find_one();

View File

@ -51,9 +51,28 @@ if (empty($c_all)) {
}
$ui->assign('c_all', $c_all);
//user expire
$expire = ORM::for_table('tbl_user_recharges')->whereLte('expiration', $mdate)->order_by_desc('id')->limit(30)->find_many();
$ui->assign('expire', $expire);
if($config['hide_uet'] != 'yes'){
//user expire
$paginator = Paginator::build(ORM::for_table('tbl_user_recharges'));
$expire = ORM::for_table('tbl_user_recharges')
->where_lte('expiration', $mdate)
->offset($paginator['startpoint'])
->limit($paginator['limit'])
->order_by_desc('expiration')
->find_many();
// Get the total count of expired records for pagination
$totalCount = ORM::for_table('tbl_user_recharges')
->where_lte('expiration', $mdate)
->count();
// Pass the total count and current page to the paginator
$paginator['total_count'] = $totalCount;
// Assign the pagination HTML to the template variable
$ui->assign('paginator', $paginator);
$ui->assign('expire', $expire);
}
//activity log
$dlog = ORM::for_table('tbl_logs')->limit(5)->order_by_desc('id')->find_many();
@ -61,28 +80,113 @@ $ui->assign('dlog', $dlog);
$log = ORM::for_table('tbl_logs')->count();
$ui->assign('log', $log);
// Count stock
$tmp = $v = ORM::for_table('tbl_plans')->select('id')->select('name_plan')->find_many();
$plans = array();
$stocks = array("used" => 0, "unused" => 0);
$n = 0;
foreach ($tmp as $plan) {
$unused = ORM::for_table('tbl_voucher')
->where('id_plan', $plan['id'])
->where('status', 0)->count();
$used = ORM::for_table('tbl_voucher')
->where('id_plan', $plan['id'])
->where('status', 1)->count();
if($unused>0 || $used>0){
$plans[$n]['name_plan'] = $plan['name_plan'];
$plans[$n]['unused'] = $unused;
$plans[$n]['used'] = $used;
$stocks["unused"] += $unused;
$stocks["used"] += $used;
$n++;
if($config['hide_vs'] != 'yes'){
$cacheStocksfile = File::pathFixer('system/cache/VoucherStocks.temp');
$cachePlanfile = File::pathFixer('system/cache/VoucherPlans.temp');
//Cache for 5 minutes
if(file_exists($cacheStocksfile) && time()- filemtime($cacheStocksfile) < 600){
$stocks = json_decode(file_get_contents($cacheStocksfile), true);
$plans = json_decode(file_get_contents($cachePlanfile), true);
}else{
// Count stock
$tmp = $v = ORM::for_table('tbl_plans')->select('id')->select('name_plan')->find_many();
$plans = array();
$stocks = array("used" => 0, "unused" => 0);
$n = 0;
foreach ($tmp as $plan) {
$unused = ORM::for_table('tbl_voucher')
->where('id_plan', $plan['id'])
->where('status', 0)->count();
$used = ORM::for_table('tbl_voucher')
->where('id_plan', $plan['id'])
->where('status', 1)->count();
if ($unused > 0 || $used > 0) {
$plans[$n]['name_plan'] = $plan['name_plan'];
$plans[$n]['unused'] = $unused;
$plans[$n]['used'] = $used;
$stocks["unused"] += $unused;
$stocks["used"] += $used;
$n++;
}
}
file_put_contents($cacheStocksfile, json_encode($stocks));
file_put_contents($cachePlanfile, json_encode($plans));
}
}
$cacheMRfile = File::pathFixer('system/cache/monthlyRegistered.temp');
//Cache for 1 hour
if(file_exists($cacheMRfile) && time()- filemtime($cacheMRfile) < 3600){
$monthlyRegistered = json_decode(file_get_contents($cacheMRfile), true);
}else{
//Monthly Registered Customers
$result = ORM::for_table('tbl_customers')
->select_expr('MONTH(created_at)', 'month')
->select_expr('COUNT(*)', 'count')
->where_raw('YEAR(created_at) = YEAR(NOW())')
->group_by_expr('MONTH(created_at)')
->find_many();
$monthlyRegistered = [];
foreach ($result as $row) {
$monthlyRegistered[] = [
'date' => $row->month,
'count' => $row->count
];
}
file_put_contents($cacheMRfile, json_encode($monthlyRegistered));
}
$cacheMSfile = File::pathFixer('system/cache/monthlySales.temp');
//Cache for 12 hours
if(file_exists($cacheMSfile) && time()- filemtime($cacheMSfile) < 43200){
$monthlySales = json_decode(file_get_contents($cacheMSfile), true);
}else{
// Query to retrieve monthly data
$results = ORM::for_table('tbl_transactions')
->select_expr('MONTH(recharged_on)', 'month')
->select_expr('SUM(price)', 'total')
->where_raw("YEAR(recharged_on) = YEAR(CURRENT_DATE())") // Filter by the current year
->group_by_expr('MONTH(recharged_on)')
->find_many();
// Create an array to hold the monthly sales data
$monthlySales = array();
// Iterate over the results and populate the array
foreach ($results as $result) {
$month = $result->month;
$totalSales = $result->total;
$monthlySales[$month] = array(
'month' => $month,
'totalSales' => $totalSales
);
}
// Fill in missing months with zero sales
for ($month = 1; $month <= 12; $month++) {
if (!isset($monthlySales[$month])) {
$monthlySales[$month] = array(
'month' => $month,
'totalSales' => 0
);
}
}
// Sort the array by month
ksort($monthlySales);
// Reindex the array
$monthlySales = array_values($monthlySales);
file_put_contents($cacheMSfile, json_encode($monthlySales));
}
// Assign the monthly sales data to Smarty
$ui->assign('monthlySales', $monthlySales);
$ui->assign('xfooter', '');
$ui->assign('monthlyRegistered', $monthlyRegistered);
$ui->assign('stocks', $stocks);
$ui->assign('plans', $plans);

View File

@ -90,29 +90,35 @@ if (_post('send') == 'balance') {
$ui->assign('_bills', User::_billing());
if(isset($_GET['recharge']) && !empty($_GET['recharge'])){
if (isset($_GET['recharge']) && !empty($_GET['recharge'])) {
$bill = ORM::for_table('tbl_user_recharges')->where('id', $_GET['recharge'])->where('username', $user['username'])->findOne();
if ($bill) {
$router = ORM::for_table('tbl_routers')->where('name', $bill['routers'])->find_one();
if ($config['enable_balance'] == 'yes') {
$plan = ORM::for_table('tbl_plans')->find_one($bill['plan_id']);
if($user['balance']>$plan['price']){
if(!$plan['enabled']){
r2(U . "home", 'e', 'Plan is not exists');
}
if($plan['allow_purchase'] != 'yes'){
r2(U . "home", 'e', 'Cannot recharge this plan');
}
if ($user['balance'] > $plan['price']) {
r2(U . "order/pay/$router[id]/$bill[plan_id]", 'e', 'Order Plan');
}else{
} else {
r2(U . "order/buy/$router[id]/$bill[plan_id]", 'e', 'Order Plan');
}
}else{
} else {
r2(U . "order/buy/$router[id]/$bill[plan_id]", 'e', 'Order Plan');
}
}
}else if(isset($_GET['deactivate']) && !empty($_GET['deactivate'])){
} else if (isset($_GET['deactivate']) && !empty($_GET['deactivate'])) {
$bill = ORM::for_table('tbl_user_recharges')->where('id', $_GET['deactivate'])->where('username', $user['username'])->findOne();
if ($bill) {
$p = ORM::for_table('tbl_plans')->where('id', $bill['plan_id'])->find_one();
if($p['is_radius']){
if ($p['is_radius']) {
Radius::customerDeactivate($user['username']);
}else{
try{
} else {
try {
$mikrotik = Mikrotik::info($bill['routers']);
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
if ($bill['type'] == 'Hotspot') {
@ -122,7 +128,7 @@ if(isset($_GET['recharge']) && !empty($_GET['recharge'])){
Mikrotik::removePpoeUser($client, $bill['username']);
Mikrotik::removePpoeActive($client, $bill['username']);
}
}catch(Exception $e){
} catch (Exception $e) {
//ignore it maybe mikrotik has been deleted
}
}
@ -130,10 +136,10 @@ if(isset($_GET['recharge']) && !empty($_GET['recharge'])){
$bill->expiration = date('Y-m-d');
$bill->time = date('H:i:s');
$bill->save();
_log('User ' . $bill['username'] . ' Deactivate '.$bill['namebp'], 'User', $bill['customer_id']);
Message::sendTelegram('User u' . $bill['username'] . ' Deactivate '.$bill['namebp']);
r2(U . 'home', 's', 'Success deactivate '.$bill['namebp']);
}else{
_log('User ' . $bill['username'] . ' Deactivate ' . $bill['namebp'], 'User', $bill['customer_id']);
Message::sendTelegram('User u' . $bill['username'] . ' Deactivate ' . $bill['namebp']);
r2(U . 'home', 's', 'Success deactivate ' . $bill['namebp']);
} else {
r2(U . 'home', 'e', 'No Active Plan');
}
}

View File

@ -42,8 +42,117 @@ switch ($do) {
break;
case 'activation':
$voucher = _post('voucher');
$username = _post('username');
$v1 = ORM::for_table('tbl_voucher')->where('code', $voucher)->find_one();
if ($v1) {
// voucher exists, check customer exists or not
$user = ORM::for_table('tbl_customers')->where('username', $username)->find_one();
if (!$user) {
$d = ORM::for_table('tbl_customers')->create();
$d->username = alphanumeric($username, "+_.");
$d->password = $voucher;
$d->fullname = '';
$d->address = '';
$d->email = '';
$d->phonenumber = (strlen($username) < 21) ? $username : '';
if ($d->save()) {
$user = ORM::for_table('tbl_customers')->where('username', $username)->find_one($d->id());
if (!$user) {
r2(U . 'login', 'e', Lang::T('Voucher activation failed'));
}
} else {
r2(U . 'login', 'e', Lang::T('Voucher activation failed') . '.');
}
}
if ($v1['status'] == 0) {
$oldPass = $user['password'];
// change customer password to voucher code
$user->password = $voucher;
$user->save();
// voucher activation
if (Package::rechargeUser($user['id'], $v1['routers'], $v1['id_plan'], "Voucher", $voucher)) {
$v1->status = "1";
$v1->user = $user['username'];
$v1->save();
$user->last_login = date('Y-m-d H:i:s');
$user->save();
// add customer to mikrotik
if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'])) {
try {
$m = Mikrotik::info($v1['routers']);
$c = Mikrotik::getClient($m['ip_address'], $m['username'], $m['password']);
Mikrotik::logMeIn($c, $user['username'], $user['password'], $_SESSION['nux-ip'], $_SESSION['nux-mac']);
if (!empty($config['voucher_redirect'])) {
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, you are connected to internet"));
} else {
r2(U . "login", 's', Lang::T("Voucher activation success, you are connected to internet"));
}
} catch (Exception $e) {
if (!empty($config['voucher_redirect'])) {
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, now you can login"));
} else {
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
}
}
}
if (!empty($config['voucher_redirect'])) {
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, now you can login"));
} else {
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
}
} else {
// if failed to recharge, restore old password
$user->password = $oldPass;
$user->save();
r2(U . 'login', 'e', Lang::T("Failed to activate voucher"));
}
} else {
// used voucher
// check if voucher used by this username
if ($v1['user'] == $user['username']) {
$user->last_login = date('Y-m-d H:i:s');
$user->save();
if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'])) {
try {
$m = Mikrotik::info($v1['routers']);
$c = Mikrotik::getClient($m['ip_address'], $m['username'], $m['password']);
Mikrotik::logMeIn($c, $user['username'], $user['password'], $_SESSION['nux-ip'], $_SESSION['nux-mac']);
if (!empty($config['voucher_redirect'])) {
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, you are connected to internet"));
} else {
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
}
} catch (Exception $e) {
if (!empty($config['voucher_redirect'])) {
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, now you can login"));
} else {
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
}
}
} else {
if (!empty($config['voucher_redirect'])) {
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, you are connected to internet"));
} else {
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
}
}
} else {
// voucher used by other customer
r2(U . 'login', 'e', $_L['Voucher_Not_Valid']);
}
}
} else {
_msglog('e', $_L['Invalid_Username_or_Password']);
r2(U . 'login');
}
default:
run_hook('customer_view_login'); #HOOK
$ui->display('user-login.tpl');
if ($config['disable_registration'] == 'yes') {
$ui->display('user-login-noreg.tpl');
} else {
$ui->display('user-login.tpl');
}
break;
}

View File

@ -23,7 +23,7 @@ switch ($action) {
$q = (_post('q') ? _post('q') : _get('q'));
$keep = _post('keep');
if (!empty($keep)) {
ORM::raw_execute("DELETE FROM tbl_logs WHERE date < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL $keep DAY))");
ORM::raw_execute("DELETE FROM tbl_logs WHERE UNIX_TIMESTAMP(date) < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL $keep DAY))");
r2(U . "logs/list/", 's', "Delete logs older than $keep days");
}
if ($q != '') {

View File

@ -37,7 +37,7 @@ switch ($action) {
}
$ui->assign('_title', 'Top Up');
$ui->assign('_system_menu', 'balance');
$plans_balance = ORM::for_table('tbl_plans')->where('enabled', '1')->where('type', 'Balance')->find_many();
$plans_balance = ORM::for_table('tbl_plans')->where('enabled', '1')->where('type', 'Balance')->where('allow_purchase', 'yes')->find_many();
$ui->assign('plans_balance', $plans_balance);
$ui->display('user-orderBalance.tpl');
break;
@ -49,24 +49,24 @@ switch ($action) {
$ui->assign('_system_menu', 'package');
if (!empty($_SESSION['nux-router'])) {
if ($_SESSION['nux-router'] == 'radius') {
$radius_pppoe = ORM::for_table('tbl_plans')->where('enabled', '1')->where('is_radius', 1)->where('type', 'PPPOE')->find_many();
$radius_hotspot = ORM::for_table('tbl_plans')->where('enabled', '1')->where('is_radius', 1)->where('type', 'Hotspot')->find_many();
$radius_pppoe = ORM::for_table('tbl_plans')->where('enabled', '1')->where('is_radius', 1)->where('type', 'PPPOE')->where('allow_purchase', 'yes')->find_many();
$radius_hotspot = ORM::for_table('tbl_plans')->where('enabled', '1')->where('is_radius', 1)->where('type', 'Hotspot')->where('allow_purchase', 'yes')->find_many();
} else {
$routers = ORM::for_table('tbl_routers')->where('id', $_SESSION['nux-router'])->find_many();
$rs = [];
foreach ($routers as $r) {
$rs[] = $r['name'];
}
$plans_pppoe = ORM::for_table('tbl_plans')->where('enabled', '1')->where_in('routers', $rs)->where('is_radius', 0)->where('type', 'PPPOE')->find_many();
$plans_hotspot = ORM::for_table('tbl_plans')->where('enabled', '1')->where_in('routers', $rs)->where('is_radius', 0)->where('type', 'Hotspot')->find_many();
$plans_pppoe = ORM::for_table('tbl_plans')->where('enabled', '1')->where_in('routers', $rs)->where('is_radius', 0)->where('type', 'PPPOE')->where('allow_purchase', 'yes')->find_many();
$plans_hotspot = ORM::for_table('tbl_plans')->where('enabled', '1')->where_in('routers', $rs)->where('is_radius', 0)->where('type', 'Hotspot')->where('allow_purchase', 'yes')->find_many();
}
} else {
$radius_pppoe = ORM::for_table('tbl_plans')->where('enabled', '1')->where('is_radius', 1)->where('type', 'PPPOE')->find_many();
$radius_hotspot = ORM::for_table('tbl_plans')->where('enabled', '1')->where('is_radius', 1)->where('type', 'Hotspot')->find_many();
$radius_pppoe = ORM::for_table('tbl_plans')->where('enabled', '1')->where('is_radius', 1)->where('type', 'PPPOE')->where('allow_purchase', 'yes')->find_many();
$radius_hotspot = ORM::for_table('tbl_plans')->where('enabled', '1')->where('is_radius', 1)->where('type', 'Hotspot')->where('allow_purchase', 'yes')->find_many();
$routers = ORM::for_table('tbl_routers')->find_many();
$plans_pppoe = ORM::for_table('tbl_plans')->where('enabled', '1')->where('is_radius', 0)->where('type', 'PPPOE')->find_many();
$plans_hotspot = ORM::for_table('tbl_plans')->where('enabled', '1')->where('is_radius', 0)->where('type', 'Hotspot')->find_many();
$plans_pppoe = ORM::for_table('tbl_plans')->where('enabled', '1')->where('is_radius', 0)->where('type', 'PPPOE')->where('allow_purchase', 'yes')->find_many();
$plans_hotspot = ORM::for_table('tbl_plans')->where('enabled', '1')->where('is_radius', 0)->where('type', 'Hotspot')->where('allow_purchase', 'yes')->find_many();
}
$ui->assign('routers', $routers);
$ui->assign('radius_pppoe', $radius_pppoe);
@ -149,6 +149,12 @@ switch ($action) {
if (empty($plan)) {
r2(U . "order/package", 'e', Lang::T("Plan Not found"));
}
if(!$plan['enabled']){
r2(U . "home", 'e', 'Plan is not exists');
}
if($plan['allow_purchase'] != 'yes'){
r2(U . "home", 'e', 'Cannot recharge this plan');
}
if ($routes['2'] == 'radius') {
$router_name = 'radius';
} else {
@ -166,7 +172,7 @@ switch ($action) {
"\nPrice: " . $p['price']);
}
} else {
echo "no renewall | plan enabled: $p[enabled] | User balance: $c[balance] | price $p[price]\n";
r2(U . "home", 'e', 'Plan is not exists');
}
break;
case 'send':
@ -179,6 +185,12 @@ switch ($action) {
if (empty($plan)) {
r2(U . "order/package", 'e', Lang::T("Plan Not found"));
}
if(!$plan['enabled']){
r2(U . "home", 'e', 'Plan is not exists');
}
if($plan['allow_purchase'] != 'yes'){
r2(U . "home", 'e', 'Cannot recharge this plan');
}
if ($routes['2'] == 'radius') {
$router_name = 'radius';
} else {
@ -277,7 +289,7 @@ switch ($action) {
$router['id'] = 0;
$router['name'] = 'balance';
}
$plan = ORM::for_table('tbl_plans')->where('enabled', '1')->find_one($routes['3']);
$plan = ORM::for_table('tbl_plans')->where('enabled', '1')->where('allow_purchase', 'yes')->find_one($routes['3']);
if (empty($router) || empty($plan)) {
r2(U . "order/package", 'e', Lang::T("Plan Not found"));
}

View File

@ -5,7 +5,7 @@
**/
_admin();
$ui->assign('_title', $_L['Plugin Manager']);
$ui->assign('_title', 'Plugin Manager');
$ui->assign('_system_menu', 'settings');
$plugin_repository = 'https://hotspotbilling.github.io/Plugin-Repository/repository.json';

View File

@ -68,6 +68,8 @@ switch ($action) {
Mikrotik::removePool($client, $d['pool_name']);
} catch (Exception $e) {
//ignore exception, it means router has already deleted
} catch(Throwable $e){
//ignore exception, it means router has already deleted
}
}
$d->delete();

View File

@ -159,7 +159,7 @@ switch ($action) {
case 'print':
$id = _post('id');
$d = ORM::for_table('tbl_transactions')->where('id', $id)->find_one();
$ui->assign('d', $d);
$ui->assign('in', $d);
$ui->assign('date', Lang::dateAndTimeFormat($d['recharged_on'], $d['recharged_time']));
run_hook('print_invoice'); #HOOK
@ -174,6 +174,7 @@ switch ($action) {
$p = ORM::for_table('tbl_plans')->where('enabled', '1')->where_not_equal('type', 'Balance')->find_many();
$ui->assign('p', $p);
run_hook('view_edit_customer_plan'); #HOOK
$ui->assign('_title', 'Edit Plan');
$ui->display('prepaid-edit.tpl');
} else {
r2(U . 'services/list', 'e', $_L['Account_Not_Found']);
@ -219,7 +220,7 @@ switch ($action) {
} else {
$msg .= $_L['Data_Not_Found'] . '<br>';
}
$p = ORM::for_table('tbl_plans')->where('id', $plan_id)->where('enabled', '1')->find_one();
$p = ORM::for_table('tbl_plans')->where('id', $id_plan)->where('enabled', '1')->find_one();
if ($d) {
} else {
$msg .= ' Plan Not Found<br>';
@ -228,13 +229,25 @@ switch ($action) {
run_hook('edit_customer_plan'); #HOOK
$d->username = $username;
$d->plan_id = $id_plan;
$d->namebp = $p['name_plan'];
//$d->recharged_on = $recharged_on;
$d->expiration = $expiration;
$d->time = $time;
$d->routers = $p['routers'];
if($d['status'] == 'off'){
if(strtotime($expiration.' '.$time) > time()){
$d->status = 'on';
}
}
if($p['is_radius']){
$d->routers = 'radius';
}else{
$d->routers = $p['routers'];
}
$d->save();
Package::changeTo($username, $id_plan, $id);
_log('[' . $admin['username'] . ']: ' . 'Edit Plan for Customer ' . $d['username'] . ' to [' . $d['plan_name'] . '][' . Lang::moneyFormat($d['price']) . ']', 'Admin', $admin['id']);
if($d['status'] == 'on'){
Package::changeTo($username, $id_plan, $id);
}
_log('[' . $admin['username'] . ']: ' . 'Edit Plan for Customer ' . $d['username'] . ' to [' . $d['namebp'] . '][' . Lang::moneyFormat($p['price']) . ']', 'Admin', $admin['id']);
r2(U . 'prepaid/list', 's', $_L['Updated_Successfully']);
} else {
r2(U . 'prepaid/edit/' . $id, 'e', $msg);
@ -243,7 +256,7 @@ switch ($action) {
case 'voucher':
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/voucher.js"></script>');
$ui->assign('_title', $_L['Prepaid_Vouchers']);
$code = _post('code');
if ($code != '') {
$ui->assign('code', $code);
@ -270,7 +283,7 @@ switch ($action) {
break;
case 'add-voucher':
$ui->assign('_title', $_L['Add_Voucher']);
$c = ORM::for_table('tbl_customers')->find_many();
$ui->assign('c', $c);
$p = ORM::for_table('tbl_plans')->where('enabled', '1')->find_many();
@ -281,6 +294,18 @@ switch ($action) {
$ui->display('voucher-add.tpl');
break;
case 'remove-voucher':
$d = ORM::for_table('tbl_voucher')->where_equal('status', '1')->findMany();
if ($d) {
$jml = 0;
foreach ($d as $v) {
if(!ORM::for_table('tbl_user_recharges')->where_equal("method",'Voucher - '.$v['code'])->findOne()){
$v->delete();
$jml++;
}
}
r2(U . 'prepaid/voucher', 's', "$jml ".$_L['Delete_Successfully']);
}
case 'print-voucher':
$from_id = _post('from_id');
$planid = _post('planid');
@ -383,6 +408,8 @@ switch ($action) {
case 'voucher-post':
$type = _post('type');
$plan = _post('plan');
$voucher_format = _post('voucher_format');
$prefix = _post('prefix');
$server = _post('server');
$numbervoucher = _post('numbervoucher');
$lengthcode = _post('lengthcode');
@ -398,21 +425,34 @@ switch ($action) {
$msg .= 'The Length Code must be a number' . '<br>';
}
if ($msg == '') {
if(!empty($prefix)){
$d = ORM::for_table('tbl_appconfig')->where('setting', 'voucher_prefix')->find_one();
if ($d) {
$d->value = $prefix;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'voucher_prefix';
$d->value = $prefix;
$d->save();
}
}
run_hook('create_voucher'); #HOOK
for ($i = 0; $i < $numbervoucher; $i++) {
$code = strtoupper(substr(md5(time() . rand(10000, 99999)), 0, $lengthcode));
if ($config['voucher_format'] == 'low') {
if ($voucher_format == 'low') {
$code = strtolower($code);
} else if ($config['voucher_format'] == 'rand') {
} else if ($voucher_format == 'rand') {
$code = Lang::randomUpLowCase($code);
}
$d = ORM::for_table('tbl_voucher')->create();
$d->type = $type;
$d->routers = $server;
$d->id_plan = $plan;
$d->code = $code;
$d->code = $prefix.$code;
$d->user = '0';
$d->status = '0';
$d->generated_by = $admin['id'];
$d->save();
}
@ -447,7 +487,7 @@ switch ($action) {
run_hook('refill_customer'); #HOOK
if ($v1) {
if (Package::rechargeUser($user['id'], $v1['routers'], $v1['id_plan'], "Refill", "Voucher")) {
if (Package::rechargeUser($user['id'], $v1['routers'], $v1['id_plan'], "Voucher", $code)) {
$v1->status = "1";
$v1->user = $user['username'];
$v1->save();

View File

@ -173,6 +173,8 @@ switch ($action) {
Mikrotik::removeHotspotPlan($client, $d['name_plan']);
} catch (Exception $e) {
//ignore exception, it means router has already deleted
} catch(Throwable $e){
//ignore exception, it means router has already deleted
}
}
@ -199,6 +201,7 @@ switch ($action) {
$routers = _post('routers');
$pool_expired = _post('pool_expired');
$enabled = _post('enabled');
$allow_purchase = _post('allow_purchase');
$msg = '';
if (Validator::UnsignedNumber($validity) == false) {
@ -264,6 +267,7 @@ switch ($action) {
$d->pool_expired = $pool_expired;
}
$d->enabled = $enabled;
$d->allow_purchase = $allow_purchase;
$d->save();
$plan_id = $d->id();
@ -302,6 +306,7 @@ switch ($action) {
$validity_unit = _post('validity_unit');
$pool_expired = _post('pool_expired');
$enabled = _post('enabled');
$allow_purchase = _post('allow_purchase');
$routers = _post('routers');
$msg = '';
if (Validator::UnsignedNumber($validity) == false) {
@ -363,6 +368,7 @@ switch ($action) {
$d->shared_users = $sharedusers;
$d->pool_expired = $pool_expired;
$d->enabled = $enabled;
$d->allow_purchase = $allow_purchase;
$d->save();
r2(U . 'services/hotspot', 's', $_L['Updated_Successfully']);
@ -437,6 +443,8 @@ switch ($action) {
Mikrotik::removePpoePlan($client, $d['name_plan']);
} catch (Exception $e) {
//ignore exception, it means router has already deleted
} catch(Throwable $e){
//ignore exception, it means router has already deleted
}
}
$d->delete();
@ -456,6 +464,8 @@ switch ($action) {
$pool = _post('pool_name');
$pool_expired = _post('pool_expired');
$enabled = _post('enabled');
$allow_purchase = _post('allow_purchase');
$msg = '';
if (Validator::UnsignedNumber($validity) == false) {
@ -514,6 +524,7 @@ switch ($action) {
$d->pool_expired = $pool_expired;
}
$d->enabled = $enabled;
$d->allow_purchase = $allow_purchase;
$d->save();
$plan_id = $d->id();
@ -545,6 +556,7 @@ switch ($action) {
$pool = _post('pool_name');
$pool_expired = _post('pool_expired');
$enabled = _post('enabled');
$allow_purchase = _post('allow_purchase');
$msg = '';
if (Validator::UnsignedNumber($validity) == false) {
@ -602,6 +614,7 @@ switch ($action) {
$d->pool = $pool;
$d->pool_expired = $pool_expired;
$d->enabled = $enabled;
$d->allow_purchase = $allow_purchase;
$d->save();
r2(U . 'services/pppoe', 's', $_L['Updated_Successfully']);
@ -653,6 +666,7 @@ switch ($action) {
$name = _post('name');
$price = _post('price');
$enabled = _post('enabled');
$allow_purchase = _post('allow_purchase');
$msg = '';
if (Validator::UnsignedNumber($price) == false) {
@ -672,6 +686,7 @@ switch ($action) {
$d->name_plan = $name;
$d->price = $price;
$d->enabled = $enabled;
$d->allow_purchase = $allow_purchase;
$d->save();
r2(U . 'services/balance', 's', $_L['Updated_Successfully']);
@ -683,6 +698,7 @@ switch ($action) {
$name = _post('name');
$price = _post('price');
$enabled = _post('enabled');
$allow_purchase = _post('allow_purchase');
$msg = '';
if (Validator::UnsignedNumber($price) == false) {
@ -708,6 +724,7 @@ switch ($action) {
$d->routers = '';
$d->pool = '';
$d->enabled = $enabled;
$d->allow_purchase = $allow_purchase;
$d->save();
r2(U . 'services/balance', 's', $_L['Created_Successfully']);

View File

@ -17,6 +17,20 @@ switch ($action) {
if ($admin['user_type'] != 'Admin') {
r2(U . "dashboard", 'e', $_L['Do_Not_Access']);
}
if (!empty(_get('testWa'))) {
$result = Message::sendWhatsapp(_get('testWa'), 'PHPNuxBill Test Whatsapp');
r2(U . "settings/app", 's', 'Test Whatsapp has been send<br>Result: ' . $result);
}
if (!empty(_get('testSms'))) {
$result = Message::sendSMS(_get('testSms'), 'PHPNuxBill Test SMS');
r2(U . "settings/app", 's', 'Test SMS has been send<br>Result: ' . $result);
}
if (!empty(_get('testTg'))) {
$result = Message::sendTelegram('PHPNuxBill Test Telegram');
r2(U . "settings/app", 's', 'Test Telegram has been send<br>Result: ' . $result);
}
if (file_exists('system/uploads/logo.png')) {
$logo = 'system/uploads/logo.png?' . time();
} else {
@ -38,8 +52,14 @@ switch ($action) {
$themes[] = $file;
}
}
$php = trim(shell_exec('which php'));
if (empty($php)) {
$r = ORM::for_table('tbl_routers')->find_many();
$ui->assign('r', $r);
if (function_exists("shell_exec")) {
$php = trim(shell_exec('which php'));
if (empty($php)) {
$php = 'php';
}
} else {
$php = 'php';
}
$ui->assign('php', $php);
@ -237,27 +257,7 @@ switch ($action) {
break;
case 'app-post':
$company = _post('company');
$footer = _post('footer');
$enable_balance = _post('enable_balance');
$allow_balance_transfer = _post('allow_balance_transfer');
$disable_voucher = _post('disable_voucher');
$telegram_bot = _post('telegram_bot');
$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');
$address = _post('address');
$tawkto = _post('tawkto');
$http_proxy = _post('http_proxy');
$http_proxyauth = _post('http_proxyauth');
$radius_enable = _post('radius_enable');
$radius_client = _post('radius_client');
$theme = _post('theme');
$voucher_format = _post('voucher_format');
$company = _post('CompanyName');
run_hook('save_settings'); #HOOK
@ -273,210 +273,9 @@ switch ($action) {
if ($company == '') {
r2(U . 'settings/app', 'e', $_L['All_field_is_required']);
} else {
$d = ORM::for_table('tbl_appconfig')->where('setting', 'CompanyName')->find_one();
$d->value = $company;
$d->save();
$d = ORM::for_table('tbl_appconfig')->where('setting', 'address')->find_one();
$d->value = $address;
$d->save();
$phone = _post('phone');
$d = ORM::for_table('tbl_appconfig')->where('setting', 'phone')->find_one();
$d->value = $phone;
$d->save();
$d = ORM::for_table('tbl_appconfig')->where('setting', 'http_proxy')->find_one();
if ($d) {
$d->value = $http_proxy;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'http_proxy';
$d->value = $http_proxy;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'http_proxyauth')->find_one();
if ($d) {
$d->value = $http_proxyauth;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'http_proxyauth';
$d->value = $http_proxyauth;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'theme')->find_one();
if ($d) {
$d->value = $theme;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'theme';
$d->value = $theme;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'CompanyFooter')->find_one();
if ($d) {
$d->value = $footer;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'CompanyFooter';
$d->value = $footer;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'voucher_format')->find_one();
if ($d) {
$d->value = $voucher_format;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'voucher_format';
$d->value = $voucher_format;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'disable_voucher')->find_one();
if ($d) {
$d->value = $disable_voucher;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'disable_voucher';
$d->value = $disable_voucher;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'enable_balance')->find_one();
if ($d) {
$d->value = $enable_balance;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'enable_balance';
$d->value = $enable_balance;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'allow_balance_transfer')->find_one();
if ($d) {
$d->value = $allow_balance_transfer;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'allow_balance_transfer';
$d->value = $allow_balance_transfer;
$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;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'telegram_bot';
$d->value = $telegram_bot;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'telegram_target_id')->find_one();
if ($d) {
$d->value = $telegram_target_id;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'telegram_target_id';
$d->value = $telegram_target_id;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'sms_url')->find_one();
if ($d) {
$d->value = $sms_url;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'sms_url';
$d->value = $sms_url;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'wa_url')->find_one();
if ($d) {
$d->value = $wa_url;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'wa_url';
$d->value = $wa_url;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'user_notification_expired')->find_one();
if ($d) {
$d->value = $user_notification_expired;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'user_notification_expired';
$d->value = $user_notification_expired;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'user_notification_reminder')->find_one();
if ($d) {
$d->value = $user_notification_reminder;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'user_notification_reminder';
$d->value = $user_notification_reminder;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'user_notification_payment')->find_one();
if ($d) {
$d->value = $user_notification_payment;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'user_notification_payment';
$d->value = $user_notification_payment;
$d->save();
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'tawkto')->find_one();
if ($d) {
$d->value = $tawkto;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'tawkto';
$d->value = $tawkto;
$d->save();
}
if ($radius_enable) {
try {
Radius::getTableNas()->find_one(1);
Radius::getTableNas()->find_many();
} catch (Exception $e) {
$ui->assign("error_title", "RADIUS Error");
$ui->assign("error_message", "Radius table not found.<br><br>" .
@ -486,34 +285,37 @@ switch ($action) {
die();
}
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'radius_enable')->find_one();
if ($d) {
$d->value = $radius_enable;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'radius_enable';
$d->value = $radius_enable;
$d->save();
// save all settings
foreach ($_POST as $key => $value) {
$d = ORM::for_table('tbl_appconfig')->where('setting', $key)->find_one();
if ($d) {
$d->value = $value;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = $key;
$d->value = $value;
$d->save();
}
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'radius_client')->find_one();
if ($d) {
$d->value = $radius_client;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'radius_client';
$d->value = $radius_client;
$d->save();
//checkbox
$checks = ['hide_mrc','hide_tms','hide_aui','hide_al','hide_uet','hide_vs','hide_pg'];
foreach ($checks as $check) {
if(!isset($_POST[$check])){
$d = ORM::for_table('tbl_appconfig')->where('setting', $check)->find_one();
if ($d) {
$d->value = 'no';
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = $check;
$d->value = 'no';
$d->save();
}
}
}
$note = _post('note');
$d = ORM::for_table('tbl_appconfig')->where('setting', 'note')->find_one();
$d->value = $note;
$d->save();
_log('[' . $admin['username'] . ']: ' . $_L['Settings_Saved_Successfully'], 'Admin', $admin['id']);
r2(U . 'settings/app', 's', $_L['Settings_Saved_Successfully']);

View File

@ -11,8 +11,6 @@ $action = $routes['1'];
$user = User::_info();
$ui->assign('_user', $user);
use PEAR2\Net\RouterOS;
require_once 'system/autoload/PEAR2/Autoload.php';
switch ($action) {
@ -27,7 +25,7 @@ switch ($action) {
$v1 = ORM::for_table('tbl_voucher')->where('code', $code)->where('status', 0)->find_one();
run_hook('customer_activate_voucher'); #HOOK
if ($v1) {
if (Package::rechargeUser($user['id'], $v1['routers'], $v1['id_plan'], "Activation", "Voucher")) {
if (Package::rechargeUser($user['id'], $v1['routers'], $v1['id_plan'], "Voucher", $code)) {
$v1->status = "1";
$v1->user = $user['username'];
$v1->save();

View File

@ -35,16 +35,16 @@ if (php_sapi_name() !== 'cli') {
echo "<pre>";
}
if(!file_exists('../config.php')){
if (!file_exists('../config.php')) {
die("config.php file not found");
}
if(!file_exists('orm.php')){
if (!file_exists('orm.php')) {
die("orm.php file not found");
}
if(!file_exists('uploads/notifications.default.json')){
if (!file_exists('uploads/notifications.default.json')) {
die("uploads/notifications.default.json file not found");
}
@ -68,13 +68,20 @@ $_notifmsg_default = json_decode(file_get_contents('uploads/notifications.defaul
//register all plugin
foreach (glob(File::pathFixer("plugin/*.php")) as $filename) {
include $filename;
try{
include $filename;
} catch(Throwable $e){
//ignore plugin error
}catch(Exception $e){
//ignore plugin error
}
}
$result = ORM::for_table('tbl_appconfig')->find_many();
foreach ($result as $value) {
$config[$value['setting']] = $value['value'];
}
date_default_timezone_set($config['timezone']);
if (!empty($radius_user) && $config['radius_enable']) {
ORM::configure("mysql:host=$radius_host;dbname=$radius_name", null, 'radius');
@ -94,7 +101,6 @@ while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
$_c = $config;
date_default_timezone_set($config['timezone']);
$textExpired = Lang::getNotifText('expired');
@ -111,9 +117,9 @@ foreach ($d as $ds) {
echo " : EXPIRED \r\n";
$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();
$m = ORM::for_table('tbl_routers')->where('name', $ds['routers'])->find_one();
$m = Mikrotik::info($ds['routers']);
$p = ORM::for_table('tbl_plans')->where('id', $u['plan_id'])->find_one();
$price = Lang::moneyFormat($p['price']);
if ($p['is_radius']) {
if (empty($p['pool_expired'])) {
print_r(Radius::customerDeactivate($c['username']));
@ -130,14 +136,14 @@ foreach ($d as $ds) {
}
Mikrotik::removeHotspotActiveUser($client, $c['username']);
}
Message::sendPackageNotification($c['phonenumber'], $c['fullname'], $u['namebp'], $textExpired, $config['user_notification_expired']);
echo Message::sendPackageNotification($c['phonenumber'], $c['fullname'], $u['namebp'], $price, $textExpired, $config['user_notification_expired'])."\n";
//update database user dengan status off
$u->status = 'off';
$u->save();
// autorenewal from deposit
if ($config['enable_balance'] == 'yes' && $c['auto_renewal']) {
if ($p && $p['enabled'] && $c['balance'] >= $p['price']) {
if ($p && $p['enabled'] && $c['balance'] >= $p['price'] && $p['allow_purchase'] == 'yes') {
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']);
@ -147,7 +153,7 @@ foreach ($d as $ds) {
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 .
"\nRouter: " . $p['routers'] .
"\nPrice: " . $p['price']);
}
} else {
@ -156,7 +162,8 @@ foreach ($d as $ds) {
} else {
echo "no renewall | balance $config[enable_balance] auto_renewal $c[auto_renewal]\n";
}
} else echo " : ACTIVE \r\n";
} else
echo " : ACTIVE \r\n";
} else {
$date_now = strtotime(date("Y-m-d H:i:s"));
$expiration = strtotime($ds['expiration'] . ' ' . $ds['time']);
@ -167,7 +174,7 @@ foreach ($d as $ds) {
$c = ORM::for_table('tbl_customers')->where('id', $ds['customer_id'])->find_one();
$m = ORM::for_table('tbl_routers')->where('name', $ds['routers'])->find_one();
$p = ORM::for_table('tbl_plans')->where('id', $u['plan_id'])->find_one();
$price = Lang::moneyFormat($p['price']);
if ($p['is_radius']) {
if (empty($p['pool_expired'])) {
print_r(Radius::customerDeactivate($c['username']));
@ -184,14 +191,14 @@ foreach ($d as $ds) {
}
Mikrotik::removePpoeActive($client, $c['username']);
}
Message::sendPackageNotification($c['phonenumber'], $c['fullname'], $u['namebp'], $textExpired, $config['user_notification_expired']);
echo Message::sendPackageNotification($c['phonenumber'], $c['fullname'], $u['namebp'], $price, $textExpired, $config['user_notification_expired'])."\n";
$u->status = 'off';
$u->save();
// autorenewal from deposit
if ($config['enable_balance'] == 'yes' && $c['auto_renewal']) {
if ($p && $p['enabled'] && $c['balance'] >= $p['price']) {
if ($p && $p['enabled'] && $c['balance'] >= $p['price'] && $p['allow_purchase'] == 'yes') {
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']);
@ -201,11 +208,12 @@ foreach ($d as $ds) {
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 #PPPOE \n" . $p['name_plan'] .
"\nRouter: " . $router_name .
"\nRouter: " . $p['routers'] .
"\nPrice: " . $p['price']);
}
}
}
} else echo " : ACTIVE \r\n";
} else
echo " : ACTIVE \r\n";
}
}

View File

@ -67,7 +67,13 @@ $_notifmsg_default = json_decode(file_get_contents('uploads/notifications.defaul
//register all plugin
foreach (glob(File::pathFixer("plugin/*.php")) as $filename) {
include $filename;
try{
include $filename;
} catch(Throwable $e){
//ignore plugin error
}catch(Exception $e){
//ignore plugin error
}
}
$result = ORM::for_table('tbl_appconfig')->find_many();
@ -98,13 +104,15 @@ print_r([$day1, $day3, $day7]);
foreach ($d as $ds) {
if (in_array($ds['expiration'], [$day1, $day3, $day7])) {
$u = ORM::for_table('tbl_user_recharges')->where('id', $ds['id'])->find_one();
$p = ORM::for_table('tbl_plans')->where('id', $u['plan_id'])->find_one();
$c = ORM::for_table('tbl_customers')->where('id', $ds['customer_id'])->find_one();
$price = Lang::moneyFormat($p['price']);
if ($ds['expiration'] == $day7) {
echo Message::sendPackageNotification($c['phonenumber'], $c['fullname'], $u['namebp'], Lang::getNotifText('reminder_7_day'), $config['user_notification_reminder']) . "\n";
echo Message::sendPackageNotification($c['phonenumber'], $c['fullname'], $p['name_plan'], $price, 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";
echo Message::sendPackageNotification($c['phonenumber'], $c['fullname'], $p['name_plan'], $price, 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";
echo Message::sendPackageNotification($c['phonenumber'], $c['fullname'], $p['name_plan'], $price, Lang::getNotifText('reminder_1_day'), $config['user_notification_reminder']) . "\n";
}
}
}

View File

@ -3,8 +3,6 @@
-----------------------------------
Language Name: English
Contributor: Ismail Marzuqi
Web: www.phpnuxbill.com
Email: iesien22@yahoo.com
2017
Contributor: Ibnu Maksum (@ibnux)
@ -261,7 +259,6 @@ $_L['Plan_Not_found'] = 'Plan Not found';
$_L['Failed_to_create_transaction'] = 'Failed to create transaction.';
$_L['Seller_has_not_yet_setup_Xendit_payment_gateway'] = 'Seller has not yet setup Xendit payment gateway';
$_L['Admin_has_not_yet_setup_Xendit_payment_gateway_please_tell_admin'] = 'Admin has not yet setup Xendit payment gateway, please tell admin';
$_L['Buy_this_your_active_package_will_be_overwrite'] = 'Buy this? your active package will be overwrite';
$_L['You_already_have_unpaid_transaction_cancel_it_or_pay_it'] = 'You already have unpaid transaction, cancel it or pay it.';
$_L['Transaction_Not_found'] = 'Transaction Not found';
$_L['Cancel_it'] = 'Cancel it?';
@ -314,7 +311,6 @@ $_L['User_Notification'] = 'User Notification';
$_L['Expired_Notification'] = 'Expired Notification';
$_L['User_will_get_notification_when_package_expired'] = 'User will get notification when package expired';
$_L['Expired_Notification_Message'] = 'Expired Notification Message';
$_L['bnameb_will_be_replaced_with_Customer_Name_bpackageb_will_be_replaced_with_Package_name'] = '<b>[[name]]</b> will be replaced with Customer Name. <b>[[package]]</b> will be replaced with Package name.';
$_L['Payment_Notification'] = 'Payment Notification';
$_L['User_will_get_invoice_notification_when_buy_package_or_package_refilled'] = 'User will get invoice notification when buy package or package refilled';
$_L['Current_IP'] = 'Current IP';
@ -408,4 +404,27 @@ $_L['Change_title_in_user_Plan_order'] = 'Change title in user Plan order';
$_L['Logs'] = 'Logs';
$_L['Voucher_Format'] = 'Voucher Format';
$_L['Resend_To_Customer'] = 'Resend To Customer';
$_L['Your_friend_do_not_have_active_package'] = 'Your friend do not have active package';
$_L['Your_friend_do_not_have_active_package'] = 'Your friend do not have active package';
$_L['Service_Type'] = 'Service Type';
$_L['Others'] = 'Others';
$_L['PPPoE'] = 'PPPoE';
$_L['Hotspot'] = 'Hotspot';
$_L['Disable_Registration'] = 'Disable Registration';
$_L['Customer_just_Login_with_Phone_number_and_Voucher_Code_Voucher_will_be_password'] = 'Customer just Login with Phone number and Voucher Code, Voucher will be password';
$_L['Login__Activate_Voucher'] = 'Login / Activate Voucher';
$_L['After_Customer_activate_voucher_or_login_customer_will_be_redirected_to_this_url'] = 'After Customer activate voucher or login, customer will be redirected to this url';
$_L['Voucher_Prefix'] = 'Voucher Prefix';
$_L['Voucher_activation_success_now_you_can_login'] = 'Voucher activation success, now you can login';
$_L['Client_Can_Purchase'] = 'Client Can Purchase';
$_L['Buy_this_your_active_package_will_be_overwritten'] = 'Buy this? your active package will be overwritten';
$_L['Pay_this_with_Balance_your_active_package_will_be_overwritten'] = 'Pay this with Balance? your active package will be overwritten';
$_L['Buy_this_your_active_package_will_be_overwrite'] = 'Buy this? your active package will be overwrite';
$_L['Buy_this_your_active_package_will_be_overwrite'] = 'Buy this? your active package will be overwrite';
$_L['Buy_this_your_active_package_will_be_overwrite'] = 'Buy this? your active package will be overwrite';
$_L['Buy_this_your_active_package_will_be_overwrite'] = 'Buy this? your active package will be overwrite';
$_L['Buy_this_your_active_package_will_be_overwrite'] = 'Buy this? your active package will be overwrite';
$_L['Buy_this_your_active_package_will_be_overwrite'] = 'Buy this? your active package will be overwrite';
$_L['Monthly_Registered_Customers'] = 'Monthly Registered Customers';
$_L['Total_Monthly_Sales'] = 'Total Monthly Sales';
$_L['Active_Users'] = 'Active Users';
$_L['All_Users_Insights'] = 'All Users Insights';

View File

@ -3,9 +3,6 @@
-----------------------------------
Language Name: Indonesia
Contributor: Ismail Marzuqi
Web: www.phpnuxbill.com
Email: iesien22@yahoo.com
2017
Contributor: Ibnu Maksum (@ibnux)
@ -408,3 +405,10 @@ $_L['Change_title_in_user_Plan_order'] = 'Ubah judul dalam urutan paket pelangga
$_L['Logs'] = 'Log';
$_L['Voucher_Format'] = 'Format Voucher';
$_L['Resend_To_Customer'] = 'Kirim Ulang Ke Pelanggan';
$_L['Service_Type'] = 'Service Type';
$_L['Others'] = 'Lainnya';
$_L['PPPoE'] = 'PPPoE';
$_L['Hotspot'] = 'Hotspot';
$_L['Monthly_Registered_Customers'] = 'Pendaftaran Pelanggan perbulan';
$_L['Total_Monthly_Sales'] = 'Total penjualan Perbulan';
$_L['Active_Users'] = 'Pelanggan Aktif';

View File

@ -401,4 +401,11 @@ $_L['Deactivate'] = 'Deactivate';
$_L['Sync'] = 'Sync';
$_L['Failed_to_create_PaymeTrust_transaction'] = 'Failed to create PaymeTrust transaction.';
$_L['Location'] = 'Location';
$_L['Voucher_Format'] = 'Voucher Format';
$_L['Voucher_Format'] = 'Voucher Format';
$_L['Service_Type'] = 'Service Type';
$_L['Others'] = 'Others';
$_L['PPPoE'] = 'PPPoE';
$_L['Hotspot'] = 'Hotspot';
$_L['Monthly_Registered_Customers'] = 'Monthly Registered Customers';
$_L['Total_Monthly_Sales'] = 'Total Monthly Sales';
$_L['Active_Users'] = 'Active Users';

View File

@ -378,4 +378,11 @@ $_L['Deactivate'] = 'Deactivate';
$_L['Sync'] = 'Sync';
$_L['Failed_to_create_PaymeTrust_transaction'] = 'Failed to create PaymeTrust transaction.';
$_L['Location'] = 'Location';
$_L['Voucher_Format'] = 'Voucher Format';
$_L['Voucher_Format'] = 'Voucher Format';
$_L['Service_Type'] = 'Service Type';
$_L['Others'] = 'Others';
$_L['PPPoE'] = 'PPPoE';
$_L['Hotspot'] = 'Hotspot';
$_L['Monthly_Registered_Customers'] = 'Monthly Registered Customers';
$_L['Total_Monthly_Sales'] = 'Total Monthly Sales';
$_L['Active_Users'] = 'Active Users';

View File

@ -35,5 +35,15 @@
],
"2023.10.24" : [
"ALTER TABLE `nas` ADD `routers` VARCHAR(32) NOT NULL DEFAULT '' AFTER `description`;"
],
"2023.12.15": [
"ALTER TABLE `tbl_customers` ADD `service_type` ENUM('Hotspot','PPPoE','Others') DEFAULT 'Others' COMMENT 'For selecting user type' AFTER `balance`;"
],
"2024.1.11": [
"ALTER TABLE `tbl_plans` ADD `allow_purchase` ENUM('yes','no') DEFAULT 'yes' COMMENT 'allow to show package in buy package page' AFTER `enabled`;"
],
"2024.2.7": [
"ALTER TABLE `tbl_voucher` ADD `generated_by` INT NOT NULL DEFAULT '0' COMMENT 'id admin' AFTER `status`;",
"ALTER TABLE `tbl_users` ADD `root` INT NOT NULL DEFAULT '0' COMMENT 'for sub account' AFTER `id`;"
]
}

View File

@ -7,10 +7,9 @@
<title>{$_title} - {$_L['Login']}</title>
<link rel="shortcut icon" href="ui/ui/images/logo.png" type="image/x-icon" />
<!-- Css/Less Stylesheets -->
<link rel="stylesheet" href="ui/ui/styles/bootstrap.min.css">
<link rel="stylesheet" href="ui/ui/styles/adminlte.min.css">
<link rel="stylesheet" href="ui/ui/styles/modern-AdminLTE.min.css">
</head>
@ -37,9 +36,6 @@
</form>
</div>
</div>
<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>
</body>
</html>

View File

@ -21,7 +21,7 @@
rows="3">{if $_json['expired']!=''}{Lang::htmlspecialchars($_json['expired'])}{else}Hello [[name]], your internet package [[package]] has been expired.{/if}</textarea>
</div>
<p class="help-block col-md-4">
{Lang::T('<b>[[name]]</b> will be replaced with Customer Name. <b>[[package]]</b> will be replaced with Package name.')}
<b>[[name]]</b> will be replaced with Customer Name. <b>[[package]]</b> will be replaced with Package name. <b>[[price]]</b> will be replaced with Package price.
</p>
</div>
</div>
@ -33,7 +33,7 @@
rows="3">{Lang::htmlspecialchars($_json['reminder_7_day'])}</textarea>
</div>
<p class="help-block col-md-4">
{Lang::T('<b>[[name]]</b> will be replaced with Customer Name. <b>[[package]]</b> will be replaced with Package name.')}
<b>[[name]]</b> will be replaced with Customer Name. <b>[[package]]</b> will be replaced with Package name. <b>[[price]]</b> will be replaced with Package price.
</p>
</div>
</div>
@ -45,7 +45,7 @@
rows="3">{Lang::htmlspecialchars($_json['reminder_3_day'])}</textarea>
</div>
<p class="help-block col-md-4">
{Lang::T('<b>[[name]]</b> will be replaced with Customer Name. <b>[[package]]</b> will be replaced with Package name.')}
<b>[[name]]</b> will be replaced with Customer Name. <b>[[package]]</b> will be replaced with Package name. <b>[[price]]</b> will be replaced with Package price.
</p>
</div>
</div>
@ -57,7 +57,7 @@
rows="3">{Lang::htmlspecialchars($_json['reminder_1_day'])}</textarea>
</div>
<p class="help-block col-md-4">
{Lang::T('<b>[[name]]</b> will be replaced with Customer Name. <b>[[package]]</b> will be replaced with Package name.')}
<b>[[name]]</b> will be replaced with Customer Name. <b>[[package]]</b> will be replaced with Package name. <b>[[price]]</b> will be replaced with Package price.
</p>
</div>
</div>

View File

@ -15,7 +15,7 @@
<div class="form-group">
<label class="col-md-2 control-label">{$_L['App_Name']}</label>
<div class="col-md-6">
<input type="text" required class="form-control" id="company" name="company"
<input type="text" required class="form-control" id="CompanyName" name="CompanyName"
value="{$_c['CompanyName']}">
</div>
<span class="help-block col-md-4">{$_L['App_Name_Help_Text']}</span>
@ -34,7 +34,7 @@
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Company Footer')}</label>
<div class="col-md-6">
<input type="text" required class="form-control" id="footer" name="footer"
<input type="text" required class="form-control" id="CompanyFooter" name="CompanyFooter"
value="{$_c['CompanyFooter']}">
</div>
<span class="help-block col-md-4">{Lang::T('Will show below user pages')}</span>
@ -53,6 +53,15 @@
<input type="text" class="form-control" id="phone" name="phone" value="{$_c['phone']}">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label"><i class="glyphicon glyphicon-print"></i> Print Max
Char</label>
<div class="col-md-6">
<input type="number" required class="form-control" id="printer_cols" placeholder="37"
name="printer_cols" value="{$_c['printer_cols']}">
</div>
<span class="help-block col-md-4">For invoice print using Thermal Printer</span>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Theme</label>
<div class="col-md-6">
@ -77,6 +86,24 @@
<p class="help-block col-md-4">edit at config.php</p>
</div>
</div>
<div class="panel-heading">
<div class="btn-group pull-right">
<button class="btn btn-primary btn-xs" title="save" type="submit"><span
class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span></button>
</div>
Hide Dashboard Content
</div>
<div class="panel-body">
<div class="form-group">
<label class="col-md-3 control-label"><input type="checkbox" name="hide_mrc" value="yes" {if $_c['hide_mrc'] eq 'yes'}checked{/if}> {Lang::T('Monthly Registered Customers')}</label>
<label class="col-md-2 control-label"><input type="checkbox" name="hide_tms" value="yes" {if $_c['hide_tms'] eq 'yes'}checked{/if}> {Lang::T('Total Monthly Sales')}</label>
<label class="col-md-2 control-label"><input type="checkbox" name="hide_aui" value="yes" {if $_c['hide_aui'] eq 'yes'}checked{/if}> {Lang::T('All Users Insights')}</label>
<label class="col-md-2 control-label"><input type="checkbox" name="hide_al" value="yes" {if $_c['hide_al'] eq 'yes'}checked{/if}> {$_L['Activity_Log']}</label>
<label class="col-md-2 control-label"><input type="checkbox" name="hide_uet" value="yes" {if $_c['hide_uet'] eq 'yes'}checked{/if}> {$_L['User_Expired_Today']}</label>
<label class="col-md-2 control-label"><input type="checkbox" name="hide_vs" value="yes" {if $_c['hide_vs'] eq 'yes'}checked{/if}> Vouchers Stock</label>
<label class="col-md-2 control-label"><input type="checkbox" name="hide_pg" value="yes" {if $_c['hide_pg'] eq 'yes'}checked{/if}> Payment Gateway</label>
</div>
</div>
<div class="panel-heading">
<div class="btn-group pull-right">
<button class="btn btn-primary btn-xs" title="save" type="submit"><span
@ -113,6 +140,33 @@
</div>
<p class="help-block col-md-4">UPPERCASE lowercase RaNdoM</p>
</div>
{if $_c['disable_voucher'] != 'yes'}
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Disable Registration')}</label>
<div class="col-md-6">
<select name="disable_registration" id="disable_registration" class="form-control">
<option value="no" {if $_c['disable_registration'] == 'no'}selected="selected" {/if}>No
</option>
<option value="yes" {if $_c['disable_registration'] == 'yes'}selected="selected" {/if}>
Yes
</option>
</select>
</div>
<p class="help-block col-md-4">
{Lang::T('Customer just Login with Phone number and Voucher Code, Voucher will be password')}
</p>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Redirect after Activation</label>
<div class="col-md-6">
<input type="text" class="form-control" id="voucher_redirect" name="voucher_redirect"
placeholder="https://192.168.88.1/status" value="{$voucher_redirect}">
</div>
<p class="help-block col-md-4">
{Lang::T('After Customer activate voucher or login, customer will be redirected to this url')}
</p>
</div>
{/if}
</div>
<div class="panel-heading">
<div class="btn-group pull-right">
@ -183,6 +237,7 @@
</div>
<div class="panel-heading">
<div class="btn-group pull-right">
<a class="btn btn-success btn-xs" style="color: black;" href="javascript:testTg()">Test TG</a>
<button class="btn btn-primary btn-xs" title="save" type="submit"><span
class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span></button>
</div>
@ -198,7 +253,7 @@
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Telegram Target ID</label>
<label class="col-md-2 control-label">Telegram User/Channel/Group ID</label>
<div class="col-md-6">
<input type="text" class="form-control" id="telegram_target_id" name="telegram_target_id"
value="{$_c['telegram_target_id']}" placeholder="12345678">
@ -209,6 +264,7 @@
</div>
<div class="panel-heading">
<div class="btn-group pull-right">
<a class="btn btn-success btn-xs" style="color: black;" href="javascript:testSms()">Test SMS</a>
<button class="btn btn-primary btn-xs" title="save" type="submit"><span
class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span></button>
</div>
@ -225,11 +281,28 @@
replaced.
</p>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Or use Mikrotik SMS</label>
<div class="col-md-6">
<select class="form-control"
onchange="document.getElementById('sms_url').value = this.value">
<option value="">Select Router</option>
{foreach $r as $rs}
<option value="{$rs['name']}" {if $rs['name']==$_c['sms_url']}selected{/if}>
{$rs['name']}</option>
{/foreach}
</select>
</div>
<p class="help-block col-md-4">Must include <b>[text]</b> &amp; <b>[number]</b>, it will be
replaced.
</p>
</div>
<small id="emailHelp" class="form-text text-muted">You can use WhatsApp in here too. <a
href="https://wa.nux.my.id/login" target="_blank">Free Server</a></small>
</div>
<div class="panel-heading">
<div class="btn-group pull-right">
<a class="btn btn-success btn-xs" style="color: black;" href="javascript:testWa()">Test WA</a>
<button class="btn btn-primary btn-xs" title="save" type="submit"><span
class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span></button>
</div>
@ -362,6 +435,34 @@
</div>
</div>
</div>
{* <div class="panel-heading" id="envato">
<div class="btn-group pull-right">
<button class="btn btn-primary btn-xs" title="save" type="submit"><span
class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span></button>
</div>
Envato / Codecanyon
</div>
<div class="panel-body">
<div class="form-group">
<label class="col-md-2 control-label">Envato Personal Token</label>
<div class="col-md-6">
<input type="password" class="form-control" id="envato_token" name="envato_token"
value="{$_c['envato_token']}" placeholder="BldWuBsxxxxxxxxxxxPDzPozHAPui">
</div>
<span class="help-block col-md-4"><a href="https://build.envato.com/create-token/"
target="_blank">Create Token</a></span>
</div>
<div class="form-group">
<label class="control-label col-md-offset-2 col-md-8" style="text-align: left;">Envato
Permission<br>
- View and search Envato sites<br>
- Download the user's purchased items<br>
- List purchases the user has made<br><br>
<a href="https://codecanyon.net/category/php-scripts?term=phpnuxbill" target="_blank"
class="btn btn-xs btn-primary">View MarketPlace</a>
</label>
</div>
</div> *}
</div>
<div class="panel-body">
@ -389,4 +490,23 @@ add dst-host=*.{$_domain}</pre>
</div>
</div>
</form>
<script>
function testWa() {
var target = prompt("Phone number\nSave First before Test", "");
if (target != null) {
window.location.href = '{$_url}settings/app&testWa='+target;
}
}
function testSms() {
var target = prompt("Phone number\nSave First before Test", "");
if (target != null) {
window.location.href = '{$_url}settings/app&testSms='+target;
}
}
function testTg() {
window.location.href = '{$_url}settings/app&testTg=test';
}
</script>
{include file="sections/footer.tpl"}

View File

@ -17,6 +17,17 @@
</label>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Client Can Purchase')}</label>
<div class="col-md-10">
<label class="radio-inline warning">
<input type="radio" checked name="allow_purchase" value="yes"> Yes
</label>
<label class="radio-inline">
<input type="radio" name="allow_purchase" value="no"> No
</label>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{$_L['Plan_Name']}</label>
<div class="col-md-6">

View File

@ -18,6 +18,18 @@
</label>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Client Can Purchase')}</label>
<div class="col-md-10">
<label class="radio-inline warning">
<input type="radio" {if $d['allow_purchase'] == yes}checked{/if} name="allow_purchase" value="yes"> Yes
</label>
<label class="radio-inline">
<input type="radio" {if $d['allow_purchase'] == no}checked{/if} name="allow_purchase" value="no">
No
</label>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{$_L['Plan_Name']}</label>
<div class="col-md-6">

54
ui/ui/codecanyon.tpl Normal file
View File

@ -0,0 +1,54 @@
{include file="sections/header.tpl"}
<div class="row">
<div class="col-sm-12">
<div class="panel panel-primary panel-hovered">
<div class="panel-heading">
<div class="btn-group pull-right">
<a class="btn btn-danger btn-xs" href="https://codecanyon.net/category/php-scripts?term=phpnuxbill"
target="_blank">Buy Plugin</a>
</div>
Plugin Purcashed
</div>
<div class="panel-body row">
{if Lang::arrayCount($plugins) > 0}
{foreach $plugins as $plugin}
<div class="col-md-4">
<div class="box box-hovered mb20 box-primary">
<div class="box-header">
<h3 class="box-title text1line">{$plugin['item']['name']}</h3>
</div>
<div class="box-body"><small><i>@{$plugin['item']['author_username']} &bull; Last update:
{Lang::dateFormat($plugin['item']['updated_at'])}</i></small></div>
<div class="box-footer ">
<div class="btn-group btn-group-justified" role="group" aria-label="...">
<a href="{$plugin['item']['author_url']}" target="_blank" class="btn btn-primary"><i
class="ion ion-chatboxes"></i> Author</a>
<a href="{$plugin['item']['url']}" target="_blank" class="btn btn-success"><i
class="ion ion-chatboxes"></i> Product</a>
<a {if $zipExt } href="{$_url}codecanyon/install/{$plugin['item']['id']}"
onclick="return confirm('Installing plugin will take some time to complete, do not close the page while it loading to install the plugin')"
{else} href="#" onclick="alert('PHP ZIP extension is not installed')"
{/if}
class="btn btn-danger"><i class="ion ion-chatboxes"></i> Install</a>
</div>
</div>
</div>
</div>
{/foreach}
{else}
<div class="col-md-12">
<div class="alert alert-info">
<i class="fa fa-info-circle"></i> No plugins purcashed yet.
</div>
</div>
{/if}
</div>
<div class="panel-footer">
{if $chached_until}Cached Until {$chached_until} <a href="{$_url}codecanyon/reload">Force reload</a>
&bull; {/if}<a
href="https://github.com/hotspotbilling/phpnuxbill/wiki/Selling-Paid-Plugin-or-Payment-Gateway"
target="_blank"> Sell your own plugin/paymentgateway/theme?</a>
</div>
</div>
</div>
{include file="sections/footer.tpl"}

View File

@ -1,5 +1,8 @@
{include file="sections/header.tpl"}
<center><a href="https://s.id/standwithpalestine" target="_blank"><img src="https://raw.githubusercontent.com/Safouene1/support-palestine-banner/master/banner-support.svg" class="img-responsive"></a></center>
<br><br>
<div class="row">
<div class="col-sm-6">
<div class="box box-hovered mb20 box-primary">
@ -101,7 +104,12 @@
</table>
</div>
<div class="box-footer">
<a href="https://paypal.me/ibnux" target="_blank" class="btn btn-primary btn-sm btn-block">Paypal</a>
<div class="btn-group btn-group-justified" role="group" aria-label="...">
<a href="https://paypal.me/ibnux" target="_blank"
class="btn btn-primary btn-sm btn-block">Paypal</a>
<a href="https://wise.com/pay/me/ibnum37" target="_blank"
class="btn btn-primary btn-sm btn-block">Wise</a>
</div>
</div>
</div>
</div>

View File

@ -72,6 +72,16 @@
<textarea name="address" id="address" class="form-control"></textarea>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Service Type')}</label>
<div class="col-md-6">
<select class="form-control" id="service_type" name="service_type">
<option value="Hotspot" {if $d['service_type'] eq 'Hotspot'}selected{/if}>Hotspot</option>
<option value="PPPoE" {if $d['service_type'] eq 'PPPoE'}selected{/if}>PPPoE</option>
<option value="Others" {if $d['service_type'] eq 'Others'}selected{/if}>Others</option>
</select>
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">

View File

@ -77,6 +77,16 @@
<textarea name="address" id="address" class="form-control">{$d['address']}</textarea>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Service Type')}</label>
<div class="col-md-6">
<select class="form-control" id="service_type" name="service_type">
<option value="Hotspot" {if $d['service_type'] eq 'Hotspot'}selected{/if}>Hotspot</option>
<option value="PPPoE" {if $d['service_type'] eq 'PPPoE'}selected{/if}>PPPoE</option>
<option value="Others" {if $d['service_type'] eq 'Others'}selected{/if}>Others</option>
</select>
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">

View File

@ -37,6 +37,9 @@
onclick="this.select()">
</li>
{/if}
<li class="list-group-item">
<b>{Lang::T('Service Type')}</b> <span class="pull-right">{Lang::T($d['service_type'])}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Balance')}</b> <span class="pull-right">{Lang::moneyFormat($d['balance'])}</span>
</li>

View File

@ -33,6 +33,7 @@
<th>{$_L['Phone_Number']}</th>
<th>{$_L['Email']}</th>
<th>{$_L['Package']}</th>
<th>{Lang::T('Service Type')}</th>
<th>{$_L['Created_On']}</th>
<th>{$_L['Manage']}</th>
</tr>
@ -48,6 +49,7 @@
<td align="center" api-get-text="{$_url}autoload/customer_is_active/{$ds['id']}">
<span class="label label-default">&bull;</span>
</td>
<td>{$ds['service_type']}</td>
<td>{Lang::dateTimeFormat($ds['created_at'])}</td>
<td align="center">
<a href="{$_url}customers/view/{$ds['id']}" id="{$ds['id']}" style="margin: 0px;"

View File

@ -1,5 +1,6 @@
{include file="sections/header.tpl"}
<div class="row">
<div class="col-lg-3 col-xs-6">
<div class="small-box bg-aqua">
@ -59,97 +60,322 @@
</div>
</div>
</div>
<!-- solid sales graph -->
{if $_c['hide_mrc'] != 'yes'}
<div class="box box-solid ">
<div class="box-header">
<i class="fa fa-th"></i>
<h3 class="box-title">{Lang::T('Monthly Registered Customers')}</h3>
<div class="box-tools pull-right">
<button type="button" class="btn bg-teal btn-sm" data-widget="collapse"><i class="fa fa-minus"></i>
</button>
<button type="button" class="btn bg-teal btn-sm" data-widget="remove"><i class="fa fa-times"></i>
</button>
</div>
</div>
<div class="box-body border-radius-none">
<canvas class="chart" id="chart" style="height: 250px;"></canvas>
</div>
</div>
{/if}
<!-- solid sales graph -->
{if $_c['hide_tms'] != 'yes'}
<div class="box box-solid ">
<div class="box-header">
<i class="fa fa-inbox"></i>
<h3 class="box-title">{Lang::T('Total Monthly Sales')}</h3>
<div class="box-tools pull-right">
<button type="button" class="btn bg-teal btn-sm" data-widget="collapse"><i class="fa fa-minus"></i>
</button>
<button type="button" class="btn bg-teal btn-sm" data-widget="remove"><i class="fa fa-times"></i>
</button>
</div>
</div>
<div class="box-body border-radius-none">
<canvas class="chart" id="salesChart" style="height: 250px;"></canvas>
</div>
</div>
{/if}
<div class="row">
<div class="col-md-7">
{if $_c['disable_voucher'] != 'yes' && $stocks['unused']>0 || $stocks['used']>0}
<div class="panel panel-primary mb20 panel-hovered project-stats table-responsive">
<div class="panel-heading">Vouchers Stock</div>
{if $_c['hide_vs'] != 'yes'}
<div class="panel panel-primary mb20 panel-hovered project-stats table-responsive">
<div class="panel-heading">Vouchers Stock</div>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>{$_L['Plan_Name']}</th>
<th>unused</th>
<th>used</th>
</tr>
</thead>
<tbody>
{foreach $plans as $stok}
<tr>
<td>{$stok['name_plan']}</td>
<td>{$stok['unused']}</td>
<td>{$stok['used']}</td>
</tr>
</tbody>
{/foreach}
<tr>
<td>Total</td>
<td>{$stocks['unused']}</td>
<td>{$stocks['used']}</td>
</tr>
</table>
</div>
</div>
{/if}
{/if}
{if $_c['hide_uet'] != 'yes'}
<div class="panel panel-warning mb20 panel-hovered project-stats table-responsive">
<div class="panel-heading">{$_L['User_Expired_Today']}</div>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>{$_L['Plan_Name']}</th>
<th>unused</th>
<th>used</th>
<th>Id</th>
<th>{$_L['Username']}</th>
<th>{$_L['Created_On']}</th>
<th>{$_L['Expires_On']}</th>
</tr>
</thead>
<tbody>
{foreach $plans as $stok}
{$no = 1}
{foreach $expire as $expired}
<tr>
<td>{$stok['name_plan']}</td>
<td>{$stok['unused']}</td>
<td>{$stok['used']}</td>
<td>{$no++}</td>
<td><a href="{$_url}customers/viewu/{$expired['username']}">{$expired['username']}</a></td>
<td>{Lang::dateAndTimeFormat($expired['recharged_on'],$expired['recharged_time'])}
</td>
<td>{Lang::dateAndTimeFormat($expired['expiration'],$expired['time'])}
</td>
</tr>
</tbody>
{/foreach}
<tr>
<td>Total</td>
<td>{$stocks['unused']}</td>
<td>{$stocks['used']}</td>
</tr>
</table>
</div>
&nbsp; {$paginator['contents']}
</div>
{/if}
</div>
<div class="col-md-5">
{if $_c['hide_pg'] != 'yes'}
<div class="panel panel-success panel-hovered mb20 activities">
<div class="panel-heading">{Lang::T('Payment Gateway')}: {$_c['payment_gateway']}</div>
</div>
{/if}
{if $_c['hide_aui'] != 'yes'}
<div class="panel panel-info panel-hovered mb20 activities">
<div class="panel-heading">{Lang::T('All Users Insights')}</div>
<div class="panel-body">
<canvas id="userRechargesChart"></canvas>
</div>
</div>
{/if}
<div class="panel panel-warning mb20 panel-hovered project-stats table-responsive">
<div class="panel-heading">{$_L['User_Expired_Today']}</div>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>Id</th>
<th>{$_L['Username']}</th>
<th>{$_L['Created_On']}</th>
<th>{$_L['Expires_On']}</th>
</tr>
</thead>
<tbody>
{$no = 1}
{foreach $expire as $expired}
<tr>
<td>{$no++}</td>
<td><a href="{$_url}customers/viewu/{$expired['username']}">{$expired['username']}</a></td>
<td>{Lang::dateAndTimeFormat($expired['recharged_on'],$expired['recharged_time'])}
</td>
<td>{Lang::dateAndTimeFormat($expired['expiration'],$expired['time'])}
</td>
</tr>
</tbody>
{/foreach}
</table>
{if $_c['hide_al'] != 'yes'}
<div class="panel panel-info panel-hovered mb20 activities">
<div class="panel-heading"><a href="{$_url}logs">{$_L['Activity_Log']}</a></div>
<div class="panel-body">
<ul class="list-unstyled">
{foreach $dlog as $dlogs}
<li class="primary">
<span class="point"></span>
<span class="time small text-muted">{time_elapsed_string($dlogs['date'],true)}</span>
<p>{$dlogs['description']}</p>
</li>
{/foreach}
</ul>
</div>
</div>
</div>
{/if}
</div>
<div class="col-md-5">
<div class="panel panel-success panel-hovered mb20 activities">
<div class="panel-heading">{Lang::T('Payment Gateway')}: {$_c['payment_gateway']}</div>
</div>
<div class="panel panel-info panel-hovered mb20 activities">
<div class="panel-heading"><a href="{$_url}logs">{$_L['Activity_Log']}</a></div>
<div class="panel-body">
<ul class="list-unstyled">
{foreach $dlog as $dlogs}
<li class="primary">
<span class="point"></span>
<span class="time small text-muted">{time_elapsed_string($dlogs['date'],true)}</span>
<p>{$dlogs['description']}</p>
</li>
{/foreach}
</ul>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.5.1/dist/chart.min.js"></script>
<script type="text/javascript">
{if $_c['hide_mrc'] != 'yes'}
{literal}
document.addEventListener("DOMContentLoaded", function() {
var counts = JSON.parse('{/literal}{$monthlyRegistered|json_encode}{literal}');
var monthNames = [
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
];
var labels = [];
var data = [];
for (var i = 1; i <= 12; i++) {
var month = counts.find(count => count.date === i);
labels.push(month ? monthNames[i - 1] : monthNames[i - 1].substring(0, 3));
data.push(month ? month.count : 0);
}
var ctx = document.getElementById('chart').getContext('2d');
var chart = new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'Registered Members',
data: data,
backgroundColor: 'rgba(0, 0, 255, 0.5)',
borderColor: 'rgba(0, 0, 255, 0.7)',
borderWidth: 1
}]
},
options: {
responsive: true,
scales: {
x: {
grid: {
display: false
}
},
y: {
beginAtZero: true,
grid: {
color: 'rgba(0, 0, 0, 0.1)'
}
}
}
}
});
});
{/literal}
{/if}
{if $_c['hide_tmc'] != 'yes'}
{literal}
document.addEventListener("DOMContentLoaded", function() {
var monthlySales = JSON.parse('{/literal}{$monthlySales|json_encode}{literal}');
var monthNames = [
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
];
var labels = [];
var data = [];
for (var i = 1; i <= 12; i++) {
var month = findMonthData(monthlySales, i);
labels.push(month ? monthNames[i - 1] : monthNames[i - 1].substring(0, 3));
data.push(month ? month.totalSales : 0);
}
var ctx = document.getElementById('salesChart').getContext('2d');
var chart = new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'Monthly Sales',
data: data,
backgroundColor: 'rgba(2, 10, 242)', // Customize the background color
borderColor: 'rgba(255, 99, 132, 1)', // Customize the border color
borderWidth: 1
}]
},
options: {
responsive: true,
scales: {
x: {
grid: {
display: false
}
},
y: {
beginAtZero: true,
grid: {
color: 'rgba(0, 0, 0, 0.1)'
}
}
}
}
});
});
function findMonthData(monthlySales, month) {
for (var i = 0; i < monthlySales.length; i++) {
if (monthlySales[i].month === month) {
return monthlySales[i];
}
}
return null;
}
{/literal}
{/if}
{if $_c['hide_aui'] != 'yes'}
{literal}
document.addEventListener("DOMContentLoaded", function() {
// Get the data from PHP and assign it to JavaScript variables
var u_act = '{/literal}{$u_act}{literal}';
var c_all = '{/literal}{$c_all}{literal}';
var u_all = '{/literal}{$u_all}{literal}';
//lets calculate the inactive users as reported
var expired = u_all - u_act;
var inactive = c_all - u_all;
// Create the chart data
var data = {
labels: ['Active Users', 'Expired Users', 'Inactive Users'],
datasets: [{
label: 'User Recharges',
data: [parseInt(u_act), parseInt(expired), parseInt(inactive)],
backgroundColor: ['rgba(4, 191, 13)', 'rgba(191, 35, 4)', 'rgba(0, 0, 255, 0.5'],
borderColor: ['rgba(0, 255, 0, 1)', 'rgba(255, 99, 132, 1)', 'rgba(0, 0, 255, 0.7'],
borderWidth: 1
}]
};
// Create chart options
var options = {
responsive: true,
aspectRatio: 1,
plugins: {
legend: {
position: 'bottom',
labels: {
boxWidth: 15
}
}
}
};
// Get the canvas element and create the chart
var ctx = document.getElementById('userRechargesChart').getContext('2d');
var chart = new Chart(ctx, {
type: 'pie',
data: data,
options: options
});
});
{/literal}
{/if}
</script>
<script>
window.addEventListener('DOMContentLoaded', function() {
$.getJSON("./version.json?" + Math.random(), function(data) {
var localVersion = data.version;
$('#version').html('Version: ' + localVersion);
$.getJSON("https://raw.githubusercontent.com/hotspotbilling/phpnuxbill/master/version.json?" + Math
$.getJSON(
"https://raw.githubusercontent.com/hotspotbilling/phpnuxbill/master/version.json?" +
Math
.random(),
function(data) {
var latestVersion = data.version;

View File

@ -9,12 +9,15 @@
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Status')}</label>
<div class="col-md-10">
<label class="radio-inline warning">
<input type="radio" checked name="enabled" value="1"> Enable
</label>
<label class="radio-inline">
<input type="radio" name="enabled" value="0"> Disable
</label>
<input type="radio" name="enabled" value="1" checked> Enable
<input type="radio" name="enabled" value="0"> Disable
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Client Can Purchase')}</label>
<div class="col-md-10">
<input type="radio" name="allow_purchase" value="yes" checked> Yes
<input type="radio" name="allow_purchase" value="no"> No
</div>
</div>
{if $_c['radius_enable']}
@ -172,23 +175,22 @@
if (cek.checked) {
$("#routerChoose").addClass('hidden');
document.getElementById("routers").required = false;
$("#pool_expired").html('');
$.ajax({
url: "index.php?_route=autoload/pool",
data: "routers=radius",
cache: false,
success: function(msg) {
$("#pool_expired").html(msg);
}
});
} else {
document.getElementById("routers").required = true;
$("#routerChoose").removeClass('hidden');
}
}
setTimeout(() => {
$.ajax({
url: "index.php?_route=autoload/pool",
data: "routers=radius",
cache: false,
success: function(msg) {
$("#pool_expired").html(msg);
}
});
}, 2000);
</script>
{/literal}
{/if}
{include file="sections/footer.tpl"}
{include file="sections/footer.tpl"}

View File

@ -3,20 +3,22 @@
<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_Plan']}</div>
<div class="panel-heading">{$_L['Edit_Plan']} || {$d['name_plan']}</div>
<div class="panel-body">
<form class="form-horizontal" method="post" role="form" action="{$_url}services/edit-post">
<input type="hidden" name="id" value="{$d['id']}">
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Status')}</label>
<div class="col-md-10">
<label class="radio-inline warning">
<input type="radio" {if $d['enabled'] == 1}checked{/if} name="enabled" value="1"> Enable
</label>
<label class="radio-inline">
<input type="radio" {if $d['enabled'] == 0}checked{/if} name="enabled" value="0">
Disable
</label>
<input type="radio" name="enabled" value="1" {if $d['enabled'] == 1}checked{/if}> Enable
<input type="radio" name="enabled" value="0" {if $d['enabled'] == 0}checked{/if}> Disable
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Client Can Purchase')}</label>
<div class="col-md-10">
<input type="radio" name="allow_purchase" value="yes" {if $d['allow_purchase'] == yes}checked{/if}> Yes
<input type="radio" name="allow_purchase" value="no" {if $d['allow_purchase'] == no}checked{/if}> No
</div>
</div>
{if $_c['radius_enable'] and $d['is_radius']}
@ -177,7 +179,7 @@
</div>
</div>
{if $_c['radius_enable']}
{if $_c['radius_enable'] && $d['is_radius']}
{literal}
<script>
function isRadius(cek) {
@ -204,4 +206,4 @@
</script>
{/literal}
{/if}
{include file="sections/footer.tpl"}
{include file="sections/footer.tpl"}

View File

@ -49,7 +49,8 @@
</thead>
<tbody>
{foreach $d as $ds}
<tr {if $ds['enabled'] != 1}class="danger" title="disabled" {/if}>
<tr {if $ds['enabled'] != 1}class="danger" title="disabled"
{elseif $ds['allow_purchase'] != 'yes'}class="warning" title="Customer can't purchase" {/if}>
<td>{$ds['name_plan']}</td>
<td>{$ds['typebp']}</td>
<td>{$ds['name_bw']}</td>

View File

@ -21,30 +21,27 @@
<table width="200">
<tr>
<td>
<fieldset>
<center>
<b>{$_c['CompanyName']}</b><br>
{$_c['address']}<br>
{$_c['phone']}<br>
</center>
============================================<br>
INVOICE: <b>{$d['invoice']}</b> - {$_L['Date']} : {$date}<br>
{$_L['Sales']} : {$_admin['fullname']}<br>
============================================<br>
{$_L['Type']} : <b>{$d['type']}</b><br>
{$_L['Plan_Name']} : <b>{$d['plan_name']}</b><br>
{$_L['Plan_Price']} : <b>{Lang::moneyFormat($d['price'])}</b><br>
<br>
{$_L['Username']} : <b>{$d['username']}</b><br>
{$_L['Password']} : **********<br>
{if $in['type'] != 'Balance'}
<br>
{$_L['Created_On']} : <b>{Lang::dateAndTimeFormat($d['recharged_on'],$d['recharged_time'])}</b><br>
{$_L['Expires_On']} : <b>{Lang::dateAndTimeFormat($d['expiration'],$d['time'])}</b><br>
{/if}
============================================<br>
<center>{$_c['note']}</center>
</fieldset>
<pre style="border-style: none; background-color: white;"><b>{Lang::pad($_c['CompanyName'],' ', 2)}</b>
{Lang::pad($_c['address'],' ', 2)}
{Lang::pad($_c['phone'],' ', 2)}
{Lang::pad("", '=')}
{Lang::pads("Invoice", $in['invoice'], ' ')}
{Lang::pads($_L['Date'], $date, ' ')}
{Lang::pads($_L['Sales'], $_admin['fullname'], ' ')}
{Lang::pad("", '=')}
{Lang::pads($_L['Type'], $in['type'], ' ')}
{Lang::pads($_L['Plan_Name'], $in['plan_name'], ' ')}
{Lang::pads($_L['Plan_Price'], Lang::moneyFormat($in['price']), ' ')}
{Lang::pad($in['method'], ' ', 2)}
{Lang::pads($_L['Username'], $in['username'], ' ')}
{Lang::pads($_L['Password'], '**********', ' ')}
{if $in['type'] != 'Balance'}
{Lang::pads($_L['Created_On'], Lang::dateAndTimeFormat($in['recharged_on'],$in['recharged_time']), ' ')}
{Lang::pads($_L['Expires_On'], Lang::dateAndTimeFormat($in['expiration'],$in['time']), ' ')}
{/if}
{Lang::pad("", '=')}
{Lang::pad($_c['note'],' ', 2)}</pre>
</td>
</tr>
</table>

View File

@ -5,42 +5,36 @@
<div class="panel panel-hovered panel-primary panel-stacked mb30">
<div class="panel-heading">{$in['invoice']}</div>
<div class="panel-body">
<div class="well">
<fieldset>
<center>
<b>{$_c['CompanyName']}</b><br>
{$_c['address']}<br>
{$_c['phone']}<br>
</center>
====================================================<br>
INVOICE: <b>{$in['invoice']}</b> - {$_L['Date']} : {$date}<br>
{$_L['Sales']} : {$_admin['fullname']}<br>
====================================================<br>
{$_L['Type']} : <b>{$in['type']}</b><br>
{$_L['Plan_Name']} : <b>{$in['plan_name']}</b><br>
{$_L['Plan_Price']} : <b>{Lang::moneyFormat($in['price'])}</b><br>
{$in['method']}<br>
<br>
{$_L['Username']} : <b>{$in['username']}</b><br>
{$_L['Password']} : **********<br>
{if $in['type'] != 'Balance'}
<br>
{$_L['Created_On']} : <b>{Lang::dateAndTimeFormat($in['recharged_on'],$in['recharged_time'])}</b><br>
{$_L['Expires_On']} : <b>{Lang::dateAndTimeFormat($in['expiration'],$in['time'])}</b><br>
{/if}
=====================================================<br>
<center>{$_c['note']}</center>
</fieldset>
</div>
<form class="form-horizontal" method="post" action="{$_url}prepaid/print" target="_blank">
<input type="hidden" name="id" value="{$in['id']}">
<a href="{$_url}prepaid/list" class="btn btn-primary btn-sm"><i
class="ion-reply-all"></i>{$_L['Finish']}</a>
<a href="{$_url}prepaid/view/{$in['id']}/send" class="btn btn-info text-black btn-sm"><i
class="glyphicon glyphicon-envelope"></i> {Lang::T("Resend To Customer")}</a>
<button type="submit" class="btn btn-default btn-sm"><i class="fa fa-print"></i>
{$_L['Click_Here_to_Print']}</button>
</form>
<pre><b>{Lang::pad($_c['CompanyName'],' ', 2)}</b>
{Lang::pad($_c['address'],' ', 2)}
{Lang::pad($_c['phone'],' ', 2)}
{Lang::pad("", '=')}
{Lang::pads("Invoice", $in['invoice'], ' ')}
{Lang::pads($_L['Date'], $date, ' ')}
{Lang::pads($_L['Sales'], $_admin['fullname'], ' ')}
{Lang::pad("", '=')}
{Lang::pads($_L['Type'], $in['type'], ' ')}
{Lang::pads($_L['Plan_Name'], $in['plan_name'], ' ')}
{Lang::pads($_L['Plan_Price'], Lang::moneyFormat($in['price']), ' ')}
{Lang::pad($in['method'], ' ', 2)}
{Lang::pads($_L['Username'], $in['username'], ' ')}
{Lang::pads($_L['Password'], '**********', ' ')}
{if $in['type'] != 'Balance'}
{Lang::pads($_L['Created_On'], Lang::dateAndTimeFormat($in['recharged_on'],$in['recharged_time']), ' ')}
{Lang::pads($_L['Expires_On'], Lang::dateAndTimeFormat($in['expiration'],$in['time']), ' ')}
{/if}
{Lang::pad("", '=')}
{Lang::pad($_c['note'],' ', 2)}</pre>
<form class="form-horizontal" method="post" action="{$_url}prepaid/print" target="_blank">
<input type="hidden" name="id" value="{$in['id']}">
<a href="{$_url}prepaid/list" class="btn btn-primary btn-sm"><i
class="ion-reply-all"></i>{$_L['Finish']}</a>
<a href="{$_url}prepaid/view/{$in['id']}/send" class="btn btn-info text-black btn-sm"><i
class="glyphicon glyphicon-envelope"></i> {Lang::T("Resend To Customer")}</a>
<button type="submit" class="btn btn-default btn-sm"><i class="fa fa-print"></i>
{$_L['Click_Here_to_Print']}</button>
</form>
</div>
</div>

View File

@ -44,7 +44,7 @@
<td>{Lang::dateTimeFormat($ds['date'])}</td>
<td>{$ds['type']}</td>
<td>{$ds['ip']}</td>
<td style="overflow-x: scroll;">{$ds['description']}</td>
<td style="overflow-x: scroll;">{nl2br($ds['description'])}</td>
</tr>
{/foreach}
</tbody>

View File

@ -8,19 +8,21 @@
<div class="col-md-4">
<div class="box box-hovered mb20 box-primary">
<div class="box-header">
<h3 class="box-title">{$plugin['name']}</h3>
<h3 class="box-title text1line">{$plugin['name']}</h3>
</div>
<div class="box-body" style="overflow-y: scroll;">
<div style="max-height: 50px; min-height: 50px;">{$plugin['description']}</div>
</div>
<div class="box-body">{$plugin['description']}<br><small><i>@{$plugin['author']} Last update: {$plugin['last_update']}</i></small></div>
<div class="box-footer ">
<center><small><i>@{$plugin['author']} Last update: {$plugin['last_update']}</i></small></center>
<div class="btn-group btn-group-justified" role="group" aria-label="...">
<a href="{$plugin['url']}" target="_blank"
class="btn btn-primary"><i class="ion ion-chatboxes"></i> Website</a>
<a href="{$plugin['github']}" target="_blank"
class="btn btn-success"><i class="ion ion-chatboxes"></i> Github</a>
<a {if $zipExt }
href="{$_url}pluginmanager/install/plugin/{$plugin['id']}" onclick="return confirm('Installing plugin will take some time to complete, do not close the page while it loading to install the plugin')"
{else}
href="#" onclick="alert('PHP ZIP extension is not available')"
<a href="{$plugin['url']}" target="_blank" class="btn btn-primary"><i
class="ion ion-chatboxes"></i> Website</a>
<a href="{$plugin['github']}" target="_blank" class="btn btn-success"><i
class="ion ion-chatboxes"></i> Github</a>
<a {if $zipExt } href="{$_url}pluginmanager/install/plugin/{$plugin['id']}"
onclick="return confirm('Installing plugin will take some time to complete, do not close the page while it loading to install the plugin')"
{else} href="#" onclick="alert('PHP ZIP extension is not installed')"
{/if}
class="btn btn-warning"><i class="ion ion-chatboxes"></i> Install</a>
</div>
@ -37,19 +39,21 @@
<div class="col-md-4">
<div class="box box-hovered mb20 box-primary">
<div class="box-header">
<h3 class="box-title">{$pg['name']}</h3>
<h3 class="box-title text1line">{$pg['name']}</h3>
</div>
<div class="box-body" style="overflow-y: scroll;">
<div style="max-height: 50px; min-height: 50px;">{$pg['description']}</div>
</div>
<div class="box-body">{$pg['description']}<br><small><i>@{$plugin['author']} Last update: {$plugin['last_update']}</i></small></div>
<div class="box-footer ">
<center><small><i>@{$pg['author']} Last update: {$pg['last_update']}</i></small></center>
<div class="btn-group btn-group-justified" role="group" aria-label="...">
<a href="{$pg['url']}" target="_blank"
class="btn btn-primary"><i class="ion ion-chatboxes"></i> Website</a>
<a href="{$pg['github']}" target="_blank"
class="btn btn-success"><i class="ion ion-chatboxes"></i> Github</a>
<a {if $zipExt }
href="{$_url}pluginmanager/install/payment/{$pg['id']}" onclick="return confirm('Installing plugin will take some time to complete, do not close the page while it loading to install the plugin')"
{else}
href="#" onclick="alert('PHP ZIP extension is not available')"
<a href="{$pg['url']}" target="_blank" class="btn btn-primary"><i
class="ion ion-chatboxes"></i> Website</a>
<a href="{$pg['github']}" target="_blank" class="btn btn-success"><i
class="ion ion-chatboxes"></i> Github</a>
<a {if $zipExt } href="{$_url}pluginmanager/install/payment/{$pg['id']}"
onclick="return confirm('Installing plugin will take some time to complete, do not close the page while it loading to install the plugin')"
{else} href="#" onclick="alert('PHP ZIP extension is not available')"
{/if}
class="btn btn-warning"><i class="ion ion-chatboxes"></i> Install</a>
</div>

View File

@ -9,21 +9,22 @@
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Status')}</label>
<div class="col-md-10">
<label class="radio-inline warning">
<input type="radio" checked name="enabled" value="1"> Enable
</label>
<label class="radio-inline">
<input type="radio" name="enabled" value="0"> Disable
</label>
<input type="radio" checked name="enabled" value="1"> Enable
<input type="radio" name="enabled" value="0"> Disable
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Client Can Purchase')}</label>
<div class="col-md-10">
<input type="radio" checked name="allow_purchase" value="yes"> Yes
<input type="radio" name="allow_purchase" value="no"> No
</div>
</div>
{if $_c['radius_enable']}
<div class="form-group">
<label class="col-md-2 control-label">Radius</label>
<div class="col-md-6">
<label class="radio-inline">
<input type="checkbox" name="radius" onclick="isRadius(this)" value="1"> Radius Plan
</label>
<input type="checkbox" name="radius" onclick="isRadius(this)" value="1"> Radius Plan
</div>
<p class="help-block col-md-4">{Lang::T('Cannot be change after saved')}</p>
</div>
@ -142,4 +143,4 @@
</script>
{/literal}
{/if}
{include file="sections/footer.tpl"}
{include file="sections/footer.tpl"}

View File

@ -3,20 +3,22 @@
<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_Plan']}</div>
<div class="panel-heading">{$_L['Edit_Plan']} || {$d['name_plan']}</div>
<div class="panel-body">
<form class="form-horizontal" method="post" role="form" action="{$_url}services/edit-pppoe-post">
<input type="hidden" name="id" value="{$d['id']}">
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Status')}</label>
<div class="col-md-10">
<label class="radio-inline warning">
<input type="radio" {if $d['enabled'] == 1}checked{/if} name="enabled" value="1"> Enable
</label>
<label class="radio-inline">
<input type="radio" {if $d['enabled'] == 0}checked{/if} name="enabled" value="0">
Disable
</label>
<input type="radio" name="enabled" value="1" {if $d['enabled'] == 1}checked{/if}> Enable
<input type="radio" name="enabled" value="0" {if $d['enabled'] == 0}checked{/if}> Disable
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Client Can Purchase')}</label>
<div class="col-md-10">
<input type="radio" name="allow_purchase" value="yes" {if $d['allow_purchase'] == yes}checked{/if}> Yes
<input type="radio" name="allow_purchase" value="no" {if $d['allow_purchase'] == no}checked{/if}> No
</div>
</div>
{if $_c['radius_enable'] and $d['is_radius']}
@ -119,7 +121,7 @@
</div>
</div>
{if $_c['radius_enable'] and $d['is_radius']}
{if $_c['radius_enable'] && $d['is_radius']}
{literal}
<script>
document.getElementById("routers").required = false;
@ -137,4 +139,4 @@
</script>
{/literal}
{/if}
{include file="sections/footer.tpl"}
{include file="sections/footer.tpl"}

View File

@ -47,7 +47,8 @@
</thead>
<tbody>
{foreach $d as $ds}
<tr {if $ds['enabled'] != 1}class="danger" title="disabled" {/if}>
<tr {if $ds['enabled'] != 1}class="danger" title="disabled"
{elseif $ds['allow_purchase'] != 'yes'}class="warning" title="Customer can't purchase" {/if}>
<td>{$ds['name_plan']}</td>
<td>{$ds['name_bw']}</td>
<td>{Lang::moneyFormat($ds['price'])}</td>

View File

@ -4,7 +4,7 @@
<div class="col-sm-12">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">{$_L['Recharge_Account']}</h3>
<h3 class="panel-title">Edit Plan</h3>
</div>
<div class="panel-body">
<form class="form-horizontal" method="post" role="form" action="{$_url}prepaid/edit-post">

View File

@ -8,7 +8,8 @@
<link rel="shortcut icon" href="ui/ui/images/logo.png" type="image/x-icon" />
<link rel="stylesheet" href="ui/ui/styles/bootstrap.min.css">
<link rel="stylesheet" href="ui/ui/styles/adminlte.min.css">
<link rel="stylesheet" href="ui/ui/styles/modern-AdminLTE.min.css">
</head>

View File

@ -7,25 +7,13 @@
<title>{$_title} - {$_L['Register']}</title>
<link rel="shortcut icon" href="ui/ui/images/logo.png" type="image/x-icon" />
<!-- Icons -->
<link rel="stylesheet" href="ui/ui/fonts/ionicons/css/ionicons.min.css">
<link rel="stylesheet" href="ui/ui/fonts/font-awesome/css/font-awesome.min.css">
<!-- Plugins -->
<link rel="stylesheet" href="ui/ui/styles/plugins/waves.css">
<link rel="stylesheet" href="ui/ui/styles/plugins/perfect-scrollbar.css">
<!-- Css/Less Stylesheets -->
<link rel="stylesheet" href="ui/ui/styles/bootstrap.min.css">
<link rel="stylesheet" href="ui/ui/styles/main.min.css">
<!-- Match Media polyfill for IE9 -->
<!--[if IE 9]> <script src="ui/ui/scripts/ie/matchMedia.js"></script> <![endif]-->
<link rel="stylesheet" href="ui/ui/styles/modern-AdminLTE.min.css">
</head>
<body id="app" class="app off-canvas body-full">
<div class="container">
<div class="hidden-xs" style="height:150px"></div>
<div class="form-head mb20">

View File

@ -8,7 +8,8 @@
<link rel="shortcut icon" href="ui/ui/images/logo.png" type="image/x-icon" />
<link rel="stylesheet" href="ui/ui/styles/bootstrap.min.css">
<link rel="stylesheet" href="ui/ui/styles/adminlte.min.css">
<link rel="stylesheet" href="ui/ui/styles/modern-AdminLTE.min.css">
</head>

View File

@ -13,8 +13,8 @@
<link rel="stylesheet" href="ui/ui/fonts/font-awesome/css/font-awesome.min.css">
<link rel="stylesheet" href="ui/ui/fonts/MaterialDesign/css/materialdesignicons.min.css">
<link rel="stylesheet" href="ui/ui/styles/adminlte.min.css">
<link rel="stylesheet" href="ui/ui/styles/skin-blue.min.css">
<link rel="stylesheet" href="ui/ui/styles/modern-AdminLTE.min.css">
<style>
::-moz-selection {
/* Code for Firefox */
@ -57,9 +57,16 @@
<div class="box-footer">
<div class="btn-group btn-group-justified" role="group" aria-label="...">
<a href="./update.php?step=4" class="btn btn-info btn-sm btn-block">Update Database</a>
<a href="{$_url}community#update" class="btn btn-primary btn-sm btn-block">Update
<a href="{$_url}community#update" class="btn btn-success btn-sm btn-block">Update
PHPNuxBill</a>
</div>
<br>
<div class="btn-group btn-group-justified" role="group" aria-label="...">
<a href="https://github.com/hotspotbilling/phpnuxbill/discussions" target="_blank"
class="btn btn-success btn-sm btn-block">Ask Github Community</a>
<a href="https://t.me/phpnuxbill" target="_blank"
class="btn btn-primary btn-sm btn-block">Ask Telegram Community</a>
</div>
<br><br>
<a href="javascript::history.back()" onclick="history.back()"
class="btn btn-warning btn-block">back</a>

View File

@ -12,9 +12,7 @@
<link rel="stylesheet" href="ui/ui/fonts/ionicons/css/ionicons.min.css">
<link rel="stylesheet" href="ui/ui/fonts/font-awesome/css/font-awesome.min.css">
<link rel="stylesheet" href="ui/ui/fonts/MaterialDesign/css/materialdesignicons.min.css">
<link rel="stylesheet" href="ui/ui/styles/adminlte.min.css">
<link rel="stylesheet" href="ui/ui/styles/skin-blue.min.css">
<link rel="stylesheet" href="ui/ui/styles/modern-AdminLTE.min.css">
<link rel="stylesheet" href="ui/ui/styles/select2.min.css" />
<link rel="stylesheet" href="ui/ui/styles/select2-bootstrap.min.css" />
<style>
@ -32,6 +30,23 @@
.select2-container .select2-selection--single .select2-selection__rendered {
margin-top: 0px !important;
}
@media (min-width: 768px) {
.outer {
height: 200px
/* Or whatever */
}
}
.text1line {
display: block;
/* or inline-block */
text-overflow: ellipsis;
word-wrap: break-word;
overflow: hidden;
max-height: 1em;
line-height: 1em;
}
</style>
{if isset($xheader)}
@ -40,7 +55,7 @@
</head>
<body class="hold-transition skin-blue sidebar-mini">
<body class="hold-transition modern-skin-dark sidebar-mini">
<div class="wrapper">
<header class="main-header">
@ -184,7 +199,7 @@
<li {if $_routes[1] eq 'by-period'}class="active" {/if}><a
href="{$_url}reports/by-period">{$_L['Period_Reports']}</a></li>
<li {if $_routes[1] eq 'activation'}class="active" {/if}><a
href="{$_url}reports/activation">{Lang::T('Activation History')}</a></li>
href="{$_url}reports/activation">{Lang::T('Activation History')}</a></li>
{$_MENU_REPORTS}
</ul>
</li>
@ -254,15 +269,20 @@
href="{$_url}settings/users">{$_L['Administrator_Users']}</a></li>
<li {if $_routes[1] eq 'dbstatus'}class="active" {/if}><a
href="{$_url}settings/dbstatus">{$_L['Backup_Restore']}</a></li>
<li {if $_routes[0] eq 'pluginmanager'}class="active" {/if}>
<a href="{$_url}pluginmanager">{Lang::T('Plugin Manager')}</a>
</li>
<li {if $_system_menu eq 'paymentgateway'}class="active" {/if}>
<a href="{$_url}paymentgateway">
<span class="text">{Lang::T('Payment Gateway')}</span>
</a>
</li>
{$_MENU_SETTINGS}
<li {if $_routes[0] eq 'pluginmanager'}class="active" {/if}>
<a href="{$_url}pluginmanager"><i class="glyphicon glyphicon-tasks"></i>
{Lang::T('Plugin Manager')} <small class="label pull-right">Free</small></a>
</li>
{* <li {if $_routes[0] eq 'codecanyon'}class="active" {/if}>
<a href="{$_url}codecanyon"><i class="glyphicon glyphicon-shopping-cart"></i>
Codecanyon.net <small class="label pull-right">Paid</small></a>
</li> *}
</ul>
</li>
{$_MENU_AFTER_SETTINGS}
@ -276,10 +296,10 @@
<ul class="treeview-menu">
<li {if $_routes[1] eq 'list'}class="active" {/if}><a
href="{$_url}logs/phpnuxbill">PhpNuxBill</a></li>
{if $_c['radius_enable']}
{if $_c['radius_enable']}
<li {if $_routes[1] eq 'radius'}class="active" {/if}><a href="{$_url}logs/radius">Radius</a>
</li>
{/if}
{/if}
</ul>
{$_MENU_LOGS}
</li>
@ -303,11 +323,11 @@
</section>
<section class="content">
{if isset($notify)}
<div class="alert alert-{if $notify_t == 's'}success{else}danger{/if}">
<button type="button" class="close" data-dismiss="alert">
<span aria-hidden="true">×</span>
</button>
<div>{$notify}</div>
</div>
{if isset($notify)}
<div class="alert alert-{if $notify_t == 's'}success{else}danger{/if}">
<button type="button" class="close" data-dismiss="alert">
<span aria-hidden="true">×</span>
</button>
<div>{$notify}</div>
</div>
{/if}

View File

@ -12,9 +12,8 @@
<link rel="stylesheet" href="ui/ui/fonts/ionicons/css/ionicons.min.css">
<link rel="stylesheet" href="ui/ui/fonts/font-awesome/css/font-awesome.min.css">
<link rel="stylesheet" href="ui/ui/fonts/MaterialDesign/css/materialdesignicons.min.css">
<link rel="stylesheet" href="ui/ui/styles/adminlte.min.css">
<link rel="stylesheet" href="ui/ui/styles/skin-blue.min.css">
<link rel="stylesheet" href="ui/ui/styles/modern-AdminLTE.min.css">
<style>
::-moz-selection {
@ -45,7 +44,7 @@
</head>
<body class="hold-transition skin-blue sidebar-mini">
<body class="hold-transition modern-skin-dark sidebar-mini">
<div class="wrapper">
<header class="main-header" style="position:fixed; width: 100%">
<a href="{$_url}home" class="logo">
@ -77,8 +76,8 @@
<p>
{$_user['fullname']}
<small>{$_user['phonenumber']}</small><br>
<small>{$_user['email']}</small>
<small>{$_user['phonenumber']}<br>
{$_user['email']}</small>
</p>
</li>
<li class="user-body">

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 KiB

11
ui/ui/styles/modern-AdminLTE.min.css vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -74,6 +74,19 @@
style="width:100%; border: 0px;" onmouseleave="this.type = 'password'"
onmouseenter="this.type = 'text'" onclick="this.select()"></td>
</tr>
<tr>
<td class="small text-success text-uppercase text-normal">{Lang::T('Service Type')}</td>
<td class="small mb15">
{if $_user.service_type == 'Hotspot'}
Hotspot
{elseif $_user.service_type == 'PPPoE'}
PPPoE
{elseif $_user.service_type == 'Others' || $_user.service_type == null}
Others
{/if}
</td>
</tr>
{if $_c['enable_balance'] == 'yes'}
<tr>
<td class="small text-warning text-uppercase text-normal">{Lang::T('Balance')}</td>
@ -272,4 +285,4 @@
{/if}
</div>
</div>
{include file="sections/user-footer.tpl"}
{include file="sections/user-footer.tpl"}

View File

@ -0,0 +1,85 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>{$_title} - {$_L['Login']}</title>
<link rel="shortcut icon" href="ui/ui/images/logo.png" type="image/x-icon" />
<link rel="stylesheet" href="ui/ui/styles/bootstrap.min.css">
<link rel="stylesheet" href="ui/ui/styles/modern-AdminLTE.min.css">
</head>
<body>
<div class="container">
<div class="hidden-xs" style="height:150px"></div>
<div class="form-head mb20">
<h1 class="site-logo h2 mb5 mt5 text-center text-uppercase text-bold"
style="text-shadow: 2px 2px 4px #757575;">{$_c['CompanyName']}</h1>
<hr>
</div>
{if isset($notify)}
<div class="alert alert-{if $notify_t == 's'}success{else}danger{/if}">
<button type="button" class="close" data-dismiss="alert">
<span aria-hidden="true">×</span>
</button>
<div>{$notify}</div>
</div>
{/if}
<div class="row">
<div class="col-sm-8">
<div class="panel panel-info">
<div class="panel-heading">{$_L['Announcement']}</div>
<div class="panel-body">
{include file="$_path/../pages/Announcement.html"}
</div>
</div>
</div>
<div class="col-sm-4">
<div class="panel panel-primary">
<div class="panel-heading">{Lang::T('Login / Activate Voucher')}</div>
<div class="panel-body">
<form action="{$_url}login/activation" method="post">
<div class="form-group">
<label>{$_L['Phone_Number']}</label>
<div class="input-group">
{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="08xxxxxxx">
</div>
</div>
<div class="form-group">
<label>{$_L['Enter_Voucher_Code']}</label>
<input type="text" class="form-control" name="voucher" required autocomplete="off"
placeholder="{$_L['Code_Voucher']}">
</div>
<div class="btn-group btn-group-justified mb15">
<div class="btn-group">
<button type="submit"
class="btn btn-primary">{Lang::T('Login / Activate Voucher')}</button>
</div>
</div>
<br>
<center>
<a href="./pages/Privacy_Policy.html" target="_blank">Privacy</a>
&bull;
<a href="./pages/Terms_of_Conditions.html" target="_blank">ToC</a>
</center>
</form>
</div>
</div>
</div>
</div>
</div>
<script src="ui/ui/scripts/vendors.js"></script>
</body>
</html>

View File

@ -8,7 +8,8 @@
<link rel="shortcut icon" href="ui/ui/images/logo.png" type="image/x-icon" />
<link rel="stylesheet" href="ui/ui/styles/bootstrap.min.css">
<link rel="stylesheet" href="ui/ui/styles/adminlte.min.css">
<link rel="stylesheet" href="ui/ui/styles/modern-AdminLTE.min.css">
</head>

View File

@ -6,218 +6,368 @@
<div class="box-header">{Lang::T('Order Internet Package')}</div>
</div>
{if $_c['radius_enable']}
{if Lang::arrayCount($radius_hotspot)>0}
<ol class="breadcrumb">
<li>{if $_c['radius_plan']==''}Radius Plan{else}{$_c['radius_plan']}{/if}</li>
<li>{if $_c['hotspot_plan']==''}Hotspot Plan{else}{$_c['hotspot_plan']}{/if}</li>
</ol>
<div class="row">
{foreach $radius_hotspot as $plan}
<div class="col col-md-4">
<div class="box box-primary">
<div class="box-header text-bold">{$plan['name_plan']}</div>
<div class="table-responsive">
<table class="table table-bordered table-striped">
<tbody>
<tr>
<td>{Lang::T('Type')}</td>
<td>{$plan['type']}</td>
</tr>
<tr>
<td>{Lang::T('Price')}</td>
<td>{Lang::moneyFormat($plan['price'])}</td>
</tr>
<tr>
<td>{Lang::T('Validity')}</td>
<td>{$plan['validity']} {$plan['validity_unit']}</td>
</tr>
</tbody>
</table>
</div>
<div class="box-body">
<div class="btn-group btn-group-justified" role="group" aria-label="...">
<a href="{$_url}order/buy/radius/{$plan['id']}"
onclick="return confirm('{Lang::T('Buy this? your active package will be overwrite')}')"
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/radius/{$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>
{if $_c['enable_balance'] == 'yes' && $_c['allow_balance_transfer'] == 'yes' && $_user['balance']>=$plan['price']}
<a href="{$_url}order/send/radius/{$plan['id']}"
onclick="return confirm('{Lang::T('Buy this for friend account?')}')"
class="btn btn-sm btn-block btn-primary">{Lang::T('Buy for friend')}</a>
{/if}
</div>
</div>
{if $_user['service_type'] == 'PPPoE'}
{if Lang::arrayCount($radius_pppoe)>0}
<ol class="breadcrumb">
<li>{if $_c['radius_plan']==''}Radius Plan{else}{$_c['radius_plan']}{/if}</li>
<li>{if $_c['pppoe_plan']==''}PPPOE Plan{else}{$_c['pppoe_plan']}{/if}</li>
</ol>
<div class="row">
{foreach $radius_pppoe as $plan}
<div class="col col-md-4">
<div class="box box-primary">
<div class="box-header text-bold">{$plan['name_plan']}</div>
<div class="table-responsive">
<table class="table table-bordered table-striped">
<tbody>
<tr>
<td>{Lang::T('Type')}</td>
<td>{$plan['type']}</td>
</tr>
<tr>
<td>{Lang::T('Price')}</td>
<td>{Lang::moneyFormat($plan['price'])}</td>
</tr>
<tr>
<td>{Lang::T('Validity')}</td>
<td>{$plan['validity']} {$plan['validity_unit']}</td>
</tr>
</tbody>
</table>
</div>
{/foreach}
</div>
{/if}
{if Lang::arrayCount($radius_pppoe)>0}
<ol class="breadcrumb">
<li>{if $_c['radius_plan']==''}Radius Plan{else}{$_c['radius_plan']}{/if}</li>
<li>{if $_c['pppoe_plan']==''}PPPOE Plan{else}{$_c['pppoe_plan']}{/if}</li>
</ol>
<div class="row">
{foreach $radius_pppoe as $plan}
<div class="col col-md-4">
<div class="box box- box-primary">
<div class="box-header text-bold">{$plan['name_plan']}</div>
<div class="table-responsive">
<table class="table table-bordered table-striped">
<tbody>
<tr>
<td>{Lang::T('Type')}</td>
<td>{$plan['type']}</td>
</tr>
<tr>
<td>{Lang::T('Price')}</td>
<td>{Lang::moneyFormat($plan['price'])}</td>
</tr>
<tr>
<td>{Lang::T('Validity')}</td>
<td>{$plan['validity']} {$plan['validity_unit']}</td>
</tr>
</tbody>
</table>
</div>
<div class="box-body">
<div class="btn-group btn-group-justified" role="group" aria-label="...">
<a href="{$_url}order/buy/radius/{$plan['id']}"
onclick="return confirm('{Lang::T('Buy this? your active package will be overwrite')}')"
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/radius/{$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>
{if $_c['enable_balance'] == 'yes' && $_c['allow_balance_transfer'] == 'yes' && $_user['balance']>=$plan['price']}
<a href="{$_url}order/send/radius/{$plan['id']}"
onclick="return confirm('{Lang::T('Buy this for friend account?')}')"
class="btn btn-sm btn-block btn-primary">{Lang::T('Buy for friend')}</a>
{/if}
</div>
</div>
<div class="box-body">
<div class="btn-group btn-group-justified" role="group" aria-label="...">
<a href="{$_url}order/buy/radius/{$plan['id']}" onclick="return confirm('{Lang::T('Buy this? your active package will be overwrite')}')" 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/radius/{$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>
{/foreach}
{if $_c['enable_balance'] == 'yes' && $_c['allow_balance_transfer'] == 'yes' && $_user['balance']>=$plan['price']}
<a href="{$_url}order/send/radius/{$plan['id']}" onclick="return confirm('{Lang::T('Buy this for friend account?')}')" class="btn btn-sm btn-block btn-primary">{Lang::T('Buy for friend')}</a>
{/if}
</div>
</div>
</div>
{/foreach}
</div>
{/if}
{elseif $_user['service_type'] == 'Hotspot'}
{if Lang::arrayCount($radius_hotspot)>0}
<ol class="breadcrumb">
<li>{if $_c['radius_plan']==''}Radius Plan{else}{$_c['radius_plan']}{/if}</li>
<li>{if $_c['hotspot_plan']==''}Hotspot Plan{else}{$_c['hotspot_plan']}{/if}</li>
</ol>
<div class="row">
{foreach $radius_hotspot as $plan}
<div class="col col-md-4">
<div class="box box-primary">
<div class="box-header text-bold">{$plan['name_plan']}</div>
<div class="table-responsive">
<table class="table table-bordered table-striped">
<tbody>
<tr>
<td>{Lang::T('Type')}</td>
<td>{$plan['type']}</td>
</tr>
<tr>
<td>{Lang::T('Price')}</td>
<td>{Lang::moneyFormat($plan['price'])}</td>
</tr>
<tr>
<td>{Lang::T('Validity')}</td>
<td>{$plan['validity']} {$plan['validity_unit']}</td>
</tr>
</tbody>
</table>
</div>
<div class="box-body">
<div class="btn-group btn-group-justified" role="group" aria-label="...">
<a href="{$_url}order/buy/radius/{$plan['id']}" onclick="return confirm('{Lang::T('Buy this? your active package will be overwrite')}')" 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/radius/{$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>
{if $_c['enable_balance'] == 'yes' && $_c['allow_balance_transfer'] == 'yes' && $_user['balance']>=$plan['price']}
<a href="{$_url}order/send/radius/{$plan['id']}" onclick="return confirm('{Lang::T('Buy this for friend account?')}')" class="btn btn-sm btn-block btn-primary">{Lang::T('Buy for friend')}</a>
{/if}
</div>
</div>
</div>
{/foreach}
</div>
{/if}
{elseif $_user['service_type'] == 'Others' || $_user['service_type'] == '' && (Lang::arrayCount($radius_pppoe)>0 || Lang::arrayCount($radius_hotspot)>0)}
<ol class="breadcrumb">
<li>{if $_c['radius_plan']==''}Radius Plan{else}{$_c['radius_plan']}{/if}</li>
<li>{if $_c['pppoe_plan']==''}PPPOE Plan{else}{$_c['pppoe_plan']}{/if}</li>
</ol>
<div class="row">
{if Lang::arrayCount($radius_pppoe)>0}
{foreach $radius_pppoe as $plan}
<div class="col col-md-4">
<div class="box box-primary">
<div class="box-header text-bold">{$plan['name_plan']}</div>
<div class="table-responsive">
<table class="table table-bordered table-striped">
<tbody>
<tr>
<td>{Lang::T('Type')}</td>
<td>{$plan['type']}</td>
</tr>
<tr>
<td>{Lang::T('Price')}</td>
<td>{Lang::moneyFormat($plan['price'])}</td>
</tr>
<tr>
<td>{Lang::T('Validity')}</td>
<td>{$plan['validity']} {$plan['validity_unit']}</td>
</tr>
</tbody>
</table>
</div>
<div class="box-body">
<div class="btn-group btn-group-justified" role="group" aria-label="...">
<a href="{$_url}order/buy/pppoe/{$plan['id']}" onclick="return confirm('{Lang::T('Buy this? your active package will be overwritten')}')" 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/pppoe/{$plan['id']}" onclick="return confirm('{Lang::T('Pay this with Balance? your active package will be overwritten')}')" class="btn btn-sm btn-block btn-success">{Lang::T('Pay With Balance')}</a>
{/if}
</div>
{if $_c['enable_balance'] == 'yes' && $_c['allow_balance_transfer'] == 'yes' && $_user['balance']>=$plan['price']}
<a href="{$_url}order/send/pppoe/{$plan['id']}" onclick="return confirm('{Lang::T('Buy this for friend account?')}')" class="btn btn-sm btn-block btn-primary">{Lang::T('Buy for friend')}</a>
{/if}
</div>
</div>
</div>
{/foreach}
{/if}
{if Lang::arrayCount($radius_hotspot)>0}
<ol class="breadcrumb">
<li>{if $_c['radius_plan']==''}Radius Plan{else}{$_c['radius_plan']}{/if}</li>
<li>{if $_c['hotspot_plan']==''}Hotspot Plan{else}{$_c['hotspot_plan']}{/if}</li>
</ol>
{foreach $radius_hotspot as $plan}
<div class="col col-md-4">
<div class="box box-primary">
<div class="box-header text-bold">{$plan['name_plan']}</div>
<div class="table-responsive">
<table class="table table-bordered table-striped">
<tbody>
<tr>
<td>{Lang::T('Type')}</td>
<td>{$plan['type']}</td>
</tr>
<tr>
<td>{Lang::T('Price')}</td>
<td>{Lang::moneyFormat($plan['price'])}</td>
</tr>
<tr>
<td>{Lang::T('Validity')}</td>
<td>{$plan['validity']} {$plan['validity_unit']}</td>
</tr>
</tbody>
</table>
</div>
<div class="box-body">
<div class="btn-group btn-group-justified" role="group" aria-label="...">
<a href="{$_url}order/buy/hotspot/{$plan['id']}" onclick="return confirm('{Lang::T('Buy this? your active package will be overwritten')}')" 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/hotspot/{$plan['id']}" onclick="return confirm('{Lang::T('Pay this with Balance? your active package will be overwritten')}')" class="btn btn-sm btn-block btn-success">{Lang::T('Pay With Balance')}</a>
{/if}
</div>
{if $_c['enable_balance'] == 'yes' && $_c['allow_balance_transfer'] == 'yes' && $_user['balance']>=$plan['price']}
<a href="{$_url}order/send/hotspot/{$plan['id']}" onclick="return confirm('{Lang::T('Buy this for friend account?')}')" class="btn btn-sm btn-block btn-primary">{Lang::T('Buy for friend')}</a>
{/if}
</div>
</div>
</div>
{/foreach}
{/if}
</div>
{/if}
{/if}
{foreach $routers as $router}
{if Validator::isRouterHasPlan($plans_hotspot, $router['name']) || Validator::isRouterHasPlan($plans_pppoe, $router['name'])}
<div class="box box-solid box-primary bg-gray">
<div class="box-header text-white text-bold">{$router['name']}</div>
{if $router['description'] != ''}
<div class="box-body">
{$router['description']}
</div>
{/if}
{if Validator::countRouterPlan($plans_hotspot, $router['name'])>0}
<div class="box-header text-white">{if $_c['hotspot_plan']==''}Hotspot Plan{else}{$_c['hotspot_plan']}{/if}</div>
<div class="box-body row">
{foreach $plans_hotspot as $plan}
{if $router['name'] eq $plan['routers']}
<div class="col col-md-4">
<div class="box box-primary">
<div class="box-header text-center text-bold">{$plan['name_plan']}</div>
<div class="table-responsive">
<table class="table table-bordered table-striped">
<tbody>
<tr>
<td>{Lang::T('Type')}</td>
<td>{$plan['type']}</td>
</tr>
<tr>
<td>{Lang::T('Price')}</td>
<td>{Lang::moneyFormat($plan['price'])}</td>
</tr>
<tr>
<td>{Lang::T('Validity')}</td>
<td>{$plan['validity']} {$plan['validity_unit']}</td>
</tr>
</tbody>
</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-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>
{if $_c['enable_balance'] == 'yes' && $_c['allow_balance_transfer'] == 'yes' && $_user['balance']>=$plan['price']}
<a href="{$_url}order/send/{$router['id']}/{$plan['id']}"
onclick="return confirm('{Lang::T('Buy this for friend account?')}')"
class="btn btn-sm btn-block btn-primary">{Lang::T('Buy for friend')}</a>
{/if}
</div>
</div>
</div>
{/if}
{/foreach}
</div>
{/if}
{if Validator::countRouterPlan($plans_pppoe,$router['name'])>0}
<div class="box-header text-white">{if $_c['pppoe_plan']==''}PPPOE Plan{else}{$_c['pppoe_plan']}{/if}</div>
<div class="box-body row">
{foreach $plans_pppoe as $plan}
{if $router['name'] eq $plan['routers']}
<div class="col col-md-4">
<div class="box box- box-primary">
<div class="box-header text-bold text-center">{$plan['name_plan']}</div>
<div class="table-responsive">
<table class="table table-bordered table-striped">
<tbody>
<tr>
<td>{Lang::T('Type')}</td>
<td>{$plan['type']}</td>
</tr>
<tr>
<td>{Lang::T('Price')}</td>
<td>{Lang::moneyFormat($plan['price'])}</td>
</tr>
<tr>
<td>{Lang::T('Validity')}</td>
<td>{$plan['validity']} {$plan['validity_unit']}</td>
</tr>
</tbody>
</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-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>
{if $_c['enable_balance'] == 'yes' && $_c['allow_balance_transfer'] == 'yes' && $_user['balance']>=$plan['price']}
<a href="{$_url}order/send/{$router['id']}/{$plan['id']}"
onclick="return confirm('{Lang::T('Buy this for friend account?')}')"
class="btn btn-sm btn-block btn-primary">{Lang::T('Buy for friend')}</a>
{/if}
</div>
</div>
</div>
{/if}
{/foreach}
</div>
{/if}
</div>
{if Validator::isRouterHasPlan($plans_hotspot, $router['name']) || Validator::isRouterHasPlan($plans_pppoe, $router['name'])}
<div class="box box-solid box-primary bg-gray">
<div class="box-header text-white text-bold">{$router['name']}</div>
{if $router['description'] != ''}
<div class="box-body">
{$router['description']}
</div>
{/if}
{if $_user['service_type'] == 'Hotspot' && Validator::countRouterPlan($plans_hotspot, $router['name'])>0}
<div class="box-header text-white">{if $_c['hotspot_plan']==''}Hotspot Plan{else}{$_c['hotspot_plan']}{/if}</div>
<div class="box-body row">
{foreach $plans_hotspot as $plan}
{if $router['name'] eq $plan['routers']}
<div class="col col-md-4">
<div class="box box-primary">
<div class="box-header text-center text-bold">{$plan['name_plan']}</div>
<div class="table-responsive">
<table class="table table-bordered table-striped">
<tbody>
<tr>
<td>{Lang::T('Type')}</td>
<td>{$plan['type']}</td>
</tr>
<tr>
<td>{Lang::T('Price')}</td>
<td>{Lang::moneyFormat($plan['price'])}</td>
</tr>
<tr>
<td>{Lang::T('Validity')}</td>
<td>{$plan['validity']} {$plan['validity_unit']}</td>
</tr>
</tbody>
</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-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>
{if $_c['enable_balance'] == 'yes' && $_c['allow_balance_transfer'] == 'yes' && $_user['balance']>=$plan['price']}
<a href="{$_url}order/send/{$router['id']}/{$plan['id']}" onclick="return confirm('{Lang::T('Buy this for friend account?')}')" class="btn btn-sm btn-block btn-primary">{Lang::T('Buy for friend')}</a>
{/if}
</div>
</div>
</div>
{/if}
{/foreach}
</div>
{/if}
{if $_user['service_type'] == 'PPPoE' && Validator::countRouterPlan($plans_pppoe,$router['name'])>0}
<div class="box-header text-white">{if $_c['pppoe_plan']==''}PPPOE Plan{else}{$_c['pppoe_plan']}{/if}</div>
<div class="box-body row">
{foreach $plans_pppoe as $plan}
{if $router['name'] eq $plan['routers']}
<div class="col col-md-4">
<div class="box box- box-primary">
<div class="box-header text-bold text-center">{$plan['name_plan']}</div>
<div class="table-responsive">
<table class="table table-bordered table-striped">
<tbody>
<tr>
<td>{Lang::T('Type')}</td>
<td>{$plan['type']}</td>
</tr>
<tr>
<td>{Lang::T('Price')}</td>
<td>{Lang::moneyFormat($plan['price'])}</td>
</tr>
<tr>
<td>{Lang::T('Validity')}</td>
<td>{$plan['validity']} {$plan['validity_unit']}</td>
</tr>
</tbody>
</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-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>
{if $_c['enable_balance'] == 'yes' && $_c['allow_balance_transfer'] == 'yes' && $_user['balance']>=$plan['price']}
<a href="{$_url}order/send/{$router['id']}/{$plan['id']}" onclick="return confirm('{Lang::T('Buy this for friend account?')}')" class="btn btn-sm btn-block btn-primary">{Lang::T('Buy for friend')}</a>
{/if}
</div>
</div>
</div>
{/if}
{/foreach}
</div>
{/if}
{if $_user['service_type'] == 'Others' || $_user['service_type'] == '' && (Validator::countRouterPlan($plans_hotspot, $router['name'])>0 || Validator::countRouterPlan($plans_pppoe, $router['name'])>0)}
<div class="box-header text-white">{if $_c['hotspot_plan']==''}Hotspot Plan{else}{$_c['hotspot_plan']}{/if}</div>
<div class="box-body row">
{foreach $plans_hotspot as $plan}
{if $router['name'] eq $plan['routers']}
<div class="col col-md-4">
<div class="box box-primary">
<div class="box-header text-center text-bold">{$plan['name_plan']}</div>
<div class="table-responsive">
<table class="table table-bordered table-striped">
<tbody>
<tr>
<td>{Lang::T('Type')}</td>
<td>{$plan['type']}</td>
</tr>
<tr>
<td>{Lang::T('Price')}</td>
<td>{Lang::moneyFormat($plan['price'])}</td>
</tr>
<tr>
<td>{Lang::T('Validity')}</td>
<td>{$plan['validity']} {$plan['validity_unit']}</td>
</tr>
</tbody>
</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-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>
{if $_c['enable_balance'] == 'yes' && $_c['allow_balance_transfer'] == 'yes' && $_user['balance']>=$plan['price']}
<a href="{$_url}order/send/{$router['id']}/{$plan['id']}" onclick="return confirm('{Lang::T('Buy this for friend account?')}')" class="btn btn-sm btn-block btn-primary">{Lang::T('Buy for friend')}</a>
{/if}
</div>
</div>
</div>
{/if}
{/foreach}
</div>
<div class="box-header text-white">{if $_c['pppoe_plan']==''}PPPOE Plan{else}{$_c['pppoe_plan']}{/if}</div>
<div class="box-body row">
{foreach $plans_pppoe as $plan}
{if $router['name'] eq $plan['routers']}
<div class="col col-md-4">
<div class="box box- box-primary">
<div class="box-header text-bold text-center">{$plan['name_plan']}</div>
<div class="table-responsive">
<table class="table table-bordered table-striped">
<tbody>
<tr>
<td>{Lang::T('Type')}</td>
<td>{$plan['type']}</td>
</tr>
<tr>
<td>{Lang::T('Price')}</td>
<td>{Lang::moneyFormat($plan['price'])}</td>
</tr>
<tr>
<td>{Lang::T('Validity')}</td>
<td>{$plan['validity']} {$plan['validity_unit']}</td>
</tr>
</tbody>
</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-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>
{if $_c['enable_balance'] == 'yes' && $_c['allow_balance_transfer'] == 'yes' && $_user['balance']>=$plan['price']}
<a href="{$_url}order/send/{$router['id']}/{$plan['id']}" onclick="return confirm('{Lang::T('Buy this for friend account?')}')" class="btn btn-sm btn-block btn-primary">{Lang::T('Buy for friend')}</a>
{/if}
</div>
</div>
</div>
{/if}
{/foreach}
</div>
{/if}
</div>
{/if}
{/foreach}
</div>
</div>
</div>
{include file="sections/user-footer.tpl"}

View File

@ -31,21 +31,41 @@
</select>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{$_L['Number_of_Vouchers']}</label>
<div class="col-md-6">
<input type="text" class="form-control" name="numbervoucher" value="1">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Voucher Format')}</label>
<div class="col-md-6">
<select name="voucher_format" id="voucher_format" class="form-control">
<option value="up" {if $_c['voucher_format'] == 'up'}selected="selected" {/if}>UPPERCASE
</option>
<option value="low" {if $_c['voucher_format'] == 'low'}selected="selected" {/if}>
lowercase
</option>
<option value="rand" {if $_c['voucher_format'] == 'rand'}selected="selected" {/if}>
RaNdoM
</option>
</select>
</div>
<p class="help-block col-md-4">UPPERCASE lowercase RaNdoM</p>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Voucher Prefix')}</label>
<div class="col-md-6">
<input type="text" class="form-control" name="prefix" placeholder="NUX-" value="{$_c['voucher_prefix']}">
</div>
<p class="help-block col-md-4">NUX-VoUCHeRCOdE</p>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{$_L['Length_Code']}</label>
<div class="col-md-6">
<input type="text" class="form-control" name="lengthcode" value="12">
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<button class="btn btn-success waves-effect waves-light"

View File

@ -3,7 +3,13 @@
<div class="row">
<div class="col-sm-12">
<div class="panel panel-hovered mb20 panel-primary">
<div class="panel-heading">{$_L['Prepaid_Vouchers']}</div>
<div class="panel-heading">
<div class="btn-group pull-right">
<a class="btn btn-danger btn-xs" title="Remove used Voucher" href="{$_url}prepaid/remove-voucher" onclick="return confirm('Delete all used voucher code?')"><span
class="glyphicon glyphicon-trash" aria-hidden="true"></span> Delete All</a>
</div>
{$_L['Prepaid_Vouchers']}
</div>
<div class="panel-body">
<div class="md-whiteframe-z1 mb20 text-center" style="padding: 15px">
<div class="col-md-8">

View File

@ -184,8 +184,8 @@ function deleteFolder($path)
<link rel="stylesheet" href="ui/ui/fonts/font-awesome/css/font-awesome.min.css">
<link rel="stylesheet" href="ui/ui/fonts/MaterialDesign/css/materialdesignicons.min.css">
<link rel="stylesheet" href="ui/ui/styles/adminlte.min.css">
<link rel="stylesheet" href="ui/ui/styles/skin-blue.min.css">
<link rel="stylesheet" href="ui/ui/styles/modern-AdminLTE.min.css">
<?php if ($continue) { ?>
<meta http-equiv="refresh" content="3; ./update.php?step=<?= $step ?>">
<?php } ?>

View File

@ -1,3 +1,3 @@
{
"version": "2023.11.17"
"version": "2024.2.7"
}