/// <summary> /// Transforms the HL7 v2 diagnostic imaging message into a MHR compliant CDA document. /// </summary> /// <param name="message">HL7 message model.</param> /// <param name="metadata">Additional data required from the source system.</param> /// <param name="reportData"></param> /// <returns>Transformed diagnostic imaging report model</returns> public DiagnosticImagingTransformResult Transform(HL7GenericMessage message, DiagnosticImagingMetadata metadata, byte[] reportData = null) { _diagnosticImagingMessageValidator.Validate(message, metadata, reportData); return(_diagnosticImagingMessageTransformer.Transform(message, metadata, reportData)); }
/// <summary> /// Creates a DiagnosticImagingMetadata instance for this sample. /// </summary> /// <returns></returns> public static DiagnosticImagingMetadata CreateRequiredMetadataForDiagnosticImagingCdaTransform() { DiagnosticImagingMetadata metadata = new DiagnosticImagingMetadata(); // Author organisation HPIO metadata.AuthorOrganisationHpio = "8003628233352432"; // Report identifier metadata.AccessionNumber = BaseCDAModel.CreateIdentifier("1.2.36.1.2001.1005.54.8003628233352432", "HOM07051718571.7841"); // Requester order identifier metadata.RequesterOrderIdentifier = BaseCDAModel.CreateIdentifier("1.2.36.1.2001.1005.52.8003628233352432", "100041"); // Reporting pathologist metadata.ReportingRadiologist = new ReportingRadiologist(); metadata.ReportingRadiologist.Hpii = "8003610102030405"; // Hpii must be set here, or provided in OBR-32 of HL7 V2 report metadata.ReportingRadiologist.OrganisationHpio = "8003628233352432"; metadata.ReportingRadiologist.Role = Occupation.Pathologist; // Reporting pathologist - address var address = BaseCDAModel.CreateAddress(); address.AddressPurpose = AddressPurpose.Business; address.AustralianAddress = BaseCDAModel.CreateAustralianAddress(); address.AustralianAddress.UnstructuredAddressLines = new List <string> { "400 George Street" }; address.AustralianAddress.PostCode = "4000"; address.AustralianAddress.State = AustralianState.QLD; metadata.ReportingRadiologist.Address = new List <IAddress>() { address }; // Reporting pathologist - contact details var coms = BaseCDAModel.CreateElectronicCommunicationDetail( "(08) 8888 6666", ElectronicCommunicationMedium.Telephone, ElectronicCommunicationUsage.WorkPlace); metadata.ReportingRadiologist.ContactDetails = new List <ElectronicCommunicationDetail>() { coms }; return(metadata); }
/// <summary> /// Validates the specified HL7 generic diagnostic imaging message. /// </summary> /// <param name="hl7GenericMessage">The HL7 generic diagnostic imaging message.</param> /// <param name="metadata">The metadata instance providing required information.</param> /// <param name="reportData">The diagnostic imaging report data, if not included in the path message.</param> /// <exception cref="MessageValidationException">hl7GenericMessage</exception> public void Validate(HL7GenericMessage hl7GenericMessage, DiagnosticImagingMetadata metadata, byte[] reportData) { if (hl7GenericMessage == null) { throw new MessageValidationException(nameof(hl7GenericMessage)); } if (metadata == null) { throw new MessageValidationException(nameof(metadata)); } ValidatePatientIdentification(hl7GenericMessage); ValidateOrder(hl7GenericMessage, metadata); ValidateAttachment(hl7GenericMessage, reportData); ValidateMetadata(metadata); }
/// <summary> /// Sample code showing how an HL7 V2 diagnostic imaging message is transformed into a CDA document. /// </summary> public static void TransformHL7V2DiagnosticImagingToCdaDocumentSample() { // Obtain HL7 V2 report in a string. var v2DiagnosticImagingText = File.ReadAllText($"{AppContext.BaseDirectory}/Sample/imagingreport.hl7"); // Create an instance of the DiagnosticImagingTransformer. IDiagnosticImagingTransformer cdaImagingTransformer = new DiagnosticImagingTransformer(); // Parse the HL7 V2 string into an object model of the diagnostic imaging message. HL7GenericMessage hl7Message = cdaImagingTransformer.ParseHl7Message(v2DiagnosticImagingText); // Create a DiagnosticImagingMetadata instance (to provide additional information required for CDA document generation, that is not // available from the HL7 V2 report). DiagnosticImagingMetadata requiredMetadata = CreateRequiredMetadataForDiagnosticImagingCdaTransform(); // Transform the diagnostic imaging message into a DiagnosticImagingTransformResult. DiagnosticImagingTransformResult contains two // properties: // 1) DiagnosticImagingReport - This is the object model of the diagnostic imaging report CDA document. Prior to CDA document generation, // you can modify this instance to include more information for the CDA document. // 2) Attachment - This contains the byte array of the extracted report attachment // Note: reportData argument must not be supplied if the report attachment is found within the HL7 V2 report. Otherwise, reportData // has to be provided in this function. DiagnosticImagingTransformResult imagingTransformResult = cdaImagingTransformer.Transform(hl7Message, requiredMetadata); // This would be how you insert and external report not embedded in the OBX ED segment // byte[] reportdata = File.ReadAllBytes($"{AppContext.BaseDirectory}/Sample/prdfreport.pdf"); // DiagnosticImagingTransformResult imagingTransformResult = cdaImagingTransformer.Transform(hl7Message, requiredMetadata, reportdata); // An example of how you can modify DiagnosticImagingReport instance to include more information for the CDA document. // For more examples, please view the CDA.R5Samples project. imagingTransformResult.DiagnosticImagingReport.SCSContext.Author.Participant.Person.Organisation.Name = "Sample Organisation Name"; // Generates the CDA document XML XmlDocument cdaDocument = cdaImagingTransformer.Generate(imagingTransformResult.DiagnosticImagingReport); // Save the CDA document XML to file cdaDocument.Save($"{AppContext.BaseDirectory}/cdadocument.xml"); // Save the report attachment to file File.WriteAllBytes($"{AppContext.BaseDirectory}/{imagingTransformResult.Attachment.Filename}", imagingTransformResult.Attachment.Data); }
/// <summary> /// Validate metadata instance. /// </summary> /// <param name="metadata">Metadata instance to validate.</param> internal static void ValidateMetadata(DiagnosticImagingMetadata metadata) { if (metadata.AccessionNumber == null) { throw new ArgumentNullException(nameof(metadata.AccessionNumber)); } if (String.IsNullOrEmpty(metadata.AccessionNumber.Root)) { throw new ArgumentNullException(nameof(metadata.AccessionNumber.Root)); } if (String.IsNullOrEmpty(metadata.AccessionNumber.Extension)) { throw new ArgumentNullException(nameof(metadata.AccessionNumber.Extension)); } if (metadata.RequesterOrderIdentifier == null) { throw new ArgumentNullException(nameof(metadata.RequesterOrderIdentifier)); } if (String.IsNullOrEmpty(metadata.RequesterOrderIdentifier.Root)) { throw new ArgumentNullException(nameof(metadata.RequesterOrderIdentifier.Root)); } if (String.IsNullOrEmpty(metadata.RequesterOrderIdentifier.Extension)) { throw new ArgumentNullException(nameof(metadata.RequesterOrderIdentifier.Extension)); } //Required has to be HPI-O if (String.IsNullOrEmpty(metadata.AuthorOrganisationHpio)) { throw new ArgumentNullException(nameof(metadata.AuthorOrganisationHpio)); } if (!metadata.AuthorOrganisationHpio.StartsWith("80036")) { throw new ArgumentException(nameof(metadata.AuthorOrganisationHpio)); } //Required if (metadata.ReportingRadiologist == null) { throw new ArgumentNullException(nameof(metadata.ReportingRadiologist)); } if (metadata.ReportingRadiologist.Address == null || !metadata.ReportingRadiologist.Address.Any()) { throw new ArgumentNullException(nameof(metadata.ReportingRadiologist.Address)); } if (String.IsNullOrEmpty(metadata.ReportingRadiologist.OrganisationHpio)) { throw new ArgumentNullException(nameof(metadata.ReportingRadiologist.OrganisationHpio)); } if (!metadata.ReportingRadiologist.OrganisationHpio.StartsWith("80036")) { throw new ArgumentException(nameof(metadata.ReportingRadiologist.OrganisationHpio)); } //Role SHOULD have a value chosen from 1220.0 - ANZSCO - Australian and New Zealand Standard Classification of Occupations, First Edition, Revision 1[ABS2009] Occupation role; if (!Enum.TryParse(metadata.ReportingRadiologist.Role.ToString(), out role)) { throw new ArgumentException(nameof(metadata.ReportingRadiologist.Role)); } if (metadata.ReportingRadiologist.Address.Any(y => y.AustralianAddress == null)) { throw new ArgumentNullException(nameof(metadata.ReportingRadiologist.Address)); } if (metadata.ReportingRadiologist.Address.Any(y => y.AddressPurpose != AddressPurpose.Business)) { throw new ArgumentException(nameof(metadata.ReportingRadiologist.ContactDetails)); } if (!metadata.ReportingRadiologist.ContactDetails.All(x => x.Usage != null && x.Usage.Any(y => y == ElectronicCommunicationUsage.WorkPlace))) { throw new ArgumentException(nameof(metadata.ReportingRadiologist.ContactDetails)); } }
/// <summary> /// Validates the order. /// </summary> /// <param name="hl7GenericMessage">The HL7 generic message.</param> /// <param name="metadata">Diagnostic Imaging metadata instance.</param> /// <exception cref="MessageValidationException"> /// Order /// or /// Observation /// or /// ObservationsReportID /// </exception> internal static void ValidateOrder(HL7GenericMessage hl7GenericMessage, DiagnosticImagingMetadata metadata) { if (hl7GenericMessage.Order?.First().Observation?.First().ObservationsReportID?.PrincipalResultInterpreter? .name?.assigningauthority?.namespaceID != TransformerConstants.Aushic && String.IsNullOrEmpty(metadata.ReportingRadiologist.Hpii)) { throw new MessageValidationException("ReportingRadiologist.Hpii must be set in the metadata, if not provided in OBR-32 of the HL7 V2 message."); } if (hl7GenericMessage.Order == null || hl7GenericMessage.Order.Length == 0) { throw new MessageValidationException(nameof(hl7GenericMessage.Order)); } foreach (OrderGroup orderGroup in hl7GenericMessage.Order) { if (orderGroup.Observation == null || orderGroup.Observation.Length == 0) { throw new MessageValidationException(nameof(orderGroup.Observation)); } foreach (ObservationGroup observationGroup in orderGroup.Observation) { OBR obrSegment = observationGroup.ObservationsReportID; if (observationGroup.ObservationsReportID == null) { throw new MessageValidationException(nameof(observationGroup.ObservationsReportID)); } if (obrSegment.UniversalServiceID?.identifier == null) { throw new MessageValidationException("Message OBR contains no UniversalServiceID.identifier"); } if (obrSegment.UniversalServiceID.identifier != TransformerConstants.ReportText) { if (obrSegment.ResultsRptStatusChngDateTime == null || !obrSegment.ResultsRptStatusChngDateTime.Any(r => r.TimestampValue.HasValue)) { throw new MessageValidationException(ConstantsResource.InvalidResultsDateTime); } if (obrSegment.UniversalServiceID == null || String.IsNullOrEmpty(obrSegment.UniversalServiceID.alternatetext ?? obrSegment.UniversalServiceID.text)) { throw new MessageValidationException(ConstantsResource.NoTestResultNameSupplied); } if (obrSegment.ObservationDateTime?.TimestampValue == null) { throw new MessageValidationException(ConstantsResource.InvalidObservationDateTime); } Hl7V3ResultStatus hl7V3ResultStatus; if (!EnumHelper.TryGetEnumValue <Hl7V3ResultStatus, NameAttribute>(attribute => attribute.Code == obrSegment.ResultStatus, out hl7V3ResultStatus)) { throw new MessageValidationException(ConstantsResource.IncorrectTestResultStatusSupplied); } if (obrSegment.UniversalServiceID.text == null && obrSegment.UniversalServiceID.alternatetext == null) { throw new MessageValidationException("Message OBR contains no UniversalServiceID value"); } ValidatePrincipalResultInterpreter(obrSegment.PrincipalResultInterpreter); } } ValidateOrderingProvider(orderGroup); } }
/// <summary> /// Create a DiagnosticImagingTransformResult instance (containing a DiagnosticImagingReport and a ReportAttachment instance) from a /// HL7 V2 diagnostic imaging message. The DiagnosticImagingTransformResult instance is then used to generate a CDA document. /// </summary> /// <param name="hl7GenericMessage">The HL7 V2 message to transform.</param> /// <param name="metadata">Mandatory information to supplement the transform.</param> /// <param name="reportData">Report data.</param> /// <returns></returns> internal DiagnosticImagingTransformResult Transform(HL7GenericMessage hl7GenericMessage, DiagnosticImagingMetadata metadata, byte[] reportData = null) { DiagnosticImagingReport diagnosticImagingReport = DiagnosticImagingReport.CreateDiagnosticImagingReport(); // Include Logo diagnosticImagingReport.IncludeLogo = false; // Set Creation Time diagnosticImagingReport.DocumentCreationTime = GetResultsReportStatusChange(hl7GenericMessage); // Document Status diagnosticImagingReport.DocumentStatus = GetReportStatus(hl7GenericMessage); #region Setup and populate the CDA context model // CDA Context model var cdaContext = DiagnosticImagingReport.CreateCDAContext(); // Document Id cdaContext.DocumentId = BaseCDAModel.CreateIdentifier(BaseCDAModel.CreateOid(), null); // Set Id cdaContext.SetId = BaseCDAModel.CreateIdentifier(BaseCDAModel.CreateGuid(), null); // CDA Context Version cdaContext.Version = "1"; // Legal Authenticator cdaContext.LegalAuthenticator = CreateLegalAuthenticator(hl7GenericMessage); // Custodian cdaContext.Custodian = BaseCDAModel.CreateCustodian(); ICustodian custodian = BaseCDAModel.CreateParticipantCustodian(); cdaContext.Custodian.Participant = custodian; diagnosticImagingReport.CDAContext = cdaContext; #endregion #region Setup and Populate the SCS Context model // SCS Context model diagnosticImagingReport.SCSContext = DiagnosticImagingReport.CreateSCSContext(); // Author Health Care Provider diagnosticImagingReport.SCSContext.Author = CreateAuthor(hl7GenericMessage); // The Reporting Radiologist diagnosticImagingReport.SCSContext.ReportingRadiologist = CreateReportingRadiologist(hl7GenericMessage); // Order Details diagnosticImagingReport.SCSContext.OrderDetails = CreateOrderDetails(hl7GenericMessage); // Subject Of Care diagnosticImagingReport.SCSContext.SubjectOfCare = CreateSubjectOfCare(hl7GenericMessage); #endregion #region Setup and populate the SCS Content model // SCS Content model diagnosticImagingReport.SCSContent = DiagnosticImagingReport.CreateSCSContent(); ReportAttachment reportAttachment = GetReportAttachment(hl7GenericMessage, reportData); // Imaging Examination Results diagnosticImagingReport.SCSContent.ImagingExaminationResults = CreateImagingExaminationResults(hl7GenericMessage); // Related Document diagnosticImagingReport.SCSContent.RelatedDocument = CreateRelatedDocument(hl7GenericMessage, reportAttachment); #endregion FillInAdditionalMetadata(diagnosticImagingReport, metadata); return(new DiagnosticImagingTransformResult { DiagnosticImagingReport = diagnosticImagingReport, Attachment = reportAttachment }); }
/// <summary> /// Fill in additional required information in the DiagnosticImagingReport. /// </summary> /// <param name="report">The DiagnosticImagingReport to complete.</param> /// <param name="metadata">Metadata information.</param> internal static void FillInAdditionalMetadata(DiagnosticImagingReport report, DiagnosticImagingMetadata metadata) { report.SCSContext.OrderDetails.RequesterOrderIdentifier = metadata.RequesterOrderIdentifier; report.SCSContext.OrderDetails.AccessionNumber = metadata.AccessionNumber; // Author report.SCSContext.Author.Participant.Person.Organisation = BaseCDAModel.CreateEmploymentOrganisation(); report.SCSContext.Author.Participant.Person.Organisation.Identifiers = new List <Identifier> { BaseCDAModel.CreateHealthIdentifier(HealthIdentifierType.HPIO, metadata.AuthorOrganisationHpio) }; // Reporting radiologist report.SCSContext.ReportingRadiologist.Role = DiagnosticImagingReport.CreateRole(metadata.ReportingRadiologist.Role, CodingSystem.ANZSCO); report.SCSContext.ReportingRadiologist.Participant.Addresses = metadata.ReportingRadiologist.Address; report.SCSContext.ReportingRadiologist.Participant.ElectronicCommunicationDetails = metadata.ReportingRadiologist.ContactDetails; report.SCSContext.ReportingRadiologist.Participant.Person.Organisation = BaseCDAModel.CreateEmploymentOrganisation(); report.SCSContext.ReportingRadiologist.Participant.Person.Organisation.Identifiers = new List <Identifier> { BaseCDAModel.CreateHealthIdentifier(HealthIdentifierType.HPIO, metadata.ReportingRadiologist.OrganisationHpio) }; }