/// <summary> /// Map to Model /// </summary> protected override Core.Model.Entities.Organization MapToModel(SanteDB.Messaging.FHIR.Resources.Organization resource, RestOperationContext webOperationContext) { // Organization var retVal = new Core.Model.Entities.Organization() { TypeConcept = DataTypeConverter.ToConcept(resource.Type), Addresses = resource.Address.Select(DataTypeConverter.ToEntityAddress).ToList(), CreationTime = DateTimeOffset.Now, // TODO: Extensions Extensions = resource.Extension.Select(DataTypeConverter.ToEntityExtension).OfType <EntityExtension>().ToList(), Identifiers = resource.Identifier.Select(DataTypeConverter.ToEntityIdentifier).ToList(), Key = Guid.NewGuid(), Names = new List <EntityName>() { new EntityName(NameUseKeys.OfficialRecord, resource.Name) }, StatusConceptKey = resource.Active?.Value == true ? StatusKeys.Active : StatusKeys.Obsolete, Telecoms = resource.Telecom.Select(DataTypeConverter.ToEntityTelecomAddress).ToList() }; Guid key; if (!Guid.TryParse(resource.Id, out key)) { key = Guid.NewGuid(); } retVal.Key = key; return(retVal); }
/// <summary> /// Map an immunization FHIR resource to a substance administration. /// </summary> /// <param name="resource">The resource.</param> /// <returns>Returns the mapped model.</returns> protected override SubstanceAdministration MapToModel(Immunization resource, WebOperationContext webOperationContext) { var substanceAdministration = new SubstanceAdministration { ActTime = resource.Date.DateValue.Value, DoseQuantity = resource.DoseQuantity.Value.Value.Value, Extensions = resource.Extension?.Select(DataTypeConverter.ToActExtension).ToList(), Identifiers = resource.Identifier?.Select(DataTypeConverter.ToActIdentifier).ToList(), Key = Guid.NewGuid(), MoodConceptKey = DataTypeConverter.ToConcept <string>(resource.Status, "http://hl7.org/fhir/medication-admin-status")?.Key, ReasonConceptKey = DataTypeConverter.ToConcept <string>(resource.Status, "http://snomed.info/sct")?.Key, RouteKey = DataTypeConverter.ToConcept <string>(resource.Status, "http://hl7.org/fhir/v3/RouteOfAdministration")?.Key, SiteKey = DataTypeConverter.ToConcept(resource.Site.GetPrimaryCode(), resource.Site.GetPrimaryCode().System)?.Key, }; Guid key; if (Guid.TryParse(resource.Id, out key)) { substanceAdministration.Key = key; } if (resource.WasNotGiven.Value == true) { substanceAdministration.IsNegated = true; } return(substanceAdministration); }
/// <summary> /// Map to model the encounter /// </summary> protected override PatientEncounter MapToModel(Encounter resource) { var status = resource.Status; var retVal = new PatientEncounter { TypeConcept = DataTypeConverter.ToConcept(resource.Class, "http://santedb.org/conceptset/v3-ActEncounterCode"), // TODO: Extensions Extensions = resource.Extension.Select(DataTypeConverter.ToActExtension).OfType <ActExtension>().ToList(), Identifiers = resource.Identifier.Select(DataTypeConverter.ToActIdentifier).ToList(), Key = Guid.NewGuid(), StatusConceptKey = status == Encounter.EncounterStatus.Finished ? StatusKeys.Completed : status == Encounter.EncounterStatus.Cancelled ? StatusKeys.Cancelled : status == Encounter.EncounterStatus.InProgress || status == Encounter.EncounterStatus.Arrived ? StatusKeys.Active : status == Encounter.EncounterStatus.Planned ? StatusKeys.New : status == Encounter.EncounterStatus.EnteredInError ? StatusKeys.Nullified : StatusKeys.Inactive, MoodConceptKey = status == Encounter.EncounterStatus.Planned ? ActMoodKeys.Intent : ActMoodKeys.Eventoccurrence, ReasonConcept = DataTypeConverter.ToConcept(resource.ReasonCode.FirstOrDefault()), StartTime = DataTypeConverter.ToDateTimeOffset(resource.Period.Start), StopTime = DataTypeConverter.ToDateTimeOffset(resource.Period.End) }; if (!Guid.TryParse(resource.Id, out var key)) { key = Guid.NewGuid(); } retVal.Key = key; // Attempt to resolve relationships if (resource.Subject != null) { // if the subject is a UUID then add the record target key // otherwise attempt to resolve the reference retVal.Participations.Add(resource.Subject.Reference.StartsWith("urn:uuid:") ? new ActParticipation(ActParticipationKey.RecordTarget, Guid.Parse(resource.Subject.Reference.Substring(9))) : new ActParticipation(ActParticipationKey.RecordTarget, DataTypeConverter.ResolveEntity <Core.Model.Roles.Patient>(resource.Subject, resource))); } // Attempt to resolve organization if (resource.ServiceProvider != null) { // Is the subject a uuid if (resource.ServiceProvider.Reference.StartsWith("urn:uuid:")) { retVal.Participations.Add(new ActParticipation(ActParticipationKey.Custodian, Guid.Parse(resource.ServiceProvider.Reference.Substring(9)))); } else { this.m_tracer.TraceError("Only UUID references are supported"); throw new NotSupportedException(this.m_localizationService.FormatString("error.type.NotSupportedException.paramOnlySupported", new { param = "UUID" })); } } // TODO : Other Participations return(retVal); }
/// <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, RestOperationContext restOperationContext) { var patient = new Core.Model.Roles.Patient { Addresses = resource.Address.Select(DataTypeConverter.ToEntityAddress).ToList(), CreationTime = DateTimeOffset.Now, DateOfBirth = resource.BirthDate?.DateValue, DateOfBirthPrecision = resource.BirthDate.Precision == DataTypes.DatePrecision.Day ? DatePrecision.Day : DatePrecision.Year, // TODO: Extensions Extensions = resource.Extension.Select(DataTypeConverter.ToEntityExtension).OfType <EntityExtension>().ToList(), GenderConceptKey = DataTypeConverter.ToConcept(new FhirCoding(new Uri("http://hl7.org/fhir/administrative-gender"), resource.Gender?.Value))?.Key, Identifiers = resource.Identifier.Select(DataTypeConverter.ToEntityIdentifier).ToList(), LanguageCommunication = resource.Communication.Select(DataTypeConverter.ToPersonLanguageCommunication).ToList(), Names = resource.Name.Select(DataTypeConverter.ToEntityName).ToList(), Relationships = resource.Contact.Select(DataTypeConverter.ToEntityRelationship).ToList(), StatusConceptKey = resource.Active?.Value == true ? StatusKeys.Active : StatusKeys.Obsolete, Telecoms = resource.Telecom.Select(DataTypeConverter.ToEntityTelecomAddress).ToList() }; Guid key; if (!Guid.TryParse(resource.Id, out key)) { foreach (var id in patient.Identifiers) // try to lookup based on reliable id for the record to update { if (id.Authority.IsUnique) { var match = ApplicationServiceContext.Current.GetService <IDataPersistenceService <Core.Model.Roles.Patient> >().Query(o => o.Identifiers.Any(i => i.Authority.DomainName == id.Authority.DomainName && i.Value == id.Value), 0, 1, out int tr, AuthenticationContext.SystemPrincipal); key = match.FirstOrDefault()?.Key ?? Guid.NewGuid(); } } } patient.Key = key; if (resource.Deceased is FhirDateTime) { patient.DeceasedDate = (FhirDateTime)resource.Deceased; } else if (resource.Deceased is FhirBoolean) { // 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.Now; patient.DeceasedDatePrecision = DatePrecision.Year; } if (resource.MultipleBirth as FhirBoolean == true) { patient.MultipleBirthOrder = 0; } else if (resource.MultipleBirth is FhirInt) { patient.MultipleBirthOrder = ((FhirInt)resource.MultipleBirth).Value; } return(patient); }
/// <summary> /// Parse the extension /// </summary> public bool Parse(Extension fhirExtension, IdentifiedData modelObject) { if (modelObject is SanteDB.Core.Model.Roles.Patient patient && fhirExtension.Value is CodeableConcept cc) { patient.ReligiousAffiliation = DataTypeConverter.ToConcept(cc); return(true); } return(false); }
/// <summary> /// Parse the extension /// </summary> public bool Parse(Extension fhirExtension, IdentifiedData modelObject) { if (modelObject is Core.Model.Roles.Patient patient && fhirExtension.Value is CodeableConcept cc) { patient.VipStatus = DataTypeConverter.ToConcept(cc); return(true); } return(false); }
/// <summary> /// Maps a FHIR patient resource to an IMSI patient. /// </summary> /// <param name="resource">The resource.</param> /// <returns>Returns the mapped model.</returns> protected override Core.Model.Roles.Patient MapToModel(Patient resource, WebOperationContext webOperationContext) { var patient = new Core.Model.Roles.Patient { Addresses = resource.Address.Select(DataTypeConverter.ToEntityAddress).ToList(), CreationTime = DateTimeOffset.Now, DateOfBirth = resource.BirthDate?.DateValue, // TODO: Extensions Extensions = resource.Extension.Select(DataTypeConverter.ToEntityExtension).ToList(), GenderConceptKey = DataTypeConverter.ToConcept(new FhirCoding(new Uri("http://hl7.org/fhir/administrative-gender"), resource.Gender?.Value))?.Key, Identifiers = resource.Identifier.Select(DataTypeConverter.ToEntityIdentifier).ToList(), LanguageCommunication = resource.Communication.Select(DataTypeConverter.ToPersonLanguageCommunication).ToList(), Key = Guid.NewGuid(), Names = resource.Name.Select(DataTypeConverter.ToEntityName).ToList(), Relationships = resource.Contact.Select(DataTypeConverter.ToEntityRelationship).ToList(), StatusConceptKey = resource.Active?.Value == true ? StatusKeys.Active : StatusKeys.Obsolete, Telecoms = resource.Telecom.Select(DataTypeConverter.ToEntityTelecomAddress).ToList() }; Guid key; if (!Guid.TryParse(resource.Id, out key)) { key = Guid.NewGuid(); } patient.Key = key; if (resource.Deceased is FhirDateTime) { patient.DeceasedDate = (FhirDateTime)resource.Deceased; } else if (resource.Deceased is FhirBoolean) { // 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.Now; patient.DeceasedDatePrecision = DatePrecision.Year; } if (resource.MultipleBirth is FhirBoolean) { patient.MultipleBirthOrder = 0; } else if (resource.MultipleBirth is FhirInt) { patient.MultipleBirthOrder = ((FhirInt)resource.MultipleBirth).Value; } return(patient); }
/// <summary> /// Maps a FHIR <see cref="Medication"/> to a <see cref="ManufacturedMaterial"/> instance. /// </summary> /// <param name="resource">The model resource to be mapped</param> /// <returns>Returns the mapped <see cref="ManufacturedMaterial"/> instance.</returns> protected override ManufacturedMaterial MapToModel(Medication resource) { ManufacturedMaterial manufacturedMaterial; if (Guid.TryParse(resource.Id, out var key)) { manufacturedMaterial = this.m_repository.Get(key) ?? new ManufacturedMaterial { Key = key }; } else { manufacturedMaterial = new ManufacturedMaterial { Key = Guid.NewGuid() }; } manufacturedMaterial.Identifiers = resource.Identifier.Select(DataTypeConverter.ToEntityIdentifier).ToList(); manufacturedMaterial.TypeConcept = DataTypeConverter.ToConcept(resource.Code?.Coding?.FirstOrDefault(), "http://snomed.info/sct"); switch (resource.Status) { case Medication.MedicationStatusCodes.Active: manufacturedMaterial.StatusConceptKey = StatusKeys.Active; break; case Medication.MedicationStatusCodes.Inactive: manufacturedMaterial.StatusConceptKey = StatusKeys.Obsolete; break; case Medication.MedicationStatusCodes.EnteredInError: manufacturedMaterial.StatusConceptKey = StatusKeys.Nullified; break; } manufacturedMaterial.LotNumber = resource.Batch?.LotNumber; manufacturedMaterial.ExpiryDate = DataTypeConverter.ToDateTimeOffset(resource.Batch?.ExpirationDateElement)?.DateTime; if (resource.Manufacturer != null) { manufacturedMaterial.Relationships.Add(new EntityRelationship(EntityRelationshipTypeKeys.ManufacturedProduct, DataTypeConverter.ResolveEntity <Core.Model.Entities.Organization>(resource.Manufacturer, resource))); } return(manufacturedMaterial); }
/// <inheritdoc/> protected override Act MapToModel(AdverseEvent resource) { #if !DEBUG throw new NotSupportedException(); #endif var retVal = new Act(); if (!Guid.TryParse(resource.Id, out var key)) { key = Guid.NewGuid(); } retVal.ClassConceptKey = ActClassKeys.Act; // retVal.StatusConceptKey = StatusKeys.Active; retVal.Key = key; retVal.MoodConceptKey = ActMoodKeys.Eventoccurrence; // map identifier to identifiers retVal.Identifiers.Add(DataTypeConverter.ToActIdentifier(resource.Identifier)); /* retVal.Identifiers = new List<ActIdentifier> * { * DataTypeConverter.ToActIdentifier(resource.Identifier) * };*/ //map category to type concept retVal.TypeConcept = DataTypeConverter.ToConcept(resource.Category.FirstOrDefault()); // map subject to patient if (resource.Subject != null) { retVal.Participations.Add(resource.Subject.Reference.StartsWith("urn:uuid:") ? new ActParticipation(ActParticipationKey.RecordTarget, Guid.Parse(resource.Subject.Reference.Substring(9))): new ActParticipation(ActParticipationKey.RecordTarget, DataTypeConverter.ResolveEntity <Core.Model.Roles.Patient>(resource.Subject, resource))); } // map date element to act time var occurTime = (DateTimeOffset)DataTypeConverter.ToDateTimeOffset(resource.DateElement); var targetAct = new CodedObservation() { ActTime = occurTime }; retVal.Relationships.Add(new ActRelationship(ActRelationshipTypeKeys.HasSubject, targetAct)); retVal.ActTime = occurTime; // map event to relationships var reactionTarget = new CodedObservation() { Value = DataTypeConverter.ToConcept(resource.Event) }; targetAct.Relationships.Add(new ActRelationship(ActRelationshipTypeKeys.HasManifestation, reactionTarget)); // map location to place if (resource.Location != null) { retVal.Participations.Add(resource.Location.Reference.StartsWith("urn:uuid:") ? new ActParticipation(ActParticipationKey.Location, Guid.Parse(resource.Location.Reference.Substring(9))) : new ActParticipation(ActParticipationKey.Location, DataTypeConverter.ResolveEntity <Core.Model.Entities.Place>(resource.Location, resource))); // retVal.Participations.Add(new ActParticipation(ActParticipationKey.Location, DataTypeConverter.ResolveEntity<Core.Model.Entities.Place>(resource.Location, resource))); } // map seriousness to relationships if (resource.Severity != null) { var severityTarget = new CodedObservation() { Value = DataTypeConverter.ToConcept(resource.Severity.Coding.FirstOrDefault(), "http://terminology.hl7.org/CodeSystem/adverse-event-severity"), TypeConceptKey = ObservationTypeKeys.Severity }; targetAct.Relationships.Add(new ActRelationship(ActRelationshipTypeKeys.HasComponent, severityTarget)); } // map recoder to provider if (resource.Recorder != null) { retVal.Participations.Add(resource.Recorder.Reference.StartsWith("urn:uuid:") ? new ActParticipation(ActParticipationKey.Authororiginator, Guid.Parse(resource.Recorder.Reference.Substring(9))) : new ActParticipation(ActParticipationKey.Authororiginator, DataTypeConverter.ResolveEntity <Core.Model.Roles.Provider>(resource.Recorder, resource))); // retVal.Participations.Add(new ActParticipation(ActParticipationKey.Authororiginator, DataTypeConverter.ResolveEntity<Core.Model.Roles.Provider>(resource.Recorder, resource))); } // map outcome to status concept key or relationships if (resource.Outcome != null) { if (resource.Outcome.Coding.Any(o => o.System == "http://hl7.org/fhir/adverse-event-outcome")) { if (resource.Outcome.Coding.Any(o => o.Code == "fatal")) { retVal.Relationships.Add(new ActRelationship(ActRelationshipTypeKeys.IsCauseOf, new CodedObservation { TypeConceptKey = ObservationTypeKeys.ClinicalState, ValueKey = Guid.Parse("6df3720b-857f-4ba2-826f-b7f1d3c3adbb") })); } else if (resource.Outcome.Coding.Any(o => o.Code == "ongoing")) { retVal.StatusConceptKey = StatusKeys.Active; } else if (resource.Outcome.Coding.Any(o => o.Code == "resolved")) { retVal.StatusConceptKey = StatusKeys.Completed; } } } // map instance to relationships and participations if (resource.SuspectEntity != null) { foreach (var component in resource.SuspectEntity) { var adm = new SubstanceAdministration(); if (component.Instance.GetType() == typeof(Medication)) { adm.Participations.Add(component.Instance.Reference.StartsWith("urn:uuid:") ? new ActParticipation(ActParticipationKey.Consumable, Guid.Parse(component.Instance.Reference.Substring(9))) : new ActParticipation(ActParticipationKey.Consumable, DataTypeConverter.ResolveEntity <Core.Model.Entities.ManufacturedMaterial>(component.Instance, resource))); // adm.Participations.Add(new ActParticipation(ActParticipationKey.Consumable, DataTypeConverter.ResolveEntity<Core.Model.Entities.ManufacturedMaterial>(component.Instance, resource))); retVal.Relationships.Add(new ActRelationship(ActRelationshipTypeKeys.RefersTo, adm)); } else if (component.Instance.GetType() == typeof(Substance)) { adm.Participations.Add((component.Instance.Reference.StartsWith("urn:uuid:") ? new ActParticipation(ActParticipationKey.Product, Guid.Parse(component.Instance.Reference.Substring(9))) : new ActParticipation(ActParticipationKey.Product, DataTypeConverter.ResolveEntity <Core.Model.Entities.Material>(component.Instance, resource)))); // adm.Participations.Add(new ActParticipation(ActParticipationKey.Product, DataTypeConverter.ResolveEntity<Core.Model.Entities.Material>(component.Instance, resource))); retVal.Relationships.Add(new ActRelationship(ActRelationshipTypeKeys.RefersTo, adm)); } } } 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 the encounter /// </summary> protected override PatientEncounter MapToModel(Encounter resource, RestOperationContext webOperationContext) { // Organization var status = resource.Status?.Value; var retVal = new PatientEncounter() { TypeConcept = DataTypeConverter.ToConcept(resource.Class, new Uri("http://openiz.org/conceptset/v3-ActEncounterCode")), StartTime = resource.Period?.Start?.DateValue, StopTime = resource.Period?.Stop?.DateValue, // TODO: Extensions Extensions = resource.Extension.Select(DataTypeConverter.ToActExtension).OfType <ActExtension>().ToList(), Identifiers = resource.Identifier.Select(DataTypeConverter.ToActIdentifier).ToList(), Key = Guid.NewGuid(), StatusConceptKey = status == EncounterStatus.Finished ? StatusKeys.Completed : status == EncounterStatus.Cancelled ? StatusKeys.Cancelled : status == EncounterStatus.InProgress || status == EncounterStatus.Arrived ? StatusKeys.Active : status == EncounterStatus.Planned ? StatusKeys.Active : StatusKeys.Obsolete, MoodConceptKey = status == EncounterStatus.Planned ? ActMoodKeys.Intent : ActMoodKeys.Eventoccurrence, ReasonConcept = DataTypeConverter.ToConcept(resource.Reason) }; // Parse key Guid key; if (!Guid.TryParse(resource.Id, out key)) { key = Guid.NewGuid(); } retVal.Key = key; // Attempt to resolve relationships if (resource.Subject != null) { // Is the subject a uuid if (resource.Subject.ReferenceUrl.Value.StartsWith("urn:uuid:")) { retVal.Participations.Add(new ActParticipation(ActParticipationKey.RecordTarget, Guid.Parse(resource.Subject.ReferenceUrl.Value.Substring(9)))); } else { throw new NotSupportedException("Only UUID references are supported"); } } // Attempt to resolve organiztaion if (resource.ServiceProvider != null) { // Is the subject a uuid if (resource.ServiceProvider.ReferenceUrl.Value.StartsWith("urn:uuid:")) { retVal.Participations.Add(new ActParticipation(ActParticipationKey.Custodian, Guid.Parse(resource.ServiceProvider.ReferenceUrl.Value.Substring(9)))); } else { throw new NotSupportedException("Only UUID references are supported"); } } // TODO : Other Participations return(retVal); }
/// <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); }
/// <summary> /// Map the incoming FHIR resource to a MODEL resource /// </summary> /// <param name="resource">The resource to be mapped</param> /// <returns></returns> protected override Place MapToModel(Location resource) { Place place = null; if (Guid.TryParse(resource.Id, out Guid key)) { place = this.m_repository.Get(key); if (place == null) { place = new Place { Key = key }; } } else if (resource.Identifier.Any()) { foreach (var ii in resource.Identifier.Select(DataTypeConverter.ToEntityIdentifier)) { if (ii.LoadProperty(o => o.Authority).IsUnique) { place = this.m_repository.Find(o => o.Identifiers.Where(i => i.AuthorityKey == ii.AuthorityKey).Any(i => i.Value == ii.Value)).FirstOrDefault(); } if (place != null) { break; } } if (place == null) { place = new Place { Key = Guid.NewGuid() }; } } else { place = new Place { Key = Guid.NewGuid() }; } switch (resource.Status) { case Location.LocationStatus.Active: place.StatusConceptKey = StatusKeys.Active; break; case Location.LocationStatus.Suspended: throw new NotSupportedException(this.m_localizationService.GetString("error.type.NotSupportedException")); case Location.LocationStatus.Inactive: place.StatusConceptKey = StatusKeys.Inactive; break; } // add the textual representation of the name of the place as the address text property for search purposes // see the BirthPlaceExtension class if (!string.IsNullOrEmpty(resource.Address?.Text)) { place.Names.Add(new EntityName(NameUseKeys.Search, resource.Address.Text)); } place.Names.Add(new EntityName(NameUseKeys.OfficialRecord, resource.Name)); place.Names.AddRange(resource.Alias.Select(o => new EntityName(NameUseKeys.Pseudonym, o))); if (resource.Mode == Location.LocationMode.Kind) { place.DeterminerConceptKey = DeterminerKeys.Described; } else { place.DeterminerConceptKey = DeterminerKeys.Specific; } place.TypeConcept = DataTypeConverter.ToConcept(resource.Type.FirstOrDefault()); place.Telecoms = resource.Telecom.Select(DataTypeConverter.ToEntityTelecomAddress).OfType <EntityTelecomAddress>().ToList(); place.Identifiers = resource.Identifier.Select(DataTypeConverter.ToEntityIdentifier).ToList(); if (resource.Address != null) { place.Addresses = new List <EntityAddress>() { DataTypeConverter.ToEntityAddress(resource.Address) } } ; if (resource.Position != null) { place.GeoTag = new GeoTag { Lat = (double)resource.Position.Latitude, Lng = (double)resource.Position.Longitude }; } if (resource.PartOf != null) { var reference = DataTypeConverter.ResolveEntity <Place>(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 place entity at the target place entity with a relationship of parent place.Relationships.Add(new EntityRelationship(EntityRelationshipTypeKeys.Parent, reference)); } return(place); }
/// <summary> /// Map to model /// </summary> protected override Core.Model.Acts.Observation MapToModel(Observation resource) { //value type and value Core.Model.Acts.Observation retVal; switch (resource.Value) { case CodeableConcept codeableConcept: retVal = new CodedObservation { ValueType = "CD", Value = DataTypeConverter.ToConcept(codeableConcept) }; break; case Quantity quantity: retVal = new QuantityObservation { ValueType = "PQ", Value = quantity.Value.Value, UnitOfMeasure = DataTypeConverter.ToConcept(quantity.Unit, "http://hl7.org/fhir/sid/ucum") }; break; case FhirString fhirString: retVal = new TextObservation { ValueType = "ST", Value = fhirString.Value }; break; default: retVal = new Core.Model.Acts.Observation(); break; } retVal.Extensions = resource.Extension.Select(DataTypeConverter.ToActExtension).ToList(); retVal.Identifiers = resource.Identifier.Select(DataTypeConverter.ToActIdentifier).ToList(); retVal.Key = Guid.TryParse(resource.Id, out var id) ? id : Guid.NewGuid(); // Observation var status = resource.Status; //status concept key switch (status) { case ObservationStatus.Preliminary: retVal.StatusConceptKey = StatusKeys.Active; break; case ObservationStatus.Cancelled: retVal.StatusConceptKey = StatusKeys.Cancelled; break; case ObservationStatus.EnteredInError: retVal.StatusConceptKey = StatusKeys.Nullified; break; case ObservationStatus.Final: retVal.StatusConceptKey = StatusKeys.Completed; break; case ObservationStatus.Amended: case ObservationStatus.Corrected: throw new NotSupportedException(this.m_localizationService.GetString("error.messaging.fhir.observationStatus")); case ObservationStatus.Unknown: retVal.StatusConceptKey = StatusKeys.Obsolete; break; } //Effective switch (resource.Effective) { case Period period: retVal.StartTime = DataTypeConverter.ToDateTimeOffset(period.Start); retVal.StopTime = DataTypeConverter.ToDateTimeOffset(period.End); break; case FhirDateTime fhirDateTime: retVal.ActTime = DataTypeConverter.ToDateTimeOffset(fhirDateTime) ?? DateTimeOffset.MinValue; break; } retVal.TypeConcept = DataTypeConverter.ToConcept(resource.Code); //issued if (resource.Issued.HasValue) { retVal.CreationTime = (DateTimeOffset)resource.Issued; } //interpretation if (resource.Interpretation.Any()) { retVal.InterpretationConcept = DataTypeConverter.ToConcept(resource.Interpretation.First()); } //subject if (resource.Subject != null) { // if the subject is a UUID then add the record target key // otherwise attempt to resolve the reference retVal.Participations.Add(resource.Subject.Reference.StartsWith("urn:uuid:") ? new ActParticipation(ActParticipationKey.RecordTarget, Guid.Parse(resource.Subject.Reference.Substring(9))) : new ActParticipation(ActParticipationKey.RecordTarget, DataTypeConverter.ResolveEntity <Core.Model.Roles.Patient>(resource.Subject, resource))); //else //{ // this.m_tracer.TraceError("Only UUID references are supported"); // throw new NotSupportedException(this.m_localizationService.FormatString("error.type.NotSupportedException.paramOnlySupported", new // { // param = "UUID" // })); //} } //performer if (resource.Performer.Any()) { foreach (var res in resource.Performer) { retVal.Participations.Add(res.Reference.StartsWith("urn:uuid:") ? new ActParticipation(ActParticipationKey.Performer, Guid.Parse(res.Reference.Substring(9))) : new ActParticipation(ActParticipationKey.Performer, DataTypeConverter.ResolveEntity <Provider>(res, resource))); //if (res.Reference.StartsWith("urn:uuid:")) //{ // retVal.Participations.Add(new ActParticipation(ActParticipationKey.Performer, Guid.Parse(res.Reference.Substring(9)))); //} //else //{ // this.m_tracer.TraceError("Only UUID references are supported"); // throw new NotSupportedException(this.m_localizationService.FormatString("error.type.NotSupportedException.paramOnlySupported", new // { // param = "UUID" // })); //} } } // to bypass constraint at function 'CK_IS_CD_SET_MEM' retVal.MoodConceptKey = ActMoodKeys.Eventoccurrence; return(retVal); }
/// <summary> /// Map an immunization FHIR resource to a substance administration. /// </summary> /// <param name="resource">The resource.</param> /// <param name="restOperationContext">The operation context in which this method is being called</param> /// <returns>Returns the mapped model.</returns> protected override SubstanceAdministration MapToModel(Immunization resource, RestOperationContext restOperationContext) { var substanceAdministration = new SubstanceAdministration { ActTime = resource.Date.DateValue.Value, DoseQuantity = resource.DoseQuantity?.Value.Value ?? 0, DoseUnit = resource.DoseQuantity != null?DataTypeConverter.ToConcept <String>(resource.DoseQuantity.Units.Value, "http://hl7.org/fhir/sid/ucum") : null, Extensions = resource.Extension?.Select(DataTypeConverter.ToActExtension).ToList(), Identifiers = resource.Identifier?.Select(DataTypeConverter.ToActIdentifier).ToList(), Key = Guid.NewGuid(), MoodConceptKey = ActMoodKeys.Eventoccurrence, StatusConceptKey = resource.Status == "completed" ? StatusKeys.Completed : StatusKeys.Nullified, RouteKey = DataTypeConverter.ToConcept(resource.Route)?.Key, SiteKey = DataTypeConverter.ToConcept(resource.Site)?.Key, }; Guid key; if (Guid.TryParse(resource.Id, out key)) { substanceAdministration.Key = key; } // Was not given if (resource.WasNotGiven?.Value == true) { substanceAdministration.IsNegated = true; } // Patient if (resource.Patient != null) { // Is the subject a uuid if (resource.Patient.ReferenceUrl.Value.StartsWith("urn:uuid:")) { substanceAdministration.Participations.Add(new ActParticipation(ActParticipationKey.RecordTarget, Guid.Parse(resource.Patient.ReferenceUrl.Value.Substring(9)))); } else { throw new NotSupportedException("Only UUID references are supported"); } } // Encounter if (resource.Encounter != null) { // Is the subject a uuid if (resource.Encounter.ReferenceUrl.Value.StartsWith("urn:uuid:")) { substanceAdministration.Relationships.Add(new ActRelationship(ActRelationshipTypeKeys.HasComponent, substanceAdministration.Key) { SourceEntityKey = Guid.Parse(resource.Encounter.ReferenceUrl.Value.Substring(9)) }); } else { throw new NotSupportedException("Only UUID references are supported"); } } // Find the material that was issued if (resource.VaccineCode != null) { var concept = DataTypeConverter.ToConcept(resource.VaccineCode); if (concept == null) { this.traceSource.TraceWarning("Ignoring administration {0} don't have concept mapped", resource.VaccineCode); return(null); } // Get the material int t = 0; var material = ApplicationServiceContext.Current.GetService <IRepositoryService <Material> >().Find(m => m.TypeConceptKey == concept.Key, 0, 1, out t).FirstOrDefault(); if (material == null) { this.traceSource.TraceWarning("Ignoring administration {0} don't have material registered for {1}", resource.VaccineCode, concept?.Mnemonic); return(null); } else { substanceAdministration.Participations.Add(new ActParticipation(ActParticipationKey.Product, material.Key)); if (resource.LotNumber != null) { // TODO: Need to also find where the GTIN is kept var mmaterial = ApplicationServiceContext.Current.GetService <IRepositoryService <ManufacturedMaterial> >().Find(o => o.LotNumber == resource.LotNumber && o.Relationships.Any(r => r.SourceEntityKey == material.Key && r.RelationshipTypeKey == EntityRelationshipTypeKeys.Instance)); substanceAdministration.Participations.Add(new ActParticipation(ActParticipationKey.Consumable, material.Key) { Quantity = 1 }); } // Get dose units if (substanceAdministration.DoseQuantity == 0) { substanceAdministration.DoseQuantity = 1; substanceAdministration.DoseUnitKey = material.QuantityConceptKey; } } } return(substanceAdministration); }