SPB Git forge

spb/house-ka

Public
18commits 1branches 0releases
1.9 MBsize
maindefault branch
20 days agolast push
Python 67% TypeScript 18.2% CSS 14.4%
3.8 KB · 86 lines markdown
Rendered Raw Blame History
1# Providers de taux hypothécaires23Un connecteur **indépendant** par institution. Auto-découverte : tout module du4dossier définissant une sous-classe de `RateProvider` avec un `provider_id`5non vide est enregistré dans `PROVIDERS` automatiquement (aucun registre à6éditer). La panne d'un provider n'affecte jamais les autres.78**Règle absolue : aucun taux inventé.** Un produit non confirmé sur la page9officielle est simplement omis — jamais deviné, jamais de valeur par défaut.1011## Ajouter une institution (8 étapes)12131. **Créer `<slug>.py`** dans ce dossier, avec une sous-classe de14   `RateProvider` :1516   ```python17   from .base import RateProvider1819   class MaBanque(RateProvider):20       provider_id = "ma_banque"           # slug stable (clé BD)21       institution = "Ma Banque"           # nom d'affichage fr-CA22       source_url = "https://mabanque.ca/taux-hypothecaires"2324       def fetch(self) -> list[dict]:25           html = self.get(self.source_url).text   # ou .json()26           return self.parse(html)2728       def parse(self, html: str) -> list[dict]:29           ...  # → [self.make_product(...), ...]30   ```3132   Séparer `fetch()` (réseau) de `parse()` (pur) : les tests appellent33   `parse()` sur des fixtures, sans réseau.34352. **Backend réseau** : `self.get(url)` (requests + politesse `request_delay`)36   d'abord ; `self.get_scrapfly(url, render_js=True)` **en dernier recours37   seulement** si le site bloque (403/JS requis).38393. **Normaliser** chaque produit via `self.make_product(...)` :40   - `rate_type` : `fixed` / `variable` — ou **`other` pour tout taux41     préférentiel/prime/référence** (avec `purpose="unknown"`), afin qu'il ne42     tombe jamais dans un classement « meilleur taux d'achat » ;43   - `kind` : `posted` (affiché) ou `special` (offre spéciale) — ne jamais44     confondre ;45   - `insured_status` : `insured` / `insurable` / `uninsured`, ou `unknown`46     si la page ne le précise pas — ne pas deviner ;47   - `product_name` en français, explicite (ex. « Fixe fermé 5 ans ») ;48   - `apr` (TAP) seulement s'il est publié.49504. **Aucune écriture BD** dans le provider : le scheduler valide51   (`validate_batch`) puis enregistre (`store.record_observations`). Ne pas52   filtrer soi-même les aberrations — la validation s'en charge et journalise.53545. **Fixture** : sauvegarder la réponse réelle (HTML/JSON) dans55   `tests/fixtures/mortgage/<slug>.<ext>` (anonymisée si besoin, taille56   raisonnable — garder le bloc utile).57586. **Test** : ajouter le slug dans `EXPECTED` de59   `tests/test_mortgage_providers.py` (fixture + nombre exact de produits) ;60   le test générique vérifie déjà validation propre, `source_url`,61   `institution` et la règle « préférentiel → other/unknown ». Ajouter un62   test ciblé sur 1–2 valeurs connues de la fixture.63647. **Exécuter** :6566   ```bash67   PYTHONPATH=. .venv/bin/python -P -m unittest tests.test_mortgage_providers68   .venv/bin/python run.py mortgage-sync ma_banque   # collecte réelle69   .venv/bin/python run.py mortgage-status           # santé70   ```71728. **Vérifier en BD/API** : `GET /api/mortgage/rates?provider=ma_banque` —73   provenance (`source_url`), fraîcheur et nature correctes. C'est tout :74   ni web.py, ni le scheduler, ni le frontend n'ont besoin d'être modifiés.7576## Pièges connus7778- `4.19 % → 419` : toujours vérifier l'échelle ; la validation rejette79  > 24 %, mais un « 41,9 » passerait — parser au bon endroit.80- Pages avec plusieurs onglets (assuré/non assuré) : étiqueter81  `insured_status` correctement plutôt que de tout mélanger.82- Taux « ouverts » vs « fermés » : les distinguer dans `product_name`83  (ex. BNC publie « Fixe ouvert 1 an » à 9,65 % — ce n'est pas une erreur).84- Ne jamais soumettre de formulaire ni simuler une demande de prêt : pages85  publiques de taux uniquement.86