payfrit-works/api/menu/getForBuilder.cfm
John Mizerek 1f4d06edba Add Payfrit Works (WDS) support and task completion flow
Task System:
- Tasks auto-created when KDS marks order Ready (status 3)
- Duplicate task prevention via TaskOrderID check
- Task completion now marks associated order as Completed (status 4)
- Fixed isNull() check for TaskCompletedOn (use len() instead)
- Added TaskOrderID to task queries for order linking

Worker APIs:
- api/workers/myBusinesses.cfm with GROUP BY to prevent duplicates
- api/tasks/listMine.cfm for worker's claimed tasks with filters
- api/tasks/complete.cfm updates both task and order status
- api/tasks/accept.cfm for claiming tasks

KDS/Portal:
- KDS only shows orders with status < 4
- Portal dashboard improvements

Admin/Debug:
- Debug endpoints for tasks and businesses
- Test data reset endpoint

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 14:52:04 -08:00

108 lines
3.2 KiB
Text

<cfscript>
// Get menu data formatted for the builder UI
// Input: BusinessID
// Output: { OK: true, MENU: { categories: [...] } }
param name="form.BusinessID" default="0";
param name="url.BusinessID" default="#form.BusinessID#";
businessID = val(url.BusinessID);
response = { "OK": false };
try {
if (businessID == 0) {
// Try to get from request body
requestBody = toString(getHttpRequestData().content);
if (len(requestBody)) {
jsonData = deserializeJSON(requestBody);
businessID = val(jsonData.BusinessID ?: 0);
}
}
if (businessID == 0) {
throw("BusinessID is required");
}
// Get categories
categories = queryExecute("
SELECT CategoryID, CategoryName, CategoryDescription, CategorySortOrder
FROM Categories
WHERE CategoryBusinessID = :businessID
ORDER BY CategorySortOrder, CategoryName
", { businessID: businessID });
menuCategories = [];
for (cat in categories) {
// Get items for this category (without Tasks join which may not exist)
items = queryExecute("
SELECT i.ItemID, i.ItemName, i.ItemDescription, i.ItemPrice,
i.ItemIsActive, i.ItemSortOrder
FROM Items i
WHERE i.ItemCategoryID = :categoryID
AND i.ItemParentItemID = 0
ORDER BY i.ItemSortOrder, i.ItemName
", { categoryID: cat.CategoryID });
categoryItems = [];
for (item in items) {
// Get modifiers for this item
modifiers = queryExecute("
SELECT ItemID, ItemName, ItemPrice, ItemIsCheckedByDefault, ItemSortOrder
FROM Items
WHERE ItemParentItemID = :itemID
ORDER BY ItemSortOrder, ItemName
", { itemID: item.ItemID });
itemModifiers = [];
for (mod in modifiers) {
arrayAppend(itemModifiers, {
"id": mod.ItemID,
"name": mod.ItemName,
"price": mod.ItemPrice,
"isDefault": mod.ItemIsCheckedByDefault == 1,
"sortOrder": mod.ItemSortOrder
});
}
arrayAppend(categoryItems, {
"id": item.ItemID,
"name": item.ItemName,
"description": item.ItemDescription ?: "",
"price": item.ItemPrice,
"imageUrl": "",
"photoTaskId": "",
"modifiers": itemModifiers,
"sortOrder": item.ItemSortOrder
});
}
arrayAppend(menuCategories, {
"id": cat.CategoryID,
"name": cat.CategoryName,
"description": cat.CategoryDescription ?: "",
"sortOrder": cat.CategorySortOrder,
"items": categoryItems
});
}
response = {
"OK": true,
"MENU": {
"categories": menuCategories
}
};
} catch (any e) {
response = {
"OK": false,
"ERROR": e.message,
"DETAIL": e.detail ?: ""
};
}
cfheader(name="Content-Type", value="application/json");
writeOutput(serializeJSON(response));
</cfscript>