feat: add GET /api/v1/orders endpoint

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:12:57 +02:00
parent 940ad510e0
commit ebbeb0b42c
2 changed files with 49 additions and 0 deletions

View File

@ -1335,6 +1335,16 @@ async def get_calendar_events(days: int = 14):
logger.error(f"Calendar fetch error: {str(e)}") logger.error(f"Calendar fetch error: {str(e)}")
raise HTTPException(status_code=503, detail=f"Calendar unavailable: {str(e)}") raise HTTPException(status_code=503, detail=f"Calendar unavailable: {str(e)}")
@app.get("/api/v1/orders", dependencies=[Depends(require_admin_key)])
async def get_orders(status: Optional[str] = None):
"""Bestellungen aus dem Nextcloud-Deck-Board 'Bestellungen'"""
try:
orders = await list_orders(status)
return {"orders": orders}
except Exception as e:
logger.error(f"Orders fetch error: {str(e)}")
raise HTTPException(status_code=503, detail=f"Orders unavailable: {str(e)}")
@app.get("/api/v1/emails", dependencies=[Depends(require_admin_key)]) @app.get("/api/v1/emails", dependencies=[Depends(require_admin_key)])
async def get_cached_emails(limit: int = 10): async def get_cached_emails(limit: int = 10):
"""Recently cached emails, populated by the n8n 'Neue E-Mails Cache' workflow""" """Recently cached emails, populated by the n8n 'Neue E-Mails Cache' workflow"""

View File

@ -306,3 +306,42 @@ async def test_run_chat_completion_includes_order_tools_and_instructions():
_, kwargs = main.claude_client.messages.create.call_args _, kwargs = main.claude_client.messages.create.call_args
assert kwargs["tools"] == main.CALENDAR_TOOLS + main.MEMORY_TOOLS + main.ORDER_TOOLS assert kwargs["tools"] == main.CALENDAR_TOOLS + main.MEMORY_TOOLS + main.ORDER_TOOLS
assert "create_order" in kwargs["system"] or "Bestellungen" in kwargs["system"] assert "create_order" in kwargs["system"] or "Bestellungen" in kwargs["system"]
from fastapi.testclient import TestClient
main.API_KEY_ADMIN = "test-secret"
HEADERS = {"X-Admin-Key": "test-secret"}
@pytest.fixture()
def client():
with TestClient(main.app) as c:
yield c
def test_orders_endpoint_returns_list(client):
orders = [{"id": 55, "customer": "A", "description": "", "status": "Offen", "due_date": None}]
with patch.object(main, "list_orders", new=AsyncMock(return_value=orders)) as mock_list:
response = client.get("/api/v1/orders", headers=HEADERS)
assert response.status_code == 200
assert response.json() == {"orders": orders}
mock_list.assert_called_once_with(None)
def test_orders_endpoint_filters_by_status_query_param(client):
with patch.object(main, "list_orders", new=AsyncMock(return_value=[])) as mock_list:
response = client.get("/api/v1/orders?status=Erledigt", headers=HEADERS)
assert response.status_code == 200
mock_list.assert_called_once_with("Erledigt")
def test_orders_endpoint_requires_admin_key(client):
response = client.get("/api/v1/orders")
assert response.status_code == 401
def test_orders_endpoint_returns_503_on_deck_error(client):
with patch.object(main, "list_orders", new=AsyncMock(side_effect=RuntimeError("Deck down"))):
response = client.get("/api/v1/orders", headers=HEADERS)
assert response.status_code == 503