feat: add Storniert status column to Bestellungen board

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V57jSQPqwkGG8BuAXg59X5
This commit is contained in:
Jonny 2026-09-13 19:56:40 +02:00
parent 69bf530ff3
commit 529b9c3320
2 changed files with 35 additions and 10 deletions

View File

@ -486,7 +486,7 @@ async def _deck_request(method: str, path: str, json_body: dict = None):
_deck_cache: dict = {}
_DECK_BOARD_TITLE = "Bestellungen"
_DECK_STACK_TITLES = ["Offen", "In Arbeit", "Erledigt"]
_DECK_STACK_TITLES = ["Offen", "In Arbeit", "Erledigt", "Storniert"]
async def _ensure_deck_board() -> dict:
@ -830,15 +830,15 @@ ORDER_TOOLS = [
"properties": {
"status": {
"type": "string",
"description": "Filter by column: 'Offen', 'In Arbeit' or 'Erledigt'. Omit to list all.",
"enum": ["Offen", "In Arbeit", "Erledigt"],
"description": "Filter by column: 'Offen', 'In Arbeit', 'Erledigt' or 'Storniert'. Omit to list all.",
"enum": ["Offen", "In Arbeit", "Erledigt", "Storniert"],
},
},
},
},
{
"name": "update_order_status",
"description": "Move an order to a different status column (e.g. mark it 'In Arbeit' or 'Erledigt'). Call list_orders first if you don't already know the order's id.",
"description": "Move an order to a different status column (e.g. mark it 'In Arbeit', 'Erledigt' or 'Storniert'). Call list_orders first if you don't already know the order's id.",
"input_schema": {
"type": "object",
"properties": {
@ -846,7 +846,7 @@ ORDER_TOOLS = [
"status": {
"type": "string",
"description": "New status column",
"enum": ["Offen", "In Arbeit", "Erledigt"],
"enum": ["Offen", "In Arbeit", "Erledigt", "Storniert"],
},
},
"required": ["order_id", "status"],
@ -904,7 +904,7 @@ ORDER_ASSISTANT_INSTRUCTIONS = (
"Du hast ausserdem Zugriff auf Bestellungen ueber die Tools "
"create_order, list_orders, update_order_status und update_order - sie "
"leben als Karten im Nextcloud-Deck-Board 'Bestellungen' mit den "
"Spalten Offen, In Arbeit und Erledigt. update_order_status aendert "
"Spalten Offen, In Arbeit, Erledigt und Storniert. update_order_status aendert "
"nur die Spalte/den Status; update_order aendert Kunde, Beschreibung "
"und/oder Faelligkeitsdatum, ohne die Spalte zu wechseln. Du kannst "
"alle vier Tools direkt aufrufen, sobald du die noetigen Angaben hast "

View File

@ -107,8 +107,8 @@ async def test_ensure_deck_board_creates_board_and_stacks_when_missing():
board = await main._ensure_deck_board()
assert board["board_id"] == 10
assert titles_created == ["Offen", "In Arbeit", "Erledigt"]
assert set(board["stacks"].keys()) == {"Offen", "In Arbeit", "Erledigt"}
assert titles_created == ["Offen", "In Arbeit", "Erledigt", "Storniert"]
assert set(board["stacks"].keys()) == {"Offen", "In Arbeit", "Erledigt", "Storniert"}
@pytest.mark.asyncio
@ -121,20 +121,45 @@ async def test_ensure_deck_board_reuses_existing_board_and_stacks():
{"id": 1, "title": "Offen", "cards": []},
{"id": 2, "title": "In Arbeit", "cards": []},
{"id": 3, "title": "Erledigt", "cards": []},
{"id": 4, "title": "Storniert", "cards": []},
]
raise AssertionError(f"unexpected call {method} {path}")
with patch.object(main, "_deck_request", new=AsyncMock(side_effect=fake_deck_request)) as mock_req:
board = await main._ensure_deck_board()
assert board == {"board_id": 10, "stacks": {"Offen": 1, "In Arbeit": 2, "Erledigt": 3}}
assert board == {"board_id": 10, "stacks": {"Offen": 1, "In Arbeit": 2, "Erledigt": 3, "Storniert": 4}}
assert mock_req.call_count == 2
@pytest.mark.asyncio
async def test_ensure_deck_board_creates_missing_stack_on_existing_board():
"""Regression: a board created before 'Storniert' existed only has the
original three stacks - the fourth must be added, not just assumed."""
async def fake_deck_request(method, path, json_body=None):
if (method, path) == ("GET", "/boards"):
return [{"id": 10, "title": "Bestellungen"}]
if (method, path) == ("GET", "/boards/10/stacks"):
return [
{"id": 1, "title": "Offen", "cards": []},
{"id": 2, "title": "In Arbeit", "cards": []},
{"id": 3, "title": "Erledigt", "cards": []},
]
if (method, path) == ("POST", "/boards/10/stacks"):
assert json_body["title"] == "Storniert"
return {"id": 4, "title": "Storniert"}
raise AssertionError(f"unexpected call {method} {path}")
with patch.object(main, "_deck_request", new=AsyncMock(side_effect=fake_deck_request)):
board = await main._ensure_deck_board()
assert board["stacks"] == {"Offen": 1, "In Arbeit": 2, "Erledigt": 3, "Storniert": 4}
@pytest.mark.asyncio
async def test_ensure_deck_board_caches_after_first_lookup():
main._deck_cache["board_id"] = 10
main._deck_cache["stacks"] = {"Offen": 1, "In Arbeit": 2, "Erledigt": 3}
main._deck_cache["stacks"] = {"Offen": 1, "In Arbeit": 2, "Erledigt": 3, "Storniert": 4}
with patch.object(main, "_deck_request", new=AsyncMock()) as mock_req:
board = await main._ensure_deck_board()