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/menu/menus.cfm
John Mizerek 1210249f54 Normalize database column and table names across entire codebase
Update all SQL queries, query result references, and ColdFusion code to match
the renamed database schema. Tables use plural CamelCase, PKs are all `ID`,
column prefixes stripped (e.g. BusinessName→Name, UserFirstName→FirstName).

Key changes:
- Strip table-name prefixes from all column references (Businesses, Users,
  Addresses, Hours, Menus, Categories, Items, Stations, Orders,
  OrderLineItems, Tasks, TaskCategories, TaskRatings, QuickTaskTemplates,
  ScheduledTaskDefinitions, ChatMessages, Beacons, ServicePoints, Employees,
  VisitorTrackings, ApiPerfLogs, tt_States, tt_Days, tt_AddressTypes,
  tt_OrderTypes, tt_TaskTypes)
- Rename PK references from {TableName}ID to ID in all queries
- Rewrite 7 admin beacon files to use ServicePoints.BeaconID instead of
  dropped lt_Beacon_Businesses_ServicePoints link table
- Rewrite beacon assignment files (list, save, delete) for new schema
- Fix FK references incorrectly changed to ID (OrderLineItems.OrderID,
  Categories.MenuID, Tasks.CategoryID, ServicePoints.BeaconID)
- Update Addresses: AddressLat→Latitude, AddressLng→Longitude
- Update Users: UserPassword→Password, UserIsEmailVerified→IsEmailVerified,
  UserIsActive→IsActive, UserBalance→Balance, etc.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 15:39:12 -08:00

254 lines
10 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>
/**
* Menu CRUD API
*
* GET: List all menus for a business
* POST: Create or update a menu
* DELETE: Soft-delete a menu
*
* Input: BusinessID, and optionally Menu data for POST
*/
response = { "OK": false };
function apiAbort(payload) {
writeOutput(serializeJSON(payload));
abort;
}
try {
requestBody = toString(getHttpRequestData().content);
requestData = {};
if (len(requestBody)) {
requestData = deserializeJSON(requestBody);
}
businessID = 0;
if (structKeyExists(requestData, "BusinessID")) {
businessID = val(requestData.BusinessID);
}
if (businessID == 0) {
apiAbort({ "OK": false, "ERROR": "missing_business_id", "MESSAGE": "BusinessID is required" });
}
method = cgi.REQUEST_METHOD;
action = structKeyExists(requestData, "action") ? lCase(requestData.action) : "list";
// Handle different actions
switch (action) {
case "list":
// Get all active menus for this business
qMenus = queryExecute("
SELECT
ID,
Name,
Description,
DaysActive,
StartTime,
EndTime,
SortOrder,
IsActive
FROM Menus
WHERE BusinessID = :businessID
AND IsActive = 1
ORDER BY SortOrder, Name
", { businessID: businessID }, { datasource: "payfrit" });
menus = [];
for (i = 1; i <= qMenus.recordCount; i++) {
// Count categories in this menu
qCatCount = queryExecute("
SELECT COUNT(*) as cnt FROM Categories
WHERE BusinessID = :businessID
AND MenuID = :menuID
", { businessID: businessID, menuID: qMenus.ID[i] }, { datasource: "payfrit" });
arrayAppend(menus, {
"MenuID": qMenus.ID[i],
"Name": qMenus.Name[i],
"Description": isNull(qMenus.Description[i]) ? "" : qMenus.Description[i],
"DaysActive": qMenus.DaysActive[i],
"StartTime": isNull(qMenus.StartTime[i]) ? "" : timeFormat(qMenus.StartTime[i], "HH:mm"),
"EndTime": isNull(qMenus.EndTime[i]) ? "" : timeFormat(qMenus.EndTime[i], "HH:mm"),
"SortOrder": qMenus.SortOrder[i],
"CategoryCount": qCatCount.cnt
});
}
response = {
"OK": true,
"MENUS": menus,
"COUNT": arrayLen(menus)
};
break;
case "get":
// Get a single menu by ID
menuID = structKeyExists(requestData, "MenuID") ? val(requestData.MenuID) : 0;
if (menuID == 0) {
apiAbort({ "OK": false, "ERROR": "missing_menu_id", "MESSAGE": "MenuID is required" });
}
qMenu = queryExecute("
SELECT * FROM Menus
WHERE ID = :menuID AND BusinessID = :businessID
", { menuID: menuID, businessID: businessID }, { datasource: "payfrit" });
if (qMenu.recordCount == 0) {
apiAbort({ "OK": false, "ERROR": "menu_not_found", "MESSAGE": "Menu not found" });
}
response = {
"OK": true,
"MENU": {
"MenuID": qMenu.ID,
"Name": qMenu.Name,
"Description": isNull(qMenu.Description) ? "" : qMenu.Description,
"DaysActive": qMenu.DaysActive,
"StartTime": isNull(qMenu.StartTime) ? "" : timeFormat(qMenu.StartTime, "HH:mm"),
"EndTime": isNull(qMenu.EndTime) ? "" : timeFormat(qMenu.EndTime, "HH:mm"),
"SortOrder": qMenu.SortOrder,
"IsActive": qMenu.IsActive
}
};
break;
case "save":
// Create or update a menu
menuID = structKeyExists(requestData, "MenuID") ? val(requestData.MenuID) : 0;
menuName = structKeyExists(requestData, "Name") ? trim(requestData.Name) : "";
menuDescription = structKeyExists(requestData, "Description") ? trim(requestData.Description) : "";
menuDaysActive = structKeyExists(requestData, "DaysActive") ? val(requestData.DaysActive) : 127;
menuStartTime = structKeyExists(requestData, "StartTime") && len(trim(requestData.StartTime)) ? trim(requestData.StartTime) : "";
menuEndTime = structKeyExists(requestData, "EndTime") && len(trim(requestData.EndTime)) ? trim(requestData.EndTime) : "";
menuSortOrder = structKeyExists(requestData, "SortOrder") ? val(requestData.SortOrder) : 0;
if (len(menuName) == 0) {
apiAbort({ "OK": false, "ERROR": "missing_menu_name", "MESSAGE": "Menu name is required" });
}
if (menuID > 0) {
// Update existing menu
queryExecute("
UPDATE Menus SET
Name = :menuName,
Description = :menuDescription,
DaysActive = :menuDaysActive,
StartTime = :menuStartTime,
EndTime = :menuEndTime,
SortOrder = :menuSortOrder
WHERE ID = :menuID AND BusinessID = :businessID
", {
menuID: { value: menuID, cfsqltype: "cf_sql_integer" },
businessID: { value: businessID, cfsqltype: "cf_sql_integer" },
menuName: { value: menuName, cfsqltype: "cf_sql_varchar" },
menuDescription: { value: menuDescription, cfsqltype: "cf_sql_varchar" },
menuDaysActive: { value: menuDaysActive, cfsqltype: "cf_sql_integer" },
menuStartTime: { value: menuStartTime, cfsqltype: "cf_sql_time", null: !len(menuStartTime) },
menuEndTime: { value: menuEndTime, cfsqltype: "cf_sql_time", null: !len(menuEndTime) },
menuSortOrder: { value: menuSortOrder, cfsqltype: "cf_sql_integer" }
}, { datasource: "payfrit" });
response = { "OK": true, "MenuID": menuID, "ACTION": "updated" };
} else {
// Create new menu
queryExecute("
INSERT INTO Menus (
BusinessID, Name, Description,
DaysActive, StartTime, EndTime,
SortOrder, IsActive, AddedOn
) VALUES (
:businessID, :menuName, :menuDescription,
:menuDaysActive, :menuStartTime, :menuEndTime,
:menuSortOrder, 1, NOW()
)
", {
businessID: { value: businessID, cfsqltype: "cf_sql_integer" },
menuName: { value: menuName, cfsqltype: "cf_sql_varchar" },
menuDescription: { value: menuDescription, cfsqltype: "cf_sql_varchar" },
menuDaysActive: { value: menuDaysActive, cfsqltype: "cf_sql_integer" },
menuStartTime: { value: menuStartTime, cfsqltype: "cf_sql_time", null: !len(menuStartTime) },
menuEndTime: { value: menuEndTime, cfsqltype: "cf_sql_time", null: !len(menuEndTime) },
menuSortOrder: { value: menuSortOrder, cfsqltype: "cf_sql_integer" }
}, { datasource: "payfrit" });
result = queryExecute("SELECT LAST_INSERT_ID() as newID", {}, { datasource: "payfrit" });
response = { "OK": true, "MenuID": result.newID, "ACTION": "created" };
}
break;
case "delete":
// Soft-delete a menu
menuID = structKeyExists(requestData, "MenuID") ? val(requestData.MenuID) : 0;
if (menuID == 0) {
apiAbort({ "OK": false, "ERROR": "missing_menu_id", "MESSAGE": "MenuID is required" });
}
// Check if menu has categories/items for warning
qCatCheck = queryExecute("
SELECT COUNT(*) as cnt FROM Categories
WHERE MenuID = :menuID AND BusinessID = :businessID
", { menuID: menuID, businessID: businessID }, { datasource: "payfrit" });
// Unassign categories from this menu
if (qCatCheck.cnt > 0) {
queryExecute("
UPDATE Categories SET MenuID = 0
WHERE MenuID = :menuID AND BusinessID = :businessID
", { menuID: menuID, businessID: businessID }, { datasource: "payfrit" });
}
// Soft-delete the menu
queryExecute("
UPDATE Menus SET IsActive = 0
WHERE ID = :menuID AND BusinessID = :businessID
", { menuID: menuID, businessID: businessID }, { datasource: "payfrit" });
response = {
"OK": true,
"MenuID": menuID,
"ACTION": "deleted",
"CategoriesUnassigned": qCatCheck.cnt
};
break;
case "reorder":
// Reorder menus
menuOrder = structKeyExists(requestData, "MenuOrder") ? requestData.MenuOrder : [];
if (!isArray(menuOrder) || arrayLen(menuOrder) == 0) {
apiAbort({ "OK": false, "ERROR": "missing_menu_order", "MESSAGE": "MenuOrder array is required" });
}
for (i = 1; i <= arrayLen(menuOrder); i++) {
queryExecute("
UPDATE Menus SET SortOrder = :sortOrder
WHERE ID = :menuID AND BusinessID = :businessID
", {
menuID: val(menuOrder[i]),
businessID: businessID,
sortOrder: i - 1
}, { datasource: "payfrit" });
}
response = { "OK": true, "ACTION": "reordered" };
break;
default:
apiAbort({ "OK": false, "ERROR": "invalid_action", "MESSAGE": "Unknown action: " & action });
}
} catch (any e) {
response["ERROR"] = "server_error";
response["MESSAGE"] = e.message;
response["DETAIL"] = e.detail ?: "";
}
writeOutput(serializeJSON(response));
</cfscript>