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.6 KB · 84 lines python
Raw Blame History
1# -----------------------------------------------------------------------------2# Immo-Ka — Agrégateur de maisons à vendre (province de Québec)3# Auteur : Simon-Pierre Boucher — contact@spboucher.ai4# mortgage/providers/desjardins.py : Desjardins — JSON server-rendered5#   window.dcomProducts sur la page des taux. Clé = cfPath COMPLET (le même6#   id existe dans les familles « taux-hypothecaires » (affichés) et7#   « taux-hypothecaires-promotionnels » (spéciaux) avec des valeurs8#   différentes — ne jamais confondre).9# -----------------------------------------------------------------------------10from __future__ import annotations1112import json13import re1415from .base import RateProvider1617PAGE_URL = "https://www.desjardins.com/fr/hypotheque/taux-hypothecaires.html"1819# id Desjardins -> (rate_type, terme mois, nom, purpose)20ID_MAP: dict[str, tuple] = {21    "6000_6M": ("fixed", 6, "Fixe fermé 6 mois"),22    "6000_1A": ("fixed", 12, "Fixe fermé 1 an"),23    "6000_2A": ("fixed", 24, "Fixe fermé 2 ans"),24    "6000_3A": ("fixed", 36, "Fixe fermé 3 ans"),25    "6000_4A": ("fixed", 48, "Fixe fermé 4 ans"),26    "6000_5A": ("fixed", 60, "Fixe fermé 5 ans"),27    "6000_6A": ("fixed", 72, "Fixe fermé 6 ans"),28    "6000_7A": ("fixed", 84, "Fixe fermé 7 ans"),29    "6000_10A": ("fixed", 120, "Fixe fermé 10 ans"),30    "6000_6MO": ("fixed", 6, "Fixe ouvert 6 mois"),31    "6000_1AO": ("fixed", 12, "Fixe ouvert 1 an"),32    "6004_5AR": ("variable", 60, "Variable réduit 5 ans"),33    "tvp": ("variable", 60, "Variable protégé 5 ans"),34    "tvred": ("variable", 60, "Variable réduit"),35    "tvreg": ("variable", 60, "Variable régulier"),36    "tra": ("fixed", 12, "Révisable annuellement"),37}38PRIME_ID = "tpcad"394041class DesjardinsProvider(RateProvider):42    provider_id = "desjardins"43    institution = "Desjardins"44    source_url = PAGE_URL45    request_delay = 1.54647    def fetch(self) -> list[dict]:48        return self.parse(self.get(self.source_url).text)4950    def parse(self, payload: str) -> list[dict]:51        m = re.search(r"window\.dcomProducts\s*=\s*(\{.*?\});", payload, re.S)52        if not m:53            raise ValueError("dcomProducts introuvable (structure changée)")54        products = json.loads(m.group(1))55        out: list[dict] = []56        for cf_path, cell in products.items():57            if "/hypotheque/" not in cf_path or not isinstance(cell, dict):58                continue59            pid = cell.get("id") or ""60            try:61                rate = float(cell.get("rate"))62            except (TypeError, ValueError):63                continue64            if rate <= 0:65                continue66            promo = "taux-hypothecaires-promotionnels" in cf_path67            if pid == PRIME_ID:68                out.append(self.make_product(69                    rate=rate, rate_type="other", term_months=12,70                    kind="posted", product_name="Taux préférentiel Desjardins",71                    purpose="unknown", raw={"cfPath": cf_path, "rate": rate}))72                continue73            if pid not in ID_MAP:74                continue  # id inconnu : jamais deviné75            rtype, term, label = ID_MAP[pid]76            out.append(self.make_product(77                rate=rate, rate_type=rtype, term_months=term,78                kind="special" if promo else "posted",79                product_name=label + (" (promotion)" if promo else ""),80                conditions="Taux promotionnel Desjardins" if promo81                           else "Taux affiché Desjardins",82                raw={"cfPath": cf_path, "id": pid, "rate": cell.get("rate")}))83        return out84