<!--- EVV Update Log Action Handler --->
<cfsetting enablecfoutputonly="false" showdebugoutput="false">
<cfparam name="FORM.action" default="">
<cfparam name="FORM.schedule_id" default="0">
<cfparam name="FORM.evv_id" default="0">
<cfparam name="FORM.update_log_id" default="0">
<cfparam name="FORM.reason_code_id" default="0">
<cfparam name="FORM.change_memo" default="">

<cffunction name="autoTransmitVisitFromUpdateLog" access="private" returntype="struct" output="false">
	<cfargument name="scheduleID" type="numeric" required="true">
	<cfargument name="patientID" type="numeric" required="true">
	<cfargument name="reasonCodeID" type="numeric" required="true">
	<cfargument name="changeMemo" type="string" required="true">

	<cfset var result = { "attempted" = false, "success" = false, "message" = "", "removeRow" = false }>
	<cfset var agencyID = val(session.agencyid)>
	<cfset var empID = structKeyExists(session, "employeeid") ? val(session.employeeid) : 0>
	<cfset var queueResult = "">
	<cfset var transmitResult = "">
	<cfset var evvStatusMgr = createObject("component", "components.evv.EVVStatusManager").init()>

	<!--- #10447: auto-send only after Reason Code is selected; Change Reason Memo is required first --->
	<cfif arguments.reasonCodeID LTE 0 OR NOT len(trim(arguments.changeMemo))>
		<cfreturn result>
	</cfif>

	<cfset result.attempted = true>
	<cfset result.sent_reason_code = arguments.reasonCodeID>
	<cfset result.sent_change_memo = trim(arguments.changeMemo)>
	<cfset result.sent_reason_description = "">

	<cfquery name="qTransmitReasonDesc" datasource="#Application.DataSrc#">
		SELECT Description
		FROM #Request.prefix_db_lookup#.EVV_Reason_Codes
		WHERE Reason_Code_ID = <cfqueryparam value="#arguments.reasonCodeID#" cfsqltype="cf_sql_integer">
		AND Status = 0
	</cfquery>
	<cfif qTransmitReasonDesc.recordCount GT 0>
		<cfset result.sent_reason_description = trim(qTransmitReasonDesc.Description)>
	</cfif>

	<cftry>
		<cfset var evvAuto = createObject("component", "components.evv.EVVVisitAutomation").init()>
		<cfset var useAutomationQueue = evvStatusMgr.agencyUsesEVVAutomation(agencyID)>

		<!--- #10447: always retransmit visit (same as manual Send EVV); use automation queue when configured --->
		<cfif useAutomationQueue>
			<cfset queueResult = evvAuto.queueVisitAutomation(
				scheduleID = arguments.scheduleID,
				agencyID = agencyID,
				triggerSource = "evv_update_log",
				patientID = arguments.patientID,
				createdBy = empID,
				reasonCodeID = arguments.reasonCodeID,
				changeMemo = arguments.changeMemo,
				reasonCodeDescription = result.sent_reason_description
			)>
			<cfif queueResult.queued AND findNoCase("failed", queueResult.message) EQ 0 AND (
				findNoCase("transmitted", queueResult.message) GT 0
				OR findNoCase("scheduled", queueResult.message) GT 0
				OR findNoCase("queued", queueResult.message) GT 0
			)>
				<cfset result.success = true>
				<cfset result.message = queueResult.message>
			</cfif>
		</cfif>

		<cfif NOT result.success>
			<cfset transmitResult = evvAuto.transmitVisit(
				arguments.scheduleID,
				agencyID,
				empID,
				arguments.reasonCodeID,
				arguments.changeMemo,
				result.sent_reason_description
			)>
			<cfset result.success = transmitResult.success>
			<cfset result.message = len(trim(transmitResult.message)) ? transmitResult.message : "Visit transmit completed">
			<cfif result.success AND useAutomationQueue>
				<cftry>
					<cfset evvAuto.queueStatusPollingOnly(
						scheduleID = arguments.scheduleID,
						agencyID = agencyID,
						transactionId = transmitResult.transactionId,
						triggerSource = "evv_update_log",
						patientID = arguments.patientID,
						createdBy = empID
					)>
					<cfcatch type="any">
						<!--- polling queue is optional; transmit already succeeded --->
					</cfcatch>
				</cftry>
			</cfif>
		</cfif>

		<cfif result.success>
			<cfquery datasource="#Application.DataSrc#">
				UPDATE #Request.prefix_db_lookup#.EVV_Update_Log
				SET Status = 1
				WHERE Schedule_ID = <cfqueryparam value="#arguments.scheduleID#" cfsqltype="cf_sql_integer">
				AND Agency_ID = <cfqueryparam value="#agencyID#" cfsqltype="cf_sql_integer">
				AND Status = 0
			</cfquery>
			<cfset result.removeRow = true>
			<cflog file="evv_update_log" text="Ticket 10447 auto-transmit success Schedule_ID #arguments.scheduleID# agency #agencyID#: #result.message#">
		<cfelse>
			<cflog file="evv_update_log" text="Ticket 10447 auto-transmit failed Schedule_ID #arguments.scheduleID# agency #agencyID#: #result.message#">
		</cfif>

		<cfcatch type="any">
			<cfset result.message = cfcatch.message>
			<cflog file="evv_update_log_errors" text="Ticket 10447 auto-transmit exception Schedule_ID #arguments.scheduleID#: #cfcatch.message#">
		</cfcatch>
	</cftry>

	<cfreturn result>
</cffunction>

<cffunction name="getActiveUpdateLog" access="private" returntype="query" output="false">
	<cfargument name="scheduleID" type="numeric" required="true">
	<cfargument name="agencyID" type="numeric" required="true">
	<cfquery name="local.qLog" datasource="#Application.DataSrc#">
		SELECT Update_Log_ID, Change_Memo, Reason_Code_ID, EVV_ID
		FROM #Request.prefix_db_lookup#.EVV_Update_Log
		WHERE Schedule_ID = <cfqueryparam value="#arguments.scheduleID#" cfsqltype="cf_sql_integer">
		AND Agency_ID = <cfqueryparam value="#arguments.agencyID#" cfsqltype="cf_sql_integer">
		AND Status = 0
		ORDER BY Update_Log_ID DESC
		LIMIT 1
	</cfquery>
	<cfreturn local.qLog>
</cffunction>

<cffunction name="upsertUpdateLog" access="private" returntype="struct" output="false">
	<cfargument name="scheduleID" type="numeric" required="true">
	<cfargument name="agencyID" type="numeric" required="true">
	<cfargument name="evvID" type="numeric" required="false" default="0">
	<cfargument name="changeMemo" type="string" required="false" default="">
	<cfargument name="reasonCodeID" type="numeric" required="false" default="0">
	<cfargument name="dateUpdated" type="any" required="false">
	<cfargument name="changedBy" type="numeric" required="false" default="0">
	<cfargument name="changedByEmail" type="string" required="false" default="system@powerpathemr.com">
	<cfargument name="updateReasonCode" type="boolean" required="false" default="false">
	<cfargument name="updateMemo" type="boolean" required="false" default="false">

	<cfset var result = { "update_log_id" = 0, "change_memo" = "", "reason_code_id" = 0 }>
	<cfset var activeLog = getActiveUpdateLog(arguments.scheduleID, arguments.agencyID)>
	<cfset var memoToSave = trim(arguments.changeMemo)>
	<cfset var reasonToSave = arguments.reasonCodeID>
	<cfset var logDateUpdated = structKeyExists(arguments, "dateUpdated") AND isDate(arguments.dateUpdated) ? arguments.dateUpdated : now()>

	<cfif activeLog.recordCount GT 0 AND (NOT arguments.updateMemo OR NOT len(memoToSave))>
		<cfset memoToSave = trim(activeLog.Change_Memo & "")>
	</cfif>

	<!--- Keep only one active log row per schedule/agency --->
	<cfquery datasource="#Application.DataSrc#">
		UPDATE #Request.prefix_db_lookup#.EVV_Update_Log
		SET Status = 2
		WHERE Schedule_ID = <cfqueryparam value="#arguments.scheduleID#" cfsqltype="cf_sql_integer">
		AND Agency_ID = <cfqueryparam value="#arguments.agencyID#" cfsqltype="cf_sql_integer">
		AND Status = 0
		<cfif activeLog.recordCount GT 0>
			AND Update_Log_ID <> <cfqueryparam value="#activeLog.Update_Log_ID#" cfsqltype="cf_sql_integer">
		</cfif>
	</cfquery>

	<cfif activeLog.recordCount GT 0>
		<cfset result.update_log_id = val(activeLog.Update_Log_ID)>
		<cfif NOT arguments.updateReasonCode OR reasonToSave LTE 0>
			<cfset reasonToSave = val(activeLog.Reason_Code_ID)>
		</cfif>

		<cfquery datasource="#Application.DataSrc#">
			UPDATE #Request.prefix_db_lookup#.EVV_Update_Log
			SET
				Change_Memo = <cfqueryparam value="#memoToSave#" cfsqltype="cf_sql_longvarchar" null="#NOT len(trim(memoToSave))#">,
				Reason_Code_ID = <cfif reasonToSave GT 0><cfqueryparam value="#reasonToSave#" cfsqltype="cf_sql_integer"><cfelse>NULL</cfif>,
				<cfif arguments.updateReasonCode AND reasonToSave GT 0>
					Date_Reason_Added = <cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp">,
					Reason_Added_By = <cfqueryparam value="#session.employeeid#" cfsqltype="cf_sql_integer">,
				</cfif>
				EVV_ID = <cfif arguments.evvID GT 0><cfqueryparam value="#arguments.evvID#" cfsqltype="cf_sql_integer"><cfelseif isNumeric(activeLog.EVV_ID) AND activeLog.EVV_ID GT 0><cfqueryparam value="#activeLog.EVV_ID#" cfsqltype="cf_sql_integer"><cfelse>NULL</cfif>
			WHERE Update_Log_ID = <cfqueryparam value="#result.update_log_id#" cfsqltype="cf_sql_integer">
			AND Status = 0
		</cfquery>
	<cfelse>
		<cfquery datasource="#Application.DataSrc#" result="local.insertResult">
			INSERT INTO #Request.prefix_db_lookup#.EVV_Update_Log (
				Schedule_ID,
				Agency_ID,
				EVV_ID,
				Date_Updated,
				Change_Memo,
				Changed_By,
				Changed_By_Email,
				Reason_Code_ID,
				Date_Reason_Added,
				Reason_Added_By,
				Status
			) VALUES (
				<cfqueryparam value="#arguments.scheduleID#" cfsqltype="cf_sql_integer">,
				<cfqueryparam value="#arguments.agencyID#" cfsqltype="cf_sql_integer">,
				<cfif arguments.evvID GT 0><cfqueryparam value="#arguments.evvID#" cfsqltype="cf_sql_integer"><cfelse>NULL</cfif>,
				<cfqueryparam value="#logDateUpdated#" cfsqltype="cf_sql_timestamp">,
				<cfqueryparam value="#memoToSave#" cfsqltype="cf_sql_longvarchar" null="#NOT len(trim(memoToSave))#">,
				<cfif arguments.changedBy GT 0><cfqueryparam value="#arguments.changedBy#" cfsqltype="cf_sql_integer"><cfelse>NULL</cfif>,
				<cfqueryparam value="#arguments.changedByEmail#" cfsqltype="cf_sql_varchar">,
				<cfif reasonToSave GT 0><cfqueryparam value="#reasonToSave#" cfsqltype="cf_sql_integer"><cfelse>NULL</cfif>,
				<cfif arguments.updateReasonCode AND reasonToSave GT 0><cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp"><cfelse>NULL</cfif>,
				<cfif arguments.updateReasonCode AND reasonToSave GT 0><cfqueryparam value="#session.employeeid#" cfsqltype="cf_sql_integer"><cfelse>NULL</cfif>,
				0
			)
		</cfquery>
		<cfset result.update_log_id = val(local.insertResult.generatedKey)>
	</cfif>

	<cfset result.change_memo = memoToSave>
	<cfset result.reason_code_id = reasonToSave>
	<cfreturn result>
</cffunction>

<cffunction name="buildSaveJsonResponse" access="private" returntype="string" output="false">
	<cfargument name="success" type="boolean" required="true">
	<cfargument name="message" type="string" required="true">
	<cfargument name="updateLogID" type="numeric" required="false" default="0">
	<cfargument name="reasonCodeID" type="numeric" required="false" default="0">
	<cfargument name="reasonCodeDescription" type="string" required="false" default="">
	<cfargument name="autoTransmit" type="struct" required="false">
	<cfset var json = '{"success": ' & (arguments.success ? "true" : "false") & ', "message": "#JSStringFormat(arguments.message)#"'>
	<cfif arguments.updateLogID GT 0>
		<cfset json &= ', "update_log_id": #arguments.updateLogID#'>
	</cfif>
	<cfif arguments.reasonCodeID GT 0>
		<cfset json &= ', "reason_code_id": #arguments.reasonCodeID#'>
	</cfif>
	<cfif len(trim(arguments.reasonCodeDescription))>
		<cfset json &= ', "reason_code_description": "#JSStringFormat(arguments.reasonCodeDescription)#"'>
	</cfif>
	<cfif structKeyExists(arguments, "autoTransmit") AND arguments.autoTransmit.attempted>
		<cfset json &= ', "auto_transmitted": ' & (arguments.autoTransmit.success ? "true" : "false")>
		<cfset json &= ', "remove_row": ' & (arguments.autoTransmit.removeRow ? "true" : "false")>
		<cfset json &= ', "transmit_message": "#JSStringFormat(arguments.autoTransmit.message)#"'>
		<cfif structKeyExists(arguments.autoTransmit, "sent_reason_code") AND arguments.autoTransmit.sent_reason_code GT 0>
			<cfset json &= ', "sent_reason_code": #arguments.autoTransmit.sent_reason_code#'>
		</cfif>
		<cfif structKeyExists(arguments.autoTransmit, "sent_change_memo") AND len(trim(arguments.autoTransmit.sent_change_memo))>
			<cfset json &= ', "sent_change_memo": "#JSStringFormat(arguments.autoTransmit.sent_change_memo)#"'>
		</cfif>
		<cfif structKeyExists(arguments.autoTransmit, "sent_reason_description") AND len(trim(arguments.autoTransmit.sent_reason_description))>
			<cfset json &= ', "sent_reason_description": "#JSStringFormat(arguments.autoTransmit.sent_reason_description)#"'>
		</cfif>
	</cfif>
	<cfset json &= '}'>
	<cfreturn json>
</cffunction>

<cftry>
	<cfif FORM.action EQ "save_reason_code">
		<!--- Validate inputs --->
		<cfif NOT isNumeric(FORM.schedule_id) OR FORM.schedule_id EQ 0>
			<cfthrow message="Invalid Schedule ID">
		</cfif>
		
		<cfif NOT isNumeric(FORM.reason_code_id) OR FORM.reason_code_id EQ 0>
			<cfthrow message="Invalid Reason Code">
		</cfif>

		<cfif NOT len(trim(FORM.change_memo))>
			<!--- Prefer memo already saved on the active log (user entered memo first) --->
			<cfset existingMemoForReason = "">
			<cfset existingLogForReason = getActiveUpdateLog(val(FORM.schedule_id), val(session.agencyid))>
			<cfif existingLogForReason.recordCount GT 0 AND len(trim(existingLogForReason.Change_Memo)) GT 0>
				<cfset existingMemoForReason = trim(existingLogForReason.Change_Memo)>
				<cfset FORM.change_memo = existingMemoForReason>
			<cfelse>
				<cfthrow message="Please enter a Change Reason Memo before selecting a reason code">
			</cfif>
		</cfif>
		
		<!--- Get visit details --->
		<cfquery name="getVisit" datasource="#Application.DataSrc#">
			SELECT 
				pSchedules.Schedule_ID,
				pSchedules.Date_Change,
				pSchedules.Change_by,
				pPatients.Patient_ID,
				pEmployee.Emp_Email
			FROM #Request.prefix_db_agency#.pSchedules
			JOIN #Request.prefix_db_agency#.pPatients ON pPatients.Patient_ID = pSchedules.Patient_ID
			LEFT JOIN #Request.prefix_db_lookup#.pEmployee ON pEmployee.Emp_ID = pSchedules.Change_by
			WHERE pSchedules.Schedule_ID = <cfqueryparam value="#FORM.schedule_id#" cfsqltype="cf_sql_integer">
			AND pSchedules.status = 0
		</cfquery>
		
		<cfif getVisit.recordcount EQ 0>
			<cfthrow message="Visit not found">
		</cfif>
		
		<!--- Update pSchedules table with reason code --->
		<cfquery name="updateSchedule" datasource="#Application.DataSrc#">
			UPDATE #Request.prefix_db_agency#.pSchedules
			SET EVV_Reason_Code_ID = <cfqueryparam value="#FORM.reason_code_id#" cfsqltype="cf_sql_integer">
			WHERE Schedule_ID = <cfqueryparam value="#FORM.schedule_id#" cfsqltype="cf_sql_integer">
			AND status = 0
		</cfquery>

		<cfset changedByEmail = (getVisit.recordcount GT 0 AND len(trim(getVisit.Emp_Email)) GT 0) ? getVisit.Emp_Email : "system@powerpathemr.com">
		<cfset savedLog = upsertUpdateLog(
			scheduleID = val(FORM.schedule_id),
			agencyID = val(session.agencyid),
			evvID = val(FORM.evv_id),
			changeMemo = trim(FORM.change_memo),
			reasonCodeID = val(FORM.reason_code_id),
			dateUpdated = IsDate(getVisit.Date_Change) ? getVisit.Date_Change : now(),
			changedBy = isNumeric(getVisit.Change_by) ? val(getVisit.Change_by) : 0,
			changedByEmail = changedByEmail,
			updateReasonCode = true,
			updateMemo = true
		)>
		
		<!--- Get the reason code description for response --->
		<cfquery name="getReasonCode" datasource="#Application.DataSrc#">
			SELECT Description
			FROM #Request.prefix_db_lookup#.EVV_Reason_Codes
			WHERE Reason_Code_ID = <cfqueryparam value="#FORM.reason_code_id#" cfsqltype="cf_sql_integer">
		</cfquery>
		
		<cflog file="evv_update_log" text="Reason code #FORM.reason_code_id# added for Schedule_ID #FORM.schedule_id# (Update_Log_ID #savedLog.update_log_id#) by Employee #session.employeeid#">

		<!--- #10447: auto-send only when Reason Code is selected (include memo from form/log in payload) --->
		<cfset memoForTransmit = len(trim(FORM.change_memo)) ? trim(FORM.change_memo) : trim(savedLog.change_memo)>
		<cfset autoTransmit = autoTransmitVisitFromUpdateLog(
			scheduleID = val(FORM.schedule_id),
			patientID = val(getVisit.Patient_ID),
			reasonCodeID = val(FORM.reason_code_id),
			changeMemo = memoForTransmit
		)>
		
		<cfcontent type="application/json" reset="true"><cfoutput>#buildSaveJsonResponse(
			success = true,
			message = "Reason code saved successfully",
			updateLogID = savedLog.update_log_id,
			reasonCodeID = val(FORM.reason_code_id),
			reasonCodeDescription = getReasonCode.Description,
			autoTransmit = autoTransmit
		)#</cfoutput><cfabort>
		
	<cfelseif FORM.action EQ "encrypt_schedule_id">
		<!--- Encrypt Schedule_ID for EVV transmission --->
		<cfif NOT isNumeric(FORM.schedule_id) OR FORM.schedule_id EQ 0>
			<cfthrow message="Invalid Schedule ID">
		</cfif>
		
		<cfset encrypted_id = encrypt(FORM.schedule_id, Application.enckey, "AES", "Hex")>
		<cfset reasonDescription = "">
		<cfif isNumeric(FORM.reason_code_id) AND FORM.reason_code_id GT 0>
			<cfquery name="getEncryptReasonCode" datasource="#Application.DataSrc#">
				SELECT Description
				FROM #Request.prefix_db_lookup#.EVV_Reason_Codes
				WHERE Reason_Code_ID = <cfqueryparam value="#FORM.reason_code_id#" cfsqltype="cf_sql_integer">
				AND Status = 0
			</cfquery>
			<cfif getEncryptReasonCode.recordCount GT 0>
				<cfset reasonDescription = trim(getEncryptReasonCode.Description)>
			</cfif>
		</cfif>
		
		<cfcontent type="application/json" reset="true"><cfoutput>{"success": true, "encrypted_id": "#encrypted_id#", "reason_code_description": "#JSStringFormat(reasonDescription)#"}</cfoutput><cfabort>
		
	<cfelseif FORM.action EQ "save_change_memo">
		<!--- Save Change Reason Memo --->
		<cfparam name="FORM.change_memo" default="">
		
		<cfif NOT isNumeric(FORM.schedule_id) OR FORM.schedule_id EQ 0>
			<cfthrow message="Invalid Schedule ID">
		</cfif>

		<cfif NOT len(trim(FORM.change_memo))>
			<cfthrow message="Change reason memo is required">
		</cfif>
		
		<!--- Get visit information --->
		<cfquery name="getVisit" datasource="#Application.DataSrc#">
			SELECT 
				pSchedules.Schedule_ID,
				pSchedules.Date_Change,
				pSchedules.Change_by,
				pSchedules.EVV_Reason_Code_ID,
				pPatients.Patient_ID,
				pEmployee.Emp_Email
			FROM #Request.prefix_db_agency#.pSchedules
			JOIN #Request.prefix_db_agency#.pPatients ON pPatients.Patient_ID = pSchedules.Patient_ID
			LEFT JOIN #Request.prefix_db_lookup#.pEmployee ON pEmployee.Emp_ID = pSchedules.Change_by
			WHERE pSchedules.Schedule_ID = <cfqueryparam value="#FORM.schedule_id#" cfsqltype="cf_sql_integer">
			AND pSchedules.status = 0
		</cfquery>
		
		<cfif getVisit.recordcount EQ 0>
			<cfthrow message="Visit not found">
		</cfif>
		
		<!--- Update pSchedules table with reason code if provided --->
		<cfset reasonCodeToSave = 0>
		<cfif isNumeric(FORM.reason_code_id) AND FORM.reason_code_id GT 0>
			<cfset reasonCodeToSave = val(FORM.reason_code_id)>
		<cfelseif isNumeric(getVisit.EVV_Reason_Code_ID) AND getVisit.EVV_Reason_Code_ID GT 0>
			<cfset reasonCodeToSave = val(getVisit.EVV_Reason_Code_ID)>
		</cfif>

		<cfif reasonCodeToSave GT 0>
			<cfquery name="updateScheduleReasonCode" datasource="#Application.DataSrc#">
				UPDATE #Request.prefix_db_agency#.pSchedules
				SET EVV_Reason_Code_ID = <cfqueryparam value="#reasonCodeToSave#" cfsqltype="cf_sql_integer">
				WHERE Schedule_ID = <cfqueryparam value="#FORM.schedule_id#" cfsqltype="cf_sql_integer">
				AND status = 0
			</cfquery>
		</cfif>

		<cfset changedByEmail = (len(trim(getVisit.Emp_Email)) GT 0) ? getVisit.Emp_Email : "system@powerpathemr.com">
		<cfset savedLog = upsertUpdateLog(
			scheduleID = val(FORM.schedule_id),
			agencyID = val(session.agencyid),
			evvID = val(FORM.evv_id),
			changeMemo = trim(FORM.change_memo),
			reasonCodeID = reasonCodeToSave,
			dateUpdated = IsDate(getVisit.Date_Change) ? getVisit.Date_Change : now(),
			changedBy = isNumeric(getVisit.Change_by) ? val(getVisit.Change_by) : 0,
			changedByEmail = changedByEmail,
			updateReasonCode = reasonCodeToSave GT 0,
			updateMemo = true
		)>

		<cflog file="evv_update_log" text="Change memo saved for Schedule_ID #FORM.schedule_id# (Update_Log_ID #savedLog.update_log_id#) by Employee #session.employeeid#">

		<!--- #10447: memo save only — EVV auto-send happens when Reason Code is selected --->
		<cfcontent type="application/json" reset="true"><cfoutput>#buildSaveJsonResponse(
			success = true,
			message = "Change memo saved successfully",
			updateLogID = savedLog.update_log_id,
			reasonCodeID = val(savedLog.reason_code_id)
		)#</cfoutput><cfabort>
		
	<cfelse>
		<cfthrow message="Invalid action">
	</cfif>
	
	<cfcatch type="any">
		<!--- Log error --->
		<cflog file="evv_update_log_errors" text="Error in evv_update_log_action: #cfcatch.message# - #cfcatch.detail# - SQL: #cfcatch.sql#">
		
		<!--- Return detailed error for debugging --->
		<cfcontent type="application/json" reset="true"><cfoutput>{"success": false, "message": "#JSStringFormat(cfcatch.message)#", "detail": "#JSStringFormat(cfcatch.detail)#"}</cfoutput><cfabort>
	</cfcatch>
</cftry>