Treat unoccupied stop invoice errors as completed washes

This commit is contained in:
Jeppe Bundgaard
2026-06-04 01:55:35 +02:00
parent 82e1e4a466
commit 985571af87
3 changed files with 70 additions and 1 deletions
+4 -1
View File
@@ -70,7 +70,10 @@ export function useWashSessionActions(options) {
const isAlreadyStoppedStopError = (message) => {
const normalized = String(message || "").toLowerCase();
return normalized.includes("cannot stop lane") && normalized.includes("not occupied");
return (
normalized.includes("not occupied") &&
(normalized.includes("cannot stop lane") || normalized.includes("cannot invoice"))
);
};
const clearActiveWashState = () => {
@@ -126,4 +126,25 @@ describe("useWashSessionActions production commands", () => {
expect(state.stopElapsedTimer).toHaveBeenCalled();
expect(state.clearProgress).toHaveBeenCalled();
});
it("recovers local state when STOP says an unoccupied lane cannot invoice", async () => {
const request = vi.fn(async () => ({
data: { success: false, message: "Failed to execute command: Lane ID 7 is not occupied; cannot invoice." },
}));
const { state, actions } = createActions({
request,
washInProgress: ref(true),
washLaneId: ref(7),
washStartTime: ref(1_000),
now: ref(6_000),
});
await expect(actions.onStopWash(7)).resolves.toBe(true);
expect(state.washInProgress.value).toBe(false);
expect(state.washLaneId.value).toBeNull();
expect(state.completedDurationMs.value).toBe(5_000);
expect(state.stopElapsedTimer).toHaveBeenCalled();
expect(state.clearProgress).toHaveBeenCalled();
});
});
@@ -446,6 +446,51 @@ describe("useWashSessionActions property gate commands", () => {
expect(clearProgress).toHaveBeenCalledTimes(1);
});
it("clears active wash state when stop reports the lane cannot invoice because it is unoccupied", async () => {
const washInProgress = ref(true);
const washLaneId = ref(7);
const washStartTime = ref(2_000);
const completedDurationMs = ref(null);
const now = ref(47_000);
const clearProgress = vi.fn();
const stopElapsedTimer = vi.fn();
const request = vi.fn(async (_url, _method, body) => {
if (body.command === "STOP") {
return {
data: {
success: false,
data: {
message: "Failed to execute command: Lane ID 7 is not occupied; cannot invoice.",
},
},
};
}
return { data: { success: true } };
});
const { actions, alertFn } = createActions({
request,
washInProgress,
washLaneId,
washStartTime,
completedDurationMs,
now,
clearProgress,
stopElapsedTimer,
});
const result = await actions.onStopWash(7);
expect(result).toBe(true);
expect(alertFn).not.toHaveBeenCalled();
expect(completedDurationMs.value).toBe(45_000);
expect(washInProgress.value).toBe(false);
expect(washLaneId.value).toBeNull();
expect(stopElapsedTimer).toHaveBeenCalledTimes(1);
expect(clearProgress).toHaveBeenCalledTimes(1);
});
it("clears active wash state only after the stop command succeeds", async () => {
const washInProgress = ref(true);
const washLaneId = ref(7);