diff --git a/artifacts/api-server/tests/service-orders.test.mjs b/artifacts/api-server/tests/service-orders.test.mjs index aabb202d..fe5a45dc 100644 --- a/artifacts/api-server/tests/service-orders.test.mjs +++ b/artifacts/api-server/tests/service-orders.test.mjs @@ -423,6 +423,128 @@ test("owner can restore (undo) a freshly cancelled order to its prior status; ex assert.match(body.error, /undo_window_expired/); }); +test("confirm-receipt returns 409 order_unavailable when the order is cancelled or completed", async () => { + const owner = await createUser("ownU", "user"); + const recv1 = await createUser("recvU1", "order_receiver"); + const recv2 = await createUser("recvU2", "order_receiver"); + const co = await login(owner.username); + const cr1 = await login(recv1.username); + const cr2 = await login(recv2.username); + + // Case A: order cancelled before any claim → second receiver sees order_unavailable + let res = await call(co, "POST", "/orders", { serviceId }); + assert.equal(res.status, 201); + const oCancelled = await res.json(); + createdOrderIds.push(oCancelled.id); + + res = await call(co, "PATCH", `/orders/${oCancelled.id}/status`, { + status: "cancelled", + }); + assert.equal(res.status, 200); + + res = await call(cr1, "PATCH", `/orders/${oCancelled.id}/confirm-receipt`); + assert.equal(res.status, 409); + let body = await res.json(); + assert.equal( + body.error, + "order_unavailable", + "cancelled order should report order_unavailable, not already_claimed", + ); + + // Case B: order taken all the way to completed → another receiver sees order_unavailable + res = await call(co, "POST", "/orders", { serviceId }); + assert.equal(res.status, 201); + const oCompleted = await res.json(); + createdOrderIds.push(oCompleted.id); + + res = await call(cr1, "PATCH", `/orders/${oCompleted.id}/confirm-receipt`); + assert.equal(res.status, 200); + res = await call(cr1, "PATCH", `/orders/${oCompleted.id}/status`, { + status: "preparing", + }); + assert.equal(res.status, 200); + res = await call(cr1, "PATCH", `/orders/${oCompleted.id}/status`, { + status: "completed", + }); + assert.equal(res.status, 200); + + res = await call(cr2, "PATCH", `/orders/${oCompleted.id}/confirm-receipt`); + assert.equal(res.status, 409); + body = await res.json(); + assert.equal( + body.error, + "order_unavailable", + "completed order should report order_unavailable, not already_claimed", + ); +}); + +test("PATCH /orders/:id/status returns 409 order_unavailable when targeting a terminal order", async () => { + const owner = await createUser("ownT", "user"); + const recv = await createUser("recvT", "order_receiver"); + const co = await login(owner.username); + const cr = await login(recv.username); + + // Build a completed order (assignee = recv) + let res = await call(co, "POST", "/orders", { serviceId }); + assert.equal(res.status, 201); + const oDone = await res.json(); + createdOrderIds.push(oDone.id); + + res = await call(cr, "PATCH", `/orders/${oDone.id}/confirm-receipt`); + assert.equal(res.status, 200); + res = await call(cr, "PATCH", `/orders/${oDone.id}/status`, { + status: "preparing", + }); + assert.equal(res.status, 200); + res = await call(cr, "PATCH", `/orders/${oDone.id}/status`, { + status: "completed", + }); + assert.equal(res.status, 200); + + // Assignee tries preparing on a completed order → 409 order_unavailable + res = await call(cr, "PATCH", `/orders/${oDone.id}/status`, { + status: "preparing", + }); + assert.equal(res.status, 409); + let body = await res.json(); + assert.equal(body.error, "order_unavailable"); + + // Assignee tries completed (again) on a completed order → 409 order_unavailable + res = await call(cr, "PATCH", `/orders/${oDone.id}/status`, { + status: "completed", + }); + assert.equal(res.status, 409); + body = await res.json(); + assert.equal(body.error, "order_unavailable"); + + // Owner tries to cancel a completed order → 409 order_unavailable (non-admin) + res = await call(co, "PATCH", `/orders/${oDone.id}/status`, { + status: "cancelled", + }); + assert.equal(res.status, 409); + body = await res.json(); + assert.equal(body.error, "order_unavailable"); + + // Build a cancelled order (no assignee) + res = await call(co, "POST", "/orders", { serviceId }); + assert.equal(res.status, 201); + const oCxl = await res.json(); + createdOrderIds.push(oCxl.id); + + res = await call(co, "PATCH", `/orders/${oCxl.id}/status`, { + status: "cancelled", + }); + assert.equal(res.status, 200); + + // Owner tries to cancel an already-cancelled order → 409 order_unavailable (non-admin) + res = await call(co, "PATCH", `/orders/${oCxl.id}/status`, { + status: "cancelled", + }); + assert.equal(res.status, 409); + body = await res.json(); + assert.equal(body.error, "order_unavailable"); +}); + test("unauthenticated cannot place order", async () => { const res = await fetch(`${API_BASE}/api/orders`, { method: "POST",