From fb7d5df759f93450cb92b54ffb344838098eb4ad Mon Sep 17 00:00:00 2001 From: Paula Quispe Date: Mon, 30 Sep 2024 20:42:02 -0400 Subject: [PATCH 1/7] FOUR-18968 --- .../Http/Controllers/Api/TaskController.php | 7 ++++ .../Traits/TaskControllerIndexMethods.php | 33 ++++++++++++++++--- .../casesDetail/components/RequestTable.vue | 2 +- .../casesDetail/components/TaskTable.vue | 2 +- .../cases/casesMain/CasesDataSection.vue | 2 +- tests/Feature/Api/TaskControllerTest.php | 32 ++++++++++++++++++ 6 files changed, 71 insertions(+), 7 deletions(-) diff --git a/ProcessMaker/Http/Controllers/Api/TaskController.php b/ProcessMaker/Http/Controllers/Api/TaskController.php index 929f3da72d..5fc33fbbfd 100644 --- a/ProcessMaker/Http/Controllers/Api/TaskController.php +++ b/ProcessMaker/Http/Controllers/Api/TaskController.php @@ -178,8 +178,11 @@ public function indexCase(Request $request, User $user = null) 'order_direction' => 'nullable|string|in:asc,desc', 'page' => 'nullable|integer|min:1', 'per_page' => 'nullable|integer', + 'includeScreen' => 'sometimes|boolean', ]); + $includeScreen = $request->input('includeScreen', false); + // Get only the columns defined $query = ProcessRequestToken::select($this->defaultCase); // Filter by case_number @@ -200,6 +203,10 @@ public function indexCase(Request $request, User $user = null) try { $response = $query->applyPagination($request); $response->inOverdue = 0; + + if ($includeScreen) { + $response = $this->processScreenData($response); + } } catch (QueryException $e) { return $this->handleQueryException($e); } diff --git a/ProcessMaker/Traits/TaskControllerIndexMethods.php b/ProcessMaker/Traits/TaskControllerIndexMethods.php index e4d171cc45..c20507f84a 100644 --- a/ProcessMaker/Traits/TaskControllerIndexMethods.php +++ b/ProcessMaker/Traits/TaskControllerIndexMethods.php @@ -7,6 +7,7 @@ use Illuminate\Support\Arr; use Illuminate\Support\Str; use ProcessMaker\Filters\Filter; +use ProcessMaker\Managers\DataManager; use ProcessMaker\Models\ProcessRequest; use ProcessMaker\Models\ProcessRequestToken; use ProcessMaker\Models\User; @@ -17,18 +18,18 @@ trait TaskControllerIndexMethods private function indexBaseQuery($request) { $query = ProcessRequestToken::exclude(['data'])->with([ - 'processRequest' => fn($q) => $q->exclude(['data']), + 'processRequest' => fn ($q) => $q->exclude(['data']), // review if bpmn is reuiqred here process - 'process' => fn($q) => $q->exclude(['svg', 'warnings']), + 'process' => fn ($q) => $q->exclude(['svg', 'warnings']), // review if bpmn is reuiqred here processRequest.process - 'processRequest.process' => fn($q) => $q->exclude(['svg', 'warnings']), + 'processRequest.process' => fn ($q) => $q->exclude(['svg', 'warnings']), // The following lines use to much memory but reduce the number of queries // bpmn is required here in processRequest.processVersion // 'processRequest.processVersion' => fn($q) => $q->exclude(['svg', 'warnings']), // review if bpmn is reuiqred here processRequest.processVersion.process // 'processRequest.processVersion.process' => fn($q) => $q->exclude(['svg', 'warnings']), 'user', - 'draft' + 'draft', ]); $include = $request->input('include') ? explode(',', $request->input('include')) : []; @@ -123,6 +124,30 @@ private function applyDefaultFiltering($query, $column, $filterByFields, $fieldF $query->where(is_string($key) ? $key : $column, $operator, $fieldFilter); } + private function processScreenData($response) + { + $collection = $response->getCollection()->transform(function ($token) { + $definition = $token->getDefinition(); + + if (array_key_exists('screenRef', $definition)) { + $screen = $token->getScreenVersion(); + if ($screen) { + $dataManager = new DataManager(); + $screen->data = $dataManager->getData($token, true); + $screen->screen_id = $screen->id; + + return $screen; + } + } + + return $token; + })->values(); + + $response->setCollection($collection); + + return $response; + } + private function excludeNonVisibleTasks($query, $request) { $nonSystem = filter_var($request->input('non_system'), FILTER_VALIDATE_BOOLEAN); diff --git a/resources/jscomposition/cases/casesDetail/components/RequestTable.vue b/resources/jscomposition/cases/casesDetail/components/RequestTable.vue index 797ed4606b..2f850acf76 100644 --- a/resources/jscomposition/cases/casesDetail/components/RequestTable.vue +++ b/resources/jscomposition/cases/casesDetail/components/RequestTable.vue @@ -24,7 +24,7 @@ export default defineComponent({ const columnsConfig = ref(null); const dataPagination = ref({ total: 153, - page: 0, + page: 1, pages: 10, perPage: 15, }); diff --git a/resources/jscomposition/cases/casesDetail/components/TaskTable.vue b/resources/jscomposition/cases/casesDetail/components/TaskTable.vue index 5cd0f71eec..01b08e2f7a 100644 --- a/resources/jscomposition/cases/casesDetail/components/TaskTable.vue +++ b/resources/jscomposition/cases/casesDetail/components/TaskTable.vue @@ -27,7 +27,7 @@ const data = ref(null); const columnsConfig = ref(null); const dataPagination = ref({ total: 153, - page: 0, + page: 1, pages: 10, perPage: 15, }); diff --git a/resources/jscomposition/cases/casesMain/CasesDataSection.vue b/resources/jscomposition/cases/casesMain/CasesDataSection.vue index d4040f7f21..5050dd8e5f 100644 --- a/resources/jscomposition/cases/casesMain/CasesDataSection.vue +++ b/resources/jscomposition/cases/casesMain/CasesDataSection.vue @@ -48,7 +48,7 @@ export default defineComponent({ const dataPagination = ref({ total: 153, - page: 0, + page: 1, pages: 10, perPage: 15, }); diff --git a/tests/Feature/Api/TaskControllerTest.php b/tests/Feature/Api/TaskControllerTest.php index ead180bc0d..64dd4f4705 100644 --- a/tests/Feature/Api/TaskControllerTest.php +++ b/tests/Feature/Api/TaskControllerTest.php @@ -107,4 +107,36 @@ public function test_index_case_returns_inactive_tasks_for_case_number() 'meta', ]); } + + /** + * Test indexCase returns completed tasks related to the case_number. + * + * @return void + */ + public function test_index_cas_returns_with_data() + { + // Simulate an authenticated user + $user = User::factory()->create(); + Auth::login($user); + + // Create a ProcessRequestToken associated with a specific case_number + $processRequest = ProcessRequest::factory()->create(); + ProcessRequestToken::factory()->create([ + 'user_id' => $user->id, + 'status' => 'COMPLETED', + 'process_request_id' => $processRequest->id, // id del ProcessRequest + ]); + + // Call the endpoint with the 'case_number' parameter + $filter = "?case_number=$processRequest->case_number&status=COMPLETED&includeScreen=" . true; + $response = $this->apiCall('GET', self::API_TASK_BY_CASE . $filter); + + // Check if the response is successful and contains the expected tasks + $response->assertStatus(200); + $this->assertCount(1, $response->json('data')); + $response->assertJsonStructure([ + 'data' => ['*' => self::TASK_BY_CASE_STRUCTURE], + 'meta', + ]); + } } From a1ee8d4da14dcdae078940a9b27556a5aaa981af Mon Sep 17 00:00:00 2001 From: Paula Quispe Date: Wed, 2 Oct 2024 13:15:38 -0400 Subject: [PATCH 2/7] solve unit test issue --- tests/Feature/Api/TaskControllerTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Feature/Api/TaskControllerTest.php b/tests/Feature/Api/TaskControllerTest.php index 38a6285d72..53c96936f5 100644 --- a/tests/Feature/Api/TaskControllerTest.php +++ b/tests/Feature/Api/TaskControllerTest.php @@ -123,12 +123,12 @@ public function test_index_cas_returns_with_data() $processRequest = ProcessRequest::factory()->create(); ProcessRequestToken::factory()->create([ 'user_id' => $user->id, - 'status' => 'COMPLETED', + 'status' => 'CLOSED', 'process_request_id' => $processRequest->id, // id del ProcessRequest ]); // Call the endpoint with the 'case_number' parameter - $filter = "?case_number=$processRequest->case_number&status=COMPLETED&includeScreen=" . true; + $filter = "?case_number=$processRequest->case_number&status=CLOSED&includeScreen=" . true; $response = $this->apiCall('GET', self::API_TASK_BY_CASE . $filter); // Check if the response is successful and contains the expected tasks From bbd89585bf894a1c97cfe699b022b5f9c731803d Mon Sep 17 00:00:00 2001 From: paulis Date: Wed, 2 Oct 2024 23:18:10 -0400 Subject: [PATCH 3/7] solving obser --- ProcessMaker/Traits/TaskControllerIndexMethods.php | 6 ++---- .../cases/casesDetail/components/TaskTable.vue | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/ProcessMaker/Traits/TaskControllerIndexMethods.php b/ProcessMaker/Traits/TaskControllerIndexMethods.php index c20507f84a..ee668ccaee 100644 --- a/ProcessMaker/Traits/TaskControllerIndexMethods.php +++ b/ProcessMaker/Traits/TaskControllerIndexMethods.php @@ -129,14 +129,12 @@ private function processScreenData($response) $collection = $response->getCollection()->transform(function ($token) { $definition = $token->getDefinition(); + $token->screenData = null; if (array_key_exists('screenRef', $definition)) { $screen = $token->getScreenVersion(); if ($screen) { $dataManager = new DataManager(); - $screen->data = $dataManager->getData($token, true); - $screen->screen_id = $screen->id; - - return $screen; + $token->screenData = $dataManager->getData($token, true); } } diff --git a/resources/jscomposition/cases/casesDetail/components/TaskTable.vue b/resources/jscomposition/cases/casesDetail/components/TaskTable.vue index 9ec70cebf6..60276e8a0a 100644 --- a/resources/jscomposition/cases/casesDetail/components/TaskTable.vue +++ b/resources/jscomposition/cases/casesDetail/components/TaskTable.vue @@ -29,7 +29,7 @@ const data = ref(null); const columnsConfig = ref(null); const dataPagination = ref({ total: 153, - page: 0, + page: 1, pages: 10, perPage: 15, }); From caeacf1d8dfe7d8dcebb86df78f0a0a97940cea0 Mon Sep 17 00:00:00 2001 From: Fabio Date: Thu, 3 Oct 2024 12:35:07 -0400 Subject: [PATCH 4/7] FOUR-19366:Request - Details add a button "Go to Case" --- resources/views/requests/show.blade.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/resources/views/requests/show.blade.php b/resources/views/requests/show.blade.php index cb15a74490..e28283ce3d 100644 --- a/resources/views/requests/show.blade.php +++ b/resources/views/requests/show.blade.php @@ -345,6 +345,13 @@ class="btn d-block mr-0 ml-auto button-collapse" @endif +
  • + +
  • @{{ __(statusLabel) }}
    @@ -486,6 +493,7 @@ class="btn btn-outline-info btn-block" window.PM4ConfigOverrides = { requestFiles: @json($request->requestFiles()) }; + const request = @json($request); @@ -785,6 +793,9 @@ classStatusCard() { }, ); }, + onReturnCase() { + window.open(`../cases/${request.case_number}`); + }, completeRequest() { ProcessMaker.confirmModal( this.$t('Caution!'), From 7db5368a24eb5505b100802890f0dd1b9a4eacab Mon Sep 17 00:00:00 2001 From: Paula Quispe Date: Thu, 3 Oct 2024 18:59:15 -0400 Subject: [PATCH 5/7] solving issue with test --- .../Http/Controllers/Api/TaskController.php | 4 ++-- .../Traits/TaskControllerIndexMethods.php | 20 +++++-------------- routes/api.php | 2 +- tests/Feature/Api/TaskControllerTest.php | 2 +- 4 files changed, 9 insertions(+), 19 deletions(-) diff --git a/ProcessMaker/Http/Controllers/Api/TaskController.php b/ProcessMaker/Http/Controllers/Api/TaskController.php index bcc44edaf0..e0540bec79 100644 --- a/ProcessMaker/Http/Controllers/Api/TaskController.php +++ b/ProcessMaker/Http/Controllers/Api/TaskController.php @@ -164,7 +164,7 @@ public function index(Request $request, $getTotal = false, User $user = null) * @param User $user used by Saved Search package to return accurate counts * @return array */ - public function indexCase(Request $request, User $user = null) + public function getTasksByCase(Request $request, User $user = null) { if (!$user) { $user = Auth::user(); @@ -202,11 +202,11 @@ public function indexCase(Request $request, User $user = null) try { $response = $query->applyPagination($request); - $response->inOverdue = 0; if ($includeScreen) { $response = $this->processScreenData($response); } + $response->inOverdue = 0; } catch (QueryException $e) { return $this->handleQueryException($e); } diff --git a/ProcessMaker/Traits/TaskControllerIndexMethods.php b/ProcessMaker/Traits/TaskControllerIndexMethods.php index ee668ccaee..39a5208546 100644 --- a/ProcessMaker/Traits/TaskControllerIndexMethods.php +++ b/ProcessMaker/Traits/TaskControllerIndexMethods.php @@ -126,22 +126,12 @@ private function applyDefaultFiltering($query, $column, $filterByFields, $fieldF private function processScreenData($response) { - $collection = $response->getCollection()->transform(function ($token) { - $definition = $token->getDefinition(); - - $token->screenData = null; - if (array_key_exists('screenRef', $definition)) { - $screen = $token->getScreenVersion(); - if ($screen) { - $dataManager = new DataManager(); - $token->screenData = $dataManager->getData($token, true); - } - } + $dataManager = new DataManager(); + $response->getCollection()->transform(function ($row) use ($dataManager) { + $row->taskData = $dataManager->getData($row); - return $token; - })->values(); - - $response->setCollection($collection); + return $row; + }); return $response; } diff --git a/routes/api.php b/routes/api.php index f32d2b8c2a..211c87917f 100644 --- a/routes/api.php +++ b/routes/api.php @@ -189,7 +189,7 @@ // Tasks Route::get('tasks', [TaskController::class, 'index'])->name('tasks.index'); // Already filtered in controller - Route::get('tasks-by-case', [TaskController::class, 'indexCase'])->name('tasks.indexCase'); + Route::get('tasks-by-case', [TaskController::class, 'getTasksByCase'])->name('tasks.index.case'); Route::get('tasks/{task}', [TaskController::class, 'show'])->name('tasks.show')->middleware('can:view,task'); Route::get('tasks/{task}/screen_fields', [TaskController::class, 'getScreenFields'])->name('getScreenFields.show')->middleware('can:view,task'); Route::get('tasks/{task}/screens/{screen}', [TaskController::class, 'getScreen'])->name('tasks.get_screen')->middleware('can:viewScreen,task,screen'); diff --git a/tests/Feature/Api/TaskControllerTest.php b/tests/Feature/Api/TaskControllerTest.php index 53c96936f5..2c36069bb2 100644 --- a/tests/Feature/Api/TaskControllerTest.php +++ b/tests/Feature/Api/TaskControllerTest.php @@ -135,7 +135,7 @@ public function test_index_cas_returns_with_data() $response->assertStatus(200); $this->assertCount(1, $response->json('data')); $response->assertJsonStructure([ - 'data' => ['*' => self::TASK_BY_CASE_STRUCTURE], + 'data' => ['*' => array_merge(self::TASK_BY_CASE_STRUCTURE, ['taskData'])], 'meta', ]); } From 1057b59aa746353aeac6a0c6b3209f71a659d5f2 Mon Sep 17 00:00:00 2001 From: Paula Quispe Date: Thu, 3 Oct 2024 19:11:36 -0400 Subject: [PATCH 6/7] update the method name --- ProcessMaker/Http/Controllers/Api/TaskController.php | 2 +- ProcessMaker/Traits/TaskControllerIndexMethods.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ProcessMaker/Http/Controllers/Api/TaskController.php b/ProcessMaker/Http/Controllers/Api/TaskController.php index e0540bec79..401b354a8c 100644 --- a/ProcessMaker/Http/Controllers/Api/TaskController.php +++ b/ProcessMaker/Http/Controllers/Api/TaskController.php @@ -204,7 +204,7 @@ public function getTasksByCase(Request $request, User $user = null) $response = $query->applyPagination($request); if ($includeScreen) { - $response = $this->processScreenData($response); + $response = $this->addTaskData($response); } $response->inOverdue = 0; } catch (QueryException $e) { diff --git a/ProcessMaker/Traits/TaskControllerIndexMethods.php b/ProcessMaker/Traits/TaskControllerIndexMethods.php index 39a5208546..62ac5055e1 100644 --- a/ProcessMaker/Traits/TaskControllerIndexMethods.php +++ b/ProcessMaker/Traits/TaskControllerIndexMethods.php @@ -124,7 +124,7 @@ private function applyDefaultFiltering($query, $column, $filterByFields, $fieldF $query->where(is_string($key) ? $key : $column, $operator, $fieldFilter); } - private function processScreenData($response) + private function addTaskData($response) { $dataManager = new DataManager(); $response->getCollection()->transform(function ($row) use ($dataManager) { From b0e94e919cb7871dc0fb36c12f561114ff225d38 Mon Sep 17 00:00:00 2001 From: Paula Quispe Date: Fri, 4 Oct 2024 16:21:15 -0400 Subject: [PATCH 7/7] FOUR-18969 --- .../Controllers/Api/CommentController.php | 44 ++++++++++- ...4956_add_case_number_to_comments_table.php | 31 ++++++++ routes/api.php | 1 + tests/Feature/Api/CommentTest.php | 76 +++++++++++++++++++ 4 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 database/migrations/2024_10_04_154956_add_case_number_to_comments_table.php diff --git a/ProcessMaker/Http/Controllers/Api/CommentController.php b/ProcessMaker/Http/Controllers/Api/CommentController.php index de799861b3..1f9724b32c 100644 --- a/ProcessMaker/Http/Controllers/Api/CommentController.php +++ b/ProcessMaker/Http/Controllers/Api/CommentController.php @@ -29,7 +29,7 @@ class CommentController extends Controller * * @param Request $request * - * @return \ProcessMaker\Http\Resources\ApiCollection + * @return ApiCollection * * @return \Illuminate\Http\Response */ @@ -87,6 +87,48 @@ public function index(Request $request) return new ApiCollection($response); } + /** + * Display comments related to the case + * + * @param Request $request + * + * @return ApiCollection + * + * @return \Illuminate\Http\Response + */ + public function getCommentsByCase(Request $request) + { + $request->validate([ + 'case_number' => 'required|integer', + ]); + + $query = Comment::query() + ->with('user') + ->with('repliedMessage'); + + $flag = 'visible'; + if (\Auth::user()->is_administrator) { + $flag = 'all'; + } + $query->hidden($flag); + $caseNumber = $request->input('case_number', null); + + $query->where('case_number', $caseNumber); + + if ($request->has('type')) { + $types = explode(',', $request->input('type')); + $query->whereIn('type', $types); + } + + $response = + $query->orderBy( + $request->input('order_by', 'created_at'), + $request->input('order_direction', 'ASC') + )->paginate($request->input('per_page', 100)); + + return new ApiCollection($response); + } + private function authorizeComment(Request $request) { $request->validate([ diff --git a/database/migrations/2024_10_04_154956_add_case_number_to_comments_table.php b/database/migrations/2024_10_04_154956_add_case_number_to_comments_table.php new file mode 100644 index 0000000000..fb41fb6520 --- /dev/null +++ b/database/migrations/2024_10_04_154956_add_case_number_to_comments_table.php @@ -0,0 +1,31 @@ +unsignedInteger('case_number')->nullable(); + + $table->index('type'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('comments', function (Blueprint $table) { + $table->dropColumn('case_number'); + + $table->dropIndex(['type']); + }); + } +}; diff --git a/routes/api.php b/routes/api.php index 211c87917f..b534a8ca0b 100644 --- a/routes/api.php +++ b/routes/api.php @@ -263,6 +263,7 @@ // Comments Route::get('comments', [CommentController::class, 'index'])->name('comments.index'); + Route::get('comments-by-case', [CommentController::class, 'getCommentsByCase'])->name('comments.index.case'); Route::get('comments/{comment}', [CommentController::class, 'show'])->name('comments.show'); Route::post('comments', [CommentController::class, 'store'])->name('comments.store'); Route::put('comments/{comment}', [CommentController::class, 'update'])->name('comments.update'); diff --git a/tests/Feature/Api/CommentTest.php b/tests/Feature/Api/CommentTest.php index a76dc1423c..5385578231 100644 --- a/tests/Feature/Api/CommentTest.php +++ b/tests/Feature/Api/CommentTest.php @@ -21,6 +21,8 @@ class CommentTest extends TestCase const API_TEST_URL = '/comments'; + const API_COMMENT_BY_CASE = '/comments-by-case'; + const STRUCTURE = [ 'id', 'user_id', @@ -220,4 +222,78 @@ public function testDeleteCommentNotExist() //Validate the header status code $response->assertStatus(405); } + + /** + * Test indexCase without case_number. + * + * @return void + */ + public function test_index_case_requires_case_number() + { + // Call the endpoint without the 'case_number' parameter + $response = $this->apiCall('GET', self::API_COMMENT_BY_CASE); + + // Check if the response returns a 400 error due to missing 'case_number' + $response->assertStatus(422) + ->assertJson(['message' => 'The Case number field is required.']); + } + + /** + * Test comments by case + */ + public function testGetCommentByTypeByCase() + { + $this->user = User::factory()->create([ + 'password' => Hash::make('password'), + 'is_administrator' => false, + ]); + // Create a request1 then a task related to the request + $request1 = ProcessRequest::factory()->create(); + $task1 = ProcessRequestToken::factory()->create([ + 'user_id' => $this->user->getKey(), + 'process_request_id' => $request1->getKey(), + ]); + Comment::factory()->count(2)->create([ + 'commentable_id' => $request1->getKey(), + 'commentable_type' => get_class($request1), + 'case_number' => $request1->case_number, + 'type' => 'LOG', + 'hidden' => false, + ]); + Comment::factory()->count(2)->create([ + 'commentable_id' => $task1->getKey(), + 'commentable_type' => get_class($task1), + 'case_number' => $request1->case_number, + 'type' => 'LOG', + 'hidden' => false, + ]); + // Create a request2 with the same case_number then a task related to the request + $request2 = ProcessRequest::factory()->create([ + 'parent_request_id' => $request1->getKey(), + ]); + $task2 = ProcessRequestToken::factory()->create([ + 'user_id' => $this->user->getKey(), + 'process_request_id' => $request2->getKey(), + ]); + Comment::factory()->count(2)->create([ + 'commentable_id' => $request2->getKey(), + 'commentable_type' => get_class($request2), + 'case_number' => $request1->case_number, + 'type' => 'LOG', + 'hidden' => false, + ]); + Comment::factory()->count(2)->create([ + 'commentable_id' => $task2->getKey(), + 'commentable_type' => get_class($task2), + 'case_number' => $request1->case_number, + 'type' => 'LOG', + 'hidden' => false, + ]); + // Load api + $filter = "?case_number=$request1->case_number"; + $response = $this->apiCall('GET', self::API_COMMENT_BY_CASE . $filter); + // Check if the response is successful and contains the expected tasks + $response->assertStatus(200); + $this->assertCount(8, $response->json('data')); + } }