66 lines
2.1 KiB
Python
66 lines
2.1 KiB
Python
"""Model produk Catalog. Atribut khusus per kategori mengikuti AR-01 / FR-CAT-03."""
|
|
|
|
from abc import ABC, abstractmethod
|
|
from datetime import date
|
|
|
|
CLOTHING_SIZES = ("S", "M", "L", "XL")
|
|
|
|
|
|
class Product(ABC):
|
|
"""Kelas dasar produk. Subclass menentukan atribut khusus kategorinya."""
|
|
|
|
category = "generic"
|
|
|
|
def __init__(self, product_id, shop_id, name, price, on_hand, reserved=0):
|
|
if price < 0:
|
|
raise ValueError("price tidak boleh negatif")
|
|
if not 0 <= reserved <= on_hand:
|
|
raise ValueError("reserved harus di antara 0 dan on_hand")
|
|
self.product_id = product_id
|
|
self.shop_id = shop_id
|
|
self.name = name
|
|
self.price = price
|
|
self.on_hand = on_hand
|
|
self.reserved = reserved
|
|
|
|
@property
|
|
def available(self):
|
|
"""Stok yang dapat dipesan: onHand - reserved (glosarium SRS)."""
|
|
return self.on_hand - self.reserved
|
|
|
|
def is_orderable(self, today):
|
|
"""Aturan dasar: produk dapat dipesan jika masih ada stok tersedia."""
|
|
return self.available > 0
|
|
|
|
@abstractmethod
|
|
def attributes(self):
|
|
"""Atribut khusus kategori, dikembalikan sebagai dict."""
|
|
|
|
|
|
class FoodProduct(Product):
|
|
category = "food"
|
|
|
|
def __init__(self, product_id, shop_id, name, price, on_hand, expiry_date, reserved=0):
|
|
super().__init__(product_id, shop_id, name, price, on_hand, reserved)
|
|
self.expiry_date = expiry_date
|
|
|
|
def is_orderable(self, today):
|
|
"""Makanan tidak boleh dipesan setelah tanggal kedaluwarsa."""
|
|
return super().is_orderable(today) and today <= self.expiry_date
|
|
|
|
def attributes(self):
|
|
return {"expiryDate": self.expiry_date.isoformat()}
|
|
|
|
|
|
class ClothingProduct(Product):
|
|
category = "clothing"
|
|
|
|
def __init__(self, product_id, shop_id, name, price, on_hand, size, reserved=0):
|
|
if size not in CLOTHING_SIZES:
|
|
raise ValueError(f"size harus salah satu dari {CLOTHING_SIZES}")
|
|
super().__init__(product_id, shop_id, name, price, on_hand, reserved)
|
|
self.size = size
|
|
|
|
def attributes(self):
|
|
return {"size": self.size}
|