Compare commits
342 Commits
renamed-us
...
form-row-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
750c376725 | ||
|
|
08630d948f | ||
|
|
dc6ee342c5 | ||
|
|
eea1922841 | ||
|
|
57824848e9 | ||
|
|
235dcbc7d9 | ||
|
|
f0561475cc | ||
|
|
3b4c51bab6 | ||
|
|
150c205615 | ||
|
|
cde22977b0 | ||
|
|
1c09657631 | ||
|
|
02a4268180 | ||
|
|
f8362f4a45 | ||
|
|
682c1a8fa7 | ||
|
|
3863e82dcc | ||
|
|
b766f6e2b5 | ||
|
|
a3bad98096 | ||
|
|
33e7425dee | ||
|
|
2554b50b38 | ||
|
|
433a3e11fd | ||
|
|
c3efdd0c8d | ||
|
|
d2e3a13043 | ||
|
|
c4923fa971 | ||
|
|
253026de5d | ||
|
|
a59914e9f9 | ||
|
|
671e79f01b | ||
|
|
5c716c3f24 | ||
|
|
e138c9307e | ||
|
|
7c0c3b2bb8 | ||
|
|
514711ddbb | ||
|
|
9023eda66f | ||
|
|
8ce3001ef9 | ||
|
|
25ce63f00b | ||
|
|
2462bc05b3 | ||
|
|
c3748da0b1 | ||
|
|
90c242a441 | ||
|
|
52239a88b5 | ||
|
|
7a3596c86d | ||
|
|
ac8a9e38f0 | ||
|
|
5c08f3a27e | ||
|
|
5216dd75bf | ||
|
|
b8b45d2d81 | ||
|
|
4b2b2cb68e | ||
|
|
be4ace293e | ||
|
|
764b363bbc | ||
|
|
9da9166442 | ||
|
|
8ea339f0ef | ||
|
|
89b36ba63f | ||
|
|
1d3dfa1fa4 | ||
|
|
ca567eec8a | ||
|
|
41da31c379 | ||
|
|
e81f63f46b | ||
|
|
ade03e4827 | ||
|
|
33a4c88c3a | ||
|
|
1f79776b8f | ||
|
|
11e5f851f0 | ||
|
|
4ca1db8a1b | ||
|
|
14b829aa30 | ||
|
|
384652b3df | ||
|
|
9db65c6ae9 | ||
|
|
1346e33e99 | ||
|
|
ab9cc447aa | ||
|
|
fe9e0444b4 | ||
|
|
a18957dbe9 | ||
|
|
13d5b724ee | ||
|
|
c7d8203da9 | ||
|
|
96b5c1d8e1 | ||
|
|
882ee80424 | ||
|
|
e977771fe4 | ||
|
|
4339e4552e | ||
|
|
b54d222943 | ||
|
|
e4e613550a | ||
|
|
d1207444db | ||
|
|
0bad75b263 | ||
|
|
74b98083e2 | ||
|
|
9034b5ec11 | ||
|
|
927f557672 | ||
|
|
86fb089901 | ||
|
|
630ea05e17 | ||
|
|
7df5196083 | ||
|
|
01f7b5d709 | ||
|
|
ec47ee3573 | ||
|
|
7062962cc8 | ||
|
|
fde447846a | ||
|
|
319cb1bd1e | ||
|
|
58cda5ae6d | ||
|
|
251a3db880 | ||
|
|
30b6dcd767 | ||
|
|
05f6622912 | ||
|
|
36183ac19d | ||
|
|
f6a823e0a8 | ||
|
|
312353551d | ||
|
|
fd5c9cee38 | ||
|
|
84bf71802c | ||
|
|
35739c2eef | ||
|
|
1914a71623 | ||
|
|
dcc53886d9 | ||
|
|
21ef87ef09 | ||
|
|
b67f808da9 | ||
|
|
ad69447b53 | ||
|
|
b4614df88c | ||
|
|
7171247cdc | ||
|
|
6d0084f108 | ||
|
|
29359f42ae | ||
|
|
cf875bf872 | ||
|
|
13c0d335d3 | ||
|
|
ceb33409b5 | ||
|
|
83597d4a8b | ||
|
|
81eefc5448 | ||
|
|
082bc3ece4 | ||
|
|
b2406b61fb | ||
|
|
15698d7694 | ||
|
|
990cd82f97 | ||
|
|
c87829b3e8 | ||
|
|
6799c41d65 | ||
|
|
80c059be58 | ||
|
|
aa3f896538 | ||
|
|
d8c17a8a5e | ||
|
|
850939367c | ||
|
|
bf4fef9bf7 | ||
|
|
d5175961a4 | ||
|
|
e7e1d6a232 | ||
|
|
712345f3a0 | ||
|
|
54c9bc3dcb | ||
|
|
e796c0da4a | ||
|
|
cf8ff0f43e | ||
|
|
e67ce23a7c | ||
|
|
a66bb95a81 | ||
|
|
c66fa33b2e | ||
|
|
56eebb9db4 | ||
|
|
d9773f107e | ||
|
|
e09112f46a | ||
|
|
50a17a82b6 | ||
|
|
7eb032d646 | ||
|
|
e065f22f8e | ||
|
|
c1b4ba1f85 | ||
|
|
eeaec471f0 | ||
|
|
0d3c8678d8 | ||
|
|
bbddf5f95b | ||
|
|
3b8c8b3af9 | ||
|
|
84753aa13f | ||
|
|
90b84451d8 | ||
|
|
54c8ae41cc | ||
|
|
7d32b1a724 | ||
|
|
69ffd63ca6 | ||
|
|
4857c19eb6 | ||
|
|
d535e23da0 | ||
|
|
30e02544ab | ||
|
|
ee53925bd2 | ||
|
|
40495b8a17 | ||
|
|
6bc9a82a7a | ||
|
|
6504ee37bd | ||
|
|
082bff2fa8 | ||
|
|
ab7bd86336 | ||
|
|
eada0b0bb5 | ||
|
|
f221f9f22a | ||
|
|
6731e44a0d | ||
|
|
acc37045e4 | ||
|
|
a7c5899c16 | ||
|
|
80b02635a9 | ||
|
|
f90de5ec67 | ||
|
|
9a3e046530 | ||
|
|
7f56e461fe | ||
|
|
1da37e0d38 | ||
|
|
0004d4936c | ||
|
|
7a6fdc4e0a | ||
|
|
2eb727bd0c | ||
|
|
57af507170 | ||
|
|
e37f87465c | ||
|
|
324070f345 | ||
|
|
e1aa843b6d | ||
|
|
e652a7fd61 | ||
|
|
2397bfbad0 | ||
|
|
7e2bc8e452 | ||
|
|
00e8fd0483 | ||
|
|
6d8bf2c665 | ||
|
|
72466f1aab | ||
|
|
6901deccbf | ||
|
|
5a9c906eb9 | ||
|
|
b95b60b49e | ||
|
|
14408ef18f | ||
|
|
6b87c90e02 | ||
|
|
2b4d5222eb | ||
|
|
9604ecebad | ||
|
|
0d67970a45 | ||
|
|
913b9f0c40 | ||
|
|
610a5745f0 | ||
|
|
dff12324c6 | ||
|
|
f340390fc8 | ||
|
|
be81e74921 | ||
|
|
2bee8729e4 | ||
|
|
5d03038734 | ||
|
|
75b11de0f4 | ||
|
|
c5bede8594 | ||
|
|
cd9ea6ae3b | ||
|
|
113b762ec7 | ||
|
|
78704d8b85 | ||
|
|
1109db76fe | ||
|
|
b1b390febf | ||
|
|
be451fa0c0 | ||
|
|
1fa553c785 | ||
|
|
905f61371d | ||
|
|
7da5210a01 | ||
|
|
18172d3896 | ||
|
|
c28e78b9e2 | ||
|
|
e7827a3847 | ||
|
|
039564e74c | ||
|
|
e164595a0f | ||
|
|
d29e09a3ff | ||
|
|
db9f85e9da | ||
|
|
27022954b1 | ||
|
|
30362c924f | ||
|
|
bf63b15b46 | ||
|
|
19aea4bd6c | ||
|
|
090890e9c6 | ||
|
|
605022a9e3 | ||
|
|
b06c58fe7b | ||
|
|
f5c8b3eb04 | ||
|
|
739980aa09 | ||
|
|
afde5943e3 | ||
|
|
32300cb42c | ||
|
|
de3b1697c8 | ||
|
|
a18fb10b5a | ||
|
|
52140dbe06 | ||
|
|
db5bb1928e | ||
|
|
65b66beb07 | ||
|
|
c83504b4e7 | ||
|
|
cd2e7ee31d | ||
|
|
c3a0a0415a | ||
|
|
709f4672b7 | ||
|
|
e6c030b050 | ||
|
|
7bd3a791a1 | ||
|
|
b9cfc03b4f | ||
|
|
131327a64d | ||
|
|
77d002a158 | ||
|
|
94699893ac | ||
|
|
9f81989bdd | ||
|
|
15abe36c53 | ||
|
|
3094e007ee | ||
|
|
eb259aee22 | ||
|
|
c05c8defb9 | ||
|
|
bf5668a42e | ||
|
|
ec310bc8fb | ||
|
|
db477421b2 | ||
|
|
30a9496cf5 | ||
|
|
6cefa0d0b3 | ||
|
|
9284984265 | ||
|
|
53b96168a9 | ||
|
|
eadce51f10 | ||
|
|
b3c583b6dc | ||
|
|
28abeab31d | ||
|
|
12a649ec4b | ||
|
|
35b79e4d14 | ||
|
|
751dad7f2e | ||
|
|
b08d86220a | ||
|
|
3a27ecc475 | ||
|
|
da6fab5d43 | ||
|
|
ca95b29cd6 | ||
|
|
c5c68e9dd5 | ||
|
|
44fbde26fa | ||
|
|
6e2bcd6aa9 | ||
|
|
9c0202e5ce | ||
|
|
39ef353073 | ||
|
|
7b5d90dd81 | ||
|
|
d1129081df | ||
|
|
315a812df5 | ||
|
|
cfc979acf0 | ||
|
|
d7407d70a3 | ||
|
|
8ccd2e97a8 | ||
|
|
988204619f | ||
|
|
4298aad008 | ||
|
|
823c67400d | ||
|
|
3160d1064d | ||
|
|
918426a2fa | ||
|
|
c076b37c9b | ||
|
|
7c58bfa282 | ||
|
|
0caaba156d | ||
|
|
c22575812d | ||
|
|
0ede4da816 | ||
|
|
98e23ff92e | ||
|
|
c7bdad649a | ||
|
|
18c2508d2f | ||
|
|
4dcfd8b353 | ||
|
|
726116574d | ||
|
|
27f02014ca | ||
|
|
f80f1acaa7 | ||
|
|
39d5ffeceb | ||
|
|
48ba7eed3e | ||
|
|
35b358d336 | ||
|
|
ae109be631 | ||
|
|
3f7ed73395 | ||
|
|
9caa240fdb | ||
|
|
3ffb73a516 | ||
|
|
cc1132be87 | ||
|
|
1c31f126ef | ||
|
|
d8eaf2676f | ||
|
|
3101212c49 | ||
|
|
3f0ac103a1 | ||
|
|
59bd6ca360 | ||
|
|
22fe9a786e | ||
|
|
d2ee8de9ac | ||
|
|
03d3fb6a5f | ||
|
|
553ab8851a | ||
|
|
2b8ea9a233 | ||
|
|
b0067fee51 | ||
|
|
732c3dae89 | ||
|
|
d45bd67cae | ||
|
|
9200de5032 | ||
|
|
3fbbff5a47 | ||
|
|
c22efc2c3d | ||
|
|
8c0281bf70 | ||
|
|
720a4bc4a2 | ||
|
|
7fd93645b3 | ||
|
|
fcbfbca6d0 | ||
|
|
f2bca9491c | ||
|
|
b48f309ab6 | ||
|
|
0b1be3e63b | ||
|
|
8c129c10af | ||
|
|
63ce2a14fe | ||
|
|
f435ebb110 | ||
|
|
843f001bf6 | ||
|
|
0d28165c04 | ||
|
|
ee31bfbcd4 | ||
|
|
1c67d6802d | ||
|
|
5da8c86ec7 | ||
|
|
10a2d59ec1 | ||
|
|
34e8360b10 | ||
|
|
ca259ee4c3 | ||
|
|
2143952a1e | ||
|
|
6bab6e7151 | ||
|
|
d217c2e295 | ||
|
|
52bf0faaa5 | ||
|
|
3f3f2bfc61 | ||
|
|
f050864fb4 | ||
|
|
db11fc35f4 | ||
|
|
f47a2b10c0 | ||
|
|
344b4e7d60 | ||
|
|
7a23372489 | ||
|
|
9da15a8e58 | ||
|
|
50e0e4a07b | ||
|
|
5e1562ae4c | ||
|
|
8a0ed49623 |
@@ -3206,7 +3206,8 @@
|
|||||||
"avatar_url": "https://avatars.githubusercontent.com/u/3755203?v=4",
|
"avatar_url": "https://avatars.githubusercontent.com/u/3755203?v=4",
|
||||||
"profile": "https://github.com/swift2512",
|
"profile": "https://github.com/swift2512",
|
||||||
"contributions": [
|
"contributions": [
|
||||||
"bug"
|
"bug",
|
||||||
|
"code"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
137
.github/ISSUE_TEMPLATE/Bug-Report.yml
vendored
Normal file
137
.github/ISSUE_TEMPLATE/Bug-Report.yml
vendored
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
name: Bug Report
|
||||||
|
description: File a bug report.
|
||||||
|
title: "[Bug]: "
|
||||||
|
projects: ["grokability/snipe-it"]
|
||||||
|
type: bug
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Thanks for taking the time to fill out this bug report! Most issues are documented in the [Snipe-IT repository's issues](https://github.com/grokability/snipe-it/issues) or in the official [Common Issues section of the Documentation](https://snipe-it.readme.io/docs/common-issues#/) and are due to the following:
|
||||||
|
|
||||||
|
- `.env` misconfiguration
|
||||||
|
- [Server Permissions](https://snipe-it.readme.io/docs/debugging-permissions#/)
|
||||||
|
- [Database Migrations](https://snipe-it.readme.io/docs/database-issues#run-migrations)
|
||||||
|
|
||||||
|
Please make sure you've checked these resources before submitting a new issue. If you find an existing issue, please add your context to it instead of opening a new issue. If your issue is more of a question, consider [opening a new discussion](https://github.com/grokability/snipe-it/discussions) or [pop by our Discord](https://discord.gg/yZFtShAcKk) instead of creating an issue.
|
||||||
|
|
||||||
|
**Please write your bug report in English.** You can use tools like [DeepL](https://www.deepl.com) or [Google Translate](https://translate.google.com/) to translate if necessary.
|
||||||
|
|
||||||
|
**If you choose to upload screenshots or videos (which we always encourage), please make sure they do not contain any sensitive information.**
|
||||||
|
- type: input
|
||||||
|
id: version
|
||||||
|
attributes:
|
||||||
|
label: Snipe-IT Version
|
||||||
|
description: What version of Snipe-IT are you seeing this issue on? You can find the version number in the footer of any page in Snipe-IT.
|
||||||
|
placeholder: ex. v8.3.1 - build 19577 (master)
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: db-version
|
||||||
|
attributes:
|
||||||
|
label: MySQL/MariaDB version
|
||||||
|
description: What database are you using, and what version?
|
||||||
|
placeholder: ex. MySQL 5.7
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: install-method
|
||||||
|
attributes:
|
||||||
|
label: How did you install Snipe-IT?
|
||||||
|
options:
|
||||||
|
- Git install
|
||||||
|
- Manual install (downloading zip/tar.gz)
|
||||||
|
- Docker
|
||||||
|
- install.sh
|
||||||
|
- Hosted by Grokability
|
||||||
|
- Other
|
||||||
|
- Not sure
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: what-happened
|
||||||
|
attributes:
|
||||||
|
label: What happened?
|
||||||
|
description: Also tell us, what did you expect to happen?
|
||||||
|
placeholder: Tell us what you see! (Be nice!)
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: browsers
|
||||||
|
attributes:
|
||||||
|
label: What browsers are you seeing the problem on?
|
||||||
|
multiple: true
|
||||||
|
options:
|
||||||
|
- Firefox
|
||||||
|
- Chrome
|
||||||
|
- Safari
|
||||||
|
- Microsoft Edge
|
||||||
|
- Other
|
||||||
|
- type: dropdown
|
||||||
|
id: on-demo
|
||||||
|
attributes:
|
||||||
|
label: Can you reproduce this on the public demo?
|
||||||
|
description: You can check this at https://demo.snipeitapp.com.
|
||||||
|
options:
|
||||||
|
- 'Yes'
|
||||||
|
- 'No'
|
||||||
|
- N/A
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: fmcs
|
||||||
|
attributes:
|
||||||
|
label: Do you have full multiple company support enabled?
|
||||||
|
description: You can check this in your Snipe-IT installation at `Admin Settings > General Settings > Scoping`.
|
||||||
|
options:
|
||||||
|
- 'Yes'
|
||||||
|
- 'No'
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: fmcs-location
|
||||||
|
attributes:
|
||||||
|
label: If you have full multiple company support enabled, do you have location scoping to company enabled?
|
||||||
|
description: You can check this in your Snipe-IT installation at `Admin Settings > General Settings > Scoping`.
|
||||||
|
options:
|
||||||
|
- 'Yes'
|
||||||
|
- 'No'
|
||||||
|
- I do not have full multiple company support enabled
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: server-logs
|
||||||
|
attributes:
|
||||||
|
label: Application log output
|
||||||
|
description: Please copy and paste any relevant log output from `storage/logs/laravel.log`. This will be automatically formatted into code, so no need for backticks.
|
||||||
|
render: shell
|
||||||
|
- type: textarea
|
||||||
|
id: browser-logs
|
||||||
|
attributes:
|
||||||
|
label: Browser console output
|
||||||
|
description: Please copy and paste any relevant log output from your browser console. This will be automatically formatted into code, so no need for backticks.
|
||||||
|
render: shell
|
||||||
|
- type: checkboxes
|
||||||
|
id: common-issues
|
||||||
|
attributes:
|
||||||
|
label: Common Issues
|
||||||
|
description: Please make sure you have done the following before submitting your issue.
|
||||||
|
options:
|
||||||
|
- label: I have searched this repo for existing issues related to my issue (including closed issues)
|
||||||
|
required: true
|
||||||
|
- label: My APP_URL is set correctly in my .env file (including http or https and no trailing slash)
|
||||||
|
required: true
|
||||||
|
- label: I have searched the official Snipe-IT documentation and have checked the Common Issues documentation (where applicable)
|
||||||
|
required: true
|
||||||
|
- label: I have run database migrations (where applicable).
|
||||||
|
required: true
|
||||||
|
- label: I have attached screenshots and/or videos of the issue (where applicable)
|
||||||
|
required: true
|
||||||
|
- type: checkboxes
|
||||||
|
id: terms
|
||||||
|
attributes:
|
||||||
|
label: Code of Conduct
|
||||||
|
description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/grokability/snipe-it/blob/master/CODE_OF_CONDUCT.md).
|
||||||
|
options:
|
||||||
|
- label: I agree to follow this project's Code of Conduct
|
||||||
|
required: true
|
||||||
38
.github/ISSUE_TEMPLATE/Feature-Request.yml
vendored
Normal file
38
.github/ISSUE_TEMPLATE/Feature-Request.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
name: Feature Request
|
||||||
|
description: Request a new feature.
|
||||||
|
title: "[Feature]: "
|
||||||
|
projects: ["grokability/snipe-it"]
|
||||||
|
type: feature
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Thanks for taking the time to fill out this feature request! Please make sure to search the existing issues in this repository to see if your feature has already been requested, and feel free to add your context to any existing requests.
|
||||||
|
|
||||||
|
**Please write your issue in English.** You can use tools like [DeepL](https://www.deepl.com) or [Google Translate](https://translate.google.com/) to translate if necessary.
|
||||||
|
|
||||||
|
**If you choose to upload screenshots or videos (which we always encourage), please make sure they do not contain any sensitive information.**
|
||||||
|
- type: input
|
||||||
|
id: version
|
||||||
|
attributes:
|
||||||
|
label: Snipe-IT Version
|
||||||
|
description: What version of Snipe-IT are you currently running? You can find the version number in the footer of any page in Snipe-IT.
|
||||||
|
placeholder: ex. v8.3.1 - build 19577 (master)
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: feature-description
|
||||||
|
attributes:
|
||||||
|
label: How can we help?
|
||||||
|
description: Let us know in detail what feature you'd like to see added. While we can't promise to implement every feature request, we do read every one and take them into consideration when planning future releases.
|
||||||
|
placeholder: Tell us what you'd like to see in Snipe-IT! (Be nice!)
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: checkboxes
|
||||||
|
id: terms
|
||||||
|
attributes:
|
||||||
|
label: Code of Conduct
|
||||||
|
description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/grokability/snipe-it/blob/master/CODE_OF_CONDUCT.md).
|
||||||
|
options:
|
||||||
|
- label: I agree to follow this project's Code of Conduct
|
||||||
|
required: true
|
||||||
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
|||||||
issues: write
|
issues: write
|
||||||
# pull-requests: write
|
# pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@v9
|
- uses: actions/stale@v10
|
||||||
with:
|
with:
|
||||||
debug-only: true
|
debug-only: true
|
||||||
ascending: true
|
ascending: true
|
||||||
|
|||||||
12
.github/workflows/tests-mysql.yml
vendored
12
.github/workflows/tests-mysql.yml
vendored
@@ -76,4 +76,16 @@ jobs:
|
|||||||
DB_DATABASE: snipeit
|
DB_DATABASE: snipeit
|
||||||
DB_PORT: ${{ job.services.mysql.ports[3306] }}
|
DB_PORT: ${{ job.services.mysql.ports[3306] }}
|
||||||
DB_USERNAME: root
|
DB_USERNAME: root
|
||||||
|
LOG_CHANNEL: single
|
||||||
|
LOG_LEVEL: debug
|
||||||
run: php artisan test
|
run: php artisan test
|
||||||
|
|
||||||
|
- name: Upload Laravel logs as artifacts
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: laravel-logs-php-${{ matrix.php-version }}-run-${{ github.run_attempt }}
|
||||||
|
path: |
|
||||||
|
storage/logs/*.log
|
||||||
|
if-no-files-found: ignore
|
||||||
|
retention-days: 7
|
||||||
|
|||||||
12
.github/workflows/tests-postgres.yml
vendored
12
.github/workflows/tests-postgres.yml
vendored
@@ -75,4 +75,16 @@ jobs:
|
|||||||
DB_PORT: ${{ job.services.postgresql.ports[5432] }}
|
DB_PORT: ${{ job.services.postgresql.ports[5432] }}
|
||||||
DB_USERNAME: snipeit
|
DB_USERNAME: snipeit
|
||||||
DB_PASSWORD: password
|
DB_PASSWORD: password
|
||||||
|
LOG_CHANNEL: single
|
||||||
|
LOG_LEVEL: debug
|
||||||
run: php artisan test
|
run: php artisan test
|
||||||
|
|
||||||
|
- name: Upload Laravel logs as artifacts
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: laravel-logs-php-${{ matrix.php-version }}-run-${{ github.run_attempt }}
|
||||||
|
path: |
|
||||||
|
storage/logs/*.log
|
||||||
|
if-no-files-found: ignore
|
||||||
|
retention-days: 7
|
||||||
|
|||||||
12
.github/workflows/tests-sqlite.yml
vendored
12
.github/workflows/tests-sqlite.yml
vendored
@@ -61,4 +61,16 @@ jobs:
|
|||||||
- name: Execute tests (Unit and Feature tests) via PHPUnit
|
- name: Execute tests (Unit and Feature tests) via PHPUnit
|
||||||
env:
|
env:
|
||||||
DB_CONNECTION: sqlite
|
DB_CONNECTION: sqlite
|
||||||
|
LOG_CHANNEL: single
|
||||||
|
LOG_LEVEL: debug
|
||||||
run: php artisan test
|
run: php artisan test
|
||||||
|
|
||||||
|
- name: Upload Laravel logs as artifacts
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: laravel-logs-php-${{ matrix.php-version }}-run-${{ github.run_attempt }}
|
||||||
|
path: |
|
||||||
|
storage/logs/*.log
|
||||||
|
if-no-files-found: ignore
|
||||||
|
retention-days: 7
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
|
|||||||
| [<img src="https://avatars.githubusercontent.com/u/2565989?v=4" width="110px;"/><br /><sub>coach1988</sub>](https://github.com/coach1988)<br />[💻](https://github.com/snipe/snipe-it/commits?author=coach1988 "Code") | [<img src="https://avatars.githubusercontent.com/u/11910225?v=4" width="110px;"/><br /><sub>MrM</sub>](https://github.com/mauro-miatello)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mauro-miatello "Code") | [<img src="https://avatars.githubusercontent.com/u/60405354?v=4" width="110px;"/><br /><sub>koiakoia</sub>](https://github.com/koiakoia)<br />[💻](https://github.com/snipe/snipe-it/commits?author=koiakoia "Code") | [<img src="https://avatars.githubusercontent.com/u/5323832?v=4" width="110px;"/><br /><sub>Mustafa Online</sub>](https://github.com/mustafa-online)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mustafa-online "Code") | [<img src="https://avatars.githubusercontent.com/u/104601439?v=4" width="110px;"/><br /><sub>franceslui</sub>](https://github.com/franceslui)<br />[💻](https://github.com/snipe/snipe-it/commits?author=franceslui "Code") | [<img src="https://avatars.githubusercontent.com/u/125313163?v=4" width="110px;"/><br /><sub>Q4kK</sub>](https://github.com/Q4kK)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Q4kK "Code") | [<img src="https://avatars.githubusercontent.com/u/55590532?v=4" width="110px;"/><br /><sub>squintfox</sub>](https://github.com/squintfox)<br />[💻](https://github.com/snipe/snipe-it/commits?author=squintfox "Code") |
|
| [<img src="https://avatars.githubusercontent.com/u/2565989?v=4" width="110px;"/><br /><sub>coach1988</sub>](https://github.com/coach1988)<br />[💻](https://github.com/snipe/snipe-it/commits?author=coach1988 "Code") | [<img src="https://avatars.githubusercontent.com/u/11910225?v=4" width="110px;"/><br /><sub>MrM</sub>](https://github.com/mauro-miatello)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mauro-miatello "Code") | [<img src="https://avatars.githubusercontent.com/u/60405354?v=4" width="110px;"/><br /><sub>koiakoia</sub>](https://github.com/koiakoia)<br />[💻](https://github.com/snipe/snipe-it/commits?author=koiakoia "Code") | [<img src="https://avatars.githubusercontent.com/u/5323832?v=4" width="110px;"/><br /><sub>Mustafa Online</sub>](https://github.com/mustafa-online)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mustafa-online "Code") | [<img src="https://avatars.githubusercontent.com/u/104601439?v=4" width="110px;"/><br /><sub>franceslui</sub>](https://github.com/franceslui)<br />[💻](https://github.com/snipe/snipe-it/commits?author=franceslui "Code") | [<img src="https://avatars.githubusercontent.com/u/125313163?v=4" width="110px;"/><br /><sub>Q4kK</sub>](https://github.com/Q4kK)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Q4kK "Code") | [<img src="https://avatars.githubusercontent.com/u/55590532?v=4" width="110px;"/><br /><sub>squintfox</sub>](https://github.com/squintfox)<br />[💻](https://github.com/snipe/snipe-it/commits?author=squintfox "Code") |
|
||||||
| [<img src="https://avatars.githubusercontent.com/u/1380084?v=4" width="110px;"/><br /><sub>Jeff Clay</sub>](https://github.com/jeffclay)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jeffclay "Code") | [<img src="https://avatars.githubusercontent.com/u/52716446?v=4" width="110px;"/><br /><sub>Phil J R</sub>](https://github.com/PP-JN-RL)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PP-JN-RL "Code") | [<img src="https://avatars.githubusercontent.com/u/1496725?v=4" width="110px;"/><br /><sub>i_virus</sub>](https://www.corelight.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chandanchowdhury "Code") | [<img src="https://avatars.githubusercontent.com/u/1020541?v=4" width="110px;"/><br /><sub>Paul Grime</sub>](https://github.com/gitgrimbo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gitgrimbo "Code") | [<img src="https://avatars.githubusercontent.com/u/922815?v=4" width="110px;"/><br /><sub>Lee Porte</sub>](https://leeporte.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=LeePorte "Code") | [<img src="https://avatars.githubusercontent.com/u/23613427?v=4" width="110px;"/><br /><sub>BRYAN </sub>](https://github.com/bryanlopezinc)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Code") [⚠️](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Tests") | [<img src="https://avatars.githubusercontent.com/u/64061710?v=4" width="110px;"/><br /><sub>U-H-T</sub>](https://github.com/U-H-T)<br />[💻](https://github.com/snipe/snipe-it/commits?author=U-H-T "Code") |
|
| [<img src="https://avatars.githubusercontent.com/u/1380084?v=4" width="110px;"/><br /><sub>Jeff Clay</sub>](https://github.com/jeffclay)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jeffclay "Code") | [<img src="https://avatars.githubusercontent.com/u/52716446?v=4" width="110px;"/><br /><sub>Phil J R</sub>](https://github.com/PP-JN-RL)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PP-JN-RL "Code") | [<img src="https://avatars.githubusercontent.com/u/1496725?v=4" width="110px;"/><br /><sub>i_virus</sub>](https://www.corelight.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chandanchowdhury "Code") | [<img src="https://avatars.githubusercontent.com/u/1020541?v=4" width="110px;"/><br /><sub>Paul Grime</sub>](https://github.com/gitgrimbo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gitgrimbo "Code") | [<img src="https://avatars.githubusercontent.com/u/922815?v=4" width="110px;"/><br /><sub>Lee Porte</sub>](https://leeporte.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=LeePorte "Code") | [<img src="https://avatars.githubusercontent.com/u/23613427?v=4" width="110px;"/><br /><sub>BRYAN </sub>](https://github.com/bryanlopezinc)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Code") [⚠️](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Tests") | [<img src="https://avatars.githubusercontent.com/u/64061710?v=4" width="110px;"/><br /><sub>U-H-T</sub>](https://github.com/U-H-T)<br />[💻](https://github.com/snipe/snipe-it/commits?author=U-H-T "Code") |
|
||||||
| [<img src="https://avatars.githubusercontent.com/u/5395363?v=4" width="110px;"/><br /><sub>Matt Tyree</sub>](https://github.com/Tyree)<br />[📖](https://github.com/snipe/snipe-it/commits?author=Tyree "Documentation") | [<img src="https://avatars.githubusercontent.com/u/292081?v=4" width="110px;"/><br /><sub>Florent Bervas</sub>](http://spoontux.net)<br />[💻](https://github.com/snipe/snipe-it/commits?author=FlorentDotMe "Code") | [<img src="https://avatars.githubusercontent.com/u/4498077?v=4" width="110px;"/><br /><sub>Daniel Albertsen</sub>](https://ditscheri.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dbakan "Code") | [<img src="https://avatars.githubusercontent.com/u/100710244?v=4" width="110px;"/><br /><sub>r-xyz</sub>](https://github.com/r-xyz)<br />[💻](https://github.com/snipe/snipe-it/commits?author=r-xyz "Code") | [<img src="https://avatars.githubusercontent.com/u/47491036?v=4" width="110px;"/><br /><sub>Steven Mainor</sub>](https://github.com/DrekiDegga)<br />[💻](https://github.com/snipe/snipe-it/commits?author=DrekiDegga "Code") | [<img src="https://avatars.githubusercontent.com/u/65785975?v=4" width="110px;"/><br /><sub>arne-kroeger</sub>](https://github.com/arne-kroeger)<br />[💻](https://github.com/snipe/snipe-it/commits?author=arne-kroeger "Code") | [<img src="https://avatars.githubusercontent.com/u/167117705?v=4" width="110px;"/><br /><sub>Glukose1</sub>](https://github.com/Glukose1)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Glukose1 "Code") |
|
| [<img src="https://avatars.githubusercontent.com/u/5395363?v=4" width="110px;"/><br /><sub>Matt Tyree</sub>](https://github.com/Tyree)<br />[📖](https://github.com/snipe/snipe-it/commits?author=Tyree "Documentation") | [<img src="https://avatars.githubusercontent.com/u/292081?v=4" width="110px;"/><br /><sub>Florent Bervas</sub>](http://spoontux.net)<br />[💻](https://github.com/snipe/snipe-it/commits?author=FlorentDotMe "Code") | [<img src="https://avatars.githubusercontent.com/u/4498077?v=4" width="110px;"/><br /><sub>Daniel Albertsen</sub>](https://ditscheri.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dbakan "Code") | [<img src="https://avatars.githubusercontent.com/u/100710244?v=4" width="110px;"/><br /><sub>r-xyz</sub>](https://github.com/r-xyz)<br />[💻](https://github.com/snipe/snipe-it/commits?author=r-xyz "Code") | [<img src="https://avatars.githubusercontent.com/u/47491036?v=4" width="110px;"/><br /><sub>Steven Mainor</sub>](https://github.com/DrekiDegga)<br />[💻](https://github.com/snipe/snipe-it/commits?author=DrekiDegga "Code") | [<img src="https://avatars.githubusercontent.com/u/65785975?v=4" width="110px;"/><br /><sub>arne-kroeger</sub>](https://github.com/arne-kroeger)<br />[💻](https://github.com/snipe/snipe-it/commits?author=arne-kroeger "Code") | [<img src="https://avatars.githubusercontent.com/u/167117705?v=4" width="110px;"/><br /><sub>Glukose1</sub>](https://github.com/Glukose1)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Glukose1 "Code") |
|
||||||
| [<img src="https://avatars.githubusercontent.com/u/1197791?v=4" width="110px;"/><br /><sub>Scarzy</sub>](https://github.com/Scarzy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Scarzy "Code") | [<img src="https://avatars.githubusercontent.com/u/37372069?v=4" width="110px;"/><br /><sub>setpill</sub>](https://github.com/setpill)<br />[💻](https://github.com/snipe/snipe-it/commits?author=setpill "Code") | [<img src="https://avatars.githubusercontent.com/u/3755203?v=4" width="110px;"/><br /><sub>swift2512</sub>](https://github.com/swift2512)<br />[🐛](https://github.com/snipe/snipe-it/issues?q=author%3Aswift2512 "Bug reports") | [<img src="https://avatars.githubusercontent.com/u/6136439?v=4" width="110px;"/><br /><sub>Darren Rainey</sub>](https://darrenraineys.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=DarrenRainey "Code") | [<img src="https://avatars.githubusercontent.com/u/133033121?v=4" width="110px;"/><br /><sub>maciej-poleszczyk</sub>](https://github.com/maciej-poleszczyk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=maciej-poleszczyk "Code") | [<img src="https://avatars.githubusercontent.com/u/143394709?v=4" width="110px;"/><br /><sub>Sebastian Groß</sub>](https://github.com/sgross-emlix)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sgross-emlix "Code") | [<img src="https://avatars.githubusercontent.com/u/41107778?v=4" width="110px;"/><br /><sub>Anouar Touati</sub>](https://github.com/AnouarTouati)<br />[💻](https://github.com/snipe/snipe-it/commits?author=AnouarTouati "Code") |
|
| [<img src="https://avatars.githubusercontent.com/u/1197791?v=4" width="110px;"/><br /><sub>Scarzy</sub>](https://github.com/Scarzy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Scarzy "Code") | [<img src="https://avatars.githubusercontent.com/u/37372069?v=4" width="110px;"/><br /><sub>setpill</sub>](https://github.com/setpill)<br />[💻](https://github.com/snipe/snipe-it/commits?author=setpill "Code") | [<img src="https://avatars.githubusercontent.com/u/3755203?v=4" width="110px;"/><br /><sub>swift2512</sub>](https://github.com/swift2512)<br />[🐛](https://github.com/snipe/snipe-it/issues?q=author%3Aswift2512 "Bug reports") [💻](https://github.com/snipe/snipe-it/commits?author=swift2512 "Code") | [<img src="https://avatars.githubusercontent.com/u/6136439?v=4" width="110px;"/><br /><sub>Darren Rainey</sub>](https://darrenraineys.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=DarrenRainey "Code") | [<img src="https://avatars.githubusercontent.com/u/133033121?v=4" width="110px;"/><br /><sub>maciej-poleszczyk</sub>](https://github.com/maciej-poleszczyk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=maciej-poleszczyk "Code") | [<img src="https://avatars.githubusercontent.com/u/143394709?v=4" width="110px;"/><br /><sub>Sebastian Groß</sub>](https://github.com/sgross-emlix)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sgross-emlix "Code") | [<img src="https://avatars.githubusercontent.com/u/41107778?v=4" width="110px;"/><br /><sub>Anouar Touati</sub>](https://github.com/AnouarTouati)<br />[💻](https://github.com/snipe/snipe-it/commits?author=AnouarTouati "Code") |
|
||||||
| [<img src="https://avatars.githubusercontent.com/u/25596663?v=4" width="110px;"/><br /><sub>aHVzY2g</sub>](https://github.com/aHVzY2g)<br />[💻](https://github.com/snipe/snipe-it/commits?author=aHVzY2g "Code") | [<img src="https://avatars.githubusercontent.com/u/13408130?v=4" width="110px;"/><br /><sub>林博仁 Buo-ren Lin</sub>](https://brlin.me)<br />[💻](https://github.com/snipe/snipe-it/commits?author=brlin-tw "Code") | [<img src="https://avatars.githubusercontent.com/u/18550946?v=4" width="110px;"/><br /><sub>Adugna Gizaw</sub>](https://orbalia.pythonanywhere.com/)<br />[🌍](#translation-addex12 "Translation") | [<img src="https://avatars.githubusercontent.com/u/760989?v=4" width="110px;"/><br /><sub>Jesse Ostrander</sub>](https://github.com/jostrander)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jostrander "Code") | [<img src="https://avatars.githubusercontent.com/u/31522486?v=4" width="110px;"/><br /><sub>James M</sub>](https://github.com/azmcnutt)<br />[💻](https://github.com/snipe/snipe-it/commits?author=azmcnutt "Code") | [<img src="https://avatars.githubusercontent.com/u/5183146?v=4" width="110px;"/><br /><sub>Fiala06</sub>](https://github.com/Fiala06)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Fiala06 "Code") | [<img src="https://avatars.githubusercontent.com/u/28693782?v=4" width="110px;"/><br /><sub>Nathan Taylor</sub>](https://github.com/ntaylor-86)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ntaylor-86 "Code") |
|
| [<img src="https://avatars.githubusercontent.com/u/25596663?v=4" width="110px;"/><br /><sub>aHVzY2g</sub>](https://github.com/aHVzY2g)<br />[💻](https://github.com/snipe/snipe-it/commits?author=aHVzY2g "Code") | [<img src="https://avatars.githubusercontent.com/u/13408130?v=4" width="110px;"/><br /><sub>林博仁 Buo-ren Lin</sub>](https://brlin.me)<br />[💻](https://github.com/snipe/snipe-it/commits?author=brlin-tw "Code") | [<img src="https://avatars.githubusercontent.com/u/18550946?v=4" width="110px;"/><br /><sub>Adugna Gizaw</sub>](https://orbalia.pythonanywhere.com/)<br />[🌍](#translation-addex12 "Translation") | [<img src="https://avatars.githubusercontent.com/u/760989?v=4" width="110px;"/><br /><sub>Jesse Ostrander</sub>](https://github.com/jostrander)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jostrander "Code") | [<img src="https://avatars.githubusercontent.com/u/31522486?v=4" width="110px;"/><br /><sub>James M</sub>](https://github.com/azmcnutt)<br />[💻](https://github.com/snipe/snipe-it/commits?author=azmcnutt "Code") | [<img src="https://avatars.githubusercontent.com/u/5183146?v=4" width="110px;"/><br /><sub>Fiala06</sub>](https://github.com/Fiala06)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Fiala06 "Code") | [<img src="https://avatars.githubusercontent.com/u/28693782?v=4" width="110px;"/><br /><sub>Nathan Taylor</sub>](https://github.com/ntaylor-86)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ntaylor-86 "Code") |
|
||||||
| [<img src="https://avatars.githubusercontent.com/u/16699443?v=4" width="110px;"/><br /><sub>fvollmer</sub>](https://github.com/fvollmer)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fvollmer "Code") | [<img src="https://avatars.githubusercontent.com/u/109086466?v=4" width="110px;"/><br /><sub>36864</sub>](https://github.com/36864)<br />[💻](https://github.com/snipe/snipe-it/commits?author=36864 "Code") | [<img src="https://avatars.githubusercontent.com/u/365751?v=4" width="110px;"/><br /><sub>Daniel O'Connor</sub>](http://clockwerx.blogspot.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=CloCkWeRX "Code") | [<img src="https://avatars.githubusercontent.com/u/102852568?v=4" width="110px;"/><br /><sub>BeatSpark</sub>](https://github.com/BeatSpark)<br />[💻](https://github.com/snipe/snipe-it/commits?author=BeatSpark "Code") | [<img src="https://avatars.githubusercontent.com/u/59203607?v=4" width="110px;"/><br /><sub>mrdahbi</sub>](https://github.com/mrdahbi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mrdahbi "Code") | [<img src="https://avatars.githubusercontent.com/u/6661332?v=4" width="110px;"/><br /><sub>Fabian Schmid</sub>](http://sr.solutions)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chfsx "Code") | [<img src="https://avatars.githubusercontent.com/u/1288116?v=4" width="110px;"/><br /><sub>Chris Olin</sub>](https://www.chrisolin.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=realchrisolin "Code") |
|
| [<img src="https://avatars.githubusercontent.com/u/16699443?v=4" width="110px;"/><br /><sub>fvollmer</sub>](https://github.com/fvollmer)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fvollmer "Code") | [<img src="https://avatars.githubusercontent.com/u/109086466?v=4" width="110px;"/><br /><sub>36864</sub>](https://github.com/36864)<br />[💻](https://github.com/snipe/snipe-it/commits?author=36864 "Code") | [<img src="https://avatars.githubusercontent.com/u/365751?v=4" width="110px;"/><br /><sub>Daniel O'Connor</sub>](http://clockwerx.blogspot.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=CloCkWeRX "Code") | [<img src="https://avatars.githubusercontent.com/u/102852568?v=4" width="110px;"/><br /><sub>BeatSpark</sub>](https://github.com/BeatSpark)<br />[💻](https://github.com/snipe/snipe-it/commits?author=BeatSpark "Code") | [<img src="https://avatars.githubusercontent.com/u/59203607?v=4" width="110px;"/><br /><sub>mrdahbi</sub>](https://github.com/mrdahbi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mrdahbi "Code") | [<img src="https://avatars.githubusercontent.com/u/6661332?v=4" width="110px;"/><br /><sub>Fabian Schmid</sub>](http://sr.solutions)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chfsx "Code") | [<img src="https://avatars.githubusercontent.com/u/1288116?v=4" width="110px;"/><br /><sub>Chris Olin</sub>](https://www.chrisolin.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=realchrisolin "Code") |
|
||||||
| [<img src="https://avatars.githubusercontent.com/u/3803132?v=4" width="110px;"/><br /><sub>Dan</sub>](https://github.com/mnemonicly)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mnemonicly "Code") | [<img src="https://avatars.githubusercontent.com/u/43917728?v=4" width="110px;"/><br /><sub>Nebel</sub>](https://github.com/NebelKreis)<br />[💻](https://github.com/snipe/snipe-it/commits?author=NebelKreis "Code") | [<img src="https://avatars.githubusercontent.com/u/132433803?v=4" width="110px;"/><br /><sub>test1337ahp</sub>](https://github.com/test1337ahp)<br />[💻](https://github.com/snipe/snipe-it/commits?author=test1337ahp "Code") | [<img src="https://avatars.githubusercontent.com/u/1916566?v=4" width="110px;"/><br /><sub>Jonathon Reinhart</sub>](https://github.com/JonathonReinhart)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JonathonReinhart "Code") | [<img src="https://avatars.githubusercontent.com/u/484742?v=4" width="110px;"/><br /><sub>aranar-pro</sub>](https://github.com/aranar-pro)<br />[💻](https://github.com/snipe/snipe-it/commits?author=aranar-pro "Code") | [<img src="https://avatars.githubusercontent.com/u/27019397?v=4" width="110px;"/><br /><sub>Phil</sub>](https://github.com/phil-flip)<br />[💻](https://github.com/snipe/snipe-it/commits?author=phil-flip "Code") | [<img src="https://avatars.githubusercontent.com/u/6473460?v=4" width="110px;"/><br /><sub>Steffy Fort</sub>](https://fe80.fr/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fe80 "Code") |
|
| [<img src="https://avatars.githubusercontent.com/u/3803132?v=4" width="110px;"/><br /><sub>Dan</sub>](https://github.com/mnemonicly)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mnemonicly "Code") | [<img src="https://avatars.githubusercontent.com/u/43917728?v=4" width="110px;"/><br /><sub>Nebel</sub>](https://github.com/NebelKreis)<br />[💻](https://github.com/snipe/snipe-it/commits?author=NebelKreis "Code") | [<img src="https://avatars.githubusercontent.com/u/132433803?v=4" width="110px;"/><br /><sub>test1337ahp</sub>](https://github.com/test1337ahp)<br />[💻](https://github.com/snipe/snipe-it/commits?author=test1337ahp "Code") | [<img src="https://avatars.githubusercontent.com/u/1916566?v=4" width="110px;"/><br /><sub>Jonathon Reinhart</sub>](https://github.com/JonathonReinhart)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JonathonReinhart "Code") | [<img src="https://avatars.githubusercontent.com/u/484742?v=4" width="110px;"/><br /><sub>aranar-pro</sub>](https://github.com/aranar-pro)<br />[💻](https://github.com/snipe/snipe-it/commits?author=aranar-pro "Code") | [<img src="https://avatars.githubusercontent.com/u/27019397?v=4" width="110px;"/><br /><sub>Phil</sub>](https://github.com/phil-flip)<br />[💻](https://github.com/snipe/snipe-it/commits?author=phil-flip "Code") | [<img src="https://avatars.githubusercontent.com/u/6473460?v=4" width="110px;"/><br /><sub>Steffy Fort</sub>](https://fe80.fr/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fe80 "Code") |
|
||||||
|
|||||||
@@ -59,6 +59,9 @@ class PaveIt extends Command
|
|||||||
'migrations',
|
'migrations',
|
||||||
'settings',
|
'settings',
|
||||||
'users',
|
'users',
|
||||||
|
'telescope_entries',
|
||||||
|
'telescope_entries_tags',
|
||||||
|
'telescope_monitoring',
|
||||||
];
|
];
|
||||||
|
|
||||||
// We only need to find out what these are so we can nuke these columns on the assets table.
|
// We only need to find out what these are so we can nuke these columns on the assets table.
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class Purge extends Command
|
|||||||
$maintenances = 0;
|
$maintenances = 0;
|
||||||
|
|
||||||
foreach ($assets as $asset) {
|
foreach ($assets as $asset) {
|
||||||
$this->info('- Asset "'.$asset->present()->name().'" deleted.');
|
$this->info('- Asset "'.$asset->display_name.'" deleted.');
|
||||||
$asset_assoc += $asset->assetlog()->count();
|
$asset_assoc += $asset->assetlog()->count();
|
||||||
$asset->assetlog()->forceDelete();
|
$asset->assetlog()->forceDelete();
|
||||||
$maintenances += $asset->maintenances()->count();
|
$maintenances += $asset->maintenances()->count();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Helpers\Helper;
|
||||||
use App\Mail\ExpiringAssetsMail;
|
use App\Mail\ExpiringAssetsMail;
|
||||||
use App\Mail\ExpiringLicenseMail;
|
use App\Mail\ExpiringLicenseMail;
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
@@ -52,19 +53,35 @@ class SendExpirationAlerts extends Command
|
|||||||
->filter(fn($item) => !empty($item))
|
->filter(fn($item) => !empty($item))
|
||||||
->all();
|
->all();
|
||||||
// Expiring Assets
|
// Expiring Assets
|
||||||
$assets = Asset::getExpiringWarrantee($alert_interval);
|
$assets = Asset::getExpiringWarrantyOrEol($alert_interval);
|
||||||
|
|
||||||
if ($assets->count() > 0) {
|
if ($assets->count() > 0) {
|
||||||
$this->info(trans_choice('mail.assets_warrantee_alert', $assets->count(), ['count' => $assets->count(), 'threshold' => $alert_interval]));
|
|
||||||
Mail::to($recipients)->send(new ExpiringAssetsMail($assets, $alert_interval));
|
Mail::to($recipients)->send(new ExpiringAssetsMail($assets, $alert_interval));
|
||||||
|
|
||||||
|
$this->table(
|
||||||
|
['ID', 'Tag', 'Model', 'Model Number', 'EOL', 'EOL Months', 'Warranty Expires', 'Warranty Months'],
|
||||||
|
$assets->map(fn($item) => ['ID' => $item->id, 'Tag' => $item->asset_tag, 'Model' => $item->model->name, 'Model Number' => $item->model->model_number, 'EOL' => $item->asset_eol_date, 'EOL Months' => $item->model->eol, 'Warranty Expires' => $item->warranty_expires, 'Warranty Months' => $item->warranty_months])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expiring licenses
|
// Expiring licenses
|
||||||
$licenses = License::getExpiringLicenses($alert_interval);
|
$licenses = License::getExpiringLicenses($alert_interval);
|
||||||
if ($licenses->count() > 0) {
|
if ($licenses->count() > 0) {
|
||||||
$this->info(trans_choice('mail.license_expiring_alert', $licenses->count(), ['count' => $licenses->count(), 'threshold' => $alert_interval]));
|
|
||||||
Mail::to($recipients)->send(new ExpiringLicenseMail($licenses, $alert_interval));
|
Mail::to($recipients)->send(new ExpiringLicenseMail($licenses, $alert_interval));
|
||||||
|
|
||||||
|
$this->table(
|
||||||
|
['ID', 'Name', 'Expires', 'Termination Date'],
|
||||||
|
$licenses->map(fn($item) => ['ID' => $item->id, 'Name' => $item->name, 'Expires' => $item->expiration_date, 'Termination Date' => $item->termination_date])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send a message even if the count is 0
|
||||||
|
$this->info(trans_choice('mail.assets_warrantee_alert', $assets->count(), ['count' => $assets->count(), 'threshold' => $alert_interval]));
|
||||||
|
$this->info(trans_choice('mail.license_expiring_alert', $licenses->count(), ['count' => $licenses->count(), 'threshold' => $alert_interval]));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if ($settings->alert_email == '') {
|
if ($settings->alert_email == '') {
|
||||||
$this->error('Could not send email. No alert email configured in settings');
|
$this->error('Could not send email. No alert email configured in settings');
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ class Helper
|
|||||||
$Parsedown->setSafeMode(true);
|
$Parsedown->setSafeMode(true);
|
||||||
|
|
||||||
if ($str) {
|
if ($str) {
|
||||||
return $Parsedown->text($str);
|
return $Parsedown->text(strip_tags($str));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ class Helper
|
|||||||
$Parsedown->setSafeMode(true);
|
$Parsedown->setSafeMode(true);
|
||||||
|
|
||||||
if ($str) {
|
if ($str) {
|
||||||
return $Parsedown->line($str);
|
return $Parsedown->line(strip_tags($str));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,6 +435,34 @@ class Helper
|
|||||||
return $colors[$index];
|
return $colors[$index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a string has any RTL characters
|
||||||
|
* @param $value
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function hasRtl($string) {
|
||||||
|
$rtlChar = '/[\x{0590}-\x{083F}]|[\x{08A0}-\x{08FF}]|[\x{FB1D}-\x{FDFF}]|[\x{FE70}-\x{FEFF}]/u';
|
||||||
|
return preg_match($rtlChar, $string) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// is chinese, japanese or korean language
|
||||||
|
public static function isCjk($string) {
|
||||||
|
return Helper::isChinese($string) || Helper::isJapanese($string) || Helper::isKorean($string);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isChinese($string) {
|
||||||
|
return preg_match("/\p{Han}+/u", $string);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isJapanese($string) {
|
||||||
|
return preg_match('/[\x{4E00}-\x{9FBF}\x{3040}-\x{309F}\x{30A0}-\x{30FF}]/u', $string);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isKorean($string) {
|
||||||
|
return preg_match('/[\x{3130}-\x{318F}\x{AC00}-\x{D7AF}]/u', $string);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increases or decreases the brightness of a color by a percentage of the current brightness.
|
* Increases or decreases the brightness of a color by a percentage of the current brightness.
|
||||||
*
|
*
|
||||||
@@ -1706,5 +1734,5 @@ class Helper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $mismatched;
|
return $mismatched;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ class IconHelper
|
|||||||
case 'clone':
|
case 'clone':
|
||||||
return 'far fa-clone';
|
return 'far fa-clone';
|
||||||
case 'delete':
|
case 'delete':
|
||||||
|
case 'upload deleted':
|
||||||
return 'fas fa-trash';
|
return 'fas fa-trash';
|
||||||
case 'create':
|
case 'create':
|
||||||
return 'fa-solid fa-plus';
|
return 'fa-solid fa-plus';
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ class AccessoryCheckoutController extends Controller
|
|||||||
$this->authorize('checkout', $accessory);
|
$this->authorize('checkout', $accessory);
|
||||||
|
|
||||||
$target = $this->determineCheckoutTarget();
|
$target = $this->determineCheckoutTarget();
|
||||||
|
session()->put(['checkout_to_type' => $target]);
|
||||||
|
|
||||||
$accessory->checkout_qty = $request->input('checkout_qty', 1);
|
$accessory->checkout_qty = $request->input('checkout_qty', 1);
|
||||||
|
|
||||||
|
|||||||
@@ -8,33 +8,23 @@ use App\Events\ItemAccepted;
|
|||||||
use App\Events\ItemDeclined;
|
use App\Events\ItemDeclined;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Mail\CheckoutAcceptanceResponseMail;
|
use App\Mail\CheckoutAcceptanceResponseMail;
|
||||||
use App\Models\Actionlog;
|
|
||||||
use App\Models\Asset;
|
|
||||||
use App\Models\CheckoutAcceptance;
|
use App\Models\CheckoutAcceptance;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\Contracts\Acceptable;
|
use App\Models\Contracts\Acceptable;
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Models\AssetModel;
|
|
||||||
use App\Models\Accessory;
|
|
||||||
use App\Models\License;
|
|
||||||
use App\Models\Component;
|
|
||||||
use App\Models\Consumable;
|
|
||||||
use App\Notifications\AcceptanceAssetAcceptedNotification;
|
use App\Notifications\AcceptanceAssetAcceptedNotification;
|
||||||
use App\Notifications\AcceptanceAssetAcceptedToUserNotification;
|
use App\Notifications\AcceptanceAssetAcceptedToUserNotification;
|
||||||
use App\Notifications\AcceptanceAssetDeclinedNotification;
|
use App\Notifications\AcceptanceAssetDeclinedNotification;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Illuminate\Support\Facades\Mail;
|
use Illuminate\Support\Facades\Mail;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use App\Http\Controllers\SettingsController;
|
|
||||||
use Barryvdh\DomPDF\Facade\Pdf;
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use \Illuminate\Contracts\View\View;
|
use \Illuminate\Contracts\View\View;
|
||||||
use \Illuminate\Http\RedirectResponse;
|
use \Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use App\Helpers\Helper;
|
||||||
|
|
||||||
class AcceptanceController extends Controller
|
class AcceptanceController extends Controller
|
||||||
{
|
{
|
||||||
@@ -85,6 +75,11 @@ class AcceptanceController extends Controller
|
|||||||
public function store(Request $request, $id) : RedirectResponse
|
public function store(Request $request, $id) : RedirectResponse
|
||||||
{
|
{
|
||||||
$acceptance = CheckoutAcceptance::find($id);
|
$acceptance = CheckoutAcceptance::find($id);
|
||||||
|
$assigned_user = User::find($acceptance->assigned_to_id);
|
||||||
|
$settings = Setting::getSettings();
|
||||||
|
$path_logo = '';
|
||||||
|
$sig_filename='';
|
||||||
|
|
||||||
|
|
||||||
if (is_null($acceptance)) {
|
if (is_null($acceptance)) {
|
||||||
return redirect()->route('account.accept')->with('error', trans('admin/hardware/message.does_not_exist'));
|
return redirect()->route('account.accept')->with('error', trans('admin/hardware/message.does_not_exist'));
|
||||||
@@ -107,140 +102,75 @@ class AcceptanceController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the signature and save it
|
* Check for the signature directory
|
||||||
*/
|
*/
|
||||||
if (! Storage::exists('private_uploads/signatures')) {
|
if (! Storage::exists('private_uploads/signatures')) {
|
||||||
Storage::makeDirectory('private_uploads/signatures', 775);
|
Storage::makeDirectory('private_uploads/signatures', 775);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for the eula-pdfs directory
|
||||||
|
*/
|
||||||
|
if (! Storage::exists('private_uploads/eula-pdfs')) {
|
||||||
|
Storage::makeDirectory('private_uploads/eula-pdfs', 775);
|
||||||
|
}
|
||||||
|
|
||||||
$item = $acceptance->checkoutable_type::find($acceptance->checkoutable_id);
|
$item = $acceptance->checkoutable_type::find($acceptance->checkoutable_id);
|
||||||
$display_model = '';
|
|
||||||
$pdf_view_route = '';
|
|
||||||
$pdf_filename = 'accepted-eula-'.date('Y-m-d-h-i-s').'.pdf';
|
|
||||||
$sig_filename='';
|
// If signatures are required, make sure we have one
|
||||||
|
if (Setting::getSettings()->require_accept_signature == '1') {
|
||||||
|
|
||||||
|
// The item was accepted, check for a signature
|
||||||
|
if ($request->filled('signature_output')) {
|
||||||
|
$sig_filename = 'siglog-' . Str::uuid() . '-' . date('Y-m-d-his') . '.png';
|
||||||
|
$data_uri = $request->input('signature_output');
|
||||||
|
$encoded_image = explode(',', $data_uri);
|
||||||
|
$decoded_image = base64_decode($encoded_image[1]);
|
||||||
|
Storage::put('private_uploads/signatures/' . $sig_filename, (string)$decoded_image);
|
||||||
|
|
||||||
|
// No image data is present, kick them back.
|
||||||
|
// This mostly only applies to users on super-duper crapola browsers *cough* IE *cough*
|
||||||
|
} else {
|
||||||
|
return redirect()->back()->with('error', trans('general.shitty_browser'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Get the data array ready for the notifications and PDF generation
|
||||||
|
$data = [
|
||||||
|
'item_tag' => $item->asset_tag,
|
||||||
|
'item_name' => $item->name, // this handles licenses seats, which don't have a 'name' field
|
||||||
|
'item_model' => $item->model?->name,
|
||||||
|
'item_serial' => $item->serial,
|
||||||
|
'item_status' => $item->assetstatus?->name,
|
||||||
|
'eula' => $item->getEula(),
|
||||||
|
'note' => $request->input('note'),
|
||||||
|
'check_out_date' => Helper::getFormattedDateObject($acceptance->created_at, 'datetime', false),
|
||||||
|
'accepted_date' => Helper::getFormattedDateObject(now()->format('Y-m-d H:i:s'), 'datetime', false),
|
||||||
|
'declined_date' => Helper::getFormattedDateObject(now()->format('Y-m-d H:i:s'), 'datetime', false),
|
||||||
|
'assigned_to' => $assigned_user->display_name,
|
||||||
|
'site_name' => $settings->site_name,
|
||||||
|
'company_name' => $item->company?->name?? $settings->site_name,
|
||||||
|
'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null,
|
||||||
|
'logo' => ($settings->acceptance_pdf_logo) ? public_path() . '/uploads/' . $settings->acceptance_pdf_logo : null,
|
||||||
|
'date_settings' => $settings->date_display_format,
|
||||||
|
'admin' => auth()->user()->present()?->fullName,
|
||||||
|
'qty' => $acceptance->qty ?? 1,
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
if ($request->input('asset_acceptance') == 'accepted') {
|
if ($request->input('asset_acceptance') == 'accepted') {
|
||||||
|
|
||||||
/**
|
|
||||||
* Check for the eula-pdfs directory
|
|
||||||
*/
|
|
||||||
if (! Storage::exists('private_uploads/eula-pdfs')) {
|
|
||||||
Storage::makeDirectory('private_uploads/eula-pdfs', 775);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Setting::getSettings()->require_accept_signature == '1') {
|
$pdf_filename = 'accepted-'.$acceptance->checkoutable_id.'-'.$acceptance->display_checkoutable_type.'-eula-'.date('Y-m-d-h-i-s').'.pdf';
|
||||||
|
|
||||||
// Check if the signature directory exists, if not create it
|
|
||||||
if (!Storage::exists('private_uploads/signatures')) {
|
|
||||||
Storage::makeDirectory('private_uploads/signatures', 775);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The item was accepted, check for a signature
|
// Generate the PDF content
|
||||||
if ($request->filled('signature_output')) {
|
$pdf_content = $acceptance->generateAcceptancePdf($data, $acceptance);
|
||||||
$sig_filename = 'siglog-' . Str::uuid() . '-' . date('Y-m-d-his') . '.png';
|
Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf_content);
|
||||||
$data_uri = $request->input('signature_output');
|
|
||||||
$encoded_image = explode(',', $data_uri);
|
|
||||||
$decoded_image = base64_decode($encoded_image[1]);
|
|
||||||
Storage::put('private_uploads/signatures/' . $sig_filename, (string)$decoded_image);
|
|
||||||
|
|
||||||
// No image data is present, kick them back.
|
|
||||||
// This mostly only applies to users on super-duper crapola browsers *cough* IE *cough*
|
|
||||||
} else {
|
|
||||||
return redirect()->back()->with('error', trans('general.shitty_browser'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$assigned_user = User::find($acceptance->assigned_to_id);
|
|
||||||
// this is horrible
|
|
||||||
switch($acceptance->checkoutable_type){
|
|
||||||
case 'App\Models\Asset':
|
|
||||||
$pdf_view_route ='account.accept.accept-asset-eula';
|
|
||||||
$asset_model = AssetModel::find($item->model_id);
|
|
||||||
if (!$asset_model) {
|
|
||||||
return redirect()->back()->with('error', trans('admin/models/message.does_not_exist'));
|
|
||||||
}
|
|
||||||
$display_model = $asset_model->name;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'App\Models\Accessory':
|
|
||||||
$pdf_view_route ='account.accept.accept-accessory-eula';
|
|
||||||
$accessory = Accessory::find($item->id);
|
|
||||||
$display_model = $accessory->name;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'App\Models\LicenseSeat':
|
|
||||||
$pdf_view_route ='account.accept.accept-license-eula';
|
|
||||||
$license = License::find($item->license_id);
|
|
||||||
$display_model = $license->name;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'App\Models\Component':
|
|
||||||
$pdf_view_route ='account.accept.accept-component-eula';
|
|
||||||
$component = Component::find($item->id);
|
|
||||||
$display_model = $component->name;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'App\Models\Consumable':
|
|
||||||
$pdf_view_route ='account.accept.accept-consumable-eula';
|
|
||||||
$consumable = Consumable::find($item->id);
|
|
||||||
$display_model = $consumable->name;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// if ($acceptance->checkoutable_type == 'App\Models\Asset') {
|
|
||||||
// $pdf_view_route ='account.accept.accept-asset-eula';
|
|
||||||
// $asset_model = AssetModel::find($item->model_id);
|
|
||||||
// $display_model = $asset_model->name;
|
|
||||||
// $assigned_to = User::find($item->assigned_to)->present()->fullName;
|
|
||||||
//
|
|
||||||
// } elseif ($acceptance->checkoutable_type== 'App\Models\Accessory') {
|
|
||||||
// $pdf_view_route ='account.accept.accept-accessory-eula';
|
|
||||||
// $accessory = Accessory::find($item->id);
|
|
||||||
// $display_model = $accessory->name;
|
|
||||||
// $assigned_to = User::find($item->assignedTo);
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gather the data for the PDF. We fire this whether there is a signature required or not,
|
|
||||||
* since we want the moment-in-time proof of what the EULA was when they accepted it.
|
|
||||||
*/
|
|
||||||
$branding_settings = SettingsController::getPDFBranding();
|
|
||||||
|
|
||||||
$path_logo = "";
|
|
||||||
|
|
||||||
// Check for the PDF logo path and use that, otherwise use the regular logo path
|
|
||||||
if (!is_null($branding_settings->acceptance_pdf_logo)) {
|
|
||||||
$path_logo = public_path() . '/uploads/' . $branding_settings->acceptance_pdf_logo;
|
|
||||||
} elseif (!is_null($branding_settings->logo)) {
|
|
||||||
$path_logo = public_path() . '/uploads/' . $branding_settings->logo;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'item_tag' => $item->asset_tag,
|
|
||||||
'item_model' => $display_model,
|
|
||||||
'item_serial' => $item->serial,
|
|
||||||
'item_status' => $item->assetstatus?->name,
|
|
||||||
'eula' => $item->getEula(),
|
|
||||||
'note' => $request->input('note'),
|
|
||||||
'check_out_date' => Carbon::parse($acceptance->created_at)->format('Y-m-d'),
|
|
||||||
'accepted_date' => Carbon::parse($acceptance->accepted_at)->format('Y-m-d'),
|
|
||||||
'assigned_to' => $assigned_user->present()->fullName,
|
|
||||||
'company_name' => $branding_settings->site_name,
|
|
||||||
'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null,
|
|
||||||
'logo' => $path_logo,
|
|
||||||
'date_settings' => $branding_settings->date_display_format,
|
|
||||||
'admin' => auth()->user()->present()?->fullName,
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($pdf_view_route!='') {
|
|
||||||
Log::debug($pdf_filename.' is the filename, and the route was specified.');
|
|
||||||
$pdf = Pdf::loadView($pdf_view_route, $data);
|
|
||||||
Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf->output());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Log the acceptance
|
||||||
$acceptance->accept($sig_filename, $item->getEula(), $pdf_filename, $request->input('note'));
|
$acceptance->accept($sig_filename, $item->getEula(), $pdf_filename, $request->input('note'));
|
||||||
|
|
||||||
// Send the PDF to the signing user
|
// Send the PDF to the signing user
|
||||||
@@ -248,9 +178,8 @@ class AcceptanceController extends Controller
|
|||||||
|
|
||||||
// Add the attachment for the signing user into the $data array
|
// Add the attachment for the signing user into the $data array
|
||||||
$data['file'] = $pdf_filename;
|
$data['file'] = $pdf_filename;
|
||||||
$locale = $assigned_user->locale;
|
|
||||||
try {
|
try {
|
||||||
$assigned_user->notify((new AcceptanceAssetAcceptedToUserNotification($data))->locale($locale));
|
$assigned_user->notify((new AcceptanceAssetAcceptedToUserNotification($data))->locale($assigned_user->locale));
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
Log::warning($e);
|
Log::warning($e);
|
||||||
}
|
}
|
||||||
@@ -264,95 +193,21 @@ class AcceptanceController extends Controller
|
|||||||
|
|
||||||
$return_msg = trans('admin/users/message.accepted');
|
$return_msg = trans('admin/users/message.accepted');
|
||||||
|
|
||||||
|
// Item was declined
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/**
|
for ($i = 0; $i < ($acceptance->qty ?? 1); $i++) {
|
||||||
* Check for the eula-pdfs directory
|
$acceptance->decline($sig_filename, $request->input('note'));
|
||||||
*/
|
|
||||||
if (! Storage::exists('private_uploads/eula-pdfs')) {
|
|
||||||
Storage::makeDirectory('private_uploads/eula-pdfs', 775);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Setting::getSettings()->require_accept_signature == '1') {
|
|
||||||
|
|
||||||
// Check if the signature directory exists, if not create it
|
|
||||||
if (!Storage::exists('private_uploads/signatures')) {
|
|
||||||
Storage::makeDirectory('private_uploads/signatures', 775);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The item was accepted, check for a signature
|
|
||||||
if ($request->filled('signature_output')) {
|
|
||||||
$sig_filename = 'siglog-' . Str::uuid() . '-' . date('Y-m-d-his') . '.png';
|
|
||||||
$data_uri = $request->input('signature_output');
|
|
||||||
$encoded_image = explode(',', $data_uri);
|
|
||||||
$decoded_image = base64_decode($encoded_image[1]);
|
|
||||||
Storage::put('private_uploads/signatures/' . $sig_filename, (string)$decoded_image);
|
|
||||||
|
|
||||||
// No image data is present, kick them back.
|
|
||||||
// This mostly only applies to users on super-duper crapola browsers *cough* IE *cough*
|
|
||||||
} else {
|
|
||||||
return redirect()->back()->with('error', trans('general.shitty_browser'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format the data to send the declined notification
|
|
||||||
$branding_settings = SettingsController::getPDFBranding();
|
|
||||||
|
|
||||||
// This is the most horriblest
|
|
||||||
switch($acceptance->checkoutable_type){
|
|
||||||
case 'App\Models\Asset':
|
|
||||||
$asset_model = AssetModel::find($item->model_id);
|
|
||||||
$display_model = $asset_model->name;
|
|
||||||
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'App\Models\Accessory':
|
|
||||||
$accessory = Accessory::find($item->id);
|
|
||||||
$display_model = $accessory->name;
|
|
||||||
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'App\Models\LicenseSeat':
|
|
||||||
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'App\Models\Component':
|
|
||||||
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'App\Models\Consumable':
|
|
||||||
$consumable = Consumable::find($item->id);
|
|
||||||
$display_model = $consumable->name;
|
|
||||||
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'item_tag' => $item->asset_tag,
|
|
||||||
'item_model' => $display_model,
|
|
||||||
'item_serial' => $item->serial,
|
|
||||||
'item_status' => $item->assetstatus?->name,
|
|
||||||
'note' => $request->input('note'),
|
|
||||||
'declined_date' => Carbon::parse($acceptance->declined_at)->format('Y-m-d'),
|
|
||||||
'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null,
|
|
||||||
'assigned_to' => $assigned_to,
|
|
||||||
'company_name' => $branding_settings->site_name,
|
|
||||||
'date_settings' => $branding_settings->date_display_format,
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($pdf_view_route!='') {
|
|
||||||
Log::debug($pdf_filename.' is the filename, and the route was specified.');
|
|
||||||
$pdf = Pdf::loadView($pdf_view_route, $data);
|
|
||||||
Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf->output());
|
|
||||||
}
|
|
||||||
|
|
||||||
$acceptance->decline($sig_filename, $request->input('note'));
|
|
||||||
$acceptance->notify(new AcceptanceAssetDeclinedNotification($data));
|
$acceptance->notify(new AcceptanceAssetDeclinedNotification($data));
|
||||||
Log::debug('New event acceptance.');
|
Log::debug('New event acceptance.');
|
||||||
event(new CheckoutDeclined($acceptance));
|
event(new CheckoutDeclined($acceptance));
|
||||||
$return_msg = trans('admin/users/message.declined');
|
$return_msg = trans('admin/users/message.declined');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Send an email notification if one is requested
|
||||||
if ($acceptance->alert_on_response_id) {
|
if ($acceptance->alert_on_response_id) {
|
||||||
try {
|
try {
|
||||||
$recipient = User::find($acceptance->alert_on_response_id);
|
$recipient = User::find($acceptance->alert_on_response_id);
|
||||||
@@ -371,9 +226,10 @@ class AcceptanceController extends Controller
|
|||||||
Log::warning($e);
|
Log::warning($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->to('account/accept')->with('success', $return_msg);
|
return redirect()->to('account/accept')->with('success', $return_msg);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,13 @@
|
|||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
|
use App\Models\Actionlog;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use \Illuminate\Http\Response;
|
|
||||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||||
|
use \Illuminate\Http\Response;
|
||||||
|
|
||||||
class ActionlogController extends Controller
|
class ActionlogController extends Controller
|
||||||
{
|
{
|
||||||
public function displaySig($filename) : RedirectResponse | Response | bool
|
public function displaySig($filename) : RedirectResponse | Response | bool
|
||||||
@@ -39,17 +41,29 @@ class ActionlogController extends Controller
|
|||||||
|
|
||||||
public function getStoredEula($filename) : Response | BinaryFileResponse | RedirectResponse
|
public function getStoredEula($filename) : Response | BinaryFileResponse | RedirectResponse
|
||||||
{
|
{
|
||||||
$this->authorize('view', \App\Models\Asset::class);
|
|
||||||
|
|
||||||
if (config('filesystems.default') == 's3_private') {
|
if ($actionlog = Actionlog::where('filename', $filename)->with('user')->with('target')->firstOrFail()) {
|
||||||
return redirect()->away(Storage::disk('s3_private')->temporaryUrl('private_uploads/eula-pdfs/'.$filename, now()->addMinutes(5)));
|
|
||||||
|
$this->authorize('view', $actionlog->target);
|
||||||
|
$this->authorize('view', $actionlog->user);
|
||||||
|
|
||||||
|
|
||||||
|
if (config('filesystems.default') == 's3_private') {
|
||||||
|
return redirect()->away(Storage::disk('s3_private')->temporaryUrl('private_uploads/eula-pdfs/' . $filename, now()->addMinutes(5)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Storage::exists('private_uploads/eula-pdfs/' . $filename)) {
|
||||||
|
|
||||||
|
if (request()->input('inline') == 'true') {
|
||||||
|
return response()->file(config('app.private_uploads') . '/eula-pdfs/' . $filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->download(config('app.private_uploads') . '/eula-pdfs/' . $filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->back()->with('error', trans('general.file_does_not_exist'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Storage::exists('private_uploads/eula-pdfs/'.$filename)) {
|
return redirect()->back()->with('error', trans('general.record_not_found'));
|
||||||
return response()->download(config('app.private_uploads').'/eula-pdfs/'.$filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect()->back()->with('error', trans('general.file_does_not_exist'));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -288,32 +288,42 @@ class AccessoriesController extends Controller
|
|||||||
'note' => $request->input('note'),
|
'note' => $request->input('note'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
$accessory_checkout->created_by = auth()->id();
|
$accessory_checkout->created_by = auth()->id();
|
||||||
$accessory_checkout->save();
|
$accessory_checkout->save();
|
||||||
|
|
||||||
|
$payload = [
|
||||||
|
'accessory_id' => $accessory->id,
|
||||||
|
'assigned_to' => $target->id,
|
||||||
|
'assigned_type' => $target::class,
|
||||||
|
'note' => $request->input('note'),
|
||||||
|
'created_by' => auth()->id(),
|
||||||
|
'pivot' => $accessory_checkout->id,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set this value to be able to pass the qty through to the event
|
// Set this value to be able to pass the qty through to the event
|
||||||
event(new CheckoutableCheckedOut($accessory, $target, auth()->user(), $request->input('note')));
|
event(new CheckoutableCheckedOut($accessory, $target, auth()->user(), $request->input('note')));
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkout.success')));
|
return response()->json(Helper::formatStandardApiResponse('success', $payload, trans('admin/accessories/message.checkout.success')));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check in the item so that it can be checked out again to someone else
|
* Check in the item so that it can be checked out again to someone else
|
||||||
*
|
*
|
||||||
* @uses Accessory::checkin_email() to determine if an email can and should be sent
|
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param int $accessoryUserId
|
* @param int $accessoryUserId
|
||||||
* @param string $backto
|
* @param string $backto
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return JsonResponse
|
||||||
|
* @uses Accessory::checkin_email() to determine if an email can and should be sent
|
||||||
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @internal param int $accessoryId
|
* @internal param int $accessoryId
|
||||||
*/
|
*/
|
||||||
public function checkin(Request $request, $accessoryUserId = null)
|
public function checkin(Request $request, $accessoryUserId = null)
|
||||||
{
|
{
|
||||||
if (is_null($accessory_checkout = AccessoryCheckout::find($accessoryUserId))) {
|
if (is_null($accessory_checkout = AccessoryCheckout::find($accessoryUserId))) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.does_not_exist')));
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.does_not_exist', ['id' => $accessoryUserId])));
|
||||||
}
|
}
|
||||||
|
|
||||||
$accessory = Accessory::find($accessory_checkout->accessory_id);
|
$accessory = Accessory::find($accessory_checkout->accessory_id);
|
||||||
@@ -327,7 +337,14 @@ class AccessoriesController extends Controller
|
|||||||
$user = User::find($accessory_checkout->assigned_to);
|
$user = User::find($accessory_checkout->assigned_to);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkin.success')));
|
$payload = [
|
||||||
|
'accessory_id' => $accessory->id,
|
||||||
|
'note' => $request->input('note'),
|
||||||
|
'created_by' => auth()->id(),
|
||||||
|
'pivot' => $accessory_checkout->id,
|
||||||
|
];
|
||||||
|
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('success', $payload, trans('admin/accessories/message.checkin.success')));
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.checkin.error')));
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.checkin.error')));
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ class AssetModelsController extends Controller
|
|||||||
'fieldset',
|
'fieldset',
|
||||||
'deleted_at',
|
'deleted_at',
|
||||||
'updated_at',
|
'updated_at',
|
||||||
|
'require_serial',
|
||||||
];
|
];
|
||||||
|
|
||||||
$assetmodels = AssetModel::select([
|
$assetmodels = AssetModel::select([
|
||||||
@@ -69,6 +70,7 @@ class AssetModelsController extends Controller
|
|||||||
'models.fieldset_id',
|
'models.fieldset_id',
|
||||||
'models.deleted_at',
|
'models.deleted_at',
|
||||||
'models.updated_at',
|
'models.updated_at',
|
||||||
|
'models.require_serial'
|
||||||
])
|
])
|
||||||
->with('category', 'depreciation', 'manufacturer', 'fieldset.fields.defaultValues', 'adminuser')
|
->with('category', 'depreciation', 'manufacturer', 'fieldset.fields.defaultValues', 'adminuser')
|
||||||
->withCount('assets as assets_count');
|
->withCount('assets as assets_count');
|
||||||
|
|||||||
@@ -1290,9 +1290,19 @@ class AssetsController extends Controller
|
|||||||
|
|
||||||
public function assignedAssets(Request $request, Asset $asset) : JsonResponse | array
|
public function assignedAssets(Request $request, Asset $asset) : JsonResponse | array
|
||||||
{
|
{
|
||||||
|
$this->authorize('view', Asset::class);
|
||||||
|
$this->authorize('view', $asset);
|
||||||
|
|
||||||
return [];
|
$query = Asset::where([
|
||||||
// to do
|
'assigned_to' => $asset->id,
|
||||||
|
'assigned_type' => Asset::class,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$total = $query->count();
|
||||||
|
|
||||||
|
$assets = $query->applyOffsetAndLimit($total)->get();
|
||||||
|
|
||||||
|
return (new AssetsTransformer)->transformAssets($assets, $total);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function assignedAccessories(Request $request, Asset $asset) : JsonResponse | array
|
public function assignedAccessories(Request $request, Asset $asset) : JsonResponse | array
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ class CategoriesController extends Controller
|
|||||||
'consumables_count',
|
'consumables_count',
|
||||||
'components_count',
|
'components_count',
|
||||||
'licenses_count',
|
'licenses_count',
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
'image',
|
'image',
|
||||||
'notes',
|
'notes',
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ class ImportController extends Controller
|
|||||||
if (function_exists('iconv')) {
|
if (function_exists('iconv')) {
|
||||||
$file_contents = $file->getContent(); //TODO - this *does* load the whole file in RAM, but we need that to be able to 'iconv' it?
|
$file_contents = $file->getContent(); //TODO - this *does* load the whole file in RAM, but we need that to be able to 'iconv' it?
|
||||||
$encoding = $detector->getEncoding($file_contents);
|
$encoding = $detector->getEncoding($file_contents);
|
||||||
\Log::warning("Discovered encoding: $encoding in uploaded CSV");
|
\Log::debug("Discovered encoding: $encoding in uploaded CSV");
|
||||||
$reader = null;
|
$reader = null;
|
||||||
if (strcasecmp($encoding, 'UTF-8') != 0) {
|
if (strcasecmp($encoding, 'UTF-8') != 0) {
|
||||||
$transliterated = false;
|
$transliterated = false;
|
||||||
@@ -103,7 +103,7 @@ class ImportController extends Controller
|
|||||||
$reader = Reader::createFromFileObject($file->openFile('r')); //file pointer leak?
|
$reader = Reader::createFromFileObject($file->openFile('r')); //file pointer leak?
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$import->header_row = $reader->fetchOne(0);
|
$import->header_row = $reader->nth(0);
|
||||||
} catch (JsonEncodingException $e) {
|
} catch (JsonEncodingException $e) {
|
||||||
return response()->json(
|
return response()->json(
|
||||||
Helper::formatStandardApiResponse(
|
Helper::formatStandardApiResponse(
|
||||||
@@ -136,7 +136,7 @@ class ImportController extends Controller
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Grab the first row to display via ajax as the user picks fields
|
// Grab the first row to display via ajax as the user picks fields
|
||||||
$import->first_row = $reader->fetchOne(1);
|
$import->first_row = $reader->nth(1);
|
||||||
} catch (JsonEncodingException $e) {
|
} catch (JsonEncodingException $e) {
|
||||||
return response()->json(
|
return response()->json(
|
||||||
Helper::formatStandardApiResponse(
|
Helper::formatStandardApiResponse(
|
||||||
|
|||||||
@@ -128,7 +128,9 @@ class LicenseSeatsController extends Controller
|
|||||||
// nothing to update
|
// nothing to update
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success')));
|
return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success')));
|
||||||
}
|
}
|
||||||
|
if( $touched && $licenseSeat->unreassignable_seat) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/licenses/message.checkout.unavailable')));
|
||||||
|
}
|
||||||
// the logging functions expect only one "target". if both asset and user are present in the request,
|
// the logging functions expect only one "target". if both asset and user are present in the request,
|
||||||
// we simply let assets take precedence over users...
|
// we simply let assets take precedence over users...
|
||||||
if ($licenseSeat->isDirty('assigned_to')) {
|
if ($licenseSeat->isDirty('assigned_to')) {
|
||||||
@@ -145,7 +147,11 @@ class LicenseSeatsController extends Controller
|
|||||||
if ($licenseSeat->save()) {
|
if ($licenseSeat->save()) {
|
||||||
|
|
||||||
if ($is_checkin) {
|
if ($is_checkin) {
|
||||||
$licenseSeat->logCheckin($target, $request->input('notes'));
|
if(!$licenseSeat->license->reassignable){
|
||||||
|
$licenseSeat->unreassignable_seat = true;
|
||||||
|
$licenseSeat->save();
|
||||||
|
}
|
||||||
|
$licenseSeat->logCheckin($target, $licenseSeat->notes);
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success')));
|
return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success')));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,12 @@ class LicensesController extends Controller
|
|||||||
|
|
||||||
$licenses = License::with('company', 'manufacturer', 'supplier','category', 'adminuser')->withCount('freeSeats as free_seats_count');
|
$licenses = License::with('company', 'manufacturer', 'supplier','category', 'adminuser')->withCount('freeSeats as free_seats_count');
|
||||||
|
|
||||||
|
if ($request->input('status')=='inactive') {
|
||||||
|
$licenses->ExpiredLicenses();
|
||||||
|
} else {
|
||||||
|
$licenses->ActiveLicenses();
|
||||||
|
}
|
||||||
|
|
||||||
if ($request->filled('company_id')) {
|
if ($request->filled('company_id')) {
|
||||||
$licenses->where('licenses.company_id', '=', $request->input('company_id'));
|
$licenses->where('licenses.company_id', '=', $request->input('company_id'));
|
||||||
}
|
}
|
||||||
@@ -94,6 +100,8 @@ class LicensesController extends Controller
|
|||||||
$licenses->onlyTrashed();
|
$licenses->onlyTrashed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||||
$offset = ($request->input('offset') > $licenses->count()) ? $licenses->count() : app('api_offset_value');
|
$offset = ($request->input('offset') > $licenses->count()) ? $licenses->count() : app('api_offset_value');
|
||||||
$limit = app('api_limit_value');
|
$limit = app('api_limit_value');
|
||||||
|
|||||||
@@ -37,10 +37,14 @@ class LocationsController extends Controller
|
|||||||
'address',
|
'address',
|
||||||
'address2',
|
'address2',
|
||||||
'assets_count',
|
'assets_count',
|
||||||
'assets_count',
|
'assigned_assets_count',
|
||||||
|
'rtd_assets_count',
|
||||||
|
'accessories_count',
|
||||||
'assigned_accessories_count',
|
'assigned_accessories_count',
|
||||||
'assigned_assets_count',
|
'components_count',
|
||||||
'assigned_assets_count',
|
'consumables_count',
|
||||||
|
'users_count',
|
||||||
|
'children_count',
|
||||||
'city',
|
'city',
|
||||||
'country',
|
'country',
|
||||||
'created_at',
|
'created_at',
|
||||||
@@ -54,7 +58,6 @@ class LocationsController extends Controller
|
|||||||
'rtd_assets_count',
|
'rtd_assets_count',
|
||||||
'state',
|
'state',
|
||||||
'updated_at',
|
'updated_at',
|
||||||
'users_count',
|
|
||||||
'zip',
|
'zip',
|
||||||
'notes',
|
'notes',
|
||||||
];
|
];
|
||||||
@@ -79,8 +82,9 @@ class LocationsController extends Controller
|
|||||||
'locations.currency',
|
'locations.currency',
|
||||||
'locations.company_id',
|
'locations.company_id',
|
||||||
'locations.notes',
|
'locations.notes',
|
||||||
|
'locations.created_by',
|
||||||
|
'locations.deleted_at',
|
||||||
])
|
])
|
||||||
->withCount('assignedAssets as assigned_assets_count')
|
|
||||||
->withCount('assignedAssets as assigned_assets_count')
|
->withCount('assignedAssets as assigned_assets_count')
|
||||||
->withCount('assets as assets_count')
|
->withCount('assets as assets_count')
|
||||||
->withCount('assignedAccessories as assigned_accessories_count')
|
->withCount('assignedAccessories as assigned_accessories_count')
|
||||||
@@ -88,6 +92,8 @@ class LocationsController extends Controller
|
|||||||
->withCount('rtd_assets as rtd_assets_count')
|
->withCount('rtd_assets as rtd_assets_count')
|
||||||
->withCount('children as children_count')
|
->withCount('children as children_count')
|
||||||
->withCount('users as users_count')
|
->withCount('users as users_count')
|
||||||
|
->withCount('consumables as consumables_count')
|
||||||
|
->withCount('components as components_count')
|
||||||
->with('adminuser');
|
->with('adminuser');
|
||||||
|
|
||||||
// Only scope locations if the setting is enabled
|
// Only scope locations if the setting is enabled
|
||||||
@@ -131,6 +137,14 @@ class LocationsController extends Controller
|
|||||||
$locations->where('locations.company_id', '=', $request->input('company_id'));
|
$locations->where('locations.company_id', '=', $request->input('company_id'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($request->filled('parent_id')) {
|
||||||
|
$locations->where('locations.parent_id', '=', $request->input('parent_id'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->input('status') == 'deleted') {
|
||||||
|
$locations->onlyTrashed();
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||||
$offset = ($request->input('offset') > $locations->count()) ? $locations->count() : app('api_offset_value');
|
$offset = ($request->input('offset') > $locations->count()) ? $locations->count() : app('api_offset_value');
|
||||||
$limit = app('api_limit_value');
|
$limit = app('api_limit_value');
|
||||||
@@ -224,8 +238,13 @@ class LocationsController extends Controller
|
|||||||
])
|
])
|
||||||
->withCount('assignedAssets as assigned_assets_count')
|
->withCount('assignedAssets as assigned_assets_count')
|
||||||
->withCount('assets as assets_count')
|
->withCount('assets as assets_count')
|
||||||
|
->withCount('assignedAccessories as assigned_accessories_count')
|
||||||
|
->withCount('accessories as accessories_count')
|
||||||
->withCount('rtd_assets as rtd_assets_count')
|
->withCount('rtd_assets as rtd_assets_count')
|
||||||
|
->withCount('children as children_count')
|
||||||
->withCount('users as users_count')
|
->withCount('users as users_count')
|
||||||
|
->withCount('consumables as consumables_count')
|
||||||
|
->withCount('components as components_count')
|
||||||
->findOrFail($id);
|
->findOrFail($id);
|
||||||
|
|
||||||
return (new LocationsTransformer)->transformLocation($location);
|
return (new LocationsTransformer)->transformLocation($location);
|
||||||
@@ -320,11 +339,15 @@ class LocationsController extends Controller
|
|||||||
{
|
{
|
||||||
$this->authorize('delete', Location::class);
|
$this->authorize('delete', Location::class);
|
||||||
$location = Location::withCount('assignedAssets as assigned_assets_count')
|
$location = Location::withCount('assignedAssets as assigned_assets_count')
|
||||||
|
->withCount('assignedAssets as assigned_assets_count')
|
||||||
->withCount('assets as assets_count')
|
->withCount('assets as assets_count')
|
||||||
|
->withCount('assignedAccessories as assigned_accessories_count')
|
||||||
|
->withCount('accessories as accessories_count')
|
||||||
->withCount('rtd_assets as rtd_assets_count')
|
->withCount('rtd_assets as rtd_assets_count')
|
||||||
->withCount('children as children_count')
|
->withCount('children as children_count')
|
||||||
->withCount('users as users_count')
|
->withCount('users as users_count')
|
||||||
->withCount('accessories as accessories_count')
|
->withCount('consumables as consumables_count')
|
||||||
|
->withCount('components as components_count')
|
||||||
->findOrFail($id);
|
->findOrFail($id);
|
||||||
|
|
||||||
if (! $location->isDeletable()) {
|
if (! $location->isDeletable()) {
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ class ProfileController extends Controller
|
|||||||
if ($checkoutRequest && $checkoutRequest->itemRequested()) {
|
if ($checkoutRequest && $checkoutRequest->itemRequested()) {
|
||||||
$assets = [
|
$assets = [
|
||||||
'image' => e($checkoutRequest->itemRequested()->present()->getImageUrl()),
|
'image' => e($checkoutRequest->itemRequested()->present()->getImageUrl()),
|
||||||
'name' => e($checkoutRequest->itemRequested()->present()->name()),
|
'name' => e($checkoutRequest->itemRequested()->display_name),
|
||||||
'type' => e($checkoutRequest->itemType()),
|
'type' => e($checkoutRequest->itemType()),
|
||||||
'qty' => (int) $checkoutRequest->quantity,
|
'qty' => (int) $checkoutRequest->quantity,
|
||||||
'location' => ($checkoutRequest->location()) ? e($checkoutRequest->location()->name) : null,
|
'location' => ($checkoutRequest->location()) ? e($checkoutRequest->location()->name) : null,
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class UploadedFilesController extends Controller
|
|||||||
{
|
{
|
||||||
|
|
||||||
// Check the permissions to make sure the user can view the object
|
// Check the permissions to make sure the user can view the object
|
||||||
$object = self::$map_object_type[$object_type]::find($id);
|
$object = self::$map_object_type[$object_type]::withTrashed()->find($id);
|
||||||
$this->authorize('view', $object);
|
$this->authorize('view', $object);
|
||||||
|
|
||||||
if (!$object) {
|
if (!$object) {
|
||||||
@@ -51,11 +51,7 @@ class UploadedFilesController extends Controller
|
|||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
$uploads = Actionlog::select('action_logs.*')
|
$uploads = self::$map_object_type[$object_type]::withTrashed()->find($id)->uploads()
|
||||||
->whereNotNull('filename')
|
|
||||||
->where('item_type', self::$map_object_type[$object_type])
|
|
||||||
->where('item_id', $object->id)
|
|
||||||
->where('action_type', '=', 'uploaded')
|
|
||||||
->with('adminuser');
|
->with('adminuser');
|
||||||
|
|
||||||
$offset = ($request->input('offset') > $uploads->count()) ? $uploads->count() : abs($request->input('offset'));
|
$offset = ($request->input('offset') > $uploads->count()) ? $uploads->count() : abs($request->input('offset'));
|
||||||
@@ -96,7 +92,7 @@ class UploadedFilesController extends Controller
|
|||||||
{
|
{
|
||||||
|
|
||||||
// Check the permissions to make sure the user can view the object
|
// Check the permissions to make sure the user can view the object
|
||||||
$object = self::$map_object_type[$object_type]::find($id);
|
$object = self::$map_object_type[$object_type]::withTrashed()->find($id);
|
||||||
$this->authorize('view', $object);
|
$this->authorize('view', $object);
|
||||||
|
|
||||||
if (!$object) {
|
if (!$object) {
|
||||||
@@ -144,7 +140,7 @@ class UploadedFilesController extends Controller
|
|||||||
public function show($object_type, $id, $file_id) : JsonResponse | StreamedResponse | Storage | StorageHelper | BinaryFileResponse
|
public function show($object_type, $id, $file_id) : JsonResponse | StreamedResponse | Storage | StorageHelper | BinaryFileResponse
|
||||||
{
|
{
|
||||||
// Check the permissions to make sure the user can view the object
|
// Check the permissions to make sure the user can view the object
|
||||||
$object = self::$map_object_type[$object_type]::find($id);
|
$object = self::$map_object_type[$object_type]::withTrashed()->find($id);
|
||||||
$this->authorize('view', $object);
|
$this->authorize('view', $object);
|
||||||
|
|
||||||
if (!$object) {
|
if (!$object) {
|
||||||
@@ -188,7 +184,7 @@ class UploadedFilesController extends Controller
|
|||||||
{
|
{
|
||||||
|
|
||||||
// Check the permissions to make sure the user can view the object
|
// Check the permissions to make sure the user can view the object
|
||||||
$object = self::$map_object_type[$object_type]::find($id);
|
$object = self::$map_object_type[$object_type]::withTrashed()->find($id);
|
||||||
$this->authorize('update', self::$map_object_type[$object_type]);
|
$this->authorize('update', self::$map_object_type[$object_type]);
|
||||||
|
|
||||||
if (!$object) {
|
if (!$object) {
|
||||||
@@ -206,7 +202,7 @@ class UploadedFilesController extends Controller
|
|||||||
Storage::delete(self::$map_storage_path[$object_type].'/'.$log->filename);
|
Storage::delete(self::$map_storage_path[$object_type].'/'.$log->filename);
|
||||||
}
|
}
|
||||||
// Delete the record of the file
|
// Delete the record of the file
|
||||||
if ($log->delete()) {
|
if ($log->logUploadDelete($object, $log->filename)) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans_choice('general.file_upload_status.delete.success', 1)), 200);
|
return response()->json(Helper::formatStandardApiResponse('success', null, trans_choice('general.file_upload_status.delete.success', 1)), 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -435,7 +435,7 @@ class UsersController extends Controller
|
|||||||
$user->password = $user->noPassword();
|
$user->password = $user->noPassword();
|
||||||
}
|
}
|
||||||
|
|
||||||
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'image', 'avatars', 'avatar');
|
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
|
||||||
|
|
||||||
if ($user->save()) {
|
if ($user->save()) {
|
||||||
|
|
||||||
@@ -560,7 +560,7 @@ class UsersController extends Controller
|
|||||||
Asset::where('assigned_type', User::class)
|
Asset::where('assigned_type', User::class)
|
||||||
->where('assigned_to', $user->id)->update(['location_id' => $request->input('location_id', null)]);
|
->where('assigned_to', $user->id)->update(['location_id' => $request->input('location_id', null)]);
|
||||||
}
|
}
|
||||||
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'image', 'avatars', 'avatar');
|
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
|
||||||
|
|
||||||
if ($user->save()) {
|
if ($user->save()) {
|
||||||
// Check if the request has groups passed and has a value, AND that the user us a superuser
|
// Check if the request has groups passed and has a value, AND that the user us a superuser
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ class AssetModelsController extends Controller
|
|||||||
$model->notes = $request->input('notes');
|
$model->notes = $request->input('notes');
|
||||||
$model->created_by = auth()->id();
|
$model->created_by = auth()->id();
|
||||||
$model->requestable = $request->has('requestable');
|
$model->requestable = $request->has('requestable');
|
||||||
|
$model->require_serial = $request->input('require_serial', 0);
|
||||||
|
|
||||||
if ($request->input('fieldset_id') != '') {
|
if ($request->input('fieldset_id') != '') {
|
||||||
$model->fieldset_id = $request->input('fieldset_id');
|
$model->fieldset_id = $request->input('fieldset_id');
|
||||||
@@ -155,7 +156,7 @@ class AssetModelsController extends Controller
|
|||||||
$model->category_id = $request->input('category_id');
|
$model->category_id = $request->input('category_id');
|
||||||
$model->notes = $request->input('notes');
|
$model->notes = $request->input('notes');
|
||||||
$model->requestable = $request->input('requestable', '0');
|
$model->requestable = $request->input('requestable', '0');
|
||||||
|
$model->require_serial = $request->input('require_serial', 0);
|
||||||
$model->fieldset_id = $request->input('fieldset_id');
|
$model->fieldset_id = $request->input('fieldset_id');
|
||||||
|
|
||||||
if ($model->save()) {
|
if ($model->save()) {
|
||||||
|
|||||||
@@ -65,6 +65,8 @@ class AssetCheckoutController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function store(AssetCheckoutRequest $request, $assetId) : RedirectResponse
|
public function store(AssetCheckoutRequest $request, $assetId) : RedirectResponse
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Check if the asset exists
|
// Check if the asset exists
|
||||||
if (! $asset = Asset::find($assetId)) {
|
if (! $asset = Asset::find($assetId)) {
|
||||||
@@ -81,6 +83,7 @@ class AssetCheckoutController extends Controller
|
|||||||
$admin = auth()->user();
|
$admin = auth()->user();
|
||||||
|
|
||||||
$target = $this->determineCheckoutTarget();
|
$target = $this->determineCheckoutTarget();
|
||||||
|
session()->put(['checkout_to_type' => $target]);
|
||||||
|
|
||||||
$asset = $this->updateAssetLocation($asset, $target);
|
$asset = $this->updateAssetLocation($asset, $target);
|
||||||
|
|
||||||
|
|||||||
@@ -110,17 +110,35 @@ class AssetsController extends Controller
|
|||||||
// This is only necessary on create, not update, since bulk editing is handled
|
// This is only necessary on create, not update, since bulk editing is handled
|
||||||
// differently
|
// differently
|
||||||
$asset_tags = $request->input('asset_tags');
|
$asset_tags = $request->input('asset_tags');
|
||||||
|
$model = AssetModel::find($request->input('model_id'));
|
||||||
|
$serial_errors = [];
|
||||||
|
$serials = $request->input('serials');
|
||||||
|
|
||||||
$settings = Setting::getSettings();
|
$settings = Setting::getSettings();
|
||||||
|
|
||||||
|
//Validate required serial based on model setting
|
||||||
|
for ($a = 1, $aMax = count($asset_tags); $a <= $aMax; $a++) {
|
||||||
|
if ($model && $model->require_serial === 1 && empty($serials[$a])) {
|
||||||
|
$serial_errors["serials.$a"] = trans('admin/hardware/form.serial_required', ['number' => $a]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($serial_errors)) {
|
||||||
|
return redirect()->back()
|
||||||
|
->withInput()
|
||||||
|
->withErrors($serial_errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
$asset = null;
|
||||||
|
$companyId = Company::getIdForCurrentUser($request->input('company_id'));
|
||||||
$successes = [];
|
$successes = [];
|
||||||
$failures = [];
|
$failures = [];
|
||||||
$serials = $request->input('serials');
|
|
||||||
$asset = null;
|
|
||||||
|
|
||||||
for ($a = 1; $a <= count($asset_tags); $a++) {
|
for ($a = 1, $aMax = count($asset_tags); $a <= $aMax; $a++) {
|
||||||
$asset = new Asset();
|
$asset = new Asset();
|
||||||
$asset->model()->associate(AssetModel::find($request->input('model_id')));
|
|
||||||
|
$asset->model()->associate($model);
|
||||||
$asset->name = $request->input('name');
|
$asset->name = $request->input('name');
|
||||||
|
|
||||||
// Check for a corresponding serial
|
// Check for a corresponding serial
|
||||||
@@ -132,7 +150,7 @@ class AssetsController extends Controller
|
|||||||
$asset->asset_tag = $asset_tags[$a];
|
$asset->asset_tag = $asset_tags[$a];
|
||||||
}
|
}
|
||||||
|
|
||||||
$asset->company_id = Company::getIdForCurrentUser($request->input('company_id'));
|
$asset->company_id = $companyId;
|
||||||
$asset->model_id = $request->input('model_id');
|
$asset->model_id = $request->input('model_id');
|
||||||
$asset->order_number = $request->input('order_number');
|
$asset->order_number = $request->input('order_number');
|
||||||
$asset->notes = $request->input('notes');
|
$asset->notes = $request->input('notes');
|
||||||
@@ -172,7 +190,6 @@ class AssetsController extends Controller
|
|||||||
|
|
||||||
// Update custom fields in the database.
|
// Update custom fields in the database.
|
||||||
// Validation for these fields is handled through the AssetRequest form request
|
// Validation for these fields is handled through the AssetRequest form request
|
||||||
$model = AssetModel::find($request->get('model_id'));
|
|
||||||
|
|
||||||
if (($model) && ($model->fieldset)) {
|
if (($model) && ($model->fieldset)) {
|
||||||
foreach ($model->fieldset->fields as $field) {
|
foreach ($model->fieldset->fields as $field) {
|
||||||
@@ -453,6 +470,13 @@ class AssetsController extends Controller
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
//Validate required serial based on model setting
|
||||||
|
if ($model && $model->require_serial === 1 && empty($serial[1])) {
|
||||||
|
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets'))
|
||||||
|
->with('warning', trans('admin/hardware/form.serial_required_post_model_update', [
|
||||||
|
'asset_model' => $model->name
|
||||||
|
]));
|
||||||
|
}
|
||||||
if ($asset->save()) {
|
if ($asset->save()) {
|
||||||
return Helper::getRedirectOption($request, $asset->id, 'Assets')
|
return Helper::getRedirectOption($request, $asset->id, 'Assets')
|
||||||
->with('success', trans('admin/hardware/message.update.success'));
|
->with('success', trans('admin/hardware/message.update.success'));
|
||||||
|
|||||||
@@ -637,6 +637,7 @@ class BulkAssetsController extends Controller
|
|||||||
$admin = auth()->user();
|
$admin = auth()->user();
|
||||||
|
|
||||||
$target = $this->determineCheckoutTarget();
|
$target = $this->determineCheckoutTarget();
|
||||||
|
session()->put(['checkout_to_type' => $target]);
|
||||||
|
|
||||||
if (! is_array($request->get('selected_assets'))) {
|
if (! is_array($request->get('selected_assets'))) {
|
||||||
return redirect()->route('hardware.bulkcheckout.show')->withInput()->with('error', trans('admin/hardware/message.checkout.no_assets_selected'));
|
return redirect()->route('hardware.bulkcheckout.show')->withInput()->with('error', trans('admin/hardware/message.checkout.no_assets_selected'));
|
||||||
@@ -646,6 +647,15 @@ class BulkAssetsController extends Controller
|
|||||||
|
|
||||||
$assets = Asset::findOrFail($asset_ids);
|
$assets = Asset::findOrFail($asset_ids);
|
||||||
|
|
||||||
|
// Prevent checking out assets that are already checked out
|
||||||
|
if ($assets->pluck('assigned_to')->unique()->filter()->isNotEmpty()) {
|
||||||
|
// re-add the asset ids so the assets select is re-populated
|
||||||
|
$request->session()->flashInput(['selected_assets' => $asset_ids]);
|
||||||
|
|
||||||
|
return redirect(route('hardware.bulkcheckout.show'))
|
||||||
|
->with('error', trans('general.error_assets_already_checked_out'));
|
||||||
|
}
|
||||||
|
|
||||||
if (request('checkout_to_type') == 'asset') {
|
if (request('checkout_to_type') == 'asset') {
|
||||||
foreach ($asset_ids as $asset_id) {
|
foreach ($asset_ids as $asset_id) {
|
||||||
if ($target->id == $asset_id) {
|
if ($target->id == $asset_id) {
|
||||||
|
|||||||
@@ -92,7 +92,9 @@ class BulkAssetModelsController extends Controller
|
|||||||
$update_array['min_amt'] = $request->input('min_amt');
|
$update_array['min_amt'] = $request->input('min_amt');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($request->filled('require_serial')) {
|
||||||
|
$update_array['require_serial'] = $request->input('require_serial');
|
||||||
|
}
|
||||||
|
|
||||||
if (count($update_array) > 0) {
|
if (count($update_array) > 0) {
|
||||||
AssetModel::whereIn('id', $models_raw_array)->update($update_array);
|
AssetModel::whereIn('id', $models_raw_array)->update($update_array);
|
||||||
|
|||||||
@@ -102,13 +102,15 @@ class ComponentCheckoutController extends Controller
|
|||||||
return redirect()->route('components.checkout.show', $componentId)->with('error', trans('general.error_user_company'));
|
return redirect()->route('components.checkout.show', $componentId)->with('error', trans('general.error_user_company'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$component->checkout_qty = $request->input('assigned_qty');
|
||||||
|
|
||||||
// Update the component data
|
// Update the component data
|
||||||
$component->asset_id = $request->input('asset_id');
|
$component->asset_id = $request->input('asset_id');
|
||||||
$component->assets()->attach($component->id, [
|
$component->assets()->attach($component->id, [
|
||||||
'component_id' => $component->id,
|
'component_id' => $component->id,
|
||||||
'created_by' => auth()->user()->id,
|
'created_by' => auth()->user()->id,
|
||||||
'created_at' => date('Y-m-d H:i:s'),
|
'created_at' => date('Y-m-d H:i:s'),
|
||||||
'assigned_qty' => $request->input('assigned_qty'),
|
'assigned_qty' => $component->checkout_qty,
|
||||||
'asset_id' => $request->input('asset_id'),
|
'asset_id' => $request->input('asset_id'),
|
||||||
'note' => $request->input('note'),
|
'note' => $request->input('note'),
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -64,12 +64,7 @@ class LicenseCheckinController extends Controller
|
|||||||
|
|
||||||
$this->authorize('checkout', $license);
|
$this->authorize('checkout', $license);
|
||||||
|
|
||||||
if (! $license->reassignable) {
|
|
||||||
// Not allowed to checkin
|
|
||||||
Session::flash('error', trans('admin/licenses/message.checkin.not_reassignable') . '.');
|
|
||||||
|
|
||||||
return redirect()->back()->withInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Declare the rules for the form validation
|
// Declare the rules for the form validation
|
||||||
$rules = [
|
$rules = [
|
||||||
@@ -98,6 +93,9 @@ class LicenseCheckinController extends Controller
|
|||||||
$licenseSeat->assigned_to = null;
|
$licenseSeat->assigned_to = null;
|
||||||
$licenseSeat->asset_id = null;
|
$licenseSeat->asset_id = null;
|
||||||
$licenseSeat->notes = $request->input('notes');
|
$licenseSeat->notes = $request->input('notes');
|
||||||
|
if (! $licenseSeat->license->reassignable) {
|
||||||
|
$licenseSeat->unreassignable_seat = true;
|
||||||
|
}
|
||||||
|
|
||||||
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||||
if ($request->get('redirect_option') === 'target'){
|
if ($request->get('redirect_option') === 'target'){
|
||||||
@@ -106,7 +104,7 @@ class LicenseCheckinController extends Controller
|
|||||||
|
|
||||||
// Was the asset updated?
|
// Was the asset updated?
|
||||||
if ($licenseSeat->save()) {
|
if ($licenseSeat->save()) {
|
||||||
event(new CheckoutableCheckedIn($licenseSeat, $return_to, auth()->user(), $request->input('notes')));
|
event(new CheckoutableCheckedIn($licenseSeat, $return_to, auth()->user(), $licenseSeat->notes));
|
||||||
|
|
||||||
|
|
||||||
return Helper::getRedirectOption($request, $license->id, 'Licenses')
|
return Helper::getRedirectOption($request, $license->id, 'Licenses')
|
||||||
@@ -132,21 +130,17 @@ class LicenseCheckinController extends Controller
|
|||||||
$license = License::findOrFail($licenseId);
|
$license = License::findOrFail($licenseId);
|
||||||
$this->authorize('checkin', $license);
|
$this->authorize('checkin', $license);
|
||||||
|
|
||||||
if (! $license->reassignable) {
|
|
||||||
// Not allowed to checkin
|
|
||||||
Session::flash('error', 'License not reassignable.');
|
|
||||||
|
|
||||||
return redirect()->back()->withInput();
|
|
||||||
}
|
|
||||||
|
|
||||||
$licenseSeatsByUser = LicenseSeat::where('license_id', '=', $licenseId)
|
$licenseSeatsByUser = LicenseSeat::where('license_id', '=', $licenseId)
|
||||||
->whereNotNull('assigned_to')
|
->whereNotNull('assigned_to')
|
||||||
->with('user')
|
->with('user', 'license')
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
|
$license = $licenseSeatsByUser->first()?->license;
|
||||||
foreach ($licenseSeatsByUser as $user_seat) {
|
foreach ($licenseSeatsByUser as $user_seat) {
|
||||||
$user_seat->assigned_to = null;
|
$user_seat->assigned_to = null;
|
||||||
|
if ($license && ! $license->reassignable) {
|
||||||
|
$user_seat->unreassignable_seat = true;
|
||||||
|
}
|
||||||
if ($user_seat->save()) {
|
if ($user_seat->save()) {
|
||||||
Log::debug('Checking in '.$license->name.' from user '.$user_seat->username);
|
Log::debug('Checking in '.$license->name.' from user '.$user_seat->username);
|
||||||
$user_seat->logCheckin($user_seat->user, trans('admin/licenses/general.bulk.checkin_all.log_msg'));
|
$user_seat->logCheckin($user_seat->user, trans('admin/licenses/general.bulk.checkin_all.log_msg'));
|
||||||
@@ -159,9 +153,12 @@ class LicenseCheckinController extends Controller
|
|||||||
->get();
|
->get();
|
||||||
|
|
||||||
$count = 0;
|
$count = 0;
|
||||||
|
$license = $licenseSeatsByAsset->first()?->license;
|
||||||
foreach ($licenseSeatsByAsset as $asset_seat) {
|
foreach ($licenseSeatsByAsset as $asset_seat) {
|
||||||
$asset_seat->asset_id = null;
|
$asset_seat->asset_id = null;
|
||||||
|
if ($license && ! $license->reassignable) {
|
||||||
|
$asset_seat->unreassignable_seat = true;
|
||||||
|
}
|
||||||
if ($asset_seat->save()) {
|
if ($asset_seat->save()) {
|
||||||
Log::debug('Checking in '.$license->name.' from asset '.$asset_seat->asset_tag);
|
Log::debug('Checking in '.$license->name.' from asset '.$asset_seat->asset_tag);
|
||||||
$asset_seat->logCheckin($asset_seat->asset, trans('admin/licenses/general.bulk.checkin_all.log_msg'));
|
$asset_seat->logCheckin($asset_seat->asset, trans('admin/licenses/general.bulk.checkin_all.log_msg'));
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class LicenseCheckoutController extends Controller
|
|||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @param $id
|
* @param $id
|
||||||
* @return \Illuminate\Contracts\View\View
|
* @return \Illuminate\Contracts\View\View |\Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
*/
|
*/
|
||||||
public function create(License $license)
|
public function create(License $license)
|
||||||
@@ -39,6 +39,16 @@ class LicenseCheckoutController extends Controller
|
|||||||
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.not_enough_seats'));
|
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.not_enough_seats'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure the license is expired or terminated
|
||||||
|
if ($license->isInactive()) {
|
||||||
|
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.license_is_inactive'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't currently allow checking out licenses to locations, so we'll reset that to user if needed
|
||||||
|
if (session()->get('checkout_to_type') == 'location') {
|
||||||
|
session()->put(['checkout_to_type' => 'user']);
|
||||||
|
}
|
||||||
|
|
||||||
// Return the checkout view
|
// Return the checkout view
|
||||||
return view('licenses/checkout', compact('license'));
|
return view('licenses/checkout', compact('license'));
|
||||||
}
|
}
|
||||||
@@ -65,22 +75,31 @@ class LicenseCheckoutController extends Controller
|
|||||||
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.not_found'));
|
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.not_found'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$this->authorize('checkout', $license);
|
$this->authorize('checkout', $license);
|
||||||
|
|
||||||
|
// Make sure there is at least one available to checkout
|
||||||
|
if ($license->availCount()->count() < 1) {
|
||||||
|
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.not_enough_seats'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the license is expired or terminated
|
||||||
|
if ($license->isInactive()) {
|
||||||
|
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.license_is_inactive'));
|
||||||
|
}
|
||||||
|
|
||||||
$licenseSeat = $this->findLicenseSeatToCheckout($license, $seatId);
|
$licenseSeat = $this->findLicenseSeatToCheckout($license, $seatId);
|
||||||
$licenseSeat->created_by = auth()->id();
|
$licenseSeat->created_by = auth()->id();
|
||||||
$licenseSeat->notes = $request->input('notes');
|
$licenseSeat->notes = $request->input('notes');
|
||||||
|
|
||||||
|
|
||||||
$checkoutMethod = 'checkoutTo'.ucwords(request('checkout_to_type'));
|
|
||||||
|
|
||||||
if ($request->filled('asset_id')) {
|
if ($request->filled('asset_id')) {
|
||||||
|
session()->put(['checkout_to_type' => 'asset']);
|
||||||
$checkoutTarget = $this->checkoutToAsset($licenseSeat);
|
$checkoutTarget = $this->checkoutToAsset($licenseSeat);
|
||||||
$request->request->add(['assigned_asset' => $checkoutTarget->id]);
|
$request->request->add(['assigned_asset' => $checkoutTarget->id]);
|
||||||
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => 'asset']);
|
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => 'asset']);
|
||||||
|
|
||||||
} elseif ($request->filled('assigned_to')) {
|
} elseif ($request->filled('assigned_to')) {
|
||||||
|
session()->put(['checkout_to_type' => 'user']);
|
||||||
$checkoutTarget = $this->checkoutToUser($licenseSeat);
|
$checkoutTarget = $this->checkoutToUser($licenseSeat);
|
||||||
$request->request->add(['assigned_user' => $checkoutTarget->id]);
|
$request->request->add(['assigned_user' => $checkoutTarget->id]);
|
||||||
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => 'user']);
|
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => 'user']);
|
||||||
@@ -89,6 +108,7 @@ class LicenseCheckoutController extends Controller
|
|||||||
|
|
||||||
|
|
||||||
if ($checkoutTarget) {
|
if ($checkoutTarget) {
|
||||||
|
|
||||||
return Helper::getRedirectOption($request, $license->id, 'Licenses')
|
return Helper::getRedirectOption($request, $license->id, 'Licenses')
|
||||||
->with('success', trans('admin/licenses/message.checkout.success'));
|
->with('success', trans('admin/licenses/message.checkout.success'));
|
||||||
}
|
}
|
||||||
@@ -110,6 +130,7 @@ class LicenseCheckoutController extends Controller
|
|||||||
throw new \Illuminate\Http\Exceptions\HttpResponseException(redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.not_enough_seats')));
|
throw new \Illuminate\Http\Exceptions\HttpResponseException(redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.not_enough_seats')));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (! $licenseSeat->license->is($license)) {
|
if (! $licenseSeat->license->is($license)) {
|
||||||
throw new \Illuminate\Http\Exceptions\HttpResponseException(redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.mismatch')));
|
throw new \Illuminate\Http\Exceptions\HttpResponseException(redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.mismatch')));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -245,16 +245,28 @@ class LicensesController extends Controller
|
|||||||
$license = License::with('assignedusers')->find($license->id);
|
$license = License::with('assignedusers')->find($license->id);
|
||||||
|
|
||||||
$users_count = User::where('autoassign_licenses', '1')->count();
|
$users_count = User::where('autoassign_licenses', '1')->count();
|
||||||
$total_seats_count = $license->totalSeatsByLicenseID();
|
|
||||||
|
$total_seats_count = (int) $license->totalSeatsByLicenseID();
|
||||||
$available_seats_count = $license->availCount()->count();
|
$available_seats_count = $license->availCount()->count();
|
||||||
$checkedout_seats_count = ($total_seats_count - $available_seats_count);
|
$unreassignable_seats_count = License::unReassignableCount($license);
|
||||||
|
|
||||||
|
if(!$license->reassignable){
|
||||||
|
$checkedout_seats_count = ($total_seats_count - $available_seats_count - $unreassignable_seats_count );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$checkedout_seats_count = ($total_seats_count - $available_seats_count);
|
||||||
|
}
|
||||||
|
if($license->isInactive()){
|
||||||
|
session()->flash('warning', (trans('admin/licenses/message.checkout.license_is_inactive')));
|
||||||
|
}
|
||||||
|
|
||||||
$this->authorize('view', $license);
|
$this->authorize('view', $license);
|
||||||
return view('licenses.view', compact('license'))
|
return view('licenses.view', compact('license'))
|
||||||
->with('users_count', $users_count)
|
->with('users_count', $users_count)
|
||||||
->with('total_seats_count', $total_seats_count)
|
->with('total_seats_count', $total_seats_count)
|
||||||
->with('available_seats_count', $available_seats_count)
|
->with('available_seats_count', $available_seats_count)
|
||||||
->with('checkedout_seats_count', $checkedout_seats_count);
|
->with('checkedout_seats_count', $checkedout_seats_count)
|
||||||
|
->with('unreassignable_seats_count', $unreassignable_seats_count);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -189,30 +189,36 @@ class LocationsController extends Controller
|
|||||||
{
|
{
|
||||||
$this->authorize('delete', Location::class);
|
$this->authorize('delete', Location::class);
|
||||||
|
|
||||||
if (is_null($location = Location::find($locationId))) {
|
$location = Location::withCount('assignedAssets as assigned_assets_count')
|
||||||
|
->withCount('assets as assets_count')
|
||||||
|
->withCount('assignedAccessories as assigned_accessories_count')
|
||||||
|
->withCount('accessories as accessories_count')
|
||||||
|
->withCount('rtd_assets as rtd_assets_count')
|
||||||
|
->withCount('children as children_count')
|
||||||
|
->withCount('users as users_count')
|
||||||
|
->withCount('consumables as consumables_count')
|
||||||
|
->withCount('components as components_count')
|
||||||
|
->find($locationId);
|
||||||
|
|
||||||
|
if (!$location) {
|
||||||
return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.does_not_exist'));
|
return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.does_not_exist'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($location->users()->count() > 0) {
|
if ($location->isDeletable()) {
|
||||||
return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.assoc_users'));
|
|
||||||
} elseif ($location->children()->count() > 0) {
|
|
||||||
return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.assoc_child_loc'));
|
|
||||||
} elseif ($location->assets()->count() > 0) {
|
|
||||||
return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.assoc_assets'));
|
|
||||||
} elseif ($location->assignedassets()->count() > 0) {
|
|
||||||
return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.assoc_assets'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($location->image) {
|
if ($location->image) {
|
||||||
try {
|
try {
|
||||||
Storage::disk('public')->delete('locations/'.$location->image);
|
Storage::disk('public')->delete('locations/'.$location->image);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
Log::error($e);
|
Log::error($e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
$location->delete();
|
||||||
|
return redirect()->to(route('locations.index'))->with('success', trans('admin/locations/message.delete.success'));
|
||||||
|
} else {
|
||||||
|
return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.assoc_users'));
|
||||||
}
|
}
|
||||||
$location->delete();
|
|
||||||
|
|
||||||
return redirect()->to(route('locations.index'))->with('success', trans('admin/locations/message.delete.success'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -247,23 +253,41 @@ class LocationsController extends Controller
|
|||||||
$this->authorize('view', Location::class);
|
$this->authorize('view', Location::class);
|
||||||
|
|
||||||
if ($location = Location::where('id', $id)->first()) {
|
if ($location = Location::where('id', $id)->first()) {
|
||||||
$parent = Location::where('id', $location->parent_id)->first();
|
|
||||||
$manager = User::where('id', $location->manager_id)->first();
|
|
||||||
$company = Company::where('id', $location->company_id)->first();
|
|
||||||
$users = User::where('location_id', $id)->with('company', 'department', 'location')->get();
|
|
||||||
$assets = Asset::where('assigned_to', $id)->where('assigned_type', Location::class)->with('model', 'model.category')->get();
|
|
||||||
return view('locations/print')
|
return view('locations/print')
|
||||||
->with('assets', $assets)
|
->with('assigned', false)
|
||||||
->with('users',$users)
|
->with('assets', $location->assets)
|
||||||
|
->with('assignedAssets', $location->assignedAssets)
|
||||||
|
->with('accessories', $location->accessories)
|
||||||
|
->with('assignedAccessories', $location->assignedAccessories)
|
||||||
|
->with('users',$location->users)
|
||||||
->with('location', $location)
|
->with('location', $location)
|
||||||
->with('parent', $parent)
|
->with('consumables', $location->consumables)
|
||||||
->with('manager', $manager)
|
->with('components', $location->components)
|
||||||
->with('company', $company);
|
->with('children', $location->children);
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
|
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function print_all_assigned($id) : View | RedirectResponse
|
||||||
|
{
|
||||||
|
$this->authorize('view', Location::class);
|
||||||
|
if ($location = Location::where('id', $id)->first()) {
|
||||||
|
return view('locations/print')
|
||||||
|
->with('assigned', true)
|
||||||
|
->with('assets', $location->assets)
|
||||||
|
->with('assignedAssets', $location->assignedAssets)
|
||||||
|
->with('accessories', $location->accessories)
|
||||||
|
->with('assignedAccessories', $location->assignedAccessories)
|
||||||
|
->with('users',$location->users)
|
||||||
|
->with('location', $location)
|
||||||
|
->with('consumables', $location->consumables)
|
||||||
|
->with('components', $location->components)
|
||||||
|
->with('children', $location->children);
|
||||||
|
}
|
||||||
|
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a view that presents a form to clone a location.
|
* Returns a view that presents a form to clone a location.
|
||||||
@@ -321,33 +345,12 @@ class LocationsController extends Controller
|
|||||||
return redirect()->route('locations.index')->with('success', trans('admin/locations/message.restore.success'));
|
return redirect()->route('locations.index')->with('success', trans('admin/locations/message.restore.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check validation
|
|
||||||
return redirect()->back()->with('error', trans('general.could_not_restore', ['item_type' => trans('general.location'), 'error' => $location->getErrors()->first()]));
|
return redirect()->back()->with('error', trans('general.could_not_restore', ['item_type' => trans('general.location'), 'error' => $location->getErrors()->first()]));
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->back()->with('error', trans('admin/models/message.does_not_exist'));
|
return redirect()->back()->with('error', trans('admin/models/message.does_not_exist'));
|
||||||
|
|
||||||
}
|
}
|
||||||
public function print_all_assigned($id) : View | RedirectResponse
|
|
||||||
{
|
|
||||||
$this->authorize('view', Location::class);
|
|
||||||
if ($location = Location::where('id', $id)->first()) {
|
|
||||||
$parent = Location::where('id', $location->parent_id)->first();
|
|
||||||
$manager = User::where('id', $location->manager_id)->first();
|
|
||||||
$company = Company::where('id', $location->company_id)->first();
|
|
||||||
$users = User::where('location_id', $id)->with('company', 'department', 'location')->get();
|
|
||||||
$assets = Asset::where('location_id', $id)->with('model', 'model.category')->get();
|
|
||||||
return view('locations/print')
|
|
||||||
->with('assets', $assets)
|
|
||||||
->with('users',$users)
|
|
||||||
->with('location', $location)
|
|
||||||
->with('parent', $parent)
|
|
||||||
->with('manager', $manager)
|
|
||||||
->with('company', $company);
|
|
||||||
}
|
|
||||||
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a view that allows the user to bulk delete locations
|
* Returns a view that allows the user to bulk delete locations
|
||||||
@@ -366,8 +369,12 @@ class LocationsController extends Controller
|
|||||||
$locations = Location::whereIn('id', $locations_raw_array)
|
$locations = Location::whereIn('id', $locations_raw_array)
|
||||||
->withCount('assignedAssets as assigned_assets_count')
|
->withCount('assignedAssets as assigned_assets_count')
|
||||||
->withCount('assets as assets_count')
|
->withCount('assets as assets_count')
|
||||||
|
->withCount('assignedAccessories as assigned_accessories_count')
|
||||||
|
->withCount('accessories as accessories_count')
|
||||||
->withCount('rtd_assets as rtd_assets_count')
|
->withCount('rtd_assets as rtd_assets_count')
|
||||||
->withCount('children as children_count')
|
->withCount('children as children_count')
|
||||||
|
->withCount('consumables as consumables_count')
|
||||||
|
->withCount('components as components_count')
|
||||||
->withCount('users as users_count')->get();
|
->withCount('users as users_count')->get();
|
||||||
|
|
||||||
$valid_count = 0;
|
$valid_count = 0;
|
||||||
@@ -400,9 +407,13 @@ class LocationsController extends Controller
|
|||||||
$locations = Location::whereIn('id', $locations_raw_array)
|
$locations = Location::whereIn('id', $locations_raw_array)
|
||||||
->withCount('assignedAssets as assigned_assets_count')
|
->withCount('assignedAssets as assigned_assets_count')
|
||||||
->withCount('assets as assets_count')
|
->withCount('assets as assets_count')
|
||||||
|
->withCount('assignedAccessories as assigned_accessories_count')
|
||||||
|
->withCount('accessories as accessories_count')
|
||||||
->withCount('rtd_assets as rtd_assets_count')
|
->withCount('rtd_assets as rtd_assets_count')
|
||||||
->withCount('children as children_count')
|
->withCount('children as children_count')
|
||||||
->withCount('users as users_count')->get();
|
->withCount('users as users_count')
|
||||||
|
->withCount('consumables as consumables_count')
|
||||||
|
->withCount('components as components_count')->get();
|
||||||
|
|
||||||
$success_count = 0;
|
$success_count = 0;
|
||||||
$error_count = 0;
|
$error_count = 0;
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ class ReportsController extends Controller
|
|||||||
$row[] = e($asset->serial);
|
$row[] = e($asset->serial);
|
||||||
|
|
||||||
if ($target = $asset->assignedTo) {
|
if ($target = $asset->assignedTo) {
|
||||||
$row[] = e($target->present()->name());
|
$row[] = e($target->display_name);
|
||||||
} else {
|
} else {
|
||||||
$row[] = ''; // Empty string if unassigned
|
$row[] = ''; // Empty string if unassigned
|
||||||
}
|
}
|
||||||
@@ -274,22 +274,18 @@ class ReportsController extends Controller
|
|||||||
$target_name = '';
|
$target_name = '';
|
||||||
|
|
||||||
if ($actionlog->target) {
|
if ($actionlog->target) {
|
||||||
if ($actionlog->targetType() == 'user') {
|
$target_name = $actionlog->target->display_name;
|
||||||
$target_name = $actionlog->target->display_name;
|
|
||||||
} else {
|
|
||||||
$target_name = $actionlog->target->getDisplayNameAttribute();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if($actionlog->item){
|
if ($actionlog->item){
|
||||||
$item_name = e($actionlog->item->getDisplayNameAttribute());
|
$item_name = e($actionlog->item->display_name);
|
||||||
} else {
|
} else {
|
||||||
$item_name = '';
|
$item_name = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$row = [
|
$row = [
|
||||||
$actionlog->created_at,
|
$actionlog->created_at,
|
||||||
($actionlog->adminuser) ? e($actionlog->adminuser->display_name) : '',
|
($actionlog->adminuser) ? $actionlog->adminuser->display_name : '',
|
||||||
$actionlog->present()->actionType(),
|
$actionlog->present()->actionType(),
|
||||||
e($actionlog->itemType()),
|
e($actionlog->itemType()),
|
||||||
($actionlog->itemType() == 'user') ? $actionlog->filename : $item_name,
|
($actionlog->itemType() == 'user') ? $actionlog->filename : $item_name,
|
||||||
@@ -298,10 +294,10 @@ class ReportsController extends Controller
|
|||||||
(($actionlog->item) && ($actionlog->item->model)) ? $actionlog->item->model->model_number : null,
|
(($actionlog->item) && ($actionlog->item->model)) ? $actionlog->item->model->model_number : null,
|
||||||
$target_name,
|
$target_name,
|
||||||
($actionlog->note) ? e($actionlog->note) : '',
|
($actionlog->note) ? e($actionlog->note) : '',
|
||||||
$actionlog->log_meta,
|
|
||||||
$actionlog->remote_ip,
|
$actionlog->remote_ip,
|
||||||
$actionlog->user_agent,
|
$actionlog->user_agent,
|
||||||
$actionlog->action_source,
|
$actionlog->action_source,
|
||||||
|
$actionlog->log_meta,
|
||||||
];
|
];
|
||||||
fputcsv($handle, $row);
|
fputcsv($handle, $row);
|
||||||
}
|
}
|
||||||
@@ -830,7 +826,7 @@ class ReportsController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($request->filled('location')) {
|
if ($request->filled('location')) {
|
||||||
$row[] = ($asset->location) ? $asset->location->present()->name() : '';
|
$row[] = ($asset->location) ? $asset->location->display_name : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->filled('location_address')) {
|
if ($request->filled('location_address')) {
|
||||||
@@ -843,7 +839,7 @@ class ReportsController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($request->filled('rtd_location')) {
|
if ($request->filled('rtd_location')) {
|
||||||
$row[] = ($asset->defaultLoc) ? $asset->defaultLoc->present()->name() : '';
|
$row[] = ($asset->defaultLoc) ? $asset->defaultLoc->display_name : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->filled('rtd_location_address')) {
|
if ($request->filled('rtd_location_address')) {
|
||||||
@@ -856,8 +852,8 @@ class ReportsController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($request->filled('assigned_to')) {
|
if ($request->filled('assigned_to')) {
|
||||||
$row[] = ($asset->checkedOutToUser() && $asset->assigned) ?? $asset->assigned->display_name;
|
$row[] = ($asset->assigned) ? $asset->assigned->display_name : '';
|
||||||
$row[] = ($asset->checkedOutToUser() && $asset->assigned) ? 'user' : $asset->assignedType();
|
$row[] = ($asset->assigned) ? $asset->assignedType() : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->filled('username')) {
|
if ($request->filled('username')) {
|
||||||
@@ -1260,7 +1256,7 @@ class ReportsController extends Controller
|
|||||||
$row[] = str_replace(',', '', e($item['assetItem']->model->name));
|
$row[] = str_replace(',', '', e($item['assetItem']->model->name));
|
||||||
$row[] = str_replace(',', '', e($item['assetItem']->name));
|
$row[] = str_replace(',', '', e($item['assetItem']->name));
|
||||||
$row[] = str_replace(',', '', e($item['assetItem']->asset_tag));
|
$row[] = str_replace(',', '', e($item['assetItem']->asset_tag));
|
||||||
$row[] = str_replace(',', '', e(($item['acceptance']->assignedTo) ? $item['acceptance']->assignedTo->present()->name() : trans('admin/reports/general.deleted_user')));
|
$row[] = str_replace(',', '', e(($item['acceptance']->assignedTo) ? $item['acceptance']->assignedTo->display_name : trans('admin/reports/general.deleted_user')));
|
||||||
$rows[] = implode(',', $row);
|
$rows[] = implode(',', $row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class UploadedFilesController extends Controller
|
|||||||
{
|
{
|
||||||
|
|
||||||
// Check the permissions to make sure the user can view the object
|
// Check the permissions to make sure the user can view the object
|
||||||
$object = self::$map_object_type[$object_type]::find($id);
|
$object = self::$map_object_type[$object_type]::withTrashed()->find($id);
|
||||||
$this->authorize('update', $object);
|
$this->authorize('update', $object);
|
||||||
|
|
||||||
if (!$object) {
|
if (!$object) {
|
||||||
@@ -85,7 +85,7 @@ class UploadedFilesController extends Controller
|
|||||||
public function show($object_type, $id, $file_id) : RedirectResponse | StreamedResponse | Storage | StorageHelper | BinaryFileResponse
|
public function show($object_type, $id, $file_id) : RedirectResponse | StreamedResponse | Storage | StorageHelper | BinaryFileResponse
|
||||||
{
|
{
|
||||||
// Check the permissions to make sure the user can view the object
|
// Check the permissions to make sure the user can view the object
|
||||||
$object = self::$map_object_type[$object_type]::find($id);
|
$object = self::$map_object_type[$object_type]::withTrashed()->find($id);
|
||||||
$this->authorize('view', $object);
|
$this->authorize('view', $object);
|
||||||
|
|
||||||
if (!$object) {
|
if (!$object) {
|
||||||
@@ -130,7 +130,7 @@ class UploadedFilesController extends Controller
|
|||||||
{
|
{
|
||||||
|
|
||||||
// Check the permissions to make sure the user can view the object
|
// Check the permissions to make sure the user can view the object
|
||||||
$object = self::$map_object_type[$object_type]::find($id);
|
$object = self::$map_object_type[$object_type]::withTrashed()->find($id);
|
||||||
$this->authorize('update', self::$map_object_type[$object_type]);
|
$this->authorize('update', self::$map_object_type[$object_type]);
|
||||||
|
|
||||||
if (!$object) {
|
if (!$object) {
|
||||||
@@ -139,7 +139,7 @@ class UploadedFilesController extends Controller
|
|||||||
|
|
||||||
|
|
||||||
// Check for the file
|
// Check for the file
|
||||||
$log = Actionlog::find($file_id)->where('item_type', self::$map_object_type[$object_type])
|
$log = Actionlog::where('id',$file_id)->where('item_type', self::$map_object_type[$object_type])
|
||||||
->where('item_id', $object->id)->first();
|
->where('item_id', $object->id)->first();
|
||||||
|
|
||||||
if ($log) {
|
if ($log) {
|
||||||
@@ -148,7 +148,7 @@ class UploadedFilesController extends Controller
|
|||||||
Storage::delete(self::$map_storage_path[$object_type].'/'.$log->filename);
|
Storage::delete(self::$map_storage_path[$object_type].'/'.$log->filename);
|
||||||
}
|
}
|
||||||
// Delete the record of the file
|
// Delete the record of the file
|
||||||
if ($log->delete()) {
|
if ($log->logUploadDelete($object, $log->filename)) {
|
||||||
return redirect()->back()->withFragment('files')->with('success', trans_choice('general.file_upload_status.delete.success', 1));
|
return redirect()->back()->withFragment('files')->with('success', trans_choice('general.file_upload_status.delete.success', 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,10 +34,7 @@ class AssetCountForSidebar
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$total_assets = Asset::count();
|
$total_assets = Asset::AssetsForShow()->count();
|
||||||
if ($settings->show_archived_in_list != '1') {
|
|
||||||
$total_assets -= Asset::Archived()->count();
|
|
||||||
}
|
|
||||||
view()->share('total_assets', $total_assets);
|
view()->share('total_assets', $total_assets);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
Log::debug($e);
|
Log::debug($e);
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ class AccessoriesTransformer
|
|||||||
'qty' => ($accessory->qty) ? (int) $accessory->qty : null,
|
'qty' => ($accessory->qty) ? (int) $accessory->qty : null,
|
||||||
'purchase_date' => ($accessory->purchase_date) ? Helper::getFormattedDateObject($accessory->purchase_date, 'date') : null,
|
'purchase_date' => ($accessory->purchase_date) ? Helper::getFormattedDateObject($accessory->purchase_date, 'date') : null,
|
||||||
'purchase_cost' => Helper::formatCurrencyOutput($accessory->purchase_cost),
|
'purchase_cost' => Helper::formatCurrencyOutput($accessory->purchase_cost),
|
||||||
|
'total_cost' => Helper::formatCurrencyOutput($accessory->totalCostSum()),
|
||||||
'order_number' => ($accessory->order_number) ? e($accessory->order_number) : null,
|
'order_number' => ($accessory->order_number) ? e($accessory->order_number) : null,
|
||||||
'min_qty' => ($accessory->min_amt) ? (int) $accessory->min_amt : null, // Legacy - should phase out - replaced by below, for the bootstrap table formatter
|
'min_qty' => ($accessory->min_amt) ? (int) $accessory->min_amt : null, // Legacy - should phase out - replaced by below, for the bootstrap table formatter
|
||||||
'min_amt' => ($accessory->min_amt) ? (int) $accessory->min_amt : null,
|
'min_amt' => ($accessory->min_amt) ? (int) $accessory->min_amt : null,
|
||||||
|
|||||||
@@ -50,17 +50,20 @@ class ActionlogsTransformer
|
|||||||
|
|
||||||
public function transformActionlog (Actionlog $actionlog, $settings = null)
|
public function transformActionlog (Actionlog $actionlog, $settings = null)
|
||||||
{
|
{
|
||||||
|
|
||||||
$icon = $actionlog->present()->icon();
|
$icon = $actionlog->present()->icon();
|
||||||
|
|
||||||
|
if (($actionlog->filename!='') && ($actionlog->action_type!='upload deleted')) {
|
||||||
|
$icon = Helper::filetype_icon($actionlog->filename);
|
||||||
|
}
|
||||||
|
|
||||||
static $custom_fields = false;
|
static $custom_fields = false;
|
||||||
|
|
||||||
if ($custom_fields === false) {
|
if ($custom_fields === false) {
|
||||||
$custom_fields = CustomField::all();
|
$custom_fields = CustomField::all();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($actionlog->filename!='') {
|
|
||||||
$icon = Helper::filetype_icon($actionlog->filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is necessary since we can't escape special characters within a JSON object
|
// This is necessary since we can't escape special characters within a JSON object
|
||||||
if (($actionlog->log_meta) && ($actionlog->log_meta!='')) {
|
if (($actionlog->log_meta) && ($actionlog->log_meta!='')) {
|
||||||
@@ -144,7 +147,7 @@ class ActionlogsTransformer
|
|||||||
[
|
[
|
||||||
'url' => $actionlog->uploads_file_url(),
|
'url' => $actionlog->uploads_file_url(),
|
||||||
'filename' => $actionlog->filename,
|
'filename' => $actionlog->filename,
|
||||||
'inlineable' => StorageHelper::allowSafeInline($actionlog->uploads_file_url()),
|
'inlineable' => StorageHelper::allowSafeInline($actionlog->uploads_file_path()),
|
||||||
'exists_on_disk' => Storage::exists($actionlog->uploads_file_path()) ? true : false,
|
'exists_on_disk' => Storage::exists($actionlog->uploads_file_path()) ? true : false,
|
||||||
] : null,
|
] : null,
|
||||||
|
|
||||||
@@ -152,7 +155,7 @@ class ActionlogsTransformer
|
|||||||
'id' => (int) $actionlog->item->id,
|
'id' => (int) $actionlog->item->id,
|
||||||
'name' => e($actionlog->item->display_name) ?? null,
|
'name' => e($actionlog->item->display_name) ?? null,
|
||||||
'type' => e($actionlog->itemType()),
|
'type' => e($actionlog->itemType()),
|
||||||
'serial' =>e($actionlog->item->serial) ? e($actionlog->item->serial) : null
|
'serial' => e($actionlog->item->serial) ? e($actionlog->item->serial) : null
|
||||||
] : null,
|
] : null,
|
||||||
'location' => ($actionlog->location) ? [
|
'location' => ($actionlog->location) ? [
|
||||||
'id' => (int) $actionlog->location->id,
|
'id' => (int) $actionlog->location->id,
|
||||||
@@ -165,7 +168,7 @@ class ActionlogsTransformer
|
|||||||
'action_type' => $actionlog->present()->actionType(),
|
'action_type' => $actionlog->present()->actionType(),
|
||||||
'admin' => ($actionlog->adminuser) ? [
|
'admin' => ($actionlog->adminuser) ? [
|
||||||
'id' => (int) $actionlog->adminuser->id,
|
'id' => (int) $actionlog->adminuser->id,
|
||||||
'name' => e($actionlog->adminuser->display_name),
|
'name' => e($actionlog->adminuser->display_name) ?? null,
|
||||||
'first_name'=> e($actionlog->adminuser->first_name),
|
'first_name'=> e($actionlog->adminuser->first_name),
|
||||||
'last_name'=> e($actionlog->adminuser->last_name)
|
'last_name'=> e($actionlog->adminuser->last_name)
|
||||||
] : null,
|
] : null,
|
||||||
@@ -177,7 +180,7 @@ class ActionlogsTransformer
|
|||||||
] : null,
|
] : null,
|
||||||
'target' => ($actionlog->target) ? [
|
'target' => ($actionlog->target) ? [
|
||||||
'id' => (int) $actionlog->target->id,
|
'id' => (int) $actionlog->target->id,
|
||||||
'name' => ($actionlog->target->display_name) ?? null,
|
'name' => e($actionlog->target->display_name) ?? null,
|
||||||
'type' => e($actionlog->targetType()),
|
'type' => e($actionlog->targetType()),
|
||||||
] : null,
|
] : null,
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ class AssetModelsTransformer
|
|||||||
'default_fieldset_values' => $default_field_values,
|
'default_fieldset_values' => $default_field_values,
|
||||||
'eol' => ($assetmodel->eol > 0) ? $assetmodel->eol.' months' : 'None',
|
'eol' => ($assetmodel->eol > 0) ? $assetmodel->eol.' months' : 'None',
|
||||||
'requestable' => ($assetmodel->requestable == '1') ? true : false,
|
'requestable' => ($assetmodel->requestable == '1') ? true : false,
|
||||||
|
'require_serial' => $assetmodel->require_serial,
|
||||||
'notes' => Helper::parseEscapedMarkedownInline($assetmodel->notes),
|
'notes' => Helper::parseEscapedMarkedownInline($assetmodel->notes),
|
||||||
'created_by' => ($assetmodel->adminuser) ? [
|
'created_by' => ($assetmodel->adminuser) ? [
|
||||||
'id' => (int) $assetmodel->adminuser->id,
|
'id' => (int) $assetmodel->adminuser->id,
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ class ComponentsTransformer
|
|||||||
'order_number' => e($component->order_number),
|
'order_number' => e($component->order_number),
|
||||||
'purchase_date' => Helper::getFormattedDateObject($component->purchase_date, 'date'),
|
'purchase_date' => Helper::getFormattedDateObject($component->purchase_date, 'date'),
|
||||||
'purchase_cost' => Helper::formatCurrencyOutput($component->purchase_cost),
|
'purchase_cost' => Helper::formatCurrencyOutput($component->purchase_cost),
|
||||||
|
'total_cost' => Helper::formatCurrencyOutput($component->totalCostSum()),
|
||||||
'remaining' => (int) $component->numRemaining(),
|
'remaining' => (int) $component->numRemaining(),
|
||||||
'company' => ($component->company) ? [
|
'company' => ($component->company) ? [
|
||||||
'id' => (int) $component->company->id,
|
'id' => (int) $component->company->id,
|
||||||
@@ -76,7 +77,7 @@ class ComponentsTransformer
|
|||||||
$array[] = [
|
$array[] = [
|
||||||
'assigned_pivot_id' => $asset->pivot->id,
|
'assigned_pivot_id' => $asset->pivot->id,
|
||||||
'id' => (int) $asset->id,
|
'id' => (int) $asset->id,
|
||||||
'name' => e($asset->model->present()->name).' '.e($asset->present()->name),
|
'name' => e($asset->model->display_name).' '.e($asset->display_name),
|
||||||
'qty' => $asset->pivot->assigned_qty,
|
'qty' => $asset->pivot->assigned_qty,
|
||||||
'note' => $asset->pivot->note,
|
'note' => $asset->pivot->note,
|
||||||
'type' => 'asset',
|
'type' => 'asset',
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ class ConsumablesTransformer
|
|||||||
'remaining' => $consumable->numRemaining(),
|
'remaining' => $consumable->numRemaining(),
|
||||||
'order_number' => e($consumable->order_number),
|
'order_number' => e($consumable->order_number),
|
||||||
'purchase_cost' => Helper::formatCurrencyOutput($consumable->purchase_cost),
|
'purchase_cost' => Helper::formatCurrencyOutput($consumable->purchase_cost),
|
||||||
|
'total_cost' => Helper::formatCurrencyOutput($consumable->totalCostSum()),
|
||||||
'purchase_date' => Helper::getFormattedDateObject($consumable->purchase_date, 'date'),
|
'purchase_date' => Helper::getFormattedDateObject($consumable->purchase_date, 'date'),
|
||||||
'qty' => (int) $consumable->qty,
|
'qty' => (int) $consumable->qty,
|
||||||
'notes' => ($consumable->notes) ? Helper::parseEscapedMarkedownInline($consumable->notes) : null,
|
'notes' => ($consumable->notes) ? Helper::parseEscapedMarkedownInline($consumable->notes) : null,
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ use App\Models\License;
|
|||||||
use App\Models\LicenseSeat;
|
use App\Models\LicenseSeat;
|
||||||
use Illuminate\Support\Facades\Gate;
|
use Illuminate\Support\Facades\Gate;
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
|
||||||
class LicenseSeatsTransformer
|
class LicenseSeatsTransformer
|
||||||
{
|
{
|
||||||
public function transformLicenseSeats(Collection $seats, $total)
|
public function transformLicenseSeats(Collection $seats, $total)
|
||||||
@@ -52,6 +51,7 @@ class LicenseSeatsTransformer
|
|||||||
'reassignable' => (bool) $seat->license->reassignable,
|
'reassignable' => (bool) $seat->license->reassignable,
|
||||||
'notes' => e($seat->notes),
|
'notes' => e($seat->notes),
|
||||||
'user_can_checkout' => (($seat->assigned_to == '') && ($seat->asset_id == '')),
|
'user_can_checkout' => (($seat->assigned_to == '') && ($seat->asset_id == '')),
|
||||||
|
'disabled' => $seat->unreassignable_seat || $seat->license->isInactive(),
|
||||||
];
|
];
|
||||||
|
|
||||||
$permissions_array['available_actions'] = [
|
$permissions_array['available_actions'] = [
|
||||||
|
|||||||
@@ -31,13 +31,13 @@ class LicensesTransformer
|
|||||||
'purchase_order' => ($license->purchase_order) ? e($license->purchase_order) : null,
|
'purchase_order' => ($license->purchase_order) ? e($license->purchase_order) : null,
|
||||||
'purchase_date' => Helper::getFormattedDateObject($license->purchase_date, 'date'),
|
'purchase_date' => Helper::getFormattedDateObject($license->purchase_date, 'date'),
|
||||||
'termination_date' => Helper::getFormattedDateObject($license->termination_date, 'date'),
|
'termination_date' => Helper::getFormattedDateObject($license->termination_date, 'date'),
|
||||||
|
'expiration_date' => Helper::getFormattedDateObject($license->expiration_date, 'date'),
|
||||||
'depreciation' => ($license->depreciation) ? ['id' => (int) $license->depreciation->id,'name'=> e($license->depreciation->name)] : null,
|
'depreciation' => ($license->depreciation) ? ['id' => (int) $license->depreciation->id,'name'=> e($license->depreciation->name)] : null,
|
||||||
'purchase_cost' => Helper::formatCurrencyOutput($license->purchase_cost),
|
'purchase_cost' => Helper::formatCurrencyOutput($license->purchase_cost),
|
||||||
'purchase_cost_numeric' => $license->purchase_cost,
|
'purchase_cost_numeric' => $license->purchase_cost,
|
||||||
'notes' => Helper::parseEscapedMarkedownInline($license->notes),
|
'notes' => Helper::parseEscapedMarkedownInline($license->notes),
|
||||||
'expiration_date' => Helper::getFormattedDateObject($license->expiration_date, 'date'),
|
|
||||||
'seats' => (int) $license->seats,
|
'seats' => (int) $license->seats,
|
||||||
'free_seats_count' => (int) $license->free_seats_count,
|
'free_seats_count' => (int) $license->free_seats_count - License::unReassignableCount($license),
|
||||||
'remaining' => (int) $license->free_seats_count,
|
'remaining' => (int) $license->free_seats_count,
|
||||||
'min_amt' => ($license->min_amt) ? (int) ($license->min_amt) : null,
|
'min_amt' => ($license->min_amt) ? (int) ($license->min_amt) : null,
|
||||||
'license_name' => ($license->license_name) ? e($license->license_name) : null,
|
'license_name' => ($license->license_name) ? e($license->license_name) : null,
|
||||||
@@ -54,7 +54,7 @@ class LicensesTransformer
|
|||||||
'updated_at' => Helper::getFormattedDateObject($license->updated_at, 'datetime'),
|
'updated_at' => Helper::getFormattedDateObject($license->updated_at, 'datetime'),
|
||||||
'deleted_at' => Helper::getFormattedDateObject($license->deleted_at, 'datetime'),
|
'deleted_at' => Helper::getFormattedDateObject($license->deleted_at, 'datetime'),
|
||||||
'user_can_checkout' => (bool) ($license->free_seats_count > 0),
|
'user_can_checkout' => (bool) ($license->free_seats_count > 0),
|
||||||
|
'disabled' => $license->isInactive(),
|
||||||
];
|
];
|
||||||
|
|
||||||
$permissions_array['available_actions'] = [
|
$permissions_array['available_actions'] = [
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ class LocationsTransformer
|
|||||||
'assets_count' => (int) $location->assets_count,
|
'assets_count' => (int) $location->assets_count,
|
||||||
'rtd_assets_count' => (int) $location->rtd_assets_count,
|
'rtd_assets_count' => (int) $location->rtd_assets_count,
|
||||||
'users_count' => (int) $location->users_count,
|
'users_count' => (int) $location->users_count,
|
||||||
|
'consumables_count' => (int) $location->consumables_count,
|
||||||
|
'components_count' => (int) $location->components_count,
|
||||||
|
'children_count' => (int) $location->children_count,
|
||||||
'currency' => ($location->currency) ? e($location->currency) : null,
|
'currency' => ($location->currency) ? e($location->currency) : null,
|
||||||
'ldap_ou' => ($location->ldap_ou) ? e($location->ldap_ou) : null,
|
'ldap_ou' => ($location->ldap_ou) ? e($location->ldap_ou) : null,
|
||||||
'notes' => Helper::parseEscapedMarkedownInline($location->notes),
|
'notes' => Helper::parseEscapedMarkedownInline($location->notes),
|
||||||
@@ -76,12 +79,13 @@ class LocationsTransformer
|
|||||||
];
|
];
|
||||||
|
|
||||||
$permissions_array['available_actions'] = [
|
$permissions_array['available_actions'] = [
|
||||||
'update' => Gate::allows('update', Location::class) ? true : false,
|
'update' => (Gate::allows('update', Location::class) && ($location->deleted_at == '')),
|
||||||
'delete' => $location->isDeletable(),
|
'delete' => $location->isDeletable(),
|
||||||
'bulk_selectable' => [
|
'bulk_selectable' => [
|
||||||
'delete' => $location->isDeletable()
|
'delete' => $location->isDeletable()
|
||||||
],
|
],
|
||||||
'clone' => (Gate::allows('create', Location::class) && ($location->deleted_at == '')),
|
'clone' => (Gate::allows('create', Location::class) && ($location->deleted_at == '')),
|
||||||
|
'restore' => (Gate::allows('create', Location::class) && ($location->deleted_at != '')),
|
||||||
];
|
];
|
||||||
|
|
||||||
$array += $permissions_array;
|
$array += $permissions_array;
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ namespace App\Http\Transformers;
|
|||||||
|
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use App\Models\Asset;
|
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
|
||||||
class ProfileTransformer
|
class ProfileTransformer
|
||||||
@@ -26,7 +25,7 @@ class ProfileTransformer
|
|||||||
'id' => (int) $file->id,
|
'id' => (int) $file->id,
|
||||||
'icon' => Helper::filetype_icon($file->filename),
|
'icon' => Helper::filetype_icon($file->filename),
|
||||||
'item' => ($file->item) ? [
|
'item' => ($file->item) ? [
|
||||||
'name' => ($file->itemType()=='user') ? e($file->item->display_name) : e($file->item->getDisplayNameAttribute()),
|
'name' => $file->item->display_name ? e($file->item->display_name) : null,
|
||||||
'type' => e($file->itemType()),
|
'type' => e($file->itemType()),
|
||||||
] : null,
|
] : null,
|
||||||
'filename' => e($file->filename),
|
'filename' => e($file->filename),
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class UsersTransformer
|
|||||||
public function transformUser(User $user)
|
public function transformUser(User $user)
|
||||||
{
|
{
|
||||||
|
|
||||||
$role = '';
|
$role = null;
|
||||||
if ($user->isSuperUser()) {
|
if ($user->isSuperUser()) {
|
||||||
$role = 'superadmin';
|
$role = 'superadmin';
|
||||||
} elseif ($user->isAdmin()) {
|
} elseif ($user->isAdmin()) {
|
||||||
@@ -34,7 +34,7 @@ class UsersTransformer
|
|||||||
'name' => e($user->getFullNameAttribute()) ?? null,
|
'name' => e($user->getFullNameAttribute()) ?? null,
|
||||||
'first_name' => e($user->first_name) ?? null,
|
'first_name' => e($user->first_name) ?? null,
|
||||||
'last_name' => e($user->last_name) ?? null,
|
'last_name' => e($user->last_name) ?? null,
|
||||||
'display_name' => e($user->getRawOriginal('display_name')) ?? null,
|
'display_name' => ($user->getRawOriginal('display_name')) ? e($user->getRawOriginal('display_name')) : null,
|
||||||
'username' => e($user->username) ?? null,
|
'username' => e($user->username) ?? null,
|
||||||
'remote' => ($user->remote == '1') ? true : false,
|
'remote' => ($user->remote == '1') ? true : false,
|
||||||
'locale' => ($user->locale) ? e($user->locale) : null,
|
'locale' => ($user->locale) ? e($user->locale) : null,
|
||||||
|
|||||||
@@ -40,11 +40,32 @@ class AssetModelImporter extends ItemImporter
|
|||||||
{
|
{
|
||||||
|
|
||||||
$editingAssetModel = false;
|
$editingAssetModel = false;
|
||||||
$assetModel = AssetModel::where('name', '=', $this->findCsvMatch($row, 'name'))->first();
|
|
||||||
|
/**
|
||||||
|
* This part gets a little confusing, since folks might be importing multiple models with the same name and different model numbers for the first time
|
||||||
|
* or they might be wanting to update existing models with new model numbers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// They are not trying to update existing models, so we'll check for duplicates with model name *and* number
|
||||||
|
if (! $this->updating) {
|
||||||
|
$this->log('Finding model by name and model number: '.$this->findCsvMatch($row, 'name').' / '.$this->findCsvMatch($row, 'model_number'));
|
||||||
|
$assetModel = AssetModel::where('name', '=', $this->findCsvMatch($row, 'name'))->where('model_number', '=', $this->findCsvMatch($row, 'model_number'))->first();
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if ($this->findCsvMatch($row, 'id')!='') {
|
||||||
|
// Override model if an ID was given
|
||||||
|
$this->log('Finding model by ID: '.$this->findCsvMatch($row, 'id'));
|
||||||
|
$assetModel = AssetModel::find($this->findCsvMatch($row, 'id'));
|
||||||
|
} else {
|
||||||
|
$this->log('Finding model by name: '.$this->findCsvMatch($row, 'name'));
|
||||||
|
$assetModel = AssetModel::where('name', '=', $this->findCsvMatch($row, 'name'))->first();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if ($assetModel) {
|
if ($assetModel) {
|
||||||
if (! $this->updating) {
|
if (! $this->updating) {
|
||||||
$this->log('A matching Model '.$this->item['name'].' already exists');
|
$this->log('A matching Model '.$this->item['name'].' already exists and we are not updating. Skipping.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,6 +87,7 @@ class AssetModelImporter extends ItemImporter
|
|||||||
$this->item['fieldset'] = trim($this->findCsvMatch($row, 'fieldset'));
|
$this->item['fieldset'] = trim($this->findCsvMatch($row, 'fieldset'));
|
||||||
$this->item['depreciation'] = trim($this->findCsvMatch($row, 'depreciation'));
|
$this->item['depreciation'] = trim($this->findCsvMatch($row, 'depreciation'));
|
||||||
$this->item['requestable'] = trim(($this->fetchHumanBoolean($this->findCsvMatch($row, 'requestable'))) == 1) ? 1 : 0;
|
$this->item['requestable'] = trim(($this->fetchHumanBoolean($this->findCsvMatch($row, 'requestable'))) == 1) ? 1 : 0;
|
||||||
|
$this->item['require_serial'] = trim(($this->fetchHumanBoolean($this->findCsvMatch($row, 'require_serial'))) == 1) ? 1 : 0;
|
||||||
|
|
||||||
if (!empty($this->item['category'])) {
|
if (!empty($this->item['category'])) {
|
||||||
if ($category = $this->createOrFetchCategory($this->item['category'])) {
|
if ($category = $this->createOrFetchCategory($this->item['category'])) {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class ManufacturerImporter extends ItemImporter
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a supplier if a duplicate does not exist.
|
* Create a manufacturer if a duplicate does not exist.
|
||||||
* @todo Investigate how this should interact with Importer::createManufacturerIfNotExists
|
* @todo Investigate how this should interact with Importer::createManufacturerIfNotExists
|
||||||
*
|
*
|
||||||
* @author A. Gianotto
|
* @author A. Gianotto
|
||||||
@@ -39,16 +39,16 @@ class ManufacturerImporter extends ItemImporter
|
|||||||
|
|
||||||
$editingManufacturer = false;
|
$editingManufacturer = false;
|
||||||
|
|
||||||
$supplier = Manufacturer::where('name', '=', $this->findCsvMatch($row, 'name'))->first();
|
$manufacturer = Manufacturer::where('name', '=', $this->findCsvMatch($row, 'name'))->first();
|
||||||
|
|
||||||
if ($this->findCsvMatch($row, 'id')!='') {
|
if ($this->findCsvMatch($row, 'id')!='') {
|
||||||
// Override supplier if an ID was given
|
// Override manufacturer if an ID was given
|
||||||
\Log::debug('Finding supplier by ID: '.$this->findCsvMatch($row, 'id'));
|
\Log::debug('Finding manufacturer by ID: '.$this->findCsvMatch($row, 'id'));
|
||||||
$supplier = Manufacturer::find($this->findCsvMatch($row, 'id'));
|
$manufacturer = Manufacturer::find($this->findCsvMatch($row, 'id'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ($supplier) {
|
if ($manufacturer) {
|
||||||
if (! $this->updating) {
|
if (! $this->updating) {
|
||||||
$this->log('A matching Manufacturer '.$this->item['name'].' already exists');
|
$this->log('A matching Manufacturer '.$this->item['name'].' already exists');
|
||||||
return;
|
return;
|
||||||
@@ -58,8 +58,8 @@ class ManufacturerImporter extends ItemImporter
|
|||||||
$editingManufacturer = true;
|
$editingManufacturer = true;
|
||||||
} else {
|
} else {
|
||||||
$this->log('No Matching Manufacturer, Create a new one');
|
$this->log('No Matching Manufacturer, Create a new one');
|
||||||
$supplier = new Manufacturer;
|
$manufacturer = new Manufacturer;
|
||||||
$supplier->created_by = auth()->id();
|
$manufacturer->created_by = auth()->id();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pull the records from the CSV to determine their values
|
// Pull the records from the CSV to determine their values
|
||||||
@@ -79,21 +79,21 @@ class ManufacturerImporter extends ItemImporter
|
|||||||
|
|
||||||
|
|
||||||
if ($editingManufacturer) {
|
if ($editingManufacturer) {
|
||||||
Log::debug('Updating existing supplier');
|
Log::debug('Updating existing manufacturer');
|
||||||
$supplier->update($this->sanitizeItemForUpdating($supplier));
|
$manufacturer->update($this->sanitizeItemForUpdating($manufacturer));
|
||||||
} else {
|
} else {
|
||||||
Log::debug('Creating supplier');
|
Log::debug('Creating manufacturer');
|
||||||
$supplier->fill($this->sanitizeItemForStoring($supplier));
|
$manufacturer->fill($this->sanitizeItemForStoring($manufacturer));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($supplier->save()) {
|
if ($manufacturer->save()) {
|
||||||
$this->log('Manufacturer '.$supplier->name.' created or updated from CSV import');
|
$this->log('Manufacturer '.$manufacturer->name.' created or updated from CSV import');
|
||||||
return $supplier;
|
return $manufacturer;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Log::debug($supplier->getErrors());
|
Log::debug($manufacturer->getErrors());
|
||||||
$this->logError($supplier, 'Manufacturer "'.$this->item['name'].'"');
|
$this->logError($manufacturer, 'Manufacturer "'.$this->item['name'].'"');
|
||||||
return $supplier->errors;
|
return $manufacturer->errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -96,8 +96,8 @@ class CheckoutableListener
|
|||||||
|
|
||||||
if (!empty($to)) {
|
if (!empty($to)) {
|
||||||
try {
|
try {
|
||||||
Mail::to(array_flatten($to))->send($mailable->locale($notifiable->locale));
|
$toMail = (clone $mailable)->locale($notifiable->locale);
|
||||||
Mail::to(array_flatten($cc))->send($mailable->locale(Setting::getSettings()->locale));
|
Mail::to(array_flatten($to))->send($toMail);
|
||||||
Log::info('Checkout Mail sent to checkout target');
|
Log::info('Checkout Mail sent to checkout target');
|
||||||
} catch (ClientException $e) {
|
} catch (ClientException $e) {
|
||||||
Log::debug("Exception caught during checkout email: " . $e->getMessage());
|
Log::debug("Exception caught during checkout email: " . $e->getMessage());
|
||||||
@@ -105,6 +105,16 @@ class CheckoutableListener
|
|||||||
Log::debug("Exception caught during checkout email: " . $e->getMessage());
|
Log::debug("Exception caught during checkout email: " . $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!empty($cc)) {
|
||||||
|
try {
|
||||||
|
$ccMail = (clone $mailable)->locale(Setting::getSettings()->locale);
|
||||||
|
Mail::to(array_flatten($cc))->send($ccMail);
|
||||||
|
} catch (ClientException $e) {
|
||||||
|
Log::debug("Exception caught during checkout email: " . $e->getMessage());
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Log::debug("Exception caught during checkout email: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($shouldSendWebhookNotification) {
|
if ($shouldSendWebhookNotification) {
|
||||||
@@ -179,16 +189,26 @@ class CheckoutableListener
|
|||||||
|
|
||||||
[$to, $cc] = $this->generateEmailRecipients($shouldSendEmailToUser, $shouldSendEmailToAlertAddress, $notifiable);
|
[$to, $cc] = $this->generateEmailRecipients($shouldSendEmailToUser, $shouldSendEmailToAlertAddress, $notifiable);
|
||||||
|
|
||||||
try {
|
if (!empty($to)) {
|
||||||
if (!empty($to)) {
|
try {
|
||||||
Mail::to(array_flatten($to))->send($mailable->locale($notifiable->locale));
|
$toMail = (clone $mailable)->locale($notifiable->locale);
|
||||||
Mail::to(array_flatten($cc))->send($mailable->locale(Setting::getSettings()->locale));
|
Mail::to(array_flatten($to))->send($toMail);
|
||||||
Log::info('Checkin Mail sent to CC addresses');
|
Log::info('Checkin Mail sent to checkin target');
|
||||||
|
} catch (ClientException $e) {
|
||||||
|
Log::debug("Exception caught during checkin email: " . $e->getMessage());
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Log::debug("Exception caught during checkin email: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!empty($cc)) {
|
||||||
|
try {
|
||||||
|
$ccMail = (clone $mailable)->locale(Setting::getSettings()->locale);
|
||||||
|
Mail::to(array_flatten($cc))->send($ccMail);
|
||||||
|
} catch (ClientException $e) {
|
||||||
|
Log::debug("Exception caught during checkin email: " . $e->getMessage());
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Log::debug("Exception caught during checkin email: " . $e->getMessage());
|
||||||
}
|
}
|
||||||
} catch (ClientException $e) {
|
|
||||||
Log::debug("Exception caught during checkin email: " . $e->getMessage());
|
|
||||||
} catch (Exception $e) {
|
|
||||||
Log::debug("Exception caught during checkin email: " . $e->getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,6 +262,12 @@ class CheckoutableListener
|
|||||||
$acceptance->checkoutable()->associate($event->checkoutable);
|
$acceptance->checkoutable()->associate($event->checkoutable);
|
||||||
$acceptance->assignedTo()->associate($event->checkedOutTo);
|
$acceptance->assignedTo()->associate($event->checkedOutTo);
|
||||||
|
|
||||||
|
$acceptance->qty = 1;
|
||||||
|
|
||||||
|
if (isset($event->checkoutable->checkout_qty)) {
|
||||||
|
$acceptance->qty = $event->checkoutable->checkout_qty;
|
||||||
|
}
|
||||||
|
|
||||||
$category = $this->getCategoryFromCheckoutable($event->checkoutable);
|
$category = $this->getCategoryFromCheckoutable($event->checkoutable);
|
||||||
|
|
||||||
if ($category?->alert_on_response) {
|
if ($category?->alert_on_response) {
|
||||||
|
|||||||
@@ -403,6 +403,7 @@ class Importer extends Component
|
|||||||
|
|
||||||
|
|
||||||
$this->assetmodels_fields = [
|
$this->assetmodels_fields = [
|
||||||
|
'id' => trans('general.id'),
|
||||||
'category' => trans('general.category'),
|
'category' => trans('general.category'),
|
||||||
'eol' => trans('general.eol'),
|
'eol' => trans('general.eol'),
|
||||||
'fieldset' => trans('admin/models/general.fieldset'),
|
'fieldset' => trans('admin/models/general.fieldset'),
|
||||||
@@ -412,6 +413,7 @@ class Importer extends Component
|
|||||||
'model_number' => trans('general.model_no'),
|
'model_number' => trans('general.model_no'),
|
||||||
'notes' => trans('general.item_notes', ['item' => trans('admin/hardware/form.model')]),
|
'notes' => trans('general.item_notes', ['item' => trans('admin/hardware/form.model')]),
|
||||||
'requestable' => trans('admin/models/general.requestable'),
|
'requestable' => trans('admin/models/general.requestable'),
|
||||||
|
'require_serial' => trans('admin/hardware/general.require_serial'),
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -535,6 +537,10 @@ class Importer extends Component
|
|||||||
'product key',
|
'product key',
|
||||||
'key',
|
'key',
|
||||||
],
|
],
|
||||||
|
'require_serial' =>
|
||||||
|
[
|
||||||
|
'serial required',
|
||||||
|
],
|
||||||
'model_number' =>
|
'model_number' =>
|
||||||
[
|
[
|
||||||
'model',
|
'model',
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class CheckoutAccessoryMail extends Mailable
|
|||||||
|
|
||||||
return new Envelope(
|
return new Envelope(
|
||||||
from: $from,
|
from: $from,
|
||||||
subject: trans('mail.Accessory_Checkout_Notification'),
|
subject: trans_choice('mail.Accessory_Checkout_Notification', $this->checkout_qty),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,17 +83,19 @@ class CheckoutAccessoryMail extends Mailable
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function introductionLine(): string
|
private function introductionLine(): string
|
||||||
{
|
{
|
||||||
if ($this->target instanceof Location) {
|
if ($this->target instanceof Location) {
|
||||||
return trans('mail.new_item_checked_location', ['location' => $this->target->name ]);
|
return trans_choice('mail.new_item_checked_location', $this->checkout_qty, ['location' => $this->target->name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->requiresAcceptance()) {
|
if ($this->requiresAcceptance()) {
|
||||||
return trans('mail.new_item_checked_with_acceptance');
|
return trans_choice('mail.new_item_checked_with_acceptance', $this->checkout_qty);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->requiresAcceptance()) {
|
if (!$this->requiresAcceptance()) {
|
||||||
return trans('mail.new_item_checked');
|
return trans_choice('mail.new_item_checked', $this->checkout_qty);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we shouldn't get here but let's send a default message just in case
|
// we shouldn't get here but let's send a default message just in case
|
||||||
|
|||||||
@@ -138,14 +138,15 @@ class CheckoutAssetMail extends Mailable
|
|||||||
private function introductionLine(): string
|
private function introductionLine(): string
|
||||||
{
|
{
|
||||||
if ($this->firstTimeSending && $this->target instanceof Location) {
|
if ($this->firstTimeSending && $this->target instanceof Location) {
|
||||||
return trans('mail.new_item_checked_location', ['location' => $this->target->name ]);
|
return trans_choice('mail.new_item_checked_location', 1, ['location' => $this->target->name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->firstTimeSending && $this->requiresAcceptance()) {
|
if ($this->firstTimeSending && $this->requiresAcceptance()) {
|
||||||
return trans('mail.new_item_checked_with_acceptance');
|
return trans_choice('mail.new_item_checked_with_acceptance', 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->firstTimeSending && !$this->requiresAcceptance()) {
|
if ($this->firstTimeSending && !$this->requiresAcceptance()) {
|
||||||
return trans('mail.new_item_checked');
|
return trans_choice('mail.new_item_checked', 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->firstTimeSending && $this->requiresAcceptance()) {
|
if (!$this->firstTimeSending && $this->requiresAcceptance()) {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class CheckoutComponentMail extends Mailable
|
|||||||
$this->note = $note;
|
$this->note = $note;
|
||||||
$this->target = $checkedOutTo;
|
$this->target = $checkedOutTo;
|
||||||
$this->acceptance = $acceptance;
|
$this->acceptance = $acceptance;
|
||||||
$this->qty = $component->assets->first()?->pivot?->assigned_qty;
|
$this->qty = $component->checkout_qty;
|
||||||
|
|
||||||
$this->settings = Setting::getSettings();
|
$this->settings = Setting::getSettings();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ namespace App\Models;
|
|||||||
|
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Models\Traits\Acceptable;
|
use App\Models\Traits\Acceptable;
|
||||||
|
use App\Models\Traits\CompanyableTrait;
|
||||||
use App\Models\Traits\HasUploads;
|
use App\Models\Traits\HasUploads;
|
||||||
use App\Models\Traits\Searchable;
|
use App\Models\Traits\Searchable;
|
||||||
use App\Presenters\Presentable;
|
use App\Presenters\Presentable;
|
||||||
@@ -65,7 +66,7 @@ class Accessory extends SnipeModel
|
|||||||
'company_id' => 'integer|nullable',
|
'company_id' => 'integer|nullable',
|
||||||
'location_id' => 'exists:locations,id|nullable|fmcs_location',
|
'location_id' => 'exists:locations,id|nullable|fmcs_location',
|
||||||
'min_amt' => 'integer|min:0|nullable',
|
'min_amt' => 'integer|min:0|nullable',
|
||||||
'purchase_cost' => 'numeric|nullable|gte:0|max:9999999999999',
|
'purchase_cost' => 'numeric|nullable|gte:0|max:99999999999999999.99',
|
||||||
'purchase_date' => 'date_format:Y-m-d|nullable',
|
'purchase_date' => 'date_format:Y-m-d|nullable',
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -308,27 +309,6 @@ class Accessory extends SnipeModel
|
|||||||
return $this->category->require_acceptance ?? false;
|
return $this->category->require_acceptance ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks for a category-specific EULA, and if that doesn't exist,
|
|
||||||
* checks for a settings level EULA
|
|
||||||
*
|
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
||||||
* @since [v3.0]
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getEula()
|
|
||||||
{
|
|
||||||
|
|
||||||
if ($this->category->eula_text) {
|
|
||||||
return Helper::parseEscapedMarkedown($this->category->eula_text);
|
|
||||||
} elseif ((Setting::getSettings()->default_eula_text) && ($this->category->use_default_eula == '1')) {
|
|
||||||
return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check how many items within an accessory are checked out
|
* Check how many items within an accessory are checked out
|
||||||
*
|
*
|
||||||
@@ -377,6 +357,10 @@ class Accessory extends SnipeModel
|
|||||||
|
|
||||||
$accessory_checkout->limit(1)->delete();
|
$accessory_checkout->limit(1)->delete();
|
||||||
}
|
}
|
||||||
|
public function totalCostSum() {
|
||||||
|
|
||||||
|
return $this->purchase_cost !== null ? $this->qty * $this->purchase_cost : null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* -----------------------------------------------
|
* -----------------------------------------------
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Models\Traits\CompanyableTrait;
|
||||||
use App\Models\Traits\Searchable;
|
use App\Models\Traits\Searchable;
|
||||||
use App\Presenters\Presentable;
|
use App\Presenters\Presentable;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
@@ -245,19 +246,6 @@ class Actionlog extends SnipeModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Establishes the actionlog -> uploads relationship
|
|
||||||
*
|
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
||||||
* @since [v3.0]
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
|
||||||
*/
|
|
||||||
public function uploads()
|
|
||||||
{
|
|
||||||
return $this->morphTo('item')
|
|
||||||
->where('action_type', '=', 'uploaded')
|
|
||||||
->withTrashed();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Establishes the actionlog -> userlog relationship
|
* Establishes the actionlog -> userlog relationship
|
||||||
@@ -455,6 +443,26 @@ class Actionlog extends SnipeModel
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Godfrey Martinez
|
||||||
|
* @since [v8.0.4]
|
||||||
|
* @return \App\Models\Actionlog
|
||||||
|
*/
|
||||||
|
public function logUploadDelete($object, $filename)
|
||||||
|
{
|
||||||
|
$log = new Actionlog;
|
||||||
|
$log->item_type = $object instanceof SnipeModel ? get_class($object) : $object;
|
||||||
|
$log->item_id = $object->id;
|
||||||
|
$log->created_by = auth()->id();
|
||||||
|
$log->target_id = null;
|
||||||
|
$log->filename = $filename;
|
||||||
|
$log->created_at = date('Y-m-d H:i:s');
|
||||||
|
$log->logaction('upload deleted');
|
||||||
|
|
||||||
|
return $log;
|
||||||
|
}
|
||||||
|
|
||||||
public function uploads_file_url()
|
public function uploads_file_url()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -7,19 +7,20 @@ use App\Exceptions\CheckoutNotAllowed;
|
|||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Http\Traits\UniqueUndeletedTrait;
|
use App\Http\Traits\UniqueUndeletedTrait;
|
||||||
use App\Models\Traits\Acceptable;
|
use App\Models\Traits\Acceptable;
|
||||||
|
use App\Models\Traits\CompanyableTrait;
|
||||||
use App\Models\Traits\HasUploads;
|
use App\Models\Traits\HasUploads;
|
||||||
use App\Models\Traits\Searchable;
|
use App\Models\Traits\Searchable;
|
||||||
use App\Presenters\Presentable;
|
|
||||||
use App\Presenters\AssetPresenter;
|
use App\Presenters\AssetPresenter;
|
||||||
|
use App\Presenters\Presentable;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Illuminate\Support\Facades\Crypt;
|
use Illuminate\Support\Facades\Crypt;
|
||||||
use Illuminate\Support\Facades\Gate;
|
use Illuminate\Support\Facades\Gate;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Watson\Validating\ValidatingTrait;
|
use Watson\Validating\ValidatingTrait;
|
||||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model for Assets.
|
* Model for Assets.
|
||||||
@@ -113,7 +114,7 @@ class Asset extends Depreciable
|
|||||||
'rtd_location_id' => ['nullable', 'exists:locations,id', 'fmcs_location'],
|
'rtd_location_id' => ['nullable', 'exists:locations,id', 'fmcs_location'],
|
||||||
'purchase_date' => ['nullable', 'date', 'date_format:Y-m-d'],
|
'purchase_date' => ['nullable', 'date', 'date_format:Y-m-d'],
|
||||||
'serial' => ['nullable', 'string', 'unique_undeleted:assets,serial'],
|
'serial' => ['nullable', 'string', 'unique_undeleted:assets,serial'],
|
||||||
'purchase_cost' => ['nullable', 'numeric', 'gte:0', 'max:9999999999999'],
|
'purchase_cost' => ['nullable', 'numeric', 'gte:0', 'max:99999999999999999.99'],
|
||||||
'supplier_id' => ['nullable', 'exists:suppliers,id'],
|
'supplier_id' => ['nullable', 'exists:suppliers,id'],
|
||||||
'asset_eol_date' => ['nullable', 'date'],
|
'asset_eol_date' => ['nullable', 'date'],
|
||||||
'eol_explicit' => ['nullable', 'boolean'],
|
'eol_explicit' => ['nullable', 'boolean'],
|
||||||
@@ -160,7 +161,6 @@ class Asset extends Depreciable
|
|||||||
'eol_explicit',
|
'eol_explicit',
|
||||||
'last_audit_date',
|
'last_audit_date',
|
||||||
'next_audit_date',
|
'next_audit_date',
|
||||||
'asset_eol_date',
|
|
||||||
'last_checkin',
|
'last_checkin',
|
||||||
'last_checkout',
|
'last_checkout',
|
||||||
];
|
];
|
||||||
@@ -823,21 +823,26 @@ class Asset extends Depreciable
|
|||||||
* @since [v2.0]
|
* @since [v2.0]
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public static function getExpiringWarrantee($days = 30)
|
public static function getExpiringWarrantyOrEol($days = 30)
|
||||||
{
|
{
|
||||||
$days = (is_null($days)) ? 30 : $days;
|
|
||||||
|
return self::where('archived', '=', '0')
|
||||||
return self::where('archived', '=', '0') // this can stay for right now, as `archived` defaults to 0 at the db level, but should probably be replaced with assetstatus->archived?
|
|
||||||
->whereNotNull('warranty_months')
|
|
||||||
->whereNotNull('purchase_date')
|
|
||||||
->whereNull('deleted_at')
|
|
||||||
->NotArchived()
|
->NotArchived()
|
||||||
->whereRaw(
|
->whereNull('deleted_at')
|
||||||
'DATE_ADD(`purchase_date`, INTERVAL `warranty_months` MONTH) <= DATE_ADD(NOW(), INTERVAL '
|
->where(function ($query) use ($days) {
|
||||||
. $days
|
// Check for manual asset EOL first
|
||||||
. ' DAY) AND DATE_ADD(`purchase_date`, INTERVAL `warranty_months` MONTH) > NOW()'
|
$query->where(function ($query) use ($days) {
|
||||||
)
|
$query->whereNotNull('asset_eol_date')
|
||||||
->orderByRaw('DATE_ADD(`purchase_date`,INTERVAL `warranty_months` MONTH)')
|
->whereBetween('asset_eol_date', [Carbon::now(), Carbon::now()->addDays($days)]);
|
||||||
|
// Otherwise use the warranty months + purchase date + threshold
|
||||||
|
})->orWhere(function ($query) use ($days) {
|
||||||
|
$query->whereNotNull('purchase_date')
|
||||||
|
->whereNotNull('warranty_months')
|
||||||
|
->whereBetween('purchase_date', [Carbon::now(), Carbon::now()->addMonths('assets.warranty_months')->addDays($days)]);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
->orderBy('asset_eol_date', 'ASC')
|
||||||
|
->orderBy('purchase_date', 'ASC')
|
||||||
->get();
|
->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1018,31 +1023,6 @@ class Asset extends Depreciable
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks for a category-specific EULA, and if that doesn't exist,
|
|
||||||
* checks for a settings level EULA
|
|
||||||
*
|
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
||||||
* @since [v4.0]
|
|
||||||
* @return string | false
|
|
||||||
*/
|
|
||||||
public function getEula()
|
|
||||||
{
|
|
||||||
|
|
||||||
if (($this->model) && ($this->model->category)) {
|
|
||||||
if (($this->model->category->eula_text) && ($this->model->category->use_default_eula === 0)) {
|
|
||||||
return Helper::parseEscapedMarkedown($this->model->category->eula_text);
|
|
||||||
} elseif ($this->model->category->use_default_eula === 1) {
|
|
||||||
return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
public function getComponentCost()
|
public function getComponentCost()
|
||||||
{
|
{
|
||||||
$cost = 0;
|
$cost = 0;
|
||||||
@@ -1892,6 +1872,30 @@ class Asset extends Depreciable
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($fieldname == 'jobtitle') {
|
||||||
|
$query->where(function ($query) use ($search_val) {
|
||||||
|
if (is_array($search_val)) {
|
||||||
|
$query->whereHasMorph(
|
||||||
|
'assignedTo',
|
||||||
|
[User::class],
|
||||||
|
function ($query) use ($search_val) {
|
||||||
|
$query->whereIn('users.jobtitle', $search_val);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$query->whereHasMorph(
|
||||||
|
'assignedTo',
|
||||||
|
[User::class],
|
||||||
|
function ($query) use ($search_val) {
|
||||||
|
$query->where(function ($query) use ($search_val) {
|
||||||
|
$query->where('users.jobtitle', 'LIKE', '%' . $search_val . '%');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* THIS CLUNKY BIT IS VERY IMPORTANT
|
* THIS CLUNKY BIT IS VERY IMPORTANT
|
||||||
@@ -1916,7 +1920,7 @@ class Asset extends Depreciable
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
if (($fieldname!='category') && ($fieldname!='model_number') && ($fieldname!='rtd_location') && ($fieldname!='location') && ($fieldname!='supplier')
|
if (($fieldname!='category') && ($fieldname!='model_number') && ($fieldname!='rtd_location') && ($fieldname!='location') && ($fieldname!='supplier')
|
||||||
&& ($fieldname!='status_label') && ($fieldname!='assigned_to') && ($fieldname!='model') && ($fieldname!='company') && ($fieldname!='manufacturer')
|
&& ($fieldname!='status_label') && ($fieldname!='assigned_to') && ($fieldname!='model') && ($fieldname!='jobtitle') && ($fieldname!='company') && ($fieldname!='manufacturer')
|
||||||
) {
|
) {
|
||||||
$query->where('assets.'.$fieldname, 'LIKE', '%' . $search_val . '%');
|
$query->where('assets.'.$fieldname, 'LIKE', '%' . $search_val . '%');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ class AssetModel extends SnipeModel
|
|||||||
'name',
|
'name',
|
||||||
'notes',
|
'notes',
|
||||||
'requestable',
|
'requestable',
|
||||||
|
'require_serial'
|
||||||
];
|
];
|
||||||
|
|
||||||
use Searchable;
|
use Searchable;
|
||||||
|
|||||||
@@ -2,11 +2,14 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Helpers\Helper;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
|
use TCPDF;
|
||||||
|
|
||||||
class CheckoutAcceptance extends Model
|
class CheckoutAcceptance extends Model
|
||||||
{
|
{
|
||||||
@@ -129,8 +132,7 @@ class CheckoutAcceptance extends Model
|
|||||||
/**
|
/**
|
||||||
* Filter checkout acceptences by the user
|
* Filter checkout acceptences by the user
|
||||||
*
|
*
|
||||||
* @param Illuminate\Database\Eloquent\Builder $query
|
* @param User $user
|
||||||
* @param User $user
|
|
||||||
* @return \Illuminate\Database\Eloquent\Builder
|
* @return \Illuminate\Database\Eloquent\Builder
|
||||||
*/
|
*/
|
||||||
public function scopeForUser(Builder $query, User $user)
|
public function scopeForUser(Builder $query, User $user)
|
||||||
@@ -141,11 +143,111 @@ class CheckoutAcceptance extends Model
|
|||||||
/**
|
/**
|
||||||
* Filter to only get pending acceptances
|
* Filter to only get pending acceptances
|
||||||
*
|
*
|
||||||
* @param Illuminate\Database\Eloquent\Builder $query
|
|
||||||
* @return \Illuminate\Database\Eloquent\Builder
|
* @return \Illuminate\Database\Eloquent\Builder
|
||||||
*/
|
*/
|
||||||
public function scopePending(Builder $query)
|
public function scopePending(Builder $query)
|
||||||
{
|
{
|
||||||
return $query->whereNull('accepted_at')->whereNull('declined_at');
|
return $query->whereNull('accepted_at')->whereNull('declined_at');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function scopeDeclined(Builder $query)
|
||||||
|
{
|
||||||
|
return $query->whereNull('accepted_at')->whereNotNull('declined_at');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function displayCheckoutableType(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute:: make(
|
||||||
|
get: fn(mixed $value) => strtolower(str_replace('App\Models\\', '', $this->checkoutable_type)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generateAcceptancePdf($data, $pdf_filename) {
|
||||||
|
|
||||||
|
// set some language dependent data:
|
||||||
|
$lg = Array();
|
||||||
|
$lg['a_meta_charset'] = 'UTF-8';
|
||||||
|
$lg['w_page'] = 'page';
|
||||||
|
|
||||||
|
$pdf = new TCPDF('P', 'mm', 'A4', true, 'UTF-8', false);
|
||||||
|
$pdf->setRTL(false);
|
||||||
|
$pdf->setLanguageArray($lg);
|
||||||
|
$pdf->SetFontSubsetting(true);
|
||||||
|
$pdf->SetCreator('Snipe-IT Asset Management System');
|
||||||
|
$pdf->SetAuthor($data['assigned_to']);
|
||||||
|
$pdf->SetTitle('Asset Acceptance: '.$data['item_tag']);
|
||||||
|
$pdf->SetSubject('Asset Acceptance: '.$data['item_tag']);
|
||||||
|
$pdf->SetKeywords('Snipe-IT, assets, acceptance, eula, tos');
|
||||||
|
$pdf->SetFont('dejavusans', '', 8, '', true);
|
||||||
|
$pdf->SetPrintHeader(false);
|
||||||
|
$pdf->SetPrintFooter(false);
|
||||||
|
|
||||||
|
$pdf->AddPage();
|
||||||
|
if ($data['logo'] != null) {
|
||||||
|
$pdf->writeHTML('<img src="'.$data['logo'].'">', true, 0, true, 0, '');
|
||||||
|
} else {
|
||||||
|
$pdf->writeHTML('<h3>'.$data['site_name'].'</h3><br /><br />', true, 0, true, 0, 'C');
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdf->Ln();
|
||||||
|
$pdf->writeHTML(trans('general.date') . ': ' . Helper::getFormattedDateObject(now(), 'datetime', false), true, 0, true, 0, '');
|
||||||
|
|
||||||
|
if ($data['company_name'] != null) {
|
||||||
|
$pdf->writeHTML(trans('general.company') . ': ' . e($data['company_name']), true, 0, true, 0, '');
|
||||||
|
}
|
||||||
|
if ($data['item_tag'] != null) {
|
||||||
|
$pdf->writeHTML(trans('general.asset_tag') . ': ' . e($data['item_tag']), true, 0, true, 0, '');
|
||||||
|
}
|
||||||
|
if ($data['item_name'] != null) {
|
||||||
|
$pdf->writeHTML(trans('general.name') . ': ' . e($data['item_name']), true, 0, true, 0, '');
|
||||||
|
}
|
||||||
|
if ($data['item_model'] != null) {
|
||||||
|
$pdf->writeHTML(trans('general.asset_model') . ': ' . e($data['item_model']), true, 0, true, 0, '');
|
||||||
|
}
|
||||||
|
if ($data['item_serial'] != null) {
|
||||||
|
$pdf->writeHTML(trans('admin/hardware/form.serial').': '.e($data['item_serial']), true, 0, true, 0, '');
|
||||||
|
}
|
||||||
|
if (($data['qty'] != null) && ($data['qty'] > 1)) {
|
||||||
|
$pdf->writeHTML(trans('general.qty').': '.e($data['qty']), true, 0, true, 0, '');
|
||||||
|
}
|
||||||
|
$pdf->writeHTML(trans('general.assignee').': '.e($data['assigned_to']), true, 0, true, 0, '');
|
||||||
|
$pdf->Ln();
|
||||||
|
$pdf->writeHTML('<hr>', true, 0, true, 0, '');
|
||||||
|
|
||||||
|
|
||||||
|
// Break the EULA into lines based on newlines, and check each line for RTL or CJK characters
|
||||||
|
$eula_lines = preg_split("/\r\n|\n|\r/", $data['eula']);
|
||||||
|
|
||||||
|
foreach ($eula_lines as $eula_line) {
|
||||||
|
Helper::hasRtl($eula_line) ? $pdf->setRTL(true) : $pdf->setRTL(false);
|
||||||
|
Helper::isCjk($eula_line) ? $pdf->SetFont('cid0cs', '', 9) : $pdf->SetFont('dejavusans', '', 8, '', true);
|
||||||
|
|
||||||
|
$pdf->writeHTML(Helper::parseEscapedMarkedown($eula_line), true, 0, true, 0, '');
|
||||||
|
}
|
||||||
|
$pdf->Ln();
|
||||||
|
$pdf->Ln();
|
||||||
|
$pdf->setRTL(false);
|
||||||
|
$pdf->Ln();
|
||||||
|
|
||||||
|
if ($data['signature'] != null) {
|
||||||
|
$pdf->writeHTML('<img src="'.$data['signature'].'">', true, 0, true, 0, '');
|
||||||
|
$pdf->writeHTML('<hr>', true, 0, true, 0, '');
|
||||||
|
$pdf->writeHTML(e($data['assigned_to']), true, 0, true, 0, 'C');
|
||||||
|
$pdf->Ln();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($data['note'] != null) {
|
||||||
|
Helper::isCjk($data['note']) ? $pdf->SetFont('cid0cs', '', 9) : $pdf->SetFont('dejavusans', '', 8, '', true);
|
||||||
|
$pdf->writeHTML(trans('general.notes') . ': ' . e($data['note']), true, 0, true, 0, '');
|
||||||
|
$pdf->Ln();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$pdf->writeHTML(trans('general.assigned_date').': '.e($data['check_out_date']), true, 0, true, 0, '');
|
||||||
|
$pdf->writeHTML(trans('general.accepted_date').': '.e($data['accepted_date']), true, 0, true, 0, '');
|
||||||
|
|
||||||
|
return $pdf->Output($pdf_filename, 'S');
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ class CheckoutRequest extends Model
|
|||||||
public function name()
|
public function name()
|
||||||
{
|
{
|
||||||
if ($this->itemType() == 'asset') {
|
if ($this->itemType() == 'asset') {
|
||||||
return $this->itemRequested()->present()->name();
|
return $this->itemRequested()->display_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->itemRequested()->name;
|
return $this->itemRequested()->name;
|
||||||
|
|||||||
@@ -2,14 +2,16 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Models\Traits\CompanyableTrait;
|
||||||
use App\Models\Traits\Searchable;
|
use App\Models\Traits\Searchable;
|
||||||
use App\Presenters\Presentable;
|
use App\Presenters\Presentable;
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Gate;
|
use Illuminate\Support\Facades\Gate;
|
||||||
use Watson\Validating\ValidatingTrait;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\Facades\Schema;
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Watson\Validating\ValidatingTrait;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model for Companies.
|
* Model for Companies.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
|
use App\Models\Traits\CompanyableTrait;
|
||||||
use App\Models\Traits\HasUploads;
|
use App\Models\Traits\HasUploads;
|
||||||
use App\Models\Traits\Searchable;
|
use App\Models\Traits\Searchable;
|
||||||
use App\Presenters\Presentable;
|
use App\Presenters\Presentable;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Illuminate\Support\Facades\Gate;
|
use Illuminate\Support\Facades\Gate;
|
||||||
use Illuminate\Support\Facades\Storage;
|
|
||||||
use Watson\Validating\ValidatingTrait;
|
use Watson\Validating\ValidatingTrait;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -43,7 +43,7 @@ class Component extends SnipeModel
|
|||||||
'location_id' => 'exists:locations,id|nullable|fmcs_location',
|
'location_id' => 'exists:locations,id|nullable|fmcs_location',
|
||||||
'min_amt' => 'integer|min:0|nullable',
|
'min_amt' => 'integer|min:0|nullable',
|
||||||
'purchase_date' => 'date_format:Y-m-d|nullable',
|
'purchase_date' => 'date_format:Y-m-d|nullable',
|
||||||
'purchase_cost' => 'numeric|nullable|gte:0|max:9999999999999',
|
'purchase_cost' => 'numeric|nullable|gte:0|max:99999999999999999.99',
|
||||||
'manufacturer_id' => 'integer|exists:manufacturers,id|nullable',
|
'manufacturer_id' => 'integer|exists:manufacturers,id|nullable',
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -217,24 +217,6 @@ class Component extends SnipeModel
|
|||||||
return $this->category->require_acceptance;
|
return $this->category->require_acceptance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks for a category-specific EULA, and if that doesn't exist,
|
|
||||||
* checks for a settings level EULA
|
|
||||||
*
|
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
||||||
* @since [v4.0]
|
|
||||||
* @return string | false
|
|
||||||
*/
|
|
||||||
public function getEula()
|
|
||||||
{
|
|
||||||
if ($this->category->eula_text) {
|
|
||||||
return Helper::parseEscapedMarkedown($this->category->eula_text);
|
|
||||||
} elseif ((Setting::getSettings()->default_eula_text) && ($this->category->use_default_eula == '1')) {
|
|
||||||
return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Establishes the component -> action logs relationship
|
* Establishes the component -> action logs relationship
|
||||||
@@ -306,7 +288,10 @@ class Component extends SnipeModel
|
|||||||
return $this->qty - $this->numCheckedOut();
|
return $this->qty - $this->numCheckedOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function totalCostSum() {
|
||||||
|
|
||||||
|
return $this->purchase_cost !== null ? $this->qty * $this->purchase_cost : null;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* -----------------------------------------------
|
* -----------------------------------------------
|
||||||
* BEGIN MUTATORS
|
* BEGIN MUTATORS
|
||||||
|
|||||||
@@ -4,22 +4,16 @@ namespace App\Models;
|
|||||||
|
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Models\Traits\Acceptable;
|
use App\Models\Traits\Acceptable;
|
||||||
|
use App\Models\Traits\CompanyableTrait;
|
||||||
use App\Models\Traits\HasUploads;
|
use App\Models\Traits\HasUploads;
|
||||||
use App\Models\Traits\Searchable;
|
use App\Models\Traits\Searchable;
|
||||||
|
use App\Presenters\ConsumablePresenter;
|
||||||
use App\Presenters\Presentable;
|
use App\Presenters\Presentable;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Watson\Validating\ValidatingTrait;
|
use Watson\Validating\ValidatingTrait;
|
||||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
|
||||||
use App\Presenters\ConsumablePresenter;
|
|
||||||
use App\Models\Actionlog;
|
|
||||||
use App\Models\ConsumableAssignment;
|
|
||||||
use App\Models\User;
|
|
||||||
use App\Models\Location;
|
|
||||||
use App\Models\Manufacturer;
|
|
||||||
use App\Models\Supplier;
|
|
||||||
use App\Models\Category;
|
|
||||||
|
|
||||||
class Consumable extends SnipeModel
|
class Consumable extends SnipeModel
|
||||||
{
|
{
|
||||||
@@ -53,7 +47,7 @@ class Consumable extends SnipeModel
|
|||||||
'company_id' => 'integer|nullable',
|
'company_id' => 'integer|nullable',
|
||||||
'location_id' => 'exists:locations,id|nullable|fmcs_location',
|
'location_id' => 'exists:locations,id|nullable|fmcs_location',
|
||||||
'min_amt' => 'integer|min:0|max:99999|nullable',
|
'min_amt' => 'integer|min:0|max:99999|nullable',
|
||||||
'purchase_cost' => 'numeric|nullable|gte:0|max:9999999999999',
|
'purchase_cost' => 'numeric|nullable|gte:0|max:99999999999999999.99',
|
||||||
'purchase_date' => 'date_format:Y-m-d|nullable',
|
'purchase_date' => 'date_format:Y-m-d|nullable',
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -291,25 +285,6 @@ class Consumable extends SnipeModel
|
|||||||
return $this->category->require_acceptance;
|
return $this->category->require_acceptance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks for a category-specific EULA, and if that doesn't exist,
|
|
||||||
* checks for a settings level EULA
|
|
||||||
*
|
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
||||||
* @since [v4.0]
|
|
||||||
* @return string | false
|
|
||||||
*/
|
|
||||||
public function getEula()
|
|
||||||
{
|
|
||||||
if ($this->category->eula_text) {
|
|
||||||
return Helper::parseEscapedMarkedown($this->category->eula_text);
|
|
||||||
} elseif ((Setting::getSettings()->default_eula_text) && ($this->category->use_default_eula == '1')) {
|
|
||||||
return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check how many items within a consumable are checked out
|
* Check how many items within a consumable are checked out
|
||||||
*
|
*
|
||||||
@@ -337,7 +312,10 @@ class Consumable extends SnipeModel
|
|||||||
|
|
||||||
return $remaining;
|
return $remaining;
|
||||||
}
|
}
|
||||||
|
public function totalCostSum() {
|
||||||
|
|
||||||
|
return $this->purchase_cost !== null ? $this->qty * $this->purchase_cost : null;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* -----------------------------------------------
|
* -----------------------------------------------
|
||||||
* BEGIN MUTATORS
|
* BEGIN MUTATORS
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Models\Traits\CompanyableTrait;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Watson\Validating\ValidatingTrait;
|
use Watson\Validating\ValidatingTrait;
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Http\Traits\UniqueUndeletedTrait;
|
use App\Http\Traits\UniqueUndeletedTrait;
|
||||||
|
use App\Models\Traits\CompanyableTrait;
|
||||||
use App\Models\Traits\Searchable;
|
use App\Models\Traits\Searchable;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Watson\Validating\ValidatingTrait;
|
use Watson\Validating\ValidatingTrait;
|
||||||
|
|||||||
@@ -78,6 +78,13 @@ class Ldap extends Model
|
|||||||
if (env('LDAPTLS_CACERT')) {
|
if (env('LDAPTLS_CACERT')) {
|
||||||
putenv('LDAPTLS_CACERT='.env('LDAPTLS_CACERT'));
|
putenv('LDAPTLS_CACERT='.env('LDAPTLS_CACERT'));
|
||||||
}
|
}
|
||||||
|
// You _were_ allowed to do this *after* the ldap_connect() in some versions of PHP, but it's not how they want
|
||||||
|
// you to anymore, and it seems to not work at all in later PHP versions.
|
||||||
|
if (Setting::getSettings()->ldap_client_tls_cert && Setting::getSettings()->ldap_client_tls_key) {
|
||||||
|
ldap_set_option(null, LDAP_OPT_X_TLS_CERTFILE, Setting::get_client_side_cert_path());
|
||||||
|
ldap_set_option(null, LDAP_OPT_X_TLS_KEYFILE, Setting::get_client_side_key_path());
|
||||||
|
}
|
||||||
|
|
||||||
$connection = @ldap_connect($ldap_host);
|
$connection = @ldap_connect($ldap_host);
|
||||||
|
|
||||||
if (! $connection) {
|
if (! $connection) {
|
||||||
@@ -89,11 +96,6 @@ class Ldap extends Model
|
|||||||
ldap_set_option($connection, LDAP_OPT_PROTOCOL_VERSION, $ldap_version);
|
ldap_set_option($connection, LDAP_OPT_PROTOCOL_VERSION, $ldap_version);
|
||||||
ldap_set_option($connection, LDAP_OPT_NETWORK_TIMEOUT, 20);
|
ldap_set_option($connection, LDAP_OPT_NETWORK_TIMEOUT, 20);
|
||||||
|
|
||||||
if (Setting::getSettings()->ldap_client_tls_cert && Setting::getSettings()->ldap_client_tls_key) {
|
|
||||||
ldap_set_option(null, LDAP_OPT_X_TLS_CERTFILE, Setting::get_client_side_cert_path());
|
|
||||||
ldap_set_option(null, LDAP_OPT_X_TLS_KEYFILE, Setting::get_client_side_key_path());
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($ldap_use_tls=='1') {
|
if ($ldap_use_tls=='1') {
|
||||||
ldap_start_tls($connection);
|
ldap_start_tls($connection);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,17 +3,18 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
|
use App\Models\Traits\CompanyableTrait;
|
||||||
use App\Models\Traits\HasUploads;
|
use App\Models\Traits\HasUploads;
|
||||||
use App\Models\Traits\Searchable;
|
use App\Models\Traits\Searchable;
|
||||||
use App\Presenters\Presentable;
|
use App\Presenters\Presentable;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Session;
|
use Illuminate\Support\Facades\Session;
|
||||||
use Watson\Validating\ValidatingTrait;
|
use Watson\Validating\ValidatingTrait;
|
||||||
|
|
||||||
|
|
||||||
class License extends Depreciable
|
class License extends Depreciable
|
||||||
{
|
{
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
@@ -51,7 +52,7 @@ class License extends Depreciable
|
|||||||
'notes' => 'string|nullable',
|
'notes' => 'string|nullable',
|
||||||
'category_id' => 'required|exists:categories,id',
|
'category_id' => 'required|exists:categories,id',
|
||||||
'company_id' => 'integer|nullable',
|
'company_id' => 'integer|nullable',
|
||||||
'purchase_cost'=> 'numeric|nullable|gte:0',
|
'purchase_cost' => 'numeric|nullable|gte:0|max:99999999999999999.99',
|
||||||
'purchase_date' => 'date_format:Y-m-d|nullable|max:10|required_with:depreciation_id',
|
'purchase_date' => 'date_format:Y-m-d|nullable|max:10|required_with:depreciation_id',
|
||||||
'expiration_date' => 'date_format:Y-m-d|nullable|max:10',
|
'expiration_date' => 'date_format:Y-m-d|nullable|max:10',
|
||||||
'termination_date' => 'date_format:Y-m-d|nullable|max:10',
|
'termination_date' => 'date_format:Y-m-d|nullable|max:10',
|
||||||
@@ -296,6 +297,38 @@ class License extends Depreciable
|
|||||||
}
|
}
|
||||||
$this->attributes['termination_date'] = $value;
|
$this->attributes['termination_date'] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isInactive(): bool
|
||||||
|
{
|
||||||
|
$day = now()->startOfDay();
|
||||||
|
|
||||||
|
$expired = $this->expiration_date && $this->asDateTime($this->expiration_date)->startofDay()->lessThanOrEqualTo($day);
|
||||||
|
|
||||||
|
$terminated = $this->termination_date && $this->asDateTime($this->termination_date)->startofDay()->lessThanOrEqualTo($day);
|
||||||
|
|
||||||
|
|
||||||
|
return $this->isExpired() || $this->isTerminated();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isExpired(): bool
|
||||||
|
{
|
||||||
|
$day = now()->startOfDay();
|
||||||
|
|
||||||
|
$expired = $this->expiration_date && $this->asDateTime($this->expiration_date)->startofDay()->lessThanOrEqualTo($day);
|
||||||
|
|
||||||
|
return $expired;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isTerminated(): bool
|
||||||
|
{
|
||||||
|
$day = now()->startOfDay();
|
||||||
|
|
||||||
|
$terminated = $this->termination_date && $this->asDateTime($this->termination_date)->startofDay()->lessThanOrEqualTo($day);
|
||||||
|
|
||||||
|
|
||||||
|
return $terminated;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets free_seat_count attribute
|
* Sets free_seat_count attribute
|
||||||
*
|
*
|
||||||
@@ -375,27 +408,6 @@ class License extends Depreciable
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks for a category-specific EULA, and if that doesn't exist,
|
|
||||||
* checks for a settings level EULA
|
|
||||||
*
|
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
||||||
* @since [v4.0]
|
|
||||||
* @return string | false
|
|
||||||
*/
|
|
||||||
public function getEula()
|
|
||||||
{
|
|
||||||
if ($this->category) {
|
|
||||||
if ($this->category->eula_text) {
|
|
||||||
return Helper::parseEscapedMarkedown($this->category->eula_text);
|
|
||||||
} elseif ($this->category->use_default_eula == '1') {
|
|
||||||
return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Establishes the license -> assigned user relationship
|
* Establishes the license -> assigned user relationship
|
||||||
@@ -534,6 +546,7 @@ class License extends Depreciable
|
|||||||
return $this->licenseSeatsRelation()
|
return $this->licenseSeatsRelation()
|
||||||
->whereNull('asset_id')
|
->whereNull('asset_id')
|
||||||
->whereNull('assigned_to')
|
->whereNull('assigned_to')
|
||||||
|
->where('unreassignable_seat', '=', false)
|
||||||
->whereNull('deleted_at');
|
->whereNull('deleted_at');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -585,7 +598,22 @@ class License extends Depreciable
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Calculates the number of unreassignable seats
|
||||||
|
*
|
||||||
|
* @author G. Martinez
|
||||||
|
* @since [v7.1.15]
|
||||||
|
*/
|
||||||
|
public static function unReassignableCount($license) : int
|
||||||
|
{
|
||||||
|
$count = 0;
|
||||||
|
if (!$license->reassignable) {
|
||||||
|
$count = LicenseSeat::query()->where('unreassignable_seat', '=', true)
|
||||||
|
->where('license_id', '=', $license->id)
|
||||||
|
->count();
|
||||||
|
}
|
||||||
|
return $count;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Calculates the number of remaining seats
|
* Calculates the number of remaining seats
|
||||||
*
|
*
|
||||||
@@ -593,11 +621,12 @@ class License extends Depreciable
|
|||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function remaincount()
|
public function remaincount() : int
|
||||||
{
|
{
|
||||||
$total = $this->licenseSeatsCount;
|
$total = $this->licenseSeatsCount;
|
||||||
$taken = $this->assigned_seats_count;
|
$taken = $this->assigned_seats_count;
|
||||||
$diff = ($total - $taken);
|
$unreassignable = self::unReassignableCount($this);
|
||||||
|
$diff = ($total - $taken - $unreassignable);
|
||||||
|
|
||||||
return (int) $diff;
|
return (int) $diff;
|
||||||
}
|
}
|
||||||
@@ -655,12 +684,11 @@ class License extends Depreciable
|
|||||||
{
|
{
|
||||||
return $this->licenseseats()
|
return $this->licenseseats()
|
||||||
->whereNull('deleted_at')
|
->whereNull('deleted_at')
|
||||||
->where(
|
->where('unreassignable_seat', '=', false)
|
||||||
function ($query) {
|
->where(function ($query) {
|
||||||
$query->whereNull('assigned_to')
|
$query->whereNull('assigned_to')
|
||||||
->whereNull('asset_id');
|
->whereNull('asset_id');
|
||||||
}
|
})
|
||||||
)
|
|
||||||
->orderBy('id', 'asc')
|
->orderBy('id', 'asc')
|
||||||
->first();
|
->first();
|
||||||
}
|
}
|
||||||
@@ -679,26 +707,80 @@ class License extends Depreciable
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns expiring licenses
|
* Returns expiring licenses.
|
||||||
*
|
*
|
||||||
* @todo should refactor. I don't like get() in model methods
|
* This checks if:
|
||||||
|
*
|
||||||
|
* 1) The license has not been deleted
|
||||||
|
* 2) The expiration date is between now and the number of days specified
|
||||||
|
* 3) There is an expiration date set and the termination date has not passed
|
||||||
|
* 4) The license termination date is null or has not passed
|
||||||
*
|
*
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
* @author A. Gianotto <snipe@snipe.net>
|
||||||
* @since [v1.0]
|
* @since [v1.0]
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||||
|
* @see \App\Console\Commands\SendExpiringLicenseNotifications
|
||||||
*/
|
*/
|
||||||
public static function getExpiringLicenses($days = 60)
|
public static function getExpiringLicenses($days = 60)
|
||||||
{
|
{
|
||||||
$days = (is_null($days)) ? 60 : $days;
|
|
||||||
|
|
||||||
return self::whereNotNull('expiration_date')
|
return self::whereNull('licenses.deleted_at')
|
||||||
->whereNull('deleted_at')
|
|
||||||
->whereRaw('DATE_SUB(`expiration_date`,INTERVAL '.$days.' DAY) <= DATE(NOW()) ')
|
// The termination date is null or within range
|
||||||
->where('expiration_date', '>', date('Y-m-d'))
|
->where(function ($query) use ($days) {
|
||||||
|
$query->whereNull('termination_date')
|
||||||
|
->orWhereBetween('termination_date', [Carbon::now(), Carbon::now()->addDays($days)]);
|
||||||
|
})
|
||||||
|
->where(function ($query) use ($days) {
|
||||||
|
$query->whereNotNull('expiration_date')
|
||||||
|
// Handle expired licenses without termination dates
|
||||||
|
->where(function ($query) use ($days) {
|
||||||
|
$query->whereNull('termination_date')
|
||||||
|
->whereBetween('expiration_date', [Carbon::now(), Carbon::now()->addDays($days)]);
|
||||||
|
})
|
||||||
|
|
||||||
|
// Handle expired licenses with termination dates in the future
|
||||||
|
->orWhere(function ($query) use ($days) {
|
||||||
|
$query->whereBetween('termination_date', [Carbon::now(), Carbon::now()->addDays($days)]);
|
||||||
|
});
|
||||||
|
})
|
||||||
->orderBy('expiration_date', 'ASC')
|
->orderBy('expiration_date', 'ASC')
|
||||||
|
->orderBy('termination_date', 'ASC')
|
||||||
->get();
|
->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function scopeActiveLicenses($query)
|
||||||
|
{
|
||||||
|
|
||||||
|
return $query->whereNull('licenses.deleted_at')
|
||||||
|
|
||||||
|
// The termination date is null or within range
|
||||||
|
->where(function ($query) {
|
||||||
|
$query->whereNull('termination_date')
|
||||||
|
->orWhereDate('termination_date', '>', [Carbon::now()]);
|
||||||
|
})
|
||||||
|
->where(function ($query) {
|
||||||
|
$query->whereNull('expiration_date')
|
||||||
|
->orWhereDate('expiration_date', '>', [Carbon::now()]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scopeExpiredLicenses($query)
|
||||||
|
{
|
||||||
|
|
||||||
|
return $query->whereNull('licenses.deleted_at')
|
||||||
|
|
||||||
|
// The termination date is null or within range
|
||||||
|
->where(function ($query) {
|
||||||
|
$query->whereNull('termination_date')
|
||||||
|
->orWhereDate('termination_date', '<=', [Carbon::now()]);
|
||||||
|
})
|
||||||
|
->orWhere(function ($query) {
|
||||||
|
$query->whereNull('expiration_date')
|
||||||
|
->orWhereDate('expiration_date', '<=', [Carbon::now()]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query builder scope to order on manufacturer
|
* Query builder scope to order on manufacturer
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -3,9 +3,11 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Models\Traits\Acceptable;
|
use App\Models\Traits\Acceptable;
|
||||||
|
use App\Models\Traits\CompanyableChildTrait;
|
||||||
use App\Notifications\CheckinLicenseNotification;
|
use App\Notifications\CheckinLicenseNotification;
|
||||||
use App\Notifications\CheckoutLicenseNotification;
|
use App\Notifications\CheckoutLicenseNotification;
|
||||||
use App\Presenters\Presentable;
|
use App\Presenters\Presentable;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
@@ -21,6 +23,9 @@ class LicenseSeat extends SnipeModel implements ICompanyableChild
|
|||||||
|
|
||||||
protected $guarded = 'id';
|
protected $guarded = 'id';
|
||||||
protected $table = 'license_seats';
|
protected $table = 'license_seats';
|
||||||
|
protected $casts = [
|
||||||
|
'unreassignable_seat' => 'boolean',
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The attributes that are mass assignable.
|
* The attributes that are mass assignable.
|
||||||
@@ -60,6 +65,21 @@ class LicenseSeat extends SnipeModel implements ICompanyableChild
|
|||||||
return $this->license->getEula();
|
return $this->license->getEula();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function name(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute:: make(
|
||||||
|
get: fn(mixed $value) => $this->license->name,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function displayName(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute:: make(
|
||||||
|
get: fn(mixed $value) => $this->license->name,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Establishes the seat -> license relationship
|
* Establishes the seat -> license relationship
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -3,16 +3,11 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Http\Traits\UniqueUndeletedTrait;
|
use App\Http\Traits\UniqueUndeletedTrait;
|
||||||
use App\Models\Asset;
|
use App\Models\Traits\CompanyableTrait;
|
||||||
use App\Models\Setting;
|
|
||||||
use App\Models\SnipeModel;
|
|
||||||
use App\Models\Traits\HasUploads;
|
use App\Models\Traits\HasUploads;
|
||||||
use App\Models\Traits\Searchable;
|
use App\Models\Traits\Searchable;
|
||||||
use App\Models\User;
|
|
||||||
use App\Presenters\Presentable;
|
use App\Presenters\Presentable;
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Illuminate\Support\Facades\Gate;
|
use Illuminate\Support\Facades\Gate;
|
||||||
use Watson\Validating\ValidatingTrait;
|
use Watson\Validating\ValidatingTrait;
|
||||||
@@ -48,6 +43,7 @@ class Location extends SnipeModel
|
|||||||
'company_id' => 'integer',
|
'company_id' => 'integer',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the model should inject its identifier to the unique
|
* Whether the model should inject its identifier to the unique
|
||||||
* validation rules before attempting validation. If this property
|
* validation rules before attempting validation. If this property
|
||||||
@@ -118,13 +114,19 @@ class Location extends SnipeModel
|
|||||||
{
|
{
|
||||||
|
|
||||||
return Gate::allows('delete', $this)
|
return Gate::allows('delete', $this)
|
||||||
&& ($this->assets_count == 0)
|
&& ($this->deleted_at == '')
|
||||||
&& ($this->assigned_assets_count == 0)
|
&& (($this->assets_count ?? $this->assets()->count()) === 0)
|
||||||
&& ($this->children_count == 0)
|
&& (($this->assigned_assets_count ?? $this->assignedAssets()->count()) === 0)
|
||||||
&& ($this->accessories_count == 0)
|
&& (($this->accessories_count ?? $this->accessories()->count()) === 0)
|
||||||
&& ($this->users_count == 0);
|
&& (($this->assigned_accessories_count ?? $this->assignedAccessories()->count()) === 0)
|
||||||
|
&& (($this->children_count ?? $this->children()->count()) === 0)
|
||||||
|
&& (($this->components_count ?? $this->components()->count()) === 0)
|
||||||
|
&& (($this->consumables_count ?? $this->consumables()->count()) === 0)
|
||||||
|
&& (($this->rtd_assets_count ?? $this->rtd_assets()->count()) === 0)
|
||||||
|
&& (($this->users_count ?? $this->users()->count()) === 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Establishes the user -> location relationship
|
* Establishes the user -> location relationship
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -3,12 +3,13 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
|
use App\Models\Traits\CompanyableChildTrait;
|
||||||
|
use App\Models\Traits\HasUploads;
|
||||||
use App\Models\Traits\Searchable;
|
use App\Models\Traits\Searchable;
|
||||||
use App\Presenters\Presentable;
|
use App\Presenters\Presentable;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Watson\Validating\ValidatingTrait;
|
use Watson\Validating\ValidatingTrait;
|
||||||
use App\Models\Traits\HasUploads;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model for Asset Maintenances.
|
* Model for Asset Maintenances.
|
||||||
@@ -31,12 +32,12 @@ class Maintenance extends SnipeModel implements ICompanyableChild
|
|||||||
'asset_id' => 'required|integer',
|
'asset_id' => 'required|integer',
|
||||||
'supplier_id' => 'nullable|integer',
|
'supplier_id' => 'nullable|integer',
|
||||||
'asset_maintenance_type' => 'required',
|
'asset_maintenance_type' => 'required',
|
||||||
'name' => 'required|max:100',
|
'name' => 'required|max:100',
|
||||||
'is_warranty' => 'boolean',
|
'is_warranty' => 'boolean',
|
||||||
'start_date' => 'required|date_format:Y-m-d',
|
'start_date' => 'required|date_format:Y-m-d',
|
||||||
'completion_date' => 'date_format:Y-m-d|nullable|after_or_equal:start_date',
|
'completion_date' => 'date_format:Y-m-d|nullable|after_or_equal:start_date',
|
||||||
'notes' => 'string|nullable',
|
'notes' => 'string|nullable',
|
||||||
'cost' => 'numeric|nullable',
|
'cost' => 'numeric|nullable|gte:0|max:99999999999999999.99',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,10 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Support\Facades\Request;
|
||||||
|
|
||||||
class SnipeModel extends Model
|
class SnipeModel extends Model
|
||||||
{
|
{
|
||||||
@@ -156,6 +158,20 @@ class SnipeModel extends Model
|
|||||||
$this->attributes['status_id'] = $value;
|
$this->attributes['status_id'] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies offset (from request) and limit to query.
|
||||||
|
*
|
||||||
|
* @param Builder $query
|
||||||
|
* @param int $total
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function scopeApplyOffsetAndLimit(Builder $query, int $total)
|
||||||
|
{
|
||||||
|
$offset = (Request::input('offset') > $total) ? $total : app('api_offset_value');
|
||||||
|
$limit = app('api_limit_value');
|
||||||
|
|
||||||
|
$query->skip($offset)->take($limit);
|
||||||
|
}
|
||||||
|
|
||||||
protected function displayName(): Attribute
|
protected function displayName(): Attribute
|
||||||
{
|
{
|
||||||
@@ -164,5 +180,27 @@ class SnipeModel extends Model
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getEula()
|
||||||
|
{
|
||||||
|
|
||||||
|
// This is - for now - only for assets, where the asset model is the thing tied to the category
|
||||||
|
if (($this->model) && ($this->model->category)) {
|
||||||
|
if (($this->model->category->eula_text) && ($this->model->category->use_default_eula == 0)) {
|
||||||
|
return $this->model->category->eula_text;
|
||||||
|
} elseif ($this->model->category->use_default_eula == 1) {
|
||||||
|
return Setting::getSettings()->default_eula_text;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// For everything else, just check the category for EULA info
|
||||||
|
} elseif (($this->category) && ($this->category->eula_text)) {
|
||||||
|
return $this->category->eula_text;
|
||||||
|
} elseif ((Setting::getSettings()->default_eula_text) && (($this->category) && ($this->category->use_default_eula == '1'))) {
|
||||||
|
return Setting::getSettings()->default_eula_text;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models\Traits;
|
||||||
|
|
||||||
|
use App\Models\CompanyableChildScope;
|
||||||
|
|
||||||
trait CompanyableChildTrait
|
trait CompanyableChildTrait
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models\Traits;
|
||||||
|
|
||||||
|
use App\Models\CompanyableScope;
|
||||||
|
use App\Models\Setting;
|
||||||
|
|
||||||
trait CompanyableTrait
|
trait CompanyableTrait
|
||||||
{
|
{
|
||||||
@@ -12,7 +12,14 @@ trait HasUploads
|
|||||||
return $this->hasMany(Actionlog::class, 'item_id')
|
return $this->hasMany(Actionlog::class, 'item_id')
|
||||||
->where('item_type', self::class)
|
->where('item_type', self::class)
|
||||||
->where('action_type', '=', 'uploaded')
|
->where('action_type', '=', 'uploaded')
|
||||||
->whereNotNull('filename');
|
->whereNotNull('filename')
|
||||||
|
->whereNotIn('filename', function ($query) {
|
||||||
|
$query->select('filename')
|
||||||
|
->from('action_logs')
|
||||||
|
->where('item_type', '=', self::class)
|
||||||
|
->where('action_type', '=', 'upload deleted')
|
||||||
|
->where('item_id', $this->id);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,11 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Http\Traits\UniqueUndeletedTrait;
|
use App\Http\Traits\UniqueUndeletedTrait;
|
||||||
use App\Models\Traits\Searchable;
|
use App\Models\Traits\CompanyableTrait;
|
||||||
use App\Models\Traits\HasUploads;
|
use App\Models\Traits\HasUploads;
|
||||||
|
use App\Models\Traits\Searchable;
|
||||||
use App\Presenters\Presentable;
|
use App\Presenters\Presentable;
|
||||||
|
use App\Presenters\UserPresenter;
|
||||||
use Illuminate\Auth\Authenticatable;
|
use Illuminate\Auth\Authenticatable;
|
||||||
use Illuminate\Auth\Passwords\CanResetPassword;
|
use Illuminate\Auth\Passwords\CanResetPassword;
|
||||||
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
|
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
|
||||||
@@ -13,6 +15,7 @@ use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
|
|||||||
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
|
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
|
||||||
use Illuminate\Contracts\Translation\HasLocalePreference;
|
use Illuminate\Contracts\Translation\HasLocalePreference;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
@@ -22,8 +25,6 @@ use Illuminate\Support\Facades\Gate;
|
|||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Laravel\Passport\HasApiTokens;
|
use Laravel\Passport\HasApiTokens;
|
||||||
use Watson\Validating\ValidatingTrait;
|
use Watson\Validating\ValidatingTrait;
|
||||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
|
||||||
use App\Presenters\UserPresenter;
|
|
||||||
|
|
||||||
class User extends SnipeModel implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract, HasLocalePreference
|
class User extends SnipeModel implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract, HasLocalePreference
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Notifications;
|
namespace App\Notifications;
|
||||||
|
|
||||||
|
use AllowDynamicProperties;
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
@@ -10,7 +11,7 @@ use Illuminate\Notifications\Messages\MailMessage;
|
|||||||
use Illuminate\Notifications\Messages\SlackMessage;
|
use Illuminate\Notifications\Messages\SlackMessage;
|
||||||
use Illuminate\Notifications\Notification;
|
use Illuminate\Notifications\Notification;
|
||||||
|
|
||||||
class AcceptanceAssetAcceptedNotification extends Notification
|
#[AllowDynamicProperties] class AcceptanceAssetAcceptedNotification extends Notification
|
||||||
{
|
{
|
||||||
use Queueable;
|
use Queueable;
|
||||||
|
|
||||||
@@ -22,15 +23,18 @@ class AcceptanceAssetAcceptedNotification extends Notification
|
|||||||
public function __construct($params)
|
public function __construct($params)
|
||||||
{
|
{
|
||||||
$this->item_tag = $params['item_tag'];
|
$this->item_tag = $params['item_tag'];
|
||||||
|
$this->item_name = $params['item_name'];
|
||||||
$this->item_model = $params['item_model'];
|
$this->item_model = $params['item_model'];
|
||||||
$this->item_serial = $params['item_serial'];
|
$this->item_serial = $params['item_serial'];
|
||||||
$this->item_status = $params['item_status'];
|
$this->item_status = $params['item_status'];
|
||||||
$this->accepted_date = Helper::getFormattedDateObject($params['accepted_date'], 'date', false);
|
$this->accepted_date = Helper::getFormattedDateObject($params['accepted_date'], 'datetime', false);
|
||||||
$this->assigned_to = $params['assigned_to'];
|
$this->assigned_to = $params['assigned_to'];
|
||||||
$this->note = $params['note'];
|
|
||||||
$this->company_name = $params['company_name'];
|
$this->company_name = $params['company_name'];
|
||||||
$this->admin = $params['admin'] ?? null;
|
|
||||||
$this->settings = Setting::getSettings();
|
$this->settings = Setting::getSettings();
|
||||||
|
$this->file = $params['file'] ?? null;
|
||||||
|
$this->qty = $params['qty'] ?? null;
|
||||||
|
$this->note = $params['note'] ?? null;
|
||||||
|
$this->admin = $params['admin'] ?? null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,6 +69,7 @@ class AcceptanceAssetAcceptedNotification extends Notification
|
|||||||
$message = (new MailMessage)->markdown('notifications.markdown.asset-acceptance',
|
$message = (new MailMessage)->markdown('notifications.markdown.asset-acceptance',
|
||||||
[
|
[
|
||||||
'item_tag' => $this->item_tag,
|
'item_tag' => $this->item_tag,
|
||||||
|
'item_name' => $this->item_name,
|
||||||
'item_model' => $this->item_model,
|
'item_model' => $this->item_model,
|
||||||
'item_serial' => $this->item_serial,
|
'item_serial' => $this->item_serial,
|
||||||
'item_status' => $this->item_status,
|
'item_status' => $this->item_status,
|
||||||
@@ -72,8 +77,9 @@ class AcceptanceAssetAcceptedNotification extends Notification
|
|||||||
'accepted_date' => $this->accepted_date,
|
'accepted_date' => $this->accepted_date,
|
||||||
'assigned_to' => $this->assigned_to,
|
'assigned_to' => $this->assigned_to,
|
||||||
'company_name' => $this->company_name,
|
'company_name' => $this->company_name,
|
||||||
'intro_text' => trans('mail.acceptance_asset_accepted'),
|
|
||||||
'admin' => $this->admin,
|
'admin' => $this->admin,
|
||||||
|
'qty' => $this->qty,
|
||||||
|
'intro_text' => trans('mail.acceptance_asset_accepted'),
|
||||||
])
|
])
|
||||||
->subject(trans('mail.acceptance_asset_accepted'));
|
->subject(trans('mail.acceptance_asset_accepted'));
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,14 @@
|
|||||||
|
|
||||||
namespace App\Notifications;
|
namespace App\Notifications;
|
||||||
|
|
||||||
|
use AllowDynamicProperties;
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Notifications\Notification;
|
use Illuminate\Notifications\Notification;
|
||||||
|
|
||||||
class AcceptanceAssetAcceptedToUserNotification extends Notification
|
#[AllowDynamicProperties] class AcceptanceAssetAcceptedToUserNotification extends Notification
|
||||||
{
|
{
|
||||||
use Queueable;
|
use Queueable;
|
||||||
|
|
||||||
@@ -20,16 +21,18 @@ class AcceptanceAssetAcceptedToUserNotification extends Notification
|
|||||||
public function __construct($params)
|
public function __construct($params)
|
||||||
{
|
{
|
||||||
$this->item_tag = $params['item_tag'];
|
$this->item_tag = $params['item_tag'];
|
||||||
|
$this->item_name = $params['item_name'];
|
||||||
$this->item_model = $params['item_model'];
|
$this->item_model = $params['item_model'];
|
||||||
$this->item_serial = $params['item_serial'];
|
$this->item_serial = $params['item_serial'];
|
||||||
$this->item_status = $params['item_status'];
|
$this->item_status = $params['item_status'];
|
||||||
$this->accepted_date = Helper::getFormattedDateObject($params['accepted_date'], 'date', false);
|
$this->accepted_date = Helper::getFormattedDateObject($params['accepted_date'], 'datetime', false);
|
||||||
$this->assigned_to = $params['assigned_to'];
|
$this->assigned_to = $params['assigned_to'];
|
||||||
$this->note = $params['note'];
|
$this->note = $params['note'] ?? null;
|
||||||
$this->company_name = $params['company_name'];
|
$this->company_name = $params['company_name'];
|
||||||
$this->settings = Setting::getSettings();
|
$this->settings = Setting::getSettings();
|
||||||
$this->file = $params['file'] ?? null;
|
$this->file = $params['file'] ?? null;
|
||||||
|
$this->qty = $params['qty'] ?? null;
|
||||||
|
$this->admin = $params['admin'] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -59,6 +62,7 @@ class AcceptanceAssetAcceptedToUserNotification extends Notification
|
|||||||
$message = (new MailMessage)->markdown('notifications.markdown.asset-acceptance',
|
$message = (new MailMessage)->markdown('notifications.markdown.asset-acceptance',
|
||||||
[
|
[
|
||||||
'item_tag' => $this->item_tag,
|
'item_tag' => $this->item_tag,
|
||||||
|
'item_name' => $this->item_name,
|
||||||
'item_model' => $this->item_model,
|
'item_model' => $this->item_model,
|
||||||
'item_serial' => $this->item_serial,
|
'item_serial' => $this->item_serial,
|
||||||
'item_status' => $this->item_status,
|
'item_status' => $this->item_status,
|
||||||
@@ -66,10 +70,12 @@ class AcceptanceAssetAcceptedToUserNotification extends Notification
|
|||||||
'accepted_date' => $this->accepted_date,
|
'accepted_date' => $this->accepted_date,
|
||||||
'assigned_to' => $this->assigned_to,
|
'assigned_to' => $this->assigned_to,
|
||||||
'company_name' => $this->company_name,
|
'company_name' => $this->company_name,
|
||||||
'intro_text' => trans('mail.acceptance_asset_accepted_to_user', ['site_name' => $this->company_name ?? $this->settings->site_name]),
|
'admin' => $this->admin,
|
||||||
|
'qty' => $this->qty,
|
||||||
|
'intro_text' => trans_choice('mail.acceptance_asset_accepted_to_user', $this->qty, ['qty' => $this->qty, 'site_name' => $this->settings->site_name]),
|
||||||
])
|
])
|
||||||
->attach($pdf_path)
|
->attach($pdf_path)
|
||||||
->subject(trans('mail.acceptance_asset_accepted_to_user', ['site_name' => $this->settings->site_name]));
|
->subject(trans_choice('mail.acceptance_asset_accepted_to_user', $this->qty, ['qty' => $this->qty, 'site_name' => $this->settings->site_name]));
|
||||||
|
|
||||||
return $message;
|
return $message;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ class AcceptanceAssetDeclinedNotification extends Notification
|
|||||||
$this->assigned_to = $params['assigned_to'];
|
$this->assigned_to = $params['assigned_to'];
|
||||||
$this->company_name = $params['company_name'];
|
$this->company_name = $params['company_name'];
|
||||||
$this->settings = Setting::getSettings();
|
$this->settings = Setting::getSettings();
|
||||||
|
$this->qty = $params['qty'] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,6 +70,7 @@ class AcceptanceAssetDeclinedNotification extends Notification
|
|||||||
'declined_date' => $this->declined_date,
|
'declined_date' => $this->declined_date,
|
||||||
'assigned_to' => $this->assigned_to,
|
'assigned_to' => $this->assigned_to,
|
||||||
'company_name' => $this->company_name,
|
'company_name' => $this->company_name,
|
||||||
|
'qty' => $this->qty,
|
||||||
'intro_text' => trans('mail.acceptance_asset_declined'),
|
'intro_text' => trans('mail.acceptance_asset_declined'),
|
||||||
])
|
])
|
||||||
->subject(trans('mail.acceptance_asset_declined'));
|
->subject(trans('mail.acceptance_asset_declined'));
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
|
|||||||
->from(($this->settings->webhook_botname) ? $this->settings->webhook_botname : 'Snipe-Bot')
|
->from(($this->settings->webhook_botname) ? $this->settings->webhook_botname : 'Snipe-Bot')
|
||||||
->to($channel)
|
->to($channel)
|
||||||
->attachment(function ($attachment) {
|
->attachment(function ($attachment) {
|
||||||
$item = $this->params['item'];
|
$item = $this->params['item'] ?? null;
|
||||||
$admin_user = $this->params['admin'];
|
$admin_user = $this->params['admin'];
|
||||||
$fields = [
|
$fields = [
|
||||||
'By' => '<'.$admin_user->present()->viewUrl().'|'.$admin_user->display_name.'>',
|
'By' => '<'.$admin_user->present()->viewUrl().'|'.$admin_user->display_name.'>',
|
||||||
@@ -93,7 +93,7 @@ use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
|
|||||||
}
|
}
|
||||||
$message = class_basename(get_class($params['item'])) . ' Audited By '.$admin_user->display_name;
|
$message = class_basename(get_class($params['item'])) . ' Audited By '.$admin_user->display_name;
|
||||||
$details = [
|
$details = [
|
||||||
trans('mail.asset') => htmlspecialchars_decode($item->present()->name),
|
trans('mail.asset') => htmlspecialchars_decode($item->display_name),
|
||||||
trans('mail.notes') => $note ?: '',
|
trans('mail.notes') => $note ?: '',
|
||||||
trans('general.location') => $location ?: '',
|
trans('general.location') => $location ?: '',
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ class CheckinAccessoryNotification extends Notification
|
|||||||
->from($botname)
|
->from($botname)
|
||||||
->to($channel)
|
->to($channel)
|
||||||
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
||||||
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
|
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
|
||||||
->fields($fields)
|
->fields($fields)
|
||||||
->content($note);
|
->content($note);
|
||||||
});
|
});
|
||||||
@@ -107,7 +107,7 @@ class CheckinAccessoryNotification extends Notification
|
|||||||
->addStartGroupToSection('activityTitle')
|
->addStartGroupToSection('activityTitle')
|
||||||
->title(trans('Accessory_Checkin_Notification'))
|
->title(trans('Accessory_Checkin_Notification'))
|
||||||
->addStartGroupToSection('activityText')
|
->addStartGroupToSection('activityText')
|
||||||
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityTitle')
|
->fact(htmlspecialchars_decode($item->display_name), '', 'activityTitle')
|
||||||
->fact(trans('mail.checked_into'), $item->location->name ? $item->location->name : '')
|
->fact(trans('mail.checked_into'), $item->location->name ? $item->location->name : '')
|
||||||
->fact(trans('mail.Accessory_Checkin_Notification')." by ", $admin->display_name)
|
->fact(trans('mail.Accessory_Checkin_Notification')." by ", $admin->display_name)
|
||||||
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
|
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
|
||||||
@@ -116,7 +116,7 @@ class CheckinAccessoryNotification extends Notification
|
|||||||
|
|
||||||
$message = trans('mail.Accessory_Checkin_Notification');
|
$message = trans('mail.Accessory_Checkin_Notification');
|
||||||
$details = [
|
$details = [
|
||||||
trans('mail.accessory_name') => htmlspecialchars_decode($item->present()->name),
|
trans('mail.accessory_name') => htmlspecialchars_decode($item->display_name),
|
||||||
trans('mail.checked_into') => $item->location->name ? $item->location->name : '',
|
trans('mail.checked_into') => $item->location->name ? $item->location->name : '',
|
||||||
trans('mail.Accessory_Checkin_Notification'). ' by' => $admin->display_name,
|
trans('mail.Accessory_Checkin_Notification'). ' by' => $admin->display_name,
|
||||||
trans('admin/consumables/general.remaining')=> $item->numRemaining(),
|
trans('admin/consumables/general.remaining')=> $item->numRemaining(),
|
||||||
@@ -135,7 +135,7 @@ class CheckinAccessoryNotification extends Notification
|
|||||||
Card::create()
|
Card::create()
|
||||||
->header(
|
->header(
|
||||||
'<strong>'.trans('mail.Accessory_Checkin_Notification').'</strong>' ?: '',
|
'<strong>'.trans('mail.Accessory_Checkin_Notification').'</strong>' ?: '',
|
||||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
htmlspecialchars_decode($item->display_name) ?: '',
|
||||||
)
|
)
|
||||||
->section(
|
->section(
|
||||||
Section::create(
|
Section::create(
|
||||||
|
|||||||
@@ -93,11 +93,11 @@ class CheckinAssetNotification extends Notification
|
|||||||
|
|
||||||
|
|
||||||
return (new SlackMessage)
|
return (new SlackMessage)
|
||||||
->content(':arrow_down: :computer: '.trans('mail.Asset_Checkin_Notification'))
|
->content(':arrow_down: :computer: '.trans('mail.Asset_Checkin_Notification', ['tag' => '']))
|
||||||
->from($botname)
|
->from($botname)
|
||||||
->to($channel)
|
->to($channel)
|
||||||
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
||||||
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
|
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
|
||||||
->fields($fields)
|
->fields($fields)
|
||||||
->content($note);
|
->content($note);
|
||||||
});
|
});
|
||||||
@@ -112,21 +112,21 @@ class CheckinAssetNotification extends Notification
|
|||||||
return MicrosoftTeamsMessage::create()
|
return MicrosoftTeamsMessage::create()
|
||||||
->to($this->settings->webhook_endpoint)
|
->to($this->settings->webhook_endpoint)
|
||||||
->type('success')
|
->type('success')
|
||||||
->title(trans('mail.Asset_Checkin_Notification'))
|
->title(trans('mail.Asset_Checkin_Notification', ['tag' => '']))
|
||||||
->addStartGroupToSection('activityText')
|
->addStartGroupToSection('activityText')
|
||||||
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityText')
|
->fact(htmlspecialchars_decode($item->display_name), '', 'activityText')
|
||||||
->fact(trans('mail.checked_into'), ($item->location) ? $item->location->name : '')
|
->fact(trans('mail.checked_into'), ($item->location) ? $item->location->name : '')
|
||||||
->fact(trans('mail.Asset_Checkin_Notification') . " by ", $admin->display_name)
|
->fact(trans('general.administrator'), $admin->display_name)
|
||||||
->fact(trans('admin/hardware/form.status'), $item->assetstatus?->name)
|
->fact(trans('admin/hardware/form.status'), $item->assetstatus?->name)
|
||||||
->fact(trans('mail.notes'), $note ?: '');
|
->fact(trans('mail.notes'), $note ?: '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$message = trans('mail.Asset_Checkin_Notification');
|
$message = trans('mail.Asset_Checkin_Notification', ['tag' => '']);
|
||||||
$details = [
|
$details = [
|
||||||
trans('mail.asset') => htmlspecialchars_decode($item->present()->name),
|
trans('mail.asset') => htmlspecialchars_decode($item->display_name),
|
||||||
trans('mail.checked_into') => ($item->location) ? $item->location->name : '',
|
trans('mail.checked_into') => ($item->location) ? $item->location->name : '',
|
||||||
trans('mail.Asset_Checkin_Notification')." by " => $admin->display_name,
|
trans('general.administrator') => $admin->display_name,
|
||||||
trans('admin/hardware/form.status') => $item->assetstatus?->name,
|
trans('admin/hardware/form.status') => $item->assetstatus?->name,
|
||||||
trans('mail.notes') => $note ?: '',
|
trans('mail.notes') => $note ?: '',
|
||||||
];
|
];
|
||||||
@@ -144,8 +144,8 @@ class CheckinAssetNotification extends Notification
|
|||||||
->card(
|
->card(
|
||||||
Card::create()
|
Card::create()
|
||||||
->header(
|
->header(
|
||||||
'<strong>'.trans('mail.Asset_Checkin_Notification').'</strong>' ?: '',
|
'<strong>'.trans('mail.Asset_Checkin_Notification', ['tag' =>'']).'</strong>' ?: '',
|
||||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
htmlspecialchars_decode($item->display_name) ?: '',
|
||||||
)
|
)
|
||||||
->section(
|
->section(
|
||||||
Section::create(
|
Section::create(
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ class CheckinComponentNotification extends Notification
|
|||||||
->from($botname)
|
->from($botname)
|
||||||
->to($channel)
|
->to($channel)
|
||||||
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
||||||
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
|
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
|
||||||
->fields($fields)
|
->fields($fields)
|
||||||
->content($note);
|
->content($note);
|
||||||
});
|
});
|
||||||
@@ -118,7 +118,7 @@ class CheckinComponentNotification extends Notification
|
|||||||
->addStartGroupToSection('activityTitle')
|
->addStartGroupToSection('activityTitle')
|
||||||
->title(trans('mail.Component_checkin_notification'))
|
->title(trans('mail.Component_checkin_notification'))
|
||||||
->addStartGroupToSection('activityText')
|
->addStartGroupToSection('activityText')
|
||||||
->fact(htmlspecialchars_decode($item->present()->name), '', 'header')
|
->fact(htmlspecialchars_decode($item->display_name), '', 'header')
|
||||||
->fact(trans('mail.Component_checkin_notification')." by ", $admin->display_name ?: 'CLI tool')
|
->fact(trans('mail.Component_checkin_notification')." by ", $admin->display_name ?: 'CLI tool')
|
||||||
->fact(trans('mail.checkedin_from'), $target->display_name)
|
->fact(trans('mail.checkedin_from'), $target->display_name)
|
||||||
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
|
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
|
||||||
@@ -147,7 +147,7 @@ class CheckinComponentNotification extends Notification
|
|||||||
Card::create()
|
Card::create()
|
||||||
->header(
|
->header(
|
||||||
'<strong>'.trans('mail.Component_checkin_notification').'</strong>' ?: '',
|
'<strong>'.trans('mail.Component_checkin_notification').'</strong>' ?: '',
|
||||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
htmlspecialchars_decode($item->display_name) ?: '',
|
||||||
)
|
)
|
||||||
->section(
|
->section(
|
||||||
Section::create(
|
Section::create(
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ class CheckinLicenseSeatNotification extends Notification
|
|||||||
->from($botname)
|
->from($botname)
|
||||||
->to($channel)
|
->to($channel)
|
||||||
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
||||||
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
|
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
|
||||||
->fields($fields)
|
->fields($fields)
|
||||||
->content($note);
|
->content($note);
|
||||||
});
|
});
|
||||||
@@ -119,7 +119,7 @@ class CheckinLicenseSeatNotification extends Notification
|
|||||||
->addStartGroupToSection('activityTitle')
|
->addStartGroupToSection('activityTitle')
|
||||||
->title(trans('mail.License_Checkin_Notification'))
|
->title(trans('mail.License_Checkin_Notification'))
|
||||||
->addStartGroupToSection('activityText')
|
->addStartGroupToSection('activityText')
|
||||||
->fact(htmlspecialchars_decode($item->present()->name), '', 'header')
|
->fact(htmlspecialchars_decode($item->display_name), '', 'header')
|
||||||
->fact(trans('mail.License_Checkin_Notification')." by ", $admin->display_name ?: 'CLI tool')
|
->fact(trans('mail.License_Checkin_Notification')." by ", $admin->display_name ?: 'CLI tool')
|
||||||
->fact(trans('mail.checkedin_from'), $target->display_name)
|
->fact(trans('mail.checkedin_from'), $target->display_name)
|
||||||
->fact(trans('admin/consumables/general.remaining'), $item->availCount()->count())
|
->fact(trans('admin/consumables/general.remaining'), $item->availCount()->count())
|
||||||
@@ -129,7 +129,7 @@ class CheckinLicenseSeatNotification extends Notification
|
|||||||
$message = trans('mail.License_Checkin_Notification');
|
$message = trans('mail.License_Checkin_Notification');
|
||||||
$details = [
|
$details = [
|
||||||
trans('mail.checkedin_from')=> $target->display_name,
|
trans('mail.checkedin_from')=> $target->display_name,
|
||||||
trans('mail.license_for') => htmlspecialchars_decode($item->present()->name),
|
trans('mail.license_for') => htmlspecialchars_decode($item->display_name),
|
||||||
trans('mail.License_Checkin_Notification')." by " => $admin->display_name ?: 'CLI tool',
|
trans('mail.License_Checkin_Notification')." by " => $admin->display_name ?: 'CLI tool',
|
||||||
trans('admin/consumables/general.remaining') => $item->availCount()->count(),
|
trans('admin/consumables/general.remaining') => $item->availCount()->count(),
|
||||||
trans('mail.notes') => $note ?: '',
|
trans('mail.notes') => $note ?: '',
|
||||||
@@ -149,7 +149,7 @@ class CheckinLicenseSeatNotification extends Notification
|
|||||||
Card::create()
|
Card::create()
|
||||||
->header(
|
->header(
|
||||||
'<strong>'.trans('mail.License_Checkin_Notification').'</strong>' ?: '',
|
'<strong>'.trans('mail.License_Checkin_Notification').'</strong>' ?: '',
|
||||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
htmlspecialchars_decode($item->display_name) ?: '',
|
||||||
)
|
)
|
||||||
->section(
|
->section(
|
||||||
Section::create(
|
Section::create(
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ class CheckoutAccessoryNotification extends Notification
|
|||||||
->from($botname)
|
->from($botname)
|
||||||
->to($channel)
|
->to($channel)
|
||||||
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
||||||
$attachment->title(htmlspecialchars_decode($this->checkout_qty.' x '.$item->present()->name), $item->present()->viewUrl())
|
$attachment->title(htmlspecialchars_decode($this->checkout_qty.' x '.$item->display_name), $item->present()->viewUrl())
|
||||||
->fields($fields)
|
->fields($fields)
|
||||||
->content($note);
|
->content($note);
|
||||||
});
|
});
|
||||||
@@ -136,8 +136,8 @@ class CheckoutAccessoryNotification extends Notification
|
|||||||
->addStartGroupToSection('activityTitle')
|
->addStartGroupToSection('activityTitle')
|
||||||
->title(trans('mail.Accessory_Checkout_Notification'))
|
->title(trans('mail.Accessory_Checkout_Notification'))
|
||||||
->addStartGroupToSection('activityText')
|
->addStartGroupToSection('activityText')
|
||||||
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityTitle')
|
->fact(htmlspecialchars_decode($item->display_name), '', 'activityTitle')
|
||||||
->fact(trans('mail.assigned_to'), $target->present()->name)
|
->fact(trans('mail.assigned_to'), $target->display_name)
|
||||||
->fact(trans('general.qty'), $this->checkout_qty)
|
->fact(trans('general.qty'), $this->checkout_qty)
|
||||||
->fact(trans('mail.checkedout_from'), $item->location->name ? $item->location->name : '')
|
->fact(trans('mail.checkedout_from'), $item->location->name ? $item->location->name : '')
|
||||||
->fact(trans('mail.Accessory_Checkout_Notification') . " by ", $admin->display_name)
|
->fact(trans('mail.Accessory_Checkout_Notification') . " by ", $admin->display_name)
|
||||||
@@ -148,7 +148,7 @@ class CheckoutAccessoryNotification extends Notification
|
|||||||
$message = trans('mail.Accessory_Checkout_Notification');
|
$message = trans('mail.Accessory_Checkout_Notification');
|
||||||
$details = [
|
$details = [
|
||||||
trans('mail.assigned_to') => $target->present()->name,
|
trans('mail.assigned_to') => $target->present()->name,
|
||||||
trans('mail.accessory_name') => htmlspecialchars_decode($item->present()->name),
|
trans('mail.accessory_name') => htmlspecialchars_decode($item->display_name),
|
||||||
trans('general.qty') => $this->checkout_qty,
|
trans('general.qty') => $this->checkout_qty,
|
||||||
trans('mail.checkedout_from') => $item->location->name ? $item->location->name : '',
|
trans('mail.checkedout_from') => $item->location->name ? $item->location->name : '',
|
||||||
trans('mail.Accessory_Checkout_Notification'). ' by' => $admin->display_name,
|
trans('mail.Accessory_Checkout_Notification'). ' by' => $admin->display_name,
|
||||||
@@ -169,7 +169,7 @@ class CheckoutAccessoryNotification extends Notification
|
|||||||
Card::create()
|
Card::create()
|
||||||
->header(
|
->header(
|
||||||
'<strong>'.trans('mail.Accessory_Checkout_Notification').'</strong>' ?: '',
|
'<strong>'.trans('mail.Accessory_Checkout_Notification').'</strong>' ?: '',
|
||||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
htmlspecialchars_decode($item->display_name) ?: '',
|
||||||
)
|
)
|
||||||
->section(
|
->section(
|
||||||
Section::create(
|
Section::create(
|
||||||
|
|||||||
@@ -110,11 +110,11 @@ class CheckoutAssetNotification extends Notification
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (new SlackMessage)
|
return (new SlackMessage)
|
||||||
->content(':arrow_up: :computer: '.trans('mail.Asset_Checkout_Notification'))
|
->content(':arrow_up: :computer: '.trans('mail.Asset_Checkout_Notification', ['tag' => '']))
|
||||||
->from($botname)
|
->from($botname)
|
||||||
->to($channel)
|
->to($channel)
|
||||||
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
||||||
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
|
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
|
||||||
->fields($fields)
|
->fields($fields)
|
||||||
->content($note);
|
->content($note);
|
||||||
});
|
});
|
||||||
@@ -131,19 +131,19 @@ class CheckoutAssetNotification extends Notification
|
|||||||
return MicrosoftTeamsMessage::create()
|
return MicrosoftTeamsMessage::create()
|
||||||
->to($this->settings->webhook_endpoint)
|
->to($this->settings->webhook_endpoint)
|
||||||
->type('success')
|
->type('success')
|
||||||
->title(trans('mail.Asset_Checkout_Notification'))
|
->title(trans('mail.Asset_Checkout_Notification', ['tag' => '']))
|
||||||
->addStartGroupToSection('activityText')
|
->addStartGroupToSection('activityText')
|
||||||
->fact(trans('mail.assigned_to'), $target->present()->name)
|
->fact(trans('mail.assigned_to'), $target->display_name)
|
||||||
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityText')
|
->fact(htmlspecialchars_decode($item->display_name), '', 'activityText')
|
||||||
->fact(trans('mail.Asset_Checkout_Notification') . " by ", $admin->display_name)
|
->fact(trans('general.administrator'), $admin->display_name)
|
||||||
->fact(trans('mail.notes'), $note ?: '');
|
->fact(trans('mail.notes'), $note ?: '');
|
||||||
}
|
}
|
||||||
|
|
||||||
$message = trans('mail.Asset_Checkout_Notification');
|
$message = trans('mail.Asset_Checkout_Notification', ['tag' => '']);
|
||||||
$details = [
|
$details = [
|
||||||
trans('mail.assigned_to') => $target->present()->name,
|
trans('mail.assigned_to') => $target->present()->name,
|
||||||
trans('mail.asset') => htmlspecialchars_decode($item->present()->name),
|
trans('mail.asset') => htmlspecialchars_decode($item->display_name),
|
||||||
trans('mail.Asset_Checkout_Notification'). ' by' => $admin->display_name,
|
trans('general.administrator') => $admin->display_name,
|
||||||
trans('mail.notes') => $note ?: '',
|
trans('mail.notes') => $note ?: '',
|
||||||
];
|
];
|
||||||
return array($message, $details);
|
return array($message, $details);
|
||||||
@@ -159,8 +159,8 @@ public function toGoogleChat()
|
|||||||
->card(
|
->card(
|
||||||
Card::create()
|
Card::create()
|
||||||
->header(
|
->header(
|
||||||
'<strong>'.trans('mail.Asset_Checkout_Notification').'</strong>' ?: '',
|
'<strong>'.trans('mail.Asset_Checkout_Notification', ['tag' => '']).'</strong>' ?: '',
|
||||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
htmlspecialchars_decode($item->display_name) ?: '',
|
||||||
)
|
)
|
||||||
->section(
|
->section(
|
||||||
Section::create(
|
Section::create(
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ class CheckoutComponentNotification extends Notification
|
|||||||
->from($botname)
|
->from($botname)
|
||||||
->to($channel)
|
->to($channel)
|
||||||
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
||||||
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
|
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
|
||||||
->fields($fields)
|
->fields($fields)
|
||||||
->content($note);
|
->content($note);
|
||||||
});
|
});
|
||||||
@@ -116,7 +116,7 @@ class CheckoutComponentNotification extends Notification
|
|||||||
->addStartGroupToSection('activityTitle')
|
->addStartGroupToSection('activityTitle')
|
||||||
->title(trans('mail.Component_checkout_notification'))
|
->title(trans('mail.Component_checkout_notification'))
|
||||||
->addStartGroupToSection('activityText')
|
->addStartGroupToSection('activityText')
|
||||||
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityTitle')
|
->fact(htmlspecialchars_decode($item->display_name), '', 'activityTitle')
|
||||||
->fact(trans('mail.Component_checkout_notification')." by ", $admin->display_name)
|
->fact(trans('mail.Component_checkout_notification')." by ", $admin->display_name)
|
||||||
->fact(trans('mail.assigned_to'), $target->display_name)
|
->fact(trans('mail.assigned_to'), $target->display_name)
|
||||||
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
|
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
|
||||||
@@ -126,7 +126,7 @@ class CheckoutComponentNotification extends Notification
|
|||||||
$message = trans('mail.Component_checkout_notification');
|
$message = trans('mail.Component_checkout_notification');
|
||||||
$details = [
|
$details = [
|
||||||
trans('mail.assigned_to') => $target->display_name,
|
trans('mail.assigned_to') => $target->display_name,
|
||||||
trans('mail.item') => htmlspecialchars_decode($item->present()->name),
|
trans('mail.item') => htmlspecialchars_decode($item->display_name),
|
||||||
trans('mail.Component_checkout_notification').' by' => $admin->display_name,
|
trans('mail.Component_checkout_notification').' by' => $admin->display_name,
|
||||||
trans('admin/consumables/general.remaining') => $item->numRemaining(),
|
trans('admin/consumables/general.remaining') => $item->numRemaining(),
|
||||||
trans('mail.notes') => $note ?: '',
|
trans('mail.notes') => $note ?: '',
|
||||||
@@ -146,7 +146,7 @@ class CheckoutComponentNotification extends Notification
|
|||||||
Card::create()
|
Card::create()
|
||||||
->header(
|
->header(
|
||||||
'<strong>'.trans('mail.Component_checkout_notification').'</strong>' ?: '',
|
'<strong>'.trans('mail.Component_checkout_notification').'</strong>' ?: '',
|
||||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
htmlspecialchars_decode($item->display_name) ?: '',
|
||||||
)
|
)
|
||||||
->section(
|
->section(
|
||||||
Section::create(
|
Section::create(
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ class CheckoutConsumableNotification extends Notification
|
|||||||
->from($botname)
|
->from($botname)
|
||||||
->to($channel)
|
->to($channel)
|
||||||
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
||||||
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
|
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
|
||||||
->fields($fields)
|
->fields($fields)
|
||||||
->content($note);
|
->content($note);
|
||||||
});
|
});
|
||||||
@@ -116,7 +116,7 @@ class CheckoutConsumableNotification extends Notification
|
|||||||
->addStartGroupToSection('activityTitle')
|
->addStartGroupToSection('activityTitle')
|
||||||
->title(trans('mail.Consumable_checkout_notification'))
|
->title(trans('mail.Consumable_checkout_notification'))
|
||||||
->addStartGroupToSection('activityText')
|
->addStartGroupToSection('activityText')
|
||||||
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityTitle')
|
->fact(htmlspecialchars_decode($item->display_name), '', 'activityTitle')
|
||||||
->fact(trans('mail.Consumable_checkout_notification')." by ", $admin->display_name)
|
->fact(trans('mail.Consumable_checkout_notification')." by ", $admin->display_name)
|
||||||
->fact(trans('mail.assigned_to'), $target->display_name)
|
->fact(trans('mail.assigned_to'), $target->display_name)
|
||||||
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
|
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
|
||||||
@@ -126,7 +126,7 @@ class CheckoutConsumableNotification extends Notification
|
|||||||
$message = trans('mail.Consumable_checkout_notification');
|
$message = trans('mail.Consumable_checkout_notification');
|
||||||
$details = [
|
$details = [
|
||||||
trans('mail.assigned_to') => $target->display_name,
|
trans('mail.assigned_to') => $target->display_name,
|
||||||
trans('mail.item') => htmlspecialchars_decode($item->present()->name),
|
trans('mail.item') => htmlspecialchars_decode($item->display_name),
|
||||||
trans('mail.Consumable_checkout_notification').' by' => $admin->display_name,
|
trans('mail.Consumable_checkout_notification').' by' => $admin->display_name,
|
||||||
trans('admin/consumables/general.remaining') => $item->numRemaining(),
|
trans('admin/consumables/general.remaining') => $item->numRemaining(),
|
||||||
trans('mail.notes') => $note ?: '',
|
trans('mail.notes') => $note ?: '',
|
||||||
@@ -146,7 +146,7 @@ class CheckoutConsumableNotification extends Notification
|
|||||||
Card::create()
|
Card::create()
|
||||||
->header(
|
->header(
|
||||||
'<strong>'.trans('mail.Consumable_checkout_notification').'</strong>' ?: '',
|
'<strong>'.trans('mail.Consumable_checkout_notification').'</strong>' ?: '',
|
||||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
htmlspecialchars_decode($item->display_name) ?: '',
|
||||||
)
|
)
|
||||||
->section(
|
->section(
|
||||||
Section::create(
|
Section::create(
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ class CheckoutLicenseSeatNotification extends Notification
|
|||||||
->from($botname)
|
->from($botname)
|
||||||
->to($channel)
|
->to($channel)
|
||||||
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
||||||
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
|
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
|
||||||
->fields($fields)
|
->fields($fields)
|
||||||
->content($note);
|
->content($note);
|
||||||
});
|
});
|
||||||
@@ -114,7 +114,7 @@ class CheckoutLicenseSeatNotification extends Notification
|
|||||||
->addStartGroupToSection('activityTitle')
|
->addStartGroupToSection('activityTitle')
|
||||||
->title(trans('mail.License_Checkout_Notification'))
|
->title(trans('mail.License_Checkout_Notification'))
|
||||||
->addStartGroupToSection('activityText')
|
->addStartGroupToSection('activityText')
|
||||||
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityTitle')
|
->fact(htmlspecialchars_decode($item->display_name), '', 'activityTitle')
|
||||||
->fact(trans('mail.License_Checkout_Notification')." by ", $admin->display_name)
|
->fact(trans('mail.License_Checkout_Notification')." by ", $admin->display_name)
|
||||||
->fact(trans('mail.assigned_to'), $target->display_name)
|
->fact(trans('mail.assigned_to'), $target->display_name)
|
||||||
->fact(trans('admin/consumables/general.remaining'), $item->availCount()->count())
|
->fact(trans('admin/consumables/general.remaining'), $item->availCount()->count())
|
||||||
@@ -124,7 +124,7 @@ class CheckoutLicenseSeatNotification extends Notification
|
|||||||
$message = trans('mail.License_Checkout_Notification');
|
$message = trans('mail.License_Checkout_Notification');
|
||||||
$details = [
|
$details = [
|
||||||
trans('mail.assigned_to') => $target->display_name,
|
trans('mail.assigned_to') => $target->display_name,
|
||||||
trans('mail.license_for') => htmlspecialchars_decode($item->present()->name),
|
trans('mail.license_for') => htmlspecialchars_decode($item->display_name),
|
||||||
trans('mail.License_Checkout_Notification').' by' => $admin->display_name,
|
trans('mail.License_Checkout_Notification').' by' => $admin->display_name,
|
||||||
trans('admin/consumables/general.remaining') => $item->availCount()->count(),
|
trans('admin/consumables/general.remaining') => $item->availCount()->count(),
|
||||||
trans('mail.notes') => $note ?: '',
|
trans('mail.notes') => $note ?: '',
|
||||||
@@ -143,7 +143,7 @@ class CheckoutLicenseSeatNotification extends Notification
|
|||||||
Card::create()
|
Card::create()
|
||||||
->header(
|
->header(
|
||||||
'<strong>'.trans('mail.License_Checkout_Notification').'</strong>' ?: '',
|
'<strong>'.trans('mail.License_Checkout_Notification').'</strong>' ?: '',
|
||||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
htmlspecialchars_decode($item->display_name) ?: '',
|
||||||
)
|
)
|
||||||
->section(
|
->section(
|
||||||
Section::create(
|
Section::create(
|
||||||
|
|||||||
@@ -50,11 +50,11 @@ class ExpectedCheckinNotification extends Notification
|
|||||||
$message = (new MailMessage)->markdown('notifications.markdown.expected-checkin',
|
$message = (new MailMessage)->markdown('notifications.markdown.expected-checkin',
|
||||||
[
|
[
|
||||||
'date' => Helper::getFormattedDateObject($this->params->expected_checkin, 'date', false),
|
'date' => Helper::getFormattedDateObject($this->params->expected_checkin, 'date', false),
|
||||||
'asset' => $this->params->present()->name(),
|
'asset' => $this->params->display_name,
|
||||||
'serial' => $this->params->serial,
|
'serial' => $this->params->serial,
|
||||||
'asset_tag' => $this->params->asset_tag,
|
'asset_tag' => $this->params->asset_tag,
|
||||||
])
|
])
|
||||||
->subject(trans('mail.Expected_Checkin_Notification', ['name' => $this->params->present()->name()]));
|
->subject(trans('mail.Expected_Checkin_Notification', ['name' => $this->params->display_name]));
|
||||||
|
|
||||||
return $message;
|
return $message;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ class RequestAssetCancelation extends Notification
|
|||||||
->from($botname)
|
->from($botname)
|
||||||
->to($channel)
|
->to($channel)
|
||||||
->attachment(function ($attachment) use ($item, $note, $fields) {
|
->attachment(function ($attachment) use ($item, $note, $fields) {
|
||||||
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
|
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
|
||||||
->fields($fields)
|
->fields($fields)
|
||||||
->content($note);
|
->content($note);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ class RequestAssetNotification extends Notification
|
|||||||
->from($botname)
|
->from($botname)
|
||||||
->to($channel)
|
->to($channel)
|
||||||
->attachment(function ($attachment) use ($item, $note, $fields) {
|
->attachment(function ($attachment) use ($item, $note, $fields) {
|
||||||
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
|
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
|
||||||
->fields($fields)
|
->fields($fields)
|
||||||
->content($note);
|
->content($note);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -120,7 +120,13 @@ class AccessoryPresenter extends Presenter
|
|||||||
'field' => 'purchase_cost',
|
'field' => 'purchase_cost',
|
||||||
'searchable' => true,
|
'searchable' => true,
|
||||||
'sortable' => true,
|
'sortable' => true,
|
||||||
'title' => trans('general.purchase_cost'),
|
'title' => trans('general.unit_cost'),
|
||||||
|
'class' => 'text-right text-padding-number-cell',
|
||||||
|
], [
|
||||||
|
'field' => 'total_cost',
|
||||||
|
'searchable' => true,
|
||||||
|
'sortable' => true,
|
||||||
|
'title' => trans('general.total_cost'),
|
||||||
'footerFormatter' => 'sumFormatterQuantity',
|
'footerFormatter' => 'sumFormatterQuantity',
|
||||||
'class' => 'text-right text-padding-number-cell',
|
'class' => 'text-right text-padding-number-cell',
|
||||||
], [
|
], [
|
||||||
|
|||||||
@@ -62,6 +62,10 @@ class ActionlogPresenter extends Presenter
|
|||||||
return 'fa-solid fa-user-minus';
|
return 'fa-solid fa-user-minus';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->action_type == 'upload deleted') {
|
||||||
|
return 'fa-solid fa-trash';
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->action_type == 'update') {
|
if ($this->action_type == 'update') {
|
||||||
return 'fa-solid fa-user-pen';
|
return 'fa-solid fa-user-pen';
|
||||||
}
|
}
|
||||||
@@ -74,7 +78,7 @@ class ActionlogPresenter extends Presenter
|
|||||||
return 'fa-solid fa-plus';
|
return 'fa-solid fa-plus';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->action_type == 'delete') {
|
if (($this->action_type == 'delete') || ($this->action_type == 'upload deleted')) {
|
||||||
return 'fa-solid fa-trash';
|
return 'fa-solid fa-trash';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +145,7 @@ class ActionlogPresenter extends Presenter
|
|||||||
return $target->present()->nameUrl();
|
return $target->present()->nameUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
return '<del>'.$target->present()->name().'</del>';
|
return '<del>'.$target->display_name.'</del>';
|
||||||
}
|
}
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
|
|||||||
@@ -143,6 +143,14 @@ class AssetModelPresenter extends Presenter
|
|||||||
'title' => trans('admin/hardware/general.requestable'),
|
'title' => trans('admin/hardware/general.requestable'),
|
||||||
'formatter' => 'trueFalseFormatter',
|
'formatter' => 'trueFalseFormatter',
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'field' => 'require_serial',
|
||||||
|
'searchable' => false,
|
||||||
|
'sortable' => true,
|
||||||
|
'visible' => false,
|
||||||
|
'title' => trans('admin/hardware/general.require_serial'),
|
||||||
|
'formatter' => 'trueFalseFormatter',
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'field' => 'notes',
|
'field' => 'notes',
|
||||||
'searchable' => true,
|
'searchable' => true,
|
||||||
|
|||||||
@@ -79,6 +79,25 @@ class ComponentPresenter extends Presenter
|
|||||||
'title' => trans('general.manufacturer'),
|
'title' => trans('general.manufacturer'),
|
||||||
'visible' => false,
|
'visible' => false,
|
||||||
'formatter' => 'manufacturersLinkObjFormatter',
|
'formatter' => 'manufacturersLinkObjFormatter',
|
||||||
|
], [
|
||||||
|
'field' => 'location',
|
||||||
|
'searchable' => true,
|
||||||
|
'sortable' => true,
|
||||||
|
'title' => trans('general.location'),
|
||||||
|
'formatter' => 'locationsLinkObjFormatter',
|
||||||
|
], [
|
||||||
|
'field' => 'order_number',
|
||||||
|
'searchable' => true,
|
||||||
|
'sortable' => true,
|
||||||
|
'title' => trans('general.order_number'),
|
||||||
|
'visible' => true,
|
||||||
|
], [
|
||||||
|
'field' => 'purchase_date',
|
||||||
|
'searchable' => true,
|
||||||
|
'sortable' => true,
|
||||||
|
'title' => trans('general.purchase_date'),
|
||||||
|
'visible' => true,
|
||||||
|
'formatter' => 'dateDisplayFormatter',
|
||||||
], [
|
], [
|
||||||
'field' => 'min_amt',
|
'field' => 'min_amt',
|
||||||
'searchable' => false,
|
'searchable' => false,
|
||||||
@@ -103,33 +122,20 @@ class ComponentPresenter extends Presenter
|
|||||||
'visible' => true,
|
'visible' => true,
|
||||||
'class' => 'text-right text-padding-number-cell',
|
'class' => 'text-right text-padding-number-cell',
|
||||||
'footerFormatter' => 'qtySumFormatter',
|
'footerFormatter' => 'qtySumFormatter',
|
||||||
], [
|
|
||||||
'field' => 'location',
|
|
||||||
'searchable' => true,
|
|
||||||
'sortable' => true,
|
|
||||||
'title' => trans('general.location'),
|
|
||||||
'formatter' => 'locationsLinkObjFormatter',
|
|
||||||
], [
|
|
||||||
'field' => 'order_number',
|
|
||||||
'searchable' => true,
|
|
||||||
'sortable' => true,
|
|
||||||
'title' => trans('general.order_number'),
|
|
||||||
'visible' => true,
|
|
||||||
], [
|
|
||||||
'field' => 'purchase_date',
|
|
||||||
'searchable' => true,
|
|
||||||
'sortable' => true,
|
|
||||||
'title' => trans('general.purchase_date'),
|
|
||||||
'visible' => true,
|
|
||||||
'formatter' => 'dateDisplayFormatter',
|
|
||||||
], [
|
], [
|
||||||
'field' => 'purchase_cost',
|
'field' => 'purchase_cost',
|
||||||
'searchable' => true,
|
'searchable' => true,
|
||||||
'sortable' => true,
|
'sortable' => true,
|
||||||
'title' => trans('general.purchase_cost'),
|
'title' => trans('general.unit_cost'),
|
||||||
'visible' => true,
|
'visible' => true,
|
||||||
'footerFormatter' => 'sumFormatterQuantity',
|
|
||||||
'class' => 'text-right',
|
'class' => 'text-right',
|
||||||
|
], [
|
||||||
|
'field' => 'total_cost',
|
||||||
|
'searchable' => true,
|
||||||
|
'sortable' => true,
|
||||||
|
'title' => trans('general.total_cost'),
|
||||||
|
'footerFormatter' => 'sumFormatterQuantity',
|
||||||
|
'class' => 'text-right text-padding-number-cell',
|
||||||
], [
|
], [
|
||||||
'field' => 'notes',
|
'field' => 'notes',
|
||||||
'searchable' => true,
|
'searchable' => true,
|
||||||
|
|||||||
@@ -67,35 +67,6 @@ class ConsumablePresenter extends Presenter
|
|||||||
'searchable' => true,
|
'searchable' => true,
|
||||||
'sortable' => true,
|
'sortable' => true,
|
||||||
'title' => trans('general.model_no'),
|
'title' => trans('general.model_no'),
|
||||||
], [
|
|
||||||
'field' => 'item_no',
|
|
||||||
'searchable' => true,
|
|
||||||
'sortable' => true,
|
|
||||||
'title' => trans('admin/consumables/general.item_no'),
|
|
||||||
], [
|
|
||||||
'field' => 'qty',
|
|
||||||
'searchable' => false,
|
|
||||||
'sortable' => true,
|
|
||||||
'title' => trans('admin/components/general.total'),
|
|
||||||
'visible' => true,
|
|
||||||
'class' => 'text-right text-padding-number-cell',
|
|
||||||
'footerFormatter' => 'qtySumFormatter',
|
|
||||||
], [
|
|
||||||
'field' => 'remaining',
|
|
||||||
'searchable' => false,
|
|
||||||
'sortable' => true,
|
|
||||||
'title' => trans('admin/components/general.remaining'),
|
|
||||||
'visible' => true,
|
|
||||||
'class' => 'text-right text-padding-number-cell',
|
|
||||||
'footerFormatter' => 'qtySumFormatter',
|
|
||||||
], [
|
|
||||||
'field' => 'min_amt',
|
|
||||||
'searchable' => false,
|
|
||||||
'sortable' => true,
|
|
||||||
'title' => trans('general.min_amt'),
|
|
||||||
'visible' => true,
|
|
||||||
'formatter' => 'minAmtFormatter',
|
|
||||||
'class' => 'text-right text-padding-number-cell',
|
|
||||||
], [
|
], [
|
||||||
'field' => 'location',
|
'field' => 'location',
|
||||||
'searchable' => true,
|
'searchable' => true,
|
||||||
@@ -103,6 +74,12 @@ class ConsumablePresenter extends Presenter
|
|||||||
'title' => trans('general.location'),
|
'title' => trans('general.location'),
|
||||||
'formatter' => 'locationsLinkObjFormatter',
|
'formatter' => 'locationsLinkObjFormatter',
|
||||||
], [
|
], [
|
||||||
|
'field' => 'item_no',
|
||||||
|
'searchable' => true,
|
||||||
|
'sortable' => true,
|
||||||
|
'title' => trans('admin/consumables/general.item_no'),
|
||||||
|
], [
|
||||||
|
|
||||||
'field' => 'manufacturer',
|
'field' => 'manufacturer',
|
||||||
'searchable' => true,
|
'searchable' => true,
|
||||||
'sortable' => true,
|
'sortable' => true,
|
||||||
@@ -122,12 +99,42 @@ class ConsumablePresenter extends Presenter
|
|||||||
'title' => trans('general.purchase_date'),
|
'title' => trans('general.purchase_date'),
|
||||||
'visible' => true,
|
'visible' => true,
|
||||||
'formatter' => 'dateDisplayFormatter',
|
'formatter' => 'dateDisplayFormatter',
|
||||||
|
], [
|
||||||
|
'field' => 'min_amt',
|
||||||
|
'searchable' => false,
|
||||||
|
'sortable' => true,
|
||||||
|
'title' => trans('general.min_amt'),
|
||||||
|
'visible' => true,
|
||||||
|
'formatter' => 'minAmtFormatter',
|
||||||
|
'class' => 'text-right text-padding-number-cell',
|
||||||
|
], [
|
||||||
|
'field' => 'qty',
|
||||||
|
'searchable' => false,
|
||||||
|
'sortable' => true,
|
||||||
|
'title' => trans('admin/components/general.total'),
|
||||||
|
'visible' => true,
|
||||||
|
'class' => 'text-right text-padding-number-cell',
|
||||||
|
'footerFormatter' => 'qtySumFormatter',
|
||||||
|
], [
|
||||||
|
'field' => 'remaining',
|
||||||
|
'searchable' => false,
|
||||||
|
'sortable' => true,
|
||||||
|
'title' => trans('admin/components/general.remaining'),
|
||||||
|
'visible' => true,
|
||||||
|
'class' => 'text-right text-padding-number-cell',
|
||||||
|
'footerFormatter' => 'qtySumFormatter',
|
||||||
], [
|
], [
|
||||||
'field' => 'purchase_cost',
|
'field' => 'purchase_cost',
|
||||||
'searchable' => true,
|
'searchable' => true,
|
||||||
'sortable' => true,
|
'sortable' => true,
|
||||||
'title' => trans('general.purchase_cost'),
|
'title' => trans('general.unit_cost'),
|
||||||
'visible' => true,
|
'visible' => true,
|
||||||
|
'class' => 'text-right text-padding-number-cell',
|
||||||
|
], [
|
||||||
|
'field' => 'total_cost',
|
||||||
|
'searchable' => true,
|
||||||
|
'sortable' => true,
|
||||||
|
'title' => trans('general.total_cost'),
|
||||||
'footerFormatter' => 'sumFormatterQuantity',
|
'footerFormatter' => 'sumFormatterQuantity',
|
||||||
'class' => 'text-right text-padding-number-cell',
|
'class' => 'text-right text-padding-number-cell',
|
||||||
], [
|
], [
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ class LicensePresenter extends Presenter
|
|||||||
'switchable' => false,
|
'switchable' => false,
|
||||||
'title' => trans('general.checkin').'/'.trans('general.checkout'),
|
'title' => trans('general.checkin').'/'.trans('general.checkout'),
|
||||||
'visible' => true,
|
'visible' => true,
|
||||||
'formatter' => 'licensesInOutFormatter',
|
'formatter' => 'licenseInOutFormatter',
|
||||||
'printIgnore' => true,
|
'printIgnore' => true,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user