Skip to content

Commit 029f303

Browse files
committed
Merge remote-tracking branch 'origin/develop'
2 parents 8c59a8d + 4a39d7c commit 029f303

File tree

7 files changed

+155
-59
lines changed

7 files changed

+155
-59
lines changed

app/Http/Controllers/Api/DepartmentsController.php

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use App\Helpers\Helper;
66
use App\Http\Controllers\Controller;
7+
use App\Http\Requests\StoreDepartmentRequest;
78
use App\Http\Transformers\DepartmentsTransformer;
89
use App\Http\Transformers\SelectlistTransformer;
910
use App\Models\Department;
@@ -26,18 +27,19 @@ public function index(Request $request) : JsonResponse | array
2627
$allowed_columns = ['id', 'name', 'image', 'users_count', 'notes'];
2728

2829
$departments = Department::select(
29-
'departments.id',
30-
'departments.name',
31-
'departments.phone',
32-
'departments.fax',
33-
'departments.location_id',
34-
'departments.company_id',
35-
'departments.manager_id',
36-
'departments.created_at',
37-
'departments.updated_at',
38-
'departments.image',
39-
'departments.notes',
40-
)->with('users')->with('location')->with('manager')->with('company')->withCount('users as users_count');
30+
[
31+
'departments.id',
32+
'departments.name',
33+
'departments.phone',
34+
'departments.fax',
35+
'departments.location_id',
36+
'departments.company_id',
37+
'departments.manager_id',
38+
'departments.created_at',
39+
'departments.updated_at',
40+
'departments.image',
41+
'departments.notes'
42+
])->with('users')->with('location')->with('manager')->with('company')->withCount('users as users_count');
4143

4244
if ($request->filled('search')) {
4345
$departments = $departments->TextSearch($request->input('search'));
@@ -94,18 +96,17 @@ public function index(Request $request) : JsonResponse | array
9496
* @since [v4.0]
9597
* @param \App\Http\Requests\ImageUploadRequest $request
9698
*/
97-
public function store(ImageUploadRequest $request) : JsonResponse
99+
public function store(StoreDepartmentRequest $request): JsonResponse
98100
{
99-
$this->authorize('create', Department::class);
100101
$department = new Department;
101-
$department->fill($request->all());
102+
$department->fill($request->validated());
102103
$department = $request->handleImages($department);
103104

104105
$department->created_by = auth()->id();
105106
$department->manager_id = ($request->filled('manager_id') ? $request->input('manager_id') : null);
106107

107108
if ($department->save()) {
108-
return response()->json(Helper::formatStandardApiResponse('success', $department, trans('admin/departments/message.create.success')));
109+
return response()->json(Helper::formatStandardApiResponse('success', (new DepartmentsTransformer)->transformDepartment($department), trans('admin/departments/message.create.success')));
109110
}
110111
return response()->json(Helper::formatStandardApiResponse('error', null, $department->getErrors()));
111112

@@ -121,7 +122,7 @@ public function store(ImageUploadRequest $request) : JsonResponse
121122
public function show($id) : array
122123
{
123124
$this->authorize('view', Department::class);
124-
$department = Department::findOrFail($id);
125+
$department = Department::withCount('users as users_count')->findOrFail($id);
125126
return (new DepartmentsTransformer)->transformDepartment($department);
126127
}
127128

@@ -141,7 +142,7 @@ public function update(ImageUploadRequest $request, $id) : JsonResponse
141142
$department = $request->handleImages($department);
142143

143144
if ($department->save()) {
144-
return response()->json(Helper::formatStandardApiResponse('success', $department, trans('admin/departments/message.update.success')));
145+
return response()->json(Helper::formatStandardApiResponse('success', (new DepartmentsTransformer)->transformDepartment($department), trans('admin/departments/message.update.success')));
145146
}
146147

147148
return response()->json(Helper::formatStandardApiResponse('error', null, $department->getErrors()));
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace App\Http\Requests;
4+
5+
use App\Models\Department;
6+
use Illuminate\Foundation\Http\FormRequest;
7+
use Illuminate\Support\Facades\Gate;
8+
9+
class StoreDepartmentRequest extends ImageUploadRequest
10+
{
11+
/**
12+
* Determine if the user is authorized to make this request.
13+
*/
14+
public function authorize(): bool
15+
{
16+
return Gate::allows('create', new Department);
17+
}
18+
19+
/**
20+
* Get the validation rules that apply to the request.
21+
*
22+
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
23+
*/
24+
public function rules(): array
25+
{
26+
$modelRules = (new Department)->getRules();
27+
28+
return array_merge(
29+
$modelRules,
30+
);
31+
}
32+
}

app/Http/Transformers/DepartmentsTransformer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public function transformDepartment(Department $department = null)
4343
'id' => (int) $department->location->id,
4444
'name' => e($department->location->name),
4545
] : null,
46-
'users_count' => e($department->users_count),
46+
'users_count' => (int) ($department->users_count),
4747
'notes' => Helper::parseEscapedMarkedownInline($department->notes),
4848
'created_at' => Helper::getFormattedDateObject($department->created_at, 'datetime'),
4949
'updated_at' => Helper::getFormattedDateObject($department->updated_at, 'datetime'),

app/Models/Department.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,13 @@ class Department extends SnipeModel
3131
];
3232

3333
protected $rules = [
34-
'name' => 'required|max:255|is_unique_department',
35-
'location_id' => 'numeric|nullable',
36-
'company_id' => 'numeric|nullable',
37-
'manager_id' => 'numeric|nullable',
34+
'name' => 'required|max:255|is_unique_across_company_and_location:departments,name',
35+
'location_id' => 'numeric|nullable|exists:locations,id',
36+
'company_id' => 'numeric|nullable|exists:companies,id',
37+
'manager_id' => 'numeric|nullable|exists:users,id',
38+
'phone' => 'string|max:255|nullable',
39+
'fax' => 'string|max:255|nullable',
40+
'notes' => 'string|max:255|nullable',
3841
];
3942

4043
/**

app/Providers/ValidationServiceProvider.php

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -283,41 +283,36 @@ public function boot()
283283
}
284284
});
285285

286-
Validator::extend('is_unique_department', function ($attribute, $value, $parameters, $validator) {
286+
/**
287+
* Check that the 'name' field is unique in the table while within both company_id and location_id
288+
* This is only used by Departments right now, but could be used elsewhere in the future.
289+
*/
290+
Validator::extend('is_unique_across_company_and_location', function ($attribute, $value, $parameters, $validator) {
287291
$data = $validator->getData();
292+
$table = array_get($parameters, 0);
288293

289-
if (
290-
array_key_exists('location_id', $data) && $data['location_id'] !== null &&
291-
array_key_exists('company_id', $data) && $data['company_id'] !== null
292-
) {
293-
//for updating existing departments
294-
if(array_key_exists('id', $data) && $data['id'] !== null){
295-
$count = Department::where('name', $data['name'])
296-
->where('location_id', $data['location_id'])
297-
->where('company_id', $data['company_id'])
298-
->whereNotNull('company_id')
299-
->whereNotNull('location_id')
300-
->where('id', '!=', $data['id'])
301-
->count('name');
302-
303-
return $count < 1;
304-
}else // for entering in new departments
305-
{
306-
$count = Department::where('name', $data['name'])
307-
->where('location_id', $data['location_id'])
308-
->where('company_id', $data['company_id'])
309-
->whereNotNull('company_id')
310-
->whereNotNull('location_id')
311-
->count('name');
294+
$count = DB::table($table)->select($attribute)
295+
->where($attribute, $value)
296+
->whereNull('deleted_at');
312297

313-
return $count < 1;
298+
if (array_key_exists('id', $data) && $data['id'] !== null) {
299+
$count = $count->where('id', '!=', $data['id']);
314300
}
315-
}
316-
else {
317-
return true;
318-
}
301+
302+
if (array_key_exists('location_id', $data) && $data['location_id'] !== null) {
303+
$count = $count->where('location_id', $data['location_id']);
304+
}
305+
306+
if (array_key_exists('company_id', $data) && $data['company_id'] !== null) {
307+
$count = $count->where('company_id', $data['company_id']);
308+
}
309+
310+
$count = $count->count('name');
311+
return $count < 1;
312+
319313
});
320314

315+
321316
Validator::extend('not_array', function ($attribute, $value, $parameters, $validator) {
322317
return !is_array($value);
323318
});

resources/lang/en-US/validation.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@
174174
'ulid' => 'The :attribute field must be a valid ULID.',
175175
'uuid' => 'The :attribute field must be a valid UUID.',
176176
'fmcs_location' => 'Full multiple company support and location scoping is enabled in the Admin Settings, and the selected location and selected company are not compatible.',
177-
177+
'is_unique_across_company_and_location' => 'The :attribute must be unique within the selected company and location.',
178178

179179
/*
180180
|--------------------------------------------------------------------------

tests/Feature/Departments/Api/CreateDepartmentsTest.php

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
namespace Tests\Feature\Departments\Api;
44

55
use App\Models\AssetModel;
6+
use App\Models\Company;
67
use App\Models\Department;
78
use App\Models\Category;
9+
use App\Models\Location;
810
use App\Models\User;
911
use Illuminate\Testing\Fluent\AssertableJson;
1012
use Tests\TestCase;
@@ -13,30 +15,93 @@ class CreateDepartmentsTest extends TestCase
1315
{
1416

1517

16-
public function testRequiresPermissionToCreateDepartment()
18+
public function test_requires_permission_to_create_department()
1719
{
1820
$this->actingAsForApi(User::factory()->create())
1921
->postJson(route('api.departments.store'))
2022
->assertForbidden();
2123
}
2224

23-
public function testCanCreateDepartment()
25+
public function test_can_create_department_with_all_fields()
2426
{
25-
$response = $this->actingAsForApi(User::factory()->superuser()->create())
27+
$company = Company::factory()->create();
28+
$location = Location::factory()->create();
29+
$manager = User::factory()->create();
30+
$user = User::factory()->superuser()->create();
31+
$response = $this->actingAsForApi($user)
2632
->postJson(route('api.departments.store'), [
27-
'name' => 'Test Department',
28-
'notes' => 'Test Note',
33+
'name' => 'Test Department',
34+
'company_id' => $company->id,
35+
'location_id' => $location->id,
36+
'manager_id' => $manager->id,
37+
'notes' => 'Test Note',
38+
'phone' => '1234567890',
39+
'fax' => '1234567890',
2940
])
3041
->assertOk()
3142
->assertStatusMessageIs('success')
32-
->assertStatus(200)
3343
->json();
3444

3545
$this->assertTrue(Department::where('name', 'Test Department')->exists());
3646

3747
$department = Department::find($response['payload']['id']);
3848
$this->assertEquals('Test Department', $department->name);
3949
$this->assertEquals('Test Note', $department->notes);
50+
51+
$this->assertDatabaseHas('departments', [
52+
'name' => 'Test Department',
53+
'company_id' => $company->id,
54+
'location_id' => $location->id,
55+
'manager_id' => $manager->id,
56+
'notes' => 'Test Note',
57+
'phone' => '1234567890',
58+
'fax' => '1234567890',
59+
'created_by' => $user->id,
60+
]);
61+
}
62+
63+
public function test_name_required_for_department()
64+
{
65+
$response = $this->actingAsForApi(User::factory()->superuser()->create())
66+
->postJson(route('api.departments.store'), [
67+
'company_id' => Company::factory()->create()->id,
68+
])
69+
->assertOk()
70+
->assertStatusMessageIs('error');
71+
}
72+
73+
public function test_only_name_required_for_department()
74+
{
75+
$response = $this->actingAsForApi(User::factory()->superuser()->create())
76+
->postJson(route('api.departments.store'), [
77+
'name' => 'Test Department',
78+
])
79+
->assertOk()
80+
->assertStatusMessageIs('success');
4081
}
4182

83+
public function test_arrays_not_allowed_for_numeric_fields()
84+
{
85+
$response = $this->actingAsForApi(User::factory()->superuser()->create())
86+
->postJson(route('api.departments.store'), [
87+
'name' => 'Test Department',
88+
'company_id' => [1, 2],
89+
])
90+
->assertOk()
91+
->assertStatusMessageIs('error');
92+
}
93+
94+
public function test_arrays_of_strings_are_not_allowed_for_numeric_fields()
95+
{
96+
$response = $this->actingAsForApi(User::factory()->superuser()->create())
97+
->postJson(route('api.departments.store'), [
98+
'name' => 'Test Department',
99+
'company_id' => ['1', '2'],
100+
])
101+
->assertOk()
102+
->assertStatusMessageIs('error');
103+
}
104+
105+
106+
42107
}

0 commit comments

Comments
 (0)