Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP - Fixes #15185 - adds accessories to locations and asset screens #15235

Closed
wants to merge 28 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/Http/Controllers/Api/AccessoriesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ public function accessory_detail($id)
* @param int $id
* @return \Illuminate\Http\Response
*/
public function checkedout($id, Request $request)
public function checkedout(Request $request, $id)
{
$this->authorize('view', Accessory::class);

Expand Down Expand Up @@ -216,7 +216,7 @@ public function checkedout($id, Request $request)
$total = $accessory_checkouts->count();
}

return (new AccessoriesTransformer)->transformCheckedoutAccessory($accessory, $accessory_checkouts, $total);
return (new AccessoriesTransformer)->transformCheckedoutAccessory($accessory_checkouts, $total);
}


Expand Down
2 changes: 1 addition & 1 deletion app/Http/Controllers/Api/AssetsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public function index(Request $request, $action = null, $upcoming_status = null)
}

$assets = Asset::select('assets.*')
->with('location', 'assetstatus', 'company', 'defaultLoc','assignedTo',
->with('model', 'location', 'assetstatus', 'company', 'defaultLoc','assignedTo',
'model.category', 'model.manufacturer', 'model.fieldset','supplier'); //it might be tempting to add 'assetlog' here, but don't. It blows up update-heavy users.


Expand Down
23 changes: 21 additions & 2 deletions app/Http/Controllers/Api/LocationsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
use App\Helpers\Helper;
use App\Http\Requests\ImageUploadRequest;
use App\Http\Controllers\Controller;
use App\Http\Transformers\AccessoriesTransformer;
use App\Http\Transformers\AssetsTransformer;
use App\Http\Transformers\LocationsTransformer;
use App\Http\Transformers\SelectlistTransformer;
use App\Models\AccessoryCheckout;
use App\Models\Asset;
use App\Models\Location;
use App\Models\Accessory;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
Expand Down Expand Up @@ -41,11 +44,11 @@ public function index(Request $request) : JsonResponse | array
'manager_id',
'image',
'assigned_assets_count',
'assigned_accessories_count',
'users_count',
'assets_count',
'assigned_assets_count',
'assets_count',
'rtd_assets_count',
'accessories_count',
'currency',
'ldap_ou',
];
Expand All @@ -70,6 +73,8 @@ public function index(Request $request) : JsonResponse | array
'locations.currency',
])->withCount('assignedAssets as assigned_assets_count')
->withCount('assets as assets_count')
->withCount('assignedAccessories as assigned_accessories_count')
->withCount('accessories as accessories_count')
->withCount('rtd_assets as rtd_assets_count')
->withCount('children as children_count')
->withCount('users as users_count');
Expand Down Expand Up @@ -233,6 +238,20 @@ public function assets(Request $request, Location $location) : JsonResponse | ar
return (new AssetsTransformer)->transformAssets($assets, $assets->count(), $request);
}

public function assignedAccessories(Request $request, Location $location) : JsonResponse | array
{
$this->authorize('view', Accessory::class);
$this->authorize('view', $location);
$accessory_checkouts = AccessoryCheckout::LocationAssigned()->with('admin')->with('accessories')->where('assigned_to', '=', $location->id);

$offset = ($request->input('offset') > $accessory_checkouts->count()) ? $accessory_checkouts->count() : app('api_offset_value');
$limit = app('api_limit_value');

$total = $accessory_checkouts->count();
$accessory_checkouts = $accessory_checkouts->skip($offset)->take($limit)->get();
return (new LocationsTransformer)->transformCheckedoutAccessories($accessory_checkouts, $total);
}

/**
* Remove the specified resource from storage.
*
Expand Down
30 changes: 15 additions & 15 deletions app/Http/Transformers/AccessoriesTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,21 @@ public function transformAccessory(Accessory $accessory)
return $array;
}

public function transformCheckedoutAccessory($accessory, $accessory_checkouts, $total)
public function transformCheckedoutAccessory($accessory_checkouts, $total)
{
$array = [];

$array = [];
foreach ($accessory_checkouts as $checkout) {
$array[] = [
'id' => $checkout->id,
'assigned_to' => $this->transformAssignedTo($checkout),
'checkout_notes' => e($checkout->note),
'last_checkout' => Helper::getFormattedDateObject($checkout->created_at, 'datetime'),
'available_actions' => ['checkin' => true],
'note' => $checkout->note ? e($checkout->note) : null,
'created_by' => $checkout->admin ? [
'id' => (int) $checkout->admin->id,
'name'=> e($checkout->admin->present()->fullName),
]: null,
'created_at' => Helper::getFormattedDateObject($checkout->created_at, 'datetime'),
'available_actions' => Gate::allows('checkout', Accessory::class) ? ['checkin' => true] : ['checkin' => false],
];
}

Expand All @@ -85,17 +89,13 @@ public function transformCheckedoutAccessory($accessory, $accessory_checkouts, $

public function transformAssignedTo($accessoryCheckout)
{

if ($accessoryCheckout->checkedOutToUser()) {
return [
'id' => (int) $accessoryCheckout->assigned->id,
'username' => e($accessoryCheckout->assigned->username),
'name' => e($accessoryCheckout->assigned->getFullNameAttribute()),
'first_name'=> e($accessoryCheckout->assigned->first_name),
'last_name'=> ($accessoryCheckout->assigned->last_name) ? e($accessoryCheckout->assigned->last_name) : null,
'email'=> ($accessoryCheckout->assigned->email) ? e($accessoryCheckout->assigned->email) : null,
'employee_number' => ($accessoryCheckout->assigned->employee_num) ? e($accessoryCheckout->assigned->employee_num) : null,
'type' => 'user',
];
return (new UsersTransformer)->transformUserCompact($accessoryCheckout->assigned);
} elseif ($accessoryCheckout->checkedOutToLocation()) {
return (new LocationsTransformer())->transformLocationCompact($accessoryCheckout->assigned);
} elseif ($accessoryCheckout->checkedOutToAsset()) {
return (new AssetsTransformer())->transformAssetCompact($accessoryCheckout->assigned);
}

return $accessoryCheckout->assigned ? [
Expand Down
18 changes: 18 additions & 0 deletions app/Http/Transformers/AssetsTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -266,5 +266,23 @@ public function transformRequestedAsset(Asset $asset)
return $array;


}

public function transformAssetCompact(Asset $asset)
{
$array = [
'id' => (int) $asset->id,
'image' => ($asset->getImageUrl()) ? $asset->getImageUrl() : null,
'type' => 'asset',
'name' => e($asset->present()->fullName()),
'model' => ($asset->model) ? e($asset->model->name) : null,
'model_number' => (($asset->model) && ($asset->model->model_number)) ? e($asset->model->model_number) : null,
'asset_tag' => e($asset->asset_tag),
'serial' => e($asset->serial),
];

return $array;


}
}
58 changes: 58 additions & 0 deletions app/Http/Transformers/LocationsTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace App\Http\Transformers;

use App\Helpers\Helper;
use App\Models\Accessory;
use App\Models\Location;
use Illuminate\Support\Facades\Gate;
use Illuminate\Database\Eloquent\Collection;
Expand Down Expand Up @@ -45,6 +46,8 @@ public function transformLocation(Location $location = null)
'zip' => ($location->zip) ? e($location->zip) : null,
'phone' => ($location->phone!='') ? e($location->phone): null,
'fax' => ($location->fax!='') ? e($location->fax): null,
'accessories_count' => (int) $location->accessories_count,
'assigned_accessories_count' => (int) $location->assigned_accessories_count,
'assigned_assets_count' => (int) $location->assigned_assets_count,
'assets_count' => (int) $location->assets_count,
'rtd_assets_count' => (int) $location->rtd_assets_count,
Expand Down Expand Up @@ -76,4 +79,59 @@ public function transformLocation(Location $location = null)
return $array;
}
}

public function transformCheckedoutAccessories($accessory_checkouts, $total)
{

$array = [];
foreach ($accessory_checkouts as $checkout) {
$array = [
'id' => $checkout->id,
'accessory' => [
'id' => $checkout->accessory->id,
'name' => $checkout->accessory->name,
],
'image' => ($checkout->accessory->image) ? Storage::disk('public')->url('accessories/'.e($checkout->accessory->image)) : null,
'note' => $checkout->note ? e($checkout->note) : null,
'created_by' => $checkout->admin ? [
'id' => (int) $checkout->admin->id,
'name'=> e($checkout->admin->present()->fullName),
]: null,
'created_at' => Helper::getFormattedDateObject($checkout->created_at, 'datetime'),
];

$permissions_array['available_actions'] = [
'checkout' => Gate::allows('checkout', Accessory::class),
'checkin' => Gate::allows('checkin', Accessory::class),
];

$array += $permissions_array;
}

return (new DatatablesTransformer)->transformDatatables($array, $total);
}

/**
* This gives a compact view of the location data without any additional relational queries,
* allowing us to 1) deliver a smaller payload and 2) avoid additional queries on relations that
* have not been easy/lazy loaded already
*
* @param Location $location
* @return array
* @throws \Exception
*/
public function transformLocationCompact(Location $location = null)
{
if ($location) {

$array = [
'id' => (int) $location->id,
'image' => ($location->image) ? Storage::disk('public')->url('locations/'.e($location->image)) : null,
'type' => "location",
'name' => e($location->name),
];

return $array;
}
}
}
28 changes: 28 additions & 0 deletions app/Http/Transformers/UsersTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,34 @@ public function transformUser(User $user)
return $array;
}


/**
* This gives a compact view of the user data without any additional relational queries,
* allowing us to 1) deliver a smaller payload and 2) avoid additional queries on relations that
* have not been easy/lazy loaded already
*
* @param User $user
* @return array
* @throws \Exception
*/
public function transformUserCompact(User $user) : array
{

$array = [
'id' => (int) $user->id,
'image' => e($user->present()->gravatar) ?? null,
'type' => 'user',
'name' => e($user->getFullNameAttribute()),
'first_name' => e($user->first_name),
'last_name' => e($user->last_name),
'username' => e($user->username),
'created_at' => Helper::getFormattedDateObject($user->created_at, 'datetime'),
'deleted_at' => ($user->deleted_at) ? Helper::getFormattedDateObject($user->deleted_at, 'datetime') : null,
];

return $array;
}

public function transformUsersDatatable($users)
{
return (new DatatablesTransformer)->transformDatatables($users);
Expand Down
51 changes: 41 additions & 10 deletions app/Models/AccessoryCheckout.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@
use App\Models\Traits\Searchable;
use App\Presenters\Presentable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Storage;
use Watson\Validating\ValidatingTrait;

/**
* Model for Accessories.
Expand All @@ -21,8 +17,17 @@
class AccessoryCheckout extends Model
{
use Searchable;
use Presentable;

protected $fillable = ['user_id', 'accessory_id', 'assigned_to', 'assigned_type', 'note'];
protected $fillable = [
'user_id',
'accessory_id',
'assigned_to',
'assigned_type',
'note'
];

protected $presenter = \App\Presenters\AccessoryPresenter::class;
protected $table = 'accessories_checkout';

/**
Expand All @@ -34,7 +39,12 @@ class AccessoryCheckout extends Model
*/
public function accessory()
{
return $this->hasOne(\App\Models\Accessory::class, 'accessory_id');
return $this->hasOne(Accessory::class, 'id', 'accessory_id');
}

public function accessories()
{
return $this->hasMany(Accessory::class, 'id', 'accessory_id');
}

/**
Expand All @@ -44,9 +54,9 @@ public function accessory()
* @since [v7.0.9]
* @return \Illuminate\Database\Eloquent\Relations\Relation
*/
public function user()
public function admin()
{
return $this->hasOne(\App\Models\User::class, 'user_id');
return $this->hasOne(User::class, 'id', 'user_id');
}

/**
Expand Down Expand Up @@ -76,22 +86,43 @@ public function assignedType()
/**
* Determines whether the accessory is checked out to a user
*
* Even though we allow allow for checkout to things beyond users
* Even though we allow for checkout to things beyond users
* this method is an easy way of seeing if we are checked out to a user.
*
* @author [A. Kroeger]
* @since [v7.0]
*/
public function checkedOutToUser(): bool
{
return $this->assignedType() === Asset::USER;
return $this->assigned_type == User::class;
}

public function checkedOutToLocation(): bool
{
return $this->assigned_type == Location::class;
}

public function checkedOutToAsset(): bool
{
return $this->assigned_type == Asset::class;
}


public function scopeUserAssigned(Builder $query): void
{
$query->where('assigned_type', '=', User::class);
}

public function scopeLocationAssigned(Builder $query): void
{
$query->where('assigned_type', '=', Location::class);
}

public function scopeAssetAssigned(Builder $query): void
{
$query->where('assigned_type', '=', Asset::class);
}

/**
* Run additional, advanced searches.
*
Expand Down
12 changes: 12 additions & 0 deletions app/Models/Location.php
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,18 @@ public function assignedAssets()
return $this->morphMany(\App\Models\Asset::class, 'assigned', 'assigned_type', 'assigned_to')->withTrashed();
}

/**
* Establishes the asset -> location assignment relationship
*
* @author A. Gianotto <snipe@snipe.net>
* @since [v3.0]
* @return \Illuminate\Database\Eloquent\Relations\Relation
*/
public function assignedAccessories()
{
return $this->morphMany(\App\Models\AccessoryCheckout::class, 'assigned', 'assigned_type', 'assigned_to');
}

public function setLdapOuAttribute($ldap_ou)
{
return $this->attributes['ldap_ou'] = empty($ldap_ou) ? null : $ldap_ou;
Expand Down
Loading