payfrit-works/api/menu/saveCategory.cfm
John Mizerek c2ae037e71 App Store Version 2: Multi-menu support, beacon lookup, category scheduling
Features:
- Multi-menu support with time-based availability
- Menu hours validation against business operating hours
- Setup wizard now creates Menu records and links categories
- New menus.cfm API for menu CRUD operations
- Category schedule filtering (day/time based visibility)
- Beacon UUID lookup API for customer app
- Parent/child business relationships for franchises
- Category listing API for menu builder

Portal improvements:
- Menu builder theming to match admin UI
- Brand color picker fix
- Header image preview improvements

API fixes:
- Filter demo/hidden businesses from restaurant list
- Improved error handling throughout

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 19:51:44 -08:00

111 lines
4.7 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>
/**
* Save/Update Category
*
* POST body:
* {
* "CategoryID": 123, // Required for update
* "CategoryBusinessID": 37, // Required for insert
* "CategoryName": "Breakfast",
* "CategorySortOrder": 1,
* "CategoryOrderTypes": "1,2,3", // 1=Dine-In, 2=Takeaway, 3=Delivery
* "CategoryScheduleStart": "06:00:00", // Optional, null = always available
* "CategoryScheduleEnd": "11:00:00", // Optional
* "CategoryScheduleDays": "2,3,4,5,6" // Optional, 1=Sun..7=Sat, null = all days
* }
*/
function readJsonBody() {
var raw = getHttpRequestData().content;
if (isNull(raw) || len(trim(raw)) == 0) return {};
try {
var data = deserializeJSON(raw);
return isStruct(data) ? data : {};
} catch (any e) {
return {};
}
}
response = { "OK": false };
try {
data = readJsonBody();
CategoryID = structKeyExists(data, "CategoryID") ? val(data.CategoryID) : 0;
CategoryBusinessID = structKeyExists(data, "CategoryBusinessID") ? val(data.CategoryBusinessID) : 0;
CategoryName = structKeyExists(data, "CategoryName") ? left(trim(data.CategoryName), 30) : "";
CategorySortOrder = structKeyExists(data, "CategorySortOrder") ? val(data.CategorySortOrder) : 0;
CategoryOrderTypes = structKeyExists(data, "CategoryOrderTypes") ? trim(data.CategoryOrderTypes) : "1,2,3";
CategoryScheduleStart = structKeyExists(data, "CategoryScheduleStart") && len(trim(data.CategoryScheduleStart))
? trim(data.CategoryScheduleStart) : javaCast("null", "");
CategoryScheduleEnd = structKeyExists(data, "CategoryScheduleEnd") && len(trim(data.CategoryScheduleEnd))
? trim(data.CategoryScheduleEnd) : javaCast("null", "");
CategoryScheduleDays = structKeyExists(data, "CategoryScheduleDays") && len(trim(data.CategoryScheduleDays))
? trim(data.CategoryScheduleDays) : javaCast("null", "");
if (CategoryID > 0) {
// Update existing category
queryExecute("
UPDATE Categories SET
CategoryName = :name,
CategorySortOrder = :sortOrder,
CategoryOrderTypes = :orderTypes,
CategoryScheduleStart = :schedStart,
CategoryScheduleEnd = :schedEnd,
CategoryScheduleDays = :schedDays
WHERE CategoryID = :catId
", {
catId: CategoryID,
name: CategoryName,
sortOrder: CategorySortOrder,
orderTypes: CategoryOrderTypes,
schedStart: { value = CategoryScheduleStart, cfsqltype = "cf_sql_time", null = isNull(CategoryScheduleStart) },
schedEnd: { value = CategoryScheduleEnd, cfsqltype = "cf_sql_time", null = isNull(CategoryScheduleEnd) },
schedDays: { value = CategoryScheduleDays, cfsqltype = "cf_sql_varchar", null = isNull(CategoryScheduleDays) }
}, { datasource = "payfrit" });
response["OK"] = true;
response["CategoryID"] = CategoryID;
response["MESSAGE"] = "Category updated";
} else if (CategoryBusinessID > 0 && len(CategoryName)) {
// Insert new category
queryExecute("
INSERT INTO Categories
(CategoryBusinessID, CategoryName, CategorySortOrder, CategoryOrderTypes,
CategoryScheduleStart, CategoryScheduleEnd, CategoryScheduleDays, CategoryAddedOn)
VALUES
(:bizId, :name, :sortOrder, :orderTypes, :schedStart, :schedEnd, :schedDays, NOW())
", {
bizId: CategoryBusinessID,
name: CategoryName,
sortOrder: CategorySortOrder,
orderTypes: CategoryOrderTypes,
schedStart: { value = CategoryScheduleStart, cfsqltype = "cf_sql_time", null = isNull(CategoryScheduleStart) },
schedEnd: { value = CategoryScheduleEnd, cfsqltype = "cf_sql_time", null = isNull(CategoryScheduleEnd) },
schedDays: { value = CategoryScheduleDays, cfsqltype = "cf_sql_varchar", null = isNull(CategoryScheduleDays) }
}, { datasource = "payfrit" });
qNew = queryExecute("SELECT LAST_INSERT_ID() as newId", {}, { datasource = "payfrit" });
response["OK"] = true;
response["CategoryID"] = qNew.newId;
response["MESSAGE"] = "Category created";
} else {
response["ERROR"] = "invalid_params";
response["MESSAGE"] = "CategoryID required for update, or CategoryBusinessID and CategoryName for insert";
}
} catch (any e) {
response["ERROR"] = "server_error";
response["MESSAGE"] = e.message;
response["DETAIL"] = e.detail;
}
writeOutput(serializeJSON(response));
</cfscript>