Skip to content

Commit

Permalink
Merge pull request #710 from eresearchqut/ERP-2589_Demographics_Page_…
Browse files Browse the repository at this point in the history
…Changes_Working_Groups

[ERP-2589] Changes to Demographics Page - Working Groups
  • Loading branch information
ppettitau authored Oct 14, 2024
2 parents 5d344ef + d51ef9b commit fba559e
Show file tree
Hide file tree
Showing 12 changed files with 438 additions and 116 deletions.
13 changes: 12 additions & 1 deletion rdrf/rdrf/helpers/form_section_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,21 @@ def get_next_of_kin_fields(self):
]
return (PATIENT_NEXT_OF_KIN_SECTION_NAME, next_of_kin_fields)

def get_registry_fields(self, clinician_has_patients=False):
def get_registry_fields(
self, clinician_has_patients=False, patient_form_fields=None
):
fields = ["rdrf_registry", "working_groups"]
if clinician_has_patients:
fields.append("registered_clinicians")

if patient_form_fields:
wg_fields = [
field
for field, value in patient_form_fields.items()
if field.startswith("working_groups_")
]
fields.extend(wg_fields)

return _("Registry"), fields

def get_patient_address_section(self):
Expand Down
3 changes: 2 additions & 1 deletion rdrf/rdrf/helpers/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,8 @@ def display(form_or_formset, field, error):
else:
for field in form._errors:
for error in form._errors[field]:
messages.append(display(form, field, error))
field_label = form.fields[field].label
messages.append(display(form, field_label, error))
results = list(map(strip_tags, messages))
return results

Expand Down
12 changes: 11 additions & 1 deletion rdrf/rdrf/models/definition/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from django.contrib.postgres.fields import ArrayField
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models import Q
from django.db.models import Exists, OuterRef, Q
from django.db.models.signals import post_delete, post_save, pre_delete
from django.dispatch.dispatcher import receiver
from django.forms.models import model_to_dict
Expand Down Expand Up @@ -445,6 +445,16 @@ def carer_registration_allowed(self):
def has_email_notification(self, event_type):
return self._registration_check([event_type])

@property
def working_group_types(self):
from registry.groups.models import WorkingGroup, WorkingGroupType

return WorkingGroupType.objects.filter(
Exists(
WorkingGroup.objects.filter(type=OuterRef("pk"), registry=self)
)
)


def get_owner_choices():
"""
Expand Down
6 changes: 6 additions & 0 deletions rdrf/rdrf/static/css/rdrf.css
Original file line number Diff line number Diff line change
Expand Up @@ -308,4 +308,10 @@ form .aligned ul.errorlist {
* Data tables overrides */
.dataTables_processing {
top: 130px !important;
}

/**************************************************************************
* Expandable multi selects */
select[multiple] {
resize: vertical;
}
3 changes: 2 additions & 1 deletion rdrf/rdrf/views/patient_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,8 @@ def get_form_sections(
builder.get_registry_fields(
registry.has_feature(
RegistryFeatures.CLINICIANS_HAVE_PATIENTS
)
),
patient_form.fields,
),
),
),
Expand Down
51 changes: 45 additions & 6 deletions rdrf/registry/groups/forms.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,56 @@
import logging

from django import forms
from django.db.models import Count, F

logger = logging.getLogger(__name__)


def _working_group_types(wg_queryset):
return (
wg_queryset.values("type")
.annotate(name=F("type__name"), aggregate_by_count=Count("type"))
.order_by("type__name")
)


def working_group_fields(wg_queryset, initial):
def filter_queryset_by_type(queryset, working_group_type):
return queryset.filter(type=working_group_type)

def working_group_choices(queryset):
return [(wg.id, wg.display_name) for wg in queryset]

base_choices = working_group_choices(
filter_queryset_by_type(wg_queryset, None)
)

additional_fields = {
f"working_groups_{working_group_type['type']}": forms.MultipleChoiceField(
label=working_group_type["name"],
choices=working_group_choices(
filter_queryset_by_type(wg_queryset, working_group_type["type"])
),
initial=[
wg.id
for wg in filter_queryset_by_type(
initial, working_group_type["type"]
)
],
)
for working_group_type in _working_group_types(wg_queryset)
if working_group_type["type"]
}

return base_choices, additional_fields


def working_group_optgroup_choices(wg_queryset, make_option_fn=None):
def default_make_option_fn(working_group):
# e.g. <option value="{{working_group.id}}">{{working_group}}</option>
return working_group.id, working_group.display_name

make_option_fn = make_option_fn or default_make_option_fn
wg_types = (
wg_queryset.values("type")
.annotate(name=F("type__name"), type_cnt=Count("type"))
.order_by("type__name")
)
return [
(
wg_type.get("name"),
Expand All @@ -20,5 +59,5 @@ def default_make_option_fn(working_group):
for wg in wg_queryset.filter(type=wg_type.get("type"))
],
)
for wg_type in wg_types
for wg_type in (_working_group_types(wg_queryset))
]
126 changes: 91 additions & 35 deletions rdrf/registry/patients/admin_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
DemographicFields,
)
from registry.groups import GROUPS
from registry.groups.forms import working_group_optgroup_choices
from registry.groups.forms import working_group_fields
from registry.groups.models import CustomUser, WorkingGroup
from registry.patients.patient_widgets import PatientRelativeLinkWidget

Expand Down Expand Up @@ -505,11 +505,24 @@ def clinician_display_str(obj):
"working_groups"
].queryset = instance.working_groups.all()
else:
self.fields[
"working_groups"
].choices = working_group_optgroup_choices(
WorkingGroup.objects.filter(registry=self.registry_model)
working_groups_choices, additional_working_group_fields = (
working_group_fields(
WorkingGroup.objects.filter(
registry=self.registry_model
),
self.instance.working_groups.all()
if self.instance.id
else WorkingGroup.objects.none(),
)
)
self.fields.update(additional_working_group_fields)
self.fields["working_groups"].choices = working_groups_choices
if not working_groups_choices:
self.fields["working_groups"].disabled = True
self.fields["working_groups"].required = False
self.fields[
"working_groups"
].widget = forms.MultipleHiddenInput()

# field visibility restricted no non admins
if not user.is_superuser:
Expand All @@ -528,31 +541,56 @@ def get_field_config(field):
if fc is not None
]

for field_config in field_configs:
field = field_config.field
def apply_field_config(target_field, target_field_config):
if getattr(
self.fields[field].widget,
self.fields[target_field].widget,
"allow_multiple_selected",
False,
):
if field_config.status == DemographicFields.HIDDEN:
if (
target_field_config.status
== DemographicFields.HIDDEN
):
self.fields[
field
target_field
].widget = forms.MultipleHiddenInput()
elif field_config.status == DemographicFields.READONLY:
self.fields[field].required = False
self.fields[field].widget.attrs.update(
elif (
target_field_config.status
== DemographicFields.READONLY
):
self.fields[target_field].required = False
self.fields[target_field].widget.attrs.update(
{"disabled": "disabled"}
)
else:
if field_config.status == DemographicFields.HIDDEN:
self.fields[field].widget = forms.HiddenInput()
self.fields[field].label = ""
elif field_config.status == DemographicFields.READONLY:
self.fields[field].widget = forms.TextInput(
if (
target_field_config.status
== DemographicFields.HIDDEN
):
self.fields[
target_field
].widget = forms.HiddenInput()
self.fields[target_field].label = ""
elif (
target_field_config.status
== DemographicFields.READONLY
):
self.fields[target_field].widget = forms.TextInput(
attrs={"readonly": "readonly"}
)

for field_config in field_configs:
field = field_config.field
apply_field_config(field, field_config)
if field == "working_groups":
additional_working_group_fields = [
form_fields
for form_fields in self.fields
if form_fields.startswith("working_groups_")
]
for wg_field in additional_working_group_fields:
apply_field_config(wg_field, field_config)

if (
not user.is_patient
and self.registry_model
Expand Down Expand Up @@ -638,20 +676,18 @@ def _setup_add_form(self):
user = None

if not user.is_superuser:
working_groups_query = (
WorkingGroup.objects.get_by_user_and_registry(
user, self.registry_model
)
self.fields[
"working_groups"
].queryset = WorkingGroup.objects.get_by_user_and_registry(
user, self.registry_model
)
else:
working_groups_query = WorkingGroup.objects.filter(
self.fields[
"working_groups"
].queryset = WorkingGroup.objects.filter(
registry=self.registry_model
)

self.fields["working_groups"].choices = working_group_optgroup_choices(
working_groups_query
)

date_of_birth = forms.DateField(
widget=forms.DateInput(
attrs={"class": "datepicker"}, format="%d-%m-%Y"
Expand Down Expand Up @@ -699,17 +735,37 @@ def clean_rdrf_registry(self):
return registries

def clean_working_groups(self):
is_disabled = "disabled" in self.fields["working_groups"].widget.attrs
is_disabled = (
"disabled" in self.fields["working_groups"].widget.attrs
or self.fields["working_groups"].disabled
)
empty_choices = not self.fields["working_groups"].choices

if is_disabled:
return self.instance.working_groups.all()
if empty_choices:
working_groups = WorkingGroup.objects.none()
else:
working_groups = self.instance.working_groups.all()
else:
ret_val = self.cleaned_data["working_groups"]
if not ret_val:
raise forms.ValidationError(
"Patient must be assigned to a working group"
)
return ret_val
working_groups = self.cleaned_data["working_groups"]

field_names = [
key for key in self.data.keys() if key.startswith("working_groups_")
]
field_values = [
value
for field_name in field_names
for value in self.data.getlist(field_name)
]

all_selected_working_groups = working_groups.union(
WorkingGroup.objects.filter(id__in=field_values)
)
if not all_selected_working_groups:
raise forms.ValidationError(
"Patient must be assigned to a working group"
)
return all_selected_working_groups

def clean_registered_clinicians(self):
reg = self.cleaned_data.get("rdrf_registry", Registry.objects.none())
Expand Down
22 changes: 14 additions & 8 deletions rdrf/report/forms.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import logging

from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
Expand Down Expand Up @@ -30,20 +31,25 @@
)
from report.utils import load_report_configuration

logger = logging.getLogger(__name__)


def get_demographic_field_value(model_name, field):
return json.dumps({"model": model_name, "field": field})


def get_demographic_field_choices(cfg_demographic_model):
demographic_fields = []
for model, model_attrs in cfg_demographic_model.items():
field_choices = [
(get_demographic_field_value(model, key), value)
for key, value in model_attrs["fields"].items()
]
demographic_fields.append((model_attrs["label"], field_choices))
return demographic_fields
return [
(
model_attrs["label"],
[
(get_demographic_field_value(model, key), value)
for key, value in model_attrs["fields"].items()
],
)
for model, model_attrs in cfg_demographic_model.items()
if model_attrs.get("show_in_designer", True)
]


def get_cde_field_value(context_form_group, cde_key):
Expand Down
Loading

0 comments on commit fba559e

Please sign in to comment.