/** * Save/Update Category * * POST body: * { * "CategoryID": 123, // Required for update * "BusinessID": 37, // Required for insert * "Name": "Breakfast", * "SortOrder": 1, * "OrderTypes": "1,2,3", // 1=Dine-In, 2=Takeaway, 3=Delivery * "ParentCategoryID": 0, // 0 = top-level, >0 = subcategory (max 2 levels) * "ScheduleStart": "06:00:00", // Optional, null = always available * "ScheduleEnd": "11:00:00", // Optional * "ScheduleDays": "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; BusinessID = structKeyExists(data, "BusinessID") ? val(data.BusinessID) : 0; Name = structKeyExists(data, "Name") ? left(trim(data.Name), 30) : ""; SortOrder = structKeyExists(data, "SortOrder") ? val(data.SortOrder) : 0; OrderTypes = structKeyExists(data, "OrderTypes") ? trim(data.OrderTypes) : "1,2,3"; ScheduleStart = structKeyExists(data, "ScheduleStart") && len(trim(data.ScheduleStart)) ? trim(data.ScheduleStart) : javaCast("null", ""); ScheduleEnd = structKeyExists(data, "ScheduleEnd") && len(trim(data.ScheduleEnd)) ? trim(data.ScheduleEnd) : javaCast("null", ""); ScheduleDays = structKeyExists(data, "ScheduleDays") && len(trim(data.ScheduleDays)) ? trim(data.ScheduleDays) : javaCast("null", ""); ParentCategoryID = structKeyExists(data, "ParentCategoryID") ? val(data.ParentCategoryID) : 0; // Enforce 2-level max: if the proposed parent is itself a subcategory, reject if (ParentCategoryID > 0) { qParent = queryTimed("SELECT ParentCategoryID FROM Categories WHERE ID = :parentId", { parentId: ParentCategoryID }, { datasource = "payfrit" }); if (qParent.recordCount == 0) { response["ERROR"] = "invalid_parent"; response["MESSAGE"] = "Parent category not found"; writeOutput(serializeJSON(response)); return; } if (val(qParent.ParentCategoryID) > 0) { response["ERROR"] = "nesting_too_deep"; response["MESSAGE"] = "Subcategories cannot have their own subcategories (max 2 levels)"; writeOutput(serializeJSON(response)); return; } } if (CategoryID > 0) { // Update existing category queryTimed(" UPDATE Categories SET Name = :name, SortOrder = :sortOrder, OrderTypes = :orderTypes, ParentCategoryID = :parentCatId, ScheduleStart = :schedStart, ScheduleEnd = :schedEnd, ScheduleDays = :schedDays WHERE ID = :catId ", { catId: CategoryID, name: Name, sortOrder: SortOrder, orderTypes: OrderTypes, parentCatId: ParentCategoryID, schedStart: { value = ScheduleStart, cfsqltype = "cf_sql_time", null = isNull(ScheduleStart) }, schedEnd: { value = ScheduleEnd, cfsqltype = "cf_sql_time", null = isNull(ScheduleEnd) }, schedDays: { value = ScheduleDays, cfsqltype = "cf_sql_varchar", null = isNull(ScheduleDays) } }, { datasource = "payfrit" }); response["OK"] = true; response["CategoryID"] = CategoryID; response["MESSAGE"] = "Category updated"; } else if (BusinessID > 0 && len(Name)) { // Insert new category queryTimed(" INSERT INTO Categories (BusinessID, Name, SortOrder, OrderTypes, ParentCategoryID, ScheduleStart, ScheduleEnd, ScheduleDays, AddedOn) VALUES (:bizId, :name, :sortOrder, :orderTypes, :parentCatId, :schedStart, :schedEnd, :schedDays, NOW()) ", { bizId: BusinessID, name: Name, sortOrder: SortOrder, orderTypes: OrderTypes, parentCatId: ParentCategoryID, schedStart: { value = ScheduleStart, cfsqltype = "cf_sql_time", null = isNull(ScheduleStart) }, schedEnd: { value = ScheduleEnd, cfsqltype = "cf_sql_time", null = isNull(ScheduleEnd) }, schedDays: { value = ScheduleDays, cfsqltype = "cf_sql_varchar", null = isNull(ScheduleDays) } }, { datasource = "payfrit" }); qNew = queryTimed("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 BusinessID and Name for insert"; } } catch (any e) { response["ERROR"] = "server_error"; response["MESSAGE"] = e.message; response["DETAIL"] = e.detail; } writeOutput(serializeJSON(response));