try { // Get authenticated user ID from request context (set by Application.cfm) userId = request.UserID ?: 0; if (userId <= 0) { writeOutput(serializeJSON({ "OK": false, "ERROR": "unauthorized", "MESSAGE": "Authentication required" })); abort; } // Get user's delivery addresses (AddressTypeID contains "2" for delivery, BusinessID is 0 or NULL for personal) // Use GROUP BY to return only distinct addresses based on content qAddresses = queryExecute(" SELECT MIN(a.AddressID) as AddressID, a.AddressLabel, MAX(a.AddressIsDefaultDelivery) as AddressIsDefaultDelivery, a.AddressLine1, a.AddressLine2, a.AddressCity, a.AddressStateID, s.tt_StateAbbreviation as StateAbbreviation, s.tt_StateName as StateName, a.AddressZIPCode FROM Addresses a LEFT JOIN tt_States s ON a.AddressStateID = s.tt_StateID WHERE a.AddressUserID = :userId AND (a.AddressBusinessID = 0 OR a.AddressBusinessID IS NULL) AND a.AddressTypeID LIKE '%2%' AND a.AddressIsDeleted = 0 GROUP BY a.AddressLine1, COALESCE(a.AddressLine2, ''), a.AddressCity, a.AddressStateID, a.AddressZIPCode ORDER BY AddressIsDefaultDelivery DESC, AddressID DESC ", { userId: { value: userId, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); addresses = []; for (row in qAddresses) { arrayAppend(addresses, { "AddressID": row.AddressID, "Label": len(row.AddressLabel) ? row.AddressLabel : "Address", "IsDefault": row.AddressIsDefaultDelivery == 1, "Line1": row.AddressLine1, "Line2": row.AddressLine2 ?: "", "City": row.AddressCity, "StateID": row.AddressStateID, "StateAbbr": row.StateAbbreviation ?: "", "StateName": row.StateName ?: "", "ZIPCode": row.AddressZIPCode, "DisplayText": row.AddressLine1 & (len(row.AddressLine2) ? ", " & row.AddressLine2 : "") & ", " & row.AddressCity & ", " & (row.StateAbbreviation ?: "") & " " & row.AddressZIPCode }); } writeOutput(serializeJSON({ "OK": true, "ADDRESSES": addresses })); } catch (any e) { writeOutput(serializeJSON({ "OK": false, "ERROR": "server_error", "MESSAGE": e.message })); }