Compare commits
1124 Commits
Author | SHA1 | Date |
---|---|---|
|
241583769e | |
|
77526c63ce | |
|
00988a4871 | |
|
9e797abb97 | |
|
076c6a32d7 | |
|
ff4bfad12f | |
|
8f41aad1a2 | |
|
fda25ccc0d | |
|
441a51c96e | |
|
df678c5a67 | |
|
1a20e28adf | |
|
8b33b8b118 | |
|
a318318da6 | |
|
4a38a86bdf | |
|
e05bd4d0d5 | |
|
ea700d360a | |
|
7d22fbede5 | |
|
63dde5e2c2 | |
|
03b4e1d662 | |
|
cea813109f | |
|
9e64b00231 | |
|
3bef725798 | |
|
0c15c92f46 | |
|
fec77f0714 | |
|
eebe5e2ddd | |
|
ec3272fb78 | |
|
2f37390b5f | |
|
e2d6bb8d63 | |
|
542f0b75fb | |
|
695c21354f | |
|
1e2eefb701 | |
|
a871ae89b5 | |
|
aac06d1c0f | |
|
bdc7487da6 | |
|
b78f595d04 | |
|
4e0e20c351 | |
|
9afe6f628d | |
|
f69d1e924a | |
|
431ea8845a | |
|
ef12639604 | |
|
0b5c5183d0 | |
|
8cddd61f28 | |
|
df968b47c9 | |
|
5b85edb4ce | |
|
ea2e64f1d3 | |
|
4df94a05b3 | |
|
571fb389eb | |
|
2a35de786c | |
|
2a837e614c | |
|
6ec6f17706 | |
|
715b5c0a68 | |
|
44ab37e059 | |
|
1b759cbf7e | |
|
ca4a9a2632 | |
|
c6395c0a38 | |
|
e8ebebf67d | |
|
59ad71de80 | |
|
20620c9f07 | |
|
01b52432e1 | |
|
6d9cc53f47 | |
|
f6d3d1e487 | |
|
eabd75b242 | |
|
093e679e33 | |
|
263742451e | |
|
e5d8d661a3 | |
|
d60510e6c0 | |
|
98ed3e6144 | |
|
339bfd5774 | |
|
2584ebc3c9 | |
|
28405b4492 | |
|
8230d44ead | |
|
5ecff77254 | |
|
af7f2c4402 | |
|
00393ddaf5 | |
|
de6634bf96 | |
|
bee09d6be5 | |
|
b9941211a4 | |
|
19c6587a5a | |
|
73e3e5599d | |
|
44c5b0a1b0 | |
|
50e0e95e2a | |
|
3573737eb9 | |
|
11457f853f | |
|
b9c2e7c903 | |
|
94b5d57b24 | |
|
bf8c520d0f | |
|
7e76ff6d08 | |
|
49f4c9ddb7 | |
|
1250256b39 | |
|
3039c88ae9 | |
|
03abf74f58 | |
|
7caf878698 | |
|
cc3f49c576 | |
|
3037a19d5a | |
|
8039010d89 | |
|
d3ca5c443c | |
|
b6106fd744 | |
|
d255fc8517 | |
|
1809d33d6a | |
|
8a94a728a6 | |
|
e8f93d0620 | |
|
7d3a5541bf | |
|
bf305d0e4b | |
|
42312e5501 | |
|
95f20080f2 | |
|
8907734985 | |
|
85cfa84fda | |
|
9998f3bf08 | |
|
fbe4fce452 | |
|
6ffcee0f2e | |
|
89256f5b83 | |
|
feabb1b215 | |
|
c6c32330ee | |
|
41316a5557 | |
|
8870c288f1 | |
|
f7de2dbb6b | |
|
47fc8e9c89 | |
|
def00d1e50 | |
|
420bbba8f1 | |
|
9883e392b2 | |
|
2391db70bb | |
|
72ec540d3f | |
|
3ae94863a8 | |
|
f21d07e304 | |
|
22e7a62030 | |
|
0feedd99aa | |
|
fe8635b33f | |
|
6609d71b10 | |
|
9337763f20 | |
|
57020cef47 | |
|
d8cd1ef780 | |
|
ac25a097da | |
|
1978970355 | |
|
5a6e6670ed | |
|
3386b4d948 | |
|
f134ae440d | |
|
a39497f019 | |
|
b9d5431258 | |
|
8031b9abdc | |
|
9ee3b098b6 | |
|
c4872f39ee | |
|
38fd2e7f2e | |
|
5d1e77472d | |
|
1ef791c5f9 | |
|
31568ff0fd | |
|
e7410e4bfb | |
|
7293094023 | |
|
ea1d9bf4d7 | |
|
a58841cef2 | |
|
e3c8cfda89 | |
|
a9e2a061ff | |
|
0a82d52a96 | |
|
c0a77ab2a9 | |
|
67240f5b5c | |
|
2a1c6c83b4 | |
|
cf181380bf | |
|
df2e6ba3c3 | |
|
67d7a5ca62 | |
|
ac64450de9 | |
|
8d1878b1c2 | |
|
a7bb2c1bc5 | |
|
cb2da9f991 | |
|
bb43544c59 | |
|
5140dc5b78 | |
|
909d535b5f | |
|
2179e9f30f | |
|
697685e268 | |
|
90d9a80f4f | |
|
123582b730 | |
|
ed2c9abba5 | |
|
63f42c130c | |
|
dcee9a7dc7 | |
|
ca3a074e77 | |
|
eee3f4382a | |
|
448a47b5a3 | |
|
648fb32987 | |
|
e6fa02d41a | |
|
00e7364950 | |
|
c2a740920c | |
|
e2873c30f0 | |
|
abda0b2265 | |
|
18adb9e379 | |
|
9b745228c6 | |
|
967b57999d | |
|
bf3a0a22ea | |
|
3c013380df | |
|
22960059f2 | |
|
0036e53a1d | |
|
b3c4fff620 | |
|
1d2d06b60d | |
|
4985df2ebc | |
|
b8e19be76f | |
|
5d0e3102ee | |
|
50e02eaa16 | |
|
c35e24d08b | |
|
869a7fddab | |
|
8865fec6d9 | |
|
aa831bd8fc | |
|
47b2df170c | |
|
c85540c888 | |
|
635ad11534 | |
|
968ace04b4 | |
|
f41b025dce | |
|
0662ba11d7 | |
|
bbd0825f6a | |
|
bee21f02da | |
|
058c76fb45 | |
|
c808e25967 | |
|
4661a184b0 | |
|
6e846483f2 | |
|
4eeeed12d8 | |
|
50e3d73400 | |
|
527b0c82e5 | |
|
857a8694f9 | |
|
540fe7b4d2 | |
|
44a9355477 | |
|
8da9743c29 | |
|
585c47bb18 | |
|
58aa7675ce | |
|
7defba3e5a | |
|
63a002cdf0 | |
|
1dc8343e0b | |
|
b969957394 | |
|
786f638706 | |
|
97c1817c65 | |
|
4c83fe7c73 | |
|
450494f279 | |
|
a7bf474c84 | |
|
06d0b87cee | |
|
57a389fc6a | |
|
4b8a12e164 | |
|
137a5e6ffe | |
|
8c20974e5b | |
|
01cf1379d0 | |
|
158d463232 | |
|
d2bdd6cc19 | |
|
432d781ce2 | |
|
063337f9cb | |
|
dac7d5f5cd | |
|
bcf6c7a142 | |
|
8fc4ccc7be | |
|
cf917bd94f | |
|
07e326bd9f | |
|
d8829ac8f8 | |
|
16f9bf4032 | |
|
d497d6ae92 | |
|
e8cf2a53e2 | |
|
4fdb6a6c94 | |
|
b14fced154 | |
|
9333c2c119 | |
|
894e3aea5a | |
|
6501672ac6 | |
|
408b88457b | |
|
5cb07c8b08 | |
|
b1a815dce2 | |
|
03b1cf0ded | |
|
3b6ff36a9c | |
|
7de3170635 | |
|
246f0e8295 | |
|
eb68e8f92d | |
|
2d91614f43 | |
|
143272993e | |
|
f4a85c583e | |
|
818ce3cc1e | |
|
4c23e1cf95 | |
|
e0f02d302d | |
|
ed5d524fff | |
|
672c9ce34e | |
|
f57ee2ab7e | |
|
fbc4b3d718 | |
|
eadeb43b8a | |
|
146a36ab9e | |
|
1cc40b76e2 | |
|
cccd2b3c39 | |
|
f25ea17ba7 | |
|
1bc6e5d3fe | |
|
5871b8e608 | |
|
00ca74ee24 | |
|
a569100444 | |
|
6096968262 | |
|
1bae45821a | |
|
5d55ad191d | |
|
e62d206c14 | |
|
2f8fb8077a | |
|
dbf6846653 | |
|
aa93371e2b | |
|
b3d8779005 | |
|
4152b51b83 | |
|
9df84eb7fb | |
|
ec326c35f5 | |
|
f9c5b4aa35 | |
|
6b7fa73bc3 | |
|
9b1e2e82e0 | |
|
961186c3d1 | |
|
edde4a50ce | |
|
927f1abf6a | |
|
1710ec1720 | |
|
03eb6a166b | |
|
c41ca167eb | |
|
901c79edb2 | |
|
f144877ee1 | |
|
5e66283d09 | |
|
d23788ca8b | |
|
1e68240070 | |
|
e0f0fcdd27 | |
|
c65bbd3f39 | |
|
9f0e319a03 | |
|
8ffe852c19 | |
|
fc495377d6 | |
|
c4e3c2f484 | |
|
c9f007db16 | |
|
9858c371c6 | |
|
ec940b82f2 | |
|
c8c5f59abf | |
|
2ebb059b3e | |
|
f98ae71340 | |
|
7b8018c68a | |
|
95f7840a44 | |
|
8a018f8606 | |
|
519c7219cd | |
|
9b9744b134 | |
|
072c2e615a | |
|
95b0fc5b1a | |
|
6809ca0ce3 | |
|
97a3c0ef47 | |
|
b4d2fec82b | |
|
edda7c38e2 | |
|
c1f86dace3 | |
|
b975cbc24e | |
|
6172a7c89b | |
|
ce8ac0f846 | |
|
eb15f24ac9 | |
|
c20ba3eeee | |
|
f373036f15 | |
|
025dc5dcd3 | |
|
2700b0c0f8 | |
|
4da98e49d0 | |
|
5ac04f4a01 | |
|
982f029f43 | |
|
bc43765546 | |
|
fedf455b1f | |
|
6c6fb4fd24 | |
|
6bf644e45d | |
|
e4b2fceda2 | |
|
3419d5fcaa | |
|
1bb6311339 | |
|
6873ec686a | |
|
477a56e953 | |
|
de4759fd5b | |
|
6369cb466e | |
|
00baaa0788 | |
|
cd80a18bca | |
|
783fd1a9c6 | |
|
60282b2007 | |
|
2d03b1b173 | |
|
62137f0da7 | |
|
e4a7fa2cf0 | |
|
df3ce50315 | |
|
76fde27116 | |
|
1eb711d873 | |
|
247ad030ca | |
|
9f57920975 | |
|
9b4cccf2fe | |
|
982829ca88 | |
|
d7822c33bf | |
|
728c30d5a2 | |
|
d853766ff7 | |
|
37517ce0b9 | |
|
4a7db72004 | |
|
2f56ddcfb2 | |
|
8c02c99132 | |
|
6d0f6ba3ac | |
|
7b9811bd69 | |
|
450633b863 | |
|
317884b8ea | |
|
3d85b76a93 | |
|
b72dce21dc | |
|
62d372df0a | |
|
22edea5520 | |
|
0ace49cec3 | |
|
ab2f83fbf0 | |
|
cd1cb11198 | |
|
41f75cf19f | |
|
847177a0ec | |
|
a6faefaa99 | |
|
0459dd2e4a | |
|
1535abf4a6 | |
|
e506e4b18a | |
|
ed056e060d | |
|
9ff3022deb | |
|
71cacecf75 | |
|
126949a16c | |
|
6f4ca17fb7 | |
|
0f9c5e71dd | |
|
365bdf5551 | |
|
22cec86092 | |
|
8072aaf537 | |
|
72f569659a | |
|
9fda45c411 | |
|
da0999dd84 | |
|
cd12fb6e4d | |
|
4e2f399a59 | |
|
f3126950c4 | |
|
caa2b4bd44 | |
|
d4866e4ce4 | |
|
529cf6f5c5 | |
|
88ba7311b3 | |
|
c3338c78a9 | |
|
a864b251b2 | |
|
dfedb4b512 | |
|
700b67a3d2 | |
|
e1c7781c8b | |
|
5ecaf54c12 | |
|
1b8c632d69 | |
|
9fce000535 | |
|
e71ede0641 | |
|
d451464911 | |
|
54b45f1656 | |
|
99ec335ee5 | |
|
db698f114d | |
|
83c400f693 | |
|
ab061d6f7e | |
|
dd8c2ef464 | |
|
4d49a52296 | |
|
0091fca368 | |
|
11e4482d0a | |
|
935738af86 | |
|
15d55d140b | |
|
68fac4c12a | |
|
5fff793da2 | |
|
4592e7de5b | |
|
7cd57dd12a | |
|
160947e49a | |
|
5cbc4125a7 | |
|
203606855e | |
|
96120c4b4a | |
|
ffcedce0ed | |
|
d2c79a9cb5 | |
|
e58f728c6f | |
|
0b03fb8d1e | |
|
2d4846ceb1 | |
|
d2381c453e | |
|
24c316594f | |
|
715b715248 | |
|
fbea29d7fd | |
|
092e9880e8 | |
|
bf34ae7051 | |
|
2df908b11c | |
|
a6363ca6c5 | |
|
639eda7eac | |
|
ee2320338e | |
|
649673eb1c | |
|
e0ce1b3bfc | |
|
5dd1302a1e | |
|
f093ba4382 | |
|
1c1072d4ed | |
|
6e16df9669 | |
|
780c67102f | |
|
ca88797519 | |
|
87b23d8ae7 | |
|
af7cf059a0 | |
|
add94f9bd0 | |
|
08b6bb5556 | |
|
2560328be8 | |
|
6c7a47700a | |
|
a22597e29d | |
|
cf6d7c9b01 | |
|
c349125f4f | |
|
e5a2e75b2d | |
|
ceea29fb80 | |
|
6f117d5fbf | |
|
54330664f3 | |
|
cc34b665f7 | |
|
c459ebe812 | |
|
366da4d89e | |
|
c9a3731378 | |
|
e32bdec38f | |
|
1ba9f45549 | |
|
8c2a3023a4 | |
|
b6cf28aa7c | |
|
837bcae1b2 | |
|
2ea249275a | |
|
646fc7390a | |
|
c86aa025dd | |
|
98ef40d45d | |
|
f53559eef1 | |
|
d818d2e393 | |
|
aa14944c92 | |
|
d60890734e | |
|
395aeae7b6 | |
|
21c08cbcdb | |
|
55c386e7b4 | |
|
d9148f2622 | |
|
8dd7577557 | |
|
82204f66dc | |
|
897b29e60a | |
|
ffc81244e6 | |
|
44021dfa8b | |
|
d321458d25 | |
|
8cc3137ba2 | |
|
8a48347649 | |
|
b042c567ef | |
|
56f144604b | |
|
180422cb6f | |
|
286ad99d2a | |
|
ba90d10567 | |
|
2cbf758edd | |
|
604fad69f6 | |
|
a96fa70eb3 | |
|
69d05523bd | |
|
615f1b92ca | |
|
8622ad9da0 | |
|
38cd6a4145 | |
|
df54653961 | |
|
f2ede64b1a | |
|
3fbe9bbe50 | |
|
47e1a4a1d0 | |
|
8aaecb8218 | |
|
3adc516ed2 | |
|
0af35e0a64 | |
|
05a6bb9123 | |
|
ee25709e46 | |
|
7fb94fde8f | |
|
032a60f653 | |
|
5ff6d4c427 | |
|
c7720101b9 | |
|
138030d5c0 | |
|
5624f9ea07 | |
|
0d005c1a97 | |
|
1016296697 | |
|
8aaabb3f88 | |
|
c7cdee2a67 | |
|
169df3fc07 | |
|
407e04ee17 | |
|
1e41d3f33d | |
|
1a3da53ba9 | |
|
afa646c36a | |
|
fe9e082f66 | |
|
dd211750d3 | |
|
a5994a5eb4 | |
|
cf68c56b3a | |
|
5cc4a2884f | |
|
eff9ad1783 | |
|
ba8d30ecb0 | |
|
a615bea36e | |
|
502dcd326a | |
|
d9bf9b57e7 | |
|
9278651f00 | |
|
e682aba173 | |
|
4f90f52bba | |
|
aef2266684 | |
|
cb7d6d425d | |
|
54e1e961bf | |
|
ba2109c042 | |
|
344e116b90 | |
|
08dd078a71 | |
|
a3d1313469 | |
|
61199687d3 | |
|
2d3465ce4f | |
|
659ea9f97a | |
|
91ddc0c77b | |
|
675d1f11da | |
|
877379134b | |
|
88e5623a9e | |
|
00e8fb9be1 | |
|
5d2d4ca620 | |
|
49083abc6a | |
|
0294d0aa87 | |
|
a5c8bdf718 | |
|
4aad89de9b | |
|
cb1e69f6ec | |
|
5f79a6ee71 | |
|
7a904d5450 | |
|
3c190fdcb9 | |
|
2f78d4f555 | |
|
cafb43878d | |
|
77bf9dd235 | |
|
acb0a5da1d | |
|
4c4c4080dc | |
|
6d33274dbb | |
|
5d77defea7 | |
|
ef16c663eb | |
|
aa1abce671 | |
|
762463d01a | |
|
7e2b19ee45 | |
|
9f53db57db | |
|
9d9bd9e4bc | |
|
8f279df90a | |
|
d63a9f300c | |
|
ff5e68e5ec | |
|
c05cb17fb0 | |
|
eca64a10d4 | |
|
791d1431f4 | |
|
f43d67e20d | |
|
0ade18167a | |
|
72171f24b9 | |
|
8e42483c7e | |
|
6318f722bd | |
|
1985015aeb | |
|
cd92b6b58f | |
|
04f0d8a20c | |
|
fd7a021605 | |
|
9d8f884e18 | |
|
7c3e8a63d4 | |
|
641d1aee80 | |
|
ca0cc77b86 | |
|
cc834940d2 | |
|
20a4c9dc2e | |
|
6406135540 | |
|
752d4feceb | |
|
ccc80f5408 | |
|
67eac60e8b | |
|
a69f016a29 | |
|
cd801efce9 | |
|
da00337c6c | |
|
c6da8e890a | |
|
1fbb02fbaa | |
|
0d85aba8f6 | |
|
87529dd442 | |
|
132579719c | |
|
2cbbea902b | |
|
685a1b7dcb | |
|
c894c20c12 | |
|
58dcb1e099 | |
|
98259586f1 | |
|
6168165bcb | |
|
331fb5094e | |
|
9073633705 | |
|
026127d7b3 | |
|
8cecb9c4eb | |
|
5b8f1e9834 | |
|
e1fb9d763c | |
|
d5285a36b4 | |
|
36998c07a2 | |
|
cced7ac246 | |
|
e113edaacb | |
|
088f520374 | |
|
b1fbc4ce21 | |
|
3774755825 | |
|
bf399db100 | |
|
61facdfc3d | |
|
a058f89f9a | |
|
0f8b68e7d6 | |
|
6490ca640d | |
|
39b6c16345 | |
|
9e0abc0d8a | |
|
fce1ce09c9 | |
|
c39cc5412d | |
|
7fdf81dafa | |
|
2bde2db940 | |
|
1b3ba587e4 | |
|
760b594e70 | |
|
74930d424f | |
|
12a3a760e3 | |
|
b7f2fa13b6 | |
|
70d48973bd | |
|
09b2f3d236 | |
|
fe6677e760 | |
|
17e004f0f7 | |
|
1bb7878a06 | |
|
fa42d44bb2 | |
|
6552a1bba3 | |
|
0d81129756 | |
|
04e541ff6a | |
|
ed1e233eee | |
|
93adf5b23e | |
|
99eb832786 | |
|
01c8675215 | |
|
a5e39bf800 | |
|
3a5a942051 | |
|
bb4fb17b4d | |
|
e684fe1e12 | |
|
7fdad47f3b | |
|
8e2049270b | |
|
f54ec72fc7 | |
|
03dd006979 | |
|
963e214308 | |
|
1525a72efe | |
|
84c3e061ee | |
|
bcb8cb0ac3 | |
|
0925445981 | |
|
a490a5746b | |
|
8227b32fda | |
|
7efb51f0bb | |
|
5c7f5cc712 | |
|
4633113022 | |
|
f1f3e553a7 | |
|
8789a839ad | |
|
657a9b47e6 | |
|
ad29334cc0 | |
|
98b79a3052 | |
|
cdbda8eaed | |
|
31d11bdee0 | |
|
c3107c1969 | |
|
6a24c96952 | |
|
ae2cfdde4f | |
|
39374285e0 | |
|
8373970656 | |
|
5334747609 | |
|
6da04b302e | |
|
6f7d9f1dc3 | |
|
67856a523a | |
|
263e9b100f | |
|
3fffd5f1d9 | |
|
8b6ebe4be1 | |
|
c6fced8ff2 | |
|
ecb234178d | |
|
4b380fbff5 | |
|
eedada707b | |
|
886ae8fe14 | |
|
52400fac42 | |
|
2720e99581 | |
|
0e1afcff37 | |
|
fafab7221f | |
|
435edd153a | |
|
e41618dc7d | |
|
45f0edf0ab | |
|
8d0bcbc1d0 | |
|
5d11a63c18 | |
|
b2b39cbff4 | |
|
7385be6218 | |
|
a711877c19 | |
|
ca82ceb175 | |
|
7d928242cb | |
|
fc25f24713 | |
|
ed2408b3ca | |
|
a6692b34bb | |
|
c86b027955 | |
|
7e16c40d24 | |
|
66b5e663ee | |
|
04c89f8596 | |
|
be1200fb7b | |
|
88bd9c993d | |
|
17a6174f9f | |
|
ad96b9e30c | |
|
9c91c51042 | |
|
c3861da79e | |
|
0b402f12d1 | |
|
9e4ced1fea | |
|
c3bebe640f | |
|
82cdbeb723 | |
|
06991f8b79 | |
|
a9c4abfef6 | |
|
5beba88c4b | |
|
2f42eb061e | |
|
331e525ee9 | |
|
571b5d2f85 | |
|
74ad2bd1e3 | |
|
801ed47ef8 | |
|
94c630b8de | |
|
17fa885d33 | |
|
09934d7f7a | |
|
d6359306be | |
|
c8c3afbc83 | |
|
7782769922 | |
|
58bab546d8 | |
|
107eb6fb4d | |
|
cf0ff2c4ae | |
|
068e0cd102 | |
|
4e573c53df | |
|
0f60108464 | |
|
305c772f80 | |
|
5c38f26f48 | |
|
b56416712f | |
|
b23315f2b2 | |
|
67e3e8db9f | |
|
bb4ba12185 | |
|
66305b3657 | |
|
6722e59de4 | |
|
e13ad96b65 | |
|
9e07fb442f | |
|
92b4746585 | |
|
bf275837e0 | |
|
ff89f281e2 | |
|
c6107b0121 | |
|
4e9169f227 | |
|
71eea29909 | |
|
b36a5f7d91 | |
|
7cd3b7180e | |
|
2bafa32b19 | |
|
033fff9b00 | |
|
0c6293bac3 | |
|
8fd3170fdd | |
|
71b1f91005 | |
|
47801bf4f8 | |
|
9e6d1ba37e | |
|
1c2202a51b | |
|
8966998511 | |
|
992d0bc57e | |
|
14f3ef9556 | |
|
abea14a12e | |
|
b2c05c8701 | |
|
620a3317e1 | |
|
9f01ead36b | |
|
d29cc8d55e | |
|
4162871c10 | |
|
6b80a88343 | |
|
9e2b76ffdf | |
|
2541aaec3a | |
|
725a0870d5 | |
|
fbdd4f4587 | |
|
921fc0ad98 | |
|
328f03b473 | |
|
039054a300 | |
|
9c1d3a0ed7 | |
|
6bb0bad1dd | |
|
ac78f3d589 | |
|
f527f7cfe9 | |
|
e18c2e2da6 | |
|
7ee0b0ff50 | |
|
1f8cd4edd0 | |
|
775903561c | |
|
ae996c22a2 | |
|
754d5d22bf | |
|
f96cc83379 | |
|
c8ceb36dc8 | |
|
f693fbfe7b | |
|
87f91d4ab2 | |
|
4d2a5bf0ea | |
|
59aabaf705 | |
|
13dbb3d80a | |
|
764ffb7639 | |
|
c26cc608f4 | |
|
02ffb6d811 | |
|
0bd7cb533b | |
|
3b35d3ff42 | |
|
3e3d70e87e | |
|
17423f2131 | |
|
f0aba5bd4b | |
|
92fb4f9bd0 | |
|
0462c0acc0 | |
|
5b4abf66f1 | |
|
b3c6cb7110 | |
|
453b3603cc | |
|
0dace8b900 | |
|
f01affbf55 | |
|
2636a71ef7 | |
|
c0b632b4e6 | |
|
2dae8961a3 | |
|
02b9f581e3 | |
|
702ddd712d | |
|
58736564be | |
|
6e31818c53 | |
|
f380044c60 | |
|
322e7483f5 | |
|
3edf623da0 | |
|
f463e0cab7 | |
|
54bb955759 | |
|
34a0edd2d0 | |
|
f40d3ee4f3 | |
|
98a7a6ed79 | |
|
7cdfbbff18 | |
|
96f1a62e0f | |
|
7aa8e90d24 | |
|
421f4129a7 | |
|
07f3f139a6 | |
|
9976403e41 | |
|
9996dc6df8 | |
|
9ec77ca597 | |
|
2d2bf85710 | |
|
cb984db073 | |
|
29f35ff91e | |
|
513e17e33d | |
|
5539326a58 | |
|
0e14bf0923 | |
|
14f55a1998 | |
|
307570f0cb | |
|
c1fe86c222 | |
|
b4b4a67abf | |
|
af97d0d310 | |
|
02c35f1d41 | |
|
ec48dffbcd | |
|
566e0e0e38 | |
|
f15b28fcb3 | |
|
70c9e02126 | |
|
6dffe7b481 | |
|
3501e0ffee | |
|
bf5fcd87fe | |
|
768b5fd5a7 | |
|
f16395151a | |
|
17f64af531 | |
|
66d6912c92 | |
|
90c31c9d23 | |
|
8b2bd668a8 | |
|
4ccbcc7cab | |
|
96df096a68 | |
|
9736ec97aa | |
|
3fad8c53a1 | |
|
ea49c110d4 | |
|
e6e8ed58da | |
|
1edc3189ff | |
|
fd8869d400 | |
|
47c65d4802 | |
|
90a8a6527c | |
|
e04785d530 | |
|
02c988db3f | |
|
fa68a95c58 | |
|
93527d7c7c | |
|
69bb242570 | |
|
4ea3cc130c | |
|
52150c17d7 | |
|
c2744876c6 | |
|
a8ad5f3f5a | |
|
224e1eca85 | |
|
1ea3829ae1 | |
|
968fd7f1dc | |
|
bf19f15f52 | |
|
0c41dc9bb8 | |
|
09fe13d5d9 | |
|
eed67da504 | |
|
154b2a80f4 | |
|
0a606fece8 | |
|
1dea0135da | |
|
34c3b6242b | |
|
d7316f73ee | |
|
c28adb3d79 | |
|
d8d3855052 | |
|
741130f30b | |
|
0aebed89cf | |
|
7faaf50888 | |
|
bff0ddf748 | |
|
70f8a79d91 | |
|
fe1ea7e935 | |
|
2b9f735f98 | |
|
967c6a28d6 | |
|
1f4fca3c6e | |
|
5352e4ab24 | |
|
7ec7a26505 | |
|
d57ee7edaa | |
|
e752db93c0 | |
|
8d7740b271 | |
|
dc0b739c7e | |
|
d0a8011ce6 | |
|
b1080c129b | |
|
68ae1bd206 | |
|
fc0d100d7b | |
|
341e85869c | |
|
d0a6957f5a | |
|
6aa15f0da3 | |
|
925f7da15f | |
|
72c4f0d0f8 | |
|
848c2bf22c | |
|
ce2da169ff | |
|
dcfa03b2b9 | |
|
e4ace9b192 | |
|
818d0a6b02 | |
|
5b4208d007 | |
|
de5ebf5eda | |
|
2f5518303e | |
|
6f7563345e | |
|
7522a67263 | |
|
88d400b132 | |
|
405c2f01e5 | |
|
4e67b8efb3 | |
|
f715c8a77b | |
|
02930cfe8a | |
|
3613eb18dc | |
|
c96d66cbf9 | |
|
ed7ae630b9 | |
|
678029eeea | |
|
211a74f7f6 | |
|
2bed6d7da2 | |
|
d8ef71b3f1 | |
|
0c79ebb073 | |
|
3eb359d25c | |
|
b0ddbc5e7a | |
|
618164dbbd | |
|
2e7f11d2c5 | |
|
d58052df2e | |
|
39035f459e | |
|
d2a0d25ab5 | |
|
eac54f9c98 | |
|
3e0028db06 | |
|
09f3407579 | |
|
41cdce5f1b | |
|
590104dabc | |
|
0d0f986f1d | |
|
ee5a693652 | |
|
31c5199be6 | |
|
6d924749e2 | |
|
d2c666ce18 | |
|
d3c82137f4 | |
|
2fcff3c80c | |
|
7572affced | |
|
d640e806eb | |
|
e4a4b3a7c4 | |
|
3bf253587e | |
|
3808e0612d | |
|
5409b5af7e | |
|
02dc04e937 | |
|
6c93ce4ad1 | |
|
b181d26af8 | |
|
ad5e8c174b | |
|
1d0efdf6d3 | |
|
c762f8fa55 | |
|
6b9776e0a9 | |
|
99213c1127 | |
|
a2ef25ef13 | |
|
f899c57ed2 | |
|
c70de5ceb5 | |
|
9236b8ec1f | |
|
c4b6c1fcb0 | |
|
195edf22b4 | |
|
d674dfb2aa | |
|
b65ca03e52 | |
|
2bd2b33509 | |
|
053200de9d | |
|
652917b137 | |
|
d92f1b980e | |
|
dfcd04755e | |
|
5bfa7e71f4 | |
|
0ccfaa0fff | |
|
5ae664af99 | |
|
905a20051c | |
|
22bfae0c0f | |
|
8fe7b769c8 | |
|
3dcb5b0c3a | |
|
8061481ddf | |
|
d68feee4c3 | |
|
c3bbde2395 | |
|
ad1ea0f933 | |
|
1c7fa5a5b5 | |
|
cf65bf5bcc | |
|
2c4768438a | |
|
dba329953f | |
|
2b0c5f886e | |
|
7dc118b075 | |
|
072a240d4d | |
|
c400eb7614 | |
|
11b3fb7664 | |
|
54f9c58c63 | |
|
352b97d71a | |
|
51ee3c48db | |
|
e651812528 | |
|
88c4651f8e | |
|
8669c5ef7c | |
|
2f7ddad013 | |
|
9b0e6947b0 | |
|
5ced7116bb | |
|
04a8989ae8 | |
|
63f00a80b5 | |
|
6f83f01e47 | |
|
d5b232743b | |
|
78d03c8260 | |
|
8dba03e2bb | |
|
543e39d6cc | |
|
f2f1d5528c | |
|
85e8f861b0 | |
|
6cc4607892 | |
|
ce924f434b | |
|
53792e1acd | |
|
328a41915c | |
|
8a47d54026 | |
|
369ffb9edb | |
|
2394855b57 | |
|
6db962f068 | |
|
262e8016a7 | |
|
ec971fec1f | |
|
4832ac44f4 | |
|
b1c2f56537 | |
|
fda99fd92b | |
|
8ac662a6ff | |
|
f14b151c32 | |
|
9a29164d48 | |
|
af7e0b5e34 | |
|
fb8e67ec10 | |
|
4c66be78a4 | |
|
1f6ea9ef45 | |
|
8754b1c750 | |
|
20a15f2494 | |
|
3dd9d654bc | |
|
057120b338 | |
|
cb22d644ba | |
|
bcf1273903 | |
|
f6aa14fba8 | |
|
6e9c7d6330 | |
|
d733a1db4a | |
|
ab6c0f11c5 | |
|
3db93349d1 | |
|
ffc5585bea | |
|
648b708683 | |
|
1a058239df | |
|
19317428f5 | |
|
a7b67ae947 | |
|
baf184de84 | |
|
c4ff568437 | |
|
901b64d1db | |
|
7276a0a913 | |
|
8fc61a8199 | |
|
d676fee946 | |
|
6393c58256 | |
|
ebf7da62c4 | |
|
32276222c2 | |
|
f251677606 | |
|
8d681a96d9 | |
|
ff55cd430f | |
|
a8df2fcb08 | |
|
9da4e35705 | |
|
6c41fab087 | |
|
6660dda5b3 | |
|
93b6eecd19 | |
|
6ea89e29dc | |
|
9a62a4604c | |
|
f726d2629c | |
|
f1f9752f76 | |
|
2a7a6704bd | |
|
d152e6cc51 | |
|
92354a0281 | |
|
1bb63bb99b | |
|
045ccd16fd | |
|
893850db4b | |
|
8bde63c0b0 | |
|
b95d551b22 | |
|
6ea7b52e3d | |
|
a9d5468678 | |
|
6466bed391 | |
|
69bb54b04b | |
|
80848ac799 | |
|
7745e29c13 | |
|
686c9af24e | |
|
2f2655fc7d | |
|
95ca1f6488 | |
|
af2f79f817 | |
|
d0884fb87c |
|
@ -91,8 +91,10 @@ REVISION
|
|||
.php_cs.cache
|
||||
manifest.json
|
||||
checksum.json
|
||||
database.json
|
||||
database_5_7.json
|
||||
mysql.json
|
||||
mysql_5_7.json
|
||||
mariadb_10_x.json
|
||||
settings.json
|
||||
|
||||
/tests/_log/*
|
||||
/tests/_temp/*
|
||||
|
|
|
@ -90,3 +90,7 @@ ServerSignature Off
|
|||
mod_gzip_item_exclude mime ^image/.*
|
||||
mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_mime.c>
|
||||
AddType text/javascript mjs
|
||||
</IfModule>
|
307
CHANGELOG.md
307
CHANGELOG.md
|
@ -4,6 +4,14 @@ Tutti i maggiori cambiamenti di questo progetto saranno documentati in questo fi
|
|||
|
||||
Il formato utilizzato è basato sulle linee guida di [Keep a Changelog](http://keepachangelog.com/), e il progetto segue il [Semantic Versioning](http://semver.org/) per definire le versioni delle release.
|
||||
|
||||
- [2.5.2 (2024-05-31)](#252-2024-05-31)
|
||||
- [2.5.1 (2024-04-24)](#251-2024-04-24)
|
||||
- [2.5 (2024-03-28)](#25-2024-03-28)
|
||||
- [2.4.54 (2024-02-02)](#2454-2024-02-02)
|
||||
- [2.4.53 (2024-01-05)](#2453-2024-01-05)
|
||||
- [2.4.52 (2023-12-08)](#2452-2023-12-08)
|
||||
- [2.4.51 (2023-10-30)](#2451-2023-10-30)
|
||||
- [2.4.50 (2023-10-06)](#2450-2023-10-06)
|
||||
- [2.4.49 (2023-09-22)](#2449-2023-09-25)
|
||||
- [2.4.48 (2023-08-01)](#2448-2023-08-01)
|
||||
- [2.4.47 (2023-06-30)](#2447-2023-06-30)
|
||||
|
@ -60,6 +68,305 @@ Il formato utilizzato è basato sulle linee guida di [Keep a Changelog](http://k
|
|||
- [2.2 (2016-11-10)](#22-2016-11-10)
|
||||
- [2.1 (2015-04-02)](#21-2015-04-02)
|
||||
|
||||
## 2.5.2 (2024-05-31)
|
||||
### Aggiunto (Added)
|
||||
- Migrazione a tema grafico AdminLTE 3
|
||||
- Aggiunto plugin Assicurazione crediti
|
||||
- Aggiunta gestione dei file header.php
|
||||
- Aggiunta Tags in Attività
|
||||
- Aggiunta la gestione del calcolo della media sulle colonne delle viste
|
||||
- Aggiunti Marca e Modello su Impianti
|
||||
- Aggiunto avviso in caso di permessi assenti sui vari segmenti
|
||||
- Aggiunta legenda in Scadenzario
|
||||
- Aggiunti nuovi temi grafici
|
||||
- Aggiunta funzione di ridimensionamento immagini
|
||||
|
||||
### Modificato (Changed)
|
||||
- Migliorato il conteggio dei caratteri per la generazione delle righe in stampa
|
||||
- Migliorata la gestione delle attività in dashboard con apertura su nuova scheda
|
||||
- Aggiornato lo stylesheet FE
|
||||
- Migliorata la gestione delle rate nello scadenzario
|
||||
- Ottimizzato il codice per php8.3
|
||||
|
||||
### Fixed
|
||||
- Corretta l'esportazione delle Ri.Ba.
|
||||
- Corretto il controllo della numerazione attività
|
||||
- Corretta la modifica del nome degli allegati
|
||||
- Corretta la correzione degli allegati in Attività
|
||||
- Corretta l'impostazione della banca controparte in fattura
|
||||
- Corretto l'invio del sollecito di pagamento
|
||||
- Corretta la ricerca del metodo di pagamento
|
||||
- Corrette la ricerca globale su ddt e automezzi
|
||||
- Corretta l'esportazione bancaria
|
||||
- Corretta la creazione dei campi personalizzati in fase di creazione documenti
|
||||
- Corretta la registrazione delle scadenze da azioni di gruppo
|
||||
|
||||
## 2.5.1 (2024-04-24)
|
||||
### Aggiunto (Added)
|
||||
- Aggiunto user-agent nei log di accesso
|
||||
- Aggiunta la visualizzazione delle checklist impianti in stampa Attività
|
||||
- Aggiunta colonna Gruppi abilitati in **Categorie documenti**
|
||||
|
||||
### Modificato (Changed)
|
||||
- Ottimizzato il codice per renderlo compatibile con php8.1
|
||||
- Migliorata la procedura di aggiornamento
|
||||
- Rinominato il plugin **Sedi** in **Sedi aggiuntive**
|
||||
- Modificata la forzatura aggiornamento in ?force=1
|
||||
|
||||
### Fixed
|
||||
- Corretto il salvataggio nome in **Viste**
|
||||
- Ripristinata la verifica query in **Viste**
|
||||
- Corretta la gestione degli allegati
|
||||
- Corretta l'azione di gruppo per il download degli allegati
|
||||
- Corretta la selezione anagrafiche clienti-fornitori
|
||||
- Corrette le stampe contabili
|
||||
- Corretti gli upload di moduli, plugins e template
|
||||
- Corretta l'aggiunta attività
|
||||
- Corretta la gestione degli automezzi per tecnico
|
||||
- Corretto il caricamento dei promemoria da pianificare in dashboard
|
||||
- Corretta l'emissione di fatture
|
||||
|
||||
## 2.5 (2024-03-28)
|
||||
### Aggiunto (Added)
|
||||
- Aggiunte le tabelle '_lang' per la gestione delle traduzioni dei dati presenti a database
|
||||
- Aggiunta log rimozione sessioni per velocizzare la sincronizzazione dell'app
|
||||
- Introduzione del file Known-issue.md
|
||||
- Aggiunle le skin light per i temi
|
||||
- Aggiunta colonna N. utenti abilitati e N. api abilitate nel modulo **Utenti e permessi**
|
||||
- Aggiunto il riferimento alle attività collegate nei moduli **DDT**
|
||||
- Aggiunto il blocco **Aggiorna informazioni di acquisto** in fase di importazione fattura elettronica
|
||||
- Aggiunta creazione automatica della banca in fase di importazione CSV anagrafiche
|
||||
- Aggiunta informazioni di creazione per campi delle viste
|
||||
- Aggiunto il flag 'Fatture elettroniche' in segmenti
|
||||
- Aggiunta la visualizzazione delle sessioni attive in **Stato dei servizi**
|
||||
- Aggiunta la navigazione tra **Attività** con codice precedente e successivo
|
||||
- Aggiunto un avviso nel caso di righe con quantità a 0 nelle **Fatture di vendita**
|
||||
- Aggiunto un controllo sulla partita IVA per **Fatture** emesse verso anagrafiche cliente di tipo Azienda o codice fiscale se Ente pubblico
|
||||
- Aggiunto controllo per validare il codice dell'intermediario in **Anagrafica**
|
||||
- Aggiunta la validazione dell'indirizzo email in aggiunta **Utente**
|
||||
- Aggiunta la controparte in plugin **Movimenti**
|
||||
- Aggiunta la **stampa cespiti**
|
||||
- Aggiunta la verifica di integrità database per MariaDB
|
||||
- Aggiunta la possibilità di creare **Backup** escludendo la cartella files e il database
|
||||
- Aggiunta la gestione dei campi personalizzati su applicazione
|
||||
- Aggiunta la gestione della visualizzazione articoli distinta inline nei documenti
|
||||
- Aggiunta impostazione Raggruppa attività per tipologia in fattura
|
||||
- Introduzione connettori per il caricamento dei file
|
||||
- Aggiunta gestione stato fattura Non valida
|
||||
- Aggiunta gestione pagamento in **Attività**
|
||||
|
||||
### Modificato (Changed)
|
||||
- Abilitato il ritorno al punto precedente anche per i dispositivi mobili
|
||||
- Aggiornata la chiave di licenza per Wacom v2
|
||||
- Migliorato graficamente il riquadro **Plugin**
|
||||
- Migliorata la **Stampa fatturato** escludendo le autofatture
|
||||
- Migliorato il plugin **Regole pagamenti**
|
||||
- Migliorata l'impostazione della ricevuta della fattura elettronica nel caso di ricevuta di scarto per fattura duplicata
|
||||
- Migliorato l'avviso della scadenza per l'invio della fattura elettronica nel caso in cui corrisponda a giorni non lavorativi
|
||||
- Migliorata l'eliminazione degli utente con un controllo sui logs associati
|
||||
- Rimosso il modulo **Voci di servizio**
|
||||
- Corretta la firma con tavoletta grafica
|
||||
- Migliorata la gestione dei seriali su documenti bloccati
|
||||
- Spostato il panel Dettagli cliente in fase di aggiunta intervento
|
||||
|
||||
### Fixed
|
||||
- Corretto errore notifica di lettura email mancante
|
||||
- Corretto il flag per la fatturazione negli stati attività
|
||||
- Corretta l'importazione delle **Fatture di acquisto** con rivalsa non specificata nelle righe
|
||||
- Corretta la creazione del file config
|
||||
- Corretta la creazione della banca in fase di importazione fatture di acquisto
|
||||
- Corretta la lettura dei valori dai campi personalizzati
|
||||
- Corretto l'avviso di ckeditor
|
||||
- Corretto l'arrotondamento dei movimenti contabili che creavano incongruenze nel piano dei conti
|
||||
- Corretta la generazione delle scadenze
|
||||
- Corretta la valorizzazione del campo RegimeFiscale in generazione XML fattura
|
||||
- Corretta la gestione dell'IVA indetraibile
|
||||
- Corretta l'aggiunta di un conto in **Partitario**
|
||||
- Corretta l'aggiunta attività per utenti senza permessi specifici
|
||||
- Corretta la stampa **Carico automezzi**
|
||||
- Corretta la ricerca nel **Piano dei conti**
|
||||
- Corretta l'impostazione del segmento predefinito per tipo di documento limitandola ai sezionali
|
||||
- Corretto l'avviso del codice anagrafica già presente
|
||||
- Corretta la duplicazione dell'**Attività** dalla scheda attività
|
||||
- Corretto l'allineamento degli orari delle sessioni in line in **Attività**
|
||||
- Corrette le api dell'app
|
||||
- Corretta la gestione dei caratteri accentati sul file di esportazione delle ricevute bancarie
|
||||
- Corretta la ricerca articoli escludendo gli articoli eliminati
|
||||
- Corretta la visualizzazione della password in impostazione
|
||||
- Corretto l'ordinamento dei promemoria in **Dashboard**
|
||||
- Corretta la versione di pdfjs viewer
|
||||
- Corretta la larghezza automatica delle colonne nelle tabelle
|
||||
|
||||
## 2.4.54 (2024-02-02)
|
||||
### Aggiunto (Added)
|
||||
- Aggiunto un controllo sulle impostazioni presenti a gestionale
|
||||
- Aggiunta la possibilità di impostare un tema diverso per ogni gruppo di utenti
|
||||
- Aggiunta la gestione della fatturazione da azione di gruppo raggruppata per sede
|
||||
- Aggiunto il metodo getValue per la lettura dei valori dei campi personalizzati
|
||||
- Aggiunta variabile random per evitare la cache del browser in fase di link pdf o anteprima di stampa
|
||||
- Aggiunta sede di partenza merce in stampa ddt
|
||||
- Aggiunta la gestione del login tramite Microsoft
|
||||
- Aggiunta impostazione per timeout tavoletta grafica
|
||||
|
||||
### Modificato (Changed)
|
||||
- Migliorato il form di login AdminLTE
|
||||
- Migliorato l'esempio di importazione Attività
|
||||
- Migliorata la pianificazione dei promemoria
|
||||
|
||||
|
||||
- Corretta la visualizzazione dei referenti in fase di aggiunta nuova sede
|
||||
- Corretta la stampa di ordini con immagini
|
||||
- Corretta la modifica inline dell'orario della sessione dei tecnici
|
||||
- Corretti i campi richiesta e descrizione in fase di aggiunta attività
|
||||
- Corretta l'aggiunta delle scadenze
|
||||
- Corretta la selezione del fornitore predefinito in articoli
|
||||
- Corrette le API delle checklist per gli impianti
|
||||
- Corrette le api per login da app
|
||||
- Corretta la firma da dispositivo mobile
|
||||
- Corretta la pianificazione degli interventi
|
||||
- Corretto l'avviso di sessioni tecnici senza ore in attività
|
||||
- Corretta l'aggiunta dei seriali
|
||||
- Corretta la gestione de campi personalizzati
|
||||
|
||||
## 2.4.53 (2024-01-05)
|
||||
### Aggiunto (Added)
|
||||
- Aggiunta sezione **dettagli aggiuntivi** nel plugin sedi per compilare i dettagli dell'automezzo (nome, descrizione, targa)
|
||||
- Aggiunta impostazione per definire il **listino cliente** predefinito in fase di aggiunta anagrafica cliente
|
||||
- Aggiunta azione di gruppo in **Anagrafiche** e **Articoli** per impostare il listino cliente massivamente ad Anagrafiche e Articoli
|
||||
- Aggiunto import listini cliente
|
||||
- Aggiunta icona nel campo input prezzo e sconto nelle righe dei documenti per segnalare incongruenza tra prezzo di listino e prezzo inserito
|
||||
- Aggiunta impostazione per scegliere di non importare i seriali in fase di importazione delle fatture elettroniche
|
||||
- Aggiunta colonna email in vista **Anagrafiche**
|
||||
- Aggiunto mod_mime ai requisiti server
|
||||
- Aggiunta la ricerca articolo per barcode in fase di importazione fattura elettronica
|
||||
- Aggiunta impostazione per raggruppare i riferimenti riga in fase di stampa
|
||||
|
||||
### Modificato (Changed)
|
||||
- Migliorata la visualizzazione del plugin movimenti in **Anagrafiche**
|
||||
- Migliorata la stampa **Automezzi** per automezzi senza magazzino registrato
|
||||
- Modificato il valore di decimali per le quantità in stampa di default a 2
|
||||
- Migliorate le ricerche indirizzo in italiano
|
||||
|
||||
### Fixed
|
||||
- Corretto filtro articoli negli **Automezzi** per visualizzare correttamente la giacenza della sede centrale
|
||||
- Corretta selezione automatica iva all'aggiunta degli articoli nei documenti di vendita. Il sistema da priorità all'iva del fornitore se presente, altrimenti passa all'iva dell'articolo se presente, altrimenti assegna l'iva di default definita in impostazioni.
|
||||
- Corretta la vista riferimenti negli **Ordini cliente** aggiungendo il numero esterno del DDT al posto dell'id come veniva erroneamente visualizzato prima
|
||||
- Corretta l'applicazione della rivalsa sulla marca da bollo
|
||||
- Corretto l'automatismo che aggiorna la quantità degli articoli nelle righe quando sono servizi
|
||||
- Corretto il controllo che verifica la presenza della cartella backup/
|
||||
- Corretta l'IVA di acquisto degli articoli
|
||||
- Corretti gli arrotondamenti in fase di importazione fattura elettronica
|
||||
- Corretti i seriali in fase di importazione fattura elettronica
|
||||
- Corretta la ricerca coordinate con google maps
|
||||
|
||||
## 2.4.52 (2023-12-08)
|
||||
### Aggiunto (Added)
|
||||
- Aggiunta la gestione delle sedi definite come automezzi con pratico modulo per il carico/scarico degli articoli nell'automezzo, l'assegnazione di tecnici/autisti con date di validità e stampe di carico filtrabili
|
||||
- Aggiunta una limitazione sulle quantità scaricabili nei documenti di vendita in modo da non poter vendere più articoli di quelli presenti fisicamente nel magazzino selezionato. Questa limitazione è legata all'impostazione **Permetti selezione articoli con quantità minore o uguale a zero in Documenti di Vendita**
|
||||
- Aggiunti costi e margine negli ordini cliente
|
||||
- Aggiunta la possibilità di importare tramite CSV Impianti e Attività
|
||||
- Aggiunte le sottocategorie in Impianti
|
||||
- Aggiunti i DDT alla lista dei documenti collegati nel modulo Preventivi
|
||||
- Aggiunto il calcolo della provvigione in pianificazione fatturazione
|
||||
- Aggiunta una seconda ricerca delle coordinate anagrafica da azione di gruppo con Google Maps
|
||||
- Aggiunta la gestione dei seriali da riferimento documento in fase di importazione di una fattura elettronica
|
||||
- Aggiunta la gestione dei seriali nei contratti
|
||||
- Aggiunta la stampa preventivo (solo totale imponibile)
|
||||
- Aggiunta la selezione delle sottocategorie in fase di aggiunta impianto
|
||||
- Aggiunta la creazione al volo dei referenti in attività
|
||||
- Aggiunto colore in base allo stato in modifica stato da azioni di gruppo in Preventivi, Contratti e Ordini
|
||||
- Aggiunta la gestione del rappresentante fiscale negli XML
|
||||
- Aggiunte le impostazioni per definire il numero di decimali per gli importi, per le quantità e per i totali nelle stampe
|
||||
- Aggiunta la variabile Nome preventivo nei Preventivi
|
||||
- Aggiunto il tipo di pagamento e banca di accredito e addebito nelle scadenze
|
||||
|
||||
### Modificato (Changed)
|
||||
- Migliorata l'importazione degli articoli tramite CSV, le anagrafiche relative a clienti e fornitori vengono ora create se non presenti a gestionale
|
||||
- Migliorato il controllo sulle chiavi esterne nel controllo del database
|
||||
- Ripristinata la funzionalità di duplicazione degli ordini
|
||||
- La modifica della data competenza di una fattura aggiorna ora la data del movimento relativo
|
||||
- Migliorato il caricamento della lista allegati
|
||||
- L'aggiunta di note aggiuntive e la modifica della data competenza è ora sempre possibile nelle fatture
|
||||
- Spostati tutti gli avvisi in basso a destra
|
||||
- Modificate le funzioni nei file modutil.php per permettere l'aggiunta di file custom
|
||||
|
||||
### Fixed
|
||||
- Corretto il problema di visualizzazione dei PDF negli allegati
|
||||
- Corretto un problema di movimentazione magazzino: gli articoli nelle attività venivano sempre movimentati da sede legale anche se specificata diversa sede di partenza nel documento (solo da popup di modifica articolo)
|
||||
- Corretta la selezione degli impianti in pianificazione ciclica delle attività
|
||||
- Corretta la rimozione del referente nelle sedi
|
||||
- Corretta la visualizzazione del modulo fatture di vendita per schermi a bassa risoluzione
|
||||
- Corretti i calcoli della ritenuta e rivalsa in fattura
|
||||
- Corretta l'importazione delle anagrafiche da CSV
|
||||
- Corretta l'importazione di fatture elettroniche con aliquote IVA multiple
|
||||
- Corretta la stampa del consuntivo ordine, della scadenza e del consuntivo
|
||||
- Corretta la validazione di password contenenti il carattere '&'
|
||||
- Corretto il calcolo del totale nei consuntivi
|
||||
- Corretta l'applicazione della marca da bollo in fattura
|
||||
- Corretta la visualizzazione della quantità articoli in fase di selezione
|
||||
- Corretta la visualizzazione delle righe nei documenti in presenza di articoli con quantità 0
|
||||
- Corretta la movimentazione degli articoli
|
||||
- Corretta la creazione del conto del piano dei conti per le anagrafiche
|
||||
- Corretto il funzionamento dei campi personalizzati
|
||||
- Corretta la vista Fatture di vendita per l'icona email
|
||||
- Corretta la crezione di attività da documenti, viene ora mantenuto il collegamento
|
||||
|
||||
## 2.4.51 (2023-10-30)
|
||||
### Aggiunto (Added)
|
||||
- Aggiunta la gestione checklist nel plugin impianti
|
||||
- Aggiunto il modulo **Gestione task**
|
||||
- Aggiunte Note interne per anagrafiche
|
||||
- Aggiunta la variabile email nei template delle anagrafiche
|
||||
- Aggiunta impostazioni **Crea contratto rinnovabile di default** e **Giorni di preavviso di default**
|
||||
- Aggiunta colonna Allegati in Attività
|
||||
- Aggiunta la gestione di verifica dei movimenti contabili
|
||||
- Aggiunta gestione apertura mappe con applicazione dispositivo mobile
|
||||
- Aggiunto il modulo **Stati fatture**
|
||||
- Aggiunto il controllo di integrità del database su relazioni chiavi esterne
|
||||
- Aggiunta gestione filtro =data su tabelle
|
||||
|
||||
### Modificato (Changed)
|
||||
- Miglioria pulsanti mappa
|
||||
- Rinominato il widget Notifiche interne in Note interne
|
||||
|
||||
### Fixed
|
||||
- Corretta la stampa liquidazione iva per aliquote con natura iva non specificata
|
||||
- Corretta la selezione delle sedi azienda
|
||||
- Corretto il footer delle fatture
|
||||
- Corretta la generazione di autofatture per righe con natura iva N2 e N6
|
||||
- Corretta la query Invio sollecito di pagamento da azioni di gruppo per escludere le note di credito
|
||||
- Corretto l'invio scadenze per anagrafica da azioni di gruppo
|
||||
- Corretti i tooltip in dashboard
|
||||
|
||||
|
||||
## 2.4.50 (2023-10-06)
|
||||
### Aggiunto (Added)
|
||||
- Aggiunta funzionalità Aggiorna prezzi in row-list dei documenti
|
||||
- Aggiunta mappa nei moduli DDT
|
||||
- Aggiunta colore nei record in base allo stato del documento
|
||||
- Aggiunta colonna Sezionale in Tipi documento
|
||||
- Aggiunta gestione fatture con più ritenute
|
||||
- Aggiunti i preventivi in attesa di conferma in Informazioni Aggiuntive
|
||||
- Aggiunta l'importazione dei seriali da fatture di acquisto
|
||||
- Aggiunta creazione del tipo di anagrafica se mancante in import anagrafiche
|
||||
- Aggiunta gestione inline dei campi Costo e Prezzo unitario nei documenti
|
||||
- Aggiunto il login amministratore da app
|
||||
- Aggiunta l'esportazione xml delle scadenze di bonifici per la banca
|
||||
### Modificato (Changed)
|
||||
- Aggiornato il modello Asso Invoice
|
||||
- Eliminata la cartella tests
|
||||
- Disabilitato il tasto Elimina documento nel caso siano selezionate delle righe
|
||||
### Fixed
|
||||
- Corretto il campo RiferimentoAmministrazione in generazione XML
|
||||
- Corretta la visualizzazione della dicitura fissa in fattura
|
||||
- Corretta la visualizzazione della tabella del modulo Listini cliente
|
||||
- Corretta l'importazione delle anagrafiche con chiave primaria rientrante in campi_sede
|
||||
- Corretto il template sollecito di pagamento raggruppato per anagrafica
|
||||
- Corretta la visualizzazione del tasto sms
|
||||
- Corretta la generazione dell'autofattura in presenza di articoli
|
||||
- Corretto il campo RiferimentoNumeroLinea in fase di generazione XML
|
||||
- Corretta la duplicazione delle fatture
|
||||
- Corretta la query dei documenti collegati
|
||||
## 2.4.49 (2023-09-25)
|
||||
### Aggiunto (Added)
|
||||
- Aggiunto avviso in caso di impossibilità di caricare la mappa
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
In questo file verranno riassunte le problematiche del gestionale che sono già note alla community.
|
||||
Le problematiche saranno raggruppate per release e le relative correzioni (se applicabili) saranno riportate sotto la sezione **Soluzione**.
|
||||
|
||||
#### 2.4.54 - 03/02/2024
|
||||
|
||||
##### Problemi noti
|
||||
- In fase di installazione non viene compilato il file config se assente
|
||||
|
||||
##### Soluzione
|
||||
Modificare il file index.php sostituendo il blocco di codice che inizia alla riga 30 con
|
||||
|
||||
```php
|
||||
if ($dbo->isConnected()) {
|
||||
try {
|
||||
$microsoft = $dbo->selectOne('zz_oauth2', '*', ['nome' => 'Microsoft', 'enabled' => 1, 'is_login' => 1]);
|
||||
} catch (QueryException $e) {
|
||||
}
|
||||
}
|
||||
```
|
||||
oppure aggiornare alla **v.2.5** di OpenSTAManager.
|
||||
|
||||
#### 2.4.35 - 12/08/2022
|
||||
|
||||
##### Problemi noti
|
||||
- Colonna **id_module_start** mancante per tabella **zz_groups**
|
||||
- Icona non aggiornata per il modulo **Causali movimenti**
|
||||
|
||||
##### Soluzione
|
||||
Eseguire a database le seguenti query di allineamento:
|
||||
```bash
|
||||
UPDATE `zz_modules` SET `icon` = 'fa fa-exchange' WHERE `title` = 'Causali movimenti';
|
||||
ALTER TABLE `zz_groups` ADD `id_module_start` INT NULL AFTER `editable`;
|
||||
```
|
||||
|
||||
oppure aggiornare alla **v.2.5** di OpenSTAManager.
|
37
README.md
37
README.md
|
@ -21,7 +21,6 @@
|
|||
[![Downloads](https://img.shields.io/github/downloads/devcode-it/openstamanager/total.svg)](https://github.com/devcode-it/openstamanager/releases)
|
||||
[![SourceForge](https://img.shields.io/sourceforge/dt/openstamanager.svg?label=SourceForge)](https://sourceforge.net/projects/openstamanager/)
|
||||
[![license](https://img.shields.io/github/license/devcode-it/openstamanager.svg)](https://github.com/devcode-it/openstamanager/blob/master/LICENSE)
|
||||
[![huntr](https://cdn.huntr.dev/huntr_security_badge_mono.svg)](https://huntr.dev)
|
||||
|
||||
Il gestionale OpenSTAManager è un software open-source e web based, sviluppato dall'azienda informatica [DevCode](https://www.devcode.it/) di Este per gestire ed archiviare il servizio di assistenza tecnica e la relativa fatturazione.
|
||||
Il nome del progetto deriva dalla parziale traduzione in inglese degli elementi principali che lo compongono: la natura open-source e il suo obiettivo quale Gestore del Servizio Tecnico di Assistenza.
|
||||
|
@ -53,7 +52,7 @@ La documentazione ufficiale è disponibile all'indirizzo <https://docs.openstama
|
|||
|
||||
<!-- /TOC -->
|
||||
|
||||
## Requisiti
|
||||
## Requisiti software
|
||||
|
||||
L'installazione del gestionale richiede la presenza di un server web con abilitato il [DBMS MySQL](https://www.mysql.com) e il linguaggio di programmazione [PHP](https://php.net).
|
||||
|
||||
|
@ -63,18 +62,22 @@ L'installazione del gestionale richiede la presenza di un server web con abilita
|
|||
|
||||
| PHP | EOL | Supportato |
|
||||
|-----|-----|:----------:|
|
||||
| 8.1 | 25/11/2024 | ❌ |
|
||||
| 8.0 | 26/11/2023 | ✔️ |
|
||||
| 7.4 | 28/11/2022 | ✔️ |
|
||||
| 7.3 | 06/12/2021 | ✔️ |
|
||||
| 7.2 | 30/11/2020 | ❌ |
|
||||
| 8.3 | 23/11/2026 | ✔️ |
|
||||
| 8.2 | 08/12/2025 | ✔️ |
|
||||
| 8.1 | 25/11/2024 | ✔️ |
|
||||
| 8.0 | 26/11/2023 | ❌ |
|
||||
| 7.4 | 28/11/2022 | ❌ |
|
||||
| 7.3 | 06/12/2021 | ❌ |
|
||||
|
||||
</td>
|
||||
<td valign="top">
|
||||
|
||||
| MYSQL | EOL | Supportato |
|
||||
|-----|-----|:----------:|
|
||||
| 8.0 | 01/04/2026 | ✔️ |
|
||||
| 8.3 | 30/04/2024 | ✔️ |
|
||||
| 8.2 | 31/01/2024 | ✔️ |
|
||||
| 8.1 | 25/10/2023 | ✔️ |
|
||||
| 8.0 | 30/04/2026 | ✔️ |
|
||||
| 5.7 | 21/10/2023 | ✔️ |
|
||||
| 5.6 | 05/02/2021 | ❌ |
|
||||
|
||||
|
@ -83,7 +86,21 @@ L'installazione del gestionale richiede la presenza di un server web con abilita
|
|||
</tr>
|
||||
</table>
|
||||
|
||||
Per ulteriori informazioni sui pacchetti che forniscono questi elementi di default, visitare la sezione [Installazione](https://docs.openstamanager.com/configurazione/installazione) della documentazione.
|
||||
❗Alcune dipendenze presenti dalla versione 2.5 non sono più compatibili con PHP 7.4 e PHP 8.0, dalla versione 2.5.3 sarà quindi richiesta una versione di php >= 8.1.
|
||||
|
||||
Per ulteriori informazioni, visitare la sezione [Installazione](https://docs.openstamanager.com/configurazione/installazione) della documentazione.
|
||||
|
||||
### Requisiti hardware
|
||||
|
||||
Minimi:
|
||||
- 1 CPU
|
||||
- 2GB di ram
|
||||
- 200MB di spazio per il gestionale
|
||||
|
||||
Consigliati:
|
||||
- 2 CPU
|
||||
- 4GB di ram
|
||||
- 2GB di spazio per il gestionale
|
||||
|
||||
## Installazione rapida
|
||||
```bash
|
||||
|
@ -158,7 +175,7 @@ In questo modo è possibile ottenere un'ulteriore garanzia sul funzionamento del
|
|||
|
||||
La community è una componente importante in un progetto open-source, perché mette in contatto utenti e programmatori tra di loro e permette pertanto l'individuazione di soluzioni innovative e migliori.
|
||||
|
||||
Siamo presenti su [Facebook](https://www.facebook.com/openstamanager), [Twitter](https://twitter.com/openstamanager/), [YouTube](https://www.youtube.com/channel/UCoToaK4dhDXmcQXi1AnqQ4Q) e [Mastodon](https://mastodon.uno/@openstamanager) e il nostro forum ufficiale è disponibile all'indirizzo <https://forum.openstamanager.com>, dove potete segnalare i vostri problemi e soddisfare le vostre curiosità nelle sezioni più adeguate.
|
||||
Siamo presenti su [Facebook](https://www.facebook.com/openstamanager), [Instagram](https://www.instagram.com/openstamanager/), [Twitter](https://twitter.com/openstamanager/), [YouTube](https://www.youtube.com/@openstamanager2900), [Telegram](https://t.me/openstamanager_official) e [Mastodon](https://mastodon.uno/@openstamanager) e il nostro forum ufficiale è disponibile all'indirizzo <https://forum.openstamanager.com>, dove potete segnalare i vostri problemi e soddisfare le vostre curiosità nelle sezioni più adeguate.
|
||||
|
||||
## Contribuire
|
||||
|
||||
|
|
66
actions.php
66
actions.php
|
@ -19,6 +19,7 @@
|
|||
|
||||
include_once __DIR__.'/core.php';
|
||||
|
||||
use Models\Module;
|
||||
use Models\Note;
|
||||
use Models\OperationLog;
|
||||
use Models\Upload;
|
||||
|
@ -41,20 +42,13 @@ if (filter('op') == 'aggiungi-allegato' || filter('op') == 'rimuovi-allegato') {
|
|||
// Controllo sui permessi di scrittura per il modulo
|
||||
if (Modules::getPermission($id_module) != 'rw') {
|
||||
flash()->error(tr('Non hai permessi di scrittura per il modulo _MODULE_', [
|
||||
'_MODULE_' => '"'.Modules::get($id_module)['name'].'"',
|
||||
]));
|
||||
}
|
||||
|
||||
// Controllo sui permessi di scrittura per il file system
|
||||
elseif (!directory($upload_dir)) {
|
||||
flash()->error(tr('Non hai i permessi di scrittura nella cartella _DIR_!', [
|
||||
'_DIR_' => '"files"',
|
||||
'_MODULE_' => '"'.Module::find($id_module)->getTranslation('title').'"',
|
||||
]));
|
||||
}
|
||||
|
||||
// Gestione delle operazioni
|
||||
else {
|
||||
//UPLOAD PER CKEDITOR
|
||||
// UPLOAD PER CKEDITOR
|
||||
if (filter('op') == 'aggiungi-allegato' && !empty($_FILES) && !empty($_FILES['upload']['name'])) {
|
||||
$CKEditor = get('CKEditor');
|
||||
$funcNum = get('CKEditorFuncNum');
|
||||
|
@ -63,8 +57,8 @@ if (filter('op') == 'aggiungi-allegato' || filter('op') == 'rimuovi-allegato') {
|
|||
'png', 'jpg', 'jpeg',
|
||||
];
|
||||
|
||||
//Maximum file limit (unit: byte)
|
||||
$max_size = '2097152'; //2MB
|
||||
// Maximum file limit (unit: byte)
|
||||
$max_size = '2097152'; // 2MB
|
||||
|
||||
// Get image file extension
|
||||
$file_extension = pathinfo($_FILES['upload']['name'], PATHINFO_EXTENSION);
|
||||
|
@ -73,7 +67,7 @@ if (filter('op') == 'aggiungi-allegato' || filter('op') == 'rimuovi-allegato') {
|
|||
$upload = Uploads::upload($_FILES['upload'], [
|
||||
'name' => filter('nome_allegato'),
|
||||
'category' => filter('categoria'),
|
||||
'id_module' => Modules::get('Gestione documentale')['id'],
|
||||
'id_module' => Module::where('name', 'Gestione documentale')->first()->id,
|
||||
'id_record' => $id_record,
|
||||
]);
|
||||
|
||||
|
@ -86,7 +80,7 @@ if (filter('op') == 'aggiungi-allegato' || filter('op') == 'rimuovi-allegato') {
|
|||
|
||||
// Creazione file fisico
|
||||
if (!empty($upload)) {
|
||||
//flash()->info(tr('File caricato correttamente!'));
|
||||
// flash()->info(tr('File caricato correttamente!'));
|
||||
|
||||
$id_allegato = $dbo->lastInsertedID();
|
||||
$upload = Upload::find($id_allegato);
|
||||
|
@ -113,15 +107,15 @@ if (filter('op') == 'aggiungi-allegato' || filter('op') == 'rimuovi-allegato') {
|
|||
echo json_encode($response);
|
||||
}
|
||||
} else {
|
||||
//flash()->error(tr('Errore durante il caricamento del file!'));
|
||||
// flash()->error(tr('Errore durante il caricamento del file!'));
|
||||
echo '<script type="text/javascript"> window.parent.toastr.error("'.tr('Errore durante il caricamento del file!').'"); </script>';
|
||||
}
|
||||
} else {
|
||||
//flash()->error(tr('Estensione non permessa!'));
|
||||
// flash()->error(tr('Estensione non permessa!'));
|
||||
echo '<script type="text/javascript"> window.parent.toastr.error("'.tr('Estensione non permessa').'"); </script>';
|
||||
}
|
||||
|
||||
exit();
|
||||
exit;
|
||||
}
|
||||
|
||||
// UPLOAD
|
||||
|
@ -167,7 +161,17 @@ if (filter('op') == 'aggiungi-allegato' || filter('op') == 'rimuovi-allegato') {
|
|||
elseif (filter('op') == 'download-allegato') {
|
||||
$rs = $dbo->fetchArray('SELECT * FROM zz_files WHERE id_module='.prepare($id_module).' AND id='.prepare(filter('id')).' AND filename='.prepare(filter('filename')));
|
||||
|
||||
download($upload_dir.'/'.$rs[0]['filename'], $rs[0]['original']);
|
||||
// download($upload_dir.'/'.$rs[0]['filename'], $rs[0]['original']);
|
||||
$file = Upload::find($rs[0]['id']);
|
||||
|
||||
if (!empty($file)) {
|
||||
$content = $file->get_contents();
|
||||
|
||||
header('Content-Type: application/octet-stream');
|
||||
header('Content-Transfer-Encoding: Binary');
|
||||
header('Content-disposition: attachment; filename="'.basename($file->original_name).'"');
|
||||
echo $content;
|
||||
}
|
||||
} elseif (filter('op') == 'visualizza-modifica-allegato') {
|
||||
include_once base_dir().'/include/modifica_allegato.php';
|
||||
}
|
||||
|
@ -193,10 +197,10 @@ elseif (filter('op') == 'download-zip-allegati') {
|
|||
$src = basename($allegato->filepath);
|
||||
$dst = basename($allegato->original_name);
|
||||
|
||||
$file = slashes($module->upload_directory.'/'.$src);
|
||||
$dest = slashes($dir.'tmp/'.$dst);
|
||||
$file_content = $allegato->get_contents();
|
||||
|
||||
$result = copy($file, $dest);
|
||||
$dest = slashes($dir.'tmp/'.$dst);
|
||||
file_put_contents($dest, $file_content);
|
||||
}
|
||||
|
||||
// Creazione zip
|
||||
|
@ -359,7 +363,7 @@ elseif (filter('op') == 'ordina-checks') {
|
|||
elseif (post('op') == 'send-email') {
|
||||
$template = Template::find(post('template'));
|
||||
|
||||
$mail = \Modules\Emails\Mail::build($user, $template, $id_record);
|
||||
$mail = Modules\Emails\Mail::build($user, $template, $id_record);
|
||||
|
||||
// Rimozione allegati predefiniti
|
||||
$mail->resetPrints();
|
||||
|
@ -410,12 +414,12 @@ elseif (post('op') == 'send-email') {
|
|||
$visible = filter('visible');
|
||||
$id_riga = filter('id_vista');
|
||||
|
||||
$dbo->query('UPDATE `zz_views` SET `visible` = '.prepare($visible).' WHERE id = '.prepare($id_riga));
|
||||
$dbo->query('UPDATE `zz_views` SET `visible` = '.prepare($visible).' WHERE `id` = '.prepare($id_riga));
|
||||
} elseif (filter('op') == 'ordina_colonne') {
|
||||
$order = explode(',', post('order', true));
|
||||
|
||||
foreach ($order as $i => $id_riga) {
|
||||
$dbo->query('UPDATE `zz_views` SET `order` = '.prepare($i).' WHERE id='.prepare($id_riga));
|
||||
$dbo->query('UPDATE `zz_views` SET `order` = '.prepare($i).' WHERE `id`='.prepare($id_riga));
|
||||
}
|
||||
} elseif (filter('op') == 'visualizza_righe_riferimenti') {
|
||||
include_once base_dir().'/include/riferimenti/riferimenti.php';
|
||||
|
@ -485,22 +489,27 @@ if ($structure->permission == 'rw') {
|
|||
($include_file = $structure->filepath('actions.php')) ? include $include_file : null;
|
||||
|
||||
// Operazioni generiche per i campi personalizzati
|
||||
if (post('op') != null) {
|
||||
if (!empty(post('op'))) {
|
||||
$custom_where = !empty($id_plugin) ? '`id_plugin` = '.prepare($id_plugin) : '`id_module` = '.prepare($id_module);
|
||||
|
||||
$query = 'SELECT `id`, `html_name` AS `name` FROM `zz_fields` WHERE '.$custom_where;
|
||||
$query = 'SELECT `id`, `html_name` AS `title` FROM `zz_fields` WHERE '.$custom_where;
|
||||
$customs = $dbo->fetchArray($query);
|
||||
|
||||
if (!string_starts_with(post('op'), 'delete')) {
|
||||
if (post('op') != 'delete') {
|
||||
$values = [];
|
||||
foreach ($customs as $custom) {
|
||||
if (post($custom['name']) !== null) {
|
||||
$values[$custom['id']] = post($custom['name']);
|
||||
} else {
|
||||
$values[$custom['id']] = '';
|
||||
}
|
||||
}
|
||||
|
||||
// Lista casi in cui creare i campi personalizzati
|
||||
$list = ['add', 'add_documento', 'add_preventivo', 'add_ordine_fornitore'];
|
||||
|
||||
// Inserimento iniziale
|
||||
if (string_starts_with(post('op'), 'add')) {
|
||||
if (in_array(post('op'), $list)) {
|
||||
// Informazioni di log
|
||||
Filter::set('get', 'id_record', $id_record);
|
||||
|
||||
|
@ -514,12 +523,13 @@ if ($structure->permission == 'rw') {
|
|||
}
|
||||
|
||||
// Aggiornamento
|
||||
elseif (string_starts_with(post('op'), 'update')) {
|
||||
if (post('op') == 'update') {
|
||||
$query = 'SELECT `zz_field_record`.`id_field` FROM `zz_field_record` JOIN `zz_fields` ON `zz_fields`.`id` = `zz_field_record`.`id_field` WHERE id_record = '.prepare($id_record).' AND '.$custom_where;
|
||||
$customs_present = $dbo->fetchArray($query);
|
||||
$customs_present = array_column($customs_present, 'id_field');
|
||||
|
||||
foreach ($values as $key => $value) {
|
||||
$value = (!is_array($value) ? $value : json_encode($value));
|
||||
if (in_array($key, $customs_present)) {
|
||||
$dbo->update('zz_field_record', [
|
||||
'value' => $value,
|
||||
|
|
14
add.php
14
add.php
|
@ -40,20 +40,20 @@ echo '
|
|||
// Campi personalizzati
|
||||
echo '
|
||||
|
||||
<div class="hide" id="custom_fields_top-add">
|
||||
<div class="hide" id="custom_fields_top-add_'.$id_module.'-'.$id_plugin.'">
|
||||
<input type="hidden" name="id_module" value="'.$id_module.'">
|
||||
<input type="hidden" name="id_plugin" value="'.$id_plugin.'">
|
||||
|
||||
{( "name": "custom_fields", "id_module": "'.$id_module.'", "id_plugin": "'.$id_plugin.'", "position": "top", "place": "add" )}
|
||||
</div>
|
||||
|
||||
<div class="hide" id="custom_fields_bottom-add">
|
||||
<div class="hide" id="custom_fields_bottom-add_'.$id_module.'-'.$id_plugin.'">
|
||||
{( "name": "custom_fields", "id_module": "'.$id_module.'", "id_plugin": "'.$id_plugin.'", "position": "bottom", "place": "add" )}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
let form = $("#custom_fields_top-add").parent().find("form").first();
|
||||
let form = $("#custom_fields_top-add_'.$id_module.'-'.$id_plugin.'").parent().find("form").first();
|
||||
|
||||
// Ultima sezione/campo del form
|
||||
let last = form.find(".panel").last();
|
||||
|
@ -62,15 +62,19 @@ $(document).ready(function(){
|
|||
last = form.find(".box").last();
|
||||
}
|
||||
|
||||
if (!last.length) {
|
||||
last = form.find(".card").last();
|
||||
}
|
||||
|
||||
if (!last.length) {
|
||||
last = form.find(".row").eq(-2);
|
||||
}
|
||||
|
||||
// Campi a inizio form
|
||||
aggiungiContenuto(form, "#custom_fields_top-add", {}, true);
|
||||
aggiungiContenuto(form, "#custom_fields_top-add_'.$id_module.'-'.$id_plugin.'", {}, true);
|
||||
|
||||
// Campi a fine form
|
||||
aggiungiContenuto(last, "#custom_fields_bottom-add", {});
|
||||
aggiungiContenuto(last, "#custom_fields_bottom-add_'.$id_module.'-'.$id_plugin.'", {});
|
||||
});
|
||||
</script>';
|
||||
|
||||
|
|
16
ajax.php
16
ajax.php
|
@ -78,12 +78,12 @@ switch (filter('op')) {
|
|||
|
||||
case 'active_users':
|
||||
$posizione = get('id_module');
|
||||
if (isset($id_record)) {
|
||||
if (!empty($id_record)) {
|
||||
$posizione .= ', '.get('id_record');
|
||||
}
|
||||
|
||||
$user = Auth::user();
|
||||
$interval = setting('Timeout notifica di presenza (minuti)') * 60 * 2;
|
||||
$interval = setting('Timeout notifica di presenza (minuti)') * 60;
|
||||
|
||||
$dbo->query('UPDATE zz_semaphores SET updated = NOW() WHERE id_utente = :user_id AND posizione = :position', [
|
||||
':user_id' => $user['id'],
|
||||
|
@ -112,7 +112,7 @@ switch (filter('op')) {
|
|||
if ($hook->permission != '-') {
|
||||
$results[] = [
|
||||
'id' => $hook->id,
|
||||
'name' => $hook->name,
|
||||
'name' => $hook->getTranslation('title'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -167,5 +167,15 @@ switch (filter('op')) {
|
|||
|
||||
echo json_encode($results);
|
||||
|
||||
break;
|
||||
|
||||
case 'avg-results':
|
||||
$ids = post('ids') ?: [];
|
||||
$results = Util\Query::getAverages($structure, [
|
||||
'id' => $ids,
|
||||
]);
|
||||
|
||||
echo json_encode($results);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ if (!empty(filter('order'))) {
|
|||
}
|
||||
array_shift($columns);
|
||||
|
||||
$total = Util\Query::readQuery($structure);
|
||||
$total = Query::readQuery($structure);
|
||||
|
||||
// Ricerca
|
||||
$search = [];
|
||||
|
@ -52,6 +52,7 @@ $results = [
|
|||
'recordsTotal' => 0,
|
||||
'recordsFiltered' => 0,
|
||||
'summable' => [],
|
||||
'avg' => [],
|
||||
'draw' => $draw_numer,
|
||||
];
|
||||
|
||||
|
@ -74,7 +75,10 @@ if (!empty($query)) {
|
|||
$results['recordsFiltered'] = $data['count'];
|
||||
|
||||
// SOMME
|
||||
$results['summable'] = Util\Query::getSums($structure, $search);
|
||||
$results['summable'] = Query::getSums($structure, $search);
|
||||
|
||||
// MEDIE
|
||||
$results['avg'] = Query::getAverages($structure, $search);
|
||||
|
||||
// Allineamento delle righe
|
||||
$align = [];
|
||||
|
@ -113,8 +117,12 @@ if (!empty($query)) {
|
|||
$column = [];
|
||||
|
||||
if (!empty($r['_bg_'])) {
|
||||
if (preg_match('/-light$/', $r['_bg_'])) {
|
||||
$column['data-background'] = substr($r['_bg_'], 0, -6); // Remove the "-light" suffix from the word
|
||||
} else {
|
||||
$column['data-background'] = $r['_bg_'];
|
||||
}
|
||||
}
|
||||
|
||||
// Allineamento
|
||||
if (!empty($align[$field])) {
|
||||
|
@ -160,7 +168,7 @@ if (!empty($query)) {
|
|||
|
||||
// Icona
|
||||
elseif (preg_match('/^icon_(.+?)$/', trim($field), $m)) {
|
||||
$value = '<span class=\'label text-black\' style=\'font-weight:normal;\' ><i class="'.$r[$field].'" title="'.$r['icon_title_'.$m[1]].'" ></i> <span>'.$r['icon_title_'.$m[1]].'</span></span>';
|
||||
$value = '<span class=\'badge text-black\' style=\'font-weight:normal;\' ><i class="'.$r[$field].'" title="'.$r['icon_title_'.$m[1]].'" ></i> <span>'.$r['icon_title_'.$m[1]].'</span></span>';
|
||||
}
|
||||
|
||||
// Colore del testo
|
||||
|
|
|
@ -43,7 +43,7 @@ try {
|
|||
} catch (Exception $e) {
|
||||
// Log dell'errore
|
||||
$logger = logger();
|
||||
$logger->addRecord(\Monolog\Logger::ERROR, $e);
|
||||
$logger->addRecord(Monolog\Logger::ERROR, $e);
|
||||
|
||||
$response = Response::error('serverError');
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
|
|||
$response = Response::error('ok');
|
||||
}
|
||||
|
||||
json_decode($response);
|
||||
json_decode((string) $response);
|
||||
|
||||
// Impostazioni di Content-Type e Charset Header
|
||||
if (json_last_error() == JSON_ERROR_NONE) {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
After Width: | Height: | Size: 8.6 KiB |
|
@ -18,12 +18,7 @@
|
|||
|
||||
// Aggiunta dell'ingranaggio all'unload della pagina
|
||||
$(window).on("beforeunload", function () {
|
||||
$("#main_loading").show();
|
||||
});
|
||||
|
||||
// Rimozione dell'ingranaggio al caricamento completo della pagina
|
||||
$(window).on("load", function () {
|
||||
$("#main_loading").fadeOut();
|
||||
$("#main_loading").css('height', '100vh').find('img').show().removeClass('animation__shake').addClass('animation__shake');
|
||||
});
|
||||
|
||||
// Fix multi-modal
|
||||
|
@ -39,7 +34,7 @@ $(document).ready(function () {
|
|||
"debug": false,
|
||||
"newestOnTop": false,
|
||||
"progressBar": true,
|
||||
"positionClass": "toast-top-right",
|
||||
"positionClass": "toast-bottom-right",
|
||||
//"preventDuplicates": true,
|
||||
"onclick": null,
|
||||
"showDuration": "300",
|
||||
|
@ -117,6 +112,14 @@ $(document).on('select2:open', () => {
|
|||
|
||||
//Send a WhatsApp message using JavaScript
|
||||
function sendWhatsAppMessage(phoneNumber, message) {
|
||||
// Rimuove eventuali spazi bianchi dal numero di telefono
|
||||
phoneNumber = phoneNumber.replace(/\s/g, '');
|
||||
|
||||
// Rimuove il simbolo "+" all'inizio del numero, se presente
|
||||
if (phoneNumber.startsWith('+')) {
|
||||
phoneNumber = phoneNumber.slice(1);
|
||||
}
|
||||
|
||||
var text = message ? "&text=" + encodeURIComponent(message) : "";
|
||||
var url = "https://api.whatsapp.com/send?phone=" + phoneNumber + text;
|
||||
window.open(url);
|
||||
|
|
|
@ -35,7 +35,8 @@ $(document).ready(function () {
|
|||
});
|
||||
|
||||
// Nel caso la navigazione sia da mobile, disabilito il ritorno al punto precedente
|
||||
if (!globals.is_mobile) {
|
||||
// 2024-01-30 disabilito controllo in quanto non è chiaro il proposito
|
||||
//if (!globals.is_mobile) {
|
||||
// Salvo lo scroll per riportare qui l'utente al reload
|
||||
$(window).on('scroll', function () {
|
||||
if (sessionStorage != undefined) {
|
||||
|
@ -49,7 +50,7 @@ $(document).ready(function () {
|
|||
scrollToOffset(sessionStorage['scrollTop_' + globals.id_module + '_' + globals.id_record]);
|
||||
}, 1);
|
||||
}
|
||||
}
|
||||
//}
|
||||
|
||||
$('.nav-tabs a').click(function (e) {
|
||||
$(this).tab('show');
|
||||
|
@ -61,7 +62,7 @@ $(document).ready(function () {
|
|||
});
|
||||
|
||||
// Fix per la visualizzazione di Datatables all'interno dei tab Bootstrap
|
||||
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
|
||||
$('a[data-widget="tab"]').on('shown.bs.tab', function (e) {
|
||||
$($.fn.dataTable.tables(true)).DataTable().columns.adjust();
|
||||
$($.fn.dataTable.tables(true)).DataTable().scroller.measure();
|
||||
});
|
||||
|
|
|
@ -17,31 +17,9 @@
|
|||
*/
|
||||
|
||||
$(document).ready(function () {
|
||||
// Fix per il menu principale
|
||||
$('.sidebar-menu').tree({
|
||||
followLink: true,
|
||||
});
|
||||
|
||||
$('.sidebar-menu > li.treeview i.fa-angle-left').click(function (e) {
|
||||
e.preventDefault();
|
||||
$(this).find('ul').stop().slideDown();
|
||||
});
|
||||
|
||||
$('.sidebar-menu > li.treeview i.fa-angle-down').click(function (e) {
|
||||
e.preventDefault();
|
||||
$(this).find('ul').stop().slideUp();
|
||||
});
|
||||
|
||||
const elenco_menu = $('.treeview-menu > li.active');
|
||||
for (i = 0; i < elenco_menu.length; i++) {
|
||||
const elemento = $(elenco_menu[i]);
|
||||
elemento.parent().show().parent().addClass('active');
|
||||
elemento.parent().parent().find('i.fa-angle-left').removeClass('fa-angle-left').addClass('fa-angle-down');
|
||||
}
|
||||
|
||||
// Menu ordinabile
|
||||
if (!globals.is_mobile) {
|
||||
const menu = sortable(".sidebar-menu", {
|
||||
const menu = sortable(".nav-sidebar", {
|
||||
axis: "y",
|
||||
cursor: "move",
|
||||
dropOnEmpty: true,
|
||||
|
@ -50,7 +28,7 @@ $(document).ready(function () {
|
|||
|
||||
if (menu) {
|
||||
menu.addEventListener("sortupdate", function (e) {
|
||||
let order = $(".sidebar-menu > .treeview[data-id]").toArray().map(a => $(a).data("id"))
|
||||
let order = $(".nav-sidebar > .nav-item[data-id]").toArray().map(a => $(a).data("id"))
|
||||
|
||||
$.post(globals.rootdir + "/actions.php", {
|
||||
id_module: globals.order_manager_id,
|
||||
|
@ -80,7 +58,7 @@ $(document).ready(function () {
|
|||
|
||||
// Gestione click sul pulsante per il toggle
|
||||
pluginToggle.on("click", function () {
|
||||
$("aside.content-wrapper, .main-footer").toggleClass("with-control-sidebar");
|
||||
$("aside.content-sidebar, section.content, .main-footer").toggleClass("with-control-sidebar");
|
||||
|
||||
toggleControlSidebar();
|
||||
});
|
||||
|
@ -101,6 +79,18 @@ $(document).ready(function () {
|
|||
if (largeScreen && !globals.collapse_plugin_sidebar) {
|
||||
pluginToggle.click();
|
||||
}
|
||||
|
||||
$('.control-sidebar-button').on("click", function(){
|
||||
toggleControlSidebar();
|
||||
});
|
||||
|
||||
$('.control-sidebar .nav-item > a').on("click", function(){
|
||||
toggleControlSidebar();
|
||||
});
|
||||
|
||||
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
|
||||
window.dispatchEvent(new Event('resize'));
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -110,13 +100,4 @@ function toggleControlSidebar() {
|
|||
const sidebar = $(".control-sidebar");
|
||||
|
||||
sidebar.toggleClass("control-sidebar-open");
|
||||
|
||||
if (sidebar.hasClass("control-sidebar-open")) {
|
||||
sidebar.delay(50)
|
||||
.animate(
|
||||
{width: "show"},
|
||||
350,
|
||||
'easeInOutQuint'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ $(document).ready(function () {
|
|||
// Trasformazione risultati in formato leggibile
|
||||
const results = data.map(function (result) {
|
||||
return {
|
||||
label: result.label ? result.label : '<h4>' + result.title + '</h4>' + result.labels
|
||||
label: result.badge ? result.badge : '<h4>' + result.title + '</h4>' + result.badges
|
||||
.join('').split('<br/>,').join('<br/>'),
|
||||
group: result.category,
|
||||
link: result.link,
|
||||
|
@ -87,8 +87,8 @@ $(document).ready(function () {
|
|||
},
|
||||
render: function(item, currentValue){
|
||||
const itemElement = document.createElement("div");
|
||||
itemElement.innerHTML = item.label;
|
||||
// <a href='" + item.link + "' title='Clicca per aprire'><b>" + item.value + "</b><br/>" + item.label + "</a>
|
||||
itemElement.innerHTML = item.badge;
|
||||
// <a href='" + item.link + "' title='Clicca per aprire'><b>" + item.value + "</b><br/>" + item.badge + "</a>
|
||||
return itemElement;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -322,7 +322,7 @@ function impostaCategorieAllegatiDisponibili(gestione, categorie) {
|
|||
update(results);
|
||||
},
|
||||
onSelect: function (item) {
|
||||
input.value = item.label;
|
||||
input.value = item.badge;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -291,7 +291,7 @@ function initComplete(settings) {
|
|||
forceSearch = true;
|
||||
}
|
||||
|
||||
$('<br><input type="text" style="width:100%" class="form-control' + (value ? ' input-searching' : '') + '" placeholder="' + globals.translations.filter + '..." value="' + value.replace(/"/g, '"') + '"><i class="deleteicon fa fa-times fa-2x' + (value ? '' : ' hide') + '"></i>')
|
||||
$('<br><input type="text" style="width:100%" class="form-control' + (value ? ' input-searching' : '') + '" placeholder="' + globals.translations.filter + '..." value="' + value.replace(/"/g, '"') + '"><i class="deleteicon fa fa-times ' + (value ? '' : ' hide') + '"></i>')
|
||||
.appendTo(column.header())
|
||||
.on('keyup', function (e) {
|
||||
clearInterval(tempo);
|
||||
|
@ -410,6 +410,11 @@ function drawCallback(settings) {
|
|||
}).select();
|
||||
}
|
||||
});
|
||||
|
||||
// Fix larghezza colonne datatables
|
||||
setTimeout( function(){
|
||||
datatable.columns.adjust()
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function footerCallback(row, data, start, end, display) {
|
||||
|
@ -418,11 +423,17 @@ function footerCallback(row, data, start, end, display) {
|
|||
|
||||
this.api().columns().every(function () {
|
||||
if (json.summable[i] !== undefined) {
|
||||
$(this.footer()).addClass("text-right")
|
||||
$(this.footer()).css("text-align", "right")
|
||||
.attr("id", "summable")
|
||||
.html(json.summable[i]);
|
||||
}
|
||||
|
||||
if (json.avg[i] !== undefined) {
|
||||
$(this.footer()).css("text-align", "right")
|
||||
.attr("id", "avg")
|
||||
.html(json.avg[i]);
|
||||
}
|
||||
|
||||
i++;
|
||||
});
|
||||
}
|
||||
|
@ -527,7 +538,11 @@ function getTable(selector) {
|
|||
getSelectedRowsFooter: function () {
|
||||
let ids = this.getSelectedRows();
|
||||
|
||||
return $.ajax({
|
||||
let summable_results = [];
|
||||
let avg_results = [];
|
||||
let results = [];
|
||||
|
||||
summable_results = $.ajax({
|
||||
url: globals.rootdir + "/ajax.php",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
|
@ -538,10 +553,25 @@ function getTable(selector) {
|
|||
ids: ids,
|
||||
}
|
||||
});
|
||||
|
||||
avg_results = $.ajax({
|
||||
url: globals.rootdir + "/ajax.php",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
data: {
|
||||
id_module: this.id_module,
|
||||
id_plugin: this.id_plugin,
|
||||
op: "avg-results",
|
||||
ids: ids,
|
||||
}
|
||||
});
|
||||
|
||||
results = $.when(summable_results, avg_results);
|
||||
return results;
|
||||
},
|
||||
|
||||
/**
|
||||
* Aggiornamento dei campi summable
|
||||
* Aggiornamento dei campi summable e avg
|
||||
*/
|
||||
updateFooterForSelectedRows: function () {
|
||||
let datatable = this.datatable;
|
||||
|
@ -550,9 +580,12 @@ function getTable(selector) {
|
|||
for (let [column, value] of Object.entries(response)) {
|
||||
let index = parseInt(column) + 1;
|
||||
let sel = datatable.column(index).footer();
|
||||
$(sel).addClass("text-right")
|
||||
$(sel).css("text-align", "right")
|
||||
.attr("id", "summable")
|
||||
.html(value);
|
||||
$(sel).css("text-align", "right")
|
||||
.attr("id", "avg")
|
||||
.html(value);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
|
|
@ -129,6 +129,7 @@ function start_complete_calendar(id, callback) {
|
|||
ranges[globals.translations.nextMonth] = [moment().add(1, 'month').startOf('month'), moment().add(1, 'month').endOf('month')];
|
||||
ranges[globals.translations.thisYear] = [moment().startOf('year'), moment().endOf('year')];
|
||||
ranges[globals.translations.lastYear] = [moment().subtract(1, 'year').startOf('year'), moment().subtract(1, 'year').endOf('year')];
|
||||
ranges[globals.translations.lastYear_thisYear] = [moment().subtract(1, 'year').startOf('year'), moment().endOf('year')];
|
||||
|
||||
var format = dateFormatMoment(globals.date_format);
|
||||
$(id).daterangepicker({
|
||||
|
|
|
@ -33,8 +33,7 @@ function launch_modal(title, href, init_modal) {
|
|||
*/
|
||||
function openModal(title, href) {
|
||||
// Fix - Select2 does not function properly when I use it inside a Bootstrap modal.
|
||||
$.fn.modal.Constructor.prototype.enforceFocus = function () {
|
||||
};
|
||||
$.fn.modal.Constructor.prototype._enforceFocus = function() {};
|
||||
|
||||
// Generazione dinamica modal
|
||||
do {
|
||||
|
@ -58,13 +57,13 @@ function openModal(title, href) {
|
|||
|
||||
const content = '<div class="modal-dialog modal-lg">\
|
||||
<div class="modal-content">\
|
||||
<div class="modal-header bg-light-blue">\
|
||||
<button type="button" class="close" data-dismiss="modal">\
|
||||
<span aria-hidden="true">×</span><span class="sr-only">' + globals.translations.close + '</span>\
|
||||
</button>\
|
||||
<div class="modal-header">\
|
||||
<h4 class="modal-title">\
|
||||
<i class="fa fa-pencil"></i> ' + title + '\
|
||||
</h4>\
|
||||
<button type="button" class="close" data-dismiss="modal">\
|
||||
<span aria-hidden="true">×</span><span class="sr-only">' + globals.translations.close + '</span>\
|
||||
</button>\
|
||||
</div>\
|
||||
<div class="modal-body">|data|</div>\
|
||||
</div>\
|
||||
|
@ -94,7 +93,7 @@ function openModal(title, href) {
|
|||
* @param link
|
||||
*/
|
||||
function openLink(event, link) {
|
||||
if (event.ctrlKey) {
|
||||
if (event.ctrlKey || event.metaKey) {
|
||||
window.open(link);
|
||||
} else {
|
||||
location.href = link;
|
||||
|
@ -451,17 +450,17 @@ function alertPush() {
|
|||
|
||||
$('.alert-success.push').each(function () {
|
||||
i++;
|
||||
tops = 60 * i + 95;
|
||||
bottoms = 60 * i;
|
||||
|
||||
$(this).css({
|
||||
'position': 'fixed',
|
||||
'z-index': 3000,
|
||||
'z-index': 300000,
|
||||
'right': '10px',
|
||||
'top': -100,
|
||||
'bottom': -100,
|
||||
}).delay(1000).animate({
|
||||
'top': tops,
|
||||
'bottom': bottoms,
|
||||
}).delay(3000).animate({
|
||||
'top': -100,
|
||||
'bottom': -100,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -469,7 +468,7 @@ function alertPush() {
|
|||
// Nascondo la notifica se passo sopra col mouse
|
||||
$('.alert-success.push').on('mouseover', function () {
|
||||
$(this).stop().animate({
|
||||
'top': -100,
|
||||
'bottom': -100,
|
||||
'opacity': 0
|
||||
});
|
||||
});
|
||||
|
|
|
@ -19,15 +19,11 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
function startHooks() {
|
||||
$.ajax({
|
||||
url: globals.rootdir + "/ajax.php",
|
||||
type: "get",
|
||||
data: {
|
||||
op: "hooks",
|
||||
},
|
||||
success: function (data) {
|
||||
hooks = JSON.parse(data);
|
||||
|
||||
// Funzione per richiesta AJAX hooks completata con successo
|
||||
function handleHooksSuccess(hooks) {
|
||||
|
||||
completedRequests = 0;
|
||||
|
||||
$("#hooks-header").text(globals.translations.hooksExecuting);
|
||||
$("#hooks-number").text(hooks.length);
|
||||
|
@ -45,8 +41,33 @@ function startHooks() {
|
|||
});
|
||||
|
||||
startHook(item, true);
|
||||
completedRequests++;
|
||||
});
|
||||
|
||||
totalRequests = hooks.length;
|
||||
if (completedRequests === totalRequests) {
|
||||
// Verifica se tutte le richieste sono state completate con successo
|
||||
//console.log("Tutte le richieste AJAX sono state eseguite con successo.");
|
||||
}else{
|
||||
console.log("Alcune richieste AJAX non sono state eseguite.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function startHooks() {
|
||||
$.ajax({
|
||||
url: globals.rootdir + "/ajax.php",
|
||||
type: "get",
|
||||
data: {
|
||||
op: "hooks",
|
||||
},
|
||||
success: function (data) {
|
||||
hooks = JSON.parse(data);
|
||||
handleHooksSuccess(hooks);
|
||||
},
|
||||
error: function (xhr, status, error) {
|
||||
console.error("Errore durante la richiesta AJAX relativa agli Hooks");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -76,6 +97,7 @@ function startHook(hook, init) {
|
|||
if (token) {
|
||||
executeHook(hook, token);
|
||||
} else {
|
||||
//Rallentamento esecuzione hooks
|
||||
var timeout = 30;
|
||||
|
||||
setTimeout(function () {
|
||||
|
@ -151,11 +173,11 @@ function updateHook(hook) {
|
|||
if (number == 0) {
|
||||
$("#hooks-notified").html('<i class="fa fa-check" aria-hidden="true"></i>');
|
||||
$("#hooks-label").removeClass();
|
||||
$("#hooks-label").addClass('label').addClass('label-success');
|
||||
$("#hooks-label").addClass('badge').addClass('badge-success');
|
||||
} else {
|
||||
$("#hooks-notified").text(number);
|
||||
$("#hooks-label").removeClass();
|
||||
$("#hooks-label").addClass('label').addClass('label-danger');
|
||||
$("#hooks-label").addClass('badge').addClass('badge-danger');
|
||||
}
|
||||
|
||||
if (counter == $("#hooks-number").text()) {
|
||||
|
@ -206,7 +228,7 @@ function renderHook(hook, result) {
|
|||
// Inizializzazione
|
||||
var element = $("#" + element_id);
|
||||
if (element.length == 0) {
|
||||
$("#hooks").append('<li class="hook-element" id="' + element_id + '"></li>');
|
||||
$("#hooks").append('<div class="dropdown-item hook-element" id="' + element_id + '"></div>');
|
||||
|
||||
element = $("#" + element_id);
|
||||
}
|
||||
|
@ -219,7 +241,16 @@ function renderHook(hook, result) {
|
|||
}
|
||||
|
||||
// Contenuto
|
||||
var content = '<a href="' + (result.link ? result.link : "#") + '"><i class="' + result.icon + '"></i><span class="small"> ' + result.message + '</span>';
|
||||
var content = '';
|
||||
|
||||
if (result.link) {
|
||||
content += '<a href="' + result.link + '">';
|
||||
} else {
|
||||
content += '<div class="hooks-header">';
|
||||
}
|
||||
|
||||
|
||||
content += '<i class="' + result.icon + '"></i> <span class="small"> ' + result.message + '</span>';
|
||||
|
||||
if (result.progress) {
|
||||
var current = result.progress.current;
|
||||
|
@ -232,7 +263,11 @@ function renderHook(hook, result) {
|
|||
content += '<div class="progress" style="margin-bottom: 0px;"><div class="progress-bar" role="progressbar" aria-valuenow="' + percentage + '" aria-valuemin="0" aria-valuemax="100" style="width:' + percentage + '%">' + percentage + '% (' + current + '/' + total + ')</div></div>';
|
||||
}
|
||||
|
||||
if (result.link) {
|
||||
content += '</a>';
|
||||
} else {
|
||||
content += '</div>';
|
||||
}
|
||||
|
||||
element.html(content);
|
||||
}
|
||||
|
|
|
@ -17,9 +17,6 @@
|
|||
*/
|
||||
|
||||
function init() {
|
||||
// Inizializzazzione dei box AdminLTE
|
||||
$('.box').boxWidget();
|
||||
|
||||
// Modal di default
|
||||
$('[data-href]').not('.ask, .bound').click(function () {
|
||||
launch_modal($(this).data('title'), $(this).data('href'), 1);
|
||||
|
|
|
@ -238,7 +238,7 @@ function initStaticSelectInput(input) {
|
|||
let $input = $(input);
|
||||
|
||||
$input.select2({
|
||||
theme: "bootstrap",
|
||||
theme: "bootstrap4",
|
||||
language: "it",
|
||||
width: '100%',
|
||||
maximumSelectionLength: $input.data('maximum') ? $input.data('maximum') : -1,
|
||||
|
@ -261,7 +261,7 @@ function initDynamicSelectInput(input) {
|
|||
let $input = $(input);
|
||||
|
||||
$input.select2({
|
||||
theme: "bootstrap",
|
||||
theme: "bootstrap4",
|
||||
language: "it",
|
||||
maximumSelectionLength: $input.data('maximum') ? $input.data('maximum') : -1,
|
||||
minimumInputLength: $input.data('heavy') ? 3 : 0,
|
||||
|
|
|
@ -119,6 +119,7 @@ function initCKEditor(input) {
|
|||
filebrowserUploadMethod: 'form',
|
||||
fullPage: (input.hasAttribute('use_full_ckeditor')) ? true : false,
|
||||
allowedContent: (input.hasAttribute('use_full_ckeditor')) ? true : false,
|
||||
versionCheck: false,
|
||||
extraPlugins: 'scayt,textwatcher,autocomplete,textmatch,emoji',
|
||||
skin: 'moono-lisa',
|
||||
});
|
||||
|
|
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -1,3 +1,8 @@
|
|||
/**
|
||||
* Copyright (C) 2023 Wacom.
|
||||
* Use of this source code is governed by the MIT License that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
function integrityStatusDesc(status) {
|
||||
switch (status) {
|
||||
case Module.IntegrityStatus.OK: return "Integrity correct";
|
||||
|
|
0
assets/src/js/wacom/sigCaptDialog/libs/stu_capture/stu-sdk.min.js → assets/src/js/wacom/common/libs/stu-sdk.min.js
vendored
Executable file → Normal file
0
assets/src/js/wacom/sigCaptDialog/libs/stu_capture/stu-sdk.min.js → assets/src/js/wacom/common/libs/stu-sdk.min.js
vendored
Executable file → Normal file
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"name": "STU-SDK",
|
||||
"productName": "STU-SDK",
|
||||
"version": "1.0.0",
|
||||
"description": "STU SDK for Javascript",
|
||||
"dependencies": {
|
||||
"blueimp-md5": "^2.19.0",
|
||||
"sjcl": "^1.0.8"
|
||||
},
|
||||
"author": "Juan Garrido",
|
||||
"license": "Wacom"
|
||||
}
|
|
@ -1,826 +0,0 @@
|
|||
//
|
||||
// stu_capture.js
|
||||
//
|
||||
// Displays a form with 3 buttons on the STU pad and on the browser allowing user to input a signature.
|
||||
// The final signature is then reproduced on a second window on the PC screen
|
||||
//
|
||||
// Copyright (c) 2021 Wacom GmbH. All rights reserved.
|
||||
//
|
||||
//
|
||||
|
||||
var signatureForm;
|
||||
|
||||
function captureFromSTU(sigObj, integrityType, hash, extraData) {
|
||||
if (!signatureForm) {
|
||||
signatureForm = new SignatureForm(sigObj, integrityType, hash, extraData);
|
||||
}
|
||||
signatureForm.connect();
|
||||
}
|
||||
|
||||
class Point {
|
||||
constructor(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
|
||||
// In order to simulate buttons, we have our own Button class that stores the bounds and event handler.
|
||||
// Using an array of these makes it easy to add or remove buttons as desired.
|
||||
// delegate void ButtonClick();
|
||||
function Button() {
|
||||
this.Bounds; // in Screen coordinates
|
||||
this.Text;
|
||||
this.Click;
|
||||
}
|
||||
|
||||
function Rectangle(x, y, width, height) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
|
||||
this.Contains = function (pt) {
|
||||
if (((pt.x >= this.x) && (pt.x <= (this.x + this.width))) &&
|
||||
((pt.y >= this.y) && (pt.y <= (this.y + this.height)))) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SignatureForm {
|
||||
|
||||
constructor(sigObj, integrityType, hash, extraData) {
|
||||
this.sigObj = sigObj;
|
||||
this.integrityType = integrityType;
|
||||
this.hash = hash;
|
||||
this.extraData = extraData;
|
||||
|
||||
// The mIsDown flag is used like this:
|
||||
// 0 = up
|
||||
// +ve = down, pressed on button number
|
||||
// -1 = down, inking
|
||||
// -2 = down, ignoring
|
||||
this.mIsDown = 0;
|
||||
|
||||
this.mPenData = new Array(); // Array of data being stored. This can be subsequently used as desired.
|
||||
this.currentDevice = null;
|
||||
|
||||
this.onClick = false;
|
||||
}
|
||||
|
||||
// Connect to the first device
|
||||
async connect() {
|
||||
if (!this.currentDevice) {
|
||||
let devices = await com.WacomGSS.STU.UsbDevice.requestDevices();
|
||||
if (devices.length > 0) {
|
||||
this.currentDevice = devices[0];
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.mTablet = new com.WacomGSS.STU.Tablet();
|
||||
this.mTablet.setEncryptionHandler(new MyEncryptionHandler());
|
||||
this.mTablet.setEncryptionHandler2(new MyEncryptionHandler2());
|
||||
|
||||
try {
|
||||
await this.mTablet.usbConnect(this.currentDevice);
|
||||
this.mCapability = await this.mTablet.getCapability();
|
||||
this.mInformation = await this.mTablet.getInformation();
|
||||
this.mInkThreshold = await this.mTablet.getInkThreshold();
|
||||
|
||||
try {
|
||||
await this.mTablet.setPenDataOptionMode(com.WacomGSS.STU.Protocol.PenDataOptionMode.TimeCountSequence);
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
this.mTablet.addTabletHandler(this);
|
||||
|
||||
//if (this.mTablet.isSupported(com.WacomGSS.STU.Protocol.ReportId.OperationMode_$LI$())) {
|
||||
//this.mSignatureMode = true;
|
||||
//}
|
||||
this.mSignatureMode = false;
|
||||
|
||||
const pixelWidth = (96*this.mCapability.tabletMaxX*0.01)/25.4;
|
||||
const pixelHeight = (96*this.mCapability.tabletMaxY*0.01)/25.4;
|
||||
//this.createModalWindow(this.mCapability.screenWidth, this.mCapability.screenHeight);
|
||||
this.createModalWindow(pixelWidth, pixelHeight);
|
||||
|
||||
this.mScaleX = this.canvas.width / this.mCapability.tabletMaxX;
|
||||
this.mScaleY = this.canvas.height / this.mCapability.tabletMaxY;
|
||||
|
||||
this.mBtns = new Array(3);
|
||||
this.mBtns[0] = new Button();
|
||||
this.mBtns[1] = new Button();
|
||||
this.mBtns[2] = new Button();
|
||||
|
||||
if (this.mSignatureMode) {
|
||||
|
||||
// LCD is 800x480; Button positions and sizes are fixed
|
||||
this.mBtns[0].Bounds = new Rectangle( 0, 431, 265, 48);
|
||||
this.mBtns[1].Bounds = new Rectangle(266, 431, 265, 48);
|
||||
this.mBtns[2].Bounds = new Rectangle(532, 431, 265, 48);
|
||||
} else if (this.mInformation.modelName != "STU-300") {
|
||||
|
||||
// Place the buttons across the bottom of the screen.
|
||||
const w2 = this.canvas.width / 3;
|
||||
const w3 = this.canvas.width / 3;
|
||||
const w1 = this.canvas.width - w2 - w3;
|
||||
const y = this.canvas.height * 6 / 7;
|
||||
const h = this.canvas.height - y;
|
||||
|
||||
this.mBtns[0].Bounds = new Rectangle(0, y, w1, h);
|
||||
this.mBtns[1].Bounds = new Rectangle(w1, y, w2, h);
|
||||
this.mBtns[2].Bounds = new Rectangle(w1 + w2, y, w3, h);
|
||||
|
||||
} else {
|
||||
// The STU-300 is very shallow, so it is better to utilise
|
||||
// the buttons to the side of the display instead.
|
||||
|
||||
const x = this.mCapability.screenWidth * 3 / 4;
|
||||
const w = this.mCapability.screenWidth - x;
|
||||
|
||||
const h2 = this.mCapability.screenHeight / 3;
|
||||
const h3 = this.mCapability.screenHeight / 3;
|
||||
const h1 = this.mCapability.screenHeight - h2 - h3;
|
||||
|
||||
this.mBtns[0].Bounds = new Rectangle(x, 0, w, h1);
|
||||
this.mBtns[1].Bounds = new Rectangle(x, h1, w, h2);
|
||||
this.mBtns[2].Bounds = new Rectangle(x, h1 + h2, w, h3);
|
||||
}
|
||||
|
||||
this.mBtns[0].Text = "Clear";
|
||||
this.mBtns[0].Click = this.btnClearClick.bind(this);
|
||||
this.mBtns[1].Text = "Cancel";
|
||||
this.mBtns[1].Click = this.btnCancelClick.bind(this);
|
||||
this.mBtns[2].Text = "OK";
|
||||
this.mBtns[2].Click = this.btnOkClick.bind(this);
|
||||
|
||||
// This application uses the same bitmap for both the screen and client (window).
|
||||
this.ctx.lineWidth = 1;
|
||||
this.ctx.strokeStyle = 'black';
|
||||
this.ctx.font = "30px Arial";
|
||||
|
||||
this.ctx.fillStyle = "white";
|
||||
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
|
||||
|
||||
let encodingFlag = com.WacomGSS.STU.Protocol.ProtocolHelper.simulateEncodingFlag(this.mTablet.getProductId(), this.mCapability.ecodingFlag);
|
||||
// Disable color if the bulk driver isn't installed (supportsWrite())
|
||||
if ((encodingFlag & com.WacomGSS.STU.Protocol.EncodingFlag.EncodingFlag_24bit) != 0) {
|
||||
this.mEncodingMode = this.mTablet.supportsWrite() ? com.WacomGSS.STU.Protocol.EncodingMode.EncodingMode_24bit_Bulk : com.WacomGSS.STU.Protocol.EncodingMode.EncodingMode_24bit;
|
||||
} else if ((encodingFlag & com.WacomGSS.STU.Protocol.EncodingFlag.EncodingFlag_16bit) != 0) {
|
||||
this.mEncodingMode = this.mTablet.supportsWrite() ? com.WacomGSS.STU.Protocol.EncodingMode.EncodingMode_16bit_Bulk : com.WacomGSS.STU.Protocol.EncodingMode.EncodingMode_16bit;
|
||||
} else {
|
||||
// assumes 1bit is available
|
||||
this.mEncodingMode = com.WacomGSS.STU.Protocol.EncodingMode.EncodingMode_1bit;
|
||||
}
|
||||
|
||||
if (this.mSignatureMode && !await this.initializeSigMode()) {
|
||||
alert("Exception initializing Signature Mode, reverting to normal operation");
|
||||
this.mSignatureMode = false;
|
||||
}
|
||||
|
||||
if (!this.mSignatureMode) {
|
||||
let btnsColors = ["white", "white", "white"];
|
||||
if((this.mEncodingMode & (com.WacomGSS.STU.Protocol.EncodingMode.EncodingMode_16bit_Bulk | com.WacomGSS.STU.Protocol.EncodingMode.EncodingMode_24bit_Bulk)) != 0)
|
||||
btnsColors = ["lightgrey", "lightgrey", "lightgrey"];
|
||||
|
||||
let newCanvas = this.createScreenImage(btnsColors, "black", null);
|
||||
|
||||
//store the background image in order to be reuse it when clear the screen
|
||||
this.mCanvasBackgroundImage = newCanvas.toDataURL("image/jpeg");
|
||||
this.mDeviceBackgroundImage = com.WacomGSS.STU.Protocol.ProtocolHelper.resizeAndFlatten(newCanvas, 0, 0, newCanvas.width, newCanvas.height,
|
||||
this.mCapability.screenWidth, this.mCapability.screenHeight, this.mEncodingMode,0, "white", false, 0);
|
||||
|
||||
// If you wish to further optimize image transfer, you can compress the image using
|
||||
// the Zlib algorithm.
|
||||
const useZlibCompression = false;
|
||||
|
||||
if (this.mEncodingMode == com.WacomGSS.STU.Protocol.EncodingMode.EncodingMode_1bit && useZlibCompression) {
|
||||
this.mDeviceBackgroundImage = compress_using_zlib(this.mDeviceBackgroundImage); // insert compression here!
|
||||
this.mEncodingMode = com.WacomGSS.STU.Protocol.EncodingMode.EncodingMode_1bit_ZLib;
|
||||
}
|
||||
|
||||
// Initialize the screen
|
||||
await this.clearScreen();
|
||||
}
|
||||
|
||||
if ((this.mTablet.isSupported(com.WacomGSS.STU.Protocol.ReportId.EncryptionStatus)) ||
|
||||
(await com.WacomGSS.STU.Protocol.ProtocolHelper.supportsEncryption(this.mTablet.getProtocol()))) {
|
||||
|
||||
await this.mTablet.startCapture(0xc0ffee);
|
||||
this.mIsEncrypted = true;
|
||||
}
|
||||
|
||||
// Enable the pen data on the screen (if not already)
|
||||
await this.mTablet.setInkingMode(com.WacomGSS.STU.Protocol.InkingMode.On);
|
||||
|
||||
this.willCanvas = document.createElement("canvas");
|
||||
this.willCanvas.id = "willCanvas";
|
||||
this.willCanvas.style.position = "absolute";
|
||||
this.willCanvas.style.top = this.canvas.style.top;
|
||||
this.willCanvas.style.left = this.canvas.style.left;
|
||||
this.willCanvas.height = this.canvas.height;
|
||||
this.willCanvas.width = this.canvas.width;
|
||||
this.mFormDiv.appendChild(this.willCanvas);
|
||||
|
||||
if (this.willCanvas.addEventListener) {
|
||||
this.willCanvas.addEventListener("click", this.onCanvasClick.bind(this), false);
|
||||
}
|
||||
|
||||
await this.initInkController(this.willCanvas);
|
||||
|
||||
} catch (e) {
|
||||
alert(e);
|
||||
}
|
||||
}
|
||||
|
||||
async disconnect() {
|
||||
// Ensure that you correctly disconnect from the tablet, otherwise you are
|
||||
// likely to get errors when wanting to connect a second time.
|
||||
if (this.mTablet != null) {
|
||||
if (this.mIsEncrypted) {
|
||||
await this.mTablet.endCapture();
|
||||
this.mIsEncrypted = false;
|
||||
}
|
||||
|
||||
await this.mTablet.setInkingMode(com.WacomGSS.STU.Protocol.InkingMode.Off);
|
||||
await this.mTablet.setClearScreen();
|
||||
await this.mTablet.disconnect();
|
||||
}
|
||||
|
||||
this.closeModalWindow();
|
||||
}
|
||||
|
||||
showLoadingScreen(value) {
|
||||
if (value) {
|
||||
//this.canvas.style.display = "none";
|
||||
this.mLoadingImageDiv.style.display = "block";
|
||||
} else {
|
||||
//this.canvas.style.display = "block";
|
||||
this.mLoadingImageDiv.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
createModalWindow(width, height) {
|
||||
this.mModalBackground = document.createElement('div');
|
||||
this.mModalBackground.id = "modal-background";
|
||||
this.mModalBackground.className = "active";
|
||||
this.mModalBackground.style.width = window.innerWidth;
|
||||
this.mModalBackground.style.height = window.innerHeight;
|
||||
document.getElementsByTagName('body')[0].appendChild(this.mModalBackground);
|
||||
|
||||
let titleBarHeight = 25;
|
||||
let margin = 2;
|
||||
this.mSignatureWindow = document.createElement('div');
|
||||
this.mSignatureWindow.id = "signatureWindow";
|
||||
this.mSignatureWindow.style.position = "absolute";
|
||||
this.mSignatureWindow.style.backgroundColor = "#0097d4";
|
||||
this.mSignatureWindow.style.top = (window.innerHeight / 2) - (height / 2) + "px";
|
||||
this.mSignatureWindow.style.left = (window.innerWidth / 2) - (width / 2) + "px";
|
||||
this.mSignatureWindow.style.width = (width + margin + margin) + "px";
|
||||
this.mSignatureWindow.style.height = (height+titleBarHeight + margin + margin) + "px";
|
||||
document.getElementsByTagName('body')[0].appendChild(this.mSignatureWindow);
|
||||
|
||||
this.mTitleBar = document.createElement("div");
|
||||
this.mTitleBar.id = "titleBar";
|
||||
this.mTitleBar.style.width = "100%";
|
||||
this.mTitleBar.style.height = (titleBarHeight-5)+"px";
|
||||
this.mTitleBar.innerHTML = this.mInformation.modelName;
|
||||
this.mSignatureWindow.appendChild(this.mTitleBar);
|
||||
|
||||
this.mFormDiv = document.createElement('div');
|
||||
//this.mFormDiv.id = "signatureWindow";
|
||||
//this.mFormDiv.className = "active";
|
||||
this.mFormDiv.style.position = "absolute";
|
||||
this.mFormDiv.style.margin = "2px 2px 2px 2px";
|
||||
this.mFormDiv.style.top = titleBarHeight;//(window.innerHeight / 2) - (height / 2) + "px";
|
||||
//this.mFormDiv.style.left = "10px";//(window.innerWidth / 2) - (width / 2) + "px";
|
||||
this.mFormDiv.style.width = width + "px";
|
||||
this.mFormDiv.style.height = height + "px";
|
||||
this.mSignatureWindow.appendChild(this.mFormDiv);
|
||||
//document.getElementsByTagName('body')[0].appendChild(this.mFormDiv);
|
||||
|
||||
this.canvas = document.createElement("canvas");
|
||||
this.canvas.id = "myCanvas";
|
||||
this.canvas.style.position = "absolute";
|
||||
this.canvas.height = this.mFormDiv.offsetHeight;
|
||||
this.canvas.width = this.mFormDiv.offsetWidth;
|
||||
this.ctx = this.canvas.getContext("2d");
|
||||
this.mFormDiv.appendChild(this.canvas);
|
||||
//this.canvas.style.display = "none";
|
||||
|
||||
//if (this.canvas.addEventListener) {
|
||||
//this.canvas.addEventListener("click", this.onCanvasClick.bind(this), false);
|
||||
//}
|
||||
|
||||
this.mLoadingImageDiv = document.createElement('div');
|
||||
this.mLoadingImageDiv.style.position = "absolute";
|
||||
this.mLoadingImageDiv.style.backgroundColor="white";
|
||||
this.mLoadingImageDiv.style.width = "100%";
|
||||
this.mLoadingImageDiv.style.height = "100%";
|
||||
this.mLoadingImageDiv.innerHTML = '<div id="loadingDiv"><table><tr><td><img src="../common/stu_capture/loading.gif"></td><td>Loading the image, this could take a few seconds...</td></tr></div>';
|
||||
this.mFormDiv.appendChild(this.mLoadingImageDiv);
|
||||
|
||||
$("#signatureWindow").draggable({handle:"#titleBar"});
|
||||
}
|
||||
|
||||
// Initialize Signature Mode (STU-540 only)
|
||||
async initializeSigMode() {
|
||||
// Buttons on bitmaps sent to the tablet must be in the order Cancel / OK / Clear. The tablet will then
|
||||
// reorder button images displayed according to parameters passed to it in OperationMode_Signature
|
||||
// This application uses Clear / Cancel / OK
|
||||
const btnOrder = [2, 0, 1];
|
||||
const btnsUpColors = ["blue", "red", "green"];
|
||||
const btnsDownColors = ["darkblue", "darkred", "darkgreen"];
|
||||
|
||||
let canvas = this.createScreenImage(btnsUpColors, "black", btnOrder);
|
||||
let bitmapData = com.WacomGSS.STU.Protocol.ProtocolHelper.resizeAndFlatten(canvas, 0, 0, canvas.width, canvas.height,
|
||||
this.mCapability.screenWidth, this.mCapability.screenHeight, this.mEncodingMode,
|
||||
com.WacomGSS.STU.Protocol.ProtocolHelper.Scale.Strech, "white", false, 0);
|
||||
await this.checkSigModeImage(false, bitmapData);
|
||||
|
||||
canvas = this.createScreenImage(btnsDownColors, "white", btnOrder);
|
||||
bitmapData = com.WacomGSS.STU.Protocol.ProtocolHelper.resizeAndFlatten(canvas, 0, 0, canvas.width, canvas.height,
|
||||
this.mCapability.screenWidth, this.mCapability.screenHeight, this.mEncodingMode,
|
||||
com.WacomGSS.STU.Protocol.ProtocolHelper.Scale.Strech, "white", false, 0);
|
||||
await this.checkSigModeImage(true, bitmapData);
|
||||
|
||||
let sigMode = new com.WacomGSS.STU.Protocol.OperationMode_Signature(2, btnOrder, 0, 0);
|
||||
await this.mTablet.setOperationMode(new com.WacomGSS.STU.Protocol.OperationMode(sigMode));
|
||||
|
||||
canvas = this.createScreenImage(btnsUpColors, "black", null);
|
||||
this.mCanvasBackgroundImage = canvas.toDataURL("image/jpeg");
|
||||
|
||||
this.clearScreen();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
createScreenImage(btnColors, txtColor, btnOrder) {
|
||||
let canvas = document.createElement("canvas");
|
||||
canvas.width = this.canvas.width;
|
||||
canvas.height = this.canvas.height;
|
||||
|
||||
let ctx = canvas.getContext("2d");
|
||||
ctx.lineWidth = 1;
|
||||
ctx.strokeStyle = 'black';
|
||||
ctx.font = "30px Arial";
|
||||
|
||||
ctx.fillStyle = "white";
|
||||
ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
|
||||
|
||||
// Draw the buttons
|
||||
for (let i = 0; i < this.mBtns.length; ++i) {
|
||||
// Button objects are created in the order, left-to-right, Clear / Cancel / OK
|
||||
// If reordering for Signature Mode (btnOrder != null), use bounds of another button when drawing
|
||||
// for image to be sent to tablet.
|
||||
let btn = this.mBtns[i];
|
||||
let bounds = btnOrder != null ? this.mBtns[btnOrder[i]].Bounds : this.mBtns[i].Bounds;
|
||||
|
||||
if (this.mEncodingMode != com.WacomGSS.STU.Protocol.EncodingMode.EncodingMode_1bit) {
|
||||
ctx.fillStyle = btnColors[i];
|
||||
ctx.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
|
||||
}
|
||||
|
||||
ctx.fillStyle = txtColor;
|
||||
ctx.rect(bounds.x, bounds.y, bounds.width, bounds.height);
|
||||
|
||||
let xPos = bounds.x + ((bounds.width / 2) - (ctx.measureText(btn.Text).width / 2));
|
||||
|
||||
let metrics = ctx.measureText(btn.Text);
|
||||
let fontHeight = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent;
|
||||
let actualHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
|
||||
|
||||
let yOffset = bounds.height - ((bounds.height / 2) - (actualHeight / 2));
|
||||
/*if (m_information.idProduct == enumProductId.STU_300)
|
||||
yOffset = 28;
|
||||
else if (m_information.idProduct == enumProductId.STU_430)
|
||||
yOffset = 26;
|
||||
else
|
||||
yOffset = 40;*/
|
||||
ctx.fillText(btn.Text, xPos, bounds.y + yOffset);
|
||||
}
|
||||
|
||||
ctx.stroke();
|
||||
|
||||
/*if ((this.mTablet.isSupported(com.WacomGSS.STU.Protocol.ReportId.EncryptionStatus)) ||
|
||||
(await com.WacomGSS.STU.Protocol.ProtocolHelper.supportsEncryption(this.mTablet.getProtocol()))) {
|
||||
ctx.fillStyle = "black";
|
||||
ctx.fillText("\uD83D\uDD12", 20, 50);
|
||||
}*/
|
||||
return canvas;
|
||||
}
|
||||
|
||||
// Check if a Signature Mode screen image is already stored on the tablet. Download it if not.
|
||||
async checkSigModeImage(pushed, imageData) {
|
||||
let sigScreenImageNum = 2;
|
||||
let romStartImageData = com.WacomGSS.STU.Protocol.RomStartImageData.initializeSignature(this.mEncodingMode, pushed, sigScreenImageNum, [true, true, true]);
|
||||
|
||||
await this.mTablet.setRomImageHash(com.WacomGSS.STU.Protocol.OperationModeType.Signature_$LI$(), pushed, sigScreenImageNum);
|
||||
let romImgHash = await this.mTablet.getRomImageHash();
|
||||
|
||||
let writeImage = true;
|
||||
if (romImgHash.getResult() == 0) {
|
||||
// There is already an image stored on the tablet corresponding to this image number and pushed state:
|
||||
// compare image hashes to determine if we need to overwrite it.
|
||||
if (arrayEquals(md5.array(imageData), romImgHash.getHash())) {
|
||||
// Image hashes match: no need to write image again
|
||||
writeImage = false;
|
||||
}
|
||||
}
|
||||
// else - no image on pad, writeImage = true;
|
||||
|
||||
if (writeImage) {
|
||||
// no image on pad
|
||||
await this.mTablet.writeRomImage(romStartImageData, imageData);
|
||||
}
|
||||
}
|
||||
|
||||
async clearScreen() {
|
||||
if (window.WILL) {
|
||||
window.WILL.clear();
|
||||
} else {
|
||||
// repaint the background image on the screen.
|
||||
const outer = this;
|
||||
const image = new Image();
|
||||
image.onload = function () {
|
||||
outer.ctx.drawImage(image, 0, 0);
|
||||
}
|
||||
image.src = this.mCanvasBackgroundImage;
|
||||
}
|
||||
|
||||
this.showLoadingScreen(true);
|
||||
if (!this.mSignatureMode) {
|
||||
// note: There is no need to clear the tablet screen prior to writing an image.
|
||||
await this.mTablet.writeImage(this.mEncodingMode, this.mDeviceBackgroundImage);
|
||||
}
|
||||
|
||||
this.mPenData = new Array();
|
||||
this.mIsDown = 0;
|
||||
|
||||
this.showLoadingScreen(false);
|
||||
}
|
||||
|
||||
closeModalWindow() {
|
||||
this.deleteInkCanvas();
|
||||
document.getElementsByTagName('body')[0].removeChild(this.mSignatureWindow);
|
||||
const modalBackground = document.getElementById("modal-background");
|
||||
if (modalBackground) {
|
||||
document.getElementsByTagName('body')[0].removeChild(modalBackground);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
tabletToScreen(penData) {
|
||||
// Screen means LCD screen of the tablet.
|
||||
return new Point(penData.x * this.mScaleX, penData.y * this.mScaleY);
|
||||
}
|
||||
|
||||
async onSignatureEvent(keyValue) {
|
||||
switch (keyValue) {
|
||||
case 0:
|
||||
await this.btnCancelClick()
|
||||
break;
|
||||
case 1:
|
||||
await this.btnOkClick();
|
||||
break;
|
||||
case 2:
|
||||
await this.btnClearClick();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
onCanvasClick(event) {
|
||||
// Enable the mouse to click on the simulated buttons that we have displayed.
|
||||
|
||||
// Note that this can add some tricky logic into processing pen data
|
||||
// if the pen was down at the time of this click, especially if the pen was logically
|
||||
// also 'pressing' a button! This demo however ignores any that.
|
||||
|
||||
const posX = event.pageX - $("#willCanvas").offset().left;
|
||||
const posY = event.pageY - $("#willCanvas").offset().top;
|
||||
|
||||
for (let i = 0; i < this.mBtns.length; i++) {
|
||||
if (this.mBtns[i].Bounds.Contains(new Point(posX, posY))) {
|
||||
this.mBtns[i].Click();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async btnOkClick() {
|
||||
if (this.mPenData.length > 0) {
|
||||
await this.getCaptureData();
|
||||
await this.btnCancelClick();
|
||||
this.renderSignature = true;
|
||||
}
|
||||
this.onClick = false;
|
||||
|
||||
}
|
||||
|
||||
async btnClearClick() {
|
||||
if (this.mPenData.length > 0) {
|
||||
await this.clearScreen();
|
||||
}
|
||||
this.onClick = false;
|
||||
}
|
||||
|
||||
async btnCancelClick() {
|
||||
await this.disconnect();
|
||||
this.onClick = false;
|
||||
}
|
||||
|
||||
// Generate the signature image
|
||||
async getCaptureData() {
|
||||
//Create Stroke Data
|
||||
var strokeVector = new Module.StrokeVector();
|
||||
var currentStroke = new Module.PointVector();
|
||||
|
||||
var currentStrokeID = 0;
|
||||
var isDown = true;
|
||||
var hasDown = false;
|
||||
|
||||
for (let index = 0; index < this.mPenData.length; index++) {
|
||||
if (this.mPenData[index].sw == 0 && !hasDown) {
|
||||
continue;
|
||||
}
|
||||
|
||||
hasDown = true;
|
||||
|
||||
if (isDown && this.mPenData[index].sw == 0 || !isDown && this.mPenData[index].sw == 1) {
|
||||
isDown = (this.mPenData[index].sw == 1);
|
||||
//Move the current stroke data into the strokes array
|
||||
strokeVector.push_back({'points': currentStroke});
|
||||
currentStroke.delete();
|
||||
currentStroke = new Module.PointVector();
|
||||
currentStrokeID++;
|
||||
}
|
||||
|
||||
var point = {
|
||||
'x': this.mPenData[index].x,
|
||||
'y': this.mPenData[index].y,
|
||||
'p': this.mPenData[index].pressure,
|
||||
't': this.mPenData[index].timeCount,
|
||||
'tilt': 0,
|
||||
'twist': 0,
|
||||
'is_down': this.mPenData[index].sw,
|
||||
'stroke_id': currentStrokeID
|
||||
};
|
||||
|
||||
currentStroke.push_back(point);
|
||||
}
|
||||
|
||||
//Create capture area character
|
||||
var device = {
|
||||
'device_max_X': this.mCapability.tabletMaxX,
|
||||
'device_max_Y': this.mCapability.tabletMaxY,
|
||||
'device_max_P': this.mCapability.tabletMaxPressure,
|
||||
'device_pixels_per_m_x': 100000,
|
||||
'device_pixels_per_m_y': 100000,
|
||||
'device_origin_X': 0,
|
||||
'device_origin_Y': 1,
|
||||
'has_tilt': false,
|
||||
'has_twist': false
|
||||
}
|
||||
|
||||
var uid2;
|
||||
try {
|
||||
// getUid2 will throw if pad doesn't support Uid2
|
||||
uid2 = mTablet.getUid2();
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
|
||||
if (!uid2) {
|
||||
uid2 = 0;
|
||||
}
|
||||
|
||||
var digitizerInfo = "STU;'"+this.mInformation.modelName+"';"+this.mInformation.firmwareMajorVersion+"."+((parseInt(this.mInformation.firmwareMinorVersion) >> 4) & 0x0f)+"."+(parseInt(this.mInformation.firmwareMinorVersion) & 0x0f)+";"+uid2;
|
||||
var nicInfo = "";
|
||||
var timeResolution = 1000;
|
||||
var who = "Test user";
|
||||
var why = "test signature";
|
||||
var where = "";
|
||||
|
||||
await this.sigObj.generateSignature(who, why, where, this.integrityType, this.hash, strokeVector, device, digitizerInfo, nicInfo, timeResolution, new Date());
|
||||
|
||||
// put the extra data
|
||||
for (const [key, value] of this.extraData) {
|
||||
this.sigObj.setExtraData(key, value);
|
||||
}
|
||||
|
||||
//this.hash.delete();
|
||||
strokeVector.delete();
|
||||
currentStroke.delete();
|
||||
}
|
||||
|
||||
onPenDataOption(penData, time) {
|
||||
this.onPenData(penData, time);
|
||||
}
|
||||
|
||||
onPenDataTimeCountSequence(penData, time) {
|
||||
this.onPenData(penData, time);
|
||||
}
|
||||
|
||||
onPenDataTimeCountSequenceEncrypted(penData, time) {
|
||||
this.onPenDataTimeCountSequence(penData, time);
|
||||
}
|
||||
|
||||
onPenDataEncryptedOption(penData, time) { // Process incoming pen data
|
||||
this.onPenData(penData.penData1, time);
|
||||
this.onPenData(penData.penData2, time);
|
||||
}
|
||||
|
||||
onPenDataEncrypted(penData, time) { // Process incoming pen data
|
||||
this.onPenData(penData.penData1, time);
|
||||
this.onPenData(penData.penData2, time);
|
||||
}
|
||||
|
||||
onPenData(penData, time) { // Process incoming pen data
|
||||
|
||||
// console.log(JSON.stringify(penData));
|
||||
|
||||
|
||||
if (this.onClick) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!penData.timeCount) {
|
||||
penData.timeCount = Math.trunc(time)%1000000;
|
||||
}
|
||||
|
||||
// when the pen goes behind borders there is a bug that onalsy return 0
|
||||
let pt = this.tabletToScreen(penData);
|
||||
|
||||
let btn = 0; // will be +ve if the pen is over a button.
|
||||
for (var i = 0; i < this.mBtns.length; ++i) {
|
||||
if (this.mBtns[i].Bounds.Contains(pt)) {
|
||||
btn = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.mIsDown == 0)
|
||||
{
|
||||
const isDown = (penData.pressure > this.mInkThreshold.onPressureMark);
|
||||
|
||||
if (isDown)
|
||||
{
|
||||
// transition to down
|
||||
if (btn > 0)
|
||||
{
|
||||
// We have put the pen down on a button.
|
||||
// Track the pen without inking on the client.
|
||||
|
||||
this.mIsDown = btn;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We have put the pen down somewhere else.
|
||||
// Treat it as part of the signature.
|
||||
|
||||
this.mIsDown = -1;
|
||||
this.mPenData.push(penData);
|
||||
this.mPainting = true;
|
||||
|
||||
var downEvent = new PointerEvent("pointerdown", {
|
||||
pointerId: 1,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
pointerType: "pen",
|
||||
pressure: penData.pressure/this.mCapability.tabletMaxPressure,
|
||||
isPrimary: true,
|
||||
clientX: pt.x,
|
||||
clientY: pt.y,
|
||||
time: penData.timeCount
|
||||
});
|
||||
|
||||
window.WILL.begin(InkBuilder.createPoint(downEvent));
|
||||
}
|
||||
} else {
|
||||
// hover point
|
||||
this.mPenData.push(penData);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const isDown = !(penData.pressure <= this.mInkThreshold.offPressureMark);
|
||||
if (!isDown)
|
||||
{
|
||||
// transition to up
|
||||
if (btn > 0) {
|
||||
// The pen is over a button
|
||||
|
||||
if (btn == this.mIsDown) {
|
||||
// The pen was pressed down over the same button as is was lifted now.
|
||||
// Consider that as a clicki!
|
||||
this.onClick = true; //
|
||||
this.mBtns[btn-1].Click();
|
||||
}
|
||||
}
|
||||
this.mIsDown = 0;
|
||||
|
||||
if (this.mPainting) {
|
||||
this.mPainting = false;
|
||||
this.mPenData.push(penData);
|
||||
|
||||
if ((penData.x == 0) && (penData.y == 0) && (penData.pressure == 0)) {
|
||||
penData.x = this.lastPenData.x;
|
||||
penData.y = this.lastPenData.y;
|
||||
pt = this.tabletToScreen(penData);
|
||||
}
|
||||
|
||||
var upEvent = new PointerEvent("pointerup", {
|
||||
pointerId: 1,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
pointerType: "pen",
|
||||
pressure: penData.pressure/this.mCapability.tabletMaxPressure,
|
||||
isPrimary: true,
|
||||
clientX: pt.x,
|
||||
clientY: pt.y,
|
||||
time: penData.timeCount
|
||||
});
|
||||
|
||||
window.WILL.end(InkBuilder.createPoint(upEvent));
|
||||
}
|
||||
} else {
|
||||
if (this.mPainting) {
|
||||
this.mPenData.push(penData);
|
||||
|
||||
var moveEvent = new PointerEvent("pointermove", {
|
||||
pointerId: 1,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
pointerType: "pen",
|
||||
width: 10,
|
||||
height: 10,
|
||||
pressure: penData.pressure/this.mCapability.tabletMaxPressure,
|
||||
isPrimary: true,
|
||||
clientX: pt.x,
|
||||
clientY: pt.y,
|
||||
time: penData.timeCount
|
||||
});
|
||||
|
||||
window.WILL.move(InkBuilder.createPoint(moveEvent));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
this.lastPenData = penData;
|
||||
}
|
||||
|
||||
onEventDataSignature(eventData) {
|
||||
this.onSignatureEvent(eventData.getKeyValue());
|
||||
}
|
||||
|
||||
onEventDataSignatureEncrypted(eventData) {
|
||||
this.onSignatureEvent(eventData.getKeyValue());
|
||||
}
|
||||
|
||||
// Capture any report exception.
|
||||
onGetReportException(exception) {
|
||||
try {
|
||||
exception.getException();
|
||||
} catch (e) {
|
||||
alert(e);
|
||||
}
|
||||
}
|
||||
|
||||
async initInkController(canvas) {
|
||||
const inkColor = "#0000ff";
|
||||
let inkCanvas = await new InkCanvasRaster(canvas, canvas.width, canvas.height);
|
||||
await BrushPalette.configure(inkCanvas.canvas.ctx);
|
||||
|
||||
window.WILL = inkCanvas;
|
||||
WILL.setColor(Color.fromHex(inkColor));
|
||||
WILL.type = "raster";
|
||||
await WILL.setTool("pen");
|
||||
}
|
||||
|
||||
async deleteInkCanvas() {
|
||||
await BrushPalette.delete();
|
||||
await window.WILL.delete();
|
||||
window.WILL = null;
|
||||
|
||||
if (this.renderSignature) {
|
||||
this.renderSignature = false;
|
||||
renderSignature(true);
|
||||
}
|
||||
}
|
||||
|
||||
onDisconnect(device) {
|
||||
if (device == this.currentDevice) {
|
||||
if (document.getElementById("modal-background")) {
|
||||
this.closeModalWindow();
|
||||
}
|
||||
alert(device.productName+" has been disconnected, please connect it again.");
|
||||
this.currentDevice = null;
|
||||
signatureForm = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,289 +0,0 @@
|
|||
/**
|
||||
* Classes for encryption on STU devices
|
||||
**/
|
||||
|
||||
function toHex(value, padding) {
|
||||
var hex = value.toString(16);
|
||||
return "0000000000000000".substr(0,padding-hex.length)+hex;
|
||||
}
|
||||
|
||||
function toHex2(value) { return toHex(value,2); }
|
||||
function toHex4(value) { return toHex(value,4); }
|
||||
function toHex8(value) { return toHex(value,8); }
|
||||
|
||||
function arrayToHex(v) {
|
||||
var s="";
|
||||
for (var i = 0; i < v.length; ++i)
|
||||
s = s + toHex2(v[i]);
|
||||
return s;
|
||||
}
|
||||
|
||||
function hexToArray(s) {
|
||||
var a = new Array();
|
||||
for (var i = 0; i < s.length;i+=2)
|
||||
a.push(parseInt("0x"+ s.substr(i,2),16));
|
||||
return a;
|
||||
}
|
||||
|
||||
function padLeft(str, len, pad) {
|
||||
if (typeof(pad) == "undefined") pad = ' ';
|
||||
str = str.toString();
|
||||
if (len > str.length)
|
||||
str = Array(len+1-str.length).join(pad) + str;
|
||||
return str;
|
||||
}
|
||||
|
||||
function base64UrlDecode(str) {
|
||||
str = atob(str.replace(/-/g, '+').replace(/_/g, '/'));
|
||||
var buffer = new Array(str.length);
|
||||
for(var i = 0; i < str.length; ++i) {
|
||||
buffer[i] = str.charCodeAt(i);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function arrayEquals(a, b) {
|
||||
return Array.isArray(a) &&
|
||||
Array.isArray(b) &&
|
||||
a.length === b.length &&
|
||||
a.every((val, index) => val === b[index]);
|
||||
}
|
||||
|
||||
function generateHexString(length) {
|
||||
var ret = "";
|
||||
while (ret.length < length) {
|
||||
ret += Math.random().toString(16).substring(2);
|
||||
}
|
||||
return ret.substring(0,length);
|
||||
}
|
||||
|
||||
function powMod(a, b, prime) {
|
||||
if (b <= BigInt(0)) {
|
||||
return (BigInt(1));
|
||||
} else if (b === BigInt(1)) {
|
||||
return a % prime;
|
||||
} else if (b % BigInt(2) === BigInt(0)) {
|
||||
return powMod((a * a) % prime, b / BigInt(2) | BigInt(0), prime) % prime;
|
||||
} else {
|
||||
return (powMod((a * a) % prime, b / BigInt(2) | BigInt(0), prime) * a) % prime;
|
||||
}
|
||||
}
|
||||
|
||||
class MyEncryptionHandler {
|
||||
|
||||
constructor() {
|
||||
this.clearKeys();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the encryption handler
|
||||
*/
|
||||
reset() {
|
||||
this.clearKeys();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all encryption key values
|
||||
*/
|
||||
clearKeys() {
|
||||
this.bigint_p = null;
|
||||
this.bigint_g = null;
|
||||
this.sjcl_keyAES = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if Diffie-Hellman key exchange is required
|
||||
* @return true if key exchange is required
|
||||
*/
|
||||
requireDH() {
|
||||
return this.bigint_p == null || this.bigint_g == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes parameters for Diffie-Hellman key exchange
|
||||
* @param dhPrime Diffie-Hellman prime number
|
||||
* @param dhBase Diffie-Hellman base number
|
||||
*/
|
||||
setDH(dhPrime, dhBase) {
|
||||
var p = dhPrime;
|
||||
var g = dhBase;
|
||||
|
||||
this.bigint_p = BigInt("0x"+arrayToHex(p));
|
||||
this.bigint_g = BigInt("0x"+arrayToHex(g));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a public key
|
||||
* @return 128-bit key, as array of bytes
|
||||
*/
|
||||
generateHostPublicKey() {
|
||||
// secret key
|
||||
let randomValues = new Uint8Array(64);
|
||||
window.crypto.getRandomValues(randomValues);
|
||||
this.bigint_a = BigInt("0x"+arrayToHex(randomValues));
|
||||
|
||||
// public key
|
||||
var bigint_A = powMod(this.bigint_g, this.bigint_a, this.bigint_p);
|
||||
|
||||
var hex_A = padLeft(bigint_A.toString(16), 32, '0');
|
||||
var A = hexToArray(hex_A);
|
||||
return A;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a shared key, given the tablet's public key
|
||||
* @param devicePublicKey the tablet's public key
|
||||
*/
|
||||
computeSharedKey(devicePublicKey) {
|
||||
var B = devicePublicKey;
|
||||
|
||||
var bigint_B = BigInt("0x"+arrayToHex(B));
|
||||
|
||||
var bigint_shared = powMod(bigint_B, this.bigint_a, this.bigint_p);
|
||||
|
||||
var str_shared = padLeft(bigint_shared.toString(16), 32, '0');
|
||||
|
||||
this.sjcl_keyAES = new sjcl.cipher.aes( sjcl.codec.hex.toBits(str_shared) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a block of encrypted data
|
||||
* @param data an array of bytes to decrypt
|
||||
* @return decrypted data
|
||||
*/
|
||||
decrypt(data) {
|
||||
var arr_cipherText = data;
|
||||
var hex_cipherText = arrayToHex(arr_cipherText);
|
||||
var sjcl_cipherText = sjcl.codec.hex.toBits(hex_cipherText);
|
||||
|
||||
var sjcl_plainText = this.sjcl_keyAES.decrypt(sjcl_cipherText);
|
||||
|
||||
var hex_plainText = sjcl.codec.hex.fromBits(sjcl_plainText);
|
||||
var arr_plainText = hexToArray(hex_plainText);
|
||||
return arr_plainText;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class MyEncryptionHandler2 {
|
||||
|
||||
constructor() {
|
||||
this.clearKeys();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the encryption handler
|
||||
*/
|
||||
reset() {
|
||||
this.clearKeys();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all encryption key values
|
||||
*/
|
||||
clearKeys() {
|
||||
this.privateKey = null;
|
||||
this.keyAES = null;
|
||||
this.exponent = null;
|
||||
this.modulus = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the symmetric key type
|
||||
* @return a Protocol.SymmetricKeyType value
|
||||
*/
|
||||
getSymmetricKeyType() {
|
||||
return com.WacomGSS.STU.Protocol.SymmetricKeyType.AES256;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the asymmetric padding type
|
||||
* @return a Protocol.AsymmetricPaddingType value
|
||||
*/
|
||||
getAsymmetricPaddingType() {
|
||||
return com.WacomGSS.STU.Protocol.AsymmetricPaddingType.OAEP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the asymmetric key type
|
||||
* @return a Protocol.AsymmetricKeyType value
|
||||
*/
|
||||
getAsymmetricKeyType() {
|
||||
return com.WacomGSS.STU.Protocol.AsymmetricKeyType.RSA2048;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the public key exponent
|
||||
* @return RSA public key exponent as a byte array
|
||||
*/
|
||||
async getPublicExponent() {
|
||||
const keyPair = await window.crypto.subtle.generateKey({
|
||||
name: "RSA-OAEP",
|
||||
modulusLength: 2048,
|
||||
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
|
||||
hash: {
|
||||
name: "SHA-1"
|
||||
},
|
||||
},
|
||||
true, //wheter the key is extractable or not
|
||||
["encrypt", "decrypt"]);
|
||||
|
||||
this.privateKey = keyPair.privateKey;
|
||||
const publicKey = await window.crypto.subtle.exportKey("jwk", keyPair.publicKey);
|
||||
|
||||
// base64url-decode modulus
|
||||
this.modulus = base64UrlDecode(publicKey.n);
|
||||
|
||||
// base64url-decode exponent
|
||||
this.exponent = base64UrlDecode(publicKey.e);
|
||||
|
||||
return this.exponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a public key
|
||||
* @return generated key as a byte array
|
||||
*/
|
||||
async generatePublicKey() {
|
||||
return this.modulus
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses private key and padding type to decrypt an encrypted AES (symmetric) key to use in
|
||||
* subsequent calls to #decrypt.
|
||||
* @param data Encrypted AES key
|
||||
*/
|
||||
async computeSessionKey(data) {
|
||||
const key = await window.crypto.subtle.decrypt({
|
||||
name: "RSA-OAEP"
|
||||
},
|
||||
this.privateKey,
|
||||
Uint8Array.from(data)
|
||||
);
|
||||
|
||||
// replace additional left zeros
|
||||
const decryptKey = BigInt("0x"+arrayToHex(new Uint8Array(key)));
|
||||
const hexKey = padLeft(decryptKey.toString(16), 64, '0');
|
||||
|
||||
// SubtleCrypto only supports AES-CBC with PKCS#7 padding.
|
||||
// so we need to use another library as STU devices uses no padding.
|
||||
this.keyAES = new sjcl.cipher.aes(sjcl.codec.hex.toBits(hexKey));
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a block of encrypted data
|
||||
* @param data an array of bytes to decrypt
|
||||
* @return decrypted data
|
||||
*/
|
||||
decrypt(data) {
|
||||
var hex_cipherText = arrayToHex(data);
|
||||
var sjcl_cipherText = sjcl.codec.hex.toBits(hex_cipherText);
|
||||
|
||||
var sjcl_plainText = this.keyAES.decrypt(sjcl_cipherText);
|
||||
|
||||
var hex_plainText = sjcl.codec.hex.fromBits(sjcl_plainText);
|
||||
var arr_plainText = hexToArray(hex_plainText);
|
||||
|
||||
return arr_plainText;
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
# js-ext ChangeLog
|
||||
|
||||
## 1.0.2
|
||||
|
||||
_2021-10-01_
|
||||
|
||||
### Updates
|
||||
- TypedArray extened with createSharedIntsance - instance with SharedArrayBuffer, various updates across TypedArray related with shared memory
|
||||
|
||||
## 1.0.1
|
||||
|
||||
_2021-06-01_
|
||||
|
||||
### Updates
|
||||
- Function Set, Location extension implemented
|
||||
- Number MAX_$Type constatnts implemented
|
||||
|
||||
## 1.0.0
|
||||
|
||||
_2020-07-01_
|
||||
|
||||
- First release
|
|
@ -1,7 +0,0 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,26 +0,0 @@
|
|||
# js-ext
|
||||
|
||||
## Description
|
||||
|
||||
The Javascript extension. Provides additional functionality to classes when they are available and when particular functionality is missing.
|
||||
|
||||
* Object
|
||||
* String
|
||||
* Number
|
||||
* Function
|
||||
* Array
|
||||
* ArrayBuffer
|
||||
* TypedArray
|
||||
* Set
|
||||
* Screen
|
||||
* Location
|
||||
* HTMLElement
|
||||
* HTMLImageElement
|
||||
* Image
|
||||
* Canvas (Adds support for OffscreenCanvas when is not available)
|
||||
* DOMPoint
|
||||
* DOMRect
|
||||
* DOMMatrix
|
||||
|
||||
Functionallity extensions through not existant classes:
|
||||
* DOMSize
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,16 +0,0 @@
|
|||
{
|
||||
"name": "js-ext",
|
||||
"productName": "JavaScript Extensions",
|
||||
"version": "1.0.2",
|
||||
"description": "Additional functionality provider",
|
||||
"main": "js-ext-min.cjs",
|
||||
"module": "js-ext-min.js",
|
||||
"unpkg": "js-ext-min.js",
|
||||
"repository": "https://github.com/js-ext.git",
|
||||
"author": "Tzvetelin Vassilev",
|
||||
"homepage": "https://github.com/js-ext",
|
||||
"bugs": {
|
||||
"url": "https://github.com/js-ext/issues"
|
||||
},
|
||||
"license": "ISC"
|
||||
}
|
|
@ -1,155 +0,0 @@
|
|||
# digital-ink ChangeLog
|
||||
|
||||
## 1.5.0 (3.0.7)
|
||||
|
||||
_2022-07-01_
|
||||
|
||||
### Updates
|
||||
- _BrushApplier_ optimizations - simplify transform - mat4 to mat2d
|
||||
- _RIFFEncoder_ and _RIFFDecoder_ LIST chunk support added
|
||||
- _InkBuilderSettings_ extended - keepAllData, keepSplineParameters options added
|
||||
- _InkPathProducer_ build method optional settings added, additional pipeline data could be achieved from the worker
|
||||
- _InkModel_ clear method implemented
|
||||
_ _SplineInterpolator_ is capable to process and SplineFragments as input
|
||||
- _InkBuilderAsync_ open / close methods added, open workers is a prerequisite for proper usage
|
||||
|
||||
### Breaking Changes
|
||||
- Long dependency update - ECMA 6 compatible version integrated
|
||||
- Manipulation module refactoring based on C# implementation
|
||||
- SpatialContext createInstance method is removed, clone method is provided
|
||||
- InkModel createCopyInstance method is removed, clone method is provided
|
||||
- ArrayPath / SharedPath primitives replaced from Path implementation
|
||||
- View name validation - for non valid names error is throwing
|
||||
- Interval type deprecated, SplineFragment replace it
|
||||
- _Stroke_ subStroke method is removed, because Interval dependency, slice replace it, based on SplineFragment
|
||||
|
||||
## 1.4.2 (3.0.6)
|
||||
|
||||
_2021-11-01_
|
||||
|
||||
### Updates
|
||||
- _ConvexHullChainProducerAsync_ worker _ConvexHullProvider_ as external resource
|
||||
- _Selector_ selection algorythm improvments
|
||||
- _InkModel_ version support added, reffers UIM version
|
||||
- _SplineParameter_ implementation and integration
|
||||
|
||||
## 1.4.1 (3.0.5)
|
||||
|
||||
_2021-10-01_
|
||||
|
||||
### Updates
|
||||
- _View_ tree property is deprecated, use root instead
|
||||
- _Stroke_ Stroke.onPipeline abstract static could be implemented to provide custom settings for pipeline
|
||||
- _Stroke_ target property is deprected, Target enum is obsolete, onPipeline should be implemented when specific behaiour is needed.
|
||||
- Pipeline refactoring, prediction control increased, POLYGON_SIMPLIFIER stage is deprecated, lastPipelineStage defaults to POLYGON_MERGER
|
||||
- _InkBuilderSettings_ concatSegments option added, mergePrediction is deprecated
|
||||
- ArrayPath / SharedPath primitives implemented
|
||||
- Polygon primitive implemented - shape and holes paths, vertices property provides access to triangulated geometry
|
||||
- InkPath2D refactored - list of polygons, vertices property provides access to triangulated geometry of all underlying polygons, representing the shape
|
||||
- Pipeline output update for some of stages - Polygon / InkPath2D
|
||||
|
||||
### Bugfixes
|
||||
- _Scalar_ refactoring, DIP fixed (pixel representation), DP and DPI included
|
||||
- _SensorChannel_ default resolution fix
|
||||
- _OffscreenCanvasGL_ height property fix
|
||||
|
||||
## 1.4.0 (3.0.4)
|
||||
|
||||
_2021-09-01_
|
||||
|
||||
### Breaking Changes
|
||||
- _StrokeRendererGL_ streamUpdatedArea is replaced with blendStroke2D for better integration between GL and 2D contexts
|
||||
- _InkCodec_ decodeInkModel is async
|
||||
|
||||
### Updates
|
||||
- _InputListener_ resize reason listeners added - for orientation, window resolution, screen resolution, InkController resize method argument reason provided, ResizeReason enum provided
|
||||
- _InputListener_ suppressKeys properly introduced, it configures ctrlKey, altKey, shiftKey and metaKey and by default if any of them is pressed ink is suppressed
|
||||
- _InputListener_ provides prediction to _InkController_ move method when is browser supported
|
||||
- _OffscreenLayer2D_ draws with alpha
|
||||
- _InkBuilderSettings_ excludedPipelineStages, lastPipelineStage option added
|
||||
- Stroke renderMode defaults to SOURCE_OVER, required
|
||||
- StrokeRenderers can batch strokes list, blendStrokes implemented
|
||||
- Brush2D shape frame based on 1 diameter provides thiner strokes generation
|
||||
- Selector functionallity bug-fixes
|
||||
- SpatialContext createInstance method provided - could be based on another context (RTree clone)
|
||||
- Ink data format update to v.3.1.0
|
||||
- InkOperation protocol is created
|
||||
- PrecisionDetection compression serialisation functionality introduced, InkCodec precisionCalculator optional property controlls it
|
||||
- TripleStore refactoring, extends Array
|
||||
|
||||
## 1.3.0 (3.0.3)
|
||||
|
||||
_2021-01-15_
|
||||
|
||||
### Breaking Changes
|
||||
- _InkBuilder_ configure method should be called only once before starting new path building
|
||||
- InkBuilderSettings onBuildComplete property is deprecated, InkBuilder onComplete property should be used instead
|
||||
|
||||
### Updates
|
||||
- _InputListener_ - affects ink input when surface transform is available
|
||||
- _Stroke_ style support implemented
|
||||
- _Color_ - hex property provides color as hex
|
||||
- _Matrix_
|
||||
- properties setters impl
|
||||
- is2D property impl
|
||||
- matrix3d support added
|
||||
- fromPoints static method impl
|
||||
- distribution file name updated
|
||||
- PipelineStage enum available
|
||||
- InkBuilderSettings updated, pipeline options added:
|
||||
- lastPipelineStep - controls where pipeline to complete
|
||||
- excludedPipelineStages - excludes stages from pipeline
|
||||
|
||||
### Bugfixes
|
||||
- _InputDevice_ - fix senosor input validation when pointer is not available
|
||||
- loading BrushGL assets in Safari
|
||||
|
||||
## 1.2.0 (3.0.2)
|
||||
|
||||
_2020-09-01_
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- _InkController_ - interface is updated, registerTouches(changedTouches) method is replaced with registerInputProvider(pointerID, isPrimary), getInkBuilder(changedTouches) with getInkBuilder(pointerID), implementation update is required
|
||||
- _InkBuilderAbstract_ - property touchID is renamed to pointerID
|
||||
|
||||
### Updates
|
||||
|
||||
- _InputListener_ - based on PointerEvent only, fallback class is provided when PointerEvent is not available which implementation is based on MouseEvent and TouchEvent
|
||||
- _SensorPoint_ - PointerEvent based InputListener extends SensorPoint with coalesced and predicted points, when available
|
||||
- _Matrix_ - provides access to additional properties like scaleX, translateX, etc.
|
||||
- _InkPath2D_ - 2D ink path type implemented and integrated
|
||||
- Layer and StrokeRender implementations extended with setTransform method
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- _PathPoint_ - transform properly applied rotation when available
|
||||
|
||||
## 1.1.0 (3.0.1)
|
||||
|
||||
_2020-08-11_
|
||||
|
||||
### Updates
|
||||
|
||||
- _Spline_ - transfrom functionallity provided
|
||||
- _Stroke_ - transform functionality updated - transform underlying spline and path if available
|
||||
- _Intersector_ - intersect2 method renamed to intersectSegmentation, doc update
|
||||
- _InkContext_ - drawSprite is replaced from drawSpritesBatch (batching points sprites)
|
||||
- _InputDevice_ - decouple sensor point building from ink builder, InputDevice handles building, validation and provides sensor layout as string array
|
||||
- _InkCanvas2D_ - context attributes support (Layers inherits canvas attributes)
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- _InkModel_ - provide proper strokes order after manipulations
|
||||
- _StrokeDrawContext_ - randomSeed fix (int number instead long)
|
||||
- _StrokeRendererGL_ - renderer configuration color update, overrides path color
|
||||
- _InkGLContext_ - blend mode MIN fixed, blendMode as property instead method
|
||||
- _Matrix_ - fromMatrix method do not recreates Matrix when data is Matrix instance
|
||||
- _PathPointContext_ - improved attributes values analyse, added suppot for tocuh devices with radius range (0, 1)
|
||||
- _CurvatureBasedInterpolator_ - rotation bug-fix, ts and tf aplyed
|
||||
|
||||
## 1.0.0 (3.0.0)
|
||||
|
||||
_2020-07-01_
|
||||
|
||||
- First release
|
|
@ -1,9 +0,0 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2020 Wacom Co LTD (https://www.wacom.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,140 +0,0 @@
|
|||
# WILL SDK for ink
|
||||
|
||||
**Wacom Ink Layer Language (WILL™)** is a cross-platform digital ink technology.
|
||||
It is based on the needs of the end-user and Wacom's experience with different domains.
|
||||
WILL allows you to include premium digital inking features in your applications.
|
||||
It uses a modularized pipeline allowing each module to be configured, replaced, or omitted as required by the specific application, providing you with superior flexibility.
|
||||
|
||||
The newly introduced **Universal Ink Model** is a data model describing ink related data structures and meta-data concept to describe the semantic content of ink.
|
||||
You can also use the file encoding of the Universal Ink Model to exchange ink content between applications and cross-platform.
|
||||
|
||||
The WILL 3 Framework includes:
|
||||
|
||||
* Software libraries for multiple platforms (Windows, Android, iOS, Web)
|
||||
* Code samples illustrating particular functionality
|
||||
* A web-based **Ink Designer** to configure and test the pipeline
|
||||
* Comprehensive documentation, including step-by-step guides
|
||||
|
||||
## Design Concepts
|
||||
The following is an introduction to the Design Concepts for our WILL technology.
|
||||
|
||||
## Interoperability
|
||||
WILL 3.0 technology and its **Universal Ink Model** is platform and device agnostic, thus the specification does not focus on specific hardware platforms.
|
||||
Ink Markup Language **[InkML]** and Ink Serialized Format **[ISF]** are the most well-known formats for storing digital ink besides Wacom Ink Layer Language **[WILL]**.
|
||||
The previous version of WILL did not support the storage of sensor data samples for digital ink (e.g., timestamps, (x,y)-coordinates, or pressure values).
|
||||
WILL 3.0 gives the ability to store ink sensor samples along with the visual representation of digital ink as well as semantic metadata.
|
||||
As a result it is now possible to make a loss-less conversion of the Universal Ink Data format to other existing formats.
|
||||
|
||||
|
||||
### Natural
|
||||
Digital ink has to look natural and similar to real ink.
|
||||
To ensure that the visual appearance of the digital ink can be shared across platforms, WILL 3.0 contains all relevant data to present ink in a consistent way across all platforms.
|
||||
By using WILL particle ink rasterization, natural brushes can be configured to create artwork, as illustrated in *Figure 1*.
|
||||
|
||||
![Artwork created with raster / particle ink.](media/overview_artwork.png)
|
||||
|
||||
*Figure 1: Artwork created with raster / particle ink.*
|
||||
|
||||
### Active
|
||||
Mobile apps, Cloud application, or Cloud services have become a part of modern IT infrastructures.
|
||||
Thus, modern data formats need to address issues including:
|
||||
|
||||
* Unique identifiable IDs for devices
|
||||
* Streaming capability for partial updates of ink data
|
||||
* Document size reduction
|
||||
* Support for commonly used Web Standards such as JSON
|
||||
|
||||
![Active.](media/overview_active.png)
|
||||
|
||||
*Figure 2: Active Ink.*
|
||||
|
||||
### Meta Data and Semantics
|
||||
There are three types of metadata:
|
||||
|
||||
- Descriptive
|
||||
- Structural
|
||||
- Administrative
|
||||
|
||||
*Descriptive metadata* are typically used for discovery and identification, as information used to search and locate an object such as title, author, subject, keyword, and publisher.
|
||||
WILL offers metadata for the description of Document and Author in the ink document.
|
||||
|
||||
*Structural metadata* give a description of how the components of an object are organised.
|
||||
The metadata for ink can be used to describe the structure of ink documents.
|
||||
|
||||
Finally, *administrative metadata* give information to help manage the source.
|
||||
They refer to the technical information including file type or when and how the file was created.
|
||||
Two sub-types of administrative metadata are *rights management metadata* and *preservation metadata*.
|
||||
Rights management metadata explain intellectual property rights, while preservation metadata contain information that is needed to preserve and save a resource.
|
||||
|
||||
*Semantic metadata* is slowly becoming the differentiator in the vocabulary of many vendors.
|
||||
Semantics is the study of meaning.
|
||||
As it applies to technology and unstructured content, it represents the ability to extract meaning from words, phrases, sentences, and larger units of text that provide the context within content, and is manually applied or automatically generated as semantic metadata to describe the object.
|
||||
Semantic metadata is typically leveraged to improve search, but any application that uses metadata can achieve significant benefits through the generation or application of semantic metadata.
|
||||
Thus, WILL metadata is based on established metadata for document and author descriptions and defines its own semantic metadata for ink.
|
||||
|
||||
### Sensor Data and Biometrics
|
||||
Another important objective in the design of the Universal Ink Model is to support the capture of sensor data from ink devices.
|
||||
For example, sensor data is used in the context of handwriting analysis, as well as signature capture and verification.
|
||||
|
||||
Some ink devices provide additional information *(see Figure 3)* that in most use cases is considered less important and may not be supported by all makes or types of devices.
|
||||
This includes:
|
||||
|
||||
* **Pressure** - the force applied to the nib of the pen
|
||||
* **Inclination** - the angle between the pen barrel and vertical
|
||||
* **Orientation** - the plain-direction of the pen from the nib
|
||||
* **Rotation** - the rotation of the barrel during signing
|
||||
|
||||
![Overview ink sensor channels.](media/overview_ink_device_sensor_channels.png)
|
||||
|
||||
*Figure 3: Overview ink sensor channels.*
|
||||
|
||||
The forensic character of the data is of paramount importance, and means that the data-collection philosophy differs in many respects from competing signature technologies.
|
||||
A key principle is that during the collection of the signature, the software stores the data exactly as it is supplied by the device.
|
||||
Each type of data (e.g. position, time, pressure, etc.) is collected with metric information which describes the units being used by the device, and this is stored with the raw point data to allow the conversion to true units when required.
|
||||
The advantage of this is that the accuracy of the information is determined by the device and cannot be compromised by the conversion process.
|
||||
In addition to the pen-data, contextual data is collected and stored with the signature.
|
||||
This includes:
|
||||
|
||||
* The name of the signatory
|
||||
* The date and time at which the signature was given
|
||||
* The reason for signing
|
||||
* The make and type of digitizer being used
|
||||
* The type and version of the digitizer driver being used
|
||||
* The type and version of the operating system of the client PC being used
|
||||
* The Network Interface Card address of the PC
|
||||
|
||||
The objective is to store sensor data and the characteristics of the ink device alongside the visual representation of the digital ink.
|
||||
|
||||
## Technology
|
||||
The WILL technology is designed to be a platform-independent inking engine, providing the most relevant capabilities:
|
||||
|
||||
- **Ink Geometry Pipeline and Rendering** - Converts sensor data from an input device into a geometry which is rendered by a platform-specific rendering engine
|
||||
- **Ink Serialization** - Exchanges the rendering results, the collected sensor data, and relevant metadata; the Universal Ink Format is used to serialize and de-serialize the information
|
||||
- **Ink Manipulation** - Manipulates the generated geometry; the ink manipulation operations will be able to scale, move, rotate, and erase ink strokes (including exact split)
|
||||
|
||||
|
||||
---
|
||||
|
||||
# Additional resources
|
||||
|
||||
## Sample Code
|
||||
For further samples check Wacom's Developer additional samples, see [https://github.com/Wacom-Developer](https://github.com/Wacom-Developer)
|
||||
|
||||
## Documentation
|
||||
For further details on using the SDK see [WILL SDK for ink documentation](http://developer-docs.wacom.com/sdk-for-ink/)
|
||||
|
||||
The API Reference is available directly in the downloaded SDK.
|
||||
|
||||
## Support
|
||||
If you experience issues with the technology components, please see related [FAQs](http://developer-docs.wacom.com/faqs)
|
||||
|
||||
For further support file a ticket in our **Developer Support Portal** described here: [Request Support](http://developer-docs.wacom.com/faqs/docs/q-support/support)
|
||||
|
||||
## Developer Community
|
||||
Join our developer community:
|
||||
|
||||
- [LinkedIn - Wacom for Developers](https://www.linkedin.com/company/wacom-for-developers/)
|
||||
- [Twitter - Wacom for Developers](https://twitter.com/Wacomdevelopers)
|
||||
|
||||
## License
|
||||
This sample code is licensed under the [MIT License](https://choosealicense.com/licenses/mit/)
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,64 +0,0 @@
|
|||
{
|
||||
"name": "digital-ink",
|
||||
"version": "1.5.0",
|
||||
"productName": "WILL SDK for ink",
|
||||
"productVersion": "3.0.5",
|
||||
"description": "WILL™ SDK for ink supports a variety of input technologies and generates the highest quality, most attractive digital ink outputs via these modules: Path generation and smoothing, Rasterizer, Manipulation and Serialization",
|
||||
"main": "digital-ink-min.cjs",
|
||||
"module": "./digital-ink-min.js",
|
||||
"exports": {
|
||||
".": {
|
||||
"node": {
|
||||
"import": "./digital-ink-min.cjs.mjs",
|
||||
"require": "./digital-ink-min.cjs"
|
||||
},
|
||||
"browser": {
|
||||
"import": "./digital-ink-min.mjs"
|
||||
},
|
||||
"default": "./digital-ink-min.js"
|
||||
},
|
||||
"./web-integrator": {
|
||||
"node": {
|
||||
"import": "./web-integrator/web-integrator.mjs",
|
||||
"require": "./web-integrator/web-integrator.cjs"
|
||||
},
|
||||
"default": "./web-integrator/web-integrator.js"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"canvas": "^2.9.1",
|
||||
"clipper-lib": "^6.4.2",
|
||||
"gl": "^5.0.0",
|
||||
"gl-matrix": "^3.4.3",
|
||||
"js-ext": "../../wacom/js-ext",
|
||||
"js-md5": "^0.7.3",
|
||||
"jszip": "^3.9.1",
|
||||
"long": "^5.2.0",
|
||||
"poly2tri": "^1.5.0",
|
||||
"protobufjs": "^6.11.2",
|
||||
"rbush": "^3.0.1",
|
||||
"systeminformation": "^5.11.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"files": [
|
||||
"*.*",
|
||||
"web-integrator/**",
|
||||
"workers/**"
|
||||
],
|
||||
"keywords": [
|
||||
"wacom",
|
||||
"ink",
|
||||
"canvas",
|
||||
"rasterization",
|
||||
"universal-ink-model"
|
||||
],
|
||||
"repository": "https://github.com/orgs/Wacom-Developer",
|
||||
"author": "Wacom Co., Ltd",
|
||||
"homepage": "https://developer.wacom.com",
|
||||
"bugs": {
|
||||
"url": "https://developer.wacom.com/developer-dashboard/support"
|
||||
},
|
||||
"license": "Wacom INK SDK Evaluation Agreement"
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
"use strict";class e{static DEPENDENCIES_SRC="/node_modules";get dependenciesESM(){return{quickselect:`${this.src}/quickselect/index.js`,rbush:`${this.src}/rbush/index.js`,long:`${this.src}/long/index.js`,"gl-matrix":`${this.src}/gl-matrix/esm/index.js`,"js-ext":`${this.src}/js-ext/js-ext-min.mjs`,"digital-ink":`${this.src}/digital-ink/digital-ink-min.mjs`}}get devDependenciesESM(){return Object.assign({},this.dependenciesESM,{"js-ext":`${this.src}/js-ext/js-ext.mjs`,"digital-ink":`${this.src}/digital-ink/digital-ink.mjs`})}get dependenciesUMD(){return{"clipper-lib":`${this.src}/clipper-lib/clipper.js`,poly2tri:`${this.src}/poly2tri/dist/poly2tri.min.js`,protobufjs:`${this.src}/protobufjs/dist/protobuf.min.js`,"js-md5":`${this.src}/js-md5/build/md5.min.js`,jszip:`${this.src}/jszip/dist/jszip.min.js`,rbush:`${this.src}/rbush/rbush.js`,long:`${this.src}/long/umd/index.js`,"gl-matrix":`${this.src}/gl-matrix/gl-matrix.js`,"js-ext":`${this.src}/js-ext/js-ext-min.js`,"digital-ink":`${this.src}/digital-ink/digital-ink-min.js`}}get devDependenciesUMD(){return Object.assign({},this.dependenciesUMD,{poly2tri:`${this.src}/poly2tri/dist/poly2tri.js`,protobufjs:`${this.src}/protobufjs/dist/protobuf.js`,"js-md5":`${this.src}/js-md5/src/md5.js`,jszip:`${this.src}/jszip/dist/jszip.js`,"js-ext":`${this.src}/js-ext/js-ext.js`,"digital-ink":`${this.src}/digital-ink/digital-ink.js`})}constructor(t=!0,i=""){this.cdn=t||"function"==typeof DedicatedWorkerGlobalScope,this.src=i+e.DEPENDENCIES_SRC}build(){return this.dependencies||(e.dev?this.cdn?this.dependencies=Object.assign({},this.devDependenciesUMD):this.dependencies=Object.assign({},this.devDependenciesUMD,this.devDependenciesESM):this.cdn?this.dependencies=Object.assign({},this.dependenciesUMD):this.dependencies=Object.assign({},this.dependenciesUMD,this.dependenciesESM)),this.dependencies}include(e={}){this.dependencies=Object.assign(this.build(),e)}integrate(){if(this.build(),this.cdn)if("function"==typeof DedicatedWorkerGlobalScope)Object.values(this.dependencies).forEach((e=>self.importScripts(e)));else{if("undefined"==typeof document)throw new Error("Integration failed. Supported env is browser - main or worker thread!");Object.values(this.dependencies).forEach((e=>document.write(`<script type="text/javascript" src="${e}"><\/script>`)))}else{if("undefined"==typeof document)throw new Error("Integration failed. Supported env is browser - main thread!");{let e={imports:this.dependencies},t=document.createElement("script");t.setAttribute("type","importmap"),t.textContent=JSON.stringify(e,0,4),document.currentScript?document.currentScript.after(t):document.head.appendChild(t)}}}static linkWorkers(...e){for(let t of e){let e=t.buildWorkerURL().split(location.host).last,i=document.createElement("link");i.setAttribute("rel","modulepreload"),i.setAttribute("href",e),document.head.appendChild(i)}}static integrate(t){new e(!0,t).integrate()}static integrateECMA6(t,i){let s=new e(!1,i);s.include(t),s.integrate()}static getCDNImports(t){return new e(!0,t).build()}}module.exports=e;
|
|
@ -1 +0,0 @@
|
|||
var DigitalInkWebIntegrator=function(){"use strict";function e(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function t(e,t){for(var i=0;i<t.length;i++){var n=t[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}var i,n,s,c=function(){function i(){var t=!(arguments.length>0&&void 0!==arguments[0])||arguments[0],n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";e(this,i),this.cdn=t||"function"==typeof DedicatedWorkerGlobalScope,this.src=n+i.DEPENDENCIES_SRC}var n,s,c;return n=i,s=[{key:"dependenciesESM",get:function(){return{quickselect:"".concat(this.src,"/quickselect/index.js"),rbush:"".concat(this.src,"/rbush/index.js"),long:"".concat(this.src,"/long/index.js"),"gl-matrix":"".concat(this.src,"/gl-matrix/esm/index.js"),"js-ext":"".concat(this.src,"/js-ext/js-ext-min.mjs"),"digital-ink":"".concat(this.src,"/digital-ink/digital-ink-min.mjs")}}},{key:"devDependenciesESM",get:function(){return Object.assign({},this.dependenciesESM,{"js-ext":"".concat(this.src,"/js-ext/js-ext.mjs"),"digital-ink":"".concat(this.src,"/digital-ink/digital-ink.mjs")})}},{key:"dependenciesUMD",get:function(){return{"clipper-lib":"".concat(this.src,"/clipper-lib/clipper.js"),poly2tri:"".concat(this.src,"/poly2tri/dist/poly2tri.min.js"),protobufjs:"".concat(this.src,"/protobufjs/dist/protobuf.min.js"),"js-md5":"".concat(this.src,"/js-md5/build/md5.min.js"),jszip:"".concat(this.src,"/jszip/dist/jszip.min.js"),rbush:"".concat(this.src,"/rbush/rbush.js"),long:"".concat(this.src,"/long/umd/index.js"),"gl-matrix":"".concat(this.src,"/gl-matrix/gl-matrix.js"),"js-ext":"".concat(this.src,"/js-ext/js-ext-min.js"),"digital-ink":"".concat(this.src,"/digital-ink/digital-ink-min.js")}}},{key:"devDependenciesUMD",get:function(){return Object.assign({},this.dependenciesUMD,{poly2tri:"".concat(this.src,"/poly2tri/dist/poly2tri.js"),protobufjs:"".concat(this.src,"/protobufjs/dist/protobuf.js"),"js-md5":"".concat(this.src,"/js-md5/src/md5.js"),jszip:"".concat(this.src,"/jszip/dist/jszip.js"),"js-ext":"".concat(this.src,"/js-ext/js-ext.js"),"digital-ink":"".concat(this.src,"/digital-ink/digital-ink.js")})}},{key:"build",value:function(){return this.dependencies||(i.dev?this.cdn?this.dependencies=Object.assign({},this.devDependenciesUMD):this.dependencies=Object.assign({},this.devDependenciesUMD,this.devDependenciesESM):this.cdn?this.dependencies=Object.assign({},this.dependenciesUMD):this.dependencies=Object.assign({},this.dependenciesUMD,this.dependenciesESM)),this.dependencies}},{key:"include",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this.dependencies=Object.assign(this.build(),e)}},{key:"integrate",value:function(){if(this.build(),this.cdn)if("function"==typeof DedicatedWorkerGlobalScope)Object.values(this.dependencies).forEach((function(e){return self.importScripts(e)}));else{if("undefined"==typeof document)throw new Error("Integration failed. Supported env is browser - main or worker thread!");Object.values(this.dependencies).forEach((function(e){return document.write('<script type="text/javascript" src="'.concat(e,'"><\/script>'))}))}else{if("undefined"==typeof document)throw new Error("Integration failed. Supported env is browser - main thread!");var e={imports:this.dependencies},t=document.createElement("script");t.setAttribute("type","importmap"),t.textContent=JSON.stringify(e,0,4),document.currentScript?document.currentScript.after(t):document.head.appendChild(t)}}}],c=[{key:"linkWorkers",value:function(){for(var e=arguments.length,t=new Array(e),i=0;i<e;i++)t[i]=arguments[i];for(var n=0,s=t;n<s.length;n++){var c=s[n],r=c.buildWorkerURL().split(location.host).last,o=document.createElement("link");o.setAttribute("rel","modulepreload"),o.setAttribute("href",r),document.head.appendChild(o)}}},{key:"integrate",value:function(e){new i(!0,e).integrate()}},{key:"integrateECMA6",value:function(e,t){var n=new i(!1,t);n.include(e),n.integrate()}},{key:"getCDNImports",value:function(e){return new i(!0,e).build()}}],s&&t(n.prototype,s),c&&t(n,c),Object.defineProperty(n,"prototype",{writable:!1}),i}();return s="/node_modules",(n="DEPENDENCIES_SRC")in(i=c)?Object.defineProperty(i,n,{value:s,enumerable:!0,configurable:!0,writable:!0}):i[n]=s,c}();
|
|
@ -1 +0,0 @@
|
|||
class e{static DEPENDENCIES_SRC="/node_modules";get dependenciesESM(){return{quickselect:`${this.src}/quickselect/index.js`,rbush:`${this.src}/rbush/index.js`,long:`${this.src}/long/index.js`,"gl-matrix":`${this.src}/gl-matrix/esm/index.js`,"js-ext":`${this.src}/js-ext/js-ext-min.mjs`,"digital-ink":`${this.src}/digital-ink/digital-ink-min.mjs`}}get devDependenciesESM(){return Object.assign({},this.dependenciesESM,{"js-ext":`${this.src}/js-ext/js-ext.mjs`,"digital-ink":`${this.src}/digital-ink/digital-ink.mjs`})}get dependenciesUMD(){return{"clipper-lib":`${this.src}/clipper-lib/clipper.js`,poly2tri:`${this.src}/poly2tri/dist/poly2tri.min.js`,protobufjs:`${this.src}/protobufjs/dist/protobuf.min.js`,"js-md5":`${this.src}/js-md5/build/md5.min.js`,jszip:`${this.src}/jszip/dist/jszip.min.js`,rbush:`${this.src}/rbush/rbush.js`,long:`${this.src}/long/umd/index.js`,"gl-matrix":`${this.src}/gl-matrix/gl-matrix.js`,"js-ext":`${this.src}/js-ext/js-ext-min.js`,"digital-ink":`${this.src}/digital-ink/digital-ink-min.js`}}get devDependenciesUMD(){return Object.assign({},this.dependenciesUMD,{poly2tri:`${this.src}/poly2tri/dist/poly2tri.js`,protobufjs:`${this.src}/protobufjs/dist/protobuf.js`,"js-md5":`${this.src}/js-md5/src/md5.js`,jszip:`${this.src}/jszip/dist/jszip.js`,"js-ext":`${this.src}/js-ext/js-ext.js`,"digital-ink":`${this.src}/digital-ink/digital-ink.js`})}constructor(t=!0,i=""){this.cdn=t||"function"==typeof DedicatedWorkerGlobalScope,this.src=i+e.DEPENDENCIES_SRC}build(){return this.dependencies||(e.dev?this.cdn?this.dependencies=Object.assign({},this.devDependenciesUMD):this.dependencies=Object.assign({},this.devDependenciesUMD,this.devDependenciesESM):this.cdn?this.dependencies=Object.assign({},this.dependenciesUMD):this.dependencies=Object.assign({},this.dependenciesUMD,this.dependenciesESM)),this.dependencies}include(e={}){this.dependencies=Object.assign(this.build(),e)}integrate(){if(this.build(),this.cdn)if("function"==typeof DedicatedWorkerGlobalScope)Object.values(this.dependencies).forEach((e=>self.importScripts(e)));else{if("undefined"==typeof document)throw new Error("Integration failed. Supported env is browser - main or worker thread!");Object.values(this.dependencies).forEach((e=>document.write(`<script type="text/javascript" src="${e}"><\/script>`)))}else{if("undefined"==typeof document)throw new Error("Integration failed. Supported env is browser - main thread!");{let e={imports:this.dependencies},t=document.createElement("script");t.setAttribute("type","importmap"),t.textContent=JSON.stringify(e,0,4),document.currentScript?document.currentScript.after(t):document.head.appendChild(t)}}}static linkWorkers(...e){for(let t of e){let e=t.buildWorkerURL().split(location.host).last,i=document.createElement("link");i.setAttribute("rel","modulepreload"),i.setAttribute("href",e),document.head.appendChild(i)}}static integrate(t){new e(!0,t).integrate()}static integrateECMA6(t,i){let s=new e(!1,i);s.include(t),s.integrate()}static getCDNImports(t){return new e(!0,t).build()}}export{e as default};
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
|
@ -17,10 +17,14 @@ class StuCaptDialog {
|
|||
this.config.sizeMode = "stu";
|
||||
}
|
||||
|
||||
|
||||
this.config.strokeColor = config.strokeColor ?? "#0202FE";
|
||||
this.config.strokeSize = config.strokeSize ?? 6;
|
||||
this.config.showWait = config.showWait ?? true;
|
||||
this.config.stuDevice = config.stuDevice;
|
||||
|
||||
} else {
|
||||
this.config = {showWait:true, sizeMode:"stu"};
|
||||
this.config = {showWait:true, sizeMode:"stu", strokeColor:"#0202FE", strokeSize:6 };
|
||||
}
|
||||
|
||||
this.mPenData = Array();
|
||||
|
@ -36,40 +40,14 @@ class StuCaptDialog {
|
|||
* @param {string} - Reason for signing.
|
||||
* @param {IntegrityType} - Hash method to maintain the signature integrity. None by default.
|
||||
* @param {Hash} - Hash of an attached document. None by default.
|
||||
* @param {string} - osInfo, string indicating the OS.
|
||||
* @param {string} - nicInfo.
|
||||
**/
|
||||
async open(sigObj, who, why, extraData, integrityType, documentHash) {
|
||||
this.sigObj = sigObj;
|
||||
|
||||
if (who) {
|
||||
this.who = who;
|
||||
} else {
|
||||
this.who = 'Customer';
|
||||
}
|
||||
|
||||
if (why) {
|
||||
this.why = why;
|
||||
} else {
|
||||
this.why = 'Confirmed';
|
||||
}
|
||||
|
||||
this.extraData = extraData;
|
||||
|
||||
if (integrityType) {
|
||||
this.integrityType = integrityType;
|
||||
} else {
|
||||
this.integrityType = Module.KeyType.None;
|
||||
}
|
||||
|
||||
if (documentHash) {
|
||||
this.documentHash = documentHash;
|
||||
} else {
|
||||
this.documentHash = new Module.Hash(Module.HashType.None);
|
||||
}
|
||||
|
||||
if (!this.currentDevice) {
|
||||
async open(sigObj, who, why, where, extraData, integrityType, documentHash, osInfo, nicInfo) {
|
||||
if (!this.config.stuDevice) {
|
||||
let devices = await com.WacomGSS.STU.UsbDevice.requestDevices();
|
||||
if (devices.length > 0) {
|
||||
this.currentDevice = devices[0];
|
||||
this.config.stuDevice = devices[0];
|
||||
} else {
|
||||
throw "No STU devices found";
|
||||
}
|
||||
|
@ -87,7 +65,11 @@ class StuCaptDialog {
|
|||
}
|
||||
}
|
||||
|
||||
await this.mTablet.usbConnect(this.currentDevice);
|
||||
try {
|
||||
await this.mTablet.usbConnect(this.config.stuDevice);
|
||||
} catch (e) {
|
||||
alert("STU Device not found");
|
||||
}
|
||||
this.mCapability = await this.mTablet.getCapability();
|
||||
this.mInformation = await this.mTablet.getInformation();
|
||||
this.mInkThreshold = await this.mTablet.getInkThreshold();
|
||||
|
@ -156,20 +138,18 @@ class StuCaptDialog {
|
|||
//this.config.borderColor = "#cccccc";
|
||||
this.config.source = {mouse:false, touch:false, pen:false, stu:true},
|
||||
this.sigCaptDialog = new SigCaptDialog(this.config);
|
||||
this.config.will = this.sigCaptDialog.config.will;
|
||||
this.sigCaptDialog.getCaptureData = this.getCaptureData.bind(this);
|
||||
this.sigCaptDialog.addEventListener("clear", this.onClearBtn.bind(this));
|
||||
this.sigCaptDialog.addEventListener("cancel", this.onCancelBtn.bind(this));
|
||||
this.sigCaptDialog.addEventListener("ok", this.onOkBtn.bind(this));
|
||||
|
||||
await this.sigCaptDialog.open(this.sigObj, this.who, this.why, this.extraData, this.integrityType, this.documentHash);
|
||||
await this.sigCaptDialog.open(sigObj, who, why, where, extraData, integrityType, documentHash, osInfo, "", nicInfo);
|
||||
|
||||
//store the background image in order to be reuse it when clear the screen
|
||||
//store the background image in order for it to be reused when the screen is cleared
|
||||
let canvas = await this.drawImageToCanvas(this.sigCaptDialog.createScreenImage(useColor));
|
||||
let ctx = canvas.getContext("2d");
|
||||
this.mDeviceBackgroundImage = com.WacomGSS.STU.Protocol.ProtocolHelper.resizeAndFlatten(canvas, 0, 0, canvasWidth, canvasHeight,
|
||||
this.mCapability.screenWidth, this.mCapability.screenHeight, this.mEncodingMode, com.WacomGSS.STU.Protocol.ProtocolHelper.Scale.Stretch, "white", false, false);
|
||||
// Initialize the screen
|
||||
await this.clearScreen();
|
||||
|
||||
if (this.config.encryption) {
|
||||
if ((this.mTablet.isSupported(com.WacomGSS.STU.Protocol.ReportId.EncryptionStatus)) ||
|
||||
|
@ -183,14 +163,22 @@ class StuCaptDialog {
|
|||
if (useColor) {
|
||||
let htc = await this.mTablet.getHandwritingThicknessColor();
|
||||
|
||||
let components = this.hexToRgb(this.config.will.color);
|
||||
let components = this.hexToRgb(this.config.strokeColor);
|
||||
htc.penColor = this.rgb3216(components.r, components.g, components.b);
|
||||
htc.penThickness = this.config.strokeSize;
|
||||
await this.mTablet.setHandwritingThicknessColor(htc);
|
||||
}
|
||||
|
||||
const reportCountLengths = this.mTablet.getReportCountLengths();
|
||||
if (reportCountLengths[com.WacomGSS.STU.Protocol.ReportId.RenderingMode_$LI$()] !== undefined) {
|
||||
await this.mTablet.setRenderingMode(com.WacomGSS.STU.Protocol.RenderingMode.WILL);
|
||||
}
|
||||
|
||||
// Enable the pen data on the screen (if not already)
|
||||
await this.mTablet.setInkingMode(com.WacomGSS.STU.Protocol.InkingMode.On);
|
||||
|
||||
// Initialize the screen
|
||||
await this.clearScreen();
|
||||
}
|
||||
|
||||
rgb3216(r, g, b) {
|
||||
|
@ -261,6 +249,7 @@ class StuCaptDialog {
|
|||
|
||||
async clearScreen() {
|
||||
this.sigCaptDialog.stopCapture();
|
||||
await this.mTablet.setClearScreen();
|
||||
|
||||
if ((this.config.showWait) &&
|
||||
(this.mTablet.isSupported(com.WacomGSS.STU.Protocol.ReportId.StartImageDataArea_$LI$()))) {
|
||||
|
@ -321,7 +310,6 @@ class StuCaptDialog {
|
|||
}
|
||||
|
||||
async onOkBtn() {
|
||||
await this.getCaptureData();
|
||||
await this.disconnect();
|
||||
this.onOkListeners.forEach(listener => listener());
|
||||
}
|
||||
|
@ -363,24 +351,22 @@ class StuCaptDialog {
|
|||
// transition to down we save the button pressed
|
||||
this.mBtnIndex = btnIndex;
|
||||
if (this.mBtnIndex == -1) {
|
||||
// We have put the pen down outside a buttom.
|
||||
// We have put the pen down outside a button.
|
||||
// Treat it as part of the signature.
|
||||
this.mPenData.push(penData);
|
||||
|
||||
var downEvent = new PointerEvent("pointerdown", {
|
||||
pointerId: 1,
|
||||
pointerType: "pen",
|
||||
pointerType: "stu",
|
||||
isPrimary: true,
|
||||
clientX: pt.x,
|
||||
clientY: pt.y,
|
||||
pressure: penData.pressure/this.mCapability.tabletMaxPressure
|
||||
pressure: penData.pressure/this.mCapability.tabletMaxPressure,
|
||||
buttons: 1
|
||||
});
|
||||
|
||||
const point = window.DigitalInk.InkBuilder.createPoint(downEvent);
|
||||
point.timestamp = penData.timeCount;
|
||||
this.sigCaptDialog.draw("begin", point);
|
||||
this.sigCaptDialog.stopTimeOut();
|
||||
this.startDown = Date.now();
|
||||
//downEvent.timeStamp = penData.timeCount;
|
||||
this.sigCaptDialog.onDown(downEvent);
|
||||
}
|
||||
} else {
|
||||
// hover point
|
||||
|
@ -397,36 +383,36 @@ class StuCaptDialog {
|
|||
} else {
|
||||
var upEvent = new PointerEvent("pointerup", {
|
||||
pointerId: 1,
|
||||
pointerType: "pen",
|
||||
isPrimary: true,
|
||||
clientX: pt.x,
|
||||
clientY: pt.y,
|
||||
pressure: penData.pressure/this.mCapability.tabletMaxPressure
|
||||
});
|
||||
|
||||
const point = window.DigitalInk.InkBuilder.createPoint(upEvent);
|
||||
point.timestamp = penData.timeCount;
|
||||
this.sigCaptDialog.draw("end", point);
|
||||
this.mPenData.push(penData);
|
||||
this.sigCaptDialog.startTimeOut();
|
||||
this.sigCaptDialog.addTimeOnSurface(Date.now() - this.startDown);
|
||||
}
|
||||
} else {
|
||||
// continue inking
|
||||
var moveEvent = new PointerEvent("pointermove", {
|
||||
pointerId: 1,
|
||||
pointerType: "pen",
|
||||
pointerType: "stu",
|
||||
isPrimary: true,
|
||||
clientX: pt.x,
|
||||
clientY: pt.y,
|
||||
pressure: penData.pressure/this.mCapability.tabletMaxPressure,
|
||||
buttons: 1
|
||||
});
|
||||
|
||||
const point = window.DigitalInk.InkBuilder.createPoint(moveEvent);
|
||||
point.timestamp = penData.timeCount;
|
||||
this.sigCaptDialog.draw("move", point);
|
||||
//upEvent.timeStamp = penData.timeCount;
|
||||
this.sigCaptDialog.onUp(upEvent);
|
||||
this.mPenData.push(penData);
|
||||
}
|
||||
} else {
|
||||
// continue inking
|
||||
if (this.mBtnIndex == -1) {
|
||||
var moveEvent = new PointerEvent("pointermove", {
|
||||
pointerId: 1,
|
||||
pointerType: "stu",
|
||||
isPrimary: true,
|
||||
clientX: pt.x,
|
||||
clientY: pt.y,
|
||||
pressure: penData.pressure/this.mCapability.tabletMaxPressure,
|
||||
buttons: 1
|
||||
});
|
||||
|
||||
//moveEvent.timeStamp = penData.timeCount;
|
||||
this.sigCaptDialog.onMove(moveEvent);
|
||||
this.mPenData.push(penData);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.mIsDown = isDown;
|
||||
}
|
||||
|
@ -434,7 +420,7 @@ class StuCaptDialog {
|
|||
/**
|
||||
* Generate the signature from the raw data.
|
||||
**/
|
||||
async getCaptureData() {
|
||||
getCaptureData() {
|
||||
//Create Stroke Data
|
||||
let strokeVector = new Module.StrokeVector();
|
||||
let currentStroke = new Module.PointVector();
|
||||
|
@ -485,7 +471,8 @@ class StuCaptDialog {
|
|||
'device_pixels_per_m_x': 100000,
|
||||
'device_pixels_per_m_y': 100000,
|
||||
'device_origin_X': 0,
|
||||
'device_origin_Y': 1
|
||||
'device_origin_Y': 1,
|
||||
'device_unit_pixels': false
|
||||
}
|
||||
|
||||
var uid2;
|
||||
|
@ -500,24 +487,39 @@ class StuCaptDialog {
|
|||
uid2 = 0;
|
||||
}
|
||||
|
||||
var digitizerInfo = "STU;'"+this.mInformation.modelName+"';"+this.mInformation.firmwareMajorVersion+"."+((parseInt(this.mInformation.firmwareMinorVersion) >> 4) & 0x0f)+"."+(parseInt(this.mInformation.firmwareMinorVersion) & 0x0f)+";"+uid2;
|
||||
var nicInfo = "";
|
||||
var timeResolution = 1000;
|
||||
var who = this.who;
|
||||
var why = this.why;
|
||||
var where = "";
|
||||
|
||||
await this.sigObj.generateSignature(who, why, where, this.integrityType, this.documentHash, strokeVector, device, digitizerInfo, nicInfo, timeResolution);
|
||||
const digitizerInfo = "STU;'"+this.mInformation.modelName+"';"+this.mInformation.firmwareMajorVersion+"."+((parseInt(this.mInformation.firmwareMinorVersion) >> 4) & 0x0f)+"."+(parseInt(this.mInformation.firmwareMinorVersion) & 0x0f)+";"+uid2;
|
||||
const timeResolution = 1000;
|
||||
|
||||
const myPromise = new Promise((resolve, reject) => {
|
||||
try {
|
||||
const promise = this.sigCaptDialog.sigObj.generateSignature(this.sigCaptDialog.signatory, this.sigCaptDialog.reason, this.sigCaptDialog.where, this.sigCaptDialog.integrityType, this.sigCaptDialog.documentHash, strokeVector, device, this.sigCaptDialog.osInfo, digitizerInfo, this.sigCaptDialog.nicInfo, timeResolution);
|
||||
promise.then((value) => {
|
||||
if (value) {
|
||||
// put the extra data
|
||||
if (this.extraData) {
|
||||
for (const data of this.extraData) {
|
||||
this.sigObj.setExtraData(data.name, data.value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
strokeVector.delete();
|
||||
currentStroke.delete();
|
||||
resolve(value);
|
||||
});
|
||||
|
||||
promise.catch(error => {
|
||||
strokeVector.delete();
|
||||
currentStroke.delete();
|
||||
reject(error);
|
||||
});
|
||||
} catch (exception) {
|
||||
strokeVector.delete();
|
||||
currentStroke.delete();
|
||||
reject(exception);
|
||||
}
|
||||
});
|
||||
|
||||
return myPromise;
|
||||
}
|
||||
|
||||
drawImageToCanvas(src){
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
/* touch-action: none; is required to make pen works fine with WILL */
|
||||
/*#signatureWindow {touch-action: none;}*/
|
||||
body {
|
||||
-webkit-user-select: none;
|
||||
-webkit-touch-callout: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
/*touch-action: none;*/
|
||||
}
|
||||
|
||||
#modal-background {
|
||||
position: absolute;
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
paths:
|
||||
tests: tests
|
||||
output: tests/_output
|
||||
data: tests/_data
|
||||
support: tests/_support
|
||||
envs: tests/_envs
|
||||
settings:
|
||||
bootstrap: _bootstrap.php
|
||||
error_level: E_ALL & ~E_WARNING & ~E_NOTICE & ~E_USER_DEPRECATED
|
||||
actor_suffix: Tester
|
||||
extensions:
|
||||
enabled:
|
||||
- Codeception\Extension\RunFailed
|
||||
#- Codeception\Extension\Recorder
|
|
@ -15,7 +15,7 @@
|
|||
}],
|
||||
"type": "project",
|
||||
"require": {
|
||||
"php": "^7.3|^8.0",
|
||||
"php": "^8.1|^8.3",
|
||||
"ext-curl": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-fileinfo": "*",
|
||||
|
@ -28,45 +28,47 @@
|
|||
"ext-simplexml": "*",
|
||||
"ext-xsl": "*",
|
||||
"ext-zip": "*",
|
||||
"davidepastore/codice-fiscale": "^0.6.0",
|
||||
"davidepastore/codice-fiscale": "^0.9.1",
|
||||
"devcode-it/ical-easy-reader": "dev-main",
|
||||
"digitick/sepa-xml": "^2.1",
|
||||
"dragonmantank/cron-expression": "^1.0",
|
||||
"ezyang/htmlpurifier": "^4.8",
|
||||
"filp/whoops": "^2.1",
|
||||
"filp/whoops": "^2.15.0",
|
||||
"greenlion/php-sql-parser": "^4.5",
|
||||
"guzzlehttp/guzzle": "^7.0.1",
|
||||
"ifsnop/mysqldump-php": "^2.3",
|
||||
"illuminate/database": "^8.0",
|
||||
"intervention/image": "^2.3",
|
||||
"jurosh/pdf-merge": "^2.1",
|
||||
"league/csv": "9.7.0",
|
||||
"league/csv": "^9.7.0",
|
||||
"league/oauth2-client": "^2.6",
|
||||
"league/oauth2-google": "^3.0",
|
||||
"league/oauth2-google": "^4.0",
|
||||
"league/flysystem": "^3.0",
|
||||
"league/flysystem-ftp": "^3.0",
|
||||
"maximebf/debugbar": "^1.15",
|
||||
"monolog/monolog": "^1.22",
|
||||
"mpdf/mpdf": "^v8.0.10",
|
||||
"mpociot/vat-calculator": "^2.3",
|
||||
"owasp/csrf-protector-php": "^1.0",
|
||||
"phpmailer/phpmailer": "^6.0",
|
||||
"respect/validation": "^1.1",
|
||||
"servo/fluidxml": "^1.21",
|
||||
"respect/validation": "^2.0",
|
||||
"servo/fluidxml": "^2.0",
|
||||
"slim/flash": "^0.4.0",
|
||||
"spipu/html2pdf": "^5.0",
|
||||
"symfony/filesystem": "^4.0",
|
||||
"symfony/finder": "^4.0",
|
||||
"spipu/html2pdf": "^5.0.0",
|
||||
"symfony/filesystem": "^5.0",
|
||||
"symfony/finder": "^5.0",
|
||||
"symfony/polyfill-ctype": "^1.8",
|
||||
"symfony/polyfill-php70": "^1.8",
|
||||
"symfony/translation": "^4.0",
|
||||
"symfony/var-dumper": "^4.0",
|
||||
"symfony/var-dumper": "^5.0",
|
||||
"thenetworg/oauth2-azure": "^2.0",
|
||||
"voku/stringy": "~6.0",
|
||||
"voku/stringy": "^6.0.0",
|
||||
"wdog/sdd_ita": "dev-master",
|
||||
"willdurand/geocoder": "^4.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"codeception/codeception": "^4.0",
|
||||
"friendsofphp/php-cs-fixer": "^3.4"
|
||||
"friendsofphp/php-cs-fixer": "^3.53",
|
||||
"rector/rector": "^1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
@ -111,6 +113,8 @@
|
|||
"Modules\\Impostazioni\\": ["modules/impostazioni/custom/src/", "modules/impostazioni/src/"],
|
||||
"Modules\\Partitario\\": ["modules/partitario/custom/src/", "modules/partitario/src/"],
|
||||
"Modules\\StatoEmail\\": ["modules/stato_email/custom/src/", "modules/stato_email/src/"],
|
||||
"Modules\\FileAdapters\\": ["modules/adattatori_archiviazione/custom/src/", "modules/adattatori_archiviazione/src/"],
|
||||
"Plugins\\AssicurazioneCrediti\\": ["plugins/assicurazione_crediti/custom/src/", "plugins/assicurazione_crediti/src/"],
|
||||
"Plugins\\ExportFE\\": ["plugins/exportFE/custom/src/", "plugins/exportFE/src/"],
|
||||
"Plugins\\ImportFE\\": ["plugins/importFE/custom/src/", "plugins/importFE/src/"],
|
||||
"Plugins\\ReceiptFE\\": ["plugins/receiptFE/custom/src/", "plugins/receiptFE/src/"],
|
||||
|
@ -139,13 +143,13 @@
|
|||
],
|
||||
"config": {
|
||||
"sort-packages": true,
|
||||
"optimize-autoloader": false,
|
||||
"optimize-autoloader": true,
|
||||
"apcu-autoloader": true,
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"platform-check": false,
|
||||
"platform": {
|
||||
"php": "8.0.17"
|
||||
"php": "8.3.7"
|
||||
},
|
||||
"allow-plugins": {
|
||||
"kylekatarnls/update-helper": true
|
||||
|
|
|
@ -22,9 +22,9 @@ $db_host = '|host|';
|
|||
$db_username = '|username|';
|
||||
$db_password = '|password|';
|
||||
$db_name = '|database|';
|
||||
//$port = '|port|';
|
||||
// $port = '|port|';
|
||||
$db_options = [
|
||||
//'sort_buffer_size' => '2M',
|
||||
// 'sort_buffer_size' => '2M',
|
||||
];
|
||||
|
||||
// Percorso della cartella di backup
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use Models\Plugin;
|
||||
|
||||
include_once __DIR__.'/core.php';
|
||||
|
||||
if (!empty($id_record) && !empty($id_module)) {
|
||||
|
@ -33,37 +35,40 @@ include_once base_dir().'/actions.php';
|
|||
// Widget in alto
|
||||
echo '{( "name": "widgets", "id_module": "'.$id_module.'", "position": "top", "place": "controller" )}';
|
||||
|
||||
$segmenti = $dbo->FetchArray('SELECT `id` FROM `zz_segments` WHERE `id_module` = '.prepare($id_module));
|
||||
if ($segmenti) {
|
||||
$segmenti = Modules::getSegments($id_module);
|
||||
if (empty($segmenti)) {
|
||||
echo '
|
||||
<div class="alert alert-warning">
|
||||
<i class="fa fa-warning-circle"></i> '.tr('Questo gruppo di utenti non ha i permessi per visualizzare nessun segmento di questo modulo').'.
|
||||
</div>';
|
||||
}
|
||||
}
|
||||
|
||||
// Lettura eventuali plugins modulo da inserire come tab
|
||||
echo '
|
||||
<div class="nav-tabs-custom">
|
||||
<ul class="nav nav-tabs pull-right" id="tabs" role="tablist">
|
||||
<li class="pull-left active header">
|
||||
<a data-toggle="tab" href="#tab_0">
|
||||
<i class="'.$structure['icon'].'"></i> '.$structure['title'];
|
||||
<section class="content-header">
|
||||
<div class="container-fluid">
|
||||
<div class="row mb-2">
|
||||
<div class="col-sm-6">
|
||||
<h1>
|
||||
<i class="'.$structure['icon'].'"></i> '.$structure->getTranslation('title');
|
||||
|
||||
// Pulsante "Aggiungi" solo se il modulo è di tipo "table" e se esiste il template per la popup
|
||||
if ($structure->hasAddFile() && $structure->permission == 'rw') {
|
||||
echo '
|
||||
<button type="button" class="btn btn-primary" data-toggle="modal" data-title="'.tr('Aggiungi').'..." data-href="add.php?id_module='.$id_module.'&id_plugin='.$id_plugin.'"><i class="fa fa-plus"></i></button>';
|
||||
<button type="button" class="btn btn-primary" data-widget="modal" data-title="'.tr('Aggiungi').'..." data-href="add.php?id_module='.$id_module.'&id_plugin='.$id_plugin.'"><i class="fa fa-plus"></i></button>';
|
||||
}
|
||||
|
||||
echo '
|
||||
</a>
|
||||
</li>';
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
$plugins = $dbo->fetchArray('SELECT id, title FROM zz_plugins WHERE idmodule_to='.prepare($id_module)." AND position='tab_main' AND enabled = 1");
|
||||
|
||||
// Tab dei plugin
|
||||
foreach ($plugins as $plugin) {
|
||||
echo '
|
||||
<li>
|
||||
<a data-toggle="tab" href="#tab_'.$plugin['id'].'" id="link-tab_'.$plugin['id'].'">'.$plugin['title'].'</a>
|
||||
</li>';
|
||||
}
|
||||
|
||||
echo '
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-content">
|
||||
<div id="tab_0" class="tab-pane active">';
|
||||
|
||||
include base_dir().'/include/manager.php';
|
||||
|
@ -71,15 +76,17 @@ include base_dir().'/include/manager.php';
|
|||
echo '
|
||||
</div>';
|
||||
|
||||
// Plugin
|
||||
// Plugins
|
||||
$plugins = Plugin::where('idmodule_to', $id_module)->where('position', 'tab_main')->where('enabled', 1)->get();
|
||||
|
||||
$module_record = $record;
|
||||
foreach ($plugins as $plugin) {
|
||||
$record = $module_record;
|
||||
|
||||
echo '
|
||||
<div id="tab_'.$plugin['id'].'" class="tab-pane">';
|
||||
<div id="tab_'.$plugin->id.'" class="tab-pane">';
|
||||
|
||||
$id_plugin = $plugin['id'];
|
||||
$id_plugin = $plugin->id;
|
||||
|
||||
include base_dir().'/include/manager.php';
|
||||
|
||||
|
@ -89,18 +96,21 @@ foreach ($plugins as $plugin) {
|
|||
|
||||
$record = $module_record;
|
||||
|
||||
echo '
|
||||
</div>
|
||||
</div>';
|
||||
|
||||
redirectOperation($id_module, isset($id_parent) ? $id_parent : $id_record);
|
||||
redirectOperation($id_module, !empty($id_parent) ? $id_parent : $id_record);
|
||||
|
||||
// Interfaccia per la modifica dell'ordine e della visibilità delle colonne (Amministratore)
|
||||
if ($user->is_admin && string_contains($module['option'], '|select|')) {
|
||||
echo '
|
||||
<a class="btn btn-xs btn-default pull-right" style="margin-top: -1.25rem;" onclick="modificaColonne(this)">
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="col-md-12 text-right">
|
||||
<a class="btn btn-xs btn-default " style="margin-top: -1.25rem;" onclick="modificaColonne(this)">
|
||||
<i class="fa fa-th-list"></i> '.tr('Modifica colonne').'
|
||||
</a><div class="clearfix" > </div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix" >
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function modificaColonne(button) {
|
||||
|
@ -109,6 +119,9 @@ function modificaColonne(button) {
|
|||
</script>';
|
||||
}
|
||||
|
||||
echo '
|
||||
</div>';
|
||||
|
||||
// Widget in basso
|
||||
echo '{( "name": "widgets", "id_module": "'.$id_module.'", "position": "right", "place": "controller" )}';
|
||||
|
||||
|
|
38
core.php
38
core.php
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
// Rimozione header X-Powered-By
|
||||
header_remove('X-Powered-By');
|
||||
// header_remove('X-Powered-By');
|
||||
|
||||
// Impostazioni di configurazione PHP
|
||||
date_default_timezone_set('Europe/Rome');
|
||||
|
@ -30,7 +30,7 @@ if (version_compare(phpversion(), $minimum) < 0) {
|
|||
<p>Stai utilizzando la versione PHP '.phpversion().', non compatibile con OpenSTAManager.</p>
|
||||
|
||||
<p>Aggiorna PHP alla versione >= '.$minimum.'.</p>';
|
||||
exit();
|
||||
exit;
|
||||
}
|
||||
|
||||
// Caricamento delle impostazioni personalizzabili
|
||||
|
@ -54,13 +54,16 @@ $docroot = DOCROOT;
|
|||
$rootdir = ROOTDIR;
|
||||
$baseurl = BASEURL;
|
||||
|
||||
// Sicurezza della sessioni
|
||||
ini_set('session.cookie_samesite', 'lax');
|
||||
ini_set('session.use_trans_sid', '0');
|
||||
ini_set('session.use_only_cookies', '1');
|
||||
// Controllo che le intestazioni non siano già state inviate.
|
||||
if (!headers_sent()) {
|
||||
// Sicurezza della sessioni
|
||||
ini_set('session.cookie_samesite', 'lax');
|
||||
ini_set('session.use_trans_sid', '0');
|
||||
ini_set('session.use_only_cookies', '1');
|
||||
|
||||
session_set_cookie_params(0, base_path(), null, isHTTPS(true));
|
||||
session_start();
|
||||
session_set_cookie_params(0, base_path(), null, isHTTPS(true));
|
||||
session_start();
|
||||
}
|
||||
|
||||
// Lettura della configurazione
|
||||
$config = App::getConfig();
|
||||
|
@ -69,7 +72,7 @@ $config = App::getConfig();
|
|||
if (!empty($config['redirectHTTPS']) && !isHTTPS(true)) {
|
||||
header('HTTP/1.1 301 Moved Permanently');
|
||||
header('Location: https://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
|
||||
exit();
|
||||
exit;
|
||||
}
|
||||
|
||||
/* GESTIONE DEGLI ERRORI */
|
||||
|
@ -161,7 +164,6 @@ $formatter = !empty($config['formatter']) ? $config['formatter'] : [];
|
|||
$translator = trans();
|
||||
$translator->addLocalePath(base_dir().'/locale');
|
||||
$translator->addLocalePath(base_dir().'/modules/*/locale');
|
||||
$translator->setLocale($lang, $formatter);
|
||||
|
||||
// Individuazione di versione e revisione del progetto
|
||||
$version = Update::getVersion();
|
||||
|
@ -181,7 +183,7 @@ if (!$continue && getURLPath() != slashes(base_path().'/index.php') && !Permissi
|
|||
}
|
||||
|
||||
redirect(base_path().'/index.php');
|
||||
exit();
|
||||
exit;
|
||||
}
|
||||
|
||||
/* INIZIALIZZAZIONE GENERALE */
|
||||
|
@ -246,8 +248,8 @@ if (!API\Response::isAPIRequest()) {
|
|||
$plugin = Plugins::getCurrent();
|
||||
$structure = isset($plugin) ? $plugin : $module;
|
||||
|
||||
$id_module = $module ? $module['id'] : null;
|
||||
$id_plugin = $plugin ? $plugin['id'] : null;
|
||||
$id_module = $module ? $module->id : null;
|
||||
$id_plugin = $plugin ? $plugin->id : null;
|
||||
|
||||
$user = Auth::user();
|
||||
|
||||
|
@ -300,3 +302,13 @@ $list = array_merge($files, $custom_files);
|
|||
foreach ($list as $file) {
|
||||
include_once $file;
|
||||
}
|
||||
|
||||
// Inizializzazione traduzioni
|
||||
if (database()->tableExists('zz_settings') && database()->tableExists('zz_langs')) {
|
||||
$id_lang = setting('Lingua');
|
||||
Models\Locale::setDefault($id_lang);
|
||||
Models\Locale::setPredefined();
|
||||
|
||||
$lang = Models\Locale::find($id_lang)->language_code;
|
||||
$translator->setLocale($lang, $formatter);
|
||||
}
|
||||
|
|
18
cron.php
18
cron.php
|
@ -61,13 +61,13 @@ $handler->setFormatter($formatter);
|
|||
$logger->pushHandler($handler);
|
||||
|
||||
// Lettura della cache
|
||||
$ultima_esecuzione = Cache::pool('Ultima esecuzione del cron');
|
||||
$ultima_esecuzione = Cache::where('name', 'Ultima esecuzione del cron')->first();
|
||||
$data = $ultima_esecuzione->content;
|
||||
|
||||
$in_esecuzione = Cache::pool('Cron in esecuzione');
|
||||
$cron_id = Cache::pool('ID del cron');
|
||||
$in_esecuzione = Cache::where('name', 'Cron in esecuzione')->first();
|
||||
$cron_id = Cache::where('name', 'ID del cron')->first();
|
||||
|
||||
$disattiva = Cache::pool('Disabilita cron');
|
||||
$disattiva = Cache::where('name', 'Disabilita cron')->first();
|
||||
if ($disattiva->content || (in_array($_SERVER['HTTP_HOST'], ['localhost', '127.0.0.1']) && !$forza_cron_localhost)) {
|
||||
return;
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ while (true) {
|
|||
}
|
||||
|
||||
// Rimozione dei log più vecchi
|
||||
$database->query('DELETE FROM zz_tasks_logs WHERE DATE_ADD(created_at, INTERVAL :interval DAY) <= NOW()', [
|
||||
$database->query('DELETE FROM `zz_tasks_logs` WHERE DATE_ADD(`created_at`, INTERVAL :interval DAY) <= NOW()', [
|
||||
':interval' => 7,
|
||||
]);
|
||||
|
||||
|
@ -139,7 +139,7 @@ while (true) {
|
|||
$task->registerNextExecution($inizio_iterazione);
|
||||
$task->save();
|
||||
|
||||
$logger->info($task->name.': data mancante', [
|
||||
$logger->info($task->getTranslation('title').': data mancante', [
|
||||
'timestamp' => $task->next_execution_at->toDateTimeString(),
|
||||
]);
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ while (true) {
|
|||
// Esecuzione diretta solo nel caso in cui sia prevista
|
||||
if ($task->next_execution_at->copy()->addSeconds(20)->greaterThanOrEqualTo($inizio_iterazione) && $task->next_execution_at->lessThanOrEqualTo($adesso->copy()->addseconds(20))) {
|
||||
// Registrazione dell'esecuzione nei log
|
||||
$logger->info($task->name.': '.$task->expression);
|
||||
$logger->info($task->getTranslation('title').': '.$task->expression);
|
||||
try {
|
||||
$task->execute();
|
||||
} catch (Exception $e) {
|
||||
|
@ -158,12 +158,12 @@ while (true) {
|
|||
'trace' => $e->getTraceAsString(),
|
||||
]);
|
||||
|
||||
$logger->error($task->name.': errore');
|
||||
$logger->error($task->getTranslation('title').': errore');
|
||||
}
|
||||
}
|
||||
// Esecuzione mancata
|
||||
elseif ($task->next_execution_at->lessThan($inizio_iterazione)) {
|
||||
$logger->warning($task->name.': mancata', [
|
||||
$logger->warning($task->getTranslation('title').': mancata', [
|
||||
'timestamp' => $task->next_execution_at->toDateTimeString(),
|
||||
]);
|
||||
|
||||
|
|
172
editor.php
172
editor.php
|
@ -20,6 +20,7 @@
|
|||
include_once __DIR__.'/core.php';
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Models\Module;
|
||||
|
||||
// Disabilitazione dei campi
|
||||
$read_only = $structure->permission == 'r';
|
||||
|
@ -41,19 +42,21 @@ if (!empty($id_record)) {
|
|||
}
|
||||
// Rimozione della condizione deleted_at IS NULL per visualizzare anche i record eliminati
|
||||
if (!empty($query)) {
|
||||
if (preg_match('/[`]*([a-z0-9_]*)[`]*[\.]*([`]*deleted_at[`]* IS NULL)/i', $query, $m)) {
|
||||
if (preg_match('/[`]*([a-z0-9_]*)[`]*[\.]*([`]*deleted_at[`]* IS NULL)/si', $query, $m)) {
|
||||
$query = str_replace(["\n", "\t"], ' ', $query);
|
||||
$conditions_to_remove = [];
|
||||
|
||||
$condition = trim($m[0]);
|
||||
|
||||
if (!empty($table_name)) {
|
||||
$condition = $table_name.'.'.$condition;
|
||||
}
|
||||
|
||||
$conditions_to_remove[] = ' AND '.$condition;
|
||||
$conditions_to_remove[] = $condition.' AND ';
|
||||
$conditions_to_remove[] = ' AND\s*'.$condition;
|
||||
$conditions_to_remove[] = $condition.'\s*AND ';
|
||||
|
||||
$query = str_replace($conditions_to_remove, '', $query);
|
||||
foreach ($conditions_to_remove as $condition_to_remove) {
|
||||
$query = preg_replace('/'.$condition_to_remove.'/si', '', $query);
|
||||
}
|
||||
$query = str_replace($condition, '', $query);
|
||||
}
|
||||
}
|
||||
|
@ -95,41 +98,43 @@ if (empty($record) || !$has_access) {
|
|||
<h3 class="box-title"><i class="fa fa-warning"></i> '.tr('Attenzione!').'</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<p>'.tr('I seguenti utenti stanno visualizzando questa pagina').':</p>
|
||||
<p>'.tr('I seguenti utenti stanno consultando questa scheda').':</p>
|
||||
<ul class="list">
|
||||
</ul>
|
||||
<p>'.tr('Prestare attenzione prima di effettuare modifiche, poichè queste potrebbero essere perse a causa di multipli salvataggi contemporanei').'.</p>
|
||||
<p>'.tr('Prestare attenzione prima di effettuare modifiche, poiché queste potrebbero essere perse a causa di una sovrascrittura delle informazioni').'.</p>
|
||||
</div>
|
||||
</div>';
|
||||
}
|
||||
|
||||
echo '
|
||||
|
||||
<div class="nav-tabs-custom">
|
||||
<ul class="nav nav-tabs pull-right" id="tabs" role="tablist">
|
||||
<li class="pull-left active header">
|
||||
<a data-toggle="tab" href="#tab_0">
|
||||
<i class="'.$structure['icon'].'"></i> '.$structure['title'];
|
||||
<section class="content-header">
|
||||
<div class="container-fluid">
|
||||
<div class="row mb-2">
|
||||
<div class="col-sm-6">
|
||||
<h1>
|
||||
<i class="'.$structure['icon'].'"></i> '.$structure->getTranslation('title');
|
||||
|
||||
// Pulsante "Aggiungi" solo se il modulo è di tipo "table" e se esiste il template per la popup
|
||||
if ($structure->hasAddFile() && $structure->permission == 'rw') {
|
||||
echo '
|
||||
<button type="button" class="btn btn-primary" data-toggle="modal" data-title="'.tr('Aggiungi').'..." data-href="add.php?id_module='.$id_module.'&id_plugin='.$id_plugin.'"><i class="fa fa-plus"></i></button>';
|
||||
<button type="button" class="btn btn-primary" data-widget="modal" data-title="'.tr('Aggiungi').'..." data-href="add.php?id_module='.$id_module.'&id_plugin='.$id_plugin.'"><i class="fa fa-plus"></i></button>';
|
||||
}
|
||||
|
||||
echo '
|
||||
</a>
|
||||
</li>';
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
echo '
|
||||
|
||||
<li class="control-sidebar-toggle">
|
||||
<a style="cursor: pointer">'.tr('Plugin').'</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="col-sm-6">
|
||||
<ol class="breadcrumb float-sm-right">
|
||||
<li class="breadcrumb-item"><a href="'.$rootdir.'/">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="'.$rootdir.'/controller.php?id_module='.$id_module.'">'.$structure->getTranslation('title').'</a></li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="tab-content">
|
||||
<div id="tab_0" class="tab-pane active">';
|
||||
<div id="tab_0" class="tab-pane active nav-item">';
|
||||
|
||||
if (!empty($record['deleted_at'])) {
|
||||
$operation = $dbo->fetchOne("SELECT zz_operations.created_at, username FROM zz_operations INNER JOIN zz_users ON zz_operations.id_utente = zz_users.id WHERE op='delete' AND id_module=".prepare($id_module).' AND id_record='.prepare($id_record).' ORDER BY zz_operations.created_at DESC');
|
||||
|
@ -160,17 +165,18 @@ if (empty($record) || !$has_access) {
|
|||
|
||||
// Pulsanti di default
|
||||
echo '
|
||||
|
||||
<div id="pulsanti">
|
||||
<a class="btn btn-warning" id="back" href="'.base_path().'/controller.php?id_module='.$id_module.'">
|
||||
<a class="btn btn-default" id="back" href="'.base_path().'/controller.php?id_module='.$id_module.'">
|
||||
<i class="fa fa-chevron-left"></i> '.tr("Torna all'elenco").'
|
||||
</a>
|
||||
|
||||
<div class="pull-right">
|
||||
<div class="float-right d-none d-sm-inline">
|
||||
{( "name": "button", "type": "print", "id_module": "'.$id_module.'", "id_plugin": "'.$id_plugin.'", "id_record": "'.$id_record.'" )}
|
||||
|
||||
{( "name": "button", "type": "email", "id_module": "'.$id_module.'", "id_plugin": "'.$id_plugin.'", "id_record": "'.$id_record.'" )}';
|
||||
|
||||
if (Modules::get('Account SMS')) {
|
||||
if (Module::where('name', 'Account SMS')->first()->id) {
|
||||
echo '
|
||||
{( "name": "button", "type": "sms", "id_module": "'.$id_module.'", "id_plugin": "'.$id_plugin.'", "id_record": "'.$id_record.'" )}';
|
||||
}
|
||||
|
@ -178,22 +184,22 @@ if (empty($record) || !$has_access) {
|
|||
echo '
|
||||
|
||||
<div class="btn-group" id="save-buttons">
|
||||
<a class="btn btn-success" id="'.(!empty($record['deleted_at']) ? 'restore' : 'save').'">
|
||||
<button type="button" class="btn btn-success" id="'.(!empty($record['deleted_at']) ? 'restore' : 'save').'">
|
||||
<i class="fa fa-'.(!empty($record['deleted_at']) ? 'undo' : 'check').'"></i> '.(!empty($record['deleted_at']) ? tr('Salva e ripristina') : tr('Salva')).'
|
||||
</a>
|
||||
<a type="button" class="btn btn-success dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-success dropdown-toggle dropdown-icon" data-toggle="dropdown" aria-expanded="false">
|
||||
<span class="sr-only">Toggle Dropdown</span>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-right">
|
||||
<li><a href="#" id="'.(!empty($record['deleted_at']) ? 'restore' : 'save').'-close">
|
||||
</button>
|
||||
<div class="dropdown-menu" role="menu">
|
||||
<a class="dropdown-item" href="#" id="'.(!empty($record['deleted_at']) ? 'restore' : 'save').'-close">
|
||||
<i class="fa fa-'.(!empty($record['deleted_at']) ? 'undo' : 'check-square-o').'"></i>
|
||||
'.(!empty($record['deleted_at']) ? tr('Ripristina e chiudi') : tr('Salva e chiudi')).'
|
||||
</a></li>
|
||||
</ul>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
|
@ -211,31 +217,7 @@ if (empty($record) || !$has_access) {
|
|||
$("#save-close").on("click", function (){
|
||||
form.find("[name=backto]").val("record-list");
|
||||
$("#submit").trigger("click");
|
||||
});';
|
||||
|
||||
// Pulsanti dinamici
|
||||
if (!isMobile()) {
|
||||
echo '
|
||||
$("#pulsanti").affix({
|
||||
offset: {
|
||||
top: 200
|
||||
}
|
||||
});
|
||||
|
||||
if ($("#pulsanti").hasClass("affix")) {
|
||||
$("#pulsanti").css("width", $("#tab_0").css("width"));
|
||||
}
|
||||
|
||||
$("#pulsanti").on("affix.bs.affix", function(){
|
||||
$("#pulsanti").css("width", $("#tab_0").css("width"));
|
||||
});
|
||||
|
||||
$("#pulsanti").on("affix-top.bs.affix", function(){
|
||||
$("#pulsanti").css("width", "100%");
|
||||
});';
|
||||
}
|
||||
|
||||
echo '
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -250,12 +232,17 @@ if (empty($record) || !$has_access) {
|
|||
$buttons = ob_get_clean();
|
||||
|
||||
echo '
|
||||
<div class="pull-right" id="pulsanti-modulo">
|
||||
<div class="float-right d-none d-sm-inline" id="pulsanti-modulo">
|
||||
'.$buttons.'
|
||||
</div>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
<br>';
|
||||
// Eventuale header personalizzato
|
||||
$header = $structure->filepath('header.php');
|
||||
if ($header) {
|
||||
include_once $header;
|
||||
}
|
||||
}
|
||||
|
||||
// Contenuti del modulo
|
||||
|
@ -275,11 +262,11 @@ if (empty($record) || !$has_access) {
|
|||
// Campi personalizzati
|
||||
echo '
|
||||
|
||||
<div class="hide" id="custom_fields_top-edit">
|
||||
<div class="hide" id="custom_fields_top-edit_'.$id_module.'-'.$id_plugin.'">
|
||||
{( "name": "custom_fields", "id_module": "'.$id_module.'", "id_record": "'.$id_record.'", "position": "top" )}
|
||||
</div>
|
||||
|
||||
<div class="hide" id="custom_fields_bottom-edit">
|
||||
<div class="hide" id="custom_fields_bottom-edit_'.$id_module.'-'.$id_plugin.'">
|
||||
{( "name": "custom_fields", "id_module": "'.$id_module.'", "id_record": "'.$id_record.'" )}
|
||||
</div>
|
||||
|
||||
|
@ -299,10 +286,10 @@ if (empty($record) || !$has_access) {
|
|||
}
|
||||
|
||||
// Campi a inizio form
|
||||
aggiungiContenuto(form, "#custom_fields_top-edit", {}, true);
|
||||
aggiungiContenuto(form, "#custom_fields_top-edit_'.$id_module.'-'.$id_plugin.'", {}, true);
|
||||
|
||||
// Campi a fine form
|
||||
aggiungiContenuto(last, "#custom_fields_bottom-edit", {});
|
||||
aggiungiContenuto(last, "#custom_fields_bottom-edit_'.$id_module.'-'.$id_plugin.'", {});
|
||||
});
|
||||
</script>';
|
||||
|
||||
|
@ -329,19 +316,16 @@ if (empty($record) || !$has_access) {
|
|||
// Informazioni sulle operazioni
|
||||
if (Auth::admin()) {
|
||||
echo '
|
||||
<div id="tab_info" class="tab-pane">';
|
||||
<div id="tab_info" class="tab-pane">
|
||||
<div class="timeline">';
|
||||
|
||||
$operations = $dbo->fetchArray('SELECT `zz_operations`.*, `zz_users`.`username` FROM `zz_operations` JOIN `zz_users` ON `zz_operations`.`id_utente` = `zz_users`.`id` WHERE id_module = '.prepare($id_module).' AND id_record = '.prepare($id_record).' ORDER BY `created_at` DESC LIMIT 200');
|
||||
$operations = $dbo->fetchArray('SELECT `zz_operations`.*, `zz_users`.`username` FROM `zz_operations` LEFT JOIN `zz_users` ON `zz_operations`.`id_utente` = `zz_users`.`id` WHERE id_module = '.prepare($id_module).' AND id_record = '.prepare($id_record).' ORDER BY `created_at` DESC LIMIT 200');
|
||||
|
||||
if (!empty($operations)) {
|
||||
echo '
|
||||
<ul class="timeline">';
|
||||
|
||||
foreach ($operations as $operation) {
|
||||
$description = $operation['op'];
|
||||
$icon = 'pencil-square-o';
|
||||
$color = null;
|
||||
$timeline_class = null;
|
||||
$color = 'warning';
|
||||
|
||||
switch ($operation['op']) {
|
||||
case 'add':
|
||||
|
@ -367,39 +351,25 @@ if (empty($record) || !$has_access) {
|
|||
$icon = 'clone';
|
||||
$color = 'info';
|
||||
break;
|
||||
|
||||
default:
|
||||
$timeline_class = ' class="timeline-inverted"';
|
||||
break;
|
||||
}
|
||||
|
||||
echo '
|
||||
<li '.$timeline_class.'>
|
||||
<div class="timeline-badge '.$color.'"><i class="fa fa-'.$icon.'"></i></div>
|
||||
<div class="timeline-panel">
|
||||
<div class="timeline-heading">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h4 class="timeline-title">'.$description.'</h4>
|
||||
</div>
|
||||
<div class="col-md-4 text-right">
|
||||
<p><small class="label label-default tip" title="'.Translator::timestampToLocale($operation['created_at']).'"><i class="fa fa-clock-o"></i> '.Carbon::parse($operation['created_at'])->diffForHumans().'</small></p>
|
||||
<p><small class="label label-default"><i class="fa fa-user"></i> '.$operation['username'].'</small></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<i class="fa fa-'.$icon.' bg-'.$color.'"></i>
|
||||
<div class="timeline-item">
|
||||
<span class="time"><i class="fa fa-clock-o"></i> '.Carbon::parse($operation['created_at'])->diffForHumans().'</small></span>
|
||||
<h4 class="timeline-header">'.$description.'</h4>
|
||||
<div class="timeline-body">
|
||||
|
||||
</div>
|
||||
<div class="timeline-footer">
|
||||
|
||||
<span class="badge badge-default"><i class="fa fa-user"></i> '.$operation['username'].'
|
||||
</div>
|
||||
</div>
|
||||
</li>';
|
||||
</div>';
|
||||
}
|
||||
|
||||
echo '
|
||||
</ul>';
|
||||
<div>
|
||||
<i class="fa fa-clock-o bg-gray"></i>
|
||||
</div>
|
||||
</div>';
|
||||
} else {
|
||||
echo '
|
||||
<div class="alert alert-info">
|
||||
|
@ -431,11 +401,10 @@ if (empty($record) || !$has_access) {
|
|||
$record = $module_record;
|
||||
|
||||
echo '
|
||||
</div>
|
||||
</div>';
|
||||
}
|
||||
|
||||
redirectOperation($id_module, isset($id_parent) ? $id_parent : $id_record);
|
||||
redirectOperation($id_module, !empty($id_parent) ? $id_parent : $id_record);
|
||||
|
||||
// Widget in basso
|
||||
echo '{( "name": "widgets", "id_module": "'.$id_module.'", "id_record": "'.$id_record.'", "position": "right", "place": "editor" )}';
|
||||
|
@ -459,7 +428,7 @@ if ($read_only || !empty($block_edit)) {
|
|||
$(document).ready(function(){
|
||||
$("input, textarea, select", "section.content")'.$not.'.attr("readonly", "true");
|
||||
$("select, input[type=checkbox]", "section.content")'.$not.'.prop("disabled", true);
|
||||
$(".checkbox-buttons label", "section.content")'.$not.'.addClass("disabled");
|
||||
$(".checkbox-buttons badge", "section.content")'.$not.'.addClass("disabled");
|
||||
';
|
||||
|
||||
// Nascondo il plugin Note interne ai clienti
|
||||
|
@ -506,15 +475,10 @@ if ($read_only || !empty($block_edit)) {
|
|||
if(content_was_modified) {
|
||||
var dialogText = "Uscire senza salvare?";
|
||||
e.returnValue = dialogText;
|
||||
$("#main_loading").fadeOut();
|
||||
return dialogText;
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("unload", function(e) {
|
||||
$("#main_loading").show();
|
||||
});
|
||||
|
||||
|
||||
<?php
|
||||
if (!empty($advanced_sessions)) {
|
||||
|
|
46
gulpfile.js
46
gulpfile.js
|
@ -84,6 +84,7 @@ const JS = gulp.parallel(() => {
|
|||
'autosize/dist/autosize.js',
|
||||
'autocompleter/autocomplete.js',
|
||||
'html5sortable/dist/html5sortable.js',
|
||||
'popper.js/dist/umd/popper.js',
|
||||
'bootstrap-colorpicker/dist/js/bootstrap-colorpicker.js',
|
||||
'moment/moment.js',
|
||||
'components-jqueryui/jquery-ui.js',
|
||||
|
@ -122,6 +123,8 @@ const JS = gulp.parallel(() => {
|
|||
'bootstrap-maxlength/dist/bootstrap-maxlength.js',
|
||||
'leaflet/dist/leaflet.js',
|
||||
'leaflet-gesture-handling/dist/leaflet-gesture-handling.min.js',
|
||||
'ismobilejs/dist/isMobile.min.js',
|
||||
'ua-parser-js/dist/ua-parser.min.js',
|
||||
];
|
||||
|
||||
for (const i in vendor) {
|
||||
|
@ -133,7 +136,7 @@ const JS = gulp.parallel(() => {
|
|||
})
|
||||
.pipe(babel(config.babelOptions))
|
||||
.pipe(concat('app.min.js'))
|
||||
.pipe(gulpIf(!config.debug, minifyJS()))
|
||||
.pipe(gulpIf(!config.debug, minifyJS({compress:false})))
|
||||
.pipe(gulp.dest(config.production + '/' + config.paths.js));
|
||||
}, srcJS);
|
||||
|
||||
|
@ -177,11 +180,11 @@ const CSS = gulp.parallel(() => {
|
|||
'datatables.net-buttons-bs/css/buttons.bootstrap.css',
|
||||
'datatables.net-scroller-bs/css/scroller.bootstrap.css',
|
||||
'datatables.net-select-bs/css/select.bootstrap.css',
|
||||
'select2-bootstrap-theme/dist/select2-bootstrap.css',
|
||||
'smartwizard/dist/css/smart_wizard.min.css',
|
||||
'smartwizard/dist/css/smart_wizard_theme_arrows.min.css',
|
||||
'leaflet-gesture-handling/dist/leaflet-gesture-handling.min.css',
|
||||
'leaflet/dist/leaflet.css',
|
||||
'@ttskch/select2-bootstrap4-theme/dist/select2-bootstrap4.min.css'
|
||||
];
|
||||
|
||||
for (const i in vendor) {
|
||||
|
@ -224,7 +227,7 @@ function srcCSS() {
|
|||
|
||||
const themes = gulp.src([
|
||||
config.development + '/' + config.paths.css + '/themes/*.{css,scss,less,styl}',
|
||||
config.nodeDirectory + '/admin-lte/dist/css/skins/_all-skins.min.css',
|
||||
config.nodeDirectory + '/admin-lte/dist/css/adminlte.min.css',
|
||||
])
|
||||
.pipe(gulpIf('*.scss', sass(), gulpIf('*.less', less(), gulpIf('*.styl', stylus()))))
|
||||
.pipe(autoprefixer())
|
||||
|
@ -269,10 +272,9 @@ function wacom(){
|
|||
'modules/digital-ink/digital-ink-min.js',
|
||||
'common/will/tools.js',
|
||||
'modules/sjcl/sjcl.js',
|
||||
'sigCaptDialog/libs/stu_capture/stu-sdk.min.js',
|
||||
'sigCaptDialog/libs/stu_capture/stu_capture_encryption.js',
|
||||
'common/libs/signature_sdk.js',
|
||||
'common/libs/signature_sdk_helper.js',
|
||||
'common/libs/stu-sdk.min.js',
|
||||
'modules/node-forge/dist/forge.min.js',
|
||||
'sigCaptDialog/sigCaptDialog.js',
|
||||
'sigCaptDialog/stuCaptDialog.js'
|
||||
|
@ -306,11 +308,6 @@ const fonts = gulp.parallel(() => {
|
|||
'font-awesome/fonts/fontawesome-webfont.woff',
|
||||
'font-awesome/fonts/fontawesome-webfont.woff2',
|
||||
'font-awesome/fonts/FontAwesome.otf',
|
||||
'bootstrap/dist/fonts/glyphicons-halflings-regular.eot',
|
||||
'bootstrap/dist/fonts/glyphicons-halflings-regular.svg',
|
||||
'bootstrap/dist/fonts/glyphicons-halflings-regular.ttf',
|
||||
'bootstrap/dist/fonts/glyphicons-halflings-regular.woff',
|
||||
'bootstrap/dist/fonts/glyphicons-halflings-regular.woff2',
|
||||
'../assets/src/css/fonts/sourcesanspro-regular-webfont.eot',
|
||||
'../assets/src/css/fonts/sourcesanspro-regular-webfont.svg',
|
||||
'../assets/src/css/fonts/sourcesanspro-regular-webfont.ttf',
|
||||
|
@ -396,16 +393,16 @@ function csrf() {
|
|||
|
||||
function pdfjs() {
|
||||
const web = gulp.src([
|
||||
config.nodeDirectory + '/pdf.js/demo/vue/public/pdfjs-prebuilt/web/**/*',
|
||||
'!' + config.nodeDirectory + '/pdf.js/demo/vue/public/pdfjs-prebuilt/web/cmaps/*',
|
||||
'!' + config.nodeDirectory + '/pdf.js/demo/vue/public/pdfjs-prebuilt/web/*.map',
|
||||
'!' + config.nodeDirectory + '/pdf.js/demo/vue/public/pdfjs-prebuilt/web/*.pdf',
|
||||
config.nodeDirectory + '/pdfjs-viewer-element/dist/pdfjs-4.0.379-dist/web/**/*',
|
||||
'!' + config.nodeDirectory + '/pdfjs-viewer-element/dist/pdfjs-4.0.379-dist/web/cmaps/*',
|
||||
'!' + config.nodeDirectory + '/pdfjs-viewer-element/dist/pdfjs-4.0.379-dist/web/*.map',
|
||||
'!' + config.nodeDirectory + '/pdfjs-viewer-element/dist/pdfjs-4.0.379-dist/web/*.pdf',
|
||||
])
|
||||
.pipe(gulp.dest(config.production + '/pdfjs/web'));
|
||||
|
||||
const build = gulp.src([
|
||||
config.nodeDirectory + '/pdf.js/demo/vue/public/pdfjs-prebuilt/build/*',
|
||||
'!' + config.nodeDirectory + '/pdf.js/demo/vue/public/pdfjs-prebuilt/build/*.map',
|
||||
config.nodeDirectory + '/pdfjs-viewer-element/dist/pdfjs-4.0.379-dist/build/*',
|
||||
'!' + config.nodeDirectory + '/pdfjs-viewer-element/dist/pdfjs-4.0.379-dist/build/*.map',
|
||||
])
|
||||
.pipe(gulp.dest(config.production + '/pdfjs/build'));
|
||||
|
||||
|
@ -463,8 +460,11 @@ function release(done) {
|
|||
glob([
|
||||
'**/*',
|
||||
'!checksum.json',
|
||||
'!database.json',
|
||||
'!database_5_7.json',
|
||||
'!mysql.json',
|
||||
'!mysql_5_7.json',
|
||||
'!mariadb_10_x.json',
|
||||
'!settings.json',
|
||||
'!manifest.json',
|
||||
'!.idea/**',
|
||||
'!.git/**',
|
||||
'!.github/**',
|
||||
|
@ -478,6 +478,7 @@ function release(done) {
|
|||
'!config.inc.php',
|
||||
'!psalm.xml',
|
||||
'!update/structure.php',
|
||||
'!update/settings.php',
|
||||
'!**/*.(lock|phar|log|zip|bak|jar|txt)',
|
||||
'!**/~*',
|
||||
'!vendor/tecnickcom/tcpdf/examples/**',
|
||||
|
@ -523,7 +524,14 @@ function release(done) {
|
|||
archive.append(shell.exec('php update/structure.php', {
|
||||
silent: true
|
||||
}).stdout, {
|
||||
name: 'database.json'
|
||||
name: 'mysql.json'
|
||||
});
|
||||
|
||||
// Aggiunta del file per il controllo delle impostazioni
|
||||
archive.append(shell.exec('php update/settings.php', {
|
||||
silent: true
|
||||
}).stdout, {
|
||||
name: 'settings.json'
|
||||
});
|
||||
|
||||
// Aggiunta del commit corrente nel file REVISION
|
||||
|
|
|
@ -21,10 +21,8 @@ include_once __DIR__.'/../core.php';
|
|||
|
||||
if (Auth::check()) {
|
||||
echo '
|
||||
</div>
|
||||
</div><!-- /.row -->
|
||||
</section><!-- /.content -->
|
||||
</aside><!-- /.content-wrapper -->
|
||||
</div><!-- /.content-wrapper -->
|
||||
|
||||
<footer class="main-footer">
|
||||
<a class="hidden-xs" href="'.tr('https://www.openstamanager.com').'" title="'.tr("Il gestionale open source per l'assistenza tecnica e la fatturazione").'." target="_blank"><strong>'.tr('OpenSTAManager').'</strong></a>
|
||||
|
@ -78,7 +76,7 @@ if (Auth::check()) {
|
|||
// Hooks
|
||||
if (!$config['disable_hooks']) {
|
||||
echo '
|
||||
setTimeout("startHooks();", 1000);';
|
||||
startHooks();';
|
||||
}
|
||||
|
||||
// Abilitazione del cron autonoma
|
||||
|
@ -97,7 +95,7 @@ echo '
|
|||
</html>';
|
||||
|
||||
// Retrocompatibilità
|
||||
if (!empty($id_record) || basename($_SERVER['PHP_SELF']) == 'controller.php' || basename($_SERVER['PHP_SELF']) == 'index.php') {
|
||||
if (!empty($id_record) || basename((string) $_SERVER['PHP_SELF']) == 'controller.php' || basename((string) $_SERVER['PHP_SELF']) == 'index.php') {
|
||||
unset($_SESSION['infos']);
|
||||
unset($_SESSION['errors']);
|
||||
unset($_SESSION['warnings']);
|
||||
|
|
|
@ -18,19 +18,20 @@
|
|||
*/
|
||||
|
||||
include_once __DIR__.'/../core.php';
|
||||
use Models\Module;
|
||||
|
||||
// Compatibilità per controller ed editor
|
||||
$structure = Modules::get($id_module);
|
||||
$structure = Module::find($id_module);
|
||||
|
||||
echo '
|
||||
<p>'.tr('Trascina le colonne per ordinare la struttura della tabella principale, seleziona e deseleziona le colonne per renderle visibili o meno').'.</p>
|
||||
<div class="sortable">';
|
||||
<div class="sortable row">';
|
||||
|
||||
$fields = $dbo->fetchArray('SELECT *, (SELECT GROUP_CONCAT(zz_groups.nome) FROM zz_group_view INNER JOIN zz_groups ON zz_group_view.id_gruppo = zz_groups.id WHERE zz_group_view.id_vista = zz_views.id) AS gruppi_con_accesso FROM zz_views WHERE id_module='.prepare($id_module).' ORDER BY `order` ASC');
|
||||
$fields = $dbo->fetchArray('SELECT `zz_views`.*, (SELECT GROUP_CONCAT(`zz_groups_lang`.`title`) FROM `zz_group_view` INNER JOIN `zz_groups` ON `zz_group_view`.`id_gruppo` = `zz_groups`.`id` LEFT JOIN `zz_groups_lang` ON (`zz_groups`.`id` = `zz_groups_lang`.`id_record` AND `zz_groups_lang`.`id_lang` = '.prepare(Models\Locale::getDefault()->id).') WHERE `zz_group_view`.`id_vista` = `zz_views`.`id`) AS gruppi_con_accesso FROM `zz_views` LEFT JOIN `zz_views_lang` ON (`zz_views`.`id` = `zz_views_lang`.`id_record` AND `zz_views_lang`.`id_lang` = '.prepare(Models\Locale::getDefault()->id).') WHERE `id_module`='.prepare($id_module).' ORDER BY `order` ASC');
|
||||
foreach ($fields as $field) {
|
||||
echo '
|
||||
<div class="panel panel-default clickable col-md-4" data-id="'.$field['id'].'">
|
||||
<div class="panel-body no-selection">
|
||||
<div class="card card-default clickable col-md-4" data-id="'.$field['id'].'">
|
||||
<div class="card-body no-selection">
|
||||
<input type="checkbox" name="visibile" '.($field['visible'] ? 'checked' : '').'>
|
||||
|
||||
<span class="text-'.($field['visible'] ? 'success' : 'danger').'">'.$field['name'].'<br><small>( '.$field['gruppi_con_accesso'].')</small></span>
|
||||
|
@ -47,8 +48,8 @@ echo '
|
|||
<script>
|
||||
// Abilitazione dinamica delle colonne
|
||||
$("input[name=visibile]").change(function() {
|
||||
let panel = $(this).closest(".panel[data-id]");
|
||||
let id = panel.data("id");
|
||||
let card = $(this).closest(".card[data-id]");
|
||||
let id = card.data("id");
|
||||
|
||||
// Aggiornamento effettivo
|
||||
$.post(globals.rootdir + "/actions.php", {
|
||||
|
@ -59,7 +60,7 @@ echo '
|
|||
});
|
||||
|
||||
// Aggiornamento grafico
|
||||
let text = panel.find("span");
|
||||
let text = card.find("span");
|
||||
if ($(this).is(":checked")) {
|
||||
text.removeClass("text-danger")
|
||||
.addClass("text-success");
|
||||
|
@ -82,7 +83,7 @@ echo '
|
|||
dropOnEmpty: true,
|
||||
scroll: true,
|
||||
})[0].addEventListener("sortupdate", function(e) {
|
||||
let order = $(".panel[data-id]").toArray().map(a => $(a).data("id"))
|
||||
let order = $(".card[data-id]").toArray().map(a => $(a).data("id"))
|
||||
console.log(order);
|
||||
|
||||
$.post(globals.rootdir + "/actions.php", {
|
||||
|
|
|
@ -17,24 +17,27 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
$result['idarticolo'] = isset($result['idarticolo']) ? $result['idarticolo'] : null;
|
||||
$result['idarticolo'] ??= null;
|
||||
$qta_minima = 0;
|
||||
$id_listino = $dbo->selectOne('an_anagrafiche', 'id_listino', ['idanagrafica' => $options['idanagrafica']])['id_listino'];
|
||||
|
||||
// Articolo
|
||||
$database = database();
|
||||
$articolo = $database->fetchOne('SELECT mg_articoli.id,
|
||||
mg_fornitore_articolo.id AS id_dettaglio_fornitore,
|
||||
IFNULL(mg_fornitore_articolo.codice_fornitore, mg_articoli.codice) AS codice,
|
||||
IFNULL(mg_fornitore_articolo.descrizione, mg_articoli.descrizione) AS descrizione,
|
||||
IFNULL(mg_fornitore_articolo.qta_minima, 0) AS qta_minima
|
||||
FROM mg_articoli
|
||||
LEFT JOIN mg_fornitore_articolo ON mg_fornitore_articolo.id_articolo = mg_articoli.id AND mg_fornitore_articolo.id = '.prepare($result['id_dettaglio_fornitore']).'
|
||||
WHERE mg_articoli.id = '.prepare($result['idarticolo']));
|
||||
$articolo = $database->fetchOne('SELECT
|
||||
`mg_articoli`.`id`,
|
||||
`mg_fornitore_articolo`.`id` AS id_dettaglio_fornitore,
|
||||
IFNULL(`mg_fornitore_articolo`.`codice_fornitore`, `mg_articoli`.`codice`) AS codice,
|
||||
IFNULL(`mg_fornitore_articolo`.`descrizione`, `mg_articoli_lang`.`title`) AS descrizione,
|
||||
IFNULL(`mg_fornitore_articolo`.`qta_minima`, 0) AS qta_minima
|
||||
FROM `mg_articoli`
|
||||
LEFT JOIN `mg_articoli_lang` ON (`mg_articoli_lang`.`id_record` = `mg_articoli`.`id` AND `mg_articoli_lang`.`id_lang` = '.prepare(Models\Locale::getDefault()->id).')
|
||||
LEFT JOIN `mg_fornitore_articolo` ON `mg_fornitore_articolo`.`id_articolo` = `mg_articoli`.`id` AND `mg_fornitore_articolo`.`id` = '.prepare($result['id_dettaglio_fornitore']).'
|
||||
WHERE
|
||||
`mg_articoli`.`id` = '.prepare($result['idarticolo']));
|
||||
|
||||
$qta_minima = $articolo['qta_minima'];
|
||||
|
||||
echo '
|
||||
echo '
|
||||
{[ "type": "select", "disabled":"1", "label": "'.tr('Articolo').'", "name": "idarticolo", "value": "'.$result['idarticolo'].'", "ajax-source": "articoli", "select-options": '.json_encode($options['select-options']['articoli']).' ]}
|
||||
|
||||
<script>
|
||||
|
@ -53,7 +56,7 @@ $qta_minima = $articolo['qta_minima'];
|
|||
<input type="hidden" name="blocca_minimo_vendita" value="'.setting('Bloccare i prezzi inferiori al minimo di vendita').'">';
|
||||
|
||||
// Selezione impianto per gli Interventi
|
||||
if ($module['name'] == 'Interventi') {
|
||||
if ($module->getTranslation('title') == 'Attività') {
|
||||
echo '
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
|
@ -180,12 +183,6 @@ $("#idarticolo").on("change", function() {
|
|||
});
|
||||
});
|
||||
|
||||
$("#idsede").on("change", function() {
|
||||
updateSelectOption("idsede_partenza", $(this).val());
|
||||
session_set("superselect,idsede_partenza", $(this).val(), 0);
|
||||
$("#idarticolo").selectReset();
|
||||
});
|
||||
|
||||
$(document).on("change", "input[name^=qta], input[name^=prezzo_unitario], input[name^=sconto]", function() {
|
||||
verificaPrezzoArticolo();
|
||||
verificaScontoArticolo();
|
||||
|
@ -388,7 +385,7 @@ function verificaPrezzoArticolo() {
|
|||
let table = $(".table-prezzi");
|
||||
|
||||
if (prezzo_anagrafica) {
|
||||
table.append(`<tr><td class="pr_anagrafica"><small>'.($options['dir'] == 'uscita' ? tr('Prezzo listino') : tr('Netto cliente')).': '.Plugins::link(($options['dir'] == 'uscita' ? 'Listino Fornitori' : 'Netto Clienti'), $result['idarticolo'], tr('Visualizza'), null, '').'</small></td><td align="right" class="pr_anagrafica"><small>` + prezzo_anagrafica.toLocale() + ` ` + globals.currency + `</small></td>`);
|
||||
table.append(`<tr><td class="pr_anagrafica"><small>'.($options['dir'] == 'uscita' ? tr('Prezzo listino') : tr('Netto cliente')).': '.Plugins::link($options['dir'] == 'uscita' ? 'Listino Fornitori' : 'Netto Clienti', $result['idarticolo'], tr('Visualizza'), null, '').'</small></td><td align="right" class="pr_anagrafica"><small>` + prezzo_anagrafica.toLocale() + ` ` + globals.currency + `</small></td>`);
|
||||
|
||||
let tr = $(".pr_anagrafica").parent();
|
||||
if (prezzo_unitario == prezzo_anagrafica.toFixed(2)) {
|
||||
|
@ -504,7 +501,7 @@ function verificaScontoArticolo() {
|
|||
}
|
||||
|
||||
div.css("margin-top", "-13px");
|
||||
div.html(`<small class="label label-info">'.tr('Sconto suggerito').': ` + sconto_previsto.toLocale() + `%<button type="button" class="btn btn-xs btn-info pull-right" onclick="aggiornaScontoArticolo()"><i class="fa fa-refresh"></i> '.tr('Aggiorna').'</button></small>`);
|
||||
div.html(` <span class="right badge badge-info">'.tr('Sconto suggerito').': ` + sconto_previsto.toLocale() + `%<button type="button" class="btn btn-xs btn-info pull-right" onclick="aggiornaScontoArticolo()"><i class="fa fa-refresh"></i> '.tr('Aggiorna').'</button></small>`);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -612,7 +609,7 @@ function verificaMinimoVendita() {
|
|||
div.css("margin-top", "-13px");
|
||||
if (prezzo_unitario < minimo_vendita) {
|
||||
if (input("blocca_minimo_vendita").get() == "0") {
|
||||
div.html(`<p class="label-warning">'.tr('Attenzione:<br>valore inferiore al prezzo minimo di vendita ').'` + minimo_vendita.toLocale() + ` ` + globals.currency + `</p>`);
|
||||
div.html(`<p class="badge-warning">'.tr('Attenzione:<br>valore inferiore al prezzo minimo di vendita ').'` + minimo_vendita.toLocale() + ` ` + globals.currency + `</p>`);
|
||||
}
|
||||
} else {
|
||||
div.html("");
|
||||
|
@ -620,7 +617,7 @@ function verificaMinimoVendita() {
|
|||
if (prezzo_unitario <= minimo_vendita) {
|
||||
if (input("blocca_minimo_vendita").get() == "1") {
|
||||
prezzo_unitario_input.val(minimo_vendita);
|
||||
div.html(`<p class="label-warning">'.tr('Attenzione:<br>non è possibile inserire un prezzo inferiore al prezzo minimo di vendita ').'` + minimo_vendita.toLocale() + ` ` + globals.currency + `</p>`);
|
||||
div.html(`<p class="badge-warning">'.tr('Attenzione:<br>non è possibile inserire un prezzo inferiore al prezzo minimo di vendita ').'` + minimo_vendita.toLocale() + ` ` + globals.currency + `</p>`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
// Informazioni aggiuntive per Fatture
|
||||
if ($module['name'] != 'Fatture di acquisto' && $module['name'] != 'Fatture di vendita') {
|
||||
if ($module->getTranslation('title') != 'Fatture di acquisto' && $module->getTranslation('title') != 'Fatture di vendita') {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -48,25 +48,25 @@ $calcolo_ritenuta_acconto = $calcolo_ritenuta_acconto ?: setting("Metodologia ca
|
|||
echo '
|
||||
<div class="row">';
|
||||
|
||||
// Cassa previdenziale
|
||||
echo '
|
||||
// Cassa previdenziale
|
||||
echo '
|
||||
<div class="col-md-4">
|
||||
{[ "type": "select", "label": "'.tr('Cassa previdenziale').'", "name": "id_rivalsa_inps", "value": "'.$id_rivalsa_inps.'", "values": "query=SELECT * FROM co_rivalse", "help": "'.(($options['dir'] == 'entrata') ? setting('Tipo Cassa Previdenziale') : null).'" ]}
|
||||
</div>';
|
||||
|
||||
// Ritenuta d'acconto
|
||||
echo '
|
||||
// Ritenuta d'acconto
|
||||
echo '
|
||||
<div class="col-md-4">
|
||||
{[ "type": "select", "label": "'.tr("Ritenuta d'acconto").'", "name": "id_ritenuta_acconto", "value": "'.$id_ritenuta_acconto.'", "values": "query=SELECT * FROM co_ritenutaacconto" ]}
|
||||
</div>';
|
||||
|
||||
// Calcola ritenuta d'acconto su
|
||||
echo '
|
||||
// Calcola ritenuta d'acconto su
|
||||
echo '
|
||||
<div class="col-md-4">
|
||||
{[ "type": "select", "label": "'.tr("Calcola ritenuta d'acconto su").'", "name": "calcolo_ritenuta_acconto", "value": "'.$calcolo_ritenuta_acconto.'", "values": "list=\"IMP\":\"Imponibile\", \"IMP+RIV\":\"Imponibile + rivalsa\""]}
|
||||
</div>';
|
||||
|
||||
echo '
|
||||
echo '
|
||||
</div>';
|
||||
|
||||
if (!empty($options['show-ritenuta-contributi']) || empty($options['hide_conto'])) {
|
||||
|
|
|
@ -32,11 +32,11 @@ echo '
|
|||
</div>
|
||||
</div>';
|
||||
|
||||
if ($module['name'] == 'Preventivi' && $options['op'] == 'manage_descrizione') {
|
||||
if ($module->getTranslation('title') == 'Preventivi' && $options['op'] == 'manage_descrizione') {
|
||||
echo '
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{[ "type": "checkbox", "label": "'.tr('Utilizza come titolo del gruppo').'", "name": "is_titolo", "value": '.json_encode($result['is_titolo']).', "help": "'.tr('').'" ]}
|
||||
{[ "type": "checkbox", "label": "'.tr('Utilizza come titolo del gruppo').'", "name": "is_titolo", "value": '.json_encode($result['is_titolo']).', "help": "'.tr(' ').'" ]}
|
||||
</div>
|
||||
</div>';
|
||||
}
|
||||
|
|
|
@ -17,11 +17,9 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
$result['id'] = isset($result['id']) ? $result['id'] : null;
|
||||
|
||||
// Form di inserimento riga documento
|
||||
echo '
|
||||
<form action="'.base_path().'/editor.php?id_module='.$id_module.'&id_record='.$id_record.'" method="post">
|
||||
<form action="'.base_path().'/editor.php?id_module='.$id_module.'&id_record='.$id_record.'" method="post" id="submit-form">
|
||||
<input type="hidden" name="id_plugin" value="'.$id_plugin.'">
|
||||
<input type="hidden" name="hash" value="tab_'.$id_plugin.'">
|
||||
<input type="hidden" name="backto" value="record-edit">
|
||||
|
@ -41,10 +39,26 @@ echo '
|
|||
<!-- PULSANTI -->
|
||||
<div class="row">
|
||||
<div class="col-md-12 text-right">
|
||||
<button type="submit" class="btn btn-primary pull-right"><i class="fa '.$icon.'"></i> '.$button.'</button>
|
||||
<button type="button" class="btn btn-primary pull-right" onclick="submitForm()"><i class="fa '.$icon.'"></i> '.$button.'</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>';
|
||||
|
||||
echo '
|
||||
<script>$(document).ready(init)</script>';
|
||||
|
||||
echo '
|
||||
<script>
|
||||
function submitForm() {
|
||||
var form = input("#submit-form");
|
||||
salvaForm("#submit-form", {
|
||||
id_module: "'.$id_module.'",
|
||||
id_record: "'.$id_record.'",
|
||||
}).then(function(response) {
|
||||
form.getElement().closest("div[id^=bs-popup").modal("hide");
|
||||
caricaRighe(null);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
</script>';
|
||||
|
|
|
@ -17,6 +17,12 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use Models\Module;
|
||||
use Modules\Contratti\Stato as StatoContratto;
|
||||
use Modules\DDT\Stato;
|
||||
use Modules\Fatture\Stato as StatoFattura;
|
||||
use Modules\Fatture\Tipo as Tipofattura;
|
||||
use Modules\Ordini\Stato as StatoOrdine;
|
||||
use Plugins\ListinoFornitori\DettaglioFornitore;
|
||||
|
||||
// Inizializzazione
|
||||
|
@ -28,22 +34,25 @@ if (empty($documento)) {
|
|||
|
||||
// Informazioni utili
|
||||
$dir = $documento->direzione;
|
||||
$original_module = Modules::get($documento->module);
|
||||
$original_module = Module::where('name', $documento->module)->first();
|
||||
|
||||
$name = !empty($documento_finale) ? $documento_finale->module : $options['module'];
|
||||
$final_module = Modules::get($name);
|
||||
$id_segment = $_SESSION['module_'.$final_module['id']]['id_segment'];
|
||||
$final_module = Module::where('name', $name)->first();
|
||||
$id_segment = $_SESSION['module_'.$final_module->id]['id_segment'];
|
||||
|
||||
// IVA predefinita
|
||||
$id_iva = $id_iva ?: setting('Iva predefinita');
|
||||
|
||||
$righe_totali = $documento->getRighe();
|
||||
if ($final_module['name'] == 'Interventi') {
|
||||
|
||||
$id_module_interventi = Module::where('name', 'Interventi')->first()->id;
|
||||
$id_module_ordini_f = Module::where('name', 'Ordini fornitore')->first()->id;
|
||||
if ($final_module->id == $id_module_interventi) {
|
||||
$righe = $righe_totali->where('is_descrizione', '=', 0)
|
||||
->where('qta_rimanente', '>', 0);
|
||||
$righe_evase = $righe_totali->where('is_descrizione', '=', 0)
|
||||
->where('qta_rimanente', '=', 0);
|
||||
} elseif ($final_module['name'] == 'Ordini fornitore') {
|
||||
} elseif ($final_module->id == $id_module_ordini_f) {
|
||||
$righe = $righe_totali;
|
||||
$righe_evase = collect();
|
||||
} else {
|
||||
|
@ -58,7 +67,7 @@ if ($righe->isEmpty()) {
|
|||
return;
|
||||
}
|
||||
|
||||
$link = !empty($documento_finale) ? base_path().'/editor.php?id_module='.$final_module['id'].'&id_record='.$documento_finale->id : base_path().'/controller.php?id_module='.$final_module['id'];
|
||||
$link = !empty($documento_finale) ? base_path().'/editor.php?id_module='.$final_module->id.'&id_record='.$documento_finale->id : base_path().'/controller.php?id_module='.$final_module->id;
|
||||
|
||||
echo '
|
||||
<form action="'.$link.'" method="post">
|
||||
|
@ -67,17 +76,17 @@ echo '
|
|||
|
||||
<input type="hidden" name="id_documento" value="'.$documento->id.'">
|
||||
<input type="hidden" name="type" value="'.$options['type'].'">
|
||||
<input type="hidden" name="class" value="'.get_class($documento).'">
|
||||
<input type="hidden" name="class" value="'.$documento::class.'">
|
||||
<input type="hidden" name="is_evasione" value="1">';
|
||||
|
||||
// Creazione fattura dal documento
|
||||
if (!empty($options['create_document'])) {
|
||||
echo '
|
||||
<div class="box box-warning">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">'.tr('Nuovo documento').'</h3>
|
||||
<div class="card card-warning">
|
||||
<div class="card-header with-border">
|
||||
<h3 class="card-title">'.tr('Nuovo documento').'</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="card-body">
|
||||
|
||||
<div class="row">
|
||||
<input type="hidden" name="create_document" value="on" />
|
||||
|
@ -87,33 +96,32 @@ if (!empty($options['create_document'])) {
|
|||
</div>';
|
||||
|
||||
// Opzioni aggiuntive per le Fatture
|
||||
if (in_array($final_module['name'], ['Fatture di vendita', 'Fatture di acquisto'])) {
|
||||
$stato_predefinito = $database->fetchOne("SELECT id FROM co_statidocumento WHERE descrizione = 'Bozza'");
|
||||
$id_module_fatt_vendita = Module::where('name', 'Fatture di vendita')->first()->id;
|
||||
$id_module_fatt_acquisto = Module::where('name', 'Fatture di acquisto')->first()->id;
|
||||
$id_module_ddt_vendita = Module::where('name', 'Ddt di vendita')->first()->id;
|
||||
$id_module_ddt_acquisto = Module::where('name', 'Ddt di acquisto')->first()->id;
|
||||
if (in_array($final_module->id, [$id_module_fatt_vendita, $id_module_fatt_acquisto])) {
|
||||
$stato_predefinito = StatoFattura::where('name', 'Bozza')->first()->id;
|
||||
$fatt_differita_acquisto = Tipofattura::where('name', 'Fattura differita di acquisto')->first()->id;
|
||||
$fatt_differita_vendita = Tipofattura::where('name', 'Fattura differita di vendita')->first()->id;;
|
||||
|
||||
if (!empty($options['reversed'])) {
|
||||
$idtipodocumento = $dbo->selectOne('co_tipidocumento', ['id'], [
|
||||
'dir' => $dir,
|
||||
'descrizione' => 'Nota di credito',
|
||||
])['id'];
|
||||
} elseif (in_array($original_module['name'], ['Ddt di vendita', 'Ddt di acquisto'])) {
|
||||
$idtipodocumento = $dbo->selectOne('co_tipidocumento', ['id'], [
|
||||
'dir' => $dir,
|
||||
'descrizione' => ($dir == 'uscita' ? 'Fattura differita di acquisto' : 'Fattura differita di vendita'),
|
||||
])['id'];
|
||||
$idtipodocumento = database()->fetchOne('SELECT `co_tipidocumento`.`id` FROM `co_tipidocumento` LEFT JOIN `co_tipidocumento_lang` ON (`co_tipidocumento_lang`.`id_record` = `co_tipidocumento`.`id` AND `co_tipidocumento_lang`.`id_lang` = '.prepare(Models\Locale::getDefault()->id).') WHERE `title` = "Nota di credito" AND `dir` = \''.$dir.'\'')['id'];
|
||||
} elseif (in_array($original_module->id, [$id_module_ddt_vendita, $id_module_ddt_acquisto])) {
|
||||
$idtipodocumento = database()->fetchOne('SELECT `co_tipidocumento`.`id` FROM `co_tipidocumento` LEFT JOIN `co_tipidocumento_lang` ON (`co_tipidocumento_lang`.`id_record` = `co_tipidocumento`.`id` AND `co_tipidocumento_lang`.`id_lang` = '.prepare(Models\Locale::getDefault()->id).') WHERE `co_tipidocumento`.`id` = '.($dir == 'uscita' ? $fatt_differita_acquisto : $fatt_differita_vendita).' AND `dir` = \''.$dir.'\'')['id'];
|
||||
} else {
|
||||
$idtipodocumento = $dbo->selectOne('co_tipidocumento', ['id'], [
|
||||
'predefined' => 1,
|
||||
'dir' => $dir,
|
||||
])['id'];
|
||||
$idtipodocumento = database()->fetchOne('SELECT `co_tipidocumento`.`id` FROM `co_tipidocumento` LEFT JOIN `co_tipidocumento_lang` ON (`co_tipidocumento_lang`.`id_record` = `co_tipidocumento`.`id` AND `co_tipidocumento_lang`.`id_lang` = '.prepare(Models\Locale::getDefault()->id).') WHERE `dir` = \''.$dir.'\' AND `predefined` = 1')['id'];
|
||||
}
|
||||
|
||||
$id_bozza = StatoFattura::where('name', 'Bozza')->first()->id;
|
||||
$id_emessa = StatoFattura::where('name', 'Emessa')->first()->id;
|
||||
echo '
|
||||
<div class="col-md-6">
|
||||
{[ "type": "select", "label": "'.tr('Stato').'", "name": "id_stato", "required": 1, "values": "query=SELECT * FROM co_statidocumento WHERE descrizione IN (\'Emessa\', \'Bozza\')", "value": "'.$stato_predefinito['id'].'"]}
|
||||
{[ "type": "select", "label": "'.tr('Stato').'", "name": "id_stato", "required": 1, "values": "query=SELECT `co_statidocumento`.`id` as id, `co_statidocumento_lang`.`title` as descrizione FROM `co_statidocumento` LEFT JOIN `co_statidocumento_lang` ON (`co_statidocumento`.`id` = `co_statidocumento_lang`.`id_record` AND `co_statidocumento_lang`.`id_lang` = '.prepare(Models\Locale::getDefault()->id).') WHERE `co_statidocumento`.`id` IN ('.$id_bozza.', '.$id_emessa.')", "value": "'.$stato_predefinito.'"]}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{[ "type": "select", "label": "'.tr('Tipo documento').'", "name": "idtipodocumento", "required": 1, "values": "query=SELECT id, CONCAT(codice_tipo_documento_fe, \' - \', descrizione) AS descrizione FROM co_tipidocumento WHERE enabled = 1 AND dir = '.prepare($dir).' ORDER BY codice_tipo_documento_fe", "value": "'.$idtipodocumento.'" ]}
|
||||
{[ "type": "select", "label": "'.tr('Tipo documento').'", "name": "idtipodocumento", "required": 1, "values": "query=SELECT `co_tipidocumento`.`id`, CONCAT(`codice_tipo_documento_fe`, \' - \', `title`) AS descrizione FROM `co_tipidocumento` LEFT JOIN `co_tipidocumento_lang` ON (`co_tipidocumento`.`id` = `co_tipidocumento_lang`.`id_record` AND `co_tipidocumento_lang`.`id_lang` = '.prepare(Models\Locale::getDefault()->id).') WHERE `enabled` = 1 AND `dir` = '.prepare($dir).' ORDER BY `codice_tipo_documento_fe`", "value": "'.$idtipodocumento.'" ]}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
|
@ -122,10 +130,10 @@ if (!empty($options['create_document'])) {
|
|||
}
|
||||
|
||||
// Opzioni aggiuntive per gli Interventi
|
||||
elseif ($final_module['name'] == 'Interventi') {
|
||||
elseif ($final_module->getTranslation('title') == 'Attività') {
|
||||
echo '
|
||||
<div class="col-md-6">
|
||||
{[ "type": "select", "label": "'.tr('Stato').'", "name": "id_stato_intervento", "required": 1, "values": "query=SELECT idstatointervento AS id, descrizione, colore AS _bgcolor_ FROM in_statiintervento WHERE deleted_at IS NULL AND is_completato = 0 ORDER BY descrizione" ]}
|
||||
{[ "type": "select", "label": "'.tr('Stato').'", "name": "id_stato_intervento", "required": 1, "values": "query=SELECT `in_statiintervento`.`id`, `in_statiintervento_lang`.`title` as `descrizione`, `colore` AS _bgcolor_ FROM `in_statiintervento` LEFT JOIN `in_statiintervento_lang` ON (`in_statiintervento`.`id` = `in_statiintervento_lang`.`id_record` AND `in_statiintervento_lang`.`id_lang` = '.prepare(Models\Locale::getDefault()->id).') WHERE `deleted_at` IS NULL AND `is_completato` = 0 ORDER BY `title`" ]}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
|
@ -134,36 +142,36 @@ if (!empty($options['create_document'])) {
|
|||
}
|
||||
|
||||
// Opzioni aggiuntive per i Contratti
|
||||
elseif ($final_module['name'] == 'Contratti') {
|
||||
$stato_predefinito = $database->fetchOne("SELECT * FROM co_staticontratti WHERE descrizione = 'Bozza'");
|
||||
elseif ($final_module->getTranslation('title') == 'Contratti') {
|
||||
$stato_predefinito = StatoContratto::where('name', 'Bozza')->first()->id;
|
||||
|
||||
echo '
|
||||
<div class="col-md-6">
|
||||
{[ "type": "select", "label": "'.tr('Stato').'", "name": "id_stato", "required": 1, "values": "query=SELECT id, descrizione FROM co_staticontratti", "value": "'.$stato_predefinito['id'].'" ]}
|
||||
{[ "type": "select", "label": "'.tr('Stato').'", "name": "id_stato", "required": 1, "values": "query=SELECT `co_staticontratti`.`id`, `co_staticontratti_lang`.`title` AS descrizione FROM `co_staticontratti` LEFT JOIN `co_staticontratti_lang` ON (`co_staticontratti`.`id` = `co_staticontratti_lang`.`id_record` AND `co_staticontratti_lang`.`id_lang` = '.prepare(Models\Locale::getDefault()->id).')", "value": "'.$stato_predefinito.'" ]}
|
||||
</div>';
|
||||
}
|
||||
|
||||
// Opzioni aggiuntive per i DDT
|
||||
elseif (in_array($final_module['name'], ['Ddt di vendita', 'Ddt di acquisto'])) {
|
||||
$stato_predefinito = $database->fetchOne("SELECT * FROM dt_statiddt WHERE descrizione = 'Bozza'");
|
||||
elseif (in_array($final_module->getTranslation('title'), ['Ddt in uscita', 'Ddt in entrata'])) {
|
||||
$stato_predefinito = Stato::where('name', 'Bozza')->first()->id;
|
||||
|
||||
echo '
|
||||
<div class="col-md-6">
|
||||
{[ "type": "select", "label": "'.tr('Stato').'", "name": "id_stato", "required": 1, "values": "query=SELECT * FROM dt_statiddt", "value": "'.$stato_predefinito['id'].'" ]}
|
||||
{[ "type": "select", "label": "'.tr('Stato').'", "name": "id_stato", "required": 1, "values": "query=SELECT `dt_statiddt`.*, `dt_statiddt_lang`.`title` AS descrizione FROM `dt_statiddt` LEFT JOIN `dt_statiddt_lang` ON (`dt_statiddt`.`id` = `dt_statiddt_lang`.`id_record` AND `dt_statiddt_lang`.`id_lang` = '.prepare(Models\Locale::getDefault()->id).')", "value": "'.$stato_predefinito.'" ]}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{[ "type": "select", "label": "'.tr('Causale trasporto').'", "name": "id_causale_trasporto", "required": 1, "ajax-source": "causali", "icon-after": "add|'.Modules::get('Causali')['id'].'", "help": "'.tr('Definisce la causale del trasporto').'" ]}
|
||||
{[ "type": "select", "label": "'.tr('Causale trasporto').'", "name": "id_causale_trasporto", "required": 1, "ajax-source": "causali", "icon-after": "add|'.Module::where('name', 'Causali')->first()->id.'", "help": "'.tr('Definisce la causale del trasporto').'" ]}
|
||||
</div>';
|
||||
}
|
||||
|
||||
// Opzioni aggiuntive per gli Ordini
|
||||
elseif (in_array($final_module['name'], ['Ordini cliente', 'Ordini fornitore'])) {
|
||||
$stato_predefinito = $database->fetchOne("SELECT * FROM or_statiordine WHERE descrizione = 'Bozza'");
|
||||
elseif (in_array($final_module->getTranslation('title'), ['Ordini cliente', 'Ordini fornitore'])) {
|
||||
$stato_predefinito = StatoOrdine::where('name', 'Bozza')->first()->id;
|
||||
|
||||
echo '
|
||||
<div class="col-md-6">
|
||||
{[ "type": "select", "label": "'.tr('Stato').'", "name": "id_stato", "required": 1, "values": "query=SELECT * FROM or_statiordine WHERE descrizione IN(\'Bozza\', \'Accettato\', \'In attesa di conferma\', \'Annullato\')", "value": "'.$stato_predefinito['id'].'" ]}
|
||||
{[ "type": "select", "label": "'.tr('Stato').'", "name": "id_stato", "required": 1, "values": "query=SELECT * ,`or_statiordine`.`id`, `or_statiordine_lang`.`title` AS descrizione FROM `or_statiordine` LEFT JOIN `or_statiordine_lang` ON (`or_statiordine`.`id` = `or_statiordine_lang`.`id_record` AND `or_statiordine_lang`.`id_lang` = '.prepare(Models\Locale::getDefault()->id).') WHERE `title` IN(\'Bozza\', \'Accettato\', \'In attesa di conferma\', \'Annullato\')", "value": "'.$stato_predefinito.'" ]}
|
||||
</div>';
|
||||
}
|
||||
|
||||
|
@ -174,13 +182,13 @@ if (!empty($options['create_document'])) {
|
|||
|
||||
echo '
|
||||
<div class="col-md-6">
|
||||
{[ "type": "select", "label": "'.$tipo_anagrafica.'", "name": "idanagrafica", "required": 1, "ajax-source": "'.$ajax.'", "icon-after": "add|'.Modules::get('Anagrafiche')['id'].'|tipoanagrafica='.$tipo_anagrafica.'" ]}
|
||||
{[ "type": "select", "label": "'.$tipo_anagrafica.'", "name": "idanagrafica", "required": 1, "ajax-source": "'.$ajax.'", "icon-after": "add|'.Module::where('name', 'Anagrafiche')->first()->id.'|tipoanagrafica='.$tipo_anagrafica.'" ]}
|
||||
</div>';
|
||||
}
|
||||
|
||||
echo '
|
||||
<div class="col-md-6">
|
||||
{[ "type": "select", "label": "'.tr('Sezionale').'", "name": "id_segment", "required": 1, "ajax-source": "segmenti", "select-options": '.json_encode(['id_module' => $final_module['id'], 'is_sezionale' => 1]).', "value": "'.$id_segment.'" ]}
|
||||
{[ "type": "select", "label": "'.tr('Sezionale').'", "name": "id_segment", "required": 1, "ajax-source": "segmenti", "select-options": '.json_encode(['id_module' => $final_module->id, 'is_sezionale' => 1]).', "value": "'.$database->selectOne('co_tipidocumento', 'id_segment', ['id' => $idtipodocumento])['id_segment'].'" ]}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -188,7 +196,7 @@ if (!empty($options['create_document'])) {
|
|||
}
|
||||
|
||||
// Conto, rivalsa INPS, ritenuta d'acconto e ritenuta previdenziale
|
||||
if (in_array($final_module['name'], ['Fatture di vendita', 'Fatture di acquisto']) && !in_array($original_module['name'], ['Fatture di vendita', 'Fatture di acquisto'])) {
|
||||
if (in_array($final_module->getTranslation('title'), ['Fatture di vendita', 'Fatture di acquisto']) && !in_array($original_module->getTranslation('title'), ['Fatture di vendita', 'Fatture di acquisto'])) {
|
||||
$id_rivalsa_inps = setting('Cassa previdenziale predefinita');
|
||||
if ($dir == 'uscita') {
|
||||
$id_ritenuta_acconto = $documento->anagrafica->id_ritenuta_acconto_acquisti;
|
||||
|
@ -205,11 +213,11 @@ if (in_array($final_module['name'], ['Fatture di vendita', 'Fatture di acquisto'
|
|||
}
|
||||
|
||||
echo '
|
||||
<div class="box box-info">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">'.tr('Opzioni generali delle righe').'</h3>
|
||||
<div class="card card-info">
|
||||
<div class="card-header with-border">
|
||||
<h3 class="card-title">'.tr('Opzioni generali delle righe').'</h3>
|
||||
</div>
|
||||
<div class="box-body">';
|
||||
<div class="card-body">';
|
||||
|
||||
echo '
|
||||
<div class="row">';
|
||||
|
@ -273,12 +281,12 @@ if (!empty($options['serials'])) {
|
|||
|
||||
// Righe del documento
|
||||
echo '
|
||||
<div class="box box-success">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">'.tr('Righe da importare').'</h3>
|
||||
<div class="card card-success">
|
||||
<div class="card-header with-border">
|
||||
<h3 class="card-title">'.tr('Righe da importare').'</h3>
|
||||
</div>
|
||||
|
||||
<table class="box-body table table-striped table-hover table-condensed">
|
||||
<table class="card-body table table-striped table-hover table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="2%"><input id="import_all" type="checkbox" checked/></th>
|
||||
|
@ -298,14 +306,14 @@ echo '
|
|||
<tbody id="righe_documento_importato">';
|
||||
|
||||
foreach ($righe as $i => $riga) {
|
||||
if ($final_module['name'] == 'Ordini fornitore') {
|
||||
if ($final_module->getTranslation('title') == 'Ordini fornitore') {
|
||||
$qta_rimanente = $riga['qta'];
|
||||
} else {
|
||||
$qta_rimanente = $riga['qta_rimanente'];
|
||||
}
|
||||
|
||||
$attr = 'checked="checked"';
|
||||
if ($original_module['name'] == 'Preventivi') {
|
||||
if ($original_module->getTranslation('title') == 'Preventivi') {
|
||||
if (empty($riga['confermato']) && $riga['is_descrizione'] == 0) {
|
||||
$attr = '';
|
||||
}
|
||||
|
@ -420,15 +428,15 @@ echo '
|
|||
// Elenco righe evase completametne
|
||||
if (!$righe_evase->isEmpty()) {
|
||||
echo '
|
||||
<div class="box box-info collapsable collapsed-box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">'.tr('Righe evase completamente').'</h3>
|
||||
<div class="box-tools pull-right">
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-plus"></i></button>
|
||||
<div class="card card-info collapsable collapsed-card">
|
||||
<div class="card-header with-border">
|
||||
<h3 class="card-title">'.tr('Righe evase completamente').'</h3>
|
||||
<div class="card-tools pull-right">
|
||||
<button type="button" class="btn btn-tool" data-widget="collapse"><i class="fa fa-plus"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="box-body table table-striped table-hover table-condensed">
|
||||
<table class="card-body table table-striped table-hover table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>'.tr('Descrizione').'</th>
|
||||
|
@ -490,7 +498,7 @@ foreach ($articoli as $elenco) {
|
|||
$qta = $elenco->sum('qta');
|
||||
$articolo = $elenco->first()->articolo;
|
||||
|
||||
$descrizione_riga = $articolo->codice.' - '.$articolo->descrizione;
|
||||
$descrizione_riga = $articolo->codice.' - '.$articolo->getTranslation('title');
|
||||
$text = $articolo ? Modules::link('Articoli', $articolo->id, $descrizione_riga) : $descrizione_riga;
|
||||
|
||||
$scorte[$articolo->id] = [
|
||||
|
|
|
@ -17,8 +17,11 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
$articolo = $database->selectOne('mg_articoli', '*', ['id' => $result['idarticolo']]);
|
||||
$width = $options['dir'] == 'uscita' && $articolo['fattore_um_secondaria'] ? 3 : 4;
|
||||
use Models\Module;
|
||||
use Modules\Articoli\Articolo;
|
||||
|
||||
$articolo = Articolo::find($result['idarticolo']);
|
||||
$width = $options['dir'] == 'uscita' && $articolo->fattore_um_secondaria ? 3 : 4;
|
||||
|
||||
// Descrizione
|
||||
echo App::internalLoad('descrizione.php', $result, $options);
|
||||
|
@ -42,14 +45,14 @@ echo '
|
|||
// Unità di misura
|
||||
echo '
|
||||
<div class="col-md-'.$width.'">
|
||||
{[ "type": "select", "label": "'.tr('Unità di misura').'", "icon-after": "add|'.Modules::get('Unità di misura')['id'].'", "name": "um", "value": "'.$result['um'].'", "ajax-source": "misure" ]}
|
||||
{[ "type": "select", "label": "'.tr('Unità di misura').'", "icon-after": "add|'.Module::where('name', 'Unità di misura')->first()->id.'", "name": "um", "value": "'.$result['um'].'", "ajax-source": "misure" ]}
|
||||
</div>';
|
||||
|
||||
// Unità di misura
|
||||
if ($options['dir'] == 'uscita' && $articolo['fattore_um_secondaria']) {
|
||||
if ($options['dir'] == 'uscita' && $articolo->fattore_um_secondaria) {
|
||||
echo '
|
||||
<div class="col-md-3">
|
||||
{[ "type": "number", "label": "'.tr('Q.tà secondaria').'", "name": "fattore_um_secondaria", "value": "'.abs((float) $articolo['fattore_um_secondaria'] * $result['qta']).'", "icon-after": "'.$articolo['um_secondaria'].'" ]}
|
||||
{[ "type": "number", "label": "'.tr('Q.tà secondaria').'", "name": "fattore_um_secondaria", "value": "'.abs((float) $articolo->fattore_um_secondaria * $result['qta']).'", "icon-after": "'.$articolo->um_secondaria.'" ]}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
@ -129,7 +132,7 @@ if ($options['dir'] == 'entrata') {
|
|||
mediaponderata = parseFloat($("#idarticolo").selectData().media_ponderata);
|
||||
}
|
||||
|
||||
div.html("<table class=\"table table-extra-condensed table-margine\" style=\"margin-top:-13px;\" >\
|
||||
div.html("<table class=\"table table-extra-condensed table-margine\" style=\"margin-top:-25px;\" >\
|
||||
<tr>\
|
||||
<td>\
|
||||
<small> '.tr('Guadagno').':</small>\
|
||||
|
@ -178,10 +181,10 @@ if ($options['dir'] == 'entrata') {
|
|||
|
||||
if (guadagno < 0) {
|
||||
parent.addClass("has-error");
|
||||
$(".table-margine").addClass("label-danger").removeClass("label-success");
|
||||
$(".table-margine").addClass("badge-danger").removeClass("badge-success");
|
||||
} else {
|
||||
parent.removeClass("has-error");
|
||||
$(".table-margine").removeClass("label-danger").addClass("label-success");
|
||||
$(".table-margine").removeClass("badge-danger").addClass("badge-success");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,7 +228,7 @@ if ($options['dir'] == 'entrata') {
|
|||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-offset-4 col-md-4 minimo_vendita text-center"></div>
|
||||
<div class="offset-md-4 col-md-4 minimo_vendita text-center"></div>
|
||||
</div>';
|
||||
} else {
|
||||
echo '
|
||||
|
@ -238,11 +241,11 @@ if ($options['dir'] == 'entrata') {
|
|||
|
||||
// Data prevista evasione (per ordini)
|
||||
|
||||
if (in_array($module['name'], ['Ordini cliente', 'Ordini fornitore', 'Preventivi'])) {
|
||||
if (in_array($module->getTranslation('title'), ['Ordini cliente', 'Ordini fornitore', 'Preventivi'])) {
|
||||
if ($options['action'] == 'add') {
|
||||
if ($module['name'] == 'Ordini cliente') {
|
||||
if ($module->getTranslation('title') == 'Ordini cliente') {
|
||||
$confermato = setting('Conferma automaticamente le quantità negli ordini cliente');
|
||||
} elseif ($module['name'] == 'Ordini fornitore') {
|
||||
} elseif ($module->getTranslation('title') == 'Ordini fornitore') {
|
||||
$confermato = setting('Conferma automaticamente le quantità negli ordini fornitore');
|
||||
} else {
|
||||
$confermato = setting('Conferma automaticamente le quantità nei preventivi');
|
||||
|
@ -251,15 +254,15 @@ if (in_array($module['name'], ['Ordini cliente', 'Ordini fornitore', 'Preventivi
|
|||
$confermato = $result['confermato'];
|
||||
}
|
||||
echo '
|
||||
<div class="box box-info collapsable collapsed-box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">'.tr('Informazioni aggiuntive').'</h3>
|
||||
<div class="box-tools pull-right">
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-plus"></i></button>
|
||||
<div class="card card-info collapsable collapsed-card">
|
||||
<div class="card-header with-border">
|
||||
<h3 class="card-title">'.tr('Informazioni aggiuntive').'</h3>
|
||||
<div class="card-tools pull-right">
|
||||
<button type="button" class="btn btn-tool" data-widget="collapse"><i class="fa fa-plus"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box-body">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
{[ "type": "date", "label": "'.tr('Data prevista evasione').'", "name": "data_evasione", "value": "'.$result['data_evasione'].'" ]}
|
||||
|
@ -276,7 +279,7 @@ if (in_array($module['name'], ['Ordini cliente', 'Ordini fornitore', 'Preventivi
|
|||
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
{[ "type": "checkbox", "label": "'.tr('Articolo confermato').'", "name": "confermato", "value": "'.$confermato.'", "help": "'.tr('Articolo confermato dal _ANA_ e che è possibile evadere', ['_ANA_' => $module['name'] == 'Ordini fornitore' ? tr('fornitore') : tr('cliente')]).'" ]}
|
||||
{[ "type": "checkbox", "label": "'.tr('Articolo confermato').'", "name": "confermato", "value": "'.$confermato.'", "help": "'.tr('Articolo confermato dal _ANA_ e che è possibile evadere', ['_ANA_' => $module->getTranslation('title') == 'Ordini fornitore' ? tr('fornitore') : tr('cliente')]).'" ]}
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
{[ "type": "checkbox", "label": "'.tr('Cambia stato a tutte le righe').'", "name": "confermato_all", "value": "" ]}
|
||||
|
@ -303,7 +306,7 @@ if (in_array($module['name'], ['Ordini cliente', 'Ordini fornitore', 'Preventivi
|
|||
</script>';
|
||||
}
|
||||
|
||||
if (in_array($module['name'], ['Fatture di vendita', 'Fatture di acquisto'])) {
|
||||
if (in_array($module->getTranslation('title'), ['Fatture di vendita', 'Fatture di acquisto'])) {
|
||||
echo '
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
|
@ -338,15 +341,15 @@ if (in_array($module['name'], ['Fatture di vendita', 'Fatture di acquisto'])) {
|
|||
if (prezzo_unitario < 0) {
|
||||
if (input("is_nota").get() == true) {
|
||||
if (input("dir").get() == "entrata") {
|
||||
div.html(`<small class="label label-warning"><i class="fa fa-exclamation-triangle"></i> '.tr('Importo a credito').'</small>`);
|
||||
div.html(`<span class="right badge badge-warning"><i class="fa fa-exclamation-triangle"></i> '.tr('Importo a credito').'</small>`);
|
||||
} else {
|
||||
div.html(`<small class="label label-warning"><i class="fa fa-exclamation-triangle"></i> '.tr('Importo a debito').'</small>`);
|
||||
div.html(`<span class="right badge badge-warning"><i class="fa fa-exclamation-triangle"></i> '.tr('Importo a debito').'</small>`);
|
||||
}
|
||||
} else {
|
||||
if (input("dir").get() == "entrata") {
|
||||
div.html(`<small class="label label-warning"><i class="fa fa-exclamation-triangle"></i> '.tr('Importo a debito').'</small>`);
|
||||
div.html(`<span class="right badge badge-warning"><i class="fa fa-exclamation-triangle"></i> '.tr('Importo a debito').'</small>`);
|
||||
} else {
|
||||
div.html(`<small class="label label-warning"><i class="fa fa-exclamation-triangle"></i> '.tr('Importo a credito').'</small>`);
|
||||
div.html(`<span class="right badge badge-warning"><i class="fa fa-exclamation-triangle"></i> '.tr('Importo a credito').'</small>`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -365,12 +368,12 @@ if (in_array($module['name'], ['Fatture di vendita', 'Fatture di acquisto'])) {
|
|||
div_margine.css("margin-top", "-20px");
|
||||
div_prezzi.css("margin-top", "-20px");
|
||||
div_prezzi.css("margin-bottom", "20px");
|
||||
div.html(`<small class="label label-default" >'.tr('Sconto').'</small>`);
|
||||
div.html(`<span class="right badge badge-default" >'.tr('Sconto').'</small>`);
|
||||
} else if (sconto < 0) {
|
||||
div_margine.css("margin-top", "-20px");
|
||||
div_prezzi.css("margin-top", "-20px");
|
||||
div_prezzi.css("margin-bottom", "20px");
|
||||
div.html(`<small class="label label-default" >'.tr('Maggiorazione').'</small>`);
|
||||
div.html(`<span class="right badge badge-default" >'.tr('Maggiorazione').'</small>`);
|
||||
} else {
|
||||
div_margine.css("margin-top", "0px");
|
||||
div_prezzi.css("margin-top", "0px");
|
||||
|
|
|
@ -74,9 +74,9 @@ echo '
|
|||
}
|
||||
|
||||
if (sconto > 0) {
|
||||
div.html(`<small class="label label-default" >'.tr('Sconto').'</small>`);
|
||||
div.html(`<span class="right badge badge-default" >'.tr('Sconto').'</small>`);
|
||||
} else if (sconto < 0) {
|
||||
div.html(`<small class="label label-default" >'.tr('Maggiorazione').'</small>`);
|
||||
div.html(`<span class="right badge badge-default" >'.tr('Maggiorazione').'</small>`);
|
||||
} else {
|
||||
div.html("");
|
||||
}
|
||||
|
@ -94,9 +94,9 @@ echo '
|
|||
}
|
||||
|
||||
if (sconto > 0) {
|
||||
div.html(`<small class="label label-default" >'.tr('Sconto').'</small>`);
|
||||
div.html(`<span class="right badge badge-default" >'.tr('Sconto').'</small>`);
|
||||
} else if (sconto < 0) {
|
||||
div.html(`<small class="label label-default" >'.tr('Maggiorazione').'</small>`);
|
||||
div.html(`<span class="right badge badge-default" >'.tr('Maggiorazione').'</small>`);
|
||||
} else {
|
||||
div.html("");
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ $pageTitle = tr('Configurazione');
|
|||
include_once App::filepath('include|custom|', 'top.php');
|
||||
|
||||
// Controllo sull'esistenza di nuovi parametri di configurazione
|
||||
if (post('db_host') !== null) {
|
||||
if (!empty(post('db_host'))) {
|
||||
$db_host = $_POST['db_host']; // Fix per evitare la conversione in numero
|
||||
$db_name = post('db_name');
|
||||
$db_username = post('db_username');
|
||||
|
@ -47,11 +47,11 @@ if (post('db_host') !== null) {
|
|||
'db_username' => $db_username,
|
||||
'db_password' => $db_password,
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
} catch (Exception) {
|
||||
}
|
||||
|
||||
// Test della configurazione
|
||||
if (post('test') !== null) {
|
||||
if (!empty(post('test'))) {
|
||||
ob_end_clean();
|
||||
|
||||
if ($dbo->isConnected()) {
|
||||
|
@ -73,8 +73,8 @@ if (post('db_host') !== null) {
|
|||
$privileges = current($result);
|
||||
|
||||
if (
|
||||
string_contains($privileges, ' ON `'.$db_name.'`.*') ||
|
||||
string_contains($privileges, ' ON *.*')
|
||||
string_contains($privileges, ' ON `'.$db_name.'`.*')
|
||||
|| string_contains($privileges, ' ON *.*')
|
||||
) {
|
||||
$pieces = explode(', ', explode(' ON ', str_replace('GRANT ', '', $privileges))[0]);
|
||||
|
||||
|
@ -110,7 +110,7 @@ if (post('db_host') !== null) {
|
|||
}
|
||||
|
||||
echo $state;
|
||||
exit();
|
||||
exit;
|
||||
}
|
||||
|
||||
// Creazione della configurazione
|
||||
|
@ -141,11 +141,11 @@ if (post('db_host') !== null) {
|
|||
$creation = file_put_contents('config.inc.php', $new_config);
|
||||
if (!$creation) {
|
||||
echo '
|
||||
<div class="box box-center box-danger box-solid text-center">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">'.tr('Permessi di scrittura mancanti').'</h3>
|
||||
<div class="card card-center card-danger card-solid text-center">
|
||||
<div class="card-header with-border">
|
||||
<h3 class="card-title">'.tr('Permessi di scrittura mancanti').'</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="card-body">
|
||||
<p>'.tr('Sembra che non ci siano i permessi di scrittura sul file _FILE_', [
|
||||
'_FILE_' => '<b>config.inc.php</b>',
|
||||
]).'</p>
|
||||
|
@ -160,14 +160,14 @@ if (post('db_host') !== null) {
|
|||
<button class="btn btn-info"><i class="fa fa-repeat"></i> '.tr('Riprova').'</button>
|
||||
</form>
|
||||
<hr>
|
||||
<div class="box box-default collapsed-box">
|
||||
<div class="box-header with-border">
|
||||
<h4 class="box-title"><a class="clickable" data-widget="collapse">'.tr('Creazione manuale').'...</a></h4>
|
||||
<div class="box-tools pull-right">
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-plus"></i></button>
|
||||
<div class="card card-default collapsed-card">
|
||||
<div class="card-header with-border">
|
||||
<h4 class="card-title"><a class="clickable" data-widget="collapse">'.tr('Creazione manuale').'...</a></h4>
|
||||
<div class="card-tools pull-right">
|
||||
<button type="button" class="btn btn-tool" data-widget="collapse"><i class="fa fa-plus"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="card-body">
|
||||
<p>'.tr('Inserire il seguente testo nel file _FILE_', [
|
||||
'_FILE_' => '<b>config.inc.php</b>',
|
||||
]).'</p>
|
||||
|
@ -182,7 +182,7 @@ if (post('db_host') !== null) {
|
|||
// Creazione manifest.json
|
||||
include_once App::filepath('include/init', 'manifest.php');
|
||||
redirect(base_path().'/index.php');
|
||||
exit();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -190,11 +190,11 @@ if (post('db_host') !== null) {
|
|||
// Controlla che i parametri di configurazione permettano l'accesso al database
|
||||
if ((file_exists('config.inc.php') || $valid_config) && !$dbo->isConnected()) {
|
||||
echo '
|
||||
<div class="box box-center box-danger box-solid text-center">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">'.tr('Impossibile connettersi al database').'</h3>
|
||||
<div class="card card-center card-danger card-solid text-center">
|
||||
<div class="card-header with-border">
|
||||
<h3 class="card-title">'.tr('Impossibile connettersi al database').'</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="card-body">
|
||||
<p>'.tr('Si è verificato un errore durante la connessione al database').'.</p>
|
||||
<p>'.tr('Controllare di aver inserito correttamente i dati di accesso, e che il database atto ad ospitare i dati del gestionale sia esistente').'.</p>
|
||||
<a class="btn btn-info" href="'.base_path().'/index.php"><i class="fa fa-repeat"></i> '.tr('Riprova').'</a>
|
||||
|
@ -208,12 +208,12 @@ $img = App::getPaths()['img'];
|
|||
if (empty($creation) && (!file_exists('config.inc.php') || !$valid_config)) {
|
||||
if (file_exists('config.inc.php')) {
|
||||
echo '
|
||||
<div class="box box-center box-danger box-solid text-center">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">'.tr('Parametri non sufficienti!').'</h3>
|
||||
<div class="card card-center card-danger card-solid text-center">
|
||||
<div class="card-header with-border">
|
||||
<h3 class="card-title">'.tr('Parametri non sufficienti!').'</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<p>'.tr("L'avvio del software è fallito a causa dell'assenza di alcuni paramentri nella configurazione di base").'.</p>
|
||||
<div class="card-body">
|
||||
<p>'.tr("L'avvio del software è fallito a causa dell'assenza di alcuni parametri nella configurazione di base").'.</p>
|
||||
<p>'.tr("Si prega di controllare che il file _FILE_ contenga tutti i dati inseriti durante la configurazione iniziale (con l'eccezione di password e indirizzo email amministrativi)", [
|
||||
'_FILE_' => '<b>config.inc.php</b>',
|
||||
]).'.</p>
|
||||
|
@ -305,12 +305,12 @@ if (empty($creation) && (!file_exists('config.inc.php') || !$valid_config)) {
|
|||
</script>';
|
||||
|
||||
echo '
|
||||
<div class="box box-center-large box-warning">
|
||||
<div class="box-header with-border text-center">
|
||||
<div class="card card-center-large card-warning">
|
||||
<div class="card-header with-border text-center">
|
||||
<img src="'.$img.'/logo_completo.png" width="300" alt="'.tr('OSM Logo').'">
|
||||
</div>
|
||||
|
||||
<div class="box-body" id="smartwizard">
|
||||
<div class="card-body" id="smartwizard">
|
||||
<span class="pull-right col-md-4">
|
||||
<select class="form-control hide" id="language" required="1">';
|
||||
|
||||
|
@ -354,7 +354,7 @@ if (empty($creation) && (!file_exists('config.inc.php') || !$valid_config)) {
|
|||
$("#language").removeClass("hide");
|
||||
|
||||
$("#language").select2({
|
||||
theme: "bootstrap",
|
||||
theme: "bootstrap4",
|
||||
templateResult: function(item) {
|
||||
if (!item.id || !flag) {
|
||||
return item.text;
|
||||
|
@ -431,9 +431,12 @@ if (empty($creation) && (!file_exists('config.inc.php') || !$valid_config)) {
|
|||
// LICENZA
|
||||
echo '
|
||||
<div id="step-2">
|
||||
<p>'.tr('OpenSTAManager è tutelato dalla licenza _LICENSE_!', [
|
||||
<p>'.tr('OpenSTAManager è tutelato dalla licenza _LICENSE_', [
|
||||
'_LICENSE_' => 'GPL 3.0',
|
||||
]).'</p>
|
||||
]).':</p>
|
||||
|
||||
<textarea class="form-control autosize" rows="15" readonly>'.file_get_contents('LICENSE').'</textarea><br>
|
||||
<a class="pull-left" href="https://www.gnu.org/licenses/translations.en.html#GPL" target="_blank">[ '.tr('Versioni tradotte').' ]</a><hr>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
|
@ -445,10 +448,6 @@ if (empty($creation) && (!file_exists('config.inc.php') || !$valid_config)) {
|
|||
<label for="agree">'.tr('Ho visionato e accetto').'.</label>
|
||||
</form>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
<textarea class="form-control autosize" rows="15" readonly>'.file_get_contents('LICENSE').'</textarea><br>
|
||||
<a class="pull-left" href="https://www.gnu.org/licenses/translations.en.html#GPL" target="_blank">[ '.tr('Versioni tradotte').' ]</a><br><br>
|
||||
</div>';
|
||||
|
||||
$host = !empty($db_host) ? $db_host : '';
|
||||
|
@ -587,4 +586,4 @@ if (empty($creation) && (!file_exists('config.inc.php') || !$valid_config)) {
|
|||
|
||||
include_once App::filepath('include|custom|', 'bottom.php');
|
||||
|
||||
exit();
|
||||
exit;
|
||||
|
|
|
@ -19,14 +19,22 @@
|
|||
|
||||
include_once __DIR__.'/../../core.php';
|
||||
|
||||
use Models\Group;
|
||||
use Models\Module;
|
||||
use Models\Setting;
|
||||
use Modules\Anagrafiche\Tipo;
|
||||
|
||||
if (Update::isUpdateAvailable() || !$dbo->isInstalled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$has_azienda = $dbo->fetchNum("SELECT `an_anagrafiche`.`idanagrafica` FROM `an_anagrafiche`
|
||||
$id_tipo_azienda = Tipo::where('name', 'Azienda')->first()->id;
|
||||
|
||||
$has_azienda = $dbo->fetchNum('SELECT `an_anagrafiche`.`idanagrafica` FROM `an_anagrafiche`
|
||||
LEFT JOIN `an_tipianagrafiche_anagrafiche` ON `an_anagrafiche`.`idanagrafica`=`an_tipianagrafiche_anagrafiche`.`idanagrafica`
|
||||
LEFT JOIN `an_tipianagrafiche` ON `an_tipianagrafiche`.`idtipoanagrafica`=`an_tipianagrafiche_anagrafiche`.`idtipoanagrafica`
|
||||
WHERE `an_tipianagrafiche`.`descrizione` = 'Azienda' AND `an_anagrafiche`.`deleted_at` IS NULL") != 0;
|
||||
LEFT JOIN `an_tipianagrafiche` ON `an_tipianagrafiche`.`id`=`an_tipianagrafiche_anagrafiche`.`idtipoanagrafica`
|
||||
LEFT JOIN `an_tipianagrafiche_lang` ON (`an_tipianagrafiche`.`id`=`an_tipianagrafiche_lang`.`id_record` AND `an_tipianagrafiche_lang`.`id_lang`='.prepare(Models\Locale::getDefault()->id).')
|
||||
WHERE `an_tipianagrafiche`.`id` = '.$id_tipo_azienda.' AND `an_anagrafiche`.`deleted_at` IS NULL') != 0;
|
||||
$has_user = $dbo->fetchNum('SELECT `id` FROM `zz_users`') != 0;
|
||||
|
||||
$settings = [
|
||||
|
@ -66,7 +74,7 @@ if (post('action') == 'init') {
|
|||
// Azienda predefinita
|
||||
if (!$has_azienda) {
|
||||
Filter::set('post', 'op', 'add');
|
||||
$id_module = Modules::get('Anagrafiche')['id'];
|
||||
$id_module = Module::where('name', 'Anagrafiche')->first()->id;
|
||||
include base_dir().'/modules/anagrafiche/actions.php';
|
||||
|
||||
// Logo stampe
|
||||
|
@ -83,9 +91,7 @@ if (post('action') == 'init') {
|
|||
|
||||
// Utente amministratore
|
||||
if (!$has_user) {
|
||||
$admin = $dbo->selectOne('zz_groups', ['id'], [
|
||||
'nome' => 'Amministratori',
|
||||
]);
|
||||
$admin = Group::where('nome', '=', 'Amministratori')->first();
|
||||
|
||||
// Creazione utente Amministratore
|
||||
$dbo->insert('zz_users', [
|
||||
|
@ -93,7 +99,7 @@ if (post('action') == 'init') {
|
|||
'password' => Auth::hashPassword(post('admin_password')),
|
||||
'email' => post('admin_email'),
|
||||
'idgruppo' => $admin['id'],
|
||||
'idanagrafica' => isset($id_record) ? $id_record : 0,
|
||||
'idanagrafica' => $id_record ?? 0,
|
||||
'enabled' => 1,
|
||||
]);
|
||||
|
||||
|
@ -106,52 +112,57 @@ if (post('action') == 'init') {
|
|||
|
||||
if (!$has_settings) {
|
||||
foreach ($settings as $setting => $required) {
|
||||
$setting = Settings::get($setting);
|
||||
$setting = Setting::where('nome', '=', $setting)->first();
|
||||
|
||||
$value = post('setting')[$setting['id']];
|
||||
$value = post('setting')[$setting->id];
|
||||
if (!empty($value)) {
|
||||
Settings::setValue($setting['nome'], $value);
|
||||
Settings::setValue($setting->id, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
redirect(base_path(), 'js');
|
||||
exit();
|
||||
exit;
|
||||
}
|
||||
|
||||
$img = App::getPaths()['img'];
|
||||
|
||||
// Visualizzazione dell'interfaccia di impostazione iniziale, nel caso il file di configurazione sia mancante oppure i paramentri non siano sufficienti
|
||||
echo '
|
||||
<div class="box box-center-large box-warning">
|
||||
<div class="box-header with-border text-center">
|
||||
<div class="card card-center-large card-warning">
|
||||
<div class="card-header text-center">
|
||||
<img src="'.$img.'/logo_completo.png" class="logo-image" alt="'.tr('OSM Logo').'">
|
||||
</div>
|
||||
|
||||
<div class="box-body">
|
||||
<div class="card-body">
|
||||
<form action="" method="post" id="init-form" enctype="multipart/form-data">
|
||||
<input type="hidden" name="action" value="init">';
|
||||
|
||||
if (!$has_user) {
|
||||
echo '
|
||||
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">'.tr('Amministrazione').'</h3>
|
||||
<div class="card card-primary">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">'.tr('Amministrazione').'</h3>
|
||||
</div>
|
||||
|
||||
<div class="panel-body">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{[ "type": "text", "label": "'.tr('Username').'", "name": "admin_username", "value": "", "placeholder": "'.tr("Imposta l'username dell'amministratore").'", "required": 1 ]}
|
||||
<div class="col-md-4">
|
||||
<div class="form-group">
|
||||
<label for="admin_username">'.tr('Username').'</label>
|
||||
<input type="text" class="form-control" id="admin_username" name="admin_username" placeholder="'.tr("Imposta l'username dell'amministratore").'" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-4">
|
||||
{[ "type": "password", "label": "'.tr('Password').'", "id": "password", "name": "admin_password", "value": "", "placeholder": "'.tr("Imposta la password dell'amministratore").'", "required": 1, "strength": "#config" ]}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{[ "type": "email", "label": "'.tr('Email').'", "name": "admin_email", "value": "", "placeholder": "'.tr("Imposta l'indirizzo email dell'amministratore").'", "required": 1 ]}
|
||||
<div class="col-md-4">
|
||||
<div class="form-group">
|
||||
<label for="admin_email">'.tr('Email').'</label>
|
||||
<input type="email" class="form-control" id="admin_email" name="admin_email" placeholder="'.tr("Imposta l'indirizzo email dell'amministratore").'" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -160,15 +171,14 @@ if (!$has_user) {
|
|||
|
||||
if (!$has_azienda) {
|
||||
echo '
|
||||
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">'.tr('Azienda predefinita').'</h3>
|
||||
<div class="card card-primary">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">'.tr('Azienda predefinita').'</h3>
|
||||
</div>
|
||||
|
||||
<div class="panel-body" id="bs-popup">';
|
||||
<div class="card-body" id="bs-popup">';
|
||||
|
||||
$idtipoanagrafica = $dbo->fetchArray("SELECT idtipoanagrafica FROM an_tipianagrafiche WHERE descrizione='Azienda'")[0]['idtipoanagrafica'];
|
||||
$idtipoanagrafica = Tipo::where('name', 'Azienda')->first()->id;
|
||||
$readonly_tipo = true;
|
||||
|
||||
ob_start();
|
||||
|
@ -178,24 +188,27 @@ if (!$has_azienda) {
|
|||
echo str_replace('</form>', '', $anagrafica);
|
||||
|
||||
echo '
|
||||
<div class="box box-success collapsed-box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">'.tr('Logo stampe').'</h3>
|
||||
<div class="box-tools pull-right">
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse">
|
||||
<div class="card card-success collapsed-card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">'.tr('Logo stampe').'</h3>
|
||||
<div class="card-tools">
|
||||
<button type="button" class="btn btn-tool" data-card-widget="collapse">
|
||||
<i class="fa fa-plus"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-body collapse">
|
||||
<div class="card-body collapse">
|
||||
|
||||
<div class="col-md-12">
|
||||
{[ "type": "file", "placeholder": "'.tr('File').'", "name": "blob" ]}
|
||||
<div class="form-group">
|
||||
<label>'.tr('File').'</label>
|
||||
<input type="file" class="form-control" name="blob">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<p> </p><div class="col-md-12 alert alert-info text-center">'.tr('Per impostare il logo delle stampe, caricare un file ".jpg". Risoluzione consigliata 302x111 pixel').'.</div>
|
||||
|
||||
<p> </p>
|
||||
<div class="col-md-12 alert alert-info text-center">'.tr('Per impostare il logo delle stampe, caricare un file ".jpg". Risoluzione consigliata 302x111 pixel').'.
|
||||
</div>
|
||||
</div>
|
||||
</div>';
|
||||
|
||||
|
@ -206,35 +219,26 @@ if (!$has_azienda) {
|
|||
|
||||
if (!$has_settings) {
|
||||
echo '
|
||||
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">'.tr('Impostazioni di base').'</h3>
|
||||
<div class="card card-primary">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">'.tr('Impostazioni di base').'</h3>
|
||||
</div>
|
||||
|
||||
<div class="panel-body">';
|
||||
$i = 0;
|
||||
<div class="card-body">
|
||||
<div class="row">';
|
||||
foreach ($settings as $setting => $required) {
|
||||
if (empty(setting($setting))) {
|
||||
if ($i % 2 == 0 or $i == 0) {
|
||||
echo ' <div class="row">';
|
||||
}
|
||||
|
||||
echo '
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-4">
|
||||
'.Settings::input($setting, $required).'
|
||||
</div>';
|
||||
++$i;
|
||||
if ($i % 2 == 0 or $i == sizeof($settings)) {
|
||||
echo ' </div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo ' </div>
|
||||
</div>
|
||||
</div>';
|
||||
}
|
||||
|
||||
echo '
|
||||
<!-- PULSANTI -->
|
||||
<div class="row">
|
||||
|
@ -250,9 +254,8 @@ echo '
|
|||
|
||||
</form>
|
||||
</div>
|
||||
</div>';
|
||||
</div>
|
||||
|
||||
echo '
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$("button[type=submit]").not("#config").remove();
|
||||
|
@ -263,4 +266,4 @@ echo '
|
|||
|
||||
include_once App::filepath('include|custom|', 'bottom.php');
|
||||
|
||||
exit();
|
||||
exit;
|
||||
|
|
|
@ -24,17 +24,17 @@ if ($config['maintenance_ip'] != $_SERVER['REMOTE_ADDR']) {
|
|||
$img = App::getPaths()['img'];
|
||||
|
||||
echo '
|
||||
<div class="box box-center-large box-danger">
|
||||
<div class="box-header with-border text-center">
|
||||
<div class="card card-center-large card-danger">
|
||||
<div class="card-header with-border text-center">
|
||||
<img src="'.$img.'/logo_completo.png" width="300" alt="'.tr('OSM Logo').'">
|
||||
</div>
|
||||
|
||||
<div class="box-body">
|
||||
<div class="box box-center box-danger box-solid text-center">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">'.tr('Manutenzione in corso!').'</h3>
|
||||
<div class="card-body">
|
||||
<div class="card card-center card-danger card-solid text-center">
|
||||
<div class="card-header with-border">
|
||||
<h3 class="card-title">'.tr('Manutenzione in corso!').'</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="card-body">
|
||||
<p>'.tr('Il software si trova attualmente in modalità manutenzione, siete pregati di attendere sino alla conclusione dell\'intervento').'.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -43,5 +43,5 @@ if ($config['maintenance_ip'] != $_SERVER['REMOTE_ADDR']) {
|
|||
|
||||
include_once App::filepath('include|custom|', 'bottom.php');
|
||||
|
||||
exit();
|
||||
exit;
|
||||
}
|
||||
|
|
|
@ -46,11 +46,11 @@ if (!$creation) {
|
|||
file_put_contents('manifest.json', $manifest);
|
||||
} else {
|
||||
echo '
|
||||
<div class="box box-center box-danger box-solid text-center">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">'.tr('Permessi di scrittura mancanti').'</h3>
|
||||
<div class="card card-center card-danger card-solid text-center">
|
||||
<div class="card-header with-border">
|
||||
<h3 class="card-title">'.tr('Permessi di scrittura mancanti').'</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="card-body">
|
||||
<p>'.tr('Sembra che non ci siano i permessi di scrittura sul file _FILE_', [
|
||||
'_FILE_' => '<b>manifest.json</b>',
|
||||
]).'</p>
|
||||
|
|
|
@ -23,8 +23,27 @@ $modules = [
|
|||
'server' => 'HTTP_MOD_REWRITE',
|
||||
'description' => tr('Fornisce un sistema di riscrittura URL basato su regole predefinite'),
|
||||
],
|
||||
'mod_mime' => [
|
||||
'server' => 'text/javascript mjs',
|
||||
'description' => tr('Consente di associare i tipi di file ai tipi di contenuto corretti.'),
|
||||
],
|
||||
];
|
||||
|
||||
$sapi_name = php_sapi_name();
|
||||
$php_interface = '';
|
||||
$php_interface = match (true) {
|
||||
str_contains($sapi_name, 'apache') => 'apache',
|
||||
str_contains($sapi_name, 'fpm-fcgi') => 'fpm-fcgi',
|
||||
str_contains($sapi_name, 'fpm') => 'fpm',
|
||||
str_contains($sapi_name, 'cgi-fcgi') => 'cgi-fcgi',
|
||||
str_contains($sapi_name, 'cgi') => 'cgi',
|
||||
str_contains($sapi_name, 'cli') => 'cli',
|
||||
str_contains($sapi_name, 'embed') => 'embed',
|
||||
str_contains($sapi_name, 'litespeed') => 'litespeed',
|
||||
str_contains($sapi_name, 'isapi') => 'isapi',
|
||||
default => 'n.d.',
|
||||
};
|
||||
|
||||
if (function_exists('apache_get_modules')) {
|
||||
$available_modules = apache_get_modules();
|
||||
}
|
||||
|
@ -35,6 +54,15 @@ foreach ($modules as $name => $values) {
|
|||
|
||||
$status = isset($available_modules) ? in_array($name, $available_modules) : $_SERVER[$values['server']] == 'On';
|
||||
|
||||
if ($name == 'mod_mime' && $php_interface != 'apache') {
|
||||
$headers = get_headers((!empty($config['redirectHTTPS']) && !isHTTPS(true)) ? 'https://' : 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'], true);
|
||||
if (isset($headers['Content-Type'])) {
|
||||
$status = 1;
|
||||
} else {
|
||||
$status = 0;
|
||||
}
|
||||
}
|
||||
|
||||
$apache[] = [
|
||||
'name' => $name,
|
||||
'description' => $description,
|
||||
|
@ -43,13 +71,13 @@ foreach ($modules as $name => $values) {
|
|||
];
|
||||
}
|
||||
|
||||
//PHP
|
||||
// PHP
|
||||
$settings = [
|
||||
'php_version' => [
|
||||
'type' => 'version',
|
||||
'description' => '7.3.x - 8.0.x, consigliato almeno 7.4.x',
|
||||
'minimum' => '7.3.0',
|
||||
'maximum' => '8.0.99',
|
||||
'description' => '8.0.x - 8.3.x',
|
||||
'minimum' => '8.0.0',
|
||||
'maximum' => '8.3.99',
|
||||
],
|
||||
|
||||
'zip' => [
|
||||
|
@ -97,10 +125,10 @@ $settings = [
|
|||
'description' => tr('Permette la creazione dell\'immagine della firma per il rapportino d\'intervento (facoltativo)'),
|
||||
],
|
||||
|
||||
//'display_errors' => [
|
||||
// 'display_errors' => [
|
||||
// 'type' => 'value',
|
||||
// 'description' => true,
|
||||
//],
|
||||
// ],
|
||||
|
||||
'allow_url_fopen' => [
|
||||
'type' => 'value',
|
||||
|
@ -121,6 +149,11 @@ $settings = [
|
|||
'type' => 'value',
|
||||
'description' => '>5000',
|
||||
],
|
||||
|
||||
'exec' => [
|
||||
'type' => 'function',
|
||||
'description' => tr('Permette di importare file con estensione .p7m'),
|
||||
],
|
||||
];
|
||||
|
||||
$php = [];
|
||||
|
@ -136,6 +169,8 @@ foreach ($settings as $name => $values) {
|
|||
$status = ((version_compare(phpversion(), $values['minimum'], '>=') && version_compare(phpversion(), $values['maximum'], '<=')) ? 1 : 0);
|
||||
} elseif ($values['type'] == 'ext') {
|
||||
$status = extension_loaded($name);
|
||||
} elseif ($values['type'] == 'function') {
|
||||
$status = ((function_exists($name) && is_callable($name)) ? 1 : 0);
|
||||
} else {
|
||||
$ini = str_replace(['k', 'M'], ['000', '000000'], ini_get($name));
|
||||
$real = str_replace(['k', 'M'], ['000', '000000'], $description);
|
||||
|
@ -160,12 +195,12 @@ foreach ($settings as $name => $values) {
|
|||
]);
|
||||
}
|
||||
|
||||
$type = ($values['type'] == 'ext') ? tr('Estensione') : tr('Impostazione');
|
||||
|
||||
if ($values['type'] == 'ext') {
|
||||
$type = tr('Estensione');
|
||||
} elseif ($values['type'] == 'version') {
|
||||
$type = tr('Versione');
|
||||
} elseif ($values['type'] == 'function') {
|
||||
$type = tr('Funzione');
|
||||
} else {
|
||||
$type = tr('Impostazione');
|
||||
}
|
||||
|
@ -180,12 +215,14 @@ foreach ($settings as $name => $values) {
|
|||
|
||||
// MySQL
|
||||
if ($database->isInstalled()) {
|
||||
if (method_exists($database, 'isMySQL')) {
|
||||
$db = [
|
||||
'mysql_version' => [
|
||||
'type' => 'version',
|
||||
'description' => '5.7.x - 8.0.x',
|
||||
'minimum' => '5.7.0',
|
||||
'maximum' => '8.0.99',
|
||||
'warning' => $database->isMySQL() ? false : true,
|
||||
'description' => $database->isMySQL() ? '5.7.x - 8.0.x' : '10.x',
|
||||
'minimum' => $database->isMySQL() ? '5.7.0' : '10.1.0',
|
||||
'maximum' => $database->isMySQL() ? '8.3.99' : '10.6.99',
|
||||
],
|
||||
|
||||
'sort_buffer_size' => [
|
||||
|
@ -193,6 +230,14 @@ if ($database->isInstalled()) {
|
|||
'description' => '>2M',
|
||||
],
|
||||
];
|
||||
} else {
|
||||
$db = [
|
||||
'sort_buffer_size' => [
|
||||
'type' => 'value',
|
||||
'description' => '>2M',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/*foreach (App::getConfig()['db_options'] as $n => $v){
|
||||
|
||||
|
@ -208,6 +253,8 @@ if ($database->isInstalled()) {
|
|||
}*/
|
||||
}
|
||||
|
||||
$mysql = [];
|
||||
|
||||
foreach ($db as $name => $values) {
|
||||
$description = $values['description'];
|
||||
|
||||
|
@ -219,10 +266,15 @@ foreach ($db as $name => $values) {
|
|||
]);
|
||||
|
||||
$status = ((version_compare($database->getMySQLVersion(), $values['minimum'], '>=') && version_compare($database->getMySQLVersion(), $values['maximum'], '<=')) ? 1 : 0);
|
||||
|
||||
if ($values['warning'] && $status == 1) {
|
||||
$status = 0;
|
||||
$description .= '. <i class="fa fa-exclamation-triangle text-danger" ></i><b> '.tr('Al momento MariaDB _MYSQL_VERSION_ non è completamente supportato, si consiglia di passare a MySQL.', ['_MYSQL_VERSION_' => $database->getMySQLVersion()]).'</b>';
|
||||
}
|
||||
} else {
|
||||
$type = tr('Impostazione');
|
||||
|
||||
//Vedo se riesco a recuperare l'impostazione dalle variabili di sessione o globali di mysql
|
||||
// Vedo se riesco a recuperare l'impostazione dalle variabili di sessione o globali di mysql
|
||||
$rs_session_variabile = $dbo->fetchArray('SHOW SESSION VARIABLES LIKE '.prepare($name));
|
||||
$rs_global_variabile = $dbo->fetchArray('SHOW GLOBAL VARIABLES LIKE '.prepare($name));
|
||||
|
||||
|
@ -252,7 +304,7 @@ foreach ($db as $name => $values) {
|
|||
|
||||
$description = tr('Valore consigliato: _VALUE_ (Valore attuale: _INC_)', [
|
||||
'_VALUE_' => $description,
|
||||
'_INC_' => \Util\FileSystem::formatBytes($inc),
|
||||
'_INC_' => Util\FileSystem::formatBytes($inc),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -266,7 +318,6 @@ foreach ($db as $name => $values) {
|
|||
|
||||
// Percorsi di servizio
|
||||
$dirs_to_check = [
|
||||
'backup' => tr('Necessario per il salvataggio dei backup'),
|
||||
'files' => tr('Necessario per il salvataggio di file inseriti dagli utenti'),
|
||||
'files/temp' => tr('Necessario per la generazione delle stampe'),
|
||||
'logs' => tr('Necessario per la gestione dei file di log'),
|
||||
|
@ -287,14 +338,16 @@ foreach ($dirs_to_check as $name => $description) {
|
|||
// File di servizio
|
||||
$files_to_check = [
|
||||
'manifest.json' => tr('Necessario per l\'aggiunta a schermata home da terminale (creato al termine della configurazione)'),
|
||||
'database_5_7.json' => tr('Necessario per il controllo integrità con database MySQL 5.7.x'),
|
||||
'database.json' => tr('Necessario per il controllo integrità con database MySQL 8.0.x'),
|
||||
'mariadb_10_x.json' => tr('Necessario per il controllo integrità con database MariaDB 10.x'),
|
||||
'mysql_5_7.json' => tr('Necessario per il controllo integrità con database MySQL 5.7.x'),
|
||||
'mysql.json' => tr('Necessario per il controllo integrità con database MySQL 8.0.x'),
|
||||
'checksum.json' => tr('Necessario per il controllo integrità dei files del gestionale'),
|
||||
'settings.json' => tr('Necessario per il controllo delle impostazioni del gestionale'),
|
||||
];
|
||||
|
||||
$files = [];
|
||||
foreach ($files_to_check as $name => $description) {
|
||||
$status = is_writable(base_dir().DIRECTORY_SEPARATOR.$name);
|
||||
$status = is_readable(base_dir().DIRECTORY_SEPARATOR.$name);
|
||||
|
||||
$files[] = [
|
||||
'name' => $name,
|
||||
|
@ -344,11 +397,11 @@ foreach ($config_to_check as $name => $values) {
|
|||
if ($type == 'value') {
|
||||
$description = tr('Valore consigliato: _SUGGESTED_ (Valore attuale: _ACTUAL_)', [
|
||||
'_SUGGESTED_' => $values['suggested_value'],
|
||||
'_ACTUAL_' => (!empty($values['section']) ? ${$values['section']}[$name] : $$name),
|
||||
'_ACTUAL_' => (!empty($values['section']) ? ${$values['section']}[$name] : ${$name}),
|
||||
]);
|
||||
}
|
||||
|
||||
$status = ($values['operator']((!empty($values['section']) ? ${$values['section']}[$name] : $$name), $values['value_to_check']) ? 1 : 0);
|
||||
$status = ($values['operator'](!empty($values['section']) ? ${$values['section']}[$name] : ${$name}, $values['value_to_check']) ? 1 : 0);
|
||||
|
||||
$config[] = [
|
||||
'name' => $name,
|
||||
|
@ -359,19 +412,25 @@ foreach ($config_to_check as $name => $values) {
|
|||
}
|
||||
|
||||
$requirements = [
|
||||
tr('Apache') => $apache,
|
||||
tr('Apache (_INTERFACE_)', [
|
||||
'_INTERFACE_' => $php_interface,
|
||||
]) => $apache,
|
||||
tr('PHP (_VERSION_ _SUPPORTED_)', [
|
||||
'_VERSION_' => phpversion(),
|
||||
'_SUPPORTED_' => ((version_compare(phpversion(), $settings['php_version']['minimum'], '>=') && version_compare(phpversion(), $settings['php_version']['maximum'], '<=')) ? '' : '<small><small class="label label-danger" ><i class="fa fa-warning"></i> '.tr('versioni supportate:').' '.$settings['php_version']['description'].'</small></small>'),
|
||||
'_SUPPORTED_' => ((version_compare(phpversion(), $settings['php_version']['minimum'], '>=') && version_compare(phpversion(), $settings['php_version']['maximum'], '<=')) ? '' : '<small> <span class="right badge badge-danger" ><i class="fa fa-warning"></i> '.tr('versioni supportate:').' '.$settings['php_version']['description'].'</small></small>'),
|
||||
]) => $php,
|
||||
tr('MySQL') => $mysql,
|
||||
tr('DBMS (_TYPE_)', [
|
||||
'_TYPE_' => method_exists($database, 'getType') ? $database->getType() : '',
|
||||
]) => $mysql,
|
||||
tr('Percorsi di servizio') => $directories,
|
||||
tr('File di servizio') => $files,
|
||||
tr('Configurazioni') => $config,
|
||||
];
|
||||
|
||||
if (!$database->isInstalled() || empty($mysql)) {
|
||||
unset($requirements['MySQL']);
|
||||
unset($requirements[tr('DBMS (_TYPE_)', [
|
||||
'_TYPE_' => $database->getType(),
|
||||
])]);
|
||||
}
|
||||
|
||||
// Tabelle di riepilogo
|
||||
|
@ -383,14 +442,14 @@ foreach ($requirements as $key => $values) {
|
|||
}
|
||||
|
||||
echo '
|
||||
<div class="box box-'.($general_status ? 'success collapsed-box' : 'danger').'">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">'.$key.'</h3>';
|
||||
<div class="card card-'.($general_status ? 'success collapsed-card' : 'danger').'">
|
||||
<div class="card-header with-border">
|
||||
<h3 class="card-title">'.$key.'</h3>';
|
||||
|
||||
if ($general_status) {
|
||||
echo '
|
||||
<div class="box-tools pull-right">
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse">
|
||||
<div class="card-tools pull-right">
|
||||
<button type="button" class="btn btn-tool" data-widget="collapse">
|
||||
<i class="fa fa-plus"></i>
|
||||
</button>
|
||||
</div>';
|
||||
|
@ -398,7 +457,7 @@ foreach ($requirements as $key => $values) {
|
|||
|
||||
echo '
|
||||
</div>
|
||||
<div class="box-body no-padding">
|
||||
<div class="card-body no-padding">
|
||||
<table class="table">';
|
||||
|
||||
foreach ($values as $value) {
|
||||
|
@ -406,7 +465,7 @@ foreach ($requirements as $key => $values) {
|
|||
<tr class="'.($value['status'] ? 'success' : 'danger').'">
|
||||
<td style="width: 10px"><i class="fa fa-'.($value['status'] ? 'check' : 'times').'"></i></td>
|
||||
<td style="width: 120px" >'.$value['type'].'</td>
|
||||
<td style="width: 200px" >'.$value['name'].'</td>
|
||||
<td style="width: 300px" >'.$value['name'].'</td>
|
||||
<td>'.$value['description'].'</td>
|
||||
</tr>';
|
||||
}
|
||||
|
|
|
@ -33,18 +33,18 @@ if (filter('action') == 'do_update') {
|
|||
$result = Update::doUpdate($updateRate);
|
||||
|
||||
if (!empty($result)) {
|
||||
// Aggiunta del messaggio generico riguardante l'aggiornamento
|
||||
// Adding a generic message regarding the update
|
||||
echo '
|
||||
<script>
|
||||
addVersion("'.$update['name'].'");
|
||||
</script>';
|
||||
|
||||
if (is_array($result)) {
|
||||
// Aggiunta del messaggio riguardante la conclusione dell'aggiornamento del database
|
||||
// Adding a message about the completion of the database update
|
||||
if (!empty($update['sql']) && $result[1] == $result[2]) {
|
||||
echo '
|
||||
<script>
|
||||
$("#progress .info").html($("#progress .info").html() + "<p> <i class=\"fa fa-check\"></i> '.tr('Aggiornamento del database (_FILENAME_)', [
|
||||
$("#progress .info").html($("#progress .info").html() + "<p><i class=\"fa fa-check\"></i> '.tr('Aggiornamento del database (_FILENAME_)', [
|
||||
'_FILENAME_' => '<i>'.$update['filename'].'.sql</i>',
|
||||
]).'</p>");
|
||||
</script>';
|
||||
|
@ -52,10 +52,10 @@ if (filter('action') == 'do_update') {
|
|||
|
||||
$rate = $result[1] - $result[0];
|
||||
} elseif (!empty($update['script'])) {
|
||||
// Aggiunta del messaggio riguardante la conclusione dello script
|
||||
// Adding a message about the completion of the script
|
||||
echo '
|
||||
<script>
|
||||
$("#progress .info").html($("#progress .info").html() + "<p> <i class=\"fa fa-check\"></i> '.tr('Esecuzione dello script di aggiornamento (_FILENAME_)', [
|
||||
$("#progress .info").html($("#progress .info").html() + "<p><i class=\"fa fa-check\"></i> '.tr('Esecuzione dello script di aggiornamento (_FILENAME_)', [
|
||||
'_FILENAME_' => '<i>'.$update['filename'].'.php</i>',
|
||||
]).'</p>");
|
||||
</script>';
|
||||
|
@ -63,7 +63,7 @@ if (filter('action') == 'do_update') {
|
|||
$rate = $scriptValue;
|
||||
}
|
||||
|
||||
// Aumento della percentuale di completamento totale
|
||||
// Increasing the total completion percentage
|
||||
if (!empty($rate)) {
|
||||
echo '
|
||||
<script>
|
||||
|
@ -76,7 +76,7 @@ if (filter('action') == 'do_update') {
|
|||
$("#result").load("index.php?action=do_update&firstuse='.$_GET['firstuse'].'");
|
||||
</script>';
|
||||
} else {
|
||||
// Fallimento
|
||||
// Failure
|
||||
echo '
|
||||
<div class="alert alert-danger">
|
||||
<i class="fa fa-times"></i> '.tr("Errore durante l'esecuzione dell'aggiornamento alla versione _VERSION_", [
|
||||
|
@ -85,20 +85,20 @@ if (filter('action') == 'do_update') {
|
|||
</div>';
|
||||
}
|
||||
}
|
||||
// Aggiornamento completato
|
||||
// Update completed
|
||||
elseif (Update::isUpdateCompleted()) {
|
||||
Update::updateCleanup();
|
||||
|
||||
echo '
|
||||
<p><strong>'.tr('Aggiornamento completato').'</strong> <i class="fa fa-smile-o"></i></p>
|
||||
<p><strong>'.tr('Aggiornamento completato').'</strong> 😃</p>
|
||||
<script>
|
||||
setPercent(100);
|
||||
</script>';
|
||||
|
||||
// Istruzioni per la prima installazione
|
||||
// Instructions for the first installation
|
||||
if ($_GET['firstuse'] == 'true') {
|
||||
echo '
|
||||
<p class="text-danger">'.tr("E' fortemente consigliato rimuovere i permessi di scrittura dal file _FILE_", [
|
||||
<p class="text-danger">'.tr('Si consiglia di rimuovere i permessi di scrittura dal file _FILE_', [
|
||||
'_FILE_' => '<b>config.inc.php</b>',
|
||||
]).'.</p>';
|
||||
}
|
||||
|
@ -109,29 +109,29 @@ if (filter('action') == 'do_update') {
|
|||
</a>';
|
||||
}
|
||||
|
||||
exit();
|
||||
exit;
|
||||
} elseif (Update::isUpdateAvailable()) {
|
||||
// Controllo se l'aggiornamento è in esecuzione
|
||||
if (Update::isUpdateLocked() && filter('force') === null) {
|
||||
// Check if the update is in progress
|
||||
if (Update::isUpdateLocked() && filter('force') != '1') {
|
||||
$pageTitle = tr('Aggiornamento in corso!');
|
||||
|
||||
include_once App::filepath('include|custom|', 'top.php');
|
||||
|
||||
echo '
|
||||
<div class="box box-center box-danger box-solid text-center">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">'.tr('Aggiornamento in corso!').'</h3>
|
||||
<div class="card card-danger card-outline text-center">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">'.tr('Aggiornamento in corso!').'</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="card-body">
|
||||
<p>'.tr('Il software si trova attualmente nella fase di aggiornamento, potrebbero volerci fino a 10 minuti, siete pregati di attendere sino alla sua conclusione').'.</p>
|
||||
<p>'.tr("In caso di problemi rivolgersi all'amministratore di sistema o all'assistenza del gestionale").'.</p>
|
||||
<a class="btn btn-info" href="'.base_path().'/index.php"><i class="fa fa-repeat"></i> '.tr('Riprova').'</a>
|
||||
<a class="btn btn-info" href="'.base_path().'/index.php"><i class="fa fa-redo"></i> '.tr('Riprova').'</a>
|
||||
</div>
|
||||
</div>';
|
||||
|
||||
include_once App::filepath('include|custom|', 'bottom.php');
|
||||
|
||||
exit();
|
||||
exit;
|
||||
}
|
||||
|
||||
$firstuse = !$dbo->isInstalled() ? 'true' : 'false';
|
||||
|
@ -142,11 +142,11 @@ if (filter('action') == 'do_update') {
|
|||
include_once App::filepath('include|custom|', 'top.php');
|
||||
|
||||
echo '
|
||||
<div class="box box-center-large box-warning text-center">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">'.(!$dbo->isInstalled() ? tr('Installazione') : tr('Aggiornamento')).'</h3>
|
||||
<div class="card card-warning card-center-large text-center">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title"><i class="fa fa-refresh"></i> '.(!$dbo->isInstalled() ? tr('Installazione') : tr('Aggiornamento')).'</h3>
|
||||
</div>
|
||||
<div class="box-body">';
|
||||
<div class="card-body">';
|
||||
if (!$dbo->isInstalled()) {
|
||||
echo '
|
||||
<p><strong>'.tr("E' la prima volta che avvii OpenSTAManager e non hai ancora installato il database").'.</strong></p>';
|
||||
|
@ -158,7 +158,7 @@ if (filter('action') == 'do_update') {
|
|||
<p>'.tr("Premi il tasto _BUTTON_ per procedere con l'".(!$dbo->isInstalled() ? tr('installazione') : tr('aggiornamento')).'!', [
|
||||
'_BUTTON_' => '<b>"'.$button.'"</b>',
|
||||
]).'</p>
|
||||
<input type="button" class="btn btn-primary" value="'.$button.'" onclick="continue_update()" id="contine_button">
|
||||
<input type="button" class="btn btn-primary" value="'.$button.'" onclick="continue_update()" id="continue_button">
|
||||
|
||||
<script>
|
||||
function continue_update(){
|
||||
|
@ -173,7 +173,7 @@ if (filter('action') == 'do_update') {
|
|||
function(){
|
||||
$("#progress").show();
|
||||
$("#result").load("index.php?action=do_update&firstuse='.$firstuse.'");
|
||||
$("#contine_button").remove();
|
||||
$("#continue_button").remove();
|
||||
}, function(){});
|
||||
}
|
||||
</script>
|
||||
|
@ -185,21 +185,20 @@ if (filter('action') == 'do_update') {
|
|||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="box box-info text-center collapsed-box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title"><a class="clickable" data-widget="collapse">'.tr('Log').'</a></h3>
|
||||
<div class="box-tools pull-right">
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-plus"></i></button>
|
||||
<div class="card card-info text-center collapsed-card">
|
||||
<div class="card-header with-border">
|
||||
<h3 class="card-title"><a class="clickable" data-card-widget="collapse">'.tr('Log').'</a></h3>
|
||||
<div class="card-tools pull-right">
|
||||
<button type="button" class="btn btn-tool" data-card-widget="collapse"><i class="fa fa-plus"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-body info text-left"></div>
|
||||
<div class="card-body info text-left"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="result"></div>';
|
||||
|
||||
$total = 0;
|
||||
$updates = Update::getTodoUpdates();
|
||||
|
||||
foreach ($updates as $update) {
|
||||
if ($update['sql'] && (!empty($update['done']) || is_null($update['done']))) {
|
||||
$queries = readSQLFile(base_dir().'/'.$update['directory'].$update['filename'].'.sql', ';');
|
||||
|
@ -256,5 +255,6 @@ if (filter('action') == 'do_update') {
|
|||
}
|
||||
</script>
|
||||
</div>
|
||||
|
||||
</div>';
|
||||
}
|
||||
|
|
|
@ -18,14 +18,16 @@
|
|||
*/
|
||||
|
||||
use HTMLBuilder\HTMLBuilder;
|
||||
use Models\Module;
|
||||
use Models\Plugin;
|
||||
|
||||
include_once __DIR__.'/../core.php';
|
||||
|
||||
// Compatibilità per controller ed editor
|
||||
if (!empty($id_plugin)) {
|
||||
$structure = Plugins::get($id_plugin);
|
||||
$structure = Plugin::find($id_plugin);
|
||||
} else {
|
||||
$structure = Modules::get($id_module);
|
||||
$structure = Module::find($id_module);
|
||||
}
|
||||
|
||||
if (!empty($id_plugin)) {
|
||||
|
@ -42,7 +44,7 @@ if (!empty($id_plugin)) {
|
|||
echo '
|
||||
<h4>
|
||||
<span class="'.(!empty($structure['help']) ? ' tip' : '').'"'.(!empty($structure['help']) ? ' title="'.prepareToField($structure['help']).'" data-position="bottom"' : '').' >
|
||||
'.$structure['title'].(!empty($structure['help']) ? ' <i class="fa fa-question-circle-o"></i>' : '').'</span>';
|
||||
'.$structure->getTranslation('title').(!empty($structure['help']) ? ' <i class="fa fa-question-circle-o"></i>' : '').'</span>';
|
||||
|
||||
if ($structure->hasAddFile()) {
|
||||
echo '
|
||||
|
@ -72,12 +74,11 @@ if (!empty($type) && $type != 'menu' && $type != 'custom') {
|
|||
|
||||
if (empty($id_plugin) && count(Modules::getSegments($id_module)) > 1) {
|
||||
echo '
|
||||
<div class="row">
|
||||
<div class="col-md-4 pull-right">
|
||||
<div class="row justify-content-end">
|
||||
<div class="col-md-3">
|
||||
{[ "type": "select", "name": "id_segment_", "required": 0, "ajax-source": "segmenti", "select-options": '.json_encode(['id_module' => $id_module]).', "value": "'.$_SESSION['module_'.$id_module]['id_segment'].'" ]}
|
||||
</div>
|
||||
</div>
|
||||
<br>';
|
||||
</div>';
|
||||
|
||||
echo '
|
||||
<script>
|
||||
|
@ -97,33 +98,33 @@ if (!empty($type) && $type != 'menu' && $type != 'custom') {
|
|||
$_SESSION['module_'.$id_module]['selected'] = [];
|
||||
$selezione = array_keys($_SESSION['module_'.$id_module]['selected']);
|
||||
|
||||
$table_id = 'main_'.rand(0, 99);
|
||||
$table_id = 'main_'.random_int(0, 99);
|
||||
echo '
|
||||
<table data-idmodule="'.$id_module.'" data-idplugin="'.$id_plugin.'" data-idparent="'.$id_record.'" data-selected="'.implode(';', $selezione).'" id="'.$table_id.'" width="100%" class="main-records'.(!empty($id_plugin) ? '-plugins' : '').' table table-condensed table-bordered">
|
||||
<table data-idmodule="'.$id_module.'" data-idplugin="'.$id_plugin.'" data-idparent="'.$id_record.'" data-selected="'.implode(';', $selezione).'" id="'.$table_id.'" width="100%" class="table main-records table-hover table-striped '.(!empty($id_plugin) ? '-plugins' : '').'">
|
||||
<thead>
|
||||
<tr>
|
||||
<th id="th_selector"></th>';
|
||||
|
||||
foreach ($total['fields'] as $key => $field) {
|
||||
$attr_td = '';
|
||||
$name = trim($field);
|
||||
$name = trim((string) $field);
|
||||
|
||||
// Check per tipologie di campi particolari
|
||||
if (preg_match('/^color_/', $field)) {
|
||||
if (preg_match('/^color_/', (string) $field)) {
|
||||
$attr_td .= " width='140'";
|
||||
$field = str_replace('color_', '', $field);
|
||||
}
|
||||
|
||||
// Data (larghezza fissa)
|
||||
elseif (preg_match('/^Data/', $field)) {
|
||||
elseif (preg_match('/^Data/', (string) $field)) {
|
||||
$attr_td .= " width='100'";
|
||||
}
|
||||
|
||||
// Icona di stampa
|
||||
elseif (trim($field) == '_print_') {
|
||||
elseif (trim((string) $field) == '_print_') {
|
||||
$attr_td .= " width='30'";
|
||||
$field = str_replace('_print_', '', $field);
|
||||
} elseif (preg_match('/^icon_/', $field)) {
|
||||
} elseif (preg_match('/^icon_/', (string) $field)) {
|
||||
$attr_td .= " width='30'";
|
||||
$name = str_replace('icon_', 'icon_title_', $name);
|
||||
$field = str_replace('icon_', '', $field);
|
||||
|
@ -178,12 +179,13 @@ if (!empty($type) && $type != 'menu' && $type != 'custom') {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-2 dropdown">';
|
||||
|
||||
<div class="col-md-2 dropup">';
|
||||
if (!empty($bulk) && $structure->permission == 'rw' && empty($id_plugin)) {
|
||||
echo '
|
||||
<button class="btn btn-primary btn-block dropdown-toggle actions-container disabled" type="button" data-toggle="dropdown" disabled>'.tr('Azioni di gruppo').' <span class="caret"></span></button>
|
||||
<ul class="dropdown-menu" data-target="'.$table_id.'" role="menu">';
|
||||
<div class="btn-group">
|
||||
|
||||
<button class="btn btn-primary btn-lg dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> '.tr('Azioni di gruppo').' </button>
|
||||
<div class="dropdown-menu dropdown-menu-right">';
|
||||
|
||||
foreach ($bulk as $key => $value) {
|
||||
$text = is_array($value) ? $value['text'] : $value;
|
||||
|
@ -195,13 +197,13 @@ if (!empty($type) && $type != 'menu' && $type != 'custom') {
|
|||
}
|
||||
|
||||
echo '
|
||||
<li role="presentation"><a class="bulk-action clickable" data-op="'.prepareToField($key).'" data-backto="record-list" '.implode(' ', $extra).'>'.$text.'</a></li>';
|
||||
<a class="bulk-action clickable dropdown-item" data-op="'.prepareToField($key).'" data-backto="record-list" '.implode(' ', $extra).'>'.$text.'</a>';
|
||||
}
|
||||
|
||||
echo '
|
||||
</ul>';
|
||||
</div>
|
||||
</div>';
|
||||
}
|
||||
|
||||
echo '
|
||||
</div>
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ echo '
|
|||
<input type="hidden" name="op" value="modifica-allegato">
|
||||
|
||||
<div class="row">';
|
||||
if (sizeof($id_allegati) == 1) {
|
||||
if (sizeof($id_allegati) == 1) {
|
||||
$allegato = Upload::find($id_allegati[0]);
|
||||
echo '
|
||||
<div class="col-md-6">
|
||||
|
@ -38,14 +38,14 @@ echo '
|
|||
<div class="col-md-6">
|
||||
{[ "type": "text", "label": "'.tr('Categoria').'", "name": "categoria_allegato", "value": "'.$allegato->category.'", "disabled": "'.intval(in_array($allegato->category, ['Fattura Elettronica'])).'" ]}
|
||||
</div>';
|
||||
} else {
|
||||
} else {
|
||||
$allegato = Upload::find($id_allegati[0]);
|
||||
echo '
|
||||
<div class="col-md-6">
|
||||
{[ "type": "text", "label": "'.tr('Categoria').'", "name": "categoria_allegato", "value": "" ]}
|
||||
</div>';
|
||||
}
|
||||
echo '
|
||||
}
|
||||
echo '
|
||||
</div>
|
||||
|
||||
<!-- PULSANTI -->
|
||||
|
@ -90,7 +90,7 @@ $(document).ready(function () {
|
|||
update(results);
|
||||
},
|
||||
onSelect: function (item) {
|
||||
input.value = item.label;
|
||||
input.value = item.badge;
|
||||
},
|
||||
});
|
||||
});
|
||||
|
|
|
@ -20,7 +20,9 @@
|
|||
include_once __DIR__.'/../../core.php';
|
||||
|
||||
use Modules\DDT\DDT;
|
||||
use Modules\DDT\Stato as StatoDDT;
|
||||
use Modules\Ordini\Ordine;
|
||||
use Modules\Ordini\Stato as StatoOrdine;
|
||||
|
||||
// Informazioni generali sulla riga
|
||||
$source_type = filter('riga_type');
|
||||
|
@ -43,7 +45,7 @@ include_once __DIR__.'/righe_riferimenti.php';
|
|||
echo '
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info" id="box-loading-riferimenti">
|
||||
<div class="alert alert-info" id="card-loading-riferimenti">
|
||||
<i class="fa fa-spinner fa-spin"></i> '.tr('Caricamento in corso').'...
|
||||
</div>';
|
||||
|
||||
|
@ -52,13 +54,14 @@ $direzione_richiesta = $source->getDocument()->direzione == 'entrata' ? 'uscita'
|
|||
|
||||
// Individuazione DDT disponibili
|
||||
$ddt = DDT::whereHas('stato', function ($query) {
|
||||
$query->where('descrizione', '!=', 'Bozza');
|
||||
$id_stato = StatoDDT::where('name', 'Bozza')->first()->id;
|
||||
$query->where('id', '!=', $id_stato);
|
||||
})->whereHas('tipo', function ($query) use ($direzione_richiesta) {
|
||||
$query->where('dir', '=', $direzione_richiesta);
|
||||
})->get();
|
||||
foreach ($ddt as $elemento) {
|
||||
$documenti_disponibili->push([
|
||||
'id' => get_class($elemento).'|'.$elemento->id,
|
||||
'id' => $elemento::class.'|'.$elemento->id,
|
||||
'text' => $elemento->getReference(1),
|
||||
'optgroup' => tr('Ddt in ').$source->getDocument()->direzione,
|
||||
]);
|
||||
|
@ -67,25 +70,26 @@ foreach ($ddt as $elemento) {
|
|||
// Individuazione ordini disponibili
|
||||
$tipo_ordini = $direzione_richiesta == 'entrata' ? 'cliente' : 'fornitore';
|
||||
$ordini = Ordine::whereHas('stato', function ($query) {
|
||||
$query->where('descrizione', '!=', 'Bozza');
|
||||
$id_stato = StatoOrdine::where('name', 'Bozza')->first()->id;
|
||||
$query->where('id', '!=', $id_stato);
|
||||
})->whereHas('tipo', function ($query) use ($direzione_richiesta) {
|
||||
$query->where('dir', '=', $direzione_richiesta);
|
||||
})->get();
|
||||
foreach ($ordini as $elemento) {
|
||||
$documenti_disponibili->push([
|
||||
'id' => get_class($elemento).'|'.$elemento->id,
|
||||
'id' => $elemento::class.'|'.$elemento->id,
|
||||
'text' => $elemento->getReference(1),
|
||||
'optgroup' => tr('Ordini ').$tipo_ordini,
|
||||
]);
|
||||
}
|
||||
|
||||
echo '
|
||||
<div class="box">
|
||||
<div class="box-header">
|
||||
<h3 class="box-title">'.tr('Nuovo riferimento').'</h3>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">'.tr('Nuovo riferimento').'</h3>
|
||||
</div>
|
||||
|
||||
<div class="box-body">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{[ "type": "select", "label": "'.tr('Documento').'", "name": "documento_riferimento", "required": 1, "values": '.$documenti_disponibili->toJson().' ]}
|
||||
|
@ -94,7 +98,7 @@ echo '
|
|||
|
||||
<div id="righe_documento"></div>
|
||||
|
||||
<div class="alert alert-info" id="box-loading">
|
||||
<div class="alert alert-info" id="card-loading">
|
||||
<i class="fa fa-spinner fa-spin"></i> '.tr('Caricamento in corso').'...
|
||||
</div>
|
||||
</div>
|
||||
|
@ -106,8 +110,8 @@ echo '
|
|||
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$("#box-loading").hide();
|
||||
$("#box-loading-riferimenti").hide();
|
||||
$("#card-loading").hide();
|
||||
$("#card-loading-riferimenti").hide();
|
||||
});
|
||||
|
||||
var riferimenti = JSON.parse(\''.json_encode($elenco_riferimenti).'\');
|
||||
|
@ -126,7 +130,7 @@ echo '
|
|||
});
|
||||
|
||||
function caricaRiferimenti() {
|
||||
let loader = $("#box-loading-riferimenti");
|
||||
let loader = $("#card-loading-riferimenti");
|
||||
let content = $("#righe_riferimenti");
|
||||
|
||||
loader.show();
|
||||
|
@ -154,7 +158,7 @@ echo '
|
|||
|
||||
function caricaRighe(tipo_documento, id_documento){
|
||||
let content = $("#righe_documento");
|
||||
let loader = $("#box-loading");
|
||||
let loader = $("#card-loading");
|
||||
|
||||
loader.show();
|
||||
content.html("");
|
||||
|
|
|
@ -42,9 +42,9 @@ echo '
|
|||
|
||||
<tbody>';
|
||||
|
||||
$righe = $documento->getRighe();
|
||||
foreach ($righe as $riga) {
|
||||
$riga_class = get_class($riga);
|
||||
$righe = $documento->getRighe();
|
||||
foreach ($righe as $riga) {
|
||||
$riga_class = $riga::class;
|
||||
|
||||
$riferimento_locale = $riga_class.'|'.$riga->id;
|
||||
$presente = in_array($riferimento_locale, $riferimenti);
|
||||
|
@ -59,8 +59,8 @@ echo '
|
|||
</button>
|
||||
</td>
|
||||
</tr>';
|
||||
}
|
||||
}
|
||||
|
||||
echo '
|
||||
echo '
|
||||
</tbody>
|
||||
</table>';
|
||||
|
|
|
@ -43,12 +43,12 @@ if (!$riferimenti->isEmpty()) {
|
|||
|
||||
foreach ($riferimenti as $riferimento) {
|
||||
$riga = $riferimento->target;
|
||||
$riga_class = get_class($source);
|
||||
$riga_class = $source::class;
|
||||
|
||||
echo '
|
||||
<tr data-id="'.$riga->id.'" data-type="'.$riga_class.'">
|
||||
<td>
|
||||
<button type="button" class="btn btn-xs btn-danger pull-right" onclick="rimuoviRiferimento(this, \''.addslashes($source_type).'\', \''.$source_id.'\', \''.$riferimento->id.'\')">
|
||||
<button type="button" class="btn btn-xs btn-danger pull-right" onclick="rimuoviRiferimento(this, \''.addslashes((string) $source_type).'\', \''.$source_id.'\', \''.$riferimento->id.'\')">
|
||||
<i class="fa fa-trash"></i>
|
||||
</button>
|
||||
|
||||
|
|
336
include/top.php
336
include/top.php
|
@ -17,6 +17,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use Models\Module;
|
||||
use Util\FileSystem;
|
||||
|
||||
include_once __DIR__.'/../core.php';
|
||||
|
@ -24,7 +25,7 @@ include_once __DIR__.'/../core.php';
|
|||
$paths = App::getPaths();
|
||||
$user = Auth::user();
|
||||
|
||||
$pageTitle = !empty($pageTitle) ? $pageTitle : $structure->title;
|
||||
$pageTitle = !empty($pageTitle) ? $pageTitle : $structure->getTranslation('title');
|
||||
|
||||
$lang = (empty($lang) || $lang == '|lang|') ? 'it_IT' : $lang;
|
||||
|
||||
|
@ -46,7 +47,7 @@ echo '<!DOCTYPE html>
|
|||
|
||||
if (file_exists(base_dir().'/manifest.json')) {
|
||||
echo '
|
||||
<link rel="manifest" href="'.base_path().'/manifest.json?r='.rand().'">';
|
||||
<link rel="manifest" href="'.base_path().'/manifest.json?r='.random_int(0, mt_getrandmax()).'">';
|
||||
}
|
||||
|
||||
// CSS
|
||||
|
@ -74,7 +75,7 @@ if (Auth::check()) {
|
|||
|
||||
echo '
|
||||
search.push("search_'.$field_name.'");
|
||||
search["search_'.$field_name.'"] = "'.addslashes($value).'";';
|
||||
search["search_'.$field_name.'"] = "'.addslashes((string) $value).'";';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -97,6 +98,7 @@ if (Auth::check()) {
|
|||
'nextMonth' => tr('Mese prossimo'),
|
||||
'thisYear' => tr("Quest'anno"),
|
||||
'lastYear' => tr('Anno scorso'),
|
||||
'lastYear_thisYear' => tr("Quest'anno + prec."),
|
||||
'apply' => tr('Applica'),
|
||||
'cancel' => tr('Annulla'),
|
||||
'from' => tr('Da'),
|
||||
|
@ -204,7 +206,7 @@ if (Auth::check()) {
|
|||
|
||||
search: search,
|
||||
translations: translations,
|
||||
locale: "'.(explode('_', $lang)[0]).'",
|
||||
locale: "'.explode('_', (string) $lang)[0].'",
|
||||
full_locale: "'.$lang.'",
|
||||
|
||||
start_date: "'.$_SESSION['period_start'].'",
|
||||
|
@ -236,7 +238,7 @@ if (Auth::check()) {
|
|||
{ name: "tools", items : [ "Maximize", "ShowBlocks" ] },
|
||||
{ name: "about", items: [ "About" ] }
|
||||
],
|
||||
order_manager_id: "'.($dbo->isInstalled() ? Modules::get('Stato dei servizi')['id'] : '').'",
|
||||
order_manager_id: "'.($dbo->isInstalled() ? Module::where('name', 'Stato dei servizi')->first()->id : '').'",
|
||||
dataload_page_buffer: '.setting('Lunghezza in pagine del buffer Datatables').',
|
||||
tempo_attesa_ricerche: '.setting('Tempo di attesa ricerche in secondi').',
|
||||
restrict_summables_to_selected: '.setting('Totali delle tabelle ristretti alla selezione').',
|
||||
|
@ -274,7 +276,7 @@ if (Auth::check()) {
|
|||
date_format: "'.formatter()->getDatePattern().'",
|
||||
time_format: "'.formatter()->getTimePattern().'",
|
||||
|
||||
locale: "'.(explode('_', $lang)[0]).'",
|
||||
locale: "'.explode('_', (string) $lang)[0].'",
|
||||
full_locale: "'.$lang.'",
|
||||
};
|
||||
</script>';
|
||||
|
@ -300,13 +302,13 @@ echo '
|
|||
if (Auth::check()) {
|
||||
if (setting('Abilita esportazione Excel e PDF')) {
|
||||
echo '
|
||||
<script type="text/javascript" charset="utf-8" src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.3/jszip.min.js"></script>
|
||||
<script type="text/javascript" charset="utf-8" src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.36/pdfmake.min.js"></script>
|
||||
<script type="text/javascript" charset="utf-8" src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.36/vfs_fonts.js"></script>';
|
||||
<script type="text/javascript" charset="utf-8" src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
|
||||
<script type="text/javascript" charset="utf-8" src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.9/pdfmake.min.js"></script>
|
||||
<script type="text/javascript" charset="utf-8" src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.9/vfs_fonts.min.js"></script>';
|
||||
}
|
||||
|
||||
if (setting('Attiva scorciatoie da tastiera')) {
|
||||
echo '<script type="text/javascript" charset="utf-8" src="'.App::getPaths()['js'].'/hotkeys-js/hotkeys.min.js"></script>';
|
||||
echo '<script type="text/javascript" charset="utf-8" src="'.App::getPaths()['js'].'/hotkeys-js/hotkeys.min.js?v='.$version.'"></script>';
|
||||
echo '
|
||||
<script>
|
||||
|
||||
|
@ -336,23 +338,35 @@ if (Auth::check()) {
|
|||
}
|
||||
}
|
||||
|
||||
// Set the group theme
|
||||
if (isset($user)) {
|
||||
if ($user->getThemeAttribute()) {
|
||||
$theme = $user->getThemeAttribute();
|
||||
}
|
||||
}
|
||||
|
||||
if ($theme == 'default') {
|
||||
$theme = 'sidebar-dark-secondary';
|
||||
} else {
|
||||
$theme = 'bg-'.$theme;
|
||||
}
|
||||
|
||||
$settings_collapse = session_get('settings.sidebar-collapse') ? 1 : 0;
|
||||
$hide_sidebar = Auth::check() && (setting('Nascondere la barra sinistra di default') || $settings_collapse);
|
||||
echo '
|
||||
</head>
|
||||
|
||||
<body class="sidebar-mini skin-'.$theme.(!empty($hide_sidebar) ? ' sidebar-collapse' : '').(!Auth::check() ? ' hold-transition login-page' : '').'">
|
||||
<body class="sidebar-mini layout-fixed '.(!empty($hide_sidebar) ? ' sidebar-collapse' : '').(!Auth::check() ? ' hold-transition login-page' : '').'">
|
||||
<div class="'.(!Auth::check() ? '' : 'wrapper').'">';
|
||||
|
||||
if (Auth::check()) {
|
||||
$calendar_color_label = ($_SESSION['period_start'] != date('Y').'-01-01' || $_SESSION['period_end'] != date('Y').'-12-31') ? 'danger' : 'default';
|
||||
$calendar_color_label = ($_SESSION['period_start'] != date('Y').'-01-01' || $_SESSION['period_end'] != date('Y').'-12-31') ? 'danger' : 'secondary';
|
||||
|
||||
echo '
|
||||
<!-- Loader principale -->
|
||||
<div id="main_loading">
|
||||
<div>
|
||||
<i class="fa fa-cog fa-spin text-danger"></i>
|
||||
</div>
|
||||
<!-- Preloader -->
|
||||
<div id="main_loading" class="preloader flex-column justify-content-center align-items-center">
|
||||
<img class="animation__shake" src="'.$rootdir.'/assets/dist/img/logo.png" alt="OSM" height="60" width="60">
|
||||
</div>
|
||||
|
||||
<!-- Loader secondario -->
|
||||
|
@ -363,168 +377,165 @@ if (Auth::check()) {
|
|||
<!-- Loader senza overlay -->
|
||||
<div id="tiny-loader" style="display:none;"></div>
|
||||
|
||||
<header class="main-header">
|
||||
<a href="'.tr('https://www.openstamanager.com').'" class="logo" title="'.tr("Il gestionale open source per l'assistenza tecnica e la fatturazione").'" target="_blank">
|
||||
<!-- mini logo for sidebar mini 50x50 pixels -->
|
||||
<span class="logo-mini">'.tr('OSM').'</span>
|
||||
<!-- logo for regular state and mobile devices -->
|
||||
<span class="logo-lg">'.tr('OpenSTAManager').'</span>
|
||||
</a>
|
||||
<!-- Header Navbar: style can be found in header.less -->
|
||||
<nav class="navbar navbar-static-top" role="navigation">
|
||||
|
||||
<!-- Sidebar toggle button-->
|
||||
<a href="#" class="sidebar-toggle" data-toggle="push-menu" role="button">
|
||||
<span class="sr-only">'.tr('Mostra/nascondi menu').'</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</a>
|
||||
|
||||
<!-- Navbar Left Menu -->
|
||||
<div class="navbar-left">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="#" id="daterange" role="button" >
|
||||
<i class="fa fa-calendar" style="color:inherit"></i> <i class="fa fa-caret-down" style="color:inherit"></i>
|
||||
</a></li>
|
||||
|
||||
<li><a style="cursor:default;padding:0px;padding-right:5px;padding-left:5px;margin-top:15px;" class="label label-'.$calendar_color_label.'">
|
||||
'.Translator::dateToLocale($_SESSION['period_start']).' - '.Translator::dateToLocale($_SESSION['period_end']).'
|
||||
</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Navbar Right Menu -->
|
||||
<div class="navbar-custom-menu">
|
||||
<ul class="nav navbar-nav">
|
||||
|
||||
<li class="nav-button hide"><a href="'.base_path().'/bug.php" class="tip nav-button" title="'.tr('Segnalazione bug').'">
|
||||
<i class="fa fa-bug"></i>
|
||||
</a></li>
|
||||
|
||||
<li class="nav-button" >
|
||||
<p style="padding:10px 15px;"> </p>
|
||||
</li>';
|
||||
|
||||
if ($user->gruppo == 'Amministratori') {
|
||||
echo '
|
||||
<li class="dropdown notifications-menu nav-button">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<i class="fa fa-bell-o"></i>
|
||||
<span id="hooks-label" class="label label-warning">
|
||||
<span id="hooks-loading"><i class="fa fa-spinner fa-spin"></i></span>
|
||||
<span id="hooks-notified"></span>
|
||||
<span id="hooks-counter" class="hide">0</span>
|
||||
<span id="hooks-number" class="hide">0</span>
|
||||
</span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li class="header"><span class="small" id="hooks-header"></span></li>
|
||||
<li><ul class="menu" id="hooks">
|
||||
|
||||
</ul></li>
|
||||
</ul>
|
||||
<!-- Navbar -->
|
||||
<nav class="main-header navbar navbar-expand navbar-white navbar-light">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-widget="pushmenu" href="#" role="button"><i class="fa fa-bars"></i></a>
|
||||
</li>
|
||||
|
||||
<li class="nav-button"><a href="#" onclick="window.print()" class="tip nav-button" title="'.tr('Stampa').'">
|
||||
<i class="fa fa-print"></i>
|
||||
</a></li>
|
||||
<li class="nav-item">
|
||||
<a href="#" id="daterange" class="nav-link" role="button">
|
||||
<i class="fa fa-calendar"></i> <i class="fa fa-caret-down"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item d-none d-sm-inline-block">
|
||||
<a class="nav-link text-'.$calendar_color_label.'">
|
||||
'.Translator::dateToLocale($_SESSION['period_start']).' - '.Translator::dateToLocale($_SESSION['period_end']).'
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<li class="nav-button"><a href="'.base_path().'/log.php" class="tip nav-button" title="'.tr('Log accessi').'">
|
||||
<i class="fa fa-book"></i>
|
||||
</a></li>';
|
||||
|
||||
<!-- Navbar Right Menu -->
|
||||
<ul class="navbar-nav ml-auto">';
|
||||
// Visualizzo gli hooks solo se non sono stati disabilitati
|
||||
if (!$config['disable_hooks']) {
|
||||
echo '
|
||||
<div class="nav-item dropdown">
|
||||
<a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown">
|
||||
<i class="fa fa-bell-o"></i>
|
||||
<span id="hooks-badge" class="badge badge-warning">
|
||||
<span id="hooks-loading"><i class="fa fa-spinner fa-spin"></i></span>
|
||||
<span id="hooks-notified"></span>
|
||||
<span id="hooks-counter" class="d-none">0</span>
|
||||
<span id="hooks-number" class="d-none">0</span>
|
||||
</span>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-lg dropdown-menu-right">
|
||||
<a href="#" class="dropdown-item">
|
||||
<span class="small" id="hooks-header"></span>
|
||||
</a>
|
||||
<div id="hooks"></div>
|
||||
</div>
|
||||
</div>';
|
||||
}
|
||||
|
||||
echo '
|
||||
<li class="nav-button"><a data-href="'.base_path().'/shortcuts.php" data-title="'.tr('Scorciatoie da tastiera').'" class="tip nav-button" title="'.tr('Scorciatoie').'">
|
||||
<i class="fa fa-keyboard-o"></i>
|
||||
</a></li>
|
||||
<li class="nav-item">
|
||||
<a href="#" onclick="window.print()" class="nav-link" title="'.tr('Stampa').'">
|
||||
<i class="fa fa-print nav-icon"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-button"><a href="'.base_path().'/info.php" class="tip nav-button" title="'.tr('Informazioni').'">
|
||||
<i class="fa fa-info"></i>
|
||||
</a></li>
|
||||
<li class="nav-item">
|
||||
<a href="'.base_path().'/log.php" class="nav-link" title="'.tr('Log accessi').'">
|
||||
<i class="fa fa-book nav-icon"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-button"><a href="'.base_path().'/index.php?op=logout" onclick="sessionStorage.clear()" class="bg-red tip" title="'.tr('Esci').'">
|
||||
<i class="fa fa-power-off"></i>
|
||||
</a></li>
|
||||
<li class="nav-item">
|
||||
<a href="'.base_path().'/shortcuts.php" class="nav-link" title="'.tr('Scorciatoie').'">
|
||||
<i class="fa fa-keyboard-o nav-icon"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a href="'.base_path().'/info.php" class="nav-link" title="'.tr('Informazioni').'">
|
||||
<i class="fa fa-info nav-icon"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a href="'.base_path().'/index.php?op=logout" onclick="sessionStorage.clear()" class="nav-link bg-danger" title="'.tr('Esci').'">
|
||||
<i class="fa fa-power-off nav-icon"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
<!-- /.navbar -->
|
||||
|
||||
<aside class="main-sidebar">
|
||||
<section class="sidebar">
|
||||
<!-- Main Sidebar Container -->
|
||||
<aside class="main-sidebar '.$theme.' elevation-4">
|
||||
<a href="'.tr('https://www.openstamanager.com').'" class="brand-link" title="'.tr("Il gestionale open source per l'assistenza tecnica e la fatturazione").'" target="_blank">
|
||||
<img src="'.$rootdir.'/assets/dist/img/logo_completo.png" alt="'.tr("Il gestionale open source per l'assistenza tecnica e la fatturazione").'" class="img-fluid">
|
||||
<span class="brand-text font-weight-light"> </span>
|
||||
</a>
|
||||
|
||||
<!-- Sidebar user panel -->
|
||||
<div class="user-panel text-center info" style="height: 60px">
|
||||
<div class="info">
|
||||
<p><a href="'.base_path().'/modules/utenti/info.php">
|
||||
'.$user['username'].'
|
||||
</a></p>
|
||||
<p id="datetime"></p>
|
||||
</div>
|
||||
<!-- Sidebar -->
|
||||
<div class="sidebar">
|
||||
|
||||
<a class="image" href="'.base_path().'/modules/utenti/info.php">';
|
||||
<!-- Sidebar user panel (optional) -->
|
||||
<div class="user-panel mt-3 pb-3 mb-3 d-flex">
|
||||
<div class="image">';
|
||||
|
||||
$user_photo = $user->photo;
|
||||
if ($user_photo) {
|
||||
echo '
|
||||
<img src="'.$user_photo.'" class="img-circle pull-left" alt="'.$user['username'].'" />';
|
||||
<img src="'.$user_photo.'" class="img-circle elevation-2" alt="'.$user['username'].'" />';
|
||||
} else {
|
||||
echo '
|
||||
<i class="fa fa-user-circle-o fa-3x pull-left" alt="'.tr('OpenSTAManager').'"></i>';
|
||||
<i class="fa fa-user-circle-o fa-2x" alt="'.tr('Utente').'"></i>';
|
||||
}
|
||||
|
||||
echo '
|
||||
</div>
|
||||
|
||||
<div class="info">
|
||||
<a href="'.base_path().'/modules/utenti/info.php" class="d-block">
|
||||
'.$user['username'].'
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- search form -->
|
||||
<div class="sidebar-form">
|
||||
<div class="input-group">
|
||||
<input type="text" name="q" class="form-control" id="supersearch" placeholder="'.tr('Cerca').'..."/>
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-flat" id="search-btn" name="search" type="submit">
|
||||
<i class="fa fa-search"></i>
|
||||
|
||||
<!-- SidebarSearch Form -->
|
||||
<div class="form-inline">
|
||||
<div class="input-group" data-widget="sidebar-search">
|
||||
<input class="form-control form-control-sidebar" id="supersearch" type="search" placeholder="'.tr('Cerca').'" aria-label="'.tr('Cerca').'">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-sidebar">
|
||||
<i class="fa fa-search fa-fw"></i>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.search form -->
|
||||
</div>
|
||||
|
||||
<ul class="sidebar-menu">';
|
||||
<!-- Sidebar Menu -->
|
||||
<nav class="mt-2">
|
||||
<ul class="nav nav-pills nav-sidebar flex-column" data-widget="treeview" role="menu">';
|
||||
echo Modules::getMainMenu();
|
||||
echo '
|
||||
</ul>
|
||||
</section>
|
||||
<!-- /.sidebar -->
|
||||
</nav>
|
||||
<!-- / Sidebar Menu -->
|
||||
</div>
|
||||
</aside>';
|
||||
|
||||
if (string_contains($_SERVER['SCRIPT_FILENAME'], 'editor.php')) {
|
||||
$in_editor = string_contains($_SERVER['SCRIPT_FILENAME'], 'editor.php');
|
||||
$in_controller = string_contains($_SERVER['SCRIPT_FILENAME'], 'controller.php');
|
||||
if ($in_editor || $in_controller) {
|
||||
// Menu laterale per la visualizzazione dei plugin
|
||||
echo '
|
||||
<div class="control-sidebar-button"><i class="fa fa-chevron-left"></i></div>
|
||||
<aside class="control-sidebar control-sidebar-light">
|
||||
<h4 class="text-center">'.tr('Plugin disponibili').'</h4>
|
||||
<h4><i class="fa fa-plug"></i> '.tr('Plugin').'</h4>
|
||||
<ul class="nav nav-tabs nav-pills nav-stacked">
|
||||
<li data-toggle="control-sidebar" class="active btn-default">
|
||||
<a data-toggle="tab" href="#tab_0">
|
||||
<i class="'.$structure['icon'].'"></i> '.$structure['title'].'
|
||||
<li data-toggle="control-sidebar" class="active btn-default nav-item">
|
||||
<a class="nav-link" data-toggle="tab" href="#tab_0">
|
||||
'.$structure->getTranslation('title').'
|
||||
</a>
|
||||
</li>';
|
||||
|
||||
// Tab dei plugin
|
||||
if (!empty($id_record)) {
|
||||
$plugins = $dbo->fetchArray('SELECT id, title, options, options2 FROM zz_plugins WHERE idmodule_to='.prepare($id_module)." AND position='tab' AND enabled = 1 ORDER BY zz_plugins.order DESC");
|
||||
$plugins = $dbo->fetchArray('SELECT `zz_plugins`.`id`, `title`, `options`, `options2` FROM `zz_plugins` LEFT JOIN `zz_plugins_lang` ON (`zz_plugins`.`id` = `zz_plugins_lang`.`id_record` AND `zz_plugins_lang`.`id_lang` = '.prepare(Models\Locale::getDefault()->id).') WHERE `idmodule_to`='.prepare($id_module)." AND `position`='".($in_editor ? 'tab' : 'tab_main')."' AND `enabled` = 1 ORDER BY `zz_plugins`.`order` DESC");
|
||||
foreach ($plugins as $plugin) {
|
||||
//Badge count per record plugin
|
||||
// Badge count per record plugin
|
||||
$count = 0;
|
||||
$opt = '';
|
||||
if (!empty($plugin['options2'])) {
|
||||
$opt = json_decode($plugin['options2'], true);
|
||||
$opt = json_decode((string) $plugin['options2'], true);
|
||||
} elseif (!empty($plugin['options'])) {
|
||||
$opt = json_decode($plugin['options'], true);
|
||||
$opt = json_decode((string) $plugin['options'], true);
|
||||
}
|
||||
|
||||
if (!empty($opt)) {
|
||||
|
@ -533,22 +544,22 @@ if (Auth::check()) {
|
|||
}
|
||||
|
||||
echo '
|
||||
<li data-toggle="control-sidebar" class="btn-default" >
|
||||
<a data-toggle="tab" href="#tab_'.$plugin['id'].'" id="link-tab_'.$plugin['id'].'">
|
||||
<li data-toggle="control-sidebar" class="btn-default nav-item" >
|
||||
<a class="nav-link" data-toggle="tab" href="#tab_'.$plugin['id'].'" id="link-tab_'.$plugin['id'].'">
|
||||
'.$plugin['title'].'
|
||||
<span class="badge pull-right">'.($count > 0 ? $count : '').'</span>
|
||||
<span class="right badge badge-danger">'.($count > 0 ? $count : '').'</span>
|
||||
</a>
|
||||
</li>';
|
||||
}
|
||||
}
|
||||
|
||||
// Tab per le note interne
|
||||
if ($in_editor) {
|
||||
if ($structure->permission != '-' && $structure->use_notes) {
|
||||
$notes = $structure->recordNotes($id_record);
|
||||
|
||||
echo '
|
||||
<li data-toggle="control-sidebar" class="btn-default">
|
||||
<a class="bg-info" data-toggle="tab" href="#tab_note" id="link-tab_note">
|
||||
<li data-toggle="control-sidebar" class="btn-default nav-item">
|
||||
<a class="bg-info nav-link" data-toggle="tab" href="#tab_note" id="link-tab_note">
|
||||
'.tr('Note interne').'
|
||||
<span class="badge pull-right">'.($notes->count() ?: '').'</span>
|
||||
</a>
|
||||
|
@ -561,11 +572,11 @@ if (Auth::check()) {
|
|||
$checklists_total = $structure->recordChecks($id_record);
|
||||
|
||||
echo '
|
||||
<li data-toggle="control-sidebar" class="btn-default">
|
||||
<a class="bg-info" data-toggle="tab" href="#tab_checks" id="link-tab_checks">
|
||||
'.tr('Checklist').'
|
||||
'.(($checklists_total->count() > 0) ?
|
||||
'<span class="badge pull-right">'.$checklists_unchecked->count().tr(' / ').($checklists_total->count()).'</span>' : '').'
|
||||
<li data-toggle="control-sidebar" class="btn-default nav-item">
|
||||
<a class="bg-info nav-link" data-toggle="tab" href="#tab_checks" id="link-tab_checks">
|
||||
'.tr('Checklist')
|
||||
.($checklists_total ? ' <span class="badge pull-right">'.$checklists_unchecked->count().tr(' / ').$checklists_total->count().'</span>' : '')
|
||||
.'
|
||||
</a>
|
||||
</li>';
|
||||
}
|
||||
|
@ -573,13 +584,13 @@ if (Auth::check()) {
|
|||
// Tab per le informazioni sulle operazioni
|
||||
if (Auth::admin()) {
|
||||
echo '
|
||||
<li data-toggle="control-sidebar" class="btn-default">
|
||||
<a class="bg-info" data-toggle="tab" href="#tab_info" id="link-tab_info">
|
||||
<li data-toggle="control-sidebar" class="btn-default nav-item">
|
||||
<a class="bg-info nav-link" data-toggle="tab" href="#tab_info" id="link-tab_info">
|
||||
'.tr('Info').'
|
||||
</a>
|
||||
</li>';
|
||||
}
|
||||
|
||||
}
|
||||
echo '
|
||||
</ul>
|
||||
</aside>
|
||||
|
@ -588,12 +599,9 @@ if (Auth::check()) {
|
|||
}
|
||||
|
||||
echo '
|
||||
<!-- Right side column. Contains the navbar and content of the page -->
|
||||
<aside class="content-wrapper">
|
||||
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
<div class="row">';
|
||||
<div class="content-wrapper">
|
||||
<section class="content">';
|
||||
|
||||
if (string_contains($_SERVER['SCRIPT_FILENAME'], 'editor.php')) {
|
||||
$location = 'editor_right';
|
||||
|
@ -601,9 +609,6 @@ if (Auth::check()) {
|
|||
$location = 'controller_right';
|
||||
}
|
||||
|
||||
echo '
|
||||
<div class="col-md-12">';
|
||||
|
||||
// Eventuale messaggio personalizzato per l'installazione corrente
|
||||
$extra_file = App::filepath('include/custom/extra', 'extra.php');
|
||||
if ($extra_file) {
|
||||
|
@ -616,14 +621,14 @@ if (Auth::check()) {
|
|||
include_once $extra_file;
|
||||
}
|
||||
|
||||
if (!empty($messages['info']) || !empty($messages['warning']) || !empty($messages['error'])) {
|
||||
if (!empty($messages['warning']) || !empty($messages['error'])) {
|
||||
echo '
|
||||
<div class="box box-warning box-center">
|
||||
<div class="box-header with-border text-center">
|
||||
<h3 class="box-title">'.tr('Informazioni').'</h3>
|
||||
<div class="card card-warning card-center">
|
||||
<div class="card-header with-border text-center">
|
||||
<h3 class="card-title">'.tr('Informazioni').'</h3>
|
||||
</div>
|
||||
|
||||
<div class="box-body">';
|
||||
<div class="card-body">';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -631,9 +636,11 @@ if (Auth::check()) {
|
|||
if (!empty($messages['info'])) {
|
||||
foreach ($messages['info'] as $value) {
|
||||
echo '
|
||||
<div class="alert alert-success push">
|
||||
<i class="fa fa-check"></i> '.$value.'
|
||||
</div>';
|
||||
<script>
|
||||
$(document).ready( function(){
|
||||
window.parent.toastr.success("'.$value.'", toastr.options);
|
||||
});
|
||||
</script>';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -642,7 +649,8 @@ if (!empty($messages['error'])) {
|
|||
foreach ($messages['error'] as $value) {
|
||||
echo '
|
||||
<div class="alert alert-danger push">
|
||||
<i class="fa fa-times"></i> '.$value.'
|
||||
<h4><i class="fa fa fa-ban"></i> '.tr('Errore').'</h4>
|
||||
'.$value.'
|
||||
</div>';
|
||||
}
|
||||
}
|
||||
|
@ -652,7 +660,7 @@ if (!empty($messages['warning'])) {
|
|||
foreach ($messages['warning'] as $value) {
|
||||
echo '
|
||||
<div class="alert alert-warning push">
|
||||
<i class="fa fa-warning"></i>
|
||||
<h4><i class="fa fa-warning"></i> '.tr('Attenzione').'</h4>
|
||||
'.$value.'
|
||||
</div>';
|
||||
}
|
||||
|
|
88
index.php
88
index.php
|
@ -21,14 +21,24 @@ $skip_permissions = true;
|
|||
include_once __DIR__.'/core.php';
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\QueryException;
|
||||
|
||||
$op = filter('op');
|
||||
|
||||
$microsoft = null;
|
||||
|
||||
if ($dbo->isConnected()) {
|
||||
try {
|
||||
$microsoft = $dbo->selectOne('zz_oauth2', '*', ['nome' => 'Microsoft', 'enabled' => 1, 'is_login' => 1]);
|
||||
} catch (QueryException $e) {
|
||||
}
|
||||
}
|
||||
|
||||
// LOGIN
|
||||
switch ($op) {
|
||||
case 'login':
|
||||
$username = post('username');
|
||||
$password = post('password');
|
||||
$password = $_POST['password'];
|
||||
|
||||
if ($dbo->isConnected() && $dbo->isInstalled() && auth()->attempt($username, $password)) {
|
||||
$_SESSION['keep_alive'] = true;
|
||||
|
@ -46,14 +56,14 @@ switch ($op) {
|
|||
}
|
||||
|
||||
// Rimozione log vecchi
|
||||
//$dbo->query('DELETE FROM `zz_operations` WHERE DATE_ADD(`created_at`, INTERVAL 30*24*60*60 SECOND) <= NOW()');
|
||||
// $dbo->query('DELETE FROM `zz_operations` WHERE DATE_ADD(`created_at`, INTERVAL 30*24*60*60 SECOND) <= NOW()');
|
||||
} else {
|
||||
$status = auth()->getCurrentStatus();
|
||||
|
||||
flash()->error(Auth::getStatus()[$status]['message']);
|
||||
|
||||
redirect(base_path().'/index.php');
|
||||
exit();
|
||||
exit;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -62,7 +72,7 @@ switch ($op) {
|
|||
Auth::logout();
|
||||
|
||||
redirect(base_path().'/index.php');
|
||||
exit();
|
||||
exit;
|
||||
}
|
||||
|
||||
if (Auth::check() && isset($dbo) && $dbo->isConnected() && $dbo->isInstalled()) {
|
||||
|
@ -73,7 +83,7 @@ if (Auth::check() && isset($dbo) && $dbo->isConnected() && $dbo->isInstalled())
|
|||
} else {
|
||||
redirect(base_path().'/index.php?op=logout');
|
||||
}
|
||||
exit();
|
||||
exit;
|
||||
}
|
||||
|
||||
// Modalità manutenzione
|
||||
|
@ -97,10 +107,9 @@ include_once App::filepath('include|custom|', 'top.php');
|
|||
// Controllo se è una beta e in caso mostro un warning
|
||||
if (Update::isBeta()) {
|
||||
echo '
|
||||
<div class="clearfix"> </div>
|
||||
<div class="alert alert-warning alert-dismissable col-md-6 col-md-push-3 text-center fade in">
|
||||
<i class="fa fa-warning"></i> <b>'.tr('Attenzione!').'</b> '.tr('Stai utilizzando una versione <b>non stabile</b> di OSM.').'
|
||||
|
||||
<div class="clearfix"></div>
|
||||
<div class="alert alert-warning alert-dismissible col-md-6 offset-md-3 text-center show">
|
||||
<i class="fa fa-exclamation-triangle"></i> <strong>'.tr('Attenzione!').'</strong> '.tr('Stai utilizzando una versione <b>non stabile</b> di OSM.').'
|
||||
<button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button>
|
||||
</div>';
|
||||
}
|
||||
|
@ -108,73 +117,86 @@ if (Update::isBeta()) {
|
|||
// Controllo se è una beta e in caso mostro un warning
|
||||
if (Auth::isBrute()) {
|
||||
echo '
|
||||
<div class="box box-danger box-center" id="brute">
|
||||
<div class="box box-danger" id="brute">
|
||||
<div class="box-header with-border text-center">
|
||||
<h3 class="box-title">'.tr('Attenzione').'</h3>
|
||||
</div>
|
||||
|
||||
<div class="box-body text-center">
|
||||
<p>'.tr('Sono stati effettuati troppi tentativi di accesso consecutivi!').'</p>
|
||||
<p>'.tr('Tempo rimanente (in secondi)').': <span id="brute-timeout">'.(Auth::getBruteTimeout() + 1).'</span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$(".login-box").fadeOut();
|
||||
$(".login-box").hide();
|
||||
brute();
|
||||
});
|
||||
|
||||
function brute() {
|
||||
var value = parseFloat($("#brute-timeout").html()) - 1;
|
||||
$("#brute-timeout").html(value);
|
||||
var value = parseFloat($("#brute-timeout").text()) - 1;
|
||||
$("#brute-timeout").text(value);
|
||||
|
||||
if(value > 0){
|
||||
setTimeout("brute()", 1000);
|
||||
} else{
|
||||
setTimeout(brute, 1000);
|
||||
} else {
|
||||
$("#brute").fadeOut();
|
||||
$(".login-box").fadeIn();
|
||||
}
|
||||
}
|
||||
</script>';
|
||||
}
|
||||
|
||||
if (!empty(flash()->getMessage('error'))) {
|
||||
echo '
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$(".login-box").effect("shake");
|
||||
$(".login-box").addClass("animated shake");
|
||||
});
|
||||
</script>';
|
||||
}
|
||||
|
||||
echo '
|
||||
<form action="?op=login" method="post" class="login-box box" autocomplete="off" >
|
||||
<div class="box-header with-border text-center">
|
||||
<img src="'.App::getPaths()['img'].'/logo_completo.png" class="img-responsive" alt="'.tr('OpenSTAManager, il software gestionale open source per assistenza tecnica e fatturazione elettronica').'">
|
||||
<form action="?op=login" method="post" autocomplete="off">
|
||||
<div class="login-box">
|
||||
<div class="card card-outline card-orange">
|
||||
<div class="card-header text-center">
|
||||
<img src="'.App::getPaths()['img'].'/logo_completo.png" alt="'.tr('OpenSTAManager, il software gestionale open source per assistenza tecnica e fatturazione elettronica').'" class="img-fluid">
|
||||
</div>
|
||||
|
||||
<div class="login-box-body box-body">
|
||||
<div class="form-group input-group">
|
||||
<span class="input-group-addon before"><i class="fa fa-user"></i> </span>
|
||||
<div class="card-body">
|
||||
<p class="login-box-msg">'.tr('Accedi con le tue credenziali').'</p>
|
||||
<div class="input-group mb-3">
|
||||
<input type="text" name="username" autocomplete="username" class="form-control" placeholder="'.tr('Nome utente').'"';
|
||||
if (isset($username)) {
|
||||
echo ' value="'.$username.'"';
|
||||
}
|
||||
|
||||
echo ' required>
|
||||
<div class="input-group-append">
|
||||
<div class="input-group-text">
|
||||
<i class="fa fa-user"></i>
|
||||
</div>
|
||||
|
||||
{[ "type": "password", "name": "password", "autocomplete": "current-password", "placeholder": "'.tr('Password').'", "icon-before": "<i class=\"fa fa-lock\"></i>"]}
|
||||
|
||||
<div class="text-right">
|
||||
<small><a href="'.base_path().'/reset.php">'.tr('Password dimenticata?').'</a></small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- /.box-body -->
|
||||
<div class="box-footer">
|
||||
<button type="submit" id="login" class="btn btn-danger btn-block">'.tr('Accedi').'</button>
|
||||
<div class="mb-3">
|
||||
{[ "type": "password", "name": "password", "autocomplete": "current-password", "placeholder": "'.tr('Password').'" ]}
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-danger btn-block btn-flat">'.tr('Accedi').'</button>
|
||||
<br>
|
||||
<p><a href="'.base_path().'/reset.php">'.tr('Password dimenticata?').'</a></p>';
|
||||
if ($microsoft) {
|
||||
echo '
|
||||
<div class="social-auth-links text-center">
|
||||
<p>- oppure -</p>
|
||||
|
||||
<a href="'.base_path().'/oauth2_login.php?id='.$microsoft['id'].'" class="btn btn-block btn-social btn-primary btn-flat"><i class="fa fa-windows"></i>'.tr('Accedi con Microsoft').'</a>
|
||||
</div>';
|
||||
}
|
||||
echo '
|
||||
</div>
|
||||
</div>
|
||||
<!-- box-footer -->
|
||||
</form>
|
||||
<!-- /.box -->
|
||||
|
||||
|
|
48
info.php
48
info.php
|
@ -26,15 +26,15 @@ $paths = App::getPaths();
|
|||
include_once App::filepath('include|custom|', 'top.php');
|
||||
|
||||
echo '
|
||||
<div class="box">
|
||||
<div class="box-header">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<img src="'.$paths['img'].'/logo_completo.png" class="pull-left img-responsive" width="300" alt="'.tr('OSM Logo').'">
|
||||
<div class="pull-right">
|
||||
<div class="float-right d-none d-sm-inline">
|
||||
<i class="fa fa-info"></i> '.tr('Informazioni').'
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box-body">';
|
||||
<div class="card-body">';
|
||||
|
||||
if (file_exists(base_dir().'/assistenza.php')) {
|
||||
include base_dir().'/assistenza.php';
|
||||
|
@ -60,12 +60,12 @@ if (file_exists(base_dir().'/assistenza.php')) {
|
|||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="box box-primary">
|
||||
<div class="box-header">
|
||||
<h3 class="box-title text-uppercase"><i class="fa fa-globe"></i> '.tr('Perchè software libero').'</h3>
|
||||
<div class="card card-primary">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title text-uppercase"><i class="fa fa-globe"></i> '.tr('Perchè software libero').'</h3>
|
||||
</div>
|
||||
|
||||
<div class="box-body">
|
||||
<div class="card-body">
|
||||
<p>'.tr("Il progetto è software libero perchè permette a tutti di conoscere come funziona avendo il codice sorgente del programma e fornisce così la possibilità di studiare come funziona, modificarlo, adattarlo alle proprie esigenze e, in ambito commerciale, non obbliga l'utilizzatore ad essere legato allo stesso fornitore di assistenza").'.</p>
|
||||
|
||||
<p>'.tr("E' altrettanto importante sapere come funziona per conoscere come vengono trattati i VOSTRI dati, proteggendo così la vostra <b>privacy</b>").'.</p>
|
||||
|
@ -83,23 +83,23 @@ if (file_exists(base_dir().'/assistenza.php')) {
|
|||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="box box-warning">
|
||||
<div class="box-header">
|
||||
<h3 class="box-title text-uppercase"><i class="fa fa-download"></i> '.tr('Aggiornamenti e nuove versioni').'</h3>
|
||||
<div class="card card-warning">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title text-uppercase"><i class="fa fa-download"></i> '.tr('Aggiornamenti e nuove versioni').'</h3>
|
||||
</div>
|
||||
|
||||
<div class="box-body">
|
||||
<div class="card-body">
|
||||
<p>'.tr("Tutti gli aggiornamenti e le nuove versioni sono disponibili all'indirizzo").':</p>
|
||||
<a href="https://www.openstamanager.com/downloads/" target="_blank"><i class="fa fa-external-link"></i> www.openstamanager.com/downloads/</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box box-default">
|
||||
<div class="box-header">
|
||||
<h3 class="box-title text-uppercase"><i class="fa fa-book"></i> '.tr('Guida e documentazione tecnica').'</h3>
|
||||
<div class="card card-default">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title text-uppercase"><i class="fa fa-book"></i> '.tr('Guida e documentazione tecnica').'</h3>
|
||||
</div>
|
||||
|
||||
<div class="box-body">
|
||||
<div class="card-body">
|
||||
<p>'.tr("La guida all'utilizzo di <strong>OpenSTAManager</strong> e la documentazione tecnica sono consultabili all'indirizzo").':</p>
|
||||
<a href="https://docs.openstamanager.com/" target="_blank"><i class="fa fa-external-link"></i> docs.openstamanager.com/</a>
|
||||
</div>
|
||||
|
@ -109,12 +109,12 @@ if (file_exists(base_dir().'/assistenza.php')) {
|
|||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="box box-danger">
|
||||
<div class="box-header">
|
||||
<h3 class="box-title text-uppercase"><i class="fa fa-group"></i> '.tr('Community').'</h3>
|
||||
<div class="card card-danger">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title text-uppercase"><i class="fa fa-group"></i> '.tr('Community').'</h3>
|
||||
</div>
|
||||
|
||||
<div class="box-body">
|
||||
<div class="card-body">
|
||||
<p>'.tr('La community è un componente importante in un progetto open-source perchè mette in contatto le persone tra di loro, utenti e programmatori').'.</p>
|
||||
|
||||
<p>'.tr('Con OpenSTAManager siamo presenti su').':</p>
|
||||
|
@ -164,12 +164,12 @@ if (file_exists(base_dir().'/assistenza.php')) {
|
|||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="box box-success">
|
||||
<div class="box-header">
|
||||
<h3 class="box-title text-uppercase"><i class="fa fa-euro"></i> '.tr('Servizi a pagamento').'</h3>
|
||||
<div class="card card-success">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title text-uppercase"><i class="fa fa-euro"></i> '.tr('Servizi a pagamento').'</h3>
|
||||
</div>
|
||||
|
||||
<div class="box-body">
|
||||
<div class="card-body">
|
||||
<p>'.tr('Per le aziende che hanno necessità di essere seguite da <b>supporto professionale</b> è disponibile un servizio di assistenza e supporto a pagamento').'.</p>
|
||||
|
||||
<p>'.tr("E' disponibile anche un <b>servizio cloud</b> su cui poter installare OpenSTAManager, in modo da non doverti più preoccupare di backup, aggiornamenti e gestione dei dati").'.</p>
|
||||
|
|
186
lib/common.php
186
lib/common.php
|
@ -75,7 +75,7 @@ function calcola_sconto($data)
|
|||
|
||||
$price = floatval($data['prezzo']);
|
||||
|
||||
$percentages = explode('+', $data['sconto']);
|
||||
$percentages = explode('+', (string) $data['sconto']);
|
||||
foreach ($percentages as $percentage) {
|
||||
$discount = $price / 100 * floatval($percentage);
|
||||
|
||||
|
@ -95,12 +95,6 @@ function calcola_sconto($data)
|
|||
|
||||
/**
|
||||
* Individua il valore della colonna order per i nuovi elementi di una tabella.
|
||||
*
|
||||
* @param $table
|
||||
* @param $field
|
||||
* @param $id
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function orderValue($table, $field, $id)
|
||||
{
|
||||
|
@ -109,10 +103,6 @@ function orderValue($table, $field, $id)
|
|||
|
||||
/**
|
||||
* Ricalcola il riordinamento righe di una tabella.
|
||||
*
|
||||
* @param $table
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function reorderRows($table, $field, $id)
|
||||
{
|
||||
|
@ -172,14 +162,13 @@ function provvigioneInfo(Accounting $riga, $mostra_provigione = true)
|
|||
/**
|
||||
* Genera i riferimenti ai documenti del gestionale, attraverso l'interfaccia Common\ReferenceInterface.
|
||||
*
|
||||
* @param $document
|
||||
* @param string $text Formato "Contenuto descrittivo _DOCUMENT_"
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function reference($document, $text = null)
|
||||
{
|
||||
if (!empty($document) && !($document instanceof \Common\ReferenceInterface)) {
|
||||
if (!empty($document) && !($document instanceof Common\ReferenceInterface)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -198,7 +187,7 @@ function reference($document, $text = null)
|
|||
}
|
||||
|
||||
$description = $text ?: tr('Rif. _DOCUMENT_', [
|
||||
'_DOCUMENT_' => strtolower($content),
|
||||
'_DOCUMENT_' => strtolower((string) $content),
|
||||
]);
|
||||
|
||||
return Modules::link($module_id, $document_id, $description, $description, $extra);
|
||||
|
@ -208,22 +197,20 @@ function reference($document, $text = null)
|
|||
* Funzione che gestisce il parsing di uno sconto combinato e la relativa trasformazione in sconto fisso.
|
||||
* Esempio: (40 + 10) % = 44 %.
|
||||
*
|
||||
* @param $combinato
|
||||
*
|
||||
* @return float|int
|
||||
*/
|
||||
function parseScontoCombinato($combinato)
|
||||
{
|
||||
$sign = substr($combinato, 0, 1);
|
||||
$sign = substr((string) $combinato, 0, 1);
|
||||
$original = $sign != '+' && $sign != '-' ? '+'.$combinato : $combinato;
|
||||
$pieces = preg_split('/[+,-]+/', $original);
|
||||
$pieces = preg_split('/[+,-]+/', (string) $original);
|
||||
unset($pieces[0]);
|
||||
|
||||
$result = 1;
|
||||
$text = $original;
|
||||
foreach ($pieces as $piece) {
|
||||
$sign = substr($text, 0, 1);
|
||||
$text = substr($text, 1 + strlen($piece));
|
||||
$sign = substr((string) $text, 0, 1);
|
||||
$text = substr((string) $text, 1 + strlen($piece));
|
||||
|
||||
$result *= 1 - floatval($sign.$piece) / 100;
|
||||
}
|
||||
|
@ -232,10 +219,7 @@ function parseScontoCombinato($combinato)
|
|||
}
|
||||
|
||||
/**
|
||||
* Funzione che gestisce il parsing di uno sconto combinato e la relativa trasformazione in sconto fisso.
|
||||
* Esempio: (40 + 10) % = 44 %.
|
||||
*
|
||||
* @param $combinato
|
||||
* Visualizza le informazioni del segmento.
|
||||
*
|
||||
* @return float|int
|
||||
*/
|
||||
|
@ -245,3 +229,157 @@ function getSegmentPredefined($id_module)
|
|||
|
||||
return $id_segment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Funzione che visualizza i prezzi degli articoli nei listini.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getPrezzoConsigliato($id_anagrafica, $direzione, $id_articolo, $riga = null)
|
||||
{
|
||||
if ($riga) {
|
||||
$qta = $riga->qta;
|
||||
$prezzo_unitario_corrente = $riga->prezzo_unitario_corrente;
|
||||
$sconto_percentuale_corrente = $riga->sconto_percentuale;
|
||||
} else {
|
||||
$qta = 1;
|
||||
}
|
||||
$prezzi_ivati = setting('Utilizza prezzi di vendita comprensivi di IVA');
|
||||
$show_notifica_prezzo = null;
|
||||
$show_notifica_sconto = null;
|
||||
$prezzo_unitario = 0;
|
||||
$sconto = 0;
|
||||
|
||||
// Prezzi netti clienti / listino fornitore
|
||||
$query = 'SELECT minimo, massimo,
|
||||
sconto_percentuale,
|
||||
'.($prezzi_ivati ? 'prezzo_unitario_ivato' : 'prezzo_unitario').' AS prezzo_unitario
|
||||
FROM mg_prezzi_articoli
|
||||
WHERE id_articolo = '.prepare($id_articolo).' AND dir = '.prepare($direzione).' AND id_anagrafica = '.prepare($id_anagrafica).'
|
||||
ORDER BY minimo ASC, massimo DESC';
|
||||
$prezzi = database()->fetchArray($query);
|
||||
|
||||
// Prezzi listini clienti
|
||||
$query = 'SELECT sconto_percentuale AS sconto_percentuale_listino,
|
||||
'.($prezzi_ivati ? 'prezzo_unitario_ivato' : 'prezzo_unitario').' AS prezzo_unitario_listino
|
||||
FROM mg_listini
|
||||
LEFT JOIN mg_listini_articoli ON mg_listini.id=mg_listini_articoli.id_listino
|
||||
LEFT JOIN an_anagrafiche ON mg_listini.id=an_anagrafiche.id_listino
|
||||
WHERE mg_listini.data_attivazione<=NOW()
|
||||
AND (mg_listini_articoli.data_scadenza>=NOW() OR (mg_listini_articoli.data_scadenza IS NULL AND mg_listini.data_scadenza_predefinita>=NOW()))
|
||||
AND mg_listini.attivo=1
|
||||
AND id_articolo = '.prepare($id_articolo).'
|
||||
AND dir = '.prepare($direzione).'
|
||||
AND idanagrafica = '.prepare($id_anagrafica);
|
||||
$listino = database()->fetchOne($query);
|
||||
|
||||
// Prezzi listini clienti sempre visibili
|
||||
$query = 'SELECT mg_listini.nome, sconto_percentuale AS sconto_percentuale_listino_visibile,
|
||||
'.($prezzi_ivati ? 'prezzo_unitario_ivato' : 'prezzo_unitario').' AS prezzo_unitario_listino_visibile
|
||||
FROM mg_listini
|
||||
LEFT JOIN mg_listini_articoli ON mg_listini.id=mg_listini_articoli.id_listino
|
||||
WHERE mg_listini.data_attivazione<=NOW()
|
||||
AND (mg_listini_articoli.data_scadenza>=NOW() OR (mg_listini_articoli.data_scadenza IS NULL AND mg_listini.data_scadenza_predefinita>=NOW()))
|
||||
AND mg_listini.attivo=1 AND mg_listini.is_sempre_visibile=1 AND id_articolo = '.prepare($id_articolo).' AND dir = '.prepare($direzione);
|
||||
$listini_sempre_visibili = database()->fetchArray($query);
|
||||
|
||||
if ($prezzi) {
|
||||
foreach ($prezzi as $prezzo) {
|
||||
if ($qta >= $prezzo['minimo'] && $qta <= $prezzo['massimo']) {
|
||||
$show_notifica_prezzo = $prezzo['prezzo_unitario'] != $prezzo_unitario_corrente ? true : $show_notifica_prezzo;
|
||||
$show_notifica_sconto = $prezzo['sconto_percentuale'] != $sconto_percentuale_corrente ? true : $show_notifica_sconto;
|
||||
$prezzo_unitario = $prezzo['prezzo_unitario'];
|
||||
$sconto = $prezzo['sconto_percentuale'];
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($prezzo['minimo'] == null && $prezzo['massimo'] == null && $prezzo['prezzo_unitario'] != null) {
|
||||
$show_notifica_prezzo = $prezzo['prezzo_unitario'] != $prezzo_unitario_corrente ? true : $show_notifica_prezzo;
|
||||
$show_notifica_sconto = $prezzo['sconto_percentuale'] != $sconto_percentuale_corrente ? true : $show_notifica_sconto;
|
||||
$prezzo_unitario = $prezzo['prezzo_unitario'];
|
||||
$sconto = $prezzo['sconto_percentuale'];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($listino) {
|
||||
$show_notifica_prezzo = $listino['prezzo_unitario_listino'] != $prezzo_unitario_corrente ? true : $show_notifica_prezzo;
|
||||
$show_notifica_sconto = $listino['sconto_percentuale_listino'] != $sconto_percentuale_corrente ? true : $show_notifica_sconto;
|
||||
$prezzo_unitario = $listino['prezzo_unitario_listino'];
|
||||
$sconto = $listino['sconto_percentuale_listino'];
|
||||
}
|
||||
if ($listini_sempre_visibili) {
|
||||
foreach ($listini_sempre_visibili as $listino_sempre_visibile) {
|
||||
$show_notifica_prezzo = $listino_sempre_visibile['prezzo_unitario_listino_visibile'] != $prezzo_unitario_corrente ? true : $show_notifica_prezzo;
|
||||
$show_notifica_sconto = $listino_sempre_visibile['sconto_percentuale_listino_visibile'] != $sconto_percentuale_corrente ? true : $show_notifica_sconto;
|
||||
}
|
||||
}
|
||||
|
||||
$result = [];
|
||||
$result['show_notifica_prezzo'] = $show_notifica_prezzo;
|
||||
$result['show_notifica_sconto'] = $show_notifica_sconto;
|
||||
$result['prezzo_unitario'] = $prezzo_unitario;
|
||||
$result['sconto'] = $sconto;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Funzione PHP che controlla se un campo "cellulare" contiene già un prefisso telefonico:
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function checkPrefix($cellulare)
|
||||
{
|
||||
// Array di prefissi telefonici da controllare
|
||||
$internationalPrefixes = ['+1', '+44', '+49', '+33', '+39']; // Esempi di prefissi
|
||||
|
||||
// Controlla se il campo "cellulare" inizia con uno dei prefissi
|
||||
foreach ($internationalPrefixes as $prefix) {
|
||||
if (str_starts_with((string) $cellulare, $prefix)) {
|
||||
return true; // Un prefisso è già presente
|
||||
}
|
||||
}
|
||||
|
||||
return false; // Nessun prefisso trovato
|
||||
}
|
||||
|
||||
/**
|
||||
* Funzione PHP che dato id_modulo restituisce un array contenente tutti i valori di "search_" per quel modulo.
|
||||
*
|
||||
* @param int $id_module
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getSearchValues($id_module)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
if (isset($_SESSION['module_'.$id_module])) {
|
||||
// Itera su tutti i valori
|
||||
foreach ($_SESSION['module_'.$id_module] as $key => $value) {
|
||||
// Controlla se la chiave inizia con "search_"
|
||||
if (!empty($value) && string_starts_with($key, 'search_')) {
|
||||
$result[str_replace(['search_', '-'], ['', ' '], $key)] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Funzione PHP che controlla se l'articolo ha una distinta.
|
||||
*
|
||||
* @param int $id_articolo
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function hasArticoliFiglio($id_articolo)
|
||||
{
|
||||
if (function_exists('renderDistinta')) {
|
||||
return database()->fetchOne('SELECT qta FROM mg_articoli_distinte WHERE id_articolo='.prepare($id_articolo));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,13 +40,9 @@ function get_next_code($str, $qty = 1, $mask = '')
|
|||
* Se descrizione = 1 e il tipo è 'query=' mi restituisce il valore del campo descrizione della query.
|
||||
*
|
||||
* @deprecated 2.4.2
|
||||
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $sezione
|
||||
* @param string $descrizione
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function get_var($nome, $sezione = null, $descrizione = false, $again = false)
|
||||
{
|
||||
|
@ -163,7 +159,7 @@ function datediff($interval, $datefrom, $dateto, $using_timestamps = false)
|
|||
break;
|
||||
case 'm': // Number of full months
|
||||
$months_difference = floor($difference / 2678400);
|
||||
while (mktime(date('H', $datefrom), date('i', $datefrom), date('s', $datefrom), date('n', $datefrom) + ($months_difference), date('j', $dateto), date('Y', $datefrom)) < $dateto) {
|
||||
while (mktime(date('H', $datefrom), date('i', $datefrom), date('s', $datefrom), date('n', $datefrom) + $months_difference, date('j', $dateto), date('Y', $datefrom)) < $dateto) {
|
||||
++$months_difference;
|
||||
}
|
||||
--$months_difference;
|
||||
|
@ -207,12 +203,6 @@ function datediff($interval, $datefrom, $dateto, $using_timestamps = false)
|
|||
}
|
||||
|
||||
/**
|
||||
* @param $field
|
||||
* @param $id_riga
|
||||
* @param $old_qta
|
||||
* @param $new_qta
|
||||
* @param $dir
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
* @return bool
|
||||
|
@ -274,8 +264,6 @@ function seriali_non_rimuovibili($field, $id_riga, $dir)
|
|||
/**
|
||||
* Restistuisce le informazioni sull'eventuale riferimento ai documenti.
|
||||
*
|
||||
* @param $info
|
||||
* @param $dir
|
||||
* @param array $ignore
|
||||
*
|
||||
* @deprecated
|
||||
|
|
|
@ -54,8 +54,6 @@ function redirect($url, $type = 'php')
|
|||
* Verifica e corregge il nome di un file.
|
||||
*
|
||||
* @param string $filename
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function sanitizeFilename($filename)
|
||||
{
|
||||
|
@ -80,7 +78,7 @@ function delete($files)
|
|||
// Eliminazione
|
||||
try {
|
||||
$fs->remove($files);
|
||||
} catch (IOException $e) {
|
||||
} catch (IOException) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -96,14 +94,13 @@ function delete($files)
|
|||
*/
|
||||
function directory($path)
|
||||
{
|
||||
return Util\FileSystem::directory($path);
|
||||
return FileSystem::directory($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a file, or recursively copy a folder and its contents.
|
||||
*
|
||||
* @param array|string $source Source path
|
||||
* @param string $dest Destination path
|
||||
* @param array|string $ignores Paths to ingore
|
||||
*
|
||||
* @return bool Returns TRUE on success, FALSE on failure
|
||||
|
@ -132,16 +129,16 @@ function copyr($source, $destination, $ignores = [])
|
|||
|
||||
try {
|
||||
$fs->chmod($destination, 0777, 0000, true);
|
||||
} catch (IOException $e) {
|
||||
} catch (IOException) {
|
||||
}
|
||||
|
||||
foreach ($files as $file) {
|
||||
$filename = rtrim($destination, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.$file->getRelativePathname();
|
||||
$filename = rtrim((string) $destination, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.$file->getRelativePathname();
|
||||
|
||||
// Copia effettiva del file
|
||||
try {
|
||||
$fs->copy($file, $filename, true);
|
||||
} catch (IOException $e) {
|
||||
} catch (IOException) {
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
|
@ -178,7 +175,7 @@ function getOS()
|
|||
];
|
||||
|
||||
foreach ($os as $key => $value) {
|
||||
if (strpos($_SERVER['HTTP_USER_AGENT'], $key)) {
|
||||
if (strpos((string) $_SERVER['HTTP_USER_AGENT'], $key)) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
@ -212,7 +209,7 @@ function get_client_ip()
|
|||
$ipaddress = 'UNKNOWN';
|
||||
}
|
||||
|
||||
return strip_tags($ipaddress);
|
||||
return strip_tags((string) $ipaddress);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -239,12 +236,12 @@ function translateTemplate()
|
|||
];
|
||||
|
||||
$template = replace($template, $replaces);
|
||||
$template = HTMLBuilder::replace($template);
|
||||
$template = $template ? HTMLBuilder::replace($template) : $template;
|
||||
$template = replace($template, $replaces);
|
||||
|
||||
// Informazioni estese sulle azioni dell'utente
|
||||
$op = post('op');
|
||||
if (!empty($op) && $op != 'summable-results') {
|
||||
if (!empty($op) && $op != 'summable-results' && $op != 'avg-results') {
|
||||
OperationLog::setInfo('id_module', $id_module);
|
||||
OperationLog::setInfo('id_plugin', $id_plugin);
|
||||
OperationLog::setInfo('id_record', $id_record);
|
||||
|
@ -271,7 +268,7 @@ function translateTemplate()
|
|||
|
||||
// Annullo le notifiche (AJAX)
|
||||
if (isAjaxRequest()) {
|
||||
//flash()->clearMessage('info');
|
||||
// flash()->clearMessage('info');
|
||||
}
|
||||
|
||||
echo $template;
|
||||
|
@ -300,7 +297,7 @@ function slashes($string)
|
|||
*/
|
||||
function isAjaxRequest()
|
||||
{
|
||||
return \Whoops\Util\Misc::isAjaxRequest() && filter('ajax') !== null;
|
||||
return Whoops\Util\Misc::isAjaxRequest() && filter('ajax') !== null && filter('ajax') !== '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -327,7 +324,7 @@ function redirectOperation($id_module, $id_record)
|
|||
redirect(base_path().'/controller.php?id_module='.$id_module.$hash);
|
||||
}
|
||||
|
||||
exit();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -342,7 +339,7 @@ function redirectOperation($id_module, $id_record)
|
|||
*/
|
||||
function prepareToField($string)
|
||||
{
|
||||
return str_replace('"', '"', $string);
|
||||
return $string ? str_replace('"', '"', $string) : $string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -354,7 +351,7 @@ function prepareToField($string)
|
|||
*/
|
||||
function isMobile()
|
||||
{
|
||||
return preg_match("/(android|avantgo|blackberry|bolt|boost|cricket|docomo|fone|hiptop|mini|mobi|palm|phone|pie|tablet|up\.browser|up\.link|webos|wos)/i", $_SERVER['HTTP_USER_AGENT']);
|
||||
return preg_match("/(android|avantgo|blackberry|bolt|boost|cricket|docomo|fone|hiptop|mini|mobi|palm|phone|pie|tablet|up\.browser|up\.link|webos|wos)/i", (string) $_SERVER['HTTP_USER_AGENT']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -367,10 +364,10 @@ function isMobile()
|
|||
function getURLPath()
|
||||
{
|
||||
$path = $_SERVER['SCRIPT_FILENAME'];
|
||||
$prefix = rtrim($_SERVER['DOCUMENT_ROOT'], '/\\');
|
||||
$prefix = rtrim((string) $_SERVER['DOCUMENT_ROOT'], '/\\');
|
||||
|
||||
if (substr($path, 0, strlen($prefix)) == $prefix) {
|
||||
$path = substr($path, strlen($prefix));
|
||||
if (str_starts_with((string) $path, $prefix)) {
|
||||
$path = substr((string) $path, strlen($prefix));
|
||||
} else {
|
||||
$path = str_replace(base_dir(), base_path(), $path);
|
||||
}
|
||||
|
@ -409,7 +406,7 @@ function clean($string, $permitted = '')
|
|||
|
||||
function check_query($query)
|
||||
{
|
||||
$query = mb_strtoupper($query);
|
||||
$query = mb_strtoupper((string) $query);
|
||||
|
||||
$blacklist = ['INSERT', 'UPDATE', 'TRUNCATE', 'DELETE', 'DROP', 'GRANT', 'CREATE', 'REVOKE'];
|
||||
foreach ($blacklist as $value) {
|
||||
|
@ -445,18 +442,17 @@ function session_get($name, $default = null)
|
|||
$session = &$session[$piece];
|
||||
}
|
||||
|
||||
return isset($session) ? $session : $default;
|
||||
return $session ?? $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imposta un parametro nella sessione secondo un nome indicato.
|
||||
*
|
||||
* @param string $name Nome del parametro in dot-notation
|
||||
* @param mixed $value Valore da impostare
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function session_set($name, $value)
|
||||
function session_set($name, mixed $value)
|
||||
{
|
||||
$session = &$_SESSION;
|
||||
|
||||
|
|
|
@ -23,15 +23,16 @@
|
|||
* @since 2.4.2
|
||||
*/
|
||||
use HTMLBuilder\HTMLBuilder;
|
||||
use Models\Setting;
|
||||
|
||||
/**
|
||||
* Restituisce l'oggetto dedicato alla gestione della connessione con il database.
|
||||
*
|
||||
* @return \Database
|
||||
* @return Database
|
||||
*/
|
||||
function database()
|
||||
{
|
||||
return \Database::getConnection();
|
||||
return Database::getConnection();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -41,8 +42,6 @@ function database()
|
|||
* @param string $parameter
|
||||
*
|
||||
* @since 2.3
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function prepare($parameter)
|
||||
{
|
||||
|
@ -62,7 +61,7 @@ function prepare($parameter)
|
|||
*/
|
||||
function filter($param, $method = null, $raw = false)
|
||||
{
|
||||
return \Filter::getValue($param, $method, $raw);
|
||||
return Filter::getValue($param, $method, $raw);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -77,7 +76,7 @@ function filter($param, $method = null, $raw = false)
|
|||
*/
|
||||
function post($param, $raw = false)
|
||||
{
|
||||
return \Filter::getValue($param, 'post', $raw);
|
||||
return Filter::getValue($param, 'post', $raw);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -92,7 +91,7 @@ function post($param, $raw = false)
|
|||
*/
|
||||
function get($param, $raw = false)
|
||||
{
|
||||
return \Filter::getValue($param, 'get', $raw);
|
||||
return Filter::getValue($param, 'get', $raw);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -107,7 +106,7 @@ function get($param, $raw = false)
|
|||
*/
|
||||
function setting($name, $again = false)
|
||||
{
|
||||
return \Settings::getValue($name);
|
||||
return Setting::where('nome', '=', $name)->first()->valore;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -115,7 +114,7 @@ function setting($name, $again = false)
|
|||
*
|
||||
* @since 2.4.2
|
||||
*
|
||||
* @return \Util\Messages
|
||||
* @return Util\Messages
|
||||
*/
|
||||
function flash()
|
||||
{
|
||||
|
@ -127,11 +126,11 @@ function flash()
|
|||
*
|
||||
* @since 2.4.2
|
||||
*
|
||||
* @return \Auth
|
||||
* @return Auth
|
||||
*/
|
||||
function auth()
|
||||
{
|
||||
return \Auth::getInstance();
|
||||
return Auth::getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -139,11 +138,11 @@ function auth()
|
|||
*
|
||||
* @since 2.4.2
|
||||
*
|
||||
* @return \Translator
|
||||
* @return Translator
|
||||
*/
|
||||
function trans()
|
||||
{
|
||||
return \Translator::getInstance();
|
||||
return Translator::getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -151,11 +150,11 @@ function trans()
|
|||
*
|
||||
* @since 2.4.2
|
||||
*
|
||||
* @return \Intl\Formatter
|
||||
* @return Intl\Formatter
|
||||
*/
|
||||
function formatter()
|
||||
{
|
||||
return \Translator::getFormatter();
|
||||
return Translator::getFormatter();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -171,7 +170,7 @@ function formatter()
|
|||
*/
|
||||
function tr($string, $parameters = [], $operations = [])
|
||||
{
|
||||
return \Translator::translate($string, $parameters, $operations);
|
||||
return Translator::translate($string, $parameters, $operations);
|
||||
}
|
||||
|
||||
// Retrocompatibilità (con la funzione gettext)
|
||||
|
@ -187,7 +186,7 @@ if (!function_exists('_')) {
|
|||
*
|
||||
* @since 2.4.2
|
||||
*
|
||||
* @return \Monolog\Logger
|
||||
* @return Monolog\Logger
|
||||
*/
|
||||
function logger()
|
||||
{
|
||||
|
@ -213,7 +212,8 @@ function numberFormat($number, $decimals = null)
|
|||
* Restituisce il timestamp indicato formattato secondo la configurazione del sistema.
|
||||
*
|
||||
* @param string $timestamp
|
||||
+ *
|
||||
* + *
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 2.4.8
|
||||
|
@ -260,14 +260,12 @@ function timeFormat($time)
|
|||
*/
|
||||
function currency()
|
||||
{
|
||||
return \Translator::getCurrency();
|
||||
return Translator::getCurrency();
|
||||
}
|
||||
|
||||
/**
|
||||
* Restituisce il numero indicato formattato come una valuta secondo la configurazione del sistema.
|
||||
*
|
||||
* @param string $time
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 2.4.9
|
||||
|
|
53
lib/util.php
53
lib/util.php
|
@ -38,9 +38,7 @@ if (!function_exists('array_column')) {
|
|||
*/
|
||||
function array_column($array, $key)
|
||||
{
|
||||
return array_map(function ($v) use ($key) {
|
||||
return is_object($v) ? $v->$key : $v[$key];
|
||||
}, $array);
|
||||
return array_map(fn ($v) => is_object($v) ? $v->$key : $v[$key], $array);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,8 +46,6 @@ if (!function_exists('array_clean')) {
|
|||
/**
|
||||
* Pulisce i contenuti vuoti di un array.
|
||||
*
|
||||
* @param $array
|
||||
*
|
||||
* @since 2.3.2
|
||||
*
|
||||
* @return array
|
||||
|
@ -57,9 +53,7 @@ if (!function_exists('array_clean')) {
|
|||
function array_clean($array)
|
||||
{
|
||||
if (!empty($array)) {
|
||||
return array_unique(array_values(array_filter($array, function ($value) {
|
||||
return !empty($value);
|
||||
})));
|
||||
return array_unique(array_values(array_filter($array, fn ($value) => !empty($value))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,8 +62,6 @@ if (!function_exists('array_deep_clean')) {
|
|||
/**
|
||||
* Pulisce i contenuti vuoti di un array.
|
||||
*
|
||||
* @param $array
|
||||
*
|
||||
* @since 2.4.11
|
||||
*
|
||||
* @return array
|
||||
|
@ -111,7 +103,7 @@ if (!function_exists('string_starts_with')) {
|
|||
*/
|
||||
function string_starts_with($string, $starts_with)
|
||||
{
|
||||
//return strpos($string, $string_starts_with) === 0;
|
||||
// return strpos($string, $string_starts_with) === 0;
|
||||
return S::create($string)->startsWith($starts_with);
|
||||
}
|
||||
}
|
||||
|
@ -127,7 +119,7 @@ if (!function_exists('string_ends_with')) {
|
|||
*/
|
||||
function string_ends_with($string, $ends_with)
|
||||
{
|
||||
//return substr($string, -strlen($string_ends_with)) === $string_ends_with;
|
||||
// return substr($string, -strlen($string_ends_with)) === $string_ends_with;
|
||||
return S::create($string)->endsWith($ends_with);
|
||||
}
|
||||
}
|
||||
|
@ -143,7 +135,7 @@ if (!function_exists('string_contains')) {
|
|||
*/
|
||||
function string_contains($string, $contains)
|
||||
{
|
||||
//return strpos($string, $contains) !== false;
|
||||
// return strpos($string, $contains) !== false;
|
||||
return S::create($string)->contains($contains);
|
||||
}
|
||||
}
|
||||
|
@ -240,7 +232,7 @@ if (!function_exists('random_string')) {
|
|||
// Don't allow duplicate letters to be disabled if the length is
|
||||
// longer than the available characters
|
||||
if ($no_duplicate_chars && strlen($pool) < $length) {
|
||||
throw new \LengthException('$length exceeds the size of the pool and $no_duplicate_chars is enabled');
|
||||
throw new LengthException('$length exceeds the size of the pool and $no_duplicate_chars is enabled');
|
||||
}
|
||||
|
||||
// Convert the pool of characters into an array of characters and
|
||||
|
@ -286,7 +278,7 @@ if (!function_exists('secure_random_string')) {
|
|||
$bytes = openssl_random_pseudo_bytes($length * 2);
|
||||
|
||||
if ($bytes === false) {
|
||||
throw new \LengthException('$length is not accurate, unable to generate random string');
|
||||
throw new LengthException('$length is not accurate, unable to generate random string');
|
||||
}
|
||||
|
||||
return substr(str_replace(['/', '+', '='], '', base64_encode($bytes)), 0, $length);
|
||||
|
@ -304,9 +296,6 @@ if (!function_exists('download')) {
|
|||
*
|
||||
* @param string $filename The name of the filename to display to
|
||||
* browsers
|
||||
* @param string $content The content to output for the download.
|
||||
* If you don't specify this, just the
|
||||
* headers will be sent
|
||||
*
|
||||
* @since 2.3
|
||||
*
|
||||
|
@ -318,7 +307,7 @@ if (!function_exists('download')) {
|
|||
ob_end_clean();
|
||||
|
||||
if (!headers_sent()) {
|
||||
$filename = !empty($filename) ? $filename : basename($file);
|
||||
$filename = !empty($filename) ? $filename : basename((string) $file);
|
||||
|
||||
// Required for some browsers
|
||||
if (ini_get('zlib.output_compression')) {
|
||||
|
@ -396,13 +385,13 @@ if (!function_exists('isHTTPS')) {
|
|||
*/
|
||||
function isHTTPS($trust_proxy_headers = false)
|
||||
{
|
||||
if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off') {
|
||||
if (!empty($_SERVER['HTTPS']) && strtolower((string) $_SERVER['HTTPS']) !== 'off') {
|
||||
// Check the standard HTTPS headers
|
||||
return true;
|
||||
} elseif ($trust_proxy_headers && isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
|
||||
// Check proxy headers if allowed
|
||||
return true;
|
||||
} elseif (!empty($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) !== 'off') {
|
||||
} elseif (!empty($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower((string) $_SERVER['HTTP_FRONT_END_HTTPS']) !== 'off') {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -427,7 +416,7 @@ if (!function_exists('color_darken')) {
|
|||
}
|
||||
$rgb = '';
|
||||
for ($x = 0; $x < 3; ++$x) {
|
||||
$c = hexdec(substr($color, (2 * $x), 2)) - $dif;
|
||||
$c = hexdec(substr($color, 2 * $x, 2)) - $dif;
|
||||
$c = ($c < 0) ? 0 : dechex($c);
|
||||
$rgb .= (strlen($c) < 2) ? '0'.$c : $c;
|
||||
}
|
||||
|
@ -448,15 +437,15 @@ if (!function_exists('color_inverse')) {
|
|||
*/
|
||||
function color_inverse($start_colour)
|
||||
{
|
||||
if (preg_match('/^#[a-f0-9]{6}$/i', $start_colour)) { //hex color is valid
|
||||
if (preg_match('/^#[a-f0-9]{6}$/i', $start_colour)) { // hex color is valid
|
||||
$R1 = hexdec(substr($start_colour, 1, 2));
|
||||
$G1 = hexdec(substr($start_colour, 3, 2));
|
||||
$B1 = hexdec(substr($start_colour, 5, 2));
|
||||
$R2 = 255;
|
||||
$G2 = 255;
|
||||
$B2 = 255;
|
||||
$L1 = 0.2126 * pow($R1 / 255, 2.2) + 0.7152 * pow($G1 / 255, 2.2) + 0.0722 * pow($B1 / 255, 2.2);
|
||||
$L2 = 0.2126 * pow($R2 / 255, 2.2) + 0.7152 * pow($G2 / 255, 2.2) + 0.0722 * pow($B2 / 255, 2.2);
|
||||
$L1 = 0.2126 * ($R1 / 255) ** 2.2 + 0.7152 * ($G1 / 255) ** 2.2 + 0.0722 * ($B1 / 255) ** 2.2;
|
||||
$L2 = 0.2126 * ($R2 / 255) ** 2.2 + 0.7152 * ($G2 / 255) ** 2.2 + 0.0722 * ($B2 / 255) ** 2.2;
|
||||
if ($L1 > $L2) {
|
||||
$lum = ($L1 + 0.05) / ($L2 + 0.05);
|
||||
} else {
|
||||
|
@ -468,7 +457,12 @@ if (!function_exists('color_inverse')) {
|
|||
return '#000';
|
||||
}
|
||||
} else {
|
||||
return '#000';
|
||||
return match ($start_colour) {
|
||||
'black' => 'white',
|
||||
'blue' => 'white',
|
||||
'purple' => 'white',
|
||||
default => '#000',
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -543,9 +537,6 @@ if (!function_exists('temp_file')) {
|
|||
/**
|
||||
* Crea un file temporaneo e lo imposta per la rimozione alla fine dell'esecuzione.
|
||||
*
|
||||
* @param $name
|
||||
* @param $content
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function temp_file($name = null, $content = null)
|
||||
|
@ -562,7 +553,7 @@ if (!function_exists('temp_file')) {
|
|||
]);
|
||||
$file = rtrim($base_directory, DIRECTORY_SEPARATOR).
|
||||
DIRECTORY_SEPARATOR.
|
||||
ltrim($name, DIRECTORY_SEPARATOR);
|
||||
ltrim((string) $name, DIRECTORY_SEPARATOR);
|
||||
|
||||
file_put_contents($file, $content);
|
||||
|
||||
|
@ -602,6 +593,6 @@ if (!function_exists('adjustBrightness')) {
|
|||
$color = str_pad(dechex($color + $adjustAmount), 2, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
return '#'.implode($hexCode);
|
||||
return '#'.implode('', $hexCode);
|
||||
}
|
||||
}
|
||||
|
|
7433
locale/catalog.pot
7433
locale/catalog.pot
File diff suppressed because it is too large
Load Diff
|
@ -9796,7 +9796,7 @@ msgstr ""
|
|||
#: plugins/receiptFE/edit.php:25
|
||||
msgid ""
|
||||
"Le ricevute delle Fatture Elettroniche permettono di individuare se una "
|
||||
"determinata fattura tramessa è stata accettata dal Sistema Di Interscambio"
|
||||
"determinata fattura trasmessa è stata accettata dal Sistema Di Interscambio"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/receiptFE/edit.php:29 plugins/receiptFE/edit.php:87
|
||||
|
|
Binary file not shown.
16686
locale/en_GB/en_GB.po
16686
locale/en_GB/en_GB.po
File diff suppressed because it is too large
Load Diff
74
log.php
74
log.php
|
@ -17,6 +17,8 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
||||
include_once __DIR__.'/core.php';
|
||||
|
||||
$pageTitle = tr('Log');
|
||||
|
@ -24,20 +26,21 @@ $pageTitle = tr('Log');
|
|||
include_once App::filepath('include|custom|', 'top.php');
|
||||
|
||||
echo '
|
||||
<div class="box">
|
||||
<div class="box-header">
|
||||
<h3 class="box-title"><i class="fa fa-book"></i> '.tr('Ultimi 100 accessi').'</h3>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title"><i class="fa fa-book"></i> '.tr('Ultimi 100 accessi').'</h3>
|
||||
</div>
|
||||
|
||||
<!-- /.box-header -->
|
||||
<div class="box-body table-responsive no-padding">
|
||||
<!-- /.card-header -->
|
||||
<div class="card-body table-responsive no-padding">
|
||||
<table class="datatables table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>'.tr('Username').'</th>
|
||||
<th>'.tr('Data').'</th>
|
||||
<th>'.tr('Stato').'</th>
|
||||
<th>'.tr('Indirizzo IP').'</th>
|
||||
<th width="200">'.tr('Username').'</th>
|
||||
<th width="150">'.tr('Data').'</th>
|
||||
<th width="100">'.tr('Indirizzo IP').'</th>
|
||||
<th>'.tr('Dispositivo').'</th>
|
||||
<th width="180">'.tr('Stato').'</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>';
|
||||
|
@ -50,25 +53,19 @@ if (Auth::admin()) {
|
|||
} else {
|
||||
$q = 'SELECT * FROM `zz_logs` WHERE `id_utente`='.prepare(Auth::user()['id']).' ORDER BY `created_at` DESC LIMIT 0, 100';
|
||||
}
|
||||
$rs = $dbo->fetchArray($q);
|
||||
$n = sizeof($rs);
|
||||
$logs = $dbo->fetchArray($q);
|
||||
|
||||
for ($i = 0; $i < $n; ++$i) {
|
||||
$id = $rs[$i]['id'];
|
||||
$id_utente = $rs[$i]['id_utente'];
|
||||
$username = $rs[$i]['username'];
|
||||
$ip = $rs[$i]['ip'];
|
||||
|
||||
$timestamp = Translator::timestampToLocale($rs[$i]['created_at']);
|
||||
foreach ($logs as $log) {
|
||||
$timestamp = Translator::timestampToLocale($log['created_at']);
|
||||
|
||||
$status = Auth::getStatus();
|
||||
if ($rs[$i]['stato'] == $status['success']['code']) {
|
||||
if ($log['stato'] == $status['success']['code']) {
|
||||
$type = 'success';
|
||||
$stato = $status['success']['message'];
|
||||
} elseif ($rs[$i]['stato'] == $status['disabled']['code']) {
|
||||
} elseif ($log['stato'] == $status['disabled']['code']) {
|
||||
$type = 'warning';
|
||||
$stato = $status['disabled']['message'];
|
||||
} elseif ($rs[$i]['stato'] == $status['unauthorized']['code']) {
|
||||
} elseif ($log['stato'] == $status['unauthorized']['code']) {
|
||||
$type = 'warning';
|
||||
$stato = $status['unauthorized']['message'];
|
||||
} else {
|
||||
|
@ -76,12 +73,15 @@ for ($i = 0; $i < $n; ++$i) {
|
|||
$stato = $status['failed']['message'];
|
||||
}
|
||||
|
||||
$created_at = new Carbon($log['created_at']);
|
||||
|
||||
echo '
|
||||
<tr class="'.$type.'">
|
||||
<td>'.$username.'</td>
|
||||
<td>'.$timestamp.'</td>
|
||||
<td><span class="label label-'.$type.'">'.$stato.'</span></td>
|
||||
<td>'.$ip.'</td>
|
||||
<td>'.$log['username'].'</td>
|
||||
<td class="tip" title="'.$created_at->format('d/m/Y H:i:s').'">'.$created_at->diffForHumans().'</td>
|
||||
<td>'.$log['ip'].'</td>
|
||||
<td class="user-agent tip" title="'.strip_tags($log['user_agent']).'">'.$log['user_agent'].'</td>
|
||||
<td><span class="badge badge-'.$type.'">'.$stato.'</span></td>
|
||||
</tr>';
|
||||
}
|
||||
|
||||
|
@ -90,8 +90,28 @@ echo '
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- /.box-body -->
|
||||
<!-- /.card-body -->
|
||||
</div>
|
||||
<!-- /.box -->';
|
||||
<!-- /.card -->';
|
||||
?>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var parser = new UAParser();
|
||||
|
||||
$('tr').each(function(){
|
||||
user_agent_cell = $(this).find('.user-agent');
|
||||
user_agent = user_agent_cell.text();
|
||||
|
||||
if (user_agent !== '') {
|
||||
parser.setUA(user_agent);
|
||||
device = parser.getResult();
|
||||
|
||||
user_agent_cell.html('<strong>' + (device.browser.name || '') + '</strong> ' + (device.browser.version || '') + ' | <strong>' + (device.os.name || '') + '</strong> ' + (device.os.version || ''));
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<?php
|
||||
include_once App::filepath('include|custom|', 'bottom.php');
|
||||
|
|
30
mail.php
30
mail.php
|
@ -17,6 +17,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use Models\Module;
|
||||
use Modules\Emails\Template;
|
||||
|
||||
include_once __DIR__.'/core.php';
|
||||
|
@ -29,8 +30,8 @@ $placeholder_options = [
|
|||
'is_pec' => intval($smtp['pec']),
|
||||
];
|
||||
|
||||
$body = $module->replacePlaceholders($id_record, $template['body'], $placeholder_options);
|
||||
$subject = $module->replacePlaceholders($id_record, $template['subject'], $placeholder_options);
|
||||
$body = $module->replacePlaceholders($id_record, $template->getTranslation('body'), $placeholder_options);
|
||||
$subject = $module->replacePlaceholders($id_record, $template->getTranslation('subject'), $placeholder_options);
|
||||
|
||||
$emails = [];
|
||||
if ($module->replacePlaceholders($id_record, '{email}')) {
|
||||
|
@ -51,7 +52,7 @@ foreach ($mansioni as $mansione) {
|
|||
}
|
||||
|
||||
// Aggiungo email tecnici assegnati quando sono sul template Notifica intervento
|
||||
if ($template->name == 'Notifica intervento') {
|
||||
if ($template->getTranslation('title') == 'Notifica intervento') {
|
||||
$tecnici = $dbo->select('in_interventi_tecnici_assegnati', 'id_tecnico', [], ['id_intervento' => $id_record]);
|
||||
foreach ($tecnici as $tecnico) {
|
||||
$anagrafica = $dbo->table('an_anagrafiche')->where('idanagrafica', $tecnico['id_tecnico'])->where('email', '!=', '')->first();
|
||||
|
@ -112,21 +113,21 @@ echo '
|
|||
<b>'.tr('Destinatari').' <span class="tip" title="'.tr('Email delle sedi, dei referenti o agente collegato all\'anagrafica.').'"><i class="fa fa-question-circle-o"></i></span></b>
|
||||
<div class="row" id="lista-destinatari">';
|
||||
|
||||
$idx = 0;
|
||||
$idx = 0;
|
||||
|
||||
foreach ($emails as $email) {
|
||||
foreach ($emails as $email) {
|
||||
echo '
|
||||
<div class="col-md-12">
|
||||
{[ "type": "email", "name": "destinatari['.$idx++.']", "value": "'.$email.'", "icon-before": "choice|email", "extra": "onkeyup=\'aggiungiDestinatario();\'", "class": "destinatari", "required": 0 ]}
|
||||
</div>';
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($emails)) {
|
||||
if (empty($emails)) {
|
||||
echo '
|
||||
<div class="col-md-12">
|
||||
{[ "type": "email", "name": "destinatari['.$idx++.']", "value": "", "icon-before": "choice|email", "extra": "onkeyup=\'aggiungiDestinatario();\'", "class": "destinatari", "required": 0 ]}
|
||||
</div>';
|
||||
}
|
||||
}
|
||||
echo '
|
||||
</div>
|
||||
|
||||
|
@ -150,11 +151,11 @@ echo '
|
|||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{[ "type": "select", "multiple": "1", "label": "'.tr('Stampe').'", "name": "prints[]", "value": "'.implode(',', $selected).'", "values": "query=SELECT id, title AS text FROM zz_prints WHERE id_module = '.prepare($id_module).' AND enabled=1 AND is_record=1", "link": "stampa" ]}
|
||||
{[ "type": "select", "multiple": "1", "label": "'.tr('Stampe').'", "name": "prints[]", "value": "'.implode(',', $selected).'", "values": "query=SELECT `zz_prints`.`id`, `title` AS text FROM `zz_prints` LEFT JOIN `zz_prints_lang` ON (`zz_prints`.`id` = `zz_prints_lang`.`id_record` AND `zz_prints_lang`.`id_lang` = '.prepare(Models\Locale::getDefault()->id).') WHERE `id_module` = '.prepare($id_module).' AND `enabled`=1 AND `is_record`=1", "link": "stampa" ]}
|
||||
</div>';
|
||||
|
||||
$uploads = [];
|
||||
if ($smtp['pec'] == 1 && $module['name'] == 'Fatture di vendita') {
|
||||
if ($smtp['pec'] == 1 && $module->getTranslation('title') == 'Fatture di vendita') {
|
||||
$uploads = $dbo->fetchArray('SELECT id FROM zz_files WHERE id_module = '.prepare($module['id']).' AND id_record = '.prepare($id_record).' AND category = \'Fattura Elettronica\'');
|
||||
$uploads = array_column($uploads, 'id');
|
||||
}
|
||||
|
@ -163,24 +164,23 @@ if ($smtp['pec'] == 1 && $module['name'] == 'Fatture di vendita') {
|
|||
echo '
|
||||
|
||||
<div class="col-md-6">
|
||||
{[ "type": "select", "multiple": "1", "label": "'.tr('Allegati').'", "name": "uploads[]", "value": "'.implode(',', $uploads).'", "help": "'.tr('Allegati del documento o caricati nell\'anagrafica dell\'azienda.').'", "values": "query=SELECT id, name AS text FROM zz_files WHERE id_module = '.prepare($id_module).' AND id_record = '.prepare($id_record).' UNION SELECT id, CONCAT(name, \' (Azienda)\') AS text FROM zz_files WHERE id_module = '.prepare(Modules::get('Anagrafiche')['id']).' AND id_record = (SELECT valore FROM zz_settings WHERE nome = \'Azienda predefinita\')", "link": "allegato" ]}
|
||||
{[ "type": "select", "multiple": "1", "label": "'.tr('Allegati').'", "name": "uploads[]", "value": "'.implode(',', $uploads).'", "help": "'.tr('Allegati del documento o caricati nell\'anagrafica dell\'azienda.').'", "values": "query=SELECT `id`, `name` AS text FROM `zz_files` WHERE `id_module` = '.prepare($id_module).' AND `id_record` = '.prepare($id_record).' UNION SELECT `id`, CONCAT(`name`, \' (Azienda)\') AS text FROM `zz_files` WHERE `id_module` = '.Module::where('name', 'Anagrafiche')->first()->id.' AND `id_record` = '.setting('Azienda predefinita').'", "link": "allegato" ]}
|
||||
</div>
|
||||
</div>';
|
||||
|
||||
echo '
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">';
|
||||
echo input([
|
||||
echo input([
|
||||
'type' => 'ckeditor',
|
||||
'use_full_ckeditor' => 1,
|
||||
'label' => tr('Contenuto'),
|
||||
'name' => 'body',
|
||||
'id' => 'body_'.rand(0, 999),
|
||||
'value' => $body,
|
||||
]);
|
||||
]);
|
||||
|
||||
echo '
|
||||
echo '
|
||||
</div>
|
||||
</div>';
|
||||
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
/*
|
||||
* OpenSTAManager: il software gestionale open source per l'assistenza tecnica e la fatturazione
|
||||
* Copyright (C) DevCode s.r.l.
|
||||
*
|
||||
* 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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
include_once __DIR__.'/../../core.php';
|
||||
|
||||
use Modules\FileAdapters\FileAdapter;
|
||||
|
||||
switch (filter('op')) {
|
||||
case 'add':
|
||||
$adapter = new FileAdapter();
|
||||
|
||||
$adapter->name = post('name');
|
||||
$adapter->class = '\\Modules\\FileAdapters\\Adapters\\'.post('class');
|
||||
|
||||
$adapter->save();
|
||||
|
||||
$id_record = $adapter->id;
|
||||
|
||||
flash()->info(tr('Nuoovo adattatore aggiunto!'));
|
||||
|
||||
break;
|
||||
|
||||
case 'update':
|
||||
$adapter->name = post('name');
|
||||
$adapter->class = '\\Modules\\FileAdapters\\Adapters\\'.post('class');
|
||||
$adapter->options = post('options');
|
||||
|
||||
if (post('is_default') == 1) {
|
||||
$dbo->query('UPDATE `zz_storage_adapters` SET `is_default` = 0');
|
||||
$adapter->is_default = post('is_default');
|
||||
}
|
||||
|
||||
$adapter->save();
|
||||
|
||||
flash()->info(tr('Adattatore modificato correttamente!'));
|
||||
|
||||
break;
|
||||
|
||||
case 'delete':
|
||||
$adapter->delete();
|
||||
|
||||
break;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue