initial_commit
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
"""Mesin status order (FR-ORD-04, FR-ORD-09, FR-ORD-10, UC-07, UC-08)."""
|
||||
|
||||
from datetime import timedelta
|
||||
from enum import Enum
|
||||
|
||||
AUTO_COMPLETE_AFTER = timedelta(days=3)
|
||||
|
||||
|
||||
class OrderStatus(Enum):
|
||||
PENDING_PAYMENT = "PENDING_PAYMENT"
|
||||
PAID = "PAID"
|
||||
SHIPPED = "SHIPPED"
|
||||
COMPLETED = "COMPLETED"
|
||||
CANCELLED = "CANCELLED"
|
||||
EXPIRED = "EXPIRED"
|
||||
|
||||
|
||||
class InvalidTransitionError(Exception):
|
||||
"""Event tidak diizinkan pada status order saat ini."""
|
||||
|
||||
|
||||
class PermissionDeniedError(Exception):
|
||||
"""Pelaku tidak berhak memicu event ini."""
|
||||
|
||||
|
||||
S = OrderStatus
|
||||
|
||||
# Tabel transisi: (status asal, event) -> status tujuan. Pasangan lain ditolak.
|
||||
TRANSITIONS = {
|
||||
(S.PENDING_PAYMENT, "pay"): S.PAID,
|
||||
(S.PENDING_PAYMENT, "cancel"): S.CANCELLED,
|
||||
(S.PENDING_PAYMENT, "expire"): S.EXPIRED,
|
||||
(S.PAID, "ship"): S.SHIPPED,
|
||||
(S.SHIPPED, "complete"): S.COMPLETED,
|
||||
}
|
||||
|
||||
|
||||
class Order:
|
||||
def __init__(self, order_id, buyer_id, seller_id):
|
||||
self.order_id = order_id
|
||||
self.buyer_id = buyer_id
|
||||
self.seller_id = seller_id
|
||||
self.status = S.PENDING_PAYMENT
|
||||
self.shipped_at = None
|
||||
|
||||
def _fire(self, event):
|
||||
target = TRANSITIONS.get((self.status, event))
|
||||
if target is None:
|
||||
raise InvalidTransitionError(f"{event} tidak valid pada status {self.status.value}")
|
||||
self.status = target
|
||||
|
||||
def pay(self):
|
||||
"""Event payment.succeeded dari Payment Service."""
|
||||
self._fire("pay")
|
||||
|
||||
def cancel(self, actor_id):
|
||||
"""Pembeli membatalkan order yang belum dibayar."""
|
||||
if actor_id != self.buyer_id:
|
||||
raise PermissionDeniedError("hanya pembeli yang dapat membatalkan")
|
||||
self._fire("cancel")
|
||||
|
||||
def expire(self):
|
||||
"""Batas waktu pembayaran habis (dipicu sistem)."""
|
||||
self._fire("expire")
|
||||
|
||||
def ship(self, actor_id, now):
|
||||
"""Seller pemilik toko menandai order terkirim."""
|
||||
if actor_id != self.seller_id:
|
||||
raise PermissionDeniedError("hanya seller pemilik toko yang dapat mengirim")
|
||||
self._fire("ship")
|
||||
self.shipped_at = now
|
||||
|
||||
def confirm_received(self, actor_id):
|
||||
"""Pembeli mengonfirmasi pesanan diterima. Seller tidak boleh."""
|
||||
if actor_id != self.buyer_id:
|
||||
raise PermissionDeniedError("hanya pembeli yang dapat mengonfirmasi")
|
||||
self._fire("complete")
|
||||
|
||||
def auto_complete(self, now):
|
||||
"""Sistem menyelesaikan order 3 hari setelah SHIPPED tanpa konfirmasi."""
|
||||
if self.status is S.SHIPPED and now - self.shipped_at < AUTO_COMPLETE_AFTER:
|
||||
raise InvalidTransitionError("belum 3 hari sejak SHIPPED")
|
||||
self._fire("complete")
|
||||
Reference in New Issue
Block a user