id) ->with(['materials']) ->get(); if ($tasks->isEmpty()) { return 0.0; } $totalWeightedProgress = 0.0; $totalWeight = 0.0; foreach ($tasks as $task) { $taskWeight = $task->weight ?? 1.0; $totalWeight += $taskWeight; $plannedBoq = $task->materials->sum('planned_quantity'); $consumedQty = $task->materials->sum('consumed_quantity'); if ($plannedBoq > 0) { $materialProgress = min(1.0, $consumedQty / $plannedBoq); $totalWeightedProgress += ($materialProgress * 100) * $taskWeight; } else { // Fallback to task completion percentage if no BOQ material planned $taskProgress = $task->status === 'completed' ? 100 : ($task->progress_percentage ?? 0); $totalWeightedProgress += $taskProgress * $taskWeight; } } return $totalWeight > 0 ? round($totalWeightedProgress / $totalWeight, 2) : 0.0; } }