/// <summary> /// Construct the extension /// </summary> public IEnumerable <Extension> Construct(IIdentifiedEntity modelObject) { if (modelObject is Person person && person.DateOfBirthPrecision > DatePrecision.Day) { yield return(new Extension(this.Uri.ToString(), DataTypeConverter.ToFhirDateTime(person.DateOfBirth))); } }
/// <summary> /// Map the substance to FHIR /// </summary> protected override Substance MapToFhir(Material model) { var retVal = DataTypeConverter.CreateResource <Substance>(model); // Identifiers retVal.Identifier = model.Identifiers.Select(o => DataTypeConverter.ToFhirIdentifier(o)).ToList(); // sTatus switch (model.StatusConceptKey.ToString().ToUpper()) { case StatusKeyStrings.New: case StatusKeyStrings.Active: retVal.Status = Substance.FHIRSubstanceStatus.Active; break; case StatusKeyStrings.Nullified: retVal.Status = Substance.FHIRSubstanceStatus.EnteredInError; break; case StatusKeyStrings.Obsolete: retVal.Status = Substance.FHIRSubstanceStatus.Inactive; break; } // Category and code retVal.Category = new List <CodeableConcept> { DataTypeConverter.ToFhirCodeableConcept(model.TypeConceptKey, "http://terminology.hl7.org/CodeSystem/substance-category") }; retVal.Code = DataTypeConverter.ToFhirCodeableConcept(model.TypeConceptKey, "http://snomed.info/sct"); retVal.Description = model.LoadCollection <EntityName>("Names").FirstOrDefault(o => o.NameUseKey == NameUseKeys.OfficialRecord)?.LoadCollection <EntityNameComponent>("Components")?.FirstOrDefault()?.Value; // TODO: Instance or kind if (model.DeterminerConceptKey == DeterminerKeys.Described) { retVal.Instance = model.GetRelationships().Where(o => o.RelationshipTypeKey == EntityRelationshipTypeKeys.Instance).Select(s => s.LoadProperty <Material>(nameof(EntityRelationship.TargetEntity))).Select(m => new Substance.InstanceComponent { ExpiryElement = DataTypeConverter.ToFhirDateTime(model.ExpiryDate), Identifier = DataTypeConverter.ToFhirIdentifier(m.GetIdentifiers().FirstOrDefault()), Quantity = DataTypeConverter.ToQuantity(m.Quantity, m.QuantityConceptKey) }).ToList(); } else if (model.DeterminerConceptKey == DeterminerKeys.Specific) { var conceptRepo = ApplicationServiceContext.Current.GetService <IConceptRepositoryService>(); retVal.Instance = new List <Substance.InstanceComponent> { new Substance.InstanceComponent { ExpiryElement = DataTypeConverter.ToFhirDateTime(model.ExpiryDate), Quantity = DataTypeConverter.ToQuantity(model.Quantity, model.QuantityConceptKey) } }; } return(retVal); }
/// <summary> /// Maps a <see cref="ManufacturedMaterial"/> instance to a FHIR <see cref="Medication"/> instance. /// </summary> /// <param name="model">The instance to map.</param> /// <returns>Returns the mapped instance.</returns> protected override Medication MapToFhir(ManufacturedMaterial model) { var retVal = DataTypeConverter.CreateResource <Medication>(model); // Code of medication code retVal.Code = DataTypeConverter.ToFhirCodeableConcept(model.TypeConceptKey, "http://snomed.info/sct"); retVal.Identifier = model.LoadCollection <EntityIdentifier>(nameof(Entity.Identifiers)).Select(DataTypeConverter.ToFhirIdentifier).ToList(); switch (model.StatusConceptKey.ToString().ToUpper()) { case StatusKeyStrings.Active: case StatusKeyStrings.New: retVal.Status = Medication.MedicationStatusCodes.Active; break; case StatusKeyStrings.Obsolete: retVal.Status = Medication.MedicationStatusCodes.Inactive; break; case StatusKeyStrings.Nullified: retVal.Status = Medication.MedicationStatusCodes.EnteredInError; break; } // Is brand? var manufacturer = model.LoadCollection <EntityRelationship>("Relationships").FirstOrDefault(o => o.RelationshipTypeKey == EntityRelationshipTypeKeys.ManufacturedProduct); if (manufacturer != null) { retVal.Manufacturer = DataTypeConverter.CreateVersionedReference <Organization>(manufacturer.LoadProperty <Entity>(nameof(EntityRelationship.TargetEntity))); } // Form retVal.Form = DataTypeConverter.ToFhirCodeableConcept(model.FormConceptKey, "http://hl7.org/fhir/ValueSet/medication-form-codes"); retVal.Batch = new Medication.BatchComponent { LotNumber = model.LotNumber, ExpirationDateElement = DataTypeConverter.ToFhirDateTime(model.ExpiryDate) }; return(retVal); }
/// <summary> /// Map a patient object to FHIR. /// </summary> /// <param name="model">The patient to map to FHIR</param> /// <returns>Returns the mapped FHIR resource.</returns> protected override Patient MapToFhir(Core.Model.Roles.Patient model) { // If the model is being constructed as part of a bundle, then the caller // should have included the bundle so we can add any related resources var partOfBundle = model.GetAnnotations <Bundle>().FirstOrDefault(); var retVal = DataTypeConverter.CreateResource <Patient>(model); retVal.Active = StatusKeys.ActiveStates.Contains(model.StatusConceptKey.Value); retVal.Address = model.GetAddresses().Select(DataTypeConverter.ToFhirAddress).ToList(); if (model.DateOfBirth.HasValue) { switch (model.DateOfBirthPrecision.GetValueOrDefault()) { case DatePrecision.Day: retVal.BirthDate = model.DateOfBirth.Value.ToString("yyyy-MM-dd"); break; case DatePrecision.Month: retVal.BirthDate = model.DateOfBirth.Value.ToString("yyyy-MM"); break; case DatePrecision.Year: retVal.BirthDate = model.DateOfBirth.Value.ToString("yyyy"); break; } } // Deceased precision if (model.DeceasedDate.HasValue) { if (model.DeceasedDate == DateTime.MinValue) { retVal.Deceased = new FhirBoolean(true); } else { switch (model.DeceasedDatePrecision) { case DatePrecision.Day: retVal.Deceased = new FhirDateTime(model.DeceasedDate.Value.Year, model.DeceasedDate.Value.Month, model.DeceasedDate.Value.Day); break; case DatePrecision.Month: retVal.Deceased = new FhirDateTime(model.DeceasedDate.Value.Year, model.DeceasedDate.Value.Month); break; case DatePrecision.Year: retVal.Deceased = new FhirDateTime(model.DeceasedDate.Value.Year); break; default: retVal.Deceased = DataTypeConverter.ToFhirDateTime(model.DeceasedDate); break; } } } if (model.GenderConceptKey.HasValue) { retVal.Gender = DataTypeConverter.ToFhirEnumeration <AdministrativeGender>(model.GenderConceptKey, "http://hl7.org/fhir/administrative-gender", true); } retVal.Identifier = model.Identifiers?.Select(DataTypeConverter.ToFhirIdentifier).ToList(); retVal.MultipleBirth = model.MultipleBirthOrder == 0 ? (DataType) new FhirBoolean(true) : model.MultipleBirthOrder.HasValue ? new Integer(model.MultipleBirthOrder.Value) : null; retVal.Name = model.GetNames().Select(DataTypeConverter.ToFhirHumanName).ToList(); retVal.Telecom = model.GetTelecoms().Select(DataTypeConverter.ToFhirTelecom).ToList(); retVal.Communication = model.GetPersonLanguages().Select(DataTypeConverter.ToFhirCommunicationComponent).ToList(); foreach (var rel in model.GetRelationships().Where(o => !o.InversionIndicator)) { if (rel.RelationshipTypeKey == EntityRelationshipTypeKeys.Contact) { var relEntity = rel.LoadProperty(o => o.TargetEntity); if (relEntity is Core.Model.Entities.Person person) { var contact = new Patient.ContactComponent() { ElementId = $"{person.Key}", Address = DataTypeConverter.ToFhirAddress(person.GetAddresses().FirstOrDefault()), Relationship = new List <CodeableConcept>() { DataTypeConverter.ToFhirCodeableConcept(rel.RelationshipRoleKey, "http://terminology.hl7.org/CodeSystem/v2-0131"), DataTypeConverter.ToFhirCodeableConcept(rel.RelationshipTypeKey, "http://terminology.hl7.org/CodeSystem/v2-0131") }.OfType <CodeableConcept>().ToList(), Name = DataTypeConverter.ToFhirHumanName(person.GetNames().FirstOrDefault()), // TODO: Gender Gender = DataTypeConverter.ToFhirEnumeration <AdministrativeGender>(person.GenderConceptKey, "http://hl7.org/fhir/administrative-gender"), Telecom = person.GetTelecoms().Select(t => DataTypeConverter.ToFhirTelecom(t)).ToList() }; var scoper = person.LoadCollection(o => o.Relationships).FirstOrDefault(o => o.RelationshipTypeKey == EntityRelationshipTypeKeys.Scoper); if (scoper != null) { contact.Organization = DataTypeConverter.CreateNonVersionedReference <Hl7.Fhir.Model.Organization>(scoper.LoadProperty(o => o.TargetEntity)); } DataTypeConverter.AddExtensions(person, contact); retVal.Contact.Add(contact); } else if (relEntity is Core.Model.Entities.Organization org) // it *IS* an organization { var contact = new Patient.ContactComponent() { ElementId = $"{org.Key}", Relationship = new List <CodeableConcept>() { DataTypeConverter.ToFhirCodeableConcept(rel.RelationshipRoleKey, "http://terminology.hl7.org/CodeSystem/v2-0131"), DataTypeConverter.ToFhirCodeableConcept(rel.RelationshipTypeKey, "http://terminology.hl7.org/CodeSystem/v2-0131") }.OfType <CodeableConcept>().ToList(), Organization = DataTypeConverter.CreateNonVersionedReference <Hl7.Fhir.Model.Organization>(org) }; retVal.Contact.Add(contact); } } else if (rel.RelationshipTypeKey == EntityRelationshipTypeKeys.Scoper) { var scoper = rel.LoadProperty(o => o.TargetEntity); retVal.ManagingOrganization = DataTypeConverter.CreateNonVersionedReference <Hl7.Fhir.Model.Organization>(scoper); // If this is part of a bundle, include it partOfBundle?.Entry.Add(new Bundle.EntryComponent { FullUrl = $"{MessageUtil.GetBaseUri()}/Organization/{scoper.Key}", Resource = FhirResourceHandlerUtil.GetMapperForInstance(scoper).MapToFhir(scoper) }); } else if (rel.RelationshipTypeKey == EntityRelationshipTypeKeys.HealthcareProvider) { var practitioner = rel.LoadProperty(o => o.TargetEntity); retVal.GeneralPractitioner.Add(DataTypeConverter.CreateVersionedReference <Practitioner>(practitioner)); // If this is part of a bundle, include it partOfBundle?.Entry.Add(new Bundle.EntryComponent { FullUrl = $"{MessageUtil.GetBaseUri()}/Practitioner/{practitioner.Key}", Resource = FhirResourceHandlerUtil.GetMapperForInstance(practitioner).MapToFhir(practitioner) }); } else if (rel.RelationshipTypeKey == EntityRelationshipTypeKeys.Replaces) { retVal.Link.Add(this.CreateLink <Patient>(rel.TargetEntityKey.Value, Patient.LinkType.Replaces)); } else if (rel.RelationshipTypeKey == EntityRelationshipTypeKeys.Duplicate) { retVal.Link.Add(this.CreateLink <Patient>(rel.TargetEntityKey.Value, Patient.LinkType.Seealso)); } else if (rel.RelationshipTypeKey == MDM_MASTER_LINK) // HACK: MDM Master Record { if (rel.SourceEntityKey.HasValue && rel.SourceEntityKey != model.Key) { retVal.Link.Add(this.CreateLink <Patient>(rel.SourceEntityKey.Value, Patient.LinkType.Seealso)); } else // Is a local { retVal.Link.Add(this.CreateLink <Patient>(rel.TargetEntityKey.Value, Patient.LinkType.Refer)); } } else if (rel.ClassificationKey == EntityRelationshipTypeKeys.EquivalentEntity) { retVal.Link.Add(this.CreateLink <Patient>(rel.TargetEntityKey.Value, Patient.LinkType.Refer)); } else if (partOfBundle != null) // This is part of a bundle and we need to include it { // HACK: This piece of code is used to add any RelatedPersons to the container bundle if it is part of a bundle if (this.GetRelatedPersonConceptUuids().Contains(rel.RelationshipTypeKey.Value)) { var relative = FhirResourceHandlerUtil.GetMapperForInstance(rel).MapToFhir(rel); partOfBundle.Entry.Add(new Bundle.EntryComponent() { FullUrl = $"{MessageUtil.GetBaseUri()}/RelatedPerson/{rel.Key}", Resource = relative }); } } } // Reverse relationships of family member? var uuids = model.Relationships.Where(r => r.RelationshipTypeKey == MDM_MASTER_LINK).Select(r => r.SourceEntityKey).Union(new Guid?[] { model.Key }).ToArray(); var familyMemberConcepts = this.GetFamilyMemberUuids(); var reverseRelationships = this.m_erRepository.Find(o => uuids.Contains(o.TargetEntityKey) && familyMemberConcepts.Contains(o.RelationshipTypeKey.Value) && o.ObsoleteVersionSequenceId == null); foreach (var rrv in reverseRelationships) { retVal.Link.Add(new Patient.LinkComponent { Type = Patient.LinkType.Seealso, Other = DataTypeConverter.CreateNonVersionedReference <RelatedPerson>(rrv) }); // If this is part of a bundle, include it partOfBundle?.Entry.Add(new Bundle.EntryComponent { FullUrl = $"{MessageUtil.GetBaseUri()}/RelatedPerson/{rrv.Key}", Resource = FhirResourceHandlerUtil.GetMappersFor(ResourceType.RelatedPerson).First().MapToFhir(rrv) }); } // Was this record replaced? if (!retVal.Active.GetValueOrDefault()) { var replacedRelationships = this.m_erRepository.Find(o => uuids.Contains(o.TargetEntityKey) && o.RelationshipTypeKey == EntityRelationshipTypeKeys.Replaces && o.ObsoleteVersionSequenceId == null); foreach (var repl in replacedRelationships) { retVal.Link.Add(new Patient.LinkComponent() { Type = Patient.LinkType.ReplacedBy, Other = DataTypeConverter.CreateNonVersionedReference <Patient>(repl.LoadProperty(o => o.SourceEntity)), }); } } var photo = model.LoadCollection(o => o.Extensions).FirstOrDefault(o => o.ExtensionTypeKey == ExtensionTypeKeys.JpegPhotoExtension); if (photo != null) { retVal.Photo = new List <Attachment> { new Attachment { ContentType = "image/jpg", Data = photo.ExtensionValueXml } }; } return(retVal); }
/// <summary> /// Map to FHIR /// </summary> protected override Observation MapToFhir(Core.Model.Acts.Observation model) { var retVal = DataTypeConverter.CreateResource <Observation>(model); retVal.Identifier = model.LoadCollection <ActIdentifier>(nameof(Act.Identifiers)).Select(o => DataTypeConverter.ToFhirIdentifier(o)).ToList(); switch (model.StatusConceptKey.ToString().ToUpper()) { case StatusKeyStrings.New: case StatusKeyStrings.Active: retVal.Status = ObservationStatus.Preliminary; break; case StatusKeyStrings.Cancelled: retVal.Status = ObservationStatus.Cancelled; break; case StatusKeyStrings.Nullified: retVal.Status = ObservationStatus.EnteredInError; break; case StatusKeyStrings.Completed: if (model.LoadCollection <ActRelationship>(nameof(Act.Relationships)).Any(o => o.RelationshipTypeKey == ActRelationshipTypeKeys.Replaces)) // was amended { retVal.Status = ObservationStatus.Amended; } else { retVal.Status = ObservationStatus.Final; } break; case StatusKeyStrings.Obsolete: retVal.Status = ObservationStatus.Unknown; break; } if (model.StartTime.HasValue || model.StopTime.HasValue) { retVal.Effective = DataTypeConverter.ToPeriod(model.StartTime, model.StopTime); } else { retVal.Effective = DataTypeConverter.ToFhirDateTime(model.ActTime); } retVal.Code = DataTypeConverter.ToFhirCodeableConcept(model.TypeConceptKey); // RCT var rct = model.LoadCollection <ActParticipation>(nameof(Act.Participations)).FirstOrDefault(o => o.ParticipationRoleKey == ActParticipationKey.RecordTarget); if (rct != null) { retVal.Subject = DataTypeConverter.CreateNonVersionedReference <Patient>(rct.LoadProperty <Entity>(nameof(ActParticipation.PlayerEntity))); } // Performer retVal.Performer = model.Participations.Where(o => o.ParticipationRoleKey == ActParticipationKey.Performer) .Select(o => DataTypeConverter.CreateNonVersionedReference <Practitioner>(o.LoadProperty <Entity>(nameof(ActParticipation.PlayerEntity)))) .ToList(); retVal.Issued = model.CreationTime; // Value switch (model.ValueType) { case "CD": retVal.Value = DataTypeConverter.ToFhirCodeableConcept((model as CodedObservation).ValueKey); break; case "PQ": var qty = model as QuantityObservation; retVal.Value = DataTypeConverter.ToQuantity(qty.Value, qty.UnitOfMeasureKey); break; case "ED": case "ST": retVal.Value = new FhirString((model as TextObservation).Value); break; } if (model.InterpretationConceptKey.HasValue) { retVal.Interpretation = new List <CodeableConcept> { DataTypeConverter.ToFhirCodeableConcept(model.InterpretationConceptKey) }; } return(retVal); }