[ka2] fix connecteur gestion_cem: préfixe de locale /fr sur les routes Eversa — le portail gestioncem.eversa.app exige depuis ~2026-09-17 un préfixe de locale (/fr, /en) sur toutes ses routes React Router. Le sync du 2026-09-17 10:14 a échoué franc (« 'list' object has no attribute 'get' ») : /listings/list.data renvoie désormais un turbo-stream SingleFetchRedirect 301 vers /en/listings/list (HTTP 202, 147 octets) dont le décodage donne une LISTE, que fetch() traitait comme un dict. Vérifié live : /listings/list.data → 202 SingleFetchRedirect ; /fr/listings/list.data → 200, 54 Ko, structure PublicListingsLayoutPage inchangée (13 immeubles) ; idem pour les pages détail. Fix minimal : préfixer /fr sur la route de liste, les routes détail et les page_url publiques (le décodeur et les parseurs sont intacts). Testé : fetch() venv → 31 annonces (11626 rue Prince-Albert Montréal-Est 2 095 $/mois 3 photos, 115 rue de la Maçonnerie Châteauguay 1 595 $ — médiane 31.0 pile), run.py sync gestion_cem → found=31 ok (0,2 s, updated=31 : migration des URL vers /fr/), pm2 restart lou-ka-sync, site :8095 → 200.
1 changed file +5 −3
modified
louka/connectors/gestion_cem.py
+5 −3
@@ -10,6 +10,8 @@ | ||
| 10 | 10 | # Granularité : UNITÉ (page détail par immeuble -> units[] avec listed=true, |
| 11 | 11 | # prix, pi², chambres, sdb, photos, date de disponibilité). Repli sur la |
| 12 | 12 | # carte de l'immeuble si la page détail est indisponible (404 transitoire). |
| 13 | +# Depuis ~2026-09-17 les routes exigent un préfixe de locale (/fr, /en) : | |
| 14 | +# sans préfixe, `.data` renvoie un SingleFetchRedirect 301 (payload liste). | |
| 13 | 15 | # ----------------------------------------------------------------------------- |
| 14 | 16 | from __future__ import annotations |
| 15 | 17 | |
@@ -136,7 +138,7 @@ class GestionCemConnector(BaseConnector): | ||
| 136 | 138 | return payload |
| 137 | 139 | |
| 138 | 140 | def _detail_listing(self, slug: str) -> dict | None: |
| 139 | − data = self._route_data(f"/listings/{slug}/details") | |
| 141 | + data = self._route_data(f"/fr/listings/{slug}/details") | |
| 140 | 142 | if not isinstance(data, dict): |
| 141 | 143 | return None |
| 142 | 144 | page = data.get("PublicListingDetailPage") or {} |
@@ -171,7 +173,7 @@ class GestionCemConnector(BaseConnector): | ||
| 171 | 173 | |
| 172 | 174 | # -- contrat --------------------------------------------------------------- |
| 173 | 175 | def fetch(self) -> list[Listing]: |
| 174 | − data = self._route_data("/listings/list") | |
| 176 | + data = self._route_data("/fr/listings/list") | |
| 175 | 177 | page = (data or {}).get("PublicListingsLayoutPage") or {} |
| 176 | 178 | if "data" in page: |
| 177 | 179 | page = page.get("data") or {} |
@@ -190,7 +192,7 @@ class GestionCemConnector(BaseConnector): | ||
| 190 | 192 | slug = b.get("slug") or "" |
| 191 | 193 | if not slug: |
| 192 | 194 | continue |
| 193 | − page_url = f"{BASE}/listings/{slug}/details" | |
| 195 | + page_url = f"{BASE}/fr/listings/{slug}/details" | |
| 194 | 196 | |
| 195 | 197 | # détail (cache BD : clé = contenu de la carte liste) |
| 196 | 198 | key = json.dumps({k: b.get(k) for k in |
| 197 | 199 | |