/// <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); }
/// <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)); }
/// <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); } }