Skip to content

Commit

Permalink
Merge pull request #109 from SocialGouv/feat/obiz-scripts
Browse files Browse the repository at this point in the history
feat: obiz scripts & new fields for offer
  • Loading branch information
ClementNumericite authored Oct 28, 2024
2 parents f13f817 + 3ac52cf commit cdeddc9
Show file tree
Hide file tree
Showing 16 changed files with 4,663 additions and 12 deletions.
56 changes: 56 additions & 0 deletions scripts/obiz/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]

# C extensions
*.so

# Distribution / packaging
bin/
build/
develop-eggs/
dist/
eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
.tox/
.coverage
.cache
nosetests.xml
coverage.xml

# Translations
*.mo

# Mr Developer
.mr.developer.cfg
.project
.pydevproject

# Rope
.ropeproject

# Django stuff:
*.log
*.pot

# Sphinx documentation
docs/_build/

# idea
.idea/

# Specific
inputs/
65 changes: 65 additions & 0 deletions scripts/obiz/config/genre_mapping.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from typing import Dict, Optional
from enum import Enum

class Category(Enum):
"""
Énumération des catégories selon la structure fournie
"""
TELEPHONY = "Internet et abonnements"
BANK = "Banque et assurance"
CULTURE = "Livres, presse et culture"
EQUIPMENT = "High Tech et équipements"
HYGIENE = "Hygiène et beauté"
SPORT = "Sport"
HOBBY = "Loisirs et sorties"
MOBILITY = "Transport et voyage"
FASHION = "Mode et vêtements"
SHOP = "Courses et restauration"

class GenreMapper:
"""
Classe pour gérer les correspondances entre genres et catégories
"""
def __init__(self, mapping_file: str = None):
self._mapping: Dict[str, Category] = {
# reduccine
"Abonnements": Category.TELEPHONY,
"E-billets": Category.HOBBY,
"Billets papier": Category.HOBBY,
"Achats groupés par lot": Category.SHOP,

# reduckdo
"Sport": Category.SPORT,
"Alimentation, Gastronomie": Category.SHOP,
"Brico, Déco, Aménagement": Category.EQUIPMENT,
"Chèques Culture": Category.CULTURE,
"Cours en Ligne, Coaching": Category.CULTURE,
"Escape Game, Autres Loisirs": Category.HOBBY,
"Jeux, Livres, Puériculture": Category.CULTURE,
"Loisirs": Category.HOBBY,
"Mode, Beauté, Parfumerie": Category.FASHION,
"Multi-Enseigne, Gd Distrib": Category.SHOP,
"Produits Artisanaux": Category.SHOP,
"Voyages": Category.MOBILITY,
"VR / Coaching eSport": Category.HOBBY,
"Abonnement Digital, Multimédia": Category.EQUIPMENT,
"Echèques": Category.SHOP,

# reducparc
"Aquariums": Category.HOBBY,
"E-coffret Expériences": Category.HOBBY,
"Grands Parcs": Category.HOBBY,
"Loisirs & Tourisme": Category.HOBBY,
"Offres Séjours": Category.MOBILITY,
"Parcs animaliers": Category.HOBBY,
"Parcs aquatiques": Category.HOBBY,
"Parcs culturels": Category.HOBBY,
"Parcs d'attractions": Category.HOBBY
}

def get_category(self, genre: str) -> Optional[str]:
"""
Retourne la catégorie correspondant au genre
"""
category = self._mapping.get(genre)
return category.value if category else None
7 changes: 7 additions & 0 deletions scripts/obiz/config/sousgenres_whitelist.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
sousgenre_ids = [
'4de46793-f99e-4134-9060-f3f25eaf54cb',
'7c0c156b-a34e-42df-93e7-6d9b580e9d2c',
'993a12af-7bcf-4c23-8d99-54b3c58dd136',
'fca7f854-2304-48d5-bb4b-b674b4f98c69',
'a8ce74c6-5214-4737-b04c-8267069066b6'
]
69 changes: 69 additions & 0 deletions scripts/obiz/explorer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import json
from parsers.articles import get_article_names
from parsers.sousgenres import get_sousgenre_names
from parsers.genres import get_genre_names
from finders.sousgenre import search_sousgenre_articles, print_sousgenre_details

def main():
file_paths = [
'inputs/reduccine.fr-preprod.json',
'inputs/reduckdo.fr-preprod.json',
'inputs/reducparc.fr-preprod.json'
]

try:
while True:
print("\nQue souhaitez-vous faire ?")
print("1. Afficher tous les noms d'articles")
print("2. Afficher tous les noms de sous-genres")
print("3. Afficher tous les noms de genres")
print("4. Rechercher un sous-genre spécifique")
print("5. Quitter")

choice = input("\nVotre choix (1-4): ")

if choice == "1":
all_articles = get_article_names(file_paths)
print("\nListe des noms d'articles par source :")
for source, articles in all_articles.items():
print(f"\n{'-' * 20} {source} {'-' * 20}")
for name in articles:
print(f"- {name}")

elif choice == "2":
all_sousgenres = get_sousgenre_names(file_paths)
print("\nListe des noms de sous-genres par source :")
for source, sousgenres in all_sousgenres.items():
print(f"\n{'-' * 20} {source} {'-' * 20}")
for name in sousgenres:
print(f"- {name}")

elif choice == "3":
all_genres = get_genre_names(file_paths)
print("\nListe des noms de genres par source :")
for source, genres in all_genres.items():
print(f"\n{'-' * 20} {source} {'-' * 20}")
for name in genres:
print(f"- {name}")

elif choice == "4":
search_name = input("\nEntrez le nom du sous-genre à rechercher: ")
results = search_sousgenre_articles(file_paths, search_name)
print_sousgenre_details(results)

elif choice == "5":
print("Au revoir!")
break

else:
print("Choix invalide. Veuillez réessayer.")

except FileNotFoundError as e:
print(f"Le fichier n'a pas été trouvé: {str(e)}")
except json.JSONDecodeError as e:
print(f"Erreur lors de la lecture du fichier JSON: {str(e)}")
except Exception as e:
print(f"Une erreur est survenue : {str(e)}")

if __name__ == "__main__":
main()
136 changes: 136 additions & 0 deletions scripts/obiz/finders/sousgenre.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import json
from typing import Dict, List
from colorama import init, Fore, Style

def format_reduction(reduction: float, variable_remise: str, is_variable: str) -> str:
"""
Formate la réduction en fonction des conditions
"""
if is_variable == 'True':
return variable_remise
return f"{reduction:.1f}"


def format_price(price_str: str) -> str:
"""
Formate un prix en string avec 2 décimales et le symbole €
"""
try:
# Remplace la virgule par un point pour la conversion
price_float = float(price_str.replace(',', '.'))
# Formate le prix avec 2 décimales et le symbole €
return f"{price_float:.2f} €"
except (ValueError, AttributeError):
return "Prix non disponible"


def calculate_reduction(prix_public: str, prix_reduc: str) -> float:
"""
Calcule le pourcentage de réduction entre deux prix
"""
try:
prix_public_float = float(prix_public.replace(',', '.'))
prix_reduc_float = float(prix_reduc.replace(',', '.'))

if prix_public_float == 0:
return 0.0

reduction = ((prix_public_float - prix_reduc_float) / prix_public_float) * 100
return reduction
except (ValueError, AttributeError):
return 0.0


def search_sousgenre_articles(file_paths: List[str], sousgenre_name: str) -> Dict[str, List[Dict]]:
"""
Recherche un sous-genre par son nom dans plusieurs fichiers et retourne tous ses articles associés
"""
all_results = {}

for file_path in file_paths:
source_name = file_path.split('/')[-1].split('.')[0]

with open(file_path, 'r', encoding='utf-8') as file:
data = json.load(file)

results = []

for catalogue in data.get('catalogues', []):
for cat in catalogue.get('catalogue', []):
for genre in cat.get('genres', []):
for gen in genre.get('genre', []):
for sousgenre in gen.get('sousgenres', []):
for sg in sousgenre.get('sousgenre', []):
if sg.get('sousgenres_nom', '').lower() == sousgenre_name.lower():
sousgenre_info = {
'nom': sg.get('sousgenres_nom', ''),
'id': sg.get('sousgenres_id'),
'genre_nom': gen.get('genres_nom', ''),
'url': sg.get('sousgenres_url', ''),
'description': sg.get('sousgenres_descriptif', {}).get('#cdata-section', ''),
'articles': []
}

for articles in sg.get('articles', []):
for article in articles.get('article', []):
if article['articles_actif'] == "True":
article_info = {
'nom': article.get('articles_nom', ''),
'prix_public': article.get('articles_prix_public', ''),
'prix_reduc_ttc': article.get('articles_puttc', ''),
'variable': article.get('articles_valeur_variable', ''),
'variable_remise': article.get('articles_remise_btob', ''),
'code': article.get('articles_code', ''),
'type': article.get('articles_type', ''),
'description': article.get('articles_descriptif', {}).get(
'#cdata-section', '')
}
sousgenre_info['articles'].append(article_info)

results.append(sousgenre_info)

if results:
all_results[source_name] = results

return all_results


def print_sousgenre_details(results: Dict[str, List[Dict]]) -> None:
"""
Affiche les détails d'un sous-genre et ses articles de manière formatée pour chaque source
"""
if not results:
print("Aucun sous-genre trouvé avec ce nom dans aucune source.")
return

for source, source_results in results.items():
print(f"\n{'=' * 20} Source: {source} {'=' * 20}")

for result in source_results:
print(f"\nSous-genre: {result['nom']} (genre - {result['genre_nom']})")
print(f"ID : {result['id']}")
print(f"URL: {result['url']}")
print("\nArticles associés:")
print("-" * 30)

if not result['articles']:
print("Aucun article trouvé pour ce sous-genre.")

for article in result['articles']:
prix_public = article['prix_public']
prix_reduc = article['prix_reduc_ttc']
reduction = calculate_reduction(prix_public, prix_reduc)

formatted_reduction = format_reduction(
reduction,
article['variable_remise'],
article['variable']
)

print(f"\nNom: {Style.BRIGHT}{Fore.BLUE}{article['nom']}{Style.RESET_ALL}")
print(f"Réduction: {Style.BRIGHT}{Fore.GREEN}{formatted_reduction}%{Style.RESET_ALL}")
print(f"Valeur variable : {'Oui' if article['variable'] == 'True' else 'Non'}")
print(f"Code: {article['code']}")
print(f"Type: {article['type']}")
print(f"Prix public: {format_price(prix_public)}")
print(f"Prix avec réduc ttc : {format_price(prix_reduc)}")
Loading

0 comments on commit cdeddc9

Please sign in to comment.