예제 #1
0
        /// <summary>
        /// Maps a FHIR patient resource to an HDSI patient.
        /// </summary>
        /// <param name="resource">The resource.</param>
        /// <returns>Returns the mapped model.</returns>
        protected override Core.Model.Roles.Patient MapToModel(Patient resource)
        {
            Core.Model.Roles.Patient patient = null;

            // Attempt to XRef
            if (Guid.TryParse(resource.Id, out Guid key))
            {
                patient = this.m_repository.Get(key);

                // Patient doesn't exist?
                if (patient == null)
                {
                    patient = new Core.Model.Roles.Patient
                    {
                        Key = key
                    };
                }
            }
            else if (resource.Identifier.Any())
            {
                foreach (var ii in resource.Identifier.Select(DataTypeConverter.ToEntityIdentifier))
                {
                    if (ii.LoadProperty(o => o.Authority).IsUnique)
                    {
                        patient = this.m_repository.Find(o => o.Identifiers.Where(i => i.AuthorityKey == ii.AuthorityKey).Any(i => i.Value == ii.Value)).FirstOrDefault();
                    }
                    if (patient != null)
                    {
                        break;
                    }
                }

                if (patient == null)
                {
                    patient = new Core.Model.Roles.Patient
                    {
                        Key = Guid.NewGuid()
                    };
                }
            }
            else
            {
                patient = new Core.Model.Roles.Patient
                {
                    Key = Guid.NewGuid()
                };
            }

            patient.Addresses             = resource.Address.Select(DataTypeConverter.ToEntityAddress).ToList();
            patient.CreationTime          = DateTimeOffset.Now;
            patient.GenderConceptKey      = resource.Gender == null ? null : DataTypeConverter.ToConcept(new Coding("http://hl7.org/fhir/administrative-gender", Hl7.Fhir.Utility.EnumUtility.GetLiteral(resource.Gender)))?.Key;
            patient.Identifiers           = resource.Identifier.Select(DataTypeConverter.ToEntityIdentifier).ToList();
            patient.LanguageCommunication = resource.Communication.Select(DataTypeConverter.ToLanguageCommunication).ToList();
            patient.Names            = resource.Name.Select(DataTypeConverter.ToEntityName).ToList();
            patient.StatusConceptKey = resource.Active == null || resource.Active == true ? StatusKeys.Active : StatusKeys.Inactive;
            patient.Telecoms         = resource.Telecom.Select(DataTypeConverter.ToEntityTelecomAddress).OfType <EntityTelecomAddress>().ToList();
            patient.Relationships    = resource.Contact.Select(r => DataTypeConverter.ToEntityRelationship(r, resource)).ToList();
            patient.Extensions       = resource.Extension.Select(o => DataTypeConverter.ToEntityExtension(o, patient)).ToList();

            patient.DateOfBirth = DataTypeConverter.ToDateTimeOffset(resource.BirthDate, out var dateOfBirthPrecision)?.DateTime;
            // TODO: fix
            // HACK: the date of birth precision CK only allows "Y", "M", or "D" for the precision value
            patient.DateOfBirthPrecision = dateOfBirthPrecision == DatePrecision.Full ? DatePrecision.Day : dateOfBirthPrecision;

            switch (resource.Deceased)
            {
            case FhirDateTime dtValue when !String.IsNullOrEmpty(dtValue.Value):
                patient.DeceasedDate = DataTypeConverter.ToDateTimeOffset(dtValue.Value, out var datePrecision)?.DateTime;
                // TODO: fix
                // HACK: the deceased date precision CK only allows "Y", "M", or "D" for the precision value
                patient.DeceasedDatePrecision = datePrecision == DatePrecision.Full ? DatePrecision.Day : datePrecision;
                break;

            case FhirBoolean boolValue when boolValue.Value.GetValueOrDefault():
                // we don't have a field for "deceased indicator" to say that the patient is dead, but we don't know that actual date/time of death
                // should find a better way to do this
                patient.DeceasedDate = DateTime.MinValue;

                patient.DeceasedDatePrecision = DatePrecision.Year;
                break;
            }

            switch (resource.MultipleBirth)
            {
            case FhirBoolean boolBirth when boolBirth.Value.GetValueOrDefault():
                patient.MultipleBirthOrder = 0;

                break;

            case Integer intBirth:
                patient.MultipleBirthOrder = intBirth.Value;
                break;
            }

            if (resource.GeneralPractitioner != null)
            {
                patient.Relationships.AddRange(resource.GeneralPractitioner.Select(r =>
                {
                    var referenceKey = DataTypeConverter.ResolveEntity <Core.Model.Roles.Provider>(r, resource) as Entity ?? DataTypeConverter.ResolveEntity <Core.Model.Entities.Organization>(r, resource);

                    if (referenceKey == null)
                    {
                        this.m_tracer.TraceError("Can't locate a registered general practitioner");
                        throw new KeyNotFoundException(m_localizationService.FormatString("error.type.KeyNotFoundException.cannotLocateRegistered", new
                        {
                            param = "general practitioner"
                        }));
                    }

                    return(new EntityRelationship(EntityRelationshipTypeKeys.HealthcareProvider, referenceKey));
                }));
            }
            if (resource.ManagingOrganization != null)
            {
                var referenceKey = DataTypeConverter.ResolveEntity <Core.Model.Entities.Organization>(resource.ManagingOrganization, resource);

                if (referenceKey == null)
                {
                    this.m_tracer.TraceError("Can't locate a registered managing organization");

                    throw new KeyNotFoundException(m_localizationService.FormatString("error.type.KeyNotFoundException.cannotLocateRegistered", new
                    {
                        param = "managing organization"
                    }));
                }

                patient.Relationships.Add(new EntityRelationship(EntityRelationshipTypeKeys.Scoper, referenceKey));
            }

            // Process contained related persons
            foreach (var itm in resource.Contained.OfType <RelatedPerson>())
            {
                var er = FhirResourceHandlerUtil.GetMappersFor(ResourceType.RelatedPerson).First().MapToModel(itm) as Core.Model.Entities.EntityRelationship;

                // Relationship bindings
                er.ClassificationKey = RelationshipClassKeys.ContainedObjectLink;
                er.SourceEntityKey   = patient.Key;

                // Now add rels to me
                patient.Relationships.Add(er);
            }

            // Links
            foreach (var lnk in resource.Link)
            {
                switch (lnk.Type.Value)
                {
                case Patient.LinkType.Replaces:
                {
                    // Find the victim
                    var replacee = DataTypeConverter.ResolveEntity <Core.Model.Roles.Patient>(lnk.Other, resource);

                    if (replacee == null)
                    {
                        this.m_tracer.TraceError($"Cannot locate patient referenced by {lnk.Type} relationship");
                        throw new KeyNotFoundException(m_localizationService.FormatString("error.messaging.fhir.patientResource.cannotLocatePatient", new
                            {
                                param = lnk.Type
                            }));
                    }

                    replacee.StatusConceptKey = StatusKeys.Obsolete;
                    patient.Relationships.Add(new EntityRelationship(EntityRelationshipTypeKeys.Replaces, replacee));
                    break;
                }

                case Patient.LinkType.ReplacedBy:
                {
                    // Find the new
                    var replacer = DataTypeConverter.ResolveEntity <Core.Model.Roles.Patient>(lnk.Other, resource);

                    if (replacer == null)
                    {
                        this.m_tracer.TraceError($"Cannot locate patient referenced by {lnk.Type} relationship");
                        throw new KeyNotFoundException(m_localizationService.FormatString("error.messaging.fhir.patientResource.cannotLocatePatient", new
                            {
                                param = lnk.Type
                            }));
                    }

                    patient.StatusConceptKey = StatusKeys.Obsolete;
                    patient.Relationships.Add(new EntityRelationship(EntityRelationshipTypeKeys.Replaces, patient)
                        {
                            HolderKey = replacer.Key
                        });
                    break;
                }

                case Patient.LinkType.Seealso:
                {
                    var referee = DataTypeConverter.ResolveEntity <Entity>(lnk.Other, resource);        // We use Entity here in lieu Patient since the code below can handle the MDM layer

                    // Is this a current MDM link?
                    if (referee.GetTag(FhirConstants.PlaceholderTag) == "true")         // The referee wants us to become the data
                    {
                        patient.Key = referee.Key;
                    }
                    else if (referee.LoadCollection(o => o.Relationships).Any(r => r.RelationshipTypeKey == MDM_MASTER_LINK) &&
                             referee.GetTag("$mdm.type") == "M")       // HACK: This is a master and someone is attempting to point another record at it
                    {
                        patient.Relationships.Add(new EntityRelationship()
                            {
                                RelationshipTypeKey = MDM_MASTER_LINK,
                                SourceEntityKey     = referee.Key,
                                TargetEntityKey     = patient.Key
                            });
                    }
                    else
                    {
                        patient.Relationships.Add(new EntityRelationship(EntityRelationshipTypeKeys.EquivalentEntity, referee));
                    }
                    break;
                }

                case Patient.LinkType.Refer:     // This points to a more detailed view of the patient
                {
                    var referee = DataTypeConverter.ResolveEntity <Entity>(lnk.Other, resource);
                    if (referee.GetTag("$mdm.type") == "M")         // HACK: MDM User is attempting to point this at another Master (note: THE MDM LAYER WON'T LIKE THIS)
                    {
                        patient.Relationships.Add(new EntityRelationship(MDM_MASTER_LINK, referee));
                    }
                    else
                    {
                        this.m_tracer.TraceError($"Setting refer relationships to source of truth is not supported");
                        throw new NotSupportedException(m_localizationService.GetString("error.type.NotSupportedException.userMessage"));
                    }

                    break;         // TODO: These are special cases of references
                }
                }
            }

            if (resource.Photo != null && resource.Photo.Any())
            {
                patient.Extensions.RemoveAll(o => o.ExtensionTypeKey == ExtensionTypeKeys.JpegPhotoExtension);
                patient.Extensions.Add(new EntityExtension(ExtensionTypeKeys.JpegPhotoExtension, resource.Photo.First().Data));
            }

            return(patient);
        }