/// <summary>
        /// Creates a PathologyMetadata instance for this sample.
        /// </summary>
        /// <returns></returns>
        public static PathologyMetadata CreateRequiredMetadataForPathologyCdaTransform()
        {
            PathologyMetadata metadata = new PathologyMetadata();

            // Author organisation HPIO
            metadata.AuthorOrganisationHpio = "8003628233352432";

            // Report identifier
            metadata.ReportIdentifier = 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.ReportingPathologist                  = new ReportingPathologist();
            metadata.ReportingPathologist.Hpii             = "8003610102030405"; // Hpii must be set here, or provided in OBR-32 of HL7 V2 report
            metadata.ReportingPathologist.OrganisationHpio = "8003628233352432";
            metadata.ReportingPathologist.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.ReportingPathologist.Address = new List <IAddress>()
            {
                address
            };

            // Reporting pathologist - contact details
            var coms = BaseCDAModel.CreateElectronicCommunicationDetail(
                "(08) 8888 6666",
                ElectronicCommunicationMedium.Telephone,
                ElectronicCommunicationUsage.WorkPlace);

            metadata.ReportingPathologist.ContactDetails = new List <ElectronicCommunicationDetail>()
            {
                coms
            };

            return(metadata);
        }
        /// <summary>
        /// Validates the specified HL7 generic path message.
        /// </summary>
        /// <param name="hl7GenericMessage">The HL7 generic message.</param>
        /// <param name="metadata">The metadata instance providing required information.</param>
        /// <param name="reportData">The pathology report data, if not included in the path message.</param>
        /// <exception cref="MessageValidationException">hl7GenericMessage</exception>
        public void Validate(HL7GenericMessage hl7GenericMessage, PathologyMetadata 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);
        }
Example #3
0
        /// <summary>
        /// Fill in additional required information in the PathologyResultReport.
        /// </summary>
        /// <param name="report">The PathologyResultReport to complete.</param>
        /// <param name="metadata">Metadata information.</param>
        internal static void FillInAdditionalMetadata(PathologyResultReport report, PathologyMetadata metadata)
        {
            report.SCSContext.OrderDetails.RequesterOrderIdentifier            = metadata.RequesterOrderIdentifier;
            report.SCSContent.RelatedDocument.DocumentDetails.ReportIdentifier = metadata.ReportIdentifier;

            // 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 pathologist
            report.SCSContext.ReportingPathologist.Role = PathologyResultReport.CreateRole(metadata.ReportingPathologist.Role, CodingSystem.ANZSCO);
            report.SCSContext.ReportingPathologist.Participant.Addresses = metadata.ReportingPathologist.Address;
            report.SCSContext.ReportingPathologist.Participant.ElectronicCommunicationDetails  = metadata.ReportingPathologist.ContactDetails;
            report.SCSContext.ReportingPathologist.Participant.Person.Organisation             = BaseCDAModel.CreateEmploymentOrganisation();
            report.SCSContext.ReportingPathologist.Participant.Person.Organisation.Identifiers = new List <Identifier> {
                BaseCDAModel.CreateHealthIdentifier(HealthIdentifierType.HPIO, metadata.ReportingPathologist.OrganisationHpio)
            };
        }
        /// <summary>
        /// Sample code showing how an HL7 V2 pathology message is transformed into a CDA document.
        /// </summary>
        public static void TransformHL7V2PathologyToCdaDocumentSample()
        {
            // Obtain HL7 V2 report in a string.
            var v2PathologyText = File.ReadAllText($"{AppContext.BaseDirectory}/Sample/pathologyreport.hl7");

            // Create an instance of the PathologyTransformer.
            IPathologyTransformer cdaPathologyTransformer = new PathologyTransformer();

            // Parse the HL7 V2 string into an object model of the pathology message.
            HL7GenericMessage hl7Message = cdaPathologyTransformer.ParseHl7Message(v2PathologyText);

            // Create a PathologyMetadata instance (to provide additional information required for CDA document generation, that is not
            // available from the HL7 V2 report).
            PathologyMetadata requiredMetadata = CreateRequiredMetadataForPathologyCdaTransform();

            // Transform the pathology message into a PathologyTransformResult. PathologyTransformResult contains two properties:
            // 1) PathologyResultReport - This is the object model of the pathology 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.
            PathologyTransformResult pathologyTransformResult = cdaPathologyTransformer.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");
            // PathologyTransformResult pathologyTransformResult = cdaPathologyTransformer.Transform(hl7Message, requiredMetadata, reportdata);

            // An example of how you can modify PathologyResultReport instance to include more information for the CDA document.
            // For more examples, please view the CDA.R5Samples project.
            pathologyTransformResult.PathologyResultReport.SCSContext.Author.Participant.Person.Organisation.Name = "Sample Organisation Name";

            // Generates the CDA document XML
            XmlDocument cdaDocument = cdaPathologyTransformer.Generate(pathologyTransformResult.PathologyResultReport);

            // Save the CDA document XML to file
            cdaDocument.Save($"{AppContext.BaseDirectory}/cdadocument.xml");

            // Save the report attachment to file
            File.WriteAllBytes($"{AppContext.BaseDirectory}/{pathologyTransformResult.Attachment.Filename}", pathologyTransformResult.Attachment.Data);
        }
        /// <summary>
        /// Transforms the HL7 v2 pathology message into a MHR compliant CDA document.
        /// </summary>
        /// <param name="message">HL7 pathology message model.</param>
        /// <param name="metadata">Additional data required from the source system.</param>
        /// <param name="reportData"></param>
        /// <returns>Transformed pathology report model</returns>
        public PathologyTransformResult Transform(HL7GenericMessage message, PathologyMetadata metadata, byte[] reportData = null)
        {
            _pathologyMessageValidator.Validate(message, metadata, reportData);

            return(_pathologyMessageTransformer.Transform(message, metadata, reportData));
        }
Example #6
0
        /// <summary>
        /// Create a PathologyTransformResult instance (containing a PathologyResultReport and a ReportAttachment instance) from a HL7 V2 pathology message.
        /// The PathologyTransformResult 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 PathologyTransformResult Transform(HL7GenericMessage hl7GenericMessage, PathologyMetadata metadata, byte[] reportData = null)
        {
            PathologyResultReport pathologyResultReport = PathologyResultReport.CreatePathologyResultReport();

            // Include Logo
            pathologyResultReport.IncludeLogo = false;

            // Set Creation Time
            pathologyResultReport.DocumentCreationTime = GetResultsReportStatusChange(hl7GenericMessage);

            // Document Status
            pathologyResultReport.DocumentStatus = GetReportStatus(hl7GenericMessage);

            #region Setup and populate the CDA context model

            // CDA Context model
            var cdaContext = PathologyResultReport.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;

            pathologyResultReport.CDAContext = cdaContext;

            #endregion

            #region Setup and Populate the SCS Context model

            // SCS Context model
            pathologyResultReport.SCSContext = PathologyResultReport.CreateSCSContext();

            // Author Health Care Provider
            pathologyResultReport.SCSContext.Author = CreateAuthor(hl7GenericMessage);

            // The Reporting Pathologist
            pathologyResultReport.SCSContext.ReportingPathologist = CreateReportingPathologist(hl7GenericMessage);

            // Order Details
            pathologyResultReport.SCSContext.OrderDetails = CreateOrderDetails(hl7GenericMessage);

            // Subject Of Care
            pathologyResultReport.SCSContext.SubjectOfCare = CreateSubjectOfCare(hl7GenericMessage);

            #endregion

            #region Setup and populate the SCS Content model

            // SCS Content model
            pathologyResultReport.SCSContent = PathologyResultReport.CreateSCSContent();

            ReportAttachment reportAttachment = GetReportAttachment(hl7GenericMessage, reportData);

            // Pathology Test Result
            pathologyResultReport.SCSContent.PathologyTestResult = CreatePathologyTestResults(hl7GenericMessage);

            // Related Document
            pathologyResultReport.SCSContent.RelatedDocument = CreateRelatedDocument(hl7GenericMessage, reportAttachment);

            #endregion

            FillInAdditionalMetadata(pathologyResultReport, metadata);

            return(new PathologyTransformResult
            {
                PathologyResultReport = pathologyResultReport,
                Attachment = reportAttachment
            });
        }
        /// <summary>
        /// Validate metadata instance.
        /// </summary>
        /// <param name="metadata">Metadata instance to validate.</param>
        internal static void ValidateMetadata(PathologyMetadata metadata)
        {
            if (metadata.ReportIdentifier == null)
            {
                throw new ArgumentNullException(nameof(metadata.ReportIdentifier));
            }

            if (String.IsNullOrEmpty(metadata.ReportIdentifier.Root))
            {
                throw new ArgumentNullException(nameof(metadata.ReportIdentifier.Root));
            }

            if (String.IsNullOrEmpty(metadata.ReportIdentifier.Extension))
            {
                throw new ArgumentNullException(nameof(metadata.ReportIdentifier.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.ReportingPathologist == null)
            {
                throw new ArgumentNullException(nameof(metadata.ReportingPathologist));
            }

            if (metadata.ReportingPathologist.Address == null || !metadata.ReportingPathologist.Address.Any())
            {
                throw new ArgumentNullException(nameof(metadata.ReportingPathologist.Address));
            }

            if (String.IsNullOrEmpty(metadata.ReportingPathologist.OrganisationHpio))
            {
                throw new ArgumentNullException(nameof(metadata.ReportingPathologist.OrganisationHpio));
            }

            if (!metadata.ReportingPathologist.OrganisationHpio.StartsWith("80036"))
            {
                throw new ArgumentException(nameof(metadata.ReportingPathologist.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.ReportingPathologist.Role.ToString(), out role))
            {
                throw new ArgumentException(nameof(metadata.ReportingPathologist.Role));
            }

            if (metadata.ReportingPathologist.Address.Any(y => y.AustralianAddress == null))
            {
                throw new ArgumentNullException(nameof(metadata.ReportingPathologist.Address));
            }

            if (metadata.ReportingPathologist.Address.Any(y => y.AddressPurpose != AddressPurpose.Business))
            {
                throw new ArgumentException(nameof(metadata.ReportingPathologist.ContactDetails));
            }

            if (!metadata.ReportingPathologist.ContactDetails.All(x => x.Usage != null && x.Usage.Any(y => y == ElectronicCommunicationUsage.WorkPlace)))
            {
                throw new ArgumentException(nameof(metadata.ReportingPathologist.ContactDetails));
            }
        }
        /// <summary>
        /// Validates the order.
        /// </summary>
        /// <param name="hl7GenericMessage">The HL7 generic message.</param>
        /// <param name="metadata">Pathology metadata instance.</param>
        /// <exception cref="MessageValidationException">
        /// Order
        /// or
        /// Observation
        /// or
        /// ObservationsReportID
        /// </exception>
        internal static void ValidateOrder(HL7GenericMessage hl7GenericMessage, PathologyMetadata metadata)
        {
            if (hl7GenericMessage.Order?.First().Observation?.First().ObservationsReportID?.PrincipalResultInterpreter?
                .name?.assigningauthority?.namespaceID != TransformerConstants.Aushic &&
                String.IsNullOrEmpty(metadata.ReportingPathologist.Hpii))
            {
                throw new MessageValidationException("ReportingPathologist.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);
            }
        }