year; $month = $month ?? now()->month; // Get current KPI target (no longer filtered by year/month) $kpiTarget = $user->kpiTargets() ->where('is_active', true) ->first(); if (!$kpiTarget) { Log::info("No KPI target found for user {$user->id}"); return null; } // Calculate actual value based on month $actualValue = $this->getActualWorkCount($user, $year, $month); // Calculate percentage $achievementPercentage = $kpiTarget->target_value > 0 ? ($actualValue / $kpiTarget->target_value) * 100 : 0; // Save or update achievement with target value stored directly return KpiAchievement::updateOrCreate( [ 'user_id' => $user->id, 'year' => $year, 'month' => $month ], [ 'kpi_target_id' => $kpiTarget->id, 'target_value' => $kpiTarget->target_value, // Store target value directly for historical tracking 'actual_value' => $actualValue, 'achievement_percentage' => $achievementPercentage ] ); } /** * Get actual work count for a user in specific month * * @param User $user * @param int $year * @param int $month * @return int */ private function getActualWorkCount(User $user, $year, $month) { return Transaction::where('user_id', $user->id) ->where('status', 'completed') ->whereYear('date', $year) ->whereMonth('date', $month) ->sum('qty'); } /** * Generate KPI report for a user * * @param User $user * @param int|null $year * @param int|null $month * @return array */ public function generateKpiReport(User $user, $year = null, $month = null) { $year = $year ?? now()->year; $month = $month ?? now()->month; $achievements = $user->kpiAchievements() ->where('year', $year) ->where('month', $month) ->orderBy('month') ->get(); $target = $user->kpiTargets() ->where('is_active', true) ->first(); return [ 'user' => $user, 'target' => $target, 'achievements' => $achievements, 'summary' => $this->calculateSummary($achievements), 'period' => [ 'year' => $year, 'month' => $month, 'period_name' => $this->getMonthName($month) . ' ' . $year ] ]; } /** * Calculate summary statistics for achievements * * @param \Illuminate\Database\Eloquent\Collection $achievements * @return array */ private function calculateSummary($achievements) { if ($achievements->isEmpty()) { return [ 'total_target' => 0, 'total_actual' => 0, 'average_achievement' => 0, 'best_period' => null, 'worst_period' => null, 'total_periods' => 0, 'achievement_rate' => 0 ]; } $totalTarget = $achievements->sum('target_value'); $totalActual = $achievements->sum('actual_value'); $averageAchievement = $achievements->avg('achievement_percentage'); $totalPeriods = $achievements->count(); $achievementRate = $totalPeriods > 0 ? ($achievements->where('achievement_percentage', '>=', 100)->count() / $totalPeriods) * 100 : 0; $bestPeriod = $achievements->sortByDesc('achievement_percentage')->first(); $worstPeriod = $achievements->sortBy('achievement_percentage')->first(); return [ 'total_target' => $totalTarget, 'total_actual' => $totalActual, 'average_achievement' => round($averageAchievement, 2), 'best_period' => $bestPeriod, 'worst_period' => $worstPeriod, 'total_periods' => $totalPeriods, 'achievement_rate' => round($achievementRate, 2) ]; } /** * Get KPI statistics for all mechanics * * @param int|null $year * @param int|null $month * @return array */ public function getMechanicsKpiStats($year = null, $month = null) { $year = $year ?? now()->year; $month = $month ?? now()->month; $mechanics = User::whereHas('role', function($query) { $query->where('name', 'mechanic'); })->get(); $stats = []; foreach ($mechanics as $mechanic) { $report = $this->generateKpiReport($mechanic, $year, $month); $stats[] = [ 'user' => $mechanic, 'summary' => $report['summary'], 'target' => $report['target'] ]; } return $stats; } /** * Auto-calculate KPI achievements for all mechanics * * @param int|null $year * @param int|null $month * @return array */ public function autoCalculateAllMechanics($year = null, $month = null) { $year = $year ?? now()->year; $month = $month ?? now()->month; $mechanics = User::whereHas('role', function($query) { $query->where('name', 'mechanic'); })->get(); $results = []; foreach ($mechanics as $mechanic) { try { $achievement = $this->calculateKpiAchievement($mechanic, $year, $month); $results[] = [ 'user_id' => $mechanic->id, 'user_name' => $mechanic->name, 'success' => true, 'achievement' => $achievement ]; } catch (\Exception $e) { Log::error("Failed to calculate KPI for user {$mechanic->id}: " . $e->getMessage()); $results[] = [ 'user_id' => $mechanic->id, 'user_name' => $mechanic->name, 'success' => false, 'error' => $e->getMessage() ]; } } return $results; } /** * Get KPI trend data for chart * * @param User $user * @param int $months * @return array */ public function getKpiTrendData(User $user, $months = 12) { $endDate = now(); $startDate = $endDate->copy()->subMonths($months); $achievements = $user->kpiAchievements() ->where(function($query) use ($startDate, $endDate) { $query->where(function($q) use ($startDate, $endDate) { $q->where('year', '>', $startDate->year) ->orWhere(function($subQ) use ($startDate, $endDate) { $subQ->where('year', $startDate->year) ->where('month', '>=', $startDate->month); }); }) ->where(function($q) use ($endDate) { $q->where('year', '<', $endDate->year) ->orWhere(function($subQ) use ($endDate) { $subQ->where('year', $endDate->year) ->where('month', '<=', $endDate->month); }); }); }) ->orderBy('year') ->orderBy('month') ->get(); $trendData = []; foreach ($achievements as $achievement) { $trendData[] = [ 'period' => $achievement->getPeriodDisplayName(), 'target' => $achievement->target_value, 'actual' => $achievement->actual_value, 'percentage' => $achievement->achievement_percentage, 'status' => $achievement->status ]; } return $trendData; } /** * Get month name in Indonesian * * @param int $month * @return string */ private function getMonthName($month) { $monthNames = [ 1 => 'Januari', 2 => 'Februari', 3 => 'Maret', 4 => 'April', 5 => 'Mei', 6 => 'Juni', 7 => 'Juli', 8 => 'Agustus', 9 => 'September', 10 => 'Oktober', 11 => 'November', 12 => 'Desember' ]; return $monthNames[$month] ?? 'Unknown'; } /** * Get KPI summary for dashboard * * @param User $user * @return array */ public function getKpiSummary(User $user) { $currentYear = now()->year; $currentMonth = now()->month; // Get current month achievement $currentAchievement = $user->kpiAchievements() ->where('year', $currentYear) ->where('month', $currentMonth) ->first(); // Get current month target (no longer filtered by year/month) $currentTarget = $user->kpiTargets() ->where('is_active', true) ->first(); // Get last 6 months achievements $recentAchievements = $user->kpiAchievements() ->where(function($query) use ($currentYear, $currentMonth) { $query->where('year', '>', $currentYear - 1) ->orWhere(function($q) use ($currentYear, $currentMonth) { $q->where('year', $currentYear) ->where('month', '>=', max(1, $currentMonth - 5)); }); }) ->orderBy('year', 'desc') ->orderBy('month', 'desc') ->limit(6) ->get(); return [ 'current_achievement' => $currentAchievement, 'current_target' => $currentTarget, 'recent_achievements' => $recentAchievements, 'current_percentage' => $currentAchievement ? $currentAchievement->achievement_percentage : 0, 'is_on_track' => $currentAchievement ? $currentAchievement->achievement_percentage >= 100 : false ]; } }