225 lines
7.2 KiB
PHP
225 lines
7.2 KiB
PHP
<?php
|
|
|
|
namespace Modules\ProjectManagement\Tests\Feature;
|
|
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Modules\ProjectManagement\Models\Project;
|
|
use Modules\ProjectManagement\Models\Task;
|
|
use Modules\ProjectManagement\Models\TaskActivity;
|
|
use Modules\ProjectManagement\Enums\ProjectStatus;
|
|
use Modules\ProjectManagement\Enums\TaskStatus;
|
|
use Modules\ProjectManagement\Enums\DelayReason;
|
|
use Modules\MasterData\Models\Material;
|
|
use Spatie\Permission\Models\Role;
|
|
use Tests\TestCase;
|
|
|
|
class TaskActivityAndCostTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
protected User $user;
|
|
protected Project $project;
|
|
protected Material $material;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
$role = Role::firstOrCreate(['name' => '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',
|
|
]);
|
|
}
|
|
}
|