This repository has been archived on 2026-03-21. You can view files and clone it, but cannot push or open issues or pull requests.
payfrit-biz/api/admin/_scripts/migrateModifierTemplates.cfm
John 16a3b7c9a3 Replace queryExecute with queryTimed across all endpoints for perf tracking
Converts 200+ endpoint files to use queryTimed() wrapper which tracks
DB query count and execution time. Restores perf dashboard files that
were accidentally moved to _scripts/. Includes portal UI updates.
2026-02-02 00:28:37 -08:00

186 lines
6.8 KiB
Text

<cfsetting showdebugoutput="false">
<cfsetting enablecfoutputonly="true">
<cfcontent type="application/json; charset=utf-8" reset="true">
<!--- Only allow from localhost --->
<cfif NOT (cgi.remote_addr EQ "127.0.0.1" OR cgi.remote_addr EQ "::1" OR findNoCase("localhost", cgi.server_name))>
<cfoutput>#serializeJSON({"OK": false, "ERROR": "admin_only"})#</cfoutput>
<cfabort>
</cfif>
<cfscript>
/**
* Migrate Modifier Templates for In and Out Burger (BusinessID=1)
*
* This script:
* 1. Identifies unique modifier trees (children of parent items)
* 2. Keeps ONE instance of each unique modifier name as the template
* 3. Links all parent items to these templates
* 4. Reports which duplicate items can be deleted
*/
response = { "OK": false, "steps": [], "templates": [], "links": [], "orphans": [] };
try {
businessID = 17; // In and Out Burger
// Step 1: Get all parent items (burgers, combos, etc.)
qParentItems = queryTimed("
SELECT i.ID, i.Name
FROM Items i
INNER JOIN Categories c ON c.ID = i.CategoryID
WHERE c.BusinessID = :businessID
AND i.ParentItemID = 0
AND i.IsActive = 1
ORDER BY i.Name
", { businessID: businessID }, { datasource: "payfrit" });
arrayAppend(response.steps, "Found " & qParentItems.recordCount & " parent items");
// Step 2: Get all direct children (level 1 modifiers) of parent items
qModifiers = queryTimed("
SELECT
m.ItemID,
m.Name,
m.ParentItemID,
m.Price,
m.IsCheckedByDefault,
m.SortOrder,
p.Name as ParentName
FROM Items m
INNER JOIN Items p ON p.ItemID = m.ParentItemID
INNER JOIN Categories c ON c.ID = p.CategoryID
WHERE c.BusinessID = :businessID
AND m.ParentItemID > 0
AND m.IsActive = 1
AND p.ParentItemID = 0
ORDER BY m.Name, m.ItemID
", { businessID: businessID }, { datasource: "payfrit" });
arrayAppend(response.steps, "Found " & qModifiers.recordCount & " level-1 modifiers");
// Step 3: Group modifiers by name to find duplicates
modifiersByName = {};
for (mod in qModifiers) {
modName = mod.Name;
if (!structKeyExists(modifiersByName, modName)) {
modifiersByName[modName] = [];
}
arrayAppend(modifiersByName[modName], {
"ItemID": mod.ItemID,
"ParentItemID": mod.ParentItemID,
"ParentName": mod.ParentName,
"Price": mod.Price,
"IsDefault": mod.IsCheckedByDefault,
"SortOrder": mod.SortOrder
});
}
// Step 4: For each unique modifier name, pick ONE as the template
// Keep the first occurrence (usually oldest/original)
templateMap = {}; // modifierName -> templateItemID
orphanItems = []; // Items to delete later
for (modName in modifiersByName) {
instances = modifiersByName[modName];
if (arrayLen(instances) > 1) {
// Multiple instances - first one becomes template
templateItem = instances[1];
templateItemID = templateItem.ItemID;
// Mark as template
queryTimed("
UPDATE Items SET IsModifierTemplate = 1 WHERE ItemID = :itemID
", { itemID: templateItemID }, { datasource: "payfrit" });
templateMap[modName] = templateItemID;
arrayAppend(response.templates, {
"name": modName,
"templateItemID": templateItemID,
"originalParent": templateItem.ParentName,
"duplicateCount": arrayLen(instances) - 1
});
// Create links for ALL parent items that had this modifier
for (i = 1; i <= arrayLen(instances); i++) {
inst = instances[i];
parentItemID = inst.ParentItemID;
// Insert link (ignore duplicates)
try {
queryTimed("
INSERT INTO lt_ItemID_TemplateItemID (ItemID, TemplateItemID, SortOrder)
VALUES (:itemID, :templateID, :sortOrder)
ON DUPLICATE KEY UPDATE SortOrder = :sortOrder
", {
itemID: parentItemID,
templateID: templateItemID,
sortOrder: inst.SortOrder
}, { datasource: "payfrit" });
arrayAppend(response.links, {
"parentItemID": parentItemID,
"parentName": inst.ParentName,
"templateItemID": templateItemID,
"templateName": modName
});
} catch (any linkErr) {
// Link already exists, ignore
}
// Mark duplicates (not the template) as orphans
if (i > 1) {
arrayAppend(orphanItems, {
"ItemID": inst.ItemID,
"Name": modName,
"WasUnder": inst.ParentName
});
}
}
} else {
// Single instance - still mark as template for consistency
singleItem = instances[1];
queryTimed("
UPDATE Items SET IsModifierTemplate = 1 WHERE ItemID = :itemID
", { itemID: singleItem.ItemID }, { datasource: "payfrit" });
// Create link
queryTimed("
INSERT INTO lt_ItemID_TemplateItemID (ItemID, TemplateItemID, SortOrder)
VALUES (:itemID, :templateID, :sortOrder)
ON DUPLICATE KEY UPDATE SortOrder = :sortOrder
", {
itemID: singleItem.ParentItemID,
templateID: singleItem.ItemID,
sortOrder: singleItem.SortOrder
}, { datasource: "payfrit" });
arrayAppend(response.templates, {
"name": modName,
"templateItemID": singleItem.ItemID,
"originalParent": singleItem.ParentName,
"duplicateCount": 0
});
}
}
response["orphans"] = orphanItems;
response["orphanCount"] = arrayLen(orphanItems);
response["templateCount"] = arrayLen(response.templates);
response["linkCount"] = arrayLen(response.links);
arrayAppend(response.steps, "Created " & arrayLen(response.templates) & " templates");
arrayAppend(response.steps, "Created " & arrayLen(response.links) & " links");
arrayAppend(response.steps, "Identified " & arrayLen(orphanItems) & " orphan items for deletion");
response["OK"] = true;
} catch (any e) {
response["ERROR"] = e.message;
response["DETAIL"] = e.detail;
}
writeOutput(serializeJSON(response));
</cfscript>