'Super Admin']); $this->user = User::factory()->create([ 'status' => 'active', 'user_type' => 'admin', ]); $this->user->assignRole($role); // Parent Project $this->parentProject = Project::create([ 'name' => 'Terminal A Expansion', 'code' => 'PRJ-PARENT-01', 'status' => ProjectStatus::InProgress, 'project_type' => 'standard', 'contract_value' => 100000.00, 'total_capitalization' => 30000.00, ]); // Child Project (Extension / Variation Order) $this->childProject = Project::create([ 'name' => 'Terminal A - Gate 5 Extension', 'code' => 'PRJ-CHILD-01', 'parent_project_id' => $this->parentProject->id, 'status' => ProjectStatus::InProgress, 'project_type' => 'extension', 'contract_value' => 50000.00, 'total_capitalization' => 15000.00, ]); } public function test_rollup_calculations_aggregate_parent_and_child(): void { // Combined Contract Value (100k parent + 50k child = 150k rollup) $this->assertEquals(150000.00, $this->parentProject->rollup_contract_value); // Combined Capitalization (30k parent + 15k child = 45k rollup) $this->assertEquals(45000.00, $this->parentProject->rollup_capitalization); } public function test_parent_completion_blocked_by_active_children(): void { // Assign a project manager to avoid PM requirement exception $this->parentProject->personnel()->attach($this->user->id, ['role' => 'pm']); $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Cannot complete or close parent project while there are active child projects (extensions).'); // Try to transition parent directly to Completed $this->parentProject->transitionTo(ProjectStatus::Completed); } public function test_parent_completion_allowed_when_children_are_completed(): void { // Complete the child project first $this->childProject->update(['status' => ProjectStatus::Completed]); // Assign PM $this->parentProject->personnel()->attach($this->user->id, ['role' => 'pm']); // Transition parent to Completed should work now $this->parentProject->transitionTo(ProjectStatus::Completed); $this->assertEquals(ProjectStatus::Completed, $this->parentProject->fresh()->status); } }