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>
156 lines
6.7 KiB
Text
156 lines
6.7 KiB
Text
<cfsetting showdebugoutput="false">
|
|
<cfsetting enablecfoutputonly="true">
|
|
|
|
<!---
|
|
Payfrit API Application.cfm
|
|
|
|
FIX: Provide a DEFAULT datasource so endpoints can call queryExecute()
|
|
without specifying { datasource="payfrit" } every time.
|
|
|
|
Token-auth gate for /api endpoints.
|
|
|
|
Public allowlist (NO auth):
|
|
- /api/login.cfm
|
|
- /api/logout.cfm
|
|
- /api/auth/login.cfm
|
|
- /api/auth/logout.cfm
|
|
- /api/businesses/list.cfm
|
|
- /api/servicepoints/list.cfm
|
|
|
|
Authenticated requests should send:
|
|
- Header: X-User-Token: <token from /api/auth/login.cfm>
|
|
- Header: X-Business-ID: <selected BusinessID> (required for most endpoints)
|
|
--->
|
|
|
|
<!--- OPTION A: default datasource for the whole app (THIS fixes "missing datasource") --->
|
|
<cfapplication
|
|
name="payfrit_api"
|
|
sessionmanagement="true"
|
|
clientmanagement="false"
|
|
setclientcookies="false"
|
|
datasource="payfrit"
|
|
>
|
|
|
|
<!--- Stripe Configuration --->
|
|
<cfset application.stripeSecretKey = "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">
|
|
<cfset application.stripePublishableKey = "pk_live_Wqj4yGmtTghVJu7oufnWmU5H">
|
|
<cfset application.stripeWebhookSecret = "whsec_8t6s9Lz0S5M1SYcEYvZ73qFP4zmtlG6h">
|
|
|
|
<cfscript>
|
|
function apiAbort(payload) {
|
|
writeOutput(serializeJSON(payload));
|
|
abort;
|
|
}
|
|
|
|
function headerValue(name) {
|
|
k = "HTTP_" & ucase(reReplace(arguments.name, "[^A-Za-z0-9]", "_", "all"));
|
|
if (structKeyExists(cgi, k)) return trim(cgi[k]);
|
|
return "";
|
|
}
|
|
|
|
// Determine request path
|
|
request._api_scriptName = "";
|
|
if (structKeyExists(cgi, "SCRIPT_NAME")) {
|
|
request._api_scriptName = cgi.SCRIPT_NAME;
|
|
} else if (structKeyExists(cgi, "PATH_INFO")) {
|
|
request._api_scriptName = cgi.PATH_INFO;
|
|
}
|
|
request._api_path = lcase(request._api_scriptName);
|
|
|
|
// Public allowlist
|
|
request._api_isPublic = false;
|
|
if (len(request._api_path)) {
|
|
if (findNoCase("/api/login.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/logout.cfm", request._api_path)) request._api_isPublic = true;
|
|
|
|
if (findNoCase("/api/auth/login.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/auth/logout.cfm", request._api_path)) request._api_isPublic = true;
|
|
|
|
if (findNoCase("/api/businesses/list.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/businesses/get.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/servicepoints/list.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/beacons/list_all.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/beacons/getBusinessFromBeacon.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/menu/items.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/orders/getOrCreateCart.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/orders/getCart.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/orders/setLineItem.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/orders/submit.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/orders/listForKDS.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/orders/updateStatus.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/orders/checkStatusUpdate.cfm", request._api_path)) request._api_isPublic = true;
|
|
|
|
if (findNoCase("/api/tasks/listPending.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/tasks/accept.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/tasks/listMine.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/tasks/complete.cfm", request._api_path)) request._api_isPublic = true;
|
|
|
|
// Worker app endpoints
|
|
if (findNoCase("/api/workers/myBusinesses.cfm", request._api_path)) request._api_isPublic = true;
|
|
|
|
// Portal endpoints
|
|
if (findNoCase("/api/portal/stats.cfm", request._api_path)) request._api_isPublic = true;
|
|
|
|
// Menu builder endpoints
|
|
if (findNoCase("/api/menu/getForBuilder.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/menu/saveFromBuilder.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/tasks/create.cfm", request._api_path)) request._api_isPublic = true;
|
|
|
|
// Admin endpoints
|
|
if (findNoCase("/api/admin/resetTestData.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/admin/debugTasks.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/admin/testTaskInsert.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/admin/debugBusinesses.cfm", request._api_path)) request._api_isPublic = true;
|
|
|
|
// Stripe endpoints
|
|
if (findNoCase("/api/stripe/onboard.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/stripe/status.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/stripe/createPaymentIntent.cfm", request._api_path)) request._api_isPublic = true;
|
|
if (findNoCase("/api/stripe/webhook.cfm", request._api_path)) request._api_isPublic = true;
|
|
}
|
|
|
|
// Carry session values into request (if present)
|
|
if (!structKeyExists(request, "UserID") && structKeyExists(session, "UserID")) {
|
|
request.UserID = Duplicate(session.UserID);
|
|
}
|
|
if (!structKeyExists(request, "BusinessID") && structKeyExists(session, "BusinessID")) {
|
|
request.BusinessID = Duplicate(session.BusinessID);
|
|
}
|
|
|
|
// Token auth: X-User-Token -> request.UserID
|
|
request._api_userToken = headerValue("X-User-Token");
|
|
if (len(request._api_userToken)) {
|
|
try {
|
|
request._api_qTok = queryExecute(
|
|
"SELECT UserID FROM UserTokens WHERE Token = ? LIMIT 1",
|
|
[ { value = request._api_userToken, cfsqltype = "cf_sql_varchar" } ],
|
|
{ datasource = "payfrit" }
|
|
);
|
|
|
|
if (request._api_qTok.recordCount EQ 1) {
|
|
request.UserID = request._api_qTok.UserID;
|
|
session.UserID = request._api_qTok.UserID;
|
|
}
|
|
} catch (any e) {
|
|
// ignore; treated as unauthenticated
|
|
}
|
|
}
|
|
|
|
// Business header: X-Business-ID -> request.BusinessID
|
|
request._api_hdrBiz = headerValue("X-Business-ID");
|
|
if (len(request._api_hdrBiz) && isNumeric(request._api_hdrBiz)) {
|
|
request.BusinessID = int(request._api_hdrBiz);
|
|
session.BusinessID = request.BusinessID;
|
|
}
|
|
|
|
|
|
// Enforce auth (except public)
|
|
if (!request._api_isPublic) {
|
|
if (!structKeyExists(request, "UserID") || !isNumeric(request.UserID) || request.UserID LTE 0) {
|
|
apiAbort({ "OK": false, "ERROR": "not_logged_in" });
|
|
}
|
|
if (!structKeyExists(request, "BusinessID") || !isNumeric(request.BusinessID) || request.BusinessID LTE 0) {
|
|
apiAbort({ "OK": false, "ERROR": "no_business_selected" });
|
|
}
|
|
}
|
|
</cfscript>
|