Skip to content

Commit

Permalink
Adds M2M Consultation Diagnosis model (#1690)
Browse files Browse the repository at this point in the history
* Add ConsultationDiagnosis M2M model and migrations

* ABDM: Update FHIR utils with ConsultationDiagnoses M2M relation

* Update HCX: Update diagnoses in make_claim with M2M relation

* API: Adds serializers, viewsets and api route

* Unlock `unconfirmed` and `differential` verification status

* uncomplicate things....

* minor fixes

* more bug fixes.... :/

* gracefully handle invalid icd11 objects

* fix `load_icd11_diagnoses_data` re-run issue

* Update Discharge Summary

* Annotate CSV export by diagoses

* fix create_disgnoses not working

* minor fix

* fix existing tests

* add tests

* squash migrations

* improve coverage by a tiny factor

* Add authz, optimizations to model, proper validation message

* fix validation

* fix authz

* fix typo

* fix patient notes

* Add chapter information to ICD serialization (#1696)

* HCX: update diagnoses in make claim

* avoid redundant permission checks

* fix errors

* make code pretty

* Apply suggestions from code review

Co-authored-by: Aakash Singh <mail@singhaakash.dev>

---------

Co-authored-by: Aakash Singh <mail@singhaakash.dev>
  • Loading branch information
rithviknishad and sainak authored Nov 8, 2023
1 parent 6f4bedb commit cadfebf
Show file tree
Hide file tree
Showing 20 changed files with 1,006 additions and 239 deletions.
30 changes: 14 additions & 16 deletions care/abdm/utils/fhir.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@
from fhir.resources.reference import Reference

from care.facility.models.file_upload import FileUpload
from care.facility.models.icd11_diagnosis import REVERSE_CONDITION_VERIFICATION_STATUSES
from care.facility.models.patient_investigation import InvestigationValue
from care.facility.static_data.icd11 import ICDDiseases
from care.facility.static_data.icd11 import get_icd11_diagnosis_object_by_id


class Fhir:
Expand Down Expand Up @@ -136,8 +137,8 @@ def _organization(self):

return self._organization_profile

def _condition(self, diagnosis_id, provisional=False):
diagnosis = ICDDiseases.by.id[diagnosis_id]
def _condition(self, diagnosis_id, verification_status):
diagnosis = get_icd11_diagnosis_object_by_id(diagnosis_id)
[code, label] = diagnosis.label.split(" ", 1)
condition_profile = Condition(
id=diagnosis_id,
Expand All @@ -158,8 +159,10 @@ def _condition(self, diagnosis_id, provisional=False):
coding=[
Coding(
system="http://terminology.hl7.org/CodeSystem/condition-ver-status",
code="provisional" if provisional else "confirmed",
display="Provisional" if provisional else "Confirmed",
code=verification_status,
display=REVERSE_CONDITION_VERIFICATION_STATUSES[
verification_status
],
)
]
),
Expand Down Expand Up @@ -368,20 +371,15 @@ def _encounter(self, include_diagnosis=False):
"period": Period(start=period_start, end=period_end),
"diagnosis": list(
map(
lambda diagnosis: EncounterDiagnosis(
lambda consultation_diagnosis: EncounterDiagnosis(
condition=self._reference(
self._condition(diagnosis),
self._condition(
consultation_diagnosis.diagnosis_id,
consultation_diagnosis.verification_status,
),
)
),
self.consultation.icd11_diagnoses,
)
)
+ list(
map(
lambda diagnosis: EncounterDiagnosis(
condition=self._reference(self._condition(diagnosis))
),
self.consultation.icd11_provisional_diagnoses,
self.consultation.diagnoses.all(),
)
)
if include_diagnosis
Expand Down
127 changes: 127 additions & 0 deletions care/facility/api/serializers/consultation_diagnosis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
from typing import Any

from rest_framework import serializers

from care.facility.models import (
INACTIVE_CONDITION_VERIFICATION_STATUSES,
ConsultationDiagnosis,
)
from care.facility.models.icd11_diagnosis import ICD11Diagnosis
from care.facility.static_data.icd11 import get_icd11_diagnosis_object_by_id
from care.users.api.serializers.user import UserBaseMinimumSerializer


class ConsultationCreateDiagnosisSerializer(serializers.ModelSerializer):
def validate_verification_status(self, value):
if value in INACTIVE_CONDITION_VERIFICATION_STATUSES:
raise serializers.ValidationError("Verification status not allowed")
return value

class Meta:
model = ConsultationDiagnosis
fields = ("diagnosis", "verification_status", "is_principal")


class ConsultationDiagnosisSerializer(serializers.ModelSerializer):
id = serializers.UUIDField(source="external_id", read_only=True)
diagnosis = serializers.PrimaryKeyRelatedField(
queryset=ICD11Diagnosis.objects.all(), required=True, allow_null=False
)
diagnosis_object = serializers.SerializerMethodField()
created_by = UserBaseMinimumSerializer(read_only=True)

def get_diagnosis_object(self, obj):
return get_icd11_diagnosis_object_by_id(obj.diagnosis_id, as_dict=True)

class Meta:
model = ConsultationDiagnosis
exclude = (
"consultation",
"external_id",
"deleted",
)
read_only_fields = (
"created_by",
"created_date",
"modified_date",
"is_migrated",
)

def get_consultation_external_id(self):
return self.context["request"].parser_context["kwargs"][
"consultation_external_id"
]

def validate_diagnosis(self, value):
if self.instance and value != self.instance.diagnosis:
raise serializers.ValidationError("Diagnosis cannot be changed")

if (
not self.instance
and ConsultationDiagnosis.objects.filter(
consultation__external_id=self.get_consultation_external_id(),
diagnosis=value,
).exists()
):
raise serializers.ValidationError(
"Diagnosis already exists for consultation"
)

return value

def validate_verification_status(self, value):
if not self.instance and value in INACTIVE_CONDITION_VERIFICATION_STATUSES:
raise serializers.ValidationError("Verification status not allowed")
return value

def validate_is_principal(self, value):
if not value:
return value

qs = ConsultationDiagnosis.objects.filter(
consultation__external_id=self.get_consultation_external_id(),
is_principal=True,
)

if self.instance:
qs = qs.exclude(id=self.instance.id)

if qs.exists():
raise serializers.ValidationError(
"Consultation already has a principal diagnosis. Unset the existing principal diagnosis first."
)

return value

def update(self, instance, validated_data):
if (
"verification_status" in validated_data
and validated_data["verification_status"]
in INACTIVE_CONDITION_VERIFICATION_STATUSES
):
instance.is_principal = False
return super().update(instance, validated_data)

def validate(self, attrs: Any) -> Any:
validated = super().validate(attrs)

if (
"verification_status" in validated
and validated["verification_status"]
in INACTIVE_CONDITION_VERIFICATION_STATUSES
):
validated["is_principal"] = False

if "is_principal" in validated and validated["is_principal"]:
verification_status = validated.get(
"verification_status",
self.instance.verification_status if self.instance else None,
)
if verification_status in INACTIVE_CONDITION_VERIFICATION_STATUSES:
raise serializers.ValidationError(
{
"is_principal": "Refuted/Entered in error diagnoses cannot be marked as Principal Diagnosis"
}
)

return validated
Loading

0 comments on commit cadfebf

Please sign in to comment.