162 lines
6.4 KiB
PHP
162 lines
6.4 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\JadwalKelas;
|
|
use App\Models\Logbooks;
|
|
use Illuminate\Support\Carbon;
|
|
|
|
class LogbookGeneratorService
|
|
{
|
|
/**
|
|
* Generate entri logbook berdasarkan Master Jadwal GA (jadwal_kelas)
|
|
* untuk rentang tanggal tertentu, dibatasi oleh total sesi/pertemuan per kelas (jenis_kelas).
|
|
*
|
|
* @param string $startDate (Format: YYYY-MM-DD)
|
|
* @param string $endDate (Format: YYYY-MM-DD)
|
|
* @param array $options
|
|
* @return array
|
|
*/
|
|
public function generateFromJadwal(string $startDate, string $endDate, array $options = []): array
|
|
{
|
|
$start = Carbon::parse($startDate)->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
|
|
];
|
|
}
|
|
}
|