false, 'ERROR' => 'no_business_selected']); } $qBiz = queryOne(" SELECT ID, Name, BeaconShardID, BeaconMajor FROM Businesses WHERE ID = ? LIMIT 1 ", [$businessId]); if (!$qBiz) { apiAbort(['OK' => false, 'ERROR' => 'invalid_business', 'MESSAGE' => 'Business not found']); } $shardID = (int) ($qBiz['BeaconShardID'] ?? 0); $major = (int) ($qBiz['BeaconMajor'] ?? 0); // Auto-allocate shard if needed if ($shardID <= 0) { $qFreeShard = queryOne(" SELECT bs.ID FROM BeaconShards bs WHERE bs.IsActive = 1 AND bs.ID NOT IN (SELECT BeaconShardID FROM Businesses WHERE BeaconShardID IS NOT NULL) ORDER BY bs.ID LIMIT 1 ", []); if (!$qFreeShard) { apiAbort(['OK' => false, 'ERROR' => 'no_shards_available', 'MESSAGE' => 'No beacon shards available']); } $shardID = (int) $qFreeShard['ID']; $qMaxMajor = queryOne(" SELECT COALESCE(MAX(BeaconMajor), 0) AS MaxMajor FROM Businesses WHERE BeaconShardID = ? ", [$shardID]); $major = (int) $qMaxMajor['MaxMajor'] + 1; queryTimed("UPDATE Businesses SET BeaconShardID = ?, BeaconMajor = ? WHERE ID = ?", [$shardID, $major, $businessId]); } $qShard = queryOne("SELECT UUID FROM BeaconShards WHERE ID = ?", [$shardID]); $shardUUID = $qShard['UUID']; // Service point handling $spName = trim($data['Name'] ?? ''); if ($spName === '') { apiAbort(['OK' => false, 'ERROR' => 'missing_name', 'MESSAGE' => 'Service point name is required']); } $servicePointID = (int) ($data['ServicePointID'] ?? 0); if ($servicePointID > 0) { $qSP = queryOne(" SELECT ID, BeaconMinor FROM ServicePoints WHERE ID = ? AND BusinessID = ? LIMIT 1 ", [$servicePointID, $businessId]); if (!$qSP) { apiAbort(['OK' => false, 'ERROR' => 'invalid_service_point', 'MESSAGE' => 'Service point not found']); } $minor = $qSP['BeaconMinor']; if ($minor === null) { $qMaxMinor = queryOne(" SELECT COALESCE(MAX(BeaconMinor), 0) AS MaxMinor FROM ServicePoints WHERE BusinessID = ? ", [$businessId]); $minor = (int) $qMaxMinor['MaxMinor'] + 1; } queryTimed("UPDATE ServicePoints SET Name = ?, BeaconMinor = ?, IsActive = 1 WHERE ID = ?", [$spName, $minor, $servicePointID]); } else { $qMaxMinor = queryOne(" SELECT COALESCE(MAX(BeaconMinor), 0) AS MaxMinor FROM ServicePoints WHERE BusinessID = ? ", [$businessId]); $minor = (int) $qMaxMinor['MaxMinor'] + 1; queryTimed(" INSERT INTO ServicePoints (BusinessID, Name, TypeID, IsActive, BeaconMinor, SortOrder) VALUES (?, ?, 1, 1, ?, ?) ", [$businessId, $spName, $minor, $minor]); $servicePointID = (int) lastInsertId(); } jsonResponse([ 'OK' => true, 'ERROR' => '', 'ServicePointID' => $servicePointID, 'ServicePointName' => $spName, 'BusinessID' => $businessId, 'BusinessName' => $qBiz['Name'], 'ShardID' => $shardID, 'UUID' => $shardUUID, 'Major' => $major, 'Minor' => (int) $minor, ]);