diff --git a/api/beacons/list.cfm b/api/beacons/list.cfm
index 6df35a2..e84a80e 100644
--- a/api/beacons/list.cfm
+++ b/api/beacons/list.cfm
@@ -42,7 +42,7 @@ if (bizId LTE 0) {
apiAbort({ OK=false, ERROR="no_business_selected" });
}
-// Default behavior: only active beacons unless onlyActive is explicitly false/0
+// Default behavior: only active unless onlyActive is explicitly false/0
onlyActive = true;
if (structKeyExists(data, "onlyActive")) {
if (isBoolean(data.onlyActive)) {
@@ -55,102 +55,66 @@ if (structKeyExists(data, "onlyActive")) {
}
-
+
- SELECT BeaconShardID, BeaconMajor
- FROM Businesses
- WHERE ID =
+ SELECT b.ID, b.Name, b.BeaconShardID, b.BeaconMajor, bs.UUID AS ShardUUID
+ FROM Businesses b
+ LEFT JOIN BeaconShards bs ON bs.ID = b.BeaconShardID
+ WHERE b.ID =
LIMIT 1
-
-
-
-
-
-
- SELECT UUID FROM BeaconShards WHERE ID =
-
-
+
+ #serializeJSON({ OK=false, ERROR="business_not_found" })#
+
-
-
- SELECT DISTINCT
- b.ID,
- b.BusinessID,
- b.Name,
- b.UUID,
- b.IsActive
- FROM Beacons b
- WHERE (
- b.BusinessID =
- OR b.ID IN (
- SELECT lt.BeaconID FROM lt_BeaconsID_BusinessesID lt
- WHERE lt.BusinessID =
- )
- )
+
+
+
+
+
+ SELECT
+ sp.ID AS ServicePointID,
+ sp.Name,
+ sp.BeaconMinor,
+ sp.IsActive,
+ sp.TypeID
+ FROM ServicePoints sp
+ WHERE sp.BusinessID =
+ AND sp.BeaconMinor IS NOT NULL
- AND b.IsActive = 1
+ AND sp.IsActive = 1
- ORDER BY b.Name, b.ID
+ ORDER BY sp.BeaconMinor, sp.Name
-
+
-
-
-
- SELECT
- sp.ID AS ServicePointID,
- sp.Name,
- sp.BeaconMinor,
- sp.IsActive
- FROM ServicePoints sp
- WHERE sp.BusinessID =
- AND sp.BeaconMinor IS NOT NULL
-
- AND sp.IsActive = 1
-
- ORDER BY sp.BeaconMinor, sp.Name
-
-
-
-
-
-
-
try{logPerf(0);}catch(any e){}
#serializeJSON({
- OK=true,
- ERROR="",
- BusinessID=bizId,
- COUNT=arrayLen(beacons),
- BEACONS=beacons,
- USES_SHARDING=usesSharding,
- SHARDING_INFO=shardingInfo
+ OK = true,
+ ERROR = "",
+ BusinessID = bizId,
+ BusinessName = qBiz.Name,
+ COUNT = arrayLen(beacons),
+ BEACONS = beacons,
+ HAS_SHARD = hasShard,
+ SHARD_INFO = shardInfo
})#
diff --git a/api/beacons/list_all.cfm b/api/beacons/list_all.cfm
index 54308ef..5df93b5 100644
--- a/api/beacons/list_all.cfm
+++ b/api/beacons/list_all.cfm
@@ -4,20 +4,11 @@
-
-function apiAbort(obj) {
- writeOutput(serializeJSON(obj));
- abort;
-}
-
-
-
+
- SELECT
- ID,
- UUID
- FROM Beacons
+ SELECT ID, UUID
+ FROM BeaconShards
WHERE IsActive = 1
ORDER BY ID
@@ -25,7 +16,7 @@ function apiAbort(obj) {
@@ -33,5 +24,6 @@ function apiAbort(obj) {
#serializeJSON({
"OK" = true,
"ERROR" = "",
+ "SHARDS" = items,
"ITEMS" = items
})#
diff --git a/api/beacons/lookup.cfm b/api/beacons/lookup.cfm
index 8c9d95e..8c6940b 100644
--- a/api/beacons/lookup.cfm
+++ b/api/beacons/lookup.cfm
@@ -6,95 +6,10 @@
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- SELECT
- biz.ID AS BusinessID,
- biz.Name AS BusinessName,
- biz.ParentBusinessID,
- COALESCE(parent.Name, '') AS ParentBusinessName,
- sp.ID AS ServicePointID,
- sp.Name AS ServicePointName,
- bs.UUID AS ShardUUID,
- (SELECT COUNT(*) FROM Businesses WHERE ParentBusinessID = biz.ID) AS ChildCount
- FROM BeaconShards bs
- JOIN Businesses biz ON biz.BeaconShardID = bs.ID AND biz.BeaconMajor =
- LEFT JOIN ServicePoints sp ON sp.BusinessID = biz.ID AND sp.BeaconMinor = AND sp.IsActive = 1
- LEFT JOIN Businesses parent ON biz.ParentBusinessID = parent.ID
- WHERE LEFT(REPLACE(bs.UUID, '-', ''), 20) =
- AND bs.IsActive = 1
- AND biz.IsDemo = 0
- AND biz.IsPrivate = 0
- LIMIT 1
-
-
-
-
-
-
-
- #serializeJSON({
- "OK" = true,
- "ERROR" = "",
- "BEACONS" = beacons
- })#
-
-
-
-
-
+
#serializeJSON({
"OK" = true,
"ERROR" = "",
@@ -103,62 +18,69 @@
-
-
-
-
-
-
-
-
-
-
- #serializeJSON({
- "OK" = true,
- "ERROR" = "",
- "BEACONS" = []
- })#
-
-
-
-
-
- SELECT
- b.ID AS BeaconID,
- b.Name AS BeaconName,
- b.UUID,
- COALESCE(sp.ID, 0) AS ServicePointID,
- COALESCE(sp.Name, '') AS ServicePointName,
- COALESCE(sp.BusinessID, lt.BusinessID, b.BusinessID) AS BusinessID,
- biz.Name AS BusinessName,
- biz.ParentBusinessID AS ParentBusinessID,
- COALESCE(parent.Name, '') AS ParentBusinessName,
- (SELECT COUNT(*) FROM Businesses WHERE ParentBusinessID = biz.ID) AS ChildCount
- FROM Beacons b
- LEFT JOIN ServicePoints sp ON sp.BeaconID = b.ID
- LEFT JOIN lt_BeaconsID_BusinessesID lt ON lt.BeaconID = b.ID
- INNER JOIN Businesses biz ON COALESCE(sp.BusinessID, lt.BusinessID, b.BusinessID) = biz.ID
- LEFT JOIN Businesses parent ON biz.ParentBusinessID = parent.ID
- WHERE b.UUID IN ()
- AND b.IsActive = 1
- AND biz.IsDemo = 0
- AND biz.IsPrivate = 0
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SELECT
+ biz.ID AS BusinessID,
+ biz.Name AS BusinessName,
+ biz.ParentBusinessID,
+ COALESCE(parent.Name, '') AS ParentBusinessName,
+ sp.ID AS ServicePointID,
+ sp.Name AS ServicePointName,
+ (SELECT COUNT(*) FROM Businesses WHERE ParentBusinessID = biz.ID) AS ChildCount
+ FROM BeaconShards bs
+ JOIN Businesses biz ON biz.BeaconShardID = bs.ID AND biz.BeaconMajor =
+ LEFT JOIN ServicePoints sp ON sp.BusinessID = biz.ID AND sp.BeaconMinor = AND sp.IsActive = 1
+ LEFT JOIN Businesses parent ON biz.ParentBusinessID = parent.ID
+ WHERE bs.UUID =
+ AND bs.IsActive = 1
+ AND biz.IsDemo = 0
+ AND biz.IsPrivate = 0
+ LIMIT 1
+
+
+
+
+
#serializeJSON({
diff --git a/api/beacons/save.cfm b/api/beacons/save.cfm
index cfc0de2..3cfcadc 100644
--- a/api/beacons/save.cfm
+++ b/api/beacons/save.cfm
@@ -34,155 +34,158 @@ if (!structKeyExists(request, "BusinessID") || !isNumeric(request.BusinessID) ||
apiAbort({ OK=false, ERROR="no_business_selected" });
}
-// Verify the business exists
-qBiz = queryTimed(
- "SELECT ID FROM Businesses WHERE ID = ? LIMIT 1",
- [ { value=request.BusinessID, cfsqltype="cf_sql_integer" } ],
+businessID = request.BusinessID;
+
+// Get business and check if it has a shard assigned
+qBiz = queryExecute(
+ "SELECT ID, Name, BeaconShardID, BeaconMajor FROM Businesses WHERE ID = ? LIMIT 1",
+ [ { value=businessID, cfsqltype="cf_sql_integer" } ],
{ datasource="payfrit" }
);
if (qBiz.recordCount EQ 0) {
- apiAbort({ OK=false, ERROR="invalid_business", MESSAGE="Business ID #request.BusinessID# does not exist. Please log out and log back in." });
+ apiAbort({ OK=false, ERROR="invalid_business", MESSAGE="Business not found" });
}
-if (!structKeyExists(data, "Name") || len(normStr(data.Name)) EQ 0) {
- apiAbort({ OK=false, ERROR="missing_beacon_name", MESSAGE="Name is required" });
-}
+// If business doesn't have a shard, allocate one
+shardID = qBiz.BeaconShardID;
+major = qBiz.BeaconMajor;
-beaconId = 0;
-if (structKeyExists(data, "BeaconID") && isNumeric(data.BeaconID) && int(data.BeaconID) GT 0) {
- beaconId = int(data.BeaconID);
-}
-
-beaconName = normStr(data.Name);
-uuid = structKeyExists(data, "UUID") ? normStr(data.UUID) : "";
-
-isActive = 1;
-if (structKeyExists(data, "IsActive")) {
- if (isBoolean(data.IsActive)) isActive = (data.IsActive ? 1 : 0);
- else if (isNumeric(data.IsActive)) isActive = int(data.IsActive);
- else if (isSimpleValue(data.IsActive)) isActive = (lcase(trim(toString(data.IsActive))) EQ "true" ? 1 : 0);
-}
-
-// App is authoritative: if UUID exists, treat as update (overwrite)
-if (beaconId EQ 0 && len(uuid) GT 0) {
- qExisting = queryTimed(
- "SELECT ID FROM Beacons WHERE UUID = ? LIMIT 1",
- [ { value=uuid, cfsqltype="cf_sql_varchar" } ],
+if (isNull(shardID) || val(shardID) EQ 0) {
+ // Find an unassigned shard
+ qFreeShard = queryExecute(
+ "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",
+ [],
{ datasource="payfrit" }
);
- if (qExisting.recordCount GT 0) {
- beaconId = qExisting.ID;
+
+ if (qFreeShard.recordCount EQ 0) {
+ apiAbort({ OK=false, ERROR="no_shards_available", MESSAGE="No beacon shards available" });
}
+
+ shardID = qFreeShard.ID;
+
+ // Find next available major for this shard (in case multiple businesses share a shard in future)
+ qMaxMajor = queryExecute(
+ "SELECT COALESCE(MAX(BeaconMajor), 0) AS MaxMajor FROM Businesses WHERE BeaconShardID = ?",
+ [ { value=shardID, cfsqltype="cf_sql_integer" } ],
+ { datasource="payfrit" }
+ );
+ major = val(qMaxMajor.MaxMajor) + 1;
+
+ // Assign shard to business
+ queryExecute(
+ "UPDATE Businesses SET BeaconShardID = ?, BeaconMajor = ? WHERE ID = ?",
+ [
+ { value=shardID, cfsqltype="cf_sql_integer" },
+ { value=major, cfsqltype="cf_sql_smallint" },
+ { value=businessID, cfsqltype="cf_sql_integer" }
+ ],
+ { datasource="payfrit" }
+ );
}
+
+// Get the shard UUID
+qShard = queryExecute(
+ "SELECT UUID FROM BeaconShards WHERE ID = ?",
+ [ { value=shardID, cfsqltype="cf_sql_integer" } ],
+ { datasource="payfrit" }
+);
+shardUUID = qShard.UUID;
+
+// Service point handling
+spName = structKeyExists(data, "Name") ? normStr(data.Name) : "";
+if (len(spName) EQ 0) {
+ apiAbort({ OK=false, ERROR="missing_name", MESSAGE="Service point name is required" });
+}
+
+servicePointID = 0;
+if (structKeyExists(data, "ServicePointID") && isNumeric(data.ServicePointID) && int(data.ServicePointID) GT 0) {
+ servicePointID = int(data.ServicePointID);
+}
+
+// Check if we're updating an existing service point or creating new
+if (servicePointID GT 0) {
+ // Update existing service point
+ qSP = queryExecute(
+ "SELECT ID, BeaconMinor FROM ServicePoints WHERE ID = ? AND BusinessID = ? LIMIT 1",
+ [
+ { value=servicePointID, cfsqltype="cf_sql_integer" },
+ { value=businessID, cfsqltype="cf_sql_integer" }
+ ],
+ { datasource="payfrit" }
+ );
+
+ if (qSP.recordCount EQ 0) {
+ apiAbort({ OK=false, ERROR="invalid_service_point", MESSAGE="Service point not found" });
+ }
+
+ minor = qSP.BeaconMinor;
+
+ // If no minor assigned yet, get next available
+ if (isNull(minor)) {
+ qMaxMinor = queryExecute(
+ "SELECT COALESCE(MAX(BeaconMinor), 0) AS MaxMinor FROM ServicePoints WHERE BusinessID = ?",
+ [ { value=businessID, cfsqltype="cf_sql_integer" } ],
+ { datasource="payfrit" }
+ );
+ minor = val(qMaxMinor.MaxMinor) + 1;
+ }
+
+ // Update service point
+ queryExecute(
+ "UPDATE ServicePoints SET Name = ?, BeaconMinor = ?, IsActive = 1 WHERE ID = ?",
+ [
+ { value=spName, cfsqltype="cf_sql_varchar" },
+ { value=minor, cfsqltype="cf_sql_smallint" },
+ { value=servicePointID, cfsqltype="cf_sql_integer" }
+ ],
+ { datasource="payfrit" }
+ );
+
+} else {
+ // Create new service point with next available minor
+ qMaxMinor = queryExecute(
+ "SELECT COALESCE(MAX(BeaconMinor), 0) AS MaxMinor FROM ServicePoints WHERE BusinessID = ?",
+ [ { value=businessID, cfsqltype="cf_sql_integer" } ],
+ { datasource="payfrit" }
+ );
+ minor = val(qMaxMinor.MaxMinor) + 1;
+
+ queryExecute(
+ "INSERT INTO ServicePoints (BusinessID, Name, TypeID, IsActive, BeaconMinor, SortOrder)
+ VALUES (?, ?, 1, 1, ?, ?)",
+ [
+ { value=businessID, cfsqltype="cf_sql_integer" },
+ { value=spName, cfsqltype="cf_sql_varchar" },
+ { value=minor, cfsqltype="cf_sql_smallint" },
+ { value=minor, cfsqltype="cf_sql_integer" }
+ ],
+ { datasource="payfrit" }
+ );
+
+ qNewSP = queryExecute("SELECT LAST_INSERT_ID() AS ID", [], { datasource="payfrit" });
+ servicePointID = qNewSP.ID;
+}
+
+// Return the beacon configuration for programming
+writeOutput(serializeJSON({
+ OK = true,
+ ERROR = "",
+ ServicePointID = servicePointID,
+ ServicePointName = spName,
+ BusinessID = businessID,
+ BusinessName = qBiz.Name,
+ ShardID = shardID,
+ UUID = shardUUID,
+ Major = major,
+ Minor = minor
+}));
-
-
-
- UPDATE Beacons
- SET
- BusinessID = ,
- Name = ,
- UUID = ,
- IsActive =
- WHERE ID =
-
-
-
-
- SELECT ID FROM ServicePoints
- WHERE BeaconID =
- LIMIT 1
-
-
-
- UPDATE ServicePoints
- SET Name = ,
- BusinessID =
- WHERE BeaconID =
-
-
-
-
- INSERT INTO ServicePoints (
- BusinessID,
- Name,
- TypeID,
- IsActive,
- BeaconID
- ) VALUES (
- ,
- ,
- 1,
- 1,
-
- )
-
-
-
-
-
-
- INSERT INTO Beacons (
- BusinessID,
- Name,
- UUID,
- IsActive
- ) VALUES (
- ,
- ,
- ,
-
- )
-
-
-
- SELECT LAST_INSERT_ID() AS ID
-
-
-
-
-
- INSERT INTO ServicePoints (
- BusinessID,
- Name,
- TypeID,
- IsActive,
- BeaconID
- ) VALUES (
- ,
- ,
- 1,
- 1,
-
- )
-
-
-
-
-
- SELECT
- ID,
- BusinessID,
- Name,
- UUID,
- IsActive
- FROM Beacons
- WHERE ID =
- AND BusinessID =
- LIMIT 1
-
-
-
-
-#serializeJSON({ OK=true, ERROR="", BEACON=beacon })#
-