false, 'ERROR' => 'missing_TabID']); if ($userID === 0) apiAbort(['OK' => false, 'ERROR' => 'missing_UserID']); // 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; // Get tab $qTab = queryOne(" SELECT t.*, b.Name AS BusinessName, b.PayfritFee, b.TaxRate, sp.Name AS ServicePointName, u.FirstName AS OwnerFirstName, u.LastName AS OwnerLastName FROM Tabs t JOIN Businesses b ON b.ID = t.BusinessID LEFT JOIN ServicePoints sp ON sp.ID = t.ServicePointID JOIN Users u ON u.ID = t.OwnerUserID WHERE t.ID = ? LIMIT 1 ", [$tabID]); if (!$qTab) apiAbort(['OK' => false, 'ERROR' => 'tab_not_found']); // Get members $qMembers = queryTimed(" SELECT tm.ID, tm.UserID, tm.RoleID, tm.StatusID, tm.JoinedOn, u.FirstName, u.LastName, u.ImageExtension FROM TabMembers tm JOIN Users u ON u.ID = tm.UserID WHERE tm.TabID = ? AND tm.StatusID = 1 ORDER BY tm.RoleID, tm.JoinedOn ", [$tabID]); $members = []; foreach ($qMembers as $row) { $members[] = [ 'UserID' => (int) $row['UserID'], 'FirstName' => $row['FirstName'], 'LastName' => $row['LastName'], 'RoleID' => (int) $row['RoleID'], 'IsOwner' => (int) $row['RoleID'] === 1, 'ImageExtension' => $row['ImageExtension'] ?? '', 'JoinedOn' => toISO8601($row['JoinedOn']), ]; } // Get orders $qOrders = queryTimed(" SELECT tbo.OrderID, tbo.UserID, tbo.ApprovalStatus, tbo.SubtotalCents, tbo.TaxCents, tbo.AddedOn, o.StatusID AS OrderStatusID, o.UUID AS OrderUUID, u.FirstName, u.LastName FROM TabOrders tbo JOIN Orders o ON o.ID = tbo.OrderID JOIN Users u ON u.ID = tbo.UserID WHERE tbo.TabID = ? ORDER BY tbo.AddedOn DESC ", [$tabID]); $orders = []; foreach ($qOrders as $row) { if (!$isOwner && (int) $row['UserID'] !== $userID) continue; $orders[] = [ 'OrderID' => (int) $row['OrderID'], 'OrderUUID' => $row['OrderUUID'], 'UserID' => (int) $row['UserID'], 'UserName' => $row['FirstName'] . ' ' . $row['LastName'], 'ApprovalStatus' => $row['ApprovalStatus'], 'SubtotalCents' => (int) $row['SubtotalCents'], 'TaxCents' => (int) $row['TaxCents'], 'OrderStatusID' => (int) $row['OrderStatusID'], 'AddedOn' => toISO8601($row['AddedOn']), ]; } jsonResponse([ 'OK' => true, 'TAB' => [ 'ID' => (int) $qTab['ID'], 'UUID' => $qTab['UUID'], 'BusinessID' => (int) $qTab['BusinessID'], 'BusinessName' => $qTab['BusinessName'], 'OwnerUserID' => (int) $qTab['OwnerUserID'], 'OwnerName' => $qTab['OwnerFirstName'] . ' ' . $qTab['OwnerLastName'], 'ServicePointID' => (int) ($qTab['ServicePointID'] ?? 0), 'ServicePointName' => $qTab['ServicePointName'] ?? '', 'StatusID' => (int) $qTab['StatusID'], 'AuthAmountCents' => (int) $qTab['AuthAmountCents'], 'RunningTotalCents' => (int) $qTab['RunningTotalCents'], 'RemainingCents' => (int) $qTab['AuthAmountCents'] - (int) $qTab['RunningTotalCents'], 'TipAmountCents' => (int) ($qTab['TipAmountCents'] ?? 0), 'FinalCaptureCents' => (int) ($qTab['FinalCaptureCents'] ?? 0), 'PaymentStatus' => $qTab['PaymentStatus'] ?? '', 'OpenedOn' => toISO8601($qTab['OpenedOn']), 'ClosedOn' => !empty($qTab['ClosedOn']) ? toISO8601($qTab['ClosedOn']) : '', 'IsOwner' => $isOwner, 'PayfritFee' => (float) ($qTab['PayfritFee'] ?? 0), 'TaxRate' => (float) ($qTab['TaxRate'] ?? 0), ], 'MEMBERS' => $members, 'ORDERS' => $orders, ]); } catch (Exception $e) { jsonResponse(['OK' => false, 'ERROR' => 'server_error', 'MESSAGE' => $e->getMessage()]); }