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>
141 lines
5.9 KiB
Text
141 lines
5.9 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>
|
|
/**
|
|
* Copy drinks from In-N-Out (BusinessID 17) to Big Dean's (BusinessID 27)
|
|
*/
|
|
|
|
response = { "OK": false, "ItemsCreated": 0, "CategoryCreated": false };
|
|
|
|
try {
|
|
bigDeansBusinessId = 27;
|
|
|
|
// First, check if Big Dean's has a Beverages/Drinks category
|
|
qExistingCat = queryExecute("
|
|
SELECT CategoryID, CategoryName FROM Categories
|
|
WHERE CategoryBusinessID = :bizId AND (CategoryName LIKE '%Drink%' OR CategoryName LIKE '%Beverage%')
|
|
", { bizId: bigDeansBusinessId }, { datasource: "payfrit" });
|
|
|
|
if (qExistingCat.recordCount > 0) {
|
|
drinksCategoryId = qExistingCat.CategoryID;
|
|
response["CategoryNote"] = "Using existing category: " & qExistingCat.CategoryName;
|
|
} else {
|
|
// Create a new Beverages category for Big Dean's
|
|
qMaxCat = queryExecute("SELECT COALESCE(MAX(CategoryID), 0) + 1 as nextId FROM Categories", {}, { datasource: "payfrit" });
|
|
drinksCategoryId = qMaxCat.nextId;
|
|
|
|
qMaxSort = queryExecute("
|
|
SELECT COALESCE(MAX(CategorySortOrder), 0) + 1 as nextSort FROM Categories WHERE CategoryBusinessID = :bizId
|
|
", { bizId: bigDeansBusinessId }, { datasource: "payfrit" });
|
|
|
|
queryExecute("
|
|
INSERT INTO Categories (CategoryID, CategoryBusinessID, CategoryParentCategoryID, CategoryName, CategorySortOrder, CategoryAddedOn)
|
|
VALUES (:catId, :bizId, 0, 'Beverages', :sortOrder, NOW())
|
|
", {
|
|
catId: drinksCategoryId,
|
|
bizId: bigDeansBusinessId,
|
|
sortOrder: qMaxSort.nextSort
|
|
}, { datasource: "payfrit" });
|
|
|
|
response["CategoryCreated"] = true;
|
|
response["CategoryNote"] = "Created new category: Beverages (ID: " & drinksCategoryId & ")";
|
|
}
|
|
|
|
// Drinks to add (from In-N-Out)
|
|
drinks = [
|
|
{ name: "Fountain Soda", price: 2.10, desc: "Coca-Cola, Diet Coke, Sprite, Fanta Orange, Lemonade" },
|
|
{ name: "Bottled Water", price: 1.50, desc: "" },
|
|
{ name: "Iced Tea", price: 2.25, desc: "Freshly brewed" },
|
|
{ name: "Coffee", price: 1.95, desc: "Hot brewed coffee" },
|
|
{ name: "Hot Cocoa", price: 2.25, desc: "" },
|
|
{ name: "Milk", price: 1.25, desc: "2% milk" },
|
|
{ name: "Orange Juice", price: 2.50, desc: "Fresh squeezed" },
|
|
{ name: "Milkshake", price: 4.95, desc: "Chocolate, Vanilla, or Strawberry - made with real ice cream", requiresChild: 1 }
|
|
];
|
|
|
|
itemsCreated = 0;
|
|
|
|
for (drink in drinks) {
|
|
// Check if item already exists
|
|
qExists = queryExecute("
|
|
SELECT ItemID FROM Items
|
|
WHERE ItemBusinessID = :bizId AND ItemName = :name AND ItemCategoryID = :catId
|
|
", { bizId: bigDeansBusinessId, name: drink.name, catId: drinksCategoryId }, { datasource: "payfrit" });
|
|
|
|
if (qExists.recordCount == 0) {
|
|
// Get next ItemID
|
|
qMaxItem = queryExecute("SELECT COALESCE(MAX(ItemID), 0) + 1 as nextId FROM Items", {}, { datasource: "payfrit" });
|
|
newItemId = qMaxItem.nextId;
|
|
|
|
queryExecute("
|
|
INSERT INTO Items (
|
|
ItemID, ItemBusinessID, ItemCategoryID, ItemParentItemID,
|
|
ItemName, ItemDescription, ItemPrice, ItemIsActive,
|
|
ItemSortOrder, ItemIsCollapsible, ItemRequiresChildSelection,
|
|
ItemAddedOn
|
|
) VALUES (
|
|
:itemId, :bizId, :catId, 0,
|
|
:name, :desc, :price, 1,
|
|
:sortOrder, 0, :requiresChild,
|
|
NOW()
|
|
)
|
|
", {
|
|
itemId: newItemId,
|
|
bizId: bigDeansBusinessId,
|
|
catId: drinksCategoryId,
|
|
name: drink.name,
|
|
desc: structKeyExists(drink, "desc") ? drink.desc : "",
|
|
price: drink.price,
|
|
sortOrder: itemsCreated,
|
|
requiresChild: structKeyExists(drink, "requiresChild") ? drink.requiresChild : 0
|
|
}, { datasource: "payfrit" });
|
|
|
|
itemsCreated++;
|
|
|
|
// If milkshake, add flavor options
|
|
if (drink.name == "Milkshake") {
|
|
flavors = ["Chocolate", "Vanilla", "Strawberry"];
|
|
flavorSort = 0;
|
|
for (flavor in flavors) {
|
|
qMaxOpt = 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: qMaxOpt.nextId,
|
|
bizId: bigDeansBusinessId,
|
|
parentId: newItemId,
|
|
name: flavor,
|
|
sortOrder: flavorSort,
|
|
isDefault: (flavor == "Chocolate") ? 1 : 0
|
|
}, { datasource: "payfrit" });
|
|
flavorSort++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
response["OK"] = true;
|
|
response["ItemsCreated"] = itemsCreated;
|
|
response["CategoryID"] = drinksCategoryId;
|
|
|
|
} catch (any e) {
|
|
response["ERROR"] = "server_error";
|
|
response["MESSAGE"] = e.message;
|
|
response["DETAIL"] = e.detail;
|
|
}
|
|
|
|
writeOutput(serializeJSON(response));
|
|
</cfscript>
|