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 4e0cc65ba2 Auto-geocode addresses on create/update
Extract geocoding functions into shared api/inc/geocode.cfm and call
geocodeAddressById() via cfthread after every address INSERT or UPDATE.
Uses OpenStreetMap Nominatim (free, no API key). Non-blocking — the
HTTP call runs in a background thread so responses aren't delayed.

Affected endpoints:
- setup/saveWizard.cfm (new business creation)
- businesses/update.cfm (business address update)
- portal/updateSettings.cfm (portal settings save)
- addresses/add.cfm (customer delivery address)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 01:00:07 -08:00

146 lines
4.6 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,
* "Name": "My Business",
* "Phone": "(555) 123-4567",
* "Line1": "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, "Name") && isSimpleValue(data.Name) ? trim(data.Name) : "";
bizPhone = structKeyExists(data, "Phone") && isSimpleValue(data.Phone) ? trim(data.Phone) : "";
// 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)) {
queryTimed("
UPDATE Businesses SET Name = :name, Phone = :phone, TaxRate = :taxRate
WHERE ID = :id
", {
name: bizName,
phone: bizPhone,
taxRate: { value: taxRate, cfsqltype: "cf_sql_decimal" },
id: businessId
}, { datasource: "payfrit" });
} else {
queryTimed("
UPDATE Businesses SET Name = :name, Phone = :phone
WHERE ID = :id
", {
name: bizName,
phone: bizPhone,
id: businessId
}, { datasource: "payfrit" });
}
}
// Update or create address
addressLine1 = structKeyExists(data, "Line1") && isSimpleValue(data.Line1) ? trim(data.Line1) : "";
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 = queryTimed("
SELECT ID FROM tt_States WHERE Abbreviation = :abbr
", { abbr: uCase(state) }, { datasource: "payfrit" });
if (qState.recordCount > 0) {
stateID = qState.ID;
}
}
// Check if business has an address
qAddr = queryTimed("
SELECT ID FROM Addresses
WHERE BusinessID = :bizID AND UserID = 0 AND IsDeleted = 0
LIMIT 1
", { bizID: businessId }, { datasource: "payfrit" });
if (qAddr.recordCount > 0) {
// Update existing address
queryTimed("
UPDATE Addresses SET
Line1 = :line1,
City = :city,
StateID = :stateID,
ZIPCode = :zip
WHERE ID = :addrID
", {
line1: addressLine1,
city: city,
stateID: stateID,
zip: zip,
addrID: qAddr.ID
}, { datasource: "payfrit" });
geocodeAddrId = qAddr.ID;
} else {
// Create new address
queryTimed("
INSERT INTO Addresses (Line1, City, StateID, ZIPCode, BusinessID, UserID, AddressTypeID, AddedOn)
VALUES (:line1, :city, :stateID, :zip, :bizID, 0, 2, NOW())
", {
line1: addressLine1,
city: city,
stateID: stateID,
zip: zip,
bizID: businessId
}, { datasource: "payfrit" });
qNewAddr = queryTimed("SELECT LAST_INSERT_ID() as id", {}, { datasource: "payfrit" });
geocodeAddrId = qNewAddr.id;
}
// Auto-geocode address in background
</cfscript>
<cfthread action="run" name="geocode_biz_#geocodeAddrId#" addressId="#geocodeAddrId#">
<cfinclude template="/api/inc/geocode.cfm">
<cfset geocodeAddressById(attributes.addressId)>
</cfthread>
<cfscript>
response.OK = true;
} catch (any e) {
response.ERROR = e.message;
}
writeOutput(serializeJSON(response));
</cfscript>