Skip to content

Commit

Permalink
Merge pull request #186 from openimis/develop
Browse files Browse the repository at this point in the history
MERGING develop into release/24.10
  • Loading branch information
delcroip authored Oct 22, 2024
2 parents 3c9f369 + 9f63fab commit 2329210
Show file tree
Hide file tree
Showing 14 changed files with 55 additions and 39 deletions.
6 changes: 3 additions & 3 deletions api_fhir_r4/containedResources/claimContainedResources.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from typing import Dict, Type

from core.utils import filter_validity
from api_fhir_r4.containedResources.containedResources import AbstractContainedResourceCollection, \
ContainedResourceDefinition
from api_fhir_r4.serializers import BaseFHIRSerializer, PatientSerializer, GroupSerializer, \
Expand All @@ -22,13 +22,13 @@ def _definitions_for_serializers(cls) -> Dict[Type[BaseFHIRSerializer], Containe
MedicationSerializer: ContainedResourceDefinition(
'items', 'Medication',
lambda model, field: [
item.item for item in model.__getattribute__(field).filter(validity_to=None).all()
item.item for item in model.__getattribute__(field).filter(*filter_validity())
]
),
ActivityDefinitionSerializer: ContainedResourceDefinition(
'services', 'ActivityDefinition',
lambda model, field: [
service.service for service in model.__getattribute__(field).filter(validity_to=None).all()
service.service for service in model.__getattribute__(field).filter(*filter_validity())
]
),
}
8 changes: 4 additions & 4 deletions api_fhir_r4/converters/claimConverter.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from fhir.resources.R4B.attachment import Attachment
from fhir.resources.R4B.period import Period
from fhir.resources.R4B.claim import ClaimDiagnosis, ClaimSupportingInfo, ClaimItem as FHIRClaimItem

from core.utils import filter_validity
from api_fhir_r4.utils import TimeUtils, FhirUtils, DbManagerUtils

import logging
Expand Down Expand Up @@ -196,7 +196,7 @@ def build_imis_diagnoses(cls, imis_claim, fhir_claim, errors):

@classmethod
def get_imis_diagnosis_by_code(cls, icd_code):
return Diagnosis.objects.get(code=icd_code)
return Diagnosis.objects.get(code=icd_code, *filter_validity())

@classmethod
def get_imis_diagnosis_code(cls, diagnosis):
Expand Down Expand Up @@ -284,7 +284,7 @@ def build_fhir_items(cls, fhir_claim, imis_claim, reference_type):

@classmethod
def build_fhir_items_for_imis_items(cls, fhir_claim, imis_claim, reference_type):
for claim_item in imis_claim.items.filter(validity_to=None).all():
for claim_item in imis_claim.items.filter(*filter_validity()):
if claim_item:
item_type = R4ClaimConfig.get_fhir_claim_item_code()
cls.build_fhir_item(fhir_claim, claim_item.item.code, item_type, claim_item, reference_type)
Expand Down Expand Up @@ -318,7 +318,7 @@ def build_fhir_item(cls, fhir_claim, code, item_type, claim_item, reference_type

@classmethod
def build_fhir_items_for_imis_services(cls, fhir_claim, imis_claim, reference_type):
for claim_service in imis_claim.services.filter(validity_to=None).all():
for claim_service in imis_claim.services.filter(*filter_validity()):
if claim_service:
item_type = R4ClaimConfig.get_fhir_claim_service_code()
cls.build_fhir_item(fhir_claim, claim_service.service.code, item_type, claim_service, reference_type)
Expand Down
6 changes: 3 additions & 3 deletions api_fhir_r4/converters/claimResponseConverter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from django.db.models import Subquery
from medical.models import Item, Service
import core

from core.utils import filter_validity
from api_fhir_r4.configurations import GeneralConfiguration, R4ClaimConfig
from api_fhir_r4.converters import BaseFHIRConverter, CommunicationRequestConverter, ReferenceConverterMixin
from api_fhir_r4.converters.claimConverter import ClaimConverter
Expand Down Expand Up @@ -234,14 +234,14 @@ def build_fhir_items(cls, fhir_claim_response, imis_claim, reference_type):

@classmethod
def build_fhir_items_for_imis_services(cls, fhir_claim_response, imis_claim, reference_type):
for claim_service in imis_claim.services.filter(validity_to=None).all():
for claim_service in imis_claim.services.filter(*filter_validity()):
if claim_service:
item_type = R4ClaimConfig.get_fhir_claim_service_code()
cls.build_fhir_item(fhir_claim_response, claim_service, item_type, claim_service.rejection_reason, imis_claim, reference_type)

@classmethod
def build_fhir_items_for_imis_items(cls, fhir_claim_response, imis_claim, reference_type):
for claim_item in imis_claim.items.filter(validity_to=None).all():
for claim_item in imis_claim.items.filter(*filter_validity()):
if claim_item:
item_type = R4ClaimConfig.get_fhir_claim_item_code()
cls.build_fhir_item(fhir_claim_response, claim_item, item_type, claim_item.rejection_reason, imis_claim, reference_type)
Expand Down
2 changes: 1 addition & 1 deletion api_fhir_r4/converters/communicationConverter.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from django.utils.translation import gettext as _
from fhir.resources.R4B.communication import Communication, CommunicationPayload
from fhir.resources.R4B.extension import Extension

from django.core.exceptions import ValidationError

class CommunicationConverter(BaseFHIRConverter, ReferenceConverterMixin):

Expand Down
8 changes: 4 additions & 4 deletions api_fhir_r4/converters/contractConverter.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from insuree.models import Family
from contribution.models import Premium
from core.models import Officer
from core.utils import filter_validity
from api_fhir_r4.utils import DbManagerUtils, TimeUtils


Expand Down Expand Up @@ -123,8 +124,8 @@ def build_contract_asset_extension(cls, contract_term_asset, imis_policy, refere
def build_contract_asset_premium(cls, contract_term_asset, imis_policy):
asset_extensions = Extension.construct()
asset_extensions.url = f"{GeneralConfiguration.get_system_base_url()}StructureDefinition/contract-premium"
if Premium.objects.filter(policy=imis_policy, validity_to__isnull=True).count() > 0:
imis_premium = Premium.objects.get(policy=imis_policy, validity_to__isnull=True)
if Premium.objects.filter(policy=imis_policy, *filter_validity()).count() > 0:
imis_premium = Premium.objects.get(policy=imis_policy, *filter_validity())
fhir_premium = cls.build_contract_asset_premium_extension(asset_extensions, imis_premium)
if type(contract_term_asset.extension) is not list:
contract_term_asset.extension = [fhir_premium]
Expand Down Expand Up @@ -279,8 +280,7 @@ def build_contract_asset_type_reference(cls, contract_asset, imis_policy, refere

list_insuree_policy = InsureePolicy.objects.filter(
Q(policy=imis_policy),
Q(validity_from__lte=now),
Q(validity_to__isnull=True) | Q(validity_to__gte=now),
*filter_validity(validity=now),
).only('insuree')

for insuree_policy in list_insuree_policy:
Expand Down
16 changes: 8 additions & 8 deletions api_fhir_r4/converters/coverageEligibilityRequestConverter.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
)
from product.models import Product, ProductService, ProductItem
from uuid import UUID

from core.utils import filter_validity
class CoverageEligibilityRequestConverter(BaseFHIRConverter):

@classmethod
Expand Down Expand Up @@ -80,7 +80,7 @@ def build_fhir_obligatory_fields(cls, coverage_eligibility_request):

@classmethod
def build_fhir_patient(cls, chf_id):
insuree = Insuree.objects.filter(chf_id=chf_id, validity_to__isnull=True)
insuree = Insuree.objects.filter(chf_id=chf_id, *filter_validity())
if insuree.count() == 1:
insuree = insuree.first()
reference = PatientConverter.build_fhir_resource_reference(
Expand Down Expand Up @@ -169,9 +169,9 @@ def build_fhir_insurance(cls, fhir_response, item, request):
cls.build_fhir_benefit_item_element(result, response_eligibility_sp)
# check services and items etc
prod_service = ProductService.objects\
.filter(product=prod_id, validity_to=None, service__code=request.service_code).first()
.filter(product=prod_id, service__code=request.service_code, *filter_validity()).first()
prod_item = ProductItem.objects\
.filter(product=prod_id, validity_to=None, item__code=request.item_code).first()
.filter(product=prod_id, item__code=request.item_code, *filter_validity()).first()
# build coverage item - service
if prod_service:
cls.build_fhir_benefit_item_service_element(result, response_eligibility_sp, prod_service.service)
Expand All @@ -187,7 +187,7 @@ def build_fhir_insurance(cls, fhir_response, item, request):
def build_fhir_coverage(cls, insurance, policy_uuid):
# Due to circular dependency import has to be done inside of method
from api_fhir_r4.converters import CoverageConverter
policy = Policy.objects.filter(uuid=UUID(str(policy_uuid)), validity_to__isnull=True).first()
policy = Policy.objects.filter(uuid=UUID(str(policy_uuid)), *filter_validity()).first()
reference_coverage = CoverageConverter.build_fhir_resource_reference(
policy,
type='Coverage',
Expand Down Expand Up @@ -422,13 +422,13 @@ def __get_code_from_codeable_concept_by_coding_code(cls, codeable_concept):
def __get_coverage_data(cls, response):
policy = InsureePolicy.objects.filter(
insuree__chf_id=response.eligibility_request.chf_id,
validity_to__isnull=True).first().policy
product = Product.objects.get(id=response.prod_id, validity_to__isnull=True)
*filter_validity()).first().policy
product = Product.objects.get(id=response.prod_id, *filter_validity())
return policy, product

@classmethod
def __build_item_product_name(cls, fhir_item, prod_id):
product_queryset = Product.objects.all().filter(id=prod_id, validity_to=None)
product_queryset = Product.objects.all().filter(id=prod_id, *filter_validity())
product = product_queryset.first()
fhir_item.name = product.name
fhir_item.description = product.code
8 changes: 4 additions & 4 deletions api_fhir_r4/converters/locationConverter.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,21 +139,21 @@ def get_location_from_address(cls, fhir_patient_address):
location_reference_ext = next((
ext for ext in fhir_patient_address.extension if 'address-location-reference' in ext.url
))
location = cls.get_imis_obj_by_fhir_reference(location_reference_ext.valueReference)
location = cls.get_imis_obj_by_fhir_reference(location_reference_ext.valueReference)
if location is None and location_reference_ext:
raise FHIRException(f"Invalid location reference, {location_reference_ext.valueReference} doesn't match any location.")
if location is None:
matching_locations = Location.objects \
.filter(
validity_to__isnull=True,
name=address.district,
parent__name=address.state,
name=fhir_patient_address.district,
parent__name=fhir_patient_address.state,
type="D" # HF is expected to be at district level
).distinct()\
.all()

if matching_locations.count() != 1:
raise FHIRException(cls.__get_invalid_location_msg(address, matching_locations))
raise FHIRException(cls.__get_invalid_location_msg(fhir_patient_address, matching_locations))
else:
location = matching_locations.first()
return location
Expand Down
2 changes: 1 addition & 1 deletion api_fhir_r4/converters/locationSiteConverter.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from django.utils.translation import gettext
from location.models import HealthFacility
from location.models import HealthFacility, Location
from api_fhir_r4.configurations import R4IdentifierConfig, R4LocationConfig
from api_fhir_r4.converters import BaseFHIRConverter, ReferenceConverterMixin
from fhir.resources.R4B.location import Location as FHIRLocation
Expand Down
16 changes: 16 additions & 0 deletions api_fhir_r4/exceptions/fhir_api_exception_handler.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
from rest_framework import status
from rest_framework.response import Response
from rest_framework import exceptions, status, views
from api_fhir_r4.exceptions import FHIRException

from django.conf import settings
import traceback
import logging

logger = logging.getLogger(__name__)

def call_default_exception_handler(exc, context):
# Call REST framework's default exception handler first, to get the standard error response.
Expand All @@ -20,8 +26,18 @@ def fhir_api_exception_handler(exc, context):
if 'api_fhir_r4' in request_path:
from api_fhir_r4.converters import OperationOutcomeConverter
fhir_outcome = OperationOutcomeConverter.to_fhir_obj(exc)
if settings.DEBUG and not isinstance(exc, (
exceptions.NotAuthenticated,
exceptions.AuthenticationFailed,
exceptions.PermissionDenied,
FHIRException
)):
trace = traceback.extract_tb(traceback.sys.exc_info()[2])
logger.debug("Unexpected {exc.__class__.__name__} trace:\n" + ''.join(traceback.format_list(trace)))

if not response:
response = __create_server_error_response()

response.data = fhir_outcome.dict()

return response
Expand Down
6 changes: 3 additions & 3 deletions api_fhir_r4/serializers/claimSerializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from api_fhir_r4.converters.claimConverter import ClaimConverter
from fhir.resources.R4B import FHIRAbstractModel
from api_fhir_r4.serializers import BaseFHIRSerializer

from core.utils import filter_validity
import logging
logger = logging.getLogger(__name__)

Expand All @@ -39,11 +39,11 @@ def create(self, validated_data):
return self.create_claim_response(claim.code)

def create_claim_response(self, claim_code):
claim = get_object_or_404(Claim, code=claim_code, validity_to=None)
claim = get_object_or_404(Claim, code=claim_code, *filter_validity())
return ClaimResponseConverter.to_fhir_obj(claim)

def create_claim_attachments(self, claim_code, attachments):
claim = get_object_or_404(Claim, code=claim_code, validity_to=None)
claim = get_object_or_404(Claim, code=claim_code, *filter_validity())
create_attachments(claim.id, attachments)

def to_representation(self, obj):
Expand Down
3 changes: 1 addition & 2 deletions api_fhir_r4/tests/mixin/policyHolderOrganisationTestMixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ class PolicyHolderOrganisationTestMixin(GenericTestMixin):
_TEST_ACTIVITY_CODE = 3
_TEST_CODE = "ABCD"
_TEST_TRADE_NAME = "Test test"
_TEST_LOCATION_ID = 22
_TEST_REGION = 'Tahida'
_TEST_DISTRICT = 'Rajo'
_TEST_MUNICIPALITY = 'Jaber'
Expand Down Expand Up @@ -83,7 +82,7 @@ def verify_imis_instance(self, imis_obj):
NotImplementedError('PH Organization to_imis_obj() not implemented.')

def create_test_imis_instance(self):
location = DbManagerUtils.get_object_or_none(Location, id=self._TEST_LOCATION_ID)
location = DbManagerUtils.get_object_or_none(Location, name=self._TEST_VILLAGE, validity_to__isnull=True)

return PolicyHolder(**{
"uuid": self._TEST_UUID,
Expand Down
2 changes: 1 addition & 1 deletion api_fhir_r4/tests/test_api_authorization.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from api_fhir_r4.configurations import GeneralConfiguration
from api_fhir_r4.tests import GenericFhirAPITestMixin
from gettext import gettext as _
from django.utils.translation import gettext as _

from api_fhir_r4.tests.utils import get_connection_payload,get_or_create_user_api

Expand Down
5 changes: 3 additions & 2 deletions api_fhir_r4/tests/test_api_organisation.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from core.models import User
from rest_framework import status
from policyholder.tests.helpers import create_test_policy_holder
from django.core.exceptions import ValidationError

@dataclass
class DummyContext:
Expand All @@ -34,7 +35,7 @@ def test_simple_list_page_2(self):
"Content-Type": "application/json",
'HTTP_AUTHORIZATION': f"Bearer {self.admin_token}"
}
response = self.client.get(self.base_url+ '?page-offset=2', format='json', **headers)
response = self.client.get(self.base_url + '?page-offset=2', format='json', **headers)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertIsNotNone(response.content)

Expand All @@ -44,7 +45,7 @@ def test_simple_ph(self):
'HTTP_AUTHORIZATION': f"Bearer {self.admin_token}"
}
#
response = self.client.get(self.base_url+ str(self.test_policy_holder.uuid).upper()+ '/' , format='json', **headers)
response = self.client.get(self.base_url + str(self.test_policy_holder.uuid).upper()+ '/' , format='json', **headers)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertIsNotNone(response.content)

Expand Down
6 changes: 3 additions & 3 deletions api_fhir_r4/views/fhir/communication.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from api_fhir_r4.views.fhir.base import BaseFHIRView
from api_fhir_r4.views.filters import ValidityFromRequestParameterFilter
from claim.models import Feedback

from core.utils import filter_validity
import logging
logger = logging.getLogger(__name__)

Expand All @@ -27,7 +27,7 @@ def list(self, request, *args, **kwargs):
if identifier:
return self.retrieve(request, *args, **{**kwargs, 'identifier': identifier})
else:
queryset = queryset.filter(validity_to__isnull=True)
queryset = queryset.filter(*filter_validity())
serializer = CommunicationSerializer(self.paginate_queryset(queryset), many=True, user=request.user)
return self.get_paginated_response(serializer.data)

Expand All @@ -36,5 +36,5 @@ def retrieve(self, *args, **kwargs):
return response

def get_queryset(self):
queryset = Feedback.objects.filter(validity_to=None).order_by('validity_from')
queryset = Feedback.objects.filter(*filter_validity()).order_by('validity_from')
return ValidityFromRequestParameterFilter(self.request).filter_queryset(queryset)

0 comments on commit 2329210

Please sign in to comment.