Compare commits

...

223 Commits

Author SHA1 Message Date
ae3db05649 2024.5.14 2024-05-14 13:40:30 +07:00
fa45d5f4b5 Customizeable Payment Recharge 2024-05-14 10:25:21 +07:00
895bb26b02 add Internet Plan and Location in expired list Dashboard 2024-05-14 09:11:56 +07:00
a5affdb674 add refresh dashboard to get latest data 2024-05-14 08:55:38 +07:00
238fc03d03 update ORM so it can use array for select 2024-05-14 08:43:26 +07:00
cf8e23ae88 Fix Burst 2024-05-08 17:24:41 +07:00
b9132082e5 Merge pull request #197 from gerandonk/Development
Fix bugs burst
2024-05-08 17:22:07 +07:00
ee63abb618 Fix bugs burst
Fix Burst on php7
Fix edit hotspot plan
Fix burs reset if klick sync button on plan page
2024-05-08 13:39:15 +07:00
060718dfda Fix Validity,, forgot to explode 2024-05-07 19:11:31 +07:00
651969924c add remove Active user when extends 2024-05-07 11:28:51 +07:00
a40b2cbea3 add numeric option at Settings 2024-05-07 10:53:04 +07:00
fc73a83732 2024.5.7 2024-05-07 10:15:28 +07:00
6763fe09d8 fix validity_unit time for Days 2024-05-07 10:15:28 +07:00
0ea9de70fc Merge pull request #195 from agstrxyz/master
Update services.php
2024-05-07 08:55:29 +07:00
c7ec8e2d27 Merge pull request #194 from agstrxyz/patch-12
Update cron.php
2024-05-07 08:54:51 +07:00
822acef6d8 Merge pull request #192 from agstrxyz/Development
Update Radius.php
2024-05-07 08:54:10 +07:00
892c6bf7f5 Merge pull request #189 from pro-cms/patch-4
Added generate voucher function.
2024-05-07 08:50:25 +07:00
c0c857e735 Merge pull request #188 from pro-cms/patch-3
Add voucher type numbers in Option
2024-05-07 08:49:48 +07:00
49794b99de Merge pull request #187 from pro-cms/patch-2
Added generate numeric only vouchers
2024-05-07 08:49:11 +07:00
126212f4c2 Merge branch 'Development' into patch-2 2024-05-07 08:49:01 +07:00
e3de07d435 Update services.php
busrt radius plan
2024-05-07 08:11:16 +07:00
2f551b1755 Update cron.php
Fix Autorenewal radius plan base
2024-05-07 04:55:20 +07:00
f766393e52 Update Radius.php
Fix radius plan base
*uptime limit
*burst bw profile limit
*data limit
*user can't login after recharge radius plan base

please add this variable in "mods-available/sqlcounter" for freeradius installation wiki

sqlcounter uptimelimit {
counter_name = 'Max-All-Session-Time'
check_name = 'Max-All-Session'
sql_module_instance = sql
key = 'User-Name'
reset = never
query = "SELECT SUM(AcctSessionTime) FROM radacct WHERE UserName='%{${key}}'"
}

and this variable in "sites-enabled/default"
authorize {
expiration
quotalimit
accessperiod
uptimelimit
}
2024-05-07 04:27:13 +07:00
0bd587522a Search all field 2024-05-02 16:31:25 +07:00
47c6e90624 delete die() debug, forgot to delete it 2024-05-01 10:21:32 +07:00
fc0ef5b41a Added generate voucher function. 2024-04-30 23:16:20 +03:00
dff3970ff4 Add voucher type numbers in Option 2024-04-30 23:15:05 +03:00
4c4fe4e99f Added generate numeric only vouchers 2024-04-30 23:14:08 +03:00
2ed3dc991a CRITICAL UPDATE: last update Logic recharge not check is status on or off, it make expired customer stay in expired pool 2024-04-30 22:36:24 +07:00
be43a5b385 add anti double submit when refill balance 2024-04-29 14:01:05 +07:00
61bd042b15 add notif if Customer is not expired yet when extend 2024-04-29 13:50:26 +07:00
b6fde35eb6 add search and pagination at Customer maps, fix query 2024-04-29 13:44:59 +07:00
980af58eb1 fix logic extend from admin 2024-04-29 13:20:57 +07:00
f7deb828ac don't delete customer when plan not change 2024-04-29 13:18:07 +07:00
4c1e5da601 fix variable forsendPackageNotification 2024-04-23 15:34:40 +07:00
9712d411f5 Merge branch 'Development' 2024-04-23 11:52:04 +07:00
8dc7707b3a fix pagination Voucher 2024-04-23 11:51:34 +07:00
18bdf185d6 Update plan.php 2024-04-23 11:32:58 +07:00
2a70236576 Merge pull request #181 from agstrxyz/patch-10
Update plan.php
2024-04-23 11:31:52 +07:00
7b40fc850e Merge pull request #180 from freeispradius/master
Update to case csv. added columns
2024-04-23 11:31:18 +07:00
ad411e2223 Update plan.php 2024-04-23 09:24:47 +07:00
45a6085205 Update case csv-prepaid
changed the url
2024-04-22 23:33:54 +03:00
91fe5a4b46 Update to case csv. added columns
separated case csv now we will have one for all customers and another one for prepaid users.
for all customers csv will be downloaded from list and prepaid csv will be from prepaid users.
Also added columns instead of the previous one
2024-04-22 23:31:36 +03:00
c0cd197df2 Fix Extend Confirmation long text 2024-04-22 14:02:33 +07:00
3e89efcf46 add Customer Fullname 2024-04-22 11:33:21 +07:00
31b710e03c add username to telegram notif 2024-04-22 10:30:01 +07:00
4d6041f614 send Telegram for Extend 2024-04-22 10:30:01 +07:00
fbaf9dbe3f Merge pull request #179 from ahmadhusein17/patch-21
Indonesian Language Improvement
2024-04-22 09:51:18 +07:00
a4f5c1d422 Update indonesia.json
Improvements to the use of letter size in the language and minor improvements
2024-04-21 21:46:31 +07:00
d08137e0c3 Merge branch 'master' into Development 2024-04-21 20:55:42 +07:00
961f4770c0 Update cron_reminder.php 2024-04-21 20:54:10 +07:00
2d6fe9526c Update cron_reminder.php 2024-04-21 20:54:10 +07:00
bebc20e39f Update cron_reminder.php 2024-04-21 20:54:10 +07:00
964c141668 Update cron_reminder.php 2024-04-21 20:54:10 +07:00
88bbf3ed35 fix lang.php 2024-04-21 20:54:10 +07:00
bf00b21786 fix Lang 2024-04-21 20:54:10 +07:00
0e81db5ada indonesia lang 2024-04-21 20:54:10 +07:00
c0382c569a Update cron_reminder.php 2024-04-21 20:54:10 +07:00
c32542afda Update cron_reminder.php 2024-04-21 20:54:10 +07:00
8d17cd3f90 fix [[expired_date]] 2024-04-21 20:54:10 +07:00
6dafd549d9 Restore old cron 2024-04-21 20:54:10 +07:00
20c4be9121 As exp dev says, if it works, dont touch it 2024-04-21 20:54:10 +07:00
2f757f1006 Update cron_reminder.php 2024-04-21 20:54:10 +07:00
0ce112dc70 order activated by desc 2024-04-21 20:54:10 +07:00
ea3f5caf59 Update voucher.tpl 2024-04-21 20:54:09 +07:00
5a5032bbcc fix [[expired_date]] 2024-04-21 10:59:20 +07:00
0d44fec338 Restore old cron 2024-04-21 10:54:04 +07:00
7396c2f1d4 As exp dev says, if it works, dont touch it 2024-04-21 10:54:04 +07:00
73cf67b4cb Update cron_reminder.php 2024-04-21 10:54:04 +07:00
9e0f74926c Update cron_reminder.php 2024-04-21 10:54:04 +07:00
09af3474a9 Update cron.php 2024-04-21 10:54:04 +07:00
9b8f1fedf8 Merge pull request #178 from ahmadhusein17/master
restore cron.php and cron_reminder.php
2024-04-21 10:48:11 +07:00
05c77df315 order activated by desc 2024-04-19 14:43:06 +07:00
e88f662d8c Merge pull request #177 from ahmadhusein17/Development
Update voucher.tpl
2024-04-19 13:37:39 +07:00
2956cc2315 Update cron_reminder.php 2024-04-19 11:23:50 +07:00
3c8b2c906d Update cron_reminder.php 2024-04-19 11:22:34 +07:00
acded8eb29 Update cron.php 2024-04-19 11:21:44 +07:00
b63aeb5298 Update voucher.tpl 2024-04-16 14:10:40 +07:00
115a5c81a7 Fix variable cron for notification 2024-04-16 13:53:29 +07:00
ad565c15ca Remove question mark 2024-04-15 15:39:43 +07:00
a0c5cec31e Fix Notifications Page 2024-04-15 15:36:18 +07:00
fb4901be9f add log when extend expiraton 2024-04-15 14:35:36 +07:00
a164b345b6 dont send if message empty 2024-04-15 14:30:51 +07:00
8f07c7640c edit changelog 2024-04-15 14:15:15 +07:00
8891cd5aaa allow extend expired for postpaid customer 2024-04-15 14:09:02 +07:00
854fd54834 delete $_c = $config; as it already exists in init.php 2024-04-15 14:08:34 +07:00
21876601ba Hide Tax Settings as it still have a bug 2024-04-15 11:13:19 +07:00
6955d3fd8b Merge pull request #173 from Focuslinkstech/Development
Update: Tax System
2024-04-15 09:10:08 +07:00
d6510dffa7 Merge pull request #175 from agstrxyz/patch-9
Update home.php
2024-04-15 09:07:01 +07:00
419595554b Update home.php
fix token to prevent double recharge
2024-04-15 09:06:26 +07:00
bcc84aed9a Merge pull request #174 from agstrxyz/patch-8
Update cron.php
2024-04-15 09:01:02 +07:00
05caee1193 Merge branch 'Development' into patch-8 2024-04-15 09:00:53 +07:00
071feb3a48 Merge pull request #172 from ahmadhusein17/patch-19
Update cron.php
2024-04-15 08:54:48 +07:00
a5774fe335 Merge pull request #171 from ahmadhusein17/patch-18
Update cron_reminder.php
2024-04-15 08:53:13 +07:00
92a2690ec6 Update home.php 2024-04-14 21:13:11 +07:00
519bef21e0 Update home.php
fix user self recharge in user dashboard for radius plan base
2024-04-14 06:45:45 +07:00
1a40606720 Update cron.php
Fix auto renewal radius plan based
2024-04-14 06:40:47 +07:00
eff79df39a Update customers.tpl
add length Menu  5, 10, 25, 50, 100 and All, as suggested by one of our member and also use 5 as default page length to make the page fit the screen when loaded
2024-04-13 18:19:09 +01:00
425ed2362b Update: Tax System
Tax System Feature Added

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

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

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

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

3
.gitignore vendored
View File

@ -38,4 +38,5 @@ system/lan/**
!system/lan/spanish.json
!system/lan/turkish.json
!system/lan/english.json
!system/lan/country.json
!system/lan/country.json
*.zip

View File

@ -6,4 +6,9 @@
<Files index.php>
Order Allow,Deny
Allow from all
</Files>
<Files update.php>
Order Allow,Deny
Allow from all
</Files>

View File

@ -2,6 +2,100 @@
# CHANGELOG
## 2024.5.14
- Show Plan and Location on expired list
- Customizeable payment for recharge
## 2024.5.8
- Fix bugs burst by @Gerandonk
- Fix sync for burst by @Gerandonk
## 2024.5.7
- Fix time for period Days
- Fix Free radius attributes by @agstrxyz
- Add Numeric Voucher Code by @pro-cms
## 2024.4.30
- CRITICAL UPDATE: last update Logic recharge not check is status on or off, it make expired customer stay in expired pool
- Prevent double submit for recharge balance
## 2024.4.29
- Maps Pagination
- Maps Search
- Fix extend logic
- Fix logic customer recharge to not delete when customer not change the plan
## 2024.4.23
- Fix Pagination Voucher
- Fix Languange Translation
- Fix Alert Confirmation for requesting Extend
- Send Telegram Notification when Customer request to extend expiration
- prepaid users export list by @freeispradius
- fix show voucher by @agstrxyz
## 2024.4.21
- Restore old cron
## 2024.4.15
- Postpaid Customer can request extends expiration day if it enabled
- Some Code Fixing by @ahmadhusein17 and @agstrxyz
## 2024.4.4
- Data Tables for Customers List by @Focuslinkstech
- Add Bills to Reminder
- Prevent double submit for recharge and renew
## 2024.4.3
- Export logs to CSV by @agstrxyz
- Change to Username if Country code empty
## 2024.4.2
- Fix REST API
- Fix Log IP Cloudflare by @Gerandonk
- Show Personal or Business in customer dashboard
## 2024.3.26
- Change paginator, to make easy customization using pagination.tpl
## 2024.3.25
- Fix maps on HTTP
- Fix Cancel payment
## 2024.3.23
- Maps full height
- Show Get Directions instead Coordinates
- Maps Label always show
## 2024.3.22
- Fix Broadcast Message by @Focuslinkstech
- Add Location Picker
## 2024.3.20
- Fixing some bugs
## 2024.3.19
- Add Customer Type Personal or Bussiness by @pro-cms
- Fix Broadcast Message by @Focuslinkstech
- Add Customer Geolocation by @Focuslinkstech
- Change Customer Menu
## 2024.3.18
- Add Broadcasting SMS by @Focuslinkstech

View File

@ -11,7 +11,9 @@ if (realpath(__FILE__) == realpath($_SERVER['SCRIPT_FILENAME'])) {
die();
}
$root_path = realpath(dirname(__FILE__)) . DIRECTORY_SEPARATOR;
$isApi = false;
if (!isset($isApi)) {
$isApi = false;
}
// on some server, it getting error because of slash is backwards
function _autoloader($class)
{
@ -71,8 +73,11 @@ ORM::configure('return_result_sets', true);
if ($_app_stage != 'Live') {
ORM::configure('logging', true);
}
define('U', APP_URL . '/index.php?_route=');
if ($isApi) {
define('U', APP_URL . '/system/api.php?r=');
} else {
define('U', APP_URL . '/index.php?_route=');
}
// notification message
if (file_exists($UPLOAD_PATH . DIRECTORY_SEPARATOR . "notifications.json")) {
@ -195,7 +200,18 @@ function _log($description, $type = '', $userid = '0')
$d->type = $type;
$d->description = $description;
$d->userid = $userid;
$d->ip = $_SERVER["REMOTE_ADDR"];
if (!empty($_SERVER['HTTP_CF_CONNECTING_IP'])) //to check ip is pass from cloudflare tunnel
{
$d->ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) //to check ip is pass from proxy
{
$d->ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} elseif (!empty($_SERVER['HTTP_CLIENT_IP'])) //to check ip from share internet
{
$d->ip = $_SERVER['HTTP_CLIENT_IP'];
} else {
$d->ip = $_SERVER["REMOTE_ADDR"];
}
$d->save();
}
@ -206,9 +222,42 @@ function Lang($key)
function alphanumeric($str, $tambahan = "")
{
return preg_replace("/[^a-zA-Z0-9" . $tambahan . "]+/", "", $str);
return Text::alphanumeric($str, $tambahan);
}
function showResult($success, $message = '', $result = [], $meta = [])
{
header("Content-Type: Application/json");
$json = json_encode(['success' => $success, 'message' => $message, 'result' => $result, 'meta' => $meta]);
echo $json;
die();
}
function generateUniqueNumericVouchers($totalVouchers, $length = 8)
{
// Define characters allowed in the voucher code
$characters = '0123456789';
$charactersLength = strlen($characters);
$vouchers = array();
// Attempt to generate unique voucher codes
for ($j = 0; $j < $totalVouchers; $j++) {
do {
$voucherCode = '';
// Generate the voucher code
for ($i = 0; $i < $length; $i++) {
$voucherCode .= $characters[rand(0, $charactersLength - 1)];
}
// Check if the generated voucher code already exists in the array
$isUnique = !in_array($voucherCode, $vouchers);
} while (!$isUnique);
$vouchers[] = $voucherCode;
}
return $vouchers;
}
function sendTelegram($txt)
{
@ -227,6 +276,13 @@ function sendWhatsapp($phone, $txt)
function r2($to, $ntype = 'e', $msg = '')
{
global $isApi;
if ($isApi) {
showResult(
($ntype == 's') ? true : false,
$msg
);
}
if ($msg == '') {
header("location: $to");
exit;
@ -239,7 +295,13 @@ function r2($to, $ntype = 'e', $msg = '')
function _alert($text, $type = 'success', $url = "home", $time = 3)
{
global $ui;
global $ui, $isApi;
if ($isApi) {
showResult(
($type == 'success') ? true : false,
$text
);
}
if (!isset($ui)) return;
if (strlen($url) > 4) {
if (substr($url, 0, 4) != "http") {

View File

@ -21,13 +21,15 @@ CREATE TABLE `tbl_customers` (
`id` int(10) NOT NULL,
`username` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`password` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`pppoe_password` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1' COMMENT 'For PPPOE Login',
`pppoe_password` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login',
`fullname` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`address` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
`phonenumber` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0',
`email` varchar(128) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1',
`coordinates` VARCHAR(50) NOT NULL DEFAULT '' COMMENT 'Latitude and Longitude coordinates',
`balance` decimal(15,2) NOT NULL DEFAULT '0.00' COMMENT 'For Money Deposit',
`service_type` ENUM('Hotspot','PPPoE','Others') DEFAULT 'Others' COMMENT 'For selecting user type',
`account_type` ENUM('Business', 'Personal') DEFAULT 'Personal' COMMENT 'For selecting account type',
`auto_renewal` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'Auto renewall using balance',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_login` datetime DEFAULT NULL
@ -79,26 +81,27 @@ CREATE TABLE `tbl_payment_gateway` (
DROP TABLE IF EXISTS `tbl_plans`;
CREATE TABLE `tbl_plans` (
`id` int(10) NOT NULL,
`name_plan` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`id_bw` int(10) NOT NULL,
`price` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`type` enum('Hotspot','PPPOE','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`typebp` enum('Unlimited','Limited') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`limit_type` enum('Time_Limit','Data_Limit','Both_Limit') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`time_limit` int(10) UNSIGNED DEFAULT NULL,
`time_unit` enum('Mins','Hrs') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`data_limit` int(10) UNSIGNED DEFAULT NULL,
`data_unit` enum('MB','GB') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`validity` int(10) NOT NULL,
`validity_unit` enum('Mins','Hrs','Days','Months','Period') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`shared_users` int(10) DEFAULT NULL,
`routers` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`is_radius` tinyint(1) NOT NULL DEFAULT '0' COMMENT '1 is radius',
`pool` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`pool_expired` varchar(40) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`enabled` tinyint(1) NOT NULL DEFAULT '1' COMMENT '0 disabled\r\n',
`allow_purchase` enum('yes','no') DEFAULT 'yes' COMMENT 'allow to show package in buy package page'
`id` int(10) NOT NULL,
`name_plan` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`id_bw` int(10) NOT NULL,
`price` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`type` enum('Hotspot','PPPOE','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`typebp` enum('Unlimited','Limited') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`limit_type` enum('Time_Limit','Data_Limit','Both_Limit') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`time_limit` int(10) UNSIGNED DEFAULT NULL,
`time_unit` enum('Mins','Hrs') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`data_limit` int(10) UNSIGNED DEFAULT NULL,
`data_unit` enum('MB','GB') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`validity` int(10) NOT NULL,
`validity_unit` enum('Mins','Hrs','Days','Months','Period') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`shared_users` int(10) DEFAULT NULL,
`routers` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`is_radius` tinyint(1) NOT NULL DEFAULT '0' COMMENT '1 is radius',
`pool` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`pool_expired` varchar(40) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`enabled` tinyint(1) NOT NULL DEFAULT '1' COMMENT '0 disabled',
`allow_purchase` enum('yes','no') DEFAULT 'yes' COMMENT 'allow to show package in buy package page',
`plan_type` ENUM('Business', 'Personal') DEFAULT 'Personal' COMMENT 'For switching plan according to user type'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
DROP TABLE IF EXISTS `tbl_pool`;
@ -317,4 +320,5 @@ ALTER TABLE `tbl_bandwidth` ADD `burst` VARCHAR(128) NOT NULL DEFAULT '' AFTER `
ALTER TABLE `tbl_transactions` ADD `admin_id` INT NOT NULL DEFAULT '1' AFTER `type`;
ALTER TABLE `tbl_user_recharges` ADD `admin_id` INT NOT NULL DEFAULT '1' AFTER `type`;
ALTER TABLE `tbl_plans` CHANGE `allow_purchase` `prepaid` ENUM('yes','no') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'yes' COMMENT 'is prepaid';
ALTER TABLE `tbl_transactions` ADD `note` VARCHAR(256) NOT NULL DEFAULT '' COMMENT 'for note' AFTER `type`;
ALTER TABLE `tbl_transactions` ADD `note` VARCHAR(256) NOT NULL DEFAULT '' COMMENT 'for note' AFTER `type`;
ALTER TABLE `tbl_payment_gateway` ADD `trx_invoice` VARCHAR(25) NOT NULL DEFAULT '' COMMENT 'from tbl_transactions' AFTER `paid_date`;

View File

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

View File

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

View File

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

View File

@ -11,7 +11,9 @@ class Lang
public static function T($key)
{
global $_L, $lan_file, $config;
$_L = $_SESSION['Lang'];
if(is_array($_SESSION['Lang'])){
$_L = array_merge($_L, $_SESSION['Lang']);
}
$key = preg_replace('/\s+/', ' ', $key);
if (!empty($_L[$key])) {
return $_L[$key];

View File

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

View File

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

View File

@ -15,15 +15,17 @@ class Package
* @param int $plan_id plan id for this package
* @param string $gateway payment gateway name
* @param string $channel channel payment gateway
* @param array $pgids payment gateway ids
* @return boolean
*/
public static function rechargeUser($id_customer, $router_name, $plan_id, $gateway, $channel, $note = '')
{
global $config, $admin, $c, $p, $b, $t, $d, $zero;
global $config, $admin, $c, $p, $b, $t, $d, $zero, $trx;
$date_now = date("Y-m-d H:i:s");
$date_only = date("Y-m-d");
$time_only = date("H:i:s");
$time = date("H:i:s");
$inv = "";
if ($id_customer == '' or $router_name == '' or $plan_id == '') {
return false;
@ -44,6 +46,7 @@ class Package
foreach ($bills as $k => $v) {
$note .= $k . " : " . Lang::moneyFormat($v) . "\n";
}
$note .= $p['name_plan'] . " : " . Lang::moneyFormat($p['price']) . "\n";
}
}
@ -75,9 +78,8 @@ class Package
if ($router_name == 'balance') {
// insert table transactions
$inv = "INV-" . Package::_raid();
$t = ORM::for_table('tbl_transactions')->create();
$t->invoice = $inv;
$t->invoice = $inv = "INV-" . Package::_raid();
$t->username = $c['username'];
$t->plan_name = $p['name_plan'];
$t->price = $p['price'];
@ -148,7 +150,9 @@ class Package
->where('customer_id', $id_customer)
->where('tbl_user_recharges.routers', $router_name)
->where('tbl_user_recharges.Type', $p['type'])
->where('prepaid', $p['prepaid'])
# PPPOE or Hotspot only can have 1 per customer prepaid or postpaid
# because 1 customer can have 1 PPPOE and 1 Hotspot Plan in mikrotik
//->where('prepaid', $p['prepaid'])
->join('tbl_plans', array('tbl_plans.id', '=', 'tbl_user_recharges.plan_id'))
->find_one();
@ -164,14 +168,16 @@ class Package
$dt2 = new DateTime("$date_tmp");
$diff = $dt2->diff($dt1);
$sum = $diff->format("%a"); // => 453
if ($sum >= 35) {
if ($sum >= 35 * $p['validity']) {
$date_exp = date("Y-m-$day_exp", strtotime('+0 month'));
} else {
$date_exp = date("Y-m-$day_exp", strtotime('+' . $p['validity'] . ' month'));
};
$time = date("23:59:00");
} else if ($p['validity_unit'] == 'Days') {
$date_exp = date("Y-m-d", strtotime('+' . $p['validity'] . ' day'));
$datetime = explode(' ', date("Y-m-d H:i:s", strtotime('+' . $p['validity'] . ' day')));
$date_exp = $datetime[0];
$time = $datetime[1];
} else if ($p['validity_unit'] == 'Hrs') {
$datetime = explode(' ', date("Y-m-d H:i:s", strtotime('+' . $p['validity'] . ' hour')));
$date_exp = $datetime[0];
@ -181,9 +187,12 @@ class Package
$date_exp = $datetime[0];
$time = $datetime[1];
}
$isChangePlan = false;
if ($p['type'] == 'Hotspot') {
if ($b) {
if ($plan_id != $b['plan_id']) {
$isChangePlan = true;
}
if ($b['namebp'] == $p['name_plan'] && $b['status'] == 'on') {
// if it same internet plan, expired will extend
if ($p['validity_unit'] == 'Months') {
@ -206,13 +215,15 @@ class Package
}
}
if ($p['is_radius']) {
Radius::customerAddPlan($c, $p, "$date_exp $time");
} else {
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
Mikrotik::removeHotspotUser($client, $c['username']);
Mikrotik::removeHotspotActiveUser($client, $c['username']);
Mikrotik::addHotspotUser($client, $p, $c);
if ($isChangePlan || $b['status'] == 'off') {
if ($p['is_radius']) {
Radius::customerAddPlan($c, $p, "$date_exp $time");
} else {
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
Mikrotik::removeHotspotUser($client, $c['username']);
Mikrotik::removeHotspotActiveUser($client, $c['username']);
Mikrotik::addHotspotUser($client, $p, $c);
}
}
$b->customer_id = $id_customer;
@ -236,7 +247,7 @@ class Package
// insert table transactions
$t = ORM::for_table('tbl_transactions')->create();
$t->invoice = "INV-" . Package::_raid();
$t->invoice = $inv = "INV-" . Package::_raid();
$t->username = $c['username'];
$t->plan_name = $p['name_plan'];
if ($p['validity_unit'] == 'Period') {
@ -286,7 +297,7 @@ class Package
"\nRouter: " . $router_name .
"\nGateway: " . $gateway .
"\nChannel: " . $channel .
"\nPrice: " . Lang::moneyFormat($p['price']) .
"\nPrice: " . Lang::moneyFormat($p['price'] + $add_cost) .
"\nNote:\n" . $note);
} else {
if ($p['is_radius']) {
@ -320,7 +331,7 @@ class Package
// insert table transactions
$t = ORM::for_table('tbl_transactions')->create();
$t->invoice = "INV-" . Package::_raid();
$t->invoice = $inv = "INV-" . Package::_raid();
$t->username = $c['username'];
$t->plan_name = $p['name_plan'];
if ($p['validity_unit'] == 'Period') {
@ -356,7 +367,7 @@ class Package
$ed = new DateTime("$date_exp");
$td = $ed->diff($sd);
$fd = $td->format("%a");
$gi = ($p['price'] / 30) * $fd;
$gi = ($p['price'] / (30 * $p['validity'])) * $fd;
if ($gi > $p['price']) {
$fl->field_value = $p['price'];
} else {
@ -374,12 +385,15 @@ class Package
"\nRouter: " . $router_name .
"\nGateway: " . $gateway .
"\nChannel: " . $channel .
"\nPrice: " . Lang::moneyFormat($p['price']) .
"\nPrice: " . Lang::moneyFormat($p['price'] + $add_cost) .
"\nNote:\n" . $note);
}
} else {
if ($b) {
if ($plan_id != $b['plan_id']) {
$isChangePlan = true;
}
if ($b['namebp'] == $p['name_plan'] && $b['status'] == 'on') {
// if it same internet plan, expired will extend
if ($p['validity_unit'] == 'Months') {
@ -402,13 +416,15 @@ class Package
}
}
if ($p['is_radius']) {
Radius::customerAddPlan($c, $p, "$date_exp $time");
} else {
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
Mikrotik::removePpoeUser($client, $c['username']);
Mikrotik::removePpoeActive($client, $c['username']);
Mikrotik::addPpoeUser($client, $p, $c);
if ($isChangePlan || $b['status'] == 'off') {
if ($p['is_radius']) {
Radius::customerAddPlan($c, $p, "$date_exp $time");
} else {
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
Mikrotik::removePpoeUser($client, $c['username']);
Mikrotik::removePpoeActive($client, $c['username']);
Mikrotik::addPpoeUser($client, $p, $c);
}
}
$b->customer_id = $id_customer;
@ -432,7 +448,7 @@ class Package
// insert table transactions
$t = ORM::for_table('tbl_transactions')->create();
$t->invoice = "INV-" . Package::_raid();
$t->invoice = $inv = "INV-" . Package::_raid();
$t->username = $c['username'];
$t->plan_name = $p['name_plan'];
if ($p['validity_unit'] == 'Period') {
@ -481,7 +497,7 @@ class Package
"\nRouter: " . $router_name .
"\nGateway: " . $gateway .
"\nChannel: " . $channel .
"\nPrice: " . Lang::moneyFormat($p['price']) .
"\nPrice: " . Lang::moneyFormat($p['price'] + $add_cost) .
"\nNote:\n" . $note);
} else {
if ($p['is_radius']) {
@ -515,12 +531,14 @@ class Package
// insert table transactions
$t = ORM::for_table('tbl_transactions')->create();
$t->invoice = "INV-" . Package::_raid();
$t->invoice = $inv = "INV-" . Package::_raid();
$t->username = $c['username'];
$t->plan_name = $p['name_plan'];
if ($p['validity_unit'] == 'Period') {
// Postpaid price always zero for first time
$t->price = 0 + $add_cost;
$note = '';
$bills = [];
$t->price = 0;
} else {
$t->price = $p['price'] + $add_cost;
}
@ -551,7 +569,7 @@ class Package
$ed = new DateTime("$date_exp");
$td = $ed->diff($sd);
$fd = $td->format("%a");
$gi = ($p['price'] / 30) * $fd;
$gi = ($p['price'] / (30 * $p['validity'])) * $fd;
if ($gi > $p['price']) {
$fl->field_value = $p['price'];
} else {
@ -569,7 +587,7 @@ class Package
"\nRouter: " . $router_name .
"\nGateway: " . $gateway .
"\nChannel: " . $channel .
"\nPrice: " . Lang::moneyFormat($p['price']) .
"\nPrice: " . Lang::moneyFormat($p['price'] + $add_cost) .
"\nNote:\n" . $note);
}
}
@ -578,7 +596,10 @@ class Package
}
run_hook("recharge_user_finish");
Message::sendInvoice($c, $t);
return true;
if ($trx) {
$trx->trx_invoice = $inv;
}
return $inv;
}
public static function changeTo($username, $plan_id, $from_id)
@ -685,6 +706,8 @@ class Package
} else {
$admin['fullname'] = 'Customer';
}
$cust = ORM::for_table('tbl_customers')->where('username', $in['username'])->findOne();
$note = '';
//print
$invoice = Lang::pad($config['CompanyName'], ' ', 2) . "\n";
@ -719,6 +742,9 @@ class Package
$invoice .= Lang::pad($note, ' ', 2) . "\n";
}
$invoice .= Lang::pad("", '=') . "\n";
if ($cust) {
$invoice .= Lang::pads(Lang::T('Full Name'), $cust['fullname'], ' ') . "\n";
}
$invoice .= Lang::pads(Lang::T('Username'), $in['username'], ' ') . "\n";
$invoice .= Lang::pads(Lang::T('Password'), '**********', ' ') . "\n";
if ($in['type'] != 'Balance') {
@ -760,6 +786,9 @@ class Package
$invoice .= Lang::pad($note, ' ', 2) . "\n";
}
$invoice .= Lang::pad("", '=') . "\n";
if ($cust) {
$invoice .= Lang::pads(Lang::T('Full Name'), $cust['fullname'], ' ') . "\n";
}
$invoice .= Lang::pads(Lang::T('Username'), $in['username'], ' ') . "\n";
$invoice .= Lang::pads(Lang::T('Password'), '**********', ' ') . "\n";
if ($in['type'] != 'Balance') {

View File

@ -1,14 +1,81 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
* PHP Mikrotik Billing (https://github.com/SiberTech/)
* by https://t.me/ibnux
**/
class Paginator
{
public static function build($table, $colVal = [], $query='', $per_page = '10')
public static function findMany($query, $search = [], $per_page = '10')
{
global $routes, $ui;
$adjacents = "2";
$page = _get('p', 1);
$page = (empty($page) ? 1 : $page);
$url = U . implode('/', $routes);
if (count($search) > 0) {
$url .= '&' . http_build_query($search);
}
$url .= '&p=';
$totalReq = $query->count();
$lastpage = ceil($totalReq / $per_page);
$lpm1 = $lastpage - 1;
$limit = $per_page;
$startpoint = ($page * $limit) - $limit;
if ($lastpage >= 1) {
$pages = [];
if ($lastpage < 7 + ($adjacents * 2)) {
for ($counter = 1; $counter <= $lastpage; $counter++) {
$pages[] = $counter;
}
} elseif ($lastpage > 5 + ($adjacents * 2)) {
if ($page < 1 + ($adjacents * 2)) {
for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++) {
$pages[] = $counter;
}
$pages[] = "...";
$pages[] = $lpm1;
$pages[] = $lastpage;
} elseif ($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2)) {
$pages[] = "1";
$pages[] = "2";
$pages[] = "...";
for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++) {
$pages[] = $counter;
}
$pages[] = "...";
$pages[] = $lpm1;
$pages[] = $lastpage;
} else {
$pages[] = "1";
$pages[] = "2";
$pages[] = "...";
for ($counter = $lastpage - (2 + ($adjacents * 2)); $counter <= $lastpage; $counter++) {
$pages[] = $counter;
}
}
}
$result = [
'count' => $lastpage,
'limit' => $per_page,
'startpoint' => $startpoint,
'url' => $url,
'page' => $page,
'pages' => $pages,
'prev' => ($page > 0) ? ($page - 1) : "0",
'next' => ($page >= $lastpage) ? $lastpage : $page + 1
];
if ($ui) {
$ui->assign('paginator', $result);
}
return $query->offset($startpoint)->limit($per_page)->find_many();
}
}
public static function build($table, $colVal = [], $query = '', $per_page = '10')
{
global $routes;
global $_L;
@ -17,13 +84,13 @@ class Paginator
$adjacents = "2";
$page = (int)(empty(_get('p')) ? 1 : _get('p'));
$pagination = "";
foreach($colVal as $k=>$v) {
if(!is_array($v) && strpos($v,'%') === false) {
foreach ($colVal as $k => $v) {
if (!is_array($v) && strpos($v, '%') === false) {
$table = $table->where($k, $v);
}else{
if(is_array($v)){
} else {
if (is_array($v)) {
$table = $table->where_in($k, $v);
}else{
} else {
$table = $table->where_like($k, $v);
}
}
@ -36,60 +103,60 @@ class Paginator
$limit = $per_page;
$startpoint = ($page * $limit) - $limit;
if ($lastpage >= 1) {
$pagination .= '<ul class="pagination pagination-sm">';
$pagination .= '<ul class="pagination">';
if ($lastpage < 7 + ($adjacents * 2)) {
for ($counter = 1; $counter <= $lastpage; $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>";
$pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}&p=$counter&q=$query'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$counter&q=$query'>$counter</a></li>";
}
} elseif ($lastpage > 5 + ($adjacents * 2)) {
if ($page < 1 + ($adjacents * 2)) {
for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>";
$pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}&p=$counter&q=$query'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$counter&q=$query'>$counter</a></li>";
}
$pagination .= "<li class='disabled'><a href='#'>...</a></li>";
$pagination .= "<li><a href='{$url}&p=$lpm1&q=$query'>$lpm1</a></li>";
$pagination .= "<li><a href='{$url}&p=$lastpage&q=$query'>$lastpage</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$lpm1&q=$query'>$lpm1</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$lastpage&q=$query'>$lastpage</a></li>";
} elseif ($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2)) {
$pagination .= "<li><a href='{$url}&p=1&q=$query'>1</a></li>";
$pagination .= "<li><a href='{$url}&p=2&q=$query'>2</a></li>";
$pagination .= "<li class='disabled'><a href='#'>...</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=1&q=$query'>1</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=2&q=$query'>2</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>";
$pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}&p=$counter&q=$query'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$counter&q=$query'>$counter</a></li>";
}
$pagination .= "<li class='disabled'><a href='#'>...</a></li>";
$pagination .= "<li><a href='{$url}&p=$lpm1&q=$query'>$lpm1</a></li>";
$pagination .= "<li><a href='{$url}&p=$lastpage&q=$query'>$lastpage</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$lpm1&q=$query'>$lpm1</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$lastpage&q=$query'>$lastpage</a></li>";
} else {
$pagination .= "<li><a href='{$url}&p=1&q=$query'>1</a></li>";
$pagination .= "<li><a href='{$url}&p=2&q=$query'>2</a></li>";
$pagination .= "<li><a href='#'>...</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=1&q=$query'>1</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=2&q=$query'>2</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='#'>...</a></li>";
for ($counter = $lastpage - (2 + ($adjacents * 2)); $counter <= $lastpage; $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a class='disabled'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link disabled'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}&p=$counter&q=$query'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$counter&q=$query'>$counter</a></li>";
}
}
}
if ($page < $counter - 1) {
$pagination .= "<li><a href='{$url}&p=$next&q=$query'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li><a href='{$url}&p=$lastpage&q=$query'>" . Lang::T('Last') . "</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$next&q=$query'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$lastpage&q=$query'>" . Lang::T('Last') . "</a></li>";
} else {
$pagination .= "<li class='disabled'><a class='disabled'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li class='disabled'><a class='disabled'>" . Lang::T('Last') . "</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link disabled'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link disabled'>" . Lang::T('Last') . "</a></li>";
}
$pagination .= "</ul>";
$pagination = '<nav>' . $pagination . '</nav>';
return array("startpoint" => $startpoint, "limit" => $limit, "found" => $totalReq, "page" => $page, "lastpage" => $lastpage, "contents" => $pagination);
}
}
@ -103,7 +170,7 @@ class Paginator
$page = (int)(!isset($routes['2']) ? 1 : $routes['2']);
$pagination = "";
if(is_object($table)){
if (is_object($table)) {
if ($w1 != '') {
$totalReq = $table->where($w1, $c1)->count();
} elseif ($w2 != '') {
@ -115,7 +182,7 @@ class Paginator
} else {
$totalReq = $table->count();
}
}else{
} else {
if ($w1 != '') {
$totalReq = ORM::for_table($table)->where($w1, $c1)->count();
} elseif ($w2 != '') {
@ -142,59 +209,60 @@ class Paginator
$startpoint = ($page * $limit) - $limit;
if ($lastpage >= 1) {
$pagination .= '<ul class="pagination pagination-sm">';
$pagination .= '<ul class="pagination">';
if ($lastpage < 7 + ($adjacents * 2)) {
for ($counter = 1; $counter <= $lastpage; $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>";
$pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$counter'>$counter</a></li>";
}
} elseif ($lastpage > 5 + ($adjacents * 2)) {
if ($page < 1 + ($adjacents * 2)) {
for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>";
$pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$counter'>$counter</a></li>";
}
$pagination .= "<li class='disabled'><a href='#'>...</a></li>";
$pagination .= "<li><a href='{$url}$lpm1'>$lpm1</a></li>";
$pagination .= "<li><a href='{$url}$lastpage'>$lastpage</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lpm1'>$lpm1</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lastpage'>$lastpage</a></li>";
} elseif ($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2)) {
$pagination .= "<li><a href='{$url}1'>1</a></li>";
$pagination .= "<li><a href='{$url}2'>2</a></li>";
$pagination .= "<li class='disabled'><a href='#'>...</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}1'>1</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}2'>2</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>";
$pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$counter'>$counter</a></li>";
}
$pagination .= "<li class='disabled'><a href='#'>...</a></li>";
$pagination .= "<li><a href='{$url}$lpm1'>$lpm1</a></li>";
$pagination .= "<li><a href='{$url}$lastpage'>$lastpage</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lpm1'>$lpm1</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lastpage'>$lastpage</a></li>";
} else {
$pagination .= "<li><a href='{$url}1'>1</a></li>";
$pagination .= "<li><a href='{$url}2'>2</a></li>";
$pagination .= "<li><a href='#'>...</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}1'>1</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}2'>2</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='#'>...</a></li>";
for ($counter = $lastpage - (2 + ($adjacents * 2)); $counter <= $lastpage; $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a class='disabled'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link disabled'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$counter'>$counter</a></li>";
}
}
}
if ($page < $counter - 1) {
$pagination .= "<li><a href='{$url}$next'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li><a href='{$url}$lastpage'>" . Lang::T('Last') . "</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$next'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lastpage'>" . Lang::T('Last') . "</a></li>";
} else {
$pagination .= "<li class='disabled'><a class='disabled'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li class='disabled'><a class='disabled'>" . Lang::T('Last') . "</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link disabled'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link disabled'>" . Lang::T('Last') . "</a></li>";
}
$pagination .= "</ul>";
$pagination = '<nav>' . $pagination . '</nav>';
$gen = array("startpoint" => $startpoint, "limit" => $limit, "found" => $totalReq, "page" => $page, "lastpage" => $lastpage, "contents" => $pagination);
return $gen;
@ -209,13 +277,13 @@ class Paginator
$adjacents = "2";
$page = (int)(!isset($routes['2']) ? 1 : $routes['2']);
$pagination = "";
if(is_object($table)){
if (is_object($table)) {
if ($w1 != '') {
$totalReq = $table->where_raw($w1, $c1)->count();
} else {
$totalReq = $table->count();
}
}else{
} else {
if ($w1 != '') {
$totalReq = ORM::for_table($table)->where_raw($w1, $c1)->count();
} else {
@ -236,59 +304,60 @@ class Paginator
$startpoint = ($page * $limit) - $limit;
if ($lastpage >= 1) {
$pagination .= '<ul class="pagination pagination-sm">';
$pagination .= '<ul class="pagination">';
if ($lastpage < 7 + ($adjacents * 2)) {
for ($counter = 1; $counter <= $lastpage; $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>";
$pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$counter'>$counter</a></li>";
}
} elseif ($lastpage > 5 + ($adjacents * 2)) {
if ($page < 1 + ($adjacents * 2)) {
for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>";
$pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$counter'>$counter</a></li>";
}
$pagination .= "<li class='disabled'><a href='#'>...</a></li>";
$pagination .= "<li><a href='{$url}$lpm1'>$lpm1</a></li>";
$pagination .= "<li><a href='{$url}$lastpage'>$lastpage</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lpm1'>$lpm1</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lastpage'>$lastpage</a></li>";
} elseif ($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2)) {
$pagination .= "<li><a href='{$url}1'>1</a></li>";
$pagination .= "<li><a href='{$url}2'>2</a></li>";
$pagination .= "<li class='disabled'><a href='#'>...</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}1'>1</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}2'>2</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>";
$pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$counter'>$counter</a></li>";
}
$pagination .= "<li class='disabled'><a href='#'>...</a></li>";
$pagination .= "<li><a href='{$url}$lpm1'>$lpm1</a></li>";
$pagination .= "<li><a href='{$url}$lastpage'>$lastpage</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lpm1'>$lpm1</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lastpage'>$lastpage</a></li>";
} else {
$pagination .= "<li><a href='{$url}1'>1</a></li>";
$pagination .= "<li><a href='{$url}2'>2</a></li>";
$pagination .= "<li><a href='#'>...</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}1'>1</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}2'>2</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='#'>...</a></li>";
for ($counter = $lastpage - (2 + ($adjacents * 2)); $counter <= $lastpage; $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a class='disabled'>$counter</a></li>";
$pagination .= "<li class='page-item active'><a class='page-item disabled'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$counter'>$counter</a></li>";
}
}
}
if ($page < $counter - 1) {
$pagination .= "<li><a href='{$url}$next'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li><a href='{$url}$lastpage'>" . Lang::T('Last') . "</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$next'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lastpage'>" . Lang::T('Last') . "</a></li>";
} else {
$pagination .= "<li class='disabled'><a class='disabled'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li class='disabled'><a class='disabled'>" . Lang::T('Last') . "</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-item disabled'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-item disabled'>" . Lang::T('Last') . "</a></li>";
}
$pagination .= "</ul>";
$pagination = '<nav>' . $pagination . '</nav>';
$gen = array("startpoint" => $startpoint, "limit" => $limit, "found" => $totalReq, "page" => $page, "lastpage" => $lastpage, "contents" => $pagination);
return $gen;

View File

@ -30,7 +30,10 @@ class Radius
{
return ORM::for_table('nas', 'radius');
}
public static function getTableAcct()
{
return ORM::for_table('radacct', 'radius');
}
public static function getTableCustomer()
{
return ORM::for_table('radcheck', 'radius');
@ -88,9 +91,16 @@ class Radius
public static function planUpSert($plan_id, $rate, $pool = null)
{
$rates = explode('/', $rate);
##burst fixed
if (strpos($rate, ' ')) {
$ratos = $rates[0].'/'.$rates[1].' '.$rates[2].'/'.$rates[3].'/'.$rates[4].'/'.$rates[5].'/'.$rates[6];
} else {
$ratos = $rates[0].'/'.$rates[1];
}
Radius::upsertPackage($plan_id, 'Ascend-Data-Rate', $rates[1], ':=');
Radius::upsertPackage($plan_id, 'Ascend-Xmit-Rate', $rates[0], ':=');
Radius::upsertPackage($plan_id, 'Mikrotik-Rate-Limit', $rate, ':=');
Radius::upsertPackage($plan_id, 'Mikrotik-Rate-Limit', $ratos, ':=');
// if ($pool != null) {
// Radius::upsertPackage($plan_id, 'Framed-Pool', $pool, ':=');
// }
@ -161,6 +171,8 @@ class Radius
$p = Radius::getTableUserPackage()->where_equal('username', $customer['username'])->findOne();
if ($p) {
// if exists
Radius::delAtribute(Radius::getTableCustomer(), 'Max-All-Session', 'username', $customer['username']);
Radius::delAtribute(Radius::getTableCustomer(), 'Max-Data', 'username', $customer['username']);
$p->groupname = "plan_" . $plan['id'];
$p->save();
} else {
@ -176,7 +188,7 @@ class Radius
$timelimit = $plan['time_limit'] * 60 * 60;
else
$timelimit = $plan['time_limit'] * 60;
Radius::upsertCustomer($customer['username'], 'Expire-After', $timelimit);
Radius::upsertCustomer($customer['username'], 'Max-All-Session', $timelimit);
} else if ($plan['limit_type'] == "Data_Limit") {
if ($plan['data_unit'] == 'GB')
$datalimit = $plan['data_limit'] . "000000000";
@ -184,29 +196,40 @@ class Radius
$datalimit = $plan['data_limit'] . "000000";
//Radius::upsertCustomer($customer['username'], 'Max-Volume', $datalimit);
// Mikrotik Spesific
Radius::upsertCustomer($customer['username'], 'Mikrotik-Total-Limit', $datalimit);
Radius::upsertCustomer($customer['username'], 'Max-Data', $datalimit);
} else if ($plan['limit_type'] == "Both_Limit") {
if ($plan['time_unit'] == 'Hrs')
$timelimit = $plan['time_limit'] * 60 * 60;
else
$timelimit = $plan['time_limit'] . ":00";
$timelimit = $plan['time_limit'] * 60;
if ($plan['data_unit'] == 'GB')
$datalimit = $plan['data_limit'] . "000000000";
else
$datalimit = $plan['data_limit'] . "000000";
//Radius::upsertCustomer($customer['username'], 'Max-Volume', $datalimit);
Radius::upsertCustomer($customer['username'], 'Expire-After', $timelimit);
Radius::upsertCustomer($customer['username'], 'Max-All-Session', $timelimit);
// Mikrotik Spesific
Radius::upsertCustomer($customer['username'], 'Mikrotik-Total-Limit', $datalimit);
Radius::upsertCustomer($customer['username'], 'Max-Data', $datalimit);
}
} else {
//Radius::delAtribute(Radius::getTableCustomer(), 'Max-Volume', 'username', $customer['username']);
Radius::delAtribute(Radius::getTableCustomer(), 'Expire-After', 'username', $customer['username']);
Radius::delAtribute(Radius::getTableCustomer(), 'Mikrotik-Total-Limit', 'username', $customer['username']);
Radius::delAtribute(Radius::getTableCustomer(), 'Max-All-Session', 'username', $customer['username']);
Radius::delAtribute(Radius::getTableCustomer(), 'Max-Data', 'username', $customer['username']);
}
Radius::disconnectCustomer($customer['username']);
Radius::getTableAcct()->where_equal('username', $customer['username'])->delete_many();
// expired user
if ($expired != null) {
//Radius::upsertCustomer($customer['username'], 'access-period', strtotime($expired) - time());
//Radius::upsertCustomer($customer['username'], 'Max-All-Session', strtotime($expired) - time());
Radius::upsertCustomer($customer['username'], 'expiration', date('d M Y H:i:s', strtotime($expired)));
// Mikrotik Spesific
Radius::upsertCustomer(
@ -215,13 +238,15 @@ class Radius
date('Y-m-d', strtotime($expired)) . 'T' . date('H:i:s', strtotime($expired)) . Timezone::getTimeOffset($config['timezone'])
);
} else {
//Radius::delAtribute(Radius::getTableCustomer(), 'access-period', 'username', $customer['username']);
//Radius::delAtribute(Radius::getTableCustomer(), 'Max-All-Session', 'username', $customer['username']);
Radius::delAtribute(Radius::getTableCustomer(), 'expiration', 'username', $customer['username']);
}
if ($plan['type'] == 'PPPOE') {
Radius::upsertCustomerAttr($customer['username'], 'Framed-Pool', $plan['pool'], ':=');
}
return true;
}
return false;
@ -267,7 +292,7 @@ class Radius
/**
* To insert or update existing customer
*/
private static function upsertCustomer($username, $attr, $value, $op = ':=')
public static function upsertCustomer($username, $attr, $value, $op = ':=')
{
$r = Radius::getTableCustomer()->where_equal('username', $username)->whereEqual('attribute', $attr)->find_one();
if (!$r) {

64
system/autoload/Text.php Normal file
View File

@ -0,0 +1,64 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
* by https://t.me/ibnux
*
* This file is for Text Transformation
**/
class Text
{
public static function toHex($string)
{
return "\x" . implode("\x", str_split(array_shift(unpack('H*', $string)), 2));
}
public static function alphanumeric($str, $tambahan = "")
{
return preg_replace("/[^a-zA-Z0-9" . $tambahan . "]+/", "", $str);
}
public static function numeric($str)
{
return preg_replace("/[^0-9]+/", "", $str);
}
public static function ucWords($text)
{
return ucwords(str_replace('_', ' ', $text));
}
public static function randomUpLowCase($text)
{
$jml = strlen($text);
$result = '';
for ($i = 0; $i < $jml; $i++) {
if (rand(0, 99) % 2) {
$result .= strtolower(substr($text, $i, 1));
} else {
$result .= substr($text, $i, 1);
}
}
return $result;
}
public static function maskText($text){
$len = strlen($text);
if($len < 3){
return "***";
}else if($len<5){
return substr($text,0,1)."***".substr($text,-1,1);
}else if($len<8){
return substr($text,0,2)."***".substr($text,-2,2);
}else{
return substr($text,0,4)."******".substr($text,-3,3);
}
}
public static function sanitize($str)
{
return preg_replace("/[^A-Za-z0-9]/", '_', $str);;
}
}

View File

@ -74,7 +74,7 @@ class User
list($cost, $rem) = explode(":", $v);
// :0 installment is done
if ($rem != 0) {
User::setAttribute($k, "$cost:".($rem - 1), $id);
User::setAttribute($k, "$cost:" . ($rem - 1), $id);
}
}
}
@ -177,20 +177,13 @@ class User
}
$d = ORM::for_table('tbl_user_recharges')
->select('tbl_user_recharges.id', 'id')
->select('customer_id')
->select('username')
->select('plan_id')
->select('namebp')
->select('recharged_on')
->select('recharged_time')
->select('expiration')
->select('time')
->select('status')
->select('method')
->select('tbl_user_recharges.routers', 'routers')
->select('tbl_user_recharges.type', 'type')
->select('admin_id')
->select('prepaid')
->selects([
'customer_id', 'username', 'plan_id', 'namebp', 'recharged_on', 'recharged_time', 'expiration', 'time',
'status', 'method', 'plan_type',
['tbl_user_recharges.routers', 'routers'],
['tbl_user_recharges.type', 'type'],
'admin_id', 'prepaid'
])
->where('customer_id', $id)
->join('tbl_plans', array('tbl_plans.id', '=', 'tbl_user_recharges.plan_id'))
->find_many();

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -84,7 +84,6 @@ switch ($action) {
}
echo json_encode(['results' => $json]);
die();
break;
default:
$ui->display('a404.tpl');
}

View File

@ -1,4 +1,5 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
* by https://t.me/ibnux
@ -12,30 +13,29 @@ $action = $routes['1'];
$ui->assign('_admin', $admin);
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
r2(U."dashboard",'e',Lang::T('You do not have permission to access this page'));
r2(U . "dashboard", 'e', Lang::T('You do not have permission to access this page'));
}
switch ($action) {
case 'list':
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/bandwidth.js"></script>');
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/bandwidth.js"></script>');
run_hook('view_list_bandwidth'); #HOOK
$name = _post('name');
if ($name != ''){
$paginator = Paginator::build(ORM::for_table('tbl_bandwidth'), ['name_bw' => '%' . $name . '%'], $name);
$d = ORM::for_table('tbl_bandwidth')->where_like('name_bw','%'.$name.'%')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many();
}else{
$paginator = Paginator::build(ORM::for_table('tbl_bandwidth'));
$d = ORM::for_table('tbl_bandwidth')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many();
}
$name = _post('name');
if ($name != '') {
$query = ORM::for_table('tbl_bandwidth')->where_like('name_bw', '%' . $name . '%')->order_by_desc('id');
$d = Paginator::findMany($query, ['name' => $name]);
} else {
$query = ORM::for_table('tbl_bandwidth')->order_by_desc('id');
$d = Paginator::findMany($query);
}
$ui->assign('d',$d);
$ui->assign('paginator',$paginator);
$ui->assign('d', $d);
$ui->display('bandwidth.tpl');
break;
case 'add':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'),'danger', "dashboard");
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
run_hook('view_add_bandwidth'); #HOOK
$ui->display('bandwidth-add.tpl');
@ -43,28 +43,28 @@ switch ($action) {
case 'edit':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'),'danger', "dashboard");
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
$id = $routes['2'];
run_hook('view_edit_bandwith'); #HOOK
$d = ORM::for_table('tbl_bandwidth')->find_one($id);
if($d){
$ui->assign('burst',explode(" ", $d['burst']));
$ui->assign('d',$d);
if ($d) {
$ui->assign('burst', explode(" ", $d['burst']));
$ui->assign('d', $d);
$ui->display('bandwidth-edit.tpl');
}else{
r2(U . 'bandwidth/list', 'e', $_L['Account_Not_Found']);
} else {
r2(U . 'bandwidth/list', 'e', Lang::T('Account Not Found'));
}
break;
case 'delete':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'),'danger', "dashboard");
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
$id = $routes['2'];
run_hook('delete_bandwidth'); #HOOK
$d = ORM::for_table('tbl_bandwidth')->find_one($id);
if($d){
if ($d) {
$d->delete();
r2(U . 'bandwidth/list', 's', Lang::T('Data Deleted Successfully'));
}
@ -72,40 +72,48 @@ switch ($action) {
case 'add-post':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'),'danger', "dashboard");
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
$name = _post('name');
$rate_down = _post('rate_down');
$rate_down_unit = _post('rate_down_unit');
$rate_up = _post('rate_up');
$rate_up_unit = _post('rate_up_unit');
$rate_up = _post('rate_up');
$rate_up_unit = _post('rate_up_unit');
run_hook('add_bandwidth'); #HOOK
$isBurst = true;
$burst = "";
if(isset($_POST['burst'])){
foreach($_POST['burst'] as $b){
if(empty($b)){
if (isset($_POST['burst'])) {
foreach ($_POST['burst'] as $b) {
if (empty($b)) {
$isBurst = false;
}
}
if($isBurst){
if ($isBurst) {
$burst = implode(' ', $_POST['burst']);
};
}
$msg = '';
if(Validator::Length($name,16,4) == false){
$msg .= 'Name should be between 5 to 15 characters'. '<br>';
if (Validator::Length($name, 16, 4) == false) {
$msg .= 'Name should be between 5 to 15 characters' . '<br>';
}
if($rate_down_unit == 'Kbps'){ $unit_rate_down = $rate_down * 1024; }else{ $unit_rate_down = $rate_down * 1048576; }
if($rate_up_unit == 'Kbps'){ $unit_rate_up = $min_up * 1024; }else{ $unit_rate_up = $min_up * 1048576; }
$d = ORM::for_table('tbl_bandwidth')->where('name_bw',$name)->find_one();
if($d){
$msg .= Lang::T('Name Bandwidth Already Exist'). '<br>';
if ($rate_down_unit == 'Kbps') {
$unit_rate_down = $rate_down * 1024;
} else {
$unit_rate_down = $rate_down * 1048576;
}
if ($rate_up_unit == 'Kbps') {
$unit_rate_up = $min_up * 1024;
} else {
$unit_rate_up = $min_up * 1048576;
}
if($msg == ''){
$d = ORM::for_table('tbl_bandwidth')->where('name_bw', $name)->find_one();
if ($d) {
$msg .= Lang::T('Name Bandwidth Already Exist') . '<br>';
}
if ($msg == '') {
$d = ORM::for_table('tbl_bandwidth')->create();
$d->name_bw = $name;
$d->rate_down = $rate_down;
@ -116,53 +124,53 @@ switch ($action) {
$d->save();
r2(U . 'bandwidth/list', 's', Lang::T('Data Created Successfully'));
}else{
} else {
r2(U . 'bandwidth/add', 'e', $msg);
}
break;
case 'edit-post':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'),'danger', "dashboard");
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
$name = _post('name');
$rate_down = _post('rate_down');
$rate_down_unit = _post('rate_down_unit');
$rate_up = _post('rate_up');
$rate_up_unit = _post('rate_up_unit');
run_hook('edit_bandwidth'); #HOOK
$rate_up = _post('rate_up');
$rate_up_unit = _post('rate_up_unit');
run_hook('edit_bandwidth'); #HOOK
$isBurst = true;
$burst = "";
if(isset($_POST['burst'])){
foreach($_POST['burst'] as $b){
if(empty($b)){
if (isset($_POST['burst'])) {
foreach ($_POST['burst'] as $b) {
if (empty($b)) {
$isBurst = false;
}
}
if($isBurst){
if ($isBurst) {
$burst = implode(' ', $_POST['burst']);
};
}
$msg = '';
if(Validator::Length($name,16,4) == false){
$msg .= 'Name should be between 5 to 15 characters'. '<br>';
if (Validator::Length($name, 16, 4) == false) {
$msg .= 'Name should be between 5 to 15 characters' . '<br>';
}
$id = _post('id');
$d = ORM::for_table('tbl_bandwidth')->find_one($id);
if($d){
}else{
$msg .= Lang::T('Data Not Found'). '<br>';
if ($d) {
} else {
$msg .= Lang::T('Data Not Found') . '<br>';
}
if($d['name_bw'] != $name){
$c = ORM::for_table('tbl_bandwidth')->where('name_bw',$name)->find_one();
if($c){
$msg .= Lang::T('Name Bandwidth Already Exist'). '<br>';
if ($d['name_bw'] != $name) {
$c = ORM::for_table('tbl_bandwidth')->where('name_bw', $name)->find_one();
if ($c) {
$msg .= Lang::T('Name Bandwidth Already Exist') . '<br>';
}
}
if($msg == ''){
if ($msg == '') {
$d->name_bw = $name;
$d->rate_down = $rate_down;
$d->rate_down_unit = $rate_down_unit;
@ -172,11 +180,11 @@ switch ($action) {
$d->save();
r2(U . 'bandwidth/list', 's', Lang::T('Data Updated Successfully'));
}else{
r2(U . 'bandwidth/edit/'.$id, 'e', $msg);
} else {
r2(U . 'bandwidth/edit/' . $id, 'e', $msg);
}
break;
default:
$ui->display('a404.tpl');
}
}

View File

@ -16,53 +16,28 @@ if (empty($action)) {
$action = 'list';
}
$leafletpickerHeader = <<<EOT
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css">
EOT;
switch ($action) {
case 'list':
$search = _post('search');
run_hook('list_customers'); #HOOK
if ($search != '') {
$paginator = Paginator::build(ORM::for_table('tbl_customers'), [
'username' => '%' . $search . '%',
'fullname' => '%' . $search . '%',
'phonenumber' => '%' . $search . '%',
'email' => '%' . $search . '%',
'service_type' => '%' . $search . '%'
], $search);
$d = ORM::for_table('tbl_customers')
->where_raw("(`username` LIKE '%$search%' OR `fullname` LIKE '%$search%' OR `phonenumber` LIKE '%$search%' OR `email` LIKE '%$search%')")
->offset($paginator['startpoint'])
->limit($paginator['limit'])
->order_by_asc('username')
->find_many();
} else {
$paginator = Paginator::build(ORM::for_table('tbl_customers'));
$d = ORM::for_table('tbl_customers')
->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many();
}
$ui->assign('search', htmlspecialchars($search));
$ui->assign('d', $d);
$ui->assign('paginator', $paginator);
$ui->display('customers.tpl');
break;
case 'csv':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
$cs = ORM::for_table('tbl_customers')
->select('tbl_customers.id', 'id')
->select('tbl_customers.username', 'username')
->select('fullname')
->select('address')
->select('phonenumber')
->select('email')
->select('balance')
->select('namebp')
->select('routers')
->select('status')
->select('method', 'Payment')
->join('tbl_user_recharges', array('tbl_customers.id', '=', 'tbl_user_recharges.customer_id'))
->order_by_asc('tbl_customers.id')->find_array();
->select('service_type')
->order_by_asc('tbl_customers.id')
->find_array();
$h = false;
set_time_limit(-1);
header('Pragma: public');
@ -71,24 +46,112 @@ switch ($action) {
header("Content-type: text/csv");
header('Content-Disposition: attachment;filename="phpnuxbill_customers_' . date('Y-m-d_H_i') . '.csv"');
header('Content-Transfer-Encoding: binary');
$headers = [
'id',
'username',
'fullname',
'address',
'phonenumber',
'email',
'balance',
'service_type',
];
if (!$h) {
echo '"' . implode('","', $headers) . "\"\n";
$h = true;
}
foreach ($cs as $c) {
$ks = [];
$vs = [];
foreach ($c as $k => $v) {
$ks[] = $k;
$vs[] = $v;
}
if (!$h) {
echo '"' . implode('";"', $ks) . "\"\n";
$h = true;
}
echo '"' . implode('";"', $vs) . "\"\n";
$row = [
$c['id'],
$c['username'],
$c['fullname'],
$c['address'],
$c['phonenumber'],
$c['email'],
$c['balance'],
$c['service_type'],
];
echo '"' . implode('","', $row) . "\"\n";
}
break;
//case csv-prepaid can be moved later to (plan.php) php file dealing with prepaid users
case 'csv-prepaid':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
$cs = ORM::for_table('tbl_customers')
->select('tbl_customers.id', 'id')
->select('tbl_customers.username', 'username')
->select('fullname')
->select('address')
->select('phonenumber')
->select('email')
->select('balance')
->select('service_type')
->select('namebp')
->select('routers')
->select('status')
->select('method', 'Payment')
->join('tbl_user_recharges', array('tbl_customers.id', '=', 'tbl_user_recharges.customer_id'))
->order_by_asc('tbl_customers.id')
->find_array();
$h = false;
set_time_limit(-1);
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-type: text/csv");
header('Content-Disposition: attachment;filename="phpnuxbill_prepaid_users' . date('Y-m-d_H_i') . '.csv"');
header('Content-Transfer-Encoding: binary');
$headers = [
'id',
'username',
'fullname',
'address',
'phonenumber',
'email',
'balance',
'service_type',
'namebp',
'routers',
'status',
'Payment'
];
if (!$h) {
echo '"' . implode('","', $headers) . "\"\n";
$h = true;
}
foreach ($cs as $c) {
$row = [
$c['id'],
$c['username'],
$c['fullname'],
$c['address'],
$c['phonenumber'],
$c['email'],
$c['balance'],
$c['service_type'],
$c['namebp'],
$c['routers'],
$c['status'],
$c['Payment']
];
echo '"' . implode('","', $row) . "\"\n";
}
break;
case 'add':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
$ui->assign('xheader', $leafletpickerHeader);
run_hook('view_add_customer'); #HOOK
$ui->display('customers-add.tpl');
break;
@ -96,8 +159,8 @@ switch ($action) {
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
$id_customer = $routes['2'];
$plan_id = $routes['3'];
$id_customer = $routes['2'];
$plan_id = $routes['3'];
$b = ORM::for_table('tbl_user_recharges')->where('customer_id', $id_customer)->where('plan_id', $plan_id)->find_one();
if ($b) {
$gateway = 'Recharge';
@ -130,7 +193,7 @@ switch ($action) {
$ui->assign('using', 'cash');
$ui->assign('plan', $plan);
$ui->display('recharge-confirm.tpl');
}else{
} else {
r2(U . 'customers/view/' . $id_customer, 'e', 'Cannot find active plan');
}
break;
@ -138,8 +201,8 @@ switch ($action) {
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
$id_customer = $routes['2'];
$plan_id = $routes['3'];
$id_customer = $routes['2'];
$plan_id = $routes['3'];
$b = ORM::for_table('tbl_user_recharges')->where('customer_id', $id_customer)->where('plan_id', $plan_id)->find_one();
if ($b) {
$p = ORM::for_table('tbl_plans')->where('id', $b['plan_id'])->find_one();
@ -169,7 +232,7 @@ switch ($action) {
r2(U . 'customers/view/' . $id_customer, 'e', 'Cannot find active plan');
break;
case 'sync':
$id_customer = $routes['2'];
$id_customer = $routes['2'];
$bs = ORM::for_table('tbl_user_recharges')->where('customer_id', $id_customer)->where('status', 'on')->findMany();
if ($bs) {
$routers = [];
@ -191,14 +254,14 @@ switch ($action) {
}
}
}
r2(U . 'customers/view/' . $id_customer, 's', 'Sync success to '.implode(", ",$routers));
r2(U . 'customers/view/' . $id_customer, 's', 'Sync success to ' . implode(", ", $routers));
}
r2(U . 'customers/view/' . $id_customer, 'e', 'Cannot find active plan');
break;
case 'viewu':
$customer = ORM::for_table('tbl_customers')->where('username', $routes['2'])->find_one();
case 'view':
$id = $routes['2'];
$id = $routes['2'];
run_hook('view_customer'); #HOOK
if (!$customer) {
$customer = ORM::for_table('tbl_customers')->find_one($id);
@ -210,47 +273,35 @@ switch ($action) {
$customFields = ORM::for_table('tbl_customers_fields')
->where('customer_id', $customer['id'])
->find_many();
$v = $routes['3'];
if(empty($v)){
$v = $routes['3'];
if (empty($v)) {
$v = 'activation';
}
if ($v == 'order') {
$v = 'order';
$paginator = Paginator::build(ORM::for_table('tbl_payment_gateway'), ['username' => $customer['username']]);
$order = ORM::for_table('tbl_payment_gateway')
->where('username', $customer['username'])
->offset($paginator['startpoint'])
->limit($paginator['limit'])
->order_by_desc('id')
->find_many();
$ui->assign('paginator', $paginator);
$query = ORM::for_table('tbl_transactions')->where('username', $customer['username'])->order_by_desc('id');
$order = Paginator::findMany($query);
$ui->assign('order', $order);
} else if ($v == 'activation') {
$paginator = Paginator::build(ORM::for_table('tbl_transactions'), ['username' => $customer['username']]);
$activation = ORM::for_table('tbl_transactions')
->where('username', $customer['username'])
->offset($paginator['startpoint'])
->limit($paginator['limit'])
->order_by_desc('id')
->find_many();
$ui->assign('paginator', $paginator);
$query = ORM::for_table('tbl_transactions')->where('username', $customer['username'])->order_by_desc('id');
$activation = Paginator::findMany($query);
$ui->assign('activation', $activation);
}
$ui->assign('packages', User::_billing($customer['id']));
$ui->assign('v', $v);
$ui->assign('d', $customer);
$ui->assign('customFields', $customFields);
$ui->assign('xheader', $leafletpickerHeader);
$ui->display('customers-view.tpl');
} else {
r2(U . 'customers/list', 'e', $_L['Account_Not_Found']);
r2(U . 'customers/list', 'e', Lang::T('Account Not Found'));
}
break;
case 'edit':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
$id = $routes['2'];
$id = $routes['2'];
run_hook('edit_customer'); #HOOK
$d = ORM::for_table('tbl_customers')->find_one($id);
// Fetch the Customers Attributes values from the tbl_customers_fields table
@ -260,9 +311,10 @@ switch ($action) {
if ($d) {
$ui->assign('d', $d);
$ui->assign('customFields', $customFields);
$ui->assign('xheader', $leafletpickerHeader);
$ui->display('customers-edit.tpl');
} else {
r2(U . 'customers/list', 'e', $_L['Account_Not_Found']);
r2(U . 'customers/list', 'e', Lang::T('Account Not Found'));
}
break;
@ -270,7 +322,7 @@ switch ($action) {
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
$id = $routes['2'];
$id = $routes['2'];
run_hook('delete_customer'); #HOOK
$d = ORM::for_table('tbl_customers')->find_one($id);
if ($d) {
@ -309,7 +361,8 @@ switch ($action) {
} catch (Throwable $e) {
}
try {
if ($c) $c->delete();
if ($c)
$c->delete();
} catch (Exception $e) {
} catch (Throwable $e) {
}
@ -328,6 +381,8 @@ switch ($action) {
$address = _post('address');
$phonenumber = _post('phonenumber');
$service_type = _post('service_type');
$account_type = _post('account_type');
$coordinates = _post('coordinates');
//post Customers Attributes
$custom_field_names = (array) $_POST['custom_field_name'];
$custom_field_values = (array) $_POST['custom_field_value'];
@ -355,11 +410,13 @@ switch ($action) {
$d->password = $password;
$d->pppoe_password = $pppoe_password;
$d->email = $email;
$d->account_type = $account_type;
$d->fullname = $fullname;
$d->address = $address;
$d->created_by = $admin['id'];
$d->phonenumber = Lang::phoneFormat($phonenumber);
$d->service_type = $service_type;
$d->coordinates = $coordinates;
$d->save();
// Retrieve the customer ID of the newly created customer
@ -389,12 +446,14 @@ switch ($action) {
case 'edit-post':
$username = Lang::phoneFormat(_post('username'));
$fullname = _post('fullname');
$account_type = _post('account_type');
$password = _post('password');
$pppoe_password = _post('pppoe_password');
$email = _post('email');
$address = _post('address');
$phonenumber = Lang::phoneFormat(_post('phonenumber'));
$service_type = _post('service_type');
$coordinates = _post('coordinates');
run_hook('edit_customer'); #HOOK
$msg = '';
if (Validator::Length($username, 35, 2) == false) {
@ -422,8 +481,8 @@ switch ($action) {
}
$oldusername = $d['username'];
$oldPppoePassword = $d['password'];
$oldPassPassword = $d['pppoe_password'];
$oldPppoePassword = $d['password'];
$oldPassPassword = $d['pppoe_password'];
$userDiff = false;
$pppoeDiff = false;
$passDiff = false;
@ -451,9 +510,11 @@ switch ($action) {
$d->pppoe_password = $pppoe_password;
$d->fullname = $fullname;
$d->email = $email;
$d->account_type = $account_type;
$d->address = $address;
$d->phonenumber = $phonenumber;
$d->service_type = $service_type;
$d->coordinates = $coordinates;
$d->save();
@ -538,5 +599,21 @@ switch ($action) {
break;
default:
r2(U . 'customers/list', 'e', 'action not defined');
run_hook('list_customers'); #HOOK
$search = _post('search');
if ($search != '') {
$query = ORM::for_table('tbl_customers')
->whereRaw("username LIKE '%$search%' OR fullname LIKE '%$search%' OR address LIKE '%$search%' ".
"OR phonenumber LIKE '%$search%' OR email LIKE '%$search%' ")
->order_by_asc('username');
$d = $query->findMany();
} else {
$query = ORM::for_table('tbl_customers')->order_by_asc('username');
}
$d = $query->findMany();
$ui->assign('xheader', '<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.11.3/css/jquery.dataTables.min.css">');
$ui->assign('d', $d);
$ui->assign('search', $search);
$ui->display('customers.tpl');
break;
}

View File

@ -9,6 +9,17 @@ _admin();
$ui->assign('_title', Lang::T('Dashboard'));
$ui->assign('_admin', $admin);
if(isset($_GET['refresh'])){
$files = scandir($CACHE_PATH);
foreach ($files as $file) {
$ext = pathinfo($file, PATHINFO_EXTENSION);
if (is_file($CACHE_PATH . DIRECTORY_SEPARATOR . $file) && $ext == 'temp') {
unlink($CACHE_PATH . DIRECTORY_SEPARATOR . $file);
}
}
r2(U . 'dashboard', 's', 'Data Refreshed');
}
$fdate = date('Y-m-01');
$tdate = date('Y-m-t');
//first day of month
@ -19,7 +30,7 @@ $month_n = date('n');
$iday = ORM::for_table('tbl_transactions')
->where('recharged_on', $mdate)
->where_not_equal('method', 'Customer - Balance')
->where_not_equal('method', 'Recharge Balance - Administrator')
->where_not_equal('method', 'Recharge Balance - Administrator')
->sum('price');
if ($iday == '') {
@ -54,13 +65,10 @@ $ui->assign('c_all', $c_all);
if ($config['hide_uet'] != 'yes') {
//user expire
$paginator = Paginator::build(ORM::for_table('tbl_user_recharges'));
$expire = ORM::for_table('tbl_user_recharges')
$query = ORM::for_table('tbl_user_recharges')
->where_lte('expiration', $mdate)
->offset($paginator['startpoint'])
->limit($paginator['limit'])
->order_by_desc('expiration')
->find_many();
->order_by_desc('expiration');
$expire = Paginator::findMany($query);
// Get the total count of expired records for pagination
$totalCount = ORM::for_table('tbl_user_recharges')
@ -71,7 +79,6 @@ if ($config['hide_uet'] != 'yes') {
$paginator['total_count'] = $totalCount;
// Assign the pagination HTML to the template variable
$ui->assign('paginator', $paginator);
$ui->assign('expire', $expire);
}
@ -150,7 +157,7 @@ if (file_exists($cacheMSfile) && time() - filemtime($cacheMSfile) < 43200) {
->select_expr('SUM(price)', 'total')
->where_raw("YEAR(recharged_on) = YEAR(CURRENT_DATE())") // Filter by the current year
->where_not_equal('method', 'Customer - Balance')
->where_not_equal('method', 'Recharge Balance - Administrator')
->where_not_equal('method', 'Recharge Balance - Administrator')
->group_by_expr('MONTH(recharged_on)')
->find_many();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -59,31 +59,7 @@ switch ($action) {
}
$log .= "DONE : $plan[username], $plan[namebp], $plan[type], $plan[routers]<br>";
}
if ($isApi) {
showResult(true, $log);
}
r2(U . 'plan/list', 's', $log);
case 'list':
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/plan.js"></script>');
$ui->assign('_title', Lang::T('Customer'));
$search = _post('search');
if ($search != '') {
$paginator = Paginator::build(ORM::for_table('tbl_user_recharges'), ['username' => '%' . $search . '%'], $search);
$d = ORM::for_table('tbl_user_recharges')->where_like('username', '%' . $search . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many();
} else {
$paginator = Paginator::build(ORM::for_table('tbl_user_recharges'));
$d = ORM::for_table('tbl_user_recharges')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_array();
}
run_hook('view_list_billing'); #HOOK
if ($isApi) {
showResult(true, $action, $d, ['search' => $search]);
}
$ui->assign('d', $d);
$ui->assign('search', $search);
$ui->assign('paginator', $paginator);
$ui->display('plan.tpl');
break;
case 'recharge':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
@ -92,6 +68,12 @@ switch ($action) {
if (isset($routes['2']) && !empty($routes['2'])) {
$ui->assign('cust', ORM::for_table('tbl_customers')->find_one($routes['2']));
}
$usings = explode(',', $config['payment_usings']);
$usings = array_filter(array_unique($usings));
if(count($usings)==0){
$usings[] = Lang::T('Cash');
}
$ui->assign('usings', $usings);
run_hook('view_recharge'); #HOOK
$ui->display('recharge.tpl');
break;
@ -154,6 +136,15 @@ switch ($action) {
$server = _post('server');
$planId = _post('plan');
$using = _post('using');
$stoken = _post('stoken');
if (!empty(App::getTokenValue($stoken))) {
$username = App::getTokenValue($stoken);
$in = ORM::for_table('tbl_transactions')->where('username', $username)->order_by_desc('id')->find_one();
Package::createInvoice($in);
$ui->display('invoice.tpl');
die();
}
$msg = '';
if ($id_customer == '' or $server == '' or $planId == '' or $using == '') {
@ -161,7 +152,7 @@ switch ($action) {
}
if ($msg == '') {
$gateway = 'Recharge';
$gateway = ucwords($using);
$channel = $admin['fullname'];
$cust = User::_info($id_customer);
list($bills, $add_cost) = User::getBills($id_customer);
@ -189,6 +180,7 @@ switch ($action) {
}
$in = ORM::for_table('tbl_transactions')->where('username', $cust['username'])->order_by_desc('id')->find_one();
Package::createInvoice($in);
App::setToken($stoken, $cust['username']);
$ui->display('invoice.tpl');
_log('[' . $admin['username'] . ']: ' . 'Recharge ' . $cust['username'] . ' [' . $in['plan_name'] . '][' . Lang::moneyFormat($in['price']) . ']', $admin['user_type'], $admin['id']);
} else {
@ -254,7 +246,7 @@ switch ($action) {
$ui->assign('_title', 'Edit Plan');
$ui->display('plan-edit.tpl');
} else {
r2(U . 'plan/list', 'e', $_L['Account_Not_Found']);
r2(U . 'plan/list', 'e', Lang::T('Account Not Found'));
}
break;
@ -339,18 +331,13 @@ switch ($action) {
case 'voucher':
$ui->assign('_title', Lang::T('Vouchers'));
$limit = 10;
$page = _get('p', 0);
$pageNow = $page * $limit;
$search = _req('search');
if ($search != '') {
if (in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
$d = ORM::for_table('tbl_plans')->where('enabled', '1')
$query = ORM::for_table('tbl_plans')->where('enabled', '1')
->join('tbl_voucher', array('tbl_plans.id', '=', 'tbl_voucher.id_plan'))
->where_like('tbl_voucher.code', '%' . $search . '%')
->offset($pageNow)
->limit($limit)
->findArray();
->where_like('tbl_voucher.code', '%' . $search . '%');
$d = Paginator::findMany($query, ["search" => $search]);
} else if ($admin['user_type'] == 'Agent') {
$sales = [];
$sls = ORM::for_table('tbl_users')->select('id')->where('root', $admin['id'])->findArray();
@ -358,21 +345,17 @@ switch ($action) {
$sales[] = $s['id'];
}
$sales[] = $admin['id'];
$d = ORM::for_table('tbl_plans')
$query = ORM::for_table('tbl_plans')
->join('tbl_voucher', array('tbl_plans.id', '=', 'tbl_voucher.id_plan'))
->where_in('generated_by', $sales)
->where_like('tbl_voucher.code', '%' . $search . '%')
->offset($pageNow)
->limit($limit)
->findArray();
->where_like('tbl_voucher.code', '%' . $search . '%');
$d = Paginator::findMany($query, ["search" => $search]);
}
} else {
if (in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
$d = ORM::for_table('tbl_plans')->where('enabled', '1')
->join('tbl_voucher', array('tbl_plans.id', '=', 'tbl_voucher.id_plan'))
->offset($pageNow)
->limit($limit)
->findArray();
$query = ORM::for_table('tbl_plans')->where('enabled', '1')
->join('tbl_voucher', array('tbl_plans.id', '=', 'tbl_voucher.id_plan'));
$d = Paginator::findMany($query);
} else if ($admin['user_type'] == 'Agent') {
$sales = [];
$sls = ORM::for_table('tbl_users')->select('id')->where('root', $admin['id'])->findArray();
@ -380,12 +363,10 @@ switch ($action) {
$sales[] = $s['id'];
}
$sales[] = $admin['id'];
$d = ORM::for_table('tbl_plans')
$query = ORM::for_table('tbl_plans')
->join('tbl_voucher', array('tbl_plans.id', '=', 'tbl_voucher.id_plan'))
->where_in('generated_by', $sales)
->offset($pageNow)
->limit($limit)
->findArray();
->where_in('generated_by', $sales);
$d = Paginator::findMany($query);
}
}
// extract admin
@ -588,13 +569,27 @@ switch ($action) {
}
}
run_hook('create_voucher'); #HOOK
for ($i = 0; $i < $numbervoucher; $i++) {
$code = strtoupper(substr(md5(time() . rand(10000, 99999)), 0, $lengthcode));
if ($voucher_format == 'low') {
$code = strtolower($code);
} else if ($voucher_format == 'rand') {
$code = Lang::randomUpLowCase($code);
$vouchers = [];
if($voucher_format == 'numbers'){
if (strlen($lengthcode)<6) {
$msg .= 'The Length Code must be a more than 6 for numbers' . '<br>';
}
$vouchers = generateUniqueNumericVouchers($numbervoucher, $lengthcode);
}
else {
for ($i = 0; $i < $numbervoucher; $i++) {
$code = strtoupper(substr(md5(time() . rand(10000, 99999)), 0, $lengthcode));
if ($voucher_format == 'low') {
$code = strtolower($code);
} else if ($voucher_format == 'rand') {
$code = Lang::randomUpLowCase($code);
}
$vouchers[] = $code;
}
}
foreach($vouchers as $code){
$d = ORM::for_table('tbl_voucher')->create();
$d->type = $type;
$d->routers = $server;
@ -635,7 +630,7 @@ switch ($action) {
if (!$voucher) {
r2(U . 'plan/voucher/', 'e', Lang::T('Voucher Not Found'));
}
$plan = ORM::for_table('tbl_plans')->find_one($d['id_plan']);
$plan = ORM::for_table('tbl_plans')->find_one($voucher['id_plan']);
if ($voucher && $plan) {
$content = Lang::pad($config['CompanyName'], ' ', 2) . "\n";
$content .= Lang::pad($config['address'], ' ', 2) . "\n";
@ -738,6 +733,14 @@ switch ($action) {
}
$user = _post('id_customer');
$plan = _post('id_plan');
$stoken = _req('stoken');
if (App::getTokenValue($stoken)) {
$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();
Package::createInvoice($in);
$ui->display('invoice.tpl');
die();
}
run_hook('deposit_customer'); #HOOK
if (!empty($user) && !empty($plan)) {
@ -745,6 +748,9 @@ switch ($action) {
$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();
Package::createInvoice($in);
if(!empty($stoken)){
App::setToken($stoken, $in['id']);
}
$ui->display('invoice.tpl');
} else {
r2(U . 'plan/refill', 'e', "Failed to refill account");
@ -753,6 +759,69 @@ switch ($action) {
r2(U . 'plan/refill', 'e', "All field is required");
}
break;
case 'extend':
$id = $routes[2];
$days = $routes[3];
$stoken = $_GET['stoken'];
if (App::getTokenValue($stoken)) {
r2(U . 'plan', 's', "Extend already done");
}
$tur = ORM::for_table('tbl_user_recharges')->find_one($id);
$status = $tur['status'];
if ($status == 'off') {
if (strtotime($tur['expiration'] . ' ' . $tur['time']) > time()) {
// not expired
$expiration = date('Y-m-d', strtotime($tur['expiration'] . " +$days day"));
} else {
//expired
$expiration = date('Y-m-d', strtotime(" +$days day"));
}
$tur->expiration = $expiration;
$tur->status = "on";
$tur->save();
App::setToken($stoken, $id);
if ($tur['routers'] != 'radius') {
$mikrotik = Mikrotik::info($tur['routers']);
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
$router = $tur['routers'];
}
$p = ORM::for_table('tbl_plans')->findOne($tur['plan_id']);
$c = ORM::for_table('tbl_customers')->findOne($tur['customer_id']);
if ($tur['routers'] == 'radius') {
Radius::customerAddPlan($c, $p, $tur['expiration'] . ' ' . $tur['time']);
} else {
if ($tur['type'] == 'Hotspot') {
Mikrotik::removeHotspotUser($client, $c['username']);
Mikrotik::removeHotspotActiveUser($client, $c['username']);
Mikrotik::addHotspotUser($client, $p, $c);
} else if ($tur['type'] == 'PPPOE') {
Mikrotik::removePpoeUser($client, $c['username']);
Mikrotik::removePpoeActive($client, $c['username']);
Mikrotik::addPpoeUser($client, $p, $c);
}
}
_log("$admin[fullname] extend Customer $tur[customer_id] $tur[username] for $days days", $admin['user_type'], $admin['id']);
r2(U . 'plan', 's', "Extend until $expiration");
}else{
r2(U . 'plan', 's', "Customer is not expired yet");
}
break;
default:
$ui->display('a404.tpl');
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/plan.js"></script>');
$ui->assign('_title', Lang::T('Customer'));
$search = _post('search');
if ($search != '') {
$query = ORM::for_table('tbl_user_recharges')
->whereRaw("username LIKE '%$search%' OR namebp LIKE '%$search%' OR method LIKE '%$search%' OR routers LIKE '%$search%' OR type LIKE '%$search%'")
->order_by_desc('id');
$d = Paginator::findMany($query, ['search' => $search]);
} else {
$query = ORM::for_table('tbl_user_recharges')->order_by_desc('id');
$d = Paginator::findMany($query);
}
run_hook('view_list_billing'); #HOOK
$ui->assign('d', $d);
$ui->assign('search', $search);
$ui->display('plan.tpl');
break;
}

View File

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

View File

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

View File

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

View File

@ -17,7 +17,7 @@ use PEAR2\Net\RouterOS;
require_once 'system/autoload/PEAR2/Autoload.php';
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'),'danger', "dashboard");
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
switch ($action) {
@ -26,15 +26,14 @@ switch ($action) {
$name = _post('name');
if ($name != '') {
$paginator = Paginator::build(ORM::for_table('tbl_routers'), ['name' => '%' . $name . '%'], $name);
$d = ORM::for_table('tbl_routers')->where_like('name', '%' . $name . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many();
$query = ORM::for_table('tbl_routers')->where_like('name', '%' . $name . '%')->order_by_desc('id');
$d = Paginator::findMany($query, ['name' => $name]);
} else {
$paginator = Paginator::build(ORM::for_table('tbl_routers'));
$d = ORM::for_table('tbl_routers')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_desc('id')->find_many();
$query = ORM::for_table('tbl_routers')->order_by_desc('id');
$d = Paginator::findMany($query);
}
$ui->assign('d', $d);
$ui->assign('paginator', $paginator);
run_hook('view_list_routers'); #HOOK
$ui->display('routers.tpl');
break;
@ -55,7 +54,7 @@ switch ($action) {
run_hook('view_router_edit'); #HOOK
$ui->display('routers-edit.tpl');
} else {
r2(U . 'routers/list', 'e', $_L['Account_Not_Found']);
r2(U . 'routers/list', 'e', Lang::T('Account Not Found'));
}
break;

View File

@ -12,7 +12,7 @@ $action = $routes['1'];
$ui->assign('_admin', $admin);
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'),'danger', "dashboard");
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
use PEAR2\Net\RouterOS;
@ -38,7 +38,7 @@ switch ($action) {
} else {
$radup = '000000';
}
$radiusRate = $plan['rate_up'] . $radup . '/' . $plan['rate_down'] . $raddown;
$radiusRate = $plan['rate_up'] . $radup . '/' . $plan['rate_down'] . $raddown . '/' . $plan['burst'];
Radius::planUpSert($plan['id'], $radiusRate);
$log .= "DONE : Radius $plan[name_plan], $plan[shared_users], $radiusRate<br>";
} else {
@ -83,7 +83,7 @@ switch ($action) {
} else {
$radup = '000000';
}
$radiusRate = $plan['rate_up'] . $radup . '/' . $plan['rate_down'] . $raddown;
$radiusRate = $plan['rate_up'] . $radup . '/' . $plan['rate_down'] . $raddown . '/' . $plan['burst'];
Radius::planUpSert($plan['id'], $radiusRate, $plan['pool']);
$log .= "DONE : RADIUS $plan[name_plan], $plan[pool], $rate<br>";
} else {
@ -119,15 +119,14 @@ switch ($action) {
$name = _post('name');
if ($name != '') {
$paginator = Paginator::build(ORM::for_table('tbl_plans'), ['name_plan' => '%' . $name . '%', 'type' => 'Hotspot'], $name);
$d = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'Hotspot')->where_like('tbl_plans.name_plan', '%' . $name . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many();
$query = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'Hotspot')->where_like('tbl_plans.name_plan', '%' . $name . '%');
$d = Paginator::findMany($query, ['name' => $name]);
} else {
$paginator = Paginator::build(ORM::for_table('tbl_plans'), ['type' => 'Hotspot']);
$d = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'Hotspot')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many();
$query = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'Hotspot');
$d = Paginator::findMany($query);
}
$ui->assign('d', $d);
$ui->assign('paginator', $paginator);
run_hook('view_list_plans'); #HOOK
$ui->display('hotspot.tpl');
break;
@ -142,7 +141,7 @@ switch ($action) {
break;
case 'edit':
$id = $routes['2'];
$id = $routes['2'];
$d = ORM::for_table('tbl_plans')->find_one($id);
if ($d) {
$ui->assign('d', $d);
@ -153,12 +152,12 @@ switch ($action) {
run_hook('view_edit_plan'); #HOOK
$ui->display('hotspot-edit.tpl');
} else {
r2(U . 'services/hotspot', 'e', $_L['Account_Not_Found']);
r2(U . 'services/hotspot', 'e', Lang::T('Account Not Found'));
}
break;
case 'delete':
$id = $routes['2'];
$id = $routes['2'];
$d = ORM::for_table('tbl_plans')->find_one($id);
if ($d) {
@ -185,6 +184,7 @@ switch ($action) {
case 'add-post':
$name = _post('name');
$plan_type = _post('plan_type'); //Personal / Business
$radius = _post('radius');
$typebp = _post('typebp');
$limit_type = _post('limit_type');
@ -242,15 +242,47 @@ switch ($action) {
$radup = '000000';
}
$rate = $b['rate_up'] . $unitup . "/" . $b['rate_down'] . $unitdown;
$radiusRate = $b['rate_up'] . $radup . '/' . $b['rate_down'] . $raddown;
$radiusRate = $b['rate_up'] . $radup . '/' . $b['rate_down'] . $raddown . '/' . $b['burst'];
$rate = trim($rate . " " . $b['burst']);
// Check if tax is enabled in config
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
// Default tax rate
$default_tax_rate = 0.01; // Default tax rate 1%
// Check if tax rate is set to custom in config
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : $default_tax_rate;
// Check if tax rate is custom
if ($tax_rate_setting === 'custom') {
// Check if custom tax rate is set in config
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : $default_tax_rate;
// Convert custom tax rate to decimal
$custom_tax_rate_decimal = $custom_tax_rate / 100;
$tax_rate = $custom_tax_rate_decimal;
} else {
// Use tax rate
$tax_rate = $tax_rate_setting;
}
// Calculate the new price with tax if tax is enabled
if ($tax_enable === 'yes') {
$price_with_tax = $price + ($price * $tax_rate);
} else {
// If tax is not enabled, use the original price
$price_with_tax = $price;
}
// Create new plan
$d = ORM::for_table('tbl_plans')->create();
$d->name_plan = $name;
$d->id_bw = $id_bw;
$d->price = $price;
$d->price = $price_with_tax; // Set price with or without tax based on configuration
$d->type = 'Hotspot';
$d->typebp = $typebp;
$d->plan_type = $plan_type;
$d->limit_type = $limit_type;
$d->time_limit = $time_limit;
$d->time_unit = $time_unit;
@ -295,6 +327,7 @@ switch ($action) {
case 'edit-post':
$id = _post('id');
$name = _post('name');
$plan_type = _post('plan_type');
$id_bw = _post('id_bw');
$typebp = _post('typebp');
$price = _post('price');
@ -344,7 +377,7 @@ switch ($action) {
$radup = '000000';
}
$rate = $b['rate_up'] . $unitup . "/" . $b['rate_down'] . $unitdown;
$radiusRate = $b['rate_up'] . $radup . '/' . $b['rate_down'] . $raddown;
$radiusRate = $b['rate_up'] . $radup . '/' . $b['rate_down'] . $raddown . '/' . $b['burst'];
$rate = trim($rate . " " . $b['burst']);
@ -359,14 +392,45 @@ switch ($action) {
}
}
// Check if tax is enabled in config
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
// Default tax rate
$default_tax_rate = 0.01; // Default tax rate 1%
// Check if tax rate is set to custom in config
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : $default_tax_rate;
// Check if tax rate is custom
if ($tax_rate_setting === 'custom') {
// Check if custom tax rate is set in config
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : $default_tax_rate;
// Convert custom tax rate to decimal
$custom_tax_rate_decimal = $custom_tax_rate / 100;
$tax_rate = $custom_tax_rate_decimal;
} else {
// Use tax rate
$tax_rate = $tax_rate_setting;
}
// Calculate the new price with tax if tax is enabled
if ($tax_enable === 'yes') {
$price_with_tax = $price + ($price * $tax_rate);
} else {
// If tax is not enabled, use the original price
$price_with_tax = $price;
}
$d->name_plan = $name;
$d->id_bw = $id_bw;
$d->price = $price;
$d->price = $price_with_tax; // Set price with or without tax based on configuration
$d->typebp = $typebp;
$d->limit_type = $limit_type;
$d->time_limit = $time_limit;
$d->time_unit = $time_unit;
$d->data_limit = $data_limit;
$d->plan_type = $plan_type;
$d->data_unit = $data_unit;
$d->validity = $validity;
$d->validity_unit = $validity_unit;
@ -389,15 +453,14 @@ switch ($action) {
$name = _post('name');
if ($name != '') {
$paginator = Paginator::build(ORM::for_table('tbl_plans'), ['name_plan' => '%' . $name . '%', 'type' => 'PPPOE'], $name);
$d = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'PPPOE')->where_like('tbl_plans.name_plan', '%' . $name . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many();
$query = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'PPPOE')->where_like('tbl_plans.name_plan', '%' . $name . '%');
$d = Paginator::findMany($query, ['name' => $name]);
} else {
$paginator = Paginator::build(ORM::for_table('tbl_plans'), ['type' => 'PPPOE'], $name);
$d = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'PPPOE')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many();
$query = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'PPPOE');
$d = Paginator::findMany($query);
}
$ui->assign('d', $d);
$ui->assign('paginator', $paginator);
run_hook('view_list_ppoe'); #HOOK
$ui->display('pppoe.tpl');
break;
@ -414,7 +477,7 @@ switch ($action) {
case 'pppoe-edit':
$ui->assign('_title', Lang::T('PPPOE Plans'));
$id = $routes['2'];
$id = $routes['2'];
$d = ORM::for_table('tbl_plans')->find_one($id);
if ($d) {
$ui->assign('d', $d);
@ -430,12 +493,12 @@ switch ($action) {
run_hook('view_edit_ppoe'); #HOOK
$ui->display('pppoe-edit.tpl');
} else {
r2(U . 'services/pppoe', 'e', $_L['Account_Not_Found']);
r2(U . 'services/pppoe', 'e', Lang::T('Account Not Found'));
}
break;
case 'pppoe-delete':
$id = $routes['2'];
$id = $routes['2'];
$d = ORM::for_table('tbl_plans')->find_one($id);
if ($d) {
@ -461,6 +524,7 @@ switch ($action) {
case 'pppoe-add-post':
$name = _post('name_plan');
$plan_type = _post('plan_type');
$radius = _post('radius');
$id_bw = _post('id_bw');
$price = _post('price');
@ -512,14 +576,46 @@ switch ($action) {
$radup = '000000';
}
$rate = $b['rate_up'] . $unitup . "/" . $b['rate_down'] . $unitdown;
$radiusRate = $b['rate_up'] . $radup . '/' . $b['rate_down'] . $raddown;
$radiusRate = $b['rate_up'] . $radup . '/' . $b['rate_down'] . $raddown . '/' . $b['burst'];
$rate = trim($rate . " " . $b['burst']);
// Check if tax is enabled in config
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
// Default tax rate
$default_tax_rate = 0.01; // Default tax rate 1%
// Check if tax rate is set to custom in config
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : $default_tax_rate;
// Check if tax rate is custom
if ($tax_rate_setting === 'custom') {
// Check if custom tax rate is set in config
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : $default_tax_rate;
// Convert custom tax rate to decimal
$custom_tax_rate_decimal = $custom_tax_rate / 100;
$tax_rate = $custom_tax_rate_decimal;
} else {
// Use tax rate
$tax_rate = $tax_rate_setting;
}
// Calculate the new price with tax if tax is enabled
if ($tax_enable === 'yes') {
$price_with_tax = $price + ($price * $tax_rate);
} else {
// If tax is not enabled, use the original price
$price_with_tax = $price;
}
$d = ORM::for_table('tbl_plans')->create();
$d->type = 'PPPOE';
$d->name_plan = $name;
$d->id_bw = $id_bw;
$d->price = $price;
$d->price = $price_with_tax;
$d->plan_type = $plan_type;
$d->validity = $validity;
$d->validity_unit = $validity_unit;
$d->pool = $pool;
@ -556,6 +652,7 @@ switch ($action) {
case 'edit-pppoe-post':
$id = _post('id');
$plan_type = _post('plan_type');
$name = _post('name_plan');
$id_bw = _post('id_bw');
$price = _post('price');
@ -602,7 +699,7 @@ switch ($action) {
$radup = '000000';
}
$rate = $b['rate_up'] . $unitup . "/" . $b['rate_down'] . $unitdown;
$radiusRate = $b['rate_up'] . $radup . '/' . $b['rate_down'] . $raddown;
$radiusRate = $b['rate_up'] . $radup . '/' . $b['rate_down'] . $raddown . '/' . $b['burst'];
$rate = trim($rate . " " . $b['burst']);
if ($d['is_radius']) {
@ -616,9 +713,40 @@ switch ($action) {
}
}
// Check if tax is enabled in config
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
// Default tax rate
$default_tax_rate = 0.01; // Default tax rate 1%
// Check if tax rate is set to custom in config
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : $default_tax_rate;
// Check if tax rate is custom
if ($tax_rate_setting === 'custom') {
// Check if custom tax rate is set in config
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : $default_tax_rate;
// Convert custom tax rate to decimal
$custom_tax_rate_decimal = $custom_tax_rate / 100;
$tax_rate = $custom_tax_rate_decimal;
} else {
// Use tax rate
$tax_rate = $tax_rate_setting;
}
// Calculate the new price with tax if tax is enabled
if ($tax_enable === 'yes') {
$price_with_tax = $price + ($price * $tax_rate);
} else {
// If tax is not enabled, use the original price
$price_with_tax = $price;
}
$d->name_plan = $name;
$d->id_bw = $id_bw;
$d->price = $price;
$d->price = $price_with_tax;
$d->plan_type = $plan_type;
$d->validity = $validity;
$d->validity_unit = $validity_unit;
$d->routers = $routers;
@ -638,15 +766,14 @@ switch ($action) {
$ui->assign('_title', Lang::T('Balance Plans'));
$name = _post('name');
if ($name != '') {
$paginator = Paginator::build(ORM::for_table('tbl_plans'), ['name_plan' => '%' . $name . '%', 'type' => 'Balance'], $name);
$d = ORM::for_table('tbl_plans')->where('tbl_plans.type', 'Balance')->where_like('tbl_plans.name_plan', '%' . $name . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many();
$query = ORM::for_table('tbl_plans')->where('tbl_plans.type', 'Balance')->where_like('tbl_plans.name_plan', '%' . $name . '%');
$d = Paginator::findMany($query, ['name' => $name]);
} else {
$paginator = Paginator::build(ORM::for_table('tbl_plans'), ['type' => 'Balance'], $name);
$d = ORM::for_table('tbl_plans')->where('tbl_plans.type', 'Balance')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many();
$query = ORM::for_table('tbl_plans')->where('tbl_plans.type', 'Balance');
$d = Paginator::findMany($query);
}
$ui->assign('d', $d);
$ui->assign('paginator', $paginator);
run_hook('view_list_balance'); #HOOK
$ui->display('balance.tpl');
break;
@ -657,14 +784,14 @@ switch ($action) {
break;
case 'balance-edit':
$ui->assign('_title', Lang::T('Balance Plans'));
$id = $routes['2'];
$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'];
$id = $routes['2'];
$d = ORM::for_table('tbl_plans')->find_one($id);
if ($d) {
@ -695,8 +822,37 @@ switch ($action) {
}
run_hook('edit_ppoe'); #HOOK
if ($msg == '') {
// Check if tax is enabled in config
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
// Default tax rate
$default_tax_rate = 0.01; // Default tax rate 1%
// Check if tax rate is set to custom in config
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : $default_tax_rate;
// Check if tax rate is custom
if ($tax_rate_setting === 'custom') {
// Check if custom tax rate is set in config
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : $default_tax_rate;
// Convert custom tax rate to decimal
$custom_tax_rate_decimal = $custom_tax_rate / 100;
$tax_rate = $custom_tax_rate_decimal;
} else {
// Use tax rate
$tax_rate = $tax_rate_setting;
}
// Calculate the new price with tax if tax is enabled
if ($tax_enable === 'yes') {
$price_with_tax = $price + ($price * $tax_rate);
} else {
// If tax is not enabled, use the original price
$price_with_tax = $price;
}
$d->name_plan = $name;
$d->price = $price;
$d->price = $price_with_tax;
$d->enabled = $enabled;
$d->prepaid = 'yes';
$d->save();
@ -725,11 +881,43 @@ switch ($action) {
}
run_hook('add_ppoe'); #HOOK
if ($msg == '') {
// Check if tax is enabled in config
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
// Default tax rate
$default_tax_rate = 0.01; // Default tax rate 1%
// Check if tax rate is set to custom in config
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : $default_tax_rate;
// Check if tax rate is custom
if ($tax_rate_setting === 'custom') {
// Check if custom tax rate is set in config
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : $default_tax_rate;
// Convert custom tax rate to decimal
$custom_tax_rate_decimal = $custom_tax_rate / 100;
$tax_rate = $custom_tax_rate_decimal;
} else {
// Use tax rate
$tax_rate = $tax_rate_setting;
}
// Calculate the new price with tax if tax is enabled
if ($tax_enable === 'yes') {
$price_with_tax = $price + ($price * $tax_rate);
} else {
// If tax is not enabled, use the original price
$price_with_tax = $price;
}
$d = ORM::for_table('tbl_plans')->create();
$d->type = 'Balance';
$d->name_plan = $name;
$d->id_bw = 0;
$d->price = $price;
$d->price = $price_with_tax;
$d->validity = 0;
$d->validity_unit = 'Months';
$d->routers = '';

View File

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

View File

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

View File

@ -34,7 +34,6 @@ foreach ($d as $ds) {
$c = ORM::for_table('tbl_customers')->where('id', $ds['customer_id'])->find_one();
$m = Mikrotik::info($ds['routers']);
$p = ORM::for_table('tbl_plans')->where('id', $u['plan_id'])->find_one();
$price = Lang::moneyFormat($p['price']);
if ($p['is_radius']) {
if (empty($p['pool_expired'])) {
print_r(Radius::customerDeactivate($c['username']));
@ -54,7 +53,7 @@ foreach ($d as $ds) {
}
Mikrotik::removeHotspotActiveUser($client, $c['username']);
}
echo Message::sendPackageNotification($c, $u['namebp'], $price, $textExpired, $config['user_notification_expired']) . "\n";
echo Message::sendPackageNotification($c, $u['namebp'], $p['price'], $textExpired, $config['user_notification_expired']) . "\n";
//update database user dengan status off
$u->status = 'off';
$u->save();
@ -68,7 +67,7 @@ foreach ($d as $ds) {
}
}
if ($p && $p['enabled'] && $c['balance'] >= $p['price']) {
if (Package::rechargeUser($ds['customer_id'], $p['routers'], $p['id'], 'Customer', 'Balance')) {
if (Package::rechargeUser($ds['customer_id'], $ds['routers'], $p['id'], 'Customer', 'Balance')) {
// if success, then get the balance
Balance::min($ds['customer_id'], $p['price']);
echo "plan enabled: $p[enabled] | User balance: $c[balance] | price $p[price]\n";
@ -98,7 +97,6 @@ foreach ($d as $ds) {
$c = ORM::for_table('tbl_customers')->where('id', $ds['customer_id'])->find_one();
$m = ORM::for_table('tbl_routers')->where('name', $ds['routers'])->find_one();
$p = ORM::for_table('tbl_plans')->where('id', $u['plan_id'])->find_one();
$price = Lang::moneyFormat($p['price']);
if ($p['is_radius']) {
if (empty($p['pool_expired'])) {
print_r(Radius::customerDeactivate($c['username']));
@ -115,7 +113,7 @@ foreach ($d as $ds) {
}
Mikrotik::removePpoeActive($client, $c['username']);
}
echo Message::sendPackageNotification($c, $u['namebp'], $price, $textExpired, $config['user_notification_expired']) . "\n";
echo Message::sendPackageNotification($c, $u['namebp'], $p['price'], $textExpired, $config['user_notification_expired']) . "\n";
$u->status = 'off';
$u->save();
@ -129,7 +127,7 @@ foreach ($d as $ds) {
}
}
if ($p && $p['enabled'] && $c['balance'] >= $p['price']) {
if (Package::rechargeUser($ds['customer_id'], $p['routers'], $p['id'], 'Customer', 'Balance')) {
if (Package::rechargeUser($ds['customer_id'], $ds['routers'], $p['id'], 'Customer', 'Balance')) {
// if success, then get the balance
Balance::min($ds['customer_id'], $p['price']);
echo "plan enabled: $p[enabled] | User balance: $c[balance] | price $p[price]\n";

View File

@ -38,24 +38,17 @@ foreach ($d as $ds) {
$u = ORM::for_table('tbl_user_recharges')->where('id', $ds['id'])->find_one();
$p = ORM::for_table('tbl_plans')->where('id', $u['plan_id'])->find_one();
$c = ORM::for_table('tbl_customers')->where('id', $ds['customer_id'])->find_one();
list($bills, $add_cost) = User::getBills($ds['customer_id']);
if ($add_cost > 0) {
if (!empty($add_cost)) {
$p['price'] += $add_cost;
}
}
if ($p['validity_unit'] == 'Period') {
if ($p['validity_unit'] == 'Period') {
// Postpaid price from field
$add_inv = User::getAttribute("Invoice", $ds['customer_id']);
if (empty ($add_inv) or $add_inv == 0) {
$price = Lang::moneyFormat($p['price']);
$price = $p['price'];
} else {
$price = Lang::moneyFormat($add_inv);
$price = $add_inv;
}
} else {
$price = Lang::moneyFormat($p['price']);
$price = $p['price'];
}
//$price = Lang::moneyFormat($p['price']);
if ($ds['expiration'] == $day7) {
echo Message::sendPackageNotification($c, $p['name_plan'], $price, Lang::getNotifText('reminder_7_day'), $config['user_notification_reminder']) . "\n";
} else if ($ds['expiration'] == $day3) {
@ -64,4 +57,4 @@ foreach ($d as $ds) {
echo Message::sendPackageNotification($c, $p['name_plan'], $price, Lang::getNotifText('reminder_1_day'), $config['user_notification_reminder']) . "\n";
}
}
}
}

View File

@ -26,6 +26,7 @@
"hebrew": "iw",
"hindi": "hi",
"hungarian": "hu",
"iran": "ir",
"icelandic": "is",
"italian": "it",
"japanese": "ja",
@ -55,4 +56,4 @@
"ukrainian": "uk",
"vietnamese": "vi",
"welsh": "cy"
}
}

View File

@ -1,5 +1,5 @@
{
"Log_in": "Log-in",
"Log_in": "Login",
"Register": "Register",
"Announcement": "Announcement",
"Registration_Info": "Registration Info",
@ -484,7 +484,6 @@
"Current_Cycle": "Current Cycle",
"Additional_Cost": "Additional Cost",
"Remaining": "Remaining",
"": "",
"Not_Found": "Not Found",
"Cash": "Cash",
"Payment_not_found": "Payment not found",
@ -492,19 +491,13 @@
"Cache_cleared_successfully_": "Cache cleared successfully!",
"Paid": "Paid",
"Send_Message": "Send Message",
"Send_SMS_WA_Message": "Send SMS\/WA Message",
"Send_Bulk_SMS_WA_Message": "Send Bulk SMS\/WA Message",
"Send_Personal_Message": "Send Personal Message",
"Send_Via": "Send Via",
"Compose_your_message___": "Compose your message...",
"Use_placeholders_": "Use placeholders:",
"__name__": "[[name]]",
"Customer_Name": "Customer Name",
"__user_name__": "[[user_name]]",
"Customer_Username": "Customer Username",
"__phone__": "[[phone]]",
"Customer_Phone": "Customer Phone",
"__company_name__": "[[company_name]]",
"Your_Company_Name": "Your Company Name",
"Message_Sent_Successfully": "Message Sent Successfully",
"Send_Bulk_Message": "Send Bulk Message",
@ -512,5 +505,80 @@
"All_Customers": "All Customers",
"New_Customers": "New Customers",
"Expired_Customers": "Expired Customers",
"Active_Customers": "Active Customers"
"Active_Customers": "Active Customers",
"Map": "Map",
"Customer_Location": "Customer Location",
"Account_Type": "Account Type",
"Coordinates": "Coordinates",
"Latitude_and_Longitude_coordinates_for_map_must_be_separate_with_comma____": "Latitude and Longitude coordinates for map must be separate with comma &quot;,&quot;",
"Customer_Geo_Location_Information": "Customer Geo Location Information",
"List": "List",
"Lists": "Lists",
"Single_Customer": "Single Customer",
"Bulk_Customers": "Bulk Customers",
"Message_per_time": "Message per time",
"5_Messages": "5 Messages",
"10_Messages": "10 Messages",
"15_Messages": "15 Messages",
"20_Messages": "20 Messages",
"30_Messages": "30 Messages",
"40_Messages": "40 Messages",
"50_Messages": "50 Messages",
"60_Messages": "60 Messages",
"Use_20_and_above_if_you_are_sending_to_all_customers_to_avoid_server_time_out": "Use 20 and above if you are sending to all customers to avoid server time out",
"Delay": "Delay",
"No_Delay": "No Delay",
"5_Seconds": "5 Seconds",
"10_Seconds": "10 Seconds",
"15_Seconds": "15 Seconds",
"20_Seconds": "20 Seconds",
"Use_at_least_5_secs_if_you_are_sending_to_all_customers_to_avoid_being_banned_by_your_message_provider": "Use at least 5 secs if you are sending to all customers to avoid being banned by your message provider",
"Testing__if_checked_no_real_message_is_sent_": "Testing [if checked no real message is sent]",
"All_fields_are_required": "All fields are required",
"Personal": "Personal",
"Email_Notification": "Email Notification",
"Router_Name___Location": "Router Name \/ Location",
"Plan_Category": "Plan Category",
"ID": "ID",
"Internet_Plan": "Internet Plan",
"Privacy_Policy": "Privacy Policy",
"Terms_and_Conditions": "Terms and Conditions",
"Contact": "Contact",
"will_be_replaced_with_Customer_Name": "will be replaced with Customer Name",
"will_be_replaced_with_Customer_username": "will be replaced with Customer username",
"will_be_replaced_with_Package_name": "will be replaced with Package name",
"will_be_replaced_with_Package_price": "will be replaced with Package price",
"additional_bills_for_customers": "additional bills for customers",
"will_be_replaced_with_Expiration_date": "will be replaced with Expiration date",
"Your_Company_Name_at_Settings": "Your Company Name at Settings",
"Your_Company_Address_at_Settings": "Your Company Address at Settings",
"Your_Company_Phone_at_Settings": "Your Company Phone at Settings",
"Invoice_number": "Invoice number",
"Date_invoice_created": "Date invoice created",
"Payment_gateway_user_paid_from": "Payment gateway user paid from",
"Payment_channel_user_paid_from": "Payment channel user paid from",
"is_Hotspot_or_PPPOE": "is Hotspot or PPPOE",
"Internet_Package": "Internet Package",
"Internet_Package_Prices": "Internet Package Prices",
"Receiver_name": "Receiver name",
"Username_internet": "Username internet",
"User_password": "User password",
"Expired_datetime": "Expired datetime",
"For_Notes_by_admin": "For Notes by admin",
"Transaction_datetime": "Transaction datetime",
"Balance_Before": "Balance Before",
"Balance_After": "Balance After",
"how_much_balance_have_been_send": "how much balance have been send",
"Current_Balance": "Current Balance",
"Sender_name": "Sender name",
"how_much_balance_have_been_received": "how much balance have been received",
"Extend_Postpaid_Expiration": "Extend Postpaid Expiration",
"Allow_Extend": "Allow Extend",
"Extend_Days": "Extend Days",
"Confirmation_Message": "Confirmation Message",
"You_are_already_logged_in": "You are already logged in",
"Extend": "Extend",
"Created___Expired": "Created \/ Expired",
"Bank_Transfer": "Bank Transfer",
"Recharge_Using": "Recharge Using"
}

View File

@ -4,18 +4,18 @@
"Announcement": "Pemberitahuan",
"Registration_Info": "Info Pendaftaran",
"Voucher_not_found__please_buy_voucher_befor_register": "Voucher tidak ditemukan, silakan beli voucher sebelum mendaftar",
"Register_Success__You_can_login_now": "Daftar Sukses! Anda dapat masuk sekarang",
"Register_Success__You_can_login_now": "Daftar Sukses! Anda dapat masuk sekarang",
"Log_in_to_Member_Panel": "Masuk ke Panel Anggota",
"Register_as_Member": "Daftar sebagai Anggota",
"Enter_Admin_Area": "Masuk ke Admin Panel",
"PHPNuxBill": "PHPNuxBill",
"Username": "Nama Pengguna",
"Password": "Kata Sandi",
"Passwords_does_not_match": "Kata Sandi tidak cocok",
"Passwords_does_not_match": "Kata sandi tidak cocok",
"Account_already_axist": "Akun telah ada",
"Manage": "Mengelola",
"Submit": "Kirim",
"Save_Changes": "Simpan perubahan",
"Save_Changes": "Simpan Perubahan",
"Cancel": "Batal",
"Edit": "Sunting",
"Delete": "Hapus",
@ -25,40 +25,40 @@
"Data_Deleted_Successfully": "Data Berhasil Dihapus",
"Static_Pages": "Halaman Statis",
"Failed_to_save_page__make_sure_i_can_write_to_folder_pages___i_chmod_664_pages___html_i_": "Gagal menyimpan halaman, pastikan diperbolehkan menulis file di folder pages, <i>chmod 664 pages\/*.html<i>",
"Saving_page_success": "Menyimpan halaman sukses",
"Saving_page_success": "Menyimpan halaman berhasil",
"Sometimes_you_need_to_refresh_3_times_until_content_change": "Terkadang Anda perlu menyegarkan 3 kali hingga konten berubah",
"Dashboard": "Dasbor",
"Search_Customers___": "Cari Member...",
"My_Account": "Akun Saya",
"My_Profile": "Profil Saya",
"Settings": "Pengaturan",
"Edit_Profile": "Sunting profil",
"Edit_Profile": "Sunting Profil",
"Change_Password": "Ganti kata sandi",
"Logout": "Keluar",
"Services": "Layanan",
"Bandwidth_Plans": "Paket Bandwidth",
"Bandwidth_Name": "Nama Bandwidth",
"New_Bandwidth": "Baru Bandwidth",
"New_Bandwidth": "Bandwidth Baru",
"Edit_Bandwidth": "Sunting Bandwidth",
"Add_New_Bandwidth": "Tambahkan Bandwidth Baru",
"Rate_Download": "Nilai Unduhan",
"Rate_Upload": "Nilai Unggahan",
"Name_Bandwidth_Already_Exist": "NamanBandwidth Sudah Ada",
"Name_Bandwidth_Already_Exist": "Nama Bandwidth sudah ada",
"Hotspot_Plans": "Paket Hotspot",
"PPPOE_Plans": "Paket PPPoE",
"Plan_Name": "Nama Paket",
"New_Service_Plan": "Paket Layanan Baru",
"Add_Service_Plan": "Tambah Paket Layanan",
"Edit_Service_Plan": "Sunting Paket Layanan",
"Name_Plan_Already_Exist": "Nama Paket Sudah Ada",
"Name_Plan_Already_Exist": "Nama Paket sudah ada",
"Plan_Type": "Jenis Paket",
"Plan_Price": "Harga Paket",
"Limit_Type": "Tipe Batas",
"Unlimited": "Tak terbatas",
"Unlimited": "Tak Terbatas",
"Limited": "Terbatas",
"Time_Limit": "Batas waktu",
"Data_Limit": "Batas Data",
"Both_Limit": "Keduanya Membatasi",
"Both_Limit": "Membatasi keduanya",
"Plan_Validity": "Waktu Paket",
"Select_Bandwidth": "Pilih Bandwidth",
"Shared_Users": "Berbagi Pelanggan",
@ -69,16 +69,16 @@
"Sales": "Sales",
"Member": "Anggota",
"Confirm_New_Password": "Konfirmasi sandi baru",
"Confirm_Password": "konfirmasi sandi",
"Confirm_Password": "Konfirmasi sandi",
"Full_Name": "Nama Lengkap",
"User_Type": "Tipe Pelanggan",
"Address": "Alamat",
"Created_On": "Dibuat pada",
"Expires_On": "Kadaluarsa pada",
"Expires_On": "Kedaluwarsa pada",
"Phone_Number": "Nomor telepon",
"User_deleted_Successfully": "Pelanggan berhasil dihapus",
"Full_Administrator": "Administrator Penuh",
"Keep_Blank_to_do_not_change_Password": "Biarkan Kosong apabila tidak ingin mengubah Kata Sandi",
"Keep_Blank_to_do_not_change_Password": "Biarkan kosong apabila tidak ingin mengubah kata sandi",
"Keep_it_blank_if_you_do_not_want_to_show_currency_code": "Kosongkan jika Anda tidak ingin menampilkan kode mata uang",
"Theme_Style": "Gaya Tema",
"Theme_Color": "Warna Tema",
@ -91,25 +91,25 @@
"Edit_Router": "Sunting Router",
"Router_Name": "Nama Router",
"IP_Address": "Alamat IP",
"Router_Secret": "Rahasia Router",
"Router_Secret": "Password Router",
"Description": "Deskrispi",
"IP_Router_Already_Exist": "IP Router Sudah Ada",
"IP_Router_Already_Exist": "IP Router sudah ada",
"Name_Pool": "Nama Pool",
"Range_IP": "Rentang IP",
"New_Pool": "Pool baru",
"Add_Pool": "Tambahkan Pool",
"Edit_Pool": "Sunting Pool",
"Pool_Name_Already_Exist": "Nama Pool Sudah Ada",
"Pool_Name_Already_Exist": "Nama Pool sudah ada",
"Refill_Account": "Isi Ulang Akun",
"Recharge_Account": "Isi Ulang Akun",
"Select_Account": "Pilih Akun",
"Service_Plan": "Paket Layanan",
"Recharge": "Isi Ulang",
"Method": "Metode",
"Account_Created_Successfully": "Akun Berhasil Dibuat",
"Account_Created_Successfully": "Akun berhasil dibuat",
"Database_Status": "Status Database",
"Total_Database_Size": "Ukuran Total Database",
"Download_Database_Backup": "Unduh Cadangan Database",
"Total_Database_Size": "Ukuran total database",
"Download_Database_Backup": "Unduh cadangan database",
"Table_Name": "Nama Tabel",
"Rows": "Baris",
"Size": "Ukuran",
@ -123,15 +123,15 @@
"Period_Reports": "Laporan Periode",
"All_Transactions": "Semua Transaksi",
"Total_Income": "Jumlah Pemasukan",
"All_Transactions_at_Date": "Semua Transaksi pada Tanggal",
"Export_for_Print": "Ekspor untuk Cetak",
"All_Transactions_at_Date": "Semua transaksi pada ganggal",
"Export_for_Print": "Ekspor untuk cetak",
"Print": "Cetak",
"Export_to_PDF": "Ekspor ke PDF",
"Click_Here_to_Print": "Klik Disini untuk Mencetak",
"You_can_use_html_tag": "Anda dapat menggunakan tag html",
"Click_Here_to_Print": "Klik Disini untuk mencetak",
"You_can_use_html_tag": "Anda dapat menggunakan tag HTML",
"Date_Format": "Format tanggal",
"Income_Today": "Pendapatan Hari Ini",
"Income_This_Month": "Penghasilan Bulan Ini",
"Income_Today": "Pendapatan hari ini",
"Income_This_Month": "Penghasilan bulan ini",
"Users_Active": "Pelanggan Aktif",
"Total_Users": "Total Pelanggan",
"Users": "Pelanggan",
@ -149,11 +149,11 @@
"Settings_Saved_Successfully": "Pengaturan Berhasil Disimpan",
"User_Updated_Successfully": "Pengguna Berhasil Diperbarui",
"User_Expired__Today": "Pengguna Kedaluwarsa, Hari Ini",
"Activity_Log": "Log aktivitas",
"Activity_Log": "Log Aktivitas",
"View_Reports": "Lihat Laporan",
"View_All": "Lihat semua",
"Number_of_Vouchers": "Jumlah Voucher",
"Length_Code": "Kode Panjang",
"Length_Code": "Panjang Kode",
"Code_Voucher": "Kode Voucher",
"Voucher": "Voucher",
"Hotspot_Voucher": "Voucher Hotspot",
@ -174,10 +174,10 @@
"Timezone": "Zona waktu",
"Decimal_Point": "Titik Desimal",
"Thousands_Separator": "Pemisah Ribuan",
"Currency_Code": "Kode mata uang",
"Currency_Code": "Kode Mata Uang",
"Order_Voucher": "Pesan Voucher",
"Voucher_Activation": "Aktivasi Voucher",
"List_Activated_Voucher": "Daftar Voucher yang Diaktifkan",
"List_Activated_Voucher": "Daftar Voucher yang diaktifkan",
"Enter_voucher_code_here": "Masukkan kode voucher di sini",
"Private_Message": "Pesan Pribadi",
"Inbox": "Kotak Masuk",
@ -188,17 +188,17 @@
"Message": "Pesan",
"Your_Account_Information": "Informasi Akun Anda",
"Welcome_to_the_Panel_Members_page__on_this_page_you_can_": "Selamat datang di halaman Anggota Panel, di halaman ini Anda dapat:",
"Invalid_Username_or_Password": "Nama pengguna dan kata sandi salah",
"Invalid_Username_or_Password": "Nama pengguna atau kata sandi salah",
"You_do_not_have_permission_to_access_this_page": "Anda tidak memiliki izin untuk mengakses halaman ini",
"Incorrect_Current_Password": "Kata Sandi Saat Ini Salah",
"Password_changed_successfully__Please_login_again": "Kata sandi berhasil diubah, Silakan login kembali",
"Incorrect_Current_Password": "Kata sandi saat ini salah",
"Password_changed_successfully__Please_login_again": "Kata sandi berhasil diubah, silakan login kembali",
"All_field_is_required": "Semua bidang wajib diisi",
"Voucher_Not_Valid": "Voucher Tidak Berlaku",
"Voucher_Not_Valid": "Voucher tidak berlaku",
"Activation_Vouchers_Successfully": "Aktivasi Voucher Berhasil",
"Data_Not_Found": "Data Tidak Ditemukan",
"Search_by_Username": "Cari berdasarkan Nama Pengguna",
"Search_by_Name": "Cari berdasarkan Nama",
"Search_by_Code_Voucher": "Cari berdasarkan Kode Voucher",
"Data_Not_Found": "Data tidak ditemukan",
"Search_by_Username": "Cari berdasarkan nama pengguna",
"Search_by_Name": "Cari berdasarkan nama",
"Search_by_Code_Voucher": "Cari berdasarkan kode voucher",
"Search": "Mencari",
"Select_a_customer": "Pilih pelanggan",
"Select_Routers": "Pilih Router",
@ -212,25 +212,25 @@
"Language_Name": "Nama Bahasa",
"Folder_Name": "Nama Folder",
"Translator": "Penerjemah",
"Language_Name_Already_Exist": "Nama Bahasa Sudah Ada",
"Language_Name_Already_Exist": "Nama Bahasa sudah ada",
"Payment_Gateway": "Gerbang Pembayaran",
"Community": "Komunitas",
"1_user_can_be_used_for_many_devices_": "1 pengguna bisa digunakan untuk banyak perangkat?",
"Cannot_be_change_after_saved": "Tidak dapat diubah setelah disimpan",
"Explain_Coverage_of_router": "Jelaskan Cakupan router",
"Explain_Coverage_of_router": "Jelaskan cakupan router",
"Name_of_Area_that_router_operated": "Nama area tempat router dioperasikan",
"Payment_Notification_URL__Recurring_Notification_URL__Pay_Account_Notification_URL": "URL Notifikasi Pembayaran, URL Notifikasi Berulang, URL Notifikasi Akun Bayar",
"Finish_Redirect_URL__Unfinish_Redirect_URL__Error_Redirect_URL": "Selesaikan URL Pengalihan, Selesaikan URL Pengalihan, URL Pengalihan Kesalahan",
"Payment_Notification_URL__Recurring_Notification_URL__Pay_Account_Notification_URL": "URL notifikasi pembayaran, URL notifikasi berulang, URL notifikasi akun bayar",
"Finish_Redirect_URL__Unfinish_Redirect_URL__Error_Redirect_URL": "Selesaikan URL pengalihan, selesaikan URL pengalihan, URL pengalihan kesalahan",
"Status": "Status",
"Plan_Not_found": "Paket Tidak ditemukan",
"Plan_Not_found": "Paket tidak ditemukan",
"Failed_to_create_transaction_": "Gagal membuat transaksi.",
"Seller_has_not_yet_setup_Xendit_payment_gateway": "Penjual belum menyiapkan gateway pembayaran Xendit",
"Admin_has_not_yet_setup_Xendit_payment_gateway__please_tell_admin": "Admin belum menyiapkan gerbang pembayaran Xendit, mohon beritahu admin",
"Admin_has_not_yet_setup_Xendit_payment_gateway__please_tell_admin": "Admin belum menyiapkan gerbang pembayaran Xendit, mohon beritahu Admin",
"Buy_this__your_active_package_will_be_overwrite": "Beli ini? Paket aktif Anda akan ditimpa",
"You_already_have_unpaid_transaction__cancel_it_or_pay_it_": "Anda sudah memiliki transaksi yang belum dibayar, batalkan atau bayar.",
"Transaction_Not_found": "Transaksi Tidak ditemukan",
"Transaction_Not_found": "Transaksi tidak ditemukan",
"Cancel_it_": "Batalkan itu?",
"expired": "kedaluwarsa",
"expired": "Kedaluwarsa",
"Check_for_Payment": "Periksa Pembayaran",
"Transaction_still_unpaid_": "Transaksi masih belum dibayar.",
"Paid_Date": "Tanggal Pembayaran",
@ -243,9 +243,9 @@
"Buy_PPOE_Plan": "Beli Paket PPPoE",
"Package": "Paket",
"Order_Internet_Package": "Pesan Paket Internet",
"Unknown_Command_": "Perintah Tidak Diketahui.",
"Unknown_Command_": "Perintah tidak diketahui.",
"Checking_payment": "Memeriksa pembayaran",
"Create_Transaction_Success": "Transaksi Berhasil Dibuat",
"Create_Transaction_Success": "Transaksi berhasil dibuat",
"You_have_unpaid_transaction": "Anda memiliki transaksi yang belum dibayar",
"TripayPayment_Channel": "Saluran Pembayaran Tripay",
"Payment_Channel": "Saluran Pembayaran",
@ -258,16 +258,16 @@
"Gateway": "Gerbang",
"Date_Done": "Tanggal Selesai",
"Unpaid_Order": "Pesanan Belum Dibayar",
"Payment_Gateway_Not_Found": "Gerbang Pembayaran Tidak Ditemukan",
"Payment_Gateway_Not_Found": "Gerbang Pembayaran tidak ditemukan",
"Payment_Gateway_saved_successfully": "Gerbang Pembayaran berhasil disimpan",
"ORDER": "MEMESAN",
"Package_History": "Riwayat Paket",
"Buy_History": "Riwayat Beli",
"Activation_History": "Riwayat Aktivasi",
"Buy_Package": "Beli Paket",
"Email": "Surel",
"Email": "Email",
"Company_Footer": "Catatan Kaki Perusahaan",
"Will_show_below_user_pages": "Akan ditampilkan di bawah halaman pengguna",
"Will_show_below_user_pages": "Akan ditampilkan dibawah halaman pengguna",
"Request_OTP": "Minta OTP",
"Verification_Code": "Kode Verifikasi",
"SMS_Verification_Code": "Kode Verifikasi SMS",
@ -276,7 +276,7 @@
"Plugin": "Plugin",
"Plugin_Manager": "Manajer Plugin",
"User_Notification": "Pemberitahuan Pelanggan",
"Expired_Notification": "Pemberitahuan Kedaluarsa",
"Expired_Notification": "Pemberitahuan Kedaluwarsa",
"User_will_get_notification_when_package_expired": "Pengguna akan mendapat notifikasi ketika paket sudah habis masa berlakunya",
"Expired_Notification_Message": "Pesan Pemberitahuan Kedaluwarsa",
"Payment_Notification": "Notifikasi Pembayaran",
@ -284,15 +284,15 @@
"Current_IP": "IP saat ini",
"Current_MAC": "MAC saat ini",
"Login_Status": "Status Masuk",
"Login_Request_successfully": "Permintaan Masuk berhasil",
"Logout_Request_successfully": "Permintaan Keluar berhasil",
"Disconnect_Internet_": "Putuskan sambungan Internet?",
"Not_Online__Login_now_": "Tidak , Masuk sekarang?",
"Login_Request_successfully": "Permintaan masuk berhasil",
"Logout_Request_successfully": "Permintaan keluar berhasil",
"Disconnect_Internet_": "Putuskan sambungan internet?",
"Not_Online__Login_now_": "Tidak, masuk sekarang?",
"You_are_Online__Logout_": "Kamu sedang aktif, ingin keluar?",
"Connect_to_Internet_": "Hubungkan ke Internet?",
"Your_account_not_connected_to_internet": "Akun Anda tidak terhubung ke internet",
"Failed_to_create_transaction__": "Gagal membuat transaksi. ",
"Failed_to_check_status_transaction__": "Gagal memeriksa status transaksi. ",
"Failed_to_check_status_transaction__": "Gagal memeriksa status transaksi.",
"Disable_Voucher": "Nonaktifkan Voucher",
"Balance": "Saldo",
"Balance_System": "Saldo Sistem",
@ -313,7 +313,7 @@
"Reminder_3_days": "Pengingat 3 hari",
"Reminder_1_day": "Pengingat 1 hari",
"PPPOE_Password": "Kata sandi PPPoE",
"User_Cannot_change_this__only_admin__if_it_Empty_it_will_use_user_password": "Pelanggan tidak dapat mengubah ini, hanya Admin. Jika kosong maka akan menggunakan kata sandi pelanggan",
"User_Cannot_change_this__only_admin__if_it_Empty_it_will_use_user_password": "Pelanggan tidak dapat mengubah ini, hanya Admin. Jika kosong maka akan menggunakan kata sandi pelanggan",
"Invoice_Balance_Message": "Faktur Pesan Saldo",
"Invoice_Notification_Payment": "Faktur Pemberitahuan Pembayaran",
"Balance_Notification_Payment": "Saldo Pemberitahuan Pembayaran",
@ -322,9 +322,9 @@
"Price": "Harga",
"Validity": "Waktu",
"Disable_auto_renewal_": "Nonaktifkan perpanjangan otomatis?",
"Auto_Renewal_On": "Perpanjangan Otomatis Aktif",
"Auto_Renewal_On": "Perpanjangan otomatis aktif",
"Enable_auto_renewal_": "Aktifkan perpanjangan otomatis?",
"Auto_Renewal_Off": "Perpanjangan Otomatis Mati",
"Auto_Renewal_Off": "Perpanjangan otomatis mati",
"Refill_Balance": "Isi Ulang Saldo",
"Invoice_Footer": "Catatan Kaki Faktur",
"Pay_With_Balance": "Bayar dengan Saldo",
@ -334,7 +334,7 @@
"View": "Melihat",
"Back": "Kembali",
"Active": "Aktif",
"Transfer_Balance": "Kirim Saldo",
"Transfer_Balance": "Kirim saldo",
"Send_your_balance_": "Kirim saldo Anda?",
"Send": "Kirim",
"Cannot_send_to_yourself": "Tidak dapat mengirim ke diri Anda sendiri",
@ -342,9 +342,9 @@
"From": "Dari",
"To": "Ke",
"insufficient_balance": "Saldo tidak mencukupi",
"Send_Balance": "Kirim Saldo",
"Received_Balance": "Saldo yang Diterima",
"Minimum_Balance_Transfer": "Minimal Transfer Saldo",
"Send_Balance": "Kirim saldo",
"Received_Balance": "Saldo yang diterima",
"Minimum_Balance_Transfer": "Minimal transfer saldo",
"Minimum_Transfer": "Minimal Transfer",
"Company_Logo": "Logo Perusahaan",
"Expired_IP_Pool": "IP Pool Kedaluwarsa",
@ -361,21 +361,116 @@
"Buy_for_friend": "Beli untuk teman",
"Buy_this_for_friend_account_": "Beli ini untuk akun teman?",
"Review_package_before_recharge": "Tinjau paket sebelum mengisi ulang",
"Activate": "Mengaktifkan Paket",
"Deactivate": "Menonaktifkan Paket",
"Activate": "Mengaktifkan paket",
"Deactivate": "Menonaktifkan paket",
"Sync": "Sinkronisasi",
"Failed_to_create_PaymeTrust_transaction_": "Gagal membuat transaksi PaymeTrust.",
"Location": "Lokasi",
"Radius_Plans": "Paket Radius",
"Change_title_in_user_Plan_order": "Ubah judul dalam urutan paket pelanggan",
"Change_title_in_user_Plan_order": "Ubah Judul dalam urutan paket pelanggan",
"Logs": "Log",
"Voucher_Format": "Format Voucher",
"Resend_To_Customer": "Kirim Ulang Ke Pelanggan",
"Service_Type": "Service Type",
"Service_Type": "Jenis Layanan",
"Others": "Lainnya",
"PPPoE": "PPPoE",
"Hotspot": "Hotspot",
"Monthly_Registered_Customers": "Pendaftaran Pelanggan perbulan",
"Total_Monthly_Sales": "Total penjualan Perbulan",
"Active_Users": "Pelanggan Aktif"
}
"Total_Monthly_Sales": "Total penjualan perbulan",
"Active_Users": "Pelanggan Aktif",
"SuperAdmin": "Super Admin",
"Lists": "Daftar",
"Vouchers": "Voucher",
"Refill_Customer": "Isi Ulang Pelanggan",
"Recharge_Customer": "Isi Ulang Pelanggan",
"Plans": "Paket",
"PPPOE": "PPPOE",
"Bandwidth": "Bandwidth",
"Send_Message": "Mengirim pesan",
"Single_Customer": "Pelanggan Tunggal",
"Bulk_Customers": "Pelanggan Massal",
"Radius": "Radius",
"Radius_NAS": "Radius NAS",
"Customer_Announcement": "Pengumuman Pelanggan",
"Language_Editor": "Editor Bahasa",
"Plan_Category": "Kategori Paket",
"ID": "ID",
"Prev": "Sebelumnya",
"Internet_Plan": "Paket Internet",
"Generated_By": "Dihasilkan oleh",
"All_Users_Insights": "Semua Wawasan Pengguna",
"year": "Tahun",
"month": "Bulan",
"week": "Pekan",
"day": "Hari",
"hour": "Jam",
"minute": "Menit",
"second": "Kedua",
"Account_Type": "Jenis akun",
"Contact": "Kontak",
"Paid": "Dibayar",
"Personal": "Pribadi",
"Coordinates": "Koordinat",
"Confirm": "Mengonfirmasi",
"Name": "Nama",
"Plan": "Paket",
"Using": "Menggunakan",
"Total": "Total",
"Additional_Cost": "Biaya tambahan",
"Resend": "Kirim ulang",
"Login": "Masuk",
"success": "Sukses",
"Click_Here": "Klik disini",
"Your_friend_do_not_have_active_package": "Teman Anda tidak memiliki paket aktif",
"If_your_friend_have_Additional_Cost__you_will_pay_for_that_too": "Jika teman Anda memiliki biaya tambahan, Anda juga akan membayarnya",
"Select_Payment_Gateway": "Pilih Gerbang Pembayaran",
"Available_Payment_Gateway": "Gerbang Pembayaran yang tersedia",
"Pay_Now": "Bayar sekarang",
"Notes": "Catatan",
"will_be_replaced_with_Customer_Name": "akan diganti dengan nama Pelanggan",
"will_be_replaced_with_Customer_username": "akan diganti dengan nama pengguna Pelanggan",
"will_be_replaced_with_Package_name": "akan diganti dengan nama paket",
"will_be_replaced_with_Package_price": "akan diganti dengan harga Paket",
"will_be_replaced_with_Expiration_date": "akan diganti dengan tanggal kedaluwarsa",
"additional_bills_for_customers": "tagihan tambahan untuk pelanggan",
"Your_Company_Name_at_Settings": "Nama Perusahaan Anda di pengaturan",
"Your_Company_Address_at_Settings": "Alamat Perusahaan Anda di pengaturan",
"Your_Company_Phone_at_Settings": "Telepon Perusahaan Anda di pengaturan",
"Invoice_number": "Nomor faktur",
"Date_invoice_created": "Tanggal faktur dibuat",
"Payment_gateway_user_paid_from": "Pengguna gateway pembayaran membayar dari",
"Payment_channel_user_paid_from": "Pengguna saluran pembayaran membayar dari",
"is_Hotspot_or_PPPOE": "adalah Hotspot atau PPPOE",
"Internet_Package": "Paket internet",
"Internet_Package_Prices": "Harga paket internet",
"Receiver_name": "Nama penerima",
"Username_internet": "Nama pengguna internet",
"User_password": "Kata sandi pengguna",
"Transaction_datetime": "Tanggal waktu transaksi",
"Balance_Before": "Saldo sebelumnya",
"Balance_After": "Saldo setelahnya",
"For_Notes_by_admin": "Untuk catatan oleh Admin",
"how_much_balance_have_been_send": "berapa banyak saldo yang telah dikirim",
"Current_Balance": "Saldo saat ini",
"Sender_name": "Nama pengirim",
"Customer_Balance": "Saldo Pelanggan",
"Privacy_Policy": "Kebijakan Privasi",
"Terms_and_Conditions": "Syarat dan Ketentuan",
"Disable_Registration": "Nonaktifkan Pendaftaran",
"Customer_just_Login_with_Phone_number_and_Voucher_Code__Voucher_will_be_password": "Pelanggan cukup masuk dengan nomor telepon dan kode voucher, Voucher akan menjadi kata sandi",
"After_Customer_activate_voucher_or_login__customer_will_be_redirected_to_this_url": "Setelah Pelanggan mengaktifkan voucher atau masuk, Pelanggan akan diarahkan ke URL ini",
"Extend_Postpaid_Expiration": "Perpanjang masa kedaluwarsa pascabayar",
"Allow_Extend": "Izinkan Perpanjang",
"Extend_Days": "Perpanjang Hari",
"Confirmation_Message": "Pesan konfirmasi",
"Email_Notification": "Pemberitahuan Email",
"This_Token_will_act_as_SuperAdmin_Admin": "Token ini akan bertindak sebagai SuperAdmin\/Admin",
"Miscellaneous": "Aneka ragam",
"OTP_Required": "Diperlukan OTP",
"OTP_is_required_when_user_want_to_change_phone_number": "OTP diperlukan ketika pengguna ingin mengganti nomor telepon",
"OTP_Method": "Metode OTP",
"SMS": "SMS",
"WhatsApp": "WhatsApp",
"SMS_and_WhatsApp": "SMS dan WhatsApp",
"The_method_which_OTP_will_be_sent_to_user": "Metode OTP yang akan dikirimkan ke pengguna"
}

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -17,12 +17,14 @@
<div class="col-md-6">
<textarea class="form-control" id="expired" name="expired"
placeholder="Hello [[name]], your internet package [[package]] has been expired"
rows="3">{if $_json['expired']!=''}{Lang::htmlspecialchars($_json['expired'])}{else}Hello [[name]], your internet package [[package]] has been expired.{/if}</textarea>
rows="4">{if $_json['expired']!=''}{Lang::htmlspecialchars($_json['expired'])}{else}Hello [[name]], your internet package [[package]] has been expired.{/if}</textarea>
</div>
<p class="help-block col-md-4">
<b>[[name]]</b> will be replaced with Customer Name.
<b>[[package]]</b> will be replaced with Package name.
<b>[[price]]</b> will be replaced with Package price.
<b>[[name]]</b> - {Lang::T('will be replaced with Customer Name')}.<br>
<b>[[username]]</b> - {Lang::T('will be replaced with Customer username')}.<br>
<b>[[package]]</b> - {Lang::T('will be replaced with Package name')}.<br>
<b>[[price]]</b> - {Lang::T('will be replaced with Package price')}.<br>
<b>[[bills]]</b> - {Lang::T('additional bills for customers')}.
</p>
</div>
</div>
@ -31,13 +33,15 @@
<label class="col-md-2 control-label">{Lang::T('Reminder 7 days')}</label>
<div class="col-md-6">
<textarea class="form-control" id="reminder_7_day" name="reminder_7_day"
rows="3">{Lang::htmlspecialchars($_json['reminder_7_day'])}</textarea>
rows="4">{Lang::htmlspecialchars($_json['reminder_7_day'])}</textarea>
</div>
<p class="help-block col-md-4">
<b>[[name]]</b> will be replaced with Customer Name.
<b>[[package]]</b> will be replaced with Package name.
<b>[[price]]</b> will be replaced with Package price.
<b>[[expired_date]]</b> will be replaced with Expiration date.
<b>[[name]]</b> - {Lang::T('will be replaced with Customer Name')}.<br>
<b>[[username]]</b> - {Lang::T('will be replaced with Customer username')}.<br>
<b>[[package]]</b> - {Lang::T('will be replaced with Package name')}.<br>
<b>[[price]]</b> - {Lang::T('will be replaced with Package price')}.<br>
<b>[[expired_date]]</b> - {Lang::T('will be replaced with Expiration date')}.<br>
<b>[[bills]]</b> - {Lang::T('additional bills for customers')}.
</p>
</div>
</div>
@ -46,13 +50,15 @@
<label class="col-md-2 control-label">{Lang::T('Reminder 3 days')}</label>
<div class="col-md-6">
<textarea class="form-control" id="reminder_3_day" name="reminder_3_day"
rows="3">{Lang::htmlspecialchars($_json['reminder_3_day'])}</textarea>
rows="4">{Lang::htmlspecialchars($_json['reminder_3_day'])}</textarea>
</div>
<p class="help-block col-md-4">
<b>[[name]]</b> will be replaced with Customer Name.
<b>[[package]]</b> will be replaced with Package name.
<b>[[price]]</b> will be replaced with Package price.
<b>[[expired_date]]</b> will be replaced with Expiration date.
<b>[[name]]</b> - {Lang::T('will be replaced with Customer Name')}.<br>
<b>[[username]]</b> - {Lang::T('will be replaced with Customer username')}.<br>
<b>[[package]]</b> - {Lang::T('will be replaced with Package name')}.<br>
<b>[[price]]</b> - {Lang::T('will be replaced with Package price')}.<br>
<b>[[expired_date]]</b> - {Lang::T('will be replaced with Expiration date')}.<br>
<b>[[bills]]</b> - {Lang::T('additional bills for customers')}.
</p>
</div>
</div>
@ -61,13 +67,15 @@
<label class="col-md-2 control-label">{Lang::T('Reminder 1 day')}</label>
<div class="col-md-6">
<textarea class="form-control" id="reminder_1_day" name="reminder_1_day"
rows="3">{Lang::htmlspecialchars($_json['reminder_1_day'])}</textarea>
rows="4">{Lang::htmlspecialchars($_json['reminder_1_day'])}</textarea>
</div>
<p class="help-block col-md-4">
<b>[[name]]</b> will be replaced with Customer Name.
<b>[[package]]</b> will be replaced with Package name.
<b>[[price]]</b> will be replaced with Package price.
<b>[[expired_date]]</b> will be replaced with Expiration date.
<b>[[name]]</b> - {Lang::T('will be replaced with Customer Name')}.<br>
<b>[[username]]</b> - {Lang::T('will be replaced with Customer username')}.<br>
<b>[[package]]</b> - {Lang::T('will be replaced with Package name')}.<br>
<b>[[price]]</b> - {Lang::T('will be replaced with Package price')}.<br>
<b>[[expired_date]]</b> - {Lang::T('will be replaced with Expiration date')}.<br>
<b>[[bills]]</b> - {Lang::T('additional bills for customers')}.
</p>
</div>
</div>
@ -80,21 +88,22 @@
rows="20">{Lang::htmlspecialchars($_json['invoice_paid'])}</textarea>
</div>
<p class="col-md-4 help-block">
<b>[[company_name]]</b> Your Company Name at Settings.<br>
<b>[[address]]</b> Your Company Address at Settings.<br>
<b>[[phone]]</b> Your Company Phone at Settings.<br>
<b>[[invoice]]</b> invoice number.<br>
<b>[[date]]</b> Date invoice created.<br>
<b>[[payment_gateway]]</b> Payment gateway user paid from.<br>
<b>[[payment_channel]]</b> Payment channel user paid from.<br>
<b>[[type]]</b> is Hotspot/PPPOE.<br>
<b>[[plan_name]]</b> Internet Package.<br>
<b>[[plan_price]]</b> Internet Package Prices.<br>
<b>[[name]]</b> Receiver name.<br>
<b>[[user_name]]</b> Username internet.<br>
<b>[[user_password]]</b> User password.<br>
<b>[[expired_date]]</b> Expired datetime.<br>
<b>[[footer]]</b> Invoice Footer.
<b>[[company_name]]</b> {Lang::T('Your Company Name at Settings')}.<br>
<b>[[address]]</b> {Lang::T('Your Company Address at Settings')}.<br>
<b>[[phone]]</b> - {Lang::T('Your Company Phone at Settings')}.<br>
<b>[[invoice]]</b> - {Lang::T('Invoice number')}.<br>
<b>[[date]]</b> - {Lang::T('Date invoice created')}.<br>
<b>[[payment_gateway]]</b> - {Lang::T('Payment gateway user paid from')}.<br>
<b>[[payment_channel]]</b> - {Lang::T('Payment channel user paid from')}.<br>
<b>[[type]]</b> - {Lang::T('is Hotspot or PPPOE')}.<br>
<b>[[plan_name]]</b> - {Lang::T('Internet Package')}.<br>
<b>[[plan_price]]</b> - {Lang::T('Internet Package Prices')}.<br>
<b>[[name]]</b> - {Lang::T('Receiver name')}.<br>
<b>[[user_name]]</b> - {Lang::T('Username internet')}.<br>
<b>[[user_password]]</b> - {Lang::T('User password')}.<br>
<b>[[expired_date]]</b> - {Lang::T('Expired datetime')}.<br>
<b>[[footer]]</b> - {Lang::T('Invoice Footer')}.<br>
<b>[[note]]</b> - {Lang::T('For Notes by admin')}.<br>
</p>
</div>
</div>
@ -107,23 +116,23 @@
rows="20">{Lang::htmlspecialchars($_json['invoice_balance'])}</textarea>
</div>
<p class="col-md-4 help-block">
<b>[[company_name]]</b> Your Company Name at Settings.<br>
<b>[[address]]</b> Your Company Address at Settings.<br>
<b>[[phone]]</b> Your Company Phone at Settings.<br>
<b>[[invoice]]</b> invoice number.<br>
<b>[[date]]</b> Date invoice created.<br>
<b>[[payment_gateway]]</b> Payment gateway user paid from.<br>
<b>[[payment_channel]]</b> Payment channel user paid from.<br>
<b>[[type]]</b> is Hotspot/PPPOE.<br>
<b>[[plan_name]]</b> Internet Package.<br>
<b>[[plan_price]]</b> Internet Package Prices.<br>
<b>[[name]]</b> Receiver name.<br>
<b>[[user_name]]</b> Username internet.<br>
<b>[[user_password]]</b> User password.<br>
<b>[[trx_date]]</b> Transaction datetime.<br>
<b>[[balance_before]]</b> Balance Before.<br>
<b>[[balance]]</b> Balance After.<br>
<b>[[footer]]</b> Invoice Footer.
<b>[[company_name]]</b> - {Lang::T('Your Company Name at Settings')}.<br>
<b>[[address]]</b> - {Lang::T('Your Company Address at Settings')}.<br>
<b>[[phone]]</b> - {Lang::T('Your Company Phone at Settings')}.<br>
<b>[[invoice]]</b> - {Lang::T('Invoice number')}.<br>
<b>[[date]]</b> - {Lang::T('Date invoice created')}.<br>
<b>[[payment_gateway]]</b> - {Lang::T('Payment gateway user paid from')}.<br>
<b>[[payment_channel]]</b> - {Lang::T('Payment channel user paid from')}.<br>
<b>[[type]]</b> - {Lang::T('is Hotspot or PPPOE')}.<br>
<b>[[plan_name]]</b> - {Lang::T('Internet Package')}.<br>
<b>[[plan_price]]</b> - {Lang::T('Internet Package Prices')}.<br>
<b>[[name]]</b> - {Lang::T('Receiver name')}.<br>
<b>[[user_name]]</b> - {Lang::T('Username internet')}.<br>
<b>[[user_password]]</b> - {Lang::T('User password')}.<br>
<b>[[trx_date]]</b> - {Lang::T('Transaction datetime')}.<br>
<b>[[balance_before]]</b> - {Lang::T('Balance Before')}.<br>
<b>[[balance]]</b> - {Lang::T('Balance After')}.<br>
<b>[[footer]]</b> - {Lang::T('Invoice Footer')}.
</p>
</div>
</div>
@ -133,12 +142,12 @@
<label class="col-md-2 control-label">{Lang::T('Send Balance')}</label>
<div class="col-md-6">
<textarea class="form-control" id="balance_send" name="balance_send"
rows="3">{if $_json['balance_send']}{Lang::htmlspecialchars($_json['balance_send'])}{else}{Lang::htmlspecialchars($_default['balance_send'])}{/if}</textarea>
rows="4">{if $_json['balance_send']}{Lang::htmlspecialchars($_json['balance_send'])}{else}{Lang::htmlspecialchars($_default['balance_send'])}{/if}</textarea>
</div>
<p class="col-md-4 help-block">
<b>[[name]]</b> Receiver name.<br>
<b>[[balance]]</b> how much balance have been send.<br>
<b>[[current_balance]]</b> Current Balance.
<b>[[name]]</b> - {Lang::T('Receiver name')}.<br>
<b>[[balance]]</b> - {Lang::T('how much balance have been send')}.<br>
<b>[[current_balance]]</b> - {Lang::T('Current Balance')}.
</p>
</div>
</div>
@ -147,12 +156,12 @@
<label class="col-md-2 control-label">{Lang::T('Received Balance')}</label>
<div class="col-md-6">
<textarea class="form-control" id="balance_received" name="balance_received"
rows="3">{if $_json['balance_received']}{Lang::htmlspecialchars($_json['balance_received'])}{else}{Lang::htmlspecialchars($_default['balance_received'])}{/if}</textarea>
rows="4">{if $_json['balance_received']}{Lang::htmlspecialchars($_json['balance_received'])}{else}{Lang::htmlspecialchars($_default['balance_received'])}{/if}</textarea>
</div>
<p class="col-md-4 help-block">
<b>[[name]]</b> Sender name.<br>
<b>[[balance]]</b> how much balance have been received.<br>
<b>[[current_balance]]</b> Current Balance.
<b>[[name]]</b> - {Lang::T('Sender name')}.<br>
<b>[[balance]]</b> - {Lang::T('how much balance have been received')}.<br>
<b>[[current_balance]]</b> - {Lang::T('Current Balance')}.
</p>
</div>
</div>
@ -167,4 +176,4 @@
</div>
</div>
</form>
{include file="sections/footer.tpl"}
{include file="sections/footer.tpl"}

View File

@ -77,8 +77,8 @@
<option value="default" {if $_c['theme'] eq 'default' }selected="selected" {/if}>Default
</option>
{foreach $themes as $theme}
<option value="{$theme}" {if $_c['theme'] eq $theme}selected="selected" {/if}>
{Lang::ucWords($theme)}</option>
<option value="{$theme}" {if $_c['theme'] eq $theme}selected="selected" {/if}>
{Lang::ucWords($theme)}</option>
{/foreach}
</select>
</div>
@ -86,6 +86,13 @@
href="https://github.com/hotspotbilling/phpnuxbill/wiki/Themes" target="_blank">Theme
info</a></p>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Recharge Using')}</label>
<div class="col-md-6">
<input type="text" name="payment_usings" class="form-control" value="{$_c['payment_usings']}" placeholder="{Lang::T('Cash')}, {Lang::T('Bank Transfer')}">
</div>
<p class="help-block col-md-4">This used for admin to select payment in recharge, using comma for every new options</p>
</div>
<div class="form-group">
<label class="col-md-2 control-label">APP URL</label>
<div class="col-md-6">
@ -152,38 +159,42 @@
<option value="rand" {if $_c['voucher_format']=='rand' }selected="selected" {/if}>
RaNdoM
</option>
<option value="numbers" {if $_c['voucher_format'] == 'numbers'}selected="selected"
{/if}>
Numbers
</option>
</select>
</div>
<p class="help-block col-md-4">UPPERCASE lowercase RaNdoM</p>
</div>
{if $_c['disable_voucher'] != 'yes'}
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Disable Registration')}</label>
<div class="col-md-6">
<select name="disable_registration" id="disable_registration" class="form-control">
<option value="no" {if $_c['disable_registration']=='no' }selected="selected" {/if}>No
</option>
<option value="yes" {if $_c['disable_registration']=='yes' }selected="selected" {/if}>
Yes
</option>
</select>
</div>
<p class="help-block col-md-4">
{Lang::T('Customer just Login with Phone number and Voucher Code, Voucher will be
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Disable Registration')}</label>
<div class="col-md-6">
<select name="disable_registration" id="disable_registration" class="form-control">
<option value="no" {if $_c['disable_registration']=='no' }selected="selected" {/if}>No
</option>
<option value="yes" {if $_c['disable_registration']=='yes' }selected="selected" {/if}>
Yes
</option>
</select>
</div>
<p class="help-block col-md-4">
{Lang::T('Customer just Login with Phone number and Voucher Code, Voucher will be
password')}
</p>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Redirect after Activation</label>
<div class="col-md-6">
<input type="text" class="form-control" id="voucher_redirect" name="voucher_redirect"
placeholder="https://192.168.88.1/status" value="{$voucher_redirect}">
</p>
</div>
<p class="help-block col-md-4">
{Lang::T('After Customer activate voucher or login, customer will be redirected to this
<div class="form-group">
<label class="col-md-2 control-label">Redirect after Activation</label>
<div class="col-md-6">
<input type="text" class="form-control" id="voucher_redirect" name="voucher_redirect"
placeholder="https://192.168.88.1/status" value="{$voucher_redirect}">
</div>
<p class="help-block col-md-4">
{Lang::T('After Customer activate voucher or login, customer will be redirected to this
url')}
</p>
</div>
</p>
</div>
{/if}
</div>
<div class="panel-heading">
@ -213,6 +224,39 @@
</div>
</div>
</div>
<div class="panel-heading">
<div class="btn-group pull-right">
<button class="btn btn-primary btn-xs" title="save" type="submit"><span
class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span></button>
</div>
{Lang::T('Extend Postpaid Expiration')}
</div>
<div class="panel-body">
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Allow Extend')}</label>
<div class="col-md-6">
<select name="extend_expired" id="extend_expired" class="form-control text-muted">
<option value="0">No</option>
<option value="1" {if $_c['extend_expired']}selected="selected" {/if}>Yes</option>
</select>
</div>
<p class="help-block col-md-4">Customer can request to extend expirations</p>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Extend Days')}</label>
<div class="col-md-6">
<input type="text" class="form-control" name="extend_days" placeholder="3"
value="{$_c['extend_days']}">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Confirmation Message')}</label>
<div class="col-md-6">
<textarea type="text" rows="4" class="form-control" name="extend_confirmation"
placeholder="i agree to extends and will paid full after this">{$_c['extend_confirmation']}</textarea>
</div>
</div>
</div>
<div class="panel-heading">
<div class="btn-group pull-right">
<button class="btn btn-primary btn-xs" title="save" type="submit"><span
@ -306,8 +350,8 @@
onchange="document.getElementById('sms_url').value = this.value">
<option value="">Select Router</option>
{foreach $r as $rs}
<option value="{$rs['name']}" {if $rs['name']==$_c['sms_url']}selected{/if}>
{$rs['name']}</option>
<option value="{$rs['name']}" {if $rs['name']==$_c['sms_url']}selected{/if}>
{$rs['name']}</option>
{/foreach}
</select>
</div>
@ -340,6 +384,74 @@
<small id="emailHelp" class="form-text text-muted">You can use WhatsApp in here too. <a
href="https://wa.nux.my.id/login" target="_blank">Free Server</a></small>
</div>
<div class="panel-heading">
<div class="btn-group pull-right">
<a class="btn btn-success btn-xs" style="color: black;" href="javascript:testEmail()">Test
Email</a>
<button class="btn btn-primary btn-xs" title="save" type="submit"><span
class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span></button>
</div>
{Lang::T('Email Notification')}
</div>
<div class="panel-body">
<div class="form-group">
<label class="col-md-2 control-label">SMTP Host : port</label>
<div class="col-md-4">
<input type="text" class="form-control" id="smtp_host" name="smtp_host"
value="{$_c['smtp_host']}" placeholder="smtp.host.tld">
</div>
<div class="col-md-2">
<input type="number" class="form-control" id="smtp_port" name="smtp_port"
value="{$_c['smtp_port']}" placeholder="465 587 port">
</div>
<p class="help-block col-md-4">Empty this to use internal mail() PHP</p>
</div>
<div class="form-group">
<label class="col-md-2 control-label">SMTP username</label>
<div class="col-md-6">
<input type="text" class="form-control" id="smtp_user" name="smtp_user"
value="{$_c['smtp_user']}" placeholder="user@host.tld">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">SMTP Password</label>
<div class="col-md-6">
<input type="password" class="form-control" id="smtp_pass" name="smtp_pass"
value="{$_c['smtp_pass']}" onmouseleave="this.type = 'password'"
onmouseenter="this.type = 'text'">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">SMTP Security</label>
<div class="col-md-6">
<select name="smtp_ssltls" id="smtp_ssltls" class="form-control">
<option value="" {if $_c['smtp_ssltls']=='' }selected="selected" {/if}>Not Secure
</option>
<option value="ssl" {if $_c['smtp_ssltls']=='ssl' }selected="selected" {/if}>SSL
</option>
<option value="tls" {if $_c['smtp_ssltls']=='tls' }selected="selected" {/if}>TLS
</option>
</select>
</div>
<p class="help-block col-md-4">UPPERCASE lowercase RaNdoM</p>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Mail From</label>
<div class="col-md-6">
<input type="text" class="form-control" id="mail_from" name="mail_from"
value="{$_c['mail_from']}" placeholder="noreply@host.tld">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Mail Reply To</label>
<div class="col-md-6">
<input type="text" class="form-control" id="mail_reply_to" name="mail_reply_to"
value="{$_c['mail_reply_to']}" placeholder="support@host.tld">
</div>
<p class="help-block col-md-4">Customer will reply email to this address, empty if you want to
use From Address</p>
</div>
</div>
<div class="panel-heading">
<div class="btn-group pull-right">
<button class="btn btn-primary btn-xs" title="save" type="submit"><span
@ -491,6 +603,71 @@
<p class="help-block col-md-4">{Lang::T('The method which OTP will be sent to user')}</p>
</div>
</div>
{* <div class="panel-heading">
<div class="btn-group pull-right">
<button class="btn btn-primary btn-xs" title="save" type="submit">
<span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span>
</button>
</div>
{Lang::T('Tax System')}
</div>
<div class="panel-body">
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Enable Tax System')}</label>
<div class="col-md-6">
<select name="enable_tax" id="enable_tax" class="form-control">
<option value="no" {if $_c['enable_tax']=='no' }selected="selected" {/if}>
{Lang::T('No')}
</option>
<option value="yes" {if $_c['enable_tax']=='yes' }selected="selected" {/if}>
{Lang::T('Yes')}
</option>
</select>
</div>
<p class="help-block col-md-4">{Lang::T('Tax will be calculated in Internet Plan Price')}</p>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Tax Rate')}</label>
<div class="col-md-6">
<select name="tax_rate" id="tax_rate" class="form-control">
<option value="0.005" {if $_c['tax_rate']=='0.005' }selected="selected" {/if}>
{Lang::T('0.5%')}
</option>
<option value="0.01" {if $_c['tax_rate']=='0.01' }selected="selected" {/if}>
{Lang::T('1%')}
</option>
<option value="0.015" {if $_c['tax_rate']=='0.015' }selected="selected" {/if}>
{Lang::T('1.5%')}
</option>
<option value="0.02" {if $_c['tax_rate']=='0.02' }selected="selected" {/if}>
{Lang::T('2%')}
</option>
<option value="0.05" {if $_c['tax_rate']=='0.05' }selected="selected" {/if}>
{Lang::T('5%')}
</option>
<option value="0.1" {if $_c['tax_rate']=='0.1' }selected="selected" {/if}>
{Lang::T('10%')}
</option>
<!-- Custom tax rate option -->
<option value="custom" {if $_c['tax_rate']=='custom' }selected="selected" {/if}>
{Lang::T('Custom')}</option>
</select>
</div>
<p class="help-block col-md-4">{Lang::T('Tax Rates in percentage')}</p>
</div>
<!-- Custom tax rate input field (initially hidden) -->
<div class="form-group" id="customTaxRate" style="display: none;">
<label class="col-md-2 control-label">{Lang::T('Custom Tax Rate')}</label>
<div class="col-md-6">
<input type="text" value="{$_c['custom_tax_rate']}" class="form-control"
name="custom_tax_rate" id="custom_tax_rate"
placeholder="{Lang::T('Enter Custom Tax Rate')}">
</div>
<p class="help-block col-md-4">{Lang::T('Enter the custom tax rate (e.g., 3.75 for 3.75%)')}</p>
</div>
</div> *}
{* <div class="panel-heading" id="envato">
<div class="btn-group pull-right">
<button class="btn btn-primary btn-xs" title="save" type="submit"><span
@ -561,8 +738,38 @@ add dst-host=*.{$_domain}</pre>
}
}
function testEmail() {
var target = prompt("Email\nSave First before Test", "");
if (target != null) {
window.location.href = '{$_url}settings/app&testEmail=' + target;
}
}
function testTg() {
window.location.href = '{$_url}settings/app&testTg=test';
}
</script>
<script>
document.addEventListener("DOMContentLoaded", function() {
// Function to toggle visibility of custom tax rate input field
function toggleCustomTaxRate() {
var taxRateSelect = document.getElementById("tax_rate");
var customTaxRateInput = document.getElementById("customTaxRate");
if (taxRateSelect.value === "custom") {
customTaxRateInput.style.display = "block";
} else {
customTaxRateInput.style.display = "none";
}
}
// Call the function when the page loads
toggleCustomTaxRate();
// Call the function whenever the tax rate dropdown value changes
document.getElementById("tax_rate").addEventListener("change", toggleCustomTaxRate);
});
</script>
{include file="sections/footer.tpl"}

View File

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

View File

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

View File

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

View File

@ -1,58 +1,65 @@
{include file="sections/header.tpl"}
<div class="row">
<div class="col-sm-12">
<div class="panel panel-hovered mb20 panel-primary">
<div class="panel-heading">{Lang::T('Bandwidth Plans')}</div>
<div class="panel-body">
<div class="md-whiteframe-z1 mb20 text-center" style="padding: 15px">
<div class="col-md-8">
<form id="site-search" method="post" action="{$_url}bandwidth/list/">
<div class="input-group">
<div class="input-group-addon">
<span class="fa fa-search"></span>
</div>
<input type="text" name="name" class="form-control" placeholder="{Lang::T('Search by Name')}...">
<div class="input-group-btn">
<button class="btn btn-success" type="submit">{Lang::T('Search')}</button>
</div>
</div>
</form>
</div>
<div class="col-md-4">
<a href="{$_url}bandwidth/add" class="btn btn-primary btn-block"><i class="ion ion-android-add"> </i> {Lang::T('New Bandwidth')}</a>
</div>&nbsp;
</div>
<div class="table-responsive">
<table class="table table-bordered table-condensed table-striped table_mobile">
<thead>
<tr>
<th>{Lang::T('Bandwidth Name')}</th>
<th>{Lang::T('Rate')}</th>
<th>{Lang::T('Burst')}</th>
<th>{Lang::T('Manage')}</th>
</tr>
</thead>
<tbody>
{foreach $d as $ds}
<tr>
<td>{$ds['name_bw']}</td>
<td>{$ds['rate_down']} {$ds['rate_down_unit']} / {$ds['rate_up']} {$ds['rate_up_unit']}</td>
<td>{$ds['burst']}</td>
<td>
<a href="{$_url}bandwidth/edit/{$ds['id']}" class="btn btn-sm btn-warning">{Lang::T('Edit')}</a>
<a href="{$_url}bandwidth/delete/{$ds['id']}" id="{$ds['id']}" class="btn btn-danger btn-sm" onclick="return confirm('{Lang::T('Delete')}?')" ><i class="glyphicon glyphicon-trash"></i></a>
</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
{$paginator['contents']}
<div class="row">
<div class="col-sm-12">
<div class="panel panel-hovered mb20 panel-primary">
<div class="panel-heading">{Lang::T('Bandwidth Plans')}</div>
<div class="panel-body">
<div class="md-whiteframe-z1 mb20 text-center" style="padding: 15px">
<div class="col-md-8">
<form id="site-search" method="post" action="{$_url}bandwidth/list/">
<div class="input-group">
<div class="input-group-addon">
<span class="fa fa-search"></span>
</div>
<input type="text" name="name" class="form-control"
placeholder="{Lang::T('Search by Name')}...">
<div class="input-group-btn">
<button class="btn btn-success" type="submit">{Lang::T('Search')}</button>
</div>
</div>
</div>
</form>
</div>
<div class="col-md-4">
<a href="{$_url}bandwidth/add" class="btn btn-primary btn-block"><i class="ion ion-android-add">
</i> {Lang::T('New Bandwidth')}</a>
</div>&nbsp;
</div>
<div class="table-responsive">
<table class="table table-bordered table-condensed table-striped table_mobile">
<thead>
<tr>
<th>{Lang::T('Bandwidth Name')}</th>
<th>{Lang::T('Rate')}</th>
<th>{Lang::T('Burst')}</th>
<th>{Lang::T('Manage')}</th>
</tr>
</thead>
<tbody>
{foreach $d as $ds}
<tr>
<td>{$ds['name_bw']}</td>
<td>{$ds['rate_down']} {$ds['rate_down_unit']} / {$ds['rate_up']} {$ds['rate_up_unit']}
</td>
<td>{$ds['burst']}</td>
<td>
<a href="{$_url}bandwidth/edit/{$ds['id']}"
class="btn btn-sm btn-warning">{Lang::T('Edit')}</a>
<a href="{$_url}bandwidth/delete/{$ds['id']}" id="{$ds['id']}"
class="btn btn-danger btn-sm"
onclick="return confirm('{Lang::T('Delete')}?')"><i
class="glyphicon glyphicon-trash"></i></a>
</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
{include file="pagination.tpl"}
</div>
</div>
</div>
</div>
</div>
{include file="sections/footer.tpl"}

View File

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

View File

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

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

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

View File

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

View File

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

View File

@ -74,8 +74,7 @@
<div class="box-tools pull-right">
<button type="button" class="btn bg-teal btn-sm" data-widget="collapse"><i class="fa fa-minus"></i>
</button>
<a href="{$_url}settings/app#hide_dashboard_content" class="btn bg-teal btn-sm"><i
class="fa fa-times"></i>
<a href="{$_url}dashboard&refresh" class="btn bg-teal btn-sm"><i class="fa fa-refresh"></i>
</a>
</div>
</div>
@ -96,8 +95,7 @@
<div class="box-tools pull-right">
<button type="button" class="btn bg-teal btn-sm" data-widget="collapse"><i class="fa fa-minus"></i>
</button>
<a href="{$_url}settings/app#hide_dashboard_content" class="btn bg-teal btn-sm"><i
class="fa fa-times"></i>
<a href="{$_url}dashboard&refresh" class="btn bg-teal btn-sm"><i class="fa fa-refresh"></i>
</a>
</div>
</div>
@ -146,24 +144,30 @@
<thead>
<tr>
<th>{Lang::T('Username')}</th>
<th>{Lang::T('Created On')}</th>
<th>{Lang::T('Expires On')}</th>
<th>{Lang::T('Created / Expired')}</th>
<th>{Lang::T('Internet Plan')}</th>
<th>{Lang::T('Location')}</th>
</tr>
</thead>
<tbody>
{foreach $expire as $expired}
{assign var="rem_exp" value="{$expired['expiration']} {$expired['time']}"}
{assign var="rem_started" value="{$expired['recharged_on']} {$expired['recharged_time']}"}
<tr>
<td><a href="{$_url}customers/viewu/{$expired['username']}">{$expired['username']}</a></td>
<td>{Lang::dateAndTimeFormat($expired['recharged_on'],$expired['recharged_time'])}
</td>
<td>{Lang::dateAndTimeFormat($expired['expiration'],$expired['time'])}
<td><small data-toggle="tooltip" data-placement="top"
title="{Lang::dateAndTimeFormat($expired['recharged_on'],$expired['recharged_time'])}">{Lang::timeElapsed($rem_started)}</small> /
<span data-toggle="tooltip" data-placement="top"
title="{Lang::dateAndTimeFormat($expired['expiration'],$expired['time'])}">{Lang::timeElapsed($rem_exp)}</span>
</td>
<td>{$expired['namebp']}</td>
<td>{$expired['routers']}</td>
</tr>
</tbody>
{/foreach}
</table>
</div>
&nbsp; {$paginator['contents']}
&nbsp; {include file="pagination.tpl"}
</div>
{/if}
</div>
@ -381,6 +385,21 @@
var latestVersion = data.version;
if (localVersion !== latestVersion) {
$('#version').html('Latest Version: ' + latestVersion);
Swal.fire({
icon: 'info',
title: "New Version Available\nVersion: "+latestVersion,
toast: true,
position: 'bottom-right',
showConfirmButton: true,
showCloseButton: true,
timer: 30000,
confirmButtonText: '<a href="{$_url}community#latestVersion" style="color: white;">Update Now</a>',
timerProgressBar: true,
didOpen: (toast) => {
toast.addEventListener('mouseenter', Swal.stopTimer)
toast.addEventListener('mouseleave', Swal.resumeTimer)
}
});
}
});
});

View File

@ -6,6 +6,7 @@
<div class="panel-heading">{Lang::T('Refill Balance')}</div>
<div class="panel-body">
<form class="form-horizontal" method="post" role="form" action="{$_url}plan/deposit-post">
<input type="hidden" name="stoken" value="{App::getToken()}">
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Select Account')}</label>
<div class="col-md-6">

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,65 +1,64 @@
{include file="sections/header.tpl"}
<div class="row">
<div class="col-sm-12 col-md-12">
<div class="panel panel-primary panel-hovered panel-stacked mb30">
<div class="panel-heading">{Lang::T('Send Personal Message')}</div>
<div class="panel-body">
<form class="form-horizontal" method="post" role="form" action="{$_url}message/send-post" >
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Customer')}</label>
<div class="col-md-6">
<select id="personSelect" class="form-control select2" name="id_customer" style="width: 100%" data-placeholder="Select a customer...">
<option></option>
{foreach $c as $cs}
{if $id eq $cs['id']}
<option value="{$cs['id']}" selected>{$cs['username']}</option>
{else}
<option value="{$cs['id']}">{$cs['username']}</option>
{/if}
{/foreach}
</select>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Send Via')}</label>
<div class="col-md-6">
<select class="form-control" name="via" id="via">
<option value="sms" selected> {Lang::T('SMS')}</option>
<option value="wa"> {Lang::T('WhatsApp')}</option>
<option value="both"> {Lang::T('SMS and WhatsApp')}</option>
</select>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Message')}</label>
<div class="col-md-6">
<textarea class="form-control" id="message" name="message" placeholder="{Lang::T('Compose your message...')}" rows="5"></textarea>
</div>
<p class="help-block col-md-4">
{Lang::T('Use placeholders:')}
<br>
<b>{Lang::T('[[name]]')}</b> - {Lang::T('Customer Name')}
<br>
<b>{Lang::T('[[user_name]]')}</b> - {Lang::T('Customer Username')}
<br>
<b>{Lang::T('[[phone]]')}</b> - {Lang::T('Customer Phone')}
<br>
<b>{Lang::T('[[company_name]]')}</b> - {Lang::T('Your Company Name')}
</p>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<button class="btn btn-success" type="submit">{Lang::T('Send Message')}</button>
<a href="{$_url}dashboard" class="btn btn-default">{Lang::T('Cancel')}</a>
</div>
</div>
</form>
<div class="row">
<div class="col-sm-12 col-md-12">
<div class="panel panel-primary panel-hovered panel-stacked mb30">
<div class="panel-heading">{Lang::T('Send Personal Message')}</div>
<div class="panel-body">
<form class="form-horizontal" method="post" role="form" action="{$_url}message/send-post">
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Customer')}</label>
<div class="col-md-6">
<select {if $cust}{else}id="personSelect" {/if} class="form-control select2"
name="id_customer" style="width: 100%"
data-placeholder="{Lang::T('Select a customer')}...">
{if $cust}
<option value="{$cust['id']}">{$cust['username']} &bull; {$cust['fullname']} &bull;
{$cust['email']}</option>
{/if}
</select>
</div>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Send Via')}</label>
<div class="col-md-6">
<select class="form-control" name="via" id="via">
<option value="sms" selected> {Lang::T('SMS')}</option>
<option value="wa"> {Lang::T('WhatsApp')}</option>
<option value="both"> {Lang::T('SMS and WhatsApp')}</option>
</select>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Message')}</label>
<div class="col-md-6">
<textarea class="form-control" id="message" name="message"
placeholder="{Lang::T('Compose your message...')}" rows="5"></textarea>
</div>
<p class="help-block col-md-4">
{Lang::T('Use placeholders:')}
<br>
<b>[[name]]</b> - {Lang::T('Customer Name')}
<br>
<b>[[user_name]]</b> - {Lang::T('Customer Username')}
<br>
<b>[[phone]]</b> - {Lang::T('Customer Phone')}
<br>
<b>[[company_name]]</b> - {Lang::T('Your Company Name')}
</p>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<button class="btn btn-success" type="submit">{Lang::T('Send Message')}</button>
<a href="{$_url}dashboard" class="btn btn-default">{Lang::T('Cancel')}</a>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{include file="sections/footer.tpl"}
{include file="sections/footer.tpl"}

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

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

View File

@ -11,7 +11,7 @@
class="glyphicon glyphicon-refresh" aria-hidden="true"></span> sync</a>
</div>
<div class="btn-group pull-right">
<a class="btn btn-info btn-xs" title="save" href="{$_url}customers/csv"
<a class="btn btn-info btn-xs" title="save" href="{$_url}customers/csv-prepaid"
onclick="return confirm('This will export to CSV?')"><span class="glyphicon glyphicon-download"
aria-hidden="true"></span> CSV</a>
</div>
@ -65,23 +65,37 @@
<td>{$ds['routers']}</td>
<td>
<a href="{$_url}plan/edit/{$ds['id']}"
class="btn btn-warning btn-xs">{Lang::T('Edit')}</a>
class="btn btn-warning btn-xs" style="color: black;">{Lang::T('Edit')}</a>
{if in_array($_admin['user_type'],['SuperAdmin','Admin'])}
<a href="{$_url}plan/delete/{$ds['id']}" id="{$ds['id']}"
onclick="return confirm('{Lang::T('Delete')}?')"
class="btn btn-danger btn-xs"><i class="glyphicon glyphicon-trash"></i></a>
{/if}
{if $ds['status']=='off' && $_c['extend_expired']}
<a href="javascript:extend('{$ds['id']}')"
class="btn btn-info btn-xs">{Lang::T('Extend')}</a>
{/if}
</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
{$paginator['contents']}
{include file="pagination.tpl"}
</div>
</div>
</div>
</div>
<script>
function extend(idP){
var res = prompt("Extend for many days?", "3");
if(res){
if(confirm("Extend for "+res+" days?")){
window.location.href = "{$_url}plan/extend/"+idP+"/"+res+"&stoken={App::getToken()}";
}
}
}
</script>
{include file="sections/footer.tpl"}
{include file="sections/footer.tpl"}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -45,7 +45,9 @@
<label class="col-md-2 control-label">{Lang::T('Using')}</label>
<div class="col-md-6">
<select name="using" class="form-control">
<option value="cash">{Lang::T('Cash')}</option>
{foreach $usings as $using}
<option value="{trim(ucWords($using))}">{trim(ucWords($using))}</option>
{/foreach}
{if $_c['enable_balance'] eq 'yes'}
<option value="balance">{Lang::T('Customer Balance')}</option>
{/if}

View File

@ -26,22 +26,22 @@
<hr>
</div>
{if isset($notify)}
<script>
// Display SweetAlert toast notification
Swal.fire({
icon: '{if $notify_t == "s"}success{else}warning{/if}',
title: '{$notify}',
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 5000,
timerProgressBar: true,
didOpen: (toast) => {
toast.addEventListener('mouseenter', Swal.stopTimer)
toast.addEventListener('mouseleave', Swal.resumeTimer)
}
});
</script>
<script>
// Display SweetAlert toast notification
Swal.fire({
icon: '{if $notify_t == "s"}success{else}warning{/if}',
title: '{$notify}',
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 5000,
timerProgressBar: true,
didOpen: (toast) => {
toast.addEventListener('mouseenter', Swal.stopTimer)
toast.addEventListener('mouseleave', Swal.resumeTimer)
}
});
</script>
{/if}
<div class="row">
<div class="col-md-4">
@ -59,16 +59,17 @@
<div class="panel-body">
<div class="form-container">
<div class="form-group">
<label>{Lang::T('Phone Number')}</label>
<label>{if $_c['country_code_phone']!= ''}{Lang::T('Phone Number')}{else}{Lang::T('Username')}{/if}</label>
<div class="input-group">
{if $_c['country_code_phone']!= ''}
<span class="input-group-addon" id="basic-addon1">+</span>
{else}
<span class="input-group-addon" id="basic-addon1"><i
class="glyphicon glyphicon-phone-alt"></i></span>
{else}
<span class="input-group-addon" id="basic-addon1"><i
class="glyphicon glyphicon-user"></i></span>
{/if}
<input type="text" class="form-control" name="username" value="{$username}"
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']}{/if} {Lang::T('Phone Number')}">
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']} {Lang::T('Phone Number')}{else}{Lang::T('Username')}{/if}">
</div>
</div>
<div class="form-group">
@ -83,7 +84,7 @@
</div>
<div class="form-group">
<label>{Lang::T('Email')}</label>
<input type="text" required class="form-control" placeholder="xxxxxx@xxx.xx"
<input type="text" class="form-control" placeholder="xxxxxx@xxx.xx"
id="email" value="{$email}" name="email">
</div>
<div class="form-group">
@ -111,8 +112,7 @@
</div>
<div class="btn-group btn-group-justified mb15">
<div class="btn-group">
<button class="btn btn-primary"
type="submit">{Lang::T('Register')}</button>
<button class="btn btn-primary" type="submit">{Lang::T('Register')}</button>
</div>
<div class="btn-group">
<a href="{$_url}register" class="btn btn-success">{Lang::T('Cancel')}</a>

View File

@ -25,22 +25,22 @@
<hr>
</div>
{if isset($notify)}
<script>
// Display SweetAlert toast notification
Swal.fire({
icon: '{if $notify_t == "s"}success{else}warning{/if}',
title: '{$notify}',
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 5000,
timerProgressBar: true,
didOpen: (toast) => {
toast.addEventListener('mouseenter', Swal.stopTimer)
toast.addEventListener('mouseleave', Swal.resumeTimer)
}
});
</script>
<script>
// Display SweetAlert toast notification
Swal.fire({
icon: '{if $notify_t == "s"}success{else}warning{/if}',
title: '{$notify}',
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 5000,
timerProgressBar: true,
didOpen: (toast) => {
toast.addEventListener('mouseenter', Swal.stopTimer)
toast.addEventListener('mouseleave', Swal.resumeTimer)
}
});
</script>
{/if}
<div class="row">
<div class="col-md-2">
@ -59,16 +59,17 @@
<div class="panel-heading">1. {Lang::T('Register as Member')}</div>
<div class="panel-body">
<div class="form-group">
<label>{Lang::T('Phone Number')}</label>
<label>{if $_c['country_code_phone']!= ''}{Lang::T('Phone Number')}{else}{Lang::T('Username')}{/if}</label>
<div class="input-group">
{if $_c['country_code_phone']!= ''}
<span class="input-group-addon" id="basic-addon1">+</span>
{else}
<span class="input-group-addon" id="basic-addon1"><i
class="glyphicon glyphicon-phone-alt"></i></span>
{else}
<span class="input-group-addon" id="basic-addon1"><i
class="glyphicon glyphicon-user"></i></span>
{/if}
<input type="text" class="form-control" name="username"
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']}{/if} {Lang::T('Phone Number')}">
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']} {Lang::T('Phone Number')}{else}{Lang::T('Username')}{/if}">
</div>
</div>
<div class="btn-group btn-group-justified mb15">
@ -76,8 +77,7 @@
<a href="{$_url}login" class="btn btn-warning">{Lang::T('Cancel')}</a>
</div>
<div class="btn-group">
<button class="btn btn-success"
type="submit">{Lang::T('Request OTP')}</button>
<button class="btn btn-success" type="submit">{Lang::T('Request OTP')}</button>
</div>
</div>
<br>

View File

@ -26,22 +26,22 @@
<hr>
</div>
{if isset($notify)}
<script>
// Display SweetAlert toast notification
Swal.fire({
icon: '{if $notify_t == "s"}success{else}warning{/if}',
title: '{$notify}',
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 5000,
timerProgressBar: true,
didOpen: (toast) => {
toast.addEventListener('mouseenter', Swal.stopTimer)
toast.addEventListener('mouseleave', Swal.resumeTimer)
}
});
</script>
<script>
// Display SweetAlert toast notification
Swal.fire({
icon: '{if $notify_t == "s"}success{else}warning{/if}',
title: '{$notify}',
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 5000,
timerProgressBar: true,
didOpen: (toast) => {
toast.addEventListener('mouseenter', Swal.stopTimer)
toast.addEventListener('mouseleave', Swal.resumeTimer)
}
});
</script>
{/if}
<div class="row">
<div class="col-md-4">
@ -59,11 +59,17 @@
<div class="panel-body">
<div class="form-container">
<div class="md-input-container">
<label>{Lang::T('Phone Number')}</label>
<label>{if $_c['country_code_phone']!= ''}{Lang::T('Phone Number')}{else}{Lang::T('Username')}{/if}</label>
<div class="input-group">
<span class="input-group-addon" id="basic-addon1">+</span>
{if $_c['country_code_phone']!= ''}
<span class="input-group-addon" id="basic-addon1"><i
class="glyphicon glyphicon-phone-alt"></i></span>
{else}
<span class="input-group-addon" id="basic-addon1"><i
class="glyphicon glyphicon-user"></i></span>
{/if}
<input type="text" class="form-control" name="username"
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']}{/if} {Lang::T('Phone Number')}">
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']} {Lang::T('Phone Number')}{else}{Lang::T('Username')}{/if}">
</div>
</div>
<div class="md-input-container md-float-label">
@ -73,8 +79,8 @@
</div>
<div class="md-input-container md-float-label">
<label>{Lang::T('Email')}</label>
<input type="text" required class="form-control" id="email"
placeholder="xxxxxxx@xxxx.xx" value="{$email}" name="email">
<input type="text" class="form-control" id="email" placeholder="xxxxxxx@xxxx.xx"
value="{$email}" name="email">
</div>
<div class="md-input-container md-float-label">
<label>{Lang::T('Address')}</label>
@ -105,8 +111,7 @@
<a href="{$_url}login" class="btn btn-warning">{Lang::T('Cancel')}</a>
</div>
<div class="btn-group">
<button class="btn btn-success"
type="submit">{Lang::T('Register')}</button>
<button class="btn btn-success" type="submit">{Lang::T('Register')}</button>
</div>
</div>
<br>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -86,6 +86,10 @@
}
return null;
}
$(function() {
$('[data-toggle="tooltip"]').tooltip()
})
</script>
{/literal}

View File

@ -88,7 +88,7 @@
}
</style>
{if isset($xheader)}
{$xheader}
{$xheader}
{/if}
</head>
@ -158,62 +158,71 @@
</li>
{$_MENU_AFTER_DASHBOARD}
{if !in_array($_admin['user_type'],['Report'])}
<li {if $_system_menu eq 'customers' }class="active" {/if}>
<a href="{$_url}customers">
<i class="fa fa-users"></i>
<span>{Lang::T('Customer')}</span>
</a>
</li>
{$_MENU_AFTER_CUSTOMERS}
<li class="{if $_system_menu eq 'plan'}active{/if} treeview">
<a href="#">
<i class="fa fa-ticket"></i> <span>{Lang::T('Services')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[1] eq 'list' }class="active" {/if}><a
href="{$_url}plan/list">{Lang::T('Active Users')}</a></li>
{if $_c['disable_voucher'] != 'yes'}
<li {if $_routes[1] eq 'voucher' }class="active" {/if}><a
href="{$_url}plan/voucher">{Lang::T('Vouchers')}</a></li>
<li {if $_routes[1] eq 'refill' }class="active" {/if}><a
href="{$_url}plan/refill">{Lang::T('Refill Customer')}</a></li>
{/if}
<li {if $_routes[1] eq 'recharge' }class="active" {/if}><a
href="{$_url}plan/recharge">{Lang::T('Recharge Customer')}</a></li>
{if $_c['enable_balance'] == 'yes'}
<li {if $_routes[1] eq 'deposit' }class="active" {/if}><a
href="{$_url}plan/deposit">{Lang::T('Refill Balance')}</a></li>
{/if}
{$_MENU_SERVICES}
</ul>
</li>
<li class="{if in_array($_system_menu, ['customers', 'map'])}active{/if} treeview">
<a href="#">
<i class="fa fa-users"></i> <span>{Lang::T('Customer')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_system_menu eq 'customers' }class="active" {/if}><a
href="{$_url}customers">{Lang::T('Lists')}</a></li>
<li {if $_system_menu eq 'map' }class="active" {/if}><a
href="{$_url}map/customer">{Lang::T('Location')}</a></li>
{$_MENU_CUSTOMERS}
</ul>
</li>
{$_MENU_AFTER_CUSTOMERS}
<li class="{if $_system_menu eq 'plan'}active{/if} treeview">
<a href="#">
<i class="fa fa-ticket"></i> <span>{Lang::T('Services')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[1] eq 'list' }class="active" {/if}><a
href="{$_url}plan/list">{Lang::T('Active Users')}</a></li>
{if $_c['disable_voucher'] != 'yes'}
<li {if $_routes[1] eq 'voucher' }class="active" {/if}><a
href="{$_url}plan/voucher">{Lang::T('Vouchers')}</a></li>
<li {if $_routes[1] eq 'refill' }class="active" {/if}><a
href="{$_url}plan/refill">{Lang::T('Refill Customer')}</a></li>
{/if}
<li {if $_routes[1] eq 'recharge' }class="active" {/if}><a
href="{$_url}plan/recharge">{Lang::T('Recharge Customer')}</a></li>
{if $_c['enable_balance'] == 'yes'}
<li {if $_routes[1] eq 'deposit' }class="active" {/if}><a
href="{$_url}plan/deposit">{Lang::T('Refill Balance')}</a></li>
{/if}
{$_MENU_SERVICES}
</ul>
</li>
{/if}
{$_MENU_AFTER_SERVICES}
{if in_array($_admin['user_type'],['SuperAdmin','Admin'])}
<li class="{if $_system_menu eq 'services'}active{/if} treeview">
<a href="#">
<i class="ion ion-cube"></i> <span>{Lang::T('Plans')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[1] eq 'hotspot' }class="active" {/if}><a
href="{$_url}services/hotspot">{Lang::T('Hotspot')}</a></li>
<li {if $_routes[1] eq 'pppoe' }class="active" {/if}><a
href="{$_url}services/pppoe">{Lang::T('PPPOE')}</a></li>
<li {if $_routes[1] eq 'list' }class="active" {/if}><a
href="{$_url}bandwidth/list">{Lang::T('Bandwidth')}</a></li>
{if $_c['enable_balance'] == 'yes'}
<li {if $_routes[1] eq 'balance' }class="active" {/if}><a
href="{$_url}services/balance">{Lang::T('Balance')}</a></li>
{/if}
{$_MENU_PLANS}
</ul>
</li>
<li class="{if $_system_menu eq 'services'}active{/if} treeview">
<a href="#">
<i class="ion ion-cube"></i> <span>{Lang::T('Internet Plan')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[1] eq 'hotspot' }class="active" {/if}><a
href="{$_url}services/hotspot">Hotspot</a></li>
<li {if $_routes[1] eq 'pppoe' }class="active" {/if}><a
href="{$_url}services/pppoe">PPPOE</a></li>
<li {if $_routes[1] eq 'list' }class="active" {/if}><a
href="{$_url}bandwidth/list">{Lang::T('Bandwidth')}</a></li>
{if $_c['enable_balance'] == 'yes'}
<li {if $_routes[1] eq 'balance' }class="active" {/if}><a
href="{$_url}services/balance">{Lang::T('Customer Balance')}</a></li>
{/if}
{$_MENU_PLANS}
</ul>
</li>
{/if}
{$_MENU_AFTER_PLANS}
<li class="{if $_system_menu eq 'reports'}active{/if} treeview">
@ -243,72 +252,72 @@
</a>
<ul class="treeview-menu">
<li {if $_routes[1] eq 'send' }class="active" {/if}><a
href="{$_url}message/send">{Lang::T('Send SMS/WA Message')}</a></li>
href="{$_url}message/send">{Lang::T('Single Customer')}</a></li>
<li {if $_routes[1] eq 'send_bulk' }class="active" {/if}><a
href="{$_url}message/send_bulk">{Lang::T('Send Bulk SMS/WA Message')}</a></li>
href="{$_url}message/send_bulk">{Lang::T('Bulk Customers')}</a></li>
{$_MENU_MESSAGE}
</ul>
</li>
{$_MENU_AFTER_MESSAGE}
{if in_array($_admin['user_type'],['SuperAdmin','Admin'])}
<li class="{if $_system_menu eq 'network'}active{/if} treeview">
<a href="#">
<i class="ion ion-network"></i> <span>{Lang::T('Network')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[0] eq 'routers' and $_routes[1] eq 'list' }class="active" {/if}><a
href="{$_url}routers/list">{Lang::T('Routers')}</a></li>
<li {if $_routes[0] eq 'pool' and $_routes[1] eq 'list' }class="active" {/if}><a
href="{$_url}pool/list">{Lang::T('IP Pool')}</a></li>
{$_MENU_NETWORK}
</ul>
</li>
{$_MENU_AFTER_NETWORKS}
{if $_c['radius_enable']}
<li class="{if $_system_menu eq 'radius'}active{/if} treeview">
<a href="#">
<i class="fa fa-database"></i> <span>{Lang::T('Radius')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[0] eq 'radius' and $_routes[1] eq 'nas-list' }class="active" {/if}><a
href="{$_url}radius/nas-list">{Lang::T('Radius NAS')}</a></li>
{$_MENU_RADIUS}
</ul>
</li>
{/if}
{$_MENU_AFTER_RADIUS}
<li class="{if $_system_menu eq 'pages'}active{/if} treeview">
<a href="#">
<i class="ion ion-document"></i> <span>{Lang::T("Static Pages")}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[1] eq 'Order_Voucher' }class="active" {/if}><a
href="{$_url}pages/Order_Voucher">{Lang::T('Order Voucher')}</a></li>
<li {if $_routes[1] eq 'Voucher' }class="active" {/if}><a
href="{$_url}pages/Voucher">{Lang::T('Voucher')} Template</a></li>
<li {if $_routes[1] eq 'Announcement' }class="active" {/if}><a
href="{$_url}pages/Announcement">{Lang::T('Announcement')}</a></li>
<li {if $_routes[1] eq 'Announcement_Customer' }class="active" {/if}><a
href="{$_url}pages/Announcement_Customer">{Lang::T('Customer Announcement')}</a>
<li class="{if $_system_menu eq 'network'}active{/if} treeview">
<a href="#">
<i class="ion ion-network"></i> <span>{Lang::T('Network')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[0] eq 'routers' and $_routes[1] eq 'list' }class="active" {/if}><a
href="{$_url}routers/list">{Lang::T('Routers')}</a></li>
<li {if $_routes[0] eq 'pool' and $_routes[1] eq 'list' }class="active" {/if}><a
href="{$_url}pool/list">{Lang::T('IP Pool')}</a></li>
{$_MENU_NETWORK}
</ul>
</li>
{$_MENU_AFTER_NETWORKS}
{if $_c['radius_enable']}
<li class="{if $_system_menu eq 'radius'}active{/if} treeview">
<a href="#">
<i class="fa fa-database"></i> <span>{Lang::T('Radius')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[0] eq 'radius' and $_routes[1] eq 'nas-list' }class="active" {/if}><a
href="{$_url}radius/nas-list">{Lang::T('Radius NAS')}</a></li>
{$_MENU_RADIUS}
</ul>
</li>
<li {if $_routes[1] eq 'Registration_Info' }class="active" {/if}><a
href="{$_url}pages/Registration_Info">{Lang::T('Registration Info')}</a></li>
<li {if $_routes[1] eq 'Privacy_Policy' }class="active" {/if}><a
href="{$_url}pages/Privacy_Policy">Privacy Policy</a></li>
<li {if $_routes[1] eq 'Terms_and_Conditions' }class="active" {/if}><a
href="{$_url}pages/Terms_and_Conditions">Terms and Conditions</a></li>
{$_MENU_PAGES}
</ul>
</li>
{/if}
{$_MENU_AFTER_RADIUS}
<li class="{if $_system_menu eq 'pages'}active{/if} treeview">
<a href="#">
<i class="ion ion-document"></i> <span>{Lang::T("Static Pages")}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[1] eq 'Order_Voucher' }class="active" {/if}><a
href="{$_url}pages/Order_Voucher">{Lang::T('Order Voucher')}</a></li>
<li {if $_routes[1] eq 'Voucher' }class="active" {/if}><a
href="{$_url}pages/Voucher">{Lang::T('Voucher')} Template</a></li>
<li {if $_routes[1] eq 'Announcement' }class="active" {/if}><a
href="{$_url}pages/Announcement">{Lang::T('Announcement')}</a></li>
<li {if $_routes[1] eq 'Announcement_Customer' }class="active" {/if}><a
href="{$_url}pages/Announcement_Customer">{Lang::T('Customer Announcement')}</a>
</li>
<li {if $_routes[1] eq 'Registration_Info' }class="active" {/if}><a
href="{$_url}pages/Registration_Info">{Lang::T('Registration Info')}</a></li>
<li {if $_routes[1] eq 'Privacy_Policy' }class="active" {/if}><a
href="{$_url}pages/Privacy_Policy">{Lang::T('Privacy Policy')}</a></li>
<li {if $_routes[1] eq 'Terms_and_Conditions' }class="active" {/if}><a
href="{$_url}pages/Terms_and_Conditions">{Lang::T('Terms and Conditions')}</a></li>
{$_MENU_PAGES}
</ul>
</li>
{/if}
{$_MENU_AFTER_PAGES}
<li
@ -321,31 +330,31 @@
</a>
<ul class="treeview-menu">
{if in_array($_admin['user_type'],['SuperAdmin','Admin'])}
<li {if $_routes[1] eq 'app' }class="active" {/if}><a
href="{$_url}settings/app">{Lang::T('General Settings')}</a></li>
<li {if $_routes[1] eq 'localisation' }class="active" {/if}><a
href="{$_url}settings/localisation">{Lang::T('Localisation')}</a></li>
<li {if $_routes[1] eq 'notifications' }class="active" {/if}><a
href="{$_url}settings/notifications">{Lang::T('User Notification')}</a></li>
<li {if $_routes[1] eq 'app' }class="active" {/if}><a
href="{$_url}settings/app">{Lang::T('General Settings')}</a></li>
<li {if $_routes[1] eq 'localisation' }class="active" {/if}><a
href="{$_url}settings/localisation">{Lang::T('Localisation')}</a></li>
<li {if $_routes[1] eq 'notifications' }class="active" {/if}><a
href="{$_url}settings/notifications">{Lang::T('User Notification')}</a></li>
{/if}
{if in_array($_admin['user_type'],['SuperAdmin','Admin','Agent'])}
<li {if $_routes[1] eq 'users' }class="active" {/if}><a
href="{$_url}settings/users">{Lang::T('Administrator Users')}</a></li>
<li {if $_routes[1] eq 'users' }class="active" {/if}><a
href="{$_url}settings/users">{Lang::T('Administrator Users')}</a></li>
{/if}
{if in_array($_admin['user_type'],['SuperAdmin','Admin'])}
<li {if $_routes[1] eq 'dbstatus' }class="active" {/if}><a
href="{$_url}settings/dbstatus">{Lang::T('Backup/Restore')}</a></li>
<li {if $_system_menu eq 'paymentgateway' }class="active" {/if}>
<a href="{$_url}paymentgateway">
<span class="text">{Lang::T('Payment Gateway')}</span>
</a>
</li>
{$_MENU_SETTINGS}
<li {if $_routes[0] eq 'pluginmanager' }class="active" {/if}>
<a href="{$_url}pluginmanager"><i class="glyphicon glyphicon-tasks"></i>
{Lang::T('Plugin Manager')} <small class="label pull-right">Free</small></a>
</li>
{* <li {if $_routes[0] eq 'codecanyon' }class="active" {/if}>
<li {if $_routes[1] eq 'dbstatus' }class="active" {/if}><a
href="{$_url}settings/dbstatus">{Lang::T('Backup/Restore')}</a></li>
<li {if $_system_menu eq 'paymentgateway' }class="active" {/if}>
<a href="{$_url}paymentgateway">
<span class="text">{Lang::T('Payment Gateway')}</span>
</a>
</li>
{$_MENU_SETTINGS}
<li {if $_routes[0] eq 'pluginmanager' }class="active" {/if}>
<a href="{$_url}pluginmanager"><i class="glyphicon glyphicon-tasks"></i>
{Lang::T('Plugin Manager')} <small class="label pull-right">Free</small></a>
</li>
{* <li {if $_routes[0] eq 'codecanyon' }class="active" {/if}>
<a href="{$_url}codecanyon"><i class="glyphicon glyphicon-shopping-cart"></i>
Codecanyon.net <small class="label pull-right">Paid</small></a>
</li> *}
@ -354,24 +363,24 @@
</li>
{$_MENU_AFTER_SETTINGS}
{if in_array($_admin['user_type'],['SuperAdmin','Admin'])}
<li class="{if $_system_menu eq 'logs' }active{/if} treeview">
<a href="#">
<i class="ion ion-clock"></i> <span>{Lang::T('Logs')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[1] eq 'list' }class="active" {/if}><a
href="{$_url}logs/phpnuxbill">PhpNuxBill</a></li>
{if $_c['radius_enable']}
<li {if $_routes[1] eq 'radius' }class="active" {/if}><a
href="{$_url}logs/radius">Radius</a>
</li>
{/if}
</ul>
{$_MENU_LOGS}
</li>
<li class="{if $_system_menu eq 'logs' }active{/if} treeview">
<a href="#">
<i class="ion ion-clock"></i> <span>{Lang::T('Logs')}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li {if $_routes[1] eq 'list' }class="active" {/if}><a
href="{$_url}logs/phpnuxbill">PhpNuxBill</a></li>
{if $_c['radius_enable']}
<li {if $_routes[1] eq 'radius' }class="active" {/if}><a
href="{$_url}logs/radius">Radius</a>
</li>
{/if}
</ul>
{$_MENU_LOGS}
</li>
{/if}
{$_MENU_AFTER_LOGS}
<li {if $_system_menu eq 'community' }class="active" {/if}>
@ -394,20 +403,20 @@
<section class="content">
{if isset($notify)}
<script>
// Display SweetAlert toast notification
Swal.fire({
icon: '{if $notify_t == "s"}success{else}error{/if}',
title: '{$notify}',
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 5000,
timerProgressBar: true,
didOpen: (toast) => {
toast.addEventListener('mouseenter', Swal.stopTimer)
toast.addEventListener('mouseleave', Swal.resumeTimer)
}
});
</script>
{/if}
<script>
// Display SweetAlert toast notification
Swal.fire({
icon: '{if $notify_t == "s"}success{else}error{/if}',
title: '{$notify}',
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 5000,
timerProgressBar: true,
didOpen: (toast) => {
toast.addEventListener('mouseenter', Swal.stopTimer)
toast.addEventListener('mouseleave', Swal.resumeTimer)
}
});
</script>
{/if}

View File

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

View File

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

View File

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

View File

@ -45,24 +45,27 @@
<div class="panel-body">
<form action="{$_url}login/post" method="post">
<div class="form-group">
<label>{Lang::T('Phone Number')}</label>
<label>{if $_c['country_code_phone']!= ''}{Lang::T('Phone Number')}{else}{Lang::T('Username')}{/if}</label>
<div class="input-group">
{if $_c['country_code_phone']!= ''}
<span class="input-group-addon" id="basic-addon1">+</span>
<span class="input-group-addon" id="basic-addon1"><i
class="glyphicon glyphicon-phone-alt"></i></span>
{else}
<span class="input-group-addon" id="basic-addon1"><i
class="glyphicon glyphicon-phone-alt"></i></span>
class="glyphicon glyphicon-user"></i></span>
{/if}
<input type="text" class="form-control" name="username"
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']}{/if} {Lang::T('Phone Number')}">
placeholder="{if $_c['country_code_phone']!= ''}{$_c['country_code_phone']} {Lang::T('Phone Number')}{else}{Lang::T('Username')}{/if}">
</div>
</div>
<div class="form-group">
<label>{Lang::T('Password')}</label>
<input type="password" class="form-control" name="password"
placeholder="{Lang::T('Password')}">
</div>
<label>{Lang::T('Password')}</label>
<div class="input-group">
<span class="input-group-addon" id="basic-addon2"><i class="glyphicon glyphicon-lock"></i></span>
<input type="password" class="form-control" name="password" placeholder="{Lang::T('Password')}">
</div>
</div>
<div class="clearfix hidden">
<div class="ui-checkbox ui-checkbox-primary right">
@ -113,4 +116,4 @@
<script src="ui/ui/scripts/vendors.js?v=1"></script>
</body>
</html>
</html>

View File

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

View File

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

View File

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

View File

@ -41,6 +41,10 @@
<label class="col-md-2 control-label">{Lang::T('Voucher Format')}</label>
<div class="col-md-6">
<select name="voucher_format" id="voucher_format" class="form-control">
<option value="numbers" {if $_c['voucher_format'] == 'numbers'}selected="selected"
{/if}>
Numbers
</option>
<option value="up" {if $_c['voucher_format'] == 'up'}selected="selected" {/if}>UPPERCASE
</option>
<option value="low" {if $_c['voucher_format'] == 'low'}selected="selected" {/if}>
@ -56,7 +60,8 @@
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Voucher Prefix')}</label>
<div class="col-md-6">
<input type="text" class="form-control" name="prefix" placeholder="NUX-" value="{$_c['voucher_prefix']}">
<input type="text" class="form-control" name="prefix" placeholder="NUX-"
value="{$_c['voucher_prefix']}">
</div>
<p class="help-block col-md-4">NUX-VoUCHeRCOdE</p>
</div>
@ -68,8 +73,7 @@
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<button class="btn btn-success"
type="submit">{Lang::T('Generate')}</button>
<button class="btn btn-success" type="submit">{Lang::T('Generate')}</button>
</div>
</div>
</form>
@ -79,4 +83,4 @@
</div>
</div>
{include file="sections/footer.tpl"}
{include file="sections/footer.tpl"}

View File

@ -29,15 +29,18 @@
</div>
</form>
</div>
<div class="col-md-4">
<div class="btn-group btn-group-justified" role="group">
<div class="btn-group" role="group">
<a href="{$_url}plan/add-voucher" class="btn btn-primary btn-block"><i
class="ion ion-android-add"> </i> {Lang::T('Add Vouchers')}</a>
class="ion ion-android-add"></i> {Lang::T('Add Vouchers')}</a>
</div>
</div>
<div class="btn-group btn-group-justified" role="group">
<div class="btn-group" role="group">
<a href="{$_url}plan/print-voucher" target="print_voucher" class="btn btn-info"><i
class="ion ion-android-print"> </i> Print</a>
<a href="{$_url}plan/print-voucher" target="print_voucher"
class="btn btn-info btn-block"><i class="ion ion-android-print"></i> Print</a>
</div>
</div>
</div>&nbsp;
@ -82,8 +85,7 @@
</td>
<td>
{if $ds['status'] neq '1'}
<a href="{$_url}plan/voucher-view/{$ds['id']}" id="{$ds['id']}"
style="margin: 0px;"
<a href="{$_url}plan/voucher-view/{$ds['id']}" id="{$ds['id']}" style="margin: 0px;"
class="btn btn-success btn-xs">&nbsp;&nbsp;{Lang::T('View')}&nbsp;&nbsp;</a>
{/if}
{if in_array($_admin['user_type'],['SuperAdmin','Admin'])}
@ -98,15 +100,7 @@
</tbody>
</table>
</div>
<ul class="pagination pagination-sm">
{if $page>0}
<li><a href="{$_url}plan/voucher&p={$page-1}&code={$_code}">{Lang::T('Prev')}</a></li>
{/if}
{if $d}
<li><a href="{$_url}plan/voucher&p={$page+1}&code={$_code}">{Lang::T('Next')}</a></li>
{/if}
</ul>
{include file="pagination.tpl"}
</div>
</div>
</div>

View File

@ -141,12 +141,12 @@ function r2($to, $ntype = 'e', $msg = '')
{
if ($msg == '') {
header("location: $to");
exit;
die();
}
$_SESSION['ntype'] = $ntype;
$_SESSION['notify'] = $msg;
header("location: $to");
exit;
die();
}
function copyFolder($from, $to, $exclude = [])

View File

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