Compare commits
159 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b383cd9493 | |||
| 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 | |||
| 039564e74c | |||
| e164595a0f | |||
| d29e09a3ff | |||
| 4298aad008 | |||
| 823c67400d | |||
| 3160d1064d | |||
| 918426a2fa | |||
| c076b37c9b | |||
| 7c58bfa282 | |||
| 0caaba156d | |||
| c22575812d | |||
| 0ede4da816 | |||
| 98e23ff92e | |||
| c7bdad649a | |||
| 18c2508d2f | |||
| 4dcfd8b353 | |||
| 726116574d | |||
| 27f02014ca | |||
| f80f1acaa7 | |||
| 39d5ffeceb | |||
| 48ba7eed3e | |||
| 9caa240fdb | |||
| 3ffb73a516 | |||
| cc1132be87 | |||
| 1c31f126ef | |||
| d8eaf2676f | |||
| 3101212c49 | |||
| 3f0ac103a1 | |||
| 59bd6ca360 | |||
| 22fe9a786e | |||
| d2ee8de9ac | |||
| 03d3fb6a5f |
+2
-1
@@ -3206,7 +3206,8 @@
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/3755203?v=4",
|
||||
"profile": "https://github.com/swift2512",
|
||||
"contributions": [
|
||||
"bug"
|
||||
"bug",
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
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: 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
|
||||
@@ -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
|
||||
@@ -11,7 +11,7 @@ jobs:
|
||||
issues: write
|
||||
# pull-requests: write
|
||||
steps:
|
||||
- uses: actions/stale@v9
|
||||
- uses: actions/stale@v10
|
||||
with:
|
||||
debug-only: true
|
||||
ascending: true
|
||||
|
||||
+1
-1
@@ -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/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/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/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") |
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Mail\ExpiringAssetsMail;
|
||||
use App\Mail\ExpiringLicenseMail;
|
||||
use App\Models\Asset;
|
||||
@@ -52,11 +53,16 @@ class SendExpirationAlerts extends Command
|
||||
->filter(fn($item) => !empty($item))
|
||||
->all();
|
||||
// Expiring Assets
|
||||
$assets = Asset::getExpiringWarrantee($alert_interval);
|
||||
$assets = Asset::getExpiringWarrantyOrEol($alert_interval);
|
||||
|
||||
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));
|
||||
|
||||
$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
|
||||
@@ -64,7 +70,15 @@ class SendExpirationAlerts extends Command
|
||||
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));
|
||||
|
||||
$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])
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
if ($settings->alert_email == '') {
|
||||
$this->error('Could not send email. No alert email configured in settings');
|
||||
|
||||
@@ -435,6 +435,34 @@ class Helper
|
||||
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.
|
||||
*
|
||||
|
||||
@@ -8,8 +8,6 @@ use App\Events\ItemAccepted;
|
||||
use App\Events\ItemDeclined;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Mail\CheckoutAcceptanceResponseMail;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Asset;
|
||||
use App\Models\CheckoutAcceptance;
|
||||
use App\Models\Company;
|
||||
use App\Models\Contracts\Acceptable;
|
||||
@@ -25,16 +23,16 @@ use App\Notifications\AcceptanceAssetAcceptedToUserNotification;
|
||||
use App\Notifications\AcceptanceAssetDeclinedNotification;
|
||||
use Exception;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Http\Controllers\SettingsController;
|
||||
use Barryvdh\DomPDF\Facade\Pdf;
|
||||
use Carbon\Carbon;
|
||||
use \Illuminate\Contracts\View\View;
|
||||
use \Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use TCPDF;
|
||||
use App\Helpers\Helper;
|
||||
|
||||
class AcceptanceController extends Controller
|
||||
{
|
||||
@@ -107,12 +105,18 @@ class AcceptanceController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the signature and save it
|
||||
* Check for the signature directory
|
||||
*/
|
||||
if (! Storage::exists('private_uploads/signatures')) {
|
||||
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);
|
||||
@@ -123,19 +127,7 @@ class AcceptanceController extends Controller
|
||||
|
||||
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') {
|
||||
|
||||
// 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')) {
|
||||
@@ -152,56 +144,8 @@ class AcceptanceController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$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,
|
||||
@@ -225,21 +169,84 @@ class AcceptanceController extends Controller
|
||||
'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,
|
||||
'check_out_date' => Carbon::parse($acceptance->created_at)->format('Y-m-d H:i:s'),
|
||||
'accepted_date' => Carbon::parse($acceptance->accepted_at)->format('Y-m-d H:i:s'),
|
||||
'assigned_to' => $assigned_user->display_name,
|
||||
'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,
|
||||
'qty' => $acceptance->qty ?? 1,
|
||||
];
|
||||
|
||||
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());
|
||||
// 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');
|
||||
$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->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));
|
||||
$pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));
|
||||
|
||||
$pdf->AddPage();
|
||||
$pdf->writeHTML('<img src="'.$path_logo.'" height="30">', true, 0, true, 0, '');
|
||||
|
||||
if ($data['item_serial']) {
|
||||
$pdf->writeHTML("<strong>" . trans('general.asset_tag') . '</strong>: ' . $data['item_tag'], true, 0, true, 0, '');
|
||||
}
|
||||
$pdf->writeHTML("<strong>".trans('general.asset_model').'</strong>: '.$data['item_model'], true, 0, true, 0, '');
|
||||
if ($data['item_serial']) {
|
||||
$pdf->writeHTML("<strong>".trans('admin/hardware/form.serial').'</strong>: '.$data['item_serial'], true, 0, true, 0, '');
|
||||
}
|
||||
$pdf->writeHTML("<strong>".trans('general.assigned_date').'</strong>: '.$data['check_out_date'], true, 0, true, 0, '');
|
||||
$pdf->writeHTML("<strong>".trans('general.assignee').'</strong>: '.$data['assigned_to'], true, 0, true, 0, '');
|
||||
$pdf->Ln();
|
||||
|
||||
// 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/", $item->getEula());
|
||||
|
||||
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->writeHTML('<br><br>', true, 0, true, 0, '');
|
||||
|
||||
if ($data['note'] != null) {
|
||||
Helper::isCjk($data['note']) ? $pdf->SetFont('cid0cs', '', 9) : $pdf->SetFont('dejavusans', '', 8, '', true);
|
||||
$pdf->writeHTML("<strong>".trans('general.notes') . '</strong>: ' . $data['note'], true, 0, true, 0, '');
|
||||
$pdf->Ln();
|
||||
}
|
||||
|
||||
if ($data['signature'] != null) {
|
||||
|
||||
$pdf->writeHTML('<img src="'.$data['signature'].'" style="max-width: 600px;">', true, 0, true, 0, '');
|
||||
$pdf->writeHTML('<hr>', true, 0, true, 0, '');
|
||||
}
|
||||
|
||||
$pdf->writeHTML("<strong>".trans('general.accepted_date').'</strong>: '.$data['accepted_date'], true, 0, true, 0, '');
|
||||
|
||||
|
||||
$pdf_content = $pdf->Output($pdf_filename, 'S');
|
||||
|
||||
Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf_content);
|
||||
|
||||
|
||||
$acceptance->accept($sig_filename, $item->getEula(), $pdf_filename, $request->input('note'));
|
||||
|
||||
@@ -248,9 +255,8 @@ class AcceptanceController extends Controller
|
||||
|
||||
// Add the attachment for the signing user into the $data array
|
||||
$data['file'] = $pdf_filename;
|
||||
$locale = $assigned_user->locale;
|
||||
try {
|
||||
$assigned_user->notify((new AcceptanceAssetAcceptedToUserNotification($data))->locale($locale));
|
||||
$assigned_user->notify((new AcceptanceAssetAcceptedToUserNotification($data))->locale($assigned_user->locale));
|
||||
} catch (\Exception $e) {
|
||||
Log::warning($e);
|
||||
}
|
||||
@@ -264,23 +270,12 @@ class AcceptanceController extends Controller
|
||||
|
||||
$return_msg = trans('admin/users/message.accepted');
|
||||
|
||||
// Item was not accepted
|
||||
} else {
|
||||
|
||||
/**
|
||||
* 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') {
|
||||
|
||||
// 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
|
||||
// The item was declined, 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');
|
||||
@@ -297,39 +292,11 @@ class AcceptanceController extends Controller
|
||||
|
||||
// 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;
|
||||
}
|
||||
$assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName;
|
||||
|
||||
$data = [
|
||||
'item_tag' => $item->asset_tag,
|
||||
'item_model' => $display_model,
|
||||
'item_model' => $item->model ? $item->model->name : $item->display_name,
|
||||
'item_serial' => $item->serial,
|
||||
'item_status' => $item->assetstatus?->name,
|
||||
'note' => $request->input('note'),
|
||||
@@ -338,15 +305,14 @@ class AcceptanceController extends Controller
|
||||
'assigned_to' => $assigned_to,
|
||||
'company_name' => $branding_settings->site_name,
|
||||
'date_settings' => $branding_settings->date_display_format,
|
||||
'qty' => $acceptance->qty ?? 1,
|
||||
];
|
||||
|
||||
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());
|
||||
|
||||
for ($i = 0; $i < ($acceptance->qty ?? 1); $i++) {
|
||||
$acceptance->decline($sig_filename, $request->input('note'));
|
||||
}
|
||||
|
||||
$acceptance->decline($sig_filename, $request->input('note'));
|
||||
$acceptance->notify(new AcceptanceAssetDeclinedNotification($data));
|
||||
Log::debug('New event acceptance.');
|
||||
event(new CheckoutDeclined($acceptance));
|
||||
|
||||
@@ -1290,9 +1290,19 @@ class AssetsController extends Controller
|
||||
|
||||
public function assignedAssets(Request $request, Asset $asset) : JsonResponse | array
|
||||
{
|
||||
$this->authorize('view', Asset::class);
|
||||
$this->authorize('view', $asset);
|
||||
|
||||
return [];
|
||||
// to do
|
||||
$query = Asset::where([
|
||||
'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
|
||||
|
||||
@@ -38,6 +38,8 @@ class CategoriesController extends Controller
|
||||
'consumables_count',
|
||||
'components_count',
|
||||
'licenses_count',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
'image',
|
||||
'notes',
|
||||
];
|
||||
|
||||
@@ -26,6 +26,12 @@ class LicensesController extends Controller
|
||||
|
||||
$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')) {
|
||||
$licenses->where('licenses.company_id', '=', $request->input('company_id'));
|
||||
}
|
||||
@@ -94,6 +100,8 @@ class LicensesController extends Controller
|
||||
$licenses->onlyTrashed();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 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');
|
||||
$limit = app('api_limit_value');
|
||||
|
||||
@@ -37,10 +37,14 @@ class LocationsController extends Controller
|
||||
'address',
|
||||
'address2',
|
||||
'assets_count',
|
||||
'assets_count',
|
||||
'assigned_assets_count',
|
||||
'rtd_assets_count',
|
||||
'accessories_count',
|
||||
'assigned_accessories_count',
|
||||
'assigned_assets_count',
|
||||
'assigned_assets_count',
|
||||
'components_count',
|
||||
'consumables_count',
|
||||
'users_count',
|
||||
'children_count',
|
||||
'city',
|
||||
'country',
|
||||
'created_at',
|
||||
@@ -54,7 +58,6 @@ class LocationsController extends Controller
|
||||
'rtd_assets_count',
|
||||
'state',
|
||||
'updated_at',
|
||||
'users_count',
|
||||
'zip',
|
||||
'notes',
|
||||
];
|
||||
@@ -79,8 +82,9 @@ class LocationsController extends Controller
|
||||
'locations.currency',
|
||||
'locations.company_id',
|
||||
'locations.notes',
|
||||
'locations.created_by',
|
||||
'locations.deleted_at',
|
||||
])
|
||||
->withCount('assignedAssets as assigned_assets_count')
|
||||
->withCount('assignedAssets as assigned_assets_count')
|
||||
->withCount('assets as assets_count')
|
||||
->withCount('assignedAccessories as assigned_accessories_count')
|
||||
@@ -88,6 +92,8 @@ class LocationsController extends Controller
|
||||
->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')
|
||||
->with('adminuser');
|
||||
|
||||
// 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'));
|
||||
}
|
||||
|
||||
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
|
||||
$offset = ($request->input('offset') > $locations->count()) ? $locations->count() : app('api_offset_value');
|
||||
$limit = app('api_limit_value');
|
||||
@@ -224,8 +238,13 @@ class LocationsController extends Controller
|
||||
])
|
||||
->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')
|
||||
->findOrFail($id);
|
||||
|
||||
return (new LocationsTransformer)->transformLocation($location);
|
||||
@@ -320,11 +339,15 @@ class LocationsController extends Controller
|
||||
{
|
||||
$this->authorize('delete', Location::class);
|
||||
$location = Location::withCount('assignedAssets as assigned_assets_count')
|
||||
->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('accessories as accessories_count')
|
||||
->withCount('consumables as consumables_count')
|
||||
->withCount('components as components_count')
|
||||
->findOrFail($id);
|
||||
|
||||
if (! $location->isDeletable()) {
|
||||
|
||||
@@ -102,13 +102,15 @@ class ComponentCheckoutController extends Controller
|
||||
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
|
||||
$component->asset_id = $request->input('asset_id');
|
||||
$component->assets()->attach($component->id, [
|
||||
'component_id' => $component->id,
|
||||
'created_by' => auth()->user()->id,
|
||||
'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'),
|
||||
'note' => $request->input('note'),
|
||||
]);
|
||||
|
||||
@@ -25,7 +25,7 @@ class LicenseCheckoutController extends Controller
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.0]
|
||||
* @param $id
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
* @return \Illuminate\Contracts\View\View |\Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function create(License $license)
|
||||
@@ -39,6 +39,11 @@ class LicenseCheckoutController extends Controller
|
||||
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']);
|
||||
@@ -70,8 +75,19 @@ class LicenseCheckoutController extends Controller
|
||||
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.not_found'));
|
||||
}
|
||||
|
||||
|
||||
$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->created_by = auth()->id();
|
||||
$licenseSeat->notes = $request->input('notes');
|
||||
@@ -114,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')));
|
||||
}
|
||||
|
||||
|
||||
if (! $licenseSeat->license->is($license)) {
|
||||
throw new \Illuminate\Http\Exceptions\HttpResponseException(redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.mismatch')));
|
||||
}
|
||||
|
||||
@@ -256,6 +256,9 @@ class LicensesController extends Controller
|
||||
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);
|
||||
return view('licenses.view', compact('license'))
|
||||
|
||||
@@ -189,30 +189,36 @@ class LocationsController extends Controller
|
||||
{
|
||||
$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'));
|
||||
}
|
||||
|
||||
if ($location->users()->count() > 0) {
|
||||
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->isDeletable()) {
|
||||
|
||||
if ($location->image) {
|
||||
try {
|
||||
Storage::disk('public')->delete('locations/'.$location->image);
|
||||
} catch (\Exception $e) {
|
||||
Log::error($e);
|
||||
if ($location->image) {
|
||||
try {
|
||||
Storage::disk('public')->delete('locations/'.$location->image);
|
||||
} catch (\Exception $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);
|
||||
|
||||
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')
|
||||
->with('assets', $assets)
|
||||
->with('users',$users)
|
||||
->with('assigned', false)
|
||||
->with('assets', $location->assets)
|
||||
->with('assignedAssets', $location->assignedAssets)
|
||||
->with('accessories', $location->accessories)
|
||||
->with('assignedAccessories', $location->assignedAccessories)
|
||||
->with('users',$location->users)
|
||||
->with('location', $location)
|
||||
->with('parent', $parent)
|
||||
->with('manager', $manager)
|
||||
->with('company', $company);
|
||||
->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'));
|
||||
}
|
||||
|
||||
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.
|
||||
@@ -321,33 +345,12 @@ class LocationsController extends Controller
|
||||
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('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
|
||||
@@ -366,8 +369,12 @@ class LocationsController extends Controller
|
||||
$locations = Location::whereIn('id', $locations_raw_array)
|
||||
->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('consumables as consumables_count')
|
||||
->withCount('components as components_count')
|
||||
->withCount('users as users_count')->get();
|
||||
|
||||
$valid_count = 0;
|
||||
@@ -400,9 +407,13 @@ class LocationsController extends Controller
|
||||
$locations = Location::whereIn('id', $locations_raw_array)
|
||||
->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')->get();
|
||||
->withCount('users as users_count')
|
||||
->withCount('consumables as consumables_count')
|
||||
->withCount('components as components_count')->get();
|
||||
|
||||
$success_count = 0;
|
||||
$error_count = 0;
|
||||
|
||||
@@ -274,22 +274,18 @@ class ReportsController extends Controller
|
||||
$target_name = '';
|
||||
|
||||
if ($actionlog->target) {
|
||||
if ($actionlog->targetType() == 'user') {
|
||||
$target_name = $actionlog->target->display_name;
|
||||
} else {
|
||||
$target_name = $actionlog->target->getDisplayNameAttribute();
|
||||
}
|
||||
$target_name = $actionlog->target->display_name;
|
||||
}
|
||||
|
||||
if($actionlog->item){
|
||||
$item_name = e($actionlog->item->getDisplayNameAttribute());
|
||||
if ($actionlog->item){
|
||||
$item_name = e($actionlog->item->display_name);
|
||||
} else {
|
||||
$item_name = '';
|
||||
}
|
||||
|
||||
$row = [
|
||||
$actionlog->created_at,
|
||||
($actionlog->adminuser) ? e($actionlog->adminuser->display_name) : '',
|
||||
($actionlog->adminuser) ? $actionlog->adminuser->display_name : '',
|
||||
$actionlog->present()->actionType(),
|
||||
e($actionlog->itemType()),
|
||||
($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,
|
||||
$target_name,
|
||||
($actionlog->note) ? e($actionlog->note) : '',
|
||||
$actionlog->log_meta,
|
||||
$actionlog->remote_ip,
|
||||
$actionlog->user_agent,
|
||||
$actionlog->action_source,
|
||||
$actionlog->log_meta,
|
||||
];
|
||||
fputcsv($handle, $row);
|
||||
}
|
||||
|
||||
@@ -34,10 +34,7 @@ class AssetCountForSidebar
|
||||
}
|
||||
|
||||
try {
|
||||
$total_assets = Asset::count();
|
||||
if ($settings->show_archived_in_list != '1') {
|
||||
$total_assets -= Asset::Archived()->count();
|
||||
}
|
||||
$total_assets = Asset::AssetsForShow()->count();
|
||||
view()->share('total_assets', $total_assets);
|
||||
} catch (\Exception $e) {
|
||||
Log::debug($e);
|
||||
|
||||
@@ -155,7 +155,7 @@ class ActionlogsTransformer
|
||||
'id' => (int) $actionlog->item->id,
|
||||
'name' => e($actionlog->item->display_name) ?? null,
|
||||
'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,
|
||||
'location' => ($actionlog->location) ? [
|
||||
'id' => (int) $actionlog->location->id,
|
||||
@@ -168,7 +168,7 @@ class ActionlogsTransformer
|
||||
'action_type' => $actionlog->present()->actionType(),
|
||||
'admin' => ($actionlog->adminuser) ? [
|
||||
'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),
|
||||
'last_name'=> e($actionlog->adminuser->last_name)
|
||||
] : null,
|
||||
@@ -180,7 +180,7 @@ class ActionlogsTransformer
|
||||
] : null,
|
||||
'target' => ($actionlog->target) ? [
|
||||
'id' => (int) $actionlog->target->id,
|
||||
'name' => ($actionlog->target->display_name) ?? null,
|
||||
'name' => e($actionlog->target->display_name) ?? null,
|
||||
'type' => e($actionlog->targetType()),
|
||||
] : null,
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ class LicenseSeatsTransformer
|
||||
'reassignable' => (bool) $seat->license->reassignable,
|
||||
'notes' => e($seat->notes),
|
||||
'user_can_checkout' => (($seat->assigned_to == '') && ($seat->asset_id == '')),
|
||||
'disabled' => $seat->unreassignable_seat,
|
||||
'disabled' => $seat->unreassignable_seat || $seat->license->isInactive(),
|
||||
];
|
||||
|
||||
$permissions_array['available_actions'] = [
|
||||
|
||||
@@ -31,11 +31,11 @@ class LicensesTransformer
|
||||
'purchase_order' => ($license->purchase_order) ? e($license->purchase_order) : null,
|
||||
'purchase_date' => Helper::getFormattedDateObject($license->purchase_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,
|
||||
'purchase_cost' => Helper::formatCurrencyOutput($license->purchase_cost),
|
||||
'purchase_cost_numeric' => $license->purchase_cost,
|
||||
'notes' => Helper::parseEscapedMarkedownInline($license->notes),
|
||||
'expiration_date' => Helper::getFormattedDateObject($license->expiration_date, 'date'),
|
||||
'seats' => (int) $license->seats,
|
||||
'free_seats_count' => (int) $license->free_seats_count - License::unReassignableCount($license),
|
||||
'remaining' => (int) $license->free_seats_count,
|
||||
@@ -54,7 +54,7 @@ class LicensesTransformer
|
||||
'updated_at' => Helper::getFormattedDateObject($license->updated_at, 'datetime'),
|
||||
'deleted_at' => Helper::getFormattedDateObject($license->deleted_at, 'datetime'),
|
||||
'user_can_checkout' => (bool) ($license->free_seats_count > 0),
|
||||
|
||||
'disabled' => $license->isInactive(),
|
||||
];
|
||||
|
||||
$permissions_array['available_actions'] = [
|
||||
|
||||
@@ -53,6 +53,9 @@ class LocationsTransformer
|
||||
'assets_count' => (int) $location->assets_count,
|
||||
'rtd_assets_count' => (int) $location->rtd_assets_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,
|
||||
'ldap_ou' => ($location->ldap_ou) ? e($location->ldap_ou) : null,
|
||||
'notes' => Helper::parseEscapedMarkedownInline($location->notes),
|
||||
@@ -76,12 +79,13 @@ class LocationsTransformer
|
||||
];
|
||||
|
||||
$permissions_array['available_actions'] = [
|
||||
'update' => Gate::allows('update', Location::class) ? true : false,
|
||||
'update' => (Gate::allows('update', Location::class) && ($location->deleted_at == '')),
|
||||
'delete' => $location->isDeletable(),
|
||||
'bulk_selectable' => [
|
||||
'delete' => $location->isDeletable()
|
||||
],
|
||||
'clone' => (Gate::allows('create', Location::class) && ($location->deleted_at == '')),
|
||||
'restore' => (Gate::allows('create', Location::class) && ($location->deleted_at != '')),
|
||||
];
|
||||
|
||||
$array += $permissions_array;
|
||||
|
||||
@@ -96,8 +96,8 @@ class CheckoutableListener
|
||||
|
||||
if (!empty($to)) {
|
||||
try {
|
||||
Mail::to(array_flatten($to))->send($mailable->locale($notifiable->locale));
|
||||
Mail::to(array_flatten($cc))->send($mailable->locale(Setting::getSettings()->locale));
|
||||
$toMail = (clone $mailable)->locale($notifiable->locale);
|
||||
Mail::to(array_flatten($to))->send($toMail);
|
||||
Log::info('Checkout Mail sent to checkout target');
|
||||
} catch (ClientException $e) {
|
||||
Log::debug("Exception caught during checkout email: " . $e->getMessage());
|
||||
@@ -105,6 +105,16 @@ class CheckoutableListener
|
||||
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) {
|
||||
@@ -179,16 +189,26 @@ class CheckoutableListener
|
||||
|
||||
[$to, $cc] = $this->generateEmailRecipients($shouldSendEmailToUser, $shouldSendEmailToAlertAddress, $notifiable);
|
||||
|
||||
try {
|
||||
if (!empty($to)) {
|
||||
Mail::to(array_flatten($to))->send($mailable->locale($notifiable->locale));
|
||||
Mail::to(array_flatten($cc))->send($mailable->locale(Setting::getSettings()->locale));
|
||||
Log::info('Checkin Mail sent to CC addresses');
|
||||
if (!empty($to)) {
|
||||
try {
|
||||
$toMail = (clone $mailable)->locale($notifiable->locale);
|
||||
Mail::to(array_flatten($to))->send($toMail);
|
||||
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->assignedTo()->associate($event->checkedOutTo);
|
||||
|
||||
$acceptance->qty = 1;
|
||||
|
||||
if (isset($event->checkoutable->checkout_qty)) {
|
||||
$acceptance->qty = $event->checkoutable->checkout_qty;
|
||||
}
|
||||
|
||||
$category = $this->getCategoryFromCheckoutable($event->checkoutable);
|
||||
|
||||
if ($category?->alert_on_response) {
|
||||
|
||||
@@ -43,7 +43,7 @@ class CheckoutAccessoryMail extends Mailable
|
||||
|
||||
return new Envelope(
|
||||
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
|
||||
{
|
||||
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()) {
|
||||
return trans('mail.new_item_checked_with_acceptance');
|
||||
return trans_choice('mail.new_item_checked_with_acceptance', $this->checkout_qty);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -138,14 +138,15 @@ class CheckoutAssetMail extends Mailable
|
||||
private function introductionLine(): string
|
||||
{
|
||||
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()) {
|
||||
return trans('mail.new_item_checked_with_acceptance');
|
||||
return trans_choice('mail.new_item_checked_with_acceptance', 1);
|
||||
}
|
||||
|
||||
if ($this->firstTimeSending && !$this->requiresAcceptance()) {
|
||||
return trans('mail.new_item_checked');
|
||||
return trans_choice('mail.new_item_checked', 1);
|
||||
}
|
||||
|
||||
if (!$this->firstTimeSending && $this->requiresAcceptance()) {
|
||||
|
||||
@@ -26,7 +26,7 @@ class CheckoutComponentMail extends Mailable
|
||||
$this->note = $note;
|
||||
$this->target = $checkedOutTo;
|
||||
$this->acceptance = $acceptance;
|
||||
$this->qty = $component->assets->first()?->pivot?->assigned_qty;
|
||||
$this->qty = $component->checkout_qty;
|
||||
|
||||
$this->settings = Setting::getSettings();
|
||||
}
|
||||
|
||||
@@ -309,27 +309,6 @@ class Accessory extends SnipeModel
|
||||
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
|
||||
*
|
||||
|
||||
+43
-40
@@ -161,7 +161,6 @@ class Asset extends Depreciable
|
||||
'eol_explicit',
|
||||
'last_audit_date',
|
||||
'next_audit_date',
|
||||
'asset_eol_date',
|
||||
'last_checkin',
|
||||
'last_checkout',
|
||||
];
|
||||
@@ -824,21 +823,26 @@ class Asset extends Depreciable
|
||||
* @since [v2.0]
|
||||
* @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') // 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')
|
||||
|
||||
return self::where('archived', '=', '0')
|
||||
->NotArchived()
|
||||
->whereRaw(
|
||||
'DATE_ADD(`purchase_date`, INTERVAL `warranty_months` MONTH) <= DATE_ADD(NOW(), INTERVAL '
|
||||
. $days
|
||||
. ' DAY) AND DATE_ADD(`purchase_date`, INTERVAL `warranty_months` MONTH) > NOW()'
|
||||
)
|
||||
->orderByRaw('DATE_ADD(`purchase_date`,INTERVAL `warranty_months` MONTH)')
|
||||
->whereNull('deleted_at')
|
||||
->where(function ($query) use ($days) {
|
||||
// Check for manual asset EOL first
|
||||
$query->where(function ($query) use ($days) {
|
||||
$query->whereNotNull('asset_eol_date')
|
||||
->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();
|
||||
}
|
||||
|
||||
@@ -1019,31 +1023,6 @@ class Asset extends Depreciable
|
||||
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()
|
||||
{
|
||||
$cost = 0;
|
||||
@@ -1893,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
|
||||
@@ -1917,7 +1920,7 @@ class Asset extends Depreciable
|
||||
*/
|
||||
|
||||
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 . '%');
|
||||
}
|
||||
|
||||
@@ -148,4 +148,9 @@ class CheckoutAcceptance extends Model
|
||||
{
|
||||
return $query->whereNull('accepted_at')->whereNull('declined_at');
|
||||
}
|
||||
|
||||
public function scopeDeclined(Builder $query)
|
||||
{
|
||||
return $query->whereNull('accepted_at')->whereNotNull('declined_at');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,24 +217,6 @@ class Component extends SnipeModel
|
||||
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
|
||||
|
||||
@@ -285,25 +285,6 @@ class Consumable extends SnipeModel
|
||||
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
|
||||
*
|
||||
|
||||
@@ -229,7 +229,7 @@ class DefaultLabel extends RectangleSheet
|
||||
static::writeText(
|
||||
$pdf, $record->get('title'),
|
||||
$textX1, 0,
|
||||
'freesans', 'b', $this->textSize, 'L',
|
||||
Helper::isCjk($record->get('title')) ? 'cid0cs' : 'freesans', 'b', $this->textSize, 'L',
|
||||
$textW, $this->textSize,
|
||||
true, 0
|
||||
);
|
||||
@@ -246,11 +246,12 @@ class DefaultLabel extends RectangleSheet
|
||||
static::writeText(
|
||||
$pdf, (($field['label']) ? $field['label'].' ' : '') . $field['value'],
|
||||
$textX1, $textY,
|
||||
'freesans', '', $this->textSize, 'L',
|
||||
Helper::isCjk($field['label']) ? 'cid0cs' : 'freesans', '', $this->textSize, 'L',
|
||||
$textW, $this->textSize,
|
||||
true, 0
|
||||
);
|
||||
|
||||
|
||||
$textY += $this->textSize + self::TEXT_MARGIN;
|
||||
$fieldsDone++;
|
||||
}
|
||||
|
||||
@@ -211,29 +211,36 @@ abstract class Label
|
||||
*/
|
||||
public final function writeText(TCPDF $pdf, $text, $x, $y, $font=null, $style=null, $size=null, $align='L', $width=null, $height=null, $squash=false, $border=0, $spacing=0)
|
||||
{
|
||||
|
||||
|
||||
$prevFamily = $pdf->getFontFamily();
|
||||
$prevStyle = $pdf->getFontStyle();
|
||||
$prevSizePt = $pdf->getFontSizePt();
|
||||
|
||||
|
||||
$text = !empty($text) ? $text : '';
|
||||
|
||||
$fontFamily = !empty($font) ? $font : $prevFamily;
|
||||
$fontStyle = !empty($style) ? $style : $prevStyle;
|
||||
if ($size) { $fontSizePt = Helper::convertUnit($size, $this->getUnit(), 'pt', true);
|
||||
} else { $fontSizePt = $prevSizePt;
|
||||
|
||||
|
||||
if ($size) {
|
||||
$fontSizePt = Helper::convertUnit($size, $this->getUnit(), 'pt', true);
|
||||
} else {
|
||||
$fontSizePt = $prevSizePt;
|
||||
}
|
||||
|
||||
$pdf->SetFontSpacing($spacing);
|
||||
|
||||
$parts = collect(explode('**', $text))
|
||||
->map(
|
||||
function ($part, $index) use ($pdf, $fontFamily, $fontStyle, $fontSizePt) {
|
||||
function ($part, $index) use ($pdf, $fontFamily, $fontStyle, $fontSizePt, $text) {
|
||||
$modStyle = ($index % 2 == 1) ? 'B' : $fontStyle;
|
||||
$pdf->setFont($fontFamily, $modStyle, $fontSizePt);
|
||||
return [
|
||||
'text' => $part,
|
||||
'text_width' => $pdf->GetStringWidth($part),
|
||||
'font_family' => $fontFamily,
|
||||
'font_family' => Helper::isCjk($text) ? 'cid0cs' : $fontFamily,
|
||||
'font_style' => $modStyle,
|
||||
'font_size' => $fontSizePt,
|
||||
];
|
||||
|
||||
+7
-5
@@ -78,6 +78,13 @@ class Ldap extends Model
|
||||
if (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);
|
||||
|
||||
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_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') {
|
||||
ldap_start_tls($connection);
|
||||
}
|
||||
|
||||
+95
-29
@@ -14,6 +14,7 @@ use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
|
||||
|
||||
class License extends Depreciable
|
||||
{
|
||||
use HasFactory;
|
||||
@@ -296,6 +297,38 @@ class License extends Depreciable
|
||||
}
|
||||
$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
|
||||
*
|
||||
@@ -375,27 +408,6 @@ class License extends Depreciable
|
||||
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
|
||||
@@ -596,7 +608,7 @@ class License extends Depreciable
|
||||
{
|
||||
$count = 0;
|
||||
if (!$license->reassignable) {
|
||||
$count = licenseSeat::query()->where('unreassignable_seat', '=', true)
|
||||
$count = LicenseSeat::query()->where('unreassignable_seat', '=', true)
|
||||
->where('license_id', '=', $license->id)
|
||||
->count();
|
||||
}
|
||||
@@ -695,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>
|
||||
* @since [v1.0]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
* @see \App\Console\Commands\SendExpiringLicenseNotifications
|
||||
*/
|
||||
public static function getExpiringLicenses($days = 60)
|
||||
{
|
||||
$days = (is_null($days)) ? 60 : $days;
|
||||
|
||||
return self::whereNotNull('expiration_date')
|
||||
->whereNull('deleted_at')
|
||||
->whereRaw('DATE_SUB(`expiration_date`,INTERVAL '.$days.' DAY) <= DATE(NOW()) ')
|
||||
->where('expiration_date', '>', date('Y-m-d'))
|
||||
return self::whereNull('deleted_at')
|
||||
|
||||
// The termination date is null or within range
|
||||
->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('termination_date', 'ASC')
|
||||
->get();
|
||||
}
|
||||
|
||||
public function scopeActiveLicenses($query)
|
||||
{
|
||||
|
||||
return $query->whereNull('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('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
|
||||
*
|
||||
|
||||
+12
-5
@@ -43,6 +43,7 @@ class Location extends SnipeModel
|
||||
'company_id' => 'integer',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Whether the model should inject its identifier to the unique
|
||||
* validation rules before attempting validation. If this property
|
||||
@@ -113,13 +114,19 @@ class Location extends SnipeModel
|
||||
{
|
||||
|
||||
return Gate::allows('delete', $this)
|
||||
&& ($this->assets_count == 0)
|
||||
&& ($this->assigned_assets_count == 0)
|
||||
&& ($this->children_count == 0)
|
||||
&& ($this->accessories_count == 0)
|
||||
&& ($this->users_count == 0);
|
||||
&& ($this->deleted_at == '')
|
||||
&& (($this->assets_count ?? $this->assets()->count()) === 0)
|
||||
&& (($this->assigned_assets_count ?? $this->assignedAssets()->count()) === 0)
|
||||
&& (($this->accessories_count ?? $this->accessories()->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
|
||||
*
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
namespace App\Models;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Request;
|
||||
|
||||
class SnipeModel extends Model
|
||||
{
|
||||
@@ -156,6 +158,20 @@ class SnipeModel extends Model
|
||||
$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
|
||||
{
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ class AcceptanceAssetAcceptedNotification extends Notification
|
||||
$this->company_name = $params['company_name'];
|
||||
$this->admin = $params['admin'] ?? null;
|
||||
$this->settings = Setting::getSettings();
|
||||
$this->qty = $params['qty'] ?? null;
|
||||
|
||||
}
|
||||
|
||||
@@ -72,6 +73,7 @@ class AcceptanceAssetAcceptedNotification extends Notification
|
||||
'accepted_date' => $this->accepted_date,
|
||||
'assigned_to' => $this->assigned_to,
|
||||
'company_name' => $this->company_name,
|
||||
'qty' => $this->qty,
|
||||
'intro_text' => trans('mail.acceptance_asset_accepted'),
|
||||
'admin' => $this->admin,
|
||||
])
|
||||
|
||||
@@ -29,7 +29,7 @@ class AcceptanceAssetAcceptedToUserNotification extends Notification
|
||||
$this->company_name = $params['company_name'];
|
||||
$this->settings = Setting::getSettings();
|
||||
$this->file = $params['file'] ?? null;
|
||||
|
||||
$this->qty = $params['qty'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,6 +66,7 @@ class AcceptanceAssetAcceptedToUserNotification extends Notification
|
||||
'accepted_date' => $this->accepted_date,
|
||||
'assigned_to' => $this->assigned_to,
|
||||
'company_name' => $this->company_name,
|
||||
'qty' => $this->qty,
|
||||
'intro_text' => trans('mail.acceptance_asset_accepted_to_user', ['site_name' => $this->company_name ?? $this->settings->site_name]),
|
||||
])
|
||||
->attach($pdf_path)
|
||||
|
||||
@@ -30,6 +30,7 @@ class AcceptanceAssetDeclinedNotification extends Notification
|
||||
$this->assigned_to = $params['assigned_to'];
|
||||
$this->company_name = $params['company_name'];
|
||||
$this->settings = Setting::getSettings();
|
||||
$this->qty = $params['qty'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,6 +70,7 @@ class AcceptanceAssetDeclinedNotification extends Notification
|
||||
'declined_date' => $this->declined_date,
|
||||
'assigned_to' => $this->assigned_to,
|
||||
'company_name' => $this->company_name,
|
||||
'qty' => $this->qty,
|
||||
'intro_text' => 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')
|
||||
->to($channel)
|
||||
->attachment(function ($attachment) {
|
||||
$item = $this->params['item'];
|
||||
$item = $this->params['item'] ?? null;
|
||||
$admin_user = $this->params['admin'];
|
||||
$fields = [
|
||||
'By' => '<'.$admin_user->present()->viewUrl().'|'.$admin_user->display_name.'>',
|
||||
|
||||
@@ -120,7 +120,7 @@ class AccessoryPresenter extends Presenter
|
||||
'field' => 'purchase_cost',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'title' => trans('general.purchase_cost'),
|
||||
'title' => trans('general.unit_cost'),
|
||||
'footerFormatter' => 'sumFormatterQuantity',
|
||||
'class' => 'text-right text-padding-number-cell',
|
||||
], [
|
||||
|
||||
@@ -126,7 +126,7 @@ class ComponentPresenter extends Presenter
|
||||
'field' => 'purchase_cost',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'title' => trans('general.purchase_cost'),
|
||||
'title' => trans('general.unit_cost'),
|
||||
'visible' => true,
|
||||
'footerFormatter' => 'sumFormatterQuantity',
|
||||
'class' => 'text-right',
|
||||
|
||||
@@ -126,7 +126,7 @@ class ConsumablePresenter extends Presenter
|
||||
'field' => 'purchase_cost',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'title' => trans('general.purchase_cost'),
|
||||
'title' => trans('general.unit_cost'),
|
||||
'visible' => true,
|
||||
'footerFormatter' => 'sumFormatterQuantity',
|
||||
'class' => 'text-right text-padding-number-cell',
|
||||
|
||||
@@ -202,7 +202,7 @@ class LicensePresenter extends Presenter
|
||||
'switchable' => false,
|
||||
'title' => trans('general.checkin').'/'.trans('general.checkout'),
|
||||
'visible' => true,
|
||||
'formatter' => 'licensesInOutFormatter',
|
||||
'formatter' => 'licenseInOutFormatter',
|
||||
'printIgnore' => true,
|
||||
];
|
||||
|
||||
|
||||
@@ -61,6 +61,15 @@ class LocationPresenter extends Presenter
|
||||
'title' => trans('admin/locations/table.parent'),
|
||||
'visible' => true,
|
||||
'formatter' => 'locationsLinkObjFormatter',
|
||||
], [
|
||||
'field' => 'users_count',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'title' => trans('general.people'),
|
||||
'titleTooltip' => trans('general.people'),
|
||||
'visible' => true,
|
||||
'class' => 'css-house-user',
|
||||
], [
|
||||
'field' => 'assets_count',
|
||||
'searchable' => false,
|
||||
@@ -98,7 +107,7 @@ class LocationPresenter extends Presenter
|
||||
'titleTooltip' => trans('general.accessories'),
|
||||
'visible' => true,
|
||||
'class' => 'css-accessory',
|
||||
], [
|
||||
],[
|
||||
'field' => 'assigned_accessories_count',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
@@ -108,14 +117,34 @@ class LocationPresenter extends Presenter
|
||||
'visible' => true,
|
||||
'class' => 'css-accessory-alt',
|
||||
], [
|
||||
'field' => 'users_count',
|
||||
'field' => 'components_count',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'title' => trans('general.people'),
|
||||
'titleTooltip' => trans('general.people'),
|
||||
'title' => trans('general.components'),
|
||||
'titleTooltip' => trans('general.components'),
|
||||
'visible' => true,
|
||||
'class' => 'css-house-user',
|
||||
'class' => 'css-component',
|
||||
],
|
||||
[
|
||||
'field' => 'consumables_count',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'title' => trans('general.consumables'),
|
||||
'titleTooltip' => trans('general.consumables'),
|
||||
'visible' => true,
|
||||
'class' => 'css-consumable',
|
||||
],
|
||||
[
|
||||
'field' => 'children_count',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'title' => trans('general.child_locations'),
|
||||
'titleTooltip' => trans('general.child_locations'),
|
||||
'visible' => true,
|
||||
'class' => 'css-child-locations',
|
||||
], [
|
||||
'field' => 'currency',
|
||||
'searchable' => true,
|
||||
|
||||
@@ -60,18 +60,14 @@ class UserPresenter extends Presenter
|
||||
'title' => trans('admin/users/table.name'),
|
||||
'visible' => true,
|
||||
'formatter' => 'usersLinkFormatter',
|
||||
],
|
||||
|
||||
[
|
||||
], [
|
||||
'field' => 'first_name',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'title' => trans('general.first_name'),
|
||||
'visible' => false,
|
||||
'formatter' => 'usersLinkFormatter',
|
||||
],
|
||||
|
||||
[
|
||||
], [
|
||||
'field' => 'last_name',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
@@ -85,7 +81,23 @@ class UserPresenter extends Presenter
|
||||
'sortable' => true,
|
||||
'switchable' => false,
|
||||
'title' => trans('admin/users/table.display_name'),
|
||||
'visible' => false,
|
||||
], [
|
||||
'field' => 'username',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => false,
|
||||
'title' => trans('admin/users/table.username'),
|
||||
'visible' => true,
|
||||
'formatter' => 'usernameRoleLinkFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'employee_num',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'title' => trans('general.employee_number'),
|
||||
'visible' => false,
|
||||
],
|
||||
[
|
||||
'field' => 'jobtitle',
|
||||
@@ -129,7 +141,7 @@ class UserPresenter extends Presenter
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'title' => trans('admin/users/table.phone'),
|
||||
'visible' => true,
|
||||
'visible' => false,
|
||||
'formatter' => 'phoneFormatter',
|
||||
],
|
||||
[
|
||||
@@ -190,24 +202,7 @@ class UserPresenter extends Presenter
|
||||
'title' => trans('general.zip'),
|
||||
'visible' => false,
|
||||
],
|
||||
[
|
||||
'field' => 'username',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => false,
|
||||
'title' => trans('admin/users/table.username'),
|
||||
'visible' => true,
|
||||
'formatter' => 'usernameRoleLinkFormatter',
|
||||
],
|
||||
|
||||
[
|
||||
'field' => 'employee_num',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'title' => trans('general.employee_number'),
|
||||
'visible' => false,
|
||||
],
|
||||
[
|
||||
'field' => 'locale',
|
||||
'searchable' => true,
|
||||
@@ -231,7 +226,7 @@ class UserPresenter extends Presenter
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'title' => trans('admin/users/general.department_manager'),
|
||||
'visible' => true,
|
||||
'visible' => false,
|
||||
'formatter' => 'usersLinkObjFormatter',
|
||||
],
|
||||
[
|
||||
@@ -248,7 +243,7 @@ class UserPresenter extends Presenter
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'title' => trans('admin/users/table.manager'),
|
||||
'visible' => true,
|
||||
'visible' => false,
|
||||
'formatter' => 'usersLinkObjFormatter',
|
||||
],
|
||||
[
|
||||
|
||||
@@ -349,10 +349,19 @@ class BreadcrumbsServiceProvider extends ServiceProvider
|
||||
/**
|
||||
* Licenses Breadcrumbs
|
||||
*/
|
||||
Breadcrumbs::for('licenses.index', fn (Trail $trail) =>
|
||||
$trail->parent('home', route('home'))
|
||||
->push(trans('general.licenses'), route('licenses.index'))
|
||||
);
|
||||
if ((request()->is('licenses*')) && (request()->status=='inactive')) {
|
||||
Breadcrumbs::for('licenses.index', fn (Trail $trail) =>
|
||||
$trail->parent('home', route('home'))
|
||||
->push(trans('general.licenses'), route('licenses.index'))
|
||||
->push(trans('general.show_inactive'), route('licenses.index'))
|
||||
);
|
||||
} else {
|
||||
Breadcrumbs::for('licenses.index', fn (Trail $trail) =>
|
||||
$trail->parent('home', route('home'))
|
||||
->push(trans('general.licenses'), route('licenses.index'))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Breadcrumbs::for('licenses.create', fn (Trail $trail) =>
|
||||
$trail->parent('licenses.index', route('licenses.index'))
|
||||
|
||||
+6
-2
@@ -74,6 +74,10 @@ class Label implements View
|
||||
[0 => $template->getWidth(), 1 => $template->getHeight(), 'Rotate' => $template->getRotation()]
|
||||
);
|
||||
|
||||
// Required for CJK languages, otherwise the embedded font can get too massive
|
||||
$pdf->SetFontSubsetting(true);
|
||||
|
||||
|
||||
// Reset parameters
|
||||
$pdf->SetPrintHeader(false);
|
||||
$pdf->SetPrintFooter(false);
|
||||
@@ -176,14 +180,14 @@ class Label implements View
|
||||
// For fields that have multiple options, we need to combine them
|
||||
// into a single field so all values are displayed.
|
||||
->reduce(function ($previous, $current) {
|
||||
// On the first iteration we simply return the item.
|
||||
// On the first iteration, we simply return the item.
|
||||
// If there is only one item to be processed for the row
|
||||
// then this effectively skips everything below this if block.
|
||||
if (is_null($previous)) {
|
||||
return $current;
|
||||
}
|
||||
|
||||
// At this point we are dealing with a row with multiple items being displayed.
|
||||
// At this point, we are dealing with a row with multiple items being displayed.
|
||||
// We need to combine the label and value of the current item with the previous item.
|
||||
|
||||
// The end result of this will be in this format:
|
||||
|
||||
+2
-1
@@ -32,11 +32,11 @@
|
||||
"arietimmerman/laravel-scim-server": "dev-laravel_11_compatibility",
|
||||
"bacon/bacon-qr-code": "^2.0",
|
||||
"barryvdh/laravel-debugbar": "^3.13",
|
||||
"barryvdh/laravel-dompdf": "^2.0",
|
||||
"doctrine/cache": "^1.10",
|
||||
"doctrine/dbal": "^3.1",
|
||||
"doctrine/instantiator": "^1.3",
|
||||
"eduardokum/laravel-mail-auto-embed": "^2.0",
|
||||
"elibyy/tcpdf-laravel": "^11.5",
|
||||
"enshrined/svg-sanitize": "^0.22.0",
|
||||
"erusev/parsedown": "^1.7",
|
||||
"fakerphp/faker": "^1.24",
|
||||
@@ -73,6 +73,7 @@
|
||||
"spatie/laravel-ignition": "^2.0",
|
||||
"tabuna/breadcrumbs": "^4.2",
|
||||
"tecnickcom/tc-lib-barcode": "^1.15",
|
||||
"tecnickcom/tc-lib-pdf-font": "^2.6",
|
||||
"tecnickcom/tcpdf": "^6.5",
|
||||
"unicodeveloper/laravel-password": "^1.0",
|
||||
"watson/validating": "^8.1"
|
||||
|
||||
Generated
+430
-392
File diff suppressed because it is too large
Load Diff
+3
-2
@@ -300,7 +300,6 @@ return [
|
||||
App\Providers\SnipeTranslationServiceProvider::class, //we REPLACE the default Laravel translator with our own
|
||||
Illuminate\Validation\ValidationServiceProvider::class,
|
||||
Illuminate\View\ViewServiceProvider::class,
|
||||
Barryvdh\DomPDF\ServiceProvider::class,
|
||||
|
||||
/*
|
||||
* Package Service Providers...
|
||||
@@ -315,6 +314,8 @@ return [
|
||||
Unicodeveloper\DumbPassword\DumbPasswordServiceProvider::class,
|
||||
Eduardokum\LaravelMailAutoEmbed\ServiceProvider::class,
|
||||
Laravel\Socialite\SocialiteServiceProvider::class,
|
||||
Elibyy\TCPDF\ServiceProvider::class,
|
||||
|
||||
|
||||
/*
|
||||
* Application Service Providers...
|
||||
@@ -371,7 +372,7 @@ return [
|
||||
'Mail' => Illuminate\Support\Facades\Mail::class,
|
||||
'Notification' => Illuminate\Support\Facades\Notification::class,
|
||||
'Password' => Illuminate\Support\Facades\Password::class,
|
||||
'PDF' => Barryvdh\DomPDF\Facade::class,
|
||||
'PDF' => Elibyy\TCPDF\Facades\TCPDF::class,
|
||||
'Queue' => Illuminate\Support\Facades\Queue::class,
|
||||
'Redirect' => Illuminate\Support\Facades\Redirect::class,
|
||||
'Redis' => Illuminate\Support\Facades\Redis::class,
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'mode' => 'utf-8',
|
||||
'format' => 'A4',
|
||||
'author' => '',
|
||||
'subject' => '',
|
||||
'keywords' => '',
|
||||
'creator' => 'Snipe-IT',
|
||||
'display_mode' => 'fullpage',
|
||||
'tempDir' => base_path('../temp/'),
|
||||
'pdf_a' => false,
|
||||
'pdf_a_auto' => false,
|
||||
'icc_profile_path' => '',
|
||||
'defaultCssFile' => false,
|
||||
'pdfWrapper' => 'misterspelik\LaravelPdf\Wrapper\PdfWrapper',
|
||||
];
|
||||
@@ -33,9 +33,9 @@ class LicenseFactory extends Factory
|
||||
'seats' => $this->faker->numberBetween(1, 10),
|
||||
'purchase_date' => $this->faker->dateTimeBetween('-1 years', 'now', date_default_timezone_get())->format('Y-m-d'),
|
||||
'order_number' => $this->faker->numberBetween(1000000, 50000000),
|
||||
'expiration_date' => $this->faker->dateTimeBetween('now', '+3 years', date_default_timezone_get())->format('Y-m-d H:i:s'),
|
||||
'expiration_date' => null,
|
||||
'reassignable' => $this->faker->boolean(),
|
||||
'termination_date' => $this->faker->dateTimeBetween('-1 years', 'now', date_default_timezone_get())->format('Y-m-d H:i:s'),
|
||||
'termination_date' => null,
|
||||
'supplier_id' => Supplier::factory(),
|
||||
'category_id' => Category::factory(),
|
||||
];
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::whenTableDoesntHaveColumn('checkout_acceptances', 'qty', function () {
|
||||
Schema::table('checkout_acceptances', function (Blueprint $table) {
|
||||
$table->unsignedInteger('qty')->nullable()->after('assigned_to_id')->default(null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::whenTableHasColumn('checkout_acceptances', 'qty', function () {
|
||||
Schema::table('checkout_acceptances', function (Blueprint $table) {
|
||||
$table->dropColumn('qty');
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
// We are doing 'deleted_at' *first* here because that way this index can do double-duty -
|
||||
// handling queries for 'all undeleted users' as well as 'users who are deleted in this location'
|
||||
// and 'users who are not-deleted in this location'
|
||||
$table->index(['deleted_at','location_id']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropIndex(['deleted_at','location_id']);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -21,11 +21,11 @@ class SettingsSeeder extends Seeder
|
||||
$settings->header_color = null;
|
||||
$settings->label2_2d_type = 'QRCODE';
|
||||
$settings->default_currency = 'USD';
|
||||
$settings->brand = 3;
|
||||
$settings->brand = 2;
|
||||
$settings->ldap_enabled = 0;
|
||||
$settings->full_multiple_companies_support = 0;
|
||||
$settings->label2_1d_type = 'C128';
|
||||
$settings->skin = '';
|
||||
$settings->skin = 'blue';
|
||||
$settings->email_domain = 'example.org';
|
||||
$settings->email_format = 'filastname';
|
||||
$settings->username_format = 'filastname';
|
||||
@@ -41,6 +41,8 @@ class SettingsSeeder extends Seeder
|
||||
|
||||
if ($user = User::where('username', '=', 'admin')->first()) {
|
||||
$user->locale = 'en-US';
|
||||
$user->enable_sound = 1;
|
||||
$user->enable_confetti = 1;
|
||||
$user->save();
|
||||
}
|
||||
|
||||
|
||||
@@ -1049,6 +1049,7 @@ th.css-license > .th-inner,
|
||||
th.css-location > .th-inner,
|
||||
th.css-users > .th-inner,
|
||||
th.css-currency > .th-inner,
|
||||
th.css-child-locations > .th-inner,
|
||||
th.css-history > .th-inner {
|
||||
font-size: 0px;
|
||||
line-height: 0.75 !important;
|
||||
@@ -1071,6 +1072,7 @@ th.css-license > .th-inner::before,
|
||||
th.css-location > .th-inner::before,
|
||||
th.css-users > .th-inner::before,
|
||||
th.css-currency > .th-inner::before,
|
||||
th.css-child-locations > .th-inner::before,
|
||||
th.css-history > .th-inner::before {
|
||||
display: inline-block;
|
||||
font-size: 20px;
|
||||
@@ -1152,6 +1154,12 @@ th.css-accessory-alt > .th-inner::before {
|
||||
font-size: 19px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
th.css-child-locations > .th-inner::before {
|
||||
content: "\f64f";
|
||||
font-family: "Font Awesome 5 Free";
|
||||
font-size: 19px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
th.css-currency > .th-inner::before {
|
||||
content: "\24";
|
||||
font-family: "Font Awesome 5 Free";
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -673,6 +673,7 @@ th.css-license > .th-inner,
|
||||
th.css-location > .th-inner,
|
||||
th.css-users > .th-inner,
|
||||
th.css-currency > .th-inner,
|
||||
th.css-child-locations > .th-inner,
|
||||
th.css-history > .th-inner {
|
||||
font-size: 0px;
|
||||
line-height: 0.75 !important;
|
||||
@@ -695,6 +696,7 @@ th.css-license > .th-inner::before,
|
||||
th.css-location > .th-inner::before,
|
||||
th.css-users > .th-inner::before,
|
||||
th.css-currency > .th-inner::before,
|
||||
th.css-child-locations > .th-inner::before,
|
||||
th.css-history > .th-inner::before {
|
||||
display: inline-block;
|
||||
font-size: 20px;
|
||||
@@ -776,6 +778,12 @@ th.css-accessory-alt > .th-inner::before {
|
||||
font-size: 19px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
th.css-child-locations > .th-inner::before {
|
||||
content: "\f64f";
|
||||
font-family: "Font Awesome 5 Free";
|
||||
font-size: 19px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
th.css-currency > .th-inner::before {
|
||||
content: "\24";
|
||||
font-family: "Font Awesome 5 Free";
|
||||
|
||||
File diff suppressed because one or more lines are too long
Vendored
+16
@@ -22385,6 +22385,7 @@ th.css-license > .th-inner,
|
||||
th.css-location > .th-inner,
|
||||
th.css-users > .th-inner,
|
||||
th.css-currency > .th-inner,
|
||||
th.css-child-locations > .th-inner,
|
||||
th.css-history > .th-inner {
|
||||
font-size: 0px;
|
||||
line-height: 0.75 !important;
|
||||
@@ -22407,6 +22408,7 @@ th.css-license > .th-inner::before,
|
||||
th.css-location > .th-inner::before,
|
||||
th.css-users > .th-inner::before,
|
||||
th.css-currency > .th-inner::before,
|
||||
th.css-child-locations > .th-inner::before,
|
||||
th.css-history > .th-inner::before {
|
||||
display: inline-block;
|
||||
font-size: 20px;
|
||||
@@ -22488,6 +22490,12 @@ th.css-accessory-alt > .th-inner::before {
|
||||
font-size: 19px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
th.css-child-locations > .th-inner::before {
|
||||
content: "\f64f";
|
||||
font-family: "Font Awesome 5 Free";
|
||||
font-size: 19px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
th.css-currency > .th-inner::before {
|
||||
content: "\24";
|
||||
font-family: "Font Awesome 5 Free";
|
||||
@@ -23989,6 +23997,7 @@ th.css-license > .th-inner,
|
||||
th.css-location > .th-inner,
|
||||
th.css-users > .th-inner,
|
||||
th.css-currency > .th-inner,
|
||||
th.css-child-locations > .th-inner,
|
||||
th.css-history > .th-inner {
|
||||
font-size: 0px;
|
||||
line-height: 0.75 !important;
|
||||
@@ -24011,6 +24020,7 @@ th.css-license > .th-inner::before,
|
||||
th.css-location > .th-inner::before,
|
||||
th.css-users > .th-inner::before,
|
||||
th.css-currency > .th-inner::before,
|
||||
th.css-child-locations > .th-inner::before,
|
||||
th.css-history > .th-inner::before {
|
||||
display: inline-block;
|
||||
font-size: 20px;
|
||||
@@ -24092,6 +24102,12 @@ th.css-accessory-alt > .th-inner::before {
|
||||
font-size: 19px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
th.css-child-locations > .th-inner::before {
|
||||
content: "\f64f";
|
||||
font-family: "Font Awesome 5 Free";
|
||||
font-size: 19px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
th.css-currency > .th-inner::before {
|
||||
content: "\24";
|
||||
font-family: "Font Awesome 5 Free";
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"/js/dist/all.js": "/js/dist/all.js?id=76d88f0f91b852f7eecbce357ab5858b",
|
||||
"/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=42f97cd5b9ee7521b04a448e7fc16ac9",
|
||||
"/css/dist/skins/_all-skins.css": "/css/dist/skins/_all-skins.css?id=d81a7ed323f68a7c5e3e9115f7fb5404",
|
||||
"/css/build/overrides.css": "/css/build/overrides.css?id=257e65d85ce9cf5a413065df1b131c03",
|
||||
"/css/build/app.css": "/css/build/app.css?id=3dcb1500ec5991cc4058fd5e4d9b8b49",
|
||||
"/css/build/overrides.css": "/css/build/overrides.css?id=d8bef2b8ef03ee8dbb120749211eafc0",
|
||||
"/css/build/app.css": "/css/build/app.css?id=1bf6a5e78cbccff6e6d32640c28c54b8",
|
||||
"/css/build/AdminLTE.css": "/css/build/AdminLTE.css?id=ee0ed88465dd878588ed044eefb67723",
|
||||
"/css/dist/skins/skin-yellow.css": "/css/dist/skins/skin-yellow.css?id=3d8a3d2035ea28aaad4a703c2646f515",
|
||||
"/css/dist/skins/skin-yellow-dark.css": "/css/dist/skins/skin-yellow-dark.css?id=3979929a3423ff35b96b1fc84299fdf3",
|
||||
@@ -19,7 +19,7 @@
|
||||
"/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=b2cd9f59d7e8587939ce27b2d3363d82",
|
||||
"/css/dist/skins/skin-blue-dark.css": "/css/dist/skins/skin-blue-dark.css?id=7277edd636cf46aa7786a4449ce0ead7",
|
||||
"/css/dist/skins/skin-black.css": "/css/dist/skins/skin-black.css?id=cbd06cc1d58197ccc81d4376bbaf0d28",
|
||||
"/css/dist/all.css": "/css/dist/all.css?id=a6b8969f0f70c07cf740f30bb7139b45",
|
||||
"/css/dist/all.css": "/css/dist/all.css?id=dd5f7ab27ec80569b90d63a883718ff9",
|
||||
"/css/dist/signature-pad.css": "/css/dist/signature-pad.css?id=6a89d3cd901305e66ced1cf5f13147f7",
|
||||
"/css/dist/signature-pad.min.css": "/css/dist/signature-pad.min.css?id=6a89d3cd901305e66ced1cf5f13147f7",
|
||||
"/js/select2/i18n/af.js": "/js/select2/i18n/af.js?id=4f6fcd73488ce79fae1b7a90aceaecde",
|
||||
|
||||
@@ -746,6 +746,7 @@ th.css-license > .th-inner,
|
||||
th.css-location > .th-inner,
|
||||
th.css-users > .th-inner,
|
||||
th.css-currency > .th-inner,
|
||||
th.css-child-locations > .th-inner,
|
||||
th.css-history > .th-inner
|
||||
{
|
||||
font-size: 0px;
|
||||
@@ -771,6 +772,7 @@ th.css-license > .th-inner::before,
|
||||
th.css-location > .th-inner::before,
|
||||
th.css-users > .th-inner::before,
|
||||
th.css-currency > .th-inner::before,
|
||||
th.css-child-locations > .th-inner::before,
|
||||
th.css-history > .th-inner::before
|
||||
{
|
||||
display: inline-block;
|
||||
@@ -853,6 +855,13 @@ th.css-accessory-alt > .th-inner::before {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
th.css-child-locations > .th-inner::before {
|
||||
content: "\f64f"; // change this to f51e for coins
|
||||
font-family: "Font Awesome 5 Free";
|
||||
font-size: 19px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
th.css-currency > .th-inner::before {
|
||||
content: "\24"; // change this to f51e for coins
|
||||
font-family: "Font Awesome 5 Free";
|
||||
|
||||
@@ -46,6 +46,7 @@ return array(
|
||||
'not_enough_seats' => 'Not enough license seats available for checkout',
|
||||
'mismatch' => 'The license seat provided does not match the license',
|
||||
'unavailable' => 'This seat is not available for checkout.',
|
||||
'license_is_inactive' => 'This license is expired or terminated.',
|
||||
),
|
||||
|
||||
'checkin' => array(
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
return array(
|
||||
|
||||
'does_not_exist' => 'Location does not exist.',
|
||||
'assoc_users' => 'This location is not currently deletable because it is the location of record for at least one asset or user, has assets assigned to it, or is the parent location of another location. Please update your records to no longer reference this location and try again ',
|
||||
'assoc_users' => 'This location is not currently deletable because it is the location of record for at least one item or user, has assets assigned to it, or is the parent location of another location. Please update your records to no longer reference this location and try again ',
|
||||
'assoc_assets' => 'This location is currently associated with at least one asset and cannot be deleted. Please update your assets to no longer reference this location and try again. ',
|
||||
'assoc_child_loc' => 'This location is currently the parent of at least one child location and cannot be deleted. Please update your locations to no longer reference this location and try again. ',
|
||||
'assigned_assets' => 'Assigned Assets',
|
||||
'current_location' => 'Current Location',
|
||||
'open_map' => 'Open in :map_provider_icon Maps',
|
||||
'deleted_warning' => 'This location has been deleted. Please restore it before attempting to make any changes.',
|
||||
|
||||
|
||||
'create' => array(
|
||||
|
||||
@@ -12,7 +12,8 @@ return [
|
||||
'create' => 'Create Location',
|
||||
'update' => 'Update Location',
|
||||
'print_assigned' => 'Print Assigned',
|
||||
'print_all_assigned' => 'Print All Assigned',
|
||||
'print_inventory' => 'Print Inventory',
|
||||
'print_all_assigned' => 'Print Inventory and Assigned',
|
||||
'name' => 'Location Name',
|
||||
'address' => 'Address',
|
||||
'address2' => 'Address Line 2',
|
||||
|
||||
@@ -11,7 +11,6 @@ return array(
|
||||
'title' => 'Asset Models',
|
||||
'update' => 'Update Asset Model',
|
||||
'view' => 'View Asset Model',
|
||||
'update' => 'Update Asset Model',
|
||||
'clone' => 'Clone Model',
|
||||
'edit' => 'Edit Model',
|
||||
'clone' => 'Clone Model',
|
||||
'edit' => 'Edit Model',
|
||||
);
|
||||
|
||||
@@ -313,6 +313,7 @@ return [
|
||||
'undeployable' => 'Un-deployable',
|
||||
'unknown_admin' => 'Unknown Admin',
|
||||
'unknown_user' => 'Unknown User',
|
||||
'unit_cost' => 'Unit Cost',
|
||||
'username' => 'Username',
|
||||
'update' => 'Update',
|
||||
'updating_item' => 'Updating :item',
|
||||
@@ -353,9 +354,11 @@ return [
|
||||
'audit_overdue' => 'Overdue for Audit',
|
||||
'accept' => 'Accept :asset',
|
||||
'i_accept' => 'I accept',
|
||||
'i_decline_item' => 'Decline this item',
|
||||
'i_accept_item' => 'Accept this item',
|
||||
'i_accept_with_count' => 'I accept :count item|I accept :count items',
|
||||
'i_decline_item' => 'Decline this item|Decline these items',
|
||||
'i_accept_item' => 'Accept this item|Accept these items',
|
||||
'i_decline' => 'I decline',
|
||||
'i_decline_with_count' => 'I decline :count item|I decline :count items',
|
||||
'accept_decline' => 'Accept/Decline',
|
||||
'sign_tos' => 'Sign below to indicate that you agree to the terms of service:',
|
||||
'clear_signature' => 'Clear Signature',
|
||||
@@ -587,6 +590,7 @@ return [
|
||||
'components' => ':count Component|:count Components',
|
||||
],
|
||||
|
||||
'show_inactive' => 'Expired or Terminated',
|
||||
'more_info' => 'More Info',
|
||||
'quickscan_bulk_help' => 'Checking this box will edit the asset record to reflect this new location. Leaving it unchecked will simply note the location in the audit log. Note that if this asset is checked out, it will not change the location of the person, asset or location it is checked out to.',
|
||||
'whoops' => 'Whoops!',
|
||||
@@ -612,6 +616,7 @@ return [
|
||||
'footer_credit' => '<a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> is open source software, made with <i class="fa fa-heart" aria-hidden="true" style="color: #a94442; font-size: 10px" /></i><span class="sr-only">love</span> by <a href="https://bsky.app/profile/snipeitapp.com" rel="noopener">@snipeitapp.com</a>.',
|
||||
'set_password' => 'Set a Password',
|
||||
'upload_deleted' => 'Upload Deleted',
|
||||
'child_locations' => 'Child Locations',
|
||||
|
||||
// Add form placeholders here
|
||||
'placeholders' => [
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
return [
|
||||
|
||||
'Accessory_Checkin_Notification' => 'Accessory checked in',
|
||||
'Accessory_Checkout_Notification' => 'Accessory checked out',
|
||||
'Accessory_Checkout_Notification' => 'Accessory checked out|:count Accessories checked out',
|
||||
'Asset_Checkin_Notification' => 'Asset checked in: :tag',
|
||||
'Asset_Checkout_Notification' => 'Asset checked out: :tag',
|
||||
'Confirm_Accessory_Checkin' => 'Accessory checkin confirmation',
|
||||
@@ -21,8 +21,8 @@ return [
|
||||
'Expected_Checkin_Date' => 'An asset checked out to you is due to be checked back in on :date',
|
||||
'Expected_Checkin_Notification' => 'Reminder: :name checkin deadline approaching',
|
||||
'Expected_Checkin_Report' => 'Expected asset checkin report',
|
||||
'Expiring_Assets_Report' => 'Expiring Assets Report.',
|
||||
'Expiring_Licenses_Report' => 'Expiring Licenses Report.',
|
||||
'Expiring_Assets_Report' => 'Expiring Assets Report',
|
||||
'Expiring_Licenses_Report' => 'Expiring Licenses Report',
|
||||
'Item_Request_Canceled' => 'Item Request Canceled',
|
||||
'Item_Requested' => 'Item Requested',
|
||||
'License_Checkin_Notification' => 'License checked in',
|
||||
@@ -42,8 +42,9 @@ return [
|
||||
'asset_name' => 'Asset Name',
|
||||
'asset_requested' => 'Asset requested',
|
||||
'asset_tag' => 'Asset Tag',
|
||||
'assets_warrantee_alert' => 'There is :count asset with a warranty expiring in the next :threshold days.|There are :count assets with warranties expiring in the next :threshold days.',
|
||||
'assets_warrantee_alert' => 'There is :count asset with an expiring warranty or that are reaching their end of life in the next :threshold days.|There are :count assets with expiring warranties or that are reaching their end of life in the next :threshold days.',
|
||||
'assigned_to' => 'Assigned To',
|
||||
'eol' => 'EOL',
|
||||
'best_regards' => 'Best regards,',
|
||||
'canceled' => 'Canceled',
|
||||
'checkin_date' => 'Checkin Date',
|
||||
@@ -68,16 +69,16 @@ return [
|
||||
'inventory_report' => 'Inventory Report',
|
||||
'item' => 'Item',
|
||||
'item_checked_reminder' => 'This is a reminder that you currently have :count items checked out to you that you have not accepted or declined. Please click the link below to confirm your decision.',
|
||||
'license_expiring_alert' => 'There is :count license expiring in the next :threshold days.|There are :count licenses expiring in the next :threshold days.',
|
||||
'license_expiring_alert' => 'There is :count license expiring or terminating in the next :threshold days.|There are :count licenses expiring or terminating in the next :threshold days.',
|
||||
'link_to_update_password' => 'Please click on the following link to update your :web password:',
|
||||
'login' => 'Login',
|
||||
'login_first_admin' => 'Login to your new Snipe-IT installation using the credentials below:',
|
||||
'low_inventory_alert' => 'There is :count item that is below minimum inventory or will soon be low.|There are :count items that are below minimum inventory or will soon be low.',
|
||||
'min_QTY' => 'Min QTY',
|
||||
'name' => 'Name',
|
||||
'new_item_checked' => 'A new item has been checked out under your name, details are below.',
|
||||
'new_item_checked_with_acceptance' => 'A new item has been checked out under your name that requires acceptance, details are below.',
|
||||
'new_item_checked_location' => 'A new item has been checked out to :location, details are below.',
|
||||
'new_item_checked' => 'A new item has been checked out under your name, details are below.|:count new items have been checked out under your name, details are below.',
|
||||
'new_item_checked_with_acceptance' => 'A new item has been checked out under your name that requires acceptance, details are below.|:count new items have been checked out under your name that requires acceptance, details are below.',
|
||||
'new_item_checked_location' => 'A new item has been checked out to :location, details are below.|:count new items have been checked out to :location, details are below.',
|
||||
'recent_item_checked' => 'An item was recently checked out under your name that requires acceptance, details are below.',
|
||||
'notes' => 'Notes',
|
||||
'password' => 'Password',
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
@include ('partials.forms.edit.model_number')
|
||||
@include ('partials.forms.edit.order_number')
|
||||
@include ('partials.forms.edit.datepicker', ['translated_name' => trans('general.purchase_date'),'fieldname' => 'purchase_date'])
|
||||
@include ('partials.forms.edit.purchase_cost', ['currency_type' => $item->location->currency ?? null])
|
||||
@include ('partials.forms.edit.purchase_cost', ['currency_type' => $item->location->currency ?? null, 'unit_cost' => trans('general.unit_cost')])
|
||||
@include ('partials.forms.edit.quantity')
|
||||
@include ('partials.forms.edit.minimum_quantity')
|
||||
@include ('partials.forms.edit.notes')
|
||||
|
||||
@@ -236,7 +236,7 @@
|
||||
<div class="row">
|
||||
<div class="col-md-3" style="padding-bottom: 10px;">
|
||||
<strong>
|
||||
{{ trans('general.purchase_cost') }}
|
||||
{{ trans('general.unit_cost') }}
|
||||
</strong>
|
||||
</div>
|
||||
<div class="col-md-9" style="word-wrap: break-word;">
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<style>
|
||||
body {
|
||||
font-family:'Dejavu Sans', Arial, Helvetica, sans-serif;
|
||||
font-size: 11px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@if ($logo)
|
||||
<center>
|
||||
<img src="{{ $logo }}">
|
||||
<p>{{$company_name}}</p>
|
||||
</center>
|
||||
@endif
|
||||
<br>
|
||||
|
||||
<p>
|
||||
{{ trans('general.date') }}: {{ date($date_settings) }} <br>
|
||||
{{ trans('general.asset_model') }}: {{ $item_model }}<br>
|
||||
</p>
|
||||
|
||||
@if ($eula)
|
||||
<hr>
|
||||
{!! $eula !!}
|
||||
<hr>
|
||||
@endif
|
||||
|
||||
|
||||
<p>
|
||||
{{ trans('general.assigned_date') }}: {{$check_out_date}}<br>
|
||||
{{ trans('general.assignee') }}: {{$assigned_to}}<br>
|
||||
{{ trans('general.accepted_date') }}: {{$accepted_date}}
|
||||
</p>
|
||||
|
||||
|
||||
@if ($signature!='')
|
||||
<img src="{{ $signature }}" style="max-width: 600px; border-bottom: black solid 1px;">
|
||||
@endif
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,50 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<style>
|
||||
body {
|
||||
font-family:'Dejavu Sans', Arial, Helvetica, sans-serif;
|
||||
font-size: 11px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@if ($logo)
|
||||
<center>
|
||||
<img src="{{ $logo }}">
|
||||
<p>{{$company_name}}</p>
|
||||
</center>
|
||||
@endif
|
||||
<br>
|
||||
|
||||
<p>
|
||||
{{ trans('general.date') }}: {{ date($date_settings) }} <br>
|
||||
{{ trans('general.asset_tag') }}: {{ $item_tag }}<br>
|
||||
{{ trans('general.asset_model') }}: {{ $item_model }}<br>
|
||||
{{ trans('admin/hardware/form.serial') }}: {{ $item_serial }}
|
||||
</p>
|
||||
|
||||
|
||||
@if ($eula)
|
||||
<hr>
|
||||
{!! $eula !!}
|
||||
<hr>
|
||||
@endif
|
||||
|
||||
|
||||
<p>
|
||||
{{ trans('general.assigned_date') }}: {{$check_out_date}}<br>
|
||||
{{ trans('general.assignee') }}: {{$assigned_to}}<br>
|
||||
{{ trans('general.accepted_date') }}: {{$accepted_date}}
|
||||
</p>
|
||||
|
||||
|
||||
@if ($signature!='')
|
||||
<img src="{{ $signature }}" style="max-width: 600px; border-bottom: black solid 1px;">
|
||||
@endif
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,47 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<style>
|
||||
body {
|
||||
font-family:'Dejavu Sans', Arial, Helvetica, sans-serif;
|
||||
font-size: 11px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@if ($logo)
|
||||
<center>
|
||||
<img src="{{ $logo }}">
|
||||
<p>{{$company_name}}</p>
|
||||
</center>
|
||||
@endif
|
||||
<br>
|
||||
|
||||
<p>
|
||||
{{ trans('general.date') }}: {{ date($date_settings) }} <br>
|
||||
{{ trans('general.component') }}: {{ $item_model }}<br>
|
||||
</p>
|
||||
|
||||
@if ($eula)
|
||||
<hr>
|
||||
{!! $eula !!}
|
||||
<hr>
|
||||
@endif
|
||||
|
||||
|
||||
<p>
|
||||
{{ trans('general.assigned_date') }}: {{$check_out_date}}<br>
|
||||
{{ trans('general.assignee') }}: {{$assigned_to}}<br>
|
||||
{{ trans('general.accepted_date') }}: {{$accepted_date}}
|
||||
</p>
|
||||
|
||||
|
||||
@if ($signature!='')
|
||||
<img src="{{ $signature }}" style="max-width: 600px; border-bottom: black solid 1px;">
|
||||
@endif
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,47 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<style>
|
||||
body {
|
||||
font-family:'Dejavu Sans', Arial, Helvetica, sans-serif;
|
||||
font-size: 11px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@if ($logo)
|
||||
<center>
|
||||
<img src="{{ $logo }}">
|
||||
<p>{{$company_name}}</p>
|
||||
</center>
|
||||
@endif
|
||||
<br>
|
||||
|
||||
<p>
|
||||
{{ trans('general.date') }}: {{ date($date_settings) }} <br>
|
||||
{{ trans('general.consumable') }}: {{ $item_model }}<br>
|
||||
</p>
|
||||
|
||||
@if ($eula)
|
||||
<hr>
|
||||
{!! $eula !!}
|
||||
<hr>
|
||||
@endif
|
||||
|
||||
|
||||
<p>
|
||||
{{ trans('general.assigned_date') }}: {{$check_out_date}}<br>
|
||||
{{ trans('general.assignee') }}: {{$assigned_to}}<br>
|
||||
{{ trans('general.accepted_date') }}: {{$accepted_date}}
|
||||
</p>
|
||||
|
||||
|
||||
@if ($signature!='')
|
||||
<img src="{{ $signature }}" style="max-width: 600px; border-bottom: black solid 1px;">
|
||||
@endif
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,47 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<style>
|
||||
body {
|
||||
font-family:'Dejavu Sans', Arial, Helvetica, sans-serif;
|
||||
font-size: 11px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@if ($logo)
|
||||
<center>
|
||||
<img src="{{ $logo }}">
|
||||
<p>{{$company_name}}</p>
|
||||
</center>
|
||||
@endif
|
||||
<br>
|
||||
|
||||
<p>
|
||||
{{ trans('general.date') }}: {{ date($date_settings) }} <br>
|
||||
{{ trans('general.license') }}: {{ $item_model }}<br>
|
||||
</p>
|
||||
|
||||
@if ($eula)
|
||||
<hr>
|
||||
{!! $eula !!}
|
||||
<hr>
|
||||
@endif
|
||||
|
||||
|
||||
<p>
|
||||
{{ trans('general.assigned_date') }}: {{$check_out_date}}<br>
|
||||
{{ trans('general.assignee') }}: {{$assigned_to}}<br>
|
||||
{{ trans('general.accepted_date') }}: {{$accepted_date}}
|
||||
</p>
|
||||
|
||||
|
||||
@if ($signature!='')
|
||||
<img src="{{ $signature }}" style="max-width: 600px; border-bottom: black solid 1px;">
|
||||
@endif
|
||||
</body>
|
||||
</html>
|
||||
@@ -39,25 +39,38 @@
|
||||
<div class="box-header with-border">
|
||||
<h2 class="box-title">
|
||||
{{ $acceptance->checkoutable->display_name }}
|
||||
{{ (($acceptance->checkoutable) && ($acceptance->checkoutable->serial)) ? ' - '.trans('general.serial_number').': '.$acceptance->checkoutable->serial : '' }}
|
||||
@if ($acceptance->qty > 1)
|
||||
<strong>×{{ $acceptance->qty }}</strong>
|
||||
@endif
|
||||
|
||||
{!! (($acceptance->checkoutable) && ($acceptance->checkoutable->serial)) ? '<br>'.trans('general.serial_number').': '.e($acceptance->checkoutable->serial) : '' !!}
|
||||
|
||||
</h2>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
@if ($acceptance->checkoutable->getEula())
|
||||
<div class="col-md-12" style="padding-top: 15px; padding-bottom: 15px;">
|
||||
<div style="background-color: rgba(211,211,211,0.25); padding: 10px; border: lightgrey 1px solid;">
|
||||
{!! str_replace('<p>', '<p dir="auto">', $acceptance->checkoutable->getEula()) !!}
|
||||
<div class="col-md-12" style="padding-top: 5px; padding-bottom: 15px;">
|
||||
<div style="background-color: rgba(211,211,211,0.25); padding: 0px 10px 10px 10px; border: lightgrey 1px solid;">
|
||||
{!! str_replace('<p>', '<p dir="auto">', Helper::parseEscapedMarkedown($acceptance->checkoutable->getEula())) !!}
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
<div class="col-md-12">
|
||||
<label class="form-control">
|
||||
<input type="radio" name="asset_acceptance" id="accepted" value="accepted">
|
||||
{{trans('general.i_accept')}}
|
||||
@if ($acceptance->qty)
|
||||
{{trans_choice('general.i_accept_with_count', $acceptance->qty)}}
|
||||
@else
|
||||
{{trans('general.i_accept')}}
|
||||
@endif
|
||||
</label>
|
||||
<label class="form-control">
|
||||
<input type="radio" name="asset_acceptance" id="declined" value="declined">
|
||||
{{trans('general.i_decline')}}
|
||||
@if ($acceptance->qty)
|
||||
{{trans_choice('general.i_decline_with_count', $acceptance->qty)}}
|
||||
@else
|
||||
{{trans('general.i_decline')}}
|
||||
@endif
|
||||
</label>
|
||||
|
||||
</div>
|
||||
@@ -98,7 +111,7 @@
|
||||
<button type="submit" class="btn btn-success" id="submit-button">
|
||||
<i class="fa fa-check icon-white" aria-hidden="true" id="submitIcon"></i>
|
||||
<span id="buttonText">
|
||||
{{ trans('general.i_accept_item') }}
|
||||
{{ trans_choice('general.i_accept_item', $acceptance->qty ?? null) }}
|
||||
</span>
|
||||
</button>
|
||||
</div><!-- /.box-footer -->
|
||||
@@ -161,7 +174,7 @@
|
||||
$("#showSubmit").show();
|
||||
$("#submit-button").removeClass("btn-success").addClass("btn-danger").show();
|
||||
$("#submitIcon").removeClass("fa-check").addClass("fa-times");
|
||||
$("#buttonText").text('{{ trans('general.i_decline_item') }}');
|
||||
$("#buttonText").text('{{ trans_choice('general.i_decline_item', $acceptance->qty ?? 1) }}');
|
||||
$("#note").prop('required', true);
|
||||
|
||||
} else if ($(this).is(':checked') && $(this).attr('id') === 'accepted') {
|
||||
@@ -169,16 +182,9 @@
|
||||
$("#showSubmit").show();
|
||||
$("#submit-button").removeClass("btn-danger").addClass("btn-success").show();
|
||||
$("#submitIcon").removeClass("fa-check").addClass("fa-check");
|
||||
$("#buttonText").text('{{ trans('general.i_accept_item') }}');
|
||||
$("#buttonText").text('{{ trans_choice('general.i_accept_item', $acceptance->qty ?? 1) }}');
|
||||
$("#note").prop('required', false);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
@stop
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
<tr>
|
||||
<th>{{ trans('general.name')}}</th>
|
||||
<th>{{ trans('general.type')}}</th>
|
||||
<th>{{ trans('general.qty') }}</th>
|
||||
<th>{{ trans('general.serial_number')}}</th>
|
||||
<th>{{ trans('table.actions')}}</th>
|
||||
</tr>
|
||||
@@ -41,8 +42,9 @@
|
||||
<tr>
|
||||
@if ($acceptance->checkoutable)
|
||||
<td>{{ ($acceptance->checkoutable) ? $acceptance->checkoutable->present()->name : '' }}</td>
|
||||
<td>{{ $acceptance->checkoutable_item_type }}</td>
|
||||
<td>{{ ($acceptance->checkoutable) ? $acceptance->checkoutable->serial : '' }}</td>
|
||||
<td>{{ $acceptance->checkoutable_item_type }}</td>
|
||||
<td>{{ $acceptance->qty ?? '1' }}</td>
|
||||
<td>{{ ($acceptance->checkoutable) ? $acceptance->checkoutable->serial : '' }}</td>
|
||||
<td><a href="{{ route('account.accept.item', $acceptance) }}" class="btn btn-default btn-sm">{{ trans('general.accept_decline') }}</a></td>
|
||||
@else
|
||||
<td> ----- </td>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
{{-- Account page content --}}
|
||||
@section('content')
|
||||
|
||||
@if ($acceptances = \App\Models\CheckoutAcceptance::forUser(Auth::user())->pending()->count())
|
||||
@if ($acceptanceQuantity = \App\Models\CheckoutAcceptance::forUser(Auth::user())->pending()->sum('qty'))
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="alert alert alert-warning fade in">
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<strong>
|
||||
<a href="{{ route('account.accept') }}" style="color: white;">
|
||||
{{ trans_choice('general.unaccepted_profile_warning', $acceptances, ['count' => $acceptances]) }}
|
||||
{{ trans_choice('general.unaccepted_profile_warning', $acceptanceQuantity, ['count' => $acceptanceQuantity]) }}
|
||||
</a>
|
||||
</strong>
|
||||
</div>
|
||||
@@ -446,6 +446,9 @@
|
||||
<th class="col-md-2" data-switchable="true" data-visible="false">
|
||||
{{ trans('general.name') }}
|
||||
</th>
|
||||
<th class="col-md-2" data-switchable="true" data-visible="false">
|
||||
{{ trans('general.status') }}
|
||||
</th>
|
||||
<th class="col-md-2" data-switchable="true" data-visible="true">
|
||||
{{ trans('admin/hardware/table.asset_model') }}
|
||||
</th>
|
||||
@@ -461,7 +464,6 @@
|
||||
<th class="col-md-2" data-switchable="true" data-visible="false">
|
||||
{{ trans('general.location') }}
|
||||
</th>
|
||||
|
||||
@can('self.view_purchase_cost')
|
||||
<th class="col-md-6" data-footer-formatter="sumFormatter" data-fieldname="purchase_cost">
|
||||
{{ trans('general.purchase_cost') }}
|
||||
@@ -508,6 +510,11 @@
|
||||
<td>
|
||||
{{ $asset->name }}
|
||||
</td>
|
||||
<td>
|
||||
<x-icon type="circle-solid" class="text-blue" />
|
||||
{{ $asset->assetstatus->name }}
|
||||
<label class="label label-default">{{ trans('general.deployed') }}</label>
|
||||
</td>
|
||||
<td>
|
||||
{{ $asset->model->name }}
|
||||
</td>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
@include ('partials.forms.edit.supplier-select', ['translated_name' => trans('general.supplier'), 'fieldname' => 'supplier_id'])
|
||||
@include ('partials.forms.edit.order_number')
|
||||
@include ('partials.forms.edit.datepicker', ['translated_name' => trans('general.purchase_date'),'fieldname' => 'purchase_date'])
|
||||
@include ('partials.forms.edit.purchase_cost')
|
||||
@include ('partials.forms.edit.purchase_cost', ['unit_cost' => trans('general.unit_cost')])
|
||||
@include ('partials.forms.edit.notes')
|
||||
@include ('partials.forms.edit.image-upload', ['image_path' => app('components_upload_path')])
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@
|
||||
@endif
|
||||
|
||||
@if ($component->purchase_cost)
|
||||
<div class="col-md-12" style="padding-bottom: 5px;"><strong>{{ trans('admin/components/general.cost') }}:</strong>
|
||||
<div class="col-md-12" style="padding-bottom: 5px;"><strong>{{ trans('general.unit_cost') }}:</strong>
|
||||
{{ $snipeSettings->default_currency }}
|
||||
|
||||
{{ Helper::formatCurrencyOutput($component->purchase_cost) }} </div>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
@include ('partials.forms.edit.item_number')
|
||||
@include ('partials.forms.edit.order_number')
|
||||
@include ('partials.forms.edit.datepicker', ['translated_name' => trans('general.purchase_date'),'fieldname' => 'purchase_date'])
|
||||
@include ('partials.forms.edit.purchase_cost')
|
||||
@include ('partials.forms.edit.purchase_cost', [ 'unit_cost' => trans('general.unit_cost')])
|
||||
@include ('partials.forms.edit.quantity')
|
||||
@include ('partials.forms.edit.minimum_quantity')
|
||||
@include ('partials.forms.edit.notes')
|
||||
|
||||
@@ -272,7 +272,7 @@
|
||||
@if ($consumable->purchase_cost)
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
{{ trans('general.purchase_cost') }}
|
||||
{{ trans('general.unit_cost') }}
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
{{ $snipeSettings->default_currency }}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
id="licensesTable"
|
||||
data-buttons="licenseButtons"
|
||||
class="table table-striped snipe-table"
|
||||
data-url="{{ route('api.licenses.index') }}"
|
||||
data-url="{{ route('api.licenses.index', ['status' => e(request('status'))]) }}"
|
||||
data-export-options='{
|
||||
"fileName": "export-licenses-{{ date('Y-m-d') }}",
|
||||
"ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"]
|
||||
|
||||
@@ -249,6 +249,11 @@
|
||||
</strong>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
@if ($license->isExpired())
|
||||
<span class="text-danger">
|
||||
<x-icon type="warning" class="text-warning" />
|
||||
</span>
|
||||
@endif
|
||||
{{ Helper::getFormattedDateObject($license->expiration_date, 'date', false) }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -262,6 +267,12 @@
|
||||
</strong>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
@if ($license->isTerminated())
|
||||
<span class="text-danger">
|
||||
<x-icon type="warning" class="text-warning" />
|
||||
</span>
|
||||
@endif
|
||||
|
||||
{{ Helper::getFormattedDateObject($license->termination_date, 'date', false) }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -545,7 +556,7 @@
|
||||
|
||||
@can('checkout', $license)
|
||||
|
||||
@if ($license->availCount()->count() > 0)
|
||||
@if (($license->availCount()->count() > 0) && (!$license->isInactive()))
|
||||
|
||||
<a href="{{ route('licenses.checkout', $license->id) }}" class="btn bg-maroon btn-sm btn-social btn-block hidden-print" style="margin-bottom: 5px;">
|
||||
<x-icon type="checkout" />
|
||||
@@ -558,17 +569,13 @@
|
||||
</a>
|
||||
|
||||
@else
|
||||
<span data-tooltip="true" title=" {{ trans('admin/licenses/general.bulk.checkout_all.disabled_tooltip') }}">
|
||||
<a href="#" class="btn bg-maroon btn-sm btn-social btn-block hidden-print disabled" style="margin-bottom: 5px;" data-tooltip="true" title="{{ trans('general.checkout') }}">
|
||||
<span data-tooltip="true" title="{{ ($license->availCount()->count() == 0) ? trans('admin/licenses/general.bulk.checkout_all.disabled_tooltip') : trans('admin/licenses/message.checkout.license_is_inactive') }}" class="btn bg-maroon btn-sm btn-social btn-block hidden-print disabled" style="margin-bottom: 5px;" data-tooltip="true" title="{{ trans('general.checkout') }}">
|
||||
<x-icon type="checkout" />
|
||||
{{ trans('general.checkout') }}
|
||||
</a>
|
||||
</span>
|
||||
<span data-tooltip="true" title=" {{ trans('admin/licenses/general.bulk.checkout_all.disabled_tooltip') }}">
|
||||
<a href="#" class="btn bg-maroon btn-sm btn-social btn-block hidden-print disabled" style="margin-bottom: 5px;" data-tooltip="true" title="{{ trans('general.checkout') }}">
|
||||
<span data-tooltip="true" title="{{ ($license->availCount()->count() == 0) ? trans('admin/licenses/general.bulk.checkout_all.disabled_tooltip') : trans('admin/licenses/message.checkout.license_is_inactive') }}" class="btn bg-maroon btn-sm btn-social btn-block hidden-print disabled" style="margin-bottom: 5px;" data-tooltip="true" title="{{ trans('general.checkout') }}">
|
||||
<x-icon type="checkout" />
|
||||
{{ trans('admin/licenses/general.bulk.checkout_all.button') }}
|
||||
</a>
|
||||
</span>
|
||||
@endif
|
||||
@endcan
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
data-buttons="locationButtons"
|
||||
id="locationTable"
|
||||
class="table table-striped snipe-table"
|
||||
data-url="{{ route('api.locations.index', array('company_id'=>e(Request::get('company_id')))) }}"
|
||||
data-url="{{ route('api.locations.index', ['company_id'=>e(request('company_id')), 'status' => e(request('status'))]) }}"
|
||||
data-export-options='{
|
||||
"fileName": "export-locations-{{ date('Y-m-d') }}",
|
||||
"ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"]
|
||||
|
||||
@@ -49,107 +49,359 @@
|
||||
@endif
|
||||
@endif
|
||||
|
||||
<h2>{{ trans('general.assigned_to', array('name' => $location->display_name)) }}</h2>
|
||||
@if ($parent)
|
||||
{{ $parent->display_name }}
|
||||
<h2>
|
||||
@if ($assigned)
|
||||
{{ trans('general.assigned_to', array('name' => $location->display_name)) }}
|
||||
@else
|
||||
{{ trans('admin/locations/table.print_inventory') }} : {{ $location->display_name }}
|
||||
@endif
|
||||
</h2>
|
||||
@if ($location->parent)
|
||||
<strong>{{ trans('admin/locations/table.parent') }}:</strong> {{ $location->parent->display_name }}
|
||||
@endif
|
||||
<br>
|
||||
@if ($company)
|
||||
<b>{{ trans('admin/companies/table.name') }}:</b> {{ $company->display_name }}
|
||||
@if ($location->company)
|
||||
<b>{{ trans('admin/companies/table.name') }}:</b> {{ $location->company->display_name }}
|
||||
<br>
|
||||
@endif
|
||||
@if ($manager)
|
||||
<b>{{ trans('general.manager') }}</b> {{ $manager->display_name }}<br>
|
||||
@if ($location->manager)
|
||||
<b>{{ trans('admin/users/table.manager') }}:</b> {{ $location->manager->display_name }}<br>
|
||||
@endif
|
||||
<b>{{ trans('general.date') }}</b> {{ \App\Helpers\Helper::getFormattedDateObject(now(), 'datetime', false) }}<br><br>
|
||||
<b>{{ trans('general.date') }}:</b> {{ \App\Helpers\Helper::getFormattedDateObject(now(), 'datetime', false) }}<br><br>
|
||||
|
||||
@if ($users->count() > 0)
|
||||
@php
|
||||
$counter = 1;
|
||||
@endphp
|
||||
<table class="inventory">
|
||||
<thead>
|
||||
@php
|
||||
$counter = 1;
|
||||
@endphp
|
||||
<table class="inventory">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="6">{{ trans('general.users') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="6">{{ trans('general.users') }}</th>
|
||||
<th style="width: 5px;"></th>
|
||||
<th style="width: 25%;">{{ trans('general.company') }}</th>
|
||||
<th style="width: 25%;">{{ trans('admin/locations/table.user_name') }}</th>
|
||||
<th style="width: 10%;">{{ trans('general.employee_number') }}</th>
|
||||
<th style="width: 20%;">{{ trans('admin/locations/table.department') }}</th>
|
||||
<th style="width: 20%;">{{ trans('admin/locations/table.location') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 5px;"></th>
|
||||
<th style="width: 25%;">{{ trans('general.company') }}</th>
|
||||
<th style="width: 25%;">{{ trans('admin/locations/table.user_name') }}</th>
|
||||
<th style="width: 10%;">{{ trans('general.employee_number') }}</th>
|
||||
<th style="width: 20%;">{{ trans('admin/locations/table.department') }}</th>
|
||||
<th style="width: 20%;">{{ trans('admin/locations/table.location') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@foreach ($users as $user)
|
||||
</thead>
|
||||
@foreach ($users as $user)
|
||||
|
||||
<tr>
|
||||
<td>{{ $counter }}</td>
|
||||
<td>{{ (($user) && ($user->company)) ? $user->company->name : '' }}</td>
|
||||
<td>{{ ($user) ? $user->first_name .' '. $user->last_name : '' }}</td>
|
||||
<td>{{ ($user) ? $user->employee_num : '' }}</td>
|
||||
<td>{{ (($user) && ($user->department)) ? $user->department->name : '' }}</td>
|
||||
<td>{{ (($user) && ($user->location)) ? $user->location->name : '' }}</td>
|
||||
</tr>
|
||||
@php
|
||||
$counter++
|
||||
@endphp
|
||||
@endforeach
|
||||
</table>
|
||||
<tr>
|
||||
<td>{{ $counter }}</td>
|
||||
<td>{{ (($user) && ($user->company)) ? $user->company->name : '' }}</td>
|
||||
<td>{{ ($user) ? $user->first_name .' '. $user->last_name : '' }}</td>
|
||||
<td>{{ ($user) ? $user->employee_num : '' }}</td>
|
||||
<td>{{ (($user) && ($user->department)) ? $user->department->name : '' }}</td>
|
||||
<td>{{ (($user) && ($user->location)) ? $user->location->name : '' }}</td>
|
||||
</tr>
|
||||
@php
|
||||
$counter++
|
||||
@endphp
|
||||
@endforeach
|
||||
</table>
|
||||
@endif
|
||||
|
||||
|
||||
|
||||
@if ($assets->count() > 0)
|
||||
@if ($children->count() > 0)
|
||||
<br><br>
|
||||
<table class="inventory">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="10">{{ trans('general.assets') }}</th>
|
||||
<th colspan="10">{{ trans('general.child_locations') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 20px;"></th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_tag') }}</th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_name') }}</th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_category') }}</th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_manufacturer') }}</th>
|
||||
<th style="width: 15%;">{{ trans('admin/locations/table.asset_model') }}</th>
|
||||
<th style="width: 15%;">{{ trans('admin/locations/table.asset_serial') }}</th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_location') }}</th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_checked_out') }}</th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_expected_checkin') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@php
|
||||
$counter = 1;
|
||||
@endphp
|
||||
|
||||
@foreach ($assets as $asset)
|
||||
@php
|
||||
if($snipeSettings->show_archived_in_list != 1 && $asset->assetstatus?->archived == 1){
|
||||
continue;
|
||||
}
|
||||
@endphp
|
||||
<tr>
|
||||
<td>{{ $counter }}</td>
|
||||
<td>{{ $asset->asset_tag }}</td>
|
||||
<td>{{ $asset->name }}</td>
|
||||
<td>{{ (($asset->model) && ($asset->model->category)) ? $asset->model->category->name : '' }}</td>
|
||||
<td>{{ (($asset->model) && ($asset->model->manufacturer)) ? $asset->model->manufacturer->name : '' }}</td>
|
||||
<td>{{ ($asset->model) ? $asset->model->name : '' }}</td>
|
||||
<td>{{ $asset->serial }}</td>
|
||||
<td>{{ ($asset->location) ? $asset->location->name : '' }}</td>
|
||||
<td>{{ \App\Helpers\Helper::getFormattedDateObject( $asset->last_checkout, 'datetime', false) }}</td>
|
||||
<td>{{ \App\Helpers\Helper::getFormattedDateObject( $asset->expected_checkin, 'datetime', false) }}</td>
|
||||
<th style="width: 20px;"></th>
|
||||
<th>{{ trans('general.name') }}</th>
|
||||
<th>{{ trans('general.address') }}</th>
|
||||
<th>{{ trans('general.city') }}</th>
|
||||
<th>{{ trans('general.state') }}</th>
|
||||
<th>{{ trans('general.country') }}</th>
|
||||
<th>{{ trans('general.zip') }}</th>
|
||||
|
||||
</tr>
|
||||
</thead>
|
||||
@php
|
||||
$counter = 1;
|
||||
@endphp
|
||||
|
||||
@foreach ($children as $child)
|
||||
<tr>
|
||||
<td>{{ $counter }}</td>
|
||||
<td>{{ $child->name }}</td>
|
||||
<td>{{ $child->address }}</td>
|
||||
<td>{{ $child->city }}</td>
|
||||
<td>{{ $child->state }}</td>
|
||||
<td>{{ $child->country }}</td>
|
||||
<td>{{ $child->zip }}</td>
|
||||
</tr>
|
||||
@php
|
||||
$counter++
|
||||
@endphp
|
||||
@endforeach
|
||||
@endforeach
|
||||
</table>
|
||||
@endif
|
||||
|
||||
@if ($assets->count() > 0)
|
||||
<br><br>
|
||||
<table class="inventory">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="10">{{ trans('general.assets') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 20px;"></th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_tag') }}</th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_name') }}</th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_category') }}</th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_manufacturer') }}</th>
|
||||
<th style="width: 15%;">{{ trans('admin/locations/table.asset_model') }}</th>
|
||||
<th style="width: 15%;">{{ trans('admin/locations/table.asset_serial') }}</th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_location') }}</th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_checked_out') }}</th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_expected_checkin') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@php
|
||||
$counter = 1;
|
||||
@endphp
|
||||
|
||||
@foreach ($assets as $asset)
|
||||
@php
|
||||
if($snipeSettings->show_archived_in_list != 1 && $asset->assetstatus?->archived == 1){
|
||||
continue;
|
||||
}
|
||||
@endphp
|
||||
<tr>
|
||||
<td>{{ $counter }}</td>
|
||||
<td>{{ $asset->asset_tag }}</td>
|
||||
<td>{{ $asset->name }}</td>
|
||||
<td>{{ (($asset->model) && ($asset->model->category)) ? $asset->model->category->name : '' }}</td>
|
||||
<td>{{ (($asset->model) && ($asset->model->manufacturer)) ? $asset->model->manufacturer->name : '' }}</td>
|
||||
<td>{{ ($asset->model) ? $asset->model->name : '' }}</td>
|
||||
<td>{{ $asset->serial }}</td>
|
||||
<td>{{ ($asset->location) ? $asset->location->name : '' }}</td>
|
||||
<td>{{ \App\Helpers\Helper::getFormattedDateObject( $asset->last_checkout, 'datetime', false) }}</td>
|
||||
<td>{{ \App\Helpers\Helper::getFormattedDateObject( $asset->expected_checkin, 'datetime', false) }}</td>
|
||||
</tr>
|
||||
@php
|
||||
$counter++
|
||||
@endphp
|
||||
@endforeach
|
||||
</table>
|
||||
@endif
|
||||
|
||||
@if ($assigned)
|
||||
@if ($assignedAssets->count() > 0)
|
||||
<br><br>
|
||||
<table class="inventory">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="10">{{ trans('admin/locations/message.assigned_assets') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 20px;"></th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_tag') }}</th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_name') }}</th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_category') }}</th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_manufacturer') }}</th>
|
||||
<th style="width: 15%;">{{ trans('admin/locations/table.asset_model') }}</th>
|
||||
<th style="width: 15%;">{{ trans('admin/locations/table.asset_serial') }}</th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_location') }}</th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_checked_out') }}</th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_expected_checkin') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@php
|
||||
$counter = 1;
|
||||
@endphp
|
||||
|
||||
@foreach ($assignedAssets as $asset)
|
||||
@php
|
||||
if($snipeSettings->show_archived_in_list != 1 && $asset->assetstatus?->archived == 1){
|
||||
continue;
|
||||
}
|
||||
@endphp
|
||||
<tr>
|
||||
<td>{{ $counter }}</td>
|
||||
<td>{{ $asset->asset_tag }}</td>
|
||||
<td>{{ $asset->name }}</td>
|
||||
<td>{{ (($asset->model) && ($asset->model->category)) ? $asset->model->category->name : '' }}</td>
|
||||
<td>{{ (($asset->model) && ($asset->model->manufacturer)) ? $asset->model->manufacturer->name : '' }}</td>
|
||||
<td>{{ ($asset->model) ? $asset->model->name : '' }}</td>
|
||||
<td>{{ $asset->serial }}</td>
|
||||
<td>{{ ($asset->location) ? $asset->location->name : '' }}</td>
|
||||
<td>{{ \App\Helpers\Helper::getFormattedDateObject( $asset->last_checkout, 'datetime', false) }}</td>
|
||||
<td>{{ \App\Helpers\Helper::getFormattedDateObject( $asset->expected_checkin, 'datetime', false) }}</td>
|
||||
</tr>
|
||||
@php
|
||||
$counter++
|
||||
@endphp
|
||||
@endforeach
|
||||
</table>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
@if ($accessories->count() > 0)
|
||||
<br><br>
|
||||
<table class="inventory">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="10">{{ trans('general.accessories') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 20px;"></th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_name') }}</th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_category') }}</th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_manufacturer') }}</th>
|
||||
<th>{{ trans('admin/models/table.modelnumber') }}</th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_location') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@php
|
||||
$counter = 1;
|
||||
@endphp
|
||||
|
||||
@foreach ($accessories as $accessory)
|
||||
<tr>
|
||||
<td>{{ $counter }}</td>
|
||||
<td>{{ $accessory->name }}</td>
|
||||
<td>{{ ($accessory->category) ? $accessory->category->name : '' }}</td>
|
||||
<td>{{ ($accessory->manufacturer) ? $accessory->manufacturer->name : '' }}</td>
|
||||
<td>{{ $asset->model_number }}</td>
|
||||
<td>{{ ($asset->location) ? $asset->location->name : '' }}</td>
|
||||
</tr>
|
||||
@php
|
||||
$counter++
|
||||
@endphp
|
||||
@endforeach
|
||||
</table>
|
||||
@endif
|
||||
|
||||
@if ($assigned)
|
||||
@if ($assignedAccessories->count() > 0)
|
||||
<br><br>
|
||||
<table class="inventory">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="10">{{ trans('general.accessories_assigned') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 20px;"></th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_name') }}</th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_category') }}</th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_manufacturer') }}</th>
|
||||
<th>{{ trans('admin/models/table.modelnumber') }}</th>
|
||||
<th style="width: 10%;">{{ trans('admin/locations/table.asset_location') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@php
|
||||
$counter = 1;
|
||||
@endphp
|
||||
|
||||
@foreach ($assignedAccessories as $accessory)
|
||||
<tr>
|
||||
<td>{{ $counter }}</td>
|
||||
<td>{{ $accessory->name }}</td>
|
||||
<td>{{ ($accessory->category) ? $accessory->category->name : '' }}</td>
|
||||
<td>{{ ($accessory->manufacturer) ? $accessory->manufacturer->name : '' }}</td>
|
||||
<td>{{ $asset->model_number }}</td>
|
||||
<td>{{ ($asset->location) ? $asset->location->name : '' }}</td>
|
||||
</tr>
|
||||
@php
|
||||
$counter++
|
||||
@endphp
|
||||
@endforeach
|
||||
</table>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
@if ($consumables->count() > 0)
|
||||
<br><br>
|
||||
<table class="inventory">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="10">{{ trans('general.accessories') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 20px;"></th>
|
||||
<th>{{ trans('admin/locations/table.asset_name') }}</th>
|
||||
<th>{{ trans('general.qty') }}</th>
|
||||
<th>{{ trans('admin/locations/table.asset_category') }}</th>
|
||||
<th>{{ trans('admin/locations/table.asset_manufacturer') }}</th>
|
||||
<th>{{ trans('admin/models/table.modelnumber') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@php
|
||||
$counter = 1;
|
||||
@endphp
|
||||
|
||||
@foreach ($consumables as $consumable)
|
||||
<tr>
|
||||
<td>{{ $counter }}</td>
|
||||
<td>{{ $consumable->name }}</td>
|
||||
<td>{{ $consumable->qty }}</td>
|
||||
<td>{{ ($consumable->category) ? $consumable->category->name : '' }}</td>
|
||||
<td>{{ ($consumable->manufacturer) ? $consumable->manufacturer->name : '' }}</td>
|
||||
<td>{{ $consumable->model_number }}</td>
|
||||
</tr>
|
||||
@php
|
||||
$counter++
|
||||
@endphp
|
||||
@endforeach
|
||||
</table>
|
||||
@endif
|
||||
|
||||
@if ($components->count() > 0)
|
||||
<br><br>
|
||||
<table class="inventory">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="10">{{ trans('general.components') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 20px;"></th>
|
||||
<th>{{ trans('admin/locations/table.asset_name') }}</th>
|
||||
<th>{{ trans('general.qty') }}</th>
|
||||
<th>{{ trans('admin/locations/table.asset_category') }}</th>
|
||||
<th>{{ trans('admin/locations/table.asset_manufacturer') }}</th>
|
||||
<th>{{ trans('admin/models/table.modelnumber') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@php
|
||||
$counter = 1;
|
||||
@endphp
|
||||
|
||||
@foreach ($components as $component)
|
||||
<tr>
|
||||
<td>{{ $counter }}</td>
|
||||
<td>{{ $component->name }}</td>
|
||||
<td>{{ $component->qty }}</td>
|
||||
<td>{{ ($component->category) ? $component->category->name : '' }}</td>
|
||||
<td>{{ ($component->manufacturer) ? $component->manufacturer->name : '' }}</td>
|
||||
<td>{{ $component->model_number }}</td>
|
||||
</tr>
|
||||
@php
|
||||
$counter++
|
||||
@endphp
|
||||
@endforeach
|
||||
</table>
|
||||
@endif
|
||||
|
||||
@@ -157,26 +409,26 @@
|
||||
<br>
|
||||
<br>
|
||||
<table>
|
||||
<tr>
|
||||
<td>{{ trans('admin/locations/table.signed_by_asset_auditor') }}</td>
|
||||
<td><br>------------------------------------------------------ <br></td>
|
||||
<td>{{ trans('admin/locations/table.date') }}</td>
|
||||
<td><br>------------------------------ <br></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ trans('admin/locations/table.signed_by_asset_auditor') }}</td>
|
||||
<td><br>------------------------------------------------------ <br></td>
|
||||
<td>{{ trans('admin/locations/table.date') }}</td>
|
||||
<td><br>------------------------------ <br></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>{{ trans('admin/locations/table.signed_by_finance_auditor') }}</td>
|
||||
<td><br>------------------------------------------------------ <br></td>
|
||||
<td>{{ trans('admin/locations/table.date') }}</td>
|
||||
<td><br>------------------------------ <br></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ trans('admin/locations/table.signed_by_finance_auditor') }}</td>
|
||||
<td><br>------------------------------------------------------ <br></td>
|
||||
<td>{{ trans('admin/locations/table.date') }}</td>
|
||||
<td><br>------------------------------ <br></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>{{ trans('admin/locations/table.signed_by_location_manager') }}</td>
|
||||
<td><br>------------------------------------------------------ <br></td>
|
||||
<td>{{ trans('admin/locations/table.date') }}</td>
|
||||
<td><br>------------------------------ <br></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ trans('admin/locations/table.signed_by_location_manager') }}</td>
|
||||
<td><br>------------------------------------------------------ <br></td>
|
||||
<td>{{ trans('admin/locations/table.date') }}</td>
|
||||
<td><br>------------------------------ <br></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
@@ -17,8 +17,21 @@
|
||||
@section('content')
|
||||
|
||||
<div class="row">
|
||||
|
||||
@if ($location->deleted_at!='')
|
||||
<div class="col-md-12">
|
||||
<div class="callout callout-warning">
|
||||
<x-icon type="warning" />
|
||||
{{ trans('admin/locations/message.deleted_warning') }}
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<div class="col-md-9">
|
||||
|
||||
|
||||
|
||||
<div class="nav-tabs-custom">
|
||||
<ul class="nav nav-tabs hidden-print">
|
||||
|
||||
@@ -29,7 +42,7 @@
|
||||
<span class="sr-only">
|
||||
{{ trans('general.users') }}
|
||||
</span>
|
||||
{!! ($location->users->count() > 0) ? '<span class="badge">'.number_format($location->users->count()).'</span>' : '' !!}
|
||||
{!! ($location->users()->count() > 0) ? '<span class="badge">'.number_format($location->users()->count()).'</span>' : '' !!}
|
||||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
@@ -70,7 +83,7 @@
|
||||
<li>
|
||||
<a href="#accessories" data-toggle="tab" data-tooltip="true" title="{{ trans('general.accessories') }}">
|
||||
<i class="far fa-keyboard fa-fw" style="font-size: 17px" aria-hidden="true"></i>
|
||||
{!! ($location->accessories->count() > 0) ? '<span class="badge">'.number_format($location->accessories->count()).'</span>' : '' !!}
|
||||
{!! ($location->accessories()->count() > 0) ? '<span class="badge">'.number_format($location->accessories()->count()).'</span>' : '' !!}
|
||||
<span class="sr-only">
|
||||
{{ trans('general.accessories') }}
|
||||
</span>
|
||||
@@ -80,7 +93,7 @@
|
||||
<li>
|
||||
<a href="#accessories_assigned" data-toggle="tab" data-tooltip="true" title="{{ trans('general.accessories_assigned') }}">
|
||||
<i class="fas fa-keyboard fa-fw" style="font-size: 17px" aria-hidden="true"></i>
|
||||
{!! ($location->assignedAccessories->count() > 0) ? '<span class="badge">'.number_format($location->assignedAccessories->count()).'</span>' : '' !!}
|
||||
{!! ($location->assignedAccessories()->count() > 0) ? '<span class="badge">'.number_format($location->assignedAccessories()->count()).'</span>' : '' !!}
|
||||
<span class="sr-only">
|
||||
{{ trans('general.accessories_assigned') }}
|
||||
</span>
|
||||
@@ -93,7 +106,7 @@
|
||||
<li>
|
||||
<a href="#consumables" data-toggle="tab" data-tooltip="true" title="{{ trans('general.consumables') }}">
|
||||
<i class="fas fa-tint fa-fw" style="font-size: 17px" aria-hidden="true"></i>
|
||||
{!! ($location->consumables->count() > 0) ? '<span class="badge">'.number_format($location->consumables->count()).'</span>' : '' !!}
|
||||
{!! ($location->consumables()->count() > 0) ? '<span class="badge">'.number_format($location->consumables->count()).'</span>' : '' !!}
|
||||
<span class="sr-only">
|
||||
{{ trans('general.consumables') }}
|
||||
</span>
|
||||
@@ -105,7 +118,7 @@
|
||||
<li>
|
||||
<a href="#components" data-toggle="tab" data-tooltip="true" title="{{ trans('general.components') }}">
|
||||
<i class="fas fa-hdd fa-fw" style="font-size: 17px" aria-hidden="true"></i>
|
||||
{!! ($location->components->count() > 0) ? '<span class="badge">'.number_format($location->components->count()).'</span>' : '' !!}
|
||||
{!! ($location->components->count() > 0) ? '<span class="badge">'.number_format($location->components()->count()).'</span>' : '' !!}
|
||||
<span class="sr-only">
|
||||
{{ trans('general.components') }}
|
||||
</span>
|
||||
@@ -113,6 +126,18 @@
|
||||
</li>
|
||||
@endcan
|
||||
|
||||
<li>
|
||||
<a href="#child_locations" data-toggle="tab" data-tooltip="true" title="{{ trans('general.child_locations') }}">
|
||||
<span class="hidden-xs hidden-sm">
|
||||
<i class="fa-solid fa-city fa-fw" style="font-size: 17px" aria-hidden="true"></i>
|
||||
<span class="sr-only">
|
||||
{{ trans('general.child_locations') }}
|
||||
</span>
|
||||
{!! ($location->children()->count() > 0 ) ? '<span class="badge">'.number_format($location->children()->count()).'</span>' : '' !!}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#files" data-toggle="tab" data-tooltip="true" title="{{ trans('general.files') }}">
|
||||
|
||||
@@ -124,11 +149,15 @@
|
||||
<span class="sr-only">
|
||||
{{ trans('general.files') }}
|
||||
</span>
|
||||
{!! ($location->uploads->count() > 0 ) ? '<span class="badge">'.number_format($location->uploads->count()).'</span>' : '' !!}
|
||||
{!! ($location->uploads()->count() > 0 ) ? '<span class="badge">'.number_format($location->uploads()->count()).'</span>' : '' !!}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li>
|
||||
<a href="#history" data-toggle="tab" data-tooltip="true" title="{{ trans('general.history') }}">
|
||||
<i class="fa-solid fa-clock-rotate-left fa-fw" style="font-size: 17px" aria-hidden="true"></i>
|
||||
@@ -337,16 +366,65 @@
|
||||
</table>
|
||||
</div><!-- /.tab-pane -->
|
||||
|
||||
|
||||
<div class="tab-pane" id="child_locations">
|
||||
<h2 class="box-title">
|
||||
{{ trans('general.child_locations') }}
|
||||
</h2>
|
||||
<table
|
||||
role="table"
|
||||
data-columns="{{ \App\Presenters\LocationPresenter::dataTableLayout() }}"
|
||||
data-cookie-id-table="childrenListingTable"
|
||||
data-id-table="childrenListingTable"
|
||||
data-side-pagination="server"
|
||||
data-sort-order="asc"
|
||||
id="childrenListingTable"
|
||||
data-buttons="childrenListingTable"
|
||||
class="table table-striped snipe-table"
|
||||
data-url="{{route('api.locations.index', ['parent_id' => $location->id]) }}"
|
||||
data-export-options='{
|
||||
"fileName": "export-children-locations-{{ str_slug($location->name) }}-{{ date('Y-m-d') }}",
|
||||
"ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"]
|
||||
}'>
|
||||
</table>
|
||||
</div><!-- /.tab-pane -->
|
||||
|
||||
<div class="tab-pane fade" id="files">
|
||||
<h2 class="box-title">
|
||||
{{ trans('general.child_locations') }}
|
||||
</h2>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<x-filestable object_type="locations" :object="$location" />
|
||||
</div> <!-- /.col-md-12 -->
|
||||
</div> <!-- /.row -->
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="tab-pane" id="accessories_assigned">
|
||||
<h2 class="box-title" style="float:left">
|
||||
{{ trans('general.accessories_assigned') }}
|
||||
</h2>
|
||||
|
||||
<table
|
||||
role="table"
|
||||
data-columns="{{ \App\Presenters\LocationPresenter::assignedAccessoriesDataTableLayout() }}"
|
||||
data-cookie-id-table="accessoriesAssignedListingTable"
|
||||
data-id-table="accessoriesAssignedListingTable"
|
||||
data-side-pagination="server"
|
||||
data-sort-order="asc"
|
||||
id="accessoriesAssignedListingTable"
|
||||
data-buttons="accessoryButtons"
|
||||
class="table table-striped snipe-table"
|
||||
data-url="{{ route('api.locations.assigned_accessories', ['location' => $location]) }}"
|
||||
data-export-options='{
|
||||
"fileName": "export-locations-{{ str_slug($location->name) }}-accessories-{{ date('Y-m-d') }}",
|
||||
"ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"]
|
||||
}'>
|
||||
</table>
|
||||
</div><!-- /.tab-pane -->
|
||||
|
||||
<div class="tab-pane" id="history">
|
||||
<h2 class="box-title">{{ trans('general.history') }}</h2>
|
||||
<!-- checked out assets table -->
|
||||
@@ -411,16 +489,16 @@
|
||||
<li>{{ $location->city }} {{ $location->state }} {{ $location->zip }}</li>
|
||||
@endif
|
||||
@if ($location->manager)
|
||||
<li>{{ trans('admin/users/table.manager') }}: {!! $location->manager->present()->nameUrl() !!}</li>
|
||||
<li><strong>{{ trans('admin/users/table.manager') }}</strong>: {!! $location->manager->present()->nameUrl() !!}</li>
|
||||
@endif
|
||||
@if ($location->company)
|
||||
<li>{{ trans('admin/companies/table.name') }}: {!! $location->company->present()->nameUrl() !!}</li>
|
||||
<li><strong>{{ trans('admin/companies/table.name') }}</strong>: {!! $location->company->present()->nameUrl() !!}</li>
|
||||
@endif
|
||||
@if ($location->parent)
|
||||
<li>{{ trans('admin/locations/table.parent') }}: {!! $location->parent->present()->nameUrl() !!}</li>
|
||||
<li><strong>{{ trans('admin/locations/table.parent') }}</strong>: {!! $location->parent->present()->nameUrl() !!}</li>
|
||||
@endif
|
||||
@if ($location->ldap_ou)
|
||||
<li>{{ trans('admin/locations/table.ldap_ou') }}: {{ $location->ldap_ou }}</li>
|
||||
<li><strong>{{ trans('admin/locations/table.ldap_ou') }}</strong>: {{ $location->ldap_ou }}</li>
|
||||
@endif
|
||||
|
||||
|
||||
@@ -442,18 +520,28 @@
|
||||
</div>
|
||||
|
||||
@can('update', $location)
|
||||
<div class="col-md-12">
|
||||
<a href="{{ route('locations.edit', ['location' => $location->id]) }}" style="width: 100%;" class="btn btn-sm btn-warning btn-social">
|
||||
<x-icon type="edit" />
|
||||
{{ trans('admin/locations/table.update') }}
|
||||
</a>
|
||||
</div>
|
||||
@if ($location->deleted_at=='')
|
||||
<div class="col-md-12">
|
||||
<a href="{{ route('locations.edit', ['location' => $location->id]) }}" style="width: 100%;" class="btn btn-sm btn-warning btn-social">
|
||||
<x-icon type="edit" />
|
||||
{{ trans('admin/locations/table.update') }}
|
||||
</a>
|
||||
</div>
|
||||
@else
|
||||
<div class="col-md-12">
|
||||
<a style="width: 100%;" class="btn btn-sm btn-warning btn-social disabled">
|
||||
<x-icon type="edit" />
|
||||
{{ trans('admin/locations/table.update') }}
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
@endcan
|
||||
|
||||
@if ($location->deleted_at=='')
|
||||
<div class="col-md-12" style="padding-top: 5px;">
|
||||
<a href="{{ route('locations.print_assigned', ['locationId' => $location->id]) }}" style="width: 100%;" class="btn btn-sm btn-primary btn-social hidden-print">
|
||||
<x-icon type="print" />
|
||||
{{ trans('admin/locations/table.print_assigned') }}
|
||||
{{ trans('admin/locations/table.print_inventory') }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-12" style="padding-top: 5px;">
|
||||
@@ -462,6 +550,7 @@
|
||||
{{ trans('admin/locations/table.print_all_assigned') }}
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@can('delete', $location)
|
||||
<div class="col-md-12 hidden-print" style="padding-top: 10px;">
|
||||
@@ -474,16 +563,18 @@
|
||||
{{ trans('general.delete') }}
|
||||
</button>
|
||||
@else
|
||||
<a href="#" class="btn btn-block btn-sm btn-danger btn-social hidden-print disabled" data-tooltip="true" data-placement="top" data-title="{{ trans('general.cannot_be_deleted') }}">
|
||||
<span data-placement="top" data-tooltip="true" data-title="{{ trans('admin/locations/message.assoc_users') }}">
|
||||
<a href="#" class="btn btn-block btn-sm btn-danger btn-social hidden-print disabled" data-tooltip="true">
|
||||
<x-icon type="delete" />
|
||||
{{ trans('general.delete') }}
|
||||
</a>
|
||||
</span>
|
||||
@endif
|
||||
|
||||
@else
|
||||
<form method="POST" action="{{ route('locations.restore', ['location' => $location->id]) }}">
|
||||
@csrf
|
||||
<button class="btn btn-sm btn-block btn-warning btn-social delete-asset">
|
||||
<button class="btn btn-sm btn-block btn-warning btn-social">
|
||||
<x-icon type="restore" />
|
||||
{{ trans('general.restore') }}
|
||||
</button>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@component('mail::message')
|
||||
# {{ trans('mail.hello') }} {{ $target->assignedto->display_name }},
|
||||
|
||||
{{ trans('mail.new_item_checked') }}
|
||||
{{ trans_choice('mail.new_item_checked', $qty) }}
|
||||
|
||||
@component('mail::table')
|
||||
| | |
|
||||
@@ -47,4 +47,4 @@
|
||||
|
||||
{{ $snipeSettings->site_name }}
|
||||
|
||||
@endcomponent
|
||||
@endcomponent
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@component('mail::message')
|
||||
# {{ trans('mail.hello') }} {{ $target->display_name }},
|
||||
|
||||
{{ trans('mail.new_item_checked') }}
|
||||
{{ trans_choice('mail.new_item_checked', $qty) }}
|
||||
|
||||
|
||||
@component('mail::table')
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@component('mail::message')
|
||||
# {{ trans('mail.hello').' '.$target.','}}
|
||||
|
||||
{{ trans('mail.new_item_checked') }}
|
||||
{{ trans_choice('mail.new_item_checked', 1) }}
|
||||
|
||||
@component('mail::table')
|
||||
| | |
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
id="asssetModelsTable"
|
||||
data-buttons="modelButtons"
|
||||
class="table table-striped snipe-table"
|
||||
data-url="{{ route('api.models.index', ['status' => request('status')]) }}"
|
||||
data-url="{{ route('api.models.index', ['status' => e(request('status'))]) }}"
|
||||
data-export-options='{
|
||||
"fileName": "export-models-{{ date('Y-m-d') }}",
|
||||
"ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"]
|
||||
|
||||
@@ -37,6 +37,9 @@
|
||||
@if (isset($item_serial))
|
||||
| **{{ trans('mail.serial') }}** | {{ $item_serial }} |
|
||||
@endif
|
||||
@if (isset($qty))
|
||||
| **{{ trans('general.qty') }}** | {{ $qty }} |
|
||||
@endif
|
||||
@if (isset($admin))
|
||||
| **{{ trans('general.administrator') }}** | {{ $admin }} |
|
||||
@endif
|
||||
|
||||
@@ -1,25 +1,48 @@
|
||||
@component('mail::message')
|
||||
{{ trans_choice('mail.assets_warrantee_alert', $assets->count(), ['count'=>$assets->count(), 'threshold' => $threshold]) }}
|
||||
@component('mail::table')
|
||||
|
||||
@foreach ($assets as $asset)
|
||||
@php
|
||||
$expires = Helper::getFormattedDateObject($asset->present()->warranty_expires, 'date');
|
||||
$diff = round(abs(strtotime($asset->present()->warranty_expires) - strtotime(date('Y-m-d')))/86400);
|
||||
$icon = ($diff <= ($threshold / 2)) ? '🚨' : (($diff <= $threshold) ? '⚠️' : ' ');
|
||||
@endphp
|
||||
@component('mail::table')
|
||||
<style>
|
||||
|
||||
th, td {
|
||||
vertical-align: top;
|
||||
}
|
||||
hr {
|
||||
display: block;
|
||||
height: 1px;
|
||||
border: 0;
|
||||
border-top: 1px solid #ccc;
|
||||
margin: 1em 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
<x-mail::table>
|
||||
|
||||
| | | |
|
||||
| ------------- | ------------- | ------------- |
|
||||
@foreach ($assets as $asset)
|
||||
@php
|
||||
$warranty_expires = \App\Helpers\Helper::getFormattedDateObject($asset->present()->warranty_expires, 'date');
|
||||
$eol_date = \App\Helpers\Helper::getFormattedDateObject($asset->asset_eol_date, 'date');
|
||||
$warranty_diff = ($asset->present()->warranty_expires) ? round(\Carbon\Carbon::now()->diffInDays(\Carbon\Carbon::parse($warranty_expires['date']), false), 1) : '';
|
||||
$eol_diff = round(\Carbon\Carbon::now()->diffInDays(\Carbon\Carbon::parse($asset->asset_eol_date), false), 1);
|
||||
$icon = ($warranty_diff <= $threshold && $warranty_diff >= 0) ? '⚠️' : (($eol_diff <= $threshold && $eol_diff >= 0) ? '🚨' : 'ℹ️');
|
||||
@endphp
|
||||
| {{ $icon }} **{{ trans('mail.name') }}** | <a href="{{ route('hardware.show', $asset->id) }}">{{ $asset->display_name }}</a> <br><small>{{trans('mail.serial').': '.$asset->serial}}</small> |
|
||||
| **{{ trans('mail.expires') }}** | {{ !is_null($expires) ? $expires['formatted'] : '' }} (<strong>{{ $diff }} {{ trans('mail.Days') }}</strong>) |
|
||||
@if ($warranty_expires)
|
||||
| **{{ trans('mail.expires') }}** | {{ !is_null($warranty_expires) ? $warranty_expires['formatted'] : '' }} (<strong>{{ $warranty_diff }} {{ trans('mail.Days') }}</strong>) |
|
||||
@endif
|
||||
@if ($eol_date)
|
||||
| **{{ trans('mail.eol') }}** | {{ !is_null($eol_date) ? $eol_date['formatted'] : '' }} (<strong>{{ $eol_diff }} {{ trans('mail.Days') }}</strong>) |
|
||||
@endif
|
||||
@if ($asset->supplier)
|
||||
| **{{ trans('mail.supplier') }}** | {{ ($asset->supplier ? e($asset->supplier->name) : '') }} |
|
||||
@endif
|
||||
@if ($asset->assignedTo)
|
||||
| **{{ trans('mail.assigned_to') }}** | {{ e($asset->assignedTo->present()->display_name) }} |
|
||||
@endif
|
||||
@endcomponent
|
||||
| <hr> | <hr> |
|
||||
@endforeach
|
||||
</x-mail::table>
|
||||
|
||||
@endcomponent
|
||||
@endcomponent
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
## {{ $assets->count() }} {{ trans('general.assets') }}
|
||||
|
||||
<table width="100%">
|
||||
<tr><th align="left">{{ trans('mail.name') }} </th><th align="left">{{ trans('mail.asset_tag') }}</th><th align="left">{{ trans('admin/hardware/table.serial') }}</th><th align="left">{{ trans('general.category') }}</th> <th></th> </tr>
|
||||
<tr><th align="left">{{ trans('mail.name') }} </th><th align="left">{{ trans('mail.asset_tag') }}</th><th align="left">{{ trans('admin/hardware/table.serial') }}</th><th align="left">{{ trans('general.category') }}</th><th align="left">{{ trans('admin/hardware/table.location') }}</th> <th></th> </tr>
|
||||
|
||||
|
||||
@foreach($assets as $asset)
|
||||
@@ -18,6 +18,7 @@
|
||||
<td> {{ $asset->asset_tag }} </td>
|
||||
<td> {{ $asset->serial }} </td>
|
||||
<td> {{ $asset->model->category->name }}</td>
|
||||
<td> {{ ($asset->location) ? $asset->location->name : '' }} </td>
|
||||
@if (($snipeSettings->show_images_in_email =='1') && $asset->getImageUrl())
|
||||
<td>
|
||||
<img src="{{ asset($asset->getImageUrl()) }}" alt="Asset" style="max-width: 64px;">
|
||||
|
||||
@@ -556,21 +556,40 @@
|
||||
}
|
||||
}
|
||||
|
||||
function licenseInOutFormatter(value, row) {
|
||||
|
||||
// check that checkin is not disabled
|
||||
if (row.user_can_checkout === false) {
|
||||
return '<span class="btn btn-sm bg-maroon disabled" data-tooltip="true" title="{{ trans('admin/licenses/message.checkout.unavailable') }}">{{ trans('general.checkout') }}</span>';
|
||||
} else if (row.disabled === true) {
|
||||
return '<span class="btn btn-sm bg-maroon disabled" data-tooltip="true" title="{{ trans('admin/licenses/message.checkout.license_is_inactive') }}">{{ trans('general.checkout') }}</span>';
|
||||
|
||||
} else
|
||||
// The user is allowed to check the license seat out and it's available
|
||||
if ((row.available_actions.checkout === true) && (row.user_can_checkout === true) && (row.disabled === false)) {
|
||||
return '<a href="{{ config('app.url') }}/licenses/' + row.id + '/checkout/" class="btn btn-sm bg-maroon" data-tooltip="true" title="{{ trans('general.checkout_tooltip') }}">{{ trans('general.checkout') }}</a>';
|
||||
}
|
||||
}
|
||||
// We need a special formatter for license seats, since they don't work exactly the same
|
||||
// Checkouts need the license ID, checkins need the specific seat ID
|
||||
|
||||
function licenseSeatInOutFormatter(value, row) {
|
||||
if(row.disabled) {
|
||||
if (row.disabled && (row.assigned_user || row.assigned_asset)) {
|
||||
return '<a href="{{ config('app.url') }}/licenses/' + row.id + '/checkin" class="btn btn-sm bg-purple" data-tooltip="true" title="{{ trans('general.checkin_tooltip') }}">{{ trans('general.checkin') }}</a>';
|
||||
}
|
||||
if (row.disabled) {
|
||||
return '<a href="{{ config('app.url') }}/licenses/' + row.id + '/checkin" class="btn btn-sm bg-maroon disabled" data-tooltip="true" title="{{ trans('general.checkin_tooltip') }}">{{ trans('general.checkout') }}</a>';
|
||||
} else
|
||||
}
|
||||
// The user is allowed to check the license seat out and it's available
|
||||
if ((row.available_actions.checkout === true) && (row.user_can_checkout === true) && ((!row.asset_id) && (!row.assigned_to))) {
|
||||
if ((row.available_actions.checkout === true) && (row.user_can_checkout === true) && ((!row.assigned_asset) && (!row.assigned_user))) {
|
||||
return '<a href="{{ config('app.url') }}/licenses/' + row.license_id + '/checkout/'+row.id+'" class="btn btn-sm bg-maroon" data-tooltip="true" title="{{ trans('general.checkout_tooltip') }}">{{ trans('general.checkout') }}</a>';
|
||||
}
|
||||
else {
|
||||
return '<a href="{{ config('app.url') }}/licenses/' + row.id + '/checkin" class="btn btn-sm bg-purple" data-tooltip="true" title="{{ trans('general.checkin_tooltip') }}">{{ trans('general.checkin') }}</a>';
|
||||
}
|
||||
|
||||
// The user is allowed to check the license seat in and it's available
|
||||
if ((row.available_actions.checkin === true) && ((row.assigned_asset) || (row.assigned_user))) {
|
||||
return '<a href="{{ config('app.url') }}/licenses/' + row.id + '/checkin/" class="btn btn-sm bg-purple" data-tooltip="true" title="{{ trans('general.checkin_tooltip') }}">{{ trans('general.checkin') }}</a>';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function genericCheckinCheckoutFormatter(destination) {
|
||||
@@ -1256,6 +1275,7 @@
|
||||
},
|
||||
attributes: {
|
||||
title: '{{ trans('general.create') }}',
|
||||
class: 'btn btn-primary',
|
||||
@if ($snipeSettings->shortcuts_enabled == 1)
|
||||
accesskey: 'n'
|
||||
@endif
|
||||
@@ -1288,7 +1308,7 @@
|
||||
|
||||
btnShowDeleted: {
|
||||
text: '{{ (request()->input('status') == "deleted") ?trans('admin/users/table.show_current') : trans('admin/users/table.show_deleted') }}',
|
||||
icon: 'fa-solid fa-user-slash {{ (request()->input('status') == "deleted") ? ' text-danger' : ' fa-user-slash' }}',
|
||||
icon: 'fa-solid fa-trash {{ (request()->input('status') == "deleted") ? ' text-danger' : ' fa-user-trash' }}',
|
||||
event () {
|
||||
window.location.href = '{{ (request()->input('status') == "deleted") ? route('users.index') : route('users.index', ['status' => 'deleted']) }}';
|
||||
},
|
||||
@@ -1311,6 +1331,7 @@
|
||||
window.location.href = '{{ route('companies.create') }}';
|
||||
},
|
||||
attributes: {
|
||||
class: 'btn btn-primary',
|
||||
title: '{{ trans('general.create') }}',
|
||||
@if ($snipeSettings->shortcuts_enabled == 1)
|
||||
accesskey: 'n'
|
||||
@@ -1333,6 +1354,7 @@
|
||||
},
|
||||
attributes: {
|
||||
title: '{{ trans('general.create') }}',
|
||||
class: 'btn btn-primary',
|
||||
@if ($snipeSettings->shortcuts_enabled == 1)
|
||||
accesskey: 'n'
|
||||
@endif
|
||||
@@ -1388,12 +1410,25 @@
|
||||
window.location.href = '{{ route('locations.create') }}';
|
||||
},
|
||||
attributes: {
|
||||
class: 'btn btn-primary',
|
||||
title: '{{ trans('general.create') }}',
|
||||
@if ($snipeSettings->shortcuts_enabled == 1)
|
||||
accesskey: 'n'
|
||||
@endif
|
||||
}
|
||||
},
|
||||
|
||||
btnShowDeleted: {
|
||||
text: '{{ (request()->input('status') == "deleted") ? trans('admin/users/table.show_current') : trans('admin/users/table.show_deleted') }}',
|
||||
icon: 'fa-solid fa-trash {{ (request()->input('status') == "deleted") ? ' text-danger' : ' fa-user-trash' }}',
|
||||
event () {
|
||||
window.location.href = '{{ (request()->input('status') == "deleted") ? route('locations.index') : route('locations.index', ['status' => 'deleted']) }}';
|
||||
},
|
||||
attributes: {
|
||||
title: '{{ (request()->input('status') == "deleted") ? trans('admin/users/table.show_current') : trans('admin/users/table.show_deleted') }}',
|
||||
|
||||
}
|
||||
},
|
||||
});
|
||||
@endcan
|
||||
|
||||
@@ -1407,6 +1442,7 @@
|
||||
window.location.href = '{{ route('accessories.create') }}';
|
||||
},
|
||||
attributes: {
|
||||
class: 'btn btn-primary',
|
||||
title: '{{ trans('general.create') }}',
|
||||
@if ($snipeSettings->shortcuts_enabled == 1)
|
||||
accesskey: 'n'
|
||||
@@ -1426,6 +1462,7 @@
|
||||
window.location.href = '{{ route('depreciations.create') }}';
|
||||
},
|
||||
attributes: {
|
||||
class: 'btn btn-primary',
|
||||
title: '{{ trans('general.create') }}',
|
||||
@if ($snipeSettings->shortcuts_enabled == 1)
|
||||
accesskey: 'n'
|
||||
@@ -1445,6 +1482,7 @@
|
||||
window.location.href = '{{ route('fields.create') }}';
|
||||
},
|
||||
attributes: {
|
||||
class: 'btn btn-primary',
|
||||
title: '{{ trans('general.create') }}',
|
||||
@if ($snipeSettings->shortcuts_enabled == 1)
|
||||
accesskey: 'n'
|
||||
@@ -1465,6 +1503,7 @@
|
||||
window.location.href = '{{ route('fieldsets.create') }}';
|
||||
},
|
||||
attributes: {
|
||||
class: 'btn btn-primary',
|
||||
title: '{{ trans('general.create') }}',
|
||||
@if ($snipeSettings->shortcuts_enabled == 1)
|
||||
accesskey: 'n'
|
||||
@@ -1484,6 +1523,7 @@
|
||||
window.location.href = '{{ route('components.create') }}';
|
||||
},
|
||||
attributes: {
|
||||
class: 'btn btn-primary',
|
||||
title: '{{ trans('general.create') }}',
|
||||
@if ($snipeSettings->shortcuts_enabled == 1)
|
||||
accesskey: 'n'
|
||||
@@ -1503,6 +1543,7 @@
|
||||
window.location.href = '{{ route('consumables.create') }}';
|
||||
},
|
||||
attributes: {
|
||||
class: 'btn btn-primary',
|
||||
title: '{{ trans('general.create') }}',
|
||||
@if ($snipeSettings->shortcuts_enabled == 1)
|
||||
accesskey: 'n'
|
||||
@@ -1522,6 +1563,7 @@
|
||||
window.location.href = '{{ route('manufacturers.create') }}';
|
||||
},
|
||||
attributes: {
|
||||
class: 'btn btn-primary',
|
||||
title: '{{ trans('general.create') }}',
|
||||
@if ($snipeSettings->shortcuts_enabled == 1)
|
||||
accesskey: 'n'
|
||||
@@ -1553,6 +1595,7 @@
|
||||
window.location.href = '{{ route('suppliers.create') }}';
|
||||
},
|
||||
attributes: {
|
||||
class: 'btn btn-primary',
|
||||
title: '{{ trans('general.create') }}',
|
||||
@if ($snipeSettings->shortcuts_enabled == 1)
|
||||
accesskey: 'n'
|
||||
@@ -1572,6 +1615,7 @@
|
||||
window.location.href = '{{ route('licenses.create') }}';
|
||||
},
|
||||
attributes: {
|
||||
class: 'btn btn-primary',
|
||||
title: '{{ trans('general.create') }}',
|
||||
@if ($snipeSettings->shortcuts_enabled == 1)
|
||||
accesskey: 'n'
|
||||
@@ -1591,6 +1635,7 @@
|
||||
window.location.href = '{{ route('departments.create') }}';
|
||||
},
|
||||
attributes: {
|
||||
class: 'btn btn-primary',
|
||||
title: '{{ trans('general.create') }}',
|
||||
@if ($snipeSettings->shortcuts_enabled == 1)
|
||||
accesskey: 'n'
|
||||
@@ -1610,6 +1655,7 @@
|
||||
window.location.href = '{{ route('departments.create') }}';
|
||||
},
|
||||
attributes: {
|
||||
class: 'btn btn-primary',
|
||||
title: '{{ trans('general.create') }}',
|
||||
@if ($snipeSettings->shortcuts_enabled == 1)
|
||||
accesskey: 'n'
|
||||
@@ -1629,6 +1675,7 @@
|
||||
window.location.href = '{{ route('maintenances.create', ['asset_id' => (isset($asset)) ? $asset->id :'' ]) }}';
|
||||
},
|
||||
attributes: {
|
||||
class: 'btn btn-primary',
|
||||
title: '{{ trans('general.create') }}',
|
||||
@if ($snipeSettings->shortcuts_enabled == 1)
|
||||
accesskey: 'n'
|
||||
@@ -1648,6 +1695,7 @@
|
||||
window.location.href = '{{ route('categories.create') }}';
|
||||
},
|
||||
attributes: {
|
||||
class: 'btn btn-primary',
|
||||
title: '{{ trans('general.create') }}',
|
||||
@if ($snipeSettings->shortcuts_enabled == 1)
|
||||
accesskey: 'n'
|
||||
@@ -1667,6 +1715,7 @@
|
||||
window.location.href = '{{ route('models.create') }}';
|
||||
},
|
||||
attributes: {
|
||||
class: 'btn btn-primary',
|
||||
title: '{{ trans('general.create') }}',
|
||||
@if ($snipeSettings->shortcuts_enabled == 1)
|
||||
accesskey: 'n'
|
||||
@@ -1680,7 +1729,7 @@
|
||||
window.location.href = '{{ (request()->input('status') == "deleted") ? route('models.index') : route('models.index', ['status' => 'deleted']) }}';
|
||||
},
|
||||
attributes: {
|
||||
title: '{{ (request()->input('status') == "Deleted") ? trans('general.list_all') : trans('general.deleted') }}',
|
||||
title: '{{ (request()->input('status') == "deleted") ? trans('general.list_all') : trans('general.deleted') }}',
|
||||
|
||||
}
|
||||
},
|
||||
@@ -1697,6 +1746,7 @@
|
||||
window.location.href = '{{ route('statuslabels.create') }}';
|
||||
},
|
||||
attributes: {
|
||||
class: 'btn btn-primary',
|
||||
title: '{{ trans('general.create') }}',
|
||||
@if ($snipeSettings->shortcuts_enabled == 1)
|
||||
accesskey: 'n'
|
||||
@@ -1717,6 +1767,7 @@
|
||||
window.location.href = '{{ route('licenses.create') }}';
|
||||
},
|
||||
attributes: {
|
||||
class: 'btn btn-primary',
|
||||
title: '{{ trans('general.create') }}',
|
||||
@if ($snipeSettings->shortcuts_enabled == 1)
|
||||
accesskey: 'n'
|
||||
@@ -1734,7 +1785,19 @@
|
||||
attributes: {
|
||||
title: '{{ trans('general.export') }}'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
btnShowInactive: {
|
||||
text: '{{ (request()->input('status') == "inactive") ? trans('general.list_all') : trans('general.show_inactive') }}',
|
||||
icon: 'fas fa-clock {{ (request()->input('status') == "inactive") ? ' text-danger' : '' }}',
|
||||
event () {
|
||||
window.location.href = '{{ (request()->input('status') == "inactive") ? route('licenses.index') : route('licenses.index', ['status' => 'inactive']) }}';
|
||||
},
|
||||
attributes: {
|
||||
title: '{{ (request()->input('status') == "inactive") ? trans('general.list_all') : trans('general.show_inactive') }}',
|
||||
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!-- Purchase Cost -->
|
||||
<div class="form-group {{ $errors->has('purchase_cost') ? ' has-error' : '' }}">
|
||||
<label for="purchase_cost" class="col-md-3 control-label">{{ trans('general.purchase_cost') }}</label>
|
||||
<label for="purchase_cost" class="col-md-3 control-label">{{ $unit_cost ?? trans('general.purchase_cost') }}</label>
|
||||
<div class="col-md-9">
|
||||
<div class="input-group col-md-5" style="padding-left: 0px;">
|
||||
<input class="form-control" type="number" name="purchase_cost" min="0.00" max="99999999999999999.000" step="0.001" aria-label="purchase_cost" id="purchase_cost" value="{{ old('purchase_cost', $item->purchase_cost) }}" maxlength="25" />
|
||||
|
||||
@@ -897,7 +897,7 @@
|
||||
</td>
|
||||
<td class="hidden-print col-md-2">
|
||||
@can('update', $license)
|
||||
<a href="{{ route('licenses.checkin', $license->pivot->id, ['backto'=>'user']) }}" class="btn btn-primary btn-sm hidden-print">{{ trans('general.checkin') }}</a>
|
||||
<a href="{{ route('licenses.checkin', $license->pivot->id, ['backto'=>'user']) }}" class="btn bg-purple btn-sm hidden-print">{{ trans('general.checkin') }}</a>
|
||||
@endcan
|
||||
</td>
|
||||
</tr>
|
||||
@@ -927,7 +927,7 @@
|
||||
<th>{{ trans('general.name') }}</th>
|
||||
<th>{{ trans('general.date') }}</th>
|
||||
<th data-fieldname="note">{{ trans('general.notes') }}</th>
|
||||
<th data-footer-formatter="sumFormatter" data-fieldname="purchase_cost">{{ trans('general.purchase_cost') }}</th>
|
||||
<th data-footer-formatter="sumFormatter" data-fieldname="purchase_cost">{{ trans('general.unit_cost') }}</th>
|
||||
<th class="hidden-print">{{ trans('general.action') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -971,7 +971,7 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col-md-3">{{ trans('general.name') }}</th>
|
||||
<th class="col-md-2" data-footer-formatter="sumFormatter" data-fieldname="purchase_cost">{{ trans('general.purchase_cost') }}</th>
|
||||
<th class="col-md-2" data-footer-formatter="sumFormatter" data-fieldname="purchase_cost">{{ trans('general.unit_cost') }}</th>
|
||||
<th class="col-md-2">{{ trans('general.date') }}</th>
|
||||
<th class="col-md-5">{{ trans('general.notes') }}</th>
|
||||
</tr>
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Assets\Api;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\Company;
|
||||
use App\Models\User;
|
||||
use Illuminate\Testing\Fluent\AssertableJson;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AssignedAssetsTest extends TestCase
|
||||
{
|
||||
public function test_requires_permission()
|
||||
{
|
||||
$this->actingAsForApi(User::factory()->create())
|
||||
->getJson(route('api.assets.assigned_assets', Asset::factory()->create()))
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function test_adheres_to_company_scoping()
|
||||
{
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
[$companyA, $companyB] = Company::factory()->count(2)->create();
|
||||
|
||||
$asset = Asset::factory()->for($companyA)->create();
|
||||
|
||||
$user = User::factory()->for($companyB)->viewAssets()->create();
|
||||
|
||||
$this->actingAsForApi($user)
|
||||
->getJson(route('api.assets.assigned_assets', $asset))
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('error')
|
||||
->assertMessagesAre('Asset not found');
|
||||
}
|
||||
|
||||
public function test_can_get_assets_assigned_to_specific_asset()
|
||||
{
|
||||
$unassociatedAsset = Asset::factory()->create();
|
||||
|
||||
$asset = Asset::factory()->hasAssignedAssets(2)->create();
|
||||
|
||||
$assetsAssignedToAsset = Asset::where([
|
||||
'assigned_to' => $asset->id,
|
||||
'assigned_type' => Asset::class,
|
||||
])->get();
|
||||
|
||||
$this->actingAsForApi(User::factory()->viewAssets()->create())
|
||||
->getJson(route('api.assets.assigned_assets', $asset))
|
||||
->assertOk()
|
||||
->assertResponseContainsInRows($assetsAssignedToAsset, 'serial')
|
||||
->assertResponseDoesNotContainInRows($unassociatedAsset, 'serial')
|
||||
->assertJson(function (AssertableJson $json) {
|
||||
$json->where('total', 2)
|
||||
->count('rows', 2)
|
||||
->etc();
|
||||
});
|
||||
}
|
||||
|
||||
public function test_adheres_to_offset_and_limit()
|
||||
{
|
||||
$asset = Asset::factory()->hasAssignedAssets(2)->create();
|
||||
|
||||
$assetsAssignedToAsset = Asset::where([
|
||||
'assigned_to' => $asset->id,
|
||||
'assigned_type' => Asset::class,
|
||||
])->get();
|
||||
|
||||
$this->actingAsForApi(User::factory()->viewAssets()->create())
|
||||
->getJson(route('api.assets.assigned_assets', [
|
||||
'asset' => $asset,
|
||||
'offset' => 1,
|
||||
'limit' => 1,
|
||||
]))
|
||||
->assertOk()
|
||||
->assertResponseDoesNotContainInRows($assetsAssignedToAsset->first(), 'serial')
|
||||
->assertResponseContainsInRows($assetsAssignedToAsset->last(), 'serial')
|
||||
->assertJson(function (AssertableJson $json) {
|
||||
$json->where('total', 2)
|
||||
->count('rows', 1)
|
||||
->etc();
|
||||
});
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user