55use Carbon \Carbon ;
66use Illuminate \Foundation \Testing \RefreshDatabase ;
77use Illuminate \Support \Facades \Config ;
8+ use Illuminate \Support \Facades \Hash ;
89use ProcessMaker \Jobs \EvaluateProcessRetentionJob ;
910use ProcessMaker \Models \CaseNumber ;
11+ use ProcessMaker \Models \CaseStarted ;
1012use ProcessMaker \Models \Process ;
1113use ProcessMaker \Models \ProcessRequest ;
14+ use ProcessMaker \Models \User ;
15+ use Tests \Feature \Shared \RequestHelper ;
1216use Tests \TestCase ;
1317
1418class EvaluateProcessRetentionJobTest extends TestCase
1519{
1620 use RefreshDatabase;
21+ use RequestHelper;
1722
1823 const RETENTION_PERIOD = '1_year ' ;
1924
@@ -22,6 +27,11 @@ protected function setUp(): void
2227 parent ::setUp ();
2328 // Enable case retention policy for all tests
2429 Config::set ('app.case_retention_policy_enabled ' , true );
30+ // RequestHelper expects $this->user for apiCall (used in integration test)
31+ $ this ->user = User::factory ()->create ([
32+ 'password ' => Hash::make ('password ' ),
33+ 'is_administrator ' => true ,
34+ ]);
2535 }
2636
2737 protected function tearDown (): void
@@ -136,12 +146,13 @@ public function testItHandlesMultipleCasesInBatches()
136146 // These cases are created 13 months ago
137147 // Cutoff = now - 12 months = 12 months ago
138148 // 13 months ago < 12 months ago, so these should be deleted
149+ $ oldCaseCreatedAt = Carbon::now ()->subMonths (13 )->toIso8601String ();
139150 $ cases = CaseNumber::factory ()->count (1200 )->create ([
140151 'process_request_id ' => $ processRequest ->id ,
141- 'created_at ' => Carbon:: now ()-> subMonths ( 13 )-> toIso8601String () ,
152+ 'created_at ' => $ oldCaseCreatedAt ,
142153 ]);
143154 $ this ->assertEquals ($ processRequest ->id , $ cases ->first ()->process_request_id );
144- $ this ->assertEquals (Carbon:: now ()-> subMonths ( 13 )-> toIso8601String () , $ cases ->first ()->created_at ->toIso8601String ());
155+ $ this ->assertEquals ($ oldCaseCreatedAt , $ cases ->first ()->created_at ->toIso8601String ());
145156
146157 // Link process request to one of the case numbers so the job can resolve request IDs for full delete
147158 $ processRequest ->case_number = $ cases ->first ()->id ;
@@ -354,4 +365,51 @@ public function testItDefaultsToOneYearForProcessesWithoutRetentionPeriod()
354365 $ this ->assertNotNull (CaseNumber::find ($ newCase ->id ), 'The 5-month-old case should NOT be deleted with default 1 year retention ' );
355366 $ this ->assertDatabaseCount ('case_numbers ' , 2 );
356367 }
368+
369+ public function testDeletedCaseIsFullyInaccessibleViaApi (): void
370+ {
371+ $ process = Process::factory ()->create ([
372+ 'properties ' => [
373+ 'retention_period ' => self ::RETENTION_PERIOD ,
374+ ],
375+ ]);
376+ $ process ->save ();
377+ $ process ->refresh ();
378+
379+ $ processRequest = ProcessRequest::factory ()->create ();
380+ $ processRequest ->process_id = $ process ->id ;
381+ $ processRequest ->save ();
382+ $ processRequest ->refresh ();
383+
384+ $ oldCaseCreatedAt = Carbon::now ()->subMonths (13 )->toIso8601String ();
385+ $ caseOld = CaseNumber::factory ()->create ([
386+ 'created_at ' => $ oldCaseCreatedAt ,
387+ 'process_request_id ' => $ processRequest ->id ,
388+ ]);
389+ $ processRequest ->case_number = $ caseOld ->id ;
390+ $ processRequest ->save ();
391+
392+ CaseStarted::factory ()->create ([
393+ 'case_number ' => $ caseOld ->id ,
394+ 'user_id ' => $ this ->user ->id ,
395+ ]);
396+
397+ // Case should appear in the list before retention runs
398+ $ listBefore = $ this ->apiCall ('GET ' , route ('api.1.1.cases.all_cases ' , ['userId ' => $ this ->user ->id ]));
399+ $ listBefore ->assertStatus (200 );
400+ $ caseNumbersBefore = collect ($ listBefore ->json ('data ' ))->pluck ('case_number ' )->all ();
401+ $ this ->assertContains ($ caseOld ->id , $ caseNumbersBefore , 'Case should appear in list before retention job runs ' );
402+
403+ EvaluateProcessRetentionJob::dispatchSync ($ process ->id );
404+
405+ // DELETE case by number should return 404 (case already removed)
406+ $ deleteResponse = $ this ->apiCall ('DELETE ' , route ('api.cases.destroy ' , ['case_number ' => $ caseOld ->id ]));
407+ $ deleteResponse ->assertStatus (404 );
408+
409+ // GET all_cases should not include the deleted case
410+ $ listAfter = $ this ->apiCall ('GET ' , route ('api.1.1.cases.all_cases ' , ['userId ' => $ this ->user ->id ]));
411+ $ listAfter ->assertStatus (200 );
412+ $ caseNumbersAfter = collect ($ listAfter ->json ('data ' ))->pluck ('case_number ' )->all ();
413+ $ this ->assertNotContains ($ caseOld ->id , $ caseNumbersAfter , 'Deleted case must not appear in All Cases API ' );
414+ }
357415}
0 commit comments