* Prevent multiple checkouts of the same asset.

This adds a new method to the Asset model, availableForCheckout.
Port getDataTable to use availableForCheckout instead of doing the
check manually.

Fixes Issue #2347

* Use availableForCheckout in categories controller.  Also gate the checkin/checkout actions here.

* Use gate and availableForCheckout in manufactuers as well.
This commit is contained in:
Daniel Meltzer 2016-08-16 15:02:42 -05:00 committed by snipe
parent 7edf1db101
commit a852c624d3
5 changed files with 48 additions and 37 deletions

View file

@ -530,6 +530,8 @@ class AssetsController extends Controller
return redirect()->to('hardware')->with('error', trans('admin/hardware/message.does_not_exist')); return redirect()->to('hardware')->with('error', trans('admin/hardware/message.does_not_exist'));
} elseif (!Company::isCurrentUserHasAccess($asset)) { } elseif (!Company::isCurrentUserHasAccess($asset)) {
return redirect()->to('hardware')->with('error', trans('general.insufficient_permissions')); return redirect()->to('hardware')->with('error', trans('general.insufficient_permissions'));
} elseif (!$asset->availableForCheckout()) {
return redirect()->to('hardware')->with('error', trans('admin/hardware/message.checkout.not_available'));
} }
$user = User::find(e(Input::get('assigned_to'))); $user = User::find(e(Input::get('assigned_to')));
@ -1725,19 +1727,17 @@ class AssetsController extends Controller
$actions = '<a href="'.route('restore/hardware', $asset->id).'" title="Restore asset" data-toggle="tooltip" class="btn btn-warning btn-sm"><i class="fa fa-recycle icon-white"></i></a>'; $actions = '<a href="'.route('restore/hardware', $asset->id).'" title="Restore asset" data-toggle="tooltip" class="btn btn-warning btn-sm"><i class="fa fa-recycle icon-white"></i></a>';
} }
if ($asset->assetstatus) { if (($asset->availableForCheckout()))
if (($asset->assetstatus->deployable != 0) && ($asset->deleted_at=='')) { {
if (($asset->assigned_to !='') && ($asset->assigned_to > 0)) { if (Gate::allows('assets.checkout')) {
if (Gate::allows('assets.checkin')) { $inout = '<a href="' . route('checkout/hardware',
$inout = '<a href="' . route('checkin/hardware', $asset->id) . '" class="btn btn-info btn-sm" title="Checkout this asset to a user" data-toggle="tooltip">' . trans('general.checkout') . '</a>';
$asset->id) . '" class="btn btn-primary btn-sm" title="Checkin this asset" data-toggle="tooltip">' . trans('general.checkin') . '</a>'; }
}
} else { } else {
if (Gate::allows('assets.checkout')) { if (Gate::allows('assets.checkin')) {
$inout = '<a href="' . route('checkout/hardware', $inout = '<a href="' . route('checkin/hardware',
$asset->id) . '" class="btn btn-info btn-sm" title="Checkout this asset to a user" data-toggle="tooltip">' . trans('general.checkout') . '</a>'; $asset->id) . '" class="btn btn-primary btn-sm" title="Checkin this asset" data-toggle="tooltip">' . trans('general.checkin') . '</a>';
}
}
} }
} }

View file

@ -1,13 +1,14 @@
<?php <?php
namespace App\Http\Controllers; namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Helpers\Helper; use App\Helpers\Helper;
use App\Models\Category as Category; use App\Models\Category as Category;
use App\Models\Company; use App\Models\Company;
use App\Models\Setting; use App\Models\Setting;
use Auth; use Auth;
use DB; use DB;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
use Input; use Input;
use Lang; use Lang;
use Redirect; use Redirect;
@ -344,13 +345,13 @@ class CategoriesController extends Controller
$actions = '<a href="'.route('restore/hardware', $asset->id).'" class="btn btn-warning btn-sm"><i class="fa fa-recycle icon-white"></i></a>'; $actions = '<a href="'.route('restore/hardware', $asset->id).'" class="btn btn-warning btn-sm"><i class="fa fa-recycle icon-white"></i></a>';
} }
if ($asset->assetstatus) { if ($asset->availableForCheckout()) {
if ($asset->assetstatus->deployable != 0) { if (Gate::allows('assets.checkout')) {
if (($asset->assigned_to !='') && ($asset->assigned_to > 0)) { $inout = '<a href="'.route('checkout/hardware', $asset->id).'" class="btn btn-info btn-sm">'.trans('general.checkout').'</a>';
$inout = '<a href="'.route('checkin/hardware', $asset->id).'" class="btn btn-primary btn-sm">'.trans('general.checkin').'</a>'; }
} else { } else {
$inout = '<a href="'.route('checkout/hardware', $asset->id).'" class="btn btn-info btn-sm">'.trans('general.checkout').'</a>'; if (Gate::allows('assets.checkin')) {
} $inout = '<a href="'.route('checkin/hardware', $asset->id).'" class="btn btn-primary btn-sm">'.trans('general.checkin').'</a>';
} }
} }

View file

@ -2,14 +2,15 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Models\Company; use App\Models\Company;
use App\Models\Manufacturer;
use App\Models\Setting;
use Auth;
use Illuminate\Support\Facades\Gate;
use Input; use Input;
use Lang; use Lang;
use App\Models\Manufacturer;
use Redirect; use Redirect;
use App\Models\Setting;
use Str; use Str;
use View; use View;
use Auth;
/** /**
* This controller handles all actions related to Manufacturers for * This controller handles all actions related to Manufacturers for
@ -293,13 +294,13 @@ class ManufacturersController extends Controller
$actions = '<a href="'.route('restore/hardware', $asset->id).'" class="btn btn-warning btn-sm"><i class="fa fa-recycle icon-white"></i></a>'; $actions = '<a href="'.route('restore/hardware', $asset->id).'" class="btn btn-warning btn-sm"><i class="fa fa-recycle icon-white"></i></a>';
} }
if ($asset->assetstatus) { if ($asset->availableForCheckout()) {
if ($asset->assetstatus->deployable != 0) { if (Gate::allows('assets.checkout')) {
if (($asset->assigned_to !='') && ($asset->assigned_to > 0)) { $inout = '<a href="'.route('checkout/hardware', $asset->id).'" class="btn btn-info btn-sm">'.trans('general.checkout').'</a>';
$inout = '<a href="'.route('checkin/hardware', $asset->id).'" class="btn btn-primary btn-sm">'.trans('general.checkin').'</a>'; }
} else { } else {
$inout = '<a href="'.route('checkout/hardware', $asset->id).'" class="btn btn-info btn-sm">'.trans('general.checkout').'</a>'; if (Gate::allows('assets.checkin')) {
} $inout = '<a href="'.route('checkin/hardware', $asset->id).'" class="btn btn-primary btn-sm">'.trans('general.checkin').'</a>';
} }
} }

View file

@ -72,16 +72,26 @@ class Asset extends Depreciable
} }
public function availableForCheckout()
{
return (
empty($this->assigned_to) &&
$this->assetstatus->deployable == 1 &&
empty($this->deleted_at)
);
}
/** /**
* Checkout asset * Checkout asset
*/ */
public function checkOutToUser($user, $admin, $checkout_at = null, $expected_checkin = null, $note = null, $name = null) public function checkOutToUser($user, $admin, $checkout_at = null, $expected_checkin = null, $note = null, $name = null)
{ {
if (!$user) {
return false;
}
if ($expected_checkin) { if ($expected_checkin) {
$this->expected_checkin = $expected_checkin ; $this->expected_checkin = $expected_checkin;
} }
$this->last_checkout = $checkout_at; $this->last_checkout = $checkout_at;
@ -95,9 +105,7 @@ class Asset extends Depreciable
$this->accepted="pending"; $this->accepted="pending";
} }
if (!$user) {
return false;
}
if ($this->save()) { if ($this->save()) {

View file

@ -52,7 +52,8 @@ return array(
'checkout' => array( 'checkout' => array(
'error' => 'Asset was not checked out, please try again', 'error' => 'Asset was not checked out, please try again',
'success' => 'Asset checked out successfully.', 'success' => 'Asset checked out successfully.',
'user_does_not_exist' => 'That user is invalid. Please try again.' 'user_does_not_exist' => 'That user is invalid. Please try again.',
'not_available' => 'That asset is not available for checkout!'
), ),
'checkin' => array( 'checkin' => array(