From 466732b9186c09d4fb26d4987cbccc9993e82d28 Mon Sep 17 00:00:00 2001 From: Muhammad Sulaiman Yusuf Date: Tue, 18 Oct 2022 03:02:36 +0700 Subject: [PATCH] bod schedule health --- .../Controllers/DashboardBoDController.php | 204 ++++++++++++++++-- 1 file changed, 183 insertions(+), 21 deletions(-) diff --git a/app/Http/Controllers/DashboardBoDController.php b/app/Http/Controllers/DashboardBoDController.php index d1ba1c1..6377da7 100644 --- a/app/Http/Controllers/DashboardBoDController.php +++ b/app/Http/Controllers/DashboardBoDController.php @@ -3,6 +3,8 @@ namespace App\Http\Controllers; use App\Models\Project; +use App\Models\Activity; +use App\Models\VersionGantt; use App\Models\Divisi; use App\Models\ProjectPhase; use App\Models\AssignMaterial; @@ -57,7 +59,7 @@ class DashboardBoDController extends Controller // we can't use eloquent's sum() method because someone decided to use varchar as datatype in rencana_biaya field $totalBudgets = Project::select(DB::raw('SUM(CAST("rencana_biaya" AS DOUBLE PRECISION))')) ->where('mulai_proyek', 'like', $year) - /* ->orWhere('akhir_proyek', 'like', $year) */ + /* ->orWhere('akhir_proyek', 'like', $year) */ ->pluck('sum') ->first(); @@ -121,30 +123,52 @@ class DashboardBoDController extends Controller ], 200); } - // to do public function getTotalProjectPerScheduleHealth($year = '%'){ $year = $this->interpolateYear($year); - // get data plan (vol) in % - // get data actual in % - return response()->json([ - 'data' => [ - 'behind-schedule' => rand(0,10), - 'warning' => rand(0,10), - 'on-schedule' => rand(0,10), - ] - ], 200); + + $return = [ + 'behind-schedule' => 0, + 'warning' => 0, + 'on-schedule' => 0, + ]; + + $projects = Project::where('mulai_proyek', 'like', $year)->get(); + foreach($projects as $project) { + $project->scurve = $this->getSCurve($project->id); + if(@$project->scurve['difference'] > 0 && @$project->scurve['difference'] <= 5) + $return['warning'] += 1; + elseif(@$project->scurve['difference'] > 5 && @$project->scurve['difference'] <= 100) + $return['behind-schedule'] += 1; + elseif(@$project->scurve['difference'] == 0) + $return['on-schedule'] += 1; + } + + return response()->json(['data' => $return], 200); } - // todo public function getTotalProjectScheduleHealthPerDivision($year = '%'){ $year = $this->interpolateYear($year); $divisions = Divisi::whereNull('parent')->get(); foreach($divisions as $division){ + $scheduleData = new Collection(); - $scheduleData->prepend(rand(0, 10), 'behindSchedule'); - $scheduleData->prepend(rand(0, 10), 'warning'); - $scheduleData->prepend(rand(0, 10), 'onSchedule'); + $behindSchedule = $warning = $onSchedule = 0; + + $projects = Project::where('mulai_proyek', 'like', $year)->where('divisi_id', $division->id)->get(); + foreach($projects as $project) { + $project->scurve = $this->getSCurve($project->id); + if(@$project->scurve['difference'] > 0 && @$project->scurve['difference'] <= 5) + $warning++; + elseif(@$project->scurve['difference'] > 5 && @$project->scurve['difference'] <= 100) + $behindSchedule++; + elseif(@$project->scurve['difference'] == 0) + $onSchedule++; + } + + $scheduleData->prepend($behindSchedule, 'behindSchedule'); + $scheduleData->prepend($warning, 'warning'); + $scheduleData->prepend($onSchedule, 'onSchedule'); $division->scheduleData = $scheduleData; } return response()->json([ @@ -168,7 +192,7 @@ class DashboardBoDController extends Controller private function countTotalProjectByBudgetHealthInDivision($divisi, $year, $health){ return Project::where('divisi_id', $divisi) ->where('mulai_proyek', 'like', $year) - /* ->orWhere('akhir_proyek', 'like', $year) */ + /* ->orWhere('akhir_proyek', 'like', $year) */ ->where('budget_health', $health) ->count(); } @@ -208,9 +232,9 @@ class DashboardBoDController extends Controller $projectPhases = ProjectPhase::orderBy('order')->get(); foreach($projectPhases as $phase){ $phase->totalProject = Project::where('phase_id', $phase->id) - ->where('mulai_proyek', 'like', $year) - /* ->orWhere('akhir_proyek', 'like', $year) */ - ->count(); + ->where('mulai_proyek', 'like', $year) + /* ->orWhere('akhir_proyek', 'like', $year) */ + ->count(); } return response()->json([ 'data' => [ @@ -222,7 +246,7 @@ class DashboardBoDController extends Controller private function countTotalProjectInDivision($id, $year){ return Project::where('divisi_id', $id) ->where('mulai_proyek', 'like', $year) - /* ->orWhere('akhir_proyek', 'like', $year) */ + /* ->orWhere('akhir_proyek', 'like', $year) */ ->count(); } @@ -251,7 +275,7 @@ class DashboardBoDController extends Controller private function countTotalProjectValueInDivision($id, $year){ return Project::select(DB::raw('SUM(CAST("rencana_biaya" AS DOUBLE PRECISION))')) ->where('mulai_proyek', 'like', $year) - /* ->orWhere('akhir_proyek', 'like', $year) */ + /* ->orWhere('akhir_proyek', 'like', $year) */ ->where('divisi_id', $id) ->pluck('sum') ->first(); @@ -279,5 +303,143 @@ class DashboardBoDController extends Controller ], 200); } + private function getSCurve($project_id) + { + DB::enableQueryLog(); + + $dataPayload = [ + 'project_id' => $project_id, + 'period' => 'week', + ]; + $allGantt[] = $this->getLatestGantt($dataPayload['project_id']); + $dataResponse=[]; + + foreach ($allGantt as $keyGantt) { + $dataProject = Project::find($keyGantt['proyek_id']); + + $totalRencanaBudget = Activity::whereNull('parent_id')->where("proyek_id", $keyGantt['proyek_id'])->where("version_gantt_id", $keyGantt['last_gantt_id'])->sum("rencana_biaya"); + + if(!Activity::where("version_gantt_id", $keyGantt['last_gantt_id'])->first()) + continue; + + $alreadyHasReport = DB::table('report_activity_material as a') + ->select('a.id') + ->join('m_activity as b', 'b.id', '=', 'a.activity_id') + ->where('b.version_gantt_id', '=', $keyGantt['last_gantt_id']) + ->exists(); + + if(!$alreadyHasReport) + continue; + + $minDate = Activity::where('version_gantt_id', $keyGantt['last_gantt_id'])->min("planned_start"); + + $begin = new \DateTime($minDate.' Monday'); + $maxDate = DB::table('assign_material_to_activity as ama') + ->where("ama.proyek_id", $keyGantt['proyek_id']) + ->join('m_activity as a', 'a.id', '=', 'ama.activity_id') + ->where('a.version_gantt_id', '=', $keyGantt['last_gantt_id']) + ->max("plan_date"); // plan date overlapped with assign_material_to_activity's, it should be m_activity's + $end = new \DateTime($maxDate. ' Friday'); + $interval = new \DateInterval('P7D'); + $period = new \DatePeriod($begin, $interval, $end); + + $tempTtlPercentPlan=0; + $tempTtlPercentActual=0; + $tempPercentagePlan = []; + $tempPercentageReal = []; + + foreach ($period as $dt) { + $minSevenDays = new \Datetime($dt->format("Y-m-d")); + $minSevenDays = $minSevenDays->modify('-7 day')->format("Y-m-d"); + $dataPlanM = DB::table('assign_material_to_activity as ama') + ->select('ama.activity_id', 'ama.qty_planning', 'ama.plan_date', 'ama.start_activity', 'a.bobot_planning', 'a.biaya_actual', 'a.duration', 'a.persentase_progress') + ->join('m_activity as a', 'a.id', '=', 'ama.activity_id') + ->where('ama.proyek_id', '=', $keyGantt['proyek_id']) + ->where('a.version_gantt_id', '=', $keyGantt['last_gantt_id']) + ->whereDate('ama.plan_date', '<=',$dt->format("Y-m-d")) + ->whereDate('ama.plan_date', '>', $minSevenDays) + ->get(); + $dataActualM = DB::table('report_activity_material as ram') + ->select('ram.activity_id', 'ram.qty', 'ram.report_date', 'a.bobot_planning', 'a.biaya_actual', 'a.duration', 'a.persentase_progress') + ->join('m_activity as a', 'a.id', '=', 'ram.activity_id') + ->where('a.version_gantt_id', '=', $keyGantt['last_gantt_id']) + ->where('a.proyek_id', '=', $keyGantt['proyek_id']) + ->whereDate('ram.report_date', '<=',$dt->format("Y-m-d")) + ->whereDate('ram.report_date', '>',$minSevenDays) + ->get(); + $sumPercentagePlan=0; + + foreach ($dataPlanM as $keyPlanM) { + $sumVolPlan = DB::table('assign_material_to_activity') + ->select('activity_id', DB::raw('SUM(qty_planning) as ttl_qty_plan')) + ->where('activity_id', '=', $keyPlanM->activity_id) + ->groupBy('activity_id') + ->first(); + try { + $sumPercentagePlan+=($keyPlanM->qty_planning/$sumVolPlan->ttl_qty_plan)*$keyPlanM->bobot_planning; + } catch (\DivisionByZeroError $e) { + return response()->json(['message' => $e->getMessage()]); + } + } + + $sumPercentageActual=0; + foreach ($dataActualM as $keyActualM) { + $sumVolActual = DB::table('assign_material_to_activity') + ->select('activity_id', DB::raw('SUM(qty_planning) as ttl_qty_plan')) + ->where('activity_id', '=', $keyActualM->activity_id) + ->groupBy('activity_id') + ->first(); + try { + $sumPercentageActual+=($keyActualM->qty/$sumVolActual->ttl_qty_plan)*$keyActualM->bobot_planning; + } catch (\DivisionByZeroError $e) { + return response()->json(['message' => $e->getMessage()]); + } + } + + $tempTtlPercentPlan+= $sumPercentagePlan; + $tempTtlPercentActual+= $sumPercentageActual; + + if($tempTtlPercentPlan >= 100 || $tempTtlPercentActual >= 100){ + if($tempTtlPercentActual >= 100) + $tempTtlPercentActual = 100; + if($tempTtlPercentPlan >= 100) + $tempTtlPercentPlan = 100; + } + + + $tempPercentage[] = array(round($tempTtlPercentPlan,2), round($tempTtlPercentActual,2)); + $tempPercentagePlan[] = round($tempTtlPercentPlan, 2); + $tempPercentagePlanWhr[] = ["weekly period", $tempPercentagePlan]; + $tempPercentageReal[] = round($tempTtlPercentActual, 2); + if($tempTtlPercentPlan >= 100 && $tempTtlPercentActual >= 100){ + break; + } + } + + $plannedPercentage = end($tempPercentagePlan); + $progressPercentage = end($tempPercentageReal); + $difference = $plannedPercentage - $progressPercentage; + + $dataResponse = array( + 'planned' => $plannedPercentage, + 'progress' => $progressPercentage, + 'difference' => $difference, + ); + + + } + + return $dataResponse; + } + + private function getLatestGantt($id){ + $maxGanttId = VersionGantt::where("proyek_id", $id)->max("id"); + $data = array( + "last_gantt_id" => $maxGanttId, + "proyek_id" => $id + ); + return $data; + } + }