def hl7ACK(request, ack_type, err_description='', message_type=None, extra_segments=None): """ Generate a HL7 ACK message for a given request message This is used early on in the communications code and should not be used by the application. The default ack type is ACK^req type. This can be replaced by passing in a message type, e.g. "MFK^M01" for a master file notification ack message. """ serial = next_serial() if extra_segments is None: extra_segments = [] ack_type = ack_type.upper() iMSH = request['MSH'][0] local_fac, local_app = iMSH[5], iMSH[4] remote_fac, remote_app = iMSH[3], iMSH[2] req_message_type = iMSH[8] version_id = iMSH[11] control_id = iMSH[9] if not message_type: message_type = hl7.Field(SEP[1], ['ACK', req_message_type[1]]) elif type(message_type) not in [hl7.Field, str, unicode]: message_type = hl7.Field(SEP[1], message_type) # assume list MSH = hl7.Segment(SEP[0], ['MSH', SEP[1:], local_app , local_fac, remote_app, remote_fac, timestamp(), '', message_type, str(serial), 'P', version_id, '']) MSA = hl7.Segment(SEP[0], ['MSA', ack_type, control_id, err_description]) response = hl7.Message(CR_SEP, [MSH, MSA] + extra_segments) return response
def test_create_msg(self): # Create a message MSH = hl7.Segment(SEP[0], [hl7.Field(SEP[1], ["MSH"])]) MSA = hl7.Segment(SEP[0], [hl7.Field(SEP[1], ["MSA"])]) response = hl7.Message(CR_SEP, [MSH, MSA]) response["MSH.F1.R1"] = SEP[0] response["MSH.F2.R1"] = SEP[1:] self.assertEqual(str(response), "MSH|^~\\&|\rMSA\r")
def test_create_msg(self): # Create a message MSH = hl7.Segment(SEP[0], [hl7.Field(SEP[1], ['MSH'])]) MSA = hl7.Segment(SEP[0], [hl7.Field(SEP[1], ['MSA'])]) response = hl7.Message(CR_SEP, [MSH, MSA]) response['MSH.F1.R1'] = SEP[0] response['MSH.F2.R1'] = SEP[1:] self.assertEqual(six.text_type(response), 'MSH|^~\\&|\rMSA')
def test_append(self): # Append a segment to a message MSH = hl7.Segment(SEP[0], [hl7.Field(SEP[1], ["MSH"])]) response = hl7.Message(CR_SEP, [MSH]) response["MSH.F1.R1"] = SEP[0] response["MSH.F2.R1"] = SEP[1:] MSA = hl7.Segment(SEP[0], [hl7.Field(SEP[1], ["MSA"])]) response.append(MSA) self.assertEqual(str(response), "MSH|^~\\&|\rMSA\r")
def test_append(self): # Append a segment to a message MSH = hl7.Segment(SEP[0], [hl7.Field(SEP[1], ['MSH'])]) response = hl7.Message(CR_SEP, [MSH]) response['MSH.F1.R1'] = SEP[0] response['MSH.F2.R1'] = SEP[1:] MSA = hl7.Segment(SEP[0], [hl7.Field(SEP[1], ['MSA'])]) response.append(MSA) self.assertEqual(six.text_type(response), 'MSH|^~\\&|\rMSA')
def test_append_from_source(self): # Copy a segment between messages MSH = hl7.Segment(SEP[0], [hl7.Field(SEP[1], ["MSH"])]) MSA = hl7.Segment(SEP[0], [hl7.Field(SEP[1], ["MSA"])]) response = hl7.Message(CR_SEP, [MSH, MSA]) response["MSH.F1.R1"] = SEP[0] response["MSH.F2.R1"] = SEP[1:] self.assertEqual(str(response), "MSH|^~\\&|\rMSA\r") src_msg = hl7.parse(rep_sample_hl7) PID = src_msg["PID"][0] self.assertEqual( str(PID), "PID|Field1|Component1^Component2|Component1^Sub-Component1&Sub-Component2^Component3|Repeat1~Repeat2", ) response.append(PID) self.assertEqual( str(response), "MSH|^~\\&|\rMSA\rPID|Field1|Component1^Component2|Component1^Sub-Component1&Sub-Component2^Component3|Repeat1~Repeat2\r", )
def test_append_from_source(self): # Copy a segment between messages MSH = hl7.Segment(SEP[0], [hl7.Field(SEP[1], ['MSH'])]) MSA = hl7.Segment(SEP[0], [hl7.Field(SEP[1], ['MSA'])]) response = hl7.Message(CR_SEP, [MSH, MSA]) response['MSH.F1.R1'] = SEP[0] response['MSH.F2.R1'] = SEP[1:] self.assertEqual(six.text_type(response), 'MSH|^~\\&|\rMSA') src_msg = hl7.parse(rep_sample_hl7) PID = src_msg['PID'][0] self.assertEqual( six.text_type(PID), 'PID|Field1|Component1^Component2|Component1^Sub-Component1&Sub-Component2^Component3|Repeat1~Repeat2' ) response.append(PID) self.assertEqual( six.text_type(response), 'MSH|^~\\&|\rMSA\rPID|Field1|Component1^Component2|Component1^Sub-Component1&Sub-Component2^Component3|Repeat1~Repeat2' )
def hl7Response(request, message_type, version_id='2.4', extra_segments=None): """ Generate a HL7 RESPONSE message for a given request message. Just a MSG HDR message_type can be a string 'MFN^M02' or a list ['MFN', 'M02'] or a hl7.Field('^', ['MFN', 'M02']) """ serial = next_serial() if extra_segments is None: extra_segments = [] iMSH = request['MSH'][0] local_fac, local_app = iMSH[5], iMSH[4] remote_fac, remote_app = iMSH[3], iMSH[2] # version_id = iMSH[11] if type(message_type) not in [hl7.Field, str, unicode]: message_type = hl7.Field(SEP[1], message_type) # assume list MSH = hl7.Segment(SEP[0], [ 'MSH', SEP[1:], # 2.16.9.2 MSH-2: Encoding Characters local_app, # 2.16.9.3 MSH-3: Sending Application local_fac, # 2.16.9.4 MSH-4: Sending Facility remote_app, # 2.16.9.5 MSH-5: Receiving Application remote_fac, # 2.16.9.6 MSH-6: Receiving Facility timestamp(), # 2.16.9.7 MSH-7: Date/Time Of Message '', # 2.16.9.8 MSH-8: Security message_type, # 2.16.9.9 MSH-9: Message Type str(serial), # 2.16.9.10 MSH-10: Message Control ID 'P', # 2.16.9.11 MSH-11: Processing ID version_id, # 2.16.9.12 MSH-12: Version ID '', # Sequence Number # Continuation Pointer # Accept Acknowledgment Type # Application Acknowledgment Type # Country Code # Character Set # Principal Language Of Message # Alternate Character Set Handling Scheme # Conformance Statement ID ]) response = hl7.Message(CR_SEP, [MSH] + extra_segments) return response
def create_msh_response(msg, response_type='AA'): ''' create the msh msa response ''' SEP = '|^~\&' CR_SEP = '\r' msh = msg.segment('MSH') control_id = unicode(msg.segment('MSH')[9]) msh_response = hl7.Segment(SEP[0], [ hl7.Field(SEP[1], ['MSH']), hl7.Field('', SEP[1:]), hl7.Field('', msh[4]), hl7.Field('', msh[5]), hl7.Field('', msh[2]), hl7.Field('', msh[3]), hl7.Field('', datetime.now().strftime('%Y%m%d%H%M%S')), hl7.Field('', 'ACK'), hl7.Field('', control_id), hl7.Field('', msh[10]), hl7.Field('', msh[11]) ]) msa_response = hl7.Segment(SEP[0], [ hl7.Field(SEP[1], ['MSA']), hl7.Field('', response_type), hl7.Field('', control_id) ]) response = hl7.Message(CR_SEP, [msh_response, msa_response]) return response
def make_dg1_segment( set_id: int, diagnosis_datetime: Pendulum, coding_system: str, diagnosis_identifier: str, diagnosis_text: str, alternate_coding_system: str = "", alternate_diagnosis_identifier: str = "", alternate_diagnosis_text: str = "", diagnosis_type: str = "F", diagnosis_classification: str = "D", confidential_indicator: str = "N", clinician_id_number: Union[str, int] = None, clinician_surname: str = "", clinician_forename: str = "", clinician_middle_name_or_initial: str = "", clinician_suffix: str = "", clinician_prefix: str = "", clinician_degree: str = "", clinician_source_table: str = "", clinician_assigning_authority: str = "", clinician_name_type_code: str = "", clinician_identifier_type_code: str = "", clinician_assigning_facility: str = "", attestation_datetime: Pendulum = None, ) -> hl7.Segment: # noinspection HttpUrlsUsage """ Creates an HL7 diagnosis (DG1) segment. Args: .. code-block:: none set_id: Diagnosis sequence number, starting with 1 (use higher numbers for >1 diagnosis). diagnosis_datetime: Date/time diagnosis was made. coding_system: E.g. "I9C" for ICD9-CM; "I10" for ICD10. diagnosis_identifier: Code. diagnosis_text: Text. alternate_coding_system: Optional alternate coding system. alternate_diagnosis_identifier: Optional alternate code. alternate_diagnosis_text: Optional alternate text. diagnosis_type: A admitting, W working, F final. diagnosis_classification: C consultation, D diagnosis, M medication, O other, R radiological scheduling, S sign and symptom, T tissue diagnosis, I invasive procedure not classified elsewhere. confidential_indicator: Y yes, N no clinician_id_number: } Diagnosing clinician. clinician_surname: } clinician_forename: } clinician_middle_name_or_initial: } clinician_suffix: } clinician_prefix: } clinician_degree: } clinician_source_table: } clinician_assigning_authority: } clinician_name_type_code: } clinician_identifier_type_code: } clinician_assigning_facility: } attestation_datetime: Date/time the diagnosis was attested. - http://www.mexi.be/documents/hl7/ch600012.htm - https://www.hl7.org/special/committees/vocab/V26_Appendix_A.pdf """ segment_id = "DG1" try: int(set_id) set_id = str(set_id) except Exception: raise AssertionError("make_dg1_segment: set_id invalid") diagnosis_coding_method = "" diagnosis_code = hl7.Field( COMPONENT_SEPARATOR, [ diagnosis_identifier, diagnosis_text, coding_system, alternate_diagnosis_identifier, alternate_diagnosis_text, alternate_coding_system, ], ) diagnosis_description = "" diagnosis_datetime = format_datetime(diagnosis_datetime, DateFormat.HL7_DATETIME) if diagnosis_type not in ("A", "W", "F"): raise AssertionError("make_dg1_segment: diagnosis_type invalid") major_diagnostic_category = "" diagnostic_related_group = "" drg_approval_indicator = "" drg_grouper_review_code = "" outlier_type = "" outlier_days = "" outlier_cost = "" grouper_version_and_type = "" diagnosis_priority = "" try: clinician_id_number = (str(int(clinician_id_number)) if clinician_id_number is not None else "") except Exception: raise AssertionError("make_dg1_segment: diagnosing_clinician_id_number" " invalid") if clinician_id_number: clinician_id_check_digit = get_mod11_checkdigit(clinician_id_number) clinician_checkdigit_scheme = "M11" # Mod 11 algorithm else: clinician_id_check_digit = "" clinician_checkdigit_scheme = "" diagnosing_clinician = hl7.Field( COMPONENT_SEPARATOR, [ clinician_id_number, clinician_surname or "", clinician_forename or "", clinician_middle_name_or_initial or "", clinician_suffix or "", clinician_prefix or "", clinician_degree or "", clinician_source_table or "", clinician_assigning_authority or "", clinician_name_type_code or "", clinician_id_check_digit or "", clinician_checkdigit_scheme or "", clinician_identifier_type_code or "", clinician_assigning_facility or "", ], ) if diagnosis_classification not in ( "C", "D", "M", "O", "R", "S", "T", "I", ): raise AssertionError( "make_dg1_segment: diagnosis_classification invalid") if confidential_indicator not in ("Y", "N"): raise AssertionError( "make_dg1_segment: confidential_indicator invalid") attestation_datetime = (format_datetime(attestation_datetime, DateFormat.HL7_DATETIME) if attestation_datetime else "") fields = [ segment_id, set_id, diagnosis_coding_method, diagnosis_code, diagnosis_description, diagnosis_datetime, diagnosis_type, major_diagnostic_category, diagnostic_related_group, drg_approval_indicator, drg_grouper_review_code, outlier_type, outlier_days, outlier_cost, grouper_version_and_type, diagnosis_priority, diagnosing_clinician, diagnosis_classification, confidential_indicator, attestation_datetime, ] segment = hl7.Segment(FIELD_SEPARATOR, fields) return segment
def make_obx_segment( req: "CamcopsRequest", task: "Task", task_format: str, observation_identifier: str, observation_datetime: Pendulum, responsible_observer: str, export_options: "TaskExportOptions", ) -> hl7.Segment: # noinspection HttpUrlsUsage """ Creates an HL7 observation result (OBX) segment. - http://www.hl7standards.com/blog/2006/10/18/how-do-i-send-a-binary-file-inside-of-an-hl7-message - http://www.hl7standards.com/blog/2007/11/27/pdf-attachment-in-hl7-message/ - http://www.hl7standards.com/blog/2006/12/01/sending-images-or-formatted-documents-via-hl7-messaging/ - https://www.hl7.org/documentcenter/public/wg/ca/HL7ClmAttIG.PDF - type of data: https://www.hl7.org/implement/standards/fhir/v2/0191/index.html - subtype of data: https://www.hl7.org/implement/standards/fhir/v2/0291/index.html """ # noqa segment_id = "OBX" set_id = str(1) source_application = "CamCOPS" if task_format == FileType.PDF: value_type = "ED" # Encapsulated data (ED) field observation_value = hl7.Field( COMPONENT_SEPARATOR, [ source_application, "Application", # type of data "PDF", # data subtype "Base64", # base 64 encoding base64.standard_b64encode(task.get_pdf(req)), # data ], ) elif task_format == FileType.HTML: value_type = "ED" # Encapsulated data (ED) field observation_value = hl7.Field( COMPONENT_SEPARATOR, [ source_application, "TEXT", # type of data "HTML", # data subtype "A", # no encoding (see table 0299), but need to escape escape_hl7_text(task.get_html(req)), # data ], ) elif task_format == FileType.XML: value_type = "ED" # Encapsulated data (ED) field observation_value = hl7.Field( COMPONENT_SEPARATOR, [ source_application, "TEXT", # type of data "XML", # data subtype "A", # no encoding (see table 0299), but need to escape escape_hl7_text( task.get_xml( req, indent_spaces=0, eol="", options=export_options)), # data ], ) else: raise AssertionError( f"make_obx_segment: invalid task_format: {task_format}") observation_sub_id = "" units = "" reference_range = "" abnormal_flags = "" probability = "" nature_of_abnormal_test = "" observation_result_status = "" date_of_last_observation_normal_values = "" user_defined_access_checks = "" date_and_time_of_observation = format_datetime(observation_datetime, DateFormat.HL7_DATETIME) producer_id = "" observation_method = "" equipment_instance_identifier = "" date_time_of_analysis = "" fields = [ segment_id, set_id, value_type, observation_identifier, observation_sub_id, observation_value, units, reference_range, abnormal_flags, probability, nature_of_abnormal_test, observation_result_status, date_of_last_observation_normal_values, user_defined_access_checks, date_and_time_of_observation, producer_id, responsible_observer, observation_method, equipment_instance_identifier, date_time_of_analysis, ] segment = hl7.Segment(FIELD_SEPARATOR, fields) return segment
def make_obr_segment(task: "Task") -> hl7.Segment: # noinspection HttpUrlsUsage """ Creates an HL7 observation request (OBR) segment. - http://hl7reference.com/HL7%20Specifications%20ORM-ORU.PDF - Required in ORU^R01 message: - https://www.corepointhealth.com/resource-center/hl7-resources/hl7-oru-message - https://www.corepointhealth.com/resource-center/hl7-resources/hl7-obr-segment """ # noqa segment_id = "OBR" set_id = "1" placer_order_number = "CamCOPS" filler_order_number = "CamCOPS" universal_service_id = hl7.Field( COMPONENT_SEPARATOR, ["CamCOPS", "CamCOPS psychiatric/cognitive assessment"], ) # unused below here, apparently priority = "" requested_date_time = "" observation_date_time = "" observation_end_date_time = "" collection_volume = "" collector_identifier = "" specimen_action_code = "" danger_code = "" relevant_clinical_information = "" specimen_received_date_time = "" ordering_provider = "" order_callback_phone_number = "" placer_field_1 = "" placer_field_2 = "" filler_field_1 = "" filler_field_2 = "" results_report_status_change_date_time = "" charge_to_practice = "" diagnostic_service_section_id = "" result_status = "" parent_result = "" quantity_timing = "" result_copies_to = "" parent = "" transportation_mode = "" reason_for_study = "" principal_result_interpreter = "" assistant_result_interpreter = "" technician = "" transcriptionist = "" scheduled_date_time = "" number_of_sample_containers = "" transport_logistics_of_collected_samples = "" collectors_comment = "" transport_arrangement_responsibility = "" transport_arranged = "" escort_required = "" planned_patient_transport_comment = "" fields = [ segment_id, set_id, placer_order_number, filler_order_number, universal_service_id, priority, requested_date_time, observation_date_time, observation_end_date_time, collection_volume, collector_identifier, specimen_action_code, danger_code, relevant_clinical_information, specimen_received_date_time, ordering_provider, order_callback_phone_number, placer_field_1, placer_field_2, filler_field_1, filler_field_2, results_report_status_change_date_time, charge_to_practice, diagnostic_service_section_id, result_status, parent_result, quantity_timing, result_copies_to, parent, transportation_mode, reason_for_study, principal_result_interpreter, assistant_result_interpreter, technician, transcriptionist, scheduled_date_time, number_of_sample_containers, transport_logistics_of_collected_samples, collectors_comment, transport_arrangement_responsibility, transport_arranged, escort_required, planned_patient_transport_comment, ] segment = hl7.Segment(FIELD_SEPARATOR, fields) return segment
def make_pid_segment( forename: str, surname: str, dob: Date, sex: str, address: str, patient_id_list: List[HL7PatientIdentifier] = None, ) -> hl7.Segment: """ Creates an HL7 patient identification (PID) segment. - https://www.corepointhealth.com/resource-center/hl7-resources/hl7-pid-segment - https://www.hl7.org/documentcenter/public/wg/conf/Msgadt.pdf (s5.4.8) - ID numbers... https://www.cdc.gov/vaccines/programs/iis/technical-guidance/downloads/hl7guide-1-4-2012-08.pdf """ # noqa patient_id_list = patient_id_list or [] # type: List[HL7PatientIdentifier] segment_id = "PID" set_id = "" # External ID patient_external_id = "" # ... this one is deprecated # http://www.j4jayant.com/articles/hl7/16-patient-id # Internal ID internal_id_element_list = [] for i in range(len(patient_id_list)): if not patient_id_list[i].pid: continue ptidentifier = patient_id_list[i] pid = ptidentifier.pid check_digit = get_mod11_checkdigit(pid) check_digit_scheme = "M11" # Mod 11 algorithm type_id = patient_id_list[i].id_type assigning_authority = patient_id_list[i].assigning_authority # Now, as per Table 4.6 "Extended composite ID" of # hl7guide-1-4-2012-08.pdf: internal_id_element = hl7.Field( COMPONENT_SEPARATOR, [ pid, check_digit, check_digit_scheme, assigning_authority, type_id, # length "2..5" meaning 2-5 ], ) internal_id_element_list.append(internal_id_element) patient_internal_id = hl7.Field(REPETITION_SEPARATOR, internal_id_element_list) # Alternate ID alternate_patient_id = "" # ... this one is deprecated # http://www.j4jayant.com/articles/hl7/16-patient-id patient_name = hl7.Field( COMPONENT_SEPARATOR, [ forename, # surname surname, # forename "", # middle initial/name "", # suffix (e.g. Jr, III) "", # prefix (e.g. Dr) "", # degree (e.g. MD) ], ) mothers_maiden_name = "" date_of_birth = format_datetime(dob, DateFormat.HL7_DATE) alias = "" race = "" country_code = "" home_phone_number = "" business_phone_number = "" language = "" marital_status = "" religion = "" account_number = "" social_security_number = "" drivers_license_number = "" mother_identifier = "" ethnic_group = "" birthplace = "" birth_order = "" citizenship = "" veterans_military_status = "" fields = [ segment_id, set_id, # PID.1 patient_external_id, # PID.2 patient_internal_id, # known as "PID-3" or "PID.3" alternate_patient_id, # PID.4 patient_name, mothers_maiden_name, date_of_birth, sex, alias, race, address, country_code, home_phone_number, business_phone_number, language, marital_status, religion, account_number, social_security_number, drivers_license_number, mother_identifier, ethnic_group, birthplace, birth_order, citizenship, veterans_military_status, ] segment = hl7.Segment(FIELD_SEPARATOR, fields) return segment
def make_msh_segment(message_datetime: Pendulum, message_control_id: str) -> hl7.Segment: """ Creates an HL7 message header (MSH) segment. - MSH: https://www.hl7.org/documentcenter/public/wg/conf/HL7MSH.htm - We're making an ORU^R01 message = unsolicited result. - ORU = Observational Report - Unsolicited - ORU^R01 = Unsolicited transmission of an observation message - https://www.corepointhealth.com/resource-center/hl7-resources/hl7-oru-message - https://www.hl7kit.com/joomla/index.php/hl7resources/examples/107-orur01 """ # noqa segment_id = "MSH" encoding_characters = (COMPONENT_SEPARATOR + REPETITION_SEPARATOR + ESCAPE_CHARACTER + SUBCOMPONENT_SEPARATOR) sending_application = "CamCOPS" sending_facility = "" receiving_application = "" receiving_facility = "" date_time_of_message = format_datetime(message_datetime, DateFormat.HL7_DATETIME) security = "" message_type = hl7.Field( COMPONENT_SEPARATOR, [ "ORU", # message type ID = Observ result/unsolicited "R01" # trigger event ID = ORU/ACK - Unsolicited transmission # of an observation message ], ) processing_id = "P" # production (processing mode: current) version_id = "2.3" # HL7 version sequence_number = "" continuation_pointer = "" accept_acknowledgement_type = "" application_acknowledgement_type = "AL" # always country_code = "" character_set = "UNICODE UTF-8" # http://wiki.hl7.org/index.php?title=Character_Set_used_in_v2_messages principal_language_of_message = "" fields = [ segment_id, # field separator inserted automatically; HL7 standard considers it a # field but the python-hl7 processor doesn't when it parses encoding_characters, sending_application, sending_facility, receiving_application, receiving_facility, date_time_of_message, security, message_type, message_control_id, processing_id, version_id, sequence_number, continuation_pointer, accept_acknowledgement_type, application_acknowledgement_type, country_code, character_set, principal_language_of_message, ] segment = hl7.Segment(FIELD_SEPARATOR, fields) return segment