false, 'ERROR' => 'missing_business_id', 'MESSAGE' => 'BusinessID is required']); } $spId = (int) ($data['ServicePointID'] ?? ($_GET['ServicePointID'] ?? 0)); if ($spId <= 0) { apiAbort(['OK' => false, 'ERROR' => 'missing_servicepoint_id', 'MESSAGE' => 'ServicePointID is required']); } try { $qSP = queryOne("SELECT ID, BusinessID, Name, BeaconMinor FROM ServicePoints WHERE ID = ? LIMIT 1", [$spId]); if (!$qSP) { apiAbort(['OK' => false, 'ERROR' => 'invalid_servicepoint', 'MESSAGE' => 'Service point not found']); } if ((int) $qSP['BusinessID'] !== $bizId) { apiAbort(['OK' => false, 'ERROR' => 'access_denied', 'MESSAGE' => 'Service point does not belong to this business']); } // Already allocated if ($qSP['BeaconMinor'] !== null) { jsonResponse([ 'OK' => true, 'ServicePointID' => $spId, 'BusinessID' => $bizId, 'BeaconMinor' => (int) $qSP['BeaconMinor'], 'ServicePointName' => $qSP['Name'], 'AlreadyAllocated' => true, ]); } $qMaxMinor = queryOne(" SELECT COALESCE(MAX(BeaconMinor), -1) AS MaxMinor FROM ServicePoints WHERE BusinessID = ? ", [$bizId]); $nextMinor = (int) $qMaxMinor['MaxMinor'] + 1; if ($nextMinor > 65535) { apiAbort(['OK' => false, 'ERROR' => 'business_full', 'MESSAGE' => 'Business has reached maximum service points (65535)']); } queryTimed("UPDATE ServicePoints SET BeaconMinor = ? WHERE ID = ? AND BeaconMinor IS NULL", [$nextMinor, $spId]); jsonResponse([ 'OK' => true, 'ServicePointID' => $spId, 'BusinessID' => $bizId, 'BeaconMinor' => $nextMinor, 'ServicePointName' => $qSP['Name'], 'AlreadyAllocated' => false, ]); } catch (Exception $e) { jsonResponse(['OK' => false, 'ERROR' => 'server_error', 'MESSAGE' => $e->getMessage()]); }