from django.db import transaction from app.models import Workflow, StepAction, Rule from app.workflow_registry import ACTION_REGISTRY, validate_action_schema from app.workflow_utils import resolve_value @transaction.atomic def execute_step(step: StepAction, context: dict): #print(f"\n>>> EXECUTING STEP: {step.step_code} (Order: {step.order})") # Evaluate rules first for rule in step.rules.filter(is_active=True): if not evaluate_rule(rule, context): #print(f"Step {step.step_code} skipped due to rule failure.") return {"step": step.step_code, "skipped": True, "reason": "rule_failed"} results = [] # Lưu ý: step.actions thường là một list các dict actions_list = step.actions if isinstance(step.actions, list) else [] for action in actions_list: action_type = action.get("type") params = action.get("params", {}) #print(f" - Action Type: {action_type}") if action_type not in ACTION_REGISTRY: #print(f" - ERROR: Action type '{action_type}' not registered!") continue try: validate_action_schema(action_type, params) handler = ACTION_REGISTRY[action_type] # Thực thi handler output = handler(params, context) results.append({"action": action_type, "result": output}) # Lưu output cuối cùng vào context context["last_result"] = output except Exception as e: #print(f" - ERROR in action {action_type}: {str(e)}") # Raise để transaction.atomic rollback nếu cần, hoặc xử lý tùy ý raise e return {"step": step.step_code, "executed": True, "results": results} def evaluate_rule(rule: Rule, context: dict): for condition in (rule.conditions or []): left = resolve_value(condition.get("left"), context) right = resolve_value(condition.get("right"), context) op = condition.get("operator", "==") #print(f" Evaluating Rule: {left} {op} {right}") if op == "IN" and left not in right: return False if op == "==" and left != right: return False if op == "!=" and left == right: return False if op == ">" and not (left > right): return False if op == "<" and not (left < right): return False return True def run_workflow(workflow_code: str, trigger: str, context: dict): #print(f"\n================ START WORKFLOW: {workflow_code} ================") #print(f"Trigger: {trigger} | Initial Context: {context}") workflow = Workflow.objects.filter(code=workflow_code, is_active=True).first() if not workflow: #print(f"Workflow '{workflow_code}' not found or inactive.") raise Exception(f"Workflow '{workflow_code}' not found") steps = workflow.steps.filter(trigger_event=trigger, is_active=True).order_by("order") #print(f"Found {steps.count()} active steps.") outputs = [] for step in steps: res = execute_step(step, context) outputs.append(res) #print(f"================ FINISH WORKFLOW: {workflow_code} ================\n") return outputs