227 lines
9.0 KiB
PHP
227 lines
9.0 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\StudentGraduation;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Illuminate\Support\Str;
|
|
use Illuminate\View\View;
|
|
use RealRashid\SweetAlert\Facades\Alert;
|
|
|
|
class GraduationBulkUploadController extends Controller
|
|
{
|
|
public function index(Request $request): View
|
|
{
|
|
return view('graduated-students.bulk-upload', [
|
|
'preview' => $request->session()->get('graduation_bulk_upload_preview'),
|
|
'documentTypes' => [
|
|
'skl' => 'SKL',
|
|
'ijazah' => 'Ijazah',
|
|
'transcript' => 'Transkrip Nilai',
|
|
'ukk-certificate' => 'Sertifikat UKK',
|
|
'lsp-certificate' => 'Sertifikat LSP',
|
|
],
|
|
'matchByOptions' => [
|
|
'student_number' => 'NIS',
|
|
'nisn' => 'NISN',
|
|
],
|
|
]);
|
|
}
|
|
|
|
public function preview(Request $request): RedirectResponse
|
|
{
|
|
$preview = $this->buildPreviewPayload($request);
|
|
|
|
return $preview;
|
|
}
|
|
|
|
public function previewAjax(Request $request): JsonResponse
|
|
{
|
|
$preview = $this->buildPreviewPayload($request);
|
|
|
|
$request->session()->put('graduation_bulk_upload_preview', $preview);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'redirect_url' => route('graduated-students.bulk-upload.index'),
|
|
'summary' => $preview['summary'],
|
|
'message' => 'Preview bulk upload berhasil disiapkan.',
|
|
]);
|
|
}
|
|
|
|
protected function buildPreviewPayload(Request $request): array
|
|
{
|
|
$validated = $request->validate([
|
|
'document_type' => ['required', 'in:skl,ijazah,transcript,ukk-certificate,lsp-certificate'],
|
|
'match_by' => ['required', 'in:student_number,nisn'],
|
|
'documents' => ['required', 'array', 'min:1', 'max:10'],
|
|
'documents.*' => ['required', 'file', 'mimes:pdf,jpg,jpeg,png', 'max:4096'],
|
|
], [
|
|
'documents.required' => 'Pilih minimal satu file dokumen untuk dipreview.',
|
|
'documents.max' => 'Maksimal 10 file per batch upload.',
|
|
'documents.*.mimes' => 'Dokumen hanya boleh berupa PDF, JPG, JPEG, atau PNG.',
|
|
'documents.*.max' => 'Ukuran tiap dokumen maksimal 4 MB.',
|
|
]);
|
|
|
|
$graduations = StudentGraduation::query()->get()->keyBy($validated['match_by']);
|
|
$rows = [];
|
|
$summary = [
|
|
'total_files' => 0,
|
|
'matched' => 0,
|
|
'unmatched' => 0,
|
|
'will_replace' => 0,
|
|
'ready_to_upload' => 0,
|
|
];
|
|
|
|
foreach ($request->file('documents', []) as $file) {
|
|
$summary['total_files']++;
|
|
|
|
$originalName = $file->getClientOriginalName();
|
|
$baseName = pathinfo($originalName, PATHINFO_FILENAME);
|
|
$normalizedKey = trim($baseName);
|
|
$graduation = $graduations->get($normalizedKey);
|
|
$existingPathField = [
|
|
'skl' => 'skl_file_path',
|
|
'ijazah' => 'ijazah_file_path',
|
|
'transcript' => 'transcript_file_path',
|
|
'ukk-certificate' => 'ukk_certificate_file_path',
|
|
'lsp-certificate' => 'lsp_certificate_file_path',
|
|
][$validated['document_type']];
|
|
|
|
$storedTempPath = $file->store('temp/graduation-bulk-upload', 'public');
|
|
|
|
$row = [
|
|
'original_name' => $originalName,
|
|
'stored_temp_path' => $storedTempPath,
|
|
'mime_type' => $file->getMimeType(),
|
|
'file_size' => $file->getSize(),
|
|
'match_key' => $normalizedKey,
|
|
'graduation_id' => $graduation?->id,
|
|
'student_name' => $graduation?->full_name,
|
|
'identifier_value' => $graduation?->{$validated['match_by']},
|
|
'status' => $graduation ? 'matched' : 'unmatched',
|
|
'will_replace' => $graduation ? filled($graduation->{$existingPathField}) : false,
|
|
];
|
|
|
|
if ($graduation) {
|
|
$summary['matched']++;
|
|
$summary['ready_to_upload']++;
|
|
|
|
if ($row['will_replace']) {
|
|
$summary['will_replace']++;
|
|
}
|
|
} else {
|
|
$summary['unmatched']++;
|
|
}
|
|
|
|
$rows[] = $row;
|
|
}
|
|
|
|
$preview = [
|
|
'token' => (string) Str::uuid(),
|
|
'document_type' => $validated['document_type'],
|
|
'document_label' => [
|
|
'skl' => 'SKL',
|
|
'ijazah' => 'Ijazah',
|
|
'transcript' => 'Transkrip Nilai',
|
|
'ukk-certificate' => 'Sertifikat UKK',
|
|
'lsp-certificate' => 'Sertifikat LSP',
|
|
][$validated['document_type']],
|
|
'match_by' => $validated['match_by'],
|
|
'match_by_label' => $validated['match_by'] === 'student_number' ? 'NIS' : 'NISN',
|
|
'rows' => $rows,
|
|
'summary' => $summary,
|
|
];
|
|
|
|
return $preview;
|
|
}
|
|
|
|
public function store(Request $request): RedirectResponse
|
|
{
|
|
$request->validate([
|
|
'preview_token' => ['required', 'string'],
|
|
]);
|
|
|
|
$preview = $request->session()->get('graduation_bulk_upload_preview');
|
|
|
|
if (! $preview || ($preview['token'] ?? null) !== $request->string('preview_token')->value()) {
|
|
return back()->withErrors([
|
|
'preview_token' => 'Preview bulk upload sudah tidak valid. Silakan upload ulang dokumen.',
|
|
]);
|
|
}
|
|
|
|
$documentType = $preview['document_type'];
|
|
$documentConfig = [
|
|
'skl' => ['name' => 'skl_file_name', 'path' => 'skl_file_path', 'mime' => 'skl_mime_type', 'size' => 'skl_file_size'],
|
|
'ijazah' => ['name' => 'ijazah_file_name', 'path' => 'ijazah_file_path', 'mime' => 'ijazah_mime_type', 'size' => 'ijazah_file_size'],
|
|
'transcript' => ['name' => 'transcript_file_name', 'path' => 'transcript_file_path', 'mime' => 'transcript_mime_type', 'size' => 'transcript_file_size'],
|
|
'ukk-certificate' => ['name' => 'ukk_certificate_file_name', 'path' => 'ukk_certificate_file_path', 'mime' => 'ukk_certificate_mime_type', 'size' => 'ukk_certificate_file_size'],
|
|
'lsp-certificate' => ['name' => 'lsp_certificate_file_name', 'path' => 'lsp_certificate_file_path', 'mime' => 'lsp_certificate_mime_type', 'size' => 'lsp_certificate_file_size'],
|
|
][$documentType];
|
|
|
|
$fileNameField = $documentConfig['name'];
|
|
$filePathField = $documentConfig['path'];
|
|
$mimeTypeField = $documentConfig['mime'];
|
|
$fileSizeField = $documentConfig['size'];
|
|
|
|
$processed = 0;
|
|
$skipped = 0;
|
|
|
|
DB::transaction(function () use ($preview, $documentType, $fileNameField, $filePathField, $mimeTypeField, $fileSizeField, &$processed, &$skipped) {
|
|
foreach ($preview['rows'] as $row) {
|
|
if (($row['status'] ?? null) !== 'matched' || empty($row['graduation_id'])) {
|
|
$skipped++;
|
|
continue;
|
|
}
|
|
|
|
$graduation = StudentGraduation::query()->find($row['graduation_id']);
|
|
|
|
if (! $graduation) {
|
|
$skipped++;
|
|
continue;
|
|
}
|
|
|
|
if (! Storage::disk('public')->exists($row['stored_temp_path'])) {
|
|
$skipped++;
|
|
continue;
|
|
}
|
|
|
|
if ($graduation->{$filePathField} && Storage::disk('public')->exists($graduation->{$filePathField})) {
|
|
Storage::disk('public')->delete($graduation->{$filePathField});
|
|
}
|
|
|
|
$extension = pathinfo($row['original_name'], PATHINFO_EXTENSION);
|
|
$finalPath = "student-graduation-documents/{$graduation->student_id}/{$documentType}/" . Str::uuid() . ($extension ? '.' . $extension : '');
|
|
Storage::disk('public')->move($row['stored_temp_path'], $finalPath);
|
|
|
|
$graduation->update([
|
|
$fileNameField => $row['original_name'],
|
|
$filePathField => $finalPath,
|
|
$mimeTypeField => $row['mime_type'],
|
|
$fileSizeField => $row['file_size'],
|
|
]);
|
|
|
|
$processed++;
|
|
}
|
|
});
|
|
|
|
foreach ($preview['rows'] as $row) {
|
|
if (! empty($row['stored_temp_path']) && Storage::disk('public')->exists($row['stored_temp_path'])) {
|
|
Storage::disk('public')->delete($row['stored_temp_path']);
|
|
}
|
|
}
|
|
|
|
$request->session()->forget('graduation_bulk_upload_preview');
|
|
|
|
Alert::success('Berhasil', "Bulk upload {$preview['document_label']} selesai. {$processed} dokumen diproses, {$skipped} dilewati.");
|
|
|
|
return redirect()
|
|
->route('graduated-students.bulk-upload.index')
|
|
->with('success', "Bulk upload {$preview['document_label']} selesai. {$processed} dokumen diproses, {$skipped} dilewati.");
|
|
}
|
|
}
|