Fix beacon sharding to support Major/Minor starting from 0

- allocate_business_namespace: Start Major from 0 (was 1)
- allocate_servicepoint_minor: Start Minor from 0 (was 1)
- register_beacon_hardware: Set BeaconMinor if empty instead of rejecting
- lookup: Allow Major=0 in validation (was LTE 0, now LT 0)
- servicepoints/save: Auto-allocate BeaconMinor on insert, include in response

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
John Mizerek 2026-02-09 13:42:19 -08:00
parent 872897eabc
commit b8cf2ce150
5 changed files with 32 additions and 15 deletions

View file

@ -117,9 +117,9 @@ if (bizId LTE 0) {
<cfset shardUUID = qShard.UUID>
<!--- Find next available Major within this shard --->
<!--- Major values: 0-65535 (uint16), we start from 1 to avoid 0 --->
<!--- Major values: 0-65535 (uint16), starting from 0 --->
<cfquery name="qMaxMajor" datasource="payfrit">
SELECT COALESCE(MAX(BeaconMajor), 0) AS MaxMajor
SELECT COALESCE(MAX(BeaconMajor), -1) AS MaxMajor
FROM Businesses
WHERE BeaconShardID = <cfqueryparam cfsqltype="cf_sql_integer" value="#shardId#">
</cfquery>

View file

@ -111,9 +111,9 @@ if (spId LTE 0) {
</cfif>
<!--- Find next available Minor within this business --->
<!--- Minor values: 0-65535 (uint16), we start from 1 to avoid 0 --->
<!--- Minor values: 0-65535 (uint16), starting from 0 --->
<cfquery name="qMaxMinor" datasource="payfrit">
SELECT COALESCE(MAX(BeaconMinor), 0) AS MaxMinor
SELECT COALESCE(MAX(BeaconMinor), -1) AS MaxMinor
FROM ServicePoints
WHERE BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#bizId#">
</cfquery>

View file

@ -165,7 +165,14 @@ firmwareVersion = normStr(structKeyExists(data, "FirmwareVersion") ? data.Firmwa
<cfset apiAbort({ OK=false, ERROR="servicepoint_business_mismatch", MESSAGE="Service point does not belong to this business" })>
</cfif>
<cfif qSP.BeaconMinor NEQ minor>
<!--- If service point doesn't have a minor yet, set it now --->
<cfif isNull(qSP.BeaconMinor) OR len(trim(qSP.BeaconMinor)) EQ 0>
<cfquery datasource="payfrit">
UPDATE ServicePoints
SET BeaconMinor = <cfqueryparam cfsqltype="cf_sql_smallint" value="#minor#">
WHERE ID = <cfqueryparam cfsqltype="cf_sql_integer" value="#spId#">
</cfquery>
<cfelseif qSP.BeaconMinor NEQ minor>
<cfset apiAbort({
OK=false,
ERROR="minor_mismatch",

View file

@ -35,7 +35,7 @@
<cfset minor = int(beaconData.Minor)>
</cfif>
<cfif len(uuid) EQ 0 OR major LTE 0 OR minor LT 0>
<cfif len(uuid) EQ 0 OR major LT 0 OR minor LT 0>
<cfcontinue>
</cfif>

View file

@ -89,7 +89,17 @@ if (structKeyExists(data, "IsActive")) {
</cfif>
<cfelse>
<!--- Insert --->
<!--- Auto-allocate BeaconMinor if not provided --->
<cfif beaconMinor LT 0>
<cfquery name="qMaxMinor" datasource="payfrit">
SELECT COALESCE(MAX(BeaconMinor), -1) AS MaxMinor
FROM ServicePoints
WHERE BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
</cfquery>
<cfset beaconMinor = qMaxMinor.MaxMinor + 1>
</cfif>
<!--- Insert with BeaconMinor --->
<cfquery datasource="payfrit">
INSERT INTO ServicePoints (
BusinessID,
@ -97,16 +107,16 @@ if (structKeyExists(data, "IsActive")) {
Code,
TypeID,
IsActive,
SortOrder
<cfif beaconMinor GTE 0>, BeaconMinor</cfif>
SortOrder,
BeaconMinor
) VALUES (
<cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#spName#">,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#spCode#" null="#(len(spCode) EQ 0)#">,
<cfqueryparam cfsqltype="cf_sql_integer" value="#spTypeID#">,
<cfqueryparam cfsqltype="cf_sql_tinyint" value="#isActive#">,
<cfqueryparam cfsqltype="cf_sql_integer" value="#sortOrder#">
<cfif beaconMinor GTE 0>, <cfqueryparam cfsqltype="cf_sql_smallint" value="#beaconMinor#"></cfif>
<cfqueryparam cfsqltype="cf_sql_integer" value="#sortOrder#">,
<cfqueryparam cfsqltype="cf_sql_smallint" value="#beaconMinor#">
)
</cfquery>
@ -138,10 +148,10 @@ if (structKeyExists(data, "IsActive")) {
"BusinessID" = qOut.BusinessID,
"Name" = qOut.Name,
"Code" = qOut.Code,
"TypeID"= qOut.TypeID,
"TypeID" = qOut.TypeID,
"IsActive" = qOut.IsActive,
"SortOrder" = qOut.SortOrder,
"BeaconMinor" = val(qOut.BeaconMinor)
"BeaconMinor" = isNull(qOut.BeaconMinor) ? "" : qOut.BeaconMinor
}>
<cfoutput>#serializeJSON({ OK=true, ERROR="", SERVICEPOINT=servicePoint })#</cfoutput>