diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index c5c25d7310..c7055ecb8d 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -512,18 +512,25 @@ class AssetsController extends Controller $this->authorize('audit', Asset::class); $rules = array( - 'id' => 'required' + 'location_id' => 'exists:locations,id|nullable|numeric', + 'next_audit_date' => 'date|nullable' ); $validator = \Validator::make($request->all(), $rules); + if ($validator->fails()) { + return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()->all())); + } $asset = Asset::findOrFail($id); $asset->next_audit_date = $request->input('next_audit_date'); if ($asset->save()) { - $asset->logAudit(request('note')); + $asset->logAudit(request('note'),request('location_id')); return response()->json(Helper::formatStandardApiResponse('success', ['asset'=> e($asset->asset_tag)], trans('admin/hardware/message.audit.success'))); } + + + } } diff --git a/app/Http/Controllers/Api/ReportsController.php b/app/Http/Controllers/Api/ReportsController.php index a8c12d6937..3731122507 100644 --- a/app/Http/Controllers/Api/ReportsController.php +++ b/app/Http/Controllers/Api/ReportsController.php @@ -19,7 +19,7 @@ class ReportsController extends Controller public function index(Request $request) { - $actionlogs = Actionlog::with('item', 'user', 'target'); + $actionlogs = Actionlog::with('item', 'user', 'target','location'); if ($request->has('search')) { $actionlogs = $actionlogs->TextSearch(e($request->input('search'))); diff --git a/app/Http/Controllers/AssetsController.php b/app/Http/Controllers/AssetsController.php index 53c45eca11..666b441c53 100755 --- a/app/Http/Controllers/AssetsController.php +++ b/app/Http/Controllers/AssetsController.php @@ -1241,22 +1241,30 @@ class AssetsController extends Controller public function audit(Request $request, $id) { $this->authorize('audit', Asset::class); - $dt = Carbon::now()->addMonths(12)->toDateString(); - $asset = Asset::findOrFail($id); - return view('hardware/audit')->with('asset', $asset)->with('next_audit_date', $dt); + return view('hardware/audit')->with('asset', $asset)->with('next_audit_date', $dt)->with('locations_list', Helper::locationsList()); } public function auditStore(Request $request, $id) { $this->authorize('audit', Asset::class); + $rules = array( + 'location_id' => 'exists:locations,id|nullable|numeric', + 'next_audit_date' => 'date|nullable' + ); + + $validator = \Validator::make($request->all(), $rules); + if ($validator->fails()) { + return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()->all())); + } + $asset = Asset::findOrFail($id); $asset->next_audit_date = $request->input('next_audit_date'); if ($asset->save()) { - $asset->logAudit(request('note')); + $asset->logAudit(request('note'),request('location_id')); return redirect()->to("hardware")->with('success', trans('admin/hardware/message.audit.success')); } } diff --git a/app/Http/Controllers/SettingsController.php b/app/Http/Controllers/SettingsController.php index 4d71cce76a..2d9d5a01b8 100755 --- a/app/Http/Controllers/SettingsController.php +++ b/app/Http/Controllers/SettingsController.php @@ -562,10 +562,12 @@ class SettingsController extends Controller $alert_email = rtrim($request->input('alert_email'), ','); $alert_email = trim($alert_email); - $setting->alert_email = e($alert_email); + $setting->alert_email = $alert_email; $setting->alerts_enabled = $request->input('alerts_enabled', '0'); $setting->alert_interval = $request->input('alert_interval'); $setting->alert_threshold = $request->input('alert_threshold'); + $setting->audit_interval = $request->input('audit_interval'); + $setting->audit_warning_days = $request->input('audit_warning_days'); if ($setting->save()) { return redirect()->route('settings.index') diff --git a/app/Http/Transformers/ActionlogsTransformer.php b/app/Http/Transformers/ActionlogsTransformer.php index 2286a3b232..80b133c57a 100644 --- a/app/Http/Transformers/ActionlogsTransformer.php +++ b/app/Http/Transformers/ActionlogsTransformer.php @@ -2,6 +2,7 @@ namespace App\Http\Transformers; use App\Models\Actionlog; +use App\Models\Setting; use Gate; use Illuminate\Database\Eloquent\Collection; use App\Helpers\Helper; @@ -12,24 +13,32 @@ class ActionlogsTransformer public function transformActionlogs (Collection $actionlogs, $total) { $array = array(); + $settings = Setting::getSettings(); foreach ($actionlogs as $actionlog) { - $array[] = self::transformActionlog($actionlog); + $array[] = self::transformActionlog($actionlog, $settings); } return (new DatatablesTransformer)->transformDatatables($array, $total); } - public function transformActionlog (Actionlog $actionlog) + public function transformActionlog (Actionlog $actionlog, $settings = null) { $array = [ + 'id' => (int) $actionlog->id, 'icon' => $actionlog->present()->icon(), + 'image' => ($actionlog->item->getImageUrl()) ? $actionlog->item->getImageUrl() : null, 'item' => ($actionlog->item) ? [ 'id' => (int) $actionlog->item->id, 'name' => e($actionlog->item->getDisplayNameAttribute()), 'type' => e($actionlog->itemType()), ] : null, + 'location' => ($actionlog->location) ? [ + 'id' => (int) $actionlog->location->id, + 'name' => e($actionlog->location->name) + ] : null, 'created_at' => Helper::getFormattedDateObject($actionlog->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($actionlog->updated_at, 'datetime'), - 'next_audit_date' => ($actionlog->itemType()=='asset') ? Helper::getFormattedDateObject($actionlog->item->next_audit_date, 'datetime'): null, + 'next_audit_date' => ($actionlog->itemType()=='asset') ? Helper::getFormattedDateObject($actionlog->item->next_audit_date, 'date'): null, + 'days_to_next_audit' => $actionlog->daysUntilNextAudit($settings->audit_interval, $actionlog->item), 'action_type' => $actionlog->present()->actionType(), 'admin' => ($actionlog->user) ? [ 'id' => (int) $actionlog->user->id, diff --git a/app/Models/Actionlog.php b/app/Models/Actionlog.php index 764c64b7e8..b8bed75ceb 100755 --- a/app/Models/Actionlog.php +++ b/app/Models/Actionlog.php @@ -123,6 +123,10 @@ class Actionlog extends SnipeModel return $this->belongsTo('\App\Models\ActionLog', 'thread_id'); } + public function location() { + return $this->belongsTo('\App\Models\Location', 'location_id' )->withTrashed(); + } + /** * Check if the file exists, and if it does, force a download **/ @@ -149,6 +153,44 @@ class Actionlog extends SnipeModel } } + public function daysUntilNextAudit($monthInterval = null, $asset = null) { + + // check for next_audit_date to override global + + if (!$monthInterval) { + $monthInterval = 12; + } + $last_audit_date = $this->created_at; + $next_audit_days = $last_audit_date->diffInDays($last_audit_date->copy()->addMonth($monthInterval)); + + // Override the default setting for interval if the asset has its own next audit date + if (($asset) && ($asset->next_audit_date)) { + $override_default_next = \Carbon::parse($asset->next_audit_date); + $suborder['payment_date'] = $override_default_next->format('M d Y'); + $next_audit_days = $last_audit_date->diffInDays($override_default_next); + } + + return $next_audit_days; + } + + public function calcNextAuditDate($monthInterval = null, $asset = null) { + + if (!$monthInterval) { + $monthInterval = 12; + } + + $dt = \Carbon::now()->addMonths(12)->toDateString(); + $last_audit_date = Carbon::parse($this->created_at); + + // If there is an asset-specific next date already given, + if (($asset) && ($asset->next_audit_date)) { + return \Carbon::parse($asset->next_audit_date);; + } + + $next_audit_date = \Carbon::now()->addMonths($monthInterval)->toDateString(); + $next_audit_date = $last_audit_date->diffInDays($last_audit_date->copy()->addMonth($monthInterval)); + } + /** * getListingOfActionLogsChronologicalOrder * diff --git a/app/Models/Asset.php b/app/Models/Asset.php index 544b29b7b7..d6931576a2 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -66,6 +66,7 @@ class Asset extends Depreciable 'asset_tag' => 'required|min:1|max:255|unique_undeleted', 'status' => 'integer', 'purchase_cost' => 'numeric|nullable', + 'next_audit_date' => 'date|nullable', ]; /** diff --git a/app/Models/Loggable.php b/app/Models/Loggable.php index 5d02807888..f957c78b4b 100644 --- a/app/Models/Loggable.php +++ b/app/Models/Loggable.php @@ -127,7 +127,7 @@ trait Loggable * @since [v4.0] * @return \App\Models\Actionlog */ - public function logAudit($note) + public function logAudit($note, $location_id) { $log = new Actionlog; if (static::class == LicenseSeat::class) { @@ -137,7 +137,7 @@ trait Loggable $log->item_type = static::class; $log->item_id = $this->id; } - $log->location_id = null; + $log->location_id = ($location_id) ? $location_id : null; $log->note = $note; $log->user_id = Auth::user()->id; $log->logaction('audit'); @@ -153,6 +153,7 @@ trait Loggable } + /** * @author Daniel Meltzer integer('audit_interval')->nullable()->default(NULL); + $table->integer('audit_warning_days')->nullable()->default(NULL); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('settings', function (Blueprint $table) { + $table->dropColumn('audit_interval'); + $table->dropColumn('audit_warning_days'); + }); + } +} diff --git a/resources/lang/en/admin/settings/general.php b/resources/lang/en/admin/settings/general.php index 43195baa4c..73fd052a58 100644 --- a/resources/lang/en/admin/settings/general.php +++ b/resources/lang/en/admin/settings/general.php @@ -10,6 +10,10 @@ return array( 'alert_interval' => 'Expiring Alerts Threshold (in days)', 'alert_inv_threshold' => 'Inventory Alert Threshold', 'asset_ids' => 'Asset IDs', + 'audit_interval' => 'Audit Interval', + 'audit_interval_help' => 'If you are required to regularly physically audit your assets, enter the interval in months.', + 'audit_warning_days' => 'Audit Warning Threshold', + 'audit_warning_days_help' => 'How many days in advance should we warn you when assets are due for auditing?', 'auto_increment_assets' => 'Generate auto-incrementing asset IDs', 'auto_increment_prefix' => 'Prefix (optional)', 'auto_incrementing_help' => 'Enable auto-incrementing asset IDs first to set this', diff --git a/resources/lang/en/general.php b/resources/lang/en/general.php index a752eb41fe..d3656d96e2 100644 --- a/resources/lang/en/general.php +++ b/resources/lang/en/general.php @@ -54,6 +54,8 @@ 'current' => 'Current', 'custom_report' => 'Custom Asset Report', 'dashboard' => 'Dashboard', + 'days' => 'days', + 'days_to_next_audit' => 'Days to Next Audit', 'date' => 'Date', 'debug_warning' => 'Warning!', 'debug_warning_text' => 'This application is running in production mode with debugging enabled. This can expose sensitive data if your application is accessible to the outside world. Disable debug mode by setting the APP_DEBUG value in your .env file to false.', diff --git a/resources/views/hardware/audit.blade.php b/resources/views/hardware/audit.blade.php index 935b88c0bb..7fc9afdca0 100644 --- a/resources/views/hardware/audit.blade.php +++ b/resources/views/hardware/audit.blade.php @@ -44,11 +44,20 @@ + +
+ {{ Form::label('location_id', trans('general.location'), array('class' => 'col-md-3 control-label')) }} +
+ {{ Form::select('location_id', $locations_list , Input::old('location_id'), array('class'=>'select2', 'id'=>'location_id', 'style'=>'width:100%')) }} + + {!! $errors->first('location_id', ' :message') !!} +
+
- {{ Form::label('name', trans('admin/hardware/form.checkout_date'), array('class' => 'col-md-3 control-label')) }} + {{ Form::label('name', trans('general.next_audit_date'), array('class' => 'col-md-3 control-label')) }}
@@ -73,7 +82,7 @@
diff --git a/resources/views/partials/bootstrap-table.blade.php b/resources/views/partials/bootstrap-table.blade.php index e60602973e..8499198016 100644 --- a/resources/views/partials/bootstrap-table.blade.php +++ b/resources/views/partials/bootstrap-table.blade.php @@ -98,6 +98,15 @@ $('.snipe-table').bootstrapTable({ }); + + function dateRowCheckStyle(value) { + if ((value.days_to_next_audit) && (value.days_to_next_audit < {{ $snipeSettings->audit_warning_days }})) { + return { classes : "danger" } + } + return {}; + } + + // Handle whether or not the edit button should be disabled $('.snipe-table').on('check.bs.table', function () { $('#bulkEdit').removeAttr('disabled'); diff --git a/resources/views/reports/audit.blade.php b/resources/views/reports/audit.blade.php index ac7c8569e9..c36b120274 100644 --- a/resources/views/reports/audit.blade.php +++ b/resources/views/reports/audit.blade.php @@ -15,22 +15,25 @@
+ data-cookie-id-table="activityReportTable" + data-row-style="dateRowCheckStyle"> - - + + - - + + + + - +
{{ trans('general.date') }}{{ trans('admin/hardware/table.image') }}{{ trans('general.audit') }} {{ trans('general.admin') }}{{ trans('general.action') }}{{ trans('general.item') }}{{ trans('general.item') }}{{ trans('general.location') }}{{ trans('general.next_audit_date') }}{{ trans('general.days_to_next_audit') }}{{ trans('general.notes') }}{{ trans('general.notes') }}
@@ -42,5 +45,5 @@ @section('moar_scripts') - @include ('partials.bootstrap-table', ['exportFile' => 'activity-export', 'search' => true]) + @include ('partials.bootstrap-table', ['exportFile' => 'audit-export', 'search' => false]) @stop diff --git a/resources/views/settings/alerts.blade.php b/resources/views/settings/alerts.blade.php index 70c2c60126..29e3ea54ce 100644 --- a/resources/views/settings/alerts.blade.php +++ b/resources/views/settings/alerts.blade.php @@ -90,6 +90,41 @@
+ + +
+
+ {{ Form::label('audit_interval', trans('admin/settings/general.audit_interval')) }} +
+
+ {{ Form::text('audit_interval', Input::old('audit_interval', $setting->audit_interval), array('class' => 'form-control','placeholder' => '12', 'maxlength'=>'3', 'style'=>'width: 60px;')) }} + {{ trans('general.months') }} +
+
+ {!! $errors->first('audit_interval', ':message') !!} +

{{ trans('admin/settings/general.audit_interval_help') }}

+
+
+ + +
+
+ {{ Form::label('audit_warning_days', trans('admin/settings/general.audit_warning_days')) }} +
+
+ {{ Form::text('audit_warning_days', Input::old('audit_warning_days', $setting->audit_warning_days), array('class' => 'form-control','placeholder' => '14', 'maxlength'=>'3', 'style'=>'width: 60px;')) }} + {{ trans('general.days') }} + + + + +
+
+ {!! $errors->first('audit_warning_days', ':message') !!} +

{{ trans('admin/settings/general.audit_warning_days_help') }}

+
+
+