Sistem Informasi Perpustakaan Berbasis Web

Sistem informasi perpustakaan adalah proyek klasik yang wajib dikuasai, tetapi banyak pemula menyederhanakannya terlalu jauh — misalnya hanya membuat CRUD buku tanpa mengurus keter...

Sistem Informasi Perpustakaan Berbasis Web

Sistem informasi perpustakaan adalah proyek klasik yang wajib dikuasai, tetapi banyak pemula menyederhanakannya terlalu jauh — misalnya hanya membuat CRUD buku tanpa mengurus ketersediaan, jatuh tempo, dan denda. Padahal justru di sanalah logika bisnis yang sesungguhnya. Tutorial ini membangun perpustakaan yang benar di Laravel 11 dengan tiga entitas inti dan alur pinjam-kembali yang aman.

1. Merancang Entitas

Kita butuh tiga tabel: books (data buku beserta jumlah kopi), members (anggota), dan loans (transaksi peminjaman). Kunci desain: setiap judul buku bisa punya beberapa eksemplar, sehingga ketersediaan dihitung dari stok kopi dikurangi peminjaman yang belum dikembalikan.

php artisan make:model Book -m
php artisan make:model Member -m
php artisan make:model Loan -m

Migration books dan members

Schema::create('books', function (Blueprint $table) {
    $table->id();
    $table->string('isbn')->unique()->nullable();
    $table->string('title');
    $table->string('author');
    $table->unsignedInteger('copies')->default(1); // total eksemplar
    $table->timestamps();
});

Schema::create('members', function (Blueprint $table) {
    $table->id();
    $table->string('code')->unique(); // nomor anggota
    $table->string('name');
    $table->string('phone')->nullable();
    $table->timestamps();
});

Migration loans

Tabel peminjaman menyimpan tanggal pinjam, jatuh tempo, dan tanggal kembali. Selama returned_at masih null, buku dianggap sedang dipinjam.

Schema::create('loans', function (Blueprint $table) {
    $table->id();
    $table->foreignId('book_id')->constrained();
    $table->foreignId('member_id')->constrained();
    $table->date('borrowed_at');
    $table->date('due_at');
    $table->date('returned_at')->nullable();
    $table->unsignedInteger('fine')->default(0);
    $table->timestamps();
});
php artisan migrate

2. Model dan Cek Ketersediaan

Pada model Book, kita hitung berapa eksemplar yang sedang dipinjam, lalu ketersediaan = total kopi dikurangi yang dipinjam. Ini mencegah buku dipinjam melebihi jumlah eksemplar.

class Book extends Model
{
    protected $fillable = ['isbn', 'title', 'author', 'copies'];

    public function loans()
    {
        return $this->hasMany(Loan::class);
    }

    public function getOnLoanAttribute(): int
    {
        return $this->loans()->whereNull('returned_at')->count();
    }

    public function getAvailableAttribute(): int
    {
        return max(0, $this->copies - $this->on_loan);
    }
}

Model Loan menyimpan konstanta aturan main — lama pinjam dan tarif denda per hari — agar mudah diubah di satu tempat:

class Loan extends Model
{
    const LOAN_DAYS = 7;      // durasi pinjam standar
    const FINE_PER_DAY = 1000; // denda per hari terlambat

    protected $fillable = ['book_id', 'member_id', 'borrowed_at', 'due_at', 'returned_at', 'fine'];

    protected $casts = [
        'borrowed_at' => 'date',
        'due_at'      => 'date',
        'returned_at' => 'date',
    ];
}

3. Alur Peminjaman

Saat anggota meminjam, kita cek ketersediaan dulu, lalu buat transaksi dengan jatuh tempo otomatis. Gunakan DB::transaction dan lockForUpdate supaya dua anggota tidak berebut eksemplar terakhir secara bersamaan.

use App\Models\Loan;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;

public function borrow(Request $request)
{
    $data = $request->validate([
        'book_id'   => 'required|exists:books,id',
        'member_id' => 'required|exists:members,id',
    ]);

    DB::transaction(function () use ($data) {
        $book = Book::lockForUpdate()->findOrFail($data['book_id']);

        if ($book->available < 1) {
            abort(422, 'Semua eksemplar buku ini sedang dipinjam.');
        }

        Loan::create([
            'book_id'     => $book->id,
            'member_id'   => $data['member_id'],
            'borrowed_at' => now(),
            'due_at'      => now()->addDays(Loan::LOAN_DAYS),
        ]);
    });

    return back()->with('success', 'Peminjaman berhasil dicatat.');
}

4. Alur Pengembalian dan Hitung Denda

Saat buku dikembalikan, kita bandingkan tanggal kembali dengan jatuh tempo. Jika terlambat, denda = jumlah hari keterlambatan dikalikan tarif harian. Perhatikan penggunaan diffInDays dengan urutan argumen yang benar agar keterlambatan positif.

public function returnBook(Loan $loan)
{
    if ($loan->returned_at) {
        return back()->with('error', 'Buku ini sudah dikembalikan.');
    }

    $today = Carbon::today();
    $fine = 0;

    if ($today->greaterThan($loan->due_at)) {
        $lateDays = $loan->due_at->diffInDays($today);
        $fine = $lateDays * Loan::FINE_PER_DAY;
    }

    $loan->update([
        'returned_at' => $today,
        'fine'        => $fine,
    ]);

    return back()->with('success', $fine > 0
        ? "Buku dikembalikan. Denda: Rp " . number_format($fine)
        : 'Buku dikembalikan tepat waktu.');
}

5. Daftar Buku Terlambat

Petugas perlu melihat siapa yang masih menahan buku melewati jatuh tempo. Query-nya cukup memfilter peminjaman yang belum kembali dan sudah lewat tanggal:

$overdue = Loan::query()
    ->whereNull('returned_at')
    ->whereDate('due_at', '<', now())
    ->with(['book', 'member'])
    ->get();

foreach ($overdue as $loan) {
    $lateDays = $loan->due_at->diffInDays(now());
    // tampilkan $loan->member->name, $loan->book->title, $lateDays
}

Kesalahan Umum yang Perlu Dihindari

  • Menyimpan status "dipinjam" sebagai boolean di tabel buku: gagal menangani banyak eksemplar. Hitung ketersediaan dari kopi dikurangi peminjaman aktif.
  • Tidak memakai transaksi saat meminjam: eksemplar terakhir bisa dipinjam dua orang sekaligus.
  • Salah urutan diffInDays: pastikan menghitung selisih dari jatuh tempo ke hari ini agar denda tidak negatif.

Dengan struktur tiga entitas dan aturan yang tersimpan sebagai konstanta, sistem perpustakaan Anda mudah dikembangkan: tambahkan perpanjangan pinjam, batas maksimal buku per anggota, atau notifikasi jatuh tempo lewat email tanpa merombak model data.

Yudhi
Ditulis oleh
Yudhi
Founder & Lead Developer, GudangCode

Yudhi adalah founder GudangCode dan developer Laravel dengan pengalaman membangun puluhan sistem informasi bisnis siap pakai — mulai dari POS, HRIS, hingga aplikasi manajemen. Ia menulis panduan dan artikel di GudangCode untuk membantu developer Indonesia menjalankan, memahami, dan men-deploy source code Laravel dengan benar.

Laravel PHP MySQL Sistem Informasi Bisnis
Lihat semua artikel Yudhi
Mau source code & aplikasi lengkapnya?

Daftar gratis untuk mengunduh aplikasi bisnis, sistem informasi, dan source code Laravel siap pakai.

Daftar Gratis & Download
Sistem Informasi Perpustakaan Sistem Informasi
📚 Free Learning Hub

Learn Coding for Free at DhieCoderWeb

Explore Laravel, PHP, JavaScript tutorials, source code, web development guides, and practical programming tips.

DhieCoderWeb
100+
Tutorials
Free
Learning
SEO
Tips
Visit Dhiecoderweb.com →

Dapatkan Akses Penuh Sekarang!

Bergabunglah menjadi member kami dan dapatkan akses eksklusif ke seluruh fitur unggulan aplikasi ini. Proses cepat, mudah, dan langsung bisa Anda gunakan.

Daftar Members Sekarang
Tim Support
Online
Isi data dulu untuk mulai chat:
Beri rating & testimoni sebelum menutup:
Live chat by gudangcode.com