fix: violation alpha sync per (siswa, tanggal) — hapus violation lama saat push koreksi tanpa alpha
Bug: $alphaDate global null saat push tanpa alpha → violation lama tak pernah dihapus (false positive); totalAlpha dihitung utk semua siswa dgn tanggal global → rawan salah siswa/tanggal. Kini iterasi per (student, date) dari push. + test AttendanceSyncViolationFixTest (4 test).
This commit is contained in:
@@ -90,8 +90,7 @@ class AttendanceSyncController extends Controller
|
||||
$classNameMap = $students->pluck('class_name', 'id');
|
||||
|
||||
$alphaCounts = [];
|
||||
$alphaDate = null;
|
||||
$allStudentIdsInPush = []; // track all students for cleanup
|
||||
$datesByStudent = []; // student_id => [date => true] — untuk pembersihan violation per tanggal
|
||||
|
||||
foreach ($attendances as $item) {
|
||||
$sourceId = $item['source_student_id'];
|
||||
@@ -103,7 +102,7 @@ class AttendanceSyncController extends Controller
|
||||
}
|
||||
|
||||
$localStudentId = $studentMap[$sourceId];
|
||||
$allStudentIdsInPush[$localStudentId] = true;
|
||||
$datesByStudent[$localStudentId][$item['date']] = true;
|
||||
|
||||
$statusMap = [
|
||||
'present' => 'hadir',
|
||||
@@ -137,7 +136,6 @@ class AttendanceSyncController extends Controller
|
||||
|
||||
if ($localStatus === 'alpha') {
|
||||
$alphaCounts[$localStudentId] = ($alphaCounts[$localStudentId] ?? 0) + 1;
|
||||
$alphaDate = $item['date'];
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$results['errors'][] = "student_id={$sourceId} jam={$item['lesson_hour']}: " . $e->getMessage();
|
||||
@@ -145,57 +143,63 @@ class AttendanceSyncController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-generate / update / hapus violations untuk alpha siswa di push ini
|
||||
// Auto-generate / update / hapus violations alpha per (siswa, tanggal) dari push ini.
|
||||
// FIX 2026-08-31: sebelumnya memakai $alphaDate global (null saat push tanpa alpha)
|
||||
// sehingga violation lama tidak pernah dihapus → false positive; dan $totalAlpha
|
||||
// dihitung untuk semua siswa memakai satu tanggal global → rawan salah tanggal/siswa.
|
||||
// Sekarang iterasi per (student, date) yang benar-benar muncul di push.
|
||||
$alphaType = ViolationType::where('slug', 'alpha')->first();
|
||||
|
||||
if ($alphaType) {
|
||||
$violationService = app(\App\Services\ViolationService::class);
|
||||
|
||||
foreach ($allStudentIdsInPush as $studentId => $_) {
|
||||
try {
|
||||
// Hitung total alpha di DB (akumulasi dari semua push, bukan cuma push ini)
|
||||
$totalAlpha = \App\Models\Attendance::where('student_id', $studentId)
|
||||
->where('date', $alphaDate)
|
||||
->where('status', 'alpha')
|
||||
->count();
|
||||
foreach ($datesByStudent as $studentId => $dates) {
|
||||
foreach (array_keys($dates) as $date) {
|
||||
try {
|
||||
// Hitung total alpha di DB per (siswa, tanggal) — akumulasi dari semua push
|
||||
$totalAlpha = \App\Models\Attendance::where('student_id', $studentId)
|
||||
->where('date', $date)
|
||||
->where('status', 'alpha')
|
||||
->count();
|
||||
|
||||
// Cari existing system-generated violation
|
||||
$existing = \App\Models\Violation::where('student_id', $studentId)
|
||||
->where('violation_type_id', $alphaType->id)
|
||||
->where('violation_date', $alphaDate)
|
||||
->whereNull('recorded_by')
|
||||
->first();
|
||||
// Cari existing system-generated violation untuk (siswa, tanggal) yang sama
|
||||
$existing = \App\Models\Violation::where('student_id', $studentId)
|
||||
->where('violation_type_id', $alphaType->id)
|
||||
->where('violation_date', $date)
|
||||
->whereNull('recorded_by')
|
||||
->first();
|
||||
|
||||
if ($totalAlpha > 0) {
|
||||
// Ada alpha → buat/update violation
|
||||
$points = max(1, (int) round(($alphaType->points / 10) * $totalAlpha));
|
||||
$desc = "Alpha - Tidak hadir tanpa keterangan ({$totalAlpha} jam pelajaran)";
|
||||
if ($totalAlpha > 0) {
|
||||
// Ada alpha → buat/update violation
|
||||
$points = max(1, (int) round(($alphaType->points / 10) * $totalAlpha));
|
||||
$desc = "Alpha - Tidak hadir tanpa keterangan ({$totalAlpha} jam pelajaran)";
|
||||
|
||||
if ($existing) {
|
||||
$existing->update([
|
||||
'points' => $points,
|
||||
'description' => $desc,
|
||||
'notes' => 'Diperbarui otomatis dari sinkron E-Jurnal.',
|
||||
]);
|
||||
} else {
|
||||
$violationService->recordViolation([
|
||||
'student_id' => $studentId,
|
||||
'violation_type_id' => $alphaType->id,
|
||||
'violation_date' => $alphaDate,
|
||||
'points' => $points,
|
||||
'description' => $desc,
|
||||
'notes' => 'Dibuat otomatis dari sinkron E-Jurnal.',
|
||||
'evidences' => [],
|
||||
], null);
|
||||
if ($existing) {
|
||||
$existing->update([
|
||||
'points' => $points,
|
||||
'description' => $desc,
|
||||
'notes' => 'Diperbarui otomatis dari sinkron E-Jurnal.',
|
||||
]);
|
||||
} else {
|
||||
$violationService->recordViolation([
|
||||
'student_id' => $studentId,
|
||||
'violation_type_id' => $alphaType->id,
|
||||
'violation_date' => $date,
|
||||
'points' => $points,
|
||||
'description' => $desc,
|
||||
'notes' => 'Dibuat otomatis dari sinkron E-Jurnal.',
|
||||
'evidences' => [],
|
||||
], null);
|
||||
}
|
||||
$results['violations']++;
|
||||
} elseif ($existing) {
|
||||
// Tidak ada alpha di tanggal ini tapi ada violation system lama → hapus (ganti status ke hadir)
|
||||
$existing->delete();
|
||||
$results['violations']++;
|
||||
}
|
||||
$results['violations']++;
|
||||
} elseif ($existing) {
|
||||
// Tidak ada alpha tapi ada violation lama → hapus (ganti status ke hadir)
|
||||
$existing->delete();
|
||||
$results['violations']++;
|
||||
} catch (\Exception $e) {
|
||||
$results['errors'][] = "Violation sync failed for student={$studentId} date={$date}: " . $e->getMessage();
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$results['errors'][] = "Violation sync failed for student={$studentId}: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user