This repository has been archived on 2026-03-21. You can view files and clone it, but cannot push or open issues or pull requests.
payfrit-biz/api/beacons/lookup.cfm
John Mizerek 2f35eb69eb Add beacon sharding support to lookup API
The lookup API now handles two formats:
1. Sharding: { "Beacons": [{ "UUID", "Major", "Minor" }] }
   Resolves via BeaconShards -> Businesses.BeaconMajor -> ServicePoints.BeaconMinor
2. Legacy: { "UUIDs": ["..."] }
   Resolves via old Beacons table

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-08 12:21:30 -08:00

172 lines
6.1 KiB
Text

<cfsetting showdebugoutput="false">
<cfsetting enablecfoutputonly="true">
<cfcontent type="application/json; charset=utf-8" reset="true">
<cftry>
<cfset requestData = deserializeJSON(toString(getHttpRequestData().content))>
<!--- ============================================================================
SHARDING FORMAT: { "Beacons": [{ "UUID": "...", "Major": 49, "Minor": 15 }] }
Resolves via BeaconShards -> Businesses (BeaconMajor) -> ServicePoints (BeaconMinor)
============================================================================ --->
<cfif structKeyExists(requestData, "Beacons") AND isArray(requestData.Beacons) AND arrayLen(requestData.Beacons) GT 0>
<cfset beacons = []>
<cfloop array="#requestData.Beacons#" index="beaconData">
<cfset uuid = "">
<cfset major = 0>
<cfset minor = -1>
<!--- Extract UUID (normalize: remove dashes, add back in standard format) --->
<cfif structKeyExists(beaconData, "UUID")>
<cfset rawUuid = uCase(reReplace(beaconData.UUID, "-", "", "all"))>
<cfif len(rawUuid) EQ 32>
<!--- Convert to standard UUID format with dashes for DB lookup --->
<cfset uuid = lCase(mid(rawUuid,1,8) & "-" & mid(rawUuid,9,4) & "-" & mid(rawUuid,13,4) & "-" & mid(rawUuid,17,4) & "-" & mid(rawUuid,21,12))>
</cfif>
</cfif>
<cfif structKeyExists(beaconData, "Major") AND isNumeric(beaconData.Major)>
<cfset major = int(beaconData.Major)>
</cfif>
<cfif structKeyExists(beaconData, "Minor") AND isNumeric(beaconData.Minor)>
<cfset minor = int(beaconData.Minor)>
</cfif>
<cfif len(uuid) EQ 0 OR major LTE 0 OR minor LT 0>
<cfcontinue>
</cfif>
<!--- Resolve via sharding: UUID -> Shard -> Business (Major) -> ServicePoint (Minor) --->
<cfquery name="qShard" datasource="payfrit">
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 = <cfqueryparam cfsqltype="cf_sql_smallint" value="#major#">
LEFT JOIN ServicePoints sp ON sp.BusinessID = biz.ID AND sp.BeaconMinor = <cfqueryparam cfsqltype="cf_sql_smallint" value="#minor#"> AND sp.IsActive = 1
LEFT JOIN Businesses parent ON biz.ParentBusinessID = parent.ID
WHERE bs.UUID = <cfqueryparam cfsqltype="cf_sql_varchar" value="#uuid#">
AND bs.IsActive = 1
AND biz.IsDemo = 0
AND biz.IsPrivate = 0
LIMIT 1
</cfquery>
<cfif qShard.recordCount GT 0>
<cfset arrayAppend(beacons, {
"UUID" = uCase(reReplace(uuid, "-", "", "all")),
"Major" = major,
"Minor" = minor,
"BeaconID" = 0,
"BeaconName" = qShard.ServicePointName,
"BusinessID" = qShard.BusinessID,
"BusinessName" = qShard.BusinessName,
"ServicePointID" = val(qShard.ServicePointID),
"ServicePointName" = qShard.ServicePointName,
"ParentBusinessID" = val(qShard.ParentBusinessID),
"ParentBusinessName" = qShard.ParentBusinessName,
"HasChildren" = qShard.ChildCount GT 0
})>
</cfif>
</cfloop>
<cfoutput>#serializeJSON({
"OK" = true,
"ERROR" = "",
"BEACONS" = beacons
})#</cfoutput>
<cfabort>
</cfif>
<!--- ============================================================================
LEGACY FORMAT: { "UUIDs": ["uuid1", "uuid2", ...] }
Resolves via old Beacons table
============================================================================ --->
<cfif NOT structKeyExists(requestData, "UUIDs") OR NOT isArray(requestData.UUIDs) OR arrayLen(requestData.UUIDs) EQ 0>
<cfoutput>#serializeJSON({
"OK" = true,
"ERROR" = "",
"BEACONS" = []
})#</cfoutput>
<cfabort>
</cfif>
<!--- Clean and normalize UUIDs (remove dashes, uppercase) --->
<cfset cleanUUIDs = []>
<cfloop array="#requestData.UUIDs#" index="uuid">
<cfset cleanUUID = uCase(reReplace(uuid, "-", "", "all"))>
<cfif len(cleanUUID) EQ 32>
<cfset arrayAppend(cleanUUIDs, cleanUUID)>
</cfif>
</cfloop>
<cfif arrayLen(cleanUUIDs) EQ 0>
<cfoutput>#serializeJSON({
"OK" = true,
"ERROR" = "",
"BEACONS" = []
})#</cfoutput>
<cfabort>
</cfif>
<!--- Query for matching beacons with business info --->
<cfquery name="qBeacons" datasource="payfrit">
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 (<cfqueryparam value="#arrayToList(cleanUUIDs)#" cfsqltype="cf_sql_varchar" list="true">)
AND b.IsActive = 1
AND biz.IsDemo = 0
AND biz.IsPrivate = 0
</cfquery>
<cfset beacons = []>
<cfloop query="qBeacons">
<cfset arrayAppend(beacons, {
"UUID" = qBeacons.UUID,
"BeaconID" = qBeacons.BeaconID,
"BeaconName" = qBeacons.BeaconName,
"BusinessID" = qBeacons.BusinessID,
"BusinessName" = qBeacons.BusinessName,
"ServicePointID" = qBeacons.ServicePointID,
"ServicePointName" = qBeacons.ServicePointName,
"ParentBusinessID" = val(qBeacons.ParentBusinessID),
"ParentBusinessName" = qBeacons.ParentBusinessName,
"HasChildren" = qBeacons.ChildCount GT 0
})>
</cfloop>
<cfoutput>#serializeJSON({
"OK" = true,
"ERROR" = "",
"BEACONS" = beacons
})#</cfoutput>
<cfcatch type="any">
<cfoutput>#serializeJSON({
"OK" = false,
"ERROR" = cfcatch.message
})#</cfoutput>
</cfcatch>
</cftry>