maintenance: title: Standard MLM to mark an HM Event as done;; mlmname: STD_FUNC_HM_PERFORM_ACTION;; arden: version 2.5;; version: 18.4;; institution: AllScripts;; author: Allscripts Healthcare Solutions, Inc;; specialist: ;; date: 2018-10-26;; validation: testing;; /* P r o p r i e t a r y N o t i c e */ /* Unpublished (c) 2016 - 2018 Allscripts Healthcare, LLC. and/or its affiliates. All Rights Reserved. P r o p r i e t a r y N o t i c e: This software has been provided pursuant to a License Agreement, with Allscripts Healthcare, LLC. and/or its affiliates, containing restrictions on its use. This software contains valuable trade secrets and proprietary information of Allscripts Healthcare, LLC. and/or its affiliates and is protected by trade secret and copyright law. This software may not be copied or distributed in any form or medium, disclosed to any third parties, or used in any manner not provided for in said License Agreement except with prior written authorization from Allscripts Healthcare, LLC. and/or its affiliates. Notice to U.S. Government Users: This software is {{{SINGLE-QUOTE}}}Commercial Computer Software{{{SINGLE-QUOTE}}}. All product names are the trademarks or registered trademarks of Allscripts Healthcare, LLC. and/or its affiliates. */ /* P r o p r i e t a r y N o t i c e */ library: purpose: Standard Function MLM containing the necessary logic to Mark a Health Management immunization or wellness event as done. ;; explanation: Do not make any changes to this MLM unless instructed to do so by Allscripts. This MLM accepts several parameters which it uses to set properties on several .NET object which are then used to mark a Health Management immunization or wellness event as done. Parameter List: ClientGUID The Id for the current patient on which the trigger event is occuring. locationGUID The location group Id where the health management item was marked as done. linkedItemId An Id to an order or some other data type that is being processed by the calling MLM. If it is linked to a scheduled event occurrence the linked occurrence will be maked as done. If the Id is NULL or is not linked then the code will determine if it needs to create a new scheduled event occurrence. linkedItemType The type of the linked item. Only order (0) is supported at this time. updateDatabase A flag used to determine if the actual Mark as Done functionality will be called. If set to false it will go through all the look ups and will indicate what will happen. recordOnlyIfEventActive A flag that determines if the event being processed must be currently assigned to the patient and what state it should be. If true then the event must be assigned to the patient and it must be active. If false the the event must be assigned but it doesn{{{SINGLE-QUOTE}}}t need to be active. recordOnlyIfPatientAssignedEvent A flag that determines if the event needs to be already assigned before it can be marked as done. If true then the event must be assigned, the code will then check the flag recordOnlyIfEventActive. If false then the event will be added as long as it exists and is active in the catalog. hmAction The type of action performed (Only "MAD" and "MAND" are supported right now) eventOccurrenceObj immunizationObj vaccineMedicationLotObj consentDocumentObj educationalMaterialsObj The data objects used to create the new Health Management client event occurrence and mark it as done. For a wellness and immunization events the object eventOccurrenceObj is required. For immunization the immunizationObj is also manditory. All other objects are optional. notGivenReasonObj linkOrderToEventOccurrence ;; keywords: ;; knowledge: type: data-driven;; data: standard_libs := MLM {{{SINGLE-QUOTE}}}std_include_libs{{{SINGLE-QUOTE}}}; include standard_libs; using "Eclipsys.Clinicals.Common"; using "Sunrise.Clinicals.HealthManagement"; using "Sunrise.Clinicals.HealthManagement.ServiceInterfaces"; using namespace "Sunrise.Clinicals.HealthManagement"; using namespace "Sunrise.Clinicals.HealthManagement.ServiceInterfaces"; using namespace "Sunrise.Clinicals.HealthManagement.DataObjects"; // Parameters passed to MLM. ( clientGUID, locationGUID, linkedItemId, linkedItemType, updateDatabase, recordOnlyIfPatientAssignedEvent, recordOnlyIfEventActive, hmAction, eventOccurrenceObj, immunizationObj, vaccineMedicationLotObj, consentDocumentObj, educationalMaterialsObj, notGivenReasonObj, linkOrderToEventOccurrence ) := argument; log_execution_info := false; outputMessage := null; // Status levels // 1 = No client event on schedule // 2 = Success // 3 = Failure mlmStatus := 2; // Validate parameters if (eventOccurrenceObj is null OR eventOccurrenceObj.eventName is null OR clientGUID is null OR eventOccurrenceObj.actionProviderId is null ) then outputMessage := "The MLM STD_FUNC_HM_PERFORM_ACTION was called with invalid parameters.\n"; mlmStatus := 3; else // Test for the existance of the event if recordOnlyIfPatientAssignedEvent then // If true then check for an active schedule, otherwise the status // doesn{{{SINGLE-QUOTE}}}t matter if recordOnlyIfEventActive then activeClientEventTest := " AND ce.EventStatusType=0 "; else activeClientEventTest := " "; endif; // Find the matching Health Management Event from the mapped Ancillary Name. (eventId, eventType, eventTypeDesc ) := read last { "select e.EventID,e.Type,e1.ReferenceString as [TypeDesc] " || " from SXAHMEvent e " || " inner join SXAHMClientEvent ce on e.EventID = ce.EventID " || " inner join CV3EnumReference e1 on e1.TableName = {{{SINGLE-QUOTE}}}SXAHMEvent{{{SINGLE-QUOTE}}} " || " and e1.ColumnName={{{SINGLE-QUOTE}}}Type{{{SINGLE-QUOTE}}} and e1.EnumValue=e.Type " || "where e.Active=1 AND e.Name = " || SQL(eventOccurrenceObj.eventName) || activeClientEventTest || " AND ce.ClientGUID = " || SQL(clientGUID) }; else // Make sure there is an Event for the mapped name, doesn{{{SINGLE-QUOTE}}}t have to be on the patient{{{SINGLE-QUOTE}}}s // schedule (eventId, eventType, eventTypeDesc ) := read last { "select e.EventID,e.Type,e1.ReferenceString as [TypeDesc] " || " from SXAHMEvent e " || " inner join CV3EnumReference e1 on e1.TableName = {{{SINGLE-QUOTE}}}SXAHMEvent{{{SINGLE-QUOTE}}} " || " and e1.ColumnName={{{SINGLE-QUOTE}}}Type{{{SINGLE-QUOTE}}} and e1.EnumValue=e.Type " || "where e.Active=1 AND e.Name = " || SQL(eventOccurrenceObj.eventName) }; endif; // If found, get the necessary data from the other parameter objects // and then call the occurrence mark as done logic if eventId is not null then try placeOrder := false; //Get Pending occurrence ID for current eventID (eventOccurrenceId, linkId) := read last { "SELECT seo.ScheduledEventOccurrenceID, oli.LinkedItemID FROM SXAHMScheduledEventOccurrence seo " || " LEFT OUTER JOIN SXAHMOccurrenceLinkedItemXRef oli ON ( oli.ScheduledEventOccurrenceID = seo.ScheduledEventOccurrenceID AND oli.LinkedItemType =" || linkedItemType || ") " || " WHERE seo.OccurrenceStatusType=0 " || " AND seo.EventID=" || SQL(eventId) || " AND seo.ClientGUID=" || SQL(clientGUID) }; // Get the location facility time zone, from the location guid (locationTZNowDateTime) := read last { "DECLARE @EnterpriseNow DateTime " || " SELECT @EnterpriseNow = CurDate FROM dbo.SXADBGetEnterpriseNowTblFn(); " || " SELECT top 1 tz.LocalDate as locationTZNowDateTime " || " FROM CV3Location locn " || " left join CV3LocnFacility lf on ( iif( locn.IsFacility = 1 , locn.Guid, locn.FacilityGUID ) = lf.FacilityGUID ) " || " CROSS APPLY dbo.SXADBConvertEnterpriseToLocalTblFn(lf.TimeZone, @EnterpriseNow) tz " || " WHERE locn.GUID = " || SQL(locationGUID) }; eventOccurrenceMgr := new net_object {{{SINGLE-QUOTE}}}EventOccurrenceManager{{{SINGLE-QUOTE}}}; if ( eventOccurrenceId is not null ) then eventOccurrence := call eventOccurrenceMgr.GetEventOccurrence with eventOccurrenceId as {{{SINGLE-QUOTE}}}System.Int64{{{SINGLE-QUOTE}}}, locationTZNowDateTime as {{{SINGLE-QUOTE}}}System.Nullable{{{SINGLE-QUOTE}}}; else eventOccurrence := call {{{SINGLE-QUOTE}}}EventOccurrenceBObj{{{SINGLE-QUOTE}}}.CreateEventOccurrence with eventId as {{{SINGLE-QUOTE}}}System.Int32{{{SINGLE-QUOTE}}}; eventOccurrence.ClientPrimaryKey := (clientGUID as number) as {{{SINGLE-QUOTE}}}System.Int64{{{SINGLE-QUOTE}}}; endif; if linkOrderToEventOccurrence and linkId is null and linkedItemId is not null then placeOrder := true; endif; continueProcess := true; if hmAction = "MAD" then strAction := "Done"; elseif(hmAction = "MAND") then strAction := "not Done"; endif; // If the Mapped Event is an immunization then look for immumization and medication // lot information. if eventTypeDesc = "Immunization" then //Find if Vaccine exist. if immunizationObj.VaccineName is not null OR immunizationObj.CVXCode is not null then (vaccineId, vaccineName, vaccineCVXCode ) := read last { "SELECT vci.VaccineCatalogItemID, Name, CVXCode FROM SXAHMEventVaccineXRef vxref " || " INNER JOIN SXAHMVaccineCatalogItem vci ON (vci.VaccineCatalogItemID = vxref.VaccineID) " || " WHERE vxref.EventID =" || SQL(eventId) || " AND vci.Active = 1 AND (vci.Name =" || SQL(immunizationObj.VaccineName) || " OR vci.CVXCode =" || SQL(immunizationObj.CVXCode) || " ) " }; endif; if(vaccineId is null) then if immunizationObj.VaccineName is not null then vaccineInfo := "Vaccine name: " || immunizationObj.VaccineName ; endif; if immunizationObj.CVXCode is not null then vaccineInfo := vaccineInfo || "\nCVX Code: " || immunizationObj.CVXCode; endif; if vaccineInfo is null then vaccineInfo := "No vaccine data has been assigned to the order"; else vaccineInfo := vaccineInfo || "\n is not configured for this event"; endif; outputMessage := "Cannot mark the immunization event {{{SINGLE-QUOTE}}}" || eventOccurrenceObj.eventName || "{{{SINGLE-QUOTE}}} as " || strAction || ".\n"; outputMessage := outputMessage || vaccineInfo; mlmStatus := 3; continueProcess := false; endif; endif; if(continueProcess) then //Place Order first if(placeOrder AND updateDatabase) then //If created a new occurrence, we need to save it first if(eventOccurrence.PrimaryKey = 0)then x := call eventOccurrence.Insert; endif; occLinkedItemData := new net_object {{{SINGLE-QUOTE}}}OccurrenceLinkedItemXRefData{{{SINGLE-QUOTE}}}; occLinkedItemData.ScheduledEventOccurrenceId := eventOccurrence.PrimaryKey as {{{SINGLE-QUOTE}}}System.Int64{{{SINGLE-QUOTE}}}; occLinkedItemData.LinkedItemId := (linkedItemId as number) as {{{SINGLE-QUOTE}}}System.Int64{{{SINGLE-QUOTE}}}; occLinkedItemData.LinkedItemType := linkedItemType as {{{SINGLE-QUOTE}}}System.Int32{{{SINGLE-QUOTE}}}; occLinkedItemData.ParentOccurrenceID := eventOccurrence.ParentOccurrencePrimaryKey as {{{SINGLE-QUOTE}}}System.Nullable{{{SINGLE-QUOTE}}}; occLinkedItem := new net_object {{{SINGLE-QUOTE}}}OccurrenceLinkedItemXRefBObj{{{SINGLE-QUOTE}}} with (occLinkedItemData); x := call eventOccurrence.PlaceOrder with occLinkedItem, true; // Need to reload event occurrence, otherwise we have a update issue (MSRowVersion is different) eventOccurrence := call eventOccurrenceMgr.FindPendingEventOccurrenceForClientByEvent with (clientGUID as number) as {{{SINGLE-QUOTE}}}System.Int64{{{SINGLE-QUOTE}}}, eventId as {{{SINGLE-QUOTE}}}System.Int32{{{SINGLE-QUOTE}}}, null as {{{SINGLE-QUOTE}}}System.Nullable{{{SINGLE-QUOTE}}}; endif; //PlaceOrder // The objects eventOccurrence, consentDocument and educationMaterials are // used by both Wellness events and Immunization events. // Set the Action date and provider information yearAction := (extract year of eventOccurrenceObj.actionDate) as {{{SINGLE-QUOTE}}}System.Int32{{{SINGLE-QUOTE}}}; monthAction := (extract month of eventOccurrenceObj.actionDate) as {{{SINGLE-QUOTE}}}System.Int32{{{SINGLE-QUOTE}}}; dayAction := (extract day of eventOccurrenceObj.actionDate) as {{{SINGLE-QUOTE}}}System.Int32{{{SINGLE-QUOTE}}}; hourAction := extract hour of eventOccurrenceObj.actionDate; minAction := extract minute of eventOccurrenceObj.actionDate; timeString := hourAction formatted with "%02d" || ":" || minAction formatted with "%02d"; partialDate := new net_object {{{SINGLE-QUOTE}}}Eclipsys.Clinicals.Common.PartialDate{{{SINGLE-QUOTE}}} with (yearAction, monthAction, dayAction, timeString); eventOccurrence.ActionDateTime := partialDate; eventOccurrence.ActionProviderName := eventOccurrenceObj.actionProviderDisplayName; eventOccurrence.ActionProviderPrimaryKey := (eventOccurrenceObj.actionProviderId as number) as {{{SINGLE-QUOTE}}}System.Int64{{{SINGLE-QUOTE}}}; eventOccurrence.Comment := eventOccurrenceObj.Comment; eventOccurrence.SiteGivenCode := eventOccurrenceObj.SiteGivenCode; eventOccurrence.RouteCode := eventOccurrenceObj.RouteCode; eventOccurrence.IsPartialDose := eventOccurrenceObj.IsPartialDose; // set the action user on the history to be the user from the state object. This is the user // who triggered the MLM userGUID := read last {StateInfo: UserGUID }; if ( userGUID is not null ) then eventOccurrence.NewOccurrenceActionStatusHistory.ActionUserPrimaryKey := (userGUID as number) as {{{SINGLE-QUOTE}}}System.Nullable{{{SINGLE-QUOTE}}}; endif; if ( consentDocumentObj is not null ) then consentDocument := new net_object {{{SINGLE-QUOTE}}}ConsentDocumentBObj{{{SINGLE-QUOTE}}}; consentDocument.ConsentTypeCode := consentDocumentObj.TypeCode; consentDocument.ConsentDate := consentDocumentObj.ConsentDate as Time; //consentDocument.ConsentTypeTime := consentDocumentObj.ConsentTime; // Timespan -- not supported consentDocument.ConsentBy := consentDocumentObj.ConsentBy; consentDocument.RelationshipCode := consentDocumentObj.RelationShipCode; consentDocument.DocumentType := consentDocumentObj.DocumentType as {{{SINGLE-QUOTE}}}ConsentDocumentType{{{SINGLE-QUOTE}}}; x := call eventOccurrence.ConsentDocuments.Add with consentDocument; endif; if ( educationalMaterialsObj is not null ) then educationalMaterials := new net_object {{{SINGLE-QUOTE}}}EducationMaterialBObj{{{SINGLE-QUOTE}}}; educationalMaterials.EducationalMaterialTypeCode := educationalMaterialsObj.TypeCode; educationalMaterials.IsVis := educationalMaterialsObj.IsVis; educationalMaterials.PublishedDate := educationalMaterialsObj.PublishedDate as Time; educationalMaterials.PresentedDate := educationalMaterialsObj.PresentedDate as Time; x := call eventOccurrence.EducationMaterials.Add with educationalMaterials; endif; if( notGivenReasonObj is not null) then reasonType := eventTypeDesc || " " || notGivenReasonObj.ReasonType; reasonCode := notGivenReasonObj.ReasonCode; reason := notGivenReasonObj.Reason; //If ReasonCode is populated, get the Reason, Otherwise get the ReasonCode. if(reasonCode is not NULL) then reason := read last { "SELECT cr.Reason FROM CV3CodedReason cr WHERE Type = " || SQL(reasonType) || " AND Code = " || SQL(reasonCode) }; else reasonCode := read last { "SELECT cr.Code FROM CV3CodedReason cr WHERE Type = " || SQL(reasonType) || " AND Reason = " || SQL(notGivenReasonObj.Reason) }; endif; codedReason := new net_object {{{SINGLE-QUOTE}}}Sunrise.Clinicals.HealthManagement.ServiceInterfaces.CodedReason{{{SINGLE-QUOTE}}}; codedReason.Code := reasonCode; codedReason.Reason := reason; actionReason := new net_object {{{SINGLE-QUOTE}}}ActionReason{{{SINGLE-QUOTE}}} with (codedReason); eventOccurrence.NewOccurrenceActionStatusHistory.ActionCodedReasonType := reasonType; x := call eventOccurrence.NewOccurrenceActionStatusHistory.ActionReasons.Add with actionReason; eventOccurrence.NewOccurrenceActionStatusHistory.ActionMoreDetail := notGivenReasonObj.MoreDetails; endif; // If the Mapped Event is an immunization then look for immumization and medication // lot information. if (vaccineId is not null) then immunizationEventOccurrence := eventOccurrence as {{{SINGLE-QUOTE}}}ImmunizationEventOccurrenceBObj{{{SINGLE-QUOTE}}}; vaccineDose := (vaccineMedicationLotObj.LotDoseAmount as number) as {{{SINGLE-QUOTE}}}System.Nullable{{{SINGLE-QUOTE}}}; vaccineUom := vaccineMedicationLotObj.LotDoseUom; immunizationEventOccurrence.VaccinePrimaryKey := vaccineId; immunizationEventOccurrence.DoseAmount := vaccineDose; immunizationEventOccurrence.DoseUom := vaccineUom; immunizationEventOccurrence.VaccineProductCode := immunizationObj.VaccineProductCode; immunizationEventOccurrence.VaccineBrandName := immunizationObj.VaccineBrandName; immunizationEventOccurrence.VaccineEligibilityCode := immunizationObj.VaccineEligibilityCode; // One or the other, not both. if ( immunizationObj.VaccineManufacturerMVXCode is not null ) then immunizationEventOccurrence.VaccineManufacturerMvxCode := immunizationObj.VaccineManufacturerMVXCode; else immunizationEventOccurrence.VaccineManufacturer := immunizationObj.VaccineManufacturer; endif; // Set Lot information if (VaccineMedicationLotObj is not null) then vaccineMedicationLotData := new net_object {{{SINGLE-QUOTE}}}VaccineMedicationLotDataBObj{{{SINGLE-QUOTE}}}; vaccineMedicationLotData.LotNumber := VaccineMedicationLotObj.LotNumber; vaccineMedicationLotData.LotSourceCode := VaccineMedicationLotObj.LotSourceCode; vaccineMedicationLotData.LotExpirationDate := VaccineMedicationLotObj.LotExpirationDate as Time; vaccineMedicationLotData.LotDoseAmount := vaccineDose; vaccineMedicationLotData.LotDoseUom := vaccineUom; vaccineMedicationLotData.RemovedFromStorage := VaccineMedicationLotObj.RemovedFromStorageDate as Time; vaccineMedicationLotData.LotWasteAmount := (VaccineMedicationLotObj.LotWasteAmount as Number) as {{{SINGLE-QUOTE}}}System.Nullable{{{SINGLE-QUOTE}}}; vaccineMedicationLotData.LotWasteUom := VaccineMedicationLotObj.LotWasteUom; x := call immunizationEventOccurrence.VaccineMedicationLots.Add with vaccineMedicationLotData; endif; outputMessage := "Marked the vaccine type event occurrence {{{SINGLE-QUOTE}}}" || eventOccurrenceObj.eventName || "{{{SINGLE-QUOTE}}} as " || strAction || " using vaccine {{{SINGLE-QUOTE}}}" || vaccineName || "{{{SINGLE-QUOTE}}} CVXCode=(" || vaccineCVXCode || ")."; else outputMessage := "Marked the wellness event occurrence {{{SINGLE-QUOTE}}}" || eventOccurrenceObj.eventName || "{{{SINGLE-QUOTE}}} as " || strAction || "."; endif; //vaccineId is not null if mlmStatus = 2 AND updateDatabase then locationId := (locationGUID as Number) as {{{SINGLE-QUOTE}}}System.Nullable{{{SINGLE-QUOTE}}}; // Mark it as done via the manager eventOccurrenceMgr := new net_object {{{SINGLE-QUOTE}}}EventOccurrenceManager{{{SINGLE-QUOTE}}}; if hmAction = "MAD" then x := call eventOccurrenceMgr.MarkEventOccurrenceDone with eventOccurrence, locationId; elseif(hmAction = "MAND") then x := call eventOccurrenceMgr.MarkEventOccurrenceNotDone with eventOccurrence, locationId; endif; //hmAction = {{{SINGLE-QUOTE}}}MAD{{{SINGLE-QUOTE}}} // Re-evaluate based on possible new conditions clientEventMgr := new net_object {{{SINGLE-QUOTE}}}ClientEventManager{{{SINGLE-QUOTE}}}; dataChanged := call clientEventMgr.ReEvaluateClientEventOccurrence with (clientGUID as number) as {{{SINGLE-QUOTE}}}System.Int64{{{SINGLE-QUOTE}}}, eventId as {{{SINGLE-QUOTE}}}System.Int32{{{SINGLE-QUOTE}}}, null as {{{SINGLE-QUOTE}}}System.Nullable{{{SINGLE-QUOTE}}}; endif; endif; //continueProcess endtry; catch exception ex mlmStatus := 3; outputMessage := "An attempt to Mark as " || strAction || " the Health Management event {{{SINGLE-QUOTE}}}" || eventOccurrenceObj.eventName || "{{{SINGLE-QUOTE}}} has failed. \nThe reason for the failure is as follows:\n" || ex.Message; endcatch; else // Not an error condititon, just that the evoking object doesn{{{SINGLE-QUOTE}}}t have a matching // Health Management scheduled Client Event. mlmStatus := 1; if recordOnlyIfPatientAssignedEvent then outputMessage := "The Health Management event {{{SINGLE-QUOTE}}}" || eventOccurrenceObj.eventName || "{{{SINGLE-QUOTE}}} does not exist in the catalog or is not active on the patient{{{SINGLE-QUOTE}}}s chart.\n" || "No action has been taken."; else outputMessage := "The Health Management event {{{SINGLE-QUOTE}}}" || eventOccurrenceObj.eventName || "{{{SINGLE-QUOTE}}} does not exist in the catalog.\n" || "No action has been taken."; endif; endif; endif; ;; priority: 50 ;; evoke: ;; logic: conclude true; ;; action: return mlmStatus, outputMessage; ;; Urgency: 50;; end: