From e5c2d77c7daadfc833a2906c2980904dd4b19afa Mon Sep 17 00:00:00 2001 From: snipe Date: Sun, 5 May 2019 22:32:52 -0400 Subject: [PATCH] Fixes #6204 - added email alerts and web/API access to assets due for audits (#6992) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added upcoming audit report TODO: Fid diff/threshold math * Added route to list overdue / upcoming assets via API * Controller/API methods for due/overdue audits We could probably skip this and just handle it via view in the routes… * Added query scopes for due and overdue audits * Added audit due console command to kernel * Added ability to pass audit specs to main API asset search method * Added audit presenter * Added bootstrap-tables presenter formatter to display an audit button * Added gated sidenav items to left nav * Added audit due/overdue blades * Cleanup on audit due/overdue console command * Added language strings for audit views * Fixed :threshold placeholder * Removed unused setting variable * Fixed next audit date math * Added scope for both overdue and upcoming * Derp. Wrong version * Bumped version (I will release this version officially tomorrow) --- .../Commands/SendUpcomingAuditReport.php | 91 ++++++ app/Console/Kernel.php | 3 + app/Http/Controllers/Api/AssetsController.php | 17 +- app/Http/Controllers/AssetsController.php | 12 + app/Models/Asset.php | 77 +++++ .../SendUpcomingAuditNotification.php | 67 +++++ app/Presenters/AssetAuditPresenter.php | 273 ++++++++++++++++++ config/version.php | 12 +- resources/lang/en/general.php | 8 +- resources/lang/en/mail.php | 2 + resources/views/hardware/audit-due.blade.php | 70 +++++ .../views/hardware/audit-overdue.blade.php | 70 +++++ resources/views/layouts/default.blade.php | 17 +- .../markdown/upcoming-audits.blade.php | 20 ++ .../views/partials/bootstrap-table.blade.php | 5 + routes/api.php | 6 +- routes/web/hardware.php | 10 + 17 files changed, 747 insertions(+), 13 deletions(-) create mode 100644 app/Console/Commands/SendUpcomingAuditReport.php create mode 100644 app/Notifications/SendUpcomingAuditNotification.php create mode 100644 app/Presenters/AssetAuditPresenter.php create mode 100644 resources/views/hardware/audit-due.blade.php create mode 100644 resources/views/hardware/audit-overdue.blade.php create mode 100644 resources/views/notifications/markdown/upcoming-audits.blade.php 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 3713624422..46b3cde2cb 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; @@ -31,6 +32,7 @@ class Kernel extends ConsoleKernel Commands\RegenerateAssetTags::class, Commands\SyncAssetCounters::class, Commands\RestoreDeletedUsers::class, + Commands\SendUpcomingAuditReport::class, ]; /** @@ -47,6 +49,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(); } protected function commands() diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index c91c57ab7f..499ff8b748 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -52,7 +52,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); @@ -148,6 +148,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/AssetsController.php b/app/Http/Controllers/AssetsController.php index 8eec3f73c9..71b54cc1b6 100755 --- a/app/Http/Controllers/AssetsController.php +++ b/app/Http/Controllers/AssetsController.php @@ -744,6 +744,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(AssetFileRequest $request, $id) { diff --git a/app/Models/Asset.php b/app/Models/Asset.php index bf96e06965..03343f8c6c 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -796,6 +796,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/config/version.php b/config/version.php index 7ae4ca516d..78d3fee89c 100644 --- a/config/version.php +++ b/config/version.php @@ -1,10 +1,10 @@ 'v4.6.15', - 'full_app_version' => 'v4.6.15 - build 4011-gd1e9fbfa2', - 'build_version' => '4011', + 'app_version' => 'v4.6.16', + 'full_app_version' => 'v4.6.16 - build 4018-gce16eae50', + 'build_version' => '4018', 'prerelease_version' => '', - 'hash_version' => 'gd1e9fbfa2', - 'full_hash' => 'v4.6.15-2-gd1e9fbfa2', - 'branch' => 'master', + 'hash_version' => 'gce16eae50', + 'full_hash' => 'v4.6.16-6-gce16eae50', + 'branch' => 'features/6204_email_audit-alerts', ); diff --git a/resources/lang/en/general.php b/resources/lang/en/general.php index ae2bcf0a44..e068d7fb1e 100644 --- a/resources/lang/en/general.php +++ b/resources/lang/en/general.php @@ -219,7 +219,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/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 03f3037447..a37d206e7b 100644 --- a/resources/views/layouts/default.blade.php +++ b/resources/views/layouts/default.blade.php @@ -440,14 +440,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/notifications/markdown/upcoming-audits.blade.php b/resources/views/notifications/markdown/upcoming-audits.blade.php new file mode 100644 index 0000000000..de6e2a89c7 --- /dev/null +++ b/resources/views/notifications/markdown/upcoming-audits.blade.php @@ -0,0 +1,20 @@ +@component('mail::message') + +### {{ trans_choice('mail.upcoming-audits', $assets->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 b1eadb96c2..3132532326 100644 --- a/resources/views/partials/bootstrap-table.blade.php +++ b/resources/views/partials/bootstrap-table.blade.php @@ -167,6 +167,11 @@ }; } + function hardwareAuditFormatter(value, row) { + return '{{ trans('general.audit') }}'; + } + + // Make the edit/delete buttons function genericActionsFormatter(destination) { return function (value,row) { diff --git a/routes/api.php b/routes/api.php index fffc46d55a..a5d4b1bb5a 100644 --- a/routes/api.php +++ b/routes/api.php @@ -321,13 +321,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 081098806a..35decdc2b5 100644 --- a/routes/web/hardware.php +++ b/routes/web/hardware.php @@ -29,6 +29,16 @@ Route::group( 'uses' => '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' => 'AssetsController@audit'