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/tabs/approveOrder.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

98 lines
3.8 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>
/**
* Approve Tab Order
* Tab owner approves a pending member order. Order is then submitted to kitchen.
*
* POST: { TabID: int, OrderID: int, UserID: int (tab owner) }
*/
try {
requestData = deserializeJSON(toString(getHttpRequestData().content));
tabID = val(requestData.TabID ?: 0);
orderID = val(requestData.OrderID ?: 0);
userID = val(requestData.UserID ?: 0);
if (tabID == 0) apiAbort({ "OK": false, "ERROR": "missing_TabID" });
if (orderID == 0) apiAbort({ "OK": false, "ERROR": "missing_OrderID" });
if (userID == 0) apiAbort({ "OK": false, "ERROR": "missing_UserID" });
// Verify tab owner
qTab = queryTimed("
SELECT ID, OwnerUserID, StatusID, AuthAmountCents, RunningTotalCents
FROM Tabs WHERE ID = :tabID LIMIT 1
", { tabID: { value: tabID, cfsqltype: "cf_sql_integer" } });
if (qTab.recordCount == 0) apiAbort({ "OK": false, "ERROR": "tab_not_found" });
if (qTab.StatusID != 1) apiAbort({ "OK": false, "ERROR": "tab_not_open" });
if (qTab.OwnerUserID != userID) apiAbort({ "OK": false, "ERROR": "not_owner" });
// Get the pending order
qTabOrder = queryTimed("
SELECT ID, SubtotalCents, TaxCents, ApprovalStatus
FROM TabOrders WHERE TabID = :tabID AND OrderID = :orderID LIMIT 1
", {
tabID: { value: tabID, cfsqltype: "cf_sql_integer" },
orderID: { value: orderID, cfsqltype: "cf_sql_integer" }
});
if (qTabOrder.recordCount == 0) apiAbort({ "OK": false, "ERROR": "order_not_on_tab" });
if (qTabOrder.ApprovalStatus != "pending") apiAbort({ "OK": false, "ERROR": "not_pending", "MESSAGE": "Order is #qTabOrder.ApprovalStatus#, not pending." });
// Check authorization limit
orderTotal = qTabOrder.SubtotalCents + qTabOrder.TaxCents;
newRunning = qTab.RunningTotalCents + orderTotal;
if (newRunning > qTab.AuthAmountCents) {
apiAbort({
"OK": false, "ERROR": "exceeds_authorization",
"MESSAGE": "Approving this order would exceed your tab authorization. Increase your authorization first.",
"RUNNING_TOTAL_CENTS": qTab.RunningTotalCents,
"ORDER_CENTS": orderTotal,
"AUTH_AMOUNT_CENTS": qTab.AuthAmountCents
});
}
// Approve
queryTimed("
UPDATE TabOrders SET ApprovalStatus = 'approved', ApprovedByUserID = :approverID, ApprovedOn = NOW()
WHERE TabID = :tabID AND OrderID = :orderID
", {
approverID: { value: userID, cfsqltype: "cf_sql_integer" },
tabID: { value: tabID, cfsqltype: "cf_sql_integer" },
orderID: { value: orderID, cfsqltype: "cf_sql_integer" }
});
// Update running total
queryTimed("
UPDATE Tabs SET RunningTotalCents = :newRunning, LastActivityOn = NOW()
WHERE ID = :tabID
", {
newRunning: { value: newRunning, cfsqltype: "cf_sql_integer" },
tabID: { value: tabID, cfsqltype: "cf_sql_integer" }
});
// Auto-submit order to kitchen (StatusID 0 → 1)
qOrder = queryTimed("SELECT StatusID FROM Orders WHERE ID = :orderID LIMIT 1", {
orderID: { value: orderID, cfsqltype: "cf_sql_integer" }
});
if (qOrder.StatusID == 0) {
queryTimed("
UPDATE Orders SET StatusID = 1, SubmittedOn = NOW(), LastEditedOn = NOW()
WHERE ID = :orderID
", { orderID: { value: orderID, cfsqltype: "cf_sql_integer" } });
}
apiAbort({
"OK": true,
"RUNNING_TOTAL_CENTS": newRunning,
"AUTH_REMAINING_CENTS": qTab.AuthAmountCents - newRunning
});
} catch (any e) {
apiAbort({ "OK": false, "ERROR": "server_error", "MESSAGE": e.message });
}
</cfscript>