659 lines
24 KiB
PHP
659 lines
24 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use Illuminate\Http\Request;
|
|
use App\Models\AttendanceHistoryDaily;
|
|
use App\Models\Classes;
|
|
use App\Models\Student;
|
|
use App\Traits\ExcelExportTrait;
|
|
use Illuminate\Support\Collection;
|
|
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
|
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
|
|
use PhpOffice\PhpSpreadsheet\Style\Alignment;
|
|
use PhpOffice\PhpSpreadsheet\Style\Border;
|
|
use PhpOffice\PhpSpreadsheet\Style\Fill;
|
|
|
|
class HistoryDailyController extends Controller
|
|
{
|
|
use ExcelExportTrait;
|
|
public function absensiHarian($classId, Request $request)
|
|
{
|
|
$kelas = Classes::findOrFail($classId);
|
|
|
|
// Ambil semua siswa di kelas
|
|
$students = Student::where('id_class', $classId)->get();
|
|
|
|
// Determine filter parameters
|
|
$tanggal = $request->get('tanggal');
|
|
$bulan = $request->get('bulan');
|
|
$tahun = $request->get('tahun');
|
|
|
|
// Default ke hari ini hanya jika tidak ada filter apapun
|
|
if (!$tanggal && !$bulan && !$tahun) {
|
|
$tanggal = now()->format('Y-m-d');
|
|
}
|
|
|
|
// Build query untuk fetch attendance records
|
|
$query = AttendanceHistoryDaily::with(['student', 'class'])
|
|
->where('id_class', $classId);
|
|
|
|
// Jika tanggal diset, filter by exact date
|
|
if ($tanggal && !$bulan && !$tahun) {
|
|
$query->whereDate('created_at', $tanggal);
|
|
}
|
|
// Jika bulan dan tahun keduanya diset, filter by month AND year
|
|
else if ($bulan && $tahun) {
|
|
$query->whereMonth('created_at', $bulan)
|
|
->whereYear('created_at', $tahun);
|
|
}
|
|
// Jika hanya bulan diset, filter by month
|
|
else if ($bulan) {
|
|
$query->whereMonth('created_at', $bulan);
|
|
}
|
|
// Jika hanya tahun diset, filter by year
|
|
else if ($tahun) {
|
|
$query->whereYear('created_at', $tahun);
|
|
}
|
|
|
|
$absensiFromDB = $query->orderBy('created_at', 'desc')->get();
|
|
|
|
// Dapatkan semua hari UNIK dari records
|
|
$uniqueDates = $absensiFromDB
|
|
->map(function($item) { return $item->created_at->format('Y-m-d'); })
|
|
->unique()
|
|
->values()
|
|
->sort()
|
|
->reverse() // Terbaru dulu
|
|
->values();
|
|
|
|
// Jika filter tanggal spesifik dan tidak ada data, tambahkan tanggal tersebut
|
|
if ($tanggal && !$bulan && !$tahun && !$uniqueDates->contains($tanggal)) {
|
|
$uniqueDates = collect([$tanggal])->merge($uniqueDates);
|
|
}
|
|
|
|
// Build result: untuk SETIAP HARI, tampilkan SEMUA SISWA
|
|
$result = [];
|
|
foreach ($uniqueDates as $date) {
|
|
foreach ($students as $student) {
|
|
// Cari record di database untuk student + date ini
|
|
$record = $absensiFromDB
|
|
->where('id_student', $student->id)
|
|
->filter(function($item) use ($date) {
|
|
return $item->created_at->format('Y-m-d') === $date;
|
|
})
|
|
->first();
|
|
|
|
if ($record) {
|
|
// Ada record di database
|
|
$result[] = (object)[
|
|
'id' => $record->id,
|
|
'student' => $record->student,
|
|
'class' => $record->class,
|
|
'status' => $record->status,
|
|
'created_at' => $record->created_at,
|
|
'picture' => $record->picture,
|
|
];
|
|
} else {
|
|
// Dummy record: siswa belum absen di hari ini
|
|
// Set created_at ke hari tersebut 00:00:00 untuk filter bekerja dengan baik
|
|
$dummyDateTime = \Carbon\Carbon::parse($date . ' 00:00:00');
|
|
|
|
$result[] = (object)[
|
|
'id' => null,
|
|
'student' => $student,
|
|
'class' => $kelas,
|
|
'status' => 'in progress',
|
|
'created_at' => $dummyDateTime,
|
|
'picture' => null,
|
|
];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Group data by tanggal (created_at)
|
|
$groupedByDate = collect();
|
|
foreach ($result as $item) {
|
|
$dateKey = $item->created_at->format('Y-m-d');
|
|
|
|
if (!$groupedByDate->has($dateKey)) {
|
|
$groupedByDate->put($dateKey, []);
|
|
}
|
|
$items = $groupedByDate->get($dateKey);
|
|
$items[] = $item;
|
|
$groupedByDate->put($dateKey, $items);
|
|
}
|
|
|
|
// Urutkan by tanggal (terbaru dulu)
|
|
$groupedArray = $groupedByDate->toArray();
|
|
krsort($groupedArray);
|
|
|
|
// Get today's date untuk default filter
|
|
$today = now()->format('Y-m-d');
|
|
|
|
return view('pages.absensi.absensi_harian', [
|
|
'absensi' => collect($result),
|
|
'groupedByDate' => $groupedArray,
|
|
'today' => $today,
|
|
'kelas' => $kelas,
|
|
'selectedTanggal' => $tanggal,
|
|
'selectedBulan' => $bulan,
|
|
'selectedTahun' => $tahun
|
|
]);
|
|
}
|
|
|
|
public function editStatus(Request $request, $id)
|
|
{
|
|
$request->validate([
|
|
'status' => 'required|string'
|
|
]);
|
|
|
|
// Jika $id adalah 'null', artinya create baru (belum ada di database)
|
|
if ($id === 'null') {
|
|
$request->validate([
|
|
'id_student' => 'required|exists:students,id',
|
|
'id_class' => 'required|exists:clases,id',
|
|
]);
|
|
|
|
try {
|
|
AttendanceHistoryDaily::create([
|
|
'id_student' => $request->id_student,
|
|
'id_class' => $request->id_class,
|
|
'status' => $request->status,
|
|
'picture' => $request->picture ?? '',
|
|
]);
|
|
|
|
return response()->json(['success' => true, 'message' => 'Data absensi berhasil ditambahkan.']);
|
|
} catch (\Exception $e) {
|
|
return response()->json(['success' => false, 'message' => 'Error: ' . $e->getMessage()], 500);
|
|
}
|
|
} else {
|
|
// Update existing
|
|
$absensi = AttendanceHistoryDaily::findOrFail($id);
|
|
$absensi->status = $request->status;
|
|
$absensi->save();
|
|
|
|
return response()->json(['success' => true, 'message' => 'Status absensi berhasil diupdate.']);
|
|
}
|
|
}
|
|
|
|
public function exportExcel($classId, Request $request)
|
|
{
|
|
// Get kelas info
|
|
$kelas = Classes::findOrFail($classId);
|
|
$kelasName = $kelas->name ?? 'Kelas';
|
|
|
|
$tanggal = $request->get('tanggal');
|
|
$bulan = $request->get('bulan');
|
|
$tahun = $request->get('tahun');
|
|
|
|
// Jika bulan kosong tapi tahun ada, lakukan export tahunan
|
|
if (empty($tanggal) && empty($bulan) && $tahun) {
|
|
return $this->exportExcelYearly($classId, $tahun);
|
|
}
|
|
|
|
// Get data absensi harian
|
|
$rows = $this->getAbsensiHarianRowsForExport($classId, $request);
|
|
|
|
// Build filename suffix
|
|
if ($tanggal) {
|
|
$suffixTanggal = '_' . preg_replace('/[^0-9\-]/', '', $tanggal);
|
|
} else if ($bulan && $tahun) {
|
|
$suffixTanggal = '_' . $tahun . '-' . $bulan;
|
|
} else if ($bulan) {
|
|
$suffixTanggal = '_Bulan' . $bulan;
|
|
} else if ($tahun) {
|
|
$suffixTanggal = '_' . $tahun;
|
|
} else {
|
|
$suffixTanggal = '_' . now()->format('Y-m-d');
|
|
}
|
|
|
|
$filename = 'Rekap_Absensi_Harian_' . preg_replace('/[^A-Za-z0-9_\-]/', '_', $kelasName) . $suffixTanggal;
|
|
|
|
// Create spreadsheet
|
|
$spreadsheet = new Spreadsheet();
|
|
$sheet = $spreadsheet->getActiveSheet();
|
|
$sheet->setTitle('Absensi Harian');
|
|
|
|
// Insert 2 rows untuk title dan subtitle
|
|
$sheet->insertNewRowBefore(1, 2);
|
|
|
|
// Title and subtitle
|
|
$title = 'REKAP ABSENSI HARIAN - ' . strtoupper($kelasName);
|
|
$subtitle = 'Diekspor pada: ' . now()->timezone('Asia/Jakarta')->format('d M Y H:i:s') . ' WIB';
|
|
|
|
$sheet->setCellValue('A1', $title);
|
|
$sheet->setCellValue('A2', $subtitle);
|
|
|
|
// Merge cells untuk title dan subtitle
|
|
$sheet->mergeCells('A1:F1');
|
|
$sheet->mergeCells('A2:F2');
|
|
|
|
// Set row heights
|
|
$sheet->getRowDimension(1)->setRowHeight(24);
|
|
$sheet->getRowDimension(2)->setRowHeight(18);
|
|
|
|
// Style title (Row 1)
|
|
$sheet->getStyle('A1:G1')->applyFromArray([
|
|
'font' => [
|
|
'bold' => true,
|
|
'size' => 14,
|
|
'color' => ['rgb' => '1F2937'],
|
|
],
|
|
'alignment' => [
|
|
'horizontal' => Alignment::HORIZONTAL_CENTER,
|
|
'vertical' => Alignment::VERTICAL_CENTER,
|
|
],
|
|
]);
|
|
|
|
// Style subtitle (Row 2)
|
|
$sheet->getStyle('A2:G2')->applyFromArray([
|
|
'font' => [
|
|
'size' => 10,
|
|
'color' => ['rgb' => '6B7280'],
|
|
],
|
|
'alignment' => [
|
|
'horizontal' => Alignment::HORIZONTAL_CENTER,
|
|
'vertical' => Alignment::VERTICAL_CENTER,
|
|
],
|
|
]);
|
|
|
|
// Add headers at row 3
|
|
$headers = ['No', 'Nama Siswa', 'NISN', 'Kelas', 'Status', 'Waktu'];
|
|
foreach ($headers as $col => $header) {
|
|
$sheet->setCellValue($this->getColumnLetter($col + 1) . '3', $header);
|
|
}
|
|
|
|
// Style headers (Row 3)
|
|
$headerRange = 'A3:F3';
|
|
$sheet->getStyle($headerRange)->applyFromArray([
|
|
'font' => [
|
|
'bold' => true,
|
|
'color' => ['rgb' => 'FFFFFF'],
|
|
],
|
|
'fill' => [
|
|
'fillType' => Fill::FILL_SOLID,
|
|
'startColor' => ['rgb' => '365CF5'],
|
|
],
|
|
'alignment' => [
|
|
'horizontal' => Alignment::HORIZONTAL_CENTER,
|
|
'vertical' => Alignment::VERTICAL_CENTER,
|
|
'wrapText' => true,
|
|
],
|
|
]);
|
|
$sheet->getRowDimension(3)->setRowHeight(20);
|
|
|
|
// Add data rows starting from row 4
|
|
$dataStartRow = 4;
|
|
foreach ($rows as $index => $row) {
|
|
$currentRow = $dataStartRow + $index;
|
|
$sheet->setCellValue('A' . $currentRow, $row['no']);
|
|
$sheet->setCellValue('B' . $currentRow, $row['student_name']);
|
|
$sheet->setCellValue('C' . $currentRow, $row['nisn']);
|
|
$sheet->setCellValue('D' . $currentRow, $row['class_name']);
|
|
$sheet->setCellValue('E' . $currentRow, $row['status']);
|
|
$sheet->setCellValue('F' . $currentRow, $row['waktu']);
|
|
|
|
// Zebra rows (alternate background color)
|
|
if (($index % 2) === 1) {
|
|
$sheet->getStyle('A' . $currentRow . ':F' . $currentRow)->applyFromArray([
|
|
'fill' => [
|
|
'fillType' => Fill::FILL_SOLID,
|
|
'startColor' => ['rgb' => 'F4F7FF'],
|
|
],
|
|
]);
|
|
}
|
|
}
|
|
|
|
// Get highest row
|
|
$highestRow = $sheet->getHighestRow();
|
|
|
|
// Apply borders to all data
|
|
$tableRange = 'A3:F' . $highestRow;
|
|
$sheet->getStyle($tableRange)->applyFromArray([
|
|
'borders' => [
|
|
'allBorders' => [
|
|
'borderStyle' => Border::BORDER_THIN,
|
|
'color' => ['rgb' => 'D1D5DB'],
|
|
],
|
|
],
|
|
]);
|
|
|
|
// Center align specific columns
|
|
$sheet->getStyle('A4:A' . $highestRow)->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
|
|
$sheet->getStyle('D4:D' . $highestRow)->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
|
|
$sheet->getStyle('E4:E' . $highestRow)->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
|
|
|
|
// Set column widths
|
|
$sheet->getColumnDimension('A')->setWidth(6);
|
|
$sheet->getColumnDimension('B')->setWidth(28);
|
|
$sheet->getColumnDimension('C')->setWidth(16);
|
|
$sheet->getColumnDimension('D')->setWidth(14);
|
|
$sheet->getColumnDimension('E')->setWidth(16);
|
|
$sheet->getColumnDimension('F')->setWidth(20);
|
|
|
|
// Freeze top 3 rows (title + subtitle + header)
|
|
$sheet->freezePane('A4');
|
|
|
|
// Save and download
|
|
$writer = new Xlsx($spreadsheet);
|
|
$tempPath = storage_path('app/temp/' . $filename . '.xlsx');
|
|
@mkdir(dirname($tempPath), 0755, true);
|
|
$writer->save($tempPath);
|
|
|
|
return response()->download($tempPath)->deleteFileAfterSend(true);
|
|
}
|
|
|
|
/**
|
|
* Export absensi harian ke Excel - Format Tahunan (12 Bulan)
|
|
*/
|
|
private function exportExcelYearly($classId, $tahun)
|
|
{
|
|
// Get kelas info
|
|
$kelas = Classes::findOrFail($classId);
|
|
$kelasName = $kelas->name ?? 'Kelas';
|
|
|
|
// Get all students
|
|
$students = Student::where('id_class', $classId)->orderBy('name', 'ASC')->get();
|
|
if ($students->isEmpty()) {
|
|
return response()->json(['error' => 'Tidak ada siswa di kelas'], 400);
|
|
}
|
|
|
|
// Generate filename
|
|
$filename = 'Laporan_Tahunan_Absensi_Harian_' . preg_replace('/[^A-Za-z0-9_\-]/', '_', $kelasName) . '_' . $tahun . '.xlsx';
|
|
|
|
// Create spreadsheet
|
|
$spreadsheet = new Spreadsheet();
|
|
$sheet = $spreadsheet->getActiveSheet();
|
|
$sheet->setTitle('Laporan Tahunan');
|
|
|
|
// Row 1: Title (Yellow background)
|
|
$title = 'LAPORAN TAHUNAN ABSENSI HARIAN ' . strtoupper($kelasName);
|
|
$sheet->setCellValue('A1', $title);
|
|
$sheet->mergeCells('A1:Q1');
|
|
$sheet->getRowDimension(1)->setRowHeight(25);
|
|
$sheet->getStyle('A1')->applyFromArray([
|
|
'font' => ['bold' => true, 'size' => 14, 'color' => ['rgb' => '000000']],
|
|
'fill' => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['rgb' => 'FFCC00']],
|
|
'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER],
|
|
]);
|
|
|
|
// Row 2: Period info
|
|
$periodText = 'TAHUN ' . $tahun;
|
|
$sheet->setCellValue('A2', $periodText);
|
|
$sheet->mergeCells('A2:Q2');
|
|
$sheet->getRowDimension(2)->setRowHeight(20);
|
|
$sheet->getStyle('A2')->applyFromArray([
|
|
'font' => ['bold' => true, 'size' => 12, 'color' => ['rgb' => '000000']],
|
|
'fill' => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['rgb' => 'FFCC00']],
|
|
'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER],
|
|
]);
|
|
|
|
// Row 3: Empty
|
|
$sheet->getRowDimension(3)->setRowHeight(10);
|
|
|
|
// Row 4: Headers
|
|
$sheet->setCellValue('A4', 'Nama');
|
|
$sheet->setCellValue('B4', 'Jabatan/Kelas');
|
|
|
|
// Month Names
|
|
$months = ['Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Agt', 'Sep', 'Okt', 'Nov', 'Des'];
|
|
foreach ($months as $idx => $monthName) {
|
|
$colLetter = $this->getColumnLetter($idx + 3); // C = 3
|
|
$sheet->setCellValue($colLetter . '4', $monthName);
|
|
}
|
|
|
|
// Totals Headers
|
|
$sheet->setCellValue('O4', "Total\nTepat Waktu");
|
|
$sheet->setCellValue('P4', "Total\nTerlambat");
|
|
$sheet->setCellValue('Q4', "Total\nIzin");
|
|
|
|
// Style headers (Row 4) - Yellow background
|
|
$headerRange = 'A4:Q4';
|
|
$sheet->getStyle($headerRange)->applyFromArray([
|
|
'font' => ['bold' => true, 'size' => 11, 'color' => ['rgb' => '000000']],
|
|
'fill' => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['rgb' => 'FFCC00']],
|
|
'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER, 'wrapText' => true],
|
|
'borders' => ['allBorders' => ['borderStyle' => Border::BORDER_THIN]],
|
|
]);
|
|
$sheet->getRowDimension(4)->setRowHeight(30);
|
|
|
|
// Fetch attendance data for the whole year
|
|
$attendanceData = [];
|
|
$attendance = AttendanceHistoryDaily::where('id_class', $classId)
|
|
->whereYear('created_at', $tahun)
|
|
->get();
|
|
|
|
foreach ($attendance as $att) {
|
|
$date = \Carbon\Carbon::parse($att->created_at);
|
|
$month = $date->month;
|
|
$studentId = $att->id_student;
|
|
$status = $att->status;
|
|
|
|
if (!isset($attendanceData[$studentId])) {
|
|
$attendanceData[$studentId] = [];
|
|
}
|
|
if (!isset($attendanceData[$studentId][$month])) {
|
|
$attendanceData[$studentId][$month] = [
|
|
'tepat_waktu' => 0,
|
|
'terlambat' => 0,
|
|
'izin' => 0
|
|
];
|
|
}
|
|
if (in_array($status, ['tepat_waktu', 'terlambat', 'izin'])) {
|
|
$attendanceData[$studentId][$month][$status]++;
|
|
}
|
|
}
|
|
|
|
// Add student rows
|
|
$dataRow = 5;
|
|
foreach ($students as $student) {
|
|
$sheet->setCellValue('A' . $dataRow, $student->name);
|
|
$sheet->setCellValue('B' . $dataRow, $kelasName);
|
|
|
|
$totalTepatWaktu = 0;
|
|
$totalTerlambat = 0;
|
|
$totalIzin = 0;
|
|
|
|
// Populate months (C to N)
|
|
for ($month = 1; $month <= 12; $month++) {
|
|
$colLetter = $this->getColumnLetter($month + 2); // C = 3
|
|
|
|
$tw = 0; $tl = 0; $i = 0;
|
|
if (isset($attendanceData[$student->id][$month])) {
|
|
$tw = $attendanceData[$student->id][$month]['tepat_waktu'] ?? 0;
|
|
$tl = $attendanceData[$student->id][$month]['terlambat'] ?? 0;
|
|
$i = $attendanceData[$student->id][$month]['izin'] ?? 0;
|
|
}
|
|
|
|
$totalTepatWaktu += $tw;
|
|
$totalTerlambat += $tl;
|
|
$totalIzin += $i;
|
|
|
|
if ($tw > 0 || $tl > 0 || $i > 0) {
|
|
$displayText = "TW:{$tw}\nTL:{$tl}\nI:{$i}";
|
|
$sheet->setCellValue($colLetter . $dataRow, $displayText);
|
|
$sheet->getStyle($colLetter . $dataRow)->getAlignment()->setWrapText(true);
|
|
} else {
|
|
$sheet->setCellValue($colLetter . $dataRow, '-');
|
|
}
|
|
$sheet->getStyle($colLetter . $dataRow)->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
|
|
}
|
|
|
|
// Populate totals
|
|
$sheet->setCellValue('O' . $dataRow, $totalTepatWaktu);
|
|
$sheet->setCellValue('P' . $dataRow, $totalTerlambat);
|
|
$sheet->setCellValue('Q' . $dataRow, $totalIzin);
|
|
|
|
for ($c = 15; $c <= 17; $c++) {
|
|
$colLetter = $this->getColumnLetter($c);
|
|
$sheet->getStyle($colLetter . $dataRow)->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
|
|
}
|
|
|
|
// Border styling
|
|
$dataRange = 'A' . $dataRow . ':Q' . $dataRow;
|
|
$sheet->getStyle($dataRange)->applyFromArray([
|
|
'borders' => ['allBorders' => ['borderStyle' => Border::BORDER_THIN]],
|
|
'alignment' => ['vertical' => Alignment::VERTICAL_CENTER],
|
|
]);
|
|
|
|
// Set height for dynamic wrapped text
|
|
$sheet->getRowDimension($dataRow)->setRowHeight(45);
|
|
|
|
$dataRow++;
|
|
}
|
|
|
|
// Add legend
|
|
$legendRow = $dataRow + 2;
|
|
$sheet->setCellValue('A' . $legendRow, 'Keterangan format bulanan:');
|
|
$sheet->getStyle('A' . $legendRow)->applyFromArray(['font' => ['bold' => true, 'size' => 11]]);
|
|
|
|
$legendRow++;
|
|
$legends = [
|
|
'TW' => 'Tepat Waktu',
|
|
'TL' => 'Terlambat',
|
|
'I' => 'Izin'
|
|
];
|
|
|
|
foreach ($legends as $code => $meaning) {
|
|
$sheet->setCellValue('A' . $legendRow, $code);
|
|
$sheet->setCellValue('B' . $legendRow, $meaning);
|
|
$sheet->getStyle('A' . $legendRow)->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
|
|
$legendRow++;
|
|
}
|
|
|
|
// Set column widths
|
|
$sheet->getColumnDimension('A')->setWidth(25);
|
|
$sheet->getColumnDimension('B')->setWidth(15);
|
|
|
|
// Month columns width
|
|
for ($month = 1; $month <= 12; $month++) {
|
|
$colLetter = $this->getColumnLetter($month + 2);
|
|
$sheet->getColumnDimension($colLetter)->setWidth(10);
|
|
}
|
|
|
|
$sheet->getColumnDimension('O')->setWidth(15);
|
|
$sheet->getColumnDimension('P')->setWidth(12);
|
|
$sheet->getColumnDimension('Q')->setWidth(12);
|
|
|
|
// Save and download
|
|
$writer = new Xlsx($spreadsheet);
|
|
$tempPath = storage_path('app/temp/' . $filename);
|
|
@mkdir(dirname($tempPath), 0755, true);
|
|
$writer->save($tempPath);
|
|
|
|
return response()->download($tempPath)->deleteFileAfterSend(true);
|
|
}
|
|
|
|
/**
|
|
* Convert column number to letter (1->A, 2->B, etc)
|
|
*/
|
|
private function getColumnLetter($col)
|
|
{
|
|
$letter = '';
|
|
while ($col > 0) {
|
|
$col--;
|
|
$letter = chr(65 + ($col % 26)) . $letter;
|
|
$col = intdiv($col, 26);
|
|
}
|
|
return $letter;
|
|
}
|
|
|
|
/**
|
|
* Helper method untuk prepare data export absensi harian
|
|
*/
|
|
private function getAbsensiHarianRowsForExport($classId, Request $request)
|
|
{
|
|
// Get kelas
|
|
$kelas = Classes::findOrFail($classId);
|
|
|
|
// Get semua siswa di kelas
|
|
$students = Student::where('id_class', $classId)->get();
|
|
|
|
// Determine filter parameters
|
|
$tanggal = $request->get('tanggal');
|
|
$bulan = $request->get('bulan');
|
|
$tahun = $request->get('tahun');
|
|
|
|
// Default ke hari ini hanya jika tidak ada filter apapun
|
|
if (!$tanggal && !$bulan && !$tahun) {
|
|
$tanggal = now()->format('Y-m-d');
|
|
}
|
|
|
|
// Build query untuk fetch attendance records
|
|
$query = AttendanceHistoryDaily::with(['student', 'class'])
|
|
->where('id_class', $classId);
|
|
|
|
// Jika tanggal diset, filter by exact date
|
|
if ($tanggal && !$bulan && !$tahun) {
|
|
$query->whereDate('created_at', $tanggal);
|
|
}
|
|
// Jika bulan dan tahun keduanya diset, filter by month AND year
|
|
else if ($bulan && $tahun) {
|
|
$query->whereMonth('created_at', $bulan)
|
|
->whereYear('created_at', $tahun);
|
|
}
|
|
// Jika hanya bulan diset, filter by month
|
|
else if ($bulan) {
|
|
$query->whereMonth('created_at', $bulan);
|
|
}
|
|
// Jika hanya tahun diset, filter by year
|
|
else if ($tahun) {
|
|
$query->whereYear('created_at', $tahun);
|
|
}
|
|
|
|
$absensi = $query->get();
|
|
|
|
// Get unique dates dari filtered data
|
|
$uniqueDates = $absensi
|
|
->map(function($item) { return $item->created_at->format('Y-m-d'); })
|
|
->unique()
|
|
->values()
|
|
->sort()
|
|
->reverse()
|
|
->values();
|
|
|
|
// Build rows untuk export: untuk setiap hari, untuk setiap siswa
|
|
$rows = [];
|
|
$no = 1;
|
|
|
|
foreach ($uniqueDates as $date) {
|
|
foreach ($students as $student) {
|
|
// Cari record untuk student + date ini
|
|
$record = $absensi
|
|
->where('id_student', $student->id)
|
|
->filter(function($item) use ($date) {
|
|
return $item->created_at->format('Y-m-d') === $date;
|
|
})
|
|
->first();
|
|
|
|
if ($record) {
|
|
// Ada record di database
|
|
$rows[] = [
|
|
'no' => $no,
|
|
'student_name' => $record->student->name ?? '-',
|
|
'nisn' => $record->student->nisn ?? '-',
|
|
'class_name' => $record->class->name ?? '-',
|
|
'status' => ucfirst($record->status),
|
|
'waktu' => $record->created_at->format('d M Y H:i:s'),
|
|
];
|
|
} else {
|
|
// Dummy record: siswa belum absen di hari ini
|
|
$rows[] = [
|
|
'no' => $no,
|
|
'student_name' => $student->name,
|
|
'nisn' => $student->nisn ?? '-',
|
|
'class_name' => $kelas->name,
|
|
'status' => 'In Progress',
|
|
'waktu' => '-',
|
|
];
|
|
}
|
|
|
|
$no++;
|
|
}
|
|
}
|
|
|
|
return $rows;
|
|
}
|
|
}
|