'Super Admin']); Permission::firstOrCreate(['name' => 'projects.access']); $this->user = User::factory()->create([ 'status' => 'active', 'user_type' => 'admin', ]); $this->user->assignRole($role); // Standard Material $this->material = Material::create([ 'name' => 'Test Cement Bag', 'sku' => 'CEM-TST-101', 'unit' => 'bag', 'unit_cost' => 300.00, 'category' => 'cement', 'type' => 'raw', 'status' => 'active', ]); // Standard Labor $this->labor = Labor::create([ 'name' => 'Foreman', 'category' => 'skilled', 'hourly_rate' => 150.00, 'status' => 'active', ]); // Standard Equipment $this->equipment = Equipment::create([ 'name' => 'Dump Truck', 'owner_name' => 'Company Owned', 'hourly_rate' => 1500.00, 'status' => 'active', ]); // Create Unapproved Project (step < 8) $this->unapprovedProject = Project::create([ 'name' => 'Draft Project', 'code' => 'PRJ-DFT-2026', 'status' => ProjectStatus::Planning, 'project_type' => 'standard', 'is_unprofitable' => false, 'contract_value' => 500000.00, 'current_wizard_step' => 2, ]); // Create Approved Project (step >= 8) $this->approvedProject = Project::create([ 'name' => 'Approved Project', 'code' => 'PRJ-APP-2026', 'status' => ProjectStatus::InProgress, 'project_type' => 'standard', 'is_unprofitable' => false, 'contract_value' => 1000000.00, 'current_wizard_step' => 8, ]); } public function test_unapproved_project_can_be_updated_details(): void { $response = $this->actingAs($this->user)->put(route('projects.update', $this->unapprovedProject->ulid), [ 'name' => 'Updated Draft Project', 'project_type' => 'standard', ]); $response->assertRedirect(route('projects.show', $this->unapprovedProject->ulid)); $this->unapprovedProject->refresh(); $this->assertEquals('Updated Draft Project', $this->unapprovedProject->name); } public function test_approved_project_updates_blocked(): void { $response = $this->actingAs($this->user)->put(route('projects.update', $this->approvedProject->ulid), [ 'name' => 'Updated Approved Project', 'project_type' => 'standard', ]); $response->assertRedirect(); $response->assertSessionHas('error', 'Cannot update details: This project has been approved and locked.'); $this->approvedProject->refresh(); $this->assertEquals('Approved Project', $this->approvedProject->name); } public function test_approved_project_cannot_modify_tasks(): void { $response = $this->actingAs($this->user)->post(route('projects.wizard.tasks', $this->approvedProject->ulid), [ 'tasks' => [ [ 'name' => 'Attempted Task', ] ] ]); $response->assertRedirect(); $response->assertSessionHas('error', 'Cannot modify tasks: This project has been approved and locked.'); } public function test_approved_project_cannot_modify_estimates(): void { $response = $this->actingAs($this->user)->post(route('projects.wizard.estimates', $this->approvedProject->ulid), [ 'estimates' => [ [ 'material_ulid' => $this->material->ulid, 'estimated_qty' => 100, 'unit_cost' => 300.00, ] ] ]); $response->assertRedirect(); $response->assertSessionHas('error', 'Cannot modify estimates: This project has been approved and locked.'); } public function test_approved_project_cannot_modify_labor(): void { $task = $this->approvedProject->tasks()->create([ 'name' => 'Mock Task', 'status' => 'pending', 'labor_cost' => 0, 'estimated_hours' => 20, 'actual_hours' => 0, 'completion_percentage' => 0, 'sort_order' => 1, ]); $response = $this->actingAs($this->user)->post(route('projects.wizard.labor', $this->approvedProject->ulid), [ 'labor' => [ [ 'task_ulid' => $task->ulid, 'labor_ulid' => $this->labor->ulid, 'estimated_hours' => 40, ] ] ]); $response->assertRedirect(); $response->assertSessionHas('error', 'Cannot modify labor allocations: This project has been approved and locked.'); } public function test_approved_project_cannot_modify_equipment(): void { $task = $this->approvedProject->tasks()->create([ 'name' => 'Mock Task', 'status' => 'pending', 'labor_cost' => 0, 'estimated_hours' => 20, 'actual_hours' => 0, 'completion_percentage' => 0, 'sort_order' => 1, ]); $response = $this->actingAs($this->user)->post(route('projects.wizard.equipment', $this->approvedProject->ulid), [ 'equipment' => [ [ 'task_ulid' => $task->ulid, 'equipment_ulid' => $this->equipment->ulid, 'estimated_hours' => 12, ] ] ]); $response->assertRedirect(); $response->assertSessionHas('error', 'Cannot modify equipment allocations: This project has been approved and locked.'); } }