Compare commits

...

225 Commits

Author SHA1 Message Date
snipe 85486fa58c Merge remote-tracking branch 'origin/develop' 2024-08-15 10:53:54 +01:00
snipe 10dc1f1368 Re-pull the accessory checkout
Signed-off-by: snipe <snipe@snipe.net>
2024-08-15 10:51:49 +01:00
snipe 3618df2ec5 Merge remote-tracking branch 'origin/develop' 2024-08-15 10:44:39 +01:00
snipe 8f7bce7aad Re-added UI for checkout to non-users for accessories
Signed-off-by: snipe <snipe@snipe.net>
2024-08-15 10:44:27 +01:00
snipe a201f22fdb Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2024-08-15 10:36:12 +01:00
snipe 6070d530cf Merge remote-tracking branch 'origin/develop' 2024-08-15 10:35:33 +01:00
snipe 4d66f7c93f Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2024-08-15 10:35:02 +01:00
snipe 6c0cf94473 Merge remote-tracking branch 'origin/develop' 2024-08-15 10:28:08 +01:00
snipe 381003eeab Cleaned up asset tag field on quickscan checkin
Signed-off-by: snipe <snipe@snipe.net>
2024-08-15 10:27:31 +01:00
snipe c3d4c821f3 Merge pull request #15303 from snipe/features/#15301_optional_status_to_quickscan_checkin
Fixed #15301 - Added optional status to quickscan checkin
2024-08-15 10:26:04 +01:00
snipe d8038ac483 Removed status label list
Signed-off-by: snipe <snipe@snipe.net>
2024-08-15 10:17:08 +01:00
snipe d268f25f16 Make asset tag required
Signed-off-by: snipe <snipe@snipe.net>
2024-08-15 10:16:57 +01:00
snipe 01c69c8f8f Allow optional status label on quickscan checkin
Signed-off-by: snipe <snipe@snipe.net>
2024-08-15 10:08:48 +01:00
snipe 3e29457094 Merge pull request #15292 from snipe/features/updated_phpinsights
Updated phpinsights
2024-08-14 12:12:40 +01:00
snipe 0b3ac2a9cd Updated phpinsights
Signed-off-by: snipe <snipe@snipe.net>
2024-08-14 12:08:49 +01:00
snipe bf4b915168 Merge remote-tracking branch 'origin/develop' 2024-08-14 10:45:13 +01:00
snipe 0f1e5181a6 Nicer input layout for bulk edit name
Signed-off-by: snipe <snipe@snipe.net>
2024-08-14 10:09:14 +01:00
snipe 0a9c2e354f Merge remote-tracking branch 'origin/develop' 2024-08-14 10:02:43 +01:00
snipe e544007185 Merge pull request #15291 from snipe/features/bulk_update_asset_name
Added asset name to bulk asset edit
2024-08-14 10:02:09 +01:00
snipe 4b690e8e1f Updated test to check for nulling
Signed-off-by: snipe <snipe@snipe.net>
2024-08-14 10:01:56 +01:00
snipe 371afde52d Bulk edit asset name
Signed-off-by: snipe <snipe@snipe.net>
2024-08-14 09:52:25 +01:00
snipe 7a6a2e3d92 Merge pull request #15290 from marcusmoore/test-fixes
Fixed component check in test
2024-08-14 00:00:55 +01:00
Marcus Moore 3f8ac59f4c Reference the entry in the components_assets table 2024-08-13 15:31:16 -07:00
snipe 74e7b1cfa5 Merge pull request #15286 from marcusmoore/test-updates
Implemented artisan test case
2024-08-13 20:46:46 +01:00
Marcus Moore ae0a6d66f3 Update tests
https://masteringlaravel.io/daily/2024-02-09-watch-out-for-this-when-testing-artisan-commands
2024-08-13 12:16:08 -07:00
Marcus Moore 321839e074 Fix namespace 2024-08-13 12:14:56 -07:00
snipe e9fc455a30 Merge pull request #15192 from Godmartinz/status_labels_check_emails
Added status labels to confirmation emails
2024-08-13 18:24:15 +01:00
Godfrey M 8af4126de1 removed indent from blades 2024-08-13 10:21:33 -07:00
snipe 47f1b3b14e Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/mix-manifest.json
2024-08-13 16:48:06 +01:00
snipe 3044af9410 Merge pull request #15280 from snipe/bug/sc-23294
Fixed select2 “x” color on multi-select and border color
2024-08-13 16:46:56 +01:00
snipe 4f0f0af83b Make the border radius match the rest of the site
Signed-off-by: snipe <snipe@snipe.net>
2024-08-13 16:46:26 +01:00
snipe 198afee946 Fixed select2 “x” color on mult-select and border color
Signed-off-by: snipe <snipe@snipe.net>
2024-08-13 16:42:23 +01:00
snipe def0af652d Merge pull request #15279 from TelecomsSansFrontieres/fix_missing-translate-item-assets
Fix: add missing admin/hardware/table.name key
2024-08-13 16:35:25 +01:00
Florent Bervas 20e4ba0590 lang: relocated translation key to existing item in general 2024-08-13 15:07:54 +00:00
snipe 72fd9977e5 Merge pull request #15277 from uberbrady/silence_saml_errors
Fixed: [sc-26355] Attempt to de-escalate SAML login and logout errors
2024-08-13 15:51:03 +01:00
Brady Wetherington 10f35c682b Re-add space 2024-08-13 15:49:51 +01:00
snipe 198b76ebc2 Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	public/css/build/app.css
#	public/css/build/overrides.css
#	public/css/dist/all.css
#	public/mix-manifest.json
2024-08-13 15:47:00 +01:00
snipe 6e84c29ce4 Merge pull request #15278 from snipe/print_view_improvements
Fixed #14821 - Hide UI elements from print view on assets
2024-08-13 15:45:30 +01:00
snipe 389a06aac5 Hide UI elements from print view on assets
Signed-off-by: snipe <snipe@snipe.net>
2024-08-13 15:40:51 +01:00
Brady Wetherington 4b96721393 Attempt to de-escalate SAML login and logout errors 2024-08-13 14:55:13 +01:00
snipe e42ee0c0e1 Merge pull request #15276 from snipe/css_updates
Bold selected tab for better readability
2024-08-13 14:21:45 +01:00
snipe 277a0fd16a Make selected tab bold
Signed-off-by: snipe <snipe@snipe.net>
2024-08-13 14:19:41 +01:00
snipe c163d6774f Merge pull request #15198 from spencerrlongg/feature/add_trait_to_request
Add MayContainCustomFields Trait to Asset Update Request
2024-08-13 14:12:52 +01:00
snipe 5546f9676a Merge remote-tracking branch 'origin/develop' 2024-08-13 13:51:33 +01:00
snipe 9e73eaf955 Merge pull request #15275 from snipe/added_tooltips_to_top_bar
Added tooltips to top nav shortcuts
2024-08-13 13:50:27 +01:00
snipe 1b2094f4e2 Added tooltips to top nav shortcuts
Signed-off-by: snipe <snipe@snipe.net>
2024-08-13 13:49:13 +01:00
snipe 46caa478d2 Merge remote-tracking branch 'origin/develop' 2024-08-12 20:47:45 +01:00
snipe e6106aa7cf Merge pull request #15272 from snipe/fixes/added_selectlist_permission_for_reports
Added reporting-only access for selectlists
2024-08-12 20:47:17 +01:00
snipe b45a8f4b5f Added reporting-only access for selectlists
Signed-off-by: snipe <snipe@snipe.net>
2024-08-12 20:44:17 +01:00
snipe 4d8569e754 Merge remote-tracking branch 'origin/develop' 2024-08-12 18:01:21 +01:00
snipe c9f8a84d48 Merge pull request #15270 from snipe/fixes/make_dashboard_pie_respect_show_in_list
Fixed #15247 - make pie chart on dashboard respect the “show archived…
2024-08-12 17:59:27 +01:00
snipe ac1543d568 Fixed #15247 - make pie chart on dashboard respect the “show archived” setting
Signed-off-by: snipe <snipe@snipe.net>
2024-08-12 17:54:42 +01:00
snipe 4dc57f95e2 Merge remote-tracking branch 'origin/develop' 2024-08-12 16:38:23 +01:00
snipe 9d354ca657 Merge pull request #15266 from uberbrady/checkout_to_fixer
Checkout-to fixer
2024-08-12 16:34:19 +01:00
snipe 316ee6f810 Merge remote-tracking branch 'origin/develop' 2024-08-12 16:30:53 +01:00
snipe 3f2139349e Allow better fallthrough on image
Signed-off-by: snipe <snipe@snipe.net>
2024-08-12 16:30:21 +01:00
snipe f56dd582f9 Merge pull request #15269 from snipe/fixes/smaller_email_logo
Fixes ##15236 - smaller email logo
2024-08-12 16:27:59 +01:00
snipe 225ab47b8e Simplified logic
Signed-off-by: snipe <snipe@snipe.net>
2024-08-12 16:23:09 +01:00
snipe 4c350bd5a3 Remove the regular logo fallback, make image capped by height
Signed-off-by: snipe <snipe@snipe.net>
2024-08-12 16:21:58 +01:00
snipe 509cc812ea Merge remote-tracking branch 'origin/develop' 2024-08-12 15:58:40 +01:00
snipe e7fb29fced Fixed copy area for serial
Signed-off-by: snipe <snipe@snipe.net>
2024-08-12 15:58:30 +01:00
Brady Wetherington a2d11b43de Whoops, these were accidentally committed 2024-08-12 13:50:46 +01:00
Brady Wetherington f80cf666b1 Mark tests as incomplete for the new artisan assigned_to fixer 2024-08-12 13:46:56 +01:00
snipe d5f66bc0dd Merge remote-tracking branch 'origin/develop' 2024-08-12 10:10:59 +01:00
snipe ce5be8ac24 Merge pull request #15100 from Godmartinz/depreciation_percentage
Added Depreciation Percentage as an option
2024-08-12 10:10:25 +01:00
snipe 1e213c31ef Merge remote-tracking branch 'origin/develop' 2024-08-11 10:26:16 +01:00
snipe 1777bb4b93 Pulled searchable relation on model - needs revisit
Signed-off-by: snipe <snipe@snipe.net>
2024-08-11 10:26:02 +01:00
snipe 91874dfe0b Merge remote-tracking branch 'origin/develop' 2024-08-10 19:37:37 +01:00
snipe 5c6c655cdc Added sounds to quickscan checkin
Signed-off-by: snipe <snipe@snipe.net>
2024-08-10 19:37:18 +01:00
snipe 0e6eda5e8a Merge remote-tracking branch 'origin/develop' 2024-08-10 18:29:41 +01:00
snipe 60eb602156 Merge pull request #15264 from snipe/fixes/fixed_admin_ordering_on_report
Fixed #15252 - admin ordering on activity report
2024-08-10 18:26:15 +01:00
snipe 24560b9362 Updated prod assets
Signed-off-by: snipe <snipe@snipe.net>
2024-08-10 18:24:49 +01:00
snipe 76b114d820 Added test
Signed-off-by: snipe <snipe@snipe.net>
2024-08-10 18:21:41 +01:00
snipe ce33deed86 Remove unused use statement
Signed-off-by: snipe <snipe@snipe.net>
2024-08-10 17:14:34 +01:00
snipe 1e6c172f18 Removed unusued use statement
Signed-off-by: snipe <snipe@snipe.net>
2024-08-10 17:14:20 +01:00
snipe a1ce9b9285 Added query scope for ordering by admin
Signed-off-by: snipe <snipe@snipe.net>
2024-08-10 17:00:50 +01:00
snipe 6ec3693030 Load admin on actionlog
Signed-off-by: snipe <snipe@snipe.net>
2024-08-10 17:00:34 +01:00
snipe 71729f0b16 Load admin and model on assets
Signed-off-by: snipe <snipe@snipe.net>
2024-08-10 17:00:20 +01:00
snipe 1c229a8e08 Made notes field sortable
Signed-off-by: snipe <snipe@snipe.net>
2024-08-10 17:00:11 +01:00
snipe 07b1e3fb90 Fixed tests
Signed-off-by: snipe <snipe@snipe.net>
2024-08-10 16:55:48 +01:00
snipe 6294516271 Merge pull request #15263 from snipe/really/remove_pound_sign_for_order_number
Fixed #15248 Removed pound symbol from order number on asset view
2024-08-10 16:18:40 +01:00
snipe f3331b5045 Removed pound symbol from order number on asset view
Signed-off-by: snipe <snipe@snipe.net>
2024-08-10 16:17:07 +01:00
snipe 6a06a91fa2 Merge pull request #15262 from snipe/synk/jquery-validation-from-1.20.1-to-1.21.0
Upgrade jquery-validation from 1.20.1 to 1.21.0
2024-08-10 16:07:47 +01:00
snipe 0cba5ba67e Upgrade jquery-validation from 1.20.1 to 1.21.0
Signed-off-by: snipe <snipe@snipe.net>
2024-08-10 16:06:14 +01:00
snipe b815352a45 Merge pull request #15261 from snipe/security/upgrade_fontawesome
[Snyk] Upgrade @fortawesome/fontawesome-free from 6.5.2 to 6.6.0
2024-08-10 15:57:10 +01:00
snipe 2f299dbb20 Upgrade fontawesome, generate dev assets
Signed-off-by: snipe <snipe@snipe.net>
2024-08-10 15:51:24 +01:00
snipe f76fbe75e0 Merge pull request #15221 from marcusmoore/fixes/bulk-checkin-logging
Fixed accessories and consumables not being logged correctly during bulk check-in
2024-08-08 10:43:59 +01:00
snipe cc1e356c35 Merge pull request #15232 from marcusmoore/shift-126036
Updated PHPUnit to v10
2024-08-08 01:23:07 +01:00
snipe 8094f3c0e1 Merge pull request #15245 from spencerrlongg/bug/acceptance_issue
Fixed Issue with Acceptances Being Created
2024-08-08 01:22:34 +01:00
snipe 900beaa955 Merge pull request #15244 from snipe/features/play_sound_on_audit
Fixes #10560 - optional ability to play sound on audit
2024-08-08 00:58:30 +01:00
spencerrlongg 2412333152 added conditional to listener 2024-08-07 16:53:06 -05:00
Marcus Moore 4a2d2f7336 Improve variable name 2024-08-07 13:32:30 -07:00
Marcus Moore d03baa4613 Make diff cleaner 2024-08-07 13:29:45 -07:00
Marcus Moore 41437e4d8f Merge branch 'develop' into fixes/bulk-checkin-logging
# Conflicts:
#	app/Http/Controllers/Users/BulkUsersController.php
2024-08-07 13:06:59 -07:00
snipe 7d220dd8c2 set default
Signed-off-by: snipe <snipe@snipe.net>
2024-08-07 20:58:04 +01:00
snipe a99ec062e6 Added checkbox for preferences
Signed-off-by: snipe <snipe@snipe.net>
2024-08-07 20:49:07 +01:00
snipe 8fe6395287 Added migration
Signed-off-by: snipe <snipe@snipe.net>
2024-08-07 20:41:13 +01:00
snipe b4d51599ee Added sound effects
Signed-off-by: snipe <snipe@snipe.net>
2024-08-07 20:38:50 +01:00
snipe 9350a20189 Include accessories count
This isn’t exactly right right now

Signed-off-by: snipe <snipe@snipe.net>
2024-08-07 20:19:47 +01:00
snipe 889d5da71e Check for accessories on bulk items
Signed-off-by: snipe <snipe@snipe.net>
2024-08-07 20:04:32 +01:00
snipe 5546ab08c2 Only delete user records in accessories_checkouts for bulk delete
Signed-off-by: snipe <snipe@snipe.net>
2024-08-07 19:53:18 +01:00
snipe ef183f256c Merge pull request #15242 from Godmartinz/shortcut_option
Fixed shortcuts to be optional now
2024-08-07 18:56:27 +01:00
Godfrey M 3a96e501cc use old school input 2024-08-07 10:54:06 -07:00
Godfrey M 6b1784f2ee makes shortcuts optional 2024-08-07 10:47:16 -07:00
snipe 1a872b1643 Merge remote-tracking branch 'origin/develop' 2024-08-07 18:15:44 +01:00
snipe deef9ad181 Merge pull request #15241 from snipe/partial_revert_for_checkout_accessories_to_non_user
Partial revert for checkout accessories to non user
2024-08-07 18:15:08 +01:00
snipe 0dc7e8b8dc Temp removed other selector
Signed-off-by: snipe <snipe@snipe.net>
2024-08-07 18:04:52 +01:00
snipe a5f075548a Default to user
Signed-off-by: snipe <snipe@snipe.net>
2024-08-07 18:04:39 +01:00
Brady Wetherington 1706ddd511 working fixup script, but failing tests. But I have tests! 2024-08-07 16:06:00 +01:00
Marcus Moore a220986d16 Switch to snake case 2024-08-06 16:13:51 -07:00
Marcus Moore 2a8ac81eed Fix namespace 2024-08-06 15:22:13 -07:00
Marcus Moore d3cb3c03d2 Rerun composer update using php 8.1 2024-08-06 15:01:01 -07:00
Marcus Moore c60bc5cdbe Change indents back to 2 2024-08-06 13:51:44 -07:00
Marcus Moore 6cfbf835c7 Migrate phpunit.xml
vendor/bin/phpunit --migrate-configuration
2024-08-06 13:37:53 -07:00
Marcus Moore 047b77e038 Composer update for phpunit, collision, and paratest
composer update phpunit/phpunit nunomaduro/collision brianium/paratest --with-all-dependencies
2024-08-06 13:34:51 -07:00
snipe 766b370264 Merge pull request #15229 from marcusmoore/bug/sc-26552
Disallowed checking out components to different companies and fixed number remaining counts
2024-08-06 21:33:55 +01:00
snipe da33277234 Merge pull request #15230 from marcusmoore/fixes/test-namespaces
Fixed handful of test namespaces
2024-08-06 21:32:11 +01:00
Marcus Moore 3e832e5e94 Revert "Define test classes as final"
This reverts commit 95516b0343.
2024-08-06 13:31:17 -07:00
Marcus Moore 82e795b642 Revert "Add return types to test methods"
This reverts commit 83fb6826ee.
2024-08-06 13:30:34 -07:00
Shift 95516b0343 Define test classes as final 2024-08-06 20:25:22 +00:00
Shift 83fb6826ee Add return types to test methods 2024-08-06 20:25:22 +00:00
Shift b1e92ab866 Declare data providers as static 2024-08-06 20:25:21 +00:00
Shift 96241cb67c Adopt PHP attributes in test classes 2024-08-06 20:25:21 +00:00
Shift b680dab5c9 Ignore PHPUnit cache folder 2024-08-06 20:25:19 +00:00
Shift 984840dc82 Bump PHPUnit dependencies 2024-08-06 20:25:18 +00:00
Marcus Moore 84e447af09 Fix test namespaces 2024-08-06 13:21:36 -07:00
Marcus Moore c7ddabcc8b Check for FMCS when checking out component 2024-08-06 12:27:15 -07:00
Marcus Moore bee80fcf8a Remove global scope when counting check outs 2024-08-06 12:16:06 -07:00
Marcus Moore 0aff35b622 Scaffold additional failed tests 2024-08-06 12:07:34 -07:00
Godfrey M 46a6a84ecb adds migration and translations 2024-08-06 11:07:39 -07:00
Marcus Moore 374812f8fe Add failing test 2024-08-06 10:48:38 -07:00
Marcus Moore 94e00b8a3e Use new accessory checkout relationship 2024-08-05 17:26:11 -07:00
Marcus Moore f2b78d18a4 Merge branch 'develop' into fixes/bulk-checkin-logging
# Conflicts:
#	app/Http/Controllers/Users/BulkUsersController.php
2024-08-05 17:25:54 -07:00
Marcus Moore 17eccfcd8b Formatting 2024-08-05 16:58:27 -07:00
Marcus Moore 01e4382d20 Formatting 2024-08-05 16:58:17 -07:00
Marcus Moore 1c664af326 Remove todo outside of scope 2024-08-05 16:58:08 -07:00
Marcus Moore 392d34422a Remove code handled by ConsumableAssignment:: call above 2024-08-05 16:57:40 -07:00
Marcus Moore 35e7a3163c Implement test case 2024-08-05 16:54:31 -07:00
Marcus Moore 96fafa6952 Improve readability 2024-08-05 16:36:29 -07:00
Marcus Moore a55693211f Move test class 2024-08-05 16:27:04 -07:00
Marcus Moore 1acd24fdbe Re-order helpers 2024-08-05 16:26:25 -07:00
Marcus Moore 59b7d5db4b Remove comment 2024-08-05 16:25:14 -07:00
Marcus Moore 16aa47509b Implement test for assets 2024-08-05 16:24:52 -07:00
Marcus Moore d1bb3ef6bf Scaffold two tests 2024-08-05 16:19:09 -07:00
Marcus Moore 5cd9dd4a67 Add assertion to ensure user cannot perform bulk actions on self 2024-08-05 16:17:24 -07:00
Marcus Moore fc405d9d73 Assert redirected to correct place 2024-08-05 16:14:01 -07:00
Marcus Moore 5786ff5035 Add assertion for success message 2024-08-05 16:11:07 -07:00
Marcus Moore 8a206a6d92 Add assertion 2024-08-05 16:10:12 -07:00
Marcus Moore 67b3ab820f Add todo comments 2024-08-05 16:10:08 -07:00
Marcus Moore b06501dd02 Add assertions 2024-08-05 16:02:59 -07:00
Marcus Moore e3049fffd4 Remove comment 2024-08-05 15:50:53 -07:00
Marcus Moore 5ecdb7e07c Add validation test 2024-08-05 15:50:09 -07:00
Marcus Moore 4ed3347f52 Add permission check 2024-08-05 15:43:38 -07:00
Marcus Moore 364775dcfe Improve readability 2024-08-05 15:42:03 -07:00
Marcus Moore bfebcdc7ed Improve variable name 2024-08-05 15:22:35 -07:00
Marcus Moore 480e4f3a69 Improve readability 2024-08-05 15:16:40 -07:00
Marcus Moore 78a0417ee9 Add another user into the mix 2024-08-05 15:11:18 -07:00
snipe b83d148b37 Merge pull request #15217 from TelecomsSansFrontieres/feature_extend-search-by-tag
Feature: Extend search capabilities to other assets attributes
2024-08-05 15:38:51 +01:00
Florent Bervas ad794248fe add a warning message if asset tag not found 2024-08-05 13:54:33 +00:00
Florent Bervas b804791ff6 feature: extend search capabilities to other assets attributes 2024-08-05 12:26:29 +00:00
snipe c45bf870b7 Merge pull request #15211 from snipe/feaures/15205_copy_asset_tag
Fixed #15205 - adds copy to asset tag
2024-08-02 20:59:53 +01:00
snipe a0bd8b6049 Fixed #15205 - adds copy to asset tag
Signed-off-by: snipe <snipe@snipe.net>
2024-08-02 20:56:31 +01:00
Godfrey M ae4f278df1 edited terenaries on notifs 2024-08-01 11:13:20 -07:00
snipe 28abb8d8cc Hotfix for 405 update asset
Signed-off-by: snipe <snipe@snipe.net>
2024-08-01 12:30:35 +01:00
snipe 24d948a3f6 Merge pull request #15204 from snipe/fixes/405_on_api_asset_update
Fixed (temp) put route
2024-08-01 12:28:23 +01:00
snipe c1c9c3554e Fixed (temp) put route
Signed-off-by: snipe <snipe@snipe.net>
2024-08-01 12:27:02 +01:00
snipe fcea564afa Fixed button label
Signed-off-by: snipe <snipe@snipe.net>
2024-07-31 21:44:27 +01:00
snipe f44abd0b28 Fixed button label
Signed-off-by: snipe <snipe@snipe.net>
2024-07-31 21:43:09 +01:00
Godfrey M 854903805b one more spot 2024-07-31 12:16:41 -07:00
Godfrey M 868f117b67 Merge branch 'status_labels_check_emails' of github.com:Godmartinz/snipe-it into status_labels_check_emails 2024-07-31 12:03:56 -07:00
Godfrey M b6cac4baae corrects ? usage 2024-07-31 12:03:36 -07:00
snipe 4fcb3df1d9 Merge pull request #15199 from Godmartinz/fix-signature-pad
adds closing brackets to signature pad
2024-07-31 19:23:33 +01:00
Godfrey M b60e22bcb4 adds closing brackets to signature pad 2024-07-31 11:10:33 -07:00
spencerrlongg 61312c2eec oops, mysql 2024-07-31 12:07:50 -05:00
spencerrlongg b0063b1d4a test written 2024-07-31 11:57:35 -05:00
akemidx fffcbdc44d Merge remote-tracking branch 'upstream/develop' into upstream/dev 2024-07-31 07:14:06 -04:00
akemidx 8d1fa362f7 restoring code 2024-07-31 07:13:42 -04:00
snipe 31a2765b30 Merge pull request #15145 from Godmartinz/purge-storage
Added user storage files to purge command
2024-07-31 10:16:08 +01:00
snipe e79a5b7efe Merge pull request #15193 from Godmartinz/admin-settings
Fixed admin boxes alignment
2024-07-31 08:54:44 +01:00
snipe ca531e85f3 Merge pull request #15194 from spencerrlongg/bug/sc-26247
Fixed A Translation Issue With Auth
2024-07-31 08:54:09 +01:00
spencerrlongg 0941c0944a ok, found issue, but need to test some things now... 2024-07-30 22:55:15 -05:00
spencerrlongg 9b80843c77 tests a little broken, added some nullchecks 2024-07-30 21:44:22 -05:00
spencerrlongg 8684a3efc3 delete note, add trait to other request 2024-07-30 21:22:46 -05:00
akemidx fccfce2ae8 first thought 2024-07-30 19:27:37 -04:00
Godfrey M 935d2ce29a fixes admin box alignment 2024-07-30 15:05:09 -07:00
spencerrlongg 437ddc01b4 removed extraneous $request->validate() arguments 2024-07-30 16:26:24 -05:00
Godfrey Martinez f19e58b352 Merge pull request #21 from Godmartinz/status_labels_check_emails_checkout
adds Status labels to check in and out emails
2024-07-30 09:41:05 -07:00
Godfrey M eb6f330e67 adds status to check in and out 2024-07-30 09:38:39 -07:00
Godfrey M f19899543d changed error to info 2024-07-30 09:18:17 -07:00
snipe 3a2611f8e1 Merge pull request #14565 from spencerrlongg/bug/sc-23936
Checks that custom fields exist before saving
2024-07-30 11:36:55 +01:00
Godfrey M 53ad312700 added missing closing bracket 2024-07-29 15:17:32 -07:00
Godfrey M 89d375daad add indents 2024-07-29 15:15:41 -07:00
Godfrey M d46f9776fe remove text 2024-07-29 15:14:58 -07:00
Godfrey M f9a47c8a9f adds a try catch 2024-07-29 15:12:48 -07:00
Godfrey M e395ee1878 adds a try catch 2024-07-29 15:12:32 -07:00
snipe 4971c54b05 Fixed seeder
Signed-off-by: snipe <snipe@snipe.net>
2024-07-29 20:17:25 +01:00
snipe 4c5b82ae37 Merge pull request #15188 from Godmartinz/1d_barcode_select_bug
Fixed 1d barcode targeting.
2024-07-29 20:00:21 +01:00
Spencer Long fd7082c30f Merge branch 'develop' into bug/sc-23936 2024-07-29 14:00:00 -05:00
snipe 8d0b72293f Merge branch 'develop' of https://github.com/snipe/snipe-it into develop 2024-07-29 18:51:19 +01:00
snipe f3d98f90c0 Add @arne-kroeger as a contributor 2024-07-29 18:51:12 +01:00
snipe 4eccb5ffc6 Merge pull request #15185 from arne-kroeger/feat/accesspories-checkout-to-location-or-asset
Added #14979: add checkout to location and assets functionality to accessories
2024-07-29 18:50:48 +01:00
Godfrey M 86049624c7 retargeted new label engine to correct 1d column 2024-07-29 10:42:26 -07:00
arne-kroeger 3c3b922eae Adjusted newly added tests to new checkout form 2024-07-29 19:15:01 +02:00
arne-kroeger e8d0147075 Adjusted missing down on migration and code smells 2024-07-29 19:04:10 +02:00
arne-kroeger 3a0b03348e added additional tests 2024-07-29 11:06:36 +02:00
arne-kroeger b18baf74d2 added options to checkout accessoires to locations and assets
Added #14979: add checkout functionality to accessoires
2024-07-29 10:54:53 +02:00
Marcus Moore 44dbbeb608 Add accessory and consumable specific checkin methods 2024-07-24 14:17:49 -07:00
Marcus Moore 7161b6416e Add failing test for accessories and consumables checkin 2024-07-24 14:16:42 -07:00
Godfrey Martinez c96ccbb6cb Merge branch 'develop' into depreciation_percentage 2024-07-24 12:12:28 -07:00
Godfrey M 950fff31ed fix conflicts 2024-07-24 12:12:04 -07:00
Godfrey M f05d8281f3 fixes alignment for error msg 2024-07-24 12:06:56 -07:00
Godfrey M d5c9fa823e adds translations 2024-07-24 11:39:33 -07:00
Godfrey M 99741db645 adds status labels to confirmation emails 2024-07-24 11:24:30 -07:00
Godfrey M d01972bbe5 adds tests for amount and percent 2024-07-23 11:53:59 -07:00
Godfrey M 750015684d purges user storage files 2024-07-23 10:42:50 -07:00
Godfrey M baa7e7d561 clean up 2024-07-16 20:27:38 -07:00
Godfrey M ffaacc04ef cleaned up calculateDepreciation method 2024-07-16 20:24:18 -07:00
Godfrey M 5bb47e290f validates percentage on store and new depreciations 2024-07-16 13:07:12 -07:00
Godfrey M 48821f8391 updates transformer, api controller 2024-07-16 12:58:23 -07:00
Godfrey M aaa2858337 battling with handling depreciation percentage and amount 2024-07-16 12:25:19 -07:00
spencerrlongg 99d7155729 translation strings 2024-04-07 19:50:53 -05:00
spencerrlongg f30439a544 small refactor, pretty much good to go now though 2024-04-07 17:07:46 -05:00
spencerrlongg 997eddfed1 cleanup + notes for monday 2024-04-04 18:23:03 -05:00
spencerrlongg 52340aca78 just about wrapped up 2024-04-04 17:41:10 -05:00
spencerrlongg e1fb446888 this is a pretty good start, need to know about other PR 2024-04-04 14:20:03 -05:00
139 changed files with 2481 additions and 1020 deletions
+9
View File
@@ -3172,6 +3172,15 @@
"contributions": [
"code"
]
},
{
"login": "arne-kroeger",
"name": "arne-kroeger",
"avatar_url": "https://avatars.githubusercontent.com/u/65785975?v=4",
"profile": "https://github.com/arne-kroeger",
"contributions": [
"code"
]
}
]
}
+2
View File
@@ -68,3 +68,5 @@ _ide_helper_models.php
storage/ldap_client_tls.cert
storage/ldap_client_tls.key
/storage/framework/testing
/.phpunit.cache
+1 -1
View File
@@ -51,7 +51,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
| [<img src="https://avatars.githubusercontent.com/u/111287779?v=4" width="110px;"/><br /><sub>NojoudAlshehri</sub>](https://github.com/NojoudAlshehri)<br />[💻](https://github.com/snipe/snipe-it/commits?author=NojoudAlshehri "Code") | [<img src="https://avatars.githubusercontent.com/u/54367449?v=4" width="110px;"/><br /><sub>Stefan Stidl</sub>](https://github.com/stefanstidlffg)<br />[💻](https://github.com/snipe/snipe-it/commits?author=stefanstidlffg "Code") | [<img src="https://avatars.githubusercontent.com/u/87803479?v=4" width="110px;"/><br /><sub>Quentin Aymard</sub>](https://github.com/qay21)<br />[💻](https://github.com/snipe/snipe-it/commits?author=qay21 "Code") | [<img src="https://avatars.githubusercontent.com/u/5396871?v=4" width="110px;"/><br /><sub>Grant Le Roux</sub>](https://github.com/cram42)<br />[💻](https://github.com/snipe/snipe-it/commits?author=cram42 "Code") | [<img src="https://avatars.githubusercontent.com/u/58479551?v=4" width="110px;"/><br /><sub>Bogdan</sub>](http://@singrity)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Singrity "Code") | [<img src="https://avatars.githubusercontent.com/u/3483684?v=4" width="110px;"/><br /><sub>mmanjos</sub>](https://github.com/mmanjos)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mmanjos "Code") | [<img src="https://avatars.githubusercontent.com/u/7429229?v=4" width="110px;"/><br /><sub>Abdelaziz Faki</sub>](https://azooz2014.github.io/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Azooz2014 "Code") |
| [<img src="https://avatars.githubusercontent.com/u/47315739?v=4" width="110px;"/><br /><sub>bilias</sub>](https://github.com/bilias)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bilias "Code") | [<img src="https://avatars.githubusercontent.com/u/2565989?v=4" width="110px;"/><br /><sub>coach1988</sub>](https://github.com/coach1988)<br />[💻](https://github.com/snipe/snipe-it/commits?author=coach1988 "Code") | [<img src="https://avatars.githubusercontent.com/u/11910225?v=4" width="110px;"/><br /><sub>MrM</sub>](https://github.com/mauro-miatello)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mauro-miatello "Code") | [<img src="https://avatars.githubusercontent.com/u/60405354?v=4" width="110px;"/><br /><sub>koiakoia</sub>](https://github.com/koiakoia)<br />[💻](https://github.com/snipe/snipe-it/commits?author=koiakoia "Code") | [<img src="https://avatars.githubusercontent.com/u/5323832?v=4" width="110px;"/><br /><sub>Mustafa Online</sub>](https://github.com/mustafa-online)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mustafa-online "Code") | [<img src="https://avatars.githubusercontent.com/u/104601439?v=4" width="110px;"/><br /><sub>franceslui</sub>](https://github.com/franceslui)<br />[💻](https://github.com/snipe/snipe-it/commits?author=franceslui "Code") | [<img src="https://avatars.githubusercontent.com/u/125313163?v=4" width="110px;"/><br /><sub>Q4kK</sub>](https://github.com/Q4kK)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Q4kK "Code") |
| [<img src="https://avatars.githubusercontent.com/u/55590532?v=4" width="110px;"/><br /><sub>squintfox</sub>](https://github.com/squintfox)<br />[💻](https://github.com/snipe/snipe-it/commits?author=squintfox "Code") | [<img src="https://avatars.githubusercontent.com/u/1380084?v=4" width="110px;"/><br /><sub>Jeff Clay</sub>](https://github.com/jeffclay)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jeffclay "Code") | [<img src="https://avatars.githubusercontent.com/u/52716446?v=4" width="110px;"/><br /><sub>Phil J R</sub>](https://github.com/PP-JN-RL)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PP-JN-RL "Code") | [<img src="https://avatars.githubusercontent.com/u/1496725?v=4" width="110px;"/><br /><sub>i_virus</sub>](https://www.corelight.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chandanchowdhury "Code") | [<img src="https://avatars.githubusercontent.com/u/1020541?v=4" width="110px;"/><br /><sub>Paul Grime</sub>](https://github.com/gitgrimbo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gitgrimbo "Code") | [<img src="https://avatars.githubusercontent.com/u/922815?v=4" width="110px;"/><br /><sub>Lee Porte</sub>](https://leeporte.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=LeePorte "Code") | [<img src="https://avatars.githubusercontent.com/u/23613427?v=4" width="110px;"/><br /><sub>BRYAN </sub>](https://github.com/bryanlopezinc)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Code") [⚠️](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Tests") |
| [<img src="https://avatars.githubusercontent.com/u/64061710?v=4" width="110px;"/><br /><sub>U-H-T</sub>](https://github.com/U-H-T)<br />[💻](https://github.com/snipe/snipe-it/commits?author=U-H-T "Code") | [<img src="https://avatars.githubusercontent.com/u/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/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") |
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
@@ -0,0 +1,66 @@
<?php
namespace App\Console\Commands;
use App\Models\Asset;
use Illuminate\Console\Command;
class FixupAssignedToWithoutAssignedType extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:assigned-to-fixup
{--debug : Display debugging output}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Fixes up assets that have an assigned_to but no assigned_type';
/**
* Execute the console command.
*/
public function handle()
{
$assets = Asset::whereNull("assigned_type")->whereNotNull("assigned_to")->withTrashed();
$this->withProgressBar($assets->get(), function (Asset $asset) {
//now check each action log, from the most recent backwards, to find the last checkin or checkout
foreach($asset->log()->orderBy("id","desc")->get() as $action_log) {
if($this->option("debug")) {
$this->info("Asset id: " . $asset->id . " action log, action type is: " . $action_log->action_type);
}
switch($action_log->action_type) {
case 'checkin from':
if($this->option("debug")) {
$this->info("Doing a checkin for ".$asset->id);
}
$asset->assigned_to = null;
// if you have a required custom field, we still want to save, and we *don't* want an action_log
$asset->saveQuietly();
return;
case 'checkout':
if($this->option("debug")) {
$this->info("Doing a checkout for " . $asset->id . " picking target type: " . $action_log->target_type);
}
if($asset->assigned_to != $action_log->target_id) {
$this->error("Asset's assigned_to does *NOT* match Action Log's target_id. \$asset->assigned_to=".$asset->assigned_to." vs. \$action_log->target_id=".$action_log->target_id);
//FIXME - do we abort here? Do we try to keep looking? I don't know, this means your data is *really* messed up...
}
$asset->assigned_type = $action_log->target_type;
$asset->saveQuietly(); // see above
return;
}
}
$asset->assigned_to = null; //asset was never checked in or out in its lifetime - it stays 'checked in'
$asset->saveQuietly(); //see above
});
$this->newLine();
$this->info("Assets assigned_type are fixed");
}
}
+17
View File
@@ -3,6 +3,7 @@
namespace App\Console\Commands;
use App\Models\Accessory;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\AssetModel;
use App\Models\Category;
@@ -15,6 +16,8 @@ use App\Models\Statuslabel;
use App\Models\Supplier;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
class Purge extends Command
{
@@ -141,6 +144,20 @@ class Purge extends Command
$this->info($users->count().' users purged.');
$user_assoc = 0;
foreach ($users as $user) {
$rel_path = 'private_uploads/users';
$filenames = Actionlog::where('action_type', 'uploaded')
->where('item_id', $user->id)
->pluck('filename');
foreach($filenames as $filename) {
try {
if (Storage::exists($rel_path . '/' . $filename)) {
Storage::delete($rel_path . '/' . $filename);
}
} catch (\Exception $e) {
Log::info('An error occurred while deleting files: ' . $e->getMessage());
}
}
$this->info('- User "'.$user->username.'" deleted.');
$user_assoc += $user->userlog()->count();
$user->userlog()->forceDelete();
+1 -1
View File
@@ -92,7 +92,7 @@ class SQLStreamer {
$parser->line_aware_piping(); // <----- THIS is doing the heavy lifting!
$check_tables = ['settings' => null, 'migrations' => null /* 'assets' => null */]; //TODO - move to statics?
//can't use 'users' because the 'accessories_users' table?
//can't use 'users' because the 'accessories_checkout' table?
// can't use 'assets' because 'ver1_components_assets'
foreach($check_tables as $check_table => $_ignore) {
foreach ($parser->tablenames as $tablename => $_count) {
+2 -2
View File
@@ -721,7 +721,7 @@ class Helper
{
$alert_threshold = \App\Models\Setting::getSettings()->alert_threshold;
$consumables = Consumable::withCount('consumableAssignments as consumable_assignments_count')->whereNotNull('min_amt')->get();
$accessories = Accessory::withCount('users as users_count')->whereNotNull('min_amt')->get();
$accessories = Accessory::withCount('checkouts as checkouts_count')->whereNotNull('min_amt')->get();
$components = Component::whereNotNull('min_amt')->get();
$asset_models = AssetModel::where('min_amt', '>', 0)->get();
$licenses = License::where('min_amt', '>', 0)->get();
@@ -749,7 +749,7 @@ class Helper
}
foreach ($accessories as $accessory) {
$avail = $accessory->qty - $accessory->users_count;
$avail = $accessory->qty - $accessory->checkouts_count;
if ($avail < ($accessory->min_amt) + $alert_threshold) {
if ($accessory->qty > 0) {
$percent = number_format((($avail / $accessory->qty) * 100), 0);
@@ -144,12 +144,12 @@ class AccessoriesController extends Controller
*/
public function update(ImageUploadRequest $request, $accessoryId = null) : RedirectResponse
{
if ($accessory = Accessory::withCount('users as users_count')->find($accessoryId)) {
if ($accessory = Accessory::withCount('checkouts as checkouts_count')->find($accessoryId)) {
$this->authorize($accessory);
$validator = Validator::make($request->all(), [
"qty" => "required|numeric|min:$accessory->users_count"
"qty" => "required|numeric|min:$accessory->checkouts_count"
]);
if ($validator->fails()) {
@@ -233,7 +233,7 @@ class AccessoriesController extends Controller
*/
public function show($accessoryID = null) : View | RedirectResponse
{
$accessory = Accessory::withCount('users as users_count')->find($accessoryID);
$accessory = Accessory::withCount('checkouts as checkouts_count')->find($accessoryID);
$this->authorize('view', $accessory);
if (isset($accessory->id)) {
return view('accessories/view', compact('accessory'));
@@ -6,6 +6,7 @@ use App\Events\CheckoutableCheckedIn;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Models\Accessory;
use App\Models\AccessoryCheckout;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
@@ -24,7 +25,7 @@ class AccessoryCheckinController extends Controller
*/
public function create($accessoryUserId = null, $backto = null) : View | RedirectResponse
{
if (is_null($accessory_user = DB::table('accessories_users')->find($accessoryUserId))) {
if (is_null($accessory_user = DB::table('accessories_checkout')->find($accessoryUserId))) {
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.not_found'));
}
@@ -39,16 +40,16 @@ class AccessoryCheckinController extends Controller
*
* @uses Accessory::checkin_email() to determine if an email can and should be sent
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param null $accessoryUserId
* @param null $accessoryCheckoutId
* @param string $backto
*/
public function store(Request $request, $accessoryUserId = null, $backto = null) : RedirectResponse
public function store(Request $request, $accessoryCheckoutId = null, $backto = null) : RedirectResponse
{
if (is_null($accessory_user = DB::table('accessories_users')->find($accessoryUserId))) {
if (is_null($accessory_checkout = AccessoryCheckout::find($accessoryCheckoutId))) {
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
}
$accessory = Accessory::find($accessory_user->accessory_id);
$accessory = Accessory::find($accessory_checkout->accessory_id);
$this->authorize('checkin', $accessory);
@@ -59,10 +60,8 @@ class AccessoryCheckinController extends Controller
}
// Was the accessory updated?
if (DB::table('accessories_users')->where('id', '=', $accessory_user->id)->delete()) {
$return_to = e($accessory_user->assigned_to);
event(new CheckoutableCheckedIn($accessory, User::find($return_to), auth()->user(), $request->input('note'), $checkin_at));
if ($accessory_checkout->delete()) {
event(new CheckoutableCheckedIn($accessory, $accessory_checkout->assignedTo, auth()->user(), $request->input('note'), $checkin_at));
session()->put(['redirect_option' => $request->get('redirect_option')]);
@@ -4,9 +4,11 @@ namespace App\Http\Controllers\Accessories;
use App\Events\CheckoutableCheckedOut;
use App\Helpers\Helper;
use App\Http\Controllers\CheckInOutRequest;
use App\Http\Controllers\Controller;
use App\Http\Requests\AccessoryCheckoutRequest;
use App\Models\Accessory;
use App\Models\AccessoryCheckout;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Http\Request;
@@ -16,6 +18,9 @@ use \Illuminate\Http\RedirectResponse;
class AccessoryCheckoutController extends Controller
{
use CheckInOutRequest;
/**
* Return the form to checkout an Accessory to a user.
*
@@ -25,7 +30,7 @@ class AccessoryCheckoutController extends Controller
public function create($id) : View | RedirectResponse
{
if ($accessory = Accessory::withCount('users as users_count')->find($id)) {
if ($accessory = Accessory::withCount('checkouts as checkouts_count')->find($id)) {
$this->authorize('checkout', $accessory);
@@ -58,30 +63,32 @@ class AccessoryCheckoutController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param Request $request
* @param int $accessory
* @param Accessory $accessory
*/
public function store(AccessoryCheckoutRequest $request, Accessory $accessory) : RedirectResponse
{
$this->authorize('checkout', $accessory);
$accessory->assigned_to = $request->input('assigned_to');
$user = User::find($request->input('assigned_to'));
$accessory->checkout_qty = $request->input('checkout_qty', 1);
$target = $this->determineCheckoutTarget();
$accessory->checkout_qty = $request->input('checkout_qty', 1);
for ($i = 0; $i < $accessory->checkout_qty; $i++) {
$accessory->users()->attach($accessory->id, [
AccessoryCheckout::create([
'accessory_id' => $accessory->id,
'created_at' => Carbon::now(),
'user_id' => Auth::id(),
'assigned_to' => $request->input('assigned_to'),
'assigned_to' => $target->id,
'assigned_type' => $target::class,
'note' => $request->input('note'),
]);
}
event(new CheckoutableCheckedOut($accessory, $user, auth()->user(), $request->input('note')));
event(new CheckoutableCheckedOut($accessory, $target, auth()->user(), $request->input('note')));
// Set this as user since we only allow checkout to user for this item type
$request->request->add(['checkout_to_type' => 'user']);
$request->request->add(['assigned_user' => $user->id]);
$request->request->add(['checkout_to_type' => request('checkout_to_type')]);
$request->request->add(['assigned_user' => $target->id]);
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
@@ -218,6 +218,7 @@ class AcceptanceController extends Controller
'item_tag' => $item->asset_tag,
'item_model' => $display_model,
'item_serial' => $item->serial,
'item_status' => $item->assetstatus?->name,
'eula' => $item->getEula(),
'note' => $request->input('note'),
'check_out_date' => Carbon::parse($acceptance->created_at)->format('Y-m-d'),
@@ -308,6 +309,7 @@ class AcceptanceController extends Controller
'item_tag' => $item->asset_tag,
'item_model' => $display_model,
'item_serial' => $item->serial,
'item_status' => $item->assetstatus?->name,
'note' => $request->input('note'),
'declined_date' => Carbon::parse($acceptance->declined_at)->format('Y-m-d'),
'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null,
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Api;
use App\Events\CheckoutableCheckedOut;
use App\Helpers\Helper;
use App\Http\Controllers\CheckInOutRequest;
use App\Http\Controllers\Controller;
use App\Http\Requests\AccessoryCheckoutRequest;
use App\Http\Requests\StoreAccessoryRequest;
@@ -17,10 +18,12 @@ use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\Request;
use App\Http\Requests\ImageUploadRequest;
use App\Models\AccessoryCheckout;
class AccessoriesController extends Controller
{
use CheckInOutRequest;
/**
* Display a listing of the resource.
*
@@ -48,13 +51,13 @@ class AccessoriesController extends Controller
'min_amt',
'company_id',
'notes',
'users_count',
'checkouts_count',
'qty',
];
$accessories = Accessory::select('accessories.*')->with('category', 'company', 'manufacturer', 'users', 'location', 'supplier')
->withCount('users as users_count');
$accessories = Accessory::select('accessories.*')->with('category', 'company', 'manufacturer', 'checkouts', 'location', 'supplier')
->withCount('checkouts as checkouts_count');
if ($request->filled('search')) {
$accessories = $accessories->TextSearch($request->input('search'));
@@ -154,7 +157,7 @@ class AccessoriesController extends Controller
public function show($id)
{
$this->authorize('view', Accessory::class);
$accessory = Accessory::withCount('users as users_count')->findOrFail($id);
$accessory = Accessory::withCount('checkouts as checkouts_count')->findOrFail($id);
return (new AccessoriesTransformer)->transformAccessory($accessory);
}
@@ -197,28 +200,23 @@ class AccessoriesController extends Controller
$offset = request('offset', 0);
$limit = request('limit', 50);
$accessory_users = $accessory->users;
$total = $accessory_users->count();
$accessory_checkouts = $accessory->checkouts;
$total = $accessory_checkouts->count();
if ($total < $offset) {
$offset = 0;
}
$accessory_users = $accessory->users()->skip($offset)->take($limit)->get();
$accessory_checkouts = $accessory->checkouts()->skip($offset)->take($limit)->get();
if ($request->filled('search')) {
$accessory_users = $accessory->users()
->where(function ($query) use ($request) {
$search_str = '%' . $request->input('search') . '%';
$query->where('first_name', 'like', $search_str)
->orWhere('last_name', 'like', $search_str)
->orWhere('note', 'like', $search_str);
})
$accessory_checkouts = $accessory->checkouts()->TextSearch($request->input('search'))
->get();
$total = $accessory_users->count();
$total = $accessory_checkouts->count();
}
return (new AccessoriesTransformer)->transformCheckedoutAccessory($accessory, $accessory_users, $total);
return (new AccessoriesTransformer)->transformCheckedoutAccessory($accessory, $accessory_checkouts, $total);
}
@@ -282,22 +280,22 @@ class AccessoriesController extends Controller
public function checkout(AccessoryCheckoutRequest $request, Accessory $accessory)
{
$this->authorize('checkout', $accessory);
$accessory->assigned_to = $request->input('assigned_to');
$user = User::find($request->input('assigned_to'));
$target = $this->determineCheckoutTarget();
$accessory->checkout_qty = $request->input('checkout_qty', 1);
for ($i = 0; $i < $accessory->checkout_qty; $i++) {
$accessory->users()->attach($accessory->id, [
AccessoryCheckout::create([
'accessory_id' => $accessory->id,
'created_at' => Carbon::now(),
'user_id' => Auth::id(),
'assigned_to' => $request->input('assigned_to'),
'assigned_to' => $target->id,
'assigned_type' => $target::class,
'note' => $request->input('note'),
]);
}
// Set this value to be able to pass the qty through to the event
event(new CheckoutableCheckedOut($accessory, $user, auth()->user(), $request->input('note')));
event(new CheckoutableCheckedOut($accessory, $target, auth()->user(), $request->input('note')));
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkout.success')));
@@ -316,19 +314,19 @@ class AccessoriesController extends Controller
*/
public function checkin(Request $request, $accessoryUserId = null)
{
if (is_null($accessory_user = DB::table('accessories_users')->find($accessoryUserId))) {
if (is_null($accessory_checkout = AccessoryCheckout::find($accessoryUserId))) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.does_not_exist')));
}
$accessory = Accessory::find($accessory_user->accessory_id);
$accessory = Accessory::find($accessory_checkout->accessory_id);
$this->authorize('checkin', $accessory);
$logaction = $accessory->logCheckin(User::find($accessory_user->assigned_to), $request->input('note'));
$logaction = $accessory->logCheckin(User::find($accessory_checkout->assigned_to), $request->input('note'));
// Was the accessory updated?
if (DB::table('accessories_users')->where('id', '=', $accessory_user->id)->delete()) {
if (! is_null($accessory_user->assigned_to)) {
$user = User::find($accessory_user->assigned_to);
if ($accessory_checkout->delete()) {
if (! is_null($accessory_checkout->assigned_to)) {
$user = User::find($accessory_checkout->assigned_to);
}
$data['log_id'] = $logaction->id;
@@ -928,7 +928,7 @@ class AssetsController extends Controller
}
}
if ($request->has('status_id')) {
if ($request->filled('status_id')) {
$asset->status_id = $request->input('status_id');
}
@@ -978,7 +978,7 @@ class AssetsController extends Controller
public function checkinByTag(Request $request, $tag = null) : JsonResponse
{
$this->authorize('checkin', Asset::class);
if(null == $tag && null !== ($request->input('asset_tag'))) {
if (null == $tag && null !== ($request->input('asset_tag'))) {
$tag = $request->input('asset_tag');
}
$asset = Asset::where('asset_tag', $tag)->first();
@@ -20,9 +20,9 @@ class DepreciationsController extends Controller
public function index(Request $request) : JsonResponse | array
{
$this->authorize('view', Depreciation::class);
$allowed_columns = ['id','name','months','depreciation_min','created_at'];
$allowed_columns = ['id','name','months','depreciation_min', 'depreciation_type','created_at'];
$depreciations = Depreciation::select('id','name','months','depreciation_min','user_id','created_at','updated_at');
$depreciations = Depreciation::select('id','name','months','depreciation_min','depreciation_type','user_id','created_at','updated_at');
if ($request->filled('search')) {
$depreciations = $depreciations->TextSearch($request->input('search'));
@@ -248,6 +248,7 @@ class LocationsController extends Controller
->withCount('rtd_assets as rtd_assets_count')
->withCount('children as children_count')
->withCount('users as users_count')
->withCount('accessories as accessories_count')
->findOrFail($id);
if (! $location->isDeletable()) {
+10 -2
View File
@@ -83,11 +83,19 @@ class ReportsController extends Controller
$offset = ($request->input('offset') > $total) ? $total : app('api_offset_value');
$limit = app('api_limit_value');
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
$order = ($request->input('order') == 'asc') ? 'asc' : 'desc';
switch ($request->input('sort')) {
case 'admin':
$actionlogs->OrderAdmin($order);
break;
default:
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
$actionlogs = $actionlogs->orderBy($sort, $order);
break;
}
$actionlogs = $actionlogs->orderBy($sort, $order)->skip($offset)->take($limit)->get();
$actionlogs = $actionlogs->skip($offset)->take($limit)->get();
return response()->json((new ActionlogsTransformer)->transformActionlogs($actionlogs, $total), 200, ['Content-Type' => 'application/json;charset=utf8'], JSON_UNESCAPED_UNICODE);
}
@@ -8,6 +8,7 @@ use App\Http\Transformers\AssetsTransformer;
use App\Http\Transformers\SelectlistTransformer;
use App\Http\Transformers\StatuslabelsTransformer;
use App\Models\Asset;
use App\Models\Setting;
use App\Models\Statuslabel;
use Illuminate\Http\Request;
use App\Http\Transformers\PieChartTransformer;
@@ -187,8 +188,14 @@ class StatuslabelsController extends Controller
public function getAssetCountByStatuslabel() : array
{
$this->authorize('view', Statuslabel::class);
$statuslabels = Statuslabel::withCount('assets')->get();
$total = Array();
if (Setting::getSettings()->show_archived_in_list == 0 ) {
$statuslabels = Statuslabel::withCount('assets')->where('archived','0')->get();
} else {
$statuslabels = Statuslabel::withCount('assets')->get();
}
$total = [];
foreach ($statuslabels as $statuslabel) {
@@ -478,9 +478,16 @@ class AssetsController extends Controller
$tag = $tag ? $tag : $request->get('assetTag');
$topsearch = ($request->get('topsearch') == 'true');
if (! $asset = Asset::where('asset_tag', '=', $tag)->first()) {
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
// Search for an exact and unique asset tag match
$assets = Asset::where('asset_tag', '=', $tag);
// If not a unique result, redirect to the index view
if ($assets->count() != 1) {
return redirect()->route('hardware.index')
->with('search', $tag)
->with('warning', trans('admin/hardware/message.does_not_exist_var', [ 'asset_tag' => $tag ]));
}
$asset = $assets->first();
$this->authorize('view', $asset);
return redirect()->route('hardware.show', $asset->id)->with('topsearch', $topsearch);
@@ -837,7 +844,7 @@ class AssetsController extends Controller
{
$this->authorize('checkin', Asset::class);
return view('hardware/quickscan-checkin');
return view('hardware/quickscan-checkin')->with('statusLabel_list', Helper::statusLabelList());
}
public function audit($id)
@@ -227,7 +227,8 @@ class BulkAssetsController extends Controller
* its checkout status.
*/
if (($request->filled('purchase_date'))
if (($request->filled('name'))
|| ($request->filled('purchase_date'))
|| ($request->filled('expected_checkin'))
|| ($request->filled('purchase_cost'))
|| ($request->filled('supplier_id'))
@@ -239,6 +240,7 @@ class BulkAssetsController extends Controller
|| ($request->filled('status_id'))
|| ($request->filled('model_id'))
|| ($request->filled('next_audit_date'))
|| ($request->filled('null_name'))
|| ($request->filled('null_purchase_date'))
|| ($request->filled('null_expected_checkin_date'))
|| ($request->filled('null_next_audit_date'))
@@ -251,13 +253,14 @@ class BulkAssetsController extends Controller
$this->update_array = [];
/**
* Leave out model_id and status here because we do math on that later. We have to do some extra
* validation and checks on those two.
* Leave out model_id and status here because we do math on that later. We have to do some
* extra validation and checks on those two.
*
* It's tempting to make these match the request check above, but some of these values require
* extra work to make sure the data makes sense.
*/
$this->conditionallyAddItem('purchase_date')
$this->conditionallyAddItem('name')
->conditionallyAddItem('purchase_date')
->conditionallyAddItem('expected_checkin')
->conditionallyAddItem('order_number')
->conditionallyAddItem('requestable')
@@ -271,6 +274,11 @@ class BulkAssetsController extends Controller
/**
* Blank out fields that were requested to be blanked out via checkbox
*/
if ($request->input('null_name')=='1') {
$this->update_array['name'] = null;
}
if ($request->input('null_purchase_date')=='1') {
$this->update_array['purchase_date'] = null;
}
@@ -87,7 +87,7 @@ class ResetPasswordController extends Controller
'password.not_in' => trans('validation.disallow_same_pwd_as_user_fields'),
];
$request->validate($this->rules(), $request->all(), $this->validationErrorMessages());
$request->validate($this->rules());
Log::debug('Checking if '.$request->input('username').' exists');
// Check to see if the user even exists - we'll treat the response the same to prevent user sniffing
+20 -8
View File
@@ -99,12 +99,18 @@ class SamlController extends Controller
{
$saml = $this->saml;
$auth = $saml->getAuth();
$auth->processResponse();
$saml_exception = false;
try {
$auth->processResponse();
} catch (\Exception $e) {
Log::warning("Exception caught in SAML login: " . $e->getMessage());
$saml_exception = true;
}
$errors = $auth->getErrors();
if (! empty($errors)) {
Log::error('There was an error with SAML ACS: '.implode(', ', $errors));
Log::error('Reason: '.$auth->getLastErrorReason());
if (!empty($errors) || $saml_exception) {
Log::warning('There was an error with SAML ACS: ' . implode(', ', $errors));
Log::warning('Reason: ' . $auth->getLastErrorReason());
return redirect()->route('login')->with('error', trans('auth/message.signin.error'));
}
@@ -132,12 +138,18 @@ class SamlController extends Controller
{
$auth = $this->saml->getAuth();
$retrieveParametersFromServer = $this->saml->getSetting('retrieveParametersFromServer', false);
$sloUrl = $auth->processSLO(true, null, $retrieveParametersFromServer, null, true);
$saml_exception = false;
try {
$sloUrl = $auth->processSLO(true, null, $retrieveParametersFromServer, null, true);
} catch (\Exception $e) {
Log::warning("Exception caught in SAML single-logout: " . $e->getMessage());
$saml_exception = true;
}
$errors = $auth->getErrors();
if (! empty($errors)) {
Log::error('There was an error with SAML SLS: '.implode(', ', $errors));
Log::error('Reason: '.$auth->getLastErrorReason());
if (!empty($errors) || $saml_exception) {
Log::warning('There was an error with SAML SLS: ' . implode(', ', $errors));
Log::warning('Reason: ' . $auth->getLastErrorReason());
return view('errors.403');
}
+1 -1
View File
@@ -20,7 +20,7 @@ trait CheckInOutRequest
return Location::findOrFail(request('assigned_location'));
case 'asset':
return Asset::findOrFail(request('assigned_asset'));
case 'user':
default:
return User::findOrFail(request('assigned_user'));
}
@@ -8,6 +8,7 @@ use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Models\Asset;
use App\Models\Component;
use App\Models\Setting;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Input;
@@ -97,6 +98,10 @@ class ComponentCheckoutController extends Controller
// Check if the asset exists
$asset = Asset::find($request->input('asset_id'));
if ((Setting::getSettings()->full_multiple_companies_support) && $component->company_id !== $asset->company_id) {
return redirect()->route('components.checkout.show', $componentId)->with('error', trans('general.error_user_company'));
}
// Update the component data
$component->asset_id = $request->input('asset_id');
$component->assets()->attach($component->id, [
@@ -62,6 +62,20 @@ class DepreciationsController extends Controller
$depreciation->name = $request->input('name');
$depreciation->months = $request->input('months');
$depreciation->user_id = Auth::id();
$request->validate([
'depreciation_min' => [
'required',
'numeric',
function ($attribute, $value, $fail) use ($request) {
if ($request->input('depreciation_type') == 'percent' && ($value < 0 || $value > 100)) {
$fail(trans('validation.percent'));
}
},
],
'depreciation_type' => 'required|in:amount,percent',
]);
$depreciation->depreciation_type = $request->input('depreciation_type');
$depreciation->depreciation_min = $request->input('depreciation_min');
// Was the asset created?
@@ -116,6 +130,20 @@ class DepreciationsController extends Controller
// Depreciation data
$depreciation->name = $request->input('name');
$depreciation->months = $request->input('months');
$request->validate([
'depreciation_min' => [
'required',
'numeric',
function ($attribute, $value, $fail) use ($request) {
if ($request->input('depreciation_type') == 'percent' && ($value < 0 || $value > 100)) {
$fail(trans('validation.percent'));
}
},
],
'depreciation_type' => 'required|in:amount,percent',
]);
$depreciation->depreciation_type = $request->input('depreciation_type');
$depreciation->depreciation_min = $request->input('depreciation_min');
// Was the asset created?
@@ -49,6 +49,7 @@ class ProfileController extends Controller
$user->gravatar = $request->input('gravatar');
$user->skin = $request->input('skin');
$user->phone = $request->input('phone');
$user->enable_sounds = $request->input('enable_sounds', false);
if (! config('app.lock_passwords')) {
$user->locale = $request->input('locale', 'en-US');
@@ -324,6 +324,7 @@ class SettingsController extends Controller
$setting->full_multiple_companies_support = $request->input('full_multiple_companies_support', '0');
$setting->unique_serial = $request->input('unique_serial', '0');
$setting->shortcuts_enabled = $request->input('shortcuts_enabled', '0');
$setting->show_images_in_email = $request->input('show_images_in_email', '0');
$setting->show_archived_in_list = $request->input('show_archived_in_list', '0');
$setting->dashboard_message = $request->input('dashboard_message');
@@ -16,6 +16,7 @@ use App\Models\Consumable;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Password;
@@ -218,21 +219,19 @@ class BulkUsersController extends Controller
}
$users = User::whereIn('id', $user_raw_array)->get();
$assets = Asset::whereIn('assigned_to', $user_raw_array)->where('assigned_type', \App\Models\User::class)->get();
$accessories = DB::table('accessories_users')->whereIn('assigned_to', $user_raw_array)->get();
$assets = Asset::whereIn('assigned_to', $user_raw_array)->where('assigned_type', User::class)->get();
$accessoryUserRows = DB::table('accessories_checkout')->where('assigned_type', User::class)->whereIn('assigned_to', $user_raw_array)->get();
$licenses = DB::table('license_seats')->whereIn('assigned_to', $user_raw_array)->get();
$consumables = DB::table('consumables_users')->whereIn('assigned_to', $user_raw_array)->get();
$consumableUserRows = DB::table('consumables_users')->whereIn('assigned_to', $user_raw_array)->get();
if ((($assets->count() > 0) && ((!$request->filled('status_id')) || ($request->input('status_id') == '')))) {
return redirect()->route('users.index')->with('error', 'No status selected');
}
$this->logItemCheckinAndDelete($assets, Asset::class);
$this->logItemCheckinAndDelete($accessories, Accessory::class);
$this->logAccessoriesCheckin($accessoryUserRows);
$this->logItemCheckinAndDelete($licenses, License::class);
$this->logItemCheckinAndDelete($consumables, Consumable::class);
$this->logConsumablesCheckin($consumableUserRows);
Asset::whereIn('id', $assets->pluck('id'))->update([
'status_id' => e(request('status_id')),
@@ -241,19 +240,14 @@ class BulkUsersController extends Controller
'expected_checkin' => null,
]);
LicenseSeat::whereIn('id', $licenses->pluck('id'))->update(['assigned_to' => null]);
ConsumableAssignment::whereIn('id', $consumables->pluck('id'))->delete();
ConsumableAssignment::whereIn('id', $consumableUserRows->pluck('id'))->delete();
foreach ($users as $user) {
$user->consumables()->sync([]);
$user->accessories()->sync([]);
if ($request->input('delete_user')=='1') {
$user->delete();
}
}
$msg = trans('general.bulk_checkin_success');
@@ -279,7 +273,7 @@ class BulkUsersController extends Controller
if ($itemType == License::class){
$item_id = $item->license_id;
}
$logAction->item_id = $item_id;
// We can't rely on get_class here because the licenses/accessories fetched above are not eloquent models, but simply arrays.
$logAction->item_type = $itemType;
@@ -291,6 +285,34 @@ class BulkUsersController extends Controller
}
}
private function logAccessoriesCheckin(Collection $accessoryUserRows): void
{
foreach ($accessoryUserRows as $accessoryUserRow) {
$logAction = new Actionlog();
$logAction->item_id = $accessoryUserRow->accessory_id;
$logAction->item_type = Accessory::class;
$logAction->target_id = $accessoryUserRow->assigned_to;
$logAction->target_type = User::class;
$logAction->user_id = Auth::id();
$logAction->note = 'Bulk checkin items';
$logAction->logaction('checkin from');
}
}
private function logConsumablesCheckin(Collection $consumableUserRows): void
{
foreach ($consumableUserRows as $consumableUserRow) {
$logAction = new Actionlog();
$logAction->item_id = $consumableUserRow->consumable_id;
$logAction->item_type = Consumable::class;
$logAction->target_id = $consumableUserRow->assigned_to;
$logAction->target_type = User::class;
$logAction->user_id = Auth::id();
$logAction->note = 'Bulk checkin items';
$logAction->logaction('checkin from');
}
}
/**
* Save bulk-edited users
*
@@ -44,13 +44,10 @@ class AccessoryCheckoutRequest extends ImageUploadRequest
return array_merge(
[
'assigned_to' => [
'required',
'integer',
'exists:users,id,deleted_at,NULL',
'not_array'
],
'assigned_user' => 'required_without_all:assigned_asset,assigned_location',
'assigned_asset' => 'required_without_all:assigned_user,assigned_location',
'assigned_location' => 'required_without_all:assigned_user,assigned_asset',
'number_remaining_after_checkout' => [
'min:0',
'required',
+2
View File
@@ -2,6 +2,7 @@
namespace App\Http\Requests;
use App\Http\Requests\Traits\MayContainCustomFields;
use App\Models\Asset;
use App\Models\Company;
use App\Models\Setting;
@@ -11,6 +12,7 @@ use Illuminate\Support\Facades\Gate;
class StoreAssetRequest extends ImageUploadRequest
{
use MayContainCustomFields;
/**
* Determine if the user is authorized to make this request.
*
@@ -0,0 +1,39 @@
<?php
namespace App\Http\Requests\Traits;
use App\Models\AssetModel;
use App\Models\CustomField;
trait MayContainCustomFields
{
// this gets called automatically on a form request
public function withValidator($validator)
{
// find the model
if ($this->method() == 'POST') {
$asset_model = AssetModel::find($this->model_id);
}
if ($this->method() == 'PATCH' || $this->method() == 'PUT') {
$asset_model = $this->asset->model;
}
// collect the custom fields in the request
$validator->after(function ($validator) use ($asset_model) {
$request_fields = $this->collect()->keys()->filter(function ($attributes) {
return str_starts_with($attributes, '_snipeit_');
});
// if there are custom fields, find the one's that don't exist on the model's fieldset and add an error to the validator's error bag
if (count($request_fields) > 0) {
$request_fields->diff($asset_model?->fieldset?->fields?->pluck('db_column'))
->each(function ($request_field_name) use ($request_fields, $validator) {
if (CustomField::where('db_column', $request_field_name)->exists()) {
$validator->errors()->add($request_field_name, trans('validation.custom.custom_field_not_found_on_model'));
} else {
$validator->errors()->add($request_field_name, trans('validation.custom.custom_field_not_found'));
}
});
}
});
}
}
+2
View File
@@ -2,12 +2,14 @@
namespace App\Http\Requests;
use App\Http\Requests\Traits\MayContainCustomFields;
use App\Models\Asset;
use Illuminate\Support\Facades\Gate;
use Illuminate\Validation\Rule;
class UpdateAssetRequest extends ImageUploadRequest
{
use MayContainCustomFields;
/**
* Determine if the user is authorized to make this request.
*
@@ -39,7 +39,7 @@ class AccessoriesTransformer
'order_number' => ($accessory->order_number) ? e($accessory->order_number) : null,
'min_qty' => ($accessory->min_amt) ? (int) $accessory->min_amt : null,
'remaining_qty' => (int) $accessory->numRemaining(),
'users_count' => $accessory->users_count,
'checkouts_count' => $accessory->checkouts_count,
'created_at' => Helper::getFormattedDateObject($accessory->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($accessory->updated_at, 'datetime'),
@@ -66,27 +66,42 @@ class AccessoriesTransformer
return $array;
}
public function transformCheckedoutAccessory($accessory, $accessory_users, $total)
public function transformCheckedoutAccessory($accessory, $accessory_checkouts, $total)
{
$array = [];
foreach ($accessory_users as $user) {
foreach ($accessory_checkouts as $checkout) {
$array[] = [
'assigned_pivot_id' => $user->pivot->id,
'id' => (int) $user->id,
'username' => e($user->username),
'name' => e($user->getFullNameAttribute()),
'first_name'=> e($user->first_name),
'last_name'=> e($user->last_name),
'employee_number' => e($user->employee_num),
'checkout_notes' => e($user->pivot->note),
'last_checkout' => Helper::getFormattedDateObject($user->pivot->created_at, 'datetime'),
'type' => 'user',
'id' => $checkout->id,
'assigned_to' => $this->transformAssignedTo($checkout),
'checkout_notes' => e($checkout->note),
'last_checkout' => Helper::getFormattedDateObject($checkout->created_at, 'datetime'),
'available_actions' => ['checkin' => true],
];
}
return (new DatatablesTransformer)->transformDatatables($array, $total);
}
public function transformAssignedTo($accessoryCheckout)
{
if ($accessoryCheckout->checkedOutToUser()) {
return [
'id' => (int) $accessoryCheckout->assigned->id,
'username' => e($accessoryCheckout->assigned->username),
'name' => e($accessoryCheckout->assigned->getFullNameAttribute()),
'first_name'=> e($accessoryCheckout->assigned->first_name),
'last_name'=> ($accessoryCheckout->assigned->last_name) ? e($accessoryCheckout->assigned->last_name) : null,
'email'=> ($accessoryCheckout->assigned->email) ? e($accessoryCheckout->assigned->email) : null,
'employee_number' => ($accessoryCheckout->assigned->employee_num) ? e($accessoryCheckout->assigned->employee_num) : null,
'type' => 'user',
];
}
return $accessoryCheckout->assigned ? [
'id' => $accessoryCheckout->assigned->id,
'name' => e($accessoryCheckout->assigned->display_name),
'type' => $accessoryCheckout->assignedType(),
] : null;
}
}
@@ -205,11 +205,11 @@ class ActionlogsTransformer
public function transformCheckedoutActionlog (Collection $accessories_users, $total)
public function transformCheckedoutActionlog (Collection $accessories_checkout, $total)
{
$array = array();
foreach ($accessories_users as $user) {
foreach ($accessories_checkout as $user) {
$array[] = (new UsersTransformer)->transformUser($user);
}
return (new DatatablesTransformer)->transformDatatables($array, $total);
@@ -7,6 +7,7 @@ use App\Models\Depreciable;
use App\Models\Depreciation;
use Illuminate\Support\Facades\Gate;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Log;
class DepreciationsTransformer
{
@@ -26,7 +27,7 @@ class DepreciationsTransformer
'id' => (int) $depreciation->id,
'name' => e($depreciation->name),
'months' => $depreciation->months.' '.trans('general.months'),
'depreciation_min' => $depreciation->depreciation_min,
'depreciation_min' => $depreciation->depreciation_type === 'percent' ? $depreciation->depreciation_min.'%' : $depreciation->depreciation_min,
'created_at' => Helper::getFormattedDateObject($depreciation->created_at, 'datetime'),
'updated_at' => Helper::getFormattedDateObject($depreciation->updated_at, 'datetime')
];
+5 -1
View File
@@ -137,7 +137,11 @@ class CheckoutableListener
*/
private function getCheckoutAcceptance($event)
{
if (! $event->checkoutable->requireAcceptance()) {
$checkedOutToType = get_class($event->checkedOutTo);
if ($checkedOutToType != "App\Models\User") {
return null;
}
if (!$event->checkoutable->requireAcceptance()) {
return null;
}
+11 -8
View File
@@ -253,9 +253,10 @@ class Accessory extends SnipeModel
* @since [v3.0]
* @return \Illuminate\Database\Eloquent\Relations\Relation
*/
public function users()
public function checkouts()
{
return $this->belongsToMany(\App\Models\User::class, 'accessories_users', 'accessory_id', 'assigned_to')->withPivot('id', 'created_at', 'note')->withTrashed();
return $this->hasMany(\App\Models\AccessoryCheckout::class, 'accessory_id')
->with('assignedTo');
}
/**
@@ -267,7 +268,9 @@ class Accessory extends SnipeModel
*/
public function hasUsers()
{
return $this->belongsToMany(\App\Models\User::class, 'accessories_users', 'accessory_id', 'assigned_to')->count();
return $this->hasMany(\App\Models\AccessoryCheckout::class, 'accessory_id')
->where('assigned_type', User::class)
->count();
}
/**
@@ -338,15 +341,15 @@ class Accessory extends SnipeModel
*/
public function numCheckedOut()
{
return $this->users_count ?? $this->users()->count();
return $this->checkouts_count ?? $this->checkouts()->count();
}
/**
* Check how many items of an accessory remain.
*
* In order to use this model method, you MUST call withCount('users as users_count')
* on the eloquent query in the controller, otherwise $this->users_count will be null and
* In order to use this model method, you MUST call withCount('checkouts as checkouts_count')
* on the eloquent query in the controller, otherwise $this->checkouts_count will be null and
* bad things happen.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
@@ -370,12 +373,12 @@ class Accessory extends SnipeModel
*/
public function declinedCheckout(User $declinedBy, $signature)
{
if (is_null($accessory_user = \DB::table('accessories_users')->where('assigned_to', $declinedBy->id)->where('accessory_id', $this->id)->latest('created_at'))) {
if (is_null($accessory_checkout = AccessoryCheckout::userAssigned()->where('assigned_to', $declinedBy->id)->where('accessory_id', $this->id)->latest('created_at'))) {
// Redirect to the accessory management page with error
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
}
$accessory_user->limit(1)->delete();
$accessory_checkout->limit(1)->delete();
}
/**
+148
View File
@@ -0,0 +1,148 @@
<?php
namespace App\Models;
use App\Helpers\Helper;
use App\Models\Traits\Acceptable;
use App\Models\Traits\Searchable;
use App\Presenters\Presentable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Storage;
use Watson\Validating\ValidatingTrait;
/**
* Model for Accessories.
*
* @version v1.0
*/
class AccessoryCheckout extends Model
{
use Searchable;
protected $fillable = ['user_id', 'accessory_id', 'assigned_to', 'assigned_type', 'note'];
protected $table = 'accessories_checkout';
/**
* Establishes the accessory checkout -> accessory relationship
*
* @author [A. Kroeger]
* @since [v7.0.9]
* @return \Illuminate\Database\Eloquent\Relations\Relation
*/
public function accessory()
{
return $this->hasOne(\App\Models\Accessory::class, 'accessory_id');
}
/**
* Establishes the accessory checkout -> user relationship
*
* @author [A. Kroeger]
* @since [v7.0.9]
* @return \Illuminate\Database\Eloquent\Relations\Relation
*/
public function user()
{
return $this->hasOne(\App\Models\User::class, 'user_id');
}
/**
* Get the target this asset is checked out to
*
* @author [A. Kroeger]
* @since [v7.0]
* @return \Illuminate\Database\Eloquent\Relations\Relation
*/
public function assignedTo()
{
return $this->morphTo('assigned', 'assigned_type', 'assigned_to')->withTrashed();
}
/**
* Gets the lowercased name of the type of target the asset is assigned to
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @return string
*/
public function assignedType()
{
return $this->assigned_type ? strtolower(class_basename($this->assigned_type)) : null;
}
/**
* Determines whether the accessory is checked out to a user
*
* Even though we allow allow for checkout to things beyond users
* this method is an easy way of seeing if we are checked out to a user.
*
* @author [A. Kroeger]
* @since [v7.0]
*/
public function checkedOutToUser(): bool
{
return $this->assignedType() === Asset::USER;
}
public function scopeUserAssigned(Builder $query): void
{
$query->where('assigned_type', '=', User::class);
}
/**
* Run additional, advanced searches.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param array $terms The search terms
* @return \Illuminate\Database\Eloquent\Builder
*/
public function advancedTextSearch(Builder $query, array $terms)
{
$userQuery = User::where(function ($query) use ($terms) {
foreach ($terms as $term) {
$search_str = '%' . $term . '%';
$query->where('first_name', 'like', $search_str)
->orWhere('last_name', 'like', $search_str)
->orWhere('note', 'like', $search_str);
}
})->select('id');
$locationQuery = Location::where(function ($query) use ($terms) {
foreach ($terms as $term) {
$search_str = '%' . $term . '%';
$query->where('name', 'like', $search_str);
}
})->select('id');
$assetQuery = Asset::where(function ($query) use ($terms) {
foreach ($terms as $term) {
$search_str = '%' . $term . '%';
$query->where('name', 'like', $search_str);
}
})->select('id');
$query->where(function ($query) use ($userQuery) {
$query->where('assigned_type', User::class)
->whereIn('assigned_to', $userQuery);
})->orWhere(function($query) use ($locationQuery) {
$query->where('assigned_type', Location::class)
->whereIn('assigned_to', $locationQuery);
})->orWhere(function($query) use ($assetQuery) {
$query->where('assigned_type', Asset::class)
->whereIn('assigned_to', $assetQuery);
})->orWhere(function($query) use ($terms) {
foreach ($terms as $term) {
$search_str = '%' . $term . '%';
$query->where('note', 'like', $search_str);
}
});
return $query;
}
}
+7 -1
View File
@@ -7,7 +7,6 @@ use App\Presenters\Presentable;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Auth;
/**
* Model for the Actionlog (the table that keeps a historical log of
@@ -17,10 +16,12 @@ use Illuminate\Support\Facades\Auth;
*/
class Actionlog extends SnipeModel
{
use CompanyableTrait;
use HasFactory;
// This is to manually set the source (via setActionSource()) for determineActionSource()
protected ?string $source = null;
protected $with = ['admin'];
protected $presenter = \App\Presenters\ActionlogPresenter::class;
use SoftDeletes;
@@ -372,4 +373,9 @@ class Actionlog extends SnipeModel
{
$this->source = $source;
}
public function scopeOrderAdmin($query, $order)
{
return $query->leftJoin('users as admin_sort', 'action_logs.user_id', '=', 'admin_sort.id')->select('action_logs.*')->orderBy('admin_sort.first_name', $order)->orderBy('admin_sort.last_name', $order);
}
}
+2 -2
View File
@@ -2,7 +2,6 @@
namespace App\Models;
use App\Events\AssetCheckedOut;
use App\Events\CheckoutableCheckedOut;
use App\Exceptions\CheckoutNotAllowed;
use App\Helpers\Helper;
@@ -31,6 +30,7 @@ class Asset extends Depreciable
{
protected $presenter = AssetPresenter::class;
protected $with = ['model', 'admin'];
use CompanyableTrait;
use HasFactory, Loggable, Requestable, Presentable, SoftDeletes, ValidatingTrait, UniqueUndeletedTrait;
@@ -716,7 +716,7 @@ class Asset extends Depreciable
* @since [v1.0]
* @return \Illuminate\Database\Eloquent\Relations\Relation
*/
public function adminuser()
public function admin()
{
return $this->belongsTo(\App\Models\User::class, 'user_id');
}
+5 -1
View File
@@ -205,7 +205,11 @@ class Component extends SnipeModel
public function numCheckedOut()
{
$checkedout = 0;
foreach ($this->assets as $checkout) {
// In case there are elements checked out to assets that belong to a different company
// than this asset and full multiple company support is on we'll remove the global scope,
// so they are included in the count.
foreach ($this->assets()->withoutGlobalScope(new CompanyableScope)->get() as $checkout) {
$checkedout += $checkout->pivot->assigned_qty;
}
+16 -4
View File
@@ -76,9 +76,9 @@ class Depreciable extends SnipeModel
if ($months_passed >= $this->get_depreciation()->months){
//if there is a floor use it
if(!$this->get_depreciation()->depreciation_min == null) {
if($this->get_depreciation()->depreciation_min) {
$current_value = $this->get_depreciation()->depreciation_min;
$current_value = $this->calculateDepreciation();
}else{
$current_value = 0;
@@ -86,7 +86,7 @@ class Depreciable extends SnipeModel
}
else {
// The equation here is (Purchase_Cost-Floor_min)*(Months_passed/Months_til_depreciated)
$current_value = round(($this->purchase_cost-($this->purchase_cost - ($this->get_depreciation()->depreciation_min)) * ($months_passed / $this->get_depreciation()->months)), 2);
$current_value = round(($this->purchase_cost-($this->purchase_cost - ($this->calculateDepreciation())) * ($months_passed / $this->get_depreciation()->months)), 2);
}
@@ -95,7 +95,7 @@ class Depreciable extends SnipeModel
public function getMonthlyDepreciation(){
return ($this->purchase_cost-$this->get_depreciation()->depreciation_min)/$this->get_depreciation()->months;
return ($this->purchase_cost-$this->calculateDepreciation())/$this->get_depreciation()->months;
}
@@ -191,4 +191,16 @@ class Depreciable extends SnipeModel
{
return new \DateTime($time);
}
private function calculateDepreciation()
{
if($this->get_depreciation()->depreciation_type === 'percent') {
$depreciation_percent= $this->get_depreciation()->depreciation_min / 100;
$depreciation_min= $this->purchase_cost * $depreciation_percent;
return $depreciation_min;
}
$depreciation_min = $this->get_depreciation()->depreciation_min;
return $depreciation_min;
}
}
+5 -4
View File
@@ -108,10 +108,11 @@ class Location extends SnipeModel
{
return Gate::allows('delete', $this)
&& ($this->assets_count === 0)
&& ($this->assigned_assets_count === 0)
&& ($this->children_count === 0)
&& ($this->users_count === 0);
&& ($this->assets_count == 0)
&& ($this->assigned_assets_count == 0)
&& ($this->children_count == 0)
&& ($this->accessories_count == 0)
&& ($this->users_count == 0);
}
/**
+1 -1
View File
@@ -331,7 +331,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
*/
public function accessories()
{
return $this->belongsToMany(\App\Models\Accessory::class, 'accessories_users', 'assigned_to', 'accessory_id')
return $this->belongsToMany(\App\Models\Accessory::class, 'accessories_checkout', 'assigned_to', 'accessory_id')
->withPivot('id', 'created_at', 'note')->withTrashed()->orderBy('accessory_id');
}
@@ -24,6 +24,7 @@ class AcceptanceAssetAcceptedNotification extends Notification
$this->item_tag = $params['item_tag'];
$this->item_model = $params['item_model'];
$this->item_serial = $params['item_serial'];
$this->item_status = $params['item_status'];
$this->accepted_date = Helper::getFormattedDateObject($params['accepted_date'], 'date', false);
$this->assigned_to = $params['assigned_to'];
$this->note = $params['note'];
@@ -65,6 +66,7 @@ class AcceptanceAssetAcceptedNotification extends Notification
'item_tag' => $this->item_tag,
'item_model' => $this->item_model,
'item_serial' => $this->item_serial,
'item_status' => $this->item_status,
'note' => $this->note,
'accepted_date' => $this->accepted_date,
'assigned_to' => $this->assigned_to,
@@ -24,6 +24,7 @@ class AcceptanceAssetDeclinedNotification extends Notification
$this->item_tag = $params['item_tag'];
$this->item_model = $params['item_model'];
$this->item_serial = $params['item_serial'];
$this->item_status = $params['item_status'];
$this->declined_date = Helper::getFormattedDateObject($params['declined_date'], 'date', false);
$this->note = $params['note'];
$this->assigned_to = $params['assigned_to'];
@@ -63,6 +64,7 @@ class AcceptanceAssetDeclinedNotification extends Notification
'item_tag' => $this->item_tag,
'item_model' => $this->item_model,
'item_serial' => $this->item_serial,
'item_status' => $this->item_status,
'note' => $this->note,
'declined_date' => $this->declined_date,
'assigned_to' => $this->assigned_to,
@@ -162,6 +162,7 @@ class CheckinAssetNotification extends Notification
$message = (new MailMessage)->markdown('notifications.markdown.checkin-asset',
[
'item' => $this->item,
'status' => $this->item->assetstatus?->name,
'admin' => $this->admin,
'note' => $this->note,
'target' => $this->target,
@@ -209,6 +209,7 @@ public function toGoogleChat()
[
'item' => $this->item,
'admin' => $this->admin,
'status' => $this->item->assetstatus?->name,
'note' => $this->note,
'target' => $this->target,
'fields' => $fields,
+1 -1
View File
@@ -90,7 +90,7 @@ class AccessoryPresenter extends Presenter
'visible' => false,
'title' => trans('admin/accessories/general.remaining'),
],[
'field' => 'users_count',
'field' => 'checkouts_count',
'searchable' => false,
'sortable' => true,
'visible' => true,
+2 -1
View File
@@ -230,7 +230,8 @@ class AuthServiceProvider extends ServiceProvider
|| $user->can('update', Accessory::class)
|| $user->can('create', Accessory::class)
|| $user->can('update', User::class)
|| $user->can('create', User::class);
|| $user->can('create', User::class)
|| ($user->hasAccess('reports.view'));
});
+3 -3
View File
@@ -337,12 +337,12 @@ class Saml
/**
* Get a setting.
*
* @author Johnson Yi <jyi.dev@outlook.com>
*
* @param string|array|int $key
* @param mixed $default
*
* @return void
* @return mixed
* @author Johnson Yi <jyi.dev@outlook.com>
*
*/
public function getSetting($key, $default = null)
{
+1 -1
View File
@@ -107,7 +107,7 @@ class Label implements View
if ($settings->alt_barcode_enabled) {
if ($template->getSupport1DBarcode()) {
$barcode1DType = $settings->alt_barcode;
$barcode1DType = $settings->label2_1d_type;
if ($barcode1DType != 'none') {
$assetData->put('barcode1d', (object)[
'type' => $barcode1DType,
+4 -4
View File
@@ -52,7 +52,7 @@
"livewire/livewire": "^3.5",
"neitanod/forceutf8": "^2.0",
"nesbot/carbon": "^2.32",
"nunomaduro/collision": "^6.1",
"nunomaduro/collision": "^7.0",
"okvpn/clock-lts": "^1.0",
"onelogin/php-saml": "^3.4",
"paragonie/constant_time_encoding": "^2.3",
@@ -74,13 +74,13 @@
"ext-exif": "*"
},
"require-dev": {
"brianium/paratest": "^v6.4.4",
"brianium/paratest": "^7.0",
"fakerphp/faker": "^1.16",
"larastan/larastan": "^2.9",
"mockery/mockery": "^1.4",
"nunomaduro/phpinsights": "^2.7",
"nunomaduro/phpinsights": "^2.11",
"php-mock/php-mock-phpunit": "^2.10",
"phpunit/phpunit": "^9.6.19",
"phpunit/phpunit": "^10.0",
"squizlabs/php_codesniffer": "^3.5",
"symfony/css-selector": "^4.4",
"symfony/dom-crawler": "^4.4",
Generated
+591 -627
View File
File diff suppressed because it is too large Load Diff
+5 -5
View File
@@ -1,10 +1,10 @@
<?php
return array (
'app_version' => 'v7.0.10',
'full_app_version' => 'v7.0.10 - build 14684-gc2bcc2e2d',
'build_version' => '14684',
'app_version' => 'v7.0.11',
'full_app_version' => 'v7.0.11 - build 14904-g6c0cf9447',
'build_version' => '14904',
'prerelease_version' => '',
'hash_version' => 'gc2bcc2e2d',
'full_hash' => 'v7.0.10-311-gc2bcc2e2d',
'hash_version' => 'g6c0cf9447',
'full_hash' => 'v7.0.11-218-g6c0cf9447',
'branch' => 'master',
);
+6 -3
View File
@@ -3,6 +3,7 @@
namespace Database\Factories;
use App\Models\Accessory;
use App\Models\AccessoryCheckout;
use App\Models\Category;
use App\Models\Location;
use App\Models\Manufacturer;
@@ -125,11 +126,12 @@ class AccessoryFactory extends Factory
})->afterCreating(function ($accessory) {
$user = User::factory()->create();
$accessory->users()->attach($accessory->id, [
$accessory->checkouts()->create([
'accessory_id' => $accessory->id,
'created_at' => now(),
'created_at' => Carbon::now(),
'user_id' => $user->id,
'assigned_to' => $user->id,
'assigned_type' => User::class,
'note' => '',
]);
});
@@ -145,11 +147,12 @@ class AccessoryFactory extends Factory
public function checkedOutToUser(User $user = null)
{
return $this->afterCreating(function (Accessory $accessory) use ($user) {
$accessory->users()->attach($accessory->id, [
$accessory->checkouts()->create([
'accessory_id' => $accessory->id,
'created_at' => Carbon::now(),
'user_id' => 1,
'assigned_to' => $user->id ?? User::factory()->create()->id,
'assigned_type' => User::class,
]);
});
}
@@ -0,0 +1,28 @@
<?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('depreciations', function (Blueprint $table) {
$table->string('depreciation_type')->after('depreciation_min')->default('amount');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('depreciations', function (Blueprint $table) {
$table->dropColumn('depreciation_type');
});
}
};
@@ -0,0 +1,43 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use App\Models\Setting;
use App\Models\User;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
if (Schema::hasTable('accessories_users')) {
Schema::rename('accessories_users', 'accessories_checkout');
Schema::table('accessories_checkout', function (Blueprint $table) {
if (!Schema::hasColumn('accessories_checkout', 'assigned_type')) {
$table->string('assigned_type')->nullable();
}
});
}
DB::update('update '.DB::getTablePrefix().'accessories_checkout set assigned_type = \'App\\\\Models\\\\User\' where assigned_type is null', []);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
if (Schema::hasTable('accessories_checkout')) {
Schema::table('accessories_checkout', function (Blueprint $table) {
$table->dropColumn('assigned_type');
});
Schema::rename('accessories_checkout', 'accessories_users');
}
}
};
@@ -0,0 +1,27 @@
<?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('settings', function (Blueprint $table) {
$table->boolean('shortcuts_enabled')->default(false);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('settings', function (Blueprint $table) {
$table->dropColumn('shortcuts_enabled');
});
}
};
@@ -0,0 +1,28 @@
<?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) {
$table->boolean('enable_sounds')->default(false);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('enable_sounds');
});
}
};
+1 -1
View File
@@ -16,7 +16,7 @@ class AccessorySeeder extends Seeder
public function run()
{
Accessory::truncate();
DB::table('accessories_users')->truncate();
DB::table('accessories_checkout')->truncate();
if (! Location::count()) {
$this->call(LocationSeeder::class);
+8 -8
View File
@@ -5,7 +5,7 @@
"packages": {
"": {
"dependencies": {
"@fortawesome/fontawesome-free": "^6.5.2",
"@fortawesome/fontawesome-free": "^6.6.0",
"acorn": "^8.12.0",
"acorn-import-assertions": "^1.9.0",
"admin-lte": "^2.4.18",
@@ -23,7 +23,7 @@
"imagemin": "^8.0.1",
"jquery-slimscroll": "^1.3.8",
"jquery-ui": "^1.13.3",
"jquery-validation": "^1.20.1",
"jquery-validation": "^1.21.0",
"jquery.iframe-transport": "^1.0.0",
"jspdf-autotable": "^3.8.2",
"less": "^4.2.0",
@@ -1918,9 +1918,9 @@
}
},
"node_modules/@fortawesome/fontawesome-free": {
"version": "6.5.2",
"hasInstallScript": true,
"license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)",
"version": "6.6.0",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.6.0.tgz",
"integrity": "sha512-60G28ke/sXdtS9KZCpZSHHkCbdsOGEhIUGlwq6yhY74UpTiToIh8np7A8yphhM4BWsvNFtIvLpi4co+h9Mr9Ow==",
"engines": {
"node": ">=6"
}
@@ -7064,9 +7064,9 @@
}
},
"node_modules/jquery-validation": {
"version": "1.20.1",
"resolved": "https://registry.npmjs.org/jquery-validation/-/jquery-validation-1.20.1.tgz",
"integrity": "sha512-rbBy36Xe5WBCO8OLdZLhPhVjb70KayuoX3WYRNwNpy9TXuUadhNTcaipr6jEIacn+V4jgXB2xUJl6hYzJxr5jw==",
"version": "1.21.0",
"resolved": "https://registry.npmjs.org/jquery-validation/-/jquery-validation-1.21.0.tgz",
"integrity": "sha512-xNot0rlUIgu7duMcQ5qb6MGkGL/Z1PQaRJQoZAURW9+a/2PGOUxY36o/WyNeP2T9R6jvWB8Z9lUVvvQWI/Zs5w==",
"peerDependencies": {
"jquery": "^1.7 || ^2.0 || ^3.1"
}
+2 -2
View File
@@ -25,7 +25,7 @@
"postcss": "^8.4.5"
},
"dependencies": {
"@fortawesome/fontawesome-free": "^6.5.2",
"@fortawesome/fontawesome-free": "^6.6.0",
"acorn": "^8.12.0",
"acorn-import-assertions": "^1.9.0",
"admin-lte": "^2.4.18",
@@ -43,7 +43,7 @@
"imagemin": "^8.0.1",
"jquery-slimscroll": "^1.3.8",
"jquery-ui": "^1.13.3",
"jquery-validation": "^1.20.1",
"jquery-validation": "^1.21.0",
"jquery.iframe-transport": "^1.0.0",
"jspdf-autotable": "^3.8.2",
"less": "^4.2.0",
+8 -10
View File
@@ -1,21 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
backupGlobals="false"
backupStaticAttributes="false"
backupStaticProperties="false"
bootstrap="bootstrap/autoload.php"
cacheDirectory=".phpunit.cache"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd"
>
<coverage>
<include>
<directory suffix=".php">app/</directory>
</include>
</coverage>
<testsuites>
<testsuite name="Unit">
<directory suffix="Test.php">./tests/Unit</directory>
@@ -33,4 +26,9 @@
<env name="SESSION_DRIVER" value="array"/>
<ini name="display_errors" value="true"/>
</php>
<source>
<include>
<directory suffix=".php">app/</directory>
</include>
</source>
</phpunit>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+3 -3
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+41 -39
View File
@@ -1,24 +1,25 @@
{
"/js/build/app.js": "/js/build/app.js?id=05dea4c19ca75f9fc68915a82c341f24",
"/css/dist/skins/skin-red.css": "/css/dist/skins/skin-red.css?id=b9a74ec0cd68f83e7480d5ae39919beb",
"/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=392cc93cfc0be0349bab9697669dd091",
"/css/build/overrides.css": "/css/build/overrides.css?id=3a0b83c0a9919e91f7c795a1971382fd",
"/css/build/app.css": "/css/build/app.css?id=d6fd5ea2989e7ab278745d995c167ae7",
"/js/build/app.js": "/js/build/app.js?id=ae9230922bbd81534aabec227fd0cbe6",
"/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=5f3abb12a286d6cb8aa523322d7f053b",
"/css/dist/skins/_all-skins.css": "/css/dist/skins/_all-skins.css?id=89b7dcd91db033fb19ebbd7f7dcc0c35",
"/css/build/overrides.css": "/css/build/overrides.css?id=693e2f5274862fc13e4d2453b0b58631",
"/css/build/app.css": "/css/build/app.css?id=1431db05a5856d8efc731120da7caa38",
"/css/build/AdminLTE.css": "/css/build/AdminLTE.css?id=a67bd93bed52e6a29967fe472de66d6c",
"/css/dist/skins/skin-yellow.css": "/css/dist/skins/skin-yellow.css?id=fc7adb943668ac69fe4b646625a7571f",
"/css/dist/skins/skin-yellow-dark.css": "/css/dist/skins/skin-yellow-dark.css?id=dd5eb6c76770bacaa2e960849d275516",
"/css/dist/skins/skin-red.css": "/css/dist/skins/skin-red.css?id=b9a74ec0cd68f83e7480d5ae39919beb",
"/css/dist/skins/skin-red-dark.css": "/css/dist/skins/skin-red-dark.css?id=eb99dbccf43841b18be1b3ffc69d9497",
"/css/dist/skins/skin-purple.css": "/css/dist/skins/skin-purple.css?id=cf6c8c340420724b02d6e787ef9bded5",
"/css/dist/skins/skin-purple-dark.css": "/css/dist/skins/skin-purple-dark.css?id=b391d15ee01e2aaffe90554eae9fde0b",
"/css/dist/skins/skin-orange.css": "/css/dist/skins/skin-orange.css?id=268041e902b019730c23ee3875838005",
"/css/dist/skins/skin-orange-dark.css": "/css/dist/skins/skin-orange-dark.css?id=8a12dfa3bef796fc17178890e0aff8d6",
"/css/dist/skins/skin-blue-dark.css": "/css/dist/skins/skin-blue-dark.css?id=34023bf46b7c2486b7468de9b750dbff",
"/css/dist/skins/skin-yellow-dark.css": "/css/dist/skins/skin-yellow-dark.css?id=dd5eb6c76770bacaa2e960849d275516",
"/css/dist/skins/skin-yellow.css": "/css/dist/skins/skin-yellow.css?id=fc7adb943668ac69fe4b646625a7571f",
"/css/dist/skins/skin-purple-dark.css": "/css/dist/skins/skin-purple-dark.css?id=b391d15ee01e2aaffe90554eae9fde0b",
"/css/dist/skins/skin-purple.css": "/css/dist/skins/skin-purple.css?id=cf6c8c340420724b02d6e787ef9bded5",
"/css/dist/skins/skin-red-dark.css": "/css/dist/skins/skin-red-dark.css?id=eb99dbccf43841b18be1b3ffc69d9497",
"/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=5f3abb12a286d6cb8aa523322d7f053b",
"/css/dist/skins/skin-black.css": "/css/dist/skins/skin-black.css?id=1f33ca3d860461c1127ec465ab3ebb6b",
"/css/dist/skins/skin-green-dark.css": "/css/dist/skins/skin-green-dark.css?id=198553147983f411db55d774009bf481",
"/css/dist/skins/skin-green.css": "/css/dist/skins/skin-green.css?id=b48f4d8af0e1ca5621c161e93951109f",
"/css/dist/skins/skin-green-dark.css": "/css/dist/skins/skin-green-dark.css?id=198553147983f411db55d774009bf481",
"/css/dist/skins/skin-contrast.css": "/css/dist/skins/skin-contrast.css?id=f0fbbb0ac729ea092578fb05ca615460",
"/css/dist/all.css": "/css/dist/all.css?id=fba2adaeb1f10de7b4f6628260ee6ef2",
"/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=392cc93cfc0be0349bab9697669dd091",
"/css/dist/skins/skin-blue-dark.css": "/css/dist/skins/skin-blue-dark.css?id=34023bf46b7c2486b7468de9b750dbff",
"/css/dist/skins/skin-black.css": "/css/dist/skins/skin-black.css?id=1f33ca3d860461c1127ec465ab3ebb6b",
"/css/dist/all.css": "/css/dist/all.css?id=74363ddd27850adaa2c4b1ed18f866e3",
"/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",
@@ -81,33 +82,34 @@
"/js/select2/i18n/vi.js": "/js/select2/i18n/vi.js?id=097a5b75b3e146e2d94ab8e1510be607",
"/js/select2/i18n/zh-CN.js": "/js/select2/i18n/zh-CN.js?id=2cff662ec5f972b4613566cf5988cda2",
"/js/select2/i18n/zh-TW.js": "/js/select2/i18n/zh-TW.js?id=04554a227c2ba0f3bb6ca3d2e01e5440",
"/css/webfonts/fa-brands-400.ttf": "/css/webfonts/fa-brands-400.ttf?id=0141634c24336be626e05c8b77d1fa27",
"/css/webfonts/fa-brands-400.woff2": "/css/webfonts/fa-brands-400.woff2?id=b3cf7a6dd618bd392f3ddcc61343a463",
"/css/webfonts/fa-regular-400.ttf": "/css/webfonts/fa-regular-400.ttf?id=9cf69d99de9d83f82466a647f5cb1f94",
"/css/webfonts/fa-regular-400.woff2": "/css/webfonts/fa-regular-400.woff2?id=f0549181a126fe40849a53792bb0e077",
"/css/webfonts/fa-solid-900.ttf": "/css/webfonts/fa-solid-900.ttf?id=509c0e46de844df754d10179cf03c953",
"/css/webfonts/fa-solid-900.woff2": "/css/webfonts/fa-solid-900.woff2?id=96d16b1bdb177fd796c810b9e706c780",
"/css/webfonts/fa-v4compatibility.ttf": "/css/webfonts/fa-v4compatibility.ttf?id=8994b282f9f3b7a00380bb1e2731a4bf",
"/css/webfonts/fa-v4compatibility.woff2": "/css/webfonts/fa-v4compatibility.woff2?id=111e341dba724e1df946e8d1f406a7bd",
"/css/webfonts/fa-brands-400.ttf": "/css/webfonts/fa-brands-400.ttf?id=67c719c0d21dfb09066b4ecdc2310cb8",
"/css/webfonts/fa-brands-400.woff2": "/css/webfonts/fa-brands-400.woff2?id=ea42d181254fd563d365feb2b03a07f4",
"/css/webfonts/fa-regular-400.ttf": "/css/webfonts/fa-regular-400.ttf?id=60e2f6dc1bf9de9da0aa485ccf81b40e",
"/css/webfonts/fa-regular-400.woff2": "/css/webfonts/fa-regular-400.woff2?id=f43a0d63897b14b80bcf10f2fae2d6f8",
"/css/webfonts/fa-solid-900.ttf": "/css/webfonts/fa-solid-900.ttf?id=d1d4daff53a4c06220c5b90933fca9dc",
"/css/webfonts/fa-solid-900.woff2": "/css/webfonts/fa-solid-900.woff2?id=541cafc702f56f57de95f3d1f792f428",
"/css/webfonts/fa-v4compatibility.ttf": "/css/webfonts/fa-v4compatibility.ttf?id=51ade19e1b10d7a0031b18568a2b01d5",
"/css/webfonts/fa-v4compatibility.woff2": "/css/webfonts/fa-v4compatibility.woff2?id=1cc408d68a27c3757b4460bbc542433e",
"/js/dist/bootstrap-table-locale-all.min.js": "/js/dist/bootstrap-table-locale-all.min.js?id=27eb00f47f9bae70cd630d184b7969f1",
"/js/dist/bootstrap-table-en-US.min.js": "/js/dist/bootstrap-table-en-US.min.js?id=57bdb4770b2924f5efeda100caf3c9b7",
"/css/dist/bootstrap-table.css": "/css/dist/bootstrap-table.css?id=8abbb6aea625ec64cd7ebdad77ebf6e5",
"/js/build/vendor.js": "/js/build/vendor.js?id=e27070bdbc5fce3bfd132b952d641fd6",
"/js/dist/bootstrap-table.js": "/js/dist/bootstrap-table.js?id=859e11e4e6b05c84e4b7302de29bac5e",
"/js/dist/all.js": "/js/dist/all.js?id=d4e3181b505407e7bd10b1fd802ae109",
"/css/dist/skins/skin-green.min.css": "/css/dist/skins/skin-green.min.css?id=b48f4d8af0e1ca5621c161e93951109f",
"/css/dist/skins/skin-green-dark.min.css": "/css/dist/skins/skin-green-dark.min.css?id=198553147983f411db55d774009bf481",
"/css/dist/skins/skin-black.min.css": "/css/dist/skins/skin-black.min.css?id=1f33ca3d860461c1127ec465ab3ebb6b",
"/css/dist/skins/_all-skins.min.css": "/css/dist/skins/_all-skins.min.css?id=89b7dcd91db033fb19ebbd7f7dcc0c35",
"/css/dist/skins/skin-black-dark.min.css": "/css/dist/skins/skin-black-dark.min.css?id=5f3abb12a286d6cb8aa523322d7f053b",
"/css/dist/skins/skin-blue.min.css": "/css/dist/skins/skin-blue.min.css?id=392cc93cfc0be0349bab9697669dd091",
"/css/dist/skins/skin-black.min.css": "/css/dist/skins/skin-black.min.css?id=1f33ca3d860461c1127ec465ab3ebb6b",
"/css/dist/skins/skin-blue-dark.min.css": "/css/dist/skins/skin-blue-dark.min.css?id=34023bf46b7c2486b7468de9b750dbff",
"/css/dist/skins/skin-yellow.min.css": "/css/dist/skins/skin-yellow.min.css?id=fc7adb943668ac69fe4b646625a7571f",
"/css/dist/skins/skin-yellow-dark.min.css": "/css/dist/skins/skin-yellow-dark.min.css?id=dd5eb6c76770bacaa2e960849d275516",
"/css/dist/skins/skin-red.min.css": "/css/dist/skins/skin-red.min.css?id=b9a74ec0cd68f83e7480d5ae39919beb",
"/css/dist/skins/skin-red-dark.min.css": "/css/dist/skins/skin-red-dark.min.css?id=eb99dbccf43841b18be1b3ffc69d9497",
"/css/dist/skins/skin-purple.min.css": "/css/dist/skins/skin-purple.min.css?id=cf6c8c340420724b02d6e787ef9bded5",
"/css/dist/skins/skin-purple-dark.min.css": "/css/dist/skins/skin-purple-dark.min.css?id=b391d15ee01e2aaffe90554eae9fde0b",
"/css/dist/skins/skin-orange.min.css": "/css/dist/skins/skin-orange.min.css?id=268041e902b019730c23ee3875838005",
"/css/dist/skins/skin-blue.min.css": "/css/dist/skins/skin-blue.min.css?id=392cc93cfc0be0349bab9697669dd091",
"/css/dist/skins/skin-contrast.min.css": "/css/dist/skins/skin-contrast.min.css?id=f0fbbb0ac729ea092578fb05ca615460",
"/css/dist/skins/skin-green-dark.min.css": "/css/dist/skins/skin-green-dark.min.css?id=198553147983f411db55d774009bf481",
"/css/dist/skins/skin-green.min.css": "/css/dist/skins/skin-green.min.css?id=b48f4d8af0e1ca5621c161e93951109f",
"/css/dist/skins/skin-orange-dark.min.css": "/css/dist/skins/skin-orange-dark.min.css?id=8a12dfa3bef796fc17178890e0aff8d6",
"/css/dist/skins/skin-contrast.min.css": "/css/dist/skins/skin-contrast.min.css?id=f0fbbb0ac729ea092578fb05ca615460"
"/css/dist/skins/skin-orange.min.css": "/css/dist/skins/skin-orange.min.css?id=268041e902b019730c23ee3875838005",
"/css/dist/skins/skin-purple-dark.min.css": "/css/dist/skins/skin-purple-dark.min.css?id=b391d15ee01e2aaffe90554eae9fde0b",
"/css/dist/skins/skin-purple.min.css": "/css/dist/skins/skin-purple.min.css?id=cf6c8c340420724b02d6e787ef9bded5",
"/css/dist/skins/skin-red-dark.min.css": "/css/dist/skins/skin-red-dark.min.css?id=eb99dbccf43841b18be1b3ffc69d9497",
"/css/dist/skins/skin-red.min.css": "/css/dist/skins/skin-red.min.css?id=b9a74ec0cd68f83e7480d5ae39919beb",
"/css/dist/skins/skin-yellow-dark.min.css": "/css/dist/skins/skin-yellow-dark.min.css?id=dd5eb6c76770bacaa2e960849d275516",
"/css/dist/skins/skin-yellow.min.css": "/css/dist/skins/skin-yellow.min.css?id=fc7adb943668ac69fe4b646625a7571f",
"/css/dist/bootstrap-table.css": "/css/dist/bootstrap-table.css?id=8abbb6aea625ec64cd7ebdad77ebf6e5",
"/js/build/vendor.js": "/js/build/vendor.js?id=c1c24b883f48dc3d16b817aed0b457cc",
"/js/dist/bootstrap-table.js": "/js/dist/bootstrap-table.js?id=859e11e4e6b05c84e4b7302de29bac5e",
"/js/dist/all.js": "/js/dist/all.js?id=9dc81f7efc796fdef51858d1a3fae2a2"
}
Binary file not shown.
Binary file not shown.
+141 -2
View File
@@ -363,8 +363,10 @@ body {
}
@media print {
a[href]:after {
content: none;
@page {
size: A4;
margin: 0mm;
}
.tab-content > .tab-pane {
@@ -372,8 +374,136 @@ body {
opacity: 1 !important;
visibility: visible !important;
}
.img-responsive {
width: 200px;
}
html, body {
width: 1024px;
}
body {
margin: 0 auto;
line-height: 1em;
word-spacing:1px;
letter-spacing:0.2px;
font: 15px "Times New Roman", Times, serif;
background:white;
color:black;
width: 100%;
float: none;
}
/* avoid page-breaks inside a listingContainer*/
.listingContainer {
page-break-inside: avoid;
}
h1 {
font: 28px "Times New Roman", Times, serif;
}
h2 {
font: 24px "Times New Roman", Times, serif;
}
h3 {
font: 20px "Times New Roman", Times, serif;
}
/* Improve colour contrast of links */
a:link, a:visited {
color: #781351
}
/* URL */
a:link, a:visited {
background: transparent;
color:#333;
text-decoration:none;
}
a[href]:after {
content: "" !important;
}
a[href^="http://"] {
color:#000;
}
#header {
height:75px;
font-size: 24pt;
color:black
}
div.row-new-striped {
margin: 0px;
padding: 0px;
}
.pagination-detail, .fixed-table-toolbar {
visibility: hidden;
}
.col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 .col-sm-pull-3 .col-sm-push-9 {
float: left;
}
.col-sm-12 {
width: 100%;
}
.col-sm-11 {
width: 91.66666666666666%;
}
.col-sm-10 {
width: 83.33333333333334%;
}
.col-sm-9 {
width: 75%;
}
.col-sm-8 {
width: 66.66666666666666%;
}
.col-sm-7 {
width: 58.333333333333336%;
}
.col-sm-6 {
width: 50%;
}
.col-sm-5 {
width: 41.66666666666667%;
}
.col-sm-4 {
width: 33.33333333333333%;
}
.col-sm-3 {
width: 25%;
}
.col-sm-2 {
width: 16.666666666666664%;
}
.col-sm-1 {
width: 8.333333333333332%;
}
}
.select2-selection__choice__remove {
color: white !important;
}
.select2-selection--multiple {
border-color: #d2d6de !important;
height: 34px;
}
.select2-selection__choice {
border-radius: 0px !important;
}
img.navbar-brand-img, .navbar-brand>img {
float: left;
padding: 5px 5px 5px 0;
@@ -714,6 +844,11 @@ th.css-location > .th-inner::before {
margin-top:50px
}
}
@media screen and (max-width: 1318px) and (min-width: 1200px){
.box{
height:170px;
}
}
.ellipsis {
overflow: hidden;
@@ -880,6 +1015,10 @@ input[type="radio"]:checked::before {
padding-left:15px;
}
.nav-tabs-custom > .nav-tabs > li.active {
font-weight: bold;
}
/** --------------------------------------- **/
/** End checkbox styles to replace iCheck **/
/** --------------------------------------- **/
+1
View File
@@ -12,4 +12,5 @@ return array(
'api_reference' => 'Please check the <a href="https://snipe-it.readme.io/reference" target="_blank">API reference</a> to find specific API endpoints and additional API documentation.',
'profile_updated' => 'Account successfully updated',
'no_tokens' => 'You have not created any personal access tokens.',
'enable_sounds' => 'Enable sound effects',
);
@@ -218,6 +218,8 @@ return [
'webhook_integration_help' => ':app integration is optional, however the endpoint and channel are required if you wish to use it. To configure :app integration, you must first <a href=":webhook_link" target="_new" rel="noopener">create an incoming webhook</a> on your :app account. Click on the <strong>Test :app Integration</strong> button to confirm your settings are correct before saving. ',
'webhook_integration_help_button' => 'Once you have saved your :app information, a test button will appear.',
'webhook_test_help' => 'Test whether your :app integration is configured correctly. YOU MUST SAVE YOUR UPDATED :app SETTINGS FIRST.',
'shortcuts_enabled' => 'Enable Shortcuts',
'shortcuts_help_text' => '<strong>Windows</strong>: Alt + Access key, <strong>Mac</strong>: Control + Option + Access key',
'snipe_version' => 'Snipe-IT version',
'support_footer' => 'Support Footer Links ',
'support_footer_help' => 'Specify who sees the links to the Snipe-IT Support info and Users Manual',
+1
View File
@@ -279,6 +279,7 @@ return [
'site_name' => 'Site Name',
'state' => 'State',
'status_labels' => 'Status Labels',
'status_label' => 'Status Label',
'status' => 'Status',
'accept_eula' => 'Acceptance Agreement',
'supplier' => 'Supplier',
+4
View File
@@ -125,6 +125,8 @@ return [
'symbols' => 'The :attribute field must contain at least one symbol.',
'uncompromised' => 'The given :attribute has appeared in a data leak. Please choose a different :attribute.',
],
'percent' => 'The depreciation minimum must be between 0 and 100 when depreciation type is percentage.',
'present' => 'The :attribute field must be present.',
'present_if' => 'The :attribute field must be present when :other is :value.',
'present_unless' => 'The :attribute field must be present unless :other is :value.',
@@ -188,6 +190,8 @@ return [
'hashed_pass' => 'Your current password is incorrect',
'dumbpwd' => 'That password is too common.',
'statuslabel_type' => 'You must select a valid status label type',
'custom_field_not_found' => 'This field does not seem to exist, please double check your custom field names.',
'custom_field_not_found_on_model' => 'This field seems to exist, but is not available on this Asset Model\'s fieldset.',
// date_format validation with slightly less stupid messages. It duplicates a lot, but it gets the job done :(
// We use this because the default error message for date_format is reflects php Y-m-d, which non-PHP
@@ -66,7 +66,8 @@
</div>
<!-- User -->
@include ('partials.forms.edit.user-select', ['translated_name' => trans('general.select_user'), 'fieldname' => 'assigned_to', 'required'=> 'true'])
@include ('partials.forms.edit.user-select', ['translated_name' => trans('general.select_user'), 'fieldname' => 'assigned_user', 'required'=> 'true'])
<!-- Checkout QTY -->
<div class="form-group {{ $errors->has('checkout_qty') ? 'error' : '' }} ">
+1 -1
View File
@@ -8,7 +8,7 @@
@section('header_right')
@can('create', \App\Models\Accessory::class)
<a href="{{ route('accessories.create') }}" accesskey="n" class="btn btn-primary pull-right"> {{ trans('general.create') }}</a>
<a href="{{ route('accessories.create') }}" {{$snipeSettings->shortcuts_enabled == 1 ? "accesskey=n" : ''}} class="btn btn-primary pull-right"> {{ trans('general.create') }}</a>
@endcan
@stop
+7 -7
View File
@@ -68,9 +68,9 @@
<div class="row">
<div class="col-md-12">
<table
data-cookie-id-table="usersTable"
data-cookie-id-table="checkoutsTable"
data-pagination="true"
data-id-table="usersTable"
data-id-table="checkoutsTable"
data-search="true"
data-side-pagination="server"
data-show-columns="true"
@@ -78,16 +78,16 @@
data-show-export="true"
data-show-refresh="true"
data-sort-order="asc"
id="usersTable"
id="checkoutsTable"
class="table table-striped snipe-table"
data-url="{{ route('api.accessories.checkedout', $accessory->id) }}"
data-export-options='{
"fileName": "export-accessories-{{ str_slug($accessory->name) }}-users-{{ date('Y-m-d') }}",
"fileName": "export-accessories-{{ str_slug($accessory->name) }}-checkouts-{{ date('Y-m-d') }}",
"ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"]
}'>
<thead>
<tr>
<th data-searchable="false" data-formatter="usersLinkFormatter" data-sortable="false" data-field="name">{{ trans('general.user') }}</th>
<th data-searchable="false" data-formatter="polymorphicItemFormatter" data-sortable="false" data-field="assigned_to">{{ trans('general.checked_out_to') }}</th>
<th data-searchable="false" data-sortable="false" data-field="checkout_notes">{{ trans('general.notes') }}</th>
<th data-searchable="false" data-formatter="dateDisplayFormatter" data-sortable="false" data-field="last_checkout">{{ trans('admin/hardware/table.checkout_date') }}</th>
<th data-searchable="false" data-sortable="false" data-field="actions" data-formatter="accessoriesInOutFormatter">{{ trans('table.actions') }}</th>
@@ -314,7 +314,7 @@
<strong>{{ trans('general.checked_out') }}</strong>
</div>
<div class="col-md-9">
{{ $accessory->users_count }}
{{ $accessory->checkouts_count }}
</div>
</div>
</div>
@@ -337,7 +337,7 @@
@endcan
@can('delete', $accessory)
@if ($accessory->users_count == 0)
@if ($accessory->checkouts_count == 0)
<div class="text-center" style="padding-top:5px;">
<button class="btn btn-block btn-danger delete-asset" style="padding-top:5px;" data-toggle="modal" data-title="{{ trans('general.delete') }}" data-content="{{ trans('general.delete_confirm_no_undo', ['item' => $accessory->name]) }}" data-target="#dataConfirmModal">
{{ trans('general.delete') }}
+10
View File
@@ -89,6 +89,15 @@
</div>
</div>
<div class="form-group{{ $errors->has('enable_sounds') ? ' has-error' : '' }}">
<div class="col-md-9 col-md-offset-3">
<label for="enable_sounds" class="form-control">
<input type="checkbox" name="enable_sounds" value="1" {{ old('enable_sounds', $user->enable_sounds) ? 'checked' : '' }}>
{{ trans('account/general.enable_sounds') }}
</label>
</div>
</div>
<!-- Gravatar Email -->
<div class="form-group {{ $errors->has('gravatar') ? ' has-error' : '' }}">
<label for="gravatar" class="col-md-3 control-label">{{ trans('general.gravatar_email') }}
@@ -152,6 +161,7 @@
@endif
</div> <!-- .box-body -->
<div class="text-right box-footer">
<a class="btn btn-link" href="{{ URL::previous() }}">{{ trans('button.cancel') }}</a>
+1 -1
View File
@@ -8,7 +8,7 @@
@section('header_right')
@can('create', \App\Models\Component::class)
<a href="{{ route('components.create') }}" accesskey="n" class="btn btn-primary pull-right"> {{ trans('general.create') }}</a>
<a href="{{ route('components.create') }}" {{$snipeSettings->shortcuts_enabled == 1 ? "accesskey=n" : ''}} class="btn btn-primary pull-right"> {{ trans('general.create') }}</a>
@endcan
@stop
+1 -1
View File
@@ -8,7 +8,7 @@
@section('header_right')
@can('create', \App\Models\Consumable::class)
<a href="{{ route('consumables.create') }}" accesskey="n" class="btn btn-primary pull-right"> {{ trans('general.create') }}</a>
<a href="{{ route('consumables.create') }}" {{$snipeSettings->shortcuts_enabled == 1 ? "accesskey=n" : ''}} class="btn btn-primary pull-right"> {{ trans('general.create') }}</a>
@endcan
@stop
+7 -3
View File
@@ -28,9 +28,13 @@
<label for="depreciation_min" class="col-md-3 control-label">
{{ trans('admin/depreciations/general.depreciation_min') }}
</label>
<div class="col-md-2" style="padding-left:0px">
<input class="form-control" name="depreciation_min" id="depreciation_min" value="{{ old('depreciation_min', $item->depreciation_min) }}" style="width: 80px; margin-left:15px" />
<div class="col-md-2" style="display: flex;">
<input class="form-control" name="depreciation_min" id="depreciation_min" value="{{ old('depreciation_min', $item->depreciation_min) }}" style="width: 80px; margin-right: 15px; display: inline-block;" />
<select class="form-control select2" name="depreciation_type" id="depreciation_type" data-minimum-results-for-search="Infinity" style="width: 150px; display: inline-block;">
<option value="amount" {{ old('depreciation_type', $item->depreciation_type) == 'amount' ? 'selected' : '' }}>Amount</option>
<option value="percent" {{ old('depreciation_type', $item->depreciation_type) == 'percent' ? 'selected' : '' }}>Percentage</option>
</select>
</div>
{!! $errors->first('depreciation_min', '<span class="alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i> :message</span>') !!}
{!! $errors->first('depreciation_min', '<span class="col-md-7 col-md-offset-3 alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i> :message</span>') !!}
</div>
@stop
@@ -30,7 +30,7 @@
<tr>
<td></td>
<td>{{ trans('admin/hardware/table.id') }}</td>
<td>{{ trans('admin/hardware/table.name') }}</td>
<td>{{ trans('general.asset_name') }}</td>
<td>{{ trans('admin/hardware/table.location')}}</td>
<td>{{ trans('admin/hardware/table.assigned_to') }}</td>
</tr>
+19
View File
@@ -35,6 +35,25 @@
@endif
</div>
<!-- Name -->
<div class="form-group {{ $errors->has('name') ? ' has-error' : '' }}">
<label for="name" class="col-md-3 control-label">
{{ trans('admin/hardware/form.name') }}
</label>
<div class="col-md-4">
<input type="text" class="form-control" name="name" id="name" value="{{ old('name') }}" maxlength="100" style="width:100%">
{!! $errors->first('name', '<span class="alert-msg" aria-hidden="true">
<i class="fas fa-times" aria-hidden="true"></i> :message</span>') !!}
</div>
<div class="col-md-5">
<label class="form-control">
{{ Form::checkbox('null_name', '1', false) }}
{{ trans_choice('general.set_to_null', count($assets), ['asset_count' => count($assets)]) }}
</label>
</div>
</div>
<!-- Purchase Date -->
<div class="form-group {{ $errors->has('purchase_date') ? ' has-error' : '' }}">
<label for="purchase_date" class="col-md-3 control-label">{{ trans('admin/hardware/form.date') }}</label>
+1 -1
View File
@@ -129,7 +129,7 @@
<x-redirect_submit_options
index_route="hardware.index"
:button_label="trans('general.checkout')"
:button_label="trans('general.checkin')"
:disabled_select="!$asset->model"
:options="[
'index' => trans('admin/hardware/form.redirect_to_all', ['type' => 'assets']),
+2 -1
View File
@@ -47,7 +47,7 @@
<a href="{{ route('reports/custom') }}" style="margin-right: 5px;" class="btn btn-default">
{{ trans('admin/hardware/general.custom_export') }}</a>
@can('create', \App\Models\Asset::class)
<a href="{{ route('hardware.create') }}" accesskey="n" class="btn btn-primary pull-right"></i> {{ trans('general.create') }}</a>
<a href="{{ route('hardware.create') }}" {{$snipeSettings->shortcuts_enabled == 1 ? "n" : ''}} class="btn btn-primary pull-right"></i> {{ trans('general.create') }}</a>
@endcan
@stop
@@ -73,6 +73,7 @@
data-pagination="true"
data-id-table="assetsListingTable"
data-search="true"
data-search-text="{{ e(Session::get('search')) }}"
data-side-pagination="server"
data-show-columns="true"
data-show-export="true"
@@ -33,14 +33,25 @@
<div class="form-group {{ $errors->has('asset_tag') ? 'error' : '' }}">
{{ Form::label('asset_tag', trans('general.asset_tag'), array('class' => 'col-md-3 control-label', 'id' => 'checkin_tag')) }}
<div class="col-md-9">
<div class="input-group date col-md-5" data-date-format="yyyy-mm-dd">
<input type="text" class="form-control" name="asset_tag" id="asset_tag" value="{{ old('asset_tag') }}">
<div class="input-group col-md-11 required">
<input type="text" class="form-control" name="asset_tag" id="asset_tag" value="{{ old('asset_tag') }}" required>
</div>
{!! $errors->first('asset_tag', '<span class="alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i> :message</span>') !!}
</div>
</div>
<!-- Status -->
<div class="form-group {{ $errors->has('status_id') ? 'error' : '' }}">
<label for="status_id" class="col-md-3 control-label">
{{ trans('admin/hardware/form.status') }}
</label>
<div class="col-md-7">
{{ Form::select('status_id', $statusLabel_list, '', array('class'=>'select2', 'style'=>'width:100%','', 'aria-label'=>'status_id')) }}
{!! $errors->first('status_id', '<span class="alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i> :message</span>') !!}
</div>
</div>
<!-- Locations -->
@include ('partials.forms.edit.location-select', ['translated_name' => trans('general.location'), 'fieldname' => 'location_id'])
@@ -129,6 +140,12 @@
success : function (data) {
if (data.status == 'success') {
$('#checkedin tbody').prepend("<tr class='success'><td>" + data.payload.asset_tag + "</td><td>" + data.payload.model + "</td><td>" + data.payload.model_number + "</td><td>" + data.messages + "</td><td><i class='fas fa-check text-success'></i></td></tr>");
@if ($user->enable_sounds)
var audio = new Audio('{{ config('app.url') }}/sounds/success.mp3');
audio.play()
@endif
incrementOnSuccess();
} else {
handlecheckinFail(data);
@@ -148,6 +165,12 @@
});
function handlecheckinFail (data) {
@if ($user->enable_sounds)
var audio = new Audio('{{ config('app.url') }}/sounds/error.mp3');
audio.play()
@endif
if (data.payload.asset_tag) {
var asset_tag = data.payload.asset_tag;
var model = data.payload.model;
+18 -5
View File
@@ -31,7 +31,7 @@
<div class="form-group {{ $errors->has('asset_tag') ? 'error' : '' }}">
{{ Form::label('asset_tag', trans('general.asset_tag'), array('class' => 'col-md-3 control-label', 'id' => 'audit_tag')) }}
<div class="col-md-9">
<div class="input-group date col-md-5" data-date-format="yyyy-mm-dd">
<div class="input-group date col-md-11 required" data-date-format="yyyy-mm-dd">
<input type="text" class="form-control" name="asset_tag" id="asset_tag" value="{{ old('asset_tag') }}">
</div>
@@ -49,10 +49,13 @@
<div class="form-group">
<div class="col-sm-offset-3 col-md-9">
<label class="form-control">
<input type="checkbox" value="1" name="update_location" {{ old('update_location') == '1' ? ' checked="checked"' : '' }}> {{ trans('admin/hardware/form.asset_location') }}
<input type="checkbox" value="1" name="update_location" {{ old('update_location') == '1' ? ' checked="checked"' : '' }}>
<span>{{ trans('admin/hardware/form.asset_location') }}
<a href="#" class="text-dark-gray" tabindex="0" role="button" data-toggle="popover" data-trigger="focus" title="<i class='far fa-life-ring'></i> {{ trans('general.more_info') }}" data-html="true" data-content="{{ trans('general.quickscan_bulk_help') }}"><i class="far fa-life-ring"></i></a></span>
</label>
<a href="#" class="text-dark-gray" tabindex="0" role="button" data-toggle="popover" data-trigger="focus" title="<i class='far fa-life-ring'></i>"{{ trans('general.more_info') }} data-html="true" data-content="{{ trans('general.quickscan_bulk_help') }}"><i class="far fa-life-ring"></i></a>
</div>
</div>
@@ -153,7 +156,13 @@
data : formData,
success : function (data) {
if (data.status == 'success') {
$('#audited tbody').prepend("<tr class='success'><td>" + data.payload.asset_tag + "</td><td>" + data.messages + "</td><td><i class='fas fa-check text-success'></i></td></tr>");
$('#audited tbody').prepend("<tr class='success'><td>" + data.payload.asset_tag + "</td><td>" + data.messages + "</td><td><i class='fas fa-check text-success' style='font-size:18px;'></i></td></tr>");
@if ($user->enable_sounds)
var audio = new Audio('{{ config('app.url') }}/sounds/success.mp3');
audio.play()
@endif
incrementOnSuccess();
} else {
handleAuditFail(data);
@@ -173,6 +182,10 @@
});
function handleAuditFail (data) {
@if ($user->enable_sounds)
var audio = new Audio('{{ config('app.url') }}/sounds/error.mp3');
audio.play()
@endif
if (data.asset_tag) {
var asset_tag = data.asset_tag;
} else {
@@ -183,7 +196,7 @@
} else {
var messages = '';
}
$('#audited tbody').prepend("<tr class='danger'><td>" + data.payload.asset_tag + "</td><td>" + messages + "</td><td><i class='fas fa-times text-danger'></i></td></tr>");
$('#audited tbody').prepend("<tr class='danger'><td>" + data.payload.asset_tag + "</td><td>" + messages + "</td><td><i class='fas fa-times text-danger' style='font-size:18px;'></i></td></tr>");
}
function incrementOnSuccess() {

Some files were not shown because too many files have changed in this diff Show More