from typing import List import streamlit as st from utils.translations import _ import networkx as nx from utils.persistance import supprime_champ_statut, get_champ_statut, maj_champ_statut def get_produits_personnalises( G: nx.DiGraph ) -> List[str]: """ Récupère la liste des produits personnalisés du niveau 0. Args: G (Any): Le graphe NetworkX contenant les données des produits. Returns: List[str]: Liste triée des noms de produits. """ return sorted([n for n, d in G.nodes(data=True) if d.get("niveau") == "0" and d.get("personnalisation") == "oui"]) def supprimer_produit( G: nx.DiGraph, prod: str ) -> nx.DiGraph: """ Supprime un produit du graphe et affiche le message de succès. Args: G (Any): Le graphe NetworkX sur lequel supprimer le produit. prod (str): Le nom du produit à supprimer. """ G.remove_node(prod) st.success(f"{prod} {str(_('pages.personnalisation.deleted'))}") st.session_state.pop("prod_sel", None) st.rerun() return G def get_operations_disponibles( G: nx.DiGraph ) -> List[str]: """ Récupère la liste des opérations d'assemblage disponibles. Args: G (Any): Le graphe NetworkX contenant les données des produits et des opérations. Returns: List[str]: Liste triée des noms des opérations. """ return sorted([ n for n, d in G.nodes(data=True) if d.get("niveau") == "10" and any(G.has_edge(p, n) and G.nodes[p].get("niveau") == "0" for p in G.predecessors(n)) ]) def get_operations_actuelles( G: nx.DiGraph, prod: str ) -> List[str]: """ Récupère les opérations actuellement liées au produit. Args: G (nx.DiGraph): Le graphe NetworkX contenant les données des produits et des opérations. prod (str): Le nom du produit dont récupérer les opérations. Returns: List[str]: Liste des noms des opérations actuelles. """ return [succ for succ in G.successors(prod) if G.nodes[succ].get("niveau") == "10"] def get_composants_niveau1( G: nx.DiGraph ) -> List[str]: """ Récupère la liste des composants de niveau 1. Args: G (nx.DiGraph): Le graphe NetworkX contenant les données des produits et des composants. Returns: List[str]: Liste triée des noms des composants. """ return sorted([n for n, d in G.nodes(data=True) if d.get("niveau") == "1"]) def get_composants_lies( G: nx.DiGraph, prod: str ) -> List[str]: """ Récupère les composants actuellement liés au produit. Args: G (nx.DiGraph): Le graphe NetworkX contenant les données des produits et des composants. prod (str): Le nom du produit dont récupérer les composants. Returns: List[str]: Liste des noms des composants liés. """ return [succ for succ in G.successors(prod) if G.nodes[succ].get("niveau") == "1"] def mettre_a_jour_operations( G: nx.DiGraph, prod: str, curr_ops: List[str], sel_op: str ) -> nx.DiGraph: """ Met à jour les opérations liées au produit. Args: G (Any): Le graphe NetworkX contenant les données des produits et des opérations. prod (str): Le nom du produit dont mettre à jour les opérations. curr_ops (List[str]): Liste actuelle des opérations liées. sel_op (str): L'opération sélectionnée pour mise à jour. Notes: Cette fonction crée ou supprime les liens entre le produit et les opérations selon la sélection effectuée par l'utilisateur. """ none_option = str(_("pages.personnalisation.none")) for op in curr_ops: if sel_op == none_option or op != sel_op: G.remove_edge(prod, op) if sel_op != none_option and (not curr_ops or sel_op not in curr_ops): G.add_edge(prod, sel_op) return G def mettre_a_jour_composants( G: nx.DiGraph, prod: str, linked: List[str], nouveaux: List[str] ) -> nx.DiGraph: """ Met à jour les composants liés au produit. Args: G (nx.DiGraph): Le graphe NetworkX contenant les données des produits et des composants. prod (str): Le nom du produit dont mettre à jour les composants. linked (List[str]): Liste actuelle des composants liés. nouveaux (List[str]): Nouvelle liste de composants à lier. Notes: Cette fonction crée ou supprime les liens entre le produit et les composants selon la sélection effectuée par l'utilisateur. """ """Met à jour les composants liés au produit.""" for comp in set(linked) - set(nouveaux): G.remove_edge(prod, comp) for comp in set(nouveaux) - set(linked): G.add_edge(prod, comp) return G def modifier_produit( G: nx.DiGraph ) -> nx.DiGraph: """ Méthode de personnalisation qui permet à l'utilisateur d'ajuster un produit. Args: G (Any): Le graphe NetworkX sur lequel modifier les produits et leurs composants. Contient des données concernant la personalisation des produits, leur niveau, et les opérations liées. Notes: Cette fonction fournit une interface utilisateur pour sélectionner un produit à personnaliser, gérer ses composants, et définir ses opérations d'assemblage. Elle implémente la logique de mise à jour des connexions entre les différents éléments du graphe. """ st.markdown(f"## {str(_('pages.personnalisation.modify_product'))}") # Restauration des produits personnalisés sauvegardés if "pages.personnalisation.create_product.fait" not in st.session_state and get_champ_statut("pages.personnalisation.create_product.fait") == "oui": index = 0 while True: new_prod = get_champ_statut(f"pages.personnalisation.create_product.{index}.nom") if new_prod == "": break G.add_node(new_prod, niveau="0", personnalisation="oui", label=new_prod) sel_new_op = get_champ_statut(f"pages.personnalisation.create_product.{index}.edge") if sel_new_op: G.add_edge(new_prod, sel_new_op) i = 0 while True: comp = get_champ_statut(f"pages.personnalisation.create_product.{index}.composants.{i}") if comp == "": break G.add_edge(new_prod, comp) i += 1 index += 1 st.session_state["pages.personnalisation.create_product.fait"] = "oui" # Sélection du produit à modifier produits0 = get_produits_personnalises(G) # Restaurer la sélection du produit depuis la persistance if "pages.personnalisation.modify.selected_product" not in st.session_state: st.session_state["pages.personnalisation.modify.selected_product"] = get_champ_statut("pages.personnalisation.modify.selected_product") sel_display = st.selectbox( label=str(_("pages.personnalisation.products_to_modify")), options=produits0, key="pages.personnalisation.modify.selected_product" ) if sel_display: maj_champ_statut("pages.personnalisation.modify.selected_product", sel_display) if not sel_display: return G # Obtention du produit sélectionné prod = sel_display # Trouver l'index du produit dans la sauvegarde index_key = None index = 0 while True: saved_name = get_champ_statut(f"pages.personnalisation.create_product.{index}.nom") if saved_name == "": break if saved_name == prod: index_key = index break index += 1 # Suppression du produit si demandé if st.button(f"{str(_('pages.personnalisation.delete'))} {prod}"): if index_key is not None: # Supprimer les données du produit supprime_champ_statut(f"pages.personnalisation.create_product.{index_key}.nom") supprime_champ_statut(f"pages.personnalisation.create_product.{index_key}.edge") supprime_champ_statut(f"pages.personnalisation.create_product.{index_key}.composants") # Réorganiser les indices pour combler le trou next_index = index_key + 1 while get_champ_statut(f"pages.personnalisation.create_product.{next_index}.nom") != "": # Déplacer le produit suivant vers l'index actuel nom = get_champ_statut(f"pages.personnalisation.create_product.{next_index}.nom") edge = get_champ_statut(f"pages.personnalisation.create_product.{next_index}.edge") maj_champ_statut(f"pages.personnalisation.create_product.{next_index - 1}.nom", nom) if edge: maj_champ_statut(f"pages.personnalisation.create_product.{next_index - 1}.edge", edge) else: supprime_champ_statut(f"pages.personnalisation.create_product.{next_index - 1}.edge") # Copier les composants i = 0 while True: comp = get_champ_statut(f"pages.personnalisation.create_product.{next_index}.composants.{i}") if comp == "": break maj_champ_statut(f"pages.personnalisation.create_product.{next_index - 1}.composants.{i}", comp) i += 1 # Supprimer l'ancien emplacement supprime_champ_statut(f"pages.personnalisation.create_product.{next_index}") next_index += 1 # Nettoyer aussi les champs de modification supprime_champ_statut("pages.personnalisation.modify") if "pages.personnalisation.modify.selected_product" in st.session_state: del st.session_state["pages.personnalisation.modify.selected_product"] if "pages.personnalisation.modify.selected_operation" in st.session_state: del st.session_state["pages.personnalisation.modify.selected_operation"] if "pages.personnalisation.modify.selected_components" in st.session_state: del st.session_state["pages.personnalisation.modify.selected_components"] return supprimer_produit(G, prod) # Gestion des opérations d'assemblage ops_dispo = get_operations_disponibles(G) curr_ops = get_operations_actuelles(G, prod) # Restaurer la sélection de l'opération depuis la persistance if "pages.personnalisation.modify.selected_operation" not in st.session_state: saved_op = get_champ_statut("pages.personnalisation.modify.selected_operation") if saved_op and saved_op in [str(_("pages.personnalisation.none"))] + ops_dispo: st.session_state["pages.personnalisation.modify.selected_operation"] = saved_op else: default_op = curr_ops[0] if curr_ops else str(_("pages.personnalisation.none")) st.session_state["pages.personnalisation.modify.selected_operation"] = default_op sel_op = st.selectbox( str(_("pages.personnalisation.linked_assembly_operation")), [str(_("pages.personnalisation.none"))] + ops_dispo, key="pages.personnalisation.modify.selected_operation" ) if sel_op: maj_champ_statut("pages.personnalisation.modify.selected_operation", sel_op) # Gestion des composants niveau1 = get_composants_niveau1(G) linked = get_composants_lies(G, prod) # Restaurer la sélection des composants depuis la persistance if "pages.personnalisation.modify.selected_components" not in st.session_state: saved_comps = [] i = 0 while True: comp = get_champ_statut(f"pages.personnalisation.modify.selected_components.{i}") if comp == "": break if comp in niveau1: saved_comps.append(comp) i += 1 st.session_state["pages.personnalisation.modify.selected_components"] = saved_comps if saved_comps else linked nouveaux = st.multiselect( f"{str(_('pages.personnalisation.components_linked_to'))} {prod}", options=niveau1, key="pages.personnalisation.modify.selected_components" ) if nouveaux: supprime_champ_statut("pages.personnalisation.modify.selected_components") for i, comp in enumerate(nouveaux): maj_champ_statut(f"pages.personnalisation.modify.selected_components.{i}", comp) # Mise à jour des liens si demandé if st.button(f"{str(_('pages.personnalisation.update'))} {prod}"): G = mettre_a_jour_operations(G, prod, curr_ops, sel_op) if index_key is not None: if sel_op != str(_("pages.personnalisation.none")): maj_champ_statut(f"pages.personnalisation.create_product.{index_key}.edge", sel_op) else: supprime_champ_statut(f"pages.personnalisation.create_product.{index_key}.edge") G = mettre_a_jour_composants(G, prod, linked, nouveaux) if index_key is not None: if nouveaux: supprime_champ_statut(f"pages.personnalisation.create_product.{index_key}.composants") for j, comp in enumerate(nouveaux): maj_champ_statut(f"pages.personnalisation.create_product.{index_key}.composants.{j}", comp) else: supprime_champ_statut(f"pages.personnalisation.create_product.{index_key}.composants") st.success(f"{prod} {str(_('pages.personnalisation.updated'))}") # Forcer la sauvegarde de l'état maj_champ_statut("pages.personnalisation.create_product.fait", "oui") return G