- 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>
99 lines
4.7 KiB
Text
99 lines
4.7 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>
|
|
function apiAbort(obj) {
|
|
writeOutput(serializeJSON(obj));
|
|
abort;
|
|
}
|
|
|
|
function readJsonBody() {
|
|
raw = toString(getHttpRequestData().content);
|
|
if (isNull(raw) || len(trim(raw)) EQ 0) {
|
|
apiAbort({ OK = false, ERROR = "missing_body" });
|
|
}
|
|
try {
|
|
parsed = deserializeJSON(raw);
|
|
} catch (any e) {
|
|
apiAbort({ OK = false, ERROR = "bad_json", MESSAGE = "Invalid JSON body" });
|
|
}
|
|
if (!isStruct(parsed)) {
|
|
apiAbort({ OK = false, ERROR = "bad_json", MESSAGE = "JSON must be an object" });
|
|
}
|
|
return parsed;
|
|
}
|
|
|
|
data = readJsonBody();
|
|
|
|
if (!structKeyExists(data, "BusinessID") || !isNumeric(data.BusinessID) || int(data.BusinessID) LTE 0) {
|
|
apiAbort({ OK = false, ERROR = "missing_BusinessID" });
|
|
}
|
|
|
|
BusinessID = int(data.BusinessID);
|
|
SessionEnabled = structKeyExists(data, "SessionEnabled") && isNumeric(data.SessionEnabled) ? int(data.SessionEnabled) : 0;
|
|
SessionLockMinutes = structKeyExists(data, "SessionLockMinutes") && isNumeric(data.SessionLockMinutes) ? int(data.SessionLockMinutes) : 30;
|
|
SessionPaymentStrategy = structKeyExists(data, "SessionPaymentStrategy") ? left(trim(data.SessionPaymentStrategy), 1) : "A";
|
|
TabMinAuthAmount = structKeyExists(data, "TabMinAuthAmount") && isNumeric(data.TabMinAuthAmount) ? val(data.TabMinAuthAmount) : 50.00;
|
|
TabDefaultAuthAmount = structKeyExists(data, "TabDefaultAuthAmount") && isNumeric(data.TabDefaultAuthAmount) ? val(data.TabDefaultAuthAmount) : 150.00;
|
|
TabMaxAuthAmount = structKeyExists(data, "TabMaxAuthAmount") && isNumeric(data.TabMaxAuthAmount) ? val(data.TabMaxAuthAmount) : 1000.00;
|
|
TabAutoIncreaseThreshold = structKeyExists(data, "TabAutoIncreaseThreshold") && isNumeric(data.TabAutoIncreaseThreshold) ? val(data.TabAutoIncreaseThreshold) : 0.80;
|
|
TabMaxMembers = structKeyExists(data, "TabMaxMembers") && isNumeric(data.TabMaxMembers) ? int(data.TabMaxMembers) : 10;
|
|
TabApprovalRequired = structKeyExists(data, "TabApprovalRequired") && isNumeric(data.TabApprovalRequired) ? int(data.TabApprovalRequired) : 1;
|
|
|
|
// Validate
|
|
if (SessionLockMinutes < 5) SessionLockMinutes = 5;
|
|
if (SessionLockMinutes > 480) SessionLockMinutes = 480;
|
|
if (SessionPaymentStrategy != "A" && SessionPaymentStrategy != "P") SessionPaymentStrategy = "A";
|
|
if (TabMinAuthAmount < 10) TabMinAuthAmount = 10;
|
|
if (TabMinAuthAmount > 10000) TabMinAuthAmount = 10000;
|
|
if (TabDefaultAuthAmount < TabMinAuthAmount) TabDefaultAuthAmount = TabMinAuthAmount;
|
|
if (TabDefaultAuthAmount > TabMaxAuthAmount) TabDefaultAuthAmount = TabMaxAuthAmount;
|
|
if (TabMaxAuthAmount < TabMinAuthAmount) TabMaxAuthAmount = TabMinAuthAmount;
|
|
if (TabMaxAuthAmount > 10000) TabMaxAuthAmount = 10000;
|
|
if (TabAutoIncreaseThreshold < 0.5) TabAutoIncreaseThreshold = 0.5;
|
|
if (TabAutoIncreaseThreshold > 1.0) TabAutoIncreaseThreshold = 1.0;
|
|
if (TabMaxMembers < 1) TabMaxMembers = 1;
|
|
if (TabMaxMembers > 50) TabMaxMembers = 50;
|
|
</cfscript>
|
|
|
|
<cftry>
|
|
<cfquery datasource="payfrit">
|
|
UPDATE Businesses
|
|
SET SessionEnabled = <cfqueryparam cfsqltype="cf_sql_tinyint" value="#SessionEnabled#">,
|
|
SessionLockMinutes = <cfqueryparam cfsqltype="cf_sql_integer" value="#SessionLockMinutes#">,
|
|
SessionPaymentStrategy = <cfqueryparam cfsqltype="cf_sql_char" value="#SessionPaymentStrategy#">,
|
|
TabMinAuthAmount = <cfqueryparam cfsqltype="cf_sql_decimal" value="#TabMinAuthAmount#">,
|
|
TabDefaultAuthAmount = <cfqueryparam cfsqltype="cf_sql_decimal" value="#TabDefaultAuthAmount#">,
|
|
TabMaxAuthAmount = <cfqueryparam cfsqltype="cf_sql_decimal" value="#TabMaxAuthAmount#">,
|
|
TabAutoIncreaseThreshold = <cfqueryparam cfsqltype="cf_sql_decimal" value="#TabAutoIncreaseThreshold#">,
|
|
TabMaxMembers = <cfqueryparam cfsqltype="cf_sql_integer" value="#TabMaxMembers#">,
|
|
TabApprovalRequired = <cfqueryparam cfsqltype="cf_sql_tinyint" value="#TabApprovalRequired#">
|
|
WHERE ID = <cfqueryparam cfsqltype="cf_sql_integer" value="#BusinessID#">
|
|
</cfquery>
|
|
|
|
<cfoutput>#serializeJSON({
|
|
"OK" = true,
|
|
"ERROR" = "",
|
|
"BusinessID" = BusinessID,
|
|
"SessionEnabled" = SessionEnabled,
|
|
"SessionLockMinutes" = SessionLockMinutes,
|
|
"SessionPaymentStrategy" = SessionPaymentStrategy,
|
|
"TabMinAuthAmount" = TabMinAuthAmount,
|
|
"TabDefaultAuthAmount" = TabDefaultAuthAmount,
|
|
"TabMaxAuthAmount" = TabMaxAuthAmount,
|
|
"TabAutoIncreaseThreshold" = TabAutoIncreaseThreshold,
|
|
"TabMaxMembers" = TabMaxMembers,
|
|
"TabApprovalRequired" = TabApprovalRequired
|
|
})#</cfoutput>
|
|
|
|
<cfcatch>
|
|
<cfoutput>#serializeJSON({
|
|
"OK" = false,
|
|
"ERROR" = "server_error",
|
|
"MESSAGE" = cfcatch.message
|
|
})#</cfoutput>
|
|
</cfcatch>
|
|
</cftry>
|