Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

validation-patient-nhs-number #588

Open
wants to merge 6 commits into
base: live
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions project/npda/forms/patient_form.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,31 @@ def clean(self):
),
)

if nhs_number:
if (
Patient.objects.filter(nhs_number=nhs_number)
.exclude(id=self.instance.id)
.exists()
):
self.add_error(
"nhs_number",
ValidationError(
"A patient with this NHS number already exists in the database."
),
)
if unique_reference_number:
if (
Patient.objects.filter(unique_reference_number=unique_reference_number)
.exclude(id=self.instance.id)
.exists()
):
self.add_error(
"unique_reference_number",
ValidationError(
"A patient with this Unique Reference Number already exists in the database."
),
)

reason_leaving_service = cleaned_data.get("reason_leaving_service")
date_leaving_service = cleaned_data.get("date_leaving_service")
if date_leaving_service and not reason_leaving_service:
Expand Down
40 changes: 20 additions & 20 deletions project/npda/general_functions/map.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,29 +107,29 @@ def generate_distance_from_organisation_scatterplot_figure(
"""

english_colorscale = [
[0, RCPCH_PINK_DARK_TINT], # Very dark pink
[0.11, RCPCH_PINK], # pink
[0.22, RCPCH_PINK_LIGHT_TINT1], # Medium light pink
[0.33, RCPCH_PINK_LIGHT_TINT2], # light pink
[0.44, RCPCH_PINK_LIGHT_TINT3], # very light pink
[0.55, RCPCH_LIGHT_BLUE_TINT3], # Very light blue
[0.66, RCPCH_LIGHT_BLUE_TINT2], # Light blue
[0.77, RCPCH_LIGHT_BLUE_TINT1], # Medium light blue
[0.88, RCPCH_LIGHT_BLUE], # blue
[1, RCPCH_LIGHT_BLUE_DARK_TINT], # Dark blue
[0, RCPCH_LIGHT_BLUE_DARK_TINT], # Dark blue
[0.11, RCPCH_LIGHT_BLUE], # blue
[0.22, RCPCH_LIGHT_BLUE_TINT1], # Medium light blue
[0.33, RCPCH_LIGHT_BLUE_TINT2], # Light blue
[0.44, RCPCH_LIGHT_BLUE_TINT3], # Very light blue
[0.55, RCPCH_PINK_LIGHT_TINT3], # very light pink
[0.66, RCPCH_PINK_LIGHT_TINT2], # light pink
[0.77, RCPCH_PINK_LIGHT_TINT1], # Medium light pink
[0.88, RCPCH_PINK], # pink
[1, RCPCH_PINK_DARK_TINT], # Very dark pink
]

welsh_colorscale = [
[0, RCPCH_RED_DARK_TINT],
[0.11, RCPCH_RED],
[0.22, RCPCH_RED_LIGHT_TINT1],
[0.33, RCPCH_RED_LIGHT_TINT2],
[0.44, RCPCH_RED_LIGHT_TINT3],
[0.55, RCPCH_STRONG_GREEN_LIGHT_TINT3],
[0.66, RCPCH_STRONG_GREEN_LIGHT_TINT2],
[0.77, RCPCH_STRONG_GREEN_LIGHT_TINT1],
[0.88, RCPCH_STRONG_GREEN],
[1, RCPCH_STRONG_GREEN_DARK_TINT],
[0, RCPCH_STRONG_GREEN_DARK_TINT],
[0.11, RCPCH_STRONG_GREEN],
[0.22, RCPCH_STRONG_GREEN_LIGHT_TINT1],
[0.33, RCPCH_STRONG_GREEN_LIGHT_TINT2],
[0.44, RCPCH_STRONG_GREEN_LIGHT_TINT3],
[0.55, RCPCH_RED_LIGHT_TINT3],
[0.66, RCPCH_RED_LIGHT_TINT2],
[0.77, RCPCH_RED_LIGHT_TINT1],
[0.88, RCPCH_RED],
[1, RCPCH_RED_DARK_TINT],
]

# # Load the IMD data (there are two files of merged data, one with IMD ranks merged with english LSOA shapes,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,20 @@
{% extends 'dashboard/components/bases/base_card.html' %}
{% block card_title %}
Ethnicity
{% endblock card_title%}
{% endblock card_title %}
{% block card_body %}
{% if charts.pt_ethnicity_tree_map_data.no_eligible_patients %}
<div class="alert alert-info">
<i class="fa-solid fa-person-circle-exclamation"></i> No eligible patients.
</div>
{% else %}
<div
hx-get="{% url 'get_treemap_chart_partial' %}"
hx-vals='{{ charts.pt_ethnicity_tree_map_data }}'
hx-trigger="load" hx-swap="innerHTML"
_="on htmx:afterSwap remove #loading-spinner-ethnicity-card"></div>

<div id="loading-spinner-ethnicity-card"
class="loading loading-spinner text-rcpch_dark_blue flex flex-grow-1 justify-center items-center h-full w-1/5 mx-auto bg-center">
</div>
{% endif %}
{% if charts.pt_ethnicity_tree_map_data.no_eligible_patients %}
<div class="alert alert-info">
<i class="fa-solid fa-person-circle-exclamation"></i> No eligible patients.
</div>
{% else %}
<div hx-get="{% url 'get_treemap_chart_partial' %}"
hx-vals='{{ charts.pt_ethnicity_tree_map_data }}'
hx-trigger="load"
hx-swap="innerHTML"
_="on htmx:afterSwap remove #loading-spinner-ethnicity-card"></div>
<div id="loading-spinner-ethnicity-card"
class="loading loading-spinner text-rcpch_dark_blue flex flex-grow-1 justify-center items-center h-full w-1/5 mx-auto bg-center">
</div>
{% endif %}
{% endblock %}






6 changes: 3 additions & 3 deletions project/npda/templates/dashboard/treemap_chart_partial.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{% if error %}
<div class="alert alert-danger">
<i class="fa-solid fa-person-circle-exclamation"></i> {{ error }}
</div>
<div class="alert alert-danger">
<i class="fa-solid fa-person-circle-exclamation"></i> {{ error }}
</div>
{% elif chart_html %}
{{ chart_html|safe }}
{% endif %}
4 changes: 2 additions & 2 deletions project/npda/templates/partials/patient_table.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
<tbody>
{% for patient in page_obj %}
{% if patient.is_first_valid or patient.is_first_error or patient.is_first_incomplete_full_year %}
<thead class="bg-rcpch_strong_blue text-xs text-white text-gray-700 uppercase bg-gray-50">
<thead class="{% if patient.is_first_incomplete_full_year %} bg-rcpch_strong_blue_dark_tint text-xs {% else %} bg-rcpch_strong_blue text-xs {% endif %} text-white text-gray-700 uppercase bg-gray-50">
<tr>
<th colspan="13" class="px-6 py-3">
{% if patient.is_first_valid %}
Expand All @@ -57,7 +57,7 @@
</tr>
</thead>
{% endif %}
<tr class="{% if forloop.counter|divisibleby:2 %} bg-gray-100 {% endif %} hover:bg-gray-200 {% if patient.is_in_transfer_in_the_last_year %}bg-rcpch_yellow hover:bg-rcpch_yellow_dark_tint {% endif %}">
<tr class="{% if forloop.counter|divisibleby:2 %} bg-gray-100 {% endif %} hover:bg-gray-200 {% if patient.is_in_transfer_in_the_last_year %}bg-rcpch_yellow hover:bg-rcpch_yellow_dark_tint {% elif patient.incomplete_full_year_of_care %} bg-rcpch_strong_blue_light_tint3 hover:bg-rcpch_strong_blue_light_tint2 {% endif %}">
{% with nhs_number_error=patient.errors|error_for_field:"nhs_number" unique_reference_number_error=patient_errors|error_for_field:"unique_reference_number" gp_error=patient.errors|error_for_field:"gp_practice_ods_code" %}
{% jersify_errors_for_unique_patient_identifier pz_code nhs_number_error unique_reference_number_error as unique_identifier_error %}
<td class="whitespace-nowrap">
Expand Down
6 changes: 2 additions & 4 deletions project/npda/views/dashboard/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,14 +323,14 @@ def dashboard(request):
"pt_sex_value_counts_pct": {
"data": json.dumps(pt_sex_value_counts_pct),
},
"pt_ethnicity_tree_map_data": json.dumps(
"pt_ethnicity_tree_map_data":
{
"no_eligible_patients": not pt_ethnicity_value_counts,
"data": pt_ethnicity_value_counts,
"parent_color_map": constants.ethnicities.ETHNICITY_PARENT_COLOR_MAP,
"child_parent_map": constants.ethnicities.ETHNICITY_CHILD_PARENT_MAP,
}
),
,
"pt_imd_value_counts_pct": {
"data": json.dumps(pt_imd_value_counts_pct),
},
Expand All @@ -355,6 +355,4 @@ def dashboard(request):
"aggregation_level": "pdu",
}

print(f"!! {context['charts']['pt_ethnicity_tree_map_data']}")

return render(request, template_name=template, context=context)
7 changes: 2 additions & 5 deletions project/npda/views/dashboard/partials.py
Original file line number Diff line number Diff line change
Expand Up @@ -767,13 +767,10 @@ def get_treemap_chart_partial(request):
labels=all_labels, # Labels including parents
parents=all_parents, # Hierarchical structure
values=all_values, # Sizes
textinfo="label+percent parent", # Show labels and percentages
hoverinfo="label+percent parent", # Show labels and percentages
marker=dict(
# Apply parent colors to subcategories
colors=[all_colors[label] for label in all_labels]
),
hovertemplate=(
"<b>%{label}</b><br>" "N=%{value} (%{percentRoot:.0%})<br><extra></extra>"
colors=[all_colors[label] for label in all_labels],
),
)
)
Expand Down
25 changes: 11 additions & 14 deletions project/npda/views/patient.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# python imports
import datetime
import logging
import json

Expand Down Expand Up @@ -121,14 +122,14 @@ def get_queryset(self):

a_year_ago = timezone.now() - timezone.timedelta(days=365)

has_completed_a_full_year = Q(
diagnosis_date__gt=a_year_ago,
)

patient_queryset = patient_queryset.annotate(
audit_year=F("submissions__audit_year"),
visit_error_count=Count(Case(When(visit__is_valid=False, then=1))),
full_year_of_care=has_completed_a_full_year,
incomplete_full_year_of_care=Case(
When(death_date__isnull=False, then=True),
When(diagnosis_date__lt=a_year_ago, then=True),
default=False,
),
last_upload_date=Max("submissions__submission_date"),
most_recent_visit_date=Max("visit__visit_date"),
distance_from_lead_organisation=Distance(
Expand All @@ -142,12 +143,11 @@ def get_queryset(self):
)

sort_by = self.get_sort_by()

if sort_by:
patient_queryset = patient_queryset.order_by(sort_by)
else:
patient_queryset = patient_queryset.order_by(
"is_valid", "-visit_error_count", "full_year_of_care"
"incomplete_full_year_of_care", "is_valid", "-visit_error_count"
)

return patient_queryset
Expand Down Expand Up @@ -223,10 +223,8 @@ def get_context_data(self, **kwargs):
# unless we are sorting by a particular field in which case errors appear mixed
if not context["sort_by"]:
if (
(not patient.is_valid or patient.visit_error_count > 0)
and patient.full_year_of_care
and patient.death_date is None
):
not patient.is_valid or patient.visit_error_count > 0
) and not patient.incomplete_full_year_of_care:
if error_count_in_page == 0:
patient.is_first_error = True

Expand All @@ -235,15 +233,14 @@ def get_context_data(self, **kwargs):
if (
patient.is_valid
and patient.visit_error_count == 0
and patient.full_year_of_care
and patient.death_date is None
and not patient.incomplete_full_year_of_care
):
if valid_count_in_page == 0:
patient.is_first_valid = True

valid_count_in_page += 1

if patient.full_year_of_care is False or patient.death_date is not None:
if patient.incomplete_full_year_of_care:
if first_incomplete_year_count_in_page == 0:
patient.is_first_incomplete_full_year = True
else:
Expand Down
Loading