186 lines
7.6 KiB
PHP
186 lines
7.6 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use Illuminate\Http\Request;
|
|
use App\Models\Peminjaman;
|
|
use App\Models\Anggota;
|
|
use App\Models\Buku;
|
|
use Barryvdh\DomPDF\Facade\Pdf;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class PeminjamanController extends Controller
|
|
{
|
|
public function index(\Illuminate\Http\Request $request)
|
|
{
|
|
$search = $request->input('search');
|
|
|
|
$query = Peminjaman::with(['anggota', 'user', 'buku'])->latest();
|
|
|
|
if ($search) {
|
|
$searchTerm = strtolower($search);
|
|
$query->where(function ($q) use ($searchTerm) {
|
|
$q->whereHas('anggota', function ($qMember) use ($searchTerm) {
|
|
$qMember->whereRaw('LOWER(nama) LIKE ?', ["%{$searchTerm}%"]);
|
|
})->orWhereHas('buku', function ($qBuku) use ($searchTerm) {
|
|
$qBuku->whereRaw('LOWER(judul) LIKE ?', ["%{$searchTerm}%"]);
|
|
});
|
|
});
|
|
}
|
|
|
|
$peminjaman = $query->paginate(15)->appends(['search' => $search]);
|
|
$buku = Buku::where('eksemplar', '>', 0)->get();
|
|
$anggota = Anggota::all();
|
|
return view('admin.peminjaman.index', compact('peminjaman', 'buku', 'anggota', 'search'));
|
|
}
|
|
|
|
public function create()
|
|
{
|
|
$anggota = Anggota::all();
|
|
$bukus = Buku::all();
|
|
return view('admin.peminjaman.create', compact('anggota', 'bukus'));
|
|
}
|
|
|
|
public function store(Request $request)
|
|
{
|
|
// 1. Validasi input
|
|
$request->validate([
|
|
'id_anggota' => 'required|exists:anggotas,id',
|
|
'id_buku' => 'required|exists:buku,id_buku',
|
|
'tanggal_pinjam' => 'required|date',
|
|
'tanggal_kembali' => 'required|date|after_or_equal:tanggal_pinjam',
|
|
]);
|
|
|
|
// 2. Cek dan kurangi stok buku
|
|
$buku = Buku::findOrFail($request->id_buku);
|
|
if ($buku->eksemplar <= 0) {
|
|
return back()->withErrors(['id_buku' => 'Stok buku habis!'])->withInput();
|
|
}
|
|
$buku->decrement('eksemplar');
|
|
|
|
// 3. Simpan data peminjaman ke database
|
|
$peminjaman = Peminjaman::create([
|
|
'id_anggota' => $request->id_anggota,
|
|
'id_buku' => $request->id_buku,
|
|
'tanggal_pinjam' => $request->tanggal_pinjam,
|
|
'tanggal_kembali' => $request->tanggal_kembali,
|
|
'status_peminjaman' => 'Dipinjam',
|
|
]);
|
|
|
|
// Muat relasi untuk mendapatkan data anggota (seperti no_hp) dan buku untuk keperluan struk PDF
|
|
$peminjaman->load(['anggota', 'buku']);
|
|
|
|
$waSuccess = false;
|
|
|
|
// 4. Proses render PDF & Kirim Fonnte dengan Exception Handling
|
|
try {
|
|
// Tentukan direktori penyimpanan sementara (temp)
|
|
$tempDir = storage_path('app/public/temp');
|
|
|
|
// Jika foldernya belum ada, buat foldernya terlebih dahulu.
|
|
if (!file_exists($tempDir)) {
|
|
mkdir($tempDir, 0755, true);
|
|
}
|
|
|
|
// Buat nama file unik (agar tidak masalah saat request bersamaan)
|
|
$fileName = 'struk_peminjaman_' . $peminjaman->id . '_' . time() . '.pdf';
|
|
$filePath = $tempDir . '/' . $fileName;
|
|
|
|
// Generate dokumen PDF dari view yang sudah ada
|
|
$pdf = Pdf::loadView('admin.peminjaman.struk', compact('peminjaman'));
|
|
|
|
// Simpan PDF sementara
|
|
$pdf->save($filePath);
|
|
|
|
// Dapatkan nomor handphone pendaftar & Fonnte Token
|
|
$targetNum = $peminjaman->anggota->no_hp ?? '';
|
|
$fonnteToken = 'vpzqxF2ZGgTGz9F5UbUS'; // Token Fonnte
|
|
|
|
// Standarisasi Format Nomor ke awalan 62 (Kode Internasional Indonesia) standar yang dianjurkan Fonnte
|
|
if (!empty($targetNum)) {
|
|
$targetNum = preg_replace('/^0/', '62', trim($targetNum));
|
|
}
|
|
|
|
|
|
// Jika token terisi & nomor HP valid, jalankan request ke service API Fonnte
|
|
if (!empty($targetNum) && !empty($fonnteToken)) {
|
|
// Gunakan attach() untuk menyisipkan file PDF dari folder temp
|
|
$response = Http::withoutVerifying()->timeout(15)->withHeaders([
|
|
'Authorization' => $fonnteToken,
|
|
])->attach('file', file_get_contents($filePath), $fileName)->post('https://api.fonnte.com/send', [
|
|
'target' => $targetNum,
|
|
'message' => "Halo Kak *{$peminjaman->anggota->nama}*! 📚✨\n\nTerima kasih telah meminjam buku di *Perpustakaan Daerah Jember*.\n\nBersama pesan ini, kami lampirkan file e-Struk (PDF) untuk peminjaman buku:\n📖 Judul: _{$peminjaman->buku->judul}_\n📅 Batas Kembali: *{$peminjaman->tanggal_kembali}*\n\nMohon simpan dokumen PDF ini sebagai bukti transaksi yang sah. Harap kembalikan buku tepat waktu untuk menghindari denda keterlambatan.\n\nSelamat menikmati waktu membaca Anda!\n\nSalam Literasi,\n*Sistem Sarakata Jember*"
|
|
]);
|
|
|
|
// Cek respon resmi fonnte API
|
|
if ($response->successful() && ($response->json('status') == true)) {
|
|
$waSuccess = true;
|
|
} else {
|
|
\Illuminate\Support\Facades\Log::warning("Fonnte Log: Gagal Terkirim", ['body' => $response->body()]);
|
|
}
|
|
} else {
|
|
Log::warning('Fonnte Log: Token / No HP kosong (Pesan tidak diproses).');
|
|
}
|
|
|
|
// 5. Cleanup Darurat File PDF Secara Otomatis
|
|
if (file_exists($filePath)) {
|
|
unlink($filePath);
|
|
}
|
|
} catch (\Exception $e) {
|
|
// Bila error (misal: memori PDF kurang, library dompdf crash, timeout dari Fonnte)
|
|
// Error ditangkap agar sistem tidak langsung menampilkan layar error 500 ke User.
|
|
Log::error("Error PDF/WA Pengiriman: " . $e->getMessage());
|
|
|
|
// Pembersihan ekstra bila error terjadi saat file sudah diciptakan di temp folder, tapi belum dieksekusi unlink di dalam block atas.
|
|
if (isset($filePath) && file_exists($filePath)) {
|
|
unlink($filePath);
|
|
}
|
|
}
|
|
|
|
// Notifikasi Balikan Final ke User
|
|
$alertSuccessMessage = 'Transaksi peminjaman berhasil direkap.';
|
|
$alertSuccessMessage .= $waSuccess ? ' Struk WA berhasil terkirim kepada Anggota.' : ' (Namun e-Struk belum sempat terkirim via WA, silakan cek Logs).';
|
|
|
|
return redirect()->route('admin.peminjaman.index')->with('success', $alertSuccessMessage);
|
|
}
|
|
public function kembali(Peminjaman $peminjaman)
|
|
{
|
|
$tglTenggat = \Carbon\Carbon::parse($peminjaman->tanggal_kembali)->startOfDay();
|
|
$tglSekarang = \Carbon\Carbon::now()->startOfDay();
|
|
|
|
$denda = 0;
|
|
if ($tglSekarang->gt($tglTenggat)) {
|
|
$selisihHari = $tglSekarang->diffInDays($tglTenggat);
|
|
$denda = $selisihHari * 1000;
|
|
}
|
|
|
|
$peminjaman->update([
|
|
'status_peminjaman' => 'Dikembalikan',
|
|
'tanggal_dikembalikan' => now(),
|
|
'denda' => $denda
|
|
]);
|
|
|
|
if ($peminjaman->buku) {
|
|
$peminjaman->buku->increment('eksemplar');
|
|
}
|
|
|
|
$pesan = 'Buku berhasil dikembalikan.';
|
|
if ($denda > 0) {
|
|
$pesan .= ' Denda keterlambatan Rp ' . number_format($denda, 0, ',', '.');
|
|
}
|
|
|
|
return back()->with('success', $pesan);
|
|
}
|
|
|
|
public function indexPengembalian()
|
|
{
|
|
$pengembalian = Peminjaman::where('status_peminjaman', 'Dikembalikan')
|
|
->with(['anggota', 'user', 'buku'])
|
|
->orderBy('tanggal_kembali', 'desc')
|
|
->paginate(10);
|
|
|
|
return view('admin.peminjaman.pengembalian', compact('pengembalian'));
|
|
}
|
|
}
|