/// <summary> /// Notify the operation /// </summary> public void Notify(NotificationQueueWorkItem workItem) { // configuration service ISystemConfigurationService config = this.Context.GetService(typeof(ISystemConfigurationService)) as ISystemConfigurationService; ILocalizationService locale = this.Context.GetService(typeof(ILocalizationService)) as ILocalizationService; // Common message bits we need to update IMessage notificationMessage = null; MSH msh = null; PID pid = null; EVN evn = null; PV1 pv1 = null; MRG mrg = null; // Identify the work item action switch (workItem.Action) { case MARC.HI.EHRS.CR.Notification.PixPdq.Configuration.ActionType.Create: { ADT_A01 message = new ADT_A01(); msh = message.MSH; pid = message.PID; evn = message.EVN; pv1 = message.PV1; notificationMessage = message; msh.MessageType.TriggerEvent.Value = "A04"; break; } case MARC.HI.EHRS.CR.Notification.PixPdq.Configuration.ActionType.DuplicatesResolved: { ADT_A39 message = new ADT_A39(); msh = message.MSH; msh.MessageType.TriggerEvent.Value = "A40"; pid = message.GetPATIENT(0).PID; evn = message.EVN; pv1 = message.GetPATIENT(0).PV1; mrg = message.GetPATIENT(0).MRG; notificationMessage = message; break; }; case MARC.HI.EHRS.CR.Notification.PixPdq.Configuration.ActionType.Update: { ADT_A01 message = new ADT_A01(); msh = message.MSH; pid = message.PID; evn = message.EVN; pv1 = message.PV1; notificationMessage = message; msh.MessageType.TriggerEvent.Value = "A08"; break; } } // Populate the MSH header first this.UpdateMSH(msh, config); // Populate the EVN segment evn.EventTypeCode.Value = workItem.Event.Mode.ToString(); evn.RecordedDateTime.TimeOfAnEvent.Value = (TS)workItem.Event.Timestamp; // Populate the PID segment Person subject = workItem.Event.FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf) as Person; this.UpdatePID(subject, pid, config); pv1.PatientClass.Value = "I"; // Populate MRG if (mrg != null) { var registration = this.Context.GetService(typeof(IDataRegistrationService)) as IDataRegistrationService; var persistence = this.Context.GetService(typeof(IDataPersistenceService)) as IDataPersistenceService; var replacements = subject.FindAllComponents(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.ReplacementOf); foreach (PersonRegistrationRef rplc in replacements) { // First, need to de-persist the identifiers QueryParameters qp = new QueryParameters() { Confidence = 1.0f, MatchingAlgorithm = MatchAlgorithm.Exact, MatchStrength = MatchStrength.Exact }; var queryEvent = new QueryEvent(); var patientQuery = new RegistrationEvent(); queryEvent.Add(qp, "FLT", SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.FilterOf, null); patientQuery.Add(new Person() { AlternateIdentifiers = rplc.AlternateIdentifiers }, "SUBJ", SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf, null); queryEvent.Add(patientQuery, "SUBJ", SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf, null); // Perform the query var patientIdentifiers = registration.QueryRecord(queryEvent); if (patientIdentifiers.Length == 0) { throw new InvalidOperationException(); } var replacedPerson = (persistence.GetContainer(patientIdentifiers[0], true) as RegistrationEvent).FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf) as Person; foreach (var ii in replacedPerson.AlternateIdentifiers.FindAll(o => this.Target.NotificationDomain.Exists(d => d.Domain == o.Domain))) { var cx = mrg.GetPriorPatientIdentifierList(mrg.PriorAlternatePatientIDRepetitionsUsed); cx.ID.Value = ii.Identifier; if (String.IsNullOrEmpty(ii.AssigningAuthority)) { cx.AssigningAuthority.NamespaceID.Value = config.OidRegistrar.FindData(ii.Domain).Attributes.Find(o => o.Key == "AssigningAuthorityName").Value; } else { cx.AssigningAuthority.NamespaceID.Value = ii.AssigningAuthority; } cx.AssigningAuthority.UniversalID.Value = ii.Domain; cx.AssigningAuthority.UniversalIDType.Value = "ISO"; } } } // Send var queueItem = new Hl7MessageQueue.MessageQueueWorkItem(this.Target, notificationMessage); if (!queueItem.TrySend()) { Trace.TraceWarning(locale.GetString("NTFW005")); Hl7MessageQueue.Current.EnqueueMessageItem(queueItem); } }
/// <summary> /// Represents when the ADT registration occurs /// </summary> protected void AdtPatientRegistrationInterceptor_Behavior(object sender, DataPersistedEventArgs <Patient> e) { ApplicationServiceContext.Current.GetService <IThreadPoolService>().QueueNonPooledWorkItem( (p) => { AuthenticationContext.Current = new AuthenticationContext(AuthenticationContext.SystemPrincipal); Patient pat = p as Patient; // We want to construct an ADT message if (and only if) the guards are met and if the last ADT was not this version var tag = pat.LoadCollection <EntityTag>("Tags").FirstOrDefault(o => o.TagKey == TagName); if (tag?.Value == e.Data.VersionKey.ToString()) { return; // No need } else if (base.ExecuteGuard(pat)) { // Perform notification IMessage notificationMessage; IGroup patientGroup; if (tag?.Value == null) { // Set the tag value and send an ADMIT patientGroup = notificationMessage = new ADT_A01(); ApplicationServiceContext.Current.GetService <ITagPersistenceService>().Save(pat.Key.Value, new EntityTag(TagName, pat.VersionKey.ToString())); (notificationMessage.GetStructure("MSH") as MSH).MessageType.TriggerEvent.Value = "A04"; (notificationMessage.GetStructure("MSH") as MSH).MessageType.MessageStructure.Value = "ADT_A01"; } else if (pat.LoadCollection <EntityRelationship>("Relationships").Any(o => o.RelationshipTypeKey == EntityRelationshipTypeKeys.Replaces && o.EffectiveVersionSequenceId == pat.VersionSequence)) { // Set the tag value and send an ADMIT notificationMessage = new ADT_A39(); patientGroup = (notificationMessage as ADT_A39).GetPATIENT(); ApplicationServiceContext.Current.GetService <ITagPersistenceService>().Save(pat.Key.Value, new EntityTag(TagName, pat.VersionKey.ToString())); (notificationMessage.GetStructure("MSH") as MSH).MessageType.TriggerEvent.Value = "A40"; (notificationMessage.GetStructure("MSH") as MSH).MessageType.MessageStructure.Value = "ADT_A40"; foreach (var mrg in pat.LoadCollection <EntityRelationship>("Relationships").Where(o => o.RelationshipTypeKey == EntityRelationshipTypeKeys.Replaces && o.EffectiveVersionSequenceId == pat.VersionSequence)) { var seg = patientGroup.GetStructure("MRG", patientGroup.GetAll("MRG").Length) as MRG; if (this.Configuration.ExportDomains.Any(o => o.DomainName == this.m_configuration.LocalAuthority.DomainName)) { var key = seg.PriorAlternatePatientIDRepetitionsUsed; seg.GetPriorAlternatePatientID(key).IDNumber.Value = mrg.TargetEntityKey.Value.ToString(); seg.GetPriorAlternatePatientID(key).IdentifierTypeCode.Value = "PI"; seg.GetPriorAlternatePatientID(key).AssigningAuthority.NamespaceID.Value = this.m_configuration.LocalAuthority.DomainName; seg.GetPriorAlternatePatientID(key).AssigningAuthority.UniversalID.Value = this.m_configuration.LocalAuthority.Oid; seg.GetPriorAlternatePatientID(key).AssigningAuthority.UniversalIDType.Value = "ISO"; } // Alternate identifiers foreach (var extrn in pat.LoadCollection <EntityIdentifier>("Identifiers")) { var key = seg.PriorAlternatePatientIDRepetitionsUsed; if (this.Configuration.ExportDomains.Any(o => o.DomainName == extrn.LoadProperty <AssigningAuthority>("Authority").DomainName)) { seg.GetPriorAlternatePatientID(key).IDNumber.Value = extrn.Value; seg.GetPriorAlternatePatientID(key).IdentifierTypeCode.Value = "PT"; seg.GetPriorAlternatePatientID(key).AssigningAuthority.NamespaceID.Value = extrn.LoadProperty <AssigningAuthority>("Authority")?.DomainName; seg.GetPriorAlternatePatientID(key).AssigningAuthority.UniversalID.Value = extrn.LoadProperty <AssigningAuthority>("Authority")?.Oid; seg.GetPriorAlternatePatientID(key).AssigningAuthority.UniversalIDType.Value = "ISO"; } } } } else { // Set the tag value and send an ADMIT patientGroup = notificationMessage = new ADT_A01(); ApplicationServiceContext.Current.GetService <ITagPersistenceService>().Save(pat.Key.Value, new EntityTag(TagName, pat.VersionKey.ToString())); (notificationMessage.GetStructure("MSH") as MSH).MessageType.TriggerEvent.Value = "A08"; (notificationMessage.GetStructure("MSH") as MSH).MessageType.MessageStructure.Value = "ADT_A08"; } if (!String.IsNullOrEmpty(this.Configuration.Version)) { (notificationMessage.GetStructure("MSH") as MSH).VersionID.VersionID.Value = this.Configuration.Version; } // Add SFT if (new Version(this.Configuration.Version ?? "2.5") >= new Version(2, 4)) { (notificationMessage.GetStructure("SFT", 0) as SFT).SetDefault(); } // Create the PID segment SegmentHandlers.GetSegmentHandler("PID").Create(e.Data, patientGroup, this.Configuration.ExportDomains.ToArray()); SegmentHandlers.GetSegmentHandler("PD1").Create(e.Data, patientGroup, this.Configuration.ExportDomains.ToArray()); SegmentHandlers.GetSegmentHandler("NK1").Create(e.Data, patientGroup, this.Configuration.ExportDomains.ToArray()); //SegmentHandlers.GetSegmentHandler("EVN").Create(e.Data, patientGroup, this.Configuration.ExportDomains.ToArray()); foreach (var itm in this.Configuration.Endpoints) { try { // TODO: Create an HL7 Queue (notificationMessage.GetStructure("MSH") as MSH).SetDefault(itm.ReceivingDevice, itm.ReceivingFacility, itm.SecurityToken); var response = itm.GetSender().SendAndReceive(notificationMessage); if (!(response.GetStructure("MSA") as MSA).AcknowledgmentCode.Value.EndsWith("A")) { throw new HL7Exception("Remote server rejected message"); } } catch (Exception ex) { this.m_tracer.TraceEvent(EventLevel.Error, "Error dispatching message {0} to {1}: {2} \r\n {3}", pat, itm.Address, ex, new PipeParser().Encode(notificationMessage)); } } } }, e.Data ); }
/// <summary> /// Notifies a remote system. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="workItem">The work item of the notification.</param> /// <exception cref="System.ArgumentOutOfRangeException"></exception> public void Notify <T>(NotificationQueueWorkItem <T> workItem) where T : IdentifiedData { IMessage notificationMessage; var patient = workItem.Event as Patient; MSH msh; PID pid; EVN evn; PV1 pv1; MRG mrg = null; switch (workItem.ActionType) { case ActionType.Create: { tracer.TraceEvent(TraceEventType.Information, 0, "Received create notification"); var message = new ADT_A01(); msh = message.MSH; msh.MessageType.MessageType.Value = "ADT"; msh.MessageType.MessageStructure.Value = "ADT_A01"; msh.MessageType.TriggerEvent.Value = "A01"; pid = message.PID; evn = message.EVN; evn.EventTypeCode.Value = "A01"; pv1 = message.PV1; notificationMessage = message; break; } case ActionType.DuplicatesResolved: { tracer.TraceEvent(TraceEventType.Information, 0, "Received duplicates resolved notification"); var message = new ADT_A39(); msh = message.MSH; msh.MessageType.MessageType.Value = "ADT"; msh.MessageType.MessageStructure.Value = "ADT_A40"; msh.MessageType.TriggerEvent.Value = "A40"; pid = message.GetPATIENT(0).PID; evn = message.EVN; evn.EventTypeCode.Value = "A40"; pv1 = message.GetPATIENT(0).PV1; mrg = message.GetPATIENT(0).MRG; notificationMessage = message; break; } case ActionType.Update: { tracer.TraceEvent(TraceEventType.Information, 0, "Received update notification"); var message = new ADT_A01(); msh = message.MSH; msh.MessageType.MessageType.Value = "ADT"; msh.MessageType.MessageStructure.Value = "ADT_A08"; msh.MessageType.TriggerEvent.Value = "A08"; pid = message.PID; evn = message.EVN; evn.EventTypeCode.Value = "A08"; pv1 = message.PV1; notificationMessage = message; break; } default: throw new ArgumentOutOfRangeException($"Invalid notification type {workItem.ActionType}"); } NotifierBase.UpdateMSH(msh, patient, this.TargetConfiguration); evn.RecordedDateTime.TimeOfAnEvent.Value = (TS)patient.CreationTime.DateTime; NotifierBase.UpdatePID(patient, pid, this.TargetConfiguration); pv1.PatientClass.Value = "I"; // TODO: populate the merge information if (mrg != null) { } var queueItem = new MessageQueueWorkItem(notificationMessage, this.TargetConfiguration); if (!queueItem.TrySend()) { tracer.TraceEvent(TraceEventType.Warning, 0, "Unable to send message to remote endpoint: {0}", this.TargetConfiguration.ConnectionString); Hl7MessageQueue.Current.Enqueue(queueItem); } }