diff --git a/app/Http/Controllers/Assets/AssetCheckinController.php b/app/Http/Controllers/Assets/AssetCheckinController.php index 2c34bc5c9..80667c9ce 100644 --- a/app/Http/Controllers/Assets/AssetCheckinController.php +++ b/app/Http/Controllers/Assets/AssetCheckinController.php @@ -7,6 +7,8 @@ use App\Helpers\Helper; use App\Http\Controllers\Controller; use App\Http\Requests\AssetCheckinRequest; use App\Models\Asset; +use App\Models\CheckoutAcceptance; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Redirect; use Illuminate\Support\Facades\View; @@ -109,6 +111,16 @@ class AssetCheckinController extends Controller $checkin_at = $request->input('checkin_at'); } + // Get all pending Acceptances for this asset and delete them + $acceptances = CheckoutAcceptance::pending()->whereHasMorph('checkoutable', + [Asset::class], + function (Builder $query) use ($asset) { + $query->where('id', $asset->id); + })->get(); + $acceptances->map(function($acceptance) { + $acceptance->delete(); + }); + // Was the asset updated? if ($asset->save()) { event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note'), $checkin_at)); diff --git a/app/Http/Controllers/ReportsController.php b/app/Http/Controllers/ReportsController.php index fac4699bb..8199715b9 100644 --- a/app/Http/Controllers/ReportsController.php +++ b/app/Http/Controllers/ReportsController.php @@ -12,8 +12,10 @@ use App\Models\CustomField; use App\Models\Depreciation; use App\Models\License; use App\Models\Setting; +use App\Notifications\CheckoutAssetNotification; use Carbon\Carbon; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Notification; use Illuminate\Support\Facades\Response; use Illuminate\Support\Facades\View; use Input; @@ -73,7 +75,7 @@ class ReportsController extends Controller trans('admin/accessories/general.remaining'), ]; $header = array_map('trim', $header); - $rows[] = implode($header, ', '); + $rows[] = implode(', ', $header); // Row per accessory foreach ($accessories as $accessory) { @@ -83,10 +85,10 @@ class ReportsController extends Controller $row[] = e($accessory->total); $row[] = e($accessory->remaining); - $rows[] = implode($row, ','); + $rows[] = implode(',', $row); } - $csv = implode($rows, "\n"); + $csv = implode("\n", $rows); $response = Response::make($csv, 200); $response->header('Content-Type', 'text/csv'); $response->header('Content-disposition', 'attachment;filename=report.csv'); @@ -344,7 +346,7 @@ class ReportsController extends Controller ]; $header = array_map('trim', $header); - $rows[] = implode($header, ', '); + $rows[] = implode(', ', $header); // Row per license foreach ($licenses as $license) { @@ -358,10 +360,11 @@ class ReportsController extends Controller $row[] = ($license->depreciation != '') ? '' : e($license->depreciation->name); $row[] = '"'.Helper::formatCurrencyOutput($license->purchase_cost).'"'; - $rows[] = implode($row, ','); + $rows[] = implode(',', $row); } - $csv = implode($rows, "\n"); + + $csv = implode("\n", $rows); $response = Response::make($csv, 200); $response->header('Content-Type', 'text/csv'); $response->header('Content-disposition', 'attachment;filename=report.csv'); @@ -869,7 +872,7 @@ class ReportsController extends Controller ]; $header = array_map('trim', $header); - $rows[] = implode($header, ','); + $rows[] = implode(',', $header); foreach ($assetMaintenances as $assetMaintenance) { $row = []; @@ -886,13 +889,13 @@ class ReportsController extends Controller } else { $improvementTime = intval($assetMaintenance->asset_maintenance_time); } - $row[] = $improvementTime; - $row[] = trans('general.currency').Helper::formatCurrencyOutput($assetMaintenance->cost); - $rows[] = implode($row, ','); + $row[] = $improvementTime; + $row[] = trans('general.currency') . Helper::formatCurrencyOutput($assetMaintenance->cost); + $rows[] = implode(',', $row); } // spit out a csv - $csv = implode($rows, "\n"); + $csv = implode("\n", $rows); $response = Response::make($csv, 200); $response->header('Content-Type', 'text/csv'); $response->header('Content-disposition', 'attachment;filename=report.csv'); @@ -904,42 +907,124 @@ class ReportsController extends Controller * getAssetAcceptanceReport * * @return mixed + * @throws \Illuminate\Auth\Access\AuthorizationException * @author Vincent Sposato * @version v1.0 */ - public function getAssetAcceptanceReport() + public function getAssetAcceptanceReport($deleted = false) { $this->authorize('reports.view'); + $showDeleted = $deleted == 'deleted'; /** * Get all assets with pending checkout acceptances */ - $acceptances = CheckoutAcceptance::pending()->get(); + if($showDeleted) { + $acceptances = CheckoutAcceptance::pending()->withTrashed()->with(['assignedTo' , 'checkoutable.assignedTo', 'checkoutable.model'])->get(); + } else { + $acceptances = CheckoutAcceptance::pending()->with(['assignedTo' => function ($query) { + $query->withTrashed(); + }, 'checkoutable.assignedTo', 'checkoutable.model'])->get(); + } $assetsForReport = $acceptances ->filter(function ($acceptance) { return $acceptance->checkoutable_type == \App\Models\Asset::class; }) - ->map(function ($acceptance) { - return $acceptance->checkoutable; + ->map(function($acceptance) { + return ['assetItem' => $acceptance->checkoutable, 'acceptance' => $acceptance]; }); - return view('reports/unaccepted_assets', compact('assetsForReport')); + return view('reports/unaccepted_assets', compact('assetsForReport','showDeleted' )); } /** - * exportAssetAcceptanceReport + * sentAssetAcceptanceReminder + * + * @param integer|null $acceptanceId + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + * @version v1.0 + */ + public function sentAssetAcceptanceReminder($acceptanceId = null) + { + $this->authorize('reports.view'); + + if (!$acceptance = CheckoutAcceptance::pending()->find($acceptanceId)) { + // Redirect to the unaccepted assets report page with error + return redirect()->route('reports/unaccepted_assets')->with('error', trans('general.bad_data')); + } + $assetItem = $acceptance->checkoutable; + + $logItem = $assetItem->checkouts()->where('created_at', '=', $acceptance->created_at)->get()[0]; + + if(!$assetItem->assignedTo->locale){ + Notification::locale(Setting::getSettings()->locale)->send( + $assetItem->assignedTo, + new CheckoutAssetNotification($assetItem, $assetItem->assignedTo, $logItem->user, $acceptance, $logItem->note) + ); + } else { + Notification::send( + $assetItem->assignedTo, + new CheckoutAssetNotification($assetItem, $assetItem->assignedTo, $logItem->user, $acceptance, $logItem->note) + ); + } + + return redirect()->route('reports/unaccepted_assets')->with('success', trans('admin/reports/general.reminder_sent')); + } + + /** + * sentAssetAcceptanceReminder + * + * @param integer|null $acceptanceId + * @return \Illuminate\Http\RedirectResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + * @version v1.0 + */ + public function deleteAssetAcceptance($acceptanceId = null) + { + $this->authorize('reports.view'); + + if (!$acceptance = CheckoutAcceptance::pending()->find($acceptanceId)) { + // Redirect to the unaccepted assets report page with error + return redirect()->route('reports/unaccepted_assets')->with('error', trans('general.bad_data')); + } + + if($acceptance->delete()) { + return redirect()->route('reports/unaccepted_assets')->with('success', trans('admin/reports/general.acceptance_deleted')); + } else { + return redirect()->route('reports/unaccepted_assets')->with('error', trans('general.deletion_failed')); + } + } + + /** + * Exports the AssetAcceptance report to CSV * * @return \Illuminate\Http\Response * @author Vincent Sposato * @version v1.0 */ - public function exportAssetAcceptanceReport() + public function postAssetAcceptanceReport($deleted = false) { $this->authorize('reports.view'); - // Grab all the improvements - $assetsForReport = Actionlog::whereIn('id', $this->getAssetsNotAcceptedYet()) - ->get(); + $showDeleted = $deleted == 'deleted'; + + /** + * Get all assets with pending checkout acceptances + */ + if($showDeleted) { + $acceptances = CheckoutAcceptance::pending()->withTrashed()->with(['assignedTo', 'checkoutable.assignedTo', 'checkoutable.model'])->get(); + } else { + $acceptances = CheckoutAcceptance::pending()->with(['assignedTo', 'checkoutable.assignedTo', 'checkoutable.model'])->get(); + } + + $assetsForReport = $acceptances + ->filter(function($acceptance) { + return $acceptance->checkoutable_type == 'App\Models\Asset'; + }) + ->map(function($acceptance) { + return ['assetItem' => $acceptance->checkoutable, 'acceptance' => $acceptance]; + }); $rows = []; @@ -952,20 +1037,20 @@ class ReportsController extends Controller ]; $header = array_map('trim', $header); - $rows[] = implode($header, ','); + $rows[] = implode(',', $header); - foreach ($assetsForReport as $assetItem) { - $row = []; - $row[] = str_replace(',', '', e($assetItem->assetlog->model->category->name)); - $row[] = str_replace(',', '', e($assetItem->assetlog->model->name)); - $row[] = str_replace(',', '', e($assetItem->assetlog->present()->name())); - $row[] = str_replace(',', '', e($assetItem->assetlog->asset_tag)); - $row[] = str_replace(',', '', e($assetItem->assetlog->assignedTo->present()->name())); - $rows[] = implode($row, ','); + foreach ($assetsForReport as $item) { + $row = [ ]; + $row[] = str_replace(',', '', e($item['assetItem']->model->category->name)); + $row[] = str_replace(',', '', e($item['assetItem']->model->name)); + $row[] = str_replace(',', '', e($item['assetItem']->name)); + $row[] = str_replace(',', '', e($item['assetItem']->asset_tag)); + $row[] = str_replace(',', '', e(($item['acceptance']->assignedTo) ? $item['acceptance']->assignedTo->present()->name() : trans('admin/reports/general.deleted_user'))); + $rows[] = implode(',', $row); } // spit out a csv - $csv = implode($rows, "\n"); + $csv = implode("\n", $rows); $response = Response::make($csv, 200); $response->header('Content-Type', 'text/csv'); $response->header('Content-disposition', 'attachment;filename=report.csv'); diff --git a/app/Notifications/CheckoutAssetNotification.php b/app/Notifications/CheckoutAssetNotification.php index e218a76d1..44708220a 100644 --- a/app/Notifications/CheckoutAssetNotification.php +++ b/app/Notifications/CheckoutAssetNotification.php @@ -2,6 +2,7 @@ namespace App\Notifications; +use App\Helpers\Helper; use App\Models\Asset; use App\Models\Setting; use App\Models\User; diff --git a/resources/lang/en/admin/reports/general.php b/resources/lang/en/admin/reports/general.php index 65e2bb1d7..344d5c874 100644 --- a/resources/lang/en/admin/reports/general.php +++ b/resources/lang/en/admin/reports/general.php @@ -2,4 +2,9 @@ return [ 'info' => 'Select the options you want for your asset report.', -]; + 'deleted_user' => 'Deleted user', + 'send_reminder' => 'Send reminder', + 'reminder_sent' => 'Reminder sent', + 'acceptance_deleted' => 'Acceptance request deleted', + 'acceptance_request' => 'Acceptance request' +]; \ No newline at end of file diff --git a/resources/lang/en/general.php b/resources/lang/en/general.php index 5c79f227e..6a0971cb0 100644 --- a/resources/lang/en/general.php +++ b/resources/lang/en/general.php @@ -73,6 +73,7 @@ 'delete_confirm' => 'Are you sure you wish to delete :item?', 'deleted' => 'Deleted', 'delete_seats' => 'Deleted Seats', + 'deletion_failed' => 'Deletion failed', 'departments' => 'Departments', 'department' => 'Department', 'deployed' => 'Deployed', @@ -247,4 +248,5 @@ 'show_help' => 'Show help', 'hide_help' => 'Hide help', 'view_all' => 'view all', + 'hide_deleted' => 'Hide Deleted', ]; diff --git a/resources/views/reports/unaccepted_assets.blade.php b/resources/views/reports/unaccepted_assets.blade.php index 45b6f163a..275a1c842 100644 --- a/resources/views/reports/unaccepted_assets.blade.php +++ b/resources/views/reports/unaccepted_assets.blade.php @@ -8,6 +8,25 @@ @parent @stop +@section('header_right') + + +@stop + {{-- Page content --}} @section('content') @@ -27,6 +46,7 @@ data-show-export="true" data-show-refresh="true" data-sort-order="asc" + data-sort-name="created_at" id="unacceptedAssetsReport" class="table table-striped snipe-table" data-export-options='{ @@ -35,25 +55,34 @@ }'> - {{ trans('admin/companies/table.title') }} - {{ trans('general.category') }} - {{ trans('admin/hardware/form.model') }} - {{ trans('admin/hardware/form.name') }} - {{ trans('admin/hardware/table.asset_tag') }} - {{ trans('admin/hardware/table.checkoutto') }} + {{ trans('general.date') }} + {{ trans('admin/companies/table.title') }} + {{ trans('general.category') }} + {{ trans('admin/hardware/form.model') }} + {{ trans('admin/hardware/form.name') }} + {{ trans('admin/hardware/table.asset_tag') }} + {{ trans('admin/hardware/table.checkoutto') }} + {{ trans('table.actions') }} @if ($assetsForReport) - @foreach ($assetsForReport as $assetItem) - @if ($assetItem) - - {{ ($assetItem->company) ? $assetItem->company->name : '' }} - {{ $assetItem->model->category->name }} - {{ $assetItem->model->name }} - {!! $assetItem->present()->nameUrl() !!} - {{ $assetItem->asset_tag }} - {!! ($assetItem->assignedTo) ? $assetItem->assignedTo->present()->nameUrl() : 'Deleted user' !!} + @foreach ($assetsForReport as $item) + @if ($item['assetItem']) + trashed()) style="text-decoration: line-through" @endif> + {{ $item['acceptance']->created_at }} + {{ ($item['assetItem']->company) ? $assetItem->company->name : '' }} + {!! $item['assetItem']->model->category->present()->nameUrl() !!} + {!! $item['assetItem']->present()->modelUrl() !!} + {!! $item['assetItem']->present()->nameUrl() !!} + {{ $item['assetItem']->asset_tag }} + assignedTo === null || $item['acceptance']->assignedTo->trashed()) style="text-decoration: line-through" @endif>{!! ($item['acceptance']->assignedTo) ? $item['acceptance']->assignedTo->present()->nameUrl() : trans('admin/reports/general.deleted_user') !!} + + @if(!$item['acceptance']->trashed()) + @if ($item['acceptance']->assignedTo){{ trans('admin/reports/general.send_reminder') }}@endif + + @endif + @endif @endforeach diff --git a/routes/web.php b/routes/web.php index 7a6c25bdc..96f638f28 100644 --- a/routes/web.php +++ b/routes/web.php @@ -319,12 +319,20 @@ Route::group(['middleware' => ['auth']], function () { Route::post('reports/activity', [ReportsController::class, 'postActivityReport']); Route::get( - 'reports/unaccepted_assets', + 'reports/unaccepted_assets/{deleted?}', [ReportsController::class, 'getAssetAcceptanceReport'] )->name('reports/unaccepted_assets'); Route::get( - 'reports/export/unaccepted_assets', - [ReportsController::class, 'exportAssetAcceptanceReport'] + 'reports/unaccepted_assets/{acceptanceId}/sent_reminder', + [ReportsController::class, 'sentAssetAcceptanceReminder'] + )->name('reports/unaccepted_assets_sent_reminder'); + Route::delete( + 'reports/unaccepted_assets/{acceptanceId}/delete', + [ReportsController::class, 'deleteAssetAcceptance'] + )->name('reports/unaccepted_assets_delete'); + Route::post( + 'reports/unaccepted_assets/{deleted?}', + [ReportsController::class, 'postAssetAcceptanceReport'] )->name('reports/export/unaccepted_assets'); });