Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
9 changes: 9 additions & 0 deletions care/emr/api/viewsets/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,15 @@ def perform_create(self, instance):
def perform_update(self, instance):
identifiers = instance._identifiers # noqa: SLF001
with transaction.atomic():
if (
instance.deceased_datetime is None
and self.get_object().deceased_datetime
and not AuthorizationController.call(
"can_unmark_deceased_patient", self.request.user
)
):
raise PermissionDenied(detail="Cannot mark deceased patient alive")

super().perform_update(instance)
for identifier in identifiers:
config = get_object_or_404(
Expand Down
2 changes: 2 additions & 0 deletions care/emr/resources/patient/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ def perform_extra_deserialization(self, is_update, obj):
obj.year_of_birth = timezone.now().year - self.age
elif self.date_of_birth:
obj.year_of_birth = self.date_of_birth.year
if self.deceased_datetime is None:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am a bit terrified about this because None is the default value and if the admin changes some other attribute the patient will be marked undead automatically

obj.deceased_datetime = None
Comment thread
praffq marked this conversation as resolved.
if not self.pincode:
obj.pincode = None

Expand Down
63 changes: 63 additions & 0 deletions care/emr/tests/test_patient_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,69 @@ def test_invalid_date_of_birth_and_death_date(self):
self.assertEqual(error["type"], "validation_error")
self.assertIn("Date of birth cannot be after the date of death", error["msg"])

def test_update_deceased_patient_to_alive(self):
"""Test that a superuser can set deceased_datetime back to None"""
geo_organization = self.create_organization(org_type="govt")
superuser = self.create_super_user()
role = self.create_role_with_permissions(
permissions=[
PatientPermissions.can_create_patient.name,
PatientPermissions.can_write_patient.name,
PatientPermissions.can_list_patients.name,
]
)
self.attach_role_organization_user(geo_organization, superuser, role)
self.client.force_authenticate(user=superuser)

# Create patient with deceased_datetime
deceased_time = care_now() - datetime.timedelta(days=2)
patient_data = self.generate_patient_data(
geo_organization=geo_organization.external_id,
deceased_datetime=deceased_time,
)
response = self.client.post(self.base_url, patient_data, format="json")
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertIsNotNone(response.data["deceased_datetime"])
patient_id = response.data["id"]

# Update patient to set deceased_datetime to None
update_url = reverse("patient-detail", kwargs={"external_id": patient_id})
patient_data["deceased_datetime"] = None
response = self.client.put(update_url, patient_data, format="json")
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertIsNone(response.data["deceased_datetime"])
Comment thread
praffq marked this conversation as resolved.

def test_non_superuser_cannot_unmark_deceased(self):
"""Test that a non-superuser cannot set deceased_datetime back to None"""
geo_organization = self.create_organization(org_type="govt")
user = self.create_user()
Comment thread
coderabbitai[bot] marked this conversation as resolved.
role = self.create_role_with_permissions(
permissions=[
PatientPermissions.can_create_patient.name,
PatientPermissions.can_write_patient.name,
PatientPermissions.can_list_patients.name,
]
)
self.attach_role_organization_user(geo_organization, user, role)
self.client.force_authenticate(user=user)

# Create patient with deceased_datetime
deceased_time = care_now() - datetime.timedelta(days=2)
patient_data = self.generate_patient_data(
geo_organization=geo_organization.external_id,
deceased_datetime=deceased_time,
)
response = self.client.post(self.base_url, patient_data, format="json")
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertIsNotNone(response.data["deceased_datetime"])
patient_id = response.data["id"]

# Attempt to set deceased_datetime to None should be denied
update_url = reverse("patient-detail", kwargs={"external_id": patient_id})
patient_data["deceased_datetime"] = None
response = self.client.put(update_url, patient_data, format="json")
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
Comment thread
praffq marked this conversation as resolved.

def test_invalid_age_and_death_date(self):
user = self.create_user()
geo_organization = self.create_organization(org_type="govt")
Expand Down
4 changes: 4 additions & 0 deletions care/security/authorization/patient.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,5 +127,9 @@ def get_filtered_patients(self, qs, user):
| Q(users_cache__overlap=[user.id])
)

def can_unmark_deceased_patient(self, user):
"""Permission to reverse a patient's deceased status"""
return user.is_superuser


AuthorizationController.register_internal_controller(PatientAccess)