orderBy('created_at', 'desc') ->get(); return view('admin.peminjaman', compact('transactions')); } public function cetakNota($id) { $transaction = BorrowTransaction::with(['anggota', 'koleksi'])->findOrFail($id); return view('admin.peminjaman.nota', compact('transaction')); } public function downloadSuratPengantar($id) { $transaction = BorrowTransaction::findOrFail($id); if (!$transaction->surat_pengantar) { return back()->with('error', 'File surat pengantar tidak tersedia.'); } $filePath = 'public/surat_pengantar/' . $transaction->surat_pengantar; if (!Storage::exists($filePath)) { return back()->with('error', 'File surat pengantar tidak ditemukan.'); } return Storage::download($filePath, $transaction->surat_pengantar); } public function setujui(Request $request, $id) { $transaction = BorrowTransaction::with('anggota.user')->findOrFail($id); if (!in_array($transaction->status, ['menunggu', 'pending'])) { return redirect()->back()->with('error', 'Transaksi ini sudah diproses.'); } // 🔥 CEK LIMIT PINJAMAN $jumlahPinjaman = BorrowTransaction::where('anggota_id', $transaction->anggota_id) ->whereIn('status', ['dipinjam', 'disetujui', 'pengembalian_menunggu']) ->count(); if ($jumlahPinjaman >= 2) { return redirect()->back()->with('error', 'Anggota sudah mencapai batas maksimal peminjaman (2 buku).'); } $request->validate([ 'pickup_date' => 'required|date', 'pickup_time' => 'required', 'tanggal_kembali' => 'nullable|date|after_or_equal:pickup_date', ]); $tanggalKembali = $request->tanggal_kembali ? Carbon::parse($request->tanggal_kembali) : Carbon::parse($request->pickup_date)->addDays(7); // Update Data $transaction->update([ 'pickup_date' => $request->pickup_date, 'pickup_time' => $request->pickup_time, 'tanggal_kembali' => $tanggalKembali, 'status' => 'disetujui' ]); IotMode::query()->update([ 'mode' => 'user', 'updated_at' => now() ]); // 📧 PROSES KIRIM EMAIL // Pastikan relasi ke user benar untuk mengambil email $recipientEmail = $transaction->anggota->user->email ?? $transaction->anggota->email; if ($recipientEmail) { try { Mail::to($recipientEmail)->send(new BukuSiapDiambilMail($transaction)); } catch (\Exception $e) { Log::error('Gagal kirim email BukuSiapDiambil: ' . $e->getMessage()); // Tetap lanjut meskipun email gagal agar status di DB tersimpan } } return redirect()->route('admin.peminjaman')->with('success', 'Peminjaman disetujui dan email notifikasi dikirim.'); } public function ambilBuku($id) { $transaction = BorrowTransaction::findOrFail($id); if ($transaction->status !== 'disetujui') { return redirect()->route('admin.peminjaman')->with('error', 'Buku belum disetujui atau sudah diambil.'); } $transaction->markAsDipinjam(); IotMode::query()->update([ 'mode' => 'standby', 'updated_at' => now() ]); return redirect()->route('admin.peminjaman')->with('success', 'Buku berhasil diambil.'); } public function tolak($id) { $transaction = BorrowTransaction::with('anggota.user')->findOrFail($id); if (!in_array($transaction->status, ['menunggu', 'pending'])) { return redirect()->back()->with('error', 'Transaksi ini sudah diproses.'); } $transaction->markAsDitolak(); $recipientEmail = $transaction->anggota->user->email ?? $transaction->anggota->email; if ($recipientEmail) { try { Mail::to($recipientEmail)->send(new PeminjamanDitolakMail($transaction)); } catch (\Exception $e) { Log::error('Gagal kirim email PeminjamanDitolak: ' . $e->getMessage()); } } return redirect()->route('admin.peminjaman')->with('success', 'Peminjaman ditolak.'); } public function setujuiPerpanjangan(Request $request, $id) { $transaction = BorrowTransaction::with('anggota.user')->findOrFail($id); if ($transaction->status !== 'perpanjangan_menunggu') { return back()->with('error', 'Permohonan perpanjangan tidak ditemukan.'); } // Jika Admin input tanggal di modal, gunakan itu. Jika tidak, tambah 7 hari dari tanggal kembali lama. $newTanggalKembali = $request->tanggal_kembali ? Carbon::parse($request->tanggal_kembali) : Carbon::parse($transaction->tanggal_kembali)->addDays(7); $transaction->update([ 'tanggal_kembali' => $newTanggalKembali, 'status' => 'dipinjam' ]); $recipientEmail = $transaction->anggota->user->email ?? $transaction->anggota->email; if ($recipientEmail) { try { Mail::to($recipientEmail)->send(new PerpanjanganDisetujuiMail($transaction)); } catch (\Exception $e) { Log::error('Gagal kirim email PerpanjanganDisetujui: ' . $e->getMessage()); } } return back()->with('success', 'Perpanjangan disetujui.'); } public function tolakPerpanjangan($id) { $transaction = BorrowTransaction::with('anggota.user')->findOrFail($id); if ($transaction->status !== 'perpanjangan_menunggu') { return back()->with('error', 'Permohonan tidak valid.'); } $transaction->update(['status' => 'dipinjam']); $recipientEmail = $transaction->anggota->user->email ?? $transaction->anggota->email; if ($recipientEmail) { try { Mail::to($recipientEmail)->send(new PerpanjanganDitolakMail($transaction)); } catch (\Exception $e) { Log::error('Gagal kirim email PerpanjanganDitolak: ' . $e->getMessage()); } } return back()->with('success', 'Perpanjangan ditolak.'); } public function kembalikan($id) { $transaction = BorrowTransaction::with('anggota.user')->findOrFail($id); if (!in_array($transaction->status, ['dipinjam', 'pengembalian_menunggu'])) { return redirect()->route('admin.peminjaman')->with('error', 'Status tidak valid untuk dikembalikan.'); } $transaction->markAsDikembalikan(); $recipientEmail = $transaction->anggota->user->email ?? $transaction->anggota->email; if ($recipientEmail) { try { Mail::to($recipientEmail)->send(new BukuDikembalikanMail($transaction)); } catch (\Exception $e) { Log::error('Gagal kirim email BukuDikembalikan: ' . $e->getMessage()); } } return redirect()->route('admin.peminjaman')->with('success', 'Buku berhasil dikembalikan.'); } public function espScan(Request $request) { $uid = strtoupper($request->query('uid') ?? ''); $mode = $request->query('mode') ?? ''; if (!$uid) return response()->json(['status' => 'uid_kosong']); if ($mode !== 'user') return response()->json(['status' => 'mode_salah']); $anggota = DB::table('anggota')->where('uid', $uid)->first(); if (!$anggota) return response()->json(['status' => 'tidak_valid']); $jumlahPinjaman = BorrowTransaction::where('anggota_id', $anggota->id) ->whereIn('status', ['dipinjam', 'pengembalian_menunggu']) ->count(); if ($jumlahPinjaman >= 2) return response()->json(['status' => 'limit_tercapai']); $transaction = BorrowTransaction::where('anggota_id', $anggota->id) ->where('status', 'disetujui') ->first(); if (!$transaction) return response()->json(['status' => 'tidak_valid']); $transaction->markAsDipinjam(); IotMode::query()->update([ 'mode' => 'standby', 'updated_at' => now() ]); return response()->json(['status' => 'valid']); } // Tambahkan ini di PeminjamanController.php public function konfirmasiKembali() { try { // 1. Ambil data terakhir dari IotMode untuk tahu buku apa yang baru di-scan $iot = IotMode::first(); if (!$iot || !$iot->book_id) { return response()->json([ 'status' => 'error', 'message' => 'Data buku tidak ditemukan di sistem IoT' ], 404); } // 2. Cari transaksi yang statusnya 'dipinjam' atau 'pengembalian_menunggu' berdasarkan buku tersebut $transaction = BorrowTransaction::with('anggota.user') ->where('koleksi_id', $iot->book_id) // Pastikan kolom ini sesuai dengan di DB Anda ->whereIn('status', ['dipinjam', 'pengembalian_menunggu']) ->first(); if (!$transaction) { return response()->json([ 'status' => 'error', 'message' => 'Transaksi aktif untuk buku ini tidak ditemukan' ], 404); } // 3. Proses Pengembalian (Memakai fungsi yang sudah Anda punya di model) $transaction->markAsDikembalikan(); // 4. Reset IotMode ke standby IotMode::query()->update([ 'mode' => 'standby', 'book_id' => null, // Bersihkan ID buku agar tidak terbaca lagi 'updated_at' => now() ]); // 5. Kirim Email (Opsional, memakai logika yang sama dengan fungsi kembalikan manual) $recipientEmail = $transaction->anggota->user->email ?? $transaction->anggota->email; if ($recipientEmail) { try { Mail::to($recipientEmail)->send(new BukuDikembalikanMail($transaction)); } catch (\Exception $e) { Log::error('Gagal kirim email: ' . $e->getMessage()); } } // 6. WAJIB: Kirim balasan JSON agar JS tidak error return response()->json([ 'status' => 'berhasil_kembali', 'message' => 'Buku ' . $transaction->koleksi->judul . ' berhasil dikembalikan' ]); } catch (\Exception $e) { Log::error('Error Konfirmasi Kembali: ' . $e->getMessage()); return response()->json([ 'status' => 'error', 'message' => 'Terjadi kesalahan internal: ' . $e->getMessage() ], 500); } } }