forked from kevinowino869/mitrobill
Compare commits
757 Commits
Author | SHA1 | Date | |
---|---|---|---|
8f099bdefb | |||
9fae0f84fd | |||
d50a66845f | |||
915af6fc03 | |||
0a29ec9a86 | |||
27fd677a0a | |||
e2f24c0cc6 | |||
cf60c470b1 | |||
1cc7057dca | |||
1740c568f9 | |||
3347b39f3b | |||
f0b9b56bb0 | |||
24b713804a | |||
182add517c | |||
45cc2afab5 | |||
ba19b1c569 | |||
5caa9f905b | |||
28541f366c | |||
ad7998ebbf | |||
4c64cfabd2 | |||
9bae41dbe7 | |||
bad0545be5 | |||
43a92c5d3b | |||
11e5ebe103 | |||
c573c49fb9 | |||
7bfbdb1efb | |||
dc28298d53 | |||
655e0494d3 | |||
4a441c5763 | |||
5072ff8ba2 | |||
d506dd66ff | |||
e9b0cfd8f0 | |||
aa4dbc0cea | |||
4ef054466d | |||
41a3cbe700 | |||
4938840c5d | |||
127d43e45d | |||
cdfbab7119 | |||
1a2b85ae4f | |||
2e2d967a5b | |||
c45e19189a | |||
d372bf4711 | |||
8b8a0357f0 | |||
1cb0e30e6b | |||
20916b44f0 | |||
c63545d33a | |||
84500cdfc9 | |||
5b21ffcde5 | |||
009040cd3c | |||
781481e118 | |||
66d67cb61d | |||
3372da2ac4 | |||
803d04a91d | |||
17de653752 | |||
9301f1058c | |||
0868d61271 | |||
5f353392e3 | |||
fdd8dad509 | |||
3563fa531b | |||
525f2311fc | |||
3b6a6d2f55 | |||
3cebfa2171 | |||
c65b569f94 | |||
ca5a7d60cf | |||
5987ffafce | |||
d7bbb4d18f | |||
e3c173bea4 | |||
78e1e2f989 | |||
3c7e6c7a64 | |||
827bb8706d | |||
4731a506bc | |||
597c051948 | |||
40d3127ca1 | |||
c75133c9d2 | |||
ed3369244c | |||
cf9abbfb45 | |||
c74d2bf7ec | |||
ec9a06f468 | |||
4e3d89a23c | |||
30ca1d1b2d | |||
1cbff8f9a4 | |||
43b1025d3c | |||
da14a7bfef | |||
8429ed763e | |||
3b7d478635 | |||
ee3dcc05a0 | |||
1e7d9cf6ef | |||
986016083b | |||
c95de08ed8 | |||
d657632876 | |||
d8dbe68f51 | |||
366ef73d57 | |||
dfdf35286f | |||
eea99d218d | |||
08d1de563e | |||
51a0b859ab | |||
47a57912ba | |||
7bbaee1b88 | |||
791e6d55d0 | |||
4564ef90d5 | |||
23524e4c1f | |||
c486acaaf6 | |||
e3476a971c | |||
b9ccc7561c | |||
5a1bb441af | |||
19a48c0c88 | |||
8d2c334da0 | |||
9163f02717 | |||
da86f2c422 | |||
f929560384 | |||
1387f32865 | |||
a39ff8a9a4 | |||
eb96c7a1e4 | |||
83a2505eed | |||
e91fbe89ba | |||
925097c0b2 | |||
6cd46cdf7c | |||
9b331813d1 | |||
1e500d8941 | |||
c433363d31 | |||
3901213a73 | |||
8860ad1d13 | |||
5df32c7119 | |||
08be62053e | |||
71bf301ccf | |||
0e32f128af | |||
686f3de2d3 | |||
b379266973 | |||
9332063c87 | |||
db4c643f93 | |||
1a2f2e24cd | |||
92ce363b16 | |||
5ddbf8258c | |||
4105ad0b8b | |||
af22a26c4c | |||
a2ade795c7 | |||
7b36a46c50 | |||
fa9fe241e2 | |||
1aa4110552 | |||
8917b2ab7b | |||
8238061510 | |||
096b4fb3af | |||
5d3eea1f45 | |||
ee6098774a | |||
d272e572c0 | |||
2be111e9df | |||
6cf7d6b5de | |||
e9a947a24a | |||
20c0543143 | |||
cd1034c3ab | |||
f9a938830d | |||
5b79432f9a | |||
023b4884d1 | |||
fca86ac4dc | |||
ef51d833d8 | |||
c05a943ff5 | |||
693d7f4acf | |||
5b9cdd6681 | |||
a013373554 | |||
aeae936f17 | |||
ea203ebf64 | |||
da0779e368 | |||
4bb5361d4b | |||
69a7d842e0 | |||
fefcd56801 | |||
5f0df84fe7 | |||
80d213bea3 | |||
0b52d3eb35 | |||
569d5e3670 | |||
7396bcdddf | |||
eee1ad72f8 | |||
2b80f5e6f1 | |||
f98aecc61f | |||
4cc85b9261 | |||
eff0c7dab7 | |||
30bdb89d91 | |||
8fc7afb173 | |||
fa5be4c196 | |||
304de7a999 | |||
1ad1320779 | |||
a3f66fdd84 | |||
86b18e27cd | |||
535a44bb54 | |||
929f75dc4d | |||
8e7a1dc0f2 | |||
6865d321c3 | |||
75d6f17eb5 | |||
4bc47a8d85 | |||
0a3205915f | |||
60d945d87f | |||
685b325ef3 | |||
e0884c0a5a | |||
b6fadae2e5 | |||
91271b9f00 | |||
a2237390e0 | |||
b3169a2060 | |||
b3f4edb2d7 | |||
f301382a72 | |||
92f2caeece | |||
9fd8feb16f | |||
ee022781b1 | |||
85c5441934 | |||
9cc7c0c811 | |||
7f785a7c4a | |||
05aa1499ab | |||
2469aa6b99 | |||
4d71c1d48e | |||
bdef2b62c3 | |||
1cae09763f | |||
4ba7c14693 | |||
aa9a2e4277 | |||
bd87f0143b | |||
8c94e9ea01 | |||
d09e657ed5 | |||
fbe541ef9c | |||
5feeb2625e | |||
0d116fcb5b | |||
8d704f496e | |||
94569bca0e | |||
129302d558 | |||
56762ef277 | |||
75880e8366 | |||
cbacb1c52f | |||
01d966082c | |||
e4124bd210 | |||
0d4fde6481 | |||
6790fdd6d4 | |||
40d8a4edfc | |||
09eedf4999 | |||
9adf1412bc | |||
d3e813e7df | |||
6ccabf8b45 | |||
af064ac5bb | |||
0ec7176d1e | |||
c594cf28bb | |||
2a038d63bb | |||
7170b63890 | |||
d44c58f610 | |||
10adbe48ab | |||
b3cb6de028 | |||
96dca1a38b | |||
face7360e8 | |||
f520352bc9 | |||
a81bb5c4f5 | |||
8d9919afa7 | |||
3386b17b1b | |||
60c7f61579 | |||
fa05ffa58b | |||
fa3e256174 | |||
0346a843ea | |||
5a2e75017e | |||
609a24df80 | |||
31dda69d3d | |||
d60b1827d9 | |||
1e43ac210a | |||
9bf80467a1 | |||
093ac7e336 | |||
a67681424e | |||
7799bf1aee | |||
3502be2c78 | |||
f6084f6ca4 | |||
123b74001a | |||
a39bbc3b34 | |||
a15f759dcb | |||
883eb1bbee | |||
8af46e5e51 | |||
1f1e529e3a | |||
bed81136a1 | |||
f322282c6d | |||
396ece50f4 | |||
681d0214c8 | |||
c7d9f8e8c6 | |||
4dd190a61d | |||
88bb3a29f1 | |||
5e8414aa61 | |||
01e832a955 | |||
ada655a074 | |||
3f3435157c | |||
ec6d6cf203 | |||
7026438acc | |||
8a6ee9490b | |||
89808f3291 | |||
8f6bc9f66e | |||
87ebabe1c0 | |||
bf95713512 | |||
0f19c80cfc | |||
b232ccddbf | |||
f4944866a4 | |||
61fafcd5cf | |||
0b2a9bac21 | |||
cbc66fa470 | |||
e2f2146f1e | |||
0dc50a68f5 | |||
690e5912c0 | |||
0e302a5171 | |||
45e2bb5a96 | |||
9aff4dbf26 | |||
0eb900ffd6 | |||
73e85a97ce | |||
da84015aab | |||
754b23b53f | |||
f997ecc702 | |||
5b7ffec115 | |||
1cbdf5a9b2 | |||
273b6d80c2 | |||
1a5a7124f7 | |||
4fe0e8d58c | |||
bbdf561b3b | |||
96fccecbcf | |||
0780438ca8 | |||
cfe0a14f31 | |||
b1e145f0dc | |||
357b7932e9 | |||
b3f6417bbe | |||
051a8de5f2 | |||
1a931ef617 | |||
c5907c194b | |||
1906b1aefd | |||
62c447da9b | |||
51b68b648c | |||
86407f731b | |||
d2d52d0ad0 | |||
c527f1cc7c | |||
47469df558 | |||
c5fd7c0249 | |||
1ea971d3f5 | |||
7d5e0c7a8e | |||
cf6f89b3f2 | |||
2dc50c3637 | |||
da0ca4f087 | |||
486c849eee | |||
c7a09c60cb | |||
fce910455a | |||
ade4e22454 | |||
487d31358d | |||
daf1bb7d67 | |||
7c547c967e | |||
2e61c89d89 | |||
27c736fa69 | |||
b3fd1d5a3e | |||
5d492def3c | |||
0dfa412be8 | |||
c6cb63a1c5 | |||
32418f05fb | |||
3c1d8dbb8a | |||
67a097fddf | |||
e03b250fb7 | |||
8a36746a0f | |||
fd920748be | |||
e32e0aba16 | |||
98589cd283 | |||
fd20ede7aa | |||
226ed41075 | |||
9ec090a621 | |||
c8d5861f2e | |||
92491e22ec | |||
f9e7a8dbb4 | |||
5559069aac | |||
d6144537c4 | |||
04742535ba | |||
f76753b247 | |||
e4f209030f | |||
5c54223454 | |||
13a2de2664 | |||
538cf4e675 | |||
9edb0b4d2f | |||
d0a7f2b991 | |||
f4c15c3475 | |||
50dd4b4839 | |||
1d7dca8ada | |||
694b4d7bac | |||
82dce56209 | |||
b2ac84900e | |||
16de814091 | |||
4ce4633999 | |||
5788c9c0a7 | |||
7acab4d50e | |||
79d0921ebe | |||
77d25738b1 | |||
b34b9064d0 | |||
13adfc8254 | |||
73b829b8c1 | |||
91e7caae80 | |||
40a39f0ced | |||
699ffc1302 | |||
5e2eaa5578 | |||
38f6738c45 | |||
63e564c9dd | |||
27a5d2d45a | |||
153da7c63b | |||
c9778e71b9 | |||
eb970b257a | |||
242dda2e99 | |||
5445aedcd1 | |||
3f77dcf129 | |||
357df8d986 | |||
16199b4c18 | |||
318b52905d | |||
581b765c28 | |||
c3355ad8f7 | |||
5bb724b9b3 | |||
e431f07a71 | |||
b5efe81637 | |||
c827c983ce | |||
a81ddd68dd | |||
9c06225cc2 | |||
6a5fd9d11a | |||
d20fea1cdf | |||
3bd8ebdc76 | |||
8dcd00bc6b | |||
56ddf65fdf | |||
a2347dd241 | |||
b316e4a242 | |||
2b7361cf6b | |||
5ccddf11be | |||
dbf1623ca6 | |||
e17f07f410 | |||
23bba0b189 | |||
167732094b | |||
9569847612 | |||
4c1f49ea81 | |||
b7fdc90aa7 | |||
fec7780f50 | |||
7d24b719b5 | |||
a34f1bb0fc | |||
2863d70214 | |||
949a3d27eb | |||
1b7f449d96 | |||
0295ab44e5 | |||
7f35e7fb68 | |||
b28b40280f | |||
35243cb9b0 | |||
de4c6c730f | |||
53b64548fc | |||
bf11fd2f2c | |||
e0f150633c | |||
06c68ccebd | |||
6db2f2bf0d | |||
32a64d944a | |||
1903dc6b45 | |||
27bd2590f2 | |||
8908f4bdc3 | |||
7fb08eb76f | |||
8a0c17b319 | |||
afbb39b1d9 | |||
7006ad8c40 | |||
99b30f747f | |||
1f1430fd21 | |||
93583afb65 | |||
9779d77f22 | |||
3dfb12d830 | |||
6e446192d8 | |||
51811bd753 | |||
db8affce1f | |||
c740820731 | |||
80e0dc6485 | |||
5552fb20d5 | |||
f08211a83a | |||
71d6024d62 | |||
73993c4f25 | |||
25be52fe9c | |||
5d79f9d842 | |||
70d8cd8e01 | |||
df7293e3d0 | |||
7614422bd8 | |||
5ff9c74f63 | |||
8fdbe0ec1d | |||
e4fb835f2c | |||
d69086d99b | |||
dc42a09685 | |||
08b2e16e73 | |||
8e41749cd4 | |||
383a1e55d7 | |||
3778499611 | |||
fda935b3a6 | |||
d5c2c72a74 | |||
0df7027851 | |||
00081d40e5 | |||
01c2808e43 | |||
e02bf9863f | |||
7f72b0c34a | |||
a04c3dd82b | |||
1a0b3ffaf3 | |||
3ddfc92b18 | |||
9de7a07de4 | |||
52f65ec143 | |||
e8a800bbd6 | |||
36162381cb | |||
d14599f720 | |||
244e552eb6 | |||
6bb9b001dc | |||
7c42ab5b89 | |||
717f29c95d | |||
ee52a2ec1e | |||
2b3d3a6796 | |||
859e0ce6af | |||
8c5ed98f09 | |||
8347a982c5 | |||
60188c736b | |||
ba729f44fc | |||
954a892f86 | |||
fe41b92a7c | |||
b835520ccf | |||
3adfd2f2c3 | |||
434d7d8cf9 | |||
c617bb9a4d | |||
853af04362 | |||
d8894ab296 | |||
0c2249daf9 | |||
e7f4c88648 | |||
da541595a4 | |||
495da312a8 | |||
71cc8290a3 | |||
575ef1c117 | |||
bcb39f114a | |||
544706d82e | |||
6f4f788d8f | |||
0f59250215 | |||
bcff2253ee | |||
676caec8ca | |||
9d6cd6756c | |||
b375460789 | |||
b7aee6f91c | |||
b4907ed661 | |||
44d091cae8 | |||
766c2c268e | |||
14f9559033 | |||
53885a6f7d | |||
46a83d4e30 | |||
b313f1de36 | |||
a6df867ca1 | |||
7339be29f8 | |||
8ae88adc17 | |||
c960baaf1f | |||
5e310cba29 | |||
eb1d804a4d | |||
6ffa396b05 | |||
cd5f9101f2 | |||
f8878ad8b6 | |||
dc55957a53 | |||
bdda199523 | |||
8086802bf6 | |||
53aa187d1f | |||
7685323bd6 | |||
1fe2dac580 | |||
0428d9620e | |||
ad862640cc | |||
a4e8ae8c5c | |||
d4c34afb8d | |||
0dc4d22da3 | |||
169a7afe67 | |||
67890881f3 | |||
3febb60253 | |||
005155e2a5 | |||
f8a15e4754 | |||
f0da633808 | |||
5f6b14ab7e | |||
3475a6086d | |||
49f194a7f2 | |||
b3744a5007 | |||
234e5e3967 | |||
97296abf06 | |||
a7232e2b92 | |||
7c0bdeea41 | |||
5566a7ebb5 | |||
de49a9992f | |||
0cf5483353 | |||
b15fdf1d6a | |||
ca98ca2223 | |||
5ccb8520d3 | |||
ff4e620b75 | |||
1b7e5c7510 | |||
084cc0e0fb | |||
25d9524f53 | |||
4308765bec | |||
70dbe59319 | |||
577ed31f57 | |||
064e4c80ed | |||
70bcff7679 | |||
47b729867d | |||
696b2e4789 | |||
0f0929db2a | |||
7267bd082a | |||
d5cba4b3c1 | |||
155b2959b5 | |||
a35137b7ab | |||
83dd564e53 | |||
8e8a52d807 | |||
5bc273a9dd | |||
f9fe261e55 | |||
0dc79cd5c4 | |||
b32e2901af | |||
f77d7051c1 | |||
60e1eacc59 | |||
82ffc15c03 | |||
6e5450d104 | |||
6458b792f6 | |||
6be0da383c | |||
534886f8f3 | |||
c9b9808112 | |||
e737ae9d29 | |||
78e3f2e8fb | |||
3eaa302128 | |||
9bc3ccc02b | |||
99e8b20bb3 | |||
bd30261e84 | |||
96365eef2a | |||
c08c069479 | |||
71d653f3d1 | |||
b1919555e5 | |||
2522f3112e | |||
ba63face92 | |||
8f78f5184e | |||
e9ae2e04ce | |||
56c69122e4 | |||
2198c00d52 | |||
695b3c7a6f | |||
f7cb6c196f | |||
5adb09efcf | |||
e70a6c4dae | |||
4f3647beae | |||
9016ecbb98 | |||
277ab87645 | |||
3a929c5418 | |||
2771eba0ee | |||
5b51af1b6e | |||
05eab22062 | |||
d4eaaad535 | |||
3407571474 | |||
da1341d971 | |||
e4e70c5104 | |||
fbde8b0056 | |||
9552783eee | |||
44f852ab2f | |||
3da0c356de | |||
d2db2bef79 | |||
44af731c4c | |||
0a9733b0b3 | |||
79c25a64d6 | |||
e4d3aff618 | |||
6462572fb8 | |||
a51462ef1a | |||
4ffbac878c | |||
3a2c55e0d8 | |||
229eae5c8f | |||
aa0432df38 | |||
8e3a16a123 | |||
aa1ef2c41c | |||
4567f82a06 | |||
ce61df9057 | |||
6a24c6c11e | |||
b1ad007db0 | |||
bfd014417b | |||
9b1adb15da | |||
686d2a188a | |||
1a65c04666 | |||
7e9f6123e8 | |||
f738c9b120 | |||
5f7f785d99 | |||
c0c54ce767 | |||
f81f3df700 | |||
3c6ef3bcf3 | |||
985ddda41f | |||
a31286d781 | |||
c2916da215 | |||
82569239e2 | |||
bc0b3abe92 | |||
f5d9649f97 | |||
095e8937a2 | |||
5f50d725f1 | |||
68de3a71b9 | |||
fe532a6238 | |||
05b681df47 | |||
723e99ebed | |||
13aabeea8e | |||
400672454c | |||
aa3e522bc9 | |||
b7fce955ac | |||
594fab1151 | |||
3aead7a98a | |||
9a1321f597 | |||
45bb3f04ee | |||
0d2b140bcf | |||
f736868819 | |||
84bc680f40 | |||
53512cfa58 | |||
d0e66d8651 | |||
c45ea74a29 | |||
22615eb278 | |||
ae550df078 | |||
cc74667451 | |||
0fec69df89 | |||
36b4a282ee | |||
cb5ffb4236 | |||
2328489a14 | |||
f8351e46f6 | |||
cf9a11ef94 | |||
80d4c904d0 | |||
9e63d7ce20 | |||
b517ef2b73 | |||
ea0c663278 | |||
299fd90949 | |||
c255a7be49 | |||
4f74aa0bff | |||
93d53cc6d8 | |||
40f452cff8 | |||
aa787af017 | |||
af753d3a52 | |||
d060e21032 | |||
f43a2dcd7a | |||
0b5bc1fe71 | |||
4f969c787a | |||
087ce1d0b6 | |||
d7d76dde94 | |||
7cbb874029 | |||
44fe6a0ff7 | |||
74ec6128ab | |||
899c27f1a7 | |||
f7a86666c2 | |||
a22e2e1b2c | |||
cc6babf04a | |||
9e7698f83d | |||
e1008ae61f | |||
ef0d19393f | |||
8e2a40d670 | |||
34482ff0d4 | |||
35ace619d2 | |||
6da6041cb8 | |||
463ee27116 | |||
fe930a1012 | |||
abd22418ce | |||
9099584d7c | |||
5a84e10b70 | |||
89786c64af | |||
e7ec68872b | |||
82d756567e | |||
9436a6e8f1 | |||
e8885e91ec | |||
8e96f1457a | |||
2a2e9c3bd4 | |||
b8e856518f | |||
4e19894152 | |||
414f9929e5 | |||
5bcf278733 | |||
453ea564cf | |||
a167d97e3c | |||
55349b40dd | |||
bac8819c31 | |||
aaeaa9305a | |||
f37987a4c6 | |||
393939fab4 | |||
0189234b56 | |||
8d4d88f702 | |||
5d79cb65ce | |||
1d08e8d204 | |||
afaafd6195 | |||
bd9989eaf2 |
9
.gitignore
vendored
9
.gitignore
vendored
@ -46,10 +46,17 @@ system/devices/**
|
||||
!system/devices/Radius.php
|
||||
!system/devices/RadiusRest.php
|
||||
!system/devices/MikrotikPppoe.php
|
||||
!system/devices/MikrotikPppoeCustom.php
|
||||
!system/devices/MikrotikHotspot.php
|
||||
/.vs
|
||||
docker-compose.yml
|
||||
docs/**
|
||||
!docs/*.html
|
||||
!docs/*.md
|
||||
.htaccess
|
||||
.htaccess
|
||||
.idea
|
||||
!docs/insomnia.rest.json
|
||||
!system/uploads/paid.png
|
||||
system/uploads/invoices/**
|
||||
!system/uploads/invoices/
|
||||
!system/uploads/invoices/index.html
|
@ -13,6 +13,11 @@
|
||||
Allow from all
|
||||
</Files>
|
||||
|
||||
<Files radius.php>
|
||||
Order Allow,Deny
|
||||
Allow from all
|
||||
</Files>
|
||||
|
||||
RewriteEngine On
|
||||
RewriteBase /
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
|
48
CHANGELOG.md
48
CHANGELOG.md
@ -2,6 +2,54 @@
|
||||
|
||||
# CHANGELOG
|
||||
|
||||
## 2024.10.23
|
||||
|
||||
- Custom Balance admin refill Requested by Javi Tech
|
||||
- Only Admin can edit Customer Requested by Fiberwan
|
||||
- Only Admin can show password Requested by Fiberwan
|
||||
|
||||
## 2024.10.18
|
||||
|
||||
- Single Session Admin Can be set in the Settings
|
||||
- Auto expired unpaid transaction
|
||||
- Registration Type
|
||||
- Can Login as User from Customer View
|
||||
- Can select customer register must using OTP or not
|
||||
- Add Meta.php for additional information
|
||||
|
||||
## 2024.10.15
|
||||
|
||||
- CSRF Security
|
||||
- Admin can only have 1 active session
|
||||
- Move Miscellaneous Settings to new page
|
||||
- Fix Customer Online
|
||||
- Count Shared user online for Radius REST
|
||||
- Fix Invoice Print
|
||||
|
||||
## 2024.10.7
|
||||
|
||||
- Show Customer is Online or not
|
||||
- Change Invoice Theme for printing
|
||||
- Rearange Customer View
|
||||
|
||||
## 2024.9.23
|
||||
|
||||
- Discount Price
|
||||
- Burst Preset
|
||||
|
||||
## 2024.9.20
|
||||
|
||||
- Forgot Password
|
||||
- Forgot Username
|
||||
- Public header template
|
||||
|
||||
## 2024.9.13
|
||||
|
||||
- Add Selling Mikrotik VPN By @agstrxyz
|
||||
- Theme Redesign by @Focuslinkstech
|
||||
- Fix That and this
|
||||
|
||||
|
||||
## 2024.8.28
|
||||
|
||||
- add Router Status Offline/Online by @Focuslinkstech
|
||||
|
27
README.md
27
README.md
@ -36,7 +36,7 @@ Most current web servers with PHP & MySQL installed will be capable of running P
|
||||
Minimum Requirements
|
||||
|
||||
- Linux or Windows OS
|
||||
- Minimum PHP Version 7.4
|
||||
- Minimum PHP Version 8.2
|
||||
- Both PDO & MySQLi Support
|
||||
- PHP-GD2 Image Library
|
||||
- PHP-CURL
|
||||
@ -83,27 +83,4 @@ Contact me at [Telegram](https://t.me/ibnux)
|
||||
|
||||
GNU General Public License version 2 or later
|
||||
|
||||
see [LICENSE](LICENSE) file
|
||||
|
||||
|
||||
## Donate to ibnux
|
||||
|
||||
[](https://paypal.me/ibnux)
|
||||
|
||||
BCA: 5410454825
|
||||
|
||||
Mandiri: 163-000-1855-793
|
||||
|
||||
a.n Ibnu Maksum
|
||||
|
||||
## SPONSORS
|
||||
|
||||
- [mlink.id](https://mlink.id)
|
||||
- [https://github.com/sonyinside](https://github.com/sonyinside)
|
||||
|
||||
## Thanks
|
||||
We appreciate all people who are participating in this project.
|
||||
|
||||
<a href="https://github.com/hotspotbilling/phpnuxbill/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=hotspotbilling/phpnuxbill" />
|
||||
</a>
|
||||
see [LICENSE](LICENSE) file
|
@ -5,4 +5,4 @@
|
||||
**/
|
||||
|
||||
|
||||
header('location: ../index.php?_route=admin/');
|
||||
header('location: ../?_route=admin/');
|
@ -1,10 +1,15 @@
|
||||
<?php
|
||||
|
||||
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
|
||||
$host = $_SERVER['HTTP_HOST'];
|
||||
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ||
|
||||
(isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443)) ? "https://" : "http://";
|
||||
|
||||
// Check if HTTP_HOST is set, otherwise use a default value or SERVER_NAME
|
||||
$host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost');
|
||||
|
||||
$baseDir = rtrim(dirname($_SERVER['SCRIPT_NAME']), '/\\');
|
||||
define('APP_URL', $protocol . $host . $baseDir);
|
||||
|
||||
|
||||
$_app_stage = 'Live'; # Do not change this
|
||||
|
||||
$db_host = "localhost"; # Database Host
|
||||
|
File diff suppressed because one or more lines are too long
1
docs/insomnia.rest.json
Normal file
1
docs/insomnia.rest.json
Normal file
File diff suppressed because one or more lines are too long
94
init.php
94
init.php
@ -42,12 +42,13 @@ spl_autoload_register('_autoloader');
|
||||
if (!file_exists($root_path . 'config.php')) {
|
||||
$root_path .= '..' . DIRECTORY_SEPARATOR;
|
||||
if (!file_exists($root_path . 'config.php')) {
|
||||
r2('install');
|
||||
r2('./install');
|
||||
}
|
||||
}
|
||||
|
||||
if (!file_exists($root_path . File::pathFixer('system/orm.php'))) {
|
||||
die($root_path . "orm.php file not found");
|
||||
echo $root_path . "orm.php file not found";
|
||||
die();
|
||||
}
|
||||
|
||||
$DEVICE_PATH = $root_path . File::pathFixer('system/devices');
|
||||
@ -55,11 +56,13 @@ $UPLOAD_PATH = $root_path . File::pathFixer('system/uploads');
|
||||
$CACHE_PATH = $root_path . File::pathFixer('system/cache');
|
||||
$PAGES_PATH = $root_path . File::pathFixer('pages');
|
||||
$PLUGIN_PATH = $root_path . File::pathFixer('system/plugin');
|
||||
$WIDGET_PATH = $root_path . File::pathFixer('system/widgets');
|
||||
$PAYMENTGATEWAY_PATH = $root_path . File::pathFixer('system/paymentgateway');
|
||||
$UI_PATH = 'ui';
|
||||
|
||||
if (!file_exists($UPLOAD_PATH . File::pathFixer('/notifications.default.json'))) {
|
||||
die($UPLOAD_PATH . File::pathFixer("/notifications.default.json file not found"));
|
||||
echo $UPLOAD_PATH . File::pathFixer("/notifications.default.json file not found");
|
||||
die();
|
||||
}
|
||||
|
||||
require_once $root_path . 'config.php';
|
||||
@ -67,11 +70,11 @@ require_once $root_path . File::pathFixer('system/orm.php');
|
||||
require_once $root_path . File::pathFixer('system/autoload/PEAR2/Autoload.php');
|
||||
include $root_path . File::pathFixer('system/autoload/Hookers.php');
|
||||
|
||||
if($db_password != null && ($db_pass == null || empty($db_pass))){
|
||||
if ($db_password != null && ($db_pass == null || empty($db_pass))) {
|
||||
// compability for old version
|
||||
$db_pass = $db_password;
|
||||
}
|
||||
if($db_pass != null){
|
||||
if ($db_pass != null) {
|
||||
// compability for old version
|
||||
$db_password = $db_pass;
|
||||
}
|
||||
@ -85,7 +88,7 @@ if ($_app_stage != 'Live') {
|
||||
if ($isApi) {
|
||||
define('U', APP_URL . '/system/api.php?r=');
|
||||
} else {
|
||||
define('U', APP_URL . '/index.php?_route=');
|
||||
define('U', APP_URL . '/?_route=');
|
||||
}
|
||||
|
||||
// notification message
|
||||
@ -109,6 +112,24 @@ $result = ORM::for_table('tbl_appconfig')->find_many();
|
||||
foreach ($result as $value) {
|
||||
$config[$value['setting']] = $value['value'];
|
||||
}
|
||||
|
||||
if(empty($config['dashboard_Admin'])){
|
||||
$config['dashboard_Admin'] = "12.7,5.12";
|
||||
}
|
||||
|
||||
if(empty($config['dashboard_Agent'])){
|
||||
$config['dashboard_Agent'] = "12.7,5.12";
|
||||
}
|
||||
|
||||
if(empty($config['dashboard_Sales'])){
|
||||
$config['dashboard_Sales'] = "12.7,5.12";
|
||||
}
|
||||
|
||||
if(empty($config['dashboard_Customer'])){
|
||||
$config['dashboard_Customer'] = "6,6";
|
||||
}
|
||||
|
||||
|
||||
$_c = $config;
|
||||
if (empty($http_proxy) && !empty($config['http_proxy'])) {
|
||||
$http_proxy = $config['http_proxy'];
|
||||
@ -119,7 +140,7 @@ if (empty($http_proxy) && !empty($config['http_proxy'])) {
|
||||
date_default_timezone_set($config['timezone']);
|
||||
|
||||
if ((!empty($radius_user) && $config['radius_enable']) || _post('radius_enable')) {
|
||||
if(!empty($radius_password)){
|
||||
if (!empty($radius_password)) {
|
||||
// compability for old version
|
||||
$radius_pass = $radius_password;
|
||||
}
|
||||
@ -134,32 +155,25 @@ if ((!empty($radius_user) && $config['radius_enable']) || _post('radius_enable')
|
||||
// Check if the user has selected a language
|
||||
if (!empty($_SESSION['user_language'])) {
|
||||
$config['language'] = $_SESSION['user_language'];
|
||||
}else if (!empty($_COOKIE['user_language'])) {
|
||||
} else if (!empty($_COOKIE['user_language'])) {
|
||||
$config['language'] = $_COOKIE['user_language'];
|
||||
}else if(User::getID()>0){
|
||||
} else if (User::getID() > 0) {
|
||||
$lang = User::getAttribute("Language");
|
||||
if(!empty($lang)){
|
||||
if (!empty($lang)) {
|
||||
$config['language'] = $lang;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($_SESSION['Lang'])) {
|
||||
if (empty($config['language'])) {
|
||||
$config['language'] = 'english';
|
||||
}
|
||||
$lan_file = $root_path . File::pathFixer('system/lan/' . $config['language'] . '.json');
|
||||
if (file_exists($lan_file)) {
|
||||
$_L = json_decode(file_get_contents($lan_file), true);
|
||||
$_SESSION['Lang'] = $_L;
|
||||
} else {
|
||||
$_L['author'] = 'Auto Generated by iBNuX Script';
|
||||
$_SESSION['Lang'] = $_L;
|
||||
file_put_contents($lan_file, json_encode($_L));
|
||||
}
|
||||
} else {
|
||||
$_L = $_SESSION['Lang'];
|
||||
if (empty($config['language'])) {
|
||||
$config['language'] = 'english';
|
||||
}
|
||||
$lan_file = $root_path . File::pathFixer('system/lan/' . $config['language'] . '.json');
|
||||
if (file_exists($lan_file)) {
|
||||
$_L = json_decode(file_get_contents($lan_file), true);
|
||||
} else {
|
||||
$_L['author'] = 'Auto Generated by PHPNuxBill Script';
|
||||
file_put_contents($lan_file, json_encode($_L));
|
||||
}
|
||||
|
||||
|
||||
function safedata($value)
|
||||
{
|
||||
@ -201,7 +215,7 @@ function _auth($login = true)
|
||||
return true;
|
||||
} else {
|
||||
if ($login) {
|
||||
r2(U . 'login');
|
||||
r2(getUrl('login'));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -214,7 +228,7 @@ function _admin($login = true)
|
||||
return true;
|
||||
} else {
|
||||
if ($login) {
|
||||
r2(U . 'login');
|
||||
r2(getUrl('login'));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -238,8 +252,12 @@ function _log($description, $type = '', $userid = '0')
|
||||
} elseif (!empty($_SERVER['HTTP_CLIENT_IP'])) //to check ip from share internet
|
||||
{
|
||||
$d->ip = $_SERVER['HTTP_CLIENT_IP'];
|
||||
} else {
|
||||
} else if (isset($_SERVER["REMOTE_ADDR"])) {
|
||||
$d->ip = $_SERVER["REMOTE_ADDR"];
|
||||
} else if (php_sapi_name() == 'cli') {
|
||||
$d->ip = 'CLI';
|
||||
} else {
|
||||
$d->ip = 'Unknown';
|
||||
}
|
||||
$d->save();
|
||||
}
|
||||
@ -262,6 +280,13 @@ function showResult($success, $message = '', $result = [], $meta = [])
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* make url canonical or standar
|
||||
*/
|
||||
function getUrl($url)
|
||||
{
|
||||
return Text::url($url);
|
||||
}
|
||||
|
||||
function generateUniqueNumericVouchers($totalVouchers, $length = 8)
|
||||
{
|
||||
@ -334,16 +359,16 @@ function _alert($text, $type = 'success', $url = "home", $time = 3)
|
||||
if (!isset($ui)) return;
|
||||
if (strlen($url) > 4) {
|
||||
if (substr($url, 0, 4) != "http") {
|
||||
$url = U . $url;
|
||||
$url = getUrl($url);
|
||||
}
|
||||
} else {
|
||||
$url = U . $url;
|
||||
$url = getUrl($url);
|
||||
}
|
||||
$ui->assign('text', $text);
|
||||
$ui->assign('type', $type);
|
||||
$ui->assign('time', $time);
|
||||
$ui->assign('url', $url);
|
||||
$ui->display('alert.tpl');
|
||||
$ui->display('admin/alert.tpl');
|
||||
die();
|
||||
}
|
||||
|
||||
@ -356,12 +381,12 @@ function displayMaintenanceMessage(): void
|
||||
{
|
||||
global $config, $ui;
|
||||
$date = $config['maintenance_date'];
|
||||
if ($date){
|
||||
if ($date) {
|
||||
$ui->assign('date', $date);
|
||||
}
|
||||
http_response_code(503);
|
||||
$ui->assign('companyName', $config['CompanyName']);
|
||||
$ui->display('maintenance.tpl');
|
||||
$ui->display('admin/maintenance.tpl');
|
||||
die();
|
||||
}
|
||||
|
||||
@ -374,4 +399,3 @@ function isTableExist($table)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
20
install/css/bootstrap.css
vendored
20
install/css/bootstrap.css
vendored
@ -1374,7 +1374,7 @@ pre {
|
||||
color: #333;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
background-color: #f5f5f5;
|
||||
background-color: #f6f8fa;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}
|
||||
@ -2126,7 +2126,7 @@ th {
|
||||
}
|
||||
.table-hover > tbody > tr:hover > td,
|
||||
.table-hover > tbody > tr:hover > th {
|
||||
background-color: #f5f5f5;
|
||||
background-color: #f6f8fa;
|
||||
}
|
||||
table col[class*="col-"] {
|
||||
position: static;
|
||||
@ -2151,7 +2151,7 @@ table th[class*="col-"] {
|
||||
.table > thead > tr.active > th,
|
||||
.table > tbody > tr.active > th,
|
||||
.table > tfoot > tr.active > th {
|
||||
background-color: #f5f5f5;
|
||||
background-color: #f6f8fa;
|
||||
}
|
||||
.table-hover > tbody > tr > td.active:hover,
|
||||
.table-hover > tbody > tr > th.active:hover,
|
||||
@ -3170,7 +3170,7 @@ tbody.collapse.in {
|
||||
.dropdown-menu > li > a:focus {
|
||||
color: #262626;
|
||||
text-decoration: none;
|
||||
background-color: #f5f5f5;
|
||||
background-color: #f6f8fa;
|
||||
}
|
||||
.dropdown-menu > .active > a,
|
||||
.dropdown-menu > .active > a:hover,
|
||||
@ -4293,7 +4293,7 @@ fieldset[disabled] .navbar-inverse .btn-link:focus {
|
||||
padding: 8px 15px;
|
||||
margin-bottom: 20px;
|
||||
list-style: none;
|
||||
background-color: #f5f5f5;
|
||||
background-color: #f6f8fa;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.breadcrumb > li {
|
||||
@ -4711,7 +4711,7 @@ a.thumbnail.active {
|
||||
height: 20px;
|
||||
margin-bottom: 20px;
|
||||
overflow: hidden;
|
||||
background-color: #f5f5f5;
|
||||
background-color: #f6f8fa;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
|
||||
@ -4854,7 +4854,7 @@ a.list-group-item:hover,
|
||||
a.list-group-item:focus {
|
||||
color: #555;
|
||||
text-decoration: none;
|
||||
background-color: #f5f5f5;
|
||||
background-color: #f6f8fa;
|
||||
}
|
||||
.list-group-item.disabled,
|
||||
.list-group-item.disabled:hover,
|
||||
@ -5023,7 +5023,7 @@ a.list-group-item-danger.active:focus {
|
||||
}
|
||||
.panel-footer {
|
||||
padding: 10px 15px;
|
||||
background-color: #f5f5f5;
|
||||
background-color: #f6f8fa;
|
||||
border-top: 1px solid #ddd;
|
||||
border-bottom-right-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
@ -5197,7 +5197,7 @@ a.list-group-item-danger.active:focus {
|
||||
}
|
||||
.panel-default > .panel-heading {
|
||||
color: #333;
|
||||
background-color: #f5f5f5;
|
||||
background-color: #f6f8fa;
|
||||
border-color: #ddd;
|
||||
}
|
||||
.panel-default > .panel-heading + .panel-collapse > .panel-body {
|
||||
@ -5329,7 +5329,7 @@ a.list-group-item-danger.active:focus {
|
||||
min-height: 20px;
|
||||
padding: 19px;
|
||||
margin-bottom: 20px;
|
||||
background-color: #f5f5f5;
|
||||
background-color: #f6f8fa;
|
||||
border: 1px solid #e3e3e3;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
|
||||
|
@ -27,6 +27,7 @@ CREATE TABLE `tbl_customers` (
|
||||
`id` int 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,
|
||||
`photo` VARCHAR(128) NOT NULL DEFAULT '/user.default.jpg',
|
||||
`pppoe_username` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login',
|
||||
`pppoe_password` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login',
|
||||
`pppoe_ip` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login',
|
||||
@ -71,6 +72,7 @@ DROP TABLE IF EXISTS `tbl_payment_gateway`;
|
||||
CREATE TABLE `tbl_payment_gateway` (
|
||||
`id` int NOT NULL,
|
||||
`username` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`user_id` int(11) NOT NULL DEFAULT 0,
|
||||
`gateway` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'xendit | midtrans',
|
||||
`gateway_trx_id` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
|
||||
`plan_id` int NOT NULL,
|
||||
@ -149,6 +151,7 @@ CREATE TABLE `tbl_transactions` (
|
||||
`id` int NOT NULL,
|
||||
`invoice` varchar(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`username` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`user_id` int(11) NOT NULL DEFAULT 0,
|
||||
`plan_name` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`price` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`recharged_on` date NOT NULL,
|
||||
@ -166,6 +169,7 @@ DROP TABLE IF EXISTS `tbl_users`;
|
||||
CREATE TABLE `tbl_users` (
|
||||
`id` int UNSIGNED NOT NULL,
|
||||
`root` int NOT NULL DEFAULT '0' COMMENT 'for sub account',
|
||||
`photo` VARCHAR(128) NOT NULL DEFAULT '/admin.default.png',
|
||||
`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` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
@ -176,7 +180,9 @@ CREATE TABLE `tbl_users` (
|
||||
`ward` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'kelurahan',
|
||||
`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',
|
||||
`data` TEXT NULL DEFAULT NULL COMMENT 'to put additional data',
|
||||
`last_login` datetime DEFAULT NULL,
|
||||
`login_token` VARCHAR(40),
|
||||
`creationdate` datetime NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
@ -207,6 +213,7 @@ CREATE TABLE `tbl_voucher` (
|
||||
`code` varchar(55) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`user` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`status` varchar(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`used_date` DATETIME NULL DEFAULT NULL,
|
||||
`generated_by` int NOT NULL DEFAULT '0' COMMENT 'id admin'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
@ -223,6 +230,7 @@ CREATE TABLE `rad_acct` (
|
||||
`nasportid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||
`nasporttype` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||
`framedipaddress` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
|
||||
`acctsessiontime` BIGINT NOT NULL DEFAULT '0',
|
||||
`acctinputoctets` BIGINT NOT NULL DEFAULT '0',
|
||||
`acctoutputoctets` BIGINT NOT NULL DEFAULT '0',
|
||||
`acctstatustype` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||
@ -243,6 +251,63 @@ CREATE TABLE `tbl_customers_inbox` (
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
DROP TABLE IF EXISTS `tbl_port_pool`;
|
||||
CREATE TABLE IF NOT EXISTS `tbl_port_pool` (
|
||||
`id` int(10) NOT NULL AUTO_INCREMENT,
|
||||
`public_ip` varchar(40) NOT NULL,
|
||||
`port_name` varchar(40) NOT NULL,
|
||||
`range_port` varchar(40) NOT NULL,
|
||||
`routers` varchar(40) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `tbl_meta` (
|
||||
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`tbl` varchar(32) COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Table name',
|
||||
`tbl_id` int NOT NULL COMMENT 'table value id',
|
||||
`name` varchar(32) COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`value` mediumtext COLLATE utf8mb4_general_ci,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='This Table to add additional data for any table';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `tbl_coupons` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`code` VARCHAR(50) NOT NULL UNIQUE,
|
||||
`type` ENUM('fixed', 'percent') NOT NULL,
|
||||
`value` DECIMAL(10,2) NOT NULL,
|
||||
`description` TEXT NOT NULL,
|
||||
`max_usage` INT NOT NULL DEFAULT 1,
|
||||
`usage_count` INT NOT NULL DEFAULT 0,
|
||||
`status` ENUM('active', 'inactive') NOT NULL,
|
||||
`min_order_amount` DECIMAL(10,2) NOT NULL,
|
||||
`max_discount_amount` DECIMAL(10,2) NOT NULL,
|
||||
`start_date` DATE NOT NULL,
|
||||
`end_date` DATE NOT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `tbl_widgets` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`orders` int NOT NULL DEFAULT '99',
|
||||
`position` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1. top 2. left 3. right 4. bottom',
|
||||
`user` ENUM('Admin','Agent','Sales','Customer') NOT NULL DEFAULT 'Admin',
|
||||
`enabled` tinyint(1) NOT NULL DEFAULT '1',
|
||||
`title` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`widget` varchar(64) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
|
||||
`content` text COLLATE utf8mb4_general_ci NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE tbl_message_logs (
|
||||
`id` SERIAL PRIMARY KEY,
|
||||
`message_type` VARCHAR(50),
|
||||
`recipient` VARCHAR(255),
|
||||
`message_content` TEXT,
|
||||
`status` VARCHAR(50),
|
||||
`error_message` TEXT,
|
||||
`sent_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
ALTER TABLE `rad_acct`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
@ -364,3 +429,48 @@ VALUES (
|
||||
'2022-09-06 16:09:50',
|
||||
'2014-06-23 01:43:07'
|
||||
);
|
||||
|
||||
INSERT INTO `tbl_widgets` (`id`, `orders`, `position`, `user`, `enabled`, `title`, `widget`, `content`) VALUES
|
||||
(1, 1, 1, 'Admin', 1, 'Top Widget', 'top_widget', ''),
|
||||
(2, 2, 1, 'Admin', 1, 'Default Info', 'default_info_row', ''),
|
||||
(3, 1, 2, 'Admin', 1, 'Graph Monthly Registered Customers', 'graph_monthly_registered_customers', ''),
|
||||
(4, 2, 2, 'Admin', 1, 'Graph Monthly Sales', 'graph_monthly_sales', ''),
|
||||
(5, 3, 2, 'Admin', 1, 'Voucher Stocks', 'voucher_stocks', ''),
|
||||
(6, 4, 2, 'Admin', 1, 'Customer Expired', 'customer_expired', ''),
|
||||
(7, 1, 3, 'Admin', 1, 'Cron Monitor', 'cron_monitor', ''),
|
||||
(8, 2, 3, 'Admin', 1, 'Mikrotik Cron Monitor', 'mikrotik_cron_monitor', ''),
|
||||
(9, 3, 3, 'Admin', 1, 'Info Payment Gateway', 'info_payment_gateway', ''),
|
||||
(10, 4, 3, 'Admin', 1, 'Graph Customers Insight', 'graph_customers_insight', ''),
|
||||
(11, 5, 3, 'Admin', 1, 'Activity Log', 'activity_log', ''),
|
||||
|
||||
(30, 1, 1, 'Agent', 1, 'Top Widget', 'top_widget', ''),
|
||||
(31, 2, 1, 'Agent', 1, 'Default Info', 'default_info_row', ''),
|
||||
(32, 1, 2, 'Agent', 1, 'Graph Monthly Registered Customers', 'graph_monthly_registered_customers', ''),
|
||||
(33, 2, 2, 'Agent', 1, 'Graph Monthly Sales', 'graph_monthly_sales', ''),
|
||||
(34, 3, 2, 'Agent', 1, 'Voucher Stocks', 'voucher_stocks', ''),
|
||||
(35, 4, 2, 'Agent', 1, 'Customer Expired', 'customer_expired', ''),
|
||||
(36, 1, 3, 'Agent', 1, 'Cron Monitor', 'cron_monitor', ''),
|
||||
(37, 2, 3, 'Agent', 1, 'Mikrotik Cron Monitor', 'mikrotik_cron_monitor', ''),
|
||||
(38, 3, 3, 'Agent', 1, 'Info Payment Gateway', 'info_payment_gateway', ''),
|
||||
(39, 4, 3, 'Agent', 1, 'Graph Customers Insight', 'graph_customers_insight', ''),
|
||||
(40, 5, 3, 'Agent', 1, 'Activity Log', 'activity_log', ''),
|
||||
|
||||
(41, 1, 1, 'Sales', 1, 'Top Widget', 'top_widget', ''),
|
||||
(42, 2, 1, 'Sales', 1, 'Default Info', 'default_info_row', ''),
|
||||
(43, 1, 2, 'Sales', 1, 'Graph Monthly Registered Customers', 'graph_monthly_registered_customers', ''),
|
||||
(44, 2, 2, 'Sales', 1, 'Graph Monthly Sales', 'graph_monthly_sales', ''),
|
||||
(45, 3, 2, 'Sales', 1, 'Voucher Stocks', 'voucher_stocks', ''),
|
||||
(46, 4, 2, 'Sales', 1, 'Customer Expired', 'customer_expired', ''),
|
||||
(47, 1, 3, 'Sales', 1, 'Cron Monitor', 'cron_monitor', ''),
|
||||
(48, 2, 3, 'Sales', 1, 'Mikrotik Cron Monitor', 'mikrotik_cron_monitor', ''),
|
||||
(49, 3, 3, 'Sales', 1, 'Info Payment Gateway', 'info_payment_gateway', ''),
|
||||
(50, 4, 3, 'Sales', 1, 'Graph Customers Insight', 'graph_customers_insight', ''),
|
||||
(51, 5, 3, 'Sales', 1, 'Activity Log', 'activity_log', ''),
|
||||
|
||||
(60, 1, 2, 'Customer', 1, 'Account Info', 'account_info', ''),
|
||||
(61, 3, 1, 'Customer', 1, 'Active Internet Plan', 'active_internet_plan', ''),
|
||||
(62, 4, 1, 'Customer', 1, 'Balance Transfer', 'balance_transfer', ''),
|
||||
(63, 1, 1, 'Customer', 1, 'Unpaid Order', 'unpaid_order', ''),
|
||||
(64, 2, 1, 'Customer', 1, 'Announcement', 'announcement', ''),
|
||||
(65, 5, 1, 'Customer', 1, 'Recharge A Friend', 'recharge_a_friend', ''),
|
||||
(66, 2, 2, 'Customer', 1, 'Voucher Activation', 'voucher_activation', '');
|
643
login.html
Normal file
643
login.html
Normal file
@ -0,0 +1,643 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>yatmack</title>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/3.8.3/core.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link href='https://fonts.googleapis.com/css2?family=Lexend:wght@300;400;500;600;700&display=swap' rel='stylesheet'>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script>
|
||||
tailwind.config = {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
navy: {
|
||||
DEFAULT: '#023047',
|
||||
50: '#e6f0f5',
|
||||
100: '#cce1eb',
|
||||
200: '#99c3d7',
|
||||
300: '#66a5c3',
|
||||
400: '#3387af',
|
||||
500: '#023047',
|
||||
600: '#022640',
|
||||
700: '#011d39',
|
||||
800: '#011332',
|
||||
900: '#010a2b'
|
||||
},
|
||||
orange: {
|
||||
DEFAULT: '#fb8500',
|
||||
50: '#fff4e6',
|
||||
100: '#ffe9cc',
|
||||
200: '#ffd399',
|
||||
300: '#ffbd66',
|
||||
400: '#ffa733',
|
||||
500: '#fb8500',
|
||||
600: '#cc6d00',
|
||||
700: '#995200',
|
||||
800: '#663600',
|
||||
900: '#331b00'
|
||||
}
|
||||
},
|
||||
fontFamily: {
|
||||
'lexend': ['Lexend', 'sans-serif'],
|
||||
},
|
||||
animation: {
|
||||
'spin-fast': 'spin 0.5s linear infinite',
|
||||
'fade-in': 'fadeIn 0.3s ease-in-out',
|
||||
'slide-up': 'slideUp 0.3s ease-out'
|
||||
},
|
||||
keyframes: {
|
||||
fadeIn: {
|
||||
'0%': { opacity: '0' },
|
||||
'100%': { opacity: '1' }
|
||||
},
|
||||
slideUp: {
|
||||
'0%': { transform: 'translateY(10px)', opacity: '0' },
|
||||
'100%': { transform: 'translateY(0)', opacity: '1' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body class="font-lexend min-h-screen bg-gradient-to-b from-navy to-navy/95 text-gray-100">
|
||||
<div class="container mx-auto px-2 py-4 max-w-3xl">
|
||||
<div class="bg-white/10 backdrop-blur-lg rounded-2xl shadow-xl mb-6 overflow-hidden border border-white/10">
|
||||
<div class="p-3 relative">
|
||||
<h1 class="text-2xl font-bold text-center text-orange mb-3">YATMACK HOTSPOT</h1>
|
||||
<p class="text-gray-100/90 text-center text-sm mb-4">
|
||||
Select package ? Enter M-Pesa number ? Complete payment
|
||||
</p>
|
||||
<div class="flex items-center justify-center gap-2 py-2 px-4 bg-white/5 rounded-xl">
|
||||
<i class="fas fa-headset text-orange"></i>
|
||||
<p class="text-sm font-medium">Support: 254705042522</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="py-2 sm:py-1 lg:py-1">
|
||||
<div class="mx-auto max-w-screen-2xl px-1 md:px-1">
|
||||
<div class="mx-auto max-w-lg grid grid-cols-2 sm:grid-cols-2 md:grid-cols-3 gap-4 p-1" id="cards-container">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button onclick="redeemVoucher()" class="w-full bg-orange hover:bg-orange/90 text-white font-medium py-4 px-6 rounded-xl shadow-lg transition duration-200 flex items-center justify-center gap-3 mb-6">
|
||||
<i class="fas fa-ticket-alt"></i>
|
||||
<span>Redeem Voucher</span>
|
||||
</button>
|
||||
<div class="bg-white/10 backdrop-blur-lg rounded-2xl shadow-xl overflow-hidden border border-white/10 mb-6">
|
||||
<div class="p-6 space-y-8">
|
||||
<!-- Reconnect with M-Pesa -->
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-lg font-semibold text-orange">Reconnect with M-Pesa</h3>
|
||||
<div class="flex flex-col sm:flex-row gap-3">
|
||||
<input id="mpesaCodeInput" type="text" placeholder="Enter M-Pesa code (e.g., SCK15SKB4Z)" class="flex-grow px-4 py-3 bg-white/5 border border-white/10 rounded-xl focus:outline-none focus:ring-2 focus:ring-orange/50 text-white placeholder:text-gray-400">
|
||||
<button id="reconnectBtn" class="bg-orange hover:bg-orange/90 text-white font-medium py-3 px-6 rounded-xl transition duration-200">Reconnect</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-4">
|
||||
<h3 class="text-lg font-semibold text-orange">Active Package Login</h3>
|
||||
<form id="loginForm" action="$(link-login-only)" method="post" $(if chap-id)onSubmit="return doLogin()" $(endif)>
|
||||
<input type="hidden" name="dst" value="$(link-orig)">
|
||||
<input type="hidden" name="popup" value="true">
|
||||
<input type="hidden" name="mac" id="mac" value="$(mac)">
|
||||
<div class="flex flex-col sm:flex-row gap-3">
|
||||
<input id="usernameInput" name="username" type="text" placeholder="Enter Username (e.g., ACC123456)" class="flex-grow px-4 py-3 bg-white/5 border border-white/10 rounded-xl focus:outline-none focus:ring-2 focus:ring-orange/50 text-white placeholder:text-gray-400">
|
||||
<button id="submitBtn" type="button" onclick="submitLogin()" class="bg-orange hover:bg-orange/90 text-white font-medium py-3 px-6 rounded-xl transition duration-200">Connect</button>
|
||||
</div>
|
||||
<input type="hidden" name="password" value="1234">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<p class="text-sm text-gray-400">© 2025 yatmack. Created by Smartisp</p>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
function fetchData() {
|
||||
var domain = 'https://yatmack2.smartisp.co.ke/';
|
||||
var siteUrl = domain + "/index.php?_route=plugin/hotspot_plan";
|
||||
var routerName = encodeURIComponent("yatmack");
|
||||
var dataparams = `routername=${routerName}`;
|
||||
fetch(siteUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body: dataparams
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`Error ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
populateCards(data);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Fetch error:', error);
|
||||
});
|
||||
}
|
||||
function populateCards(data) {
|
||||
var cardsContainer = document.getElementById('cards-container');
|
||||
cardsContainer.innerHTML = ''; // Clear existing content
|
||||
// Sort the plans by price in ascending order
|
||||
data.data.forEach(router => {
|
||||
// Sort hotspot plans by price
|
||||
router.plans_hotspot.sort((a, b) => parseFloat(a.price) - parseFloat(b.price));
|
||||
router.plans_hotspot.forEach(item => {
|
||||
var cardDiv = document.createElement('div');
|
||||
cardDiv.className = 'bg-white border border-black rounded-lg shadow-md overflow-hidden transition duration-300 hover:shadow-lg flex flex-col items-center justify-between mx-auto mb-4 w-40';
|
||||
cardDiv.innerHTML = `
|
||||
<div class="bg-blue-500 text-white w-full py-1">
|
||||
<h2 class="text-sm font-medium uppercase text-center" style="font-size: clamp(0.75rem, 1.5vw, 1rem); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
|
||||
${item.planname}
|
||||
</h2>
|
||||
</div>
|
||||
<div class="px-4 py-2 flex-grow">
|
||||
<p class="text-2xl font-bold text-blue-600 mb-1">
|
||||
<span class="text-lg font-medium text-black">${item.currency}</span>
|
||||
${item.price}
|
||||
</p>
|
||||
<p class="text-sm text-black mb-2">
|
||||
Valid for ${item.validity} ${item.timelimit}
|
||||
</p>
|
||||
<hr class="border-black mb-2">
|
||||
</div>
|
||||
<div class="px-4 py-2 flex-shrink-0">
|
||||
<a href="#" class="inline-block bg-gray-900 text-white hover:bg-blue-600 font-semibold py-1 px-4 rounded-lg transition duration-300 text-md"
|
||||
onclick="handlePhoneNumberSubmission('${item.planId}', '${item.routerId}'); return false;"
|
||||
data-plan-id="${item.planId}"
|
||||
data-router-id="${item.routerId}">
|
||||
Buy
|
||||
</a>
|
||||
</div>
|
||||
`;
|
||||
cardsContainer.appendChild(cardDiv);
|
||||
});
|
||||
});
|
||||
}
|
||||
fetchData();
|
||||
function getMacAddress() {
|
||||
return "$(mac)"; // MikroTik replaces this with the user's MAC address
|
||||
}
|
||||
|
||||
function getOrCreateAccountId() {
|
||||
var radiaxid = localStorage.getItem('radiaxid');
|
||||
if (!radiaxid) {
|
||||
radiaxid = getMacAddress();
|
||||
localStorage.setItem('radiaxid', radiaxid);
|
||||
setCookie('radiaxid', radiaxid, 365);
|
||||
}
|
||||
return radiaxid;
|
||||
}
|
||||
|
||||
function getAccountId() {
|
||||
return localStorage.getItem('radiaxid') || getCookie('radiaxid') || getMacAddress();
|
||||
}
|
||||
|
||||
function formatPhoneNumber(phoneNumber) {
|
||||
if (phoneNumber.startsWith('+')) {
|
||||
phoneNumber = phoneNumber.substring(1);
|
||||
}
|
||||
if (phoneNumber.startsWith('0')) {
|
||||
phoneNumber = '254' + phoneNumber.substring(1);
|
||||
}
|
||||
if (phoneNumber.match(/^(7|1)/)) {
|
||||
phoneNumber = '254' + phoneNumber;
|
||||
}
|
||||
return phoneNumber;
|
||||
}
|
||||
|
||||
function setCookie(name, value, days) {
|
||||
var expires = "";
|
||||
if (days) {
|
||||
var date = new Date();
|
||||
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||
expires = "; expires=" + date.toUTCString();
|
||||
}
|
||||
document.cookie = name + "=" + (value || "") + expires + "; path=/";
|
||||
}
|
||||
|
||||
function getCookie(name) {
|
||||
var nameEQ = name + "=";
|
||||
var ca = document.cookie.split(';');
|
||||
for (var i = 0; i < ca.length; i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
|
||||
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
var loginTimeout;
|
||||
function handlePhoneNumberSubmission(planId, routerId, price) {
|
||||
var accountId = getOrCreateAccountId();
|
||||
var modalHtml = `
|
||||
<div id="paymentModal" class='fixed inset-0 bg-black/30 backdrop-blur-sm z-50 animate-fade-in'>
|
||||
<div class="fixed left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 w-full max-w-md">
|
||||
<div class="bg-white text-black rounded-lg shadow-xl">
|
||||
<div class="flex items-center justify-between p-4 border-b border-gray-300">
|
||||
<h5 class="text-xl font-semibold">
|
||||
Enter Your Mpesa Number
|
||||
</h5>
|
||||
<button class="text-gray-500 hover:text-black" onclick="closeModal('paymentModal')">
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<div class="bg-navy-50 border-l-4 border-navy-400 p-4 rounded-md mb-4"> <div class="flex"> <div class="flex-shrink-0"> <svg class="h-5 w-5 text-navy-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1 4v.01m6.938-2.162A9 9 0 1111 3v0a9 9 0 018.938 10.838z" /> </svg> </div> <div class="ml-3"> <p class="text-sm text-navy-700"> You are about to initiate M-pesa payment. Enter phone number below and click Pay Now to initialize payment. </p> </div> </div></div> <input type="text" class="w-full px-4 py-3 border border-orange-300 rounded-lg focus:ring-2 focus:ring-navy-400 focus:border-blue-500 text-black" id="phoneNumberInput" required placeholder="e.g. 0712345678">
|
||||
<div class="text-red-500 mt-1 hidden" id="invalidPhone">Please enter a valid phone number!</div>
|
||||
</div>
|
||||
<div class="flex justify-end space-x-2 p-4 border-t border-gray-300">
|
||||
<button onclick="closeModal('paymentModal')" class="px-4 py-2 bg-orange text-black rounded-lg hover:bg-gray-300">Close</button>
|
||||
<button id="payNowBtn" class="px-4 py-2 bg-navy text-white font-semibold hover:from-blue-600 hover:to-blue-500 flex items-center rounded-lg">
|
||||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 9V7a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2m2 4h10a2 2 0 002-2v-6a2 2 0 00-2-2H9a2 2 0 00-2 2v6a2 2 0 002 2zm7-5a2 2 0 11-4 0 2 2 0 014 0z" />
|
||||
</svg>
|
||||
Pay Now
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
document.body.insertAdjacentHTML('beforeend', modalHtml);
|
||||
var modal = document.getElementById('paymentModal');
|
||||
modal.classList.remove('hidden');
|
||||
var payNowBtn = document.getElementById('payNowBtn');
|
||||
var phoneInput = document.getElementById('phoneNumberInput');
|
||||
phoneInput.focus();
|
||||
payNowBtn.addEventListener('click', function() { handlePayment(); });
|
||||
function handlePayment() {
|
||||
if (!phoneInput.value) {
|
||||
document.getElementById('invalidPhone').classList.remove('hidden');
|
||||
return;
|
||||
}
|
||||
payNowBtn.disabled = true;
|
||||
payNowBtn.innerHTML = `
|
||||
<svg class='animate-spin -ml-1 mr-3 h-5 w-5 text-white' xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24'>
|
||||
<circle class='opacity-25' cx='12' cy='12' r='10' stroke='currentColor' stroke-width='4'></circle>
|
||||
<path class='opacity-75' fill='currentColor' d='M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z'></path>
|
||||
</svg>
|
||||
Processing...
|
||||
`;
|
||||
var formattedPhoneNumber = formatPhoneNumber(phoneInput.value);
|
||||
document.getElementById('usernameInput').value = accountId;
|
||||
|
||||
fetch('https://yatmack2.smartisp.co.ke/index.php?_route=plugin/CreateHotspotuser&type=grant', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({
|
||||
phone_number: formattedPhoneNumber,
|
||||
plan_id: planId,
|
||||
router_id: routerId,
|
||||
account_id: accountId
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.status === 'error') throw new Error(data.message);
|
||||
closeModal('paymentModal');
|
||||
showProcessingModal();
|
||||
checkPaymentStatus(formattedPhoneNumber);
|
||||
})
|
||||
.catch(error => {
|
||||
closeModal('paymentModal');
|
||||
showErrorModal(error.message);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function showProcessingModal() {
|
||||
var processingModalHtml = `
|
||||
<div id='processingModal' class='fixed inset-0 bg-black/30 backdrop-blur-sm z-50 animate-fade-in'>
|
||||
<div class='fixed left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 w-full max-w-md animate-slide-up'>
|
||||
<div class='bg-gradient-to-br from-white to-gray-50 shadow-2xl rounded-2xl p-8 text-center border border-gray-100'>
|
||||
<div class='flex justify-center'>
|
||||
<svg class='animate-spin h-20 w-20 text-navy-500' xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24'>
|
||||
<circle class='opacity-25' cx='12' cy='12' r='10' stroke='currentColor' stroke-width='4'></circle>
|
||||
<path class='opacity-75' fill='currentColor' d='M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z'></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="mt-6 bg-navy-50/50 backdrop-blur-xs border border-navy-200 rounded-xl p-6 shadow-lg"> <div class="flex items-center space-x-4"> <svg class="h-8 w-8 text-navy-400 flex-shrink-0" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1 4v.01m6.938-2.162A9 9 0 1111 3v0a9 9 0 018.938 10.838z" /> </svg> <div class="flex-1"> <h2 class="text-xl font-semibold text-navy-600 font-lexend">Initializing Payment</h2> <p class="text-navy-500 mt-2">A payment request has been sent to your phone. Please wait while we process your payment.</p> </div> </div> <div class="mt-4 h-2 w-full bg-navy-100 rounded-full overflow-hidden"> <div class="h-2 bg-navy-400 rounded-full animate-pulse"></div> </div> </div> </div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
document.body.insertAdjacentHTML('beforeend', processingModalHtml);
|
||||
}
|
||||
function closeModal(modalId) {
|
||||
var modal = document.getElementById(modalId);
|
||||
if (modal) {
|
||||
modal.classList.add('hidden');
|
||||
setTimeout(function() { modal.remove(); }, 300);
|
||||
}
|
||||
}
|
||||
|
||||
function showSuccessModal() {
|
||||
var successModalHtml = `
|
||||
<div id='successModal' class='fixed inset-0 bg-black/60 backdrop-blur-sm z-50 transition-all duration-300'>
|
||||
<div class='fixed left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 w-full max-w-lg transition-all duration-300 ease-out'>
|
||||
<div class='bg-white/95 backdrop-blur-md shadow-2xl rounded-3xl p-8 text-center border border-gray-200/50 ring-1 ring-gray-900/5'>
|
||||
<div class='flex justify-center mb-6'>
|
||||
<div class='relative'>
|
||||
<div class='absolute inset-0 rounded-full bg-green-500/20 animate-pulse'></div>
|
||||
<svg class='h-16 w-16 text-green-500' xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
|
||||
<path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z'/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class='space-y-4'>
|
||||
<h2 class='text-2xl font-semibold text-gray-900'>Payment Successful</h2>
|
||||
<div class='bg-green-50 rounded-2xl p-6 border border-green-100'>
|
||||
<div class='flex items-center gap-4'>
|
||||
<svg class='h-6 w-6 text-green-500 flex-shrink-0' xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
|
||||
<path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M9 12l2 2 4-4'/>
|
||||
</svg>
|
||||
<p class='text-sm text-green-700'>Your transaction has been completed successfully. You will be redirected shortly.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
document.body.insertAdjacentHTML('beforeend', successModalHtml);
|
||||
setTimeout(function() { closeModal('successModal'); }, 2000);
|
||||
}
|
||||
|
||||
function showErrorModal(errorMsg) {
|
||||
var errorModalHtml = `
|
||||
<div id='errorModal' class='fixed inset-0 bg-black/60 backdrop-blur-sm z-50 transition-all duration-300'>
|
||||
<div class='fixed left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 w-full max-w-lg transition-all duration-300 ease-out'>
|
||||
<div class='bg-white/95 backdrop-blur-md shadow-2xl rounded-3xl p-8 text-center border border-gray-200/50 ring-1 ring-gray-900/5'>
|
||||
<div class='flex justify-center mb-6'>
|
||||
<div class='relative'>
|
||||
<div class='absolute inset-0 rounded-full bg-red-500/20 animate-pulse'></div>
|
||||
<svg class='h-16 w-16 text-red-500' xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
|
||||
<path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M6 18L18 6M6 6l12 12'/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class='space-y-4'>
|
||||
<h2 class='text-2xl font-semibold text-gray-900'>Payment Failed</h2>
|
||||
<div class='bg-red-50 rounded-2xl p-6 border border-red-100'>
|
||||
<div class='flex items-center gap-4'>
|
||||
<svg class='h-6 w-6 text-red-500 flex-shrink-0' xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='currentColor'>
|
||||
<path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z'/>
|
||||
</svg>
|
||||
<p class='text-sm text-red-700'>An error occurred while processing your payment. Please try again.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
document.body.insertAdjacentHTML('beforeend', errorModalHtml);
|
||||
setTimeout(function() { closeModal('errorModal'); }, 2000);
|
||||
}
|
||||
|
||||
function checkPaymentStatus(phoneNumber) {
|
||||
var accountId = getOrCreateAccountId();
|
||||
var checkInterval = setInterval(function() {
|
||||
fetch('https://yatmack2.smartisp.co.ke/index.php?_route=plugin/CreateHotspotuser&type=verify', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({account_id: accountId})
|
||||
})
|
||||
.then(function(response) { return response.json(); })
|
||||
.then(function(data) {
|
||||
console.log('Raw Response:', data);
|
||||
if (data.Resultcode === '3') {
|
||||
clearInterval(checkInterval);
|
||||
closeModal('processingModal');
|
||||
showSuccessModal();
|
||||
if (loginTimeout) clearTimeout(loginTimeout);
|
||||
loginTimeout = setTimeout(function() { document.getElementById('loginForm').submit(); }, 2000);
|
||||
} else if (data.Resultcode === '2') {
|
||||
clearInterval(checkInterval);
|
||||
closeModal('processingModal');
|
||||
showErrorModal(data.Message);
|
||||
} else {
|
||||
console.error('Unexpected result code:', data.Resultcode);
|
||||
}
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.error('Error during fetch request:', error);
|
||||
clearInterval(checkInterval);
|
||||
closeModal('processingModal');
|
||||
showErrorModal('An error occurred while checking payment status.');
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
setTimeout(function() {
|
||||
clearInterval(checkInterval);
|
||||
closeModal('processingModal');
|
||||
showErrorModal('Timeout while waiting for payment confirmation.');
|
||||
}, 300000); // 5 minutes
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var accountId = getOrCreateAccountId();
|
||||
var usernameInput = document.getElementById('usernameInput');
|
||||
if (usernameInput && !usernameInput.value) {
|
||||
usernameInput.value = accountId;
|
||||
}
|
||||
var submitBtn = document.getElementById('submitBtn');
|
||||
if (submitBtn) {
|
||||
submitBtn.addEventListener('click', function() {
|
||||
document.getElementById('loginForm').submit();
|
||||
});
|
||||
}
|
||||
});
|
||||
var loginTimeout; // Variable to store the timeout ID
|
||||
function redeemVoucher() {
|
||||
Swal.fire({
|
||||
title: 'Redeem Voucher',
|
||||
input: 'text',
|
||||
inputPlaceholder: 'Enter voucher code',
|
||||
inputValidator: function(value) {
|
||||
if (!value) {
|
||||
return 'You need to enter a voucher code!';
|
||||
}
|
||||
},
|
||||
confirmButtonColor: '#3085d6',
|
||||
cancelButtonColor: '#d33',
|
||||
confirmButtonText: 'Redeem',
|
||||
showLoaderOnConfirm: true,
|
||||
preConfirm: (voucherCode) => {
|
||||
var accountId = voucherCode;
|
||||
return fetch('https://yatmack2.smartisp.co.ke/index.php?_route=plugin/CreateHotspotuser&type=voucher', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({voucher_code: voucherCode, account_id: accountId}),
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) throw new Error('Network response was not ok');
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
if (data.status === 'error') throw new Error(data.message);
|
||||
return data;
|
||||
});
|
||||
},
|
||||
allowOutsideClick: () => !Swal.isLoading()
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Voucher Redeemed',
|
||||
text: result.value.message,
|
||||
showConfirmButton: false,
|
||||
allowOutsideClick: false,
|
||||
didOpen: () => {
|
||||
Swal.showLoading();
|
||||
var username = result.value.username;
|
||||
console.log('Received username from server:', username);
|
||||
var usernameInput = document.querySelector('input[name="username"]');
|
||||
if (usernameInput) {
|
||||
console.log('Found username input element.');
|
||||
usernameInput.value = username;
|
||||
loginTimeout = setTimeout(function() {
|
||||
var loginForm = document.getElementById('loginForm');
|
||||
if (loginForm) {
|
||||
loginForm.submit();
|
||||
} else {
|
||||
console.error('Login form not found.');
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error',
|
||||
text: 'Login form not found. Please try again.',
|
||||
});
|
||||
}
|
||||
}, 2000);
|
||||
} else {
|
||||
console.error('Username input element not found.');
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error',
|
||||
text: 'Username input not found. Please try again.',
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}).catch(error => {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Oops...',
|
||||
text: error.message,
|
||||
});
|
||||
});
|
||||
}
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var reconnectBtn = document.getElementById('reconnectBtn');
|
||||
var mpesaCodeInput = document.getElementById('mpesaCodeInput');
|
||||
var macInput = document.getElementById('mac');
|
||||
var loginForm = document.getElementById('loginForm');
|
||||
if (reconnectBtn) {
|
||||
reconnectBtn.addEventListener('click', function() {
|
||||
// Validate inputs before processing
|
||||
if (!mpesaCodeInput || !macInput || !loginForm) {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error',
|
||||
text: 'Required form elements are missing'
|
||||
});
|
||||
return;
|
||||
}
|
||||
var mpesaCode = mpesaCodeInput.value.trim().split(' ')[0];
|
||||
var mac = macInput.value.trim();
|
||||
fetch('https://yatmack2.smartisp.co.ke/index.php?_route=plugin/ReconnectUser', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({ mpesa_code: mpesaCode, mac: mac }),
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
console.log('Response data:', data);
|
||||
var resultCode = data.Resultcode;
|
||||
var message = data.Message;
|
||||
var status = data.Status;
|
||||
var username = data.username;
|
||||
if (resultCode === '1') {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Invalid Code',
|
||||
text: message
|
||||
});
|
||||
}
|
||||
else if (resultCode === '3') {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Expired Package',
|
||||
text: message
|
||||
});
|
||||
}
|
||||
else if (resultCode === '2') {
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: status,
|
||||
text: message,
|
||||
showConfirmButton: false,
|
||||
allowOutsideClick: false,
|
||||
didOpen: () => {
|
||||
Swal.showLoading();
|
||||
console.log('Received username from server:', username);
|
||||
var usernameInput = document.querySelector('input[name="username"]');
|
||||
if (usernameInput) {
|
||||
console.log('Found username input element.');
|
||||
usernameInput.value = username;
|
||||
setTimeout(function() {
|
||||
var loginForm = document.getElementById('loginForm');
|
||||
if (loginForm) {
|
||||
loginForm.submit();
|
||||
} else {
|
||||
console.error('Login form not found.');
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error',
|
||||
text: 'Login form not found. Please try again.',
|
||||
});
|
||||
}
|
||||
}, 2000);
|
||||
} else {
|
||||
console.error('Username input element not found.');
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error',
|
||||
text: 'Username input not found. Please try again.',
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Oops...',
|
||||
text: error.message
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
console.error('Reconnect button not found');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</html>
|
128
radius.php
128
radius.php
@ -42,7 +42,7 @@ try {
|
||||
$CHAPchallenge = _req('CHAPchallenge');
|
||||
$isCHAP = false;
|
||||
if (!empty($CHAPassword)) {
|
||||
$c = ORM::for_table('tbl_customers')->select('password')->select('pppoe_password')->whereRaw("BINARY `username` = '$username'")->find_one();
|
||||
$c = ORM::for_table('tbl_customers')->select('password')->select('pppoe_password')->whereRaw("BINARY username = '$username' AND status = 'Active'")->find_one();
|
||||
if ($c) {
|
||||
if (Password::chap_verify($c['password'], $CHAPassword, $CHAPchallenge)) {
|
||||
$password = $c['password'];
|
||||
@ -68,7 +68,7 @@ try {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$c = ORM::for_table('tbl_customers')->select('password')->select('pppoe_password')->whereRaw("BINARY `pppoe_username` = '$username'")->find_one();
|
||||
$c = ORM::for_table('tbl_customers')->select('password')->select('pppoe_password')->whereRaw("BINARY pppoe_username = '$username' AND status = 'Active'")->find_one();
|
||||
if ($c) {
|
||||
if (Password::chap_verify($c['password'], $CHAPassword, $CHAPchallenge)) {
|
||||
$password = $c['password'];
|
||||
@ -109,9 +109,9 @@ try {
|
||||
}
|
||||
if ($username == $password) {
|
||||
$username = Text::alphanumeric($username, "-_.,");
|
||||
$d = ORM::for_table('tbl_voucher')->whereRaw("BINARY `code` = '$username'")->find_one();
|
||||
$d = ORM::for_table('tbl_voucher')->whereRaw("BINARY code = '$username'")->find_one();
|
||||
} else {
|
||||
$d = ORM::for_table('tbl_customers')->whereRaw("BINARY `username` = '$username'")->find_one();
|
||||
$d = ORM::for_table('tbl_customers')->whereRaw("BINARY username = '$username' AND status = 'Active'")->find_one();
|
||||
if ($d['password'] != $password) {
|
||||
if ($d['pppoe_password'] != $password) {
|
||||
unset($d);
|
||||
@ -136,7 +136,7 @@ try {
|
||||
$CHAPchallenge = _req('CHAPchallenge');
|
||||
$isCHAP = false;
|
||||
if (!empty($CHAPassword)) {
|
||||
$c = ORM::for_table('tbl_customers')->select('password')->select('pppoe_password')->whereRaw("BINARY `username` = '$username'")->find_one();
|
||||
$c = ORM::for_table('tbl_customers')->select('password')->select('pppoe_password')->whereRaw("BINARY username = '$username' AND status = 'Active'")->find_one();
|
||||
if ($c) {
|
||||
if (Password::chap_verify($c['password'], $CHAPassword, $CHAPchallenge)) {
|
||||
$password = $c['password'];
|
||||
@ -162,14 +162,16 @@ try {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$c = ORM::for_table('tbl_customers')->select('password')->select('pppoe_password')->whereRaw("BINARY `pppoe_username` = '$username'")->find_one();
|
||||
$c = ORM::for_table('tbl_customers')->select('password')->select('username')->select('pppoe_password')->whereRaw("BINARY pppoe_username = '$username' AND status = 'Active'")->find_one();
|
||||
if ($c) {
|
||||
if (Password::chap_verify($c['password'], $CHAPassword, $CHAPchallenge)) {
|
||||
$password = $c['password'];
|
||||
$username = $c['username'];
|
||||
$isVoucher = false;
|
||||
$isCHAP = true;
|
||||
} else if (!empty($c['pppoe_password']) && Password::chap_verify($c['pppoe_password'], $CHAPassword, $CHAPchallenge)) {
|
||||
$password = $c['pppoe_password'];
|
||||
$username = $c['username'];
|
||||
$isVoucher = false;
|
||||
$isCHAP = true;
|
||||
} else {
|
||||
@ -201,10 +203,18 @@ try {
|
||||
], 401);
|
||||
}
|
||||
}
|
||||
$tur = ORM::for_table('tbl_user_recharges')->whereRaw("BINARY `username` = '$username'")->find_one();
|
||||
$tur = ORM::for_table('tbl_user_recharges')->whereRaw("BINARY username = '$username'")->find_one();
|
||||
if (!$tur) {
|
||||
// if check if pppoe_username
|
||||
$c = ORM::for_table('tbl_customers')->select('username')->select('pppoe_password')->whereRaw("BINARY pppoe_username = '$username'")->find_one();
|
||||
if ($c) {
|
||||
$username = $c['username'];
|
||||
$tur = ORM::for_table('tbl_user_recharges')->whereRaw("BINARY username = '$username'")->find_one();
|
||||
}
|
||||
}
|
||||
if ($tur) {
|
||||
if (!$isVoucher && !$isCHAP) {
|
||||
$d = ORM::for_table('tbl_customers')->select('password')->select('pppoe_password')->whereRaw("BINARY `username` = '$username'")->find_one();
|
||||
$d = ORM::for_table('tbl_customers')->select('password')->select('pppoe_password')->whereRaw("BINARY username = '$username' AND status = 'Active'")->find_one();
|
||||
if ($d) {
|
||||
if ($d['password'] != $password) {
|
||||
if ($d['pppoe_password'] != $password) {
|
||||
@ -212,7 +222,7 @@ try {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$d = ORM::for_table('tbl_customers')->select('password')->select('pppoe_password')->whereRaw("BINARY `pppoe_username` = '$username'")->find_one();
|
||||
$d = ORM::for_table('tbl_customers')->select('password')->select('pppoe_password')->whereRaw("BINARY pppoe_username = '$username' AND status = 'Active'")->find_one();
|
||||
if ($d) {
|
||||
if ($d['password'] != $password) {
|
||||
if ($d['pppoe_password'] != $password) {
|
||||
@ -226,14 +236,14 @@ try {
|
||||
} else {
|
||||
if ($isVoucher) {
|
||||
$username = Text::alphanumeric($username, "-_.,");
|
||||
$v = ORM::for_table('tbl_voucher')->whereRaw("BINARY `code` = '$username'")->where('routers', 'radius')->find_one();
|
||||
$v = ORM::for_table('tbl_voucher')->whereRaw("BINARY code = '$username' AND routers = 'radius'")->find_one();
|
||||
if ($v) {
|
||||
if ($v['status'] == 0) {
|
||||
if (Package::rechargeUser(0, $v['routers'], $v['id_plan'], "Voucher", $username)) {
|
||||
$v->status = "1";
|
||||
$v->used_date = date('Y-m-d H:i:s');
|
||||
$v->save();
|
||||
$tur = ORM::for_table('tbl_user_recharges')->whereRaw("BINARY `username` = '$username'")->find_one();
|
||||
$tur = ORM::for_table('tbl_user_recharges')->whereRaw("BINARY username = '$username'")->find_one();
|
||||
if ($tur) {
|
||||
process_radiust_rest($tur, $code);
|
||||
} else {
|
||||
@ -246,7 +256,7 @@ try {
|
||||
show_radius_result(['Reply-Message' => 'Voucher Expired...'], 401);
|
||||
}
|
||||
} else {
|
||||
show_radius_result(['Reply-Message' => 'Voucher Expired..'], 401);
|
||||
show_radius_result(['Reply-Message' => 'Invalid Voucher..'], 401);
|
||||
}
|
||||
} else {
|
||||
show_radius_result(['Reply-Message' => 'Internet Plan Expired..'], 401);
|
||||
@ -264,76 +274,58 @@ try {
|
||||
}
|
||||
header("HTTP/1.1 200 ok");
|
||||
$d = ORM::for_table('rad_acct')
|
||||
->whereRaw("BINARY `username` = '$username'")
|
||||
->where('acctstatustype', _post('acctStatusType'))
|
||||
->whereRaw("BINARY username = '$username' AND macaddr = '" . _post('macAddr') . "' AND nasid = '" . _post('nasid') . "'")
|
||||
->findOne();
|
||||
if (!$d) {
|
||||
$d = ORM::for_table('rad_acct')->create();
|
||||
}
|
||||
$acctOutputOctets = _post('acctOutputOctets', 0);
|
||||
$acctInputOctets = _post('acctInputOctets', 0);
|
||||
if (_post('acctStatusType') == 'Stop') {
|
||||
// log in the Start only
|
||||
$start = ORM::for_table('rad_acct')
|
||||
->whereRaw("BINARY `username` = '$username'")
|
||||
->where('acctstatustype', 'Start')
|
||||
->findOne();
|
||||
if (!$start) {
|
||||
$start = ORM::for_table('rad_acct')->create();
|
||||
}
|
||||
if ($acctOutputOctets !== false && $acctInputOctets !== false) {
|
||||
$start->acctOutputOctets += intval($acctOutputOctets);
|
||||
$start->acctInputOctets += intval($acctInputOctets);
|
||||
} else {
|
||||
$start->acctOutputOctets = 0;
|
||||
$start->acctInputOctets = 0;
|
||||
}
|
||||
$start->acctsessionid = _post('acctSessionId');
|
||||
$start->username = $username;
|
||||
$start->realm = _post('realm');
|
||||
$start->nasipaddress = _post('nasip');
|
||||
$start->nasid = _post('nasid');
|
||||
$start->nasportid = _post('nasPortId');
|
||||
$start->nasporttype = _post('nasPortType');
|
||||
$start->framedipaddress = _post('framedIPAddress');
|
||||
$start->acctstatustype = _post('acctStatusType');
|
||||
$start->macaddr = _post('macAddr');
|
||||
$start->dateAdded = date('Y-m-d H:i:s');
|
||||
$start->save();
|
||||
if ($acctOutputOctets !== false && $acctInputOctets !== false) {
|
||||
$d->acctOutputOctets += intval($acctOutputOctets);
|
||||
$d->acctInputOctets += intval($acctInputOctets);
|
||||
} else {
|
||||
$d->acctOutputOctets = 0;
|
||||
$d->acctInputOctets = 0;
|
||||
} else {
|
||||
if ($acctOutputOctets !== false && $acctInputOctets !== false) {
|
||||
$d->acctOutputOctets += intval($acctOutputOctets);
|
||||
$d->acctInputOctets += intval($acctInputOctets);
|
||||
} else {
|
||||
$d->acctOutputOctets = 0;
|
||||
$d->acctInputOctets = 0;
|
||||
}
|
||||
}
|
||||
$d->acctsessionid = _post('acctSessionId');
|
||||
$d->username = $username;
|
||||
$d->realm = _post('realm');
|
||||
$d->nasipaddress = _post('nasip');
|
||||
$d->nasipaddress = _post('nasIpAddress');
|
||||
$d->acctsessiontime = intval(_post('acctSessionTime'));
|
||||
$d->nasid = _post('nasid');
|
||||
$d->nasportid = _post('nasPortId');
|
||||
$d->nasporttype = _post('nasPortType');
|
||||
$d->framedipaddress = _post('framedIPAddress');
|
||||
$d->acctstatustype = _post('acctStatusType');
|
||||
if (in_array(_post('acctStatusType'), ['Start', 'Stop'])) {
|
||||
$d->acctstatustype = _post('acctStatusType');
|
||||
}
|
||||
$d->macaddr = _post('macAddr');
|
||||
$d->dateAdded = date('Y-m-d H:i:s');
|
||||
$d->save();
|
||||
if (_post('acctStatusType') == 'Start') {
|
||||
$tur = ORM::for_table('tbl_user_recharges')->whereRaw("BINARY `username` = '$username'")->where('status', 'on')->where('routers', 'radius')->find_one();
|
||||
$plan = ORM::for_table('tbl_plans')->where('id', $tur['plan_id'])->find_one();
|
||||
if ($plan['limit_type'] == "Data_Limit" || $plan['limit_type'] == "Both_Limit") {
|
||||
$totalUsage = $d['acctOutputOctets'] + $d['acctInputOctets'];
|
||||
$attrs['reply:Mikrotik-Total-Limit'] = Text::convertDataUnit($plan['data_limit'], $plan['data_unit']) - $totalUsage;
|
||||
if ($attrs['reply:Mikrotik-Total-Limit'] < 0) {
|
||||
$attrs['reply:Mikrotik-Total-Limit'] = 0;
|
||||
show_radius_result(["control:Auth-Type" => "Accept", 'Reply-Message' => 'You have exceeded your data limit.'], 401);
|
||||
// pastikan data akunting yang disimpan memang customer aktif phpnuxbill
|
||||
$tur = ORM::for_table('tbl_user_recharges')->whereRaw("BINARY username = '$username' AND `status` = 'on' AND `routers` = 'radius'")->find_one();
|
||||
if (!$tur) {
|
||||
// check if pppoe_username
|
||||
$c = ORM::for_table('tbl_customers')->select('username')->whereRaw("BINARY pppoe_username = '$username'")->find_one();
|
||||
if ($c) {
|
||||
$username = $c['username'];
|
||||
$tur = ORM::for_table('tbl_user_recharges')->whereRaw("BINARY username = '$username'")->find_one();
|
||||
}
|
||||
}
|
||||
if ($tur) {
|
||||
$d->save();
|
||||
if (_post('acctStatusType') == 'Start') {
|
||||
$plan = ORM::for_table('tbl_plans')->where('id', $tur['plan_id'])->find_one();
|
||||
if ($plan['limit_type'] == "Data_Limit" || $plan['limit_type'] == "Both_Limit") {
|
||||
$totalUsage = $d['acctOutputOctets'] + $d['acctInputOctets'];
|
||||
$attrs['reply:Mikrotik-Total-Limit'] = Text::convertDataUnit($plan['data_limit'], $plan['data_unit']) - $totalUsage;
|
||||
if ($attrs['reply:Mikrotik-Total-Limit'] < 0) {
|
||||
$attrs['reply:Mikrotik-Total-Limit'] = 0;
|
||||
show_radius_result(["control:Auth-Type" => "Accept", 'Reply-Message' => 'You have exceeded your data limit.'], 401);
|
||||
}
|
||||
}
|
||||
}
|
||||
process_radiust_rest($tur, 200);
|
||||
}
|
||||
show_radius_result([
|
||||
"control:Auth-Type" => "Accept",
|
||||
@ -364,6 +356,16 @@ function process_radiust_rest($tur, $code)
|
||||
global $config;
|
||||
$plan = ORM::for_table('tbl_plans')->where('id', $tur['plan_id'])->find_one();
|
||||
$bw = ORM::for_table("tbl_bandwidth")->find_one($plan['id_bw']);
|
||||
// Count User Onlines
|
||||
$USRon = ORM::for_table('rad_acct')
|
||||
->whereRaw("BINARY username = '" . $tur['username'] . "' AND acctStatusType = 'Start'")
|
||||
->find_array();
|
||||
// get all the IP
|
||||
$ips = array_column($USRon, 'framedipaddress');
|
||||
// check if user reach shared_users limit but IP is not in the list active
|
||||
if (count($USRon) >= $plan['shared_users'] && $plan['type'] == 'Hotspot' && !in_array(_post('framedIPAddress'), $ips)) {
|
||||
show_radius_result(["control:Auth-Type" => "Accept", 'Reply-Message' => 'You are already logged in - access denied (' . $USRon . ')'], 401);
|
||||
}
|
||||
if ($bw['rate_down_unit'] == 'Kbps') {
|
||||
$unitdown = 'K';
|
||||
} else {
|
||||
@ -403,7 +405,7 @@ function process_radiust_rest($tur, $code)
|
||||
|
||||
if ($plan['typebp'] == "Limited") {
|
||||
if ($plan['limit_type'] == "Data_Limit" || $plan['limit_type'] == "Both_Limit") {
|
||||
$raddact = ORM::for_table('rad_acct')->whereRaw("BINARY `username` = '$tur[username]'")->where('acctstatustype', 'Start')->find_one();
|
||||
$raddact = ORM::for_table('rad_acct')->whereRaw("BINARY username = '$tur[username]'")->where('acctstatustype', 'Start')->find_one();
|
||||
$totalUsage = intval($raddact['acctOutputOctets']) + intval($raddact['acctInputOctets']);
|
||||
$attrs['reply:Mikrotik-Total-Limit'] = Text::convertDataUnit($plan['data_limit'], $plan['data_unit']) - $totalUsage;
|
||||
if ($attrs['reply:Mikrotik-Total-Limit'] < 0) {
|
||||
|
@ -4,25 +4,66 @@
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>QRCode Scanner</title>
|
||||
<title>QR Code Scanner</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f2f2f2;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
}
|
||||
#container {
|
||||
background-color: #ffffff;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
text-align: center;
|
||||
}
|
||||
#qr-reader {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
#qr-reader-results {
|
||||
padding: 10px;
|
||||
background-color: #f8f8f8;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
}
|
||||
button {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 30px;
|
||||
padding: 10px 20px;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="qr-reader" style="width:100%; height:auto"></div>
|
||||
<div id="qr-reader-results"></div>
|
||||
<div id="container">
|
||||
<h2>QR Code Scanner</h2>
|
||||
<div id="qr-reader"></div>
|
||||
<div id="qr-reader-results"></div>
|
||||
<button id="camera-button">Open Camera</button>
|
||||
</div>
|
||||
<script src="qrcode.min.js"></script>
|
||||
<script>
|
||||
function docReady(fn) {
|
||||
// see if DOM is already available
|
||||
// lihat apakah DOM sudah tersedia
|
||||
if (document.readyState === "complete" ||
|
||||
document.readyState === "interactive") {
|
||||
// call on next available tick
|
||||
// panggil di detik berikutnya yang tersedia
|
||||
setTimeout(fn, 1);
|
||||
} else {
|
||||
document.addEventListener("DOMContentLoaded", fn);
|
||||
@ -51,6 +92,9 @@
|
||||
docReady(function() {
|
||||
var resultContainer = document.getElementById('qr-reader-results');
|
||||
var lastResult, countResults = 0;
|
||||
var html5QrcodeScanner;
|
||||
var isCameraOpen = false;
|
||||
|
||||
function onScanSuccess(decodedText, decodedResult) {
|
||||
if (decodedText !== lastResult) {
|
||||
++countResults;
|
||||
@ -67,14 +111,26 @@
|
||||
}
|
||||
}
|
||||
|
||||
var html5QrcodeScanner = new Html5QrcodeScanner(
|
||||
"qr-reader", {
|
||||
fps: 10,
|
||||
qrbox: 250
|
||||
});
|
||||
html5QrcodeScanner.render(onScanSuccess);
|
||||
function toggleCamera() {
|
||||
if (isCameraOpen) {
|
||||
html5QrcodeScanner.clear();
|
||||
document.getElementById('camera-button').textContent = "Open Camera";
|
||||
isCameraOpen = false;
|
||||
} else {
|
||||
html5QrcodeScanner = new Html5QrcodeScanner(
|
||||
"qr-reader", {
|
||||
fps: 10,
|
||||
qrbox: 250
|
||||
});
|
||||
html5QrcodeScanner.render(onScanSuccess);
|
||||
document.getElementById('camera-button').textContent = "Close Camera";
|
||||
isCameraOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('camera-button').addEventListener('click', toggleCamera);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
@ -48,7 +48,28 @@ $ui = new class($key)
|
||||
}
|
||||
function getAll()
|
||||
{
|
||||
return $this->assign;
|
||||
|
||||
$result = [];
|
||||
foreach ($this->assign as $key => $value) {
|
||||
if($value instanceof ORM){
|
||||
$result[$key] = $value->as_array();
|
||||
}else if($value instanceof IdiormResultSet){
|
||||
$count = count($value);
|
||||
for($n=0;$n<$count;$n++){
|
||||
foreach ($value[$n] as $k=>$v) {
|
||||
$result[$key][$n][$k] = $v;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
$result[$key] = $value;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function fetch()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -11,35 +11,62 @@ class Admin
|
||||
|
||||
public static function getID()
|
||||
{
|
||||
global $db_pass, $config;
|
||||
$enable_session_timeout = $config['enable_session_timeout'];
|
||||
if ($enable_session_timeout) {
|
||||
$timeout = 60;
|
||||
if ($config['session_timeout_duration']) {
|
||||
$timeout = intval($config['session_timeout_duration']);
|
||||
}
|
||||
$session_timeout_duration = $timeout * 60; // Convert minutes to seconds
|
||||
}
|
||||
global $db_pass, $config, $isApi;
|
||||
|
||||
if (isset($_SESSION['aid']) && isset($_SESSION['aid_expiration']) && $_SESSION['aid_expiration'] > time()) {
|
||||
return $_SESSION['aid'];
|
||||
} elseif ($enable_session_timeout && isset($_SESSION['aid']) && isset($_SESSION['aid_expiration']) && $_SESSION['aid_expiration'] <= time()) {
|
||||
self::removeCookie();
|
||||
session_destroy();
|
||||
_alert(Lang::T('Session has expired. Please log in again.'), 'danger', "admin");
|
||||
return 0;
|
||||
$enable_session_timeout = $config['enable_session_timeout'] == 1;
|
||||
$session_timeout_duration = $config['session_timeout_duration'] ? intval($config['session_timeout_duration'] * 60) : intval(60 * 60); // Convert minutes to seconds
|
||||
if ($isApi) {
|
||||
$enable_session_timeout = false;
|
||||
}
|
||||
// Check if cookie is set and valid
|
||||
if ($enable_session_timeout && !empty($_SESSION['aid']) && !empty($_SESSION['aid_expiration'])) {
|
||||
if ($_SESSION['aid_expiration'] > time()) {
|
||||
$isValid = self::validateToken($_SESSION['aid'], $_COOKIE['aid']);
|
||||
if (!$isValid) {
|
||||
self::removeCookie();
|
||||
_alert(Lang::T('Token has expired. Please log in again.'), 'danger', "admin");
|
||||
return 0;
|
||||
}
|
||||
// extend timeout duration
|
||||
$_SESSION['aid_expiration'] = time() + $session_timeout_duration;
|
||||
|
||||
return $_SESSION['aid'];
|
||||
} else {
|
||||
// Session expired, log out the user
|
||||
self::removeCookie();
|
||||
_alert(Lang::T('Session has expired. Please log in again.'), 'danger', "admin");
|
||||
return 0;
|
||||
}
|
||||
} else if (!empty($_SESSION['aid'])) {
|
||||
$isValid = self::validateToken($_SESSION['aid'], $_COOKIE['aid']);
|
||||
if (!$isValid) {
|
||||
self::removeCookie();
|
||||
_alert(Lang::T('Token has expired. Please log in again.') . '.'.$_SESSION['aid'], 'danger', "admin");
|
||||
return 0;
|
||||
}
|
||||
return $_SESSION['aid'];
|
||||
}
|
||||
// Check if the cookie is set and valid
|
||||
elseif (isset($_COOKIE['aid'])) {
|
||||
// id.time.sha1
|
||||
$tmp = explode('.', $_COOKIE['aid']);
|
||||
if (sha1($tmp[0] . '.' . $tmp[1] . '.' . $db_pass) == $tmp[2]) {
|
||||
if (time() - $tmp[1] < 86400 * 7) {
|
||||
$_SESSION['aid'] = $tmp[0];
|
||||
if ($enable_session_timeout) {
|
||||
$_SESSION['aid_expiration'] = time() + $session_timeout_duration;
|
||||
if (sha1("$tmp[0].$tmp[1].$db_pass") == $tmp[2]) {
|
||||
// Validate the token in the cookie
|
||||
$isValid = self::validateToken($tmp[0], $_COOKIE['aid']);
|
||||
if ($isApi) {
|
||||
// For now API need to always return true, next need to add revoke token API
|
||||
$isValid = true;
|
||||
}
|
||||
if (!empty($_COOKIE['aid']) && !$isValid) {
|
||||
self::removeCookie();
|
||||
_alert(Lang::T('Token has expired. Please log in again.') . '..', 'danger', "admin");
|
||||
return 0;
|
||||
} else {
|
||||
if (time() - $tmp[1] < 86400 * 7) {
|
||||
$_SESSION['aid'] = $tmp[0];
|
||||
if ($enable_session_timeout) {
|
||||
$_SESSION['aid_expiration'] = time() + $session_timeout_duration;
|
||||
}
|
||||
return $tmp[0];
|
||||
}
|
||||
return $tmp[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -51,28 +78,55 @@ class Admin
|
||||
{
|
||||
global $db_pass, $config;
|
||||
$enable_session_timeout = $config['enable_session_timeout'];
|
||||
$session_timeout_duration = intval($config['session_timeout_duration']) * 60; // Convert minutes to seconds
|
||||
|
||||
if (isset($aid)) {
|
||||
$time = time();
|
||||
$token = $aid . '.' . $time . '.' . sha1($aid . '.' . $time . '.' . $db_pass);
|
||||
setcookie('aid', $token, time() + 86400 * 7);
|
||||
$token = $aid . '.' . $time . '.' . sha1("$aid.$time.$db_pass");
|
||||
|
||||
// Detect the current protocol
|
||||
$isSecure = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';
|
||||
// Set cookie with security flags
|
||||
setcookie('aid', $token, [
|
||||
'expires' => time() + 86400 * 7, // 7 days
|
||||
'path' => '/',
|
||||
'domain' => '',
|
||||
'secure' => $isSecure,
|
||||
'httponly' => true,
|
||||
'samesite' => 'Lax', // or Strict
|
||||
]);
|
||||
|
||||
$_SESSION['aid'] = $aid;
|
||||
|
||||
if ($enable_session_timeout) {
|
||||
$timeout = 60;
|
||||
if ($config['session_timeout_duration']) {
|
||||
$timeout = intval($config['session_timeout_duration']);
|
||||
}
|
||||
$session_timeout_duration = $timeout * 60; // Convert minutes to seconds
|
||||
$_SESSION['aid_expiration'] = $time + $session_timeout_duration;
|
||||
}
|
||||
|
||||
self::upsertToken($aid, $token);
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
public static function removeCookie()
|
||||
{
|
||||
global $_app_stage;
|
||||
if (isset($_COOKIE['aid'])) {
|
||||
setcookie('aid', '', time() - 86400);
|
||||
$isSecure = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';
|
||||
setcookie('aid', '', [
|
||||
'expires' => time() - 3600,
|
||||
'path' => '/',
|
||||
'domain' => '',
|
||||
'secure' => $isSecure,
|
||||
'httponly' => true,
|
||||
'samesite' => 'Lax',
|
||||
]);
|
||||
session_destroy();
|
||||
session_unset();
|
||||
session_start();
|
||||
unset($_COOKIE['aid'], $_SESSION['aid']);
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,4 +141,24 @@ class Admin
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static function upsertToken($aid, $token)
|
||||
{
|
||||
$query = ORM::for_table('tbl_users')->findOne($aid);
|
||||
$query->login_token = sha1($token);
|
||||
$query->save();
|
||||
}
|
||||
|
||||
public static function validateToken($aid, $cookieToken)
|
||||
{
|
||||
global $config;
|
||||
$query = ORM::for_table('tbl_users')->select('login_token')->findOne($aid);
|
||||
if ($config['single_session'] != 'yes') {
|
||||
return true; // For multi-session, any token is valid
|
||||
}
|
||||
if (empty($query)) {
|
||||
return true;
|
||||
}
|
||||
return $query->login_token === sha1($cookieToken);
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,9 @@ class App{
|
||||
}
|
||||
|
||||
public static function getTokenValue($key){
|
||||
if(empty($key)){
|
||||
return "";
|
||||
}
|
||||
if(isset($_SESSION[$key])){
|
||||
return $_SESSION[$key];
|
||||
}else{
|
||||
@ -26,4 +29,23 @@ class App{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public static function getVoucher(){
|
||||
return md5(microtime());
|
||||
}
|
||||
|
||||
public static function setVoucher($token, $value){
|
||||
$_SESSION[$token] = $value;
|
||||
}
|
||||
|
||||
public static function getVoucherValue($key){
|
||||
if(empty($key)){
|
||||
return "";
|
||||
}
|
||||
if(isset($_SESSION[$key])){
|
||||
return $_SESSION[$key];
|
||||
}else{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,13 +30,9 @@ class Balance
|
||||
public static function min($id_customer, $amount)
|
||||
{
|
||||
$c = ORM::for_table('tbl_customers')->where('id', $id_customer)->find_one();
|
||||
if ($c && $c['balance'] >= $amount) {
|
||||
$c->balance = $c['balance'] - $amount;
|
||||
$c->save();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
$c->balance = $c['balance'] - $amount;
|
||||
$c->save();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function plusByPhone($phone_customer, $amount)
|
||||
|
55
system/autoload/Csrf.php
Normal file
55
system/autoload/Csrf.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
**/
|
||||
|
||||
|
||||
class Csrf
|
||||
{
|
||||
private static $tokenExpiration = 1800; // 30 minutes
|
||||
|
||||
public static function generateToken($length = 16)
|
||||
{
|
||||
return bin2hex(random_bytes($length));
|
||||
}
|
||||
|
||||
public static function validateToken($token, $storedToken)
|
||||
{
|
||||
return hash_equals($token, $storedToken);
|
||||
}
|
||||
|
||||
public static function check($token)
|
||||
{
|
||||
global $config, $isApi;
|
||||
if($config['csrf_enabled'] == 'yes' && !$isApi) {
|
||||
if (isset($_SESSION['csrf_token'], $_SESSION['csrf_token_time'], $token)) {
|
||||
$storedToken = $_SESSION['csrf_token'];
|
||||
$tokenTime = $_SESSION['csrf_token_time'];
|
||||
|
||||
if (time() - $tokenTime > self::$tokenExpiration) {
|
||||
self::clearToken();
|
||||
return false;
|
||||
}
|
||||
|
||||
return self::validateToken($token, $storedToken);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function generateAndStoreToken()
|
||||
{
|
||||
$token = self::generateToken();
|
||||
$_SESSION['csrf_token'] = $token;
|
||||
$_SESSION['csrf_token_time'] = time();
|
||||
return $token;
|
||||
}
|
||||
|
||||
public static function clearToken()
|
||||
{
|
||||
unset($_SESSION['csrf_token'], $_SESSION['csrf_token_time']);
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
@ -86,13 +87,55 @@ class File
|
||||
$src_img = $image_create($source_file);
|
||||
imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $nwidth, $nheight, $width, $height);
|
||||
|
||||
$image($dst_img, $dst_dir, $quality);
|
||||
imagepng($dst_img, $dst_dir);
|
||||
|
||||
if ($dst_img) imagedestroy($dst_img);
|
||||
if ($src_img) imagedestroy($src_img);
|
||||
return file_exists($dst_dir);
|
||||
}
|
||||
|
||||
public static function makeThumb($srcFile, $thumbFile, $thumbSize = 200)
|
||||
{
|
||||
/* Determine the File Type */
|
||||
$type = substr($srcFile, strrpos($srcFile, '.') + 1);
|
||||
$imgsize = getimagesize($srcFile);
|
||||
$oldW = $imgsize[0];
|
||||
$oldH = $imgsize[1];
|
||||
$mime = $imgsize['mime'];
|
||||
switch ($mime) {
|
||||
case 'image/gif':
|
||||
$src = imagecreatefromgif($srcFile);
|
||||
break;
|
||||
|
||||
case 'image/png':
|
||||
$src = imagecreatefrompng($srcFile);
|
||||
break;
|
||||
|
||||
case 'image/jpeg':
|
||||
$src = imagecreatefromjpeg($srcFile);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
/* Calculate the New Image Dimensions */
|
||||
$limiting_dim = 0;
|
||||
if ($oldH > $oldW) {
|
||||
/* Portrait */
|
||||
$limiting_dim = $oldW;
|
||||
} else {
|
||||
/* Landscape */
|
||||
$limiting_dim = $oldH;
|
||||
}
|
||||
/* Create the New Image */
|
||||
$new = imagecreatetruecolor($thumbSize, $thumbSize);
|
||||
/* Transcribe the Source Image into the New (Square) Image */
|
||||
imagecopyresampled($new, $src, 0, 0, ($oldW - $limiting_dim) / 2, ($oldH - $limiting_dim) / 2, $thumbSize, $thumbSize, $limiting_dim, $limiting_dim);
|
||||
imagejpeg($new, $thumbFile, 100);
|
||||
imagedestroy($new);
|
||||
return file_exists($thumbFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* file path fixer
|
||||
|
@ -14,14 +14,14 @@
|
||||
|
||||
class Http
|
||||
{
|
||||
public static function getData($url, $headers = [])
|
||||
public static function getData($url, $headers = [], $connect_timeout = 3000, $wait_timeout = 3000)
|
||||
{
|
||||
global $http_proxy, $http_proxyauth, $admin;
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_POST, 0);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 100);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 100);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, $wait_timeout);
|
||||
if (is_array($headers) && count($headers) > 0) {
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
}
|
||||
@ -49,15 +49,15 @@ class Http
|
||||
return (!empty($server_output)) ? $server_output : $error_msg;
|
||||
}
|
||||
|
||||
public static function postJsonData($url, $array_post, $headers = [], $basic = null)
|
||||
public static function postJsonData($url, $array_post, $headers = [], $basic = null, $connect_timeout = 3000, $wait_timeout = 3000)
|
||||
{
|
||||
global $http_proxy, $http_proxyauth, $admin;
|
||||
$headers[] = 'Content-Type: application/json';
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 100);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 100);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, $wait_timeout);
|
||||
curl_setopt($ch, CURLOPT_VERBOSE, false);
|
||||
curl_setopt($ch, CURLINFO_HEADER_OUT, false);
|
||||
if (!empty($http_proxy)) {
|
||||
@ -92,15 +92,15 @@ class Http
|
||||
}
|
||||
|
||||
|
||||
public static function postData($url, $array_post, $headers = [], $basic = null)
|
||||
public static function postData($url, $array_post, $headers = [], $basic = null, $connect_timeout = 3000, $wait_timeout = 3000)
|
||||
{
|
||||
global $http_proxy, $http_proxyauth, $admin;
|
||||
$headers[] = 'Content-Type: application/x-www-form-urlencoded';
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 100);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 100);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, $wait_timeout);
|
||||
curl_setopt($ch, CURLOPT_VERBOSE, false);
|
||||
curl_setopt($ch, CURLINFO_HEADER_OUT, false);
|
||||
if (!empty($http_proxy)) {
|
||||
|
347
system/autoload/Invoice.php
Normal file
347
system/autoload/Invoice.php
Normal file
@ -0,0 +1,347 @@
|
||||
<?php
|
||||
|
||||
use Mpdf\Mpdf;
|
||||
|
||||
class Invoice
|
||||
{
|
||||
public static function generateInvoice($invoiceData)
|
||||
{
|
||||
try {
|
||||
if (empty($invoiceData['invoice'])) {
|
||||
throw new Exception(Lang::T("Invoice No is required"));
|
||||
}
|
||||
|
||||
$template = Lang::getNotifText('email_invoice');
|
||||
if (!$template) {
|
||||
throw new Exception(Lang::T("Invoice template not found"));
|
||||
}
|
||||
|
||||
if (strpos($template, '<body') === false) {
|
||||
$template = "<html><body>$template</body></html>";
|
||||
}
|
||||
|
||||
$processedHtml = self::renderTemplate($template, $invoiceData);
|
||||
|
||||
// Debugging: Save processed HTML to file for review
|
||||
// file_put_contents('debug_invoice.html', $processedHtml);
|
||||
|
||||
// Generate PDF
|
||||
$mpdf = new Mpdf([
|
||||
'mode' => 'utf-8',
|
||||
'format' => 'A4',
|
||||
'margin_left' => 10,
|
||||
'margin_right' => 10,
|
||||
'margin_top' => 10,
|
||||
'margin_bottom' => 10,
|
||||
'default_font' => 'helvetica',
|
||||
'orientation' => 'P',
|
||||
]);
|
||||
|
||||
$mpdf->SetDisplayMode('fullpage');
|
||||
$mpdf->SetProtection(['print']);
|
||||
$mpdf->shrink_tables_to_fit = 1;
|
||||
$mpdf->SetWatermarkText(strtoupper($invoiceData['status'] ?? 'UNPAID'), 0.15);
|
||||
$mpdf->showWatermarkText = true;
|
||||
$mpdf->WriteHTML($processedHtml);
|
||||
|
||||
// Save PDF
|
||||
$filename = "invoice_{$invoiceData['invoice']}.pdf";
|
||||
$outputPath = "system/uploads/invoices/{$filename}";
|
||||
$dir = dirname($outputPath);
|
||||
if (!is_dir($dir)) {
|
||||
mkdir($dir, 0755, true);
|
||||
}
|
||||
$mpdf->Output($outputPath, 'F');
|
||||
|
||||
if (!file_exists($outputPath)) {
|
||||
throw new Exception(Lang::T("Failed to save PDF file"));
|
||||
}
|
||||
|
||||
return $filename;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
_log("Invoice generation failed: " . $e->getMessage());
|
||||
sendTelegram("Invoice generation failed: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static function renderTemplate($template, $invoiceData)
|
||||
{
|
||||
return preg_replace_callback('/\[\[(\w+)\]\]/', function ($matches) use ($invoiceData) {
|
||||
$key = $matches[1];
|
||||
if (!isset($invoiceData[$key])) {
|
||||
_log(Lang::T("Missing invoice key: ") . $key);
|
||||
return '';
|
||||
}
|
||||
|
||||
if (in_array($key, ['created_at', 'due_date'])) {
|
||||
return date('F j, Y', strtotime($invoiceData[$key]));
|
||||
}
|
||||
|
||||
if (in_array($key, ['amount', 'total', 'subtotal', 'tax'])) {
|
||||
return $invoiceData['currency_code'] . number_format((float) $invoiceData[$key], 2);
|
||||
}
|
||||
|
||||
if ($key === 'bill_rows') {
|
||||
return $invoiceData[$key];
|
||||
}
|
||||
|
||||
return htmlspecialchars($invoiceData[$key] ?? '');
|
||||
}, $template);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send invoice to user
|
||||
*
|
||||
* @param int $userId
|
||||
* @param array $invoice
|
||||
* @param array $bills
|
||||
* @param string $status
|
||||
* @param string $invoiceNo
|
||||
* @return bool
|
||||
*/
|
||||
|
||||
public static function sendInvoice($userId, $invoice = null, $bills = [], $status = "Unpaid", $invoiceNo = null)
|
||||
{
|
||||
global $config, $root_path, $UPLOAD_PATH;
|
||||
|
||||
// Set default currency code
|
||||
$config['currency_code'] ??= '$';
|
||||
|
||||
$account = ORM::for_table('tbl_customers')->find_one($userId);
|
||||
self::validateAccount($account);
|
||||
if (!$invoiceNo) {
|
||||
$invoiceNo = "INV-" . Package::_raid();
|
||||
}
|
||||
// Fetch invoice if not provided
|
||||
if ($status === "Unpaid" && !$invoice) {
|
||||
$data = ORM::for_table('tbl_user_recharges')->where('customer_id', $userId)
|
||||
->where('status', 'off')
|
||||
->left_outer_join('tbl_plans', 'tbl_user_recharges.namebp = tbl_plans.name_plan')
|
||||
->select('tbl_plans.price', 'price')
|
||||
->select('tbl_plans.name_plan', 'namebp')
|
||||
->find_one();
|
||||
if (!$data) {
|
||||
$data = ORM::for_table('tbl_user_recharges')->where('username', $account->username)
|
||||
->left_outer_join('tbl_plans', 'tbl_user_recharges.namebp = tbl_plans.name_plan')
|
||||
->select('tbl_plans.price', 'price')
|
||||
->select('tbl_plans.name_plan', 'namebp')
|
||||
->where('status', 'off')
|
||||
->find_one();
|
||||
}
|
||||
if (!$data) {
|
||||
throw new Exception(Lang::T("No unpaid invoice found for username:") . $account->username);
|
||||
}
|
||||
$invoice = [
|
||||
'price' => $data->price,
|
||||
'plan_name' => $data->namebp,
|
||||
'routers' => $data->routers,
|
||||
];
|
||||
|
||||
} else if ($status === "Paid" && !$invoice) {
|
||||
$invoice = ORM::for_table("tbl_transactions")->where("username", $account->username)->find_one();
|
||||
}
|
||||
if (!$invoice) {
|
||||
throw new Exception(Lang::T("Transaction not found for username: ") . $account->username);
|
||||
}
|
||||
|
||||
// Get additional bills if not provided
|
||||
if (empty($bills)) {
|
||||
[$bills, $add_cost] = User::getBills($account->id);
|
||||
}
|
||||
|
||||
$invoiceItems = self::generateInvoiceItems($invoice, $bills, $add_cost);
|
||||
$subtotal = array_sum(array_column($invoiceItems, 'amount'));
|
||||
$tax = $config['enable_tax'] ? Package::tax($subtotal) : 0;
|
||||
$tax_rate = $config['tax_rate'] ?? 0;
|
||||
$total = $subtotal + $tax;
|
||||
|
||||
$payLink = self::generatePaymentLink($account, $invoice, $status);
|
||||
$logo = self::getCompanyLogo($UPLOAD_PATH, $root_path);
|
||||
|
||||
$invoiceData = [
|
||||
'invoice' => $invoiceNo,
|
||||
'fullname' => $account->fullname,
|
||||
'email' => $account->email,
|
||||
'address' => $account->address,
|
||||
'phone' => $account->phonenumber,
|
||||
'bill_rows' => self::generateBillRows($invoiceItems, $config['currency_code'], $subtotal, $tax_rate, $tax, $total),
|
||||
'status' => $status,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'due_date' => date('Y-m-d H:i:s', strtotime('+7 days')),
|
||||
'currency' => $config['currency_code'],
|
||||
'company_address' => $config['address'],
|
||||
'company_name' => $config['CompanyName'],
|
||||
'company_phone' => $config['phone'],
|
||||
'logo' => $logo,
|
||||
'payment_link' => $payLink
|
||||
];
|
||||
|
||||
if (empty($invoiceData['bill_rows'])) {
|
||||
throw new Exception(Lang::T("Bill rows data is empty."));
|
||||
}
|
||||
|
||||
$filename = self::generateInvoice($invoiceData);
|
||||
if (!$filename) {
|
||||
throw new Exception(Lang::T("Failed to generate invoice PDF"));
|
||||
}
|
||||
|
||||
$pdfPath = "system/uploads/invoices/{$filename}";
|
||||
self::saveToDatabase($filename, $account->id, $invoiceData, $total);
|
||||
|
||||
try {
|
||||
Message::sendEmail(
|
||||
$account->email,
|
||||
Lang::T("Invoice for Account {$account->fullname}"),
|
||||
Lang::T("Please find your invoice attached"),
|
||||
$pdfPath
|
||||
);
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
throw new Exception(Lang::T("Failed to send email invoice to ") . $account->email . ". " . Lang::T("Reason: ") . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static function validateAccount($account)
|
||||
{
|
||||
if (!$account) {
|
||||
throw new Exception(Lang::T("User not found"));
|
||||
}
|
||||
if (!$account->email || !filter_var($account->email, FILTER_VALIDATE_EMAIL)) {
|
||||
throw new Exception(Lang::T("Invalid user email"));
|
||||
}
|
||||
}
|
||||
|
||||
private static function generateInvoiceItems($invoice, $bills, $add_cost)
|
||||
{
|
||||
$items = [
|
||||
[
|
||||
'description' => $invoice['plan_name'],
|
||||
'details' => Lang::T('Subscription'),
|
||||
'amount' => (float) $invoice['price']
|
||||
]
|
||||
];
|
||||
|
||||
if ($invoice->routers != 'balance') {
|
||||
foreach ($bills as $description => $amount) {
|
||||
if (is_numeric($amount)) {
|
||||
$items[] = [
|
||||
'description' => $description,
|
||||
'details' => Lang::T('Additional Bill'),
|
||||
'amount' => (float) $amount
|
||||
];
|
||||
} else {
|
||||
_log(Lang::T("Invalid bill amount for {$description}: {$amount}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
private static function generatePaymentLink($account, $invoice, $status)
|
||||
{
|
||||
$token = User::generateToken($account->id, 1);
|
||||
if (empty($token['token'])) {
|
||||
return '?_route=home';
|
||||
}
|
||||
|
||||
$tur = ORM::for_table('tbl_user_recharges')
|
||||
->where('customer_id', $account->id)
|
||||
->where('namebp', $invoice->plan_name);
|
||||
|
||||
$tur->where('status', $status === 'Paid' ? 'on' : 'off');
|
||||
$turResult = $tur->find_one();
|
||||
|
||||
return $turResult ? '?_route=home&recharge=' . $turResult['id'] . '&uid=' . urlencode($token['token']) : '?_route=home';
|
||||
}
|
||||
|
||||
private static function getCompanyLogo($UPLOAD_PATH, $root_path)
|
||||
{
|
||||
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
|
||||
return file_exists($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png') ?
|
||||
$UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'logo.png?' . time() :
|
||||
$UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'logo.default.png';
|
||||
}
|
||||
|
||||
private static function generateBillRows($items, $currency, $subtotal, $tax_rate, $tax, $total)
|
||||
{
|
||||
$html = "<table style='width: 100%; border-collapse: collapse; margin: 20px 0;'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style='background: #3498db; color: white; padding: 12px; text-align: left;'>Description</th>
|
||||
<th style='background: #3498db; color: white; padding: 12px; text-align: left;'>Details</th>
|
||||
<th style='background: #3498db; color: white; padding: 12px; text-align: left;'>Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>";
|
||||
|
||||
foreach ($items as $item) {
|
||||
$desc = htmlspecialchars($item['description'], ENT_QUOTES);
|
||||
$details = htmlspecialchars($item['details'], ENT_QUOTES);
|
||||
$html .= "<tr>
|
||||
<td style='padding: 10px; border-bottom: 1px solid #ddd;'>{$desc}</td>
|
||||
<td style='padding: 10px; border-bottom: 1px solid #ddd;'>{$details}</td>
|
||||
<td style='padding: 10px; border-bottom: 1px solid #ddd;'>{$currency}" . number_format((float) $item['amount'], 2) . "</td>
|
||||
</tr>";
|
||||
}
|
||||
|
||||
$html .= "<tr>
|
||||
<td colspan='2' style='text-align: right; padding: 10px; border-top: 2px solid #3498db;'>Subtotal:</td>
|
||||
<td style='padding: 10px; border-top: 2px solid #3498db;'>{$currency}" . number_format($subtotal, 2) . "</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='2' style='text-align: right; padding: 10px;'>TAX ({$tax_rate}%):</td>
|
||||
<td style='padding: 10px;'>{$currency}" . number_format($tax, 2) . "</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='2' style='text-align: right; padding: 10px; font-weight: bold;'>Total:</td>
|
||||
<td style='padding: 10px; font-weight: bold;'>{$currency}" . number_format($total, 2) . "</td>
|
||||
</tr>";
|
||||
|
||||
$html .= "</tbody></table>";
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
private static function saveToDatabase($filename, $customer_id, $invoiceData, $total)
|
||||
{
|
||||
$invoice = ORM::for_table('tbl_invoices')->create();
|
||||
$invoice->number = $invoiceData['invoice'];
|
||||
$invoice->customer_id = $customer_id;
|
||||
$invoice->fullname = $invoiceData['fullname'];
|
||||
$invoice->email = $invoiceData['email'];
|
||||
$invoice->address = $invoiceData['address'];
|
||||
$invoice->status = $invoiceData['status'];
|
||||
$invoice->due_date = $invoiceData['due_date'];
|
||||
$invoice->filename = $filename;
|
||||
$invoice->amount = $total;
|
||||
$invoice->data = json_encode($invoiceData);
|
||||
$invoice->created_at = date('Y-m-d H:i:s');
|
||||
$invoice->save();
|
||||
return $invoice->id;
|
||||
}
|
||||
|
||||
public static function getAll()
|
||||
{
|
||||
return ORM::for_table('tbl_invoices')->order_by_desc('id')->find_many();
|
||||
}
|
||||
public static function getById($id)
|
||||
{
|
||||
return ORM::for_table('tbl_invoices')->find_one($id);
|
||||
}
|
||||
public static function getByNumber($number)
|
||||
{
|
||||
return ORM::for_table('tbl_invoices')->where('number', $number)->find_one();
|
||||
}
|
||||
public static function delete($id)
|
||||
{
|
||||
$invoice = ORM::for_table('tbl_invoices')->find_one($id);
|
||||
if ($invoice) {
|
||||
$invoice->delete();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -10,15 +10,8 @@ class Lang
|
||||
{
|
||||
public static function T($key)
|
||||
{
|
||||
global $_L, $lan_file, $root_path, $config;
|
||||
global $_L, $lan_file, $config;
|
||||
|
||||
if (empty($lan_file)) {
|
||||
$lan_file = $root_path . File::pathFixer('system/lan/' . $config['language'] . '.json');
|
||||
}
|
||||
|
||||
if (is_array($_SESSION['Lang'])) {
|
||||
$_L = array_merge($_L, $_SESSION['Lang']);
|
||||
}
|
||||
$key = preg_replace('/\s+/', ' ', $key);
|
||||
if (!empty($_L[$key])) {
|
||||
return $_L[$key];
|
||||
@ -34,15 +27,14 @@ class Lang
|
||||
if (empty($iso)) {
|
||||
return $val;
|
||||
}
|
||||
if (!empty($iso) && !empty($val)) {
|
||||
if (!empty($iso) && !empty($val) && $iso != 'en') {
|
||||
$temp = Lang::translate($val, $iso);
|
||||
if (!empty($temp)) {
|
||||
$val = $temp;
|
||||
}
|
||||
}
|
||||
$_L[$key] = $val;
|
||||
$_SESSION['Lang'][$key] = $val;
|
||||
file_put_contents($lan_file, json_encode($_SESSION['Lang'], JSON_PRETTY_PRINT));
|
||||
file_put_contents($lan_file, json_encode($_L, JSON_PRETTY_PRINT));
|
||||
return $val;
|
||||
}
|
||||
}
|
||||
|
@ -17,12 +17,18 @@ require $root_path . 'system/autoload/mail/SMTP.php';
|
||||
class Message
|
||||
{
|
||||
|
||||
public static function sendTelegram($txt)
|
||||
public static function sendTelegram($txt, $chat_id = null, $topik = '')
|
||||
{
|
||||
global $config;
|
||||
run_hook('send_telegram', [$txt]); #HOOK
|
||||
if (!empty($config['telegram_bot']) && !empty($config['telegram_target_id'])) {
|
||||
return Http::getData('https://api.telegram.org/bot' . $config['telegram_bot'] . '/sendMessage?chat_id=' . $config['telegram_target_id'] . '&text=' . urlencode($txt));
|
||||
run_hook('send_telegram', [$txt, $chat_id, $topik]); #HOOK
|
||||
if (!empty($config['telegram_bot'])) {
|
||||
if (empty($chat_id)) {
|
||||
$chat_id = $config['telegram_target_id'];
|
||||
}
|
||||
if (!empty($topik)) {
|
||||
$topik = "message_thread_id=$topik&";
|
||||
}
|
||||
return Http::getData('https://api.telegram.org/bot' . $config['telegram_bot'] . '/sendMessage?' . $topik . 'chat_id=' . $chat_id . '&text=' . urlencode($txt));
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,31 +46,39 @@ class Message
|
||||
$txts = str_split($txt, 160);
|
||||
try {
|
||||
foreach ($txts as $txt) {
|
||||
self::sendSMS($config['sms_url'], $phone, $txt);
|
||||
self::sendSMS($phone, $txt);
|
||||
self::logMessage('SMS', $phone, $txt, 'Success');
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
} catch (Throwable $e) {
|
||||
// ignore, add to logs
|
||||
_log("Failed to send SMS using Mikrotik.\n" . $e->getMessage(), 'SMS', 0);
|
||||
self::logMessage('SMS', $phone, $txt, 'Error', $e->getMessage());
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
self::sendSMS($config['sms_url'], $phone, $txt);
|
||||
} catch (Exception $e) {
|
||||
self::MikrotikSendSMS($config['sms_url'], $phone, $txt);
|
||||
self::logMessage('MikroTikSMS', $phone, $txt, 'Success');
|
||||
} catch (Throwable $e) {
|
||||
// ignore, add to logs
|
||||
_log("Failed to send SMS using Mikrotik.\n" . $e->getMessage(), 'SMS', 0);
|
||||
self::logMessage('MikroTikSMS', $phone, $txt, 'Error', $e->getMessage());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$smsurl = str_replace('[number]', urlencode($phone), $config['sms_url']);
|
||||
$smsurl = str_replace('[text]', urlencode($txt), $smsurl);
|
||||
return Http::getData($smsurl);
|
||||
try {
|
||||
$response = Http::getData($smsurl);
|
||||
self::logMessage('SMS HTTP Response', $phone, $txt, 'Success', $response);
|
||||
return $response;
|
||||
} catch (Throwable $e) {
|
||||
self::logMessage('SMS HTTP Request', $phone, $txt, 'Error', $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function MikrotikSendSMS($router_name, $to, $message)
|
||||
{
|
||||
global $_app_stage, $client_m;
|
||||
global $_app_stage, $client_m, $config;
|
||||
if ($_app_stage == 'demo') {
|
||||
return null;
|
||||
}
|
||||
@ -73,7 +87,10 @@ class Message
|
||||
$iport = explode(":", $mikrotik['ip_address']);
|
||||
$client_m = new RouterOS\Client($iport[0], $mikrotik['username'], $mikrotik['password'], ($iport[1]) ? $iport[1] : null);
|
||||
}
|
||||
$smsRequest = new RouterOS\Request('/tool sms send');
|
||||
if (empty($config['mikrotik_sms_command'])) {
|
||||
$config['mikrotik_sms_command'] = "/tool sms send";
|
||||
}
|
||||
$smsRequest = new RouterOS\Request($config['mikrotik_sms_command']);
|
||||
$smsRequest
|
||||
->setArgument('phone-number', $to)
|
||||
->setArgument('message', $message);
|
||||
@ -86,15 +103,24 @@ class Message
|
||||
if (empty($txt)) {
|
||||
return "kosong";
|
||||
}
|
||||
run_hook('send_whatsapp', [$phone, $txt]); #HOOK
|
||||
|
||||
run_hook('send_whatsapp', [$phone, $txt]); // HOOK
|
||||
|
||||
if (!empty($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);
|
||||
|
||||
try {
|
||||
$response = Http::getData($waurl);
|
||||
self::logMessage('WhatsApp HTTP Response', $phone, $txt, 'Success', $response);
|
||||
return $response;
|
||||
} catch (Throwable $e) {
|
||||
self::logMessage('WhatsApp HTTP Request', $phone, $txt, 'Error', $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function sendEmail($to, $subject, $body)
|
||||
public static function sendEmail($to, $subject, $body, $attachmentPath = null)
|
||||
{
|
||||
global $config, $PAGES_PATH, $debug_mail;
|
||||
if (empty($body)) {
|
||||
@ -113,18 +139,20 @@ class Message
|
||||
$attr .= "Reply-To: " . $config['mail_reply_to'] . "\r\n";
|
||||
}
|
||||
mail($to, $subject, $body, $attr);
|
||||
self::logMessage('Email', $to, $body, 'Success');
|
||||
return true;
|
||||
} else {
|
||||
$mail = new PHPMailer();
|
||||
$mail->isSMTP();
|
||||
if (isset($debug_mail) && $debug_mail == 'Dev') {
|
||||
$mail->SMTPDebug = SMTP::DEBUG_SERVER;
|
||||
}
|
||||
$mail->Host = $config['smtp_host'];
|
||||
$mail->SMTPAuth = true;
|
||||
$mail->Username = $config['smtp_user'];
|
||||
$mail->Password = $config['smtp_pass'];
|
||||
$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'];
|
||||
$mail->Port = $config['smtp_port'];
|
||||
if (!empty($config['mail_from'])) {
|
||||
$mail->setFrom($config['mail_from']);
|
||||
}
|
||||
@ -134,6 +162,10 @@ class Message
|
||||
|
||||
$mail->addAddress($to);
|
||||
$mail->Subject = $subject;
|
||||
// Attachments
|
||||
if (!empty($attachmentPath)) {
|
||||
$mail->addAttachment($attachmentPath);
|
||||
}
|
||||
|
||||
if (!file_exists($PAGES_PATH . DIRECTORY_SEPARATOR . 'Email.html')) {
|
||||
if (!copy($PAGES_PATH . '_template' . DIRECTORY_SEPARATOR . 'Email.html', $PAGES_PATH . DIRECTORY_SEPARATOR . 'Email.html')) {
|
||||
@ -148,12 +180,20 @@ class Message
|
||||
$html = str_replace('[[Company_Name]]', nl2br($config['CompanyName']), $html);
|
||||
$html = str_replace('[[Body]]', nl2br($body), $html);
|
||||
$mail->isHTML(true);
|
||||
$mail->Body = $html;
|
||||
$mail->Body = $html;
|
||||
$mail->Body = $html;
|
||||
} else {
|
||||
$mail->isHTML(false);
|
||||
$mail->Body = $body;
|
||||
$mail->Body = $body;
|
||||
}
|
||||
if (!$mail->send()) {
|
||||
$errorMessage = Lang::T("Email not sent, Mailer Error: ") . $mail->ErrorInfo;
|
||||
self::logMessage('Email', $to, $body, 'Error', $errorMessage);
|
||||
return false;
|
||||
} else {
|
||||
self::logMessage('Email', $to, $body, 'Success');
|
||||
return true;
|
||||
}
|
||||
$mail->send();
|
||||
|
||||
//<p style="font-family: Helvetica, sans-serif; font-size: 16px; font-weight: normal; margin: 0; margin-bottom: 16px;">
|
||||
}
|
||||
@ -170,41 +210,86 @@ class Message
|
||||
$msg = str_replace('[[plan]]', $package, $msg);
|
||||
$msg = str_replace('[[package]]', $package, $msg);
|
||||
$msg = str_replace('[[price]]', Lang::moneyFormat($price), $msg);
|
||||
// Calculate bills and additional costs
|
||||
list($bills, $add_cost) = User::getBills($customer['id']);
|
||||
if ($add_cost > 0) {
|
||||
$note = "";
|
||||
|
||||
// Initialize note and total variables
|
||||
$note = "";
|
||||
$total = $price;
|
||||
|
||||
// Add bills to the note if there are any additional costs
|
||||
if ($add_cost != 0) {
|
||||
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);
|
||||
$total += $add_cost;
|
||||
}
|
||||
|
||||
// Calculate tax
|
||||
$tax = 0;
|
||||
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
|
||||
if ($tax_enable === 'yes') {
|
||||
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
|
||||
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float) $config['custom_tax_rate'] : null;
|
||||
|
||||
$tax_rate = ($tax_rate_setting === 'custom') ? $custom_tax_rate : $tax_rate_setting;
|
||||
$tax = Package::tax($price, $tax_rate);
|
||||
|
||||
if ($tax != 0) {
|
||||
$note .= "Tax : " . Lang::moneyFormat($tax) . "\n";
|
||||
$total += $tax;
|
||||
}
|
||||
}
|
||||
|
||||
// Add total to the note
|
||||
$note .= "Total : " . Lang::moneyFormat($total) . "\n";
|
||||
|
||||
// Replace placeholders in the message
|
||||
$msg = str_replace('[[bills]]', $note, $msg);
|
||||
|
||||
if ($ds) {
|
||||
$msg = str_replace('[[expired_date]]', Lang::dateAndTimeFormat($ds['expiration'], $ds['time']), $msg);
|
||||
} else {
|
||||
$msg = str_replace('[[expired_date]]', "", $msg);
|
||||
}
|
||||
|
||||
if (strpos($msg, '[[payment_link]]') !== false) {
|
||||
// token only valid for 1 day, for security reason
|
||||
$token = User::generateToken($customer['id'], 1);
|
||||
if (!empty($token['token'])) {
|
||||
$tur = ORM::for_table('tbl_user_recharges')
|
||||
->where('customer_id', $customer['id'])
|
||||
->where('namebp', $package)
|
||||
->find_one();
|
||||
if ($tur) {
|
||||
$url = '?_route=home&recharge=' . $tur['id'] . '&uid=' . urlencode($token['token']);
|
||||
$msg = str_replace('[[payment_link]]', $url, $msg);
|
||||
}
|
||||
} else {
|
||||
$msg = str_replace('[[payment_link]]', '', $msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
!empty($customer['phonenumber']) && strlen($customer['phonenumber']) > 5
|
||||
&& !empty($message) && in_array($via, ['sms', 'wa'])
|
||||
) {
|
||||
if ($via == 'sms') {
|
||||
echo Message::sendSMS($customer['phonenumber'], $msg);
|
||||
Message::sendSMS($customer['phonenumber'], $msg);
|
||||
} else if ($via == 'email') {
|
||||
self::sendEmail($customer['email'], '[' . $config['CompanyName'] . '] ' . Lang::T("Internet Plan Reminder"), $msg);
|
||||
} else if ($via == 'wa') {
|
||||
echo Message::sendWhatsapp($customer['phonenumber'], $msg);
|
||||
Message::sendWhatsapp($customer['phonenumber'], $msg);
|
||||
}
|
||||
}
|
||||
return "$via: $msg";
|
||||
}
|
||||
|
||||
public static function sendBalanceNotification($cust, $balance, $balance_now, $message, $via)
|
||||
public static function sendBalanceNotification($cust, $target, $balance, $balance_now, $message, $via)
|
||||
{
|
||||
global $config;
|
||||
$msg = str_replace('[[name]]', $cust['fullname'] . ' (' . $cust['username'] . ')', $message);
|
||||
$msg = str_replace('[[name]]', $target['fullname'] . ' (' . $target['username'] . ')', $message);
|
||||
$msg = str_replace('[[current_balance]]', Lang::moneyFormat($balance_now), $msg);
|
||||
$msg = str_replace('[[balance]]', Lang::moneyFormat($balance), $msg);
|
||||
$phone = $cust['phonenumber'];
|
||||
@ -214,24 +299,26 @@ class Message
|
||||
) {
|
||||
if ($via == 'sms') {
|
||||
Message::sendSMS($phone, $msg);
|
||||
} else if ($config['user_notification_payment'] == 'email') {
|
||||
} else if ($via == 'email') {
|
||||
self::sendEmail($cust['email'], '[' . $config['CompanyName'] . '] ' . Lang::T("Balance Notification"), $msg);
|
||||
} else if ($via == 'wa') {
|
||||
Message::sendWhatsapp($phone, $msg);
|
||||
}
|
||||
self::addToInbox($cust['id'], Lang::T('Balance Notification'), $msg);
|
||||
}
|
||||
return "$via: $msg";
|
||||
}
|
||||
|
||||
public static function sendInvoice($cust, $trx)
|
||||
{
|
||||
global $config;
|
||||
global $config, $db_pass;
|
||||
$textInvoice = Lang::getNotifText('invoice_paid');
|
||||
$textInvoice = str_replace('[[company_name]]', $config['CompanyName'], $textInvoice);
|
||||
$textInvoice = str_replace('[[address]]', $config['address'], $textInvoice);
|
||||
$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);
|
||||
$textInvoice = str_replace('[[trx_date]]', Lang::dateAndTimeFormat($trx['recharged_on'], $trx['recharged_time']), $textInvoice);
|
||||
if (!empty($trx['note'])) {
|
||||
$textInvoice = str_replace('[[note]]', $trx['note'], $textInvoice);
|
||||
}
|
||||
@ -240,7 +327,7 @@ class Message
|
||||
$textInvoice = str_replace('[[payment_channel]]', trim($gc[1]), $textInvoice);
|
||||
$textInvoice = str_replace('[[type]]', $trx['type'], $textInvoice);
|
||||
$textInvoice = str_replace('[[plan_name]]', $trx['plan_name'], $textInvoice);
|
||||
$textInvoice = str_replace('[[plan_price]]', Lang::moneyFormat($trx['price']), $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);
|
||||
@ -250,6 +337,46 @@ class Message
|
||||
$textInvoice = str_replace('[[expired_date]]', Lang::dateAndTimeFormat($trx['expiration'], $trx['time']), $textInvoice);
|
||||
$textInvoice = str_replace('[[footer]]', $config['note'], $textInvoice);
|
||||
|
||||
$inv_url = "?_route=voucher/invoice/$trx[id]/" . md5($trx['id'] . $db_pass);
|
||||
$textInvoice = str_replace('[[invoice_link]]', $inv_url, $textInvoice);
|
||||
|
||||
// Calculate bills and additional costs
|
||||
list($bills, $add_cost) = User::getBills($cust['id']);
|
||||
|
||||
// Initialize note and total variables
|
||||
$note = "";
|
||||
$total = $trx['price'];
|
||||
|
||||
// Add bills to the note if there are any additional costs
|
||||
if ($add_cost != 0) {
|
||||
foreach ($bills as $k => $v) {
|
||||
$note .= $k . " : " . Lang::moneyFormat($v) . "\n";
|
||||
}
|
||||
$total += $add_cost;
|
||||
}
|
||||
|
||||
// Calculate tax
|
||||
$tax = 0;
|
||||
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
|
||||
if ($tax_enable === 'yes') {
|
||||
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
|
||||
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float) $config['custom_tax_rate'] : null;
|
||||
|
||||
$tax_rate = ($tax_rate_setting === 'custom') ? $custom_tax_rate : $tax_rate_setting;
|
||||
$tax = Package::tax($trx['price'], $tax_rate);
|
||||
|
||||
if ($tax != 0) {
|
||||
$note .= "Tax : " . Lang::moneyFormat($tax) . "\n";
|
||||
$total += $tax;
|
||||
}
|
||||
}
|
||||
|
||||
// Add total to the note
|
||||
$note .= "Total : " . Lang::moneyFormat($total) . "\n";
|
||||
|
||||
// Replace placeholders in the message
|
||||
$textInvoice = str_replace('[[bills]]', $note, $textInvoice);
|
||||
|
||||
if ($config['user_notification_payment'] == 'sms') {
|
||||
Message::sendSMS($cust['phonenumber'], $textInvoice);
|
||||
} else if ($config['user_notification_payment'] == 'email') {
|
||||
@ -258,4 +385,49 @@ class Message
|
||||
Message::sendWhatsapp($cust['phonenumber'], $textInvoice);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function addToInbox($to_customer_id, $subject, $body, $from = 'System')
|
||||
{
|
||||
$user = User::find($to_customer_id);
|
||||
try {
|
||||
$v = ORM::for_table('tbl_customers_inbox')->create();
|
||||
$v->from = $from;
|
||||
$v->customer_id = $to_customer_id;
|
||||
$v->subject = $subject;
|
||||
$v->date_created = date('Y-m-d H:i:s');
|
||||
$v->body = nl2br($body);
|
||||
$v->save();
|
||||
self::logMessage("Inbox", $user->username, $body, "Success");
|
||||
return true;
|
||||
} catch (Throwable $e) {
|
||||
$errorMessage = Lang::T("Error adding message to inbox: " . $e->getMessage());
|
||||
self::logMessage('Inbox', $user->username, $body, 'Error', $errorMessage);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function getMessageType($type, $message)
|
||||
{
|
||||
if (strpos($message, "<divider>") === false) {
|
||||
return $message;
|
||||
}
|
||||
$msgs = explode("<divider>", $message);
|
||||
if ($type == "PPPOE") {
|
||||
return $msgs[1];
|
||||
} else {
|
||||
return $msgs[0];
|
||||
}
|
||||
}
|
||||
|
||||
public static function logMessage($messageType, $recipient, $messageContent, $status, $errorMessage = null)
|
||||
{
|
||||
$log = ORM::for_table('tbl_message_logs')->create();
|
||||
$log->message_type = $messageType;
|
||||
$log->recipient = $recipient;
|
||||
$log->message_content = $messageContent;
|
||||
$log->status = $status;
|
||||
$log->error_message = $errorMessage;
|
||||
$log->save();
|
||||
}
|
||||
}
|
||||
|
118
system/autoload/Meta.php
Normal file
118
system/autoload/Meta.php
Normal file
@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
*
|
||||
* Meta is for save adtional information in database for every existing table
|
||||
*
|
||||
* * Good for Plugin, so plugin don't need to modify existing tables
|
||||
*
|
||||
* Example to put data
|
||||
* if plan need to add point value for loyalty poin
|
||||
* Meta::for("tbl_plans")->set(1, 'point', '24');
|
||||
* it means tbl_plans with id 1 have point value 24, customer will get 24 point for loyalty if buy plan with id 1
|
||||
* You need to create the logic for that, Meta only hold the data
|
||||
*
|
||||
* Example to get data
|
||||
* $point = Meta::for("tbl_plans")->get(1, 'point');
|
||||
* this will return the point value of plan with id 1
|
||||
*
|
||||
* to get all key value
|
||||
* $metas = Meta::for("tbl_plans")->getAll(1);
|
||||
*
|
||||
* to delete 1 data
|
||||
* Meta::for("tbl_plans")->delete(1, 'point');
|
||||
*
|
||||
* to delete all data
|
||||
* Meta::for("tbl_plans")->deleteAll(1);
|
||||
**/
|
||||
|
||||
|
||||
class Meta
|
||||
{
|
||||
protected $table = '';
|
||||
|
||||
protected function __construct($table)
|
||||
{
|
||||
$this->table = $table;
|
||||
}
|
||||
|
||||
public static function for($table)
|
||||
{
|
||||
return new self($table);
|
||||
}
|
||||
|
||||
public function get($id, $key)
|
||||
{
|
||||
// get the Value
|
||||
return ORM::for_table('tbl_meta')
|
||||
->select('value')
|
||||
->where('tbl', $this->table)
|
||||
->where('tbl_id', $id)
|
||||
->where('name', $key)
|
||||
->find_one()['value'];
|
||||
}
|
||||
|
||||
public function getAll($id)
|
||||
{
|
||||
//get all key Value
|
||||
$metas = [];
|
||||
$result = ORM::for_table('tbl_meta')
|
||||
->select('name')
|
||||
->select('value')
|
||||
->where('tbl', $this->table)
|
||||
->where('tbl_id', $id)
|
||||
->find_array();
|
||||
foreach ($result as $value) {
|
||||
$metas[$value['name']] = $value['value'];
|
||||
}
|
||||
return $metas;
|
||||
}
|
||||
|
||||
public function set($id, $key, $value = '')
|
||||
{
|
||||
$meta = ORM::for_table('tbl_meta')
|
||||
->where('tbl', $this->table)
|
||||
->where('tbl_id', $id)
|
||||
->where('name', $key)
|
||||
->find_one();
|
||||
if (!$meta) {
|
||||
$meta = ORM::for_table('tbl_meta')->create();
|
||||
$meta->tbl = $this->table;
|
||||
$meta->tbl_id = $id;
|
||||
$meta->name = $key;
|
||||
$meta->value = $value;
|
||||
$meta->save();
|
||||
$result = $meta->id();
|
||||
if ($result) {
|
||||
return $result;
|
||||
}
|
||||
} else {
|
||||
$meta->value = $value;
|
||||
$meta->save();
|
||||
return $meta['id'];
|
||||
}
|
||||
}
|
||||
|
||||
public function delete($id, $key = '')
|
||||
{
|
||||
// get the Value
|
||||
return ORM::for_table('tbl_meta')
|
||||
->select('value')
|
||||
->where('tbl', $this->table)
|
||||
->where('tbl_id', $id)
|
||||
->where('name', $key)
|
||||
->delete();
|
||||
}
|
||||
|
||||
public function deleteAll($id)
|
||||
{
|
||||
//get all key Value
|
||||
return ORM::for_table('tbl_meta')
|
||||
->select('value')
|
||||
->where('tbl', $this->table)
|
||||
->where('tbl_id', $id)
|
||||
->delete_many();
|
||||
}
|
||||
}
|
@ -46,7 +46,11 @@ class Response extends Message
|
||||
/**
|
||||
* The last response for a request.
|
||||
*/
|
||||
const TYPE_FINAL = '!done';
|
||||
const TYPE_FINAL = '!done';/**
|
||||
|
||||
* The empty response for a request.
|
||||
*/
|
||||
const TYPE_EMPTY = '!empty';
|
||||
|
||||
/**
|
||||
* A response with data.
|
||||
@ -246,6 +250,7 @@ class Response extends Message
|
||||
{
|
||||
switch ($type) {
|
||||
case self::TYPE_FINAL:
|
||||
case self::TYPE_EMPTY:
|
||||
case self::TYPE_DATA:
|
||||
case self::TYPE_ERROR:
|
||||
case self::TYPE_FATAL:
|
||||
|
@ -21,7 +21,6 @@ class Package
|
||||
public static function rechargeUser($id_customer, $router_name, $plan_id, $gateway, $channel, $note = '')
|
||||
{
|
||||
global $config, $admin, $c, $p, $b, $t, $d, $zero, $trx, $_app_stage, $isChangePlan;
|
||||
$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");
|
||||
@ -64,7 +63,7 @@ class Package
|
||||
} else {
|
||||
// Additional cost
|
||||
list($bills, $add_cost) = User::getBills($id_customer);
|
||||
if ($add_cost > 0 && $router_name != 'balance') {
|
||||
if ($add_cost != 0 && $router_name != 'balance') {
|
||||
foreach ($bills as $k => $v) {
|
||||
$note .= $k . " : " . Lang::moneyFormat($v) . "\n";
|
||||
}
|
||||
@ -75,10 +74,10 @@ class Package
|
||||
|
||||
if (!$p['enabled']) {
|
||||
if (!isset($admin) || !isset($admin['id']) || empty($admin['id'])) {
|
||||
r2(U . 'home', 'e', Lang::T('Plan Not found'));
|
||||
r2(getUrl('home'), 'e', Lang::T('Plan Not found'));
|
||||
}
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
r2(U . 'dashboard', 'e', Lang::T('Plan Not found'));
|
||||
r2(getUrl('dashboard'), 'e', Lang::T('You do not have permission to access this page'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,57 +99,11 @@ class Package
|
||||
|
||||
|
||||
if ($router_name == 'balance') {
|
||||
// insert table transactions
|
||||
$t = ORM::for_table('tbl_transactions')->create();
|
||||
$t->invoice = $inv = "INV-" . Package::_raid();
|
||||
$t->username = $c['username'];
|
||||
$t->plan_name = $p['name_plan'];
|
||||
$t->price = $p['price'];
|
||||
$t->recharged_on = $date_only;
|
||||
$t->recharged_time = date("H:i:s");
|
||||
$t->expiration = $date_only;
|
||||
$t->time = $time;
|
||||
$t->method = "$gateway - $channel";
|
||||
$t->routers = $router_name;
|
||||
$t->type = "Balance";
|
||||
if ($admin) {
|
||||
$t->admin_id = ($admin['id']) ? $admin['id'] : '0';
|
||||
} else {
|
||||
$t->admin_id = '0';
|
||||
}
|
||||
$t->save();
|
||||
return self::rechargeBalance($c, $p, $gateway, $channel);
|
||||
}
|
||||
|
||||
$balance_before = $c['balance'];
|
||||
Balance::plus($id_customer, $p['price']);
|
||||
$balance = $c['balance'] + $p['price'];
|
||||
|
||||
$textInvoice = Lang::getNotifText('invoice_balance');
|
||||
$textInvoice = str_replace('[[company_name]]', $config['CompanyName'], $textInvoice);
|
||||
$textInvoice = str_replace('[[address]]', $config['address'], $textInvoice);
|
||||
$textInvoice = str_replace('[[phone]]', $config['phone'], $textInvoice);
|
||||
$textInvoice = str_replace('[[invoice]]', $inv, $textInvoice);
|
||||
$textInvoice = str_replace('[[date]]', Lang::dateTimeFormat($date_now), $textInvoice);
|
||||
$textInvoice = str_replace('[[payment_gateway]]', $gateway, $textInvoice);
|
||||
$textInvoice = str_replace('[[payment_channel]]', $channel, $textInvoice);
|
||||
$textInvoice = str_replace('[[type]]', 'Balance', $textInvoice);
|
||||
$textInvoice = str_replace('[[plan_name]]', $p['name_plan'], $textInvoice);
|
||||
$textInvoice = str_replace('[[plan_price]]', Lang::moneyFormat($p['price']), $textInvoice);
|
||||
$textInvoice = str_replace('[[name]]', $c['fullname'], $textInvoice);
|
||||
$textInvoice = str_replace('[[user_name]]', $c['username'], $textInvoice);
|
||||
$textInvoice = str_replace('[[user_password]]', $c['password'], $textInvoice);
|
||||
$textInvoice = str_replace('[[footer]]', $config['note'], $textInvoice);
|
||||
$textInvoice = str_replace('[[balance_before]]', Lang::moneyFormat($balance_before), $textInvoice);
|
||||
$textInvoice = str_replace('[[balance]]', Lang::moneyFormat($balance), $textInvoice);
|
||||
|
||||
if ($config['user_notification_payment'] == 'sms') {
|
||||
Message::sendSMS($c['phonenumber'], $textInvoice);
|
||||
} else if ($config['user_notification_payment'] == 'wa') {
|
||||
Message::sendWhatsapp($c['phonenumber'], $textInvoice);
|
||||
} else if ($config['user_notification_payment'] == 'email') {
|
||||
Message::sendEmail($c['email'], '[' . $config['CompanyName'] . '] ' . Lang::T("Invoice") . ' ' . $inv, $textInvoice);
|
||||
}
|
||||
|
||||
return true;
|
||||
if ($router_name == 'Custom Balance') {
|
||||
return self::rechargeCustomBalance($c, $p, $gateway, $channel);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -191,17 +144,40 @@ class Package
|
||||
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");
|
||||
$current_date = new DateTime($date_only);
|
||||
$exp_date = clone $current_date;
|
||||
$exp_date->modify('first day of next month');
|
||||
$exp_date->setDate($exp_date->format('Y'), $exp_date->format('m'), $day_exp);
|
||||
|
||||
$min_days = 7 * $p['validity'];
|
||||
$max_days = 35 * $p['validity'];
|
||||
|
||||
$days_until_exp = $exp_date->diff($current_date)->days;
|
||||
|
||||
// If less than min_days away, move to the next period
|
||||
while ($days_until_exp < $min_days) {
|
||||
$exp_date->modify('+1 month');
|
||||
$days_until_exp = $exp_date->diff($current_date)->days;
|
||||
}
|
||||
|
||||
// If more than max_days away, move to the previous period
|
||||
while ($days_until_exp > $max_days) {
|
||||
$exp_date->modify('-1 month');
|
||||
$days_until_exp = $exp_date->diff($current_date)->days;
|
||||
}
|
||||
|
||||
// Final check to ensure we're not less than min_days or in the past
|
||||
if ($days_until_exp < $min_days || $exp_date <= $current_date) {
|
||||
$exp_date->modify('+1 month');
|
||||
}
|
||||
|
||||
// Adjust for multiple periods
|
||||
if ($p['validity'] > 1) {
|
||||
$exp_date->modify('+' . ($p['validity'] - 1) . ' months');
|
||||
}
|
||||
|
||||
$date_exp = $exp_date->format('Y-m-d');
|
||||
$time = "23:59:59";
|
||||
} else if ($p['validity_unit'] == 'Days') {
|
||||
$datetime = explode(' ', date("Y-m-d H:i:s", strtotime('+' . $p['validity'] . ' day')));
|
||||
$date_exp = $datetime[0];
|
||||
@ -219,35 +195,39 @@ class Package
|
||||
if ($b) {
|
||||
$lastExpired = Lang::dateAndTimeFormat($b['expiration'], $b['time']);
|
||||
$isChangePlan = false;
|
||||
if ($config['extend_expiry'] != 'no') {
|
||||
if ($b['namebp'] == $p['name_plan'] && $b['status'] == 'on') {
|
||||
// if it same internet plan, expired will extend
|
||||
if ($p['validity_unit'] == 'Months') {
|
||||
if ($b['namebp'] == $p['name_plan'] && $b['status'] == 'on' && $config['extend_expiry'] == 'yes') {
|
||||
// if it same internet plan, expired will extend
|
||||
switch ($p['validity_unit']) {
|
||||
case 'Months':
|
||||
$date_exp = date("Y-m-d", strtotime($b['expiration'] . ' +' . $p['validity'] . ' months'));
|
||||
$time = $b['time'];
|
||||
} else if ($p['validity_unit'] == 'Period') {
|
||||
break;
|
||||
case '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') {
|
||||
break;
|
||||
case 'Days':
|
||||
$date_exp = date("Y-m-d", strtotime($b['expiration'] . ' +' . $p['validity'] . ' days'));
|
||||
$time = $b['time'];
|
||||
} else if ($p['validity_unit'] == 'Hrs') {
|
||||
break;
|
||||
case 'Hrs':
|
||||
$datetime = explode(' ', date("Y-m-d H:i:s", strtotime($b['expiration'] . ' ' . $b['time'] . ' +' . $p['validity'] . ' hours')));
|
||||
$date_exp = $datetime[0];
|
||||
$time = $datetime[1];
|
||||
} else if ($p['validity_unit'] == 'Mins') {
|
||||
break;
|
||||
case 'Mins':
|
||||
$datetime = explode(' ', date("Y-m-d H:i:s", strtotime($b['expiration'] . ' ' . $b['time'] . ' +' . $p['validity'] . ' minutes')));
|
||||
$date_exp = $datetime[0];
|
||||
$time = $datetime[1];
|
||||
}
|
||||
} else {
|
||||
$isChangePlan = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$isChangePlan = true;
|
||||
}
|
||||
|
||||
//if ($b['status'] == 'on') {
|
||||
$dvc = Package::getDevice($p);
|
||||
if ($_app_stage != 'demo') {
|
||||
if ($_app_stage != 'Demo') {
|
||||
try {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
@ -257,7 +237,7 @@ class Package
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
Message::sendTelegram(
|
||||
"Sistem Error. When activate Package. You need to sync manually\n" .
|
||||
"System Error. When activate Package. You need to sync manually\n" .
|
||||
"Router: $router_name\n" .
|
||||
"Customer: u$c[username]\n" .
|
||||
"Plan: p$p[name_plan]\n" .
|
||||
@ -266,7 +246,7 @@ class Package
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
Message::sendTelegram(
|
||||
"Sistem Error. When activate Package. You need to sync manually\n" .
|
||||
"System Error. When activate Package. You need to sync manually\n" .
|
||||
"Router: $router_name\n" .
|
||||
"Customer: u$c[username]\n" .
|
||||
"Plan: p$p[name_plan]\n" .
|
||||
@ -303,6 +283,7 @@ class Package
|
||||
$t = ORM::for_table('tbl_transactions')->create();
|
||||
$t->invoice = $inv = "INV-" . Package::_raid();
|
||||
$t->username = $c['username'];
|
||||
$t->user_id = $id_customer;
|
||||
$t->plan_name = $p['name_plan'];
|
||||
if ($gateway == 'Voucher' && User::isUserVoucher($channel)) {
|
||||
//its already paid
|
||||
@ -362,7 +343,7 @@ class Package
|
||||
} else {
|
||||
// active plan not exists
|
||||
$dvc = Package::getDevice($p);
|
||||
if ($_app_stage != 'demo') {
|
||||
if ($_app_stage != 'Demo') {
|
||||
try {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
@ -372,7 +353,7 @@ class Package
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
Message::sendTelegram(
|
||||
"Sistem Error. When activate Package. You need to sync manually\n" .
|
||||
"System Error. When activate Package. You need to sync manually\n" .
|
||||
"Router: $router_name\n" .
|
||||
"Customer: u$c[username]\n" .
|
||||
"Plan: p$p[name_plan]\n" .
|
||||
@ -381,7 +362,7 @@ class Package
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
Message::sendTelegram(
|
||||
"Sistem Error. When activate Package. You need to sync manually\n" .
|
||||
"System Error. When activate Package. You need to sync manually\n" .
|
||||
"Router: $router_name\n" .
|
||||
"Customer: u$c[username]\n" .
|
||||
"Plan: p$p[name_plan]\n" .
|
||||
@ -418,6 +399,7 @@ class Package
|
||||
$t = ORM::for_table('tbl_transactions')->create();
|
||||
$t->invoice = $inv = "INV-" . Package::_raid();
|
||||
$t->username = $c['username'];
|
||||
$t->user_id = $id_customer;
|
||||
$t->plan_name = $p['name_plan'];
|
||||
if ($gateway == 'Voucher' && User::isUserVoucher($channel)) {
|
||||
$t->price = 0;
|
||||
@ -493,6 +475,130 @@ class Package
|
||||
return $inv;
|
||||
}
|
||||
|
||||
public static function rechargeBalance($customer, $plan, $gateway, $channel, $note = '')
|
||||
{
|
||||
global $admin, $config;
|
||||
// insert table transactions
|
||||
$t = ORM::for_table('tbl_transactions')->create();
|
||||
$t->invoice = $inv = "INV-" . Package::_raid();
|
||||
$t->username = $customer['username'];
|
||||
$t->user_id = $customer['id'];
|
||||
$t->plan_name = $plan['name_plan'];
|
||||
$t->price = $plan['price'];
|
||||
$t->recharged_on = date("Y-m-d");
|
||||
$t->recharged_time = date("H:i:s");
|
||||
$t->expiration = date("Y-m-d");
|
||||
$t->time = date("H:i:s");
|
||||
$t->method = "$gateway - $channel";
|
||||
$t->routers = 'balance';
|
||||
$t->type = "Balance";
|
||||
$t->note = $note;
|
||||
if ($admin) {
|
||||
$t->admin_id = ($admin['id']) ? $admin['id'] : '0';
|
||||
} else {
|
||||
$t->admin_id = '0';
|
||||
}
|
||||
$t->save();
|
||||
|
||||
$balance_before = $customer['balance'];
|
||||
Balance::plus($customer['id'], $plan['price']);
|
||||
$balance = $customer['balance'] + $plan['price'];
|
||||
|
||||
$textInvoice = Lang::getNotifText('invoice_balance');
|
||||
$textInvoice = str_replace('[[company_name]]', $config['CompanyName'], $textInvoice);
|
||||
$textInvoice = str_replace('[[address]]', $config['address'], $textInvoice);
|
||||
$textInvoice = str_replace('[[phone]]', $config['phone'], $textInvoice);
|
||||
$textInvoice = str_replace('[[invoice]]', $inv, $textInvoice);
|
||||
$textInvoice = str_replace('[[date]]', Lang::dateTimeFormat(date("Y-m-d H:i:s")), $textInvoice);
|
||||
$textInvoice = str_replace('[[trx_date]]', Lang::dateTimeFormat(date("Y-m-d H:i:s")), $textInvoice);
|
||||
$textInvoice = str_replace('[[payment_gateway]]', $gateway, $textInvoice);
|
||||
$textInvoice = str_replace('[[payment_channel]]', $channel, $textInvoice);
|
||||
$textInvoice = str_replace('[[type]]', 'Balance', $textInvoice);
|
||||
$textInvoice = str_replace('[[plan_name]]', $plan['name_plan'], $textInvoice);
|
||||
$textInvoice = str_replace('[[plan_price]]', Lang::moneyFormat($plan['price']), $textInvoice);
|
||||
$textInvoice = str_replace('[[name]]', $customer['fullname'], $textInvoice);
|
||||
$textInvoice = str_replace('[[user_name]]', $customer['username'], $textInvoice);
|
||||
$textInvoice = str_replace('[[user_password]]', $customer['password'], $textInvoice);
|
||||
$textInvoice = str_replace('[[footer]]', $config['note'], $textInvoice);
|
||||
$textInvoice = str_replace('[[balance_before]]', Lang::moneyFormat($balance_before), $textInvoice);
|
||||
$textInvoice = str_replace('[[balance]]', Lang::moneyFormat($balance), $textInvoice);
|
||||
|
||||
if ($config['user_notification_payment'] == 'sms') {
|
||||
Message::sendSMS($customer['phonenumber'], $textInvoice);
|
||||
} else if ($config['user_notification_payment'] == 'wa') {
|
||||
Message::sendWhatsapp($customer['phonenumber'], $textInvoice);
|
||||
} else if ($config['user_notification_payment'] == 'email') {
|
||||
Message::sendEmail($customer['email'], '[' . $config['CompanyName'] . '] ' . Lang::T("Invoice") . ' ' . $inv, $textInvoice);
|
||||
}
|
||||
return $t->id();
|
||||
}
|
||||
|
||||
public static function rechargeCustomBalance($customer, $plan, $gateway, $channel, $note = '')
|
||||
{
|
||||
global $admin, $config;
|
||||
$plan = ORM::for_table('tbl_payment_gateway')
|
||||
->where('username', $customer['username'])
|
||||
->where('routers', 'Custom Balance')
|
||||
->where('status', '1')
|
||||
->find_one();
|
||||
if (!$plan) {
|
||||
return false;
|
||||
}
|
||||
// insert table transactions
|
||||
$t = ORM::for_table('tbl_transactions')->create();
|
||||
$t->invoice = $inv = "INV-" . Package::_raid();
|
||||
$t->username = $customer['username'];
|
||||
$t->user_id = $customer['id'];
|
||||
$t->plan_name = 'Custom Balance';
|
||||
$t->price = $plan['price'];
|
||||
$t->recharged_on = date("Y-m-d");
|
||||
$t->recharged_time = date("H:i:s");
|
||||
$t->expiration = date("Y-m-d");
|
||||
$t->time = date("H:i:s");
|
||||
$t->method = "$gateway - $channel";
|
||||
$t->routers = 'balance';
|
||||
$t->type = "Balance";
|
||||
$t->note = $note;
|
||||
if ($admin) {
|
||||
$t->admin_id = ($admin['id']) ? $admin['id'] : '0';
|
||||
} else {
|
||||
$t->admin_id = '0';
|
||||
}
|
||||
$t->save();
|
||||
|
||||
$balance_before = $customer['balance'];
|
||||
Balance::plus($customer['id'], $plan['price']);
|
||||
$balance = $customer['balance'] + $plan['price'];
|
||||
|
||||
$textInvoice = Lang::getNotifText('invoice_balance');
|
||||
$textInvoice = str_replace('[[company_name]]', $config['CompanyName'], $textInvoice);
|
||||
$textInvoice = str_replace('[[address]]', $config['address'], $textInvoice);
|
||||
$textInvoice = str_replace('[[phone]]', $config['phone'], $textInvoice);
|
||||
$textInvoice = str_replace('[[invoice]]', $inv, $textInvoice);
|
||||
$textInvoice = str_replace('[[date]]', Lang::dateTimeFormat(date("Y-m-d H:i:s")), $textInvoice);
|
||||
$textInvoice = str_replace('[[trx_date]]', Lang::dateTimeFormat(date("Y-m-d H:i:s")), $textInvoice);
|
||||
$textInvoice = str_replace('[[payment_gateway]]', $gateway, $textInvoice);
|
||||
$textInvoice = str_replace('[[payment_channel]]', $channel, $textInvoice);
|
||||
$textInvoice = str_replace('[[type]]', 'Balance', $textInvoice);
|
||||
$textInvoice = str_replace('[[plan_name]]', $plan['name_plan'], $textInvoice);
|
||||
$textInvoice = str_replace('[[plan_price]]', Lang::moneyFormat($plan['price']), $textInvoice);
|
||||
$textInvoice = str_replace('[[name]]', $customer['fullname'], $textInvoice);
|
||||
$textInvoice = str_replace('[[user_name]]', $customer['username'], $textInvoice);
|
||||
$textInvoice = str_replace('[[user_password]]', $customer['password'], $textInvoice);
|
||||
$textInvoice = str_replace('[[footer]]', $config['note'], $textInvoice);
|
||||
$textInvoice = str_replace('[[balance_before]]', Lang::moneyFormat($balance_before), $textInvoice);
|
||||
$textInvoice = str_replace('[[balance]]', Lang::moneyFormat($balance), $textInvoice);
|
||||
|
||||
if ($config['user_notification_payment'] == 'sms') {
|
||||
Message::sendSMS($customer['phonenumber'], $textInvoice);
|
||||
} else if ($config['user_notification_payment'] == 'wa') {
|
||||
Message::sendWhatsapp($customer['phonenumber'], $textInvoice);
|
||||
} else if ($config['user_notification_payment'] == 'email') {
|
||||
Message::sendEmail($customer['email'], '[' . $config['CompanyName'] . '] ' . Lang::T("Invoice") . ' ' . $inv, $textInvoice);
|
||||
}
|
||||
return $t->id();
|
||||
}
|
||||
|
||||
public static function _raid()
|
||||
{
|
||||
return ORM::for_table('tbl_transactions')->max('id') + 1;
|
||||
|
@ -10,15 +10,16 @@ class Paginator
|
||||
{
|
||||
public static function findMany($query, $search = [], $per_page = '10', $append_url = "", $toArray = false)
|
||||
{
|
||||
global $routes, $ui;
|
||||
global $routes, $ui, $isApi;
|
||||
$adjacents = "2";
|
||||
$page = _get('p', 1);
|
||||
$page = (empty($page) ? 1 : $page);
|
||||
$url = U . implode('/', $routes);
|
||||
$url = getUrl(implode('/', $routes));
|
||||
if (count($search) > 0) {
|
||||
$url .= '&' . http_build_query($search);
|
||||
}
|
||||
$url .= $append_url.'&p=';
|
||||
$url = Text::fixUrl($url);
|
||||
$totalReq = $query->count();
|
||||
$lastpage = ceil($totalReq / $per_page);
|
||||
$lpm1 = $lastpage - 1;
|
||||
@ -71,7 +72,7 @@ class Paginator
|
||||
if ($ui) {
|
||||
$ui->assign('paginator', $result);
|
||||
}
|
||||
if($toArray){
|
||||
if($toArray || $isApi){
|
||||
return $query->offset($startpoint)->limit($per_page)->find_array();
|
||||
}else{
|
||||
return $query->offset($startpoint)->limit($per_page)->find_many();
|
||||
@ -83,7 +84,7 @@ class Paginator
|
||||
{
|
||||
global $routes;
|
||||
global $_L;
|
||||
$url = U . implode('/', $routes);
|
||||
$url = getUrl(implode('/', $routes));
|
||||
$query = urlencode($query);
|
||||
$adjacents = "2";
|
||||
$page = (int)(empty(_get('p')) ? 1 : _get('p'));
|
||||
@ -169,7 +170,7 @@ class Paginator
|
||||
{
|
||||
global $routes;
|
||||
global $_L;
|
||||
$url = U . $routes['0'] . '/' . $routes['1'] . '/';
|
||||
$url = getUrl($routes['0'] . '/' . $routes['1'] . '/');
|
||||
$adjacents = "2";
|
||||
$page = (int)(!isset($routes['2']) ? 1 : $routes['2']);
|
||||
$pagination = "";
|
||||
@ -277,7 +278,7 @@ class Paginator
|
||||
{
|
||||
global $routes;
|
||||
global $_L;
|
||||
$url = U . $routes['0'] . '/' . $routes['1'] . '/';
|
||||
$url = getUrl($routes['0'] . '/' . $routes['1'] . '/');
|
||||
$adjacents = "2";
|
||||
$page = (int)(!isset($routes['2']) ? 1 : $routes['2']);
|
||||
$pagination = "";
|
||||
|
@ -109,4 +109,44 @@ class Text
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* ...$data means it can take any number of arguments.
|
||||
* it can url($var1, $var2, $var3) or url($var1)
|
||||
* and variable will be merge with implode
|
||||
* @return string the URL with all the arguments combined.
|
||||
*/
|
||||
public static function url(...$data){
|
||||
global $config;
|
||||
$url = implode("", $data);
|
||||
if ($config['url_canonical'] == 'yes') {
|
||||
$u = str_replace('?_route=', '', U);
|
||||
$pos = strpos($url, '&');
|
||||
if ($pos === false) {
|
||||
return $u . $url;
|
||||
} else {
|
||||
return $u . substr($url, 0, $pos) . '?' . substr($url, $pos + 1);
|
||||
}
|
||||
} else {
|
||||
return U . $url;
|
||||
}
|
||||
}
|
||||
|
||||
public static function fixUrl($url){
|
||||
//if url dont have ? then add it with replace first & to ?
|
||||
if(strpos($url, '?') === false && strpos($url, '&')!== false){
|
||||
return substr($url, 0, strpos($url, '&')). '?'. substr($url, strpos($url, '&')+1);
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
// this will return & or ?
|
||||
public static function isQA(){
|
||||
global $config;
|
||||
if ($config['url_canonical'] == 'yes') {
|
||||
return '?';
|
||||
} else {
|
||||
return '&';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,15 @@ class User
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function getTawkToHash($email)
|
||||
{
|
||||
global $config;
|
||||
if (!empty($config['tawkto_api_key']) && !empty($email)) {
|
||||
return hash_hmac('sha256', $email, $config['tawkto_api_key']);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
public static function getBills($id = 0)
|
||||
{
|
||||
if (!$id) {
|
||||
@ -157,19 +166,38 @@ class User
|
||||
return [];
|
||||
}
|
||||
|
||||
public static function generateToken($uid, $validDays = 30)
|
||||
{
|
||||
global $db_pass;
|
||||
if ($validDays >= 30) {
|
||||
$time = time();
|
||||
} else {
|
||||
// for customer, deafult expired is 30 days
|
||||
$time = strtotime('+ ' . (30 - $validDays) . ' days');
|
||||
}
|
||||
|
||||
return [
|
||||
'time' => $time,
|
||||
'token' => $uid . '.' . $time . '.' . sha1($uid . '.' . $time . '.' . $db_pass)
|
||||
];
|
||||
}
|
||||
|
||||
public static function setCookie($uid)
|
||||
{
|
||||
global $db_pass;
|
||||
if (isset($uid)) {
|
||||
$time = time();
|
||||
setcookie('uid', $uid . '.' . $time . '.' . sha1($uid . '.' . $time . '.' . $db_pass), time() + 86400 * 30);
|
||||
$token = self::generateToken($uid);
|
||||
setcookie('uid', $token['token'], time() + 86400 * 30, "/");
|
||||
return $token;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function removeCookie()
|
||||
{
|
||||
if (isset($_COOKIE['uid'])) {
|
||||
setcookie('uid', '', time() - 86400);
|
||||
setcookie('uid', '', time() - 86400, "/");
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,7 +206,7 @@ class User
|
||||
global $config;
|
||||
if ($config['maintenance_mode'] == true) {
|
||||
if ($config['maintenance_mode_logout'] == true) {
|
||||
r2(U . 'logout', 'd', '');
|
||||
r2(getUrl('logout'), 'd', '');
|
||||
} else {
|
||||
displayMaintenanceMessage();
|
||||
}
|
||||
@ -190,13 +218,28 @@ class User
|
||||
if ($d['status'] == 'Banned') {
|
||||
_alert(Lang::T('This account status') . ' : ' . Lang::T($d['status']), 'danger', "logout");
|
||||
}
|
||||
if (empty($d['username'])) {
|
||||
r2(U . 'logout', 'd', '');
|
||||
return $d;
|
||||
}
|
||||
|
||||
public static function _infoByName($username)
|
||||
{
|
||||
global $config;
|
||||
if ($config['maintenance_mode'] == true) {
|
||||
if ($config['maintenance_mode_logout'] == true) {
|
||||
r2(getUrl('logout'), 'd', '');
|
||||
} else {
|
||||
displayMaintenanceMessage();
|
||||
}
|
||||
}
|
||||
$d = ORM::for_table('tbl_customers')->where("username", $username)->find_one();
|
||||
if ($d['status'] == 'Banned') {
|
||||
_alert(Lang::T('This account status') . ' : ' . Lang::T($d['status']), 'danger', "logout");
|
||||
}
|
||||
return $d;
|
||||
}
|
||||
|
||||
public static function isUserVoucher($kode) {
|
||||
public static function isUserVoucher($kode)
|
||||
{
|
||||
$regex = '/^GC\d+C.{10}$/';
|
||||
return preg_match($regex, $kode);
|
||||
}
|
||||
@ -209,16 +252,78 @@ class User
|
||||
$d = ORM::for_table('tbl_user_recharges')
|
||||
->select('tbl_user_recharges.id', 'id')
|
||||
->selects([
|
||||
'customer_id', 'username', 'plan_id', 'namebp', 'recharged_on', 'recharged_time', 'expiration', 'time',
|
||||
'status', 'method', 'plan_type', 'name_bw',
|
||||
'customer_id',
|
||||
'username',
|
||||
'plan_id',
|
||||
'namebp',
|
||||
'recharged_on',
|
||||
'recharged_time',
|
||||
'expiration',
|
||||
'time',
|
||||
'status',
|
||||
'method',
|
||||
'plan_type',
|
||||
['tbl_user_recharges.routers', 'routers'],
|
||||
['tbl_user_recharges.type', 'type'],
|
||||
'admin_id', 'prepaid'
|
||||
'admin_id',
|
||||
'prepaid'
|
||||
])
|
||||
->left_outer_join('tbl_plans', ['tbl_plans.id', '=', 'tbl_user_recharges.plan_id'])
|
||||
->left_outer_join('tbl_bandwidth', ['tbl_bandwidth.id', '=', 'tbl_plans.id_bw'])
|
||||
->select('tbl_bandwidth.name_bw', 'name_bw')
|
||||
->select('tbl_plans.price', 'price')
|
||||
->where('customer_id', $id)
|
||||
->left_outer_join('tbl_plans', array('tbl_plans.id', '=', 'tbl_user_recharges.plan_id'))
|
||||
->left_outer_join('tbl_bandwidth', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))
|
||||
->find_many();
|
||||
return $d;
|
||||
}
|
||||
|
||||
public static function setFormCustomField($uid = 0)
|
||||
{
|
||||
global $UPLOAD_PATH;
|
||||
$fieldPath = $UPLOAD_PATH . DIRECTORY_SEPARATOR . "customer_field.json";
|
||||
if (!file_exists($fieldPath)) {
|
||||
return '';
|
||||
}
|
||||
$fields = json_decode(file_get_contents($fieldPath), true);
|
||||
foreach ($fields as $field) {
|
||||
if (!empty(_post($field['name']))) {
|
||||
self::setAttribute($field['name'], _post($field['name']), $uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function getFormCustomField($ui, $register = false, $uid = 0)
|
||||
{
|
||||
global $UPLOAD_PATH;
|
||||
$fieldPath = $UPLOAD_PATH . DIRECTORY_SEPARATOR . "customer_field.json";
|
||||
if (!file_exists($fieldPath)) {
|
||||
return '';
|
||||
}
|
||||
$fields = json_decode(file_get_contents($fieldPath), true);
|
||||
$attrs = [];
|
||||
if (!$register) {
|
||||
$attrs = self::getAttributes('', $uid);
|
||||
$ui->assign('attrs', $attrs);
|
||||
}
|
||||
$html = '';
|
||||
$ui->assign('register', $register);
|
||||
foreach ($fields as $field) {
|
||||
if ($register) {
|
||||
if ($field['register']) {
|
||||
$ui->assign('field', $field);
|
||||
$html .= $ui->fetch('customer/custom_field.tpl');
|
||||
}
|
||||
} else {
|
||||
$ui->assign('field', $field);
|
||||
$html .= $ui->fetch('customer/custom_field.tpl');
|
||||
}
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
public static function find($id)
|
||||
{
|
||||
return ORM::for_table('tbl_customers')->find_one($id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
50
system/autoload/Widget.php
Normal file
50
system/autoload/Widget.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
**/
|
||||
|
||||
|
||||
/**
|
||||
* Validator class
|
||||
*/
|
||||
class Widget
|
||||
{
|
||||
|
||||
public static function rows($rows, $result){
|
||||
$result .= '<div class="row">';
|
||||
foreach($rows as $row){
|
||||
|
||||
}
|
||||
$result .= '</div>';
|
||||
}
|
||||
|
||||
public static function columns($cols, $result){
|
||||
$c = count($cols);
|
||||
switch($c){
|
||||
case 1:
|
||||
$result .= '<div class="col-md-12">';
|
||||
break;
|
||||
case 2:
|
||||
$result .= '<div class="col-md-6">';
|
||||
break;
|
||||
case 3:
|
||||
$result .= '<div class="col-md-4">';
|
||||
break;
|
||||
case 4:
|
||||
$result .= '<div class="col-md-4">';
|
||||
break;
|
||||
case 5:
|
||||
$result .= '<div class="col-md-4">';
|
||||
break;
|
||||
default:
|
||||
$result .= '<div class="col-md-1">';
|
||||
break;
|
||||
}
|
||||
|
||||
foreach($cols as $col){
|
||||
}
|
||||
$result .= '</div>';
|
||||
}
|
||||
}
|
@ -67,20 +67,28 @@ if (isset($_SESSION['notify'])) {
|
||||
unset($_SESSION['ntype']);
|
||||
}
|
||||
|
||||
if(!isset($_GET['_route'])) {
|
||||
$req = ltrim(parse_url($_SERVER['REQUEST_URI'])['path'], '/');
|
||||
}else{
|
||||
if (!isset($_GET['_route'])) {
|
||||
$req = ltrim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/');
|
||||
$len = strlen(ltrim(parse_url(APP_URL, PHP_URL_PATH), '/'));
|
||||
if ($len > 0) {
|
||||
$req = ltrim(substr($req, $len), '/');
|
||||
}
|
||||
} else {
|
||||
// Routing Engine
|
||||
$req = _get('_route');
|
||||
}
|
||||
|
||||
$routes = explode('/', $req);
|
||||
$ui->assign('_routes', $routes);
|
||||
$handler = $routes[0];
|
||||
if ($handler == '') {
|
||||
$handler = 'default';
|
||||
}
|
||||
$admin = Admin::_info();
|
||||
try {
|
||||
if (!empty($_GET['uid'])) {
|
||||
$_COOKIE['uid'] = $_GET['uid'];
|
||||
}
|
||||
$admin = Admin::_info();
|
||||
$sys_render = $root_path . File::pathFixer('system/controllers/' . $handler . '.php');
|
||||
if (file_exists($sys_render)) {
|
||||
$menus = array();
|
||||
@ -92,7 +100,7 @@ try {
|
||||
foreach ($menu_registered as $menu) {
|
||||
if ($menu['admin'] && _admin(false)) {
|
||||
if (count($menu['auth']) == 0 || in_array($admin['user_type'], $menu['auth'])) {
|
||||
$menus[$menu['position']] .= '<li' . (($routes[1] == $menu['function']) ? ' class="active"' : '') . '><a href="' . U . 'plugin/' . $menu['function'] . '">';
|
||||
$menus[$menu['position']] .= '<li' . (($routes[1] == $menu['function']) ? ' class="active"' : '') . '><a href="' . getUrl('plugin/' . $menu['function']) . '">';
|
||||
if (!empty($menu['icon'])) {
|
||||
$menus[$menu['position']] .= '<i class="' . $menu['icon'] . '"></i>';
|
||||
}
|
||||
@ -103,7 +111,7 @@ try {
|
||||
$menus[$menu['position']] .= '<span class="text">' . $menu['name'] . '</span></a></li>';
|
||||
}
|
||||
} else if (!$menu['admin'] && _auth(false)) {
|
||||
$menus[$menu['position']] .= '<li' . (($routes[1] == $menu['function']) ? ' class="active"' : '') . '><a href="' . U . 'plugin/' . $menu['function'] . '">';
|
||||
$menus[$menu['position']] .= '<li' . (($routes[1] == $menu['function']) ? ' class="active"' : '') . '><a href="' . getUrl('plugin/' . $menu['function']) . '">';
|
||||
if (!empty($menu['icon'])) {
|
||||
$menus[$menu['position']] .= '<i class="' . $menu['icon'] . '"></i>';
|
||||
}
|
||||
@ -120,7 +128,15 @@ try {
|
||||
unset($menus, $menu_registered);
|
||||
include($sys_render);
|
||||
} else {
|
||||
r2(U . 'dashboard', 'e', 'not found');
|
||||
if( empty($_SERVER["HTTP_SEC_FETCH_DEST"]) || $_SERVER["HTTP_SEC_FETCH_DEST"] != 'document' ){
|
||||
// header 404
|
||||
header("HTTP/1.0 404 Not Found");
|
||||
header("Content-Type: text/html; charset=utf-8");
|
||||
echo "404 Not Found";
|
||||
die();
|
||||
}else{
|
||||
r2(getUrl('login'));
|
||||
}
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
Message::sendTelegram(
|
||||
@ -128,12 +144,13 @@ try {
|
||||
$e->getMessage() . "\n" .
|
||||
$e->getTraceAsString()
|
||||
);
|
||||
if (!Admin::getID()) {
|
||||
r2(U . 'home', 'e', $e->getMessage());
|
||||
if (empty($_SESSION['aid'])) {
|
||||
$ui->display('customer/error.tpl');
|
||||
die();
|
||||
}
|
||||
$ui->assign("error_message", $e->getMessage() . '<br><pre>' . $e->getTraceAsString() . '</pre>');
|
||||
$ui->assign("error_title", "PHPNuxBill Crash");
|
||||
$ui->display('router-error.tpl');
|
||||
$ui->display('admin/error.tpl');
|
||||
die();
|
||||
} catch (Exception $e) {
|
||||
Message::sendTelegram(
|
||||
@ -141,11 +158,12 @@ try {
|
||||
$e->getMessage() . "\n" .
|
||||
$e->getTraceAsString()
|
||||
);
|
||||
if (!Admin::getID()) {
|
||||
r2(U . 'home', 'e', $e->getMessage());
|
||||
if (empty($_SESSION['aid'])) {
|
||||
$ui->display('customer/error.tpl');
|
||||
die();
|
||||
}
|
||||
$ui->assign("error_message", $e->getMessage() . '<br><pre>' . $e->getTraceAsString() . '</pre>');
|
||||
$ui->assign("error_title", "PHPNuxBill Crash");
|
||||
$ui->display('router-error.tpl');
|
||||
$ui->display('admin/error.tpl');
|
||||
die();
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"require": {
|
||||
"mpdf/mpdf": "^8.1",
|
||||
"smarty/smarty": "=4.5.3"
|
||||
"smarty/smarty": "=4.5.3",
|
||||
"yosiazwan/php-facedetection": "^0.1.0"
|
||||
}
|
||||
}
|
||||
|
44
system/composer.lock
generated
44
system/composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "a33a5e0440af423877195440decefd29",
|
||||
"content-hash": "a5f201dce3d594a500f2b9e9a8532e66",
|
||||
"packages": [
|
||||
{
|
||||
"name": "mpdf/mpdf",
|
||||
@ -476,6 +476,48 @@
|
||||
"source": "https://github.com/smarty-php/smarty/tree/v4.5.3"
|
||||
},
|
||||
"time": "2024-05-28T21:46:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "yosiazwan/php-facedetection",
|
||||
"version": "0.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/yosiazwan/php-facedetection.git",
|
||||
"reference": "b016273ceceacd85562bbc50384fbabc947fe525"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/yosiazwan/php-facedetection/zipball/b016273ceceacd85562bbc50384fbabc947fe525",
|
||||
"reference": "b016273ceceacd85562bbc50384fbabc947fe525",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-gd": "*",
|
||||
"php": ">=5.2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"FaceDetector.php",
|
||||
"Exception/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"GPL-2.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Maurice Svay",
|
||||
"homepage": "https://github.com/mauricesvay/php-facedetection/graphs/contributors"
|
||||
}
|
||||
],
|
||||
"description": "PHP class to detect one face in images. A pure PHP port of an existing JS code from Karthik Tharavad.",
|
||||
"homepage": "https://github.com/mauricesvay/php-facedetection",
|
||||
"support": {
|
||||
"source": "https://github.com/yosiazwan/php-facedetection/tree/0.1.0"
|
||||
},
|
||||
"time": "2016-01-26T22:10:00+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
|
@ -18,11 +18,17 @@ switch ($action) {
|
||||
|
||||
case 'change-password':
|
||||
run_hook('customer_view_change_password'); #HOOK
|
||||
$ui->display('user-ui/change-password.tpl');
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->display('customer/change-password.tpl');
|
||||
break;
|
||||
|
||||
case 'change-password-post':
|
||||
$password = _post('password');
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('accounts/change-password'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
run_hook('customer_change_password'); #HOOK
|
||||
if ($password != '') {
|
||||
$d_pass = $user['password'];
|
||||
@ -30,10 +36,10 @@ switch ($action) {
|
||||
$cnpass = _post('cnpass');
|
||||
if ($password == $d_pass) {
|
||||
if (!Validator::Length($password, 36, 2)) {
|
||||
r2(U . 'accounts/change-password', 'e', 'New Password must be 2 to 35 character');
|
||||
r2(getUrl('accounts/change-password'), 'e', 'New Password must be 2 to 35 character');
|
||||
}
|
||||
if ($npass != $cnpass) {
|
||||
r2(U . 'accounts/change-password', 'e', 'Both Password should be same');
|
||||
r2(getUrl('accounts/change-password'), 'e', 'Both Password should be same');
|
||||
}
|
||||
$user->password = $npass;
|
||||
$turs = ORM::for_table('tbl_user_recharges')->where('customer_id', $user['id'])->find_many();
|
||||
@ -58,19 +64,25 @@ switch ($action) {
|
||||
_log('[' . $user['username'] . ']: Password changed successfully', 'User', $user['id']);
|
||||
_alert(Lang::T('Password changed successfully, Please login again'), 'success', "login");
|
||||
} else {
|
||||
die($password);
|
||||
r2(U . 'accounts/change-password', 'e', Lang::T('Incorrect Current Password'));
|
||||
r2(getUrl('accounts/change-password'), 'e', Lang::T('Incorrect Current Password'));
|
||||
}
|
||||
} else {
|
||||
r2(U . 'accounts/change-password', 'e', Lang::T('Incorrect Current Password'));
|
||||
r2(getUrl('accounts/change-password'), 'e', Lang::T('Incorrect Current Password'));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'profile':
|
||||
run_hook('customer_view_edit_profile'); #HOOK
|
||||
$ui->display('user-ui/profile.tpl');
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->assign('customFields', User::getFormCustomField($ui, false, $user['id']));
|
||||
$ui->display('customer/profile.tpl');
|
||||
break;
|
||||
case 'edit-profile-post':
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('accounts/profile'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$fullname = _post('fullname');
|
||||
$address = _post('address');
|
||||
$email = _post('email');
|
||||
@ -84,44 +96,105 @@ switch ($action) {
|
||||
$msg .= 'Phone Number must be a number' . '<br>';
|
||||
}
|
||||
|
||||
$user->fullname = $fullname;
|
||||
$user->address = $address;
|
||||
if ($_c['allow_phone_otp'] != 'yes') {
|
||||
$user->phonenumber = $phonenumber;
|
||||
}
|
||||
if ($_c['allow_email_otp'] != 'yes') {
|
||||
$user->email = $email;
|
||||
}
|
||||
if (empty($msg)) {
|
||||
if (!empty($_FILES['photo']['name']) && file_exists($_FILES['photo']['tmp_name'])) {
|
||||
if (function_exists('imagecreatetruecolor')) {
|
||||
$hash = md5_file($_FILES['photo']['tmp_name']);
|
||||
$subfolder = substr($hash, 0, 2);
|
||||
$folder = $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'photos' . DIRECTORY_SEPARATOR;
|
||||
if (!file_exists($folder)) {
|
||||
mkdir($folder);
|
||||
}
|
||||
$folder = $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'photos' . DIRECTORY_SEPARATOR . $subfolder . DIRECTORY_SEPARATOR;
|
||||
if (!file_exists($folder)) {
|
||||
mkdir($folder);
|
||||
}
|
||||
$imgPath = $folder . $hash . '.jpg';
|
||||
if (!file_exists($imgPath)) {
|
||||
File::resizeCropImage($_FILES['photo']['tmp_name'], $imgPath, 1600, 1600, 100);
|
||||
}
|
||||
if (!file_exists($imgPath . '.thumb.jpg')) {
|
||||
if (_post('faceDetect') == 'yes') {
|
||||
try {
|
||||
$detector = new svay\FaceDetector();
|
||||
$detector->setTimeout(5000);
|
||||
$detector->faceDetect($imgPath);
|
||||
$detector->cropFaceToJpeg($imgPath . '.thumb.jpg', false);
|
||||
} catch (Exception $e) {
|
||||
File::makeThumb($imgPath, $imgPath . '.thumb.jpg', 200);
|
||||
} catch (Throwable $e) {
|
||||
File::makeThumb($imgPath, $imgPath . '.thumb.jpg', 200);
|
||||
}
|
||||
} else {
|
||||
File::makeThumb($imgPath, $imgPath . '.thumb.jpg', 200);
|
||||
}
|
||||
}
|
||||
if (file_exists($imgPath)) {
|
||||
if ($user['photo'] != '' && strpos($user['photo'], 'default') === false) {
|
||||
if (file_exists($UPLOAD_PATH . $user['photo'])) {
|
||||
unlink($UPLOAD_PATH . $user['photo']);
|
||||
if (file_exists($UPLOAD_PATH . $user['photo'] . '.thumb.jpg')) {
|
||||
unlink($UPLOAD_PATH . $user['photo'] . '.thumb.jpg');
|
||||
}
|
||||
}
|
||||
}
|
||||
$user->photo = '/photos/' . $subfolder . '/' . $hash . '.jpg';
|
||||
}
|
||||
if (file_exists($_FILES['photo']['tmp_name'])) unlink($_FILES['photo']['tmp_name']);
|
||||
} else {
|
||||
r2(getUrl('settings/app'), 'e', 'PHP GD is not installed');
|
||||
}
|
||||
}
|
||||
|
||||
$user->save();
|
||||
$user->fullname = $fullname;
|
||||
$user->address = $address;
|
||||
if ($_c['allow_phone_otp'] != 'yes') {
|
||||
$user->phonenumber = $phonenumber;
|
||||
}
|
||||
if ($_c['allow_email_otp'] != 'yes') {
|
||||
$user->email = $email;
|
||||
}
|
||||
|
||||
_log('[' . $user['username'] . ']: ' . Lang::T('User Updated Successfully'), 'User', $user['id']);
|
||||
r2(U . 'accounts/profile', 's', Lang::T('User Updated Successfully'));
|
||||
User::setFormCustomField($user['id']);
|
||||
|
||||
$user->save();
|
||||
|
||||
_log('[' . $user['username'] . ']: ' . Lang::T('User Updated Successfully'), 'User', $user['id']);
|
||||
r2(getUrl('accounts/profile'), 's', Lang::T('User Updated Successfully'));
|
||||
}else{
|
||||
r2(getUrl('accounts/profile'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'phone-update':
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->assign('new_phone', $_SESSION['new_phone']);
|
||||
$ui->display('user-ui/phone-update.tpl');
|
||||
$ui->display('customer/phone-update.tpl');
|
||||
break;
|
||||
|
||||
case 'phone-update-otp':
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$phone = Lang::phoneFormat(_post('phone'));
|
||||
$username = $user['username'];
|
||||
$otpPath = $CACHE_PATH . '/sms/';
|
||||
$_SESSION['new_phone'] = $phone;
|
||||
// Validate the phone number format
|
||||
if (!preg_match('/^[0-9]{10,}$/', $phone) || empty($phone)) {
|
||||
r2(U . 'accounts/phone-update', 'e', Lang::T('Invalid phone number format'));
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Invalid phone number format'));
|
||||
}
|
||||
|
||||
if (empty($config['sms_url'])) {
|
||||
r2(U . 'accounts/phone-update', 'e', Lang::T('SMS server not Available, Please try again later'));
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('SMS server not Available, Please try again later'));
|
||||
}
|
||||
|
||||
$d = ORM::for_table('tbl_customers')->whereNotEqual('username', $username)->where('phonenumber', $phone)->find_one();
|
||||
if ($d) {
|
||||
r2(U . 'accounts/phone-update', 'e', Lang::T('Phone number already registered by another customer'));
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Phone number already registered by another customer'));
|
||||
}
|
||||
if (!file_exists($otpPath)) {
|
||||
mkdir($otpPath);
|
||||
@ -132,27 +205,31 @@ switch ($action) {
|
||||
|
||||
// expired 10 minutes
|
||||
if (file_exists($otpFile) && time() - filemtime($otpFile) < 600) {
|
||||
r2(U . 'accounts/phone-update', 'e', Lang::T('Please wait ') . (600 - (time() - filemtime($otpFile))) . Lang::T(' seconds before sending another SMS'));
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Please wait ') . (600 - (time() - filemtime($otpFile))) . Lang::T(' seconds before sending another SMS'));
|
||||
} else {
|
||||
$otp = rand(100000, 999999);
|
||||
file_put_contents($otpFile, $otp);
|
||||
file_put_contents($phoneFile, $phone);
|
||||
// send send OTP to user
|
||||
if ($config['phone_otp_type'] === 'sms') {
|
||||
Message::sendSMS($phone, $config['CompanyName'] . "\n Your Verification code is: $otp");
|
||||
Message::sendSMS($phone, $config['CompanyName'] . "\n\n" . Lang::T("Verification code") . "\n$otp");
|
||||
} elseif ($config['phone_otp_type'] === 'whatsapp') {
|
||||
Message::sendWhatsapp($phone, $config['CompanyName'] . "\n Your Verification code is: $otp");
|
||||
Message::sendWhatsapp($phone, $config['CompanyName'] . "\n\n" . Lang::T("Verification code") . "\n$otp");
|
||||
} elseif ($config['phone_otp_type'] === 'both') {
|
||||
Message::sendSMS($phone, $config['CompanyName'] . "\n Your Verification code is: $otp");
|
||||
Message::sendWhatsapp($phone, $config['CompanyName'] . "\n Your Verification code is: $otp");
|
||||
Message::sendSMS($phone, $config['CompanyName'] . "\n\n" . Lang::T("Verification code") . "\n$otp");
|
||||
Message::sendWhatsapp($phone, $config['CompanyName'] . "\n\n" . Lang::T("Verification code") . "\n$otp");
|
||||
}
|
||||
//redirect after sending OTP
|
||||
r2(U . 'accounts/phone-update', 'e', Lang::T('Verification code has been sent to your phone'));
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Verification code has been sent to your phone'));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'phone-update-post':
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$phone = Lang::phoneFormat(_post('phone'));
|
||||
$otp_code = _post('otp');
|
||||
$username = $user['username'];
|
||||
@ -160,11 +237,11 @@ switch ($action) {
|
||||
|
||||
// Validate the phone number format
|
||||
if (!preg_match('/^[0-9]{10,}$/', $phone)) {
|
||||
r2(U . 'accounts/phone-update', 'e', Lang::T('Invalid phone number format'));
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Invalid phone number format'));
|
||||
}
|
||||
|
||||
if (empty($config['sms_url'])) {
|
||||
r2(U . 'accounts/phone-update', 'e', Lang::T('SMS server not Available, Please try again later'));
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('SMS server not Available, Please try again later'));
|
||||
}
|
||||
|
||||
$otpFile = $otpPath . sha1($username . $db_pass) . ".txt";
|
||||
@ -172,7 +249,7 @@ switch ($action) {
|
||||
|
||||
// Check if OTP file exists
|
||||
if (!file_exists($otpFile)) {
|
||||
r2(U . 'accounts/phone-update', 'e', Lang::T('Please request OTP first'));
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Please request OTP first'));
|
||||
exit();
|
||||
}
|
||||
|
||||
@ -180,21 +257,21 @@ switch ($action) {
|
||||
if (time() - filemtime($otpFile) > 1200) {
|
||||
unlink($otpFile);
|
||||
unlink($phoneFile);
|
||||
r2(U . 'accounts/phone-update', 'e', Lang::T('Verification code expired'));
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Verification code expired'));
|
||||
exit();
|
||||
} else {
|
||||
$code = file_get_contents($otpFile);
|
||||
|
||||
// Check if OTP code matches
|
||||
if ($code != $otp_code) {
|
||||
r2(U . 'accounts/phone-update', 'e', Lang::T('Wrong Verification code'));
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('Wrong Verification code'));
|
||||
exit();
|
||||
}
|
||||
|
||||
// Check if the phone number matches the one that requested the OTP
|
||||
$savedPhone = file_get_contents($phoneFile);
|
||||
if ($savedPhone !== $phone) {
|
||||
r2(U . 'accounts/phone-update', 'e', Lang::T('The phone number does not match the one that requested the OTP'));
|
||||
r2(getUrl('accounts/phone-update'), 'e', Lang::T('The phone number does not match the one that requested the OTP'));
|
||||
exit();
|
||||
}
|
||||
|
||||
@ -207,30 +284,36 @@ switch ($action) {
|
||||
$user->phonenumber = Lang::phoneFormat($phone);
|
||||
$user->save();
|
||||
|
||||
r2(U . 'accounts/profile', 's', Lang::T('Phone number updated successfully'));
|
||||
r2(getUrl('accounts/profile'), 's', Lang::T('Phone number updated successfully'));
|
||||
break;
|
||||
|
||||
case 'email-update':
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->assign('new_email', $_SESSION['new_email']);
|
||||
$ui->display('user-ui/email-update.tpl');
|
||||
$ui->display('customer/email-update.tpl');
|
||||
break;
|
||||
case 'email-update-otp':
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$email = trim(_post('email'));
|
||||
$username = $user['username'];
|
||||
$otpPath = $CACHE_PATH . '/email/';
|
||||
$_SESSION['new_email'] = $email;
|
||||
// Validate the phone number format
|
||||
if (!Validator::Email($email)) {
|
||||
r2(U . 'accounts/email-update', 'e', Lang::T('Invalid Email address format'));
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('Invalid Email address format'));
|
||||
}
|
||||
|
||||
if (empty($config['smtp_host'])) {
|
||||
r2(U . 'accounts/email-update', 'e', Lang::T('Email server not Available, Please ask admin to configure it'));
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('Email server not Available, Please ask admin to configure it'));
|
||||
}
|
||||
|
||||
$d = ORM::for_table('tbl_customers')->whereNotEqual('username', $username)->where('email', $email)->find_one();
|
||||
if ($d) {
|
||||
r2(U . 'accounts/email-update', 'e', Lang::T('Email already used by another Customer'));
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('Email already used by another Customer'));
|
||||
}
|
||||
if (!file_exists($otpPath)) {
|
||||
mkdir($otpPath);
|
||||
@ -241,7 +324,7 @@ switch ($action) {
|
||||
|
||||
// expired 10 minutes
|
||||
if (file_exists($otpFile) && time() - filemtime($otpFile) < 600) {
|
||||
r2(U . 'accounts/email-update', 'e', Lang::T('Please wait ') . (600 - (time() - filemtime($otpFile))) . Lang::T(' seconds before sending another Email'));
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('Please wait ') . (600 - (time() - filemtime($otpFile))) . Lang::T(' seconds before sending another Email'));
|
||||
} else {
|
||||
$otp = rand(100000, 999999);
|
||||
file_put_contents($otpFile, $otp);
|
||||
@ -250,24 +333,28 @@ switch ($action) {
|
||||
$body = Lang::T("Hello") . ' ' . $user['fullname'] . ",\n\n" . Lang::T("Your Email Verification Code is:") . " $otp";
|
||||
Message::sendEmail($email, Lang::T('Change Email Verification Code'), $body);
|
||||
//redirect after sending OTP
|
||||
r2(U . 'accounts/email-update', 'e', Lang::T('Verification code has been sent to your email. Check Spam folder if not found.'));
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('Verification code has been sent to your email. Check Spam folder if not found.'));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'email-update-post':
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$email = trim(_post('email'));
|
||||
$otp_code = _post('otp');
|
||||
$username = $user['username'];
|
||||
$otpPath = $CACHE_PATH . '/email/';
|
||||
// Validate the phone number format
|
||||
if (!Validator::Email($email)) {
|
||||
r2(U . 'accounts/email-update', 'e', Lang::T('Invalid Email address format'));
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('Invalid Email address format'));
|
||||
exit();
|
||||
}
|
||||
|
||||
if (empty($config['smtp_host'])) {
|
||||
r2(U . 'accounts/email-update', 'e', Lang::T('Email server not Available, Please ask admin to configure it'));
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('Email server not Available, Please ask admin to configure it'));
|
||||
}
|
||||
|
||||
$otpFile = $otpPath . sha1($username . $db_pass) . ".txt";
|
||||
@ -275,7 +362,7 @@ switch ($action) {
|
||||
|
||||
// Check if OTP file exists
|
||||
if (!file_exists($otpFile)) {
|
||||
r2(U . 'accounts/email-update', 'e', Lang::T('Please request OTP first'));
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('Please request OTP first'));
|
||||
exit();
|
||||
}
|
||||
|
||||
@ -283,21 +370,21 @@ switch ($action) {
|
||||
if (time() - filemtime($otpFile) > 1200) {
|
||||
unlink($otpFile);
|
||||
unlink($emailFile);
|
||||
r2(U . 'accounts/email-update', 'e', Lang::T('Verification code expired'));
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('Verification code expired'));
|
||||
exit();
|
||||
} else {
|
||||
$code = file_get_contents($otpFile);
|
||||
|
||||
// Check if OTP code matches
|
||||
if ($code != $otp_code) {
|
||||
r2(U . 'accounts/email-update', 'e', Lang::T('Wrong Verification code'));
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('Wrong Verification code'));
|
||||
exit();
|
||||
}
|
||||
|
||||
// Check if the phone number matches the one that requested the OTP
|
||||
$savedEmail = file_get_contents($emailFile);
|
||||
if ($savedEmail !== $email) {
|
||||
r2(U . 'accounts/email-update', 'e', Lang::T('The Email Address does not match the one that requested the OTP'));
|
||||
r2(getUrl('accounts/email-update'), 'e', Lang::T('The Email Address does not match the one that requested the OTP'));
|
||||
exit();
|
||||
}
|
||||
|
||||
@ -309,7 +396,7 @@ switch ($action) {
|
||||
$user->email = $email;
|
||||
$user->save();
|
||||
|
||||
r2(U . 'accounts/profile', 's', Lang::T('Email Address updated successfully'));
|
||||
r2(getUrl('accounts/profile'), 's', Lang::T('Email Address updated successfully'));
|
||||
break;
|
||||
|
||||
case 'language-update-post':
|
||||
@ -322,10 +409,8 @@ switch ($action) {
|
||||
|
||||
if (file_exists($lan_file)) {
|
||||
$_L = json_decode(file_get_contents($lan_file), true);
|
||||
$_SESSION['Lang'] = $_L;
|
||||
} else {
|
||||
$_L['author'] = 'Auto Generated by iBNuX Script';
|
||||
$_SESSION['Lang'] = $_L;
|
||||
file_put_contents($lan_file, json_encode($_L));
|
||||
}
|
||||
User::setAttribute("Language", $selected_language);
|
||||
@ -335,5 +420,5 @@ switch ($action) {
|
||||
break;
|
||||
|
||||
default:
|
||||
$ui->display('a404.tpl');
|
||||
$ui->display('admin/404.tpl');
|
||||
}
|
||||
|
@ -5,8 +5,12 @@
|
||||
* by https://t.me/ibnux
|
||||
**/
|
||||
|
||||
if(Admin::getID()){
|
||||
r2(U.'dashboard', "s", Lang::T("You are already logged in"));
|
||||
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
|
||||
header("Expires: Tue, 01 Jan 2000 00:00:00 GMT");
|
||||
header("Pragma: no-cache");
|
||||
|
||||
if (Admin::getID()) {
|
||||
r2(getUrl('dashboard'), "s", Lang::T("You are already logged in"));
|
||||
}
|
||||
|
||||
if (isset($routes['1'])) {
|
||||
@ -19,6 +23,11 @@ switch ($do) {
|
||||
case 'post':
|
||||
$username = _post('username');
|
||||
$password = _post('password');
|
||||
//csrf token
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
_alert(Lang::T('Invalid or Expired CSRF Token') . ".", 'danger', "admin");
|
||||
}
|
||||
run_hook('admin_login'); #HOOK
|
||||
if ($username != '' and $password != '') {
|
||||
$d = ORM::for_table('tbl_users')->where('username', $username)->find_one();
|
||||
@ -32,26 +41,28 @@ switch ($do) {
|
||||
_log($username . ' ' . Lang::T('Login Successful'), $d['user_type'], $d['id']);
|
||||
if ($isApi) {
|
||||
if ($token) {
|
||||
showResult(true, Lang::T('Login Successful'), ['token' => "a.".$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");
|
||||
_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;
|
||||
default:
|
||||
run_hook('view_login'); #HOOK
|
||||
$ui->display('admin-login.tpl');
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->display('admin/admin/login.tpl');
|
||||
break;
|
||||
}
|
||||
|
@ -26,14 +26,25 @@ switch ($action) {
|
||||
}
|
||||
$ui->assign('routers', $routers);
|
||||
$ui->assign('d', $d);
|
||||
$ui->display('autoload-pool.tpl');
|
||||
$ui->display('admin/autoload/pool.tpl');
|
||||
break;
|
||||
|
||||
case 'bw_name':
|
||||
$bw = ORM::for_table('tbl_bandwidth')->select("name_bw")->find_one($routes['2']);
|
||||
echo $bw['name_bw'];
|
||||
die();
|
||||
case 'balance':
|
||||
$balance = ORM::for_table('tbl_customers')->select("balance")->find_one($routes['2'])['balance'];
|
||||
if ($routes['3'] == '1') {
|
||||
echo Lang::moneyFormat($balance);
|
||||
} else {
|
||||
echo $balance;
|
||||
}
|
||||
die();
|
||||
case 'server':
|
||||
$d = ORM::for_table('tbl_routers')->where('enabled', '1')->find_many();
|
||||
$ui->assign('d', $d);
|
||||
|
||||
$ui->display('autoload-server.tpl');
|
||||
$ui->display('admin/autoload/server.tpl');
|
||||
break;
|
||||
case 'pppoe_ip_used':
|
||||
if (!empty(_get('ip'))) {
|
||||
@ -65,32 +76,91 @@ switch ($action) {
|
||||
$server = _post('server');
|
||||
$jenis = _post('jenis');
|
||||
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();
|
||||
switch ($server) {
|
||||
case 'radius':
|
||||
$d = ORM::for_table('tbl_plans')->where('is_radius', 1)->where('type', $jenis)->find_many();
|
||||
break;
|
||||
case '':
|
||||
break;
|
||||
default:
|
||||
$d = ORM::for_table('tbl_plans')->where('routers', $server)->where('type', $jenis)->find_many();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
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();
|
||||
switch ($server) {
|
||||
case 'radius':
|
||||
$d = ORM::for_table('tbl_plans')->where('is_radius', 1)->where('type', $jenis)->find_many();
|
||||
break;
|
||||
case '':
|
||||
break;
|
||||
default:
|
||||
$d = ORM::for_table('tbl_plans')->where('routers', $server)->where('type', $jenis)->find_many();
|
||||
break;
|
||||
}
|
||||
}
|
||||
$ui->assign('d', $d);
|
||||
|
||||
$ui->display('autoload.tpl');
|
||||
$ui->display('admin/autoload/plan.tpl');
|
||||
break;
|
||||
case 'customer_is_active':
|
||||
$d = ORM::for_table('tbl_user_recharges')->where('customer_id', $routes['2'])->findOne();
|
||||
if ($d) {
|
||||
if ($d['status'] == 'on') {
|
||||
die('<span class="label label-success" title="Expired ' . Lang::dateAndTimeFormat($d['expiration'], $d['time']) . '">' . $d['namebp'] . '</span>');
|
||||
} else {
|
||||
die('<span class="label label-danger" title="Expired ' . Lang::dateAndTimeFormat($d['expiration'], $d['time']) . '">' . $d['namebp'] . '</span>');
|
||||
if ($config['check_customer_online'] == 'yes') {
|
||||
$c = ORM::for_table('tbl_customers')->where('username', $routes['2'])->find_one();
|
||||
$p = ORM::for_table('tbl_plans')->find_one($routes['3']);
|
||||
$dvc = Package::getDevice($p);
|
||||
if ($_app_stage != 'Demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
try {
|
||||
//don't wait more than 5 seconds for response from device, otherwise we get timeout error.
|
||||
ini_set('default_socket_timeout', 5);
|
||||
if ((new $p['device'])->online_customer($c, $p['routers'])) {
|
||||
echo '<span style="color: green;" title="online">•</span>';
|
||||
}else{
|
||||
echo '<span style="color: yellow;" title="offline">•</span>';
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
echo '<span style="color: red;" title="'.$e->getMessage().'">•</span>';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'plan_is_active':
|
||||
$ds = ORM::for_table('tbl_user_recharges')->where('customer_id', $routes['2'])->find_array();
|
||||
if ($ds) {
|
||||
$ps = [];
|
||||
$c = ORM::for_table('tbl_customers')->find_one($routes['2']);
|
||||
foreach ($ds as $d) {
|
||||
if ($d['status'] == 'on') {
|
||||
if ($config['check_customer_online'] == 'yes') {
|
||||
$p = ORM::for_table('tbl_plans')->find_one($d['plan_id']);
|
||||
$dvc = Package::getDevice($p);
|
||||
$status = "";
|
||||
if ($_app_stage != 'Demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
try {
|
||||
//don't wait more than 5 seconds for response from device, otherwise we get timeout error.
|
||||
ini_set('default_socket_timeout', 5);
|
||||
if ((new $p['device'])->online_customer($c, $p['routers'])) {
|
||||
$status = '<span style="color: green;" title="online">•</span>';
|
||||
}else{
|
||||
$status = '<span style="color: yellow;" title="offline">•</span>';
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$status = '<span style="color: red;" title="'.$e->getMessage().'">•</span>';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$ps[] = ('<span class="label label-primary m-1" title="Expired ' . Lang::dateAndTimeFormat($d['expiration'], $d['time']) . '">' . $d['namebp'] . ' ' . $status . '</span>');
|
||||
} else {
|
||||
$ps[] = ('<span class="label label-danger m-1" title="Expired ' . Lang::dateAndTimeFormat($d['expiration'], $d['time']) . '">' . $d['namebp'] . '</span>');
|
||||
}
|
||||
}
|
||||
echo implode("<br>", $ps);
|
||||
} else {
|
||||
die('<span class="label label-danger">•</span>');
|
||||
die('');
|
||||
}
|
||||
break;
|
||||
case 'customer_select2':
|
||||
@ -111,5 +181,5 @@ switch ($action) {
|
||||
echo json_encode(['results' => $json]);
|
||||
die();
|
||||
default:
|
||||
$ui->display('a404.tpl');
|
||||
$ui->display('admin/404.tpl');
|
||||
}
|
||||
|
@ -25,10 +25,10 @@ switch ($action) {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
if ((new $p['device'])->online_customer($user, $bill['routers'])) {
|
||||
die('<a href="' . U . 'home&mikrotik=logout&id=' . $bill['id'] . '" onclick="return confirm(\'' . Lang::T('Disconnect Internet?') . '\')" class="btn btn-success btn-xs btn-block">' . Lang::T('You are Online, Logout?') . '</a>');
|
||||
die('<a href="' . getUrl('home&mikrotik=logout&id=' . $bill['id']) . '" onclick="return confirm(\'' . Lang::T('Disconnect Internet?') . '\')" class="btn btn-success btn-xs btn-block">' . Lang::T('You are Online, Logout?') . '</a>');
|
||||
} else {
|
||||
if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'])) {
|
||||
die('<a href="' . U . 'home&mikrotik=login&id=' . $bill['id'] . '" onclick="return confirm(\'' . Lang::T('Connect to Internet?') . '\')" class="btn btn-danger btn-xs btn-block">' . Lang::T('Not Online, Login now?') . '</a>');
|
||||
die('<a href="' . getUrl('home&mikrotik=login&id=' . $bill['id']) . '" onclick="return confirm(\'' . Lang::T('Connect to Internet?') . '\')" class="btn btn-danger btn-xs btn-block">' . Lang::T('Not Online, Login now?') . '</a>');
|
||||
} else {
|
||||
die(Lang::T('-'));
|
||||
}
|
||||
@ -45,6 +45,10 @@ switch ($action) {
|
||||
die('--');
|
||||
}
|
||||
break;
|
||||
case 'bw_name':
|
||||
$bw = ORM::for_table('tbl_bandwidth')->select("name_bw")->find_one($routes['2']);
|
||||
echo $bw['name_bw'];
|
||||
die();
|
||||
case 'inbox_unread':
|
||||
$count = ORM::for_table('tbl_customers_inbox')->where('customer_id', $user['id'])->whereRaw('date_read is null')->count('id');
|
||||
if ($count > 0) {
|
||||
@ -54,7 +58,7 @@ switch ($action) {
|
||||
case 'inbox':
|
||||
$inboxs = ORM::for_table('tbl_customers_inbox')->selects(['id', 'subject', 'date_created'])->where('customer_id', $user['id'])->whereRaw('date_read is null')->order_by_desc('date_created')->limit(10)->find_many();
|
||||
foreach ($inboxs as $inbox) {
|
||||
echo '<li><a href="' . U . 'mail/view/' . $inbox['id'] . '">' . $inbox['subject'] . '<br><sub class="text-muted">' . Lang::dateTimeFormat($inbox['date_created']) . '</sub></a></li>';
|
||||
echo '<li><a href="' . getUrl('mail/view/' . $inbox['id']) . '">' . $inbox['subject'] . '<br><sub class="text-muted">' . Lang::dateTimeFormat($inbox['date_created']) . '</sub></a></li>';
|
||||
}
|
||||
die();
|
||||
case 'language':
|
||||
@ -65,7 +69,7 @@ switch ($action) {
|
||||
if (is_file('system/lan/' . $file) && !in_array($file, ['index.html', 'country.json', '.DS_Store'])) {
|
||||
$file = str_replace(".json", "", $file);
|
||||
if(!empty($file)){
|
||||
echo '<li><a href="' . U . 'accounts/language-update-post&lang=' . $file. '">';
|
||||
echo '<li><a href="' . getUrl('accounts/language-update-post&lang=' . $file) . '">';
|
||||
if($select == $file){
|
||||
echo '<span class="glyphicon glyphicon-ok"></span> ';
|
||||
}
|
||||
@ -75,5 +79,5 @@ switch ($action) {
|
||||
}
|
||||
die();
|
||||
default:
|
||||
$ui->display('404.tpl');
|
||||
die();
|
||||
}
|
||||
|
@ -13,12 +13,11 @@ $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(getUrl('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>');
|
||||
run_hook('view_list_bandwidth'); #HOOK
|
||||
$name = _post('name');
|
||||
if ($name != '') {
|
||||
@ -30,7 +29,7 @@ switch ($action) {
|
||||
}
|
||||
|
||||
$ui->assign('d', $d);
|
||||
$ui->display('bandwidth.tpl');
|
||||
$ui->display('admin/bandwidth/list.tpl');
|
||||
break;
|
||||
|
||||
case 'add':
|
||||
@ -38,7 +37,7 @@ switch ($action) {
|
||||
_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');
|
||||
$ui->display('admin/bandwidth/add.tpl');
|
||||
break;
|
||||
|
||||
case 'edit':
|
||||
@ -51,9 +50,9 @@ switch ($action) {
|
||||
if ($d) {
|
||||
$ui->assign('burst', explode(" ", $d['burst']));
|
||||
$ui->assign('d', $d);
|
||||
$ui->display('bandwidth-edit.tpl');
|
||||
$ui->display('admin/bandwidth/edit.tpl');
|
||||
} else {
|
||||
r2(U . 'bandwidth/list', 'e', Lang::T('Account Not Found'));
|
||||
r2(getUrl('bandwidth/list'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -66,7 +65,7 @@ switch ($action) {
|
||||
$d = ORM::for_table('tbl_bandwidth')->find_one($id);
|
||||
if ($d) {
|
||||
$d->delete();
|
||||
r2(U . 'bandwidth/list', 's', Lang::T('Data Deleted Successfully'));
|
||||
r2(getUrl('bandwidth/list'), 's', Lang::T('Data Deleted Successfully'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -123,9 +122,9 @@ switch ($action) {
|
||||
$d->burst = $burst;
|
||||
$d->save();
|
||||
|
||||
r2(U . 'bandwidth/list', 's', Lang::T('Data Created Successfully'));
|
||||
r2(getUrl('bandwidth/list'), 's', Lang::T('Data Created Successfully'));
|
||||
} else {
|
||||
r2(U . 'bandwidth/add', 'e', $msg);
|
||||
r2(getUrl('bandwidth/add'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -179,12 +178,12 @@ switch ($action) {
|
||||
$d->burst = $burst;
|
||||
$d->save();
|
||||
|
||||
r2(U . 'bandwidth/list', 's', Lang::T('Data Updated Successfully'));
|
||||
r2(getUrl('bandwidth/list'), 's', Lang::T('Data Updated Successfully'));
|
||||
} else {
|
||||
r2(U . 'bandwidth/edit/' . $id, 'e', $msg);
|
||||
r2(getUrl('bandwidth/edit/') . $id, 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$ui->display('a404.tpl');
|
||||
$ui->display('admin/404.tpl');
|
||||
}
|
||||
|
@ -19,8 +19,8 @@ switch ($action) {
|
||||
|
||||
$ui->assign('masters', $masters);
|
||||
$ui->assign('devs', $devs);
|
||||
$ui->display('community-rollback.tpl');
|
||||
$ui->display('admin/rollback.tpl');
|
||||
break;
|
||||
default:
|
||||
$ui->display('community.tpl');
|
||||
$ui->display('admin/community.tpl');
|
||||
}
|
315
system/controllers/coupons.php
Normal file
315
system/controllers/coupons.php
Normal file
@ -0,0 +1,315 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
* Coupons Controller by https://t.me/focuslinkstech
|
||||
**/
|
||||
|
||||
_admin();
|
||||
$ui->assign('_title', Lang::T('Coupons'));
|
||||
$ui->assign('_system_menu', 'crm');
|
||||
|
||||
$action = $routes['1'];
|
||||
$ui->assign('_admin', $admin);
|
||||
|
||||
switch ($action) {
|
||||
|
||||
case 'add':
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Sales'])) {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T('You do not have permission to access this page')]);
|
||||
exit;
|
||||
}
|
||||
$ui->assign('_title', Lang::T('Add Coupon'));
|
||||
$ui->assign('csrf_token', Csrf::generateAndStoreToken());
|
||||
$ui->display('admin/coupons/add.tpl');
|
||||
break;
|
||||
|
||||
case 'add-post':
|
||||
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Sales'])) {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T('You do not have permission to access this page')]);
|
||||
exit;
|
||||
}
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$code = Text::alphanumeric(_post('code', ''));
|
||||
$type = _post('type', '');
|
||||
$value = floatval(_post('value', ''));
|
||||
$description = _post('description', '');
|
||||
$max_usage = _post('max_usage', '0');
|
||||
$min_order_amount = _post('min_order_amount', '');
|
||||
$max_discount_amount = intval(_post('max_discount_amount', ''));
|
||||
$status = _post('status', 'active');
|
||||
$start_date = strtotime(_post('start_date', '0000-00-00'));
|
||||
$end_date = strtotime(_post('end_date', '0000-00-00'));
|
||||
|
||||
$error = [];
|
||||
if (empty($code)) {
|
||||
$error[] = Lang::T('Coupon Code is required');
|
||||
}
|
||||
if (empty($type)) {
|
||||
$error[] = Lang::T('Coupon Type is required');
|
||||
}
|
||||
if (empty($value)) {
|
||||
$error[] = Lang::T('Coupon Value is required');
|
||||
}
|
||||
if (empty($description)) {
|
||||
$error[] = Lang::T('Coupon Description is required');
|
||||
}
|
||||
if ($max_usage < 0) {
|
||||
$error[] = Lang::T('Coupon Maximum Usage must be greater than or equal to 0');
|
||||
}
|
||||
if (empty($min_order_amount)) {
|
||||
$error[] = Lang::T('Coupon Minimum Order Amount is required');
|
||||
}
|
||||
if (empty($max_discount_amount)) {
|
||||
$error[] = Lang::T('Coupon Maximum Discount Amount is required');
|
||||
}
|
||||
if (empty($status)) {
|
||||
$error[] = Lang::T('Coupon Status is required');
|
||||
}
|
||||
if (empty($start_date)) {
|
||||
$error[] = Lang::T('Coupon Start Date is required');
|
||||
}
|
||||
if (empty($end_date)) {
|
||||
$error[] = Lang::T('Coupon End Date is required');
|
||||
}
|
||||
|
||||
if (!empty($error)) {
|
||||
r2(getUrl('coupons/add'), 'e', implode('<br>', $error));
|
||||
exit;
|
||||
}
|
||||
|
||||
//check if coupon code already exists
|
||||
$coupon = ORM::for_table('tbl_coupons')->where('code', $code)->find_one();
|
||||
if ($coupon) {
|
||||
r2(getUrl('coupons/add'), 'e', Lang::T('Coupon Code already exists'));
|
||||
exit;
|
||||
}
|
||||
|
||||
$coupon = ORM::for_table('tbl_coupons')->create();
|
||||
$coupon->code = $code;
|
||||
$coupon->type = $type;
|
||||
$coupon->value = $value;
|
||||
$coupon->description = $description;
|
||||
$coupon->max_usage = $max_usage;
|
||||
$coupon->min_order_amount = $min_order_amount;
|
||||
$coupon->max_discount_amount = $max_discount_amount;
|
||||
$coupon->status = $status;
|
||||
$coupon->start_date = date('Y-m-d', $start_date);
|
||||
$coupon->end_date = date('Y-m-d', $end_date);
|
||||
$coupon->created_at = date('Y-m-d H:i:s');
|
||||
try {
|
||||
$coupon->save();
|
||||
r2(getUrl('coupons'), 's', Lang::T('Coupon has been added successfully'));
|
||||
} catch (Exception $e) {
|
||||
_log(Lang::T('Error adding coupon: ' . $e->getMessage()));
|
||||
r2(getUrl('coupons/add'), 'e', Lang::T('Error adding coupon: ' . $e->getMessage()));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'edit':
|
||||
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Sales'])) {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T('You do not have permission to access this page')]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$coupon_id = intval($routes['2']);
|
||||
if (empty($coupon_id)) {
|
||||
r2(getUrl('coupons'), 'e', Lang::T('Invalid Coupon ID'));
|
||||
exit;
|
||||
}
|
||||
$coupon = ORM::for_table('tbl_coupons')->find_one($coupon_id);
|
||||
if (!$coupon) {
|
||||
r2(getUrl('coupons'), 'e', Lang::T('Coupon Not Found'));
|
||||
exit;
|
||||
}
|
||||
$ui->assign('coupon', $coupon);
|
||||
$ui->assign('_title', Lang::T('Edit Coupon: ' . $coupon['code']));
|
||||
$ui->assign('csrf_token', Csrf::generateAndStoreToken());
|
||||
$ui->display('admin/coupons/edit.tpl');
|
||||
break;
|
||||
|
||||
case 'edit-post':
|
||||
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Sales'])) {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T('You do not have permission to access this page')]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
|
||||
$code = Text::alphanumeric(_post('code', ''));
|
||||
$type = _post('type', '');
|
||||
$value = floatval(_post('value', ''));
|
||||
$description = _post('description', '');
|
||||
$max_usage = _post('max_usage', '');
|
||||
$min_order_amount = _post('min_order_amount', '');
|
||||
$max_discount_amount = intval(_post('max_discount_amount', ''));
|
||||
$status = _post('status', 'active');
|
||||
$start_date = strtotime(_post('start_date', '0000-00-00'));
|
||||
$end_date = strtotime(_post('end_date', '0000-00-00'));
|
||||
|
||||
$error = [];
|
||||
if (empty($code)) {
|
||||
$error[] = Lang::T('Coupon code is required');
|
||||
}
|
||||
if (empty($type)) {
|
||||
$error[] = Lang::T('Coupon type is required');
|
||||
}
|
||||
if (empty($value)) {
|
||||
$error[] = Lang::T('Coupon value is required');
|
||||
}
|
||||
if (empty($description)) {
|
||||
$error[] = Lang::T('Coupon description is required');
|
||||
}
|
||||
if ($max_usage < 0) {
|
||||
$error[] = Lang::T('Coupon Maximum Usage must be greater than or equal to 0');
|
||||
}
|
||||
if (empty($min_order_amount)) {
|
||||
$error[] = Lang::T('Coupon minimum order amount is required');
|
||||
}
|
||||
if (empty($max_discount_amount)) {
|
||||
$error[] = Lang::T('Coupon maximum discount amount is required');
|
||||
}
|
||||
if (empty($status)) {
|
||||
$error[] = Lang::T('Coupon status is required');
|
||||
}
|
||||
if (empty($start_date)) {
|
||||
$error[] = Lang::T('Coupon start date is required');
|
||||
}
|
||||
if (empty($end_date)) {
|
||||
$error[] = Lang::T('Coupon end date is required');
|
||||
}
|
||||
if (!empty($error)) {
|
||||
r2(getUrl('coupons/edit/') . $coupon_id, 'e', implode('<br>', $error));
|
||||
exit;
|
||||
}
|
||||
$coupon = ORM::for_table('tbl_coupons')->find_one($coupon_id);
|
||||
$coupon->code = $code;
|
||||
$coupon->type = $type;
|
||||
$coupon->value = $value;
|
||||
$coupon->description = $description;
|
||||
$coupon->max_usage = $max_usage;
|
||||
$coupon->min_order_amount = $min_order_amount;
|
||||
$coupon->max_discount_amount = $max_discount_amount;
|
||||
$coupon->status = $status;
|
||||
$coupon->start_date = date('Y-m-d', $start_date);
|
||||
$coupon->end_date = date('Y-m-d', $end_date);
|
||||
$coupon->updated_at = date('Y-m-d H:i:s');
|
||||
try {
|
||||
$coupon->save();
|
||||
r2(getUrl('coupons'), 's', Lang::T('Coupon has been updated successfully'));
|
||||
} catch (Exception $e) {
|
||||
_log(Lang::T('Error updating coupon: ') . $e->getMessage());
|
||||
r2(getUrl('coupons/edit/') . $coupon_id, 'e', Lang::T('Error updating coupon: ') . $e->getMessage());
|
||||
}
|
||||
break;
|
||||
|
||||
case 'delete':
|
||||
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Sales'])) {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T('You do not have permission to access this page')]);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$couponIds = json_decode($_POST['couponIds'], true);
|
||||
|
||||
if (is_array($couponIds) && !empty($couponIds)) {
|
||||
// Delete coupons from the database
|
||||
ORM::for_table('tbl_coupons')
|
||||
->where_in('id', $couponIds)
|
||||
->delete_many();
|
||||
|
||||
// Return success response
|
||||
echo json_encode(['status' => 'success', 'message' => Lang::T("Coupons Deleted Successfully.")]);
|
||||
exit;
|
||||
} else {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T("Invalid or missing coupon IDs.")]);
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T("Invalid request method.")]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'status':
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Sales'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
$couponId = $_GET['coupon_id'] ?? '';
|
||||
$csrf_token = $_GET['csrf_token'] ?? '';
|
||||
$status = $_GET['status'] ?? '';
|
||||
if (empty($couponId) || empty($csrf_token) || !Csrf::check($csrf_token) || empty($status)) {
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T("Invalid request"));
|
||||
exit;
|
||||
}
|
||||
$coupon = ORM::for_table('tbl_coupons')->where('id', $couponId)->find_one();
|
||||
if (!$coupon) {
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T("Coupon not found."));
|
||||
exit;
|
||||
}
|
||||
$coupon->status = $status;
|
||||
$coupon->save();
|
||||
r2($_SERVER['HTTP_REFERER'], 's', Lang::T("Coupon status updated successfully."));
|
||||
} else {
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T("Invalid request method"));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Sales'])) {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T('You do not have permission to access this page')]);
|
||||
exit;
|
||||
}
|
||||
$ui->assign('_title', Lang::T('Coupons'));
|
||||
$ui->assign('_system_menu', 'crm');
|
||||
|
||||
$search = _post('search');
|
||||
$filter = _post('filter', 'none');
|
||||
|
||||
$couponsData = ORM::for_table('tbl_coupons')
|
||||
->table_alias('c')
|
||||
->select_many(
|
||||
'c.id',
|
||||
'c.code',
|
||||
'c.type',
|
||||
'c.value',
|
||||
'c.description',
|
||||
'c.max_usage',
|
||||
'c.usage_count',
|
||||
'c.status',
|
||||
'c.min_order_amount',
|
||||
'c.max_discount_amount',
|
||||
'c.start_date',
|
||||
'c.end_date',
|
||||
'c.created_at',
|
||||
'c.updated_at'
|
||||
);
|
||||
|
||||
// Apply filters
|
||||
if ($search != '') {
|
||||
$searchLike = "%$search%";
|
||||
$couponsData->whereRaw(
|
||||
"code LIKE ? OR type LIKE ? OR value LIKE ? OR max_usage LIKE ? OR usage_count LIKE ? OR status LIKE ? OR min_order_amount LIKE ? OR max_discount_amount LIKE ?",
|
||||
[$searchLike, $searchLike, $searchLike, $searchLike, $searchLike, $searchLike, $searchLike, $searchLike]
|
||||
);
|
||||
}
|
||||
$couponsData->order_by_asc('c.id');
|
||||
$coupons = Paginator::findMany($couponsData, ['search' => $search], 5, '');
|
||||
$ui->assign('csrf_token', Csrf::generateAndStoreToken());
|
||||
$ui->assign('coupons', $coupons);
|
||||
$ui->display('admin/coupons/list.tpl');
|
||||
break;
|
||||
}
|
@ -25,6 +25,10 @@ switch ($action) {
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$csrf_token = _req('token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('customers'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
|
||||
$cs = ORM::for_table('tbl_customers')
|
||||
->select('tbl_customers.id', 'id')
|
||||
@ -153,7 +157,8 @@ switch ($action) {
|
||||
}
|
||||
$ui->assign('xheader', $leafletpickerHeader);
|
||||
run_hook('view_add_customer'); #HOOK
|
||||
$ui->display('customers-add.tpl');
|
||||
$ui->assign('csrf_token', Csrf::generateAndStoreToken());
|
||||
$ui->display('admin/customers/add.tpl');
|
||||
break;
|
||||
case 'recharge':
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) {
|
||||
@ -161,22 +166,43 @@ switch ($action) {
|
||||
}
|
||||
$id_customer = $routes['2'];
|
||||
$plan_id = $routes['3'];
|
||||
$csrf_token = _req('token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('customers/view/') . $id_customer, 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$b = ORM::for_table('tbl_user_recharges')->where('customer_id', $id_customer)->where('plan_id', $plan_id)->find_one();
|
||||
if ($b) {
|
||||
$gateway = 'Recharge';
|
||||
$channel = $admin['fullname'];
|
||||
$cust = User::_info($id_customer);
|
||||
$plan = ORM::for_table('tbl_plans')->find_one($b['plan_id']);
|
||||
$add_inv = User::getAttribute("Invoice", $id_customer);
|
||||
if (!empty($add_inv)) {
|
||||
$plan['price'] = $add_inv;
|
||||
}
|
||||
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
|
||||
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
|
||||
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : null;
|
||||
if ($tax_rate_setting === 'custom') {
|
||||
$tax_rate = $custom_tax_rate;
|
||||
} else {
|
||||
$tax_rate = $tax_rate_setting;
|
||||
}
|
||||
if ($tax_enable === 'yes') {
|
||||
$tax = Package::tax($plan['price'], $tax_rate);
|
||||
} else {
|
||||
$tax = 0;
|
||||
}
|
||||
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'));
|
||||
r2(getUrl('plan/recharge'), 'e', Lang::T('Customer not found'));
|
||||
}
|
||||
if (!$plan) {
|
||||
r2(U . 'plan/recharge', 'e', Lang::T('Plan not found'));
|
||||
r2(getUrl('plan/recharge'), 'e', Lang::T('Plan not found'));
|
||||
}
|
||||
if ($cust['balance'] < ($plan['price'] + $add_cost)) {
|
||||
r2(U . 'plan/recharge', 'e', Lang::T('insufficient balance'));
|
||||
if ($cust['balance'] < ($plan['price'] + $add_cost + $tax)) {
|
||||
r2(getUrl('plan/recharge'), 'e', Lang::T('insufficient balance'));
|
||||
}
|
||||
$gateway = 'Recharge Balance';
|
||||
}
|
||||
@ -189,7 +215,12 @@ switch ($action) {
|
||||
if (count($usings) == 0) {
|
||||
$usings[] = Lang::T('Cash');
|
||||
}
|
||||
$abills = User::getAttributes("Bill");
|
||||
if ($tax_enable === 'yes') {
|
||||
$ui->assign('tax', $tax);
|
||||
}
|
||||
$ui->assign('usings', $usings);
|
||||
$ui->assign('abills', $abills);
|
||||
$ui->assign('bills', $bills);
|
||||
$ui->assign('add_cost', $add_cost);
|
||||
$ui->assign('cust', $cust);
|
||||
@ -197,9 +228,11 @@ switch ($action) {
|
||||
$ui->assign('channel', $channel);
|
||||
$ui->assign('server', $b['routers']);
|
||||
$ui->assign('plan', $plan);
|
||||
$ui->display('recharge-confirm.tpl');
|
||||
$ui->assign('add_inv', $add_inv);
|
||||
$ui->assign('csrf_token', Csrf::generateAndStoreToken());
|
||||
$ui->display('admin/plan/recharge-confirm.tpl');
|
||||
} else {
|
||||
r2(U . 'customers/view/' . $id_customer, 'e', 'Cannot find active plan');
|
||||
r2(getUrl('customers/view/') . $id_customer, 'e', 'Cannot find active plan');
|
||||
}
|
||||
break;
|
||||
case 'deactivate':
|
||||
@ -208,6 +241,10 @@ switch ($action) {
|
||||
}
|
||||
$id_customer = $routes['2'];
|
||||
$plan_id = $routes['3'];
|
||||
$csrf_token = _req('token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('customers/view/') . $id_customer, 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$b = ORM::for_table('tbl_user_recharges')->where('customer_id', $id_customer)->where('plan_id', $plan_id)->find_one();
|
||||
if ($b) {
|
||||
$p = ORM::for_table('tbl_plans')->where('id', $b['plan_id'])->find_one();
|
||||
@ -229,13 +266,17 @@ switch ($action) {
|
||||
$b->save();
|
||||
_log('Admin ' . $admin['username'] . ' Deactivate ' . $b['namebp'] . ' for ' . $b['username'], 'User', $b['customer_id']);
|
||||
Message::sendTelegram('Admin ' . $admin['username'] . ' Deactivate ' . $b['namebp'] . ' for u' . $b['username']);
|
||||
r2(U . 'customers/view/' . $id_customer, 's', 'Success deactivate customer to Mikrotik');
|
||||
r2(getUrl('customers/view/') . $id_customer, 's', 'Success deactivate customer to Mikrotik');
|
||||
}
|
||||
}
|
||||
r2(U . 'customers/view/' . $id_customer, 'e', 'Cannot find active plan');
|
||||
r2(getUrl('customers/view/') . $id_customer, 'e', 'Cannot find active plan');
|
||||
break;
|
||||
case 'sync':
|
||||
$id_customer = $routes['2'];
|
||||
$csrf_token = _req('token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('customers/view/') . $id_customer, 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$bs = ORM::for_table('tbl_user_recharges')->where('customer_id', $id_customer)->where('status', 'on')->findMany();
|
||||
if ($bs) {
|
||||
$routers = [];
|
||||
@ -248,16 +289,37 @@ switch ($action) {
|
||||
if ($_app_stage != 'demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
(new $p['device'])->add_customer($c, $p);
|
||||
if (method_exists($dvc, 'sync_customer')) {
|
||||
(new $p['device'])->sync_customer($c, $p);
|
||||
}else{
|
||||
(new $p['device'])->add_customer($c, $p);
|
||||
}
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
r2(U . 'customers/view/' . $id_customer, 's', 'Sync success to ' . implode(", ", $routers));
|
||||
r2(getUrl('customers/view/') . $id_customer, 's', 'Sync success to ' . implode(", ", $routers));
|
||||
}
|
||||
r2(U . 'customers/view/' . $id_customer, 'e', 'Cannot find active plan');
|
||||
r2(getUrl('customers/view/') . $id_customer, 'e', 'Cannot find active plan');
|
||||
break;
|
||||
case 'login':
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$id = $routes['2'];
|
||||
$csrf_token = _req('token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('customers/view/') . $id, 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$customer = ORM::for_table('tbl_customers')->find_one($id);
|
||||
if ($customer) {
|
||||
$_SESSION['uid'] = $id;
|
||||
User::setCookie($id);
|
||||
_alert("You are logging in as $customer[fullname],<br>don't logout just close tab.", 'info', "home", 10);
|
||||
}
|
||||
_alert(Lang::T('Customer not found'), 'danger', "customers");
|
||||
break;
|
||||
case 'viewu':
|
||||
$customer = ORM::for_table('tbl_customers')->where('username', $routes['2'])->find_one();
|
||||
@ -268,8 +330,6 @@ switch ($action) {
|
||||
$customer = ORM::for_table('tbl_customers')->find_one($id);
|
||||
}
|
||||
if ($customer) {
|
||||
|
||||
|
||||
// Fetch the Customers Attributes values from the tbl_customer_custom_fields table
|
||||
$customFields = ORM::for_table('tbl_customers_fields')
|
||||
->where('customer_id', $customer['id'])
|
||||
@ -278,28 +338,44 @@ switch ($action) {
|
||||
if (empty($v)) {
|
||||
$v = 'activation';
|
||||
}
|
||||
if ($v == 'order') {
|
||||
$v = 'order';
|
||||
$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') {
|
||||
$query = ORM::for_table('tbl_transactions')->where('username', $customer['username'])->order_by_desc('id');
|
||||
$activation = Paginator::findMany($query);
|
||||
$ui->assign('activation', $activation);
|
||||
switch ($v) {
|
||||
case 'order':
|
||||
$v = 'order';
|
||||
$query = ORM::for_table('tbl_payment_gateway')->where('user_id', $customer['id'])->order_by_desc('id');
|
||||
$order = Paginator::findMany($query);
|
||||
|
||||
if (empty($order) || $order < 5) {
|
||||
$query = ORM::for_table('tbl_payment_gateway')->where('username', $customer['username'])->order_by_desc('id');
|
||||
$order = Paginator::findMany($query);
|
||||
}
|
||||
|
||||
$ui->assign('order', $order);
|
||||
break;
|
||||
case 'activation':
|
||||
$query = ORM::for_table('tbl_transactions')->where('user_id', $customer['id'])->order_by_desc('id');
|
||||
$activation = Paginator::findMany($query);
|
||||
|
||||
if (empty($activation) || $activation < 5) {
|
||||
$query = ORM::for_table('tbl_transactions')->where('username', $customer['username'])->order_by_desc('id');
|
||||
$activation = Paginator::findMany($query);
|
||||
}
|
||||
|
||||
$ui->assign('activation', $activation);
|
||||
break;
|
||||
}
|
||||
$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');
|
||||
$ui->assign('csrf_token', Csrf::generateAndStoreToken());
|
||||
$ui->display('admin/customers/view.tpl');
|
||||
} else {
|
||||
r2(U . 'customers/list', 'e', Lang::T('Account Not Found'));
|
||||
r2(getUrl('customers/list'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
case 'edit':
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent'])) {
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$id = $routes['2'];
|
||||
@ -310,13 +386,31 @@ switch ($action) {
|
||||
->where('customer_id', $id)
|
||||
->find_many();
|
||||
if ($d) {
|
||||
if (isset($routes['3']) && $routes['3'] == 'deletePhoto') {
|
||||
if ($d['photo'] != '' && strpos($d['photo'], 'default') === false) {
|
||||
if (file_exists($UPLOAD_PATH . $d['photo']) && strpos($d['photo'], 'default') === false) {
|
||||
unlink($UPLOAD_PATH . $d['photo']);
|
||||
if (file_exists($UPLOAD_PATH . $d['photo'] . '.thumb.jpg')) {
|
||||
unlink($UPLOAD_PATH . $d['photo'] . '.thumb.jpg');
|
||||
}
|
||||
}
|
||||
$d->photo = '/user.default.jpg';
|
||||
$d->save();
|
||||
$ui->assign('notify_t', 's');
|
||||
$ui->assign('notify', 'You have successfully deleted the photo');
|
||||
} else {
|
||||
$ui->assign('notify_t', 'e');
|
||||
$ui->assign('notify', 'No photo found to delete');
|
||||
}
|
||||
}
|
||||
$ui->assign('d', $d);
|
||||
$ui->assign('statuses', ORM::for_table('tbl_customers')->getEnum("status"));
|
||||
$ui->assign('customFields', $customFields);
|
||||
$ui->assign('xheader', $leafletpickerHeader);
|
||||
$ui->display('customers-edit.tpl');
|
||||
$ui->assign('csrf_token', Csrf::generateAndStoreToken());
|
||||
$ui->display('admin/customers/edit.tpl');
|
||||
} else {
|
||||
r2(U . 'customers/list', 'e', Lang::T('Account Not Found'));
|
||||
r2(getUrl('customers/list'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -325,6 +419,10 @@ switch ($action) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$id = $routes['2'];
|
||||
$csrf_token = _req('token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('customers/view/') . $id, 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
run_hook('delete_customer'); #HOOK
|
||||
$c = ORM::for_table('tbl_customers')->find_one($id);
|
||||
if ($c) {
|
||||
@ -355,11 +453,16 @@ switch ($action) {
|
||||
$c->delete();
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
r2(U . 'customers/list', 's', Lang::T('User deleted Successfully'));
|
||||
r2(getUrl('customers/list'), 's', Lang::T('User deleted Successfully'));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'add-post':
|
||||
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('customers/add'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$username = alphanumeric(_post('username'), ":+_.@-");
|
||||
$fullname = _post('fullname');
|
||||
$password = trim(_post('password'));
|
||||
@ -444,7 +547,7 @@ switch ($action) {
|
||||
$welcomeMessage = str_replace('[[name]]', $d['fullname'], $welcomeMessage);
|
||||
$welcomeMessage = str_replace('[[username]]', $d['username'], $welcomeMessage);
|
||||
$welcomeMessage = str_replace('[[password]]', $d['password'], $welcomeMessage);
|
||||
$welcomeMessage = str_replace('[[url]]', APP_URL . '/index.php?_route=login', $welcomeMessage);
|
||||
$welcomeMessage = str_replace('[[url]]', APP_URL . '/?_route=login', $welcomeMessage);
|
||||
|
||||
$emailSubject = "Welcome to " . $config['CompanyName'];
|
||||
|
||||
@ -455,12 +558,12 @@ switch ($action) {
|
||||
'args' => [$d['phonenumber'], $welcomeMessage]
|
||||
],
|
||||
'whatsapp' => [
|
||||
'enabled' => isset($_POST['wa']) && $_POST['wa'] == 'wa',
|
||||
'enabled' => isset($_POST['wa']),
|
||||
'method' => 'sendWhatsapp',
|
||||
'args' => [$d['phonenumber'], $welcomeMessage]
|
||||
],
|
||||
'email' => [
|
||||
'enabled' => isset($_POST['email']),
|
||||
'enabled' => isset($_POST['mail']),
|
||||
'method' => 'Message::sendEmail',
|
||||
'args' => [$d['email'], $emailSubject, $welcomeMessage, $d['email']]
|
||||
]
|
||||
@ -477,13 +580,18 @@ switch ($action) {
|
||||
}
|
||||
}
|
||||
}
|
||||
r2(U . 'customers/list', 's', Lang::T('Account Created Successfully'));
|
||||
r2(getUrl('customers/list'), 's', Lang::T('Account Created Successfully'));
|
||||
} else {
|
||||
r2(U . 'customers/add', 'e', $msg);
|
||||
r2(getUrl('customers/add'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'edit-post':
|
||||
$id = _post('id');
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('customers/edit/') . $id, 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$username = alphanumeric(_post('username'), ":+_.@-");
|
||||
$fullname = _post('fullname');
|
||||
$account_type = _post('account_type');
|
||||
@ -511,7 +619,6 @@ switch ($action) {
|
||||
$msg .= 'Full Name should be between 2 to 25 characters' . '<br>';
|
||||
}
|
||||
|
||||
$id = _post('id');
|
||||
$c = ORM::for_table('tbl_customers')->find_one($id);
|
||||
|
||||
if (!$c) {
|
||||
@ -536,8 +643,8 @@ switch ($action) {
|
||||
if (ORM::for_table('tbl_customers')->where('username', $username)->find_one()) {
|
||||
$msg .= Lang::T('Username already used by another customer') . '<br>';
|
||||
}
|
||||
if(ORM::for_table('tbl_customers')->where('pppoe_username', $username)->find_one()){
|
||||
$msg.= Lang::T('Username already used by another pppoe username customer') . '<br>';
|
||||
if (ORM::for_table('tbl_customers')->where('pppoe_username', $username)->find_one()) {
|
||||
$msg .= Lang::T('Username already used by another pppoe username customer') . '<br>';
|
||||
}
|
||||
$userDiff = true;
|
||||
}
|
||||
@ -561,6 +668,54 @@ switch ($action) {
|
||||
}
|
||||
|
||||
if ($msg == '') {
|
||||
if (!empty($_FILES['photo']['name']) && file_exists($_FILES['photo']['tmp_name'])) {
|
||||
if (function_exists('imagecreatetruecolor')) {
|
||||
$hash = md5_file($_FILES['photo']['tmp_name']);
|
||||
$subfolder = substr($hash, 0, 2);
|
||||
$folder = $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'photos' . DIRECTORY_SEPARATOR;
|
||||
if (!file_exists($folder)) {
|
||||
mkdir($folder);
|
||||
}
|
||||
$folder = $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'photos' . DIRECTORY_SEPARATOR . $subfolder . DIRECTORY_SEPARATOR;
|
||||
if (!file_exists($folder)) {
|
||||
mkdir($folder);
|
||||
}
|
||||
$imgPath = $folder . $hash . '.jpg';
|
||||
if (!file_exists($imgPath)) {
|
||||
File::resizeCropImage($_FILES['photo']['tmp_name'], $imgPath, 1600, 1600, 100);
|
||||
}
|
||||
if (!file_exists($imgPath . '.thumb.jpg')) {
|
||||
if (_post('faceDetect') == 'yes') {
|
||||
try {
|
||||
$detector = new svay\FaceDetector();
|
||||
$detector->setTimeout(5000);
|
||||
$detector->faceDetect($imgPath);
|
||||
$detector->cropFaceToJpeg($imgPath . '.thumb.jpg', false);
|
||||
} catch (Exception $e) {
|
||||
File::makeThumb($imgPath, $imgPath . '.thumb.jpg', 200);
|
||||
} catch (Throwable $e) {
|
||||
File::makeThumb($imgPath, $imgPath . '.thumb.jpg', 200);
|
||||
}
|
||||
} else {
|
||||
File::makeThumb($imgPath, $imgPath . '.thumb.jpg', 200);
|
||||
}
|
||||
}
|
||||
if (file_exists($imgPath)) {
|
||||
if ($c['photo'] != '' && strpos($c['photo'], 'default') === false) {
|
||||
if (file_exists($UPLOAD_PATH . $c['photo'])) {
|
||||
unlink($UPLOAD_PATH . $c['photo']);
|
||||
if (file_exists($UPLOAD_PATH . $c['photo'] . '.thumb.jpg')) {
|
||||
unlink($UPLOAD_PATH . $c['photo'] . '.thumb.jpg');
|
||||
}
|
||||
}
|
||||
}
|
||||
$c->photo = '/photos/' . $subfolder . '/' . $hash . '.jpg';
|
||||
}
|
||||
if (file_exists($_FILES['photo']['tmp_name'])) unlink($_FILES['photo']['tmp_name']);
|
||||
} else {
|
||||
r2(getUrl('settings/app'), 'e', 'PHP GD is not installed');
|
||||
}
|
||||
}
|
||||
if ($userDiff) {
|
||||
$c->username = $username;
|
||||
}
|
||||
@ -644,13 +799,13 @@ switch ($action) {
|
||||
(new $p['device'])->change_username($p, $oldusername, $username);
|
||||
}
|
||||
if ($pppoeDiff && $tur['type'] == 'PPPOE') {
|
||||
if(empty($oldPppoeUsername) && !empty($pppoe_username)){
|
||||
if (empty($oldPppoeUsername) && !empty($pppoe_username)) {
|
||||
// admin just add pppoe username
|
||||
(new $p['device'])->change_username($p, $username, $pppoe_username);
|
||||
}else if(empty($pppoe_username) && !empty($oldPppoeUsername)){
|
||||
} else if (empty($pppoe_username) && !empty($oldPppoeUsername)) {
|
||||
// admin want to use customer username
|
||||
(new $p['device'])->change_username($p, $oldPppoeUsername, $username);
|
||||
}else{
|
||||
} else {
|
||||
// regular change pppoe username
|
||||
(new $p['device'])->change_username($p, $oldPppoeUsername, $pppoe_username);
|
||||
}
|
||||
@ -665,18 +820,18 @@ switch ($action) {
|
||||
$tur->save();
|
||||
}
|
||||
}
|
||||
r2(U . 'customers/view/' . $id, 's', 'User Updated Successfully');
|
||||
r2(getUrl('customers/view/') . $id, 's', 'User Updated Successfully');
|
||||
} else {
|
||||
r2(U . 'customers/edit/' . $id, 'e', $msg);
|
||||
r2(getUrl('customers/edit/') . $id, 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
run_hook('list_customers'); #HOOK
|
||||
$search = _post('search');
|
||||
$order = _post('order', 'username');
|
||||
$filter = _post('filter', 'Active');
|
||||
$orderby = _post('orderby', 'asc');
|
||||
$search = _req('search');
|
||||
$order = _req('order', 'username');
|
||||
$filter = _req('filter', 'Active');
|
||||
$orderby = _req('orderby', 'asc');
|
||||
$order_pos = [
|
||||
'username' => 0,
|
||||
'created_at' => 8,
|
||||
@ -694,12 +849,20 @@ switch ($action) {
|
||||
$query = ORM::for_table('tbl_customers');
|
||||
$query->where("status", $filter);
|
||||
}
|
||||
if ($orderby == 'asc') {
|
||||
$query->order_by_asc($order);
|
||||
if ($order == 'lastname') {
|
||||
$query->order_by_expr("SUBSTR(fullname, INSTR(fullname, ' ')) $orderby");
|
||||
} else {
|
||||
$query->order_by_desc($order);
|
||||
if ($orderby == 'asc') {
|
||||
$query->order_by_asc($order);
|
||||
} else {
|
||||
$query->order_by_desc($order);
|
||||
}
|
||||
}
|
||||
if (_post('export', '') == 'csv') {
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('customers'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$d = $query->findMany();
|
||||
$h = false;
|
||||
set_time_limit(-1);
|
||||
@ -749,6 +912,7 @@ switch ($action) {
|
||||
$ui->assign('order', $order);
|
||||
$ui->assign('order_pos', $order_pos[$order]);
|
||||
$ui->assign('orderby', $orderby);
|
||||
$ui->display('customers.tpl');
|
||||
$ui->assign('csrf_token', Csrf::generateAndStoreToken());
|
||||
$ui->display('admin/customers/list.tpl');
|
||||
break;
|
||||
}
|
||||
|
53
system/controllers/customfield.php
Normal file
53
system/controllers/customfield.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
**/
|
||||
|
||||
_admin();
|
||||
$ui->assign('_title', Lang::T('Custom Fields'));
|
||||
$ui->assign('_system_menu', 'settings');
|
||||
|
||||
$action = $routes['1'];
|
||||
$ui->assign('_admin', $admin);
|
||||
|
||||
$fieldPath = $UPLOAD_PATH . DIRECTORY_SEPARATOR . "customer_field.json";
|
||||
|
||||
switch ($action) {
|
||||
case 'save':
|
||||
print_r($_POST);
|
||||
$datas = [];
|
||||
$count = count($_POST['name']);
|
||||
for($n=0;$n<$count;$n++){
|
||||
if(!empty($_POST['name'][$n])){
|
||||
$datas[] = [
|
||||
'order' => $_POST['order'][$n],
|
||||
'name' => Text::alphanumeric(strtolower(str_replace(" ", "_", $_POST['name'][$n])), "_"),
|
||||
'type' => $_POST['type'][$n],
|
||||
'placeholder' => $_POST['placeholder'][$n],
|
||||
'value' => $_POST['value'][$n],
|
||||
'register' => $_POST['register'][$n],
|
||||
'required' => $_POST['required'][$n]
|
||||
];
|
||||
}
|
||||
}
|
||||
if(count($datas)>1){
|
||||
usort($datas, function ($item1, $item2) {
|
||||
return $item1['order'] <=> $item2['order'];
|
||||
});
|
||||
}
|
||||
if(file_put_contents($fieldPath, json_encode($datas))){
|
||||
r2(getUrl('customfield'), 's', 'Successfully saved custom fields!');
|
||||
}else{
|
||||
r2(getUrl('customfield'), 'e', 'Failed to save custom fields!');
|
||||
}
|
||||
default:
|
||||
$fields = [];
|
||||
if(file_exists($fieldPath)){
|
||||
$fields = json_decode(file_get_contents($fieldPath), true);
|
||||
}
|
||||
$ui->assign('fields', $fields);
|
||||
$ui->display('admin/settings/customfield.tpl');
|
||||
break;
|
||||
}
|
@ -1,228 +1,66 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
**/
|
||||
|
||||
_admin();
|
||||
$ui->assign('_title', Lang::T('Dashboard'));
|
||||
$ui->assign('_admin', $admin);
|
||||
|
||||
if (isset($_GET['refresh'])) {
|
||||
$files = scandir($CACHE_PATH);
|
||||
foreach ($files as $file) {
|
||||
$ext = pathinfo($file, PATHINFO_EXTENSION);
|
||||
if (is_file($CACHE_PATH . DIRECTORY_SEPARATOR . $file) && $ext == 'temp') {
|
||||
unlink($CACHE_PATH . DIRECTORY_SEPARATOR . $file);
|
||||
}
|
||||
}
|
||||
r2(U . 'dashboard', 's', 'Data Refreshed');
|
||||
}
|
||||
|
||||
$reset_day = $config['reset_day'];
|
||||
if (empty($reset_day)) {
|
||||
$reset_day = 1;
|
||||
}
|
||||
//first day of month
|
||||
if (date("d") >= $reset_day) {
|
||||
$start_date = date('Y-m-' . $reset_day);
|
||||
} else {
|
||||
$start_date = date('Y-m-' . $reset_day, strtotime("-1 MONTH"));
|
||||
}
|
||||
|
||||
$current_date = date('Y-m-d');
|
||||
$month_n = date('n');
|
||||
|
||||
$iday = ORM::for_table('tbl_transactions')
|
||||
->where('recharged_on', $current_date)
|
||||
->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_not_equal('method', 'Customer - Balance')
|
||||
->where_not_equal('method', 'Recharge Balance - Administrator')
|
||||
->where_gte('recharged_on', $start_date)
|
||||
->where_lte('recharged_on', $current_date)->sum('price');
|
||||
if ($imonth == '') {
|
||||
$imonth = '0.00';
|
||||
}
|
||||
$ui->assign('imonth', $imonth);
|
||||
|
||||
if ($config['enable_balance'] == 'yes'){
|
||||
$cb = ORM::for_table('tbl_customers')->whereGte('balance', 0)->sum('balance');
|
||||
$ui->assign('cb', $cb);
|
||||
}
|
||||
|
||||
$u_act = ORM::for_table('tbl_user_recharges')->where('status', 'on')->count();
|
||||
if (empty($u_act)) {
|
||||
$u_act = '0';
|
||||
}
|
||||
$ui->assign('u_act', $u_act);
|
||||
|
||||
$u_all = ORM::for_table('tbl_user_recharges')->count();
|
||||
if (empty($u_all)) {
|
||||
$u_all = '0';
|
||||
}
|
||||
$ui->assign('u_all', $u_all);
|
||||
|
||||
|
||||
$c_all = ORM::for_table('tbl_customers')->count();
|
||||
if (empty($c_all)) {
|
||||
$c_all = '0';
|
||||
}
|
||||
$ui->assign('c_all', $c_all);
|
||||
|
||||
if ($config['hide_uet'] != 'yes') {
|
||||
//user expire
|
||||
$query = ORM::for_table('tbl_user_recharges')
|
||||
->where_lte('expiration', $current_date)
|
||||
->order_by_desc('expiration');
|
||||
$expire = Paginator::findMany($query);
|
||||
|
||||
// Get the total count of expired records for pagination
|
||||
$totalCount = ORM::for_table('tbl_user_recharges')
|
||||
->where_lte('expiration', $current_date)
|
||||
->count();
|
||||
|
||||
// Pass the total count and current page to the paginator
|
||||
$paginator['total_count'] = $totalCount;
|
||||
|
||||
// Assign the pagination HTML to the template variable
|
||||
$ui->assign('expire', $expire);
|
||||
}
|
||||
|
||||
//activity log
|
||||
$dlog = ORM::for_table('tbl_logs')->limit(5)->order_by_desc('id')->find_many();
|
||||
$ui->assign('dlog', $dlog);
|
||||
$log = ORM::for_table('tbl_logs')->count();
|
||||
$ui->assign('log', $log);
|
||||
|
||||
|
||||
if ($config['hide_vs'] != 'yes') {
|
||||
$cacheStocksfile = $CACHE_PATH . File::pathFixer('/VoucherStocks.temp');
|
||||
$cachePlanfile = $CACHE_PATH . File::pathFixer('/VoucherPlans.temp');
|
||||
//Cache for 5 minutes
|
||||
if (file_exists($cacheStocksfile) && time() - filemtime($cacheStocksfile) < 600) {
|
||||
$stocks = json_decode(file_get_contents($cacheStocksfile), true);
|
||||
$plans = json_decode(file_get_contents($cachePlanfile), true);
|
||||
} else {
|
||||
// Count stock
|
||||
$tmp = $v = ORM::for_table('tbl_plans')->select('id')->select('name_plan')->find_many();
|
||||
$plans = array();
|
||||
$stocks = array("used" => 0, "unused" => 0);
|
||||
$n = 0;
|
||||
foreach ($tmp as $plan) {
|
||||
$unused = ORM::for_table('tbl_voucher')
|
||||
->where('id_plan', $plan['id'])
|
||||
->where('status', 0)->count();
|
||||
$used = ORM::for_table('tbl_voucher')
|
||||
->where('id_plan', $plan['id'])
|
||||
->where('status', 1)->count();
|
||||
if ($unused > 0 || $used > 0) {
|
||||
$plans[$n]['name_plan'] = $plan['name_plan'];
|
||||
$plans[$n]['unused'] = $unused;
|
||||
$plans[$n]['used'] = $used;
|
||||
$stocks["unused"] += $unused;
|
||||
$stocks["used"] += $used;
|
||||
$n++;
|
||||
}
|
||||
}
|
||||
file_put_contents($cacheStocksfile, json_encode($stocks));
|
||||
file_put_contents($cachePlanfile, json_encode($plans));
|
||||
}
|
||||
}
|
||||
|
||||
$cacheMRfile = File::pathFixer('/monthlyRegistered.temp');
|
||||
//Cache for 1 hour
|
||||
if (file_exists($cacheMRfile) && time() - filemtime($cacheMRfile) < 3600) {
|
||||
$monthlyRegistered = json_decode(file_get_contents($cacheMRfile), true);
|
||||
} else {
|
||||
//Monthly Registered Customers
|
||||
$result = ORM::for_table('tbl_customers')
|
||||
->select_expr('MONTH(created_at)', 'month')
|
||||
->select_expr('COUNT(*)', 'count')
|
||||
->where_raw('YEAR(created_at) = YEAR(NOW())')
|
||||
->group_by_expr('MONTH(created_at)')
|
||||
->find_many();
|
||||
|
||||
$monthlyRegistered = [];
|
||||
foreach ($result as $row) {
|
||||
$monthlyRegistered[] = [
|
||||
'date' => $row->month,
|
||||
'count' => $row->count
|
||||
];
|
||||
}
|
||||
file_put_contents($cacheMRfile, json_encode($monthlyRegistered));
|
||||
}
|
||||
|
||||
$cacheMSfile = $CACHE_PATH . File::pathFixer('/monthlySales.temp');
|
||||
//Cache for 12 hours
|
||||
if (file_exists($cacheMSfile) && time() - filemtime($cacheMSfile) < 43200) {
|
||||
$monthlySales = json_decode(file_get_contents($cacheMSfile), true);
|
||||
} else {
|
||||
// Query to retrieve monthly data
|
||||
$results = ORM::for_table('tbl_transactions')
|
||||
->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();
|
||||
|
||||
// Create an array to hold the monthly sales data
|
||||
$monthlySales = array();
|
||||
|
||||
// Iterate over the results and populate the array
|
||||
foreach ($results as $result) {
|
||||
$month = $result->month;
|
||||
$totalSales = $result->total;
|
||||
|
||||
$monthlySales[$month] = array(
|
||||
'month' => $month,
|
||||
'totalSales' => $totalSales
|
||||
);
|
||||
}
|
||||
|
||||
// Fill in missing months with zero sales
|
||||
for ($month = 1; $month <= 12; $month++) {
|
||||
if (!isset($monthlySales[$month])) {
|
||||
$monthlySales[$month] = array(
|
||||
'month' => $month,
|
||||
'totalSales' => 0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the array by month
|
||||
ksort($monthlySales);
|
||||
|
||||
// Reindex the array
|
||||
$monthlySales = array_values($monthlySales);
|
||||
file_put_contents($cacheMSfile, json_encode($monthlySales));
|
||||
}
|
||||
|
||||
if ($config['router_check']) {
|
||||
$routeroffs = ORM::for_table('tbl_routers')->selects(['id', 'name', 'last_seen'])->where('status', 'Offline')->order_by_desc('name')->find_array();
|
||||
print_r($routeroffs);
|
||||
$ui->assign('routeroffs', $routeroffs);
|
||||
}
|
||||
|
||||
// Assign the monthly sales data to Smarty
|
||||
$ui->assign('start_date', $start_date);
|
||||
$ui->assign('current_date', $current_date);
|
||||
$ui->assign('monthlySales', $monthlySales);
|
||||
$ui->assign('xfooter', '');
|
||||
$ui->assign('monthlyRegistered', $monthlyRegistered);
|
||||
$ui->assign('stocks', $stocks);
|
||||
$ui->assign('plans', $plans);
|
||||
|
||||
run_hook('view_dashboard'); #HOOK
|
||||
$ui->display('dashboard.tpl');
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
**/
|
||||
|
||||
_admin();
|
||||
$ui->assign('_title', Lang::T('Dashboard'));
|
||||
$ui->assign('_admin', $admin);
|
||||
|
||||
if (isset($_GET['refresh'])) {
|
||||
$files = scandir($CACHE_PATH);
|
||||
foreach ($files as $file) {
|
||||
$ext = pathinfo($file, PATHINFO_EXTENSION);
|
||||
if (is_file($CACHE_PATH . DIRECTORY_SEPARATOR . $file) && $ext == 'temp') {
|
||||
unlink($CACHE_PATH . DIRECTORY_SEPARATOR . $file);
|
||||
}
|
||||
}
|
||||
r2(getUrl('dashboard'), 's', 'Data Refreshed');
|
||||
}
|
||||
|
||||
$tipeUser = _req("user");
|
||||
if (empty($tipeUser)) {
|
||||
$tipeUser = 'Admin';
|
||||
}
|
||||
$ui->assign('tipeUser', $tipeUser);
|
||||
|
||||
$reset_day = $config['reset_day'];
|
||||
if (empty($reset_day)) {
|
||||
$reset_day = 1;
|
||||
}
|
||||
//first day of month
|
||||
if (date("d") >= $reset_day) {
|
||||
$start_date = date('Y-m-' . $reset_day);
|
||||
} else {
|
||||
$start_date = date('Y-m-' . $reset_day, strtotime("-1 MONTH"));
|
||||
}
|
||||
|
||||
$current_date = date('Y-m-d');
|
||||
$ui->assign('start_date', $start_date);
|
||||
$ui->assign('current_date', $current_date);
|
||||
|
||||
$tipeUser = $admin['user_type'];
|
||||
if (in_array($tipeUser, ['SuperAdmin', 'Admin'])) {
|
||||
$tipeUser = 'Admin';
|
||||
}
|
||||
|
||||
$widgets = ORM::for_table('tbl_widgets')->where("enabled", 1)->where('user', $tipeUser)->order_by_asc("orders")->findArray();
|
||||
$count = count($widgets);
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
try{
|
||||
if(file_exists($WIDGET_PATH . DIRECTORY_SEPARATOR . $widgets[$i]['widget'].".php")){
|
||||
require_once $WIDGET_PATH . DIRECTORY_SEPARATOR . $widgets[$i]['widget'].".php";
|
||||
$widgets[$i]['content'] = (new $widgets[$i]['widget'])->getWidget($widgets[$i]);
|
||||
}else{
|
||||
$widgets[$i]['content'] = "Widget not found";
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
$widgets[$i]['content'] = $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
$ui->assign('widgets', $widgets);
|
||||
run_hook('view_dashboard'); #HOOK
|
||||
$ui->display('admin/dashboard.tpl');
|
@ -5,9 +5,13 @@
|
||||
**/
|
||||
|
||||
if(Admin::getID()){
|
||||
r2(U.'dashboard');
|
||||
}if(User::getID()){
|
||||
r2(U.'home');
|
||||
//r2(getUrl('dashboard'));
|
||||
$handler = 'dashboard';
|
||||
}else if(User::getID()){
|
||||
//r2(getUrl('home'));
|
||||
$handler = 'home';
|
||||
}else{
|
||||
r2(U.'login');
|
||||
//r2(getUrl('login'));
|
||||
$handler = 'login';
|
||||
}
|
||||
include($root_path . File::pathFixer('system/controllers/' . $handler . '.php'));
|
@ -71,8 +71,8 @@ switch ($action) {
|
||||
if (count($plns) > 0) {
|
||||
$query->where_in('plan_name', $plns);
|
||||
}
|
||||
$x = $query->find_array();
|
||||
$xy = $query->sum('price');
|
||||
$x = $query->find_array();
|
||||
$xy = $query->sum('price');
|
||||
|
||||
$ui->assign('sd', $sd);
|
||||
$ui->assign('ed', $ed);
|
||||
@ -83,7 +83,7 @@ switch ($action) {
|
||||
$ui->assign('mdate', $mdate);
|
||||
$ui->assign('recharged_on', $mdate);
|
||||
run_hook('print_by_date'); #HOOK
|
||||
$ui->display('print-by-date.tpl');
|
||||
$ui->display('admin/print/by-date.tpl');
|
||||
break;
|
||||
|
||||
case 'pdf-by-date':
|
||||
@ -114,7 +114,10 @@ switch ($action) {
|
||||
$query = ORM::for_table('tbl_transactions')
|
||||
->whereRaw("UNIX_TIMESTAMP(CONCAT(`recharged_on`,' ',`recharged_time`)) >= " . strtotime("$sd $ts"))
|
||||
->whereRaw("UNIX_TIMESTAMP(CONCAT(`recharged_on`,' ',`recharged_time`)) <= " . strtotime("$ed $te"))
|
||||
->order_by_desc('id');
|
||||
->left_outer_join('tbl_customers', 'tbl_transactions.username = tbl_customers.username')
|
||||
->select('tbl_transactions.*')
|
||||
->select('tbl_customers.fullname', 'fullname')
|
||||
->order_by_desc('tbl_transactions.id');
|
||||
if (count($tps) > 0) {
|
||||
$query->where_in('type', $tps);
|
||||
}
|
||||
@ -131,13 +134,13 @@ switch ($action) {
|
||||
if (count($plns) > 0) {
|
||||
$query->where_in('plan_name', $plns);
|
||||
}
|
||||
$x = $query->find_array();
|
||||
$xy = $query->sum('price');
|
||||
$x = $query->find_array();
|
||||
$xy = $query->sum('price');
|
||||
|
||||
$title = ' Reports [' . $mdate . ']';
|
||||
$title = str_replace('-', ' ', $title);
|
||||
|
||||
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
|
||||
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
|
||||
if (file_exists($UPLOAD_PATH . '/logo.png')) {
|
||||
$logo = $UPLOAD_URL_PATH . '/logo.png';
|
||||
} else {
|
||||
@ -154,10 +157,11 @@ switch ($action) {
|
||||
</div>
|
||||
<div id="logo"><img id="image" src="' . $logo . '" alt="logo" /></div>
|
||||
</div>
|
||||
<div id="header">' . Lang::T('All Transactions at Date') . ': ' . Lang::dateAndTimeFormat($sd, $ts) .' - '. Lang::dateAndTimeFormat($ed, $te) . '</div>
|
||||
<div id="header">' . Lang::T('All Transactions at Date') . ': ' . Lang::dateAndTimeFormat($sd, $ts) . ' - ' . Lang::dateAndTimeFormat($ed, $te) . '</div>
|
||||
<table id="customers">
|
||||
<tr>
|
||||
<th>' . Lang::T('Username') . '</th>
|
||||
<th>' . Lang::T('Fullname') . '</th>
|
||||
<th>' . Lang::T('Plan Name') . '</th>
|
||||
<th>' . Lang::T('Type') . '</th>
|
||||
<th>' . Lang::T('Plan Price') . '</th>
|
||||
@ -170,6 +174,7 @@ switch ($action) {
|
||||
foreach ($x as $value) {
|
||||
|
||||
$username = $value['username'];
|
||||
$fullname = $value['fullname'];
|
||||
$plan_name = $value['plan_name'];
|
||||
$type = $value['type'];
|
||||
$price = $config['currency_code'] . ' ' . number_format($value['price'], 0, $config['dec_point'], $config['thousands_sep']);
|
||||
@ -181,6 +186,7 @@ switch ($action) {
|
||||
|
||||
$html .= "<tr" . (($c = !$c) ? ' class="alt"' : ' class=""') . ">" . "
|
||||
<td>$username</td>
|
||||
<td>$fullname</td>
|
||||
<td>$plan_name</td>
|
||||
<td>$type</td>
|
||||
<td align='right'>$price</td>
|
||||
@ -245,7 +251,7 @@ $style
|
||||
$html
|
||||
EOF;
|
||||
$mpdf->WriteHTML($nhtml);
|
||||
$mpdf->Output('phpnuxbill_reports_'.date('Ymd_His') . '.pdf', 'D');
|
||||
$mpdf->Output('phpnuxbill_reports_' . date('Ymd_His') . '.pdf', 'D');
|
||||
} else {
|
||||
echo 'No Data';
|
||||
}
|
||||
@ -258,13 +264,17 @@ EOF;
|
||||
$stype = _post('stype');
|
||||
|
||||
$d = ORM::for_table('tbl_transactions');
|
||||
$d->left_outer_join('tbl_customers', 'tbl_transactions.username = tbl_customers.username')
|
||||
->select('tbl_transactions.*')
|
||||
->select('tbl_customers.fullname', 'fullname')
|
||||
->order_by_desc('tbl_transactions.id');
|
||||
if ($stype != '') {
|
||||
$d->where('type', $stype);
|
||||
}
|
||||
$d->where_gte('recharged_on', $fdate);
|
||||
$d->where_lte('recharged_on', $tdate);
|
||||
$d->order_by_desc('id');
|
||||
$x = $d->find_many();
|
||||
$x = $d->find_many();
|
||||
|
||||
$dr = ORM::for_table('tbl_transactions');
|
||||
if ($stype != '') {
|
||||
@ -281,7 +291,7 @@ EOF;
|
||||
$ui->assign('tdate', $tdate);
|
||||
$ui->assign('stype', $stype);
|
||||
run_hook('print_by_period'); #HOOK
|
||||
$ui->display('print-by-period.tpl');
|
||||
$ui->display('admin/print/by-period.tpl');
|
||||
break;
|
||||
|
||||
|
||||
@ -290,6 +300,10 @@ EOF;
|
||||
$tdate = _post('tdate');
|
||||
$stype = _post('stype');
|
||||
$d = ORM::for_table('tbl_transactions');
|
||||
$d->left_outer_join('tbl_customers', 'tbl_transactions.username = tbl_customers.username')
|
||||
->select('tbl_transactions.*')
|
||||
->select('tbl_customers.fullname', 'fullname')
|
||||
->order_by_desc('tbl_transactions.id');
|
||||
if ($stype != '') {
|
||||
$d->where('type', $stype);
|
||||
}
|
||||
@ -297,7 +311,7 @@ EOF;
|
||||
$d->where_gte('recharged_on', $fdate);
|
||||
$d->where_lte('recharged_on', $tdate);
|
||||
$d->order_by_desc('id');
|
||||
$x = $d->find_many();
|
||||
$x = $d->find_many();
|
||||
|
||||
$dr = ORM::for_table('tbl_transactions');
|
||||
if ($stype != '') {
|
||||
@ -311,7 +325,7 @@ EOF;
|
||||
$title = ' Reports [' . $mdate . ']';
|
||||
$title = str_replace('-', ' ', $title);
|
||||
|
||||
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
|
||||
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
|
||||
if (file_exists($UPLOAD_PATH . '/logo.png')) {
|
||||
$logo = $UPLOAD_URL_PATH . '/logo.png';
|
||||
} else {
|
||||
@ -332,6 +346,7 @@ EOF;
|
||||
<table id="customers">
|
||||
<tr>
|
||||
<th>' . Lang::T('Username') . '</th>
|
||||
<th>' . Lang::T('Fullname') . '</th>
|
||||
<th>' . Lang::T('Plan Name') . '</th>
|
||||
<th>' . Lang::T('Type') . '</th>
|
||||
<th>' . Lang::T('Plan Price') . '</th>
|
||||
@ -344,6 +359,7 @@ EOF;
|
||||
foreach ($x as $value) {
|
||||
|
||||
$username = $value['username'];
|
||||
$fullname = $value['fullname'];
|
||||
$plan_name = $value['plan_name'];
|
||||
$type = $value['type'];
|
||||
$price = $config['currency_code'] . ' ' . number_format($value['price'], 0, $config['dec_point'], $config['thousands_sep']);
|
||||
@ -355,7 +371,8 @@ EOF;
|
||||
|
||||
$html .= "<tr" . (($c = !$c) ? ' class="alt"' : ' class=""') . ">" . "
|
||||
<td>$username</td>
|
||||
<td>$plan_name</td>
|
||||
<td>$fullname</td>
|
||||
<td>$plan_name</td>
|
||||
<td>$type</td>
|
||||
<td align='right'>$price</td>
|
||||
<td>$recharged_on </td>
|
||||
@ -427,5 +444,5 @@ EOF;
|
||||
break;
|
||||
|
||||
default:
|
||||
$ui->display('a404.tpl');
|
||||
$ui->display('admin/404.tpl');
|
||||
}
|
||||
|
169
system/controllers/forgot.php
Normal file
169
system/controllers/forgot.php
Normal file
@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
**/
|
||||
$step = _req('step', 0);
|
||||
$otpPath = $CACHE_PATH . File::pathFixer('/forgot/');
|
||||
|
||||
if ($step == '-1') {
|
||||
$_COOKIE['forgot_username'] = '';
|
||||
setcookie('forgot_username', '', time() - 3600, '/');
|
||||
$step = 0;
|
||||
}
|
||||
|
||||
if (!empty($_COOKIE['forgot_username']) && in_array($step, [0, 1])) {
|
||||
$step = 1;
|
||||
$_POST['username'] = $_COOKIE['forgot_username'];
|
||||
}
|
||||
|
||||
if ($step == 1) {
|
||||
$username = _post('username');
|
||||
if (!empty($username)) {
|
||||
$ui->assign('username', $username);
|
||||
if (!file_exists($otpPath)) {
|
||||
mkdir($otpPath);
|
||||
}
|
||||
setcookie('forgot_username', $username, time() + 3600, '/');
|
||||
$user = ORM::for_table('tbl_customers')->selects(['phonenumber', 'email'])->where('username', $username)->find_one();
|
||||
if ($user) {
|
||||
$otpPath .= sha1($username . $db_pass) . ".txt";
|
||||
if (file_exists($otpPath) && time() - filemtime($otpPath) < 600) {
|
||||
$sec = time() - filemtime($otpPath);
|
||||
$ui->assign('notify_t', 's');
|
||||
$ui->assign('notify', Lang::T("Verification Code already Sent to Your Phone/Email/Whatsapp, please wait")." $sec seconds.");
|
||||
} else {
|
||||
$via = $config['user_notification_reminder'];
|
||||
if ($via == 'email') {
|
||||
$via = 'sms';
|
||||
}
|
||||
$otp = mt_rand(100000, 999999);
|
||||
file_put_contents($otpPath, $otp);
|
||||
if ($via == 'sms') {
|
||||
Message::sendSMS($user['phonenumber'], $config['CompanyName'] . " C0de: $otp");
|
||||
} else {
|
||||
Message::sendWhatsapp($user['phonenumber'], $config['CompanyName'] . " C0de: $otp");
|
||||
}
|
||||
Message::sendEmail(
|
||||
$user['email'],
|
||||
$config['CompanyName'] . Lang::T("Your Verification Code") . ' : ' . $otp,
|
||||
Lang::T("Your Verification Code") . ' : <b>' . $otp . '</b>'
|
||||
);
|
||||
$ui->assign('notify_t', 's');
|
||||
$ui->assign('notify', Lang::T("If your Username is found, Verification Code has been Sent to Your Phone/Email/Whatsapp"));
|
||||
}
|
||||
} else {
|
||||
// Username not found
|
||||
$ui->assign('notify_t', 's');
|
||||
$ui->assign('notify', Lang::T("If your Username is found, Verification Code has been Sent to Your Phone/Email/Whatsapp") . ".");
|
||||
}
|
||||
} else {
|
||||
$step = 0;
|
||||
}
|
||||
} else if ($step == 2) {
|
||||
$username = _post('username');
|
||||
$otp_code = _post('otp_code');
|
||||
if (!empty($username) && !empty($otp_code)) {
|
||||
$otpPath .= sha1($username . $db_pass) . ".txt";
|
||||
if (file_exists($otpPath) && time() - filemtime($otpPath) <= 600) {
|
||||
$otp = file_get_contents($otpPath);
|
||||
if ($otp == $otp_code) {
|
||||
$pass = mt_rand(10000, 99999);
|
||||
$user = ORM::for_table('tbl_customers')->where('username', $username)->find_one();
|
||||
$user->password = $pass;
|
||||
$user->save();
|
||||
$ui->assign('username', $username);
|
||||
$ui->assign('passsword', $pass);
|
||||
$ui->assign('notify_t', 's');
|
||||
$ui->assign('notify', Lang::T("Verification Code Valid"));
|
||||
if (file_exists($otpPath)) {
|
||||
unlink($otpPath);
|
||||
}
|
||||
setcookie('forgot_username', '', time() - 3600, '/');
|
||||
} else {
|
||||
r2(getUrl('forgot&step=1'), 'e', Lang::T('Invalid Username or Verification Code'));
|
||||
}
|
||||
} else {
|
||||
if (file_exists($otpPath)) {
|
||||
unlink($otpPath);
|
||||
}
|
||||
r2(getUrl('forgot&step=1'), 'e', Lang::T('Invalid Username or Verification Code'));
|
||||
}
|
||||
} else {
|
||||
r2(getUrl('forgot&step=1'), 'e', Lang::T('Invalid Username or Verification Code'));
|
||||
}
|
||||
} else if ($step == 7) {
|
||||
$find = _post('find');
|
||||
$step = 6;
|
||||
if (!empty($find)) {
|
||||
$via = $config['user_notification_reminder'];
|
||||
if ($via == 'email') {
|
||||
$via = 'sms';
|
||||
}
|
||||
if (!file_exists($otpPath)) {
|
||||
mkdir($otpPath);
|
||||
}
|
||||
$otpPath .= sha1($find . $db_pass) . ".txt";
|
||||
$users = ORM::for_table('tbl_customers')->selects(['username', 'phonenumber', 'email'])->where('phonenumber', $find)->find_array();
|
||||
if ($users) {
|
||||
// prevent flooding only can request every 10 minutes
|
||||
if (!file_exists($otpPath) || (file_exists($otpPath) && time() - filemtime($otpPath) >= 600)) {
|
||||
$usernames = implode(", ", array_column($users, 'username'));
|
||||
if ($via == 'sms') {
|
||||
Message::sendSMS($find, Lang::T("Your username for") . ' ' . $config['CompanyName'] . "\n" . $usernames);
|
||||
} else {
|
||||
Message::sendWhatsapp($find, Lang::T("Your username for") . ' ' . $config['CompanyName'] . "\n" . $usernames);
|
||||
}
|
||||
file_put_contents($otpPath, time());
|
||||
}
|
||||
$ui->assign('notify_t', 's');
|
||||
$ui->assign('notify', Lang::T("Usernames have been sent to your phone/Whatsapp") . " $find");
|
||||
$step = 0;
|
||||
} else {
|
||||
$users = ORM::for_table('tbl_customers')->selects(['username', 'phonenumber', 'email'])->where('email', $find)->find_array();
|
||||
if ($users) {
|
||||
// prevent flooding only can request every 10 minutes
|
||||
if (!file_exists($otpPath) || (file_exists($otpPath) && time() - filemtime($otpPath) >= 600)) {
|
||||
$usernames = implode(", ", array_column($users, 'username'));
|
||||
$phones = [];
|
||||
foreach ($users as $user) {
|
||||
if (!in_array($user['phonenumber'], $phones)) {
|
||||
if ($via == 'sms') {
|
||||
Message::sendSMS($user['phonenumber'], Lang::T("Your username for") . ' ' . $config['CompanyName'] . "\n" . $usernames);
|
||||
} else {
|
||||
Message::sendWhatsapp($user['phonenumber'], Lang::T("Your username for") . ' ' . $config['CompanyName'] . "\n" . $usernames);
|
||||
}
|
||||
$phones[] = $user['phonenumber'];
|
||||
}
|
||||
}
|
||||
Message::sendEmail(
|
||||
$user['email'],
|
||||
Lang::T("Your username for") . ' ' . $config['CompanyName'],
|
||||
Lang::T("Your username for") . ' ' . $config['CompanyName'] . "\n" . $usernames
|
||||
);
|
||||
file_put_contents($otpPath, time());
|
||||
}
|
||||
$ui->assign('notify_t', 's');
|
||||
$ui->assign('notify', Lang::T("Usernames have been sent to your phone/Whatsapp/Email"));
|
||||
$step = 0;
|
||||
} else {
|
||||
$ui->assign('notify_t', 'e');
|
||||
$ui->assign('notify', Lang::T("No data found"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// delete old files
|
||||
$pth = $CACHE_PATH . File::pathFixer('/forgot/');
|
||||
$fs = scandir($pth);
|
||||
foreach ($fs as $file) {
|
||||
if(is_file($pth.$file) && time() - filemtime($pth.$file) > 3600) {
|
||||
unlink($pth.$file);
|
||||
}
|
||||
}
|
||||
|
||||
$ui->assign('step', $step);
|
||||
$ui->assign('_title', Lang::T('Forgot Password'));
|
||||
$ui->display('customer/forgot.tpl');
|
@ -23,18 +23,18 @@ if (_post('send') == 'balance') {
|
||||
}
|
||||
$target = ORM::for_table('tbl_customers')->where('username', _post('username'))->find_one();
|
||||
if (!$target) {
|
||||
r2(U . 'home', 'd', Lang::T('Username not found'));
|
||||
r2(getUrl('home'), 'd', Lang::T('Username not found'));
|
||||
}
|
||||
$username = _post('username');
|
||||
$balance = _post('balance');
|
||||
if ($user['balance'] < $balance) {
|
||||
r2(U . 'home', 'd', Lang::T('insufficient balance'));
|
||||
r2(getUrl('home'), 'd', Lang::T('insufficient balance'));
|
||||
}
|
||||
if (!empty($config['minimum_transfer']) && intval($balance) < intval($config['minimum_transfer'])) {
|
||||
r2(U . 'home', 'd', Lang::T('Minimum Transfer') . ' ' . Lang::moneyFormat($config['minimum_transfer']));
|
||||
r2(getUrl('home'), 'd', Lang::T('Minimum Transfer') . ' ' . Lang::moneyFormat($config['minimum_transfer']));
|
||||
}
|
||||
if ($user['username'] == $target['username']) {
|
||||
r2(U . 'home', 'd', Lang::T('Cannot send to yourself'));
|
||||
r2(getUrl('home'), 'd', Lang::T('Cannot send to yourself'));
|
||||
}
|
||||
if (Balance::transfer($user['id'], $username, $balance)) {
|
||||
//sender
|
||||
@ -71,13 +71,14 @@ if (_post('send') == 'balance') {
|
||||
$d->pg_url_payment = 'balance';
|
||||
$d->status = 2;
|
||||
$d->save();
|
||||
Message::sendBalanceNotification($user, $balance, ($user['balance'] - $balance), Lang::getNotifText('balance_send'), $config['user_notification_payment']);
|
||||
Message::sendBalanceNotification($target, $balance, ($target['balance'] + $balance), Lang::getNotifText('balance_received'), $config['user_notification_payment']);
|
||||
//
|
||||
Message::sendBalanceNotification($user, $target, $balance, ($user['balance'] - $balance), Lang::getNotifText('balance_send'), $config['user_notification_payment']);
|
||||
Message::sendBalanceNotification($target, $user, $balance, ($target['balance'] + $balance), Lang::getNotifText('balance_received'), $config['user_notification_payment']);
|
||||
Message::sendTelegram("#u$user[username] send balance to #u$target[username] \n" . Lang::moneyFormat($balance));
|
||||
r2(U . 'home', 's', Lang::T('Sending balance success'));
|
||||
r2(getUrl('home'), 's', Lang::T('Sending balance success'));
|
||||
}
|
||||
} else {
|
||||
r2(U . 'home', 'd', Lang::T('Failed, balance is not available'));
|
||||
r2(getUrl('home'), 'd', Lang::T('Failed, balance is not available'));
|
||||
}
|
||||
} else if (_post('send') == 'plan') {
|
||||
if ($user['status'] != 'Active') {
|
||||
@ -89,18 +90,17 @@ if (_post('send') == 'balance') {
|
||||
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(getUrl('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'));
|
||||
r2(getUrl('home'), 'w', Lang::T('Your friend do not have active package'));
|
||||
}
|
||||
$_bill = User::_billing();
|
||||
$ui->assign('_bills', $_bill);
|
||||
|
||||
|
||||
// Sync plan to router
|
||||
if (isset($_GET['sync']) && !empty($_GET['sync'])) {
|
||||
foreach ($_bill as $tur) {
|
||||
if($tur['status'] == 'on'){
|
||||
if ($tur['status'] == 'on') {
|
||||
$p = ORM::for_table('tbl_plans')->findOne($tur['plan_id']);
|
||||
if ($p) {
|
||||
$c = ORM::for_table('tbl_customers')->findOne($tur['customer_id']);
|
||||
@ -109,7 +109,11 @@ if (isset($_GET['sync']) && !empty($_GET['sync'])) {
|
||||
if ($_app_stage != 'demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
(new $p['device'])->add_customer($c, $p);
|
||||
if (method_exists($dvc, 'sync_customer')) {
|
||||
(new $p['device'])->sync_customer($c, $p);
|
||||
}else{
|
||||
(new $p['device'])->add_customer($c, $p);
|
||||
}
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
}
|
||||
@ -123,7 +127,7 @@ if (isset($_GET['sync']) && !empty($_GET['sync'])) {
|
||||
}
|
||||
}
|
||||
}
|
||||
r2(U . 'home', 's', $log);
|
||||
r2(getUrl('home'), 's', $log);
|
||||
}
|
||||
|
||||
if (isset($_GET['recharge']) && !empty($_GET['recharge'])) {
|
||||
@ -131,7 +135,7 @@ if (isset($_GET['recharge']) && !empty($_GET['recharge'])) {
|
||||
_alert(Lang::T('This account status') . ' : ' . Lang::T($user['status']), 'danger', "");
|
||||
}
|
||||
if (!empty(App::getTokenValue(_get('stoken')))) {
|
||||
r2(U . "voucher/invoice/");
|
||||
r2(getUrl('voucher/invoice/'));
|
||||
die();
|
||||
}
|
||||
$bill = ORM::for_table('tbl_user_recharges')->where('id', $_GET['recharge'])->where('username', $user['username'])->findOne();
|
||||
@ -142,29 +146,17 @@ if (isset($_GET['recharge']) && !empty($_GET['recharge'])) {
|
||||
$routers = ORM::for_table('tbl_routers')->where('name', $bill['routers'])->find_one();
|
||||
$router = $routers['id'];
|
||||
}
|
||||
if ($config['enable_balance'] == 'yes') {
|
||||
$plan = ORM::for_table('tbl_plans')->find_one($bill['plan_id']);
|
||||
if (!$plan['enabled']) {
|
||||
r2(U . "home", 'e', 'Plan is not exists');
|
||||
}
|
||||
if ($user['balance'] > $plan['price']) {
|
||||
r2(U . "order/pay/$router/$bill[plan_id]&stoken=" . _get('stoken'), 'e', 'Order Plan');
|
||||
} else {
|
||||
r2(U . "order/buy/$router/$bill[plan_id]", 'e', 'Order Plan');
|
||||
}
|
||||
} else {
|
||||
r2(U . "order/buy/$router/$bill[plan_id]", 'e', 'Order Plan');
|
||||
}
|
||||
r2(getUrl("order/gateway/$router/$bill[plan_id]"));
|
||||
}
|
||||
} else if (!empty(_get('extend'))) {
|
||||
if ($user['status'] != 'Active') {
|
||||
_alert(Lang::T('This account status') . ' : ' . Lang::T($user['status']), 'danger', "");
|
||||
}
|
||||
if (!$config['extend_expired']) {
|
||||
r2(U . 'home', 'e', "cannot extend");
|
||||
r2(getUrl('home'), 'e', "cannot extend");
|
||||
}
|
||||
if (!empty(App::getTokenValue(_get('stoken')))) {
|
||||
r2(U . 'home', 'e', "You already extend");
|
||||
r2(getUrl('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();
|
||||
@ -179,7 +171,7 @@ if (isset($_GET['recharge']) && !empty($_GET['recharge'])) {
|
||||
// is already extend
|
||||
$last = file_get_contents($path);
|
||||
if ($last == $m) {
|
||||
r2(U . 'home', 'e', "You already extend for this month");
|
||||
r2(getUrl('home'), 'e', "You already extend for this month");
|
||||
}
|
||||
}
|
||||
if ($tur['status'] != 'on') {
|
||||
@ -188,6 +180,8 @@ if (isset($_GET['recharge']) && !empty($_GET['recharge'])) {
|
||||
if ($_app_stage != 'demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
global $isChangePlan;
|
||||
$isChangePlan = true;
|
||||
(new $p['device'])->add_customer($user, $p);
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
@ -202,17 +196,17 @@ if (isset($_GET['recharge']) && !empty($_GET['recharge'])) {
|
||||
$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'] .
|
||||
_log("Customer $tur[customer_id] $user[fullname] ($tur[username]) extend for $days days", "Customer", $user['id']);
|
||||
Message::sendTelegram("#u$user[username] ($user[fullname]) #id$tur[customer_id] #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");
|
||||
r2(getUrl('home'), 's', "Extend until $expiration");
|
||||
} else {
|
||||
r2(U . 'home', 'e', "Plan is not expired");
|
||||
r2(getUrl('home'), 'e', "Plan is not expired");
|
||||
}
|
||||
} else {
|
||||
r2(U . 'home', 'e', "Plan Not Found or Not Active");
|
||||
r2(getUrl('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();
|
||||
@ -233,9 +227,9 @@ if (isset($_GET['recharge']) && !empty($_GET['recharge'])) {
|
||||
$bill->save();
|
||||
_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']);
|
||||
r2(getUrl('home'), 's', 'Success deactivate ' . $bill['namebp']);
|
||||
} else {
|
||||
r2(U . 'home', 'e', 'No Active Plan');
|
||||
r2(getUrl('home'), 'e', 'No Active Plan');
|
||||
}
|
||||
}
|
||||
|
||||
@ -250,10 +244,10 @@ if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'] && $_c['hs_auth_m
|
||||
require_once $dvc;
|
||||
if ($_GET['mikrotik'] == 'login') {
|
||||
(new $p['device'])->connect_customer($user, $_SESSION['nux-ip'], $_SESSION['nux-mac'], $bill['routers']);
|
||||
r2(U . 'home', 's', Lang::T('Login Request successfully'));
|
||||
r2(getUrl('home'), 's', Lang::T('Login Request successfully'));
|
||||
} else if ($_GET['mikrotik'] == 'logout') {
|
||||
(new $p['device'])->disconnect_customer($user, $bill['routers']);
|
||||
r2(U . 'home', 's', Lang::T('Logout Request successfully'));
|
||||
r2(getUrl('home'), 's', Lang::T('Logout Request successfully'));
|
||||
}
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
@ -262,7 +256,7 @@ if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'] && $_c['hs_auth_m
|
||||
}
|
||||
|
||||
if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'] && !empty($_SESSION['nux-hostname']) && $_c['hs_auth_method'] == 'hchap')) {
|
||||
$apkurl = (((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'onoff')|| $_SERVER['SERVER_PORT'] == 443)?'https':'http').'://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
|
||||
$apkurl = (((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'onoff') || $_SERVER['SERVER_PORT'] == 443) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
|
||||
$ui->assign('nux_mac', $_SESSION['nux-mac']);
|
||||
$ui->assign('nux_ip', $_SESSION['nux-ip']);
|
||||
$keys = explode('-', $_SESSION['nux-key']);
|
||||
@ -273,23 +267,23 @@ if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'] && !empty($_SESSI
|
||||
$ui->assign('hchap', $_GET['hchap']);
|
||||
$ui->assign('logged', $_GET['logged']);
|
||||
if ($_app_stage != 'demo') {
|
||||
if ($_GET['mikrotik'] == 'login') {
|
||||
r2(U . 'home&hchap=true', 's', Lang::T('Login Request successfully'));
|
||||
}
|
||||
$getmsg = $_GET['msg'];
|
||||
///get auth notification from mikrotik
|
||||
if($getmsg == 'Connected') {
|
||||
$msg .= Lang::T($getmsg);
|
||||
r2(U . 'home&logged=1', 's', $msg);
|
||||
} else if($getmsg){
|
||||
$msg .= Lang::T($getmsg);
|
||||
r2(U . 'home', 's', $msg);
|
||||
}
|
||||
if ($_GET['mikrotik'] == 'login') {
|
||||
r2(getUrl('home&hchap=true'), 's', Lang::T('Login Request successfully'));
|
||||
}
|
||||
$getmsg = $_GET['msg'];
|
||||
///get auth notification from mikrotik
|
||||
if ($getmsg == 'Connected') {
|
||||
$msg .= Lang::T($getmsg);
|
||||
r2(getUrl('home&logged=1'), 's', $msg);
|
||||
} else if ($getmsg) {
|
||||
$msg .= Lang::T($getmsg);
|
||||
r2(getUrl('home'), 's', $msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'] && !empty($_SESSION['nux-hostname']) && $_c['hs_auth_method'] == 'hchap')) {
|
||||
$apkurl = (((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'onoff')|| $_SERVER['SERVER_PORT'] == 443)?'https':'http').'://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
|
||||
$apkurl = (((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'onoff') || $_SERVER['SERVER_PORT'] == 443) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
|
||||
$ui->assign('nux_mac', $_SESSION['nux-mac']);
|
||||
$ui->assign('nux_ip', $_SESSION['nux-ip']);
|
||||
$keys = explode('-', $_SESSION['nux-key']);
|
||||
@ -300,29 +294,40 @@ if (!empty($_SESSION['nux-mac']) && !empty($_SESSION['nux-ip'] && !empty($_SESSI
|
||||
$ui->assign('hchap', $_GET['hchap']);
|
||||
$ui->assign('logged', $_GET['logged']);
|
||||
if ($_app_stage != 'demo') {
|
||||
if ($_GET['mikrotik'] == 'login') {
|
||||
r2(U . 'home&hchap=true', 's', Lang::T('Login Request successfully'));
|
||||
}
|
||||
$getmsg = $_GET['msg'];
|
||||
///get auth notification from mikrotik
|
||||
if($getmsg == 'Connected') {
|
||||
$msg .= Lang::T($getmsg);
|
||||
r2(U . 'home&logged=1', 's', $msg);
|
||||
} else if($getmsg){
|
||||
$msg .= Lang::T($getmsg);
|
||||
r2(U . 'home', 's', $msg);
|
||||
}
|
||||
if ($_GET['mikrotik'] == 'login') {
|
||||
r2(getUrl('home&hchap=true'), 's', Lang::T('Login Request successfully'));
|
||||
}
|
||||
$getmsg = $_GET['msg'];
|
||||
///get auth notification from mikrotik
|
||||
if ($getmsg == 'Connected') {
|
||||
$msg .= Lang::T($getmsg);
|
||||
r2(getUrl('home&logged=1'), 's', $msg);
|
||||
} else if ($getmsg) {
|
||||
$msg .= Lang::T($getmsg);
|
||||
r2(getUrl('home'), 's', $msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$widgets = ORM::for_table('tbl_widgets')->where("enabled", 1)->where('user', 'Customer')->order_by_asc("orders")->findArray();
|
||||
$count = count($widgets);
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
try{
|
||||
if(file_exists($WIDGET_PATH . DIRECTORY_SEPARATOR . 'customer' . DIRECTORY_SEPARATOR . $widgets[$i]['widget'].".php")){
|
||||
require_once $WIDGET_PATH . DIRECTORY_SEPARATOR . 'customer' . DIRECTORY_SEPARATOR . $widgets[$i]['widget'].".php";
|
||||
$widgets[$i]['content'] = (new $widgets[$i]['widget'])->getWidget($widgets[$i]);
|
||||
}else{
|
||||
$widgets[$i]['content'] = "Widget not found";
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
$widgets[$i]['content'] = $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
$ui->assign('widgets', $widgets);
|
||||
|
||||
$ui->assign('unpaid', ORM::for_table('tbl_payment_gateway')
|
||||
->where('username', $user['username'])
|
||||
->where('status', 1)
|
||||
->find_one());
|
||||
$ui->assign('code', alphanumeric(_get('code'), "-"));
|
||||
|
||||
$abills = User::getAttributes("Bill");
|
||||
$ui->assign('abills', $abills);
|
||||
|
||||
run_hook('view_customer_dashboard'); #HOOK
|
||||
$ui->display('user-ui/dashboard.tpl');
|
||||
$ui->display('customer/dashboard.tpl');
|
||||
|
27
system/controllers/invoices.php
Normal file
27
system/controllers/invoices.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
*
|
||||
**/
|
||||
|
||||
|
||||
_admin();
|
||||
$ui->assign('_title', Lang::T('Invoice Lists'));
|
||||
$ui->assign('_system_menu', 'reports');
|
||||
$action = $routes['1'];
|
||||
$ui->assign('_admin', $admin);
|
||||
|
||||
if (empty($action)) {
|
||||
$action = 'list';
|
||||
}
|
||||
switch ($action) {
|
||||
case 'list':
|
||||
$ui->assign('xheader', '<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.11.3/css/jquery.dataTables.min.css">');
|
||||
$ui->assign('invoices', Invoice::getAll());
|
||||
$ui->display('admin/invoices/list.tpl');
|
||||
break;
|
||||
default:
|
||||
$ui->display('admin/404.tpl');
|
||||
}
|
@ -11,7 +11,7 @@ if ($maintenance_mode == true) {
|
||||
}
|
||||
|
||||
if (User::getID()) {
|
||||
r2(U . 'home');
|
||||
r2(getUrl('home'));
|
||||
}
|
||||
|
||||
if (isset($routes['1'])) {
|
||||
@ -24,6 +24,11 @@ switch ($do) {
|
||||
case 'post':
|
||||
$username = _post('username');
|
||||
$password = _post('password');
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
_msglog('e', Lang::T('Invalid or Expired CSRF Token'));
|
||||
r2(getUrl('login'));
|
||||
}
|
||||
run_hook('customer_login'); #HOOK
|
||||
if ($username != '' and $password != '') {
|
||||
$d = ORM::for_table('tbl_customers')->where('username', $username)->find_one();
|
||||
@ -34,29 +39,41 @@ switch ($do) {
|
||||
}
|
||||
if (Password::_uverify($password, $d_pass) == true) {
|
||||
$_SESSION['uid'] = $d['id'];
|
||||
User::setCookie($d['id']);
|
||||
$token = User::setCookie($d['id']);
|
||||
$d->last_login = date('Y-m-d H:i:s');
|
||||
$d->save();
|
||||
_log($username . ' ' . Lang::T('Login Successful'), 'User', $d['id']);
|
||||
if ($isApi) {
|
||||
if ($token) {
|
||||
showResult(true, Lang::T('Login Successful'), ['token' => "u." . $token]);
|
||||
} else {
|
||||
showResult(false, Lang::T('Invalid Username or Password'));
|
||||
}
|
||||
}
|
||||
_alert(Lang::T('Login Successful'), 'success', "home");
|
||||
} else {
|
||||
_msglog('e', Lang::T('Invalid Username or Password'));
|
||||
_log($username . ' ' . Lang::T('Failed Login'), 'User');
|
||||
r2(U . 'login');
|
||||
r2(getUrl('login'));
|
||||
}
|
||||
} else {
|
||||
_msglog('e', Lang::T('Invalid Username or Password'));
|
||||
r2(U . 'login');
|
||||
r2(getUrl('login'));
|
||||
}
|
||||
} else {
|
||||
_msglog('e', Lang::T('Invalid Username or Password'));
|
||||
r2(U . 'login');
|
||||
r2(getUrl('login'));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'activation':
|
||||
if (!empty(_post('voucher_only'))) {
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
_msglog('e', Lang::T('Invalid or Expired CSRF Token'));
|
||||
r2(getUrl('login'));
|
||||
}
|
||||
$voucher = Text::alphanumeric(_post('voucher_only'), "-_.,");
|
||||
$tur = ORM::for_table('tbl_user_recharges')
|
||||
->where('username', $voucher)
|
||||
@ -86,7 +103,7 @@ switch ($do) {
|
||||
if (!empty($config['voucher_redirect'])) {
|
||||
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, now you can login"));
|
||||
} else {
|
||||
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
|
||||
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
|
||||
}
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
@ -95,13 +112,13 @@ switch ($do) {
|
||||
if (!empty($config['voucher_redirect'])) {
|
||||
_alert(Lang::T("Voucher activation success, now you can login"), 'danger', $config['voucher_redirect']);
|
||||
} else {
|
||||
r2(U . "login", 's', Lang::T("Voucher activation success, you are connected to internet"));
|
||||
r2(getUrl('login'), 's', Lang::T("Voucher activation success, you are connected to internet"));
|
||||
}
|
||||
} else {
|
||||
_alert(Lang::T('Internet Plan Expired'), 'danger', "login");
|
||||
}
|
||||
} else {
|
||||
$v = ORM::for_table('tbl_voucher')->whereRaw("BINARY `code` = '$voucher'")->find_one();
|
||||
$v = ORM::for_table('tbl_voucher')->whereRaw("BINARY code = '$voucher'")->find_one();
|
||||
if (!$v) {
|
||||
_alert(Lang::T('Voucher invalid'), 'danger', "login");
|
||||
}
|
||||
@ -131,7 +148,7 @@ switch ($do) {
|
||||
if (!empty($config['voucher_redirect'])) {
|
||||
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, now you can login"));
|
||||
} else {
|
||||
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
|
||||
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
|
||||
}
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
@ -140,7 +157,7 @@ switch ($do) {
|
||||
if (!empty($config['voucher_redirect'])) {
|
||||
_alert(Lang::T("Voucher activation success, now you can login"), 'danger', $config['voucher_redirect']);
|
||||
} else {
|
||||
r2(U . "login", 's', Lang::T("Voucher activation success, you are connected to internet"));
|
||||
r2(getUrl('login'), 's', Lang::T("Voucher activation success, you are connected to internet"));
|
||||
}
|
||||
} else {
|
||||
_alert(Lang::T('Internet Plan Expired'), 'danger', "login");
|
||||
@ -158,7 +175,7 @@ switch ($do) {
|
||||
} else {
|
||||
$voucher = Text::alphanumeric(_post('voucher'), "-_.,");
|
||||
$username = _post('username');
|
||||
$v1 = ORM::for_table('tbl_voucher')->whereRaw("BINARY `code` = '$voucher'")->find_one();
|
||||
$v1 = ORM::for_table('tbl_voucher')->whereRaw("BINARY code = '$voucher'")->find_one();
|
||||
if ($v1) {
|
||||
// voucher exists, check customer exists or not
|
||||
$user = ORM::for_table('tbl_customers')->where('username', $username)->find_one();
|
||||
@ -173,11 +190,11 @@ switch ($do) {
|
||||
if ($d->save()) {
|
||||
$user = ORM::for_table('tbl_customers')->where('username', $username)->find_one($d->id());
|
||||
if (!$user) {
|
||||
r2(U . 'login', 'e', Lang::T('Voucher activation failed'));
|
||||
r2(getUrl('login'), 'e', Lang::T('Voucher activation failed'));
|
||||
}
|
||||
} else {
|
||||
_alert(Lang::T('Login Successful'), 'success', "dashboard");
|
||||
r2(U . 'login', 'e', Lang::T('Voucher activation failed') . '.');
|
||||
r2(getUrl('login'), 'e', Lang::T('Voucher activation failed') . '.');
|
||||
}
|
||||
}
|
||||
if ($v1['status'] == 0) {
|
||||
@ -205,7 +222,7 @@ switch ($do) {
|
||||
if (!empty($config['voucher_redirect'])) {
|
||||
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, now you can login"));
|
||||
} else {
|
||||
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
|
||||
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
|
||||
}
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
@ -214,26 +231,26 @@ switch ($do) {
|
||||
if (!empty($config['voucher_redirect'])) {
|
||||
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, you are connected to internet"));
|
||||
} else {
|
||||
r2(U . "login", 's', Lang::T("Voucher activation success, you are connected to internet"));
|
||||
r2(getUrl('login'), 's', Lang::T("Voucher activation success, you are connected to internet"));
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
if (!empty($config['voucher_redirect'])) {
|
||||
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, now you can login"));
|
||||
} else {
|
||||
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
|
||||
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($config['voucher_redirect'])) {
|
||||
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, now you can login"));
|
||||
} else {
|
||||
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
|
||||
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
|
||||
}
|
||||
} else {
|
||||
// if failed to recharge, restore old password
|
||||
$user->password = $oldPass;
|
||||
$user->save();
|
||||
r2(U . 'login', 'e', Lang::T("Failed to activate voucher"));
|
||||
r2(getUrl('login'), 'e', Lang::T("Failed to activate voucher"));
|
||||
}
|
||||
} else {
|
||||
// used voucher
|
||||
@ -252,7 +269,7 @@ switch ($do) {
|
||||
if (!empty($config['voucher_redirect'])) {
|
||||
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, now you can login"));
|
||||
} else {
|
||||
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
|
||||
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
|
||||
}
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
@ -261,39 +278,80 @@ switch ($do) {
|
||||
if (!empty($config['voucher_redirect'])) {
|
||||
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, you are connected to internet"));
|
||||
} else {
|
||||
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
|
||||
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
if (!empty($config['voucher_redirect'])) {
|
||||
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, now you can login"));
|
||||
} else {
|
||||
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
|
||||
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!empty($config['voucher_redirect'])) {
|
||||
r2($config['voucher_redirect'], 's', Lang::T("Voucher activation success, you are connected to internet"));
|
||||
} else {
|
||||
r2(U . "login", 's', Lang::T("Voucher activation success, now you can login"));
|
||||
r2(getUrl('login'), 's', Lang::T("Voucher activation success, now you can login"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// voucher used by other customer
|
||||
r2(U . 'login', 'e', Lang::T('Voucher Not Valid'));
|
||||
r2(getUrl('login'), 'e', Lang::T('Voucher Not Valid'));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_msglog('e', Lang::T('Invalid Username or Password'));
|
||||
r2(U . 'login');
|
||||
r2(getUrl('login'));
|
||||
}
|
||||
}
|
||||
default:
|
||||
run_hook('customer_view_login'); #HOOK
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
if ($config['disable_registration'] == 'yes') {
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->assign('_title', Lang::T('Activation'));
|
||||
$ui->assign('code', alphanumeric(_get('code'), "-"));
|
||||
$ui->display('user-ui/login-noreg.tpl');
|
||||
$ui->display('customer/login-noreg.tpl');
|
||||
} else {
|
||||
$ui->display('user-ui/login.tpl');
|
||||
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
|
||||
if (!empty($config['login_page_logo']) && file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_logo'])) {
|
||||
$login_logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_logo'];
|
||||
} elseif (file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'login-logo.png')) {
|
||||
$login_logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'login-logo.png';
|
||||
} else {
|
||||
$login_logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'login-logo.default.png';
|
||||
}
|
||||
|
||||
if (!empty($config['login_page_wallpaper']) && file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_wallpaper'])) {
|
||||
$wallpaper = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_wallpaper'];
|
||||
} elseif (file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'wallpaper.png')) {
|
||||
$wallpaper = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'wallpaper.png';
|
||||
} else {
|
||||
$wallpaper = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'wallpaper.default.png';
|
||||
}
|
||||
|
||||
if (!empty($config['login_page_favicon']) && file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_favicon'])) {
|
||||
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_favicon'];
|
||||
} elseif (file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.png')) {
|
||||
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.png';
|
||||
} else {
|
||||
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.default.png';
|
||||
}
|
||||
|
||||
$ui->assign('login_logo', $login_logo);
|
||||
$ui->assign('wallpaper', $wallpaper);
|
||||
$ui->assign('favicon', $favicon);
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->assign('_title', Lang::T('Login'));
|
||||
switch ($config['login_page_type']) {
|
||||
case 'custom':
|
||||
$ui->display('customer/login-custom-' . $config['login_Page_template'] . '.tpl');
|
||||
break;
|
||||
default:
|
||||
$ui->display('customer/login.tpl');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -1,12 +1,17 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
**/
|
||||
|
||||
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
|
||||
header("Expires: Tue, 01 Jan 2000 00:00:00 GMT");
|
||||
header("Pragma: no-cache");
|
||||
|
||||
run_hook('customer_logout'); #HOOK
|
||||
if (session_status() == PHP_SESSION_NONE) session_start();
|
||||
Admin::removeCookie();
|
||||
User::removeCookie();
|
||||
session_destroy();
|
||||
_alert(Lang::T('Logout Successful'),'warning', "login");
|
||||
_alert(Lang::T('Logout Successful'), 'warning', "login");
|
||||
|
@ -80,12 +80,45 @@ switch ($action) {
|
||||
}
|
||||
break;
|
||||
|
||||
case 'message-csv':
|
||||
$logs = ORM::for_table('tbl_message_logs')
|
||||
->select('id')
|
||||
->select('message_type')
|
||||
->select('recipient')
|
||||
->select('message_content')
|
||||
->select('status')
|
||||
->select('error_message')
|
||||
->select('sent_at')
|
||||
->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="message-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');
|
||||
if (!empty($keep)) {
|
||||
ORM::raw_execute("DELETE FROM tbl_logs WHERE UNIX_TIMESTAMP(date) < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL $keep DAY))");
|
||||
r2(U . "logs/list/", 's', "Delete logs older than $keep days");
|
||||
r2(getUrl('logs/list/'), 's', "Delete logs older than $keep days");
|
||||
}
|
||||
if ($q != '') {
|
||||
$query = ORM::for_table('tbl_logs')->where_like('description', '%' . $q . '%')->order_by_desc('id');
|
||||
@ -97,14 +130,14 @@ switch ($action) {
|
||||
|
||||
$ui->assign('d', $d);
|
||||
$ui->assign('q', $q);
|
||||
$ui->display('logs.tpl');
|
||||
$ui->display('admin/logs/system.tpl');
|
||||
break;
|
||||
case 'radius':
|
||||
$q = (_post('q') ? _post('q') : _get('q'));
|
||||
$keep = _post('keep');
|
||||
if (!empty($keep)) {
|
||||
ORM::raw_execute("DELETE FROM radpostauth WHERE UNIX_TIMESTAMP(authdate) < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL $keep DAY))", [], 'radius');
|
||||
r2(U . "logs/radius/", 's', "Delete logs older than $keep days");
|
||||
r2(getUrl('logs/radius/'), 's', "Delete logs older than $keep days");
|
||||
}
|
||||
if ($q != '') {
|
||||
$query = ORM::for_table('radpostauth', 'radius')->where_like('username', '%' . $q . '%')->order_by_desc('id');
|
||||
@ -116,10 +149,37 @@ switch ($action) {
|
||||
|
||||
$ui->assign('d', $d);
|
||||
$ui->assign('q', $q);
|
||||
$ui->display('logs-radius.tpl');
|
||||
$ui->display('admin/logs/radius.tpl');
|
||||
break;
|
||||
|
||||
case 'message':
|
||||
$q = _post('q') ?: _get('q');
|
||||
$keep = (int) _post('keep');
|
||||
if (!empty($keep)) {
|
||||
ORM::raw_execute("DELETE FROM tbl_message_logs WHERE UNIX_TIMESTAMP(sent_at) < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL $keep DAY))");
|
||||
r2(getUrl('logs/message/'), 's', "Deleted logs older than $keep days");
|
||||
}
|
||||
|
||||
if ($q !== null && $q !== '') {
|
||||
$query = ORM::for_table('tbl_message_logs')
|
||||
->whereRaw("message_type LIKE '%$q%' OR recipient LIKE '%$q%' OR message_content LIKE '%$q%' OR status LIKE '%$q%' OR error_message LIKE '%$q%'")
|
||||
->order_by_desc('sent_at');
|
||||
$d = Paginator::findMany($query, ['q' => $q]);
|
||||
} else {
|
||||
$query = ORM::for_table('tbl_message_logs')->order_by_desc('sent_at');
|
||||
$d = Paginator::findMany($query);
|
||||
}
|
||||
|
||||
if ($d) {
|
||||
$ui->assign('d', $d);
|
||||
} else {
|
||||
$ui->assign('d', []);
|
||||
}
|
||||
|
||||
$ui->assign('q', $q);
|
||||
$ui->display('admin/logs/message.tpl');
|
||||
break;
|
||||
|
||||
default:
|
||||
r2(U . 'logs/list/', 's', '');
|
||||
r2(getUrl('logs/list/'), 's', '');
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ switch ($action) {
|
||||
case 'view':
|
||||
$mail = ORM::for_table('tbl_customers_inbox')->where('customer_id', $user['id'])->find_one($routes['2']);
|
||||
if(!$mail){
|
||||
r2(U. 'mail', 'e', Lang::T('Message Not Found'));
|
||||
r2(getUrl('mail'), 'e', Lang::T('Message Not Found'));
|
||||
}
|
||||
if($mail['date_read'] == null){
|
||||
$mail->date_read = date('Y-m-d H:i:s');
|
||||
@ -29,14 +29,14 @@ switch ($action) {
|
||||
$ui->assign('tipe', 'view');
|
||||
$ui->assign('_system_menu', 'inbox');
|
||||
$ui->assign('_title', Lang::T('Inbox'));
|
||||
$ui->display('user-ui/inbox.tpl');
|
||||
$ui->display('customer/inbox.tpl');
|
||||
break;
|
||||
case 'delete':
|
||||
if($routes['2']){
|
||||
if(ORM::for_table('tbl_customers_inbox')->where('customer_id', $user['id'])->where('id', $routes['2'])->find_one()->delete()){
|
||||
r2(U. 'mail', 's', Lang::T('Mail Deleted Successfully'));
|
||||
r2(getUrl('mail'), 's', Lang::T('Mail Deleted Successfully'));
|
||||
}else{
|
||||
r2(U. 'home', 'e', Lang::T('Failed to Delete Message'));
|
||||
r2(getUrl('home'), 'e', Lang::T('Failed to Delete Message'));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -57,5 +57,5 @@ switch ($action) {
|
||||
$ui->assign('mails', $mails);
|
||||
$ui->assign('_system_menu', 'inbox');
|
||||
$ui->assign('_title', Lang::T('Inbox'));
|
||||
$ui->display('user-ui/inbox.tpl');
|
||||
$ui->display('customer/inbox.tpl');
|
||||
}
|
@ -15,6 +15,9 @@ if (empty($action)) {
|
||||
$action = 'customer';
|
||||
}
|
||||
|
||||
$ui->assign('xheader', '<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css">');
|
||||
$ui->assign('xfooter', '<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>');
|
||||
|
||||
switch ($action) {
|
||||
case 'customer':
|
||||
if(!empty(_req('search'))){
|
||||
@ -42,13 +45,23 @@ switch ($action) {
|
||||
}
|
||||
$ui->assign('search', $search);
|
||||
$ui->assign('customers', $customerData);
|
||||
$ui->assign('xheader', '<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css">');
|
||||
$ui->assign('_title', Lang::T('Customer Geo Location Information'));
|
||||
$ui->assign('xfooter', '<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>');
|
||||
$ui->display('customers-map.tpl');
|
||||
$ui->display('admin/maps/customers.tpl');
|
||||
break;
|
||||
|
||||
case 'routers':
|
||||
$name = _post('name');
|
||||
$query = ORM::for_table('tbl_routers')->where_not_equal('coordinates', '')->order_by_desc('id');
|
||||
$query->selects(['id', 'name', 'coordinates', 'description', 'coverage', 'enabled']);
|
||||
if ($name != '') {
|
||||
$query->where_like('name', '%' . $name . '%');
|
||||
}
|
||||
$d = Paginator::findMany($query, ['name' => $name], '20', '', true);
|
||||
$ui->assign('name', $name);
|
||||
$ui->assign('d', $d);
|
||||
$ui->assign('_title', Lang::T('Routers Geo Location Information'));
|
||||
$ui->display('admin/maps/routers.tpl');
|
||||
break;
|
||||
default:
|
||||
r2(U . 'map/customer', 'e', 'action not defined');
|
||||
r2(getUrl('map/customer'), 'e', 'action not defined');
|
||||
break;
|
||||
}
|
@ -22,6 +22,8 @@ switch ($action) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
|
||||
$appUrl = APP_URL;
|
||||
|
||||
$select2_customer = <<<EOT
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
@ -30,9 +32,9 @@ document.addEventListener("DOMContentLoaded", function(event) {
|
||||
ajax: {
|
||||
url: function(params) {
|
||||
if(params.term != undefined){
|
||||
return './index.php?_route=autoload/customer_select2&s='+params.term;
|
||||
return '{$appUrl}/?_route=autoload/customer_select2&s='+params.term;
|
||||
}else{
|
||||
return './index.php?_route=autoload/customer_select2';
|
||||
return '{$appUrl}/?_route=autoload/customer_select2';
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -46,7 +48,7 @@ EOT;
|
||||
$id = $routes['2'];
|
||||
$ui->assign('id', $id);
|
||||
$ui->assign('xfooter', $select2_customer);
|
||||
$ui->display('message.tpl');
|
||||
$ui->display('admin/message/single.tpl');
|
||||
break;
|
||||
|
||||
case 'send-post':
|
||||
@ -55,40 +57,79 @@ EOT;
|
||||
_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'];
|
||||
$id_customer = $_POST['id_customer'] ?? '';
|
||||
$message = $_POST['message'] ?? '';
|
||||
$via = $_POST['via'] ?? '';
|
||||
$subject = $_POST['subject'] ?? '';
|
||||
|
||||
// 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);
|
||||
// Validate subject based on the selected channel
|
||||
if (($via === 'all' || $via === 'email' || $via === 'inbox') && empty($subject)) {
|
||||
r2(getUrl('message/send'), 'e', LANG::T('Subject is required to send message using') . ' ' . $via . '.');
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (empty($id_customer) || empty($message) || empty($via)) {
|
||||
r2(getUrl('message/send'), 'e', Lang::T('Customer, Message, and Channel are required'));
|
||||
}
|
||||
|
||||
$customer = ORM::for_table('tbl_customers')->find_one($id_customer);
|
||||
if (!$customer) {
|
||||
r2(getUrl('message/send'), 'e', Lang::T('Customer not found'));
|
||||
}
|
||||
|
||||
//Send the message
|
||||
if ($via == 'sms' || $via == 'both') {
|
||||
$smsSent = Message::sendSMS($c['phonenumber'], $message);
|
||||
}
|
||||
// Replace placeholders in message and subject
|
||||
$currentMessage = str_replace(
|
||||
['[[name]]', '[[user_name]]', '[[phone]]', '[[company_name]]'],
|
||||
[$customer['fullname'], $customer['username'], $customer['phonenumber'], $config['CompanyName']],
|
||||
$message
|
||||
);
|
||||
|
||||
if ($via == 'wa' || $via == 'both') {
|
||||
$waSent = Message::sendWhatsapp($c['phonenumber'], $message);
|
||||
}
|
||||
$currentSubject = str_replace(
|
||||
['[[name]]', '[[user_name]]', '[[phone]]', '[[company_name]]'],
|
||||
[$customer['fullname'], $customer['username'], $customer['phonenumber'], $config['CompanyName']],
|
||||
$subject
|
||||
);
|
||||
|
||||
if (isset($smsSent) || isset($waSent)) {
|
||||
r2(U . 'message/send', 's', Lang::T('Message Sent Successfully'));
|
||||
if (strpos($message, '[[payment_link]]') !== false) {
|
||||
$token = User::generateToken($customer['id'], 1);
|
||||
if (!empty($token['token'])) {
|
||||
$tur = ORM::for_table('tbl_user_recharges')
|
||||
->where('customer_id', $customer['id'])
|
||||
->find_one();
|
||||
if ($tur) {
|
||||
$url = '?_route=home&recharge=' . $tur['id'] . '&uid=' . urlencode($token['token']);
|
||||
$currentMessage = str_replace('[[payment_link]]', $url, $currentMessage);
|
||||
}
|
||||
} else {
|
||||
r2(U . 'message/send', 'e', Lang::T('Failed to send message'));
|
||||
$currentMessage = str_replace('[[payment_link]]', '', $currentMessage);
|
||||
}
|
||||
}
|
||||
|
||||
// Send the message through the selected channels
|
||||
$smsSent = $waSent = $emailSent = $inboxSent = false;
|
||||
|
||||
if ($via === 'sms' || $via === 'both' || $via === 'all') {
|
||||
$smsSent = Message::sendSMS($customer['phonenumber'], $currentSubject);
|
||||
}
|
||||
|
||||
if ($via === 'wa' || $via === 'both' || $via === 'all') {
|
||||
$waSent = Message::sendWhatsapp($customer['phonenumber'], $currentSubject);
|
||||
}
|
||||
|
||||
if ($via === 'email' || $via === 'all') {
|
||||
$emailSent = Message::sendEmail($customer['email'], $currentSubject, $currentMessage);
|
||||
}
|
||||
|
||||
if ($via === 'inbox' || $via === 'all') {
|
||||
$inboxSent = Message::addToInbox($customer['id'], $currentSubject, $currentMessage, 'Admin');
|
||||
}
|
||||
|
||||
// Check if any message was sent successfully
|
||||
if ($smsSent || $waSent || $emailSent || $inboxSent) {
|
||||
r2(getUrl('message/send'), 's', Lang::T('Message Sent Successfully'));
|
||||
} else {
|
||||
r2(getUrl('message/send'), 'e', Lang::T('Failed to send message'));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'send_bulk':
|
||||
@ -96,143 +137,362 @@ EOT;
|
||||
_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'];
|
||||
$ui->assign('routers', ORM::forTable('tbl_routers')->where('enabled', '1')->find_many());
|
||||
$ui->display('admin/message/bulk.tpl');
|
||||
break;
|
||||
|
||||
// Initialize counters
|
||||
case 'send_bulk_ajax':
|
||||
// Check user permissions
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) {
|
||||
die(json_encode(['status' => 'error', 'message' => 'Permission denied']));
|
||||
}
|
||||
|
||||
set_time_limit(0);
|
||||
|
||||
// Get request parameters
|
||||
$group = $_REQUEST['group'] ?? '';
|
||||
$message = $_REQUEST['message'] ?? '';
|
||||
$via = $_REQUEST['via'] ?? '';
|
||||
$batch = $_REQUEST['batch'] ?? 100;
|
||||
$page = $_REQUEST['page'] ?? 0;
|
||||
$router = $_REQUEST['router'] ?? null;
|
||||
$test = isset($_REQUEST['test']) && $_REQUEST['test'] === 'on';
|
||||
$service = $_REQUEST['service'] ?? '';
|
||||
$subject = $_REQUEST['subject'] ?? '';
|
||||
|
||||
if (empty($group) || empty($message) || empty($via) || empty($service)) {
|
||||
die(json_encode(['status' => 'error', 'message' => LANG::T('All fields are required')]));
|
||||
}
|
||||
|
||||
if (in_array($via, ['all', 'email', 'inbox']) && empty($subject)) {
|
||||
die(json_encode(['status' => 'error', 'message' => LANG::T('Subject is required to send message using') . ' ' . $via . '.']));
|
||||
}
|
||||
|
||||
// Get batch of customers based on group
|
||||
$startpoint = $page * $batch;
|
||||
$customers = [];
|
||||
$totalCustomers = 0;
|
||||
|
||||
if (isset($router) && !empty($router)) {
|
||||
switch ($router) {
|
||||
case 'radius':
|
||||
$routerName = 'Radius';
|
||||
break;
|
||||
default:
|
||||
$router = ORM::for_table('tbl_routers')->find_one($router);
|
||||
if (!$router) {
|
||||
die(json_encode(['status' => 'error', 'message' => LANG::T('Invalid router')]));
|
||||
}
|
||||
$routerName = $router->name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($router) && !empty($router)) {
|
||||
$query = ORM::for_table('tbl_user_recharges')
|
||||
->left_outer_join('tbl_customers', 'tbl_user_recharges.customer_id = tbl_customers.id')
|
||||
->where('tbl_user_recharges.routers', $routerName);
|
||||
|
||||
switch ($service) {
|
||||
case 'all':
|
||||
break;
|
||||
default:
|
||||
$validServices = ['PPPoE', 'Hotspot', 'VPN'];
|
||||
if (in_array($service, $validServices)) {
|
||||
$query->where('type', $service);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$totalCustomers = $query->count();
|
||||
|
||||
$query->offset($startpoint)
|
||||
->limit($batch);
|
||||
|
||||
switch ($group) {
|
||||
case 'all':
|
||||
break;
|
||||
case 'new':
|
||||
$query->where_raw("DATE(recharged_on) >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)");
|
||||
break;
|
||||
case 'expired':
|
||||
$query->where('tbl_user_recharges.status', 'off');
|
||||
break;
|
||||
case 'active':
|
||||
$query->where('tbl_user_recharges.status', 'on');
|
||||
break;
|
||||
}
|
||||
|
||||
// Fetch the customers
|
||||
$query->selects([
|
||||
['tbl_customers.phonenumber', 'phonenumber'],
|
||||
['tbl_user_recharges.customer_id', 'customer_id'],
|
||||
['tbl_customers.fullname', 'fullname'],
|
||||
['tbl_customers.username', 'username'],
|
||||
['tbl_customers.email', 'email'],
|
||||
['tbl_customers.service_type', 'service_type'],
|
||||
]);
|
||||
$customers = $query->find_array();
|
||||
} else {
|
||||
switch ($group) {
|
||||
case 'all':
|
||||
$totalCustomersQuery = ORM::for_table('tbl_customers');
|
||||
|
||||
switch ($service) {
|
||||
case 'all':
|
||||
break;
|
||||
default:
|
||||
$validServices = ['PPPoE', 'Hotspot', 'VPN'];
|
||||
if (in_array($service, $validServices)) {
|
||||
$totalCustomersQuery->where('service_type', $service);
|
||||
}
|
||||
break;
|
||||
}
|
||||
$totalCustomers = $totalCustomersQuery->count();
|
||||
$customers = $totalCustomersQuery->offset($startpoint)->limit($batch)->find_array();
|
||||
break;
|
||||
|
||||
case 'new':
|
||||
$totalCustomersQuery = ORM::for_table('tbl_customers')
|
||||
->where_raw("DATE(created_at) >= DATE_SUB(CURDATE(), INTERVAL 1 MONTH)");
|
||||
|
||||
switch ($service) {
|
||||
case 'all':
|
||||
break;
|
||||
default:
|
||||
$validServices = ['PPPoE', 'Hotspot', 'VPN'];
|
||||
if (in_array($service, $validServices)) {
|
||||
$totalCustomersQuery->where('service_type', $service);
|
||||
}
|
||||
break;
|
||||
}
|
||||
$totalCustomers = $totalCustomersQuery->count();
|
||||
$customers = $totalCustomersQuery->offset($startpoint)->limit($batch)->find_array();
|
||||
break;
|
||||
|
||||
case 'expired':
|
||||
$totalCustomersQuery = ORM::for_table('tbl_user_recharges')
|
||||
->where('status', 'off');
|
||||
|
||||
switch ($service) {
|
||||
case 'all':
|
||||
break;
|
||||
default:
|
||||
$validServices = ['PPPoE', 'Hotspot', 'VPN'];
|
||||
if (in_array($service, $validServices)) {
|
||||
$totalCustomersQuery->where('type', $service);
|
||||
}
|
||||
break;
|
||||
}
|
||||
$totalCustomers = $totalCustomersQuery->count();
|
||||
$customers = $totalCustomersQuery->select('customer_id')->offset($startpoint)->limit($batch)->find_array();
|
||||
break;
|
||||
|
||||
case 'active':
|
||||
$totalCustomersQuery = ORM::for_table('tbl_user_recharges')
|
||||
->where('status', 'on');
|
||||
|
||||
switch ($service) {
|
||||
case 'all':
|
||||
break;
|
||||
default:
|
||||
$validServices = ['PPPoE', 'Hotspot', 'VPN'];
|
||||
if (in_array($service, $validServices)) {
|
||||
$totalCustomersQuery->where('type', $service);
|
||||
}
|
||||
break;
|
||||
}
|
||||
$totalCustomers = $totalCustomersQuery->count();
|
||||
$customers = $totalCustomersQuery->select('customer_id')->offset($startpoint)->limit($batch)->find_array(); // Get customer data
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure $customers is always an array
|
||||
if (!$customers) {
|
||||
$customers = [];
|
||||
}
|
||||
|
||||
// Send messages
|
||||
$totalSMSSent = 0;
|
||||
$totalSMSFailed = 0;
|
||||
$totalWhatsappSent = 0;
|
||||
$totalWhatsappFailed = 0;
|
||||
$totalEmailSent = 0;
|
||||
$totalEmailFailed = 0;
|
||||
$totalInboxSent = 0;
|
||||
$totalInboxFailed = 0;
|
||||
$batchStatus = [];
|
||||
//$subject = $config['CompanyName'] . ' ' . Lang::T('Notification Message');
|
||||
$form = 'Admin';
|
||||
|
||||
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'));
|
||||
foreach ($customers as $customer) {
|
||||
$currentMessage = str_replace(
|
||||
['[[name]]', '[[user_name]]', '[[phone]]', '[[company_name]]'],
|
||||
[$customer['fullname'], $customer['username'], $customer['phonenumber'], $config['CompanyName']],
|
||||
$message
|
||||
);
|
||||
|
||||
$currentSubject = str_replace(
|
||||
['[[name]]', '[[user_name]]', '[[phone]]', '[[company_name]]'],
|
||||
[$customer['fullname'], $customer['username'], $customer['phonenumber'], $config['CompanyName']],
|
||||
$subject
|
||||
);
|
||||
|
||||
$phoneNumber = preg_replace('/\D/', '', $customer['phonenumber']);
|
||||
|
||||
if (empty($phoneNumber)) {
|
||||
$batchStatus[] = [
|
||||
'name' => $customer['fullname'],
|
||||
'phone' => '',
|
||||
'status' => 'No Phone Number'
|
||||
];
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($test) {
|
||||
$batchStatus[] = [
|
||||
'name' => $customer['fullname'],
|
||||
'channel' => 'Test Channel',
|
||||
'status' => 'Test Mode',
|
||||
'message' => $currentMessage,
|
||||
'service' => $service,
|
||||
'router' => $routerName,
|
||||
];
|
||||
} 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;
|
||||
if ($via === 'sms' || $via === 'both' || $via === 'all') {
|
||||
if (Message::sendSMS($customer['phonenumber'], $currentMessage)) {
|
||||
$totalSMSSent++;
|
||||
$batchStatus[] = ['name' => $customer['fullname'], 'phone' => $customer['phonenumber'], 'status' => 'SMS Sent', 'message' => $currentMessage];
|
||||
} else {
|
||||
$totalSMSFailed++;
|
||||
$batchStatus[] = ['name' => $customer['fullname'], 'phone' => $customer['phonenumber'], 'status' => 'SMS Failed', 'message' => $currentMessage];
|
||||
}
|
||||
$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'
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($via === 'wa' || $via == 'both' || $via === 'all') {
|
||||
if (Message::sendWhatsapp($customer['phonenumber'], $currentMessage)) {
|
||||
$totalWhatsappSent++;
|
||||
$batchStatus[] = ['name' => $customer['fullname'], 'channel' => $customer['phonenumber'], 'status' => 'WhatsApp Sent', 'message' => $currentMessage];
|
||||
} else {
|
||||
$totalWhatsappFailed++;
|
||||
$batchStatus[] = ['name' => $customer['fullname'], 'channel' => $customer['phonenumber'], 'status' => 'WhatsApp Failed', 'message' => $currentMessage];
|
||||
}
|
||||
}
|
||||
|
||||
// Introduce a delay between each batch
|
||||
if ($batchIndex < $totalBatches - 1) {
|
||||
sleep($delay);
|
||||
if ($via === 'email' || $via === 'all') {
|
||||
if (Message::sendEmail($customer['email'], $currentSubject, $currentMessage)) {
|
||||
$totalEmailSent++;
|
||||
$batchStatus[] = ['name' => $customer['fullname'], 'channel' => $customer['email'], 'status' => 'Email Sent', 'message' => $currentMessage];
|
||||
} else {
|
||||
$totalEmailFailed++;
|
||||
$batchStatus[] = ['name' => $customer['fullname'], 'channel' => $customer['email'], 'status' => 'Email Failed', 'message' => $currentMessage];
|
||||
}
|
||||
}
|
||||
|
||||
if ($via === 'inbox' || $via === 'all') {
|
||||
if (Message::addToInbox($customer['customer_id'], $currentSubject, $currentMessage, $form)) {
|
||||
$totalInboxSent++;
|
||||
$batchStatus[] = ['name' => $customer['fullname'], 'channel' => 'Inbox', 'status' => 'Inbox Message Sent', 'message' => $currentMessage];
|
||||
} else {
|
||||
$totalInboxFailed++;
|
||||
$batchStatus[] = ['name' => $customer['fullname'], 'channel' => 'Inbox', 'status' => 'Inbox Message Failed', 'message' => $currentMessage];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$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');
|
||||
|
||||
// Calculate if there are more customers to process
|
||||
$hasMore = ($startpoint + $batch) < $totalCustomers;
|
||||
|
||||
// Return JSON response
|
||||
echo json_encode([
|
||||
'status' => 'success',
|
||||
'page' => $page + 1,
|
||||
'batchStatus' => $batchStatus,
|
||||
'message' => $currentMessage,
|
||||
'totalSent' => $totalSMSSent + $totalWhatsappSent + $totalEmailSent + $totalInboxSent,
|
||||
'totalFailed' => $totalSMSFailed + $totalWhatsappFailed + $totalEmailFailed + $totalInboxFailed,
|
||||
'hasMore' => $hasMore,
|
||||
'service' => $service,
|
||||
'router' => $routerName,
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'send_bulk_selected':
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// Set headers
|
||||
header('Content-Type: application/json');
|
||||
header('Cache-Control: no-cache, no-store, must-revalidate');
|
||||
|
||||
// Get the posted data
|
||||
$customerIds = $_POST['customer_ids'] ?? [];
|
||||
$via = $_POST['message_type'] ?? '';
|
||||
$subject = $_POST['subject'] ?? '';
|
||||
$message = isset($_POST['message']) ? trim($_POST['message']) : '';
|
||||
if (empty($customerIds) || empty($message) || empty($via)) {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T('Invalid customer IDs, Message, or Message Type.')]);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($via === 'all' || $via === 'email' || $via === 'inbox' && empty($subject)) {
|
||||
die(json_encode(['status' => 'error', 'message' => LANG::T('Subject is required to send message using') . ' ' . $via . '.']));
|
||||
}
|
||||
|
||||
// Prepare to send messages
|
||||
$sentCount = 0;
|
||||
$failedCount = 0;
|
||||
$form = 'Admin';
|
||||
|
||||
foreach ($customerIds as $customerId) {
|
||||
$customer = ORM::for_table('tbl_customers')->where('id', $customerId)->find_one();
|
||||
if ($customer) {
|
||||
$messageSent = false;
|
||||
|
||||
// Check the message type and send accordingly
|
||||
try {
|
||||
if ($via === 'sms' || $via === 'all') {
|
||||
$messageSent = Message::sendSMS($customer['phonenumber'], $message);
|
||||
}
|
||||
if (!$messageSent && ($via === 'wa' || $via === 'all')) {
|
||||
$messageSent = Message::sendWhatsapp($customer['phonenumber'], $message);
|
||||
}
|
||||
if (!$messageSent && ($via === 'inbox' || $via === 'all')) {
|
||||
Message::addToInbox($customer['id'], $subject, $message, $form);
|
||||
$messageSent = true;
|
||||
}
|
||||
if (!$messageSent && ($via === 'email' || $via === 'all')) {
|
||||
$messageSent = Message::sendEmail($customer['email'], $subject, $message);
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
$messageSent = false;
|
||||
$failedCount++;
|
||||
sendTelegram('Failed to send message to ' . $e->getMessage());
|
||||
_log('Failed to send message to ' . $customer['fullname'] . ': ' . $e->getMessage());
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($messageSent) {
|
||||
$sentCount++;
|
||||
} else {
|
||||
$failedCount++;
|
||||
}
|
||||
} else {
|
||||
$failedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare the response
|
||||
echo json_encode([
|
||||
'status' => 'success',
|
||||
'totalSent' => $sentCount,
|
||||
'totalFailed' => $failedCount
|
||||
]);
|
||||
} else {
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T('Invalid request method.')]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
r2(U . 'message/send_sms', 'e', 'action not defined');
|
||||
r2(getUrl('message/send_sms'), 'e', 'action not defined');
|
||||
}
|
||||
|
@ -15,30 +15,36 @@ switch ($action) {
|
||||
$ui->assign('_system_menu', 'voucher');
|
||||
$ui->assign('_title', Lang::T('Order Voucher'));
|
||||
run_hook('customer_view_order'); #HOOK
|
||||
$ui->display('user-ui/order.tpl');
|
||||
$ui->display('customer/order.tpl');
|
||||
break;
|
||||
case 'history':
|
||||
$ui->assign('_system_menu', 'history');
|
||||
$query = ORM::for_table('tbl_payment_gateway')->where('username', $user['username'])->order_by_desc('id');
|
||||
$query = ORM::for_table('tbl_payment_gateway')->where('user_id', $user['id'])->order_by_desc('id');
|
||||
$d = Paginator::findMany($query);
|
||||
|
||||
if (empty($order) || $order < 5) {
|
||||
$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
|
||||
$ui->display('user-ui/orderHistory.tpl');
|
||||
$ui->display('customer/orderHistory.tpl');
|
||||
break;
|
||||
case 'balance':
|
||||
if (strpos($user['email'], '@') === false) {
|
||||
r2(U . 'accounts/profile', 'e', Lang::T("Please enter your email address"));
|
||||
r2(getUrl('accounts/profile'), 'e', Lang::T("Please enter your email address"));
|
||||
}
|
||||
$ui->assign('_title', 'Top Up');
|
||||
$ui->assign('_system_menu', 'balance');
|
||||
$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-ui/orderBalance.tpl');
|
||||
$ui->display('customer/orderBalance.tpl');
|
||||
break;
|
||||
case 'package':
|
||||
if (strpos($user['email'], '@') === false) {
|
||||
r2(U . 'accounts/profile', 'e', Lang::T("Please enter your email address"));
|
||||
r2(getUrl('accounts/profile'), 'e', Lang::T("Please enter your email address"));
|
||||
}
|
||||
$ui->assign('_title', 'Order Plan');
|
||||
$ui->assign('_system_menu', 'package');
|
||||
@ -113,14 +119,21 @@ switch ($action) {
|
||||
->where('type', 'Hotspot')
|
||||
->where('prepaid', 'yes')
|
||||
->find_many();
|
||||
$plans_vpn = ORM::for_table('tbl_plans')
|
||||
->where('plan_type', $account_type)
|
||||
->where('enabled', '1')->where('is_radius', 0)
|
||||
->where('type', 'VPN')
|
||||
->where('prepaid', 'yes')
|
||||
->find_many();
|
||||
}
|
||||
$ui->assign('routers', $routers);
|
||||
$ui->assign('radius_pppoe', $radius_pppoe);
|
||||
$ui->assign('radius_hotspot', $radius_hotspot);
|
||||
$ui->assign('plans_pppoe', $plans_pppoe);
|
||||
$ui->assign('plans_hotspot', $plans_hotspot);
|
||||
$ui->assign('plans_vpn', $plans_vpn);
|
||||
run_hook('customer_view_order_plan'); #HOOK
|
||||
$ui->display('user-ui/orderPlan.tpl');
|
||||
$ui->display('customer/orderPlan.tpl');
|
||||
break;
|
||||
case 'unpaid':
|
||||
$d = ORM::for_table('tbl_payment_gateway')
|
||||
@ -131,12 +144,12 @@ switch ($action) {
|
||||
r_find_unpaid'); #HOOK
|
||||
if ($d) {
|
||||
if (empty($d['pg_url_payment'])) {
|
||||
r2(U . "order/buy/" . $trx['routers_id'] . '/' . $trx['plan_id'], 'w', Lang::T("Checking payment"));
|
||||
r2(getUrl('order/buy/') . $trx['routers_id'] . '/' . $trx['plan_id'], 'w', Lang::T("Checking payment"));
|
||||
} else {
|
||||
r2(U . "order/view/" . $d['id'] . '/check/', 's', Lang::T("You have unpaid transaction"));
|
||||
r2(getUrl('order/view/') . $d['id'] . '/check/', 's', Lang::T("You have unpaid transaction"));
|
||||
}
|
||||
} else {
|
||||
r2(U . "order/package/", 's', Lang::T("You have no unpaid transaction"));
|
||||
r2(getUrl('order/package/'), 's', Lang::T("You have no unpaid transaction"));
|
||||
}
|
||||
break;
|
||||
case 'view':
|
||||
@ -147,15 +160,15 @@ switch ($action) {
|
||||
run_hook('customer_view_payment'); #HOOK
|
||||
// jika tidak ditemukan, berarti punya orang lain
|
||||
if (empty($trx)) {
|
||||
r2(U . "order/package", 'w', Lang::T("Payment not found"));
|
||||
r2(getUrl('order/package'), 'w', Lang::T("Payment not found"));
|
||||
}
|
||||
// jika url kosong, balikin ke buy, kecuali cancel
|
||||
if ($trx['status'] == 1 && 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"));
|
||||
r2(getUrl('order/buy/') . (($trx['routers_id'] == 0) ? $trx['routers'] : $trx['routers_id']) . '/' . $trx['plan_id'], 'w', Lang::T("Checking payment"));
|
||||
}
|
||||
if ($routes['3'] == 'check') {
|
||||
if (!file_exists($PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $trx['gateway'] . '.php')) {
|
||||
r2(U . 'order/view/' . $trxid, 'e', Lang::T("No Payment Gateway Available"));
|
||||
r2(getUrl('order/view/') . $trxid, 'e', Lang::T("No Payment Gateway Available"));
|
||||
}
|
||||
run_hook('customer_check_payment_status'); #HOOK
|
||||
include $PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $trx['gateway'] . '.php';
|
||||
@ -172,7 +185,7 @@ switch ($action) {
|
||||
->find_one($trxid);
|
||||
}
|
||||
if (empty($trx)) {
|
||||
r2(U . "order/package", 'e', Lang::T("Transaction Not found"));
|
||||
r2(getUrl('order/package'), 'e', Lang::T("Transaction Not found"));
|
||||
}
|
||||
|
||||
$router = ORM::for_table('tbl_routers')->where('name', $trx['routers'])->find_one();
|
||||
@ -185,28 +198,26 @@ switch ($action) {
|
||||
$ui->assign('plan', $plan);
|
||||
$ui->assign('bandw', $bandw);
|
||||
$ui->assign('_title', 'TRX #' . $trxid);
|
||||
$ui->display('user-ui/orderView.tpl');
|
||||
$ui->display('customer/orderView.tpl');
|
||||
break;
|
||||
case 'pay':
|
||||
if ($config['enable_balance'] != 'yes') {
|
||||
r2(U . "order/package", 'e', Lang::T("Balance not enabled"));
|
||||
r2(getUrl('order/package'), 'e', Lang::T("Balance not enabled"));
|
||||
}
|
||||
if (!empty(App::getTokenValue($_GET['stoken']))) {
|
||||
r2(U . "voucher/invoice/");
|
||||
r2(getUrl('voucher/invoice/'));
|
||||
die();
|
||||
}
|
||||
if ($user['status'] != 'Active') {
|
||||
_alert(Lang::T('This account status') . ' : ' . Lang::T($user['status']), 'danger', "");
|
||||
}
|
||||
$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"));
|
||||
}
|
||||
if (!$plan['enabled']) {
|
||||
r2(U . "home", 'e', 'Plan is not exists');
|
||||
$plan = ORM::for_table('tbl_plans')->find_one($routes[3]);
|
||||
if (!$plan) {
|
||||
r2(getUrl('order/package'), 'e', Lang::T("Plan Not found"));
|
||||
}
|
||||
if ($plan['is_radius'] == '1') {
|
||||
$router_name = 'radius';
|
||||
$router = 'radius';
|
||||
} else {
|
||||
$router_name = $plan['routers'];
|
||||
}
|
||||
@ -230,27 +241,27 @@ switch ($action) {
|
||||
$tax = 0;
|
||||
}
|
||||
// Tax calculation stop
|
||||
|
||||
if ($plan && $plan['enabled'] && $user['balance'] >= $plan['price'] + $tax) {
|
||||
$total_cost = $plan['price'] + $add_cost + $tax;
|
||||
if ($plan && $plan['enabled'] && $user['balance'] >= $total_cost) {
|
||||
if (Package::rechargeUser($user['id'], $router_name, $plan['id'], 'Customer', 'Balance')) {
|
||||
// if success, then get the balance
|
||||
Balance::min($user['id'], $plan['price'] + $add_cost + $tax);
|
||||
Balance::min($user['id'], $total_cost);
|
||||
App::setToken($_GET['stoken'], "success");
|
||||
r2(U . "voucher/invoice/", 's', Lang::T("Success to buy package"));
|
||||
r2(getUrl('voucher/invoice/'), 's', Lang::T("Success to buy package"));
|
||||
} else {
|
||||
r2(U . "order/package", 'e', Lang::T("Failed to buy package"));
|
||||
r2(getUrl('order/package'), 'e', Lang::T("Failed to buy package"));
|
||||
Message::sendTelegram("Buy Package with Balance Failed\n\n#u$c[username] #buy \n" . $plan['name_plan'] .
|
||||
"\nRouter: " . $router_name .
|
||||
"\nPrice: " . $plan['price'] + $tax);
|
||||
"\nPrice: " . $total_cost);
|
||||
}
|
||||
} else {
|
||||
r2(U . "home", 'e', 'Plan is not exists');
|
||||
r2(getUrl('order/gateway/$routes[2]/$routes[3]'), 'e', Lang::T("Insufficient balance"));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'send':
|
||||
if ($config['enable_balance'] != 'yes') {
|
||||
r2(U . "order/package", 'e', Lang::T("Balance not enabled"));
|
||||
r2(getUrl('order/package'), 'e', Lang::T("Balance not enabled"));
|
||||
}
|
||||
if ($user['status'] != 'Active') {
|
||||
_alert(Lang::T('This account status') . ' : ' . Lang::T($user['status']), 'danger', "");
|
||||
@ -259,12 +270,13 @@ switch ($action) {
|
||||
$ui->assign('_system_menu', 'package');
|
||||
$plan = ORM::for_table('tbl_plans')->find_one($routes['3']);
|
||||
if (empty($plan)) {
|
||||
r2(U . "order/package", 'e', Lang::T("Plan Not found"));
|
||||
r2(getUrl('order/package'), 'e', Lang::T("Plan Not found"));
|
||||
}
|
||||
if (!$plan['enabled']) {
|
||||
r2(U . "home", 'e', 'Plan is not exists');
|
||||
r2(getUrl('home'), 'e', 'Plan is not exists');
|
||||
}
|
||||
if ($routes['2'] == 'radius') {
|
||||
if ($plan['is_radius'] == '1') {
|
||||
$routes['2'] = 0;
|
||||
$router_name = 'radius';
|
||||
} else {
|
||||
$router_name = $plan['routers'];
|
||||
@ -300,13 +312,13 @@ switch ($action) {
|
||||
}
|
||||
|
||||
if (!$target) {
|
||||
r2(U . 'home', 'd', Lang::T('Username not found'));
|
||||
r2(getUrl('home'), 'd', Lang::T('Username not found'));
|
||||
}
|
||||
if ($user['balance'] < $plan['price']) {
|
||||
r2(U . 'home', 'd', Lang::T('insufficient balance'));
|
||||
r2(getUrl('home'), 'd', Lang::T('insufficient balance'));
|
||||
}
|
||||
if ($user['username'] == $target['username']) {
|
||||
r2(U . "order/pay/$routes[2]/$routes[3]", 's', '^_^ v');
|
||||
r2(getUrl('order/pay/$routes[2]/$routes[3]'), 's', '^_^ v');
|
||||
}
|
||||
$active = ORM::for_table('tbl_user_recharges')
|
||||
->where('username', _post('username'))
|
||||
@ -314,7 +326,7 @@ switch ($action) {
|
||||
->find_one();
|
||||
|
||||
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> ]");
|
||||
r2(getUrl('order/package'), 'e', Lang::T("Target has active plan, different with current plant.") . " [ <b>$active[namebp]</b> ]");
|
||||
}
|
||||
$result = Package::rechargeUser($target['id'], $router_name, $plan['id'], $user['username'], 'Balance');
|
||||
if (!empty($result)) {
|
||||
@ -323,6 +335,7 @@ switch ($action) {
|
||||
//sender
|
||||
$d = ORM::for_table('tbl_payment_gateway')->create();
|
||||
$d->username = $user['username'];
|
||||
$d->user_id = $user['id'];
|
||||
$d->gateway = $target['username'];
|
||||
$d->plan_id = $plan['id'];
|
||||
$d->plan_name = $plan['name_plan'];
|
||||
@ -342,6 +355,7 @@ switch ($action) {
|
||||
//receiver
|
||||
$d = ORM::for_table('tbl_payment_gateway')->create();
|
||||
$d->username = $target['username'];
|
||||
$d->user_id = $target['id'];
|
||||
$d->gateway = $user['username'];
|
||||
$d->plan_id = $plan['id'];
|
||||
$d->plan_name = $plan['name_plan'];
|
||||
@ -357,7 +371,7 @@ switch ($action) {
|
||||
$d->trx_invoice = $result;
|
||||
$d->status = 2;
|
||||
$d->save();
|
||||
r2(U . "order/view/$trx_id", 's', Lang::T("Success to send package"));
|
||||
r2(getUrl("order/view/$trx_id"), 's', Lang::T("Success to send package"));
|
||||
} else {
|
||||
$errorMessage = "Send Package with Balance Failed\n\n#u$user[username] #send \n" . $plan['name_plan'] .
|
||||
"\nRouter: " . $router_name .
|
||||
@ -367,7 +381,7 @@ switch ($action) {
|
||||
$errorMessage .= "\nTax: " . $tax;
|
||||
}
|
||||
|
||||
r2(U . "order/package", 'e', Lang::T("Failed to Send package"));
|
||||
r2(getUrl('order/package'), 'e', Lang::T("Failed to Send package"));
|
||||
Message::sendTelegram($errorMessage);
|
||||
}
|
||||
}
|
||||
@ -375,13 +389,13 @@ switch ($action) {
|
||||
$ui->assign('router', $router_name);
|
||||
$ui->assign('plan', $plan);
|
||||
$ui->assign('tax', $tax);
|
||||
$ui->display('user-ui/sendPlan.tpl');
|
||||
$ui->display('customer/sendPlan.tpl');
|
||||
break;
|
||||
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"));
|
||||
r2(getUrl('accounts/profile'), 'e', Lang::T("Please enter your email address"));
|
||||
}
|
||||
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
|
||||
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
|
||||
@ -396,32 +410,139 @@ switch ($action) {
|
||||
if ($router['name'] != 'balance') {
|
||||
list($bills, $add_cost) = User::getBills($id_customer);
|
||||
}
|
||||
$add_inv = User::getAttribute("Invoice", $id_customer);
|
||||
if (!empty($add_inv)) {
|
||||
$plan['price'] = $add_inv;
|
||||
}
|
||||
|
||||
if($config['enable_coupons']){
|
||||
if (!isset($_SESSION['coupon_attempts'])) {
|
||||
$_SESSION['coupon_attempts'] = 0;
|
||||
$_SESSION['last_attempt_time'] = time();
|
||||
}
|
||||
|
||||
if ($_SESSION['coupon_attempts'] >= 5) {
|
||||
$timeout = 10 * 60; // 10 minutes in seconds
|
||||
$time_diff = time() - $_SESSION['last_attempt_time'];
|
||||
|
||||
if ($time_diff >= $timeout) {
|
||||
$_SESSION['coupon_attempts'] = 0;
|
||||
$_SESSION['last_attempt_time'] = time();
|
||||
} else {
|
||||
$remaining_time = ceil(($timeout - $time_diff) / 60);
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T("Too many invalid attempts. Please try again after $remaining_time minutes."));
|
||||
}
|
||||
}
|
||||
|
||||
if (_post('coupon')) {
|
||||
if ($plan['routers'] === 'balance') {
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T("Coupon not available for Balance"));
|
||||
}
|
||||
|
||||
$coupon = ORM::for_table('tbl_coupons')->where('code', _post('coupon'))->find_one();
|
||||
|
||||
if (!$coupon) {
|
||||
$_SESSION['coupon_attempts']++;
|
||||
$_SESSION['last_attempt_time'] = time();
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T("Coupon not found"));
|
||||
}
|
||||
|
||||
if ($coupon['status'] != 'active') {
|
||||
$_SESSION['coupon_attempts']++;
|
||||
$_SESSION['last_attempt_time'] = time();
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T("Coupon is not active"));
|
||||
}
|
||||
|
||||
// Reset attempts after a successful coupon validation
|
||||
$_SESSION['coupon_attempts'] = 0;
|
||||
$_SESSION['last_attempt_time'] = time();
|
||||
|
||||
$today = date('Y-m-d');
|
||||
if ($today < $coupon['start_date'] || $today > $coupon['end_date']) {
|
||||
$_SESSION['coupon_attempts']++;
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T("Coupon is not valid for today"));
|
||||
}
|
||||
|
||||
if ($coupon['max_usage'] > 0 && $coupon['usage_count'] >= $coupon['max_usage']) {
|
||||
$_SESSION['coupon_attempts']++;
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T("Coupon usage limit reached"));
|
||||
}
|
||||
|
||||
if ($plan['price'] < $coupon['min_order_amount']) {
|
||||
$_SESSION['coupon_attempts']++;
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T("The order amount does not meet the minimum requirement for this coupon"));
|
||||
}
|
||||
|
||||
// Calculate discount value
|
||||
$discount = 0;
|
||||
switch ($coupon['type']) {
|
||||
case 'percent':
|
||||
$discount = ($coupon['value'] / 100) * $plan['price'];
|
||||
if ($discount > $coupon['max_discount_amount']) {
|
||||
$discount = $coupon['max_discount_amount'];
|
||||
}
|
||||
break;
|
||||
case 'fixed':
|
||||
$discount = $coupon['value'];
|
||||
break;
|
||||
}
|
||||
|
||||
// Ensure discount does not exceed the plan price
|
||||
if ($discount >= $plan['price']) {
|
||||
r2($_SERVER['HTTP_REFERER'], 'e', Lang::T("Discount value exceeds the plan price"));
|
||||
}
|
||||
|
||||
$plan['price'] -= $discount;
|
||||
$coupon->usage_count = $coupon['usage_count'] + 1;
|
||||
$coupon->save();
|
||||
|
||||
$ui->assign('discount', $discount);
|
||||
$ui->assign('notify', Lang::T("Coupon applied successfully. You saved " . Lang::moneyFormat($discount)));
|
||||
$ui->assign('notify_t', 's');
|
||||
}
|
||||
}
|
||||
|
||||
$tax = Package::tax($plan['price'] + $add_cost, $tax_rate);
|
||||
$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.."));
|
||||
r2(getUrl('home'), 'e', Lang::T("Failed to create Transaction.."));
|
||||
}
|
||||
if (count($pgs) > 0) {
|
||||
$ui->assign('pgs', $pgs);
|
||||
if ($tax_enable === 'yes') {
|
||||
$ui->assign('tax', $tax);
|
||||
}
|
||||
|
||||
if (_post('custom') == '1') {
|
||||
if (_post('amount') > 0) {
|
||||
$ui->assign('custom', '1');
|
||||
$ui->assign('amount', _post('amount'));
|
||||
} else {
|
||||
r2(getUrl('order/balance'), 'e', Lang::T("Please enter amount"));
|
||||
}
|
||||
}
|
||||
|
||||
$ui->assign('route2', $routes[2]);
|
||||
$ui->assign('route3', $routes[3]);
|
||||
$ui->assign('add_cost', $add_cost);
|
||||
$ui->assign('bills', $bills);
|
||||
$ui->assign('plan', $plan);
|
||||
$ui->display('user-ui/selectGateway.tpl');
|
||||
$ui->display('customer/selectGateway.tpl');
|
||||
break;
|
||||
} else {
|
||||
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.."));
|
||||
r2(getUrl('home'), 'e', Lang::T("Failed to create Transaction.."));
|
||||
}
|
||||
case 'buy':
|
||||
$gateway = _post('gateway');
|
||||
$discount = _post('discount') ?: 0;
|
||||
if ($gateway == 'balance') {
|
||||
unset($_SESSION['gateway']);
|
||||
r2(getUrl('order/pay/') . $routes[2] . '/' . $routes[3]);
|
||||
}
|
||||
if (empty($gateway) && !empty($_SESSION['gateway'])) {
|
||||
$gateway = $_SESSION['gateway'];
|
||||
} else if (!empty($gateway)) {
|
||||
@ -431,111 +552,156 @@ switch ($action) {
|
||||
_alert(Lang::T('This account status') . ' : ' . Lang::T($user['status']), 'danger', "");
|
||||
}
|
||||
if (empty($gateway)) {
|
||||
r2(U . 'order/gateway/' . $routes[2] . '/' . $routes[3], 'w', Lang::T("Please select Payment Gateway"));
|
||||
r2(getUrl('order/gateway/') . $routes[2] . '/' . $routes[3], 'w', Lang::T("Please select Payment Gateway"));
|
||||
}
|
||||
run_hook('customer_buy_plan'); #HOOK
|
||||
include $PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $gateway . '.php';
|
||||
call_user_func($gateway . '_validate_config');
|
||||
|
||||
$plan = ORM::for_table('tbl_plans')->where('enabled', '1')->find_one($routes['3']);
|
||||
if ($plan['is_radius'] == '1') {
|
||||
$router['id'] = 0;
|
||||
$router['name'] = 'radius';
|
||||
} else if ($routes['2'] > 0) {
|
||||
$router = ORM::for_table('tbl_routers')->where('enabled', '1')->find_one($routes['2']);
|
||||
} else {
|
||||
$router['id'] = 0;
|
||||
$router['name'] = 'balance';
|
||||
}
|
||||
if (empty($router) || empty($plan)) {
|
||||
r2(U . "order/package", 'e', Lang::T("Plan Not found"));
|
||||
}
|
||||
$d = ORM::for_table('tbl_payment_gateway')
|
||||
->where('username', $user['username'])
|
||||
->where('status', 1)
|
||||
->find_one();
|
||||
if ($d) {
|
||||
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 ($gateway == $d['gateway']) {
|
||||
$id = $d['id'];
|
||||
|
||||
switch (_post('custom')) {
|
||||
case '1':
|
||||
$amount = _post('amount');
|
||||
$amount = (float) $amount;
|
||||
|
||||
if ($amount <= 0) {
|
||||
r2(getUrl('order/gateway/') . $routes[2] . '/' . $routes[3], 'w', Lang::T("Please enter amount"));
|
||||
}
|
||||
|
||||
$d = ORM::for_table('tbl_payment_gateway')
|
||||
->where('username', $user['username'])
|
||||
->where('status', 1)
|
||||
->find_one();
|
||||
if ($d) {
|
||||
if ($d['pg_url_payment']) {
|
||||
r2(getUrl('order/view/') . $d['id'], 'w', Lang::T("You already have unpaid transaction, cancel it or pay it."));
|
||||
} else {
|
||||
if ($gateway == $d['gateway']) {
|
||||
$id = $d['id'];
|
||||
} else {
|
||||
$d->status = 4;
|
||||
$d->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
$d = ORM::for_table('tbl_payment_gateway')->create();
|
||||
$d->username = $user['username'];
|
||||
$d->user_id = $user['id'];
|
||||
$d->gateway = $gateway;
|
||||
$d->plan_id = 0;
|
||||
$d->plan_name = 'Custom';
|
||||
$d->routers_id = '0';
|
||||
$d->routers = 'Custom Balance';
|
||||
$d->price = $amount;
|
||||
$d->created_date = date('Y-m-d H:i:s');
|
||||
$d->status = 1;
|
||||
$d->save();
|
||||
$id = $d->id;
|
||||
break;
|
||||
|
||||
default:
|
||||
$plan = ORM::for_table('tbl_plans')->where('enabled', '1')->find_one($routes['3']);
|
||||
if ($plan['is_radius'] == '1') {
|
||||
$router['id'] = 0;
|
||||
$router['name'] = 'radius';
|
||||
} else if ($routes['2'] > 0) {
|
||||
$router = ORM::for_table('tbl_routers')->where('enabled', '1')->find_one($routes['2']);
|
||||
} else {
|
||||
$d->status = 4;
|
||||
$router['id'] = 0;
|
||||
$router['name'] = 'balance';
|
||||
}
|
||||
if (empty($router) || empty($plan)) {
|
||||
r2(getUrl('order/package'), 'e', Lang::T("Plan Not found"));
|
||||
}
|
||||
$d = ORM::for_table('tbl_payment_gateway')
|
||||
->where('username', $user['username'])
|
||||
->where('status', 1)
|
||||
->find_one();
|
||||
if ($d) {
|
||||
if ($d['pg_url_payment']) {
|
||||
r2(getUrl('order/view/') . $d['id'], 'w', Lang::T("You already have unpaid transaction, cancel it or pay it."));
|
||||
} else {
|
||||
if ($gateway == $d['gateway']) {
|
||||
$id = $d['id'];
|
||||
} else {
|
||||
$d->status = 4;
|
||||
$d->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
$add_cost = 0;
|
||||
$tax = 0;
|
||||
if ($router['name'] != 'balance') {
|
||||
list($bills, $add_cost) = User::getBills($id_customer);
|
||||
}
|
||||
// Tax calculation start
|
||||
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
|
||||
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
|
||||
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : null;
|
||||
if ($tax_rate_setting === 'custom') {
|
||||
$tax_rate = $custom_tax_rate;
|
||||
} else {
|
||||
$tax_rate = $tax_rate_setting;
|
||||
}
|
||||
if ($tax_enable === 'yes') {
|
||||
$tax = Package::tax($plan['price'], $tax_rate);
|
||||
}
|
||||
// Tax calculation stop
|
||||
if (empty($id)) {
|
||||
$d = ORM::for_table('tbl_payment_gateway')->create();
|
||||
$d->username = $user['username'];
|
||||
$d->user_id = $user['id'];
|
||||
$d->gateway = $gateway;
|
||||
$d->plan_id = $plan['id'];
|
||||
$d->plan_name = $plan['name_plan'];
|
||||
$d->routers_id = $router['id'];
|
||||
$d->routers = $router['name'];
|
||||
if ($plan['validity_unit'] == 'Period') {
|
||||
// Postpaid price from field
|
||||
$add_inv = User::getAttribute("Invoice", $id_customer);
|
||||
if (empty($add_inv) or $add_inv == 0) {
|
||||
$d->price = $plan['price'] + $add_cost + $tax - $discount;
|
||||
} else {
|
||||
$d->price = $add_inv + $add_cost + $tax - $discount;
|
||||
}
|
||||
} else {
|
||||
$d->price = $plan['price'] + $add_cost + $tax - $discount;
|
||||
}
|
||||
$d->created_date = date('Y-m-d H:i:s');
|
||||
$d->status = 1;
|
||||
$d->save();
|
||||
$id = $d->id();
|
||||
} else {
|
||||
$d->username = $user['username'];
|
||||
$d->user_id = $user['id'];
|
||||
$d->gateway = $gateway;
|
||||
$d->plan_id = $plan['id'];
|
||||
$d->plan_name = $plan['name_plan'];
|
||||
$d->routers_id = $router['id'];
|
||||
$d->routers = $router['name'];
|
||||
if ($plan['validity_unit'] == 'Period') {
|
||||
// Postpaid price from field
|
||||
$add_inv = User::getAttribute("Invoice", $id_customer);
|
||||
if (empty($add_inv) or $add_inv == 0) {
|
||||
$d->price = ($plan['price'] + $add_cost + $tax - $discount);
|
||||
} else {
|
||||
$d->price = ($add_inv + $add_cost + $tax - $discount);
|
||||
}
|
||||
} else {
|
||||
$d->price = ($plan['price'] + $add_cost + $tax - $discount);
|
||||
}
|
||||
//$d->price = ($plan['price'] + $add_cost);
|
||||
$d->created_date = date('Y-m-d H:i:s');
|
||||
$d->status = 1;
|
||||
$d->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
$add_cost = 0;
|
||||
$tax = 0;
|
||||
if ($router['name'] != 'balance') {
|
||||
list($bills, $add_cost) = User::getBills($id_customer);
|
||||
}
|
||||
// Tax calculation start
|
||||
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
|
||||
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
|
||||
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float)$config['custom_tax_rate'] : null;
|
||||
if ($tax_rate_setting === 'custom') {
|
||||
$tax_rate = $custom_tax_rate;
|
||||
} else {
|
||||
$tax_rate = $tax_rate_setting;
|
||||
}
|
||||
if ($tax_enable === 'yes') {
|
||||
$tax = Package::tax($plan['price'], $tax_rate);
|
||||
}
|
||||
// Tax calculation stop
|
||||
if (empty($id)) {
|
||||
$d = ORM::for_table('tbl_payment_gateway')->create();
|
||||
$d->username = $user['username'];
|
||||
$d->gateway = $gateway;
|
||||
$d->plan_id = $plan['id'];
|
||||
$d->plan_name = $plan['name_plan'];
|
||||
$d->routers_id = $router['id'];
|
||||
$d->routers = $router['name'];
|
||||
if ($plan['validity_unit'] == 'Period') {
|
||||
// Postpaid price from field
|
||||
$add_inv = User::getAttribute("Invoice", $id_customer);
|
||||
if (empty($add_inv) or $add_inv == 0) {
|
||||
$d->price = ($plan['price'] + $add_cost + $tax);
|
||||
} else {
|
||||
$d->price = ($add_inv + $add_cost + $tax);
|
||||
}
|
||||
} else {
|
||||
$d->price = ($plan['price'] + $add_cost + $tax);
|
||||
}
|
||||
$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 = $gateway;
|
||||
$d->plan_id = $plan['id'];
|
||||
$d->plan_name = $plan['name_plan'];
|
||||
$d->routers_id = $router['id'];
|
||||
$d->routers = $router['name'];
|
||||
if ($plan['validity_unit'] == 'Period') {
|
||||
// Postpaid price from field
|
||||
$add_inv = User::getAttribute("Invoice", $id_customer);
|
||||
if (empty($add_inv) or $add_inv == 0) {
|
||||
$d->price = ($plan['price'] + $add_cost + $tax);
|
||||
} else {
|
||||
$d->price = ($add_inv + $add_cost + $tax);
|
||||
}
|
||||
} else {
|
||||
$d->price = ($plan['price'] + $add_cost + $tax);
|
||||
}
|
||||
//$d->price = ($plan['price'] + $add_cost);
|
||||
$d->created_date = date('Y-m-d H:i:s');
|
||||
$d->status = 1;
|
||||
$d->save();
|
||||
break;
|
||||
}
|
||||
if (!$id) {
|
||||
r2(U . "order/package/" . $d['id'], 'e', Lang::T("Failed to create Transaction.."));
|
||||
r2(getUrl('order/package/') . $d['id'], 'e', Lang::T("Failed to create Transaction.."));
|
||||
} else {
|
||||
call_user_func($gateway . '_create_transaction', $d, $user);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
r2(U . "order/package/", 's', '');
|
||||
r2(getUrl('order/package/'), 's', '');
|
||||
}
|
||||
|
@ -16,6 +16,6 @@ if(file_exists(__DIR__."/../../pages/".str_replace(".","",$action).".html")){
|
||||
$ui->assign("PageFile",$action);
|
||||
$ui->assign("pageHeader",$action);
|
||||
run_hook('customer_view_page'); #HOOK
|
||||
$ui->display('user-ui/pages.tpl');
|
||||
$ui->display('customer/pages.tpl');
|
||||
}else
|
||||
$ui->display('user-ui/404.tpl');
|
||||
$ui->display('customer/404.tpl');
|
@ -26,7 +26,7 @@ if (strpos($action, "-reset") !== false) {
|
||||
} else {
|
||||
file_put_contents($path, Http::getData('https://raw.githubusercontent.com/hotspotbilling/phpnuxbill/master/pages_template/' . $action . '.html'));
|
||||
}
|
||||
r2(U . 'pages/' . $action);
|
||||
r2(getUrl('pages/') . $action);
|
||||
} else if (strpos($action, "-post") === false) {
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
@ -60,9 +60,9 @@ if (strpos($action, "-reset") !== false) {
|
||||
$ui->assign("writeable", is_writable($path));
|
||||
$ui->assign("pageHeader", str_replace('_', ' ', $action));
|
||||
$ui->assign("PageFile", $action);
|
||||
$ui->display('page-edit.tpl');
|
||||
$ui->display('admin/settings/page.tpl');
|
||||
} else
|
||||
$ui->display('a404.tpl');
|
||||
$ui->display('admin/404.tpl');
|
||||
} else {
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
@ -78,10 +78,10 @@ if (strpos($action, "-reset") !== false) {
|
||||
file_put_contents("$PAGES_PATH/vouchers/" . _post('template_name') . '.html', $html);
|
||||
}
|
||||
}
|
||||
r2(U . 'pages/' . $action, 's', Lang::T("Saving page success"));
|
||||
r2(getUrl('pages/') . $action, 's', Lang::T("Saving page success"));
|
||||
} else {
|
||||
r2(U . 'pages/' . $action, 'e', Lang::T("Failed to save page, make sure i can write to folder pages, <i>chmod 664 pages/*.html<i>"));
|
||||
r2(getUrl('pages/') . $action, 'e', Lang::T("Failed to save page, make sure i can write to folder pages, <i>chmod 664 pages/*.html<i>"));
|
||||
}
|
||||
} else
|
||||
$ui->display('a404.tpl');
|
||||
$ui->display('admin/404.tpl');
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ switch ($action) {
|
||||
if (file_exists($PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $pg . '.php')) {
|
||||
deleteFile($PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR, $pg);
|
||||
}
|
||||
r2(U . 'paymentgateway', 's', Lang::T('Payment Gateway Deleted'));
|
||||
r2(getUrl('paymentgateway'), 's', Lang::T('Payment Gateway Deleted'));
|
||||
|
||||
case 'audit':
|
||||
$pg = alphanumeric($routes[2]);
|
||||
@ -34,7 +34,7 @@ switch ($action) {
|
||||
$ui->assign('pgs', $pgs);
|
||||
$ui->assign('pg', $pg);
|
||||
$ui->assign('q', $q);
|
||||
$ui->display('paymentgateway-audit.tpl');
|
||||
$ui->display('admin/paymentgateway/audit.tpl');
|
||||
break;
|
||||
case 'auditview':
|
||||
$pg = alphanumeric($routes[2]);
|
||||
@ -43,7 +43,7 @@ switch ($action) {
|
||||
$d['pg_paid_response'] = (!empty($d['pg_paid_response']))? Text::jsonArray21Array(json_decode($d['pg_paid_response'], true)) : [];
|
||||
$ui->assign('_title', 'Payment Gateway Audit View');
|
||||
$ui->assign('pg', $d);
|
||||
$ui->display('paymentgateway-audit-view.tpl');
|
||||
$ui->display('admin/paymentgateway/audit-view.tpl');
|
||||
break;
|
||||
default:
|
||||
if (_post('save') == 'actives') {
|
||||
@ -61,7 +61,7 @@ switch ($action) {
|
||||
$d->value = $pgs;
|
||||
$d->save();
|
||||
}
|
||||
r2(U . 'paymentgateway', 's', Lang::T('Payment Gateway saved successfully'));
|
||||
r2(getUrl('paymentgateway'), 's', Lang::T('Payment Gateway saved successfully'));
|
||||
}
|
||||
|
||||
if (file_exists($PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR . $action . '.php')) {
|
||||
@ -70,18 +70,18 @@ switch ($action) {
|
||||
if (function_exists($action . '_save_config')) {
|
||||
call_user_func($action . '_save_config');
|
||||
} else {
|
||||
$ui->display('a404.tpl');
|
||||
$ui->display('admin/404.tpl');
|
||||
}
|
||||
} else {
|
||||
if (function_exists($action . '_show_config')) {
|
||||
call_user_func($action . '_show_config');
|
||||
} else {
|
||||
$ui->display('a404.tpl');
|
||||
$ui->display('admin/404.tpl');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!empty($action)) {
|
||||
r2(U . 'paymentgateway', 'w', Lang::T('Payment Gateway Not Found'));
|
||||
r2(getUrl('paymentgateway'), 'w', Lang::T('Payment Gateway Not Found'));
|
||||
} else {
|
||||
$files = scandir($PAYMENTGATEWAY_PATH);
|
||||
foreach ($files as $file) {
|
||||
@ -92,7 +92,7 @@ switch ($action) {
|
||||
$ui->assign('_title', 'Payment Gateway Settings');
|
||||
$ui->assign('pgs', $pgs);
|
||||
$ui->assign('actives', explode(',', $config['payment_gateway']));
|
||||
$ui->display('paymentgateway.tpl');
|
||||
$ui->display('admin/paymentgateway/list.tpl');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,8 @@ $ui->assign('_system_menu', 'plan');
|
||||
$action = $routes['1'];
|
||||
$ui->assign('_admin', $admin);
|
||||
|
||||
$appUrl = APP_URL;
|
||||
|
||||
$select2_customer = <<<EOT
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
@ -20,9 +22,9 @@ document.addEventListener("DOMContentLoaded", function(event) {
|
||||
ajax: {
|
||||
url: function(params) {
|
||||
if(params.term != undefined){
|
||||
return './index.php?_route=autoload/customer_select2&s='+params.term;
|
||||
return '{$appUrl}/?_route=autoload/customer_select2&s='+params.term;
|
||||
}else{
|
||||
return './index.php?_route=autoload/customer_select2';
|
||||
return '{$appUrl}/?_route=autoload/customer_select2';
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -30,7 +32,7 @@ document.addEventListener("DOMContentLoaded", function(event) {
|
||||
});
|
||||
</script>
|
||||
EOT;
|
||||
|
||||
getUrl('docs');
|
||||
switch ($action) {
|
||||
case 'sync':
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
@ -49,7 +51,11 @@ switch ($action) {
|
||||
if ($_app_stage != 'demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
(new $p['device'])->add_customer($c, $p);
|
||||
if (method_exists($dvc, 'sync_customer')) {
|
||||
(new $p['device'])->sync_customer($c, $p);
|
||||
} else {
|
||||
(new $p['device'])->add_customer($c, $p);
|
||||
}
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
}
|
||||
@ -62,7 +68,7 @@ switch ($action) {
|
||||
$log .= "PLAN NOT FOUND : $tur[username], $tur[namebp], $tur[type], $tur[routers]<br>";
|
||||
}
|
||||
}
|
||||
r2(U . 'plan/list', 's', $log);
|
||||
r2(getUrl('plan/list'), 's', $log);
|
||||
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");
|
||||
@ -78,7 +84,7 @@ switch ($action) {
|
||||
}
|
||||
$ui->assign('usings', $usings);
|
||||
run_hook('view_recharge'); #HOOK
|
||||
$ui->display('recharge.tpl');
|
||||
$ui->display('admin/plan/recharge.tpl');
|
||||
break;
|
||||
|
||||
case 'recharge-confirm':
|
||||
@ -101,15 +107,39 @@ switch ($action) {
|
||||
$cust = User::_info($id_customer);
|
||||
$plan = ORM::for_table('tbl_plans')->find_one($planId);
|
||||
list($bills, $add_cost) = User::getBills($id_customer);
|
||||
$add_inv = User::getAttribute("Invoice", $id_customer);
|
||||
if (!empty($add_inv)) {
|
||||
$plan['price'] = $add_inv;
|
||||
}
|
||||
|
||||
// Tax calculation start
|
||||
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
|
||||
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
|
||||
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float) $config['custom_tax_rate'] : null;
|
||||
|
||||
if ($tax_rate_setting === 'custom') {
|
||||
$tax_rate = $custom_tax_rate;
|
||||
} else {
|
||||
$tax_rate = $tax_rate_setting;
|
||||
}
|
||||
|
||||
if ($tax_enable === 'yes') {
|
||||
$tax = Package::tax($plan['price'], $tax_rate);
|
||||
} else {
|
||||
$tax = 0;
|
||||
}
|
||||
// Tax calculation stop
|
||||
$total_cost = $plan['price'] + $add_cost + $tax;
|
||||
|
||||
if ($using == 'balance' && $config['enable_balance'] == 'yes') {
|
||||
if (!$cust) {
|
||||
r2(U . 'plan/recharge', 'e', Lang::T('Customer not found'));
|
||||
r2(getUrl('plan/recharge'), 'e', Lang::T('Customer not found'));
|
||||
}
|
||||
if (!$plan) {
|
||||
r2(U . 'plan/recharge', 'e', Lang::T('Plan not found'));
|
||||
r2(getUrl('plan/recharge'), 'e', Lang::T('Plan not found'));
|
||||
}
|
||||
if ($cust['balance'] < ($plan['price'] + $add_cost)) {
|
||||
r2(U . 'plan/recharge', 'e', Lang::T('insufficient balance'));
|
||||
if ($cust['balance'] < $total_cost) {
|
||||
r2(getUrl('plan/recharge'), 'e', Lang::T('insufficient balance'));
|
||||
}
|
||||
$gateway = 'Recharge Balance';
|
||||
}
|
||||
@ -122,6 +152,9 @@ switch ($action) {
|
||||
if (count($usings) == 0) {
|
||||
$usings[] = Lang::T('Cash');
|
||||
}
|
||||
if ($tax_enable === 'yes') {
|
||||
$ui->assign('tax', $tax);
|
||||
}
|
||||
$ui->assign('usings', $usings);
|
||||
$ui->assign('bills', $bills);
|
||||
$ui->assign('add_cost', $add_cost);
|
||||
@ -131,9 +164,10 @@ switch ($action) {
|
||||
$ui->assign('server', $server);
|
||||
$ui->assign('using', $using);
|
||||
$ui->assign('plan', $plan);
|
||||
$ui->display('recharge-confirm.tpl');
|
||||
$ui->assign('add_inv', $add_inv);
|
||||
$ui->display('admin/plan/recharge-confirm.tpl');
|
||||
} else {
|
||||
r2(U . 'plan/recharge', 'e', $msg);
|
||||
r2(getUrl('plan/recharge'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -145,13 +179,15 @@ switch ($action) {
|
||||
$server = _post('server');
|
||||
$planId = _post('plan');
|
||||
$using = _post('using');
|
||||
$stoken = _post('stoken');
|
||||
$svoucher = _post('svoucher');
|
||||
|
||||
if (!empty(App::getTokenValue($stoken))) {
|
||||
$username = App::getTokenValue($stoken);
|
||||
$plan = ORM::for_table('tbl_plans')->find_one($planId);
|
||||
|
||||
if (!empty(App::getVoucherValue($svoucher))) {
|
||||
$username = App::getVoucherValue($svoucher);
|
||||
$in = ORM::for_table('tbl_transactions')->where('username', $username)->order_by_desc('id')->find_one();
|
||||
Package::createInvoice($in);
|
||||
$ui->display('invoice.tpl');
|
||||
$ui->display('admin/plan/invoice.tpl');
|
||||
die();
|
||||
}
|
||||
|
||||
@ -165,16 +201,36 @@ switch ($action) {
|
||||
$channel = $admin['fullname'];
|
||||
$cust = User::_info($id_customer);
|
||||
list($bills, $add_cost) = User::getBills($id_customer);
|
||||
|
||||
// Tax calculation start
|
||||
$tax_enable = isset($config['enable_tax']) ? $config['enable_tax'] : 'no';
|
||||
$tax_rate_setting = isset($config['tax_rate']) ? $config['tax_rate'] : null;
|
||||
$custom_tax_rate = isset($config['custom_tax_rate']) ? (float) $config['custom_tax_rate'] : null;
|
||||
|
||||
if ($tax_rate_setting === 'custom') {
|
||||
$tax_rate = $custom_tax_rate;
|
||||
} else {
|
||||
$tax_rate = $tax_rate_setting;
|
||||
}
|
||||
|
||||
if ($tax_enable === 'yes') {
|
||||
$tax = Package::tax($plan['price'], $tax_rate);
|
||||
} else {
|
||||
$tax = 0;
|
||||
}
|
||||
// Tax calculation stop
|
||||
$total_cost = $plan['price'] + $add_cost + $tax;
|
||||
|
||||
if ($using == 'balance' && $config['enable_balance'] == 'yes') {
|
||||
$plan = ORM::for_table('tbl_plans')->find_one($planId);
|
||||
//$plan = ORM::for_table('tbl_plans')->find_one($planId);
|
||||
if (!$cust) {
|
||||
r2(U . 'plan/recharge', 'e', Lang::T('Customer not found'));
|
||||
r2(getUrl('plan/recharge'), 'e', Lang::T('Customer not found'));
|
||||
}
|
||||
if (!$plan) {
|
||||
r2(U . 'plan/recharge', 'e', Lang::T('Plan not found'));
|
||||
r2(getUrl('plan/recharge'), 'e', Lang::T('Plan not found'));
|
||||
}
|
||||
if ($cust['balance'] < ($plan['price'] + $add_cost)) {
|
||||
r2(U . 'plan/recharge', 'e', Lang::T('insufficient balance'));
|
||||
if ($cust['balance'] < $total_cost) {
|
||||
r2(getUrl('plan/recharge'), 'e', Lang::T('insufficient balance'));
|
||||
}
|
||||
$gateway = 'Recharge Balance';
|
||||
}
|
||||
@ -185,18 +241,18 @@ switch ($action) {
|
||||
}
|
||||
if (Package::rechargeUser($id_customer, $server, $planId, $gateway, $channel)) {
|
||||
if ($using == 'balance') {
|
||||
Balance::min($cust['id'], $plan['price'] + $add_cost);
|
||||
Balance::min($cust['id'], $total_cost);
|
||||
}
|
||||
$in = ORM::for_table('tbl_transactions')->where('username', $cust['username'])->order_by_desc('id')->find_one();
|
||||
Package::createInvoice($in);
|
||||
App::setToken($stoken, $cust['username']);
|
||||
$ui->display('invoice.tpl');
|
||||
App::setVoucher($svoucher, $cust['username']);
|
||||
$ui->display('admin/plan/invoice.tpl');
|
||||
_log('[' . $admin['username'] . ']: ' . 'Recharge ' . $cust['username'] . ' [' . $in['plan_name'] . '][' . Lang::moneyFormat($in['price']) . ']', $admin['user_type'], $admin['id']);
|
||||
} else {
|
||||
r2(U . 'plan/recharge', 'e', "Failed to recharge account");
|
||||
r2(getUrl('plan/recharge'), 'e', "Failed to recharge account");
|
||||
}
|
||||
} else {
|
||||
r2(U . 'plan/recharge', 'e', $msg);
|
||||
r2(getUrl('plan/recharge'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -208,13 +264,26 @@ switch ($action) {
|
||||
$c = ORM::for_table('tbl_customers')->where('username', $in['username'])->find_one();
|
||||
if ($c) {
|
||||
Message::sendInvoice($c, $in);
|
||||
r2(U . 'plan/view/' . $id, 's', "Success send to customer");
|
||||
r2(getUrl('plan/view/') . $id, 's', "Success send to customer");
|
||||
}
|
||||
r2(U . 'plan/view/' . $id, 'd', "Customer not found");
|
||||
r2(getUrl('plan/view/') . $id, 'd', "Customer not found");
|
||||
}
|
||||
Package::createInvoice($in);
|
||||
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
|
||||
$logo = '';
|
||||
if (file_exists($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png')) {
|
||||
$logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'logo.png';
|
||||
$imgsize = getimagesize($logo);
|
||||
$width = $imgsize[0];
|
||||
$height = $imgsize[1];
|
||||
$ui->assign('wlogo', $width);
|
||||
$ui->assign('hlogo', $height);
|
||||
}
|
||||
|
||||
$ui->assign('public_url', getUrl("voucher/invoice/$id/".md5($id. $db_pass)));
|
||||
$ui->assign('logo', $logo);
|
||||
$ui->assign('_title', 'View Invoice');
|
||||
$ui->display('invoice.tpl');
|
||||
$ui->display('admin/plan/invoice.tpl');
|
||||
break;
|
||||
|
||||
|
||||
@ -228,20 +297,22 @@ switch ($action) {
|
||||
$ui->assign('content', $content);
|
||||
} else {
|
||||
$id = _post('id');
|
||||
if (empty($id)) {
|
||||
$id = $routes['2'];
|
||||
}
|
||||
$d = ORM::for_table('tbl_transactions')->where('id', $id)->find_one();
|
||||
$ui->assign('in', $d);
|
||||
$ui->assign('date', Lang::dateAndTimeFormat($d['recharged_on'], $d['recharged_time']));
|
||||
}
|
||||
|
||||
run_hook('print_invoice'); #HOOK
|
||||
$ui->display('invoice-print.tpl');
|
||||
$ui->display('admin/plan/invoice-print.tpl');
|
||||
break;
|
||||
|
||||
case 'edit':
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$id = $routes['2'];
|
||||
$id = $routes['2'];
|
||||
$d = ORM::for_table('tbl_user_recharges')->find_one($id);
|
||||
if ($d) {
|
||||
$ui->assign('d', $d);
|
||||
@ -261,9 +332,9 @@ switch ($action) {
|
||||
$ui->assign('p', $ps);
|
||||
run_hook('view_edit_customer_plan'); #HOOK
|
||||
$ui->assign('_title', 'Edit Plan');
|
||||
$ui->display('plan-edit.tpl');
|
||||
$ui->display('admin/plan/edit.tpl');
|
||||
} else {
|
||||
r2(U . 'plan/list', 'e', Lang::T('Account Not Found'));
|
||||
r2(getUrl('plan/list'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -271,7 +342,7 @@ switch ($action) {
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$id = $routes['2'];
|
||||
$id = $routes['2'];
|
||||
$d = ORM::for_table('tbl_user_recharges')->find_one($id);
|
||||
if ($d) {
|
||||
run_hook('delete_customer_active_plan'); #HOOK
|
||||
@ -288,7 +359,7 @@ switch ($action) {
|
||||
}
|
||||
$d->delete();
|
||||
_log('[' . $admin['username'] . ']: ' . 'Delete Plan for Customer ' . $c['username'] . ' [' . $in['plan_name'] . '][' . Lang::moneyFormat($in['price']) . ']', $admin['user_type'], $admin['id']);
|
||||
r2(U . 'plan/list', 's', Lang::T('Data Deleted Successfully'));
|
||||
r2(getUrl('plan/list'), 's', Lang::T('Data Deleted Successfully'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -354,14 +425,14 @@ switch ($action) {
|
||||
}
|
||||
$d->save();
|
||||
_log('[' . $admin['username'] . ']: ' . 'Edit Plan for Customer ' . $d['username'] . ' to [' . $d['namebp'] . '][' . Lang::moneyFormat($p['price']) . ']', $admin['user_type'], $admin['id']);
|
||||
r2(U . 'plan/list', 's', Lang::T('Data Updated Successfully'));
|
||||
r2(getUrl('plan/list'), 's', Lang::T('Data Updated Successfully'));
|
||||
} else {
|
||||
r2(U . 'plan/edit/' . $id, 'e', $msg);
|
||||
r2(getUrl('plan/edit/') . $id, 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'voucher':
|
||||
$ui->assign('_title', Lang::T('Vouchers'));
|
||||
$ui->assign('_title', Lang::T('Voucher Cards'));
|
||||
$search = _req('search');
|
||||
$router = _req('router');
|
||||
$customer = _req('customer');
|
||||
@ -371,9 +442,10 @@ switch ($action) {
|
||||
$ui->assign('customer', $customer);
|
||||
$ui->assign('status', $status);
|
||||
$ui->assign('plan', $plan);
|
||||
$ui->assign('_system_menu', 'cards');
|
||||
|
||||
$query = ORM::for_table('tbl_plans')
|
||||
->left_outer_join('tbl_voucher', array('tbl_plans.id', '=', 'tbl_voucher.id_plan'));
|
||||
->inner_join('tbl_voucher', ['tbl_plans.id', '=', 'tbl_voucher.id_plan']);
|
||||
|
||||
if (!empty($router)) {
|
||||
$query->where('tbl_voucher.routers', $router);
|
||||
@ -394,7 +466,7 @@ switch ($action) {
|
||||
$append_url = "&search=" . urlencode($search) . "&router=" . urlencode($router) . "&customer=" . urlencode($customer) . "&plan=" . urlencode($plan) . "&status=" . urlencode($status);
|
||||
|
||||
// option customers
|
||||
$ui->assign('customers', ORM::for_table('tbl_voucher')->distinct()->select("user")->whereNotEqual("user", '0')->findArray());
|
||||
$ui->assign('customers', ORM::for_table('tbl_voucher')->distinct()->select("user")->whereNotEqual("user", '0')->findArray());
|
||||
// option plans
|
||||
$plns = ORM::for_table('tbl_voucher')->distinct()->select("id_plan")->findArray();
|
||||
if (count($plns) > 0) {
|
||||
@ -458,7 +530,7 @@ switch ($action) {
|
||||
$ui->assign('search', $search);
|
||||
$ui->assign('page', $page);
|
||||
run_hook('view_list_voucher'); #HOOK
|
||||
$ui->display('voucher.tpl');
|
||||
$ui->display('admin/voucher/list.tpl');
|
||||
break;
|
||||
|
||||
case 'add-voucher':
|
||||
@ -473,7 +545,7 @@ switch ($action) {
|
||||
$r = ORM::for_table('tbl_routers')->where('enabled', '1')->find_many();
|
||||
$ui->assign('r', $r);
|
||||
run_hook('view_add_voucher'); #HOOK
|
||||
$ui->display('voucher-add.tpl');
|
||||
$ui->display('admin/voucher/add.tpl');
|
||||
break;
|
||||
|
||||
case 'remove-voucher':
|
||||
@ -492,7 +564,7 @@ switch ($action) {
|
||||
$jml++;
|
||||
}
|
||||
}
|
||||
r2(U . 'plan/voucher', 's', "$jml " . Lang::T('Data Deleted Successfully'));
|
||||
r2(getUrl('plan/voucher'), 's', "$jml " . Lang::T('Data Deleted Successfully'));
|
||||
}
|
||||
case 'print-voucher':
|
||||
$from_id = _post('from_id');
|
||||
@ -500,12 +572,15 @@ switch ($action) {
|
||||
$pagebreak = _post('pagebreak');
|
||||
$limit = _post('limit');
|
||||
$vpl = _post('vpl');
|
||||
$selected_datetime = _post('selected_datetime');
|
||||
if (empty($vpl)) {
|
||||
$vpl = 3;
|
||||
}
|
||||
if ($pagebreak < 1) $pagebreak = 12;
|
||||
if ($pagebreak < 1)
|
||||
$pagebreak = 12;
|
||||
|
||||
if ($limit < 1) $limit = $pagebreak * 2;
|
||||
if ($limit < 1)
|
||||
$limit = $pagebreak * 2;
|
||||
if (empty($from_id)) {
|
||||
$from_id = 0;
|
||||
}
|
||||
@ -542,6 +617,17 @@ switch ($action) {
|
||||
->left_outer_join('tbl_voucher', array('tbl_plans.id', '=', 'tbl_voucher.id_plan'))
|
||||
->where('tbl_voucher.status', '0')
|
||||
->where_gt('tbl_voucher.id', $from_id);
|
||||
} else if ($from_id > 0 && $planid == 0 && $selected_datetime != '') {
|
||||
$v = ORM::for_table('tbl_plans')
|
||||
->left_outer_join('tbl_voucher', array('tbl_plans.id', '=', 'tbl_voucher.id_plan'))
|
||||
->where('tbl_voucher.status', '0')
|
||||
->where_raw("DATE(created_at) = ?", [$selected_datetime])
|
||||
->where_gt('tbl_voucher.id', $from_id)
|
||||
->limit($limit);
|
||||
$vc = ORM::for_table('tbl_plans')
|
||||
->left_outer_join('tbl_voucher', array('tbl_plans.id', '=', 'tbl_voucher.id_plan'))
|
||||
->where('tbl_voucher.status', '0')
|
||||
->where_gt('tbl_voucher.id', $from_id);
|
||||
} else {
|
||||
$v = ORM::for_table('tbl_plans')
|
||||
->left_outer_join('tbl_voucher', array('tbl_plans.id', '=', 'tbl_voucher.id_plan'))
|
||||
@ -551,6 +637,16 @@ switch ($action) {
|
||||
->left_outer_join('tbl_voucher', array('tbl_plans.id', '=', 'tbl_voucher.id_plan'))
|
||||
->where('tbl_voucher.status', '0');
|
||||
}
|
||||
if (!empty($selected_datetime)) {
|
||||
$v = ORM::for_table('tbl_plans')
|
||||
->left_outer_join('tbl_voucher', array('tbl_plans.id', '=', 'tbl_voucher.id_plan'))
|
||||
->where('tbl_voucher.status', '0')
|
||||
->where('tbl_voucher.created_at', $selected_datetime)
|
||||
->limit($limit);
|
||||
$vc = ORM::for_table('tbl_plans')
|
||||
->left_outer_join('tbl_voucher', array('tbl_plans.id', '=', 'tbl_voucher.id_plan'))
|
||||
->where('tbl_voucher.status', '0');
|
||||
}
|
||||
if (in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
$v = $v->find_many();
|
||||
$vc = $vc->count();
|
||||
@ -577,6 +673,19 @@ switch ($action) {
|
||||
$ui->assign('limit', $limit);
|
||||
$ui->assign('planid', $planid);
|
||||
|
||||
$createdate = ORM::for_table('tbl_voucher')
|
||||
->select_expr(
|
||||
"CASE WHEN DATE(created_at) = CURDATE() THEN 'Today' ELSE DATE(created_at) END",
|
||||
'created_datetime'
|
||||
)
|
||||
->where_not_equal('created_at', '0')
|
||||
->select_expr('COUNT(*)', 'voucher_count')
|
||||
->group_by('created_datetime')
|
||||
->order_by_desc('created_datetime')
|
||||
->find_array();
|
||||
|
||||
$ui->assign('createdate', $createdate);
|
||||
|
||||
$voucher = [];
|
||||
$n = 1;
|
||||
foreach ($v as $vs) {
|
||||
@ -592,16 +701,21 @@ switch ($action) {
|
||||
|
||||
$ui->assign('voucher', $voucher);
|
||||
$ui->assign('vc', $vc);
|
||||
$ui->assign('selected_datetime', $selected_datetime);
|
||||
|
||||
//for counting pagebreak
|
||||
$ui->assign('jml', 0);
|
||||
run_hook('view_print_voucher'); #HOOK
|
||||
$ui->display('print-voucher.tpl');
|
||||
$ui->display('admin/print/voucher.tpl');
|
||||
break;
|
||||
case 'voucher-post':
|
||||
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 ($_app_stage == 'Demo') {
|
||||
r2(getUrl('plan/add-voucher/'), 'e', 'You cannot perform this action in Demo mode');
|
||||
}
|
||||
|
||||
$type = _post('type');
|
||||
$plan = _post('plan');
|
||||
$voucher_format = _post('voucher_format');
|
||||
@ -609,18 +723,22 @@ switch ($action) {
|
||||
$server = _post('server');
|
||||
$numbervoucher = _post('numbervoucher');
|
||||
$lengthcode = _post('lengthcode');
|
||||
$printNow = _post('print_now', 'no');
|
||||
$voucherPerPage = _post('voucher_per_page', '36');
|
||||
|
||||
$msg = '';
|
||||
if ($type == '' or $plan == '' or $server == '' or $numbervoucher == '' or $lengthcode == '') {
|
||||
$msg .= Lang::T('All field is required') . '<br>';
|
||||
if (empty($type) || empty($plan) || empty($server) || empty($numbervoucher) || empty($lengthcode)) {
|
||||
$msg .= Lang::T('All fields are required') . '<br>';
|
||||
}
|
||||
if (Validator::UnsignedNumber($numbervoucher) == false) {
|
||||
if (!Validator::UnsignedNumber($numbervoucher)) {
|
||||
$msg .= 'The Number of Vouchers must be a number' . '<br>';
|
||||
}
|
||||
if (Validator::UnsignedNumber($lengthcode) == false) {
|
||||
if (!Validator::UnsignedNumber($lengthcode)) {
|
||||
$msg .= 'The Length Code must be a number' . '<br>';
|
||||
}
|
||||
|
||||
if ($msg == '') {
|
||||
// Update or create voucher prefix
|
||||
if (!empty($prefix)) {
|
||||
$d = ORM::for_table('tbl_appconfig')->where('setting', 'voucher_prefix')->find_one();
|
||||
if ($d) {
|
||||
@ -633,11 +751,14 @@ switch ($action) {
|
||||
$d->save();
|
||||
}
|
||||
}
|
||||
run_hook('create_voucher'); #HOOK
|
||||
|
||||
run_hook('create_voucher'); // HOOK
|
||||
$vouchers = [];
|
||||
$newVoucherIds = [];
|
||||
|
||||
if ($voucher_format == 'numbers') {
|
||||
if (strlen($lengthcode) < 6) {
|
||||
$msg .= 'The Length Code must be a more than 6 for numbers' . '<br>';
|
||||
if ($lengthcode < 6) {
|
||||
$msg .= 'The Length Code must be more than 6 for numbers' . '<br>';
|
||||
}
|
||||
$vouchers = generateUniqueNumericVouchers($numbervoucher, $lengthcode);
|
||||
} else {
|
||||
@ -657,19 +778,91 @@ switch ($action) {
|
||||
$d->type = $type;
|
||||
$d->routers = $server;
|
||||
$d->id_plan = $plan;
|
||||
$d->code = $prefix . $code;
|
||||
$d->code = "$prefix$code";
|
||||
$d->user = '0';
|
||||
$d->status = '0';
|
||||
$d->generated_by = $admin['id'];
|
||||
$d->save();
|
||||
}
|
||||
if ($numbervoucher == 1) {
|
||||
r2(U . 'plan/voucher-view/' . $d->id(), 's', Lang::T('Create Vouchers Successfully'));
|
||||
$newVoucherIds[] = $d->id();
|
||||
}
|
||||
|
||||
r2(U . 'plan/voucher', 's', Lang::T('Create Vouchers Successfully'));
|
||||
if ($printNow == 'yes' && count($newVoucherIds) > 0) {
|
||||
$template = file_get_contents("pages/Voucher.html");
|
||||
$template = str_replace('[[company_name]]', $config['CompanyName'], $template);
|
||||
|
||||
$vouchersToPrint = ORM::for_table('tbl_voucher')
|
||||
->left_outer_join('tbl_plans', ['tbl_plans.id', '=', 'tbl_voucher.id_plan'])
|
||||
->where_in('tbl_voucher.id', $newVoucherIds)
|
||||
->find_many();
|
||||
|
||||
$voucherHtmls = [];
|
||||
$n = 1;
|
||||
|
||||
foreach ($vouchersToPrint as $vs) {
|
||||
$temp = $template;
|
||||
$temp = str_replace('[[qrcode]]', '<img src="qrcode/?data=' . $vs['code'] . '">', $temp);
|
||||
$temp = str_replace('[[price]]', Lang::moneyFormat($vs['price']), $temp);
|
||||
$temp = str_replace('[[voucher_code]]', $vs['code'], $temp);
|
||||
$temp = str_replace('[[plan]]', $vs['name_plan'], $temp);
|
||||
$temp = str_replace('[[counter]]', $n, $temp);
|
||||
$voucherHtmls[] = $temp;
|
||||
$n++;
|
||||
}
|
||||
|
||||
$vc = count($voucherHtmls);
|
||||
$ui->assign('voucher', $voucherHtmls);
|
||||
$ui->assign('vc', $vc);
|
||||
$ui->assign('jml', 0);
|
||||
$ui->assign('from_id', 0);
|
||||
$ui->assign('vpl', '3');
|
||||
$ui->assign('pagebreak', $voucherPerPage);
|
||||
$ui->display('admin/print/voucher.tpl');
|
||||
}
|
||||
|
||||
if ($numbervoucher == 1) {
|
||||
r2(getUrl('plan/voucher-view/') . $d->id(), 's', Lang::T('Create Vouchers Successfully'));
|
||||
}
|
||||
|
||||
r2(getUrl('plan/voucher'), 's', Lang::T('Create Vouchers Successfully'));
|
||||
} else {
|
||||
r2(U . 'plan/add-voucher/' . $id, 'e', $msg);
|
||||
r2(getUrl('plan/add-voucher/') . $id, 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'voucher-delete-many':
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$admin = Admin::_info();
|
||||
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T('You do not have permission to access this page')]);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$voucherIds = json_decode($_POST['voucherIds'], true);
|
||||
|
||||
if (is_array($voucherIds) && !empty($voucherIds)) {
|
||||
$voucherIds = array_map('intval', $voucherIds);
|
||||
|
||||
try {
|
||||
ORM::for_table('tbl_voucher')
|
||||
->where_in('id', $voucherIds)
|
||||
->delete_many();
|
||||
} catch (Exception $e) {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T('Failed to delete vouchers.')]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Return success response
|
||||
echo json_encode(['status' => 'success', 'message' => Lang::T("Vouchers Deleted Successfully.")]);
|
||||
exit;
|
||||
} else {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T("Invalid or missing voucher IDs.")]);
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
echo json_encode(['status' => 'error', 'message' => Lang::T("Invalid request method.")]);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -687,11 +880,11 @@ switch ($action) {
|
||||
$voucher = ORM::for_table('tbl_voucher')
|
||||
->find_one($id);
|
||||
if (!in_array($voucher['generated_by'], $sales)) {
|
||||
r2(U . 'plan/voucher/', 'e', Lang::T('Voucher Not Found'));
|
||||
r2(getUrl('plan/voucher/'), 'e', Lang::T('Voucher Not Found'));
|
||||
}
|
||||
}
|
||||
if (!$voucher) {
|
||||
r2(U . 'plan/voucher/', 'e', Lang::T('Voucher Not Found'));
|
||||
r2(getUrl('plan/voucher/'), 'e', Lang::T('Voucher Not Found'));
|
||||
}
|
||||
$plan = ORM::for_table('tbl_plans')->find_one($voucher['id_plan']);
|
||||
if ($voucher && $plan) {
|
||||
@ -723,21 +916,21 @@ switch ($action) {
|
||||
$content .= Lang::pad($config['note'], ' ', 2) . "\n";
|
||||
$ui->assign('_title', Lang::T('View'));
|
||||
$ui->assign('whatsapp', urlencode("```$content```"));
|
||||
$ui->display('voucher-view.tpl');
|
||||
$ui->display('admin/voucher/view.tpl');
|
||||
} else {
|
||||
r2(U . 'plan/voucher/', 'e', Lang::T('Voucher Not Found'));
|
||||
r2(getUrl('plan/voucher/'), 'e', Lang::T('Voucher Not Found'));
|
||||
}
|
||||
break;
|
||||
case 'voucher-delete':
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$id = $routes['2'];
|
||||
$id = $routes['2'];
|
||||
run_hook('delete_voucher'); #HOOK
|
||||
$d = ORM::for_table('tbl_voucher')->find_one($id);
|
||||
if ($d) {
|
||||
$d->delete();
|
||||
r2(U . 'plan/voucher', 's', Lang::T('Data Deleted Successfully'));
|
||||
r2(getUrl('plan/voucher'), 's', Lang::T('Data Deleted Successfully'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -748,7 +941,7 @@ switch ($action) {
|
||||
$ui->assign('xfooter', $select2_customer);
|
||||
$ui->assign('_title', Lang::T('Refill Account'));
|
||||
run_hook('view_refill'); #HOOK
|
||||
$ui->display('refill.tpl');
|
||||
$ui->display('admin/plan/refill.tpl');
|
||||
|
||||
break;
|
||||
|
||||
@ -758,7 +951,7 @@ switch ($action) {
|
||||
}
|
||||
$code = Text::alphanumeric(_post('code'), "-_.,");
|
||||
$user = ORM::for_table('tbl_customers')->where('id', _post('id_customer'))->find_one();
|
||||
$v1 = ORM::for_table('tbl_voucher')->whereRaw("BINARY `code` = '$code'")->where('status', 0)->find_one();
|
||||
$v1 = ORM::for_table('tbl_voucher')->whereRaw("BINARY code = '$code'")->where('status', 0)->find_one();
|
||||
|
||||
run_hook('refill_customer'); #HOOK
|
||||
if ($v1) {
|
||||
@ -768,12 +961,12 @@ switch ($action) {
|
||||
$v1->save();
|
||||
$in = ORM::for_table('tbl_transactions')->where('username', $user['username'])->order_by_desc('id')->find_one();
|
||||
Package::createInvoice($in);
|
||||
$ui->display('invoice.tpl');
|
||||
$ui->display('admin/plan/invoice.tpl');
|
||||
} else {
|
||||
r2(U . 'plan/refill', 'e', "Failed to refill account");
|
||||
r2(getUrl('plan/refill'), 'e', "Failed to refill account");
|
||||
}
|
||||
} else {
|
||||
r2(U . 'plan/refill', 'e', Lang::T('Voucher Not Valid'));
|
||||
r2(getUrl('plan/refill'), 'e', Lang::T('Voucher Not Valid'));
|
||||
}
|
||||
break;
|
||||
case 'deposit':
|
||||
@ -788,46 +981,64 @@ switch ($action) {
|
||||
$ui->assign('p', ORM::for_table('tbl_plans')->where('enabled', '1')->where('type', 'Balance')->find_many());
|
||||
}
|
||||
run_hook('view_deposit'); #HOOK
|
||||
$ui->display('deposit.tpl');
|
||||
$ui->display('admin/plan/deposit.tpl');
|
||||
break;
|
||||
case 'deposit-post':
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent', 'Sales'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$user = _post('id_customer');
|
||||
$amount = _post('amount');
|
||||
$plan = _post('id_plan');
|
||||
$stoken = _req('stoken');
|
||||
if (App::getTokenValue($stoken)) {
|
||||
$c = ORM::for_table('tbl_customers')->where('id', $user)->find_one();
|
||||
$in = ORM::for_table('tbl_transactions')->where('username', $c['username'])->order_by_desc('id')->find_one();
|
||||
$note = _post('note');
|
||||
$svoucher = _req('svoucher');
|
||||
$c = ORM::for_table('tbl_customers')->find_one($user);
|
||||
if (App::getVoucherValue($svoucher)) {
|
||||
$in = ORM::for_table('tbl_transactions')->find_one(App::getVoucherValue($svoucher));
|
||||
Package::createInvoice($in);
|
||||
$ui->display('invoice.tpl');
|
||||
$ui->display('admin/plan/invoice.tpl');
|
||||
die();
|
||||
}
|
||||
|
||||
run_hook('deposit_customer'); #HOOK
|
||||
if (!empty($user) && !empty($plan)) {
|
||||
if (Package::rechargeUser($user, 'balance', $plan, "Deposit", $admin['fullname'])) {
|
||||
$c = ORM::for_table('tbl_customers')->where('id', $user)->find_one();
|
||||
$in = ORM::for_table('tbl_transactions')->where('username', $c['username'])->order_by_desc('id')->find_one();
|
||||
if (!empty($user) && strlen($amount) > 0 && $amount != 0) {
|
||||
$plan = [];
|
||||
$plan['name_plan'] = Lang::T('Balance');
|
||||
$plan['price'] = $amount;
|
||||
$trxId = Package::rechargeBalance($c, $plan, "Deposit", $admin['fullname'], $note);
|
||||
if ($trxId > 0) {
|
||||
$in = ORM::for_table('tbl_transactions')->find_one($trxId);
|
||||
Package::createInvoice($in);
|
||||
if (!empty($stoken)) {
|
||||
App::setToken($stoken, $in['id']);
|
||||
if (!empty($svoucher)) {
|
||||
App::setVoucher($svoucher, $trxId);
|
||||
}
|
||||
$ui->display('invoice.tpl');
|
||||
$ui->display('admin/plan/invoice.tpl');
|
||||
} else {
|
||||
r2(U . 'plan/refill', 'e', "Failed to refill account");
|
||||
r2(getUrl('plan/refill'), 'e', "Failed to refill account");
|
||||
}
|
||||
} else if (!empty($user) && !empty($plan)) {
|
||||
$p = ORM::for_table('tbl_plans')->find_one($plan);
|
||||
$trxId = Package::rechargeBalance($c, $p, "Deposit", $admin['fullname'], $note);
|
||||
if ($trxId > 0) {
|
||||
$in = ORM::for_table('tbl_transactions')->find_one($trxId);
|
||||
Package::createInvoice($in);
|
||||
if (!empty($svoucher)) {
|
||||
App::setVoucher($svoucher, $trxId);
|
||||
}
|
||||
$ui->display('admin/plan/invoice.tpl');
|
||||
} else {
|
||||
r2(getUrl('plan/refill'), 'e', "Failed to refill account");
|
||||
}
|
||||
} else {
|
||||
r2(U . 'plan/refill', 'e', "All field is required");
|
||||
r2(getUrl('plan/refill'), 'e', "All field is required");
|
||||
}
|
||||
break;
|
||||
case 'extend':
|
||||
$id = $routes[2];
|
||||
$days = $routes[3];
|
||||
$stoken = $_GET['stoken'];
|
||||
if (App::getTokenValue($stoken)) {
|
||||
r2(U . 'plan', 's', "Extend already done");
|
||||
$svoucher = $_GET['svoucher'];
|
||||
if (App::getVoucherValue($svoucher)) {
|
||||
r2(getUrl('plan'), 's', "Extend already done");
|
||||
}
|
||||
$tur = ORM::for_table('tbl_user_recharges')->find_one($id);
|
||||
$status = $tur['status'];
|
||||
@ -839,7 +1050,7 @@ switch ($action) {
|
||||
//expired
|
||||
$expiration = date('Y-m-d', strtotime(" +$days day"));
|
||||
}
|
||||
App::setToken($stoken, $id);
|
||||
App::setVoucher($svoucher, $id);
|
||||
$c = ORM::for_table('tbl_customers')->findOne($tur['customer_id']);
|
||||
if ($c) {
|
||||
$p = ORM::for_table('tbl_plans')->find_one($tur['plan_id']);
|
||||
@ -848,6 +1059,8 @@ switch ($action) {
|
||||
if ($_app_stage != 'demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
global $isChangePlan;
|
||||
$isChangePlan = true;
|
||||
(new $p['device'])->add_customer($c, $p);
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
@ -857,23 +1070,22 @@ switch ($action) {
|
||||
$tur->status = "on";
|
||||
$tur->save();
|
||||
} else {
|
||||
r2(U . 'plan', 's', "Plan not found");
|
||||
r2(getUrl('plan'), 's', "Plan not found");
|
||||
}
|
||||
} else {
|
||||
r2(U . 'plan', 's', "Customer not found");
|
||||
r2(getUrl('plan'), 's', "Customer not found");
|
||||
}
|
||||
Message::sendTelegram("#u$tur[username] #extend #" . $p['type'] . " \n" . $p['name_plan'] .
|
||||
Message::sendTelegram("#u$tur[username] #id$tur[customer_id] #extend by $admin[fullname] #" . $p['type'] . " \n" . $p['name_plan'] .
|
||||
"\nLocation: " . $p['routers'] .
|
||||
"\nCustomer: " . $c['fullname'] .
|
||||
"\nNew Expired: " . Lang::dateAndTimeFormat($expiration, $tur['time']));
|
||||
_log("$admin[fullname] extend Customer $tur[customer_id] $tur[username] for $days days", $admin['user_type'], $admin['id']);
|
||||
r2(U . 'plan', 's', "Extend until $expiration");
|
||||
_log("$admin[fullname] extend Customer $tur[customer_id] $tur[username] #$tur[customer_id] for $days days", $admin['user_type'], $admin['id']);
|
||||
r2(getUrl('plan'), 's', "Extend until $expiration");
|
||||
} else {
|
||||
r2(U . 'plan', 's', "Customer is not expired yet");
|
||||
r2(getUrl('plan'), 's', "Customer is not expired yet");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/plan.js"></script>');
|
||||
$ui->assign('_title', Lang::T('Customer'));
|
||||
$search = _post('search');
|
||||
$status = _req('status');
|
||||
@ -914,6 +1126,6 @@ switch ($action) {
|
||||
$d = Paginator::findMany($query, ['search' => $search], 25, $append_url);
|
||||
run_hook('view_list_billing'); #HOOK
|
||||
$ui->assign('d', $d);
|
||||
$ui->display('plan.tpl');
|
||||
$ui->display('admin/plan/active.tpl');
|
||||
break;
|
||||
}
|
||||
|
@ -7,5 +7,5 @@
|
||||
if(function_exists($routes[1])){
|
||||
call_user_func($routes[1]);
|
||||
}else{
|
||||
r2(U.'dashboard', 'e', 'Function not found');
|
||||
r2(getUrl('dashboard'), 'e', 'Function not found');
|
||||
}
|
@ -25,7 +25,7 @@ if (file_exists($cache) && time() - filemtime($cache) < (24 * 60 * 60)) {
|
||||
$json = json_decode($txt, true);
|
||||
if (empty($json['plugins']) && empty($json['payment_gateway'])) {
|
||||
unlink($cache);
|
||||
r2(U . 'pluginmanager');
|
||||
r2(getUrl('pluginmanager'));
|
||||
}
|
||||
} else {
|
||||
$data = Http::getData($plugin_repository);
|
||||
@ -34,24 +34,25 @@ if (file_exists($cache) && time() - filemtime($cache) < (24 * 60 * 60)) {
|
||||
}
|
||||
switch ($action) {
|
||||
case 'refresh':
|
||||
if (file_exists($cache)) unlink($cache);
|
||||
r2(U . "pluginmanager", 's', 'Refresh success');
|
||||
if (file_exists($cache))
|
||||
unlink($cache);
|
||||
r2(getUrl('pluginmanager'), 's', 'Refresh success');
|
||||
break;
|
||||
case 'dlinstall':
|
||||
if ($_app_stage == 'demo') {
|
||||
r2(U . "pluginmanager", 'e', 'Demo Mode cannot install as it Security risk');
|
||||
if ($_app_stage == 'Demo') {
|
||||
r2(getUrl('pluginmanager'), 'e', 'Demo Mode cannot install as it Security risk');
|
||||
}
|
||||
if (!is_writeable($CACHE_PATH)) {
|
||||
r2(U . "pluginmanager", 'e', 'Folder cache/ is not writable');
|
||||
r2(getUrl('pluginmanager'), 'e', 'Folder cache/ is not writable');
|
||||
}
|
||||
if (!is_writeable($PLUGIN_PATH)) {
|
||||
r2(U . "pluginmanager", 'e', 'Folder plugin/ is not writable');
|
||||
r2(getUrl('pluginmanager'), 'e', 'Folder plugin/ is not writable');
|
||||
}
|
||||
if (!is_writeable($DEVICE_PATH)) {
|
||||
r2(U . "pluginmanager", 'e', 'Folder devices/ is not writable');
|
||||
r2(getUrl('pluginmanager'), 'e', 'Folder devices/ is not writable');
|
||||
}
|
||||
if (!is_writeable($UI_PATH . DIRECTORY_SEPARATOR . 'themes')) {
|
||||
r2(U . "pluginmanager", 'e', 'Folder themes/ is not writable');
|
||||
r2(getUrl('pluginmanager'), 'e', 'Folder themes/ is not writable');
|
||||
}
|
||||
$cache = $CACHE_PATH . DIRECTORY_SEPARATOR . 'installer' . DIRECTORY_SEPARATOR;
|
||||
if (!file_exists($cache)) {
|
||||
@ -97,7 +98,7 @@ switch ($action) {
|
||||
}
|
||||
//Cleaning
|
||||
File::deleteFolder($cache);
|
||||
r2(U . "pluginmanager", 's', 'Installation success');
|
||||
r2(getUrl('pluginmanager'), 's', 'Installation success');
|
||||
} else if (_post('gh_url', '') != '') {
|
||||
$ghUrl = _post('gh_url', '');
|
||||
if (!empty($config['github_token']) && !empty($config['github_username'])) {
|
||||
@ -121,7 +122,7 @@ switch ($action) {
|
||||
$zip->extractTo($cache);
|
||||
$zip->close();
|
||||
$folder = $cache . DIRECTORY_SEPARATOR . $plugin . '-main' . DIRECTORY_SEPARATOR;
|
||||
if(!file_exists($folder)) {
|
||||
if (!file_exists($folder)) {
|
||||
$folder = $cache . DIRECTORY_SEPARATOR . $plugin . '-master' . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
$success = 0;
|
||||
@ -155,23 +156,27 @@ switch ($action) {
|
||||
}
|
||||
}
|
||||
File::deleteFolder($cache);
|
||||
r2(U . "pluginmanager", 's', 'Installation success');
|
||||
r2(getUrl('pluginmanager'), 's', 'Installation success');
|
||||
} else {
|
||||
r2(U . 'pluginmanager', 'e', 'Nothing Installed');
|
||||
r2(getUrl('pluginmanager'), 'e', 'Nothing Installed');
|
||||
}
|
||||
break;
|
||||
case 'delete':
|
||||
if ($_app_stage == 'Demo') {
|
||||
r2(getUrl('pluginmanager'), 'e', 'You cannot perform this action in Demo mode');
|
||||
}
|
||||
if (!is_writeable($CACHE_PATH)) {
|
||||
r2(U . "pluginmanager", 'e', 'Folder cache/ is not writable');
|
||||
r2(getUrl('pluginmanager'), 'e', 'Folder cache/ is not writable');
|
||||
}
|
||||
if (!is_writeable($PLUGIN_PATH)) {
|
||||
r2(U . "pluginmanager", 'e', 'Folder plugin/ is not writable');
|
||||
r2(getUrl('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 (file_exists($file))
|
||||
unlink($file);
|
||||
if ($tipe == 'plugin') {
|
||||
foreach ($json['plugins'] as $plg) {
|
||||
if ($plg['id'] == $plugin) {
|
||||
@ -199,12 +204,12 @@ switch ($action) {
|
||||
$folder = $CACHE_PATH . File::pathFixer('/' . $plugin . '-master/');
|
||||
}
|
||||
if (!file_exists($folder)) {
|
||||
r2(U . "pluginmanager", 'e', 'Extracted Folder is unknown');
|
||||
r2(getUrl('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');
|
||||
r2(getUrl('pluginmanager'), 's', 'Plugin ' . $plugin . ' has been deleted');
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -212,17 +217,21 @@ switch ($action) {
|
||||
}
|
||||
break;
|
||||
case 'install':
|
||||
if ($_app_stage == 'Demo') {
|
||||
r2(getUrl('pluginmanager'), 'e', 'You cannot perform this action in Demo mode');
|
||||
}
|
||||
if (!is_writeable($CACHE_PATH)) {
|
||||
r2(U . "pluginmanager", 'e', 'Folder cache/ is not writable');
|
||||
r2(getUrl('pluginmanager'), 'e', 'Folder cache/ is not writable');
|
||||
}
|
||||
if (!is_writeable($PLUGIN_PATH)) {
|
||||
r2(U . "pluginmanager", 'e', 'Folder plugin/ is not writable');
|
||||
r2(getUrl('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 (file_exists($file))
|
||||
unlink($file);
|
||||
if ($tipe == 'plugin') {
|
||||
foreach ($json['plugins'] as $plg) {
|
||||
if ($plg['id'] == $plugin) {
|
||||
@ -250,12 +259,12 @@ switch ($action) {
|
||||
$folder = $CACHE_PATH . File::pathFixer('/' . $plugin . '-master/');
|
||||
}
|
||||
if (!file_exists($folder)) {
|
||||
r2(U . "pluginmanager", 'e', 'Extracted Folder is unknown');
|
||||
r2(getUrl('pluginmanager'), 'e', 'Extracted Folder is unknown');
|
||||
}
|
||||
File::copyFolder($folder, $PLUGIN_PATH . DIRECTORY_SEPARATOR, ['README.md', 'LICENSE']);
|
||||
File::deleteFolder($folder);
|
||||
unlink($file);
|
||||
r2(U . "pluginmanager", 's', 'Plugin ' . $plugin . ' has been installed');
|
||||
r2(getUrl('pluginmanager'), 's', 'Plugin ' . $plugin . ' has been installed');
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -287,12 +296,12 @@ switch ($action) {
|
||||
$folder = $CACHE_PATH . File::pathFixer('/' . $plugin . '-master/');
|
||||
}
|
||||
if (!file_exists($folder)) {
|
||||
r2(U . "pluginmanager", 'e', 'Extracted Folder is unknown');
|
||||
r2(getUrl('pluginmanager'), 'e', 'Extracted Folder is unknown');
|
||||
}
|
||||
File::copyFolder($folder, $PAYMENTGATEWAY_PATH . DIRECTORY_SEPARATOR, ['README.md', 'LICENSE']);
|
||||
File::deleteFolder($folder);
|
||||
unlink($file);
|
||||
r2(U . "paymentgateway", 's', 'Payment Gateway ' . $plugin . ' has been installed');
|
||||
r2(getUrl('paymentgateway'), 's', 'Payment Gateway ' . $plugin . ' has been installed');
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -324,12 +333,12 @@ switch ($action) {
|
||||
$folder = $CACHE_PATH . File::pathFixer('/' . $plugin . '-master/');
|
||||
}
|
||||
if (!file_exists($folder)) {
|
||||
r2(U . "pluginmanager", 'e', 'Extracted Folder is unknown');
|
||||
r2(getUrl('pluginmanager'), 'e', 'Extracted Folder is unknown');
|
||||
}
|
||||
File::copyFolder($folder, $DEVICE_PATH . DIRECTORY_SEPARATOR, ['README.md', 'LICENSE']);
|
||||
File::deleteFolder($folder);
|
||||
unlink($file);
|
||||
r2(U . "settings/devices", 's', 'Device ' . $plugin . ' has been installed');
|
||||
r2(getUrl('settings/devices'), 's', 'Device ' . $plugin . ' has been installed');
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -345,7 +354,7 @@ switch ($action) {
|
||||
$ui->assign('plugins', $json['plugins']);
|
||||
$ui->assign('pgs', $json['payment_gateway']);
|
||||
$ui->assign('dvcs', $json['devices']);
|
||||
$ui->display('plugin-manager.tpl');
|
||||
$ui->display('admin/settings/plugin-manager.tpl');
|
||||
}
|
||||
|
||||
|
||||
|
@ -20,7 +20,6 @@ require_once $DEVICE_PATH . DIRECTORY_SEPARATOR . 'MikrotikPppoe' . '.php';
|
||||
|
||||
switch ($action) {
|
||||
case 'list':
|
||||
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/pool.js"></script>');
|
||||
|
||||
$name = _post('name');
|
||||
if ($name != '') {
|
||||
@ -33,14 +32,14 @@ switch ($action) {
|
||||
|
||||
$ui->assign('d', $d);
|
||||
run_hook('view_pool'); #HOOK
|
||||
$ui->display('pool.tpl');
|
||||
$ui->display('admin/pool/list.tpl');
|
||||
break;
|
||||
|
||||
case 'add':
|
||||
$r = ORM::for_table('tbl_routers')->find_many();
|
||||
$ui->assign('r', $r);
|
||||
run_hook('view_add_pool'); #HOOK
|
||||
$ui->display('pool-add.tpl');
|
||||
$ui->display('admin/pool/add.tpl');
|
||||
break;
|
||||
|
||||
case 'edit':
|
||||
@ -49,9 +48,9 @@ switch ($action) {
|
||||
if ($d) {
|
||||
$ui->assign('d', $d);
|
||||
run_hook('view_edit_pool'); #HOOK
|
||||
$ui->display('pool-edit.tpl');
|
||||
$ui->display('admin/pool/edit.tpl');
|
||||
} else {
|
||||
r2(U . 'pool/list', 'e', Lang::T('Account Not Found'));
|
||||
r2(getUrl('pool/list'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -65,7 +64,7 @@ switch ($action) {
|
||||
}
|
||||
$d->delete();
|
||||
|
||||
r2(U . 'pool/list', 's', Lang::T('Data Deleted Successfully'));
|
||||
r2(getUrl('pool/list'), 's', Lang::T('Data Deleted Successfully'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -78,7 +77,7 @@ switch ($action) {
|
||||
$log .= 'DONE: ' . $pool['pool_name'] . ': ' . $pool['range_ip'] . '<br>';
|
||||
}
|
||||
}
|
||||
r2(U . 'pool/list', 's', $log);
|
||||
r2(getUrl('pool/list'), 's', $log);
|
||||
break;
|
||||
case 'add-post':
|
||||
$name = _post('name');
|
||||
@ -108,9 +107,9 @@ switch ($action) {
|
||||
(new MikrotikPppoe())->add_pool($b);
|
||||
}
|
||||
$b->save();
|
||||
r2(U . 'pool/list', 's', Lang::T('Data Created Successfully'));
|
||||
r2(getUrl('pool/list'), 's', Lang::T('Data Created Successfully'));
|
||||
} else {
|
||||
r2(U . 'pool/add', 'e', $msg);
|
||||
r2(getUrl('pool/add'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -143,12 +142,135 @@ switch ($action) {
|
||||
(new MikrotikPppoe())->update_pool($old, $d);
|
||||
}
|
||||
|
||||
r2(U . 'pool/list', 's', Lang::T('Data Updated Successfully'));
|
||||
r2(getUrl('pool/list'), 's', Lang::T('Data Updated Successfully'));
|
||||
} else {
|
||||
r2(U . 'pool/edit/' . $id, 'e', $msg);
|
||||
r2(getUrl('pool/edit/') . $id, 'e', $msg);
|
||||
}
|
||||
|
||||
case 'port':
|
||||
|
||||
$name = _post('name');
|
||||
if ($name != '') {
|
||||
$query = ORM::for_table('tbl_port_pool')->where_like('pool_name', '%' . $name . '%')->order_by_desc('id');
|
||||
$d = Paginator::findMany($query, ['name' => $name]);
|
||||
} else {
|
||||
$query = ORM::for_table('tbl_port_pool')->order_by_desc('id');
|
||||
$d = Paginator::findMany($query);
|
||||
}
|
||||
|
||||
$ui->assign('d', $d);
|
||||
run_hook('view_port'); #HOOK
|
||||
$ui->display('admin/port/list.tpl');
|
||||
break;
|
||||
|
||||
case 'add-port':
|
||||
$r = ORM::for_table('tbl_routers')->find_many();
|
||||
$ui->assign('r', $r);
|
||||
run_hook('view_add_port'); #HOOK
|
||||
$ui->display('admin/port/add.tpl');
|
||||
break;
|
||||
|
||||
case 'edit-port':
|
||||
$id = $routes['2'];
|
||||
$d = ORM::for_table('tbl_port_pool')->find_one($id);
|
||||
if ($d) {
|
||||
$ui->assign('d', $d);
|
||||
run_hook('view_edit_port'); #HOOK
|
||||
$ui->display('admin/port/edit.tpl');
|
||||
} else {
|
||||
r2(getUrl('pool/port'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'delete-port':
|
||||
$id = $routes['2'];
|
||||
run_hook('delete_port'); #HOOK
|
||||
$d = ORM::for_table('tbl_port_pool')->find_one($id);
|
||||
if ($d) {
|
||||
$d->delete();
|
||||
|
||||
r2(getUrl('pool/port'), 's', Lang::T('Data Deleted Successfully'));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'sync':
|
||||
$pools = ORM::for_table('tbl_port_pool')->find_many();
|
||||
$log = '';
|
||||
foreach ($pools as $pool) {
|
||||
if ($pool['routers'] != 'radius') {
|
||||
(new MikrotikPppoe())->update_pool($pool, $pool);
|
||||
$log .= 'DONE: ' . $pool['port_name'] . ': ' . $pool['range_port'] . '<br>';
|
||||
}
|
||||
}
|
||||
r2(getUrl('pool/list'), 's', $log);
|
||||
break;
|
||||
case 'add-port-post':
|
||||
$name = _post('name');
|
||||
$port_range = _post('port_range');
|
||||
$public_ip = _post('public_ip');
|
||||
$routers = _post('routers');
|
||||
run_hook('add_pool'); #HOOK
|
||||
$msg = '';
|
||||
if (Validator::Length($name, 30, 2) == false) {
|
||||
$msg .= 'Name should be between 3 to 30 characters' . '<br>';
|
||||
}
|
||||
if ($port_range == '' or $routers == '') {
|
||||
$msg .= Lang::T('All field is required') . '<br>';
|
||||
}
|
||||
|
||||
$d = ORM::for_table('tbl_port_pool')->where('routers', $routers)->find_one();
|
||||
if ($d) {
|
||||
$msg .= Lang::T('Routers already have ports, each router can only have 1 port range!') . '<br>';
|
||||
}
|
||||
if ($msg == '') {
|
||||
$b = ORM::for_table('tbl_port_pool')->create();
|
||||
$b->public_ip = $public_ip;
|
||||
$b->port_name = $name;
|
||||
$b->range_port = $port_range;
|
||||
$b->routers = $routers;
|
||||
$b->save();
|
||||
r2(getUrl('pool/port'), 's', Lang::T('Data Created Successfully'));
|
||||
} else {
|
||||
r2(getUrl('pool/add-port'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'edit-port-post':
|
||||
$name = _post('name');
|
||||
$public_ip = _post('public_ip');
|
||||
$range_port = _post('range_port');
|
||||
$routers = _post('routers');
|
||||
run_hook('edit_port'); #HOOK
|
||||
$msg = '';
|
||||
$msg = '';
|
||||
if (Validator::Length($name, 30, 2) == false) {
|
||||
$msg .= 'Name should be between 3 to 30 characters' . '<br>';
|
||||
}
|
||||
if ($range_port == '' or $routers == '') {
|
||||
$msg .= Lang::T('All field is required') . '<br>';
|
||||
}
|
||||
|
||||
$id = _post('id');
|
||||
$d = ORM::for_table('tbl_port_pool')->find_one($id);
|
||||
$old = ORM::for_table('tbl_port_pool')->find_one($id);
|
||||
if (!$d) {
|
||||
$msg .= Lang::T('Data Not Found') . '<br>';
|
||||
}
|
||||
|
||||
if ($msg == '') {
|
||||
$d->port_name = $name;
|
||||
$d->public_ip = $public_ip;
|
||||
$d->range_port = $range_port;
|
||||
$d->routers = $routers;
|
||||
$d->save();
|
||||
|
||||
r2(getUrl('pool/port'), 's', Lang::T('Data Updated Successfully'));
|
||||
} else {
|
||||
r2(getUrl('pool/edit-port/') . $id, 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
r2(U . 'pool/list/', 's', '');
|
||||
r2(getUrl('pool/list/'), 's', '');
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ switch ($action) {
|
||||
$ui->assign('_system_menu', 'radius');
|
||||
$ui->assign('_title', "Network Access Server");
|
||||
$ui->assign('routers', ORM::for_table('tbl_routers')->find_many());
|
||||
$ui->display('radius-nas-add.tpl');
|
||||
$ui->display('admin/radius/nas-add.tpl');
|
||||
break;
|
||||
case 'nas-add-post':
|
||||
$shortname = _post('shortname');
|
||||
@ -58,12 +58,12 @@ switch ($action) {
|
||||
if ($msg == '') {
|
||||
require_once $DEVICE_PATH . DIRECTORY_SEPARATOR . "Radius.php";
|
||||
if ((new Radius())->nasAdd($shortname, $nasname, $ports, $secret, $routers, $description, $type, $server, $community) > 0) {
|
||||
r2(U . 'radius/nas-list/', 's', "NAS Added");
|
||||
r2(getUrl('radius/nas-list/'), 's', "NAS Added");
|
||||
} else {
|
||||
r2(U . 'radius/nas-add/', 'e', "NAS Added Failed");
|
||||
r2(getUrl('radius/nas-add/'), 'e', "NAS Added Failed");
|
||||
}
|
||||
} else {
|
||||
r2(U . 'radius/nas-add', 'e', $msg);
|
||||
r2(getUrl('radius/nas-add'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
case 'nas-edit':
|
||||
@ -78,9 +78,9 @@ switch ($action) {
|
||||
if ($d) {
|
||||
$ui->assign('routers', ORM::for_table('tbl_routers')->find_many());
|
||||
$ui->assign('d', $d);
|
||||
$ui->display('radius-nas-edit.tpl');
|
||||
$ui->display('admin/radius/nas-edit.tpl');
|
||||
} else {
|
||||
r2(U . 'radius/list', 'e', Lang::T('Account Not Found'));
|
||||
r2(getUrl('radius/list'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
|
||||
break;
|
||||
@ -115,12 +115,12 @@ switch ($action) {
|
||||
if ($msg == '') {
|
||||
require_once $DEVICE_PATH . DIRECTORY_SEPARATOR . "Radius.php";
|
||||
if ((new Radius())->nasUpdate($id, $shortname, $nasname, $ports, $secret, $routers, $description, $type, $server, $community)) {
|
||||
r2(U . 'radius/list/', 's', "NAS Saved");
|
||||
r2(getUrl('radius/list/'), 's', "NAS Saved");
|
||||
} else {
|
||||
r2(U . 'radius/nas-add', 'e', 'NAS NOT Exists');
|
||||
r2(getUrl('radius/nas-add'), 'e', 'NAS NOT Exists');
|
||||
}
|
||||
} else {
|
||||
r2(U . 'radius/nas-add', 'e', $msg);
|
||||
r2(getUrl('radius/nas-add'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
case 'nas-delete':
|
||||
@ -129,7 +129,7 @@ switch ($action) {
|
||||
if ($d) {
|
||||
$d->delete();
|
||||
} else {
|
||||
r2(U . 'radius/nas-list', 'e', 'NAS Not found');
|
||||
r2(getUrl('radius/nas-list'), 'e', 'NAS Not found');
|
||||
}
|
||||
default:
|
||||
$ui->assign('_system_menu', 'radius');
|
||||
@ -147,5 +147,5 @@ switch ($action) {
|
||||
}
|
||||
$ui->assign('name', $name);
|
||||
$ui->assign('nas', $nas);
|
||||
$ui->display('radius-nas.tpl');
|
||||
$ui->display('admin/radius/nas.tpl');
|
||||
}
|
||||
|
@ -5,6 +5,9 @@
|
||||
* by https://t.me/ibnux
|
||||
**/
|
||||
|
||||
if ($_c['disable_registration'] == 'noreg') {
|
||||
_alert(Lang::T('Registration Disabled'), 'danger', "login");
|
||||
}
|
||||
if (isset($routes['1'])) {
|
||||
$do = $routes['1'];
|
||||
} else {
|
||||
@ -22,36 +25,39 @@ switch ($do) {
|
||||
$password = _post('password');
|
||||
$cpassword = _post('cpassword');
|
||||
$address = _post('address');
|
||||
if (!empty($config['sms_url']) && $_c['allow_phone_otp'] == 'yes') {
|
||||
$phonenumber = Lang::phoneFormat($username);
|
||||
$username = $phonenumber;
|
||||
} else if (strlen($username) < 21) {
|
||||
$phonenumber = $username;
|
||||
}
|
||||
|
||||
// Separate phone number input if OTP is required
|
||||
$phone_number = ($config['sms_otp_registration'] == 'yes') ? alphanumeric(_post('phone_number'), "+_.@-") : $username;
|
||||
|
||||
$msg = '';
|
||||
if (Validator::Length($username, 35, 2) == false) {
|
||||
$msg .= 'Username should be between 3 to 55 characters' . '<br>';
|
||||
$msg .= "Username should be between 3 to 55 characters<br>";
|
||||
}
|
||||
if (Validator::Length($fullname, 36, 2) == false) {
|
||||
$msg .= 'Full Name should be between 3 to 25 characters' . '<br>';
|
||||
if ($config['man_fields_fname'] == 'yes') {
|
||||
if (Validator::Length($fullname, 36, 2) == false) {
|
||||
$msg .= "Full Name should be between 3 to 25 characters<br>";
|
||||
}
|
||||
}
|
||||
if (!Validator::Length($password, 35, 2)) {
|
||||
$msg .= 'Password should be between 3 to 35 characters' . '<br>';
|
||||
$msg .= "Password should be between 3 to 35 characters<br>";
|
||||
}
|
||||
if (!Validator::Email($email)) {
|
||||
$msg .= 'Email is not Valid<br>';
|
||||
if ($config['man_fields_email'] == 'yes') {
|
||||
if (!Validator::Email($email)) {
|
||||
$msg .= 'Email is not Valid<br>';
|
||||
}
|
||||
}
|
||||
if ($password != $cpassword) {
|
||||
$msg .= Lang::T('Passwords does not match') . '<br>';
|
||||
}
|
||||
|
||||
if (!empty($config['sms_url']) && $_c['allow_phone_otp'] == 'yes') {
|
||||
$otpPath .= sha1($username . $db_pass) . ".txt";
|
||||
// OTP verification if OTP is enabled
|
||||
if ($_c['sms_otp_registration'] == 'yes') {
|
||||
$otpPath .= sha1("$phone_number$db_pass") . ".txt";
|
||||
run_hook('validate_otp'); #HOOK
|
||||
//expired 10 minutes
|
||||
// Expire after 10 minutes
|
||||
if (file_exists($otpPath) && time() - filemtime($otpPath) > 1200) {
|
||||
unlink($otpPath);
|
||||
r2(U . 'register', 's', 'Verification code expired');
|
||||
r2(getUrl('register'), 's', 'Verification code expired');
|
||||
} else if (file_exists($otpPath)) {
|
||||
$code = file_get_contents($otpPath);
|
||||
if ($code != $otp_code) {
|
||||
@ -59,97 +65,222 @@ switch ($do) {
|
||||
$ui->assign('fullname', $fullname);
|
||||
$ui->assign('address', $address);
|
||||
$ui->assign('email', $email);
|
||||
$ui->assign('phonenumber', $phonenumber);
|
||||
$ui->assign('phone_number', $phone_number);
|
||||
$ui->assign('notify', 'Wrong Verification code');
|
||||
$ui->assign('notify_t', 'd');
|
||||
$ui->display('user-ui/register-otp.tpl');
|
||||
$ui->assign('_title', Lang::T('Register'));
|
||||
$ui->display('customer/register-otp.tpl');
|
||||
exit();
|
||||
} else {
|
||||
unlink($otpPath);
|
||||
}
|
||||
} else {
|
||||
r2(U . 'register', 's', 'No Verification code');
|
||||
r2(getUrl('register'), 's', 'No Verification code');
|
||||
}
|
||||
}
|
||||
|
||||
// Check if username already exists
|
||||
$d = ORM::for_table('tbl_customers')->where('username', $username)->find_one();
|
||||
if ($d) {
|
||||
$msg .= Lang::T('Account already axist') . '<br>';
|
||||
$msg .= Lang::T('Account already exists') . '<br>';
|
||||
}
|
||||
|
||||
if ($msg == '') {
|
||||
run_hook('register_user'); #HOOK
|
||||
$d = ORM::for_table('tbl_customers')->create();
|
||||
$d->username = alphanumeric($username, "+_.@-");
|
||||
$d->password = $password;
|
||||
$d->fullname = $fullname;
|
||||
$d->address = $address;
|
||||
$d->email = $email;
|
||||
$d->phonenumber = $phonenumber;
|
||||
$d->phonenumber = $phone_number;
|
||||
if ($d->save()) {
|
||||
$user = $d->id();
|
||||
r2(U . 'login', 's', Lang::T('Register Success! You can login now'));
|
||||
if ($config['photo_register'] == 'yes' && !empty($_FILES['photo']['name']) && file_exists($_FILES['photo']['tmp_name'])) {
|
||||
if (function_exists('imagecreatetruecolor')) {
|
||||
$hash = md5_file($_FILES['photo']['tmp_name']);
|
||||
$subfolder = substr($hash, 0, 2);
|
||||
$folder = $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'photos' . DIRECTORY_SEPARATOR;
|
||||
if (!file_exists($folder)) {
|
||||
mkdir($folder);
|
||||
}
|
||||
$folder = $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'photos' . DIRECTORY_SEPARATOR . $subfolder . DIRECTORY_SEPARATOR;
|
||||
if (!file_exists($folder)) {
|
||||
mkdir($folder);
|
||||
}
|
||||
$imgPath = $folder . $hash . '.jpg';
|
||||
File::resizeCropImage($_FILES['photo']['tmp_name'], $imgPath, 1600, 1600, 100);
|
||||
$d->photo = '/photos/' . $subfolder . '/' . $hash . '.jpg';
|
||||
$d->save();
|
||||
}
|
||||
}
|
||||
if (file_exists($_FILES['photo']['tmp_name']))
|
||||
unlink($_FILES['photo']['tmp_name']);
|
||||
User::setFormCustomField($user);
|
||||
run_hook('register_user'); #HOOK
|
||||
$msg .= Lang::T('Registration successful') . '<br>';
|
||||
if ($config['reg_nofify_admin'] == 'yes') {
|
||||
sendTelegram($config['CompanyName'] . ' - ' . Lang::T('New User Registration') . "\n\nFull Name: " . $fullname . "\nUsername: " . $username . "\nEmail: " . $email . "\nPhone Number: " . $phone_number . "\nAddress: " . $address);
|
||||
}
|
||||
r2(getUrl('login'), 's', Lang::T('Register Success! You can login now'));
|
||||
} else {
|
||||
$ui->assign('username', $username);
|
||||
$ui->assign('fullname', $fullname);
|
||||
$ui->assign('address', $address);
|
||||
$ui->assign('email', $email);
|
||||
$ui->assign('phonenumber', $phonenumber);
|
||||
$ui->assign('phone_number', $phone_number);
|
||||
$ui->assign('notify', 'Failed to register');
|
||||
$ui->assign('notify_t', 'd');
|
||||
$ui->assign('_title', Lang::T('Register'));
|
||||
run_hook('view_otp_register'); #HOOK
|
||||
$ui->display('user-ui/register-rotp.tpl');
|
||||
$ui->display('customer/register-rotp.tpl');
|
||||
}
|
||||
} else {
|
||||
$ui->assign('username', $username);
|
||||
$ui->assign('fullname', $fullname);
|
||||
$ui->assign('address', $address);
|
||||
$ui->assign('email', $email);
|
||||
$ui->assign('phonenumber', $phonenumber);
|
||||
$ui->assign('phone_number', $phone_number);
|
||||
$ui->assign('notify', $msg);
|
||||
$ui->assign('notify_t', 'd');
|
||||
$ui->display('user-ui/register.tpl');
|
||||
$ui->assign('_title', Lang::T('Register'));
|
||||
// Check if OTP is enabled
|
||||
if (!empty($config['sms_url']) && $_c['sms_otp_registration'] == 'yes') {
|
||||
// Display register-otp.tpl if OTP is enabled
|
||||
$ui->display('customer/register-otp.tpl');
|
||||
} else {
|
||||
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
|
||||
if (!empty($config['login_page_logo']) && file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_logo'])) {
|
||||
$login_logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_logo'];
|
||||
} elseif (file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'login-logo.png')) {
|
||||
$login_logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'login-logo.png';
|
||||
} else {
|
||||
$login_logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'login-logo.default.png';
|
||||
}
|
||||
|
||||
if (!empty($config['login_page_wallpaper']) && file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_wallpaper'])) {
|
||||
$wallpaper = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_wallpaper'];
|
||||
} elseif (file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'wallpaper.png')) {
|
||||
$wallpaper = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'wallpaper.png';
|
||||
} else {
|
||||
$wallpaper = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'wallpaper.default.png';
|
||||
}
|
||||
|
||||
if (!empty($config['login_page_favicon']) && file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_favicon'])) {
|
||||
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_favicon'];
|
||||
} elseif (file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.png')) {
|
||||
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.png';
|
||||
} else {
|
||||
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.default.png';
|
||||
}
|
||||
|
||||
$ui->assign('login_logo', $login_logo);
|
||||
$ui->assign('wallpaper', $wallpaper);
|
||||
$ui->assign('favicon', $favicon);
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->assign('_title', Lang::T('Login'));
|
||||
$ui->assign('customFields', User::getFormCustomField($ui, true));
|
||||
switch ($config['login_page_type']) {
|
||||
case 'custom':
|
||||
$ui->display('customer/reg-login-custom-' . $config['login_Page_template'] . '.tpl');
|
||||
break;
|
||||
default:
|
||||
$ui->display('customer/register.tpl');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!empty($config['sms_url']) && $_c['allow_phone_otp'] == 'yes') {
|
||||
$username = _post('username');
|
||||
if (!empty($username)) {
|
||||
$d = ORM::for_table('tbl_customers')->where('username', $username)->find_one();
|
||||
if ($_c['sms_otp_registration'] == 'yes') {
|
||||
$phone_number = _post('phone_number');
|
||||
if (!empty($phone_number)) {
|
||||
$d = ORM::for_table('tbl_customers')->where('username', $phone_number)->find_one();
|
||||
if ($d) {
|
||||
r2(U . 'register', 's', Lang::T('Account already axist'));
|
||||
r2(getUrl('register'), 's', Lang::T('Account already exists'));
|
||||
}
|
||||
if (!file_exists($otpPath)) {
|
||||
mkdir($otpPath);
|
||||
touch($otpPath . 'index.html');
|
||||
}
|
||||
$otpPath .= sha1($username . $db_pass) . ".txt";
|
||||
//expired 10 minutes
|
||||
$otpPath .= sha1($phone_number . $db_pass) . ".txt";
|
||||
if (file_exists($otpPath) && time() - filemtime($otpPath) < 600) {
|
||||
$ui->assign('username', $username);
|
||||
$ui->assign('phone_number', $phone_number);
|
||||
$ui->assign('notify', 'Please wait ' . (600 - (time() - filemtime($otpPath))) . ' seconds before sending another SMS');
|
||||
$ui->assign('notify_t', 'd');
|
||||
$ui->display('user-ui/register-otp.tpl');
|
||||
$ui->assign('_title', Lang::T('Register'));
|
||||
$ui->display('customer/register-otp.tpl');
|
||||
} else {
|
||||
$otp = rand(100000, 999999);
|
||||
file_put_contents($otpPath, $otp);
|
||||
Message::sendSMS($username, $config['CompanyName'] . "\nYour Verification code are: $otp");
|
||||
$ui->assign('username', $username);
|
||||
$ui->assign('notify', 'Verification code has been sent to your phone');
|
||||
if ($config['phone_otp_type'] == 'whatsapp') {
|
||||
Message::sendWhatsapp($phone_number, $config['CompanyName'] . "\n\n" . Lang::T("Registration code") . "\n$otp");
|
||||
} else if ($config['phone_otp_type'] == 'both') {
|
||||
Message::sendWhatsapp($phone_number, $config['CompanyName'] . "\n\n" . Lang::T("Registration code") . "\n$otp");
|
||||
Message::sendSMS($phone_number, $config['CompanyName'] . "\n\n" . Lang::T("Registration code") . "\n$otp");
|
||||
} else {
|
||||
Message::sendSMS($phone_number, $config['CompanyName'] . "\n\n" . Lang::T("Registration code") . "\n$otp");
|
||||
}
|
||||
$ui->assign('phone_number', $phone_number);
|
||||
$ui->assign('notify', 'Registration code has been sent to your phone');
|
||||
$ui->assign('notify_t', 's');
|
||||
$ui->display('user-ui/register-otp.tpl');
|
||||
$ui->assign('_title', Lang::T('Register'));
|
||||
$ui->assign('customFields', User::getFormCustomField($ui, true));
|
||||
$ui->display('customer/register-otp.tpl');
|
||||
}
|
||||
} else {
|
||||
$ui->assign('_title', Lang::T('Register'));
|
||||
run_hook('view_otp_register'); #HOOK
|
||||
$ui->display('user-ui/register-rotp.tpl');
|
||||
$ui->display('customer/register-rotp.tpl');
|
||||
}
|
||||
} else {
|
||||
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
|
||||
if (!empty($config['login_page_logo']) && file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_logo'])) {
|
||||
$login_logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_logo'];
|
||||
} elseif (file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'login-logo.png')) {
|
||||
$login_logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'login-logo.png';
|
||||
} else {
|
||||
$login_logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'login-logo.default.png';
|
||||
}
|
||||
|
||||
if (!empty($config['login_page_wallpaper']) && file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_wallpaper'])) {
|
||||
$wallpaper = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_wallpaper'];
|
||||
} elseif (file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'wallpaper.png')) {
|
||||
$wallpaper = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'wallpaper.png';
|
||||
} else {
|
||||
$wallpaper = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'wallpaper.default.png';
|
||||
}
|
||||
|
||||
if (!empty($config['login_page_favicon']) && file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_favicon'])) {
|
||||
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_favicon'];
|
||||
} elseif (file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.png')) {
|
||||
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.png';
|
||||
} else {
|
||||
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.default.png';
|
||||
}
|
||||
|
||||
$ui->assign('login_logo', $login_logo);
|
||||
$ui->assign('wallpaper', $wallpaper);
|
||||
$ui->assign('favicon', $favicon);
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->assign('_title', Lang::T('Login'));
|
||||
$ui->assign('customFields', User::getFormCustomField($ui, true));
|
||||
$ui->assign('username', "");
|
||||
$ui->assign('fullname', "");
|
||||
$ui->assign('address', "");
|
||||
$ui->assign('email', "");
|
||||
$ui->assign('otp', false);
|
||||
$ui->assign('_title', Lang::T('Register'));
|
||||
run_hook('view_register'); #HOOK
|
||||
$ui->display('user-ui/register.tpl');
|
||||
switch ($config['login_page_type']) {
|
||||
case 'custom':
|
||||
$ui->display('customer/reg-login-custom-' . $config['login_Page_template'] . '.tpl');
|
||||
break;
|
||||
default:
|
||||
$ui->display('customer/register.tpl');
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -55,9 +55,13 @@ switch ($action) {
|
||||
->where('type', $tp);
|
||||
if (count($mts) > 0) {
|
||||
if (count($mts) != count($methods)) {
|
||||
$w = [];
|
||||
$v = [];
|
||||
foreach ($mts as $mt) {
|
||||
$query->where_like('method', "$mt - %");
|
||||
$w[] = 'method';
|
||||
$v[] = "$mt - %";
|
||||
}
|
||||
$query->where_likes($w, $v);
|
||||
}
|
||||
}
|
||||
if (count($rts) > 0) {
|
||||
@ -84,9 +88,13 @@ switch ($action) {
|
||||
}
|
||||
if (count($mts) > 0) {
|
||||
if (count($mts) != count($methods)) {
|
||||
$w = [];
|
||||
$v = [];
|
||||
foreach ($mts as $mt) {
|
||||
$query->where_like('method', "$mt - %");
|
||||
$w[] = 'method';
|
||||
$v[] = "$mt - %";
|
||||
}
|
||||
$query->where_likes($w, $v);
|
||||
}
|
||||
}
|
||||
if (count($rts) > 0) {
|
||||
@ -114,13 +122,6 @@ switch ($action) {
|
||||
if (count($plns) > 0) {
|
||||
$query->where_in('plan_name', $plns);
|
||||
}
|
||||
if (count($mts) > 0) {
|
||||
if (count($mts) != count($methods)) {
|
||||
foreach ($mts as $mt) {
|
||||
$query->where_like('method', "$mt - %");
|
||||
}
|
||||
}
|
||||
}
|
||||
$count = $query->count();
|
||||
if ($count > 0) {
|
||||
$result['datas'][] = $count;
|
||||
@ -157,9 +158,13 @@ switch ($action) {
|
||||
}
|
||||
if (count($mts) > 0) {
|
||||
if (count($mts) != count($methods)) {
|
||||
$w = [];
|
||||
$v = [];
|
||||
foreach ($mts as $mt) {
|
||||
$query->where_like('method', "$mt - %");
|
||||
$w[] = 'method';
|
||||
$v[] = "$mt - %";
|
||||
}
|
||||
$query->where_likes($w, $v);
|
||||
}
|
||||
}
|
||||
if (count($rts) > 0) {
|
||||
@ -241,7 +246,7 @@ switch ($action) {
|
||||
$total += $v;
|
||||
$array['data'][] = $v;
|
||||
}
|
||||
if($total>0){
|
||||
if ($total > 0) {
|
||||
$result['datas'][] = $array;
|
||||
}
|
||||
}
|
||||
@ -253,23 +258,34 @@ switch ($action) {
|
||||
die();
|
||||
case 'by-date':
|
||||
case 'activation':
|
||||
$q = (_post('q') ? _post('q') : _get('q'));
|
||||
$q = trim(_post('q') ?: _get('q'));
|
||||
$keep = _post('keep');
|
||||
|
||||
if (!empty($keep)) {
|
||||
ORM::raw_execute("DELETE FROM tbl_transactions WHERE date < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL $keep DAY))");
|
||||
r2(U . "logs/list/", 's', "Delete logs older than $keep days");
|
||||
ORM::raw_execute("DELETE FROM tbl_transactions WHERE date < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL ? DAY))", [$keep]);
|
||||
r2(getUrl('reports/activation/'), 's', "Deleted logs older than $keep days");
|
||||
}
|
||||
if ($q != '') {
|
||||
$query = ORM::for_table('tbl_transactions')->where_like('invoice', '%' . $q . '%')->order_by_desc('id');
|
||||
|
||||
$query = ORM::for_table('tbl_transactions')
|
||||
->left_outer_join('tbl_customers', 'tbl_transactions.username = tbl_customers.username')
|
||||
->select('tbl_transactions.*')
|
||||
->select('tbl_customers.fullname', 'fullname')
|
||||
->order_by_desc('tbl_transactions.id');
|
||||
|
||||
if ($q !== '') {
|
||||
$query->where_like('invoice', "%$q%");
|
||||
}
|
||||
|
||||
try {
|
||||
$d = Paginator::findMany($query, ['q' => $q]);
|
||||
} else {
|
||||
$query = ORM::for_table('tbl_transactions')->order_by_desc('id');
|
||||
$d = Paginator::findMany($query);
|
||||
} catch (Exception $e) {
|
||||
r2(getUrl('reports/activation/'), 'e', 'Database query failed: ' . $e->getMessage());
|
||||
$d = [];
|
||||
}
|
||||
|
||||
$ui->assign('activation', $d);
|
||||
$ui->assign('q', $q);
|
||||
$ui->display('reports-activation.tpl');
|
||||
$ui->display('admin/reports/activation.tpl');
|
||||
break;
|
||||
|
||||
case 'by-period':
|
||||
@ -277,7 +293,7 @@ switch ($action) {
|
||||
$ui->assign('mtime', $mtime);
|
||||
$ui->assign('tdate', $tdate);
|
||||
run_hook('view_reports_by_period'); #HOOK
|
||||
$ui->display('reports-period.tpl');
|
||||
$ui->display('admin/reports/period.tpl');
|
||||
break;
|
||||
|
||||
case 'period-view':
|
||||
@ -286,6 +302,10 @@ switch ($action) {
|
||||
$stype = _post('stype');
|
||||
|
||||
$d = ORM::for_table('tbl_transactions');
|
||||
$d->left_outer_join('tbl_customers', 'tbl_transactions.username = tbl_customers.username')
|
||||
->select('tbl_transactions.*')
|
||||
->select('tbl_customers.fullname', 'fullname')
|
||||
->order_by_desc('tbl_transactions.id');
|
||||
if ($stype != '') {
|
||||
$d->where('type', $stype);
|
||||
}
|
||||
@ -293,7 +313,7 @@ switch ($action) {
|
||||
$d->where_gte('recharged_on', $fdate);
|
||||
$d->where_lte('recharged_on', $tdate);
|
||||
$d->order_by_desc('id');
|
||||
$x = $d->find_many();
|
||||
$x = $d->find_many();
|
||||
|
||||
$dr = ORM::for_table('tbl_transactions');
|
||||
if ($stype != '') {
|
||||
@ -310,7 +330,7 @@ switch ($action) {
|
||||
$ui->assign('tdate', $tdate);
|
||||
$ui->assign('stype', $stype);
|
||||
run_hook('view_reports_period'); #HOOK
|
||||
$ui->display('reports-period-view.tpl');
|
||||
$ui->display('admin/reports/period-view.tpl');
|
||||
break;
|
||||
|
||||
case 'daily-report':
|
||||
@ -343,16 +363,21 @@ switch ($action) {
|
||||
$query = ORM::for_table('tbl_transactions')
|
||||
->whereRaw("UNIX_TIMESTAMP(CONCAT(`recharged_on`,' ',`recharged_time`)) >= " . strtotime("$sd $ts"))
|
||||
->whereRaw("UNIX_TIMESTAMP(CONCAT(`recharged_on`,' ',`recharged_time`)) <= " . strtotime("$ed $te"))
|
||||
->order_by_desc('id');
|
||||
->left_outer_join('tbl_customers', 'tbl_transactions.username = tbl_customers.username')
|
||||
->select('tbl_transactions.*')
|
||||
->select('tbl_customers.fullname', 'fullname')
|
||||
->order_by_desc('tbl_transactions.id');
|
||||
if (count($tps) > 0) {
|
||||
$query->where_in('type', $tps);
|
||||
}
|
||||
if (count($mts) > 0) {
|
||||
if (count($mts) != count($methods)) {
|
||||
foreach ($mts as $mt) {
|
||||
$query->where_like('method', "$mt - %");
|
||||
}
|
||||
$w = [];
|
||||
$v = [];
|
||||
foreach ($mts as $mt) {
|
||||
$w[] = 'method';
|
||||
$v[] = "$mt - %";
|
||||
}
|
||||
$query->where_likes($w, $v);
|
||||
}
|
||||
if (count($rts) > 0) {
|
||||
$query->where_in('routers', $rts);
|
||||
@ -384,6 +409,6 @@ switch ($action) {
|
||||
$ui->assign('dr', $dr);
|
||||
$ui->assign('mdate', $mdate);
|
||||
run_hook('view_daily_reports'); #HOOK
|
||||
$ui->display('reports.tpl');
|
||||
$ui->display('admin/reports/list.tpl');
|
||||
break;
|
||||
}
|
||||
|
@ -23,24 +23,9 @@ $leafletpickerHeader = <<<EOT
|
||||
EOT;
|
||||
|
||||
switch ($action) {
|
||||
case 'maps':
|
||||
$name = _post('name');
|
||||
$query = ORM::for_table('tbl_routers')->where_not_equal('coordinates', '')->order_by_desc('id');
|
||||
$query->selects(['id', 'name', 'coordinates', 'description', 'coverage', 'enabled']);
|
||||
if ($name != '') {
|
||||
$query->where_like('name', '%' . $name . '%');
|
||||
}
|
||||
$d = Paginator::findMany($query, ['name' => $name], '20', '', true);
|
||||
$ui->assign('name', $name);
|
||||
$ui->assign('d', $d);
|
||||
$ui->assign('_title', Lang::T('Routers Geo Location Information'));
|
||||
$ui->assign('xheader', $leafletpickerHeader);
|
||||
$ui->assign('xfooter', '<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>');
|
||||
$ui->display('routers-maps.tpl');
|
||||
break;
|
||||
case 'add':
|
||||
run_hook('view_add_routers'); #HOOK
|
||||
$ui->display('routers-add.tpl');
|
||||
$ui->display('admin/routers/add.tpl');
|
||||
break;
|
||||
|
||||
case 'edit':
|
||||
@ -53,9 +38,9 @@ switch ($action) {
|
||||
if ($d) {
|
||||
$ui->assign('d', $d);
|
||||
run_hook('view_router_edit'); #HOOK
|
||||
$ui->display('routers-edit.tpl');
|
||||
$ui->display('admin/routers/edit.tpl');
|
||||
} else {
|
||||
r2(U . 'routers/list', 'e', Lang::T('Account Not Found'));
|
||||
r2(getUrl('routers/list'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -65,7 +50,7 @@ switch ($action) {
|
||||
$d = ORM::for_table('tbl_routers')->find_one($id);
|
||||
if ($d) {
|
||||
$d->delete();
|
||||
r2(U . 'routers/list', 's', Lang::T('Data Deleted Successfully'));
|
||||
r2(getUrl('routers/list'), 's', Lang::T('Data Deleted Successfully'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -109,9 +94,9 @@ switch ($action) {
|
||||
$d->enabled = $enabled;
|
||||
$d->save();
|
||||
|
||||
r2(U . 'routers/edit/' . $d->id(), 's', Lang::T('Data Created Successfully'));
|
||||
r2(getUrl('routers/edit/') . $d->id(), 's', Lang::T('Data Created Successfully'));
|
||||
} else {
|
||||
r2(U . 'routers/add', 'e', $msg);
|
||||
r2(getUrl('routers/add'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -197,14 +182,13 @@ switch ($action) {
|
||||
$p->set('routers', $name);
|
||||
$p->save();
|
||||
}
|
||||
r2(U . 'routers/list', 's', Lang::T('Data Updated Successfully'));
|
||||
r2(getUrl('routers/list'), 's', Lang::T('Data Updated Successfully'));
|
||||
} else {
|
||||
r2(U . 'routers/edit/' . $id, 'e', $msg);
|
||||
r2(getUrl('routers/edit/') . $id, 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/routers.js"></script>');
|
||||
|
||||
$name = _post('name');
|
||||
$name = _post('name');
|
||||
@ -215,6 +199,6 @@ switch ($action) {
|
||||
$d = Paginator::findMany($query, ['name' => $name]);
|
||||
$ui->assign('d', $d);
|
||||
run_hook('view_list_routers'); #HOOK
|
||||
$ui->display('routers.tpl');
|
||||
$ui->display('admin/routers/list.tpl');
|
||||
break;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
$query = isset($_GET['query']) ? trim($_GET['query']) : '';
|
||||
|
||||
if (!empty($query)) {
|
||||
if (!empty($query)) {
|
||||
$results = ORM::for_table('tbl_customers')
|
||||
->where_like('username', "%$query%")
|
||||
->find_many();
|
||||
|
@ -33,7 +33,7 @@ switch ($action) {
|
||||
}
|
||||
}
|
||||
}
|
||||
r2(U . 'services/hotspot', 's', $log);
|
||||
r2(getUrl('services/hotspot'), 's', $log);
|
||||
} else if ($routes['2'] == 'pppoe') {
|
||||
$plans = ORM::for_table('tbl_plans')->where('type', 'PPPOE')->find_many();
|
||||
$log = '';
|
||||
@ -49,11 +49,10 @@ switch ($action) {
|
||||
}
|
||||
}
|
||||
}
|
||||
r2(U . 'services/pppoe', 's', $log);
|
||||
r2(getUrl('services/pppoe'), 's', $log);
|
||||
}
|
||||
r2(U . 'services/hotspot', 'w', 'Unknown command');
|
||||
r2(getUrl('services/hotspot'), 'w', 'Unknown command');
|
||||
case 'hotspot':
|
||||
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/hotspot.js"></script>');
|
||||
$name = _req('name');
|
||||
$type1 = _req('type1');
|
||||
$type2 = _req('type2');
|
||||
@ -83,9 +82,9 @@ switch ($action) {
|
||||
|
||||
$bws = ORM::for_table('tbl_plans')->distinct()->select("id_bw")->where('tbl_plans.type', 'Hotspot')->findArray();
|
||||
$ids = array_column($bws, 'id_bw');
|
||||
if(count($ids)){
|
||||
if (count($ids)) {
|
||||
$ui->assign('bws', ORM::for_table('tbl_bandwidth')->select("id")->select('name_bw')->where_id_in($ids)->findArray());
|
||||
}else{
|
||||
} else {
|
||||
$ui->assign('bws', []);
|
||||
}
|
||||
$ui->assign('type2s', ORM::for_table('tbl_plans')->getEnum("plan_type"));
|
||||
@ -139,7 +138,7 @@ switch ($action) {
|
||||
$d = Paginator::findMany($query, ['name' => $name], 20, $append_url);
|
||||
$ui->assign('d', $d);
|
||||
run_hook('view_list_plans'); #HOOK
|
||||
$ui->display('hotspot.tpl');
|
||||
$ui->display('admin/hotspot/list.tpl');
|
||||
break;
|
||||
case 'add':
|
||||
$d = ORM::for_table('tbl_bandwidth')->find_many();
|
||||
@ -156,7 +155,7 @@ switch ($action) {
|
||||
}
|
||||
$ui->assign('devices', $devices);
|
||||
run_hook('view_add_plan'); #HOOK
|
||||
$ui->display('hotspot-add.tpl');
|
||||
$ui->display('admin/hotspot/add.tpl');
|
||||
break;
|
||||
|
||||
case 'edit':
|
||||
@ -191,9 +190,9 @@ switch ($action) {
|
||||
}
|
||||
$ui->assign('exps', $exps);
|
||||
run_hook('view_edit_plan'); #HOOK
|
||||
$ui->display('hotspot-edit.tpl');
|
||||
$ui->display('admin/hotspot/edit.tpl');
|
||||
} else {
|
||||
r2(U . 'services/hotspot', 'e', Lang::T('Account Not Found'));
|
||||
r2(getUrl('services/hotspot'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -214,7 +213,7 @@ switch ($action) {
|
||||
}
|
||||
$d->delete();
|
||||
|
||||
r2(U . 'services/hotspot', 's', Lang::T('Data Deleted Successfully'));
|
||||
r2(getUrl('services/hotspot'), 's', Lang::T('Data Deleted Successfully'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -307,9 +306,9 @@ switch ($action) {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
}
|
||||
}
|
||||
r2(U . 'services/edit/' . $d->id(), 's', Lang::T('Data Created Successfully'));
|
||||
r2(getUrl('services/edit/') . $d->id(), 's', Lang::T('Data Created Successfully'));
|
||||
} else {
|
||||
r2(U . 'services/add', 'e', $msg);
|
||||
r2(getUrl('services/add'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -321,6 +320,7 @@ switch ($action) {
|
||||
$id_bw = _post('id_bw');
|
||||
$typebp = _post('typebp');
|
||||
$price = _post('price');
|
||||
$price_old = _post('price_old');
|
||||
$limit_type = _post('limit_type');
|
||||
$time_limit = _post('time_limit');
|
||||
$time_unit = _post('time_unit');
|
||||
@ -353,6 +353,11 @@ switch ($action) {
|
||||
} else {
|
||||
$msg .= Lang::T('Data Not Found') . '<br>';
|
||||
}
|
||||
|
||||
if ($price_old <= $price) {
|
||||
$price_old = '';
|
||||
}
|
||||
|
||||
run_hook('edit_plan'); #HOOK
|
||||
if ($msg == '') {
|
||||
$b = ORM::for_table('tbl_bandwidth')->where('id', $id_bw)->find_one();
|
||||
@ -378,6 +383,7 @@ switch ($action) {
|
||||
$d->name_plan = $name;
|
||||
$d->id_bw = $id_bw;
|
||||
$d->price = $price; // Set price with or without tax based on configuration
|
||||
$d->price_old = $price_old;
|
||||
$d->typebp = $typebp;
|
||||
$d->limit_type = $limit_type;
|
||||
$d->time_limit = $time_limit;
|
||||
@ -413,15 +419,14 @@ switch ($action) {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
}
|
||||
}
|
||||
r2(U . 'services/hotspot', 's', Lang::T('Data Updated Successfully'));
|
||||
r2(getUrl('services/hotspot'), 's', Lang::T('Data Updated Successfully'));
|
||||
} else {
|
||||
r2(U . 'services/edit/' . $id, 'e', $msg);
|
||||
r2(getUrl('services/edit/') . $id, 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'pppoe':
|
||||
$ui->assign('_title', Lang::T('PPPOE Plans'));
|
||||
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/pppoe.js"></script>');
|
||||
|
||||
$name = _post('name');
|
||||
$name = _req('name');
|
||||
@ -453,9 +458,9 @@ switch ($action) {
|
||||
|
||||
$bws = ORM::for_table('tbl_plans')->distinct()->select("id_bw")->where('tbl_plans.type', 'PPPOE')->findArray();
|
||||
$ids = array_column($bws, 'id_bw');
|
||||
if(count($ids)){
|
||||
if (count($ids)) {
|
||||
$ui->assign('bws', ORM::for_table('tbl_bandwidth')->select("id")->select('name_bw')->where_id_in($ids)->findArray());
|
||||
}else{
|
||||
} else {
|
||||
$ui->assign('bws', []);
|
||||
}
|
||||
$ui->assign('type2s', ORM::for_table('tbl_plans')->getEnum("plan_type"));
|
||||
@ -509,7 +514,7 @@ switch ($action) {
|
||||
|
||||
$ui->assign('d', $d);
|
||||
run_hook('view_list_ppoe'); #HOOK
|
||||
$ui->display('pppoe.tpl');
|
||||
$ui->display('admin/pppoe/list.tpl');
|
||||
break;
|
||||
|
||||
case 'pppoe-add':
|
||||
@ -528,7 +533,7 @@ switch ($action) {
|
||||
}
|
||||
$ui->assign('devices', $devices);
|
||||
run_hook('view_add_ppoe'); #HOOK
|
||||
$ui->display('pppoe-add.tpl');
|
||||
$ui->display('admin/pppoe/add.tpl');
|
||||
break;
|
||||
|
||||
case 'pppoe-edit':
|
||||
@ -571,9 +576,9 @@ switch ($action) {
|
||||
}
|
||||
$ui->assign('exps', $exps);
|
||||
run_hook('view_edit_ppoe'); #HOOK
|
||||
$ui->display('pppoe-edit.tpl');
|
||||
$ui->display('admin/pppoe/edit.tpl');
|
||||
} else {
|
||||
r2(U . 'services/pppoe', 'e', Lang::T('Account Not Found'));
|
||||
r2(getUrl('services/pppoe'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -595,7 +600,7 @@ switch ($action) {
|
||||
}
|
||||
$d->delete();
|
||||
|
||||
r2(U . 'services/pppoe', 's', Lang::T('Data Deleted Successfully'));
|
||||
r2(getUrl('services/pppoe'), 's', Lang::T('Data Deleted Successfully'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -693,9 +698,9 @@ switch ($action) {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
}
|
||||
}
|
||||
r2(U . 'services/pppoe', 's', Lang::T('Data Created Successfully'));
|
||||
r2(getUrl('services/pppoe'), 's', Lang::T('Data Created Successfully'));
|
||||
} else {
|
||||
r2(U . 'services/pppoe-add', 'e', $msg);
|
||||
r2(getUrl('services/pppoe-add'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -705,6 +710,7 @@ switch ($action) {
|
||||
$name = _post('name_plan');
|
||||
$id_bw = _post('id_bw');
|
||||
$price = _post('price');
|
||||
$price_old = _post('price_old');
|
||||
$validity = _post('validity');
|
||||
$validity_unit = _post('validity_unit');
|
||||
$routers = _post('routers');
|
||||
@ -728,6 +734,10 @@ switch ($action) {
|
||||
$msg .= Lang::T('All field is required') . '<br>';
|
||||
}
|
||||
|
||||
if ($price_old <= $price) {
|
||||
$price_old = '';
|
||||
}
|
||||
|
||||
$d = ORM::for_table('tbl_plans')->where('id', $id)->find_one();
|
||||
$old = ORM::for_table('tbl_plans')->where('id', $id)->find_one();
|
||||
if ($d) {
|
||||
@ -758,6 +768,7 @@ switch ($action) {
|
||||
$d->name_plan = $name;
|
||||
$d->id_bw = $id_bw;
|
||||
$d->price = $price;
|
||||
$d->price_old = $price_old;
|
||||
$d->plan_type = $plan_type;
|
||||
$d->validity = $validity;
|
||||
$d->validity_unit = $validity_unit;
|
||||
@ -788,9 +799,9 @@ switch ($action) {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
}
|
||||
}
|
||||
r2(U . 'services/pppoe', 's', Lang::T('Data Updated Successfully'));
|
||||
r2(getUrl('services/pppoe'), 's', Lang::T('Data Updated Successfully'));
|
||||
} else {
|
||||
r2(U . 'services/pppoe-edit/' . $id, 'e', $msg);
|
||||
r2(getUrl('services/pppoe-edit/') . $id, 'e', $msg);
|
||||
}
|
||||
break;
|
||||
case 'balance':
|
||||
@ -806,12 +817,12 @@ switch ($action) {
|
||||
|
||||
$ui->assign('d', $d);
|
||||
run_hook('view_list_balance'); #HOOK
|
||||
$ui->display('balance.tpl');
|
||||
$ui->display('admin/balance/list.tpl');
|
||||
break;
|
||||
case 'balance-add':
|
||||
$ui->assign('_title', Lang::T('Balance Plans'));
|
||||
run_hook('view_add_balance'); #HOOK
|
||||
$ui->display('balance-add.tpl');
|
||||
$ui->display('admin/balance/add.tpl');
|
||||
break;
|
||||
case 'balance-edit':
|
||||
$ui->assign('_title', Lang::T('Balance Plans'));
|
||||
@ -819,7 +830,7 @@ switch ($action) {
|
||||
$d = ORM::for_table('tbl_plans')->find_one($id);
|
||||
$ui->assign('d', $d);
|
||||
run_hook('view_edit_balance'); #HOOK
|
||||
$ui->display('balance-edit.tpl');
|
||||
$ui->display('admin/balance/edit.tpl');
|
||||
break;
|
||||
case 'balance-delete':
|
||||
$id = $routes['2'];
|
||||
@ -828,13 +839,14 @@ switch ($action) {
|
||||
if ($d) {
|
||||
run_hook('delete_balance'); #HOOK
|
||||
$d->delete();
|
||||
r2(U . 'services/balance', 's', Lang::T('Data Deleted Successfully'));
|
||||
r2(getUrl('services/balance'), 's', Lang::T('Data Deleted Successfully'));
|
||||
}
|
||||
break;
|
||||
case 'balance-edit-post':
|
||||
$id = _post('id');
|
||||
$name = _post('name');
|
||||
$price = _post('price');
|
||||
$price_old = _post('price_old');
|
||||
$enabled = _post('enabled');
|
||||
$prepaid = _post('prepaid');
|
||||
|
||||
@ -851,17 +863,21 @@ switch ($action) {
|
||||
} else {
|
||||
$msg .= Lang::T('Data Not Found') . '<br>';
|
||||
}
|
||||
if ($price_old <= $price) {
|
||||
$price_old = '';
|
||||
}
|
||||
run_hook('edit_ppoe'); #HOOK
|
||||
if ($msg == '') {
|
||||
$d->name_plan = $name;
|
||||
$d->price = $price;
|
||||
$d->enabled = $enabled;
|
||||
$d->price_old = $price_old;
|
||||
$d->prepaid = 'yes';
|
||||
$d->save();
|
||||
|
||||
r2(U . 'services/balance', 's', Lang::T('Data Updated Successfully'));
|
||||
r2(getUrl('services/balance'), 's', Lang::T('Data Updated Successfully'));
|
||||
} else {
|
||||
r2(U . 'services/balance-edit/' . $id, 'e', $msg);
|
||||
r2(getUrl('services/balance-edit/') . $id, 'e', $msg);
|
||||
}
|
||||
break;
|
||||
case 'balance-add-post':
|
||||
@ -896,11 +912,390 @@ switch ($action) {
|
||||
$d->prepaid = 'yes';
|
||||
$d->save();
|
||||
|
||||
r2(U . 'services/balance', 's', Lang::T('Data Created Successfully'));
|
||||
r2(getUrl('services/balance'), 's', Lang::T('Data Created Successfully'));
|
||||
} else {
|
||||
r2(U . 'services/balance-add', 'e', $msg);
|
||||
r2(getUrl('services/balance-add'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
case 'vpn':
|
||||
$ui->assign('_title', Lang::T('VPN Plans'));
|
||||
|
||||
$name = _post('name');
|
||||
$name = _req('name');
|
||||
$type1 = _req('type1');
|
||||
$type2 = _req('type2');
|
||||
$type3 = _req('type3');
|
||||
$bandwidth = _req('bandwidth');
|
||||
$valid = _req('valid');
|
||||
$device = _req('device');
|
||||
$status = _req('status');
|
||||
$router = _req('router');
|
||||
$ui->assign('type1', $type1);
|
||||
$ui->assign('type2', $type2);
|
||||
$ui->assign('type3', $type3);
|
||||
$ui->assign('bandwidth', $bandwidth);
|
||||
$ui->assign('valid', $valid);
|
||||
$ui->assign('device', $device);
|
||||
$ui->assign('status', $status);
|
||||
$ui->assign('router', $router);
|
||||
|
||||
$append_url = "&type1=" . urlencode($type1)
|
||||
. "&type2=" . urlencode($type2)
|
||||
. "&type3=" . urlencode($type3)
|
||||
. "&bandwidth=" . urlencode($bandwidth)
|
||||
. "&valid=" . urlencode($valid)
|
||||
. "&device=" . urlencode($device)
|
||||
. "&status=" . urlencode($status)
|
||||
. "&router=" . urlencode($router);
|
||||
|
||||
$bws = ORM::for_table('tbl_plans')->distinct()->select("id_bw")->where('tbl_plans.type', 'VPN')->findArray();
|
||||
$ids = array_column($bws, 'id_bw');
|
||||
if (count($ids)) {
|
||||
$ui->assign('bws', ORM::for_table('tbl_bandwidth')->select("id")->select('name_bw')->where_id_in($ids)->findArray());
|
||||
} else {
|
||||
$ui->assign('bws', []);
|
||||
}
|
||||
$ui->assign('type2s', ORM::for_table('tbl_plans')->getEnum("plan_type"));
|
||||
$ui->assign('type3s', ORM::for_table('tbl_plans')->getEnum("typebp"));
|
||||
$ui->assign('valids', ORM::for_table('tbl_plans')->getEnum("validity_unit"));
|
||||
$ui->assign('routers', array_column(ORM::for_table('tbl_plans')->distinct()->select("routers")->whereNotEqual('routers', '')->findArray(), 'routers'));
|
||||
$devices = [];
|
||||
$files = scandir($DEVICE_PATH);
|
||||
foreach ($files as $file) {
|
||||
$ext = pathinfo($file, PATHINFO_EXTENSION);
|
||||
if ($ext == 'php') {
|
||||
$devices[] = pathinfo($file, PATHINFO_FILENAME);
|
||||
}
|
||||
}
|
||||
$ui->assign('devices', $devices);
|
||||
$query = ORM::for_table('tbl_bandwidth')
|
||||
->left_outer_join('tbl_plans', array('tbl_bandwidth.id', '=', 'tbl_plans.id_bw'))
|
||||
->where('tbl_plans.type', 'VPN');
|
||||
if (!empty($type1)) {
|
||||
$query->where('tbl_plans.prepaid', $type1);
|
||||
}
|
||||
if (!empty($type2)) {
|
||||
$query->where('tbl_plans.plan_type', $type2);
|
||||
}
|
||||
if (!empty($type3)) {
|
||||
$query->where('tbl_plans.typebp', $type3);
|
||||
}
|
||||
if (!empty($bandwidth)) {
|
||||
$query->where('tbl_plans.id_bw', $bandwidth);
|
||||
}
|
||||
if (!empty($valid)) {
|
||||
$query->where('tbl_plans.validity_unit', $valid);
|
||||
}
|
||||
if (!empty($router)) {
|
||||
if ($router == 'radius') {
|
||||
$query->where('tbl_plans.is_radius', '1');
|
||||
} else {
|
||||
$query->where('tbl_plans.routers', $router);
|
||||
}
|
||||
}
|
||||
if (!empty($device)) {
|
||||
$query->where('tbl_plans.device', $device);
|
||||
}
|
||||
if (in_array($status, ['0', '1'])) {
|
||||
$query->where('tbl_plans.enabled', $status);
|
||||
}
|
||||
if ($name != '') {
|
||||
$query->where_like('tbl_plans.name_plan', '%' . $name . '%');
|
||||
}
|
||||
$d = Paginator::findMany($query, ['name' => $name], 20, $append_url);
|
||||
|
||||
$ui->assign('d', $d);
|
||||
run_hook('view_list_vpn'); #HOOK
|
||||
$ui->display('admin/vpn/list.tpl');
|
||||
break;
|
||||
|
||||
case 'vpn-add':
|
||||
$ui->assign('_title', Lang::T('VPN Plans'));
|
||||
$d = ORM::for_table('tbl_bandwidth')->find_many();
|
||||
$ui->assign('d', $d);
|
||||
$r = ORM::for_table('tbl_routers')->find_many();
|
||||
$ui->assign('r', $r);
|
||||
$devices = [];
|
||||
$files = scandir($DEVICE_PATH);
|
||||
foreach ($files as $file) {
|
||||
$ext = pathinfo($file, PATHINFO_EXTENSION);
|
||||
if ($ext == 'php') {
|
||||
$devices[] = pathinfo($file, PATHINFO_FILENAME);
|
||||
}
|
||||
}
|
||||
$ui->assign('devices', $devices);
|
||||
run_hook('view_add_vpn'); #HOOK
|
||||
$ui->display('admin/vpn/add.tpl');
|
||||
break;
|
||||
|
||||
case 'vpn-edit':
|
||||
$ui->assign('_title', Lang::T('VPN Plans'));
|
||||
$id = $routes['2'];
|
||||
$d = ORM::for_table('tbl_plans')->find_one($id);
|
||||
if ($d) {
|
||||
if (empty($d['device'])) {
|
||||
if ($d['is_radius']) {
|
||||
$d->device = 'Radius';
|
||||
} else {
|
||||
$d->device = 'MikrotikVpn';
|
||||
}
|
||||
$d->save();
|
||||
}
|
||||
$ui->assign('d', $d);
|
||||
$p = ORM::for_table('tbl_pool')->where('routers', ($d['is_radius']) ? 'radius' : $d['routers'])->find_many();
|
||||
$ui->assign('p', $p);
|
||||
$b = ORM::for_table('tbl_bandwidth')->find_many();
|
||||
$ui->assign('b', $b);
|
||||
$r = [];
|
||||
if ($d['is_radius']) {
|
||||
$r = ORM::for_table('tbl_routers')->find_many();
|
||||
}
|
||||
$ui->assign('r', $r);
|
||||
$devices = [];
|
||||
$files = scandir($DEVICE_PATH);
|
||||
foreach ($files as $file) {
|
||||
$ext = pathinfo($file, PATHINFO_EXTENSION);
|
||||
if ($ext == 'php') {
|
||||
$devices[] = pathinfo($file, PATHINFO_FILENAME);
|
||||
}
|
||||
}
|
||||
$ui->assign('devices', $devices);
|
||||
//select expired plan
|
||||
if ($d['is_radius']) {
|
||||
$exps = ORM::for_table('tbl_plans')->selects('id', 'name_plan')->where('type', 'VPN')->where("is_radius", 1)->findArray();
|
||||
} else {
|
||||
$exps = ORM::for_table('tbl_plans')->selects('id', 'name_plan')->where('type', 'VPN')->where("routers", $d['routers'])->findArray();
|
||||
}
|
||||
$ui->assign('exps', $exps);
|
||||
run_hook('view_edit_vpn'); #HOOK
|
||||
$ui->display('admin/vpn/edit.tpl');
|
||||
} else {
|
||||
r2(getUrl('services/vpn'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'vpn-delete':
|
||||
$id = $routes['2'];
|
||||
|
||||
$d = ORM::for_table('tbl_plans')->find_one($id);
|
||||
if ($d) {
|
||||
run_hook('delete_vpn'); #HOOK
|
||||
|
||||
$dvc = Package::getDevice($d);
|
||||
if ($_app_stage != 'demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
(new $d['device'])->remove_plan($d);
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
}
|
||||
}
|
||||
$d->delete();
|
||||
|
||||
r2(getUrl('services/vpn'), 's', Lang::T('Data Deleted Successfully'));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'vpn-add-post':
|
||||
$name = _post('name_plan');
|
||||
$plan_type = _post('plan_type');
|
||||
$radius = _post('radius');
|
||||
$id_bw = _post('id_bw');
|
||||
$price = _post('price');
|
||||
$validity = _post('validity');
|
||||
$validity_unit = _post('validity_unit');
|
||||
$routers = _post('routers');
|
||||
$device = _post('device');
|
||||
$pool = _post('pool_name');
|
||||
$enabled = _post('enabled');
|
||||
$prepaid = _post('prepaid');
|
||||
$expired_date = _post('expired_date');
|
||||
|
||||
|
||||
$msg = '';
|
||||
if (Validator::UnsignedNumber($validity) == false) {
|
||||
$msg .= 'The validity must be a number' . '<br>';
|
||||
}
|
||||
if (Validator::UnsignedNumber($price) == false) {
|
||||
$msg .= 'The price must be a number' . '<br>';
|
||||
}
|
||||
if ($name == '' or $id_bw == '' or $price == '' or $validity == '' or $pool == '') {
|
||||
$msg .= Lang::T('All field is required') . '<br>';
|
||||
}
|
||||
if (empty($radius)) {
|
||||
if ($routers == '') {
|
||||
$msg .= Lang::T('All field is required') . '<br>';
|
||||
}
|
||||
}
|
||||
|
||||
$d = ORM::for_table('tbl_plans')->where('name_plan', $name)->find_one();
|
||||
if ($d) {
|
||||
$msg .= Lang::T('Name Plan Already Exist') . '<br>';
|
||||
}
|
||||
run_hook('add_vpn'); #HOOK
|
||||
if ($msg == '') {
|
||||
$b = ORM::for_table('tbl_bandwidth')->where('id', $id_bw)->find_one();
|
||||
if ($b['rate_down_unit'] == 'Kbps') {
|
||||
$unitdown = 'K';
|
||||
$raddown = '000';
|
||||
} else {
|
||||
$unitdown = 'M';
|
||||
$raddown = '000000';
|
||||
}
|
||||
if ($b['rate_up_unit'] == 'Kbps') {
|
||||
$unitup = 'K';
|
||||
$radup = '000';
|
||||
} else {
|
||||
$unitup = 'M';
|
||||
$radup = '000000';
|
||||
}
|
||||
$rate = $b['rate_up'] . $unitup . "/" . $b['rate_down'] . $unitdown;
|
||||
$radiusRate = $b['rate_up'] . $radup . '/' . $b['rate_down'] . $raddown . '/' . $b['burst'];
|
||||
$rate = trim($rate . " " . $b['burst']);
|
||||
$d = ORM::for_table('tbl_plans')->create();
|
||||
$d->type = 'VPN';
|
||||
$d->name_plan = $name;
|
||||
$d->id_bw = $id_bw;
|
||||
$d->price = $price;
|
||||
$d->plan_type = $plan_type;
|
||||
$d->validity = $validity;
|
||||
$d->validity_unit = $validity_unit;
|
||||
$d->pool = $pool;
|
||||
if (!empty($radius)) {
|
||||
$d->is_radius = 1;
|
||||
$d->routers = '';
|
||||
} else {
|
||||
$d->is_radius = 0;
|
||||
$d->routers = $routers;
|
||||
}
|
||||
if ($prepaid == 'no') {
|
||||
if ($expired_date > 28 && $expired_date < 1) {
|
||||
$expired_date = 20;
|
||||
}
|
||||
$d->expired_date = $expired_date;
|
||||
} else {
|
||||
$d->expired_date = 0;
|
||||
}
|
||||
$d->enabled = $enabled;
|
||||
$d->prepaid = $prepaid;
|
||||
$d->device = $device;
|
||||
$d->save();
|
||||
|
||||
$dvc = Package::getDevice($d);
|
||||
if ($_app_stage != 'demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
(new $d['device'])->add_plan($d);
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
}
|
||||
}
|
||||
r2(getUrl('services/vpn'), 's', Lang::T('Data Created Successfully'));
|
||||
} else {
|
||||
r2(getUrl('services/vpn-add'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'edit-vpn-post':
|
||||
$id = _post('id');
|
||||
$plan_type = _post('plan_type');
|
||||
$name = _post('name_plan');
|
||||
$id_bw = _post('id_bw');
|
||||
$price = _post('price');
|
||||
$price_old = _post('price_old');
|
||||
$validity = _post('validity');
|
||||
$validity_unit = _post('validity_unit');
|
||||
$routers = _post('routers');
|
||||
$device = _post('device');
|
||||
$pool = _post('pool_name');
|
||||
$plan_expired = _post('plan_expired');
|
||||
$enabled = _post('enabled');
|
||||
$prepaid = _post('prepaid');
|
||||
$expired_date = _post('expired_date');
|
||||
$on_login = _post('on_login');
|
||||
$on_logout = _post('on_logout');
|
||||
|
||||
$msg = '';
|
||||
if (Validator::UnsignedNumber($validity) == false) {
|
||||
$msg .= 'The validity must be a number' . '<br>';
|
||||
}
|
||||
if (Validator::UnsignedNumber($price) == false) {
|
||||
$msg .= 'The price must be a number' . '<br>';
|
||||
}
|
||||
if ($name == '' or $id_bw == '' or $price == '' or $validity == '' or $pool == '') {
|
||||
$msg .= Lang::T('All field is required') . '<br>';
|
||||
}
|
||||
|
||||
if($price_old<=$price){
|
||||
$price_old = '';
|
||||
}
|
||||
|
||||
$d = ORM::for_table('tbl_plans')->where('id', $id)->find_one();
|
||||
$old = ORM::for_table('tbl_plans')->where('id', $id)->find_one();
|
||||
if ($d) {
|
||||
} else {
|
||||
$msg .= Lang::T('Data Not Found') . '<br>';
|
||||
}
|
||||
run_hook('edit_vpn'); #HOOK
|
||||
if ($msg == '') {
|
||||
$b = ORM::for_table('tbl_bandwidth')->where('id', $id_bw)->find_one();
|
||||
if ($b['rate_down_unit'] == 'Kbps') {
|
||||
$unitdown = 'K';
|
||||
$raddown = '000';
|
||||
} else {
|
||||
$unitdown = 'M';
|
||||
$raddown = '000000';
|
||||
}
|
||||
if ($b['rate_up_unit'] == 'Kbps') {
|
||||
$unitup = 'K';
|
||||
$radup = '000';
|
||||
} else {
|
||||
$unitup = 'M';
|
||||
$radup = '000000';
|
||||
}
|
||||
$rate = $b['rate_up'] . $unitup . "/" . $b['rate_down'] . $unitdown;
|
||||
$radiusRate = $b['rate_up'] . $radup . '/' . $b['rate_down'] . $raddown . '/' . $b['burst'];
|
||||
$rate = trim($rate . " " . $b['burst']);
|
||||
|
||||
$d->name_plan = $name;
|
||||
$d->id_bw = $id_bw;
|
||||
$d->price = $price;
|
||||
$d->price_old = $price_old;
|
||||
$d->plan_type = $plan_type;
|
||||
$d->validity = $validity;
|
||||
$d->validity_unit = $validity_unit;
|
||||
$d->routers = $routers;
|
||||
$d->pool = $pool;
|
||||
$d->plan_expired = $plan_expired;
|
||||
$d->enabled = $enabled;
|
||||
$d->prepaid = $prepaid;
|
||||
$d->device = $device;
|
||||
$d->on_login = $on_login;
|
||||
$d->on_logout = $on_logout;
|
||||
if ($prepaid == 'no') {
|
||||
if ($expired_date > 28 && $expired_date < 1) {
|
||||
$expired_date = 20;
|
||||
}
|
||||
$d->expired_date = $expired_date;
|
||||
} else {
|
||||
$d->expired_date = 0;
|
||||
}
|
||||
$d->save();
|
||||
|
||||
$dvc = Package::getDevice($d);
|
||||
if ($_app_stage != 'demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
(new $d['device'])->update_plan($old, $d);
|
||||
} else {
|
||||
new Exception(Lang::T("Devices Not Found"));
|
||||
}
|
||||
}
|
||||
r2(getUrl('services/vpn'), 's', Lang::T('Data Updated Successfully'));
|
||||
} else {
|
||||
r2(getUrl('services/vpn-edit/') . $id, 'e', $msg);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$ui->display('a404.tpl');
|
||||
$ui->display('admin/404.tpl');
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ switch ($action) {
|
||||
$d->value = 'yes';
|
||||
$d->save();
|
||||
}
|
||||
r2('./docs');
|
||||
r2(APP_URL . '/docs');
|
||||
break;
|
||||
case 'devices':
|
||||
$files = scandir($DEVICE_PATH);
|
||||
@ -34,11 +34,11 @@ switch ($action) {
|
||||
$dev = pathinfo($file, PATHINFO_FILENAME);
|
||||
require_once $DEVICE_PATH . DIRECTORY_SEPARATOR . $file;
|
||||
$dvc = new $dev;
|
||||
if(method_exists($dvc, 'description')){
|
||||
if (method_exists($dvc, 'description')) {
|
||||
$arr = $dvc->description();
|
||||
$arr['file'] = $dev;
|
||||
$devices[] = $arr;
|
||||
}else{
|
||||
} else {
|
||||
$devices[] = [
|
||||
'title' => $dev,
|
||||
'description' => '',
|
||||
@ -50,7 +50,7 @@ switch ($action) {
|
||||
}
|
||||
}
|
||||
$ui->assign('devices', $devices);
|
||||
$ui->display('app-devices.tpl');
|
||||
$ui->display('admin/settings/devices.tpl');
|
||||
break;
|
||||
case 'app':
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
@ -58,29 +58,70 @@ switch ($action) {
|
||||
}
|
||||
|
||||
if (!empty(_get('testWa'))) {
|
||||
if ($_app_stage == 'Demo') {
|
||||
r2(getUrl('settings/app'), 'e', 'You cannot perform this action in Demo mode');
|
||||
}
|
||||
$result = Message::sendWhatsapp(_get('testWa'), 'PHPNuxBill Test Whatsapp');
|
||||
r2(U . "settings/app", 's', 'Test Whatsapp has been send<br>Result: ' . $result);
|
||||
r2(getUrl('settings/app'), 's', 'Test Whatsapp has been send<br>Result: ' . $result);
|
||||
}
|
||||
if (!empty(_get('testSms'))) {
|
||||
if ($_app_stage == 'Demo') {
|
||||
r2(getUrl('settings/app'), 'e', 'You cannot perform this action in Demo mode');
|
||||
}
|
||||
$result = Message::sendSMS(_get('testSms'), 'PHPNuxBill Test SMS');
|
||||
r2(U . "settings/app", 's', 'Test SMS has been send<br>Result: ' . $result);
|
||||
r2(getUrl('settings/app'), 's', 'Test SMS has been send<br>Result: ' . $result);
|
||||
}
|
||||
if (!empty(_get('testEmail'))) {
|
||||
if ($_app_stage == 'Demo') {
|
||||
r2(getUrl('settings/app'), 'e', 'You cannot perform this action in Demo mode');
|
||||
}
|
||||
Message::sendEmail(_get('testEmail'), 'PHPNuxBill Test Email', 'PHPNuxBill Test Email Body');
|
||||
r2(U . "settings/app", 's', 'Test Email has been send');
|
||||
r2(getUrl('settings/app'), 's', 'Test Email has been send');
|
||||
}
|
||||
if (!empty(_get('testTg'))) {
|
||||
if ($_app_stage == 'Demo') {
|
||||
r2(getUrl('settings/app'), 'e', 'You cannot perform this action in Demo mode');
|
||||
}
|
||||
$result = Message::sendTelegram('PHPNuxBill Test Telegram');
|
||||
r2(U . "settings/app", 's', 'Test Telegram has been send<br>Result: ' . $result);
|
||||
r2(getUrl('settings/app'), 's', 'Test Telegram has been send<br>Result: ' . $result);
|
||||
}
|
||||
|
||||
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
|
||||
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
|
||||
if (file_exists($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png')) {
|
||||
$logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'logo.png?' . time();
|
||||
} else {
|
||||
$logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'logo.default.png';
|
||||
}
|
||||
$ui->assign('logo', $logo);
|
||||
|
||||
if (!empty($config['login_page_logo']) && file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_logo'])) {
|
||||
$login_logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_logo'];
|
||||
} elseif (file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'login-logo.png')) {
|
||||
$login_logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'login-logo.png';
|
||||
} else {
|
||||
$login_logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'login-logo.default.png';
|
||||
}
|
||||
|
||||
if (!empty($config['login_page_wallpaper']) && file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_wallpaper'])) {
|
||||
$wallpaper = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_wallpaper'];
|
||||
} elseif (file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'wallpaper.png')) {
|
||||
$wallpaper = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'wallpaper.png';
|
||||
} else {
|
||||
$wallpaper = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'wallpaper.default.png';
|
||||
}
|
||||
|
||||
if (!empty($config['login_page_favicon']) && file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_favicon'])) {
|
||||
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . $config['login_page_favicon'];
|
||||
} elseif (file_exists($UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.png')) {
|
||||
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.png';
|
||||
} else {
|
||||
$favicon = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'favicon.default.png';
|
||||
}
|
||||
|
||||
$ui->assign('login_logo', $login_logo);
|
||||
$ui->assign('wallpaper', $wallpaper);
|
||||
$ui->assign('favicon', $favicon);
|
||||
|
||||
$themes = [];
|
||||
$files = scandir('ui/themes/');
|
||||
foreach ($files as $file) {
|
||||
@ -88,10 +129,25 @@ switch ($action) {
|
||||
$themes[] = $file;
|
||||
}
|
||||
}
|
||||
|
||||
$template_files = glob('ui/ui/customer/login-custom-*.tpl');
|
||||
$templates = [];
|
||||
|
||||
foreach ($template_files as $file) {
|
||||
$parts = explode('-', basename($file, '.tpl'));
|
||||
$template_identifier = $parts[2] ?? 'unknown';
|
||||
$templates[] = [
|
||||
'filename' => basename($file),
|
||||
'value' => $template_identifier,
|
||||
'name' => str_replace('_', ' ', ucfirst($template_identifier))
|
||||
];
|
||||
}
|
||||
|
||||
$r = ORM::for_table('tbl_routers')->find_many();
|
||||
$ui->assign('r', $r);
|
||||
if (function_exists("shell_exec")) {
|
||||
$php = trim(shell_exec('which php'));
|
||||
$which = stripos(php_uname('s'), "Win") === 0 ? 'where' : 'which';
|
||||
$php = trim(shell_exec("$which php"));
|
||||
if (empty($php)) {
|
||||
$php = 'php';
|
||||
}
|
||||
@ -111,36 +167,54 @@ switch ($action) {
|
||||
$d->save();
|
||||
}
|
||||
}
|
||||
if (empty($config['mikrotik_sms_command'])) {
|
||||
$config['mikrotik_sms_command'] = "/tool sms send";
|
||||
}
|
||||
$ui->assign('template_files', $templates);
|
||||
$ui->assign('_c', $config);
|
||||
$ui->assign('php', $php);
|
||||
$ui->assign('dir', str_replace('controllers', '', __DIR__));
|
||||
$ui->assign('themes', $themes);
|
||||
run_hook('view_app_settings'); #HOOK
|
||||
$ui->display('app-settings.tpl');
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->display('admin/settings/app.tpl');
|
||||
break;
|
||||
|
||||
case 'app-post':
|
||||
|
||||
if ($_app_stage == 'Demo') {
|
||||
r2(getUrl('settings/app'), 'e', 'You cannot perform this action in Demo mode');
|
||||
}
|
||||
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$csrf_token = _post('csrf_token');
|
||||
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('settings/app'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$company = _post('CompanyName');
|
||||
$custom_tax_rate = filter_var(_post('custom_tax_rate'), FILTER_SANITIZE_SPECIAL_CHARS);
|
||||
if (preg_match('/[^0-9.]/', $custom_tax_rate)) {
|
||||
r2(U . 'settings/app', 'e', 'Special characters are not allowed in tax rate');
|
||||
r2(getUrl('settings/app'), 'e', 'Special characters are not allowed in tax rate');
|
||||
die();
|
||||
}
|
||||
run_hook('save_settings'); #HOOK
|
||||
if (!empty($_FILES['logo']['name'])) {
|
||||
if (function_exists('imagecreatetruecolor')) {
|
||||
if (file_exists($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png')) unlink($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png');
|
||||
if (file_exists($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png'))
|
||||
unlink($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png');
|
||||
File::resizeCropImage($_FILES['logo']['tmp_name'], $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png', 1078, 200, 100);
|
||||
if (file_exists($_FILES['logo']['tmp_name'])) unlink($_FILES['logo']['tmp_name']);
|
||||
if (file_exists($_FILES['logo']['tmp_name']))
|
||||
unlink($_FILES['logo']['tmp_name']);
|
||||
} else {
|
||||
r2(U . 'settings/app', 'e', 'PHP GD is not installed');
|
||||
r2(getUrl('settings/app'), 'e', 'PHP GD is not installed');
|
||||
}
|
||||
}
|
||||
if ($company == '') {
|
||||
r2(U . 'settings/app', 'e', Lang::T('All field is required'));
|
||||
if ($_POST['general'] && $company == '') {
|
||||
r2(getUrl('settings/app'), 'e', Lang::T('All field is required'));
|
||||
} else {
|
||||
if ($radius_enable) {
|
||||
try {
|
||||
@ -151,13 +225,99 @@ switch ($action) {
|
||||
$ui->assign("error_message", "Radius table not found.<br><br>" .
|
||||
$e->getMessage() .
|
||||
"<br><br>Download <a href=\"https://raw.githubusercontent.com/hotspotbilling/phpnuxbill/Development/install/radius.sql\">here</a> or <a href=\"https://raw.githubusercontent.com/hotspotbilling/phpnuxbill/master/install/radius.sql\">here</a> and import it to database.<br><br>Check config.php for radius connection details");
|
||||
$ui->display('router-error.tpl');
|
||||
$ui->display('admin/error.tpl');
|
||||
die();
|
||||
}
|
||||
}
|
||||
// Save all settings including tax system
|
||||
// Save all settings including tax system
|
||||
$_POST['man_fields_email'] = isset($_POST['man_fields_email']) ? 'yes' : 'no';
|
||||
$_POST['man_fields_fname'] = isset($_POST['man_fields_fname']) ? 'yes' : 'no';
|
||||
$_POST['man_fields_address'] = isset($_POST['man_fields_address']) ? 'yes' : 'no';
|
||||
$_POST['man_fields_custom'] = isset($_POST['man_fields_custom']) ? 'yes' : 'no';
|
||||
$enable_session_timeout = isset($_POST['enable_session_timeout']) ? 1 : 0;
|
||||
$_POST['enable_session_timeout'] = $enable_session_timeout;
|
||||
$_POST['notification_reminder_1day'] = isset($_POST['notification_reminder_1day']) ? 'yes' : 'no';
|
||||
$_POST['notification_reminder_3days'] = isset($_POST['notification_reminder_3days']) ? 'yes' : 'no';
|
||||
$_POST['notification_reminder_7days'] = isset($_POST['notification_reminder_7days']) ? 'yes' : 'no';
|
||||
|
||||
// hide dashboard
|
||||
$_POST['hide_mrc'] = _post('hide_mrc', 'no');
|
||||
$_POST['hide_tms'] = _post('hide_tms', 'no');
|
||||
$_POST['hide_al'] = _post('hide_al', 'no');
|
||||
$_POST['hide_uet'] = _post('hide_uet', 'no');
|
||||
$_POST['hide_vs'] = _post('hide_vs', 'no');
|
||||
$_POST['hide_pg'] = _post('hide_pg', 'no');
|
||||
$_POST['hide_aui'] = _post('hide_aui', 'no');
|
||||
|
||||
// Login page post
|
||||
$login_page_title = _post('login_page_head');
|
||||
$login_page_description = _post('login_page_description');
|
||||
$login_Page_template = _post('login_Page_template');
|
||||
$login_page_type = _post('login_page_type');
|
||||
$csrf_token = _post('csrf_token');
|
||||
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('settings/app'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
|
||||
if ($login_page_type == 'custom' && (empty($login_Page_template) || empty($login_page_title) || empty($login_page_description))) {
|
||||
r2(getUrl('settings/app'), 'e', 'Please fill all required fields');
|
||||
return;
|
||||
}
|
||||
|
||||
if (strlen($login_page_title) > 25) {
|
||||
r2(getUrl('settings/app'), 'e', 'Login page title must not exceed 25 characters');
|
||||
return;
|
||||
}
|
||||
if (strlen($login_page_description) > 100) {
|
||||
r2(getUrl('settings/app'), 'e', 'Login page description must not exceed 50 characters');
|
||||
return;
|
||||
}
|
||||
|
||||
$image_paths = [];
|
||||
$allowed_types = ['image/jpeg', 'image/png'];
|
||||
|
||||
if ($_FILES['login_page_favicon']['name'] != '') {
|
||||
$favicon_type = $_FILES['login_page_favicon']['type'];
|
||||
if (in_array($favicon_type, $allowed_types) && preg_match('/\.(jpg|jpeg|png)$/i', $_FILES['login_page_favicon']['name'])) {
|
||||
$extension = pathinfo($_FILES['login_page_favicon']['name'], PATHINFO_EXTENSION);
|
||||
$favicon_path = $UPLOAD_PATH . DIRECTORY_SEPARATOR . uniqid('favicon_') . '.' . $extension;
|
||||
File::resizeCropImage($_FILES['login_page_favicon']['tmp_name'], $favicon_path, 16, 16, 100);
|
||||
$_POST['login_page_favicon'] = basename($favicon_path); // Save dynamic file name
|
||||
if (file_exists($_FILES['login_page_favicon']['tmp_name']))
|
||||
unlink($_FILES['login_page_favicon']['tmp_name']);
|
||||
} else {
|
||||
r2(getUrl('settings/app'), 'e', 'Favicon must be a JPG, JPEG, or PNG image.');
|
||||
}
|
||||
}
|
||||
|
||||
if ($_FILES['login_page_wallpaper']['name'] != '') {
|
||||
$wallpaper_type = $_FILES['login_page_wallpaper']['type'];
|
||||
if (in_array($wallpaper_type, $allowed_types) && preg_match('/\.(jpg|jpeg|png)$/i', $_FILES['login_page_wallpaper']['name'])) {
|
||||
$extension = pathinfo($_FILES['login_page_wallpaper']['name'], PATHINFO_EXTENSION);
|
||||
$wallpaper_path = $UPLOAD_PATH . DIRECTORY_SEPARATOR . uniqid('wallpaper_') . '.' . $extension;
|
||||
File::resizeCropImage($_FILES['login_page_wallpaper']['tmp_name'], $wallpaper_path, 1920, 1080, 100);
|
||||
$_POST['login_page_wallpaper'] = basename($wallpaper_path); // Save dynamic file name
|
||||
if (file_exists($_FILES['login_page_wallpaper']['tmp_name']))
|
||||
unlink($_FILES['login_page_wallpaper']['tmp_name']);
|
||||
} else {
|
||||
r2(getUrl('settings/app'), 'e', 'Wallpaper must be a JPG, JPEG, or PNG image.');
|
||||
}
|
||||
}
|
||||
|
||||
if ($_FILES['login_page_logo']['name'] != '') {
|
||||
$logo_type = $_FILES['login_page_logo']['type'];
|
||||
if (in_array($logo_type, $allowed_types) && preg_match('/\.(jpg|jpeg|png)$/i', $_FILES['login_page_logo']['name'])) {
|
||||
$extension = pathinfo($_FILES['login_page_logo']['name'], PATHINFO_EXTENSION);
|
||||
$logo_path = $UPLOAD_PATH . DIRECTORY_SEPARATOR . uniqid('logo_') . '.' . $extension;
|
||||
File::resizeCropImage($_FILES['login_page_logo']['tmp_name'], $logo_path, 300, 60, 100);
|
||||
$_POST['login_page_logo'] = basename($logo_path); // Save dynamic file name
|
||||
if (file_exists($_FILES['login_page_logo']['tmp_name']))
|
||||
unlink($_FILES['login_page_logo']['tmp_name']);
|
||||
} else {
|
||||
r2(getUrl('settings/app'), 'e', 'Logo must be a JPG, JPEG, or PNG image.');
|
||||
}
|
||||
}
|
||||
foreach ($_POST as $key => $value) {
|
||||
$d = ORM::for_table('tbl_appconfig')->where('setting', $key)->find_one();
|
||||
if ($d) {
|
||||
@ -170,26 +330,9 @@ switch ($action) {
|
||||
$d->save();
|
||||
}
|
||||
}
|
||||
//checkbox
|
||||
$checks = ['hide_mrc', 'hide_tms', 'hide_aui', 'hide_al', 'hide_uet', 'hide_vs', 'hide_pg'];
|
||||
foreach ($checks as $check) {
|
||||
if (!isset($_POST[$check])) {
|
||||
$d = ORM::for_table('tbl_appconfig')->where('setting', $check)->find_one();
|
||||
if ($d) {
|
||||
$d->value = 'no';
|
||||
$d->save();
|
||||
} else {
|
||||
$d = ORM::for_table('tbl_appconfig')->create();
|
||||
$d->setting = $check;
|
||||
$d->value = 'no';
|
||||
$d->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_log('[' . $admin['username'] . ']: ' . Lang::T('Settings Saved Successfully'), $admin['user_type'], $admin['id']);
|
||||
|
||||
r2(U . 'settings/app', 's', Lang::T('Settings Saved Successfully'));
|
||||
r2(getUrl('settings/app'), 's', Lang::T('Settings Saved Successfully'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -217,20 +360,29 @@ switch ($action) {
|
||||
$ui->assign('tlist', $timezonelist);
|
||||
$ui->assign('xjq', ' $("#tzone").select2(); ');
|
||||
run_hook('view_localisation'); #HOOK
|
||||
$ui->display('app-localisation.tpl');
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->display('admin/settings/localisation.tpl');
|
||||
break;
|
||||
|
||||
case 'localisation-post':
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
if ($_app_stage == 'Demo') {
|
||||
r2(getUrl('settings/localisation'), 'e', 'You cannot perform this action in Demo mode');
|
||||
}
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('settings/localisation'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$tzone = _post('tzone');
|
||||
$date_format = _post('date_format');
|
||||
$country_code_phone = _post('country_code_phone');
|
||||
$lan = _post('lan');
|
||||
run_hook('save_localisation'); #HOOK
|
||||
if ($tzone == '' or $date_format == '' or $lan == '') {
|
||||
r2(U . 'settings/app', 'e', Lang::T('All field is required'));
|
||||
r2(getUrl('settings/localisation'), 'e', Lang::T('All field is required'));
|
||||
} else {
|
||||
$d = ORM::for_table('tbl_appconfig')->where('setting', 'timezone')->find_one();
|
||||
$d->value = $tzone;
|
||||
@ -295,6 +447,16 @@ switch ($action) {
|
||||
$d->value = _post('pppoe_plan');
|
||||
$d->save();
|
||||
}
|
||||
$d = ORM::for_table('tbl_appconfig')->where('setting', 'vpn_plan')->find_one();
|
||||
if ($d) {
|
||||
$d->value = _post('vpn_plan');
|
||||
$d->save();
|
||||
} else {
|
||||
$d = ORM::for_table('tbl_appconfig')->create();
|
||||
$d->setting = 'vpn_plan';
|
||||
$d->value = _post('vpn_plan');
|
||||
$d->save();
|
||||
}
|
||||
|
||||
$currency_code = $_POST['currency_code'];
|
||||
$d = ORM::for_table('tbl_appconfig')->where('setting', 'currency_code')->find_one();
|
||||
@ -304,9 +466,8 @@ switch ($action) {
|
||||
$d = ORM::for_table('tbl_appconfig')->where('setting', 'language')->find_one();
|
||||
$d->value = $lan;
|
||||
$d->save();
|
||||
unset($_SESSION['Lang']);
|
||||
_log('[' . $admin['username'] . ']: ' . 'Settings Saved Successfully', $admin['user_type'], $admin['id']);
|
||||
r2(U . 'settings/localisation', 's', 'Settings Saved Successfully');
|
||||
r2(getUrl('settings/localisation'), 's', 'Settings Saved Successfully');
|
||||
}
|
||||
break;
|
||||
|
||||
@ -324,11 +485,11 @@ switch ($action) {
|
||||
} else if ($admin['user_type'] == 'Admin') {
|
||||
$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']]
|
||||
])->order_by_asc('id');
|
||||
['user_type' => 'Report'],
|
||||
['user_type' => 'Agent'],
|
||||
['user_type' => 'Sales'],
|
||||
['id' => $admin['id']]
|
||||
])->order_by_asc('id');
|
||||
$d = Paginator::findMany($query, ['search' => $search]);
|
||||
} else {
|
||||
$query = ORM::for_table('tbl_users')
|
||||
@ -377,26 +538,30 @@ switch ($action) {
|
||||
$ui->assign('d', $d);
|
||||
$ui->assign('search', $search);
|
||||
run_hook('view_list_admin'); #HOOK
|
||||
$ui->display('admin.tpl');
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->display('admin/admin/list.tpl');
|
||||
break;
|
||||
|
||||
case 'users-add':
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->assign('_title', Lang::T('Add User'));
|
||||
$ui->assign('agents', ORM::for_table('tbl_users')->where('user_type', 'Agent')->find_many());
|
||||
$ui->display('admin-add.tpl');
|
||||
$ui->display('admin/admin/add.tpl');
|
||||
break;
|
||||
case 'users-view':
|
||||
$ui->assign('_title', Lang::T('Edit User'));
|
||||
$id = $routes['2'];
|
||||
$id = $routes['2'];
|
||||
if (empty($id)) {
|
||||
$id = $admin['id'];
|
||||
}
|
||||
//allow see himself
|
||||
if ($admin['id'] == $id) {
|
||||
$d = ORM::for_table('tbl_users')->where('id', $id)->find_array($id)[0];
|
||||
$d = ORM::for_table('tbl_users')->where('id', $id)->find_array()[0];
|
||||
} else {
|
||||
if (in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
// Super Admin can see anyone
|
||||
@ -413,9 +578,11 @@ switch ($action) {
|
||||
}
|
||||
$ui->assign('d', $d);
|
||||
$ui->assign('_title', $d['username']);
|
||||
$ui->display('admin-view.tpl');
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->display('admin/admin/view.tpl');
|
||||
} else {
|
||||
r2(U . 'settings/users', 'e', Lang::T('Account Not Found'));
|
||||
r2(getUrl('settings/users'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
case 'users-edit':
|
||||
@ -423,7 +590,7 @@ switch ($action) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$ui->assign('_title', Lang::T('Edit User'));
|
||||
$id = $routes['2'];
|
||||
$id = $routes['2'];
|
||||
if (empty($id)) {
|
||||
$id = $admin['id'];
|
||||
}
|
||||
@ -447,12 +614,31 @@ switch ($action) {
|
||||
}
|
||||
}
|
||||
if ($d) {
|
||||
if (isset($routes['3']) && $routes['3'] == 'deletePhoto') {
|
||||
if ($d['photo'] != '' && strpos($d['photo'], 'default') === false) {
|
||||
if (file_exists($UPLOAD_PATH . $d['photo']) && strpos($d['photo'], 'default') === false) {
|
||||
unlink($UPLOAD_PATH . $d['photo']);
|
||||
if (file_exists($UPLOAD_PATH . $d['photo'] . '.thumb.jpg')) {
|
||||
unlink($UPLOAD_PATH . $d['photo'] . '.thumb.jpg');
|
||||
}
|
||||
}
|
||||
$d->photo = '/admin.default.png';
|
||||
$d->save();
|
||||
$ui->assign('notify_t', 's');
|
||||
$ui->assign('notify', 'You have successfully deleted the photo');
|
||||
} else {
|
||||
$ui->assign('notify_t', 'e');
|
||||
$ui->assign('notify', 'No photo found to delete');
|
||||
}
|
||||
}
|
||||
$ui->assign('id', $id);
|
||||
$ui->assign('d', $d);
|
||||
run_hook('view_edit_admin'); #HOOK
|
||||
$ui->display('admin-edit.tpl');
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->display('admin/admin/edit.tpl');
|
||||
} else {
|
||||
r2(U . 'settings/users', 'e', Lang::T('Account Not Found'));
|
||||
r2(getUrl('settings/users'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -460,18 +646,20 @@ switch ($action) {
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
|
||||
$id = $routes['2'];
|
||||
if ($_app_stage == 'Demo') {
|
||||
r2(getUrl('settings/users'), 'e', 'You cannot perform this action in Demo mode');
|
||||
}
|
||||
$id = $routes['2'];
|
||||
if (($admin['id']) == $id) {
|
||||
r2(U . 'settings/users', 'e', 'Sorry You can\'t delete yourself');
|
||||
r2(getUrl('settings/users'), 'e', 'Sorry You can\'t delete yourself');
|
||||
}
|
||||
$d = ORM::for_table('tbl_users')->find_one($id);
|
||||
if ($d) {
|
||||
run_hook('delete_admin'); #HOOK
|
||||
$d->delete();
|
||||
r2(U . 'settings/users', 's', Lang::T('User deleted Successfully'));
|
||||
r2(getUrl('settings/users'), 's', Lang::T('User deleted Successfully'));
|
||||
} else {
|
||||
r2(U . 'settings/users', 'e', Lang::T('Account Not Found'));
|
||||
r2(getUrl('settings/users'), 'e', Lang::T('Account Not Found'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -479,6 +667,13 @@ switch ($action) {
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin', 'Agent'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
if ($_app_stage == 'Demo') {
|
||||
r2(getUrl('settings/users-add'), 'e', 'You cannot perform this action in Demo mode');
|
||||
}
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('settings/users-add'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$username = _post('username');
|
||||
$fullname = _post('fullname');
|
||||
$password = _post('password');
|
||||
@ -536,13 +731,20 @@ switch ($action) {
|
||||
}
|
||||
|
||||
_log('[' . $admin['username'] . ']: ' . "Created $user_type <b>$username</b>", $admin['user_type'], $admin['id']);
|
||||
r2(U . 'settings/users', 's', Lang::T('Account Created Successfully'));
|
||||
r2(getUrl('settings/users'), 's', Lang::T('Account Created Successfully'));
|
||||
} else {
|
||||
r2(U . 'settings/users-add', 'e', $msg);
|
||||
r2(getUrl('settings/users-add'), 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'users-edit-post':
|
||||
if ($_app_stage == 'Demo') {
|
||||
r2(getUrl('settings/users-edit/'), 'e', 'You cannot perform this action in Demo mode');
|
||||
}
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('settings/users-edit/'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$username = _post('username');
|
||||
$fullname = _post('fullname');
|
||||
$password = _post('password');
|
||||
@ -599,6 +801,56 @@ switch ($action) {
|
||||
}
|
||||
run_hook('edit_admin'); #HOOK
|
||||
if ($msg == '') {
|
||||
if (!empty($_FILES['photo']['name']) && file_exists($_FILES['photo']['tmp_name'])) {
|
||||
if (function_exists('imagecreatetruecolor')) {
|
||||
$hash = md5_file($_FILES['photo']['tmp_name']);
|
||||
$subfolder = substr($hash, 0, 2);
|
||||
$folder = $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'photos' . DIRECTORY_SEPARATOR;
|
||||
if (!file_exists($folder)) {
|
||||
mkdir($folder);
|
||||
}
|
||||
$folder = $UPLOAD_PATH . DIRECTORY_SEPARATOR . 'photos' . DIRECTORY_SEPARATOR . $subfolder . DIRECTORY_SEPARATOR;
|
||||
if (!file_exists($folder)) {
|
||||
mkdir($folder);
|
||||
}
|
||||
$imgPath = $folder . $hash . '.jpg';
|
||||
if (!file_exists($imgPath)) {
|
||||
File::resizeCropImage($_FILES['photo']['tmp_name'], $imgPath, 1600, 1600, 100);
|
||||
}
|
||||
if (!file_exists($imgPath . '.thumb.jpg')) {
|
||||
if (_post('faceDetect') == 'yes') {
|
||||
try {
|
||||
$detector = new svay\FaceDetector();
|
||||
$detector->setTimeout(5000);
|
||||
$detector->faceDetect($imgPath);
|
||||
$detector->cropFaceToJpeg($imgPath . '.thumb.jpg', false);
|
||||
} catch (Exception $e) {
|
||||
File::makeThumb($imgPath, $imgPath . '.thumb.jpg', 200);
|
||||
} catch (Throwable $e) {
|
||||
File::makeThumb($imgPath, $imgPath . '.thumb.jpg', 200);
|
||||
}
|
||||
} else {
|
||||
File::makeThumb($imgPath, $imgPath . '.thumb.jpg', 200);
|
||||
}
|
||||
}
|
||||
if (file_exists($imgPath)) {
|
||||
if ($d['photo'] != '' && strpos($d['photo'], 'default') === false) {
|
||||
if (file_exists($UPLOAD_PATH . $d['photo'])) {
|
||||
unlink($UPLOAD_PATH . $d['photo']);
|
||||
if (file_exists($UPLOAD_PATH . $d['photo'] . '.thumb.jpg')) {
|
||||
unlink($UPLOAD_PATH . $d['photo'] . '.thumb.jpg');
|
||||
}
|
||||
}
|
||||
}
|
||||
$d->photo = '/photos/' . $subfolder . '/' . $hash . '.jpg';
|
||||
}
|
||||
if (file_exists($_FILES['photo']['tmp_name']))
|
||||
unlink($_FILES['photo']['tmp_name']);
|
||||
} else {
|
||||
r2(getUrl('settings/app'), 'e', 'PHP GD is not installed');
|
||||
}
|
||||
}
|
||||
|
||||
$d->username = $username;
|
||||
if ($password != '') {
|
||||
$password = Password::_crypt($password);
|
||||
@ -629,19 +881,28 @@ switch ($action) {
|
||||
$d->save();
|
||||
|
||||
_log('[' . $admin['username'] . ']: $username ' . Lang::T('User Updated Successfully'), $admin['user_type'], $admin['id']);
|
||||
r2(U . 'settings/users', 's', 'User Updated Successfully');
|
||||
r2(getUrl('settings/users-view/') . $id, 's', 'User Updated Successfully');
|
||||
} else {
|
||||
r2(U . 'settings/users-edit/' . $id, 'e', $msg);
|
||||
r2(getUrl('settings/users-edit/') . $id, 'e', $msg);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'change-password':
|
||||
run_hook('view_change_password'); #HOOK
|
||||
$ui->display('change-password.tpl');
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->display('admin/change-password.tpl');
|
||||
break;
|
||||
|
||||
case 'change-password-post':
|
||||
if ($_app_stage == 'Demo') {
|
||||
r2(getUrl('settings/change-password'), 'e', 'You cannot perform this action in Demo mode');
|
||||
}
|
||||
$password = _post('password');
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('settings/change-password'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
if ($password != '') {
|
||||
$d = ORM::for_table('tbl_users')->where('username', $admin['username'])->find_one();
|
||||
run_hook('change_password'); #HOOK
|
||||
@ -651,10 +912,10 @@ switch ($action) {
|
||||
$npass = _post('npass');
|
||||
$cnpass = _post('cnpass');
|
||||
if (!Validator::Length($npass, 15, 5)) {
|
||||
r2(U . 'settings/change-password', 'e', 'New Password must be 6 to 14 character');
|
||||
r2(getUrl('settings/change-password'), 'e', 'New Password must be 6 to 14 character');
|
||||
}
|
||||
if ($npass != $cnpass) {
|
||||
r2(U . 'settings/change-password', 'e', 'Both Password should be same');
|
||||
r2(getUrl('settings/change-password'), 'e', 'Both Password should be same');
|
||||
}
|
||||
|
||||
$npass = Password::_crypt($npass);
|
||||
@ -664,15 +925,15 @@ switch ($action) {
|
||||
_msglog('s', Lang::T('Password changed successfully, Please login again'));
|
||||
_log('[' . $admin['username'] . ']: Password changed successfully', $admin['user_type'], $admin['id']);
|
||||
|
||||
r2(U . 'admin');
|
||||
r2(getUrl('admin'));
|
||||
} else {
|
||||
r2(U . 'settings/change-password', 'e', Lang::T('Incorrect Current Password'));
|
||||
r2(getUrl('settings/change-password'), 'e', Lang::T('Incorrect Current Password'));
|
||||
}
|
||||
} else {
|
||||
r2(U . 'settings/change-password', 'e', Lang::T('Incorrect Current Password'));
|
||||
r2(getUrl('settings/change-password'), 'e', Lang::T('Incorrect Current Password'));
|
||||
}
|
||||
} else {
|
||||
r2(U . 'settings/change-password', 'e', Lang::T('Incorrect Current Password'));
|
||||
r2(getUrl('settings/change-password'), 'e', Lang::T('Incorrect Current Password'));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -686,15 +947,25 @@ switch ($action) {
|
||||
} else {
|
||||
$ui->assign('_json', json_decode(file_get_contents($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'notifications.default.json'), true));
|
||||
}
|
||||
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->assign('_default', json_decode(file_get_contents($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'notifications.default.json'), true));
|
||||
$ui->display('app-notifications.tpl');
|
||||
$ui->display('admin/settings/notifications.tpl');
|
||||
break;
|
||||
case 'notifications-post':
|
||||
if ($_app_stage == 'Demo') {
|
||||
r2(getUrl('settings/notifications'), 'e', 'You cannot perform this action in Demo mode');
|
||||
}
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('settings/notifications'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
file_put_contents($UPLOAD_PATH . "/notifications.json", json_encode($_POST));
|
||||
r2(U . 'settings/notifications', 's', Lang::T('Settings Saved Successfully'));
|
||||
r2(getUrl('settings/notifications'), 's', Lang::T('Settings Saved Successfully'));
|
||||
break;
|
||||
case 'dbstatus':
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
@ -710,11 +981,14 @@ switch ($action) {
|
||||
}
|
||||
$ui->assign('tables', $tables);
|
||||
run_hook('view_database'); #HOOK
|
||||
$ui->display('dbstatus.tpl');
|
||||
$ui->display('admin/settings/dbstatus.tpl');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'dbbackup':
|
||||
if ($_app_stage == 'Demo') {
|
||||
r2(getUrl('settings/dbstatus'), 'e', 'You cannot perform this action in Demo mode');
|
||||
}
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
@ -735,6 +1009,9 @@ switch ($action) {
|
||||
echo json_encode($array);
|
||||
break;
|
||||
case 'dbrestore':
|
||||
if ($_app_stage == 'Demo') {
|
||||
r2(getUrl('settings/dbstatus'), 'e', 'You cannot perform this action in Demo mode');
|
||||
}
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
}
|
||||
@ -782,10 +1059,11 @@ switch ($action) {
|
||||
} catch (Throwable $e) {
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
if (file_exists($_FILES['json']['tmp_name'])) unlink($_FILES['json']['tmp_name']);
|
||||
r2(U . "settings/dbstatus", 's', "Restored $suc success $fal failed");
|
||||
if (file_exists($_FILES['json']['tmp_name']))
|
||||
unlink($_FILES['json']['tmp_name']);
|
||||
r2(getUrl('settings/dbstatus'), 's', "Restored $suc success $fal failed");
|
||||
} else {
|
||||
r2(U . "settings/dbstatus", 'e', 'Upload failed');
|
||||
r2(getUrl('settings/dbstatus'), 'e', 'Upload failed');
|
||||
}
|
||||
break;
|
||||
case 'language':
|
||||
@ -798,12 +1076,21 @@ switch ($action) {
|
||||
} else {
|
||||
$ui->assign('langs', []);
|
||||
}
|
||||
$ui->display('language-add.tpl');
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->display('admin/settings/language-add.tpl');
|
||||
break;
|
||||
|
||||
case 'lang-post':
|
||||
if ($_app_stage == 'Demo') {
|
||||
r2(getUrl('settings/dbstatus'), 'e', 'You cannot perform this action in Demo mode');
|
||||
}
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('settings/language'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
file_put_contents($lan_file, json_encode($_POST, JSON_PRETTY_PRINT));
|
||||
r2(U . 'settings/language', 's', Lang::T('Translation saved Successfully'));
|
||||
r2(getUrl('settings/language'), 's', Lang::T('Translation saved Successfully'));
|
||||
break;
|
||||
|
||||
case 'maintenance':
|
||||
@ -811,7 +1098,15 @@ switch ($action) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
exit;
|
||||
}
|
||||
|
||||
if (_post('save') == 'save') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
r2(getUrl('settings/maintenance'), 'e', 'You cannot perform this action in Demo mode');
|
||||
}
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('settings/maintenance'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
$status = isset($_POST['maintenance_mode']) ? 1 : 0; // Checkbox returns 1 if checked, otherwise 0
|
||||
$force_logout = isset($_POST['maintenance_mode_logout']) ? 1 : 0; // Checkbox returns 1 if checked, otherwise 0
|
||||
$date = isset($_POST['maintenance_date']) ? $_POST['maintenance_date'] : null;
|
||||
@ -835,13 +1130,50 @@ switch ($action) {
|
||||
}
|
||||
}
|
||||
|
||||
r2(U . "settings/maintenance", 's', Lang::T('Settings Saved Successfully'));
|
||||
r2(getUrl('settings/maintenance'), 's', Lang::T('Settings Saved Successfully'));
|
||||
}
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->assign('_c', $config);
|
||||
$ui->assign('_title', Lang::T('Maintenance Mode Settings'));
|
||||
$ui->display('maintenance-mode.tpl');
|
||||
$ui->display('admin/settings/maintenance-mode.tpl');
|
||||
break;
|
||||
|
||||
case 'miscellaneous':
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
||||
exit;
|
||||
}
|
||||
if (_post('save') == 'save') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
r2(getUrl('settings/miscellaneous'), 'e', 'You cannot perform this action in Demo mode');
|
||||
}
|
||||
$csrf_token = _post('csrf_token');
|
||||
if (!Csrf::check($csrf_token)) {
|
||||
r2(getUrl('settings/miscellaneous'), 'e', Lang::T('Invalid or Expired CSRF Token') . ".");
|
||||
}
|
||||
foreach ($_POST as $key => $value) {
|
||||
$d = ORM::for_table('tbl_appconfig')->where('setting', $key)->find_one();
|
||||
if ($d) {
|
||||
$d->value = $value;
|
||||
$d->save();
|
||||
} else {
|
||||
$d = ORM::for_table('tbl_appconfig')->create();
|
||||
$d->setting = $key;
|
||||
$d->value = $value;
|
||||
$d->save();
|
||||
}
|
||||
}
|
||||
|
||||
r2(getUrl('settings/miscellaneous'), 's', Lang::T('Settings Saved Successfully'));
|
||||
}
|
||||
$csrf_token = Csrf::generateAndStoreToken();
|
||||
$ui->assign('csrf_token', $csrf_token);
|
||||
$ui->assign('_c', $config);
|
||||
$ui->assign('_title', Lang::T('Miscellaneous Settings'));
|
||||
$ui->display('admin/settings/miscellaneous.tpl');
|
||||
break;
|
||||
|
||||
default:
|
||||
$ui->display('a404.tpl');
|
||||
$ui->display('admin/404.tpl');
|
||||
}
|
||||
|
@ -4,11 +4,47 @@
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
**/
|
||||
_auth();
|
||||
|
||||
$ui->assign('_title', Lang::T('Voucher'));
|
||||
$ui->assign('_system_menu', 'voucher');
|
||||
|
||||
$action = $routes['1'];
|
||||
if(!_auth(false)){
|
||||
if($action== 'invoice'){
|
||||
$id = $routes[2];
|
||||
$sign = $routes[3];
|
||||
if($sign != md5($id. $db_pass)) {
|
||||
die("beda");
|
||||
}
|
||||
if (empty($id)) {
|
||||
$in = ORM::for_table('tbl_transactions')->order_by_desc('id')->find_one();
|
||||
} else {
|
||||
$in = ORM::for_table('tbl_transactions')->where('id', $id)->find_one();
|
||||
}
|
||||
if ($in) {
|
||||
Package::createInvoice($in);
|
||||
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
|
||||
$logo = '';
|
||||
if (file_exists($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png')) {
|
||||
$logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'logo.png';
|
||||
$imgsize = getimagesize($logo);
|
||||
$width = $imgsize[0];
|
||||
$height = $imgsize[1];
|
||||
$ui->assign('wlogo', $width);
|
||||
$ui->assign('hlogo', $height);
|
||||
}
|
||||
$ui->assign('public_url', getUrl("voucher/invoice/$id/".md5($id. $db_pass)));
|
||||
$ui->assign('logo', $logo);
|
||||
$ui->display('customer/invoice-customer.tpl');
|
||||
die();
|
||||
} else {
|
||||
r2(getUrl('voucher/list-activated'), 'e', Lang::T('Not Found'));
|
||||
}
|
||||
}else{
|
||||
r2(getUrl('login'));
|
||||
}
|
||||
}
|
||||
|
||||
$user = User::_info();
|
||||
$ui->assign('_user', $user);
|
||||
|
||||
@ -17,12 +53,12 @@ switch ($action) {
|
||||
case 'activation':
|
||||
run_hook('view_activate_voucher'); #HOOK
|
||||
$ui->assign('code', alphanumeric(_get('code'), "-_.,"));
|
||||
$ui->display('user-ui/activation.tpl');
|
||||
$ui->display('customer/activation.tpl');
|
||||
break;
|
||||
|
||||
case 'activation-post':
|
||||
$code = alphanumeric(_post('code'), "-_.,");
|
||||
$v1 = ORM::for_table('tbl_voucher')->whereRaw("BINARY `code` = '$code'")->where('status', 0)->find_one();
|
||||
$v1 = ORM::for_table('tbl_voucher')->whereRaw("BINARY code = '$code'")->where('status', 0)->find_one();
|
||||
run_hook('customer_activate_voucher'); #HOOK
|
||||
if ($v1) {
|
||||
if (Package::rechargeUser($user['id'], $v1['routers'], $v1['id_plan'], "Voucher", $code)) {
|
||||
@ -30,23 +66,29 @@ switch ($action) {
|
||||
$v1->used_date = date('Y-m-d H:i:s');
|
||||
$v1->user = $user['username'];
|
||||
$v1->save();
|
||||
r2(U . "voucher/list-activated", 's', Lang::T('Activation Vouchers Successfully'));
|
||||
r2(getUrl('voucher/list-activated'), 's', Lang::T('Activation Vouchers Successfully'));
|
||||
} else {
|
||||
r2(U . 'voucher/activation', 'e', "Failed to refill account");
|
||||
r2(getUrl('voucher/activation'), 'e', "Failed to refill account");
|
||||
}
|
||||
} else {
|
||||
r2(U . 'voucher/activation', 'e', Lang::T('Voucher Not Valid'));
|
||||
r2(getUrl('voucher/activation'), 'e', Lang::T('Voucher Not Valid'));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'list-activated':
|
||||
$ui->assign('_system_menu', 'list-activated');
|
||||
$query = ORM::for_table('tbl_transactions')->where('username', $user['username'])->order_by_desc('id');
|
||||
$query = ORM::for_table('tbl_transactions')->where('user_id', $user['id'])->order_by_desc('id');
|
||||
$d = Paginator::findMany($query);
|
||||
|
||||
if (empty($d) || $d < 5) {
|
||||
$query = ORM::for_table('tbl_transactions')->where('username', $user['username'])->order_by_desc('id');
|
||||
$d = Paginator::findMany($query);
|
||||
}
|
||||
|
||||
$ui->assign('d', $d);
|
||||
$ui->assign('_title', Lang::T('Activation History'));
|
||||
run_hook('customer_view_activation_list'); #HOOK
|
||||
$ui->display('user-ui/activation-list.tpl');
|
||||
$ui->display('customer/activation-list.tpl');
|
||||
|
||||
break;
|
||||
case 'invoice':
|
||||
@ -58,11 +100,23 @@ switch ($action) {
|
||||
}
|
||||
if ($in) {
|
||||
Package::createInvoice($in);
|
||||
$ui->display('user-ui/invoice-customer.tpl');
|
||||
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
|
||||
$logo = '';
|
||||
if (file_exists($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png')) {
|
||||
$logo = $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'logo.png';
|
||||
$imgsize = getimagesize($logo);
|
||||
$width = $imgsize[0];
|
||||
$height = $imgsize[1];
|
||||
$ui->assign('wlogo', $width);
|
||||
$ui->assign('hlogo', $height);
|
||||
}
|
||||
$ui->assign('public_url', getUrl("voucher/invoice/$id/".md5($id. $db_pass)));
|
||||
$ui->assign('logo', $logo);
|
||||
$ui->display('customer/invoice-customer.tpl');
|
||||
} else {
|
||||
r2(U . 'voucher/list-activated', 'e', Lang::T('Not Found'));
|
||||
r2(getUrl('voucher/list-activated'), 'e', Lang::T('Not Found'));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$ui->display('a404.tpl');
|
||||
$ui->display('admin/404.tpl');
|
||||
}
|
||||
|
147
system/controllers/widgets.php
Normal file
147
system/controllers/widgets.php
Normal file
@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||
* by https://t.me/ibnux
|
||||
**/
|
||||
_admin();
|
||||
$ui->assign('_title', Lang::T('Dashboard Widgets'));
|
||||
$ui->assign('_system_menu', 'settings');
|
||||
|
||||
$action = alphanumeric($routes['1']);
|
||||
$ui->assign('_admin', $admin);
|
||||
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
||||
r2(getUrl('dashboard'), 'e', Lang::T('You do not have permission to access this page'));
|
||||
}
|
||||
|
||||
$tipeUser = _req("user");
|
||||
if (empty($tipeUser)) {
|
||||
$tipeUser = 'Admin';
|
||||
}
|
||||
if($tipeUser == 'Customer') {
|
||||
$WIDGET_PATH .= DIRECTORY_SEPARATOR. 'customer';
|
||||
}
|
||||
|
||||
$ui->assign('tipeUser', $tipeUser);
|
||||
$max = ORM::for_table('tbl_widgets')->where("user", $tipeUser)->max('position');
|
||||
$max2 = substr_count($config['dashboard_' . $tipeUser], '.') + substr_count($config['dashboard_' . $tipeUser], ',') + 1;
|
||||
if ($max2 > $max) {
|
||||
$max = $max2;
|
||||
}
|
||||
$ui->assign('max', $max);
|
||||
|
||||
if ($action == 'add') {
|
||||
$pos = alphanumeric($routes['2']);
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$orders = alphanumeric($_POST['orders']);
|
||||
$position = alphanumeric($_POST['position']);
|
||||
$tipeUser = alphanumeric($_POST['tipeUser']);
|
||||
$enabled = alphanumeric($_POST['enabled']);
|
||||
$title = _post('title');
|
||||
$widget = _post('widget');
|
||||
|
||||
$d = ORM::for_table('tbl_widgets')->create();
|
||||
$d->orders = $orders;
|
||||
$d->position = $position;
|
||||
$d->user = $tipeUser;
|
||||
$d->enabled = $enabled;
|
||||
$d->title = $title;
|
||||
$d->widget = $widget;
|
||||
$d->content = _post('content');
|
||||
$d->save();
|
||||
if ($d->id() > 0) {
|
||||
r2(getUrl('widgets&user=' . $tipeUser), 's', 'Widget Added Successfully');
|
||||
}
|
||||
}
|
||||
$files = scandir($WIDGET_PATH);
|
||||
$widgets = [];
|
||||
foreach ($files as $file) {
|
||||
if (strpos($file, '.php') !== false) {
|
||||
$name = ucwords(str_replace('.php', '', str_replace('_', ' ', $file)));
|
||||
$widgets[str_replace('.php', '', $file)] = $name;
|
||||
}
|
||||
}
|
||||
$widget['position'] = $pos;
|
||||
$widget['user'] = $tipeUser;
|
||||
$ui->assign('users', ORM::for_table('tbl_widgets')->getEnum("user"));
|
||||
$ui->assign('do', 'add');
|
||||
$ui->assign('widgets', $widgets);
|
||||
$ui->assign('widget', $widget);
|
||||
$ui->display('admin/settings/widgets_add_edit.tpl');
|
||||
} else if ($action == 'edit') {
|
||||
// if request method post then save data
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$id = alphanumeric($_POST['id']);
|
||||
$orders = alphanumeric($_POST['orders']);
|
||||
$position = alphanumeric($_POST['position']);
|
||||
$tipeUser = alphanumeric($_POST['tipeUser']);
|
||||
$enabled = alphanumeric($_POST['enabled']);
|
||||
$title = _post('title');
|
||||
$widget = _post('widget');
|
||||
$d = ORM::for_table('tbl_widgets')->find_one($id);
|
||||
$d->orders = $orders;
|
||||
$d->position = $position;
|
||||
$d->user = $tipeUser;
|
||||
$d->enabled = $enabled;
|
||||
$d->title = $title;
|
||||
$d->widget = $widget;
|
||||
$d->content = _post('content');
|
||||
$d->save();
|
||||
r2(getUrl('widgets&user=' . $tipeUser), 's', 'Widget Saved Successfully');
|
||||
}
|
||||
$id = alphanumeric($routes['2']);
|
||||
$widget = ORM::for_table('tbl_widgets')->find_one($id);
|
||||
$files = scandir($WIDGET_PATH);
|
||||
$widgets = [];
|
||||
foreach ($files as $file) {
|
||||
if (strpos($file, '.php') !== false) {
|
||||
$name = ucwords(str_replace('.php', '', str_replace('_', ' ', $file)));
|
||||
$widgets[str_replace('.php', '', $file)] = $name;
|
||||
}
|
||||
}
|
||||
$ui->assign('users', ORM::for_table('tbl_widgets')->getEnum("user"));
|
||||
$ui->assign('do', 'edit');
|
||||
$ui->assign('widgets', $widgets);
|
||||
$ui->assign('widget', $widget);
|
||||
$ui->display('admin/settings/widgets_add_edit.tpl');
|
||||
} else if ($action == 'delete') {
|
||||
$id = alphanumeric($routes['2']);
|
||||
$d = ORM::for_table('tbl_widgets')->find_one($id);
|
||||
if ($d) {
|
||||
$d->delete();
|
||||
r2(getUrl('widgets&user=' . $tipeUser), 's', 'Widget Deleted Successfully');
|
||||
}
|
||||
r2(getUrl('widgets&user=' . $tipeUser), 'e', 'Widget Not Found');
|
||||
} else if (!empty($action) && file_exists("system/widget/$action.php") && !empty($routes['2'])) {
|
||||
require_once "system/widget/$action.php";
|
||||
try {
|
||||
(new $action)->run_command($routes['2']);
|
||||
} catch (Throwable $e) {
|
||||
//nothing to do
|
||||
}
|
||||
} else if ($action == 'pos') {
|
||||
$jml = count($_POST['orders']);
|
||||
for ($i = 0; $i < $jml; $i++) {
|
||||
$d = ORM::for_table('tbl_widgets')->find_one($_POST['id'][$i]);
|
||||
$d->orders = $_POST['orders'][$i];
|
||||
$d->save();
|
||||
}
|
||||
r2(getUrl('widgets&user=' . $tipeUser), 's', 'Widget order Saved Successfully');
|
||||
} else {
|
||||
if (_post("save") == 'struct') {
|
||||
$d = ORM::for_table('tbl_appconfig')->where('setting', 'dashboard_' . $tipeUser)->find_one();
|
||||
if ($d) {
|
||||
$d->value = _post('dashboard');
|
||||
$d->save();
|
||||
} else {
|
||||
$d = ORM::for_table('tbl_appconfig')->create();
|
||||
$d->setting = 'dashboard_' . $tipeUser;
|
||||
$d->value = _post('dashboard');
|
||||
$d->save();
|
||||
}
|
||||
_alert("Dashboard Structure Saved Successfully", "success", getUrl('widgets&user=' . $tipeUser));
|
||||
}
|
||||
$widgets = ORM::for_table('tbl_widgets')->where("user", $tipeUser)->order_by_asc("orders")->find_many();
|
||||
$ui->assign('widgets', $widgets);
|
||||
$ui->display('admin/settings/widgets.tpl');
|
||||
}
|
205
system/cron.php
205
system/cron.php
@ -1,6 +1,27 @@
|
||||
<?php
|
||||
|
||||
include "../init.php";
|
||||
$lockFile = "$CACHE_PATH/router_monitor.lock";
|
||||
|
||||
if (!is_dir($CACHE_PATH)) {
|
||||
echo "Directory '$CACHE_PATH' does not exist. Exiting...\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$lock = fopen($lockFile, 'c');
|
||||
|
||||
if ($lock === false) {
|
||||
echo "Failed to open lock file. Exiting...\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!flock($lock, LOCK_EX | LOCK_NB)) {
|
||||
echo "Script is already running. Exiting...\n";
|
||||
fclose($lock);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
$isCli = true;
|
||||
if (php_sapi_name() !== 'cli') {
|
||||
$isCli = false;
|
||||
@ -9,7 +30,7 @@ if (php_sapi_name() !== 'cli') {
|
||||
echo "PHP Time\t" . date('Y-m-d H:i:s') . "\n";
|
||||
$res = ORM::raw_execute('SELECT NOW() AS WAKTU;');
|
||||
$statement = ORM::get_last_statement();
|
||||
$rows = array();
|
||||
$rows = [];
|
||||
while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
|
||||
echo "MYSQL Time\t" . $row['WAKTU'] . "\n";
|
||||
}
|
||||
@ -24,84 +45,115 @@ echo "Found " . count($d) . " user(s)\n";
|
||||
run_hook('cronjob'); #HOOK
|
||||
|
||||
foreach ($d as $ds) {
|
||||
$date_now = strtotime(date("Y-m-d H:i:s"));
|
||||
$expiration = strtotime($ds['expiration'] . ' ' . $ds['time']);
|
||||
echo $ds['expiration'] . " : " . (($isCli) ? $ds['username'] : Lang::maskText($ds['username']));
|
||||
if ($date_now >= $expiration) {
|
||||
echo " : EXPIRED \r\n";
|
||||
$u = ORM::for_table('tbl_user_recharges')->where('id', $ds['id'])->find_one();
|
||||
$c = ORM::for_table('tbl_customers')->where('id', $ds['customer_id'])->find_one();
|
||||
$p = ORM::for_table('tbl_plans')->where('id', $u['plan_id'])->find_one();
|
||||
$dvc = Package::getDevice($p);
|
||||
if ($_app_stage != 'demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
(new $p['device'])->remove_customer($c, $p);
|
||||
} else {
|
||||
echo "Cron error Devices $p[device] not found, cannot disconnect $c[username]";
|
||||
Message::sendTelegram("Cron error Devices $p[device] not found, cannot disconnect $c[username]");
|
||||
}
|
||||
}
|
||||
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();
|
||||
try {
|
||||
$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']));
|
||||
|
||||
// autorenewal from deposit
|
||||
if ($config['enable_balance'] == 'yes' && $c['auto_renewal']) {
|
||||
list($bills, $add_cost) = User::getBills($ds['customer_id']);
|
||||
if ($add_cost > 0) {
|
||||
if (!empty($add_cost)) {
|
||||
if ($date_now >= $expiration) {
|
||||
echo " : EXPIRED \r\n";
|
||||
|
||||
// Fetch user recharge details
|
||||
$u = ORM::for_table('tbl_user_recharges')->where('id', $ds['id'])->find_one();
|
||||
if (!$u) {
|
||||
throw new Exception("User recharge record not found for ID: " . $ds['id']);
|
||||
}
|
||||
|
||||
// Fetch customer details
|
||||
$c = ORM::for_table('tbl_customers')->where('id', $ds['customer_id'])->find_one();
|
||||
if (!$c) {
|
||||
$c = $u;
|
||||
}
|
||||
|
||||
// Fetch plan details
|
||||
$p = ORM::for_table('tbl_plans')->where('id', $u['plan_id'])->find_one();
|
||||
if (!$p) {
|
||||
throw new Exception("Plan not found for ID: " . $u['plan_id']);
|
||||
}
|
||||
|
||||
$dvc = Package::getDevice($p);
|
||||
if ($_app_stage != 'demo') {
|
||||
if (file_exists($dvc)) {
|
||||
require_once $dvc;
|
||||
(new $p['device'])->remove_customer($c, $p);
|
||||
} else {
|
||||
throw new Exception("Cron error: Devices " . $p['device'] . "not found, cannot disconnect ".$c['username']."\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Send notification and update user status
|
||||
try {
|
||||
echo Message::sendPackageNotification(
|
||||
$c,
|
||||
$u['namebp'],
|
||||
$p['price'],
|
||||
Message::getMessageType($p['type'], $textExpired),
|
||||
$config['user_notification_expired']
|
||||
) . "\n";
|
||||
$u->status = 'off';
|
||||
$u->save();
|
||||
} catch (Throwable $e) {
|
||||
_log($e->getMessage());
|
||||
sendTelegram($e->getMessage());
|
||||
echo "Error: " . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
// Auto-renewal from deposit
|
||||
if ($config['enable_balance'] == 'yes' && $c['auto_renewal']) {
|
||||
[$bills, $add_cost] = User::getBills($ds['customer_id']);
|
||||
if ($add_cost != 0) {
|
||||
$p['price'] += $add_cost;
|
||||
}
|
||||
}
|
||||
if ($p && $c['balance'] >= $p['price']) {
|
||||
if (Package::rechargeUser($ds['customer_id'], $ds['routers'], $p['id'], 'Customer', 'Balance')) {
|
||||
// if success, then get the balance
|
||||
Balance::min($ds['customer_id'], $p['price']);
|
||||
echo "plan enabled: $p[enabled] | User balance: $c[balance] | price $p[price]\n";
|
||||
echo "auto renewall Success\n";
|
||||
|
||||
if ($p && $c['balance'] >= $p['price']) {
|
||||
if (Package::rechargeUser($ds['customer_id'], $ds['routers'], $p['id'], 'Customer', 'Balance')) {
|
||||
Balance::min($ds['customer_id'], $p['price']);
|
||||
echo "plan enabled: " . (string) $p['enabled'] . " | User balance: " . (string) $c['balance'] . " | price " . (string) $p['price'] . "\n";
|
||||
echo "auto renewal Success\n";
|
||||
} else {
|
||||
echo "plan enabled: " . $p['enabled'] . " | User balance: " . $c['balance'] . " | price " . $p['price'] . "\n";
|
||||
echo "auto renewal Failed\n";
|
||||
Message::sendTelegram("FAILED RENEWAL #cron\n\n#u." . $c['username'] . " #buy #Hotspot \n" . $p['name_plan'] .
|
||||
"\nRouter: " . $p['routers'] .
|
||||
"\nPrice: " . $p['price']);
|
||||
}
|
||||
} else {
|
||||
echo "plan enabled: $p[enabled] | User balance: $c[balance] | price $p[price]\n";
|
||||
echo "auto renewall Failed\n";
|
||||
Message::sendTelegram("FAILED RENEWAL #cron\n\n#u$c[username] #buy #Hotspot \n" . $p['name_plan'] .
|
||||
"\nRouter: " . $p['routers'] .
|
||||
"\nPrice: " . $p['price']);
|
||||
echo "no renewal | plan enabled: " . (string) $p['enabled'] . " | User balance: " . (string) $c['balance'] . " | price " . (string) $p['price'] . "\n";
|
||||
}
|
||||
} else {
|
||||
echo "no renewall | plan enabled: $p[enabled] | User balance: $c[balance] | price $p[price]\n";
|
||||
echo "no renewal | balance" . $config['enable_balance'] . " auto_renewal " . $c['auto_renewal'] . "\n";
|
||||
}
|
||||
} else {
|
||||
echo "no renewall | balance $config[enable_balance] auto_renewal $c[auto_renewal]\n";
|
||||
echo " : ACTIVE \r\n";
|
||||
}
|
||||
} else {
|
||||
echo " : ACTIVE \r\n";
|
||||
} catch (Throwable $e) {
|
||||
// Catch any unexpected errors
|
||||
_log($e->getMessage());
|
||||
sendTelegram($e->getMessage());
|
||||
echo "Unexpected Error: " . $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
//Cek interim-update radiusrest
|
||||
if ($config['frrest_interim_update'] != 0) {
|
||||
|
||||
$r_a = ORM::for_table('rad_acct')
|
||||
->whereRaw("BINARY acctstatustype = 'Start' OR acctstatustype = 'Interim-Update'")
|
||||
->where_lte('dateAdded', date("Y-m-d H:i:s"))->find_many();
|
||||
|
||||
foreach ($r_a as $ra) {
|
||||
$interval = $_c['frrest_interim_update'] * 60;
|
||||
$timeUpdate = strtotime($ra['dateAdded']) + $interval;
|
||||
$timeNow = strtotime(date("Y-m-d H:i:s"));
|
||||
if ($timeNow >= $timeUpdate) {
|
||||
$ra->acctstatustype = 'Stop';
|
||||
$ra->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($config['router_check']) {
|
||||
|
||||
$lockFile = $CACHE_PATH . '/router_monitor.lock';
|
||||
|
||||
if (!is_dir($CACHE_PATH)) {
|
||||
echo "Directory '$CACHE_PATH' does not exist. Exiting...\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$lock = fopen($lockFile, 'c');
|
||||
|
||||
if ($lock === false) {
|
||||
echo "Failed to open lock file. Exiting...\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!flock($lock, LOCK_EX | LOCK_NB)) {
|
||||
echo "Script is already running. Exiting...\n";
|
||||
fclose($lock);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo "Checking router status...\n";
|
||||
$routers = ORM::for_table('tbl_routers')->where('enabled', '1')->find_many();
|
||||
if (!$routers) {
|
||||
echo "No active routers found in the database.\n";
|
||||
@ -116,7 +168,7 @@ if ($config['router_check']) {
|
||||
|
||||
foreach ($routers as $router) {
|
||||
// check if custom port
|
||||
if (strpos($router->ip_address, ':') === false){
|
||||
if (strpos($router->ip_address, ':') === false) {
|
||||
$ip = $router->ip_address;
|
||||
$port = 8728;
|
||||
} else {
|
||||
@ -186,14 +238,15 @@ if ($config['router_check']) {
|
||||
Message::SendEmail($adminEmail, $subject, $message);
|
||||
sendTelegram($message);
|
||||
}
|
||||
|
||||
if (defined('PHP_SAPI') && PHP_SAPI === 'cli') {
|
||||
echo "Cronjob finished\n";
|
||||
} else {
|
||||
echo "</pre>";
|
||||
}
|
||||
|
||||
flock($lock, LOCK_UN);
|
||||
fclose($lock);
|
||||
unlink($lockFile);
|
||||
echo "Router monitoring finished checking.\n";
|
||||
}
|
||||
|
||||
flock($lock, LOCK_UN);
|
||||
fclose($lock);
|
||||
unlink($lockFile);
|
||||
|
||||
$timestampFile = "$UPLOAD_PATH/cron_last_run.txt";
|
||||
file_put_contents($timestampFile, time());
|
||||
|
||||
run_hook('cronjob_end'); #HOOK
|
||||
echo "Cron job finished and completed successfully.\n";
|
@ -23,7 +23,7 @@ run_hook('cronjob_reminder'); #HOOK
|
||||
echo "PHP Time\t" . date('Y-m-d H:i:s') . "\n";
|
||||
$res = ORM::raw_execute('SELECT NOW() AS WAKTU;');
|
||||
$statement = ORM::get_last_statement();
|
||||
$rows = array();
|
||||
$rows = [];
|
||||
while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
|
||||
echo "MYSQL Time\t" . $row['WAKTU'] . "\n";
|
||||
}
|
||||
@ -39,22 +39,52 @@ foreach ($d as $ds) {
|
||||
$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();
|
||||
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 {
|
||||
// Postpaid price from field
|
||||
$add_inv = User::getAttribute("Invoice", $ds['customer_id']);
|
||||
if (empty($add_inv) or $add_inv == 0) {
|
||||
$price = $p['price'];
|
||||
} else {
|
||||
$price = $add_inv;
|
||||
}
|
||||
} else {
|
||||
$price = $p['price'];
|
||||
}
|
||||
if ($ds['expiration'] == $day7) {
|
||||
echo Message::sendPackageNotification($c, $p['name_plan'], $price, Lang::getNotifText('reminder_7_day'), $config['user_notification_reminder']) . "\n";
|
||||
} else if ($ds['expiration'] == $day3) {
|
||||
echo Message::sendPackageNotification($c, $p['name_plan'], $price, Lang::getNotifText('reminder_3_day'), $config['user_notification_reminder']) . "\n";
|
||||
} else if ($ds['expiration'] == $day1) {
|
||||
echo Message::sendPackageNotification($c, $p['name_plan'], $price, Lang::getNotifText('reminder_1_day'), $config['user_notification_reminder']) . "\n";
|
||||
if ($ds['expiration'] == $day7 && $config['notification_reminder_7days'] !== 'no') {
|
||||
try {
|
||||
echo Message::sendPackageNotification(
|
||||
$c,
|
||||
$p['name_plan'],
|
||||
$price,
|
||||
Message::getMessageType($p['type'], Lang::getNotifText('reminder_7_day')),
|
||||
$config['user_notification_reminder']
|
||||
) . "\n";
|
||||
} catch (Exception $e) {
|
||||
sendTelegram("Cron Reminder failed to send 7-day reminder to " . $ds['username'] . " Error: " . $e->getMessage());
|
||||
}
|
||||
} else if ($ds['expiration'] == $day3 && $config['notification_reminder_3days'] !== 'no') {
|
||||
try {
|
||||
echo Message::sendPackageNotification(
|
||||
$c,
|
||||
$p['name_plan'],
|
||||
$price,
|
||||
Message::getMessageType($p['type'], Lang::getNotifText('reminder_3_day')),
|
||||
$config['user_notification_reminder']
|
||||
) . "\n";
|
||||
} catch (Exception $e) {
|
||||
sendTelegram("Cron Reminder failed to send 3-day reminder to " . $ds['username'] . " Error: " . $e->getMessage());
|
||||
}
|
||||
} else if ($ds['expiration'] == $day1 && $config['notification_reminder_1day'] !== 'no') {
|
||||
try {
|
||||
echo Message::sendPackageNotification(
|
||||
$c,
|
||||
$p['name_plan'],
|
||||
$price,
|
||||
Message::getMessageType($p['type'], Lang::getNotifText('reminder_1_day')),
|
||||
$config['user_notification_reminder']
|
||||
) . "\n";
|
||||
} catch (Exception $e) {
|
||||
sendTelegram("Cron Reminder failed to send 1-day reminder to " . $ds['username'] . " Error: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,10 +33,38 @@ class MikrotikHotspot
|
||||
{
|
||||
$mikrotik = $this->info($plan['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$isExp = ORM::for_table('tbl_plans')->select("id")->where('plan_expired', $plan['id'])->find_one();
|
||||
$this->removeHotspotUser($client, $customer['username']);
|
||||
if ($isExp){
|
||||
$this->removeHotspotActiveUser($client, $customer['username']);
|
||||
}
|
||||
$this->addHotspotUser($client, $plan, $customer);
|
||||
}
|
||||
|
||||
function sync_customer($customer, $plan)
|
||||
{
|
||||
$mikrotik = $this->info($plan['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$t = ORM::for_table('tbl_user_recharges')->where('username', $customer['username'])->where('status', 'on')->find_one();
|
||||
if ($t) {
|
||||
$printRequest = new RouterOS\Request('/ip/hotspot/user/print');
|
||||
$printRequest->setArgument('.proplist', '.id,limit-uptime,limit-bytes-total');
|
||||
$printRequest->setQuery(RouterOS\Query::where('name', $customer['username']));
|
||||
$userInfo = $client->sendSync($printRequest);
|
||||
$id = $userInfo->getProperty('.id');
|
||||
$uptime = $userInfo->getProperty('limit-uptime');
|
||||
$data = $userInfo->getProperty('limit-bytes-total');
|
||||
if (!empty($id) && (!empty($uptime) || !empty($data))) {
|
||||
$setRequest = new RouterOS\Request('/ip/hotspot/user/set');
|
||||
$setRequest->setArgument('numbers', $id);
|
||||
$setRequest->setArgument('profile', $t['namebp']);
|
||||
$client->sendSync($setRequest);
|
||||
} else {
|
||||
$this->add_customer($customer, $plan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function remove_customer($customer, $plan)
|
||||
{
|
||||
@ -94,6 +122,9 @@ class MikrotikHotspot
|
||||
if (!empty(trim($bw['burst']))) {
|
||||
$rate .= ' ' . $bw['burst'];
|
||||
}
|
||||
if ($bw['rate_up'] == '0' || $bw['rate_down'] == '0') {
|
||||
$rate = '';
|
||||
}
|
||||
$addRequest = new RouterOS\Request('/ip/hotspot/user/profile/add');
|
||||
$client->sendSync(
|
||||
$addRequest
|
||||
@ -109,9 +140,10 @@ class MikrotikHotspot
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$printRequest = new RouterOS\Request(
|
||||
'/ip hotspot active print',
|
||||
RouterOS\Query::where('name', $customer['username'])
|
||||
RouterOS\Query::where('user', $customer['username'])
|
||||
);
|
||||
return $client->sendSync($printRequest)->getProperty('.id');
|
||||
$id = $client->sendSync($printRequest)->getProperty('.id');
|
||||
return $id;
|
||||
}
|
||||
|
||||
function connect_customer($customer, $ip, $mac_address, $router_name)
|
||||
@ -173,6 +205,9 @@ class MikrotikHotspot
|
||||
if (!empty(trim($bw['burst']))) {
|
||||
$rate .= ' ' . $bw['burst'];
|
||||
}
|
||||
if ($bw['rate_up'] == '0' || $bw['rate_down'] == '0') {
|
||||
$rate = '';
|
||||
}
|
||||
$setRequest = new RouterOS\Request('/ip/hotspot/user/profile/set');
|
||||
$client->sendSync(
|
||||
$setRequest
|
||||
@ -210,7 +245,7 @@ class MikrotikHotspot
|
||||
function getClient($ip, $user, $pass)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
return null;
|
||||
}
|
||||
$iport = explode(":", $ip);
|
||||
@ -220,7 +255,7 @@ class MikrotikHotspot
|
||||
function removeHotspotUser($client, $username)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
return null;
|
||||
}
|
||||
$printRequest = new RouterOS\Request(
|
||||
@ -238,7 +273,7 @@ class MikrotikHotspot
|
||||
function addHotspotUser($client, $plan, $customer)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
return null;
|
||||
}
|
||||
$addRequest = new RouterOS\Request('/ip/hotspot/user/add');
|
||||
@ -306,7 +341,7 @@ class MikrotikHotspot
|
||||
function setHotspotUser($client, $user, $pass)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
return null;
|
||||
}
|
||||
$printRequest = new RouterOS\Request('/ip/hotspot/user/print');
|
||||
@ -323,7 +358,7 @@ class MikrotikHotspot
|
||||
function setHotspotUserPackage($client, $username, $plan_name)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
return null;
|
||||
}
|
||||
$printRequest = new RouterOS\Request('/ip/hotspot/user/print');
|
||||
@ -340,7 +375,7 @@ class MikrotikHotspot
|
||||
function removeHotspotActiveUser($client, $username)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
return null;
|
||||
}
|
||||
$onlineRequest = new RouterOS\Request('/ip/hotspot/active/print');
|
||||
@ -356,7 +391,7 @@ class MikrotikHotspot
|
||||
function getIpHotspotUser($client, $username)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
return null;
|
||||
}
|
||||
$printRequest = new RouterOS\Request(
|
||||
|
@ -33,9 +33,10 @@ class MikrotikPppoe
|
||||
$mikrotik = $this->info($plan['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$cid = self::getIdByCustomer($customer, $client);
|
||||
$isExp = ORM::for_table('tbl_plans')->select("id")->where('plan_expired', $plan['id'])->find_one();
|
||||
if (empty($cid)) {
|
||||
//customer not exists, add it
|
||||
$this->addPpoeUser($client, $plan, $customer);
|
||||
$this->addPpoeUser($client, $plan, $customer, $isExp);
|
||||
}else{
|
||||
$setRequest = new RouterOS\Request('/ppp/secret/set');
|
||||
$setRequest->setArgument('numbers', $cid);
|
||||
@ -49,14 +50,24 @@ class MikrotikPppoe
|
||||
} else {
|
||||
$setRequest->setArgument('name', $customer['username']);
|
||||
}
|
||||
if (!empty($customer['pppoe_ip'])) {
|
||||
$setRequest->setArgument('local-address', $customer['pppoe_ip']);
|
||||
}else{
|
||||
$setRequest->setArgument('local-address', '0.0.0.0');
|
||||
}
|
||||
$unsetIP = false;
|
||||
if (!empty($customer['pppoe_ip']) && !$isExp){
|
||||
$setRequest->setArgument('remote-address', $customer['pppoe_ip']);
|
||||
} else {
|
||||
$unsetIP = true;
|
||||
}
|
||||
$setRequest->setArgument('profile', $plan['name_plan']);
|
||||
$setRequest->setArgument('comment', $customer['fullname'] . ' | ' . $customer['email'] . ' | ' . implode(', ', User::getBillNames($customer['id'])));
|
||||
$client->sendSync($setRequest);
|
||||
|
||||
if($unsetIP){
|
||||
$unsetRequest = new RouterOS\Request('/ppp/secret/unset');
|
||||
$unsetRequest->setArgument('.id', $cid);
|
||||
$unsetRequest->setArgument('value-name','remote-address');
|
||||
$client->sendSync($unsetRequest);
|
||||
}
|
||||
|
||||
|
||||
//disconnect then
|
||||
if(isset($isChangePlan) && $isChangePlan){
|
||||
$this->removePpoeActive($client, $customer['username']);
|
||||
@ -67,6 +78,11 @@ class MikrotikPppoe
|
||||
}
|
||||
}
|
||||
|
||||
function sync_customer($customer, $plan)
|
||||
{
|
||||
$this->add_customer($customer, $plan);
|
||||
}
|
||||
|
||||
function remove_customer($customer, $plan)
|
||||
{
|
||||
$mikrotik = $this->info($plan['routers']);
|
||||
@ -133,6 +149,9 @@ class MikrotikPppoe
|
||||
if(!empty(trim($bw['burst']))){
|
||||
$rate .= ' '.$bw['burst'];
|
||||
}
|
||||
if ($bw['rate_up'] == '0' || $bw['rate_down'] == '0') {
|
||||
$rate = '';
|
||||
}
|
||||
$pool = ORM::for_table("tbl_pool")->where("pool_name", $plan['pool'])->find_one();
|
||||
$addRequest = new RouterOS\Request('/ppp/profile/add');
|
||||
$client->sendSync(
|
||||
@ -189,6 +208,9 @@ class MikrotikPppoe
|
||||
if(!empty(trim($bw['burst']))){
|
||||
$rate .= ' '.$bw['burst'];
|
||||
}
|
||||
if ($bw['rate_up'] == '0' || $bw['rate_down'] == '0') {
|
||||
$rate = '';
|
||||
}
|
||||
$pool = ORM::for_table("tbl_pool")->where("pool_name", $new_plan['pool'])->find_one();
|
||||
$setRequest = new RouterOS\Request('/ppp/profile/set');
|
||||
$client->sendSync(
|
||||
@ -222,7 +244,7 @@ class MikrotikPppoe
|
||||
|
||||
function add_pool($pool){
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
return null;
|
||||
}
|
||||
$mikrotik = $this->info($pool['routers']);
|
||||
@ -237,7 +259,7 @@ class MikrotikPppoe
|
||||
|
||||
function update_pool($old_pool, $new_pool){
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
return null;
|
||||
}
|
||||
$mikrotik = $this->info($new_pool['routers']);
|
||||
@ -262,7 +284,7 @@ class MikrotikPppoe
|
||||
|
||||
function remove_pool($pool){
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
return null;
|
||||
}
|
||||
$mikrotik = $this->info($pool['routers']);
|
||||
@ -286,9 +308,17 @@ class MikrotikPppoe
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$printRequest = new RouterOS\Request(
|
||||
'/ppp active print',
|
||||
RouterOS\Query::where('user', $customer['username'])
|
||||
RouterOS\Query::where('name', $customer['username'])
|
||||
);
|
||||
return $client->sendSync($printRequest)->getProperty('.id');
|
||||
$id = $client->sendSync($printRequest)->getProperty('.id');
|
||||
if(empty($id)){
|
||||
$printRequest = new RouterOS\Request(
|
||||
'/ppp active print',
|
||||
RouterOS\Query::where('name', $customer['pppoe_username'])
|
||||
);
|
||||
$id = $client->sendSync($printRequest)->getProperty('.id');
|
||||
}
|
||||
return $id;
|
||||
}
|
||||
|
||||
function info($name)
|
||||
@ -299,7 +329,7 @@ class MikrotikPppoe
|
||||
function getClient($ip, $user, $pass)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
return null;
|
||||
}
|
||||
$iport = explode(":", $ip);
|
||||
@ -309,7 +339,7 @@ class MikrotikPppoe
|
||||
function removePpoeUser($client, $username)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
return null;
|
||||
}
|
||||
$printRequest = new RouterOS\Request('/ppp/secret/print');
|
||||
@ -321,7 +351,7 @@ class MikrotikPppoe
|
||||
$client->sendSync($removeRequest);
|
||||
}
|
||||
|
||||
function addPpoeUser($client, $plan, $customer)
|
||||
function addPpoeUser($client, $plan, $customer, $isExp = false)
|
||||
{
|
||||
$setRequest = new RouterOS\Request('/ppp/secret/add');
|
||||
$setRequest->setArgument('service', 'pppoe');
|
||||
@ -337,8 +367,8 @@ class MikrotikPppoe
|
||||
} else {
|
||||
$setRequest->setArgument('name', $customer['username']);
|
||||
}
|
||||
if (!empty($customer['pppoe_ip'])) {
|
||||
$setRequest->setArgument('local-address', $customer['pppoe_ip']);
|
||||
if (!empty($customer['pppoe_ip']) && !$isExp) {
|
||||
$setRequest->setArgument('remote-address', $customer['pppoe_ip']);
|
||||
}
|
||||
$client->sendSync($setRequest);
|
||||
}
|
||||
@ -346,7 +376,7 @@ class MikrotikPppoe
|
||||
function removePpoeActive($client, $username)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
return null;
|
||||
}
|
||||
$onlineRequest = new RouterOS\Request('/ppp/active/print');
|
||||
@ -362,7 +392,7 @@ class MikrotikPppoe
|
||||
function getIpHotspotUser($client, $username)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
return null;
|
||||
}
|
||||
$printRequest = new RouterOS\Request(
|
||||
@ -375,7 +405,7 @@ class MikrotikPppoe
|
||||
function addIpToAddressList($client, $ip, $listName, $comment = '')
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
return null;
|
||||
}
|
||||
$addRequest = new RouterOS\Request('/ip/firewall/address-list/add');
|
||||
@ -390,7 +420,7 @@ class MikrotikPppoe
|
||||
function removeIpFromAddressList($client, $ip)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
if ($_app_stage == 'Demo') {
|
||||
return null;
|
||||
}
|
||||
$printRequest = new RouterOS\Request(
|
||||
|
512
system/devices/MikrotikVpn.php
Normal file
512
system/devices/MikrotikVpn.php
Normal file
@ -0,0 +1,512 @@
|
||||
<?php
|
||||
|
||||
use PEAR2\Net\RouterOS;
|
||||
|
||||
class MikrotikVpn
|
||||
{
|
||||
|
||||
function description()
|
||||
{
|
||||
return [
|
||||
'title' => 'Mikrotik Vpn',
|
||||
'description' => 'To handle connection between PHPNuxBill with Mikrotik VPN',
|
||||
'author' => 'agstr',
|
||||
'url' => [
|
||||
'Github' => 'https://github.com/agstrxyz',
|
||||
'Telegram' => 'https://t.me/agstrxyz',
|
||||
'Youtube' => 'https://www.youtube.com/@agstrxyz',
|
||||
'Donate' => 'https://paypal.me/ibnux'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
function add_customer($customer, $plan)
|
||||
{
|
||||
global $isChangePlan;
|
||||
$mikrotik = $this->info($plan['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$cid = self::getIdByCustomer($customer, $client);
|
||||
if (empty($cid)) {
|
||||
$this->addVpnUser($client, $plan, $customer);
|
||||
} else {
|
||||
$setRequest = new RouterOS\Request('/ppp/secret/set');
|
||||
$setRequest->setArgument('numbers', $cid);
|
||||
if (!empty($customer['pppoe_password'])) {
|
||||
$setRequest->setArgument('password', $customer['pppoe_password']);
|
||||
} else {
|
||||
$setRequest->setArgument('password', $customer['password']);
|
||||
}
|
||||
if (!empty($customer['pppoe_username'])) {
|
||||
$setRequest->setArgument('name', $customer['pppoe_username']);
|
||||
} else {
|
||||
$setRequest->setArgument('name', $customer['username']);
|
||||
}
|
||||
if (!empty($customer['pppoe_ip'])) {
|
||||
$setRequest->setArgument('remote-address', $customer['pppoe_ip']);
|
||||
} else {
|
||||
$setRequest->setArgument('remote-address', '0.0.0.0');
|
||||
}
|
||||
$setRequest->setArgument('profile', $plan['name_plan']);
|
||||
$setRequest->setArgument('comment', $customer['fullname'] . ' | ' . $customer['email'] . ' | ' . implode(', ', User::getBillNames($customer['id'])));
|
||||
$client->sendSync($setRequest);
|
||||
if (isset($isChangePlan) && $isChangePlan) {
|
||||
$this->removeVpnActive($client, $customer['username']);
|
||||
if (!empty($customer['pppoe_username'])) {
|
||||
$this->removeVpnActive($client, $customer['pppoe_username']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sync_customer($customer, $plan)
|
||||
{
|
||||
$this->add_customer($customer, $plan);
|
||||
}
|
||||
|
||||
function remove_customer($customer, $plan)
|
||||
{
|
||||
$mikrotik = $this->info($plan['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
if (!empty($plan['plan_expired'])) {
|
||||
$p = ORM::for_table("tbl_plans")->find_one($plan['plan_expired']);
|
||||
if ($p) {
|
||||
$this->add_customer($customer, $p);
|
||||
$this->removeVpnActive($client, $customer['username']);
|
||||
if (!empty($customer['pppoe_username'])) {
|
||||
$this->removeVpnActive($client, $customer['pppoe_username']);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->removeVpnUser($client, $customer['username'], $customer['id']);
|
||||
if (!empty($customer['pppoe_username'])) {
|
||||
$this->removeVpnUser($client, $customer['pppoe_username'], $customer['id']);
|
||||
}
|
||||
$this->removeVpnActive($client, $customer['username']);
|
||||
if (!empty($customer['pppoe_username'])) {
|
||||
$this->removeVpnActive($client, $customer['pppoe_username']);
|
||||
}
|
||||
}
|
||||
|
||||
public function change_username($plan, $from, $to)
|
||||
{
|
||||
$mikrotik = $this->info($plan['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$printRequest = new RouterOS\Request('/ppp/secret/print');
|
||||
$printRequest->setQuery(RouterOS\Query::where('name', $from));
|
||||
$cid = $client->sendSync($printRequest)->getProperty('.id');
|
||||
if (!empty($cid)) {
|
||||
$setRequest = new RouterOS\Request('/ppp/secret/set');
|
||||
$setRequest->setArgument('numbers', $cid);
|
||||
$setRequest->setArgument('name', $to);
|
||||
$client->sendSync($setRequest);
|
||||
$this->removeVpnActive($client, $from);
|
||||
}
|
||||
}
|
||||
|
||||
function add_plan($plan)
|
||||
{
|
||||
$mikrotik = $this->info($plan['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
|
||||
|
||||
$bw = ORM::for_table("tbl_bandwidth")->find_one($plan['id_bw']);
|
||||
if ($bw['rate_down_unit'] == 'Kbps') {
|
||||
$unitdown = 'K';
|
||||
} else {
|
||||
$unitdown = 'M';
|
||||
}
|
||||
if ($bw['rate_up_unit'] == 'Kbps') {
|
||||
$unitup = 'K';
|
||||
} else {
|
||||
$unitup = 'M';
|
||||
}
|
||||
$rate = $bw['rate_up'] . $unitup . "/" . $bw['rate_down'] . $unitdown;
|
||||
if (!empty(trim($bw['burst']))) {
|
||||
$rate .= ' ' . $bw['burst'];
|
||||
}
|
||||
$pool = ORM::for_table("tbl_pool")->where("pool_name", $plan['pool'])->find_one();
|
||||
$addRequest = new RouterOS\Request('/ppp/profile/add');
|
||||
$client->sendSync(
|
||||
$addRequest
|
||||
->setArgument('name', $plan['name_plan'])
|
||||
->setArgument('local-address', (!empty($pool['local_ip'])) ? $pool['local_ip'] : $pool['pool_name'])
|
||||
->setArgument('remote-address', $pool['pool_name'])
|
||||
->setArgument('rate-limit', $rate)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function getIdByCustomer($customer, $client)
|
||||
{
|
||||
$printRequest = new RouterOS\Request('/ppp/secret/print');
|
||||
$printRequest->setQuery(RouterOS\Query::where('name', $customer['username']));
|
||||
$id = $client->sendSync($printRequest)->getProperty('.id');
|
||||
if (empty($id)) {
|
||||
if (!empty($customer['pppoe_username'])) {
|
||||
$printRequest = new RouterOS\Request('/ppp/secret/print');
|
||||
$printRequest->setQuery(RouterOS\Query::where('name', $customer['pppoe_username']));
|
||||
$id = $client->sendSync($printRequest)->getProperty('.id');
|
||||
}
|
||||
}
|
||||
return $id;
|
||||
}
|
||||
|
||||
function update_plan($old_name, $new_plan)
|
||||
{
|
||||
$mikrotik = $this->info($new_plan['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
|
||||
$printRequest = new RouterOS\Request(
|
||||
'/ppp profile print .proplist=.id',
|
||||
RouterOS\Query::where('name', $old_name['name_plan'])
|
||||
);
|
||||
$profileID = $client->sendSync($printRequest)->getProperty('.id');
|
||||
if (empty($profileID)) {
|
||||
$this->add_plan($new_plan);
|
||||
} else {
|
||||
$bw = ORM::for_table("tbl_bandwidth")->find_one($new_plan['id_bw']);
|
||||
if ($bw['rate_down_unit'] == 'Kbps') {
|
||||
$unitdown = 'K';
|
||||
} else {
|
||||
$unitdown = 'M';
|
||||
}
|
||||
if ($bw['rate_up_unit'] == 'Kbps') {
|
||||
$unitup = 'K';
|
||||
} else {
|
||||
$unitup = 'M';
|
||||
}
|
||||
$rate = $bw['rate_up'] . $unitup . "/" . $bw['rate_down'] . $unitdown;
|
||||
if (!empty(trim($bw['burst']))) {
|
||||
$rate .= ' ' . $bw['burst'];
|
||||
}
|
||||
$pool = ORM::for_table("tbl_pool")->where("pool_name", $new_plan['pool'])->find_one();
|
||||
$setRequest = new RouterOS\Request('/ppp/profile/set');
|
||||
$client->sendSync(
|
||||
$setRequest
|
||||
->setArgument('numbers', $profileID)
|
||||
->setArgument('local-address', (!empty($pool['local_ip'])) ? $pool['local_ip'] : $pool['pool_name'])
|
||||
->setArgument('remote-address', $pool['pool_name'])
|
||||
->setArgument('rate-limit', $rate)
|
||||
->setArgument('on-up', $new_plan['on_login'])
|
||||
->setArgument('on-down', $new_plan['on_logout'])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function remove_plan($plan)
|
||||
{
|
||||
$mikrotik = $this->info($plan['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$printRequest = new RouterOS\Request(
|
||||
'/ppp profile print .proplist=.id',
|
||||
RouterOS\Query::where('name', $plan['name_plan'])
|
||||
);
|
||||
$profileID = $client->sendSync($printRequest)->getProperty('.id');
|
||||
|
||||
$removeRequest = new RouterOS\Request('/ppp/profile/remove');
|
||||
$client->sendSync(
|
||||
$removeRequest
|
||||
->setArgument('numbers', $profileID)
|
||||
);
|
||||
}
|
||||
|
||||
function add_pool($pool)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
return null;
|
||||
}
|
||||
$mikrotik = $this->info($pool['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$addRequest = new RouterOS\Request('/ip/pool/add');
|
||||
$client->sendSync(
|
||||
$addRequest
|
||||
->setArgument('name', $pool['pool_name'])
|
||||
->setArgument('ranges', $pool['range_ip'])
|
||||
);
|
||||
}
|
||||
|
||||
function update_pool($old_pool, $new_pool)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
return null;
|
||||
}
|
||||
$mikrotik = $this->info($new_pool['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$printRequest = new RouterOS\Request(
|
||||
'/ip pool print .proplist=.id',
|
||||
RouterOS\Query::where('name', $old_pool['pool_name'])
|
||||
);
|
||||
$poolID = $client->sendSync($printRequest)->getProperty('.id');
|
||||
if (empty($poolID)) {
|
||||
$this->add_pool($new_pool);
|
||||
} else {
|
||||
$setRequest = new RouterOS\Request('/ip/pool/set');
|
||||
$client->sendSync(
|
||||
$setRequest
|
||||
->setArgument('numbers', $poolID)
|
||||
->setArgument('name', $new_pool['pool_name'])
|
||||
->setArgument('ranges', $new_pool['range_ip'])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function remove_pool($pool)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
return null;
|
||||
}
|
||||
$mikrotik = $this->info($pool['routers']);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$printRequest = new RouterOS\Request(
|
||||
'/ip pool print .proplist=.id',
|
||||
RouterOS\Query::where('name', $pool['pool_name'])
|
||||
);
|
||||
$poolID = $client->sendSync($printRequest)->getProperty('.id');
|
||||
$removeRequest = new RouterOS\Request('/ip/pool/remove');
|
||||
$client->sendSync(
|
||||
$removeRequest
|
||||
->setArgument('numbers', $poolID)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function online_customer($customer, $router_name)
|
||||
{
|
||||
$mikrotik = $this->info($router_name);
|
||||
$client = $this->getClient($mikrotik['ip_address'], $mikrotik['username'], $mikrotik['password']);
|
||||
$printRequest = new RouterOS\Request(
|
||||
'/ppp active print',
|
||||
RouterOS\Query::where('user', $customer['username'])
|
||||
);
|
||||
return $client->sendSync($printRequest)->getProperty('.id');
|
||||
}
|
||||
|
||||
function info($name)
|
||||
{
|
||||
return ORM::for_table('tbl_routers')->where('name', $name)->find_one();
|
||||
}
|
||||
|
||||
function getClient($ip, $user, $pass)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
return null;
|
||||
}
|
||||
$iport = explode(":", $ip);
|
||||
return new RouterOS\Client($iport[0], $user, $pass, ($iport[1]) ? $iport[1] : null);
|
||||
}
|
||||
|
||||
function removeVpnUser($client, $username, $cstid)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
return null;
|
||||
}
|
||||
$printRequest = new RouterOS\Request('/ppp/secret/print');
|
||||
//$printRequest->setArgument('.proplist', '.id');
|
||||
$printRequest->setQuery(RouterOS\Query::where('name', $username));
|
||||
$id = $client->sendSync($printRequest)->getProperty('.id');
|
||||
$removeRequest = new RouterOS\Request('/ppp/secret/remove');
|
||||
$removeRequest->setArgument('numbers', $id);
|
||||
$client->sendSync($removeRequest);
|
||||
$this->rmNat($client, $cstid);
|
||||
}
|
||||
|
||||
function addVpnUser($client, $plan, $customer)
|
||||
{
|
||||
$setRequest = new RouterOS\Request('/ppp/secret/add');
|
||||
$setRequest->setArgument('service', 'any');
|
||||
$setRequest->setArgument('profile', $plan['name_plan']);
|
||||
$setRequest->setArgument('comment', $customer['fullname'] . ' | ' . $customer['email'] . ' | ' . implode(', ', User::getBillNames($customer['id'])));
|
||||
if (!empty($customer['pppoe_password'])) {
|
||||
$setRequest->setArgument('password', $customer['pppoe_password']);
|
||||
} else {
|
||||
$setRequest->setArgument('password', $customer['password']);
|
||||
}
|
||||
if (!empty($customer['pppoe_username'])) {
|
||||
$setRequest->setArgument('name', $customer['pppoe_username']);
|
||||
} else {
|
||||
$setRequest->setArgument('name', $customer['username']);
|
||||
}
|
||||
if (!empty($customer['pppoe_ip'])) {
|
||||
$ips = $customer['pppoe_ip'];
|
||||
$setRequest->setArgument('remote-address', $customer['pppoe_ip']);
|
||||
} else {
|
||||
$ips = $this->checkIpAddr($plan['pool'], $customer['id']);
|
||||
$setRequest->setArgument('remote-address', $ips);
|
||||
}
|
||||
$this->addNat($client, $plan, $customer, $ips);
|
||||
$client->sendSync($setRequest);
|
||||
$customer->service_type = 'VPN';
|
||||
$customer->pppoe_ip = $ips;
|
||||
$customer->save();
|
||||
}
|
||||
|
||||
function removeVpnActive($client, $username)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
return null;
|
||||
}
|
||||
$onlineRequest = new RouterOS\Request('/ppp/active/print');
|
||||
$onlineRequest->setArgument('.proplist', '.id');
|
||||
$onlineRequest->setQuery(RouterOS\Query::where('name', $username));
|
||||
$id = $client->sendSync($onlineRequest)->getProperty('.id');
|
||||
|
||||
$removeRequest = new RouterOS\Request('/ppp/active/remove');
|
||||
$removeRequest->setArgument('numbers', $id);
|
||||
$client->sendSync($removeRequest);
|
||||
}
|
||||
|
||||
|
||||
function addIpToAddressList($client, $ip, $listName, $comment = '')
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
return null;
|
||||
}
|
||||
$addRequest = new RouterOS\Request('/ip/firewall/address-list/add');
|
||||
$client->sendSync(
|
||||
$addRequest
|
||||
->setArgument('address', $ip)
|
||||
->setArgument('comment', $comment)
|
||||
->setArgument('list', $listName)
|
||||
);
|
||||
}
|
||||
|
||||
function removeIpFromAddressList($client, $ip)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
return null;
|
||||
}
|
||||
$printRequest = new RouterOS\Request(
|
||||
'/ip firewall address-list print .proplist=.id',
|
||||
RouterOS\Query::where('address', $ip)
|
||||
);
|
||||
$id = $client->sendSync($printRequest)->getProperty('.id');
|
||||
$removeRequest = new RouterOS\Request('/ip/firewall/address-list/remove');
|
||||
$client->sendSync(
|
||||
$removeRequest
|
||||
->setArgument('numbers', $id)
|
||||
);
|
||||
}
|
||||
|
||||
function addNat($client, $plan, $cust, $ips)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
return null;
|
||||
}
|
||||
$this->checkPort($cust['id'], 'Winbox', $plan['routers']);
|
||||
$this->checkPort($cust['id'], 'Api', $plan['routers']);
|
||||
$this->checkPort($cust['id'], 'Web', $plan['routers']);
|
||||
$tcf = ORM::for_table('tbl_customers_fields')
|
||||
->where('customer_id', $cust['id'])
|
||||
->find_many();
|
||||
$ip = ORM::for_table('tbl_port_pool')
|
||||
->where('routers', $plan['routers'])
|
||||
->find_one();
|
||||
foreach ($tcf as $cf) {
|
||||
$dst = $cf['field_value'];
|
||||
$cmnt = $cf['field_name'];
|
||||
if ($cmnt == 'Winbox') {
|
||||
$tp = '8291';
|
||||
}
|
||||
if ($cmnt == 'Web') {
|
||||
$tp = '80';
|
||||
}
|
||||
if ($cmnt == 'Api') {
|
||||
$tp = '8728';
|
||||
}
|
||||
if ($cmnt == 'Winbox' || $cmnt == 'Web' || $cmnt == 'Api') {
|
||||
$addRequest = new RouterOS\Request('/ip/firewall/nat/add');
|
||||
$client->sendSync(
|
||||
$addRequest
|
||||
->setArgument('chain', 'dstnat')
|
||||
->setArgument('protocol', 'tcp')
|
||||
->setArgument('dst-port', $dst)
|
||||
->setArgument('action', 'dst-nat')
|
||||
->setArgument('to-addresses', $ips)
|
||||
->setArgument('to-ports', $tp)
|
||||
->setArgument('dst-address', $ip['public_ip'])
|
||||
->setArgument('comment', $cmnt . ' || ' . $cust['username'])
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function rmNat($client, $cstid)
|
||||
{
|
||||
global $_app_stage;
|
||||
if ($_app_stage == 'demo') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$cst = ORM::for_table('tbl_customers')->find_one($cstid);
|
||||
$printRequest = new RouterOS\Request('/ip/firewall/nat/print');
|
||||
$printRequest->setQuery(RouterOS\Query::where('to-addresses', $cst['pppoe_ip']));
|
||||
$nats = $client->sendSync($printRequest);
|
||||
foreach ($nats as $nat) {
|
||||
$id = $client->sendSync($printRequest)->getProperty('.id');
|
||||
$removeRequest = new RouterOS\Request('/ip/firewall/nat/remove');
|
||||
$removeRequest->setArgument('numbers', $id);
|
||||
$client->sendSync($removeRequest);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function checkPort($id, $portn, $router)
|
||||
{
|
||||
$tcf = ORM::for_table('tbl_customers_fields')
|
||||
->where('customer_id', $id)
|
||||
->where('field_name', $portn)
|
||||
->find_one();
|
||||
$ports = ORM::for_table('tbl_port_pool')
|
||||
->where('routers', $router)
|
||||
->find_one();
|
||||
$port = explode('-', $ports['range_port']);
|
||||
if (empty($tcf) && !empty($ports)) {
|
||||
repeat:
|
||||
$portr = rand($port['0'], $port['1']);
|
||||
if (ORM::for_table('tbl_customers_fields')->where('field_value', $portr)->find_one()) {
|
||||
if ($portr == $port['1']) {
|
||||
return;
|
||||
}
|
||||
goto repeat;
|
||||
}
|
||||
$cf = ORM::for_table('tbl_customers_fields')->create();
|
||||
$cf->customer_id = $id;
|
||||
$cf->field_name = $portn;
|
||||
$cf->field_value = $portr;
|
||||
$cf->save();
|
||||
}
|
||||
}
|
||||
|
||||
function checkIpAddr($pname, $id)
|
||||
{
|
||||
$c = ORM::for_table('tbl_customers')->find_one($id);
|
||||
$ipp = ORM::for_table('tbl_pool')
|
||||
->where('pool_name', $pname)
|
||||
->find_one();
|
||||
$ip_r = explode('-', $ipp['range_ip']);
|
||||
$ip_1 = explode('.', $ip_r['0']);
|
||||
$ip_2 = explode('.', $ip_r['1']);
|
||||
repeat:
|
||||
$ipt = rand($ip_1['3'], $ip_2['3']);
|
||||
$ips = $ip_1['0'] . '.' . $ip_1['1'] . '.' . $ip_1['2'] . '.' . $ipt;
|
||||
if (empty($c['pppoe_ip'])) {
|
||||
if (ORM::for_table('tbl_customers')->where('pppoe_ip', $ips)->find_one()) {
|
||||
if ($ip_2['3'] == $ipt) {
|
||||
return;
|
||||
}
|
||||
goto repeat;
|
||||
}
|
||||
return $ips;
|
||||
}
|
||||
}
|
||||
}
|
@ -50,18 +50,42 @@ class Radius
|
||||
|
||||
if ($p['validity_unit'] == 'Months') {
|
||||
$date_exp = date("Y-m-d", strtotime('+' . $p['validity'] . ' month'));
|
||||
$time = date("H:i:s");
|
||||
} 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");
|
||||
$current_date = new DateTime($date_only);
|
||||
$exp_date = clone $current_date;
|
||||
$exp_date->modify('first day of next month');
|
||||
$exp_date->setDate($exp_date->format('Y'), $exp_date->format('m'), $day_exp);
|
||||
|
||||
$min_days = 7 * $p['validity'];
|
||||
$max_days = 35 * $p['validity'];
|
||||
|
||||
$days_until_exp = $exp_date->diff($current_date)->days;
|
||||
|
||||
// If less than min_days away, move to the next period
|
||||
while ($days_until_exp < $min_days) {
|
||||
$exp_date->modify('+1 month');
|
||||
$days_until_exp = $exp_date->diff($current_date)->days;
|
||||
}
|
||||
|
||||
// If more than max_days away, move to the previous period
|
||||
while ($days_until_exp > $max_days) {
|
||||
$exp_date->modify('-1 month');
|
||||
$days_until_exp = $exp_date->diff($current_date)->days;
|
||||
}
|
||||
|
||||
// Final check to ensure we're not less than min_days or in the past
|
||||
if ($days_until_exp < $min_days || $exp_date <= $current_date) {
|
||||
$exp_date->modify('+1 month');
|
||||
}
|
||||
|
||||
// Adjust for multiple periods
|
||||
if ($p['validity'] > 1) {
|
||||
$exp_date->modify('+' . ($p['validity'] - 1) . ' months');
|
||||
}
|
||||
|
||||
$date_exp = $exp_date->format('Y-m-d');
|
||||
$time = "23:59:59";
|
||||
} else if ($p['validity_unit'] == 'Days') {
|
||||
$datetime = explode(' ', date("Y-m-d H:i:s", strtotime('+' . $p['validity'] . ' day')));
|
||||
$date_exp = $datetime[0];
|
||||
@ -80,6 +104,14 @@ class Radius
|
||||
$this->customerAddPlan($customer, $plan, $date_exp . ' ' . $time);
|
||||
}
|
||||
}
|
||||
|
||||
function sync_customer($customer, $plan)
|
||||
{
|
||||
$t = ORM::for_table('tbl_user_recharges')->where('username', $customer['username'])->where('status', 'on')->findOne();
|
||||
$date_exp = $t['expiration'];
|
||||
$time = $t['time'];
|
||||
$this->customerAddPlan($customer, $plan, $date_exp . ' ' . $time);
|
||||
}
|
||||
|
||||
function remove_customer($customer, $plan)
|
||||
{
|
||||
@ -341,12 +373,11 @@ class Radius
|
||||
// expired user
|
||||
if ($expired != '') {
|
||||
//extend session time only if the plan are the same
|
||||
if ($plan['plan_id'] == $p['plan_id'] && $config['extend_expiry'] != 'no') {
|
||||
// session timeout [it reset everyday, am still making my research] we can use it for something like 1H/Day - since it reset daily, and Max-All-Session clear everything
|
||||
//$this->upsertCustomer($customer['username'], 'Session-Timeout', 3600); // 3600 = 1 hour
|
||||
$this->upsertCustomer($customer['username'], 'Max-All-Session', strtotime($expired) - time());
|
||||
$this->upsertCustomer($customer['username'], 'Expiration', date('d M Y H:i:s', strtotime($expired)));
|
||||
}
|
||||
// session timeout [it reset everyday, am still making my research] we can use it for something like 1H/Day - since it reset daily, and Max-All-Session clear everything
|
||||
//$this->upsertCustomer($customer['username'], 'Session-Timeout', 3600); // 3600 = 1 hour
|
||||
$this->upsertCustomer($customer['username'], 'Max-All-Session', strtotime($expired) - time());
|
||||
$this->upsertCustomer($customer['username'], 'Expiration', date('d M Y H:i:s', strtotime($expired)));
|
||||
|
||||
// Mikrotik Spesific
|
||||
$this->upsertCustomer(
|
||||
$customer['username'],
|
||||
@ -372,7 +403,7 @@ class Radius
|
||||
$this->upsertCustomerAttr($customer['username'], 'Framed-IP-Address', '0.0.0.0', ':=');
|
||||
$this->upsertCustomerAttr($customer['username'], 'Framed-IP-Netmask', '255.255.255.0', ':=');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
|
@ -21,6 +21,11 @@ class RadiusRest {
|
||||
function add_customer($customer, $plan)
|
||||
{
|
||||
}
|
||||
|
||||
function sync_customer($customer, $plan)
|
||||
{
|
||||
$this->add_customer($customer, $plan);
|
||||
}
|
||||
|
||||
// Remove Customer to Mikrotik/Device
|
||||
function remove_customer($customer, $plan)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -4,7 +4,7 @@
|
||||
"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 berhadil! 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",
|
||||
@ -13,11 +13,12 @@
|
||||
"Password": "Kata Sandi",
|
||||
"Passwords_does_not_match": "Kata sandi tidak cocok",
|
||||
"Account_already_axist": "Akun telah ada",
|
||||
"Manage": "Mengelola",
|
||||
"Manage": "Kelola",
|
||||
"Submit": "Kirim",
|
||||
"Save_Changes": "Simpan Perubahan",
|
||||
"Cancel": "Batal",
|
||||
"Edit": "Sunting",
|
||||
"Order": "Urutan",
|
||||
"Delete": "Hapus",
|
||||
"Welcome": "Selamat Datang",
|
||||
"Data_Created_Successfully": "Data Berhasil Dibuat",
|
||||
@ -123,7 +124,7 @@
|
||||
"Period_Reports": "Laporan Periode",
|
||||
"All_Transactions": "Semua Transaksi",
|
||||
"Total_Income": "Jumlah Pemasukan",
|
||||
"All_Transactions_at_Date": "Semua transaksi pada ganggal",
|
||||
"All_Transactions_at_Date": "Semua transaksi pada tanggal",
|
||||
"Export_for_Print": "Ekspor untuk cetak",
|
||||
"Print": "Cetak",
|
||||
"Export_to_PDF": "Ekspor ke PDF",
|
||||
@ -199,7 +200,7 @@
|
||||
"Search_by_Username": "Cari berdasarkan nama pengguna",
|
||||
"Search_by_Name": "Cari berdasarkan nama",
|
||||
"Search_by_Code_Voucher": "Cari berdasarkan kode voucher",
|
||||
"Search": "Mencari",
|
||||
"Search": "Cari",
|
||||
"Select_a_customer": "Pilih pelanggan",
|
||||
"Select_Routers": "Pilih Router",
|
||||
"Select_Plans": "Pilih Paket",
|
||||
@ -331,7 +332,7 @@
|
||||
"Pay_this_with_Balance__your_active_package_will_be_overwrite": "Bayar ini dengan Saldo? Paket aktif Anda akan ditimpa",
|
||||
"Success_to_buy_package": "Berhasil membeli paket",
|
||||
"Auto_Renewal": "Perpanjangan otomatis",
|
||||
"View": "Melihat",
|
||||
"View": "Lihat",
|
||||
"Back": "Kembali",
|
||||
"Active": "Aktif",
|
||||
"Transfer_Balance": "Kirim saldo",
|
||||
@ -381,8 +382,9 @@
|
||||
"SuperAdmin": "Super Admin",
|
||||
"Lists": "Daftar",
|
||||
"Vouchers": "Voucher",
|
||||
"Refill_Customer": "Isi Ulang Pelanggan",
|
||||
"Recharge_Customer": "Isi Ulang Pelanggan",
|
||||
"Refill_Customer": "Isi Ulang Voucher",
|
||||
"Recharge_Customer": "Isi Ulang Paket",
|
||||
"Plan": "Paket",
|
||||
"Plans": "Paket",
|
||||
"PPPOE": "PPPOE",
|
||||
"Bandwidth": "Bandwidth",
|
||||
@ -411,7 +413,7 @@
|
||||
"Paid": "Dibayar",
|
||||
"Personal": "Pribadi",
|
||||
"Coordinates": "Koordinat",
|
||||
"Confirm": "Mengonfirmasi",
|
||||
"Confirm": "Konfirmasi",
|
||||
"Name": "Nama",
|
||||
"Plan": "Paket",
|
||||
"Using": "Menggunakan",
|
||||
@ -419,7 +421,7 @@
|
||||
"Additional_Cost": "Biaya tambahan",
|
||||
"Resend": "Kirim ulang",
|
||||
"Login": "Masuk",
|
||||
"success": "Sukses",
|
||||
"success": "Berhasil",
|
||||
"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",
|
||||
@ -490,7 +492,7 @@
|
||||
"Enable_Tax_System": "Aktifkan Sistem Pajak",
|
||||
"Tax_will_be_calculated_in_Internet_Plan_Price": "Pajak akan dihitung dalam Harga Paket Internet",
|
||||
"Tax_Rate": "Persentase pajak",
|
||||
"Custom": "Kebiasaan",
|
||||
"Custom": "Kustom",
|
||||
"Tax_Rates_in_percentage": "Tarif Pajak dalam persentase",
|
||||
"Custom_Tax_Rate": "Tarif Pajak Khusus",
|
||||
"Enter_Custom_Tax_Rate": "Masukkan Tarif Pajak Khusus",
|
||||
@ -503,11 +505,11 @@
|
||||
"Time": "Waktu",
|
||||
"Data": "Data",
|
||||
"1_Period___1_Month__Expires_the_20th_of_each_month": "1 Periode = 1 Bulan, Berakhir pada tanggal 20 setiap bulannya",
|
||||
"Expired_Date": "Tanggal kadaluarsa",
|
||||
"Expired_Date": "Tanggal kadaluwarsa",
|
||||
"Expired_Action": "Tindakan Kedaluwarsa",
|
||||
"Optional": "Opsional",
|
||||
"Expired_Internet_Plan": "Paket Internet Kedaluwarsa",
|
||||
"When_Expired__customer_will_be_move_to_selected_internet_plan": "Ketika Expired, pelanggan akan dipindahkan ke paket internet yang dipilih",
|
||||
"When_Expired__customer_will_be_move_to_selected_internet_plan": "Ketika kedaluwarsa, pelanggan akan dipindahkan ke paket internet yang dipilih",
|
||||
"Period": "Periode",
|
||||
"Rate": "Kecepatan",
|
||||
"Burst": "Burst",
|
||||
@ -522,7 +524,8 @@
|
||||
"Ascending": "Naik",
|
||||
"Descending": "Menurun",
|
||||
"Query": "Query",
|
||||
"Add": "Menambahkan",
|
||||
"Add": "Tambah",
|
||||
"Search": "Cari",
|
||||
"Logout_Successful": "Berhasil Keluar",
|
||||
"warning": "peringatan",
|
||||
"Created___Expired": "Dibuat \/ Kedaluwarsa",
|
||||
@ -532,13 +535,12 @@
|
||||
"Customer_can_login_but_cannot_buy_internet_plan__Admin_cannot_recharge_customer": "Pelanggan dapat login tetapi tidak dapat membeli paket internet, Admin tidak dapat mengisi ulang pelanggan",
|
||||
"Don_t_forget_to_deactivate_all_active_plan_too": "Jangan lupa untuk menonaktifkan semua paket aktif juga",
|
||||
"Attributes": "Atribut",
|
||||
"Additional_Information": "informasi tambahan",
|
||||
"City_of_Resident": "Kota Residen",
|
||||
"Additional_Information": "Informasi tambahan",
|
||||
"City_of_Resident": "Kota Tempat Tinggal",
|
||||
"State_of_Resident": "Negara Bagian Tempat Tinggal",
|
||||
"Zip_Code": "Kode Pos",
|
||||
"Phone": "Telepon",
|
||||
"Customer_Geo_Location_Information": "Informasi Lokasi Geo Pelanggan",
|
||||
"": "",
|
||||
"Code": "Kode",
|
||||
"Send_Personal_Message": "Kirim Pesan Pribadi",
|
||||
"Send_Via": "Kirim melalui",
|
||||
@ -547,7 +549,7 @@
|
||||
"Customer_Name": "Nama Pelanggan",
|
||||
"Customer_Username": "Nama Pengguna Pelanggan",
|
||||
"Customer_Phone": "Telepon Pelanggan",
|
||||
"Your_Company_Name": "Nama perusahaan Anda",
|
||||
"Your_Company_Name": "Nama Perusahaan Anda",
|
||||
"Change": "Mengubah",
|
||||
"Change_Phone_Number": "Ubah Nomor Telepon",
|
||||
"Current_Number": "Nomor Saat Ini",
|
||||
@ -555,7 +557,7 @@
|
||||
"Input_your_phone_number": "Masukkan nomor telepon Anda",
|
||||
"OTP": "OTP",
|
||||
"Enter_OTP_that_was_sent_to_your_phone": "Masukkan OTP yang dikirimkan ke ponsel Anda",
|
||||
"Update": "Memperbarui",
|
||||
"Update": "Perbarui",
|
||||
"Verification_code_has_been_sent_to_your_phone": "Kode verifikasi telah dikirimkan ke ponsel Anda",
|
||||
"Please_wait_1039_seconds_before_sending_another_SMS": "Harap tunggu 1039 detik sebelum mengirim SMS lainnya",
|
||||
"Please_wait_1015_seconds_before_sending_another_SMS": "Harap tunggu 1015 detik sebelum mengirim SMS lainnya",
|
||||
@ -568,11 +570,349 @@
|
||||
"Api": "Api",
|
||||
"Http_Chap": "Http-Chap",
|
||||
"Hotspot_Authentication_Method__Make_sure_you_have_changed_your_hotspot_login_page_": "Metode Otentikasi Hotspot. Pastikan Anda telah mengubah halaman login hotspot Anda.",
|
||||
"Languge_set_to_indonesia": "Language set to indonesia",
|
||||
"Languge_set_to_indonesia": "Bahasa diatur ke Indonesia",
|
||||
"Enable": "Aktifkan",
|
||||
"Diable": "Nonaktifkan",
|
||||
"Balance" "Saldo",
|
||||
"Verification_code": "Kod3 V3r1fik@s1",
|
||||
"Registration_code": "Kod3 R3g1str@s1",
|
||||
"TX": "TX",
|
||||
"RX": "RX",
|
||||
"Database": "Database"
|
||||
"Database": "Database",
|
||||
"Additional_Billing": "Penagihan Tambahan",
|
||||
"paid_off": "terbayar lunas",
|
||||
"Sync_account_if_you_failed_login_to_internet": "Sinkronkan akun jika Anda gagal masuk ke internet",
|
||||
"_Are_You_Sure_": "Apa kamu yakin?",
|
||||
"Send_your_balance___": "Kirim saldo Anda?",
|
||||
"_": "-",
|
||||
"Search_Users": "Pencarian Pengguna",
|
||||
"Routers_Maps": "Peta Router",
|
||||
"Theme_Voucher": "Tema Voucher",
|
||||
"Payment_Info": "Info Pembayaran",
|
||||
"Documentation": "Dokumentasi",
|
||||
"Customers": "Pelanggan",
|
||||
"Package_Name": "Nama Paket",
|
||||
"Routers_Offline": "Router Off",
|
||||
"Cron_appear_not_been_setup__please_check_your_cron_setup_": "Cron tampaknya belum disiapkan, silakan periksa pengaturan cron Anda.",
|
||||
"Buy": "Beli",
|
||||
"You_are_already_logged_in": "Anda sudah masuk",
|
||||
"PPPOE_Package": "Paket PPPoE",
|
||||
"Prepaid": "Prabayar",
|
||||
"Postpaid": "Pascabayar",
|
||||
"Enabled": "Aktifkan",
|
||||
"Disable": "Nonaktifkan",
|
||||
"Create_expired_Internet_Plan": "Buat Paket Internet yang Kedaluwarsa",
|
||||
"When_customer_expired__you_can_move_it_to_Expired_Internet_Plan": "Ketika pelanggan kedaluwarsa, Anda dapat memindahkannya ke Paket Internet Kedaluwarsa",
|
||||
"Price_Before_Discount": "Harga Sebelum Diskon",
|
||||
"For_Discount_Rate__this_is_price_before_get_discount__must_be_more_expensive_with_real_price": "Untuk tarif diskon. Ini adalah harga sebelum mendapat diskon, pasti lebih mahal dari harga sebenarnya",
|
||||
"on_login___on_up": "saat masuk \/ saat naik",
|
||||
"on_logout___on_down": "saat keluar \/ saat turun",
|
||||
"Get_Directions": "Dapatkan Petunjuk Arah",
|
||||
"Not_Working_with_Freeradius_Mysql": "Tidak Bekerja dengan Freeradius Mysql",
|
||||
"User_Cannot_change_this__only_admin__if_it_Empty_it_will_use_Customer_Credentials": "Pengguna tidak dapat mengubah ini, hanya admin. Jika Kosong, maka akan menggunakan Kredensial Pelanggan",
|
||||
"Buy_this__your_active_package_will_be_overwritten": "Beli paket ini? Paket aktif Anda akan ditimpa",
|
||||
"Pay_this_with_Balance__your_active_package_will_be_overwritten": "Bayar ini dengan Saldo? Paket aktif Anda akan ditimpa",
|
||||
"Error": "Kesalahan",
|
||||
"Internal_Error": "Kesalahan Internal",
|
||||
"Sorry__the_software_failed_to_process_the_request__if_it_still_happening__please_tell": "Maaf, perangkat lunak gagal memproses permintaan. Jika masih terjadi, mohon beri tahu",
|
||||
"Try_Again": "Coba Lagi",
|
||||
"Make_sure_you_use_API_Port__Default_8728": "Pastikan Anda menggunakan Port API, Default 8728",
|
||||
"Make_sure_Username_and_Password_are_correct": "Pastikan nama pengguna dan kata sandi sudah benar",
|
||||
"Make_sure_your_hosting_not_blocking_port_to_external": "Pastikan hosting Anda tidak memblokir port ke eksternal",
|
||||
"Make_sure_your_Mikrotik_accessible_from_PHPNuxBill": "Pastikan Mikrotik Anda dapat diakses dari PHPNuxBill",
|
||||
"If_you_just_update_PHPNuxBill_from_upload_files__try_click_Update": "Jika Anda baru saja memperbarui PHPNuxBill dari mengunggah file, coba klik Perbarui",
|
||||
"Update_PHPNuxBill": "Perbarui PHPNuxBill",
|
||||
"Ask_Github_Community": "Tanya Komunitas Github",
|
||||
"Ask_Telegram_Community": "Tanya Komunitas Telegram",
|
||||
"Token_has_expired__Please_log_in_again_": "Token telah kedaluwarsa. Silakan masuk lagi.",
|
||||
"danger": "bahaya",
|
||||
"Application_Name___Company_Name": "Nama Aplikasi \/ Nama Perusahaan",
|
||||
"For_PDF_Reports___Best_size_1078_x_200___uploaded_image_will_be_autosize": "Untuk Laporan PDF | Ukuran terbaik 1078 x 200 | gambar yang diunggah akan berukuran otomatis",
|
||||
"Print_Max_Char": "Cetak Max Char",
|
||||
"For_invoice_print_using_Thermal_Printer": "Untuk cetak faktur menggunakan Printer Thermal",
|
||||
"Theme": "Tema",
|
||||
"Default": "Bawaan",
|
||||
"Theme_Info": "Info Tema",
|
||||
"This_used_for_admin_to_select_payment_in_recharge__using_comma_for_every_new_options": "Ini digunakan untuk admin untuk memilih pembayaran dalam pengisian ulang, menggunakan koma untuk setiap opsi baru",
|
||||
"Income_will_reset_every_this_day": "Pendapatan akan direset setiap hari ini",
|
||||
"edit_at_config_php": "edit di config.php",
|
||||
"Hide_Dashboard_Content": "Sembunyikan Konten Dasbor",
|
||||
"Redirect_URL_after_Activation": "Pengalihan URL setelah Aktivasi",
|
||||
"Enable_Radius": "Aktifkan Radius",
|
||||
"Radius_Instructions": "Petunjuk Radius",
|
||||
"Customer_can_request_to_extend_expirations": "Pelanggan dapat meminta perpanjangan masa berlaku",
|
||||
"i_agree_to_extends_and_will_paid_full_after_this": "Saya setuju untuk memperpanjang dan akan membayar penuh setelah ini",
|
||||
"Customer_Balance_System": "Sistem Saldo Pelanggan",
|
||||
"Telegram_Bot_Token": "Token Bot Telegram",
|
||||
"Telegram_User_Channel_Group_ID": "ID Pengguna\/Saluran\/Grup Telegram",
|
||||
"You_will_get_Payment_and_Error_notification": "Anda akan mendapatkan pemberitahuan Pembayaran dan Kesalahan",
|
||||
"Test_SMS": "Tes SMS",
|
||||
"SMS_Server_URL": "URL Server SMS",
|
||||
"Must_include": "Harus menyertakan",
|
||||
"it_will_be_replaced_": "itu akan diganti.",
|
||||
"Or_use_Mikrotik_SMS": "Atau gunakan Mikrotik SMS",
|
||||
"Select_Router": "Pilih Router",
|
||||
"You_can_use": "Anda dapat menggunakan",
|
||||
"in_here_too_": "di sini juga.",
|
||||
"Free_Server": "Server Gratis",
|
||||
"WhatsApp_Server_URL": "URL Server WhatsApp",
|
||||
"Empty_this_to_use_internal_mail___PHP": "Kosongkan ini untuk menggunakan internal mail() PHP",
|
||||
"SMTP_Username": "Nama Pengguna SMTP",
|
||||
"SMTP_Password": "Kata Sandi SMTP",
|
||||
"SMTP_Security": "Keamanan SMTP",
|
||||
"Mail_Reply_To": "Balas Email Ke",
|
||||
"Customer_will_reply_email_to_this_address__empty_if_you_want_to_use_From_Address": "Pelanggan akan membalas email ke alamat ini, kosong jika Anda ingin menggunakan Alamat Dari",
|
||||
"None": "Tidak ada",
|
||||
"By_WhatsApp": "Melalui WhatsApp",
|
||||
"By_SMS": "Melalui SMS",
|
||||
"By_Email": "Melalui Email",
|
||||
"From_Direct_Chat_Link_": "Dari Tautan Obrolan Langsung.",
|
||||
"Access_Token": "Token Akses",
|
||||
"Empty_this_to_randomly_created_API_key": "Kosongkan ini ke kunci API yang dibuat secara acak",
|
||||
"Enable_Session_Timeout": "Aktifkan Batas Waktu Sesi",
|
||||
"Logout_Admin_if_not_Available_Online_a_period_of_time": "Logout Admin jika tidak tersedia\/Online dalam jangka waktu tertentu",
|
||||
"Timeout_Duration": "Durasi Waktu Habis",
|
||||
"Enter_the_session_timeout_duration__minutes_": "Masukkan durasi batas waktu sesi (menit)",
|
||||
"Idle_Timeout__Logout_Admin_if_Idle_for_xx_minutes": "Batas waktu idle, Keluar dari Admin jika Idle selama xx menit",
|
||||
"New_Version_Notification": "Pemberitahuan Versi Baru",
|
||||
"This_is_to_notify_you_when_new_updates_is_available": "Ini untuk memberi tahu Anda ketika pembaruan baru tersedia",
|
||||
"Router_Check": "Pemeriksaan Router",
|
||||
"If_enabled__the_system_will_notify_Admin_when_router_goes_Offline__If_admin_have_10_or_more_router_and_many_customers__it_will_get_overlapping__you_can_disabled": "Jika diaktifkan, sistem akan memberitahu Admin ketika router Off, Jika Admin memiliki 10 atau lebih router dan banyak pelanggan, maka akan terjadi tumpang tindih, Anda dapat menonaktifkannya",
|
||||
"Phone_OTP_Required": "Diperlukan OTP Telepon",
|
||||
"OTP_is_required_when_user_want_to_change_phone_number_and_registration": "OTP diperlukan ketika pengguna ingin mengubah nomor telepon dan registrasi",
|
||||
"by_WhatsApp": "melalui WhatsApp",
|
||||
"By_WhatsApp_and_SMS": "Melalui WhatsApp dan SMS",
|
||||
"Email_OTP_Required": "Email OTP Diperlukan",
|
||||
"OTP_is_required_when_user_want_to_change_Email_Address": "OTP diperlukan ketika pengguna ingin mengubah Alamat Email",
|
||||
"Show_Bandwidth_Plan": "Tampilkan Paket Bandwidth",
|
||||
"_for_Customer": "untuk Pelanggan",
|
||||
"Custome": "Pelanggan",
|
||||
"Custome_Tax_Rate": "Tarif Pajak Bea Cukai",
|
||||
"Enter_Custome_Tax_Rate": "Masukkan Tarif Pajak Pelanggan",
|
||||
"Authentication": "Autentikasi",
|
||||
"Github_Username": "Nama Pengguna Github",
|
||||
"Github_Token": "Token Github",
|
||||
"Create_GitHub_personal_access_token": "Buat token akses pribadi GitHub",
|
||||
"only_need_repo_scope": "hanya butuh cakupan repo",
|
||||
"This_will_allow_you_to_download_plugin_from_private_paid_repository": "Ini akan memungkinkan Anda mengunduh plugin dari repositori pribadi\/berbayar",
|
||||
"Expired_Cronjob_Every_5_Minutes": "Cronjob Kedaluwarsa Setiap 5 Menit",
|
||||
"Expired_Cronjob_Every_1_Hour": "Cronjob Kedaluwarsa Setiap 1 Jam",
|
||||
"Reminder_Cronjob_Every_7_AM": "Pengingat Cronjob Setiap Jam 7 Pagi",
|
||||
"Check_if_Customer_Online": "Periksa apakah Pelanggan Online",
|
||||
"Active_Customers": "Pelanggan Aktif",
|
||||
"This_will_show_is_Customer_currently_is_online_or_not": "Ini akan menunjukkan apakah Pelanggan sedang online atau tidak",
|
||||
"3_Months": "3 Bulan",
|
||||
"Used_Date": "Tanggal Penggunaan",
|
||||
"Plugin_Installer": "Pemasang Plugin",
|
||||
"Upload_Zip_Plugin_Theme_Device": "Unggah Plugin\/Tema\/Perangkat Zip",
|
||||
"Install": "Pasang",
|
||||
"via_SMS": "melalui SMS",
|
||||
"Via_WhatsApp": "Melalui WhatsApp",
|
||||
"Via_WhatsApp_and_SMS": "Melalui WhatsApp dan SMS",
|
||||
"Send_Bulk_Message": "Kirim Pesan Massal",
|
||||
"Group": "Kelompok",
|
||||
"All_Customers": "Semua Pelanggan",
|
||||
"New_Customers": "Pelanggan Baru",
|
||||
"Expired_Customers": "Pelanggan yang Kedaluwarsa",
|
||||
"Message_per_time": "Pesan per waktu",
|
||||
"5_Messages": "5 Pesan",
|
||||
"10_Messages": "10 Pesan",
|
||||
"15_Messages": "15 Pesan",
|
||||
"20_Messages": "20 Pesan",
|
||||
"30_Messages": "30 Pesan",
|
||||
"40_Messages": "40 Pesan",
|
||||
"50_Messages": "50 Pesan",
|
||||
"60_Messages": "60 Pesan",
|
||||
"Use_20_and_above_if_you_are_sending_to_all_customers_to_avoid_server_time_out": "Gunakan 20 dan di atasnya jika Anda mengirim ke semua pelanggan untuk menghindari waktu server habis",
|
||||
"Delay": "Menunda",
|
||||
"No_Delay": "Tidak Ada Penundaan",
|
||||
"5_Seconds": "5 Detik",
|
||||
"10_Seconds": "10 Detik",
|
||||
"15_Seconds": "15 Detik",
|
||||
"20_Seconds": "20 Detik",
|
||||
"Use_at_least_5_secs_if_you_are_sending_to_all_customers_to_avoid_being_banned_by_your_message_provider": "Gunakan setidaknya 5 detik jika Anda mengirim ke semua pelanggan untuk menghindari pemblokiran oleh penyedia pesan Anda",
|
||||
"Testing__if_checked_no_real_message_is_sent_": "Pengujian [jika dicentang, tidak ada pesan nyata yang dikirim]",
|
||||
"Message_Results": "Hasil Pesan",
|
||||
"VPN_Plans": "Paket VPN",
|
||||
"VPN_Package": "Paket VPN",
|
||||
"Balance_Package": "Paket Saldo",
|
||||
"New_Service_Package": "Paket Layanan Baru",
|
||||
"Package_Price": "Harga Paket",
|
||||
"Radius_Package": "Paket Radius",
|
||||
"Hotspot_Package": "Paket Hotspot",
|
||||
"Maintenance_Mode_Settings": "Pengaturan Mode Pemeliharaan",
|
||||
"Status_": "Status:",
|
||||
"Force_Logout_": "Paksa Keluar:",
|
||||
"End_Date_": "Tanggal Berakhir:",
|
||||
"Save": "Simpan",
|
||||
"Not_Active": "Tidak Aktif",
|
||||
"Limit": "Batasi",
|
||||
"Create_expired_Internet_Package": "Buat Paket Internet yang Kedaluwarsa",
|
||||
"When_customer_expired__you_can_move_it_to_Expired_Internet_Package": "Ketika pelanggan telah kedaluwarsa, Anda dapat memindahkannya ke Paket Internet Kedaluwarsa",
|
||||
"Miscellaneous_Settings": "Pengaturan Lain-Lain",
|
||||
"Minute": "Menit",
|
||||
"Hour": "Jam",
|
||||
"Buy_Balance_Plans": "Beli Paket Saldo",
|
||||
"New_Voucher_for_10mbps_Created": "Voucher Baru untuk 10mbps Dibuat",
|
||||
"Previous": "Sebelumnya",
|
||||
"Share": "Bagikan",
|
||||
"Agent": "Agen",
|
||||
"Sub_District": "Kecamatan",
|
||||
"Ward": "Kelurahan",
|
||||
"Profile": "Profil",
|
||||
"Credentials": "Kredensial",
|
||||
"Cron_has_not_run_for_over_1_hour__Please_check_your_setup_": "Cron tidak berjalan selama lebih dari 1 jam. Harap periksa pengaturan Anda.",
|
||||
"Photo": "Foto",
|
||||
"just_now": "baru saja",
|
||||
"Face_Detection": "Deteksi Wajah",
|
||||
"Password_should_be_minimum_6_characters": "Kata sandi minimal harus 6 karakter",
|
||||
"Username_should_be_between_3_to_45_characters": "Nama pengguna harus terdiri dari 3 hingga 45 karakter",
|
||||
"Single_session_Admin": "Sesi Tunggal Admin",
|
||||
"Admin_can_only_have_single_session_login__it_will_logout_another_session": "Admin hanya dapat memiliki login satu sesi, maka akan keluar dari sesi berikutnya",
|
||||
"For_Registration_and_Update_Phone_Number": "Untuk Registrasi dan Perbarui Nomor Telepon",
|
||||
"Login_as_Customer": "Masuk sebagai Pelanggan",
|
||||
"Invalid_or_Expired_CSRF_Token": "Token CSRF Tidak Valid atau Kedaluwarsa",
|
||||
"Edit_Service_Package": "Edit Paket Layanan",
|
||||
"Package_Type": "Tipe Paket",
|
||||
"Package_Validity": "Validitas Paket",
|
||||
"Expired_Internet_Package": "Paket Internet Kedaluwarsa",
|
||||
"Default___Remove_Customer": "Default - Hapus Pelanggan",
|
||||
"When_Expired__customer_will_be_move_to_selected_internet_package": "Jika masa berlaku habis, pelanggan akan dipindahkan ke paket internet yang dipilih",
|
||||
"Data_Change": "Perubahan Data",
|
||||
"Home_Address": "Alamat Rumah",
|
||||
"Email_Address": "Alamat Email",
|
||||
"Custom_Balance": "Saldo Kustom",
|
||||
"Input_Desired_Amount": "Masukkan jumlah yang diinginkan",
|
||||
"Advanced_Hotspot_System": "Sistem Hotspot Lanjutan",
|
||||
"Successful_Payments": "Pembayaran Berhasil",
|
||||
"More_Info": "Info lebih lanjut",
|
||||
"Failed_Payments": "Pembayaran Gagal",
|
||||
"Pending_Payments": "Pembayaran Tertunda",
|
||||
"Cancelled_Payments": "Pembayaran yang Dibatalkan",
|
||||
"Daily_Sales": "Penjualan Harian",
|
||||
"Monthly_Sales": "Penjualan Bulanan",
|
||||
"Weekly_Sales": "Penjualan Mingguan",
|
||||
"How_its_Works": "Cara kerjanya",
|
||||
"_Click_this": "Klik ini",
|
||||
"_to_visit_the_hotspot_login_page": "untuk mengunjungi halaman login hotspot",
|
||||
"_Choose_your_desired_plan__enter_your_phone_number_and_click_Pay_Now__you_will_be_redirected_to_payment_portal_": "Pilih paket yang Anda inginkan, masukkan nomor telepon Anda dan klik Bayar Sekarang, Anda akan diarahkan ke portal pembayaran.",
|
||||
"_Pay_with_Demo_Success_": "Bayar dengan Demo berhasil.",
|
||||
"_After_Successful_Payment_you_will_be_awarded_the_package_and_you_will_received_your_Voucher_Code_for_login_": "Setelah Pembayaran Berhasil, Anda akan diberikan paket dan Anda akan menerima Kode Voucher untuk login.",
|
||||
"_Come_back_here_to_see_your_hotspot_performance_at_a_glance_": "Kembali ke sini untuk melihat sekilas kinerja hotspot Anda.",
|
||||
"Hotspot_Payment_History": "Riwayat Pembayaran Hotspot",
|
||||
"Search_Phone_Number_____": "Cari Nomor Telepon.....",
|
||||
"Transaction_ID": "ID Transaksi",
|
||||
"Transaction_Ref": "Referensi Transaksi",
|
||||
"Voucher_Code": "Kode Voucher",
|
||||
"Amount": "Jumlah",
|
||||
"Transaction_Status": "Status Transaksi",
|
||||
"Payment_Method": "Metode Pembayaran",
|
||||
"Payment_Date": "Tanggal Pembayaran",
|
||||
"Plan_Expiry_Date": "Tanggal Kedaluwarsa Paket",
|
||||
"Created_on": "Dibuat pada",
|
||||
"Expires_on": "Kedaluwarsa pada",
|
||||
"Package_Details": "Rincian Paket",
|
||||
"Summary": "Ringkasan",
|
||||
"Allow_Balance_custom_amount": "Izinkan Saldo jumlah khusus",
|
||||
"Allow_Customer_buy_balance_with_any_amount": "Izinkan Pelanggan membeli saldo dengan jumlah berapa pun",
|
||||
"Or": "Atau",
|
||||
"Filter": "Menyaring",
|
||||
"Show_chart": "Tampilkan grafik",
|
||||
"Start_Date": "Tanggal Mulai",
|
||||
"Start_time": "Waktu Mulai",
|
||||
"End_Date": "Tanggal Akhir",
|
||||
"End_Time": "Waktu berakhir",
|
||||
"Internet_Plans": "Paket Internet",
|
||||
"Methods": "Metode",
|
||||
"Hap_Lite": "Hap Lite",
|
||||
"balance": "saldo",
|
||||
"radius": "radius",
|
||||
"Max_30_days": "Maksimal 30 hari",
|
||||
"Information": "Informasi",
|
||||
"Export_and_Print_will_show_all_data_without_pagination": "Ekspor dan Cetak akan menampilkan semua data tanpa paginasi",
|
||||
"First_Name": "Nama Depan",
|
||||
"Last_Name": "Nama Belakang",
|
||||
"General": "Umum",
|
||||
"Registration": "Pendaftaran",
|
||||
"Allow_Registration": "Izinkan Registrasi",
|
||||
"Voucher_Only": "Hanya Voucher",
|
||||
"No_Registration": "Tidak Ada Registrasi",
|
||||
"Registration_Username": "Nama Pengguna Registrasi",
|
||||
"Customer_Registration_need_to_validate_using_OTP": "Registrasi Pelanggan perlu divalidasi menggunakan OTP",
|
||||
"SMS_Notification": "Pemberitahuan SMS",
|
||||
"Tax_Rates_by_percentage": "Tarif Pajak Berdasarkan Persentase",
|
||||
"Settings_For_Mikrotik": "Pengaturan Untuk Mikrotik",
|
||||
"Settings_For_Cron_Expired": "Pengaturan Untuk Cron Kedaluwarsa",
|
||||
"Choose_one__above_or_below": "Pilih salah satu, di atas atau di bawah",
|
||||
"Settings_For_Cron_Reminder": "Pengaturan Untuk Pengingat Cron",
|
||||
"Security": "Keamanan",
|
||||
"Enable_CSRF_Validation": "Aktifkan Validasi CSRF",
|
||||
"Cross_site_request_forgery": "Pemalsuan permintaan lintas situs",
|
||||
"Forgot_Password": "Lupa Kata Sandi",
|
||||
"Validity_Periode": "Periode Validitas",
|
||||
"Transaction_History_List": "Daftar Riwayat Transaksi",
|
||||
"plan": "paket",
|
||||
"package": "paket",
|
||||
"Cards": "Kartu",
|
||||
"CRM": "CRM",
|
||||
"Coupons": "Kupon",
|
||||
"Custom_Fields": "Bidang Kustom",
|
||||
"Search_Coupons": "Cari Kupon",
|
||||
"Add_Coupon": "Tambahkan Kupon",
|
||||
"Value": "Nilai",
|
||||
"Max_Usage": "Penggunaan Maksimal",
|
||||
"Usage_Count": "Jumlah Pemakaian",
|
||||
"Min_Order": "Pesanan Min",
|
||||
"Max_Discount": "Diskon Maksimal",
|
||||
"Updated_Date": "Tanggal Diperbarui",
|
||||
"Action": "Tindakan",
|
||||
"No_coupons_found_": "Tidak ada kupon yang ditemukan.",
|
||||
"Delete_Selected": "Hapus yang Dipilih",
|
||||
"Coupon_Code": "Kode Kupon",
|
||||
"Random": "Acak",
|
||||
"Unique_code_for_the_coupon": "Kode unik untuk kupon",
|
||||
"Fixed_Discount": "Diskon Tetap",
|
||||
"Percent_Discount": "Diskon Persen",
|
||||
"Discount_Value": "Nilai Diskon",
|
||||
"Value_of_the_discount__amount_or_percentage_": "Nilai diskon (jumlah atau persentase)",
|
||||
"Brief_explanation_of_the_coupon": "Penjelasan singkat tentang kupon",
|
||||
"Maximum_number_of_times_this_coupon_can_be_used_0_is_Unlimited": "Jumlah maksimum penggunaan kupon ini 0 adalah Tidak Terbatas",
|
||||
"Minimum_Order_Amount": "Jumlah Pesanan Minimum",
|
||||
"Minimum_cart_total_required_to_use_this_coupon": "Total keranjang minimum yang diperlukan untuk menggunakan kupon ini",
|
||||
"Max_Discount_Amount": "Jumlah Diskon Maksimum",
|
||||
"Maximum_discount_amount_applicable__for_percent_type_": "Jumlah diskon maksimum yang berlaku (untuk jenis persen)",
|
||||
"Value_of_the_discount__percentage__max_100_": "Nilai diskon (persentase, maks 100)",
|
||||
"Value_of_the_discount__amount_": "Nilai diskon (jumlah)",
|
||||
"Voucher_Cards": "Kartu Voucher",
|
||||
"Create_Date": "Tanggal Pembuatan",
|
||||
"Postpaid_Recharge_for_the_first_time_use": "Isi Ulang Pascabayar untuk penggunaan pertama kali",
|
||||
"Select_Balance_Package_or_Custom_Amount": "Pilih Paket Saldo atau Jumlah Kustom",
|
||||
"Or_custom_balance_amount_below": "Atau jumlah saldo khusus di bawah ini",
|
||||
"Balance_Amount": "Jumlah Saldo",
|
||||
"Input_custom_balance__will_ignore_plan_above": "Masukkan saldo khusus, akan mengabaikan paket di atas",
|
||||
"Note": "Catatan",
|
||||
"Customer_Login_Page_Settings": "Pengaturan Halaman Login Pelanggan",
|
||||
"Choose_Template": "Pilih Template",
|
||||
"Select_your_login_template_type": "Pilih jenis template login Anda",
|
||||
"Select_Login_Page": "Pilih Halaman Login",
|
||||
"Select_your_preferred_login_template": "Pilih template login pilihan Anda",
|
||||
"Page_Heading___Company_Name": "Judul Halaman \/ Nama Perusahaan",
|
||||
"This_Name_will_be_shown_on_the_login_wallpaper": "Nama ini akan ditampilkan pada wallpaper login",
|
||||
"Page_Description": "Deskripsi Halaman",
|
||||
"This_will_also_display_on_wallpaper__You_can_use_html_tag": "Ini juga akan ditampilkan di wallpaper, Anda dapat menggunakan tag html",
|
||||
"Favicon": "Ikon favicon",
|
||||
"Best_size_30_x_30___uploaded_image_will_be_autosize": "Ukuran terbaik 30 x 30 | gambar yang diunggah akan berukuran otomatis",
|
||||
"Login_Page_Logo": "Logo Halaman Login",
|
||||
"Best_size_300_x_60___uploaded_image_will_be_autosize": "Ukuran terbaik 300 x 60 | gambar yang diunggah akan berukuran otomatis",
|
||||
"Login_Page_Wallpaper": "Wallpaper Halaman Login",
|
||||
"Best_size_1920_x_1080___uploaded_image_will_be_autosize": "Ukuran terbaik 1920 x 1080 | gambar yang diunggah akan berukuran otomatis",
|
||||
"Photo_Required": "Foto Diperlukan",
|
||||
"Customer_Registration_need_to_upload_their_photo": "Registrasi Pelanggan perlu mengunggah foto mereka",
|
||||
"Notify_Admin": "Beritahu Admin",
|
||||
"Notify_Admin_upon_self_registration": "Beritahu Admin saat registrasi mandiri",
|
||||
"Mandatory_Fields": "Bidang yang wajib diisi",
|
||||
"Single_Admin_Session": "Sesi Admin Tunggal",
|
||||
"Mikrotik_SMS_Command": "Perintah SMS Mikrotik",
|
||||
"Expired_Cronjob_Every_5_Minutes__Recommended_": "Cronjob Kedaluwarsa Setiap 5 Menit [Direkomendasikan]",
|
||||
"Visit": "Kunjungi",
|
||||
"sync": "Sinkron"
|
||||
}
|
||||
|
@ -5,10 +5,10 @@
|
||||
"Registration_Info": "Informaci\u00f3n de registro",
|
||||
"Voucher_not_found__please_buy_voucher_befor_register": "Cup\u00f3n no encontrado, compre el cup\u00f3n antes de registrarse",
|
||||
"Register_Success__You_can_login_now": "\u00a1Registro exitoso! Puedes iniciar sesi\u00f3n ahora",
|
||||
"Log_in_to_Member_Panel": "Log in to Member Panel",
|
||||
"Log_in_to_Member_Panel": "Iniciar sesi\u00f3n en el panel de miembros",
|
||||
"Register_as_Member": "Reg\u00edstrese como miembro",
|
||||
"Enter_Admin_Area": "Panel de administraci\u00f3n",
|
||||
"PHPNuxBill": "DIGITAL-RED",
|
||||
"PHPNuxBill": "Compañia",
|
||||
"Username": "Usuario",
|
||||
"Password": "Contrase\u00f1a",
|
||||
"Passwords_does_not_match": "Las contrase\u00f1as no coinciden",
|
||||
@ -27,7 +27,7 @@
|
||||
"Failed_to_save_page__make_sure_i_can_write_to_folder_pages___i_chmod_664_pages___html_i_": "No se pudo guardar la p\u00e1gina, aseg\u00farese de que pueda escribir en las p\u00e1ginas de la carpeta, <i>chmod 664 pages\/*.html<i>",
|
||||
"Saving_page_success": "Guardando el \u00e9xito de la p\u00e1gina",
|
||||
"Sometimes_you_need_to_refresh_3_times_until_content_change": "A veces es necesario actualizar 3 veces hasta que cambie el contenido",
|
||||
"Dashboard": "Dashboard",
|
||||
"Dashboard": "Panel",
|
||||
"Search_Customers___": "Buscar clientes...",
|
||||
"My_Account": "Mi cuenta",
|
||||
"My_Profile": "Mi perfil",
|
||||
@ -140,7 +140,7 @@
|
||||
"Administrator_Users": "Usuarios administradores",
|
||||
"Manage_Administrator": "Administrar administrador",
|
||||
"Add_New_Administrator": "Agregar nuevo administrador",
|
||||
"Localisation": "Localizaci\u00f3n",
|
||||
"Localisation": "Idioma y Fecha",
|
||||
"Backup_Restore": "Copia de seguridad\/restauracion",
|
||||
"General_Settings": "Configuraci\u00f3n general",
|
||||
"Date": "Fecha",
|
||||
@ -213,166 +213,630 @@
|
||||
"Folder_Name": "Nombre de la carpeta",
|
||||
"Translator": "Traducir",
|
||||
"Language_Name_Already_Exist": "El nombre del idioma ya existe",
|
||||
"Payment_Gateway": "Payment Gateway",
|
||||
"Community": "Community",
|
||||
"1_user_can_be_used_for_many_devices_": "1 user can be used for many devices?",
|
||||
"Cannot_be_change_after_saved": "Cannot be change after saved",
|
||||
"Explain_Coverage_of_router": "Jelaskan Cakupan wilayah hotspot",
|
||||
"Name_of_Area_that_router_operated": "Nama Lokasi\/Wilayah Router beroperasi",
|
||||
"Payment_Notification_URL__Recurring_Notification_URL__Pay_Account_Notification_URL": "Payment Notification URL, Recurring Notification URL, Pay Account Notification URL",
|
||||
"Finish_Redirect_URL__Unfinish_Redirect_URL__Error_Redirect_URL": "Finish Redirect URL, Unfinish Redirect URL, Error Redirect URL",
|
||||
"Status": "Status",
|
||||
"Plan_Not_found": "Plan Not found",
|
||||
"Failed_to_create_transaction_": "Failed to create transaction.",
|
||||
"Seller_has_not_yet_setup_Xendit_payment_gateway": "Seller has not yet setup Xendit payment gateway",
|
||||
"Admin_has_not_yet_setup_Xendit_payment_gateway__please_tell_admin": "Admin has not yet setup Xendit payment gateway, please tell admin",
|
||||
"Buy_this__your_active_package_will_be_overwrite": "Buy this? your active package will be overwrite",
|
||||
"You_already_have_unpaid_transaction__cancel_it_or_pay_it_": "You already have unpaid transaction, cancel it or pay it.",
|
||||
"Transaction_Not_found": "Transaction Not found",
|
||||
"Cancel_it_": "Cancel it?",
|
||||
"expired": "expired",
|
||||
"Check_for_Payment": "Check for Payment",
|
||||
"Transaction_still_unpaid_": "Transaction still unpaid.",
|
||||
"Paid_Date": "Paid Date",
|
||||
"Transaction_has_been_paid_": "Transaction has been paid.",
|
||||
"PAID": "PAID",
|
||||
"CANCELED": "CANCELED",
|
||||
"UNPAID": "UNPAID",
|
||||
"PAY_NOW": "PAY NOW",
|
||||
"Buy_Hotspot_Plan": "Buy Hotspot Plan",
|
||||
"Buy_PPOE_Plan": "Buy PPOE Plan",
|
||||
"Package": "Package",
|
||||
"Order_Internet_Package": "Order Internet Package",
|
||||
"Unknown_Command_": "Unknown Command.",
|
||||
"Checking_payment": "Checking payment",
|
||||
"Create_Transaction_Success": "Create Transaction Success",
|
||||
"You_have_unpaid_transaction": "You have unpaid transaction",
|
||||
"TripayPayment_Channel": "TripayPayment Channel",
|
||||
"Payment_Channel": "Payment Channel",
|
||||
"Payment_check_failed_": "Payment check failed.",
|
||||
"Order_Package": "Order Package",
|
||||
"Transactions": "Transactions",
|
||||
"Payments": "Payments",
|
||||
"History": "History",
|
||||
"Order_History": "Order History",
|
||||
"Gateway": "Gateway",
|
||||
"Date_Done": "Date Done",
|
||||
"Unpaid_Order": "Unpaid Order",
|
||||
"Payment_Gateway_Not_Found": "Payment Gateway Not Found",
|
||||
"Payment_Gateway_saved_successfully": "Payment Gateway saved successfully",
|
||||
"ORDER": "ORDER",
|
||||
"Package_History": "Package History",
|
||||
"Buy_History": "Buy History",
|
||||
"Activation_History": "Activation History",
|
||||
"Buy_Package": "Buy Package",
|
||||
"Email": "Email",
|
||||
"Company_Footer": "Company Footer",
|
||||
"Will_show_below_user_pages": "Will show below user pages",
|
||||
"Request_OTP": "Request OTP",
|
||||
"Verification_Code": "Verification Code",
|
||||
"SMS_Verification_Code": "SMS Verification Code",
|
||||
"Please_enter_your_email_address": "Please enter your email address",
|
||||
"Failed_to_create_Paypal_transaction_": "Failed to create Paypal transaction.",
|
||||
"Payment_Gateway": "Pasarela de Pago",
|
||||
"Community": "Comunidad",
|
||||
"1_user_can_be_used_for_many_devices_": "1 usuario puede utilizarse para varios dispositivos?",
|
||||
"Cannot_be_change_after_saved": "No se puede cambiar despu\u00e9s de guardar",
|
||||
"Explain_Coverage_of_router": "Explicar la cobertura del enrutador",
|
||||
"Name_of_Area_that_router_operated": "Nombre del \u00e1rea que operaba el enrutador",
|
||||
"Payment_Notification_URL__Recurring_Notification_URL__Pay_Account_Notification_URL": "URL de notificaci\u00f3n de pago, URL de notificaci\u00f3n recurrente, URL de notificaci\u00f3n de cuenta de pago",
|
||||
"Finish_Redirect_URL__Unfinish_Redirect_URL__Error_Redirect_URL": "URL de redireccionamiento finalizada, URL de redireccionamiento incompleta, URL de redireccionamiento con error",
|
||||
"Status": "Estado",
|
||||
"Plan_Not_found": "Plan no encontrado",
|
||||
"Failed_to_create_transaction_": "No se pudo crear la transacci\u00f3n.",
|
||||
"Seller_has_not_yet_setup_Xendit_payment_gateway": "El vendedor a\u00fan no ha configurado la pasarela de pago Xendit",
|
||||
"Admin_has_not_yet_setup_Xendit_payment_gateway__please_tell_admin": "El administrador a\u00fan no ha configurado la pasarela de pago Xendit, inf\u00f3rmeselo al administrador.",
|
||||
"Buy_this__your_active_package_will_be_overwrite": "\u00bfCompraste esto? Tu paquete activo se sobrescribir\u00e1",
|
||||
"You_already_have_unpaid_transaction__cancel_it_or_pay_it_": "Ya tienes transacci\u00f3n impaga, canc\u00e9lala o p\u00e1gala.",
|
||||
"Transaction_Not_found": "Transacci\u00f3n no encontrada",
|
||||
"Cancel_it_": "\u00bfCancelalo?",
|
||||
"expired": "Caducada",
|
||||
"Check_for_Payment": "Verificar pago",
|
||||
"Transaction_still_unpaid_": "Transacci\u00f3n a\u00fan impaga.",
|
||||
"Paid_Date": "Fecha de pago",
|
||||
"Transaction_has_been_paid_": "La transacci\u00f3n ha sido pagada.",
|
||||
"PAID": "PAGADA",
|
||||
"CANCELED": "CANCELADA",
|
||||
"UNPAID": "NO PAGADO",
|
||||
"PAY_NOW": "PAGAR AHORA",
|
||||
"Buy_Hotspot_Plan": "Comprar plan de hotspot",
|
||||
"Buy_PPOE_Plan": "Comprar Plan PPPoE",
|
||||
"Package": "Paquete",
|
||||
"Order_Internet_Package": "Solicitar paquete de Internet",
|
||||
"Unknown_Command_": "Comando desconocido.",
|
||||
"Checking_payment": "Comprobando el pago",
|
||||
"Create_Transaction_Success": "Crear transacciones exitosas",
|
||||
"You_have_unpaid_transaction": "Tienes transacci\u00f3n impaga",
|
||||
"TripayPayment_Channel": "Canal de pago Tripay",
|
||||
"Payment_Channel": "Canal de pago",
|
||||
"Payment_check_failed_": "El cheque de pago fall\u00f3.",
|
||||
"Order_Package": "Paquete de pedido",
|
||||
"Transactions": "Transacciones",
|
||||
"Payments": "Pagos",
|
||||
"History": "Historial",
|
||||
"Order_History": "Historial de pedidos",
|
||||
"Gateway": "Puerta",
|
||||
"Date_Done": "Fecha de finalizaci\u00f3n",
|
||||
"Unpaid_Order": "Orden no pagada",
|
||||
"Payment_Gateway_Not_Found": "Pasarela de pago no encontrada",
|
||||
"Payment_Gateway_saved_successfully": "Pasarela de pago guardada exitosamente",
|
||||
"ORDER": "ORDEN",
|
||||
"Package_History": "Historial de paquetes",
|
||||
"Buy_History": "Historial de compra",
|
||||
"Activation_History": "Historial de activaci\u00f3n",
|
||||
"Buy_Package": "Comprar paquete",
|
||||
"Email": "Correo",
|
||||
"Company_Footer": "Pie de p\u00e1gina",
|
||||
"Will_show_below_user_pages": "Se mostrar\u00e1n debajo de las p\u00e1ginas de usuario.",
|
||||
"Request_OTP": "Solicitar OTP",
|
||||
"Verification_Code": "Verificacion por codigo",
|
||||
"SMS_Verification_Code": "C\u00f3digo de verificaci\u00f3n por SMS",
|
||||
"Please_enter_your_email_address": "Por favor, introduzca su direcci\u00f3n de correo electr\u00f3nico",
|
||||
"Failed_to_create_Paypal_transaction_": "No se pudo crear la transacci\u00f3n de Paypal.",
|
||||
"Plugin": "Plugin",
|
||||
"Plugin_Manager": "Plugin Manager",
|
||||
"User_Notification": "User Notification",
|
||||
"Expired_Notification": "Expired Notification",
|
||||
"User_will_get_notification_when_package_expired": "User will get notification when package expired",
|
||||
"Expired_Notification_Message": "Expired Notification Message",
|
||||
"Payment_Notification": "Payment Notification",
|
||||
"User_will_get_invoice_notification_when_buy_package_or_package_refilled": "User will get invoice notification when buy package or package refilled",
|
||||
"Current_IP": "Current IP",
|
||||
"Current_MAC": "Current MAC",
|
||||
"Login_Status": "Login Status",
|
||||
"Login_Request_successfully": "Login Request successfully",
|
||||
"Logout_Request_successfully": "Logout Request successfully",
|
||||
"Disconnect_Internet_": "Disconnect Internet?",
|
||||
"Not_Online__Login_now_": "Not Online, Login now?",
|
||||
"You_are_Online__Logout_": "You are Online, Logout?",
|
||||
"Connect_to_Internet_": "Connect to Internet?",
|
||||
"Your_account_not_connected_to_internet": "Your account not connected to internet",
|
||||
"Balance": "Balance",
|
||||
"Balance_System": "Balance System",
|
||||
"Enable_System": "Enable System",
|
||||
"Allow_Transfer": "Allow Transfer",
|
||||
"Telegram_Notification": "Telegram Notification",
|
||||
"SMS_OTP_Registration": "SMS OTP Registration",
|
||||
"Whatsapp_Notification": "Whatsapp Notification",
|
||||
"Plugin_Manager": "Administraci\u00f3n de Plugins",
|
||||
"User_Notification": "Notificaci\u00f3n de usuario",
|
||||
"Expired_Notification": "Notificaci\u00f3n caducada",
|
||||
"User_will_get_notification_when_package_expired": "El usuario recibir\u00e1 una notificaci\u00f3n cuando el paquete caduque",
|
||||
"Expired_Notification_Message": "Mensaje de notificaci\u00f3n caducado",
|
||||
"Payment_Notification": "Notificacion de pago",
|
||||
"User_will_get_invoice_notification_when_buy_package_or_package_refilled": "El usuario recibir\u00e1 una notificaci\u00f3n de factura cuando compre el paquete o recargue el paquete.",
|
||||
"Current_IP": "IP actual",
|
||||
"Current_MAC": "MAC actual",
|
||||
"Login_Status": "Estado de inicio de sesi\u00f3n",
|
||||
"Login_Request_successfully": "Solicitud de inicio de sesi\u00f3n exitosa",
|
||||
"Logout_Request_successfully": "Solicitud de cierre de sesi\u00f3n exitosa",
|
||||
"Disconnect_Internet_": "\u00bfDesconectar Internet?",
|
||||
"Not_Online__Login_now_": "No en l\u00ednea, \u00bfiniciar sesi\u00f3n ahora?",
|
||||
"You_are_Online__Logout_": "Est\u00e1s en l\u00ednea, \u00bfcerrar sesi\u00f3n?",
|
||||
"Connect_to_Internet_": "\u00bfConectado a Internet?",
|
||||
"Your_account_not_connected_to_internet": "Su cuenta no est\u00e1 conectada a Internet",
|
||||
"Balance": "Saldo",
|
||||
"Balance_System": "Sistema de Saldo",
|
||||
"Enable_System": "Habilitar sistema",
|
||||
"Allow_Transfer": "Permitir transferencia",
|
||||
"Telegram_Notification": "Notificaci\u00f3n de Telegram",
|
||||
"SMS_OTP_Registration": "Registro OTP por SMS",
|
||||
"Whatsapp_Notification": "Notificaci\u00f3n de whatsapp",
|
||||
"Tawk_to_Chat_Widget": "Tawk.to Chat Widget",
|
||||
"Invoice": "Invoice",
|
||||
"Country_Code_Phone": "Country Code Phone",
|
||||
"Voucher_activation_menu_will_be_hidden": "Voucher activation menu will be hidden",
|
||||
"Customer_can_deposit_money_to_buy_voucher": "Customer can deposit money to buy voucher",
|
||||
"Allow_balance_transfer_between_customers": "Allow balance transfer between customers",
|
||||
"Refill_Balance": "Refill Balance",
|
||||
"Balance_Plans": "Balance Plans",
|
||||
"Failed_to_create_transaction__": "Failed to create transaction. ",
|
||||
"Failed_to_check_status_transaction__": "Failed to check status transaction. ",
|
||||
"Disable_Voucher": "Disable Voucher",
|
||||
"Reminder_Notification": "Reminder Notification",
|
||||
"Reminder_Notification_Message": "Reminder Notification Message",
|
||||
"Reminder_7_days": "Reminder 7 days",
|
||||
"Reminder_3_days": "Reminder 3 days",
|
||||
"Reminder_1_day": "Reminder 1 day",
|
||||
"PPPOE_Password": "PPPOE Password",
|
||||
"User_Cannot_change_this__only_admin__if_it_Empty_it_will_use_user_password": "User Cannot change this, only admin. if it Empty it will use user password",
|
||||
"Invoice_Balance_Message": "Invoice Balance Message",
|
||||
"Invoice_Notification_Payment": "Invoice Notification Payment",
|
||||
"Balance_Notification_Payment": "Balance Notification Payment",
|
||||
"Buy_Balance": "Buy Balance",
|
||||
"Price": "Price",
|
||||
"Validity": "Validity",
|
||||
"Disable_auto_renewal_": "Disable auto renewal?",
|
||||
"Auto_Renewal_On": "Auto Renewal On",
|
||||
"Enable_auto_renewal_": "Enable auto renewal?",
|
||||
"Auto_Renewal_Off": "Auto Renewal Off",
|
||||
"Invoice_Footer": "Invoice Footer",
|
||||
"Pay_With_Balance": "Pay With Balance",
|
||||
"Pay_this_with_Balance__your_active_package_will_be_overwrite": "Pay this with Balance? your active package will be overwrite",
|
||||
"Success_to_buy_package": "Success to buy package",
|
||||
"Auto_Renewal": "Auto Renewal",
|
||||
"View": "View",
|
||||
"Back": "Back",
|
||||
"Active": "Active",
|
||||
"Transfer_Balance": "Transfer Balance",
|
||||
"Send_your_balance_": "Send your balance?",
|
||||
"Send": "Send",
|
||||
"Cannot_send_to_yourself": "Cannot send to yourself",
|
||||
"Sending_balance_success": "Sending balance success",
|
||||
"From": "From",
|
||||
"To": "To",
|
||||
"insufficient_balance": "insufficient balance",
|
||||
"Send_Balance": "Send Balance",
|
||||
"Received_Balance": "Received Balance",
|
||||
"Minimum_Balance_Transfer": "Minimum Balance Transfer",
|
||||
"Minimum_Transfer": "Minimum Transfer",
|
||||
"Company_Logo": "Company Logo",
|
||||
"Expired_IP_Pool": "Expired IP Pool",
|
||||
"Invoice": "Factura",
|
||||
"Country_Code_Phone": "C\u00f3digo de pa\u00eds Tel\u00e9fono",
|
||||
"Voucher_activation_menu_will_be_hidden": "El men\u00fa de activaci\u00f3n del vale estar\u00e1 oculto",
|
||||
"Customer_can_deposit_money_to_buy_voucher": "El cliente puede depositar dinero para comprar un vale.",
|
||||
"Allow_balance_transfer_between_customers": "Permitir transferencia de saldo entre clientes",
|
||||
"Refill_Balance": "Saldo de recarga",
|
||||
"Balance_Plans": "Planes de Saldo",
|
||||
"Failed_to_create_transaction__": "No se pudo crear la transacci\u00f3n.",
|
||||
"Failed_to_check_status_transaction__": "No se pudo verificar el estado de la transacci\u00f3n.",
|
||||
"Disable_Voucher": "Desactivar Fichas",
|
||||
"Reminder_Notification": "Notificaci\u00f3n de recordatorio",
|
||||
"Reminder_Notification_Message": "Mensaje de notificaci\u00f3n de recordatorio",
|
||||
"Reminder_7_days": "Recordatorio 7 d\u00edas",
|
||||
"Reminder_3_days": "Recordatorio 3 d\u00edas",
|
||||
"Reminder_1_day": "Recordatorio 1 d\u00edas",
|
||||
"PPPOE_Password": "Contrase\u00f1a PPPOE",
|
||||
"User_Cannot_change_this__only_admin__if_it_Empty_it_will_use_user_password": "El usuario no puede cambiar esto, solo el administrador. si est\u00e1 vac\u00edo usar\u00e1 la contrase\u00f1a de usuario",
|
||||
"Invoice_Balance_Message": "Mensaje de saldo de factura",
|
||||
"Invoice_Notification_Payment": "Pago de notificaci\u00f3n de factura",
|
||||
"Balance_Notification_Payment": "Pago de notificaci\u00f3n de saldo",
|
||||
"Buy_Balance": "Comprar Saldo",
|
||||
"Price": "Precio",
|
||||
"Validity": "Validez",
|
||||
"Disable_auto_renewal_": "\u00bfDesactivar la renovaci\u00f3n autom\u00e1tica?",
|
||||
"Auto_Renewal_On": "Renovaci\u00f3n autom\u00e1tica activada",
|
||||
"Enable_auto_renewal_": "\u00bfHabilitar la renovaci\u00f3n autom\u00e1tica?",
|
||||
"Auto_Renewal_Off": "Renovaci\u00f3n autom\u00e1tica desactivada",
|
||||
"Invoice_Footer": "Pie de p\u00e1gina de factura",
|
||||
"Pay_With_Balance": "Pagar con saldo",
|
||||
"Pay_this_with_Balance__your_active_package_will_be_overwrite": "\u00bfPagar esto con Saldo? su paquete activo ser\u00e1 sobrescrito",
|
||||
"Success_to_buy_package": "\u00c9xito al comprar el paquete.",
|
||||
"Auto_Renewal": "Auto renovaci\u00f3n",
|
||||
"View": "Vista",
|
||||
"Back": "Atras",
|
||||
"Active": "Activo",
|
||||
"Transfer_Balance": "Transferir saldo",
|
||||
"Send_your_balance_": "\u00bfEnviar tu saldo?",
|
||||
"Send": "Enviar",
|
||||
"Cannot_send_to_yourself": "No puedes enviarte a ti mismo",
|
||||
"Sending_balance_success": "Env\u00edo de saldo exitoso",
|
||||
"From": "De",
|
||||
"To": "A",
|
||||
"insufficient_balance": "Saldo Insuficiente",
|
||||
"Send_Balance": "Saldo Enviado",
|
||||
"Received_Balance": "Saldo Recibido",
|
||||
"Minimum_Balance_Transfer": "Transferencia de saldo m\u00ednimo",
|
||||
"Minimum_Transfer": "Transferencia m\u00ednima",
|
||||
"Company_Logo": "Logo de la compa\u00f1\u00eda",
|
||||
"Expired_IP_Pool": "Grupo de IP caducado",
|
||||
"Proxy": "Proxy",
|
||||
"Proxy_Server": "Proxy Server",
|
||||
"Proxy_Server_Login": "Proxy Server Login",
|
||||
"Proxy_Server": "Servidor Proxy",
|
||||
"Proxy_Server_Login": "Iniciar sesi\u00f3n en el servidor proxy",
|
||||
"Hotspot_Plan": "Hotspot Plan",
|
||||
"PPPOE_Plan": "PPPOE Plan",
|
||||
"UNKNOWN": "UNKNOWN",
|
||||
"Are_You_Sure_": "Are You Sure?",
|
||||
"Success_to_send_package": "Success to send package",
|
||||
"Target_has_active_plan__different_with_current_plant_": "Target has active plan, different with current plant.",
|
||||
"Recharge_a_friend": "Recharge a friend",
|
||||
"Buy_for_friend": "Buy for friend",
|
||||
"Buy_this_for_friend_account_": "Buy this for friend account?",
|
||||
"Review_package_before_recharge": "Review package before recharge",
|
||||
"Activate": "Activate",
|
||||
"Deactivate": "Deactivate",
|
||||
"Sync": "Sync",
|
||||
"Failed_to_create_PaymeTrust_transaction_": "Failed to create PaymeTrust transaction.",
|
||||
"Location": "Location",
|
||||
"Voucher_Format": "Voucher Format",
|
||||
"Service_Type": "Service Type",
|
||||
"Others": "Others",
|
||||
"PPPOE_Plan": "PPPoE Plan",
|
||||
"UNKNOWN": "DESCONOCIDO",
|
||||
"Are_You_Sure_": "Estas seguro\/a?",
|
||||
"Success_to_send_package": "\u00c9xito al enviar el paquete",
|
||||
"Target_has_active_plan__different_with_current_plant_": "Objetivo tiene plan activo, diferente con planta actual.",
|
||||
"Recharge_a_friend": "Recargar a un amigo\/a",
|
||||
"Buy_for_friend": "Comprar para amigo\/a",
|
||||
"Buy_this_for_friend_account_": "\u00bfCompra esto por cuenta de amigo\/a?",
|
||||
"Review_package_before_recharge": "Revisar paquete antes de recargar",
|
||||
"Activate": "Activado",
|
||||
"Deactivate": "Desactivado",
|
||||
"Sync": "Sincronizar",
|
||||
"Failed_to_create_PaymeTrust_transaction_": "No se pudo crear la transacci\u00f3n PaymeTrust.",
|
||||
"Location": "Localizacion",
|
||||
"Voucher_Format": "Formato de cup\u00f3n",
|
||||
"Service_Type": "Tipo de Servicios",
|
||||
"Others": "Otros",
|
||||
"PPPoE": "PPPoE",
|
||||
"Hotspot": "Hotspot",
|
||||
"Monthly_Registered_Customers": "Monthly Registered Customers",
|
||||
"Total_Monthly_Sales": "Total Monthly Sales",
|
||||
"Active_Users": "Active Users",
|
||||
"Languge_set_to_spanish": "Bahasa disetel ke bahasa Spanyol"
|
||||
"Monthly_Registered_Customers": "Clientes registrados mensualmente",
|
||||
"Total_Monthly_Sales": "Ventas mensuales totales",
|
||||
"Active_Users": "Usuarios activos",
|
||||
"Languge_set_to_spanish": "Idioma establecido en espa\u00f1ol",
|
||||
"Login": "Acceso",
|
||||
"Forgot_Password": "Has olvidado tu contrase\u00f1a",
|
||||
"success": "Logueado con Exito",
|
||||
"Click_Here": "Haga clic aqu\u00ed",
|
||||
"Search_Users": "Buscar usuarios",
|
||||
"SuperAdmin": "Superadministrador",
|
||||
"Lists": "Listas de Clientes",
|
||||
"Vouchers": "Fichas",
|
||||
"Refill_Customer": "Recarga de cliente",
|
||||
"Recharge_Customer": "Recargar Cliente",
|
||||
"Internet_Plan": "Plan de Internet",
|
||||
"Send_Message": "Enviar mensaje",
|
||||
"Single_Customer": "Cliente \u00fanico",
|
||||
"Bulk_Customers": "Clientes al por mayor",
|
||||
"Routers_Maps": "Mapas de enrutadores",
|
||||
"Theme_Voucher": "Cup\u00f3n tem\u00e1tico",
|
||||
"Customer_Announcement": "Anuncio para el cliente",
|
||||
"Payment_Info": "Informaci\u00f3n de pago",
|
||||
"Privacy_Policy": "Pol\u00edtica de Privacidad",
|
||||
"Terms_and_Conditions": "T\u00e9rminos y condiciones",
|
||||
"Maintenance_Mode": "Modo de mantenimiento",
|
||||
"Devices": "Dispositivos",
|
||||
"Logs": "Registros",
|
||||
"Documentation": "Documentaci\u00f3n",
|
||||
"Expired": "Venci\u00f3",
|
||||
"Customers": "Clientes",
|
||||
"Package_Name": "Nombre del paquete",
|
||||
"Created___Expired": "Creado \/ Expirado",
|
||||
"Internet_Package": "Paquete de Internet",
|
||||
"year": "A\u00f1o",
|
||||
"month": "Mes",
|
||||
"week": "Semana",
|
||||
"day": "D\u00eda",
|
||||
"hour": "Hora",
|
||||
"minute": "Minuto",
|
||||
"second": "Segundo",
|
||||
"ago": "Atr\u00e1s",
|
||||
"Prev": "Anterior",
|
||||
"Cron_Job_last_ran_on": "La \u00faltima ejecuci\u00f3n del trabajo cron se realiz\u00f3 el",
|
||||
"All_Users_Insights": "Informaci\u00f3n de todos los usuarios",
|
||||
"Created_Date": "Fecha de creaci\u00f3n",
|
||||
"Ascending": "Ascendente",
|
||||
"Descending": "Descendiendo",
|
||||
"Banned": "Prohibido",
|
||||
"Disabled": "Desactivado",
|
||||
"Inactive": "Inactivo",
|
||||
"Suspended": "Suspendido",
|
||||
"Add": "Agregar",
|
||||
"Account_Type": "Tipo de cuenta",
|
||||
"Contact": "Contacto",
|
||||
"Active_Customers": "Clientes activos",
|
||||
"Extend": "Extender",
|
||||
"Application_Name___Company_Name": "Nombre de la aplicaci\u00f3n \/ Nombre de la empresa",
|
||||
"For_PDF_Reports___Best_size_1078_x_200___uploaded_image_will_be_autosize": "Para informes en PDF | Tama\u00f1o \u00f3ptimo 1078 x 200 | La imagen cargada se ajustar\u00e1 autom\u00e1ticamente",
|
||||
"Print_Max_Char": "Imprimir Max Char",
|
||||
"For_invoice_print_using_Thermal_Printer": "Para imprimir facturas mediante impresora t\u00e9rmica",
|
||||
"Theme": "Tema",
|
||||
"Default": "Por defecto",
|
||||
"Theme_Info": "Informaci\u00f3n del tema",
|
||||
"Recharge_Using": "Recargar usando",
|
||||
"Cash": "Dinero",
|
||||
"Bank_Transfer": "Transferencia bancaria",
|
||||
"This_used_for_admin_to_select_payment_in_recharge__using_comma_for_every_new_options": "Esto se utiliza para que el administrador seleccione el pago en la recarga, utilizando una coma para cada nueva opci\u00f3n.",
|
||||
"Income_reset_date": "Fecha de reinicio de ingresos",
|
||||
"Income_will_reset_every_this_day": "Los ingresos se restablecer\u00e1n cada d\u00eda.",
|
||||
"edit_at_config_php": "editar en config.php",
|
||||
"Hide_Dashboard_Content": "Ocultar el contenido del panel",
|
||||
"No": "No",
|
||||
"Yes": "S\u00ed",
|
||||
"Disable_Registration": "Deshabilitar registro",
|
||||
"Customer_just_Login_with_Phone_number_and_Voucher_Code__Voucher_will_be_password": "El cliente solo debe iniciar sesi\u00f3n con su n\u00famero de tel\u00e9fono y el c\u00f3digo del cup\u00f3n. El cup\u00f3n ser\u00e1 su contrase\u00f1a.",
|
||||
"Redirect_URL_after_Activation": "Redireccionar URL despu\u00e9s de la activaci\u00f3n",
|
||||
"After_Customer_activate_voucher_or_login__customer_will_be_redirected_to_this_url": "Despu\u00e9s de que el Cliente active el cup\u00f3n o inicie sesi\u00f3n, ser\u00e1 redirigido a esta URL",
|
||||
"Enable_Radius": "Habilitar radio",
|
||||
"Radius_Instructions": "Instrucciones de radio",
|
||||
"Extend_Postpaid_Expiration": "Extender vencimiento de pospago",
|
||||
"Allow_Extend": "Permitir extender",
|
||||
"Customer_can_request_to_extend_expirations": "El cliente puede solicitar la extensi\u00f3n de los vencimientos.",
|
||||
"Extend_Days": "Extender d\u00edas",
|
||||
"Confirmation_Message": "Mensaje de confirmaci\u00f3n",
|
||||
"i_agree_to_extends_and_will_paid_full_after_this": "Acepto extender y pagar\u00e9 el total despu\u00e9s de esto.",
|
||||
"Customer_Balance_System": "Sistema de saldo de clientes",
|
||||
"Telegram_Bot_Token": "Token de bot de Telegram",
|
||||
"Telegram_User_Channel_Group_ID": "ID de usuario\/canal\/grupo de Telegram",
|
||||
"You_will_get_Payment_and_Error_notification": "Recibir\u00e1 una notificaci\u00f3n de pago y error.",
|
||||
"Test_SMS": "Prueba de SMS",
|
||||
"SMS_Server_URL": "URL del servidor SMS",
|
||||
"Must_include": "Debe incluir",
|
||||
"it_will_be_replaced_": "Ser\u00e1 reemplazado.",
|
||||
"Or_use_Mikrotik_SMS": "O utilice Mikrotik SMS",
|
||||
"Select_Router": "Seleccionar enrutador",
|
||||
"You_can_use": "Puedes utilizar",
|
||||
"in_here_too_": "Aqu\u00ed tambi\u00e9n.",
|
||||
"Free_Server": "Servidor gratuito",
|
||||
"WhatsApp_Server_URL": "URL del servidor de WhatsApp",
|
||||
"Email_Notification": "Notificaci\u00f3n por correo electr\u00f3nico",
|
||||
"Empty_this_to_use_internal_mail___PHP": "Vac\u00ede esto para usar el correo interno PHP",
|
||||
"SMTP_Username": "Nombre de usuario SMTP",
|
||||
"SMTP_Password": "Contrase\u00f1a SMTP",
|
||||
"SMTP_Security": "Seguridad SMTP",
|
||||
"Mail_Reply_To": "Responder a correo",
|
||||
"Customer_will_reply_email_to_this_address__empty_if_you_want_to_use_From_Address": "El cliente responder\u00e1 el correo electr\u00f3nico a esta direcci\u00f3n; deje el campo vac\u00edo si desea utilizar la direcci\u00f3n de remitente.",
|
||||
"None": "Ninguno",
|
||||
"By_WhatsApp": "Por WhatsApp",
|
||||
"By_SMS": "Por SMS",
|
||||
"By_Email": "Por correo electr\u00f3nico",
|
||||
"From_Direct_Chat_Link_": "Desde el enlace de chat directo.",
|
||||
"Access_Token": "Token de acceso",
|
||||
"Empty_this_to_randomly_created_API_key": "Vac\u00ede esto para crear una clave API aleatoria",
|
||||
"This_Token_will_act_as_SuperAdmin_Admin": "Este token actuar\u00e1 como SuperAdmin\/Admin",
|
||||
"Miscellaneous": "Miscel\u00e1neas",
|
||||
"Enable_Session_Timeout": "Habilitar tiempo de espera de sesi\u00f3n",
|
||||
"Logout_Admin_if_not_Available_Online_a_period_of_time": "Cerrar sesi\u00f3n como administrador si no est\u00e1 disponible o en l\u00ednea durante un per\u00edodo de tiempo",
|
||||
"Timeout_Duration": "Duraci\u00f3n del tiempo de espera",
|
||||
"Enter_the_session_timeout_duration__minutes_": "Introduzca la duraci\u00f3n del tiempo de espera de la sesi\u00f3n (minutos)",
|
||||
"Idle_Timeout__Logout_Admin_if_Idle_for_xx_minutes": "Tiempo de espera inactivo, cerrar sesi\u00f3n como administrador si est\u00e1 inactivo durante xx minutos",
|
||||
"New_Version_Notification": "Notificaci\u00f3n de nueva versi\u00f3n",
|
||||
"Enabled": "Activado",
|
||||
"This_is_to_notify_you_when_new_updates_is_available": "Esto es para notificarle cuando haya nuevas actualizaciones disponibles.",
|
||||
"Router_Check": "Comprobaci\u00f3n del enrutador",
|
||||
"If_enabled__the_system_will_notify_Admin_when_router_goes_Offline__If_admin_have_10_or_more_router_and_many_customers__it_will_get_overlapping__you_can_disabled": "Si est\u00e1 habilitado, el sistema notificar\u00e1 al administrador cuando el enrutador se desconecte. Si el administrador tiene 10 o m\u00e1s enrutadores y muchos clientes, se superpondr\u00e1; puede deshabilitarlo.",
|
||||
"Phone_OTP_Required": "Se requiere OTP en el tel\u00e9fono",
|
||||
"OTP_is_required_when_user_want_to_change_phone_number_and_registration": "Se requiere OTP cuando el usuario desea cambiar el n\u00famero de tel\u00e9fono y el registro",
|
||||
"OTP_Method": "M\u00e9todo OTP",
|
||||
"by_WhatsApp": "por WhatsApp",
|
||||
"By_WhatsApp_and_SMS": "Por WhatsApp y SMS",
|
||||
"The_method_which_OTP_will_be_sent_to_user": "El m\u00e9todo mediante el cual se enviar\u00e1 la OTP al usuario",
|
||||
"Email_OTP_Required": "Se requiere OTP en el correo electr\u00f3nico",
|
||||
"OTP_is_required_when_user_want_to_change_Email_Address": "Se requiere OTP cuando el usuario desea cambiar la direcci\u00f3n de correo electr\u00f3nico",
|
||||
"Extend_Package_Expiry": "Extender la caducidad del paquete",
|
||||
"If_user_buy_same_internet_plan__expiry_date_will_extend": "Si el usuario compra el mismo plan de Internet, la fecha de vencimiento se extender\u00e1",
|
||||
"Show_Bandwidth_Plan": "Mostrar plan de ancho de banda",
|
||||
"_for_Customer": "Para el cliente",
|
||||
"Hotspot_Auth_Method": "M\u00e9todo de autenticaci\u00f3n de punto de acceso",
|
||||
"Api": "API",
|
||||
"Http_Chap": "Http-Chap",
|
||||
"Hotspot_Authentication_Method__Make_sure_you_have_changed_your_hotspot_login_page_": "M\u00e9todo de autenticaci\u00f3n del punto de acceso. Aseg\u00farate de haber cambiado la p\u00e1gina de inicio de sesi\u00f3n del punto de acceso.",
|
||||
"Tax_System": "Sistema tributario",
|
||||
"Enable_Tax_System": "Habilitar el sistema tributario",
|
||||
"Tax_will_be_calculated_in_Internet_Plan_Price": "El impuesto se calcular\u00e1 en el precio del plan de Internet.",
|
||||
"Tax_Rate": "Tasa de impuesto",
|
||||
"Custome": "Personalizado",
|
||||
"Tax_Rates_in_percentage": "Tasas de impuestos en porcentaje",
|
||||
"Custome_Tax_Rate": "Tasa de impuesto al cliente",
|
||||
"Enter_Custome_Tax_Rate": "Introduzca la tasa de impuesto personalizada",
|
||||
"Enter_the_custom_tax_rate__e_g___3_75_for_3_75__": "Introduzca la tasa de impuesto personalizada (por ejemplo, 3,75 para 3,75 %)",
|
||||
"Authentication": "Autenticaci\u00f3n",
|
||||
"Github_Username": "Nombre de usuario de Github",
|
||||
"Github_Token": "Token de Github",
|
||||
"Create_GitHub_personal_access_token": "Crear un token de acceso personal de GitHub",
|
||||
"only_need_repo_scope": "Solo se necesita el \u00e1mbito del repositorio",
|
||||
"This_will_allow_you_to_download_plugin_from_private_paid_repository": "Esto le permitir\u00e1 descargar el complemento desde un repositorio privado\/pago.",
|
||||
"Expired_Cronjob_Every_5_Minutes": "Cronjob vencido cada 5 minutos",
|
||||
"Expired_Cronjob_Every_1_Hour": "Cronjob vencido cada 1 hora",
|
||||
"Reminder_Cronjob_Every_7_AM": "Recordatorio de Cronjob cada 7 a. m.",
|
||||
"Email_not_sent__Mailer_Error__": "Correo electr\u00f3nico no enviado, error de Mailer:",
|
||||
"Language_Editor": "Editor de idioma",
|
||||
"Radius_Package": "Paquete Radius",
|
||||
"Change_title_in_user_Plan_order": "Cambiar t\u00edtulo en el pedido del plan de usuario",
|
||||
"Hotspot_Package": "Paquete de punto de acceso",
|
||||
"PPPOE_Package": "Paquete PPPoE",
|
||||
"VPN_Package": "Paquete VPN",
|
||||
"Translation": "Traducci\u00f3n",
|
||||
"Agent": "Agente",
|
||||
"Session_has_expired__Please_log_in_again_": "La sesi\u00f3n ha expirado. Por favor, inicie sesi\u00f3n nuevamente.",
|
||||
"danger": "Peligro",
|
||||
"City": "Pais",
|
||||
"District": "Distrito",
|
||||
"State": "Estado",
|
||||
"Zip": "C\u00f3digo Postal",
|
||||
"Personal": "Personal",
|
||||
"Bandwidth": "Ancho de banda",
|
||||
"Translation_saved_Successfully": "La traducci\u00f3n se guard\u00f3 correctamente",
|
||||
"Filter": "Filtrar",
|
||||
"Show_chart": "Mostrar gr\u00e1fico",
|
||||
"Start_Date": "Fecha de inicio",
|
||||
"Start_time": "Hora de inicio",
|
||||
"End_Date": "Fecha de finalizaci\u00f3n",
|
||||
"End_Time": "Fin del tiempo",
|
||||
"Internet_Plans": "Planes de Internet",
|
||||
"Methods": "M\u00e9todos",
|
||||
"AREA1": "\u00c1REA 1",
|
||||
"AREA2": "\u00c1REA 2",
|
||||
"AREA4": "\u00c1REA 4",
|
||||
"AREA3": "\u00c1REA 3",
|
||||
"MK_ADMIN": "Administrador de MK",
|
||||
"AREA6": "\u00c1REA 6",
|
||||
"Max_30_days": "M\u00e1ximo 30 d\u00edas",
|
||||
"Total": "Total",
|
||||
"Information": "Informaci\u00f3n",
|
||||
"Export_and_Print_will_show_all_data_without_pagination": "Exportar e imprimir mostrar\u00e1 todos los datos sin paginaci\u00f3n",
|
||||
"Maps": "Mapas",
|
||||
"Custom_Fields": "Campos personalizados",
|
||||
"Cron_appear_not_been_setup__please_check_your_cron_setup_": "Aparece que no se ha configurado Cron, consulte su configuraci\u00f3n de Cron.",
|
||||
"Check_if_Router_Online_": "\u00bfVerifique si Router Online?",
|
||||
"To_check_whether_the_Router_is_online_or_not__please_visit_the_following_page": "Para verificar si el enrutador est\u00e1 en l\u00ednea o no, visite la p\u00e1gina siguiente",
|
||||
"Cek_Now": "Cek ahora",
|
||||
"Enable": "Permitir",
|
||||
"Disable": "Desactivar",
|
||||
"Router_Name___Location": "Nombre \/ ubicaci\u00f3n del enrutador",
|
||||
"Coordinates": "Coordenadas",
|
||||
"Coverage": "Cobertura",
|
||||
"Continue_the_process_of_changing_Routers_": "\u00bfContinuar el proceso de cambiar los enrutadores?",
|
||||
"First_Name": "Nombre",
|
||||
"Last_Name": "Apellido",
|
||||
"Plugin_Installer": "Instalador de plugin",
|
||||
"Upload_Zip_Plugin_Theme_Device": "Subir el complemento\/tema\/dispositivo con zip",
|
||||
"Install": "Instalar",
|
||||
"CPU_Load": "Carga de la CPU",
|
||||
"Temperature": "Temperatura",
|
||||
"Voltage": "Voltaje",
|
||||
"Wireless_Status": "Estado inal\u00e1mbrico",
|
||||
"Interface_Status": "Estado de la interfaz",
|
||||
"Hotspot_Online_Users": "Usuarios en l\u00ednea de hotspot",
|
||||
"PPPoE_Online_Users": "Usuarios en l\u00ednea de PPPOE",
|
||||
"Traffic_Monitor": "Monitor de tr\u00e1fico",
|
||||
"Interface_Name": "Nombre de la interfaz",
|
||||
"Tx__bytes_Out_": "Tx (bytes fuera)",
|
||||
"Rx__bytes_In_": "Rx (bytes en)",
|
||||
"Total_Usage": "Uso total",
|
||||
"Uptime": "Tiempo de actividad",
|
||||
"Server": "Servidor",
|
||||
"Mac_Address": "Direcci\u00f3n MAC",
|
||||
"Session_Time_Left": "Tiempo de sesi\u00f3n restante",
|
||||
"Upload__RX_": "Cargue (RX)",
|
||||
"Download__TX_": "Descargar (TX)",
|
||||
"Service": "Servicio",
|
||||
"Caller_ID": "Identificador de llamadas",
|
||||
"Download": "Descargar",
|
||||
"Upload": "Subir",
|
||||
"Interface": "Interfaz",
|
||||
"Last_Ip": "\u00daltima IP",
|
||||
"Last_Activity": "\u00daltima actividad",
|
||||
"Signal_Strength": "Resistencia a la se\u00f1al",
|
||||
"Tx___Rx_CCQ": "TX \/ RX CCQ",
|
||||
"Rx_Rate": "Tasa de rx",
|
||||
"Tx_Rate": "Tasa de tx",
|
||||
"Interace": "Interacci\u00f3n",
|
||||
"TX": "Tx",
|
||||
"RX": "Rx",
|
||||
"Date_Time": "Fecha\/hora",
|
||||
"Topic": "Tema",
|
||||
"Send_Personal_Message": "Enviar mensaje personal",
|
||||
"Send_Via": "Enviar",
|
||||
"via_SMS": "a trav\u00e9s de SMS",
|
||||
"Via_WhatsApp": "A trav\u00e9s de whatsapp",
|
||||
"Via_WhatsApp_and_SMS": "A trav\u00e9s de whatsapp y sms",
|
||||
"Compose_your_message___": "Componga tu mensaje ...",
|
||||
"Use_placeholders_": "Use marcadores de posici\u00f3n:",
|
||||
"Customer_Name": "Nombre del cliente",
|
||||
"Customer_Username": "Nombre de usuario del cliente",
|
||||
"Customer_Phone": "Tel\u00e9fono del cliente",
|
||||
"Your_Company_Name": "Nombre de su empresa",
|
||||
"Sign_in_into_your_account": "Inicie sesi\u00f3n en su cuenta",
|
||||
"Usernames": "Nombre de usuario",
|
||||
"Don_t_have_an_account_": "\u00bfNo tienes una cuenta?",
|
||||
"General": "General",
|
||||
"Pretty_URL": "Bonita url",
|
||||
"rename__htaccess_firewall_to__htaccess": "renombrar .htaccess_firewall a .htaccess",
|
||||
"Customer_Login_Page_Settings": "Configuraci\u00f3n de la p\u00e1gina de inicio de sesi\u00f3n del cliente",
|
||||
"Choose_Template": "Elija plantilla",
|
||||
"Custom": "Costumbre",
|
||||
"Select_your_login_template_type": "Seleccione su tipo de plantilla de inicio de sesi\u00f3n",
|
||||
"Select_Login_Page": "Seleccione la p\u00e1gina de inicio de sesi\u00f3n",
|
||||
"Select_your_preferred_login_template": "Seleccione su plantilla de inicio de sesi\u00f3n preferida",
|
||||
"Page_Heading___Company_Name": "Encabezado de p\u00e1gina \/ nombre de la empresa",
|
||||
"This_Name_will_be_shown_on_the_login_wallpaper": "Este nombre se mostrar\u00e1 en el fondo de pantalla de inicio de sesi\u00f3n.",
|
||||
"Page_Description": "Descripci\u00f3n de la p\u00e1gina",
|
||||
"This_will_also_display_on_wallpaper__You_can_use_html_tag": "Esto tambi\u00e9n se mostrar\u00e1 en papel tapiz, puede usar la etiqueta HTML",
|
||||
"Favicon": "Favic\u00f3n",
|
||||
"Best_size_30_x_30___uploaded_image_will_be_autosize": "El mejor tama\u00f1o 30 x 30 | La imagen cargada se automatizar\u00e1",
|
||||
"Login_Page_Logo": "Logotipo de la p\u00e1gina de inicio de sesi\u00f3n",
|
||||
"Best_size_300_x_60___uploaded_image_will_be_autosize": "El mejor tama\u00f1o 300 x 60 | La imagen cargada se automatizar\u00e1",
|
||||
"Login_Page_Wallpaper": "Fondo de pantalla de la p\u00e1gina de inicio de sesi\u00f3n",
|
||||
"Best_size_1920_x_1080___uploaded_image_will_be_autosize": "El mejor tama\u00f1o 1920 x 1080 | La imagen cargada se automatizar\u00e1",
|
||||
"Registration": "Registro",
|
||||
"Allow_Registration": "Permitir el registro",
|
||||
"No_Registration": "Sin registro",
|
||||
"Registration_Username": "Nombre de usuario de registro",
|
||||
"Photo_Required": "Foto requerida",
|
||||
"Customer_Registration_need_to_upload_their_photo": "El registro del cliente necesita subir su foto",
|
||||
"Customer_Registration_need_to_validate_using_OTP": "El registro del cliente debe validar con OTP",
|
||||
"For_Registration_and_Update_Phone_Number": "Para el n\u00famero de tel\u00e9fono de registro y actualizaci\u00f3n",
|
||||
"Notify_Admin": "Notificar a administrador",
|
||||
"Notify_Admin_upon_self_registration": "Notificar al administrador sobre el registro autom\u00e1tico",
|
||||
"Mandatory_Fields": "Campos obligatorios",
|
||||
"Security": "Seguridad",
|
||||
"Single_Admin_Session": "Sesi\u00f3n de administrador \u00fanica",
|
||||
"Admin_can_only_have_single_session_login__it_will_logout_another_session": "El administrador solo puede tener inicio de sesi\u00f3n de una sola sesi\u00f3n, iniciar\u00e1 sesi\u00f3n en otra sesi\u00f3n",
|
||||
"Enable_CSRF_Validation": "Habilitar la validaci\u00f3n de CSRF",
|
||||
"Cross_site_request_forgery": "Falsificaci\u00f3n de solicitud de sitio cruzado",
|
||||
"SMS_Notification": "Notificaci\u00f3n de SMS",
|
||||
"Mikrotik_SMS_Command": "Comando de mikrotik sms",
|
||||
"Tax_Rates_by_percentage": "Tasas impositivas por porcentaje",
|
||||
"Settings_For_Mikrotik": "Configuraci\u00f3n para Mikrotik",
|
||||
"Settings_For_Cron_Expired": "Configuraci\u00f3n para Cron expirado",
|
||||
"Expired_Cronjob_Every_5_Minutes__Recommended_": "Cronjob vencido cada 5 minutos [recomendado]",
|
||||
"Settings_For_Cron_Reminder": "Configuraci\u00f3n para el recordatorio de Cron",
|
||||
"Login_Page_Settings_Saved_Successfully": "Configuraci\u00f3n de la p\u00e1gina de inicio de sesi\u00f3n guardada correctamente",
|
||||
"Logout_Successful": "INCOMPTIR SEXITO",
|
||||
"warning": "Advertencia",
|
||||
"Go_Back": "Volver",
|
||||
"Validate": "Validar",
|
||||
"Forgot_Usernames": "Olvid\u00e9 nombres de usuario",
|
||||
"You_are_already_logged_in": "Ya est\u00e1s iniciado",
|
||||
"Hello": "Hola",
|
||||
"your_internet_package": "Tu paquete de Internet",
|
||||
"has_been_expired": "ha sido expirado",
|
||||
"will_be_replaced_with_Customer_Name": "ser\u00e1 reemplazado por el nombre del cliente",
|
||||
"will_be_replaced_with_Customer_username": "ser\u00e1 reemplazado por el nombre de usuario del cliente",
|
||||
"will_be_replaced_with_Package_name": "ser\u00e1 reemplazado por el nombre del paquete",
|
||||
"will_be_replaced_with_Package_price": "ser\u00e1 reemplazado por el precio del paquete",
|
||||
"additional_bills_for_customers": "facturas adicionales para los clientes",
|
||||
"will_be_replaced_with_Expiration_date": "ser\u00e1 reemplazado por la fecha de vencimiento",
|
||||
"Your_Company_Name_at_Settings": "Nombre de su empresa en la configuraci\u00f3n",
|
||||
"Your_Company_Address_at_Settings": "Direcci\u00f3n de su empresa en la configuraci\u00f3n",
|
||||
"Your_Company_Phone_at_Settings": "Tel\u00e9fono de su empresa en la configuraci\u00f3n",
|
||||
"Invoice_number": "N\u00famero de factura",
|
||||
"Date_invoice_created": "Factura de fecha creada",
|
||||
"Payment_gateway_user_paid_from": "El usuario de la pasarela de pago pagado por",
|
||||
"Payment_channel_user_paid_from": "Usuario de canal de pago pagado desde",
|
||||
"is_Hotspot_or_PPPOE": "es hotspot o pppoe",
|
||||
"Internet_Package_Prices": "Precios de paquetes de Internet",
|
||||
"Receiver_name": "Nombre del receptor",
|
||||
"Username_internet": "Nombre de usuario Internet",
|
||||
"User_password": "Contrase\u00f1a de usuario",
|
||||
"Expired_datetime": "Expirado de fecha y hora",
|
||||
"For_Notes_by_admin": "Para notas de admin",
|
||||
"Transaction_datetime": "Transacci\u00f3n data de data",
|
||||
"Balance_Before": "Equilibrar antes",
|
||||
"Balance_After": "Equilibrar",
|
||||
"Welcome_Message": "Mensaje de bienvenida",
|
||||
"will_be_replaced_with_Customer_password": "ser\u00e1 reemplazado por la contrase\u00f1a del cliente",
|
||||
"will_be_replaced_with_Customer_Portal_URL": "ser\u00e1 reemplazado por URL del portal del cliente",
|
||||
"will_be_replaced_with_Company_Name": "ser\u00e1 reemplazado por el nombre de la empresa",
|
||||
"Save": "Guardar",
|
||||
"Save_as_template": "Guardar como plantilla",
|
||||
"Template_Name": "Nombre de plantilla",
|
||||
"Package_Price": "Precio del paquete",
|
||||
"Voucher_Code": "C\u00f3digo de cup\u00f3n",
|
||||
"Voucher_Package": "Paquete de cupones",
|
||||
"Counter": "Contador",
|
||||
"Sub_District": "Distrito",
|
||||
"Ward": "Código Postal",
|
||||
"Profile": "Perfil",
|
||||
"Photo": "Foto",
|
||||
"Phone": "Tel\u00e9fono",
|
||||
"Credentials": "Cartas credenciales",
|
||||
"RB5009_39": "RB5009-39",
|
||||
"Admin": "Administraci\u00f3n",
|
||||
"VPN_Plans": "Planes VPN",
|
||||
"Using": "Usando",
|
||||
"Postpaid_Recharge_for_the_first_time_use": "Recarga pospago por primera vez uso",
|
||||
"Or": "O",
|
||||
"Confirm": "Confirmar",
|
||||
"Name": "Nombre",
|
||||
"Plan": "Plan",
|
||||
"Resend": "Revender",
|
||||
"Home_Address": "Direcci\u00f3n de la casa",
|
||||
"Other": "Otro",
|
||||
"Business": "Negocio",
|
||||
"Not_Working_for_freeradius": "No funciona para freeradius",
|
||||
"Also_Working_for_freeradius": "Tambi\u00e9n trabajando para freeradius",
|
||||
"User_Cannot_change_this__only_admin__if_it_Empty_it_will_use_Customer_Credentials": "El usuario no puede cambiar esto, solo administrador. Si se vac\u00eda, usar\u00e1 las credenciales del cliente",
|
||||
"Send_welcome_message": "Enviar mensaje de bienvenida",
|
||||
"Notification_via": "Notificaci\u00f3n a trav\u00e9s de",
|
||||
"SMS": "SMS",
|
||||
"WA": "Whatsapp",
|
||||
"Attributes": "Atributos",
|
||||
"Additional_Information": "informaci\u00f3n adicional",
|
||||
"City_of_Resident": "Ciudad del residente",
|
||||
"State_of_Resident": "Estado de residente",
|
||||
"Zip_Code": "C\u00f3digo postal",
|
||||
"Continue_the_process_of_adding_Customer_Data_": "\u00bfContinuar el proceso de agregar datos de clientes?",
|
||||
"Customer_cannot_buy_disabled_Package__but_admin_can_recharge_it__use_it_if_you_want_only_admin_recharge_it": "El cliente no puede comprar el paquete discapacitado, pero el administrador puede recargarlo, usarlo si solo desea recargarlo de administrador",
|
||||
"Postpaid_will_have_fix_expired_date": "Postpaid tendr\u00e1 una fecha vencida",
|
||||
"Prepaid": "Pagado",
|
||||
"Postpaid": "Pospago",
|
||||
"Personal_Package_will_only_show_to_personal_Customer__Business_Package_will_only_show_to_Business_Customer": "El paquete personal solo se mostrar\u00e1 al cliente personal, el paquete comercial solo se mostrar\u00e1 al cliente empresarial",
|
||||
"Device": "Dispositivo",
|
||||
"This_Device_are_the_logic_how_PHPNuxBill_Communicate_with_Mikrotik_or_other_Devices": "Este dispositivo es la l\u00f3gica de c\u00f3mo PhpNuxbill se comunica con Mikrotik u otros dispositivos",
|
||||
"Price_Before_Discount": "Precio antes de descuento",
|
||||
"For_Discount_Rate__this_is_price_before_get_discount__must_be_more_expensive_with_real_price": "Para una tasa de descuento, este es el precio antes de obtener descuento, debe ser m\u00e1s costoso con un precio real",
|
||||
"1_Period___1_Month__Expires_the_20th_of_each_month": "1 per\u00edodo = 1 mes, expira el 20 de cada mes",
|
||||
"Expired_Date": "Fecha vencida",
|
||||
"Expired_will_be_this_date_every_month": "Caducado ser\u00e1 esta fecha cada mes",
|
||||
"Expired_Action": "Acci\u00f3n vencida",
|
||||
"Optional": "Opcional",
|
||||
"Expired_Internet_Plan": "Plan de Internet vencido",
|
||||
"When_Expired__customer_will_be_move_to_selected_internet_plan": "Cuando expire, el cliente se trasladar\u00e1 al plan de Internet seleccionado",
|
||||
"on_login___on_up": "en el login \/ encendido",
|
||||
"on_logout___on_down": "On-Logout \/ On-Down",
|
||||
"Continue_the_PPPoE_Package_change_process_": "\u00bfContinuar el proceso de cambio de paquete PPPOE?",
|
||||
"Period": "Per\u00edodo",
|
||||
"Login_as_Customer": "Iniciar sesi\u00f3n como cliente",
|
||||
"Rate": "Tasa",
|
||||
"Create_Bandwidth_Package_for_expired_Internet_Package": "Crear paquete de ancho de banda para paquete de Internet vencido",
|
||||
"When_customer_expired__you_can_move_it_to_Expired_Internet_Package": "Cuando el cliente caduque, podr\u00e1 moverlo a Paquete de Internet Caducado",
|
||||
"Category": "Categor\u00eda",
|
||||
"Create_expired_Internet_Plan": "Crear plan de Internet vencido",
|
||||
"When_customer_expired__you_can_move_it_to_Expired_Internet_Plan": "Cuando el cliente caduque, podr\u00e1 moverlo a Plan de Internet Caducado",
|
||||
"Personal_Package_will_only_show_to_personal_Customer__Business_package_will_only_show_to_Business_Customer": "El paquete personal solo se mostrar\u00e1 a los clientes personales, el paquete comercial solo se mostrar\u00e1 a los clientes comerciales",
|
||||
"Continue_the_process_of_adding_the_PPPoE_Package_": "\u00bfContinuar con el proceso de agregar el paquete PPPoE?",
|
||||
"Face_Detection": "Detecci\u00f3n de rostros",
|
||||
"Customer_cannot_login_again": "El cliente no puede iniciar sesi\u00f3n nuevamente",
|
||||
"Customer_can_login_but_cannot_buy_internet_package__Admin_cannot_recharge_customer": "El cliente puede iniciar sesi\u00f3n pero no puede comprar un paquete de Internet. El administrador no puede recargar al cliente.",
|
||||
"Don_t_forget_to_deactivate_all_active_package_too": "No olvides desactivar tambi\u00e9n todos los paquetes activos.",
|
||||
"Not_Working_with_Freeradius_Mysql": "No funciona con Freeradius Mysql",
|
||||
"Continue_the_Customer_Data_change_process_": "\u00bfContinuar con el proceso de cambio de datos del cliente?",
|
||||
"Port_Pool": "Grupo de puerto",
|
||||
"New_port": "Nuevo puerto",
|
||||
"Port_Name": "Nombre del puerto",
|
||||
"Public_IP": "IP p\u00fablica",
|
||||
"Range_Port": "Rango de Puertos",
|
||||
"Add_Port_Pool": "Agregar grupo de puertos",
|
||||
"Continue_the_process_of_adding_Ports_": "\u00bfContinuar con el proceso de agregar puertos?",
|
||||
"Continue_the_VPN_creation_process_": "\u00bfContinuar con el proceso de creaci\u00f3n de VPN?",
|
||||
"": "",
|
||||
"Local_IP": "IP local",
|
||||
"Test_Connection": "Conexi\u00f3n de prueba",
|
||||
"Continue_the_process_of_adding_Routers_": "\u00bfContinuar con el proceso de agregar enrutadores?",
|
||||
"Continue_the_Pool_addition_process_": "\u00bfContinuar con el proceso de adici\u00f3n de la piscina?",
|
||||
"Private_IP": "IP privada",
|
||||
"Sync_account_if_you_failed_login_to_internet": "Sincronizar cuenta si no se pudo iniciar sesi\u00f3n en Internet",
|
||||
"Data_Change": "Cambio de datos",
|
||||
"Face_Detect": "Detecci\u00f3n de rostro",
|
||||
"Email_Address": "Direcci\u00f3n de correo electr\u00f3nico",
|
||||
"Transaction_History_List": "Lista de historial de transacciones",
|
||||
"Contabo": "Contabo",
|
||||
"Not_Active": "No activo",
|
||||
"New_Service_Package": "Nuevo paquete de servicios",
|
||||
"Limit": "L\u00edmite",
|
||||
"Time": "Tiempo",
|
||||
"Data": "Datos",
|
||||
"ID": "IDENTIFICACI\u00d3N",
|
||||
"Create_expired_Internet_Package": "Crear paquete de Internet vencido",
|
||||
"Oops__The_page_you_are_looking_for_was_not_found": "\u00a1Ups! La p\u00e1gina que est\u00e1 buscando no fue encontrada",
|
||||
"Back_to_Dashboard": "Volver al panel de control",
|
||||
"Add_User": "Agregar usuario",
|
||||
"Report_Viewer": "Visor de informes",
|
||||
"Super_Administrator": "Super administrador",
|
||||
"Send_Notification": "Enviar notificaci\u00f3n",
|
||||
"Don_t_Send": "No env\u00ede",
|
||||
"Registration_successful": "Registro exitoso",
|
||||
"New_User_Registration": "Registro de nuevo usuario",
|
||||
"New_Field": "Nuevo campo",
|
||||
"Installed_Devices": "Dispositivos instalados",
|
||||
"Miscellaneous_Settings": "Configuraciones varias",
|
||||
"Display_bandwidth_plan_for_customer": "Mostrar plan de ancho de banda para el cliente",
|
||||
"Radius_Rest_Interim_Update": "Actualizaci\u00f3n provisional de Radius Rest",
|
||||
"in_minutes__leave_0_to_disable_this_feature_": "en minutos, deje 0 para deshabilitar esta funci\u00f3n.",
|
||||
"Check_if_Customer_Online": "Verificar si el cliente est\u00e1 en l\u00ednea",
|
||||
"This_will_show_is_Customer_currently_is_online_or_not": "Esto mostrar\u00e1 si el cliente est\u00e1 actualmente en l\u00ednea o no.",
|
||||
"Allow_Balance_Custom_Amount": "Permitir saldo Importe personalizado",
|
||||
"Allow_Customer_buy_balance_with_any_amount": "Permitir al Cliente comprar saldo con cualquier monto",
|
||||
"Make_sure_you_use_API_Port__Default_8728": "Aseg\u00farese de utilizar el puerto API, predeterminado 8728",
|
||||
"Make_sure_Username_and_Password_are_correct": "Aseg\u00farese de que el nombre de usuario y la contrase\u00f1a sean correctos",
|
||||
"Make_sure_your_hosting_not_blocking_port_to_external": "Aseg\u00farese de que su hosting no bloquee el puerto al externo",
|
||||
"Make_sure_your_Mikrotik_accessible_from_PHPNuxBill": "Aseg\u00farese de que su Mikrotik sea accesible desde PHPNuxBill",
|
||||
"If_you_just_update_PHPNuxBill_from_upload_files__try_click_Update": "Si simplemente actualiza PHPNuxBill desde la carga de archivos, intente hacer clic en Actualizar",
|
||||
"Update": "Actualizar",
|
||||
"Update_PHPNuxBill": "Actualizar PHPNuxBill",
|
||||
"Ask_Github_Community": "Pregunta a la comunidad de Github",
|
||||
"Ask_Telegram_Community": "Pregunta a la comunidad de Telegram"
|
||||
}
|
@ -1483,6 +1483,14 @@ class ORM implements ArrayAccess
|
||||
return $this->_add_simple_where($column_name, 'LIKE', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any WHERE ... LIKE clause to your query.
|
||||
*/
|
||||
public function where_likes($column = null, $values = null)
|
||||
{
|
||||
return $this->_addWhere('(' . implode(' LIKE ? OR ', $column) . ' LIKE ? )', $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add where WHERE ... NOT LIKE clause to your query.
|
||||
*/
|
||||
|
@ -1,159 +1,211 @@
|
||||
{
|
||||
"2023.8.9": [
|
||||
"ALTER TABLE `tbl_customers` ADD `balance` decimal(15,2) NOT NULL DEFAULT 0.00 COMMENT 'For Money Deposit' AFTER `email`;",
|
||||
"CREATE TABLE `tbl_customers_meta` (`id` int(11) NOT NULL, `customer_id` int(11) NOT NULL,`meta_key` varchar(64) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `meta_value` longtext COLLATE utf8mb4_general_ci) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;",
|
||||
"ALTER TABLE `tbl_customers_meta` ADD PRIMARY KEY (`id`);",
|
||||
"ALTER TABLE `tbl_customers_meta` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;"
|
||||
],
|
||||
"2023.8.14": [
|
||||
"ALTER TABLE `tbl_customers` ADD `pppoe_password` varchar(45) NOT NULL DEFAULT '' 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 '' 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`;",
|
||||
"ALTER TABLE `tbl_transactions` ADD `recharged_time` time NOT NULL DEFAULT '00:00:00' AFTER `recharged_on`;"
|
||||
],
|
||||
"2023.9.5": [
|
||||
"DROP TABLE `tbl_language`;",
|
||||
"ALTER TABLE `tbl_plans` ADD `pool_expired` varchar(40) NOT NULL DEFAULT '' AFTER `pool`;"
|
||||
],
|
||||
"2023.9.27": [
|
||||
"ALTER TABLE `tbl_plans` CHANGE `type` `type` ENUM('Hotspot','PPPOE','Balance','Radius') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;",
|
||||
"ALTER TABLE `tbl_transactions` CHANGE `type` `type` ENUM('Hotspot','PPPOE','Balance','Radius') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;"
|
||||
],
|
||||
"2023.9.28": [
|
||||
"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;"
|
||||
],
|
||||
"2023.10.1": [
|
||||
"ALTER TABLE `tbl_plans` ADD `is_radius` TINYINT(1) NOT NULL DEFAULT '0' COMMENT '1 is radius' AFTER `routers`; "
|
||||
],
|
||||
"2023.10.24": [
|
||||
"ALTER TABLE `nas` ADD `routers` VARCHAR(32) NOT NULL DEFAULT '' AFTER `description`;"
|
||||
],
|
||||
"2023.12.15": [
|
||||
"ALTER TABLE `tbl_customers` ADD `service_type` ENUM('Hotspot','PPPoE','Others') DEFAULT 'Others' COMMENT 'For selecting user type' AFTER `balance`;"
|
||||
],
|
||||
"2024.1.11": [
|
||||
"ALTER TABLE `tbl_plans` ADD `allow_purchase` ENUM('yes','no') DEFAULT 'yes' COMMENT 'allow to show package in buy package page' AFTER `enabled`;"
|
||||
],
|
||||
"2024.2.7": [
|
||||
"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`;"
|
||||
],
|
||||
"2024.2.12": [
|
||||
"ALTER TABLE `tbl_users` CHANGE `user_type` `user_type` ENUM('SuperAdmin','Admin','Report','Agent','Sales') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;"
|
||||
],
|
||||
"2024.2.15": [
|
||||
"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`;"
|
||||
],
|
||||
"2024.2.16": [
|
||||
"ALTER TABLE `tbl_customers` ADD `created_by` INT NOT NULL DEFAULT '0' AFTER `auto_renewal`;"
|
||||
],
|
||||
"2024.2.19": [
|
||||
"CREATE TABLE `tbl_customers_fields` (`id` INT PRIMARY KEY AUTO_INCREMENT, `customer_id` INT NOT NULL, `field_name` VARCHAR(255) NOT NULL, `field_value` VARCHAR(255) NOT NULL, FOREIGN KEY (customer_id) REFERENCES tbl_customers(id));"
|
||||
],
|
||||
"2024.2.20" : [
|
||||
"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`;"
|
||||
],
|
||||
"2024.2.20.1" : [
|
||||
"DROP TABLE IF EXISTS `tbl_customers_meta`;"
|
||||
],
|
||||
"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`;"
|
||||
],
|
||||
"2024.5.17" : [
|
||||
"ALTER TABLE `tbl_customers` ADD `status` ENUM('Active','Banned','Disabled') NOT NULL DEFAULT 'Active' AFTER `auto_renewal`;"
|
||||
],
|
||||
"2024.5.18" : [
|
||||
"ALTER TABLE `tbl_customers` CHANGE `status` `status` ENUM('Active','Banned','Disabled','Inactive','Limited','Suspended') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'Active';"
|
||||
],
|
||||
"2024.5.20" : [
|
||||
"ALTER TABLE `tbl_customers` ADD `city` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci AFTER `address`, ADD `district` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci AFTER `city`, ADD `state` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci AFTER `district`, ADD `zip` VARCHAR(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci AFTER `state`;"
|
||||
],
|
||||
"2024.6.5" : [
|
||||
"ALTER TABLE `tbl_plans` ADD `price_old` VARCHAR(40) NOT NULL DEFAULT '' AFTER `price`;",
|
||||
"ALTER TABLE `tbl_plans` ADD `device` VARCHAR(32) NOT NULL DEFAULT '' AFTER `plan_type`;"
|
||||
],
|
||||
"2024.6.10" : [
|
||||
"ALTER TABLE `tbl_pool` ADD `local_ip` VARCHAR(40) NOT NULL DEFAULT '' AFTER `pool_name`;"
|
||||
],
|
||||
"2024.6.11" : [
|
||||
"ALTER TABLE `tbl_plans` ADD `plan_expired` INT NOT NULL DEFAULT '0' AFTER `pool`;",
|
||||
"ALTER TABLE `tbl_plans` DROP `pool_expired`, DROP `list_expired`;"
|
||||
],
|
||||
"2024.6.19" : [
|
||||
"ALTER TABLE `tbl_plans` ADD `expired_date` TINYINT(1) NOT NULL DEFAULT '20' AFTER `plan_expired`;"
|
||||
],
|
||||
"2024.6.21" : [
|
||||
"ALTER TABLE `tbl_plans` ADD `on_login` TEXT NULL DEFAULT NULL AFTER `device`;",
|
||||
"ALTER TABLE `tbl_plans` ADD `on_logout` TEXT NULL DEFAULT NULL AFTER `on_login`;"
|
||||
],
|
||||
"2024.7.6" : [
|
||||
"CREATE TABLE IF NOT EXISTS `rad_acct` ( `id` bigint NOT NULL, `acctsessionid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `username` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `realm` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `nasid` varchar(32) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `nasipaddress` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `nasportid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, `nasporttype` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, `framedipaddress` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',`acctstatustype` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, `macaddr` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `dateAdded` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;",
|
||||
"ALTER TABLE `rad_acct` ADD PRIMARY KEY (`id`), ADD KEY `username` (`username`), ADD KEY `framedipaddress` (`framedipaddress`), ADD KEY `acctsessionid` (`acctsessionid`), ADD KEY `nasipaddress` (`nasipaddress`);",
|
||||
"ALTER TABLE `rad_acct` MODIFY `id` bigint NOT NULL AUTO_INCREMENT;"
|
||||
],
|
||||
"2024.7.24" : [
|
||||
"ALTER TABLE `tbl_voucher` ADD `used_date` DATETIME NULL DEFAULT NULL AFTER `status`;",
|
||||
"UPDATE `tbl_voucher` SET `used_date`=now() WHERE `status`=1;"
|
||||
],
|
||||
"2024.8.1" : [
|
||||
"ALTER TABLE `tbl_payment_gateway` CHANGE `gateway_trx_id` `gateway_trx_id` VARCHAR(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '';",
|
||||
"ALTER TABLE `tbl_payment_gateway` CHANGE `pg_url_payment` `pg_url_payment` VARCHAR(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '';"
|
||||
],
|
||||
"2024.8.2" : [
|
||||
"CREATE TABLE IF NOT EXISTS `tbl_customers_inbox` (`id` int UNSIGNED NOT NULL AUTO_INCREMENT, `customer_id` int NOT NULL, `date_created` datetime NOT NULL, `date_read` datetime DEFAULT NULL, `subject` varchar(64) COLLATE utf8mb4_general_ci NOT NULL, `body` TEXT NULL DEFAULT NULL, `from` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'System' COMMENT 'System or Admin or Else',`admin_id` int NOT NULL DEFAULT '0' COMMENT 'other than admin is 0', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;"
|
||||
],
|
||||
"2024.8.5" : [
|
||||
"ALTER TABLE `tbl_customers` ADD `pppoe_username` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login' AFTER `password`;",
|
||||
"ALTER TABLE `tbl_customers` ADD `pppoe_ip` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login' AFTER `pppoe_password`;"
|
||||
],
|
||||
"2024.8.5.1" : [
|
||||
"ALTER TABLE `tbl_routers` ADD `coordinates` VARCHAR(50) NOT NULL DEFAULT '' AFTER `description`;",
|
||||
"ALTER TABLE `tbl_routers` ADD `coverage` VARCHAR(8) NOT NULL DEFAULT '0' AFTER `coordinates`;"
|
||||
],
|
||||
"2024.8.6" : [
|
||||
"ALTER TABLE `rad_acct` ADD `acctinputoctets` BIGINT NOT NULL DEFAULT '0' AFTER `framedipaddress`;",
|
||||
"ALTER TABLE `rad_acct` ADD `acctoutputoctets` BIGINT NOT NULL DEFAULT '0' AFTER `acctinputoctets`;"
|
||||
],
|
||||
"2024.8.7" : [
|
||||
"ALTER TABLE `tbl_customers` CHANGE `coordinates` `coordinates` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Latitude and Longitude coordinates';"
|
||||
],
|
||||
"2024.8.28" : [
|
||||
"ALTER TABLE `tbl_routers` ADD `status` ENUM('Online', 'Offline') DEFAULT 'Online' AFTER `coordinates`;",
|
||||
"ALTER TABLE `tbl_routers` ADD `last_seen` DATETIME AFTER `status`;"
|
||||
]
|
||||
}
|
||||
"2023.8.9": [
|
||||
"ALTER TABLE `tbl_customers` ADD `balance` decimal(15,2) NOT NULL DEFAULT 0.00 COMMENT 'For Money Deposit' AFTER `email`;",
|
||||
"CREATE TABLE `tbl_customers_meta` (`id` int(11) NOT NULL, `customer_id` int(11) NOT NULL,`meta_key` varchar(64) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `meta_value` longtext COLLATE utf8mb4_general_ci) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;",
|
||||
"ALTER TABLE `tbl_customers_meta` ADD PRIMARY KEY (`id`);",
|
||||
"ALTER TABLE `tbl_customers_meta` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;"
|
||||
],
|
||||
"2023.8.14": [
|
||||
"ALTER TABLE `tbl_customers` ADD `pppoe_password` varchar(45) NOT NULL DEFAULT '' 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 '' 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`;",
|
||||
"ALTER TABLE `tbl_transactions` ADD `recharged_time` time NOT NULL DEFAULT '00:00:00' AFTER `recharged_on`;"
|
||||
],
|
||||
"2023.9.5": [
|
||||
"DROP TABLE `tbl_language`;",
|
||||
"ALTER TABLE `tbl_plans` ADD `pool_expired` varchar(40) NOT NULL DEFAULT '' AFTER `pool`;"
|
||||
],
|
||||
"2023.9.27": [
|
||||
"ALTER TABLE `tbl_plans` CHANGE `type` `type` ENUM('Hotspot','PPPOE','Balance','Radius') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;",
|
||||
"ALTER TABLE `tbl_transactions` CHANGE `type` `type` ENUM('Hotspot','PPPOE','Balance','Radius') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;"
|
||||
],
|
||||
"2023.9.28": [
|
||||
"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;"
|
||||
],
|
||||
"2023.10.1": [
|
||||
"ALTER TABLE `tbl_plans` ADD `is_radius` TINYINT(1) NOT NULL DEFAULT '0' COMMENT '1 is radius' AFTER `routers`; "
|
||||
],
|
||||
"2023.10.24": [
|
||||
"ALTER TABLE `nas` ADD `routers` VARCHAR(32) NOT NULL DEFAULT '' AFTER `description`;"
|
||||
],
|
||||
"2023.12.15": [
|
||||
"ALTER TABLE `tbl_customers` ADD `service_type` ENUM('Hotspot','PPPoE','Others') DEFAULT 'Others' COMMENT 'For selecting user type' AFTER `balance`;"
|
||||
],
|
||||
"2024.1.11": [
|
||||
"ALTER TABLE `tbl_plans` ADD `allow_purchase` ENUM('yes','no') DEFAULT 'yes' COMMENT 'allow to show package in buy package page' AFTER `enabled`;"
|
||||
],
|
||||
"2024.2.7": [
|
||||
"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`;"
|
||||
],
|
||||
"2024.2.12": [
|
||||
"ALTER TABLE `tbl_users` CHANGE `user_type` `user_type` ENUM('SuperAdmin','Admin','Report','Agent','Sales') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;"
|
||||
],
|
||||
"2024.2.15": [
|
||||
"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`;"
|
||||
],
|
||||
"2024.2.16": [
|
||||
"ALTER TABLE `tbl_customers` ADD `created_by` INT NOT NULL DEFAULT '0' AFTER `auto_renewal`;"
|
||||
],
|
||||
"2024.2.19": [
|
||||
"CREATE TABLE `tbl_customers_fields` (`id` INT PRIMARY KEY AUTO_INCREMENT, `customer_id` INT NOT NULL, `field_name` VARCHAR(255) NOT NULL, `field_value` VARCHAR(255) NOT NULL, FOREIGN KEY (customer_id) REFERENCES tbl_customers(id));"
|
||||
],
|
||||
"2024.2.20": [
|
||||
"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`;"
|
||||
],
|
||||
"2024.2.20.1": ["DROP TABLE IF EXISTS `tbl_customers_meta`;"],
|
||||
"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`;"
|
||||
],
|
||||
"2024.5.17": [
|
||||
"ALTER TABLE `tbl_customers` ADD `status` ENUM('Active','Banned','Disabled') NOT NULL DEFAULT 'Active' AFTER `auto_renewal`;"
|
||||
],
|
||||
"2024.5.18": [
|
||||
"ALTER TABLE `tbl_customers` CHANGE `status` `status` ENUM('Active','Banned','Disabled','Inactive','Limited','Suspended') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'Active';"
|
||||
],
|
||||
"2024.5.20": [
|
||||
"ALTER TABLE `tbl_customers` ADD `city` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci AFTER `address`, ADD `district` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci AFTER `city`, ADD `state` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci AFTER `district`, ADD `zip` VARCHAR(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci AFTER `state`;"
|
||||
],
|
||||
"2024.6.5": [
|
||||
"ALTER TABLE `tbl_plans` ADD `price_old` VARCHAR(40) NOT NULL DEFAULT '' AFTER `price`;",
|
||||
"ALTER TABLE `tbl_plans` ADD `device` VARCHAR(32) NOT NULL DEFAULT '' AFTER `plan_type`;"
|
||||
],
|
||||
"2024.6.10": [
|
||||
"ALTER TABLE `tbl_pool` ADD `local_ip` VARCHAR(40) NOT NULL DEFAULT '' AFTER `pool_name`;"
|
||||
],
|
||||
"2024.6.11": [
|
||||
"ALTER TABLE `tbl_plans` ADD `plan_expired` INT NOT NULL DEFAULT '0' AFTER `pool`;",
|
||||
"ALTER TABLE `tbl_plans` DROP `pool_expired`, DROP `list_expired`;"
|
||||
],
|
||||
"2024.6.19": [
|
||||
"ALTER TABLE `tbl_plans` ADD `expired_date` TINYINT(1) NOT NULL DEFAULT '20' AFTER `plan_expired`;"
|
||||
],
|
||||
"2024.6.21": [
|
||||
"ALTER TABLE `tbl_plans` ADD `on_login` TEXT NULL DEFAULT NULL AFTER `device`;",
|
||||
"ALTER TABLE `tbl_plans` ADD `on_logout` TEXT NULL DEFAULT NULL AFTER `on_login`;"
|
||||
],
|
||||
"2024.7.6": [
|
||||
"CREATE TABLE IF NOT EXISTS `rad_acct` ( `id` bigint NOT NULL, `acctsessionid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `username` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `realm` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `nasid` varchar(32) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `nasipaddress` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `nasportid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, `nasporttype` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, `framedipaddress` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',`acctstatustype` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, `macaddr` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `dateAdded` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;",
|
||||
"ALTER TABLE `rad_acct` ADD PRIMARY KEY (`id`), ADD KEY `username` (`username`), ADD KEY `framedipaddress` (`framedipaddress`), ADD KEY `acctsessionid` (`acctsessionid`), ADD KEY `nasipaddress` (`nasipaddress`);",
|
||||
"ALTER TABLE `rad_acct` MODIFY `id` bigint NOT NULL AUTO_INCREMENT;"
|
||||
],
|
||||
"2024.7.24": [
|
||||
"ALTER TABLE `tbl_voucher` ADD `used_date` DATETIME NULL DEFAULT NULL AFTER `status`;",
|
||||
"UPDATE `tbl_voucher` SET `used_date`=now() WHERE `status`=1;"
|
||||
],
|
||||
"2024.8.1": [
|
||||
"ALTER TABLE `tbl_payment_gateway` CHANGE `gateway_trx_id` `gateway_trx_id` VARCHAR(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '';",
|
||||
"ALTER TABLE `tbl_payment_gateway` CHANGE `pg_url_payment` `pg_url_payment` VARCHAR(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '';"
|
||||
],
|
||||
"2024.8.2": [
|
||||
"CREATE TABLE IF NOT EXISTS `tbl_customers_inbox` (`id` int UNSIGNED NOT NULL AUTO_INCREMENT, `customer_id` int NOT NULL, `date_created` datetime NOT NULL, `date_read` datetime DEFAULT NULL, `subject` varchar(64) COLLATE utf8mb4_general_ci NOT NULL, `body` TEXT NULL DEFAULT NULL, `from` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'System' COMMENT 'System or Admin or Else',`admin_id` int NOT NULL DEFAULT '0' COMMENT 'other than admin is 0', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;"
|
||||
],
|
||||
"2024.8.5": [
|
||||
"ALTER TABLE `tbl_customers` ADD `pppoe_username` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login' AFTER `password`;",
|
||||
"ALTER TABLE `tbl_customers` ADD `pppoe_ip` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'For PPPOE Login' AFTER `pppoe_password`;"
|
||||
],
|
||||
"2024.8.5.1": [
|
||||
"ALTER TABLE `tbl_routers` ADD `coordinates` VARCHAR(50) NOT NULL DEFAULT '' AFTER `description`;",
|
||||
"ALTER TABLE `tbl_routers` ADD `coverage` VARCHAR(8) NOT NULL DEFAULT '0' AFTER `coordinates`;"
|
||||
],
|
||||
"2024.8.6": [
|
||||
"ALTER TABLE `rad_acct` ADD `acctinputoctets` BIGINT NOT NULL DEFAULT '0' AFTER `framedipaddress`;",
|
||||
"ALTER TABLE `rad_acct` ADD `acctoutputoctets` BIGINT NOT NULL DEFAULT '0' AFTER `acctinputoctets`;"
|
||||
],
|
||||
"2024.8.7": [
|
||||
"ALTER TABLE `tbl_customers` CHANGE `coordinates` `coordinates` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Latitude and Longitude coordinates';"
|
||||
],
|
||||
"2024.8.28": [
|
||||
"ALTER TABLE `tbl_routers` ADD `status` ENUM('Online', 'Offline') DEFAULT 'Online' AFTER `coordinates`;",
|
||||
"ALTER TABLE `tbl_routers` ADD `last_seen` DATETIME AFTER `status`;"
|
||||
],
|
||||
"2024.9.13": [
|
||||
"ALTER TABLE `tbl_plans` CHANGE `type` `type` ENUM('Hotspot','PPPOE','VPN','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;",
|
||||
"ALTER TABLE `tbl_customers` CHANGE `service_type` `service_type` ENUM('Hotspot','PPPoE','VPN','Others') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'Others' COMMENT 'For selecting user type';",
|
||||
"ALTER TABLE `tbl_transactions` CHANGE `type` `type` ENUM('Hotspot','PPPOE','VPN','Balance') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL;",
|
||||
"CREATE TABLE IF NOT EXISTS `tbl_port_pool` ( `id` int(10) NOT NULL AUTO_INCREMENT , `public_ip` varchar(40) NOT NULL, `port_name` varchar(40) NOT NULL, `range_port` varchar(40) NOT NULL, `routers` varchar(40) NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;"
|
||||
],
|
||||
"2024.10.10": [
|
||||
"ALTER TABLE `tbl_users` ADD `login_token` VARCHAR(40) AFTER `last_login`;"
|
||||
],
|
||||
"2024.10.17": [
|
||||
"CREATE TABLE IF NOT EXISTS `tbl_meta` ( `id` int UNSIGNED NOT NULL AUTO_INCREMENT, `tbl` varchar(32) COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Table name', `tbl_id` int NOT NULL COMMENT 'table value id', `name` varchar(32) COLLATE utf8mb4_general_ci NOT NULL, `value` mediumtext COLLATE utf8mb4_general_ci, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='This Table to add additional data for any table';"
|
||||
],
|
||||
"2024.10.30": [
|
||||
"ALTER TABLE `tbl_users` ADD `photo` VARCHAR(128) NOT NULL DEFAULT '/admin.default.png' AFTER `root`;",
|
||||
"ALTER TABLE `tbl_users` ADD `data` TEXT NULL DEFAULT NULL COMMENT 'to put additional data' AFTER `status`;"
|
||||
],
|
||||
"2024.10.31": [
|
||||
"ALTER TABLE `tbl_customers` ADD `photo` VARCHAR(128) NOT NULL DEFAULT '/user.default.jpg' AFTER `password`;"
|
||||
],
|
||||
"2024.12.5.1": [
|
||||
"ALTER TABLE `tbl_transactions` ADD `user_id` INT(11) NOT NULL DEFAULT 0 AFTER `username`;",
|
||||
"ALTER TABLE `tbl_payment_gateway` ADD `user_id` INT(11) NOT NULL DEFAULT 0 AFTER `username`;"
|
||||
],
|
||||
"2024.12.16": [
|
||||
"CREATE TABLE `tbl_coupons` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `code` VARCHAR(50) NOT NULL UNIQUE, `type` ENUM('fixed', 'percent') NOT NULL, `value` DECIMAL(10,2) NOT NULL, `description` TEXT NOT NULL, `max_usage` INT NOT NULL DEFAULT 1,`usage_count` INT NOT NULL DEFAULT 0,`status` ENUM('active', 'inactive') NOT NULL, `min_order_amount` DECIMAL(10,2) NOT NULL, `max_discount_amount` DECIMAL(10,2) NOT NULL, `start_date` DATE NOT NULL,`end_date` DATE NOT NULL, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP);"
|
||||
],
|
||||
"2024.12.20": [
|
||||
"ALTER TABLE `tbl_voucher` ADD `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `status`;"
|
||||
],
|
||||
"2025.1.23": [
|
||||
"ALTER TABLE `rad_acct` ADD `acctsessiontime` BIGINT(12) NOT NULL DEFAULT '0' AFTER `framedipaddress`;"
|
||||
],
|
||||
"2025.2.14": [
|
||||
"CREATE TABLE IF NOT EXISTS `tbl_widgets` ( `id` int NOT NULL AUTO_INCREMENT, `orders` int NOT NULL DEFAULT '99', `position` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1. top 2. left 3. right 4. bottom',`enabled` tinyint(1) NOT NULL DEFAULT '1', `title` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `widget` varchar(64) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `content` text COLLATE utf8mb4_general_ci NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;"
|
||||
],
|
||||
"2025.2.17": [
|
||||
"INSERT INTO `tbl_widgets` (`id`, `orders`, `position`, `enabled`, `title`, `widget`, `content`) VALUES (1, 1, 1, 1, 'Top Widget', 'top_widget', ''),(2, 2, 1, 1, 'Default Info', 'default_info_row', ''),(3, 1, 2, 1, 'Graph Monthly Registered Customers', 'graph_monthly_registered_customers', ''),(4, 2, 2, 1, 'Graph Monthly Sales', 'graph_monthly_sales', ''),(5, 3, 2, 1, 'Voucher Stocks', 'voucher_stocks', ''),(6, 4, 2, 1, 'Customer Expired', 'customer_expired', ''),(7, 1, 3, 1, 'Cron Monitor', 'cron_monitor', ''),(8, 2, 3, 1, 'Mikrotik Cron Monitor', 'mikrotik_cron_monitor', ''),(9, 3, 3, 1, 'Info Payment Gateway', 'info_payment_gateway', ''),(10, 4, 3, 1, 'Graph Customers Insight', 'graph_customers_insight', ''),(11, 5, 3, 1, 'Activity Log', 'activity_log', '');"
|
||||
],
|
||||
"2025.2.19": [
|
||||
"ALTER TABLE `tbl_widgets` ADD `user` ENUM('Admin','Agent','Sales','Customer') NOT NULL DEFAULT 'Admin' AFTER `position`;"
|
||||
],
|
||||
"2025.2.21": [
|
||||
"INSERT INTO `tbl_widgets` (`id`, `orders`, `position`, `user`, `enabled`, `title`, `widget`, `content`) VALUES (60, 1, 2, 'Customer', 1, 'Account Info', 'account_info', ''),(61, 3, 1, 'Customer', 1, 'Active Internet Plan', 'active_internet_plan', ''),(62, 4, 1, 'Customer', 1, 'Balance Transfer', 'balance_transfer', ''),(63, 1, 1, 'Customer', 1, 'Unpaid Order', 'unpaid_order', ''),(64, 2, 1, 'Customer', 1, 'Announcement', 'announcement', ''),(65, 5, 1, 'Customer', 1, 'Recharge A Friend', 'recharge_a_friend', ''),(66, 2, 2, 'Customer', 1, 'Voucher Activation', 'voucher_activation', '');"
|
||||
],
|
||||
"2025.2.25": [
|
||||
"INSERT INTO `tbl_widgets` (`id`, `orders`, `position`, `user`, `enabled`, `title`, `widget`, `content`) VALUES (30, 1, 1, 'Agent', 1, 'Top Widget', 'top_widget', ''), (31, 2, 1, 'Agent', 1, 'Default Info', 'default_info_row', ''), (32, 1, 2, 'Agent', 1, 'Graph Monthly Registered Customers', 'graph_monthly_registered_customers', ''), (33, 2, 2, 'Agent', 1, 'Graph Monthly Sales', 'graph_monthly_sales', ''), (34, 3, 2, 'Agent', 1, 'Voucher Stocks', 'voucher_stocks', ''), (35, 4, 2, 'Agent', 1, 'Customer Expired', 'customer_expired', ''), (36, 1, 3, 'Agent', 1, 'Cron Monitor', 'cron_monitor', ''), (37, 2, 3, 'Agent', 1, 'Mikrotik Cron Monitor', 'mikrotik_cron_monitor', ''), (38, 3, 3, 'Agent', 1, 'Info Payment Gateway', 'info_payment_gateway', ''), (39, 4, 3, 'Agent', 1, 'Graph Customers Insight', 'graph_customers_insight', ''),(40, 5, 3, 'Agent', 1, 'Activity Log', 'activity_log', '');",
|
||||
"INSERT INTO `tbl_widgets` (`id`, `orders`, `position`, `user`, `enabled`, `title`, `widget`, `content`) VALUES (41, 1, 1, 'Sales', 1, 'Top Widget', 'top_widget', ''), (42, 2, 1, 'Sales', 1, 'Default Info', 'default_info_row', ''), (43, 1, 2, 'Sales', 1, 'Graph Monthly Registered Customers', 'graph_monthly_registered_customers', ''), (44, 2, 2, 'Sales', 1, 'Graph Monthly Sales', 'graph_monthly_sales', ''), (45, 3, 2, 'Sales', 1, 'Voucher Stocks', 'voucher_stocks', ''), (46, 4, 2, 'Sales', 1, 'Customer Expired', 'customer_expired', ''), (47, 1, 3, 'Sales', 1, 'Cron Monitor', 'cron_monitor', ''), (48, 2, 3, 'Sales', 1, 'Mikrotik Cron Monitor', 'mikrotik_cron_monitor', ''), (49, 3, 3, 'Sales', 1, 'Info Payment Gateway', 'info_payment_gateway', ''), (50, 4, 3, 'Sales', 1, 'Graph Customers Insight', 'graph_customers_insight', ''), (51, 5, 3, 'Sales', 1, 'Activity Log', 'activity_log', '');"
|
||||
],
|
||||
"2025.3.5": [
|
||||
"CREATE TABLE IF NOT EXISTS `tbl_message_logs` ( `id` SERIAL PRIMARY KEY, `message_type` VARCHAR(50), `recipient` VARCHAR(255), `message_content` TEXT, `status` VARCHAR(50), `error_message` TEXT, `sent_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;"
|
||||
],
|
||||
"2025.3.10": [
|
||||
"CREATE TABLE IF NOT EXISTS `tbl_invoices` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `number` VARCHAR(50) NOT NULL, `customer_id` INT NOT NULL, `fullname` VARCHAR(100) NOT NULL, `email` VARCHAR(100) NOT NULL, `address` TEXT, `status` ENUM('Unpaid', 'Paid', 'Cancelled') NOT NULL DEFAULT 'Unpaid', `due_date` DATETIME NOT NULL, `filename` VARCHAR(255), `amount` DECIMAL(10, 2) NOT NULL, `data` JSON NOT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP);"
|
||||
]
|
||||
}
|
||||
|
BIN
system/uploads/favicon.default.png
Normal file
BIN
system/uploads/favicon.default.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1002 B |
BIN
system/uploads/login-logo.default.png
Normal file
BIN
system/uploads/login-logo.default.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.5 KiB |
File diff suppressed because one or more lines are too long
BIN
system/uploads/paid.png
Normal file
BIN
system/uploads/paid.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
BIN
system/uploads/wallpaper.default.png
Normal file
BIN
system/uploads/wallpaper.default.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 68 KiB |
2
system/vendor/composer/autoload_classmap.php
vendored
2
system/vendor/composer/autoload_classmap.php
vendored
@ -176,4 +176,6 @@ return array(
|
||||
'Smarty_Variable' => $vendorDir . '/smarty/smarty/libs/sysplugins/smarty_variable.php',
|
||||
'TPC_yyStackEntry' => $vendorDir . '/smarty/smarty/libs/sysplugins/smarty_internal_configfileparser.php',
|
||||
'TP_yyStackEntry' => $vendorDir . '/smarty/smarty/libs/sysplugins/smarty_internal_templateparser.php',
|
||||
'svay\\Exception\\NoFaceException' => $vendorDir . '/yosiazwan/php-facedetection/Exception/NoFaceException.php',
|
||||
'svay\\FaceDetector' => $vendorDir . '/yosiazwan/php-facedetection/FaceDetector.php',
|
||||
);
|
||||
|
2
system/vendor/composer/autoload_real.php
vendored
2
system/vendor/composer/autoload_real.php
vendored
@ -22,8 +22,6 @@ class ComposerAutoloaderInit405fa5c7a0972c286ef93b1161b83367
|
||||
return self::$loader;
|
||||
}
|
||||
|
||||
require __DIR__ . '/platform_check.php';
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInit405fa5c7a0972c286ef93b1161b83367', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit405fa5c7a0972c286ef93b1161b83367', 'loadClassLoader'));
|
||||
|
2
system/vendor/composer/autoload_static.php
vendored
2
system/vendor/composer/autoload_static.php
vendored
@ -229,6 +229,8 @@ class ComposerStaticInit405fa5c7a0972c286ef93b1161b83367
|
||||
'Smarty_Variable' => __DIR__ . '/..' . '/smarty/smarty/libs/sysplugins/smarty_variable.php',
|
||||
'TPC_yyStackEntry' => __DIR__ . '/..' . '/smarty/smarty/libs/sysplugins/smarty_internal_configfileparser.php',
|
||||
'TP_yyStackEntry' => __DIR__ . '/..' . '/smarty/smarty/libs/sysplugins/smarty_internal_templateparser.php',
|
||||
'svay\\Exception\\NoFaceException' => __DIR__ . '/..' . '/yosiazwan/php-facedetection/Exception/NoFaceException.php',
|
||||
'svay\\FaceDetector' => __DIR__ . '/..' . '/yosiazwan/php-facedetection/FaceDetector.php',
|
||||
);
|
||||
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
|
45
system/vendor/composer/installed.json
vendored
45
system/vendor/composer/installed.json
vendored
@ -494,6 +494,51 @@
|
||||
"source": "https://github.com/smarty-php/smarty/tree/v4.5.3"
|
||||
},
|
||||
"install-path": "../smarty/smarty"
|
||||
},
|
||||
{
|
||||
"name": "yosiazwan/php-facedetection",
|
||||
"version": "0.1.0",
|
||||
"version_normalized": "0.1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/yosiazwan/php-facedetection.git",
|
||||
"reference": "b016273ceceacd85562bbc50384fbabc947fe525"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/yosiazwan/php-facedetection/zipball/b016273ceceacd85562bbc50384fbabc947fe525",
|
||||
"reference": "b016273ceceacd85562bbc50384fbabc947fe525",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-gd": "*",
|
||||
"php": ">=5.2.0"
|
||||
},
|
||||
"time": "2016-01-26T22:10:00+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "source",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"FaceDetector.php",
|
||||
"Exception/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"GPL-2.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Maurice Svay",
|
||||
"homepage": "https://github.com/mauricesvay/php-facedetection/graphs/contributors"
|
||||
}
|
||||
],
|
||||
"description": "PHP class to detect one face in images. A pure PHP port of an existing JS code from Karthik Tharavad.",
|
||||
"homepage": "https://github.com/mauricesvay/php-facedetection",
|
||||
"support": {
|
||||
"source": "https://github.com/yosiazwan/php-facedetection/tree/0.1.0"
|
||||
},
|
||||
"install-path": "../yosiazwan/php-facedetection"
|
||||
}
|
||||
],
|
||||
"dev": true,
|
||||
|
13
system/vendor/composer/installed.php
vendored
13
system/vendor/composer/installed.php
vendored
@ -3,7 +3,7 @@
|
||||
'name' => '__root__',
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'reference' => 'a9c0e955937e3ccb2ff050c71b77353b298a982b',
|
||||
'reference' => '925c24cbd822f776eb913df987a063f95c6d9cc0',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
@ -13,7 +13,7 @@
|
||||
'__root__' => array(
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'reference' => 'a9c0e955937e3ccb2ff050c71b77353b298a982b',
|
||||
'reference' => '925c24cbd822f776eb913df987a063f95c6d9cc0',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
@ -91,5 +91,14 @@
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'yosiazwan/php-facedetection' => array(
|
||||
'pretty_version' => '0.1.0',
|
||||
'version' => '0.1.0.0',
|
||||
'reference' => 'b016273ceceacd85562bbc50384fbabc947fe525',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../yosiazwan/php-facedetection',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
26
system/vendor/composer/platform_check.php
vendored
26
system/vendor/composer/platform_check.php
vendored
@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
// platform_check.php @generated by Composer
|
||||
|
||||
$issues = array();
|
||||
|
||||
if (!(PHP_VERSION_ID >= 70200)) {
|
||||
$issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.0". You are running ' . PHP_VERSION . '.';
|
||||
}
|
||||
|
||||
if ($issues) {
|
||||
if (!headers_sent()) {
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
if (!ini_get('display_errors')) {
|
||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
|
||||
} elseif (!headers_sent()) {
|
||||
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
'Composer detected issues in your platform: ' . implode(' ', $issues),
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
BIN
system/vendor/mpdf/mpdf/ttfonts/DejaVuSansCondensed-Oblique.ttf
vendored
Normal file
BIN
system/vendor/mpdf/mpdf/ttfonts/DejaVuSansCondensed-Oblique.ttf
vendored
Normal file
Binary file not shown.
@ -131,13 +131,7 @@ abstract class Smarty_Internal_TemplateBase extends Smarty_Internal_Data
|
||||
public function display($template = null, $cache_id = null, $compile_id = null, $parent = null)
|
||||
{
|
||||
// display template
|
||||
if(strpos($template, "user-ui") === false){
|
||||
if(strpos($template, "section/user-") === false){
|
||||
$template = str_replace("user-",'', $template);
|
||||
}else{
|
||||
$template = str_replace("section/user-",'user-ui/', $template);
|
||||
}
|
||||
}
|
||||
$template = str_replace("section/user-",'customer/', $template);
|
||||
$this->_execute($template, $cache_id, $compile_id, $parent, 1);
|
||||
}
|
||||
|
||||
|
13
system/vendor/yosiazwan/php-facedetection/Exception/NoFaceException.php
vendored
Normal file
13
system/vendor/yosiazwan/php-facedetection/Exception/NoFaceException.php
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Throws exception if face was not detected in `faceDetect` call.
|
||||
*/
|
||||
|
||||
namespace svay\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
class NoFaceException extends Exception {
|
||||
|
||||
}
|
396
system/vendor/yosiazwan/php-facedetection/FaceDetector.php
vendored
Normal file
396
system/vendor/yosiazwan/php-facedetection/FaceDetector.php
vendored
Normal file
@ -0,0 +1,396 @@
|
||||
<?php
|
||||
//
|
||||
// This program 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.
|
||||
//
|
||||
// This program is distributed in the hope that it 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.
|
||||
//
|
||||
// @Author Karthik Tharavaad
|
||||
// karthik_tharavaad@yahoo.com
|
||||
// @Contributor Maurice Svay
|
||||
// maurice@svay.Com
|
||||
|
||||
namespace svay;
|
||||
|
||||
use Exception;
|
||||
use svay\Exception\NoFaceException;
|
||||
|
||||
class FaceDetector
|
||||
{
|
||||
|
||||
protected $detection_data;
|
||||
protected $canvas;
|
||||
protected $face;
|
||||
private $reduced_canvas;
|
||||
protected $timeout = null;
|
||||
protected $time_start;
|
||||
|
||||
/**
|
||||
* Creates a face-detector with the given configuration
|
||||
*
|
||||
* Configuration can be either passed as an array or as
|
||||
* a filepath to a serialized array file-dump
|
||||
*
|
||||
* @param string|array $detection_data
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct($detection_data = 'detection.json')
|
||||
{
|
||||
if (is_array($detection_data)) {
|
||||
$this->detection_data = $detection_data;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_file($detection_data)) {
|
||||
// fallback to same file in this class's directory
|
||||
$detection_data = dirname(__FILE__) . DIRECTORY_SEPARATOR . $detection_data;
|
||||
|
||||
if (!is_file($detection_data)) {
|
||||
throw new \Exception("Couldn't load detection data");
|
||||
}
|
||||
}
|
||||
|
||||
$this->detection_data = json_decode(file_get_contents($detection_data));
|
||||
}
|
||||
|
||||
public function setTimeout($micro_seconds)
|
||||
{
|
||||
$this->timeout = $micro_seconds;
|
||||
}
|
||||
|
||||
public function faceDetect($file)
|
||||
{
|
||||
$this->time_start = microtime();
|
||||
if (is_resource($file)) {
|
||||
|
||||
$this->canvas = $file;
|
||||
} elseif (is_file($file)) {
|
||||
|
||||
$this->canvas = imagecreatefromjpeg($file);
|
||||
} elseif (is_string($file)) {
|
||||
|
||||
$this->canvas = imagecreatefromstring($file);
|
||||
} else {
|
||||
|
||||
throw new Exception("Can not load $file");
|
||||
}
|
||||
|
||||
$sharpen = array(
|
||||
array(0.0, -1.0, 0.0),
|
||||
array(-1.0, 5.0, -1.0),
|
||||
array(0.0, -1.0, 0.0)
|
||||
);
|
||||
|
||||
$divisor = array_sum(array_map('array_sum', $sharpen));
|
||||
|
||||
imageconvolution($this->canvas, $sharpen, $divisor, 0);
|
||||
|
||||
$im_width = imagesx($this->canvas);
|
||||
$im_height = imagesy($this->canvas);
|
||||
|
||||
//Resample before detection?
|
||||
$diff_width = 320 - $im_width;
|
||||
$diff_height = 240 - $im_height;
|
||||
if ($diff_width > $diff_height) {
|
||||
$ratio = $im_width / 320;
|
||||
} else {
|
||||
$ratio = $im_height / 240;
|
||||
}
|
||||
|
||||
if ($ratio != 0) {
|
||||
$this->reduced_canvas = imagecreatetruecolor($im_width / $ratio, $im_height / $ratio);
|
||||
|
||||
imagecopyresampled(
|
||||
$this->reduced_canvas,
|
||||
$this->canvas,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
$im_width / $ratio,
|
||||
$im_height / $ratio,
|
||||
$im_width,
|
||||
$im_height
|
||||
);
|
||||
|
||||
$stats = $this->getImgStats($this->reduced_canvas);
|
||||
|
||||
$this->face = $this->doDetectGreedyBigToSmall(
|
||||
$stats['ii'],
|
||||
$stats['ii2'],
|
||||
$stats['width'],
|
||||
$stats['height']
|
||||
);
|
||||
|
||||
if ($this->face['w'] > 0) {
|
||||
$this->face['x'] *= $ratio;
|
||||
$this->face['y'] *= $ratio;
|
||||
$this->face['w'] *= $ratio;
|
||||
}
|
||||
} else {
|
||||
$stats = $this->getImgStats($this->canvas);
|
||||
|
||||
$this->face = $this->doDetectGreedyBigToSmall(
|
||||
$stats['ii'],
|
||||
$stats['ii2'],
|
||||
$stats['width'],
|
||||
$stats['height']
|
||||
);
|
||||
}
|
||||
return ($this->face['w'] > 0);
|
||||
}
|
||||
|
||||
|
||||
public function toJpeg()
|
||||
{
|
||||
$color = imagecolorallocate($this->canvas, 255, 0, 0); //red
|
||||
|
||||
imagerectangle(
|
||||
$this->canvas,
|
||||
$this->face['x'],
|
||||
$this->face['y'],
|
||||
$this->face['x'] + $this->face['w'],
|
||||
$this->face['y'] + $this->face['w'],
|
||||
$color
|
||||
);
|
||||
|
||||
header('Content-type: image/jpeg');
|
||||
imagejpeg($this->canvas);
|
||||
}
|
||||
|
||||
/**
|
||||
* Crops the face from the photo.
|
||||
* Should be called after `faceDetect` function call
|
||||
* If file is provided, the face will be stored in file, other way it will be output to standard output.
|
||||
*
|
||||
* @param string|null $outFileName file name to store. If null, will be printed to output
|
||||
* @param boolean|false $resize resize crop image.
|
||||
* @param int $width widht of new crop image. $resize value must 'true'. default to 200
|
||||
* @param int $height height of new crop image. $resize value must 'true'. default to 200
|
||||
*
|
||||
* @throws NoFaceException
|
||||
*/
|
||||
public function cropFaceToJpeg($outFileName = null, $width = 200)
|
||||
{
|
||||
if (empty($this->face)) {
|
||||
throw new NoFaceException('No face detected');
|
||||
}
|
||||
// if (!$resize) {
|
||||
$x = ($a = $this->face['x'] - $this->face['w'] / 2) > 0 ? $a : 0;
|
||||
$y = ($b = $this->face['y'] - $this->face['w'] / 2) > 0 ? $b : 0;
|
||||
$im_width = imagesx($this->canvas);
|
||||
$im_height = imagesy($this->canvas);
|
||||
$w = ($w = $this->face['w'] * 2) > $im_width ? $im_width : $w;
|
||||
$h = ($h = $w) > $im_height ? $im_height : $h;
|
||||
|
||||
$canvas = imagecreatetruecolor($width, $width);
|
||||
imagecopy($canvas, $this->canvas, 0, 0, $x, $y, $w, $h);
|
||||
// $canvas = imagecreatetruecolor($this->face['w'], $this->face['w']);
|
||||
// imagecopy($canvas, $this->canvas, 0, 0, $this->face['x'], $this->face['y'], $this->face['w'], $this->face['w']);
|
||||
// } else {
|
||||
// $x = ($a = $this->face['x'] - $width / 2) > 0 ? $a : 0;
|
||||
// $y = ($b = $this->face['y'] - $width / 2) > 0 ? $b : 0;
|
||||
// $im_width = imagesx($this->canvas);
|
||||
// $im_height = imagesy($this->canvas);
|
||||
// $w = ($w = $width * 2) > $im_width ? $im_width : $w;
|
||||
// $h = ($h = $w) > $im_height ? $im_height : $h;
|
||||
|
||||
// $canvas = imagecreatetruecolor($w, $h);
|
||||
// imagecopy($canvas, $this->canvas, 0, 0, $width, $width, $w, $h);
|
||||
|
||||
// // $canvas = imagecreatetruecolor($width, $width);
|
||||
// // imagecopyresized($canvas, $this->canvas, 0, 0, $this->face['x'], $this->face['y'], $width, $width, $this->face['w'], $this->face['w']);
|
||||
// }
|
||||
|
||||
if ($outFileName === null) {
|
||||
header('Content-type: image/jpeg');
|
||||
}
|
||||
|
||||
imagejpeg($canvas, $outFileName);
|
||||
}
|
||||
|
||||
public function toJson()
|
||||
{
|
||||
return json_encode($this->face);
|
||||
}
|
||||
|
||||
public function getFace()
|
||||
{
|
||||
return $this->face;
|
||||
}
|
||||
|
||||
protected function getImgStats($canvas)
|
||||
{
|
||||
$image_width = imagesx($canvas);
|
||||
$image_height = imagesy($canvas);
|
||||
$iis = $this->computeII($canvas, $image_width, $image_height);
|
||||
return array(
|
||||
'width' => $image_width,
|
||||
'height' => $image_height,
|
||||
'ii' => $iis['ii'],
|
||||
'ii2' => $iis['ii2']
|
||||
);
|
||||
}
|
||||
|
||||
protected function computeII($canvas, $image_width, $image_height)
|
||||
{
|
||||
$ii_w = $image_width + 1;
|
||||
$ii_h = $image_height + 1;
|
||||
$ii = array();
|
||||
$ii2 = array();
|
||||
|
||||
for ($i = 0; $i < $ii_w; $i++) {
|
||||
$ii[$i] = 0;
|
||||
$ii2[$i] = 0;
|
||||
}
|
||||
|
||||
for ($i = 1; $i < $ii_h - 1; $i++) {
|
||||
$ii[$i * $ii_w] = 0;
|
||||
$ii2[$i * $ii_w] = 0;
|
||||
$rowsum = 0;
|
||||
$rowsum2 = 0;
|
||||
for ($j = 1; $j < $ii_w - 1; $j++) {
|
||||
$rgb = ImageColorAt($canvas, $j, $i);
|
||||
$red = ($rgb >> 16) & 0xFF;
|
||||
$green = ($rgb >> 8) & 0xFF;
|
||||
$blue = $rgb & 0xFF;
|
||||
$grey = (0.2989 * $red + 0.587 * $green + 0.114 * $blue) >> 0; // this is what matlab uses
|
||||
$rowsum += $grey;
|
||||
$rowsum2 += $grey * $grey;
|
||||
|
||||
$ii_above = ($i - 1) * $ii_w + $j;
|
||||
$ii_this = $i * $ii_w + $j;
|
||||
|
||||
$ii[$ii_this] = $ii[$ii_above] + $rowsum;
|
||||
$ii2[$ii_this] = $ii2[$ii_above] + $rowsum2;
|
||||
}
|
||||
}
|
||||
return array('ii' => $ii, 'ii2' => $ii2);
|
||||
}
|
||||
|
||||
protected function doDetectGreedyBigToSmall($ii, $ii2, $width, $height)
|
||||
{
|
||||
$s_w = $width / 20.0;
|
||||
$s_h = $height / 20.0;
|
||||
$start_scale = $s_h < $s_w ? $s_h : $s_w;
|
||||
$scale_update = 1 / 1.2;
|
||||
for ($scale = $start_scale; $scale > 1; $scale *= $scale_update) {
|
||||
if ($this->timeout && microtime() - $this->time_start > $this->timeout) {
|
||||
throw new Exception("Face dectection has timed out");
|
||||
}
|
||||
$w = (20 * $scale) >> 0;
|
||||
$endx = $width - $w - 1;
|
||||
$endy = $height - $w - 1;
|
||||
$step = max($scale, 2) >> 0;
|
||||
$inv_area = 1 / ($w * $w);
|
||||
for ($y = 0; $y < $endy; $y += $step) {
|
||||
for ($x = 0; $x < $endx; $x += $step) {
|
||||
$passed = $this->detectOnSubImage($x, $y, $scale, $ii, $ii2, $w, $width + 1, $inv_area);
|
||||
if ($passed) {
|
||||
return array('x' => $x, 'y' => $y, 'w' => $w);
|
||||
}
|
||||
} // end x
|
||||
} // end y
|
||||
} // end scale
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function detectOnSubImage($x, $y, $scale, $ii, $ii2, $w, $iiw, $inv_area)
|
||||
{
|
||||
$mean = ($ii[($y + $w) * $iiw + $x + $w] + $ii[$y * $iiw + $x] - $ii[($y + $w) * $iiw + $x] - $ii[$y * $iiw + $x + $w]) * $inv_area;
|
||||
|
||||
$vnorm = ($ii2[($y + $w) * $iiw + $x + $w]
|
||||
+ $ii2[$y * $iiw + $x]
|
||||
- $ii2[($y + $w) * $iiw + $x]
|
||||
- $ii2[$y * $iiw + $x + $w]) * $inv_area - ($mean * $mean);
|
||||
|
||||
$vnorm = $vnorm > 1 ? sqrt($vnorm) : 1;
|
||||
|
||||
$count_data = count($this->detection_data);
|
||||
|
||||
for ($i_stage = 0; $i_stage < $count_data; $i_stage++) {
|
||||
$stage = $this->detection_data[$i_stage];
|
||||
$trees = $stage[0];
|
||||
|
||||
$stage_thresh = $stage[1];
|
||||
$stage_sum = 0;
|
||||
|
||||
$count_trees = count($trees);
|
||||
|
||||
for ($i_tree = 0; $i_tree < $count_trees; $i_tree++) {
|
||||
$tree = $trees[$i_tree];
|
||||
$current_node = $tree[0];
|
||||
$tree_sum = 0;
|
||||
while ($current_node != null) {
|
||||
$vals = $current_node[0];
|
||||
$node_thresh = $vals[0];
|
||||
$leftval = $vals[1];
|
||||
$rightval = $vals[2];
|
||||
$leftidx = $vals[3];
|
||||
$rightidx = $vals[4];
|
||||
$rects = $current_node[1];
|
||||
|
||||
$rect_sum = 0;
|
||||
$count_rects = count($rects);
|
||||
|
||||
for ($i_rect = 0; $i_rect < $count_rects; $i_rect++) {
|
||||
$s = $scale;
|
||||
$rect = $rects[$i_rect];
|
||||
$rx = ($rect[0] * $s + $x) >> 0;
|
||||
$ry = ($rect[1] * $s + $y) >> 0;
|
||||
$rw = ($rect[2] * $s) >> 0;
|
||||
$rh = ($rect[3] * $s) >> 0;
|
||||
$wt = $rect[4];
|
||||
|
||||
$r_sum = ($ii[($ry + $rh) * $iiw + $rx + $rw]
|
||||
+ $ii[$ry * $iiw + $rx]
|
||||
- $ii[($ry + $rh) * $iiw + $rx]
|
||||
- $ii[$ry * $iiw + $rx + $rw]) * $wt;
|
||||
|
||||
$rect_sum += $r_sum;
|
||||
}
|
||||
|
||||
$rect_sum *= $inv_area;
|
||||
|
||||
$current_node = null;
|
||||
|
||||
if ($rect_sum >= $node_thresh * $vnorm) {
|
||||
|
||||
if ($rightidx == -1) {
|
||||
|
||||
$tree_sum = $rightval;
|
||||
} else {
|
||||
|
||||
$current_node = $tree[$rightidx];
|
||||
}
|
||||
} else {
|
||||
|
||||
if ($leftidx == -1) {
|
||||
|
||||
$tree_sum = $leftval;
|
||||
} else {
|
||||
|
||||
$current_node = $tree[$leftidx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$stage_sum += $tree_sum;
|
||||
}
|
||||
if ($stage_sum < $stage_thresh) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user