Skip to content

Commit 91cce8a

Browse files
Merge pull request #8748 from ProcessMaker/task/FOUR-29115
Add cases_retention_policy_logs Table and Logging for Case Deletions
2 parents c8c44e1 + e3ee625 commit 91cce8a

File tree

5 files changed

+172
-0
lines changed

5 files changed

+172
-0
lines changed

ProcessMaker/Jobs/EvaluateProcessRetentionJob.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use ProcessMaker\Http\Controllers\Api\Actions\Cases\DeletesCaseRecords;
1010
use ProcessMaker\Models\CaseNumber;
1111
use ProcessMaker\Models\CaseParticipated;
12+
use ProcessMaker\Models\CaseRetentionPolicyLog;
1213
use ProcessMaker\Models\CaseStarted;
1314
use ProcessMaker\Models\Process;
1415
use ProcessMaker\Models\ProcessRequest;
@@ -139,6 +140,8 @@ public function handle(): void
139140
CaseNumber::whereIn('process_request_id', $processRequestSubquery)
140141
->where($this->buildRetentionQuery($retentionUpdatedAt, $oldCasesCutoff, $newCasesCutoff))
141142
->chunkById(100, function ($cases) use (&$processRequestIdsToDelete, &$totalDeleted, &$chunkCount) {
143+
$chunkStartTime = microtime(true);
144+
142145
$caseIds = $cases->pluck('id')->all();
143146
$processRequestIds = $cases->pluck('process_request_id')->unique()->all();
144147

@@ -170,10 +173,21 @@ public function handle(): void
170173
$chunkSize = count($caseIds);
171174
$totalDeleted += $chunkSize;
172175

176+
$chunkTimeMs = round((microtime(true) - $chunkStartTime) * 1000, 2);
177+
173178
Log::info('EvaluateProcessRetentionJob: Deleted chunk of cases', [
174179
'process_id' => $this->processId,
175180
'chunk_number' => $chunkCount,
176181
'cases_deleted' => $chunkSize,
182+
'deletion_time_ms' => $chunkTimeMs,
183+
]);
184+
185+
CaseRetentionPolicyLog::create([
186+
'process_id' => $this->processId,
187+
'case_ids' => json_encode($caseIds),
188+
'deleted_count' => $chunkSize,
189+
'total_time_taken' => $chunkTimeMs,
190+
'deleted_at' => Carbon::now(),
177191
]);
178192
});
179193

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace ProcessMaker\Models;
4+
5+
use Illuminate\Database\Eloquent\Factories\HasFactory;
6+
use ProcessMaker\Models\ProcessMakerModel;
7+
8+
class CaseRetentionPolicyLog extends ProcessMakerModel
9+
{
10+
use HasFactory;
11+
12+
protected $table = 'case_retention_policy_logs';
13+
14+
const UPDATED_AT = null;
15+
16+
protected $guarded = [
17+
'id',
18+
'created_at',
19+
];
20+
21+
protected $fillable = [
22+
'process_id',
23+
'case_ids',
24+
'deleted_count',
25+
'total_time_taken',
26+
'deleted_at',
27+
];
28+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace Database\Factories\ProcessMaker\Models;
4+
5+
use Illuminate\Database\Eloquent\Factories\Factory;
6+
use ProcessMaker\Models\CaseNumber;
7+
use ProcessMaker\Models\Process;
8+
9+
/**
10+
* Model factory for a settings.
11+
*/
12+
class CaseRetentionPolicyLogFactory extends Factory
13+
{
14+
/**
15+
* Define the model's default state.
16+
*
17+
* @return array
18+
*/
19+
public function definition()
20+
{
21+
return [
22+
'process_id' => function () {
23+
return Process::factory()->create()->id;
24+
},
25+
'case_ids' => json_encode(CaseNumber::factory()->count($this->faker->numberBetween(1, 1000))->create()->pluck('id')->toArray()),
26+
'deleted_count' => $this->faker->numberBetween(1, 1000),
27+
'total_time_taken' => $this->faker->numberBetween(1, 1000000),
28+
'deleted_at' => $this->faker->dateTimeBetween('-1 year', 'now'),
29+
'created_at' => $this->faker->dateTimeBetween('-1 year', 'now'),
30+
];
31+
}
32+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
return new class extends Migration {
8+
/**
9+
* Run the migrations.
10+
*/
11+
public function up(): void
12+
{
13+
Schema::create('case_retention_policy_logs', function (Blueprint $table) {
14+
$table->id();
15+
$table->unsignedInteger('process_id');
16+
$table->json('case_ids')->nullable();
17+
$table->bigInteger('deleted_count')->default(0);
18+
19+
$table->bigInteger('total_time_taken')->nullable(); // in seconds
20+
$table->timestamp('deleted_at')->nullable();
21+
$table->timestamp('created_at')->nullable();
22+
});
23+
}
24+
25+
/**
26+
* Reverse the migrations.
27+
*/
28+
public function down(): void
29+
{
30+
Schema::dropIfExists('case_retention_policy_logs');
31+
}
32+
};
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
namespace Tests\Unit\ProcessMaker\Models;
4+
5+
use Carbon\Carbon;
6+
use Illuminate\Foundation\Testing\RefreshDatabase;
7+
use Illuminate\Support\Facades\Config;
8+
use Illuminate\Support\Facades\DB;
9+
use ProcessMaker\Jobs\EvaluateProcessRetentionJob;
10+
use ProcessMaker\Models\CaseNumber;
11+
use ProcessMaker\Models\CaseParticipated;
12+
use ProcessMaker\Models\CaseRetentionPolicyLog;
13+
use ProcessMaker\Models\CaseStarted;
14+
use ProcessMaker\Models\Process;
15+
use ProcessMaker\Models\ProcessRequest;
16+
use Tests\TestCase;
17+
18+
class CaseRetentionPolicyLogTest extends TestCase
19+
{
20+
use RefreshDatabase;
21+
22+
public function testJobAddsLogRecordWhenCasesAreDeleted(): void
23+
{
24+
Config::set('app.case_retention_policy_enabled', true);
25+
26+
$process = Process::factory()->create([
27+
'properties' => ['retention_period' => 'one_year'],
28+
]);
29+
$process->save();
30+
$process->refresh();
31+
32+
$processRequest = ProcessRequest::factory()->create();
33+
$processRequest->process_id = $process->id;
34+
$processRequest->save();
35+
$processRequest->refresh();
36+
37+
CaseNumber::where('process_request_id', $processRequest->id)->delete();
38+
39+
$oldCaseCreatedAt = Carbon::now()->subMonths(13)->toIso8601String();
40+
$caseOld = CaseNumber::factory()->create([
41+
'created_at' => $oldCaseCreatedAt,
42+
'process_request_id' => $processRequest->id,
43+
]);
44+
CaseStarted::factory()->create(['case_number' => $caseOld->id]);
45+
CaseParticipated::factory()->create(['case_number' => $caseOld->id]);
46+
47+
$this->assertDatabaseCount('case_retention_policy_logs', 0);
48+
49+
EvaluateProcessRetentionJob::dispatchSync($process->id);
50+
51+
$this->assertDatabaseCount('case_retention_policy_logs', 1);
52+
53+
$log = CaseRetentionPolicyLog::first();
54+
$this->assertSame((int) $process->id, (int) $log->process_id);
55+
$this->assertSame(1, $log->deleted_count);
56+
$this->assertNotEmpty($log->total_time_taken);
57+
$this->assertIsNumeric($log->total_time_taken);
58+
$this->assertNotNull($log->deleted_at);
59+
60+
$loggedCaseIds = json_decode($log->case_ids, true);
61+
$this->assertIsArray($loggedCaseIds);
62+
$this->assertContains((int) $caseOld->id, array_map('intval', $loggedCaseIds));
63+
64+
Config::set('app.case_retention_policy_enabled', false);
65+
}
66+
}

0 commit comments

Comments
 (0)