diff --git a/ProcessMaker/Http/Controllers/Api/Administration/GroupsController.php b/ProcessMaker/Http/Controllers/Api/Administration/GroupsController.php index 482d52b338..e6c9d21f35 100644 --- a/ProcessMaker/Http/Controllers/Api/Administration/GroupsController.php +++ b/ProcessMaker/Http/Controllers/Api/Administration/GroupsController.php @@ -39,7 +39,7 @@ public function index(Request $request) // Need to include number of users associations with this group $groups = $groups->leftJoin('group_users', 'group_users.group_id', 'groups.id') ->groupBy('groups.id') - ->select(DB::raw('groups.*, count(group_users.id) as total_users')); + ->select(DB::raw('`groups`.*, count(group_users.id) as total_users')); } $groups = $groups->paginate($perPage); } else { @@ -47,7 +47,7 @@ public function index(Request $request) // Need to include users count with roles $groups = Group::leftJoin('group_users', 'group_users.group_id', 'groups.id') ->groupBy('groups.id') - ->select(DB::raw('groups.*, count(group_users.id) as total_users')) + ->select(DB::raw('`groups`.*, count(group_users.id) as total_users')) ->orderBy($orderBy, $orderDirection)->paginate($perPage); } else { $groups = Group::orderBy($orderBy, $orderDirection)->paginate($perPage); diff --git a/ProcessMaker/Http/Controllers/Api/Administration/ProcessCategoryController.php b/ProcessMaker/Http/Controllers/Api/Administration/ProcessCategoryController.php index 77c256a1dd..3f0ac167dc 100644 --- a/ProcessMaker/Http/Controllers/Api/Administration/ProcessCategoryController.php +++ b/ProcessMaker/Http/Controllers/Api/Administration/ProcessCategoryController.php @@ -4,10 +4,11 @@ use Illuminate\Database\Eloquent\Collection; use Illuminate\Http\Request; -use ProcessMaker\Facades\ProcessCategoryManager; use ProcessMaker\Http\Controllers\Controller; use ProcessMaker\Model\Permission; use ProcessMaker\Model\ProcessCategory; +use ProcessMaker\Transformers\ProcessCategoryTransformer; +use Ramsey\Uuid\Uuid; /** * Implements endpoints to manage the process categories. @@ -25,12 +26,24 @@ class ProcessCategoryController extends Controller */ public function index(Request $request) { - $this->authorize('has-permission', Permission::PM_SETUP_PROCESS_CATEGORIES); + $query = ProcessCategory::where('uid', '!=', '') + ->withCount('processes'); + $filter = $request->input("filter"); - $start = $request->input("start"); - $limit = $request->input("limit"); - $response = ProcessCategoryManager::index($filter, $start, $limit); - return response($this->formatList($response), 200); + $filter === null ? : $query->where( + 'name', 'like', '%' . $filter . '%' + ); + + $orderBy = $request->input('order_by', 'name'); + $orderDirection = $request->input('order_direction', 'ASC'); + $orderBy === null ? : $query->orderBy($orderBy, $orderDirection); + + $status = $request->input('status'); + $status === null ? : $query->where('status', $status); + + $perPage = $request->input('per_page', 10); + $result = $query->paginate($perPage); + return fractal($result, new ProcessCategoryTransformer())->respond(); } /** @@ -42,10 +55,15 @@ public function index(Request $request) */ public function store(Request $request) { - $this->authorize('has-permission', Permission::PM_SETUP_PROCESS_CATEGORIES); $data = $request->json()->all(); - $response = ProcessCategoryManager::store($data); - return response($this->format($response), 201); + + $processCategory = new ProcessCategory(); + $processCategory->uid = str_replace('-', '', Uuid::uuid4()); + $processCategory->fill($data); + $processCategory->saveOrFail(); + + + return fractal($processCategory, new ProcessCategoryTransformer())->respond(201); } /** @@ -59,8 +77,10 @@ public function store(Request $request) public function update(Request $request, ProcessCategory $processCategory) { $data = $request->json()->all(); - $response = ProcessCategoryManager::update($processCategory, $data); - return response($this->format($response), 200); + $processCategory->fill($data); + $processCategory->saveOrFail(); + + return fractal($processCategory, new ProcessCategoryTransformer())->respond(200); } /** @@ -72,7 +92,7 @@ public function update(Request $request, ProcessCategory $processCategory) */ public function destroy(ProcessCategory $processCategory) { - ProcessCategoryManager::remove($processCategory); + $processCategory->delete(); return response('', 204); } @@ -85,39 +105,7 @@ public function destroy(ProcessCategory $processCategory) */ public function show(ProcessCategory $processCategory) { - return response($this->format($processCategory), 200); - } - - /** - * Format the process category as a JSON response. - * - * @param ProcessCategory $processCategory - * - * @return array - */ - public function format(ProcessCategory $processCategory) - { - return [ - "cat_uid" => $processCategory->uid, - "cat_name" => $processCategory->name, - "cat_total_processes" => isset($processCategory->processes_count) - ? $processCategory->processes_count : 0, - ]; - } - - /** - * Format the process category index as a JSON response. - * - * @param Collection $processCategories - * - * @return array - */ - public function formatList(Collection $processCategories) - { - $response = []; - foreach ($processCategories as $processCategory) { - $response[] = $this->format($processCategory); - } - return $response; + return fractal($processCategory, new ProcessCategoryTransformer()) + ->respond(); } } diff --git a/ProcessMaker/Http/Controllers/Designer/ProcessCategoryController.php b/ProcessMaker/Http/Controllers/Designer/ProcessCategoryController.php new file mode 100644 index 0000000000..76f0c0ac49 --- /dev/null +++ b/ProcessMaker/Http/Controllers/Designer/ProcessCategoryController.php @@ -0,0 +1,20 @@ + 'homeid' ]); }); - Menu::make('sidebar_process', function ($menu) {}); + + Menu::make('sidebar_processes', function ($menu) { + $submenu = $menu->add(__('menus.sidebar_processes.processes')); + $submenu->add(__('menus.sidebar_processes.processes'), [ + 'route' => 'processes', + 'icon' => 'fa-play-circle', + 'id' => 'processes' + ]); + $submenu->add(__('menus.sidebar_processes.categories'), [ + 'route' => 'process-categories-index', + 'icon' => 'fa-list', + 'id' => 'process-categories' + ]); + }); Menu::make('sidebar_designer', function ($menu) {}); diff --git a/ProcessMaker/Managers/ProcessCategoryManager.php b/ProcessMaker/Managers/ProcessCategoryManager.php deleted file mode 100644 index 1dd3bf74f7..0000000000 --- a/ProcessMaker/Managers/ProcessCategoryManager.php +++ /dev/null @@ -1,142 +0,0 @@ -validate( - [ - 'start' => $start, - 'limit' => $limit, - ], - [ - 'start' => 'nullable|numeric|min:0', - 'limit' => 'nullable|numeric|min:0', - ] - ); - $query = ProcessCategory::select([ - 'uid', - 'name', - ])->where('uid', '!=', '') - ->withCount('processes'); - $filter === null ?: $query->where('name', 'like', "%$filter%"); - $start === null ? : $query->offset($start); - $limit === null ? : $query->limit($limit); - return $query->get(); - } - - /** - * Stores a new process category. - * - * @param array $data - * - * @return \ProcessMaker\Model\ProcessCategory - */ - public function store(array $data) - { - $this->validate( - $data, - [ - 'cat_name' => 'required|string|max:100|unique:process_categories,name', - ] - ); - return ProcessCategory::create([ - 'uid' => str_replace('-', '', Uuid::uuid4()), - 'name' => $data['cat_name'], - ]); - } - - /** - * Update a process category. - * - * @param ProcessCategory $processCategory - * @param array $data - * - * @return \ProcessMaker\Model\ProcessCategory - */ - public function update(ProcessCategory $processCategory, array $data) - { - $this->validate( - $data, - [ - 'cat_name' => 'required|string|max:100|unique:process_categories,name', - ] - ); - $processCategory->update([ - 'name' => $data['cat_name'], - ]); - $processCategory->save(); - return $processCategory; - } - - /** - * Remove a process category. - * - * @param ProcessCategory $processCategory - * - * @return bool - */ - public function remove(ProcessCategory $processCategory) - { - $this->validate( - [ - 'processCategory' => $processCategory, - ], - [ - 'processCategory' => 'process_category_manager.category_does_not_have_processes', - ] - ); - return $processCategory->delete(); - } - - /** - * Validate the given data with the given rules. - * - * @param array $data - * @param array $rules - * @param array $messages - * @param array $customAttributes - * - * @throws ValidationException - */ - private function validate( - array $data, - array $rules, - array $messages = [], - array $customAttributes = [] - ) { - $validator = Validator::make($data, $rules, $messages, $customAttributes); - - /** - * Validate that the category does not have processes. - */ - $validator->addExtension( - 'process_category_manager.category_does_not_have_processes', - function ($attribute, $processCategory, $parameters, ValidatorImplementation $validator) { - return $processCategory->processes()->count() === 0; - } - ); - - if ($validator->fails()) { - throw new ValidationException($validator); - } - } -} diff --git a/ProcessMaker/Model/ProcessCategory.php b/ProcessMaker/Model/ProcessCategory.php index 59786d517b..fab465576d 100644 --- a/ProcessMaker/Model/ProcessCategory.php +++ b/ProcessMaker/Model/ProcessCategory.php @@ -4,6 +4,8 @@ use Illuminate\Database\Eloquent\Model; use Watson\Validating\ValidatingTrait; +use Illuminate\Support\Facades\Validator; +use ProcessMaker\Exception\ValidationException; use ProcessMaker\Model\Traits\Uuid; /** @@ -22,13 +24,17 @@ class ProcessCategory extends Model use ValidatingTrait; use Uuid; + const STATUS_ACTIVE = 'ACTIVE'; + const STATUS_INACTIVE = 'INACTIVE'; + /** * Validation rules. * * @var array $rules */ - protected $rules = [ + public $rules = [ 'name' => 'required|string|max:100|unique:process_categories,name', + 'status' => 'required|string|in:ACTIVE,INACTIVE', ]; @@ -39,6 +45,7 @@ class ProcessCategory extends Model */ protected $fillable = [ 'name', + 'status', ]; /** @@ -58,6 +65,34 @@ public function getRouteKeyName() */ public function processes() { - return $this->hasMany(Process::class, 'id', 'id'); + return $this->hasMany(Process::class); + } + + /** + * Check that the category has no processes before deleting + * + * @return bool|null + * + * @throws \Exception + */ + public function delete() + { + $validator = Validator::make([ + 'processCategory' => $this, + ], [ + 'processCategory' => 'process_category_manager.category_does_not_have_processes', + ]); + + $validator->addExtension( + 'process_category_manager.category_does_not_have_processes', + function ($attribute, $processCategory, $parameters, $validator) { + return $processCategory->processes()->count() === 0; + } + ); + + if ($validator->fails()) { + throw new ValidationException($validator); + } + parent::delete(); } } diff --git a/ProcessMaker/Transformers/ProcessCategoryTransformer.php b/ProcessMaker/Transformers/ProcessCategoryTransformer.php new file mode 100644 index 0000000000..1599d81358 --- /dev/null +++ b/ProcessMaker/Transformers/ProcessCategoryTransformer.php @@ -0,0 +1,23 @@ +toArray(); + if (!array_key_exists('processes_count', $data)) { + $data['processes_count'] = $processCategory->processes->count(); + } + return $data; + } +} + \ No newline at end of file diff --git a/database/factories/ProcessCategory.php b/database/factories/ProcessCategory.php deleted file mode 100644 index 0d7868e257..0000000000 --- a/database/factories/ProcessCategory.php +++ /dev/null @@ -1,14 +0,0 @@ -define(\ProcessMaker\Model\ProcessCategory::class, function (Faker $faker) { - return [ - 'uid' => Uuid::uuid4(), - 'name' => $faker->name(), - ]; -}); diff --git a/database/factories/ProcessCategoryFactory.php b/database/factories/ProcessCategoryFactory.php new file mode 100644 index 0000000000..cc2f847c9d --- /dev/null +++ b/database/factories/ProcessCategoryFactory.php @@ -0,0 +1,18 @@ +define(ProcessCategory::class, function (Faker $faker) { + return [ + 'uid' => Uuid::uuid4(), + 'name' => $faker->name(), + 'status' => $faker->randomElement( + [ProcessCategory::STATUS_ACTIVE, ProcessCategory::STATUS_INACTIVE] + ) + ]; +}); diff --git a/database/migrations/2018_06_04_124650_create_process_categories_table.php b/database/migrations/2018_06_04_124650_create_process_categories_table.php index 7fe754ca29..e16703aaef 100644 --- a/database/migrations/2018_06_04_124650_create_process_categories_table.php +++ b/database/migrations/2018_06_04_124650_create_process_categories_table.php @@ -18,6 +18,8 @@ public function up() $table->increments('id'); $table->uuid('uid')->unique(); $table->string('name')->default(''); + $table->enum('status', ['ACTIVE', 'INACTIVE']) + ->default('ACTIVE'); $table->timestamps(); }); } diff --git a/resources/assets/js/processes/categories/components/CategoriesListing.vue b/resources/assets/js/processes/categories/components/CategoriesListing.vue new file mode 100644 index 0000000000..c6b0a91b33 --- /dev/null +++ b/resources/assets/js/processes/categories/components/CategoriesListing.vue @@ -0,0 +1,119 @@ + + + + + \ No newline at end of file diff --git a/resources/assets/js/processes/categories/components/modal/modal-category-add-edit.vue b/resources/assets/js/processes/categories/components/modal/modal-category-add-edit.vue new file mode 100644 index 0000000000..c73cfea74f --- /dev/null +++ b/resources/assets/js/processes/categories/components/modal/modal-category-add-edit.vue @@ -0,0 +1,121 @@ + + + + diff --git a/resources/assets/js/processes/categories/index.js b/resources/assets/js/processes/categories/index.js new file mode 100644 index 0000000000..25072db76e --- /dev/null +++ b/resources/assets/js/processes/categories/index.js @@ -0,0 +1,41 @@ +import Vue from 'vue' +import CategoriesListing from './components/CategoriesListing' +import ModalCategoryAddEdit from "./components/modal/modal-category-add-edit"; + +new Vue({ + el: '#process-categories-listing', + data: { + filter: '', + formData: null, + }, + components: { + CategoriesListing, + ModalCategoryAddEdit, + }, + methods: { + editCategory(data) { + this.formData = Object.assign({}, data); + this.showModal() + }, + showModal() { + this.$refs.addEdit.$refs.modal.show() + }, + deleteCategory(data) { + //@todo implement + ProcessMaker.apiClient.delete('category/' + data.uid) + .then(response => { + ProcessMaker.alert('Category Successfully Deleted', 'success'); + this.reload(); + }) + .catch(error => { + if (error.response.status === 422) { + let errors = error.response.data.errors; + ProcessMaker.alert(errors.processCategory.join(', '), 'danger'); + } + }); + }, + reload() { + this.$refs.list.fetch(); + } + } +}); diff --git a/resources/assets/js/processes/components/ProcessesListing.vue b/resources/assets/js/processes/components/ProcessesListing.vue index 17ddeaaca7..c38ed31fda 100644 --- a/resources/assets/js/processes/components/ProcessesListing.vue +++ b/resources/assets/js/processes/components/ProcessesListing.vue @@ -115,7 +115,7 @@ if (actionType === 'remove-item') { let that = this; - ProcessMaker.confirmModal('Caution!', 'Are you sure to delete the process ' + data.name + '?', '', function () { + ProcessMaker.confirmModal('Caution!', 'Are you sure to delete the category ' + data.name + '?', '', function () { ProcessMaker.apiClient .delete('processes/' + data.uid) .then(response => { diff --git a/resources/assets/js/processes/components/modal/modal-process-add.vue b/resources/assets/js/processes/components/modal/modal-process-add.vue index f9ec694140..1d490a317d 100644 --- a/resources/assets/js/processes/components/modal/modal-process-add.vue +++ b/resources/assets/js/processes/components/modal/modal-process-add.vue @@ -63,17 +63,17 @@ this.loadCategories(); }, loadCategories() { - window.ProcessMaker.apiClient.get('categories') + window.ProcessMaker.apiClient.get('categories?per_page=1000&status=ACTIVE') .then((response) => { let options = [ { value: null, content: 'None' } ]; - response.data.map(function (category) { + response.data.data.map(function (category) { options.push({ - value: category.cat_uid, - content: category.cat_name + value: category.uid, + content: category.name }) }); this.categorySelectOptions = options; diff --git a/resources/lang/en/menus.php b/resources/lang/en/menus.php index 592e91f9f7..d0351ffc7d 100644 --- a/resources/lang/en/menus.php +++ b/resources/lang/en/menus.php @@ -45,5 +45,9 @@ 'manage_cache' => 'Manage Cache ', 'audit_log' => 'Audit Log', 'schedule_jobs' => 'Schedule Jobs', + ], + 'sidebar_processes' => [ + 'processes' => 'Processes', + 'categories' => 'Process Categories', ] ]; diff --git a/resources/lang/en/validation.php b/resources/lang/en/validation.php index 723692c664..0d463e3e87 100644 --- a/resources/lang/en/validation.php +++ b/resources/lang/en/validation.php @@ -109,9 +109,6 @@ 'process_category_manager' => [ 'category_does_not_have_processes' => 'The category cannot be deleted while it is still assigned to processes.', ] - ], - 'cat_name' => [ - 'unique' => 'The category name already exists.' ] ] ]; diff --git a/resources/views/processes/categories/index.blade.php b/resources/views/processes/categories/index.blade.php new file mode 100644 index 0000000000..034e4291ff --- /dev/null +++ b/resources/views/processes/categories/index.blade.php @@ -0,0 +1,32 @@ +@extends('layouts.layout', ['title' => __('Processes Management')]) + +@section('sidebar') + @include('layouts.sidebar', ['sidebar'=> Menu::get('sidebar_processes')]) +@endsection + +@section('content') +
+
+
+
+
+

{{__('Process Categories')}}

+ +
+ +
+ + +
+
+
+@endsection + +@section('js') + +@endsection diff --git a/resources/views/processes/index.blade.php b/resources/views/processes/index.blade.php index d8c9ce80de..2f64e7ee94 100644 --- a/resources/views/processes/index.blade.php +++ b/resources/views/processes/index.blade.php @@ -1,7 +1,7 @@ @extends('layouts.layout', ['title' => __('Processes Management')]) @section('sidebar') - @include('layouts.sidebar', ['sidebar'=> Menu::get('sidebar_process')]) + @include('layouts.sidebar', ['sidebar'=> Menu::get('sidebar_processes')]) @endsection @section('content') diff --git a/routes/web.php b/routes/web.php index 53d1636843..50fd49ef99 100644 --- a/routes/web.php +++ b/routes/web.php @@ -73,6 +73,8 @@ ], function() { $this->get('/process/{process}/tasks', 'Designer\TaskController@index')->name('processes-task-index'); $this->get('/processes', 'Designer\ProcessController@index')->name('processes'); + $this->get('/processes/categories', 'Designer\ProcessCategoryController@index') + ->name('process-categories-index'); }); $this->get('/designer/{process?}', 'Designer\ProcessController@show')->name('designer-edit-process'); diff --git a/tests/Feature/Api/Administration/ProcessCategoryTest.php b/tests/Feature/Api/Administration/ProcessCategoryTest.php new file mode 100644 index 0000000000..2f9073814e --- /dev/null +++ b/tests/Feature/Api/Administration/ProcessCategoryTest.php @@ -0,0 +1,350 @@ +testUser) { + $this->testUser = factory(User::class)->create([ + 'password' => Hash::make('password'), + ]); + } + return call_user_func_array( + [$this->actingAs($this->testUser, 'api'), 'json'], func_get_args() + ); + } + + /** + * Test get the list of categories. + */ + public function testGetListOfCategories() + { + //Create test categories + $process = factory(Process::class)->create(); + $processCategory = $process->category; + + $response = $this->api('GET', self::API_TEST_CATEGORIES); + $response->assertStatus(200); + $response->assertJsonStructure(); + $response->assertJsonFragment( + [ + "uid" => $processCategory->uid, + "name" => $processCategory->name, + "status" => $processCategory->status, + "processes_count" => 1, + ] + ); + } + + /** + * Test get the list of active categories. + */ + public function testGetListOfCategoriesActive() + { + // set seeded categories to inactive + ProcessCategory::query()->update( + ['status' => ProcessCategory::STATUS_INACTIVE] + ); + + //Create test categories + $processCategory1 = factory(ProcessCategory::class)->create( + ['status' => ProcessCategory::STATUS_INACTIVE] + ); + $processCategory2 = factory(ProcessCategory::class)->create( + ['status' => ProcessCategory::STATUS_ACTIVE] + ); + + $response = $this->api('GET', self::API_TEST_CATEGORIES . '?status=ACTIVE'); + $response->assertStatus(200); + $response->assertJsonStructure(); + $this->assertCount(1, $response->json()['data']); + $response->assertJsonFragment( + [ + "uid" => $processCategory2->uid, + ] + ); + } + + /** + * Test get the list of categories filter + */ + public function testGetListOfCategoriesFilter() + { + $process = factory(Process::class)->create(); + + //Create test categories + $processCategory = $process->category; + $otherCategory = factory(ProcessCategory::class)->create(); + + //Test filter + $response = $this->api('GET', self::API_TEST_CATEGORIES . '?filter=' . urlencode($processCategory->name)); + $response->assertStatus(200); + $response->assertJsonStructure(); + + $response->assertJsonFragment( + [ + "uid" => $processCategory->uid, + "name" => $processCategory->name, + "status" => $processCategory->status, + "processes_count" => 1, + ] + ); + + } + /** + * Test sorting by category name + */ + public function testGetListOfCategoriesSorted() + { + factory(ProcessCategory::class)->create([ + 'name' => 'first test category' + ]); + + factory(ProcessCategory::class)->create([ + 'name' => 'second test category' + ]); + + // defaults sort to name ASC + $response = $this->api('GET', self::API_TEST_CATEGORIES . '?filter=test'); + $json = $response->json()['data']; + $this->assertEquals($json[0]['name'], 'first test category'); + $this->assertEquals($json[1]['name'], 'second test category'); + + // sort by name ASC + $response = $this->api( + 'GET', self::API_TEST_CATEGORIES . '?filter=test&order_by=name&order_direction=ASC' + ); + $json = $response->json()['data']; + $this->assertEquals($json[0]['name'], 'first test category'); + $this->assertEquals($json[1]['name'], 'second test category'); + + // sort by name DESC + $response = $this->api( + 'GET', self::API_TEST_CATEGORIES . '?filter=test&order_by=name&order_direction=DESC' + ); + $json = $response->json()['data']; + $this->assertEquals($json[0]['name'], 'second test category'); + $this->assertEquals($json[1]['name'], 'first test category'); + } + + /** + * Test get the list of categories without results + */ + public function testGetFilterWithoutResult() + { + //Create test categories + $processCategory = factory(ProcessCategory::class)->create(); + factory(ProcessCategory::class)->create(); + factory(Process::class)->create([ + 'process_category_id' => $processCategory->id + ]); + //Test filter not found + $response = $this->api('GET', self::API_TEST_CATEGORIES . '?filter=NOT_FOUND_TEXT'); + $response->assertStatus(200); + $response->assertJsonStructure(); + $this->assertCount(0, $response->json()['data']); + } + + /** + * Test get the list of categories with start and limit + */ + public function testGetListOfCategoriesStartLimit() + { + //Create test categories + $processCategory1 = factory(ProcessCategory::class)->create(['name' => "a"]); + $processCategory2 = factory(ProcessCategory::class)->create(['name' => "b"]); + + //Test start and limit + $response = $this->api('GET', self::API_TEST_CATEGORIES . '?per_page=1'); + $response->assertStatus(200); + $response->assertJsonStructure(); + $response->assertJsonFragment( + [ + "uid" => $processCategory1->uid, + "name" => $processCategory1->name, + "processes_count" => 0, + ] + ); + $this->assertCount(1, $response->json()['data']); + } + + /** + * Test the creation of process categories. + */ + public function testCreateProcessCategory() + { + $faker = Faker::create(); + + $processCategory = factory(ProcessCategory::class)->make(); + $data = [ + "name" => $processCategory->name, + "status" => $processCategory->status, + ]; + $response = $this->api('POST', self::API_TEST_CATEGORY, $data); + $response->assertStatus(201); + $response->assertJsonStructure(); + $processCategoryJson = $response->json(); + $processCategory = ProcessCategory::where('uid', $processCategoryJson['uid']) + ->first(); + $this->assertNotNull($processCategory); + $response->assertJsonFragment( + [ + "uid" => $processCategory->uid, + "name" => $processCategory->name, + "status" => $processCategory->status, + "processes_count" => 0, + ] + ); + + //Validate required name + $response = $this->api('POST', self::API_TEST_CATEGORY, []); + $response->assertStatus(422); + $this->assertEquals( + __('validation.required', ['attribute' => 'name']), + $response->json()['errors']['name'][0] + ); + + //Validate creation of duplicated category + $response = $this->api('POST', self::API_TEST_CATEGORY, $data); + $response->assertStatus(422); + $this->assertEquals( + __('validation.unique', ['attribute' => 'name']), + $response->json()['errors']['name'][0] + ); + + //Validate invalid large name + $data = [ + "name" => $faker->sentence(100), + "status" => $processCategory->status, + ]; + $response = $this->api('POST', self::API_TEST_CATEGORY, $data); + $response->assertStatus(422); + $this->assertEquals( + __('validation.max.string', ['attribute' => 'name', 'max' => 100]), + $response->json()['errors']['name'][0] + ); + } + + /** + * Test the update of process categories. + */ + public function testUpdateProcessCategory() + { + $faker = Faker::create(); + + $processCategoryExisting = factory(ProcessCategory::class)->create(); + $processCategory = factory(ProcessCategory::class)->create(); + $catUid = $processCategory->uid; + $data = [ + "name" => $faker->name(), + "status" => ProcessCategory::STATUS_ACTIVE, + ]; + $response = $this->api('PUT', self::API_TEST_CATEGORY . $catUid, $data); + $response->assertStatus(200); + $response->assertJsonStructure(); + $processCategoryJson = $response->json(); + $processCategory = ProcessCategory::where('uid', $processCategoryJson['uid']) + ->first(); + $this->assertNotNull($processCategory); + $this->assertEquals($processCategory->uid, $processCategoryJson['uid']); + $this->assertEquals($processCategory->name, $data['name']); + + //Validate required name + $response = $this->api('PUT', self::API_TEST_CATEGORY . $catUid, ["name" => '']); + $response->assertStatus(422); + $this->assertEquals( + __('validation.required', ['attribute' => 'name']), + $response->json()['errors']['name'][0] + ); + + //Validate 404 if category does not exists + $response = $this->api('PUT', self::API_TEST_CATEGORY . 'DOES_NOT_EXISTS', $data); + $response->assertStatus(404); + + //Validate that category name is unique + $data = [ + "name" => $processCategoryExisting->name, + ]; + $response = $this->api('PUT', self::API_TEST_CATEGORY . $catUid, $data); + $response->assertStatus(422); + $this->assertEquals( + __('validation.unique', ['attribute' => 'name']), + $response->json()['errors']['name'][0] + ); + + //Validate invalid large name + $data = [ + "name" => $faker->sentence(100), + ]; + $response = $this->api('PUT', self::API_TEST_CATEGORY . $catUid, $data); + $response->assertStatus(422); + $this->assertEquals( + __('validation.max.string', ['attribute' => 'name', 'max' => 100]), + $response->json()['errors']['name'][0] + ); + } + + /** + * Test the deletion of process categories. + */ + public function testDeleteProcessCategory() + { + $processCategory = factory(ProcessCategory::class)->create(); + $catUid = $processCategory->uid; + + $response = $this->api('DELETE', self::API_TEST_CATEGORY . $catUid); + $response->assertStatus(204); + + //Validate 404 if category does not exists + $response = $this->api('DELETE', self::API_TEST_CATEGORY . 'DOES_NOT_EXISTS'); + $response->assertStatus(404); + + //Validate to do not delete category with processes + $processCategory = factory(ProcessCategory::class)->create(); + $catUid = $processCategory->uid; + factory(Process::class)->create([ + 'process_category_id' => $processCategory->id + ]); + + } + + /** + * Test the show of process categories. + */ + public function testShowProcessCategory() + { + $processCategory = factory(ProcessCategory::class)->create(); + $catUid = $processCategory->uid; + + $response = $this->api('GET', self::API_TEST_CATEGORY . $catUid); + $response->assertStatus(200); + $response->assertJsonStructure(); + $processCategoryJson = $response->json(); + $this->assertEquals($processCategory->uid, $processCategoryJson['uid']); + $this->assertEquals($processCategory->name, $processCategoryJson['name']); + + //Validate 404 if category does not exists + $response = $this->api('GET', self::API_TEST_CATEGORY . 'DOES_NOT_EXISTS'); + $response->assertStatus(404); + } +} diff --git a/tests/js/processes/categories/components/CategoriesListing.test.js b/tests/js/processes/categories/components/CategoriesListing.test.js new file mode 100644 index 0000000000..a3ac871143 --- /dev/null +++ b/tests/js/processes/categories/components/CategoriesListing.test.js @@ -0,0 +1,7 @@ +import {mount} from '@vue/test-utils' +import CategoriesListing from '../../../../../resources/assets/js/processes/categories/components/CategoriesListing'; + +let wrapper = null; + +describe('Process Categories', () => { +}); \ No newline at end of file diff --git a/tests/unit/ProcessMaker/Model/ProcessCategoryTest.php b/tests/unit/ProcessMaker/Model/ProcessCategoryTest.php new file mode 100644 index 0000000000..f0106481be --- /dev/null +++ b/tests/unit/ProcessMaker/Model/ProcessCategoryTest.php @@ -0,0 +1,44 @@ +assertFalse($pc->isValid()); + + $pc->name = 'Test category'; + $pc->status = ProcessCategory::STATUS_ACTIVE; + $pc->isValid(); + $this->assertTrue($pc->isValid()); + + $pc->status = 'invalid'; + $this->assertFalse($pc->isValid()); + } + + /** + * Test validation when deleting with processes + */ + public function testHasProcessesValidation() + { + $process = factory(Process::class)->create(); + $processCategory = $process->category; + + $this->expectException(ValidationException::class); + + $processCategory->delete(); + } +} diff --git a/webpack.mix.js b/webpack.mix.js index 146b782d94..3230487aec 100644 --- a/webpack.mix.js +++ b/webpack.mix.js @@ -27,6 +27,7 @@ mix.webpackConfig({ .js('resources/assets/js/management/preferences/index.js', 'public/js/management/preferences') .js('resources/assets/js/processes/tasks/index.js', 'public/js/processes/tasks') .js('resources/assets/js/processes/index.js', 'public/js/processes') + .js('resources/assets/js/processes/categories/index.js', 'public/js/processes/categories') .js('resources/assets/js/requests/index.js', 'public/js/requests') .js('resources/assets/js/nayra/start.js', 'public/js/nayra')