This repository has been archived on 2026-03-21. You can view files and clone it, but cannot push or open issues or pull requests.
payfrit-biz/api/businesses/updateTabs.cfm
John Mizerek 4c0479db5c Add Open Tabs feature: tab APIs, presence tracking, shared tabs, cron, portal settings
- 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>
2026-02-24 20:56:07 -08:00

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>