/// <summary>
        /// Update conflict records
        /// </summary>
        /// <param name="oldIdentifier">The old HSR event id</param>
        /// <param name="recordId">The new HSR event id</param>
        public void ObsoleteConflicts(VersionedDomainIdentifier recordId)
        {
            // First, we load the survivor
            if (recordId.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), "recordId");
            }

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

            try
            {
                using (IDbCommand cmd = DbUtil.CreateCommandStoredProc(conn, null))
                {
                    cmd.CommandText = "obslt_mrg";
                    cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "old_hsr_id_in", DbType.Decimal, Decimal.Parse(recordId.Identifier)));
                    cmd.ExecuteNonQuery();
                }
            }
            finally
            {
                DatabasePersistenceService.ConnectionManager.ReleaseConnection(conn);
            }
        }
Exemple #2
0
        /// <summary>
        /// Create an HSR record
        /// </summary>
        private VersionedDomainIdentifier CreateHSRRecord(IDbConnection conn, IDbTransaction tx, ChangeSummary hsr)
        {
            IDbCommand cmd = DbUtil.CreateCommandStoredProc(conn, tx);

            cmd.CommandText = "crt_hsr";

            // Get the terminology service
            ISystemConfigurationService iscs = ApplicationContext.ConfigurationService; //ApplicationContext.Current.GetService(typeof(ISystemConfigurationService)) as ISystemConfigurationService;

            // Parameters
            // classifier = 0x400 = Change Summary
            cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "hsr_cls_in", DbType.Decimal, RegistrationEventType.ComponentEvent | RegistrationEventType.Revise));
            // event type code
            cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "evt_typ_cd_id_in", DbType.Decimal, DbUtil.CreateCodedValue(conn, tx, hsr.ChangeType)));
            // refuted indicator
            cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "refuted_ind_in", DbType.Boolean, false));

            decimal?efftTimeId = null;

            if (hsr.EffectiveTime != null)
            {
                efftTimeId = DbUtil.CreateTimeset(conn, tx, hsr.EffectiveTime);
            }

            cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "efft_ts_set_id_in", DbType.Decimal, efftTimeId == null ? (object)DBNull.Value : efftTimeId.Value));
            // status code
            cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "status_cs_in", DbType.Decimal, hsr.Status == null ? (object)DBNull.Value : (int)hsr.Status));
            // authored time
            cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "aut_utc_in", DbType.DateTime, hsr.Timestamp == default(DateTime) ? (object)DBNull.Value : hsr.Timestamp));
            // language code
            cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "lang_cs_in", DbType.String, hsr.LanguageCode));

            // Execute the command
            IDataReader resultRdr = cmd.ExecuteReader();

            try
            {
                // Create the return value
                VersionedDomainIdentifier id = new VersionedDomainIdentifier();
                if (!resultRdr.Read())
                {
                    return(null);
                }

                id.Version    = Convert.ToString(resultRdr["VRSN_ID"]);
                id.Identifier = Convert.ToString(resultRdr["ID"]);
                id.Domain     = iscs.OidRegistrar.GetOid(ClientRegistryOids.EVENT_OID).Oid;

                return(id);
            }
            finally
            {
                resultRdr.Close();
            }
        }
        /// <summary>
        /// Resolve an item
        /// </summary>
        /// <param name="sourceId"></param>
        public void Resolve(decimal sourceId)
        {
            // Get all Services
            IAuditorService             auditSvc = ApplicationContext.CurrentContext.GetService(typeof(IAuditorService)) as IAuditorService;
            IClientRegistryMergeService mergeSvc = ApplicationContext.CurrentContext.GetService(typeof(IClientRegistryMergeService)) as IClientRegistryMergeService;

            // Audit message
            AuditData auditMessage = this.ConstructAuditData(ActionType.Update, EventIdentifierType.ApplicationActivity);

            auditMessage.EventTypeCode = new CodeValue("ADM_Resolve");
            try
            {
                // Prepare merge
                VersionedDomainIdentifier resolveId = new VersionedDomainIdentifier()
                {
                    Domain     = ApplicationContext.ConfigurationService.OidRegistrar.GetOid("REG_EVT").Oid,
                    Identifier = sourceId.ToString()
                };

                // Merge
                mergeSvc.MarkResolved(resolveId);


                auditMessage.AuditableObjects.Add(new AuditableObject()
                {
                    IDTypeCode    = AuditableObjectIdType.ReportNumber,
                    LifecycleType = AuditableObjectLifecycle.Verification,
                    ObjectId      = string.Format("{0}^^^&{1}&ISO", resolveId.Identifier, resolveId.Domain),
                    Role          = AuditableObjectRole.Job,
                    Type          = AuditableObjectType.SystemObject
                });
            }
            catch (Exception e)
            {
                auditMessage.Outcome = OutcomeIndicator.EpicFail;
                Trace.TraceError("Could not execute Merge : {0}", e.ToString());
#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(auditMessage);
                }
            }
        }
Exemple #4
0
        /// <summary>
        /// Aync mark conflicts code
        /// </summary>
        private void MarkConflictsAsync(object state)
        {
            Trace.TraceInformation("Performing fuzzy conflict check asynchronously");
            try
            {
                VersionedDomainIdentifier vid      = state as VersionedDomainIdentifier;
                RegistrationEvent         hsrEvent = this.GetContainer(vid, true) as RegistrationEvent;
                var pid = this.m_clientRegistryMerge.FindFuzzyConflicts(hsrEvent);

                Trace.TraceInformation("Post-Update Record matched with {0} records", pid.Count());
                if (pid.Count() > 0)
                {
                    this.m_clientRegistryMerge.MarkConflicts(hsrEvent.AlternateIdentifier, pid);
                }
            }
            catch (Exception e)
            {
                Trace.TraceError(e.ToString());
            }
        }
        /// <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);
        }
        /// <summary>
        /// Perform a merge
        /// </summary>
        public Core.ComponentModel.RegistrationEvent Merge(decimal[] sourceIds, decimal targetId)
        {
            // Get all Services
            IAuditorService             auditSvc = ApplicationContext.CurrentContext.GetService(typeof(IAuditorService)) as IAuditorService;
            IDataPersistenceService     repSvc   = ApplicationContext.CurrentContext.GetService(typeof(IDataPersistenceService)) as IDataPersistenceService;
            IClientRegistryMergeService mergeSvc = ApplicationContext.CurrentContext.GetService(typeof(IClientRegistryMergeService)) as IClientRegistryMergeService;

            // Audit message
            List <AuditData> auditMessages = new List <AuditData>();

            try
            {
                // Prepare merge
                List <VersionedDomainIdentifier> domainId = new List <VersionedDomainIdentifier>(sourceIds.Length);
                foreach (var srcId in sourceIds)
                {
                    domainId.Add(new VersionedDomainIdentifier()
                    {
                        Domain     = ApplicationContext.ConfigurationService.OidRegistrar.GetOid("REG_EVT").Oid,
                        Identifier = srcId.ToString()
                    });

                    var am = ConstructAuditData(ActionType.Delete, EventIdentifierType.Import);
                    am.EventTypeCode = new CodeValue("ADM_Merge");
                    am.AuditableObjects.Add(new AuditableObject()
                    {
                        IDTypeCode    = AuditableObjectIdType.ReportNumber,
                        LifecycleType = AuditableObjectLifecycle.LogicalDeletion,
                        ObjectId      = String.Format("{0}^^^&{1}&ISO", srcId, ApplicationContext.ConfigurationService.OidRegistrar.GetOid("REG_EVT").Oid),
                        Role          = AuditableObjectRole.MasterFile,
                        Type          = AuditableObjectType.SystemObject
                    });
                    auditMessages.Add(am);
                }
                VersionedDomainIdentifier survivorId = new VersionedDomainIdentifier()
                {
                    Domain     = ApplicationContext.ConfigurationService.OidRegistrar.GetOid("REG_EVT").Oid,
                    Identifier = targetId.ToString()
                };
                var updateAudit = ConstructAuditData(ActionType.Update, EventIdentifierType.Import);
                updateAudit.EventTypeCode = new CodeValue("ADM_Merge");
                updateAudit.AuditableObjects.Add(new AuditableObject()
                {
                    IDTypeCode    = AuditableObjectIdType.ReportNumber,
                    LifecycleType = AuditableObjectLifecycle.Amendment,
                    ObjectId      = String.Format("{0}^^^&{1}&ISO", survivorId.Identifier, survivorId.Domain),
                    Role          = AuditableObjectRole.MasterFile,
                    Type          = AuditableObjectType.SystemObject
                });
                auditMessages.Add(updateAudit);

                // Merge
                mergeSvc.Resolve(domainId, survivorId, DataPersistenceMode.Production);

                // Now load
                return(repSvc.GetContainer(survivorId, true) as RegistrationEvent);
            }
            catch (Exception e)
            {
                foreach (var am in auditMessages)
                {
                    am.Outcome = OutcomeIndicator.EpicFail;
                }
                Trace.TraceError("Could not execute Merge : {0}", e.ToString());
#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)
                {
                    foreach (var am in auditMessages)
                    {
                        auditSvc.SendAudit(am);
                    }
                }
            }
        }
        /// <summary>
        /// Get a specific conflict
        /// </summary>
        public ConflictCollection GetConflict(decimal id)
        {
            // Get all Services
            IAuditorService             auditSvc = ApplicationContext.CurrentContext.GetService(typeof(IAuditorService)) as IAuditorService;
            IDataPersistenceService     repSvc   = ApplicationContext.CurrentContext.GetService(typeof(IDataPersistenceService)) as IDataPersistenceService;
            IClientRegistryMergeService mergeSvc = ApplicationContext.CurrentContext.GetService(typeof(IClientRegistryMergeService)) as IClientRegistryMergeService;

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

            audit.EventTypeCode = new CodeValue("ADM_GetConflict");
            try
            {
                var vid = new VersionedDomainIdentifier()
                {
                    Domain     = ApplicationContext.ConfigurationService.OidRegistrar.GetOid("REG_EVT").Oid,
                    Identifier = id.ToString()
                };

                // Get all with a merge
                var mergeResults = mergeSvc.GetConflicts(vid);

                var retVal = new ConflictCollection();
                // Construct the return, and load match
                var conf = new Conflict()
                {
                    Source = repSvc.GetContainer(vid, true) as RegistrationEvent
                };

                // Add audit data
                audit.AuditableObjects.Add(new AuditableObject()
                {
                    IDTypeCode    = AuditableObjectIdType.ReportNumber,
                    LifecycleType = AuditableObjectLifecycle.Export,
                    ObjectId      = String.Format("{0}^^^&{1}&ISO", conf.Source.AlternateIdentifier.Identifier, conf.Source.AlternateIdentifier.Domain),
                    Role          = AuditableObjectRole.MasterFile,
                    Type          = AuditableObjectType.SystemObject,
                    QueryData     = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes("loadFast=false"))
                });

                // Load the matches
                foreach (var match in mergeResults)
                {
                    var matchRecord = repSvc.GetContainer(match, true) as RegistrationEvent;
                    conf.Match.Add(matchRecord);
                    // Add audit data
                    audit.AuditableObjects.Add(new AuditableObject()
                    {
                        IDTypeCode    = AuditableObjectIdType.ReportNumber,
                        LifecycleType = AuditableObjectLifecycle.Export,
                        ObjectId      = String.Format("{0}^^^&{1}&ISO", matchRecord.AlternateIdentifier.Identifier, matchRecord.AlternateIdentifier.Domain),
                        Role          = AuditableObjectRole.MasterFile,
                        Type          = AuditableObjectType.SystemObject,
                        QueryData     = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes("loadFast=false"))
                    });
                }

                retVal.Conflict.Add(conf);

                return(retVal);
            }
            catch (Exception e)
            {
                Trace.TraceError("Could not execute GetConflicts : {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);
                }
            }
        }
Exemple #8
0
        /// <summary>
        /// Create the HSR record
        /// </summary>
        internal VersionedDomainIdentifier CreateHSRRecord(IDbConnection conn, IDbTransaction tx, RegistrationEvent hsr)
        {
            IDbCommand cmd = DbUtil.CreateCommandStoredProc(conn, tx);

            cmd.CommandText = "crt_hsr";

            // Get the terminology service
            //ITerminologyService its = ApplicationContext.CurrentContext.GetService(typeof(ITerminologyService)) as ITerminologyService;
            ISystemConfigurationService iscs = ApplicationContext.ConfigurationService; //ApplicationContext.Current.GetService(typeof(ISystemConfigurationService)) as ISystemConfigurationService;

            // Validate the language code
            //if (its != null)
            //{
            //    var validationError = its.Validate(hsr.LanguageCode, null, CodeSystemName.ISO639);
            //    if (validationError.Outcome != MARC.HI.EHRS.SVC.Core.Terminology.ValidationOutcome.ValidWithWarning &&
            //        validationError.Outcome != MARC.HI.EHRS.SVC.Core.Terminology.ValidationOutcome.Valid)
            //        throw new ConstraintException("Language MUST be a valid ISO639 Country code in the format XX-XX");
            //}

            // Parameters
            // classifier
            cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "hsr_cls_in", DbType.Decimal, (int)hsr.EventClassifier));
            // event type code
            cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "evt_typ_cd_id_in", DbType.Decimal, DbUtil.CreateCodedValue(conn, tx, hsr.EventType)));
            // refuted indicator
            cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "refuted_ind_in", DbType.Boolean, hsr.Refuted));

            decimal?efftTimeId = null;

            if (hsr.EffectiveTime != null)
            {
                efftTimeId = DbUtil.CreateTimeset(conn, tx, hsr.EffectiveTime);
            }

            cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "efft_ts_set_id_in", DbType.Decimal, efftTimeId == null ? (object)DBNull.Value : efftTimeId.Value));
            // status code
            cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "status_cs_in", DbType.Decimal, hsr.Status == null ? (object)DBNull.Value : (int)hsr.Status));
            // authored time
            cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "aut_utc_in", DbType.DateTime, hsr.Timestamp == default(DateTime) ? (object)DBNull.Value : hsr.Timestamp));
            // language code
            cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "lang_cs_in", DbType.String, hsr.LanguageCode));

            // Execute the command
            IDataReader resultRdr = cmd.ExecuteReader();

            try
            {
                // Create the return value
                VersionedDomainIdentifier id = new VersionedDomainIdentifier();
                if (!resultRdr.Read())
                {
                    return(null);
                }

                id.Version    = Convert.ToString(resultRdr["VRSN_ID"]);
                id.Identifier = Convert.ToString(resultRdr["ID"]);
                id.Domain     = iscs.OidRegistrar.GetOid(ClientRegistryOids.REGISTRATION_EVENT).Oid;

                return(id);
            }
            finally
            {
                resultRdr.Close();
            }
        }
        /// <summary>
        /// Get record
        /// </summary>
        private HealthServiceRecordContainer GetRecord(VersionedDomainIdentifier recordId, List <IResultDetail> dtls, RegistryQueryRequest qd)
        {
            try
            {
                // Can't find persistence
                if (this.m_persistenceService == null)
                {
                    dtls.Add(new PersistenceResultDetail(ResultDetailType.Error, "Couldn't locate an implementation of a PersistenceService object, storage is aborted", null));
                    throw new Exception("Cannot de-persist records");
                }


                // Read the record from the DB
                var result = this.m_persistenceService.GetContainer(recordId, qd.IsSummary) as HealthServiceRecordContainer;

                // Does this result match what we're looking for?
                if (result == null)
                {
                    return(null); // next record
                }
                // Calculate the matching algorithm
                Person subject;
                if (result is Person)
                {
                    subject = result as Person;
                }
                else
                {
                    subject = result.FindComponent(HealthServiceRecordSiteRoleType.SubjectOf) as Person;
                }

                // Remove all but the alternate identifiers specifed in the query
                if (qd.TargetDomain != null && subject != null)
                {
                    subject.AlternateIdentifiers.RemoveAll(o => !qd.TargetDomain.Exists(t => t.Domain.Equals(o.Domain)));
                    if (subject.AlternateIdentifiers.Count == 0)
                    {
                        return(null);
                    }
                }

                if (subject != null && qd.QueryRequest != null)
                {
                    var filter = qd.QueryRequest.FindComponent(HealthServiceRecordSiteRoleType.SubjectOf);
                    while (!(filter is Person) && filter != null)
                    {
                        filter = (filter as HealthServiceRecordContainer).FindComponent(HealthServiceRecordSiteRoleType.SubjectOf);
                    }

                    var confidence = (subject as Person).Confidence(filter as Person);

                    if (confidence.Confidence < qd.MinimumDegreeMatch)
                    {
                        return(null);
                    }

                    subject.Add(confidence, "CONF", HealthServiceRecordSiteRoleType.ComponentOf | HealthServiceRecordSiteRoleType.CommentOn, null);
                }

                // Mask
                if (this.m_policyService != null)
                {
                    var dte = new List <SVC.Core.Issues.DetectedIssue>();
                    result = this.m_policyService.ApplyPolicies(qd.QueryRequest, result, dte) as HealthServiceRecordContainer;
                    foreach (var itm in dte)
                    {
                        dtls.Add(new DetectedIssueResultDetail(
                                     ResultDetailType.Warning,
                                     itm.Text,
                                     (string)null,
                                     itm));
                    }
                }

                return(result);
            }
            catch (Exception ex)
            {
                dtls.Add(new PersistenceResultDetail(ResultDetailType.Error, ex.Message, ex));
                return(null);
            }
        }