Add per-tab ApprovalMode override for member order approval

- open.cfm: accept optional ApprovalMode param (0=auto, 1=manual, NULL=business default)
- addOrder.cfm: check tab ApprovalMode first, fall back to business TabApprovalRequired
- getActive.cfm: return resolved ApprovalRequired in tab response

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
John Mizerek 2026-02-25 11:44:06 -08:00
parent 623b94cb3d
commit ec3a15013b
3 changed files with 15 additions and 8 deletions

View file

@ -24,7 +24,7 @@ try {
// Get tab // Get tab
qTab = queryTimed(" qTab = queryTimed("
SELECT t.ID, t.StatusID, t.BusinessID, t.OwnerUserID, t.AuthAmountCents, t.RunningTotalCents, SELECT t.ID, t.StatusID, t.BusinessID, t.OwnerUserID, t.AuthAmountCents, t.RunningTotalCents,
b.TabApprovalRequired, b.TabAutoIncreaseThreshold t.ApprovalMode, b.TabApprovalRequired, b.TabAutoIncreaseThreshold
FROM Tabs t FROM Tabs t
JOIN Businesses b ON b.ID = t.BusinessID JOIN Businesses b ON b.ID = t.BusinessID
WHERE t.ID = :tabID LIMIT 1 WHERE t.ID = :tabID LIMIT 1
@ -72,9 +72,12 @@ try {
taxRate = val(qBizTax.TaxRate); taxRate = val(qBizTax.TaxRate);
taxCents = round(subtotalCents * taxRate); taxCents = round(subtotalCents * taxRate);
// Determine approval status // Determine approval status: per-tab ApprovalMode overrides business default
approvalStatus = "approved"; approvalStatus = "approved";
if (!isOwner && qTab.TabApprovalRequired == 1) { requiresApproval = len(trim(qTab.ApprovalMode)) && isNumeric(qTab.ApprovalMode)
? val(qTab.ApprovalMode) == 1
: qTab.TabApprovalRequired == 1;
if (!isOwner && requiresApproval) {
approvalStatus = "pending"; approvalStatus = "pending";
} }

View file

@ -19,7 +19,7 @@ try {
qTab = queryTimed(" qTab = queryTimed("
SELECT t.ID, t.UUID, t.BusinessID, t.OwnerUserID, t.ServicePointID, SELECT t.ID, t.UUID, t.BusinessID, t.OwnerUserID, t.ServicePointID,
t.StatusID, t.AuthAmountCents, t.RunningTotalCents, t.StatusID, t.AuthAmountCents, t.RunningTotalCents,
t.OpenedOn, t.LastActivityOn, t.PaymentStatus, t.OpenedOn, t.LastActivityOn, t.PaymentStatus, t.ApprovalMode,
b.Name AS BusinessName, b.TabApprovalRequired, b.Name AS BusinessName, b.TabApprovalRequired,
tm.RoleID, tm.RoleID,
sp.Name AS ServicePointName, sp.Name AS ServicePointName,
@ -73,7 +73,9 @@ try {
"MemberCount": qMembers.MemberCount, "MemberCount": qMembers.MemberCount,
"PendingOrderCount": pendingCount, "PendingOrderCount": pendingCount,
"IsOwner": qTab.RoleID == 1, "IsOwner": qTab.RoleID == 1,
"ApprovalRequired": qTab.TabApprovalRequired == 1 "ApprovalRequired": len(trim(qTab.ApprovalMode)) && isNumeric(qTab.ApprovalMode)
? val(qTab.ApprovalMode) == 1
: qTab.TabApprovalRequired == 1
} }
}); });

View file

@ -32,6 +32,7 @@ try {
authAmount = val(requestData.AuthAmount ?: 0); authAmount = val(requestData.AuthAmount ?: 0);
} }
servicePointID = val(requestData.ServicePointID ?: 0); servicePointID = val(requestData.ServicePointID ?: 0);
approvalMode = structKeyExists(requestData, "ApprovalMode") ? val(requestData.ApprovalMode) : javaCast("null", "");
if (userID == 0) apiAbort({ "OK": false, "ERROR": "missing_UserID" }); if (userID == 0) apiAbort({ "OK": false, "ERROR": "missing_UserID" });
if (businessID == 0) apiAbort({ "OK": false, "ERROR": "missing_BusinessID" }); if (businessID == 0) apiAbort({ "OK": false, "ERROR": "missing_BusinessID" });
@ -147,8 +148,8 @@ try {
// Insert tab // Insert tab
queryTimed(" queryTimed("
INSERT INTO Tabs (UUID, BusinessID, OwnerUserID, ServicePointID, StatusID, INSERT INTO Tabs (UUID, BusinessID, OwnerUserID, ServicePointID, StatusID,
AuthAmountCents, StripePaymentIntentID, StripeCustomerID, OpenedOn, LastActivityOn) AuthAmountCents, StripePaymentIntentID, StripeCustomerID, ApprovalMode, OpenedOn, LastActivityOn)
VALUES (:uuid, :bizID, :userID, :spID, 1, :authCents, :piID, :custID, NOW(), NOW()) VALUES (:uuid, :bizID, :userID, :spID, 1, :authCents, :piID, :custID, :approvalMode, NOW(), NOW())
", { ", {
uuid: { value: tabUUID, cfsqltype: "cf_sql_varchar" }, uuid: { value: tabUUID, cfsqltype: "cf_sql_varchar" },
bizID: { value: businessID, cfsqltype: "cf_sql_integer" }, bizID: { value: businessID, cfsqltype: "cf_sql_integer" },
@ -156,7 +157,8 @@ try {
spID: { value: servicePointID > 0 ? servicePointID : javaCast("null", ""), cfsqltype: "cf_sql_integer", null: servicePointID <= 0 }, spID: { value: servicePointID > 0 ? servicePointID : javaCast("null", ""), cfsqltype: "cf_sql_integer", null: servicePointID <= 0 },
authCents: { value: authAmountCents, cfsqltype: "cf_sql_integer" }, authCents: { value: authAmountCents, cfsqltype: "cf_sql_integer" },
piID: { value: piData.id, cfsqltype: "cf_sql_varchar" }, piID: { value: piData.id, cfsqltype: "cf_sql_varchar" },
custID: { value: stripeCustomerId, cfsqltype: "cf_sql_varchar" } custID: { value: stripeCustomerId, cfsqltype: "cf_sql_varchar" },
approvalMode: { value: isNull(approvalMode) ? javaCast("null", "") : approvalMode, cfsqltype: "cf_sql_tinyint", null: isNull(approvalMode) }
}); });
// Get the tab ID // Get the tab ID