- Move menu manager button to toolbar next to Save Menu for visibility - Implement server-side photo upload for menu items - Strip base64 data URLs from save payload to reduce size - Add scheduled tasks, quick tasks, ratings, and task categories APIs - Add vertical support and brand color features Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
92 lines
3.2 KiB
Text
92 lines
3.2 KiB
Text
<cfsetting showdebugoutput="false">
|
|
<cfcontent type="application/json; charset=utf-8">
|
|
<cfscript>
|
|
/**
|
|
* List completed tasks that admin can rate
|
|
* Returns tasks completed in the last 7 days where admin hasn't yet rated the worker
|
|
*
|
|
* POST: { BusinessID: 123 }
|
|
*/
|
|
|
|
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 {};
|
|
}
|
|
}
|
|
|
|
try {
|
|
data = readJsonBody();
|
|
businessID = val(structKeyExists(data, "BusinessID") ? data.BusinessID : 0);
|
|
|
|
if (businessID == 0) {
|
|
writeOutput(serializeJSON({ "OK": false, "ERROR": "missing_business", "MESSAGE": "BusinessID is required." }));
|
|
abort;
|
|
}
|
|
|
|
// Get completed tasks from last 7 days where a worker was assigned
|
|
// and no admin rating exists yet
|
|
qTasks = queryExecute("
|
|
SELECT t.TaskID, t.TaskTitle, t.TaskCompletedOn, t.TaskClaimedByUserID, t.TaskOrderID,
|
|
u.UserFirstName AS WorkerFirstName, u.UserLastName AS WorkerLastName,
|
|
o.OrderID, o.OrderUserID,
|
|
cu.UserFirstName AS CustomerFirstName, cu.UserLastName AS CustomerLastName,
|
|
sp.ServicePointName,
|
|
(SELECT COUNT(*) FROM TaskRatings r
|
|
WHERE r.TaskRatingTaskID = t.TaskID
|
|
AND r.TaskRatingDirection = 'admin_rates_worker') AS HasAdminRating
|
|
FROM Tasks t
|
|
INNER JOIN Users u ON u.UserID = t.TaskClaimedByUserID
|
|
LEFT JOIN Orders o ON o.OrderID = t.TaskOrderID
|
|
LEFT JOIN Users cu ON cu.UserID = o.OrderUserID
|
|
LEFT JOIN ServicePoints sp ON sp.ServicePointID = o.OrderServicePointID
|
|
WHERE t.TaskBusinessID = :businessID
|
|
AND t.TaskCompletedOn IS NOT NULL
|
|
AND t.TaskCompletedOn > DATE_SUB(NOW(), INTERVAL 7 DAY)
|
|
AND t.TaskClaimedByUserID > 0
|
|
HAVING HasAdminRating = 0
|
|
ORDER BY t.TaskCompletedOn DESC
|
|
LIMIT 50
|
|
", { businessID: businessID });
|
|
|
|
tasks = [];
|
|
for (row in qTasks) {
|
|
// Build task title
|
|
taskTitle = row.TaskTitle;
|
|
if (len(taskTitle) == 0 && row.OrderID > 0) {
|
|
taskTitle = "Order ##" & row.OrderID;
|
|
}
|
|
if (len(taskTitle) == 0) {
|
|
taskTitle = "Task ##" & row.TaskID;
|
|
}
|
|
|
|
arrayAppend(tasks, {
|
|
"TaskID": row.TaskID,
|
|
"TaskTitle": taskTitle,
|
|
"CompletedOn": dateTimeFormat(row.TaskCompletedOn, "yyyy-mm-dd HH:nn:ss"),
|
|
"WorkerUserID": row.TaskClaimedByUserID,
|
|
"WorkerName": trim(row.WorkerFirstName & " " & row.WorkerLastName),
|
|
"CustomerName": len(row.CustomerFirstName) ? trim(row.CustomerFirstName & " " & row.CustomerLastName) : "",
|
|
"ServicePointName": row.ServicePointName ?: "",
|
|
"OrderID": row.OrderID ?: 0
|
|
});
|
|
}
|
|
|
|
writeOutput(serializeJSON({
|
|
"OK": true,
|
|
"TASKS": tasks
|
|
}));
|
|
|
|
} catch (any e) {
|
|
writeOutput(serializeJSON({
|
|
"OK": false,
|
|
"ERROR": "server_error",
|
|
"MESSAGE": "Error loading tasks",
|
|
"DETAIL": e.message
|
|
}));
|
|
}
|
|
</cfscript>
|