diff --git a/ProcessMaker/Http/Controllers/Api/ProcessRequestController.php b/ProcessMaker/Http/Controllers/Api/ProcessRequestController.php index 29f6df3b0e..a57f89cd23 100644 --- a/ProcessMaker/Http/Controllers/Api/ProcessRequestController.php +++ b/ProcessMaker/Http/Controllers/Api/ProcessRequestController.php @@ -839,4 +839,43 @@ public function endEventDestination(ProcessRequest $request) return response()->json(['message' => __('End event found'), 'data' => $data]); } + + /** + * This endpoint returns requests by case number + * + * @param Request $request + * + * @return ApiCollection + */ + public function getRequestsByCase(Request $request, User $user = null) + { + if (!$user) { + $user = Auth::user(); + } + + // Validate the inputs, including optional ones + $request->validate([ + 'case_number' => 'required|integer', + 'order_by' => 'nullable|string|in:id,name,status,user_id,initiated_at,participants', + 'order_direction' => 'nullable|string|in:asc,desc', + 'page' => 'nullable|integer|min:1', + 'per_page' => 'nullable|integer', + ]); + + $query = ProcessRequest::forUser($user); + + // Filter by case_number + $query->filterByCaseNumber($request); + + // Apply ordering only if a valid order_by field is provided + $query->applyOrdering($request); + $response = $query->applyPagination($request); + + // Get activeTasks and participants + $response = $response->map(function ($processRequest) use ($request) { + return new ProcessRequestResource($processRequest); + }); + + return new ApiCollection($response); + } } diff --git a/ProcessMaker/Models/ProcessRequest.php b/ProcessMaker/Models/ProcessRequest.php index 8b83e3a498..6ddb886dcc 100644 --- a/ProcessMaker/Models/ProcessRequest.php +++ b/ProcessMaker/Models/ProcessRequest.php @@ -1089,4 +1089,36 @@ public function getElementDestination(): ?array return $endEvents->first()->elementDestination; } + + /** + * Scope apply order + */ + public function scopeApplyOrdering($query, $request) + { + $orderBy = $request->input('order_by', 'name'); + $orderDirection = $request->input('order_direction', 'asc'); + + return $query->orderBy($orderBy, $orderDirection); + } + + /** + * Scope apply pagination + */ + public function scopeApplyPagination($query, $request) + { + $page = $request->input('page', 1); + $perPage = $request->input('per_page', 10); + + return $query->paginate($perPage); + } + + /** + * Scope to filter by case_number + */ + public function scopeFilterByCaseNumber($query, $request) + { + $caseNumber = $request->input('case_number'); + + return $query->where('case_number', $caseNumber); + } } diff --git a/routes/api.php b/routes/api.php index 0c85364ffd..f32d2b8c2a 100644 --- a/routes/api.php +++ b/routes/api.php @@ -215,6 +215,7 @@ // Cases //Route::get('cases', [ProcessRequestController::class, 'index'])->name('cases.index'); + Route::get('requests-by-case', [ProcessRequestController::class, 'getRequestsByCase'])->name('requests.getRequestsByCase'); // Requests Route::get('requests', [ProcessRequestController::class, 'index'])->name('requests.index'); // Already filtered in controller Route::get('requests/{process}/count', [ProcessRequestController::class, 'getCount'])->name('requests.count'); diff --git a/tests/Feature/Api/ProcessRequestsTest.php b/tests/Feature/Api/ProcessRequestsTest.php index bc6c837089..438e97daef 100644 --- a/tests/Feature/Api/ProcessRequestsTest.php +++ b/tests/Feature/Api/ProcessRequestsTest.php @@ -30,6 +30,7 @@ class ProcessRequestsTest extends TestCase public $withPermissions = true; const API_TEST_URL = '/requests'; + const API_REQUESTS_BY_CASE = '/requests-by-case'; const STRUCTURE = [ 'id', @@ -986,4 +987,44 @@ public function testScreenRequested() $data = $response->json()['data']; $this->assertEmpty($data); } + + /** + * Get a list of Requests by Cases. + */ + public function testRequestByCase() + { + ProcessRequest::query()->delete(); + $request = ProcessRequest::factory()->create(); + ProcessRequest::factory()->count(9)->create([ + 'parent_request_id' => $request->id, + ]); + + $url = self::API_REQUESTS_BY_CASE . '?case_number=' . $request->case_number; + + $response = $this->apiCall('GET', $url); + + //Validate the header status code + $response->assertStatus(200); + + // Verify structure + $response->assertJsonStructure([ + 'data' => ['*' => self::STRUCTURE], + 'meta', + ]); + + // Verify count + $this->assertEquals(10, $response->json()['meta']['total']); + } + + /** + * Get a list of Requests by Cases. + */ + public function testRequestByCaseWithoutCaseNumber() + { + $response = $this->apiCall('GET', self::API_REQUESTS_BY_CASE); + + //Validate the header status code + $response->assertStatus(422); + $this->assertEquals('The Case number field is required.', $response->json()['message']); + } }