Compare commits
511 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90cb83be90 | ||
|
|
1d2cfb2bd7 | ||
|
|
9b00ca926a | ||
|
|
c389fa7026 | ||
|
|
515756f08a | ||
|
|
50e79da171 | ||
|
|
b0d6a9ce5b | ||
|
|
480d18d5ba | ||
|
|
9c8d0ba3cd | ||
|
|
cf62014bc5 | ||
|
|
30c302d1b6 | ||
|
|
fef994b99e | ||
|
|
32bddeca44 | ||
|
|
d61a3d89b7 | ||
|
|
54a9e63851 | ||
|
|
94140c173a | ||
|
|
71d047dd53 | ||
|
|
f721cdbe64 | ||
|
|
60e21cc1be | ||
|
|
b41249eda6 | ||
|
|
51e111f973 | ||
|
|
897c134ee3 | ||
|
|
77700a6a0d | ||
|
|
136e8bf98b | ||
|
|
36c5d915f6 | ||
|
|
e63b3cb76a | ||
|
|
a5b0348da3 | ||
|
|
a272956df2 | ||
|
|
d619522e2a | ||
|
|
22178f9476 | ||
|
|
64ac8299e4 | ||
|
|
ff888e8cf2 | ||
|
|
b65c501f02 | ||
|
|
f78443e6d9 | ||
|
|
5159288bb8 | ||
|
|
4e04e2af28 | ||
|
|
d3e44b779c | ||
|
|
1d49f1fe21 | ||
|
|
f395434f2a | ||
|
|
c975045c35 | ||
|
|
ec70871181 | ||
|
|
c90eac806f | ||
|
|
0ef5eb24d8 | ||
|
|
b645356122 | ||
|
|
f3927861bc | ||
|
|
20f8c7e1e3 | ||
|
|
2bdb26dd06 | ||
|
|
191b4f3f5d | ||
|
|
7dc1929430 | ||
|
|
71acb1189e | ||
|
|
5630193dfe | ||
|
|
2f7e91b46d | ||
|
|
7fdc8e0d00 | ||
|
|
3fed6b7771 | ||
|
|
dd2d10a54f | ||
|
|
ba0260cff5 | ||
|
|
2d08738ae6 | ||
|
|
7184f0bcdc | ||
|
|
a553bb8dff | ||
|
|
cbac71435e | ||
|
|
98d62fa340 | ||
|
|
49ec098b11 | ||
|
|
79179b923e | ||
|
|
64e7b1d4df | ||
|
|
b4e1067b15 | ||
|
|
d659d6dd90 | ||
|
|
fb294a7f7e | ||
|
|
eaaf954244 | ||
|
|
be4f184d97 | ||
|
|
10f1ac93ac | ||
|
|
e6915f36a5 | ||
|
|
ce18449cc7 | ||
|
|
cd421c4558 | ||
|
|
25dca51b5e | ||
|
|
3d69498c6e | ||
|
|
2aa850439c | ||
|
|
4756dd58f9 | ||
|
|
6d4d639c65 | ||
|
|
d08b6e874f | ||
|
|
65cf2752a6 | ||
|
|
d911c24421 | ||
|
|
3afc70bfec | ||
|
|
e3637197d7 | ||
|
|
3542d7fffb | ||
|
|
7fce31e82e | ||
|
|
59a1596732 | ||
|
|
63eeb28bc4 | ||
|
|
60e0154ac6 | ||
|
|
b94e4c602e | ||
|
|
c608336c04 | ||
|
|
2e90506a5e | ||
|
|
94624e6719 | ||
|
|
84774d208c | ||
|
|
1cba176139 | ||
|
|
6c759a8844 | ||
|
|
a631681f73 | ||
|
|
e1f15277d6 | ||
|
|
7e4593cd89 | ||
|
|
d32ac5327c | ||
|
|
e72d8ecfa2 | ||
|
|
9a5e429942 | ||
|
|
20ecad0774 | ||
|
|
044220d570 | ||
|
|
ac13be9e01 | ||
|
|
66117cd456 | ||
|
|
87eb98ca20 | ||
|
|
3b67e2a8c8 | ||
|
|
99237898de | ||
|
|
d5d917e3f8 | ||
|
|
14b67a2053 | ||
|
|
6546b41e26 | ||
|
|
b31fa80b5a | ||
|
|
e42964ffaf | ||
|
|
4c2a4fd142 | ||
|
|
8aa44f6607 | ||
|
|
3efb8cf252 | ||
|
|
aca292b737 | ||
|
|
7d268604b7 | ||
|
|
c488602b74 | ||
|
|
65795b1271 | ||
|
|
5baef3f69a | ||
|
|
0ff600fde7 | ||
|
|
67b2758d3f | ||
|
|
4e67b8b4cd | ||
|
|
5a1cdf8dfa | ||
|
|
5eb3f89650 | ||
|
|
8770f0d289 | ||
|
|
905da88348 | ||
|
|
e5716ae6c0 | ||
|
|
df32d61552 | ||
|
|
2abc7f570b | ||
|
|
4bc41fbf8e | ||
|
|
f594eea8e8 | ||
|
|
239c3e5d8d | ||
|
|
350de90af0 | ||
|
|
b99c40714f | ||
|
|
9197973eb4 | ||
|
|
79edec14c8 | ||
|
|
9962cc731b | ||
|
|
a3abff8766 | ||
|
|
825eb85d1c | ||
|
|
e50766f471 | ||
|
|
738bd0427e | ||
|
|
71146c9c94 | ||
|
|
d77e7622f7 | ||
|
|
3afeed6868 | ||
|
|
57185f1917 | ||
|
|
360f47754b | ||
|
|
cde03d132b | ||
|
|
fc4cbf335a | ||
|
|
623dd69182 | ||
|
|
248f95b295 | ||
|
|
a941cb387e | ||
|
|
b245147844 | ||
|
|
53e3b9a940 | ||
|
|
ee92e15668 | ||
|
|
fa5281f5e5 | ||
|
|
15020e201b | ||
|
|
5c48a83705 | ||
|
|
3cc3548f69 | ||
|
|
f7d1d95e3a | ||
|
|
8b7b4b138e | ||
|
|
d994994ac5 | ||
|
|
309cb5f1f7 | ||
|
|
692594fe64 | ||
|
|
68295d6bcc | ||
|
|
d84af6be3a | ||
|
|
39adbf3367 | ||
|
|
251043137d | ||
|
|
2f9749ce03 | ||
|
|
fdc9d6b4ff | ||
|
|
bcab38b364 | ||
|
|
c9bf7131b5 | ||
|
|
dbbd84b222 | ||
|
|
4234e50408 | ||
|
|
67a7778ce5 | ||
|
|
b7eb94548f | ||
|
|
ab2063ab2f | ||
|
|
20de4ede89 | ||
|
|
f4714e6603 | ||
|
|
f24c270139 | ||
|
|
18cde4bc5f | ||
|
|
95989143f9 | ||
|
|
02ef83213a | ||
|
|
12c885a377 | ||
|
|
c469ef6671 | ||
|
|
b26399713d | ||
|
|
14f8150546 | ||
|
|
b4b28385e5 | ||
|
|
e83eb6d657 | ||
|
|
0a793d898a | ||
|
|
de40281e22 | ||
|
|
00718d15df | ||
|
|
38ee8352d8 | ||
|
|
def4d1aa9f | ||
|
|
d35b5f66ad | ||
|
|
40bb6ad9ab | ||
|
|
39a58f909e | ||
|
|
aa9af574b6 | ||
|
|
b541e56071 | ||
|
|
c1ec590782 | ||
|
|
f3dcd2924c | ||
|
|
61d3737816 | ||
|
|
40005f3f25 | ||
|
|
7968b2bb5f | ||
|
|
ae52ea5971 | ||
|
|
fdaf513267 | ||
|
|
715998e67a | ||
|
|
033bb5c957 | ||
|
|
f9df879a3e | ||
|
|
1a1865045d | ||
|
|
6188b4d9cb | ||
|
|
fc35c00603 | ||
|
|
7aad5ae124 | ||
|
|
6f15447c5f | ||
|
|
9017ff4344 | ||
|
|
86993ba456 | ||
|
|
9ccfc96055 | ||
|
|
53e40a4e6a | ||
|
|
72d8c567bd | ||
|
|
587c3fd2e9 | ||
|
|
52d15bc388 | ||
|
|
ec6b3a00cc | ||
|
|
716b818a41 | ||
|
|
eb6cddeb08 | ||
|
|
12c928c5a0 | ||
|
|
a94808cf65 | ||
|
|
1254ba0ee0 | ||
|
|
8351d5a9fb | ||
|
|
a42597098f | ||
|
|
666a9398d3 | ||
|
|
4019ff08d6 | ||
|
|
31d8ecc2d0 | ||
|
|
d24d2e4b93 | ||
|
|
c4b147d7c8 | ||
|
|
cdc054a10f | ||
|
|
d2e9d3d8b4 | ||
|
|
cadd1a3b44 | ||
|
|
a86c5006af | ||
|
|
146df11c1f | ||
|
|
3190e5ac4d | ||
|
|
33c1c7e646 | ||
|
|
08efcc0342 | ||
|
|
d8a0462e1b | ||
|
|
3ab4d62bdf | ||
|
|
3e0b7a0659 | ||
|
|
5561b9dc05 | ||
|
|
69beb3b05d | ||
|
|
71d7b3217a | ||
|
|
6c54a7fa2b | ||
|
|
0749bc570c | ||
|
|
f39efb939b | ||
|
|
964be94407 | ||
|
|
303bfce10f | ||
|
|
8e223c83a5 | ||
|
|
c19cebef80 | ||
|
|
fac2c80fe7 | ||
|
|
b6e6518492 | ||
|
|
d5ea6fec60 | ||
|
|
0bdda6a529 | ||
|
|
38c017fdf8 | ||
|
|
aff75e1d59 | ||
|
|
0d1c279f64 | ||
|
|
0962e0e301 | ||
|
|
5d6b86b6c2 | ||
|
|
f6315cb640 | ||
|
|
5ecd4da153 | ||
|
|
d79c936875 | ||
|
|
ac49832ffd | ||
|
|
0621c215e7 | ||
|
|
2384e3d3e8 | ||
|
|
9afd6c6fc2 | ||
|
|
4c87d6864a | ||
|
|
42ada7e3f8 | ||
|
|
1e10bc3613 | ||
|
|
f34df17d36 | ||
|
|
a3029c4c74 | ||
|
|
bac27c8609 | ||
|
|
e0cda24c09 | ||
|
|
49242a1469 | ||
|
|
266abc8dd1 | ||
|
|
2e1a49a0cf | ||
|
|
7cbda60f46 | ||
|
|
fe563fd423 | ||
|
|
ab652c6ad0 | ||
|
|
4d4b318674 | ||
|
|
7f3ebffb36 | ||
|
|
1f81f03e45 | ||
|
|
608734b652 | ||
|
|
d7d40172cf | ||
|
|
406445dbb3 | ||
|
|
8ee1240cf7 | ||
|
|
d7f5657dda | ||
|
|
40cca935dd | ||
|
|
48fb1d0bff | ||
|
|
b35c20e511 | ||
|
|
fd443cc4c2 | ||
|
|
4b3d3d4460 | ||
|
|
bac1ed5e0c | ||
|
|
286a1a608f | ||
|
|
f45f1895a8 | ||
|
|
bee9547a87 | ||
|
|
382593a8a2 | ||
|
|
1f1acaa500 | ||
|
|
743dca7335 | ||
|
|
5a8148c09f | ||
|
|
5fdb21cbf9 | ||
|
|
59ad5724d5 | ||
|
|
ab620c00fc | ||
|
|
edd57e1ca5 | ||
|
|
485b46f235 | ||
|
|
674e5e253f | ||
|
|
d4724b417c | ||
|
|
eaa261dad8 | ||
|
|
db0c5fc578 | ||
|
|
e16900ef11 | ||
|
|
56a9bc2bdd | ||
|
|
33f70de451 | ||
|
|
d36cb2fafa | ||
|
|
eea9015cd3 | ||
|
|
aac4d8308d | ||
|
|
0b8b4a7505 | ||
|
|
602a15f648 | ||
|
|
0c7620a381 | ||
|
|
4323968240 | ||
|
|
3239a1c041 | ||
|
|
7ee7146d00 | ||
|
|
f11503567e | ||
|
|
5c61c1c0f4 | ||
|
|
30b5b33d0d | ||
|
|
38875f719a | ||
|
|
bb3603acd3 | ||
|
|
ca6e981f29 | ||
|
|
5a33c42278 | ||
|
|
fceb82ea51 | ||
|
|
43f38d9d84 | ||
|
|
6bb4bc3e69 | ||
|
|
927cd5a9a6 | ||
|
|
be00050615 | ||
|
|
3308df7fff | ||
|
|
f157b76b5f | ||
|
|
70efb7a7f2 | ||
|
|
fc26e77c95 | ||
|
|
c3a0c2a465 | ||
|
|
f6fced6b82 | ||
|
|
b4f83a5755 | ||
|
|
9d5c3bd951 | ||
|
|
8bb70c7e9a | ||
|
|
3f25b62ab6 | ||
|
|
d9a3b5453a | ||
|
|
be96bef3f0 | ||
|
|
89a243f88c | ||
|
|
9070dfe55b | ||
|
|
67044f9dd3 | ||
|
|
bde276ad67 | ||
|
|
65b30189b3 | ||
|
|
78f1df21ae | ||
|
|
17cddb902c | ||
|
|
bf7142ce43 | ||
|
|
ff455c8ed9 | ||
|
|
8020204c8d | ||
|
|
a500bfb583 | ||
|
|
6365187a1c | ||
|
|
9db94c9354 | ||
|
|
c4d2c31e06 | ||
|
|
1a554ea1e3 | ||
|
|
fa5cb690ba | ||
|
|
cf873bd197 | ||
|
|
9085a27361 | ||
|
|
2a8d2c7f5e | ||
|
|
ac11681073 | ||
|
|
1ab5bc1f6b | ||
|
|
6defaebf34 | ||
|
|
ae8457c588 | ||
|
|
e31ab11364 | ||
|
|
24daf955d8 | ||
|
|
c2dfc3055c | ||
|
|
b67b97430c | ||
|
|
0dfaf043bf | ||
|
|
6b4d8fba4a | ||
|
|
e702f24937 | ||
|
|
d9d949666f | ||
|
|
755c1f75d1 | ||
|
|
8a5621396b | ||
|
|
618743ea1a | ||
|
|
69e8f9a2f3 | ||
|
|
17c36b351d | ||
|
|
893d200e2c | ||
|
|
a9b511738f | ||
|
|
2ec4d6702c | ||
|
|
202d644d53 | ||
|
|
6ebc492454 | ||
|
|
22bc25253e | ||
|
|
5959eb8eb5 | ||
|
|
0524ac764d | ||
|
|
e6e690b32f | ||
|
|
e763a2b233 | ||
|
|
29ed0dd94b | ||
|
|
fbb5826178 | ||
|
|
0054616020 | ||
|
|
416da8b98d | ||
|
|
8ce81d15ba | ||
|
|
f222390ce8 | ||
|
|
49c4aa6a75 | ||
|
|
d6f2859d3d | ||
|
|
c0300c9e0d | ||
|
|
36290336c3 | ||
|
|
20c12533f8 | ||
|
|
34600446d9 | ||
|
|
96991da621 | ||
|
|
a4a757f288 | ||
|
|
0ee357e97a | ||
|
|
c1fa41ee30 | ||
|
|
195074a4b0 | ||
|
|
790a2a8a2d | ||
|
|
16623103cd | ||
|
|
3cc9a580e2 | ||
|
|
8c8a91ba4d | ||
|
|
caa3a34a4a | ||
|
|
4ee0512827 | ||
|
|
ba8c0eb035 | ||
|
|
3cc9eb0bec | ||
|
|
bbb72875e3 | ||
|
|
f2416b3b91 | ||
|
|
23571848d5 | ||
|
|
5b76c0a2d1 | ||
|
|
9943b89b2d | ||
|
|
5f998b0ea8 | ||
|
|
2a290765e9 | ||
|
|
b0e680ee5c | ||
|
|
989f114154 | ||
|
|
6a41952552 | ||
|
|
cb37141643 | ||
|
|
ff064367d6 | ||
|
|
ec2aedbba0 | ||
|
|
161f160ba7 | ||
|
|
36ab20ae3a | ||
|
|
3a45a48a1a | ||
|
|
e3dcf4aa47 | ||
|
|
91079b66d6 | ||
|
|
099e61343d | ||
|
|
72769deacc | ||
|
|
6656bf3ab2 | ||
|
|
1a5f89a905 | ||
|
|
6c5af5c593 | ||
|
|
a6a4eac8fd | ||
|
|
a83f441b98 | ||
|
|
003a5be614 | ||
|
|
c6a6926b7f | ||
|
|
5e7ee641a6 | ||
|
|
d41e0b4759 | ||
|
|
73da9d4acc | ||
|
|
14684c8ba7 | ||
|
|
9332d00b69 | ||
|
|
53fdf2434a | ||
|
|
ef1d55f1fe | ||
|
|
3b5bfd4eaf | ||
|
|
3733583eef | ||
|
|
89c21aa943 | ||
|
|
24d5d387ff | ||
|
|
b070782dd2 | ||
|
|
9db21e6f3c | ||
|
|
40621823dc | ||
|
|
a1d781c435 | ||
|
|
72831b0cef | ||
|
|
d543cfcc3f | ||
|
|
b818ff95b6 | ||
|
|
02fb5cede8 | ||
|
|
28d66567b4 | ||
|
|
b88ea8aa2c | ||
|
|
7546978f2b | ||
|
|
5f576a8852 | ||
|
|
fb62be10cb | ||
|
|
4a28d9d455 | ||
|
|
ecaf16f9bd | ||
|
|
736f1683d1 | ||
|
|
1a6e940888 | ||
|
|
4426be8303 | ||
|
|
ef3d1cb966 | ||
|
|
6c1bf7534a | ||
|
|
27f0fb9474 | ||
|
|
9dd1462d65 | ||
|
|
3e8565bd70 | ||
|
|
fd1c73c472 | ||
|
|
5e269ed07a | ||
|
|
31a0641943 | ||
|
|
4d471bccaf | ||
|
|
2d4769137f | ||
|
|
6fddd3a815 | ||
|
|
3a12da73bf | ||
|
|
fa45a02134 | ||
|
|
88b972be4b | ||
|
|
02b78055d4 | ||
|
|
16cc898e6a | ||
|
|
08be751aa4 | ||
|
|
738b531925 | ||
|
|
155f107238 | ||
|
|
ea8f94bb51 | ||
|
|
cd8b7649a1 | ||
|
|
48c3b5fcff | ||
|
|
a0b85b491f | ||
|
|
143b65ad9f | ||
|
|
ad973919ad | ||
|
|
6b21e0bb8e | ||
|
|
b8ec0f6cab | ||
|
|
1476f12a8d | ||
|
|
8677a72b7c | ||
|
|
dc49fad81a | ||
|
|
aefe133ba0 | ||
|
|
0fc66b0f02 | ||
|
|
5ccf7369ca |
446 changed files with 7232 additions and 18907 deletions
41
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
41
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: triage
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**What version of Invoice Ninja are you running? ie v4.5.25 / v5.0.30**
|
||||
|
||||
**What environment are you running?**
|
||||
Docker
|
||||
Shared Hosting
|
||||
ZIP
|
||||
Other
|
||||
|
||||
**Have you checked log files (storage/logs/) Please provide redacted output**
|
||||
|
||||
**Have you searched existing issues?**
|
||||
|
||||
**Have you reported this to Slack/forum before posting?**
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**Steps To Reproduce**
|
||||
Please list the steps to reproduce the issue
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
|
||||
Note: Before posting don't forget to check our "Troubleshooting" category in the [docs](https://invoiceninja.github.io/docs/self-host-troubleshooting/) (https://invoiceninja.github.io/docs/self-host-troubleshooting/).
|
||||
|
||||
**(v5) Can you replicate the issue on our demo site? https://demo.invoiceninja.com**
|
||||
24
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
24
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: feature request
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**What version of Invoice Ninja are you running? ie v4.5 / v5**
|
||||
|
||||
**What environment are you running?**
|
||||
Docker
|
||||
Shared Hosting
|
||||
ZIP
|
||||
Other
|
||||
|
||||
**Have you searched existing issues/requests?**
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your request/question.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the request/question here.
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -11,6 +11,8 @@
|
|||
/resources/assets/bower
|
||||
/storage/*.key
|
||||
/storage/documents
|
||||
/storage/import
|
||||
/storage/migrations
|
||||
/bootstrap/compiled.php
|
||||
/bootstrap/environment.php
|
||||
/vendor
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
language: php
|
||||
|
||||
services:
|
||||
- mysql
|
||||
|
||||
sudo: true
|
||||
|
||||
# Prevent tests from taking more than 50 minutes
|
||||
|
|
@ -7,9 +10,7 @@ group: deprecated-2017Q4
|
|||
|
||||
php:
|
||||
- 7.2
|
||||
|
||||
services:
|
||||
- mysql
|
||||
- 7.3
|
||||
|
||||
addons:
|
||||
hosts:
|
||||
|
|
@ -29,7 +30,7 @@ env:
|
|||
before_install:
|
||||
# set GitHub token and update composer
|
||||
- if [ -n "$GH_TOKEN" ]; then composer config github-oauth.github.com ${GH_TOKEN}; fi;
|
||||
- composer self-update && composer -V
|
||||
- composer self-update 1.10.19 && composer -V
|
||||
# - export USE_ZEND_ALLOC=0
|
||||
- rvm use 1.9.3 --install --fuzzy
|
||||
|
||||
|
|
|
|||
88
LICENSE
88
LICENSE
|
|
@ -1,47 +1,47 @@
|
|||
Elastic License 2.0 (ELv2)
|
||||
Elastic License
|
||||
Copyright (c) 2018 by Hillel Coren
|
||||
Invoice Ninja * https://www.invoiceninja.com
|
||||
"CREATE. SEND. GET PAID"
|
||||
|
||||
Acceptance
|
||||
By using the software, you agree to all of the terms and conditions below.
|
||||
All Rights Reserved
|
||||
ATTRIBUTION ASSURANCE LICENSE (adapted from the original BSD license)
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the conditions below are met.
|
||||
These conditions require a modest attribution to InvoiceNinja.com (the
|
||||
"Author"), who hopes that its promotional value may help justify the
|
||||
thousands of dollars in otherwise billable time invested in writing
|
||||
this and other freely available, open-source software.
|
||||
|
||||
Copyright License
|
||||
The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject to the limitations and conditions below
|
||||
1. Redistributions of source code, in whole or part and with or without
|
||||
modification (the "Code"), must prominently display this GPG-signed
|
||||
text in verifiable form.
|
||||
2. Redistributions of the Code in binary form must be accompanied by
|
||||
this GPG-signed text in any documentation and, each time the resulting
|
||||
executable program or a program dependent thereon is launched, a
|
||||
prominent display (e.g., splash screen or banner text) of the Author's
|
||||
attribution information, which includes:
|
||||
(a) Name ("Hillel Coren"),
|
||||
(b) Professional identification ("Invoice Ninja"), and
|
||||
(c) URL ("https://www.invoiceninja.com").
|
||||
3. Neither the name nor any trademark of the Author may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
4. Users are entirely responsible, to the exclusion of the Author and
|
||||
any other persons, for compliance with (1) regulations set by owners or
|
||||
administrators of employed equipment, (2) licensing terms of any other
|
||||
software, and (3) local regulations regarding use, including those
|
||||
regarding import, export, and use of encryption software.
|
||||
|
||||
Limitations
|
||||
You may not provide the software to third parties as a hosted or managed service, where the service provides users with access to any substantial set of the features or functionality of the software.
|
||||
|
||||
You may not move, change, disable, or circumvent the license key functionality in the software, and you may not remove or obscure any functionality in the software that is protected by the license key.
|
||||
|
||||
You may not alter, remove, or obscure any licensing, copyright, or other notices of the licensor in the software. Any use of the licensor’s trademarks is subject to applicable law.
|
||||
|
||||
Patents
|
||||
The licensor grants you a license, under any patent claims the licensor can license, or becomes able to license, to make, have made, use, sell, offer for sale, import and have imported the software, in each case subject to the limitations and conditions in this license. This license does not cover any patent claims that you cause to be infringed by modifications or additions to the software. If you or your company make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
|
||||
|
||||
Notices
|
||||
You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms.
|
||||
|
||||
If you modify the software, you must include in any modified copies of the software prominent notices stating that you have modified the software.
|
||||
|
||||
No Other Rights
|
||||
These terms do not imply any licenses other than those expressly granted in these terms.
|
||||
|
||||
Termination
|
||||
If you use the software in violation of these terms, such use is not licensed, and your licenses will automatically terminate. If the licensor provides you with a notice of your violation, and you cease all violation of this license no later than 30 days after you receive that notice, your licenses will be reinstated retroactively. However, if you violate these terms after such reinstatement, any additional violation of these terms will cause your licenses to terminate automatically and permanently.
|
||||
|
||||
No Liability
|
||||
As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.
|
||||
|
||||
Definitions
|
||||
The licensor is the entity offering these terms, and the software is the software the licensor makes available under these terms, including any portion of it.
|
||||
|
||||
you refers to the individual or entity agreeing to these terms.
|
||||
|
||||
your company is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. control means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
|
||||
|
||||
your licenses are all the licenses granted to you for the software under these terms.
|
||||
|
||||
use means anything you do with the software requiring one of your licenses.
|
||||
|
||||
trademark means trademarks, service marks, and similar rights.
|
||||
|
||||
For more information regarding the interpretation of this license please see here: https://invoiceninja.github.io/docs/legal/license/
|
||||
THIS FREE SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
EVENT SHALL THE AUTHOR OR ANY CONTRIBUTOR BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
EFFECTS OF UNAUTHORIZED OR MALICIOUS NETWORK ACCESS;
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
|
|
|||
15
README.md
15
README.md
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
# Invoice Ninja
|
||||
|
||||
[](https://travis-ci.org/invoiceninja/invoiceninja)
|
||||
[](https://travis-ci.org/invoiceninja/invoiceninja)
|
||||
[](https://invoice-ninja.readthedocs.io/en/latest/?badge=latest)
|
||||
|
||||
## [Hosted](https://www.invoiceninja.com) | [Self-Hosted](https://www.invoiceninja.org)
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
Just make sure to add the `invoice-ninja` tag to your question.
|
||||
|
||||
#### Note: v5 is now in beta. To upgrade from v4 you need to [install v5](https://invoiceninja.github.io/docs/self-host-installation/) as a separate app and then use the migration tool in the latest version of v4 on Settings > Account Management.
|
||||
#### Note: v5 is now tagged Stable! To upgrade from v4 you need to [install v5](https://invoiceninja.github.io/docs/self-host-installation/) as a separate app and then use the migration tool in the latest version of v4 on Settings > Account Management.
|
||||
|
||||
All Pro and Enterprise features from the hosted app are included in the open-source code. We offer a $30 per year white-label license to remove the Invoice Ninja branding from client facing parts of the app.
|
||||
|
||||
|
|
@ -21,8 +21,9 @@ The self-host zip includes all third party libraries whereas downloading the cod
|
|||
|
||||
* [Features](https://www.invoiceninja.com/invoicing-features/)
|
||||
* [Videos](https://www.youtube.com/channel/UCXAHcBvhW05PDtWYIq7WDFA/videos)
|
||||
* [User Guide](https://invoice-ninja.readthedocs.io/en/latest/)
|
||||
* [User Guide](https://docs.invoiceninja.com/)
|
||||
* [Support Forum](https://www.invoiceninja.com/forums/forum/support/)
|
||||
* [StackOverflow](https://stackoverflow.com/tags/invoice-ninja/)
|
||||
|
||||
## Referral Program
|
||||
* Earn 50% of Pro & Enterprise Plans up to 4 years - [Learn more](https://www.invoiceninja.com/referral-program/)
|
||||
|
|
@ -34,10 +35,12 @@ The self-host zip includes all third party libraries whereas downloading the cod
|
|||
|
||||
## Installation Options
|
||||
* [Ansible](https://github.com/invoiceninja/ansible-installer)
|
||||
* [Self-Host Zip](https://invoice-ninja.readthedocs.io/en/latest/install.html)
|
||||
* [Self-Host Zip](https://docs.invoiceninja.com/install.html)
|
||||
* [Docker File](https://hub.docker.com/r/invoiceninja/invoiceninja/)
|
||||
* [Cloudron](https://cloudron.io/store/com.invoiceninja.cloudronapp.html)
|
||||
* [Softaculous](https://www.softaculous.com/apps/ecommerce/Invoice_Ninja)
|
||||
* [Lando](https://github.com/invoiceninja/invoiceninja/issues/2880)
|
||||
* [Yunohost](https://github.com/YunoHost-Apps/invoiceninja_ynh)
|
||||
|
||||
## Recommended Providers
|
||||
* [Stripe](https://stripe.com/)
|
||||
|
|
@ -66,7 +69,7 @@ The self-host zip includes all third party libraries whereas downloading the cod
|
|||
* [Bold Compass](https://boldcompass.com/customize-invoice-ninja/)
|
||||
|
||||
## Contributing
|
||||
All contributors are welcome!
|
||||
All contributors are welcome!
|
||||
For information on how contribute to Invoice Ninja, please see our [contributing guide](CONTRIBUTING.md).
|
||||
|
||||
## Credits
|
||||
|
|
@ -89,5 +92,5 @@ For information on how contribute to Invoice Ninja, please see our [contributing
|
|||
* [Mike Skaggs](https://github.com/titan-fail)
|
||||
|
||||
## License
|
||||
Invoice Ninja is released under the Attribution Assurance License.
|
||||
Invoice Ninja is released under the Attribution Assurance License.
|
||||
See [LICENSE](LICENSE) for details.
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ class CalculatePayouts extends Command
|
|||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->info('Running CalculatePayouts...');
|
||||
$type = strtolower($this->option('type'));
|
||||
|
||||
switch ($type) {
|
||||
|
|
@ -61,7 +60,6 @@ class CalculatePayouts extends Command
|
|||
$userMap = [];
|
||||
|
||||
foreach ($servers as $server) {
|
||||
$this->info('Processing users: ' . $server->name);
|
||||
config(['database.default' => $server->name]);
|
||||
|
||||
$users = User::where('referral_code', '!=', '')
|
||||
|
|
@ -72,7 +70,6 @@ class CalculatePayouts extends Command
|
|||
}
|
||||
|
||||
foreach ($servers as $server) {
|
||||
$this->info('Processing companies: ' . $server->name);
|
||||
config(['database.default' => $server->name]);
|
||||
|
||||
$companies = Company::where('referral_code', '!=', '')
|
||||
|
|
@ -80,19 +77,27 @@ class CalculatePayouts extends Command
|
|||
->whereNotNull('payment_id')
|
||||
->get();
|
||||
|
||||
$this->info('User,Client,Date,Amount,Reference');
|
||||
|
||||
foreach ($companies as $company) {
|
||||
if (!isset($userMap[$company->referral_code])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$user = $userMap[$company->referral_code];
|
||||
$payment = $company->payment;
|
||||
|
||||
if ($payment) {
|
||||
$client = $payment->client;
|
||||
|
||||
$this->info("User: $user");
|
||||
$this->info("Client: " . $client->getDisplayName());
|
||||
|
||||
foreach ($client->payments as $payment) {
|
||||
$amount = $payment->getCompletedAmount();
|
||||
$this->info("Date: $payment->payment_date, Amount: $amount, Reference: $payment->transaction_reference");
|
||||
$this->info('"' . $user . '",' .
|
||||
'"' . $client->getDisplayName() . '",' .
|
||||
$payment->payment_date . ',' .
|
||||
$amount . ',' .
|
||||
$payment->transaction_reference
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,6 +75,8 @@ class CheckData extends Command
|
|||
config(['database.default' => $database]);
|
||||
}
|
||||
|
||||
$this->checkContacts();
|
||||
|
||||
if (! $this->option('client_id')) {
|
||||
$this->checkBlankInvoiceHistory();
|
||||
$this->checkPaidToDate();
|
||||
|
|
@ -82,10 +84,8 @@ class CheckData extends Command
|
|||
}
|
||||
|
||||
//$this->checkInvoices();
|
||||
$this->checkTranslations();
|
||||
$this->checkInvoiceBalances();
|
||||
$this->checkClientBalances();
|
||||
$this->checkContacts();
|
||||
$this->checkUserAccounts();
|
||||
//$this->checkLogoFiles();
|
||||
|
||||
|
|
@ -97,6 +97,7 @@ class CheckData extends Command
|
|||
$this->checkFailedJobs();
|
||||
}
|
||||
|
||||
$this->checkTranslations();
|
||||
$this->logMessage('Done: ' . strtoupper($this->isValid ? RESULT_SUCCESS : RESULT_FAILURE));
|
||||
$errorEmail = env('ERROR_EMAIL');
|
||||
|
||||
|
|
@ -130,6 +131,7 @@ class CheckData extends Command
|
|||
$this->logMessage($language->locale . ' is invalid: ' . $text);
|
||||
}
|
||||
|
||||
/*
|
||||
preg_match('/(.script)/', strtolower($text), $matches);
|
||||
if (count($matches)) {
|
||||
foreach ($matches as $match) {
|
||||
|
|
@ -141,6 +143,7 @@ class CheckData extends Command
|
|||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,16 +2,11 @@
|
|||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use App\Models\TicketCategory;
|
||||
use App\Models\TicketComment;
|
||||
use App\Models\TicketTemplate;
|
||||
use App\Ninja\Repositories\AccountRepository;
|
||||
use App\Ninja\Repositories\ClientRepository;
|
||||
use App\Ninja\Repositories\ExpenseRepository;
|
||||
use App\Ninja\Repositories\InvoiceRepository;
|
||||
use App\Ninja\Repositories\PaymentRepository;
|
||||
use App\Ninja\Repositories\TicketRepository;
|
||||
use App\Ninja\Repositories\VendorRepository;
|
||||
use App\Ninja\Repositories\TaskRepository;
|
||||
use App\Ninja\Repositories\ProjectRepository;
|
||||
|
|
@ -20,7 +15,6 @@ use App\Models\TaxRate;
|
|||
use App\Models\Project;
|
||||
use App\Models\ExpenseCategory;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Faker\Factory;
|
||||
use Illuminate\Console\Command;
|
||||
use Utils;
|
||||
|
|
@ -54,12 +48,8 @@ class CreateTestData extends Command
|
|||
* @param ExpenseRepository $expenseRepo
|
||||
* @param TaskRepository $taskRepo
|
||||
* @param AccountRepository $accountRepo
|
||||
* @param TicketRepository $ticketRepo
|
||||
* @param ProjectRepository $projectRepo
|
||||
*/
|
||||
|
||||
public function __construct(
|
||||
TicketRepository $ticketRepo,
|
||||
ClientRepository $clientRepo,
|
||||
InvoiceRepository $invoiceRepo,
|
||||
PaymentRepository $paymentRepo,
|
||||
|
|
@ -81,7 +71,6 @@ class CreateTestData extends Command
|
|||
$this->taskRepo = $taskRepo;
|
||||
$this->projectRepo = $projectRepo;
|
||||
$this->accountRepo = $accountRepo;
|
||||
$this->ticketRepo = $ticketRepo;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -114,8 +103,6 @@ class CreateTestData extends Command
|
|||
Auth::loginUsingId(1);
|
||||
}
|
||||
|
||||
//$this->createTicketStubs();
|
||||
//$this->createTicketTemplates();
|
||||
$this->createClients();
|
||||
$this->createVendors();
|
||||
$this->createOtherObjects();
|
||||
|
|
@ -146,85 +133,7 @@ class CreateTestData extends Command
|
|||
|
||||
$this->createInvoices($client);
|
||||
$this->createInvoices($client, true);
|
||||
$this->createTasks($client);
|
||||
$this->createTickets($client);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private function createTicketTemplates()
|
||||
{
|
||||
$ticketTemplate = TicketTemplate::createNew();
|
||||
$ticketTemplate->name = 'Default response';
|
||||
$ticketTemplate->description = $this->faker->realText(50);
|
||||
$ticketTemplate->save();
|
||||
|
||||
$ticketTemplate = TicketTemplate::createNew();
|
||||
$ticketTemplate->name = 'Updated ticket';
|
||||
$ticketTemplate->description = $this->faker->realText(50);
|
||||
$ticketTemplate->save();
|
||||
|
||||
|
||||
$ticketTemplate = TicketTemplate::createNew();
|
||||
$ticketTemplate->name = 'Ticket closed';
|
||||
$ticketTemplate->description = $this->faker->realText(50);
|
||||
$ticketTemplate->save();
|
||||
|
||||
|
||||
$ticketTemplate = TicketTemplate::createNew();
|
||||
$ticketTemplate->name = 'Generic response';
|
||||
$ticketTemplate->description = $this->faker->realText(50);
|
||||
$ticketTemplate->save();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $client
|
||||
*/
|
||||
private function createTickets($client)
|
||||
{
|
||||
$this->info('creating tickets');
|
||||
|
||||
for ($i = 0; $i < $this->count; $i++)
|
||||
{
|
||||
$maxTicketNumber = Ticket::getNextTicketNumber(Auth::user()->account->id);
|
||||
|
||||
$this->info('next ticket number = '.$maxTicketNumber);
|
||||
|
||||
$data = [
|
||||
'priority_id'=> TICKET_PRIORITY_LOW,
|
||||
'category_id'=> 1,
|
||||
'client_id' => $client->id,
|
||||
'is_deleted'=> 0,
|
||||
'is_internal'=> (bool)random_int(0, 1),
|
||||
'status_id'=> random_int(1,3),
|
||||
'category_id'=> 1,
|
||||
'subject'=> $this->faker->realText(10),
|
||||
'description'=> $this->faker->realText(50),
|
||||
'tags'=> json_encode($this->faker->words($nb = 5, $asText = false)),
|
||||
'private_notes'=> $this->faker->realText(50),
|
||||
'ccs'=> json_encode([]),
|
||||
'contact_key'=> $client->getPrimaryContact()->contact_key,
|
||||
'due_date'=> Carbon::now(),
|
||||
'ticket_number' => $maxTicketNumber ? $maxTicketNumber : 1,
|
||||
'action' => TICKET_SAVE_ONLY,
|
||||
];
|
||||
|
||||
$ticket = $this->ticketRepo->save($data);
|
||||
|
||||
$ticketComment = TicketComment::createNew($ticket);
|
||||
$ticketComment->description = $this->faker->realText(70);
|
||||
$ticketComment->contact_key = $client->getPrimaryContact()->contact_key;
|
||||
$ticket->comments()->save($ticketComment);
|
||||
|
||||
$ticketComment = TicketComment::createNew($ticket);
|
||||
$ticketComment->description = $this->faker->realText(40);
|
||||
$ticketComment->user_id = 1;
|
||||
$ticket->comments()->save($ticketComment);
|
||||
|
||||
$this->info("Ticket: - {$ticket->ticket_number} - {$client->account->account_ticket_settings->ticket_number_start} - {$maxTicketNumber}");
|
||||
// $this->createTasks($client);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
115
app/Console/Commands/ExportMigrations.php
Normal file
115
app/Console/Commands/ExportMigrations.php
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Libraries\Utils;
|
||||
use App\Models\User;
|
||||
use App\Traits\GenerateMigrationResources;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class ExportMigrations extends Command
|
||||
{
|
||||
use GenerateMigrationResources;
|
||||
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'migrations:export {--user=} {--random=}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Export account migrations to folder.';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->info('Note: Migrations will be stored inside of (storage/migrations) folder.');
|
||||
|
||||
if($this->option('user')) {
|
||||
$record = User::findOrFail($this->option('user'));
|
||||
return $this->export($record);
|
||||
}
|
||||
|
||||
if($this->option('random')){
|
||||
|
||||
User::all()->random(200)->each(function ($user){
|
||||
$this->export($user);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$users = User::all();
|
||||
|
||||
foreach($users as $user) {
|
||||
Auth::login($user);
|
||||
$this->export($user);
|
||||
}
|
||||
}
|
||||
|
||||
private function export($user)
|
||||
{
|
||||
$this->account = $user->account;
|
||||
|
||||
$date = date('Y-m-d');
|
||||
$accountKey = $this->account->account_key;
|
||||
|
||||
$output = fopen('php://output', 'w') or Utils::fatalError();
|
||||
|
||||
$fileName = "{$accountKey}-{$date}-invoiceninja";
|
||||
|
||||
$data['data'] = [
|
||||
'account' => $this->getAccount(),
|
||||
'company' => $this->getCompany(),
|
||||
'users' => $this->getUsers(),
|
||||
'tax_rates' => $this->getTaxRates(),
|
||||
'payment_terms' => $this->getPaymentTerms(),
|
||||
'clients' => $this->getClients(),
|
||||
'company_gateways' => $this->getCompanyGateways(),
|
||||
'client_gateway_tokens' => $this->getClientGatewayTokens(),
|
||||
'vendors' => $this->getVendors(),
|
||||
'projects' => $this->getProjects(),
|
||||
'products' => $this->getProducts(),
|
||||
'credits' => $this->getCreditsNotes(),
|
||||
'invoices' => $this->getInvoices(),
|
||||
'recurring_invoices' => $this->getRecurringInvoices(),
|
||||
'quotes' => $this->getQuotes(),
|
||||
'payments' => array_merge($this->getPayments(), $this->getCredits()),
|
||||
'documents' => $this->getDocuments(),
|
||||
'expense_categories' => $this->getExpenseCategories(),
|
||||
'task_statuses' => $this->getTaskStatuses(),
|
||||
'expenses' => $this->getExpenses(),
|
||||
'tasks' => $this->getTasks(),
|
||||
'documents' => $this->getDocuments(),
|
||||
];
|
||||
|
||||
$file = storage_path("migrations/{$fileName}.zip");
|
||||
|
||||
$zip = new \ZipArchive();
|
||||
$zip->open($file, \ZipArchive::CREATE | \ZipArchive::OVERWRITE);
|
||||
$zip->addFromString('migration.json', json_encode($data, JSON_PRETTY_PRINT));
|
||||
$zip->close();
|
||||
|
||||
$this->info('User with id #' . $user->id . ' exported.');
|
||||
}
|
||||
}
|
||||
|
|
@ -362,7 +362,6 @@ class InitLookup extends Command
|
|||
DB::statement('truncate lookup_invitations');
|
||||
DB::statement('truncate lookup_proposal_invitations');
|
||||
DB::statement('truncate lookup_account_tokens');
|
||||
DB::statement('truncate lookup_ticket_invitations');
|
||||
DB::statement('SET FOREIGN_KEY_CHECKS = 1');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,113 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Nwidart\Modules\Commands\GeneratorCommand;
|
||||
use Nwidart\Modules\Support\Stub;
|
||||
use Nwidart\Modules\Traits\ModuleCommandTrait;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
class MakeModuleSettings extends GeneratorCommand
|
||||
{
|
||||
use ModuleCommandTrait;
|
||||
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
// protected $signature = 'ninja:make-module-settings {name : Module name} {--route : Add routes }';
|
||||
|
||||
protected $name = 'ninja:make-module-settings';
|
||||
protected $argumentName = 'module';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Create module settings';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function getTemplateContents()
|
||||
{
|
||||
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
|
||||
$path = str_replace('/', '\\', config('modules.paths.generator.module-settings-view'));
|
||||
|
||||
return (new Stub('/module-settings-view.stub', [
|
||||
'MODULE_NAME' => $module->getName(),
|
||||
'LOWER_NAME' => $module->getLowerName(),
|
||||
'SHOW_ROUTES' => $this->option('route') ? true : false
|
||||
]))->render();
|
||||
}
|
||||
|
||||
public function handle() {
|
||||
$this->info('Creating settings view template for ' . $this->getModuleName());
|
||||
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
|
||||
|
||||
parent::handle();
|
||||
|
||||
// add default routes if option specified
|
||||
$route = $this->option('route');
|
||||
|
||||
if ($route) {
|
||||
file_put_contents(
|
||||
$this->getModuleRoutesFilePath(),
|
||||
(new Stub('/module-settings-routes.stub', [
|
||||
'MODULE_NAME' => $module->getName(),
|
||||
'LOWER_NAME' => $module->getLowerName(),
|
||||
]))->render(),
|
||||
FILE_APPEND
|
||||
);
|
||||
$this->info('Added routes to module routes.php.');
|
||||
}
|
||||
}
|
||||
|
||||
protected function getModuleRoutesFilePath() {
|
||||
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
|
||||
$seederPath = $this->laravel['modules']->config('paths.generator.module-settings-routes');
|
||||
|
||||
return $path . $seederPath . '/routes.php';
|
||||
}
|
||||
|
||||
public function getDestinationFilePath()
|
||||
{
|
||||
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
|
||||
$seederPath = $this->laravel['modules']->config('paths.generator.module-settings-view');
|
||||
|
||||
return $path . $seederPath . '/' . $this->getFileName();
|
||||
}
|
||||
|
||||
protected function getArguments()
|
||||
{
|
||||
return [
|
||||
['module', InputArgument::REQUIRED, 'The name of the module.']
|
||||
];
|
||||
}
|
||||
|
||||
protected function getOptions()
|
||||
{
|
||||
return [
|
||||
['route', null, InputOption::VALUE_NONE, 'Add default routes.', null]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getFileName()
|
||||
{
|
||||
return 'settings.blade.php';
|
||||
}
|
||||
}
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Jobs\SendOverdueTicketNotification;
|
||||
use App\Models\Ticket;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
/**
|
||||
* Class SendOverdueTickets.
|
||||
*/
|
||||
class SendOverdueTickets extends Command
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'ninja:send-overdue-tickets';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Send overdue tickets';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
parent::__construct();
|
||||
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$this->info(date('r') . ' Running SendOverdueTickets...');
|
||||
|
||||
if ($database = $this->option('database'))
|
||||
config(['database.default' => $database]);
|
||||
|
||||
$this->sendReminders();
|
||||
|
||||
$this->info(date('r') . ' Done');
|
||||
}
|
||||
|
||||
private function sendReminders()
|
||||
{
|
||||
|
||||
$tickets = Ticket::with('account', 'account.account_ticket_settings')
|
||||
->where('due_date', '<', Carbon::now())
|
||||
->whereIn('status_id', [1,2])
|
||||
->where('overdue_notification_sent', '=', 0)
|
||||
->whereHas('account.account_ticket_settings', function ($query) {
|
||||
$query->where('alert_ticket_overdue_agent_id', '>', '0');
|
||||
})->get();
|
||||
|
||||
|
||||
foreach($tickets as $ticket)
|
||||
dispatch(new SendOverdueTicketNotification($ticket));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getArguments()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getOptions()
|
||||
{
|
||||
return [
|
||||
['database', null, InputOption::VALUE_OPTIONAL, 'Database', null],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -125,7 +125,7 @@ class SendReminders extends Command
|
|||
private function chargeLateFees()
|
||||
{
|
||||
$accounts = $this->accountRepo->findWithFees();
|
||||
$this->info(date('r ') . $accounts->count() . ' accounts found with fees');
|
||||
$this->info(date('r ') . $accounts->count() . ' accounts found with fees enabled');
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
if (! $account->hasFeature(FEATURE_EMAIL_TEMPLATES_REMINDERS)) {
|
||||
|
|
@ -141,14 +141,8 @@ class SendReminders extends Command
|
|||
$account->loadLocalizationSettings($invoice->client); // support trans to add fee line item
|
||||
$number = preg_replace('/[^0-9]/', '', $reminder);
|
||||
|
||||
if ($invoice->isQuote()) {
|
||||
$amount = $account->account_email_settings->{"late_fee_quote{$number}_amount"};
|
||||
$percent = $account->account_email_settings->{"late_fee_quote{$number}_percent"};
|
||||
} else {
|
||||
$amount = $account->account_email_settings->{"late_fee{$number}_amount"};
|
||||
$percent = $account->account_email_settings->{"late_fee{$number}_percent"};
|
||||
}
|
||||
|
||||
$amount = $account->account_email_settings->{"late_fee{$number}_amount"};
|
||||
$percent = $account->account_email_settings->{"late_fee{$number}_percent"};
|
||||
$this->invoiceRepo->setLateFee($invoice, $amount, $percent);
|
||||
}
|
||||
}
|
||||
|
|
@ -158,7 +152,7 @@ class SendReminders extends Command
|
|||
private function sendReminderEmails()
|
||||
{
|
||||
$accounts = $this->accountRepo->findWithReminders();
|
||||
$this->info(date('r ') . count($accounts) . ' accounts found with reminders');
|
||||
$this->info(date('r ') . count($accounts) . ' accounts found with reminders enabled');
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
if (! $account->hasFeature(FEATURE_EMAIL_TEMPLATES_REMINDERS)) {
|
||||
|
|
@ -190,18 +184,6 @@ class SendReminders extends Command
|
|||
$this->info(date('r') . ' Send email: ' . $invoice->id);
|
||||
dispatch(new SendInvoiceEmail($invoice, $invoice->user_id, 'reminder4'));
|
||||
}
|
||||
|
||||
// endless quote reminders
|
||||
$invoices = $this->invoiceRepo->findNeedingEndlessReminding($account, true);
|
||||
$this->info(date('r ') . $account->name . ': ' . $invoices->count() . ' endless quotes found');
|
||||
|
||||
foreach ($invoices as $invoice) {
|
||||
if ($invoice->last_sent_date == date('Y-m-d')) {
|
||||
continue;
|
||||
}
|
||||
$this->info(date('r') . ' Send email: ' . $invoice->id);
|
||||
dispatch(new SendInvoiceEmail($invoice, $invoice->user_id, 'quote_reminder4'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -229,7 +211,7 @@ class SendReminders extends Command
|
|||
// send email as user
|
||||
auth()->onceUsingId($user->id);
|
||||
|
||||
$report = dispatch_now(new RunReport($scheduledReport->user, $reportType, $config, $account, true));
|
||||
$report = dispatch_now(new RunReport($scheduledReport->user, $reportType, $config, true));
|
||||
$file = dispatch_now(new ExportReportResults($scheduledReport->user, $config['export_format'], $reportType, $report->exportParams));
|
||||
|
||||
if ($file) {
|
||||
|
|
@ -258,24 +240,13 @@ class SendReminders extends Command
|
|||
if (config('ninja.exchange_rates_enabled')) {
|
||||
$this->info(date('r') . ' Loading latest exchange rates...');
|
||||
|
||||
$url = config('ninja.exchange_rates_url');
|
||||
$apiKey = config('ninja.exchange_rates_api_key');
|
||||
$url = str_replace('{apiKey}', $apiKey, $url);
|
||||
|
||||
$response = CurlUtils::get($url);
|
||||
$response = CurlUtils::get(config('ninja.exchange_rates_url'));
|
||||
$data = json_decode($response);
|
||||
|
||||
if ($data && property_exists($data, 'rates') && property_exists($data, 'base')) {
|
||||
$base = config('ninja.exchange_rates_base');
|
||||
|
||||
// should calculate to different base
|
||||
$recalculate = ($data->base != $base);
|
||||
if ($data && property_exists($data, 'rates')) {
|
||||
Currency::whereCode(config('ninja.exchange_rates_base'))->update(['exchange_rate' => 1]);
|
||||
|
||||
foreach ($data->rates as $code => $rate) {
|
||||
if($recalculate) {
|
||||
$rate = 1 / $data->rates->{$base} * $rate;
|
||||
}
|
||||
|
||||
Currency::whereCode($code)->update(['exchange_rate' => $rate]);
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
|
||||
Route::group(['middleware' => ['web', 'lookup:user', 'auth:user'], 'namespace' => 'Modules\$MODULE_NAME$\Http\Controllers'], function()
|
||||
{
|
||||
Route::get('settings/$LOWER_NAME$', function() {
|
||||
return view('$LOWER_NAME$::settings');
|
||||
});
|
||||
Route::post('settings/$LOWER_NAME$', '$MODULE_NAME$Controller@saveSettings');
|
||||
});
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
@extends('header')
|
||||
|
||||
@section('content')
|
||||
@parent
|
||||
|
||||
@include('accounts.nav', ['selected' => '$MODULE_NAME$'])
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{!! Former::open('settings/$MODULE_NAME$') !!}
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">$MODULE_NAME$ Settings</h3>
|
||||
</div>
|
||||
<div class="panel-group">
|
||||
<div class="form-group"></div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label col-lg-4 col-sm-4"></label>
|
||||
<div class="col-lg-8 col-sm-8">
|
||||
{!! Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk')) !!}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!! Former::close() !!}
|
||||
</div>
|
||||
</div>
|
||||
@stop
|
||||
|
|
@ -21,6 +21,7 @@ class Kernel extends ConsoleKernel
|
|||
'App\Console\Commands\PruneData',
|
||||
'App\Console\Commands\CreateTestData',
|
||||
'App\Console\Commands\CreateLuisData',
|
||||
'App\Console\Commands\MobileLocalization',
|
||||
'App\Console\Commands\SendRenewalInvoices',
|
||||
'App\Console\Commands\ChargeRenewalInvoices',
|
||||
'App\Console\Commands\SendReminders',
|
||||
|
|
@ -30,9 +31,7 @@ class Kernel extends ConsoleKernel
|
|||
'App\Console\Commands\InitLookup',
|
||||
'App\Console\Commands\CalculatePayouts',
|
||||
'App\Console\Commands\UpdateKey',
|
||||
'App\Console\Commands\MobileLocalization',
|
||||
'App\Console\Commands\SendOverdueTickets',
|
||||
'App\Console\Commands\MakeModuleSettings',
|
||||
'App\Console\Commands\ExportMigrations',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -47,13 +46,13 @@ class Kernel extends ConsoleKernel
|
|||
$logFile = storage_path() . '/logs/cron.log';
|
||||
|
||||
$schedule
|
||||
->command('ninja:send-invoices')
|
||||
->command('ninja:send-invoices --force')
|
||||
->sendOutputTo($logFile)
|
||||
->withoutOverlapping()
|
||||
->hourly();
|
||||
|
||||
$schedule
|
||||
->command('ninja:send-reminders')
|
||||
->command('ninja:send-reminders --force')
|
||||
->sendOutputTo($logFile)
|
||||
->daily();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ if (! defined('APP_NAME')) {
|
|||
define('ENTITY_INVOICE_ITEM', 'invoice_item');
|
||||
define('ENTITY_INVITATION', 'invitation');
|
||||
define('ENTITY_RECURRING_INVOICE', 'recurring_invoice');
|
||||
define('ENTITY_RECURRING_QUOTE', 'recurring_quote');
|
||||
define('ENTITY_PAYMENT', 'payment');
|
||||
define('ENTITY_CREDIT', 'credit');
|
||||
define('ENTITY_QUOTE', 'quote');
|
||||
|
|
@ -48,13 +47,6 @@ if (! defined('APP_NAME')) {
|
|||
define('ENTITY_PROPOSAL_SNIPPET', 'proposal_snippet');
|
||||
define('ENTITY_PROPOSAL_CATEGORY', 'proposal_category');
|
||||
define('ENTITY_PROPOSAL_INVITATION', 'proposal_invitation');
|
||||
define('ENTITY_TICKET', 'ticket');
|
||||
define('ENTITY_TICKET_COMMENT', 'ticket_comment');
|
||||
define('ENTITY_TICKET_STATUS', 'ticket_status');
|
||||
define('ENTITY_TICKET_CATEGORY', 'ticket_category');
|
||||
define('ENTITY_TICKET_RELATION', 'ticket_relation');
|
||||
define('ENTITY_TICKET_TEMPLATE', 'ticket_template');
|
||||
define('ENTITY_TICKET_INVITATION', 'ticket_invitation');
|
||||
|
||||
$permissionEntities = [
|
||||
ENTITY_CLIENT,
|
||||
|
|
@ -67,11 +59,10 @@ if (! defined('APP_NAME')) {
|
|||
ENTITY_PROJECT,
|
||||
ENTITY_PROPOSAL,
|
||||
ENTITY_QUOTE,
|
||||
'dashboard',
|
||||
'reports',
|
||||
ENTITY_TICKET,
|
||||
ENTITY_TASK,
|
||||
ENTITY_VENDOR,
|
||||
ENTITY_RECURRING_INVOICE,
|
||||
];
|
||||
|
||||
define('PERMISSION_ENTITIES', json_encode($permissionEntities));
|
||||
|
|
@ -104,7 +95,6 @@ if (! defined('APP_NAME')) {
|
|||
define('ACCOUNT_MAP', 'import_map');
|
||||
define('ACCOUNT_EXPORT', 'export');
|
||||
define('ACCOUNT_TAX_RATES', 'tax_rates');
|
||||
define('ACCOUNT_TICKETS', 'tickets');
|
||||
define('ACCOUNT_PRODUCTS', 'products');
|
||||
define('ACCOUNT_ADVANCED_SETTINGS', 'advanced_settings');
|
||||
define('ACCOUNT_INVOICE_SETTINGS', 'invoice_settings');
|
||||
|
|
@ -172,16 +162,6 @@ if (! defined('APP_NAME')) {
|
|||
define('ACTIVITY_TYPE_DELETE_TASK', 45);
|
||||
define('ACTIVITY_TYPE_RESTORE_TASK', 46);
|
||||
define('ACTIVITY_TYPE_UPDATE_EXPENSE', 47);
|
||||
define('ACTIVITY_TYPE_USER_UPDATE_TICKET', 48);
|
||||
define('ACTIVITY_TYPE_USER_CLOSE_TICKET', 49);
|
||||
define('ACTIVITY_TYPE_USER_MERGE_TICKET', 50);
|
||||
define('ACTIVITY_TYPE_USER_SPLIT_TICKET', 51);
|
||||
define('ACTIVITY_TYPE_CONTACT_OPEN_TICKET', 52);
|
||||
define('ACTIVITY_TYPE_CONTACT_REOPEN_TICKET', 53);
|
||||
define('ACTIVITY_TYPE_USER_REOPEN_TICKET', 54);
|
||||
define('ACTIVITY_TYPE_CONTACT_REPLY_TICKET', 55);
|
||||
define('ACTIVITY_TYPE_USER_VIEW_TICKET', 56);
|
||||
|
||||
|
||||
define('DEFAULT_INVOICE_NUMBER', '0001');
|
||||
define('RECENTLY_VIEWED_LIMIT', 20);
|
||||
|
|
@ -381,7 +361,7 @@ if (! defined('APP_NAME')) {
|
|||
define('NINJA_APP_URL', env('NINJA_APP_URL', 'https://app.invoiceninja.com'));
|
||||
define('NINJA_DOCS_URL', env('NINJA_DOCS_URL', 'https://invoice-ninja.readthedocs.io/en/latest'));
|
||||
define('NINJA_DATE', '2000-01-01');
|
||||
define('NINJA_VERSION', '4.5.37' . env('NINJA_VERSION_SUFFIX'));
|
||||
define('NINJA_VERSION', '4.5.40' . env('NINJA_VERSION_SUFFIX'));
|
||||
define('NINJA_TERMS_VERSION', '1.0.1');
|
||||
|
||||
define('SOCIAL_LINK_FACEBOOK', env('SOCIAL_LINK_FACEBOOK', 'https://www.facebook.com/invoiceninja'));
|
||||
|
|
@ -513,10 +493,6 @@ if (! defined('APP_NAME')) {
|
|||
define('TEMPLATE_REMINDER2', 'reminder2');
|
||||
define('TEMPLATE_REMINDER3', 'reminder3');
|
||||
define('TEMPLATE_REMINDER4', 'reminder4');
|
||||
define('TEMPLATE_QUOTE_REMINDER1', 'quote_reminder1');
|
||||
define('TEMPLATE_QUOTE_REMINDER2', 'quote_reminder2');
|
||||
define('TEMPLATE_QUOTE_REMINDER3', 'quote_reminder3');
|
||||
define('TEMPLATE_QUOTE_REMINDER4', 'quote_reminder4');
|
||||
|
||||
define('CUSTOM_MESSAGE_DASHBOARD', 'dashboard');
|
||||
define('CUSTOM_MESSAGE_UNPAID_INVOICE', 'unpaid_invoice');
|
||||
|
|
@ -598,7 +574,6 @@ if (! defined('APP_NAME')) {
|
|||
define('FEATURE_MORE_INVOICE_DESIGNS', 'more_invoice_designs');
|
||||
define('FEATURE_QUOTES', 'quotes');
|
||||
define('FEATURE_TASKS', 'tasks');
|
||||
define('FEATURE_TICKETS', 'tickets');
|
||||
define('FEATURE_EXPENSES', 'expenses');
|
||||
define('FEATURE_REPORTS', 'reports');
|
||||
define('FEATURE_BUY_NOW_BUTTONS', 'buy_now_buttons');
|
||||
|
|
@ -688,45 +663,6 @@ if (! defined('APP_NAME')) {
|
|||
// Fix for mPDF: https://github.com/kartik-v/yii2-mpdf/issues/9
|
||||
define('_MPDF_TTFONTDATAPATH', storage_path('framework/cache/'));
|
||||
|
||||
/** STD constatns */
|
||||
if(!defined('STDIN')) define('STDIN', fopen('php://stdin', 'r'));
|
||||
if(!defined('STDOUT')) define('STDOUT', fopen('php://stdout', 'w'));
|
||||
if(!defined('STDERR')) define('STDERR', fopen('php://stderr', 'w'));
|
||||
|
||||
/** Tickets constants */
|
||||
define('TICKET_PRIORITY_LOW', 10);
|
||||
define('TICKET_PRIORITY_MEDIUM', 20);
|
||||
define('TICKET_PRIORITY_HIGH', 30);
|
||||
|
||||
define('TICKET_STATUS_NEW', 1);
|
||||
define('TICKET_STATUS_OPEN',2);
|
||||
define('TICKET_STATUS_CLOSED',3);
|
||||
define('TICKET_STATUS_MERGED',4);
|
||||
|
||||
define('TICKET_CLIENT_NEW', 'ticket_client_new');
|
||||
define('TICKET_CLIENT_UPDATE', 'ticket_client_update');
|
||||
define('TICKET_INBOUND_NEW', 'ticket_inbound_new');
|
||||
define('TICKET_INBOUND_NEW_INTERNAL', 'ticket_inbound_new_internal');
|
||||
define('TICKET_INBOUND_REPLY', 'ticket_inbound_reply');
|
||||
define('TICKET_INBOUND_CONTACT_REPLY', 'ticket_inbound_contact_reply');
|
||||
define('TICKET_INBOUND_AGENT_REPLY', 'ticket_inbound_agent_reply');
|
||||
define('TICKET_INBOUND_ADMIN_REPLY', 'ticket_inbound_admin_reply');
|
||||
define('TICKET_AGENT_UPDATE', 'ticket_agent_update');
|
||||
define('TICKET_AGENT_NEW', 'ticket_agent_new');
|
||||
define('TICKET_MERGE', 'ticket_merge');
|
||||
define('TICKET_ASSIGNED', 'ticket_assigned');
|
||||
define('TICKET_OVERDUE', 'ticket_overdue');
|
||||
define('TICKET_AGENT_CLOSED', 'ticket_agent_closed');
|
||||
define('TICKET_SAVE_ONLY', 'ticket_save_only');
|
||||
|
||||
/* Default ticket statuses - Category - support*/
|
||||
$supportTicketStatuses = [
|
||||
trans('texts.new'),
|
||||
trans('texts.open'),
|
||||
trans('texts.closed'),
|
||||
trans('texts.merged')
|
||||
];
|
||||
|
||||
function uctrans($text, $data = [])
|
||||
{
|
||||
$locale = Session::get(SESSION_LOCALE);
|
||||
|
|
|
|||
|
|
@ -30,26 +30,4 @@ class Domain
|
|||
{
|
||||
return 'maildelivery@' . static::getDomainFromId($id);
|
||||
}
|
||||
|
||||
public static function getPostmarkTokenFromId($id)
|
||||
{
|
||||
switch($id)
|
||||
{
|
||||
case static::INVOICENINJA_COM:
|
||||
return config('services.postmark_token');
|
||||
case static::INVOICE_SERVICES:
|
||||
return config('services.postmark_token_2');
|
||||
}
|
||||
}
|
||||
|
||||
public static function getSupportDomainFromId($id)
|
||||
{
|
||||
switch($id)
|
||||
{
|
||||
case static::INVOICENINJA_COM:
|
||||
return config('ninja.tickets.ticket_support_domain');
|
||||
case static::INVOICE_SERVICES:
|
||||
return config('ninja.tickets.ticket_support_domain_2');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
/**
|
||||
* Class TicketUserViewed.
|
||||
*/
|
||||
class TicketUserViewed extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* @var Ticket
|
||||
*/
|
||||
public $ticket;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param Ticket $ticket
|
||||
*/
|
||||
public function __construct(Ticket $ticket)
|
||||
{
|
||||
$this->ticket = $ticket;
|
||||
}
|
||||
}
|
||||
|
|
@ -107,9 +107,9 @@ class AccountApiController extends BaseAPIController
|
|||
$user = Auth::user();
|
||||
$account = $user->account;
|
||||
|
||||
if ($createToken)
|
||||
if ($createToken) {
|
||||
$this->accountRepo->createTokens($user, $request->token_name);
|
||||
|
||||
}
|
||||
|
||||
$users = $this->accountRepo->findUsers($user, 'account.account_tokens');
|
||||
$transformer = new UserAccountTransformer($account, $request->serializer, $request->token_name);
|
||||
|
|
|
|||
|
|
@ -8,11 +8,9 @@ use App\Events\UserSettingsChanged;
|
|||
use App\Events\UserSignedUp;
|
||||
use App\Http\Requests\SaveClientPortalSettings;
|
||||
use App\Http\Requests\SaveEmailSettings;
|
||||
use App\Http\Requests\SaveTicketSettings;
|
||||
use App\Http\Requests\UpdateAccountRequest;
|
||||
use App\Models\Account;
|
||||
use App\Models\AccountGateway;
|
||||
use App\Models\AccountTicketSettings;
|
||||
use App\Models\Affiliate;
|
||||
use App\Models\Document;
|
||||
use App\Models\Gateway;
|
||||
|
|
@ -23,7 +21,6 @@ use App\Models\License;
|
|||
use App\Models\PaymentTerm;
|
||||
use App\Models\Product;
|
||||
use App\Models\TaxRate;
|
||||
use App\Models\TicketTemplate;
|
||||
use App\Models\User;
|
||||
use App\Models\AccountEmailSettings;
|
||||
use App\Ninja\Mailers\ContactMailer;
|
||||
|
|
@ -33,7 +30,6 @@ use App\Ninja\Repositories\ReferralRepository;
|
|||
use App\Services\AuthService;
|
||||
use App\Services\PaymentService;
|
||||
use App\Services\TemplateService;
|
||||
use Monolog\Handler\Curl\Util;
|
||||
use Nwidart\Modules\Facades\Module;
|
||||
use Auth;
|
||||
use Cache;
|
||||
|
|
@ -293,9 +289,7 @@ class AccountController extends BaseController
|
|||
} elseif ($section == ACCOUNT_INVOICE_SETTINGS) {
|
||||
return self::showInvoiceSettings();
|
||||
} elseif ($section == ACCOUNT_IMPORT_EXPORT) {
|
||||
return View::make('accounts.import_export', [
|
||||
'title' => trans('texts.import_export'),
|
||||
]);
|
||||
return View::make('accounts.import_export', ['title' => trans('texts.import_export')]);
|
||||
} elseif ($section == ACCOUNT_MANAGEMENT) {
|
||||
return self::showAccountManagement();
|
||||
} elseif ($section == ACCOUNT_INVOICE_DESIGN || $section == ACCOUNT_CUSTOMIZE_DESIGN) {
|
||||
|
|
@ -308,8 +302,6 @@ class AccountController extends BaseController
|
|||
return self::showProducts();
|
||||
} elseif ($section === ACCOUNT_TAX_RATES) {
|
||||
return self::showTaxRates();
|
||||
} elseif ($section === ACCOUNT_TICKETS) {
|
||||
return self::showTickets();
|
||||
} elseif ($section === ACCOUNT_PAYMENT_TERMS) {
|
||||
return self::showPaymentTerms();
|
||||
} elseif ($section === ACCOUNT_SYSTEM_SETTINGS) {
|
||||
|
|
@ -518,29 +510,11 @@ class AccountController extends BaseController
|
|||
$data = [
|
||||
'account' => Auth::user()->account,
|
||||
'title' => trans('texts.product_library'),
|
||||
|
||||
];
|
||||
|
||||
return View::make('accounts.products', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
private function showTickets()
|
||||
{
|
||||
|
||||
$data = [
|
||||
'account' => Auth::user()->account,
|
||||
'account_ticket_settings' => Auth::user()->account->account_ticket_settings,
|
||||
'templates' => TicketTemplate::scope()->get(),
|
||||
'title' => trans('texts.ticket_settings'),
|
||||
'section' => ACCOUNT_TICKETS,
|
||||
];
|
||||
|
||||
return View::make('accounts.tickets', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
|
|
@ -659,7 +633,6 @@ class AccountController extends BaseController
|
|||
$data['invoiceFonts'] = Cache::get('fonts');
|
||||
$data['section'] = $section;
|
||||
$data['pageSizes'] = array_combine(InvoiceDesign::$pageSizes, InvoiceDesign::$pageSizes);
|
||||
$data['showModuleSettings'] = Utils::hasModuleSettings();
|
||||
|
||||
$design = false;
|
||||
foreach ($data['invoiceDesigns'] as $item) {
|
||||
|
|
@ -721,14 +694,8 @@ class AccountController extends BaseController
|
|||
'account' => $account,
|
||||
'products' => Product::scope()->orderBy('product_key')->get(),
|
||||
'gateway_types' => $options,
|
||||
|
||||
];
|
||||
|
||||
if (Utils::isSelfHost()) {
|
||||
$js = $account->client_view_js ? $account->client_view_js : '';
|
||||
$data['client_view_js'] = $js;
|
||||
}
|
||||
|
||||
return View::make('accounts.client_portal', $data);
|
||||
}
|
||||
|
||||
|
|
@ -752,7 +719,6 @@ class AccountController extends BaseController
|
|||
];
|
||||
}
|
||||
$data['title'] = trans('texts.email_templates');
|
||||
$data['showModuleSettings'] = Utils::hasModuleSettings();
|
||||
|
||||
return View::make('accounts.templates_and_reminders', $data);
|
||||
}
|
||||
|
|
@ -820,7 +786,6 @@ class AccountController extends BaseController
|
|||
$user->save();
|
||||
|
||||
$account->live_preview = Input::get('live_preview') ? true : false;
|
||||
$account->realtime_preview = Input::get('realtime_preview') ? true : false;
|
||||
|
||||
// Automatically disable live preview when using a large font
|
||||
$fonts = Cache::get('fonts')->filter(function ($font) use ($account) {
|
||||
|
|
@ -891,7 +856,6 @@ class AccountController extends BaseController
|
|||
|
||||
$account->fill($request->all());
|
||||
$account->client_view_css = $request->client_view_css;
|
||||
$account->client_view_js = $request->client_view_js;
|
||||
$account->subdomain = $request->subdomain;
|
||||
$account->iframe_url = $request->iframe_url;
|
||||
$account->is_custom_domain = $request->is_custom_domain;
|
||||
|
|
@ -941,29 +905,21 @@ class AccountController extends BaseController
|
|||
$account->account_email_settings->$bodyField = ($body == $account->getDefaultEmailTemplate($type) ? null : $body);
|
||||
}
|
||||
|
||||
foreach ([TEMPLATE_REMINDER1, TEMPLATE_REMINDER2, TEMPLATE_REMINDER3, TEMPLATE_QUOTE_REMINDER1, TEMPLATE_QUOTE_REMINDER2, TEMPLATE_QUOTE_REMINDER3] as $type) {
|
||||
foreach ([TEMPLATE_REMINDER1, TEMPLATE_REMINDER2, TEMPLATE_REMINDER3] as $type) {
|
||||
$enableField = "enable_{$type}";
|
||||
$account->account_email_settings->$enableField = Input::get($enableField) ? true : false;
|
||||
$account->account_email_settings->{"num_days_{$type}"} = Input::get("num_days_{$type}");
|
||||
$account->account_email_settings->{"field_{$type}"} = Input::get("field_{$type}");
|
||||
$account->account_email_settings->{"direction_{$type}"} = Input::get("field_{$type}") == REMINDER_FIELD_INVOICE_DATE ? REMINDER_DIRECTION_AFTER : Input::get("direction_{$type}");
|
||||
$account->$enableField = Input::get($enableField) ? true : false;
|
||||
$account->{"num_days_{$type}"} = Input::get("num_days_{$type}");
|
||||
$account->{"field_{$type}"} = Input::get("field_{$type}");
|
||||
$account->{"direction_{$type}"} = Input::get("field_{$type}") == REMINDER_FIELD_INVOICE_DATE ? REMINDER_DIRECTION_AFTER : Input::get("direction_{$type}");
|
||||
|
||||
$number = preg_replace('/[^0-9]/', '', $type);
|
||||
if (strpos($type, 'quote') !== false) {
|
||||
$account->account_email_settings->{"late_fee_quote{$number}_amount"} = Input::get("late_fee_quote{$number}_amount");
|
||||
$account->account_email_settings->{"late_fee_quote{$number}_percent"} = Input::get("late_fee_quote{$number}_percent");
|
||||
} else {
|
||||
$account->account_email_settings->{"late_fee{$number}_amount"} = Input::get("late_fee{$number}_amount");
|
||||
$account->account_email_settings->{"late_fee{$number}_percent"} = Input::get("late_fee{$number}_percent");
|
||||
}
|
||||
$account->account_email_settings->{"late_fee{$number}_amount"} = Input::get("late_fee{$number}_amount");
|
||||
$account->account_email_settings->{"late_fee{$number}_percent"} = Input::get("late_fee{$number}_percent");
|
||||
}
|
||||
|
||||
$account->account_email_settings->enable_reminder4 = Input::get('enable_reminder4') ? true : false;
|
||||
$account->enable_reminder4 = Input::get('enable_reminder4') ? true : false;
|
||||
$account->account_email_settings->frequency_id_reminder4 = Input::get('frequency_id_reminder4');
|
||||
|
||||
$account->account_email_settings->enable_quote_reminder4 = Input::get('enable_quote_reminder4') ? true : false;
|
||||
$account->account_email_settings->frequency_id_quote_reminder4 = Input::get('frequency_id_quote_reminder4');
|
||||
|
||||
$account->save();
|
||||
$account->account_email_settings->save();
|
||||
|
||||
|
|
@ -973,29 +929,6 @@ class AccountController extends BaseController
|
|||
return Redirect::to('settings/'.ACCOUNT_TEMPLATES_AND_REMINDERS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
|
||||
public function saveTickets(SaveTicketSettings $request)
|
||||
{
|
||||
$account_ticket_settings = Auth::user()->account->account_ticket_settings;
|
||||
$account_ticket_settings->fill($request->all());
|
||||
$account_ticket_settings->save();
|
||||
|
||||
Session::flash('message', trans('texts.updated_settings'));
|
||||
|
||||
return Redirect::to('settings/'.ACCOUNT_TICKETS);
|
||||
}
|
||||
|
||||
public function checkUniqueLocalPart()
|
||||
{
|
||||
if(AccountTicketSettings::checkUniqueLocalPart(Input::get('support_email_local_part'), Auth::user()->account))
|
||||
return RESULT_SUCCESS;
|
||||
else
|
||||
return RESULT_FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
|
|
@ -1066,8 +999,6 @@ class AccountController extends BaseController
|
|||
$account->quote_terms = Input::get('quote_terms');
|
||||
$account->auto_convert_quote = Input::get('auto_convert_quote');
|
||||
$account->auto_archive_quote = Input::get('auto_archive_quote');
|
||||
$account->require_approve_quote = Input::get('require_approve_quote');
|
||||
$account->allow_approve_expired_quote = Input::get('allow_approve_expired_quote');
|
||||
$account->auto_archive_invoice = Input::get('auto_archive_invoice');
|
||||
$account->auto_email_invoice = Input::get('auto_email_invoice');
|
||||
$account->recurring_invoice_number_prefix = Input::get('recurring_invoice_number_prefix');
|
||||
|
|
@ -1080,7 +1011,6 @@ class AccountController extends BaseController
|
|||
$account->credit_number_pattern = trim(Input::get('credit_number_pattern'));
|
||||
$account->reset_counter_frequency_id = Input::get('reset_counter_frequency_id');
|
||||
$account->reset_counter_date = $account->reset_counter_frequency_id ? Utils::toSqlDate(Input::get('reset_counter_date')) : null;
|
||||
$account->custom_fields_options = request()->custom_fields_options;
|
||||
|
||||
if (Input::has('recurring_hour')) {
|
||||
$account->recurring_hour = Input::get('recurring_hour');
|
||||
|
|
@ -1272,7 +1202,6 @@ class AccountController extends BaseController
|
|||
*/
|
||||
public function saveUserDetails()
|
||||
{
|
||||
|
||||
/** @var \App\Models\User $user */
|
||||
$user = Auth::user();
|
||||
$email = trim(strtolower(Input::get('email')));
|
||||
|
|
@ -1302,7 +1231,6 @@ class AccountController extends BaseController
|
|||
$user->email = $email;
|
||||
$user->phone = trim(Input::get('phone'));
|
||||
$user->dark_mode = Input::get('dark_mode');
|
||||
$user->signature = Input::get('signature');
|
||||
|
||||
if (! Auth::user()->is_admin) {
|
||||
$user->notify_sent = Input::get('notify_sent');
|
||||
|
|
@ -1322,8 +1250,6 @@ class AccountController extends BaseController
|
|||
}
|
||||
}
|
||||
|
||||
$this->saveUserAvatar(Input::file('avatar'), $user);
|
||||
|
||||
$user->save();
|
||||
|
||||
event(new UserSettingsChanged());
|
||||
|
|
@ -1333,89 +1259,6 @@ class AccountController extends BaseController
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $avatar
|
||||
* @param $user
|
||||
*/
|
||||
private function saveUserAvatar($avatar, $user)
|
||||
{
|
||||
|
||||
/* Logo image file */
|
||||
if ($uploaded = $avatar) {
|
||||
$path = $avatar->getRealPath();
|
||||
$disk = $user->getAvatarDisk();
|
||||
$extension = strtolower($uploaded->getClientOriginalExtension());
|
||||
|
||||
if (empty(Document::$types[$extension]) && ! empty(Document::$extraExtensions[$extension])) {
|
||||
$documentType = Document::$extraExtensions[$extension];
|
||||
} else {
|
||||
$documentType = $extension;
|
||||
}
|
||||
|
||||
if (! in_array($documentType, ['jpeg', 'png', 'gif'])) {
|
||||
Session::flash('warning', 'Unsupported file type');
|
||||
} else {
|
||||
$documentTypeData = Document::$types[$documentType];
|
||||
|
||||
$filePath = $uploaded->path();
|
||||
$size = filesize($filePath);
|
||||
|
||||
if ($size / 1000 > MAX_DOCUMENT_SIZE) {
|
||||
Session::flash('error', trans('texts.logo_warning_too_large'));
|
||||
} else {
|
||||
if ($documentType != 'gif') {
|
||||
$user->avatar = str_random(21).'.'.$documentType;
|
||||
|
||||
try {
|
||||
$imageSize = getimagesize($filePath);
|
||||
$user->avatar_width = $imageSize[0];
|
||||
$user->avatar_height = $imageSize[1];
|
||||
$user->avatar_size = $size;
|
||||
|
||||
// make sure image isn't interlaced
|
||||
if (extension_loaded('fileinfo')) {
|
||||
$image = Image::make($path);
|
||||
$image->interlace(false);
|
||||
$imageStr = (string) $image->encode($documentType);
|
||||
$disk->put($user->avatar, $imageStr);
|
||||
$user->avatar_size = strlen($imageStr);
|
||||
} else {
|
||||
if (Utils::isInterlaced($filePath)) {
|
||||
$user->clearAvatar();
|
||||
Session::flash('error', trans('texts.logo_warning_invalid'));
|
||||
} else {
|
||||
$stream = fopen($filePath, 'r');
|
||||
$disk->getDriver()->putStream($user->avatar, $stream, ['mimetype' => $documentTypeData['mime']]);
|
||||
fclose($stream);
|
||||
}
|
||||
}
|
||||
} catch (Exception $exception) {
|
||||
$user->clearAvatar();
|
||||
Session::flash('error', trans('texts.logo_warning_invalid'));
|
||||
}
|
||||
} else {
|
||||
if (extension_loaded('fileinfo')) {
|
||||
$user->avatar = str_random(32).'.png';
|
||||
$image = Image::make($path);
|
||||
$image = Image::canvas($image->width(), $image->height(), '#FFFFFF')->insert($image);
|
||||
$imageStr = (string) $image->encode('png');
|
||||
$disk->put($user->avatar, $imageStr);
|
||||
|
||||
$user->avatar_size = strlen($imageStr);
|
||||
$user->avatar_width = $image->width();
|
||||
$user->avatar_height = $image->height();
|
||||
} else {
|
||||
Session::flash('error', trans('texts.logo_warning_fileinfo'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$user->save();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
|
|
@ -1484,28 +1327,6 @@ class AccountController extends BaseController
|
|||
return Redirect::to('settings/'.ACCOUNT_COMPANY_DETAILS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function removeAvatar()
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
if (! Utils::isNinjaProd() && $user->hasAvatar()) {
|
||||
$user->getAvatarDisk()->delete($user->avatar);
|
||||
}
|
||||
|
||||
$user->avatar = null;
|
||||
$user->avatar_size = null;
|
||||
$user->avatar_width = null;
|
||||
$user->avatar_height = null;
|
||||
$user->save();
|
||||
|
||||
Session::flash('message', trans('texts.removed_logo'));
|
||||
|
||||
return Redirect::to('settings/'.ACCOUNT_USER_DETAILS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -106,9 +106,6 @@ class ClientController extends BaseController
|
|||
if ($user->can('create', ENTITY_RECURRING_INVOICE)) {
|
||||
$actionLinks[] = ['label' => trans('texts.new_recurring_invoice'), 'url' => URL::to('/recurring_invoices/create/'.$client->public_id)];
|
||||
}
|
||||
if ($user->can('create', ENTITY_RECURRING_QUOTE)) {
|
||||
$actionLinks[] = ['label' => trans('texts.new_recurring_quote'), 'url' => URL::to('/recurring_quotes/create/'.$client->public_id)];
|
||||
}
|
||||
|
||||
if (! empty($actionLinks)) {
|
||||
$actionLinks[] = \DropdownButton::DIVIDER;
|
||||
|
|
@ -136,7 +133,6 @@ class ClientController extends BaseController
|
|||
'credit' => $client->getTotalCredit(),
|
||||
'title' => trans('texts.view_client'),
|
||||
'hasRecurringInvoices' => $account->isModuleEnabled(ENTITY_RECURRING_INVOICE) && Invoice::scope()->recurring()->withArchived()->whereClientId($client->id)->count() > 0,
|
||||
'hasRecurringQuotes' => $account->isModuleEnabled(ENTITY_RECURRING_INVOICE) && Invoice::scope()->recurringQuote()->withArchived()->whereClientId($client->id)->count() > 0,
|
||||
'hasQuotes' => $account->isModuleEnabled(ENTITY_QUOTE) && Invoice::scope()->quotes()->withArchived()->whereClientId($client->id)->count() > 0,
|
||||
'hasTasks' => $account->isModuleEnabled(ENTITY_TASK) && Task::scope()->withArchived()->whereClientId($client->id)->count() > 0,
|
||||
'hasExpenses' => $account->isModuleEnabled(ENTITY_EXPENSE) && Expense::scope()->withArchived()->whereClientId($client->id)->count() > 0,
|
||||
|
|
|
|||
|
|
@ -146,14 +146,13 @@ class ClientPortalController extends BaseController
|
|||
}
|
||||
}
|
||||
|
||||
$showApprove = ($invoice->isQuote() && $account->require_approve_quote) ? true: false;
|
||||
$showApprove = $invoice->quote_invoice_id ? false : true;
|
||||
if ($invoice->invoice_status_id >= INVOICE_STATUS_APPROVED) {
|
||||
$showApprove = false;
|
||||
}
|
||||
|
||||
$data += [
|
||||
'account' => $account,
|
||||
'approveRequired' => $account->require_approve_quote,
|
||||
'showApprove' => $showApprove,
|
||||
'showBreadcrumbs' => false,
|
||||
'invoice' => $invoice->hidePrivateFields(),
|
||||
|
|
@ -324,7 +323,7 @@ class ClientPortalController extends BaseController
|
|||
->make();
|
||||
}
|
||||
|
||||
public function recurringInvoiceIndex($quotes = false)
|
||||
public function recurringInvoiceIndex()
|
||||
{
|
||||
if (! $contact = $this->getContact()) {
|
||||
return $this->returnError();
|
||||
|
|
@ -344,19 +343,12 @@ class ClientPortalController extends BaseController
|
|||
$columns[] = 'auto_bill';
|
||||
}
|
||||
|
||||
$title = trans('texts.recurring_invoices');
|
||||
$entityType = ENTITY_RECURRING_INVOICE;
|
||||
if ($quotes) {
|
||||
$title = trans('texts.recurring_quotes');
|
||||
$entityType = ENTITY_RECURRING_QUOTE;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'color' => $color,
|
||||
'account' => $account,
|
||||
'client' => $client,
|
||||
'title' => $title,
|
||||
'entityType' => $entityType,
|
||||
'title' => trans('texts.recurring_invoices'),
|
||||
'entityType' => ENTITY_RECURRING_INVOICE,
|
||||
'columns' => Utils::trans($columns),
|
||||
'sortColumn' => 1,
|
||||
];
|
||||
|
|
@ -364,11 +356,6 @@ class ClientPortalController extends BaseController
|
|||
return response()->view('public_list', $data);
|
||||
}
|
||||
|
||||
public function recurringQuoteIndex()
|
||||
{
|
||||
return self::recurringInvoiceIndex(true);
|
||||
}
|
||||
|
||||
public function invoiceIndex()
|
||||
{
|
||||
if (! $contact = $this->getContact()) {
|
||||
|
|
@ -414,15 +401,6 @@ class ClientPortalController extends BaseController
|
|||
return $this->invoiceRepo->getClientRecurringDatatable($contact->id);
|
||||
}
|
||||
|
||||
public function recurringQuoteDatatable()
|
||||
{
|
||||
if (! $contact = $this->getContact()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->invoiceRepo->getClientRecurringDatatable($contact->id, ENTITY_RECURRING_QUOTE);
|
||||
}
|
||||
|
||||
public function paymentIndex()
|
||||
{
|
||||
if (! $contact = $this->getContact()) {
|
||||
|
|
@ -524,7 +502,6 @@ class ClientPortalController extends BaseController
|
|||
$data = [
|
||||
'color' => $color,
|
||||
'account' => $account,
|
||||
'client' => $contact->client,
|
||||
'title' => trans('texts.quotes'),
|
||||
'entityType' => ENTITY_QUOTE,
|
||||
'columns' => Utils::trans(['quote_number', 'quote_date', 'quote_total', 'due_date', 'status']),
|
||||
|
|
@ -652,7 +629,7 @@ class ClientPortalController extends BaseController
|
|||
return $this->documentRepo->getClientDatatable($contact->id, ENTITY_DOCUMENT, Input::get('sSearch'));
|
||||
}
|
||||
|
||||
public function returnError($error = false)
|
||||
private function returnError($error = false)
|
||||
{
|
||||
if (request()->phantomjs) {
|
||||
abort(404);
|
||||
|
|
@ -665,7 +642,7 @@ class ClientPortalController extends BaseController
|
|||
]);
|
||||
}
|
||||
|
||||
public function getContact()
|
||||
private function getContact()
|
||||
{
|
||||
$contactKey = session('contact_key');
|
||||
|
||||
|
|
@ -1072,6 +1049,4 @@ class ClientPortalController extends BaseController
|
|||
return view('clients.statement', $data);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,202 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\UpdateClientPortalTicketRequest;
|
||||
use App\Libraries\Utils;
|
||||
use App\Models\Ticket;
|
||||
use App\Ninja\Repositories\TicketRepository;
|
||||
use App\Services\TicketService;
|
||||
use Illuminate\Support\Facades\Redirect;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
|
||||
|
||||
class ClientPortalTicketController extends ClientPortalController
|
||||
{
|
||||
|
||||
/**
|
||||
* @var TicketRepository
|
||||
*/
|
||||
private $ticketRepo;
|
||||
|
||||
/**
|
||||
* @var TicketService
|
||||
*/
|
||||
private $ticketService;
|
||||
|
||||
/**
|
||||
* ClientPortalTicketController constructor.
|
||||
* @param TicketRepository $ticketRepo
|
||||
* @param TicketService $ticketService
|
||||
*/
|
||||
public function __construct(TicketRepository $ticketRepo, TicketService $ticketService)
|
||||
{
|
||||
$this->ticketRepo = $ticketRepo;
|
||||
$this->ticketService = $ticketService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$contact = $this->getContact();
|
||||
|
||||
if ((!$contact || (!$contact->account->enable_client_portal)))
|
||||
return $this->returnError();
|
||||
|
||||
|
||||
$account = $contact->account;
|
||||
|
||||
$data = [
|
||||
'color' => $account->primary_color ? $account->primary_color : '#0b4d78',
|
||||
'account' => $account,
|
||||
'title' => trans('texts.tickets'),
|
||||
'entityType' => ENTITY_TICKET,
|
||||
'columns' => Utils::trans(['ticket_number', 'subject', 'created_at', 'status']),
|
||||
'sortColumn' => 0,
|
||||
];
|
||||
|
||||
return response()->view('public_list', $data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function ticketDatatable()
|
||||
{
|
||||
if (! $contact = $this->getContact())
|
||||
return false;
|
||||
|
||||
return $this->ticketService->getClientDatatable($contact->client->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $invitationKey
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function viewTicket($invitationKey)
|
||||
{
|
||||
if (! $invitation = $this->ticketRepo->findInvitationByKey($invitationKey))
|
||||
return $this->returnError(trans('texts.ticket_not_found'));
|
||||
|
||||
$account = $invitation->account;
|
||||
$ticket = $invitation->ticket;
|
||||
|
||||
$data = [
|
||||
'ticket' => $ticket,
|
||||
'account' => $account,
|
||||
'ticketInvitation' => $invitation,
|
||||
];
|
||||
|
||||
return view('invited.ticket', $data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $ticketid
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function view($ticketId)
|
||||
{
|
||||
if (! $contact = $this->getContact())
|
||||
$this->returnError();
|
||||
|
||||
$account = $contact->account;
|
||||
|
||||
$ticket = Ticket::scope($ticketId, $account->id)
|
||||
->with('comments', 'documents')
|
||||
->first();
|
||||
|
||||
$data['method'] = 'PUT';
|
||||
$data['entityType'] = ENTITY_TICKET;
|
||||
|
||||
$data = array_merge($data, self::getViewModel($contact, $ticket));
|
||||
|
||||
return view('tickets.portal.ticket_view', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function update(UpdateClientPortalTicketRequest $request)
|
||||
{
|
||||
$contact = $this->getContact();
|
||||
|
||||
$data = $request->input();
|
||||
|
||||
$data['document_ids'] = $request->document_ids;
|
||||
$data['contact_key'] = $contact->contact_key;
|
||||
$data['method'] = 'PUT';
|
||||
$data['entityType'] = ENTITY_TICKET;
|
||||
$data['action'] = TICKET_INBOUND_CONTACT_REPLY;
|
||||
|
||||
$ticket = $this->ticketService->save($data, $request->entity());
|
||||
$ticket->load('documents');
|
||||
|
||||
if(!$ticket)
|
||||
$this->returnError();
|
||||
|
||||
$data = array_merge($data, self::getViewModel($contact, $ticket));
|
||||
|
||||
Session::flash('message', trans('texts.updated_ticket'));
|
||||
|
||||
return view('tickets.portal.ticket_view', $data);
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
|
||||
if (! $contact = $this->getContact())
|
||||
$this->returnError();
|
||||
|
||||
$data['method'] = 'POST';
|
||||
$data['entityType'] = ENTITY_TICKET;
|
||||
|
||||
$data = array_merge($data, self::getViewModel($contact));
|
||||
|
||||
return view('tickets.portal.ticket_view', $data);
|
||||
|
||||
}
|
||||
|
||||
public function store(UpdateClientPortalTicketRequest $request)
|
||||
{
|
||||
|
||||
if (! $contact = $this->getContact())
|
||||
$this->returnError();
|
||||
|
||||
$data = $request->input();
|
||||
|
||||
$data['document_ids'] = $request->document_ids;
|
||||
$data['contact_key'] = $contact->contact_key;
|
||||
$data['action'] = TICKET_CLIENT_NEW;
|
||||
$data['is_internal'] = 0;
|
||||
|
||||
$ticket = $this->ticketService->save($data, $request->entity());
|
||||
|
||||
Session::flash('message', trans('texts.updated_ticket'));
|
||||
|
||||
return Redirect::to('/client/tickets/'.$ticket->public_id);
|
||||
}
|
||||
|
||||
|
||||
private static function getViewModel($contact, $ticket = false)
|
||||
{
|
||||
|
||||
return [
|
||||
'color' => $contact->account->primary_color ? $contact->account->primary_color : '#0b4d78',
|
||||
'ticket' => $ticket,
|
||||
'contact' => $contact,
|
||||
'account' => $contact->account,
|
||||
'title' => $ticket ? trans('texts.ticket')." ".$ticket->ticket_number : trans('texts.new_ticket'),
|
||||
'comments' => $ticket ? $ticket->comments() :null,
|
||||
'url' => $ticket ? 'client/tickets/' . $ticket->public_id : 'client/tickets/create',
|
||||
//'timezone' => $ticket ? $ticket->account->timezone->name : DEFAULT_TIMEZONE,
|
||||
'datetimeFormat' => $contact->account->getMomentDateTimeFormat(),
|
||||
'account_ticket_settings' => $contact->account->account_ticket_settings
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -3,11 +3,9 @@
|
|||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Currency;
|
||||
use App\Models\Expense;
|
||||
use App\Ninja\Repositories\DashboardRepository;
|
||||
use Auth;
|
||||
use App\Libraries\MoneyUtils;
|
||||
use Utils;
|
||||
use View;
|
||||
|
||||
|
|
@ -36,7 +34,7 @@ class DashboardController extends BaseController
|
|||
$metrics = $dashboardRepo->totals($accountId, $userId, $viewAll);
|
||||
$paidToDate = $dashboardRepo->paidToDate($account, $userId, $viewAll);
|
||||
$averageInvoice = $dashboardRepo->averages($account, $userId, $viewAll);
|
||||
$balances = $dashboardRepo->balances($account, $userId, $viewAll);
|
||||
$balances = $dashboardRepo->balances($accountId, $userId, $viewAll);
|
||||
$activities = $dashboardRepo->activities($accountId, $userId, $viewAll);
|
||||
$pastDue = $dashboardRepo->pastDue($accountId, $userId, $viewAll);
|
||||
$upcoming = $dashboardRepo->upcoming($accountId, $userId, $viewAll);
|
||||
|
|
@ -44,60 +42,6 @@ class DashboardController extends BaseController
|
|||
$expenses = $dashboardRepo->expenses($account, $userId, $viewAll);
|
||||
$tasks = $dashboardRepo->tasks($accountId, $userId, $viewAll);
|
||||
|
||||
// calculate paid to date totals
|
||||
$paidToDateTotal = 0;
|
||||
foreach($paidToDate as $item) {
|
||||
$paidToDateTotal += ($item->value * $item->exchange_rate);
|
||||
}
|
||||
|
||||
// calculate average invoice totals
|
||||
$invoiceTotal = 0;
|
||||
$invoiceTotalCount = 0;
|
||||
foreach ($averageInvoice as $item) {
|
||||
$invoiceTotalCount += $item->invoice_count;
|
||||
|
||||
if (! $item->exchange_rate) {
|
||||
$invoiceTotal += $item->invoice_avg * $item->invoice_count;
|
||||
continue;
|
||||
}
|
||||
|
||||
$invoiceTotal += ($item->invoice_avg * $item->invoice_count / $item->exchange_rate);
|
||||
}
|
||||
$averageInvoiceTotal = $invoiceTotalCount ? ($invoiceTotal / $invoiceTotalCount) : 0;
|
||||
|
||||
// calculate balances totals
|
||||
$balancesTotals = 0;
|
||||
$currencies = [];
|
||||
foreach ($balances as $item) {
|
||||
if ($item->currency_id == $account->getCurrencyId()) {
|
||||
$balancesTotals += $item->value;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! isset($currencies[$item->currency_id])) {
|
||||
$currencies[$item->currency_id] = Currency::where('id', $item->currency_id)->firstOrFail();
|
||||
}
|
||||
|
||||
try {
|
||||
$balancesTotals += MoneyUtils::convert($item->value, $currencies[$item->currency_id]->code, $account->currency->code);
|
||||
} catch (\Exception $e) {
|
||||
Utils::logError($e);
|
||||
$balancesTotals += $item->value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// calculate expenses totals
|
||||
$expensesTotals = 0;
|
||||
foreach ($expenses as $item) {
|
||||
if ($item->currency_id == $account->getCurrencyId()) {
|
||||
$expensesTotals += $item->value;
|
||||
continue;
|
||||
}
|
||||
|
||||
$expensesTotals += ($item->value * $item->exchange_rate);
|
||||
}
|
||||
|
||||
$showBlueVinePromo = false;
|
||||
if ($user->is_admin && env('BLUEVINE_PARTNER_UNIQUE_ID')) {
|
||||
$showBlueVinePromo = ! $account->company->bluevine_status
|
||||
|
|
@ -123,14 +67,10 @@ class DashboardController extends BaseController
|
|||
'account' => $user->account,
|
||||
'user' => $user,
|
||||
'paidToDate' => $paidToDate,
|
||||
'paidToDateTotal' => $paidToDateTotal,
|
||||
'balances' => $balances,
|
||||
'balancesTotals' => $balancesTotals,
|
||||
'averageInvoice' => $averageInvoice,
|
||||
'averageInvoiceTotal' => $averageInvoiceTotal,
|
||||
'invoicesSent' => $metrics ? $metrics->invoices_sent : 0,
|
||||
'activeClients' => $metrics ? $metrics->active_clients : 0,
|
||||
'invoiceExchangeRateMissing' => $account->getInvoiceExchangeRateCustomFieldIndex() ? false : true,
|
||||
'activities' => $activities,
|
||||
'pastDue' => $pastDue,
|
||||
'upcoming' => $upcoming,
|
||||
|
|
@ -140,7 +80,6 @@ class DashboardController extends BaseController
|
|||
'showBreadcrumbs' => false,
|
||||
'currencies' => $this->getCurrencyCodes(),
|
||||
'expenses' => $expenses,
|
||||
'expensesTotals' => $expensesTotals,
|
||||
'tasks' => $tasks,
|
||||
'showBlueVinePromo' => $showBlueVinePromo,
|
||||
'showWhiteLabelExpired' => $showWhiteLabelExpired,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ namespace App\Http\Controllers;
|
|||
use App\Http\Requests\CreateDocumentRequest;
|
||||
use App\Http\Requests\DocumentRequest;
|
||||
use App\Http\Requests\UpdateDocumentRequest;
|
||||
use App\Models\Contact;
|
||||
use App\Models\Document;
|
||||
use App\Ninja\Repositories\DocumentRepository;
|
||||
use Redirect;
|
||||
|
|
@ -57,7 +56,6 @@ class DocumentController extends BaseController
|
|||
|
||||
public function getPreview(DocumentRequest $request)
|
||||
{
|
||||
|
||||
$document = $request->entity();
|
||||
|
||||
if (empty($document->preview)) {
|
||||
|
|
@ -120,7 +118,6 @@ class DocumentController extends BaseController
|
|||
'code' => 200,
|
||||
];
|
||||
}
|
||||
|
||||
return Response::json($response, 200);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ class InvoiceApiController extends BaseAPIController
|
|||
* response="default",
|
||||
* description="an ""unexpected"" error"
|
||||
* )
|
||||
* );
|
||||
* )
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -104,7 +104,7 @@ class InvoiceApiController extends BaseAPIController
|
|||
* response="default",
|
||||
* description="an ""unexpected"" error"
|
||||
* )
|
||||
* );
|
||||
* )
|
||||
*/
|
||||
public function show(InvoiceRequest $request)
|
||||
{
|
||||
|
|
@ -130,7 +130,7 @@ class InvoiceApiController extends BaseAPIController
|
|||
* response="default",
|
||||
* description="an ""unexpected"" error"
|
||||
* )
|
||||
* );
|
||||
* )
|
||||
*/
|
||||
public function store(CreateInvoiceAPIRequest $request)
|
||||
{
|
||||
|
|
@ -455,7 +455,7 @@ class InvoiceApiController extends BaseAPIController
|
|||
* response="default",
|
||||
* description="an ""unexpected"" error"
|
||||
* )
|
||||
* );
|
||||
* )
|
||||
*/
|
||||
public function destroy(UpdateInvoiceAPIRequest $request)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -81,14 +81,6 @@ class InvoiceController extends BaseController
|
|||
return $this->recurringInvoiceService->getDatatable($accountId, $clientPublicId, ENTITY_RECURRING_INVOICE, $search);
|
||||
}
|
||||
|
||||
public function getRecurringQuotesDatatable($clientPublicId = null)
|
||||
{
|
||||
$accountId = Auth::user()->account_id;
|
||||
$search = Input::get('sSearch');
|
||||
|
||||
return $this->recurringInvoiceService->getDatatable($accountId, $clientPublicId, ENTITY_RECURRING_QUOTE, $search);
|
||||
}
|
||||
|
||||
public function edit(InvoiceRequest $request, $publicId, $clone = false)
|
||||
{
|
||||
$account = Auth::user()->account;
|
||||
|
|
@ -109,6 +101,7 @@ class InvoiceController extends BaseController
|
|||
$entityType = $clone == INVOICE_TYPE_STANDARD ? ENTITY_INVOICE : ENTITY_QUOTE;
|
||||
$invoice->id = $invoice->public_id = null;
|
||||
$invoice->is_public = false;
|
||||
$invoice->is_recurring = $invoice->is_recurring && $clone == INVOICE_TYPE_STANDARD;
|
||||
$invoice->invoice_type_id = $clone;
|
||||
$invoice->invoice_number = $account->getNextNumber($invoice);
|
||||
$invoice->due_date = null;
|
||||
|
|
@ -145,11 +138,7 @@ class InvoiceController extends BaseController
|
|||
'invoice_settings' => Auth::user()->hasFeature(FEATURE_INVOICE_SETTINGS),
|
||||
];
|
||||
|
||||
$lastSent = null;
|
||||
if($invoice->is_recurring && $invoice->last_sent_date)
|
||||
{
|
||||
$lastSent = ($invoice->subEntityType() == ENTITY_RECURRING_INVOICE) ? $invoice->recurring_invoices->last() : $invoice->recurring_quotes->last();
|
||||
}
|
||||
$lastSent = ($invoice->is_recurring && $invoice->last_sent_date) ? $invoice->recurring_invoices->last() : null;
|
||||
|
||||
if (! Auth::user()->hasPermission('view_client')) {
|
||||
$clients = $clients->where('clients.user_id', '=', Auth::user()->id);
|
||||
|
|
@ -210,10 +199,11 @@ class InvoiceController extends BaseController
|
|||
return View::make('invoices.edit', $data);
|
||||
}
|
||||
|
||||
public function create(InvoiceRequest $request, $clientPublicId = 0, $entityType = ENTITY_INVOICE)
|
||||
public function create(InvoiceRequest $request, $clientPublicId = 0, $isRecurring = false)
|
||||
{
|
||||
$account = Auth::user()->account;
|
||||
|
||||
$entityType = $isRecurring ? ENTITY_RECURRING_INVOICE : ENTITY_INVOICE;
|
||||
$clientId = null;
|
||||
|
||||
if ($request->client_id) {
|
||||
|
|
@ -244,12 +234,7 @@ class InvoiceController extends BaseController
|
|||
|
||||
public function createRecurring(InvoiceRequest $request, $clientPublicId = 0)
|
||||
{
|
||||
return self::create($request, $clientPublicId, ENTITY_RECURRING_INVOICE);
|
||||
}
|
||||
|
||||
public function createRecurringQuote(InvoiceRequest $request, $clientPublicId = 0)
|
||||
{
|
||||
return self::create($request, $clientPublicId, ENTITY_RECURRING_QUOTE);
|
||||
return self::create($request, $clientPublicId, true);
|
||||
}
|
||||
|
||||
private static function getViewModel($invoice)
|
||||
|
|
@ -529,10 +514,6 @@ class InvoiceController extends BaseController
|
|||
$entityType = ENTITY_RECURRING_INVOICE;
|
||||
}
|
||||
|
||||
if (strpos(\Request::server('HTTP_REFERER'), 'recurring_quotes')) {
|
||||
$entityType = ENTITY_RECURRING_QUOTE;
|
||||
}
|
||||
|
||||
return $this->returnBulk($entityType, $action, $ids);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,21 +2,43 @@
|
|||
|
||||
namespace App\Http\Controllers\Migration;
|
||||
|
||||
use App\Models\Credit;
|
||||
use App\Models\User;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\Product;
|
||||
use App\Models\TaxRate;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use App\Http\Requests\MigrationAuthRequest;
|
||||
use App\Http\Requests\MigrationCompaniesRequest;
|
||||
use App\Http\Requests\MigrationEndpointRequest;
|
||||
use App\Http\Requests\MigrationTypeRequest;
|
||||
use App\Libraries\Utils;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Account;
|
||||
use App\Services\Migration\AuthService;
|
||||
use App\Services\Migration\CompanyService;
|
||||
use App\Services\Migration\CompleteService;
|
||||
use App\Traits\GenerateMigrationResources;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use App\Http\Controllers\BaseController;
|
||||
|
||||
class StepsController extends BaseController
|
||||
{
|
||||
private $account;
|
||||
use GenerateMigrationResources;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('migration');
|
||||
}
|
||||
|
||||
private $access = [
|
||||
'auth' => [
|
||||
'steps' => ['MIGRATION_TYPE'],
|
||||
'redirect' => '/migration/start',
|
||||
],
|
||||
'endpoint' => [
|
||||
'steps' => ['MIGRATION_TYPE'],
|
||||
'redirect' => '/migration/start',
|
||||
],
|
||||
'companies' => [
|
||||
'steps' => ['MIGRATION_TYPE', 'MIGRATION_ACCOUNT_TOKEN'],
|
||||
'redirect' => '/migration/auth',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
|
|
@ -39,573 +61,237 @@ class StepsController extends BaseController
|
|||
return view('migration.download');
|
||||
}
|
||||
|
||||
public function handleType(MigrationTypeRequest $request)
|
||||
{
|
||||
session()->put('MIGRATION_TYPE', $request->option);
|
||||
|
||||
if ($request->option == 0) {
|
||||
|
||||
session()->put('MIGRATION_ENDPOINT', 'https://invoicing.co');
|
||||
|
||||
return redirect(
|
||||
url('/migration/auth')
|
||||
);
|
||||
|
||||
// return redirect(
|
||||
// url('/migration/endpoint')
|
||||
// );
|
||||
}
|
||||
|
||||
return redirect(
|
||||
url('/migration/endpoint')
|
||||
);
|
||||
}
|
||||
|
||||
public function endpoint()
|
||||
{
|
||||
if ($this->shouldGoBack('endpoint')) {
|
||||
return redirect(
|
||||
url($this->access['endpoint']['redirect'])
|
||||
);
|
||||
}
|
||||
|
||||
return view('migration.endpoint');
|
||||
}
|
||||
|
||||
public function handleEndpoint(MigrationEndpointRequest $request)
|
||||
{
|
||||
if ($this->shouldGoBack('endpoint')) {
|
||||
return redirect(
|
||||
url($this->access['endpoint']['redirect'])
|
||||
);
|
||||
}
|
||||
|
||||
session()->put('MIGRATION_ENDPOINT', rtrim($request->endpoint,'/'));
|
||||
|
||||
return redirect(
|
||||
url('/migration/auth')
|
||||
);
|
||||
}
|
||||
|
||||
public function auth()
|
||||
{
|
||||
if ($this->shouldGoBack('auth')) {
|
||||
return redirect(
|
||||
url($this->access['auth']['redirect'])
|
||||
);
|
||||
}
|
||||
|
||||
return view('migration.auth');
|
||||
}
|
||||
|
||||
public function handleAuth(MigrationAuthRequest $request)
|
||||
{
|
||||
if ($this->shouldGoBack('auth')) {
|
||||
return redirect(
|
||||
url($this->access['auth']['redirect'])
|
||||
);
|
||||
}
|
||||
|
||||
if (auth()->user()->email !== $request->email) {
|
||||
return back()->with('responseErrors', [trans('texts.cross_migration_message')]);
|
||||
}
|
||||
|
||||
$authentication = (new AuthService($request->email, $request->password, $request->has('api_secret') ? $request->api_secret : null))
|
||||
->endpoint(session('MIGRATION_ENDPOINT'))
|
||||
->start();
|
||||
|
||||
if ($authentication->isSuccessful()) {
|
||||
session()->put('MIGRATION_ACCOUNT_TOKEN', $authentication->getAccountToken());
|
||||
session()->put('MIGRAITON_API_SECRET', $authentication->getApiSecret());
|
||||
|
||||
return redirect(
|
||||
url('/migration/companies')
|
||||
);
|
||||
}
|
||||
|
||||
return back()->with('responseErrors', $authentication->getErrors());
|
||||
}
|
||||
|
||||
public function companies()
|
||||
{
|
||||
if ($this->shouldGoBack('companies')) {
|
||||
return redirect(
|
||||
url($this->access['companies']['redirect'])
|
||||
);
|
||||
}
|
||||
|
||||
$companyService = (new CompanyService())
|
||||
->start();
|
||||
|
||||
if ($companyService->isSuccessful()) {
|
||||
return view('migration.companies', ['companies' => $companyService->getCompanies()]);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Oops, looks like something failed. Please try again.'
|
||||
], 500);
|
||||
}
|
||||
|
||||
public function handleCompanies(MigrationCompaniesRequest $request)
|
||||
{
|
||||
if ($this->shouldGoBack('companies')) {
|
||||
return redirect(
|
||||
url($this->access['companies']['redirect'])
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
$migrationData = $this->generateMigrationData($request->all());
|
||||
|
||||
$completeService = (new CompleteService(session('MIGRATION_ACCOUNT_TOKEN')))
|
||||
->data($migrationData)
|
||||
->endpoint(session('MIGRATION_ENDPOINT'))
|
||||
->start();
|
||||
}
|
||||
finally {
|
||||
|
||||
if ($completeService->isSuccessful()) {
|
||||
return view('migration.completed');
|
||||
}
|
||||
|
||||
return view('migration.completed', ['customMessage' => $completeService->getErrors()[0]]);
|
||||
}
|
||||
}
|
||||
|
||||
public function completed()
|
||||
{
|
||||
return view('migration.completed');
|
||||
}
|
||||
|
||||
/**
|
||||
* ==================================
|
||||
* Rest of functions that are used as 'actions', not controller methods.
|
||||
* ==================================
|
||||
*/
|
||||
|
||||
public function shouldGoBack(string $step)
|
||||
{
|
||||
$redirect = true;
|
||||
|
||||
foreach ($this->access[$step]['steps'] as $step) {
|
||||
if (session()->has($step)) {
|
||||
$redirect = false;
|
||||
} else {
|
||||
$redirect = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $redirect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle data downloading for the migration.
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
* @return string
|
||||
*/
|
||||
public function handleDownload()
|
||||
public function generateMigrationData(array $data): array
|
||||
{
|
||||
$this->account = Auth::user()->account;
|
||||
set_time_limit(0);
|
||||
|
||||
$date = date('Y-m-d');
|
||||
$accountKey = $this->account->account_key;
|
||||
$migrationData = [];
|
||||
|
||||
$output = fopen('php://output', 'w') or Utils::fatalError();
|
||||
foreach ($data['companies'] as $company) {
|
||||
$account = Account::where('account_key', $company['id'])->firstOrFail();
|
||||
|
||||
$fileName = "{$accountKey}-{$date}-invoiceninja";
|
||||
$this->account = $account;
|
||||
|
||||
$data = [
|
||||
'company' => $this->getCompany(),
|
||||
'users' => $this->getUsers(),
|
||||
'tax_rates' => $this->getTaxRates(),
|
||||
'clients' => $this->getClients(),
|
||||
'products' => $this->getProducts(),
|
||||
'invoices' => $this->getInvoices(),
|
||||
'quotes' => $this->getQuotes(),
|
||||
'payments' => array_merge($this->getPayments(), $this->getCredits()),
|
||||
'credits' => $this->getCreditsNotes(),
|
||||
];
|
||||
$date = date('Y-m-d');
|
||||
$accountKey = $this->account->account_key;
|
||||
|
||||
$file = storage_path("{$fileName}.zip");
|
||||
$output = fopen('php://output', 'w') or Utils::fatalError();
|
||||
|
||||
$zip = new \ZipArchive();
|
||||
$zip->open($file, \ZipArchive::CREATE | \ZipArchive::OVERWRITE);
|
||||
$zip->addFromString('migration.json', json_encode($data));
|
||||
$zip->close();
|
||||
$fileName = "{$accountKey}-{$date}-invoiceninja";
|
||||
|
||||
header('Content-Type: application/zip');
|
||||
header('Content-Length: ' . filesize($file));
|
||||
header("Content-Disposition: attachment; filename={$fileName}.zip");
|
||||
|
||||
readfile($file);
|
||||
unlink($file);
|
||||
|
||||
return response()->json($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Export company and map to the v2 fields.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getCompany()
|
||||
{
|
||||
return [
|
||||
'account_id' => $this->account->id,
|
||||
'industry_id' => $this->account->industry_id,
|
||||
'ip' => $this->account->ip,
|
||||
'company_key' => $this->account->account_key,
|
||||
'logo' => $this->account->logo,
|
||||
'convert_products' => $this->account->convert_products,
|
||||
'fill_products' => $this->account->fill_products,
|
||||
'update_products' => $this->account->update_products,
|
||||
'show_product_details' => $this->account->show_product_notes,
|
||||
'custom_surcharge_taxes1' => $this->account->custom_invoice_taxes1,
|
||||
'custom_surcharge_taxes2' => $this->account->custom_invoice_taxes2,
|
||||
'enable_invoice_quantity' => !$this->account->hide_quantity,
|
||||
'subdomain' => $this->account->subdomain,
|
||||
'size_id' => $this->account->size_id,
|
||||
'enable_modules' => $this->account->enabled_modules,
|
||||
'custom_fields' => $this->account->custom_fields,
|
||||
//'uses_inclusive_taxes' => $this->account->inclusive_taxes,
|
||||
'created_at' => $this->account->created_at ? $this->account->created_at->toDateString() : null,
|
||||
'updated_at' => $this->account->updated_at ? $this->account->updated_at->toDateString() : null,
|
||||
'settings' => $this->getCompanySettings(),
|
||||
];
|
||||
}
|
||||
|
||||
public function getCompanySettings()
|
||||
{
|
||||
// In v1: custom_invoice_taxes1 & custom_invoice_taxes2, v2: 'invoice_taxes'. What do to with this?
|
||||
// V1: invoice_number_prefix, v2: invoice_number_pattern.. same with quote_number, client_number,
|
||||
|
||||
return [
|
||||
'timezone_id' => $this->account->timezone_id,
|
||||
'date_format_id' => $this->account->date_format_id,
|
||||
'currency_id' => $this->account->currency_id,
|
||||
'name' => $this->account->name,
|
||||
'address1' => $this->account->address1,
|
||||
'address2' => $this->account->address2,
|
||||
'city' => $this->account->city,
|
||||
'state' => $this->account->state,
|
||||
'postal_code' => $this->account->postal_code,
|
||||
'country_id' => $this->account->country_id,
|
||||
'invoice_terms' => $this->account->invoice_terms,
|
||||
'enabled_item_tax_rates' => $this->account->invoice_item_taxes,
|
||||
'invoice_design_id' => $this->account->invoice_design_id,
|
||||
'phone' => $this->account->work_phone,
|
||||
'email' => $this->account->work_email,
|
||||
'language_id' => $this->account->language_id,
|
||||
'custom_value1' => $this->account->custom_value1,
|
||||
'custom_value2' => $this->account->custom_value2,
|
||||
'hide_paid_to_date' => $this->account->hide_paid_to_date,
|
||||
'vat_number' => $this->account->vat_number,
|
||||
'shared_invoice_quote_counter' => $this->account->share_counter, // @verify,
|
||||
'id_number' => $this->account->id_number,
|
||||
'invoice_footer' => $this->account->invoice_footer,
|
||||
'pdf_email_attachment' => $this->account->pdf_email_attachment,
|
||||
'font_size' => $this->account->font_size,
|
||||
'invoice_labels' => $this->account->invoice_labels,
|
||||
'military_time' => $this->account->military_time,
|
||||
'invoice_number_pattern' => $this->account->invoice_number_pattern,
|
||||
'quote_number_pattern' => $this->account->quote_number_pattern,
|
||||
'quote_terms' => $this->account->quote_terms,
|
||||
'website' => $this->account->website,
|
||||
'auto_convert_quote' => $this->account->auto_convert_quote,
|
||||
'all_pages_footer' => $this->account->all_pages_footer,
|
||||
'all_pages_header' => $this->account->all_pages_header,
|
||||
'show_currency_code' => $this->account->show_currency_code,
|
||||
'enable_client_portal_password' => $this->account->enable_portal_password,
|
||||
'send_portal_password' => $this->account->send_portal_password,
|
||||
'recurring_number_prefix' => $this->account->recurring_invoice_number_prefix, // @verify
|
||||
'enable_client_portal' => $this->account->enable_client_portal,
|
||||
'invoice_fields' => $this->account->invoice_fields,
|
||||
'company_logo' => $this->account->logo,
|
||||
'embed_documents' => $this->account->invoice_embed_documents,
|
||||
'document_email_attachment' => $this->account->document_email_attachment,
|
||||
'enable_client_portal_dashboard' => $this->account->enable_client_portal_dashboard,
|
||||
'page_size' => $this->account->page_size,
|
||||
'show_accept_invoice_terms' => $this->account->show_accept_invoice_terms,
|
||||
'show_accept_quote_terms' => $this->account->show_accept_quote_terms,
|
||||
'require_invoice_signature' => $this->account->require_invoice_signature,
|
||||
'require_quote_signature' => $this->account->require_quote_signature,
|
||||
'client_number_counter' => $this->account->client_number_counter,
|
||||
'client_number_pattern' => $this->account->client_number_pattern,
|
||||
'payment_terms' => $this->account->payment_terms,
|
||||
'reset_counter_frequency_id' => $this->account->reset_counter_frequency_id,
|
||||
'payment_type_id' => $this->account->payment_type_id,
|
||||
'reset_counter_date' => $this->account->reset_counter_date,
|
||||
'tax_name1' => $this->account->tax_name1,
|
||||
'tax_rate1' => $this->account->tax_rate1,
|
||||
'tax_name2' => $this->account->tax_name2,
|
||||
'tax_rate2' => $this->account->tax_rate2,
|
||||
'quote_design_id' => $this->account->quote_design_id,
|
||||
'credit_number_counter' => $this->account->credit_number_counter,
|
||||
'credit_number_pattern' => $this->account->credit_number_pattern,
|
||||
'default_task_rate' => $this->account->task_rate,
|
||||
'inclusive_taxes' => $this->account->inclusive_taxes,
|
||||
'signature_on_pdf' => $this->account->signature_on_pdf,
|
||||
'ubl_email_attachment' => $this->account->ubl_email_attachment,
|
||||
'auto_archive_invoice' => $this->account->auto_archive_invoice,
|
||||
'auto_archive_quote' => $this->account->auto_archive_quote,
|
||||
'auto_email_invoice' => $this->account->auto_email_invoice,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getTaxRates()
|
||||
{
|
||||
$rates = TaxRate::where('account_id', $this->account->id)
|
||||
->withTrashed()
|
||||
->get();
|
||||
|
||||
$transformed = [];
|
||||
|
||||
foreach ($rates as $rate) {
|
||||
$transformed[] = [
|
||||
'name' => $rate->name,
|
||||
'rate' => $rate->rate,
|
||||
'company_id' => $rate->account_id,
|
||||
'user_id' => $rate->user_id,
|
||||
'created_at' => $rate->created_at ? $rate->created_at->toDateString() : null,
|
||||
'updated_at' => $rate->updated_at ? $rate->updated_at->toDateString() : null,
|
||||
'deleted_at' => $rate->deleted_at ? $rate->deleted_at->toDateString() : null,
|
||||
$localMigrationData['data'] = [
|
||||
'account' => $this->getAccount(),
|
||||
'company' => $this->getCompany(),
|
||||
'users' => $this->getUsers(),
|
||||
'tax_rates' => $this->getTaxRates(),
|
||||
'payment_terms' => $this->getPaymentTerms(),
|
||||
'clients' => $this->getClients(),
|
||||
'company_gateways' => $this->getCompanyGateways(),
|
||||
'client_gateway_tokens' => $this->getClientGatewayTokens(),
|
||||
'vendors' => $this->getVendors(),
|
||||
'projects' => $this->getProjects(),
|
||||
'products' => $this->getProducts(),
|
||||
'credits' => $this->getCreditsNotes(),
|
||||
'invoices' => $this->getInvoices(),
|
||||
'recurring_invoices' => $this->getRecurringInvoices(),
|
||||
'quotes' => $this->getQuotes(),
|
||||
'payments' => array_merge($this->getPayments(), $this->getCredits()),
|
||||
'documents' => $this->getDocuments(),
|
||||
'expense_categories' => $this->getExpenseCategories(),
|
||||
'task_statuses' => $this->getTaskStatuses(),
|
||||
'expenses' => $this->getExpenses(),
|
||||
'tasks' => $this->getTasks(),
|
||||
'documents' => $this->getDocuments(),
|
||||
'ninja_tokens' => $this->getNinjaToken(),
|
||||
];
|
||||
|
||||
$localMigrationData['force'] = array_key_exists('force', $company);
|
||||
|
||||
Storage::makeDirectory('migrations');
|
||||
$file = Storage::path("migrations/{$fileName}.zip");
|
||||
|
||||
//$file = storage_path("migrations/{$fileName}.zip");
|
||||
|
||||
ksort($localMigrationData);
|
||||
|
||||
$zip = new \ZipArchive();
|
||||
$zip->open($file, \ZipArchive::CREATE | \ZipArchive::OVERWRITE);
|
||||
$zip->addFromString('migration.json', json_encode($localMigrationData, JSON_PRETTY_PRINT));
|
||||
$zip->close();
|
||||
|
||||
$localMigrationData['file'] = $file;
|
||||
|
||||
$migrationData[] = $localMigrationData;
|
||||
}
|
||||
|
||||
return $transformed;
|
||||
}
|
||||
return $migrationData;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getClients()
|
||||
{
|
||||
$clients = [];
|
||||
|
||||
foreach ($this->account->clients()->withTrashed()->get() as $client) {
|
||||
$clients[] = [
|
||||
'id' => $client->id,
|
||||
'company_id' => $client->account_id,
|
||||
'user_id' => $client->user_id,
|
||||
'name' => $client->name,
|
||||
'balance' => $client->balance,
|
||||
'paid_to_date' => $client->paid_to_date,
|
||||
'address1' => $client->address1,
|
||||
'address2' => $client->address2,
|
||||
'city' => $client->city,
|
||||
'state' => $client->state,
|
||||
'postal_code' => $client->postal_code,
|
||||
'country_id' => $client->country_id,
|
||||
'phone' => $client->work_phone,
|
||||
'private_notes' => $client->private_notes,
|
||||
'website' => $client->website,
|
||||
'industry_id' => $client->industry_id,
|
||||
'size_id' => $client->size_id,
|
||||
'is_deleted' => $client->is_deleted,
|
||||
'vat_number' => $client->vat_number,
|
||||
'id_number' => $client->id_number,
|
||||
'custom_value1' => $client->custom_value1,
|
||||
'custom_value2' => $client->custom_value2,
|
||||
'shipping_address1' => $client->shipping_address1,
|
||||
'shipping_address2' => $client->shipping_address2,
|
||||
'shipping_city' => $client->shipping_city,
|
||||
'shipping_state' => $client->shipping_state,
|
||||
'shipping_postal_code' => $client->shipping_postal_code,
|
||||
'shipping_country_id' => $client->shipping_country_id,
|
||||
'contacts' => $this->getClientContacts($client->contacts),
|
||||
];
|
||||
}
|
||||
|
||||
return $clients;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $contacts
|
||||
* @return array
|
||||
*/
|
||||
protected function getClientContacts($contacts)
|
||||
{
|
||||
$transformed = [];
|
||||
|
||||
foreach($contacts as $contact) {
|
||||
$transformed[] = [
|
||||
'id' => $contact->id,
|
||||
'company_id' => $contact->account_id,
|
||||
'user_id' => $contact->user_id,
|
||||
'client_id' => $contact->client_id,
|
||||
'first_name' => $contact->first_name,
|
||||
'last_name' => $contact->last_name,
|
||||
'phone' => $contact->phone,
|
||||
'custom_value1' => $contact->custom_value1,
|
||||
'custom_value2' => $contact->custom_value2,
|
||||
'email' => $contact->email,
|
||||
'is_primary' => $contact->is_primary,
|
||||
'send_invoice' => $contact->send_invoice,
|
||||
'confirmed' => $contact->confirmation_token ? true : false,
|
||||
'last_login' => $contact->last_login,
|
||||
'password' => $contact->password,
|
||||
'remember_token' => $contact->remember_token,
|
||||
'contact_key' => $contact->contact_key,
|
||||
];
|
||||
}
|
||||
|
||||
return $transformed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getProducts()
|
||||
{
|
||||
$products = Product::where('account_id', $this->account->id)
|
||||
->withTrashed()
|
||||
->get();
|
||||
|
||||
$transformed = [];
|
||||
|
||||
foreach ($products as $product) {
|
||||
$transformed[] = [
|
||||
'company_id' => $product->account_id,
|
||||
'user_id' => $product->user_id,
|
||||
'custom_value1' => $product->custom_value1,
|
||||
'custom_value2' => $product->custom_value2,
|
||||
'product_key' => $product->product_key,
|
||||
'notes' => $product->notes,
|
||||
'cost' => $product->cost,
|
||||
'quantity' => $product->qty,
|
||||
'tax_name1' => $product->tax_name1,
|
||||
'tax_name2' => $product->tax_name2,
|
||||
'tax_rate1' => $product->tax_rate1,
|
||||
'tax_rate2' => $product->tax_rate2,
|
||||
'created_at' => $product->created_at ? $product->created_at->toDateString() : null,
|
||||
'updated_at' => $product->updated_at ? $product->updated_at->toDateString() : null,
|
||||
'deleted_at' => $product->deleted_at ? $product->deleted_at->toDateString() : null,
|
||||
];
|
||||
}
|
||||
|
||||
return $transformed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getUsers()
|
||||
{
|
||||
$users = User::where('account_id', $this->account->id)
|
||||
->withTrashed()
|
||||
->get();
|
||||
|
||||
$transformed = [];
|
||||
|
||||
foreach ($users as $user) {
|
||||
$transformed[] = [
|
||||
'id' => $user->id,
|
||||
'first_name' => $user->first_name,
|
||||
'last_name' => $user->last_name,
|
||||
'phone' => $user->phone,
|
||||
'email' => $user->email,
|
||||
'confirmation_code' => $user->confirmation_code,
|
||||
'failed_logins' => $user->failed_logins,
|
||||
'referral_code' => $user->referral_code,
|
||||
'oauth_user_id' => $user->oauth_user_id,
|
||||
'oauth_provider_id' => $user->oauth_provider_id,
|
||||
'google_2fa_secret' => $user->google_2fa_secret,
|
||||
'accepted_terms_version' => $user->accepted_terms_version,
|
||||
'password' => $user->password,
|
||||
'remember_token' => $user->remember_token,
|
||||
'created_at' => $user->created_at ? $user->created_at->toDateString() : null,
|
||||
'updated_at' => $user->updated_at ? $user->updated_at->toDateString() : null,
|
||||
'deleted_at' => $user->deleted_at ? $user->deleted_at->toDateString() : null,
|
||||
];
|
||||
}
|
||||
|
||||
return $transformed;
|
||||
}
|
||||
|
||||
private function getCreditsNotes()
|
||||
{
|
||||
$credits = [];
|
||||
|
||||
foreach ($this->account->invoices()->where('amount', '<', '0')->withTrashed()->get() as $credit) {
|
||||
$credits[] = [
|
||||
'id' => $credit->id,
|
||||
'client_id' => $credit->client_id,
|
||||
'user_id' => $credit->user_id,
|
||||
'company_id' => $credit->account_id,
|
||||
'status_id' => $credit->invoice_status_id,
|
||||
'design_id' => $credit->invoice_design_id,
|
||||
'number' => $credit->invoice_number,
|
||||
'discount' => $credit->discount,
|
||||
'is_amount_discount' => $credit->is_amount_discount ?: false,
|
||||
'po_number' => $credit->po_number,
|
||||
'date' => $credit->invoice_date,
|
||||
'last_sent_date' => $credit->last_sent_date,
|
||||
'due_date' => $credit->due_date,
|
||||
'is_deleted' => $credit->is_deleted,
|
||||
'footer' => $credit->invoice_footer,
|
||||
'public_notes' => $credit->public_notes,
|
||||
'private_notes' => $credit->private_notes,
|
||||
'terms' => $credit->terms,
|
||||
'tax_name1' => $credit->tax_name1,
|
||||
'tax_name2' => $credit->tax_name2,
|
||||
'tax_rate1' => $credit->tax_rate1,
|
||||
'tax_rate2' => $credit->tax_rate2,
|
||||
'custom_value1' => $credit->custom_value1,
|
||||
'custom_value2' => $credit->custom_value2,
|
||||
'next_send_date' => null,
|
||||
'amount' => $credit->amount,
|
||||
'balance' => $credit->balance,
|
||||
'partial' => $credit->partial,
|
||||
'partial_due_date' => $credit->partial_due_date,
|
||||
'line_items' => $this->getInvoiceItems($credit->invoice_items),
|
||||
'created_at' => $credit->created_at ? $credit->created_at->toDateString() : null,
|
||||
'updated_at' => $credit->updated_at ? $credit->updated_at->toDateString() : null,
|
||||
'deleted_at' => $credit->deleted_at ? $credit->deleted_at->toDateString() : null,
|
||||
];
|
||||
}
|
||||
|
||||
return $credits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getInvoices()
|
||||
{
|
||||
$invoices = [];
|
||||
|
||||
foreach ($this->account->invoices()->where('amount', '>=', '0')->withTrashed()->get() as $invoice) {
|
||||
$invoices[] = [
|
||||
'id' => $invoice->id,
|
||||
'client_id' => $invoice->client_id,
|
||||
'user_id' => $invoice->user_id,
|
||||
'company_id' => $invoice->account_id,
|
||||
'status_id' => $invoice->invoice_status_id,
|
||||
'design_id' => $invoice->invoice_design_id,
|
||||
'number' => $invoice->invoice_number,
|
||||
'discount' => $invoice->discount,
|
||||
'is_amount_discount' => $invoice->is_amount_discount ?: false,
|
||||
'po_number' => $invoice->po_number,
|
||||
'date' => $invoice->invoice_date,
|
||||
'last_sent_date' => $invoice->last_sent_date,
|
||||
'due_date' => $invoice->due_date,
|
||||
'is_deleted' => $invoice->is_deleted,
|
||||
'footer' => $invoice->invoice_footer,
|
||||
'public_notes' => $invoice->public_notes,
|
||||
'private_notes' => $invoice->private_notes,
|
||||
'uses_inclusive_taxes' => $this->account->inclusive_taxes,
|
||||
'terms' => $invoice->terms,
|
||||
'tax_name1' => $invoice->tax_name1,
|
||||
'tax_name2' => $invoice->tax_name2,
|
||||
'tax_rate1' => $invoice->tax_rate1,
|
||||
'tax_rate2' => $invoice->tax_rate2,
|
||||
'custom_value1' => $invoice->custom_value1,
|
||||
'custom_value2' => $invoice->custom_value2,
|
||||
'next_send_date' => null,
|
||||
'amount' => $invoice->amount,
|
||||
'balance' => $invoice->balance,
|
||||
'partial' => $invoice->partial,
|
||||
'partial_due_date' => $invoice->partial_due_date,
|
||||
'line_items' => $this->getInvoiceItems($invoice->invoice_items),
|
||||
'created_at' => $invoice->created_at ? $invoice->created_at->toDateString() : null,
|
||||
'updated_at' => $invoice->updated_at ? $invoice->updated_at->toDateString() : null,
|
||||
'deleted_at' => $invoice->deleted_at ? $invoice->deleted_at->toDateString() : null,
|
||||
];
|
||||
}
|
||||
|
||||
return $invoices;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $items
|
||||
* @return array
|
||||
*/
|
||||
public function getInvoiceItems($items)
|
||||
{
|
||||
$transformed = [];
|
||||
|
||||
foreach ($items as $item) {
|
||||
$transformed[] = [
|
||||
'id' => $item->id,
|
||||
'quantity' => $item->qty,
|
||||
'cost' => $item->cost,
|
||||
'product_key' => $item->product_key,
|
||||
'notes' => $item->notes,
|
||||
'discount' => $item->discount,
|
||||
'tax_name1' => $item->tax_name1,
|
||||
'tax_rate1' => $item->tax_rate1,
|
||||
'date' => $item->created_at,
|
||||
'custom_value1' => $item->custom_value1,
|
||||
'custom_value2' => $item->custom_value2,
|
||||
'line_item_type_id' => $item->invoice_item_type_id,
|
||||
];
|
||||
}
|
||||
|
||||
return $transformed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getQuotes()
|
||||
{
|
||||
$transformed = [];
|
||||
|
||||
$quotes = Invoice::where('account_id', $this->account->id)
|
||||
->where('invoice_type_id', '=', INVOICE_TYPE_QUOTE)
|
||||
->withTrashed()
|
||||
->get();
|
||||
|
||||
foreach ($quotes as $quote) {
|
||||
$transformed[] = [
|
||||
'id' => $quote->id,
|
||||
'client_id' => $quote->client_id,
|
||||
'user_id' => $quote->user_id,
|
||||
'company_id' => $quote->account_id,
|
||||
'status_id' => $quote->invoice_status_id,
|
||||
'design_id' => $quote->invoice_design_id,
|
||||
'number' => $quote->invoice_number,
|
||||
'discount' => $quote->discount,
|
||||
'is_amount_discount' => $quote->is_amount_discount ?: false,
|
||||
'po_number' => $quote->po_number,
|
||||
'date' => $quote->invoice_date,
|
||||
'last_sent_date' => $quote->last_sent_date,
|
||||
'due_date' => $quote->due_date,
|
||||
'is_deleted' => $quote->is_deleted,
|
||||
'footer' => $quote->invoice_footer,
|
||||
'public_notes' => $quote->public_notes,
|
||||
'private_notes' => $quote->private_notes,
|
||||
'terms' => $quote->terms,
|
||||
'tax_name1' => $quote->tax_name1,
|
||||
'tax_name2' => $quote->tax_name2,
|
||||
'tax_rate1' => $quote->tax_rate1,
|
||||
'tax_rate2' => $quote->tax_rate2,
|
||||
'custom_value1' => $quote->custom_value1,
|
||||
'custom_value2' => $quote->custom_value2,
|
||||
'next_send_date' => null,
|
||||
'amount' => $quote->amount,
|
||||
'balance' => $quote->balance,
|
||||
'partial' => $quote->partial,
|
||||
'partial_due_date' => $quote->partial_due_date,
|
||||
'created_at' => $quote->created_at ? $quote->created_at->toDateString() : null,
|
||||
'updated_at' => $quote->updated_at ? $quote->updated_at->toDateString() : null,
|
||||
'deleted_at' => $quote->deleted_at ? $quote->deleted_at->toDateString() : null,
|
||||
];
|
||||
}
|
||||
|
||||
return $transformed;
|
||||
}
|
||||
|
||||
public function getPayments()
|
||||
{
|
||||
$transformed = [];
|
||||
|
||||
$payments = Payment::where('account_id', $this->account->id)
|
||||
->withTrashed()
|
||||
->get();
|
||||
|
||||
foreach ($payments as $payment) {
|
||||
$transformed[] = [
|
||||
'id' => $payment->id,
|
||||
'invoices' => [
|
||||
['invoice_id' => $payment->invoice_id, 'amount' => $payment->amount, 'refunded' => $payment->refunded],
|
||||
],
|
||||
'invoice_id' => $payment->invoice_id,
|
||||
'company_id' => $payment->account_id,
|
||||
'client_id' => $payment->client_id,
|
||||
'user_id' => $payment->user_id,
|
||||
'client_contact_id' => $payment->contact_id,
|
||||
'invitation_id' => $payment->invitation_id,
|
||||
'company_gateway_id' => $payment->account_gateway_id,
|
||||
'type_id' => $payment->payment_type_id,
|
||||
'status_id' => $payment->payment_status_id,
|
||||
'amount' => $payment->amount,
|
||||
'applied' => $payment->amount,
|
||||
'refunded' => $payment->refunded,
|
||||
'date' => $payment->payment_date,
|
||||
'transaction_reference' => $payment->transaction_reference,
|
||||
'payer_id' => $payment->payer_id,
|
||||
'is_deleted' => $payment->is_deleted,
|
||||
'updated_at' => $payment->updated_at ? $payment->updated_at->toDateString() : null,
|
||||
'created_at' => $payment->created_at ? $payment->created_at->toDateString() : null,
|
||||
'deleted_at' => $payment->deleted_at ? $payment->deleted_at->toDateString() : null,
|
||||
];
|
||||
}
|
||||
|
||||
return $transformed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getCredits()
|
||||
{
|
||||
$credits = Credit::where('account_id', $this->account->id)->where('balance', '>', '0')->whereIsDeleted(false)
|
||||
->withTrashed()
|
||||
->get();
|
||||
|
||||
$transformed = [];
|
||||
|
||||
foreach ($credits as $credit) {
|
||||
$transformed[] = [
|
||||
'client_id' => $credit->client_id,
|
||||
'user_id' => $credit->user_id,
|
||||
'company_id' => $credit->account_id,
|
||||
'is_deleted' => $credit->is_deleted,
|
||||
'amount' => $credit->balance,
|
||||
'applied' => 0,
|
||||
'refunded' => 0,
|
||||
'date' => $credit->date,
|
||||
'created_at' => $credit->created_at ? $credit->created_at->toDateString() : null,
|
||||
'updated_at' => $credit->updated_at ? $credit->updated_at->toDateString() : null,
|
||||
'deleted_at' => $credit->deleted_at ? $credit->deleted_at->toDateString() : null,
|
||||
];
|
||||
}
|
||||
|
||||
return $transformed;
|
||||
// header('Content-Type: application/zip');
|
||||
// header('Content-Length: ' . filesize($file));
|
||||
// header("Content-Disposition: attachment; filename={$fileName}.zip");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ use App\Ninja\Mailers\ContactMailer as Mailer;
|
|||
use App\Ninja\Repositories\ClientRepository;
|
||||
use App\Ninja\Repositories\InvoiceRepository;
|
||||
use App\Services\InvoiceService;
|
||||
use App\Services\RecurringInvoiceService;
|
||||
use Auth;
|
||||
use Cache;
|
||||
use Input;
|
||||
|
|
@ -34,7 +33,7 @@ class QuoteController extends BaseController
|
|||
protected $invoiceService;
|
||||
protected $entityType = ENTITY_INVOICE;
|
||||
|
||||
public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, InvoiceService $invoiceService, RecurringInvoiceService $recurringInvoiceService)
|
||||
public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, InvoiceService $invoiceService)
|
||||
{
|
||||
// parent::__construct();
|
||||
|
||||
|
|
@ -42,7 +41,6 @@ class QuoteController extends BaseController
|
|||
$this->invoiceRepo = $invoiceRepo;
|
||||
$this->clientRepo = $clientRepo;
|
||||
$this->invoiceService = $invoiceService;
|
||||
$this->recurringInvoiceService = $recurringInvoiceService;
|
||||
}
|
||||
|
||||
public function index()
|
||||
|
|
@ -67,14 +65,6 @@ class QuoteController extends BaseController
|
|||
return $this->invoiceService->getDatatable($accountId, $clientPublicId, ENTITY_QUOTE, $search);
|
||||
}
|
||||
|
||||
public function getRecurringDatatable($clientPublicId = null)
|
||||
{
|
||||
$accountId = Auth::user()->account_id;
|
||||
$search = Input::get('sSearch');
|
||||
|
||||
return $this->recurringInvoiceService->getDatatable($accountId, $clientPublicId, ENTITY_RECURRING_QUOTE, $search);
|
||||
}
|
||||
|
||||
public function create(QuoteRequest $request, $clientPublicId = 0)
|
||||
{
|
||||
if (! Utils::hasFeature(FEATURE_QUOTES)) {
|
||||
|
|
@ -167,7 +157,7 @@ class QuoteController extends BaseController
|
|||
|
||||
if ($invoice->due_date) {
|
||||
$carbonDueDate = \Carbon::parse($invoice->due_date);
|
||||
if (! $account->allow_approve_expired_quote && ! $carbonDueDate->isToday() && ! $carbonDueDate->isFuture()) {
|
||||
if (! $carbonDueDate->isToday() && ! $carbonDueDate->isFuture()) {
|
||||
return redirect("view/{$invitationKey}")->withError(trans('texts.quote_has_expired'));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,41 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Ninja\Datatables\RecurringInvoiceDatatable;
|
||||
use App\Ninja\Repositories\InvoiceRepository;
|
||||
|
||||
/**
|
||||
* Class RecurringQuoteController.
|
||||
*/
|
||||
class RecurringQuoteController extends BaseController
|
||||
{
|
||||
/**
|
||||
* @var InvoiceRepository
|
||||
*/
|
||||
protected $invoiceRepo;
|
||||
|
||||
/**
|
||||
* RecurringQuoteController constructor.
|
||||
*
|
||||
* @param InvoiceRepository $invoiceRepo
|
||||
*/
|
||||
public function __construct(InvoiceRepository $invoiceRepo)
|
||||
{
|
||||
$this->invoiceRepo = $invoiceRepo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$data = [
|
||||
'title' => trans('texts.recurring_quotes'),
|
||||
'entityType' => ENTITY_RECURRING_QUOTE,
|
||||
'datatable' => new RecurringInvoiceDatatable(true, false, ENTITY_RECURRING_QUOTE),
|
||||
];
|
||||
|
||||
return response()->view('list_wrapper', $data);
|
||||
}
|
||||
}
|
||||
|
|
@ -61,8 +61,6 @@ class ReportController extends BaseController
|
|||
$action = Input::get('action');
|
||||
$format = Input::get('format');
|
||||
|
||||
$account = Auth::user()->account;
|
||||
|
||||
if (Input::get('report_type')) {
|
||||
$reportType = Input::get('report_type');
|
||||
$dateField = Input::get('date_field');
|
||||
|
|
@ -87,7 +85,6 @@ class ReportController extends BaseController
|
|||
'product',
|
||||
'profit_and_loss',
|
||||
'task',
|
||||
'task_details',
|
||||
'tax_rate',
|
||||
'quote',
|
||||
];
|
||||
|
|
@ -98,10 +95,10 @@ class ReportController extends BaseController
|
|||
'reportTypes' => array_combine($reportTypes, Utils::trans($reportTypes)),
|
||||
'reportType' => $reportType,
|
||||
'title' => trans('texts.charts_and_reports'),
|
||||
'account' => $account,
|
||||
'account' => Auth::user()->account,
|
||||
];
|
||||
|
||||
if ($account->hasFeature(FEATURE_REPORTS)) {
|
||||
if (Auth::user()->account->hasFeature(FEATURE_REPORTS)) {
|
||||
$isExport = $action == 'export';
|
||||
$config = [
|
||||
'date_field' => $dateField,
|
||||
|
|
@ -114,8 +111,7 @@ class ReportController extends BaseController
|
|||
'start_date' => $params['startDate'],
|
||||
'end_date' => $params['endDate'],
|
||||
];
|
||||
|
||||
$report = dispatch_now(new RunReport(auth()->user(), $reportType, $config, $account, $isExport));
|
||||
$report = dispatch_now(new RunReport(auth()->user(), $reportType, $config, $isExport));
|
||||
$params = array_merge($params, $report->exportParams);
|
||||
switch ($action) {
|
||||
case 'export':
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class TaskApiController extends BaseAPIController
|
|||
{
|
||||
$tasks = Task::scope()
|
||||
->withTrashed()
|
||||
->with('client', 'invoice', 'project', 'task_status', 'user')
|
||||
->with('client', 'invoice', 'project', 'task_status')
|
||||
->orderBy('updated_at', 'desc');
|
||||
|
||||
return $this->listResponse($tasks);
|
||||
|
|
|
|||
47
app/Http/Controllers/TaskController.php
Executable file → Normal file
47
app/Http/Controllers/TaskController.php
Executable file → Normal file
|
|
@ -7,7 +7,6 @@ use App\Http\Requests\TaskRequest;
|
|||
use App\Http\Requests\UpdateTaskRequest;
|
||||
use App\Models\Client;
|
||||
use App\Models\Project;
|
||||
use App\Models\Product;
|
||||
use App\Models\Task;
|
||||
use App\Models\TaskStatus;
|
||||
use App\Ninja\Datatables\TaskDatatable;
|
||||
|
|
@ -129,7 +128,6 @@ class TaskController extends BaseController
|
|||
'task' => null,
|
||||
'clientPublicId' => Input::old('client') ? Input::old('client') : ($request->client_id ?: 0),
|
||||
'projectPublicId' => Input::old('project_id') ? Input::old('project_id') : ($request->project_id ?: 0),
|
||||
'productPublicId' => Input::old('product_id') ? Input::old('product_id') : ($request->product_id ?: 0),
|
||||
'method' => 'POST',
|
||||
'url' => 'tasks',
|
||||
'title' => trans('texts.new_task'),
|
||||
|
|
@ -142,12 +140,6 @@ class TaskController extends BaseController
|
|||
return View::make('tasks.edit', $data);
|
||||
}
|
||||
|
||||
|
||||
public function cloneTask(TaskRequest $request, $publicId)
|
||||
{
|
||||
return self::edit($request, $publicId, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
|
|
@ -155,7 +147,7 @@ class TaskController extends BaseController
|
|||
*
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function edit(TaskRequest $request, $publicId, $clone = false)
|
||||
public function edit(TaskRequest $request)
|
||||
{
|
||||
$this->checkTimezone();
|
||||
$task = $request->entity();
|
||||
|
|
@ -180,36 +172,19 @@ class TaskController extends BaseController
|
|||
|
||||
$actions[] = DropdownButton::DIVIDER;
|
||||
if (! $task->trashed()) {
|
||||
if (! $clone) {
|
||||
$actions[] = ['url' => 'javascript:submitAction("clone")', 'label' => trans("texts.clone_task")];
|
||||
}
|
||||
$actions[] = ['url' => 'javascript:submitAction("archive")', 'label' => trans('texts.archive_task')];
|
||||
$actions[] = ['url' => 'javascript:onDeleteClick()', 'label' => trans('texts.delete_task')];
|
||||
} else {
|
||||
$actions[] = ['url' => 'javascript:submitAction("restore")', 'label' => trans('texts.restore_task')];
|
||||
}
|
||||
|
||||
if ($clone) {
|
||||
$task->id = null;
|
||||
$task->public_id = null;
|
||||
$task->deleted_at = null;
|
||||
|
||||
$method = 'POST';
|
||||
$url = 'tasks';
|
||||
}
|
||||
else{
|
||||
$method = 'PUT';
|
||||
$url = 'tasks/'.$task->public_id;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'task' => $task,
|
||||
'entity' => $task,
|
||||
'clientPublicId' => $task->client ? $task->client->public_id : 0,
|
||||
'projectPublicId' => $task->project ? $task->project->public_id : 0,
|
||||
'productPublicId' => $task->product ? $task->product->public_id : 0,
|
||||
'method' => $method,
|
||||
'url' => $url,
|
||||
'method' => 'PUT',
|
||||
'url' => 'tasks/'.$task->public_id,
|
||||
'title' => trans('texts.edit_task'),
|
||||
'actions' => $actions,
|
||||
'timezone' => Auth::user()->account->timezone ? Auth::user()->account->timezone->name : DEFAULT_TIMEZONE,
|
||||
|
|
@ -244,7 +219,6 @@ class TaskController extends BaseController
|
|||
'clients' => Client::scope()->withActiveOrSelected($task ? $task->client_id : false)->with('contacts')->orderBy('name')->get(),
|
||||
'account' => Auth::user()->account,
|
||||
'projects' => Project::scope()->withActiveOrSelected($task ? $task->project_id : false)->with('client.contacts')->orderBy('name')->get(),
|
||||
'products' => Product::scope()->withActiveOrSelected($task ? $task->product_id : false)->orderBy('product_key')->get(),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -255,13 +229,8 @@ class TaskController extends BaseController
|
|||
*/
|
||||
private function save($request, $publicId = null)
|
||||
{
|
||||
|
||||
$action = Input::get('action');
|
||||
|
||||
if ( in_array($action, ['clone'])) {
|
||||
return redirect()->to(sprintf('tasks/%s/clone', $publicId));
|
||||
}
|
||||
|
||||
if (in_array($action, ['archive', 'delete', 'restore'])) {
|
||||
return self::bulk();
|
||||
}
|
||||
|
|
@ -334,20 +303,12 @@ class TaskController extends BaseController
|
|||
|
||||
$account = Auth::user()->account;
|
||||
$showProject = $lastProjectId != $task->project_id;
|
||||
$item_data = [
|
||||
$data[] = [
|
||||
'publicId' => $task->public_id,
|
||||
'description' => $task->present()->invoiceDescription($account, $showProject),
|
||||
'duration' => $task->getHours(),
|
||||
'cost' => $task->getRate(),
|
||||
'productKey' => null,
|
||||
];
|
||||
|
||||
if (!empty($task->product_id)) {
|
||||
$item_data['productKey'] = $task->product->product_key;
|
||||
}
|
||||
|
||||
$data[] = $item_data;
|
||||
|
||||
$lastProjectId = $task->project_id;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ class TaxRateApiController extends BaseAPIController
|
|||
{
|
||||
$entity = $request->entity();
|
||||
|
||||
$entity->delete();
|
||||
$this->taxRateRepo->delete($entity);
|
||||
|
||||
return $this->itemResponse($entity);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,375 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Events\TicketUserViewed;
|
||||
use App\Http\Requests\CreateTicketRequest;
|
||||
use App\Http\Requests\TicketAddEntityRequest;
|
||||
use App\Http\Requests\TicketInboundRequest;
|
||||
use App\Http\Requests\TicketMergeRequest;
|
||||
use App\Http\Requests\TicketRemoveEntityRequest;
|
||||
use App\Http\Requests\TicketRequest;
|
||||
use App\Http\Requests\UpdateTicketRequest;
|
||||
use App\Libraries\Utils;
|
||||
use App\Models\Client;
|
||||
use App\Models\Ticket;
|
||||
use App\Models\TicketComment;
|
||||
use App\Models\TicketRelation;
|
||||
use App\Models\User;
|
||||
use App\Ninja\Datatables\TicketDatatable;
|
||||
use App\Ninja\Repositories\TicketRepository;
|
||||
use App\Services\TicketService;
|
||||
use Barryvdh\LaravelIdeHelper\Eloquent;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Redirect;
|
||||
use Illuminate\Support\Facades\Request;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use DB;
|
||||
|
||||
/**
|
||||
* Class TicketController
|
||||
* @package App\Http\Controllers
|
||||
*/
|
||||
class TicketController extends BaseController
|
||||
{
|
||||
|
||||
/**
|
||||
* @var TicketService
|
||||
*/
|
||||
protected $ticketService;
|
||||
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
protected $ticketRepository;
|
||||
|
||||
/**
|
||||
* TicketController constructor.
|
||||
* @param TicketService $ticketService
|
||||
*/
|
||||
public function __construct(TicketService $ticketService, TicketRepository $ticketRepository)
|
||||
{
|
||||
|
||||
$this->ticketService = $ticketService;
|
||||
$this->ticketRepo = $ticketRepository;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
||||
return View::make('list_wrapper', [
|
||||
'entityType' => ENTITY_TICKET,
|
||||
'datatable' => new TicketDatatable(),
|
||||
'title' => trans('texts.tickets'),
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $clientPublicId
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function getDatatable($clientPublicId = null)
|
||||
{
|
||||
|
||||
$search = Input::get('sSearch');
|
||||
|
||||
return $this->ticketService->getDatatable($search);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $publicId
|
||||
* @return Redirect
|
||||
*/
|
||||
public function show($publicId)
|
||||
{
|
||||
|
||||
Session::reflash();
|
||||
|
||||
return redirect("tickets/$publicId/edit");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TicketRequest $request
|
||||
* @return View
|
||||
*/
|
||||
public function edit(TicketRequest $request)
|
||||
{
|
||||
|
||||
$ticket = $request->entity();
|
||||
|
||||
$clients = false;
|
||||
|
||||
//If we are missing a client from the ticket, load clients for assignment
|
||||
if($ticket->is_internal == TRUE && !$ticket->client_id)
|
||||
$clients = Client::scope()->with('contacts')->get();
|
||||
else if(!$ticket->client_id)
|
||||
$clients = $this->ticketService->findClientsByContactEmail($ticket->contact_key);
|
||||
|
||||
$data = array_merge(self::getViewModel($ticket, $clients));
|
||||
|
||||
event(new TicketUserViewed($ticket));
|
||||
|
||||
return View::make('tickets.edit', $data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UpdateTicketRequest $request
|
||||
* @return View
|
||||
*/
|
||||
|
||||
public function update(UpdateTicketRequest $request)
|
||||
{
|
||||
|
||||
$data = $request->input();
|
||||
$data['document_ids'] = $request->document_ids;
|
||||
|
||||
if($data['closed'] != '0000-00-00 00:00:00')
|
||||
$data['action'] = TICKET_AGENT_CLOSED;
|
||||
elseif(isset($data['description']) && strlen($data['description']) > 0)
|
||||
$data['action'] = TICKET_AGENT_UPDATE;
|
||||
else
|
||||
$data['action'] = TICKET_SAVE_ONLY;
|
||||
|
||||
$ticket = $request->entity();
|
||||
$ticket = $this->ticketService->save($data, $ticket);
|
||||
|
||||
$ticket->load('documents', 'relations');
|
||||
|
||||
$entityType = $ticket->getEntityType();
|
||||
|
||||
$message = trans("texts.updated_{$entityType}");
|
||||
|
||||
Session::flash('message', $message);
|
||||
|
||||
$data = array_merge($this->getViewmodel($ticket), $data);
|
||||
|
||||
return View::make('tickets.edit', $data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
public function bulk()
|
||||
{
|
||||
|
||||
$action = Input::get('action');
|
||||
|
||||
$ids = Input::get('public_id') ? Input::get('public_id') : Input::get('ids');
|
||||
|
||||
if ($action == 'purge' && ! auth()->user()->is_admin)
|
||||
return redirect('dashboard')->withError(trans('texts.not_authorized'));
|
||||
|
||||
$count = $this->ticketService->bulk($ids, $action);
|
||||
|
||||
$message = Utils::pluralize($action.'d_ticket', $count);
|
||||
|
||||
Session::flash('message', $message);
|
||||
|
||||
if ($action == 'purge')
|
||||
return redirect('dashboard')->withMessage($message);
|
||||
else
|
||||
return $this->returnBulk(ENTITY_TICKET, $action, $ids);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TicketRequest $request
|
||||
* @param int $parentTicketId
|
||||
* @return View
|
||||
*/
|
||||
public function create(TicketRequest $request, $parentTicketId = 0)
|
||||
{
|
||||
|
||||
$parentTicket = Ticket::scope($parentTicketId)->first();
|
||||
|
||||
$parentTicketClientExists = false;
|
||||
|
||||
if ($parentTicket && method_exists($parentTicket, 'client')) {
|
||||
$parentTicket->load('client');
|
||||
$parentTicketClientExists = true;
|
||||
}
|
||||
|
||||
//need to mock a ticket object or check if $request->old() exists and pass that in its place.
|
||||
$mockTicket = [
|
||||
'parent_ticket_id' => $parentTicketId ? $parentTicketId : null,
|
||||
'subject' => '',
|
||||
'description' => '',
|
||||
'due_date' => '',
|
||||
'client_public_id' => $parentTicketClientExists ? $parentTicket->client->public_id : null,
|
||||
'agent_id' => null,
|
||||
'is_internal' => $parentTicketClientExists ? true : false,
|
||||
'private_notes' => '',
|
||||
'priority_id' =>1,
|
||||
];
|
||||
|
||||
$data = [
|
||||
'users' => User::whereAccountId(Auth::user()->account_id)->get(),
|
||||
'is_internal' => $request->parent_ticket_id ? true : false,
|
||||
'parent_ticket' => $parentTicket ?: false,
|
||||
'url' => 'tickets/',
|
||||
'parent_tickets' => Ticket::scope()->where('status_id', '!=', 3)->whereNull('merged_parent_ticket_id')->OrderBy('public_id', 'DESC')->get(),
|
||||
'method' => 'POST',
|
||||
'title' => trans('texts.new_ticket'),
|
||||
'account' => Auth::user()->account->load('clients.contacts', 'users'),
|
||||
'timezone' => Auth::user()->account->timezone ? Auth::user()->account->timezone->name : DEFAULT_TIMEZONE,
|
||||
'datetimeFormat' => Auth::user()->account->getMomentDateTimeFormat(),
|
||||
'old' => $request->old() ? $request->old() : $mockTicket,
|
||||
'clients' => Client::scope()->with('contacts')->get(),
|
||||
];
|
||||
|
||||
return View::make('tickets.new_ticket', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CreateTicketRequest $request
|
||||
* @return Redirect
|
||||
*/
|
||||
public function store(CreateTicketRequest $request)
|
||||
{
|
||||
$input = $request->input();
|
||||
$input['action'] = TICKET_AGENT_NEW;
|
||||
|
||||
$ticket = $this->ticketService->save($input, $request->entity());
|
||||
|
||||
return redirect("tickets/$ticket->public_id/edit");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private static function getViewModel($ticket = false, $clients = false)
|
||||
{
|
||||
|
||||
return [
|
||||
'clients' => $clients,
|
||||
//'status' => $ticket->status(),
|
||||
'comments' => $ticket->comments(),
|
||||
'account' => Auth::user()->account,
|
||||
'url' => 'tickets/' . $ticket->public_id,
|
||||
'ticket' => $ticket,
|
||||
'entity' => $ticket,
|
||||
'title' => trans('texts.edit_ticket'),
|
||||
'timezone' => Auth::user()->account->timezone ? Auth::user()->account->timezone->name : DEFAULT_TIMEZONE,
|
||||
'datetimeFormat' => Auth::user()->account->getMomentDateTimeFormat(),
|
||||
'method' => 'PUT',
|
||||
'isAdminUser' => Auth::user()->is_admin || Auth::user()->isTicketMaster() ? true : false,
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*/
|
||||
public function inbound(TicketInboundRequest $request) : void
|
||||
{
|
||||
|
||||
$ticket = $request->entity();
|
||||
|
||||
if(!$ticket)
|
||||
Log::error('no ticket found - ? spam or new request?');
|
||||
else
|
||||
Log::error('ticket #'. $ticket->ticket_number .' found');
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $publicId
|
||||
* @return View
|
||||
*/
|
||||
public function merge($publicId)
|
||||
{
|
||||
$ticket = Ticket::scope($publicId)->first();
|
||||
|
||||
$data = [
|
||||
'mergeableTickets' => $ticket->getClientMergeableTickets(),
|
||||
'ticket' => $ticket,
|
||||
'account' => Auth::user()->account,
|
||||
'title' => trans('texts.ticket_merge'),
|
||||
'method' => 'POST',
|
||||
'url' => 'tickets/merge/',
|
||||
'entity' => $ticket,
|
||||
];
|
||||
|
||||
return View::make('tickets.merge', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TicketMergeRequest $request
|
||||
* @return Redirect
|
||||
*/
|
||||
public function actionMerge(TicketMergeRequest $request)
|
||||
{
|
||||
|
||||
$ticket = $request->entity();
|
||||
$this->ticketService->mergeTicket($ticket, $request->input());
|
||||
|
||||
Session::reflash();
|
||||
|
||||
return redirect("tickets/$request->updated_ticket_id/edit");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getTicketRelationCollection(\Illuminate\Http\Request $request)
|
||||
{
|
||||
|
||||
return $this->ticketService->getRelationCollection($request);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add ticket relation entity.
|
||||
* returns a formatted URL
|
||||
* @return string
|
||||
*/
|
||||
public function addEntity(TicketAddEntityRequest $request)
|
||||
{
|
||||
|
||||
return $request->addEntity();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove ticket
|
||||
* @return primary ID
|
||||
*/
|
||||
public function removeEntity(TicketRemoveEntityRequest $request)
|
||||
{
|
||||
TicketRelation::destroy(request()->id);
|
||||
return request()->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Algolia / Elasticsearch
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function search()
|
||||
{
|
||||
|
||||
if( config('ninja.scout_driver') != null) {
|
||||
|
||||
$result = TicketComment::search(request()->term)->where('agent_id', Auth::user()->id)->get()->pluck('description');
|
||||
return response()->json($result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,200 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\CreateTicketTemplateRequest;
|
||||
use App\Libraries\Utils;
|
||||
use App\Models\TicketTemplate;
|
||||
use App\Services\TicketTemplateService;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
use Illuminate\Support\Facades\Redirect;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Facades\View;
|
||||
|
||||
class TicketTemplateController extends BaseController
|
||||
{
|
||||
|
||||
/**
|
||||
* @var TicketTemplateService
|
||||
*/
|
||||
|
||||
protected $ticketTemplateService;
|
||||
|
||||
|
||||
/**
|
||||
* TicketTemplateController constructor.
|
||||
* @param TicketTemplateService $ticketTemplateService
|
||||
*/
|
||||
|
||||
public function __construct(TicketTemplateService $ticketTemplateService)
|
||||
{
|
||||
|
||||
$this->ticketTemplateService = $ticketTemplateService;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
|
||||
public function index()
|
||||
{
|
||||
|
||||
return Redirect::to('settings/' . ACCOUNT_TICKETS . '#templates');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $clientPublicId
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
|
||||
public function getDatatable($clientPublicId = null)
|
||||
{
|
||||
return $this->ticketTemplateService->getDatatable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $publicId
|
||||
* @return mixed
|
||||
*/
|
||||
|
||||
public function show($publicId)
|
||||
{
|
||||
Session::reflash();
|
||||
|
||||
return Redirect::to("ticket_templates/$publicId/edit");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $publicId
|
||||
* @return mixed
|
||||
*/
|
||||
|
||||
public function edit($publicId)
|
||||
{
|
||||
|
||||
$ticketTemplate = TicketTemplate::scope($publicId)->firstOrFail();
|
||||
|
||||
$data = self::getViewModel($ticketTemplate);
|
||||
|
||||
$data = array_merge($data, [
|
||||
'method' => 'PUT',
|
||||
'url' => '/ticket_templates/'.$publicId,
|
||||
]);
|
||||
|
||||
return View::make('accounts.ticket_templates', $data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $publicId
|
||||
* @return mixed
|
||||
*/
|
||||
|
||||
public function update($publicId)
|
||||
{
|
||||
return $this->save($publicId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CreateTicketTemplateRequest $request
|
||||
* @return mixed
|
||||
*/
|
||||
|
||||
public function store(CreateTicketTemplateRequest $request)
|
||||
{
|
||||
|
||||
return $this->save();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the form for account creation.
|
||||
*/
|
||||
|
||||
public function create()
|
||||
{
|
||||
|
||||
$data = self::getViewModel(null);
|
||||
|
||||
$data = array_merge($data,[
|
||||
'method' => 'POST',
|
||||
'url' => '/ticket_templates/create',
|
||||
'title' => trans('texts.add_template')
|
||||
]);
|
||||
|
||||
return View::make('accounts.ticket_templates', $data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $ticketTemplate
|
||||
* @return array
|
||||
*/
|
||||
|
||||
private function getViewModel($ticketTemplate)
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
$account = $user->account;
|
||||
|
||||
return [
|
||||
'account' => $account,
|
||||
'user' => $user,
|
||||
'config' => false,
|
||||
'ticket_templates' => $ticketTemplate,
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
|
||||
public function bulk()
|
||||
{
|
||||
|
||||
$action = Input::get('bulk_action');
|
||||
|
||||
$ids = Input::get('bulk_public_id');
|
||||
|
||||
$count = $this->ticketTemplateService->bulk($ids, $action);
|
||||
|
||||
$message = Utils::pluralize($action.'d_ticket_template', $count);
|
||||
|
||||
Session::flash('message', $message);
|
||||
|
||||
return Redirect::to('settings/' . ACCOUNT_TICKETS . '#templates');
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param bool $ticketTemplatePublicId
|
||||
* @return mixed
|
||||
*/
|
||||
|
||||
public function save($ticketTemplatePublicId = false)
|
||||
{
|
||||
|
||||
if ($ticketTemplatePublicId)
|
||||
$ticketTemplate = TicketTemplate::scope($ticketTemplatePublicId)->firstOrFail();
|
||||
else
|
||||
$ticketTemplate = TicketTemplate::createNew();
|
||||
|
||||
$ticketTemplate->name = Input::get('name');
|
||||
$ticketTemplate->description = Input::get('description');
|
||||
$ticketTemplate->save();
|
||||
|
||||
$message = $ticketTemplatePublicId ? trans('texts.updated_ticket_template') : trans('texts.created_ticket_template');
|
||||
|
||||
Session::flash('message', $message);
|
||||
|
||||
return Redirect::to('settings/' . ACCOUNT_TICKETS . '#templates');
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -63,6 +63,6 @@ class Kernel extends HttpKernel
|
|||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
'lookup' => \App\Http\Middleware\DatabaseLookup::class,
|
||||
'permissions.required' => \App\Http\Middleware\PermissionsRequired::class,
|
||||
'ticket' => \App\Http\Middleware\InboundTicketCheck::class,
|
||||
'migration' => \App\Http\Middleware\EligibleForMigration::class,
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ use App\Models\Account;
|
|||
use App\Models\Contact;
|
||||
use App\Models\Invitation;
|
||||
use App\Models\ProposalInvitation;
|
||||
use App\Models\TicketInvitation;
|
||||
use Auth;
|
||||
use Utils;
|
||||
use Closure;
|
||||
|
|
@ -29,22 +28,14 @@ class Authenticate
|
|||
public function handle($request, Closure $next, $guard = 'user')
|
||||
{
|
||||
$authenticated = Auth::guard($guard)->check();
|
||||
|
||||
$invitationKey = false;
|
||||
|
||||
if($request->invitation_key)
|
||||
$invitationKey = $request->invitation_key;
|
||||
elseif($request->proposal_invitation_key)
|
||||
$invitationKey = $request->proposal_invitation_key;
|
||||
elseif($request->ticket_invitation_key)
|
||||
$invitationKey = $request->ticket_invitation_key;
|
||||
$invitationKey = $request->invitation_key ?: $request->proposal_invitation_key;
|
||||
|
||||
if ($guard == 'client') {
|
||||
if (! empty($request->invitation_key) || ! empty($request->proposal_invitation_key) || ! empty($request->ticket_invitation_key)) {
|
||||
if (! empty($request->invitation_key) || ! empty($request->proposal_invitation_key)) {
|
||||
$contact_key = session('contact_key');
|
||||
if ($contact_key) {
|
||||
$contact = $this->getContact($contact_key);
|
||||
$invitation = $this->getInvitation($invitationKey, ! empty($request->proposal_invitation_key), ! empty($request->ticket_invitation_key));
|
||||
$invitation = $this->getInvitation($invitationKey, ! empty($request->proposal_invitation_key));
|
||||
|
||||
if (! $invitation) {
|
||||
return response()->view('error', [
|
||||
|
|
@ -72,12 +63,12 @@ class Authenticate
|
|||
$contact = false;
|
||||
if ($contact_key) {
|
||||
$contact = $this->getContact($contact_key);
|
||||
} elseif ($invitationKey && $invitation = $this->getInvitation($invitationKey, ! empty($request->proposal_invitation_key), ! empty($request->ticket_invitation_key))) {
|
||||
} elseif ($invitation = $this->getInvitation($invitationKey, ! empty($request->proposal_invitation_key))) {
|
||||
$contact = $invitation->contact;
|
||||
Session::put('contact_key', $contact->contact_key);
|
||||
}
|
||||
if (! $contact) {
|
||||
return \Redirect::to('client/session_expired');
|
||||
return \Redirect::to('client/login');
|
||||
}
|
||||
|
||||
$account = $contact->account;
|
||||
|
|
@ -136,7 +127,7 @@ class Authenticate
|
|||
*
|
||||
* @return \Illuminate\Database\Eloquent\Model|null|static
|
||||
*/
|
||||
protected function getInvitation($key, $isProposal = false, $isTicket = false)
|
||||
protected function getInvitation($key, $isProposal = false)
|
||||
{
|
||||
if (! $key) {
|
||||
return false;
|
||||
|
|
@ -148,8 +139,6 @@ class Authenticate
|
|||
|
||||
if ($isProposal) {
|
||||
$invitation = ProposalInvitation::withTrashed()->where('invitation_key', '=', $key)->first();
|
||||
} elseif ($isTicket) {
|
||||
$invitation = TicketInvitation::withTrashed()->where('invitation_key', '=', $key)->first();
|
||||
} else {
|
||||
$invitation = Invitation::withTrashed()->where('invitation_key', '=', $key)->first();
|
||||
}
|
||||
|
|
|
|||
22
app/Http/Middleware/Cors.php
Normal file
22
app/Http/Middleware/Cors.php
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
|
||||
class Cors
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
return $next($request)
|
||||
->header('Access-Control-Allow-Origin', '*')
|
||||
->header('Access-Control-Allow-Methods', 'GET, POST');
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Models\LookupTicketInvitation;
|
||||
use Illuminate\Http\Request;
|
||||
use Closure;
|
||||
use App\Models\LookupAccount;
|
||||
|
|
@ -47,14 +46,10 @@ class DatabaseLookup
|
|||
LookupInvitation::setServerByField('invitation_key', $key);
|
||||
} elseif ($key = request()->proposal_invitation_key) {
|
||||
LookupProposalInvitation::setServerByField('invitation_key', $key);
|
||||
} elseif ($key = request()->ticket_invitation_key) {
|
||||
LookupTicketInvitation::setServerByField('invitation_key', $key);
|
||||
} elseif ($key = request()->contact_key ?: session('contact_key')) {
|
||||
LookupContact::setServerByField('contact_key', $key);
|
||||
} elseif ($key = request()->account_key) {
|
||||
LookupAccount::setServerByField('account_key', $key);
|
||||
} elseif($key = request()->MailboxHash) {
|
||||
LookupTicketInvitation::setServerByField('ticket_hash', $key);
|
||||
} else {
|
||||
$subdomain = Utils::getSubdomain(\Request::server('HTTP_HOST'));
|
||||
if ($subdomain != 'app') {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ class DuplicateSubmissionCheck
|
|||
{
|
||||
if ($request->is('api/v1/*')
|
||||
|| $request->is('save_sidebar_state')
|
||||
|| $request->is('tickets/search')
|
||||
|| $request->is('documents')) {
|
||||
return $next($request);
|
||||
}
|
||||
|
|
|
|||
24
app/Http/Middleware/EligibleForMigration.php
Normal file
24
app/Http/Middleware/EligibleForMigration.php
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
|
||||
class EligibleForMigration
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
if (auth()->user()->eligibleForMigration()) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
return redirect('/settings/account_management');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Models\LookupAccount;
|
||||
use App\Models\LookupTicketInvitation;
|
||||
use App\Ninja\Tickets\Inbound\InboundTicketFactory;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
|
||||
class InboundTicketCheck
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Closure $next
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
|
||||
if (! config('ninja.multi_db_enabled'))
|
||||
return $next($request);
|
||||
|
||||
$inbound = new InboundTicketFactory($request->input());
|
||||
|
||||
if($inbound->mailboxHash()){
|
||||
//check if we can find the ticket_hash
|
||||
LookupTicketInvitation::setServerByField('ticket_hash', $inbound->mailboxHash());
|
||||
|
||||
}
|
||||
elseif($inbound->to()) {
|
||||
//otherwise check if we can find the unique localpart.
|
||||
$parts = explode("@", $inbound->to());
|
||||
|
||||
LookupAccount::setServerByField('support_email_local_part', $parts[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* If we don't trigger any of these if blocks, we need to die()
|
||||
*/
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
|
@ -62,8 +62,9 @@ class StartupCheck
|
|||
|
||||
if (Utils::isSelfHost()) {
|
||||
// Check if config:cache may have been run
|
||||
if (app()->configurationIsCached()) {
|
||||
echo 'Config caching is not currently supported, please run the following command to clear the cache.<pre>php artisan config:clear</pre>';
|
||||
if (! env('APP_URL')) {
|
||||
echo "<p>There appears to be a problem with your configuration, please check your .env file.</p>" .
|
||||
"<p>If you've run 'php artisan config:cache' you will need to run 'php artisan config:clear'</p>.";
|
||||
exit;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ class VerifyCsrfToken extends BaseVerifier
|
|||
'payment_hook/*',
|
||||
'buy_now*',
|
||||
'hook/bot/*',
|
||||
'tickets/inbound',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Client;
|
||||
|
||||
class CreateClientRequest extends ClientRequest
|
||||
{
|
||||
/**
|
||||
|
|
@ -13,7 +11,7 @@ class CreateClientRequest extends ClientRequest
|
|||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('create', Client::class);
|
||||
return $this->user()->can('create', ENTITY_CLIENT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Client;
|
||||
|
||||
class CreateContactRequest extends ContactRequest
|
||||
{
|
||||
/**
|
||||
|
|
@ -13,7 +11,7 @@ class CreateContactRequest extends ContactRequest
|
|||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('create', Client::class);
|
||||
return $this->user()->can('create', ENTITY_CONTACT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Credit;
|
||||
|
||||
class CreateCreditRequest extends CreditRequest
|
||||
{
|
||||
/**
|
||||
|
|
@ -13,7 +11,7 @@ class CreateCreditRequest extends CreditRequest
|
|||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('create', Credit::class);
|
||||
return $this->user()->can('create', ENTITY_CREDIT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ class CreateCustomerRequest extends CustomerRequest
|
|||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('create');
|
||||
return $this->user()->can('create', ENTITY_CUSTOMER);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ class CreateDocumentRequest extends DocumentRequest
|
|||
protected $autoload = [
|
||||
ENTITY_INVOICE,
|
||||
ENTITY_EXPENSE,
|
||||
ENTITY_TICKET,
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -20,27 +19,8 @@ class CreateDocumentRequest extends DocumentRequest
|
|||
*/
|
||||
public function authorize()
|
||||
{
|
||||
if(session('contact_key'))
|
||||
if($this->user()->hasFeature(FEATURE_DOCUMENTS))
|
||||
return true;
|
||||
|
||||
if (! $this->user()->hasFeature(FEATURE_DOCUMENTS))
|
||||
return false;
|
||||
|
||||
|
||||
if ($this->invoice && $this->user()->cannot('edit', $this->invoice))
|
||||
return false;
|
||||
|
||||
|
||||
if ($this->expense && $this->user()->cannot('edit', $this->expense))
|
||||
return false;
|
||||
|
||||
|
||||
if($this->ticket && $this->user()->cannot('edit', $this->ticket))
|
||||
return false;
|
||||
|
||||
|
||||
return true;
|
||||
//return $this->user()->can('create');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Expense;
|
||||
|
||||
class CreateExpenseCategoryRequest extends ExpenseCategoryRequest
|
||||
{
|
||||
// Expenses
|
||||
|
|
@ -15,7 +13,7 @@ class CreateExpenseCategoryRequest extends ExpenseCategoryRequest
|
|||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('create', Expense::class);
|
||||
return $this->user()->can('create', ENTITY_EXPENSE_CATEGORY);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Expense;
|
||||
|
||||
class CreateExpenseRequest extends ExpenseRequest
|
||||
{
|
||||
// Expenses
|
||||
|
|
@ -15,7 +13,7 @@ class CreateExpenseRequest extends ExpenseRequest
|
|||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('create', Expense::class);
|
||||
return $this->user()->can('create', ENTITY_EXPENSE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Invoice;
|
||||
|
||||
class CreateInvoiceAPIRequest extends InvoiceRequest
|
||||
{
|
||||
|
|
@ -14,7 +13,7 @@ class CreateInvoiceAPIRequest extends InvoiceRequest
|
|||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('create', Invoice::class);
|
||||
return $this->user()->can('create', ENTITY_INVOICE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Invoice;
|
||||
|
||||
class CreateInvoiceRequest extends InvoiceRequest
|
||||
{
|
||||
|
|
@ -15,10 +14,16 @@ class CreateInvoiceRequest extends InvoiceRequest
|
|||
public function authorize()
|
||||
{
|
||||
if (request()->input('is_quote'))
|
||||
return $this->user()->can('createEntity', ENTITY_QUOTE);
|
||||
else
|
||||
return $this->user()->can('create', Invoice::class);
|
||||
return $this->user()->can('create', ENTITY_QUOTE);
|
||||
else {
|
||||
|
||||
if(request()->input('is_recurring'))
|
||||
$standardOrRecurringInvoice = ENTITY_RECURRING_INVOICE;
|
||||
else
|
||||
$standardOrRecurringInvoice = ENTITY_INVOICE;
|
||||
|
||||
return $this->user()->can('create', $standardOrRecurringInvoice);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
|
||||
class CreatePaymentAPIRequest extends PaymentRequest
|
||||
{
|
||||
|
|
@ -14,7 +13,7 @@ class CreatePaymentAPIRequest extends PaymentRequest
|
|||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('create', Payment::class);
|
||||
return $this->user()->can('create', ENTITY_PAYMENT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
|
||||
class CreatePaymentRequest extends PaymentRequest
|
||||
{
|
||||
|
|
@ -14,7 +13,7 @@ class CreatePaymentRequest extends PaymentRequest
|
|||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('create', Payment::class);
|
||||
return $this->user()->can('create', ENTITY_PAYMENT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Invoice;
|
||||
use App\Models\PaymentTerm;
|
||||
|
||||
class CreatePaymentTermRequest extends PaymentTermRequest
|
||||
{
|
||||
|
|
@ -15,7 +14,7 @@ class CreatePaymentTermRequest extends PaymentTermRequest
|
|||
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('create', PaymentTerm::class) || $this->user()->can('create', Invoice::class);
|
||||
return $this->user()->can('create', ENTITY_PAYMENT_TERM);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Product;
|
||||
|
||||
class CreateProductRequest extends ProductRequest
|
||||
{
|
||||
/**
|
||||
|
|
@ -13,7 +11,7 @@ class CreateProductRequest extends ProductRequest
|
|||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('create', Product::class);
|
||||
return $this->user()->can('create', ENTITY_PRODUCT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Project;
|
||||
|
||||
class CreateProjectRequest extends ProjectRequest
|
||||
{
|
||||
/**
|
||||
|
|
@ -13,7 +11,7 @@ class CreateProjectRequest extends ProjectRequest
|
|||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('create', Project::class);
|
||||
return $this->user()->can('create', ENTITY_PROJECT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,9 +2,6 @@
|
|||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Proposal;
|
||||
use App\Models\ProposalCategory;
|
||||
|
||||
class CreateProposalCategoryRequest extends ProposalCategoryRequest
|
||||
{
|
||||
/**
|
||||
|
|
@ -14,7 +11,7 @@ class CreateProposalCategoryRequest extends ProposalCategoryRequest
|
|||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('create', Proposal::class) || $this->user()->can('create', ProposalCategory::class);
|
||||
return $this->user()->can('create', ENTITY_PROPOSAL_CATEGORY);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Proposal;
|
||||
|
||||
class CreateProposalRequest extends ProposalRequest
|
||||
{
|
||||
/**
|
||||
|
|
@ -13,7 +11,7 @@ class CreateProposalRequest extends ProposalRequest
|
|||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('create', Proposal::class);
|
||||
return $this->user()->can('create', ENTITY_PROPOSAL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Proposal;
|
||||
|
||||
class CreateProposalSnippetRequest extends ProposalSnippetRequest
|
||||
{
|
||||
/**
|
||||
|
|
@ -13,7 +11,7 @@ class CreateProposalSnippetRequest extends ProposalSnippetRequest
|
|||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('create', Proposal::class);
|
||||
return $this->user()->can('create', ENTITY_PROPOSAL_SNIPPET);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Proposal;
|
||||
|
||||
class CreateProposalTemplateRequest extends ProposalTemplateRequest
|
||||
{
|
||||
/**
|
||||
|
|
@ -13,7 +11,7 @@ class CreateProposalTemplateRequest extends ProposalTemplateRequest
|
|||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('create', Proposal::class);
|
||||
return $this->user()->can('create', ENTITY_PROPOSAL_TEMPLATE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Expense;
|
||||
|
||||
class CreateRecurringExpenseRequest extends RecurringExpenseRequest
|
||||
{
|
||||
/**
|
||||
|
|
@ -13,7 +11,7 @@ class CreateRecurringExpenseRequest extends RecurringExpenseRequest
|
|||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('create', Expense::class);
|
||||
return $this->user()->can('create', ENTITY_RECURRING_EXPENSE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Task;
|
||||
|
||||
class CreateTaskRequest extends TaskRequest
|
||||
{
|
||||
/**
|
||||
|
|
@ -13,7 +11,7 @@ class CreateTaskRequest extends TaskRequest
|
|||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('create', Task::class);
|
||||
return $this->user()->can('create', ENTITY_TASK);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class CreateTaxRateRequest extends TaxRateRequest
|
|||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->hasPermission('admin');
|
||||
return $this->user()->can('create', ENTITY_TAX_RATE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,69 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class CreateTicketRequest extends EntityRequest
|
||||
{
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected $autoload = [
|
||||
ENTITY_CLIENT
|
||||
];
|
||||
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('create', Ticket::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
|
||||
public function rules()
|
||||
{
|
||||
$rules = [];
|
||||
$rules['subject'] = 'required';
|
||||
$rules['description'] = 'required';
|
||||
|
||||
if(request()->input('is_internal'))
|
||||
$rules['agent_id'] = 'required';
|
||||
else
|
||||
$rules['client_public_id']= 'required';
|
||||
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
public function sanitize()
|
||||
{
|
||||
|
||||
$data = $this->all();
|
||||
|
||||
if(isset($data['client_public_id']) && $data['client_public_id'] > 0 && !isset($data['contact_key'])){
|
||||
$client = Client::scope($data['client_public_id'])->first();
|
||||
$contact = $client->getPrimaryContact();
|
||||
$data['contact_key'] = $contact->contact_key;
|
||||
}
|
||||
|
||||
if($data['parent_ticket_id'] > 0)
|
||||
$data['parent_ticket_id'] = Ticket::getPrivateId($data['parent_ticket_id']);
|
||||
|
||||
//if(isset($data['agent_id']) && $data['agent_id'] == 0)
|
||||
// $data['agent_id'] = Auth::user()->id;
|
||||
|
||||
$this->replace($data);
|
||||
|
||||
return $this->all();
|
||||
}
|
||||
}
|
||||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Vendor;
|
||||
|
||||
class CreateVendorRequest extends VendorRequest
|
||||
{
|
||||
/**
|
||||
|
|
@ -13,7 +11,7 @@ class CreateVendorRequest extends VendorRequest
|
|||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('create', Vendor::class);
|
||||
return $this->user()->can('create', ENTITY_VENDOR);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,20 +2,7 @@
|
|||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Contact;
|
||||
|
||||
class DocumentRequest extends EntityRequest
|
||||
{
|
||||
protected $entityType = ENTITY_DOCUMENT;
|
||||
|
||||
public function authorize()
|
||||
{
|
||||
$contact = Contact::getContactIfLoggedIn();
|
||||
|
||||
if($contact && $contact->account->hasFeature(FEATURE_DOCUMENTS))
|
||||
return true;
|
||||
else
|
||||
return $this->user()->can('view', $this->entity());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
namespace App\Http\Requests;
|
||||
|
||||
use App\Libraries\HistoryUtils;
|
||||
use App\Models\Contact;
|
||||
use App\Models\EntityModel;
|
||||
use Input;
|
||||
use Utils;
|
||||
|
|
@ -33,12 +32,6 @@ class EntityRequest extends Request
|
|||
$publicId = $this->$field;
|
||||
}
|
||||
}
|
||||
if (! $publicId) {
|
||||
$field = $this->entityType;
|
||||
if (! empty($this->$field)) {
|
||||
$publicId = $this->$field;
|
||||
}
|
||||
}
|
||||
if (! $publicId) {
|
||||
$publicId = Input::get('public_id') ?: Input::get('id');
|
||||
}
|
||||
|
|
@ -47,21 +40,10 @@ class EntityRequest extends Request
|
|||
return null;
|
||||
}
|
||||
|
||||
//Support Client Portal Scopes
|
||||
$accountId = false;
|
||||
|
||||
if($this->user()->account_id)
|
||||
$accountId = $this->user()->account_id;
|
||||
elseif(Input::get('account_id'))
|
||||
$accountId = Input::get('account_id');
|
||||
elseif($contact = Contact::getContactIfLoggedIn())
|
||||
$accountId = $contact->account->id;
|
||||
|
||||
if (method_exists($class, 'trashed')) {
|
||||
$this->entity = $class::scope($publicId, $accountId)->withTrashed()->firstOrFail();
|
||||
$this->entity = $class::scope($publicId)->withTrashed()->firstOrFail();
|
||||
} else {
|
||||
$this->entity = $class::scope($publicId, $accountId)->firstOrFail();
|
||||
|
||||
$this->entity = $class::scope($publicId)->firstOrFail();
|
||||
}
|
||||
|
||||
return $this->entity;
|
||||
|
|
@ -77,10 +59,11 @@ class EntityRequest extends Request
|
|||
if ($this->entity()) {
|
||||
if ($this->user()->can('view', $this->entity())) {
|
||||
HistoryUtils::trackViewed($this->entity());
|
||||
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return $this->user()->can('createEntity', $this->entityType);
|
||||
return $this->user()->can('create', $this->entityType);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,73 +9,59 @@ class InvoiceRequest extends EntityRequest
|
|||
{
|
||||
protected $entityType = ENTITY_INVOICE;
|
||||
|
||||
/**
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
|
||||
$invoice = parent::entity();
|
||||
$entity = $invoice ? $invoice->subEntityType() : ENTITY_INVOICE;
|
||||
|
||||
switch($entity)
|
||||
{
|
||||
case ENTITY_INVOICE:
|
||||
$crossCloneEntity = ENTITY_QUOTE;
|
||||
break;
|
||||
case ENTITY_QUOTE:
|
||||
$crossCloneEntity = ENTITY_INVOICE;
|
||||
break;
|
||||
case ENTITY_RECURRING_INVOICE:
|
||||
$crossCloneEntity = ENTITY_RECURRING_QUOTE;
|
||||
break;
|
||||
case ENTITY_RECURRING_QUOTE:
|
||||
$crossCloneEntity = ENTITY_RECURRING_INVOICE;
|
||||
break;
|
||||
}
|
||||
if ($invoice && $invoice->isQuote())
|
||||
$standardOrRecurringInvoice = ENTITY_QUOTE;
|
||||
elseif($invoice && $invoice->is_recurring)
|
||||
$standardOrRecurringInvoice = ENTITY_RECURRING_INVOICE;
|
||||
else
|
||||
$standardOrRecurringInvoice = ENTITY_INVOICE;
|
||||
|
||||
if(request()->is('invoices/create*') && $this->user()->can('createEntity', ENTITY_INVOICE))
|
||||
if(request()->is('invoices/*/edit') && request()->isMethod('get') && $this->user()->can('edit', $invoice))
|
||||
return true;
|
||||
|
||||
if(request()->is('recurring_invoices/create*') && $this->user()->can('createEntity', ENTITY_INVOICE))
|
||||
if(request()->is('quotes/*/edit') && request()->isMethod('get') && $this->user()->can('edit', $invoice))
|
||||
return true;
|
||||
|
||||
if(request()->is('quotes/create*') && $this->user()->can('createEntity', ENTITY_QUOTE))
|
||||
if(request()->is('invoices/create*') && $this->user()->can('create', ENTITY_INVOICE))
|
||||
return true;
|
||||
|
||||
if(request()->is('recurring_quotes/create*') && $this->user()->can('createEntity', ENTITY_QUOTE))
|
||||
return true;
|
||||
if(request()->is('invoices/create*') && !$this->user()->can('create', ENTITY_INVOICE))
|
||||
return false;
|
||||
|
||||
if($invoice && $invoice->isType(INVOICE_TYPE_STANDARD) && request()->is('*invoices/*/edit') && request()->isMethod('put') && $this->user()->can('edit', $invoice))
|
||||
return true;
|
||||
if(request()->is('recurring_invoices/create') && !$this->user()->can('create', ENTITY_RECURRING_INVOICE))
|
||||
return false;
|
||||
|
||||
if($invoice && $invoice->isType(INVOICE_TYPE_QUOTE) && request()->is('*quotes/*/edit') && request()->isMethod('put') && $this->user()->can('edit', $invoice))
|
||||
return true;
|
||||
if(request()->is('quotes/create*') && !$this->user()->can('create', ENTITY_QUOTE))
|
||||
return false;
|
||||
|
||||
// allow cross clone quote to invoice
|
||||
if($invoice && $invoice->isType(INVOICE_TYPE_QUOTE) && request()->is('*invoices/*/clone') && request()->isMethod('get') && $this->user()->can('view', $invoice, $crossCloneEntity))
|
||||
return true;
|
||||
if(request()->is('invoices/*/edit') && request()->isMethod('put') && !$this->user()->can('edit', $standardOrRecurringInvoice))
|
||||
return false;
|
||||
|
||||
// allow cross clone invoice to quote
|
||||
if($invoice && $invoice->isType(INVOICE_TYPE_STANDARD) && request()->is('*quotes/*/clone') && request()->isMethod('get') && $this->user()->can('view', $invoice, $crossCloneEntity))
|
||||
return true;
|
||||
if(request()->is('quotes/*/edit') && request()->isMethod('put') && !$this->user()->can('edit', ENTITY_QUOTE))
|
||||
return false;
|
||||
|
||||
if($invoice && $invoice->isType(INVOICE_TYPE_STANDARD) && request()->is('*invoices/*') && request()->isMethod('get') && $this->user()->can('view', $invoice, $entity))
|
||||
return true;
|
||||
if(request()->is('invoices/*') && request()->isMethod('get') && !$this->user()->can('view', $standardOrRecurringInvoice))
|
||||
return false;
|
||||
|
||||
if($invoice && $invoice->isType(INVOICE_TYPE_QUOTE) && request()->is('*quotes/*') && request()->isMethod('get') && $this->user()->can('view', $invoice, $entity))
|
||||
return true;
|
||||
if(request()->is('quotes/*') && request()->isMethod('get') && !$this->user()->can('view', ENTITY_QUOTE))
|
||||
return false;
|
||||
|
||||
if ($invoice) {
|
||||
HistoryUtils::trackViewed($invoice);
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public function entity()
|
||||
{
|
||||
$invoice = parent::entity();
|
||||
|
|
|
|||
|
|
@ -2,20 +2,18 @@
|
|||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
use App\Models\Ticket;
|
||||
|
||||
class CreateTicketTemplateRequest extends Request
|
||||
class MigrationAuthRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('create', Ticket::class);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -23,16 +21,11 @@ class CreateTicketTemplateRequest extends Request
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
|
||||
public function rules()
|
||||
{
|
||||
|
||||
$rules = [
|
||||
'name' => 'required',
|
||||
'description' => 'required',
|
||||
return [
|
||||
'email' => 'required|email',
|
||||
'password' => 'required',
|
||||
];
|
||||
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
30
app/Http/Requests/MigrationCompaniesRequest.php
Normal file
30
app/Http/Requests/MigrationCompaniesRequest.php
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class MigrationCompaniesRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'companies' => 'required',
|
||||
];
|
||||
}
|
||||
}
|
||||
30
app/Http/Requests/MigrationEndpointRequest.php
Normal file
30
app/Http/Requests/MigrationEndpointRequest.php
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class MigrationEndpointRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'endpoint' => 'required|url',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -2,9 +2,15 @@
|
|||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
class UpdateClientPortalTicketRequest extends TicketRequest
|
||||
{
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class MigrationTypeRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
|
|
@ -18,6 +24,7 @@ class UpdateClientPortalTicketRequest extends TicketRequest
|
|||
public function rules()
|
||||
{
|
||||
return [
|
||||
'option' => 'required|in:0,1',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -31,9 +31,4 @@ class ProposalSnippetRequest extends EntityRequest
|
|||
|
||||
return $this->all();
|
||||
}
|
||||
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('view', ENTITY_PROPOSAL) || $this->user()->can('createEntity', ENTITY_PROPOSAL);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,22 +2,7 @@
|
|||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
/**
|
||||
* Class ProposalTemplateRequest
|
||||
* @package App\Http\Requests
|
||||
*/
|
||||
class ProposalTemplateRequest extends EntityRequest
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $entityType = ENTITY_PROPOSAL_TEMPLATE;
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('view', ENTITY_PROPOSAL) || $this->user()->can('createEntity', ENTITY_PROPOSAL);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,10 +31,4 @@ class QuoteRequest extends EntityRequest
|
|||
|
||||
return $invoice;
|
||||
}
|
||||
|
||||
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('createEntity', ENTITY_QUOTE);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,10 +41,6 @@ class SaveClientPortalSettings extends Request
|
|||
$input['client_view_css'] = HTMLUtils::sanitizeCSS($this->client_view_css);
|
||||
}
|
||||
|
||||
if ($this->client_view_js && Utils::isSelfHost()) {
|
||||
$input['client_view_js'] = HTMLUtils::sanitizeJS($this->client_view_js);
|
||||
}
|
||||
|
||||
if (Utils::isNinja()) {
|
||||
if ($this->custom_link == 'subdomain') {
|
||||
$subdomain = substr(strtolower($input['subdomain']), 0, MAX_SUBDOMAIN_LENGTH);
|
||||
|
|
|
|||
|
|
@ -1,51 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class SaveTicketSettings extends Request
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->is_admin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'support_email_local_part' =>
|
||||
Rule::unique('account_ticket_settings')->ignore($this->user()->account->account_ticket_settings->id),
|
||||
];
|
||||
}
|
||||
|
||||
public function sanitize()
|
||||
{
|
||||
$input = $this->all();
|
||||
|
||||
//ensure we
|
||||
$maxTicketNumber = Ticket::scope()->withTrashed()->max('ticket_number');
|
||||
|
||||
if($input['ticket_number_start'] <= $maxTicketNumber){
|
||||
|
||||
$input['ticket_number_start'] = $maxTicketNumber+1;
|
||||
|
||||
$this->replace($input);
|
||||
|
||||
return $this->all();
|
||||
}
|
||||
|
||||
return $input;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\TicketRelation;
|
||||
|
||||
class TicketAddEntityRequest extends EntityRequest
|
||||
{
|
||||
protected $entityType = ENTITY_TICKET;
|
||||
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('edit', Ticket::class);
|
||||
}
|
||||
|
||||
|
||||
public function addEntity()
|
||||
{
|
||||
$entityType = request()->entity;
|
||||
$linkEntity = request()->entity;
|
||||
|
||||
if(request()->entity == 'quote')
|
||||
$entityType = 'invoice';
|
||||
|
||||
$className = '\App\Models\\'.ucfirst($entityType);
|
||||
$entityModel = new $className();
|
||||
|
||||
$entityId = $entityModel::getPortalPrivateId(request()->entity_id, request()->account_id);
|
||||
|
||||
$tr = new TicketRelation();
|
||||
$tr->entity = $linkEntity;
|
||||
$tr->entity_id = $entityId;
|
||||
$tr->ticket_id = request()->ticket_id;
|
||||
$tr->save();
|
||||
|
||||
$str = self::buildEntityUrl($linkEntity, request()->entity_id, request()->account_id);
|
||||
$str .= ' <i style="margin-left:5px;width:12px;cursor:pointer" onclick="removeRelation('.$tr->id.')" class="fa fa-minus-circle redlink" title="Remove item"/>';
|
||||
|
||||
$tr->entity_url = $str;
|
||||
$tr->save();
|
||||
|
||||
return $tr;
|
||||
}
|
||||
|
||||
private static function buildEntityUrl($entityType, $publicId, $accountId) : string
|
||||
{
|
||||
|
||||
$linkEntity = $entityType;
|
||||
|
||||
if($entityType == 'quote')
|
||||
$entityType = 'invoice';
|
||||
|
||||
$className = '\App\Models\\'.ucfirst($entityType);
|
||||
$entityModel = new $className();
|
||||
$entity = $entityModel::scope($publicId, $accountId)->first();
|
||||
|
||||
return link_to("{$linkEntity}s/{$publicId}/edit", self::setLinkDescription($linkEntity, $entity), ['class' => ''])->toHtml();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static function setLinkDescription($entityType, $entity)
|
||||
{
|
||||
switch($entityType)
|
||||
{
|
||||
case 'quote':
|
||||
return trans('texts.quote'). ' ' .$entity->invoice_number;
|
||||
|
||||
case 'invoice':
|
||||
return trans('texts.invoice'). ' ' .$entity->invoice_number;
|
||||
|
||||
case 'task':
|
||||
return trans('texts.task'). ' ' .$entity->description;
|
||||
|
||||
case 'payment':
|
||||
return trans('texts.payment'). '('. trans('texts.invoice') . ' #'. $entity->invoice->invoice_number. ')';
|
||||
|
||||
case 'credit':
|
||||
return trans('texts.credit'). ' (' .$entity->client->getDisplayName(). ' ' .$entity->amount.')';
|
||||
|
||||
case 'expense':
|
||||
return strlen($entity->public_notes) ? trans('texts.expense'). ' ' .$entity->public_notes : trans('texts.expense'). ' ' .$entity->amount;
|
||||
|
||||
case 'project':
|
||||
return $entity->name;
|
||||
|
||||
default:
|
||||
return '';
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Ninja\Repositories\TicketRepository;
|
||||
use App\Ninja\Tickets\Inbound\InboundTicketFactory;
|
||||
use App\Ninja\Tickets\Inbound\InboundTicketService;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class TicketInboundRequest extends Request
|
||||
{
|
||||
public function entity()
|
||||
{
|
||||
$inboundTicketService = new InboundTicketService(new InboundTicketFactory(request()->getContent()), new TicketRepository());
|
||||
return $inboundTicketService->process();
|
||||
|
||||
}
|
||||
|
||||
public function rules()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
|
||||
class TicketMergeRequest extends EntityRequest
|
||||
{
|
||||
protected $entityType = ENTITY_TICKET;
|
||||
|
||||
|
||||
public function entity()
|
||||
{
|
||||
return parent::entity();
|
||||
}
|
||||
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'updated_ticket_id' => 'required',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
class TicketRemoveEntityRequest extends EntityRequest
|
||||
{
|
||||
protected $entityType = ENTITY_TICKET;
|
||||
|
||||
public function authorize()
|
||||
{
|
||||
return $this->user()->can('edit', Ticket::class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
class TicketRequest extends EntityRequest
|
||||
{
|
||||
protected $entityType = ENTITY_TICKET;
|
||||
|
||||
|
||||
public function entity()
|
||||
{
|
||||
|
||||
$ticket = parent::entity();
|
||||
|
||||
// eager load the documents
|
||||
if ($ticket && method_exists($ticket, 'documents') && ! $ticket->relationLoaded('documents'))
|
||||
$ticket->load('documents', 'relations');
|
||||
|
||||
return $ticket;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function authorize()
|
||||
{
|
||||
if(request()->is('tickets/create*') && $this->user()->can('createEntity', ENTITY_TICKET))
|
||||
return true;
|
||||
elseif (request()->is('tickets/*/edit') && $this->user()->can('view', $this->entity()))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Contact;
|
||||
|
||||
class UpdateDocumentRequest extends DocumentRequest
|
||||
{
|
||||
/**
|
||||
|
|
@ -13,14 +11,7 @@ class UpdateDocumentRequest extends DocumentRequest
|
|||
*/
|
||||
public function authorize()
|
||||
{
|
||||
|
||||
$contact = Contact::getContactIfLoggedIn();
|
||||
|
||||
if($contact && $contact->account->hasFeature(FEATURE_DOCUMENTS))
|
||||
return true;
|
||||
else
|
||||
return $this->entity() && $this->user()->can('edit', $this->entity());
|
||||
|
||||
return $this->entity() && $this->user()->can('edit', $this->entity());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,64 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Client;
|
||||
|
||||
class UpdateTicketRequest extends TicketRequest
|
||||
{
|
||||
protected $autoload = [
|
||||
ENTITY_CLIENT
|
||||
];
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->entity() && $this->user()->can('edit', $this->entity());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
|
||||
$data = $this->all();
|
||||
|
||||
$rules = [
|
||||
'client_public_id' => 'min:1|numeric',
|
||||
];
|
||||
|
||||
if($data['is_internal'] && $data['is_internal'] == false)
|
||||
$rules['client_public_id'] = 'min:1|numeric|required';
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
public function sanitize()
|
||||
{
|
||||
|
||||
$data = $this->all();
|
||||
|
||||
if(isset($data['client_public_id']) && $data['client_public_id'] > 0 && !isset($data['contact_key'])){
|
||||
$client = Client::scope($data['client_public_id'])->first();
|
||||
$contact = $client->getPrimaryContact();
|
||||
$data['contact_key'] = $contact->contact_key;
|
||||
}
|
||||
|
||||
if(isset($data['parent_ticket_id']) && $data['parent_ticket_id'] > 0)
|
||||
$data['parent_ticket_id'] = Ticket::getPrivateId($data['parent_ticket_id']);
|
||||
|
||||
if(isset($data['agent_id']) && $data['agent_id'] > 0)
|
||||
$data['user_id'] = $data['agent_id'];
|
||||
|
||||
$this->replace($data);
|
||||
|
||||
return $this->all();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\ViewComponents;
|
||||
|
||||
use Illuminate\Contracts\Support\Htmlable;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use App\Ninja\Repositories\ClientRepository;
|
||||
|
||||
class SimpleSelectComponent implements Htmlable
|
||||
{
|
||||
protected $entityType;
|
||||
protected $items;
|
||||
protected $itemLabel;
|
||||
protected $fieldLabel;
|
||||
protected $module;
|
||||
protected $secondaryItemLabel;
|
||||
protected $selectId;
|
||||
protected $defaultValue;
|
||||
|
||||
public function __construct($entityType, $items, $itemLabel, $fieldLabel, $defaultValue = null, $secondaryItemLabel = null, $module = null, $selectId = null) {
|
||||
$this->entityType = $entityType;
|
||||
$this->items = $items;
|
||||
$this->itemLabel = $itemLabel;
|
||||
$this->fieldLabel = $fieldLabel;
|
||||
$this->defaultValue = $defaultValue;
|
||||
$this->module = $module;
|
||||
$this->secondaryItemLabel = $secondaryItemLabel;
|
||||
|
||||
if ($selectId) {
|
||||
$this->selectId = $selectId;
|
||||
} else {
|
||||
$this->selectId = $fieldLabel . '_id';
|
||||
}
|
||||
}
|
||||
|
||||
public function toHtml()
|
||||
{
|
||||
return View::make('components.simple_select')->with([
|
||||
'entityType' => $this->entityType,
|
||||
'items' => $this->items,
|
||||
'itemLabel' => $this->itemLabel,
|
||||
'secondaryItemLabel' => $this->secondaryItemLabel,
|
||||
'fieldLabel' => mtrans($this->module, $this->fieldLabel),
|
||||
'selectId' => $this->selectId,
|
||||
'defaultValue' => $this->defaultValue,
|
||||
])->render();
|
||||
}
|
||||
}
|
||||
|
|
@ -105,7 +105,7 @@ class GenerateStatementData
|
|||
$payments = Payment::with('invoice', 'payment_type')
|
||||
->withArchived()
|
||||
->whereClientId($this->client->id)
|
||||
->excludeFailed()
|
||||
//->excludeFailed()
|
||||
->where('payment_date', '>=', $this->options['start_date'])
|
||||
->where('payment_date', '<=', $this->options['end_date']);
|
||||
|
||||
|
|
@ -151,7 +151,7 @@ class GenerateStatementData
|
|||
$item->product_key = $ageGroups['age_group_0'];
|
||||
$item->notes = $ageGroups['age_group_30'];
|
||||
$item->custom_value1 = $ageGroups['age_group_60'];
|
||||
$item->custom_value1 = $ageGroups['age_group_90'];
|
||||
$item->custom_value2 = $ageGroups['age_group_90'];
|
||||
$item->cost = $ageGroups['age_group_120'];
|
||||
$item->invoice_item_type_id = 4;
|
||||
$data->push($item);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Models\Invoice;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use App\Models\User;
|
||||
use App\Ninja\Mailers\UserMailer;
|
||||
use Barracuda\ArchiveStream\Archive;
|
||||
|
|
@ -13,13 +15,15 @@ use Barracuda\ArchiveStream\Archive;
|
|||
//class DownloadInvoices extends Job implements ShouldQueue
|
||||
class DownloadInvoices extends Job
|
||||
{
|
||||
//use InteractsWithQueue, SerializesModels;
|
||||
|
||||
/**
|
||||
* @var User
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* @var Invoice[]
|
||||
* @var array
|
||||
*/
|
||||
protected $invoices;
|
||||
|
||||
|
|
@ -38,7 +42,7 @@ class DownloadInvoices extends Job
|
|||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @param UserMailer $mailer
|
||||
* @param ContactMailer $mailer
|
||||
*/
|
||||
public function handle(UserMailer $userMailer)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -65,17 +65,7 @@ class ExportReportResults extends Job
|
|||
foreach ($totals as $currencyId => $each) {
|
||||
foreach ($each as $dimension => $val) {
|
||||
$tmp = [];
|
||||
|
||||
$currency = Utils::getFromCache($currencyId, 'currencies');
|
||||
if (!$currency) {
|
||||
$name = $currencyId;
|
||||
$account = $this->user->account->first();
|
||||
$currencyId = $account->currency_id;
|
||||
} else {
|
||||
$name = $currency->name;
|
||||
}
|
||||
|
||||
$tmp[] = $dimension ? $name . ' - ' . $dimension : $name;
|
||||
$tmp[] = Utils::getFromCache($currencyId, 'currencies')->name . (($dimension) ? ' - ' . $dimension : '');
|
||||
foreach ($val as $field => $value) {
|
||||
if ($field == 'duration') {
|
||||
$tmp[] = Utils::formatTime($value);
|
||||
|
|
|
|||
|
|
@ -10,12 +10,11 @@ use App\Jobs\Job;
|
|||
|
||||
class RunReport extends Job
|
||||
{
|
||||
public function __construct($user, $reportType, $config, $account, $isExport = false)
|
||||
public function __construct($user, $reportType, $config, $isExport = false)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->reportType = $reportType;
|
||||
$this->config = $config;
|
||||
$this->account = $account;
|
||||
$this->isExport = $isExport;
|
||||
}
|
||||
|
||||
|
|
@ -47,14 +46,6 @@ class RunReport extends Job
|
|||
$startDate = Carbon::now()->subMonth()->firstOfMonth()->toDateString();
|
||||
$endDate = Carbon::now()->subMonth()->lastOfMonth()->toDateString();
|
||||
break;
|
||||
case 'this_quarter':
|
||||
$startDate = Carbon::now()->firstOfQuarter()->toDateString();
|
||||
$endDate = Carbon::now()->lastOfQuarter()->toDateString();
|
||||
break;
|
||||
case 'last_quarter':
|
||||
$startDate = Carbon::now()->subMonth(3)->firstOfQuarter()->toDateString();
|
||||
$endDate = Carbon::now()->subMonth(3)->lastOfQuarter()->toDateString();
|
||||
break;
|
||||
case 'this_year':
|
||||
$startDate = Carbon::now()->firstOfYear()->toDateString();
|
||||
$endDate = Carbon::now()->lastOfYear()->toDateString();
|
||||
|
|
@ -72,7 +63,7 @@ class RunReport extends Job
|
|||
$endDate = $config['end_date'];
|
||||
}
|
||||
|
||||
$report = new $reportClass($startDate, $endDate, $isExport, $this->account, $config);
|
||||
$report = new $reportClass($startDate, $endDate, $isExport, $config);
|
||||
$report->run();
|
||||
|
||||
$params = [
|
||||
|
|
|
|||
|
|
@ -1,51 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use App\Ninja\Tickets\Actions\TicketOverdue;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
/**
|
||||
* Class SendOverdueTicketNotification.
|
||||
*/
|
||||
class SendOverdueTicketNotification extends Job implements ShouldQueue
|
||||
{
|
||||
use InteractsWithQueue, SerializesModels;
|
||||
|
||||
/**
|
||||
* @var Ticket
|
||||
*/
|
||||
protected $ticket;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
|
||||
* @param Ticket $ticket
|
||||
* @param mixed $type
|
||||
*/
|
||||
public function __construct(Ticket $ticket)
|
||||
{
|
||||
$this->ticket = $ticket;
|
||||
$this->server = config('database.default');
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @param TicketOverdue $ticketOverdue
|
||||
*/
|
||||
public function handle(TicketOverdue $ticketOverdue)
|
||||
{
|
||||
|
||||
$ticketOverdue->fire($this->ticket);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs\Ticket;
|
||||
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Auth;
|
||||
use App;
|
||||
use App\Jobs\Job;
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class TicketAction.
|
||||
*
|
||||
* Queues the processing of ticket actions's
|
||||
*/
|
||||
|
||||
class TicketAction extends Job implements ShouldQueue
|
||||
{
|
||||
use InteractsWithQueue, SerializesModels;
|
||||
|
||||
/**
|
||||
* @var Ticket_attributes
|
||||
*/
|
||||
protected $deltaAttributes;
|
||||
|
||||
/**
|
||||
* @var Ticket
|
||||
*/
|
||||
protected $originalTicket;
|
||||
|
||||
/**
|
||||
* @var Ticket
|
||||
*/
|
||||
protected $updatedTicket;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
protected $action;
|
||||
/**
|
||||
* TicketAction constructor.
|
||||
* @param array $deltaAttributes
|
||||
* @param array $originalTicket
|
||||
* @param $updatedTicket
|
||||
* @param $action
|
||||
*/
|
||||
public function __construct($deltaAttributes, $originalTicket, $updatedTicket, $action)
|
||||
{
|
||||
|
||||
$this->deltaAttributes = $deltaAttributes;
|
||||
$this->originalTicket = $originalTicket;
|
||||
$this->updatedTicket = $updatedTicket;
|
||||
$this->server = config('database.default');
|
||||
$this->action = $action;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* process action
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
|
||||
$ticketHandler = new App\Ninja\Tickets\Factory\TicketFactory($this->originalTicket, $this->deltaAttributes, $this->updatedTicket, $this->action);
|
||||
$ticketHandler->process();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs\Ticket;
|
||||
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Auth;
|
||||
use App;
|
||||
use App\Models\Ticket;
|
||||
use App\Ninja\Mailers\TicketMailer;
|
||||
use App\Jobs\Job;
|
||||
|
||||
/**
|
||||
* Class TicketSendNotificationEmail.
|
||||
*/
|
||||
|
||||
class TicketSendNotificationEmail extends Job implements ShouldQueue
|
||||
{
|
||||
use InteractsWithQueue, SerializesModels;
|
||||
|
||||
/**
|
||||
* @var Ticket
|
||||
*/
|
||||
protected $ticket;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $ticketData;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* TicketSendNotificationEmail constructor.
|
||||
* @param array $ticketData
|
||||
* @param Ticket $ticket
|
||||
*/
|
||||
public function __construct(array $ticketData, Ticket $ticket)
|
||||
{
|
||||
$this->ticket = $ticket;
|
||||
$this->ticketData = $ticketData;
|
||||
$this->server = config('database.default');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TicketMailer $mailer
|
||||
*/
|
||||
public function handle(TicketMailer $mailer)
|
||||
{
|
||||
//harvest list of contacts to email;
|
||||
$data['bccEmail'] = $this->ticket->getCCs();
|
||||
$data['text'] = $this->ticketData['comment'];
|
||||
$data['replyTo'] = 'ticket-123@support.invoiceninja.com';
|
||||
//$toEmail = strtolower($this->ticket->contact->email); //todo
|
||||
$toEmail = 'david@romulus.com.au';
|
||||
$fromEmail = $this->ticket->getTicketFromEmail();
|
||||
$fromName = $this->ticket->getTicketFromName();
|
||||
$subject = $this->ticket->subject;
|
||||
$view = 'ticket';
|
||||
|
||||
$mailer->sendTo($toEmail, $fromEmail, $fromName, $subject, $view, $data);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -50,14 +50,6 @@ class HTMLUtils
|
|||
return $purifier->purify($html);
|
||||
}
|
||||
|
||||
public static function sanitizeJS($js) {
|
||||
if(!stripos($js, '<script')) {
|
||||
$js = "<script type=\"text/javascript\">{$js}</script>";
|
||||
}
|
||||
|
||||
return $js;
|
||||
}
|
||||
|
||||
public static function previousUrl($fallback)
|
||||
{
|
||||
$previous = url()->previous();
|
||||
|
|
|
|||
|
|
@ -1,99 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Libraries;
|
||||
|
||||
class MoneyUtilsInvalidArgumentException extends \Exception {};
|
||||
|
||||
/**
|
||||
* Class MoneyUtils
|
||||
* @package App\Libraries
|
||||
*/
|
||||
class MoneyUtils
|
||||
{
|
||||
/**
|
||||
* @var bool this is to prevent repeating initialization by loadCurrencies method
|
||||
*/
|
||||
protected static $initialized;
|
||||
|
||||
/**
|
||||
* @var array holds currency code => exchange rate
|
||||
*/
|
||||
protected static $rates = [];
|
||||
|
||||
/**
|
||||
* @var string holds base currency code
|
||||
*/
|
||||
protected static $baseCurency;
|
||||
|
||||
/**
|
||||
* Loads currencies from cache, make $rates array and $baseCurrency
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected static function loadCurrencies()
|
||||
{
|
||||
if(self::$initialized) return;
|
||||
|
||||
$currencies = cache('currencies');
|
||||
|
||||
foreach ($currencies as $currency)
|
||||
{
|
||||
if(!self::$baseCurency && $currency->exchange_rate === 1.0000)
|
||||
{
|
||||
self::$baseCurency = $currency->code;
|
||||
}
|
||||
|
||||
self::$rates[$currency->code] = $currency->exchange_rate;
|
||||
}
|
||||
|
||||
self::$initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Currency conversion
|
||||
*
|
||||
* @param $val value to convert
|
||||
* @param $from currency to convert from
|
||||
* @param $to currency to convert to
|
||||
* @throws \Exception
|
||||
* @throws MoneyUtilsInvalidArgumentException
|
||||
*/
|
||||
public static function convert($val, $from, $to)
|
||||
{
|
||||
return $val * self::getRate($from, $to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get exchange rate for `to` currency based on `from` currency
|
||||
*
|
||||
* @param $from
|
||||
* @param $to
|
||||
* @return float|int|mixed
|
||||
* @throws \Exception
|
||||
* @throws MoneyUtilsInvalidArgumentException
|
||||
*/
|
||||
public static function getRate($from, $to)
|
||||
{
|
||||
self::loadCurrencies();
|
||||
|
||||
if(!array_key_exists($from, self::$rates) || !array_key_exists($to, self::$rates))
|
||||
{
|
||||
throw new MoneyUtilsInvalidArgumentException('Invalid currency code $from or $to');
|
||||
}
|
||||
|
||||
// if `from` currency is same as `base` currency, return the basic exchange rate for the `to` currency
|
||||
if($from === self::$baseCurency)
|
||||
{
|
||||
return self::$rates[$to];
|
||||
}
|
||||
|
||||
// if `to` currency is same as `base` currency, return the basic inverse of the `from` currency
|
||||
if($to === self::$baseCurency)
|
||||
{
|
||||
return 1 / self::$rates[$from];
|
||||
}
|
||||
|
||||
// Otherwise, return the `to` rate multiplied by the inverse of the `from` rate to get the
|
||||
// relative exchange rate between the two currencies
|
||||
return self::$rates[$to] * (1 / self::$rates[$from]);
|
||||
}
|
||||
}
|
||||
|
|
@ -18,12 +18,9 @@ use Session;
|
|||
use stdClass;
|
||||
use View;
|
||||
use WePay;
|
||||
use Nwidart\Modules\Facades\Module;
|
||||
|
||||
class Utils
|
||||
{
|
||||
protected static $cacheValues = [];
|
||||
|
||||
private static $weekdayNames = [
|
||||
'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday',
|
||||
];
|
||||
|
|
@ -365,14 +362,7 @@ class Utils
|
|||
if (substr($field, 0, 1) == '-') {
|
||||
$data[] = substr($field, 1);
|
||||
} elseif ($module) {
|
||||
if(strpos($field, '::') >= 1) {
|
||||
$customField = explode('::', $field);
|
||||
if(count($customField) == 2) {
|
||||
$data[] = trans("texts.$customField[0]", [ 'VALUE' => $customField[1]], 'en');
|
||||
}
|
||||
} else {
|
||||
$data[] = mtrans($module, $field);
|
||||
}
|
||||
$data[] = mtrans($module, $field);
|
||||
} else {
|
||||
$data[] = trans("texts.$field");
|
||||
}
|
||||
|
|
@ -557,9 +547,6 @@ class Utils
|
|||
|
||||
public static function getFromCache($id, $type)
|
||||
{
|
||||
if (!empty(static::$cacheValues[$type]) && !empty(static::$cacheValues[$type][$id])) {
|
||||
return static::$cacheValues[$type][$id];
|
||||
}
|
||||
$cache = Cache::get($type);
|
||||
|
||||
if (! $cache) {
|
||||
|
|
@ -572,11 +559,7 @@ class Utils
|
|||
return $item->id == $id;
|
||||
});
|
||||
|
||||
$res = $data->first();
|
||||
if (!empty($res)) {
|
||||
static::$cacheValues[$type][$id] = $res;
|
||||
}
|
||||
return $res;
|
||||
return $data->first();
|
||||
}
|
||||
|
||||
public static function formatNumber($value, $currencyId = false, $precision = 0)
|
||||
|
|
@ -664,10 +647,6 @@ class Utils
|
|||
return 'proposal_categories';
|
||||
} elseif ($type === ENTITY_TASK_STATUS) {
|
||||
return 'task_statuses';
|
||||
} elseif ($type === ENTITY_TICKET_STATUS) {
|
||||
return 'ticket_statuses';
|
||||
} elseif ($type === ENTITY_TICKET_CATEGORY) {
|
||||
return 'ticket_categories';
|
||||
} else {
|
||||
return $type . 's';
|
||||
}
|
||||
|
|
@ -761,10 +740,9 @@ class Utils
|
|||
}
|
||||
|
||||
$timestamp = $dateTime->getTimestamp();
|
||||
$timezone = Session::get(SESSION_TIMEZONE, DEFAULT_TIMEZONE);
|
||||
$format = Session::get(SESSION_DATE_FORMAT, DEFAULT_DATE_FORMAT);
|
||||
|
||||
return self::timestampToString($timestamp, $timezone, $format);
|
||||
return self::timestampToString($timestamp, false, $format);
|
||||
}
|
||||
|
||||
public static function timestampToString($timestamp, $timezone, $format)
|
||||
|
|
@ -799,22 +777,6 @@ class Utils
|
|||
}
|
||||
}
|
||||
|
||||
public static function toSqlDateTime($date, $formatResult = true)
|
||||
{
|
||||
if (! $date) {
|
||||
return;
|
||||
}
|
||||
|
||||
$format = Session::get(SESSION_DATE_FORMAT, DEFAULT_DATE_FORMAT);
|
||||
$dateTime = DateTime::createFromFormat($format, $date);
|
||||
|
||||
if (! $dateTime) {
|
||||
return $date;
|
||||
} else {
|
||||
return $formatResult ? $dateTime->format('Y-m-d H:i:s') : $dateTime;
|
||||
}
|
||||
}
|
||||
|
||||
public static function fromSqlDate($date, $formatResult = true)
|
||||
{
|
||||
if (! $date || $date == '0000-00-00') {
|
||||
|
|
@ -874,8 +836,7 @@ class Utils
|
|||
return '';
|
||||
}
|
||||
|
||||
$variables = ['MONTH', 'QUARTER', 'YEAR', 'DATE_MONTH', 'DATE_YEAR'];
|
||||
$yearOverlap = 0;
|
||||
$variables = ['MONTH', 'QUARTER', 'YEAR'];
|
||||
for ($i = 0; $i < count($variables); $i++) {
|
||||
$variable = $variables[$i];
|
||||
$regExp = '/:'.$variable.'[+-]?[\d]*/';
|
||||
|
|
@ -897,9 +858,6 @@ class Utils
|
|||
$offset = intval($minArray[1]) * -1;
|
||||
}
|
||||
|
||||
$yearOverlap += self::getDateYearOverlap($variable, $offset);
|
||||
if($variable === 'YEAR') $offset += $yearOverlap;
|
||||
|
||||
$locale = $client && $client->language_id ? $client->language->locale : null;
|
||||
$val = self::getDatePart($variable, $offset, $locale);
|
||||
$str = str_replace($match, $val, $str);
|
||||
|
|
@ -918,54 +876,9 @@ class Utils
|
|||
return self::getQuarter($offset);
|
||||
} elseif ($part == 'YEAR') {
|
||||
return self::getYear($offset);
|
||||
} elseif ($part == 'DATE_MONTH') {
|
||||
return self::getDateMonth($offset, $locale);
|
||||
} elseif ($part == 'DATE_YEAR') {
|
||||
return self::getDateYear($offset);
|
||||
}
|
||||
}
|
||||
|
||||
private static function getDateYearOverlap(string $part, int $offset): int
|
||||
{
|
||||
$offset = intval($offset);
|
||||
|
||||
switch ($part) {
|
||||
case 'MONTH':
|
||||
return self::getMonthYearOverlap($offset);
|
||||
case 'QUARTER':
|
||||
return self::getQuarterYearOverlap($offset);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function getDateMonth($offset, $locale)
|
||||
{
|
||||
$timestamp = time();
|
||||
$res = $timestamp + ($offset * 24 * 60 * 60);
|
||||
|
||||
$months = static::$months;
|
||||
$month = intval(date('n', $res)) - 1;
|
||||
|
||||
$month = $month % 12;
|
||||
|
||||
if ($month < 0) {
|
||||
$month += 12;
|
||||
}
|
||||
|
||||
return trans('texts.' . $months[$month], [], $locale);
|
||||
}
|
||||
|
||||
public static function getDateYear($offset)
|
||||
{
|
||||
$timestamp = time();
|
||||
$res = $timestamp + ($offset * 24 * 60 * 60);
|
||||
|
||||
$year = intval(date('Y', $res));
|
||||
|
||||
return $year;
|
||||
}
|
||||
|
||||
public static function getMonthOptions()
|
||||
{
|
||||
$months = [];
|
||||
|
|
@ -1007,34 +920,6 @@ class Utils
|
|||
return 'Q'.$quarter;
|
||||
}
|
||||
|
||||
private static function getMonthYearOverlap(int $offset): int
|
||||
{
|
||||
$month = intval(date('n')) - 1;
|
||||
|
||||
$month += $offset;
|
||||
|
||||
if($month < 0){
|
||||
$month += 1;
|
||||
return (((abs($month) / 12 % 12) + 1) * -1);
|
||||
}
|
||||
|
||||
return ($month / 12 % 12);
|
||||
}
|
||||
|
||||
private static function getQuarterYearOverlap(int $offset): int
|
||||
{
|
||||
$month = intval(date('n')) - 1;
|
||||
$quarter = floor(($month + 3) / 3);
|
||||
$quarter += $offset - 1;
|
||||
|
||||
if($quarter < 0){
|
||||
$quarter += 1;
|
||||
return (((abs($quarter) / 4 % 4) + 1) * -1);
|
||||
}
|
||||
|
||||
return ($quarter / 4 % 4);
|
||||
}
|
||||
|
||||
private static function getYear($offset)
|
||||
{
|
||||
$year = intval(date('Y'));
|
||||
|
|
@ -1375,7 +1260,6 @@ class Utils
|
|||
'invoice_id',
|
||||
'credit_id',
|
||||
'invitation_id',
|
||||
'ticket_id',
|
||||
];
|
||||
|
||||
$fields1 = $entity1->getAttributes();
|
||||
|
|
@ -1630,66 +1514,4 @@ class Utils
|
|||
);
|
||||
return strtr($s, $replace);
|
||||
}
|
||||
|
||||
|
||||
public static function hasModuleSettings() {
|
||||
$module = Module::toCollection()->first(function($module) {
|
||||
return View::exists($module->getLowerName() . '::settings');
|
||||
});
|
||||
|
||||
return $module ? true : false;
|
||||
}
|
||||
|
||||
public static function getModulesWithSettings() {
|
||||
$modules = Module::toCollection()->filter(function($module) {
|
||||
return View::exists($module->getLowerName() . '::settings');
|
||||
});
|
||||
|
||||
return $modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array of file sizes, using a MAX of the php.ini variables upload_max_filesize and post_max_size
|
||||
* and iterating down by / 2 until a min size of 100kB
|
||||
*/
|
||||
public function getMaxFileUploadSizes()
|
||||
{
|
||||
$maxUploadSize = $this->fileUploadMaxSize();
|
||||
|
||||
$selectArray = [];
|
||||
|
||||
while($maxUploadSize > 100) {
|
||||
array_push($selectArray, [$maxUploadSize => $maxUploadSize]);
|
||||
$maxUploadSize = $maxUploadSize / 2;
|
||||
}
|
||||
|
||||
return array_reverse($selectArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns a file size limit in kilobytes based on the PHP upload_max_filesize and post_max_size
|
||||
*/
|
||||
public function fileUploadMaxSize() {
|
||||
|
||||
return min($this->parse_size(ini_get('post_max_size')), $this->parse_size(ini_get('upload_max_filesize')));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $size
|
||||
* @return float in kilobytes to match laravel file size validator
|
||||
*/
|
||||
private function parse_size($size) {
|
||||
$unit = preg_replace('/[^bkmgtpezy]/i', '', $size); // Remove the non-unit characters from the size.
|
||||
$size = preg_replace('/[^0-9\.]/', '', $size); // Remove the non-numeric characters from the size.
|
||||
if ($unit) {
|
||||
// Find the position of the unit in the ordered string which is the power of magnitude to multiply a kilobyte by.
|
||||
return round($size * pow(1024, stripos('bkmgtpezy', $unit[0])))/1024;
|
||||
}
|
||||
else {
|
||||
return round($size)/1024;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue