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/update.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

136 lines
4.5 KiB
Text

<cfsetting showdebugoutput="false">
<cfsetting enablecfoutputonly="true">
<cfcontent type="application/json; charset=utf-8" reset="true">
<cfscript>
/**
* Update Business Info
*
* POST JSON:
* {
* "BusinessID": 37,
* "BusinessName": "My Business",
* "BusinessPhone": "(555) 123-4567",
* "AddressLine1": "123 Main St",
* "City": "Los Angeles",
* "State": "CA",
* "Zip": "90001"
* }
*/
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");
}
// Update business name, phone, and tax rate
bizName = structKeyExists(data, "BusinessName") && isSimpleValue(data.BusinessName) ? trim(data.BusinessName) : "";
bizPhone = structKeyExists(data, "BusinessPhone") && isSimpleValue(data.BusinessPhone) ? trim(data.BusinessPhone) : "";
// Handle tax rate (accept either TaxRatePercent like 8.25, or TaxRate like 0.0825)
taxRate = "";
if (structKeyExists(data, "TaxRatePercent") && isNumeric(data.TaxRatePercent)) {
taxRate = data.TaxRatePercent / 100;
} else if (structKeyExists(data, "TaxRate") && isNumeric(data.TaxRate)) {
taxRate = data.TaxRate;
}
if (len(bizName)) {
if (isNumeric(taxRate)) {
queryExecute("
UPDATE Businesses SET BusinessName = :name, BusinessPhone = :phone, BusinessTaxRate = :taxRate
WHERE BusinessID = :id
", {
name: bizName,
phone: bizPhone,
taxRate: { value: taxRate, cfsqltype: "cf_sql_decimal" },
id: businessId
}, { datasource: "payfrit" });
} else {
queryExecute("
UPDATE Businesses SET BusinessName = :name, BusinessPhone = :phone
WHERE BusinessID = :id
", {
name: bizName,
phone: bizPhone,
id: businessId
}, { datasource: "payfrit" });
}
}
// Update or create address
addressLine1 = structKeyExists(data, "AddressLine1") && isSimpleValue(data.AddressLine1) ? trim(data.AddressLine1) : "";
city = structKeyExists(data, "City") && isSimpleValue(data.City) ? trim(data.City) : "";
state = structKeyExists(data, "State") && isSimpleValue(data.State) ? trim(data.State) : "";
zip = structKeyExists(data, "Zip") && isSimpleValue(data.Zip) ? trim(data.Zip) : "";
// Clean up city - remove trailing punctuation
city = reReplace(city, "[,.\s]+$", "", "all");
// Get state ID
stateID = 0;
if (len(state)) {
qState = queryExecute("
SELECT tt_StateID FROM tt_States WHERE tt_StateAbbreviation = :abbr
", { abbr: uCase(state) }, { datasource: "payfrit" });
if (qState.recordCount > 0) {
stateID = qState.tt_StateID;
}
}
// Check if business has an address
qAddr = queryExecute("
SELECT AddressID FROM Addresses
WHERE AddressBusinessID = :bizID AND AddressUserID = 0 AND AddressIsDeleted = 0
LIMIT 1
", { bizID: businessId }, { datasource: "payfrit" });
if (qAddr.recordCount > 0) {
// Update existing address
queryExecute("
UPDATE Addresses SET
AddressLine1 = :line1,
AddressCity = :city,
AddressStateID = :stateID,
AddressZIPCode = :zip
WHERE AddressID = :addrID
", {
line1: addressLine1,
city: city,
stateID: stateID,
zip: zip,
addrID: qAddr.AddressID
}, { datasource: "payfrit" });
} else {
// Create new address
queryExecute("
INSERT INTO Addresses (AddressLine1, AddressCity, AddressStateID, AddressZIPCode, AddressBusinessID, AddressUserID, AddressTypeID, AddressAddedOn)
VALUES (:line1, :city, :stateID, :zip, :bizID, 0, 2, NOW())
", {
line1: addressLine1,
city: city,
stateID: stateID,
zip: zip,
bizID: businessId
}, { datasource: "payfrit" });
}
response.OK = true;
appCacheInvalidate("biz_" & businessId);
} catch (any e) {
response.ERROR = e.message;
}
writeOutput(serializeJSON(response));
</cfscript>