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/businesses/updateHours.cfm
John Mizerek dc9db32b58 Add API performance profiling, caching, and query optimizations
- Add queryTimed() wrapper and logPerf() for per-endpoint timing metrics
- Add api_perf_log table flush mechanism with background thread batching
- Add application-scope cache (appCacheGet/Put/Invalidate) with TTL
- Cache businesses/get (5m), addresses/states (24h), menu/items (2m)
- Fix N+1 queries in orders/history, orders/listForKDS (batch fetch)
- Fix correlated subquery in orders/getDetail (LEFT JOIN)
- Combine 4 queries into 1 in portal/stats (subselects)
- Optimize getForBuilder tree building with pre-indexed parent lookup
- Add cache invalidation in update, saveBrandColor, updateHours, saveFromBuilder
- New admin/perf.cfm dashboard (localhost-protected)
- Instrument top 10 endpoints with queryTimed + logPerf

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 20:41:27 -08:00

78 lines
2.2 KiB
Text

<cfsetting showdebugoutput="false">
<cfsetting enablecfoutputonly="true">
<cfcontent type="application/json; charset=utf-8" reset="true">
<cfscript>
/**
* Update Business Hours
*
* POST JSON:
* {
* "BusinessID": 37,
* "Hours": [
* { "dayId": 1, "open": "09:00", "close": "17:00" },
* { "dayId": 2, "open": "09:00", "close": "17:00" },
* ...
* ]
* }
*
* Days not in the Hours array are considered closed.
*/
response = { "OK": false };
try {
requestBody = toString(getHttpRequestData().content);
if (!len(requestBody)) {
throw(message="No request body provided");
}
data = deserializeJSON(requestBody);
businessId = structKeyExists(data, "BusinessID") ? val(data.BusinessID) : 0;
if (businessId == 0) {
throw(message="BusinessID is required");
}
hours = structKeyExists(data, "Hours") && isArray(data.Hours) ? data.Hours : [];
// Delete all existing hours for this business
queryExecute("
DELETE FROM Hours WHERE HoursBusinessID = :bizID
", { bizID: businessId }, { datasource: "payfrit" });
// Insert new hours
for (h in hours) {
if (!isStruct(h)) continue;
dayId = structKeyExists(h, "dayId") ? val(h.dayId) : 0;
openTime = structKeyExists(h, "open") && isSimpleValue(h.open) ? h.open : "09:00";
closeTime = structKeyExists(h, "close") && isSimpleValue(h.close) ? h.close : "17:00";
if (dayId >= 1 && dayId <= 7) {
// Convert HH:MM to HH:MM:SS if needed
if (len(openTime) == 5) openTime = openTime & ":00";
if (len(closeTime) == 5) closeTime = closeTime & ":00";
queryExecute("
INSERT INTO Hours (HoursBusinessID, HoursDayID, HoursOpenTime, HoursClosingTime)
VALUES (:bizID, :dayID, :openTime, :closeTime)
", {
bizID: businessId,
dayID: dayId,
openTime: openTime,
closeTime: closeTime
}, { datasource: "payfrit" });
}
}
response.OK = true;
response.hoursUpdated = arrayLen(hours);
appCacheInvalidate("biz_" & businessId);
} catch (any e) {
response.ERROR = e.message;
}
writeOutput(serializeJSON(response));
</cfscript>