From 5d7dbec67cd7ec79739272986355c15bd33ad913 Mon Sep 17 00:00:00 2001 From: Gilles Soulier Date: Thu, 28 May 2026 06:41:04 +0200 Subject: [PATCH] fix(mcp): status active + search_products guard + item.product + cleanup auto-name --- backend/app/api/mcp_server.py | 37 ++++++++++++++++++----------------- backend/tests/test_mcp.py | 8 ++++++++ 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/backend/app/api/mcp_server.py b/backend/app/api/mcp_server.py index f4a54ae..c8bcdeb 100644 --- a/backend/app/api/mcp_server.py +++ b/backend/app/api/mcp_server.py @@ -361,19 +361,19 @@ async def get_shopping_lists() -> str: @mcp.tool() async def get_active_shopping_list() -> str: - """Retourne la première liste en statut 'draft' avec tous ses articles triés.""" + """Retourne la première liste en statut 'draft' ou 'active' avec tous ses articles triés.""" async with AsyncSessionLocal() as session: stmt = ( select(ShoppingList) - .where(ShoppingList.status == "draft") + .where(ShoppingList.status.in_(["draft", "active"])) .options(selectinload(ShoppingList.items).selectinload(ListItem.product)) - .order_by(ShoppingList.created_at.desc()) + .order_by(ShoppingList.status.asc(), ShoppingList.created_at.desc()) .limit(1) ) result = await session.execute(stmt) lst = result.scalar_one_or_none() if not lst: - return _dumps({"error": "Aucune liste active (statut draft)"}) + return _dumps({"error": "Aucune liste active (statut draft ou active)"}) sorted_items = sorted(lst.items, key=lambda i: (i.sort_order or 999, str(i.id))) return _dumps({ "id": lst.id, @@ -394,6 +394,8 @@ async def get_active_shopping_list() -> str: @mcp.tool() async def search_products(q: str) -> str: """Recherche dans le catalogue produits par nom, description ou catégorie.""" + if not q or not q.strip(): + return _dumps({"error": "Paramètre q requis"}) async with AsyncSessionLocal() as session: stmt = ( select(Product) @@ -490,19 +492,18 @@ async def check_shopping_item(list_id: str, item_id: str) -> str: return _dumps({"error": f"Article introuvable : {item_id} dans liste {list_id}"}) was_checked = item.is_checked item.is_checked = True - if not was_checked and item.product_id: - product = await session.get(Product, item.product_id) - if product: - today = date_type.today() - if product.last_purchased_at and product.last_purchased_at < today: - days = (today - product.last_purchased_at).days - if product.avg_interval_days is None: - product.avg_interval_days = Decimal(str(days)) - else: - product.avg_interval_days = Decimal(str( - round(float(product.avg_interval_days) * 0.7 + days * 0.3, 1) - )) - product.last_purchased_at = today - product.frequency_score += 1 + if not was_checked and item.product: + product = item.product + today = date_type.today() + if product.last_purchased_at and product.last_purchased_at < today: + days = (today - product.last_purchased_at).days + if product.avg_interval_days is None: + product.avg_interval_days = Decimal(str(days)) + else: + product.avg_interval_days = Decimal(str( + round(float(product.avg_interval_days) * 0.7 + days * 0.3, 1) + )) + product.last_purchased_at = today + product.frequency_score += 1 await session.commit() return _dumps({"id": item.id, "is_checked": item.is_checked}) diff --git a/backend/tests/test_mcp.py b/backend/tests/test_mcp.py index 17a52cf..3651a0f 100644 --- a/backend/tests/test_mcp.py +++ b/backend/tests/test_mcp.py @@ -1,4 +1,5 @@ import json +import uuid import pytest from sqlalchemy import delete import app.api.mcp_server as mcp_server_module @@ -155,7 +156,14 @@ async def test_create_shopping_list_outil(): async def test_create_shopping_list_nom_auto(): result = await create_shopping_list() data = json.loads(result) + # Le nom auto est au format "S{semaine} {année}" (ex: "S22 2026") assert data["name"].startswith("S") + # Cleanup manuel — la liste auto n'a pas le préfixe TEST_MCP_ + async with mcp_server_module.AsyncSessionLocal() as session: + await session.execute( + delete(ShoppingList).where(ShoppingList.id == uuid.UUID(data["id"])) + ) + await session.commit() async def test_add_shopping_item_outil():