payfrit-works/api/beacons/lookup.cfm
John Mizerek c2ae037e71 App Store Version 2: Multi-menu support, beacon lookup, category scheduling
Features:
- Multi-menu support with time-based availability
- Menu hours validation against business operating hours
- Setup wizard now creates Menu records and links categories
- New menus.cfm API for menu CRUD operations
- Category schedule filtering (day/time based visibility)
- Beacon UUID lookup API for customer app
- Parent/child business relationships for franchises
- Category listing API for menu builder

Portal improvements:
- Menu builder theming to match admin UI
- Brand color picker fix
- Header image preview improvements

API fixes:
- Filter demo/hidden businesses from restaurant list
- Improved error handling throughout

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 19:51:44 -08:00

113 lines
3.5 KiB
Text

<cfsetting showdebugoutput="false">
<cfsetting enablecfoutputonly="true">
<cfcontent type="application/json; charset=utf-8" reset="true">
<cfscript>
/**
* Lookup beacons by UUID
*
* POST: {
* UUIDs: array of UUID strings (without dashes, uppercase)
* }
*
* Returns: {
* OK: true,
* BEACONS: [
* {
* UUID: "...",
* BeaconID: int,
* BeaconName: string,
* BusinessID: int,
* BusinessName: string,
* ServicePointID: int,
* ServicePointName: string,
* ParentBusinessID: int (if applicable),
* ParentBusinessName: string (if applicable),
* HasChildren: boolean
* }
* ]
* }
*/
response = { "OK": false };
try {
requestData = deserializeJSON(toString(getHttpRequestData().content));
uuids = requestData.UUIDs ?: [];
if (!isArray(uuids) || arrayLen(uuids) == 0) {
response["OK"] = true;
response["BEACONS"] = [];
writeOutput(serializeJSON(response));
abort;
}
// Clean and normalize UUIDs (remove dashes, uppercase)
cleanUUIDs = [];
for (uuid in uuids) {
cleanUUID = uCase(reReplace(uuid, "-", "", "all"));
if (len(cleanUUID) == 32) {
arrayAppend(cleanUUIDs, cleanUUID);
}
}
if (arrayLen(cleanUUIDs) == 0) {
response["OK"] = true;
response["BEACONS"] = [];
writeOutput(serializeJSON(response));
abort;
}
// Query for matching beacons with business info
// Beacons link to ServicePoints via lt_Beacon_Businesses_ServicePoints
qBeacons = queryExecute("
SELECT
b.BeaconID,
b.BeaconName,
b.BeaconUUID,
COALESCE(link.ServicePointID, 0) AS ServicePointID,
COALESCE(sp.ServicePointName, '') AS ServicePointName,
COALESCE(link.BusinessID, b.BeaconBusinessID) AS BusinessID,
biz.BusinessName,
biz.BusinessParentBusinessID,
parent.BusinessName AS ParentBusinessName,
(SELECT COUNT(*) FROM Businesses WHERE BusinessParentBusinessID = biz.BusinessID) AS ChildCount
FROM Beacons b
LEFT JOIN lt_Beacon_Businesses_ServicePoints link ON b.BeaconID = link.BeaconID
LEFT JOIN ServicePoints sp ON link.ServicePointID = sp.ServicePointID
INNER JOIN Businesses biz ON COALESCE(link.BusinessID, b.BeaconBusinessID) = biz.BusinessID
LEFT JOIN Businesses parent ON biz.BusinessParentBusinessID = parent.BusinessID
WHERE b.BeaconUUID IN (:uuids)
AND b.BeaconIsActive = 1
AND biz.BusinessIsDemo = 0
AND biz.BusinessIsPrivate = 0
", {
uuids: { value: arrayToList(cleanUUIDs), cfsqltype: "cf_sql_varchar", list: true }
}, { datasource: "payfrit" });
beacons = [];
for (row in qBeacons) {
arrayAppend(beacons, {
"UUID": row.BeaconUUID,
"BeaconID": row.BeaconID,
"BeaconName": row.BeaconName,
"BusinessID": row.BusinessID,
"BusinessName": row.BusinessName,
"ServicePointID": row.ServicePointID,
"ServicePointName": row.ServicePointName,
"ParentBusinessID": val(row.BusinessParentBusinessID),
"ParentBusinessName": row.ParentBusinessName ?: "",
"HasChildren": row.ChildCount > 0
});
}
response["OK"] = true;
response["BEACONS"] = beacons;
} catch (any e) {
response["ERROR"] = e.message;
}
writeOutput(serializeJSON(response));
</cfscript>