Menu System: - Unified schema with Categories table integration - Virtual category headers with proper parent ID remapping - Filter out legacy category headers when using new schema - Add drink modifier endpoints for Fountain Soda (Size/Flavor) Admin Tools: - addDrinkModifiers.cfm - Add size/flavor modifiers to drinks - copyDrinksToBigDeans.cfm - Copy drink items between businesses - debugDrinkStructure.cfm - Debug drink item hierarchy Portal: - Station assignment improvements with better drag-drop - Enhanced debug task viewer API Fixes: - Application.cfm updated with new admin endpoint allowlist - setLineItem.cfm formatting cleanup - listMine.cfm task query fixes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
176 lines
5.8 KiB
Text
176 lines
5.8 KiB
Text
<cfsetting showdebugoutput="false">
|
|
<cfsetting enablecfoutputonly="true">
|
|
<cfcontent type="application/json; charset=utf-8" reset="true">
|
|
<cfheader name="Cache-Control" value="no-store">
|
|
|
|
<cfscript>
|
|
/**
|
|
* Add size and type modifiers to Big Dean's Fountain Soda
|
|
*/
|
|
|
|
response = { "OK": false, "SizesAdded": 0, "TypesAdded": 0 };
|
|
|
|
try {
|
|
bigDeansBusinessId = 27;
|
|
|
|
// Find the Fountain Soda item we created
|
|
qFountain = queryExecute("
|
|
SELECT ItemID, ItemName FROM Items
|
|
WHERE ItemBusinessID = :bizId AND ItemName = 'Fountain Soda'
|
|
", { bizId: bigDeansBusinessId }, { datasource: "payfrit" });
|
|
|
|
if (qFountain.recordCount == 0) {
|
|
response["ERROR"] = "Fountain Soda not found in Big Dean's menu";
|
|
writeOutput(serializeJSON(response));
|
|
abort;
|
|
}
|
|
|
|
fountainId = qFountain.ItemID;
|
|
response["FountainSodaID"] = fountainId;
|
|
|
|
// Update Fountain Soda to require child selection and be collapsible
|
|
queryExecute("
|
|
UPDATE Items
|
|
SET ItemRequiresChildSelection = 1, ItemIsCollapsible = 1
|
|
WHERE ItemID = :itemId
|
|
", { itemId: fountainId }, { datasource: "payfrit" });
|
|
|
|
// Check if modifiers already exist
|
|
qExisting = queryExecute("
|
|
SELECT COUNT(*) as cnt FROM Items WHERE ItemParentItemID = :parentId
|
|
", { parentId: fountainId }, { datasource: "payfrit" });
|
|
|
|
if (qExisting.cnt > 0) {
|
|
response["OK"] = true;
|
|
response["MESSAGE"] = "Modifiers already exist";
|
|
writeOutput(serializeJSON(response));
|
|
abort;
|
|
}
|
|
|
|
// Add Size group
|
|
qMaxItem = queryExecute("SELECT COALESCE(MAX(ItemID), 0) + 1 as nextId FROM Items", {}, { datasource: "payfrit" });
|
|
sizeGroupId = qMaxItem.nextId;
|
|
|
|
queryExecute("
|
|
INSERT INTO Items (
|
|
ItemID, ItemBusinessID, ItemCategoryID, ItemParentItemID,
|
|
ItemName, ItemDescription, ItemPrice, ItemIsActive,
|
|
ItemSortOrder, ItemIsCollapsible, ItemRequiresChildSelection,
|
|
ItemMaxNumSelectionReq, ItemAddedOn
|
|
) VALUES (
|
|
:itemId, :bizId, 0, :parentId,
|
|
'Size', 'Choose your size', 0, 1,
|
|
0, 1, 1, 1, NOW()
|
|
)
|
|
", {
|
|
itemId: sizeGroupId,
|
|
bizId: bigDeansBusinessId,
|
|
parentId: fountainId
|
|
}, { datasource: "payfrit" });
|
|
|
|
// Add Size options
|
|
sizes = [
|
|
{ name: "Small", price: 0, isDefault: 0 },
|
|
{ name: "Medium", price: 0.50, isDefault: 1 },
|
|
{ name: "Large", price: 1.00, isDefault: 0 }
|
|
];
|
|
|
|
sizesAdded = 0;
|
|
for (size in sizes) {
|
|
qMaxItem = queryExecute("SELECT COALESCE(MAX(ItemID), 0) + 1 as nextId FROM Items", {}, { datasource: "payfrit" });
|
|
queryExecute("
|
|
INSERT INTO Items (
|
|
ItemID, ItemBusinessID, ItemCategoryID, ItemParentItemID,
|
|
ItemName, ItemDescription, ItemPrice, ItemIsActive,
|
|
ItemSortOrder, ItemIsCollapsible, ItemIsCheckedByDefault,
|
|
ItemAddedOn
|
|
) VALUES (
|
|
:itemId, :bizId, 0, :parentId,
|
|
:name, '', :price, 1,
|
|
:sortOrder, 0, :isDefault,
|
|
NOW()
|
|
)
|
|
", {
|
|
itemId: qMaxItem.nextId,
|
|
bizId: bigDeansBusinessId,
|
|
parentId: sizeGroupId,
|
|
name: size.name,
|
|
price: size.price,
|
|
sortOrder: sizesAdded,
|
|
isDefault: size.isDefault
|
|
}, { datasource: "payfrit" });
|
|
sizesAdded++;
|
|
}
|
|
|
|
// Add Type/Flavor group
|
|
qMaxItem = queryExecute("SELECT COALESCE(MAX(ItemID), 0) + 1 as nextId FROM Items", {}, { datasource: "payfrit" });
|
|
typeGroupId = qMaxItem.nextId;
|
|
|
|
queryExecute("
|
|
INSERT INTO Items (
|
|
ItemID, ItemBusinessID, ItemCategoryID, ItemParentItemID,
|
|
ItemName, ItemDescription, ItemPrice, ItemIsActive,
|
|
ItemSortOrder, ItemIsCollapsible, ItemRequiresChildSelection,
|
|
ItemMaxNumSelectionReq, ItemAddedOn
|
|
) VALUES (
|
|
:itemId, :bizId, 0, :parentId,
|
|
'Flavor', 'Choose your drink', 0, 1,
|
|
1, 1, 1, 1, NOW()
|
|
)
|
|
", {
|
|
itemId: typeGroupId,
|
|
bizId: bigDeansBusinessId,
|
|
parentId: fountainId
|
|
}, { datasource: "payfrit" });
|
|
|
|
// Add Type options
|
|
types = [
|
|
{ name: "Coca-Cola", isDefault: 1 },
|
|
{ name: "Diet Coke", isDefault: 0 },
|
|
{ name: "Sprite", isDefault: 0 },
|
|
{ name: "Fanta Orange", isDefault: 0 },
|
|
{ name: "Lemonade", isDefault: 0 },
|
|
{ name: "Root Beer", isDefault: 0 },
|
|
{ name: "Dr Pepper", isDefault: 0 }
|
|
];
|
|
|
|
typesAdded = 0;
|
|
for (type in types) {
|
|
qMaxItem = queryExecute("SELECT COALESCE(MAX(ItemID), 0) + 1 as nextId FROM Items", {}, { datasource: "payfrit" });
|
|
queryExecute("
|
|
INSERT INTO Items (
|
|
ItemID, ItemBusinessID, ItemCategoryID, ItemParentItemID,
|
|
ItemName, ItemDescription, ItemPrice, ItemIsActive,
|
|
ItemSortOrder, ItemIsCollapsible, ItemIsCheckedByDefault,
|
|
ItemAddedOn
|
|
) VALUES (
|
|
:itemId, :bizId, 0, :parentId,
|
|
:name, '', 0, 1,
|
|
:sortOrder, 0, :isDefault,
|
|
NOW()
|
|
)
|
|
", {
|
|
itemId: qMaxItem.nextId,
|
|
bizId: bigDeansBusinessId,
|
|
parentId: typeGroupId,
|
|
name: type.name,
|
|
sortOrder: typesAdded,
|
|
isDefault: type.isDefault
|
|
}, { datasource: "payfrit" });
|
|
typesAdded++;
|
|
}
|
|
|
|
response["OK"] = true;
|
|
response["SizesAdded"] = sizesAdded;
|
|
response["TypesAdded"] = typesAdded;
|
|
response["SizeGroupID"] = sizeGroupId;
|
|
response["TypeGroupID"] = typeGroupId;
|
|
|
|
} catch (any e) {
|
|
response["ERROR"] = "server_error";
|
|
response["MESSAGE"] = e.message;
|
|
response["DETAIL"] = e.detail;
|
|
}
|
|
|
|
writeOutput(serializeJSON(response));
|
|
</cfscript>
|