import db from .compute_operation import compute_new_value def apply_data_action(slug, action): """Exécute au moment du clic (mode jouable) une action "modifier_donnee" : lit l'objet/la ligne/le champ visés dans l'action, calcule la nouvelle valeur selon l'opération choisie, et l'enregistre — un vrai UPDATE SQL, limité à cette seule colonne (les autres champs de la ligne ne sont pas touchés).""" definition_id = action.get("target_definition_id") row_id = action.get("target_row_id") field_name = action.get("target_field") operation = action.get("data_operation") raw_value = action.get("data_value") if not (definition_id and row_id and field_name and operation): return False definition = db.get_definition(slug, definition_id) if not definition: return False field_def = next((f for f in definition["fields"] if f["name"] == field_name), None) if not field_def: return False row = db.get_row(slug, definition, row_id) if not row: return False col = db.slugify(field_def["name"]).replace("-", "_") if field_def["type"] == "relation": col = col + "_id" current = row.get(col) try: new_value = compute_new_value(operation, current, raw_value, field_def["type"] == "nombre_decimal") except ValueError: return False new_value = _clamp_to_field_bounds(new_value, field_def) db.update_row_field(slug, definition, row_id, field_def, new_value) return True def _clamp_to_field_bounds(value, field_def): """2.2 — bornage automatique : ramène la valeur dans [min_value, max_value] si l'un ou l'autre est réglé sur ce champ, pour qu'une jauge (voir render_jauge.py) ne puisse jamais dépasser 100 % ni descendre sous 0 % (ou toute autre borne définie), quel que soit le nombre d'actions "Augmenter de..."/"Diminuer de..." posées dans le graphe de logique. Ne s'applique qu'aux champs numériques — un champ non numérique n'a pas de min_value/max_value (voir create_definition).""" if field_def["type"] not in ("nombre_entier", "nombre_decimal"): return value min_v, max_v = field_def.get("min_value"), field_def.get("max_value") if min_v is not None and value < min_v: value = min_v if max_v is not None and value > max_v: value = max_v return value if field_def["type"] == "nombre_decimal" else int(value)