TenantAtlas/apps/platform/app/Models/ReviewPublicationResolutionCase.php
ahmido ba7622a158 feat: implement ReviewPublicationResolutionWorkflow (Spec 386) (#457)
## Summary\n- Implements the ReviewPublicationResolutionWorkflow for Spec 386.\n- Adds resolution case/step persistence, policies, services, audit action IDs, and Filament integration.\n- Updates specs, UI/UX documentation, screenshots, and Pest coverage.\n\n## Tests\n- Not run during this handoff; branch was already clean and pushed.\n\n## Target\n- Base: platform-dev\n- Head/topic: 386-review-publication-resolution-workflow-v1

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #457
2026-06-18 21:06:20 +00:00

155 lines
4.1 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Models;
use App\Support\ReviewPublicationResolution\ReviewPublicationResolutionCaseStatus;
use App\Support\ReviewPublicationResolution\ReviewPublicationResolutionStepKey;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class ReviewPublicationResolutionCase extends Model
{
public const string ACTION_KEY = 'review.publication';
protected $guarded = [];
/**
* @return array<string, string>
*/
protected function casts(): array
{
return [
'summary' => 'array',
'metadata' => 'array',
'last_evaluated_at' => 'datetime',
'started_at' => 'datetime',
'completed_at' => 'datetime',
'cancelled_at' => 'datetime',
'superseded_at' => 'datetime',
];
}
/**
* @return BelongsTo<Workspace, $this>
*/
public function workspace(): BelongsTo
{
return $this->belongsTo(Workspace::class);
}
/**
* @return BelongsTo<ManagedEnvironment, $this>
*/
public function tenant(): BelongsTo
{
return $this->belongsTo(ManagedEnvironment::class, 'managed_environment_id');
}
/**
* @return BelongsTo<EnvironmentReview, $this>
*/
public function environmentReview(): BelongsTo
{
return $this->belongsTo(EnvironmentReview::class);
}
/**
* @return BelongsTo<User, $this>
*/
public function creator(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by_user_id');
}
/**
* @return BelongsTo<User, $this>
*/
public function assignee(): BelongsTo
{
return $this->belongsTo(User::class, 'assigned_to_user_id');
}
/**
* @return HasMany<ReviewPublicationResolutionStep, $this>
*/
public function steps(): HasMany
{
return $this->hasMany(ReviewPublicationResolutionStep::class, 'case_id')
->orderBy('position')
->orderBy('id');
}
public function currentStep(): ?ReviewPublicationResolutionStep
{
$currentStepKey = $this->current_step_key;
if (! is_string($currentStepKey) || $currentStepKey === '') {
return null;
}
if ($this->relationLoaded('steps')) {
$step = $this->steps->firstWhere('step_key', $currentStepKey);
return $step instanceof ReviewPublicationResolutionStep ? $step : null;
}
return $this->steps()->where('step_key', $currentStepKey)->first();
}
public function statusEnum(): ReviewPublicationResolutionCaseStatus
{
return ReviewPublicationResolutionCaseStatus::tryFrom((string) $this->status)
?? ReviewPublicationResolutionCaseStatus::Open;
}
public function isActive(): bool
{
return $this->statusEnum()->isActive();
}
public function currentStepKeyEnum(): ?ReviewPublicationResolutionStepKey
{
return ReviewPublicationResolutionStepKey::tryFrom((string) $this->current_step_key);
}
/**
* @param Builder<self> $query
* @return Builder<self>
*/
public function scopeForWorkspace(Builder $query, int $workspaceId): Builder
{
return $query->where('workspace_id', $workspaceId);
}
/**
* @param Builder<self> $query
* @return Builder<self>
*/
public function scopeForTenant(Builder $query, int $tenantId): Builder
{
return $query->where('managed_environment_id', $tenantId);
}
/**
* @param Builder<self> $query
* @return Builder<self>
*/
public function scopeForReview(Builder $query, EnvironmentReview|int $review): Builder
{
return $query->where('environment_review_id', $review instanceof EnvironmentReview ? (int) $review->getKey() : $review);
}
/**
* @param Builder<self> $query
* @return Builder<self>
*/
public function scopeActive(Builder $query): Builder
{
return $query->whereIn('status', ReviewPublicationResolutionCaseStatus::activeValues());
}
}