<cfcomponent displayname="EVV Patient Automation" hint="Automates patient EVV transmit and status polling per tickets 10421-10425" output="false">

	<cffunction name="init" access="public" returntype="EVVPatientAutomation" output="false">
		<cfreturn this>
	</cffunction>

	<cffunction name="getApplicationEncKey" access="private" returntype="string" output="false">
		<cfif structKeyExists(application, "enckey") AND len(trim(application.enckey))>
			<cfreturn application.enckey>
		</cfif>
		<cfset application.enckey = "54kczhzgHTj4a8n+SRZPyg==">
		<cfreturn application.enckey>
	</cffunction>

	<cffunction name="ensureApplicationContext" access="private" returntype="void" output="false">
		<cfset getApplicationEncKey()>
		<cfif NOT structKeyExists(application, "DEV")>
			<cfif CGI.SERVER_NAME EQ "127.0.0.1" OR CGI.SERVER_NAME EQ "localhost"
				OR CGI.SERVER_NAME EQ "52.23.186.30" OR CGI.SERVER_NAME EQ "dev.myhomecarebiz.com"
				OR CGI.SERVER_NAME EQ "98.87.35.139" OR CGI.SERVER_NAME EQ "devsecure.myhomecarebiz.com"
				OR CGI.SERVER_NAME EQ "54.175.136.41" OR CGI.SERVER_NAME EQ "stagesecure.myhomecarebiz.com">
				<cfset application.DEV = true>
			<cfelse>
				<cfset application.DEV = false>
			</cfif>
		</cfif>
		<cfif NOT structKeyExists(application, "ServerName") OR NOT len(trim(application.ServerName))>
			<cfset application.ServerName = CGI.SERVER_NAME>
		</cfif>
		<cfif NOT structKeyExists(application, "DataSrc") OR NOT len(trim(application.DataSrc))>
			<cfset application.DataSrc = "hhapowerpath">
		</cfif>
	</cffunction>

	<cffunction name="getAgencyDbPrefix" access="private" returntype="string" output="false">
		<cfargument name="agencyID" type="numeric" required="true">
		<cfif isDefined("Request.prefix_db_agency")
			AND len(trim(Request.prefix_db_agency))
			AND Request.prefix_db_agency NEQ "prefix_db_agency_invalid">
			<cfreturn Request.prefix_db_agency>
		</cfif>
		<cfreturn "agency_" & arguments.agencyID>
	</cffunction>

	<cffunction name="getSandataComponentName" access="private" returntype="string" output="false">
		<cfargument name="agencyID" type="numeric" required="true">
		<cfif arguments.agencyID EQ 1184>
			<cfreturn "AHCCCS">
		<cfelseif arguments.agencyID EQ 1195>
			<cfreturn "hhaexchange">
		</cfif>
		<cfreturn "sandata">
	</cffunction>

	<cffunction name="patientRequiresEVVAutomation" access="public" returntype="boolean" output="false">
		<cfargument name="patientID" type="numeric" required="true">
		<cfargument name="agencyID" type="numeric" required="true">

		<cfset var agencyDb = getAgencyDbPrefix(arguments.agencyID)>
		<cfset var qPayers = "">

		<cftry>
			<cfquery name="qPayers" datasource="#Application.DataSrc#">
				SELECT pPayer.evv_payer_required, pPayer.Pay_ID, pPayer.Pay_Name, pPtPayer.Payer_Responsibility
				FROM #agencyDb#.pPtPayer
				JOIN #agencyDb#.pPayer ON pPtPayer.Payer_ID = pPayer.Pay_ID
				WHERE pPtPayer.Patient_ID = <cfqueryparam value="#arguments.patientID#" cfsqltype="cf_sql_integer">
				AND pPtPayer.Status = 0
				AND pPayer.Status = 0
				AND pPayer.evv_payer_required IN (1)
				LIMIT 1
			</cfquery>

			<cfif qPayers.recordCount GT 0>
				<cflog file="EVVPatientAutomation" text="patientRequiresEVVAutomation YES patient #arguments.patientID# agency #arguments.agencyID# db #agencyDb# payer #qPayers.Pay_ID# (#qPayers.Pay_Name#)">
				<cfreturn true>
			</cfif>

			<cflog file="EVVPatientAutomation" text="patientRequiresEVVAutomation NO patient #arguments.patientID# agency #arguments.agencyID# db #agencyDb# - no active pPtPayer linked to payer with evv_payer_required=1">

			<cfcatch type="any">
				<cflog file="EVVPatientAutomation" text="patientRequiresEVVAutomation query failed for patient #arguments.patientID# agency #arguments.agencyID# db #agencyDb#: #cfcatch.message#">
			</cfcatch>
		</cftry>

		<cfreturn false>
	</cffunction>

	<cffunction name="agencySupportsClientEVV" access="public" returntype="boolean" output="false">
		<cfargument name="agencyID" type="numeric" required="true">

		<cfset var qAgency = "">
		<cfset var lookupDb = isDefined("Request.prefix_db_lookup") AND len(trim(Request.prefix_db_lookup)) ? Request.prefix_db_lookup : "hhapowerpath">

		<cfquery name="qAgency" datasource="#Application.DataSrc#">
			SELECT Agency_ID
			FROM #lookupDb#.Agency
			WHERE Agency_ID = <cfqueryparam value="#arguments.agencyID#" cfsqltype="cf_sql_integer">
			AND Status = <cfqueryparam value="active" cfsqltype="cf_sql_varchar">
			<cfif application.DEV EQ false>
				AND EVV_prod_username IS NOT NULL
				AND EVV_prod_password IS NOT NULL
			<cfelse>
				AND EVV_username IS NOT NULL
				AND EVV_password IS NOT NULL
			</cfif>
		</cfquery>

		<cfreturn qAgency.recordCount GT 0>
	</cffunction>

	<cffunction name="normalizeEvvStatusText" access="private" returntype="string" output="false">
		<cfargument name="statusText" type="string" required="true">
		<cfset var s = trim(arguments.statusText)>
		<cfif len(s) AND right(s, 1) EQ ".">
			<cfset s = trim(left(s, len(s) - 1))>
		</cfif>
		<cfreturn s>
	</cffunction>

	<cffunction name="statusTextIsTransactionReceived" access="private" returntype="boolean" output="false">
		<cfargument name="statusText" type="string" required="true">
		<cfset var s = uCase(normalizeEvvStatusText(arguments.statusText))>
		<cfreturn find("TRANSACTION RECEIVED", s) GT 0>
	</cffunction>

	<cffunction name="statusTextRequiresRetransmission" access="private" returntype="boolean" output="false">
		<cfargument name="statusText" type="string" required="true">
		<cfset var s = uCase(normalizeEvvStatusText(arguments.statusText))>
		<cfreturn find("DATA CHANGED", s) GT 0 OR find("RETRANSMISSION", s) GT 0>
	</cffunction>

	<cffunction name="patientHasTransactionReceivedEVV" access="private" returntype="boolean" output="false">
		<cfargument name="patientID" type="numeric" required="true">
		<cfargument name="agencyID" type="numeric" required="true">

		<cfset var lookupDb = isDefined("Request.prefix_db_lookup") AND len(trim(Request.prefix_db_lookup)) ? Request.prefix_db_lookup : "hhapowerpath">
		<cfset var qLatestEvv = "">
		<cfset var qAutomation = "">
		<cfset var evvManager = "">
		<cfset var evvStatus = "">
		<cfset var latestSanStatus = "">

		<cfif NOT isDefined("Request.prefix_db_lookup") OR NOT len(trim(Request.prefix_db_lookup))>
			<cfset Request.prefix_db_lookup = lookupDb>
		</cfif>

		<!--- Latest EVV clients row (authoritative unless retransmission required) --->
		<cfquery name="qLatestEvv" datasource="#Application.DataSrc#">
			SELECT San_status
			FROM #lookupDb#.EVV
			WHERE LOWER(API_Type) = <cfqueryparam value="clients" cfsqltype="cf_sql_varchar">
			AND Agency_ID = <cfqueryparam value="#arguments.agencyID#" cfsqltype="cf_sql_integer">
			AND Patient_ID = <cfqueryparam value="#arguments.patientID#" cfsqltype="cf_sql_integer">
			AND status = <cfqueryparam value="0" cfsqltype="cf_sql_integer">
			ORDER BY EVV_ID DESC
			LIMIT 1
		</cfquery>

		<cfif qLatestEvv.recordCount GT 0>
			<cfset latestSanStatus = normalizeEvvStatusText(qLatestEvv.San_status)>
			<cfif statusTextRequiresRetransmission(latestSanStatus)>
				<cflog file="EVVPatientAutomation" text="patientHasTransactionReceivedEVV NO patient #arguments.patientID# agency #arguments.agencyID# - retransmission required (EVV: #latestSanStatus#)">
				<cfreturn false>
			</cfif>
			<cfif statusTextIsTransactionReceived(latestSanStatus)>
				<cflog file="EVVPatientAutomation" text="patientHasTransactionReceivedEVV YES patient #arguments.patientID# agency #arguments.agencyID# - EVV table: #latestSanStatus#">
				<cfreturn true>
			</cfif>
		</cfif>

		<!--- Automation queue row (General Information prefers this over EVV while job is active) --->
		<cfquery name="qAutomation" datasource="#Application.DataSrc#">
			SELECT EVV_Status, Job_Status
			FROM #lookupDb#.EVV_Patient_Automation
			WHERE Agency_ID = <cfqueryparam value="#arguments.agencyID#" cfsqltype="cf_sql_integer">
			AND Patient_ID = <cfqueryparam value="#arguments.patientID#" cfsqltype="cf_sql_integer">
			<!--- AND EVV_Status IS NOT NULL
			AND TRIM(EVV_Status) <> <cfqueryparam value="" cfsqltype="cf_sql_varchar"> --->
			AND Job_Status IN (<cfqueryparam value="waiting_status,polling_status,complete" cfsqltype="cf_sql_varchar" list="true">)
			ORDER BY Automation_ID DESC
			LIMIT 1
		</cfquery>

		<cfif qAutomation.recordCount GT 0 AND statusTextIsTransactionReceived(qAutomation.EVV_Status)>
			<cflog file="EVVPatientAutomation" text="patientHasTransactionReceivedEVV YES patient #arguments.patientID# agency #arguments.agencyID# - automation job (#qAutomation.Job_Status#): #qAutomation.EVV_Status#">
			<cfreturn true>
		</cfif>

		<!--- Match General Information page load logic via EVVStatusManager --->
		<cfset evvManager = createObject("component", "components.evv.EVVStatusManager").init()>
		<cfset evvStatus = evvManager.getEVVStatusWithChangeDetection("clients", arguments.patientID, arguments.agencyID)>
		<cfif statusTextRequiresRetransmission(evvStatus.EVV_Status)>
			<cflog file="EVVPatientAutomation" text="patientHasTransactionReceivedEVV NO patient #arguments.patientID# agency #arguments.agencyID# - EVVStatusManager: #evvStatus.EVV_Status#">
			<cfreturn false>
		</cfif>
		<cfif statusTextIsTransactionReceived(evvStatus.EVV_Status)>
			<cflog file="EVVPatientAutomation" text="patientHasTransactionReceivedEVV YES patient #arguments.patientID# agency #arguments.agencyID# - EVVStatusManager: #evvStatus.EVV_Status#">
			<cfreturn true>
		</cfif>

		<cflog file="EVVPatientAutomation" text="patientHasTransactionReceivedEVV NO patient #arguments.patientID# agency #arguments.agencyID# - latest EVV: '#latestSanStatus#' automation: '#qAutomation.recordCount GT 0 ? qAutomation.EVV_Status : ''#' manager: '#evvStatus.EVV_Status#'">
		<cfreturn false>
	</cffunction>

	<cffunction name="queuePatientAutomation" access="public" returntype="struct" output="false">
		<cfargument name="patientID" type="numeric" required="true">
		<cfargument name="agencyID" type="numeric" required="true">
		<cfargument name="triggerSource" type="string" required="true">
		<cfargument name="admitID" type="numeric" required="false" default="0">
		<cfargument name="createdBy" type="numeric" required="false" default="0">

		<cfset var result = { "queued" = false, "jobID" = 0, "message" = "" }>

		<cfset setupAgencyContext(arguments.agencyID, arguments.createdBy)>

		<cfset var evvManager = createObject("component", "components.evv.EVVStatusManager").init()>
		<cfif NOT evvManager.agencyUsesEVVAutomation(arguments.agencyID)>
			<cfset result.message = "Agency #arguments.agencyID# is not configured for EVV automation (Session.EVVagencies)">
			<cflog file="EVVPatientAutomation" text="queuePatientAutomation skipped patient #arguments.patientID# agency #arguments.agencyID#: #result.message#">
			<cfreturn result>
		</cfif>

		<cfif NOT patientRequiresEVVAutomation(arguments.patientID, arguments.agencyID)>
			<cfset result.message = "No active patient payer with evv_payer_required = 1">
			<cflog file="EVVPatientAutomation" text="queuePatientAutomation skipped patient #arguments.patientID# agency #arguments.agencyID#: #result.message#">
			<cfreturn result>
		</cfif>

		<cfif NOT isDefined("Request.prefix_db_lookup") OR NOT len(trim(Request.prefix_db_lookup))>
			<cfset Request.prefix_db_lookup = "hhapowerpath">
		</cfif>

		<cfif patientHasTransactionReceivedEVV(arguments.patientID, arguments.agencyID)>
			<cfset result.message = "Patient EVV status is already Transaction Received">
			<cflog file="EVVPatientAutomation" text="queuePatientAutomation skipped patient #arguments.patientID# agency #arguments.agencyID#: #result.message#">
			<cfreturn result>
		</cfif>

		<!--- <cfif NOT agencySupportsClientEVV(arguments.agencyID)>
			<cfset result.message = "Agency #arguments.agencyID# is not configured for EVV (missing EVV credentials)">
			<cflog file="EVVPatientAutomation" text="queuePatientAutomation skipped patient #arguments.patientID#: #result.message#">
			<cfreturn result>
		</cfif> --->

		<cftry>
			<cfquery datasource="#Application.DataSrc#">
				UPDATE #Request.prefix_db_lookup#.EVV_Patient_Automation
				SET Job_Status = <cfqueryparam value="cancelled" cfsqltype="cf_sql_varchar">,
					Date_Update = <cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp">
				WHERE Agency_ID = <cfqueryparam value="#arguments.agencyID#" cfsqltype="cf_sql_integer">
				AND Patient_ID = <cfqueryparam value="#arguments.patientID#" cfsqltype="cf_sql_integer">
				AND Job_Status IN (<cfqueryparam value="pending_transmit,waiting_status,polling_status" cfsqltype="cf_sql_varchar" list="true">)
			</cfquery>

			<cfquery name="insJob" datasource="#Application.DataSrc#" result="insResult">
				INSERT INTO #Request.prefix_db_lookup#.EVV_Patient_Automation (
					Agency_ID, Patient_ID, Admit_ID, Trigger_Source, Job_Status,
					Transmit_At, Status_Check_Start, Status_Check_End,
					Created_By, Date_Create, Date_Update
				) VALUES (
					<cfqueryparam value="#arguments.agencyID#" cfsqltype="cf_sql_integer">,
					<cfqueryparam value="#arguments.patientID#" cfsqltype="cf_sql_integer">,
					<cfqueryparam value="#arguments.admitID#" cfsqltype="cf_sql_integer">,
					<cfqueryparam value="#arguments.triggerSource#" cfsqltype="cf_sql_varchar">,
					<cfqueryparam value="pending_transmit" cfsqltype="cf_sql_varchar">,
					<cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp">,
					<cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp">,
					<cfqueryparam value="#DateAdd('n', 80, now())#" cfsqltype="cf_sql_timestamp">,
					<cfqueryparam value="#arguments.createdBy#" cfsqltype="cf_sql_integer">,
					<cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp">,
					<cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp">
				)
			</cfquery>

			<cfset result.queued = true>
			<cfset result.jobID = insResult.GENERATED_KEY ?: 0>
			<cfset result.message = "EVV automation queued">
			<cflog file="EVVPatientAutomation" text="queuePatientAutomation queued job #result.jobID# patient #arguments.patientID# agency #arguments.agencyID# trigger #arguments.triggerSource#">

			<!--- #10421: transmit patient EVV JSON immediately --->
			<cfset var transmit = transmitPatientClient(arguments.patientID, arguments.agencyID, arguments.createdBy)>
			<cfif transmit.success>
				<cfquery datasource="#Application.DataSrc#">
					UPDATE #Request.prefix_db_lookup#.EVV_Patient_Automation
					SET Job_Status = <cfqueryparam value="waiting_status" cfsqltype="cf_sql_varchar">,
						Transmit_Result = <cfqueryparam value="#left(transmit.message, 500)#" cfsqltype="cf_sql_varchar">,
						Status_Check_Start = <cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp">,
						Status_Check_End = <cfqueryparam value="#DateAdd('n', 80, now())#" cfsqltype="cf_sql_timestamp">,
						Date_Update = <cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp">
					WHERE Automation_ID = <cfqueryparam value="#result.jobID#" cfsqltype="cf_sql_integer">
				</cfquery>
				<cfset result.message = "EVV client JSON transmitted; status polling scheduled">
				<cflog file="EVVPatientAutomation" text="queuePatientAutomation transmit OK job #result.jobID# patient #arguments.patientID# agency #arguments.agencyID#">
			<cfelse>
				<cfquery datasource="#Application.DataSrc#">
					UPDATE #Request.prefix_db_lookup#.EVV_Patient_Automation
					SET Job_Status = <cfqueryparam value="failed" cfsqltype="cf_sql_varchar">,
						Last_Error = <cfqueryparam value="#left(transmit.message, 1000)#" cfsqltype="cf_sql_varchar">,
						Date_Update = <cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp">
					WHERE Automation_ID = <cfqueryparam value="#result.jobID#" cfsqltype="cf_sql_integer">
				</cfquery>
				<cfset result.message = transmit.message>
				<cflog file="EVVPatientAutomation" text="queuePatientAutomation transmit FAILED job #result.jobID# patient #arguments.patientID# agency #arguments.agencyID#: #transmit.message#">
			</cfif>

			<cfcatch type="any">
				<cfset result.message = cfcatch.message>
				<cflog file="EVVPatientAutomation" text="queuePatientAutomation failed for patient #arguments.patientID#: #cfcatch.message#">
			</cfcatch>
		</cftry>

		<cfreturn result>
	</cffunction>

	<cffunction name="requeuePatientClientOnDataChange" access="public" returntype="struct" output="false">
		<cfargument name="patientID" type="numeric" required="true">
		<cfargument name="agencyID" type="numeric" required="true">
		<cfargument name="triggerSource" type="string" required="true">
		<cfargument name="createdBy" type="numeric" required="false" default="0">

		<cfset var result = { "queued" = false, "message" = "" }>
		<cfset var evvManager = createObject("component", "components.evv.EVVStatusManager").init()>

		<cfif NOT evvManager.agencyUsesEVVAutomation(arguments.agencyID)>
			<cfset result.message = "Agency #arguments.agencyID# is not configured for EVV automation">
			<cflog file="EVVPatientAutomation" text="requeuePatientClientOnDataChange skipped patient #arguments.patientID#: #result.message#">
			<cfreturn result>
		</cfif>

		<cfif NOT patientRequiresEVVAutomation(arguments.patientID, arguments.agencyID)>
			<cfset result.message = "No active patient payer with evv_payer_required = 1">
			<cflog file="EVVPatientAutomation" text="requeuePatientClientOnDataChange skipped patient #arguments.patientID#: #result.message#">
			<cfreturn result>
		</cfif>

		<cfif arguments.agencyID EQ 1184>
			<cftry>
				<cfset var ahcccsObj = createObject("component", "components.sandata.AHCCCS").init()>
				<cfset ahcccsObj.markEVVForRetransmission(
					recordType = "patient",
					recordID = arguments.patientID,
					agencyID = arguments.agencyID
				)>
				<cfcatch type="any">
					<cflog file="EVVPatientAutomation" text="requeuePatientClientOnDataChange markEVV failed patient #arguments.patientID#: #cfcatch.message#">
				</cfcatch>
			</cftry>
		</cfif>

		<cfreturn queuePatientAutomation(
			patientID = arguments.patientID,
			agencyID = arguments.agencyID,
			triggerSource = arguments.triggerSource,
			createdBy = arguments.createdBy
		)>
	</cffunction>

	<cffunction name="setupAgencyContext" access="private" returntype="void" output="false">
		<cfargument name="agencyID" type="numeric" required="true">
		<cfargument name="employeeID" type="numeric" required="false" default="0">

		<cfset ensureApplicationContext()>
		<cfset session.agencyId = arguments.agencyID>
		<cfset session.agencyid = arguments.agencyID>
		<cfset session.employeeid = arguments.employeeID>
		<cfset Request.prefix_db_agency = getAgencyDbPrefix(arguments.agencyID)>
		<cfif NOT isDefined("Request.prefix_db_lookup") OR NOT len(trim(Request.prefix_db_lookup))>
			<cfset Request.prefix_db_lookup = "hhapowerpath">
		</cfif>
		<cfset Request.sandatacfc = getSandataComponentName(arguments.agencyID) & ".cfc">
	</cffunction>

	<cffunction name="resolveAgencyID" access="private" returntype="numeric" output="false">
		<cfargument name="agencyID" type="numeric" required="false" default="0">

		<cfset var sessionKeys = ["agencyid", "agencyId", "AgencyId", "AGENCYID", "AgencyID"]>
		<cfset var key = "">

		<cfif arguments.agencyID GT 0>
			<cfreturn int(arguments.agencyID)>
		</cfif>

		<cfloop array="#sessionKeys#" index="key">
			<cfif structKeyExists(session, key) AND val(session[key]) GT 0>
				<cfreturn int(val(session[key]))>
			</cfif>
		</cfloop>

		<cfif isDefined("Request.Agency_ID") AND val(Request.Agency_ID) GT 0>
			<cfreturn int(val(Request.Agency_ID))>
		</cfif>

		<cfreturn 0>
	</cffunction>

	<cffunction name="normalizeTransmitResult" access="private" returntype="string" output="false">
		<cfargument name="transmitResult" type="any" required="true">
		<cfif NOT isSimpleValue(arguments.transmitResult)>
			<cfreturn "">
		</cfif>
		<cfreturn trim(reReplace(arguments.transmitResult, "<[^>]+>", "", "all"))>
	</cffunction>

	<cffunction name="isSuccessfulClientTransmit" access="private" returntype="boolean" output="false">
		<cfargument name="transmitResult" type="any" required="true">
		<cfset var normalized = uCase(normalizeTransmitResult(arguments.transmitResult))>
		<cfif NOT len(normalized)>
			<cfreturn false>
		</cfif>
		<cfreturn (
			find("SUCCESSFULLY", normalized) GT 0
			OR find("TRANSMITTED - INITIAL SUBMISSION", normalized) GT 0
		)>
	</cffunction>

	<cffunction name="invokeSandataClientMethod" access="private" returntype="any" output="false">
		<cfargument name="agencyID" type="numeric" required="true">
		<cfargument name="employeeID" type="numeric" required="false" default="0">
		<cfargument name="methodName" type="string" required="true">
		<cfargument name="encPatientID" type="string" required="true">

		<cfset setupAgencyContext(arguments.agencyID, arguments.employeeID)>
		<cfset var componentName = getSandataComponentName(arguments.agencyID)>
		<cfset var evvComponent = createObject("component", "components.sandata.#componentName#")>
		<!--- Call locally (not via remote HTTP) so automated transmit is not polluted by HTML output --->
		<cfreturn evvComponent.create_client(
			Patient_ID = arguments.encPatientID,
			Agency_ID = arguments.agencyID
		)>
	</cffunction>

	<cffunction name="transmitPatientClient" access="public" returntype="struct" output="false">
		<cfargument name="patientID" type="numeric" required="true">
		<cfargument name="agencyID" type="numeric" required="true">
		<cfargument name="employeeID" type="numeric" required="false" default="0">

		<cfset var result = { "success" = false, "message" = "" }>
		<cfset var encPatientID = "">
		<cfset var transmitResult = "">

		<cftry>
			<cfset setupAgencyContext(arguments.agencyID, arguments.employeeID)>
			<cfset encPatientID = encrypt(arguments.patientID, getApplicationEncKey(), "AES", "Hex")>
			<cfset transmitResult = invokeSandataClientMethod(arguments.agencyID, arguments.employeeID, "create_client", encPatientID)>

			<cfif isSuccessfulClientTransmit(transmitResult)>
				<cfset result.success = true>
				<cfset result.message = normalizeTransmitResult(transmitResult)>
			<cfelseif isSimpleValue(transmitResult) AND len(normalizeTransmitResult(transmitResult))>
				<cfset result.message = normalizeTransmitResult(transmitResult)>
			<cfelse>
				<cfset result.message = "Unexpected response from EVV create_client">
			</cfif>

			<cfcatch type="any">
				<cfset result.message = cfcatch.message>
			</cfcatch>
		</cftry>

		<cfif NOT result.success>
			<cfset sendTransmitErrorEmail(
				patientID = arguments.patientID,
				agencyID = arguments.agencyID,
				employeeID = arguments.employeeID,
				errorMessage = result.message
			)>
		</cfif>

		<cfreturn result>
	</cffunction>

	<cffunction name="sendTransmitErrorEmail" access="private" returntype="void" output="false">
		<cfargument name="patientID" type="numeric" required="true">
		<cfargument name="agencyID" type="numeric" required="true">
		<cfargument name="errorMessage" type="string" required="true">
		<cfargument name="employeeID" type="numeric" required="false" default="0">

		<cfset var mailTo = "velmurugan@myhomecarebiz.com">
		<cfif isDefined("request.send_errors_to") AND len(trim(request.send_errors_to))>
			<cfset mailTo = trim(request.send_errors_to)>
		</cfif>
		<cfset var envLabel = isDefined("Application.ServerName") ? Application.ServerName : CGI.SERVER_NAME>
		<cfset var mailSubject = "#envLabel# EVV Patient Transmit Error - Agency #arguments.agencyID# Patient #arguments.patientID#">

		<cftry>
			<cfmail to="#mailTo#" from="error@myhomecarebiz.com" subject="#mailSubject#" type="html">
				<h3>EVV Patient Transmit Error</h3>
				<p><strong>Time:</strong> #dateTimeFormat(now(), "yyyy-mm-dd HH:nn:ss")#</p>
				<p><strong>Server:</strong> #envLabel#</p>
				<p><strong>Agency ID:</strong> #arguments.agencyID#</p>
				<p><strong>Patient ID:</strong> #arguments.patientID#</p>
				<p><strong>Employee ID:</strong> #arguments.employeeID#</p>
				<p><strong>EVV component:</strong> #getSandataComponentName(arguments.agencyID)#</p>
				<p style="color: ##c00;"><strong>Error:</strong> #htmlEditFormat(arguments.errorMessage)#</p>
			</cfmail>
			<cfcatch type="any">
				<cflog file="EVVPatientAutomation" text="sendTransmitErrorEmail failed for patient #arguments.patientID#: #cfcatch.message#">
			</cfcatch>
		</cftry>
	</cffunction>

	<cffunction name="pollPatientClientStatus" access="public" returntype="struct" output="false">
		<cfargument name="patientID" type="numeric" required="true">
		<cfargument name="agencyID" type="numeric" required="true">
		<cfargument name="employeeID" type="numeric" required="false" default="0">
		<cfargument name="sendNotification" type="boolean" required="false" default="false">

		<cfset var result = { "success" = false, "status" = "", "message" = "" }>
		<cfset var encPatientID = "">
		<cfset var evvComponent = "">
		<cfset var statusResult = "">

		<cftry>
			<cfset setupAgencyContext(arguments.agencyID, arguments.employeeID)>
			<cfset encPatientID = encrypt(arguments.patientID, getApplicationEncKey(), "AES", "Hex")>
			<cfset evvComponent = createObject("component", "components.sandata.#getSandataComponentName(arguments.agencyID)#")>
			<cfif getSandataComponentName(arguments.agencyID) EQ "AHCCCS">
				<cfset statusResult = evvComponent.check_client_status(
					Patient_ID = encPatientID,
					Agency_ID = arguments.agencyID,
					sendNotification = arguments.sendNotification
				)>
			<cfelse>
				<cfset statusResult = evvComponent.check_client_status(
					Patient_ID = encPatientID,
					Agency_ID = arguments.agencyID
				)>
			</cfif>

			<cfif isStruct(statusResult)>
				<cfset result.success = structKeyExists(statusResult, "success") ? statusResult.success : false>
				<cfif structKeyExists(statusResult, "status")>
					<cfset result.status = statusResult.status>
				<cfelseif structKeyExists(statusResult, "data") AND isStruct(statusResult.data) AND structKeyExists(statusResult.data, "reason")>
					<cfset result.status = statusResult.data.reason>
				</cfif>
				<cfif structKeyExists(statusResult, "message")>
					<cfset result.message = statusResult.message>
				</cfif>
			</cfif>

			<cfcatch type="any">
				<cfset result.message = cfcatch.message>
			</cfcatch>
		</cftry>

		<cfreturn result>
	</cffunction>

	<cffunction name="isFinalEVVStatus" access="private" returntype="boolean" output="false">
		<cfargument name="statusText" type="string" required="true">

		<cfset var s = uCase(trim(arguments.statusText))>
		<cfreturn (
			find("TRANSACTION RECEIVED", s) GT 0
			OR find("SUCCESS", s) GT 0
			OR find("FAILED", s) GT 0
			OR find("ERROR", s) GT 0
		)>
	</cffunction>

	<cffunction name="updatePatientEvvSanStatus" access="private" returntype="boolean" output="false">
		<cfargument name="patientID" type="numeric" required="true">
		<cfargument name="agencyID" type="numeric" required="true">
		<cfargument name="sanStatus" type="string" required="true">

		<cfset var lookupDb = isDefined("Request.prefix_db_lookup") AND len(trim(Request.prefix_db_lookup)) ? Request.prefix_db_lookup : "hhapowerpath">
		<cfset var statusText = normalizeEvvStatusText(arguments.sanStatus)>
		<cfset var qEvv = "">

		<cfif NOT len(statusText)>
			<cfreturn false>
		</cfif>

		<cfquery name="qEvv" datasource="#Application.DataSrc#">
			SELECT EVV_ID
			FROM #lookupDb#.EVV
			WHERE LOWER(API_Type) = <cfqueryparam value="clients" cfsqltype="cf_sql_varchar">
			AND Agency_ID = <cfqueryparam value="#arguments.agencyID#" cfsqltype="cf_sql_integer">
			AND Patient_ID = <cfqueryparam value="#arguments.patientID#" cfsqltype="cf_sql_integer">
			AND status = <cfqueryparam value="0" cfsqltype="cf_sql_integer">
			ORDER BY EVV_ID DESC
			LIMIT 1
		</cfquery>

		<cfif qEvv.recordCount EQ 0>
			<cflog file="EVVPatientAutomation" text="updatePatientEvvSanStatus: no EVV clients row for patient #arguments.patientID# agency #arguments.agencyID#">
			<cfreturn false>
		</cfif>

		<cfquery datasource="#Application.DataSrc#">
			UPDATE #lookupDb#.EVV
			SET San_status = <cfqueryparam value="#left(statusText, 255)#" cfsqltype="cf_sql_varchar">,
				Date_Update = <cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp">
			WHERE EVV_ID = <cfqueryparam value="#qEvv.EVV_ID#" cfsqltype="cf_sql_integer">
		</cfquery>

		<cflog file="EVVPatientAutomation" text="updatePatientEvvSanStatus: patient #arguments.patientID# agency #arguments.agencyID# EVV_ID #qEvv.EVV_ID# set to '#statusText#'">
		<cfreturn true>
	</cffunction>

	<cffunction name="processPendingJobs" access="public" returntype="struct" output="false">
		<cfargument name="agencyID" type="numeric" required="false" default="0">

		<cfset var summary = {
			"success" = true,
			"transmitted" = 0,
			"polled" = 0,
			"completed" = 0,
			"failed" = 0,
			"jobsFound" = 0,
			"errors" = [],
			"details" = [],
			"ranAt" = now()
		}>
		<cfset var qJobs = "">
		<cfset var transmit = "">
		<cfset var poll = "">
		<cfset var currentStatus = "">
		<cfset var newJobStatus = "">
		<cfset var detailLine = "">

		<cfif NOT isDefined("Request.prefix_db_lookup") OR NOT len(trim(Request.prefix_db_lookup))>
			<cfset Request.prefix_db_lookup = "hhapowerpath">
		</cfif>

		<cfquery name="qJobs" datasource="#Application.DataSrc#">
			SELECT *
			FROM #Request.prefix_db_lookup#.EVV_Patient_Automation
			WHERE Job_Status IN (<cfqueryparam value="pending_transmit,waiting_status,polling_status" cfsqltype="cf_sql_varchar" list="true">)
			<cfif arguments.agencyID GT 0>
				AND Agency_ID = <cfqueryparam value="#arguments.agencyID#" cfsqltype="cf_sql_integer">
			</cfif>
			ORDER BY Automation_ID ASC
			LIMIT 100
		</cfquery>

		<cfset summary.jobsFound = qJobs.recordCount>

		<cfloop query="qJobs">
			<!--- <cfif NOT createObject("component", "components.evv.EVVStatusManager").init().agencyUsesEVVAutomation(qJobs.Agency_ID)>
				<cfcontinue>
			</cfif> --->
			<cftry>
				<cfif patientHasTransactionReceivedEVV(qJobs.Patient_ID, qJobs.Agency_ID)>
					<cfset updatePatientEvvSanStatus(qJobs.Patient_ID, qJobs.Agency_ID, "Transaction Received")>
					<cfquery datasource="#Application.DataSrc#">
						UPDATE #Request.prefix_db_lookup#.EVV_Patient_Automation
						SET Job_Status = <cfqueryparam value="complete" cfsqltype="cf_sql_varchar">,
							EVV_Status = <cfqueryparam value="Transaction Received" cfsqltype="cf_sql_varchar">,
							Date_Update = <cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp">
						WHERE Automation_ID = <cfqueryparam value="#qJobs.Automation_ID#" cfsqltype="cf_sql_integer">
					</cfquery>
					<cfset summary.completed++>
					<cfset arrayAppend(summary.details, "Job #qJobs.Automation_ID# (Agency #qJobs.Agency_ID#, Patient #qJobs.Patient_ID#): skipped - EVV status already Transaction Received")>
				<cfelseif qJobs.Job_Status EQ "pending_transmit" AND qJobs.Transmit_At LTE now()>
					<cfset transmit = transmitPatientClient(qJobs.Patient_ID, qJobs.Agency_ID, qJobs.Created_By)>
					<cfif transmit.success>
						<cfquery datasource="#Application.DataSrc#">
							UPDATE #Request.prefix_db_lookup#.EVV_Patient_Automation
							SET Job_Status = <cfqueryparam value="waiting_status" cfsqltype="cf_sql_varchar">,
								Transmit_Result = <cfqueryparam value="#left(transmit.message, 500)#" cfsqltype="cf_sql_varchar">,
								Status_Check_Start = <cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp">,
								Status_Check_End = <cfqueryparam value="#DateAdd('n', 80, now())#" cfsqltype="cf_sql_timestamp">,
								Last_Error = NULL,
								Date_Update = <cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp">
							WHERE Automation_ID = <cfqueryparam value="#qJobs.Automation_ID#" cfsqltype="cf_sql_integer">
						</cfquery>
						<cfset summary.transmitted++>
						<cfset arrayAppend(summary.details, "Job #qJobs.Automation_ID# (Agency #qJobs.Agency_ID#, Patient #qJobs.Patient_ID#): transmitted successfully")>
					<cfelse>
						<cfquery datasource="#Application.DataSrc#">
							UPDATE #Request.prefix_db_lookup#.EVV_Patient_Automation
							SET Job_Status = <cfqueryparam value="failed" cfsqltype="cf_sql_varchar">,
								Last_Error = <cfqueryparam value="#left(transmit.message, 1000)#" cfsqltype="cf_sql_varchar">,
								Date_Update = <cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp">
							WHERE Automation_ID = <cfqueryparam value="#qJobs.Automation_ID#" cfsqltype="cf_sql_integer">
						</cfquery>
						<cfset summary.failed++>
						<cfset summary.success = false>
						<cfset arrayAppend(summary.errors, "Job #qJobs.Automation_ID# (Agency #qJobs.Agency_ID#, Patient #qJobs.Patient_ID#): transmit failed - #transmit.message#")>
					</cfif>
				<cfelseif listFind("waiting_status,polling_status", qJobs.Job_Status) AND qJobs.Status_Check_Start LTE now()>
					<cfif qJobs.Status_Check_End LTE now()>
						<cfif len(trim(qJobs.EVV_Status))>
							<cfset updatePatientEvvSanStatus(qJobs.Patient_ID, qJobs.Agency_ID, qJobs.EVV_Status)>
						</cfif>
						<cfquery datasource="#Application.DataSrc#">
							UPDATE #Request.prefix_db_lookup#.EVV_Patient_Automation
							SET Job_Status = <cfqueryparam value="complete" cfsqltype="cf_sql_varchar">,
								Date_Update = <cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp">
							WHERE Automation_ID = <cfqueryparam value="#qJobs.Automation_ID#" cfsqltype="cf_sql_integer">
						</cfquery>
						<cfset summary.completed++>
						<cfset arrayAppend(summary.details, "Job #qJobs.Automation_ID# (Agency #qJobs.Agency_ID#, Patient #qJobs.Patient_ID#): polling window ended, marked complete")>
					<cfelse>
						<cfset poll = pollPatientClientStatus(qJobs.Patient_ID, qJobs.Agency_ID, qJobs.Created_By, false)>
						<cfset currentStatus = len(trim(poll.status)) ? poll.status : poll.message>
						<cfif len(trim(currentStatus))>
							<cfset updatePatientEvvSanStatus(qJobs.Patient_ID, qJobs.Agency_ID, currentStatus)>
						</cfif>
						<cfset newJobStatus = isFinalEVVStatus(currentStatus) ? "complete" : "polling_status">
						<cfquery datasource="#Application.DataSrc#">
							UPDATE #Request.prefix_db_lookup#.EVV_Patient_Automation
							SET Job_Status = <cfqueryparam value="#newJobStatus#" cfsqltype="cf_sql_varchar">,
								EVV_Status = <cfqueryparam value="#left(currentStatus, 255)#" cfsqltype="cf_sql_varchar">,
								Status_Check_Count = Status_Check_Count + 1,
								Last_Status_Check = <cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp">,
								Last_Error = <cfqueryparam value="#left(poll.message, 1000)#" cfsqltype="cf_sql_varchar" null="#NOT len(trim(poll.message))#">,
								Date_Update = <cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp">
							WHERE Automation_ID = <cfqueryparam value="#qJobs.Automation_ID#" cfsqltype="cf_sql_integer">
						</cfquery>
						<cfset summary.polled++>
						<cfset detailLine = "Job #qJobs.Automation_ID# (Agency #qJobs.Agency_ID#, Patient #qJobs.Patient_ID#): status poll returned '#currentStatus#'">
						<cfif isFinalEVVStatus(currentStatus)>
							<cfset summary.completed++>
							<cfset detailLine &= " - marked complete">
						</cfif>
						<cfif NOT poll.success>
							<cfset summary.success = false>
							<cfset summary.failed++>
							<cfset arrayAppend(summary.errors, detailLine & " - #poll.message#")>
						<cfelse>
							<cfset arrayAppend(summary.details, detailLine)>
						</cfif>
					</cfif>
				</cfif>

				<cfcatch type="any">
					<cfset summary.success = false>
					<cfset summary.failed++>
					<cfquery datasource="#Application.DataSrc#">
						UPDATE #Request.prefix_db_lookup#.EVV_Patient_Automation
						SET Last_Error = <cfqueryparam value="#left(cfcatch.message, 1000)#" cfsqltype="cf_sql_varchar">,
							Date_Update = <cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp">
						WHERE Automation_ID = <cfqueryparam value="#qJobs.Automation_ID#" cfsqltype="cf_sql_integer">
					</cfquery>
					<cfset arrayAppend(summary.errors, "Job #qJobs.Automation_ID# (Agency #qJobs.Agency_ID#, Patient #qJobs.Patient_ID#): #cfcatch.message#")>
					<cflog file="EVVPatientAutomation" text="processPendingJobs error for Automation_ID #qJobs.Automation_ID#: #cfcatch.message#">
				</cfcatch>
			</cftry>
		</cfloop>

		<cfreturn summary>
	</cffunction>

	<cffunction name="cronRunHasErrors" access="private" returntype="boolean" output="false">
		<cfargument name="summary" type="struct" required="true">
		<cfargument name="fatalError" type="struct" required="false" default="#structNew()#">
		<cfreturn (
			structCount(arguments.fatalError) GT 0
			OR (structKeyExists(arguments.summary, "errors") AND arrayLen(arguments.summary.errors) GT 0)
			OR (structKeyExists(arguments.summary, "failed") AND arguments.summary.failed GT 0)
			OR (structKeyExists(arguments.summary, "success") AND NOT arguments.summary.success)
		)>
	</cffunction>

	<cffunction name="sendCronRunEmail" access="public" returntype="void" output="false">
		<cfargument name="summary" type="struct" required="true">
		<cfargument name="fatalError" type="struct" required="false" default="#structNew()#">

		<cfif NOT cronRunHasErrors(arguments.summary, arguments.fatalError)>
			<cfreturn>
		</cfif>

		<cfset var mailTo = "jasmin.s@myhomecarebiz.com,velmurugan@myhomecarebiz.com">
		<cfif isDefined("request.send_errors_to") AND len(trim(request.send_errors_to))>
			<cfset mailTo = reReplace(trim(request.send_errors_to), "\s+", " ", "all")>
		</cfif>

		<cfset var hasFatal = structCount(arguments.fatalError) GT 0>
		<cfset var hasJobErrors = structKeyExists(arguments.summary, "errors") AND arrayLen(arguments.summary.errors) GT 0>
		<cfset var hasActivity = (
			arguments.summary.transmitted GT 0
			OR arguments.summary.polled GT 0
			OR arguments.summary.completed GT 0
			OR arguments.summary.failed GT 0
		)>
		<cfset var envLabel = isDefined("Application.ServerName") ? Application.ServerName : CGI.SERVER_NAME>
		<cfset var subjectPrefix = (hasFatal OR hasJobErrors OR arguments.summary.failed GT 0) ? "ERROR" : "SUCCESS">
		<cfset var mailSubject = "#envLabel# EVV Patient Automation Cron - #subjectPrefix#">

		<cfsavecontent variable="local.mailBody">
			<cfoutput>
			<h3>EVV Patient Automation Cron Run</h3>
			<p><strong>Run time:</strong> #dateTimeFormat(arguments.summary.ranAt, "yyyy-mm-dd HH:nn:ss")#</p>
			<p><strong>Server:</strong> #envLabel#</p>
			<cfif hasFatal>
				<p style="color: ##c00;"><strong>Fatal error:</strong> #arguments.fatalError.message#</p>
				<cfif structKeyExists(arguments.fatalError, "detail") AND len(arguments.fatalError.detail)>
					<p><strong>Detail:</strong> #arguments.fatalError.detail#</p>
				</cfif>
			</cfif>
			<table border="1" cellpadding="6" cellspacing="0" style="border-collapse: collapse;">
				<tr><td>Pending jobs found</td><td>#arguments.summary.jobsFound#</td></tr>
				<tr><td>Transmitted</td><td>#arguments.summary.transmitted#</td></tr>
				<tr><td>Status polls</td><td>#arguments.summary.polled#</td></tr>
				<tr><td>Completed</td><td>#arguments.summary.completed#</td></tr>
				<tr><td>Failed</td><td>#arguments.summary.failed#</td></tr>
			</table>
			<cfif structKeyExists(arguments.summary, "details") AND arrayLen(arguments.summary.details)>
				<h4>Details</h4>
				<ul>
					<cfloop array="#arguments.summary.details#" index="local.detailItem">
						<li>#htmlEditFormat(local.detailItem)#</li>
					</cfloop>
				</ul>
			</cfif>
			<cfif hasJobErrors>
				<h4 style="color: ##c00;">Errors</h4>
				<ul>
					<cfloop array="#arguments.summary.errors#" index="local.errorItem">
						<li>#htmlEditFormat(local.errorItem)#</li>
					</cfloop>
				</ul>
			</cfif>
			<cfif NOT hasActivity AND NOT hasFatal AND NOT hasJobErrors>
				<p>No pending EVV patient automation jobs required processing on this run.</p>
			</cfif>
			</cfoutput>
		</cfsavecontent>

		<cftry>
			<cfmail to="#mailTo#" from="error@myhomecarebiz.com" subject="#mailSubject#" type="html">
				<cfoutput>#local.mailBody#</cfoutput>
			</cfmail>
			<cfcatch type="any">
				<cflog file="EVVPatientAutomation" text="sendCronRunEmail failed: #cfcatch.message#">
			</cfcatch>
		</cftry>
	</cffunction>

	<cffunction name="getActiveJobForPatient" access="public" returntype="struct" output="false">
		<cfargument name="patientID" type="numeric" required="true">
		<cfargument name="agencyID" type="numeric" required="true">

		<cfset var result = { "hasActiveJob" = false, "jobStatus" = "", "evvStatus" = "", "automationID" = 0 }>
		<cfset var qJob = "">

		<cfquery name="qJob" datasource="#Application.DataSrc#">
			SELECT Automation_ID, Job_Status, EVV_Status
			FROM #Request.prefix_db_lookup#.EVV_Patient_Automation
			WHERE Agency_ID = <cfqueryparam value="#arguments.agencyID#" cfsqltype="cf_sql_integer">
			AND Patient_ID = <cfqueryparam value="#arguments.patientID#" cfsqltype="cf_sql_integer">
			AND Job_Status IN (<cfqueryparam value="pending_transmit,waiting_status,polling_status" cfsqltype="cf_sql_varchar" list="true">)
			ORDER BY Automation_ID DESC
			LIMIT 1
		</cfquery>

		<cfif qJob.recordCount GT 0>
			<cfset result.hasActiveJob = true>
			<cfset result.jobStatus = qJob.Job_Status>
			<cfset result.evvStatus = qJob.EVV_Status>
			<cfset result.automationID = qJob.Automation_ID>
		</cfif>

		<cfreturn result>
	</cffunction>

	<cffunction name="updateAutomationJobFromStatusCheck" access="public" returntype="struct" output="false">
		<cfargument name="patientID" type="numeric" required="true">
		<cfargument name="agencyID" type="numeric" required="true">
		<cfargument name="evvStatus" type="string" required="true">

		<cfset var result = { "updated" = false, "automationID" = 0, "jobStatus" = "", "hasActiveJob" = false }>
		<cfset var qJob = "">
		<cfset var statusText = trim(arguments.evvStatus)>
		<cfset var newJobStatus = "">

		<cfif NOT len(statusText)>
			<cfreturn result>
		</cfif>

		<cfif NOT isDefined("Request.prefix_db_lookup") OR NOT len(trim(Request.prefix_db_lookup))>
			<cfset Request.prefix_db_lookup = "hhapowerpath">
		</cfif>

		<cfquery name="qJob" datasource="#Application.DataSrc#">
			SELECT Automation_ID, Job_Status
			FROM #Request.prefix_db_lookup#.EVV_Patient_Automation
			WHERE Agency_ID = <cfqueryparam value="#arguments.agencyID#" cfsqltype="cf_sql_integer">
			AND Patient_ID = <cfqueryparam value="#arguments.patientID#" cfsqltype="cf_sql_integer">
			AND Job_Status IN (<cfqueryparam value="pending_transmit,waiting_status,polling_status" cfsqltype="cf_sql_varchar" list="true">)
			ORDER BY Automation_ID DESC
			LIMIT 1
		</cfquery>

		<cfif qJob.recordCount EQ 0>
			<cfquery name="qJob" datasource="#Application.DataSrc#">
				SELECT Automation_ID, Job_Status
				FROM #Request.prefix_db_lookup#.EVV_Patient_Automation
				WHERE Agency_ID = <cfqueryparam value="#arguments.agencyID#" cfsqltype="cf_sql_integer">
				AND Patient_ID = <cfqueryparam value="#arguments.patientID#" cfsqltype="cf_sql_integer">
				AND Job_Status <> <cfqueryparam value="cancelled" cfsqltype="cf_sql_varchar">
				ORDER BY Automation_ID DESC
				LIMIT 1
			</cfquery>
		</cfif>

		<cfif qJob.recordCount EQ 0>
			<cfreturn result>
		</cfif>

		<cfset newJobStatus = isFinalEVVStatus(statusText) ? "complete" : qJob.Job_Status>
		<cfif listFind("waiting_status,polling_status", qJob.Job_Status) AND NOT isFinalEVVStatus(statusText)>
			<cfset newJobStatus = "polling_status">
		</cfif>

		<cfquery datasource="#Application.DataSrc#">
			UPDATE #Request.prefix_db_lookup#.EVV_Patient_Automation
			SET EVV_Status = <cfqueryparam value="#left(statusText, 255)#" cfsqltype="cf_sql_varchar">,
				Job_Status = <cfqueryparam value="#newJobStatus#" cfsqltype="cf_sql_varchar">,
				Status_Check_Count = Status_Check_Count + 1,
				Last_Status_Check = <cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp">,
				Last_Error = NULL,
				Date_Update = <cfqueryparam value="#now()#" cfsqltype="cf_sql_timestamp">
			WHERE Automation_ID = <cfqueryparam value="#qJob.Automation_ID#" cfsqltype="cf_sql_integer">
		</cfquery>

		<cfset result.updated = true>
		<cfset result.automationID = qJob.Automation_ID>
		<cfset result.jobStatus = newJobStatus>
		<cfset result.hasActiveJob = listFind("pending_transmit,waiting_status,polling_status", newJobStatus) GT 0>

		<cfreturn result>
	</cffunction>

	<cffunction name="syncAutomationJobFromStatusCheck" access="remote" returnformat="json" output="false">
		<cfargument name="Patient_ID" required="yes">
		<cfargument name="EVV_Status" required="false" default="">
		<cfargument name="Agency_ID" required="false" default="0">

		<cfset var patientID = decrypt(arguments.Patient_ID, getApplicationEncKey(), "AES", "Hex")>
		<cfset var agencyID = resolveAgencyID(val(arguments.Agency_ID))>
		<cfset var statusText = trim(arguments.EVV_Status)>
		<cfset var syncResult = "">

		<cfif agencyID LTE 0>
			<cfreturn { "success" = false, "message" = "Agency ID is required" }>
		</cfif>

		<cfset setupAgencyContext(agencyID)>

		<cfif NOT len(statusText)>
			<cfset var evvManager = createObject("component", "components.evv.EVVStatusManager").init()>
			<cfset var evvStatus = evvManager.getEVVStatusWithChangeDetection("clients", patientID, agencyID)>
			<cfset statusText = evvStatus.EVV_Status>
		</cfif>

		<cfset syncResult = updateAutomationJobFromStatusCheck(patientID, agencyID, statusText)>

		<cfreturn {
			"success" = true,
			"status" = statusText,
			"updated" = syncResult.updated,
			"automationID" = syncResult.automationID,
			"jobStatus" = syncResult.jobStatus,
			"hasActiveJob" = syncResult.hasActiveJob
		}>
	</cffunction>

	<cffunction name="getPatientAutomationStatus" access="remote" returnformat="json" output="false">
		<cfargument name="Patient_ID" required="yes">
		<cfargument name="Agency_ID" required="false" default="0">

		<cfset var patientID = decrypt(arguments.Patient_ID, getApplicationEncKey(), "AES", "Hex")>
		<cfset var agencyID = resolveAgencyID(val(arguments.Agency_ID))>
		<cfset var evvManager = "">
		<cfset var evvStatus = "">
		<cfset var activeJob = "">
		<cfset var displayStatus = "">

		<cfif agencyID LTE 0>
			<cfreturn { "success" = false, "message" = "Agency ID is required" }>
		</cfif>

		<cfset setupAgencyContext(agencyID)>
		<cfset evvManager = createObject("component", "components.evv.EVVStatusManager").init()>
		<cfset evvStatus = evvManager.getEVVStatusWithChangeDetection("clients", patientID, agencyID)>
		<cfset activeJob = getActiveJobForPatient(patientID, agencyID)>
		<cfset displayStatus = evvStatus.EVV_Status>

		<cfif len(trim(activeJob.evvStatus))>
			<cfset displayStatus = activeJob.evvStatus>
		</cfif>

		<cfreturn {
			"success" = true,
			"status" = displayStatus,
			"hasChanges" = evvStatus.HasChanges,
			"hasActiveJob" = activeJob.hasActiveJob,
			"jobStatus" = activeJob.jobStatus
		}>
	</cffunction>

</cfcomponent>
