create([ 'start_date' => now()->subDays(10)->format('Y-m-d'), 'target_end_date' => now()->addDays(20)->format('Y-m-d'), ]); Task::factory()->create([ 'project_id' => $project->id, 'status' => 'completed', 'completion_percentage' => 100, 'start_date' => now()->subDays(10)->format('Y-m-d'), 'end_date' => now()->subDays(2)->format('Y-m-d'), ]); Task::factory()->create([ 'project_id' => $project->id, 'status' => 'in_progress', 'completion_percentage' => 50, 'start_date' => now()->subDays(5)->format('Y-m-d'), 'end_date' => now()->addDays(15)->format('Y-m-d'), ]); $service = new ProjectProgressService(); $evmData = $service->getEvmAnalysisData($project); $this->assertIsArray($evmData); $this->assertArrayHasKey('timeSeries', $evmData); $this->assertArrayHasKey('summary', $evmData); $summary = $evmData['summary']; $this->assertGreaterThan(0, $summary['actual_ev']); $this->assertNotNull($summary['spi']); $this->assertNotNull($summary['schedule_variance']); } public function test_evm_with_milestones_and_accomplishment_dates() { $project = Project::factory()->create([ 'start_date' => now()->subDays(30)->format('Y-m-d'), 'target_end_date' => now()->addDays(30)->format('Y-m-d'), ]); $m1 = $project->milestones()->create([ 'name' => 'Substructure', 'weight_percentage' => 40, 'planned_date' => now()->subDays(10)->format('Y-m-d'), 'actual_date' => now()->subDays(12)->format('Y-m-d'), 'sort_order' => 1, ]); $m2 = $project->milestones()->create([ 'name' => 'Superstructure', 'weight_percentage' => 60, 'planned_date' => now()->addDays(20)->format('Y-m-d'), 'actual_date' => null, 'sort_order' => 2, ]); Task::factory()->create([ 'project_id' => $project->id, 'milestone_id' => $m2->id, 'status' => 'in_progress', 'completion_percentage' => 50, 'start_date' => now()->subDays(5)->format('Y-m-d'), 'actual_start_date' => now()->subDays(5)->format('Y-m-d'), 'end_date' => now()->addDays(20)->format('Y-m-d'), ]); $service = new ProjectProgressService(); $evmData = $service->getEvmAnalysisData($project); $this->assertIsArray($evmData); $this->assertNotEmpty($evmData['timeSeries']); // Milestone 1 (40%) completed + Milestone 2 (50% of 60% = 30%) -> Total 70% $this->assertEquals(70.0, $evmData['summary']['actual_ev']); } }