From 1b49270c4a8c974882c443b6eff8947a88df889e Mon Sep 17 00:00:00 2001 From: Novy San87 Date: Thu, 6 Aug 2026 12:52:25 +0700 Subject: [PATCH] feat: endpoint statistik pelanggaran wali (kategori, jenis, tren 6 bulan) --- .../Api/ParentStudentController.php | 74 +++++++++++++++++++ routes/api.php | 1 + 2 files changed, 75 insertions(+) diff --git a/app/Http/Controllers/Api/ParentStudentController.php b/app/Http/Controllers/Api/ParentStudentController.php index c9b229c..49bacbb 100644 --- a/app/Http/Controllers/Api/ParentStudentController.php +++ b/app/Http/Controllers/Api/ParentStudentController.php @@ -266,6 +266,80 @@ class ParentStudentController extends Controller ]); } + /** + * Statistik pelanggaran putra/putri (per kategori, jenis, tren bulanan). + */ + public function violationsStats(Request $request, Student $student): JsonResponse + { + $hasLink = ParentStudent::where('user_id', $request->user()->id) + ->where('student_id', $student->id) + ->where('status', 'active') + ->exists(); + + abort_unless($hasLink, 403, 'Putra/putri belum tertaut aktif.'); + + $violations = $student->violations() + ->with('violationType.category') + ->get(); + + $totalCount = $violations->count(); + $totalPoints = (int) $student->total_points; + + // Per kategori (Ringan/Sedang/Berat) + $categories = $violations + ->groupBy(fn ($v) => $v->violationType?->category?->id ?? 0) + ->map(function ($items, $catId) { + $cat = $items->first()->violationType?->category; + + return [ + 'name' => $cat?->name ?? 'Lainnya', + 'color' => $cat?->color ?? '#94a3b8', + 'count' => $items->count(), + 'points' => (int) $items->sum('points'), + ]; + }) + ->values() + ->sortByDesc('count') + ->values(); + + // Jenis pelanggaran teratas + $topTypes = $violations + ->groupBy(fn ($v) => $v->violation_type_id) + ->map(function ($items) { + return [ + 'name' => $items->first()->violationType?->name ?? 'Lainnya', + 'count' => $items->count(), + 'points' => (int) $items->sum('points'), + ]; + }) + ->values() + ->sortByDesc('count') + ->take(5) + ->values(); + + // Tren 6 bulan terakhir + $monthly = []; + for ($i = 5; $i >= 0; $i--) { + $m = now()->subMonths($i); + $key = $m->format('Y-m'); + $monthly[] = [ + 'month' => $key, + 'month_number' => (int) $m->format('n'), + 'count' => $violations + ->filter(fn ($v) => $v->violation_date?->format('Y-m') === $key) + ->count(), + ]; + } + + return response()->json([ + 'total_count' => $totalCount, + 'total_points' => $totalPoints, + 'categories' => $categories, + 'top_types' => $topTypes, + 'monthly' => $monthly, + ]); + } + /** * Tautkan anak tambahan (kakak/adik) ke akun wali. */ diff --git a/routes/api.php b/routes/api.php index bc8025d..655ed3f 100644 --- a/routes/api.php +++ b/routes/api.php @@ -38,6 +38,7 @@ Route::middleware('auth:sanctum')->prefix('parent')->group(function () { Route::get('/students/{student}/schedule', [ParentStudentController::class, 'schedule'])->name('api.parent.students.schedule'); Route::get('/students/{student}/attendance', [ParentStudentController::class, 'attendance'])->name('api.parent.students.attendance'); Route::get('/students/{student}/points-history', [ParentStudentController::class, 'pointsHistory'])->name('api.parent.students.points-history'); + Route::get('/students/{student}/violations-stats', [ParentStudentController::class, 'violationsStats'])->name('api.parent.students.violations-stats'); // Notifikasi & perangkat Route::get('/notifications', [ParentNotificationController::class, 'index'])->name('api.parent.notifications');