mirror of
https://github.com/snipe/snipe-it.git
synced 2025-01-11 05:47:28 -08:00
Checkout Improvements, and initial support for requesting an asset model (#2573)
* Create a new action_log table to replace asset_log. Use Polymorphism to generalize class and targets. Port everything I can find to use it. Add a migration to port the asset_logs table to action_logs. * Initial work on requestable asset models * Backend work for polymorphic requests table to store checkout requests. * Add missing files * Add a record to the db when requesting items. Build up a testing route for interfacing with this. * Users can now toggle requests of items on the request page. Reformat page to use the same tab layout we use elsewhere * Polymorphic request function. Implement requesting of asset models. Need to port mail/slack to notifications still. * Implement requesting of asset models. Build up emails and notifications to support it. Allow specifying a quantity of model to request. * Add view to show currently requested assets. Needs some work and cleanup, but it isn't accessible from anywhere yet.
This commit is contained in:
parent
b0a8a0427d
commit
2d8269ddcd
|
@ -99,12 +99,12 @@ class AssetModelsController extends Controller
|
|||
$model->category_id = e(Input::get('category_id'));
|
||||
$model->note = e(Input::get('note'));
|
||||
$model->user_id = Auth::user()->id;
|
||||
$model->requestable = Input::has('requestable');
|
||||
|
||||
if (Input::get('custom_fieldset')!='') {
|
||||
$model->fieldset_id = e(Input::get('custom_fieldset'));
|
||||
}
|
||||
|
||||
//$model->show_mac_address = e(Input::get('show_mac_address', '0'));
|
||||
|
||||
|
||||
if (Input::file('image')) {
|
||||
$image = Input::file('image');
|
||||
|
@ -228,6 +228,9 @@ class AssetModelsController extends Controller
|
|||
$model->manufacturer_id = e(Input::get('manufacturer_id'));
|
||||
$model->category_id = e(Input::get('category_id'));
|
||||
$model->note = e(Input::get('note'));
|
||||
|
||||
$model->requestable = Input::has('requestable');
|
||||
|
||||
if (Input::get('custom_fieldset')=='') {
|
||||
$model->fieldset_id = null;
|
||||
} else {
|
||||
|
|
|
@ -1670,10 +1670,6 @@ class AssetsController extends Controller
|
|||
case 'Deployed':
|
||||
$assets->Deployed();
|
||||
break;
|
||||
default:
|
||||
$assets->NotArchived();
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if ($request->has('status_id')) {
|
||||
|
|
|
@ -336,7 +336,7 @@ class ConsumablesController extends Controller
|
|||
'fields' => [
|
||||
[
|
||||
'title' => 'Checked Out:',
|
||||
'value' => strtoupper($logaction->item_type).' <'.config('app.url').'/admin/consumables/'.$consumable->id.'/view'.'|'.$consumable->name.'> checked out to <'.config('app.url').'/admin/users/'.$user->id.'/view|'.$user->fullName().'> by <'.config('app.url').'/admin/users/'.$admin_user->id.'/view'.'|'.$admin_user->fullName().'>.'
|
||||
'value' => 'Consumable <'.config('app.url').'/admin/consumables/'.$consumable->id.'/view'.'|'.$consumable->name.'> checked out to <'.config('app.url').'/admin/users/'.$user->id.'/view|'.$user->fullName().'> by <'.config('app.url').'/admin/users/'.$admin_user->id.'/view'.'|'.$admin_user->fullName().'>.'
|
||||
],
|
||||
[
|
||||
'title' => 'Note:',
|
||||
|
|
|
@ -4,12 +4,14 @@ namespace App\Http\Controllers;
|
|||
use App\Models\Accessory;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\CheckoutRequest;
|
||||
use App\Models\Company;
|
||||
use App\Models\Consumable;
|
||||
use App\Models\Component;
|
||||
use App\Models\Consumable;
|
||||
use App\Models\License;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use App\Models\License;
|
||||
use Auth;
|
||||
use Config;
|
||||
use DB;
|
||||
|
@ -39,9 +41,7 @@ class ViewAssetsController extends Controller
|
|||
|
||||
$user = User::with('assets', 'assets.model', 'consumables', 'accessories', 'licenses', 'userloc')->withTrashed()->find(Auth::user()->id);
|
||||
|
||||
$userlog = $user->userlog->load('item', 'item.model', 'user', 'target');
|
||||
|
||||
|
||||
$userlog = $user->userlog->load('item', 'user', 'target');
|
||||
|
||||
if (isset($user->id)) {
|
||||
return View::make('account/view-assets', compact('user', 'userlog'));
|
||||
|
@ -60,11 +60,130 @@ class ViewAssetsController extends Controller
|
|||
{
|
||||
|
||||
$assets = Asset::with('model', 'defaultLoc', 'assetloc', 'assigneduser')->Hardware()->RequestableAssets()->get();
|
||||
$models = AssetModel::with('category')->RequestableModels()->get();
|
||||
|
||||
return View::make('account/requestable-assets', compact('user', 'assets'));
|
||||
return View::make('account/requestable-assets', compact('user', 'assets', 'models'));
|
||||
}
|
||||
|
||||
public function getRequestedIndex()
|
||||
{
|
||||
$requestedItems = CheckoutRequest::with('user', 'requestedItem')->get();
|
||||
return View::make('admin/requested-assets', compact('requestedItems'));
|
||||
}
|
||||
|
||||
|
||||
public function getRequestItem($itemType, $itemId = null)
|
||||
{
|
||||
$item = null;
|
||||
$fullItemType = 'App\\Models\\' . studly_case($itemType);
|
||||
if($itemType == "asset_model") {
|
||||
$itemType = "model";
|
||||
}
|
||||
$item = call_user_func(array($fullItemType, 'find'), $itemId);
|
||||
$user = Auth::user();
|
||||
$quantity = $data['item_quantity'] = Input::has('request-quantity') ? e(Input::get('request-quantity')) : 1;
|
||||
|
||||
$logaction = new Actionlog();
|
||||
$logaction->item_id = $data['asset_id'] = $item->id;
|
||||
$logaction->item_type = $fullItemType;
|
||||
$logaction->created_at = $data['requested_date'] = date("Y-m-d h:i:s");
|
||||
if ($user->location_id) {
|
||||
$logaction->location_id = $user->location_id;
|
||||
}
|
||||
$logaction->target_id = $data['user_id'] = Auth::user()->id;
|
||||
$logaction->target_type = User::class;
|
||||
|
||||
$data['requested_by'] = $user->fullName();
|
||||
$data['item_name'] = $item->name;
|
||||
$data['item_type'] = $itemType;
|
||||
|
||||
if ($fullItemType == Asset::class) {
|
||||
$data['item_url'] = route('view/hardware', $item->id);
|
||||
$slackMessage = ' Asset <'.config('app.url').'/hardware/'.$item->id.'/view'.'|'.$item->showAssetName().'> requested by <'.config('app.url').'/users/'.$item->user_id.'/view'.'|'.$user->fullName().'>.';
|
||||
} else {
|
||||
$data['item_url'] = route("view/${itemType}", $item->id);
|
||||
$slackMessage = $quantity. ' ' . class_basename(strtoupper($logaction->item_type)).' <'.$data['item_url'].'|'.$item->name.'> requested by <'.config('app.url').'/user/'.$item->id.'/view'.'|'.$user->fullName().'>.';
|
||||
}
|
||||
|
||||
$settings = Setting::getSettings();
|
||||
|
||||
if ($settings->slack_endpoint) {
|
||||
|
||||
$slack_settings = [
|
||||
'username' => $settings->botname,
|
||||
'channel' => $settings->slack_channel,
|
||||
'link_names' => true
|
||||
];
|
||||
|
||||
$slackClient = new \Maknz\Slack\Client($settings->slack_endpoint, $slack_settings);
|
||||
}
|
||||
|
||||
if ($item->isRequestedBy($user)) {
|
||||
|
||||
$item->cancelRequest();
|
||||
$log = $logaction->logaction('request_canceled');
|
||||
|
||||
if (($settings->alert_email!='') && ($settings->alerts_enabled=='1') && (!config('app.lock_passwords'))) {
|
||||
Mail::send('emails.asset-canceled', $data, function ($m) use ($user, $settings) {
|
||||
$m->to(explode(',', $settings->alert_email), $settings->site_name);
|
||||
$m->subject('Item Request Canceled');
|
||||
});
|
||||
}
|
||||
|
||||
if ($settings->slack_endpoint) {
|
||||
try {
|
||||
$slackClient->attach([
|
||||
'color' => 'good',
|
||||
'fields' => [
|
||||
[
|
||||
'title' => 'CANCELED:',
|
||||
'value' => $slackMessage
|
||||
]
|
||||
|
||||
]
|
||||
])->send('Item Request Canceled');
|
||||
|
||||
} catch (Exception $e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->route('requestable-assets')->with('success')->with('success', trans('admin/hardware/message.requests.canceled'));
|
||||
|
||||
} else {
|
||||
$item->request();
|
||||
|
||||
$log = $logaction->logaction('requested');
|
||||
|
||||
|
||||
if (($settings->alert_email!='') && ($settings->alerts_enabled=='1') && (!config('app.lock_passwords'))) {
|
||||
Mail::send('emails.asset-requested', $data, function ($m) use ($user, $settings) {
|
||||
$m->to(explode(',', $settings->alert_email), $settings->site_name);
|
||||
$m->subject('Item Requested');
|
||||
});
|
||||
}
|
||||
|
||||
if ($settings->slack_endpoint) {
|
||||
try {
|
||||
$slackClient->attach([
|
||||
'color' => 'good',
|
||||
'fields' => [
|
||||
[
|
||||
'title' => 'REQUESTED:',
|
||||
'value' => $slackMessage
|
||||
]
|
||||
|
||||
]
|
||||
])->send('Item Requested');
|
||||
|
||||
} catch (Exception $e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->route('requestable-assets')->with('success')->with('success', trans('admin/hardware/message.requests.success'));
|
||||
}
|
||||
}
|
||||
public function getRequestAsset($assetId = null)
|
||||
{
|
||||
|
||||
|
@ -76,6 +195,11 @@ class ViewAssetsController extends Controller
|
|||
return redirect()->route('requestable-assets')->with('error', trans('admin/hardware/message.does_not_exist_or_not_requestable'));
|
||||
} elseif (!Company::isCurrentUserHasAccess($asset)) {
|
||||
return redirect()->route('requestable-assets')->with('error', trans('general.insufficient_permissions'));
|
||||
}
|
||||
// If it's requested, cancel the request.
|
||||
if ($asset->isRequestedBy(Auth::user())) {
|
||||
$asset->cancelRequest();
|
||||
return redirect()->route('requestable-assets')->with('success')->with('success', trans('admin/hardware/message.requests.success'));
|
||||
} else {
|
||||
|
||||
$logaction = new Actionlog();
|
||||
|
@ -102,6 +226,8 @@ class ViewAssetsController extends Controller
|
|||
});
|
||||
}
|
||||
|
||||
$asset->request();
|
||||
|
||||
|
||||
if ($settings->slack_endpoint) {
|
||||
|
||||
|
@ -138,6 +264,13 @@ class ViewAssetsController extends Controller
|
|||
|
||||
}
|
||||
|
||||
public function getRequestedAssets()
|
||||
{
|
||||
$checkoutrequests = CheckoutRequest::all();
|
||||
|
||||
return View::make('account/requested-items', compact($checkoutrequests));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Get the acceptance screen
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
use App\Models\Statuslabel;
|
||||
use App\Models\CheckoutRequest;
|
||||
use App\Models\Location;
|
||||
use App\Models\Statuslabel;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -388,6 +389,14 @@ Route::group(
|
|||
|
||||
Route::group([ 'prefix' => 'admin','middleware' => ['web','auth']], function () {
|
||||
|
||||
Route::get('requests',
|
||||
// foreach( CheckoutRequest::with('user')->get() as $requestedItem) {
|
||||
// echo $requestedItem->user->username . ' requested ' . $requestedItem->requestedItem->name;
|
||||
[
|
||||
'as' => 'requests',
|
||||
'middleware' => 'authorize:admin',
|
||||
'uses' => 'ViewAssetsController@getRequestedIndex'
|
||||
]);
|
||||
# Licenses
|
||||
Route::group([ 'prefix' => 'licenses', 'middleware'=>'authorize:licenses.view' ], function () {
|
||||
|
||||
|
@ -858,6 +867,11 @@ Route::group([ 'prefix' => 'account', 'middleware' => ['web', 'auth']], function
|
|||
[ 'as' => 'account/request-asset', 'uses' => 'ViewAssetsController@getRequestAsset' ]
|
||||
);
|
||||
|
||||
Route::post(
|
||||
'request/{itemType}/{itemId}',
|
||||
[ 'as' => 'account/request-item', 'uses' => 'ViewAssetsController@getRequestItem']
|
||||
);
|
||||
|
||||
# Account Dashboard
|
||||
Route::get('/', [ 'as' => 'account', 'uses' => 'ViewAssetsController@getIndex' ]);
|
||||
|
||||
|
|
|
@ -37,6 +37,9 @@ class Actionlog extends Model implements ICompanyableChild
|
|||
public function itemType()
|
||||
{
|
||||
// dd($this);
|
||||
if($this->item_type == AssetModel::class) {
|
||||
return "model";
|
||||
}
|
||||
return camel_case(class_basename($this->item_type));
|
||||
}
|
||||
|
||||
|
@ -50,8 +53,6 @@ class Actionlog extends Model implements ICompanyableChild
|
|||
|
||||
public function userlog()
|
||||
{
|
||||
|
||||
// return $this->belongsTo(User::class, 'target_id')
|
||||
return $this->target();
|
||||
}
|
||||
|
||||
|
@ -68,13 +69,11 @@ class Actionlog extends Model implements ICompanyableChild
|
|||
|
||||
public function childlogs()
|
||||
{
|
||||
|
||||
return $this->hasMany('\App\Models\ActionLog', 'thread_id');
|
||||
}
|
||||
|
||||
public function parentlog()
|
||||
{
|
||||
|
||||
return $this->belongsTo('\App\Models\ActionLog', 'thread_id');
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ use App\Models\Actionlog;
|
|||
use App\Models\Company;
|
||||
use App\Models\Location;
|
||||
use App\Models\Loggable;
|
||||
use App\Models\Requestable;
|
||||
use App\Models\Setting;
|
||||
use Auth;
|
||||
use Config;
|
||||
|
@ -26,6 +27,7 @@ class Asset extends Depreciable
|
|||
{
|
||||
use Loggable;
|
||||
use SoftDeletes;
|
||||
use Requestable;
|
||||
|
||||
/**
|
||||
* The database table used by the model.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Requestable;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
|
@ -14,6 +15,7 @@ use Watson\Validating\ValidatingTrait;
|
|||
class AssetModel extends Model
|
||||
{
|
||||
use SoftDeletes;
|
||||
use Requestable;
|
||||
protected $dates = ['deleted_at'];
|
||||
protected $table = 'models';
|
||||
|
||||
|
@ -131,6 +133,22 @@ class AssetModel extends Model
|
|||
return $query->whereIn('category_id', $categoryIdListing);
|
||||
}
|
||||
|
||||
/**
|
||||
* scopeRequestable
|
||||
* Get all models that are requestable by a user.
|
||||
*
|
||||
* @param $query
|
||||
*
|
||||
* @return $query
|
||||
* @author Daniel Meltzer <parallelgrapefruit@gmail.com
|
||||
* @version v3.5
|
||||
*/
|
||||
public function scopeRequestableModels($query)
|
||||
{
|
||||
|
||||
return $query->where('requestable', '1');
|
||||
}
|
||||
|
||||
/**
|
||||
* Query builder scope to search on text
|
||||
*
|
||||
|
|
59
app/Models/CheckoutRequest.php
Normal file
59
app/Models/CheckoutRequest.php
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class CheckoutRequest extends Model
|
||||
{
|
||||
//
|
||||
protected $fillable = ['user_id'];
|
||||
protected $table = 'checkout_requests';
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function requestingUser()
|
||||
{
|
||||
return $this->user()->first();
|
||||
}
|
||||
|
||||
public function requestedItem()
|
||||
{
|
||||
return $this->morphTo('requestable');
|
||||
}
|
||||
|
||||
public function itemRequested() // Workaround for laravel polymorphic issue that's not being solved :(
|
||||
{
|
||||
return $this->requestedItem()->first();
|
||||
}
|
||||
|
||||
public function itemType()
|
||||
{
|
||||
return snake_case(class_basename($this->requestable_type));
|
||||
}
|
||||
|
||||
public function location()
|
||||
{
|
||||
if ($this->itemType() == "asset") {
|
||||
$asset = $this->itemRequested();
|
||||
if ($asset->assigneduser && $asset->assetloc) {
|
||||
return $asset->assetloc;
|
||||
} elseif ($asset->defaultLoc) {
|
||||
return $asset->defaultLoc;
|
||||
}
|
||||
}
|
||||
return $this->itemRequested()->location;
|
||||
}
|
||||
|
||||
public function name()
|
||||
{
|
||||
if ($this->itemType() == "asset") {
|
||||
return $this->itemRequested()->showAssetName();
|
||||
}
|
||||
return $this->itemRequested()->name;
|
||||
|
||||
}
|
||||
}
|
|
@ -80,5 +80,4 @@ trait Loggable
|
|||
|
||||
return $log;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
45
app/Models/Requestable.php
Normal file
45
app/Models/Requestable.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\CheckoutRequest;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
// $asset->requests
|
||||
// $asset->isRequestedBy($user)
|
||||
// $asset->whereRequestedBy($user)
|
||||
trait Requestable
|
||||
{
|
||||
|
||||
public function requests()
|
||||
{
|
||||
return $this->morphMany(CheckoutRequest::class, 'requestable');
|
||||
}
|
||||
|
||||
public function isRequestedBy(User $user)
|
||||
{
|
||||
return $this->requests()
|
||||
->where('user_id', $user->id)
|
||||
->exists();
|
||||
}
|
||||
|
||||
public function scopeRequestedBy($query, User $user)
|
||||
{
|
||||
return $query->whereHas('requests', function ($query) use ($user) {
|
||||
$query->where('user_id', $user->id);
|
||||
});
|
||||
}
|
||||
|
||||
public function request()
|
||||
{
|
||||
$this->requests()->save(
|
||||
new CheckoutRequest(['user_id' => Auth::id()])
|
||||
);
|
||||
}
|
||||
|
||||
public function cancelRequest()
|
||||
{
|
||||
$this->requests()->where('user_id', Auth::id())->delete();
|
||||
}
|
||||
}
|
|
@ -261,6 +261,14 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
|||
->orderBy('created_at', 'desc');
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch Items User has requested
|
||||
*/
|
||||
public function checkoutRequests()
|
||||
{
|
||||
return $this->belongsToMany(Asset::class, 'checkout_requests');
|
||||
}
|
||||
|
||||
public function throttle()
|
||||
{
|
||||
return $this->hasOne('\App\Models\Throttle');
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddRequestableToAssetModel extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
//
|
||||
Schema::table('models', function ($table) {
|
||||
$table->tinyInteger('requestable')->default(0);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
Schema::table('models', function ($table) {
|
||||
$table->dropColumn('requestable');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateCheckoutRequestsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('checkout_requests', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('user_id');
|
||||
$table->integer('requestable_id');
|
||||
$table->string('requestable_type');
|
||||
$table->integer('quantity')->default(1);
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['user_id', 'requestable_id', 'requestable_type']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::drop('checkout_requests');
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ return array(
|
|||
'filetype_info' => 'Allowed filetypes are png, gif, jpg, jpeg, doc, docx, pdf, txt, zip, and rar.',
|
||||
'model_deleted' => 'This Assets model has been deleted. You must restore the model before you can restore the Asset.<br/> <a href="/hardware/models/:model_id/restore">Click here to restore the model</a>.',
|
||||
'requestable' => 'Requestable',
|
||||
'requested' => 'Requested',
|
||||
'restore' => 'Restore Asset',
|
||||
'pending' => 'Pending',
|
||||
'undeployable' => 'Undeployable',
|
||||
|
|
|
@ -69,6 +69,7 @@ return array(
|
|||
'requests' => array(
|
||||
'error' => 'Asset was not requested, please try again',
|
||||
'success' => 'Asset requested successfully.',
|
||||
'canceled' => 'Checkout request successfully canceled'
|
||||
)
|
||||
|
||||
);
|
||||
|
|
|
@ -4,6 +4,7 @@ return array(
|
|||
|
||||
'deleted' => 'This model has been deleted. <a href="/hardware/models/:model_id/restore">Click here to restore it</a>.',
|
||||
'restore' => 'Restore Model',
|
||||
'requestable' => 'Users may request this model',
|
||||
'show_mac_address' => 'Show MAC address field in assets in this model',
|
||||
'view_deleted' => 'View Deleted',
|
||||
'view_models' => 'View Models',
|
||||
|
|
|
@ -127,6 +127,7 @@
|
|||
'remove_company' => 'Remove Company Association',
|
||||
'reports' => 'Reports',
|
||||
'requested' => 'Requested',
|
||||
'request_canceled' => 'Request Canceled',
|
||||
'save' => 'Save',
|
||||
'select' => 'Select',
|
||||
'search' => 'Search',
|
||||
|
|
|
@ -13,18 +13,25 @@
|
|||
{{-- Page content --}}
|
||||
@section('content')
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
|
||||
<div class="box box-default">
|
||||
<div class="box-body">
|
||||
<div class="nav-tabs-custom">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active">
|
||||
<a href="#assets" data-toggle="tab" title="{{ trans('general.assets') }}">{{ trans('general.assets') }}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#models" data-toggle="tab" title="{{ trans('general.asset_models') }}">{{ trans('general.asset_models') }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane fade in active" id="assets">
|
||||
|
||||
@if ($assets->count() > 0)
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
|
||||
<thead>
|
||||
<tr role="row">
|
||||
<th class="col-md-3" bSortable="true">{{ trans('admin/hardware/table.asset_model') }}</th>
|
||||
|
@ -36,9 +43,11 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
@foreach ($assets as $asset)
|
||||
|
||||
<tr>
|
||||
<form action="{{route('account/request-item', ['itemType' => 'asset', 'itemId' => $asset->id])}}" method="POST" accept-charset="utf-8">
|
||||
{{ csrf_field() }}
|
||||
<td>{{ $asset->model->name }}</td>
|
||||
|
||||
@if (\App\Models\Setting::getSettings()->display_asset_name)
|
||||
|
@ -47,8 +56,6 @@
|
|||
|
||||
<td>{{ $asset->serial }}</td>
|
||||
|
||||
|
||||
|
||||
<td>
|
||||
@if ($asset->assigneduser && $asset->assetloc)
|
||||
{{ $asset->assetloc->name }}
|
||||
|
@ -64,14 +71,70 @@
|
|||
<td>{{ trans('admin/hardware/general.requestable') }}</td>
|
||||
@endif
|
||||
|
||||
|
||||
<td>{{ $asset->expected_checkin }}</td>
|
||||
|
||||
|
||||
<td>
|
||||
<a href="{{ route('account/request-asset', $asset->id) }}" class="btn btn-info btn-sm" title="{{ trans('button.request') }}">{{ trans('button.request') }}</a>
|
||||
@if ($asset->isRequestedBy(Auth::user()))
|
||||
{{Form::submit(trans('button.cancel'), ['class' => 'btn btn-danger btn-sm'])}}
|
||||
@else
|
||||
{{Form::submit(trans('button.request'), ['class' => 'btn btn-primary btn-sm'])}}
|
||||
@endif
|
||||
</td>
|
||||
</form>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
@else
|
||||
<div class="col-md-12">
|
||||
<div class="alert alert-info alert-block">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
{{ trans('general.no_results') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="models">
|
||||
|
||||
@if ($models->count() > 0)
|
||||
<h4>Requestable Models</h4>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr role="row">
|
||||
<th class="col-md-6" bSortable="true">{{ trans('admin/hardware/table.asset_model') }}</th>
|
||||
<th class="col-md-3" bSortable="true">{{ trans('admin/accessories/general.remaining') }}</th>
|
||||
<th class="col-md-2" bSortable="true">{{ trans('general.quantity') }}</th>
|
||||
<th class="col-md-1 actions" bSortable="false">{{ trans('table.actions') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
@foreach($models as $requestableModel)
|
||||
|
||||
<tr>
|
||||
<form action="{{route('account/request-item', ['itemType' => 'asset_model', 'itemId' => $requestableModel->id])}}"
|
||||
method="POST"
|
||||
accept-charset="utf-8"
|
||||
>
|
||||
{{ csrf_field() }}
|
||||
<td>{{$requestableModel->name}}</td>
|
||||
<td>{{$requestableModel->assets()->where('requestable', '1')->count()}}</td>
|
||||
<td><input type="text" name="request-quantity" value=""></td>
|
||||
<td>
|
||||
@if ($requestableModel->isRequestedBy(Auth::user()))
|
||||
{{Form::submit(trans('button.cancel'), ['class' => 'btn btn-danger btn-sm'])}}
|
||||
@else
|
||||
{{Form::submit(trans('button.request'), ['class' => 'btn btn-primary btn-sm'])}}
|
||||
@endif
|
||||
</td>
|
||||
</form>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
|
@ -84,15 +147,26 @@
|
|||
{{ trans('general.no_results') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@endif
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> <!-- .tab-content-->
|
||||
</div> <!-- .nav-tabs-custom -->
|
||||
</div> <!-- .col-md-12> -->
|
||||
</div> <!-- .row -->
|
||||
|
||||
|
||||
|
||||
@stop
|
||||
@section('moar_scripts')
|
||||
<script>
|
||||
|
||||
$( "a[name='Request']").click(function(event) {
|
||||
// event.preventDefault();
|
||||
quantity = $(this).closest('td').siblings().find('input').val();
|
||||
currentUrl = $(this).attr('href');
|
||||
// $(this).attr('href', currentUrl + '?quantity=' + quantity);
|
||||
// alert($(this).attr('href'));
|
||||
});
|
||||
</script>
|
||||
@stop
|
||||
|
|
|
@ -231,7 +231,7 @@ View Assets for {{ $user->fullName() }}
|
|||
@endif
|
||||
|
||||
<div class="box-body">
|
||||
@if (count($user->userlog) > 0)
|
||||
@if (count($userlog) > 0)
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped" id="example">
|
||||
<thead>
|
||||
|
@ -244,7 +244,7 @@ View Assets for {{ $user->fullName() }}
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($user->userlog as $log)
|
||||
@foreach ($userlog as $log)
|
||||
<tr>
|
||||
<td class="text-center">
|
||||
@if ($log->itemType()=="asset")
|
||||
|
@ -260,14 +260,13 @@ View Assets for {{ $user->fullName() }}
|
|||
@endif
|
||||
|
||||
</td>
|
||||
<td>{{ $log->action_type }}</td>
|
||||
<td>
|
||||
|
||||
{{ strtolower(trans('general.'.str_replace(' ','_',$log->action_type))) }}
|
||||
</td>
|
||||
<td>
|
||||
@if ($log->itemType()=="asset")
|
||||
@if ($log->item->deleted_at=='')
|
||||
|
||||
{{ $log->item->showAssetName() }}
|
||||
|
||||
@else
|
||||
<del>{{ $log->item->showAssetName() }}</del> (deleted)
|
||||
@endif
|
||||
|
|
84
resources/views/admin/requested-assets.blade.php
Normal file
84
resources/views/admin/requested-assets.blade.php
Normal file
|
@ -0,0 +1,84 @@
|
|||
@extends('layouts/default')
|
||||
|
||||
@section('title0')
|
||||
{{ trans('admin/hardware/general.requested') }}
|
||||
{{ trans('general.assets') }}
|
||||
@stop
|
||||
|
||||
{{-- Page title --}}
|
||||
@section('title')
|
||||
@yield('title0') @parent
|
||||
@stop
|
||||
|
||||
{{-- Page content --}}
|
||||
@section('content')
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
|
||||
@if ($requestedItems->count() > 0)
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr role="row">
|
||||
<th class="col-md-1">Item Type</th>
|
||||
<th class="col-md-1">Item Name</th>
|
||||
<th class="col-md-1" bSortable="true">{{ trans('admin/hardware/table.location') }}</th>
|
||||
<th class="col-md-1" bSortable="true">{{ trans('admin/hardware/form.expected_checkin') }}</th>
|
||||
<th class="col-md-1" bSortable="true">Requesting User</th>
|
||||
<th class="col-md-1">Requested Date</th>
|
||||
<th class="col-md-1 actions" bSortable="false">{{ trans('table.actions') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($requestedItems as $request)
|
||||
|
||||
<tr>
|
||||
|
||||
<form action="#" method="POST" accept-charset="utf-8">
|
||||
{{ csrf_field() }}
|
||||
<td>{{ $request->itemType() }}</td>
|
||||
<td>{{ $request->name() }}</td>
|
||||
@if ($request->location())
|
||||
<td>{{ $request->location()->name }}</td>
|
||||
@else
|
||||
<td></td>
|
||||
@endif
|
||||
|
||||
<td>
|
||||
@if ($request->itemType() == "asset")
|
||||
{{ $request->itemRequested()->expected_checkin }}
|
||||
@else
|
||||
"N/A"
|
||||
@endif
|
||||
</td>
|
||||
<td>{{ $request->requestingUser()->fullName() }}</td>
|
||||
<td>{{$request->created_at}}</td>
|
||||
<td>
|
||||
</td>
|
||||
</form>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
@else
|
||||
<div class="col-md-12">
|
||||
<div class="alert alert-info alert-block">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
{{ trans('general.no_results') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@endif
|
||||
</div>
|
||||
</div> <!-- .col-md-12> -->
|
||||
</div> <!-- .row -->
|
||||
|
||||
|
||||
|
||||
@stop
|
|
@ -127,7 +127,7 @@
|
|||
</td>
|
||||
<td>{{ date("M d, Y g:iA", strtotime($activity->created_at)) }}</td>
|
||||
<td>
|
||||
@if ($activity->action_type!='requested')
|
||||
@if (($activity->action_type!='requested') && ($activity->action_type!="request_canceled"))
|
||||
@if ($activity->user)
|
||||
<a href="{{ route('view/user', $activity->user_id) }}">{{ $activity->user->fullName() }}</a>
|
||||
@else
|
||||
|
@ -157,7 +157,6 @@
|
|||
<a href="{{route('view/user', $activity->target_id) }}"> {{ $activity->target->fullName() }}</a>
|
||||
@elseif ($activity->action_type=='requested') <!--The user is who requested the item, not the target-->
|
||||
<a href="{{ route('view/user', $activity->user_id) }}">{{ $activity->user->fullName() }}</a>
|
||||
|
||||
@endif
|
||||
|
||||
</td>
|
||||
|
|
12
resources/views/emails/asset-canceled.blade.php
Normal file
12
resources/views/emails/asset-canceled.blade.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
@extends('emails/layouts/default')
|
||||
|
||||
@section('content')
|
||||
|
||||
<p>A user has canceled an item request on the <a href="{{ config('app.url') }}">{{ \App\Models\Setting::getSettings()->site_name }} website</a>. </p>
|
||||
|
||||
<p>User: <a href="{{ config('app.url') }}/admin/users/{{ $user_id }}/view">{{ $requested_by }}</a><br>
|
||||
Item: <a href="{{ $item_url }}">{{ $item_name }}</a> ({{ $item_type }}) <br>
|
||||
Canceled: {{ $requested_date }}
|
||||
</p>
|
||||
|
||||
@stop
|
|
@ -2,11 +2,14 @@
|
|||
|
||||
@section('content')
|
||||
|
||||
<p>A user has requested an asset on the <a href="{{ config('app.url') }}">{{ \App\Models\Setting::getSettings()->site_name }} website</a>. </p>
|
||||
<p>A user has requested an item on the <a href="{{ config('app.url') }}">{{ \App\Models\Setting::getSettings()->site_name }} website</a>. </p>
|
||||
|
||||
<p>User: <a href="{{ config('app.url') }}/admin/users/{{ $user_id }}/view">{{ $requested_by }}</a><br>
|
||||
Asset: <a href="{{ config('app.url') }}/hardware/{{ $asset_id }}/view">{{ $asset_name }}</a> ({{ $asset_type }}) <br>
|
||||
Item: <a href="{{ $item_url }}">{{ $item_name }}</a> ({{ $item_type }}) <br>
|
||||
Requested: {{ $requested_date }}
|
||||
@if ($item_quantity > 1)
|
||||
Quantity: {{ $item_quantity}}
|
||||
@endif
|
||||
</p>
|
||||
|
||||
@stop
|
||||
|
|
|
@ -523,7 +523,6 @@
|
|||
</td>
|
||||
<td>{{ $log->action_type }}</td>
|
||||
<td>
|
||||
|
||||
@if ($log->action_type=='uploaded')
|
||||
|
||||
{{ $log->filename }}
|
||||
|
|
|
@ -118,6 +118,15 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Requestable -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-3 col-sm-10">
|
||||
<label>
|
||||
<input type="checkbox" value="1" name="requestable" id="requestable" class="minimal" {{ Input::old('requestable', $model->requestable) == '1' ? ' checked="checked"' : '' }}> {{ trans('admin/models/general.requestable') }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Image -->
|
||||
@if ($model->image)
|
||||
<div class="form-group {{ $errors->has('image_delete') ? 'has-error' : '' }}">
|
||||
|
|
Loading…
Reference in a new issue