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

Added support to map care facilities with abdm health facility #1550

Merged
merged 6 commits into from
Aug 25, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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
9 changes: 9 additions & 0 deletions care/abdm/api/serializers/health_facility.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from rest_framework import serializers

from care.abdm.models import HealthFacility


class HealthFacilitySerializer(serializers.ModelSerializer):
class Meta:
model = HealthFacility
exclude = ("deleted",)
1 change: 1 addition & 0 deletions care/abdm/api/viewsets/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ def post(self, request, *args, **kwargs):

AbdmGateway().data_notify(
{
"health_id": consent["notification"]["consentDetail"]["patient"]["id"],
"consent_id": data["hiRequest"]["consent"]["id"],
"transaction_id": data["transactionId"],
"care_contexts": list(
Expand Down
67 changes: 67 additions & 0 deletions care/abdm/api/viewsets/health_facility.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from django.shortcuts import get_object_or_404
from rest_framework.mixins import (
CreateModelMixin,
ListModelMixin,
RetrieveModelMixin,
UpdateModelMixin,
)
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet

from care.abdm.api.serializers.health_facility import HealthFacilitySerializer
from care.abdm.models import HealthFacility
from care.abdm.utils.api_call import Bridge
from care.utils.queryset.facility import get_facility_queryset


class HealthFacilityViewSet(
GenericViewSet,
CreateModelMixin,
ListModelMixin,
RetrieveModelMixin,
UpdateModelMixin,
):
serializer_class = HealthFacilitySerializer
model = HealthFacility
queryset = HealthFacility.objects.all()
permission_classes = (IsAuthenticated,)
lookup_field = "facility__external_id"

def get_facility(self, facility_external_id):
facilities = get_facility_queryset(self.request.user)
return get_object_or_404(facilities.filter(external_id=facility_external_id))

def link_health_facility(self, hf_id, facility_id):
facility = self.get_facility(facility_id)
return Bridge().add_update_service(
{
"id": hf_id,
"name": facility.name,
"type": "HIP",
"active": True,
"alias": ["CARE_HIP"],
}
)

def create(self, request, *args, **kwargs):
if (
self.link_health_facility(
request.data["hf_id"], request.data["facility"]
).status_code
== 200
):
return super().create(request, *args, **kwargs)

return Response({"message": "Error linking health facility"}, status=400)

def update(self, request, *args, **kwargs):
if (
self.link_health_facility(
request.data["hf_id"], kwargs["facility__external_id"]
).status_code
== 200
):
return super().update(request, *args, **kwargs)

return Response({"message": "Error linking health facility"}, status=400)
4 changes: 3 additions & 1 deletion care/abdm/api/viewsets/healthid.py
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,9 @@ def patient_sms_notify(self, request, *args, **kwargs):
status=status.HTTP_404_NOT_FOUND,
)

response = AbdmGateway().patient_sms_notify({"phone": patient.phone_number})
response = AbdmGateway().patient_sms_notify(
{"phone": patient.phone_number, "healthId": patient.abha_number.health_id}
)

return Response(response, status=status.HTTP_202_ACCEPTED)

Expand Down
55 changes: 55 additions & 0 deletions care/abdm/migrations/0009_healthfacility.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Generated by Django 4.2.2 on 2023-08-21 09:53

import uuid

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("facility", "0378_consultationbedasset_consultationbed_assets"),
("abdm", "0008_abhanumber_new"),
]

operations = [
migrations.CreateModel(
name="HealthFacility",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"external_id",
models.UUIDField(db_index=True, default=uuid.uuid4, unique=True),
),
(
"created_date",
models.DateTimeField(auto_now_add=True, db_index=True, null=True),
),
(
"modified_date",
models.DateTimeField(auto_now=True, db_index=True, null=True),
),
("deleted", models.BooleanField(db_index=True, default=False)),
("hf_id", models.CharField(max_length=50, unique=True)),
(
"facility",
models.OneToOneField(
on_delete=django.db.models.deletion.PROTECT,
to="facility.facility",
to_field="external_id",
),
),
],
options={
"abstract": False,
},
),
]
10 changes: 10 additions & 0 deletions care/abdm/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,13 @@ class AbhaNumber(BaseModel):

def __str__(self):
return self.abha_number


class HealthFacility(BaseModel):
hf_id = models.CharField(max_length=50, unique=True)
facility = models.OneToOneField(
"facility.Facility", on_delete=models.PROTECT, to_field="external_id"
)

def __str__(self):
return self.hf_id + " " + self.facility.name
40 changes: 32 additions & 8 deletions care/abdm/utils/api_call.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

GATEWAY_API_URL = settings.ABDM_URL
HEALTH_SERVICE_API_URL = settings.HEALTH_SERVICE_API_URL
ABDM_DEVSERVICE_URL = GATEWAY_API_URL + "/devservice"
ABDM_GATEWAY_URL = GATEWAY_API_URL + "/gateway"
ABDM_TOKEN_URL = ABDM_GATEWAY_URL + "/v0.5/sessions"
ABDM_TOKEN_CACHE_KEY = "abdm_token"
Expand All @@ -42,6 +43,8 @@ def __init__(self, gateway, token):
self.url = GATEWAY_API_URL
elif gateway == "abdm_gateway":
self.url = ABDM_GATEWAY_URL
elif gateway == "abdm_devservice":
self.url = ABDM_DEVSERVICE_URL
else:
self.url = GATEWAY_API_URL
self.token = token
Expand Down Expand Up @@ -115,7 +118,7 @@ def get(self, path, params=None, auth=None):
logger.info("{} Response: {}".format(response.status_code, response.text))
return response

def post(self, path, data=None, auth=None, additional_headers=None):
def post(self, path, data=None, auth=None, additional_headers=None, method="POST"):
url = self.url + path
headers = {
"Content-Type": "application/json",
Expand All @@ -133,7 +136,7 @@ def post(self, path, data=None, auth=None, additional_headers=None):
data_json = json.dumps(data)
# logger.info("curl -X POST {} {} -d {}".format(url, headers_string, data_json))
logger.info("Posting Request to: {}".format(url))
response = requests.post(url, headers=headers, data=data_json)
response = requests.request(method, url, headers=headers, data=data_json)
logger.info("{} Response: {}".format(response.status_code, response.text))
return response

Expand Down Expand Up @@ -338,12 +341,17 @@ def verify_document_mobile_otp(self, data):
class AbdmGateway:
# TODO: replace this with in-memory db (redis)
temp_memory = {}
hip_name = "Coronasafe Care 01"
hip_id = "IN3210000017"

def __init__(self):
self.api = APIGateway("abdm_gateway", None)

def get_hip_id_by_health_id(self, health_id):
return (
AbhaNumber.objects.filter(Q(abha_number=health_id) | Q(health_id=health_id))
.first()
.patientregistration.facility.healthfacility.hf_id
)

def add_care_context(self, access_token, request_id):
if request_id not in self.temp_memory:
return
Expand Down Expand Up @@ -415,7 +423,10 @@ def fetch_modes(self, data):
"query": {
"id": data["healthId"],
"purpose": data["purpose"] if "purpose" in data else "KYC_AND_LINK",
"requester": {"type": "HIP", "id": self.hip_id},
"requester": {
"type": "HIP",
"id": self.get_hip_id_by_health_id(data["healthId"]),
},
},
}
response = self.api.post(path, payload, None, additional_headers)
Expand Down Expand Up @@ -443,7 +454,10 @@ def init(self, prev_request_id):
"id": data["healthId"],
"purpose": data["purpose"] if "purpose" in data else "KYC_AND_LINK",
"authMode": data["authMode"] if "authMode" in data else "DEMOGRAPHICS",
"requester": {"type": "HIP", "id": self.hip_id},
"requester": {
"type": "HIP",
"id": self.get_hip_id_by_health_id(data["healthId"]),
},
},
}
response = self.api.post(path, payload, None, additional_headers)
Expand Down Expand Up @@ -705,7 +719,7 @@ def data_notify(self, data):
),
"statusNotification": {
"sessionStatus": "TRANSFERRED",
"hipId": self.hip_id,
"hipId": self.get_hip_id_by_health_id(data["health_id"]),
"statusResponses": list(
map(
lambda context: {
Expand Down Expand Up @@ -753,7 +767,7 @@ def patient_sms_notify(self, data):
),
"notification": {
"phoneNo": f"+91-{data['phone']}",
"hip": {"name": self.hip_name, "id": self.hip_id},
"hip": {"id": self.get_hip_id_by_health_id(data["healthId"])},
},
}

Expand All @@ -766,3 +780,13 @@ def on_share(self, data):
additional_headers = {"X-CM-ID": settings.X_CM_ID}
response = self.api.post(path, data, None, additional_headers)
return response


class Bridge:
def __init__(self):
self.api = APIGateway("abdm_devservice", None)

def add_update_service(self, data):
path = "/v1/bridges/addUpdateServices"
response = self.api.post(path, data, method="PUT")
return response
4 changes: 4 additions & 0 deletions config/api_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from rest_framework_nested.routers import NestedSimpleRouter

from care.abdm.api.viewsets.abha import AbhaViewSet
from care.abdm.api.viewsets.health_facility import HealthFacilityViewSet
from care.abdm.api.viewsets.healthid import ABDMHealthIDViewSet
from care.facility.api.viewsets.ambulance import (
AmbulanceCreateViewSet,
Expand Down Expand Up @@ -222,6 +223,9 @@
# ABDM endpoints
if settings.ENABLE_ABDM:
router.register("abdm/healthid", ABDMHealthIDViewSet, basename="abdm-healthid")
router.register(
"abdm/health_facility", HealthFacilityViewSet, basename="abdm-healthfacility"
)

app_name = "api"
urlpatterns = [
Expand Down