Exemplo n.º 1
0
class _MultiSectionItem(object):
    def __init__(self,
                 registry_model,
                 target_form_model,
                 target_section_model,
                 value_map,
                 is_address=False):
        self.registry_model = registry_model
        self.form_model = target_form_model
        self.section_model = target_section_model
        self.humaniser = Humaniser(registry_model)
        self.value_map = value_map
        self.is_address = is_address

    @property
    def answer(self):
        fields = []
        for cde_code in self.value_map:
            cde_model = CommonDataElement.objects.get(code=cde_code)
            display_name = cde_model.name
            raw_value = self.value_map[cde_code]
            if not self.is_address:
                display_value = self.humaniser.display_value2(
                    self.form_model, self.section_model, cde_model, raw_value)
            else:
                if cde_code == "AddressType":
                    display_value = raw_value.replace("AddressType", "")
                else:
                    display_value = raw_value

            fields.append("%s=%s" % (display_name, display_value))

        csv = ",".join(fields)
        return csv
Exemplo n.º 2
0
class VerifiableCDE:
    def __init__(self,
                 registry_model,
                 cde_dict=None,
                 form_model=None,
                 section_model=None,
                 cde_model=None,
                 position=None):
        self.registry_model = registry_model
        self.cde_dict = cde_dict
        self.valid = False
        self.position = position

        self.humaniser = Humaniser(self.registry_model)
        if cde_dict is not None:
            self._load(cde_dict)

        # Allow easy setup in POST views
        if form_model is not None:
            self.form_model = form_model
        if section_model is not None:
            self.section_model = section_model
        if cde_model is not None:
            self.cde_model = cde_model

        self.patient_data = NoData
        self.clinician_data = NoData
        self.patient_display_value = NoData
        self.status = VerificationStatus.UNVERIFIED
        self.comments = ""

    @property
    def display_value(self):
        def disp(value):
            return self.humaniser.display_value2(self.form_model,
                                                 self.section_model,
                                                 self.cde_model, value)

        if self.status == "corrected":
            return disp(self.clinician_data)
        elif self.status == "verified":
            return disp(self.patient_data)

    def set_clinician_value(self, raw_value):
        # field has already been validated so type casts are safe
        if self.cde_model.datatype == "integer":
            self.clinician_data = int(raw_value)
        elif self.cde_model.datatype in ["float", "decimal", "numeric"]:
            self.clinician_data = float(raw_value)
        else:
            # everything else is string
            self.clinician_data = raw_value

    def _load(self, cde_dict):
        self.valid = False
        form_name = cde_dict.get("form", None)
        section_code = cde_dict.get("section", None)
        cde_code = cde_dict.get("cde", None)
        for form_model in self.registry_model.forms:
            if form_model.name == form_name:
                for section_model in form_model.section_models:
                    if section_model.code == section_code:
                        if not section_model.allow_multiple:
                            for cde_model in section_model.cde_models:
                                if cde_model.code == cde_code:
                                    self.form_model = form_model
                                    self.section_model = section_model
                                    self.cde_model = cde_model
                                    self.allow_multiple = False
                                    self.valid = True

    def get_data(self, patient_model, context_model, display=True):
        # gets the data the Patient has entered ( if at all)

        if not all([self.registry_model, self.section_model, self.cde_model]):

            self._load(self.cde_dict)
        else:
            self.valid = True
        if not self.valid:
            raise VerificationError("Verification CDE dict: %s is not valid" %
                                    self.cde_dict)

        try:

            cde_value = patient_model.get_form_value(
                self.registry_model.code,
                self.form_model.name,
                self.section_model.code,
                self.cde_model.code,
                context_id=context_model.pk)

            self.patient_data = cde_value

        except KeyError:
            # form not filled in
            return "NOT ENTERED"

        self.patient_display_value = self.humaniser.display_value2(
            self.form_model, self.section_model, self.cde_model, cde_value)

        if display:
            return self.patient_display_value
        else:
            return self.patient_data

    @property
    def delimited_key(self):
        from rdrf.helpers.utils import mongo_key_from_models
        return mongo_key_from_models(self.form_model, self.section_model,
                                     self.cde_model)

    def has_annotation(self, user, registry_model, patient_model,
                       context_model):
        """
        Is there no annotation or is the existing one out of date because the value of
        the cde has changed?
        """
        def carp(msg):
            logger.debug(
                "Annotations Patient %s Context %s CDE %s: %s" %
                (patient_model, context_model.id, self.cde_model.code, msg))

        annotations_query = Annotation.objects.filter(
            patient_id=patient_model.pk,
            context_id=context_model.pk,
            form_name=self.form_model.name,
            section_code=self.section_model.code,
            cde_code=self.cde_model.code,
            username=user.username).order_by("-timestamp")

        if annotations_query.count() == 0:
            carp("no annotations")
            return None
        else:
            last_annotation = annotations_query.first()
            carp("last annotation status = %s" %
                 last_annotation.annotation_type)
            form_cde_value = self.get_data(patient_model,
                                           context_model,
                                           display=False)
            if not self._value_changed(last_annotation.cde_value,
                                       form_cde_value):
                carp(
                    "value changed : patient value = [%s] annotation value = [%s]"
                    % (last_annotation.cde_value, form_cde_value))

                logger.debug(
                    "returning last annotation as values have not changed: %s"
                    % last_annotation)
                return last_annotation
            else:
                logger.debug(
                    "returning None as values have changed so new verification required"
                )
                return None

        # cde will show up as unverified

        return None

    def _value_changed(self, annotation_cde_value, form_cde_value):
        # complication here because the stored type is a string
        # let's just string compare
        logger.debug("checking value changed for cde %s" % self.cde_model.code)
        logger.debug("ann cde value = %s" % annotation_cde_value)
        logger.debug("form cde value = %s" % form_cde_value)
        values_differ = str(annotation_cde_value) != str(form_cde_value)
        if values_differ:
            logger.debug("values differ")
            return True
        else:
            logger.debug("values are the same..")
            return False
Exemplo n.º 3
0
class _Question(object):
    """
    Read only view of entered questionnaire data
    """

    def __init__(self, registry_model, questionnaire, form_name, section_code, cde_code, value):
        self.registry_model = registry_model
        self.questionnaire = questionnaire
        self.humaniser = Humaniser(self.registry_model)
        self.form_name = form_name
        self.pos = 0
        self.question_type = None
        self.form_model = RegistryForm.objects.get(registry=self.registry_model,
                                                   name=form_name)
        self.section_model = Section.objects.get(code=section_code)
        self.cde_model = CommonDataElement.objects.get(code=cde_code)
        self.section_code = section_code
        self.cde_code = cde_code
        # raw value to be stored in Mongo ( or a list of values if from a
        # multisection)
        self.value = value

        self.target = self._get_target()

        # used on form:
        self.name = self._get_name()
        self.is_address = self.section_code == "PatientDataAddressSection"
        # or list of answers if cde in multisection
        self.answer = self._get_display_value(value)
        self.dest_id = "foo"
        self.src_id = self._construct_id()

    def _construct_id(self):
        return "id__%s__%s__%s" % (self.form_name,
                                   self.section_code,
                                   self.cde_code)

    @property
    def field_expression(self):
        if self.cde_code not in KEY_MAP:
            # not a special field - a "normal" clinical field
            return "%s/%s/%s" % (self.form_name,
                                 self.section_code,
                                 self.cde_code)
        else:
            return "TODO"

    def __str__(self):
        return "Q[%s] %s = %s" % (self.pos, self.name, self.answer)

    @property
    def is_multi(self):
        return self.section_model.allow_multiple

    def _get_name(self):
        # return a short name for the GUI - use the target display name not the generated
        # questionnaire name
        try:
            return self.target.display_name
        except Exception as ex:
            logger.error("error getting target: %s" % ex)
            return "%s/%s/%s" % (self.form_name,
                                 self.section_model.display_name,
                                 self.cde_model.name)

    def _get_display_value(self, value):
        if not self.is_multi:
            return self.humaniser.display_value2(
                self.form_model, self.section_model, self.cde_model, value)
        else:
            if not self.is_address:
                display = self.humaniser.display_value2
                return ",".join([display(self.form_model,
                                         self.section_model,
                                         self.cde_model,
                                         single_value) for single_value in value])
            else:
                return ",".join([x for x in value])

    def _get_target(self):
        """
        Return the generalised field expression that data for this field should be put into.
        This step is necessary because we decided early on to present one questionnaire form
        comprised of selected questions from potentially many clinical forms.
        """

        # the generated section code in a questionnaire encodes the original form name and
        # original section code ... ugh

        if self.cde_code in KEY_MAP:
            demographic_field = KEY_MAP[self.cde_code][0]
            target_expression = demographic_field
            target_display_name = CommonDataElement.objects.get(code=self.cde_code).name
            return TargetCDE(target_display_name, target_expression)

        t = self.questionnaire.questionnaire_reverse_mapper.parse_generated_section_code(
            self.section_code)

        original_form_name = t[0]
        original_section_code = t[1]

        target_display_name = self._get_target_display_name(
            original_form_name, original_section_code, self.cde_code)

        target_expression = "%s/%s/%s" % (original_form_name,
                                          original_section_code,
                                          self.cde_code)

        return TargetCDE(target_display_name, target_expression)

    def _get_target_display_name(self, target_form_name, target_section_code, target_cde_code):
        try:
            target_form_model = RegistryForm.objects.get(registry=self.registry_model,
                                                         name=target_form_name)
        except RegistryForm.DoesNotExist:
            target_form_model = None

        try:
            target_section_model = Section.objects.get(
                code=target_section_code)
        except Section.DoesNotExist:
            target_section_model = None

        try:
            target_cde_model = CommonDataElement.objects.get(
                code=target_cde_code)
        except CommonDataElement.DoesNotExist:
            target_cde_model = None

        if None in [target_form_model, target_section_model, target_cde_model]:
            return "%s/%s/%s" % (target_form_name,
                                 target_section_code,
                                 target_cde_code)
        else:
            return "%s/%s/%s" % (target_form_model.name,
                                 target_section_model.display_name,
                                 target_cde_model.name)
Exemplo n.º 4
0
class _ExistingDataWrapper(object):
    """
    return to qr view to show data already saved on a patient
    """

    def __init__(self, registry_model, patient_model, questionnaire):
        self.registry_model = registry_model
        self.humaniser = Humaniser(self.registry_model)
        self.patient_model = patient_model
        self.patient_data = self.patient_model.get_dynamic_data(
            self.registry_model)

        self.questionnaire = questionnaire
        self.gfe_parser = GeneralisedFieldExpressionParser(self.registry_model)
        self.default_context_model = patient_model.default_context(
            registry_model)
        self.name = "%s" % self.patient_model

    def _get_field_data(self, field_expression, form_model, section_model, cde_model):
        if field_expression in list(KEY_MAP.keys()):
            field_expression = KEY_MAP[field_expression][
                0]  # the demographic field

        retrieval_function = self.gfe_parser.parse(field_expression)
        try:
            value = retrieval_function(self.patient_model, self.patient_data)
            if field_expression == "working_groups":
                return self._get_working_groups_display_value(value)
            value = self.humaniser.display_value2(
                form_model, section_model, cde_model, value)

            if isinstance(value, datetime) or isinstance(value, date):
                value = str(value)
            return value

        except Exception as ex:
            return "Error[!%s]" % ex

    def _get_working_groups_display_value(self, working_group_models):
        return ",".join(sorted([wg.name for wg in working_group_models]))

    @property
    def link(self):
        demographic_link = reverse("patient_edit", args=[self.registry_model.code,
                                                         self.patient_model.pk])
        return demographic_link

    @property
    def questions(self):
        """
        If data already filled in for patient
        grab and return as list of wrappers for view
        There are two special sections PatientData and PatientAddressData
        """
        lst = []
        for question in self.questionnaire.questions:
            if isinstance(question, _ConsentQuestion):
                existing_answer = {"name": question.name,
                                   "pos": str(question.pos),
                                   "is_multi": False,
                                   "answer": self._get_consent_answer(question)
                                   }
                lst.append(existing_answer)
                continue

            if question.section_code == "PatientData":
                field_name = self._get_patient_data_field_name(
                    question.cde_code)
                field_expression = question.cde_code
            elif question.section_code == 'PatientAddressSection':
                field_name = self._get_patient_address_field_name(
                    question.cde_code)
                field_expression = "address field expression"
            else:
                try:
                    field_name = question.target.display_name
                    field_expression = question.target.field_expression
                except Exception as ex:
                    logger.error("could not get target for %s %s: %s" % (question.section_code,
                                                                         question.cde_code,
                                                                         ex))
                    continue

            if field_name in KEY_MAP:
                field_name = question.cde_model.name

            if not question.is_multi:
                existing_answer = {
                    "name": field_name,
                    "pos": str(
                        question.pos),
                    "is_multi": False,
                    "answer": self._get_field_data(
                        field_expression,
                        question.form_model,
                        question.section_model,
                        question.cde_model)}
            else:
                if not question.is_address:
                    existing_answer = {
                        "name": field_name,
                        "pos": str(
                            question.pos),
                        "is_multi": True,
                        "answers": self._get_existing_multisection_data(
                            question.field_expression,
                            question.form_model,
                            question.section_model)}
                else:
                    existing_answer = {
                        "name": field_name, "pos": str(
                            question.pos), "is_multi": True, "answers": self._get_address_labels(
                            question.field_expression)}

            lst.append(existing_answer)

        return lst

    def _get_consent_answer(self, consent_question):
        from registry.patients.models import ConsentValue
        try:
            consent_value_model = ConsentValue.objects.get(
                patient=self.patient_model,
                consent_question=consent_question.consent_question_model)
            if consent_value_model.answer:
                return "Yes"
        except ConsentValue.DoesNotExist:
            return "No"

        return "No"

    def _get_address_labels(self, addresses_expression):

        def address_label(address):
            try:
                atype = address.address_type.description
            except Exception as ex:
                atype = "%s" % ex

            return "%s: %s %s %s %s %s" % (atype,
                                           address.address,
                                           address.suburb,
                                           address.state,
                                           address.postcode,
                                           address.country)

        retriever = self.gfe_parser.parse(addresses_expression)
        address_objects = retriever.evaluate(
            self.patient_model, self.patient_data)
        return [address_label(address) for address in address_objects]

    def _get_existing_multisection_data(self, field_expression, form_model, section_model):
        items_retriever = self.gfe_parser.parse(field_expression)
        display_items = []
        raw_items = items_retriever(self.patient_model, self.patient_data)

        for item in raw_items:
            display_fields = []
            for cde_code in item:
                cde_model = CommonDataElement.objects.get(code=cde_code)
                display_name = cde_model.name
                raw_value = item[cde_code]
                display_value = self.humaniser.display_value2(form_model,
                                                              section_model,
                                                              cde_model,
                                                              raw_value)
                display_field = "%s=%s" % (display_name, display_value)
                display_fields.append(display_field)

            item_field = ",".join(display_fields)
            display_items.append(item_field)

        # list of items displayed as key value pairs
        return display_items

    def _get_patient_data_field_name(self, cde_code):
        return cde_code

    def _get_patient_address_field_name(self, cde_code):
        return cde_code