Compare commits

..

142 Commits

Author SHA1 Message Date
fb4901be9f add log when extend expiraton 2024-04-15 14:35:36 +07:00
a164b345b6 dont send if message empty 2024-04-15 14:30:51 +07:00
8f07c7640c edit changelog 2024-04-15 14:15:15 +07:00
8891cd5aaa allow extend expired for postpaid customer 2024-04-15 14:09:02 +07:00
854fd54834 delete $_c = $config; as it already exists in init.php 2024-04-15 14:08:34 +07:00
21876601ba Hide Tax Settings as it still have a bug 2024-04-15 11:13:19 +07:00
6955d3fd8b Merge pull request #173 from Focuslinkstech/Development
Update: Tax System
2024-04-15 09:10:08 +07:00
d6510dffa7 Merge pull request #175 from agstrxyz/patch-9
Update home.php
2024-04-15 09:07:01 +07:00
419595554b Update home.php
fix token to prevent double recharge
2024-04-15 09:06:26 +07:00
bcc84aed9a Merge pull request #174 from agstrxyz/patch-8
Update cron.php
2024-04-15 09:01:02 +07:00
05caee1193 Merge branch 'Development' into patch-8 2024-04-15 09:00:53 +07:00
071feb3a48 Merge pull request #172 from ahmadhusein17/patch-19
Update cron.php
2024-04-15 08:54:48 +07:00
a5774fe335 Merge pull request #171 from ahmadhusein17/patch-18
Update cron_reminder.php
2024-04-15 08:53:13 +07:00
92a2690ec6 Update home.php 2024-04-14 21:13:11 +07:00
519bef21e0 Update home.php
fix user self recharge in user dashboard for radius plan base
2024-04-14 06:45:45 +07:00
1a40606720 Update cron.php
Fix auto renewal radius plan based
2024-04-14 06:40:47 +07:00
eff79df39a Update customers.tpl
add length Menu  5, 10, 25, 50, 100 and All, as suggested by one of our member and also use 5 as default page length to make the page fit the screen when loaded
2024-04-13 18:19:09 +01:00
425ed2362b Update: Tax System
Tax System Feature Added

The Tax System feature allows you to apply taxes to the prices of Internet plans. This feature is useful for businesses that are required to collect taxes on their services. With the Tax System, you can define tax rates based on your local tax regulations.

Enable Tax System: Choose whether to enable or disable the Tax System. When enabled, taxes will be calculated and added to the prices of Internet plans.

Tax Rate: Select from predefined tax rates such as 0.5%, 1%, 1.5%, 2%, 5%, and 10%. These rates are commonly used and can be selected easily.

Custom Tax Rate: If you have a specific tax rate that is not listed, you can enter a custom tax rate. This allows flexibility in configuring the tax rate to match your local tax requirements.
2024-04-12 19:42:12 +01:00
1fdf1d9573 Update cron.php
Changes made:
 1. Use the $recharges variable to hold the query results to clarify the context.
 2. Use the ternary operator to determine whether the application is running in a CLI environment or not
 3. Simplify the logic by combining several redundant code blocks.
 4. Unify Mikrotik client retrieval logic based on type (Hotspot or PPPOE) to reduce code duplication.
 5. Tidy up the indents to make them consistent and easier to read.
2024-04-08 21:21:54 +07:00
b893827463 Update cron_reminder.php
Improve the writing so that it is easy to read and understand (⁠.⁠ ⁠❛⁠ ⁠ᴗ⁠ ⁠❛⁠.⁠)
2024-04-08 21:12:01 +07:00
aa756fceb1 Merge pull request #166 from ahmadhusein17/patch-12
Update indonesia.json
2024-04-08 20:19:22 +07:00
186dd5571f Merge pull request #162 from ahmadhusein17/patch-9
Update user-login.tpl
2024-04-06 15:14:43 +07:00
14067f2917 Merge pull request #163 from ahmadhusein17/patch-10
Update voucher.tpl
2024-04-06 15:13:48 +07:00
887a0185fa Merge pull request #165 from ahmadhusein17/patch-13
Update header.tpl
2024-04-06 15:13:02 +07:00
88969526be Merge pull request #168 from ahmadhusein17/patch-15
Update app-notifications.tpl
2024-04-06 15:12:40 +07:00
eb18eebc8c Merge pull request #169 from ahmadhusein17/patch-16
Update indonesia.json
2024-04-06 15:11:51 +07:00
e274ca82b0 Merge branch 'Development' into patch-16 2024-04-06 15:11:40 +07:00
9ec8b54435 Merge pull request #167 from ahmadhusein17/patch-14
Update indonesia.json
2024-04-06 15:10:37 +07:00
9dba708c2c Update indonesia.json 2024-04-06 00:33:29 +07:00
cbbb77b636 Update app-notifications.tpl
Add language to the placeholder
2024-04-06 00:29:45 +07:00
1733472ad1 Update indonesia.json
Add language to customer notifications
2024-04-06 00:01:37 +07:00
11c111805d Update header.tpl
Additional Privacy and toc translations
2024-04-05 23:22:59 +07:00
4c35e79a16 Update indonesia.json
Language improvements and additions
2024-04-05 23:20:59 +07:00
fc1cc54378 Update voucher.tpl
Fix unresponsive buttons on mobile phone display
2024-04-05 22:02:26 +07:00
f62e7707a1 Update user-login.tpl
Add a lock icon to the password
2024-04-05 21:35:19 +07:00
bab56be9c7 change to username if country code empty 2024-04-05 18:01:11 +07:00
0422c1e9bb allow [[plan]] and [[package]] to be replaced with plan name 2024-04-05 17:37:41 +07:00
1f5033b471 remove [[bills]] if there no bills found 2024-04-05 17:21:06 +07:00
53a309fee8 Fix recharge friend 2024-04-05 11:18:28 +07:00
766ba59734 add new field trx_invoice to tbl_payment_gateway, to know which transaction is for 2024-04-05 10:42:30 +07:00
2e3e5d2b84 add new variable to notification settings 2024-04-05 09:43:07 +07:00
e285e53887 Total Bills 2024-04-05 09:40:11 +07:00
afd75d757e add full name in invoice 2024-04-05 09:35:05 +07:00
006693982b fix sending notif package 2024-04-04 17:42:28 +07:00
71437b9a0e Prevent double submit for recharge and renew 2024-04-04 15:27:13 +07:00
eba6048abf Add Bills to Reminder 2024-04-04 15:02:16 +07:00
f97651695d add Note to reminder 2024-04-04 15:01:45 +07:00
72c3ff6750 Lang Internet Plan 2024-04-04 14:53:11 +07:00
787f666efe Merge pull request #161 from Focuslinkstech/Development
Patch Update
2024-04-04 14:52:20 +07:00
5db8df0c3e Patch Update
customers list tables replaced with DataTables
2024-04-03 23:39:31 +01:00
f77c96f3c3 Change to Username if Country code empty 2024-04-03 11:14:50 +07:00
ffd9f2e524 Merge pull request #160 from agstrxyz/patch-6
Update logs-radius.tpl
2024-04-03 10:32:24 +07:00
366208d6d1 Merge pull request #159 from agstrxyz/patch-5
Update logs.tpl
2024-04-03 10:31:55 +07:00
db28570610 Merge pull request #158 from agstrxyz/patch-4
Update logs.php
2024-04-03 10:31:23 +07:00
feaf88fc00 Update logs-radius.tpl
add export to csv button
2024-04-03 02:37:09 +07:00
4bd5e399de Update logs.tpl
add export to csv button
2024-04-03 02:34:39 +07:00
76047a6b39 Update logs.php
Export to csv
2024-04-03 02:32:30 +07:00
68c9ab0b2e 2024.4.2 2024-04-02 14:08:03 +07:00
198dfee3cc fix package 2024-04-02 10:23:06 +07:00
5161874cf2 $ui->display will show json for api 2024-04-01 13:48:58 +07:00
254fd4ccf7 fix rest api, need to change every variable to readable 2024-04-01 13:01:21 +07:00
ee73621c85 Found lazy way to create api 2024-03-31 21:23:19 +07:00
4bf6f9c0ac Fix API Structure 2024-03-30 12:04:30 +07:00
3a2e7c9192 remove $_L 2024-03-30 12:03:12 +07:00
dcbb9434d6 Merge pull request #155 from Focuslinkstech/Development
Update hotspot.tpl
2024-03-29 16:49:09 +07:00
faca5d0359 Merge pull request #154 from gerandonk/Development
Fix Ip Log for cloudflare tunnel
2024-03-29 16:38:27 +07:00
aeddc86796 Merge pull request #153 from ahmadhusein17/patch-8
Update indonesia.json
2024-03-29 16:37:53 +07:00
c34a34ee8e Update hotspot.tpl
List rearrangement
2024-03-28 23:31:53 +01:00
7b0bc12e98 Fix Ip Log for cloudflare tunnel 2024-03-28 23:20:14 +07:00
8ff84b2c01 Update indonesia.json
Language improvements
2024-03-28 20:03:45 +07:00
954a49978c Show Personal/Bussines in Plan Customer Dashboard 2024-03-28 18:55:10 +07:00
773cfe0139 update Client.php routerOS 2024-03-28 18:53:41 +07:00
7eae86d861 Merge pull request #150 from agstrxyz/patch-1
Update indonesia.json
2024-03-28 18:44:28 +07:00
ea9974f668 Merge pull request #152 from ahmadhusein17/master
Update english.json
2024-03-28 18:43:52 +07:00
eda1750608 Merge pull request #151 from ahmadhusein17/Development
Language improvements
2024-03-28 18:43:40 +07:00
9a1c264173 Merge branch 'Development' into Development 2024-03-28 18:43:32 +07:00
6865b388d0 Merge branch 'Development' into master 2024-03-28 18:41:33 +07:00
ef15ec0ae2 Send Email Function 2024-03-27 14:32:55 +07:00
e0d21e6284 price + $add_cost in telegram 2024-03-27 11:42:17 +07:00
37a7da614e Fixing Pagination, more Simple 2024-03-27 09:44:48 +07:00
e11ab5ba01 remove print_r 2024-03-26 15:46:45 +07:00
0767c6ab23 Change paginator, to make easy customization using pagination.tpl 2024-03-26 14:39:28 +07:00
8e90cf933b Update english.json
Language improvements
2024-03-26 00:47:57 +07:00
a5ffee688c Language improvements 2024-03-26 00:40:54 +07:00
36a24238ef Fix Cancel 2024-03-25 10:27:06 +07:00
7eda29d02c Update indonesia.json 2024-03-24 19:20:54 +07:00
e709ea4353 fix maps when http 2024-03-24 13:39:00 +07:00
18967b59e2 Handle Http for maps 2024-03-24 13:35:31 +07:00
3c2ca66b48 fix sql 2024-03-23 17:46:20 +07:00
63c364a6c5 Merge pull request #149 from siavashmirtaheri/patch-1
Update country.json Iran-Persian
2024-03-23 17:45:33 +07:00
338861a630 Change to icon 2024-03-23 15:34:44 +07:00
90f72852ca Update country.json
IR translate start
2024-03-23 11:45:58 +03:30
5426d9f35f show maps on customer view 2024-03-23 12:56:25 +07:00
58c4037d8c full height maps 2024-03-23 12:44:17 +07:00
04a21d3eb2 Maps always show Tooltip 2024-03-23 12:38:23 +07:00
273d98f3ad map-customer.tpl to customer-map.tpl 2024-03-23 12:16:42 +07:00
177cdef1cd Add Location Picker 2024-03-22 21:21:23 +07:00
ffe913cb8f .htaccess allow update.php 2024-03-22 20:29:05 +07:00
75955de6c5 Fix Broadcast Message by @Focuslinkstech 2024-03-22 10:40:51 +07:00
11d97c153f Merge pull request #142 from Focuslinkstech/Development
bulk SMS/WA message improvement
2024-03-22 10:30:56 +07:00
44cded581a Enhancement in bulk SMS/WA message
Enhancement in  SMS/WA message sending
2024-03-21 16:52:52 +01:00
b8ae562367 2024.3.20 2024-03-20 16:06:42 +07:00
d6bcb4edfc Merge branch 'master' into Development 2024-03-20 09:55:27 +07:00
5d16ff9484 show prepaid or postpaid in list 2024-03-20 09:54:48 +07:00
c1f815535d compiled folder missing in installation 2024-03-20 09:29:40 +07:00
37a8187f5a delete unused file 2024-03-20 09:28:10 +07:00
ec5aeedd1b Merge pull request #140 from gerandonk/Development
fix validity period is more than one month
2024-03-20 09:28:00 +07:00
7dd27e3080 Merge pull request #139 from Focuslinkstech/Development
Update message.php
2024-03-20 09:27:47 +07:00
93ca9fa586 Update customers-view.tpl
add account type
2024-03-19 19:23:34 +01:00
de302d2656 Update customers-add.tpl
fix customer add
2024-03-19 18:59:05 +01:00
4d8cec1a88 Merge branch 'hotspotbilling:Development' into Development 2024-03-19 18:46:54 +01:00
477dd11caa fix validity period is more than one month 2024-03-19 23:54:49 +07:00
36eb5ebd3b fix 1 payment gateway 2024-03-19 20:47:31 +07:00
6e2e907d85 move account_type 2024-03-19 19:05:35 +07:00
c460cdd2d6 Merge branch 'master' into Development 2024-03-19 19:00:21 +07:00
5b7683ae30 Update message.php
fix placeholder bugs
2024-03-19 12:27:38 +01:00
ea743b6db6 update plan type 2024-03-19 18:21:38 +07:00
1a165662ca Merge pull request #136 from Focuslinkstech/Development
Update map-customer.tpl
2024-03-19 18:10:54 +07:00
21058d5c4e Update map-customer.tpl
fix Map
2024-03-19 09:08:30 +01:00
af3995b421 plan price to Note 2024-03-19 11:38:32 +07:00
e9240f462d Merge branch 'development' 2024-03-19 11:05:42 +07:00
5b3be79420 2024.3.19 2024-03-19 11:05:08 +07:00
8f595af9a1 Fix map url 2024-03-19 10:22:54 +07:00
393a1195a5 Merge pull request #135 from pro-cms/master
Added Business/Personal System
2024-03-19 09:46:16 +07:00
0dd12b717d Merge branch 'Development' into master 2024-03-19 09:46:08 +07:00
d7d6709944 Merge pull request #134 from ahmadhusein17/patch-3
Update message-bulk.tpl
2024-03-19 09:41:25 +07:00
ef187817cf Merge pull request #131 from Focuslinkstech/Development
add send message button
2024-03-19 09:36:40 +07:00
24e45db017 break; the line 2024-03-19 09:34:28 +07:00
0a67ea25b5 Update phpnuxbill.sql
add coordinates
2024-03-19 01:10:19 +01:00
f27964dde6 map and customer geo location added
added map and customer geo location, we advice you to change/edit the customer coordinates according to their location, so that you can see where the customer is located on the Map
2024-03-19 00:59:34 +01:00
5b0e782efd fix syntax phpnuxbill.sql 2024-03-19 00:12:38 +03:00
865df09116 fixed account type ui 2024-03-18 23:28:16 +03:00
f44d800400 edit ,add customer type 2024-03-18 23:25:39 +03:00
aae5b58d57 added edit customer account type 2024-03-18 23:23:52 +03:00
19d60da919 added plan type to order user account 2024-03-18 23:12:23 +03:00
7be8552784 added plan type to service class 2024-03-18 22:55:08 +03:00
b92efe3d30 added plan type to front ui 2024-03-18 22:50:46 +03:00
f769e7b798 added plan type to listing 2024-03-18 22:40:27 +03:00
15ae5c844f added plan_type and account_type 2024-03-18 22:33:10 +03:00
0aff5f437a Update message-bulk.tpl
Removed translation in placeholder contents
2024-03-18 19:57:55 +07:00
605fbb73a6 fix translation error
fix translation error
2024-03-18 13:52:33 +01:00
3d2af75e5b add send message button
add send message button in customer
 view details
2024-03-18 12:28:54 +01:00
84 changed files with 9654 additions and 1799 deletions

1
.gitignore vendored
View File

@ -39,3 +39,4 @@ system/lan/**
!system/lan/turkish.json
!system/lan/english.json
!system/lan/country.json
*.zip

View File

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

View File

@ -2,6 +2,59 @@
# CHANGELOG
## 2024.4.15
- Postpaid Customer can request extends expiration day if it enabled
- Some Code Fixing by @ahmadhusein17 and @agstrxyz
## 2024.4.4
- Data Tables for Customers List by @Focuslinkstech
- Add Bills to Reminder
- Prevent double submit for recharge and renew
## 2024.4.3
- Export logs to CSV by @agstrxyz
- Change to Username if Country code empty
## 2024.4.2
- Fix REST API
- Fix Log IP Cloudflare by @Gerandonk
- Show Personal or Business in customer dashboard
## 2024.3.26
- Change paginator, to make easy customization using pagination.tpl
## 2024.3.25
- Fix maps on HTTP
- Fix Cancel payment
## 2024.3.23
- Maps full height
- Show Get Directions instead Coordinates
- Maps Label always show
## 2024.3.22
- Fix Broadcast Message by @Focuslinkstech
- Add Location Picker
## 2024.3.20
- Fixing some bugs
## 2024.3.19
- Add Customer Type Personal or Bussiness by @pro-cms
- Fix Broadcast Message by @Focuslinkstech
- Add Customer Geolocation by @Focuslinkstech
- Change Customer Menu
## 2024.3.18
- Add Broadcasting SMS by @Focuslinkstech

View File

@ -11,7 +11,9 @@ if (realpath(__FILE__) == realpath($_SERVER['SCRIPT_FILENAME'])) {
die();
}
$root_path = realpath(dirname(__FILE__)) . DIRECTORY_SEPARATOR;
if(!isset($isApi)){
$isApi = false;
}
// on some server, it getting error because of slash is backwards
function _autoloader($class)
{
@ -71,8 +73,11 @@ ORM::configure('return_result_sets', true);
if ($_app_stage != 'Live') {
ORM::configure('logging', true);
}
if($isApi){
define('U', APP_URL . '/system/api.php?r=');
}else{
define('U', APP_URL . '/index.php?_route=');
}
// notification message
if (file_exists($UPLOAD_PATH . DIRECTORY_SEPARATOR . "notifications.json")) {
@ -195,7 +200,18 @@ function _log($description, $type = '', $userid = '0')
$d->type = $type;
$d->description = $description;
$d->userid = $userid;
if (!empty($_SERVER['HTTP_CF_CONNECTING_IP'])) //to check ip is pass from cloudflare tunnel
{
$d->ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) //to check ip is pass from proxy
{
$d->ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} elseif (!empty($_SERVER['HTTP_CLIENT_IP'])) //to check ip from share internet
{
$d->ip = $_SERVER['HTTP_CLIENT_IP'];
} else {
$d->ip = $_SERVER["REMOTE_ADDR"];
}
$d->save();
}
@ -209,6 +225,13 @@ function alphanumeric($str, $tambahan = "")
return preg_replace("/[^a-zA-Z0-9" . $tambahan . "]+/", "", $str);
}
function showResult($success, $message = '', $result = [], $meta = [])
{
header("Content-Type: Application/json");
$json = json_encode(['success' => $success, 'message' => $message, 'result' => $result, 'meta' => $meta]);
echo $json;
die();
}
function sendTelegram($txt)
{
@ -227,6 +250,13 @@ function sendWhatsapp($phone, $txt)
function r2($to, $ntype = 'e', $msg = '')
{
global $isApi;
if ($isApi) {
showResult(
($ntype=='s')? true : false,
$msg
);
}
if ($msg == '') {
header("location: $to");
exit;
@ -239,7 +269,13 @@ function r2($to, $ntype = 'e', $msg = '')
function _alert($text, $type = 'success', $url = "home", $time = 3)
{
global $ui;
global $ui, $isApi;
if ($isApi) {
showResult(
($type == 'success') ? true : false,
$text
);
}
if (!isset($ui)) return;
if (strlen($url) > 4) {
if (substr($url, 0, 4) != "http") {

View File

@ -21,13 +21,15 @@ CREATE TABLE `tbl_customers` (
`id` int(10) NOT NULL,
`username` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`password` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`pppoe_password` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1' COMMENT 'For PPPOE Login',
`pppoe_password` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login',
`fullname` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`address` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
`phonenumber` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0',
`email` varchar(128) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1',
`coordinates` VARCHAR(50) NOT NULL DEFAULT '' COMMENT 'Latitude and Longitude coordinates',
`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',
`account_type` ENUM('Business', 'Personal') DEFAULT 'Personal' COMMENT 'For selecting account 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
@ -97,8 +99,9 @@ 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',
`allow_purchase` enum('yes','no') DEFAULT 'yes' COMMENT 'allow to show package in buy package page'
`enabled` tinyint(1) NOT NULL DEFAULT '1' COMMENT '0 disabled',
`allow_purchase` enum('yes','no') DEFAULT 'yes' COMMENT 'allow to show package in buy package page',
`plan_type` ENUM('Business', 'Personal') DEFAULT 'Personal' COMMENT 'For switching plan according to user type'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
DROP TABLE IF EXISTS `tbl_pool`;
@ -318,3 +321,4 @@ ALTER TABLE `tbl_transactions` ADD `admin_id` INT NOT NULL DEFAULT '1' AFTER `ty
ALTER TABLE `tbl_user_recharges` ADD `admin_id` INT NOT NULL DEFAULT '1' AFTER `type`;
ALTER TABLE `tbl_plans` CHANGE `allow_purchase` `prepaid` ENUM('yes','no') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'yes' COMMENT 'is prepaid';
ALTER TABLE `tbl_transactions` ADD `note` VARCHAR(256) NOT NULL DEFAULT '' COMMENT 'for note' AFTER `type`;
ALTER TABLE `tbl_payment_gateway` ADD `trx_invoice` VARCHAR(25) NOT NULL DEFAULT '' COMMENT 'from tbl_transactions' AFTER `paid_date`;

View File

@ -15,42 +15,51 @@ if ($_SERVER['REQUEST_METHOD'] === "OPTIONS" || $_SERVER['REQUEST_METHOD'] === "
die();
}
include "../init.php";
$isApi = true;
include "../init.php";
// Dummy Class
$ui = new class($key)
{
var $assign = [];
function display($key)
{
global $req;
showResult(true, $req, $this->getAll());
}
function assign($key, $value)
{
$this->assign[$key] = $value;
}
function get($key, )
function get($key)
{
if (isset($this->assign[$key])) {
return $this->assign[$key];
}
return '';
}
function getTemplateVars($key)
{
if (isset($this->assign[$key])) {
return $this->assign[$key];
}
return '';
}
function getAll()
{
return $this->assign;
}
};
$req = _get('r');
# a/c.id.time.md5
# md5(a/c.id.time.$api_secret)
$token = _get('token');
$token = _req('token');
$routes = explode('/', $req);
$handler = $routes[0];
if(empty($token)){
showResult(false, Lang::T("Token is invalid"));
}
if (!empty($token)) {
if ($token == $config['api_key']) {
$admin = ORM::for_table('tbl_users')->where('user_type', 'SuperAdmin')->find_one($id);
if (empty($admin)) {
@ -61,18 +70,21 @@ if($token == $config['api_key']){
}
} else {
# validate token
list($tipe, $uid, $time, $md5) = explode('.', $token);
if ($md5 != md5($uid . '.' . $time . '.' . $api_secret)) {
list($tipe, $uid, $time, $sha1) = explode('.', $token);
if (trim($sha1) != sha1($uid . '.' . $time . '.' . $api_secret)) {
showResult(false, Lang::T("Token is invalid"));
}
#cek token expiration
if ($time != 0 && time() > $time) {
// 3 bulan
if ($time != 0 && time() - $time > 7776000) {
die("$time != " . (time() - $time));
showResult(false, Lang::T("Token Expired"), [], ['login' => true]);
}
if ($tipe == 'a') {
$_SESSION['aid'] = $uid;
$admin = Admin::_info();
} else if ($tipe == 'c') {
$_SESSION['uid'] = $uid;
} else {
@ -89,16 +101,24 @@ if($handler == 'isValid'){
showResult(true, Lang::T("Token is valid"));
}
function showResult($success, $message = '', $result = [], $meta = [])
{
header("Content-Type: Application/json; charset=utf-8");
die(json_encode(array('success' => $success, 'message' => $message, 'result' => $result, 'meta' => $meta)));
if ($handler == 'me') {
$admin = Admin::_info();
if (!empty($admin['id'])) {
showResult(true, "", $admin);
} else {
showResult(false, Lang::T("Token is invalid"));
}
}
}else{
unset($_COOKIE);
unset($_SESSION);
}
try {
$sys_render = File::pathFixer($root_path . 'system/controllers/' . $handler . '.php');
if (file_exists($sys_render)) {
include($sys_render);
showResult(true, $req, $ui->getAll());
} else {
showResult(false, Lang::T('Command not found'));
}

View File

@ -32,10 +32,14 @@ class Admin
global $db_password;
if (isset($aid)) {
$time = time();
setcookie('aid', $aid . '.' . $time . '.' . sha1($aid . '.' . $time . '.' . $db_password), time() + 86400 * 7);
$token = $aid . '.' . $time . '.' . sha1($aid . '.' . $time . '.' . $db_password);
setcookie('aid', $token, time() + 86400 * 7);
return $token;
}
return '';
}
public static function removeCookie()
{
if (isset($_COOKIE['aid'])) {

View File

@ -10,4 +10,20 @@ class App{
return true;
}
public static function getToken(){
return md5(microtime());
}
public static function setToken($token, $value){
$_SESSION[$token] = $value;
}
public static function getTokenValue($key){
if(isset($_SESSION[$key])){
return $_SESSION[$key];
}else{
return "";
}
}
}

View File

@ -5,6 +5,12 @@
* by https://t.me/ibnux
**/
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\SMTP;
require $root_path . 'system/autoload/mail/Exception.php';
require $root_path . 'system/autoload/mail/PHPMailer.php';
require $root_path . 'system/autoload/mail/SMTP.php';
class Message
{
@ -22,6 +28,9 @@ class Message
public static function sendSMS($phone, $txt)
{
global $config;
if(empty($txt)){
return "";
}
run_hook('send_sms'); #HOOK
if (!empty($config['sms_url'])) {
if (strlen($config['sms_url']) > 4 && substr($config['sms_url'], 0, 4) != "http") {
@ -58,6 +67,9 @@ class Message
public static function sendWhatsapp($phone, $txt)
{
global $config;
if(empty($txt)){
return "";
}
run_hook('send_whatsapp'); #HOOK
if (!empty($config['wa_url'])) {
$waurl = str_replace('[number]', urlencode(Lang::phoneFormat($phone)), $config['wa_url']);
@ -66,13 +78,69 @@ class Message
}
}
public static function sendEmail($to, $subject, $body)
{
global $config;
if(empty($body)){
return "";
}
run_hook('send_email'); #HOOK
if (empty($config['smtp_host'])) {
$attr = "";
if (!empty($config['mail_from'])) {
$attr .= "From: " . $config['mail_from'] . "\r\n";
}
if (!empty($config['mail_reply_to'])) {
$attr .= "Reply-To: " . $config['mail_reply_to'] . "\r\n";
}
mail($to, $subject, $body, $attr);
} else {
$mail = new PHPMailer();
$mail->isSMTP();
$mail->SMTPDebug = SMTP::DEBUG_SERVER;
$mail->Host = $config['smtp_host'];
$mail->SMTPAuth = true;
$mail->Username = $config['smtp_user'];
$mail->Password = $config['smtp_pass'];
$mail->SMTPSecure = $config['smtp_ssltls'];
$mail->Port = $config['smtp_port'];
if (!empty($config['mail_from'])) {
$mail->setFrom($config['mail_from']);
}
if (!empty($config['mail_reply_to'])) {
$mail->addReplyTo($config['mail_reply_to']);
}
$mail->isHTML(false);
$mail->addAddress($to);
$mail->Subject = $subject;
$mail->Body = $body;
$mail->send();
die();
}
}
public static function sendPackageNotification($customer, $package, $price, $message, $via)
{
global $u;
if(empty($message)){
return "";
}
$msg = str_replace('[[name]]', $customer['fullname'], $message);
$msg = str_replace('[[username]]', $customer['username'], $msg);
$msg = str_replace('[[plan]]', $package, $msg);
$msg = str_replace('[[package]]', $package, $msg);
$msg = str_replace('[[price]]', $price, $msg);
$msg = str_replace('[[price]]', Lang::moneyFormat($price), $msg);
list($bills, $add_cost) = User::getBills($customer['id']);
if($add_cost>0){
$note = "";
foreach ($bills as $k => $v) {
$note .= $k . " : " . Lang::moneyFormat($v) . "\n";
}
$note .= "Total : " . Lang::moneyFormat($add_cost+$price) . "\n";
$msg = str_replace('[[bills]]', $note, $msg);
}else{
$msg = str_replace('[[bills]]', '', $msg);
}
if ($u) {
$msg = str_replace('[[expired_date]]', Lang::dateAndTimeFormat($u['expiration'], $u['time']), $msg);
}
@ -81,9 +149,9 @@ class Message
&& !empty($message) && in_array($via, ['sms', 'wa'])
) {
if ($via == 'sms') {
Message::sendSMS($customer['phonenumber'], $msg);
echo Message::sendSMS($customer['phonenumber'], $msg);
} else if ($via == 'wa') {
Message::sendWhatsapp($customer['phonenumber'], $msg);
echo Message::sendWhatsapp($customer['phonenumber'], $msg);
}
}
return "$via: $msg";

View File

@ -19,21 +19,25 @@
/**
* The namespace declaration.
*/
namespace PEAR2\Net\RouterOS;
/**
* Refers to transmitter direction constants.
*/
use PEAR2\Net\Transmitter\Stream as S;
/**
* Refers to the cryptography constants.
*/
use PEAR2\Net\Transmitter\NetworkStream as N;
/**
* Catches arbitrary exceptions at some points.
*/
use Exception as E;
/**
@ -108,11 +112,12 @@ class Client
protected $registry = null;
/**
* Whether to stream future responses.
* Stream response words that are above this many bytes.
* NULL to disable streaming completely.
*
* @var bool
* @var int|null
*/
private $_streamingResponses = false;
private $_streamingResponses = null;
/**
* Creates a new instance of a RouterOS API client.
@ -233,7 +238,8 @@ class Client
$password = '',
$timeout = null
) {
if (null !== ($remoteCharset = $com->getCharset($com::CHARSET_REMOTE))
if (
null !== ($remoteCharset = $com->getCharset($com::CHARSET_REMOTE))
&& null !== ($localCharset = $com->getCharset($com::CHARSET_LOCAL))
) {
$password = iconv(
@ -287,31 +293,48 @@ class Client
$timeout = null
) {
$request = new Request('/login');
$request->send($com);
$response = new Response($com, false, $timeout);
$request->setArgument('name', $username);
$request->setArgument('password', $password);
// $request->setArgument(
// 'response',
// '00' . md5(
// chr(0) . $password
// . pack('H*', $response->getProperty('ret'))
// )
// );
$oldCharset = $com->getCharset($com::CHARSET_ALL);
$com->setCharset(null, $com::CHARSET_ALL);
$request->verify($com)->send($com);
$com->setCharset($oldCharset, $com::CHARSET_ALL);
$response = new Response($com, false, $timeout);
if (
$response->getType() === Response::TYPE_FINAL
&& null === $response->getProperty('ret')
) {
// version >= 6.43
return null === $response->getProperty('message');
} elseif ($response->getType() === Response::TYPE_FINAL) {
// version < 6.43
$request->setArgument('password', '');
$request->setArgument(
'response',
'00' . md5(
chr(0) . $password
. pack(
'H*',
is_string($response->getProperty('ret'))
? $response->getProperty('ret')
: stream_get_contents($response->getProperty('ret'))
)
)
);
$request->verify($com)->send($com);
$response = new Response($com, false, $timeout);
if ($response->getType() === Response::TYPE_FINAL) {
return null === $response->getProperty('ret');
} else {
while ($response->getType() !== Response::TYPE_FINAL
}
}
while (
$response->getType() !== Response::TYPE_FINAL
&& $response->getType() !== Response::TYPE_FATAL
) {
$response = new Response($com, false, $timeout);
}
return false;
}
}
/**
* Sets the charset(s) for this connection.
@ -322,7 +345,7 @@ class Client
* {@link Communicator::CHARSET_REMOTE}, and when receiving,
* {@link Communicator::CHARSET_REMOTE} is converted to
* {@link Communicator::CHARSET_LOCAL}. Setting NULL to either charset will
* disable charset convertion, and data will be both sent and received "as
* disable charset conversion, and data will be both sent and received "as
* is".
*
* @param mixed $charset The charset to set. If $charsetType is
@ -387,7 +410,7 @@ class Client
{
//Error checking
$tag = $request->getTag();
if ('' == $tag) {
if ('' === (string)$tag) {
throw new DataFlowException(
'Asynchonous commands must have a tag.',
DataFlowException::CODE_TAG_REQUIRED
@ -582,7 +605,8 @@ class Client
}
} else {
list($usStart, $sStart) = explode(' ', microtime());
while ($this->getPendingRequestsCount() !== 0
while (
$this->getPendingRequestsCount() !== 0
&& ($sTimeout >= 0 || $usTimeout >= 0)
) {
$this->dispatchNextResponse($sTimeout, $usTimeout);
@ -647,7 +671,7 @@ class Client
public function cancelRequest($tag = null)
{
$cancelRequest = new Request('/cancel');
$hasTag = !('' == $tag);
$hasTag = !('' === (string)$tag);
$hasReg = null !== $this->registry;
if ($hasReg && !$hasTag) {
$tags = array_merge(
@ -703,34 +727,39 @@ class Client
/**
* Sets response streaming setting.
*
* Sets whether future responses are streamed. If responses are streamed,
* the argument values are returned as streams instead of strings. This is
* particularly useful if you expect a response that may contain one or more
* very large words.
* Sets when future response words are streamed. If a word is streamed,
* the property value is returned a stream instead of a string, and
* unrecognized words are returned entirely as streams instead of strings.
* This is particularly useful if you expect a response that may contain
* one or more very large words.
*
* @param bool $streamingResponses Whether to stream future responses.
* @param int|null $threshold Threshold after which to stream
* a word. That is, a word less than this length will not be streamed.
* If set to 0, effectively all words are streamed.
* NULL to disable streaming altogether.
*
* @return bool The previous value of the setting.
* @return $this The client object.
*
* @see isStreamingResponses()
* @see getStreamingResponses()
*/
public function setStreamingResponses($streamingResponses)
public function setStreamingResponses($threshold)
{
$oldValue = $this->_streamingResponses;
$this->_streamingResponses = (bool) $streamingResponses;
return $oldValue;
$this->_streamingResponses = $threshold === null
? null
: (int) $threshold;
return $this;
}
/**
* Gets response streaming setting.
*
* Gets whether future responses are streamed.
* Gets when future response words are streamed.
*
* @return bool The value of the setting.
* @return int|null The value of the setting.
*
* @see setStreamingResponses()
*/
public function isStreamingResponses()
public function getStreamingResponses()
{
return $this->_streamingResponses;
}
@ -822,8 +851,8 @@ class Client
* If NULL, wait indefinitely.
* @param int $usTimeout Microseconds to add to the waiting time.
*
* @throws SocketException When there's no response within the time limit.
* @return Response The dispatched response.
* @throws SocketException When there's no response within the time limit.
*/
protected function dispatchNextResponse($sTimeout = 0, $usTimeout = 0)
{
@ -846,13 +875,14 @@ class Client
$this->pendingRequestsCount--;
}
if ('' != $tag) {
if ('' !== (string)$tag) {
if ($this->isRequestActive($tag, self::FILTER_CALLBACK)) {
if ($this->callbacks[$tag]($response, $this)) {
try {
$this->cancelRequest($tag);
} catch (DataFlowException $e) {
if ($e->getCode() !== DataFlowException::CODE_UNKNOWN_REQUEST
if (
$e->getCode() !== $e::CODE_UNKNOWN_REQUEST
) {
throw $e;
}

View File

@ -15,15 +15,17 @@ class Package
* @param int $plan_id plan id for this package
* @param string $gateway payment gateway name
* @param string $channel channel payment gateway
* @param array $pgids payment gateway ids
* @return boolean
*/
public static function rechargeUser($id_customer, $router_name, $plan_id, $gateway, $channel, $note = '')
{
global $config, $admin, $c, $p, $b, $t, $d, $zero;
global $config, $admin, $c, $p, $b, $t, $d, $zero, $trx;
$date_now = date("Y-m-d H:i:s");
$date_only = date("Y-m-d");
$time_only = date("H:i:s");
$time = date("H:i:s");
$inv = "";
if ($id_customer == '' or $router_name == '' or $plan_id == '') {
return false;
@ -44,6 +46,7 @@ class Package
foreach ($bills as $k => $v) {
$note .= $k . " : " . Lang::moneyFormat($v) . "\n";
}
$note .= $p['name_plan'] . " : " . Lang::moneyFormat($p['price']) . "\n";
}
}
@ -75,9 +78,8 @@ class Package
if ($router_name == 'balance') {
// insert table transactions
$inv = "INV-" . Package::_raid();
$t = ORM::for_table('tbl_transactions')->create();
$t->invoice = $inv;
$t->invoice = $inv = "INV-" . Package::_raid();
$t->username = $c['username'];
$t->plan_name = $p['name_plan'];
$t->price = $p['price'];
@ -148,7 +150,9 @@ class Package
->where('customer_id', $id_customer)
->where('tbl_user_recharges.routers', $router_name)
->where('tbl_user_recharges.Type', $p['type'])
->where('prepaid', $p['prepaid'])
# PPPOE or Hotspot only can have 1 per customer prepaid or postpaid
# because 1 customer can have 1 PPPOE and 1 Hotspot Plan in mikrotik
//->where('prepaid', $p['prepaid'])
->join('tbl_plans', array('tbl_plans.id', '=', 'tbl_user_recharges.plan_id'))
->find_one();
@ -164,7 +168,7 @@ class Package
$dt2 = new DateTime("$date_tmp");
$diff = $dt2->diff($dt1);
$sum = $diff->format("%a"); // => 453
if ($sum >= 35) {
if ($sum >= 35 * $p['validity']) {
$date_exp = date("Y-m-$day_exp", strtotime('+0 month'));
} else {
$date_exp = date("Y-m-$day_exp", strtotime('+' . $p['validity'] . ' month'));
@ -236,7 +240,7 @@ class Package
// insert table transactions
$t = ORM::for_table('tbl_transactions')->create();
$t->invoice = "INV-" . Package::_raid();
$t->invoice = $inv = "INV-" . Package::_raid();
$t->username = $c['username'];
$t->plan_name = $p['name_plan'];
if ($p['validity_unit'] == 'Period') {
@ -286,7 +290,7 @@ class Package
"\nRouter: " . $router_name .
"\nGateway: " . $gateway .
"\nChannel: " . $channel .
"\nPrice: " . Lang::moneyFormat($p['price']) .
"\nPrice: " . Lang::moneyFormat($p['price'] + $add_cost) .
"\nNote:\n" . $note);
} else {
if ($p['is_radius']) {
@ -320,7 +324,7 @@ class Package
// insert table transactions
$t = ORM::for_table('tbl_transactions')->create();
$t->invoice = "INV-" . Package::_raid();
$t->invoice = $inv = "INV-" . Package::_raid();
$t->username = $c['username'];
$t->plan_name = $p['name_plan'];
if ($p['validity_unit'] == 'Period') {
@ -356,7 +360,7 @@ class Package
$ed = new DateTime("$date_exp");
$td = $ed->diff($sd);
$fd = $td->format("%a");
$gi = ($p['price'] / 30) * $fd;
$gi = ($p['price'] / (30 * $p['validity'])) * $fd;
if ($gi > $p['price']) {
$fl->field_value = $p['price'];
} else {
@ -374,7 +378,7 @@ class Package
"\nRouter: " . $router_name .
"\nGateway: " . $gateway .
"\nChannel: " . $channel .
"\nPrice: " . Lang::moneyFormat($p['price']) .
"\nPrice: " . Lang::moneyFormat($p['price'] + $add_cost) .
"\nNote:\n" . $note);
}
} else {
@ -432,7 +436,7 @@ class Package
// insert table transactions
$t = ORM::for_table('tbl_transactions')->create();
$t->invoice = "INV-" . Package::_raid();
$t->invoice = $inv = "INV-" . Package::_raid();
$t->username = $c['username'];
$t->plan_name = $p['name_plan'];
if ($p['validity_unit'] == 'Period') {
@ -481,7 +485,7 @@ class Package
"\nRouter: " . $router_name .
"\nGateway: " . $gateway .
"\nChannel: " . $channel .
"\nPrice: " . Lang::moneyFormat($p['price']) .
"\nPrice: " . Lang::moneyFormat($p['price'] + $add_cost) .
"\nNote:\n" . $note);
} else {
if ($p['is_radius']) {
@ -515,12 +519,14 @@ class Package
// insert table transactions
$t = ORM::for_table('tbl_transactions')->create();
$t->invoice = "INV-" . Package::_raid();
$t->invoice = $inv = "INV-" . Package::_raid();
$t->username = $c['username'];
$t->plan_name = $p['name_plan'];
if ($p['validity_unit'] == 'Period') {
// Postpaid price always zero for first time
$t->price = 0 + $add_cost;
$note = '';
$bills = [];
$t->price = 0;
} else {
$t->price = $p['price'] + $add_cost;
}
@ -551,7 +557,7 @@ class Package
$ed = new DateTime("$date_exp");
$td = $ed->diff($sd);
$fd = $td->format("%a");
$gi = ($p['price'] / 30) * $fd;
$gi = ($p['price'] / (30 * $p['validity'])) * $fd;
if ($gi > $p['price']) {
$fl->field_value = $p['price'];
} else {
@ -569,7 +575,7 @@ class Package
"\nRouter: " . $router_name .
"\nGateway: " . $gateway .
"\nChannel: " . $channel .
"\nPrice: " . Lang::moneyFormat($p['price']) .
"\nPrice: " . Lang::moneyFormat($p['price'] + $add_cost) .
"\nNote:\n" . $note);
}
}
@ -578,7 +584,10 @@ class Package
}
run_hook("recharge_user_finish");
Message::sendInvoice($c, $t);
return true;
if($trx){
$trx->trx_invoice = $inv;
}
return $inv;
}
public static function changeTo($username, $plan_id, $from_id)
@ -685,6 +694,8 @@ class Package
} else {
$admin['fullname'] = 'Customer';
}
$cust = ORM::for_table('tbl_customers')->where('username', $in['username'])->findOne();
$note = '';
//print
$invoice = Lang::pad($config['CompanyName'], ' ', 2) . "\n";
@ -719,6 +730,9 @@ class Package
$invoice .= Lang::pad($note, ' ', 2) . "\n";
}
$invoice .= Lang::pad("", '=') . "\n";
if($cust){
$invoice .= Lang::pads(Lang::T('Full Name'), $cust['fullname'], ' ') . "\n";
}
$invoice .= Lang::pads(Lang::T('Username'), $in['username'], ' ') . "\n";
$invoice .= Lang::pads(Lang::T('Password'), '**********', ' ') . "\n";
if ($in['type'] != 'Balance') {
@ -760,6 +774,9 @@ class Package
$invoice .= Lang::pad($note, ' ', 2) . "\n";
}
$invoice .= Lang::pad("", '=') . "\n";
if($cust){
$invoice .= Lang::pads(Lang::T('Full Name'), $cust['fullname'], ' ') . "\n";
}
$invoice .= Lang::pads(Lang::T('Username'), $in['username'], ' ') . "\n";
$invoice .= Lang::pads(Lang::T('Password'), '**********', ' ') . "\n";
if ($in['type'] != 'Balance') {

View File

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

View File

@ -187,6 +187,7 @@ class User
->select('time')
->select('status')
->select('method')
->select('plan_type')
->select('tbl_user_recharges.routers', 'routers')
->select('tbl_user_recharges.type', 'type')
->select('admin_id')

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@
**/
if(Admin::getID()){
r2(U.'dashboard');
r2(U.'dashboard', "s", Lang::T("You are already logged in"));
}
if (isset($routes['1'])) {
@ -26,20 +26,27 @@ switch ($do) {
$d_pass = $d['password'];
if (Password::_verify($password, $d_pass) == true) {
$_SESSION['aid'] = $d['id'];
Admin::setCookie($d['id']);
$token = Admin::setCookie($d['id']);
$d->last_login = date('Y-m-d H:i:s');
$d->save();
_log($username . ' ' . Lang::T('Login Successful'), $d['user_type'], $d['id']);
if ($isApi) {
if ($token) {
showResult(true, Lang::T('Login Successful'), ['token' => "a.".$token]);
} else {
showResult(false, Lang::T('Invalid Username or Password'));
}
}
_alert(Lang::T('Login Successful'),'success', "dashboard");
} else {
_log($username . ' ' . Lang::T('Failed Login'), $d['user_type']);
_alert(Lang::T('Invalid Username or Password'),'danger', "admin");
_alert(Lang::T('Invalid Username or Password').".",'danger', "admin");
}
} else {
_alert(Lang::T('Invalid Username or Password'),'danger', "admin");
_alert(Lang::T('Invalid Username or Password')."..",'danger', "admin");
}
} else {
_alert(Lang::T('Invalid Username or Password'),'danger', "admin");
_alert(Lang::T('Invalid Username or Password')."...",'danger', "admin");
}
break;

View File

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

View File

@ -16,36 +16,11 @@ if (empty($action)) {
$action = 'list';
}
$leafletpickerHeader = <<<EOT
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css">
EOT;
switch ($action) {
case 'list':
$search = _post('search');
run_hook('list_customers'); #HOOK
if ($search != '') {
$paginator = Paginator::build(ORM::for_table('tbl_customers'), [
'username' => '%' . $search . '%',
'fullname' => '%' . $search . '%',
'phonenumber' => '%' . $search . '%',
'email' => '%' . $search . '%',
'service_type' => '%' . $search . '%'
], $search);
$d = ORM::for_table('tbl_customers')
->where_raw("(`username` LIKE '%$search%' OR `fullname` LIKE '%$search%' OR `phonenumber` LIKE '%$search%' OR `email` LIKE '%$search%')")
->offset($paginator['startpoint'])
->limit($paginator['limit'])
->order_by_asc('username')
->find_many();
} else {
$paginator = Paginator::build(ORM::for_table('tbl_customers'));
$d = ORM::for_table('tbl_customers')
->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many();
}
$ui->assign('search', htmlspecialchars($search));
$ui->assign('d', $d);
$ui->assign('paginator', $paginator);
$ui->display('customers.tpl');
break;
case 'csv':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
@ -89,6 +64,7 @@ switch ($action) {
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
$ui->assign('xheader', $leafletpickerHeader);
run_hook('view_add_customer'); #HOOK
$ui->display('customers-add.tpl');
break;
@ -210,40 +186,28 @@ switch ($action) {
$customFields = ORM::for_table('tbl_customers_fields')
->where('customer_id', $customer['id'])
->find_many();
$v = $routes['3'];
if (empty($v)) {
$v = 'activation';
}
if ($v == 'order') {
$v = 'order';
$paginator = Paginator::build(ORM::for_table('tbl_payment_gateway'), ['username' => $customer['username']]);
$order = ORM::for_table('tbl_payment_gateway')
->where('username', $customer['username'])
->offset($paginator['startpoint'])
->limit($paginator['limit'])
->order_by_desc('id')
->find_many();
$ui->assign('paginator', $paginator);
$query = ORM::for_table('tbl_transactions')->where('username', $customer['username'])->order_by_desc('id');
$order = Paginator::findMany($query);
$ui->assign('order', $order);
} else if ($v == 'activation') {
$paginator = Paginator::build(ORM::for_table('tbl_transactions'), ['username' => $customer['username']]);
$activation = ORM::for_table('tbl_transactions')
->where('username', $customer['username'])
->offset($paginator['startpoint'])
->limit($paginator['limit'])
->order_by_desc('id')
->find_many();
$ui->assign('paginator', $paginator);
$query = ORM::for_table('tbl_transactions')->where('username', $customer['username'])->order_by_desc('id');
$activation = Paginator::findMany($query);
$ui->assign('activation', $activation);
}
$ui->assign('packages', User::_billing($customer['id']));
$ui->assign('v', $v);
$ui->assign('d', $customer);
$ui->assign('customFields', $customFields);
$ui->assign('xheader', $leafletpickerHeader);
$ui->display('customers-view.tpl');
} else {
r2(U . 'customers/list', 'e', $_L['Account_Not_Found']);
r2(U . 'customers/list', 'e', Lang::T('Account Not Found'));
}
break;
case 'edit':
@ -260,9 +224,10 @@ switch ($action) {
if ($d) {
$ui->assign('d', $d);
$ui->assign('customFields', $customFields);
$ui->assign('xheader', $leafletpickerHeader);
$ui->display('customers-edit.tpl');
} else {
r2(U . 'customers/list', 'e', $_L['Account_Not_Found']);
r2(U . 'customers/list', 'e', Lang::T('Account Not Found'));
}
break;
@ -309,7 +274,8 @@ switch ($action) {
} catch (Throwable $e) {
}
try {
if ($c) $c->delete();
if ($c)
$c->delete();
} catch (Exception $e) {
} catch (Throwable $e) {
}
@ -328,6 +294,8 @@ switch ($action) {
$address = _post('address');
$phonenumber = _post('phonenumber');
$service_type = _post('service_type');
$account_type = _post('account_type');
$coordinates = _post('coordinates');
//post Customers Attributes
$custom_field_names = (array) $_POST['custom_field_name'];
$custom_field_values = (array) $_POST['custom_field_value'];
@ -355,11 +323,13 @@ switch ($action) {
$d->password = $password;
$d->pppoe_password = $pppoe_password;
$d->email = $email;
$d->account_type = $account_type;
$d->fullname = $fullname;
$d->address = $address;
$d->created_by = $admin['id'];
$d->phonenumber = Lang::phoneFormat($phonenumber);
$d->service_type = $service_type;
$d->coordinates = $coordinates;
$d->save();
// Retrieve the customer ID of the newly created customer
@ -389,12 +359,14 @@ switch ($action) {
case 'edit-post':
$username = Lang::phoneFormat(_post('username'));
$fullname = _post('fullname');
$account_type = _post('account_type');
$password = _post('password');
$pppoe_password = _post('pppoe_password');
$email = _post('email');
$address = _post('address');
$phonenumber = Lang::phoneFormat(_post('phonenumber'));
$service_type = _post('service_type');
$coordinates = _post('coordinates');
run_hook('edit_customer'); #HOOK
$msg = '';
if (Validator::Length($username, 35, 2) == false) {
@ -451,9 +423,11 @@ switch ($action) {
$d->pppoe_password = $pppoe_password;
$d->fullname = $fullname;
$d->email = $email;
$d->account_type = $account_type;
$d->address = $address;
$d->phonenumber = $phonenumber;
$d->service_type = $service_type;
$d->coordinates = $coordinates;
$d->save();
@ -538,5 +512,12 @@ switch ($action) {
break;
default:
r2(U . 'customers/list', 'e', 'action not defined');
run_hook('list_customers'); #HOOK
$query = ORM::for_table('tbl_customers')->order_by_asc('username');
$d = $query->findMany();
$ui->assign('xheader', '<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.11.3/css/jquery.dataTables.min.css">');
$ui->assign('d', $d);
$ui->display('customers.tpl');
break;
}

View File

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

View File

@ -77,37 +77,103 @@ if (_post('send') == 'balance') {
r2(U . 'home', 'd', Lang::T('Failed, balance is not available'));
}
} else if (_post('send') == 'plan') {
$active = ORM::for_table('tbl_user_recharges')
$actives = ORM::for_table('tbl_user_recharges')
->where('username', _post('username'))
->find_one();
->find_many();
foreach ($actives as $active) {
$router = ORM::for_table('tbl_routers')->where('name', $active['routers'])->find_one();
if ($router) {
r2(U . "order/send/$router[id]/$active[plan_id]&u=" . trim(_post('username')), 's', Lang::T('Review package before recharge'));
} else {
r2(U . 'home', 'w', Lang::T('Your friend do not have active package'));
}
}
r2(U . 'home', 'w', Lang::T('Your friend do not have active package'));
}
$ui->assign('_bills', User::_billing());
if (isset($_GET['recharge']) && !empty($_GET['recharge'])) {
if (!empty(App::getTokenValue(_get('stoken')))) {
r2(U . "voucher/invoice/");
die();
}
$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 ($bill['routers'] == 'radius') {
$router = 'radius';
} else {
$routers = ORM::for_table('tbl_routers')->where('name', $bill['routers'])->find_one();
$router = $routers['id'];
}
if ($config['enable_balance'] == 'yes') {
$plan = ORM::for_table('tbl_plans')->find_one($bill['plan_id']);
if (!$plan['enabled']) {
r2(U . "home", 'e', 'Plan is not exists');
}
if ($user['balance'] > $plan['price']) {
r2(U . "order/pay/$router[id]/$bill[plan_id]", 'e', 'Order Plan');
r2(U . "order/pay/$router/$bill[plan_id]&stoken=" . _get('stoken'), 'e', 'Order Plan');
} else {
r2(U . "order/buy/$router[id]/$bill[plan_id]", 'e', 'Order Plan');
r2(U . "order/buy/$router/$bill[plan_id]", 'e', 'Order Plan');
}
} else {
r2(U . "order/buy/$router[id]/$bill[plan_id]", 'e', 'Order Plan');
r2(U . "order/buy/$router/$bill[plan_id]", 'e', 'Order Plan');
}
}
} else if (!empty(_get('extend'))) {
if(!$config['extend_expired']){
r2(U . 'home', 'e', "cannot extend");
}
if (!empty(App::getTokenValue(_get('stoken')))) {
r2(U . 'home', 'e', "You already extend");
}
$id = _get('extend');
$tur = ORM::for_table('tbl_user_recharges')->where('customer_id', $user['id'])->where('id', $id)->find_one();
if ($tur) {
$m = date("m");
$path = $CACHE_PATH . DIRECTORY_SEPARATOR . "extends" . DIRECTORY_SEPARATOR;
if(!file_exists($path)){
mkdir($path);
}
$path .= $user['id'] . ".txt";
if (file_exists($path)) {
// is already extend
$last = file_get_contents($path);
if ($last == $m) {
r2(U . 'home', 'e', "You already extend for this month");
}
}
if ($tur['status'] != 'on') {
$days = $config['extend_days'];
$expiration = date('Y-m-d', strtotime(" +$days day"));
$tur->expiration = $expiration;
$tur->status = "on";
$tur->save();
App::setToken(_get('stoken'), $id);
if ($tur['routers'] != 'radius') {
$mikrotik = Mikrotik::info($tur['routers']);
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
$router = $tur['routers'];
}
$p = ORM::for_table('tbl_plans')->findOne($tur['plan_id']);
$c = ORM::for_table('tbl_customers')->findOne($tur['customer_id']);
if ($tur['routers'] == 'radius') {
Radius::customerAddPlan($c, $p, $tur['expiration'] . ' ' . $tur['time']);
} else {
if ($tur['type'] == 'Hotspot') {
Mikrotik::addHotspotUser($client, $p, $c);
} else if ($tur['type'] == 'PPPOE') {
Mikrotik::addPpoeUser($client, $p, $c);
}
}
// make customer cannot extend again
file_put_contents($path, $m);
_log("Customer $tur[customer_id] $tur[username] extend for $days days", "Customer", $user['id']);
r2(U . 'home', 's', "Extend until $expiration");
}else{
r2(U . 'home', 'e', "Plan is not expired");
}
} else {
r2(U . 'home', 'e', "Plan Not Found or Not Active");
}
} 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) {
@ -133,7 +199,7 @@ 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']);
_log('User ' . $bill['username'] . ' Deactivate ' . $bill['namebp'], 'Customer', $bill['customer_id']);
Message::sendTelegram('User u' . $bill['username'] . ' Deactivate ' . $bill['namebp']);
r2(U . 'home', 's', 'Success deactivate ' . $bill['namebp']);
} else {

View File

@ -18,6 +18,68 @@ if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
switch ($action) {
case 'list-csv':
$logs = ORM::for_table('tbl_logs')
->select('id')
->select('date')
->select('type')
->select('description')
->select('userid')
->select('ip')
->order_by_asc('id')->find_array();
$h = false;
set_time_limit(-1);
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-type: text/csv");
header('Content-Disposition: attachment;filename="activity-logs_' . date('Y-m-d_H_i') . '.csv"');
header('Content-Transfer-Encoding: binary');
foreach ($logs as $log) {
$ks = [];
$vs = [];
foreach ($log as $k => $v) {
$ks[] = $k;
$vs[] = $v;
}
if (!$h) {
echo '"' . implode('";"', $ks) . "\"\n";
$h = true;
}
echo '"' . implode('";"', $vs) . "\"\n";
}
break;
case 'radius-csv':
$logs = ORM::for_table('radpostauth')
->select('id')
->select('username')
->select('pass')
->select('reply')
->select('authdate')
->order_by_asc('id')->find_array();
$h = false;
set_time_limit(-1);
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-type: text/csv");
header('Content-Disposition: attachment;filename="radius-logs_' . date('Y-m-d_H_i') . '.csv"');
header('Content-Transfer-Encoding: binary');
foreach ($logs as $log) {
$ks = [];
$vs = [];
foreach ($log as $k => $v) {
$ks[] = $k;
$vs[] = $v;
}
if (!$h) {
echo '"' . implode('";"', $ks) . "\"\n";
$h = true;
}
echo '"' . implode('";"', $vs) . "\"\n";
}
break;
case 'list':
$q = (_post('q') ? _post('q') : _get('q'));
$keep = _post('keep');
@ -26,16 +88,15 @@ switch ($action) {
r2(U . "logs/list/", 's', "Delete logs older than $keep days");
}
if ($q != '') {
$paginator = Paginator::build(ORM::for_table('tbl_logs'), ['description' => '%' . $q . '%'], $q);
$d = ORM::for_table('tbl_logs')->where_like('description', '%' . $q . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many();
$query = ORM::for_table('tbl_logs')->where_like('description', '%' . $q . '%')->order_by_desc('id');
$d = Paginator::findMany($query, ['q' => $q]);
} else {
$paginator = Paginator::build(ORM::for_table('tbl_logs'));
$d = ORM::for_table('tbl_logs')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many();
$query = ORM::for_table('tbl_logs')->order_by_desc('id');
$d = Paginator::findMany($query);
}
$ui->assign('d', $d);
$ui->assign('q', $q);
$ui->assign('paginator', $paginator);
$ui->display('logs.tpl');
break;
case 'radius':
@ -46,16 +107,15 @@ switch ($action) {
r2(U . "logs/radius/", 's', "Delete logs older than $keep days");
}
if ($q != '') {
$paginator = Paginator::build(ORM::for_table('radpostauth', 'radius'), ['username' => '%' . $q . '%'], $q);
$d = ORM::for_table('radpostauth', 'radius')->where_like('username', '%' . $q . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many();
$query = ORM::for_table('radpostauth', 'radius')->where_like('username', '%' . $q . '%')->order_by_desc('id');
$d = Paginator::findMany($query, ['q' => $q]);
} else {
$paginator = Paginator::build(ORM::for_table('radpostauth', 'radius'));
$d = ORM::for_table('radpostauth', 'radius')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many();
$query = ORM::for_table('radpostauth', 'radius')->order_by_desc('id');
$d = Paginator::findMany($query);
}
$ui->assign('d', $d);
$ui->assign('q', $q);
$ui->assign('paginator', $paginator);
$ui->display('logs-radius.tpl');
break;

View File

@ -0,0 +1,48 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
* by https://t.me/ibnux
**/
_admin();
$ui->assign('_system_menu', 'map');
$action = $routes['1'];
$ui->assign('_admin', $admin);
if (empty($action)) {
$action = 'customer';
}
switch ($action) {
case 'customer':
$c = ORM::for_table('tbl_customers')->find_many();
$customerData = [];
foreach ($c as $customer) {
if (!empty($customer->coordinates)) {
$customerData[] = [
'id' => $customer->id,
'name' => $customer->fullname,
'balance' => $customer->balance,
'address' => $customer->address,
'direction' => $customer->coordinates,
'info' => Lang::T("Username") . ": " . $customer->username . " - " . Lang::T("Full Name") . ": " . $customer->fullname . " - " . Lang::T("Email") . ": " . $customer->email . " - " . Lang::T("Phone") . ": " . $customer->phonenumber . " - " . Lang::T("Service Type") . ": " . $customer->service_type,
'coordinates' => '[' . $customer->coordinates . ']',
];
}
}
$ui->assign('customers', $customerData);
$ui->assign('xheader', '<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css">');
$ui->assign('_title', Lang::T('Customer Geo Location Information'));
$ui->assign('xfooter', '<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>');
$ui->display('customers-map.tpl');
break;
default:
r2(U . 'map/customer', 'e', 'action not defined');
break;
}

View File

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

View File

@ -19,13 +19,8 @@ switch ($action) {
break;
case 'history':
$ui->assign('_system_menu', 'history');
$paginator = Paginator::build(ORM::for_table('tbl_payment_gateway'), ['username' => $user['username']]);
$d = ORM::for_table('tbl_payment_gateway')
->where('username', $user['username'])
->order_by_desc('id')
->offset($paginator['startpoint'])->limit($paginator['limit'])
->find_many();
$ui->assign('paginator', $paginator);
$query = ORM::for_table('tbl_payment_gateway')->where('username', $user['username'])->order_by_desc('id');
$d = Paginator::findMany($query);
$ui->assign('d', $d);
$ui->assign('_title', Lang::T('Order History'));
run_hook('customer_view_order_history'); #HOOK
@ -47,26 +42,30 @@ switch ($action) {
}
$ui->assign('_title', 'Order Plan');
$ui->assign('_system_menu', 'package');
$account_type = $user['account_type'];
if (empty($account_type)) {
$account_type = 'Personal';
}
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')->where('prepaid', 'yes')->find_many();
$radius_hotspot = ORM::for_table('tbl_plans')->where('enabled', '1')->where('is_radius', 1)->where('type', 'Hotspot')->where('prepaid', 'yes')->find_many();
$radius_pppoe = ORM::for_table('tbl_plans')->where('plan_type', $account_type)->where('enabled', '1')->where('is_radius', 1)->where('type', 'PPPOE')->where('prepaid', 'yes')->find_many();
$radius_hotspot = ORM::for_table('tbl_plans')->where('plan_type', $account_type)->where('enabled', '1')->where('is_radius', 1)->where('type', 'Hotspot')->where('prepaid', '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')->where('prepaid', '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('prepaid', 'yes')->find_many();
$plans_pppoe = ORM::for_table('tbl_plans')->where('plan_type', $account_type)->where('enabled', '1')->where_in('routers', $rs)->where('is_radius', 0)->where('type', 'PPPOE')->where('prepaid', 'yes')->find_many();
$plans_hotspot = ORM::for_table('tbl_plans')->where('plan_type', $account_type)->where('enabled', '1')->where_in('routers', $rs)->where('is_radius', 0)->where('type', 'Hotspot')->where('prepaid', 'yes')->find_many();
}
} else {
$radius_pppoe = ORM::for_table('tbl_plans')->where('enabled', '1')->where('is_radius', 1)->where('type', 'PPPOE')->where('prepaid', 'yes')->find_many();
$radius_hotspot = ORM::for_table('tbl_plans')->where('enabled', '1')->where('is_radius', 1)->where('type', 'Hotspot')->where('prepaid', 'yes')->find_many();
$radius_pppoe = ORM::for_table('tbl_plans')->where('plan_type', $account_type)->where('enabled', '1')->where('is_radius', 1)->where('type', 'PPPOE')->where('prepaid', 'yes')->find_many();
$radius_hotspot = ORM::for_table('tbl_plans')->where('plan_type', $account_type)->where('enabled', '1')->where('is_radius', 1)->where('type', 'Hotspot')->where('prepaid', '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')->where('prepaid', 'yes')->find_many();
$plans_hotspot = ORM::for_table('tbl_plans')->where('enabled', '1')->where('is_radius', 0)->where('type', 'Hotspot')->where('prepaid', 'yes')->find_many();
$plans_pppoe = ORM::for_table('tbl_plans')->where('plan_type', $account_type)->where('enabled', '1')->where('is_radius', 0)->where('type', 'PPPOE')->where('prepaid', 'yes')->find_many();
$plans_hotspot = ORM::for_table('tbl_plans')->where('plan_type', $account_type)->where('enabled', '1')->where('is_radius', 0)->where('type', 'Hotspot')->where('prepaid', 'yes')->find_many();
}
$ui->assign('routers', $routers);
$ui->assign('radius_pppoe', $radius_pppoe);
@ -103,8 +102,8 @@ switch ($action) {
if (empty($trx)) {
r2(U . "order/package", 'w', Lang::T("Payment not found"));
}
// jika url kosong, balikin ke buy
if (empty($trx['pg_url_payment'])) {
// jika url kosong, balikin ke buy, kecuali cancel
if (empty($trx['pg_url_payment']) && $routes['3'] != 'cancel') {
r2(U . "order/buy/" . (($trx['routers_id'] == 0) ? $trx['routers'] : $trx['routers_id']) . '/' . $trx['plan_id'], 'w', Lang::T("Checking payment"));
}
if ($routes['3'] == 'check') {
@ -128,12 +127,12 @@ switch ($action) {
if (empty($trx)) {
r2(U . "order/package", 'e', Lang::T("Transaction Not found"));
}
$router = Mikrotik::info($trx['routers']);
$plan = ORM::for_table('tbl_plans')->find_one($trx['plan_id']);
$bandw = ORM::for_table('tbl_bandwidth')->find_one($plan['id_bw']);
list($bills, $add_cost) = User::getBills($id_customer);
$ui->assign('bills', $bills);
$ui->assign('add_cost', $add_cost);
$invoice = ORM::for_table('tbl_transactions')->where("invoice",$trx['trx_invoice'])->find_one();
$ui->assign('invoice', $invoice);
$ui->assign('trx', $trx);
$ui->assign('router', $router);
$ui->assign('plan', $plan);
@ -145,6 +144,10 @@ switch ($action) {
if ($config['enable_balance'] != 'yes') {
r2(U . "order/package", 'e', Lang::T("Balance not enabled"));
}
if (!empty(App::getTokenValue($_GET['stoken']))) {
r2(U . "voucher/invoice/");
die();
}
$plan = ORM::for_table('tbl_plans')->where('enabled', '1')->find_one($routes['3']);
if (empty($plan)) {
r2(U . "order/package", 'e', Lang::T("Plan Not found"));
@ -162,6 +165,7 @@ switch ($action) {
if (Package::rechargeUser($user['id'], $router_name, $plan['id'], 'Customer', 'Balance')) {
// if success, then get the balance
Balance::min($user['id'], $plan['price'] + $add_cost);
App::setToken($_GET['stoken'], "success");
r2(U . "voucher/invoice/", 's', Lang::T("Success to buy package"));
} else {
r2(U . "order/package", 'e', Lang::T("Failed to buy package"));
@ -216,7 +220,8 @@ switch ($action) {
if ($active && $active['plan_id'] != $plan['id']) {
r2(U . "order/package", 'e', Lang::T("Target has active plan, different with current plant.") . " [ <b>$active[namebp]</b> ]");
}
if (Package::rechargeUser($target['id'], $router_name, $plan['id'], $user['fullname'], 'Balance')) {
$result = Package::rechargeUser($target['id'], $router_name, $plan['id'], $user['username'], 'Balance');
if (!empty($result)) {
// if success, then get the balance
Balance::min($user['id'], $plan['price']);
//sender
@ -234,6 +239,7 @@ switch ($action) {
$d->paid_date = date('Y-m-d H:i:s');
$d->expired_date = date('Y-m-d H:i:s');
$d->pg_url_payment = 'balance';
$d->trx_invoice = $result;
$d->status = 2;
$d->save();
$trx_id = $d->id();
@ -252,6 +258,7 @@ switch ($action) {
$d->paid_date = date('Y-m-d H:i:s');
$d->expired_date = date('Y-m-d H:i:s');
$d->pg_url_payment = 'balance';
$d->trx_invoice = $result;
$d->status = 2;
$d->save();
r2(U . "order/view/$trx_id", 's', Lang::T("Success to send package"));

View File

@ -59,31 +59,7 @@ switch ($action) {
}
$log .= "DONE : $plan[username], $plan[namebp], $plan[type], $plan[routers]<br>";
}
if ($isApi) {
showResult(true, $log);
}
r2(U . 'plan/list', 's', $log);
case 'list':
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/plan.js"></script>');
$ui->assign('_title', Lang::T('Customer'));
$search = _post('search');
if ($search != '') {
$paginator = Paginator::build(ORM::for_table('tbl_user_recharges'), ['username' => '%' . $search . '%'], $search);
$d = ORM::for_table('tbl_user_recharges')->where_like('username', '%' . $search . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many();
} else {
$paginator = Paginator::build(ORM::for_table('tbl_user_recharges'));
$d = ORM::for_table('tbl_user_recharges')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_array();
}
run_hook('view_list_billing'); #HOOK
if ($isApi) {
showResult(true, $action, $d, ['search' => $search]);
}
$ui->assign('d', $d);
$ui->assign('search', $search);
$ui->assign('paginator', $paginator);
$ui->display('plan.tpl');
break;
case 'recharge':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
@ -154,6 +130,15 @@ switch ($action) {
$server = _post('server');
$planId = _post('plan');
$using = _post('using');
$stoken = _post('stoken');
if(!empty(App::getTokenValue($stoken))){
$username = App::getTokenValue($stoken);
$in = ORM::for_table('tbl_transactions')->where('username', $username)->order_by_desc('id')->find_one();
Package::createInvoice($in);
$ui->display('invoice.tpl');
die();
}
$msg = '';
if ($id_customer == '' or $server == '' or $planId == '' or $using == '') {
@ -189,6 +174,7 @@ switch ($action) {
}
$in = ORM::for_table('tbl_transactions')->where('username', $cust['username'])->order_by_desc('id')->find_one();
Package::createInvoice($in);
App::setToken($stoken, $cust['username']);
$ui->display('invoice.tpl');
_log('[' . $admin['username'] . ']: ' . 'Recharge ' . $cust['username'] . ' [' . $in['plan_name'] . '][' . Lang::moneyFormat($in['price']) . ']', $admin['user_type'], $admin['id']);
} else {
@ -254,7 +240,7 @@ switch ($action) {
$ui->assign('_title', 'Edit Plan');
$ui->display('plan-edit.tpl');
} else {
r2(U . 'plan/list', 'e', $_L['Account_Not_Found']);
r2(U . 'plan/list', 'e', Lang::T('Account Not Found'));
}
break;
@ -753,6 +739,61 @@ switch ($action) {
r2(U . 'plan/refill', 'e', "All field is required");
}
break;
default:
$ui->display('a404.tpl');
case 'extend':
$id = $routes[2];
$days = $routes[3];
$stoken = $_GET['stoken'];
if(App::getTokenValue($stoken)){
r2(U . 'plan', 's', "Extend already done");
}
$tur = ORM::for_table('tbl_user_recharges')->find_one($id);
$status = $tur['status'];
if(strtotime($tur['expiration'].' '.$tur['time']) > time()){
// not expired
$expiration = date('Y-m-d', strtotime($tur['expiration']." +$days day"));
}else{
//expired
$expiration = date('Y-m-d', strtotime(" +$days day"));
}
$tur->expiration = $expiration;
$tur->status = "on";
$tur->save();
App::setToken($stoken, $id);
if($status=='off'){
if ($tur['routers'] != 'radius') {
$mikrotik = Mikrotik::info($tur['routers']);
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
$router = $tur['routers'];
}
$p = ORM::for_table('tbl_plans')->findOne($tur['plan_id']);
$c = ORM::for_table('tbl_customers')->findOne($tur['customer_id']);
if ($tur['routers'] == 'radius') {
Radius::customerAddPlan($c, $p, $tur['expiration'] . ' ' . $tur['time']);
} else {
if ($tur['type'] == 'Hotspot') {
Mikrotik::addHotspotUser($client, $p, $c);
} else if ($tur['type'] == 'PPPOE') {
Mikrotik::addPpoeUser($client, $p, $c);
}
}
}
_log("$admin[fullname] extend Customer $tur[customer_id] $tur[username] for $days days", $admin['user_type'], $admin['id']);
r2(U . 'plan', 's', "Extend until $expiration");
break;
default:
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/plan.js"></script>');
$ui->assign('_title', Lang::T('Customer'));
$search = _post('search');
if ($search != '') {
$query = ORM::for_table('tbl_user_recharges')->where_like('username', '%' . $search . '%')->order_by_desc('id');
$d = Paginator::findMany($query, ['search' => $search]);
} else {
$query = ORM::for_table('tbl_user_recharges')->order_by_desc('id');
$d = Paginator::findMany($query);
}
run_hook('view_list_billing'); #HOOK
$ui->assign('d', $d);
$ui->assign('search', $search);
$ui->display('plan.tpl');
break;
}

View File

@ -23,15 +23,14 @@ switch ($action) {
$name = _post('name');
if ($name != '') {
$paginator = Paginator::build(ORM::for_table('tbl_pool'), ['pool_name' => '%' . $name . '%'], $name);
$d = ORM::for_table('tbl_pool')->where_like('pool_name', '%' . $name . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many();
$query = ORM::for_table('tbl_pool')->where_like('pool_name', '%' . $name . '%')->order_by_desc('id');
$d = Paginator::findMany($query, ['name' => $name]);
} else {
$paginator = Paginator::build(ORM::for_table('tbl_pool'));
$d = ORM::for_table('tbl_pool')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many();
$query = ORM::for_table('tbl_pool')->order_by_desc('id');
$d = Paginator::findMany($query);
}
$ui->assign('d', $d);
$ui->assign('paginator', $paginator);
run_hook('view_pool'); #HOOK
$ui->display('pool.tpl');
break;
@ -51,7 +50,7 @@ switch ($action) {
run_hook('view_edit_pool'); #HOOK
$ui->display('pool-edit.tpl');
} else {
r2(U . 'pool/list', 'e', $_L['Account_Not_Found']);
r2(U . 'pool/list', 'e', Lang::T('Account Not Found'));
}
break;

View File

@ -1,10 +1,11 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
* by https://t.me/ibnux
**/
_admin();
$ui->assign('_title', $_L['Plugin Manager']);
$ui->assign('_title', Lang::T('Plugin Manager'));
$ui->assign('_system_menu', 'settings');
$action = $routes['1'];
@ -79,7 +80,7 @@ switch ($action) {
$ui->assign('d', $d);
$ui->display('radius-nas-edit.tpl');
} else {
r2(U . 'radius/list', 'e', $_L['Account_Not_Found']);
r2(U . 'radius/list', 'e', Lang::T('Account Not Found'));
}
break;
@ -134,22 +135,15 @@ switch ($action) {
$ui->assign('_title', "Network Access Server");
$name = _post('name');
if (empty($name)) {
$paginator = Paginator::build(ORM::for_table('nas', 'radius'));
$nas = ORM::for_table('nas', 'radius')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many();
$query = ORM::for_table('nas', 'radius');
$nas = Paginator::findMany($query);
} else {
$paginator = Paginator::build(ORM::for_table('nas', 'radius'), [
'nasname' => '%'.$search.'%',
'shortname' => '%'.$search.'%',
'description' => '%'.$search.'%'
]);
$nas = ORM::for_table('nas', 'radius')
$query = ORM::for_table('nas', 'radius')
->where_like('nasname', $search)
->where_like('shortname', $search)
->where_like('description', $search)
->offset($paginator['startpoint'])->limit($paginator['limit'])
->find_many();
->where_like('description', $search);
$nas = Paginator::findMany($query, ['name' => $name]);
}
$ui->assign('paginator', $paginator);
$ui->assign('name', $name);
$ui->assign('nas', $nas);
$ui->display('radius-nas.tpl');

View File

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

View File

@ -26,15 +26,14 @@ switch ($action) {
$name = _post('name');
if ($name != '') {
$paginator = Paginator::build(ORM::for_table('tbl_routers'), ['name' => '%' . $name . '%'], $name);
$d = ORM::for_table('tbl_routers')->where_like('name', '%' . $name . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many();
$query = ORM::for_table('tbl_routers')->where_like('name', '%' . $name . '%')->order_by_desc('id');
$d = Paginator::findMany($query, ['name' => $name]);
} else {
$paginator = Paginator::build(ORM::for_table('tbl_routers'));
$d = ORM::for_table('tbl_routers')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many();
$query = ORM::for_table('tbl_routers')->order_by_desc('id');
$d = Paginator::findMany($query);
}
$ui->assign('d', $d);
$ui->assign('paginator', $paginator);
run_hook('view_list_routers'); #HOOK
$ui->display('routers.tpl');
break;
@ -55,7 +54,7 @@ switch ($action) {
run_hook('view_router_edit'); #HOOK
$ui->display('routers-edit.tpl');
} else {
r2(U . 'routers/list', 'e', $_L['Account_Not_Found']);
r2(U . 'routers/list', 'e', Lang::T('Account Not Found'));
}
break;

View File

@ -119,15 +119,14 @@ switch ($action) {
$name = _post('name');
if ($name != '') {
$paginator = Paginator::build(ORM::for_table('tbl_plans'), ['name_plan' => '%' . $name . '%', 'type' => 'Hotspot'], $name);
$d = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'Hotspot')->where_like('tbl_plans.name_plan', '%' . $name . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many();
$query = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'Hotspot')->where_like('tbl_plans.name_plan', '%' . $name . '%');
$d = Paginator::findMany($query, ['name' => $name]);
} else {
$paginator = Paginator::build(ORM::for_table('tbl_plans'), ['type' => 'Hotspot']);
$d = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'Hotspot')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many();
$query = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'Hotspot');
$d = Paginator::findMany($query);
}
$ui->assign('d', $d);
$ui->assign('paginator', $paginator);
run_hook('view_list_plans'); #HOOK
$ui->display('hotspot.tpl');
break;
@ -153,7 +152,7 @@ switch ($action) {
run_hook('view_edit_plan'); #HOOK
$ui->display('hotspot-edit.tpl');
} else {
r2(U . 'services/hotspot', 'e', $_L['Account_Not_Found']);
r2(U . 'services/hotspot', 'e', Lang::T('Account Not Found'));
}
break;
@ -185,6 +184,7 @@ switch ($action) {
case 'add-post':
$name = _post('name');
$plan_type = _post('plan_type'); //Personal / Business
$radius = _post('radius');
$typebp = _post('typebp');
$limit_type = _post('limit_type');
@ -245,12 +245,44 @@ switch ($action) {
$radiusRate = $b['rate_up'] . $radup . '/' . $b['rate_down'] . $raddown;
$rate = trim($rate . " " . $b['burst']);
// Check if tax is enabled in config
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
// Default tax rate
$default_tax_rate = 0.01; // Default tax rate 1%
// Check if tax rate is set to custom in config
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : $default_tax_rate;
// Check if tax rate is custom
if ($tax_rate_setting === 'custom') {
// Check if custom tax rate is set in config
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : $default_tax_rate;
// Convert custom tax rate to decimal
$custom_tax_rate_decimal = $custom_tax_rate / 100;
$tax_rate = $custom_tax_rate_decimal;
} else {
// Use tax rate
$tax_rate = $tax_rate_setting;
}
// Calculate the new price with tax if tax is enabled
if ($tax_enable === 'yes') {
$price_with_tax = $price + ($price * $tax_rate);
} else {
// If tax is not enabled, use the original price
$price_with_tax = $price;
}
// Create new plan
$d = ORM::for_table('tbl_plans')->create();
$d->name_plan = $name;
$d->id_bw = $id_bw;
$d->price = $price;
$d->price = $price_with_tax; // Set price with or without tax based on configuration
$d->type = 'Hotspot';
$d->typebp = $typebp;
$d->plan_type = $plan_type;
$d->limit_type = $limit_type;
$d->time_limit = $time_limit;
$d->time_unit = $time_unit;
@ -295,6 +327,7 @@ switch ($action) {
case 'edit-post':
$id = _post('id');
$name = _post('name');
$plan_type = _post('plan_type');
$id_bw = _post('id_bw');
$typebp = _post('typebp');
$price = _post('price');
@ -359,14 +392,45 @@ switch ($action) {
}
}
// Check if tax is enabled in config
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
// Default tax rate
$default_tax_rate = 0.01; // Default tax rate 1%
// Check if tax rate is set to custom in config
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : $default_tax_rate;
// Check if tax rate is custom
if ($tax_rate_setting === 'custom') {
// Check if custom tax rate is set in config
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : $default_tax_rate;
// Convert custom tax rate to decimal
$custom_tax_rate_decimal = $custom_tax_rate / 100;
$tax_rate = $custom_tax_rate_decimal;
} else {
// Use tax rate
$tax_rate = $tax_rate_setting;
}
// Calculate the new price with tax if tax is enabled
if ($tax_enable === 'yes') {
$price_with_tax = $price + ($price * $tax_rate);
} else {
// If tax is not enabled, use the original price
$price_with_tax = $price;
}
$d->name_plan = $name;
$d->id_bw = $id_bw;
$d->price = $price;
$d->price = $price_with_tax; // Set price with or without tax based on configuration
$d->typebp = $typebp;
$d->limit_type = $limit_type;
$d->time_limit = $time_limit;
$d->time_unit = $time_unit;
$d->data_limit = $data_limit;
$d->plan_type = $plan_type;
$d->data_unit = $data_unit;
$d->validity = $validity;
$d->validity_unit = $validity_unit;
@ -389,15 +453,14 @@ switch ($action) {
$name = _post('name');
if ($name != '') {
$paginator = Paginator::build(ORM::for_table('tbl_plans'), ['name_plan' => '%' . $name . '%', 'type' => 'PPPOE'], $name);
$d = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'PPPOE')->where_like('tbl_plans.name_plan', '%' . $name . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many();
$query = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'PPPOE')->where_like('tbl_plans.name_plan', '%' . $name . '%');
$d = Paginator::findMany($query, ['name' => $name]);
} else {
$paginator = Paginator::build(ORM::for_table('tbl_plans'), ['type' => 'PPPOE'], $name);
$d = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'PPPOE')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many();
$query = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'PPPOE');
$d = Paginator::findMany($query);
}
$ui->assign('d', $d);
$ui->assign('paginator', $paginator);
run_hook('view_list_ppoe'); #HOOK
$ui->display('pppoe.tpl');
break;
@ -430,7 +493,7 @@ switch ($action) {
run_hook('view_edit_ppoe'); #HOOK
$ui->display('pppoe-edit.tpl');
} else {
r2(U . 'services/pppoe', 'e', $_L['Account_Not_Found']);
r2(U . 'services/pppoe', 'e', Lang::T('Account Not Found'));
}
break;
@ -461,6 +524,7 @@ switch ($action) {
case 'pppoe-add-post':
$name = _post('name_plan');
$plan_type = _post('plan_type');
$radius = _post('radius');
$id_bw = _post('id_bw');
$price = _post('price');
@ -515,11 +579,43 @@ switch ($action) {
$radiusRate = $b['rate_up'] . $radup . '/' . $b['rate_down'] . $raddown;
$rate = trim($rate . " " . $b['burst']);
// Check if tax is enabled in config
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
// Default tax rate
$default_tax_rate = 0.01; // Default tax rate 1%
// Check if tax rate is set to custom in config
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : $default_tax_rate;
// Check if tax rate is custom
if ($tax_rate_setting === 'custom') {
// Check if custom tax rate is set in config
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : $default_tax_rate;
// Convert custom tax rate to decimal
$custom_tax_rate_decimal = $custom_tax_rate / 100;
$tax_rate = $custom_tax_rate_decimal;
} else {
// Use tax rate
$tax_rate = $tax_rate_setting;
}
// Calculate the new price with tax if tax is enabled
if ($tax_enable === 'yes') {
$price_with_tax = $price + ($price * $tax_rate);
} else {
// If tax is not enabled, use the original price
$price_with_tax = $price;
}
$d = ORM::for_table('tbl_plans')->create();
$d->type = 'PPPOE';
$d->name_plan = $name;
$d->id_bw = $id_bw;
$d->price = $price;
$d->price = $price_with_tax;
$d->plan_type = $plan_type;
$d->validity = $validity;
$d->validity_unit = $validity_unit;
$d->pool = $pool;
@ -556,6 +652,7 @@ switch ($action) {
case 'edit-pppoe-post':
$id = _post('id');
$plan_type = _post('plan_type');
$name = _post('name_plan');
$id_bw = _post('id_bw');
$price = _post('price');
@ -616,9 +713,40 @@ switch ($action) {
}
}
// Check if tax is enabled in config
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
// Default tax rate
$default_tax_rate = 0.01; // Default tax rate 1%
// Check if tax rate is set to custom in config
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : $default_tax_rate;
// Check if tax rate is custom
if ($tax_rate_setting === 'custom') {
// Check if custom tax rate is set in config
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : $default_tax_rate;
// Convert custom tax rate to decimal
$custom_tax_rate_decimal = $custom_tax_rate / 100;
$tax_rate = $custom_tax_rate_decimal;
} else {
// Use tax rate
$tax_rate = $tax_rate_setting;
}
// Calculate the new price with tax if tax is enabled
if ($tax_enable === 'yes') {
$price_with_tax = $price + ($price * $tax_rate);
} else {
// If tax is not enabled, use the original price
$price_with_tax = $price;
}
$d->name_plan = $name;
$d->id_bw = $id_bw;
$d->price = $price;
$d->price = $price_with_tax;
$d->plan_type = $plan_type;
$d->validity = $validity;
$d->validity_unit = $validity_unit;
$d->routers = $routers;
@ -638,15 +766,14 @@ switch ($action) {
$ui->assign('_title', Lang::T('Balance Plans'));
$name = _post('name');
if ($name != '') {
$paginator = Paginator::build(ORM::for_table('tbl_plans'), ['name_plan' => '%' . $name . '%', 'type' => 'Balance'], $name);
$d = ORM::for_table('tbl_plans')->where('tbl_plans.type', 'Balance')->where_like('tbl_plans.name_plan', '%' . $name . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many();
$query = ORM::for_table('tbl_plans')->where('tbl_plans.type', 'Balance')->where_like('tbl_plans.name_plan', '%' . $name . '%');
$d = Paginator::findMany($query, ['name' => $name]);
} else {
$paginator = Paginator::build(ORM::for_table('tbl_plans'), ['type' => 'Balance'], $name);
$d = ORM::for_table('tbl_plans')->where('tbl_plans.type', 'Balance')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many();
$query = ORM::for_table('tbl_plans')->where('tbl_plans.type', 'Balance');
$d = Paginator::findMany($query);
}
$ui->assign('d', $d);
$ui->assign('paginator', $paginator);
run_hook('view_list_balance'); #HOOK
$ui->display('balance.tpl');
break;
@ -695,8 +822,37 @@ switch ($action) {
}
run_hook('edit_ppoe'); #HOOK
if ($msg == '') {
// Check if tax is enabled in config
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
// Default tax rate
$default_tax_rate = 0.01; // Default tax rate 1%
// Check if tax rate is set to custom in config
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : $default_tax_rate;
// Check if tax rate is custom
if ($tax_rate_setting === 'custom') {
// Check if custom tax rate is set in config
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : $default_tax_rate;
// Convert custom tax rate to decimal
$custom_tax_rate_decimal = $custom_tax_rate / 100;
$tax_rate = $custom_tax_rate_decimal;
} else {
// Use tax rate
$tax_rate = $tax_rate_setting;
}
// Calculate the new price with tax if tax is enabled
if ($tax_enable === 'yes') {
$price_with_tax = $price + ($price * $tax_rate);
} else {
// If tax is not enabled, use the original price
$price_with_tax = $price;
}
$d->name_plan = $name;
$d->price = $price;
$d->price = $price_with_tax;
$d->enabled = $enabled;
$d->prepaid = 'yes';
$d->save();
@ -725,11 +881,43 @@ switch ($action) {
}
run_hook('add_ppoe'); #HOOK
if ($msg == '') {
// Check if tax is enabled in config
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
// Default tax rate
$default_tax_rate = 0.01; // Default tax rate 1%
// Check if tax rate is set to custom in config
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : $default_tax_rate;
// Check if tax rate is custom
if ($tax_rate_setting === 'custom') {
// Check if custom tax rate is set in config
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : $default_tax_rate;
// Convert custom tax rate to decimal
$custom_tax_rate_decimal = $custom_tax_rate / 100;
$tax_rate = $custom_tax_rate_decimal;
} else {
// Use tax rate
$tax_rate = $tax_rate_setting;
}
// Calculate the new price with tax if tax is enabled
if ($tax_enable === 'yes') {
$price_with_tax = $price + ($price * $tax_rate);
} else {
// If tax is not enabled, use the original price
$price_with_tax = $price;
}
$d = ORM::for_table('tbl_plans')->create();
$d->type = 'Balance';
$d->name_plan = $name;
$d->id_bw = 0;
$d->price = $price;
$d->price = $price_with_tax;
$d->validity = 0;
$d->validity_unit = 'Months';
$d->routers = '';

View File

@ -25,6 +25,10 @@ switch ($action) {
$result = Message::sendSMS(_get('testSms'), 'PHPNuxBill Test SMS');
r2(U . "settings/app", 's', 'Test SMS has been send<br>Result: ' . $result);
}
if (!empty(_get('testEmail'))) {
Message::sendEmail(_get('testEmail'), 'PHPNuxBill Test Email', 'PHPNuxBill Test Email Body');
r2(U . "settings/app", 's', 'Test Email has been send');
}
if (!empty(_get('testTg'))) {
$result = Message::sendTelegram('PHPNuxBill Test Telegram');
r2(U . "settings/app", 's', 'Test Telegram has been send<br>Result: ' . $result);
@ -115,7 +119,7 @@ switch ($action) {
die();
}
}
// save all settings
// Save all settings including tax system
foreach ($_POST as $key => $value) {
$d = ORM::for_table('tbl_appconfig')->where('setting', $key)->find_one();
if ($d) {
@ -129,6 +133,33 @@ switch ($action) {
}
}
// Handle tax system separately
$enable_tax = isset($_POST['enable_tax']) ? $_POST['enable_tax'] : 'no';
$tax_rate = isset($_POST['tax_rate']) ? $_POST['tax_rate'] : '0.01'; // Default tax rate 1%
// Save or update tax system settings
$d_tax_enable = ORM::for_table('tbl_appconfig')->where('setting', 'enable_tax')->find_one();
if ($d_tax_enable) {
$d_tax_enable->value = $enable_tax;
$d_tax_enable->save();
} else {
$d_tax_enable = ORM::for_table('tbl_appconfig')->create();
$d_tax_enable->setting = 'enable_tax';
$d_tax_enable->value = $enable_tax;
$d_tax_enable->save();
}
$d_tax_rate = ORM::for_table('tbl_appconfig')->where('setting', 'tax_rate')->find_one();
if ($d_tax_rate) {
$d_tax_rate->value = $tax_rate;
$d_tax_rate->save();
} else {
$d_tax_rate = ORM::for_table('tbl_appconfig')->create();
$d_tax_rate->setting = 'tax_rate';
$d_tax_rate->value = $tax_rate;
$d_tax_rate->save();
}
//checkbox
$checks = ['hide_mrc', 'hide_tms', 'hide_aui', 'hide_al', 'hide_uet', 'hide_vs', 'hide_pg'];
foreach ($checks as $check) {
@ -276,60 +307,47 @@ switch ($action) {
$search = _req('search');
if ($search != '') {
if ($admin['user_type'] == 'SuperAdmin') {
$paginator = Paginator::build(ORM::for_table('tbl_users'), ['username' => '%' . $search . '%'], $search);
$d = ORM::for_table('tbl_users')
$query = ORM::for_table('tbl_users')
->where_like('username', '%' . $search . '%')
->offset($paginator['startpoint'])
->limit($paginator['limit'])->order_by_asc('id')->findArray();
->order_by_asc('id');
$d = Paginator::findMany($query, ['search' => $search]);
} else if ($admin['user_type'] == 'Admin') {
$paginator = Paginator::build(ORM::for_table('tbl_users'), [
'username' => '%' . $search . '%',
$query = ORM::for_table('tbl_users')
->where_like('username', '%' . $search . '%')->where_any_is([
['user_type' => 'Report'],
['user_type' => 'Agent'],
['user_type' => 'Sales'],
['id' => $admin['id']]
], $search);
$d = ORM::for_table('tbl_users')
->where_like('username', '%' . $search . '%')
->where_any_is([
['user_type' => 'Report'],
['user_type' => 'Agent'],
['user_type' => 'Sales'],
['id' => $admin['id']]
])
->offset($paginator['startpoint'])
->limit($paginator['limit'])->order_by_asc('id')->findArray();
])->order_by_asc('id');
$d = Paginator::findMany($query, ['search' => $search]);
} else {
$paginator = Paginator::build(ORM::for_table('tbl_users'), ['username' => '%' . $search . '%'], $search);
$d = ORM::for_table('tbl_users')
$query = ORM::for_table('tbl_users')
->where_like('username', '%' . $search . '%')
->where_any_is([
['id' => $admin['id']],
['root' => $admin['id']]
])
->offset($paginator['startpoint'])
->limit($paginator['limit'])->order_by_asc('id')->findArray();
])->order_by_asc('id');
$d = Paginator::findMany($query, ['search' => $search]);
}
} else {
if ($admin['user_type'] == 'SuperAdmin') {
$paginator = Paginator::build(ORM::for_table('tbl_users'));
$d = ORM::for_table('tbl_users')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_asc('id')->findArray();
$query = ORM::for_table('tbl_users')->order_by_asc('id');
$d = Paginator::findMany($query);
} else if ($admin['user_type'] == 'Admin') {
$paginator = Paginator::build(ORM::for_table('tbl_users'));
$d = ORM::for_table('tbl_users')->where_any_is([
$query = ORM::for_table('tbl_users')->where_any_is([
['user_type' => 'Report'],
['user_type' => 'Agent'],
['user_type' => 'Sales'],
['id' => $admin['id']]
])->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_asc('id')->findArray();
])->order_by_asc('id');
$d = Paginator::findMany($query);
} else {
$paginator = Paginator::build(ORM::for_table('tbl_users'));
$d = ORM::for_table('tbl_users')
$query = ORM::for_table('tbl_users')
->where_any_is([
['id' => $admin['id']],
['root' => $admin['id']]
])
->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_asc('id')->findArray();
])->order_by_asc('id');
$d = Paginator::findMany($query);
}
}
$admins = [];
@ -345,16 +363,9 @@ switch ($action) {
$admins[$adm['id']] = $adm['fullname'];
}
}
if ($isApi) {
showResult(true, $action, [
'admins' => $d,
'roots' => $admins
], ['search' => $search]);
}
$ui->assign('admins', $admins);
$ui->assign('d', $d);
$ui->assign('search', $search);
$ui->assign('paginator', $paginator);
run_hook('view_list_admin'); #HOOK
$ui->display('users.tpl');
break;
@ -390,20 +401,11 @@ switch ($action) {
if ($d['user_type'] == 'Sales') {
$ui->assign('agent', ORM::for_table('tbl_users')->where('id', $d['root'])->find_array()[0]);
}
if ($isApi) {
unset($d['password']);
$agent = $ui->get('agent');
if ($agent) unset($agent['password']);
showResult(true, $action, [
'admin' => $d,
'agent' => $agent
], ['search' => $search]);
}
$ui->assign('d', $d);
$ui->assign('_title', $d['username']);
$ui->display('users-view.tpl');
} else {
r2(U . 'settings/users', 'e', $_L['Account_Not_Found']);
r2(U . 'settings/users', 'e', Lang::T('Account Not Found'));
}
break;
case 'users-edit':
@ -440,7 +442,7 @@ switch ($action) {
run_hook('view_edit_admin'); #HOOK
$ui->display('users-edit.tpl');
} else {
r2(U . 'settings/users', 'e', $_L['Account_Not_Found']);
r2(U . 'settings/users', 'e', Lang::T('Account Not Found'));
}
break;
@ -459,7 +461,7 @@ switch ($action) {
$d->delete();
r2(U . 'settings/users', 's', Lang::T('User deleted Successfully'));
} else {
r2(U . 'settings/users', 'e', $_L['Account_Not_Found']);
r2(U . 'settings/users', 'e', Lang::T('Account Not Found'));
}
break;

View File

@ -40,11 +40,10 @@ switch ($action) {
case 'list-activated':
$ui->assign('_system_menu', 'list-activated');
$paginator = Paginator::build(ORM::for_table('tbl_transactions'), ['username' => $user['username']]);
$d = ORM::for_table('tbl_transactions')->where('username', $user['username'])->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many();
$query = ORM::for_table('tbl_transactions')->where('username', $user['username'])->order_by_asc('id');
$d = Paginator::findMany($query);
$ui->assign('d', $d);
$ui->assign('paginator', $paginator);
run_hook('customer_view_activation_list'); #HOOK
$ui->display('user-activation-list.tpl');
@ -62,6 +61,7 @@ switch ($action) {
}else{
r2(U . 'voucher/list-activated', 'e', Lang::T('Not Found'));
}
break;
default:
$ui->display('a404.tpl');
}

View File

@ -1,149 +1,99 @@
<?php
include "../init.php";
$isCli = true;
if (php_sapi_name() !== 'cli') {
$isCli = false;
$isCli = (php_sapi_name() !== 'cli') ? false : true;
if (!$isCli) {
echo "<pre>";
}
echo "PHP Time\t" . date('Y-m-d H:i:s') . "\n";
$res = ORM::raw_execute('SELECT NOW() AS WAKTU;');
$statement = ORM::get_last_statement();
$rows = array();
$rows = [];
while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
echo "MYSQL Time\t" . $row['WAKTU'] . "\n";
}
$_c = $config;
$textExpired = Lang::getNotifText('expired');
$d = ORM::for_table('tbl_user_recharges')->where('status', 'on')->where_lte('expiration', date("Y-m-d"))->find_many();
echo "Found " . count($d) . " user(s)\n";
run_hook('cronjob'); #HOOK
$recharges = ORM::for_table('tbl_user_recharges')
->where('status', 'on')
->where_lte('expiration', date("Y-m-d"))
->find_many();
foreach ($d as $ds) {
if ($ds['type'] == 'Hotspot') { # HOTSPOT
$date_now = strtotime(date("Y-m-d H:i:s"));
$expiration = strtotime($ds['expiration'] . ' ' . $ds['time']);
echo $ds['expiration'] . " : " . (($isCli) ? $ds['username'] : Lang::maskText($ds['username']));
if ($date_now >= $expiration) {
echo "Found " . count($recharges) . " user(s)\n";
run_hook('cronjob'); // HOOK
foreach ($recharges as $recharge) {
$dateNow = strtotime(date("Y-m-d H:i:s"));
$expiration = strtotime($recharge['expiration'] . ' ' . $recharge['time']);
echo $recharge['expiration'] . " : " . (($isCli) ? $recharge['username'] : Lang::maskText($recharge['username']));
if ($dateNow >= $expiration) {
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 = 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']));
} else {
Radius::upsertCustomerAttr($c['username'], 'Framed-Pool', $p['pool_expired'], ':=');
print_r(Radius::disconnectCustomer($c['username']));
}
} else {
$client = Mikrotik::getClient($m['ip_address'], $m['username'], $m['password']);
if (!empty($p['pool_expired'])) {
Mikrotik::setHotspotUserPackage($client, $c['username'], 'EXPIRED NUXBILL ' . $p['pool_expired']);
// }if (!empty($p['list_expired'])) {
// $ip = Mikrotik::getIpHotspotUser($client, $ds['username']);
// Mikrotik::addIpToAddressList($client, $ip, $p['list_expired'], $c['username']);
} else {
Mikrotik::removeHotspotUser($client, $c['username']);
}
Mikrotik::removeHotspotActiveUser($client, $c['username']);
}
echo Message::sendPackageNotification($c, $u['namebp'], $price, $textExpired, $config['user_notification_expired']) . "\n";
//update database user dengan status off
$u->status = 'off';
$u->save();
$userRecharge = ORM::for_table('tbl_user_recharges')->where('id', $recharge['id'])->find_one();
$customer = ORM::for_table('tbl_customers')->where('id', $recharge['customer_id'])->find_one();
$plan = ORM::for_table('tbl_plans')->where('id', $userRecharge['plan_id'])->find_one();
$router = ($recharge['type'] == 'Hotspot') ? Mikrotik::info($recharge['routers']) : ORM::for_table('tbl_routers')->where('name', $recharge['routers'])->find_one();
// autorenewal from deposit
if ($config['enable_balance'] == 'yes' && $c['auto_renewal']) {
list($bills, $add_cost) = User::getBills($ds['customer_id']);
if ($plan['is_radius']) {
if (empty($plan['pool_expired'])) {
print_r(Radius::customerDeactivate($customer['username']));
} else {
Radius::upsertCustomerAttr($customer['username'], 'Framed-Pool', $plan['pool_expired'], ':=');
print_r(Radius::disconnectCustomer($customer['username']));
}
} else {
$client = Mikrotik::getClient($router['ip_address'], $router['username'], $router['password']);
if (!empty($plan['pool_expired'])) {
if ($recharge['type'] == 'Hotspot') {
Mikrotik::setHotspotUserPackage($client, $customer['username'], 'EXPIRED NUXBILL ' . $plan['pool_expired']);
} else {
Mikrotik::setPpoeUserPlan($client, $customer['username'], 'EXPIRED NUXBILL ' . $plan['pool_expired']);
}
} else {
if ($recharge['type'] == 'Hotspot') {
Mikrotik::removeHotspotUser($client, $customer['username']);
Mikrotik::removeHotspotActiveUser($client, $customer['username']);
} else {
Mikrotik::removePpoeUser($client, $customer['username']);
Mikrotik::removePpoeActive($client, $customer['username']);
}
}
}
echo Message::sendPackageNotification($customer, $userRecharge['namebp'], $plan['price'], $textExpired, $config['user_notification_expired']) . "\n";
$userRecharge->status = 'off';
$userRecharge->save();
if ($config['enable_balance'] == 'yes' && $customer['auto_renewal']) {
list($bills, $add_cost) = User::getBills($recharge['customer_id']);
if ($add_cost > 0) {
if (!empty($add_cost)) {
$p['price'] += $add_cost;
$plan['price'] += $add_cost;
}
}
if ($p && $p['enabled'] && $c['balance'] >= $p['price']) {
if (Package::rechargeUser($ds['customer_id'], $p['routers'], $p['id'], 'Customer', 'Balance')) {
// if success, then get the balance
Balance::min($ds['customer_id'], $p['price']);
echo "plan enabled: $p[enabled] | User balance: $c[balance] | price $p[price]\n";
echo "auto renewall Success\n";
if ($plan && $plan['enabled'] && $customer['balance'] >= $plan['price']) {
if (Package::rechargeUser($recharge['customer_id'], $plan['routers'], $plan['id'], 'Customer', 'Balance')) {
Balance::min($recharge['customer_id'], $plan['price']);
echo "Plan enabled: $plan[enabled] | User balance: $customer[balance] | Price: $plan[price]\n";
echo "Autorenewal Success\n";
} else {
echo "plan enabled: $p[enabled] | User balance: $c[balance] | price $p[price]\n";
echo "auto renewall Failed\n";
Message::sendTelegram("FAILED RENEWAL #cron\n\n#u$c[username] #buy #Hotspot \n" . $p['name_plan'] .
"\nRouter: " . $p['routers'] .
"\nPrice: " . $p['price']);
echo "Plan enabled: $plan[enabled] | User balance: $customer[balance] | Price: $plan[price]\n";
echo "Autorenewal Failed\n";
Message::sendTelegram("FAILED RENEWAL #cron\n\n#u$customer[username] #buy #" . (($recharge['type'] == 'Hotspot') ? 'Hotspot' : 'PPPOE') . " \n" . $plan['name_plan'] .
"\nRouter: " . $plan['routers'] .
"\nPrice: " . $plan['price']);
}
} else {
echo "no renewall | plan enabled: $p[enabled] | User balance: $c[balance] | price $p[price]\n";
echo "No renewal | Plan enabled: $plan[enabled] | User balance: $customer[balance] | Price: $plan[price]\n";
}
} else {
echo "no renewall | balance $config[enable_balance] auto_renewal $c[auto_renewal]\n";
}
} else
echo " : ACTIVE \r\n";
} else { # PPPOE
$date_now = strtotime(date("Y-m-d H:i:s"));
$expiration = strtotime($ds['expiration'] . ' ' . $ds['time']);
echo $ds['expiration'] . " : " . (($isCli) ? $ds['username'] : Lang::maskText($ds['username']));
if ($date_now >= $expiration) {
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();
$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']));
} else {
Radius::upsertCustomerAttr($c['username'], 'Framed-Pool', $p['pool_expired'], ':=');
print_r(Radius::disconnectCustomer($c['username']));
echo "No renewal | Balance: $config[enable_balance] Auto-renewal: $customer[auto_renewal]\n";
}
} else {
$client = Mikrotik::getClient($m['ip_address'], $m['username'], $m['password']);
if (!empty($p['pool_expired'])) {
Mikrotik::setPpoeUserPlan($client, $c['username'], 'EXPIRED NUXBILL ' . $p['pool_expired']);
} else {
Mikrotik::removePpoeUser($client, $c['username']);
}
Mikrotik::removePpoeActive($client, $c['username']);
}
echo Message::sendPackageNotification($c, $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']) {
list($bills, $add_cost) = User::getBills($ds['customer_id']);
if ($add_cost > 0) {
if (!empty($add_cost)) {
$p['price'] += $add_cost;
}
}
if ($p && $p['enabled'] && $c['balance'] >= $p['price']) {
if (Package::rechargeUser($ds['customer_id'], $p['routers'], $p['id'], 'Customer', 'Balance')) {
// if success, then get the balance
Balance::min($ds['customer_id'], $p['price']);
echo "plan enabled: $p[enabled] | User balance: $c[balance] | price $p[price]\n";
echo "auto renewall Success\n";
} else {
echo "plan enabled: $p[enabled] | User balance: $c[balance] | price $p[price]\n";
echo "auto renewall Failed\n";
Message::sendTelegram("FAILED RENEWAL #cron\n\n#u$c[username] #buy #PPPOE \n" . $p['name_plan'] .
"\nRouter: " . $p['routers'] .
"\nPrice: " . $p['price']);
}
}
}
} else
echo " : ACTIVE \r\n";
}
}

View File

@ -2,8 +2,8 @@
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
* This file for reminding user about expiration
* Example to run every at 7:00 in the morning
* This file is for reminding users about expiration
* Example to run every day at 7:00 in the morning:
* 0 7 * * * /usr/bin/php /var/www/system/cron_reminder.php
**/
@ -15,10 +15,9 @@ if (php_sapi_name() !== 'cli') {
echo "<pre>";
}
$d = ORM::for_table('tbl_user_recharges')->where('status', 'on')->find_many();
run_hook('cronjob_reminder'); #HOOK
$recharges = ORM::for_table('tbl_user_recharges')->where('status', 'on')->find_many();
run_hook('cronjob_reminder'); // HOOK
echo "PHP Time\t" . date('Y-m-d H:i:s') . "\n";
$res = ORM::raw_execute('SELECT NOW() AS WAKTU;');
@ -28,40 +27,35 @@ while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
echo "MYSQL Time\t" . $row['WAKTU'] . "\n";
}
$day7 = date('Y-m-d', strtotime("+7 day"));
$day3 = date('Y-m-d', strtotime("+3 day"));
$day1 = date('Y-m-d', strtotime("+1 day"));
print_r([$day1, $day3, $day7]);
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();
list($bills, $add_cost) = User::getBills($ds['customer_id']);
if ($add_cost > 0) {
if (!empty($add_cost)) {
$p['price'] += $add_cost;
}
}
if ($p['validity_unit'] == 'Period') {
foreach ($recharges as $recharge) {
if (in_array($recharge['expiration'], [$day1, $day3, $day7])) {
$user_recharge = ORM::for_table('tbl_user_recharges')->where('id', $recharge['id'])->find_one();
$plan = ORM::for_table('tbl_plans')->where('id', $user_recharge['plan_id'])->find_one();
$customer = ORM::for_table('tbl_customers')->where('id', $recharge['customer_id'])->find_one();
if ($plan['validity_unit'] == 'Period') {
// Postpaid price from field
$add_inv = User::getAttribute("Invoice", $ds['customer_id']);
if (empty ($add_inv) or $add_inv == 0) {
$price = Lang::moneyFormat($p['price']);
$additional_invoice = User::getAttribute("Invoice", $recharge['customer_id']);
if (empty($additional_invoice) || $additional_invoice == 0) {
$price = $plan['price'];
} else {
$price = Lang::moneyFormat($add_inv);
$price = $additional_invoice;
}
} else {
$price = Lang::moneyFormat($p['price']);
$price = $plan['price'];
}
//$price = Lang::moneyFormat($p['price']);
if ($ds['expiration'] == $day7) {
echo Message::sendPackageNotification($c, $p['name_plan'], $price, Lang::getNotifText('reminder_7_day'), $config['user_notification_reminder']) . "\n";
} else if ($ds['expiration'] == $day3) {
echo Message::sendPackageNotification($c, $p['name_plan'], $price, Lang::getNotifText('reminder_3_day'), $config['user_notification_reminder']) . "\n";
} else if ($ds['expiration'] == $day1) {
echo Message::sendPackageNotification($c, $p['name_plan'], $price, Lang::getNotifText('reminder_1_day'), $config['user_notification_reminder']) . "\n";
if ($recharge['expiration'] == $day7) {
echo Message::sendPackageNotification($customer, $plan['name_plan'], $price, Lang::getNotifText('reminder_7_day'), $config['user_notification_reminder']) . "\n";
} elseif ($recharge['expiration'] == $day3) {
echo Message::sendPackageNotification($customer, $plan['name_plan'], $price, Lang::getNotifText('reminder_3_day'), $config['user_notification_reminder']) . "\n";
} elseif ($recharge['expiration'] == $day1) {
echo Message::sendPackageNotification($customer, $plan['name_plan'], $price, Lang::getNotifText('reminder_1_day'), $config['user_notification_reminder']) . "\n";
}
}
}

View File

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

View File

@ -1,5 +1,5 @@
{
"Log_in": "Log-in",
"Log_in": "Login",
"Register": "Register",
"Announcement": "Announcement",
"Registration_Info": "Registration Info",
@ -484,7 +484,6 @@
"Current_Cycle": "Current Cycle",
"Additional_Cost": "Additional Cost",
"Remaining": "Remaining",
"": "",
"Not_Found": "Not Found",
"Cash": "Cash",
"Payment_not_found": "Payment not found",
@ -492,19 +491,13 @@
"Cache_cleared_successfully_": "Cache cleared successfully!",
"Paid": "Paid",
"Send_Message": "Send Message",
"Send_SMS_WA_Message": "Send SMS\/WA Message",
"Send_Bulk_SMS_WA_Message": "Send Bulk SMS\/WA Message",
"Send_Personal_Message": "Send Personal Message",
"Send_Via": "Send Via",
"Compose_your_message___": "Compose your message...",
"Use_placeholders_": "Use placeholders:",
"__name__": "[[name]]",
"Customer_Name": "Customer Name",
"__user_name__": "[[user_name]]",
"Customer_Username": "Customer Username",
"__phone__": "[[phone]]",
"Customer_Phone": "Customer Phone",
"__company_name__": "[[company_name]]",
"Your_Company_Name": "Your Company Name",
"Message_Sent_Successfully": "Message Sent Successfully",
"Send_Bulk_Message": "Send Bulk Message",
@ -512,5 +505,42 @@
"All_Customers": "All Customers",
"New_Customers": "New Customers",
"Expired_Customers": "Expired Customers",
"Active_Customers": "Active Customers"
"Active_Customers": "Active Customers",
"Map": "Map",
"Customer_Location": "Customer Location",
"Account_Type": "Account Type",
"Coordinates": "Coordinates",
"Latitude_and_Longitude_coordinates_for_map_must_be_separate_with_comma____": "Latitude and Longitude coordinates for map must be separate with comma &quot;,&quot;",
"Customer_Geo_Location_Information": "Customer Geo Location Information",
"List": "List",
"Lists": "Lists",
"Single_Customer": "Single Customer",
"Bulk_Customers": "Bulk Customers",
"Message_per_time": "Message per time",
"5_Messages": "5 Messages",
"10_Messages": "10 Messages",
"15_Messages": "15 Messages",
"20_Messages": "20 Messages",
"30_Messages": "30 Messages",
"40_Messages": "40 Messages",
"50_Messages": "50 Messages",
"60_Messages": "60 Messages",
"Use_20_and_above_if_you_are_sending_to_all_customers_to_avoid_server_time_out": "Use 20 and above if you are sending to all customers to avoid server time out",
"Delay": "Delay",
"No_Delay": "No Delay",
"5_Seconds": "5 Seconds",
"10_Seconds": "10 Seconds",
"15_Seconds": "15 Seconds",
"20_Seconds": "20 Seconds",
"Use_at_least_5_secs_if_you_are_sending_to_all_customers_to_avoid_being_banned_by_your_message_provider": "Use at least 5 secs if you are sending to all customers to avoid being banned by your message provider",
"Testing__if_checked_no_real_message_is_sent_": "Testing [if checked no real message is sent]",
"All_fields_are_required": "All fields are required",
"Personal": "Personal",
"Email_Notification": "Email Notification",
"Router_Name___Location": "Router Name \/ Location",
"Plan_Category": "Plan Category",
"ID": "ID",
"Internet_Plan": "Internet Plan",
"Privacy_Policy": "Privacy Policy",
"Terms_and_Conditions": "Terms and Conditions"
}

View File

@ -1,381 +1,3 @@
{
"Log_in": "Masuk",
"Register": "Daftar",
"Announcement": "Pemberitahuan",
"Registration_Info": "Info Pendaftaran",
"Voucher_not_found__please_buy_voucher_befor_register": "Voucher tidak ditemukan, silakan beli voucher sebelum mendaftar",
"Register_Success__You_can_login_now": "Daftar Sukses! Anda dapat masuk sekarang",
"Log_in_to_Member_Panel": "Masuk ke Panel Anggota",
"Register_as_Member": "Daftar sebagai Anggota",
"Enter_Admin_Area": "Masuk ke Admin Panel",
"PHPNuxBill": "PHPNuxBill",
"Username": "Nama Pengguna",
"Password": "Kata Sandi",
"Passwords_does_not_match": "Kata Sandi tidak cocok",
"Account_already_axist": "Akun telah ada",
"Manage": "Mengelola",
"Submit": "Kirim",
"Save_Changes": "Simpan perubahan",
"Cancel": "Batal",
"Edit": "Sunting",
"Delete": "Hapus",
"Welcome": "Selamat Datang",
"Data_Created_Successfully": "Data Berhasil Dibuat",
"Data_Updated_Successfully": "Data Berhasil Diperbarui",
"Data_Deleted_Successfully": "Data Berhasil Dihapus",
"Static_Pages": "Halaman Statis",
"Failed_to_save_page__make_sure_i_can_write_to_folder_pages___i_chmod_664_pages___html_i_": "Gagal menyimpan halaman, pastikan diperbolehkan menulis file di folder pages, <i>chmod 664 pages\/*.html<i>",
"Saving_page_success": "Menyimpan halaman sukses",
"Sometimes_you_need_to_refresh_3_times_until_content_change": "Terkadang Anda perlu menyegarkan 3 kali hingga konten berubah",
"Dashboard": "Dasbor",
"Search_Customers___": "Cari Member...",
"My_Account": "Akun Saya",
"My_Profile": "Profil Saya",
"Settings": "Pengaturan",
"Edit_Profile": "Sunting profil",
"Change_Password": "Ganti kata sandi",
"Logout": "Keluar",
"Services": "Layanan",
"Bandwidth_Plans": "Paket Bandwidth",
"Bandwidth_Name": "Nama Bandwidth",
"New_Bandwidth": "Baru Bandwidth",
"Edit_Bandwidth": "Sunting Bandwidth",
"Add_New_Bandwidth": "Tambahkan Bandwidth Baru",
"Rate_Download": "Nilai Unduhan",
"Rate_Upload": "Nilai Unggahan",
"Name_Bandwidth_Already_Exist": "NamanBandwidth Sudah Ada",
"Hotspot_Plans": "Paket Hotspot",
"PPPOE_Plans": "Paket PPPoE",
"Plan_Name": "Nama Paket",
"New_Service_Plan": "Paket Layanan Baru",
"Add_Service_Plan": "Tambah Paket Layanan",
"Edit_Service_Plan": "Sunting Paket Layanan",
"Name_Plan_Already_Exist": "Nama Paket Sudah Ada",
"Plan_Type": "Jenis Paket",
"Plan_Price": "Harga Paket",
"Limit_Type": "Tipe Batas",
"Unlimited": "Tak terbatas",
"Limited": "Terbatas",
"Time_Limit": "Batas waktu",
"Data_Limit": "Batas Data",
"Both_Limit": "Keduanya Membatasi",
"Plan_Validity": "Waktu Paket",
"Select_Bandwidth": "Pilih Bandwidth",
"Shared_Users": "Berbagi Pelanggan",
"Choose_User_Type_Sales_to_disable_access_to_Settings": "Pilih Sales untuk menonaktifkan akses ke Pengaturan",
"Current_Password": "Kata sandi saat ini",
"New_Password": "Kata sandi baru",
"Administrator": "Administrator",
"Sales": "Sales",
"Member": "Anggota",
"Confirm_New_Password": "Konfirmasi sandi baru",
"Confirm_Password": "konfirmasi sandi",
"Full_Name": "Nama Lengkap",
"User_Type": "Tipe Pelanggan",
"Address": "Alamat",
"Created_On": "Dibuat pada",
"Expires_On": "Kadaluarsa pada",
"Phone_Number": "Nomor telepon",
"User_deleted_Successfully": "Pelanggan berhasil dihapus",
"Full_Administrator": "Administrator Penuh",
"Keep_Blank_to_do_not_change_Password": "Biarkan Kosong apabila tidak ingin mengubah Kata Sandi",
"Keep_it_blank_if_you_do_not_want_to_show_currency_code": "Kosongkan jika Anda tidak ingin menampilkan kode mata uang",
"Theme_Style": "Gaya Tema",
"Theme_Color": "Warna Tema",
"Default_Language": "Bahasa Bawaan",
"Network": "Jaringan",
"Routers": "Router",
"IP_Pool": "IP Pool",
"New_Router": "Router baru",
"Add_Router": "Tambahkan Router",
"Edit_Router": "Sunting Router",
"Router_Name": "Nama Router",
"IP_Address": "Alamat IP",
"Router_Secret": "Rahasia Router",
"Description": "Deskrispi",
"IP_Router_Already_Exist": "IP Router Sudah Ada",
"Name_Pool": "Nama Pool",
"Range_IP": "Rentang IP",
"New_Pool": "Pool baru",
"Add_Pool": "Tambahkan Pool",
"Edit_Pool": "Sunting Pool",
"Pool_Name_Already_Exist": "Nama Pool Sudah Ada",
"Refill_Account": "Isi Ulang Akun",
"Recharge_Account": "Isi Ulang Akun",
"Select_Account": "Pilih Akun",
"Service_Plan": "Paket Layanan",
"Recharge": "Isi Ulang",
"Method": "Metode",
"Account_Created_Successfully": "Akun Berhasil Dibuat",
"Database_Status": "Status Database",
"Total_Database_Size": "Ukuran Total Database",
"Download_Database_Backup": "Unduh Cadangan Database",
"Table_Name": "Nama Tabel",
"Rows": "Baris",
"Size": "Ukuran",
"Customer": "Pelanggan",
"Add_New_Contact": "Tambahkan Kontak Baru",
"Edit_Contact": "Sunting Kontak",
"List_Contact": "Daftar Kontak",
"Manage_Contact": "Kelola Kontak",
"Reports": "Laporan",
"Daily_Reports": "Laporan Harian",
"Period_Reports": "Laporan Periode",
"All_Transactions": "Semua Transaksi",
"Total_Income": "Jumlah Pemasukan",
"All_Transactions_at_Date": "Semua Transaksi pada Tanggal",
"Export_for_Print": "Ekspor untuk Cetak",
"Print": "Cetak",
"Export_to_PDF": "Ekspor ke PDF",
"Click_Here_to_Print": "Klik Disini untuk Mencetak",
"You_can_use_html_tag": "Anda dapat menggunakan tag html",
"Date_Format": "Format tanggal",
"Income_Today": "Pendapatan Hari Ini",
"Income_This_Month": "Penghasilan Bulan Ini",
"Users_Active": "Pelanggan Aktif",
"Total_Users": "Total Pelanggan",
"Users": "Pelanggan",
"Edit_User": "Sunting Pelanggan",
"Last_Login": "Terakhir Masuk",
"Administrator_Users": "Pengguna Administrator",
"Manage_Administrator": "Kelola Administrator",
"Add_New_Administrator": "Tambahkan Administrator Baru",
"Localisation": "Lokalisasi",
"Backup_Restore": "Cadangkan\/Pulihkan",
"General_Settings": "Pengaturan Umum",
"Date": "Tanggal",
"Login_Successful": "Berhasil Masuk",
"Failed_Login": "Gagal Masuk",
"Settings_Saved_Successfully": "Pengaturan Berhasil Disimpan",
"User_Updated_Successfully": "Pengguna Berhasil Diperbarui",
"User_Expired__Today": "Pengguna Kedaluwarsa, Hari Ini",
"Activity_Log": "Log aktivitas",
"View_Reports": "Lihat Laporan",
"View_All": "Lihat semua",
"Number_of_Vouchers": "Jumlah Voucher",
"Length_Code": "Kode Panjang",
"Code_Voucher": "Kode Voucher",
"Voucher": "Voucher",
"Hotspot_Voucher": "Voucher Hotspot",
"Status_Voucher": "Voucher Status",
"Add_Vouchers": "Tambah Voucher",
"Create_Vouchers_Successfully": "Buat Voucher Berhasil",
"Generate": "Menghasilkan",
"Print_side_by_side__it_will_easy_to_cut": "Info Cetak",
"From_Date": "Dari tanggal",
"To_Date": "Hingga saat ini",
"New_Service": "Layanan Baru",
"Type": "Jenis",
"Finish": "Menyelesaikan",
"Application_Name__Company_Name": "Nama Aplikasi\/ Nama Perusahaan",
"This_Name_will_be_shown_on_the_Title": "Nama ini akan ditampilkan pada Judul",
"Next": "Berikutnya",
"Last": "Terakhir",
"Timezone": "Zona waktu",
"Decimal_Point": "Titik Desimal",
"Thousands_Separator": "Pemisah Ribuan",
"Currency_Code": "Kode mata uang",
"Order_Voucher": "Pesan Voucher",
"Voucher_Activation": "Aktivasi Voucher",
"List_Activated_Voucher": "Daftar Voucher yang Diaktifkan",
"Enter_voucher_code_here": "Masukkan kode voucher di sini",
"Private_Message": "Pesan Pribadi",
"Inbox": "Kotak Masuk",
"Outbox": "Kotak Keluar",
"Compose": "Menyusun",
"Send_to": "Kirim ke",
"Title": "Judul",
"Message": "Pesan",
"Your_Account_Information": "Informasi Akun Anda",
"Welcome_to_the_Panel_Members_page__on_this_page_you_can_": "Selamat datang di halaman Anggota Panel, di halaman ini Anda dapat:",
"Invalid_Username_or_Password": "Nama pengguna dan kata sandi salah",
"You_do_not_have_permission_to_access_this_page": "Anda tidak memiliki izin untuk mengakses halaman ini",
"Incorrect_Current_Password": "Kata Sandi Saat Ini Salah",
"Password_changed_successfully__Please_login_again": "Kata sandi berhasil diubah, Silakan login kembali",
"All_field_is_required": "Semua bidang wajib diisi",
"Voucher_Not_Valid": "Voucher Tidak Berlaku",
"Activation_Vouchers_Successfully": "Aktivasi Voucher Berhasil",
"Data_Not_Found": "Data Tidak Ditemukan",
"Search_by_Username": "Cari berdasarkan Nama Pengguna",
"Search_by_Name": "Cari berdasarkan Nama",
"Search_by_Code_Voucher": "Cari berdasarkan Kode Voucher",
"Search": "Mencari",
"Select_a_customer": "Pilih pelanggan",
"Select_Routers": "Pilih Router",
"Select_Plans": "Pilih Paket",
"Select_Pool": "Pilih Pool",
"Hrs": "Jam",
"Mins": "Menit",
"Days": "Hari",
"Months": "Bulan",
"Add_Language": "Tambahkan Bahasa",
"Language_Name": "Nama Bahasa",
"Folder_Name": "Nama Folder",
"Translator": "Penerjemah",
"Language_Name_Already_Exist": "Nama Bahasa Sudah Ada",
"Payment_Gateway": "Gerbang Pembayaran",
"Community": "Komunitas",
"1_user_can_be_used_for_many_devices_": "1 pengguna bisa digunakan untuk banyak perangkat?",
"Cannot_be_change_after_saved": "Tidak dapat diubah setelah disimpan",
"Explain_Coverage_of_router": "Jelaskan Cakupan router",
"Name_of_Area_that_router_operated": "Nama area tempat router dioperasikan",
"Payment_Notification_URL__Recurring_Notification_URL__Pay_Account_Notification_URL": "URL Notifikasi Pembayaran, URL Notifikasi Berulang, URL Notifikasi Akun Bayar",
"Finish_Redirect_URL__Unfinish_Redirect_URL__Error_Redirect_URL": "Selesaikan URL Pengalihan, Selesaikan URL Pengalihan, URL Pengalihan Kesalahan",
"Status": "Status",
"Plan_Not_found": "Paket Tidak ditemukan",
"Failed_to_create_transaction_": "Gagal membuat transaksi.",
"Seller_has_not_yet_setup_Xendit_payment_gateway": "Penjual belum menyiapkan gateway pembayaran Xendit",
"Admin_has_not_yet_setup_Xendit_payment_gateway__please_tell_admin": "Admin belum menyiapkan gerbang pembayaran Xendit, mohon beritahu admin",
"Buy_this__your_active_package_will_be_overwrite": "Beli ini? Paket aktif Anda akan ditimpa",
"You_already_have_unpaid_transaction__cancel_it_or_pay_it_": "Anda sudah memiliki transaksi yang belum dibayar, batalkan atau bayar.",
"Transaction_Not_found": "Transaksi Tidak ditemukan",
"Cancel_it_": "Batalkan itu?",
"expired": "kedaluwarsa",
"Check_for_Payment": "Periksa Pembayaran",
"Transaction_still_unpaid_": "Transaksi masih belum dibayar.",
"Paid_Date": "Tanggal Pembayaran",
"Transaction_has_been_paid_": "Transaksi telah dibayar.",
"PAID": "DIBAYAR",
"CANCELED": "DIBATALKAN",
"UNPAID": "BELUM DIBAYAR",
"PAY_NOW": "BAYAR SEKARANG",
"Buy_Hotspot_Plan": "Beli Paket Hotspot",
"Buy_PPOE_Plan": "Beli Paket PPPoE",
"Package": "Paket",
"Order_Internet_Package": "Pesan Paket Internet",
"Unknown_Command_": "Perintah Tidak Diketahui.",
"Checking_payment": "Memeriksa pembayaran",
"Create_Transaction_Success": "Transaksi Berhasil Dibuat",
"You_have_unpaid_transaction": "Anda memiliki transaksi yang belum dibayar",
"TripayPayment_Channel": "Saluran Pembayaran Tripay",
"Payment_Channel": "Saluran Pembayaran",
"Payment_check_failed_": "Pemeriksaan pembayaran gagal.",
"Order_Package": "Pesan Paket",
"Transactions": "Transaksi",
"Payments": "Pembayaran",
"History": "Riwayat",
"Order_History": "Riwayat Pesanan",
"Gateway": "Gerbang",
"Date_Done": "Tanggal Selesai",
"Unpaid_Order": "Pesanan Belum Dibayar",
"Payment_Gateway_Not_Found": "Gerbang Pembayaran Tidak Ditemukan",
"Payment_Gateway_saved_successfully": "Gerbang Pembayaran berhasil disimpan",
"ORDER": "MEMESAN",
"Package_History": "Riwayat Paket",
"Buy_History": "Riwayat Beli",
"Activation_History": "Riwayat Aktivasi",
"Buy_Package": "Beli Paket",
"Email": "Surel",
"Company_Footer": "Catatan Kaki Perusahaan",
"Will_show_below_user_pages": "Akan ditampilkan di bawah halaman pengguna",
"Request_OTP": "Minta OTP",
"Verification_Code": "Kode Verifikasi",
"SMS_Verification_Code": "Kode Verifikasi SMS",
"Please_enter_your_email_address": "Silakan masukkan alamat email Anda",
"Failed_to_create_Paypal_transaction_": "Gagal membuat transaksi Paypal.",
"Plugin": "Plugin",
"Plugin_Manager": "Manajer Plugin",
"User_Notification": "Pemberitahuan Pelanggan",
"Expired_Notification": "Pemberitahuan Kedaluarsa",
"User_will_get_notification_when_package_expired": "Pengguna akan mendapat notifikasi ketika paket sudah habis masa berlakunya",
"Expired_Notification_Message": "Pesan Pemberitahuan Kedaluwarsa",
"Payment_Notification": "Notifikasi Pembayaran",
"User_will_get_invoice_notification_when_buy_package_or_package_refilled": "Pengguna akan mendapatkan notifikasi invoice saat membeli paket atau isi ulang paket",
"Current_IP": "IP saat ini",
"Current_MAC": "MAC saat ini",
"Login_Status": "Status Masuk",
"Login_Request_successfully": "Permintaan Masuk berhasil",
"Logout_Request_successfully": "Permintaan Keluar berhasil",
"Disconnect_Internet_": "Putuskan sambungan Internet?",
"Not_Online__Login_now_": "Tidak , Masuk sekarang?",
"You_are_Online__Logout_": "Kamu sedang aktif, ingin keluar?",
"Connect_to_Internet_": "Hubungkan ke Internet?",
"Your_account_not_connected_to_internet": "Akun Anda tidak terhubung ke internet",
"Failed_to_create_transaction__": "Gagal membuat transaksi. ",
"Failed_to_check_status_transaction__": "Gagal memeriksa status transaksi. ",
"Disable_Voucher": "Nonaktifkan Voucher",
"Balance": "Saldo",
"Balance_System": "Saldo Sistem",
"Enable_System": "Aktifkan Sistem",
"Allow_Transfer": "Izinkan Transfer",
"Telegram_Notification": "Pemberitahuan Telegram",
"SMS_OTP_Registration": "Pendaftaran SMS OTP",
"Whatsapp_Notification": "Pemberitahuan WhatsApp",
"Tawk_to_Chat_Widget": "Widget Obrolan Tawk.to",
"Invoice": "Faktur",
"Country_Code_Phone": "Kode Negara Telepon",
"Voucher_activation_menu_will_be_hidden": "Menu aktivasi voucher akan disembunyikan",
"Customer_can_deposit_money_to_buy_voucher": "Pelanggan dapat menyetor uang untuk membeli voucher",
"Allow_balance_transfer_between_customers": "Izinkan transfer saldo antar pelanggan",
"Reminder_Notification": "Pemberitahuan Pengingat",
"Reminder_Notification_Message": "Pesan Pemberitahuan Pengingat",
"Reminder_7_days": "Pengingat 7 hari",
"Reminder_3_days": "Pengingat 3 hari",
"Reminder_1_day": "Pengingat 1 hari",
"PPPOE_Password": "Kata sandi PPPoE",
"User_Cannot_change_this__only_admin__if_it_Empty_it_will_use_user_password": "Pelanggan tidak dapat mengubah ini, hanya Admin. Jika kosong maka akan menggunakan kata sandi pelanggan",
"Invoice_Balance_Message": "Faktur Pesan Saldo",
"Invoice_Notification_Payment": "Faktur Pemberitahuan Pembayaran",
"Balance_Notification_Payment": "Saldo Pemberitahuan Pembayaran",
"Balance_Plans": "Paket Saldo",
"Buy_Balance": "Beli Saldo",
"Price": "Harga",
"Validity": "Waktu",
"Disable_auto_renewal_": "Nonaktifkan perpanjangan otomatis?",
"Auto_Renewal_On": "Perpanjangan Otomatis Aktif",
"Enable_auto_renewal_": "Aktifkan perpanjangan otomatis?",
"Auto_Renewal_Off": "Perpanjangan Otomatis Mati",
"Refill_Balance": "Isi Ulang Saldo",
"Invoice_Footer": "Catatan Kaki Faktur",
"Pay_With_Balance": "Bayar dengan Saldo",
"Pay_this_with_Balance__your_active_package_will_be_overwrite": "Bayar ini dengan Saldo? Paket aktif Anda akan ditimpa",
"Success_to_buy_package": "Berhasil membeli paket",
"Auto_Renewal": "Perpanjangan otomatis",
"View": "Melihat",
"Back": "Kembali",
"Active": "Aktif",
"Transfer_Balance": "Kirim Saldo",
"Send_your_balance_": "Kirim saldo Anda?",
"Send": "Kirim",
"Cannot_send_to_yourself": "Tidak dapat mengirim ke diri Anda sendiri",
"Sending_balance_success": "Berhasil mengirim saldo",
"From": "Dari",
"To": "Ke",
"insufficient_balance": "Saldo tidak mencukupi",
"Send_Balance": "Kirim Saldo",
"Received_Balance": "Saldo yang Diterima",
"Minimum_Balance_Transfer": "Minimal Transfer Saldo",
"Minimum_Transfer": "Minimal Transfer",
"Company_Logo": "Logo Perusahaan",
"Expired_IP_Pool": "IP Pool Kedaluwarsa",
"Proxy": "Proksi",
"Proxy_Server": "Server Proksi",
"Proxy_Server_Login": "Masuk Server Proksi",
"Hotspot_Plan": "Paket Hotspot",
"PPPOE_Plan": "Paket PPPoE",
"UNKNOWN": "TIDAK DIKENAL",
"Are_You_Sure_": "Apa kamu yakin?",
"Success_to_send_package": "Berhasil mengirim paket",
"Target_has_active_plan__different_with_current_plant_": "Target mempunyai paket aktif, berbeda dengan paket saat ini.",
"Recharge_a_friend": "Isi ulang teman",
"Buy_for_friend": "Beli untuk teman",
"Buy_this_for_friend_account_": "Beli ini untuk akun teman?",
"Review_package_before_recharge": "Tinjau paket sebelum mengisi ulang",
"Activate": "Mengaktifkan Paket",
"Deactivate": "Menonaktifkan Paket",
"Sync": "Sinkronisasi",
"Failed_to_create_PaymeTrust_transaction_": "Gagal membuat transaksi PaymeTrust.",
"Location": "Lokasi",
"Radius_Plans": "Paket Radius",
"Change_title_in_user_Plan_order": "Ubah judul dalam urutan paket pelanggan",
"Logs": "Log",
"Voucher_Format": "Format Voucher",
"Resend_To_Customer": "Kirim Ulang Ke Pelanggan",
"Service_Type": "Service Type",
"Others": "Lainnya",
"PPPoE": "PPPoE",
"Hotspot": "Hotspot",
"Monthly_Registered_Customers": "Pendaftaran Pelanggan perbulan",
"Total_Monthly_Sales": "Total penjualan Perbulan",
"Active_Users": "Pelanggan Aktif"
"Settings_Saved_Successfully": "Pengaturan Berhasil Disimpan"
}

View File

@ -6,13 +6,13 @@
"ALTER TABLE `tbl_customers_meta` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;"
],
"2023.8.14": [
"ALTER TABLE `tbl_customers` ADD `pppoe_password` varchar(45) NOT NULL DEFAULT '1' COMMENT 'For PPPOE Login' AFTER `password`;",
"ALTER TABLE `tbl_customers` ADD `pppoe_password` varchar(45) NOT NULL DEFAULT '' COMMENT 'For PPPOE Login' AFTER `password`;",
"ALTER TABLE `tbl_plans` CHANGE `type` `type` ENUM('Hotspot','PPPOE','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;",
"ALTER TABLE `tbl_transactions` CHANGE `type` `type` ENUM('Hotspot','PPPOE','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;",
"ALTER TABLE `tbl_customers` ADD `auto_renewal` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Auto renewall using balance' AFTER `balance`;"
],
"2023.8.23": [
"ALTER TABLE `tbl_customers` CHANGE `pppoe_password` `pppoe_password` VARCHAR(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '0' COMMENT 'For PPPOE Login';"
"ALTER TABLE `tbl_customers` CHANGE `pppoe_password` `pppoe_password` VARCHAR(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login';"
],
"2023.8.28": [
"ALTER TABLE `tbl_user_recharges` ADD `recharged_time` time NOT NULL DEFAULT '00:00:00' AFTER `recharged_on`;",
@ -78,5 +78,20 @@
],
"2024.3.14" : [
"ALTER TABLE `tbl_transactions` ADD `note` VARCHAR(256) NOT NULL DEFAULT '' COMMENT 'for note' AFTER `type`;"
],
"2024.3.19" : [
"ALTER TABLE `tbl_customers` ADD `coordinates` VARCHAR(50) NOT NULL DEFAULT '' COMMENT 'Latitude and Longitude coordinates' AFTER `email`;"
],
"2024.3.19.1" : [
"ALTER TABLE `tbl_customers` ADD `account_type` ENUM('Business', 'Personal') DEFAULT 'Personal' COMMENT 'For selecting account type' AFTER `coordinates`;"
],
"2024.3.19.2" : [
"ALTER TABLE `tbl_plans` ADD `plan_type` ENUM('Business', 'Personal') DEFAULT 'Personal' COMMENT 'For selecting account type' ;"
],
"2023.3.20": [
"ALTER TABLE `tbl_customers` CHANGE `pppoe_password` `pppoe_password` VARCHAR(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login';"
],
"2024.4.5" : [
"ALTER TABLE `tbl_payment_gateway` ADD `trx_invoice` VARCHAR(25) NOT NULL DEFAULT '' COMMENT 'from tbl_transactions' AFTER `paid_date`;"
]
}

View File

@ -20,9 +20,11 @@
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">
<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.
<b>[[name]]</b> - {Lang::T('will be replaced with Customer Name)}.<br>
<b>[[username]]</b> - {Lang::T('will be replaced with Customer username)}.<br>
<b>[[package]]</b> - {Lang::T('will be replaced with Package name)}.<br>
<b>[[price]]</b> - {Lang::T('will be replaced with Package price)}.<br>
<b>[[bills]]</b> - {Lang::T('additional bills for customers)}.
</p>
</div>
</div>
@ -34,10 +36,12 @@
rows="3">{Lang::htmlspecialchars($_json['reminder_7_day'])}</textarea>
</div>
<p class="help-block col-md-4">
<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.
<b>[[expired_date]]</b> will be replaced with Expiration date.
<b>[[name]]</b> - {Lang::T('will be replaced with Customer Name)}.<br>
<b>[[username]]</b> - {Lang::T('will be replaced with Customer username)}.<br>
<b>[[package]]</b> - {Lang::T('will be replaced with Package name)}.<br>
<b>[[price]]</b> - {Lang::T('will be replaced with Package price)}.<br>
<b>[[expired_date]]</b> - {Lang::T('will be replaced with Expiration date)}.<br>
<b>[[bills]]</b> - {Lang::T('additional bills for customers)}.
</p>
</div>
</div>
@ -49,10 +53,12 @@
rows="3">{Lang::htmlspecialchars($_json['reminder_3_day'])}</textarea>
</div>
<p class="help-block col-md-4">
<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.
<b>[[expired_date]]</b> will be replaced with Expiration date.
<b>[[name]]</b> - {Lang::T('will be replaced with Customer Name)}.<br>
<b>[[username]]</b> - {Lang::T('will be replaced with Customer username)}.<br>
<b>[[package]]</b> - {Lang::T('will be replaced with Package name)}.<br>
<b>[[price]]</b> - {Lang::T('will be replaced with Package price)}.<br>
<b>[[expired_date]]</b> - {Lang::T('will be replaced with Expiration date)}.<br>
<b>[[bills]]</b> - {Lang::T('additional bills for customers)}.
</p>
</div>
</div>
@ -64,10 +70,12 @@
rows="3">{Lang::htmlspecialchars($_json['reminder_1_day'])}</textarea>
</div>
<p class="help-block col-md-4">
<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.
<b>[[expired_date]]</b> will be replaced with Expiration date.
<b>[[name]]</b> - {Lang::T('will be replaced with Customer Name)}.<br>
<b>[[username]]</b> - {Lang::T('will be replaced with Customer username)}.<br>
<b>[[package]]</b> - {Lang::T('will be replaced with Package name)}.<br>
<b>[[price]]</b> - {Lang::T('will be replaced with Package price)}.<br>
<b>[[expired_date]]</b> - {Lang::T('will be replaced with Expiration date)}.<br>
<b>[[bills]]</b> - {Lang::T('additional bills for customers)}.
</p>
</div>
</div>
@ -80,21 +88,22 @@
rows="20">{Lang::htmlspecialchars($_json['invoice_paid'])}</textarea>
</div>
<p class="col-md-4 help-block">
<b>[[company_name]]</b> Your Company Name at Settings.<br>
<b>[[address]]</b> Your Company Address at Settings.<br>
<b>[[phone]]</b> Your Company Phone at Settings.<br>
<b>[[invoice]]</b> invoice number.<br>
<b>[[date]]</b> Date invoice created.<br>
<b>[[payment_gateway]]</b> Payment gateway user paid from.<br>
<b>[[payment_channel]]</b> Payment channel user paid from.<br>
<b>[[type]]</b> is Hotspot/PPPOE.<br>
<b>[[plan_name]]</b> Internet Package.<br>
<b>[[plan_price]]</b> Internet Package Prices.<br>
<b>[[name]]</b> Receiver name.<br>
<b>[[user_name]]</b> Username internet.<br>
<b>[[user_password]]</b> User password.<br>
<b>[[expired_date]]</b> Expired datetime.<br>
<b>[[footer]]</b> Invoice Footer.
<b>[[company_name]]</b> {Lang::T('Your Company Name at Settings)}.<br>
<b>[[address]]</b> {Lang::T('Your Company Address at Settings)}.<br>
<b>[[phone]]</b> - {Lang::T('Your Company Phone at Settings)}.<br>
<b>[[invoice]]</b> - {Lang::T('Invoice number)}.<br>
<b>[[date]]</b> - {Lang::T('Date invoice created)}.<br>
<b>[[payment_gateway]]</b> - {Lang::T('Payment gateway user paid from)}.<br>
<b>[[payment_channel]]</b> - {Lang::T('Payment channel user paid from)}.<br>
<b>[[type]]</b> - {Lang::T('is Hotspot or PPPOE)}.<br>
<b>[[plan_name]]</b> - {Lang::T('Internet Package)}.<br>
<b>[[plan_price]]</b> - {Lang::T('Internet Package Prices)}.<br>
<b>[[name]]</b> - {Lang::T('Receiver name)}.<br>
<b>[[user_name]]</b> - {Lang::T('Username internet)}.<br>
<b>[[user_password]]</b> - {Lang::T('User password)}.<br>
<b>[[expired_date]]</b> - {Lang::T('Expired datetime)}.<br>
<b>[[footer]]</b> - {Lang::T('Invoice Footer)}.<br>
<b>[[note]]</b> - {Lang::T('For Notes by admin)}.<br>
</p>
</div>
</div>
@ -107,23 +116,23 @@
rows="20">{Lang::htmlspecialchars($_json['invoice_balance'])}</textarea>
</div>
<p class="col-md-4 help-block">
<b>[[company_name]]</b> Your Company Name at Settings.<br>
<b>[[address]]</b> Your Company Address at Settings.<br>
<b>[[phone]]</b> Your Company Phone at Settings.<br>
<b>[[invoice]]</b> invoice number.<br>
<b>[[date]]</b> Date invoice created.<br>
<b>[[payment_gateway]]</b> Payment gateway user paid from.<br>
<b>[[payment_channel]]</b> Payment channel user paid from.<br>
<b>[[type]]</b> is Hotspot/PPPOE.<br>
<b>[[plan_name]]</b> Internet Package.<br>
<b>[[plan_price]]</b> Internet Package Prices.<br>
<b>[[name]]</b> Receiver name.<br>
<b>[[user_name]]</b> Username internet.<br>
<b>[[user_password]]</b> User password.<br>
<b>[[trx_date]]</b> Transaction datetime.<br>
<b>[[balance_before]]</b> Balance Before.<br>
<b>[[balance]]</b> Balance After.<br>
<b>[[footer]]</b> Invoice Footer.
<b>[[company_name]]</b> - {Lang::T('Your Company Name at Settings)}.<br>
<b>[[address]]</b> - {Lang::T('Your Company Address at Settings)}.<br>
<b>[[phone]]</b> - {Lang::T('Your Company Phone at Settings)}.<br>
<b>[[invoice]]</b> - {Lang::T('Invoice number)}.<br>
<b>[[date]]</b> - {Lang::T('Date invoice created)}.<br>
<b>[[payment_gateway]]</b> - {Lang::T('Payment gateway user paid from)}.<br>
<b>[[payment_channel]]</b> - {Lang::T('Payment channel user paid from)}.<br>
<b>[[type]]</b> - {Lang::T('is Hotspot or PPPOE)}.<br>
<b>[[plan_name]]</b> - {Lang::T('Internet Package)}.<br>
<b>[[plan_price]]</b> - {Lang::T('Internet Package Prices)}.<br>
<b>[[name]]</b> - {Lang::T('Receiver name)}.<br>
<b>[[user_name]]</b> - {Lang::T('Username internet)}.<br>
<b>[[user_password]]</b> - {Lang::T('User password)}.<br>
<b>[[trx_date]]</b> - {Lang::T('Transaction datetime)}.<br>
<b>[[balance_before]]</b> - {Lang::T('Balance Before)}.<br>
<b>[[balance]]</b> - {Lang::T('Balance After)}.<br>
<b>[[footer]]</b> - {Lang::T('Invoice Footer)}.
</p>
</div>
</div>
@ -136,9 +145,9 @@
rows="3">{if $_json['balance_send']}{Lang::htmlspecialchars($_json['balance_send'])}{else}{Lang::htmlspecialchars($_default['balance_send'])}{/if}</textarea>
</div>
<p class="col-md-4 help-block">
<b>[[name]]</b> Receiver name.<br>
<b>[[balance]]</b> how much balance have been send.<br>
<b>[[current_balance]]</b> Current Balance.
<b>[[name]]</b> - {Lang::T('Receiver name)}.<br>
<b>[[balance]]</b> - {Lang::T('how much balance have been send)}.<br>
<b>[[current_balance]]</b> - {Lang::T('Current Balance)}.
</p>
</div>
</div>
@ -150,9 +159,9 @@
rows="3">{if $_json['balance_received']}{Lang::htmlspecialchars($_json['balance_received'])}{else}{Lang::htmlspecialchars($_default['balance_received'])}{/if}</textarea>
</div>
<p class="col-md-4 help-block">
<b>[[name]]</b> Sender name.<br>
<b>[[balance]]</b> how much balance have been received.<br>
<b>[[current_balance]]</b> Current Balance.
<b>[[name]]</b> - {Lang::T('Sender name)}.<br>
<b>[[balance]]</b> - {Lang::T('how much balance have been received)}.<br>
<b>[[current_balance]]</b> - {Lang::T('Current Balance)}.
</p>
</div>
</div>

View File

@ -213,6 +213,37 @@
</div>
</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>
{Lang::T('Extend Postpaid Expiration')}
</div>
<div class="panel-body">
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Allow Extend')}</label>
<div class="col-md-6">
<select name="extend_expired" id="extend_expired" class="form-control text-muted">
<option value="0">No</option>
<option value="1" {if $_c['extend_expired']}selected="selected" {/if}>Yes</option>
</select>
</div>
<p class="help-block col-md-4">Customer can request to extend expirations</p>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Extend Days')}</label>
<div class="col-md-6">
<input type="text" class="form-control" name="extend_days" placeholder="3" value="{$_c['extend_days']}">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Confirmation Message')}</label>
<div class="col-md-6">
<textarea type="text" rows="4" class="form-control" name="extend_confirmation" placeholder="i agree to extends and will paid full after this">{$_c['extend_confirmation']}</textarea>
</div>
</div>
</div>
<div class="panel-heading">
<div class="btn-group pull-right">
<button class="btn btn-primary btn-xs" title="save" type="submit"><span
@ -340,6 +371,74 @@
<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:testEmail()">Test
Email</a>
<button class="btn btn-primary btn-xs" title="save" type="submit"><span
class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span></button>
</div>
{Lang::T('Email Notification')}
</div>
<div class="panel-body">
<div class="form-group">
<label class="col-md-2 control-label">SMTP Host : port</label>
<div class="col-md-4">
<input type="text" class="form-control" id="smtp_host" name="smtp_host"
value="{$_c['smtp_host']}" placeholder="smtp.host.tld">
</div>
<div class="col-md-2">
<input type="number" class="form-control" id="smtp_port" name="smtp_port"
value="{$_c['smtp_port']}" placeholder="465 587 port">
</div>
<p class="help-block col-md-4">Empty this to use internal mail() PHP</p>
</div>
<div class="form-group">
<label class="col-md-2 control-label">SMTP username</label>
<div class="col-md-6">
<input type="text" class="form-control" id="smtp_user" name="smtp_user"
value="{$_c['smtp_user']}" placeholder="user@host.tld">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">SMTP Password</label>
<div class="col-md-6">
<input type="password" class="form-control" id="smtp_pass" name="smtp_pass"
value="{$_c['smtp_pass']}" onmouseleave="this.type = 'password'"
onmouseenter="this.type = 'text'">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">SMTP Security</label>
<div class="col-md-6">
<select name="smtp_ssltls" id="smtp_ssltls" class="form-control">
<option value="" {if $_c['smtp_ssltls']=='' }selected="selected" {/if}>Not Secure
</option>
<option value="ssl" {if $_c['smtp_ssltls']=='ssl' }selected="selected" {/if}>SSL
</option>
<option value="tls" {if $_c['smtp_ssltls']=='tls' }selected="selected" {/if}>TLS
</option>
</select>
</div>
<p class="help-block col-md-4">UPPERCASE lowercase RaNdoM</p>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Mail From</label>
<div class="col-md-6">
<input type="text" class="form-control" id="mail_from" name="mail_from"
value="{$_c['mail_from']}" placeholder="noreply@host.tld">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Mail Reply To</label>
<div class="col-md-6">
<input type="text" class="form-control" id="mail_reply_to" name="mail_reply_to"
value="{$_c['mail_reply_to']}" placeholder="support@host.tld">
</div>
<p class="help-block col-md-4">Customer will reply email to this address, empty if you want to
use From Address</p>
</div>
</div>
<div class="panel-heading">
<div class="btn-group pull-right">
<button class="btn btn-primary btn-xs" title="save" type="submit"><span
@ -491,6 +590,71 @@
<p class="help-block col-md-4">{Lang::T('The method which OTP will be sent to user')}</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>
{Lang::T('Tax System')}
</div>
<div class="panel-body">
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Enable Tax System')}</label>
<div class="col-md-6">
<select name="enable_tax" id="enable_tax" class="form-control">
<option value="no" {if $_c['enable_tax']=='no' }selected="selected" {/if}>
{Lang::T('No')}
</option>
<option value="yes" {if $_c['enable_tax']=='yes' }selected="selected" {/if}>
{Lang::T('Yes')}
</option>
</select>
</div>
<p class="help-block col-md-4">{Lang::T('Tax will be calculated in Internet Plan Price')}</p>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Tax Rate')}</label>
<div class="col-md-6">
<select name="tax_rate" id="tax_rate" class="form-control">
<option value="0.005" {if $_c['tax_rate']=='0.005' }selected="selected" {/if}>
{Lang::T('0.5%')}
</option>
<option value="0.01" {if $_c['tax_rate']=='0.01' }selected="selected" {/if}>
{Lang::T('1%')}
</option>
<option value="0.015" {if $_c['tax_rate']=='0.015' }selected="selected" {/if}>
{Lang::T('1.5%')}
</option>
<option value="0.02" {if $_c['tax_rate']=='0.02' }selected="selected" {/if}>
{Lang::T('2%')}
</option>
<option value="0.05" {if $_c['tax_rate']=='0.05' }selected="selected" {/if}>
{Lang::T('5%')}
</option>
<option value="0.1" {if $_c['tax_rate']=='0.1' }selected="selected" {/if}>
{Lang::T('10%')}
</option>
<!-- Custom tax rate option -->
<option value="custom" {if $_c['tax_rate']=='custom' }selected="selected" {/if}>
{Lang::T('Custom')}</option>
</select>
</div>
<p class="help-block col-md-4">{Lang::T('Tax Rates in percentage')}</p>
</div>
<!-- Custom tax rate input field (initially hidden) -->
<div class="form-group" id="customTaxRate" style="display: none;">
<label class="col-md-2 control-label">{Lang::T('Custom Tax Rate')}</label>
<div class="col-md-6">
<input type="text" value="{$_c['custom_tax_rate']}" class="form-control"
name="custom_tax_rate" id="custom_tax_rate"
placeholder="{Lang::T('Enter Custom Tax Rate')}">
</div>
<p class="help-block col-md-4">{Lang::T('Enter the custom tax rate (e.g., 3.75 for 3.75%)')}</p>
</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
@ -561,8 +725,38 @@ add dst-host=*.{$_domain}</pre>
}
}
function testEmail() {
var target = prompt("Email\nSave First before Test", "");
if (target != null) {
window.location.href = '{$_url}settings/app&testEmail=' + target;
}
}
function testTg() {
window.location.href = '{$_url}settings/app&testTg=test';
}
</script>
<script>
document.addEventListener("DOMContentLoaded", function() {
// Function to toggle visibility of custom tax rate input field
function toggleCustomTaxRate() {
var taxRateSelect = document.getElementById("tax_rate");
var customTaxRateInput = document.getElementById("customTaxRate");
if (taxRateSelect.value === "custom") {
customTaxRateInput.style.display = "block";
} else {
customTaxRateInput.style.display = "none";
}
}
// Call the function when the page loads
toggleCustomTaxRate();
// Call the function whenever the tax rate dropdown value changes
document.getElementById("tax_rate").addEventListener("change", toggleCustomTaxRate);
});
</script>
{include file="sections/footer.tpl"}

View File

@ -32,6 +32,16 @@
<input type="number" class="form-control" name="price" required>
</div>
</div>
{if $_c['enable_tax'] == 'yes'}
{if $_c['tax_rate'] == 'custom'}
<p class="help-block col-md-4">{number_format($_c['custom_tax_rate'], 2)} % {Lang::T('Tax Rates
will be added')}</p>
{else}
<p class="help-block col-md-4">{number_format($_c['tax_rate'] * 100, 2)} % {Lang::T('Tax Rates
will be added')}</p>
{/if}
{/if}
</div>
<div class="form-group">

View File

@ -32,6 +32,16 @@
<input type="number" class="form-control" name="price" value="{$d['price']}" required>
</div>
</div>
{if $_c['enable_tax'] == 'yes'}
{if $_c['tax_rate'] == 'custom'}
<p class="help-block col-md-4">{number_format($_c['custom_tax_rate'], 2)} % {Lang::T('Tax Rates
will be added')}</p>
{else}
<p class="help-block col-md-4">{number_format($_c['tax_rate'] * 100, 2)} % {Lang::T('Tax Rates
will be added')}</p>
{/if}
{/if}
</div>
<div class="form-group">

View File

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

View File

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

View File

@ -11,13 +11,14 @@
<div class="col-md-9">
<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>
{else}
<span class="input-group-addon" id="basic-addon1"><i
class="glyphicon glyphicon-user"></i></span>
{/if}
<input type="text" class="form-control" name="username" required
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']}{/if} {Lang::T('Phone Number')}">
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']} {Lang::T('Phone Number')}{else}{Lang::T('Username')}{/if}">
</div>
</div>
</div>
@ -51,8 +52,9 @@
<div class="form-group">
<label class="col-md-3 control-label">{Lang::T('Password')}</label>
<div class="col-md-9">
<input type="password" class="form-control" autocomplete="off" required id="password" value="{rand(000000,999999)}"
name="password" onmouseleave="this.type = 'password'" onmouseenter="this.type = 'text'">
<input type="password" class="form-control" autocomplete="off" required id="password"
value="{rand(000000,999999)}" name="password" onmouseleave="this.type = 'password'"
onmouseenter="this.type = 'text'">
</div>
</div>
<div class="form-group">
@ -76,13 +78,31 @@
<label class="col-md-3 control-label">{Lang::T('Service Type')}</label>
<div class="col-md-9">
<select class="form-control" id="service_type" name="service_type">
<option value="Hotspot" {if $d['service_type'] eq 'Hotspot' }selected{/if}>Hotspot
<option value="Hotspot">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>
<option value="PPPoE">PPPoE</option>
<option value="Others">Others</option>
</select>
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">{Lang::T('Account Type')}</label>
<div class="col-md-9">
<select class="form-control" id="account_type" name="account_type">
<option value="Personal">Personal
</option>
<option value="Business">Business</option>
</select>
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">{Lang::T('Coordinates')}</label>
<div class="col-md-9">
<input name="coordinates" id="coordinates" class="form-control" value=""
placeholder="6.465422, 3.406448">
<div id="map" style="width: '100%'; height: 200px; min-height: 150px;"></div>
</div>
</div>
</div>
</div>
</div>
@ -141,6 +161,42 @@
});
});
</script>
<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>
<script>
function getLocation() {
if (window.location.protocol == "https:" && navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition);
} else {
setupMap(51.505, -0.09);
}
}
function showPosition(position) {
setupMap(position.coords.latitude, position.coords.longitude);
}
function setupMap(lat, lon) {
var map = L.map('map').setView([lat, lon], 13);
L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/light_all/{z}/{x}/{y}.png', {
attribution:
'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',
subdomains: 'abcd',
maxZoom: 20
}).addTo(map);
var marker = L.marker([lat, lon]).addTo(map);
map.on('click', function(e){
var coord = e.latlng;
var lat = coord.lat;
var lng = coord.lng;
var newLatLng = new L.LatLng(lat, lng);
marker.setLatLng(newLatLng);
$('#coordinates').val(lat + ',' + lng);
});
}
window.onload = function() {
getLocation();
}
</script>
{/literal}

View File

@ -12,14 +12,15 @@
<div class="col-md-9">
<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>
{else}
<span class="input-group-addon" id="basic-addon1"><i
class="glyphicon glyphicon-user"></i></span>
{/if}
<input type="text" class="form-control" name="username" value="{$d['username']}"
required
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']}{/if} {Lang::T('Phone Number')}">
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']} {Lang::T('Phone Number')}{else}{Lang::T('Username')}{/if}">
</div>
</div>
</div>
@ -88,6 +89,25 @@
</select>
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">{Lang::T('Account Type')}</label>
<div class="col-md-9">
<select class="form-control" id="account_type" name="account_type">
<option value="Personal" {if $d['account_type'] eq 'Personal' }selected{/if}>Personal
</option>
<option value="Business" {if $d['account_type'] eq 'Business' }selected{/if}>Business
</option>
</select>
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">{Lang::T('Coordinates')}</label>
<div class="col-md-9">
<input name="coordinates" id="coordinates" class="form-control" value="{$d['coordinates']}"
placeholder="6.465422, 3.406448">
<div id="map" style="width: '100%'; height: 200px; min-height: 150px;"></div>
</div>
</div>
</div>
</div>
</div>
@ -106,7 +126,8 @@
id="{$customField.field_name}" value="{$customField.field_value}">
</div>
<label class="col-md-2">
<input type="checkbox" name="delete_custom_fields[]" value="{$customField.field_name}"> Delete
<input type="checkbox" name="delete_custom_fields[]" value="{$customField.field_name}">
Delete
</label>
</div>
{/foreach}
@ -164,6 +185,47 @@
});
});
</script>
<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>
<script>
function getLocation() {
if (window.location.protocol == "https:" && navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition);
} else {
setupMap(51.505, -0.09);
}
}
function showPosition(position) {
setupMap(position.coords.latitude, position.coords.longitude);
}
function setupMap(lat, lon) {
var map = L.map('map').setView([lat, lon], 13);
L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/light_all/{z}/{x}/{y}.png', {
attribution:
'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',
subdomains: 'abcd',
maxZoom: 20
}).addTo(map);
var marker = L.marker([lat, lon]).addTo(map);
map.on('click', function(e) {
var coord = e.latlng;
var lat = coord.lat;
var lng = coord.lng;
var newLatLng = new L.LatLng(lat, lng);
marker.setLatLng(newLatLng);
$('#coordinates').val(lat + ',' + lng);
});
}
window.onload = function() {
{/literal}{if $d['coordinates']}
setupMap({$d['coordinates']});
{else}
getLocation();
{/if}{literal}
}
</script>
{/literal}
{include file="sections/footer.tpl"}

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

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

View File

@ -55,6 +55,9 @@
<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('Account Type')}</b> <span class="pull-right">{Lang::T($d['account_type'])}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Balance')}</b> <span class="pull-right">{Lang::moneyFormat($d['balance'])}</span>
</li>
@ -71,6 +74,16 @@
<b>{Lang::T('Last Login')}</b> <span
class="pull-right">{Lang::dateTimeFormat($d['last_login'])}</span>
</li>
{if $d['coordinates']}
<li class="list-group-item">
<b>{Lang::T('Coordinates')}</b> <span class="pull-right">
<i class="glyphicon glyphicon-road"></i> <a style="color: black;"
href="https://www.google.com/maps/dir//{$d['coordinates']}/" target="_blank">Get
Directions</a>
</span>
<div id="map" style="width: '100%'; height: 100px;"></div>
</li>
{/if}
</ul>
<div class="row">
<div class="col-xs-4">
@ -129,11 +142,15 @@
<div class="col-xs-4">
<a href="{$_url}customers/list" class="btn btn-primary btn-sm btn-block">{Lang::T('Back')}</a>
</div>
<div class="col-xs-8">
<div class="col-xs-4">
<a href="{$_url}customers/sync/{$d['id']}"
onclick="return confirm('This will sync Customer to Mikrotik?')"
class="btn btn-info btn-sm btn-block">{Lang::T('Sync')}</a>
</div>
<div class="col-xs-4">
<a href="{$_url}message/send/{$d['id']}" class="btn btn-success btn-sm btn-block">{Lang::T('Send
Message')}</a>
</div>
</div>
</div>
<div class="col-sm-8 col-md-8">
@ -211,8 +228,28 @@
{/if}
</table>
</div>
{$paginator['contents']}
{include file="pagination.tpl"}
</div>
</div>
{if $d['coordinates']}
{literal}
<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>
<script>
function setupMap(lat, lon) {
var map = L.map('map').setView([lat, lon], 17);
L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/light_all/{z}/{x}/{y}.png', {
attribution:
'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',
subdomains: 'abcd',
maxZoom: 20
}).addTo(map);
var marker = L.marker([lat, lon]).addTo(map);
}
window.onload = function() {
{/literal}setupMap({$d['coordinates']});{literal}
}
</script>
{/literal}
{/if}
{include file="sections/footer.tpl"}

View File

@ -1,4 +1,15 @@
{include file="sections/header.tpl"}
<style>
.dataTables_wrapper .dataTables_paginate .paginate_button {
display: inline-block;
padding: 5px 10px;
margin-right: 5px;
border: 1px solid #ccc;
background-color: #fff;
color: #333;
cursor: pointer;
}
</style>
<div class="row">
<div class="col-sm-12">
@ -16,31 +27,22 @@
<div class="panel-body">
<div class="md-whiteframe-z1 mb20 text-center" style="padding: 15px">
<div class="col-md-8">
<form id="site-search" method="post" action="{$_url}customers/list/">
<div class="input-group">
<input type="text" id="search-input" name="search" value="{$search}" class="form-control"
placeholder="{Lang::T('Search')}...">
<div class="input-group-btn">
<button class="btn btn-success" type="submit"><span
class="fa fa-search"></span></button>
</div>
</div>
</form>
</div>
<div class="col-md-4">
<a href="{$_url}customers/add" class="btn btn-primary btn-block"><i
class="ion ion-android-add"> </i> {Lang::T('Add New Contact')}</a>
<a href="{$_url}customers/add" class="btn btn-primary btn-block"><i class="ion ion-android-add">
</i> {Lang::T('Add New Contact')}</a>
</div>&nbsp;
</div>
<div class="table-responsive table_mobile">
<table class="table table-bordered table-striped table-condensed">
<table id="customerTable" class="table table-bordered table-striped table-condensed">
<thead>
<tr>
<th>{Lang::T('Username')}</th>
<th>{Lang::T('Account Type')}</th>
<th>{Lang::T('Full Name')}</th>
<th>{Lang::T('Balance')}</th>
<th>{Lang::T('Phone Number')}</th>
<th>{Lang::T('Email')}</th>
<th>{Lang::T('Contact')}</th>
<th>{Lang::T('Package')}</th>
<th>{Lang::T('Service Type')}</th>
<th>{Lang::T('Created On')}</th>
@ -52,19 +54,37 @@
<tr>
<td onclick="window.location.href = '{$_url}customers/view/{$ds['id']}'"
style="cursor:pointer;">{$ds['username']}</td>
<td>{$ds['account_type']}</td>
<td onclick="window.location.href = '{$_url}customers/view/{$ds['id']}'"
style="cursor: pointer;">{$ds['fullname']}</td>
<td>{Lang::moneyFormat($ds['balance'])}</td>
<td>{$ds['phonenumber']}</td>
<td>{$ds['email']}</td>
<td align="center">
{if $ds['phonenumber']}
<a href="tel:{$ds['phonenumber']}" class="btn btn-default btn-xs"
title="{$ds['phonenumber']}"><i class="glyphicon glyphicon-earphone"></i></a>
{/if}
{if $ds['email']}
<a href="mailto:{$ds['email']}" class="btn btn-default btn-xs"
title="{$ds['email']}"><i class="glyphicon glyphicon-envelope"></i></a>
{/if}
{if $ds['coordinates']}
<a href="https://www.google.com/maps/dir//{$ds['coordinates']}/" target="_blank"
class="btn btn-default btn-xs" title="{$ds['coordinates']}"><i
class="glyphicon glyphicon-map-marker"></i></a>
{/if}
</td>
<td align="center" api-get-text="{$_url}autoload/customer_is_active/{$ds['id']}">
<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;"
<a href="{$_url}customers/view/{$ds['id']}" id="{$ds['id']}"
style="margin: 0px; color:black"
class="btn btn-success btn-xs">&nbsp;&nbsp;{Lang::T('View')}&nbsp;&nbsp;</a>
<a href="{$_url}customers/edit/{$ds['id']}" id="{$ds['id']}"
style="margin: 0px; color:black"
class="btn btn-info btn-xs">&nbsp;&nbsp;{Lang::T('Edit')}&nbsp;&nbsp;</a>
<a href="{$_url}plan/recharge/{$ds['id']}" id="{$ds['id']}" style="margin: 0px;"
class="btn btn-primary btn-xs">{Lang::T('Recharge')}</a>
</td>
@ -73,30 +93,22 @@
</tbody>
</table>
</div>
{$paginator['contents']}
</div>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.datatables.net/1.11.3/js/jquery.dataTables.min.js"></script>
<script>
// Functionality to filter table rows based on admin input
document.addEventListener('DOMContentLoaded', function () {
var searchInput = document.getElementById('search-input');
var tableRows = document.querySelectorAll('tbody tr');
var $j = jQuery.noConflict();
searchInput.addEventListener('input', function () {
var searchText = this.value.toLowerCase();
tableRows.forEach(function (row) {
var rowData = row.textContent.toLowerCase();
if (rowData.includes(searchText)) {
row.style.display = '';
} else {
row.style.display = 'none';
}
});
$j(document).ready(function () {
$j('#customerTable').DataTable({
"pagingType": "full_numbers",
"lengthMenu": [ [5, 10, 25, 50, 100, -1], [5, 10, 25, 50, 100, "All"] ],
"pageLength": 5
});
});
</script>

View File

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

View File

@ -20,6 +20,14 @@
<input type="radio" name="prepaid" onclick="postPaid()" value="no"> Postpaid
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Plan Type')}</label>
<div class="col-md-10">
<input type="radio" name="plan_type" value="Personal" checked> Personal
<input type="radio" name="plan_type" value="Business"> Business
</div>
</div>
{if $_c['radius_enable']}
<div class="form-group">
<label class="col-md-2 control-label">Radius</label>
@ -106,6 +114,16 @@
<input type="number" class="form-control" name="price" required>
</div>
</div>
{if $_c['enable_tax'] == 'yes'}
{if $_c['tax_rate'] == 'custom'}
<p class="help-block col-md-4">{number_format($_c['custom_tax_rate'], 2)} % {Lang::T('Tax Rates
will be added')}</p>
{else}
<p class="help-block col-md-4">{number_format($_c['tax_rate'] * 100, 2)} % {Lang::T('Tax Rates
will be added')}</p>
{/if}
{/if}
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Shared Users')}</label>

View File

@ -14,6 +14,8 @@
<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('Type')}</label>
<div class="col-md-10">
@ -24,6 +26,19 @@
{if $d['prepaid'] == no}checked{/if}> Postpaid
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Plan Type')}</label>
<div class="col-md-10">
<input type="radio" name="plan_type" value="Personal"
{if $d['plan_type'] == 'Personal'}checked{/if}>
Personal
<input type="radio" name="plan_type" value="Business"
{if $d['plan_type'] == 'Business'}checked{/if}> Business
</div>
</div>
{if $_c['radius_enable'] and $d['is_radius']}
<div class="form-group">
<label class="col-md-2 control-label">Radius</label>
@ -118,6 +133,16 @@
<input type="number" class="form-control" name="price" value="{$d['price']}" required>
</div>
</div>
{if $_c['enable_tax'] == 'yes'}
{if $_c['tax_rate'] == 'custom'}
<p class="help-block col-md-4">{number_format($_c['custom_tax_rate'], 2)} % {Lang::T('Tax Rates
will be added')}</p>
{else}
<p class="help-block col-md-4">{number_format($_c['tax_rate'] * 100, 2)} % {Lang::T('Tax Rates
will be added')}</p>
{/if}
{/if}
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Shared Users')}</label>

View File

@ -27,8 +27,8 @@
</form>
</div>
<div class="col-md-4">
<a href="{$_url}services/add" class="btn btn-primary btn-block"><i
class="ion ion-android-add"> </i> {Lang::T('New Service Plan')}</a>
<a href="{$_url}services/add" class="btn btn-primary btn-block"><i class="ion ion-android-add">
</i> {Lang::T('New Service Plan')}</a>
</div>&nbsp;
</div>
<div class="table-responsive">
@ -38,23 +38,25 @@
<th>{Lang::T('Plan Name')}</th>
<th>{Lang::T('Plan Type')}</th>
<th>{Lang::T('Bandwidth Plans')}</th>
<th>{Lang::T('Plan Category')}</th>
<th>{Lang::T('Plan Price')}</th>
<th>{Lang::T('Time Limit')}</th>
<th>{Lang::T('Data Limit')}</th>
<th>{Lang::T('Plan Validity')}</th>
<th>{Lang::T('Routers')}</th>
<th>{Lang::T('Expired IP Pool')}</th>
<th>{Lang::T('ID')}</th>
<th>{Lang::T('Manage')}</th>
<th>ID</th>
</tr>
</thead>
<tbody>
{foreach $d as $ds}
<tr {if $ds['enabled'] != 1}class="danger" title="disabled"
{elseif $ds['prepaid'] != 'yes'}class="warning" title="Postpaid" {/if}>
<tr {if $ds['enabled'] !=1}class="danger" title="disabled" {elseif $ds['prepaid'] !='yes'
}class="warning" title="Postpaid" {/if}>
<td class="headcol">{$ds['name_plan']}</td>
<td>{$ds['typebp']}</td>
<td>{$ds['plan_type']}</td>
<td>{$ds['name_bw']}</td>
<td>{$ds['typebp']}</td>
<td>{Lang::moneyFormat($ds['price'])}</td>
<td>{$ds['time_limit']} {$ds['time_unit']}</td>
<td>{$ds['data_limit']} {$ds['data_unit']}</td>
@ -68,7 +70,9 @@
{/if}
{/if}
</td>
<td>{$ds['pool_expired']}{if $ds['list_expired']}{if $ds['pool_expired']} | {/if}{$ds['list_expired']}{/if}</td>
<td>{$ds['pool_expired']}{if $ds['list_expired']}{if $ds['pool_expired']} |
{/if}{$ds['list_expired']}{/if}</td>
<td>{$ds['id']}</td>
<td>
<a href="{$_url}services/edit/{$ds['id']}"
class="btn btn-info btn-xs">{Lang::T('Edit')}</a>
@ -76,14 +80,12 @@
onclick="return confirm('{Lang::T('Delete')}?')"
class="btn btn-danger btn-xs"><i class="glyphicon glyphicon-trash"></i></a>
</td>
<td>{$ds['id']}</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
{$paginator['contents']}
{include file="pagination.tpl"}
</div>
</div>
</div>

View File

@ -4,6 +4,13 @@
<div class="col-sm-12">
<div class="panel panel-hovered mb20 panel-primary">
<div class="panel-heading">
{if in_array($_admin['user_type'],['SuperAdmin','Admin'])}
<div class="btn-group pull-right">
<a class="btn btn-primary btn-xs" title="save" href="{$_url}logs/radius-csv"
onclick="return confirm('This will export to CSV?')"><span class="glyphicon glyphicon-download"
aria-hidden="true"></span> CSV</a>
</div>
{/if}
Radius
</div>
<div class="panel-body">
@ -53,7 +60,7 @@
</tbody>
</table>
</div>
{$paginator['contents']}
{include file="pagination.tpl"}
</div>
</div>
</div>

View File

@ -4,6 +4,13 @@
<div class="col-sm-12">
<div class="panel panel-hovered mb20 panel-primary">
<div class="panel-heading">
{if in_array($_admin['user_type'],['SuperAdmin','Admin'])}
<div class="btn-group pull-right">
<a class="btn btn-primary btn-xs" title="save" href="{$_url}logs/list-csv"
onclick="return confirm('This will export to CSV?')"><span class="glyphicon glyphicon-download"
aria-hidden="true"></span> CSV</a>
</div>
{/if}
Activity Log
</div>
<div class="panel-body">
@ -50,7 +57,7 @@
</tbody>
</table>
</div>
{$paginator['contents']}
{include file="pagination.tpl"}
</div>
</div>
</div>

View File

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

View File

@ -9,15 +9,13 @@
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Customer')}</label>
<div class="col-md-6">
<select id="personSelect" class="form-control select2" name="id_customer" style="width: 100%" data-placeholder="Select a customer...">
<option></option>
{foreach $c as $cs}
{if $id eq $cs['id']}
<option value="{$cs['id']}" selected>{$cs['username']}</option>
{else}
<option value="{$cs['id']}">{$cs['username']}</option>
<select {if $cust}{else}id="personSelect" {/if} class="form-control select2"
name="id_customer" style="width: 100%"
data-placeholder="{Lang::T('Select a customer')}...">
{if $cust}
<option value="{$cust['id']}">{$cust['username']} &bull; {$cust['fullname']} &bull;
{$cust['email']}</option>
{/if}
{/foreach}
</select>
</div>
</div>
@ -34,18 +32,19 @@
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Message')}</label>
<div class="col-md-6">
<textarea class="form-control" id="message" name="message" placeholder="{Lang::T('Compose your message...')}" rows="5"></textarea>
<textarea class="form-control" id="message" name="message"
placeholder="{Lang::T('Compose your message...')}" rows="5"></textarea>
</div>
<p class="help-block col-md-4">
{Lang::T('Use placeholders:')}
<br>
<b>{Lang::T('[[name]]')}</b> - {Lang::T('Customer Name')}
<b>[[name]]</b> - {Lang::T('Customer Name')}
<br>
<b>{Lang::T('[[user_name]]')}</b> - {Lang::T('Customer Username')}
<b>[[user_name]]</b> - {Lang::T('Customer Username')}
<br>
<b>{Lang::T('[[phone]]')}</b> - {Lang::T('Customer Phone')}
<b>[[phone]]</b> - {Lang::T('Customer Phone')}
<br>
<b>{Lang::T('[[company_name]]')}</b> - {Lang::T('Your Company Name')}
<b>[[company_name]]</b> - {Lang::T('Your Company Name')}
</p>
</div>

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

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

View File

@ -45,6 +45,7 @@
<tr>
<th>{Lang::T('Username')}</th>
<th>{Lang::T('Plan Name')}</th>
<th>{Lang::T('Plan Type')}</th>
<th>{Lang::T('Type')}</th>
<th>{Lang::T('Created On')}</th>
<th>{Lang::T('Expires On')}</th>
@ -59,29 +60,44 @@
<td><a href="{$_url}customers/viewu/{$ds['username']}">{$ds['username']}</a></td>
<td>{$ds['namebp']}</td>
<td>{$ds['type']}</td>
<td>{$ds['plan_type']}</td>
<td>{Lang::dateAndTimeFormat($ds['recharged_on'],$ds['recharged_time'])}</td>
<td>{Lang::dateAndTimeFormat($ds['expiration'],$ds['time'])}</td>
<td>{$ds['method']}</td>
<td>{$ds['routers']}</td>
<td>
<a href="{$_url}plan/edit/{$ds['id']}"
class="btn btn-warning btn-xs">{Lang::T('Edit')}</a>
class="btn btn-warning btn-xs" style="color: black;">{Lang::T('Edit')}</a>
{if in_array($_admin['user_type'],['SuperAdmin','Admin'])}
<a href="{$_url}plan/delete/{$ds['id']}" id="{$ds['id']}"
onclick="return confirm('{Lang::T('Delete')}?')"
class="btn btn-danger btn-xs"><i class="glyphicon glyphicon-trash"></i></a>
{/if}
{if $ds['status']=='off' && $_c['extend_expired']}
<a href="javascript:extend('{$ds['id']}')"
class="btn btn-info btn-xs">{Lang::T('extend')}</a>
{/if}
</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
{$paginator['contents']}
{include file="pagination.tpl"}
</div>
</div>
</div>
</div>
<script>
function extend(idP){
var res = prompt("Extend for many days?", "3");
if(res){
if(confirm("Extend for "+res+" days?")){
window.location.href = "{$_url}plan/extend/"+idP+"/"+res+"&stoken={App::getToken()}";
}
}
}
</script>
{include file="sections/footer.tpl"}

View File

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

View File

@ -20,6 +20,15 @@
<input type="radio" name="prepaid" onclick="postPaid()" value="no"> Postpaid
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Plan Type')}</label>
<div class="col-md-10">
<input type="radio" name="plan_type" value="Personal" checked> Personal
<input type="radio" name="plan_type" value="Business"> Business
</div>
</div>
{if $_c['radius_enable']}
<div class="form-group">
<label class="col-md-2 control-label">Radius</label>
@ -55,6 +64,15 @@
<input type="number" class="form-control" name="price" required>
</div>
</div>
{if $_c['enable_tax'] == 'yes'}
{if $_c['tax_rate'] == 'custom'}
<p class="help-block col-md-4">{number_format($_c['custom_tax_rate'], 2)} % {Lang::T('Tax Rates
will be added')}</p>
{else}
<p class="help-block col-md-4">{number_format($_c['tax_rate'] * 100, 2)} % {Lang::T('Tax Rates
will be added')}</p>
{/if}
{/if}
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Plan Validity')}</label>

View File

@ -22,6 +22,17 @@
<input type="radio" name="prepaid" onclick="postPaid()" value="no" {if $d['prepaid'] == no}checked{/if}> Postpaid
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Plan Type')}</label>
<div class="col-md-10">
<input type="radio" name="plan_type" value="Personal"
{if $d['plan_type'] == 'Personal'}checked{/if}>
Personal
<input type="radio" name="plan_type" value="Business"
{if $d['plan_type'] == 'Business'}checked{/if}> Business
</div>
</div>
{if $_c['radius_enable'] and $d['is_radius']}
<div class="form-group">
<label class="col-md-2 control-label">Radius</label>
@ -57,6 +68,16 @@
<input type="number" class="form-control" name="price" required value="{$d['price']}">
</div>
</div>
{if $_c['enable_tax'] == 'yes'}
{if $_c['tax_rate'] == 'custom'}
<p class="help-block col-md-4">{number_format($_c['custom_tax_rate'], 2)} % {Lang::T('Tax Rates
will be added')}</p>
{else}
<p class="help-block col-md-4">{number_format($_c['tax_rate'] * 100, 2)} % {Lang::T('Tax Rates
will be added')}</p>
{/if}
{/if}
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Plan Validity')}</label>

View File

@ -36,6 +36,7 @@
<thead>
<tr>
<th>{Lang::T('Plan Name')}</th>
<th>{Lang::T('Plan Type')}</th>
<th>{Lang::T('Bandwidth Plans')}</th>
<th>{Lang::T('Plan Price')}</th>
<th>{Lang::T('Plan Validity')}</th>
@ -48,14 +49,17 @@
</thead>
<tbody>
{foreach $d as $ds}
<tr {if $ds['enabled'] != 1}class="danger" title="disabled"
{elseif $ds['prepaid'] != 'yes'}class="warning" title="Postpaid" {/if}>
<tr {if $ds['enabled'] != 1}class="danger" title="disabled"{/if}>
<td>{$ds['name_plan']}</td>
<td>{$ds['plan_type']} {if $ds['prepaid'] != 'yes'}<b>Postpaid</b>{else}Prepaid{/if}</td>
<td>{$ds['name_bw']}</td>
<td>{Lang::moneyFormat($ds['price'])}</td>
<td>{$ds['validity']} {$ds['validity_unit']}</td>
<td>{$ds['pool']}</td>
<td>{$ds['pool_expired']}{if $ds['list_expired']}{if $ds['pool_expired']} | {/if}{$ds['list_expired']}{/if}</td>
<td>{$ds['pool_expired']}{if $ds['list_expired']}
{if $ds['pool_expired']} |
{/if}{$ds['list_expired']}
{/if}</td>
<td>
{if $ds['is_radius']}
<span class="label label-primary">RADIUS</span>
@ -63,7 +67,8 @@
{if $ds['routers']!=''}
<a href="{$_url}routers/edit/0&name={$ds['routers']}">{$ds['routers']}</a>
{/if}
{/if}</td>
{/if}
</td>
<td>
<a href="{$_url}services/pppoe-edit/{$ds['id']}"
class="btn btn-info btn-xs">{Lang::T('Edit')}</a>
@ -77,7 +82,7 @@
</tbody>
</table>
</div>
{$paginator['contents']}
{include file="pagination.tpl"}
</div>
</div>
</div>

View File

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

View File

@ -81,6 +81,7 @@
<input type="hidden" name="plan" value="{$plan['id']}">
<input type="hidden" name="server" value="{$server}">
<input type="hidden" name="using" value="{$using}">
<input type="hidden" name="stoken" value="{App::getToken()}">
<center>
<button class="btn btn-success" type="submit">{Lang::T('Recharge')}</button><br>
<a class="btn btn-link" href="{$_url}plan/recharge">{Lang::T('Cancel')}</a>

View File

@ -59,16 +59,17 @@
<div class="panel-body">
<div class="form-container">
<div class="form-group">
<label>{Lang::T('Phone Number')}</label>
<label>{if $_c['country_code_phone']!= ''}{Lang::T('Phone Number')}{else}{Lang::T('Username')}{/if}</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>
{else}
<span class="input-group-addon" id="basic-addon1"><i
class="glyphicon glyphicon-user"></i></span>
{/if}
<input type="text" class="form-control" name="username" value="{$username}"
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']}{/if} {Lang::T('Phone Number')}">
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']} {Lang::T('Phone Number')}{else}{Lang::T('Username')}{/if}">
</div>
</div>
<div class="form-group">
@ -83,7 +84,7 @@
</div>
<div class="form-group">
<label>{Lang::T('Email')}</label>
<input type="text" required class="form-control" placeholder="xxxxxx@xxx.xx"
<input type="text" class="form-control" placeholder="xxxxxx@xxx.xx"
id="email" value="{$email}" name="email">
</div>
<div class="form-group">
@ -111,8 +112,7 @@
</div>
<div class="btn-group btn-group-justified mb15">
<div class="btn-group">
<button class="btn btn-primary"
type="submit">{Lang::T('Register')}</button>
<button class="btn btn-primary" type="submit">{Lang::T('Register')}</button>
</div>
<div class="btn-group">
<a href="{$_url}register" class="btn btn-success">{Lang::T('Cancel')}</a>

View File

@ -59,16 +59,17 @@
<div class="panel-heading">1. {Lang::T('Register as Member')}</div>
<div class="panel-body">
<div class="form-group">
<label>{Lang::T('Phone Number')}</label>
<label>{if $_c['country_code_phone']!= ''}{Lang::T('Phone Number')}{else}{Lang::T('Username')}{/if}</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>
{else}
<span class="input-group-addon" id="basic-addon1"><i
class="glyphicon glyphicon-user"></i></span>
{/if}
<input type="text" class="form-control" name="username"
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']}{/if} {Lang::T('Phone Number')}">
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']} {Lang::T('Phone Number')}{else}{Lang::T('Username')}{/if}">
</div>
</div>
<div class="btn-group btn-group-justified mb15">
@ -76,8 +77,7 @@
<a href="{$_url}login" class="btn btn-warning">{Lang::T('Cancel')}</a>
</div>
<div class="btn-group">
<button class="btn btn-success"
type="submit">{Lang::T('Request OTP')}</button>
<button class="btn btn-success" type="submit">{Lang::T('Request OTP')}</button>
</div>
</div>
<br>

View File

@ -59,11 +59,17 @@
<div class="panel-body">
<div class="form-container">
<div class="md-input-container">
<label>{Lang::T('Phone Number')}</label>
<label>{if $_c['country_code_phone']!= ''}{Lang::T('Phone Number')}{else}{Lang::T('Username')}{/if}</label>
<div class="input-group">
<span class="input-group-addon" id="basic-addon1">+</span>
{if $_c['country_code_phone']!= ''}
<span class="input-group-addon" id="basic-addon1"><i
class="glyphicon glyphicon-phone-alt"></i></span>
{else}
<span class="input-group-addon" id="basic-addon1"><i
class="glyphicon glyphicon-user"></i></span>
{/if}
<input type="text" class="form-control" name="username"
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']}{/if} {Lang::T('Phone Number')}">
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']} {Lang::T('Phone Number')}{else}{Lang::T('Username')}{/if}">
</div>
</div>
<div class="md-input-container md-float-label">
@ -73,8 +79,8 @@
</div>
<div class="md-input-container md-float-label">
<label>{Lang::T('Email')}</label>
<input type="text" required class="form-control" id="email"
placeholder="xxxxxxx@xxxx.xx" value="{$email}" name="email">
<input type="text" class="form-control" id="email" placeholder="xxxxxxx@xxxx.xx"
value="{$email}" name="email">
</div>
<div class="md-input-container md-float-label">
<label>{Lang::T('Address')}</label>
@ -105,8 +111,7 @@
<a href="{$_url}login" class="btn btn-warning">{Lang::T('Cancel')}</a>
</div>
<div class="btn-group">
<button class="btn btn-success"
type="submit">{Lang::T('Register')}</button>
<button class="btn btn-success" type="submit">{Lang::T('Register')}</button>
</div>
</div>
<br>

View File

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

View File

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

View File

@ -20,7 +20,7 @@
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Router Name')}</label>
<label class="col-md-2 control-label">{Lang::T('Router Name / Location')}</label>
<div class="col-md-6">
<input type="text" class="form-control" id="name" name="name" maxlength="32">
<p class="help-block">{Lang::T('Name of Area that router operated')}</p>

View File

@ -20,7 +20,7 @@
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Router Name')}</label>
<label class="col-md-2 control-label">{Lang::T('Router Name / Location')}</label>
<div class="col-md-6">
<input type="text" class="form-control" id="name" name="name" maxlength="32" value="{$d['name']}">
<p class="help-block">{Lang::T('Name of Area that router operated')}</p>

View File

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

View File

@ -158,11 +158,20 @@
</li>
{$_MENU_AFTER_DASHBOARD}
{if !in_array($_admin['user_type'],['Report'])}
<li {if $_system_menu eq 'customers' }class="active" {/if}>
<a href="{$_url}customers">
<i class="fa fa-users"></i>
<span>{Lang::T('Customer')}</span>
<li class="{if in_array($_system_menu, ['customers', 'map'])}active{/if} treeview">
<a href="#">
<i class="fa fa-users"></i> <span>{Lang::T('Customer')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_system_menu eq 'customers' }class="active" {/if}><a
href="{$_url}customers">{Lang::T('Lists')}</a></li>
<li {if $_system_menu eq 'map' }class="active" {/if}><a
href="{$_url}map/customer">{Lang::T('Location')}</a></li>
{$_MENU_CUSTOMERS}
</ul>
</li>
{$_MENU_AFTER_CUSTOMERS}
<li class="{if $_system_menu eq 'plan'}active{/if} treeview">
@ -195,21 +204,21 @@
{if in_array($_admin['user_type'],['SuperAdmin','Admin'])}
<li class="{if $_system_menu eq 'services'}active{/if} treeview">
<a href="#">
<i class="ion ion-cube"></i> <span>{Lang::T('Plans')}</span>
<i class="ion ion-cube"></i> <span>{Lang::T('Internet Plan')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[1] eq 'hotspot' }class="active" {/if}><a
href="{$_url}services/hotspot">{Lang::T('Hotspot')}</a></li>
href="{$_url}services/hotspot">Hotspot</a></li>
<li {if $_routes[1] eq 'pppoe' }class="active" {/if}><a
href="{$_url}services/pppoe">{Lang::T('PPPOE')}</a></li>
href="{$_url}services/pppoe">PPPOE</a></li>
<li {if $_routes[1] eq 'list' }class="active" {/if}><a
href="{$_url}bandwidth/list">{Lang::T('Bandwidth')}</a></li>
{if $_c['enable_balance'] == 'yes'}
<li {if $_routes[1] eq 'balance' }class="active" {/if}><a
href="{$_url}services/balance">{Lang::T('Balance')}</a></li>
href="{$_url}services/balance">{Lang::T('Customer Balance')}</a></li>
{/if}
{$_MENU_PLANS}
</ul>
@ -243,9 +252,9 @@
</a>
<ul class="treeview-menu">
<li {if $_routes[1] eq 'send' }class="active" {/if}><a
href="{$_url}message/send">{Lang::T('Send SMS/WA Message')}</a></li>
href="{$_url}message/send">{Lang::T('Single Customer')}</a></li>
<li {if $_routes[1] eq 'send_bulk' }class="active" {/if}><a
href="{$_url}message/send_bulk">{Lang::T('Send Bulk SMS/WA Message')}</a></li>
href="{$_url}message/send_bulk">{Lang::T('Bulk Customers')}</a></li>
{$_MENU_MESSAGE}
</ul>
</li>
@ -303,9 +312,9 @@
<li {if $_routes[1] eq 'Registration_Info' }class="active" {/if}><a
href="{$_url}pages/Registration_Info">{Lang::T('Registration Info')}</a></li>
<li {if $_routes[1] eq 'Privacy_Policy' }class="active" {/if}><a
href="{$_url}pages/Privacy_Policy">Privacy Policy</a></li>
href="{$_url}pages/Privacy_Policy">{Lang::T('Privacy Policy')}</a></li>
<li {if $_routes[1] eq 'Terms_and_Conditions' }class="active" {/if}><a
href="{$_url}pages/Terms_and_Conditions">Terms and Conditions</a></li>
href="{$_url}pages/Terms_and_Conditions">{Lang::T('Terms and Conditions')}</a></li>
{$_MENU_PAGES}
</ul>
</li>

View File

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

View File

@ -152,6 +152,7 @@
<td class="small text-success text-uppercase text-normal">{Lang::T('Type')}</td>
<td class="small mb15 text-success">
<b>{if $_bill['prepaid'] eq yes}Prepaid{else}Postpaid{/if}</b>
{Lang::T($_bill['plan_type'])}
</td>
</tr>
{if $nux_ip neq ''}
@ -177,12 +178,19 @@
<tr>
<td class="small text-primary text-uppercase text-normal">
{if $_bill['status'] == 'on'}
<a href="{$_url}home&deactivate={$_bill['id']}" onclick="return confirm('{Lang::T('Deactivate')}?')"
class="btn btn-danger btn-xs"><i class="glyphicon glyphicon-trash"></i></a>
<a href="{$_url}home&deactivate={$_bill['id']}"
onclick="return confirm('{Lang::T('Deactivate')}?')" class="btn btn-danger btn-xs"><i
class="glyphicon glyphicon-trash"></i></a>
{/if}
</td>
<td class="small row">
<a class="btn btn-primary pull-right btn-sm" href="{$_url}home&recharge={$_bill['id']}"
{if $_bill['status'] != 'on' && $_bill['prepaid'] != 'yes' && $_c['extend_expired']}
<a class="btn btn-warning text-black btn-sm"
href="{$_url}home&extend={$_bill['id']}&stoken={App::getToken()}"
onclick="return confirm('{str_replace("\n","\\n",str_replace("\r","",$_c['extend_confirmation']))}?')">{Lang::T('Extend')}</a>
{/if}
<a class="btn btn-primary pull-right btn-sm"
href="{$_url}home&recharge={$_bill['id']}&stoken={App::getToken()}"
onclick="return confirm('{Lang::T('Recharge')}?')">{Lang::T('Recharge')}</a>
</td>
</tr>

View File

@ -44,16 +44,17 @@
<div class="panel-body">
<form action="{$_url}login/activation" method="post">
<div class="form-group">
<label>{Lang::T('Phone Number')}</label>
<label>{if $_c['country_code_phone']!= ''}{Lang::T('Phone Number')}{else}{Lang::T('Username')}{/if}</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>
{else}
<span class="input-group-addon" id="basic-addon1"><i
class="glyphicon glyphicon-user"></i></span>
{/if}
<input type="text" class="form-control" name="username" required
placeholder="08xxxxxxx">
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']} {Lang::T('Phone Number')}{else}{Lang::T('Username')}{/if}">
</div>
</div>
<div class="form-group">

View File

@ -45,23 +45,26 @@
<div class="panel-body">
<form action="{$_url}login/post" method="post">
<div class="form-group">
<label>{Lang::T('Phone Number')}</label>
<label>{if $_c['country_code_phone']!= ''}{Lang::T('Phone Number')}{else}{Lang::T('Username')}{/if}</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>
{else}
<span class="input-group-addon" id="basic-addon1"><i
class="glyphicon glyphicon-user"></i></span>
{/if}
<input type="text" class="form-control" name="username"
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']}{/if} {Lang::T('Phone Number')}">
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']} {Lang::T('Phone Number')}{else}{Lang::T('Username')}{/if}">
</div>
</div>
<div class="form-group">
<label>{Lang::T('Password')}</label>
<input type="password" class="form-control" name="password"
placeholder="{Lang::T('Password')}">
<div class="input-group">
<span class="input-group-addon" id="basic-addon2"><i class="glyphicon glyphicon-lock"></i></span>
<input type="password" class="form-control" name="password" placeholder="{Lang::T('Password')}">
</div>
</div>
<div class="clearfix hidden">

View File

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

View File

@ -38,9 +38,17 @@
<td>{$trx['gateway']}</td>
</tr>
<tr>
<td>{Lang::T('Balance')}</td>
<td>{Lang::T('Total')}</td>
<td>{Lang::moneyFormat($trx['price'])}</td>
</tr>
{if $invoice['note']}
<tr>
<td>{Lang::T('Notes')}</td>
<td>
{nl2br($invoice['note'])}
</td>
</tr>
{/if}
</tbody>
</table>
{else}
@ -80,8 +88,11 @@
</tr>
{/if}
<tr>
<td>{Lang::T('Plan Price')}{if $add_cost>0}<small> + {Lang::T('Additional Cost')}{/if}</small></td>
<td style="font-size: large; font-weight:bolder; font-family: 'Courier New', Courier, monospace; ">{Lang::moneyFormat($trx['price'])}</td>
<td>{Lang::T('Plan Price')}{if $add_cost>0}<small> +
{Lang::T('Additional Cost')}{/if}</small></td>
<td
style="font-size: large; font-weight:bolder; font-family: 'Courier New', Courier, monospace; ">
{Lang::moneyFormat($trx['price'])}</td>
</tr>
<tr>
<td>{Lang::T('Type')}</td>

View File

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

View File

@ -21,23 +21,23 @@
<div class="input-group-addon">
<span class="fa fa-search"></span>
</div>
<input type="text" name="search" class="form-control"
placeholder="{Lang::T('Search by Code Voucher')}..." value="{$search}">
<input type="text" name="search" class="form-control" placeholder="{Lang::T('Search by Code Voucher')}..." value="{$search}">
<div class="input-group-btn">
<button class="btn btn-success" type="submit">{Lang::T('Search')}</button>
</div>
</div>
</form>
</div>
<div class="col-md-4">
<div class="btn-group btn-group-justified" role="group">
<div class="btn-group" role="group">
<a href="{$_url}plan/add-voucher" class="btn btn-primary btn-block"><i
class="ion ion-android-add"> </i> {Lang::T('Add Vouchers')}</a>
<a href="{$_url}plan/add-voucher" class="btn btn-primary btn-block"><i class="ion ion-android-add"></i> {Lang::T('Add Vouchers')}</a>
</div>
</div>
<div class="btn-group btn-group-justified" role="group">
<div class="btn-group" role="group">
<a href="{$_url}plan/print-voucher" target="print_voucher" class="btn btn-info"><i
class="ion ion-android-print"> </i> Print</a>
<a href="{$_url}plan/print-voucher" target="print_voucher" class="btn btn-info btn-block"><i class="ion ion-android-print"></i> Print</a>
</div>
</div>
</div>&nbsp;

View File

@ -1,3 +1,3 @@
{
"version": "2024.3.18"
"version": "2024.4.15"
}