feat: complete cash advance workflow, stock transfer capitalization ledger sync, BOQ progress engine, and PM role scoping

This commit is contained in:
Ajjj
2026-07-31 15:36:31 +08:00
parent 32c3e3af69
commit 6cafa38478
11 changed files with 511 additions and 196 deletions

View File

@@ -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;
}
}