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.
This commit is contained in:
@@ -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');
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
];
|
||||
|
||||
+30
-1
@@ -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] [<tobias.regnery@gmail.com>]
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddCompanyIdToLocations extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('locations', function (Blueprint $table) {
|
||||
$table->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');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
<!-- Manager-->
|
||||
@include ('partials.forms.edit.user-select', ['translated_name' => trans('admin/users/table.manager'), 'fieldname' => 'manager_id'])
|
||||
|
||||
<!-- Company -->
|
||||
@include ('partials.forms.edit.company-select', ['translated_name' => trans('general.company'), 'fieldname' => 'company_id'])
|
||||
|
||||
@include ('partials.forms.edit.phone')
|
||||
@include ('partials.forms.edit.fax')
|
||||
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -53,7 +53,11 @@
|
||||
@if ($parent)
|
||||
{{ $parent->present()->fullName() }}
|
||||
@endif
|
||||
|
||||
<br>
|
||||
@if ($company)
|
||||
<b>{{ trans('admin/companies/table.name') }}:</b> {{ $company->present()->Name() }}</b>
|
||||
<br>
|
||||
@endif
|
||||
@if ($manager)
|
||||
<b>{{ trans('general.manager') }}</b> {{ $manager->present()->fullName() }}<br>
|
||||
@endif
|
||||
|
||||
@@ -412,6 +412,9 @@
|
||||
@if ($location->manager)
|
||||
<li>{{ trans('admin/users/table.manager') }}: {!! $location->manager->present()->nameUrl() !!}</li>
|
||||
@endif
|
||||
@if ($location->company)
|
||||
<li>{{ trans('admin/companies/table.name') }}: {!! $location->company->present()->nameUrl() !!}</li>
|
||||
@endif
|
||||
@if ($location->parent)
|
||||
<li>{{ trans('admin/locations/table.parent') }}: {!! $location->parent->present()->nameUrl() !!}</li>
|
||||
@endif
|
||||
|
||||
@@ -11,6 +11,16 @@
|
||||
</div>
|
||||
@include('modals.partials.name', ['item' => new \App\Models\Location(), 'required' => 'true'])
|
||||
|
||||
<!-- Setup of default company, taken from asset creator -->
|
||||
@if ($user->company)
|
||||
<input type="hidden" name="company_id" id='modal-company' value='{{ $user->company->id }}' class="form-control">
|
||||
@endif
|
||||
|
||||
<!-- Select company, only for users with multicompany access - replace default company -->
|
||||
<div class="dynamic-form-row">
|
||||
@include ('partials.forms.edit.company-select', ['translated_name' => trans('general.company'), 'fieldname' => 'company_id'])
|
||||
</div>
|
||||
|
||||
<div class="dynamic-form-row">
|
||||
<div class="col-md-4 col-xs-12"><label for="modal-city">{{ trans('general.city') }}:</label></div>
|
||||
<div class="col-md-8 col-xs-12"><input type='text' name="city" id='modal-city' class="form-control"></div>
|
||||
|
||||
@@ -748,6 +748,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
function locationCompanyObjFilterFormatter(value, row) {
|
||||
if (value) {
|
||||
return '<a href="{{ url('/') }}/locations/?company_id=' + row.company.id + '">' + row.company.name + '</a>';
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
function employeeNumFormatter(value, row) {
|
||||
|
||||
if ((row) && (row.assigned_to) && ((row.assigned_to.employee_number))) {
|
||||
|
||||
Reference in New Issue
Block a user