diff --git a/.gitignore b/.gitignore index 5a2ce6e7..85d079af 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,8 @@ system/plugin/ui/* !system/plugin/ui/index.html ui/ui_custom/** !ui/ui_custom/index.html -!ui/ui_custom/README.md \ No newline at end of file +!ui/ui_custom/README.md +system/uploads/admin.png +system/uploads/logo.png +system/uploads/user.jpg +system/uploads/notifications.json \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index e65825bc..273041d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,34 @@ # CHANGELOG +## 2023.8.16 + +- Admin Can Add Balance to Customer +- Show Balance in user +- Using Select2 for Dropdown + +## 2023.8.15 + +- Fix PPPOE Delete Customer +- Fix Header Admin and Customer +- Fix PDF Export by Period +- Add pppoe_password for Customer, this pppoe_password only admin can change +- Country Code Number Settings +- Customer Meta Table for Custom Fields +- Fix Add and Edit Customer Form for admin +- add Notification Message Editor +- cron reminder +- Balance System, Customer can deposit money +- Auto renewal when package expired using Customer Balance + + ## 2023.8.1 - Add Update file script, one click updating PHPNuxBill - Add Custom UI folder, to custome your own template - Delete debug text - Fix Vendor JS + ## 2023.7.28 - Fix link buy Voucher @@ -22,13 +44,13 @@ Because the first time phpmixbill created, plan validity only for days and Months, many request ask for minutes and hours, i change it, but not the database. ## 2023.6.15 -- User can connect to internet from User Dashboard +- Customer can connect to internet from Customer Dashboard - Fix Confirm when delete - Change Logo PHPNuxBill - Using Composer -- Fix Search User -- Fix user check, if not found will logout -- User password show but hidden +- Fix Search Customer +- Fix Customer check, if not found will logout +- Customer password show but hidden - Voucher code hidden ## 2023.6.8 diff --git a/README.md b/README.md index d19af204..9c802f68 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ - Voucher Generator and Print - Self registration +- User Balance +- Auto Renewal Package using Balance - Multi Router Mikrotik - Hotspot & PPPOE - Easy Installation @@ -33,8 +35,10 @@ Minimum Requirements - Linux or Windows OS - PHP Version 7.4 - Both PDO & MySQLi Support -- GD2 Image Library -- CURL support +- PHP-GD2 Image Library +- PHP-CURL +- PHP-ZIP +- PHP-Mbstring - MySQL Version 4.1.x and above can be Installed in Raspberry Pi Device. @@ -48,6 +52,10 @@ The problem with windows is hard to set cronjob, better Linux [Installation instructions](https://github.com/hotspotbilling/phpnuxbill/wiki) +## Docker Version + +[Docker Repository](https://github.com/animegasan/phpnuxbill) + ## RADIUS system Still on development diff --git a/install/phpnuxbill.sql b/install/phpnuxbill.sql index 38169450..602f8364 100644 --- a/install/phpnuxbill.sql +++ b/install/phpnuxbill.sql @@ -50,10 +50,13 @@ CREATE TABLE `id` int(10) NOT NULL, `username` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `password` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, + `pppoe_password` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1', `fullname` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `address` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci, `phonenumber` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0', `email` varchar(128) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1', + `balance` decimal(15,2) NOT NULL COMMENT 'For Money Deposit', + `auto_renewal` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Auto renewal from balance', `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `last_login` datetime DEFAULT NULL ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci; @@ -295,6 +298,19 @@ CREATE TABLE `status` varchar(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci; + +-- +-- Struktur dari tabel `tbl_customers_meta` +-- + +CREATE TABLE `tbl_customers_meta` ( + `id` int(11) NOT NULL, + `customer_id` int(11) NOT NULL, + `meta_key` varchar(64) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', + `meta_value` longtext COLLATE utf8mb4_general_ci +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + + -- -- Indexes for dumped tables @@ -543,6 +559,17 @@ ALTER TABLE ALTER TABLE `tbl_voucher` MODIFY `id` int(10) NOT NULL AUTO_INCREMENT; +-- +-- Indeks untuk tabel `tbl_customers_meta` +-- +ALTER TABLE `tbl_customers_meta` + ADD PRIMARY KEY (`id`); + +-- +-- AUTO_INCREMENT untuk tabel `tbl_customers_meta` +-- +ALTER TABLE `tbl_customers_meta` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; COMMIT; -- diff --git a/install/step2.php b/install/step2.php index f65f6de4..df1989e3 100644 --- a/install/step2.php +++ b/install/step2.php @@ -57,7 +57,7 @@ Continue

Update System"); } else { echo ("
$ltext
Sorry. The requirements of PHPNuxBill is not available on your server. - Please contact with us- iesien22@yahoo.com with this code- $passed Or contact with your server administrator + Contact with us at Telegram @phpnuxbill with this code- $passed Or contact with your server administrator

Correct The Problem To Continue"); } diff --git a/system/autoload/Balance.php b/system/autoload/Balance.php new file mode 100644 index 00000000..2b3713d2 --- /dev/null +++ b/system/autoload/Balance.php @@ -0,0 +1,71 @@ +where('id', $id_customer)->find_one(); + $c->balance = $amount + $c['balance']; + $c->save(); + } + + public static function transfer($id_customer, $phoneTarget, $amount) + { + global $config; + if ($config['allow_balance_transfer'] == 'yes') { + if(Balance::min($id_customer, $amount)){ + if(Balance::plusByPhone($phoneTarget, $amount)){ + return true; + }else{ + Balance::plus($id_customer, $amount); + return false; + } + }else{ + return false; + } + }else{ + return false; + } + } + + public static function min($id_customer, $amount) + { + $c = ORM::for_table('tbl_customers')->where('id', $id_customer)->find_one(); + if ($c && $c['balance'] >= $amount) { + $c->balance = $amount - $c['balance']; + $c->save(); + return true; + } else { + return false; + } + } + + public static function plusByPhone($phone_customer, $amount) + { + $c = ORM::for_table('tbl_customers')->where('username', $phone_customer)->find_one(); + if($c){ + $c->balance = $amount + $c['balance']; + $c->save(); + return true; + } + return false; + } + + public static function minByPhone($phone_customer, $amount) + { + $c = ORM::for_table('tbl_customers')->where('username', $phone_customer)->find_one(); + if ($c && $c['balance'] >= $amount) { + $c->balance = $amount - $c['balance']; + $c->save(); + return true; + } else { + return false; + } + } +} diff --git a/system/autoload/Lang.php b/system/autoload/Lang.php index dc9292f6..6c790bd4 100644 --- a/system/autoload/Lang.php +++ b/system/autoload/Lang.php @@ -4,12 +4,31 @@ * PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/) **/ -class Lang { - public static function T($var) { +class Lang +{ + public static function T($var) + { return Lang($var); } - public static function htmlspecialchars($var) { + public static function htmlspecialchars($var) + { return htmlspecialchars($var); } + + public static function moneyFormat($var) + { + global $config; + return $config['currency_code'] . ' ' .number_format($var, 0, $config['dec_point'], $config['thousands_sep']); + } + + public static function phoneFormat($phone) + { + global $config; + if(Validator::UnsignedNumber($phone) && !empty($config['country_code_phone'])){ + return preg_replace('/^0/', $config['country_code_phone'], $phone); + }else{ + return $phone; + } + } } diff --git a/system/autoload/Message.php b/system/autoload/Message.php index 0606f42c..0373d682 100644 --- a/system/autoload/Message.php +++ b/system/autoload/Message.php @@ -39,20 +39,21 @@ class Message } } - public static function sendExpiredNotification($phone, $name, $package, $textExpired, $via) + public static function sendPackageNotification($phone, $name, $package, $message, $via) { + $msg = str_replace('[[name]]', "*$name*", $message); + $msg = str_replace('[[package]]', "*$package*", $msg); if ( !empty($phone) && strlen($phone) > 5 - && !empty($textExpired) && in_array($via, ['sms', 'wa']) + && !empty($message) && in_array($via, ['sms', 'wa']) ) { - $msg = str_replace('[[name]]', "*$name*", $textExpired); - $msg = str_replace('[[package]]', "*$package*", $msg); if ($via == 'sms') { Message::sendSMS($phone, $msg); } else if ($via == 'wa') { Message::sendWhatsapp($phone, $msg); } } + return "$via: $msg"; } } diff --git a/system/autoload/Mikrotik.php b/system/autoload/Mikrotik.php index 0b98ecd4..17b344e0 100644 --- a/system/autoload/Mikrotik.php +++ b/system/autoload/Mikrotik.php @@ -204,24 +204,29 @@ class Mikrotik '/ppp secret print .proplist=name', RouterOS\Query::where('name', $username) ); - $userName = $client->sendSync($printRequest)->getProperty('name'); + $id = $client->sendSync($printRequest)->getProperty('.id'); $removeRequest = new RouterOS\Request('/ppp/secret/remove'); $client( $removeRequest - ->setArgument('numbers', $userName) + ->setArgument('numbers', $id) ); } public static function addPpoeUser($client, $plan, $customer) { $addRequest = new RouterOS\Request('/ppp/secret/add'); + if(!empty($customer['pppoe_password'])){ + $pass = $customer['pppoe_password']; + }else{ + $pass = $customer['password']; + } $client->sendSync( $addRequest ->setArgument('name', $customer['username']) ->setArgument('service', 'pppoe') ->setArgument('profile', $plan['name_plan']) - ->setArgument('password', $customer['password']) + ->setArgument('password', $pass) ); } diff --git a/system/autoload/Package.php b/system/autoload/Package.php index 384140dd..0a803dfc 100644 --- a/system/autoload/Package.php +++ b/system/autoload/Package.php @@ -19,7 +19,7 @@ class Package */ public static function rechargeUser($id_customer, $router_name, $plan_id, $gateway, $channel) { - global $_c, $_L; + global $_c, $_L, $_notifmsg; $date_now = date("Y-m-d H:i:s"); $date_only = date("Y-m-d"); $time = date("H:i:s"); @@ -30,6 +30,50 @@ class Package $c = ORM::for_table('tbl_customers')->where('id', $id_customer)->find_one(); $p = ORM::for_table('tbl_plans')->where('id', $plan_id)->where('enabled', '1')->find_one(); + + if ($router_name == 'balance') { + // insert table transactions + $inv = "INV-" . _raid(5); + $t = ORM::for_table('tbl_transactions')->create(); + $t->invoice = $inv; + $t->username = $c['username']; + $t->plan_name = $p['name_plan']; + $t->price = $p['price']; + $t->recharged_on = $date_only; + $t->expiration = $date_only; + $t->time = $time; + $t->method = "$gateway - $channel"; + $t->routers = $router_name; + $t->type = "Balance"; + $t->save(); + + Balance::plus($id_customer, $p['price']); + + $textInvoice = $_notifmsg['invoice_balance']; + $textInvoice = str_replace('[[company_name]]', $_c['CompanyName'], $textInvoice); + $textInvoice = str_replace('[[address]]', $_c['address'], $textInvoice); + $textInvoice = str_replace('[[phone]]', $_c['phone'], $textInvoice); + $textInvoice = str_replace('[[invoice]]', $inv, $textInvoice); + $textInvoice = str_replace('[[date]]', date($_c['date_format'], strtotime($date_only)) . " " . $time, $textInvoice); + $textInvoice = str_replace('[[payment_gateway]]', $_c['gateway'], $textInvoice); + $textInvoice = str_replace('[[payment_channel]]', $_c['channel'], $textInvoice); + $textInvoice = str_replace('[[type]]', 'Balance', $textInvoice); + $textInvoice = str_replace('[[plan_name]]', $p['name_plan'], $textInvoice); + $textInvoice = str_replace('[[plan_price]]', $_c['currency_code'] . " " . number_format($p['price'], 2, $_c['dec_point'], $_c['thousands_sep']), $textInvoice); + $textInvoice = str_replace('[[user_name]]', $c['username'], $textInvoice); + $textInvoice = str_replace('[[user_password]]', $c['password'], $textInvoice); + $textInvoice = str_replace('[[footer]]', $_c['note'], $textInvoice); + + if ($_c['user_notification_payment'] == 'sms') { + Message::sendSMS($c['phonenumber'], $textInvoice); + } else if ($_c['user_notification_payment'] == 'wa') { + Message::sendWhatsapp($c['phonenumber'], $textInvoice); + } + + return true; + } + + $b = ORM::for_table('tbl_user_recharges')->where('customer_id', $id_customer)->find_one(); $mikrotik = Mikrotik::info($router_name); @@ -198,29 +242,63 @@ class Package $in = ORM::for_table('tbl_transactions')->where('username', $c['username'])->order_by_desc('id')->find_one(); - $msg = "*$_c[CompanyName]*\n" . - "$_c[address]\n" . - "$_c[phone]\n" . - "\n\n" . - "INVOICE: *$in[invoice]*\n" . - "$_L[Date] : $date_now\n" . - "$gateway $channel\n" . - "\n\n" . - "$_L[Type] : *$in[type]*\n" . - "$_L[Plan_Name] : *$in[plan_name]*\n" . - "$_L[Plan_Price] : *$_c[currency_code] " . number_format($in['price'], 2, $_c['dec_point'], $_c['thousands_sep']) . "*\n\n" . - "$_L[Username] : *$in[username]*\n" . - "$_L[Password] : **********\n\n" . - "$_L[Created_On] :\n*" . date($_c['date_format'], strtotime($in['recharged_on'])) . "*\n" . - "$_L[Expires_On] :\n*" . date($_c['date_format'], strtotime($in['expiration'])) . " $in[time]*\n" . - "\n\n" . - "$_c[note]"; + $textInvoice = $_notifmsg['invoice_paid']; + $textInvoice = str_replace('[[company_name]]', $_c['CompanyName'], $textInvoice); + $textInvoice = str_replace('[[address]]', $_c['address'], $textInvoice); + $textInvoice = str_replace('[[phone]]', $_c['phone'], $textInvoice); + $textInvoice = str_replace('[[invoice]]', $in['invoice'], $textInvoice); + $textInvoice = str_replace('[[date]]', date($_c['date_format'], strtotime($date_now)) . " " . $time, $textInvoice); + $textInvoice = str_replace('[[payment_gateway]]', $_c['gateway'], $textInvoice); + $textInvoice = str_replace('[[payment_channel]]', $_c['channel'], $textInvoice); + $textInvoice = str_replace('[[type]]', $in['type'], $textInvoice); + $textInvoice = str_replace('[[plan_name]]', $in['plan_name'], $textInvoice); + $textInvoice = str_replace('[[plan_price]]', $_c['currency_code'] . " " . number_format($in['price'], 2, $_c['dec_point'], $_c['thousands_sep']), $textInvoice); + $textInvoice = str_replace('[[user_name]]', $in['username'], $textInvoice); + $textInvoice = str_replace('[[user_password]]', $c['password'], $textInvoice); + $textInvoice = str_replace('[[expired_date]]', date($_c['date_format'], strtotime($in['expiration'])) . " " . $in['time'], $textInvoice); + $textInvoice = str_replace('[[footer]]', $_c['note'], $textInvoice); if ($_c['user_notification_payment'] == 'sms') { - Message::sendSMS($c['phonenumber'], $msg); + Message::sendSMS($c['phonenumber'], $textInvoice); } else if ($_c['user_notification_payment'] == 'wa') { - Message::sendWhatsapp($c['phonenumber'], $msg); + Message::sendWhatsapp($c['phonenumber'], $textInvoice); } return true; } + + public static function changeTo($username, $plan_id) + { + global $_c; + $c = ORM::for_table('tbl_customers')->where('username', $username)->find_one(); + $p = ORM::for_table('tbl_plans')->where('id', $plan_id)->where('enabled', '1')->find_one(); + $b = ORM::for_table('tbl_user_recharges')->where('customer_id', $c['id'])->find_one(); + $mikrotik = Mikrotik::info($p['routers']); + if ($p['type'] == 'Hotspot') { + if ($b) { + if (!$_c['radius_mode']) { + $client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); + Mikrotik::removeHotspotUser($client, $c['username']); + Mikrotik::addHotspotUser($client, $p, $c); + } + } else { + if (!$_c['radius_mode']) { + $client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); + Mikrotik::addHotspotUser($client, $p, $c); + } + } + } else { + if ($b) { + if (!$_c['radius_mode']) { + $client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); + Mikrotik::removePpoeUser($client, $c['username']); + Mikrotik::addPpoeUser($client, $p, $c); + } + } else { + if (!$_c['radius_mode']) { + $client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); + Mikrotik::addPpoeUser($client, $p, $c); + } + } + } + } } diff --git a/system/boot.php b/system/boot.php index c2e0c637..9e458289 100644 --- a/system/boot.php +++ b/system/boot.php @@ -128,6 +128,12 @@ if (isset($_SESSION['notify'])) { include "autoload/Hookers.php"; +// notification message +if(file_exists("system/uploads/notifications.json")){ + $_notifmsg =json_decode(file_get_contents('system/uploads/notifications.json'), true); +}else{ + $_notifmsg = json_decode(file_get_contents('system/uploads/notifications.default.json'), true); +} //register all plugin foreach (glob("system/plugin/*.php") as $filename) { diff --git a/system/controllers/accounts.php b/system/controllers/accounts.php index b586fdb2..559d7bd2 100644 --- a/system/controllers/accounts.php +++ b/system/controllers/accounts.php @@ -59,7 +59,11 @@ switch ($action) { } else { if (!$config['radius_mode']) { $client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); - Mikrotik::setPpoeUser($client, $c['username'], $npass); + if(!empty($d['pppoe_password'])){ + Mikrotik::setPpoeUser($client, $c['username'], $d['pppoe_password']); + }else{ + Mikrotik::setPpoeUser($client, $c['username'], $npass); + } Mikrotik::removePpoeActive($client, $user['username']); } $d->password = $npass; diff --git a/system/controllers/customers.php b/system/controllers/customers.php index 3aabc72b..cd12ed48 100644 --- a/system/controllers/customers.php +++ b/system/controllers/customers.php @@ -116,7 +116,8 @@ switch ($action) { $username = _post('username'); $fullname = _post('fullname'); $password = _post('password'); - $cpassword = _post('cpassword'); + $pppoe_password = _post('pppoe_password'); + $email = _post('email'); $address = _post('address'); $phonenumber = _post('phonenumber'); run_hook('add_customer'); #HOOK @@ -130,9 +131,6 @@ switch ($action) { if (!Validator::Length($password, 35, 2)) { $msg .= 'Password should be between 3 to 35 characters' . '
'; } - if ($password != $cpassword) { - $msg .= 'Passwords does not match' . '
'; - } $d = ORM::for_table('tbl_customers')->where('username', $username)->find_one(); if ($d) { @@ -141,11 +139,13 @@ switch ($action) { if ($msg == '') { $d = ORM::for_table('tbl_customers')->create(); - $d->username = $username; + $d->username = Lang::phoneFormat($username); $d->password = $password; + $d->pppoe_password = $pppoe_password; + $d->email = $email; $d->fullname = $fullname; $d->address = $address; - $d->phonenumber = $username; + $d->phonenumber = Lang::phoneFormat($phonenumber); $d->save(); r2(U . 'customers/list', 's', $_L['account_created_successfully']); } else { @@ -154,27 +154,25 @@ switch ($action) { break; case 'edit-post': - $username = _post('username'); + $username = Lang::phoneFormat(_post('username')); $fullname = _post('fullname'); $password = _post('password'); - $cpassword = _post('cpassword'); + $pppoe_password = _post('pppoe_password'); + $email = _post('email'); $address = _post('address'); - $phonenumber = _post('phonenumber'); + $phonenumber = Lang::phoneFormat(_post('phonenumber')); run_hook('edit_customer'); #HOOK $msg = ''; if (Validator::Length($username, 16, 2) == false) { $msg .= 'Username should be between 3 to 15 characters' . '
'; } - if (Validator::Length($fullname, 26, 2) == false) { - $msg .= 'Full Name should be between 3 to 25 characters' . '
'; + if (Validator::Length($fullname, 26, 1) == false) { + $msg .= 'Full Name should be between 2 to 25 characters' . '
'; } if ($password != '') { if (!Validator::Length($password, 15, 2)) { $msg .= 'Password should be between 3 to 15 characters' . '
'; } - if ($password != $cpassword) { - $msg .= 'Passwords does not match' . '
'; - } } $id = _post('id'); @@ -206,7 +204,11 @@ switch ($action) { } else { if(!$config['radius_mode']){ $client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); - Mikrotik::setPpoeUser($client,$c['username'],$password); + if(!empty($d['pppoe_password'])){ + Mikrotik::setPpoeUser($client, $c['username'], $d['pppoe_password']); + }else{ + Mikrotik::setPpoeUser($client, $c['username'], $password); + } Mikrotik::removePpoeActive($client,$user['username']); } @@ -217,7 +219,9 @@ switch ($action) { if ($password != '') { $d->password = $password; } + $d->pppoe_password = $pppoe_password; $d->fullname = $fullname; + $d->email = $email; $d->address = $address; $d->phonenumber = $phonenumber; $d->save(); @@ -227,6 +231,8 @@ switch ($action) { $d->password = $password; } $d->fullname = $fullname; + $d->pppoe_password = $pppoe_password; + $d->email = $email; $d->address = $address; $d->phonenumber = $phonenumber; $d->save(); diff --git a/system/controllers/export.php b/system/controllers/export.php index 0cd60ac7..0d2ba727 100644 --- a/system/controllers/export.php +++ b/system/controllers/export.php @@ -61,6 +61,12 @@ switch ($action) { $title = ' Reports [' . $mdate . ']'; $title = str_replace('-', ' ', $title); + if(file_exists('system/uploads/logo.png')){ + $logo = 'system/uploads/logo.png'; + }else{ + $logo = 'system/uploads/logo.default.png'; + } + if ($x) { $html = '
@@ -69,7 +75,7 @@ switch ($action) { ' . $config['address'] . '
' . $_L['Phone_Number'] . ': ' . $config['phone'] . '
- + @@ -178,7 +184,6 @@ EOF; if ($stype != '') { $d->where('type', $stype); } - $d->where_gte('recharged_on', $fdate); $d->where_lte('recharged_on', $tdate); $d->order_by_desc('id'); @@ -207,7 +212,6 @@ EOF; $fdate = _post('fdate'); $tdate = _post('tdate'); $stype = _post('stype'); - $d = ORM::for_table('tbl_transactions'); if ($stype != '') { $d->where('type', $stype); @@ -229,6 +233,11 @@ EOF; $title = ' Reports [' . $mdate . ']'; $title = str_replace('-', ' ', $title); + if(file_exists('system/uploads/logo.png')){ + $logo = 'system/uploads/logo.png'; + }else{ + $logo = 'system/uploads/logo.default.png'; + } if ($x) { $html = ' @@ -238,7 +247,7 @@ EOF; ' . $config['address'] . '
' . $_L['Phone_Number'] . ': ' . $config['phone'] . '
- +
@@ -281,11 +290,7 @@ EOF;

' . $config['currency_code'] . ' ' . number_format($xy, 2, $config['dec_point'], $config['thousands_sep']) . '

'; run_hook('pdf_by_period'); #HOOK - define('_MPDF_PATH', 'system/vendors/mpdf/'); - - require('system/vendors/mpdf/mpdf.php'); - - $mpdf = new mPDF('c', 'A4', '', '', 20, 15, 25, 25, 10, 10); + $mpdf = new \Mpdf\Mpdf(); $mpdf->SetProtection(array('print')); $mpdf->SetTitle($config['CompanyName'] . ' Reports'); $mpdf->SetAuthor($config['CompanyName']); diff --git a/system/controllers/home.php b/system/controllers/home.php index a4372225..6108d816 100644 --- a/system/controllers/home.php +++ b/system/controllers/home.php @@ -9,6 +9,11 @@ $ui->assign('_title', $_L['Dashboard']); $user = User::_info(); $ui->assign('_user', $user); +if(isset($_GET['renewal'])){ + $user->auto_renewal = $_GET['renewal']; + $user->save(); +} + //Client Page $bill = User::_billing(); diff --git a/system/controllers/order.php b/system/controllers/order.php index 016c2c4c..19ee3e2d 100644 --- a/system/controllers/order.php +++ b/system/controllers/order.php @@ -35,9 +35,13 @@ switch ($action) { $ui->assign('_title', 'Order Plan'); $ui->assign('_system_menu', 'package'); $routers = ORM::for_table('tbl_routers')->find_many(); - $plans = ORM::for_table('tbl_plans')->where('enabled', '1')->find_many(); + $plans_pppoe = ORM::for_table('tbl_plans')->where('enabled', '1')->where('type', 'PPPOE')->find_many(); + $plans_hotspot = ORM::for_table('tbl_plans')->where('enabled', '1')->where('type', 'Hotspot')->find_many(); + $plans_balance = ORM::for_table('tbl_plans')->where('enabled', '1')->where('type', 'Balance')->find_many(); $ui->assign('routers', $routers); - $ui->assign('plans', $plans); + $ui->assign('plans_pppoe', $plans_pppoe); + $ui->assign('plans_hotspot', $plans_hotspot); + $ui->assign('plans_balance', $plans_balance); run_hook('customer_view_order_plan'); #HOOK $ui->display('user-orderPlan.tpl'); break; @@ -118,11 +122,15 @@ switch ($action) { run_hook('customer_buy_plan'); #HOOK include 'system/paymentgateway/' . $config['payment_gateway'] . '.php'; call_user_func($config['payment_gateway'] . '_validate_config'); - - $router = ORM::for_table('tbl_routers')->where('enabled', '1')->find_one($routes['2'] * 1); - $plan = ORM::for_table('tbl_plans')->where('enabled', '1')->find_one($routes['3'] * 1); + if ($routes['2']>0) { + $router = ORM::for_table('tbl_routers')->where('enabled', '1')->find_one($routes['2']); + }else{ + $router['id'] = 0; + $router['name'] = 'balance'; + } + $plan = ORM::for_table('tbl_plans')->where('enabled', '1')->find_one($routes['3']); if (empty($router) || empty($plan)) { - r2(U . $back, 'e', Lang::T("Plan Not found")); + r2(U . "order/package", 'e', Lang::T("Plan Not found")); } $d = ORM::for_table('tbl_payment_gateway') ->where('username', $user['username']) @@ -172,5 +180,5 @@ switch ($action) { } break; default: - $ui->display('404.tpl'); + r2(U . "order/package/", 's',''); } diff --git a/system/controllers/prepaid.php b/system/controllers/prepaid.php index 0fbee57f..0ba294d0 100644 --- a/system/controllers/prepaid.php +++ b/system/controllers/prepaid.php @@ -72,8 +72,6 @@ switch ($action) { $type = _post('type'); $server = _post('server'); $plan = _post('plan'); - - $date_now = date("Y-m-d H:i:s"); $date_only = date("Y-m-d"); $time = date("H:i:s"); @@ -83,212 +81,28 @@ switch ($action) { } if ($msg == '') { - $c = ORM::for_table('tbl_customers')->where('id', $id_customer)->find_one(); - $p = ORM::for_table('tbl_plans')->where('id', $plan)->where('enabled', '1')->find_one(); - $b = ORM::for_table('tbl_user_recharges')->where('customer_id', $id_customer)->find_one(); - - $mikrotik = Mikrotik::info($server); - if($p['validity_unit']=='Months'){ - $date_exp = date("Y-m-d", strtotime('+'.$p['validity'].' month')); - }else if($p['validity_unit']=='Days'){ - $date_exp = date("Y-m-d", strtotime('+'.$p['validity'].' day')); - }else if($p['validity_unit']=='Hrs'){ - $datetime = explode(' ',date("Y-m-d H:i:s", strtotime('+'.$p['validity'].' hour'))); - $date_exp = $datetime[0]; - $time = $datetime[1]; - }else if($p['validity_unit']=='Mins'){ - $datetime = explode(' ',date("Y-m-d H:i:s", strtotime('+'.$p['validity'].' minute'))); - $date_exp = $datetime[0]; - $time = $datetime[1]; + if(Package::rechargeUser($id_customer, $server, $plan, "Recharge", $admin['fullname'])){ + $c = ORM::for_table('tbl_customers')->where('id', $id_customer)->find_one(); + $in = ORM::for_table('tbl_transactions')->where('username', $c['username'])->order_by_desc('id')->find_one(); + $ui->assign('in', $in); + $ui->assign('date', date("Y-m-d H:i:s")); + $ui->display('invoice.tpl'); + _log('[' . $admin['username'] . ']: ' . 'Recharge '.$c['username'].' ['.$in['plan_name'].']['.Lang::moneyFormat($in['price']).']', 'Admin', $admin['id']); + }else{ + r2(U . 'prepaid/recharge', 'e', "Failed to recharge account"); } - run_hook('recharge_customer'); #HOOK - if ($type == 'Hotspot') { - if ($b) { - if(!$config['radius_mode']){ - $client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); - Mikrotik::removeHotspotUser($client,$c['username']); - Mikrotik::addHotspotUser($client,$p,$c); - } - - $b->customer_id = $id_customer; - $b->username = $c['username']; - $b->plan_id = $plan; - $b->namebp = $p['name_plan']; - $b->recharged_on = $date_only; - $b->expiration = $date_exp; - $b->time = $time; - $b->status = "on"; - $b->method = "admin"; - $b->routers = $server; - $b->type = "Hotspot"; - $b->save(); - - // insert table transactions - $t = ORM::for_table('tbl_transactions')->create(); - $t->invoice = "INV-" . _raid(5); - $t->username = $c['username']; - $t->plan_name = $p['name_plan']; - $t->price = $p['price']; - $t->recharged_on = $date_only; - $t->expiration = $date_exp; - $t->time = $time; - $t->method = "admin"; - $t->routers = $server; - $t->type = "Hotspot"; - $t->save(); - } else { - if(!$config['radius_mode']){ - $client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); - Mikrotik::addHotspotUser($client,$p,$c); - } - - $d = ORM::for_table('tbl_user_recharges')->create(); - $d->customer_id = $id_customer; - $d->username = $c['username']; - $d->plan_id = $plan; - $d->namebp = $p['name_plan']; - $d->recharged_on = $date_only; - $d->expiration = $date_exp; - $d->time = $time; - $d->status = "on"; - $d->method = "admin"; - $d->routers = $server; - $d->type = "Hotspot"; - $d->save(); - - // insert table transactions - $t = ORM::for_table('tbl_transactions')->create(); - $t->invoice = "INV-" . _raid(5); - $t->username = $c['username']; - $t->plan_name = $p['name_plan']; - $t->price = $p['price']; - $t->recharged_on = $date_only; - $t->expiration = $date_exp; - $t->time = $time; - $t->method = "admin"; - $t->routers = $server; - $t->type = "Hotspot"; - $t->save(); - } - Message::sendTelegram( "$admin[fullname] #Recharge Voucher #Hotspot for #u$c[username]\n".$p['name_plan']. - "\nRouter: ".$server. - "\nPrice: ".$p['price']); - } else { - - if ($b) { - if(!$config['radius_mode']){ - $client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); - Mikrotik::removePpoeUser($client,$c['username']); - Mikrotik::addPpoeUser($client,$p,$c); - } - - $b->customer_id = $id_customer; - $b->username = $c['username']; - $b->plan_id = $plan; - $b->namebp = $p['name_plan']; - $b->recharged_on = $date_only; - $b->expiration = $date_exp; - $b->time = $time; - $b->status = "on"; - $b->method = "admin"; - $b->routers = $server; - $b->type = "PPPOE"; - $b->save(); - - // insert table transactions - $t = ORM::for_table('tbl_transactions')->create(); - $t->invoice = "INV-" . _raid(5); - $t->username = $c['username']; - $t->plan_name = $p['name_plan']; - $t->price = $p['price']; - $t->recharged_on = $date_only; - $t->expiration = $date_exp; - $t->time = $time; - $t->method = "admin"; - $t->routers = $server; - $t->type = "PPPOE"; - $t->save(); - } else { - if(!$config['radius_mode']){ - $client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); - Mikrotik::addPpoeUser($client,$p,$c); - } - - $d = ORM::for_table('tbl_user_recharges')->create(); - $d->customer_id = $id_customer; - $d->username = $c['username']; - $d->plan_id = $plan; - $d->namebp = $p['name_plan']; - $d->recharged_on = $date_only; - $d->expiration = $date_exp; - $d->time = $time; - $d->status = "on"; - $d->method = "admin"; - $d->routers = $server; - $d->type = "PPPOE"; - $d->save(); - - // insert table transactions - $t = ORM::for_table('tbl_transactions')->create(); - $t->invoice = "INV-" . _raid(5); - $t->username = $c['username']; - $t->plan_name = $p['name_plan']; - $t->price = $p['price']; - $t->recharged_on = $date_only; - $t->expiration = $date_exp; - $t->time = $time; - $t->method = "admin"; - $t->routers = $server; - $t->type = "PPPOE"; - $t->save(); - } - Message::sendTelegram( "$admin[fullname] #Recharge Voucher #PPPOE for #u$c[username]\n".$p['name_plan']. - "\nRouter: ".$server. - "\nPrice: ".$p['price']); - } - - $in = ORM::for_table('tbl_transactions')->where('username', $c['username'])->order_by_desc('id')->find_one(); - $ui->assign('in', $in); - - $msg = "*$config[CompanyName]*\n". - "$config[address]\n". - "$config[phone]\n". - "\n\n". - "INVOICE: *$in[invoice]*\n". - "$_L[Date] : $date_now\n". - "$_L[Sales] : $admin[fullname]\n". - "\n\n". - "$_L[Type] : *$in[type]*\n". - "$_L[Plan_Name] : *$in[plan_name]*\n". - "$_L[Plan_Price] : *$config[currency_code] ".number_format($in['price'],2,$config['dec_point'],$config['thousands_sep'])."*\n\n". - "$_L[Username] : *$in[username]*\n". - "$_L[Password] : **********\n\n". - "$_L[Created_On] :\n*".date($config['date_format'], strtotime($in['recharged_on']))."*\n". - "$_L[Expires_On] :\n*".date($config['date_format'], strtotime($in['expiration']))." $in[time]*\n". - "\n\n". - "$config[note]"; - - if ($_c['user_notification_payment'] == 'sms') { - Message::sendSMS($c['phonenumber'], $msg); - } else if ($_c['user_notification_payment'] == 'wa') { - Message::sendWhatsapp($c['phonenumber'], $msg); - } - - $ui->assign('date', $date_now); - $ui->display('invoice.tpl'); } else { r2(U . 'prepaid/recharge', 'e', $msg); } break; case 'print': - $date_now = date("Y-m-d H:i:s"); $id = _post('id'); $d = ORM::for_table('tbl_transactions')->where('id', $id)->find_one(); $ui->assign('d', $d); - $ui->assign('date', $date_now); + $ui->assign('date', date("Y-m-d H:i:s")); run_hook('print_invoice'); #HOOK $ui->display('invoice-print.tpl'); break; @@ -328,6 +142,7 @@ switch ($action) { } $d->delete(); } + _log('[' . $admin['username'] . ']: ' . 'Delete Plan for Customer '.$c['username'].' ['.$in['plan_name'].']['.Lang::moneyFormat($in['price']).']', 'Admin', $admin['id']); r2(U . 'prepaid/list', 's', $_L['Delete_Successfully']); } break; @@ -352,7 +167,8 @@ switch ($action) { $d->recharged_on = $recharged_on; $d->expiration = $expiration; $d->save(); - //TODO set mikrotik for editedd plan + Package::changeTo($username,$id_plan); + _log('[' . $admin['username'] . ']: ' . 'Edit Plan for Customer '.$d['username'].' to ['.$d['plan_name'].']['.Lang::moneyFormat($d['price']).']', 'Admin', $admin['id']); r2(U . 'prepaid/list', 's', $_L['Updated_Successfully']); } else { r2(U . 'prepaid/edit/' . $id, 'e', $msg); @@ -526,7 +342,7 @@ switch ($action) { case 'refill': $ui->assign('xfooter', ''); - + $ui->assign('_title', $_L['Refill_Account']); $c = ORM::for_table('tbl_customers')->find_many(); $ui->assign('c', $c); run_hook('view_refill'); #HOOK @@ -540,221 +356,50 @@ switch ($action) { $v1 = ORM::for_table('tbl_voucher')->where('code', $code)->where('status', 0)->find_one(); - $c = ORM::for_table('tbl_customers')->find_one($user); - $p = ORM::for_table('tbl_plans')->find_one($v1['id_plan']); - $b = ORM::for_table('tbl_user_recharges')->where('customer_id', $user)->find_one(); - - $date_now = date("Y-m-d H:i:s"); - $date_only = date("Y-m-d"); - $time = date("H:i:s"); - - $mikrotik = Mikrotik::info($v1['routers']); - - if($p['validity_unit']=='Months'){ - $date_exp = date("Y-m-d", strtotime('+'.$p['validity'].' month')); - }else if($p['validity_unit']=='Days'){ - $date_exp = date("Y-m-d", strtotime('+'.$p['validity'].' day')); - }else if($p['validity_unit']=='Hrs'){ - $datetime = explode(' ',date("Y-m-d H:i:s", strtotime('+'.$p['validity'].' hour'))); - $date_exp = $datetime[0]; - $time = $datetime[1]; - }else if($p['validity_unit']=='Mins'){ - $datetime = explode(' ',date("Y-m-d H:i:s", strtotime('+'.$p['validity'].' minute'))); - $date_exp = $datetime[0]; - $time = $datetime[1]; - } run_hook('refill_customer'); #HOOK if ($v1) { - if ($v1['type'] == 'Hotspot') { - if ($b) { - if(!$config['radius_mode']){ - $client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); - Mikrotik::removeHotspotUser($client,$c['username']); - Mikrotik::addHotspotUser($client,$p,$c); - } - - $b->customer_id = $user; - $b->username = $c['username']; - $b->plan_id = $v1['id_plan']; - $b->namebp = $p['name_plan']; - $b->recharged_on = $date_only; - $b->expiration = $date_exp; - $b->time = $time; - $b->status = "on"; - $b->method = "voucher"; - $b->routers = $v1['routers']; - $b->type = "Hotspot"; - $b->save(); - - // insert table transactions - $t = ORM::for_table('tbl_transactions')->create(); - $t->invoice = "INV-" . _raid(5); - $t->username = $c['username']; - $t->plan_name = $p['name_plan']; - $t->price = $p['price']; - $t->recharged_on = $date_only; - $t->expiration = $date_exp; - $t->time = $time; - $t->method = "voucher"; - $t->routers = $v1['routers']; - $t->type = "Hotspot"; - $t->save(); - } else { - if(!$config['radius_mode']){ - $client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); - Mikrotik::addHotspotUser($client,$p,$c); - } - - $d = ORM::for_table('tbl_user_recharges')->create(); - $d->customer_id = $user; - $d->username = $c['username']; - $d->plan_id = $v1['id_plan']; - $d->namebp = $p['name_plan']; - $d->recharged_on = $date_only; - $d->expiration = $date_exp; - $d->time = $time; - $d->status = "on"; - $d->method = "voucher"; - $d->routers = $v1['routers']; - $d->type = "Hotspot"; - $d->save(); - - // insert table transactions - $t = ORM::for_table('tbl_transactions')->create(); - $t->invoice = "INV-" . _raid(5); - $t->username = $c['username']; - $t->plan_name = $p['name_plan']; - $t->price = $p['price']; - $t->recharged_on = $date_only; - $t->expiration = $date_exp; - $t->time = $time; - $t->method = "voucher"; - $t->routers = $v1['routers']; - $t->type = "Hotspot"; - $t->save(); - } - + if(Package::rechargeUser($user, $v1['routers'], $v1['id_plan'], "Refill", "Voucher")){ $v1->status = "1"; $v1->user = $c['username']; $v1->save(); - - Message::sendTelegram( "$admin[fullname] #Refill #Voucher #Hotspot for #u$c[username]\n".$p['name_plan']. - "\nCode: ".$code. - "\nRouter: ".$v1['routers']. - "\nPrice: ".$p['price']); - } else { - if ($b) { - if(!$config['radius_mode']){ - $client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); - Mikrotik::removePpoeUser($client,$c['username']); - Mikrotik::addPpoeUser($client,$p,$c); - } - - $b->customer_id = $user; - $b->username = $c['username']; - $b->plan_id = $v1['id_plan']; - $b->namebp = $p['name_plan']; - $b->recharged_on = $date_only; - $b->expiration = $date_exp; - $b->time = $time; - $b->status = "on"; - $b->method = "voucher"; - $b->routers = $v1['routers']; - $b->type = "PPPOE"; - $b->save(); - - // insert table transactions - $t = ORM::for_table('tbl_transactions')->create(); - $t->invoice = "INV-" . _raid(5); - $t->username = $c['username']; - $t->plan_name = $p['name_plan']; - $t->price = $p['price']; - $t->recharged_on = $date_only; - $t->expiration = $date_exp; - $t->time = $time; - $t->method = "voucher"; - $t->routers = $v1['routers']; - $t->type = "PPPOE"; - $t->save(); - } else { - if(!$config['radius_mode']){ - $client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); - Mikrotik::addPpoeUser($client,$p,$c); - } - - $d = ORM::for_table('tbl_user_recharges')->create(); - $d->customer_id = $user; - $d->username = $c['username']; - $d->plan_id = $v1['id_plan']; - $d->namebp = $p['name_plan']; - $d->recharged_on = $date_only; - $d->expiration = $date_exp; - $d->time = $time; - $d->status = "on"; - $d->method = "voucher"; - $d->routers = $v1['routers']; - $d->type = "PPPOE"; - $d->save(); - - // insert table transactions - $t = ORM::for_table('tbl_transactions')->create(); - $t->invoice = "INV-" . _raid(5); - $t->username = $c['username']; - $t->plan_name = $p['name_plan']; - $t->price = $p['price']; - $t->recharged_on = $date_only; - $t->expiration = $date_exp; - $t->time = $time; - $t->method = "voucher"; - $t->routers = $v1['routers']; - $t->type = "PPPOE"; - $t->save(); - } - - $v1->status = "1"; - $v1->user = $c['username']; - $v1->save(); - - - Message::sendTelegram( "$admin[fullname] Refill #Voucher #PPPOE for #u$c[username]\n".$p['name_plan']. - "\nCode: ".$code. - "\nRouter: ".$v1['routers']. - "\nPrice: ".$p['price']); + $c = ORM::for_table('tbl_customers')->where('id', $id_customer)->find_one(); + $in = ORM::for_table('tbl_transactions')->where('username', $c['username'])->order_by_desc('id')->find_one(); + $ui->assign('in', $in); + $ui->assign('date', date("Y-m-d H:i:s")); + $ui->display('invoice.tpl'); + }else{ + r2(U . 'prepaid/refill', 'e', "Failed to refill account"); } - $in = ORM::for_table('tbl_transactions')->where('username', $c['username'])->order_by_desc('id')->find_one(); - $ui->assign('in', $in); - - - $msg = "*$config[CompanyName]*\n". - "$config[address]\n". - "$config[phone]\n". - "\n\n". - "INVOICE: *$in[invoice]*\n". - "$_L[Date] : $date_now\n". - "$_L[Sales] : $admin[fullname]\n". - "\n\n". - "$_L[Type] : *$in[type]*\n". - "$_L[Plan_Name] : *$in[plan_name]*\n". - "$_L[Plan_Price] : *$config[currency_code] ".number_format($in['price'],2,$config['dec_point'],$config['thousands_sep'])."*\n\n". - "$_L[Username] : *$in[username]*\n". - "$_L[Password] : **********\n\n". - "$_L[Created_On] :\n*".date($config['date_format'], strtotime($in['recharged_on']))."*\n". - "$_L[Expires_On] :\n*".date($config['date_format'], strtotime($in['expiration']))." $in[time]*\n". - "\n\n". - "$config[note]"; - - if ($_c['user_notification_payment'] == 'sms') { - Message::sendSMS($c['phonenumber'], $msg); - } else if ($_c['user_notification_payment'] == 'wa') { - Message::sendWhatsapp($c['phonenumber'], $msg); - } - $ui->assign('date', $date_now); - $ui->display('invoice.tpl'); } else { r2(U . 'prepaid/refill', 'e', $_L['Voucher_Not_Valid']); } break; + case 'deposit': + $ui->assign('_title', Lang::T('Refill Balance')); + $ui->assign('c', ORM::for_table('tbl_customers')->find_many()); + $ui->assign('p', ORM::for_table('tbl_plans')->where('enabled', '1')->where('type', 'Balance')->find_many()); + run_hook('view_deposit'); #HOOK + $ui->display('deposit.tpl'); + break; + case 'deposit-post': + $user = _post('id_customer'); + $plan = _post('id_plan'); + run_hook('deposit_customer'); #HOOK + if (!empty($user) && !empty($plan)) { + if(Package::rechargeUser($user, 'balance', $plan, "Deposit", $admin['fullname'])){ + $c = ORM::for_table('tbl_customers')->where('id', $user)->find_one(); + $in = ORM::for_table('tbl_transactions')->where('username', $c['username'])->order_by_desc('id')->find_one(); + $ui->assign('in', $in); + $ui->assign('date', date("Y-m-d H:i:s")); + $ui->display('invoice.tpl'); + }else{ + r2(U . 'prepaid/refill', 'e', "Failed to refill account"); + } + } else { + r2(U . 'prepaid/refill', 'e', "All field is required"); + } + break; default: echo 'action not defined'; } diff --git a/system/controllers/register.php b/system/controllers/register.php index 5f41f97f..8ebd8226 100644 --- a/system/controllers/register.php +++ b/system/controllers/register.php @@ -26,7 +26,8 @@ switch ($do) { $cpassword = _post('cpassword'); $address = _post('address'); if(!empty($config['sms_url'])){ - $phonenumber = $username; + $phonenumber = Lang::phoneFormat($username); + $username = $phonenumber; }else if(strlen($username)<21){ $phonenumber = $username; } diff --git a/system/controllers/services.php b/system/controllers/services.php index 7621a535..ed44feb3 100644 --- a/system/controllers/services.php +++ b/system/controllers/services.php @@ -70,10 +70,10 @@ switch ($action) { $d = ORM::for_table('tbl_plans')->find_one($id); if ($d) { run_hook('delete_plan'); #HOOK - if(!$config['radius_mode']){ + if (!$config['radius_mode']) { $mikrotik = Mikrotik::info($d['routers']); $client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); - Mikrotik::removeHotspotPlan($client,$d['name_plan']); + Mikrotik::removeHotspotPlan($client, $d['name_plan']); } $d->delete(); @@ -91,12 +91,12 @@ switch ($action) { $data_limit = _post('data_limit'); $data_unit = _post('data_unit'); $id_bw = _post('id_bw'); - $price = _post('pricebp'); + $price = _post('price'); $sharedusers = _post('sharedusers'); $validity = _post('validity'); $validity_unit = _post('validity_unit'); $routers = _post('routers'); - $enabled = _post('enabled')*1; + $enabled = _post('enabled'); $msg = ''; if (Validator::UnsignedNumber($validity) == false) { @@ -130,7 +130,7 @@ switch ($action) { } $rate = $b['rate_up'] . $unitup . "/" . $b['rate_down'] . $unitdown; - if(!$config['radius_mode']){ + if (!$config['radius_mode']) { $mikrotik = Mikrotik::info($routers); $client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); Mikrotik::addHotspotPlan($client, $name, $sharedusers, $rate); @@ -176,7 +176,7 @@ switch ($action) { $validity = _post('validity'); $validity_unit = _post('validity_unit'); $routers = _post('routers'); - $enabled = _post('enabled')*1; + $enabled = _post('enabled'); $msg = ''; if (Validator::UnsignedNumber($validity) == false) { @@ -209,7 +209,7 @@ switch ($action) { } $rate = $b['rate_up'] . $unitup . "/" . $b['rate_down'] . $unitdown; - if(!$config['radius_mode']){ + if (!$config['radius_mode']) { $mikrotik = Mikrotik::info($routers); $client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); Mikrotik::setHotspotPlan($client, $name, $sharedusers, $rate); @@ -293,7 +293,7 @@ switch ($action) { $d = ORM::for_table('tbl_plans')->find_one($id); if ($d) { run_hook('delete_ppoe'); #HOOK - if(!$config['radius_mode']){ + if (!$config['radius_mode']) { $mikrotik = Mikrotik::info($d['routers']); $client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); Mikrotik::removePpoePlan($client, $d['name_plan']); @@ -312,7 +312,7 @@ switch ($action) { $validity_unit = _post('validity_unit'); $routers = _post('routers'); $pool = _post('pool_name'); - $enabled = _post('enabled')*1; + $enabled = _post('enabled'); $msg = ''; if (Validator::UnsignedNumber($validity) == false) { @@ -344,7 +344,7 @@ switch ($action) { } $rate = $b['rate_up'] . $unitup . "/" . $b['rate_down'] . $unitdown; - if(!$config['radius_mode']){ + if (!$config['radius_mode']) { $mikrotik = Mikrotik::info($routers); $client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); Mikrotik::addPpoePlan($client, $name, $pool, $rate); @@ -377,7 +377,7 @@ switch ($action) { $validity_unit = _post('validity_unit'); $routers = _post('routers'); $pool = _post('pool_name'); - $enabled = _post('enabled')*1; + $enabled = _post('enabled'); $msg = ''; if (Validator::UnsignedNumber($validity) == false) { @@ -410,7 +410,7 @@ switch ($action) { } $rate = $b['rate_up'] . $unitup . "/" . $b['rate_down'] . $unitdown; - if(!$config['radius_mode']){ + if (!$config['radius_mode']) { $mikrotik = Mikrotik::info($routers); $client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']); Mikrotik::setPpoePlan($client, $name, $pool, $rate); @@ -431,7 +431,112 @@ switch ($action) { r2(U . 'services/pppoe-edit/' . $id, 'e', $msg); } break; + case 'balance': + $ui->assign('_title', Lang::T('Balance Plans')); + $name = _post('name'); + if ($name != '') { + $paginator = Paginator::bootstrap('tbl_plans', 'name_plan', '%' . $name . '%', 'type', 'Balance'); + $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(); + } else { + $paginator = Paginator::bootstrap('tbl_plans', 'type', 'Hotspot'); + $d = ORM::for_table('tbl_plans')->where('tbl_plans.type', 'Balance')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many(); + } + $ui->assign('d', $d); + $ui->assign('paginator', $paginator); + run_hook('view_list_balance'); #HOOK + $ui->display('balance.tpl'); + break; + case 'balance-add': + $ui->assign('_title', Lang::T('Balance Plans')); + run_hook('view_add_balance'); #HOOK + $ui->display('balance-add.tpl'); + break; + case 'balance-edit': + $ui->assign('_title', Lang::T('Balance Plans')); + $id = $routes['2']; + $d = ORM::for_table('tbl_plans')->find_one($id); + $ui->assign('d', $d); + run_hook('view_edit_balance'); #HOOK + $ui->display('balance-edit.tpl'); + break; + case 'balance-delete': + $id = $routes['2']; + + $d = ORM::for_table('tbl_plans')->find_one($id); + if ($d) { + run_hook('delete_balance'); #HOOK + $d->delete(); + r2(U . 'services/balance', 's', $_L['Delete_Successfully']); + } + break; + case 'balance-edit-post': + $id = _post('id'); + $name = _post('name'); + $price = _post('price'); + $enabled = _post('enabled'); + + $msg = ''; + if (Validator::UnsignedNumber($price) == false) { + $msg .= 'The price must be a number' . '
'; + } + if ($name == '') { + $msg .= $_L['All_field_is_required'] . '
'; + } + + $d = ORM::for_table('tbl_plans')->where('id', $id)->find_one(); + if ($d) { + } else { + $msg .= $_L['Data_Not_Found'] . '
'; + } + run_hook('edit_ppoe'); #HOOK + if ($msg == '') { + $d->name_plan = $name; + $d->price = $price; + $d->enabled = $enabled; + $d->save(); + + r2(U . 'services/balance', 's', $_L['Updated_Successfully']); + } else { + r2(U . 'services/balance-edit/' . $id, 'e', $msg); + } + break; + case 'balance-add-post': + $name = _post('name'); + $price = _post('price'); + $enabled = _post('enabled'); + + $msg = ''; + if (Validator::UnsignedNumber($price) == false) { + $msg .= 'The price must be a number' . '
'; + } + if ($name == '') { + $msg .= $_L['All_field_is_required'] . '
'; + } + + $d = ORM::for_table('tbl_plans')->where('name_plan', $name)->find_one(); + if ($d) { + $msg .= $_L['Plan_already_exist'] . '
'; + } + run_hook('add_ppoe'); #HOOK + if ($msg == '') { + $d = ORM::for_table('tbl_plans')->create(); + $d->type = 'Balance'; + $d->name_plan = $name; + $d->id_bw = 0; + $d->price = $price; + $d->validity = 0; + $d->validity_unit = 'Months'; + $d->routers = ''; + $d->pool = ''; + $d->enabled = $enabled; + $d->save(); + + r2(U . 'services/balance', 's', $_L['Created_Successfully']); + } else { + r2(U . 'services/balance-add', 'e', $msg); + } + break; default: echo 'action not defined'; } diff --git a/system/controllers/settings.php b/system/controllers/settings.php index 6a5625c6..0de22c16 100644 --- a/system/controllers/settings.php +++ b/system/controllers/settings.php @@ -206,13 +206,15 @@ switch ($action) { case 'app-post': $company = _post('company'); $footer = _post('footer'); + $enable_balance = _post('enable_balance'); + $allow_balance_transfer = _post('allow_balance_transfer'); $disable_voucher = _post('disable_voucher'); $telegram_bot = _post('telegram_bot'); $telegram_target_id = _post('telegram_target_id'); $sms_url = _post('sms_url'); $wa_url = _post('wa_url'); $user_notification_expired = _post('user_notification_expired'); - $user_notification_expired_text = _post('user_notification_expired_text'); + $user_notification_reminder = _post('user_notification_reminder'); $user_notification_payment = _post('user_notification_payment'); $address = _post('address'); $tawkto = _post('tawkto'); @@ -257,6 +259,28 @@ switch ($action) { $d->save(); } + $d = ORM::for_table('tbl_appconfig')->where('setting', 'enable_balance')->find_one(); + if($d){ + $d->value = $enable_balance; + $d->save(); + }else{ + $d = ORM::for_table('tbl_appconfig')->create(); + $d->setting = 'enable_balance'; + $d->value = $enable_balance; + $d->save(); + } + + $d = ORM::for_table('tbl_appconfig')->where('setting', 'allow_balance_transfer')->find_one(); + if($d){ + $d->value = $allow_balance_transfer; + $d->save(); + }else{ + $d = ORM::for_table('tbl_appconfig')->create(); + $d->setting = 'allow_balance_transfer'; + $d->value = $allow_balance_transfer; + $d->save(); + } + $d = ORM::for_table('tbl_appconfig')->where('setting', 'telegram_bot')->find_one(); if($d){ $d->value = $telegram_bot; @@ -312,14 +336,14 @@ switch ($action) { $d->save(); } - $d = ORM::for_table('tbl_appconfig')->where('setting', 'user_notification_expired_text')->find_one(); + $d = ORM::for_table('tbl_appconfig')->where('setting', 'user_notification_reminder')->find_one(); if($d){ - $d->value = $user_notification_expired_text; + $d->value = $user_notification_reminder; $d->save(); }else{ $d = ORM::for_table('tbl_appconfig')->create(); - $d->setting = 'user_notification_expired_text'; - $d->value = $user_notification_expired_text; + $d->setting = 'user_notification_reminder'; + $d->value = $user_notification_reminder; $d->save(); } @@ -370,6 +394,7 @@ switch ($action) { case 'localisation-post': $tzone = _post('tzone'); $date_format = _post('date_format'); + $country_code_phone = _post('country_code_phone'); $lan = _post('lan'); run_hook('save_localisation'); #HOOK if ($tzone == '' or $date_format == '' or $lan == '') { @@ -397,6 +422,18 @@ switch ($action) { $d->save(); } + + $d = ORM::for_table('tbl_appconfig')->where('setting', 'country_code_phone')->find_one(); + if($d){ + $d->value = $country_code_phone; + $d->save(); + }else{ + $d = ORM::for_table('tbl_appconfig')->create(); + $d->setting = 'country_code_phone'; + $d->value = $country_code_phone; + $d->save(); + } + $currency_code = $_POST['currency_code']; $d = ORM::for_table('tbl_appconfig')->where('setting', 'currency_code')->find_one(); $d->value = $currency_code; @@ -455,7 +492,22 @@ switch ($action) { } break; - + case 'notifications': + if ($admin['user_type'] != 'Admin' and $admin['user_type'] != 'Sales') { + r2(U . "dashboard", 'e', $_L['Do_Not_Access']); + } + run_hook('view_notifications'); #HOOK + if(file_exists("system/uploads/notifications.json")){ + $ui->assign('_json', json_decode(file_get_contents('system/uploads/notifications.json'), true)); + }else{ + $ui->assign('_json', json_decode(file_get_contents('system/uploads/notifications.default.json'), true)); + } + $ui->display('app-notifications.tpl'); + break; + case 'notifications-post': + file_put_contents("system/uploads/notifications.json", json_encode($_POST)); + r2(U . 'settings/notifications', 's', $_L['Settings_Saved_Successfully']); + break; case 'dbstatus': if ($admin['user_type'] != 'Admin') { r2(U . "dashboard", 'e', $_L['Do_Not_Access']); diff --git a/system/cron.php b/system/cron.php index 13a4837f..e7774867 100644 --- a/system/cron.php +++ b/system/cron.php @@ -18,9 +18,15 @@ ORM::configure('logging', true); include "autoload/Hookers.php"; +// notification message +if (file_exists("uploads/notifications.json")) { + $_notifmsg = json_decode(file_get_contents('uploads/notifications.json'), true); +} else { + $_notifmsg = json_decode(file_get_contents('uploads/notifications.default.json'), true); +} //register all plugin -foreach (glob("system/plugin/*.php") as $filename) { +foreach (glob("plugin/*.php") as $filename) { include $filename; } @@ -55,7 +61,7 @@ foreach ($result as $value) { } date_default_timezone_set($config['timezone']); -$textExpired = $config['user_notification_expired_text']; +$textExpired = $_notifmsg['expired']; $d = ORM::for_table('tbl_user_recharges')->where('status', 'on')->find_many(); @@ -76,11 +82,26 @@ foreach ($d as $ds) { $client = Mikrotik::getClient($m['ip_address'], $m['username'], $m['password']); Mikrotik::setHotspotLimitUptime($client, $c['username']); Mikrotik::removeHotspotActiveUser($client, $c['username']); - Message::sendExpiredNotification($c['phonenumber'], $c['fullname'], $u['namebp'], $textExpired, $config['user_notification_expired']); + Message::sendPackageNotification($c['phonenumber'], $c['fullname'], $u['namebp'], $textExpired, $config['user_notification_expired']); } //update database user dengan status off $u->status = 'off'; $u->save(); + + // autorenewal from deposit + if ($config['enable_balance'] == 'yes' && $c['auto_renewal']) { + $p = ORM::for_table('tbl_plans')->where('id', $u['plan_id'])->find_one(); + 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']); + } else { + Message::sendTelegram("FAILED RENEWAL #cron\n\n#u$c[username] #buy #Hotspot \n" . $p['name_plan'] . + "\nRouter: " . $router_name . + "\nPrice: " . $p['price']); + } + } + } } else echo " : ACTIVE \r\n"; } else { $date_now = strtotime(date("Y-m-d H:i:s")); @@ -96,11 +117,26 @@ foreach ($d as $ds) { $client = Mikrotik::getClient($m['ip_address'], $m['username'], $m['password']); Mikrotik::disablePpoeUser($client, $c['username']); Mikrotik::removePpoeActive($client, $c['username']); - Message::sendExpiredNotification($c['phonenumber'], $c['fullname'], $u['namebp'], $textExpired, $config['user_notification_expired']); + Message::sendPackageNotification($c['phonenumber'], $c['fullname'], $u['namebp'], $textExpired, $config['user_notification_expired']); } $u->status = 'off'; $u->save(); + + // autorenewal from deposit + if ($config['enable_balance'] == 'yes' && $c['auto_renewal']) { + $p = ORM::for_table('tbl_plans')->where('id', $u['plan_id'])->find_one(); + 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']); + } else { + Message::sendTelegram("FAILED RENEWAL #cron\n\n#u$c[username] #buy #Hotspot \n" . $p['name_plan'] . + "\nRouter: " . $router_name . + "\nPrice: " . $p['price']); + } + } + } } else echo " : ACTIVE \r\n"; } } diff --git a/system/cron_reminder.php b/system/cron_reminder.php new file mode 100644 index 00000000..8fd04c12 --- /dev/null +++ b/system/cron_reminder.php @@ -0,0 +1,90 @@ +find_many(); +foreach ($result as $value) { + $config[$value['setting']] = $value['value']; +} +date_default_timezone_set($config['timezone']); + + +$d = ORM::for_table('tbl_user_recharges')->where('status', 'on')->find_many(); + +run_hook('cronjob_reminder'); #HOOK + + + +$day7 = date('Y-m-d', strtotime("+7 day")); +$day3 = date('Y-m-d', strtotime("+3 day")); +$day1 = date('Y-m-d', strtotime("+1 day")); +print_r([$day1,$day3,$day7]); +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(); + $c = ORM::for_table('tbl_customers')->where('id', $ds['customer_id'])->find_one(); + if($ds['expiration']==$day7){ + echo Message::sendPackageNotification($c['phonenumber'], $c['fullname'], $u['namebp'], $_notifmsg['reminder_7_day'], $config['user_notification_reminder'])."\n"; + }else if($ds['expiration']==$day3){ + echo Message::sendPackageNotification($c['phonenumber'], $c['fullname'], $u['namebp'], $_notifmsg['reminder_3_day'], $config['user_notification_reminder'])."\n"; + }else if($ds['expiration']==$day1){ + echo Message::sendPackageNotification($c['phonenumber'], $c['fullname'], $u['namebp'], $_notifmsg['reminder_1_day'], $config['user_notification_reminder'])."\n"; + } + } +} diff --git a/system/lan/english/common.lan.php b/system/lan/english/common.lan.php index a72756a0..4e6ca82a 100644 --- a/system/lan/english/common.lan.php +++ b/system/lan/english/common.lan.php @@ -332,3 +332,36 @@ $_L['Your_account_not_connected_to_internet'] = 'Your account not connected to i $_L['Failed_to_create_transaction_'] = 'Failed to create transaction. '; $_L['Failed_to_check_status_transaction_'] = 'Failed to check status transaction. '; $_L['Disable_Voucher'] = 'Disable Voucher'; +$_L['Balance'] = 'Balance'; +$_L['Balance_System'] = 'Balance System'; +$_L['Enable_System'] = 'Enable System'; +$_L['Allow_Transfer'] = 'Allow Transfer'; +$_L['Telegram_Notification'] = 'Telegram Notification'; +$_L['SMS_OTP_Registration'] = 'SMS OTP Registration'; +$_L['Whatsapp_Notification'] = 'Whatsapp Notification'; +$_L['Tawkto_Chat_Widget'] = 'Tawk.to Chat Widget'; +$_L['Invoice'] = 'Invoice'; +$_L['Country_Code_Phone'] = 'Country Code Phone'; +$_L['Voucher_activation_menu_will_be_hidden'] = 'Voucher activation menu will be hidden'; +$_L['Customer_can_deposit_money_to_buy_voucher'] = 'Customer can deposit money to buy voucher'; +$_L['Allow_balance_transfer_between_customers'] = 'Allow balance transfer between customers'; +$_L['Reminder_Notification'] = 'Reminder Notification'; +$_L['Reminder_Notification_Message'] = 'Reminder Notification Message'; +$_L['Reminder_7_days'] = 'Reminder 7 days'; +$_L['Reminder_3_days'] = 'Reminder 3 days'; +$_L['Reminder_1_day'] = 'Reminder 1 day'; +$_L['PPPOE_Password'] = 'PPPOE Password'; +$_L['User_Cannot_change_this_only_admin_if_it_Empty_it_will_use_user_password'] = 'User Cannot change this, only admin. if it Empty it will use user password'; +$_L['Invoice_Balance_Message'] = 'Invoice Balance Message'; +$_L['Invoice_Notification_Payment'] = 'Invoice Notification Payment'; +$_L['Balance_Notification_Payment'] = 'Balance Notification Payment'; +$_L['Balance_Plans'] = 'Balance Plans'; +$_L['Buy_Balance'] = 'Buy Balance?'; +$_L['Price'] = 'Price'; +$_L['Validity'] = 'Validity'; +$_L['Disable_auto_renewal'] = 'Disable auto renewal?'; +$_L['Auto_Renewal_On'] = 'Auto Renewal On'; +$_L['Enable_auto_renewal'] = 'Enable auto renewal?'; +$_L['Auto_Renewal_Off'] = 'Auto Renewal Off'; +$_L['Refill_Balance'] = 'Refill Balance'; +$_L['Invoice_Footer'] = 'Invoice Footer'; diff --git a/system/lan/indonesia/common.lan.php b/system/lan/indonesia/common.lan.php index aeaafba2..8a197d45 100644 --- a/system/lan/indonesia/common.lan.php +++ b/system/lan/indonesia/common.lan.php @@ -325,3 +325,16 @@ $_L['Not_Online_Login_now'] = 'Internet mati, Nyalakan?'; $_L['You_are_Online_Logout'] = 'Internet hidup, Putuskan?'; $_L['Connect_to_Internet'] = 'Koneksikan internet?'; $_L['Your_account_not_connected_to_internet'] = 'Akun tidak terkoneksi dengan internet'; +$_L['Balance'] = 'Saldo'; +$_L['Balance_System'] = 'Sistem Saldo'; +$_L['Enable_System'] = 'Aktifkan Saldo'; +$_L['Allow_Transfer'] = 'Bolehkan Transfer'; +$_L['Telegram_Notification'] = 'Telegram Notification'; +$_L['SMS_OTP_Registration'] = 'SMS OTP Registration'; +$_L['Whatsapp_Notification'] = 'Whatsapp Notification'; +$_L['Tawkto_Chat_Widget'] = 'Tawk.to Chat Widget'; +$_L['Invoice'] = 'Invoice'; +$_L['Country_Code_Phone'] = 'Kode Negara Telepon'; +$_L['Voucher_activation_menu_will_be_hidden'] = 'Info Pembelian Voucher dan Redeem akan disembunyikan'; +$_L['Customer_can_deposit_money_to_buy_voucher'] = 'Pelanggan dapat topup saldo untuk langganan Internet'; +$_L['Allow_balance_transfer_between_customers'] = 'Bolehkan transfer saldo antar pelanggan'; diff --git a/system/lan/spanish/common.lan.php b/system/lan/spanish/common.lan.php index 661fb5dc..ec13dfd0 100644 --- a/system/lan/spanish/common.lan.php +++ b/system/lan/spanish/common.lan.php @@ -328,6 +328,16 @@ $_L['Not_Online_Login_now'] = 'Not Online, Login now?'; $_L['You_are_Online_Logout'] = 'You are Online, Logout?'; $_L['Connect_to_Internet'] = 'Connect to Internet?'; $_L['Your_account_not_connected_to_internet'] = 'Your account not connected to internet'; - - - +$_L['Balance'] = 'Balance'; +$_L['Balance_System'] = 'Balance System'; +$_L['Enable_System'] = 'Enable System'; +$_L['Allow_Transfer'] = 'Allow Transfer'; +$_L['Telegram_Notification'] = 'Telegram Notification'; +$_L['SMS_OTP_Registration'] = 'SMS OTP Registration'; +$_L['Whatsapp_Notification'] = 'Whatsapp Notification'; +$_L['Tawkto_Chat_Widget'] = 'Tawk.to Chat Widget'; +$_L['Invoice'] = 'Invoice'; +$_L['Country_Code_Phone'] = 'Country Code Phone'; +$_L['Voucher_activation_menu_will_be_hidden'] = 'Voucher activation menu will be hidden'; +$_L['Customer_can_deposit_money_to_buy_voucher'] = 'Customer can deposit money to buy voucher'; +$_L['Allow_balance_transfer_between_customers'] = 'Allow balance transfer between customers'; \ No newline at end of file diff --git a/system/lan/turkish/common.lan.php b/system/lan/turkish/common.lan.php index ef852b7c..c21d9b8b 100755 --- a/system/lan/turkish/common.lan.php +++ b/system/lan/turkish/common.lan.php @@ -304,3 +304,16 @@ $_L['Not_Online_Login_now'] = 'Not Online, Login now?'; $_L['You_are_Online_Logout'] = 'You are Online, Logout?'; $_L['Connect_to_Internet'] = 'Connect to Internet?'; $_L['Your_account_not_connected_to_internet'] = 'Your account not connected to internet'; +$_L['Balance'] = 'Balance'; +$_L['Balance_System'] = 'Balance System'; +$_L['Enable_System'] = 'Enable System'; +$_L['Allow_Transfer'] = 'Allow Transfer'; +$_L['Telegram_Notification'] = 'Telegram Notification'; +$_L['SMS_OTP_Registration'] = 'SMS OTP Registration'; +$_L['Whatsapp_Notification'] = 'Whatsapp Notification'; +$_L['Tawkto_Chat_Widget'] = 'Tawk.to Chat Widget'; +$_L['Invoice'] = 'Invoice'; +$_L['Country_Code_Phone'] = 'Country Code Phone'; +$_L['Voucher_activation_menu_will_be_hidden'] = 'Voucher activation menu will be hidden'; +$_L['Customer_can_deposit_money_to_buy_voucher'] = 'Customer can deposit money to buy voucher'; +$_L['Allow_balance_transfer_between_customers'] = 'Allow balance transfer between customers'; \ No newline at end of file diff --git a/system/updates.json b/system/updates.json new file mode 100644 index 00000000..7dce27f7 --- /dev/null +++ b/system/updates.json @@ -0,0 +1,14 @@ +{ + "2023.8.9": [ + "ALTER TABLE `tbl_customers` ADD `balance` decimal(15,2) NOT NULL DEFAULT 0.00 COMMENT 'For Money Deposit' AFTER `email`;", + "CREATE TABLE `tbl_customers_meta` (`id` int(11) NOT NULL, `customer_id` int(11) NOT NULL,`meta_key` varchar(64) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `meta_value` longtext COLLATE utf8mb4_general_ci) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;", + "ALTER TABLE `tbl_customers_meta` ADD PRIMARY KEY (`id`);", + "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_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`;" + ] +} \ No newline at end of file diff --git a/system/uploads/admin.png b/system/uploads/admin.default.png similarity index 100% rename from system/uploads/admin.png rename to system/uploads/admin.default.png diff --git a/system/uploads/logo.png b/system/uploads/logo.default.png similarity index 100% rename from system/uploads/logo.png rename to system/uploads/logo.default.png diff --git a/system/uploads/notifications.default.json b/system/uploads/notifications.default.json new file mode 100644 index 00000000..21e9c1cc --- /dev/null +++ b/system/uploads/notifications.default.json @@ -0,0 +1,8 @@ +{ + "expired": "Hello [[name]], your internet package [[package]] has been expired.", + "reminder_7_day": "Hello *[[name]]*, \r\nyour internet package *[[package]]* will be expired in 7 days.", + "reminder_3_day": "Hello *[[name]]*, \r\nyour internet package *[[package]]* will be expired in 3 days.", + "reminder_1_day": "Hello *[[name]]*,\r\n your internet package *[[package]]* will be expired tomorrow.", + "invoice_paid": "*[[company_name]]*\r\n[[address]]\r\n[[phone]]\r\n\r\n\r\nINVOICE: *[[invoice]]*\r\nDate : [[date]]\r\n[[payment_gateway]] [[payment_channel]]\r\n\r\n\r\nType : *[[type]]*\r\nPackage : *[[plan_name]]*\r\nPrice : *[[plan_price]]*\r\n\r\nUsername : *[[user_name]]*\r\nPassword : ***********\r\n\r\nExpired : *[[expired_date]]*\r\n\r\n====================\r\n[[footer]]", + "invoice_balance": "*[[company_name]]*\r\n[[address]]\r\n[[phone]]\r\n\r\n\r\nINVOICE: *[[invoice]]*\r\nDate : [[date]]\r\n[[payment_gateway]] [[payment_channel]]\r\n\r\n\r\nType : *[[type]]*\r\nPackage : *[[plan_name]]*\r\nPrice : *[[plan_price]]*\r\n\r\n====================\r\n[[footer]]" +} diff --git a/system/uploads/user.jpg b/system/uploads/user.default.jpg similarity index 100% rename from system/uploads/user.jpg rename to system/uploads/user.default.jpg diff --git a/ui/ui/app-localisation.tpl b/ui/ui/app-localisation.tpl index ebbc960a..a5ca2ba5 100644 --- a/ui/ui/app-localisation.tpl +++ b/ui/ui/app-localisation.tpl @@ -1,80 +1,107 @@ {include file="sections/header.tpl"} -
-
-
-
{$_L['Localisation']}
-
+
+
+
+
{$_L['Localisation']}
+
-
+
- -
- -
-
-
- -
- -
-
-
- -
- + {foreach $tlist as $value => $label} + {/foreach} - -
- + +
- -
- -
+ +
+ +
- -
- -
+ +
+ +
+
- -
- - {$_L['currency_help']} -
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ + {$_L['currency_help']} +
+
+
+ +
+
+ + + +
+
+
+
+
+ +
-
-
- -
-
- -
-
-
-
-{include file="sections/footer.tpl"} +
+
+
+ + +{include file="sections/footer.tpl"} \ No newline at end of file diff --git a/ui/ui/app-notifications.tpl b/ui/ui/app-notifications.tpl new file mode 100644 index 00000000..6446adf1 --- /dev/null +++ b/ui/ui/app-notifications.tpl @@ -0,0 +1,127 @@ +{include file="sections/header.tpl"} + + +
+
+
+
+
+ +
+ {Lang::T('User Notification')} +
+
+
+ +
+ +
+

+ {Lang::T('[[name]] will be replaced with Customer Name. [[package]] will be replaced with Package name.')} +

+
+
+
+
+ +
+ +
+

+ {Lang::T('[[name]] will be replaced with Customer Name. [[package]] will be replaced with Package name.')} +

+
+
+
+
+ +
+ +
+

+ {Lang::T('[[name]] will be replaced with Customer Name. [[package]] will be replaced with Package name.')} +

+
+
+
+
+ +
+ +
+

+ {Lang::T('[[name]] will be replaced with Customer Name. [[package]] will be replaced with Package name.')} +

+
+
+
+
+ +
+ +
+

+ [[company_name]] Your Company Name at Settings.
+ [[address]] Your Company Address at Settings.
+ [[phone]] Your Company Phone at Settings.
+ [[invoice]] invoice number.
+ [[date]] Date invoice created.
+ [[payment_gateway]] Payment gateway user paid from.
+ [[payment_channel]] Payment channel user paid from.
+ [[type]] is Hotspot/PPPOE.
+ [[plan_name]] Internet Package.
+ [[plan_price]] Internet Package Prices.
+ [[user_name]] Username internet.
+ [[user_password]] User password.
+ [[expired_date]] Expired datetime.
+ [[footer]] Invoice Footer. +

+
+
+
+
+ +
+ +
+

+ [[company_name]] Your Company Name at Settings.
+ [[address]] Your Company Address at Settings.
+ [[phone]] Your Company Phone at Settings.
+ [[invoice]] invoice number.
+ [[date]] Date invoice created.
+ [[payment_gateway]] Payment gateway user paid from.
+ [[payment_channel]] Payment channel user paid from.
+ [[type]] is Hotspot/PPPOE.
+ [[plan_name]] Internet Package.
+ [[plan_price]] Internet Package Prices.
+ [[user_name]] Username internet.
+ [[user_password]] User password.
+ [[trx_date]] Transaction datetime.
+ [[footer]] Invoice Footer. +

+
+
+
+ +
+
+ +
+
+
+
+ +{include file="sections/footer.tpl"} \ No newline at end of file diff --git a/ui/ui/app-settings.tpl b/ui/ui/app-settings.tpl index f8ffb419..02e44903 100644 --- a/ui/ui/app-settings.tpl +++ b/ui/ui/app-settings.tpl @@ -4,31 +4,38 @@
-
{$_L['General_Settings']}
+
+
+ +
+ {$_L['General_Settings']} +
- {$_L['App_Name_Help_Text']} +
+ {$_L['App_Name_Help_Text']}
- {Lang::T('Will show below user pages')}
+ {Lang::T('Will show below user pages')}
- {$_L['You_can_use_html_tag']}
+ {$_L['You_can_use_html_tag']}
@@ -43,31 +50,71 @@ -

Still on Testing.

-

Changing from Radius will not add existing user to Mikrotik Hotspot. -

-

With Radius user can use Hotspot or PPOE.

+

Still on Testing.
+ Changing from Radius will not add existing user to Mikrotik Hotspot.
+ With Radius user can use Hotspot or PPOE.

-

edit at config.php

+

edit at config.php

-

Voucher activation menu will be hidden

+

{Lang::T('Voucher activation menu will be hidden')}

-
Telegram Notification
+
+
+ +
+ {Lang::T('Balance System')} +
+
+
+ +
+ +
+

{Lang::T('Customer can deposit money to buy voucher')}

+
+
+ +
+ +
+

{Lang::T('Allow balance transfer between customers')}

+
+
+
+
+ +
+ {Lang::T('Telegram Notification')} +
@@ -83,85 +130,137 @@ value="{$_c['telegram_target_id']}" placeholder="12345678">
- You will get Payment and Error notification + You will get Payment and Error + notification +
+
+
+ +
+ {Lang::T('SMS OTP Registration')}
-
SMS OTP Registration
-

Must include [text] & [number], it will be replaced. -

+

Must include [text] & [number], it will be + replaced. +

- You can use WhatsApp in here too. Free Server + You can use WhatsApp in here too. Free Server +
+
+
+ +
+ {Lang::T('Whatsapp Notification')}
-
Whatsapp Notification
-

Must include [text] & [number], it will be replaced. -

+

Must include [text] & [number], it will be + replaced. +

+ You can use WhatsApp in here too. Free Server +
+
+
+ +
+ {Lang::T('User Notification')}
-
{Lang::T('User Notification')}
- - - + + -

{Lang::T('User will get notification when package expired')}

-
-
-
- -
- -

{Lang::T('[[name]] will be replaced with Customer Name. [[package]] will be replaced with Package name.')}

+

{Lang::T('User will get notification when package expired')}

- - - + + + +
+

+ {Lang::T('User will get invoice notification when buy package or package refilled')}

+
+
+ +
+ -

{Lang::T('User will get invoice notification when buy package or package refilled')}

-
Tawk.to Chat Widget
+
+
+ +
+ {Lang::T('Tawk.to Chat Widget')} +
-

From Direct Chat Link.

-
/ip hotspot walled-garden
-add dst-host=tawk.to
-add dst-host=*.tawk.to
+

From Direct Chat Link.

+ +

/ip hotspot walled-garden
+ add dst-host=tawk.to
+ add dst-host=*.tawk.to

-
Invoice
+
+
+ +
+ {Lang::T('Invoice')} +
+
- +
- + {$_L['You_can_use_html_tag']}
@@ -173,11 +272,11 @@ add dst-host=*.tawk.to
-
+
/ip hotspot walled-garden
-            add dst-host={$_domain}
-            add dst-host=*.{$_domain}
+add dst-host={$_domain} +add dst-host=*.{$_domain} diff --git a/ui/ui/balance-add.tpl b/ui/ui/balance-add.tpl new file mode 100644 index 00000000..8fa3c734 --- /dev/null +++ b/ui/ui/balance-add.tpl @@ -0,0 +1,48 @@ +{include file="sections/header.tpl"} + +
+
+
+
{$_L['Add_Plan']}
+
+
+
+ +
+ + +
+
+
+ +
+ +
+
+
+ +
+
+ {$_c['currency_code']} + +
+
+
+ +
+
+ + Or {$_L['Cancel']} +
+
+ +
+
+
+
+ +{include file="sections/footer.tpl"} diff --git a/ui/ui/balance-edit.tpl b/ui/ui/balance-edit.tpl new file mode 100644 index 00000000..16922bfb --- /dev/null +++ b/ui/ui/balance-edit.tpl @@ -0,0 +1,49 @@ +{include file="sections/header.tpl"} + +
+
+
+
{$_L['Edit_Plan']}
+
+
+ +
+ +
+ + +
+
+
+ +
+ +
+
+
+ +
+
+ {$_c['currency_code']} + +
+
+
+ +
+
+ + Or {$_L['Cancel']} +
+
+ +
+
+
+
+ +{include file="sections/footer.tpl"} diff --git a/ui/ui/balance.tpl b/ui/ui/balance.tpl new file mode 100644 index 00000000..17ace703 --- /dev/null +++ b/ui/ui/balance.tpl @@ -0,0 +1,56 @@ +{include file="sections/header.tpl"} + +
+
+
+
{Lang::T('Balance Plans')}
+
+
+
+ +
+
+ +
+ +
+ +
+
+ +
+   +
+
+
+ + + + + + + + + {foreach $d as $ds} + + + + + + {/foreach} + +
{$_L['Plan_Name']}{$_L['Plan_Price']}{$_L['Manage']}
{$ds['name_plan']}{Lang::moneyFormat($ds['price'])} + {$_L['Edit']} + {$_L['Delete']} +
+ + {$paginator['contents']} + + + + + + +{include file="sections/footer.tpl"} diff --git a/ui/ui/community.tpl b/ui/ui/community.tpl index d4e730fe..9d673bf1 100644 --- a/ui/ui/community.tpl +++ b/ui/ui/community.tpl @@ -10,9 +10,9 @@ @@ -28,7 +28,7 @@ @@ -63,9 +63,9 @@ @@ -101,7 +101,7 @@ @@ -114,7 +114,7 @@
$50 Paid Support
donation confirmation?
Or ask any Donation Alternative
@@ -126,7 +126,7 @@
@@ -142,12 +142,24 @@ + + diff --git a/ui/ui/customers-add.tpl b/ui/ui/customers-add.tpl index 0d4ecb9d..62baf313 100644 --- a/ui/ui/customers-add.tpl +++ b/ui/ui/customers-add.tpl @@ -9,9 +9,13 @@
-
- -
+
+
+ + + +
+
@@ -20,17 +24,34 @@
- +
- +
+
+ +
+
+ + + +
+
+
- +
- +
+
+ +
+ + {Lang::T('User Cannot change this, only admin. if it Empty it will use user password')} +
+
diff --git a/ui/ui/customers-edit.tpl b/ui/ui/customers-edit.tpl index 8677665b..4886620e 100644 --- a/ui/ui/customers-edit.tpl +++ b/ui/ui/customers-edit.tpl @@ -11,7 +11,11 @@
- +
+ + + +
@@ -20,17 +24,34 @@
+
+ +
+ +
+
+
+ +
+
+ + + +
+
+
- + {$_L['password_change_help']}
- +
- + + {Lang::T('User Cannot change this, only admin. if it Empty it will use user password')}
@@ -39,12 +60,6 @@
-
- -
- -
-
diff --git a/ui/ui/customers.tpl b/ui/ui/customers.tpl index a7924686..495e0e8e 100644 --- a/ui/ui/customers.tpl +++ b/ui/ui/customers.tpl @@ -36,6 +36,7 @@ {$_L['Username']} {$_L['Full_Name']} + {Lang::T('Balance')} {$_L['Phone_Number']} {$_L['Email']} {$_L['Created_On']} @@ -48,6 +49,7 @@ {$ds['username']} {$ds['fullname']} + {Lang::moneyFormat($ds['balance'])} {$ds['phonenumber']} {$ds['email']} {$ds['created_at']} diff --git a/ui/ui/deposit.tpl b/ui/ui/deposit.tpl new file mode 100644 index 00000000..02e5810e --- /dev/null +++ b/ui/ui/deposit.tpl @@ -0,0 +1,47 @@ +{include file="sections/header.tpl"} + +
+
+
+
{Lang::T('Refill Balance')}
+
+ +
+ +
+ +
+
+
+ +
+ +
+
+ +
+
+ + Or {$_L['Cancel']} +
+
+ +
+
+
+
+ +{include file="sections/footer.tpl"} \ No newline at end of file diff --git a/ui/ui/hotspot-add.tpl b/ui/ui/hotspot-add.tpl index 4477bcfc..06b361e2 100644 --- a/ui/ui/hotspot-add.tpl +++ b/ui/ui/hotspot-add.tpl @@ -21,7 +21,6 @@
-

{Lang::T('Cannot be change after saved')}

@@ -72,7 +71,7 @@
- {foreach $d as $ds} @@ -83,7 +82,10 @@
- +
+ {$_c['currency_code']} + +
@@ -110,7 +112,7 @@
- {foreach $r as $rs} {/foreach} diff --git a/ui/ui/hotspot-edit.tpl b/ui/ui/hotspot-edit.tpl index b6387279..3dab50b6 100644 --- a/ui/ui/hotspot-edit.tpl +++ b/ui/ui/hotspot-edit.tpl @@ -21,7 +21,7 @@
- +
@@ -72,7 +72,7 @@
- {foreach $b as $bs} {/foreach} @@ -82,7 +82,10 @@
- +
+ {$_c['currency_code']} + +
diff --git a/ui/ui/hotspot.tpl b/ui/ui/hotspot.tpl index 371f0dcb..1d26c376 100644 --- a/ui/ui/hotspot.tpl +++ b/ui/ui/hotspot.tpl @@ -44,14 +44,14 @@ {$ds['name_plan']} {$ds['typebp']} {$ds['name_bw']} - {$ds['price']} + {Lang::moneyFormat($ds['price'])} {$ds['time_limit']} {$ds['time_unit']} {$ds['data_limit']} {$ds['data_unit']} {$ds['validity']} {$ds['validity_unit']} {$ds['routers']} {$_L['Edit']} - {$_L['Delete']} + {$_L['Delete']} {/foreach} diff --git a/ui/ui/invoice-print.tpl b/ui/ui/invoice-print.tpl index 2036c576..8da794d5 100644 --- a/ui/ui/invoice-print.tpl +++ b/ui/ui/invoice-print.tpl @@ -1,5 +1,6 @@ + {$_title} @@ -7,52 +8,56 @@ - + -
-
- - - - -
-
-
- {$_c['CompanyName']}
- {$_c['address']}
- {$_c['phone']}
-
- ============================================
- INVOICE: {$d['invoice']} - {$_L['Date']} : {$date}
- {$_L['Sales']} : {$_admin['fullname']}
- ============================================
- {$_L['Type']} : {$d['type']}
- {$_L['Plan_Name']} : {$d['plan_name']}
- {$_L['Plan_Price']} : {$_c['currency_code']} {number_format($d['price'],2,$_c['dec_point'],$_c['thousands_sep'])}
-
- {$_L['Username']} : {$d['username']}
- {$_L['Password']} : **********
-
- {$_L['Created_On']} : {date($_c['date_format'], strtotime($d['recharged_on']))}
- {$_L['Expires_On']} : {date($_c['date_format'], strtotime($d['expiration']))} {$d['time']}
- ============================================
-
{$_c['note']}
-
-
+
+
+ + + + +
+
+
+ {$_c['CompanyName']}
+ {$_c['address']}
+ {$_c['phone']}
+
+ ============================================
+ INVOICE: {$d['invoice']} - {$_L['Date']} : {$date}
+ {$_L['Sales']} : {$_admin['fullname']}
+ ============================================
+ {$_L['Type']} : {$d['type']}
+ {$_L['Plan_Name']} : {$d['plan_name']}
+ {$_L['Plan_Price']} : {Lang::moneyFormat($in['price'])}
+
+ {$_L['Username']} : {$d['username']}
+ {$_L['Password']} : **********
+ {if $in['type'] != 'Balance'} +
+ {$_L['Created_On']} : {date($_c['date_format'], strtotime($d['recharged_on']))}
+ {$_L['Expires_On']} : {date($_c['date_format'], strtotime($d['expiration']))} + {$d['time']}
+ {/if} + ============================================
+
{$_c['note']}
+
+
+
-
- - -{if isset($xfooter)} - {$xfooter} -{/if} + + + {if isset($xfooter)} + {$xfooter} + {/if} - + + \ No newline at end of file diff --git a/ui/ui/invoice.tpl b/ui/ui/invoice.tpl index bcef36bf..5f4a9d3f 100644 --- a/ui/ui/invoice.tpl +++ b/ui/ui/invoice.tpl @@ -1,48 +1,57 @@ {include file="sections/header.tpl"}
-
-
-
PRINT INVOICE
-
-
-
-
- {$_c['CompanyName']}
- {$_c['address']}
- {$_c['phone']}
-
- ====================================================
- INVOICE: {$in['invoice']} - {$_L['Date']} : {$date}
- {$_L['Sales']} : {$_admin['fullname']}
- ====================================================
- {$_L['Type']} : {$in['type']}
- {$_L['Plan_Name']} : {$in['plan_name']}
- {$_L['Plan_Price']} : {$_c['currency_code']} {number_format($in['price'],2,$_c['dec_point'],$_c['thousands_sep'])}
-
- {$_L['Username']} : {$in['username']}
- {$_L['Password']} : **********
-
- {$_L['Created_On']} : {date($_c['date_format'], strtotime($in['recharged_on']))}
- {$_L['Expires_On']} : {date($_c['date_format'], strtotime($in['expiration']))} {$in['time']}
- =====================================================
-
{$_c['note']}
-
-
-
- - - {$_L['Finish']} -
+
+
+
PRINT INVOICE
+
+
+
+
+ {$_c['CompanyName']}
+ {$_c['address']}
+ {$_c['phone']}
+
+ ====================================================
+ INVOICE: {$in['invoice']} - {$_L['Date']} : {$date}
+ {$_L['Sales']} : {$_admin['fullname']}
+ ====================================================
+ {$_L['Type']} : {$in['type']}
+ {$_L['Plan_Name']} : {$in['plan_name']}
+ {$_L['Plan_Price']} : {Lang::moneyFormat($in['price'])}
+
+ {$_L['Username']} : {$in['username']}
+ {$_L['Password']} : **********
+ {if $in['type'] != 'Balance'} +
+ {$_L['Created_On']} : {date($_c['date_format'], strtotime($in['recharged_on']))}
+ {$_L['Expires_On']} : {date($_c['date_format'], strtotime($in['expiration']))} + {$in['time']}
+ {/if} + =====================================================
+
{$_c['note']}
+
+
+
+ + + {$_L['Finish']} +
-
-
-
+
+
+
-{include file="sections/footer.tpl"} +{include file="sections/footer.tpl"} \ No newline at end of file diff --git a/ui/ui/pool-add.tpl b/ui/ui/pool-add.tpl index 576f26ba..d0306f92 100644 --- a/ui/ui/pool-add.tpl +++ b/ui/ui/pool-add.tpl @@ -5,8 +5,8 @@
{$_L['Add_Pool']}
- -
+ +
@@ -18,11 +18,11 @@
-
+
- {foreach $r as $rs} {/foreach} @@ -36,7 +36,7 @@
- +
diff --git a/ui/ui/pool-edit.tpl b/ui/ui/pool-edit.tpl index 33112828..54b400cc 100644 --- a/ui/ui/pool-edit.tpl +++ b/ui/ui/pool-edit.tpl @@ -5,9 +5,9 @@
{$_L['Edit_Pool']}
- -
- + + +
@@ -24,10 +24,9 @@
-
- +
@@ -35,7 +34,7 @@
- +
diff --git a/ui/ui/pool.tpl b/ui/ui/pool.tpl index 6bf39add..d49a78f1 100644 --- a/ui/ui/pool.tpl +++ b/ui/ui/pool.tpl @@ -47,7 +47,7 @@ {$_L['Edit']} - {$_L['Delete']} diff --git a/ui/ui/pppoe-add.tpl b/ui/ui/pppoe-add.tpl index fbe86a6c..bd766b57 100644 --- a/ui/ui/pppoe-add.tpl +++ b/ui/ui/pppoe-add.tpl @@ -21,13 +21,12 @@
-

{Lang::T('Cannot be change after saved')}

- {foreach $d as $ds} @@ -38,7 +37,10 @@
- +
+ {$_c['currency_code']} + +
@@ -58,7 +60,7 @@
- {foreach $r as $rs} @@ -70,7 +72,7 @@
-
diff --git a/ui/ui/pppoe-edit.tpl b/ui/ui/pppoe-edit.tpl index b710db45..582645fc 100644 --- a/ui/ui/pppoe-edit.tpl +++ b/ui/ui/pppoe-edit.tpl @@ -21,13 +21,13 @@
- +
- {foreach $b as $bs} {/foreach} @@ -37,7 +37,10 @@
- +
+ {$_c['currency_code']} + +
@@ -57,7 +60,7 @@
- {foreach $p as $ps} {/foreach} diff --git a/ui/ui/pppoe.tpl b/ui/ui/pppoe.tpl index 090c9a76..6d14b1c7 100644 --- a/ui/ui/pppoe.tpl +++ b/ui/ui/pppoe.tpl @@ -41,13 +41,13 @@ {$ds['name_plan']} {$ds['name_bw']} - {$ds['price']} + {Lang::moneyFormat($ds['price'])} {$ds['validity']} {$ds['validity_unit']} {$ds['pool']} {$ds['routers']} {$_L['Edit']} - {$_L['Delete']} + {$_L['Delete']} {/foreach} diff --git a/ui/ui/prepaid-edit.tpl b/ui/ui/prepaid-edit.tpl index 654ef453..03abd043 100644 --- a/ui/ui/prepaid-edit.tpl +++ b/ui/ui/prepaid-edit.tpl @@ -17,7 +17,7 @@
- {foreach $p as $ps} {/foreach} diff --git a/ui/ui/print-by-date.tpl b/ui/ui/print-by-date.tpl index 65125971..fd8f3d9a 100644 --- a/ui/ui/print-by-date.tpl +++ b/ui/ui/print-by-date.tpl @@ -38,7 +38,7 @@ {$ds['username']} {$ds['plan_name']} {$ds['type']} - {$_c['currency_code']} {number_format($ds['price'],2,$_c['dec_point'],$_c['thousands_sep'])} + {Lang::moneyFormat($ds['price'])} {date($_c['date_format'], strtotime($ds['recharged_on']))} {date($_c['date_format'], strtotime($ds['expiration']))} {$ds['time']} {$ds['method']} diff --git a/ui/ui/print-by-period.tpl b/ui/ui/print-by-period.tpl index f4663348..95f47a51 100644 --- a/ui/ui/print-by-period.tpl +++ b/ui/ui/print-by-period.tpl @@ -38,7 +38,7 @@ {$ds['username']} {$ds['plan_name']} {$ds['type']} - {$_c['currency_code']} {number_format($ds['price'],2,$_c['dec_point'],$_c['thousands_sep'])} + {Lang::moneyFormat($ds['price'])} {date($_c['date_format'], strtotime($ds['recharged_on']))} {date($_c['date_format'], strtotime($ds['expiration']))} {$ds['time']} {$ds['method']} @@ -49,7 +49,7 @@

{$_L['Total_Income']}:

-

{$_c['currency_code']} {number_format($dr,2,$_c['dec_point'],$_c['thousands_sep'])}

+

{Lang::moneyFormat($dr)}

diff --git a/ui/ui/print-voucher.tpl b/ui/ui/print-voucher.tpl index 30b6e267..ce38327b 100644 --- a/ui/ui/print-voucher.tpl +++ b/ui/ui/print-voucher.tpl @@ -86,7 +86,7 @@ - {$_c['currency_code']} {number_format($vs['price'],2,$_c['dec_point'],$_c['thousands_sep'])} + {Lang::moneyFormat($vs['price'])} {$_L['Code_Voucher']} diff --git a/ui/ui/recharge-user.tpl b/ui/ui/recharge-user.tpl index 3a3c3018..5b87ee74 100644 --- a/ui/ui/recharge-user.tpl +++ b/ui/ui/recharge-user.tpl @@ -9,7 +9,7 @@
- {foreach $c as $cs} {if $id eq $cs['id']} @@ -31,7 +31,7 @@
-
@@ -40,7 +40,7 @@
-
diff --git a/ui/ui/recharge.tpl b/ui/ui/recharge.tpl index a7625cd7..596b57dc 100644 --- a/ui/ui/recharge.tpl +++ b/ui/ui/recharge.tpl @@ -9,7 +9,7 @@
- {foreach $c as $cs} @@ -27,7 +27,7 @@
-
@@ -36,7 +36,7 @@
-
diff --git a/ui/ui/refill.tpl b/ui/ui/refill.tpl index aab30e72..4377d6ac 100644 --- a/ui/ui/refill.tpl +++ b/ui/ui/refill.tpl @@ -3,13 +3,13 @@
-
{$_L['Recharge_Account']}
+
{$_L['Refill_Account']}
- + +
+ {if $_c['country_code_phone']!= ''} + + + {else} + + {/if} + +
- +
- +
- +
- - + +
@@ -77,12 +86,13 @@
- +
- - + +
diff --git a/ui/ui/register-rotp.tpl b/ui/ui/register-rotp.tpl index 87b80247..a1e2b402 100644 --- a/ui/ui/register-rotp.tpl +++ b/ui/ui/register-rotp.tpl @@ -51,15 +51,23 @@
- +
1. {$_L['Register_Member']}
- +
+ {if $_c['country_code_phone']!= ''} + + + {else} + + {/if} + +
diff --git a/ui/ui/register.tpl b/ui/ui/register.tpl index 9b071830..c0777380 100644 --- a/ui/ui/register.tpl +++ b/ui/ui/register.tpl @@ -45,8 +45,11 @@
- +
+ + + +
diff --git a/ui/ui/reports-daily.tpl b/ui/ui/reports-daily.tpl index 5723baf5..116a342c 100644 --- a/ui/ui/reports-daily.tpl +++ b/ui/ui/reports-daily.tpl @@ -41,8 +41,7 @@ {$ds['username']} {$ds['type']} {$ds['plan_name']} - {$_c['currency_code']} - {number_format($ds['price'],2,$_c['dec_point'],$_c['thousands_sep'])} + {Lang::moneyFormat($ds['price'])} {date($_c['date_format'], strtotime($ds['recharged_on']))} {date($_c['date_format'], strtotime($ds['expiration']))} {$ds['time']} {$ds['method']} @@ -56,7 +55,7 @@

{$_L['Total_Income']}:

-

{$_c['currency_code']} {number_format($dr,2,$_c['dec_point'],$_c['thousands_sep'])}

+

{Lang::moneyFormat($dr)}

{$_L['All_Transactions_at_Date']}: {date($_c['date_format'], strtotime($mdate))} {$mtime}

diff --git a/ui/ui/reports-period-view.tpl b/ui/ui/reports-period-view.tpl index e7ac7b3c..1082f1b5 100644 --- a/ui/ui/reports-period-view.tpl +++ b/ui/ui/reports-period-view.tpl @@ -52,8 +52,7 @@ {$ds['username']} {$ds['type']} {$ds['plan_name']} - {$_c['currency_code']} - {number_format($ds['price'],0,$_c['dec_point'],$_c['thousands_sep'])} + {Lang::moneyFormat($ds['price'])} {date($_c['date_format'], strtotime($ds['recharged_on']))} {date($_c['date_format'], strtotime($ds['expiration']))} {$ds['time']} {$ds['method']} @@ -65,7 +64,7 @@

{$_L['Total_Income']}:

-

{$_c['currency_code']} {number_format($dr,2,$_c['dec_point'],$_c['thousands_sep'])}

+

{Lang::moneyFormat($dr)}

{$stype} [{date( $_c['date_format'], strtotime($fdate))} - {date( $_c['date_format'], strtotime($tdate))}]

diff --git a/ui/ui/routers.tpl b/ui/ui/routers.tpl index 5d9fa3d5..e4857e62 100644 --- a/ui/ui/routers.tpl +++ b/ui/ui/routers.tpl @@ -50,7 +50,7 @@ {$_L['Edit']} - {$_L['Delete']} + {$_L['Delete']} {/foreach} diff --git a/ui/ui/scripts/select2.min.js b/ui/ui/scripts/select2.min.js new file mode 100644 index 00000000..49a988c7 --- /dev/null +++ b/ui/ui/scripts/select2.min.js @@ -0,0 +1,2 @@ +/*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):jQuery)}(function(a){var b=function(){if(a&&a.fn&&a.fn.select2&&a.fn.select2.amd)var b=a.fn.select2.amd;var b;return function(){if(!b||!b.requirejs){b?c=b:b={};var a,c,d;!function(b){function e(a,b){return u.call(a,b)}function f(a,b){var c,d,e,f,g,h,i,j,k,l,m,n=b&&b.split("/"),o=s.map,p=o&&o["*"]||{};if(a&&"."===a.charAt(0))if(b){for(n=n.slice(0,n.length-1),a=a.split("/"),g=a.length-1,s.nodeIdCompat&&w.test(a[g])&&(a[g]=a[g].replace(w,"")),a=n.concat(a),k=0;k0&&(a.splice(k-1,2),k-=2)}a=a.join("/")}else 0===a.indexOf("./")&&(a=a.substring(2));if((n||p)&&o){for(c=a.split("/"),k=c.length;k>0;k-=1){if(d=c.slice(0,k).join("/"),n)for(l=n.length;l>0;l-=1)if(e=o[n.slice(0,l).join("/")],e&&(e=e[d])){f=e,h=k;break}if(f)break;!i&&p&&p[d]&&(i=p[d],j=k)}!f&&i&&(f=i,h=j),f&&(c.splice(0,h,f),a=c.join("/"))}return a}function g(a,c){return function(){return n.apply(b,v.call(arguments,0).concat([a,c]))}}function h(a){return function(b){return f(b,a)}}function i(a){return function(b){q[a]=b}}function j(a){if(e(r,a)){var c=r[a];delete r[a],t[a]=!0,m.apply(b,c)}if(!e(q,a)&&!e(t,a))throw new Error("No "+a);return q[a]}function k(a){var b,c=a?a.indexOf("!"):-1;return c>-1&&(b=a.substring(0,c),a=a.substring(c+1,a.length)),[b,a]}function l(a){return function(){return s&&s.config&&s.config[a]||{}}}var m,n,o,p,q={},r={},s={},t={},u=Object.prototype.hasOwnProperty,v=[].slice,w=/\.js$/;o=function(a,b){var c,d=k(a),e=d[0];return a=d[1],e&&(e=f(e,b),c=j(e)),e?a=c&&c.normalize?c.normalize(a,h(b)):f(a,b):(a=f(a,b),d=k(a),e=d[0],a=d[1],e&&(c=j(e))),{f:e?e+"!"+a:a,n:a,pr:e,p:c}},p={require:function(a){return g(a)},exports:function(a){var b=q[a];return"undefined"!=typeof b?b:q[a]={}},module:function(a){return{id:a,uri:"",exports:q[a],config:l(a)}}},m=function(a,c,d,f){var h,k,l,m,n,s,u=[],v=typeof d;if(f=f||a,"undefined"===v||"function"===v){for(c=!c.length&&d.length?["require","exports","module"]:c,n=0;n0&&(b.call(arguments,a.prototype.constructor),e=c.prototype.constructor),e.apply(this,arguments)}function e(){this.constructor=d}var f=b(c),g=b(a);c.displayName=a.displayName,d.prototype=new e;for(var h=0;hc;c++)a[c].apply(this,b)},c.Observable=d,c.generateChars=function(a){for(var b="",c=0;a>c;c++){var d=Math.floor(36*Math.random());b+=d.toString(36)}return b},c.bind=function(a,b){return function(){a.apply(b,arguments)}},c._convertData=function(a){for(var b in a){var c=b.split("-"),d=a;if(1!==c.length){for(var e=0;e":">",'"':""","'":"'","/":"/"};return"string"!=typeof a?a:String(a).replace(/[&<>"'\/\\]/g,function(a){return b[a]})},c.appendMany=function(b,c){if("1.7"===a.fn.jquery.substr(0,3)){var d=a();a.map(c,function(a){d=d.add(a)}),c=d}b.append(c)},c}),b.define("select2/results",["jquery","./utils"],function(a,b){function c(a,b,d){this.$element=a,this.data=d,this.options=b,c.__super__.constructor.call(this)}return b.Extend(c,b.Observable),c.prototype.render=function(){var b=a('
    ');return this.options.get("multiple")&&b.attr("aria-multiselectable","true"),this.$results=b,b},c.prototype.clear=function(){this.$results.empty()},c.prototype.displayMessage=function(b){var c=this.options.get("escapeMarkup");this.clear(),this.hideLoading();var d=a('
  • '),e=this.options.get("translations").get(b.message);d.append(c(e(b.args))),this.$results.append(d)},c.prototype.append=function(a){this.hideLoading();var b=[];if(null==a.results||0===a.results.length)return void(0===this.$results.children().length&&this.trigger("results:message",{message:"noResults"}));a.results=this.sort(a.results);for(var c=0;c-1?b.attr("aria-selected","true"):b.attr("aria-selected","false")});var f=e.filter("[aria-selected=true]");f.length>0?f.first().trigger("mouseenter"):e.first().trigger("mouseenter")})},c.prototype.showLoading=function(a){this.hideLoading();var b=this.options.get("translations").get("searching"),c={disabled:!0,loading:!0,text:b(a)},d=this.option(c);d.className+=" loading-results",this.$results.prepend(d)},c.prototype.hideLoading=function(){this.$results.find(".loading-results").remove()},c.prototype.option=function(b){var c=document.createElement("li");c.className="select2-results__option";var d={role:"treeitem","aria-selected":"false"};b.disabled&&(delete d["aria-selected"],d["aria-disabled"]="true"),null==b.id&&delete d["aria-selected"],null!=b._resultId&&(c.id=b._resultId),b.title&&(c.title=b.title),b.children&&(d.role="group",d["aria-label"]=b.text,delete d["aria-selected"]);for(var e in d){var f=d[e];c.setAttribute(e,f)}if(b.children){var g=a(c),h=document.createElement("strong");h.className="select2-results__group";{a(h)}this.template(b,h);for(var i=[],j=0;j",{"class":"select2-results__options select2-results__options--nested"});m.append(i),g.append(h),g.append(m)}else this.template(b,c);return a.data(c,"data",b),c},c.prototype.bind=function(b){var c=this,d=b.id+"-results";this.$results.attr("id",d),b.on("results:all",function(a){c.clear(),c.append(a.data),b.isOpen()&&c.setClasses()}),b.on("results:append",function(a){c.append(a.data),b.isOpen()&&c.setClasses()}),b.on("query",function(a){c.showLoading(a)}),b.on("select",function(){b.isOpen()&&c.setClasses()}),b.on("unselect",function(){b.isOpen()&&c.setClasses()}),b.on("open",function(){c.$results.attr("aria-expanded","true"),c.$results.attr("aria-hidden","false"),c.setClasses(),c.ensureHighlightVisible()}),b.on("close",function(){c.$results.attr("aria-expanded","false"),c.$results.attr("aria-hidden","true"),c.$results.removeAttr("aria-activedescendant")}),b.on("results:toggle",function(){var a=c.getHighlightedResults();0!==a.length&&a.trigger("mouseup")}),b.on("results:select",function(){var a=c.getHighlightedResults();if(0!==a.length){var b=a.data("data");"true"==a.attr("aria-selected")?c.trigger("close"):c.trigger("select",{data:b})}}),b.on("results:previous",function(){var a=c.getHighlightedResults(),b=c.$results.find("[aria-selected]"),d=b.index(a);if(0!==d){var e=d-1;0===a.length&&(e=0);var f=b.eq(e);f.trigger("mouseenter");var g=c.$results.offset().top,h=f.offset().top,i=c.$results.scrollTop()+(h-g);0===e?c.$results.scrollTop(0):0>h-g&&c.$results.scrollTop(i)}}),b.on("results:next",function(){var a=c.getHighlightedResults(),b=c.$results.find("[aria-selected]"),d=b.index(a),e=d+1;if(!(e>=b.length)){var f=b.eq(e);f.trigger("mouseenter");var g=c.$results.offset().top+c.$results.outerHeight(!1),h=f.offset().top+f.outerHeight(!1),i=c.$results.scrollTop()+h-g;0===e?c.$results.scrollTop(0):h>g&&c.$results.scrollTop(i)}}),b.on("results:focus",function(a){a.element.addClass("select2-results__option--highlighted")}),b.on("results:message",function(a){c.displayMessage(a)}),a.fn.mousewheel&&this.$results.on("mousewheel",function(a){var b=c.$results.scrollTop(),d=c.$results.get(0).scrollHeight-c.$results.scrollTop()+a.deltaY,e=a.deltaY>0&&b-a.deltaY<=0,f=a.deltaY<0&&d<=c.$results.height();e?(c.$results.scrollTop(0),a.preventDefault(),a.stopPropagation()):f&&(c.$results.scrollTop(c.$results.get(0).scrollHeight-c.$results.height()),a.preventDefault(),a.stopPropagation())}),this.$results.on("mouseup",".select2-results__option[aria-selected]",function(b){var d=a(this),e=d.data("data");return"true"===d.attr("aria-selected")?void(c.options.get("multiple")?c.trigger("unselect",{originalEvent:b,data:e}):c.trigger("close")):void c.trigger("select",{originalEvent:b,data:e})}),this.$results.on("mouseenter",".select2-results__option[aria-selected]",function(){var b=a(this).data("data");c.getHighlightedResults().removeClass("select2-results__option--highlighted"),c.trigger("results:focus",{data:b,element:a(this)})})},c.prototype.getHighlightedResults=function(){var a=this.$results.find(".select2-results__option--highlighted");return a},c.prototype.destroy=function(){this.$results.remove()},c.prototype.ensureHighlightVisible=function(){var a=this.getHighlightedResults();if(0!==a.length){var b=this.$results.find("[aria-selected]"),c=b.index(a),d=this.$results.offset().top,e=a.offset().top,f=this.$results.scrollTop()+(e-d),g=e-d;f-=2*a.outerHeight(!1),2>=c?this.$results.scrollTop(0):(g>this.$results.outerHeight()||0>g)&&this.$results.scrollTop(f)}},c.prototype.template=function(b,c){var d=this.options.get("templateResult"),e=this.options.get("escapeMarkup"),f=d(b);null==f?c.style.display="none":"string"==typeof f?c.innerHTML=e(f):a(c).append(f)},c}),b.define("select2/keys",[],function(){var a={BACKSPACE:8,TAB:9,ENTER:13,SHIFT:16,CTRL:17,ALT:18,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46};return a}),b.define("select2/selection/base",["jquery","../utils","../keys"],function(a,b,c){function d(a,b){this.$element=a,this.options=b,d.__super__.constructor.call(this)}return b.Extend(d,b.Observable),d.prototype.render=function(){var b=a('');return this._tabindex=0,null!=this.$element.data("old-tabindex")?this._tabindex=this.$element.data("old-tabindex"):null!=this.$element.attr("tabindex")&&(this._tabindex=this.$element.attr("tabindex")),b.attr("title",this.$element.attr("title")),b.attr("tabindex",this._tabindex),this.$selection=b,b},d.prototype.bind=function(a){var b=this,d=(a.id+"-container",a.id+"-results");this.container=a,this.$selection.on("focus",function(a){b.trigger("focus",a)}),this.$selection.on("blur",function(a){b.trigger("blur",a)}),this.$selection.on("keydown",function(a){b.trigger("keypress",a),a.which===c.SPACE&&a.preventDefault()}),a.on("results:focus",function(a){b.$selection.attr("aria-activedescendant",a.data._resultId)}),a.on("selection:update",function(a){b.update(a.data)}),a.on("open",function(){b.$selection.attr("aria-expanded","true"),b.$selection.attr("aria-owns",d),b._attachCloseHandler(a)}),a.on("close",function(){b.$selection.attr("aria-expanded","false"),b.$selection.removeAttr("aria-activedescendant"),b.$selection.removeAttr("aria-owns"),b.$selection.focus(),b._detachCloseHandler(a)}),a.on("enable",function(){b.$selection.attr("tabindex",b._tabindex)}),a.on("disable",function(){b.$selection.attr("tabindex","-1")})},d.prototype._attachCloseHandler=function(b){a(document.body).on("mousedown.select2."+b.id,function(b){var c=a(b.target),d=c.closest(".select2"),e=a(".select2.select2-container--open");e.each(function(){var b=a(this);if(this!=d[0]){var c=b.data("element");c.select2("close")}})})},d.prototype._detachCloseHandler=function(b){a(document.body).off("mousedown.select2."+b.id)},d.prototype.position=function(a,b){var c=b.find(".selection");c.append(a)},d.prototype.destroy=function(){this._detachCloseHandler(this.container)},d.prototype.update=function(){throw new Error("The `update` method must be defined in child classes.")},d}),b.define("select2/selection/single",["jquery","./base","../utils","../keys"],function(a,b,c){function d(){d.__super__.constructor.apply(this,arguments)}return c.Extend(d,b),d.prototype.render=function(){var a=d.__super__.render.call(this);return a.addClass("select2-selection--single"),a.html(''),a},d.prototype.bind=function(a){var b=this;d.__super__.bind.apply(this,arguments);var c=a.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",c),this.$selection.attr("aria-labelledby",c),this.$selection.on("mousedown",function(a){1===a.which&&b.trigger("toggle",{originalEvent:a})}),this.$selection.on("focus",function(){}),this.$selection.on("blur",function(){}),a.on("selection:update",function(a){b.update(a.data)})},d.prototype.clear=function(){this.$selection.find(".select2-selection__rendered").empty()},d.prototype.display=function(a){var b=this.options.get("templateSelection"),c=this.options.get("escapeMarkup");return c(b(a))},d.prototype.selectionContainer=function(){return a("")},d.prototype.update=function(a){if(0===a.length)return void this.clear();var b=a[0],c=this.display(b),d=this.$selection.find(".select2-selection__rendered");d.empty().append(c),d.prop("title",b.title||b.text)},d}),b.define("select2/selection/multiple",["jquery","./base","../utils"],function(a,b,c){function d(){d.__super__.constructor.apply(this,arguments)}return c.Extend(d,b),d.prototype.render=function(){var a=d.__super__.render.call(this);return a.addClass("select2-selection--multiple"),a.html('
      '),a},d.prototype.bind=function(){var b=this;d.__super__.bind.apply(this,arguments),this.$selection.on("click",function(a){b.trigger("toggle",{originalEvent:a})}),this.$selection.on("click",".select2-selection__choice__remove",function(c){var d=a(this),e=d.parent(),f=e.data("data");b.trigger("unselect",{originalEvent:c,data:f})})},d.prototype.clear=function(){this.$selection.find(".select2-selection__rendered").empty()},d.prototype.display=function(a){var b=this.options.get("templateSelection"),c=this.options.get("escapeMarkup");return c(b(a))},d.prototype.selectionContainer=function(){var b=a('
    • ×
    • ');return b},d.prototype.update=function(a){if(this.clear(),0!==a.length){for(var b=[],d=0;d1;if(d||c)return a.call(this,b);this.clear();var e=this.createPlaceholder(this.placeholder);this.$selection.find(".select2-selection__rendered").append(e)},a}),b.define("select2/selection/allowClear",["jquery","../keys"],function(a,b){function c(){}return c.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),null==this.placeholder&&this.options.get("debug")&&window.console&&console.error&&console.error("Select2: The `allowClear` option should be used in combination with the `placeholder` option."),this.$selection.on("mousedown",".select2-selection__clear",function(a){d._handleClear(a)}),b.on("keypress",function(a){d._handleKeyboardClear(a,b)})},c.prototype._handleClear=function(a,b){if(!this.options.get("disabled")){var c=this.$selection.find(".select2-selection__clear");if(0!==c.length){b.stopPropagation();for(var d=c.data("data"),e=0;e0||0===c.length)){var d=a('×');d.data("data",c),this.$selection.find(".select2-selection__rendered").prepend(d)}},c}),b.define("select2/selection/search",["jquery","../utils","../keys"],function(a,b,c){function d(a,b,c){a.call(this,b,c)}return d.prototype.render=function(b){var c=a('');this.$searchContainer=c,this.$search=c.find("input");var d=b.call(this);return d},d.prototype.bind=function(a,b,d){var e=this;a.call(this,b,d),b.on("open",function(){e.$search.attr("tabindex",0),e.$search.focus()}),b.on("close",function(){e.$search.attr("tabindex",-1),e.$search.val(""),e.$search.focus()}),b.on("enable",function(){e.$search.prop("disabled",!1)}),b.on("disable",function(){e.$search.prop("disabled",!0)}),this.$selection.on("focusin",".select2-search--inline",function(a){e.trigger("focus",a)}),this.$selection.on("focusout",".select2-search--inline",function(a){e.trigger("blur",a)}),this.$selection.on("keydown",".select2-search--inline",function(a){a.stopPropagation(),e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented();var b=a.which;if(b===c.BACKSPACE&&""===e.$search.val()){var d=e.$searchContainer.prev(".select2-selection__choice");if(d.length>0){var f=d.data("data");e.searchRemoveChoice(f),a.preventDefault()}}}),this.$selection.on("input",".select2-search--inline",function(){e.$selection.off("keyup.search")}),this.$selection.on("keyup.search input",".select2-search--inline",function(a){e.handleSearch(a)})},d.prototype.createPlaceholder=function(a,b){this.$search.attr("placeholder",b.text)},d.prototype.update=function(a,b){this.$search.attr("placeholder",""),a.call(this,b),this.$selection.find(".select2-selection__rendered").append(this.$searchContainer),this.resizeSearch()},d.prototype.handleSearch=function(){if(this.resizeSearch(),!this._keyUpPrevented){var a=this.$search.val();this.trigger("query",{term:a})}this._keyUpPrevented=!1},d.prototype.searchRemoveChoice=function(a,b){this.trigger("unselect",{data:b}),this.trigger("open"),this.$search.val(b.text+" ")},d.prototype.resizeSearch=function(){this.$search.css("width","25px");var a="";if(""!==this.$search.attr("placeholder"))a=this.$selection.find(".select2-selection__rendered").innerWidth();else{var b=this.$search.val().length+1;a=.75*b+"em"}this.$search.css("width",a)},d}),b.define("select2/selection/eventRelay",["jquery"],function(a){function b(){}return b.prototype.bind=function(b,c,d){var e=this,f=["open","opening","close","closing","select","selecting","unselect","unselecting"],g=["opening","closing","selecting","unselecting"];b.call(this,c,d),c.on("*",function(b,c){if(-1!==a.inArray(b,f)){c=c||{};var d=a.Event("select2:"+b,{params:c});e.$element.trigger(d),-1!==a.inArray(b,g)&&(c.prevented=d.isDefaultPrevented())}})},b}),b.define("select2/translation",["jquery","require"],function(a,b){function c(a){this.dict=a||{}}return c.prototype.all=function(){return this.dict},c.prototype.get=function(a){return this.dict[a]},c.prototype.extend=function(b){this.dict=a.extend({},b.all(),this.dict)},c._cache={},c.loadPath=function(a){if(!(a in c._cache)){var d=b(a);c._cache[a]=d}return new c(c._cache[a])},c}),b.define("select2/diacritics",[],function(){var a={"Ⓐ":"A","A":"A","À":"A","Á":"A","Â":"A","Ầ":"A","Ấ":"A","Ẫ":"A","Ẩ":"A","Ã":"A","Ā":"A","Ă":"A","Ằ":"A","Ắ":"A","Ẵ":"A","Ẳ":"A","Ȧ":"A","Ǡ":"A","Ä":"A","Ǟ":"A","Ả":"A","Å":"A","Ǻ":"A","Ǎ":"A","Ȁ":"A","Ȃ":"A","Ạ":"A","Ậ":"A","Ặ":"A","Ḁ":"A","Ą":"A","Ⱥ":"A","Ɐ":"A","Ꜳ":"AA","Æ":"AE","Ǽ":"AE","Ǣ":"AE","Ꜵ":"AO","Ꜷ":"AU","Ꜹ":"AV","Ꜻ":"AV","Ꜽ":"AY","Ⓑ":"B","B":"B","Ḃ":"B","Ḅ":"B","Ḇ":"B","Ƀ":"B","Ƃ":"B","Ɓ":"B","Ⓒ":"C","C":"C","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","Ç":"C","Ḉ":"C","Ƈ":"C","Ȼ":"C","Ꜿ":"C","Ⓓ":"D","D":"D","Ḋ":"D","Ď":"D","Ḍ":"D","Ḑ":"D","Ḓ":"D","Ḏ":"D","Đ":"D","Ƌ":"D","Ɗ":"D","Ɖ":"D","Ꝺ":"D","DZ":"DZ","DŽ":"DZ","Dz":"Dz","Dž":"Dz","Ⓔ":"E","E":"E","È":"E","É":"E","Ê":"E","Ề":"E","Ế":"E","Ễ":"E","Ể":"E","Ẽ":"E","Ē":"E","Ḕ":"E","Ḗ":"E","Ĕ":"E","Ė":"E","Ë":"E","Ẻ":"E","Ě":"E","Ȅ":"E","Ȇ":"E","Ẹ":"E","Ệ":"E","Ȩ":"E","Ḝ":"E","Ę":"E","Ḙ":"E","Ḛ":"E","Ɛ":"E","Ǝ":"E","Ⓕ":"F","F":"F","Ḟ":"F","Ƒ":"F","Ꝼ":"F","Ⓖ":"G","G":"G","Ǵ":"G","Ĝ":"G","Ḡ":"G","Ğ":"G","Ġ":"G","Ǧ":"G","Ģ":"G","Ǥ":"G","Ɠ":"G","Ꞡ":"G","Ᵹ":"G","Ꝿ":"G","Ⓗ":"H","H":"H","Ĥ":"H","Ḣ":"H","Ḧ":"H","Ȟ":"H","Ḥ":"H","Ḩ":"H","Ḫ":"H","Ħ":"H","Ⱨ":"H","Ⱶ":"H","Ɥ":"H","Ⓘ":"I","I":"I","Ì":"I","Í":"I","Î":"I","Ĩ":"I","Ī":"I","Ĭ":"I","İ":"I","Ï":"I","Ḯ":"I","Ỉ":"I","Ǐ":"I","Ȉ":"I","Ȋ":"I","Ị":"I","Į":"I","Ḭ":"I","Ɨ":"I","Ⓙ":"J","J":"J","Ĵ":"J","Ɉ":"J","Ⓚ":"K","K":"K","Ḱ":"K","Ǩ":"K","Ḳ":"K","Ķ":"K","Ḵ":"K","Ƙ":"K","Ⱪ":"K","Ꝁ":"K","Ꝃ":"K","Ꝅ":"K","Ꞣ":"K","Ⓛ":"L","L":"L","Ŀ":"L","Ĺ":"L","Ľ":"L","Ḷ":"L","Ḹ":"L","Ļ":"L","Ḽ":"L","Ḻ":"L","Ł":"L","Ƚ":"L","Ɫ":"L","Ⱡ":"L","Ꝉ":"L","Ꝇ":"L","Ꞁ":"L","LJ":"LJ","Lj":"Lj","Ⓜ":"M","M":"M","Ḿ":"M","Ṁ":"M","Ṃ":"M","Ɱ":"M","Ɯ":"M","Ⓝ":"N","N":"N","Ǹ":"N","Ń":"N","Ñ":"N","Ṅ":"N","Ň":"N","Ṇ":"N","Ņ":"N","Ṋ":"N","Ṉ":"N","Ƞ":"N","Ɲ":"N","Ꞑ":"N","Ꞥ":"N","NJ":"NJ","Nj":"Nj","Ⓞ":"O","O":"O","Ò":"O","Ó":"O","Ô":"O","Ồ":"O","Ố":"O","Ỗ":"O","Ổ":"O","Õ":"O","Ṍ":"O","Ȭ":"O","Ṏ":"O","Ō":"O","Ṑ":"O","Ṓ":"O","Ŏ":"O","Ȯ":"O","Ȱ":"O","Ö":"O","Ȫ":"O","Ỏ":"O","Ő":"O","Ǒ":"O","Ȍ":"O","Ȏ":"O","Ơ":"O","Ờ":"O","Ớ":"O","Ỡ":"O","Ở":"O","Ợ":"O","Ọ":"O","Ộ":"O","Ǫ":"O","Ǭ":"O","Ø":"O","Ǿ":"O","Ɔ":"O","Ɵ":"O","Ꝋ":"O","Ꝍ":"O","Ƣ":"OI","Ꝏ":"OO","Ȣ":"OU","Ⓟ":"P","P":"P","Ṕ":"P","Ṗ":"P","Ƥ":"P","Ᵽ":"P","Ꝑ":"P","Ꝓ":"P","Ꝕ":"P","Ⓠ":"Q","Q":"Q","Ꝗ":"Q","Ꝙ":"Q","Ɋ":"Q","Ⓡ":"R","R":"R","Ŕ":"R","Ṙ":"R","Ř":"R","Ȑ":"R","Ȓ":"R","Ṛ":"R","Ṝ":"R","Ŗ":"R","Ṟ":"R","Ɍ":"R","Ɽ":"R","Ꝛ":"R","Ꞧ":"R","Ꞃ":"R","Ⓢ":"S","S":"S","ẞ":"S","Ś":"S","Ṥ":"S","Ŝ":"S","Ṡ":"S","Š":"S","Ṧ":"S","Ṣ":"S","Ṩ":"S","Ș":"S","Ş":"S","Ȿ":"S","Ꞩ":"S","Ꞅ":"S","Ⓣ":"T","T":"T","Ṫ":"T","Ť":"T","Ṭ":"T","Ț":"T","Ţ":"T","Ṱ":"T","Ṯ":"T","Ŧ":"T","Ƭ":"T","Ʈ":"T","Ⱦ":"T","Ꞇ":"T","Ꜩ":"TZ","Ⓤ":"U","U":"U","Ù":"U","Ú":"U","Û":"U","Ũ":"U","Ṹ":"U","Ū":"U","Ṻ":"U","Ŭ":"U","Ü":"U","Ǜ":"U","Ǘ":"U","Ǖ":"U","Ǚ":"U","Ủ":"U","Ů":"U","Ű":"U","Ǔ":"U","Ȕ":"U","Ȗ":"U","Ư":"U","Ừ":"U","Ứ":"U","Ữ":"U","Ử":"U","Ự":"U","Ụ":"U","Ṳ":"U","Ų":"U","Ṷ":"U","Ṵ":"U","Ʉ":"U","Ⓥ":"V","V":"V","Ṽ":"V","Ṿ":"V","Ʋ":"V","Ꝟ":"V","Ʌ":"V","Ꝡ":"VY","Ⓦ":"W","W":"W","Ẁ":"W","Ẃ":"W","Ŵ":"W","Ẇ":"W","Ẅ":"W","Ẉ":"W","Ⱳ":"W","Ⓧ":"X","X":"X","Ẋ":"X","Ẍ":"X","Ⓨ":"Y","Y":"Y","Ỳ":"Y","Ý":"Y","Ŷ":"Y","Ỹ":"Y","Ȳ":"Y","Ẏ":"Y","Ÿ":"Y","Ỷ":"Y","Ỵ":"Y","Ƴ":"Y","Ɏ":"Y","Ỿ":"Y","Ⓩ":"Z","Z":"Z","Ź":"Z","Ẑ":"Z","Ż":"Z","Ž":"Z","Ẓ":"Z","Ẕ":"Z","Ƶ":"Z","Ȥ":"Z","Ɀ":"Z","Ⱬ":"Z","Ꝣ":"Z","ⓐ":"a","a":"a","ẚ":"a","à":"a","á":"a","â":"a","ầ":"a","ấ":"a","ẫ":"a","ẩ":"a","ã":"a","ā":"a","ă":"a","ằ":"a","ắ":"a","ẵ":"a","ẳ":"a","ȧ":"a","ǡ":"a","ä":"a","ǟ":"a","ả":"a","å":"a","ǻ":"a","ǎ":"a","ȁ":"a","ȃ":"a","ạ":"a","ậ":"a","ặ":"a","ḁ":"a","ą":"a","ⱥ":"a","ɐ":"a","ꜳ":"aa","æ":"ae","ǽ":"ae","ǣ":"ae","ꜵ":"ao","ꜷ":"au","ꜹ":"av","ꜻ":"av","ꜽ":"ay","ⓑ":"b","b":"b","ḃ":"b","ḅ":"b","ḇ":"b","ƀ":"b","ƃ":"b","ɓ":"b","ⓒ":"c","c":"c","ć":"c","ĉ":"c","ċ":"c","č":"c","ç":"c","ḉ":"c","ƈ":"c","ȼ":"c","ꜿ":"c","ↄ":"c","ⓓ":"d","d":"d","ḋ":"d","ď":"d","ḍ":"d","ḑ":"d","ḓ":"d","ḏ":"d","đ":"d","ƌ":"d","ɖ":"d","ɗ":"d","ꝺ":"d","dz":"dz","dž":"dz","ⓔ":"e","e":"e","è":"e","é":"e","ê":"e","ề":"e","ế":"e","ễ":"e","ể":"e","ẽ":"e","ē":"e","ḕ":"e","ḗ":"e","ĕ":"e","ė":"e","ë":"e","ẻ":"e","ě":"e","ȅ":"e","ȇ":"e","ẹ":"e","ệ":"e","ȩ":"e","ḝ":"e","ę":"e","ḙ":"e","ḛ":"e","ɇ":"e","ɛ":"e","ǝ":"e","ⓕ":"f","f":"f","ḟ":"f","ƒ":"f","ꝼ":"f","ⓖ":"g","g":"g","ǵ":"g","ĝ":"g","ḡ":"g","ğ":"g","ġ":"g","ǧ":"g","ģ":"g","ǥ":"g","ɠ":"g","ꞡ":"g","ᵹ":"g","ꝿ":"g","ⓗ":"h","h":"h","ĥ":"h","ḣ":"h","ḧ":"h","ȟ":"h","ḥ":"h","ḩ":"h","ḫ":"h","ẖ":"h","ħ":"h","ⱨ":"h","ⱶ":"h","ɥ":"h","ƕ":"hv","ⓘ":"i","i":"i","ì":"i","í":"i","î":"i","ĩ":"i","ī":"i","ĭ":"i","ï":"i","ḯ":"i","ỉ":"i","ǐ":"i","ȉ":"i","ȋ":"i","ị":"i","į":"i","ḭ":"i","ɨ":"i","ı":"i","ⓙ":"j","j":"j","ĵ":"j","ǰ":"j","ɉ":"j","ⓚ":"k","k":"k","ḱ":"k","ǩ":"k","ḳ":"k","ķ":"k","ḵ":"k","ƙ":"k","ⱪ":"k","ꝁ":"k","ꝃ":"k","ꝅ":"k","ꞣ":"k","ⓛ":"l","l":"l","ŀ":"l","ĺ":"l","ľ":"l","ḷ":"l","ḹ":"l","ļ":"l","ḽ":"l","ḻ":"l","ſ":"l","ł":"l","ƚ":"l","ɫ":"l","ⱡ":"l","ꝉ":"l","ꞁ":"l","ꝇ":"l","lj":"lj","ⓜ":"m","m":"m","ḿ":"m","ṁ":"m","ṃ":"m","ɱ":"m","ɯ":"m","ⓝ":"n","n":"n","ǹ":"n","ń":"n","ñ":"n","ṅ":"n","ň":"n","ṇ":"n","ņ":"n","ṋ":"n","ṉ":"n","ƞ":"n","ɲ":"n","ʼn":"n","ꞑ":"n","ꞥ":"n","nj":"nj","ⓞ":"o","o":"o","ò":"o","ó":"o","ô":"o","ồ":"o","ố":"o","ỗ":"o","ổ":"o","õ":"o","ṍ":"o","ȭ":"o","ṏ":"o","ō":"o","ṑ":"o","ṓ":"o","ŏ":"o","ȯ":"o","ȱ":"o","ö":"o","ȫ":"o","ỏ":"o","ő":"o","ǒ":"o","ȍ":"o","ȏ":"o","ơ":"o","ờ":"o","ớ":"o","ỡ":"o","ở":"o","ợ":"o","ọ":"o","ộ":"o","ǫ":"o","ǭ":"o","ø":"o","ǿ":"o","ɔ":"o","ꝋ":"o","ꝍ":"o","ɵ":"o","ƣ":"oi","ȣ":"ou","ꝏ":"oo","ⓟ":"p","p":"p","ṕ":"p","ṗ":"p","ƥ":"p","ᵽ":"p","ꝑ":"p","ꝓ":"p","ꝕ":"p","ⓠ":"q","q":"q","ɋ":"q","ꝗ":"q","ꝙ":"q","ⓡ":"r","r":"r","ŕ":"r","ṙ":"r","ř":"r","ȑ":"r","ȓ":"r","ṛ":"r","ṝ":"r","ŗ":"r","ṟ":"r","ɍ":"r","ɽ":"r","ꝛ":"r","ꞧ":"r","ꞃ":"r","ⓢ":"s","s":"s","ß":"s","ś":"s","ṥ":"s","ŝ":"s","ṡ":"s","š":"s","ṧ":"s","ṣ":"s","ṩ":"s","ș":"s","ş":"s","ȿ":"s","ꞩ":"s","ꞅ":"s","ẛ":"s","ⓣ":"t","t":"t","ṫ":"t","ẗ":"t","ť":"t","ṭ":"t","ț":"t","ţ":"t","ṱ":"t","ṯ":"t","ŧ":"t","ƭ":"t","ʈ":"t","ⱦ":"t","ꞇ":"t","ꜩ":"tz","ⓤ":"u","u":"u","ù":"u","ú":"u","û":"u","ũ":"u","ṹ":"u","ū":"u","ṻ":"u","ŭ":"u","ü":"u","ǜ":"u","ǘ":"u","ǖ":"u","ǚ":"u","ủ":"u","ů":"u","ű":"u","ǔ":"u","ȕ":"u","ȗ":"u","ư":"u","ừ":"u","ứ":"u","ữ":"u","ử":"u","ự":"u","ụ":"u","ṳ":"u","ų":"u","ṷ":"u","ṵ":"u","ʉ":"u","ⓥ":"v","v":"v","ṽ":"v","ṿ":"v","ʋ":"v","ꝟ":"v","ʌ":"v","ꝡ":"vy","ⓦ":"w","w":"w","ẁ":"w","ẃ":"w","ŵ":"w","ẇ":"w","ẅ":"w","ẘ":"w","ẉ":"w","ⱳ":"w","ⓧ":"x","x":"x","ẋ":"x","ẍ":"x","ⓨ":"y","y":"y","ỳ":"y","ý":"y","ŷ":"y","ỹ":"y","ȳ":"y","ẏ":"y","ÿ":"y","ỷ":"y","ẙ":"y","ỵ":"y","ƴ":"y","ɏ":"y","ỿ":"y","ⓩ":"z","z":"z","ź":"z","ẑ":"z","ż":"z","ž":"z","ẓ":"z","ẕ":"z","ƶ":"z","ȥ":"z","ɀ":"z","ⱬ":"z","ꝣ":"z","Ά":"Α","Έ":"Ε","Ή":"Η","Ί":"Ι","Ϊ":"Ι","Ό":"Ο","Ύ":"Υ","Ϋ":"Υ","Ώ":"Ω","ά":"α","έ":"ε","ή":"η","ί":"ι","ϊ":"ι","ΐ":"ι","ό":"ο","ύ":"υ","ϋ":"υ","ΰ":"υ","ω":"ω","ς":"σ"};return a}),b.define("select2/data/base",["../utils"],function(a){function b(){b.__super__.constructor.call(this)}return a.Extend(b,a.Observable),b.prototype.current=function(){throw new Error("The `current` method must be defined in child classes.")},b.prototype.query=function(){throw new Error("The `query` method must be defined in child classes.")},b.prototype.bind=function(){},b.prototype.destroy=function(){},b.prototype.generateResultId=function(b,c){var d=b.id+"-result-";return d+=a.generateChars(4),d+=null!=c.id?"-"+c.id.toString():"-"+a.generateChars(4)},b}),b.define("select2/data/select",["./base","../utils","jquery"],function(a,b,c){function d(a,b){this.$element=a,this.options=b,d.__super__.constructor.call(this)}return b.Extend(d,a),d.prototype.current=function(a){var b=[],d=this;this.$element.find(":selected").each(function(){var a=c(this),e=d.item(a);b.push(e)}),a(b)},d.prototype.select=function(a){var b=this;if(a.selected=!0,c(a.element).is("option"))return a.element.selected=!0,void this.$element.trigger("change");if(this.$element.prop("multiple"))this.current(function(d){var e=[];a=[a],a.push.apply(a,d);for(var f=0;f=0){var k=f.filter(d(j)),l=this.item(k),m=(c.extend(!0,{},l,j),this.option(l));k.replaceWith(m)}else{var n=this.option(j);if(j.children){var o=this.convertToOptions(j.children);b.appendMany(n,o)}h.push(n)}}return h},d}),b.define("select2/data/ajax",["./array","../utils","jquery"],function(a,b,c){function d(b,c){this.ajaxOptions=this._applyDefaults(c.get("ajax")),null!=this.ajaxOptions.processResults&&(this.processResults=this.ajaxOptions.processResults),a.__super__.constructor.call(this,b,c)}return b.Extend(d,a),d.prototype._applyDefaults=function(a){var b={data:function(a){return{q:a.term}},transport:function(a,b,d){var e=c.ajax(a);return e.then(b),e.fail(d),e}};return c.extend({},b,a,!0)},d.prototype.processResults=function(a){return a},d.prototype.query=function(a,b){function d(){var d=f.transport(f,function(d){var f=e.processResults(d,a);e.options.get("debug")&&window.console&&console.error&&(f&&f.results&&c.isArray(f.results)||console.error("Select2: The AJAX results did not return an array in the `results` key of the response.")),b(f)},function(){});e._request=d}var e=this;null!=this._request&&(c.isFunction(this._request.abort)&&this._request.abort(),this._request=null);var f=c.extend({type:"GET"},this.ajaxOptions);"function"==typeof f.url&&(f.url=f.url(a)),"function"==typeof f.data&&(f.data=f.data(a)),this.ajaxOptions.delay&&""!==a.term?(this._queryTimeout&&window.clearTimeout(this._queryTimeout),this._queryTimeout=window.setTimeout(d,this.ajaxOptions.delay)):d()},d}),b.define("select2/data/tags",["jquery"],function(a){function b(b,c,d){var e=d.get("tags"),f=d.get("createTag");if(void 0!==f&&(this.createTag=f),b.call(this,c,d),a.isArray(e))for(var g=0;g0&&b.term.length>this.maximumInputLength?void this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:b.term,params:b}}):void a.call(this,b,c)},a}),b.define("select2/data/maximumSelectionLength",[],function(){function a(a,b,c){this.maximumSelectionLength=c.get("maximumSelectionLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){var d=this;this.current(function(e){var f=null!=e?e.length:0;return d.maximumSelectionLength>0&&f>=d.maximumSelectionLength?void d.trigger("results:message",{message:"maximumSelected",args:{maximum:d.maximumSelectionLength}}):void a.call(d,b,c)})},a}),b.define("select2/dropdown",["jquery","./utils"],function(a,b){function c(a,b){this.$element=a,this.options=b,c.__super__.constructor.call(this)}return b.Extend(c,b.Observable),c.prototype.render=function(){var b=a('');return b.attr("dir",this.options.get("dir")),this.$dropdown=b,b},c.prototype.position=function(){},c.prototype.destroy=function(){this.$dropdown.remove()},c}),b.define("select2/dropdown/search",["jquery","../utils"],function(a){function b(){}return b.prototype.render=function(b){var c=b.call(this),d=a('');return this.$searchContainer=d,this.$search=d.find("input"),c.prepend(d),c},b.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),this.$search.on("keydown",function(a){e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented()}),this.$search.on("input",function(){a(this).off("keyup")}),this.$search.on("keyup input",function(a){e.handleSearch(a)}),c.on("open",function(){e.$search.attr("tabindex",0),e.$search.focus(),window.setTimeout(function(){e.$search.focus()},0)}),c.on("close",function(){e.$search.attr("tabindex",-1),e.$search.val("")}),c.on("results:all",function(a){if(null==a.query.term||""===a.query.term){var b=e.showSearch(a);b?e.$searchContainer.removeClass("select2-search--hide"):e.$searchContainer.addClass("select2-search--hide")}})},b.prototype.handleSearch=function(){if(!this._keyUpPrevented){var a=this.$search.val();this.trigger("query",{term:a})}this._keyUpPrevented=!1},b.prototype.showSearch=function(){return!0},b}),b.define("select2/dropdown/hidePlaceholder",[],function(){function a(a,b,c,d){this.placeholder=this.normalizePlaceholder(c.get("placeholder")),a.call(this,b,c,d)}return a.prototype.append=function(a,b){b.results=this.removePlaceholder(b.results),a.call(this,b)},a.prototype.normalizePlaceholder=function(a,b){return"string"==typeof b&&(b={id:"",text:b}),b},a.prototype.removePlaceholder=function(a,b){for(var c=b.slice(0),d=b.length-1;d>=0;d--){var e=b[d];this.placeholder.id===e.id&&c.splice(d,1)}return c},a}),b.define("select2/dropdown/infiniteScroll",["jquery"],function(a){function b(a,b,c,d){this.lastParams={},a.call(this,b,c,d),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return b.prototype.append=function(a,b){this.$loadingMore.remove(),this.loading=!1,a.call(this,b),this.showLoadingMore(b)&&this.$results.append(this.$loadingMore)},b.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),c.on("query",function(a){e.lastParams=a,e.loading=!0}),c.on("query:append",function(a){e.lastParams=a,e.loading=!0}),this.$results.on("scroll",function(){var b=a.contains(document.documentElement,e.$loadingMore[0]);if(!e.loading&&b){var c=e.$results.offset().top+e.$results.outerHeight(!1),d=e.$loadingMore.offset().top+e.$loadingMore.outerHeight(!1);c+50>=d&&e.loadMore()}})},b.prototype.loadMore=function(){this.loading=!0;var b=a.extend({},{page:1},this.lastParams);b.page++,this.trigger("query:append",b)},b.prototype.showLoadingMore=function(a,b){return b.pagination&&b.pagination.more},b.prototype.createLoadingMore=function(){var b=a('
    • '),c=this.options.get("translations").get("loadingMore");return b.html(c(this.lastParams)),b},b}),b.define("select2/dropdown/attachBody",["jquery","../utils"],function(a,b){function c(a,b,c){this.$dropdownParent=c.get("dropdownParent")||document.body,a.call(this,b,c)}return c.prototype.bind=function(a,b,c){var d=this,e=!1;a.call(this,b,c),b.on("open",function(){d._showDropdown(),d._attachPositioningHandler(b),e||(e=!0,b.on("results:all",function(){d._positionDropdown(),d._resizeDropdown()}),b.on("results:append",function(){d._positionDropdown(),d._resizeDropdown()}))}),b.on("close",function(){d._hideDropdown(),d._detachPositioningHandler(b)}),this.$dropdownContainer.on("mousedown",function(a){a.stopPropagation()})},c.prototype.position=function(a,b,c){b.attr("class",c.attr("class")),b.removeClass("select2"),b.addClass("select2-container--open"),b.css({position:"absolute",top:-999999}),this.$container=c},c.prototype.render=function(b){var c=a(""),d=b.call(this);return c.append(d),this.$dropdownContainer=c,c},c.prototype._hideDropdown=function(){this.$dropdownContainer.detach()},c.prototype._attachPositioningHandler=function(c){var d=this,e="scroll.select2."+c.id,f="resize.select2."+c.id,g="orientationchange.select2."+c.id,h=this.$container.parents().filter(b.hasScroll);h.each(function(){a(this).data("select2-scroll-position",{x:a(this).scrollLeft(),y:a(this).scrollTop()})}),h.on(e,function(){var b=a(this).data("select2-scroll-position");a(this).scrollTop(b.y)}),a(window).on(e+" "+f+" "+g,function(){d._positionDropdown(),d._resizeDropdown()})},c.prototype._detachPositioningHandler=function(c){var d="scroll.select2."+c.id,e="resize.select2."+c.id,f="orientationchange.select2."+c.id,g=this.$container.parents().filter(b.hasScroll);g.off(d),a(window).off(d+" "+e+" "+f)},c.prototype._positionDropdown=function(){var b=a(window),c=this.$dropdown.hasClass("select2-dropdown--above"),d=this.$dropdown.hasClass("select2-dropdown--below"),e=null,f=(this.$container.position(),this.$container.offset());f.bottom=f.top+this.$container.outerHeight(!1);var g={height:this.$container.outerHeight(!1)};g.top=f.top,g.bottom=f.top+g.height;var h={height:this.$dropdown.outerHeight(!1)},i={top:b.scrollTop(),bottom:b.scrollTop()+b.height()},j=i.topf.bottom+h.height,l={left:f.left,top:g.bottom};c||d||(e="below"),k||!j||c?!j&&k&&c&&(e="below"):e="above",("above"==e||c&&"below"!==e)&&(l.top=g.top-h.height),null!=e&&(this.$dropdown.removeClass("select2-dropdown--below select2-dropdown--above").addClass("select2-dropdown--"+e),this.$container.removeClass("select2-container--below select2-container--above").addClass("select2-container--"+e)),this.$dropdownContainer.css(l)},c.prototype._resizeDropdown=function(){this.$dropdownContainer.width();var a={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(a.minWidth=a.width,a.width="auto"),this.$dropdown.css(a)},c.prototype._showDropdown=function(){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},c}),b.define("select2/dropdown/minimumResultsForSearch",[],function(){function a(b){for(var c=0,d=0;d0&&(l.dataAdapter=j.Decorate(l.dataAdapter,r)),l.maximumInputLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,s)),l.maximumSelectionLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,t)),l.tags&&(l.dataAdapter=j.Decorate(l.dataAdapter,p)),(null!=l.tokenSeparators||null!=l.tokenizer)&&(l.dataAdapter=j.Decorate(l.dataAdapter,q)),null!=l.query){var C=b(l.amdBase+"compat/query");l.dataAdapter=j.Decorate(l.dataAdapter,C)}if(null!=l.initSelection){var D=b(l.amdBase+"compat/initSelection");l.dataAdapter=j.Decorate(l.dataAdapter,D)}}if(null==l.resultsAdapter&&(l.resultsAdapter=c,null!=l.ajax&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,x)),null!=l.placeholder&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,w)),l.selectOnClose&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,A))),null==l.dropdownAdapter){if(l.multiple)l.dropdownAdapter=u;else{var E=j.Decorate(u,v);l.dropdownAdapter=E}if(0!==l.minimumResultsForSearch&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,z)),l.closeOnSelect&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,B)),null!=l.dropdownCssClass||null!=l.dropdownCss||null!=l.adaptDropdownCssClass){var F=b(l.amdBase+"compat/dropdownCss");l.dropdownAdapter=j.Decorate(l.dropdownAdapter,F)}l.dropdownAdapter=j.Decorate(l.dropdownAdapter,y)}if(null==l.selectionAdapter){if(l.selectionAdapter=l.multiple?e:d,null!=l.placeholder&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,f)),l.allowClear&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,g)),l.multiple&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,h)),null!=l.containerCssClass||null!=l.containerCss||null!=l.adaptContainerCssClass){var G=b(l.amdBase+"compat/containerCss");l.selectionAdapter=j.Decorate(l.selectionAdapter,G)}l.selectionAdapter=j.Decorate(l.selectionAdapter,i)}if("string"==typeof l.language)if(l.language.indexOf("-")>0){var H=l.language.split("-"),I=H[0];l.language=[l.language,I]}else l.language=[l.language];if(a.isArray(l.language)){var J=new k;l.language.push("en");for(var K=l.language,L=0;L0){for(var f=a.extend(!0,{},e),g=e.children.length-1;g>=0;g--){var h=e.children[g],i=c(d,h);null==i&&f.children.splice(g,1)}return f.children.length>0?f:c(d,f)}var j=b(e.text).toUpperCase(),k=b(d.term).toUpperCase();return j.indexOf(k)>-1?e:null}this.defaults={amdBase:"./",amdLanguageBase:"./i18n/",closeOnSelect:!0,debug:!1,dropdownAutoWidth:!1,escapeMarkup:j.escapeMarkup,language:C,matcher:c,minimumInputLength:0,maximumInputLength:0,maximumSelectionLength:0,minimumResultsForSearch:0,selectOnClose:!1,sorter:function(a){return a},templateResult:function(a){return a.text},templateSelection:function(a){return a.text},theme:"default",width:"resolve"}},D.prototype.set=function(b,c){var d=a.camelCase(b),e={};e[d]=c;var f=j._convertData(e);a.extend(this.defaults,f)};var E=new D;return E}),b.define("select2/options",["require","jquery","./defaults","./utils"],function(a,b,c,d){function e(b,e){if(this.options=b,null!=e&&this.fromElement(e),this.options=c.apply(this.options),e&&e.is("input")){var f=a(this.get("amdBase")+"compat/inputData");this.options.dataAdapter=d.Decorate(this.options.dataAdapter,f)}}return e.prototype.fromElement=function(a){var c=["select2"];null==this.options.multiple&&(this.options.multiple=a.prop("multiple")),null==this.options.disabled&&(this.options.disabled=a.prop("disabled")),null==this.options.language&&(a.prop("lang")?this.options.language=a.prop("lang").toLowerCase():a.closest("[lang]").prop("lang")&&(this.options.language=a.closest("[lang]").prop("lang"))),null==this.options.dir&&(this.options.dir=a.prop("dir")?a.prop("dir"):a.closest("[dir]").prop("dir")?a.closest("[dir]").prop("dir"):"ltr"),a.prop("disabled",this.options.disabled),a.prop("multiple",this.options.multiple),a.data("select2Tags")&&(this.options.debug&&window.console&&console.warn&&console.warn('Select2: The `data-select2-tags` attribute has been changed to use the `data-data` and `data-tags="true"` attributes and will be removed in future versions of Select2.'),a.data("data",a.data("select2Tags")),a.data("tags",!0)),a.data("ajaxUrl")&&(this.options.debug&&window.console&&console.warn&&console.warn("Select2: The `data-ajax-url` attribute has been changed to `data-ajax--url` and support for the old attribute will be removed in future versions of Select2."),a.attr("ajax--url",a.data("ajaxUrl")),a.data("ajax--url",a.data("ajaxUrl")));var e={};e=b.fn.jquery&&"1."==b.fn.jquery.substr(0,2)&&a[0].dataset?b.extend(!0,{},a[0].dataset,a.data()):a.data();var f=b.extend(!0,{},e);f=d._convertData(f);for(var g in f)b.inArray(g,c)>-1||(b.isPlainObject(this.options[g])?b.extend(this.options[g],f[g]):this.options[g]=f[g]);return this},e.prototype.get=function(a){return this.options[a]},e.prototype.set=function(a,b){this.options[a]=b},e}),b.define("select2/core",["jquery","./options","./utils","./keys"],function(a,b,c,d){var e=function(a,c){null!=a.data("select2")&&a.data("select2").destroy(),this.$element=a,this.id=this._generateId(a),c=c||{},this.options=new b(c,a),e.__super__.constructor.call(this);var d=a.attr("tabindex")||0;a.data("old-tabindex",d),a.attr("tabindex","-1");var f=this.options.get("dataAdapter");this.dataAdapter=new f(a,this.options);var g=this.render();this._placeContainer(g);var h=this.options.get("selectionAdapter");this.selection=new h(a,this.options),this.$selection=this.selection.render(),this.selection.position(this.$selection,g);var i=this.options.get("dropdownAdapter");this.dropdown=new i(a,this.options),this.$dropdown=this.dropdown.render(),this.dropdown.position(this.$dropdown,g);var j=this.options.get("resultsAdapter");this.results=new j(a,this.options,this.dataAdapter),this.$results=this.results.render(),this.results.position(this.$results,this.$dropdown);var k=this;this._bindAdapters(),this._registerDomEvents(),this._registerDataEvents(),this._registerSelectionEvents(),this._registerDropdownEvents(),this._registerResultsEvents(),this._registerEvents(),this.dataAdapter.current(function(a){k.trigger("selection:update",{data:a})}),a.addClass("select2-hidden-accessible"),a.attr("aria-hidden","true"),this._syncAttributes(),a.data("select2",this)};return c.Extend(e,c.Observable),e.prototype._generateId=function(a){var b="";return b=null!=a.attr("id")?a.attr("id"):null!=a.attr("name")?a.attr("name")+"-"+c.generateChars(2):c.generateChars(4),b="select2-"+b},e.prototype._placeContainer=function(a){a.insertAfter(this.$element);var b=this._resolveWidth(this.$element,this.options.get("width"));null!=b&&a.css("width",b)},e.prototype._resolveWidth=function(a,b){var c=/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;if("resolve"==b){var d=this._resolveWidth(a,"style");return null!=d?d:this._resolveWidth(a,"element")}if("element"==b){var e=a.outerWidth(!1);return 0>=e?"auto":e+"px"}if("style"==b){var f=a.attr("style");if("string"!=typeof f)return null;for(var g=f.split(";"),h=0,i=g.length;i>h;h+=1){var j=g[h].replace(/\s/g,""),k=j.match(c);if(null!==k&&k.length>=1)return k[1]}return null}return b},e.prototype._bindAdapters=function(){this.dataAdapter.bind(this,this.$container),this.selection.bind(this,this.$container),this.dropdown.bind(this,this.$container),this.results.bind(this,this.$container)},e.prototype._registerDomEvents=function(){var b=this;this.$element.on("change.select2",function(){b.dataAdapter.current(function(a){b.trigger("selection:update",{data:a})})}),this._sync=c.bind(this._syncAttributes,this),this.$element[0].attachEvent&&this.$element[0].attachEvent("onpropertychange",this._sync);var d=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver;null!=d?(this._observer=new d(function(c){a.each(c,b._sync)}),this._observer.observe(this.$element[0],{attributes:!0,subtree:!1})):this.$element[0].addEventListener&&this.$element[0].addEventListener("DOMAttrModified",b._sync,!1)},e.prototype._registerDataEvents=function(){var a=this;this.dataAdapter.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerSelectionEvents=function(){var b=this,c=["toggle"];this.selection.on("toggle",function(){b.toggleDropdown()}),this.selection.on("*",function(d,e){-1===a.inArray(d,c)&&b.trigger(d,e)})},e.prototype._registerDropdownEvents=function(){var a=this;this.dropdown.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerResultsEvents=function(){var a=this;this.results.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerEvents=function(){var a=this;this.on("open",function(){a.$container.addClass("select2-container--open")}),this.on("close",function(){a.$container.removeClass("select2-container--open")}),this.on("enable",function(){a.$container.removeClass("select2-container--disabled")}),this.on("disable",function(){a.$container.addClass("select2-container--disabled")}),this.on("focus",function(){a.$container.addClass("select2-container--focus")}),this.on("blur",function(){a.$container.removeClass("select2-container--focus")}),this.on("query",function(b){a.isOpen()||a.trigger("open"),this.dataAdapter.query(b,function(c){a.trigger("results:all",{data:c,query:b})})}),this.on("query:append",function(b){this.dataAdapter.query(b,function(c){a.trigger("results:append",{data:c,query:b})})}),this.on("keypress",function(b){var c=b.which;a.isOpen()?c===d.ENTER?(a.trigger("results:select"),b.preventDefault()):c===d.SPACE&&b.ctrlKey?(a.trigger("results:toggle"),b.preventDefault()):c===d.UP?(a.trigger("results:previous"),b.preventDefault()):c===d.DOWN?(a.trigger("results:next"),b.preventDefault()):(c===d.ESC||c===d.TAB)&&(a.close(),b.preventDefault()):(c===d.ENTER||c===d.SPACE||(c===d.DOWN||c===d.UP)&&b.altKey)&&(a.open(),b.preventDefault())})},e.prototype._syncAttributes=function(){this.options.set("disabled",this.$element.prop("disabled")),this.options.get("disabled")?(this.isOpen()&&this.close(),this.trigger("disable")):this.trigger("enable")},e.prototype.trigger=function(a,b){var c=e.__super__.trigger,d={open:"opening",close:"closing",select:"selecting",unselect:"unselecting"};if(a in d){var f=d[a],g={prevented:!1,name:a,args:b};if(c.call(this,f,g),g.prevented)return void(b.prevented=!0)}c.call(this,a,b)},e.prototype.toggleDropdown=function(){this.options.get("disabled")||(this.isOpen()?this.close():this.open())},e.prototype.open=function(){this.isOpen()||(this.trigger("query",{}),this.trigger("open"))},e.prototype.close=function(){this.isOpen()&&this.trigger("close")},e.prototype.isOpen=function(){return this.$container.hasClass("select2-container--open")},e.prototype.enable=function(a){this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("enable")` method has been deprecated and will be removed in later Select2 versions. Use $element.prop("disabled") instead.'),(null==a||0===a.length)&&(a=[!0]);var b=!a[0];this.$element.prop("disabled",b)},e.prototype.data=function(){this.options.get("debug")&&arguments.length>0&&window.console&&console.warn&&console.warn('Select2: Data can no longer be set using `select2("data")`. You should consider setting the value instead using `$element.val()`.');var a=[];return this.dataAdapter.current(function(b){a=b}),a},e.prototype.val=function(b){if(this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("val")` method has been deprecated and will be removed in later Select2 versions. Use $element.val() instead.'),null==b||0===b.length)return this.$element.val();var c=b[0];a.isArray(c)&&(c=a.map(c,function(a){return a.toString()})),this.$element.val(c).trigger("change")},e.prototype.destroy=function(){this.$container.remove(),this.$element[0].detachEvent&&this.$element[0].detachEvent("onpropertychange",this._sync),null!=this._observer?(this._observer.disconnect(),this._observer=null):this.$element[0].removeEventListener&&this.$element[0].removeEventListener("DOMAttrModified",this._sync,!1),this._sync=null,this.$element.off(".select2"),this.$element.attr("tabindex",this.$element.data("old-tabindex")),this.$element.removeClass("select2-hidden-accessible"),this.$element.attr("aria-hidden","false"),this.$element.removeData("select2"),this.dataAdapter.destroy(),this.selection.destroy(),this.dropdown.destroy(),this.results.destroy(),this.dataAdapter=null,this.selection=null,this.dropdown=null,this.results=null},e.prototype.render=function(){var b=a('');return b.attr("dir",this.options.get("dir")),this.$container=b,this.$container.addClass("select2-container--"+this.options.get("theme")),b.data("element",this.$element),b},e}),b.define("jquery.select2",["jquery","require","./select2/core","./select2/defaults"],function(a,b,c,d){if(b("jquery.mousewheel"),null==a.fn.select2){var e=["open","close","destroy"];a.fn.select2=function(b){if(b=b||{},"object"==typeof b)return this.each(function(){{var d=a.extend({},b,!0);new c(a(this),d)}}),this;if("string"==typeof b){var d=this.data("select2");null==d&&window.console&&console.error&&console.error("The select2('"+b+"') method was called on an element that is not using Select2.");var f=Array.prototype.slice.call(arguments,1),g=d[b](f);return a.inArray(b,e)>-1?this:g}throw new Error("Invalid arguments for Select2: "+b)}}return null==a.fn.select2.defaults&&(a.fn.select2.defaults=d),c}),b.define("jquery.mousewheel",["jquery"],function(a){return a}),{define:b.define,require:b.require}}(),c=b.require("jquery.select2");return a.fn.select2.amd=b,c}); \ No newline at end of file diff --git a/ui/ui/sections/footer.tpl b/ui/ui/sections/footer.tpl index b096059e..e68d9aec 100644 --- a/ui/ui/sections/footer.tpl +++ b/ui/ui/sections/footer.tpl @@ -14,10 +14,18 @@ + {if isset($xfooter)} {$xfooter} {/if} +{literal} + +{/literal} diff --git a/ui/ui/sections/header.tpl b/ui/ui/sections/header.tpl index 187b5dad..efb7d216 100644 --- a/ui/ui/sections/header.tpl +++ b/ui/ui/sections/header.tpl @@ -15,7 +15,8 @@ - + + {if isset($xheader)} @@ -53,13 +58,15 @@ @@ -155,6 +165,8 @@ href="{$_url}services/pppoe">{$_L['PPPOE_Plans']}
    • {$_L['Bandwidth_Plans']}
    • +
    • {Lang::T('Balance Plans')}
    • {$_MENU_SERVICES} @@ -213,7 +225,7 @@ {$_MENU_AFTER_PAGES} -
    • +
    • {$_L['Settings']} @@ -225,23 +237,24 @@ href="{$_url}settings/app">{$_L['General_Settings']}
    • {$_L['Localisation']}
    • +
    • {Lang::T('User Notification')}
    • {$_L['Administrator_Users']}
    • {$_L['Backup_Restore']}
    • -
    • {Lang::T('Plugin Manager')}
    • +
    • + {Lang::T('Plugin Manager')} +
    • +
    • + + {Lang::T('Payment Gateway')} + +
    • {$_MENU_SETTINGS} {$_MENU_AFTER_SETTINGS} -
    • - - - {Lang::T('Payment Gateway')} - -
    • - {$_MENU_AFTER_PAYMENTGATEWAY}
    • diff --git a/ui/ui/sections/user-header.tpl b/ui/ui/sections/user-header.tpl index d5b261ee..cdbee5ad 100644 --- a/ui/ui/sections/user-header.tpl +++ b/ui/ui/sections/user-header.tpl @@ -39,7 +39,7 @@
      - @@ -53,12 +53,14 @@