From 1ccbf8942c87d528a6ea47f41f7cf0bad6eab024 Mon Sep 17 00:00:00 2001 From: Tobias Regnery Date: Thu, 10 Feb 2022 11:36:36 +0100 Subject: [PATCH] Add ability to tie locations to companies Locations are the last big part of the application that can't be tied to companies. This can be a problem with FullMultipleCompanySupport, because you can't restrict the visibility of locations to the company of the users. In order to change this, add a company_id to the locations table and wire everything up in the views and controllers. Aditionally add a new formatter to filter the locations to a specific company, like it is done for assets. Locations are properly scoped to the users company if FullMultipleCompanySupport is enabled. If a parent location of a location has a different company than the user, the location does not show up. --- .../Controllers/Api/LocationsController.php | 21 ++++++++++- app/Http/Controllers/LocationsController.php | 27 +++++++++----- .../Transformers/LocationsTransformer.php | 4 +++ app/Models/Location.php | 31 +++++++++++++++- app/Presenters/LocationPresenter.php | 9 +++++ ..._10_110210_add_company_id_to_locations.php | 35 +++++++++++++++++++ resources/views/locations/edit.blade.php | 3 ++ resources/views/locations/index.blade.php | 2 +- resources/views/locations/print.blade.php | 6 +++- resources/views/locations/view.blade.php | 3 ++ resources/views/modals/location.blade.php | 10 ++++++ .../views/partials/bootstrap-table.blade.php | 8 +++++ 12 files changed, 147 insertions(+), 12 deletions(-) create mode 100644 database/migrations/2022_02_10_110210_add_company_id_to_locations.php diff --git a/app/Http/Controllers/Api/LocationsController.php b/app/Http/Controllers/Api/LocationsController.php index 10744bee27..93ba287d4d 100644 --- a/app/Http/Controllers/Api/LocationsController.php +++ b/app/Http/Controllers/Api/LocationsController.php @@ -9,6 +9,7 @@ use App\Http\Transformers\AssetsTransformer; use App\Http\Transformers\LocationsTransformer; use App\Http\Transformers\SelectlistTransformer; use App\Models\Asset; +use App\Models\Company; use App\Models\Location; use Illuminate\Http\Request; use Illuminate\Pagination\LengthAwarePaginator; @@ -48,6 +49,7 @@ class LocationsController extends Controller 'rtd_assets_count', 'currency', 'ldap_ou', + 'company_id', ]; $locations = Location::with('parent', 'manager', 'children')->select([ @@ -68,12 +70,15 @@ class LocationsController extends Controller 'locations.image', 'locations.ldap_ou', 'locations.currency', + 'locations.company_id', ])->withCount('assignedAssets as assigned_assets_count') ->withCount('assets as assets_count') ->withCount('rtd_assets as rtd_assets_count') ->withCount('children as children_count') ->withCount('users as users_count'); + $locations = Company::scopeCompanyables($locations); + if ($request->filled('search')) { $locations = $locations->TextSearch($request->input('search')); } @@ -106,6 +111,10 @@ class LocationsController extends Controller $locations->where('locations.manager_id', '=', $request->input('manager_id')); } + if ($request->filled('company_id')) { + $locations->where('locations.company_id', '=', $request->input('company_id')); + } + // Make sure the offset and limit are actually integers and do not exceed system limits $offset = ($request->input('offset') > $locations->count()) ? $locations->count() : app('api_offset_value'); $limit = app('api_limit_value'); @@ -122,6 +131,9 @@ class LocationsController extends Controller case 'manager': $locations->OrderManager($order); break; + case 'company': + $locations->OrderCompany($order); + break; default: $locations->orderBy($sort, $order); break; @@ -147,6 +159,7 @@ class LocationsController extends Controller $this->authorize('create', Location::class); $location = new Location; $location->fill($request->all()); + $location->company_id = Company::getIdForCurrentUser($request->get('company_id')); $location = $request->handleImages($location); if ($location->save()) { @@ -166,7 +179,7 @@ class LocationsController extends Controller public function show($id) : JsonResponse | array { $this->authorize('view', Location::class); - $location = Location::with('parent', 'manager', 'children') + $location = Location::with('parent', 'manager', 'children', 'company') ->select([ 'locations.id', 'locations.name', @@ -209,6 +222,10 @@ class LocationsController extends Controller $location->fill($request->all()); $location = $request->handleImages($location); + if ($request->filled('company_id')) { + $location->company_id = Company::getIdForCurrentUser($request->get('company_id')); + } + if ($location->isValid()) { $location->save(); @@ -305,6 +322,8 @@ class LocationsController extends Controller 'locations.image', ]); + $locations = Company::scopeCompanyables($locations); + $page = 1; if ($request->filled('page')) { $page = $request->input('page'); diff --git a/app/Http/Controllers/LocationsController.php b/app/Http/Controllers/LocationsController.php index 75abce97ed..7784ad1825 100755 --- a/app/Http/Controllers/LocationsController.php +++ b/app/Http/Controllers/LocationsController.php @@ -5,6 +5,7 @@ namespace App\Http\Controllers; use App\Http\Requests\ImageUploadRequest; use App\Models\Actionlog; use App\Models\Asset; +use App\Models\Company; use App\Models\Location; use App\Models\User; use Illuminate\Support\Facades\Storage; @@ -78,6 +79,7 @@ class LocationsController extends Controller $location->created_by = auth()->id(); $location->phone = request('phone'); $location->fax = request('fax'); + $location->company_id = Company::getIdForCurrentUser($request->input('company_id')); $location = $request->handleImages($location); @@ -138,6 +140,7 @@ class LocationsController extends Controller $location->fax = request('fax'); $location->ldap_ou = $request->input('ldap_ou'); $location->manager_id = $request->input('manager_id'); + $location->company_id = Company::getIdForCurrentUser($request->input('company_id')); $location = $request->handleImages($location); @@ -211,20 +214,22 @@ class LocationsController extends Controller public function print_assigned($id) : View | RedirectResponse { - if ($location = Location::where('id', $id)->first()) { $parent = Location::where('id', $location->parent_id)->first(); $manager = User::where('id', $location->manager_id)->first(); + $company = Company::where('id', $location->company_id)->first(); $users = User::where('location_id', $id)->with('company', 'department', 'location')->get(); $assets = Asset::where('assigned_to', $id)->where('assigned_type', Location::class)->with('model', 'model.category')->get(); - return view('locations/print')->with('assets', $assets)->with('users', $users)->with('location', $location)->with('parent', $parent)->with('manager', $manager); - + return view('locations/print') + ->with('assets', $assets) + ->with('users',$users) + ->with('location', $location) + ->with('parent', $parent) + ->with('manager', $manager) + ->with('company', $company); } return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist')); - - - } @@ -296,10 +301,16 @@ class LocationsController extends Controller if ($location = Location::where('id', $id)->first()) { $parent = Location::where('id', $location->parent_id)->first(); $manager = User::where('id', $location->manager_id)->first(); + $company = Company::where('id', $location->company_id)->first(); $users = User::where('location_id', $id)->with('company', 'department', 'location')->get(); $assets = Asset::where('location_id', $id)->with('model', 'model.category')->get(); - return view('locations/print')->with('assets', $assets)->with('users', $users)->with('location', $location)->with('parent', $parent)->with('manager', $manager); - + return view('locations/print') + ->with('assets', $assets) + ->with('users',$users) + ->with('location', $location) + ->with('parent', $parent) + ->with('manager', $manager) + ->with('company', $company); } return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist')); } diff --git a/app/Http/Transformers/LocationsTransformer.php b/app/Http/Transformers/LocationsTransformer.php index 513b967f42..0f39eea18d 100644 --- a/app/Http/Transformers/LocationsTransformer.php +++ b/app/Http/Transformers/LocationsTransformer.php @@ -58,6 +58,10 @@ class LocationsTransformer 'name'=> e($location->parent->name), ] : null, 'manager' => ($location->manager) ? (new UsersTransformer)->transformUser($location->manager) : null, + 'company' => ($location->company) ? [ + 'id' => (int) $location->company->id, + 'name'=> e($location->company->name) + ] : null, 'children' => $children_arr, ]; diff --git a/app/Models/Location.php b/app/Models/Location.php index 014db3053e..7f99c78531 100755 --- a/app/Models/Location.php +++ b/app/Models/Location.php @@ -22,6 +22,7 @@ class Location extends SnipeModel protected $presenter = \App\Presenters\LocationPresenter::class; use Presentable; use SoftDeletes; + use CompanyableTrait; protected $table = 'locations'; protected $rules = [ @@ -34,11 +35,13 @@ class Location extends SnipeModel 'zip' => 'max:10|nullable', 'manager_id' => 'exists:users,id|nullable', 'parent_id' => 'nullable|exists:locations,id|non_circular:locations,id', + 'company_id' => 'integer|nullable|exists:companies,id', ]; protected $casts = [ 'parent_id' => 'integer', 'manager_id' => 'integer', + 'company_id' => 'integer', ]; /** @@ -72,6 +75,7 @@ class Location extends SnipeModel 'currency', 'manager_id', 'image', + 'company_id', ]; protected $hidden = ['user_id']; @@ -90,7 +94,8 @@ class Location extends SnipeModel * @var array */ protected $searchableRelations = [ - 'parent' => ['name'], + 'parent' => ['name'], + 'company' => ['name'] ]; @@ -214,6 +219,17 @@ class Location extends SnipeModel ->with('parent'); } + /** + * Establishes the locations -> company relationship + * + * @author [T. Regnery] [] + * @since [v7.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ + public function company() + { + return $this->belongsTo(\App\Models\Company::class, 'company_id'); + } /** * Find the manager of a location @@ -313,4 +329,17 @@ class Location extends SnipeModel { return $query->leftJoin('users as location_user', 'locations.manager_id', '=', 'location_user.id')->orderBy('location_user.first_name', $order)->orderBy('location_user.last_name', $order); } + + /** + * Query builder scope to order on company + * + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param text $order Order + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ + public function scopeOrderCompany($query, $order) + { + return $query->leftJoin('companies as company_sort', 'locations.company_id', '=', 'company_sort.id')->orderBy('company_sort.name', $order); + } } diff --git a/app/Presenters/LocationPresenter.php b/app/Presenters/LocationPresenter.php index d6bbe0db11..7185aa04fc 100644 --- a/app/Presenters/LocationPresenter.php +++ b/app/Presenters/LocationPresenter.php @@ -27,6 +27,15 @@ class LocationPresenter extends Presenter 'title' => trans('general.id'), 'visible' => false, ], + [ + 'field' => 'company', + 'searchable' => true, + 'sortable' => true, + 'switchable' => true, + 'title' => trans('general.company'), + 'visible' => false, + 'formatter' => 'locationCompanyObjFilterFormatter' + ], [ 'field' => 'name', 'searchable' => true, diff --git a/database/migrations/2022_02_10_110210_add_company_id_to_locations.php b/database/migrations/2022_02_10_110210_add_company_id_to_locations.php new file mode 100644 index 0000000000..8ef5822812 --- /dev/null +++ b/database/migrations/2022_02_10_110210_add_company_id_to_locations.php @@ -0,0 +1,35 @@ +integer('company_id')->unsigned()->nullable(); + $table->index(['company_id']); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('locations', function (Blueprint $table) { + $table->dropIndex(['company_id']); + $table->dropColumn('company_id'); + }); + } +} + diff --git a/resources/views/locations/edit.blade.php b/resources/views/locations/edit.blade.php index 4b4e655a52..1d12b1cda9 100755 --- a/resources/views/locations/edit.blade.php +++ b/resources/views/locations/edit.blade.php @@ -17,6 +17,9 @@ @include ('partials.forms.edit.user-select', ['translated_name' => trans('admin/users/table.manager'), 'fieldname' => 'manager_id']) + +@include ('partials.forms.edit.company-select', ['translated_name' => trans('general.company'), 'fieldname' => 'company_id']) + @include ('partials.forms.edit.phone') @include ('partials.forms.edit.fax') diff --git a/resources/views/locations/index.blade.php b/resources/views/locations/index.blade.php index 2d020cb026..ba0abc545c 100755 --- a/resources/views/locations/index.blade.php +++ b/resources/views/locations/index.blade.php @@ -41,7 +41,7 @@ data-sort-order="asc" id="locationTable" class="table table-striped snipe-table" - data-url="{{ route('api.locations.index') }}" + data-url="{{ route('api.locations.index', array('company_id'=>e(Request::get('company_id')))) }}" data-export-options='{ "fileName": "export-locations-{{ date('Y-m-d') }}", "ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"] diff --git a/resources/views/locations/print.blade.php b/resources/views/locations/print.blade.php index 9f54978ff5..b7ee71cee2 100644 --- a/resources/views/locations/print.blade.php +++ b/resources/views/locations/print.blade.php @@ -53,7 +53,11 @@ @if ($parent) {{ $parent->present()->fullName() }} @endif - +
+@if ($company) + {{ trans('admin/companies/table.name') }}: {{ $company->present()->Name() }} +
+@endif @if ($manager) {{ trans('general.manager') }} {{ $manager->present()->fullName() }}
@endif diff --git a/resources/views/locations/view.blade.php b/resources/views/locations/view.blade.php index a0d3b8c742..d9f83020b7 100644 --- a/resources/views/locations/view.blade.php +++ b/resources/views/locations/view.blade.php @@ -412,6 +412,9 @@ @if ($location->manager)
  • {{ trans('admin/users/table.manager') }}: {!! $location->manager->present()->nameUrl() !!}
  • @endif + @if ($location->company) +
  • {{ trans('admin/companies/table.name') }}: {!! $location->company->present()->nameUrl() !!}
  • + @endif @if ($location->parent)
  • {{ trans('admin/locations/table.parent') }}: {!! $location->parent->present()->nameUrl() !!}
  • @endif diff --git a/resources/views/modals/location.blade.php b/resources/views/modals/location.blade.php index 9580f4bbf9..59c4516d98 100644 --- a/resources/views/modals/location.blade.php +++ b/resources/views/modals/location.blade.php @@ -11,6 +11,16 @@ @include('modals.partials.name', ['item' => new \App\Models\Location(), 'required' => 'true']) + + @if ($user->company) + + @endif + + +
    + @include ('partials.forms.edit.company-select', ['translated_name' => trans('general.company'), 'fieldname' => 'company_id']) +
    +
    diff --git a/resources/views/partials/bootstrap-table.blade.php b/resources/views/partials/bootstrap-table.blade.php index f24552d753..42bcc41b32 100644 --- a/resources/views/partials/bootstrap-table.blade.php +++ b/resources/views/partials/bootstrap-table.blade.php @@ -748,6 +748,14 @@ } } + function locationCompanyObjFilterFormatter(value, row) { + if (value) { + return '' + row.company.name + ''; + } else { + return value; + } + } + function employeeNumFormatter(value, row) { if ((row) && (row.assigned_to) && ((row.assigned_to.employee_number))) {