Compare commits

...

303 Commits

Author SHA1 Message Date
26d9e8bd03 fix restore with ID 2024-05-21 13:50:10 +07:00
7f3096ce85 stiill have variable price_with_tax, back to price 2024-05-21 11:53:29 +07:00
94e6f7fe6c change join to left_outer_join 2024-05-21 11:45:23 +07:00
fc74589a2a update CHANGLELOG.md 2024-05-21 11:01:58 +07:00
e582816982 100 update list 2024-05-21 10:58:14 +07:00
ab7725b0fb Rollback installation 2024-05-21 10:56:11 +07:00
35a327001b can change url download 2024-05-21 10:19:19 +07:00
6d8e64a1da Merge commit '951d729fcc12dcb49e391e7b6433e98556c0e089' into Development 2024-05-21 10:13:05 +07:00
e178acc8e9 add changelog 2024-05-21 10:01:36 +07:00
848c36106a fix text 2024-05-21 10:01:36 +07:00
20fdb688ad fix init radius, double check password 2024-05-21 10:01:36 +07:00
533d46bbf5 New Feature: Maintenance Mode
Maintenance Mode

when enabled user/customer will not be able to login, a maintenance page will be displayed instead.

but all admin users can login
2024-05-21 10:01:36 +07:00
0bad687f7a Update Radius.php
Fix Radius Data Limit
2024-05-21 10:01:36 +07:00
4170ab6505 Update updates.json 2024-05-21 10:01:36 +07:00
bd0f7e0ad6 patch update 2024-05-21 10:01:36 +07:00
8fb930cddf update:
Added Additional Information

City
District
State
Zip
2024-05-21 10:01:36 +07:00
066f333a85 Update Readme 2024-05-21 10:00:51 +07:00
12726bdaa0 Export CSV by Filter data 2024-05-21 10:00:51 +07:00
1ab19bfe64 Add Filter by status in Customer List 2024-05-21 10:00:51 +07:00
951d729fcc Merge pull request #199 from Focuslinkstech/master
Update:
2024-05-21 09:02:17 +07:00
a5a6957581 New Feature: Maintenance Mode
Maintenance Mode

when enabled user/customer will not be able to login, a maintenance page will be displayed instead.

but all admin users can login
2024-05-21 00:22:40 +01:00
1f27a98471 Update Radius.php
Fix Radius Data Limit
2024-05-20 15:36:37 +01:00
11cafb9b84 Update updates.json 2024-05-20 13:46:17 +01:00
836cc4cddf Merge branch 'master' of https://github.com/Focuslinkstech/phpnuxbill 2024-05-20 13:39:18 +01:00
459e153ed7 patch update 2024-05-20 13:38:43 +01:00
7710696886 Merge branch 'master' into master 2024-05-20 13:25:49 +01:00
f29e692e81 update:
Added Additional Information

City
District
State
Zip
2024-05-20 13:09:38 +01:00
d2c839a11e Update Readme 2024-05-20 09:52:33 +07:00
49ea49ec4a Export CSV by Filter data 2024-05-20 09:33:37 +07:00
a4569901a9 Add Filter by status in Customer List 2024-05-20 09:12:13 +07:00
5af514244c Merge pull request #198 from Focuslinkstech/Development
Tax System
2024-05-19 18:23:44 +07:00
8284b360a0 add red line for Customer status != Active 2024-05-18 23:16:03 +07:00
41161ebc7c Add new status when edit customers 2024-05-18 23:14:03 +07:00
1bada918b9 add status Inactive Limited Suspended to Customer 2024-05-18 23:07:02 +07:00
37a245c94a add Function getEnum in ORM 2024-05-18 23:06:11 +07:00
749ec8509f update
if it the same internet plan, expiry date will extend, now optional and can be enabled/disable in general settings [ Miscellaneous Tab]
2024-05-17 16:24:48 +01:00
ea51fa24d0 update
fixed tax logic
2024-05-17 14:47:12 +01:00
55d344febe Merge branch 'hotspotbilling:Development' into Development 2024-05-17 14:39:03 +01:00
51c4909308 Fix Logic Banned user 2024-05-17 19:05:16 +07:00
f7a912a9af Update app-settings.tpl 2024-05-17 11:05:17 +01:00
d00d04994d Merge branch 'Development' of https://github.com/Focuslinkstech/phpnuxbill into Development 2024-05-17 10:59:51 +01:00
fded62b39d Update
Add plan details to gateway
2024-05-17 10:59:41 +01:00
3769a75769 Merge branch 'hotspotbilling:Development' into Development 2024-05-17 10:57:17 +01:00
b5a9190ae7 order by status 2024-05-17 16:45:41 +07:00
6b8501313d Revert "Revert "Update Package.php""
This reverts commit 22c027aaba.
2024-05-17 09:57:14 +01:00
22c027aaba Revert "Update Package.php"
This reverts commit cd34a68cf3.
2024-05-17 09:53:35 +01:00
5c95da3a45 Merge branch 'Development' of https://github.com/Focuslinkstech/phpnuxbill into Development 2024-05-17 09:52:47 +01:00
67a4d7f534 Merge branch 'Development' of https://github.com/Focuslinkstech/phpnuxbill into Development 2024-05-17 09:52:20 +01:00
d94c62d6fc Show order by 2024-05-17 10:59:40 +07:00
2198536123 Edit Customer status 2024-05-17 10:28:47 +07:00
8594fc3876 disable customer cannot renew 2024-05-17 09:25:26 +07:00
4e1820dea2 Disable Customer cannot order plan 2024-05-17 09:25:15 +07:00
f81feee9c0 banned customer will automatically logout 2024-05-17 09:20:53 +07:00
9521e96495 banned customers cannot login 2024-05-17 09:19:04 +07:00
d84cf96d01 Not Active Customer cannot recharge 2024-05-17 09:17:38 +07:00
04fda479b7 add Customer status Active Banned Disabled 2024-05-17 09:16:57 +07:00
a9761dda28 Fix lang on remaining 2024-05-16 16:53:20 +07:00
0511459424 fix tbody position 2024-05-16 16:49:35 +07:00
aeb4d2e1ed Confirm can change Using 2024-05-16 16:40:59 +07:00
41c0190d19 Confirm Recharge can change Using 2024-05-16 16:39:45 +07:00
fa50539faa disable FOREIGN_KEY_CHECKS when restore 2024-05-14 14:25:34 +07:00
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
cd34a68cf3 Update Package.php
if it same internet plan but has expired, it will not extend expiry date
2024-05-07 09:56:53 +01: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
130451e1ae Fix notification 2024-03-18 11:48:22 +07:00
d36f39af8f Merge pull request #130 from Focuslinkstech/Development
send single and Bulk SMS, WhatsApp or Both WA/SMS message to customers
2024-03-18 11:05:03 +07:00
518917aac6 Add Message Feature
you can now send single and Bulk SMS, WhatsApp or Both WA/SMS message to customers based on their groups, more groups will be added later
2024-03-18 01:35:48 +01:00
dbc3a2623c Update customers.tpl
Functionality to filter table rows based on admin input
2024-03-17 15:56:42 +01:00
d31edde9d6 prepaid to plan file 2024-03-16 20:41:24 +07:00
32943b40be Fix Bills Zero 2024-03-16 20:41:24 +07:00
23790d3258 Merge pull request #129 from gerandonk/Development
Fix loop disconnect to all Nas
2024-03-16 20:24:25 +07:00
ffa55cdee5 Fix loop disconnect to all Nas
Fix loop disconnect to all Nas but still detecting Hotspot Multylogin from other Nas
2024-03-16 19:50:45 +07:00
6f5d49cd2f Show Paid 2024-03-15 10:56:08 +07:00
850581d328 Fix instalment finished 2024-03-15 10:48:17 +07:00
1d0d3f13ab 2024.3.14 2024-03-15 10:43:49 +07:00
c82b6b6acf Change Attribute to Bill Only 2024-03-15 10:38:05 +07:00
532fbf7337 Active plan on user page 2024-03-15 09:46:01 +07:00
c4afd6da7f Additional Cost at Cron 2024-03-15 09:29:15 +07:00
a812e3a3e0 Merge pull request #128 from gerandonk/Development
postpaid always zero for first time recharge and invoice atribute for…
2024-03-15 09:24:02 +07:00
a15510e62a postpaid always zero for first time recharge and invoice atribute for next month
for postpaid customer invoice reminder and order get from invoice attribute
2024-03-15 04:07:30 +07:00
78d1634470 Send plan to friend will pay for Additional Cost 2024-03-14 14:55:49 +07:00
cc8d810d45 Additional Cost Customer side 2024-03-14 14:42:20 +07:00
117 changed files with 15324 additions and 4948 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,132 @@
# CHANGELOG
## 2024.5.21
- Add Maintenance Mode by @freeispradius
- Add Tax System by @freeispradius
- Add Export Customer List to CSV with Filter
- Fix some Radius Variable by @freeispradius
- Add Rollback update
## 2024.5.17
- Status Customer: Active/Banned/Disabled
- Add search with order in Customer list
## 2024.5.16
- Confirm can change Using
## 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
- Fix Notification with Bills
## 2024.3.16
- Fix Zero Charging
- Fix Disconnect Customer from Radius without loop by @Gerandonk
## 2024.3.15
- Fix Customer View to list active Plan
- Additional Bill using Customer Attributes
## 2024.3.14
- Add Note to Invoices

View File

@ -7,7 +7,7 @@
## Feature
- Voucher Generator and Print
- FreeRadius
- [Freeradius](https://github.com/hotspotbilling/phpnuxbill/wiki/FreeRadius)
- Self registration
- User Balance
- Auto Renewal Package using Balance
@ -51,14 +51,11 @@ The problem with windows is hard to set cronjob, better Linux
## Changelog
[CHANGELOG.md](CHANGELOG.md)
## Installation
[Installation instructions](https://github.com/hotspotbilling/phpnuxbill/wiki)
## Docker Version
[Docker Repository](https://github.com/animegasan/phpnuxbill)
## Freeradius
Support [Freeradius with Database](https://github.com/hotspotbilling/phpnuxbill/wiki/FreeRadius)
@ -70,21 +67,24 @@ Support [Freeradius with Database](https://github.com/hotspotbilling/phpnuxbill/
## Technical Support
Start from Rp 500.000 or $50
This Software is Free and Open Source, Without any Warranty.
If you chat me for any technical support, you need to pay, except for Donors, ask anything for free in the [discussion](/hotspotbilling/phpnuxbill/discussions) page
Even if the software is free, but Technical Support is not,
Technical Support Start from Rp 500.000 or $50
[Telegram](https://t.me/ibnux)
If you chat me for any technical support,
you need to pay,
[Website](https://ibnux.net/layanan)
ask anything for free in the [discussion](/hotspotbilling/phpnuxbill/discussions) page or [Telegram Group](https://t.me/phpnuxbill)
Contact me at [Telegram](https://t.me/ibnux)
## License
GNU General Public License version 2 or later
see LICENSE file
see [LICENSE](LICENSE) file
## [CHANGELOG](CHANGELOG.md)
## Donate to ibnux

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)
{
@ -37,7 +39,6 @@ function _autoloader($class)
}
spl_autoload_register('_autoloader');
if (!file_exists($root_path . 'config.php')) {
$root_path .= '..' . DIRECTORY_SEPARATOR;
if (!file_exists($root_path . 'config.php')) {
@ -72,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")) {
@ -106,6 +110,9 @@ if (empty($http_proxy) && !empty($config['http_proxy'])) {
date_default_timezone_set($config['timezone']);
if ((!empty($radius_user) && $config['radius_enable']) || _post('radius_enable')) {
if(!empty($radius_password)){
$radius_pass = $radius_password;
}
ORM::configure("mysql:host=$radius_host;dbname=$radius_name", null, 'radius');
ORM::configure('username', $radius_user, 'radius');
ORM::configure('password', $radius_pass, 'radius');
@ -196,7 +203,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();
}
@ -207,9 +225,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)
{
@ -228,6 +279,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;
@ -240,7 +298,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") {
@ -261,3 +325,16 @@ function _alert($text, $type = 'success', $url = "home", $time = 3)
if (!isset($api_secret)) {
$api_secret = $db_password;
}
function displayMaintenanceMessage(): void
{
global $config, $ui;
$date = $config['maintenance_date'];
if ($date){
$ui->assign('date', $date);
}
http_response_code(503);
$ui->assign('companyName', $config['CompanyName']);
$ui->display('maintenance.tpl');
die();
}

View File

@ -21,13 +21,19 @@ 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,
`city` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
`district` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
`state` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
`zip` varchar(255) 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 +85,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 +324,7 @@ 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`;
ALTER TABLE `tbl_customers` ADD `status` ENUM('Active','Banned','Disabled') NOT NULL DEFAULT 'Active' AFTER `auto_renewal`;
ALTER TABLE `tbl_customers` CHANGE `status` `status` ENUM('Active','Banned','Disabled','Inactive','Limited','Suspended') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'Active';

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];
@ -125,7 +127,7 @@ class Lang
if (!$full)
$string = array_slice($string, 0, 1);
return $string ? implode(', ', $string) . ' ago' : 'just now';
return $string ? implode(', ', $string) .' '. Lang::T('ago') : Lang::T('just now');
}
public static function nl2br($text)

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";
@ -116,6 +185,9 @@ class Message
$textInvoice = str_replace('[[phone]]', $config['phone'], $textInvoice);
$textInvoice = str_replace('[[invoice]]', $trx['invoice'], $textInvoice);
$textInvoice = str_replace('[[date]]', Lang::dateAndTimeFormat($trx['recharged_on'], $trx['recharged_time']), $textInvoice);
if (!empty($trx['note'])) {
$textInvoice = str_replace('[[note]]', $trx['note'], $textInvoice);
}
$gc = explode("-", $trx['method']);
$textInvoice = str_replace('[[payment_gateway]]', trim($gc[0]), $textInvoice);
$textInvoice = str_replace('[[payment_channel]]', trim($gc[1]), $textInvoice);

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;
@ -32,29 +34,27 @@ class Package
$c = ORM::for_table('tbl_customers')->where('id', $id_customer)->find_one();
$p = ORM::for_table('tbl_plans')->where('id', $plan_id)->find_one();
// Additional cost
$add_cost = 0;
$add_rem = User::getAttribute("Additional Remaining", $id_customer);
// if empty then it doesnt have cycle, if zero then it finish
if ($add_rem != 0) {
$add_cost = User::getAttribute("Additional Cost", $id_customer);
if (empty($add_cost)) {
$add_cost = 0;
}
}
if ($add_cost > 0 && $router_name != 'balance') {
$bills = User::getAttributes("Bill", $id_customer);
foreach ($bills as $k => $v) {
$note .= $k . " : " . Lang::moneyFormat($v) . "\n";
}
if ($c['status'] != 'Active') {
_alert(Lang::T('This account status') . ' : ' . Lang::T($c['status']), 'danger', "");
}
$add_cost = 0;
$bills = [];
// Zero cost recharge
if (isset($zero) && $zero == 1) {
$p['price'] = 0;
$add_cost = 0;
} else {
// Additional cost
list($bills, $add_cost) = User::getBills($id_customer);
if ($add_cost > 0 && $router_name != 'balance') {
foreach ($bills as $k => $v) {
$note .= $k . " : " . Lang::moneyFormat($v) . "\n";
}
$note .= $p['name_plan'] . " : " . Lang::moneyFormat($p['price']) . "\n";
}
}
if (!$p['enabled']) {
if (!isset($admin) || !isset($admin['id']) || empty($admin['id'])) {
r2(U . 'home', 'e', Lang::T('Plan Not found'));
@ -82,9 +82,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'];
@ -155,8 +154,10 @@ 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'])
->join('tbl_plans', array('tbl_plans.id', '=', 'tbl_user_recharges.plan_id'))
# 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'])
->left_outer_join('tbl_plans', array('tbl_plans.id', '=', 'tbl_user_recharges.plan_id'))
->find_one();
run_hook("recharge_user");
@ -171,14 +172,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];
@ -188,38 +191,44 @@ class Package
$date_exp = $datetime[0];
$time = $datetime[1];
}
$isChangePlan = false;
if ($p['type'] == 'Hotspot') {
if ($b) {
if ($b['namebp'] == $p['name_plan'] && $b['status'] == 'on') {
// if it same internet plan, expired will extend
if ($p['validity_unit'] == 'Months') {
$date_exp = date("Y-m-d", strtotime($b['expiration'] . ' +' . $p['validity'] . ' months'));
$time = $b['time'];
} else if ($p['validity_unit'] == 'Period') {
$date_exp = date("Y-m-$day_exp", strtotime($b['expiration'] . ' +' . $p['validity'] . ' months'));
$time = date("23:59:00");
} else if ($p['validity_unit'] == 'Days') {
$date_exp = date("Y-m-d", strtotime($b['expiration'] . ' +' . $p['validity'] . ' days'));
$time = $b['time'];
} else if ($p['validity_unit'] == 'Hrs') {
$datetime = explode(' ', date("Y-m-d H:i:s", strtotime($b['expiration'] . ' ' . $b['time'] . ' +' . $p['validity'] . ' hours')));
$date_exp = $datetime[0];
$time = $datetime[1];
} else if ($p['validity_unit'] == 'Mins') {
$datetime = explode(' ', date("Y-m-d H:i:s", strtotime($b['expiration'] . ' ' . $b['time'] . ' +' . $p['validity'] . ' minutes')));
$date_exp = $datetime[0];
$time = $datetime[1];
if ($plan_id != $b['plan_id']) {
$isChangePlan = true;
}
if ($config['extend_expiry'] === 'yes') {
if ($b['namebp'] == $p['name_plan'] && $b['status'] == 'on') {
// if it same internet plan, expired will extend
if ($p['validity_unit'] == 'Months') {
$date_exp = date("Y-m-d", strtotime($b['expiration'] . ' +' . $p['validity'] . ' months'));
$time = $b['time'];
} else if ($p['validity_unit'] == 'Period') {
$date_exp = date("Y-m-$day_exp", strtotime($b['expiration'] . ' +' . $p['validity'] . ' months'));
$time = date("23:59:00");
} else if ($p['validity_unit'] == 'Days') {
$date_exp = date("Y-m-d", strtotime($b['expiration'] . ' +' . $p['validity'] . ' days'));
$time = $b['time'];
} else if ($p['validity_unit'] == 'Hrs') {
$datetime = explode(' ', date("Y-m-d H:i:s", strtotime($b['expiration'] . ' ' . $b['time'] . ' +' . $p['validity'] . ' hours')));
$date_exp = $datetime[0];
$time = $datetime[1];
} else if ($p['validity_unit'] == 'Mins') {
$datetime = explode(' ', date("Y-m-d H:i:s", strtotime($b['expiration'] . ' ' . $b['time'] . ' +' . $p['validity'] . ' minutes')));
$date_exp = $datetime[0];
$time = $datetime[1];
}
}
}
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;
@ -243,10 +252,20 @@ 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'];
$t->price = $p['price'] + $add_cost;
if ($p['validity_unit'] == 'Period') {
// Postpaid price from field
$add_inv = User::getAttribute("Invoice", $id_customer);
if (empty($add_inv) or $add_inv == 0) {
$t->price = $p['price'] + $add_cost;
} else {
$t->price = $add_inv + $add_cost;
}
} else {
$t->price = $p['price'] + $add_cost;
}
$t->recharged_on = $date_only;
$t->recharged_time = $time_only;
$t->expiration = $date_exp;
@ -263,7 +282,7 @@ class Package
$t->save();
if ($p['validity_unit'] == 'Period') {
// insert to fields
// insert price to fields for invoice next month
$fl = ORM::for_table('tbl_customers_fields')->where('field_name', 'Invoice')->where('customer_id', $c['id'])->find_one();
if (!$fl) {
$fl = ORM::for_table('tbl_customers_fields')->create();
@ -283,7 +302,8 @@ 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']) {
Radius::customerAddPlan($c, $p, "$date_exp $time");
@ -316,21 +336,12 @@ 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' && $p['price'] != 0) {
// Calculating Price
$sd = new DateTime("$date_only");
$ed = new DateTime("$date_exp");
$td = $ed->diff($sd);
$fd = $td->format("%a");
$gi = ($p['price'] / 30) * $fd;
if ($gi > $p['price']) {
$t->price = $p['price'] + $add_cost;
} else {
$t->price = $gi + $add_cost;
}
if ($p['validity_unit'] == 'Period') {
// Postpaid price always zero for first time
$t->price = 0 + $add_cost;
} else {
$t->price = $p['price'] + $add_cost;
}
@ -350,12 +361,18 @@ class Package
$t->save();
if ($p['validity_unit'] == 'Period' && $p['price'] != 0) {
// insert to fields
// insert price to fields for invoice next month
$fl = ORM::for_table('tbl_customers_fields')->where('field_name', 'Invoice')->where('customer_id', $c['id'])->find_one();
if (!$fl) {
$fl = ORM::for_table('tbl_customers_fields')->create();
$fl->customer_id = $c['id'];
$fl->field_name = 'Invoice';
// Calculating Price
$sd = new DateTime("$date_only");
$ed = new DateTime("$date_exp");
$td = $ed->diff($sd);
$fd = $td->format("%a");
$gi = ($p['price'] / (30 * $p['validity'])) * $fd;
if ($gi > $p['price']) {
$fl->field_value = $p['price'];
} else {
@ -373,40 +390,48 @@ 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 ($b['namebp'] == $p['name_plan'] && $b['status'] == 'on') {
// if it same internet plan, expired will extend
if ($p['validity_unit'] == 'Months') {
$date_exp = date("Y-m-d", strtotime($b['expiration'] . ' +' . $p['validity'] . ' months'));
$time = $b['time'];
} else if ($p['validity_unit'] == 'Period') {
$date_exp = date("Y-m-$day_exp", strtotime($b['expiration'] . ' +' . $p['validity'] . ' months'));
$time = date("23:59:00");
} else if ($p['validity_unit'] == 'Days') {
$date_exp = date("Y-m-d", strtotime($b['expiration'] . ' +' . $p['validity'] . ' days'));
$time = $b['time'];
} else if ($p['validity_unit'] == 'Hrs') {
$datetime = explode(' ', date("Y-m-d H:i:s", strtotime($b['expiration'] . ' ' . $b['time'] . ' +' . $p['validity'] . ' hours')));
$date_exp = $datetime[0];
$time = $datetime[1];
} else if ($p['validity_unit'] == 'Mins') {
$datetime = explode(' ', date("Y-m-d H:i:s", strtotime($b['expiration'] . ' ' . $b['time'] . ' +' . $p['validity'] . ' minutes')));
$date_exp = $datetime[0];
$time = $datetime[1];
if ($plan_id != $b['plan_id']) {
$isChangePlan = true;
}
if ($config['extend_expiry'] === 'yes') {
if ($b['namebp'] == $p['name_plan'] && $b['status'] == 'on') {
// if it same internet plan, expired will extend
if ($p['validity_unit'] == 'Months') {
$date_exp = date("Y-m-d", strtotime($b['expiration'] . ' +' . $p['validity'] . ' months'));
$time = $b['time'];
} else if ($p['validity_unit'] == 'Period') {
$date_exp = date("Y-m-$day_exp", strtotime($b['expiration'] . ' +' . $p['validity'] . ' months'));
$time = date("23:59:00");
} else if ($p['validity_unit'] == 'Days') {
$date_exp = date("Y-m-d", strtotime($b['expiration'] . ' +' . $p['validity'] . ' days'));
$time = $b['time'];
} else if ($p['validity_unit'] == 'Hrs') {
$datetime = explode(' ', date("Y-m-d H:i:s", strtotime($b['expiration'] . ' ' . $b['time'] . ' +' . $p['validity'] . ' hours')));
$date_exp = $datetime[0];
$time = $datetime[1];
} else if ($p['validity_unit'] == 'Mins') {
$datetime = explode(' ', date("Y-m-d H:i:s", strtotime($b['expiration'] . ' ' . $b['time'] . ' +' . $p['validity'] . ' minutes')));
$date_exp = $datetime[0];
$time = $datetime[1];
}
}
}
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;
@ -430,10 +455,20 @@ 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'];
$t->price = $p['price'] + $add_cost;
if ($p['validity_unit'] == 'Period') {
// Postpaid price from field
$add_inv = User::getAttribute("Invoice", $id_customer);
if (empty($add_inv) or $add_inv == 0) {
$t->price = $p['price'] + $add_cost;
} else {
$t->price = $add_inv + $add_cost;
}
} else {
$t->price = $p['price'] + $add_cost;
}
$t->recharged_on = $date_only;
$t->recharged_time = $time_only;
$t->expiration = $date_exp;
@ -450,7 +485,7 @@ class Package
$t->save();
if ($p['validity_unit'] == 'Period' && $p['price'] != 0) {
// insert to fields
// insert price to fields for invoice next month
$fl = ORM::for_table('tbl_customers_fields')->where('field_name', 'Invoice')->where('customer_id', $c['id'])->find_one();
if (!$fl) {
$fl = ORM::for_table('tbl_customers_fields')->create();
@ -469,7 +504,8 @@ 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']) {
Radius::customerAddPlan($c, $p, "$date_exp $time");
@ -502,21 +538,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' && $p['price'] != 0) {
// Calculating Price
$sd = new DateTime("$date_only");
$ed = new DateTime("$date_exp");
$td = $ed->diff($sd);
$fd = $td->format("%a");
$gi = ($p['price'] / 30) * $fd;
if ($gi > $p['price']) {
$t->price = $p['price'] + $add_cost;
} else {
$t->price = $gi + $add_cost;
}
if ($p['validity_unit'] == 'Period') {
// Postpaid price always zero for first time
$note = '';
$bills = [];
$t->price = 0;
} else {
$t->price = $p['price'] + $add_cost;
}
@ -536,12 +565,18 @@ class Package
$t->save();
if ($p['validity_unit'] == 'Period' && $p['price'] != 0) {
// insert to fields
// insert price to fields for invoice next month
$fl = ORM::for_table('tbl_customers_fields')->where('field_name', 'Invoice')->where('customer_id', $c['id'])->find_one();
if (!$fl) {
$fl = ORM::for_table('tbl_customers_fields')->create();
$fl->customer_id = $c['id'];
$fl->field_name = 'Invoice';
// Calculating Price
$sd = new DateTime("$date_only");
$ed = new DateTime("$date_exp");
$td = $ed->diff($sd);
$fd = $td->format("%a");
$gi = ($p['price'] / (30 * $p['validity'])) * $fd;
if ($gi > $p['price']) {
$fl->field_value = $p['price'];
} else {
@ -559,15 +594,19 @@ class Package
"\nRouter: " . $router_name .
"\nGateway: " . $gateway .
"\nChannel: " . $channel .
"\nPrice: " . Lang::moneyFormat($p['price']));
"\nPrice: " . Lang::moneyFormat($p['price'] + $add_cost) .
"\nNote:\n" . $note);
}
}
if ($add_rem > 0) {
User::setAttribute('Additional Remaining', ($add_rem - 1), $id_customer);
if (is_array($bills) && count($bills) > 0) {
User::billsPaid($bills, $id_customer);
}
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)
@ -671,7 +710,12 @@ class Package
$_admin = Admin::_info($in['admin_id']);
// if admin not deleted
if ($_admin) $admin = $_admin;
} else {
$admin['fullname'] = 'Customer';
}
$cust = ORM::for_table('tbl_customers')->where('username', $in['username'])->findOne();
$note = '';
//print
$invoice = Lang::pad($config['CompanyName'], ' ', 2) . "\n";
$invoice .= Lang::pad($config['address'], ' ', 2) . "\n";
@ -683,13 +727,31 @@ class Package
$invoice .= Lang::pad("", '=') . "\n";
$invoice .= Lang::pads(Lang::T('Type'), $in['type'], ' ') . "\n";
$invoice .= Lang::pads(Lang::T('Plan Name'), $in['plan_name'], ' ') . "\n";
$invoice .= Lang::pads(Lang::T('Plan Price'), Lang::moneyFormat($in['price']), ' ') . "\n";
$invoice .= Lang::pad($in['method'], ' ', 2) . "\n";
if(!empty($in['note'])){
if (!empty($in['note'])) {
$in['note'] = str_replace("\r", "", $in['note']);
$tmp = explode("\n", $in['note']);
foreach ($tmp as $t) {
if (strpos($t, " : ") === false) {
if (!empty($t)) {
$note .= "$t\n";
}
} else {
$tmp2 = explode(" : ", $t);
$invoice .= Lang::pads($tmp2[0], $tmp2[1], ' ') . "\n";
}
}
}
$invoice .= Lang::pads(Lang::T('Total'), Lang::moneyFormat($in['price']), ' ') . "\n";
$method = explode("-", $in['method']);
$invoice .= Lang::pads($method[0], $method[1], ' ') . "\n";
if (!empty($note)) {
$invoice .= Lang::pad("", '=') . "\n";
$invoice .= Lang::pad($in['note'], ' ', 2);
$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') {
@ -711,13 +773,29 @@ class Package
$invoice .= Lang::pad("", '=') . "\n";
$invoice .= Lang::pads(Lang::T('Type'), $in['type'], ' ') . "\n";
$invoice .= Lang::pads(Lang::T('Plan Name'), $in['plan_name'], ' ') . "\n";
$invoice .= Lang::pads(Lang::T('Plan Price'), Lang::moneyFormat($in['price']), ' ') . "\n";
$invoice .= Lang::pad($in['method'], ' ', 2) . "\n";
if(!empty($in['note'])){
if (!empty($in['note'])) {
$invoice .= Lang::pad("", '=') . "\n";
$invoice .= Lang::pad($in['note'], ' ', 2);
foreach ($tmp as $t) {
if (strpos($t, " : ") === false) {
if (!empty($t)) {
$invoice .= Lang::pad($t, ' ', 2) . "\n";
}
} else {
$tmp2 = explode(" : ", $t);
$invoice .= Lang::pads($tmp2[0], $tmp2[1], ' ') . "\n";
}
}
}
$invoice .= Lang::pads(Lang::T('Total'), Lang::moneyFormat($in['price']), ' ') . "\n";
$invoice .= Lang::pads($method[0], $method[1], ' ') . "\n";
if (!empty($note)) {
$invoice .= Lang::pad("", '=') . "\n";
$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') {
@ -729,4 +807,11 @@ class Package
$ui->assign('whatsapp', urlencode("```$invoice```"));
$ui->assign('in', $in);
}
public static function tax($price, $tax_rate = 1)
{
// Convert tax rate to decimal
$tax_rate_decimal = $tax_rate / 100;
$tax = $price * $tax_rate_decimal;
return $tax;
}
}

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-Volume', 'username', $customer['username']);
$p->groupname = "plan_" . $plan['id'];
$p->save();
} else {
@ -176,38 +188,49 @@ 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";
else
$datalimit = $plan['data_limit'] . "000000";
//Radius::upsertCustomer($customer['username'], 'Max-Volume', $datalimit);
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-Volume', $datalimit);
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-Volume', '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'], 'expiration', date('d M Y H:i:s', strtotime($expired)));
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(
$customer['username'],
@ -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(), 'expiration', '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) {
@ -301,7 +326,11 @@ class Radius
if ($_app_stage == 'demo') {
return null;
}
$nas = Radius::getTableNas()->findMany();
/**
* Fix loop to all Nas but still detecting Hotspot Multylogin from other Nas
*/
$act = ORM::for_table('radacct')->where_raw("acctstoptime IS NULL")->where('username', $username)->find_one();
$nas = Radius::getTableNas()->where('nasname', $act['nasipaddress'])->find_many();
$count = count($nas) * 15;
set_time_limit($count);
$result = [];
@ -310,7 +339,7 @@ class Radius
if (!empty($n['ports'])) {
$port = $n['ports'];
}
$result[] = $n['nasname'] . ': ' . @shell_exec("echo 'User-Name = $username' | " . Radius::getClient() . " " . trim($n['nasname']) . ":$port disconnect '" . $n['secret'] . "'");
$result[] = $n['nasname'] . ': ' . @shell_exec("echo 'User-Name = $username,Framed-IP-Address = " . $act['framedipaddress'] . "' | radclient -x " . trim($n['nasname']) . ":$port disconnect '" . $n['secret'] . "'");
}
return $result;
}

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

@ -26,6 +26,60 @@ class User
return 0;
}
public static function getBills($id = 0)
{
if (!$id) {
$id = User::getID();
if (!$id) {
return [];
}
}
$addcost = 0;
$bills = [];
$attrs = User::getAttributes('Bill', $id);
foreach ($attrs as $k => $v) {
// if has : then its an installment
if (strpos($v, ":") === false) {
// Not installment
$bills[$k] = $v;
$addcost += $v;
} else {
// installment
list($cost, $rem) = explode(":", $v);
// :0 installment is done
if (!empty($rem)) {
$bills[$k] = $cost;
$addcost += $cost;
}
}
}
return [$bills, $addcost];
}
public static function billsPaid($bills, $id = 0)
{
if (!$id) {
$id = User::getID();
if (!$id) {
return [];
}
}
foreach ($bills as $k => $v) {
// if has : then its an installment
$v = User::getAttribute($k, $id);
if (strpos($v, ":") === false) {
// Not installment, no need decrement
} else {
// installment
list($cost, $rem) = explode(":", $v);
// :0 installment is done
if ($rem != 0) {
User::setAttribute($k, "$cost:" . ($rem - 1), $id);
}
}
}
}
public static function setAttribute($name, $value, $id = 0)
{
if (!$id) {
@ -35,7 +89,7 @@ class User
}
}
$f = ORM::for_table('tbl_customers_fields')->where('field_name', $name)->where('customer_id', $id)->find_one();
if(!$f){
if (!$f) {
$f = ORM::for_table('tbl_customers_fields')->create();
$f->customer_id = $id;
$f->field_name = $name;
@ -45,7 +99,7 @@ class User
if ($result) {
return $result;
}
}else{
} else {
$f->field_value = $value;
$f->save();
return $f['id'];
@ -109,7 +163,9 @@ class User
$id = User::getID();
}
$d = ORM::for_table('tbl_customers')->find_one($id);
if ($d['status'] == 'Banned') {
_alert(Lang::T('This account status') . ' : ' . Lang::T($d['status']), 'danger', "logout");
}
if (empty($d['username'])) {
r2(U . 'logout', 'd', '');
}
@ -123,22 +179,15 @@ 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'))
->left_outer_join('tbl_plans', array('tbl_plans.id', '=', 'tbl_user_recharges.plan_id'))
->find_many();
return $d;
}

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

@ -11,4 +11,16 @@ $ui->assign('_system_menu', 'community');
$action = $routes['1'];
$ui->assign('_admin', $admin);
$ui->display('community.tpl');
switch ($action) {
case 'rollback':
$ui->assign('_title', 'Rollback Update');
$masters = json_decode(Http::getData("https://api.github.com/repos/hotspotbilling/phpnuxbill/commits?per_page=100",['User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:125.0) Gecko/20100101 Firefox/125.0']), true);
$devs = json_decode(Http::getData("https://api.github.com/repos/hotspotbilling/phpnuxbill/commits?sha=Development&per_page=100",['User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:125.0) Gecko/20100101 Firefox/125.0']), true);
$ui->assign('masters', $masters);
$ui->assign('devs', $devs);
$ui->display('community-rollback.tpl');
break;
default:
$ui->display('community.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')
->left_outer_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,30 +159,24 @@ 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'];
$b = ORM::for_table('tbl_user_recharges')->where('customer_id', $id_customer)->find_one();
$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';
$channel = $admin['fullname'];
$cust = User::_info($id_customer);
$plan = ORM::for_table('tbl_plans')->find_one($b['plan_id']);
$add_cost = 0;
$add_rem = User::getAttribute("Additional Remaining", $id_customer);
if($add_rem != 0){
$add_cost = User::getAttribute("Additional Cost", $id_customer);
if (empty($add_cost)) {
$add_cost = 0;
}
}
list($bills, $add_cost) = User::getBills($id_customer);
if ($using == 'balance' && $config['enable_balance'] == 'yes') {
if (!$cust) {
r2(U . 'prepaid/recharge', 'e', Lang::T('Customer not found'));
r2(U . 'plan/recharge', 'e', Lang::T('Customer not found'));
}
if (!$plan) {
r2(U . 'prepaid/recharge', 'e', Lang::T('Plan not found'));
r2(U . 'plan/recharge', 'e', Lang::T('Plan not found'));
}
if ($cust['balance'] < ($plan['price'] + $add_cost)) {
r2(U . 'prepaid/recharge', 'e', Lang::T('insufficient balance'));
r2(U . 'plan/recharge', 'e', Lang::T('insufficient balance'));
}
$gateway = 'Recharge Balance';
}
@ -127,27 +184,33 @@ switch ($action) {
$zero = 1;
$gateway = 'Recharge Zero';
}
$bills = User::getAttributes("Bill", $id_customer);
$usings = explode(',', $config['payment_usings']);
$usings = array_filter(array_unique($usings));
if (count($usings) == 0) {
$usings[] = Lang::T('Cash');
}
$ui->assign('usings', $usings);
$ui->assign('bills', $bills);
$ui->assign('add_cost', $add_cost);
$ui->assign('add_rem', $add_rem);
$ui->assign('cust', $cust);
$ui->assign('gateway', $gateway);
$ui->assign('channel', $channel);
$ui->assign('server', $b['routers']);
$ui->assign('using', 'cash');
$ui->assign('plan', $plan);
$ui->display('recharge-confirm.tpl');
} else {
r2(U . 'customers/view/' . $id_customer, 'e', 'Cannot find active plan');
}
r2(U . 'customers/view/' . $id_customer, 'e', 'Cannot find active plan');
break;
case 'deactivate':
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'];
$b = ORM::for_table('tbl_user_recharges')->where('customer_id', $id_customer)->find_one();
$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'])->where('enabled', '1')->find_one();
$p = ORM::for_table('tbl_plans')->where('id', $b['plan_id'])->find_one();
if ($p) {
if ($p['is_radius']) {
Radius::customerDeactivate($b['username']);
@ -174,35 +237,36 @@ switch ($action) {
r2(U . 'customers/view/' . $id_customer, 'e', 'Cannot find active plan');
break;
case 'sync':
$id_customer = $routes['2'];
$b = ORM::for_table('tbl_user_recharges')->where('customer_id', $id_customer)->where('status', 'on')->find_one();
if ($b) {
$c = ORM::for_table('tbl_customers')->find_one($id_customer);
$p = ORM::for_table('tbl_plans')->where('id', $b['plan_id'])->where('enabled', '1')->find_one();
if ($p) {
if ($p['is_radius']) {
Radius::customerAddPlan($c, $p, $p['expiration'] . ' ' . $p['time']);
r2(U . 'customers/view/' . $id_customer, 's', 'Success sync customer to Radius');
} else {
$mikrotik = Mikrotik::info($b['routers']);
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
if ($b['type'] == 'Hotspot') {
Mikrotik::addHotspotUser($client, $p, $c);
} else if ($b['type'] == 'PPPOE') {
Mikrotik::addPpoeUser($client, $p, $c);
$id_customer = $routes['2'];
$bs = ORM::for_table('tbl_user_recharges')->where('customer_id', $id_customer)->where('status', 'on')->findMany();
if ($bs) {
$routers = [];
foreach ($bs as $b) {
$c = ORM::for_table('tbl_customers')->find_one($id_customer);
$p = ORM::for_table('tbl_plans')->where('id', $b['plan_id'])->where('enabled', '1')->find_one();
if ($p) {
$routers[] = $b['routers'];
if ($p['is_radius']) {
Radius::customerAddPlan($c, $p, $p['expiration'] . ' ' . $p['time']);
} else {
$mikrotik = Mikrotik::info($b['routers']);
$client = Mikrotik::getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
if ($b['type'] == 'Hotspot') {
Mikrotik::addHotspotUser($client, $p, $c);
} else if ($b['type'] == 'PPPOE') {
Mikrotik::addPpoeUser($client, $p, $c);
}
}
r2(U . 'customers/view/' . $id_customer, 's', 'Success sync customer to Mikrotik');
}
} else {
r2(U . 'customers/view/' . $id_customer, 'e', 'Customer plan is inactive');
}
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);
@ -214,45 +278,35 @@ switch ($action) {
$customFields = ORM::for_table('tbl_customers_fields')
->where('customer_id', $customer['id'])
->find_many();
$v = $routes['3'];
if (empty($v) || $v == 'order') {
$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);
}
$package = ORM::for_table('tbl_user_recharges')->where('username', $customer['username'])->find_one();
$ui->assign('package', $package);
$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
@ -261,10 +315,12 @@ switch ($action) {
->find_many();
if ($d) {
$ui->assign('d', $d);
$ui->assign('statuses', ORM::for_table('tbl_customers')->getEnum("status"));
$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;
@ -272,7 +328,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) {
@ -311,7 +367,8 @@ switch ($action) {
} catch (Throwable $e) {
}
try {
if ($c) $c->delete();
if ($c)
$c->delete();
} catch (Exception $e) {
} catch (Throwable $e) {
}
@ -330,9 +387,16 @@ 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'];
//additional information
$city = _post('city');
$district = _post('district');
$state = _post('state');
$zip = _post('zip');
run_hook('add_customer'); #HOOK
$msg = '';
@ -357,11 +421,17 @@ 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->city = $city;
$d->district = $district;
$d->state = $state;
$d->zip = $zip;
$d->save();
// Retrieve the customer ID of the newly created customer
@ -391,12 +461,20 @@ 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');
$status = _post('status');
//additional information
$city = _post('city');
$district = _post('district');
$state = _post('state');
$zip = _post('zip');
run_hook('edit_customer'); #HOOK
$msg = '';
if (Validator::Length($username, 35, 2) == false) {
@ -424,8 +502,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;
@ -453,9 +531,16 @@ switch ($action) {
$d->pppoe_password = $pppoe_password;
$d->fullname = $fullname;
$d->email = $email;
$d->account_type = $account_type;
$d->address = $address;
$d->status = $status;
$d->phonenumber = $phonenumber;
$d->service_type = $service_type;
$d->coordinates = $coordinates;
$d->city = $city;
$d->district = $district;
$d->state = $state;
$d->zip = $zip;
$d->save();
@ -540,5 +625,81 @@ switch ($action) {
break;
default:
r2(U . 'customers/list', 'e', 'action not defined');
run_hook('list_customers'); #HOOK
$search = _post('search');
$order = _post('order', 'username');
$filter = _post('filter', 'Active');
$orderby = _post('orderby', 'asc');
$order_pos = [
'username' => 0,
'created_at' => 8,
'balance' => 3,
'status' => 7
];
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%' AND status='$filter'");
} else {
$query = ORM::for_table('tbl_customers');
$query->where("status", $filter);
}
if ($orderby == 'asc') {
$query->order_by_asc($order);
} else {
$query->order_by_desc($order);
}
$d = $query->findMany();
if (_post('export', '') == 'csv') {
$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_customers_' . $filter . '_' . date('Y-m-d_H_i') . '.csv"');
header('Content-Transfer-Encoding: binary');
$headers = [
'id',
'username',
'fullname',
'address',
'phonenumber',
'email',
'balance',
'service_type',
];
$fp = fopen('php://output', 'wb');
if (!$h) {
fputcsv($fp, $headers, ";");
$h = true;
}
foreach ($d as $c) {
$row = [
$c['id'],
$c['username'],
$c['fullname'],
str_replace("\n", " ", $c['address']),
$c['phonenumber'],
$c['email'],
$c['balance'],
$c['service_type'],
];
fputcsv($fp, $row, ";");
}
fclose($fp);
die();
}
$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('statuses', ORM::for_table('tbl_customers')->getEnum("status"));
$ui->assign('filter', $filter);
$ui->assign('search', $search);
$ui->assign('order', $order);
$ui->assign('order_pos', $order_pos[$order]);
$ui->assign('orderby', $orderby);
$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

@ -18,6 +18,9 @@ if (isset($_GET['renewal'])) {
if (_post('send') == 'balance') {
if ($config['enable_balance'] == 'yes' && $config['allow_balance_transfer'] == 'yes') {
if ($user['status'] == 'Active') {
_alert(Lang::T('This account status') . ' : ' . Lang::T($user['status']), 'danger', "");
}
$target = ORM::for_table('tbl_customers')->where('username', _post('username'))->find_one();
if (!$target) {
r2(U . 'home', 'd', Lang::T('Username not found'));
@ -77,37 +80,120 @@ 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')
->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'));
if ($user['status'] == 'Active') {
_alert(Lang::T('This account status') . ' : ' . Lang::T($user['status']), 'danger', "");
}
$actives = ORM::for_table('tbl_user_recharges')
->where('username', _post('username'))
->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 ($user['status'] == 'Active') {
_alert(Lang::T('This account status') . ' : ' . Lang::T($user['status']), 'danger', "");
}
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 ($user['status'] == 'Active') {
_alert(Lang::T('This account status') . ' : ' . Lang::T($user['status']), 'danger', "");
}
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 +219,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

@ -5,8 +5,13 @@
* by https://t.me/ibnux
**/
if(User::getID()){
r2(U.'home');
$maintenance_mode = $config['maintenance_mode'];
if ($maintenance_mode == true){
displayMaintenanceMessage();
}
if (User::getID()) {
r2(U . 'home');
}
if (isset($routes['1'])) {
@ -24,13 +29,16 @@ switch ($do) {
$d = ORM::for_table('tbl_customers')->where('username', $username)->find_one();
if ($d) {
$d_pass = $d['password'];
if ($d['status'] == 'Banned') {
_alert(Lang::T('This account status') . ' : ' . Lang::T($d['status']), 'danger', "");
}
if (Password::_uverify($password, $d_pass) == true) {
$_SESSION['uid'] = $d['id'];
User::setCookie($d['id']);
$d->last_login = date('Y-m-d H:i:s');
$d->save();
_log($username . ' ' . Lang::T('Login Successful'), 'User', $d['id']);
_alert(Lang::T('Login Successful'),'success', "home");
_alert(Lang::T('Login Successful'), 'success', "home");
} else {
_msglog('e', Lang::T('Invalid Username or Password'));
_log($username . ' ' . Lang::T('Failed Login'), 'User');
@ -68,7 +76,7 @@ switch ($do) {
r2(U . 'login', 'e', Lang::T('Voucher activation failed'));
}
} else {
_alert(Lang::T('Login Successful'),'success', "dashboard");
_alert(Lang::T('Login Successful'), 'success', "dashboard");
r2(U . 'login', 'e', Lang::T('Voucher activation failed') . '.');
}
}

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

@ -0,0 +1,238 @@
<?php
/**
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
* by https://t.me/ibnux
**/
_admin();
$ui->assign('_title', Lang::T('Send Message'));
$ui->assign('_system_menu', 'message');
$action = $routes['1'];
$ui->assign('_admin', $admin);
if (empty($action)) {
$action = 'send';
}
switch ($action) {
case 'send':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
$select2_customer = <<<EOT
<script>
document.addEventListener("DOMContentLoaded", function(event) {
$('#personSelect').select2({
theme: "bootstrap",
ajax: {
url: function(params) {
if(params.term != undefined){
return './index.php?_route=autoload/customer_select2&s='+params.term;
}else{
return './index.php?_route=autoload/customer_select2';
}
}
}
});
});
</script>
EOT;
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;
case 'send-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
$id_customer = $_POST['id_customer'];
$message = $_POST['message'];
$via = $_POST['via'];
// Check if fields are empty
if ($id_customer == '' or $message == '' or $via == '') {
r2(U . 'message/send', 'e', Lang::T('All field is required'));
} else {
// Get customer details from the database
$c = ORM::for_table('tbl_customers')->find_one($id_customer);
// Replace placeholders in the message with actual values
$message = str_replace('[[name]]', $c['fullname'], $message);
$message = str_replace('[[user_name]]', $c['username'], $message);
$message = str_replace('[[phone]]', $c['phonenumber'], $message);
$message = str_replace('[[company_name]]', $config['CompanyName'], $message);
//Send the message
if ($via == 'sms' || $via == 'both') {
$smsSent = Message::sendSMS($c['phonenumber'], $message);
}
if ($via == 'wa' || $via == 'both') {
$waSent = Message::sendWhatsapp($c['phonenumber'], $message);
}
if (isset($smsSent) || isset($waSent)) {
r2(U . 'message/send', 's', Lang::T('Message Sent Successfully'));
} else {
r2(U . 'message/send', 'e', Lang::T('Failed to send message'));
}
}
break;
case 'send_bulk':
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
$totalSMSSent = 0;
$totalSMSFailed = 0;
$totalWhatsappSent = 0;
$totalWhatsappFailed = 0;
$batchStatus = [];
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 {
// 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') {
@ -124,16 +123,16 @@ switch ($action) {
$trx = ORM::for_table('tbl_payment_gateway')
->where('username', $user['username'])
->find_one($trxid);
if ('midtrans' == $trx['gateway']) {
//Hapus invoice link
}
}
if (empty($trx)) {
r2(U . "order/package", 'e', Lang::T("Transaction Not found"));
}
$router = ORM::for_table('tbl_routers')->find_one($trx['routers_id']);
$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']);
$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"));
@ -157,21 +160,44 @@ switch ($action) {
} else {
$router_name = $plan['routers'];
}
if ($plan && $plan['enabled'] && $user['balance'] >= $plan['price']) {
list($bills, $add_cost) = User::getBills($id_customer);
// Tax calculation start
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : null;
if ($tax_rate_setting === 'custom') {
$tax_rate = $custom_tax_rate;
} else {
$tax_rate = $tax_rate_setting;
}
if ($tax_enable === 'yes') {
$tax = Package::tax($plan['price'], $tax_rate);
} else {
$tax = 0;
}
// Tax calculation stop
if ($plan && $plan['enabled'] && $user['balance'] >= $plan['price'] + $tax) {
if (Package::rechargeUser($user['id'], $router_name, $plan['id'], 'Customer', 'Balance')) {
// if success, then get the balance
Balance::min($user['id'], $plan['price']);
r2(U . "home", 's', Lang::T("Success to buy package"));
Balance::min($user['id'], $plan['price'] + $add_cost + $tax);
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"));
Message::sendTelegram("Buy Package with Balance Failed\n\n#u$c[username] #buy \n" . $plan['name_plan'] .
"\nRouter: " . $router_name .
"\nPrice: " . $p['price']);
"\nPrice: " . $plan['price'] + $tax);
}
} else {
r2(U . "home", 'e', 'Plan is not exists');
}
break;
case 'send':
if ($config['enable_balance'] != 'yes') {
r2(U . "order/package", 'e', Lang::T("Balance not enabled"));
@ -190,8 +216,36 @@ switch ($action) {
} else {
$router_name = $plan['routers'];
}
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : null;
if ($tax_rate_setting === 'custom') {
$tax_rate = $custom_tax_rate;
} else {
$tax_rate = $tax_rate_setting;
}
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
if ($tax_enable === 'yes') {
$tax = Package::tax($plan['price'], $tax_rate);
$ui->assign('tax', $tax);
} else {
$tax = 0;
}
// Add tax to plan price
$plan['price'] += $tax;
if (isset($_POST['send']) && $_POST['send'] == 'plan') {
$target = ORM::for_table('tbl_customers')->where('username', _post('username'))->find_one();
list($bills, $add_cost) = User::getBills($target['id']);
if (!empty($add_cost)) {
$ui->assign('bills', $bills);
$ui->assign('add_cost', $add_cost);
$plan['price'] += $add_cost;
}
if (!$target) {
r2(U . 'home', 'd', Lang::T('Username not found'));
}
@ -209,7 +263,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
@ -227,6 +282,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();
@ -245,19 +301,27 @@ 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"));
} else {
r2(U . "order/package", 'e', Lang::T("Failed to Send package"));
Message::sendTelegram("Send Package with Balance Failed\n\n#u$user[username] #send \n" . $plan['name_plan'] .
$errorMessage = "Send Package with Balance Failed\n\n#u$user[username] #send \n" . $plan['name_plan'] .
"\nRouter: " . $router_name .
"\nPrice: " . $plan['price']);
"\nPrice: " . $plan['price'];
if ($tax_enable === 'yes') {
$errorMessage .= "\nTax: " . $tax;
}
r2(U . "order/package", 'e', Lang::T("Failed to Send package"));
Message::sendTelegram($errorMessage);
}
}
$ui->assign('username', $_GET['u']);
$ui->assign('router', $router_name);
$ui->assign('plan', $plan);
$ui->assign('tax', $tax);
$ui->display('user-sendPlan.tpl');
break;
case 'gateway':
@ -266,27 +330,38 @@ switch ($action) {
if (strpos($user['email'], '@') === false) {
r2(U . 'accounts/profile', 'e', Lang::T("Please enter your email address"));
}
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : null;
if ($tax_rate_setting === 'custom') {
$tax_rate = $custom_tax_rate;
} else {
$tax_rate = $tax_rate_setting;
}
$plan = ORM::for_table('tbl_plans')->find_one($routes['3']);
$tax = Package::tax($plan['price'], $tax_rate);
$pgs = array_values(explode(',', $config['payment_gateway']));
if(count($pgs)==0){
if (count($pgs) == 0) {
sendTelegram("Payment Gateway not set, please set it in Settings");
_log(Lang::T("Payment Gateway not set, please set it in Settings"));
r2(U . "home", 'e', Lang::T("Failed to create Transaction.."));
}
if(count($pgs)>1){
$ui->assign('pgs',$pgs );
//$ui->assign('pgs', $pgs);
if (count($pgs) > 1) {
$ui->assign('pgs', $pgs);
if ($tax_enable === 'yes') {
$ui->assign('tax', $tax);
}
$ui->assign('route2', $routes[2]);
$ui->assign('route3', $routes[3]);
//$ui->assign('plan', $plan);
$ui->assign('plan', $plan);
$ui->display('user-selectGateway.tpl');
break;
}else{
if(empty($pgs[0])){
} else {
if (empty($pgs[0])) {
sendTelegram("Payment Gateway not set, please set it in Settings");
_log(Lang::T("Payment Gateway not set, please set it in Settings"));
r2(U . "home", 'e', Lang::T("Failed to create Transaction.."));
}else{
} else {
$_POST['gateway'] = $pgs[0];
}
}
@ -333,6 +408,24 @@ switch ($action) {
}
}
}
$add_cost = 0;
$tax = 0;
if ($router['name'] != 'balance') {
list($bills, $add_cost) = User::getBills($id_customer);
}
// Tax calculation start
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : null;
if ($tax_rate_setting === 'custom') {
$tax_rate = $custom_tax_rate;
} else {
$tax_rate = $tax_rate_setting;
}
if ($tax_enable === 'yes') {
$tax = Package::tax($plan['price'], $tax_rate);
}
// Tax calculation stop
if (empty($id)) {
$d = ORM::for_table('tbl_payment_gateway')->create();
$d->username = $user['username'];
@ -341,7 +434,18 @@ switch ($action) {
$d->plan_name = $plan['name_plan'];
$d->routers_id = $router['id'];
$d->routers = $router['name'];
$d->price = $plan['price'];
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 + $tax);
} else {
$d->price = ($add_inv + $add_cost + $tax);
}
} else {
$d->price = ($plan['price'] + $add_cost + $tax);
}
//$d->price = ($plan['price'] + $add_cost);
$d->created_date = date('Y-m-d H:i:s');
$d->status = 1;
$d->save();
@ -353,7 +457,18 @@ switch ($action) {
$d->plan_name = $plan['name_plan'];
$d->routers_id = $router['id'];
$d->routers = $router['name'];
$d->price = $plan['price'];
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 + $tax);
} else {
$d->price = ($add_inv + $add_cost + $tax);
}
} else {
$d->price = ($plan['price'] + $add_cost + $tax);
}
//$d->price = ($plan['price'] + $add_cost);
$d->created_date = date('Y-m-d H:i:s');
$d->status = 1;
$d->save();

File diff suppressed because it is too large Load Diff

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;
@ -23,7 +23,7 @@ switch ($action) {
case 'sync':
set_time_limit(-1);
if ($routes['2'] == 'hotspot') {
$plans = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'Hotspot')->where('tbl_plans.enabled', '1')->find_many();
$plans = ORM::for_table('tbl_bandwidth')->left_outer_join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'Hotspot')->where('tbl_plans.enabled', '1')->find_many();
$log = '';
$router = '';
foreach ($plans as $plan) {
@ -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 {
@ -68,7 +68,7 @@ switch ($action) {
}
r2(U . 'services/hotspot', 's', $log);
} else if ($routes['2'] == 'pppoe') {
$plans = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'PPPOE')->where('tbl_plans.enabled', '1')->find_many();
$plans = ORM::for_table('tbl_bandwidth')->left_outer_join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'PPPOE')->where('tbl_plans.enabled', '1')->find_many();
$log = '';
$router = '';
foreach ($plans as $plan) {
@ -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')->left_outer_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')->left_outer_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,16 @@ 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']);
// 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; // 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 +296,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 +346,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']);
@ -358,15 +360,15 @@ switch ($action) {
Mikrotik::setHotspotExpiredPlan($client, 'EXPIRED NUXBILL ' . $pool_expired, $pool_expired);
}
}
$d->name_plan = $name;
$d->id_bw = $id_bw;
$d->price = $price;
$d->price = $price; // 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 +391,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')->left_outer_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')->left_outer_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 +415,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 +431,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 +462,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 +514,14 @@ 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']);
$d = ORM::for_table('tbl_plans')->create();
$d->type = 'PPPOE';
$d->name_plan = $name;
$d->id_bw = $id_bw;
$d->price = $price;
$d->plan_type = $plan_type;
$d->validity = $validity;
$d->validity_unit = $validity_unit;
$d->pool = $pool;
@ -556,6 +558,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 +605,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']) {
@ -615,10 +618,10 @@ switch ($action) {
Mikrotik::setPpoePlan($client, 'EXPIRED NUXBILL ' . $pool_expired, $pool_expired, '512K/512K');
}
}
$d->name_plan = $name;
$d->id_bw = $id_bw;
$d->price = $price;
$d->plan_type = $plan_type;
$d->validity = $validity;
$d->validity_unit = $validity_unit;
$d->routers = $routers;
@ -638,15 +641,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 +659,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) {

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) {
@ -128,7 +132,6 @@ switch ($action) {
$d->save();
}
}
//checkbox
$checks = ['hide_mrc', 'hide_tms', 'hide_aui', 'hide_al', 'hide_uet', 'hide_vs', 'hide_pg'];
foreach ($checks as $check) {
@ -276,60 +279,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 +335,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 +373,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 +414,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 +433,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;
@ -730,22 +704,46 @@ switch ($action) {
$suc = 0;
$fal = 0;
$json = json_decode(file_get_contents($_FILES['json']['tmp_name']), true);
try {
ORM::raw_execute("SET FOREIGN_KEY_CHECKS=0;");
} catch (Throwable $e) {
} catch (Exception $e) {
}
try {
ORM::raw_execute("SET GLOBAL FOREIGN_KEY_CHECKS=0;");
} catch (Throwable $e) {
} catch (Exception $e) {
}
foreach ($json as $table => $records) {
ORM::raw_execute("TRUNCATE $table;");
foreach ($records as $rec) {
$t = ORM::for_table($table)->create();
foreach ($rec as $k => $v) {
if ($k != 'id') {
try {
$t = ORM::for_table($table)->create();
foreach ($rec as $k => $v) {
$t->set($k, $v);
}
}
if ($t->save()) {
$suc++;
} else {
if ($t->save()) {
$suc++;
} else {
$fal++;
}
} catch (Throwable $e) {
$fal++;
} catch (Exception $e) {
$fal++;
}
}
}
try {
ORM::raw_execute("SET FOREIGN_KEY_CHECKS=1;");
} catch (Throwable $e) {
} catch (Exception $e) {
}
try {
ORM::raw_execute("SET GLOBAL FOREIGN_KEY_CHECKS=1;");
} catch (Throwable $e) {
} catch (Exception $e) {
}
if (file_exists($_FILES['json']['tmp_name'])) unlink($_FILES['json']['tmp_name']);
r2(U . "settings/dbstatus", 's', "Restored $suc success $fal failed");
} else {
@ -770,6 +768,40 @@ switch ($action) {
r2(U . 'settings/language', 's', Lang::T('Translation saved Successfully'));
break;
case 'maintenance':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
exit;
}
if (_post('save') == 'save') {
$status = isset($_POST['maintenance_mode']) ? 1 : 0; // Checkbox returns 1 if checked, otherwise 0
$date = isset($_POST['maintenance_date']) ? $_POST['maintenance_date'] : null;
$settings = [
'maintenance_mode' => $status,
'maintenance_date' => $date
];
foreach ($settings as $key => $value) {
$d = ORM::for_table('tbl_appconfig')->where('setting', $key)->find_one();
if ($d) {
$d->value = $value;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = $key;
$d->value = $value;
$d->save();
}
}
r2(U . "settings/maintenance", 's', Lang::T('Settings Saved Successfully'));
}
$ui->assign('_c', $config);
$ui->assign('_title', Lang::T('Maintenance Mode Settings'));
$ui->display('maintenance-mode.tpl');
break;
default:
$ui->display('a404.tpl');
}

View File

@ -40,20 +40,28 @@ 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');
break;
case 'invoice':
$id = $routes[2];
$in = ORM::for_table('tbl_transactions')->where('username', $user['username'])->where('id', $id)->find_one();
Package::createInvoice($in);
$ui->display('invoice-customer.tpl');
if(empty($id)){
$in = ORM::for_table('tbl_transactions')->where('username', $user['username'])->order_by_desc('id')->find_one();
}else{
$in = ORM::for_table('tbl_transactions')->where('username', $user['username'])->where('id', $id)->find_one();
}
if($in){
Package::createInvoice($in);
$ui->display('invoice-customer.tpl');
}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']));
@ -46,23 +45,29 @@ foreach ($d as $ds) {
$client = Mikrotik::getClient($m['ip_address'], $m['username'], $m['password']);
if (!empty($p['pool_expired'])) {
Mikrotik::setHotspotUserPackage($client, $c['username'], 'EXPIRED NUXBILL ' . $p['pool_expired']);
// }if (!empty($p['list_expired'])) {
// $ip = Mikrotik::getIpHotspotUser($client, $ds['username']);
// Mikrotik::addIpToAddressList($client, $ip, $p['list_expired'], $c['username']);
// }if (!empty($p['list_expired'])) {
// $ip = Mikrotik::getIpHotspotUser($client, $ds['username']);
// Mikrotik::addIpToAddressList($client, $ip, $p['list_expired'], $c['username']);
} else {
Mikrotik::removeHotspotUser($client, $c['username']);
}
Mikrotik::removeHotspotActiveUser($client, $c['username']);
}
echo Message::sendPackageNotification($c, $u['namebp'], $price, $textExpired, $config['user_notification_expired'])."\n";
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();
// autorenewal from deposit
if ($config['enable_balance'] == 'yes' && $c['auto_renewal']) {
list($bills, $add_cost) = User::getBills($ds['customer_id']);
if ($add_cost > 0) {
if (!empty($add_cost)) {
$p['price'] += $add_cost;
}
}
if ($p && $p['enabled'] && $c['balance'] >= $p['price']) {
if (Package::rechargeUser($ds['customer_id'], $p['routers'], $p['id'], 'Customer', 'Balance')) {
if (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";
@ -92,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']));
@ -109,15 +113,21 @@ 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();
// autorenewal from deposit
if ($config['enable_balance'] == 'yes' && $c['auto_renewal']) {
list($bills, $add_cost) = User::getBills($ds['customer_id']);
if ($add_cost > 0) {
if (!empty($add_cost)) {
$p['price'] += $add_cost;
}
}
if ($p && $p['enabled'] && $c['balance'] >= $p['price']) {
if (Package::rechargeUser($ds['customer_id'], $p['routers'], $p['id'], 'Customer', 'Balance')) {
if (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,7 +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();
$price = Lang::moneyFormat($p['price']);
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 = $p['price'];
} else {
$price = $add_inv;
}
} else {
$price = $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) {
@ -47,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",
@ -100,9 +100,6 @@
"Add_Pool": "Add Pool",
"Edit_Pool": "Edit Pool",
"Pool_Name_Already_Exist": "Pool Name Already Exist",
"Prepaid": "Prepaid",
"Prepaid_Users": "Prepaid Users",
"Prepaid_Vouchers": "Prepaid Vouchers",
"Refill_Account": "Refill Account",
"Recharge_Account": "Recharge Account",
"Select_Account": "Select Account",
@ -487,5 +484,144 @@
"Current_Cycle": "Current Cycle",
"Additional_Cost": "Additional Cost",
"Remaining": "Remaining",
"": ""
"Not_Found": "Not Found",
"Cash": "Cash",
"Payment_not_found": "Payment not found",
"If_your_friend_have_Additional_Cost__you_will_pay_for_that_too": "If your friend have Additional Cost, you will pay for that too",
"Cache_cleared_successfully_": "Cache cleared successfully!",
"Paid": "Paid",
"Send_Message": "Send Message",
"Send_Personal_Message": "Send Personal Message",
"Send_Via": "Send Via",
"Compose_your_message___": "Compose your message...",
"Use_placeholders_": "Use placeholders:",
"Customer_Name": "Customer Name",
"Customer_Username": "Customer Username",
"Customer_Phone": "Customer Phone",
"Your_Company_Name": "Your Company Name",
"Message_Sent_Successfully": "Message Sent Successfully",
"Send_Bulk_Message": "Send Bulk Message",
"Group": "Group",
"All_Customers": "All Customers",
"New_Customers": "New Customers",
"Expired_Customers": "Expired 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",
"ago": "ago",
"Disabled": "Disabled",
"Banned": "Banned",
"Customer_cannot_login_again": "Customer cannot login again",
"Customer_can_login_but_cannot_buy_internet_plan__Admin_cannot_recharge_customer": "Customer can login but cannot buy internet plan, Admin cannot recharge customer",
"Don_t_forget_to_deactivate_all_active_plan_too": "Don&#39;t forget to deactivate all active plan too",
"Ascending": "Ascending",
"Descending": "Descending",
"Created_Date": "Created Date",
"Inactive": "Inactive",
"Suspended": "Suspended",
"Query": "Query",
"Notes": "Notes",
"This_account_status": "This account status",
"Maintenance_Mode": "Maintenance Mode",
"Maintenance_Mode_Settings": "Maintenance Mode Settings",
"Status_": "Status:",
"End_Date_": "End Date:",
"Save": "Save",
"Site_is_temporarily_unavailable_": "Site is temporarily unavailable.",
"Scheduled_maintenance_is_currently_in_progress__Please_check_back_soon_": "Scheduled maintenance is currently in progress. Please check back soon.",
"We_apologize_for_any_inconvenience_": "We apologize for any inconvenience.",
"The": "The",
"Team": "Team",
"Extend_Package_Expiry": "Extend Package Expiry",
"No": "No",
"Yes": "Yes",
"If_user_buy_same_internet_plan__expiry_date_will_extend": "If user buy same internet plan, expiry date will extend",
"Tax_System": "Tax System",
"Enable_Tax_System": "Enable Tax System",
"Tax_will_be_calculated_in_Internet_Plan_Price": "Tax will be calculated in Internet Plan Price",
"Tax_Rate": "Tax Rate",
"0_5_": "0.5%",
"1_": "1%",
"1_5_": "1.5%",
"2_": "2%",
"5_": "5%",
"10_": "10%",
"Custom": "Custom",
"Tax_Rates_in_percentage": "Tax Rates in percentage",
"Custom_Tax_Rate": "Custom Tax Rate",
"Enter_Custom_Tax_Rate": "Enter Custom Tax Rate",
"Enter_the_custom_tax_rate__e_g___3_75_for_3_75__": "Enter the custom tax rate (e.g., 3.75 for 3.75%)"
}

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,28 +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",
"Prepaid": "Prabayar",
"Prepaid_Users": "Pengguna Prabayar",
"Prepaid_Vouchers": "Voucher Prabayar",
"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",
@ -126,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",
@ -152,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",
@ -177,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",
@ -191,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",
@ -215,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",
@ -246,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",
@ -261,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",
@ -279,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",
@ -287,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",
@ -316,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",
@ -325,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",
@ -337,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",
@ -345,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",
@ -364,21 +361,120 @@
"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",
"Disabled": "Dinonaktifkan",
"Banned": "Dicekal",
"Inactive": "Tidak Aktif",
"Suspended": "Disuspend"
}

View File

@ -100,9 +100,6 @@
"Add_Pool": "Agregar Pool",
"Edit_Pool": "Editar Pool",
"Pool_Name_Already_Exist": "Nombre del Pool ya existe",
"Prepaid": "Prepago",
"Prepaid_Users": "Usuarios prepago",
"Prepaid_Vouchers": "Fichas prepago",
"Refill_Account": "Recargar Ficha",
"Recharge_Account": "Recargar Cuenta",
"Select_Account": "Seleccionar cuenta",

View File

@ -96,9 +96,6 @@
"Add_Pool": "Havuz ekle",
"Edit_Pool": "Havuzu D\u00fczenle",
"Pool_Name_Already_Exist": "Havuz Ad\u0131 \u200b\u200bZaten Var",
"Prepaid": "\u00d6n \u00d6demeli",
"Prepaid_Users": "\u00d6n \u00d6demeli Kullan\u0131c\u0131lar",
"Prepaid_Vouchers": "\u00d6n \u00d6demeli Kuponlar",
"Refill_Account": "Hesab\u0131 Yenile",
"Recharge_Account": "Hesab\u0131 Yeniden \u015earj Et",
"Select_Account": "Hesap Se\u00e7",

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,29 @@
],
"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`;"
],
"2024.5.17" : [
"ALTER TABLE `tbl_customers` ADD `status` ENUM('Active','Banned','Disabled') NOT NULL DEFAULT 'Active' AFTER `auto_renewal`;"
],
"2024.5.18" : [
"ALTER TABLE `tbl_customers` CHANGE `status` `status` ENUM('Active','Banned','Disabled','Inactive','Limited','Suspended') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'Active';"
],
"2024.5.20" : [
"ALTER TABLE `tbl_customers` ADD `city` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci AFTER `address`, ADD `district` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci AFTER `city`, ADD `state` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci AFTER `district`, ADD `zip` VARCHAR(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci AFTER `state`;"
]
}

View File

@ -1,8 +0,0 @@
<html>
<head>
<title>403 Forbidden</title>
</head>
<body>
<p>Directory access is forbidden.</p>
</body>
</html>

View File

@ -1,9 +1,9 @@
$(document).on("click", ".cdelete", function(e) {
e.preventDefault();
var id = this.id;
bootbox.confirm("Are you sure?", function(result) {
if(result){
window.location.href = "index.php?_route=prepaid/delete/" + id;
}
});
$(document).on("click", ".cdelete", function(e) {
e.preventDefault();
var id = this.id;
bootbox.confirm("Are you sure?", function(result) {
if(result){
window.location.href = "index.php?_route=plan/delete/" + id;
}
});
});

View File

@ -3,7 +3,7 @@
var id = this.id;
bootbox.confirm("Are you sure?", function(result) {
if(result){
window.location.href = "index.php?_route=prepaid/voucher-delete/" + id;
window.location.href = "index.php?_route=plan/voucher-delete/" + id;
}
});
});

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
@ -490,7 +602,84 @@
</div>
<p class="help-block col-md-4">{Lang::T('The method which OTP will be sent to user')}</p>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Extend Package Expiry')}</label>
<div class="col-md-6">
<select name="extend_expiry" id="extend_expiry" class="form-control">
<option value="no" {if $_c['extend_expiry']=='no' }selected="selected" {/if}>
{Lang::T('No')}
<option value="yes" {if $_c['extend_expiry']=='yes' }selected="selected"
{/if}> {Lang::T('Yes')}
</select>
</div>
<p class="help-block col-md-4">{Lang::T('If user buy same internet plan, expiry date will extend')}</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.5" {if $_c['tax_rate']=='0.5' }selected="selected" {/if}>
{Lang::T('0.5%')}
</option>
<option value="1" {if $_c['tax_rate']=='1' }selected="selected" {/if}>
{Lang::T('1%')}
</option>
<option value="1.5" {if $_c['tax_rate']=='1.5' }selected="selected" {/if}>
{Lang::T('1.5%')}
</option>
<option value="2" {if $_c['tax_rate']=='2' }selected="selected" {/if}>
{Lang::T('2%')}
</option>
<option value="5" {if $_c['tax_rate']=='5' }selected="selected" {/if}>
{Lang::T('5%')}
</option>
<option value="10" {if $_c['tax_rate']=='10' }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 +750,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

@ -1,4 +1,9 @@
<option value="">Select Plans</option>
{foreach $d as $ds}
<option value="{$ds['id']}">{if $ds['enabled'] neq 1}DISABLED PLAN &bull; {/if}{$ds['name_plan']} &bull; {Lang::moneyFormat($ds['price'])}{if $ds['prepaid'] neq 'yes'} &bull; POSTPAID {/if}</option>
<option value="{$ds['id']}">
{if $ds['enabled'] neq 1}DISABLED PLAN &bull; {/if}
{$ds['name_plan']} &bull;
{Lang::moneyFormat($ds['price'])}
{if $ds['prepaid'] neq 'yes'} &bull; POSTPAID {/if}
</option>
{/foreach}

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

@ -0,0 +1,59 @@
{include file="sections/header.tpl"}
<center><a href="https://s.id/standwithpalestine" target="_blank"><img
src="https://raw.githubusercontent.com/Safouene1/support-palestine-banner/master/banner-support.svg"
class="img-responsive"></a></center>
<br><br>
<div class="row">
<div class="col-sm-6">
<div class="box box-hovered mb20 box-primary">
<div class="box-header">
<h3 class="box-title">Master</h3>
</div>
<div class="table-responsive">
<table class="table table-bordered table-striped">
<tbody>
{foreach $masters as $data}
<tr>
<td>{nl2br($data['commit']['message'])}</td>
<td>{Lang::dateTimeFormat(str_replace(['Z','T'],'',$data['commit']['author']['date']))}</td>
<td>
<a href="/update.php?update_url=https://github.com/hotspotbilling/phpnuxbill/archive/{$data['sha']}.zip"
class="btn btn-sm btn-primary">
update
</a>
</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
</div>
</div>
<div class="col-sm-6">
<div class="box box-hovered mb20 box-primary">
<div class="box-header">
<h3 class="box-title">Development</h3>
</div>
<div class="table-responsive">
<table class="table table-bordered table-striped">
<tbody>
{foreach $devs as $data}
<tr>
<td>{nl2br($data['commit']['message'])}</td>
<td>{Lang::dateTimeFormat(str_replace(['Z','T'],'',$data['commit']['author']['date']))}</td>
<td>
<a href="/update.php?update_url=https://github.com/hotspotbilling/phpnuxbill/archive/{$data['sha']}.zip"
class="btn btn-sm btn-primary">
update
</a>
</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
</div>
</div>
</div>
{include file="sections/footer.tpl"}

View File

@ -152,8 +152,9 @@
<div class="btn-group btn-group-justified" role="group" aria-label="...">
<a href="./update.php" class="btn btn-success btn-sm btn-block">Install Latest Version</a>
<a href="https://github.com/hotspotbilling/phpnuxbill/archive/refs/heads/master.zip" target="_blank"
class="btn btn-warning btn-sm btn-block">Download Latest Version</a>
class="btn btn-warning btn-sm btn-block text-black">Download Latest Version</a>
</div>
<center><a href="{$_url}community/rollback" class="btn btn-link btn-sm btn-block">Select Old Version</a></center>
</div>
<div class="box-footer">
<div class="btn-group btn-group-justified" role="group" aria-label="...">

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>
@ -101,6 +121,51 @@
</div>
</div>
</div>
<div class="col-md-6">
<div class="box box-primary box-solid collapsed-box">
<div class="box-header with-border">
<h3 class="box-title">{Lang::T('Additional Information')}</h3>
<div class="box-tools pull-right">
<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-plus"></i>
</button>
</div>
</div>
<div class="box-body" style="display: none;">
<div class="form-group">
<label class="col-md-3 control-label">{Lang::T('City')}</label>
<div class="col-md-9">
<input type="text" class="form-control" id="city" name="city"
value="{$d['city']}">
<small class="form-text text-muted">{Lang::T('City of Resident')}</small>
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">{Lang::T('District')}</label>
<div class="col-md-9">
<input type="text" class="form-control" id="district" name="district"
value="{$d['district']}">
<small class="form-text text-muted">{Lang::T('District')}</small>
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">{Lang::T('State')}</label>
<div class="col-md-9">
<input type="text" class="form-control" id="state" name="state"
value="{$d['state']}">
<small class="form-text text-muted">{Lang::T('State of Resident')}</small>
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">{Lang::T('Zip')}</label>
<div class="col-md-9">
<input type="text" class="form-control" id="zip" name="zip"
value="{$d['zip']}">
<small class="form-text text-muted">{Lang::T('Zip Code')}</small>
</div>
</div>
</div>
</div>
</div>
</div>
<center>
<button class="btn btn-primary" type="submit">
@ -141,6 +206,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

@ -3,7 +3,7 @@
<form class="form-horizontal" method="post" role="form" action="{$_url}customers/edit-post">
<div class="row">
<div class="col-md-6">
<div class="panel panel-primary panel-hovered panel-stacked mb30">
<div class="panel panel-{if $d['status']=='Active'}primary{else}danger{/if} panel-hovered panel-stacked mb30">
<div class="panel-heading">{Lang::T('Edit Contact')}</div>
<div class="panel-body">
<input type="hidden" name="id" value="{$d['id']}">
@ -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,41 @@
</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 class="form-group">
<label class="col-md-3 control-label">{Lang::T('Status')}</label>
<div class="col-md-9">
<select class="form-control" id="status" name="status">
{foreach $statuses as $status}
<option value="{$status}" {if $d['status'] eq $status }selected{/if}>{Lang::T($status)}
</option>
{/foreach}
</select>
<span class="help-block">
{Lang::T('Banned')}: {Lang::T('Customer cannot login again')}.<br>
{Lang::T('Disabled')}: {Lang::T('Customer can login but cannot buy internet plan, Admin cannot recharge customer')}.<br>
{Lang::T('Don\'t forget to deactivate all active plan too')}.
</span>
</div>
</div>
</div>
</div>
</div>
@ -106,7 +142,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}
@ -123,6 +160,51 @@
</div>
</div>
</div>
<div class="col-md-6">
<div class="box box-primary box-solid collapsed-box">
<div class="box-header with-border">
<h3 class="box-title">{Lang::T('Additional Information')}</h3>
<div class="box-tools pull-right">
<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-plus"></i>
</button>
</div>
</div>
<div class="box-body" style="display: none;">
<div class="form-group">
<label class="col-md-3 control-label">{Lang::T('City')}</label>
<div class="col-md-9">
<input type="text" class="form-control" id="city" name="city"
value="{$d['city']}">
<small class="form-text text-muted">{Lang::T('City of Resident')}</small>
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">{Lang::T('District')}</label>
<div class="col-md-9">
<input type="text" class="form-control" id="district" name="district"
value="{$d['district']}">
<small class="form-text text-muted">{Lang::T('District')}</small>
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">{Lang::T('State')}</label>
<div class="col-md-9">
<input type="text" class="form-control" id="state" name="state"
value="{$d['state']}">
<small class="form-text text-muted">{Lang::T('State of Resident')}</small>
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">{Lang::T('Zip')}</label>
<div class="col-md-9">
<input type="text" class="form-control" id="zip" name="zip"
value="{$d['zip']}">
<small class="form-text text-muted">{Lang::T('Zip Code')}</small>
</div>
</div>
</div>
</div>
</div>
</div>
<center>
<button class="btn btn-primary" type="submit">
@ -164,6 +246,49 @@
});
});
</script>
{/literal}
{include file="sections/footer.tpl"}
<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

@ -2,15 +2,17 @@
<div class="row">
<div class="col-sm-4 col-md-4">
<div class="box box-primary">
<div class="box box-{if $d['status']=='Active'}primary{else}danger{/if}">
<div class="box-body box-profile">
<img class="profile-user-img img-responsive img-circle"
src="https://robohash.org/{$d['id']}?set=set3&size=100x100&bgset=bg1"
onerror="this.src='{$UPLOAD_PATH}/user.default.jpg'" alt="avatar">
<h3 class="profile-username text-center">{$d['fullname']}</h3>
<ul class="list-group list-group-unbordered">
<li class="list-group-item">
<b>{Lang::T('Status')}</b> <span
class="pull-right {if $d['status'] !='Active'}bg-red{/if}">&nbsp;{Lang::T($d['status'])}&nbsp;</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Username')}</b> <span class="pull-right">{$d['username']}</span>
</li>
@ -20,9 +22,19 @@
<li class="list-group-item">
<b>{Lang::T('Email')}</b> <span class="pull-right">{$d['email']}</span>
</li>
</ul>
<p class="text-muted">{Lang::nl2br($d['address'])}</p>
<ul class="list-group list-group-unbordered">
<li class="list-group-item">{Lang::nl2br($d['address'])}</li>
<li class="list-group-item">
<b>{Lang::T('City')}</b> <span class="pull-right">{Lang::T($d['city'])}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('District')}</b> <span class="pull-right">{Lang::T($d['district'])}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('State')}</b> <span class="pull-right">{Lang::T($d['state'])}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Zip')}</b> <span class="pull-right">{Lang::T($d['zip'])}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Password')}</b> <input type="password" value="{$d['password']}"
style=" border: 0px; text-align: right;" class="pull-right"
@ -30,31 +42,41 @@
onclick="this.select()">
</li>
{if $d['pppoe_password'] != ''}
<li class="list-group-item">
<b>PPPOE {Lang::T('Password')}</b> <input type="password" value="{$d['pppoe_password']}"
style=" border: 0px; text-align: right;" class="pull-right"
onmouseleave="this.type = 'password'" onmouseenter="this.type = 'text'"
onclick="this.select()">
</li>
<li class="list-group-item">
<b>PPPOE {Lang::T('Password')}</b> <input type="password" value="{$d['pppoe_password']}"
style=" border: 0px; text-align: right;" class="pull-right"
onmouseleave="this.type = 'password'" onmouseenter="this.type = 'text'"
onclick="this.select()">
</li>
{/if}
<!--Customers Attributes view start -->
{if $customFields}
{foreach $customFields as $customField}
<li class="list-group-item">
<b>{$customField.field_name}</b> <span class="pull-right">{$customField.field_value}</span>
</li>
{/foreach}
{foreach $customFields as $customField}
<li class="list-group-item">
<b>{$customField.field_name}</b> <span class="pull-right">
{if strpos($customField.field_value, ':0') === false}
{$customField.field_value}
{else}
<b>{Lang::T('Paid')}</b>
{/if}
</span>
</li>
{/foreach}
{/if}
<!--Customers Attributes view end -->
<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>
<li class="list-group-item">
<b>{Lang::T('Auto Renewal')}</b> <span class="pull-right">{if
$d['auto_renewal']}yes{else}no{/if}</span>
$d['auto_renewal']}yes{else}no
{/if}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Created On')}</b> <span
@ -64,6 +86,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">
@ -78,22 +110,26 @@
</div>
</div>
</div>
{if $package}
<div class="box box-{if $package['status']=='on'}success{else}danger{/if}">
<div class="box-body box-profile">
<h4 class="text-center">{$package['type']} - {$package['namebp']}</h4>
<ul class="list-group list-group-unbordered">
{foreach $packages as $package}
<div class="box box-{if $package['status']=='on'}success{else}danger{/if}">
<div class="box-body box-profile">
<h4 class="text-center">{$package['type']} - {$package['namebp']}</h4>
<ul class="list-group list-group-unbordered">
<li class="list-group-item">
{Lang::T('Active')} <span class="pull-right">{if
$package['status']=='on'}yes{else}no
{/if}</span>
</li>
<li class="list-group-item">
{Lang::T('Active')} <span class="pull-right">{if
$package['status']=='on'}yes{else}no{/if}</span>
{Lang::T('Type')} <span class="pull-right">
{if $package['prepaid'] eq yes}Prepaid{else}<b>Postpaid</b>{/if}</span>
</li>
<li class="list-group-item">
{Lang::T('Created On')} <span
class="pull-right">{Lang::dateAndTimeFormat($package['recharged_on'],$package['recharged_time'])}</span>
</li>
<li class="list-group-item">
{Lang::T('Expires On')} <span
class="pull-right">{Lang::dateAndTimeFormat($package['expiration'],
{Lang::T('Expires On')} <span class="pull-right">{Lang::dateAndTimeFormat($package['expiration'],
$package['time'])}</span>
</li>
<li class="list-group-item">
@ -102,28 +138,32 @@
</ul>
<div class="row">
<div class="col-xs-4">
<a href="{$_url}customers/deactivate/{$d['id']}" id="{$d['id']}"
<a href="{$_url}customers/deactivate/{$d['id']}/{$package['plan_id']}" id="{$d['id']}"
class="btn btn-danger btn-block btn-sm"
onclick="return confirm('This will deactivate Customer Plan, and make it expired')">{Lang::T('Deactivate')}</a>
</div>
<div class="col-xs-4">
<a href="{$_url}customers/recharge/{$d['id']}"
onclick="return confirm('This will extend Customer plan, same as recharge')"
<div class="col-xs-8">
<a href="{$_url}customers/recharge/{$d['id']}/{$package['plan_id']}"
class="btn btn-success btn-sm btn-block">{Lang::T('Recharge')}</a>
</div>
<div class="col-xs-4">
<a href="{$_url}customers/sync/{$d['id']}"
onclick="return confirm('This will sync Customer to Mikrotik?')"
class="btn btn-primary btn-sm btn-block">{Lang::T('Sync')}</a>
</div>
</div>
</div>
</div>
{else}
<a href="{$_url}prepaid/recharge/{$d['id']}"
class="btn btn-success btn-sm btn-block mt-1">{Lang::T('Recharge')}</a><br>
{/if}
<a href="{$_url}customers/list" class="btn btn-primary btn-sm btn-block mt-1">{Lang::T('Back')}</a><br>
{/foreach}
<div class="row">
<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-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">
<ul class="nav nav-tabs">
@ -135,73 +175,93 @@
<div class="table-responsive" style="background-color: white;">
<table id="datatable" class="table table-bordered table-striped">
{if Lang::arrayCount($activation)}
<thead>
<tr>
<th>{Lang::T('Invoice')}</th>
<th>{Lang::T('Username')}</th>
<th>{Lang::T('Plan Name')}</th>
<th>{Lang::T('Plan Price')}</th>
<th>{Lang::T('Type')}</th>
<th>{Lang::T('Created On')}</th>
<th>{Lang::T('Expires On')}</th>
<th>{Lang::T('Method')}</th>
</tr>
</thead>
<tbody>
{foreach $activation as $ds}
<tr onclick="window.location.href = '{$_url}prepaid/view/{$ds['id']}'" style="cursor:pointer;">
<td>{$ds['invoice']}</td>
<td>{$ds['username']}</td>
<td>{$ds['plan_name']}</td>
<td>{Lang::moneyFormat($ds['price'])}</td>
<td>{$ds['type']}</td>
<td class="text-success">{Lang::dateAndTimeFormat($ds['recharged_on'],$ds['recharged_time'])}
</td>
<td class="text-danger">{Lang::dateAndTimeFormat($ds['expiration'],$ds['time'])}</td>
<td>{$ds['method']}</td>
</tr>
{/foreach}
</tbody>
<thead>
<tr>
<th>{Lang::T('Invoice')}</th>
<th>{Lang::T('Username')}</th>
<th>{Lang::T('Plan Name')}</th>
<th>{Lang::T('Plan Price')}</th>
<th>{Lang::T('Type')}</th>
<th>{Lang::T('Created On')}</th>
<th>{Lang::T('Expires On')}</th>
<th>{Lang::T('Method')}</th>
</tr>
</thead>
<tbody>
{foreach $activation as $ds}
<tr onclick="window.location.href = '{$_url}plan/view/{$ds['id']}'" style="cursor:pointer;">
<td>{$ds['invoice']}</td>
<td>{$ds['username']}</td>
<td>{$ds['plan_name']}</td>
<td>{Lang::moneyFormat($ds['price'])}</td>
<td>{$ds['type']}</td>
<td class="text-success">{Lang::dateAndTimeFormat($ds['recharged_on'],$ds['recharged_time'])}
</td>
<td class="text-danger">{Lang::dateAndTimeFormat($ds['expiration'],$ds['time'])}</td>
<td>{$ds['method']}</td>
</tr>
{/foreach}
</tbody>
{/if}
{if Lang::arrayCount($order)}
<thead>
<tr>
<th>{Lang::T('Plan Name')}</th>
<th>{Lang::T('Gateway')}</th>
<th>{Lang::T('Routers')}</th>
<th>{Lang::T('Type')}</th>
<th>{Lang::T('Plan Price')}</th>
<th>{Lang::T('Created On')}</th>
<th>{Lang::T('Expires On')}</th>
<th>{Lang::T('Date Done')}</th>
<th>{Lang::T('Method')}</th>
</tr>
</thead>
<tbody>
{foreach $order as $ds}
<tr>
<td>{$ds['plan_name']}</td>
<td>{$ds['gateway']}</td>
<td>{$ds['routers']}</td>
<td>{$ds['payment_channel']}</td>
<td>{Lang::moneyFormat($ds['price'])}</td>
<td class="text-primary">{Lang::dateTimeFormat($ds['created_date'])}</td>
<td class="text-danger">{Lang::dateTimeFormat($ds['expired_date'])}</td>
<td class="text-success">{if $ds['status']!=1}{Lang::dateTimeFormat($ds['paid_date'])}{/if}</td>
<td>{if $ds['status']==1}{Lang::T('UNPAID')}
{elseif $ds['status']==2}{Lang::T('PAID')}
{elseif $ds['status']==3}{$_L['FAILED']}
{elseif $ds['status']==4}{Lang::T('CANCELED')}
{elseif $ds['status']==5}{Lang::T('UNKNOWN')}
{/if}</td>
</tr>
{/foreach}
</tbody>
<thead>
<tr>
<th>{Lang::T('Plan Name')}</th>
<th>{Lang::T('Gateway')}</th>
<th>{Lang::T('Routers')}</th>
<th>{Lang::T('Type')}</th>
<th>{Lang::T('Plan Price')}</th>
<th>{Lang::T('Created On')}</th>
<th>{Lang::T('Expires On')}</th>
<th>{Lang::T('Date Done')}</th>
<th>{Lang::T('Method')}</th>
</tr>
</thead>
<tbody>
{foreach $order as $ds}
<tr>
<td>{$ds['plan_name']}</td>
<td>{$ds['gateway']}</td>
<td>{$ds['routers']}</td>
<td>{$ds['payment_channel']}</td>
<td>{Lang::moneyFormat($ds['price'])}</td>
<td class="text-primary">{Lang::dateTimeFormat($ds['created_date'])}</td>
<td class="text-danger">{Lang::dateTimeFormat($ds['expired_date'])}</td>
<td class="text-success">{if $ds['status']!=1}{Lang::dateTimeFormat($ds['paid_date'])}{/if}</td>
<td>{if $ds['status']==1}{Lang::T('UNPAID')}
{elseif $ds['status']==2}{Lang::T('PAID')}
{elseif $ds['status']==3}{$_L['FAILED']}
{elseif $ds['status']==4}{Lang::T('CANCELED')}
{elseif $ds['status']==5}{Lang::T('UNKNOWN')}
{/if}</td>
</tr>
{/foreach}
</tbody>
{/if}
</table>
</div>
{$paginator['contents']}
{include file="pagination.tpl"}
</div>
</div>
{if $d['coordinates']}
{literal}
<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>
<script>
function setupMap(lat, lon) {
var map = L.map('map').setView([lat, lon], 17);
L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/light_all/{z}/{x}/{y}.png', {
attribution:
'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',
subdomains: 'abcd',
maxZoom: 20
}).addTo(map);
var marker = L.marker([lat, lon]).addTo(map);
}
window.onload = function() {
{/literal}setupMap({$d['coordinates']});{literal}
}
</script>
{/literal}
{/if}
{include file="sections/footer.tpl"}

View File

@ -1,4 +1,15 @@
{include file="sections/header.tpl"}
<style>
.dataTables_wrapper .dataTables_paginate .paginate_button {
display: inline-block;
padding: 5px 10px;
margin-right: 5px;
border: 1px solid #ccc;
background-color: #fff;
color: #333;
cursor: pointer;
}
</style>
<div class="row">
<div class="col-sm-12">
@ -14,58 +25,117 @@
{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="md-whiteframe-z1 mb20 text-center" style="padding: 15px">
<div class="col-lg-4">
<div class="input-group">
<input type="text" name="search" value="{$search}" class="form-control"
placeholder="{Lang::T('Search')}...">
<div class="input-group-btn">
<button class="btn btn-success" type="submit"><span
class="fa fa-search"></span></button>
<span class="input-group-addon">Order &nbsp;&nbsp;</span>
<div class="row row-no-gutters">
<div class="col-xs-8">
<select class="form-control" id="order" name="order">
<option value="username" {if $order eq 'username' }selected{/if}>{Lang::T('Username')}</option>
<option value="created_at" {if $order eq 'created_at' }selected{/if}>{Lang::T('Created Date')}</option>
<option value="balance" {if $order eq 'balance' }selected{/if}>{Lang::T('Balance')}</option>
<option value="status" {if $order eq 'status' }selected{/if}>{Lang::T('Status')}</option>
</select>
</div>
<div class="col-xs-4">
<select class="form-control" id="orderby" name="orderby">
<option value="asc" {if $orderby eq 'asc' }selected{/if}>{Lang::T('Ascending')}</option>
<option value="desc" {if $orderby eq 'desc' }selected{/if}>{Lang::T('Descending')}</option>
</select>
</div>
</div>
</div>
</form>
</div>
<div class="col-lg-3">
<div class="input-group">
<span class="input-group-addon">Status</span>
<select class="form-control" id="filter" name="filter">
{foreach $statuses as $status}
<option value="{$status}" {if $filter eq $status }selected{/if}>{Lang::T($status)}</option>
{/foreach}
</select>
</div>
</div>
<div class="col-lg-4">
<div class="input-group">
<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-primary" type="submit">{Lang::T('Query')}</button>
<button class="btn btn-primary" type="submit" name="export" value="csv">
<span class="glyphicon glyphicon-download"
aria-hidden="true"></span> CSV
</button>
</div>
</div>
</div>
<div class="col-lg-1">
<a href="{$_url}customers/add" class="btn btn-success text-black btn-block"><i
class="ion ion-android-add">
</i> {Lang::T('Add')}</a>
</div>
</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>
</div>&nbsp;
</div>
</form>
<br>&nbsp;
<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('Status')}</th>
<th>{Lang::T('Created On')}</th>
<th>{Lang::T('Manage')}</th>
</tr>
</thead>
<tbody>
{foreach $d as $ds}
<tr>
<tr {if $ds['status'] != 'Active'}class="danger"{/if}>
<td onclick="window.location.href = '{$_url}customers/view/{$ds['id']}'"
style="cursor:pointer;">{$ds['username']}</td>
<td>{$ds['account_type']}</td>
<td onclick="window.location.href = '{$_url}customers/view/{$ds['id']}'"
style="cursor: pointer;">{$ds['fullname']}</td>
<td>{Lang::moneyFormat($ds['balance'])}</td>
<td>{$ds['phonenumber']}</td>
<td>{$ds['email']}</td>
<td align="center">
{if $ds['phonenumber']}
<a href="tel:{$ds['phonenumber']}" class="btn btn-default btn-xs"
title="{$ds['phonenumber']}"><i class="glyphicon glyphicon-earphone"></i></a>
{/if}
{if $ds['email']}
<a href="mailto:{$ds['email']}" class="btn btn-default btn-xs"
title="{$ds['email']}"><i class="glyphicon glyphicon-envelope"></i></a>
{/if}
{if $ds['coordinates']}
<a href="https://www.google.com/maps/dir//{$ds['coordinates']}/" target="_blank"
class="btn btn-default btn-xs" title="{$ds['coordinates']}"><i
class="glyphicon glyphicon-map-marker"></i></a>
{/if}
</td>
<td align="center" api-get-text="{$_url}autoload/customer_is_active/{$ds['id']}">
<span class="label label-default">&bull;</span>
</td>
<td>{$ds['service_type']}</td>
<td>{Lang::T($ds['status'])}</td>
<td>{Lang::dateTimeFormat($ds['created_at'])}</td>
<td align="center">
<a href="{$_url}customers/view/{$ds['id']}" id="{$ds['id']}" style="margin: 0px;"
<a href="{$_url}customers/view/{$ds['id']}" id="{$ds['id']}"
style="margin: 0px; color:black"
class="btn btn-success btn-xs">&nbsp;&nbsp;{Lang::T('View')}&nbsp;&nbsp;</a>
<a href="{$_url}prepaid/recharge/{$ds['id']}" id="{$ds['id']}" style="margin: 0px;"
<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>
@ -73,10 +143,27 @@
</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>
var $j = jQuery.noConflict();
$j(document).ready(function() {
$j('#customerTable').DataTable({
order: [[{$order_pos}, '{$orderby}']],
"pagingType": "full_numbers",
"lengthMenu": [
[5, 10, 25, 50, 100, -1],
[5, 10, 25, 50, 100, "All"]
],
"pageLength": 25
});
});
</script>
{include file="sections/footer.tpl"}

View File

@ -41,7 +41,7 @@
<div class="icon">
<i class="ion ion-person"></i>
</div>
<a href="{$_url}prepaid/list" class="small-box-footer">{Lang::T('View All')} <i
<a href="{$_url}plan/list" class="small-box-footer">{Lang::T('View All')} <i
class="fa fa-arrow-circle-right"></i></a>
</div>
</div>
@ -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}
{/foreach}
</tbody>
</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

@ -5,7 +5,8 @@
<div class="panel panel-primary panel-hovered panel-stacked mb30">
<div class="panel-heading">{Lang::T('Refill Balance')}</div>
<div class="panel-body">
<form class="form-horizontal" method="post" role="form" action="{$_url}prepaid/deposit-post">
<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

@ -5,7 +5,7 @@
<div class="panel panel-hovered panel-primary panel-stacked mb30">
<div class="panel-heading">{$in['invoice']}</div>
<div class="panel-body">
<form class="form-horizontal" method="post" action="{$_url}prepaid/print" target="_blank">
<form class="form-horizontal" method="post" action="{$_url}plan/print" target="_blank">
<pre id="content">{$invoice}</pre>
<input type="hidden" name="id" value="{$in['id']}">
<a href="{$_url}voucher/list-activated" class="btn btn-default btn-sm"><i

View File

@ -5,16 +5,16 @@
<div class="panel panel-hovered panel-primary panel-stacked mb30">
<div class="panel-heading">{$in['invoice']}</div>
<div class="panel-body">
<form class="form-horizontal" method="post" action="{$_url}prepaid/print" target="_blank">
<form class="form-horizontal" method="post" action="{$_url}plan/print" target="_blank">
<pre id="content"></pre>
<textarea class="hidden" id="formcontent" name="content">{$invoice}</textarea>
<input type="hidden" name="id" value="{$in['id']}">
<a href="{$_url}prepaid/list" class="btn btn-default btn-sm"><i
<a href="{$_url}plan/list" class="btn btn-default btn-sm"><i
class="ion-reply-all"></i>{Lang::T('Finish')}</a>
<a href="https://api.whatsapp.com/send/?text={$whatsapp}" target="_blank"
class="btn btn-primary btn-sm">
<i class="glyphicon glyphicon-share"></i> WhatsApp</a>
<a href="{$_url}prepaid/view/{$in['id']}/send" class="btn btn-info text-black btn-sm"><i
<a href="{$_url}plan/view/{$in['id']}/send" class="btn btn-info text-black btn-sm"><i
class="glyphicon glyphicon-envelope"></i> {Lang::T("Resend")}</a>
<button type="submit" class="btn btn-info text-black btn-sm"><i class="glyphicon glyphicon-print"></i>
Print</button>

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

@ -0,0 +1,96 @@
{include file="sections/header.tpl"}
<style>
/* Checkbox container */
.switch {
position: relative;
display: inline-block;
width: 50px;
height: 24px;
}
/* Hidden checkbox */
.switch input {
opacity: 0;
width: 0;
height: 0;
}
/* Slider */
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
border-radius: 24px;
}
.slider:before {
position: absolute;
content: "";
height: 18px;
width: 18px;
left: 3px;
bottom: 3px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
border-radius: 50%;
}
input:checked+.slider {
background-color: #2196F3;
}
input:focus+.slider {
box-shadow: 0 0 1px #2196F3;
}
input:checked+.slider:before {
-webkit-transform: translateX(26px);
-ms-transform: translateX(26px);
transform: translateX(26px);
}
</style>
<form class="form-horizontal" method="post" autocomplete="off" role="form" action="">
<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('Maintenance Mode')}</div>
<div class="panel-body">
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Status:')}</label>
<div class="col-md-6">
<label class="switch">
<input type="checkbox" id="maintenance_mode" value="1" name="maintenance_mode" {if
$_c['maintenance_mode']==1}checked{/if}>
<span class="slider"></span>
</label>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('End Date:')}</label>
<div class="col-md-6">
<input class="form-control" value="{$_c['maintenance_date']}" type="date" id="start_date"
name="maintenance_date">
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<button class="btn btn-primary waves-effect waves-light" name="save" value="save"
type="submit">{Lang::T('Save')}</button>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
{include file="sections/footer.tpl"}

212
ui/ui/maintenance.tpl Normal file
View File

@ -0,0 +1,212 @@
<!DOCTYPE html>
<html>
<head>
<title>Site is down for maintenance</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
body {
font-family: 'Noto Sans', sans-serif;
color: #616161
/*#757575*/
;
background-color: #eeeeee;
}
.container {
margin: auto;
max-width: 1024px;
width: 100%;
height: 100%;
text-align: center;
position: relative;
}
.box {
width: auto;
height: 500px;
background: #fff;
margin-top: 50px;
margin-left: 100px;
margin-right: 100px;
border-radius: 5px;
box-shadow: 6px 18px 18px rgba(0, 0, 0, 0.08), -6px 18px 18px rgba(0, 0, 0, 0.08);
}
.animation {
margin-top: 20%;
display: inline-block;
margin-bottom: 5%;
}
h1 {
font-size: 32px;
font-weight: 400;
text-transform: uppercase;
margin: 0;
}
p {
font-size: 16px;
font-weight: 700;
margin: 0;
}
a {
color: #f6921e;
font-weight: bold;
text-decoration: none;
margin-left: 5px;
}
.one,
.two,
.three {
display: block;
float: left;
}
.one {
background: url('data:image/svg+xml,%3Csvg%20version%3D%221.1%22%0A%09%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20xmlns%3Aa%3D%22http%3A%2F%2Fns.adobe.com%2FAdobeSVGViewerExtensions%2F3.0%2F%22%0A%09%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2281px%22%20height%3D%2280.5px%22%20viewBox%3D%220%200%2081%2080.5%22%20style%3D%22overflow%3Ascroll%3Benable-background%3Anew%200%200%2081%2080.5%3B%22%0A%09%20xml%3Aspace%3D%22preserve%22%3E%0A%3Cstyle%20type%3D%22text%2Fcss%22%3E%0A%09.st0%7Bfill%3A%23383838%3B%7D%0A%3C%2Fstyle%3E%0A%3Cdefs%3E%0A%3C%2Fdefs%3E%0A%3Cpath%20class%3D%22st0%22%20d%3D%22M30.3%2C68.2c1.2%2C0.2%2C2.3%2C0.9%2C3.8%2C1.2c1.6%2C0.3%2C2.7%2C0.6%2C4%2C0.4l4.9%2C9.6c0.6%2C0.9%2C1.4%2C1.1%2C2.3%2C0.9l15.3-4.9%0A%09c0.5-0.3%2C1-1%2C0.9-2.3l-1.8-10.6c2-1.6%2C3.6-3.7%2C5.3-5.8l10.5%2C0.6c1.1%2C0.6%2C2.1-0.4%2C2.3-1.1L81%2C40.7c0.2-0.8-0.4-2.1-1.1-2.3l-10.2-3.8%0A%09c-0.3-2.5-1.4-4.8-2.5-7.5l5.9-8.5c0.6-1.1%2C0.4-1.9-0.2-2.9l-12-10.7c-0.3-0.5-1.6-0.3-2.5%2C0.3l-8%2C6.9c-1.2-0.2-2.3-0.9-3.8-1.2%0A%09c-1.6-0.3-2.7-0.6-4-0.4L37.7%2C1c-0.6-0.9-1.4-1.1-2.3-0.9L20.1%2C5c-0.5%2C0.3-1%2C1-0.9%2C2.3l1.8%2C10.6c-2%2C1.6-3.6%2C3.7-5.3%2C5.8L5.3%2C23%0A%09c-0.8-0.2-1.7%2C0.4-2%2C1.6L0%2C40.2c-0.2%2C0.8%2C0.4%2C2.1%2C1.1%2C2.3l9.8%2C3.7c0.7%2C2.6%2C1.4%2C5.2%2C2.5%2C7.5l-6%2C8.9c-0.6%2C0.7-0.4%2C2%2C0.3%2C2.5l12%2C10.7%0A%09c0.7%2C0.5%2C1.9%2C0.8%2C2.4%2C0.1L30.3%2C68.2z%20M26.7%2C37.3c1.6-7.4%2C9.1-12.3%2C16.5-10.8S55.6%2C35.7%2C54%2C43.1c-1.6%2C7.4-9.1%2C12.3-16.5%2C10.7%0A%09C30.1%2C52.3%2C25.1%2C44.7%2C26.7%2C37.3L26.7%2C37.3z%22%2F%3E%0A%3C%2Fsvg%3E');
width: 80px;
height: 80px;
background-size: 100% 100%;
background-repeat: no-repeat;
margin-top: -10px;
margin-right: 8px;
}
.two {
background: url('data:image/svg+xml,%3Csvg%20version%3D%221.1%22%0A%09%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20xmlns%3Aa%3D%22http%3A%2F%2Fns.adobe.com%2FAdobeSVGViewerExtensions%2F3.0%2F%22%0A%09%20x%3D%220px%22%20y%3D%220px%22%20width%3D%22103px%22%20height%3D%22103.7px%22%20viewBox%3D%220%200%20103%20103.7%22%0A%09%20style%3D%22overflow%3Ascroll%3Benable-background%3Anew%200%200%20103%20103.7%3B%22%20xml%3Aspace%3D%22preserve%22%3E%0A%3Cstyle%20type%3D%22text%2Fcss%22%3E%0A%09.st0%7Bfill%3A%23F6921E%3B%7D%0A%3C%2Fstyle%3E%0A%3Cdefs%3E%0A%3C%2Fdefs%3E%0A%3Cpath%20class%3D%22st0%22%20d%3D%22M87.3%2C64.8c0.3-1.5%2C1.1-2.9%2C1.6-4.9c0.4-2%2C0.7-3.5%2C0.5-5.1l12.3-6.3c1.2-0.8%2C1.4-1.8%2C1.1-2.9l-6.3-19.6%0A%09c-0.4-0.6-1.3-1.3-2.9-1.1l-13.5%2C2.3c-2.1-2.5-4.7-4.7-7.4-6.8l0.8-13.4C74.3%2C5.8%2C73%2C4.5%2C72%2C4.3L52.1%2C0c-1-0.2-2.7%2C0.5-2.9%2C1.5%0A%09l-4.8%2C13c-3.2%2C0.4-6.1%2C1.8-9.5%2C3.2l-10.9-7.5c-1.4-0.8-2.5-0.5-3.7%2C0.3L6.5%2C25.8c-0.6%2C0.4-0.4%2C2%2C0.4%2C3.2l8.8%2C10.2%0A%09c-0.3%2C1.5-1.1%2C2.9-1.5%2C4.9c-0.4%2C2-0.7%2C3.5-0.6%2C5.1L1.2%2C55.4c-1.2%2C0.8-1.4%2C1.8-1.1%2C2.9l6.3%2C19.6c0.4%2C0.6%2C1.3%2C1.3%2C2.9%2C1.1l13.5-2.3%0A%09c2.1%2C2.5%2C4.7%2C4.7%2C7.4%2C6.8l-0.8%2C13.4c-0.2%2C1%2C0.6%2C2.2%2C2.1%2C2.5l20%2C4.2c1%2C0.2%2C2.7-0.5%2C2.9-1.5l4.7-12.6c3.3-0.9%2C6.6-1.7%2C9.5-3.2L80.1%2C94%0A%09c0.9%2C0.7%2C2.5%2C0.5%2C3.2-0.4L97%2C78.3c0.7-0.9%2C1-2.4%2C0.1-3.1L87.3%2C64.8z%20M47.8%2C69.5C38.3%2C67.5%2C32%2C57.8%2C34%2C48.3%0A%09c2-9.5%2C11.7-15.8%2C21.2-13.8c9.5%2C2%2C15.7%2C11.7%2C13.7%2C21.2C66.9%2C65.2%2C57.3%2C71.5%2C47.8%2C69.5L47.8%2C69.5z%22%2F%3E%0A%3C%2Fsvg%3E');
width: 100px;
height: 100px;
background-size: 100% 100%;
background-repeat: no-repeat;
}
.three {
background: url('data:image/svg+xml,%3Csvg%20version%3D%221.1%22%0A%09%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20xmlns%3Aa%3D%22http%3A%2F%2Fns.adobe.com%2FAdobeSVGViewerExtensions%2F3.0%2F%22%0A%09%20x%3D%220px%22%20y%3D%220px%22%20width%3D%2281px%22%20height%3D%2280.5px%22%20viewBox%3D%220%200%2081%2080.5%22%20style%3D%22overflow%3Ascroll%3Benable-background%3Anew%200%200%2081%2080.5%3B%22%0A%09%20xml%3Aspace%3D%22preserve%22%3E%0A%3Cstyle%20type%3D%22text%2Fcss%22%3E%0A%09.st0%7Bfill%3A%23383838%3B%7D%0A%3C%2Fstyle%3E%0A%3Cdefs%3E%0A%3C%2Fdefs%3E%0A%3Cpath%20class%3D%22st0%22%20d%3D%22M30.3%2C68.2c1.2%2C0.2%2C2.3%2C0.9%2C3.8%2C1.2c1.6%2C0.3%2C2.7%2C0.6%2C4%2C0.4l4.9%2C9.6c0.6%2C0.9%2C1.4%2C1.1%2C2.3%2C0.9l15.3-4.9%0A%09c0.5-0.3%2C1-1%2C0.9-2.3l-1.8-10.6c2-1.6%2C3.6-3.7%2C5.3-5.8l10.5%2C0.6c1.1%2C0.6%2C2.1-0.4%2C2.3-1.1L81%2C40.7c0.2-0.8-0.4-2.1-1.1-2.3l-10.2-3.8%0A%09c-0.3-2.5-1.4-4.8-2.5-7.5l5.9-8.5c0.6-1.1%2C0.4-1.9-0.2-2.9l-12-10.7c-0.3-0.5-1.6-0.3-2.5%2C0.3l-8%2C6.9c-1.2-0.2-2.3-0.9-3.8-1.2%0A%09c-1.6-0.3-2.7-0.6-4-0.4L37.7%2C1c-0.6-0.9-1.4-1.1-2.3-0.9L20.1%2C5c-0.5%2C0.3-1%2C1-0.9%2C2.3l1.8%2C10.6c-2%2C1.6-3.6%2C3.7-5.3%2C5.8L5.3%2C23%0A%09c-0.8-0.2-1.7%2C0.4-2%2C1.6L0%2C40.2c-0.2%2C0.8%2C0.4%2C2.1%2C1.1%2C2.3l9.8%2C3.7c0.7%2C2.6%2C1.4%2C5.2%2C2.5%2C7.5l-6%2C8.9c-0.6%2C0.7-0.4%2C2%2C0.3%2C2.5l12%2C10.7%0A%09c0.7%2C0.5%2C1.9%2C0.8%2C2.4%2C0.1L30.3%2C68.2z%20M26.7%2C37.3c1.6-7.4%2C9.1-12.3%2C16.5-10.8S55.6%2C35.7%2C54%2C43.1c-1.6%2C7.4-9.1%2C12.3-16.5%2C10.7%0A%09C30.1%2C52.3%2C25.1%2C44.7%2C26.7%2C37.3L26.7%2C37.3z%22%2F%3E%0A%3C%2Fsvg%3E');
width: 80px;
height: 80px;
background-size: 100% 100%;
background-repeat: no-repeat;
margin-top: -50px;
margin-left: -10px;
}
@keyframes spin-one {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(-359deg);
transform: rotate(-359deg);
}
}
.spin-one {
-webkit-animation: spin-one 1.5s infinite linear;
animation: spin-one 1.5s infinite linear;
}
@keyframes spin-two {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(-359deg);
transform: rotate(359deg);
}
}
.spin-two {
-webkit-animation: spin-two 2s infinite linear;
animation: spin-two 2s infinite linear;
}
.day,
.hour,
.minute,
.second {
font-size: 18px;
background: #333;
color: #fff;
padding: 10px;
border-radius: 5px;
margin: 5px;
}
.day {
background-color: #1abc9c;
}
.hour {
background-color: #3498db;
}
.minute {
background-color: #f1c40f;
}
.second {
background-color: #e74c3c;
}
</style>
</head>
<body>
<!-- partial:index.partial.html -->
<link href="https://fonts.googleapis.com/css?family=Noto+Sans:400,700" rel="stylesheet">
<div class="container">
<div class="box">
<div class="animation">
<div class="one spin-one"></div>
<div class="two spin-two"></div>
<div class="three spin-one"></div>
</div>
<h1>{Lang::T('Site is temporarily unavailable.')}</h1>
<p>{Lang::T('Scheduled maintenance is currently in progress. Please check back soon.')}</p>
<p>{Lang::T('We apologize for any inconvenience.')} <br>
&mdash; {Lang::T('The')} {$companyName} {Lang::T('Team')}.
</p>
<br>
{if $date} <div style="display: flex; flex-direction: row; justify-content: space-between;">
<p class="day"></p>
<p class="hour"></p>
<p class="minute"></p>
<p class="second"></p>
</div>
{/if}
</div>
</div>
{if $date}
<script>
const countDown = () => {
const countDay = new Date('{$date}');
const now = new Date();
const counter = countDay - now;
const second = 1000;
const minute = second * 60;
const hour = minute * 60;
const day = hour * 24;
const textDay = Math.floor(counter / day);
const textHour = Math.floor((counter % day) / hour);
const textMinute = Math.floor((counter % hour) / minute);
const textSecond = Math.floor((counter % minute) / second)
document.querySelector(".day").innerText = textDay + ' Days';
document.querySelector(".hour").innerText = textHour + ' Hours';
document.querySelector(".minute").innerText = textMinute + ' Minutes';
document.querySelector(".second").innerText = textSecond + ' Seconds';
}
setInterval(countDown, 1000);
</script>
{/if}
</body>
</html>

142
ui/ui/message-bulk.tpl Normal file
View File

@ -0,0 +1,142 @@
{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" id="bulkMessageForm" action="">
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Group')}</label>
<div class="col-md-6">
<select class="form-control" name="group" id="group">
<option value="all" selected>{Lang::T('All Customers')}</option>
<option value="new">{Lang::T('New Customers')}</option>
<option value="expired">{Lang::T('Expired Customers')}</option>
<option value="active">{Lang::T('Active Customers')}</option>
</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 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>
<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>[[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" 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"}

64
ui/ui/message.tpl Normal file
View File

@ -0,0 +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 {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 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"}

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

@ -7,7 +7,7 @@
<h3 class="panel-title">Edit Plan</h3>
</div>
<div class="panel-body">
<form class="form-horizontal" method="post" role="form" action="{$_url}prepaid/edit-post">
<form class="form-horizontal" method="post" role="form" action="{$_url}plan/edit-post">
<input type="hidden" name="id" value="{$d['id']}">
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Select Account')}</label>
@ -56,7 +56,7 @@
<div class="col-lg-offset-2 col-lg-10">
<button class="btn btn-success"
type="submit">{Lang::T('Edit')}</button>
Or <a href="{$_url}prepaid/list">{Lang::T('Cancel')}</a>
Or <a href="{$_url}plan/list">{Lang::T('Cancel')}</a>
</div>
</div>
</form>

View File

@ -6,12 +6,12 @@
<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}prepaid/sync"
<a class="btn btn-primary btn-xs" title="save" href="{$_url}plan/sync"
onclick="return confirm('This will sync/send Caustomer active plan to Mikrotik?')"><span
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>
@ -21,7 +21,7 @@
<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}prepaid/list/">
<form id="site-search" method="post" action="{$_url}plan/list/">
<div class="input-group">
<div class="input-group-addon">
<span class="fa fa-search"></span>
@ -35,7 +35,7 @@
</form>
</div>
<div class="col-md-4">
<a href="{$_url}prepaid/recharge" class="btn btn-primary btn-block"><i
<a href="{$_url}plan/recharge" class="btn btn-primary btn-block"><i
class="ion ion-android-add"> </i> {Lang::T('Recharge Account')}</a>
</div>&nbsp;
</div>
@ -64,24 +64,38 @@
<td>{$ds['method']}</td>
<td>{$ds['routers']}</td>
<td>
<a href="{$_url}prepaid/edit/{$ds['id']}"
class="btn btn-warning btn-xs">{Lang::T('Edit')}</a>
<a href="{$_url}plan/edit/{$ds['id']}"
class="btn btn-warning btn-xs" style="color: black;">{Lang::T('Edit')}</a>
{if in_array($_admin['user_type'],['SuperAdmin','Admin'])}
<a href="{$_url}prepaid/delete/{$ds['id']}" id="{$ds['id']}"
<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

@ -60,7 +60,7 @@
<body>
<page size="A4">
<form method="post" action="{$_url}prepaid/print-voucher/" class="no-print">
<form method="post" action="{$_url}plan/print-voucher/" class="no-print">
<table width="100%" border="0" cellspacing="0" cellpadding="1" class="btn btn-default btn-sm">
<tr>
<td>From ID &gt; <input type="text" name="from_id" style="width:40px" value="{$from_id}"> limit

View File

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

View File

@ -5,90 +5,95 @@
<div class="panel panel-primary panel-hovered panel-stacked mb30">
<div class="panel-heading">{Lang::T('Confirm')}</div>
<div class="panel-body">
<center><b>{Lang::T('Customer')}</b></center>
<ul class="list-group list-group-unbordered">
<li class="list-group-item">
<b>{Lang::T('Username')}</b> <span class="pull-right">{$cust['username']}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Name')}</b> <span class="pull-right">{$cust['fullname']}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Phone Number')}</b> <span class="pull-right">{$cust['phonenumber']}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Email')}</b> <span class="pull-right">{$cust['email']}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Address')}</b> <span class="pull-right">{$cust['address']}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Balance')}</b> <span
class="pull-right">{Lang::moneyFormat($cust['balance'])}</span>
</li>
</ul>
<center><b>{Lang::T('Plan')}</b></center>
<ul class="list-group list-group-unbordered">
<li class="list-group-item">
<b>{Lang::T('Plan Name')}</b> <span class="pull-right">{$plan['name_plan']}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Location')}</b> <span
class="pull-right">{if $plan['is_radius']}Radius{else}{$plan['routers']}{/if}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Type')}</b> <span
class="pull-right">{if $plan['prepaid'] eq 'yes'}Prepaid{else}Postpaid{/if}
{$plan['type']}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Plan Price')}</b> <span
class="pull-right">{if $using eq 'zero'}{Lang::moneyFormat(0)}{else}{Lang::moneyFormat($plan['price'])}{/if}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Plan Validity')}</b> <span class="pull-right">{$plan['validity']}
{$plan['validity_unit']}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Using')}</b> <span class="pull-right">{ucwords($using)}</span>
</li>
</ul>
<center><b>{Lang::T('Total')}</b></center>
<ul class="list-group list-group-unbordered">
{if $add_rem != 0 and $using neq 'zero' and $add_cost>0}
{foreach $bills as $k => $v}
<li class="list-group-item">
<b>{$k}</b> <span class="pull-right">{Lang::moneyFormat($v)}</span>
</li>
{/foreach}
<form class="form-horizontal" method="post" role="form" action="{$_url}plan/recharge-post">
<center><b>{Lang::T('Customer')}</b></center>
<ul class="list-group list-group-unbordered">
<li class="list-group-item">
<b>{Lang::T('Additional Cost')}</b> <span
class="pull-right">{Lang::moneyFormat($add_cost)}</span>
<b>{Lang::T('Username')}</b> <span class="pull-right">{$cust['username']}</span>
</li>
{if $add_rem != ''}
<li class="list-group-item">
<b>{Lang::T('Name')}</b> <span class="pull-right">{$cust['fullname']}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Phone Number')}</b> <span class="pull-right">{$cust['phonenumber']}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Email')}</b> <span class="pull-right">{$cust['email']}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Address')}</b> <span class="pull-right">{$cust['address']}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Balance')}</b> <span
class="pull-right">{Lang::moneyFormat($cust['balance'])}</span>
</li>
</ul>
<center><b>{Lang::T('Plan')}</b></center>
<ul class="list-group list-group-unbordered">
<li class="list-group-item">
<b>{Lang::T('Plan Name')}</b> <span class="pull-right">{$plan['name_plan']}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Location')}</b> <span
class="pull-right">{if $plan['is_radius']}Radius{else}{$plan['routers']}{/if}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Type')}</b> <span
class="pull-right">{if $plan['prepaid'] eq 'yes'}Prepaid{else}Postpaid{/if}
{$plan['type']}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Plan Price')}</b> <span
class="pull-right">{if $using eq 'zero'}{Lang::moneyFormat(0)}{else}{Lang::moneyFormat($plan['price'])}{/if}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Plan Validity')}</b> <span class="pull-right">{$plan['validity']}
{$plan['validity_unit']}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Using')}</b> <span class="pull-right">
<select name="using" style="background-color: white;outline: 1px;border: 1px solid #b7b7b7;">
{foreach $usings as $us}
<option value="{trim($us)}" {if $using eq trim($us)}selected{/if}>{trim(ucWords($us))}</option>
{/foreach}
{if $_c['enable_balance'] eq 'yes'}
<option value="balance" {if $using eq 'balance'}selected{/if}>{Lang::T('Customer Balance')}</option>
{/if}
<option value="zero" {if $using eq 'zero'}selected{/if}>{$_c['currency_code']} 0</option>
</select>
</span>
</li>
</ul>
<center><b>{Lang::T('Total')}</b></center>
<ul class="list-group list-group-unbordered">
{if $using neq 'zero' and $add_cost>0}
{foreach $bills as $k => $v}
<li class="list-group-item">
<b>{$k}</b> <span class="pull-right">{Lang::moneyFormat($v)}</span>
</li>
{/foreach}
<li class="list-group-item">
<b>{Lang::T('Remaining')}</b> <span class="pull-right">{$add_rem}</span>
<b>{Lang::T('Additional Cost')}</b> <span
class="pull-right">{Lang::moneyFormat($add_cost)}</span>
</li>
<li class="list-group-item">
<b>{Lang::T('Total')}</b> <small>({Lang::T('Plan Price')} +{Lang::T('Additional Cost')})</small><span class="pull-right"
style="font-size: large; font-weight:bolder; font-family: 'Courier New', Courier, monospace; ">{Lang::moneyFormat($plan['price']+$add_cost)}</span>
</li>
{else}
<li class="list-group-item">
<b>{Lang::T('Total')}</b> <span class="pull-right"
style="font-size: large; font-weight:bolder; font-family: 'Courier New', Courier, monospace; ">{if $using eq 'zero'}{Lang::moneyFormat(0)}{else}{Lang::moneyFormat($plan['price'])}{/if}</span>
</li>
{/if}
<li class="list-group-item">
<b>{Lang::T('Total')}</b> <small>({Lang::T('Plan Price')} +{Lang::T('Additional Cost')})</small><span class="pull-right"
style="font-size: large; font-weight:bolder; font-family: 'Courier New', Courier, monospace; ">{Lang::moneyFormat($plan['price']+$add_cost)}</span>
</li>
{else}
<li class="list-group-item">
<b>{Lang::T('Total')}</b> <span class="pull-right"
style="font-size: large; font-weight:bolder; font-family: 'Courier New', Courier, monospace; ">{if $using eq 'zero'}{Lang::moneyFormat(0)}{else}{Lang::moneyFormat($plan['price'])}{/if}</span>
</li>
{/if}
</ul>
<form class="form-horizontal" method="post" role="form" action="{$_url}prepaid/recharge-post">
</ul>
<input type="hidden" name="id_customer" value="{$cust['id']}">
<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}prepaid/recharge">{Lang::T('Cancel')}</a>
<a class="btn btn-link" href="{$_url}plan/recharge">{Lang::T('Cancel')}</a>
</center>
</form>
</div>

View File

@ -5,7 +5,7 @@
<div class="panel panel-primary panel-hovered panel-stacked mb30">
<div class="panel-heading">{Lang::T('Recharge Account')}</div>
<div class="panel-body">
<form class="form-horizontal" method="post" role="form" action="{$_url}prepaid/recharge-confirm">
<form class="form-horizontal" method="post" role="form" action="{$_url}plan/recharge-confirm">
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Select Account')}</label>
<div class="col-md-6">
@ -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($using)}">{trim(ucWords($using))}</option>
{/foreach}
{if $_c['enable_balance'] eq 'yes'}
<option value="balance">{Lang::T('Customer Balance')}</option>
{/if}

View File

@ -5,7 +5,7 @@
<div class="panel panel-primary panel-hovered panel-stacked mb30">
<div class="panel-heading">{Lang::T('Refill Account')}</div>
<div class="panel-body">
<form class="form-horizontal" method="post" role="form" action="{$_url}prepaid/refill-post">
<form class="form-horizontal" method="post" role="form" action="{$_url}plan/refill-post">
<div class="form-group">
<label class="col-md-2 control-label">{Lang::T('Select Account')}</label>
<div class="col-md-6">

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

@ -44,7 +44,7 @@
<tbody>
{foreach $activation as $ds}
<tr>
<td onclick="window.location.href = '{$_url}prepaid/view/{$ds['id']}'"
<td onclick="window.location.href = '{$_url}plan/view/{$ds['id']}'"
style="cursor:pointer;">{$ds['invoice']}</td>
<td onclick="window.location.href = '{$_url}customers/viewu/{$ds['username']}'"
style="cursor:pointer;">{$ds['username']}</td>
@ -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

@ -54,17 +54,18 @@
<li>Make sure your hosting not blocking port to external</li>
<li>Make sure your Mikrotik accessible from PHPNuxBill</li>
</ul>
If you just update PHPNuxBill from upload files, try click Update Database
</div>
<div class="box-footer">
<div class="btn-group btn-group-justified" role="group" aria-label="...">
<a href="./update.php?step=4" class="btn btn-info btn-sm btn-block">Update Database</a>
<a href="{$_url}community#update" class="btn btn-success btn-sm btn-block">Update
<a href="./update.php?step=4" style="color: black;" class="btn btn-info btn-sm btn-block">Update Database</a>
<a href="{$_url}community#update" style="color: black;" class="btn btn-success btn-sm btn-block">Update
PHPNuxBill</a>
</div>
<br>
<div class="btn-group btn-group-justified" role="group" aria-label="...">
<a href="https://github.com/hotspotbilling/phpnuxbill/discussions" target="_blank"
class="btn btn-success btn-sm btn-block">Ask Github Community</a>
class="btn btn-success btn-sm btn-block" style="color: black;">Ask Github Community</a>
<a href="https://t.me/phpnuxbill" target="_blank"
class="btn btn-primary btn-sm btn-block">Ask Telegram Community</a>
</div>

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>

Some files were not shown because too many files have changed in this diff Show More