Compare commits

...

317 Commits

Author SHA1 Message Date
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
68d3c9181c View Invoice from Customer side 2024-03-14 13:40:44 +07:00
e206a583fd Additional Cost, and Confirm Recharge 2024-03-14 12:14:11 +07:00
ca27c47b75 fix get attributes 2024-03-14 11:38:32 +07:00
2c67108cf1 add Additional Cycle and check if price is zero 2024-03-14 10:28:36 +07:00
dee4c78e93 Change Menu Names 2024-03-13 16:59:12 +07:00
a6c004e1cb $day_exp 2024-03-13 16:33:06 +07:00
8318bb4e6b Merge branch 'Development' 2024-03-13 16:29:44 +07:00
b27e0adca9 Fix onclick prepaid 2024-03-13 16:29:22 +07:00
2925d3a1e3 Merge branch 'Development' 2024-03-13 15:51:23 +07:00
add28c2fca Merge pull request #124 from Focuslinkstech/Development
Update dashboard.php
2024-03-13 15:41:57 +07:00
afbab3dd42 Update dashboard.php
fix reporting
2024-03-13 09:34:57 +01:00
b68e4d2e68 2024.3.13 2024-03-13 14:54:36 +07:00
c8f4574984 Recharge with additional Cost 2024-03-13 14:53:33 +07:00
60c573821b Additional Cost from Customer Attributes 2024-03-13 14:48:01 +07:00
e6e993cf21 Expired day postpaid 2024-03-13 14:40:47 +07:00
ca0edb4e17 Postpaid 2024-03-13 14:32:10 +07:00
ed9a411095 Fix install Plugin 2024-03-13 09:37:45 +07:00
c69fb1cae2 Merge branch 'Development' 2024-03-12 16:40:58 +07:00
d30aadc5e4 Expired Date by created date 2024-03-12 16:39:01 +07:00
b732cfd90e Recharge with balance or zero cost 2024-03-12 16:39:01 +07:00
46a56c12e3 admin can recharge disabled plan 2024-03-12 16:39:01 +07:00
9b2d42610a delete allow_purchase in cron 2024-03-12 16:39:01 +07:00
ef85bdb02f Invoice number not Random 2024-03-12 16:39:01 +07:00
23763ed308 Period in hotspot 2024-03-12 16:39:00 +07:00
9fcdf04005 Show From Customer 2024-03-12 16:39:00 +07:00
60babfa7b5 Change button 2024-03-12 16:39:00 +07:00
4cdde32cb1 Multiple Payment gateway Fix 2024-03-12 16:39:00 +07:00
538850b323 delete button 2024-03-12 16:39:00 +07:00
47393b4da9 Delete Plugin 2024-03-12 16:39:00 +07:00
87167b7770 change path 2024-03-12 16:39:00 +07:00
81572a61a4 delete payment gateway 2024-03-12 16:39:00 +07:00
3412ecc7de Fix Logic Multiple Payment gateway 2024-03-12 16:39:00 +07:00
3ab38897f9 change path to /gateway/ 2024-03-12 16:39:00 +07:00
8c2471d1d2 delete none 2024-03-12 16:39:00 +07:00
b0937a424a .htaccess Firewall 2024-03-12 16:39:00 +07:00
171b938d3a Check if Period Validity 2024-03-12 16:39:00 +07:00
61c1d25096 We are excited to introduce a new feature
I am delighted to announce that a highly requested feature has been added to Nuxbill! We now support Multiple Payment Gateways, allowing customers to choose their preferred payment method. This update brings greater flexibility and convenience to our users.
2024-03-12 16:39:00 +07:00
f885b8e8a3 Update dashboard.php
Fix when user purchase services with his/her balance it wont be added as income because the balance has been added earlier
2024-03-12 16:39:00 +07:00
2bb664e241 Expired Date by created date 2024-03-12 15:28:32 +07:00
c9058769ce Recharge with balance or zero cost 2024-03-12 15:09:00 +07:00
6d15437333 admin can recharge disabled plan 2024-03-12 13:58:42 +07:00
7c5958c8c1 delete allow_purchase in cron 2024-03-12 13:46:40 +07:00
1a4a0f2c10 Invoice number not Random 2024-03-12 12:12:36 +07:00
629d9e8ed4 Period in hotspot 2024-03-12 12:01:49 +07:00
b9e987570c Show From Customer 2024-03-12 11:54:20 +07:00
b95788262d Change button 2024-03-12 11:48:17 +07:00
3bb55320e3 Multiple Payment gateway Fix 2024-03-12 11:17:05 +07:00
7a9f937a9e delete button 2024-03-12 10:43:34 +07:00
c00e51adda Delete Plugin 2024-03-12 10:42:42 +07:00
0cc526e29a change path 2024-03-12 10:00:40 +07:00
16f0642007 delete payment gateway 2024-03-12 10:00:28 +07:00
e1f7b324cb Fix Logic Multiple Payment gateway 2024-03-12 09:33:45 +07:00
8f0ff3e786 change path to /gateway/ 2024-03-12 09:24:16 +07:00
9023f89456 delete none 2024-03-12 09:23:59 +07:00
140b756994 .htaccess Firewall 2024-03-12 09:07:12 +07:00
ca59c89e1d Check if Period Validity 2024-03-12 09:07:12 +07:00
4e23918999 Merge pull request #122 from Focuslinkstech/Development
We are excited to introduce a new feature
2024-03-12 09:06:43 +07:00
758a0a99a9 We are excited to introduce a new feature
I am delighted to announce that a highly requested feature has been added to Nuxbill! We now support Multiple Payment Gateways, allowing customers to choose their preferred payment method. This update brings greater flexibility and convenience to our users.
2024-03-11 09:34:25 +01:00
b6cf9bec0b Merge pull request #121 from Focuslinkstech/Development
Update dashboard.php
2024-03-11 14:43:13 +07:00
6e07c3ae85 Update dashboard.php
Fix when user purchase services with his/her balance it wont be added as income because the balance has been added earlier
2024-03-10 22:41:48 +01:00
ef76aadc16 Merge pull request #120 from hotspotbilling/Development
fix delete customer attribute
2024-03-08 17:50:06 +07:00
8e960107fc Merge pull request #119 from Focuslinkstech/Development
Bug Fix
2024-03-08 17:47:44 +07:00
c4e702ee2f Update customers.php
Fix Delete the Customers Attributes with the given field name, it delete all from the table which belong to other customers
2024-03-08 10:43:07 +01:00
08790e7295 Merge branch 'Development' of https://github.com/Focuslinkstech/phpnuxbill into Development 2024-03-08 09:37:56 +01:00
cfefd38a31 if ($p['validity_unit'] == 'Period') then add Expired Date 2024-03-06 12:03:24 +07:00
37a5ee8566 Change the view of Attributes Customer 2024-03-06 11:15:45 +07:00
e5c8aae758 2024.3.5 2024-03-05 16:20:18 +07:00
99d393d0c0 Merge pull request #118 from gerandonk/Development
change due date for period plan to customer field attribute
2024-03-05 16:18:32 +07:00
e6280d597b change due date for period plan to customer field attribute
admin can change expired date for period plan as wish before recharger customer
2024-03-05 16:08:33 +07:00
18db9cd280 hide if balance off 2024-03-05 11:15:38 +07:00
6aab647f48 Company name in login 2024-03-05 11:15:26 +07:00
b8b4623078 notification variable fix 2024-03-04 14:26:36 +07:00
6a79cff233 checkUserType when edit is neq 2024-03-04 11:30:09 +07:00
4c02283fd0 add full name in telegram notification 2024-03-04 10:06:19 +07:00
403de91fba sendPackageNotification with customer variable 2024-03-04 10:02:23 +07:00
4ee3743cf3 Fix Password send to admin 2024-03-04 09:57:12 +07:00
77e48dae8b add is file exists 2024-03-03 19:54:04 +07:00
0745532951 2024.3.3 2024-03-03 17:29:53 +07:00
b53116d22a Customer Announcement 2024-03-03 17:24:01 +07:00
f7df824145 Merge pull request #116 from gerandonk/Development
Development
2024-03-03 17:11:38 +07:00
f154322f99 Merge pull request #115 from Focuslinkstech/master
improvement
2024-03-03 17:10:06 +07:00
a76ba6ee8b update db for validity period 2024-03-03 11:30:34 +07:00
61b3f5b5f5 Add planwith validity period 2024-03-03 11:03:25 +07:00
b153e5b595 distinguish between announcements on the user dashboard and the login page 2024-03-03 11:00:42 +07:00
9ab0b6a0fa improvement
just replace the save loading with css for better loading feature
2024-03-02 12:40:04 +01:00
a7f191f058 damn, that curly bracket make error :)) 2024-03-01 19:42:59 +07:00
012a1ecfab allow purchase = no, but can recharge 2024-03-01 16:10:01 +07:00
dc70a49f52 upload path 2024-03-01 13:44:46 +07:00
bc7380eab7 add variable to global 2024-03-01 10:36:24 +07:00
f4da09a26e move hook before sending notification 2024-03-01 10:11:18 +07:00
de3312055a add hook when recharge 2024-03-01 09:57:59 +07:00
699289662b Fix Upload URL 2024-03-01 09:37:13 +07:00
bae079f71c Fix Hook Functionality 2024-02-29 13:32:46 +07:00
28f4624e8d change Customer menu 2024-02-29 11:37:54 +07:00
fbd215e741 Merge branch 'master' into Development 2024-02-29 09:26:19 +07:00
2437096473 $_c to $config in php file 2024-02-29 09:25:26 +07:00
dfeee540cf Fix variable $_c 2024-02-28 18:19:17 +07:00
a0b9e85f38 Add Expired date for reminder 2024-02-28 11:31:36 +07:00
08153e6ec1 Fix Buy Plan with Balance 2024-02-28 11:31:31 +07:00
2660f5d2d0 Dashboard 2 Column 2024-02-27 14:22:17 +07:00
82e67f0b83 fix Recharge 2024-02-27 13:12:53 +07:00
41dd0d86e7 Fix Recharge 2024-02-27 13:12:25 +07:00
c8004f1a27 fix update file 2024-02-27 13:10:06 +07:00
61edfb932a fix wrong logic != to == 2024-02-27 12:00:49 +07:00
747a67b691 2024.2.27 2024-02-27 10:39:21 +07:00
b938db9e5d redirect after login 2024-02-27 10:37:41 +07:00
1ec8049068 fix path 2024-02-27 10:32:09 +07:00
848dcb5caf fix variable Admin.php 2024-02-27 07:12:02 +07:00
afe6b34fd6 Update Package.php
fix package recharge bug
2024-02-26 18:03:48 +01:00
fceb79bdc3 fix sql installer 2024-02-26 15:39:23 +07:00
83457fd9fc Remove unused font, too big 2024-02-26 15:18:54 +07:00
206 changed files with 12678 additions and 3568 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

14
.htaccess_firewall Normal file
View File

@ -0,0 +1,14 @@
<Files *.php>
Order Deny,Allow
Deny from all
</Files>
<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,140 @@
# CHANGELOG
## 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
- Add Additional Bill
- View Invoice from Customer side
## 2024.3.13
- Postpaid System
- Additional Cost
## 2024.3.12
- Check if Validity Period, so calculate price will not affected other validity
- Add firewall using .htaccess for apache only
- Multiple Payment Gateway by @Focuslinkstech
- Fix Logic Multiple Payment gateway
- Fix delete Attribute
- Allow Delete Payment Gateway
- Allow Delete Plugin
## 2024.3.6
- change attributes view
## 2024.3.4
- add [[username]] for reminder
- fix agent show when editing
- fix password admin when sending notification
- add file exists for pages
## 2024.3.3
- Change loading button by @Focuslinkstech
- Add Customer Announcements by @Gerandonk
- Add PPPOE Period Validity by @Gerandonk
## 2024.2.29
- Fix Hook Functionality
- Change Customer Menu
## 2024.2.28
- Fix Buy Plan with Balance
- Add Expired date for reminder
## 2024.2.27
- fix path notification
- redirect to dashboard if already login
## 2024.2.26
- Clean Unused JS and CSS

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,14 +73,17 @@ 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($root_path . $UPLOAD_PATH . DIRECTORY_SEPARATOR . "notifications.json")) {
$_notifmsg = json_decode(file_get_contents($root_path . $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'notifications.json'), true);
if (file_exists($UPLOAD_PATH . DIRECTORY_SEPARATOR . "notifications.json")) {
$_notifmsg = json_decode(file_get_contents($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'notifications.json'), true);
}
$_notifmsg_default = json_decode(file_get_contents($root_path . $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'notifications.default.json'), true);
$_notifmsg_default = json_decode(file_get_contents($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'notifications.default.json'), true);
//register all plugin
foreach (glob(File::pathFixer($PLUGIN_PATH . DIRECTORY_SEPARATOR . '*.php')) as $filename) {
@ -96,6 +100,7 @@ $result = ORM::for_table('tbl_appconfig')->find_many();
foreach ($result as $value) {
$config[$value['setting']] = $value['value'];
}
$_c = $config;
if (empty($http_proxy) && !empty($config['http_proxy'])) {
$http_proxy = $config['http_proxy'];
if (empty($http_proxyauth) && !empty($config['http_proxyauth'])) {
@ -195,7 +200,18 @@ function _log($description, $type = '', $userid = '0')
$d->type = $type;
$d->description = $description;
$d->userid = $userid;
$d->ip = $_SERVER["REMOTE_ADDR"];
if (!empty($_SERVER['HTTP_CF_CONNECTING_IP'])) //to check ip is pass from cloudflare tunnel
{
$d->ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) //to check ip is pass from proxy
{
$d->ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} elseif (!empty($_SERVER['HTTP_CLIENT_IP'])) //to check ip from share internet
{
$d->ip = $_SERVER['HTTP_CLIENT_IP'];
} else {
$d->ip = $_SERVER["REMOTE_ADDR"];
}
$d->save();
}
@ -206,9 +222,16 @@ 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 sendTelegram($txt)
{
@ -227,6 +250,13 @@ function sendWhatsapp($phone, $txt)
function r2($to, $ntype = 'e', $msg = '')
{
global $isApi;
if ($isApi) {
showResult(
($ntype=='s')? true : false,
$msg
);
}
if ($msg == '') {
header("location: $to");
exit;
@ -237,9 +267,15 @@ function r2($to, $ntype = 'e', $msg = '')
exit;
}
function _alert($text, $type = 'success', $url = "home")
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") {
@ -250,8 +286,10 @@ function _alert($text, $type = 'success', $url = "home")
}
$ui->assign('text', $text);
$ui->assign('type', $type);
$ui->assign('time', $time);
$ui->assign('url', $url);
$ui->display('alert.tpl');
die();
}

View File

@ -21,13 +21,15 @@ CREATE TABLE `tbl_customers` (
`id` int(10) NOT NULL,
`username` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`password` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`pppoe_password` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1' COMMENT 'For PPPOE Login',
`pppoe_password` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login',
`fullname` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`address` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
`phonenumber` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0',
`email` varchar(128) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1',
`coordinates` VARCHAR(50) NOT NULL DEFAULT '' COMMENT 'Latitude and Longitude coordinates',
`balance` decimal(15,2) NOT NULL DEFAULT '0.00' COMMENT 'For Money Deposit',
`service_type` ENUM('Hotspot','PPPoE','Others') DEFAULT 'Others' COMMENT 'For selecting user type',
`account_type` ENUM('Business', 'Personal') DEFAULT 'Personal' COMMENT 'For selecting account type',
`auto_renewal` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'Auto renewall using balance',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_login` datetime DEFAULT NULL
@ -79,26 +81,27 @@ CREATE TABLE `tbl_payment_gateway` (
DROP TABLE IF EXISTS `tbl_plans`;
CREATE TABLE `tbl_plans` (
`id` int(10) NOT NULL,
`name_plan` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`id_bw` int(10) NOT NULL,
`price` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`type` enum('Hotspot','PPPOE','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`typebp` enum('Unlimited','Limited') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`limit_type` enum('Time_Limit','Data_Limit','Both_Limit') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`time_limit` int(10) UNSIGNED DEFAULT NULL,
`time_unit` enum('Mins','Hrs') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`data_limit` int(10) UNSIGNED DEFAULT NULL,
`data_unit` enum('MB','GB') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`validity` int(10) NOT NULL,
`validity_unit` enum('Mins','Hrs','Days','Months') 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`;
@ -142,7 +145,7 @@ CREATE TABLE `tbl_users` (
`username` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`fullname` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`password` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`user_type` enum('Admin','Sales') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`user_type` enum('SuperAdmin','Admin','Report','Agent','Sales') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`status` enum('Active','Inactive') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'Active',
`last_login` datetime DEFAULT NULL,
`creationdate` datetime NOT NULL
@ -309,11 +312,13 @@ CREATE TABLE tbl_customers_fields (
ALTER TABLE `tbl_voucher` ADD `generated_by` INT NOT NULL DEFAULT '0' COMMENT 'id admin' AFTER `status`;
ALTER TABLE `tbl_users` ADD `root` INT NOT NULL DEFAULT '0' COMMENT 'for sub account' AFTER `id`;
ALTER TABLE `tbl_users` CHANGE `user_type` `user_type` ENUM('SuperAdmin','Admin','Report','Agent','Sales') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;
ALTER TABLE `tbl_users` CHANGE `password` `password` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;
ALTER TABLE `tbl_users` ADD `phone` VARCHAR(32) NOT NULL DEFAULT '' AFTER `password`, ADD `email` VARCHAR(128) NOT NULL DEFAULT '' AFTER `phone`, ADD `city` VARCHAR(64) NOT NULL DEFAULT '' COMMENT 'kota' AFTER `email`, ADD `subdistrict` VARCHAR(64) NOT NULL DEFAULT '' COMMENT 'kecamatan' AFTER `city`, ADD `ward` VARCHAR(64) NOT NULL DEFAULT '' COMMENT 'kelurahan' AFTER `subdistrict`;
ALTER TABLE `tbl_customers` ADD `created_by` INT NOT NULL DEFAULT '0' AFTER `auto_renewal`;
ALTER TABLE `tbl_plans` ADD `list_expired` VARCHAR(32) NOT NULL DEFAULT '' COMMENT 'address list' AFTER `pool_expired`;
ALTER TABLE `tbl_bandwidth` ADD `burst` VARCHAR(128) NOT NULL DEFAULT '' AFTER `rate_up_unit`;
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_user_recharges` ADD `admin_id` INT NOT NULL DEFAULT '1' AFTER `type`;
ALTER TABLE `tbl_plans` CHANGE `allow_purchase` `prepaid` ENUM('yes','no') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'yes' COMMENT 'is prepaid';
ALTER TABLE `tbl_transactions` ADD `note` VARCHAR(256) NOT NULL DEFAULT '' COMMENT 'for note' AFTER `type`;
ALTER TABLE `tbl_payment_gateway` ADD `trx_invoice` VARCHAR(25) NOT NULL DEFAULT '' COMMENT 'from tbl_transactions' AFTER `paid_date`;

View File

@ -1 +1,3 @@
Pengumuman!!<br>Besok libur<br><br>Announcement!!<br>Tomorrow holiday<br>
Pengumuman!!<br>Besok libur<br><br>Announcement!!<br>Tomorrow holiday<br><br>
<br>
This Announcement is for Login Page.

View File

@ -0,0 +1,8 @@
Pengumuman Pelanggan!!<br>
Besok libur<br>
<br>
Customer Announcement!!<br>
Tomorrow holiday<br>
<br>
<br>
This Announcement is for Customer Dashboard

19
system/.htaccess Normal file
View File

@ -0,0 +1,19 @@
<Files *.php>
Order Deny,Allow
Deny from all
</Files>
<Files cron.php>
Order Allow,Deny
Allow from all
</Files>
<Files api.php>
Order Allow,Deny
Allow from all
</Files>
<Files cron_reminder.php>
Order Allow,Deny
Allow from all
</Files>

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'])) {
@ -51,7 +55,7 @@ class Admin
if ($id) {
return ORM::for_table('tbl_users')->find_one($id);
} else {
return [];
return null;
}
}
}

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

@ -38,6 +38,7 @@ function register_menu($name, $admin, $function, $position, $icon = '', $label =
$hook_registered = array();
function register_hook($action, $function){
global $hook_registered;
$hook_registered[] = [
'action' => $action,
'function' => $function

View File

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

View File

@ -5,6 +5,12 @@
* by https://t.me/ibnux
**/
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\SMTP;
require $root_path . 'system/autoload/mail/Exception.php';
require $root_path . 'system/autoload/mail/PHPMailer.php';
require $root_path . 'system/autoload/mail/SMTP.php';
class Message
{
@ -22,6 +28,9 @@ class Message
public static function sendSMS($phone, $txt)
{
global $config;
if(empty($txt)){
return "";
}
run_hook('send_sms'); #HOOK
if (!empty($config['sms_url'])) {
if (strlen($config['sms_url']) > 4 && substr($config['sms_url'], 0, 4) != "http") {
@ -58,27 +67,93 @@ 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($phone), $config['wa_url']);
$waurl = str_replace('[number]', urlencode(Lang::phoneFormat($phone)), $config['wa_url']);
$waurl = str_replace('[text]', urlencode($txt), $waurl);
return Http::getData($waurl);
}
}
public static function sendPackageNotification($phone, $name, $package, $price, $message, $via)
public static function sendEmail($to, $subject, $body)
{
$msg = str_replace('[[name]]', $name, $message);
global $config;
if(empty($body)){
return "";
}
run_hook('send_email'); #HOOK
if (empty($config['smtp_host'])) {
$attr = "";
if (!empty($config['mail_from'])) {
$attr .= "From: " . $config['mail_from'] . "\r\n";
}
if (!empty($config['mail_reply_to'])) {
$attr .= "Reply-To: " . $config['mail_reply_to'] . "\r\n";
}
mail($to, $subject, $body, $attr);
} else {
$mail = new PHPMailer();
$mail->isSMTP();
$mail->SMTPDebug = SMTP::DEBUG_SERVER;
$mail->Host = $config['smtp_host'];
$mail->SMTPAuth = true;
$mail->Username = $config['smtp_user'];
$mail->Password = $config['smtp_pass'];
$mail->SMTPSecure = $config['smtp_ssltls'];
$mail->Port = $config['smtp_port'];
if (!empty($config['mail_from'])) {
$mail->setFrom($config['mail_from']);
}
if (!empty($config['mail_reply_to'])) {
$mail->addReplyTo($config['mail_reply_to']);
}
$mail->isHTML(false);
$mail->addAddress($to);
$mail->Subject = $subject;
$mail->Body = $body;
$mail->send();
die();
}
}
public static function sendPackageNotification($customer, $package, $price, $message, $via)
{
global $user_recharge;
if(empty($message)){
return "";
}
$msg = str_replace('[[name]]', $customer['fullname'], $message);
$msg = str_replace('[[username]]', $customer['username'], $msg);
$msg = str_replace('[[plan]]', $package, $msg);
$msg = str_replace('[[package]]', $package, $msg);
$msg = str_replace('[[price]]', $price, $msg);
$msg = str_replace('[[price]]', Lang::moneyFormat($price), $msg);
list($bills, $add_cost) = User::getBills($customer['id']);
if($add_cost>0){
$note = "";
foreach ($bills as $k => $v) {
$note .= $k . " : " . Lang::moneyFormat($v) . "\n";
}
$note .= "Total : " . Lang::moneyFormat($add_cost+$price) . "\n";
$msg = str_replace('[[bills]]', $note, $msg);
}else{
$msg = str_replace('[[bills]]', '', $msg);
}
if ($user_recharge) {
$msg = str_replace('[[expired_date]]', Lang::dateAndTimeFormat($user_recharge['expiration'], $user_recharge['time']), $msg);
}else{
$msg = str_replace('[[expired_date]]', "", $msg);
}
if (
!empty($phone) && strlen($phone) > 5
!empty($customer['phonenumber']) && strlen($customer['phonenumber']) > 5
&& !empty($message) && in_array($via, ['sms', 'wa'])
) {
if ($via == 'sms') {
Message::sendSMS($phone, $msg);
echo Message::sendSMS($customer['phonenumber'], $msg);
} else if ($via == 'wa') {
Message::sendWhatsapp($phone, $msg);
echo Message::sendWhatsapp($customer['phonenumber'], $msg);
}
}
return "$via: $msg";
@ -111,6 +186,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);
@ -118,8 +196,11 @@ class Message
$textInvoice = str_replace('[[plan_name]]', $trx['plan_name'], $textInvoice);
$textInvoice = str_replace('[[plan_price]]', Lang::moneyFormat($trx['price']), $textInvoice);
$textInvoice = str_replace('[[name]]', $cust['fullname'], $textInvoice);
$textInvoice = str_replace('[[note]]', $cust['note'], $textInvoice);
$textInvoice = str_replace('[[user_name]]', $trx['username'], $textInvoice);
$textInvoice = str_replace('[[user_password]]', $cust['password'], $textInvoice);
$textInvoice = str_replace('[[username]]', $trx['username'], $textInvoice);
$textInvoice = str_replace('[[password]]', $cust['password'], $textInvoice);
$textInvoice = str_replace('[[expired_date]]', Lang::dateAndTimeFormat($trx['expiration'], $trx['time']), $textInvoice);
$textInvoice = str_replace('[[footer]]', $config['note'], $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,28 +15,71 @@ 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)
public static function rechargeUser($id_customer, $router_name, $plan_id, $gateway, $channel, $note = '')
{
global $config, $admin;
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;
}
$c = ORM::for_table('tbl_customers')->where('id', $id_customer)->find_one();
$p = ORM::for_table('tbl_plans')->where('id', $plan_id)->where('enabled', '1')->find_one();
$p = ORM::for_table('tbl_plans')->where('id', $plan_id)->find_one();
$add_cost = 0;
$bills = [];
// Zero cost recharge
if (isset($zero) && $zero == 1) {
$p['price'] = 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'));
}
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
r2(U . 'dashboard', 'e', Lang::T('Plan Not found'));
}
}
if ($p['validity_unit'] == 'Period') {
$day_exp = User::getAttribute("Expired Date", $c['id']); //ORM::for_table('tbl_customers_fields')->where('field_name', 'Expired Date')->where('customer_id', $c['id'])->find_one();
if (!$day_exp) {
$day_exp = 20;
// $day_exp = date('d', strtotime($c['created_at']));
// if (empty($day_exp) || $day_exp > 28) {
// $day_exp = 1;
// }
$f = ORM::for_table('tbl_customers_fields')->create();
$f->customer_id = $c['id'];
$f->field_name = 'Expired Date';
$f->field_value = $day_exp;
$f->save();
}
}
if ($router_name == 'balance') {
// insert table transactions
$inv = "INV-" . Package::_raid(5);
$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'];
@ -48,8 +91,8 @@ class Package
$t->routers = $router_name;
$t->type = "Balance";
if ($admin) {
$t->admin_id = $admin['id'];
}else{
$t->admin_id = ($admin['id']) ? $admin['id'] : '0';
} else {
$t->admin_id = '0';
}
$t->save();
@ -86,17 +129,51 @@ class Package
}
/**
* 1 Customer only can have 1 PPPOE and 1 Hotspot Plan
* 1 Customer only can have 1 PPPOE and 1 Hotspot Plan, 1 prepaid and 1 postpaid
*/
$b = 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')
->where('customer_id', $id_customer)
->where('routers', $router_name)
->where('Type', $p['type'])
->where('tbl_user_recharges.routers', $router_name)
->where('tbl_user_recharges.Type', $p['type'])
# PPPOE or Hotspot only can have 1 per customer prepaid or postpaid
# because 1 customer can have 1 PPPOE and 1 Hotspot Plan in mikrotik
//->where('prepaid', $p['prepaid'])
->join('tbl_plans', array('tbl_plans.id', '=', 'tbl_user_recharges.plan_id'))
->find_one();
run_hook("recharge_user");
$mikrotik = Mikrotik::info($router_name);
if ($p['validity_unit'] == 'Months') {
$date_exp = date("Y-m-d", strtotime('+' . $p['validity'] . ' month'));
} else if ($p['validity_unit'] == 'Period') {
$date_tmp = date("Y-m-$day_exp", strtotime('+' . $p['validity'] . ' month'));
$dt1 = new DateTime("$date_only");
$dt2 = new DateTime("$date_tmp");
$diff = $dt2->diff($dt1);
$sum = $diff->format("%a"); // => 453
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'));
} else if ($p['validity_unit'] == 'Hrs') {
@ -116,6 +193,9 @@ class Package
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'];
@ -152,31 +232,66 @@ class Package
$b->routers = $router_name;
$b->type = "Hotspot";
if ($admin) {
$b->admin_id = $admin['id'];
}else{
$b->admin_id = ($admin['id']) ? $admin['id'] : '0';
} else {
$b->admin_id = '0';
}
$b->save();
// insert table transactions
$t = ORM::for_table('tbl_transactions')->create();
$t->invoice = "INV-" . Package::_raid(5);
$t->invoice = $inv = "INV-" . Package::_raid();
$t->username = $c['username'];
$t->plan_name = $p['name_plan'];
$t->price = $p['price'];
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;
$t->time = $time;
$t->method = "$gateway - $channel";
$t->routers = $router_name;
$t->note = $note;
$t->type = "Hotspot";
if ($admin) {
$t->admin_id = $admin['id'];
}else{
$t->admin_id = ($admin['id']) ? $admin['id'] : '0';
} else {
$t->admin_id = '0';
}
$t->save();
if ($p['validity_unit'] == 'Period') {
// 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';
$fl->field_value = $p['price'];
$fl->save();
} else {
$fl->customer_id = $c['id'];
$fl->field_value = $p['price'];
$fl->save();
}
}
Message::sendTelegram("#u$c[username] $c[fullname] #recharge #Hotspot \n" . $p['name_plan'] .
"\nRouter: " . $router_name .
"\nGateway: " . $gateway .
"\nChannel: " . $channel .
"\nPrice: " . Lang::moneyFormat($p['price'] + $add_cost) .
"\nNote:\n" . $note);
} else {
if ($p['is_radius']) {
Radius::customerAddPlan($c, $p, "$date_exp $time");
@ -201,37 +316,71 @@ class Package
$d->routers = $router_name;
$d->type = "Hotspot";
if ($admin) {
$b->admin_id = $admin['id'];
}else{
$b->admin_id = '0';
$d->admin_id = ($admin['id']) ? $admin['id'] : '0';
} else {
$d->admin_id = '0';
}
$d->save();
// insert table transactions
$t = ORM::for_table('tbl_transactions')->create();
$t->invoice = "INV-" . Package::_raid(5);
$t->invoice = $inv = "INV-" . Package::_raid();
$t->username = $c['username'];
$t->plan_name = $p['name_plan'];
$t->price = $p['price'];
if ($p['validity_unit'] == 'Period') {
// Postpaid price always zero for first time
$t->price = 0 + $add_cost;
} else {
$t->price = $p['price'] + $add_cost;
}
$t->recharged_on = $date_only;
$t->recharged_time = $time_only;
$t->expiration = $date_exp;
$t->time = $time;
$t->method = "$gateway - $channel";
$t->routers = $router_name;
$t->note = $note;
$t->type = "Hotspot";
if ($admin) {
$t->admin_id = $admin['id'];
}else{
$t->admin_id = ($admin['id']) ? $admin['id'] : '0';
} else {
$t->admin_id = '0';
}
$t->save();
if ($p['validity_unit'] == 'Period' && $p['price'] != 0) {
// 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 {
$fl->field_value = $gi;
}
$fl->save();
} else {
$fl->customer_id = $c['id'];
$fl->field_value = $p['price'];
$fl->save();
}
}
Message::sendTelegram("#u$c[username] $c[fullname] #buy #Hotspot \n" . $p['name_plan'] .
"\nRouter: " . $router_name .
"\nGateway: " . $gateway .
"\nChannel: " . $channel .
"\nPrice: " . Lang::moneyFormat($p['price'] + $add_cost) .
"\nNote:\n" . $note);
}
Message::sendTelegram("#u$c[username] #buy #Hotspot \n" . $p['name_plan'] .
"\nRouter: " . $router_name .
"\nGateway: " . $gateway .
"\nChannel: " . $channel .
"\nPrice: " . Lang::moneyFormat($p['price']));
} else {
if ($b) {
@ -240,6 +389,9 @@ class Package
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'];
@ -276,31 +428,65 @@ class Package
$b->routers = $router_name;
$b->type = "PPPOE";
if ($admin) {
$b->admin_id = $admin['id'];
}else{
$b->admin_id = ($admin['id']) ? $admin['id'] : '0';
} else {
$b->admin_id = '0';
}
$b->save();
// insert table transactions
$t = ORM::for_table('tbl_transactions')->create();
$t->invoice = "INV-" . Package::_raid(5);
$t->invoice = $inv = "INV-" . Package::_raid();
$t->username = $c['username'];
$t->plan_name = $p['name_plan'];
$t->price = $p['price'];
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;
$t->time = $time;
$t->method = "$gateway - $channel";
$t->routers = $router_name;
$t->note = $note;
$t->type = "PPPOE";
if ($admin) {
$t->admin_id = $admin['id'];
}else{
$t->admin_id = ($admin['id']) ? $admin['id'] : '0';
} else {
$t->admin_id = '0';
}
$t->save();
if ($p['validity_unit'] == 'Period' && $p['price'] != 0) {
// 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';
$fl->field_value = $p['price'];
$fl->save();
} else {
$fl->customer_id = $c['id'];
$fl->field_value = $p['price'];
$fl->save();
}
}
Message::sendTelegram("#u$c[username] $c[fullname] #recharge #PPPOE \n" . $p['name_plan'] .
"\nRouter: " . $router_name .
"\nGateway: " . $gateway .
"\nChannel: " . $channel .
"\nPrice: " . Lang::moneyFormat($p['price'] + $add_cost) .
"\nNote:\n" . $note);
} else {
if ($p['is_radius']) {
Radius::customerAddPlan($c, $p, "$date_exp $time");
@ -325,47 +511,89 @@ class Package
$d->routers = $router_name;
$d->type = "PPPOE";
if ($admin) {
$d->admin_id = $admin['id'];
}else{
$d->admin_id = ($admin['id']) ? $admin['id'] : '0';
} else {
$d->admin_id = '0';
}
$d->save();
// insert table transactions
$t = ORM::for_table('tbl_transactions')->create();
$t->invoice = "INV-" . Package::_raid(5);
$t->invoice = $inv = "INV-" . Package::_raid();
$t->username = $c['username'];
$t->plan_name = $p['name_plan'];
$t->price = $p['price'];
if ($p['validity_unit'] == 'Period') {
// Postpaid price always zero for first time
$note = '';
$bills = [];
$t->price = 0;
} else {
$t->price = $p['price'] + $add_cost;
}
$t->recharged_on = $date_only;
$t->recharged_time = $time_only;
$t->expiration = $date_exp;
$t->time = $time;
$t->method = "$gateway - $channel";
$t->note = $note;
$t->routers = $router_name;
if ($admin) {
$t->admin_id = $admin['id'];
}else{
$t->admin_id = ($admin['id']) ? $admin['id'] : '0';
} else {
$t->admin_id = '0';
}
$t->type = "PPPOE";
$t->save();
}
Message::sendTelegram("#u$c[username] #buy #PPPOE \n" . $p['name_plan'] .
"\nRouter: " . $router_name .
"\nGateway: " . $gateway .
"\nChannel: " . $channel .
"\nPrice: " . Lang::moneyFormat($p['price']));
}
if ($p['validity_unit'] == 'Period' && $p['price'] != 0) {
// 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 {
$fl->field_value = $gi;
}
$fl->save();
} else {
$fl->customer_id = $c['id'];
$fl->field_value = $p['price'];
$fl->save();
}
}
Message::sendTelegram("#u$c[username] $c[fullname] #buy #PPPOE \n" . $p['name_plan'] .
"\nRouter: " . $router_name .
"\nGateway: " . $gateway .
"\nChannel: " . $channel .
"\nPrice: " . Lang::moneyFormat($p['price'] + $add_cost) .
"\nNote:\n" . $note);
}
}
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)
{
$c = ORM::for_table('tbl_customers')->where('username', $username)->find_one();
$p = ORM::for_table('tbl_plans')->where('id', $plan_id)->where('enabled', '1')->find_one();
$p = ORM::for_table('tbl_plans')->where('id', $plan_id)->find_one();
$b = ORM::for_table('tbl_user_recharges')->find_one($from_id);
if ($p['routers'] == $b['routers'] && $b['routers'] != 'radius') {
$mikrotik = Mikrotik::info($p['routers']);
@ -442,9 +670,9 @@ class Package
}
public static function _raid($l)
public static function _raid()
{
return substr(str_shuffle(str_repeat('0123456789', $l)), 0, $l);
return ORM::for_table('tbl_transactions')->max('id') + 1;
}
/**
@ -463,7 +691,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";
@ -475,9 +708,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'])) {
$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($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') {
@ -499,9 +754,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'])) {
$invoice .= Lang::pad("", '=') . "\n";
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') {
@ -511,6 +786,6 @@ class Package
$invoice .= Lang::pad("", '=') . "\n";
$invoice .= Lang::pad($config['note'], ' ', 2) . "\n";
$ui->assign('whatsapp', urlencode("```$invoice```"));
$ui->assign('in',$in);
$ui->assign('in', $in);
}
}

View File

@ -1,14 +1,82 @@
<?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();
$next = $page + 1;
$lastpage = ceil($totalReq / $per_page);
$lpm1 = $lastpage - 1;
$limit = $per_page;
$startpoint = ($page * $limit) - $limit;
if ($lastpage >= 1) {
$pages = [];
if ($lastpage < 7 + ($adjacents * 2)) {
for ($counter = 1; $counter <= $lastpage; $counter++) {
$pages[] = $counter;
}
} elseif ($lastpage > 5 + ($adjacents * 2)) {
if ($page < 1 + ($adjacents * 2)) {
for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++) {
$pages[] = $counter;
}
$pages[] = "...";
$pages[] = $lpm1;
$pages[] = $lastpage;
} elseif ($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2)) {
$pages[] = "1";
$pages[] = "2";
$pages[] = "...";
for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++) {
$pages[] = $counter;
}
$pages[] = "...";
$pages[] = $lpm1;
$pages[] = $lastpage;
} else {
$pages[] = "1";
$pages[] = "2";
$pages[] = "...";
for ($counter = $lastpage - (2 + ($adjacents * 2)); $counter <= $lastpage; $counter++) {
$pages[] = $counter;
}
}
}
$result = [
'count' => $lastpage,
'limit' => $per_page,
'startpoint' => $startpoint,
'url' => $url,
'page' => $page,
'pages' => $pages,
'prev' => ($page > 0) ? ($page - 1) : "0",
'next' => ($page >= $lastpage) ? $lastpage : $page + 1
];
if ($ui) {
$ui->assign('paginator', $result);
}
return $query->offset($startpoint)->limit($per_page)->find_many();
}
}
public static function build($table, $colVal = [], $query = '', $per_page = '10')
{
global $routes;
global $_L;
@ -17,13 +85,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 +104,60 @@ class Paginator
$limit = $per_page;
$startpoint = ($page * $limit) - $limit;
if ($lastpage >= 1) {
$pagination .= '<ul class="pagination pagination-sm">';
$pagination .= '<ul class="pagination">';
if ($lastpage < 7 + ($adjacents * 2)) {
for ($counter = 1; $counter <= $lastpage; $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>";
$pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}&p=$counter&q=$query'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$counter&q=$query'>$counter</a></li>";
}
} elseif ($lastpage > 5 + ($adjacents * 2)) {
if ($page < 1 + ($adjacents * 2)) {
for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>";
$pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}&p=$counter&q=$query'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$counter&q=$query'>$counter</a></li>";
}
$pagination .= "<li class='disabled'><a href='#'>...</a></li>";
$pagination .= "<li><a href='{$url}&p=$lpm1&q=$query'>$lpm1</a></li>";
$pagination .= "<li><a href='{$url}&p=$lastpage&q=$query'>$lastpage</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$lpm1&q=$query'>$lpm1</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$lastpage&q=$query'>$lastpage</a></li>";
} elseif ($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2)) {
$pagination .= "<li><a href='{$url}&p=1&q=$query'>1</a></li>";
$pagination .= "<li><a href='{$url}&p=2&q=$query'>2</a></li>";
$pagination .= "<li class='disabled'><a href='#'>...</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=1&q=$query'>1</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=2&q=$query'>2</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>";
$pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}&p=$counter&q=$query'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$counter&q=$query'>$counter</a></li>";
}
$pagination .= "<li class='disabled'><a href='#'>...</a></li>";
$pagination .= "<li><a href='{$url}&p=$lpm1&q=$query'>$lpm1</a></li>";
$pagination .= "<li><a href='{$url}&p=$lastpage&q=$query'>$lastpage</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$lpm1&q=$query'>$lpm1</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$lastpage&q=$query'>$lastpage</a></li>";
} else {
$pagination .= "<li><a href='{$url}&p=1&q=$query'>1</a></li>";
$pagination .= "<li><a href='{$url}&p=2&q=$query'>2</a></li>";
$pagination .= "<li><a href='#'>...</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=1&q=$query'>1</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=2&q=$query'>2</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='#'>...</a></li>";
for ($counter = $lastpage - (2 + ($adjacents * 2)); $counter <= $lastpage; $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a class='disabled'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link disabled'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}&p=$counter&q=$query'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$counter&q=$query'>$counter</a></li>";
}
}
}
if ($page < $counter - 1) {
$pagination .= "<li><a href='{$url}&p=$next&q=$query'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li><a href='{$url}&p=$lastpage&q=$query'>" . Lang::T('Last') . "</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$next&q=$query'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}&p=$lastpage&q=$query'>" . Lang::T('Last') . "</a></li>";
} else {
$pagination .= "<li class='disabled'><a class='disabled'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li class='disabled'><a class='disabled'>" . Lang::T('Last') . "</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link disabled'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link disabled'>" . Lang::T('Last') . "</a></li>";
}
$pagination .= "</ul>";
$pagination = '<nav>' . $pagination . '</nav>';
return array("startpoint" => $startpoint, "limit" => $limit, "found" => $totalReq, "page" => $page, "lastpage" => $lastpage, "contents" => $pagination);
}
}
@ -103,7 +171,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 +183,7 @@ class Paginator
} else {
$totalReq = $table->count();
}
}else{
} else {
if ($w1 != '') {
$totalReq = ORM::for_table($table)->where($w1, $c1)->count();
} elseif ($w2 != '') {
@ -142,59 +210,60 @@ class Paginator
$startpoint = ($page * $limit) - $limit;
if ($lastpage >= 1) {
$pagination .= '<ul class="pagination pagination-sm">';
$pagination .= '<ul class="pagination">';
if ($lastpage < 7 + ($adjacents * 2)) {
for ($counter = 1; $counter <= $lastpage; $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>";
$pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$counter'>$counter</a></li>";
}
} elseif ($lastpage > 5 + ($adjacents * 2)) {
if ($page < 1 + ($adjacents * 2)) {
for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>";
$pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$counter'>$counter</a></li>";
}
$pagination .= "<li class='disabled'><a href='#'>...</a></li>";
$pagination .= "<li><a href='{$url}$lpm1'>$lpm1</a></li>";
$pagination .= "<li><a href='{$url}$lastpage'>$lastpage</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lpm1'>$lpm1</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lastpage'>$lastpage</a></li>";
} elseif ($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2)) {
$pagination .= "<li><a href='{$url}1'>1</a></li>";
$pagination .= "<li><a href='{$url}2'>2</a></li>";
$pagination .= "<li class='disabled'><a href='#'>...</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}1'>1</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}2'>2</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>";
$pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$counter'>$counter</a></li>";
}
$pagination .= "<li class='disabled'><a href='#'>...</a></li>";
$pagination .= "<li><a href='{$url}$lpm1'>$lpm1</a></li>";
$pagination .= "<li><a href='{$url}$lastpage'>$lastpage</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lpm1'>$lpm1</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lastpage'>$lastpage</a></li>";
} else {
$pagination .= "<li><a href='{$url}1'>1</a></li>";
$pagination .= "<li><a href='{$url}2'>2</a></li>";
$pagination .= "<li><a href='#'>...</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}1'>1</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}2'>2</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='#'>...</a></li>";
for ($counter = $lastpage - (2 + ($adjacents * 2)); $counter <= $lastpage; $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a class='disabled'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link disabled'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$counter'>$counter</a></li>";
}
}
}
if ($page < $counter - 1) {
$pagination .= "<li><a href='{$url}$next'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li><a href='{$url}$lastpage'>" . Lang::T('Last') . "</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$next'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lastpage'>" . Lang::T('Last') . "</a></li>";
} else {
$pagination .= "<li class='disabled'><a class='disabled'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li class='disabled'><a class='disabled'>" . Lang::T('Last') . "</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link disabled'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link disabled'>" . Lang::T('Last') . "</a></li>";
}
$pagination .= "</ul>";
$pagination = '<nav>' . $pagination . '</nav>';
$gen = array("startpoint" => $startpoint, "limit" => $limit, "found" => $totalReq, "page" => $page, "lastpage" => $lastpage, "contents" => $pagination);
return $gen;
@ -209,13 +278,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 +305,60 @@ class Paginator
$startpoint = ($page * $limit) - $limit;
if ($lastpage >= 1) {
$pagination .= '<ul class="pagination pagination-sm">';
$pagination .= '<ul class="pagination">';
if ($lastpage < 7 + ($adjacents * 2)) {
for ($counter = 1; $counter <= $lastpage; $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>";
$pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$counter'>$counter</a></li>";
}
} elseif ($lastpage > 5 + ($adjacents * 2)) {
if ($page < 1 + ($adjacents * 2)) {
for ($counter = 1; $counter < 4 + ($adjacents * 2); $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>";
$pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$counter'>$counter</a></li>";
}
$pagination .= "<li class='disabled'><a href='#'>...</a></li>";
$pagination .= "<li><a href='{$url}$lpm1'>$lpm1</a></li>";
$pagination .= "<li><a href='{$url}$lastpage'>$lastpage</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lpm1'>$lpm1</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lastpage'>$lastpage</a></li>";
} elseif ($lastpage - ($adjacents * 2) > $page && $page > ($adjacents * 2)) {
$pagination .= "<li><a href='{$url}1'>1</a></li>";
$pagination .= "<li><a href='{$url}2'>2</a></li>";
$pagination .= "<li class='disabled'><a href='#'>...</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}1'>1</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}2'>2</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
for ($counter = $page - $adjacents; $counter <= $page + $adjacents; $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a href='javascript:void(0);'>$counter</a></li>";
$pagination .= "<li class='page-item active'><a class='page-link' href='javascript:void(0);'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$counter'>$counter</a></li>";
}
$pagination .= "<li class='disabled'><a href='#'>...</a></li>";
$pagination .= "<li><a href='{$url}$lpm1'>$lpm1</a></li>";
$pagination .= "<li><a href='{$url}$lastpage'>$lastpage</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-link' href='#'>...</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lpm1'>$lpm1</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lastpage'>$lastpage</a></li>";
} else {
$pagination .= "<li><a href='{$url}1'>1</a></li>";
$pagination .= "<li><a href='{$url}2'>2</a></li>";
$pagination .= "<li><a href='#'>...</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}1'>1</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}2'>2</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='#'>...</a></li>";
for ($counter = $lastpage - (2 + ($adjacents * 2)); $counter <= $lastpage; $counter++) {
if ($counter == $page)
$pagination .= "<li class='active'><a class='disabled'>$counter</a></li>";
$pagination .= "<li class='page-item active'><a class='page-item disabled'>$counter</a></li>";
else
$pagination .= "<li><a href='{$url}$counter'>$counter</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$counter'>$counter</a></li>";
}
}
}
if ($page < $counter - 1) {
$pagination .= "<li><a href='{$url}$next'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li><a href='{$url}$lastpage'>" . Lang::T('Last') . "</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$next'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li class='page-item'><a class='page-link' href='{$url}$lastpage'>" . Lang::T('Last') . "</a></li>";
} else {
$pagination .= "<li class='disabled'><a class='disabled'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li class='disabled'><a class='disabled'>" . Lang::T('Last') . "</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-item disabled'>" . Lang::T('Next') . "</a></li>";
$pagination .= "<li class='page-item disabled'><a class='page-item disabled'>" . Lang::T('Last') . "</a></li>";
}
$pagination .= "</ul>";
$pagination = '<nav>' . $pagination . '</nav>';
$gen = array("startpoint" => $startpoint, "limit" => $limit, "found" => $totalReq, "page" => $page, "lastpage" => $lastpage, "contents" => $pagination);
return $gen;

View File

@ -301,7 +301,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 +314,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

@ -8,15 +8,16 @@
class User
{
public static function getID(){
public static function getID()
{
global $db_password;
if(isset($_SESSION['uid']) && !empty($_SESSION['uid'])){
if (isset($_SESSION['uid']) && !empty($_SESSION['uid'])) {
return $_SESSION['uid'];
}else if(isset($_COOKIE['uid'])){
} else if (isset($_COOKIE['uid'])) {
// id.time.sha1
$tmp = explode('.',$_COOKIE['uid']);
if(sha1($tmp[0].'.'.$tmp[1].'.'.$db_password)==$tmp[2]){
if(time()-$tmp[1] < 86400*30){
$tmp = explode('.', $_COOKIE['uid']);
if (sha1($tmp[0] . '.' . $tmp[1] . '.' . $db_password) == $tmp[2]) {
if (time() - $tmp[1] < 86400 * 30) {
$_SESSION['uid'] = $tmp[0];
return $tmp[0];
}
@ -25,35 +26,175 @@ class User
return 0;
}
public static function setCookie($uid){
global $db_password;
if(isset($uid)){
$time = time();
setcookie('uid', $uid.'.'.$time.'.'.sha1($uid.'.'.$time.'.'.$db_password), time()+86400*30);
}
}
public static function removeCookie(){
if(isset($_COOKIE['uid'])){
setcookie('uid', '', time()-86400);
}
}
public static function _info()
public static function getBills($id = 0)
{
$id = User::getID();
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) {
$id = User::getID();
if (!$id) {
return '';
}
}
$f = ORM::for_table('tbl_customers_fields')->where('field_name', $name)->where('customer_id', $id)->find_one();
if (!$f) {
$f = ORM::for_table('tbl_customers_fields')->create();
$f->customer_id = $id;
$f->field_name = $name;
$f->field_value = $value;
$f->save();
$result = $f->id();
if ($result) {
return $result;
}
} else {
$f->field_value = $value;
$f->save();
return $f['id'];
}
return 0;
}
public static function getAttribute($name, $id = 0)
{
if (!$id) {
$id = User::getID();
if (!$id) {
return [];
}
}
$f = ORM::for_table('tbl_customers_fields')->where('field_name', $name)->where('customer_id', $id)->find_one();
if ($f) {
return $f['field_value'];
}
return '';
}
public static function getAttributes($endWith, $id = 0)
{
if (!$id) {
$id = User::getID();
if (!$id) {
return [];
}
}
$attrs = [];
$f = ORM::for_table('tbl_customers_fields')->where_like('field_name', "%$endWith")->where('customer_id', $id)->find_many();
if ($f) {
foreach ($f as $k) {
$attrs[$k['field_name']] = $k['field_value'];
}
return $attrs;
}
return [];
}
public static function setCookie($uid)
{
global $db_password;
if (isset($uid)) {
$time = time();
setcookie('uid', $uid . '.' . $time . '.' . sha1($uid . '.' . $time . '.' . $db_password), time() + 86400 * 30);
}
}
public static function removeCookie()
{
if (isset($_COOKIE['uid'])) {
setcookie('uid', '', time() - 86400);
}
}
public static function _info($id = 0)
{
if (!$id) {
$id = User::getID();
}
$d = ORM::for_table('tbl_customers')->find_one($id);
if(empty($d['username'])){
if (empty($d['username'])) {
r2(U . 'logout', 'd', '');
}
return $d;
}
public static function _billing()
public static function _billing($id = 0)
{
$id = User::getID();
$d = ORM::for_table('tbl_user_recharges')->where('customer_id', $id)->find_many();
if (!$id) {
$id = User::getID();
}
$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('plan_type')
->select('tbl_user_recharges.routers', 'routers')
->select('tbl_user_recharges.type', 'type')
->select('admin_id')
->select('prepaid')
->where('customer_id', $id)
->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

@ -78,9 +78,9 @@ $ui->assign('_domain', str_replace('www.', '', parse_url(APP_URL, PHP_URL_HOST))
$ui->assign('_url', APP_URL . '/index.php?_route=');
$ui->assign('_path', __DIR__);
$ui->assign('_c', $config);
$ui->assign('UPLOAD_PATH', $UPLOAD_PATH);
$ui->assign('CACHE_PATH', $CACHE_PATH);
$ui->assign('PAGES_PATH', $PAGES_PATH);
$ui->assign('UPLOAD_PATH', str_replace($root_path, '', $UPLOAD_PATH));
$ui->assign('CACHE_PATH', str_replace($root_path, '', $CACHE_PATH));
$ui->assign('PAGES_PATH', str_replace($root_path, '', $PAGES_PATH));
$ui->assign('_system_menu', 'dashboard');
function _msglog($type, $msg)

View File

@ -5,6 +5,10 @@
* by https://t.me/ibnux
**/
if(Admin::getID()){
r2(U.'dashboard', "s", Lang::T("You are already logged in"));
}
if (isset($routes['1'])) {
$do = $routes['1'];
} else {
@ -22,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

@ -38,10 +38,18 @@ switch ($action) {
case 'plan':
$server = _post('server');
$jenis = _post('jenis');
if($server=='radius'){
$d = ORM::for_table('tbl_plans')->where('is_radius', 1)->where('type', $jenis)->where('enabled', '1')->find_many();
if(in_array($admin['user_type'], array('SuperAdmin', 'Admin'))){
if($server=='radius'){
$d = ORM::for_table('tbl_plans')->where('is_radius', 1)->where('type', $jenis)->find_many();
}else{
$d = ORM::for_table('tbl_plans')->where('routers', $server)->where('type', $jenis)->find_many();
}
}else{
$d = ORM::for_table('tbl_plans')->where('routers', $server)->where('type', $jenis)->where('enabled', '1')->find_many();
if($server=='radius'){
$d = ORM::for_table('tbl_plans')->where('is_radius', 1)->where('type', $jenis)->where('enabled', '1')->find_many();
}else{
$d = ORM::for_table('tbl_plans')->where('routers', $server)->where('type', $jenis)->where('enabled', '1')->find_many();
}
}
$ui->assign('d', $d);

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

@ -12,54 +12,32 @@ $ui->assign('_system_menu', 'customers');
$action = $routes['1'];
$ui->assign('_admin', $admin);
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");
_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');
@ -68,49 +46,166 @@ switch ($action) {
header("Content-type: text/csv");
header('Content-Disposition: attachment;filename="phpnuxbill_customers_' . date('Y-m-d_H_i') . '.csv"');
header('Content-Transfer-Encoding: binary');
$headers = [
'id',
'username',
'fullname',
'address',
'phonenumber',
'email',
'balance',
'service_type',
];
if (!$h) {
echo '"' . implode('","', $headers) . "\"\n";
$h = true;
}
foreach ($cs as $c) {
$ks = [];
$vs = [];
foreach ($c as $k => $v) {
$ks[] = $k;
$vs[] = $v;
}
if (!$h) {
echo '"' . implode('";"', $ks) . "\"\n";
$h = true;
}
echo '"' . implode('";"', $vs) . "\"\n";
$row = [
$c['id'],
$c['username'],
$c['fullname'],
$c['address'],
$c['phonenumber'],
$c['email'],
$c['balance'],
$c['service_type'],
];
echo '"' . implode('","', $row) . "\"\n";
}
break;
//case csv-prepaid can be moved later to (plan.php) php file dealing with prepaid users
case 'csv-prepaid':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
}
$cs = ORM::for_table('tbl_customers')
->select('tbl_customers.id', 'id')
->select('tbl_customers.username', 'username')
->select('fullname')
->select('address')
->select('phonenumber')
->select('email')
->select('balance')
->select('service_type')
->select('namebp')
->select('routers')
->select('status')
->select('method', 'Payment')
->join('tbl_user_recharges', array('tbl_customers.id', '=', 'tbl_user_recharges.customer_id'))
->order_by_asc('tbl_customers.id')
->find_array();
$h = false;
set_time_limit(-1);
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-type: text/csv");
header('Content-Disposition: attachment;filename="phpnuxbill_prepaid_users' . date('Y-m-d_H_i') . '.csv"');
header('Content-Transfer-Encoding: binary');
$headers = [
'id',
'username',
'fullname',
'address',
'phonenumber',
'email',
'balance',
'service_type',
'namebp',
'routers',
'status',
'Payment'
];
if (!$h) {
echo '"' . implode('","', $headers) . "\"\n";
$h = true;
}
foreach ($cs as $c) {
$row = [
$c['id'],
$c['username'],
$c['fullname'],
$c['address'],
$c['phonenumber'],
$c['email'],
$c['balance'],
$c['service_type'],
$c['namebp'],
$c['routers'],
$c['status'],
$c['Payment']
];
echo '"' . implode('","', $row) . "\"\n";
}
break;
case 'add':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) {
_alert(Lang::T('You do not have permission to access this page'),'danger', "dashboard");
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;
case 'recharge':
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) {
_alert(Lang::T('You do not have permission to access this page'),'danger', "dashboard");
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) {
if (Package::rechargeUser($id_customer, $b['routers'], $b['plan_id'], "Recharge", $admin['fullname'])) {
r2(U . 'customers/view/' . $id_customer, 's', 'Success Recharge Customer');
} else {
r2(U . 'customers/view/' . $id_customer, 'e', 'Customer plan is inactive');
$gateway = 'Recharge';
$channel = $admin['fullname'];
$cust = User::_info($id_customer);
$plan = ORM::for_table('tbl_plans')->find_one($b['plan_id']);
list($bills, $add_cost) = User::getBills($id_customer);
if ($using == 'balance' && $config['enable_balance'] == 'yes') {
if (!$cust) {
r2(U . 'plan/recharge', 'e', Lang::T('Customer not found'));
}
if (!$plan) {
r2(U . 'plan/recharge', 'e', Lang::T('Plan not found'));
}
if ($cust['balance'] < ($plan['price'] + $add_cost)) {
r2(U . 'plan/recharge', 'e', Lang::T('insufficient balance'));
}
$gateway = 'Recharge Balance';
}
if ($using == 'zero') {
$zero = 1;
$gateway = 'Recharge Zero';
}
$ui->assign('bills', $bills);
$ui->assign('add_cost', $add_cost);
$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");
_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']);
@ -137,35 +232,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);
@ -177,45 +273,35 @@ switch ($action) {
$customFields = ORM::for_table('tbl_customers_fields')
->where('customer_id', $customer['id'])
->find_many();
$v = $routes['3'];
if (empty($v) || $v == '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");
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
@ -225,17 +311,18 @@ switch ($action) {
if ($d) {
$ui->assign('d', $d);
$ui->assign('customFields', $customFields);
$ui->assign('xheader', $leafletpickerHeader);
$ui->display('customers-edit.tpl');
} else {
r2(U . 'customers/list', 'e', $_L['Account_Not_Found']);
r2(U . 'customers/list', 'e', Lang::T('Account Not Found'));
}
break;
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'];
$id = $routes['2'];
run_hook('delete_customer'); #HOOK
$d = ORM::for_table('tbl_customers')->find_one($id);
if ($d) {
@ -274,7 +361,8 @@ switch ($action) {
} catch (Throwable $e) {
}
try {
$c->delete();
if ($c)
$c->delete();
} catch (Exception $e) {
} catch (Throwable $e) {
}
@ -293,6 +381,8 @@ switch ($action) {
$address = _post('address');
$phonenumber = _post('phonenumber');
$service_type = _post('service_type');
$account_type = _post('account_type');
$coordinates = _post('coordinates');
//post Customers Attributes
$custom_field_names = (array) $_POST['custom_field_name'];
$custom_field_values = (array) $_POST['custom_field_value'];
@ -320,11 +410,13 @@ switch ($action) {
$d->password = $password;
$d->pppoe_password = $pppoe_password;
$d->email = $email;
$d->account_type = $account_type;
$d->fullname = $fullname;
$d->address = $address;
$d->created_by = $admin['id'];
$d->phonenumber = Lang::phoneFormat($phonenumber);
$d->service_type = $service_type;
$d->coordinates = $coordinates;
$d->save();
// Retrieve the customer ID of the newly created customer
@ -354,12 +446,14 @@ switch ($action) {
case 'edit-post':
$username = Lang::phoneFormat(_post('username'));
$fullname = _post('fullname');
$account_type = _post('account_type');
$password = _post('password');
$pppoe_password = _post('pppoe_password');
$email = _post('email');
$address = _post('address');
$phonenumber = Lang::phoneFormat(_post('phonenumber'));
$service_type = _post('service_type');
$coordinates = _post('coordinates');
run_hook('edit_customer'); #HOOK
$msg = '';
if (Validator::Length($username, 35, 2) == false) {
@ -387,8 +481,8 @@ switch ($action) {
}
$oldusername = $d['username'];
$oldPppoePassword = $d['password'];
$oldPassPassword = $d['pppoe_password'];
$oldPppoePassword = $d['password'];
$oldPassPassword = $d['pppoe_password'];
$userDiff = false;
$pppoeDiff = false;
$passDiff = false;
@ -416,9 +510,11 @@ switch ($action) {
$d->pppoe_password = $pppoe_password;
$d->fullname = $fullname;
$d->email = $email;
$d->account_type = $account_type;
$d->address = $address;
$d->phonenumber = $phonenumber;
$d->service_type = $service_type;
$d->coordinates = $coordinates;
$d->save();
@ -462,6 +558,7 @@ switch ($action) {
// Delete the Customers Attributes with the given field name
ORM::for_table('tbl_customers_fields')
->where('field_name', $fieldName)
->where('customer_id', $id)
->delete_many();
}
}
@ -495,12 +592,19 @@ switch ($action) {
}
}
}
r2(U . 'customers/list', 's', 'User Updated Successfully');
r2(U . 'customers/view/' . $id, 's', 'User Updated Successfully');
} else {
r2(U . 'customers/edit/' . $id, 'e', $msg);
}
break;
default:
r2(U . 'customers/list', 'e', 'action not defined');
run_hook('list_customers'); #HOOK
$query = ORM::for_table('tbl_customers')->order_by_asc('username');
$d = $query->findMany();
$ui->assign('xheader', '<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.11.3/css/jquery.dataTables.min.css">');
$ui->assign('d', $d);
$ui->display('customers.tpl');
break;
}

View File

@ -16,13 +16,18 @@ $first_day_month = date('Y-m-01');
$mdate = date('Y-m-d');
$month_n = date('n');
$iday = ORM::for_table('tbl_transactions')->where('recharged_on', $mdate)->sum('price');
$iday = ORM::for_table('tbl_transactions')
->where('recharged_on', $mdate)
->where_not_equal('method', 'Customer - Balance')
->where_not_equal('method', 'Recharge Balance - Administrator')
->sum('price');
if ($iday == '') {
$iday = '0.00';
}
$ui->assign('iday', $iday);
$imonth = ORM::for_table('tbl_transactions')->where_gte('recharged_on', $first_day_month)->where_lte('recharged_on', $mdate)->sum('price');
$imonth = ORM::for_table('tbl_transactions')->where_not_equal('method', 'Customer - Balance')->where_not_equal('method', 'Recharge Balance - Administrator')->where_gte('recharged_on', $first_day_month)->where_lte('recharged_on', $mdate)->sum('price');
if ($imonth == '') {
$imonth = '0.00';
}
@ -49,13 +54,10 @@ $ui->assign('c_all', $c_all);
if ($config['hide_uet'] != 'yes') {
//user expire
$paginator = Paginator::build(ORM::for_table('tbl_user_recharges'));
$expire = ORM::for_table('tbl_user_recharges')
$query = ORM::for_table('tbl_user_recharges')
->where_lte('expiration', $mdate)
->offset($paginator['startpoint'])
->limit($paginator['limit'])
->order_by_desc('expiration')
->find_many();
->order_by_desc('expiration');
$expire = Paginator::findMany($query);
// Get the total count of expired records for pagination
$totalCount = ORM::for_table('tbl_user_recharges')
@ -66,7 +68,6 @@ if ($config['hide_uet'] != 'yes') {
$paginator['total_count'] = $totalCount;
// Assign the pagination HTML to the template variable
$ui->assign('paginator', $paginator);
$ui->assign('expire', $expire);
}
@ -144,6 +145,8 @@ if (file_exists($cacheMSfile) && time() - filemtime($cacheMSfile) < 43200) {
->select_expr('MONTH(recharged_on)', 'month')
->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')
->group_by_expr('MONTH(recharged_on)')
->find_many();

View File

@ -4,5 +4,10 @@
* by https://t.me/ibnux
**/
r2(APP_URL.'/index.php?_route=dashboard');
if(Admin::getID()){
r2(U.'dashboard');
}if(User::getID()){
r2(U.'home');
}else{
r2(U.'login');
}

View File

@ -62,10 +62,11 @@ switch ($action) {
$title = ' Reports [' . $mdate . ']';
$title = str_replace('-', ' ', $title);
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
if (file_exists($UPLOAD_PATH . '/logo.png')) {
$logo = $UPLOAD_PATH . '/logo.png';
$logo = $UPLOAD_URL_PATH . '/logo.png';
} else {
$logo = $UPLOAD_PATH . '/logo.default.png';
$logo = $UPLOAD_URL_PATH . '/logo.default.png';
}
if ($x) {
@ -169,7 +170,7 @@ $style
$html
EOF;
$mpdf->WriteHTML($nhtml);
$mpdf->Output(date('Y-m-d') . Package::_raid(4) . '.pdf', 'D');
$mpdf->Output(date('Ymd_His') . '.pdf', 'D');
} else {
echo 'No Data';
}
@ -234,10 +235,12 @@ EOF;
$title = ' Reports [' . $mdate . ']';
$title = str_replace('-', ' ', $title);
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
if (file_exists($UPLOAD_PATH . '/logo.png')) {
$logo = $UPLOAD_PATH . '/logo.png';
$logo = $UPLOAD_URL_PATH . '/logo.png';
} else {
$logo = $UPLOAD_PATH . '/logo.default.png';
$logo = $UPLOAD_URL_PATH . '/logo.default.png';
}
if ($x) {
@ -341,7 +344,7 @@ $style
$html
EOF;
$mpdf->WriteHTML($nhtml);
$mpdf->Output(date('Y-m-d') . Package::_raid(4) . '.pdf', 'D');
$mpdf->Output(date('Ymd_His') . '.pdf', 'D');
} else {
echo 'No Data';
}

View File

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

View File

@ -5,6 +5,10 @@
* by https://t.me/ibnux
**/
if(User::getID()){
r2(U.'home');
}
if (isset($routes['1'])) {
$do = $routes['1'];
} else {

View File

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

View File

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

View File

@ -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
@ -37,7 +32,7 @@ switch ($action) {
}
$ui->assign('_title', 'Top Up');
$ui->assign('_system_menu', 'balance');
$plans_balance = ORM::for_table('tbl_plans')->where('enabled', '1')->where('type', 'Balance')->where('allow_purchase', 'yes')->find_many();
$plans_balance = ORM::for_table('tbl_plans')->where('enabled', '1')->where('type', 'Balance')->where('prepaid', 'yes')->find_many();
$ui->assign('plans_balance', $plans_balance);
$ui->display('user-orderBalance.tpl');
break;
@ -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('allow_purchase', 'yes')->find_many();
$radius_hotspot = ORM::for_table('tbl_plans')->where('enabled', '1')->where('is_radius', 1)->where('type', 'Hotspot')->where('allow_purchase', 'yes')->find_many();
$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('allow_purchase', 'yes')->find_many();
$plans_hotspot = ORM::for_table('tbl_plans')->where('enabled', '1')->where_in('routers', $rs)->where('is_radius', 0)->where('type', 'Hotspot')->where('allow_purchase', 'yes')->find_many();
$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('allow_purchase', 'yes')->find_many();
$radius_hotspot = ORM::for_table('tbl_plans')->where('enabled', '1')->where('is_radius', 1)->where('type', 'Hotspot')->where('allow_purchase', 'yes')->find_many();
$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('allow_purchase', 'yes')->find_many();
$plans_hotspot = ORM::for_table('tbl_plans')->where('enabled', '1')->where('is_radius', 0)->where('type', 'Hotspot')->where('allow_purchase', 'yes')->find_many();
$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') {
@ -114,7 +113,7 @@ switch ($action) {
run_hook('customer_check_payment_status'); #HOOK
include $PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $trx['gateway'] . '.php';
call_user_func($trx['gateway'] . '_validate_config');
call_user_func($config['payment_gateway'] . '_get_status', $trx, $user);
call_user_func($trx['gateway'] . '_get_status', $trx, $user);
} else if ($routes['3'] == 'cancel') {
run_hook('customer_cancel_payment'); #HOOK
$trx->pg_paid_response = '{}';
@ -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);
@ -142,9 +141,13 @@ switch ($action) {
$ui->display('user-orderView.tpl');
break;
case 'pay':
if ($_c['enable_balance'] != 'yes' && $config['allow_balance_transfer'] != 'yes') {
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"));
@ -152,19 +155,18 @@ switch ($action) {
if (!$plan['enabled']) {
r2(U . "home", 'e', 'Plan is not exists');
}
if ($plan['allow_purchase'] != 'yes') {
r2(U . "home", 'e', 'Cannot recharge this plan');
}
if ($routes['2'] == 'radius') {
$router_name = 'radius';
} else {
$router_name = $plan['routers'];
}
list($bills, $add_cost) = User::getBills($id_customer);
if ($plan && $plan['enabled'] && $user['balance'] >= $plan['price']) {
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);
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'] .
@ -176,7 +178,7 @@ switch ($action) {
}
break;
case 'send':
if ($_c['enable_balance'] != 'yes') {
if ($config['enable_balance'] != 'yes') {
r2(U . "order/package", 'e', Lang::T("Balance not enabled"));
}
$ui->assign('_title', Lang::T('Buy for friend'));
@ -188,9 +190,6 @@ switch ($action) {
if (!$plan['enabled']) {
r2(U . "home", 'e', 'Plan is not exists');
}
if ($plan['allow_purchase'] != 'yes') {
r2(U . "home", 'e', 'Cannot recharge this plan');
}
if ($routes['2'] == 'radius') {
$router_name = 'radius';
} else {
@ -198,6 +197,12 @@ switch ($action) {
}
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'));
}
@ -215,7 +220,8 @@ switch ($action) {
if ($active && $active['plan_id'] != $plan['id']) {
r2(U . "order/package", 'e', Lang::T("Target has active plan, different with current plant.") . " [ <b>$active[namebp]</b> ]");
}
if (Package::rechargeUser($target['id'], $router_name, $plan['id'], $user['fullname'], 'Balance')) {
$result = Package::rechargeUser($target['id'], $router_name, $plan['id'], $user['username'], 'Balance');
if (!empty($result)) {
// if success, then get the balance
Balance::min($user['id'], $plan['price']);
//sender
@ -233,6 +239,7 @@ switch ($action) {
$d->paid_date = date('Y-m-d H:i:s');
$d->expired_date = date('Y-m-d H:i:s');
$d->pg_url_payment = 'balance';
$d->trx_invoice = $result;
$d->status = 2;
$d->save();
$trx_id = $d->id();
@ -251,6 +258,7 @@ switch ($action) {
$d->paid_date = date('Y-m-d H:i:s');
$d->expired_date = date('Y-m-d H:i:s');
$d->pg_url_payment = 'balance';
$d->trx_invoice = $result;
$d->status = 2;
$d->save();
r2(U . "order/view/$trx_id", 's', Lang::T("Success to send package"));
@ -266,19 +274,49 @@ switch ($action) {
$ui->assign('plan', $plan);
$ui->display('user-sendPlan.tpl');
break;
case 'buy':
case 'gateway':
$ui->assign('_title', Lang::T('Select Payment Gateway'));
$ui->assign('_system_menu', 'package');
if (strpos($user['email'], '@') === false) {
r2(U . 'accounts/profile', 'e', Lang::T("Please enter your email address"));
}
if ($config['payment_gateway'] == 'none') {
r2(U . 'home', 'e', Lang::T("No Payment Gateway Available"));
$pgs = array_values(explode(',', $config['payment_gateway']));
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 (!file_exists($PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $config['payment_gateway'] . '.php')) {
r2(U . 'home', 'e', Lang::T("No Payment Gateway Available"));
if (count($pgs) > 1) {
$ui->assign('pgs', $pgs);
//$ui->assign('pgs', $pgs);
$ui->assign('route2', $routes[2]);
$ui->assign('route3', $routes[3]);
//$ui->assign('plan', $plan);
$ui->display('user-selectGateway.tpl');
break;
} 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 {
$_POST['gateway'] = $pgs[0];
}
}
case 'buy':
$gateway = _post('gateway');
if (empty($gateway) && !empty($_SESSION['gateway'])) {
$gateway = $_SESSION['gateway'];
} else if (!empty($gateway)) {
$_SESSION['gateway'] = $gateway;
}
if (empty($gateway)) {
r2(U . 'order/gateway/' . $routes[2] . '/' . $routes[3], 'w', Lang::T("Please select Payment Gateway"));
}
run_hook('customer_buy_plan'); #HOOK
include $PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $config['payment_gateway'] . '.php';
call_user_func($config['payment_gateway'] . '_validate_config');
include $PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $gateway . '.php';
call_user_func($gateway . '_validate_config');
if ($routes['2'] == 'radius') {
$router['id'] = 0;
@ -289,7 +327,7 @@ switch ($action) {
$router['id'] = 0;
$router['name'] = 'balance';
}
$plan = ORM::for_table('tbl_plans')->where('enabled', '1')->where('allow_purchase', 'yes')->find_one($routes['3']);
$plan = ORM::for_table('tbl_plans')->where('enabled', '1')->find_one($routes['3']);
if (empty($router) || empty($plan)) {
r2(U . "order/package", 'e', Lang::T("Plan Not found"));
}
@ -301,7 +339,7 @@ switch ($action) {
if ($d['pg_url_payment']) {
r2(U . "order/view/" . $d['id'], 'w', Lang::T("You already have unpaid transaction, cancel it or pay it."));
} else {
if ($config['payment_gateway'] == $d['gateway']) {
if ($gateway == $d['gateway']) {
$id = $d['id'];
} else {
$d->status = 4;
@ -309,27 +347,53 @@ switch ($action) {
}
}
}
$add_cost = 0;
if ($router['name'] != 'balance') {
list($bills, $add_cost) = User::getBills($id_customer);
}
if (empty($id)) {
$d = ORM::for_table('tbl_payment_gateway')->create();
$d->username = $user['username'];
$d->gateway = $config['payment_gateway'];
$d->gateway = $gateway;
$d->plan_id = $plan['id'];
$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);
} else {
$d->price = ($add_inv + $add_cost);
}
} else {
$d->price = ($plan['price'] + $add_cost);
}
//$d->price = ($plan['price'] + $add_cost);
$d->created_date = date('Y-m-d H:i:s');
$d->status = 1;
$d->save();
$id = $d->id();
} else {
$d->username = $user['username'];
$d->gateway = $config['payment_gateway'];
$d->gateway = $gateway;
$d->plan_id = $plan['id'];
$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);
} else {
$d->price = ($add_inv + $add_cost);
}
} else {
$d->price = ($plan['price'] + $add_cost);
}
//$d->price = ($plan['price'] + $add_cost);
$d->created_date = date('Y-m-d H:i:s');
$d->status = 1;
$d->save();
@ -337,7 +401,7 @@ switch ($action) {
if (!$id) {
r2(U . "order/package/" . $d['id'], 'e', Lang::T("Failed to create Transaction.."));
} else {
call_user_func($config['payment_gateway'] . '_create_transaction', $d, $user);
call_user_func($gateway . '_create_transaction', $d, $user);
}
break;
default:

View File

@ -8,9 +8,35 @@
_admin();
$ui->assign('_system_menu', 'paymentgateway');
$action = alphanumeric($routes['1']);
$action = alphanumeric($routes[1]);
$ui->assign('_admin', $admin);
if ($action == 'delete') {
$pg = alphanumeric($routes[2]);
if (file_exists($PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $pg . '.php')) {
deleteFile($PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR, $pg);
}
r2(U . 'paymentgateway', 's', Lang::T('Payment Gateway Deleted'));
}
if (_post('save') == 'actives') {
$pgs = '';
if(is_array($_POST['pgs'])){
$pgs = implode(',', $_POST['pgs']);
}
$d = ORM::for_table('tbl_appconfig')->where('setting', 'payment_gateway')->find_one();
if ($d) {
$d->value = $pgs;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'payment_gateway';
$d->value = $pgs;
$d->save();
}
r2(U . 'paymentgateway', 's', Lang::T('Payment Gateway saved successfully'));
}
if (file_exists($PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $action . '.php')) {
include $PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $action . '.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
@ -36,22 +62,22 @@ if (file_exists($PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $action . '.php'))
$pgs[] = str_replace('.php', '', $file);
}
}
if (isset($_POST['payment_gateway'])) {
$payment_gateway = _post('payment_gateway');
$d = ORM::for_table('tbl_appconfig')->where('setting', 'payment_gateway')->find_one();
if ($d) {
$d->value = $payment_gateway;
$d->save();
} else {
$d = ORM::for_table('tbl_appconfig')->create();
$d->setting = 'payment_gateway';
$d->value = $payment_gateway;
$d->save();
}
r2(U . 'paymentgateway', 's', Lang::T('Payment Gateway saved successfully'));
}
$ui->assign('_title', 'Payment Gateway Settings');
$ui->assign('pgs', $pgs);
$ui->assign('actives', explode(',', $config['payment_gateway']));
$ui->display('paymentgateway.tpl');
}
}
function deleteFile($path, $name)
{
$files = scandir($path);
foreach ($files as $file) {
if (is_file($path . $file) && strpos($file, $name) !== false) {
unlink($path . $file);
} else if (is_dir($path . $file) && !in_array($file, ['.', '..'])) {
deleteFile($path . $file . DIRECTORY_SEPARATOR, $name);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -32,9 +32,55 @@ if (file_exists($cache) && time() - filemtime($cache) < (24 * 60 * 60)) {
file_put_contents($cache, $data);
$json = json_decode($data, true);
}
switch ($action) {
case 'delete':
if (!is_writeable($CACHE_PATH)) {
r2(U . "pluginmanager", 'e', 'Folder cache/ is not writable');
}
if (!is_writeable($PLUGIN_PATH)) {
r2(U . "pluginmanager", 'e', 'Folder plugin/ is not writable');
}
set_time_limit(-1);
$tipe = $routes['2'];
$plugin = $routes['3'];
$file = $CACHE_PATH . DIRECTORY_SEPARATOR . $plugin . '.zip';
if (file_exists($file)) unlink($file);
if ($tipe == 'plugin') {
foreach ($json['plugins'] as $plg) {
if ($plg['id'] == $plugin) {
$fp = fopen($file, 'w+');
$ch = curl_init($plg['github'] . '/archive/refs/heads/master.zip');
curl_setopt($ch, CURLOPT_POST, 0);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_exec($ch);
curl_close($ch);
fclose($fp);
$zip = new ZipArchive();
$zip->open($file);
$zip->extractTo($CACHE_PATH);
$zip->close();
$folder = $CACHE_PATH . File::pathFixer('/' . $plugin . '-main/');
if (!file_exists($folder)) {
$folder = $CACHE_PATH . File::pathFixer('/' . $plugin . '-master/');
}
if (!file_exists($folder)) {
r2(U . "pluginmanager", 'e', 'Extracted Folder is unknown');
}
scanAndRemovePath($folder, $PLUGIN_PATH . DIRECTORY_SEPARATOR);
File::deleteFolder($folder);
unlink($file);
r2(U . "pluginmanager", 's', 'Plugin ' . $plugin . ' has been deleted');
break;
}
}
break;
}
break;
case 'install':
if (!is_writeable($CACHE_PATH)) {
r2(U . "pluginmanager", 'e', 'Folder cache/ is not writable');
@ -45,7 +91,7 @@ switch ($action) {
set_time_limit(-1);
$tipe = $routes['2'];
$plugin = $routes['3'];
$file = $CACHE_PATH . File::pathFixer('/') . $plugin . '.zip';
$file = $CACHE_PATH . DIRECTORY_SEPARATOR . $plugin . '.zip';
if (file_exists($file)) unlink($file);
if ($tipe == 'plugin') {
foreach ($json['plugins'] as $plg) {
@ -127,3 +173,24 @@ switch ($action) {
$ui->assign('pgs', $json['payment_gateway']);
$ui->display('plugin-manager.tpl');
}
function scanAndRemovePath($source, $target)
{
$files = scandir($source);
foreach ($files as $file) {
if (is_file($source . $file)) {
if(file_exists($target.$file)){
unlink($target . $file);
}
} else if (is_dir($source . $file) && !in_array($file, ['.', '..'])) {
scanAndRemovePath($source. $file. DIRECTORY_SEPARATOR, $target. $file. DIRECTORY_SEPARATOR);
if(file_exists($target.$file)){
rmdir($target . $file);
}
}
}
if(file_exists($target)){
rmdir($target);
}
}

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;
@ -119,15 +119,14 @@ switch ($action) {
$name = _post('name');
if ($name != '') {
$paginator = Paginator::build(ORM::for_table('tbl_plans'), ['name_plan' => '%' . $name . '%', 'type' => 'Hotspot'], $name);
$d = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'Hotspot')->where_like('tbl_plans.name_plan', '%' . $name . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many();
$query = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'Hotspot')->where_like('tbl_plans.name_plan', '%' . $name . '%');
$d = Paginator::findMany($query, ['name' => $name]);
} else {
$paginator = Paginator::build(ORM::for_table('tbl_plans'), ['type' => 'Hotspot']);
$d = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'Hotspot')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many();
$query = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'Hotspot');
$d = Paginator::findMany($query);
}
$ui->assign('d', $d);
$ui->assign('paginator', $paginator);
run_hook('view_list_plans'); #HOOK
$ui->display('hotspot.tpl');
break;
@ -142,7 +141,7 @@ switch ($action) {
break;
case 'edit':
$id = $routes['2'];
$id = $routes['2'];
$d = ORM::for_table('tbl_plans')->find_one($id);
if ($d) {
$ui->assign('d', $d);
@ -153,12 +152,12 @@ switch ($action) {
run_hook('view_edit_plan'); #HOOK
$ui->display('hotspot-edit.tpl');
} else {
r2(U . 'services/hotspot', 'e', $_L['Account_Not_Found']);
r2(U . 'services/hotspot', 'e', Lang::T('Account Not Found'));
}
break;
case 'delete':
$id = $routes['2'];
$id = $routes['2'];
$d = ORM::for_table('tbl_plans')->find_one($id);
if ($d) {
@ -185,6 +184,7 @@ switch ($action) {
case 'add-post':
$name = _post('name');
$plan_type = _post('plan_type'); //Personal / Business
$radius = _post('radius');
$typebp = _post('typebp');
$limit_type = _post('limit_type');
@ -201,7 +201,7 @@ switch ($action) {
$pool_expired = _post('pool_expired');
$list_expired = _post('list_expired');
$enabled = _post('enabled');
$allow_purchase = _post('allow_purchase');
$prepaid = _post('prepaid');
$msg = '';
if (Validator::UnsignedNumber($validity) == false) {
@ -245,12 +245,44 @@ switch ($action) {
$radiusRate = $b['rate_up'] . $radup . '/' . $b['rate_down'] . $raddown;
$rate = trim($rate . " " . $b['burst']);
// Check if tax is enabled in config
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
// Default tax rate
$default_tax_rate = 0.01; // Default tax rate 1%
// Check if tax rate is set to custom in config
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : $default_tax_rate;
// Check if tax rate is custom
if ($tax_rate_setting === 'custom') {
// Check if custom tax rate is set in config
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : $default_tax_rate;
// Convert custom tax rate to decimal
$custom_tax_rate_decimal = $custom_tax_rate / 100;
$tax_rate = $custom_tax_rate_decimal;
} else {
// Use tax rate
$tax_rate = $tax_rate_setting;
}
// Calculate the new price with tax if tax is enabled
if ($tax_enable === 'yes') {
$price_with_tax = $price + ($price * $tax_rate);
} else {
// If tax is not enabled, use the original price
$price_with_tax = $price;
}
// Create new plan
$d = ORM::for_table('tbl_plans')->create();
$d->name_plan = $name;
$d->id_bw = $id_bw;
$d->price = $price;
$d->price = $price_with_tax; // Set price with or without tax based on configuration
$d->type = 'Hotspot';
$d->typebp = $typebp;
$d->plan_type = $plan_type;
$d->limit_type = $limit_type;
$d->time_limit = $time_limit;
$d->time_unit = $time_unit;
@ -269,7 +301,7 @@ switch ($action) {
$d->pool_expired = $pool_expired;
$d->list_expired = $list_expired;
$d->enabled = $enabled;
$d->allow_purchase = $allow_purchase;
$d->prepaid = $prepaid;
$d->save();
$plan_id = $d->id();
@ -295,6 +327,7 @@ switch ($action) {
case 'edit-post':
$id = _post('id');
$name = _post('name');
$plan_type = _post('plan_type');
$id_bw = _post('id_bw');
$typebp = _post('typebp');
$price = _post('price');
@ -309,7 +342,7 @@ switch ($action) {
$pool_expired = _post('pool_expired');
$list_expired = _post('list_expired');
$enabled = _post('enabled');
$allow_purchase = _post('allow_purchase');
$prepaid = _post('prepaid');
$routers = _post('routers');
$msg = '';
if (Validator::UnsignedNumber($validity) == false) {
@ -359,14 +392,45 @@ switch ($action) {
}
}
// Check if tax is enabled in config
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
// Default tax rate
$default_tax_rate = 0.01; // Default tax rate 1%
// Check if tax rate is set to custom in config
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : $default_tax_rate;
// Check if tax rate is custom
if ($tax_rate_setting === 'custom') {
// Check if custom tax rate is set in config
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : $default_tax_rate;
// Convert custom tax rate to decimal
$custom_tax_rate_decimal = $custom_tax_rate / 100;
$tax_rate = $custom_tax_rate_decimal;
} else {
// Use tax rate
$tax_rate = $tax_rate_setting;
}
// Calculate the new price with tax if tax is enabled
if ($tax_enable === 'yes') {
$price_with_tax = $price + ($price * $tax_rate);
} else {
// If tax is not enabled, use the original price
$price_with_tax = $price;
}
$d->name_plan = $name;
$d->id_bw = $id_bw;
$d->price = $price;
$d->price = $price_with_tax; // Set price with or without tax based on configuration
$d->typebp = $typebp;
$d->limit_type = $limit_type;
$d->time_limit = $time_limit;
$d->time_unit = $time_unit;
$d->data_limit = $data_limit;
$d->plan_type = $plan_type;
$d->data_unit = $data_unit;
$d->validity = $validity;
$d->validity_unit = $validity_unit;
@ -374,7 +438,7 @@ switch ($action) {
$d->pool_expired = $pool_expired;
$d->list_expired = $list_expired;
$d->enabled = $enabled;
$d->allow_purchase = $allow_purchase;
$d->prepaid = $prepaid;
$d->save();
r2(U . 'services/hotspot', 's', Lang::T('Data Updated Successfully'));
@ -389,15 +453,14 @@ switch ($action) {
$name = _post('name');
if ($name != '') {
$paginator = Paginator::build(ORM::for_table('tbl_plans'), ['name_plan' => '%' . $name . '%', 'type' => 'PPPOE'], $name);
$d = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'PPPOE')->where_like('tbl_plans.name_plan', '%' . $name . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many();
$query = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'PPPOE')->where_like('tbl_plans.name_plan', '%' . $name . '%');
$d = Paginator::findMany($query, ['name' => $name]);
} else {
$paginator = Paginator::build(ORM::for_table('tbl_plans'), ['type' => 'PPPOE'], $name);
$d = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'PPPOE')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many();
$query = ORM::for_table('tbl_bandwidth')->join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))->where('tbl_plans.type', 'PPPOE');
$d = Paginator::findMany($query);
}
$ui->assign('d', $d);
$ui->assign('paginator', $paginator);
run_hook('view_list_ppoe'); #HOOK
$ui->display('pppoe.tpl');
break;
@ -414,7 +477,7 @@ switch ($action) {
case 'pppoe-edit':
$ui->assign('_title', Lang::T('PPPOE Plans'));
$id = $routes['2'];
$id = $routes['2'];
$d = ORM::for_table('tbl_plans')->find_one($id);
if ($d) {
$ui->assign('d', $d);
@ -430,12 +493,12 @@ switch ($action) {
run_hook('view_edit_ppoe'); #HOOK
$ui->display('pppoe-edit.tpl');
} else {
r2(U . 'services/pppoe', 'e', $_L['Account_Not_Found']);
r2(U . 'services/pppoe', 'e', Lang::T('Account Not Found'));
}
break;
case 'pppoe-delete':
$id = $routes['2'];
$id = $routes['2'];
$d = ORM::for_table('tbl_plans')->find_one($id);
if ($d) {
@ -461,6 +524,7 @@ switch ($action) {
case 'pppoe-add-post':
$name = _post('name_plan');
$plan_type = _post('plan_type');
$radius = _post('radius');
$id_bw = _post('id_bw');
$price = _post('price');
@ -471,7 +535,7 @@ switch ($action) {
$pool_expired = _post('pool_expired');
$list_expired = _post('list_expired');
$enabled = _post('enabled');
$allow_purchase = _post('allow_purchase');
$prepaid = _post('prepaid');
$msg = '';
@ -515,11 +579,43 @@ switch ($action) {
$radiusRate = $b['rate_up'] . $radup . '/' . $b['rate_down'] . $raddown;
$rate = trim($rate . " " . $b['burst']);
// Check if tax is enabled in config
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
// Default tax rate
$default_tax_rate = 0.01; // Default tax rate 1%
// Check if tax rate is set to custom in config
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : $default_tax_rate;
// Check if tax rate is custom
if ($tax_rate_setting === 'custom') {
// Check if custom tax rate is set in config
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : $default_tax_rate;
// Convert custom tax rate to decimal
$custom_tax_rate_decimal = $custom_tax_rate / 100;
$tax_rate = $custom_tax_rate_decimal;
} else {
// Use tax rate
$tax_rate = $tax_rate_setting;
}
// Calculate the new price with tax if tax is enabled
if ($tax_enable === 'yes') {
$price_with_tax = $price + ($price * $tax_rate);
} else {
// If tax is not enabled, use the original price
$price_with_tax = $price;
}
$d = ORM::for_table('tbl_plans')->create();
$d->type = 'PPPOE';
$d->name_plan = $name;
$d->id_bw = $id_bw;
$d->price = $price;
$d->price = $price_with_tax;
$d->plan_type = $plan_type;
$d->validity = $validity;
$d->validity_unit = $validity_unit;
$d->pool = $pool;
@ -533,7 +629,7 @@ switch ($action) {
$d->pool_expired = $pool_expired;
$d->list_expired = $list_expired;
$d->enabled = $enabled;
$d->allow_purchase = $allow_purchase;
$d->prepaid = $prepaid;
$d->save();
$plan_id = $d->id();
@ -556,6 +652,7 @@ switch ($action) {
case 'edit-pppoe-post':
$id = _post('id');
$plan_type = _post('plan_type');
$name = _post('name_plan');
$id_bw = _post('id_bw');
$price = _post('price');
@ -566,7 +663,7 @@ switch ($action) {
$pool_expired = _post('pool_expired');
$list_expired = _post('list_expired');
$enabled = _post('enabled');
$allow_purchase = _post('allow_purchase');
$prepaid = _post('prepaid');
$msg = '';
if (Validator::UnsignedNumber($validity) == false) {
@ -616,9 +713,40 @@ switch ($action) {
}
}
// Check if tax is enabled in config
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
// Default tax rate
$default_tax_rate = 0.01; // Default tax rate 1%
// Check if tax rate is set to custom in config
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : $default_tax_rate;
// Check if tax rate is custom
if ($tax_rate_setting === 'custom') {
// Check if custom tax rate is set in config
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : $default_tax_rate;
// Convert custom tax rate to decimal
$custom_tax_rate_decimal = $custom_tax_rate / 100;
$tax_rate = $custom_tax_rate_decimal;
} else {
// Use tax rate
$tax_rate = $tax_rate_setting;
}
// Calculate the new price with tax if tax is enabled
if ($tax_enable === 'yes') {
$price_with_tax = $price + ($price * $tax_rate);
} else {
// If tax is not enabled, use the original price
$price_with_tax = $price;
}
$d->name_plan = $name;
$d->id_bw = $id_bw;
$d->price = $price;
$d->price = $price_with_tax;
$d->plan_type = $plan_type;
$d->validity = $validity;
$d->validity_unit = $validity_unit;
$d->routers = $routers;
@ -626,7 +754,7 @@ switch ($action) {
$d->pool_expired = $pool_expired;
$d->list_expired = $list_expired;
$d->enabled = $enabled;
$d->allow_purchase = $allow_purchase;
$d->prepaid = $prepaid;
$d->save();
r2(U . 'services/pppoe', 's', Lang::T('Data Updated Successfully'));
@ -638,15 +766,14 @@ switch ($action) {
$ui->assign('_title', Lang::T('Balance Plans'));
$name = _post('name');
if ($name != '') {
$paginator = Paginator::build(ORM::for_table('tbl_plans'), ['name_plan' => '%' . $name . '%', 'type' => 'Balance'], $name);
$d = ORM::for_table('tbl_plans')->where('tbl_plans.type', 'Balance')->where_like('tbl_plans.name_plan', '%' . $name . '%')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many();
$query = ORM::for_table('tbl_plans')->where('tbl_plans.type', 'Balance')->where_like('tbl_plans.name_plan', '%' . $name . '%');
$d = Paginator::findMany($query, ['name' => $name]);
} else {
$paginator = Paginator::build(ORM::for_table('tbl_plans'), ['type' => 'Balance'], $name);
$d = ORM::for_table('tbl_plans')->where('tbl_plans.type', 'Balance')->offset($paginator['startpoint'])->limit($paginator['limit'])->find_many();
$query = ORM::for_table('tbl_plans')->where('tbl_plans.type', 'Balance');
$d = Paginator::findMany($query);
}
$ui->assign('d', $d);
$ui->assign('paginator', $paginator);
run_hook('view_list_balance'); #HOOK
$ui->display('balance.tpl');
break;
@ -657,14 +784,14 @@ switch ($action) {
break;
case 'balance-edit':
$ui->assign('_title', Lang::T('Balance Plans'));
$id = $routes['2'];
$id = $routes['2'];
$d = ORM::for_table('tbl_plans')->find_one($id);
$ui->assign('d', $d);
run_hook('view_edit_balance'); #HOOK
$ui->display('balance-edit.tpl');
break;
case 'balance-delete':
$id = $routes['2'];
$id = $routes['2'];
$d = ORM::for_table('tbl_plans')->find_one($id);
if ($d) {
@ -678,7 +805,7 @@ switch ($action) {
$name = _post('name');
$price = _post('price');
$enabled = _post('enabled');
$allow_purchase = _post('allow_purchase');
$prepaid = _post('prepaid');
$msg = '';
if (Validator::UnsignedNumber($price) == false) {
@ -695,10 +822,39 @@ switch ($action) {
}
run_hook('edit_ppoe'); #HOOK
if ($msg == '') {
// Check if tax is enabled in config
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
// Default tax rate
$default_tax_rate = 0.01; // Default tax rate 1%
// Check if tax rate is set to custom in config
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : $default_tax_rate;
// Check if tax rate is custom
if ($tax_rate_setting === 'custom') {
// Check if custom tax rate is set in config
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : $default_tax_rate;
// Convert custom tax rate to decimal
$custom_tax_rate_decimal = $custom_tax_rate / 100;
$tax_rate = $custom_tax_rate_decimal;
} else {
// Use tax rate
$tax_rate = $tax_rate_setting;
}
// Calculate the new price with tax if tax is enabled
if ($tax_enable === 'yes') {
$price_with_tax = $price + ($price * $tax_rate);
} else {
// If tax is not enabled, use the original price
$price_with_tax = $price;
}
$d->name_plan = $name;
$d->price = $price;
$d->price = $price_with_tax;
$d->enabled = $enabled;
$d->allow_purchase = $allow_purchase;
$d->prepaid = 'yes';
$d->save();
r2(U . 'services/balance', 's', Lang::T('Data Updated Successfully'));
@ -710,7 +866,6 @@ switch ($action) {
$name = _post('name');
$price = _post('price');
$enabled = _post('enabled');
$allow_purchase = _post('allow_purchase');
$msg = '';
if (Validator::UnsignedNumber($price) == false) {
@ -726,17 +881,49 @@ switch ($action) {
}
run_hook('add_ppoe'); #HOOK
if ($msg == '') {
// Check if tax is enabled in config
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
// Default tax rate
$default_tax_rate = 0.01; // Default tax rate 1%
// Check if tax rate is set to custom in config
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : $default_tax_rate;
// Check if tax rate is custom
if ($tax_rate_setting === 'custom') {
// Check if custom tax rate is set in config
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : $default_tax_rate;
// Convert custom tax rate to decimal
$custom_tax_rate_decimal = $custom_tax_rate / 100;
$tax_rate = $custom_tax_rate_decimal;
} else {
// Use tax rate
$tax_rate = $tax_rate_setting;
}
// Calculate the new price with tax if tax is enabled
if ($tax_enable === 'yes') {
$price_with_tax = $price + ($price * $tax_rate);
} else {
// If tax is not enabled, use the original price
$price_with_tax = $price;
}
$d = ORM::for_table('tbl_plans')->create();
$d->type = 'Balance';
$d->name_plan = $name;
$d->id_bw = 0;
$d->price = $price;
$d->price = $price_with_tax;
$d->validity = 0;
$d->validity_unit = 'Months';
$d->routers = '';
$d->pool = '';
$d->enabled = $enabled;
$d->allow_purchase = $allow_purchase;
$d->prepaid = 'yes';
$d->save();
r2(U . 'services/balance', 's', Lang::T('Data Created Successfully'));

View File

@ -25,20 +25,25 @@ 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);
if (file_exists($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png')) {
$logo = $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png?' . time();
$logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'logo.png?' . time();
} else {
$logo = $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.default.png';
$logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'logo.default.png';
}
$ui->assign('logo', $logo);
if ($_c['radius_enable'] && empty($_c['radius_client'])) {
if ($config['radius_enable'] && empty($config['radius_client'])) {
try {
$_c['radius_client'] = Radius::getClient();
$config['radius_client'] = Radius::getClient();
$ui->assign('_c', $_c);
} catch (Exception $e) {
//ignore
@ -114,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,6 +133,33 @@ switch ($action) {
}
}
// Handle tax system separately
$enable_tax = isset($_POST['enable_tax']) ? $_POST['enable_tax'] : 'no';
$tax_rate = isset($_POST['tax_rate']) ? $_POST['tax_rate'] : '0.01'; // Default tax rate 1%
// Save or update tax system settings
$d_tax_enable = ORM::for_table('tbl_appconfig')->where('setting', 'enable_tax')->find_one();
if ($d_tax_enable) {
$d_tax_enable->value = $enable_tax;
$d_tax_enable->save();
} else {
$d_tax_enable = ORM::for_table('tbl_appconfig')->create();
$d_tax_enable->setting = 'enable_tax';
$d_tax_enable->value = $enable_tax;
$d_tax_enable->save();
}
$d_tax_rate = ORM::for_table('tbl_appconfig')->where('setting', 'tax_rate')->find_one();
if ($d_tax_rate) {
$d_tax_rate->value = $tax_rate;
$d_tax_rate->save();
} else {
$d_tax_rate = ORM::for_table('tbl_appconfig')->create();
$d_tax_rate->setting = 'tax_rate';
$d_tax_rate->value = $tax_rate;
$d_tax_rate->save();
}
//checkbox
$checks = ['hide_mrc', 'hide_tms', 'hide_aui', 'hide_al', 'hide_uet', 'hide_vs', 'hide_pg'];
foreach ($checks as $check) {
@ -275,60 +307,47 @@ switch ($action) {
$search = _req('search');
if ($search != '') {
if ($admin['user_type'] == 'SuperAdmin') {
$paginator = Paginator::build(ORM::for_table('tbl_users'), ['username' => '%' . $search . '%'], $search);
$d = ORM::for_table('tbl_users')
$query = ORM::for_table('tbl_users')
->where_like('username', '%' . $search . '%')
->offset($paginator['startpoint'])
->limit($paginator['limit'])->order_by_asc('id')->findArray();
->order_by_asc('id');
$d = Paginator::findMany($query, ['search' => $search]);
} else if ($admin['user_type'] == 'Admin') {
$paginator = Paginator::build(ORM::for_table('tbl_users'), [
'username' => '%' . $search . '%',
['user_type' => 'Report'],
['user_type' => 'Agent'],
['user_type' => 'Sales'],
['id' => $admin['id']]
], $search);
$d = ORM::for_table('tbl_users')
->where_like('username', '%' . $search . '%')
->where_any_is([
$query = ORM::for_table('tbl_users')
->where_like('username', '%' . $search . '%')->where_any_is([
['user_type' => 'Report'],
['user_type' => 'Agent'],
['user_type' => 'Sales'],
['id' => $admin['id']]
])
->offset($paginator['startpoint'])
->limit($paginator['limit'])->order_by_asc('id')->findArray();
])->order_by_asc('id');
$d = Paginator::findMany($query, ['search' => $search]);
} else {
$paginator = Paginator::build(ORM::for_table('tbl_users'), ['username' => '%' . $search . '%'], $search);
$d = ORM::for_table('tbl_users')
$query = ORM::for_table('tbl_users')
->where_like('username', '%' . $search . '%')
->where_any_is([
['id' => $admin['id']],
['root' => $admin['id']]
])
->offset($paginator['startpoint'])
->limit($paginator['limit'])->order_by_asc('id')->findArray();
])->order_by_asc('id');
$d = Paginator::findMany($query, ['search' => $search]);
}
} else {
if ($admin['user_type'] == 'SuperAdmin') {
$paginator = Paginator::build(ORM::for_table('tbl_users'));
$d = ORM::for_table('tbl_users')->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_asc('id')->findArray();
$query = ORM::for_table('tbl_users')->order_by_asc('id');
$d = Paginator::findMany($query);
} else if ($admin['user_type'] == 'Admin') {
$paginator = Paginator::build(ORM::for_table('tbl_users'));
$d = ORM::for_table('tbl_users')->where_any_is([
$query = ORM::for_table('tbl_users')->where_any_is([
['user_type' => 'Report'],
['user_type' => 'Agent'],
['user_type' => 'Sales'],
['id' => $admin['id']]
])->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_asc('id')->findArray();
])->order_by_asc('id');
$d = Paginator::findMany($query);
} else {
$paginator = Paginator::build(ORM::for_table('tbl_users'));
$d = ORM::for_table('tbl_users')
$query = ORM::for_table('tbl_users')
->where_any_is([
['id' => $admin['id']],
['root' => $admin['id']]
])
->offset($paginator['startpoint'])->limit($paginator['limit'])->order_by_asc('id')->findArray();
])->order_by_asc('id');
$d = Paginator::findMany($query);
}
}
$admins = [];
@ -344,16 +363,9 @@ switch ($action) {
$admins[$adm['id']] = $adm['fullname'];
}
}
if ($isApi) {
showResult(true, $action, [
'admins' => $d,
'roots' => $admins
], ['search' => $search]);
}
$ui->assign('admins', $admins);
$ui->assign('d', $d);
$ui->assign('search', $search);
$ui->assign('paginator', $paginator);
run_hook('view_list_admin'); #HOOK
$ui->display('users.tpl');
break;
@ -389,20 +401,11 @@ switch ($action) {
if ($d['user_type'] == 'Sales') {
$ui->assign('agent', ORM::for_table('tbl_users')->where('id', $d['root'])->find_array()[0]);
}
if ($isApi) {
unset($d['password']);
$agent = $ui->get('agent');
if ($agent) unset($agent['password']);
showResult(true, $action, [
'admin' => $d,
'agent' => $agent
], ['search' => $search]);
}
$ui->assign('d', $d);
$ui->assign('_title', $d['username']);
$ui->display('users-view.tpl');
} else {
r2(U . 'settings/users', 'e', $_L['Account_Not_Found']);
r2(U . 'settings/users', 'e', Lang::T('Account Not Found'));
}
break;
case 'users-edit':
@ -439,7 +442,7 @@ switch ($action) {
run_hook('view_edit_admin'); #HOOK
$ui->display('users-edit.tpl');
} else {
r2(U . 'settings/users', 'e', $_L['Account_Not_Found']);
r2(U . 'settings/users', 'e', Lang::T('Account Not Found'));
}
break;
@ -458,7 +461,7 @@ switch ($action) {
$d->delete();
r2(U . 'settings/users', 's', Lang::T('User deleted Successfully'));
} else {
r2(U . 'settings/users', 'e', $_L['Account_Not_Found']);
r2(U . 'settings/users', 'e', Lang::T('Account Not Found'));
}
break;
@ -495,11 +498,11 @@ switch ($action) {
$date_now = date("Y-m-d H:i:s");
run_hook('add_admin'); #HOOK
if ($msg == '') {
$password = Password::_crypt($password);
$passwordC = Password::_crypt($password);
$d = ORM::for_table('tbl_users')->create();
$d->username = $username;
$d->fullname = $fullname;
$d->password = $password;
$d->password = $passwordC;
$d->user_type = $user_type;
$d->phone = $phone;
$d->email = $email;

View File

@ -40,16 +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];
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

@ -24,7 +24,7 @@ echo "Found " . count($d) . " user(s)\n";
run_hook('cronjob'); #HOOK
foreach ($d as $ds) {
if ($ds['type'] == 'Hotspot') {
if ($ds['type'] == 'Hotspot') { # HOTSPOT
$date_now = strtotime(date("Y-m-d H:i:s"));
$expiration = strtotime($ds['expiration'] . ' ' . $ds['time']);
echo $ds['expiration'] . " : " . (($isCli) ? $ds['username'] : Lang::maskText($ds['username']));
@ -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,22 +45,28 @@ 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['phonenumber'], $c['fullname'], $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']) {
if ($p && $p['enabled'] && $c['balance'] >= $p['price'] && $p['allow_purchase'] == 'yes') {
list($bills, $add_cost) = User::getBills($ds['customer_id']);
if ($add_cost > 0) {
if (!empty($add_cost)) {
$p['price'] += $add_cost;
}
}
if ($p && $p['enabled'] && $c['balance'] >= $p['price']) {
if (Package::rechargeUser($ds['customer_id'], $p['routers'], $p['id'], 'Customer', 'Balance')) {
// if success, then get the balance
Balance::min($ds['customer_id'], $p['price']);
@ -82,7 +87,7 @@ foreach ($d as $ds) {
}
} else
echo " : ACTIVE \r\n";
} else {
} else { # PPPOE
$date_now = strtotime(date("Y-m-d H:i:s"));
$expiration = strtotime($ds['expiration'] . ' ' . $ds['time']);
echo $ds['expiration'] . " : " . (($isCli) ? $ds['username'] : Lang::maskText($ds['username']));
@ -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,14 +113,20 @@ foreach ($d as $ds) {
}
Mikrotik::removePpoeActive($client, $c['username']);
}
echo Message::sendPackageNotification($c['phonenumber'], $c['fullname'], $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']) {
if ($p && $p['enabled'] && $c['balance'] >= $p['price'] && $p['allow_purchase'] == 'yes') {
list($bills, $add_cost) = User::getBills($ds['customer_id']);
if ($add_cost > 0) {
if (!empty($add_cost)) {
$p['price'] += $add_cost;
}
}
if ($p && $p['enabled'] && $c['balance'] >= $p['price']) {
if (Package::rechargeUser($ds['customer_id'], $p['routers'], $p['id'], 'Customer', 'Balance')) {
// if success, then get the balance
Balance::min($ds['customer_id'], $p['price']);
@ -134,4 +144,4 @@ foreach ($d as $ds) {
} else
echo " : ACTIVE \r\n";
}
}
}

View File

@ -38,13 +38,23 @@ 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['phonenumber'], $c['fullname'], $p['name_plan'], $price, Lang::getNotifText('reminder_7_day'), $config['user_notification_reminder']) . "\n";
echo Message::sendPackageNotification($c, $p['name_plan'], $price, Lang::getNotifText('reminder_7_day'), $config['user_notification_reminder']) . "\n";
} else if ($ds['expiration'] == $day3) {
echo Message::sendPackageNotification($c['phonenumber'], $c['fullname'], $p['name_plan'], $price, Lang::getNotifText('reminder_3_day'), $config['user_notification_reminder']) . "\n";
echo Message::sendPackageNotification($c, $p['name_plan'], $price, Lang::getNotifText('reminder_3_day'), $config['user_notification_reminder']) . "\n";
} else if ($ds['expiration'] == $day1) {
echo Message::sendPackageNotification($c['phonenumber'], $c['fullname'], $p['name_plan'], $price, Lang::getNotifText('reminder_1_day'), $config['user_notification_reminder']) . "\n";
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",
@ -384,7 +381,6 @@
"After_Customer_activate_voucher_or_login__customer_will_be_redirected_to_this_url": "After Customer activate voucher or login, customer will be redirected to this url",
"Voucher_Prefix": "Voucher Prefix",
"Voucher_activation_success__now_you_can_login": "Voucher activation success, now you can login",
"Client_Can_Purchase": "Client Can Purchase",
"Buy_this__your_active_package_will_be_overwritten": "Buy this? your active package will be overwritten",
"Pay_this_with_Balance__your_active_package_will_be_overwritten": "Pay this with Balance? your active package will be overwritten",
"Buy_this__your_active_package_will_be_overwrite": "Buy this? your active package will be overwrite",
@ -456,5 +452,130 @@
"Click_Here": "Click Here",
"danger": "danger",
"Logout_Successful": "Logout Successful",
"warning": "warning"
"warning": "warning",
"Users_Announcement": "Users Announcement",
"Customer_Announcement": "Customer Announcement",
"1_Period___1_Month__Expires_the_20th_of_each_month": "1 Period = 1 Month, Expires the 20th of each month",
"Period": "Period",
"Add": "Add",
"Select_Payment_Gateway": "Select Payment Gateway",
"Available_Payment_Gateway": "Available Payment Gateway",
"Pay_Now": "Pay Now",
"Please_select_Payment_Gateway": "Please select Payment Gateway",
"Payment_Gateway_Deleted": "Payment Gateway Deleted",
"Payment_Gateway_not_set__please_set_it_in_Settings": "Payment Gateway not set, please set it in Settings",
"Failed_to_create_Transaction__": "Failed to create Transaction..",
"Show_To_Customer": "Type",
"Using": "Using",
"Default": "Default",
"Customer_Balance": "Customer Balance",
"Vouchers": "Vouchers",
"Refill_Customer": "Refill Customer",
"Recharge_Customer": "Recharge Customer",
"Plans": "Plans",
"PPPOE": "PPPOE",
"Bandwidth": "Bandwidth",
"Customers": "Customers",
"Actives": "Actives",
"Name": "Name",
"Confirm": "Confirm",
"Plan": "Plan",
"Total": "Total",
"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"
}

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,116 @@
"Buy_for_friend": "Beli untuk teman",
"Buy_this_for_friend_account_": "Beli ini untuk akun teman?",
"Review_package_before_recharge": "Tinjau paket sebelum mengisi ulang",
"Activate": "Mengaktifkan Paket",
"Deactivate": "Menonaktifkan Paket",
"Activate": "Mengaktifkan paket",
"Deactivate": "Menonaktifkan paket",
"Sync": "Sinkronisasi",
"Failed_to_create_PaymeTrust_transaction_": "Gagal membuat transaksi PaymeTrust.",
"Location": "Lokasi",
"Radius_Plans": "Paket Radius",
"Change_title_in_user_Plan_order": "Ubah judul dalam urutan paket pelanggan",
"Change_title_in_user_Plan_order": "Ubah Judul dalam urutan paket pelanggan",
"Logs": "Log",
"Voucher_Format": "Format Voucher",
"Resend_To_Customer": "Kirim Ulang Ke Pelanggan",
"Service_Type": "Service Type",
"Service_Type": "Jenis Layanan",
"Others": "Lainnya",
"PPPoE": "PPPoE",
"Hotspot": "Hotspot",
"Monthly_Registered_Customers": "Pendaftaran Pelanggan perbulan",
"Total_Monthly_Sales": "Total penjualan Perbulan",
"Active_Users": "Pelanggan Aktif"
}
"Total_Monthly_Sales": "Total penjualan perbulan",
"Active_Users": "Pelanggan Aktif",
"SuperAdmin": "Super Admin",
"Lists": "Daftar",
"Vouchers": "Voucher",
"Refill_Customer": "Isi Ulang Pelanggan",
"Recharge_Customer": "Isi Ulang Pelanggan",
"Plans": "Paket",
"PPPOE": "PPPOE",
"Bandwidth": "Bandwidth",
"Send_Message": "Mengirim pesan",
"Single_Customer": "Pelanggan Tunggal",
"Bulk_Customers": "Pelanggan Massal",
"Radius": "Radius",
"Radius_NAS": "Radius NAS",
"Customer_Announcement": "Pengumuman Pelanggan",
"Language_Editor": "Editor Bahasa",
"Plan_Category": "Kategori Paket",
"ID": "ID",
"Prev": "Sebelumnya",
"Internet_Plan": "Paket Internet",
"Generated_By": "Dihasilkan oleh",
"All_Users_Insights": "Semua Wawasan Pengguna",
"year": "Tahun",
"month": "Bulan",
"week": "Pekan",
"day": "Hari",
"hour": "Jam",
"minute": "Menit",
"second": "Kedua",
"Account_Type": "Jenis akun",
"Contact": "Kontak",
"Paid": "Dibayar",
"Personal": "Pribadi",
"Coordinates": "Koordinat",
"Confirm": "Mengonfirmasi",
"Name": "Nama",
"Plan": "Paket",
"Using": "Menggunakan",
"Total": "Total",
"Additional_Cost": "Biaya tambahan",
"Resend": "Kirim ulang",
"Login": "Masuk",
"success": "Sukses",
"Click_Here": "Klik disini",
"Your_friend_do_not_have_active_package": "Teman Anda tidak memiliki paket aktif",
"If_your_friend_have_Additional_Cost__you_will_pay_for_that_too": "Jika teman Anda memiliki biaya tambahan, Anda juga akan membayarnya",
"Select_Payment_Gateway": "Pilih Gerbang Pembayaran",
"Available_Payment_Gateway": "Gerbang Pembayaran yang tersedia",
"Pay_Now": "Bayar sekarang",
"Notes": "Catatan",
"will_be_replaced_with_Customer_Name": "akan diganti dengan nama Pelanggan",
"will_be_replaced_with_Customer_username": "akan diganti dengan nama pengguna Pelanggan",
"will_be_replaced_with_Package_name": "akan diganti dengan nama paket",
"will_be_replaced_with_Package_price": "akan diganti dengan harga Paket",
"will_be_replaced_with_Expiration_date": "akan diganti dengan tanggal kedaluwarsa",
"additional_bills_for_customers": "tagihan tambahan untuk pelanggan",
"Your_Company_Name_at_Settings": "Nama Perusahaan Anda di pengaturan",
"Your_Company_Address_at_Settings": "Alamat Perusahaan Anda di pengaturan",
"Your_Company_Phone_at_Settings": "Telepon Perusahaan Anda di pengaturan",
"Invoice_number": "Nomor faktur",
"Date_invoice_created": "Tanggal faktur dibuat",
"Payment_gateway_user_paid_from": "Pengguna gateway pembayaran membayar dari",
"Payment_channel_user_paid_from": "Pengguna saluran pembayaran membayar dari",
"is_Hotspot_or_PPPOE": "adalah Hotspot atau PPPOE",
"Internet_Package": "Paket internet",
"Internet_Package_Prices": "Harga paket internet",
"Receiver_name": "Nama penerima",
"Username_internet": "Nama pengguna internet",
"User_password": "Kata sandi pengguna",
"Transaction_datetime": "Tanggal waktu transaksi",
"Balance_Before": "Saldo sebelumnya",
"Balance_After": "Saldo setelahnya",
"For_Notes_by_admin": "Untuk catatan oleh Admin",
"how_much_balance_have_been_send": "berapa banyak saldo yang telah dikirim",
"Current_Balance": "Saldo saat ini",
"Sender_name": "Nama pengirim",
"Customer_Balance": "Saldo Pelanggan",
"Privacy_Policy": "Kebijakan Privasi",
"Terms_and_Conditions": "Syarat dan Ketentuan",
"Disable_Registration": "Nonaktifkan Pendaftaran",
"Customer_just_Login_with_Phone_number_and_Voucher_Code__Voucher_will_be_password": "Pelanggan cukup masuk dengan nomor telepon dan kode voucher, Voucher akan menjadi kata sandi",
"After_Customer_activate_voucher_or_login__customer_will_be_redirected_to_this_url": "Setelah Pelanggan mengaktifkan voucher atau masuk, Pelanggan akan diarahkan ke URL ini",
"Extend_Postpaid_Expiration": "Perpanjang masa kedaluwarsa pascabayar",
"Allow_Extend": "Izinkan Perpanjang",
"Extend_Days": "Perpanjang Hari",
"Confirmation_Message": "Pesan konfirmasi",
"Email_Notification": "Pemberitahuan Email",
"This_Token_will_act_as_SuperAdmin_Admin": "Token ini akan bertindak sebagai SuperAdmin\/Admin",
"Miscellaneous": "Aneka ragam",
"OTP_Required": "Diperlukan OTP",
"OTP_is_required_when_user_want_to_change_phone_number": "OTP diperlukan ketika pengguna ingin mengganti nomor telepon",
"OTP_Method": "Metode OTP",
"SMS": "SMS",
"WhatsApp": "WhatsApp",
"SMS_and_WhatsApp": "SMS dan WhatsApp",
"The_method_which_OTP_will_be_sent_to_user": "Metode OTP yang akan dikirimkan ke pengguna"
}

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",

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`;",
@ -69,5 +69,29 @@
"2024.2.23" : [
"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`;"
],
"2024.3.3" : [
"ALTER TABLE `tbl_plans` CHANGE `validity_unit` `validity_unit` ENUM('Mins','Hrs','Days','Months','Period') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;"
],
"2024.3.12" : [
"ALTER TABLE `tbl_plans` CHANGE `allow_purchase` `prepaid` ENUM('yes','no') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'yes' COMMENT 'is prepaid';"
],
"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`;"
]
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,99 +0,0 @@
Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below)
Bitstream Vera Fonts Copyright
------------------------------
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
a trademark of Bitstream, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of the fonts accompanying this license ("Fonts") and associated
documentation files (the "Font Software"), to reproduce and distribute the
Font Software, including without limitation the rights to use, copy, merge,
publish, distribute, and/or sell copies of the Font Software, and to permit
persons to whom the Font Software is furnished to do so, subject to the
following conditions:
The above copyright and trademark notices and this permission notice shall
be included in all copies of one or more of the Font Software typefaces.
The Font Software may be modified, altered, or added to, and in particular
the designs of glyphs or characters in the Fonts may be modified and
additional glyphs or characters may be added to the Fonts, only if the fonts
are renamed to names not containing either the words "Bitstream" or the word
"Vera".
This License becomes null and void to the extent applicable to Fonts or Font
Software that has been modified and is distributed under the "Bitstream
Vera" names.
The Font Software may be sold as part of a larger software package but no
copy of one or more of the Font Software typefaces may be sold by itself.
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
FONT SOFTWARE.
Except as contained in this notice, the names of Gnome, the Gnome
Foundation, and Bitstream Inc., shall not be used in advertising or
otherwise to promote the sale, use or other dealings in this Font Software
without prior written authorization from the Gnome Foundation or Bitstream
Inc., respectively. For further information, contact: fonts at gnome dot
org.
Arev Fonts Copyright
------------------------------
Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining
a copy of the fonts accompanying this license ("Fonts") and
associated documentation files (the "Font Software"), to reproduce
and distribute the modifications to the Bitstream Vera Font Software,
including without limitation the rights to use, copy, merge, publish,
distribute, and/or sell copies of the Font Software, and to permit
persons to whom the Font Software is furnished to do so, subject to
the following conditions:
The above copyright and trademark notices and this permission notice
shall be included in all copies of one or more of the Font Software
typefaces.
The Font Software may be modified, altered, or added to, and in
particular the designs of glyphs or characters in the Fonts may be
modified and additional glyphs or characters may be added to the
Fonts, only if the fonts are renamed to names not containing either
the words "Tavmjong Bah" or the word "Arev".
This License becomes null and void to the extent applicable to Fonts
or Font Software that has been modified and is distributed under the
"Tavmjong Bah Arev" names.
The Font Software may be sold as part of a larger software package but
no copy of one or more of the Font Software typefaces may be sold by
itself.
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
Except as contained in this notice, the name of Tavmjong Bah shall not
be used in advertising or otherwise to promote the sale, use or other
dealings in this Font Software without prior written authorization
from Tavmjong Bah. For further information, contact: tavmjong @ free
. fr.
$Id: LICENSE 2133 2007-11-28 02:46:28Z lechimp $

Binary file not shown.

View File

@ -1,94 +0,0 @@
Copyright (c) 2010, Vernon Adams (vern@newtypography.co.uk),
with Reserved Font Names "Dhyana".
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,108 +0,0 @@
-*-text-*-
GNU FreeFont
The GNU FreeFont project aims to provide a useful set of free scalable
(i.e., OpenType) fonts covering as much as possible of the ISO 10646/Unicode
UCS (Universal Character Set).
Statement of Purpose
--------------------
The practical reason for putting glyphs together in a single font face is
to conveniently mix symbols and characters from different writing systems,
without having to switch fonts.
Coverage
--------
FreeFont covers the following character sets
* ISO 8859 parts 1-15
* CEN MES-3 European Unicode Subset
http://www.evertype.com/standards/iso10646/pdf/cwa13873.pdf
* IBM/Microsoft code pages 437, 850, 852, 1250, 1252 and more
* Microsoft/Adobe Windows Glyph List 4 (WGL4)
http://www.microsoft.com/typography/otspec/WGL4.htm
* KOI8-R and KOI8-RU
* DEC VT100 graphics symbols
* International Phonetic Alphabet
* Arabic, Hebrew, Armenian, Georgian, Ethiopian and Thai alphabets,
including Arabic presentation forms A/B
* mathematical symbols, including the whole TeX repertoire of symbols
* APL symbols
etc.
Editing
-------
The free outline font editor, George Williams's FontForge
<http://fontforge.sourceforge.net/> is used for editing the fonts.
Design Issues
-------------
Which font shapes should be made? Historical style terms like Renaissance
or Baroque letterforms cannot be applied beyond Latin/Cyrillic/Greek
scripts to any greater extent than Kufi or Nashki can be applied beyond
Arabic script; "italic" is really only meaningful for Latin letters.
However, most modern writing systems have typographic formulations for
contrasting uniform and modulated character stroke widths, and have some
history with "oblique", faces. Since the advent of the typewriter, most
have developed a typographic style with uniform-width characters.
Accordingly, the FreeFont family has one monospaced - FreeMono - and two
proportional faces (one with uniform stroke - FreeSans - and one with
modulated stroke - FreeSerif).
To make text from different writing systems look good side-by-side, each
FreeFont face is meant to contain characters of similar style and weight.
Licensing
---------
Free UCS scalable fonts is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
The fonts are distributed in the hope that they will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
As a special exception, if you create a document which uses this font, and
embed this font or unaltered portions of this font into the document, this
font does not by itself cause the resulting document to be covered by the
GNU General Public License. This exception does not however invalidate any
other reasons why the document might be covered by the GNU General Public
License. If you modify this font, you may extend this exception to your
version of the font, but you are not obligated to do so. If you do not
wish to do so, delete this exception statement from your version.
Files and their suffixes
------------------------
The files with .sfd (Spline Font Database) are in FontForge's native format.
Please use these if you plan to modify the font files.
TrueType fonts for immediate consumption are the files with the .ttf
(TrueType Font) suffix. These are ready to use in Xwindows based
systems using FreeType, on Mac OS, and on older Windows systems.
OpenType fonts (with suffix .otf) are for use in Windows Vista.
Note that although they can be installed on Linux, but many applications
in Linux still don't support them.
--------------------------------------------------------------------------
Primoz Peterlin, <primoz.peterlin@biofiz.mf.uni-lj.si>
Steve White <stevan.white@googlemail.com>
Free UCS scalable fonts: http://savannah.gnu.org/projects/freefont/
$Id: README,v 1.6 2008/12/25 12:51:41 Stevan_White Exp $

Binary file not shown.

Binary file not shown.

View File

@ -1,98 +0,0 @@
This Font Software is Copyright (c) 2006, Christopher J Fynn
All Rights Reserved.
"Jomolhari" is a Reserved Font Name for this Font Software.
This Font Software is licensed under the SIL Open Font License, Version 1.0.
No modification of the license is permitted, only verbatim copy is allowed.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.0 - 22 November 2005
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of cooperative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide an open
framework in which fonts may be shared and improved in partnership with
others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and sold with any software provided that the font
names of derivative works are changed. The fonts and derivatives,
however, cannot be released under any other type of license.
DEFINITIONS
"Font Software" refers to any and all of the following:
- font files
- data files
- source code
- build scripts
- documentation
"Reserved Font Name" refers to the Font Software name as seen by
users and any other names as specified after the copyright statement.
"Standard Version" refers to the collection of Font Software
components as distributed by the Copyright Holder.
"Modified Version" refers to any derivative font software made by
adding to, deleting, or substituting -- in part or in whole --
any of the components of the Standard Version, by changing formats
or by porting the Font Software to a new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Standard or Modified Versions, may be sold by itself.
2) Standard or Modified Versions of the Font Software may be bundled,
redistributed and sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s), in part or in whole, unless explicit written permission is
granted by the Copyright Holder. This restriction applies to all
references stored in the Font Software, such as the font menu name and
other font description fields, which are used to differentiate the
font from others.
4) The name(s) of the Copyright Holder or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed using this license, and may not be distributed
under any other license.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Binary file not shown.

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