Remove finished work orders

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rope 2026-10-20 20:11:11 +01:00
parent be478f3b2e
commit 6883b707ad
4 changed files with 28 additions and 2 deletions

2
app.py
View file

@ -330,6 +330,8 @@ class Handler(BaseHTTPRequestHandler):
return game.provide_reagent(world, player, body.get("id"), str(item))
if path == "/api/order/cancel":
return game.cancel_order(world, player, body.get("id"), now)
if path == "/api/order/remove":
return game.remove_orders(world, player, body.get("id"))
if path == "/api/order/work":
return game.work_order(world, player, body.get("id"), now)
if path == "/api/order/drop":

10
game.py
View file

@ -2285,6 +2285,16 @@ def cancel_order(world: dict, player: dict, order_id, now: float) -> str | None:
return None
def remove_orders(world: dict, player: dict, order_id=None) -> str | None:
"""Clear your finished orders: one, or all of them. Ones still holding items for your bank stay."""
gone = [o for o in world["orders"] if o["by"] == player["id"] and o["status"] != "open" and not o["held"]
and order_id in (None, o["id"])]
if not gone:
return "No such order"
world["orders"] = [o for o in world["orders"] if o not in gone]
return None
def claim_order(world: dict, player: dict, order_id, claim: bool = True) -> str | None:
order = order_by_id(world, order_id)
if not order or order["status"] != "open" or order["kind"] != "craft":

View file

@ -1240,6 +1240,7 @@ function orderCard(o) {
let buttons = "", status = "";
if (o.status !== "open") {
status = `<span class="tag ${o.status === "done" ? "good" : ""}">${{ done: "Done", cancelled: "Cancelled", expired: "Expired" }[o.status]}</span>`;
if (mine && !o.held) buttons = `<button class="btn" data-order-remove="${o.id}">Remove</button>`;
} else if (mine) {
buttons = `<button class="btn danger" data-order-cancel="${o.id}">Cancel</button>`;
if (o.claimed) status = `<span class="tag">${esc(playerName(o.claimed))}</span>`;
@ -1336,12 +1337,14 @@ function orders() {
const lists = { take: takeable, open, yours };
if (!lists[orderTab]) orderTab = "take";
const shown = lists[orderTab];
const old = orderTab === "yours" && yours.some((o) => o.status !== "open" && !o.held);
const tab =(key, label, n) => `<button class="tab ${orderTab === key ? "on" : ""}" data-otab="${key}">${label}${n ? ` <b class="badge">${n}</b>` : ""}</button>`;
return `<div class="panel"><div class="skill-head"><div class="big">${ORDER_ICON()}</div>
<div class="info"><h2>Work orders</h2></div>
<button class="btn ${draft ? "" : "primary"}" data-order-new>${draft ? "Close" : "New order"}</button></div></div>
${draft ? orderComposer() : ""}
<div class="tabs">${tab("take", "For you", takeable.length)}${tab("open", "All open", 0)}${tab("yours", "Yours", 0)}</div>
<div class="tabs">${tab("take", "For you", takeable.length)}${tab("open", "All open", 0)}${tab("yours", "Yours", 0)}
${old ? `<button class="btn" data-order-clear>Clear</button>` : ""}</div>
${shown.length ? `<div class="grid wide">${shown.map(orderCard).join("")}</div>` : `<p class="muted">None.</p>`}`;
}
@ -1664,6 +1667,8 @@ document.addEventListener("click", (e) => {
if (d.orderDrop) return act("/api/order/drop", { id: Number(d.orderDrop) });
if (d.orderDeliver) return act("/api/order/deliver", { id: Number(d.orderDeliver) });
if (d.orderCancel) return act("/api/order/cancel", { id: Number(d.orderCancel) });
if (d.orderRemove) return act("/api/order/remove", { id: Number(d.orderRemove) });
if ("orderClear" in d) return act("/api/order/remove", {});
if (d.orderFill) return act("/api/order/provide", { id: Number(d.orderFill), item: d.item });
if (d.doll) {
dollPick = dollPick === d.doll ? null : d.doll;

View file

@ -1609,6 +1609,15 @@ class WorkOrderTest(unittest.TestCase):
self.assertEqual(self.mike["gold"], 200)
self.assertEqual(self.mike["bank"]["iron_bar"], 3)
def test_finished_orders_can_be_removed(self):
self.post_hammer()
order = self.world["orders"][0]
self.assertEqual(game.remove_orders(self.world, self.mike, order["id"]), "No such order") # still open
game.cancel_order(self.world, self.mike, order["id"], T0)
self.assertEqual(game.remove_orders(self.world, self.fred, order["id"]), "No such order") # not his
self.assertIsNone(game.remove_orders(self.world, self.mike))
self.assertEqual(self.world["orders"], [])
def test_requester_can_fill_a_slot_after_posting(self):
self.mike["gold"] = 200
self.mike["bank"] = {"iron_bar": 3, "clay_core": 3}