initial_commit
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
"""Modul prosedural validasi checkout (FR-ORD-02, FR-ORD-03, FR-ORD-08).
|
||||
|
||||
Harga diambil dari katalog, bukan dari input klien. Satu order hanya boleh
|
||||
berisi produk dari satu toko. Keranjang kosong mengembalikan total 0; penolakan
|
||||
keranjang kosong menjadi tanggung jawab pemanggil.
|
||||
"""
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
class CheckoutError(Exception):
|
||||
"""Kelas dasar semua kegagalan validasi checkout."""
|
||||
|
||||
|
||||
class ProductNotFoundError(CheckoutError):
|
||||
pass
|
||||
|
||||
|
||||
class InvalidQuantityError(CheckoutError):
|
||||
pass
|
||||
|
||||
|
||||
class MultiShopError(CheckoutError):
|
||||
pass
|
||||
|
||||
|
||||
class InsufficientStockError(CheckoutError):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CartItem:
|
||||
product_id: str
|
||||
quantity: int
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CheckoutSummary:
|
||||
shop_id: str | None
|
||||
total_amount: int
|
||||
|
||||
|
||||
def validate_checkout(items, products):
|
||||
"""Validasi keranjang terhadap katalog lalu hitung total dalam rupiah."""
|
||||
shop_id = None
|
||||
total = 0
|
||||
for item in items:
|
||||
product = products.get(item.product_id)
|
||||
if product is None:
|
||||
raise ProductNotFoundError(item.product_id)
|
||||
if item.quantity <= 0:
|
||||
raise InvalidQuantityError(item.product_id)
|
||||
if shop_id is None:
|
||||
shop_id = product.shop_id
|
||||
elif product.shop_id != shop_id:
|
||||
raise MultiShopError(item.product_id)
|
||||
if product.available < item.quantity:
|
||||
raise InsufficientStockError(item.product_id)
|
||||
total += product.price * item.quantity
|
||||
return CheckoutSummary(shop_id, total)
|
||||
Reference in New Issue
Block a user