Step 3: History

Real order systems keep an audit trail, every state the order has passed through, in order. Record it as the machine moves, and note that a rejected event must not leave a trace.

The order starts its history in cart. Update fire so each successful transition appends the new state.

  • fire(event): on a successful transition, append the new state to self.history; rejected events change nothing
Hints
Starter code
class Order:
    TRANSITIONS = {
        "cart": {"checkout": "pending"},
        "pending": {"pay": "paid", "cancel": "cancelled"},
        "paid": {"ship": "shipped", "refund": "cancelled"},
        "shipped": {"deliver": "delivered"},
        "delivered": {},
        "cancelled": {},
    }

    def __init__(self):
        self.state = "cart"
        self.history = ["cart"]

    def fire(self, event):
        """Advance on an allowed event and record the new state in history."""
        # TODO: same allowed-event check against TRANSITIONS as before, but now
        # the audit trail matters. A successful move updates self.state and adds
        # the state just entered to the end of self.history; a rejected event
        # must leave self.state and self.history exactly as they were.
        pass

    def can(self, event):
        return event in self.TRANSITIONS.get(self.state, {})

    def available_events(self):
        return list(self.TRANSITIONS.get(self.state, {}).keys())

    def is_terminal(self):
        return len(self.TRANSITIONS.get(self.state, {})) == 0
Write it on a laptop

The editor and the test runner need a wide screen. Open this page on a desktop browser and your progress will be waiting.