#!/usr/bin/env python3 import json import uuid # Read flows.json with open('/home/mdares/.node-red/flows.json', 'r') as f: flows = json.load(f) # Function code for the new Progress Check Handler node progress_handler_func = """// Handle DB result from start-work-order progress check if (msg._mode === "start-check-progress") { const order = flow.get("pendingWorkOrder"); if (!order || !order.id) { node.error("No pending work order found", msg); return [null, null]; } // Get progress from DB query result const dbRow = (Array.isArray(msg.payload) && msg.payload.length > 0) ? msg.payload[0] : null; const cycleCount = dbRow ? (Number(dbRow.cycle_count) || 0) : 0; const goodParts = dbRow ? (Number(dbRow.good_parts) || 0) : 0; const targetQty = dbRow ? (Number(dbRow.target_qty) || 0) : (Number(order.target) || 0); node.warn(`[PROGRESS-CHECK] WO ${order.id}: cycles=${cycleCount}, good=${goodParts}, target=${targetQty}`); // Check if work order has existing progress if (cycleCount > 0 || goodParts > 0) { // Work order has progress - send prompt to UI node.warn(`[PROGRESS-CHECK] Work order has existing progress - sending prompt to UI`); const promptMsg = { _mode: "resume-prompt", topic: "resumePrompt", payload: { id: order.id, sku: order.sku || "", cycleCount: cycleCount, goodParts: goodParts, targetQty: targetQty, progressPercent: targetQty > 0 ? Math.round((goodParts / targetQty) * 100) : 0, // Include full order object for resume/restart actions order: {...order, cycle_count: cycleCount, good_parts: goodParts} } }; return [null, promptMsg]; } else { // No existing progress - proceed with normal start node.warn(`[PROGRESS-CHECK] No existing progress - proceeding with normal start`); // Simulate the original start-work-order behavior const startMsg = { _mode: "start", startOrder: order, topic: "UPDATE work_orders SET status = CASE WHEN work_order_id = ? THEN 'RUNNING' ELSE 'PENDING' END, updated_at = CASE WHEN work_order_id = ? THEN NOW() ELSE updated_at END WHERE status <> 'DONE'", payload: [order.id, order.id] }; global.set("activeWorkOrder", order); global.set("cycleCount", 0); flow.set("lastMachineState", 0); global.set("scrapPromptIssuedFor", null); return [startMsg, null]; } } // Pass through all other messages return [msg, null];""" # Create new Progress Check Handler function node new_node_id = "progress_check_handler_node" new_node = { "id": new_node_id, "type": "function", "z": "cac3a4383120cb57", "g": "b7ab5e0cc02b9508", "name": "Progress Check Handler", "func": progress_handler_func, "outputs": 2, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1090, "y": 340, "wires": [ ["578c92e75bf0f266"], # Output 1: To Refresh Trigger (for normal flow) ["f2bab26e27e2023d"] # Output 2: To Back to UI (for resume prompt) ] } # Update mariaDB node to output to Progress Check Handler instead of Refresh Trigger for node in flows: if node.get('id') == 'f6ad294bc02618c9' and node.get('name') == 'mariaDB': # Change wires to point to new Progress Check Handler node['wires'] = [[new_node_id]] print(f"Updated mariaDB node to output to Progress Check Handler") break # Also update Refresh Trigger function to handle resume/restart modes for node in flows: if node.get('id') == '578c92e75bf0f266' and node.get('name') == 'Refresh Trigger': # Update function to handle resume and restart modes updated_refresh_func = """if (msg._mode === "start" || msg._mode === "complete" || msg._mode === "resume" || msg._mode === "restart") { // Preserve original message for Back to UI (output 2) const originalMsg = {...msg}; // Create select message for refreshing WO table (output 1) msg._mode = "select"; msg.topic = "SELECT * FROM work_orders ORDER BY updated_at DESC;"; return [msg, originalMsg]; } if (msg._mode === "cycle" || msg._mode === "production-state") { return [null, msg]; } if (msg._mode === "scrap-prompt") { return [null, msg]; } if (msg._mode === "restore-query") { // Pass restore query results to Back to UI return [null, msg]; } if (msg._mode === "current-state") { // Pass current state to Back to UI return [null, msg]; } if (msg._mode === "scrap-complete") { // Preserve original message for Back to UI (output 2) const originalMsg = {...msg}; // Create select message for refreshing WO table (output 1) msg._mode = "select"; msg.topic = "SELECT * FROM work_orders ORDER BY updated_at DESC;"; return [msg, originalMsg]; } return [null, msg];""" node['func'] = updated_refresh_func print(f"Updated Refresh Trigger function to handle resume/restart") break # Add the new node to flows flows.append(new_node) print(f"Added Progress Check Handler node") # Write back to flows.json with open('/home/mdares/.node-red/flows.json', 'w') as f: json.dump(flows, f, indent=4) print("flows.json updated successfully with Progress Check Handler")