feat: complete cash advance workflow, stock transfer capitalization ledger sync, BOQ progress engine, and PM role scoping
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\ProjectProgress\Services;
|
||||
|
||||
use Modules\ProjectManagement\Models\Project;
|
||||
use Modules\TaskManagement\Models\Task;
|
||||
|
||||
class ProjectProgressService
|
||||
{
|
||||
/**
|
||||
* Calculate project progress dynamically using actual material consumed vs BOQ planned quantity.
|
||||
* Formula: sum((Actual Material Consumed / Planned BOQ) * Task Weight)
|
||||
*/
|
||||
public function calculateProjectProgress(Project $project): float
|
||||
{
|
||||
$tasks = Task::where('project_id', $project->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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user