214 lines
5.9 KiB
JavaScript
214 lines
5.9 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Patches flows_may_4_26.json:
|
|
* - Apply settings: pass reasonCode/active in catalog; 3 outputs; trigger MySQL mirror sync
|
|
* - New nodes: Build reason catalog mirror SQL → mysql
|
|
*/
|
|
import { readFileSync, writeFileSync } from "fs";
|
|
|
|
const path = new URL("../flows_may_4_26.json", import.meta.url).pathname;
|
|
const j = JSON.parse(readFileSync(path, "utf8"));
|
|
|
|
const applyId = "abbec199700a5e29";
|
|
const gateId = "f8e0d1c2b3a40911";
|
|
const mysqlPersistId = "f8e0d1c2b3a40912";
|
|
|
|
const apply = j.find((n) => n.id === applyId);
|
|
if (!apply || apply.type !== "function") {
|
|
console.error("Apply settings node not found");
|
|
process.exit(1);
|
|
}
|
|
|
|
const oldDetails =
|
|
"const details = detailsRaw.map((d, jdx) => ({\n id: String(d.id || d.detailId || (categoryId + \"_d\" + jdx)),\n label: String(d.label || d.detailLabel || (\"Detalle \" + (jdx + 1)))\n }));";
|
|
|
|
const newDetails = `const details = detailsRaw.map((d, jdx) => {
|
|
const row = {
|
|
id: String(d.id || d.detailId || (categoryId + "_d" + jdx)),
|
|
label: String(d.label || d.detailLabel || ("Detalle " + (jdx + 1)))
|
|
};
|
|
if (d.reasonCode != null && String(d.reasonCode).trim()) {
|
|
row.reasonCode = String(d.reasonCode).trim();
|
|
} else if (d.code != null && String(d.code).trim()) {
|
|
row.reasonCode = String(d.code).trim();
|
|
}
|
|
if (d.active === false) {
|
|
row.active = false;
|
|
}
|
|
return row;
|
|
});`;
|
|
|
|
if (!apply.func.includes(oldDetails)) {
|
|
console.error("Expected normalizeCatalog details snippet not found; abort.");
|
|
process.exit(1);
|
|
}
|
|
apply.func = apply.func.replace(oldDetails, newDetails);
|
|
|
|
apply.func = apply.func.replaceAll("node.send([uiConfigMsg, null]);", "node.send([uiConfigMsg, null, null]);");
|
|
apply.func = apply.func.replaceAll("node.send([uiMoldMsg, null]);", "node.send([uiMoldMsg, null, null]);");
|
|
apply.func = apply.func.replaceAll("node.send([uiReadOnlyMsg, null]);", "node.send([uiReadOnlyMsg, null, null]);");
|
|
apply.func = apply.func.replaceAll("node.send([uiReasonCatalogMsg, null]);", "node.send([uiReasonCatalogMsg, null, null]);");
|
|
|
|
const oldReturnAck = `const ackMsg = {
|
|
topic: ackTopic,
|
|
payload: JSON.stringify({
|
|
type: "settings_ack",
|
|
orgId,
|
|
machineId,
|
|
version,
|
|
source: "node-red",
|
|
ts: new Date().toISOString()
|
|
})
|
|
};
|
|
|
|
return [null, ackMsg];
|
|
`;
|
|
|
|
const newReturnAck = `const ackMsg = {
|
|
topic: ackTopic,
|
|
payload: JSON.stringify({
|
|
type: "settings_ack",
|
|
orgId,
|
|
machineId,
|
|
version,
|
|
source: "node-red",
|
|
ts: new Date().toISOString()
|
|
})
|
|
};
|
|
|
|
const mirrorTrigger = { payload: { _syncReasonCatalog: true } };
|
|
return [null, ackMsg, mirrorTrigger];
|
|
`;
|
|
|
|
if (!apply.func.includes(oldReturnAck.trim())) {
|
|
console.error("Expected ack return block not found");
|
|
process.exit(1);
|
|
}
|
|
apply.func = apply.func.replace(oldReturnAck.trim(), newReturnAck.trim());
|
|
|
|
apply.func = apply.func.replace(
|
|
`if (!orgId || !machineId) {
|
|
return [null, null];
|
|
}`,
|
|
`if (!orgId || !machineId) {
|
|
return [null, null, null];
|
|
}`
|
|
);
|
|
|
|
apply.outputs = 3;
|
|
apply.wires = [
|
|
["2c8562b2471078ab", "dbfd127c516efa87", "9748899355370bae"],
|
|
[],
|
|
[gateId],
|
|
];
|
|
|
|
const gateFunc = `const p = msg.payload || {};
|
|
if (!p._syncReasonCatalog) {
|
|
return null;
|
|
}
|
|
const settings = global.get("settings") || {};
|
|
const cat = settings.reasonCatalog || {};
|
|
const ver = Number(cat.version || 1);
|
|
function esc(v) {
|
|
return String(v ?? "").replace(/\\\\/g, "\\\\\\\\").replace(/'/g, "''");
|
|
}
|
|
const parts = [];
|
|
function walk(kind, list) {
|
|
if (!Array.isArray(list)) {
|
|
return;
|
|
}
|
|
let sort = 0;
|
|
list.forEach((c) => {
|
|
const categoryId = esc(String(c.id || ""));
|
|
const categoryLabel = esc(String(c.label || ""));
|
|
const ch = c.children || c.details || [];
|
|
if (!Array.isArray(ch)) {
|
|
return;
|
|
}
|
|
ch.forEach((d) => {
|
|
const id = String(d.id || "").trim();
|
|
const label = String(d.label || "").trim();
|
|
const rc = String(d.reasonCode || d.code || id || "").trim();
|
|
if (!rc) {
|
|
return;
|
|
}
|
|
const active = d.active === false ? 0 : 1;
|
|
parts.push(
|
|
"('" +
|
|
kind +
|
|
"','" +
|
|
categoryId +
|
|
"','" +
|
|
categoryLabel +
|
|
"','" +
|
|
esc(rc) +
|
|
"','" +
|
|
esc(label) +
|
|
"'," +
|
|
sort +
|
|
"," +
|
|
active +
|
|
"," +
|
|
ver +
|
|
")"
|
|
);
|
|
sort += 1;
|
|
});
|
|
});
|
|
}
|
|
walk("downtime", cat.downtime || []);
|
|
walk("scrap", cat.scrap || []);
|
|
if (!parts.length) {
|
|
node.status({ fill: "yellow", shape: "ring", text: "No reason rows to mirror" });
|
|
return null;
|
|
}
|
|
const sql =
|
|
"INSERT INTO reason_catalog_row (kind,category_id,category_label,reason_code,reason_label,sort_order,active,catalog_version) VALUES " +
|
|
parts.join(",") +
|
|
" ON DUPLICATE KEY UPDATE category_id=VALUES(category_id),category_label=VALUES(category_label),reason_label=VALUES(reason_label),sort_order=VALUES(sort_order),active=VALUES(active),catalog_version=VALUES(catalog_version),updated_at=CURRENT_TIMESTAMP(3)";
|
|
node.status({ fill: "green", shape: "dot", text: "Reason mirror SQL built" });
|
|
msg.topic = sql;
|
|
msg.payload = [];
|
|
return msg;
|
|
`;
|
|
|
|
const gateNode = {
|
|
id: gateId,
|
|
type: "function",
|
|
z: "05d4cb231221b842",
|
|
g: "a1b43a9e095c10db",
|
|
name: "Build reason catalog mirror SQL",
|
|
func: gateFunc,
|
|
outputs: 1,
|
|
timeout: 0,
|
|
noerr: 0,
|
|
initialize: "",
|
|
finalize: "",
|
|
libs: [],
|
|
x: 1500,
|
|
y: 1020,
|
|
wires: [[mysqlPersistId]],
|
|
};
|
|
|
|
const mysqlNode = {
|
|
id: mysqlPersistId,
|
|
type: "mysql",
|
|
z: "05d4cb231221b842",
|
|
g: "a1b43a9e095c10db",
|
|
mydb: "fc9634aabefee16b",
|
|
name: "Persist reason catalog mirror",
|
|
x: 1820,
|
|
y: 1020,
|
|
wires: [[]],
|
|
};
|
|
|
|
if (j.some((n) => n.id === gateId)) {
|
|
console.log("Patch already applied (gate node exists). Skipping insert.");
|
|
} else {
|
|
const idx = j.findIndex((n) => n.id === applyId);
|
|
j.splice(idx + 1, 0, gateNode, mysqlNode);
|
|
}
|
|
|
|
writeFileSync(path, JSON.stringify(j, null, 4) + "\n");
|
|
console.log("Patched", path);
|