diff --git a/app/Console/Commands/SendUpcomingAuditReport.php b/app/Console/Commands/SendUpcomingAuditReport.php new file mode 100644 index 0000000000..bac5a21698 --- /dev/null +++ b/app/Console/Commands/SendUpcomingAuditReport.php @@ -0,0 +1,91 @@ +alert_email != '') && ($settings->audit_warning_days) && ($settings->alerts_enabled == 1)) { + + // Send a rollup to the admin, if settings dictate + $recipients = collect(explode(',', $settings->alert_email))->map(function ($item, $key) { + return new \App\Models\Recipients\AlertRecipient($item); + }); + + + // Assets due for auditing + + $assets = Asset::whereNotNull('next_audit_date') + ->DueOrOverdueForAudit($settings) + ->orderBy('last_audit_date', 'asc')->get(); + + if ($assets->count() > 0) { + + $this->info(trans_choice('mail.upcoming-audits', $assets->count(), + ['count' => $assets->count(), 'threshold' => $settings->audit_warning_days])); + \Notification::send($recipients, new SendUpcomingAuditNotification($assets, $settings->audit_warning_days)); + $this->info('Audit report sent to '.$settings->alert_email); + } else { + $this->info('No assets to be audited. No report sent.'); + } + + + + } elseif ($settings->alert_email=='') { + $this->error('Could not send email. No alert email configured in settings'); + } elseif (!$settings->audit_warning_days) { + $this->error('No audit warning days set in Admin Notifications. No mail will be sent.'); + } elseif ($settings->alerts_enabled!=1) { + $this->info('Alerts are disabled in the settings. No mail will be sent'); + } else { + $this->error('Something went wrong. :( '); + $this->error('Admin Notifications Email Setting: '.$settings->alert_email); + $this->error('Admin Audit Warning Setting: '.$settings->audit_warning_days); + $this->error('Admin Alerts Emnabled: '.$settings->alerts_enabled); + } + + + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 3a68afdb1b..7ca813351d 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -2,6 +2,7 @@ namespace App\Console; +use App\Console\Commands\RestoreDeletedUsers; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; @@ -33,12 +34,14 @@ class Kernel extends ConsoleKernel Commands\RestoreDeletedUsers::class, Commands\SendCurrentInventoryToUsers::class, Commands\MoveUploadsToNewDisk::class, + Commands\SendUpcomingAuditReport::class, ]; /** * Define the application's command schedule. * - * @param \Illuminate\Console\Scheduling\Schedule $schedule + * @param \Illuminate\Console\Scheduling\Schedule $schedule + * @return void */ protected function schedule(Schedule $schedule) { @@ -47,6 +50,7 @@ class Kernel extends ConsoleKernel $schedule->command('snipeit:expected-checkin')->daily(); $schedule->command('snipeit:backup')->weekly(); $schedule->command('backup:clean')->daily(); + $schedule->command('snipeit:upcoming-audits')->daily(); } /** diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index b4b7757a25..381228a58f 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -44,7 +44,7 @@ class AssetsController extends Controller * @since [v4.0] * @return JsonResponse */ - public function index(Request $request) + public function index(Request $request, $audit = null) { $this->authorize('index', Asset::class); @@ -140,6 +140,21 @@ class AssetsController extends Controller $limit = $request->input('limit', 50); $order = $request->input('order') === 'asc' ? 'asc' : 'desc'; + // This is used by the audit reporting routes + if (Gate::allows('audit', Asset::class)) { + + switch ($audit) { + case 'due': + $assets->DueOrOverdueForAudit($settings); + break; + case 'overdue': + $assets->overdueForAudit($settings); + break; + } + } + + + // This is used by the sidenav, mostly // We switched from using query scopes here because of a Laravel bug diff --git a/app/Http/Controllers/Api/LicensesController.php b/app/Http/Controllers/Api/LicensesController.php index 46ed622e01..92d5c8c9bc 100644 --- a/app/Http/Controllers/Api/LicensesController.php +++ b/app/Http/Controllers/Api/LicensesController.php @@ -228,7 +228,8 @@ class LicensesController extends Controller $seats = LicenseSeat::where('license_id', $licenseId)->with('license', 'user', 'asset'); - $offset = request('offset', 0); + $offset = (($seats) && (request('offset') > $seats->count())) ? 0 : request('offset', 0); + $limit = request('limit', 50); $order = $request->input('order') === 'asc' ? 'asc' : 'desc'; diff --git a/app/Http/Controllers/Assets/AssetsController.php b/app/Http/Controllers/Assets/AssetsController.php index 331ba912ca..98e8dbdacd 100755 --- a/app/Http/Controllers/Assets/AssetsController.php +++ b/app/Http/Controllers/Assets/AssetsController.php @@ -678,6 +678,18 @@ class AssetsController extends Controller return view('hardware/audit')->with('asset', $asset)->with('next_audit_date', $dt)->with('locations_list'); } + public function dueForAudit() + { + $this->authorize('audit', Asset::class); + return view('hardware/audit-due'); + } + + public function overdueForAudit() + { + $this->authorize('audit', Asset::class); + return view('hardware/audit-overdue'); + } + public function auditStore(Request $request, $id) { diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index 283fdf0906..787037cfb1 100755 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -48,6 +48,9 @@ class ProfileController extends Controller $user->last_name = $request->input('last_name'); $user->website = $request->input('website'); $user->gravatar = $request->input('gravatar'); + $user->phone = $request->input('phone'); + + if (!config('app.lock_passwords')) { $user->locale = $request->input('locale', 'en'); diff --git a/app/Models/Asset.php b/app/Models/Asset.php index 3786b75560..68f12af20f 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -998,6 +998,83 @@ class Asset extends Depreciable }); } + /** + * Query builder scope for Assets that are due for auditing, based on the assets.next_audit_date + * and settings.audit_warning_days. + * + * This is/will be used in the artisan command snipeit:upcoming-audits and also + * for an upcoming API call for retrieving a report on assets that will need to be audited. + * + * Due for audit soon: + * next_audit_date greater than or equal to now (must be in the future) + * and (next_audit_date - threshold days) <= now () + * + * Example: + * next_audit_date = May 4, 2025 + * threshold for alerts = 30 days + * now = May 4, 2019 + * + * @author A. Gianotto + * @since v4.6.16 + * @param Setting $settings + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ + + public function scopeDueForAudit($query, $settings) + { + return $query->whereNotNull('assets.next_audit_date') + ->where('assets.next_audit_date', '>=', Carbon::now()) + ->whereRaw("DATE_SUB(assets.next_audit_date, INTERVAL $settings->audit_warning_days DAY) <= '".Carbon::now()."'") + ->where('assets.archived', '=', 0) + ->NotArchived(); + } + + /** + * Query builder scope for Assets that are OVERDUE for auditing, based on the assets.next_audit_date + * and settings.audit_warning_days. It checks to see if assets.next audit_date is before now + * + * This is/will be used in the artisan command snipeit:upcoming-audits and also + * for an upcoming API call for retrieving a report on overdue assets. + * + * @author A. Gianotto + * @since v4.6.16 + * @param Setting $settings + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ + + public function scopeOverdueForAudit($query) + { + return $query->whereNotNull('assets.next_audit_date') + ->where('assets.next_audit_date', '<', Carbon::now()) + ->where('assets.archived', '=', 0) + ->NotArchived(); + } + + /** + * Query builder scope for Assets that are due for auditing OR overdue, based on the assets.next_audit_date + * and settings.audit_warning_days. + * + * This is/will be used in the artisan command snipeit:upcoming-audits and also + * for an upcoming API call for retrieving a report on assets that will need to be audited. + * + * @author A. Gianotto + * @since v4.6.16 + * @param Setting $settings + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ + + public function scopeDueOrOverdueForAudit($query, $settings) + { + return $query->whereNotNull('assets.next_audit_date') + ->whereRaw("DATE_SUB(assets.next_audit_date, INTERVAL $settings->audit_warning_days DAY) <= '".Carbon::now()."'") + ->where('assets.archived', '=', 0) + ->NotArchived(); + } + + /** * Query builder scope for Archived assets * diff --git a/app/Notifications/SendUpcomingAuditNotification.php b/app/Notifications/SendUpcomingAuditNotification.php new file mode 100644 index 0000000000..0aaf11cda5 --- /dev/null +++ b/app/Notifications/SendUpcomingAuditNotification.php @@ -0,0 +1,67 @@ +assets = $params; + $this->threshold = $threshold; + } + + /** + * Get the notification's delivery channels. + * + * @param mixed $notifiable + * @return array + */ + public function via($notifiable) + { + return $notifyBy = ['mail']; + } + + /** + * Get the mail representation of the notification. + * + * @param mixed $notifiable + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { + $message = (new MailMessage)->markdown('notifications.markdown.upcoming-audits', + [ + 'assets' => $this->assets, + 'threshold' => $this->threshold, + ]) + ->subject(trans_choice('mail.upcoming-audits', $this->assets->count(), ['count' => $this->assets->count(), 'threshold' => $this->threshold])); + + return $message; + } + + /** + * Get the array representation of the notification. + * + * @param mixed $notifiable + * @return array + */ + public function toArray($notifiable) + { + return [ + // + ]; + } +} diff --git a/app/Presenters/AssetAuditPresenter.php b/app/Presenters/AssetAuditPresenter.php new file mode 100644 index 0000000000..bfc917eea5 --- /dev/null +++ b/app/Presenters/AssetAuditPresenter.php @@ -0,0 +1,273 @@ + "id", + "searchable" => false, + "sortable" => true, + "switchable" => true, + "title" => trans('general.id'), + "visible" => false + ], [ + "field" => "company", + "searchable" => true, + "sortable" => true, + "switchable" => true, + "title" => trans('general.company'), + "visible" => false, + "formatter" => 'assetCompanyObjFilterFormatter' + ], [ + "field" => "name", + "searchable" => true, + "sortable" => true, + "title" => trans('admin/hardware/form.name'), + "visible" => true, + "formatter" => "hardwareLinkFormatter" + ], [ + "field" => "image", + "searchable" => false, + "sortable" => true, + "switchable" => true, + "title" => trans('admin/hardware/table.image'), + "visible" => false, + "formatter" => "imageFormatter" + ], [ + "field" => "asset_tag", + "searchable" => true, + "sortable" => true, + "title" => trans('admin/hardware/table.asset_tag'), + "visible" => true, + "formatter" => "hardwareLinkFormatter" + ], [ + "field" => "serial", + "searchable" => true, + "sortable" => true, + "title" => trans('admin/hardware/form.serial'), + "visible" => true, + "formatter" => "hardwareLinkFormatter" + ], [ + "field" => "model", + "searchable" => true, + "sortable" => true, + "title" => trans('admin/hardware/form.model'), + "visible" => true, + "formatter" => "modelsLinkObjFormatter" + ], [ + "field" => "model_number", + "searchable" => true, + "sortable" => true, + "title" => trans('admin/models/table.modelnumber'), + "visible" => false + ], [ + "field" => "category", + "searchable" => true, + "sortable" => true, + "title" => trans('general.category'), + "visible" => false, + "formatter" => "categoriesLinkObjFormatter" + ], [ + "field" => "status_label", + "searchable" => true, + "sortable" => true, + "title" => trans('admin/hardware/table.status'), + "visible" => true, + "formatter" => "statuslabelsLinkObjFormatter" + ], [ + "field" => "assigned_to", + "searchable" => true, + "sortable" => true, + "title" => trans('admin/hardware/form.checkedout_to'), + "visible" => true, + "formatter" => "polymorphicItemFormatter" + ], [ + "field" => "location", + "searchable" => true, + "sortable" => true, + "title" => trans('admin/hardware/table.location'), + "visible" => true, + "formatter" => "deployedLocationFormatter" + ], [ + "field" => "rtd_location", + "searchable" => true, + "sortable" => true, + "title" => trans('admin/hardware/form.default_location'), + "visible" => false, + "formatter" => "deployedLocationFormatter" + ], [ + "field" => "manufacturer", + "searchable" => true, + "sortable" => true, + "title" => trans('general.manufacturer'), + "visible" => false, + "formatter" => "manufacturersLinkObjFormatter" + ], [ + "field" => "purchase_date", + "searchable" => true, + "sortable" => true, + "visible" => false, + "title" => trans('general.purchase_date'), + "formatter" => "dateDisplayFormatter" + ], [ + "field" => "purchase_cost", + "searchable" => true, + "sortable" => true, + "visible" => false, + "title" => trans('general.purchase_cost'), + "footerFormatter" => 'sumFormatter', + ], [ + "field" => "order_number", + "searchable" => true, + "sortable" => true, + "visible" => false, + "title" => trans('general.order_number'), + 'formatter' => "orderNumberObjFilterFormatter" + ], [ + "field" => "eol", + "searchable" => false, + "sortable" => false, + "visible" => false, + "title" => trans('general.eol'), + "formatter" => "dateDisplayFormatter" + ], [ + "field" => "warranty_months", + "searchable" => true, + "sortable" => true, + "visible" => false, + "title" => trans('admin/hardware/form.warranty') + ],[ + "field" => "warranty_expires", + "searchable" => false, + "sortable" => false, + "visible" => false, + "title" => trans('admin/hardware/form.warranty_expires'), + "formatter" => "dateDisplayFormatter" + ],[ + "field" => "notes", + "searchable" => true, + "sortable" => true, + "visible" => false, + "title" => trans('general.notes'), + + ], [ + "field" => "checkout_counter", + "searchable" => false, + "sortable" => true, + "visible" => false, + "title" => trans('general.checkouts_count') + + ],[ + "field" => "checkin_counter", + "searchable" => false, + "sortable" => true, + "visible" => false, + "title" => trans('general.checkins_count') + + ], [ + "field" => "requests_counter", + "searchable" => false, + "sortable" => true, + "visible" => false, + "title" => trans('general.user_requests_count') + + ], [ + "field" => "created_at", + "searchable" => false, + "sortable" => true, + "visible" => false, + "title" => trans('general.created_at'), + "formatter" => "dateDisplayFormatter" + ], [ + "field" => "updated_at", + "searchable" => false, + "sortable" => true, + "visible" => false, + "title" => trans('general.updated_at'), + "formatter" => "dateDisplayFormatter" + ], [ + "field" => "last_checkout", + "searchable" => false, + "sortable" => true, + "visible" => false, + "title" => trans('admin/hardware/table.checkout_date'), + "formatter" => "dateDisplayFormatter" + ], [ + "field" => "expected_checkin", + "searchable" => false, + "sortable" => true, + "visible" => false, + "title" => trans('admin/hardware/form.expected_checkin'), + "formatter" => "dateDisplayFormatter" + ], [ + "field" => "last_audit_date", + "searchable" => false, + "sortable" => true, + "visible" => true, + "title" => trans('general.last_audit'), + "formatter" => "dateDisplayFormatter" + ], [ + "field" => "next_audit_date", + "searchable" => false, + "sortable" => true, + "visible" => true, + "title" => trans('general.next_audit_date'), + "formatter" => "dateDisplayFormatter" + ], + ]; + + // This looks complicated, but we have to confirm that the custom fields exist in custom fieldsets + // *and* those fieldsets are associated with models, otherwise we'll trigger + // javascript errors on the bootstrap tables side of things, since we're asking for properties + // on fields that will never be passed through the REST API since they're not associated with + // models. We only pass the fieldsets that pertain to each asset (via their model) so that we + // don't junk up the REST API with tons of custom fields that don't apply + + $fields = CustomField::whereHas('fieldset', function ($query) { + $query->whereHas('models'); + })->get(); + + foreach ($fields as $field) { + $layout[] = [ + "field" => 'custom_fields.'.$field->convertUnicodeDbSlug(), + "searchable" => true, + "sortable" => true, + "visible" => false, + "switchable" => true, + "title" => ($field->field_encrypted=='1') ?' '.e($field->name) : e($field->name), + "formatter" => "customFieldsFormatter" + ]; + + } + + + $layout[] = [ + "field" => "actions", + "searchable" => false, + "sortable" => false, + "switchable" => false, + "title" => trans('table.actions'), + "formatter" => "hardwareAuditFormatter", + ]; + + return json_encode($layout); + } + + + +} diff --git a/app/Presenters/AssetPresenter.php b/app/Presenters/AssetPresenter.php index d971b09e39..689a87201a 100644 --- a/app/Presenters/AssetPresenter.php +++ b/app/Presenters/AssetPresenter.php @@ -391,7 +391,7 @@ class AssetPresenter extends Presenter public function eol_date() { - if (( $this->purchase_date ) && ( $this->model )) { + if (( $this->purchase_date ) && ( $this->model ) && ($this->model->model->eol) ) { $date = date_create($this->purchase_date); date_add($date, date_interval_create_from_date_string($this->model->model->eol . ' months')); return date_format($date, 'Y-m-d'); diff --git a/database/seeds/DatabaseSeeder.php b/database/seeds/DatabaseSeeder.php index 030b5f7c5d..c5ea09b165 100644 --- a/database/seeds/DatabaseSeeder.php +++ b/database/seeds/DatabaseSeeder.php @@ -46,5 +46,8 @@ class DatabaseSeeder extends Seeder \Log::info($output); Model::reguard(); + + DB::table('imports')->truncate(); + } } diff --git a/resources/lang/en/general.php b/resources/lang/en/general.php index 79de8afec2..b18366064b 100644 --- a/resources/lang/en/general.php +++ b/resources/lang/en/general.php @@ -225,7 +225,9 @@ 'years' => 'years', 'yes' => 'Yes', 'zip' => 'Zip', - 'noimage' => 'No image uploaded or image not found.', - 'token_expired' => 'Your form session has expired. Please try again.', - 'login_enabled' => 'Login Enabled', + 'noimage' => 'No image uploaded or image not found.', + 'token_expired' => 'Your form session has expired. Please try again.', + 'login_enabled' => 'Login Enabled', + 'audit_due' => 'Due for Audit', + 'audit_overdue' => 'Overdue for Audit', ]; diff --git a/resources/lang/en/mail.php b/resources/lang/en/mail.php index de1bafb3cc..5fd0dab1e7 100644 --- a/resources/lang/en/mail.php +++ b/resources/lang/en/mail.php @@ -64,9 +64,11 @@ return array( 'license_expiring_alert' => 'There is :count license expiring in the next :threshold days.|There are :count licenses expiring in the next :threshold days.', 'to_reset' => 'To reset your :web password, complete this form:', 'type' => 'Type', + 'upcoming-audits' => 'There is :count asset that is coming up for audit within :threshold days.|There are :count assets that are coming up for audit within :threshold days.', 'user' => 'User', 'username' => 'Username', 'welcome' => 'Welcome :name', 'welcome_to' => 'Welcome to :web!', 'your_credentials' => 'Your Snipe-IT credentials', + ); diff --git a/resources/views/account/profile.blade.php b/resources/views/account/profile.blade.php index bbff2a602f..4e99c7869f 100755 --- a/resources/views/account/profile.blade.php +++ b/resources/views/account/profile.blade.php @@ -58,6 +58,15 @@ + +
+ +
+ + {!! $errors->first('phone', ':message') !!} +
+
+ diff --git a/resources/views/hardware/audit-due.blade.php b/resources/views/hardware/audit-due.blade.php new file mode 100644 index 0000000000..ab99668f0f --- /dev/null +++ b/resources/views/hardware/audit-due.blade.php @@ -0,0 +1,70 @@ +@extends('layouts/default') + +@section('title0') + + @if ((Input::get('company_id')) && ($company)) + {{ $company->name }} + @endif + + {{ trans('general.audit_due') }} + +@stop + +{{-- Page title --}} +@section('title') + @yield('title0') @parent +@stop + + +{{-- Page content --}} +@section('content') + +
+
+
+
+ {{ Form::open([ + 'method' => 'POST', + 'route' => ['hardware/bulkedit'], + 'class' => 'form-inline', + 'id' => 'bulkForm']) }} +
+
+ + +
+ +
+
+ {{ Form::close() }} +
+
+
+
+@stop + +@section('moar_scripts') + @include('partials.bootstrap-table') + +@stop diff --git a/resources/views/hardware/audit-overdue.blade.php b/resources/views/hardware/audit-overdue.blade.php new file mode 100644 index 0000000000..7cea5d0b14 --- /dev/null +++ b/resources/views/hardware/audit-overdue.blade.php @@ -0,0 +1,70 @@ +@extends('layouts/default') + +@section('title0') + + @if ((Input::get('company_id')) && ($company)) + {{ $company->name }} + @endif + + {{ trans('general.audit_overdue') }} + +@stop + +{{-- Page title --}} +@section('title') + @yield('title0') @parent +@stop + + +{{-- Page content --}} +@section('content') + +
+
+
+
+ {{ Form::open([ + 'method' => 'POST', + 'route' => ['hardware/bulkedit'], + 'class' => 'form-inline', + 'id' => 'bulkForm']) }} +
+
+ + +
+ +
+
+ {{ Form::close() }} +
+
+
+
+@stop + +@section('moar_scripts') + @include('partials.bootstrap-table') + +@stop diff --git a/resources/views/layouts/default.blade.php b/resources/views/layouts/default.blade.php index c28e56a51a..49a20a200c 100644 --- a/resources/views/layouts/default.blade.php +++ b/resources/views/layouts/default.blade.php @@ -418,14 +418,27 @@ + @can('audit', \App\Models\Asset::class) + + + {{ trans('general.audit_due') }} + + + + + {{ trans('general.audit_overdue') }} + + + @endcan +
  •  
  • @can('checkout', \App\Models\Asset::class) - + {{ trans('general.bulk_checkout') }} - + {{ trans('general.requested') }} diff --git a/resources/views/licenses/view.blade.php b/resources/views/licenses/view.blade.php index 194a982fe3..9eee3204cf 100755 --- a/resources/views/licenses/view.blade.php +++ b/resources/views/licenses/view.blade.php @@ -44,9 +44,9 @@ count(), ['count' => $assets->count(), 'threshold' => $threshold]) }} + +@component('mail::table') +| |{{ trans('mail.name') }}|{{ trans('general.last_audit') }}|{{ trans('general.next_audit_date') }}|{{ trans('mail.Days') }}|{{ trans('mail.supplier') }} | {{ trans('mail.assigned_to') }} +| |:------------- |:-------------|:---------|:---------|:---------|:---------| +@foreach ($assets as $asset) +@php +$next_audit_date = \App\Helpers\Helper::getFormattedDateObject($asset->next_audit_date, 'date', false); +$last_audit_date = \App\Helpers\Helper::getFormattedDateObject($asset->last_audit_date, 'date', false); +$diff = Carbon::parse(Carbon::now())->diffInDays($next_audit_date, false); +$icon = ($diff <= 7) ? '🚨' : (($diff <= 14) ? '⚠️' : ' '); +@endphp +|{{ $icon }}| [{{ $asset->present()->name }}]({{ route('hardware.show', $asset->id) }}) | {{ $last_audit_date }}| {{ $next_audit_date }} | {{ $diff }} | {{ ($asset->supplier ? e($asset->supplier->name) : '') }}|{{ ($asset->assignedTo ? $asset->assignedTo->present()->name() : '') }} +@endforeach +@endcomponent + + +@endcomponent diff --git a/resources/views/partials/bootstrap-table.blade.php b/resources/views/partials/bootstrap-table.blade.php index b3ac89a902..d4d309d46c 100644 --- a/resources/views/partials/bootstrap-table.blade.php +++ b/resources/views/partials/bootstrap-table.blade.php @@ -149,6 +149,11 @@ }; } + function hardwareAuditFormatter(value, row) { + return '{{ trans('general.audit') }}'; + } + + // Make the edit/delete buttons function genericActionsFormatter(owner_name, element_name = '') { return function (value,row) { diff --git a/routes/api.php b/routes/api.php index ef0488c7bf..f97c66a2fc 100644 --- a/routes/api.php +++ b/routes/api.php @@ -339,13 +339,17 @@ Route::group(['prefix' => 'v1','namespace' => 'Api'], function () { 'uses' => 'AssetsController@selectlist' ]); + Route::get('audit/{audit}', [ + 'as' => 'api.asset.to-audit', + 'uses' => 'AssetsController@index' + ]); + Route::post('audit', [ 'as' => 'api.asset.audit', 'uses' => 'AssetsController@audit' ]); - Route::post('{asset_id}/checkout', [ 'as' => 'api.assets.checkout', diff --git a/routes/web/hardware.php b/routes/web/hardware.php index 4c8cf09cca..495b08086e 100644 --- a/routes/web/hardware.php +++ b/routes/web/hardware.php @@ -29,6 +29,16 @@ Route::group( 'uses' => 'Assets\AssetsController@scan' ]); + Route::get('audit/due', [ + 'as' => 'assets.audit.due', + 'uses' => 'AssetsController@dueForAudit' + ]); + + Route::get('audit/overdue', [ + 'as' => 'assets.audit.overdue', + 'uses' => 'AssetsController@overdueForAudit' + ]); + Route::get('audit/{id}', [ 'as' => 'asset.audit.create', 'uses' => 'Assets\AssetsController@audit'