data = {}; try { raw = toString(getHttpRequestData().content); if (len(trim(raw))) { data = deserializeJSON(raw); if (!isStruct(data)) data = {}; } } catch (any e) { data = {}; } grantID = val(data.GrantID ?: 0); if (grantID LTE 0) { apiAbort({ "OK": false, "ERROR": "missing_grantid", "MESSAGE": "GrantID is required." }); } callerUserID = val(structKeyExists(request, "UserID") ? request.UserID : 0); if (callerUserID LTE 0) { apiAbort({ "OK": false, "ERROR": "not_authenticated" }); } // Load current grant qGrant = queryExecute( "SELECT g.*, b.UserID AS OwnerUserID FROM ServicePointGrants g JOIN Businesses b ON b.ID = g.OwnerBusinessID WHERE g.ID = ? LIMIT 1", [{ value = grantID, cfsqltype = "cf_sql_integer" }], { datasource = "payfrit" } ); if (qGrant.recordCount == 0) { apiAbort({ "OK": false, "ERROR": "not_found", "MESSAGE": "Grant not found." }); } if (qGrant.OwnerUserID != callerUserID) { apiAbort({ "OK": false, "ERROR": "not_owner", "MESSAGE": "Only the owner business can update grant terms." }); } if (qGrant.StatusID != 0 && qGrant.StatusID != 1) { apiAbort({ "OK": false, "ERROR": "bad_state", "MESSAGE": "Only pending or active grants can be updated." }); } // Collect updates setClauses = []; setParams = []; previousData = {}; newData = {}; validEconomics = ["none", "flat_fee", "percent_of_orders"]; validEligibility = ["public", "employees", "guests", "internal"]; validTimePolicy = ["always", "schedule", "date_range", "event"]; // Economics if (structKeyExists(data, "EconomicsType") || structKeyExists(data, "EconomicsValue")) { eType = trim(data.EconomicsType ?: qGrant.EconomicsType); eValue = val(structKeyExists(data, "EconomicsValue") ? data.EconomicsValue : qGrant.EconomicsValue); if (!arrayFind(validEconomics, eType)) eType = qGrant.EconomicsType; if (eType != qGrant.EconomicsType || eValue != qGrant.EconomicsValue) { previousData["EconomicsType"] = qGrant.EconomicsType; previousData["EconomicsValue"] = qGrant.EconomicsValue; newData["EconomicsType"] = eType; newData["EconomicsValue"] = eValue; arrayAppend(setClauses, "EconomicsType = ?"); arrayAppend(setParams, { value = eType, cfsqltype = "cf_sql_varchar" }); arrayAppend(setClauses, "EconomicsValue = ?"); arrayAppend(setParams, { value = eValue, cfsqltype = "cf_sql_decimal" }); } } // Eligibility if (structKeyExists(data, "EligibilityScope")) { eScope = trim(data.EligibilityScope); if (!arrayFind(validEligibility, eScope)) eScope = qGrant.EligibilityScope; if (eScope != qGrant.EligibilityScope) { previousData["EligibilityScope"] = qGrant.EligibilityScope; newData["EligibilityScope"] = eScope; arrayAppend(setClauses, "EligibilityScope = ?"); arrayAppend(setParams, { value = eScope, cfsqltype = "cf_sql_varchar" }); } } // Time policy if (structKeyExists(data, "TimePolicyType") || structKeyExists(data, "TimePolicyData")) { tType = trim(data.TimePolicyType ?: qGrant.TimePolicyType); if (!arrayFind(validTimePolicy, tType)) tType = qGrant.TimePolicyType; tData = structKeyExists(data, "TimePolicyData") ? data.TimePolicyData : qGrant.TimePolicyData; changed = (tType != qGrant.TimePolicyType); if (!changed && isStruct(tData)) { changed = (serializeJSON(tData) != (qGrant.TimePolicyData ?: "")); } if (changed) { previousData["TimePolicyType"] = qGrant.TimePolicyType; previousData["TimePolicyData"] = qGrant.TimePolicyData ?: ""; newData["TimePolicyType"] = tType; newData["TimePolicyData"] = tData; arrayAppend(setClauses, "TimePolicyType = ?"); arrayAppend(setParams, { value = tType, cfsqltype = "cf_sql_varchar" }); tDataJson = javaCast("null", ""); if (isStruct(tData) && !structIsEmpty(tData)) { tDataJson = serializeJSON(tData); } else if (isSimpleValue(tData) && len(trim(tData))) { tDataJson = tData; } arrayAppend(setClauses, "TimePolicyData = ?"); arrayAppend(setParams, { value = tDataJson, cfsqltype = "cf_sql_varchar", null = isNull(tDataJson) }); } } if (arrayLen(setClauses) == 0) { apiAbort({ "OK": true, "MESSAGE": "No changes detected.", "GrantID": grantID }); } // Execute update arrayAppend(setParams, { value = grantID, cfsqltype = "cf_sql_integer" }); queryExecute( "UPDATE ServicePointGrants SET #arrayToList(setClauses, ', ')# WHERE ID = ?", setParams, { datasource = "payfrit" } ); // Determine action name for history action = "updated"; if (structKeyExists(newData, "EconomicsType") || structKeyExists(newData, "EconomicsValue")) action = "updated_economics"; if (structKeyExists(newData, "EligibilityScope")) action = "updated_eligibility"; if (structKeyExists(newData, "TimePolicyType")) action = "updated_time_policy"; recordGrantHistory( grantID = grantID, action = action, actorUserID = callerUserID, actorBusinessID = qGrant.OwnerBusinessID, previousData = previousData, newData = newData ); writeOutput(serializeJSON({ "OK": true, "GrantID": grantID, "MESSAGE": "Grant updated." }));