false, 'ERROR' => 'missing_TabID']); if ($orderID === 0) apiAbort(['OK' => false, 'ERROR' => 'missing_OrderID']); if ($userID === 0) apiAbort(['OK' => false, 'ERROR' => 'missing_UserID']); $qTab = queryOne(" SELECT t.ID, t.StatusID, t.BusinessID, t.OwnerUserID, t.AuthAmountCents, t.RunningTotalCents, t.ApprovalMode, b.TabApprovalRequired, b.TabAutoIncreaseThreshold FROM Tabs t JOIN Businesses b ON b.ID = t.BusinessID WHERE t.ID = ? LIMIT 1 ", [$tabID]); if (!$qTab) apiAbort(['OK' => false, 'ERROR' => 'tab_not_found']); if ((int) $qTab['StatusID'] !== 1) apiAbort(['OK' => false, 'ERROR' => 'tab_not_open']); // Verify user is a member $qMember = queryOne("SELECT RoleID FROM TabMembers WHERE TabID = ? AND UserID = ? AND StatusID = 1 LIMIT 1", [$tabID, $userID]); if (!$qMember) apiAbort(['OK' => false, 'ERROR' => 'not_a_member']); $isOwner = (int) $qMember['RoleID'] === 1; // Verify order $qOrder = queryOne("SELECT ID, BusinessID, StatusID, UserID FROM Orders WHERE ID = ? LIMIT 1", [$orderID]); if (!$qOrder) apiAbort(['OK' => false, 'ERROR' => 'order_not_found']); if ((int) $qOrder['BusinessID'] !== (int) $qTab['BusinessID']) apiAbort(['OK' => false, 'ERROR' => 'wrong_business']); if ((int) $qOrder['StatusID'] !== 0) apiAbort(['OK' => false, 'ERROR' => 'order_not_in_cart', 'MESSAGE' => 'Order must be in cart state.']); // Calculate order subtotal + tax $qTotals = queryOne(" SELECT COALESCE(SUM(oli.Price * oli.Quantity), 0) AS Subtotal FROM OrderLineItems oli WHERE oli.OrderID = ? AND oli.IsDeleted = 0 ", [$orderID]); $subtotal = (float) $qTotals['Subtotal']; $subtotalCents = round($subtotal * 100); $qBizTax = queryOne("SELECT TaxRate FROM Businesses WHERE ID = ?", [$qTab['BusinessID']]); $taxRate = (float) ($qBizTax['TaxRate'] ?? 0); $taxCents = round($subtotalCents * $taxRate); // Determine approval status $approvalMode = $qTab['ApprovalMode'] ?? ''; $requiresApproval = (is_numeric($approvalMode) && $approvalMode !== '') ? (int) $approvalMode === 1 : (int) ($qTab['TabApprovalRequired'] ?? 0) === 1; $approvalStatus = (!$isOwner && $requiresApproval) ? 'pending' : 'approved'; // Check authorization limit for auto-approved orders $newRunning = (int) $qTab['RunningTotalCents']; if ($approvalStatus === 'approved') { $newRunning = (int) $qTab['RunningTotalCents'] + $subtotalCents + $taxCents; if ($newRunning > (int) $qTab['AuthAmountCents']) { apiAbort([ 'OK' => false, 'ERROR' => 'exceeds_authorization', 'MESSAGE' => 'This order would exceed your tab authorization. Please increase your authorization first.', 'RUNNING_TOTAL_CENTS' => (int) $qTab['RunningTotalCents'], 'ORDER_CENTS' => $subtotalCents + $taxCents, 'AUTH_AMOUNT_CENTS' => (int) $qTab['AuthAmountCents'], ]); } } // Link order to tab queryTimed("UPDATE Orders SET TabID = ? WHERE ID = ?", [$tabID, $orderID]); queryTimed(" INSERT INTO TabOrders (TabID, OrderID, UserID, ApprovalStatus, SubtotalCents, TaxCents, AddedOn) VALUES (?, ?, ?, ?, ?, ?, NOW()) ON DUPLICATE KEY UPDATE ApprovalStatus = VALUES(ApprovalStatus), SubtotalCents = VALUES(SubtotalCents), TaxCents = VALUES(TaxCents) ", [$tabID, $orderID, $userID, $approvalStatus, $subtotalCents, $taxCents]); if ($approvalStatus === 'approved') { queryTimed("UPDATE Tabs SET RunningTotalCents = ?, LastActivityOn = NOW() WHERE ID = ?", [$newRunning, $tabID]); } // Check auto-increase threshold $needsIncrease = false; $threshold = (float) ($qTab['TabAutoIncreaseThreshold'] ?? 0); if ($threshold > 0 && (int) $qTab['AuthAmountCents'] > 0) { $needsIncrease = ($newRunning / (int) $qTab['AuthAmountCents']) >= $threshold; } jsonResponse([ 'OK' => true, 'APPROVAL_STATUS' => $approvalStatus, 'RUNNING_TOTAL_CENTS' => $newRunning, 'AUTH_REMAINING_CENTS' => (int) $qTab['AuthAmountCents'] - $newRunning, 'NEEDS_INCREASE' => $needsIncrease, 'ORDER_SUBTOTAL_CENTS' => $subtotalCents, 'ORDER_TAX_CENTS' => $taxCents, ]); } catch (Exception $e) { jsonResponse(['OK' => false, 'ERROR' => 'server_error', 'MESSAGE' => $e->getMessage()]); }