- New api/tabs/ directory with 13 endpoints: open, close, cancel, get, getActive, addOrder, increaseAuth, addMember, removeMember, getPresence, approveOrder, rejectOrder, pendingOrders - New api/presence/heartbeat.cfm for beacon-based user presence tracking - New cron/expireTabs.cfm for idle tab expiry and presence cleanup - Modified submit.cfm for tab-aware order submission (skip payment, update running total) - Modified getOrCreateCart.cfm to auto-detect active tab and set TabID on new carts - Modified webhook.cfm to handle tab capture events (metadata type=tab_close) - Modified businesses/get.cfm and updateTabs.cfm with new tab config columns - Updated portal tab settings UI with auth amounts, max members, approval toggle - Added tab and presence endpoints to Application.cfm public allowlist Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
46 lines
1.6 KiB
Text
46 lines
1.6 KiB
Text
<cfsetting showdebugoutput="false">
|
|
<cfsetting enablecfoutputonly="true">
|
|
<cfcontent type="application/json; charset=utf-8" reset="true">
|
|
<cfheader name="Cache-Control" value="no-store">
|
|
|
|
<cfscript>
|
|
/**
|
|
* Presence Heartbeat
|
|
* Records/updates that a user is at a specific business + service point.
|
|
* Called on beacon scan + periodic heartbeat from the app.
|
|
*
|
|
* POST: { UserID: int, BusinessID: int, ServicePointID: int (optional) }
|
|
*/
|
|
|
|
response = { "OK": false };
|
|
|
|
try {
|
|
requestData = deserializeJSON(toString(getHttpRequestData().content));
|
|
|
|
userID = val(requestData.UserID ?: 0);
|
|
businessID = val(requestData.BusinessID ?: 0);
|
|
servicePointID = val(requestData.ServicePointID ?: 0);
|
|
|
|
if (userID == 0) apiAbort({ "OK": false, "ERROR": "missing_UserID" });
|
|
if (businessID == 0) apiAbort({ "OK": false, "ERROR": "missing_BusinessID" });
|
|
|
|
// Upsert presence (UNIQUE on UserID means one row per user)
|
|
queryTimed("
|
|
INSERT INTO UserPresence (UserID, BusinessID, ServicePointID, LastSeenOn)
|
|
VALUES (:userID, :businessID, :spID, NOW())
|
|
ON DUPLICATE KEY UPDATE
|
|
BusinessID = VALUES(BusinessID),
|
|
ServicePointID = VALUES(ServicePointID),
|
|
LastSeenOn = NOW()
|
|
", {
|
|
userID: { value: userID, cfsqltype: "cf_sql_integer" },
|
|
businessID: { value: businessID, cfsqltype: "cf_sql_integer" },
|
|
spID: { value: servicePointID > 0 ? servicePointID : javaCast("null", ""), cfsqltype: "cf_sql_integer", null: servicePointID <= 0 }
|
|
});
|
|
|
|
apiAbort({ "OK": true });
|
|
|
|
} catch (any e) {
|
|
apiAbort({ "OK": false, "ERROR": "server_error", "MESSAGE": e.message });
|
|
}
|
|
</cfscript>
|