diff --git a/main.py b/main.py index afd8353..5de32eb 100644 --- a/main.py +++ b/main.py @@ -35,6 +35,91 @@ class _ScraperData: return None return cast(dict[str, object], current_data.get("attributes")) + def prix(self) -> float: + """ + Retourne le prix unitaire d'une bouteille (75cl). + + Le JSON contient plusieurs formats de vente dans content["items"] : + - bouteille seule : nbunit = 1 et equivbtl = 1 -> prix direct + - caisse de plusieurs bouteilles : nbunit > 1 -> on divise le prix total + - formats spéciaux (magnum etc.) : equivbtl > 1 -> même calcul + + Formule générale : + prix_unitaire = offerPrice / (nbunit * equivbtl) + + """ + + content = self._getcontent() + + # si content n'existe pas -> erreur + if content is None: + raise ValueError("Contenu introuvable") + + # On récupère la liste des formats disponibles (bouteille, carton...) + items = content.get("items") + + # Vérification que items est bien une liste non vide + if not isinstance(items, list) or len(items) == 0: + raise ValueError("Aucun prix disponible (items vide)") + + # -------------------------- + # CAS 1 : bouteille unitaire + # -------------------------- + # On cherche un format où nbunit=1 et equivbtl=1 ->bouteille standard 75cl + for item in items: + + if not isinstance(item, dict): + continue + + # On récupère les attributs du format + attrs = item.get("attributes", {}) + + # On récupère nbunit et equivbtl + nbunit = attrs.get("nbunit", {}).get("value") + equivbtl = attrs.get("equivbtl", {}).get("value") + + # Si c'est une bouteille unitaire + if nbunit == "1" and equivbtl == "1": + + p = item.get("offerPrice") + + # Vérification que c'est bien un nombre + if isinstance(p, (int, float)): + return float(p) + + # -------------------------- + # CAS 2 : caisse ou autre format + # -------------------------- + # On calcule le prix unitaire à partir du prix total + for item in items: + + if not isinstance(item, dict): + continue + + p = item.get("offerPrice") + attrs = item.get("attributes", {}) + + nbunit = attrs.get("nbunit", {}).get("value") + equivbtl = attrs.get("equivbtl", {}).get("value") + + # Vérification que toutes les valeurs existent + if isinstance(p, (int, float)) and nbunit and equivbtl: + + # Calcul du nombre total de bouteilles équivalentes + denom = float(nbunit) * float(equivbtl) + + # Évite division par zéro + if denom > 0: + + # Calcul du prix unitaire + prix_unitaire = float(p) / denom + + # Arrondi à 2 décimales + return round(prix_unitaire, 2) + + # Si aucun prix trouvé + raise ValueError("Impossible de trouver le prix unitaire.") + def appellation(self) -> str | None: """_summary_ diff --git a/test_main.py b/test_main.py index 905e902..162db92 100644 --- a/test_main.py +++ b/test_main.py @@ -94,6 +94,18 @@ def mock_site(): "type": "CHECKBOX", "isSpirit": False, }, + "equivbtl": { + "valueId": "1", + "name": "equivbtl", + "value": "1", + "isSpirit": False, + }, + "nbunit": { + "valueId": "6", + "name": "nbunit", + "value": "6", + "isSpirit": False, + }, }, "stock": 12, "availability": "2026-02-05", @@ -105,18 +117,6 @@ def mock_site(): } ], "attributes": { - "equivbtl": { - "valueId": "1", - "name": "equivbtl", - "value": "1", - "isSpirit": False, - }, - "nbunit": { - "valueId": "6", - "name": "nbunit", - "value": "6", - "isSpirit": False, - }, "appellation": { "valueId": "433", "name": "Appellation", @@ -224,3 +224,19 @@ def test_critiques(scraper: Scraper): assert contenu.robinson() == "17" assert contenu.suckling() == "93.5" assert contenu._getcritiques("test_ts") is None + +def test_prix(scraper: Scraper): + vide = scraper.getjsondata("") + poubelle = scraper.getjsondata("poubelle") + contenu = scraper.getjsondata("nino-negri-5-stelle-sfursat-2022.html") + + # Cas vide : items == [] -> on ne peut pas calculer -> ValueError + with pytest.raises(ValueError): + _ = vide.prix() + + # Cas poubelle : JSON incomplet -> _getcontent() None -> ValueError + with pytest.raises(ValueError): + _ = poubelle.prix() + + assert contenu.prix() == 65.0 +