Skip to content

Commit 01ed082

Browse files
committed
Add case delete endpoint and action with tests
1 parent f638260 commit 01ed082

5 files changed

Lines changed: 150 additions & 6 deletions

File tree

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
namespace ProcessMaker\Http\Controllers\Api\Actions\Cases;
4+
5+
use Illuminate\Support\Facades\DB;
6+
use ProcessMaker\Models\CaseNumber;
7+
use ProcessMaker\Models\CaseParticipated;
8+
use ProcessMaker\Models\CaseStarted;
9+
use ProcessMaker\Models\ProcessRequest;
10+
11+
class DeleteCase
12+
{
13+
public function __invoke(string $caseNumber): void
14+
{
15+
// Delete later dependent records for requests and tokens (process_request_tokens,
16+
// process_request_locks, process_abe_request_tokens, scheduled_tasks,
17+
// inbox_rules, inbox_rule_logs, ellucian_ethos_sync_global_task_list, comments).
18+
19+
$requestIds = ProcessRequest::query()
20+
->where('case_number', $caseNumber)
21+
->pluck('id')
22+
->all();
23+
24+
if ($requestIds === []) {
25+
abort(404);
26+
}
27+
28+
DB::transaction(function () use ($caseNumber, $requestIds) {
29+
CaseStarted::query()
30+
->where('case_number', $caseNumber)
31+
->delete();
32+
33+
CaseParticipated::query()
34+
->where('case_number', $caseNumber)
35+
->delete();
36+
37+
CaseNumber::query()
38+
->whereIn('process_request_id', $requestIds)
39+
->delete();
40+
41+
ProcessRequest::query()
42+
->whereIn('id', $requestIds)
43+
->delete();
44+
});
45+
}
46+
}

ProcessMaker/Http/Controllers/Api/CaseController.php

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace ProcessMaker\Http\Controllers\Api;
44

5+
use Illuminate\Http\JsonResponse;
6+
use ProcessMaker\Http\Controllers\Api\Actions\Cases\DeleteCase;
57
use ProcessMaker\Http\Controllers\Controller;
68
use ProcessMaker\Models\Process;
79
use ProcessMaker\Models\ProcessRequest;
@@ -12,7 +14,7 @@ class CaseController extends Controller
1214
/**
1315
* Get stage information for cases
1416
*/
15-
public function getStagePerCase($case_number = null)
17+
public function getStagePerCase(?string $case_number = null): JsonResponse
1618
{
1719
if (!empty($case_number)) {
1820
$responseData = $this->getSpecificCaseStages($case_number);
@@ -31,12 +33,44 @@ public function getStagePerCase($case_number = null)
3133
return response()->json($responseData);
3234
}
3335

36+
/**
37+
* Delete a case and its related requests.
38+
*
39+
* @param string $case_number
40+
* @return JsonResponse
41+
*
42+
* @OA\Delete(
43+
* path="/cases/{case_number}",
44+
* summary="Delete a case and its related requests",
45+
* operationId="deleteCase",
46+
* tags={"Cases"},
47+
* @OA\Parameter(
48+
* description="Case number to delete",
49+
* in="path",
50+
* name="case_number",
51+
* required=true,
52+
* @OA\Schema(type="string")
53+
* ),
54+
* @OA\Response(
55+
* response=204,
56+
* description="success"
57+
* ),
58+
* @OA\Response(response=404, ref="#/components/responses/404"),
59+
* )
60+
*/
61+
public function destroy(string $case_number): JsonResponse
62+
{
63+
(new DeleteCase)($case_number);
64+
65+
return response()->json([], 204);
66+
}
67+
3468
/**
3569
* Get specific case stages information
3670
* @param string $caseNumber The unique identifier of the case to retrieve stages for
3771
* @return array
3872
*/
39-
private function getSpecificCaseStages($caseNumber)
73+
private function getSpecificCaseStages(string $caseNumber): array
4074
{
4175
$allRequests = ProcessRequest::where('case_number', $caseNumber)->get();
4276
// Check if any requests were found
@@ -75,7 +109,7 @@ private function getSpecificCaseStages($caseNumber)
75109
* @param string|null $status The status to set for the stages
76110
* @return array
77111
*/
78-
private function getDefaultCaseStages($status = null)
112+
private function getDefaultCaseStages(?string $status = null): array
79113
{
80114
return [
81115
[
@@ -100,7 +134,7 @@ private function getDefaultCaseStages($status = null)
100134
* @param string $stageName The name of the stage ('In Progress' or 'Completed')
101135
* @return string The mapped status
102136
*/
103-
private function mapStatus($status, $stageName)
137+
private function mapStatus(?string $status, string $stageName): string
104138
{
105139
if ($status === 'COMPLETED') {
106140
return 'Done';
@@ -120,11 +154,11 @@ private function mapStatus($status, $stageName)
120154
/**
121155
* Get the stages summary based on the provided request.
122156
*
123-
* @param $requestId
157+
* @param ProcessRequest $request
124158
* @return array An array of stage results, each containing the stage ID, name, status,
125159
* and completion date.
126160
*/
127-
private function getStagesSummary(ProcessRequest $request)
161+
private function getStagesSummary(ProcessRequest $request): array
128162
{
129163
$requestId = $request->id;
130164
$processId = $request->process_id;

database/factories/ProcessMaker/Models/ProcessRequestFactory.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,20 @@ public function definition()
4747
},
4848
];
4949
}
50+
51+
public function withCaseNumber(int $caseNumber): self
52+
{
53+
$caseTitle = $this->faker->words(4, true);
54+
55+
return $this->state([
56+
'case_number' => $caseNumber,
57+
'case_title' => $caseTitle,
58+
'case_title_formatted' => $caseTitle,
59+
])->afterCreating(function (ProcessRequest $request) use ($caseNumber, $caseTitle) {
60+
$request->case_number = $caseNumber;
61+
$request->case_title = $caseTitle;
62+
$request->case_title_formatted = $caseTitle;
63+
$request->save();
64+
});
65+
}
5066
}

routes/api.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@
235235

236236
// Cases
237237
Route::get('cases/stages_bar/{case_number?}', [CaseController::class, 'getStagePerCase'])->name('cases.stage');
238+
Route::delete('cases/{case_number}', [CaseController::class, 'destroy'])->name('cases.destroy');
238239

239240
// TaskDrafts
240241
Route::put('drafts/{task}', [TaskDraftController::class, 'update'])->name('taskdraft.update');
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
namespace Tests\Feature\Api;
4+
5+
use ProcessMaker\Models\CaseNumber;
6+
use ProcessMaker\Models\CaseParticipated;
7+
use ProcessMaker\Models\CaseStarted;
8+
use ProcessMaker\Models\ProcessRequest;
9+
use Tests\Feature\Shared\RequestHelper;
10+
use Tests\TestCase;
11+
12+
class CaseDeleteTest extends TestCase
13+
{
14+
use RequestHelper;
15+
16+
public function testDeleteCaseRemovesCoreRecords(): void
17+
{
18+
$caseNumber = 12345;
19+
$requests = ProcessRequest::factory()
20+
->count(2)
21+
->withCaseNumber($caseNumber)
22+
->create();
23+
24+
CaseNumber::query()->create(['process_request_id' => $requests->first()->id]);
25+
CaseNumber::query()->create(['process_request_id' => $requests->last()->id]);
26+
CaseStarted::factory()->create(['case_number' => $caseNumber]);
27+
CaseParticipated::factory()->create(['case_number' => $caseNumber]);
28+
29+
$response = $this->apiCall('DELETE', route('api.cases.destroy', ['case_number' => $caseNumber]));
30+
31+
$response->assertStatus(204);
32+
$this->assertDatabaseMissing('process_requests', ['case_number' => $caseNumber]);
33+
$this->assertDatabaseMissing('cases_started', ['case_number' => $caseNumber]);
34+
$this->assertDatabaseMissing('cases_participated', ['case_number' => $caseNumber]);
35+
$this->assertDatabaseMissing('case_numbers', ['process_request_id' => $requests->first()->id]);
36+
$this->assertDatabaseMissing('case_numbers', ['process_request_id' => $requests->last()->id]);
37+
}
38+
39+
public function testDeleteCaseReturnsNotFoundWhenMissing(): void
40+
{
41+
$caseNumber = 99999;
42+
43+
$response = $this->apiCall('DELETE', route('api.cases.destroy', ['case_number' => $caseNumber]));
44+
45+
$response->assertStatus(404);
46+
}
47+
}

0 commit comments

Comments
 (0)