# ============================================ # Projet : API-KA # Fichier : src/collectors/restoka_collector.py # Node : m3u96b # Author : Simon-Pierre Boucher # Contact : contact@spboucher.ai # Date : 2026-08-17 # ============================================ """Collecteur quotidien du service resto-ka (table restoka_data). Contrairement aux autres collecteurs, la liste ``/api/restaurants`` ne contient que les métadonnées : les plats (menus → sections → items, avec options et prix réels) ne sont exposés que sur la fiche détaillée ``/api/restaurants/{uid}``. Le fetch pagine donc la liste, puis récupère la fiche complète de chaque restaurant — chaque enregistrement sauvegardé contient ainsi le menu entier du jour. """ from __future__ import annotations from typing import Any import httpx from src.collectors.base_collector import FETCH_TIMEOUT_SECONDS, BaseCollector class RestokaCollector(BaseCollector): """Collecte les restaurants ET leurs plats depuis RESTOKA_SOURCE_URL.""" service = "restoka" items_key = "restaurants" pagination = "offset" page_size = 500 # maximum accepté par l'API resto-ka (/api/restaurants) def fetch(self) -> Any: """Récupère la liste paginée puis la fiche détaillée (plats inclus). Returns: Liste des restaurants avec leur menu complet ; si une fiche détaillée est indisponible, l'enregistrement sommaire de la liste est conservé pour ne jamais perdre le restaurant. """ summaries: list[dict[str, Any]] = super().fetch() detailed: list[dict[str, Any]] = [] with httpx.Client( timeout=FETCH_TIMEOUT_SECONDS, follow_redirects=True ) as client: for summary in summaries: uid = summary.get("uid") if isinstance(summary, dict) else None if not uid: detailed.append(summary) continue try: response = client.get(f"{self.source_url}/{uid}") response.raise_for_status() detailed.append(response.json()) except httpx.HTTPError as exc: self.logger.warning( "Fiche détaillée indisponible, sommaire conservé", extra={"uid": uid, "error": str(exc)}, ) detailed.append(summary) return detailed