payfrit-works/api/admin/scheduledTasks/list.cfm
John Mizerek ed3f9192d5 Add Task Admin feature to portal
- Add Quick Task Templates: admin creates task shortcuts, tap to create tasks instantly
- Add Scheduled Tasks: admin defines recurring tasks with cron expressions
- New API endpoints: /api/admin/quickTasks/* and /api/admin/scheduledTasks/*
- New database tables: QuickTaskTemplates, ScheduledTaskDefinitions
- Portal UI: Task Admin page with shortcut buttons and scheduled task management

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

101 lines
3.6 KiB
Text

<cfsetting showdebugoutput="false">
<cfsetting enablecfoutputonly="true">
<cfcontent type="application/json; charset=utf-8" reset="true">
<cfscript>
// Returns scheduled task definitions for a business
// Input: BusinessID (required)
// Output: { OK: true, SCHEDULED_TASKS: [...] }
function apiAbort(required struct payload) {
writeOutput(serializeJSON(payload));
abort;
}
function readJsonBody() {
var raw = getHttpRequestData().content;
if (isNull(raw)) raw = "";
if (!len(trim(raw))) return {};
try {
var data = deserializeJSON(raw);
if (isStruct(data)) return data;
} catch (any e) {}
return {};
}
try {
data = readJsonBody();
// Get BusinessID from body, header, or URL
businessID = 0;
httpHeaders = getHttpRequestData().headers;
if (structKeyExists(data, "BusinessID") && isNumeric(data.BusinessID)) {
businessID = int(data.BusinessID);
} else if (structKeyExists(httpHeaders, "X-Business-ID") && isNumeric(httpHeaders["X-Business-ID"])) {
businessID = int(httpHeaders["X-Business-ID"]);
} else if (structKeyExists(url, "BusinessID") && isNumeric(url.BusinessID)) {
businessID = int(url.BusinessID);
}
if (businessID == 0) {
apiAbort({ "OK": false, "ERROR": "missing_params", "MESSAGE": "BusinessID is required" });
}
// Get scheduled task definitions for this business
q = queryExecute("
SELECT
st.ScheduledTaskID,
st.ScheduledTaskName as Name,
st.ScheduledTaskCategoryID as CategoryID,
st.ScheduledTaskTypeID as TypeID,
st.ScheduledTaskTitle as Title,
st.ScheduledTaskDetails as Details,
st.ScheduledTaskCronExpression as CronExpression,
st.ScheduledTaskIsActive as IsActive,
st.ScheduledTaskLastRunOn as LastRunOn,
st.ScheduledTaskNextRunOn as NextRunOn,
st.ScheduledTaskCreatedOn as CreatedOn,
tc.TaskCategoryName as CategoryName,
tc.TaskCategoryColor as CategoryColor
FROM ScheduledTaskDefinitions st
LEFT JOIN TaskCategories tc ON st.ScheduledTaskCategoryID = tc.TaskCategoryID
WHERE st.ScheduledTaskBusinessID = :businessID
ORDER BY st.ScheduledTaskIsActive DESC, st.ScheduledTaskName
", {
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
}, { datasource: "payfrit" });
scheduledTasks = [];
for (row in q) {
arrayAppend(scheduledTasks, {
"ScheduledTaskID": row.ScheduledTaskID,
"Name": row.Name,
"CategoryID": isNull(row.CategoryID) ? "" : row.CategoryID,
"TypeID": isNull(row.TypeID) ? "" : row.TypeID,
"Title": row.Title,
"Details": isNull(row.Details) ? "" : row.Details,
"CronExpression": row.CronExpression,
"IsActive": row.IsActive ? true : false,
"LastRunOn": isNull(row.LastRunOn) ? "" : dateTimeFormat(row.LastRunOn, "yyyy-mm-dd HH:nn:ss"),
"NextRunOn": isNull(row.NextRunOn) ? "" : dateTimeFormat(row.NextRunOn, "yyyy-mm-dd HH:nn:ss"),
"CreatedOn": dateTimeFormat(row.CreatedOn, "yyyy-mm-dd HH:nn:ss"),
"CategoryName": isNull(row.CategoryName) ? "" : row.CategoryName,
"CategoryColor": isNull(row.CategoryColor) ? "" : row.CategoryColor
});
}
apiAbort({
"OK": true,
"SCHEDULED_TASKS": scheduledTasks,
"COUNT": arrayLen(scheduledTasks)
});
} catch (any e) {
apiAbort({
"OK": false,
"ERROR": "server_error",
"MESSAGE": e.message
});
}
</cfscript>