Пример #1
0
        /// <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)
            };
        }