startOfDay(); $end = Carbon::parse($endDate)->endOfDay(); // 1. Ambil Master Jadwal Kelas beserta relasinya $masterJadwal = JadwalKelas::with(['kelas', 'guru', 'ruangan', 'sesi'])->get(); if ($masterJadwal->isEmpty()) { throw new \Exception('Belum ada data Master Jadwal Mingguan (`jadwal_kelas`). Silakan jalankan generate GA terlebih dahulu.'); } $createdCount = 0; $updatedCount = 0; $skippedCount = 0; $deletedExcessCount = 0; // Peta maksimal pertemuan per kelas dari jenis_kelas (ex: "12 Sesi" => 12) $maxMeetingsMap = []; foreach ($masterJadwal as $j) { if ($j->kelas && !isset($maxMeetingsMap[$j->kelas_id])) { $maxM = null; if (!empty($j->kelas->jenis_kelas)) { if (preg_match('/\d+/', $j->kelas->jenis_kelas, $matches)) { $maxM = (int) $matches[0]; } } $maxMeetingsMap[$j->kelas_id] = $maxM; } } // Track per-kelas pertemuan counter $pertemuanCounter = []; // 2. Iterasi per hari dari startDate hingga endDate $currentDate = $start->copy(); while ($currentDate->lte($end)) { $dayIso = $currentDate->dayOfWeekIso; // 1 = Senin, ..., 7 = Minggu $dateString = $currentDate->format('Y-m-d'); // Cari jadwal yang sesuai dengan hari pada tanggal ini $schedulesForDay = $masterJadwal->where('hari', $dayIso); foreach ($schedulesForDay as $jadwal) { $kelasId = $jadwal->kelas_id; $maxMeetings = $maxMeetingsMap[$kelasId] ?? null; if (!isset($pertemuanCounter[$kelasId])) { // Hitung berapa entri logbook yang sudah ada untuk kelas ini secara keseluruhan $totalExisting = Logbooks::where('kelas_id', $kelasId)->count(); $pertemuanCounter[$kelasId] = $totalExisting; } // Cek apakah logbook untuk kelas, tanggal, dan sesi ini sudah ada $existingLogbook = Logbooks::where('kelas_id', $kelasId) ->where('tanggal', $dateString) ->where('sesi_id', $jadwal->sesi_id) ->first(); // Ekstrak jam start & end dari Sesi (ex: "08:00 - 10:00") $jamStart = null; $jamEnd = null; if ($jadwal->sesi && $jadwal->sesi->jam) { $jamParts = explode('-', $jadwal->sesi->jam); $jamStart = isset($jamParts[0]) ? trim($jamParts[0]) : null; $jamEnd = isset($jamParts[1]) ? trim($jamParts[1]) : null; } if ($existingLogbook) { // Jika logbook sudah completed, lewati agar data presensi guru tidak hilang if ($existingLogbook->status === 'completed') { $skippedCount++; continue; } // Update logbook pending dengan info master jadwal terbaru $existingLogbook->update([ 'guru_id' => $jadwal->guru_id, 'ruangan_id' => $jadwal->ruangan_id, 'hari_id' => $dayIso, 'kode_kelas' => $jadwal->kelas->kode_kelas ?? $existingLogbook->kode_kelas, 'start' => $jamStart ?? $existingLogbook->start, 'end' => $jamEnd ?? $existingLogbook->end, ]); $updatedCount++; } else { // Cek apakah kelas sudah mencapai batas maksimal pertemuan (misal 12 sesi) if ($maxMeetings !== null && $pertemuanCounter[$kelasId] >= $maxMeetings) { $skippedCount++; continue; } // Inkremen nomor pertemuan $pertemuanCounter[$kelasId]++; $pertemuanKe = (string) $pertemuanCounter[$kelasId]; Logbooks::create([ 'kelas_id' => $kelasId, 'kode_kelas' => $jadwal->kelas->kode_kelas ?? null, 'guru_id' => $jadwal->guru_id, 'ruangan_id' => $jadwal->ruangan_id, 'sesi_id' => $jadwal->sesi_id, 'hari_id' => $dayIso, 'tanggal' => $dateString, 'start' => $jamStart, 'end' => $jamEnd, 'pertemuan' => $pertemuanKe, 'status' => 'pending', ]); $createdCount++; } } $currentDate->addDay(); } // 3. Bersihkan entri logbook berstatus 'pending' yang melebihi maxMeetings per kelas foreach ($maxMeetingsMap as $kelasId => $maxM) { if ($maxM !== null) { $excessLogbooks = Logbooks::where('kelas_id', $kelasId) ->where('status', 'pending') ->get() ->filter(function ($lb) use ($maxM) { return is_numeric($lb->pertemuan) && (int)$lb->pertemuan > $maxM; }); foreach ($excessLogbooks as $excess) { $excess->delete(); $deletedExcessCount++; } } } return [ 'created' => $createdCount, 'updated' => $updatedCount, 'skipped' => $skippedCount, 'deleted_excess' => $deletedExcessCount, 'total' => $createdCount + $updatedCount + $skippedCount ]; } }