예제 #1
0
        /// <summary>
        /// Enrich the registration event
        /// </summary>
        internal void EnrichRegistrationEvent(IDbConnection conn, IDbTransaction tx, RegistrationEvent hsrEvent)
        {
            decimal tryDec;
            ISystemConfigurationService configService = ApplicationContext.ConfigurationService;

            // Create a query based on the person
            Person subject = hsrEvent.FindComponent(HealthServiceRecordSiteRoleType.SubjectOf) as Person;

            if (subject.AlternateIdentifiers.Exists(o => o.Domain == configService.OidRegistrar.GetOid(ClientRegistryOids.CLIENT_CRID).Oid))
            {
                subject = new Person()
                {
                    AlternateIdentifiers = new List <DomainIdentifier>(subject.AlternateIdentifiers.FindAll(o => o.Domain == configService.OidRegistrar.GetOid(ClientRegistryOids.CLIENT_CRID).Oid)),
                    Status = StatusType.Normal
                }
            }
            ;
            else if (subject.AlternateIdentifiers.Exists(o => o is AuthorityAssignedDomainIdentifier))
            {
                subject = new Person()
                {
                    AlternateIdentifiers = new List <DomainIdentifier>(subject.AlternateIdentifiers.FindAll(o => o is AuthorityAssignedDomainIdentifier)),
                    Status = StatusType.Normal
                }
            }
            ;
            else
            {
                subject = new Person()
                {
                    AlternateIdentifiers = new List <DomainIdentifier>(subject.AlternateIdentifiers),
                    Status = StatusType.Normal
                }
            };

            QueryEvent        query = new QueryEvent();
            RegistrationEvent evt   = new RegistrationEvent();

            query.Add(evt, "SUBJ", HealthServiceRecordSiteRoleType.SubjectOf, null);
            evt.Status = StatusType.Active | StatusType.Obsolete;
            evt.Add(subject, "SUBJ", HealthServiceRecordSiteRoleType.SubjectOf, null);
            query.Add(new QueryParameters()
            {
                MatchingAlgorithm = MatchAlgorithm.Exact,
                MatchStrength     = MatchStrength.Exact
            }, "FLTR", HealthServiceRecordSiteRoleType.FilterOf, null);
            var tRecordIds = QueryRecord(query);

            if (tRecordIds.Length != 1)
            {
                throw new MissingPrimaryKeyException(ApplicationContext.LocaleService.GetString("DBCF004"));
            }
            else if (tRecordIds[0].Domain != configService.OidRegistrar.GetOid(ClientRegistryOids.REGISTRATION_EVENT).Oid)
            {
                throw new MissingPrimaryKeyException(ApplicationContext.LocaleService.GetString("DBCF005"));
            }

            tryDec = Decimal.Parse(tRecordIds[0].Identifier);
            hsrEvent.AlternateIdentifier = tRecordIds[0];
        }
예제 #2
0
        /// <summary>
        /// De-persist the component from the database
        /// </summary>
        public System.ComponentModel.IComponent DePersist(System.Data.IDbConnection conn, decimal identifier, IContainer container, HealthServiceRecordSiteRoleType?roleType, bool loadFast)
        {
            Place retVal = new Place();

            IDbCommand cmd = DbUtil.CreateCommandStoredProc(conn, null);

            try
            {
                // Determine the container
                RegistrationEvent hsrParent = container as RegistrationEvent;

                retVal = GetLocation(conn, null, new DomainIdentifier()
                {
                    Identifier = identifier.ToString()
                });

                // Data reader
                if (hsrParent != null)
                {
                    hsrParent.Add(retVal, Guid.NewGuid().ToString(), roleType.Value, retVal.AlternateIdentifiers);
                }
                else
                {
                    container.Add(retVal);
                }
            }
            finally
            {
                cmd.Dispose();
            }

            return(retVal);
        }
        /// <summary>
        /// Find conflicts using identifiers
        /// </summary>
        public IEnumerable <SVC.Core.DataTypes.VersionedDomainIdentifier> FindIdConflicts(RegistrationEvent registration)
        {
            var registrationService = this.Context.GetService(typeof(IDataRegistrationService)) as IDataRegistrationService;

            VersionedDomainIdentifier[] pid = null;

            // Check if the person exists just via the identifier?
            // This is important because it is not necessarily a merge but an "update if exists"
            var             subject = registration.FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf) as Person;
            QueryParameters qp      = new QueryParameters()
            {
                Confidence        = 1.0f,
                MatchingAlgorithm = MatchAlgorithm.Exact,
                MatchStrength     = MatchStrength.Exact
            };

            var config = this.Context.GetService(typeof(ISystemConfigurationService)) as ISystemConfigurationService;

            List <VersionedDomainIdentifier> conflictIds = new List <VersionedDomainIdentifier>();

            foreach (var id in subject.AlternateIdentifiers)
            {
                var data = config.OidRegistrar.FindData(id.Domain);
                if (data == null || !data.Attributes.Exists(a => a.Key == "IsUniqueIdentifier" && Convert.ToBoolean(a.Value)))
                {
                    continue;
                }
                var patientQuery      = new QueryEvent();
                var registrationEvent = new RegistrationEvent();
                patientQuery.Add(registrationEvent, "SUBJ", HealthServiceRecordSiteRoleType.SubjectOf, null);
                patientQuery.Add(qp, "FLT", SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.FilterOf, null);
                registrationEvent.Add(new Person()
                {
                    AlternateIdentifiers = new List <DomainIdentifier>()
                    {
                        id
                    }
                }, "SUBJ", SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf, null);
                // Perform the query
                pid = registrationService.QueryRecord(patientQuery);
                foreach (var result in pid)
                {
                    if (!conflictIds.Exists(o => o.Identifier.ToString() == result.Identifier))
                    {
                        conflictIds.Add(result);
                    }
                }
            }
            return(conflictIds.ToArray());
        }
        /// <summary>
        /// Merge two items together
        /// </summary>
        public void Resolve(IEnumerable <SVC.Core.DataTypes.VersionedDomainIdentifier> victimIds, SVC.Core.DataTypes.VersionedDomainIdentifier survivorId, SVC.Core.Services.DataPersistenceMode mode)
        {
            // First, we load the survivor
            if (survivorId.Domain != ApplicationContext.ConfigurationService.OidRegistrar.GetOid(ClientRegistryOids.REGISTRATION_EVENT).Oid)
            {
                throw new ArgumentException(String.Format("Must be drawn from the '{0}' domain", ApplicationContext.ConfigurationService.OidRegistrar.GetOid(ClientRegistryOids.REGISTRATION_EVENT).Oid), "survivorId");
            }

            // Load the survivor
            var persistenceService        = this.Context.GetService(typeof(IDataPersistenceService)) as IDataPersistenceService;
            var survivorRegistrationEvent = persistenceService.GetContainer(survivorId, true) as RegistrationEvent;

            if (survivorRegistrationEvent == null)
            {
                throw new InvalidOperationException("Could not load target registration event");
            }
            var survivorPerson = survivorRegistrationEvent.FindComponent(HealthServiceRecordSiteRoleType.SubjectOf) as Person;

            if (survivorPerson == null)
            {
                throw new InvalidOperationException("Target registration event has no SubjectOf relationship of type Person");
            }

            // Create the merge registration event
            RegistrationEvent mergeRegistrationEvent = new RegistrationEvent()
            {
                Mode            = RegistrationEventType.Replace,
                EventClassifier = RegistrationEventType.Register,
                LanguageCode    = survivorRegistrationEvent.LanguageCode
            };

            mergeRegistrationEvent.EventType = new CodeValue("ADMIN_MRG");
            mergeRegistrationEvent.Add(new ChangeSummary()
            {
                ChangeType    = new CodeValue("ADMIN_MRG"),
                EffectiveTime = new TimestampSet()
                {
                    Parts = new List <TimestampPart>()
                    {
                        new TimestampPart(TimestampPart.TimestampPartType.Standlone, DateTime.Now, "F")
                    }
                },
                Timestamp    = DateTime.Now,
                LanguageCode = survivorRegistrationEvent.LanguageCode
            }, "CHG", HealthServiceRecordSiteRoleType.ReasonFor | HealthServiceRecordSiteRoleType.OlderVersionOf, null);
            survivorPerson.Site = null;

            mergeRegistrationEvent.Add(survivorPerson, "SUBJ", HealthServiceRecordSiteRoleType.SubjectOf, null);

            // Next, we do a replaces relationship for each of the victims (loading them as well since the ID is of the patient not reg event)
            foreach (var id in victimIds)
            {
                var replacementReg = persistenceService.GetContainer(id, true) as RegistrationEvent;
                if (replacementReg == null)
                {
                    throw new InvalidOperationException("Could not load victim registration event");
                }
                var replacementPerson = replacementReg.FindComponent(HealthServiceRecordSiteRoleType.SubjectOf) as Person;
                if (replacementPerson == null)
                {
                    throw new InvalidOperationException("Victim registration event has no SubjectOf relationship of type Person");
                }

                // Now, create replaces
                survivorPerson.Add(new PersonRegistrationRef()
                {
                    AlternateIdentifiers = new List <DomainIdentifier>()
                    {
                        new DomainIdentifier()
                        {
                            Domain     = ApplicationContext.ConfigurationService.OidRegistrar.GetOid(ClientRegistryOids.CLIENT_CRID).Oid,
                            Identifier = replacementPerson.Id.ToString()
                        }
                    }
                }, Guid.NewGuid().ToString(), HealthServiceRecordSiteRoleType.ReplacementOf, null);
            }

            // Now persist the replacement
            IDbConnection  conn = DatabasePersistenceService.ConnectionManager.GetConnection();
            IDbTransaction tx   = null;

            try
            {
                // Update container
                var vid = persistenceService.UpdateContainer(mergeRegistrationEvent, DataPersistenceMode.Production);

                tx = conn.BeginTransaction();

                foreach (var id in victimIds)
                {
                    using (IDbCommand cmd = DbUtil.CreateCommandStoredProc(conn, tx))
                    {
                        cmd.CommandText = "mrg_cand";
                        cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "from_id_in", DbType.Decimal, Decimal.Parse(id.Identifier)));
                        cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "to_id_in", DbType.Decimal, Decimal.Parse(survivorId.Identifier)));
                        cmd.ExecuteNonQuery();
                    }
                    // Obsolete the victim identifier merges
                    using (IDbCommand cmd = DbUtil.CreateCommandStoredProc(conn, tx))
                    {
                        cmd.CommandText = "obslt_mrg";
                        cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "from_id_in", DbType.Decimal, Decimal.Parse(id.Identifier)));
                        cmd.ExecuteNonQuery();
                    }
                }
                tx.Commit();
            }
            catch (Exception e)
            {
                if (tx != null)
                {
                    tx.Rollback();
                }
                throw;
            }
            finally
            {
                DatabasePersistenceService.ConnectionManager.ReleaseConnection(conn);
            }
        }
        /// <summary>
        /// Find conflicts using fuzzy match
        /// </summary>
        public IEnumerable <VersionedDomainIdentifier> FindFuzzyConflicts(RegistrationEvent registration)
        {
            var registrationService = this.Context.GetService(typeof(IDataRegistrationService)) as IDataRegistrationService;
            var persistenceService  = this.Context.GetService(typeof(IDataPersistenceService)) as IDataPersistenceService;

            var clientRegistryConfigService = this.Context.GetService(typeof(IClientRegistryConfigurationService)) as IClientRegistryConfigurationService;

            VersionedDomainIdentifier[] pid = null;

            var             subject = registration.FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf) as Person;
            QueryParameters qp      = new QueryParameters()
            {
                Confidence        = 1.0f,
                MatchingAlgorithm = MatchAlgorithm.Exact,
                MatchStrength     = MatchStrength.Exact
            };

            if (subject.Status != StatusType.Active)
            {
                return(pid);
            }

            var patientQuery      = new QueryEvent();
            var registrationEvent = new RegistrationEvent();

            patientQuery.Add(registrationEvent, "SUBJ", HealthServiceRecordSiteRoleType.SubjectOf, null);
            patientQuery.Add(qp, "FLT", SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.FilterOf, null);
            // Create merge filter for fuzzy match
            var ssubject = clientRegistryConfigService.CreateMergeFilter(subject);

            if (ssubject != null) // Minimum criteria was met
            {
                registrationEvent.Add(ssubject, "SUBJ", HealthServiceRecordSiteRoleType.SubjectOf, null);
                pid = registrationService.QueryRecord(patientQuery);
            }
            else
            {
                pid = new VersionedDomainIdentifier[0];
            }


            // Now, look for all with an assigning authority
            if (pid.Length > 0)
            {
                pid = pid.Where(o => !(o.Identifier == registration.Id.ToString() && o.Domain == ApplicationContext.ConfigurationService.OidRegistrar.GetOid(ClientRegistryOids.REGISTRATION_EVENT).Oid)).ToArray();
                // Load each match quickly and ensure that they don't already have a
                // different identifier from an assigning authority (not CR_CID) provided
                // in the registration method. For example, if John Smith, Male, 1984-05-22, 123 Main Street West is
                // registered from system X with ID 102 , and a subsequent registration message for John Smith, Male, 1984-05-22, 123 Main Street West
                // is received from system X with ID 104, it is pretty much assured they aren't the same person. If however the
                // latter message came from system Y with ID 104, then the two should be considered a match.
                ssubject.AlternateIdentifiers = new List <DomainIdentifier>();
                List <VersionedDomainIdentifier> exclude = new List <VersionedDomainIdentifier>();
                foreach (var altId in subject.AlternateIdentifiers)
                {
                    if (altId.Domain != ApplicationContext.ConfigurationService.OidRegistrar.GetOid(ClientRegistryOids.CLIENT_CRID).Oid)
                    {
                        var oidData = ApplicationContext.ConfigurationService.OidRegistrar.FindData(altId.Domain);
                        if (oidData == null ||
                            oidData.Attributes.Find(o => o.Key == "IsUniqueIdentifier").Value == null ||
                            Boolean.Parse(oidData.Attributes.Find(o => o.Key == "IsUniqueIdentifier").Value))
                        {
                            ssubject.AlternateIdentifiers.Add(new DomainIdentifier()
                            {
                                Domain = altId.Domain
                            });
                        }
                    }
                }


                foreach (var p in pid)
                {
                    var re  = persistenceService.GetContainer(p, true) as RegistrationEvent;
                    var pat = re.FindComponent(HealthServiceRecordSiteRoleType.SubjectOf) as Person;
                    if (pat.Id == subject.Id || pat.Status != StatusType.Active)  // same person
                    {
                        exclude.Add(re.AlternateIdentifier);
                    }
                    else if (pat.AlternateIdentifiers.Exists(o => ssubject.AlternateIdentifiers.Exists(r => r.Domain == o.Domain)))
                    {
                        exclude.Add(re.AlternateIdentifier);
                    }
                }

                pid = pid.Where(o => !exclude.Exists(i => i.Domain == o.Domain && i.Identifier == o.Identifier)).ToArray();
            }
            return(pid);
        }
예제 #6
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>
        /// Get all registrations matching the query prototype
        /// </summary>
        public RegistrationEventCollection GetRegistrations(Person queryPrototype, int offset, int count)
        {
            // Get all Services
            IAuditorService          auditSvc = ApplicationContext.CurrentContext.GetService(typeof(IAuditorService)) as IAuditorService;
            IDataRegistrationService regSvc   = ApplicationContext.CurrentContext.GetService(typeof(IDataRegistrationService)) as IDataRegistrationService;
            IDataPersistenceService  repSvc   = ApplicationContext.CurrentContext.GetService(typeof(IDataPersistenceService)) as IDataPersistenceService;

            // Audit message
            AuditData audit = this.ConstructAuditData(ActionType.Read, EventIdentifierType.Export);

            audit.EventTypeCode = new CodeValue("ADM_GetRegistrations");

            try
            {
                // Result identifiers
                VersionedDomainIdentifier[] vids = null;
                var dummyQuery = new QueryEvent();
                var regEvt     = new RegistrationEvent()
                {
                    EventClassifier = RegistrationEventType.Register
                };
                dummyQuery.Add(regEvt, "SUBJ", SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf, null);

                if (queryPrototype == null)
                {
                    regEvt.Add(new Person(), "SUBJ", SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf, null);
                }
                else
                {
                    regEvt.Add(queryPrototype, "SUBJ", SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf, null);
                }
                vids = regSvc.QueryRecord(dummyQuery);

                RegistrationEventCollection retVal = new RegistrationEventCollection();
                Object syncLock = new object();
                retVal.Count = vids.Length;
                // Now fetch each one asynchronously
                using (WaitThreadPool thdPool = new WaitThreadPool(Environment.ProcessorCount * 2))
                {
                    foreach (var id in vids.Skip(offset).Take(count))
                    {
                        thdPool.QueueUserWorkItem(
                            delegate(object state)
                        {
                            try
                            {
                                var itm = repSvc.GetContainer(state as VersionedDomainIdentifier, true);

                                lock (syncLock)
                                    retVal.Event.Add(itm as RegistrationEvent);
                            }
                            catch (Exception e)
                            {
                                Trace.TraceError("Could not fetch result {0} : {1}", (state as VersionedDomainIdentifier).Identifier, e.ToString());
                            }
                        }
                            , id);
                    }

                    // Wait until fetch is done
                    thdPool.WaitOne(new TimeSpan(0, 0, 30), false);
                }
                //retVal.Event.Sort((a, b) => b.Timestamp.CompareTo(a.Timestamp));
                // Add audit data
                foreach (var res in retVal.Event)
                {
                    audit.AuditableObjects.Add(new AuditableObject()
                    {
                        IDTypeCode    = AuditableObjectIdType.ReportNumber,
                        LifecycleType = AuditableObjectLifecycle.Export,
                        ObjectId      = String.Format("{0}^^^&{1}&ISO", res.AlternateIdentifier.Identifier, res.AlternateIdentifier.Domain),
                        Role          = AuditableObjectRole.MasterFile,
                        Type          = AuditableObjectType.SystemObject,
                        QueryData     = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes("loadFast=true"))
                    });
                }
                return(retVal);
            }
            catch (Exception e)
            {
                Trace.TraceError("Could not execute GetRegistrations : {0}", e.ToString());
                audit.Outcome = OutcomeIndicator.EpicFail;
#if DEBUG
                throw new FaultException(new FaultReason(e.ToString()), new FaultCode(e.GetType().Name));
#else
                throw new FaultException(new FaultReason(e.Message), new FaultCode(e.GetType().Name));
#endif
            }
            finally
            {
                if (auditSvc != null)
                {
                    auditSvc.SendAudit(audit);
                }
            }
        }
예제 #8
0
        /// <summary>
        /// Create a patient registry duplicates resolved message
        /// </summary>
        private Everest.Interfaces.IInteraction CreatePatientRegistryDuplicatesResolvedMessage(Core.ComponentModel.RegistrationEvent registrationEvent, TargetConfiguration configuration)
        {
            // Construct the return value
            PRPA_IN201304UV02 retVal = new PRPA_IN201304UV02(
                Guid.NewGuid(),
                DateTime.Now,
                PRPA_IN201304UV02.GetInteractionId(),
                ProcessingID.Production,
                "T",
                AcknowledgementCondition.Always);

            // Construct the sending node
            retVal.VersionCode = HL7StandardVersionCode.Version3_Prerelease1;
            retVal.Sender      = CreateSenderNode();
            retVal.Receiver.Add(CreateReceiverNode(configuration));

            // Construct the control act process
            retVal.controlActProcess = new Everest.RMIM.UV.NE2008.MFMI_MT700701UV01.ControlActProcess <Everest.RMIM.UV.NE2008.PRPA_MT201303UV02.Patient, object>("EVN");

            // Get the subjects and components
            var subject      = registrationEvent.FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf) as Person;
            var providerOrg  = subject.FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.PlaceOfEntry | SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.InformantTo) as HealthcareParticipant;
            var custodian    = registrationEvent.FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.PlaceOfRecord | SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.ResponsibleFor);
            var replacements = subject.FindAllComponents(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.ReplacementOf);

            // Create the person
            List <DomainIdentifier> identifiers = new List <DomainIdentifier>(subject.AlternateIdentifiers.FindAll(o => configuration.NotificationDomain.Exists(d => d.Domain.Equals(o.Domain))));
            var eventRegistration = new Everest.RMIM.UV.NE2008.MFMI_MT700701UV01.Subject1 <Everest.RMIM.UV.NE2008.PRPA_MT201303UV02.Patient, object>(false,
                                                                                                                                                     new Everest.RMIM.UV.NE2008.MFMI_MT700701UV01.RegistrationEvent <Everest.RMIM.UV.NE2008.PRPA_MT201303UV02.Patient, object>(
                                                                                                                                                         ActStatus.Active,
                                                                                                                                                         new Everest.RMIM.UV.NE2008.MFMI_MT700701UV01.Subject2 <Everest.RMIM.UV.NE2008.PRPA_MT201303UV02.Patient>(
                                                                                                                                                             new Everest.RMIM.UV.NE2008.PRPA_MT201303UV02.Patient(
                                                                                                                                                                 CreateIISet(identifiers),
                                                                                                                                                                 RoleStatus.Active,
                                                                                                                                                                 CreatePerson(subject, new TargetConfiguration(String.Empty, null, configuration.Notifier.GetType().Name, null)),
                                                                                                                                                                 providerOrg == null ? null : CreateProviderOrganization(providerOrg)
                                                                                                                                                                 )
                                                                                                                                                             )
                                                                                                                                                         )
                                                                                                                                                     );

            // Get person data
            var personData = eventRegistration.RegistrationEvent.Subject1.registeredRole.PatientEntityChoiceSubject as Everest.RMIM.UV.NE2008.PRPA_MT201303UV02.Person;

            personData.AsOtherIDs.Clear();
            retVal.controlActProcess.Subject.Add(eventRegistration);

            // TODO: Replacement of compatibility mode for other XDS registries
            // Replacement
            var registration = this.Context.GetService(typeof(IDataRegistrationService)) as IDataRegistrationService;
            var persistence  = this.Context.GetService(typeof(IDataPersistenceService)) as IDataPersistenceService;

            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 patientQuery           = new QueryEvent();
                RegistrationEvent regEvent = new RegistrationEvent()
                {
                };
                patientQuery.Add(regEvent, "SUBJ", SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf, null);
                patientQuery.Add(qp, "FLT", SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.FilterOf, null);
                regEvent.Add(new Person()
                {
                    AlternateIdentifiers = rplc.AlternateIdentifiers
                }, "SUBJ", SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf, null);
                // Perform the query
                var pid = registration.QueryRecord(patientQuery);
                if (pid.Length == 0)
                {
                    throw new InvalidOperationException();
                }
                var replacedPerson = (persistence.GetContainer(pid[0], true) as RegistrationEvent).FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf) as Person;

                var ids = CreateIISet(replacedPerson.AlternateIdentifiers.FindAll(o => configuration.NotificationDomain.Exists(d => d.Domain == o.Domain)));
                if (ids.Count == 0)
                {
                    ; // TODO: Trace log
                }
                else
                {
                    eventRegistration.RegistrationEvent.ReplacementOf.Add(new Everest.RMIM.UV.NE2008.MFMI_MT700701UV01.ReplacementOf(
                                                                              new Everest.RMIM.UV.NE2008.MFMI_MT700701UV01.PriorRegistration(
                                                                                  null,
                                                                                  ActStatus.Obsolete,
                                                                                  new Everest.RMIM.UV.NE2008.MFMI_MT700701UV01.Subject3(
                                                                                      new Everest.RMIM.UV.NE2008.MFMI_MT700701UV01.PriorRegisteredRole(
                                                                                          ids
                                                                                          )
                                                                                      ),
                                                                                  null
                                                                                  )
                                                                              ));
                }
            }

            if (eventRegistration.RegistrationEvent.ReplacementOf.Count == 0)
            {
                throw new InvalidOperationException("Nothing to do");
            }

            // Custodian?
            eventRegistration.RegistrationEvent.Custodian = CreateCustodian(registrationEvent, configuration);

            return(retVal);
        }
예제 #9
0
        /// <summary>
        /// De-persist the specified data
        /// </summary>
        public System.ComponentModel.IComponent DePersist(IDbConnection conn, decimal identifier, IContainer container, HealthServiceRecordSiteRoleType?roleType, bool loadFast)
        {
            // TODO: Ensure that when a parent with context conduction exists, to grab contextual data (authors, etc...) from the parent
            RegistrationEvent retVal = new RegistrationEvent();

            // Configuration service
            ISystemConfigurationService configService = ApplicationContext.ConfigurationService; //ApplicationContext.Current.GetService(typeof(ISystemConfigurationService)) as ISystemConfigurationService;

            // Get the health service event
            IDbCommand cmd = DbUtil.CreateCommandStoredProc(conn, null);

            try
            {
                cmd.CommandText = "get_hsr_crnt_vrsn";
                cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "hsr_id_in", DbType.Decimal, identifier));

                decimal tsId          = default(decimal),
                        cdId          = default(decimal),
                        rplcVersionId = default(decimal);

                // Read data
                IDataReader reader = cmd.ExecuteReader();
                try
                {
                    if (!reader.Read())
                    {
                        return(null);
                    }

                    retVal.Id = Convert.ToDecimal(reader["hsr_id"]);
                    retVal.VersionIdentifier   = Convert.ToDecimal(reader["hsr_vrsn_id"]);
                    retVal.AlternateIdentifier = new VersionedDomainIdentifier()
                    {
                        Domain     = configService.OidRegistrar.GetOid(ClientRegistryOids.REGISTRATION_EVENT).Oid,
                        Identifier = retVal.Id.ToString(),
                        Version    = retVal.VersionIdentifier.ToString(),
                    };
                    retVal.EventClassifier = (RegistrationEventType)Convert.ToDecimal(reader["hsr_cls"]);
                    retVal.Refuted         = Convert.ToBoolean(reader["refuted_ind"]);
                    retVal.Timestamp       = DateTime.Parse(Convert.ToString(reader["aut_utc"]));
                    retVal.Status          = (StatusType)Convert.ToDecimal(reader["status_cs_id"]);
                    tsId                = Convert.ToDecimal(reader["efft_ts_set_id"]);
                    cdId                = Convert.ToDecimal(reader["evt_typ_cd_id"]);
                    rplcVersionId       = reader["rplc_vrsn_id"] == DBNull.Value ? default(decimal) : Convert.ToDecimal(reader["rplc_vrsn_id"]);
                    retVal.LanguageCode = Convert.ToString(reader["lang_cs"]);
                }
                finally
                {
                    reader.Close();
                }

                // Read codes and times
                retVal.EventType     = DbUtil.GetCodedValue(conn, null, cdId);
                retVal.EffectiveTime = DbUtil.GetEffectiveTimestampSet(conn, null, tsId);

                if (container != null)
                {
                    container.Add(retVal);
                }

                // De-persist older versions
                if (!loadFast && rplcVersionId != default(decimal))
                {
                    var oldVersion = DePersist(conn, identifier, rplcVersionId, retVal, HealthServiceRecordSiteRoleType.OlderVersionOf, loadFast);
                    if (oldVersion != null)
                    {
                        (oldVersion.Site as HealthServiceRecordSite).SiteRoleType = HealthServiceRecordSiteRoleType.OlderVersionOf;
                        retVal.Add(oldVersion);
                    }
                }

                if (roleType.HasValue && (roleType.Value & HealthServiceRecordSiteRoleType.ReplacementOf) == HealthServiceRecordSiteRoleType.ReplacementOf)
                {
                    ;
                }
                else
                {
                    DbUtil.DePersistComponents(conn, retVal, this, loadFast);
                }
            }
            finally
            {
                cmd.Dispose();
            }

            return(retVal);
        }
예제 #10
0
        /// <summary>
        /// Update container
        /// </summary>
        public VersionedDomainIdentifier UpdateContainer(System.ComponentModel.IContainer storageData, DataPersistenceMode mode)
        {
            if (m_disposed)
            {
                throw new ObjectDisposedException("DatabasePersistenceService");
            }

            if (storageData == null)
            {
                throw new ArgumentNullException("storageData");
            }

            // Get the persister
            IComponentPersister         persister     = GetPersister(storageData.GetType());
            ISystemConfigurationService configService = ApplicationContext.ConfigurationService;

            if (persister != null)
            {
                IDbTransaction tx   = null;
                IDbConnection  conn = null;
                try
                {
                    conn = DatabasePersistenceService.ConnectionManager.GetConnection();

                    RegistrationEvent hsrEvent = storageData as RegistrationEvent;

                    // Is the record something that we have access to?
                    if (hsrEvent.AlternateIdentifier != null && !hsrEvent.AlternateIdentifier.Domain.Equals(configService.OidRegistrar.GetOid(ClientRegistryOids.REGISTRATION_EVENT).Oid))
                    {
                        throw new ArgumentException(String.Format("The record OID '{0}' cannot be retrieved by this repository, expecting OID '{1}'",
                                                                  hsrEvent.AlternateIdentifier.Domain, configService.OidRegistrar.GetOid(ClientRegistryOids.REGISTRATION_EVENT).Oid));
                    }

                    decimal tryDec         = default(decimal);
                    bool    isDirectUpdate = false;

                    // Is there no event identifier ?
                    if (hsrEvent.AlternateIdentifier != null && !Decimal.TryParse(hsrEvent.AlternateIdentifier.Identifier, out tryDec))
                    {
                        throw new ArgumentException(String.Format("The identifier '{0}' is not a valid identifier for this repository", hsrEvent.AlternateIdentifier.Identifier));
                    }
                    else if (hsrEvent.AlternateIdentifier == null) // The alternate identifier is null ... so we need to look up the registration event to version ... interesting....
                    {
                        this.EnrichRegistrationEvent(conn, tx, hsrEvent);
                    }
                    else
                    {
                        // Get the person name
                        isDirectUpdate = true; // Explicit update
                    }

                    // Validate and duplicate the components that are to be loaded as part of the new version
                    var oldHsrEvent = GetContainer(hsrEvent.AlternateIdentifier, true) as RegistrationEvent; // Get the old container
                    if (oldHsrEvent == null)
                    {
                        throw new MissingPrimaryKeyException(String.Format("Record {1}^^^&{0}&ISO does not exist", hsrEvent.AlternateIdentifier.Domain, hsrEvent.AlternateIdentifier.Identifier));
                    }

                    PersonPersister cp = new PersonPersister();

                    // Validate the old record target
                    Person oldRecordTarget = oldHsrEvent.FindComponent(HealthServiceRecordSiteRoleType.SubjectOf) as Person,
                           newRecordTarget = hsrEvent.FindComponent(HealthServiceRecordSiteRoleType.SubjectOf) as Person;

                    Person verifyRecordTarget = null;
                    if (!isDirectUpdate)
                    {
                        Trace.TraceInformation("Not Direct update, enriching the Patient Data");
                        int idCheck = 0;
                        while (verifyRecordTarget == null || idCheck > newRecordTarget.AlternateIdentifiers.Count)
                        {
                            verifyRecordTarget = cp.GetPerson(conn, null, newRecordTarget.AlternateIdentifiers[idCheck++], true);
                        }

                        if (verifyRecordTarget == null || oldRecordTarget.Id != verifyRecordTarget.Id)
                        {
                            throw new ConstraintException("The update request specifies a different subject than the request currently stored");
                        }
                    }
                    else
                    {
                        verifyRecordTarget = oldRecordTarget;
                    }
                    //newRecordTarget.VersionId = verifyRecordTarget.VersionId;
                    newRecordTarget.Id = verifyRecordTarget.Id;

                    // VAlidate classific
                    if (oldHsrEvent.EventClassifier != hsrEvent.EventClassifier &&
                        (hsrEvent.EventClassifier & RegistrationEventType.Register) == RegistrationEventType.None)
                    {
                        throw new ConstraintException("Record type mis-match between update data and the data already in the persistence store");
                    }

                    if (oldHsrEvent.LanguageCode != hsrEvent.LanguageCode)
                    {
                        throw new ConstraintException("Record language mis-match between update data and data already in persistence store. To change the language use a \"replaces\" relationship rather than an update");
                    }

                    // Are we performing a component update? If so the only two components we want freshened are the CommentOn (for adding comments)
                    // and the ReasonFor | OlderVersionOf comment for change summaries
                    if ((hsrEvent.EventClassifier & RegistrationEventType.ComponentEvent) != 0)
                    {
                        for (int i = hsrEvent.XmlComponents.Count - 1; i >= 0; i--)
                        {
                            if (((hsrEvent.XmlComponents[i].Site as HealthServiceRecordSite).SiteRoleType & (HealthServiceRecordSiteRoleType.CommentOn | HealthServiceRecordSiteRoleType.ReasonFor | HealthServiceRecordSiteRoleType.OlderVersionOf | HealthServiceRecordSiteRoleType.TargetOf)) == 0)
                            {
                                hsrEvent.Remove(hsrEvent.XmlComponents[i]);
                            }
                        }
                    }

                    // Copy over any components that aren't already specified or updated in the new record
                    // Merge the old and new. Sets the update mode appropriately
                    cp.MergePersons(newRecordTarget, oldRecordTarget);

                    // Next we copy this as a replacement of
                    hsrEvent.RemoveAllFromRole(HealthServiceRecordSiteRoleType.SubjectOf);
                    hsrEvent.Add(newRecordTarget, "SUBJ", HealthServiceRecordSiteRoleType.SubjectOf, null);

                    // Begin and update
                    tx = conn.BeginTransaction();

                    var retVal = persister.Persist(conn, tx, storageData as IComponent, true);

                    if (m_configuration.OverridePersistenceMode.HasValue)
                    {
                        mode = m_configuration.OverridePersistenceMode.Value;
                    }

                    if (mode == DataPersistenceMode.Production)
                    {
                        tx.Commit();
                        tx = null;

                        // Mark conflicts if any are outstanding pointing at the old versionj
                        if (this.m_clientRegistryMerge != null)
                        {
                            var existingConflicts = this.m_clientRegistryMerge.GetConflicts(oldHsrEvent.AlternateIdentifier);
                            if (existingConflicts.Count() > 0)
                            {
                                Trace.TraceInformation("Obsoleting existing conlflicts resolved");
                                this.m_clientRegistryMerge.ObsoleteConflicts(oldHsrEvent.AlternateIdentifier);
                            }
                            this.m_threadPool.QueueUserWorkItem(this.MarkConflictsAsync, retVal);
                        }

                        // Notify register
                        if (this.m_notificationService != null)
                        {
                            if (hsrEvent.Mode == RegistrationEventType.Replace)
                            {
                                this.m_notificationService.NotifyDuplicatesResolved(hsrEvent);
                            }
                            else
                            {
                                this.m_notificationService.NotifyUpdate(hsrEvent);
                            }
                        }
                    }
                    else
                    {
                        tx.Rollback();
                    }


                    return(retVal);
                }
                catch (Exception e)
                {
                    if (tx != null)
                    {
                        tx.Rollback();
                    }
                    throw;
                }
                finally
                {
                    if (tx != null)
                    {
                        tx.Dispose();
                    }
                    if (conn != null)
                    {
                        DatabasePersistenceService.ConnectionManager.ReleaseConnection(conn);
                        conn = null;
                    }
                }
            }
            else
            {
                Trace.TraceError("Can't find a persistence handler for type '{0}'", storageData.GetType().Name);
                throw new DataException(String.Format("Can't persist type '{0}'", storageData.GetType().Name));
            }
        }
        /// <summary>
        /// De-persist
        /// </summary>
        public System.ComponentModel.IComponent DePersist(System.Data.IDbConnection conn, decimal identifier, IContainer container, HealthServiceRecordSiteRoleType?roleType, bool loadFast)
        {
            HealthcareParticipant retVal = new HealthcareParticipant();

            IDbCommand cmd = DbUtil.CreateCommandStoredProc(conn, null);

            try
            {
                // Determine the container
                RegistrationEvent hsrParent = container as RegistrationEvent;

                retVal = GetProvider(conn, null, new DomainIdentifier()
                {
                    Identifier = identifier.ToString()
                });

                // Data reader
                if (hsrParent != null)
                {
                    cmd.CommandText = "get_hsr_ptcpt";
                    cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "hsr_id_in", DbType.Decimal, hsrParent.Id));
                    //cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "vrsn_id_in", DbType.Decimal, hsrParent.VersionIdentifier));
                    cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "ptcpt_id_in", DbType.Decimal, identifier));
                    cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "ptcpt_cls_in", DbType.Decimal, (decimal)roleType.Value));

                    // Role
                    Decimal repOrgId = default(decimal);
                    List <DomainIdentifier> originalIds = new List <DomainIdentifier>();

                    // Execute a reader
                    IDataReader reader = cmd.ExecuteReader();
                    try
                    {
                        // Read a row
                        while (reader.Read())
                        {
                            repOrgId = reader["ptcpt_rep_org_id"] == DBNull.Value ? default(decimal) : Convert.ToDecimal(reader["ptcpt_rep_org_id"]);
                            originalIds.Add(new DomainIdentifier()
                            {
                                Domain             = Convert.ToString(reader["orig_id_domain"]),
                                Identifier         = Convert.ToString(reader["orig_id"]),
                                IsLicenseAuthority = Convert.ToBoolean(reader["license_ind"])
                            });
                        }
                    }
                    finally
                    {
                        reader.Close();
                    }

                    // Representative of
                    if (repOrgId != default(decimal))
                    {
                        retVal.Add(GetProvider(conn, null, new DomainIdentifier()
                        {
                            Identifier = repOrgId.ToString()
                        }), "REPOF", HealthServiceRecordSiteRoleType.RepresentitiveOf, null);
                    }

                    // Add to parent
                    hsrParent.Add(retVal, Guid.NewGuid().ToString(), roleType.Value, originalIds);
                }
                else if (container != null)
                {
                    container.Add(retVal);
                }
            }
            finally
            {
                cmd.Dispose();
            }

            // TODO: Get original identifiers for this link

            return(retVal);
        }