Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from abc import ABC, abstractmethod
- from datetime import datetime, timedelta
- from enum import Enum
- import uuid
- import pickle
- import os
- # ==============================================================================
- # Definisi Enum untuk Status
- # ==============================================================================
- class StatusItem(Enum):
- """Enum untuk status item di perpustakaan."""
- TERSEDIA = "Tersedia"
- DIPINJAM = "Dipinjam"
- HILANG = "Hilang"
- class StatusTransaksi(Enum):
- """Enum untuk status transaksi peminjaman."""
- AKTIF = "Aktif"
- SELESAI = "Selesai"
- TERLAMBAT = "Terlambat"
- # ==============================================================================
- # Hierarki Kelas Item Pustaka (LoanableItem, Buku, Majalah)
- # ==============================================================================
- class LoanableItem(ABC):
- """
- Kelas abstrak untuk semua item yang dapat dipinjam di perpustakaan.
- Ini adalah superclass (induk) untuk Buku, Majalah, dll.
- """
- def __init__(self, item_id: str, judul: str):
- self._item_id = item_id
- self._judul = judul
- self._status = StatusItem.TERSEDIA
- @abstractmethod
- def get_info(self) -> dict:
- """Metode abstrak untuk mendapatkan informasi detail dari item."""
- pass
- def ubah_status(self, status_baru: StatusItem):
- """Mengubah status ketersediaan item."""
- self._status = status_baru
- print(f"INFO: Status '{self._judul}' telah diubah menjadi {status_baru.value}.")
- @property
- def item_id(self):
- return self._item_id
- @property
- def judul(self):
- return self._judul
- @property
- def status(self):
- return self._status
- class Buku(LoanableItem):
- """Kelas turunan untuk merepresentasikan sebuah buku."""
- def __init__(self, item_id: str, judul: str, pengarang: str):
- super().__init__(item_id, judul)
- self._pengarang = pengarang
- def get_info(self) -> dict:
- """Implementasi spesifik untuk menampilkan info buku (method overriding)."""
- return {
- "ID": self._item_id,
- "Judul": self._judul,
- "Tipe": "Buku",
- "Pengarang": self._pengarang,
- "Status": self._status.value
- }
- class Majalah(LoanableItem):
- """Kelas turunan untuk merepresentasikan sebuah majalah/jurnal."""
- def __init__(self, item_id: str, judul: str, edisi: str):
- super().__init__(item_id, judul)
- self._edisi = edisi
- def get_info(self) -> dict:
- """Implementasi spesifik untuk menampilkan info majalah (method overriding)."""
- return {
- "ID": self._item_id,
- "Judul": self._judul,
- "Tipe": "Majalah",
- "Edisi": self._edisi,
- "Status": self._status.value
- }
- # ==============================================================================
- # Kelas-kelas Utama Sistem
- # ==============================================================================
- class Member:
- """Merepresentasikan anggota perpustakaan."""
- def __init__(self, nama: str, alamat: str):
- self._member_id = "MEM-" + str(uuid.uuid4())[:8].upper()
- self._nama = nama
- self._alamat = alamat
- @property
- def member_id(self):
- return self._member_id
- @property
- def nama(self):
- return self._nama
- def get_riwayat_peminjaman(self, perpus: 'Perpustakaan') -> list['Transaksi']:
- """Mendapatkan daftar transaksi yang pernah dilakukan oleh member."""
- riwayat = []
- for transaksi in perpus.daftar_transaksi:
- if transaksi.member.member_id == self._member_id:
- riwayat.append(transaksi)
- return riwayat
- class Transaksi:
- """Merepresentasikan sebuah transaksi peminjaman."""
- def __init__(self, member: Member, item: LoanableItem):
- self._transaksi_id = "TRX-" + str(uuid.uuid4())[:8].upper()
- self._member = member
- self._item = item
- self._tgl_pinjam = datetime.now()
- self._tgl_kembali = self._tgl_pinjam + timedelta(days=14) # Batas peminjaman 14 hari
- self._status = StatusTransaksi.AKTIF
- self._denda = 0.0
- @property
- def transaksi_id(self):
- return self._transaksi_id
- @property
- def member(self):
- return self._member
- @property
- def item(self):
- return self._item
- @property
- def status(self):
- return self._status
- def hitung_denda(self) -> float:
- """Menghitung denda jika pengembalian terlambat."""
- if datetime.now() > self._tgl_kembali:
- terlambat = (datetime.now() - self._tgl_kembali).days
- self._denda = float(terlambat * 1000) # Denda 1000 per hari
- self._status = StatusTransaksi.TERLAMBAT
- return self._denda
- def selesaikan_transaksi(self):
- self.hitung_denda()
- if self._status != StatusTransaksi.TERLAMBAT:
- self._status = StatusTransaksi.SELESAI
- class Perpustakaan:
- """Kelas utama yang mengelola seluruh sistem perpustakaan."""
- # Kode sebelumnya:
- # def __init__(self):
- # self._daftar_item = []
- # self._daftar_member = []
- # self._daftar_transaksi = []
- # print("Sistem Perpustakaan berhasil dibuat.")
- def __init__(self, nama_file_data="perpustakaan.pkl"):
- """
- Inisialisasi perpustakaan.
- Akan mencoba memuat data dari file jika ada.
- """
- self._nama_file_data = nama_file_data
- # Coba muat data dulu
- if not self.muat_data():
- # Jika gagal (file tidak ada), buat list kosong
- print("INFO: File data tidak ditemukan. Membuat database baru...")
- self._daftar_item = []
- self._daftar_member = []
- self._daftar_transaksi = []
- print("Sistem Perpustakaan berhasil dibuat.")
- @property
- def daftar_item(self):
- return self._daftar_item
- @property
- def daftar_member(self):
- return self._daftar_member
- @property
- def daftar_transaksi(self):
- return self._daftar_transaksi
- def muat_data(self) -> bool:
- """
- Memuat state perpustakaan (daftar item, member, transaksi)
- dari file pickle.
- Mengembalikan True jika berhasil, False jika gagal.
- """
- if not os.path.exists(self._nama_file_data):
- return False # File tidak ada, gagal memuat
- try:
- # Buka file dalam mode Read Binary ('rb')
- with open(self._nama_file_data, 'rb') as f:
- # Muat data yang disimpan
- data_dimuat = pickle.load(f)
- # Kembalikan state objek dari dictionary
- self._daftar_item = data_dimuat.get("items", [])
- self._daftar_member = data_dimuat.get("members", [])
- self._daftar_transaksi = data_dimuat.get("transaksi", [])
- print(f"INFO: Data perpustakaan berhasil dimuat dari {self._nama_file_data}.")
- return True
- except Exception as e:
- print(f"ERROR saat memuat data: {e}")
- return False
- def simpan_data(self):
- """
- Menyimpan state perpustakaan (daftar item, member, transaksi)
- ke dalam file pickle.
- """
- # Siapkan data yang akan disimpan dalam format dictionary
- data_untuk_disimpan = {
- "items": self._daftar_item,
- "members": self._daftar_member,
- "transaksi": self._daftar_transaksi
- }
- try:
- # Buka file dalam mode Write Binary ('wb')
- with open(self._nama_file_data, 'wb') as f:
- # Simpan data menggunakan pickle
- pickle.dump(data_untuk_disimpan, f)
- print(f"\nINFO: Data perpustakaan berhasil disimpan ke {self._nama_file_data}.")
- except Exception as e:
- print(f"ERROR saat menyimpan data: {e}")
- def tambah_item(self, item: LoanableItem):
- """Menambahkan item baru (buku/majalah) ke perpustakaan."""
- self._daftar_item.append(item)
- print(f"ITEM DITAMBAHKAN: '{item.judul}' ({item.__class__.__name__}) telah ditambahkan ke koleksi.")
- def tambah_member(self, nama: str, alamat: str) -> Member:
- """Mendaftarkan anggota baru."""
- member_baru = Member(nama, alamat)
- self._daftar_member.append(member_baru)
- print(f"MEMBER BARU: {nama} dengan ID {member_baru.member_id} berhasil terdaftar.")
- return member_baru
- def cari_item(self, item_id: str) -> LoanableItem | None:
- """Mencari item berdasarkan ID."""
- for item in self._daftar_item:
- if item.item_id == item_id:
- return item
- return None
- def cari_member(self, member_id: str) -> Member | None:
- """Mencari member berdasarkan ID."""
- for member in self._daftar_member:
- if member.member_id == member_id:
- return member
- return None
- def cari_transaksi(self, transaksi_id: str) -> Transaksi | None:
- """Mencari transaksi berdasarkan ID."""
- for trx in self._daftar_transaksi:
- if trx.transaksi_id == transaksi_id:
- return trx
- return None
- def pinjamkan_item(self, member_id: str, item_id: str) -> Transaksi:
- """Memproses peminjaman item oleh member."""
- member = self.cari_member(member_id)
- item = self.cari_item(item_id)
- if not member:
- raise Exception("ERROR: Member tidak ditemukan.")
- if not item:
- raise Exception("ERROR: Item tidak ditemukan.")
- if item.status != StatusItem.TERSEDIA:
- raise Exception(f"ERROR: Item '{item.judul}' sedang tidak tersedia.")
- transaksi_baru = Transaksi(member, item)
- self._daftar_transaksi.append(transaksi_baru)
- item.ubah_status(StatusItem.DIPINJAM)
- print(f"TRANSAKSI PEMINJAMAN: '{item.judul}' dipinjam oleh {member.nama}. ID Transaksi: {transaksi_baru.transaksi_id}")
- return transaksi_baru
- def terima_pengembalian(self, transaksi_id: str):
- """Memproses pengembalian item."""
- transaksi = self.cari_transaksi(transaksi_id)
- if not transaksi:
- raise Exception("ERROR: Transaksi tidak ditemukan.")
- if transaksi.status != StatusTransaksi.AKTIF:
- raise Exception("ERROR: Transaksi ini sudah tidak aktif.")
- transaksi.selesaikan_transaksi()
- item = transaksi.item
- item.ubah_status(StatusItem.TERSEDIA)
- denda = transaksi.hitung_denda()
- print(f"TRANSAKSI PENGEMBALIAN: '{item.judul}' telah dikembalikan oleh {transaksi.member.nama}.")
- if denda > 0:
- print(f" -> Dikenakan denda sebesar: Rp{denda:,.2f}")
- else:
- print(" -> Pengembalian tepat waktu.")
- # Modifikasi Kelas Pustakawan
- class Pustakawan:
- """Merepresentasikan pustakawan yang mengelola perpustakaan."""
- def __init__(self, pustakawan_id: str, nama: str):
- self._pustakawan_id = pustakawan_id
- self._nama = nama
- def lakukan_pendaftaran(self, perpus: Perpustakaan, nama: str, alamat: str) -> Member:
- """Wrapper method untuk mendaftarkan member."""
- print(f"\n[Aksi Pustakawan: {self._nama}] Mendaftarkan anggota baru...")
- return perpus.tambah_member(nama, alamat)
- # Versi Baru dengan Factory
- def tambah_item_ke_koleksi(self, perpus: Perpustakaan, item_type: str, item_id: str, judul: str, **kwargs):
- """Wrapper method untuk menambah item baru menggunakan Factory."""
- print(f"\n[Aksi Pustakawan: {self._nama}] Meminta pembuatan dan penambahan item '{judul}'...")
- try:
- # Panggil Factory untuk membuat objek
- item_baru = ItemFactory.create_item(item_type, item_id, judul, **kwargs)
- # Tambahkan objek yang sudah jadi ke perpustakaan
- perpus.tambah_item(item_baru)
- except ValueError as e:
- print(f"ERROR saat menambah item: {e}")
- except Exception as e:
- print(f"ERROR tidak terduga: {e}")
- def lakukan_peminjaman(self, perpus: Perpustakaan, member_id: str, item_id: str) -> Transaksi:
- """Wrapper method untuk melakukan peminjaman."""
- print(f"\n[Aksi Pustakawan: {self._nama}] Memproses peminjaman...")
- return perpus.pinjamkan_item(member_id, item_id)
- def lakukan_pengembalian(self, perpus: Perpustakaan, transaksi_id: str):
- """Wrapper method untuk melakukan pengembalian."""
- print(f"\n[Aksi Pustakawan: {self._nama}] Memproses pengembalian...")
- perpus.terima_pengembalian(transaksi_id)
- # Kelas Baru: ItemFactory
- class ItemFactory:
- """Kelas Factory untuk membuat instance LoanableItem."""
- @staticmethod
- def create_item(item_type: str, item_id: str, judul: str, **kwargs) -> LoanableItem:
- """
- Membuat objek Buku atau Majalah berdasarkan item_type.
- kwargs bisa berisi 'pengarang' untuk Buku atau 'edisi' untuk Majalah.
- """
- if item_type.lower() == "buku":
- pengarang = kwargs.get('pengarang', 'N/A') # Ambil pengarang, default N/A
- if pengarang == 'N/A':
- print("WARNING: Pengarang tidak disediakan untuk buku.")
- return Buku(item_id, judul, pengarang)
- elif item_type.lower() == "majalah":
- edisi = kwargs.get('edisi', 'N/A') # Ambil edisi, default N/A
- if edisi == 'N/A':
- print("WARNING: Edisi tidak disediakan untuk majalah.")
- return Majalah(item_id, judul, edisi)
- # Bisa tambahkan tipe lain di sini (misal: Artikel)
- # elif item_type.lower() == "artikel":
- # volume = kwargs.get('volume', 0)
- # return Artikel(item_id, judul, volume)
- else:
- raise ValueError(f"Tipe item tidak dikenal: {item_type}")
Advertisement
Add Comment
Please, Sign In to add comment