#!/usr/bin/env python3 import json with open('/home/mdares/.node-red/flows.json', 'r') as f: flows = json.load(f) # Find and update complete-work-order handler for node in flows: if node.get('name') == 'Work Order buttons': func = node['func'] # Replace the complete-work-order case old_complete = '''case "complete-work-order": { msg._mode = "complete"; const order = msg.payload || {}; if (!order.id) { node.error("No work order id supplied for complete", msg); return [null, null, null, null]; } msg.completeOrder = order; // SQL with bound parameter for safety msg.topic = "UPDATE work_orders SET status = 'DONE', updated_at = NOW() WHERE work_order_id = ?"; msg.payload = [order.id]; // Clear ALL state on completion global.set("activeWorkOrder", null); global.set("trackingEnabled", false); global.set("productionStarted", false); global.set("kpiStartupMode", false); global.set("operatingTime", 0); global.set("lastCycleTime", null); global.set("cycleCount", 0); flow.set("lastMachineState", 0); global.set("scrapPromptIssuedFor", null); node.warn('[COMPLETE] Cleared all state flags'); return [null, null, null, msg]; }''' new_complete = '''case "complete-work-order": { msg._mode = "complete"; const order = msg.payload || {}; if (!order.id) { node.error("No work order id supplied for complete", msg); return [null, null, null, null]; } // Get final values from global state before clearing const activeOrder = global.get("activeWorkOrder") || {}; const finalCycleCount = Number(global.get("cycleCount") || 0); const finalGoodParts = Number(activeOrder.good) || 0; const finalScrapParts = Number(activeOrder.scrap) || 0; node.warn(`[COMPLETE] Persisting final values: cycles=${finalCycleCount}, good=${finalGoodParts}, scrap=${finalScrapParts}`); msg.completeOrder = order; // SQL: Persist final counts AND set status to DONE msg.topic = "UPDATE work_orders SET status = 'DONE', cycle_count = ?, good_parts = ?, scrap_parts = ?, progress_percent = 100, updated_at = NOW() WHERE work_order_id = ?"; msg.payload = [finalCycleCount, finalGoodParts, finalScrapParts, order.id]; // Clear ALL state on completion global.set("activeWorkOrder", null); global.set("trackingEnabled", false); global.set("productionStarted", false); global.set("kpiStartupMode", false); global.set("operatingTime", 0); global.set("lastCycleTime", null); global.set("cycleCount", 0); flow.set("lastMachineState", 0); global.set("scrapPromptIssuedFor", null); node.warn('[COMPLETE] Cleared all state flags'); return [null, null, null, msg]; }''' func = func.replace(old_complete, new_complete) node['func'] = func print("✓ Updated complete-work-order to persist final counts") break # Write back with open('/home/mdares/.node-red/flows.json', 'w') as f: json.dump(flows, f, indent=4) print("✓ flows.json updated successfully")