/// <summary> /// Map a practitioner to a user entity /// </summary> protected override Provider MapToModel(Practitioner resource) { Provider retVal = null; if (Guid.TryParse(resource.Id, out var key)) { retVal = this.m_repository.Get(key); } else if (resource.Identifier.Any()) { foreach (var ii in resource.Identifier.Select(DataTypeConverter.ToEntityIdentifier)) { if (ii.LoadProperty(o => o.Authority).IsUnique) { retVal = this.m_repository.Find(o => o.Identifiers.Where(i => i.AuthorityKey == ii.AuthorityKey).Any(i => i.Value == ii.Value)).FirstOrDefault(); } if (retVal != null) { break; } } } if (retVal == null) { retVal = new Provider { Key = Guid.NewGuid() }; } // Organization retVal.Addresses = resource.Address.Select(DataTypeConverter.ToEntityAddress).ToList(); // TODO: Extensions retVal.Identifiers = resource.Identifier.Select(DataTypeConverter.ToEntityIdentifier).ToList(); retVal.Names = resource.Name.Select(DataTypeConverter.ToEntityName).ToList(); retVal.StatusConceptKey = !resource.Active.HasValue || resource.Active == true ? StatusKeys.Active : StatusKeys.Inactive; retVal.Telecoms = resource.Telecom.Select(DataTypeConverter.ToEntityTelecomAddress).ToList(); retVal.Extensions = resource.Extension.Select(o => DataTypeConverter.ToEntityExtension(o, retVal)).OfType <EntityExtension>().ToList(); retVal.GenderConceptKey = resource.Gender == null ? NullReasonKeys.Unknown : DataTypeConverter.ToConcept(new Coding("http://hl7.org/fhir/administrative-gender", Hl7.Fhir.Utility.EnumUtility.GetLiteral(resource.Gender)))?.Key; retVal.DateOfBirthXml = resource.BirthDate; retVal.DateOfBirthPrecision = DatePrecision.Day; retVal.LanguageCommunication = resource.Communication.Select(c => DataTypeConverter.ToLanguageCommunication(c, false)).ToList(); if (resource.Photo != null && resource.Photo.Any()) { retVal.Extensions.RemoveAll(o => o.ExtensionTypeKey == ExtensionTypeKeys.JpegPhotoExtension); retVal.Extensions.Add(new EntityExtension(ExtensionTypeKeys.JpegPhotoExtension, resource.Photo.First().Data)); } if (resource.Qualification.Any()) { retVal.ProviderSpecialty = DataTypeConverter.ToConcept(resource.Qualification.First().Code); } return(retVal); }
/// <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); }
/// <summary> /// Map to Model /// </summary> protected override Core.Model.Entities.Organization MapToModel(Hl7.Fhir.Model.Organization resource) { Core.Model.Entities.Organization retVal = null; if (Guid.TryParse(resource.Id, out Guid key)) { retVal = this.m_repository.Get(key); } else if (resource.Identifier?.Count > 0) { foreach (var ii in resource.Identifier.Select(DataTypeConverter.ToEntityIdentifier)) { if (ii.LoadProperty(o => o.Authority).IsUnique) { retVal = this.m_repository.Find(o => o.Identifiers.Where(i => i.AuthorityKey == ii.AuthorityKey).Any(i => i.Value == ii.Value)).FirstOrDefault(); } if (retVal != null) { break; } } } if (retVal == null) { retVal = new Core.Model.Entities.Organization() { Key = Guid.NewGuid() }; } // Organization retVal.TypeConcept = resource.Type.Select(o => DataTypeConverter.ToConcept(o)).OfType <Concept>().FirstOrDefault(); retVal.Addresses = resource.Address.Select(DataTypeConverter.ToEntityAddress).ToList(); // TODO: Extensions retVal.Identifiers = resource.Identifier.Select(DataTypeConverter.ToEntityIdentifier).ToList(); retVal.Names = new List <EntityName>() { new EntityName(NameUseKeys.OfficialRecord, resource.Name) }; retVal.Names.AddRange(resource.Alias.Select(o => new EntityName(NameUseKeys.Pseudonym, o))); retVal.StatusConceptKey = !resource.Active.HasValue || resource.Active == true ? StatusKeys.Active : StatusKeys.Inactive; retVal.Telecoms = resource.Telecom.Select(DataTypeConverter.ToEntityTelecomAddress).OfType <EntityTelecomAddress>().ToList(); if (resource.PartOf != null) { var reference = DataTypeConverter.ResolveEntity <Core.Model.Entities.Organization>(resource.PartOf, resource); if (reference == null) { this.m_tracer.TraceError($"Could not resolve {resource.PartOf.Reference}"); throw new KeyNotFoundException(m_localizationService.FormatString("error.type.KeyNotFoundException.couldNotResolve", new { param = resource.PartOf.Reference })); } // point the child organization entity at the target organization entity with a relationship of parent retVal.Relationships.Add(new EntityRelationship(EntityRelationshipTypeKeys.Parent, reference)); } retVal.Extensions = resource.Extension.Select(o => DataTypeConverter.ToEntityExtension(o, retVal)).OfType <EntityExtension>().ToList(); return(retVal); }