예제 #1
0
        /// <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
                );
        }
예제 #3
0
        /// <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);
            }
        }