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 __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 = ""
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 __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
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
def __init__(self, registry_model, questionnaire, form_name, section_code): self.pos = None self.is_address = section_code == "PatientDataAddressSection" self.registry_model = registry_model self.humaniser = Humaniser(registry_model) self.questionnaire = questionnaire self.form_name = form_name self.section_code = section_code self.target = self._get_target() self.src_id = "test" self.is_multi = True self.items = []
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
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)
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