PythiloLesson 5 of 15 · progress kept in this browser

A state machine for a workflow

An order moves from draft to submitted to paid to shipped, and can be cancelled until it is paid. Status checks scattered through the code drift apart. Writing the allowed moves down in one table makes the workflow explicit, easy to test and easy to draw.

MOVES = {
    ("draft", "submit"): "submitted",
    ("submitted", "pay"): "paid",
    ("paid", "ship"): "shipped",
}

def step(state, action):
    if (state, action) not in MOVES:
        msg = f"no {action} from {state}"
        raise ValueError(msg)
    return MOVES[(state, action)]

state = step("draft", "submit")
print(state, step(state, "pay"))

The order keeps its current state, and every change goes through one method that consults the table. A list of past states gives you an audit trail for free.

Your task

Write an Enum Status with DRAFT, SUBMITTED, PAID, SHIPPED and CANCELLED, an exception InvalidTransition, and Order with status starting at DRAFT, history listing every status it has had, and apply(action) for "submit", "pay", "ship" and "cancel" (allowed from draft or submitted). Add allowed_actions() returning the sorted actions possible now.