payfrit-works/api/admin/fixShakeFlavors.cfm
John Mizerek 51a80b537d Add local dev support and fix menu builder API
Portal local development:
- Add BASE_PATH detection to all portal files (login, portal.js, menu-builder, station-assignment)
- Allows portal to work at /biz.payfrit.com/ path locally

Menu Builder fixes:
- Fix duplicate template options in getForBuilder.cfm query
- Filter template children by business ID with DISTINCT

New APIs:
- api/portal/myBusinesses.cfm - List businesses for logged-in user
- api/stations/list.cfm - List KDS stations
- api/menu/updateStations.cfm - Update item station assignments
- api/setup/reimportBigDeans.cfm - Full Big Dean's menu import script

Admin utilities:
- Various debug and migration scripts for menu/template management
- Beacon switching, category cleanup, modifier template setup

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 22:47:12 -08:00

159 lines
4.9 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>
/**
* Fix Real Ice Cream Shake modifier structure
*
* Current (wrong):
* Real Ice Cream Shake (5808)
* ├── Chocolate (6294) - marked as template
* ├── Strawberry (6292) - marked as template
* └── Vanilla (6293) - marked as template
*
* Correct:
* Real Ice Cream Shake (5808)
* └── Choose Flavor (NEW - modifier group, REQUIRED)
* ├── Chocolate
* ├── Strawberry
* └── Vanilla
*
* Steps:
* 1. Create "Choose Flavor" modifier group under Shake (5808)
* 2. Re-parent the three flavors under the new group
* 3. Remove template flag from flavors
* 4. Mark "Choose Flavor" as the template
* 5. Create ItemTemplateLinks entry for Shake -> Choose Flavor
* 6. Set ItemRequiresChildSelection=1 on the shake item
*/
response = { "OK": false, "steps": [] };
try {
shakeItemID = 5808;
chocolateID = 6294;
strawberryID = 6292;
vanillaID = 6293;
categoryID = 46; // Fries and Shakes
// Step 1: Create "Choose Flavor" modifier group under Shake
queryExecute("
INSERT INTO Items (
ItemCategoryID,
ItemName,
ItemDescription,
ItemParentItemID,
ItemPrice,
ItemIsActive,
ItemIsCheckedByDefault,
ItemRequiresChildSelection,
ItemMaxNumSelectionReq,
ItemIsCollapsible,
ItemSortOrder,
ItemIsModifierTemplate,
ItemAddedOn
) VALUES (
:categoryID,
'Choose Flavor',
'',
:shakeItemID,
0,
1,
0,
1,
1,
1,
0,
1,
NOW()
)
", {
categoryID: categoryID,
shakeItemID: shakeItemID
}, { datasource: "payfrit" });
// Get the new Choose Flavor ID
qNewGroup = queryExecute("
SELECT ItemID FROM Items
WHERE ItemName = 'Choose Flavor'
AND ItemParentItemID = :shakeItemID
ORDER BY ItemID DESC
LIMIT 1
", { shakeItemID: shakeItemID }, { datasource: "payfrit" });
chooseFlavorID = qNewGroup.ItemID;
arrayAppend(response.steps, "Created 'Choose Flavor' group with ID: " & chooseFlavorID);
// Step 2: Re-parent the three flavors under Choose Flavor
queryExecute("
UPDATE Items
SET ItemParentItemID = :chooseFlavorID,
ItemIsModifierTemplate = 0,
ItemIsCheckedByDefault = 0
WHERE ItemID IN (:chocolateID, :strawberryID, :vanillaID)
", {
chooseFlavorID: chooseFlavorID,
chocolateID: chocolateID,
strawberryID: strawberryID,
vanillaID: vanillaID
}, { datasource: "payfrit" });
arrayAppend(response.steps, "Re-parented Chocolate, Strawberry, Vanilla under Choose Flavor");
// Step 3: Set Vanilla as default (common choice)
queryExecute("
UPDATE Items SET ItemIsCheckedByDefault = 1 WHERE ItemID = :vanillaID
", { vanillaID: vanillaID }, { datasource: "payfrit" });
arrayAppend(response.steps, "Set Vanilla as default flavor");
// Step 4: Remove old template links for the flavors
queryExecute("
DELETE FROM ItemTemplateLinks
WHERE TemplateItemID IN (:chocolateID, :strawberryID, :vanillaID)
", {
chocolateID: chocolateID,
strawberryID: strawberryID,
vanillaID: vanillaID
}, { datasource: "payfrit" });
arrayAppend(response.steps, "Removed old template links for flavor items");
// Step 5: Create ItemTemplateLinks for Shake -> Choose Flavor
queryExecute("
INSERT INTO ItemTemplateLinks (ItemID, TemplateItemID, SortOrder)
VALUES (:shakeItemID, :chooseFlavorID, 0)
ON DUPLICATE KEY UPDATE SortOrder = 0
", {
shakeItemID: shakeItemID,
chooseFlavorID: chooseFlavorID
}, { datasource: "payfrit" });
arrayAppend(response.steps, "Created template link: Shake -> Choose Flavor");
// Step 6: Set ItemRequiresChildSelection on shake
queryExecute("
UPDATE Items
SET ItemRequiresChildSelection = 1
WHERE ItemID = :shakeItemID
", { shakeItemID: shakeItemID }, { datasource: "payfrit" });
arrayAppend(response.steps, "Set ItemRequiresChildSelection=1 on Shake item");
response["OK"] = true;
response["chooseFlavorID"] = chooseFlavorID;
} catch (any e) {
response["ERROR"] = e.message;
response["DETAIL"] = e.detail;
}
writeOutput(serializeJSON(response));
</cfscript>