Skip to content

Commit

Permalink
Hcx communications (#1346)
Browse files Browse the repository at this point in the history
* added communication apis in hcx

* fixed HcxOperations import issue

* get recipentCode from policy.insurer_id

* fixed linting errors and conflict in migrations

* added authorization to hcx/communication

* merged conflicting migrations

---------

Co-authored-by: Mathew <matthewzalex@gmail.com>
  • Loading branch information
khavinshankar and mathew-alex authored Jun 15, 2023
1 parent 1219f00 commit d1d29cd
Show file tree
Hide file tree
Showing 17 changed files with 573 additions and 9 deletions.
2 changes: 2 additions & 0 deletions care/facility/api/serializers/file_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ def check_permissions(file_type, associating_id, user, action="create"):
return sample.id
elif file_type == FileUpload.FileType.CLAIM.value:
return associating_id
elif file_type == FileUpload.FileType.COMMUNICATION.value:
return associating_id
else:
raise Exception("Undefined File Type")

Expand Down
27 changes: 27 additions & 0 deletions care/facility/migrations/0360_auto_20230608_1045.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Generated by Django 2.2.11 on 2023-06-08 05:15

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("facility", "0359_auto_20230529_1907"),
]

operations = [
migrations.AlterField(
model_name="fileupload",
name="file_type",
field=models.IntegerField(
choices=[
(1, "PATIENT"),
(2, "CONSULTATION"),
(3, "SAMPLE_MANAGEMENT"),
(4, "CLAIM"),
(5, "DISCHARGE_SUMMARY"),
(6, "COMMUNICATION"),
],
default=1,
),
),
]
12 changes: 12 additions & 0 deletions care/facility/migrations/0361_merge_20230610_2126.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Generated by Django 2.2.11 on 2023-06-10 15:56

from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("facility", "0360_auto_20230608_1750"),
("facility", "0360_auto_20230608_1045"),
]

operations = []
1 change: 1 addition & 0 deletions care/facility/models/file_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class FileType(enum.Enum):
SAMPLE_MANAGEMENT = 3
CLAIM = 4
DISCHARGE_SUMMARY = 5
COMMUNICATION = 6

class FileCategory(enum.Enum):
UNSPECIFIED = "UNSPECIFIED"
Expand Down
41 changes: 41 additions & 0 deletions care/hcx/api/serializers/communication.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from rest_framework.serializers import CharField, JSONField, ModelSerializer, UUIDField

from care.hcx.api.serializers.claim import ClaimSerializer
from care.hcx.models.claim import Claim
from care.hcx.models.communication import Communication
from care.users.api.serializers.user import UserBaseMinimumSerializer
from care.utils.serializer.external_id_field import ExternalIdSerializerField

TIMESTAMP_FIELDS = (
"created_date",
"modified_date",
)


class CommunicationSerializer(ModelSerializer):
id = UUIDField(source="external_id", read_only=True)

claim = ExternalIdSerializerField(
queryset=Claim.objects.all(), write_only=True, required=True
)
claim_object = ClaimSerializer(source="claim", read_only=True)

identifier = CharField(required=False)
content = JSONField(required=False)

created_by = UserBaseMinimumSerializer(read_only=True)
last_modified_by = UserBaseMinimumSerializer(read_only=True)

class Meta:
model = Communication
exclude = ("deleted", "external_id")
read_only_fields = TIMESTAMP_FIELDS

def create(self, validated_data):
validated_data["created_by"] = self.context["request"].user
validated_data["last_modified_by"] = self.context["request"].user
return super().create(validated_data)

def update(self, instance, validated_data):
instance.last_modified_by = self.context["request"].user
return super().update(instance, validated_data)
8 changes: 8 additions & 0 deletions care/hcx/api/serializers/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
from rest_framework.serializers import Serializer, UUIDField

from care.hcx.models.claim import Claim
from care.hcx.models.communication import Communication
from care.hcx.models.policy import Policy
from care.utils.serializer.external_id_field import ExternalIdSerializerField


class CheckEligibilitySerializer(Serializer):
Expand All @@ -28,3 +30,9 @@ def validate(self, attrs):
raise ValidationError({"claim": "Field is Required"})

return super().validate(attrs)


class SendCommunicationSerializer(Serializer):
communication = ExternalIdSerializerField(
queryset=Communication.objects.all(), required=True
)
46 changes: 46 additions & 0 deletions care/hcx/api/viewsets/communication.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from django_filters import rest_framework as filters
from rest_framework import filters as drf_filters
from rest_framework.mixins import (
CreateModelMixin,
ListModelMixin,
RetrieveModelMixin,
UpdateModelMixin,
)
from rest_framework.permissions import IsAuthenticated
from rest_framework.viewsets import GenericViewSet

from care.hcx.api.serializers.communication import CommunicationSerializer
from care.hcx.models.communication import Communication
from care.utils.queryset.communications import get_communications


class CommunicationFilter(filters.FilterSet):
claim = filters.UUIDFilter(field_name="claim__external_id")


class CommunicationViewSet(
CreateModelMixin,
ListModelMixin,
RetrieveModelMixin,
UpdateModelMixin,
GenericViewSet,
):
queryset = Communication.objects.all()
permission_classes = (IsAuthenticated,)
serializer_class = CommunicationSerializer
lookup_field = "external_id"
search_fields = ["claim"]
filter_backends = (
filters.DjangoFilterBackend,
drf_filters.SearchFilter,
drf_filters.OrderingFilter,
)
filterset_class = CommunicationFilter
ordering_fields = [
"id",
"created_date",
"modified_date",
]

def get_queryset(self):
return get_communications(self.request.user)
64 changes: 62 additions & 2 deletions care/hcx/api/viewsets/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@
generate_discharge_report_signed_url,
)
from care.hcx.api.serializers.claim import ClaimSerializer
from care.hcx.api.serializers.communication import CommunicationSerializer
from care.hcx.api.serializers.gateway import (
CheckEligibilitySerializer,
MakeClaimSerializer,
SendCommunicationSerializer,
)
from care.hcx.api.serializers.policy import PolicySerializer
from care.hcx.models.base import (
Expand All @@ -31,10 +33,12 @@
REVERSE_USE_CHOICES,
)
from care.hcx.models.claim import Claim
from care.hcx.models.communication import Communication
from care.hcx.models.policy import Policy
from care.hcx.utils.fhir import Fhir
from care.hcx.utils.hcx import Hcx
from care.hcx.utils.hcx.operations import HcxOperations
from care.utils.queryset.communications import get_communications


class HcxGatewayViewSet(GenericViewSet):
Expand Down Expand Up @@ -93,7 +97,7 @@ def check_eligibility(self, request):
response = Hcx().generateOutgoingHcxCall(
fhirPayload=json.loads(eligibility_check_fhir_bundle.json()),
operation=HcxOperations.COVERAGE_ELIGIBILITY_CHECK,
recipientCode="1-29482df3-e875-45ef-a4e9-592b6f565782",
recipientCode=policy["insurer_id"],
)

return Response(dict(response.get("response")), status=status.HTTP_200_OK)
Expand Down Expand Up @@ -256,7 +260,63 @@ def make_claim(self, request):
operation=HcxOperations.CLAIM_SUBMIT
if REVERSE_USE_CHOICES[claim["use"]] == "claim"
else HcxOperations.PRE_AUTH_SUBMIT,
recipientCode="1-29482df3-e875-45ef-a4e9-592b6f565782",
recipientCode=claim["policy_object"]["insurer_id"],
)

return Response(dict(response.get("response")), status=status.HTTP_200_OK)

@swagger_auto_schema(tags=["hcx"], request_body=SendCommunicationSerializer())
@action(detail=False, methods=["post"])
def send_communication(self, request):
data = request.data

serializer = SendCommunicationSerializer(data=data)
serializer.is_valid(raise_exception=True)

communication = CommunicationSerializer(
get_communications(self.request.user).get(external_id=data["communication"])
).data

payload = [
*communication["content"],
*list(
map(
lambda file: (
{
"type": "url",
"name": file.name,
"data": file.read_signed_url(),
}
),
FileUpload.objects.filter(associating_id=communication["id"]),
)
),
]

communication_fhir_bundle = Fhir().create_communication_bundle(
communication["id"],
communication["id"],
communication["id"],
communication["id"],
payload,
[{"type": "Claim", "id": communication["claim_object"]["id"]}],
)

if not Fhir().validate_fhir_remote(communication_fhir_bundle.json())["valid"]:
return Response(
Fhir().validate_fhir_remote(communication_fhir_bundle.json())["issues"],
status=status.HTTP_400_BAD_REQUEST,
)

response = Hcx().generateOutgoingHcxCall(
fhirPayload=json.loads(communication_fhir_bundle.json()),
operation=HcxOperations.COMMUNICATION_ON_REQUEST,
recipientCode=communication["claim_object"]["policy_object"]["insurer_id"],
correlationId=Communication.objects.filter(
claim__external_id=communication["claim_object"]["id"], created_by=None
)
.last()
.identifier,
)

return Response(dict(response.get("response")), status=status.HTTP_200_OK)
Expand Down
31 changes: 31 additions & 0 deletions care/hcx/api/viewsets/listener.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from rest_framework.response import Response

from care.hcx.models.claim import Claim
from care.hcx.models.communication import Communication
from care.hcx.models.policy import Policy
from care.hcx.utils.fhir import Fhir
from care.hcx.utils.hcx import Hcx
Expand Down Expand Up @@ -91,3 +92,33 @@ def post(self, request, *args, **kwargs):
)

return Response({}, status=status.HTTP_202_ACCEPTED)


class CommunicationRequestView(GenericAPIView):
permission_classes = (AllowAny,)
authentication_classes = []

@swagger_auto_schema(tags=["hcx"])
def post(self, request, *args, **kwargs):
response = Hcx().processIncomingRequest(request.data["payload"])
data = Fhir().process_communication_request(response["payload"])

claim = Claim.objects.filter(external_id__in=data["about"] or []).last()
communication = Communication.objects.create(
claim=claim,
content=data["payload"],
identifier=data[
"identifier"
], # TODO: replace identifier with corelation id
)

message = {
"type": "MESSAGE",
"from": "communication/request",
"message": f"{communication.external_id}",
}
send_webpush(
username=claim.last_modified_by.username, message=json.dumps(message)
)

return Response({}, status=status.HTTP_202_ACCEPTED)
Loading

0 comments on commit d1d29cd

Please sign in to comment.