/// <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);
        }
Пример #2
0
        /// <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);
        }
Пример #3
0
        /// <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);
        }
Пример #5
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, 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);
        }
Пример #6
0
        /// <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);
        }
Пример #7
0
        /// <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);
        }
Пример #8
0
        /// <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);
        }
Пример #11
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);
        }
        /// <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);
        }
Пример #13
0
        /// <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);
        }
Пример #14
0
        /// <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);
        }