'Super Admin']); $this->user = User::factory()->create([ 'status' => 'active', 'user_type' => 'admin', ]); $this->user->assignRole($role); $this->project = Project::create([ 'name' => 'Test Project', 'code' => 'PRJ-2026-TEST', 'status' => ProjectStatus::Planning, 'project_type' => 'standard', 'is_unprofitable' => false, 'contract_value' => 500000.00, ]); $this->material = Material::create([ 'name' => 'Steel Rebar', 'sku' => 'STL-REB-001', 'unit' => 'pcs', 'unit_cost' => 150.00, 'category' => 'steel', 'type' => 'raw', 'status' => 'active', ]); } public function test_task_creation_activity_log(): void { $this->actingAs($this->user); $task = $this->project->tasks()->create([ 'name' => 'Task One', 'status' => TaskStatus::Pending, 'labor_cost' => 1000.00, 'equipment_cost' => 500.00, 'estimated_hours' => 10, 'sort_order' => 0, ]); $this->assertDatabaseHas('task_activities', [ 'task_id' => $task->id, 'user_id' => $this->user->id, 'description' => 'created the task.', 'type' => 'creation', ]); } public function test_task_updating_fields_activity_log(): void { $this->actingAs($this->user); $task = $this->project->tasks()->create([ 'name' => 'Initial Name', 'status' => TaskStatus::Pending, 'labor_cost' => 1000.00, 'equipment_cost' => 500.00, 'estimated_hours' => 10, 'sort_order' => 0, ]); // Clean out creation log so we only check update log $task->activities()->delete(); $task->update([ 'name' => 'Updated Name', 'estimated_hours' => 15, 'status' => TaskStatus::InProgress, ]); $this->assertDatabaseHas('task_activities', [ 'task_id' => $task->id, 'user_id' => $this->user->id, 'type' => 'update', ]); $activity = $task->activities()->first(); $this->assertStringContainsString("changed name from 'Initial Name' to 'Updated Name'", $activity->description); $this->assertStringContainsString("changed estimated hours from 10.00 to 15", $activity->description); $this->assertStringContainsString("changed status from 'Pending' to 'in_progress'", $activity->description); } public function test_task_cost_fallback_calculations(): void { $this->actingAs($this->user); $task = $this->project->tasks()->create([ 'name' => 'Task Cost Test', 'status' => TaskStatus::Pending, 'labor_cost' => 1200.00, 'equipment_cost' => 800.00, 'estimated_hours' => 10, 'sort_order' => 0, ]); // Prior to completions, actual costs should be 0 because no resource records exist $this->assertEquals(0.00, $task->actual_labor_cost); $this->assertEquals(0.00, $task->actual_equipment_cost); // Estimated costs should fall back to the columns $this->assertEquals(1200.00, $task->estimated_labor_cost); $this->assertEquals(800.00, $task->estimated_equipment_cost); // When task is completed, actual costs should fall back to columns (labor_cost and equipment_cost) $task->update(['status' => TaskStatus::Completed]); $this->assertEquals(1200.00, $task->actual_labor_cost); $this->assertEquals(800.00, $task->actual_equipment_cost); $this->assertEquals(2000.00, $task->total_cost); } public function test_task_material_actions_logged(): void { $this->actingAs($this->user); $task = $this->project->tasks()->create([ 'name' => 'Material Task', 'status' => TaskStatus::Pending, 'sort_order' => 0, ]); // Add task material $tm = $task->taskMaterials()->create([ 'material_id' => $this->material->id, 'planned_qty' => 10.00, 'actual_qty' => 0.00, 'unit_cost' => $this->material->unit_cost, ]); $this->assertDatabaseHas('task_activities', [ 'task_id' => $task->id, 'user_id' => $this->user->id, 'description' => "added material 'Steel Rebar' (Planned Qty: 10.00).", 'type' => 'material_add', ]); // Update task material $tm->update(['actual_qty' => 5.00]); $this->assertDatabaseHas('task_activities', [ 'task_id' => $task->id, 'user_id' => $this->user->id, 'description' => "updated actual quantity for 'Steel Rebar' to 5.00.", 'type' => 'material_update', ]); // Delete task material $tm->delete(); $this->assertDatabaseHas('task_activities', [ 'task_id' => $task->id, 'user_id' => $this->user->id, 'description' => "removed material 'Steel Rebar'.", 'type' => 'material_remove', ]); } public function test_task_delay_actions_logged(): void { $this->actingAs($this->user); $task = $this->project->tasks()->create([ 'name' => 'Delay Task', 'status' => TaskStatus::Pending, 'sort_order' => 0, ]); // Log delay $td = $task->delays()->create([ 'reason_type' => DelayReason::Weather, 'delay_date' => now(), 'lost_hours' => 8.00, 'reported_by' => $this->user->id, ]); $this->assertDatabaseHas('task_activities', [ 'task_id' => $task->id, 'user_id' => $this->user->id, 'type' => 'delay_add', ]); // Update delay $td->update(['lost_hours' => 12.00]); $this->assertDatabaseHas('task_activities', [ 'task_id' => $task->id, 'user_id' => $this->user->id, 'description' => 'updated delay: changed delay hours to 12.00h.', 'type' => 'delay_update', ]); // Delete delay $td->delete(); $this->assertDatabaseHas('task_activities', [ 'task_id' => $task->id, 'user_id' => $this->user->id, 'type' => 'delay_remove', ]); } }