Files
GSB-Construction/Modules/ApprovalWorkflow/app/Models/ApprovalChain.php

77 lines
1.9 KiB
PHP

<?php
namespace Modules\ApprovalWorkflow\Models;
use App\Models\User;
use App\Traits\HasPublicIdentifier;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Modules\ApprovalWorkflow\Enums\ApprovalChainStatus;
class ApprovalChain extends Model
{
use HasPublicIdentifier;
protected $fillable = [
'approvable_type',
'approvable_id',
'type',
'status',
'notes',
'initiated_by',
'completed_at',
];
protected function casts(): array
{
return [
'status' => ApprovalChainStatus::class,
'completed_at' => 'datetime',
];
}
public function approvable(): MorphTo
{
return $this->morphTo();
}
public function initiator(): BelongsTo
{
return $this->belongsTo(User::class, 'initiated_by');
}
public function steps(): HasMany
{
return $this->hasMany(ApprovalStep::class)->orderBy('order');
}
public function currentStep(): ?ApprovalStep
{
return $this->steps()->where('status', 'pending')->first();
}
public function isFullyApproved(): bool
{
return $this->steps()->where('status', '!=', 'approved')->doesntExist();
}
public function transitionTo(ApprovalChainStatus $newStatus): void
{
$allowed = $this->status->allowedTransitions();
if (!in_array($newStatus, $allowed)) {
throw new \InvalidArgumentException(
"Cannot transition chain from {$this->status->label()} to {$newStatus->label()}"
);
}
$updates = ['status' => $newStatus];
if (in_array($newStatus, [ApprovalChainStatus::Approved, ApprovalChainStatus::Rejected])) {
$updates['completed_at'] = now();
}
$this->update($updates);
}
}