334 lines
12 KiB
PHP
334 lines
12 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Admin;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Book;
|
|
use App\Models\Loan;
|
|
use App\Models\User;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class AdminPeminjamanController extends Controller
|
|
{
|
|
public function index(Request $request)
|
|
{
|
|
$loans = Loan::with(['user', 'book'])
|
|
->whereIn('status', ['Dipinjam', 'Terlambat'])
|
|
->get();
|
|
|
|
$groupedLoans = $loans->groupBy('user_id');
|
|
|
|
$peminjamanAktif = $groupedLoans->map(function ($userLoans, $userId) {
|
|
$user = $userLoans->first()->user;
|
|
$firstLoan = $userLoans->first();
|
|
|
|
return [
|
|
'id_peminjaman' => 'PIN-ADM-'.sprintf('%03d', $userId),
|
|
'user_id' => $userId,
|
|
'peminjam' => $user->nama_lengkap ?? 'Unknown',
|
|
'nomor_hp' => $user->phone ?? '-',
|
|
'tanggal_pinjam' => $firstLoan->borrowed_at,
|
|
'tenggat_kembali' => $firstLoan->due_at,
|
|
'status' => $firstLoan->status,
|
|
'role' => $user->role,
|
|
'books' => $userLoans->map(fn ($l) => [
|
|
'id' => $l->book->id,
|
|
'judul' => $l->book->judul,
|
|
'cover' => $l->book->cover,
|
|
])->toArray(),
|
|
];
|
|
})->values();
|
|
|
|
$daftarPeminjam = $peminjamanAktif->pluck('peminjam')->unique();
|
|
|
|
return view('admin.peminjaman.index', [
|
|
'pageTitle' => 'Manajemen Peminjaman',
|
|
'peminjamanAktif' => $peminjamanAktif,
|
|
'daftarPeminjam' => $daftarPeminjam,
|
|
]);
|
|
}
|
|
|
|
public function create()
|
|
{
|
|
$users = User::whereIn('role', ['siswa', 'guru'])->get();
|
|
|
|
$groupedUsers = $users->map(function ($user) {
|
|
$jumlahPinjam = Loan::where('user_id', $user->id)
|
|
->whereIn('status', ['Dipinjam', 'Terlambat'])
|
|
->count();
|
|
|
|
$user->jumlah_pinjam = $jumlahPinjam;
|
|
$user->kena_limit = $jumlahPinjam >= 2;
|
|
$user->disabled = $user->kena_limit || $user->is_banned;
|
|
|
|
if ($user->is_banned) {
|
|
$user->status_text = '(Akun Dibekukan)';
|
|
} elseif ($user->kena_limit) {
|
|
$user->status_text = '(Limit Penuh: 2/2)';
|
|
} else {
|
|
$user->status_text = '';
|
|
}
|
|
|
|
return $user;
|
|
})->groupBy('role');
|
|
|
|
$daftarBuku = Book::where('status', 'Tersedia')
|
|
->whereJsonContains('tipe_akses', 'offline')
|
|
->where('stok', '>', 0)
|
|
->get();
|
|
|
|
return view('admin.peminjaman.create', [
|
|
'pageTitle' => 'Buat Peminjaman Manual',
|
|
'groupedUsers' => $groupedUsers,
|
|
'daftarBuku' => $daftarBuku,
|
|
]);
|
|
}
|
|
|
|
public function store(Request $request)
|
|
{
|
|
$validated = $request->validate([
|
|
'peminjam_id' => 'required|exists:users,id',
|
|
'tanggal_pinjam' => 'required|date',
|
|
'tanggal_kembali' => 'required|date|after:tanggal_pinjam',
|
|
'buku_ids' => 'required|array|min:1|max:2',
|
|
'buku_ids.*' => 'exists:books,id',
|
|
]);
|
|
|
|
\DB::beginTransaction();
|
|
try {
|
|
foreach ($validated['buku_ids'] as $bookId) {
|
|
$book = Book::findOrFail($bookId);
|
|
|
|
// Check if book is available
|
|
if ($book->status !== 'Tersedia') {
|
|
throw new \Exception("Buku '{$book->judul}' tidak tersedia.");
|
|
}
|
|
|
|
// Check stock
|
|
if ($book->stok <= 0) {
|
|
throw new \Exception("Buku '{$book->judul}' stok habis.");
|
|
}
|
|
|
|
// Create loan record
|
|
Loan::create([
|
|
'user_id' => $validated['peminjam_id'],
|
|
'book_id' => $bookId,
|
|
'loan_code' => 'LOAN-'.date('Ymd').'-'.strtoupper(substr(md5(uniqid()), 0, 6)),
|
|
'borrowed_at' => $validated['tanggal_pinjam'],
|
|
'due_at' => $validated['tanggal_kembali'],
|
|
'status' => 'Dipinjam',
|
|
]);
|
|
|
|
// Update book status and decrement stock
|
|
$book->update([
|
|
'status' => 'Dipinjam',
|
|
'stok' => $book->stok - 1,
|
|
]);
|
|
}
|
|
|
|
\DB::commit();
|
|
|
|
return redirect()->route('admin.peminjaman.index')->with('success', 'Peminjaman berhasil dibuat.');
|
|
} catch (\Exception $e) {
|
|
\DB::rollBack();
|
|
|
|
return back()->withErrors(['error' => $e->getMessage()])->withInput();
|
|
}
|
|
}
|
|
|
|
public function export(Request $request)
|
|
{
|
|
$request->validate([
|
|
'bulan_laporan' => 'nullable|date',
|
|
]);
|
|
|
|
$query = Loan::with(['user', 'book'])->orderBy('borrowed_at', 'asc');
|
|
|
|
if ($request->filled('bulan_laporan')) {
|
|
$date = Carbon::parse($request->bulan_laporan);
|
|
$query->whereMonth('borrowed_at', $date->month)
|
|
->whereYear('borrowed_at', $date->year);
|
|
$fileName = 'Laporan_Peminjaman_'.$date->format('Y-m').'.csv';
|
|
} else {
|
|
$fileName = 'Laporan_Peminjaman_Semua.csv';
|
|
}
|
|
|
|
$loans = $query->get();
|
|
|
|
$headers = [
|
|
"Content-type" => "text/csv",
|
|
"Content-Disposition" => "attachment; filename=$fileName",
|
|
"Pragma" => "no-cache",
|
|
"Cache-Control" => "must-revalidate, post-check=0, pre-check=0",
|
|
"Expires" => "0"
|
|
];
|
|
|
|
$columns = ['NO', 'ID PEMINJAMAN', 'PEMINJAM', 'ROLE', 'JUDUL BUKU', 'TGL PINJAM', 'T tenggat KEMBALI', 'STATUS', 'DENDA KETERLAMBATAN'];
|
|
|
|
$callback = function() use($loans, $columns) {
|
|
$file = fopen('php://output', 'w');
|
|
fputcsv($file, $columns);
|
|
|
|
$i = 1;
|
|
foreach ($loans as $loan) {
|
|
$row['NO'] = $i++;
|
|
$row['ID_PEMINJAMAN'] = $loan->loan_code;
|
|
$row['PEMINJAM'] = $loan->user->nama_lengkap ?? 'Unknown';
|
|
$row['ROLE'] = $loan->user->role ?? '-';
|
|
$row['JUDUL_BUKU'] = $loan->book->judul ?? 'Unknown';
|
|
$row['TGL_PINJAM'] = $loan->borrowed_at->format('d/m/Y');
|
|
$row['TENGGAT_KEMBALI'] = $loan->due_at ? $loan->due_at->format('d/m/Y') : '-';
|
|
$row['STATUS'] = $loan->status;
|
|
$row['DENDA'] = $loan->fine_overdue ?? 0;
|
|
|
|
fputcsv($file, array_values($row));
|
|
}
|
|
|
|
fclose($file);
|
|
};
|
|
|
|
return response()->stream($callback, 200, $headers);
|
|
}
|
|
|
|
public function dendaIndex()
|
|
{
|
|
$now = Carbon::now();
|
|
|
|
// Fetch all loans that are overdue or users that are banned
|
|
$loans = Loan::with(['user', 'book'])
|
|
->where(function ($query) use ($now) {
|
|
$query->where('due_at', '<', $now)
|
|
->whereIn('status', ['Dipinjam', 'Terlambat']);
|
|
})
|
|
->orWhereHas('user', function ($query) {
|
|
$query->where('is_banned', true);
|
|
})
|
|
->get();
|
|
|
|
$groupedLoans = $loans->groupBy('user_id');
|
|
|
|
$siswaTelat = $groupedLoans->map(function ($userLoans, $userId) use ($now) {
|
|
$user = $userLoans->first()->user;
|
|
$firstLoan = $userLoans->first();
|
|
|
|
$tenggat = Carbon::parse($firstLoan->due_at);
|
|
$hariTelat = $now->greaterThan($tenggat) ? (int) $tenggat->diffInDays($now) : 0;
|
|
|
|
$isGuru = $user->role === 'guru';
|
|
$totalDenda = $isGuru ? 0 : ($hariTelat * 1000);
|
|
|
|
// Link WA
|
|
$hp = $user->phone ?? '';
|
|
$waLink = '#';
|
|
if ($hp) {
|
|
if (substr($hp, 0, 1) == '0') {
|
|
$hp = '62'.substr($hp, 1);
|
|
}
|
|
|
|
if ($isGuru && $hariTelat > 0) {
|
|
$pesan = "Halo Bapak/Ibu {$user->nama_lengkap}, anda terlambat pengembalian buku selama {$hariTelat} hari. Mohon segera dikembalikan ke perpustakaan. Terima kasih.";
|
|
} else {
|
|
$pesan = $hariTelat > 0
|
|
? "Halo {$user->nama_lengkap}, anda terlambat pengembalian buku. Total Denda: Rp ".number_format($totalDenda, 0, ',', '.')
|
|
: "Halo {$user->nama_lengkap}, akun anda sedang dinonaktifkan sementara. Mohon hubungi petugas.";
|
|
}
|
|
|
|
$waLink = "https://wa.me/{$hp}?text=".urlencode($pesan);
|
|
}
|
|
|
|
return [
|
|
'id' => $firstLoan->id,
|
|
'user_id' => $userId,
|
|
'peminjam' => $user->nama_lengkap,
|
|
'nomor_hp' => $user->phone ?? '-',
|
|
'kelas' => $user->kelas ?? 'Guru',
|
|
'hari_terlambat' => $hariTelat,
|
|
'total_denda' => $totalDenda,
|
|
'is_guru' => $isGuru,
|
|
'wa_link' => $waLink,
|
|
'is_banned' => $user->is_banned,
|
|
'tenggat_kembali' => $firstLoan->due_at,
|
|
'books' => $userLoans->map(fn ($l) => [
|
|
'id' => $l->book->id,
|
|
'judul' => $l->book->judul,
|
|
])->toArray(),
|
|
];
|
|
})->values();
|
|
|
|
$listKelas = $siswaTelat->pluck('kelas')->unique()->values();
|
|
|
|
return view('admin.denda.index', [
|
|
'pageTitle' => 'Manajemen Denda & Sanksi',
|
|
'siswaTelat' => $siswaTelat,
|
|
'listKelas' => $listKelas,
|
|
]);
|
|
}
|
|
|
|
public function berikanSanksi(Request $request)
|
|
{
|
|
$validated = $request->validate([
|
|
'user_id' => 'required|exists:users,id',
|
|
'action' => 'required|in:ban,unban',
|
|
]);
|
|
|
|
$user = User::findOrFail($validated['user_id']);
|
|
$user->is_banned = ($validated['action'] === 'ban');
|
|
$user->save();
|
|
|
|
return response()->json([
|
|
'status' => 'success',
|
|
'message' => $user->is_banned ? "Akun {$user->nama_lengkap} berhasil dibekukan." : "Akun {$user->nama_lengkap} telah diaktifkan kembali.",
|
|
]);
|
|
}
|
|
|
|
public function kembalikan(Request $request)
|
|
{
|
|
$validated = $request->validate([
|
|
'user_id' => 'required|exists:users,id',
|
|
'returns' => 'required|array',
|
|
'returns.*.book_id' => 'required|exists:books,id',
|
|
'returns.*.condition' => 'required|string',
|
|
'returns.*.fine_damage' => 'required|integer',
|
|
'returns.*.fine_overdue' => 'required|integer',
|
|
'returns.*.notes' => 'nullable|string',
|
|
]);
|
|
|
|
\DB::beginTransaction();
|
|
try {
|
|
foreach ($validated['returns'] as $item) {
|
|
$loan = Loan::where('user_id', $validated['user_id'])
|
|
->where('book_id', $item['book_id'])
|
|
->whereIn('status', ['Dipinjam', 'Terlambat'])
|
|
->first();
|
|
|
|
if ($loan) {
|
|
$loan->update([
|
|
'status' => 'Dikembalikan',
|
|
'returned_at' => now(),
|
|
'condition' => $item['condition'],
|
|
'fine_damage' => $item['fine_damage'],
|
|
'fine_overdue' => $item['fine_overdue'],
|
|
'return_notes' => $item['notes'],
|
|
]);
|
|
|
|
// Update book status and increment stock
|
|
$loan->book->update([
|
|
'status' => 'Tersedia',
|
|
'stok' => $loan->book->stok + 1,
|
|
]);
|
|
}
|
|
}
|
|
|
|
\DB::commit();
|
|
|
|
return response()->json(['status' => 'success', 'message' => 'Buku berhasil dikembalikan.']);
|
|
} catch (\Exception $e) {
|
|
\DB::rollBack();
|
|
|
|
return response()->json(['status' => 'error', 'message' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
}
|