Exemple #1
0
        /// <summary>
        /// Persist the person relationship
        /// </summary>
        public SVC.Core.DataTypes.VersionedDomainIdentifier Persist(System.Data.IDbConnection conn, System.Data.IDbTransaction tx, System.ComponentModel.IComponent data, bool isUpdate)
        {
            // Is this a replacement
            var pp = new PersonPersister();
            PersonRegistrationRef refr = data as PersonRegistrationRef;
            Person psn     = pp.GetPerson(conn, tx, refr.AlternateIdentifiers[0], true);
            Person cntrPsn = data.Site.Container as Person;

            if (psn == null || cntrPsn == null)
            {
                throw new ConstraintException(ApplicationContext.LocaleService.GetString("DBCF00B"));
            }
            else if (psn.Id == cntrPsn.Id)
            {
                throw new ConstraintException(ApplicationContext.LocaleService.GetString("DBCF00D"));
            }

            // Load the container person from DB so we get all data
            Person dbCntrPsn = pp.GetPerson(conn, tx, new SVC.Core.DataTypes.DomainIdentifier()
            {
                Domain     = ApplicationContext.ConfigurationService.OidRegistrar.GetOid(ClientRegistryOids.CLIENT_CRID).Oid,
                Identifier = cntrPsn.Id.ToString()
            }, true);

            pp.MergePersons(dbCntrPsn, cntrPsn);

            // Load the components for the person
#if DEBUG
            Trace.TraceInformation("Registration reference {0} > {1}", psn.Id, dbCntrPsn.Id);
#endif
            DbUtil.DePersistComponents(conn, psn, this, true);

            if (psn == null || dbCntrPsn == null)
            {
                throw new ConstraintException(ApplicationContext.LocaleService.GetString("DBCF00B"));
            }
            dbCntrPsn.Site = (data.Site.Container as IComponent).Site;

            var role     = (refr.Site as HealthServiceRecordSite).SiteRoleType;
            var symbolic = (refr.Site as HealthServiceRecordSite).IsSymbolic; // If true, the replacement does not cascade and is a symbolic replacement of only the identifiers listed

            // Replacement?
            if (role == HealthServiceRecordSiteRoleType.ReplacementOf)
            {
                // First, we obsolete all records with the existing person
                foreach (var id in psn.AlternateIdentifiers.FindAll(o => refr.AlternateIdentifiers.Exists(a => a.Domain == o.Domain)))
                {
                    id.UpdateMode = SVC.Core.DataTypes.UpdateModeType.Remove;
                }
                //psn.AlternateIdentifiers.RemoveAll(o => o.UpdateMode != SVC.Core.DataTypes.UpdateModeType.Remove);

                // Not symbolic, means that we do a hard replace
                // Symbolic replace = Just replace the reference to that identifier
                // Hard replace = Merge the new and old record and then replace them
                if (!symbolic)
                {
#if DEBUG
                    Trace.TraceInformation("Performing an administrative migration of identifiers and information from {0} > {1}", psn.Id, dbCntrPsn.Id);
#endif
                    // Now to copy the components of the current version down
                    //foreach (IComponent cmp in refr.Site.Container.Components)
                    //    if (cmp != refr)
                    //        dbCntrPsn.Add((cmp as HealthServiceRecordComponent).Clone() as IComponent);

                    // Merge the two records in memory taking the newer data
                    // This is a merge from old to new in order to capture any data elements
                    // that have been updated in the old that might be newer (or more accurate) than the
                    // the new
                    if (psn.AlternateIdentifiers == null)
                    {
                        dbCntrPsn.AlternateIdentifiers = new List <SVC.Core.DataTypes.DomainIdentifier>();
                    }
                    else if (psn.OtherIdentifiers == null)
                    {
                        dbCntrPsn.OtherIdentifiers = new List <KeyValuePair <SVC.Core.DataTypes.CodeValue, SVC.Core.DataTypes.DomainIdentifier> >();
                    }
                    foreach (var id in psn.AlternateIdentifiers)
                    {
                        // Remove the identifier from the original
                        id.UpdateMode = SVC.Core.DataTypes.UpdateModeType.Remove;

                        // If this is a duplicate id then don't add
                        if (dbCntrPsn.AlternateIdentifiers.Exists(i => i.Domain == id.Domain && i.Identifier == id.Identifier))
                        {
                            continue;
                        }

                        bool isPrivate = false;
                        var  oidData   = ApplicationContext.ConfigurationService.OidRegistrar.FindData(id.Domain);
                        if (oidData != null)
                        {
                            isPrivate = !(oidData.Attributes.Exists(o => o.Key == "IsMergeSurvivor") && Convert.ToBoolean(oidData.Attributes.Find(o => o.Key == "IsMergeSurvivor").Value));
                        }

                        // Add to alternate identifiers
                        dbCntrPsn.AlternateIdentifiers.Add(new SVC.Core.DataTypes.DomainIdentifier()
                        {
                            AssigningAuthority = id.AssigningAuthority,
                            UpdateMode         = SVC.Core.DataTypes.UpdateModeType.AddOrUpdate,
                            IsLicenseAuthority = false,
                            IsPrivate          = isPrivate, // TODO: Make this a configuration flag (cntrPsn.AlternateIdentifiers.Exists(i=>i.Domain == id.Domain)),
                            Identifier         = id.Identifier,
                            Domain             = id.Domain
                        });
                    }
                    foreach (var id in psn.OtherIdentifiers)
                    {
                        // Remove the identifier from the original
                        id.Value.UpdateMode = SVC.Core.DataTypes.UpdateModeType.Remove;

                        // If this is a duplicate id then don't add
                        if (dbCntrPsn.OtherIdentifiers.Exists(i => i.Value.Domain == id.Value.Domain && i.Value.Identifier == id.Value.Identifier))
                        {
                            continue;
                        }

                        // Add to other identifiers
                        var oth = new KeyValuePair <SVC.Core.DataTypes.CodeValue, SVC.Core.DataTypes.DomainIdentifier>(
                            id.Key,
                            new SVC.Core.DataTypes.DomainIdentifier()
                        {
                            AssigningAuthority = id.Value.AssigningAuthority,
                            UpdateMode         = SVC.Core.DataTypes.UpdateModeType.Add,
                            IsLicenseAuthority = false,
                            IsPrivate          = (dbCntrPsn.OtherIdentifiers.Exists(i => i.Value.Domain == id.Value.Domain)),
                            Identifier         = id.Value.Identifier,
                            Domain             = id.Value.Domain
                        });

                        // Copy extensions
                        var extns = psn.FindAllExtensions(o => o.PropertyPath == String.Format("OtherIdentifiers[{0}{1}]", oth.Value.Domain, oth.Value.Identifier));
                        if (extns != null)
                        {
                            foreach (var ex in extns)
                            {
                                if (dbCntrPsn.FindExtension(o => o.PropertyPath == ex.PropertyPath && o.Name == ex.Name) == null)
                                {
                                    dbCntrPsn.Add(ex);
                                }
                            }
                        }
                        dbCntrPsn.OtherIdentifiers.Add(oth);
                    }



                    // Make sure we don't update what we don't need to
                    dbCntrPsn.Addresses        = psn.Addresses = null;
                    dbCntrPsn.Citizenship      = psn.Citizenship = null;
                    dbCntrPsn.Employment       = psn.Employment = null;
                    dbCntrPsn.Language         = psn.Language = null;
                    dbCntrPsn.Names            = psn.Names = null;
                    dbCntrPsn.Race             = psn.Race = null;
                    dbCntrPsn.TelecomAddresses = psn.TelecomAddresses = null;
                    dbCntrPsn.BirthTime        = psn.BirthTime = null;
                    dbCntrPsn.DeceasedTime     = psn.DeceasedTime = null;

                    // Remove the old person from the db
                    psn.Status = SVC.Core.ComponentModel.Components.StatusType.Obsolete; // obsolete the old person
                }
                else // migrate identifiers
                {
                    foreach (var id in refr.AlternateIdentifiers)
                    {
                        bool isPrivate = false;
                        var  oidData   = ApplicationContext.ConfigurationService.OidRegistrar.FindData(id.Domain);
                        if (oidData != null)
                        {
                            isPrivate = !(oidData.Attributes.Exists(o => o.Key == "IsMergeSurvivor") && Convert.ToBoolean(oidData.Attributes.Find(o => o.Key == "IsMergeSurvivor").Value));
                        }

                        dbCntrPsn.AlternateIdentifiers.Add(new SVC.Core.DataTypes.DomainIdentifier()
                        {
                            AssigningAuthority = id.AssigningAuthority,
                            UpdateMode         = SVC.Core.DataTypes.UpdateModeType.AddOrUpdate,
                            IsLicenseAuthority = false,
                            IsPrivate          = isPrivate, // TODO: Make this a configuration flag (cntrPsn.AlternateIdentifiers.Exists(i=>i.Domain == id.Domain)),
                            Identifier         = id.Identifier,
                            Domain             = id.Domain
                        });
                    }

                    // set to ignore
                    if (psn.Names != null)
                    {
                        foreach (var rc in psn.Names)
                        {
                            rc.UpdateMode = SVC.Core.DataTypes.UpdateModeType.Ignore;
                        }
                    }

                    // set to ignore
                    if (psn.Addresses != null)
                    {
                        foreach (var rc in psn.Addresses)
                        {
                            rc.UpdateMode = SVC.Core.DataTypes.UpdateModeType.Ignore;
                        }
                    }

                    // set to ignore
                    if (psn.Race != null)
                    {
                        foreach (var rc in psn.Race)
                        {
                            rc.UpdateMode = SVC.Core.DataTypes.UpdateModeType.Ignore;
                        }
                    }
                }
                // Now update the person
                //psn.Site = refr.Site;
                //pp.Persist(conn, tx, psn, true); // update the person record
#if DEBUG
                Trace.TraceInformation("Step 1 : Prepare update to person #{0}", psn.Id, cntrPsn.Id, !symbolic);
#endif
                var regEvent      = this.GetRegistrationEvent(conn, tx, psn); // get the registration event
                var changeSummary = DbUtil.GetRegistrationEvent(refr).FindComponent(HealthServiceRecordSiteRoleType.ReasonFor | HealthServiceRecordSiteRoleType.OlderVersionOf) as ChangeSummary;
                if (changeSummary != null)
                {
                    regEvent.RemoveAllFromRole(HealthServiceRecordSiteRoleType.ReasonFor | HealthServiceRecordSiteRoleType.OlderVersionOf);
                    regEvent.Add(new ChangeSummary()
                    {
                        ChangeType    = changeSummary.ChangeType,
                        EffectiveTime = changeSummary.EffectiveTime,
                        LanguageCode  = changeSummary.LanguageCode,
                        Status        = changeSummary.Status,
                        Timestamp     = changeSummary.Timestamp
                    }, "CHG", HealthServiceRecordSiteRoleType.ReasonFor | HealthServiceRecordSiteRoleType.OlderVersionOf, null);
                }
                if (!symbolic)
                {
                    regEvent.Status = StatusType.Obsolete; // obsolete
                }
                regEvent.RemoveAllFromRole(HealthServiceRecordSiteRoleType.SubjectOf);
                regEvent.Add(psn, "SUBJ", HealthServiceRecordSiteRoleType.SubjectOf, null);

#if DEBUG
                Trace.TraceInformation("Step 2 : Perform update to person #{0}", psn.Id);
#endif
                new RegistrationEventPersister().Persist(conn, tx, regEvent, true);

                refr.AlternateIdentifiers.Clear();
                refr.AlternateIdentifiers.Add(new SVC.Core.DataTypes.DomainIdentifier()
                {
                    Domain     = ApplicationContext.ConfigurationService.OidRegistrar.GetOid("CR_CID").Oid,
                    Identifier = psn.Id.ToString()
                });

                //pp.CreatePersonVersion(conn, tx, psn);
                //DbUtil.PersistComponents(conn, tx, false, this, psn);

                // Now, we have to prepare an event so that this all makes sense
                // if we de-persist the most recent version (to reflect changes made)
                // Store the merged new record

#if DEBUG
                Trace.TraceInformation("Step 3 : Perform update to person #{0}", dbCntrPsn.Id);
#endif
                pp.CreatePersonVersion(conn, tx, dbCntrPsn);

                // Components
                DbUtil.PersistComponents(conn, tx, false, this, dbCntrPsn);
                // Now update the backreference to up the chain it gets updated
                cntrPsn.VersionId = dbCntrPsn.VersionId;
            }

            // Create the link
#if DEBUG
            Trace.TraceInformation("Creating link between persons {0} > {1}", psn.Id, dbCntrPsn.Id);
#endif
            using (var cmd = DbUtil.CreateCommandStoredProc(conn, tx))
            {
                cmd.CommandText = "crt_psn_lnk";
                cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "psn_id_in", DbType.Decimal, dbCntrPsn.Id));
                cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "psn_vrsn_id_in", DbType.Decimal, dbCntrPsn.VersionId));
                cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "lnk_psn_id_in", DbType.Decimal, psn.Id));
                cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "lnk_cls_in", DbType.Decimal, (decimal)role));
                cmd.Parameters.Add(DbUtil.CreateParameterIn(cmd, "symbolic_in", DbType.Boolean, symbolic));
                cmd.ExecuteNonQuery();
            }

            // Send notification that duplicates were resolved
            //if (symbolic)
            //{
            //    // Send an duplicates resolved message
            //    IClientNotificationService notificationService = ApplicationContext.CurrentContext.GetService(typeof(IClientNotificationService)) as IClientNotificationService;
            //    if (notificationService != null)
            //        notificationService.NotifyDuplicatesResolved(cntrPsn, refr.AlternateIdentifiers[0]);
            //}
            refr.Id = psn.Id;


            // Person identifier
            return(new SVC.Core.DataTypes.VersionedDomainIdentifier()
            {
                Identifier = psn.Id.ToString(),
                Version = psn.VersionId.ToString()
            });
        }
        /// <summary>
        /// Handle the PIX merge request
        /// </summary>
        private IMessage HandlePixMerge(NHapi.Model.V231.Message.ADT_A39 request, Hl7MessageReceivedEventArgs evt)
        {
            // Get config
            var config      = this.Context.GetService(typeof(ISystemConfigurationService)) as ISystemConfigurationService;
            var locale      = this.Context.GetService(typeof(ILocalizationService)) as ILocalizationService;
            var dataService = this.Context.GetService(typeof(IClientRegistryDataService)) as IClientRegistryDataService;

            // Create a details array
            List <IResultDetail> dtls = new List <IResultDetail>();

            // Validate the inbound message
            MessageUtil.Validate((IMessage)request, config, dtls, this.Context);

            IMessage response = null;

            // Control
            if (request == null)
            {
                return(null);
            }

            // Data controller
            //DataUtil dataUtil = new DataUtil() { Context = this.Context };
            AuditUtil auditUtil = new AuditUtil()
            {
                Context = this.Context
            };

            // Construct appropriate audit
            List <AuditData> audit = new List <AuditData>();

            try
            {
                // Create Query Data
                ComponentUtility cu = new ComponentUtility()
                {
                    Context = this.Context
                };
                DeComponentUtility dcu = new DeComponentUtility()
                {
                    Context = this.Context
                };
                var data = cu.CreateComponents(request, dtls);
                if (data == null)
                {
                    throw new InvalidOperationException(locale.GetString("MSGE00A"));
                }

                // Merge
                var result = dataService.Merge(data, request.MSH.ProcessingID.ProcessingID.Value == "P" ? DataPersistenceMode.Production : DataPersistenceMode.Debugging);

                if (result == null || result.VersionId == null)
                {
                    throw new InvalidOperationException(locale.GetString("DTPE001"));
                }

                List <VersionedDomainIdentifier> deletedRecordIds = new List <VersionedDomainIdentifier>(),
                                                 updatedRecordIds = new List <VersionedDomainIdentifier>();

                // Subjects
                var oidData = config.OidRegistrar.GetOid("CR_CID").Oid;
                foreach (Person subj in data.FindAllComponents(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf))
                {
                    PersonRegistrationRef replcd = subj.FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.ReplacementOf) as PersonRegistrationRef;
                    deletedRecordIds.Add(new VersionedDomainIdentifier()
                    {
                        Identifier = replcd.Id.ToString(),
                        Domain     = oidData
                    });
                    updatedRecordIds.Add(new VersionedDomainIdentifier()
                    {
                        Identifier = subj.Id.ToString(),
                        Domain     = oidData
                    });
                }

                // Now audit
                audit.Add(auditUtil.CreateAuditData("ITI-8", ActionType.Delete, OutcomeIndicator.Success, evt, deletedRecordIds));
                audit.Add(auditUtil.CreateAuditData("ITI-8", ActionType.Update, OutcomeIndicator.Success, evt, updatedRecordIds));
                // Now process the result
                response = MessageUtil.CreateNack(request, dtls, this.Context, typeof(NHapi.Model.V231.Message.ACK));
                MessageUtil.UpdateMSH(new NHapi.Base.Util.Terser(response), request, config);
                (response as NHapi.Model.V231.Message.ACK).MSH.MessageType.TriggerEvent.Value = request.MSH.MessageType.TriggerEvent.Value;
                (response as NHapi.Model.V231.Message.ACK).MSH.MessageType.MessageType.Value  = "ACK";
            }
            catch (Exception e)
            {
                Trace.TraceError(e.ToString());
                if (!dtls.Exists(o => o.Message == e.Message || o.Exception == e))
                {
                    dtls.Add(new ResultDetail(ResultDetailType.Error, e.Message, e));
                }
                response = MessageUtil.CreateNack(request, dtls, this.Context, typeof(NHapi.Model.V231.Message.ACK));
                audit.Add(auditUtil.CreateAuditData("ITI-8", ActionType.Delete, OutcomeIndicator.EpicFail, evt, new List <VersionedDomainIdentifier>()));
            }
            finally
            {
                IAuditorService auditSvc = this.Context.GetService(typeof(IAuditorService)) as IAuditorService;
                if (auditSvc != null)
                {
                    foreach (var aud in audit)
                    {
                        auditSvc.SendAudit(aud);
                    }
                }
            }
            return(response);
        }