feat: create and list orders as Deck cards

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 16:17:16 +02:00
parent 2313c3c490
commit 21e63685c9
2 changed files with 111 additions and 0 deletions

View File

@ -519,6 +519,43 @@ async def _ensure_deck_board() -> dict:
return _deck_cache
async def create_order(customer: str, description: str, due_date: str = None) -> dict:
board = await _ensure_deck_board()
stack_id = board["stacks"]["Offen"]
body = {"title": customer, "description": description, "type": "plain", "order": 999}
if due_date:
body["duedate"] = _as_calendar_local(datetime.fromisoformat(due_date)).isoformat()
card = await _deck_request("POST", f"/boards/{board['board_id']}/stacks/{stack_id}/cards", body)
return {
"id": card["id"],
"customer": customer,
"description": description,
"status": "Offen",
"due_date": due_date,
}
async def list_orders(status: str = None) -> list:
board = await _ensure_deck_board()
stacks = await _deck_request("GET", f"/boards/{board['board_id']}/stacks")
orders = []
for stack in stacks:
if status and stack["title"] != status:
continue
for card in stack.get("cards", []):
orders.append({
"id": card["id"],
"customer": card["title"],
"description": card.get("description", ""),
"status": stack["title"],
"due_date": card.get("duedate"),
})
return orders
def _decode_mime_words(value: str) -> str:
parts = decode_header(value)
decoded = []

View File

@ -141,3 +141,77 @@ async def test_ensure_deck_board_caches_after_first_lookup():
mock_req.assert_not_called()
assert board["board_id"] == 10
_BOARD = {"board_id": 10, "stacks": {"Offen": 1, "In Arbeit": 2, "Erledigt": 3}}
@pytest.mark.asyncio
async def test_create_order_creates_card_in_offen_stack():
with patch.object(main, "_ensure_deck_board", new=AsyncMock(return_value=_BOARD)), patch.object(
main, "_deck_request", new=AsyncMock(return_value={"id": 55})
) as mock_req:
order = await main.create_order("Feuerwehr Onza", "10x Handschuhe Groesse L")
assert order == {
"id": 55,
"customer": "Feuerwehr Onza",
"description": "10x Handschuhe Groesse L",
"status": "Offen",
"due_date": None,
}
method, path, body = mock_req.call_args[0]
assert method == "POST"
assert path == "/boards/10/stacks/1/cards"
assert body["title"] == "Feuerwehr Onza"
assert body["description"] == "10x Handschuhe Groesse L"
assert "duedate" not in body
@pytest.mark.asyncio
async def test_create_order_localizes_due_date():
with patch.object(main, "_ensure_deck_board", new=AsyncMock(return_value=_BOARD)), patch.object(
main, "_deck_request", new=AsyncMock(return_value={"id": 55})
) as mock_req:
await main.create_order("Feuerwehr Onza", "Helme", due_date="2026-09-20")
_, _, body = mock_req.call_args[0]
assert body["duedate"] == datetime(2026, 9, 20, tzinfo=main.CALENDAR_TIMEZONE).isoformat()
@pytest.mark.asyncio
async def test_list_orders_flattens_cards_across_stacks():
stacks_response = [
{"id": 1, "title": "Offen", "cards": [
{"id": 55, "title": "Feuerwehr Onza", "description": "Helme", "duedate": None}
]},
{"id": 2, "title": "In Arbeit", "cards": []},
{"id": 3, "title": "Erledigt", "cards": [
{"id": 56, "title": "Musterfirma", "description": "Stiefel", "duedate": "2026-09-20T00:00:00+02:00"}
]},
]
with patch.object(main, "_ensure_deck_board", new=AsyncMock(return_value=_BOARD)), patch.object(
main, "_deck_request", new=AsyncMock(return_value=stacks_response)
):
orders = await main.list_orders()
assert len(orders) == 2
assert orders[0] == {
"id": 55, "customer": "Feuerwehr Onza", "description": "Helme", "status": "Offen", "due_date": None
}
assert orders[1]["status"] == "Erledigt"
@pytest.mark.asyncio
async def test_list_orders_filters_by_status():
stacks_response = [
{"id": 1, "title": "Offen", "cards": [{"id": 55, "title": "A", "description": "", "duedate": None}]},
{"id": 2, "title": "In Arbeit", "cards": []},
{"id": 3, "title": "Erledigt", "cards": [{"id": 56, "title": "B", "description": "", "duedate": None}]},
]
with patch.object(main, "_ensure_deck_board", new=AsyncMock(return_value=_BOARD)), patch.object(
main, "_deck_request", new=AsyncMock(return_value=stacks_response)
):
orders = await main.list_orders(status="Erledigt")
assert [o["id"] for o in orders] == [56]