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/ratings/submit.cfm
John Mizerek 1210249f54 Normalize database column and table names across entire codebase
Update all SQL queries, query result references, and ColdFusion code to match
the renamed database schema. Tables use plural CamelCase, PKs are all `ID`,
column prefixes stripped (e.g. BusinessName→Name, UserFirstName→FirstName).

Key changes:
- Strip table-name prefixes from all column references (Businesses, Users,
  Addresses, Hours, Menus, Categories, Items, Stations, Orders,
  OrderLineItems, Tasks, TaskCategories, TaskRatings, QuickTaskTemplates,
  ScheduledTaskDefinitions, ChatMessages, Beacons, ServicePoints, Employees,
  VisitorTrackings, ApiPerfLogs, tt_States, tt_Days, tt_AddressTypes,
  tt_OrderTypes, tt_TaskTypes)
- Rename PK references from {TableName}ID to ID in all queries
- Rewrite 7 admin beacon files to use ServicePoints.BeaconID instead of
  dropped lt_Beacon_Businesses_ServicePoints link table
- Rewrite beacon assignment files (list, save, delete) for new schema
- Fix FK references incorrectly changed to ID (OrderLineItems.OrderID,
  Categories.MenuID, Tasks.CategoryID, ServicePoints.BeaconID)
- Update Addresses: AddressLat→Latitude, AddressLng→Longitude
- Update Users: UserPassword→Password, UserIsEmailVerified→IsEmailVerified,
  UserIsActive→IsActive, UserBalance→Balance, etc.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 15:39:12 -08:00

144 lines
6.3 KiB
Text

<cfsetting showdebugoutput="false">
<cfcontent type="application/json; charset=utf-8">
<cfscript>
function readJsonBody() {
var raw = getHttpRequestData().content;
if (isNull(raw) || len(trim(raw)) == 0) return {};
try {
var data = deserializeJSON(raw);
return isStruct(data) ? data : {};
} catch (any e) {
return {};
}
}
try {
data = readJsonBody();
// Token can come from URL param or JSON body
token = "";
if (structKeyExists(url, "token")) token = trim(url.token);
if (len(token) == 0 && structKeyExists(data, "token")) token = trim(data.token);
if (len(token) == 0) {
writeOutput(serializeJSON({ "OK": false, "ERROR": "missing_token", "MESSAGE": "Rating token is required." }));
abort;
}
// Look up the rating by token
qRating = queryExecute("
SELECT r.*, t.Title,
u_for.FirstName AS ForFirstName, u_for.LastName AS ForLastName,
u_by.FirstName AS ByFirstName, u_by.LastName AS ByLastName
FROM TaskRatings r
JOIN Tasks t ON t.ID = r.TaskID
LEFT JOIN Users u_for ON u_for.ID = r.ForUserID
LEFT JOIN Users u_by ON u_by.ID = r.ByUserID
WHERE r.AccessToken = ?
LIMIT 1
", [{ value = token, cfsqltype = "cf_sql_varchar" }]);
if (qRating.recordCount == 0) {
writeOutput(serializeJSON({ "OK": false, "ERROR": "invalid_token", "MESSAGE": "Rating not found or link is invalid." }));
abort;
}
// Check if expired
if (qRating.ExpiresOn < now()) {
writeOutput(serializeJSON({ "OK": false, "ERROR": "expired", "MESSAGE": "This rating link has expired." }));
abort;
}
// Check if already completed
if (len(trim(qRating.CompletedOn)) > 0) {
writeOutput(serializeJSON({ "OK": false, "ERROR": "already_submitted", "MESSAGE": "This rating has already been submitted." }));
abort;
}
// If GET request (or no rating data), return rating info for display
isSubmission = structKeyExists(data, "onTime") || structKeyExists(data, "completedScope")
|| structKeyExists(data, "requiredFollowup") || structKeyExists(data, "continueAllow")
|| structKeyExists(data, "prepared") || structKeyExists(data, "respectful")
|| structKeyExists(data, "wouldAutoAssign");
if (!isSubmission) {
// Return rating details for UI to display
result = {
"OK": true,
"RatingID": qRating.ID,
"Direction": qRating.Direction,
"Title": qRating.Title,
"ForUserName": trim(qRating.ForFirstName & " " & qRating.ForLastName),
"ExpiresOn": dateTimeFormat(qRating.ExpiresOn, "yyyy-mm-dd HH:nn:ss")
};
// Include appropriate questions based on direction
if (qRating.Direction == "customer_rates_worker" || qRating.Direction == "admin_rates_worker") {
result["Questions"] = {
"onTime": "Was the worker on time?",
"completedScope": "Was the scope completed?",
"requiredFollowup": "Was follow-up required?",
"continueAllow": "Continue to allow these tasks?"
};
} else if (qRating.Direction == "worker_rates_customer") {
result["Questions"] = {
"prepared": "Was the customer prepared?",
"completedScope": "Was the scope clear?",
"respectful": "Was the customer respectful?",
"wouldAutoAssign": "Would you serve this customer again?"
};
}
writeOutput(serializeJSON(result));
abort;
}
// Process submission based on direction
if (qRating.Direction == "customer_rates_worker" || qRating.Direction == "admin_rates_worker") {
queryExecute("
UPDATE TaskRatings SET
OnTime = ?,
CompletedScope = ?,
RequiredFollowup = ?,
ContinueAllow = ?,
CompletedOn = NOW()
WHERE ID = ?
", [
{ value = structKeyExists(data,"onTime") ? (data.onTime ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"onTime") },
{ value = structKeyExists(data,"completedScope") ? (data.completedScope ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"completedScope") },
{ value = structKeyExists(data,"requiredFollowup") ? (data.requiredFollowup ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"requiredFollowup") },
{ value = structKeyExists(data,"continueAllow") ? (data.continueAllow ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"continueAllow") },
{ value = qRating.ID, cfsqltype = "cf_sql_integer" }
]);
} else if (qRating.Direction == "worker_rates_customer") {
queryExecute("
UPDATE TaskRatings SET
Prepared = ?,
CompletedScope = ?,
Respectful = ?,
WouldAutoAssign = ?,
CompletedOn = NOW()
WHERE ID = ?
", [
{ value = structKeyExists(data,"prepared") ? (data.prepared ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"prepared") },
{ value = structKeyExists(data,"completedScope") ? (data.completedScope ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"completedScope") },
{ value = structKeyExists(data,"respectful") ? (data.respectful ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"respectful") },
{ value = structKeyExists(data,"wouldAutoAssign") ? (data.wouldAutoAssign ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"wouldAutoAssign") },
{ value = qRating.ID, cfsqltype = "cf_sql_integer" }
]);
}
writeOutput(serializeJSON({
"OK": true,
"MESSAGE": "Rating submitted successfully. Thank you for your feedback!"
}));
} catch (any e) {
writeOutput(serializeJSON({
"OK": false,
"ERROR": "server_error",
"MESSAGE": "Error submitting rating",
"DETAIL": e.message
}));
}
</cfscript>