示例#1
0
    def _create_message(self, results, ack_code):
        """
        Creates the final RSP_K21 response message. If no errors occurred and some results have been found, the message
        will carry as many different PID segments as the number of the results.

        :type:  results  ``list``
        :param: results a list providing the Gnuhealth ORM query results

        :type:  ack_code  ``str``
        :param: ack_code it is the ack:code to be put in the MSA segment. If no errors occurred, the code wull be of
            positive ACK (AA); else, one of the negative acks (AE, AR)

        :return: an hl7apy ``Message`` class instance, which is the final RSP_K21 message
        """
        try:
            qry_ack_code = 'OK'
            if len(results) == 0:
                qry_ack_code = 'NF'
            
            is_pdqv = self.is_pdqv_message()
            logger.debug("Creating response message...")
            if is_pdqv:
                message_profile = load_message_profile(os.path.join(_get_message_profiles_dir(), "pdqv_response"))
                message_structure = PDQV_MESSAGE_STRUCTURE
            else:
                message_profile = load_message_profile(os.path.join(_get_message_profiles_dir(), "pdq_response"))
                message_structure = PDQ_MESSAGE_STRUCTURE
                
            message = Message(message_structure, version='2.5', validation_level=VALIDATION_LEVEL.STRICT,
                              reference=message_profile)
            
            self._set_msh(message, is_pdqv)
            
            msa = message.add_segment("MSA")
            msa.msa_1 = ack_code
            msa.msa_2 = self.msg.msh.msh_10.msh_10_1

            qak = message.add_segment("QAK")
            qak.qak_1 = self.msg.qpd.qpd_2
            qak.qak_2 = qry_ack_code
            qak.qak_4.qak_4_1 = str(len(results))  # total results
            qak.qak_5.qak_5_1 = str(len(results))  # sent results
            qak.qak_6.qak_6_1 = "0"  # remaining results
            
            message.add_segment("QPD")
            message.qpd = self.msg.qpd

            message = self._create_pdq_res_list(message, message_structure, results)
            return message
        except Exception, e:
            logger.error('Error during Message Creation, %s' % e)
示例#2
0
    def setUp(self):
        self.rsp_k21 = \
            'MSH|^~\&|SEND APP|SEND FAC|REC APP|REC FAC|20110708163514||RSP^K22^RSP_K21|1234|D|2.5|||||ITA||EN\r' \
            'MSA|AA|26775702551812240|\r' \
            'QAK|111069|OK||1|1|0\r' \
            'QPD|IHE PDQ Query|111069|@PID.3.1^[email protected]^SMITH||||\r' \
            'PID|1||10101^^^GATEWAY&1.3.6.1.4.1.21367.2011.2.5.17&ISO||JOHN^SMITH^^^^^A||19690113|M|||VIA DELLE VIE^^CAGLIARI^^^100^H^^092009||||||||||||CAGLIARI|||||\r'

        # it misses some PID.3 components
        self.invalid_rsp_k21 = \
            'MSH|^~\&|SEND APP|SEND FAC|REC APP|REC FAC|20110708163514||RSP^K22^RSP_K21|1234|D|2.5|||||ITA||EN\r' \
            'MSA|AA|26775702551812240|\r' \
            'QAK|111069|OK||1|1|0\r' \
            'QPD|IHE PDQ Query|111069|@PID.3.1^[email protected]^SMITH||||\r' \
            'PID|1||10101^^^||JOHN^SMITH^^^^^A||19690113|M|||VIA DELLE VIE^^CAGLIARI^^^100^H^^092009|||||||||||||||||\r'

        self.rsp_k21_27 = \
            'MSH|^~\&#|SEND APP|SEND FAC|REC APP|REC FAC|20110708163514||RSP^K22^RSP_K21|1234|D|2.7|||||ITA||EN\r' \
            'MSA|AA|26775702551812240\r' \
            'QAK|111069|OK||1|1|0\r' \
            'QPD|IHE PDQ Query|111069|@PID.3.1^[email protected]^SMITH\r' \
            'PID|1||10101^^^GATEWAY&1.3.6.1.4.1.21367.2011.2.5.17&ISO||JOHN^SMITH^^^^^A||19690113|M|||VIA DELLE VIE^^CAGLIARI^^^100^H^^092009||||||||||||CAGLIARI'

        self.rsp_k21_27_no_truncation = \
            'MSH|^~\&|SEND APP|SEND FAC|REC APP|REC FAC|20110708163514||RSP^K22^RSP_K21|1234|D|2.7|||||ITA||EN\r' \
            'MSA|AA|26775702551812240\r' \
            'QAK|111069|OK||1|1|0\r' \
            'QPD|IHE PDQ Query|111069|@PID.3.1^[email protected]^SMITH\r' \
            'PID|1||10101^^^GATEWAY&1.3.6.1.4.1.21367.2011.2.5.17&ISO||JOHN^SMITH^^^^^A||19690113|M|||VIA DELLE VIE^^CAGLIARI^^^100^H^^092009||||||||||||CAGLIARI'

        base_path = os.path.abspath(os.path.dirname(__file__))
        path = os.path.join(base_path, 'profiles/iti_21')
        self.rsp_k21_mp = hl7apy.load_message_profile(path)
示例#3
0
    def setUp(self):
        self.rsp_k21 = \
            'MSH|^~\&|SEND APP|SEND FAC|REC APP|REC FAC|20110708163514||RSP^K22^RSP_K21|1234|D|2.5|||||ITA||EN\r' \
            'MSA|AA|26775702551812240|\r' \
            'QAK|111069|OK||1|1|0\r' \
            'QPD|IHE PDQ Query|111069|@PID.3.1^[email protected]^SMITH||||\r' \
            'PID|1||10101^^^GATEWAY&1.3.6.1.4.1.21367.2011.2.5.17&ISO||JOHN^SMITH^^^^^A||19690113|M|||VIA DELLE VIE^^CAGLIARI^^^100^H^^092009||||||||||||CAGLIARI|||||\r'

        # it misses some PID.3 components
        self.invalid_rsp_k21 = \
            'MSH|^~\&|SEND APP|SEND FAC|REC APP|REC FAC|20110708163514||RSP^K22^RSP_K21|1234|D|2.5|||||ITA||EN\r' \
            'MSA|AA|26775702551812240|\r' \
            'QAK|111069|OK||1|1|0\r' \
            'QPD|IHE PDQ Query|111069|@PID.3.1^[email protected]^SMITH||||\r' \
            'PID|1||10101^^^||JOHN^SMITH^^^^^A||19690113|M|||VIA DELLE VIE^^CAGLIARI^^^100^H^^092009|||||||||||||||||\r'

        self.rsp_k21_27 = \
            'MSH|^~\&#|SEND APP|SEND FAC|REC APP|REC FAC|20110708163514||RSP^K22^RSP_K21|1234|D|2.7|||||ITA||EN\r' \
            'MSA|AA|26775702551812240\r' \
            'QAK|111069|OK||1|1|0\r' \
            'QPD|IHE PDQ Query|111069|@PID.3.1^[email protected]^SMITH\r' \
            'PID|1||10101^^^GATEWAY&1.3.6.1.4.1.21367.2011.2.5.17&ISO||JOHN^SMITH^^^^^A||19690113|M|||VIA DELLE VIE^^CAGLIARI^^^100^H^^092009||||||||||||CAGLIARI'

        self.rsp_k21_27_no_truncation = \
            'MSH|^~\&|SEND APP|SEND FAC|REC APP|REC FAC|20110708163514||RSP^K22^RSP_K21|1234|D|2.7|||||ITA||EN\r' \
            'MSA|AA|26775702551812240\r' \
            'QAK|111069|OK||1|1|0\r' \
            'QPD|IHE PDQ Query|111069|@PID.3.1^[email protected]^SMITH\r' \
            'PID|1||10101^^^GATEWAY&1.3.6.1.4.1.21367.2011.2.5.17&ISO||JOHN^SMITH^^^^^A||19690113|M|||VIA DELLE VIE^^CAGLIARI^^^100^H^^092009||||||||||||CAGLIARI'

        base_path = os.path.abspath(os.path.dirname(__file__))
        path = os.path.join(base_path, 'profiles/iti_21')
        self.rsp_k21_mp = hl7apy.load_message_profile(path)
示例#4
0
    def _check_incoming_message(self):
        """
        Controls the incoming HL7 message, after parsing, according to some IHE PDQ message request rules.
        It checks that:

          - All query parameters codes and values are correct in the request message

          - The incoming message contains at least one query parameter

          - For the birth date query parameter, the date value format is HL7 - compliant
          
          - If the Allowed Application Filter is enabled. checks if the MSH_3 field contains a value included in the
            Allowed_application list table

        :raises: :exc:`MissingQueryParameters` if the incoming message has not any query parameters
            (QPD_3 hl7 message field is empty)
        :raises: :exc:`InvalidQueryParameterCode` if the incoming message has a query parameter code
            (QPD_3_1) in a not-allowed format
        :raises: :exc:`MissingQueryParameterValue` if the incoming message has a query parameter
            (QPD_3_1) correct but without the corrispondent value (QPD_3_2)
        :raises: :exc:`InvalidDateParameterValue` if the incoming message has a query parameter (QPD_3_1) asking for
            the patient birth date, but providing a not allowed date format in the value
        :raise:  :exc:`InvalidSendingApplicationParameterValue if the Application Filter is enabled and  the MSH_3
            field of the incoming message is not included into the Allowed Applications list`
        """
        
        try:
            message_profiles_dir = _get_message_profiles_dir()
            logger.debug("Checking for message profile from dir: %s" % message_profiles_dir)
            
            if self.is_pdq_message():
                message_profile = load_message_profile(os.path.join(message_profiles_dir, 'pdq_request'))
            elif self.is_pdqv_message():
                message_profile = load_message_profile(os.path.join(message_profiles_dir, 'pdqv_request'))
            else:
                raise MessageProfileNotFound()
            self.msg = parse_message(self.raw_msg, validation_level=VALIDATION_LEVEL.STRICT,
                                     message_profile=message_profile)
        except MessageProfileNotFound, e:  # NO PDQ
            logger.error("No message profile found for message: %s -> %s" % (self.raw_msg, str(e)))
            raise PDQMessageProfileNotFound
示例#5
0
    def setUp(self):
        self.rsp_k21 = \
            'MSH|^~\&|SENDING APP|SENDING FAC|RECEIVING APP|RECEIVING FAC|20140410170011||RSP^K22^RSP_K21|11111111|P|2.5\r' \
            'MSA|AA|20140410170015\r' \
            'QAK|222222222|OK\r' \
            'QPD|IHE PDQ Query|222222222|@PID.3.1.1^3333333|||||^^^IHEFACILITY&1.3.6.1.4.1.21367.3000.1.6&ISO^|\r' \
            'PID|1||10101109091948^^^GATEWAY&1.3.6.1.4.1.21367.2011.2.5.17&ISO||JOHN^SMITH^^^^^A||19690113|M|||VIA DELLE VIE^^CAGLIARI^^^ITA^H^^092009||||||||||||CAGLIARI|||\r'

        base_path = os.path.abspath(os.path.dirname(__file__))
        path = os.path.join(base_path, 'profiles/iti_21')
        self.rsp_k21_mp = hl7apy.load_message_profile(path)

        self.report_file = '/tmp/hl7apy_test_rf'
示例#6
0
    def setUp(self):
        self.rsp_k21 = \
            'MSH|^~\&|SENDING APP|SENDING FAC|RECEIVING APP|RECEIVING FAC|20140410170011||RSP^K22^RSP_K21|11111111|P|2.5\r' \
            'MSA|AA|20140410170015\r' \
            'QAK|222222222|OK\r' \
            'QPD|IHE PDQ Query|222222222|@PID.3.1.1^3333333|||||^^^IHEFACILITY&1.3.6.1.4.1.21367.3000.1.6&ISO^|\r' \
            'PID|1||10101109091948^^^GATEWAY&1.3.6.1.4.1.21367.2011.2.5.17&ISO||JOHN^SMITH^^^^^A||19690113|M|||VIA DELLE VIE^^CAGLIARI^^^ITA^H^^092009||||||||||||CAGLIARI|||\r'

        base_path = os.path.abspath(os.path.dirname(__file__))
        path = os.path.join(base_path, 'profiles/iti_21')
        self.rsp_k21_mp = hl7apy.load_message_profile(path)

        self.report_file = '/tmp/hl7apy_test_rf'
示例#7
0
def parse_messages(directory,
                   validation_level=VL.STRICT,
                   find_groups=True,
                   limit=-1,
                   output_file=None,
                   message_profile=None):
    exceptions = {VL.TOLERANT: [], VL.STRICT: []}
    msg_per_versions = {
        VL.TOLERANT: defaultdict(int),
        VL.STRICT: defaultdict(int)
    }
    msg_per_type = {VL.TOLERANT: defaultdict(int), VL.STRICT: defaultdict(int)}
    parsing_time = {VL.TOLERANT: [], VL.STRICT: []}
    encoding_time = []
    files = _get_files(directory)[:limit] if limit != -1 else _get_files(
        directory)
    n_messages = {VL.TOLERANT: 0, VL.STRICT: 0}
    mp = load_message_profile(
        message_profile) if message_profile is not None else None
    start = time.time()
    for f in sorted(files):
        with open(f) as hl7_file:
            msg_str = hl7_file.read()
            msg_str = msg_str.replace('\r\n', '\r')
            msg_str = msg_str.replace('\n', '\r')
            error_occurred = False

            validations = [VL.STRICT, VL.TOLERANT]
            if validation_level == VL.TOLERANT:
                validations.remove(VL.STRICT)

            for vl in validations:
                # it parses TOLERANT only if the user asked (validation_level == VL.TOLERANT)
                # or an error occurred
                if vl == VL.TOLERANT and (validation_level != VL.TOLERANT
                                          and not error_occurred):
                    continue
                file_base_name = os.path.basename(hl7_file.name)
                try:
                    msg_start = time.time()
                    msg = parse_message(msg_str,
                                        vl,
                                        find_groups=find_groups,
                                        message_profile=mp)
                    msg_end = time.time()

                    msg_per_versions[vl][msg.version] += 1
                    msg_per_type[vl][msg.msh.msh_9.to_er7()] += 1
                    parsing_time[vl].append(
                        (file_base_name, len(msg.children),
                         msg.msh.msh_9.to_er7(), msg_end - msg_start))
                except MessageProfileNotFound:
                    continue
                except InvalidEncodingChars:
                    if mp is None:
                        exceptions[vl].append({
                            'type': 'parsing',
                            'ex': e,
                            'file_name': f,
                            'msg': msg_str
                        })
                        if vl == VL.STRICT:
                            error_occurred = True
                    else:
                        continue
                except Exception as e:
                    exceptions[vl].append({
                        'type': 'parsing',
                        'ex': e,
                        'file_name': f,
                        'msg': msg_str
                    })
                    if vl == VL.STRICT:
                        error_occurred = True

                n_messages[vl] += 1

                try:
                    encoding_start = time.time()
                    msg.to_er7()
                    encoding_end = time.time()

                    encoding_time.append((file_base_name, len(msg.children),
                                          msg.msh.msh_9.to_er7(),
                                          encoding_end - encoding_start))
                except Exception as e:
                    exceptions[vl].append({
                        'type': 'encoding',
                        'ex': e,
                        'file_name': f,
                        'msg': msg_str
                    })

    elapsed_time = time.time() - start

    print_report(n_messages, msg_per_versions, msg_per_type, exceptions,
                 elapsed_time, output_file, parsing_time, encoding_time,
                 validation_level, message_profile)
def parse_messages(directory, validation_level=VL.STRICT, find_groups=True, limit=-1,
                   output_file=None, message_profile=None):

    exceptions = {VL.TOLERANT: [], VL.STRICT: []}
    msg_per_versions = {VL.TOLERANT: defaultdict(int), VL.STRICT: defaultdict(int)}
    msg_per_type = {VL.TOLERANT: defaultdict(int), VL.STRICT: defaultdict(int)}
    parsing_time = {VL.TOLERANT : [], VL.STRICT : []}
    encoding_time = []
    files = _get_files(directory)[:limit] if limit != -1 else _get_files(directory)
    n_messages = {VL.TOLERANT: 0, VL.STRICT: 0}
    mp = load_message_profile(message_profile) if message_profile is not None else None
    start = time.time()
    for f in sorted(files):
        with open(f) as hl7_file:
            msg_str = hl7_file.read()
            msg_str = msg_str.replace('\r\n', '\r')
            msg_str = msg_str.replace('\n', '\r')
            error_occurred = False

            validations = [VL.STRICT, VL.TOLERANT]
            if validation_level == VL.TOLERANT:
                validations.remove(VL.STRICT)

            for vl in validations:
                # it parses TOLERANT only if the user asked (validation_level == VL.TOLERANT)
                # or an error occurred
                if vl == VL.TOLERANT and (validation_level != VL.TOLERANT and not error_occurred):
                    continue
                file_base_name = os.path.basename(hl7_file.name)
                try:
                    msg_start = time.time()
                    msg = parse_message(msg_str, vl, find_groups=find_groups, message_profile=mp)
                    msg_end = time.time()

                    msg_per_versions[vl][msg.version] += 1
                    msg_per_type[vl][msg.msh.msh_9.to_er7()] += 1
                    parsing_time[vl].append((file_base_name, len(msg.children),
                                             msg.msh.msh_9.to_er7(), msg_end - msg_start))
                except MessageProfileNotFound:
                    continue
                except InvalidEncodingChars:
                    if mp is None:
                        exceptions[vl].append({'type': 'parsing', 'ex': e, 'file_name': f, 'msg': msg_str})
                        if vl == VL.STRICT:
                            error_occurred = True
                    else:
                        continue
                except Exception as e:
                    exceptions[vl].append({'type': 'parsing', 'ex': e, 'file_name': f, 'msg': msg_str})
                    if vl == VL.STRICT:
                        error_occurred = True

                n_messages[vl] += 1

                try:
                    encoding_start = time.time()
                    msg.to_er7()
                    encoding_end = time.time()

                    encoding_time.append((file_base_name, len(msg.children), msg.msh.msh_9.to_er7(),
                                          encoding_end - encoding_start))
                except Exception as e:
                    exceptions[vl].append({'type': 'encoding', 'ex': e, 'file_name': f, 'msg': msg_str})

    elapsed_time = time.time() - start

    print_report(n_messages, msg_per_versions, msg_per_type, exceptions,
                 elapsed_time, output_file, parsing_time, encoding_time,
                 validation_level, message_profile)
示例#9
0
# See license-GPLv2.txt or license-MIT.txt

import os
import re
import uuid
import socket
import hashlib

from django.conf import settings

from hl7apy import load_message_profile, VALIDATION_LEVEL as VL
from hl7apy.core import Message
from hl7apy.parser import parse_message

_MP_ROOT_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "hl7_profiles")
_PDQ_REQ_MP = load_message_profile(os.path.join(_MP_ROOT_PATH, "pdq_request"))
_PDQV_REQ_MP = load_message_profile(os.path.join(_MP_ROOT_PATH, "pdqv_request"))
_PDQ_RES_MP = load_message_profile(os.path.join(_MP_ROOT_PATH, "pdq_response"))
_PDQV_RES_MP = load_message_profile(os.path.join(_MP_ROOT_PATH, "pdqv_response"))


def make_new_uid():
    return hashlib.sha1(os.urandom(20)).hexdigest()


def json_response():
    pass


def send_hl7_message(host, port, er7_message):
    sb = "\x0b"
示例#10
0
import uuid
import logging
import datetime

from hl7apy.v2_5 import DTM
from hl7apy.utils import check_date
from hl7apy.mllp import AbstractHandler
from hl7apy.parser import parse_message
from hl7apy.core import Message
from hl7apy import load_message_profile

from dao import DAO

_ROOT_PATH = os.path.dirname(os.path.abspath(__file__))

PDQ_REQ_MP = load_message_profile(os.path.join(_ROOT_PATH, './pdq_req'))
PDQ_RES_MP = load_message_profile(os.path.join(_ROOT_PATH, './pdq_res'))

logger = logging.getLogger(__name__)


class PDQHandler(AbstractHandler):

    REQ_MP, RES_MP = PDQ_REQ_MP, PDQ_RES_MP
    PDQ_FIELD_NAMES = {
        '@PID.3.1': "IDENTIFIER",
        '@PID.5.1.1': 'SURNAME',
        '@PID.5.2': 'NAME',
        '@PID.7.1': 'DOB'
    }
示例#11
0
文件: server.py 项目: weiyd/hl7apy
class PDQSupplier(AbstractHandler):
    REQ_MP = load_message_profile(os.path.join(_ROOT_PATH, './pdq_req'))
    RES_MP = load_message_profile(os.path.join(_ROOT_PATH, './pdq_res'))

    FIELD_NAMES = {
        '@PID.5.1.1': 'SURNAME',
        '@PID.5.2': 'NAME',
        '@PID.7.1': 'DOB'
    }

    MISSING_PARAMS = 1

    def __init__(self, message):
        msg = parse_message(message, message_profile=self.REQ_MP)
        super(PDQSupplier, self).__init__(msg)

    def _create_response(self, ack_code, query_ack_code, patients):
        res = Message('RSP_K21', reference=self.RES_MP)
        res.msh.msh_5 = self.incoming_message.msh.msh_3
        res.msh.msh_6 = self.incoming_message.msh.msh_4
        res.msh.msh_7.ts_1 = DTM(datetime.datetime.now())
        res.msh.msh_9 = 'RSP^K22^RSP_K21'
        res.msh.msh_10 = uuid.uuid4().hex

        # MSA creation
        res.msa.msa_1 = ack_code
        res.msa.msa_2 = self.incoming_message.msh.msh_10.msh_10_1

        # QAK creation
        res.qak.qak_1 = self.incoming_message.qpd.qpd_2
        res.qak.qak_2 = 'OK' if len(patients) > 0 else 'NF'
        res.qak.qak_4 = str(len(patients))

        # QPD creation
        res.qpd = self.incoming_message.qpd

        # RSP_K21_QUERY_RESPONSE creation
        res.add_group('rsp_k21_query_response')
        g = res.rsp_k21_query_response
        for i, p in enumerate(patients):
            # add a pid segment for every patient
            g.add_segment('PID')
            g.pid[i].pid_3.cx_1, g.pid[i].pid_5.xpn_1, g.pid[i].pid_5.xpn_2 = p[:]

        return res.to_mllp()

    def _create_error(self, error_code):
        res = self._create_response('AR', 'AR', [])
        return res

    def reply(self):
        print('Received a message')
        print(repr(self.incoming_message.to_er7()))
        query_params = dict((self.FIELD_NAMES[q.qip_1.value], q.qip_2.value)
                            for q in self.incoming_message.qpd.qpd_3
                            if q.qip_1.value in self.FIELD_NAMES)
        print("Extracted query params: {}".format(query_params))
        if '' in query_params.values():
            return self._create_error(1)
        else:
            patients = [('0001', 'John', 'Smith')]
            return self._create_response('AA', 'OK', patients)