diff --git a/api_fhir_r4/containedResources/containedResourceHandler.py b/api_fhir_r4/containedResources/containedResourceHandler.py index 67d89b84..375f193c 100644 --- a/api_fhir_r4/containedResources/containedResourceHandler.py +++ b/api_fhir_r4/containedResources/containedResourceHandler.py @@ -111,4 +111,4 @@ def _is_saved_in_db(self, obj: models.Model): def _model_to_dict(self, instance): # Due to how serializers are build simple __dict__ is used instead of builtin model_to_dict - return instance.__dict__ + return {k: v for k, v in instance.__dict__.items() if not k.startswith('_')} diff --git a/api_fhir_r4/containedResources/serializerMixin.py b/api_fhir_r4/containedResources/serializerMixin.py index e154ae38..940d4bf9 100644 --- a/api_fhir_r4/containedResources/serializerMixin.py +++ b/api_fhir_r4/containedResources/serializerMixin.py @@ -61,7 +61,9 @@ def _get_converted_resources(self, obj): def to_internal_value(self, data): audit_user_id = self.get_audit_user_id() - return self.fhirConverter.to_imis_obj(data, audit_user_id).__dict__ + imis_obj = self.fhirConverter(user=self.user).to_imis_obj(data, audit_user_id) + # Filter out special attributes + return {k: v for k, v in imis_obj.__dict__.items() if not k.startswith('_') and v is not None} def create(self, validated_data): self._create_or_update_contained(validated_data) diff --git a/api_fhir_r4/converters/__init__.py b/api_fhir_r4/converters/__init__.py index d3b45a52..5366afc1 100644 --- a/api_fhir_r4/converters/__init__.py +++ b/api_fhir_r4/converters/__init__.py @@ -16,7 +16,7 @@ from fhir.resources.R4B.reference import Reference from fhir.resources.R4B.identifier import Identifier from api_fhir_r4.configurations import GeneralConfiguration - +from uuid import UUID class BaseFHIRConverter(ABC): @@ -25,13 +25,8 @@ def __init__(self, user=None): if user: self.user = user else: - self.user = core.models.InteractiveUser.objects.filter( - user_roles=core.models.UserRole.objects.filter( - role__is_system=64, - *core.utils.filter_validity() - ), - *core.utils.filter_validity() - ).first() + raise Exception("Converter init need a valid user") + @classmethod def to_fhir_obj(cls, obj, reference_type): @@ -275,7 +270,34 @@ def get_id_from_reference(cls, reference): id_from_reference = splited_reference_string.pop() return id_from_reference - + @classmethod + def build_imis_identifier(cls, imis_obj, fhir_obj, errors): + history_model = issubclass(imis_obj.__class__, core.models.HistoryModel) + code = cls.get_fhir_identifier_by_code( + fhir_obj.identifier, + R4IdentifierConfig.get_fhir_generic_type_code() + ) + uuid_str = cls.get_fhir_identifier_by_code( + fhir_obj.identifier, + R4IdentifierConfig.get_fhir_uuid_type_code() + ) + id_str = None + if not history_model: + id_str = cls.get_fhir_identifier_by_code( + fhir_obj.identifier, + R4IdentifierConfig.get_fhir_acsn_type_code() + ) + if id_str: + imis_obj.id = id_str + if uuid_str: + if history_model: + imis_obj.id = UUID(uuid_str) + else: + imis_obj.uuid = UUID(uuid_str) + # if we have the id th uuid in not used + if code: + imis_obj.code = code + from api_fhir_r4.converters.personConverterMixin import PersonConverterMixin from api_fhir_r4.converters.referenceConverterMixin import ReferenceConverterMixin from api_fhir_r4.converters.medicationConverter import MedicationConverter diff --git a/api_fhir_r4/converters/medicationConverter.py b/api_fhir_r4/converters/medicationConverter.py index 1232de06..9e9c3c94 100644 --- a/api_fhir_r4/converters/medicationConverter.py +++ b/api_fhir_r4/converters/medicationConverter.py @@ -18,6 +18,7 @@ from api_fhir_r4.configurations import GeneralConfiguration import core import re +from uuid import UUID class MedicationConverter(BaseFHIRConverter, ReferenceConverterMixin): @@ -44,7 +45,7 @@ def to_imis_obj(cls, fhir_medication, audit_user_id): imis_medication = Item() imis_medication.audit_user_id = audit_user_id cls.build_imis_identifier(imis_medication, fhir_medication, errors) - cls.build_imis_item_code(imis_medication, fhir_medication, errors) + #cls.build_imis_item_code(imis_medication, fhir_medication, errors) cls.build_imis_item_name(imis_medication, fhir_medication, errors) cls.build_imis_item_package(imis_medication, fhir_medication, errors) cls.build_imis_item_extension(imis_medication, fhir_medication, errors) @@ -85,11 +86,11 @@ def build_fhir_identifiers(cls, fhir_medication, imis_medication): @classmethod def build_imis_identifier(cls, imis_medication, fhir_medication, errors): - value = cls.get_fhir_identifier_by_code(fhir_medication.identifier, - R4IdentifierConfig.get_fhir_uuid_type_code()) - if value: - imis_medication.code = value - cls.valid_condition(imis_medication.code is None, gettext('Missing the item code'), errors) + super().build_imis_identifier(imis_medication, fhir_medication, errors) + cls.valid_condition( + not imis_medication.code, + gettext('Missing medication `item_code` attribute'), errors + ) @classmethod def build_fhir_package_form(cls, fhir_medication, imis_medication): diff --git a/api_fhir_r4/mixins.py b/api_fhir_r4/mixins.py index 05924c49..e9346ef6 100644 --- a/api_fhir_r4/mixins.py +++ b/api_fhir_r4/mixins.py @@ -1,20 +1,105 @@ import logging from abc import abstractmethod, ABC +from collections.abc import Iterable + from typing import List +from rest_framework import status from django.core.exceptions import ObjectDoesNotExist, FieldError from django.http import Http404 -from rest_framework import mixins - from api_fhir_r4.model_retrievers import GenericModelRetriever from rest_framework.response import Response - +from core.models import HistoryModel from api_fhir_r4.multiserializer.mixins import MultiSerializerUpdateModelMixin, MultiSerializerRetrieveModelMixin +from rest_framework.mixins import ( + CreateModelMixin as RestCreateModelMixin, + UpdateModelMixin as RestUpdateModelMixin, + ListModelMixin as RestListModelMixin, + DestroyModelMixin as RestDestroyModelMixin, + RetrieveModelMixin as RestRetrieveModelMixin, +) logger = logging.getLogger(__name__) +class CreateModelMixin(RestCreateModelMixin): + + def create(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data, user=request.user) + serializer.is_valid(raise_exception=True) + self.perform_create(serializer) + headers = self.get_success_headers(serializer.data) + return Response( + serializer.data, + status=status.HTTP_201_CREATED, + headers=headers + ) + + +class UpdateModelMixin(RestUpdateModelMixin): + """ + Update a model instance. + """ + def update(self, request, *args, **kwargs): + partial = kwargs.pop('partial', False) + instance = self.get_object() + serializer = self.get_serializer(instance, data=request.data, partial=partial, user=request.user) + serializer.is_valid(raise_exception=True) + self.perform_update(serializer) + + if getattr(instance, '_prefetched_objects_cache', None): + # If 'prefetch_related' has been applied to a queryset, we need to + # forcibly invalidate the prefetch cache on the instance. + instance._prefetched_objects_cache = {} + + return Response(serializer.data) + + +class ListModelMixin(RestListModelMixin): + """ + List a queryset. + """ + def list(self, request, *args, **kwargs): + queryset = self.filter_queryset(self.get_queryset()) + if not isinstance(queryset, Iterable): + queryset = queryset.all().order_by('code' if hasattr(queryset.model, 'code') else 'id') + page = self.paginate_queryset(queryset) + if page is not None: + serializer = self.get_serializer(page, many=True, user=request.user) + return self.get_paginated_response(serializer.data) + + serializer = self.get_serializer(queryset, many=True) + return Response(serializer.data) + +class DestroyModelMixin(RestDestroyModelMixin): + """ + Destroy a model instance. + """ + def destroy(self, request, *args, **kwargs): + instance = self.get_object() + self.user = request.user + self.perform_destroy(instance) + return Response(status=status.HTTP_204_NO_CONTENT) + + def perform_destroy(self, instance): + if issubclass(instance.__class__, HistoryModel): + instance.delete(user=self.user) + else: + instance.delete() + + +class RetrieveModelMixin(RestRetrieveModelMixin): + """ + Retrieve a model instance. + """ + def retrieve(self, request, *args, **kwargs): + self.user = request.user + instance = self.get_object() + serializer = self.get_serializer(instance, user=self.user) + return Response(serializer.data) + + class GenericMultiIdentifierMixin(ABC): lookup_field = 'identifier' @@ -44,15 +129,15 @@ def _get_object_with_first_valid_retriever(self, identifier): raise Http404(f"Resource for identifier {identifier} not found") -class MultiIdentifierRetrieverMixin(mixins.RetrieveModelMixin, GenericMultiIdentifierMixin, ABC): +class MultiIdentifierRetrieverMixin(RetrieveModelMixin, GenericMultiIdentifierMixin, ABC): def retrieve(self, request, *args, **kwargs): ref_type, instance = self._get_object_with_first_valid_retriever(kwargs['identifier']) - serializer = self.get_serializer(instance, reference_type=ref_type) + serializer = self.get_serializer(instance, reference_type=ref_type, user=request.user) return Response(serializer.data) -class MultiIdentifierUpdateMixin(mixins.UpdateModelMixin, GenericMultiIdentifierMixin, ABC): +class MultiIdentifierUpdateMixin(UpdateModelMixin, GenericMultiIdentifierMixin, ABC): def update(self, request, *args, **kwargs): partial = kwargs.pop('partial', False) @@ -101,7 +186,7 @@ def update(self, request, *args, **kwargs): for serializer, (qs, _, _) in self.get_eligible_serializers_iterator(): ref_type, instance = self._get_object_with_first_valid_retriever(qs, kwargs['identifier']) update_result = self._update_for_serializer(serializer, instance, request.data, partial, - reference_type=ref_type) + reference_type=ref_type, user=request.user) results.append(update_result) response = results[0] # By default there should be only one eligible serializer @@ -126,3 +211,4 @@ def retrieve(self, request, *args, **kwargs): raise Http404(f"Resource for identifier {kwargs['identifier']} not found") return Response(retrieved[0]) + diff --git a/api_fhir_r4/model_retrievers.py b/api_fhir_r4/model_retrievers.py index 9ca79e55..b7ef6840 100644 --- a/api_fhir_r4/model_retrievers.py +++ b/api_fhir_r4/model_retrievers.py @@ -4,9 +4,9 @@ from django.db.models.query import QuerySet from django.db.models import Model - +from insuree.services import validate_insuree_number from api_fhir_r4.converters import ReferenceConverterMixin - +from django.core.exceptions import ValidationError class GenericModelRetriever(ABC): @@ -36,7 +36,16 @@ def retriever_additional_queryset_filtering(cls, queryset): @classmethod def get_model_object(cls, queryset: QuerySet, identifier_value) -> Model: - return queryset.get(**{cls.identifier_field: identifier_value}) + filters = {} + if cls.serializer_reference_type == 'uuid_reference': + identifier_value = uuid.UUID(str(identifier_value)) + elif hasattr(queryset.model, 'validity_to'): + filters['validity_to__isnull'] = True + filters[cls.identifier_field] = identifier_value + try: + return queryset.get(**filters) + except Exception as e: + raise ValidationError(f"failed to retrieve {queryset.model.__name__} with the filter {filters}; details {e}") class UUIDIdentifierModelRetriever(GenericModelRetriever): @@ -73,10 +82,7 @@ class CodeIdentifierModelRetriever(GenericModelRetriever): def identifier_validator(cls, identifier_value): return isinstance(identifier_value, str) - @classmethod - def add_retriever_queryset_filtering(cls, queryset): - # By default no additional changes are made in queryset - return queryset.filter(validity_to__is_null=True) + class CHFIdentifierModelRetriever(CodeIdentifierModelRetriever): @@ -85,11 +91,7 @@ class CHFIdentifierModelRetriever(CodeIdentifierModelRetriever): @classmethod def identifier_validator(cls, identifier_value): # From model specification - return isinstance(identifier_value, str) and len(identifier_value) <= 12 - - @classmethod - def get_model_object(cls, queryset: QuerySet, identifier_value) -> Model: - return queryset.get(**{cls.identifier_field: identifier_value, 'validity_to__isnull': True}) + return isinstance(identifier_value, str) and validate_insuree_number(identifier_value) class GroupIdentifierModelRetriever(CHFIdentifierModelRetriever): diff --git a/api_fhir_r4/multiserializer/mixins.py b/api_fhir_r4/multiserializer/mixins.py index b4007dfd..8ea94676 100644 --- a/api_fhir_r4/multiserializer/mixins.py +++ b/api_fhir_r4/multiserializer/mixins.py @@ -379,15 +379,15 @@ def update(self, request, *args, **kwargs): results = [] for serializer, (qs, _, _) in self.get_eligible_serializers_iterator(): instance = self.get_object_by_queryset(qs=qs) - update_result = self._update_for_serializer(serializer, instance, request.data, partial) + update_result = self._update_for_serializer(serializer, instance, request.data, partial, user=request.user) results.append(update_result) response = results[0] # By default there should be only one eligible serializer return Response(response) - def _update_for_serializer(self, serializer, instance, data, partial, *args, **kwargs): + def _update_for_serializer(self, serializer, instance, data, partial, user=None, *args, **kwargs): context = self.get_serializer_context() # Required for audit user id - serializer = serializer(instance, data=data, partial=partial, context=context, *args, **kwargs) + serializer = serializer(instance, data=data, partial=partial, context=context, user=user, *args, **kwargs) serializer.is_valid(raise_exception=True) self.perform_update(serializer) if getattr(instance, '_prefetched_objects_cache', None): diff --git a/api_fhir_r4/multiserializer/serializerClass.py b/api_fhir_r4/multiserializer/serializerClass.py index 59f937eb..854f04d6 100644 --- a/api_fhir_r4/multiserializer/serializerClass.py +++ b/api_fhir_r4/multiserializer/serializerClass.py @@ -5,6 +5,15 @@ class MultiSerializerSerializerClass(Serializer): """ Serves as base serializer class for instances using multiserializer mixin. """ + user = None + + def __init__(self, user=None, **kwargs): + if user: + self.user = user + else: + context = kwargs.get('context', None) + if context and hasattr(context, 'user'): + self.user = context.user def update(self, instance, validated_data): raise NotImplementedError("MultiSerializerSerializerClass `update` not supported. Should be" diff --git a/api_fhir_r4/paymentNotice/serializer/create.py b/api_fhir_r4/paymentNotice/serializer/create.py index 0ad2a82e..eb66ba2e 100644 --- a/api_fhir_r4/paymentNotice/serializer/create.py +++ b/api_fhir_r4/paymentNotice/serializer/create.py @@ -13,8 +13,10 @@ def create(cls, validated_data, request): invoice_status = validated_data.pop('invoice_status') payment_invoice = copy.deepcopy(validated_data) - del payment_invoice['_state'] - del payment_invoice['_original_state'] + if '_state' in payment_invoice: + del payment_invoice['_state'] + if '_original_state' in payment_invoice: + del payment_invoice['_original_state'] payment_invoice_service = PaymentInvoiceService(user) result = payment_invoice_service.create_with_detail(payment_invoice, imis_payment_detail) diff --git a/api_fhir_r4/serializers/__init__.py b/api_fhir_r4/serializers/__init__.py index 999e83a7..52ca08c0 100644 --- a/api_fhir_r4/serializers/__init__.py +++ b/api_fhir_r4/serializers/__init__.py @@ -18,9 +18,14 @@ class BaseFHIRSerializer(serializers.Serializer): fhirConverter = BaseFHIRConverter user = None - def __init__(self, *args, **kwargs): + def __init__(self, *args, user=None, **kwargs): self._reference_type = kwargs.pop('reference_type', ReferenceConverterMixin.UUID_REFERENCE_TYPE) - self.user = kwargs.pop('user', None) + if user: + self.user = user + else: + context = kwargs.get('context', None) + if context and hasattr(context, 'user'): + self.user = context.user super().__init__(*args, **kwargs) def to_representation(self, obj): @@ -38,7 +43,9 @@ def to_representation(self, obj): def to_internal_value(self, data): audit_user_id = self.get_audit_user_id() - return self.fhirConverter(user=self.user).to_imis_obj(data, audit_user_id).__dict__ + imis_obj = self.fhirConverter(user=self.user).to_imis_obj(data, audit_user_id) + # Filter out special attributes + return {k: v for k, v in imis_obj.__dict__.items() if not k.startswith('_') and v is not None} def create(self, validated_data): raise NotImplementedError('`create()` must be implemented.') # pragma: no cover @@ -47,16 +54,15 @@ def update(self, instance, validated_data): raise NotImplementedError('`update()` must be implemented.') # pragma: no cover def get_audit_user_id(self): - request = self.context.get("request") - # Taking the audit_user_id from the query doesn't seem wise but there might be a use for it - # audit_user_id = request.query_params.get('auditUserId', None) - audit_user_id = request.user.id_for_audit if request.user else None - if audit_user_id is None: - audit_user_id = GeneralConfiguration.get_default_audit_user_id() + # the audit user is the user + if self.user: + return self.user.audit_user_id or self.user._u.id + audit_user_id = GeneralConfiguration.get_default_audit_user_id() if isinstance(audit_user_id, int): return audit_user_id else: - return self.__get_technical_audit_user(audit_user_id) + raise ValueError("User not available from the request for audit trail") + #return self.__get_technical_audit_user(audit_user_id) @property def reference_type(self): diff --git a/api_fhir_r4/serializers/activityDefinitionSerializer.py b/api_fhir_r4/serializers/activityDefinitionSerializer.py index 617c9bc1..33acdb60 100644 --- a/api_fhir_r4/serializers/activityDefinitionSerializer.py +++ b/api_fhir_r4/serializers/activityDefinitionSerializer.py @@ -19,7 +19,8 @@ def create(self, validated_data): validated_data['uuid'] = uuid.UUID(validated_data['uuid']) copied_data = copy.deepcopy(validated_data) - del copied_data['_state'] + if '_state' in copied_data: + del copied_data['_state'] return Service.objects.create(**copied_data) def update(self, instance, validated_data): diff --git a/api_fhir_r4/serializers/claimAdminPractitionerSerializer.py b/api_fhir_r4/serializers/claimAdminPractitionerSerializer.py index 01e40639..c6584645 100644 --- a/api_fhir_r4/serializers/claimAdminPractitionerSerializer.py +++ b/api_fhir_r4/serializers/claimAdminPractitionerSerializer.py @@ -23,7 +23,8 @@ def create(self, validated_data): if ClaimAdmin.objects.filter(code=code).count() > 0: raise FHIRException('Exists practitioner with following code `{}`'.format(code)) copied_data = copy.deepcopy(validated_data) - del copied_data['_state'] + if '_state' in copied_data: + del copied_data['_state'] return ClaimAdmin.objects.create(**copied_data) def update(self, instance, validated_data): diff --git a/api_fhir_r4/serializers/codeSystemSerializer.py b/api_fhir_r4/serializers/codeSystemSerializer.py index 5e7565b5..4a10c929 100644 --- a/api_fhir_r4/serializers/codeSystemSerializer.py +++ b/api_fhir_r4/serializers/codeSystemSerializer.py @@ -9,10 +9,10 @@ class CodeSystemSerializer(BaseFHIRSerializer): def __init__(self, *args, **kwargs): self.model = {} - + if 'user' in kwargs: + user = kwargs.pop('user') for field in self.codeSystemFields: self.model[field] = kwargs.pop(field, None) - if 'data' in kwargs: self.model['data'] = kwargs.pop('data') elif 'model_name' in kwargs: @@ -22,7 +22,7 @@ def __init__(self, *args, **kwargs): else: self.model['data'] = {} - super().__init__(*args, **kwargs) + super().__init__(*args, user=user, **kwargs) def to_representation(self, obj): return CodeSystemConverter.to_fhir_obj(self.model, self.reference_type).dict() diff --git a/api_fhir_r4/serializers/communicationSerializer.py b/api_fhir_r4/serializers/communicationSerializer.py index 673b5cff..3750a3d4 100644 --- a/api_fhir_r4/serializers/communicationSerializer.py +++ b/api_fhir_r4/serializers/communicationSerializer.py @@ -16,7 +16,8 @@ def create(self, validated_data): if Feedback.objects.filter(claim__id=claim, validity_to__isnull=True).count() > 0: raise FHIRException('Feedback exists for this claim') copied_data = copy.deepcopy(validated_data) - del copied_data['_state'] + if '_state' in copied_data: + del copied_data['_state'] from core import datetime copied_data['feedback_date'] = datetime.datetime.now() obj = Feedback.objects.create(**copied_data) diff --git a/api_fhir_r4/serializers/contractSerializer.py b/api_fhir_r4/serializers/contractSerializer.py index 2328e644..6ff2c4f0 100644 --- a/api_fhir_r4/serializers/contractSerializer.py +++ b/api_fhir_r4/serializers/contractSerializer.py @@ -22,7 +22,8 @@ def create(self, validated_data): raise FHIRException('Contract exists for this patient') copied_data = copy.deepcopy(validated_data) - del copied_data['_state'] + if '_state' in copied_data: + del copied_data['_state'] #TODO should we implement a way to create a resource with a given uuid del copied_data['uuid'] diff --git a/api_fhir_r4/serializers/coverageSerializer.py b/api_fhir_r4/serializers/coverageSerializer.py index 6c35bbc6..9fb31641 100644 --- a/api_fhir_r4/serializers/coverageSerializer.py +++ b/api_fhir_r4/serializers/coverageSerializer.py @@ -14,7 +14,8 @@ def create(self, validated_data): if Policy.objects.filter(family_id=family).count() > 0: raise FHIRException('Exists coverage with the family provided') copied_data = copy.deepcopy(validated_data) - del copied_data['_state'] + if '_state' in copied_data: + del copied_data['_state'] return Policy.objects.create(**copied_data) def update(self, instance, validated_data): diff --git a/api_fhir_r4/serializers/groupSerializer.py b/api_fhir_r4/serializers/groupSerializer.py index fc7e00a6..527be14a 100644 --- a/api_fhir_r4/serializers/groupSerializer.py +++ b/api_fhir_r4/serializers/groupSerializer.py @@ -33,7 +33,8 @@ def create(self, validated_data): # assign members of family (insuree) to the family for mf in members_family: mf = mf.__dict__ - del mf['_state'] + if '_state' in mf: + del mf['_state'] mf['family_id'] = new_family.id InsureeService(user).create_or_update(mf) @@ -43,7 +44,7 @@ def update(self, instance, validated_data): #validated_data = resolve_id_reference(validated_data) # TODO: This doesn't work request = self.context.get("request") - validated_data.pop('_state') + validated_data.pop('_state', None) members_family = validated_data.pop('members_family') user = request.user head_id = validated_data.get('head_insuree_id', None) @@ -64,7 +65,7 @@ def update(self, instance, validated_data): instance = FamilyService(user).create_or_update(validated_data) for mf in members_family: mf = mf.__dict__ - mf.pop('_state') + mf.pop('_state', None) mf['family_id'] = instance.id InsureeService(user).create_or_update(mf) diff --git a/api_fhir_r4/serializers/insurancePlanSerializer.py b/api_fhir_r4/serializers/insurancePlanSerializer.py index d9192974..b7e01ef6 100644 --- a/api_fhir_r4/serializers/insurancePlanSerializer.py +++ b/api_fhir_r4/serializers/insurancePlanSerializer.py @@ -14,7 +14,8 @@ def create(self, validated_data): if Product.objects.filter(code=code).count() > 0: raise FHIRException('Exists product with following code `{}`'.format(code)) copied_data = copy.deepcopy(validated_data) - del copied_data['_state'] + if '_state' in copied_data: + del copied_data['_state'] # TODO services in product hasn't been developed yet. return Product.objects.create(**copied_data) diff --git a/api_fhir_r4/serializers/locationSerializer.py b/api_fhir_r4/serializers/locationSerializer.py index 4a01309a..5d0cc8b3 100644 --- a/api_fhir_r4/serializers/locationSerializer.py +++ b/api_fhir_r4/serializers/locationSerializer.py @@ -11,7 +11,8 @@ class LocationSerializer(BaseFHIRSerializer): def create(self, validated_data): copied_data = copy.deepcopy(validated_data) - del copied_data['_state'] + if '_state' in copied_data: + del copied_data['_state'] return Location.objects.create(**copied_data) def update(self, instance, validated_data): diff --git a/api_fhir_r4/serializers/locationSiteSerializer.py b/api_fhir_r4/serializers/locationSiteSerializer.py index 9e60a623..f7bdd0ee 100644 --- a/api_fhir_r4/serializers/locationSiteSerializer.py +++ b/api_fhir_r4/serializers/locationSiteSerializer.py @@ -11,7 +11,8 @@ class LocationSiteSerializer(BaseFHIRSerializer): def create(self, validated_data): copied_data = copy.deepcopy(validated_data) - del copied_data['_state'] + if '_state' in copied_data: + del copied_data['_state'] return HealthFacility.objects.create(**copied_data) def update(self, instance, validated_data): diff --git a/api_fhir_r4/serializers/medicationSerializer.py b/api_fhir_r4/serializers/medicationSerializer.py index 3e6ea013..4401e9d1 100644 --- a/api_fhir_r4/serializers/medicationSerializer.py +++ b/api_fhir_r4/serializers/medicationSerializer.py @@ -2,40 +2,53 @@ import uuid from medical.models import Item + from api_fhir_r4.converters import MedicationConverter from api_fhir_r4.exceptions import FHIRException from api_fhir_r4.serializers import BaseFHIRSerializer - class MedicationSerializer(BaseFHIRSerializer): fhirConverter = MedicationConverter def create(self, validated_data): - code = validated_data.get('code') - if Item.objects.filter(code=code).count() > 0: - raise FHIRException('Exists medical item with following code `{}`'.format(code)) - - if 'uuid' in validated_data.keys() and validated_data.get('uuid') is None: - # In serializers using graphql services can't provide uuid. If uuid is provided then - # resource is updated and not created. This check ensure UUID was provided. - validated_data['uuid'] = uuid.uuid4() - elif 'uuid' in validated_data and isinstance(validated_data['uuid'], str): - validated_data['uuid'] = uuid.UUID(validated_data['uuid']) - copied_data = copy.deepcopy(validated_data) - del copied_data['_state'] - return Item.objects.create(**copied_data) + imis_medication = Item(**validated_data) + imis_medication.audit_user_id = self.get_audit_user_id() + filters = {} + if imis_medication.id: + filters['id'] = imis_medication.id + if imis_medication.uuid: + filters['uuid'] = imis_medication.uuid + if imis_medication.code and not filters: + filters['code'] = imis_medication.code + filters['validity_to__isnull'] = True + + instance = Item.objects.filter(**filters).first() + if instance: + raise ValueError(f"cannot create an already existing object, filters: {filters}") + imis_medication.audit_user_id = self.get_audit_user_id() + imis_medication.save() + return imis_medication + def update(self, instance, validated_data): - if 'uuid' in validated_data and isinstance(validated_data['uuid'], str): - validated_data['uuid'] = uuid.UUID(validated_data['uuid']) - instance.code = validated_data.get('code', instance.code) - instance.name = validated_data.get('name', instance.name) - instance.package = validated_data.get('package', instance.package) - instance.price = validated_data.get('price', instance.price) - instance.type = validated_data.get('type', instance.type) - instance.care_type = validated_data.get('care_type', instance.care_type) - instance.frequency = validated_data.get('frequency', instance.frequency) - instance.patient_category = validated_data.get('patient_category', instance.patient_category) + imis_medication = Item(**validated_data) + imis_medication.audit_user_id = self.get_audit_user_id() + filters = {} + if imis_medication.id: + filters['id'] = imis_medication.id + if imis_medication.uuid: + filters['uuid'] = imis_medication.uuid + if imis_medication.code and not filters: + filters['code'] = imis_medication.code + filters['validity_to__isnull'] = True + + instance = Item.objects.filter(**filters).first() + if not instance: + raise ValueError(f"cannot update a not found object, filters: {filters}") instance.audit_user_id = self.get_audit_user_id() - instance.save() - return instance + instance.save_history() + imis_medication.id = instance.id + imis_medication.uuid = instance.uuid + imis_medication.code = instance.code + imis_medication.save() + return imis_medication \ No newline at end of file diff --git a/api_fhir_r4/serializers/patientSerializer.py b/api_fhir_r4/serializers/patientSerializer.py index 811e4240..0d0dbc4d 100644 --- a/api_fhir_r4/serializers/patientSerializer.py +++ b/api_fhir_r4/serializers/patientSerializer.py @@ -28,7 +28,7 @@ def create(self, validated_data): def update(self, instance, validated_data): #validated_data = resolve_id_reference(Insuree, validated_data) request = self.context.get("request") - validated_data.pop('_state') + validated_data.pop('_state', None) user = request.user chf_id = validated_data.get('chf_id', None) if Insuree.objects.filter(chf_id=chf_id).count() == 0: diff --git a/api_fhir_r4/serializers/policyHolderOrganisationSerializer.py b/api_fhir_r4/serializers/policyHolderOrganisationSerializer.py index 03029224..b001429c 100644 --- a/api_fhir_r4/serializers/policyHolderOrganisationSerializer.py +++ b/api_fhir_r4/serializers/policyHolderOrganisationSerializer.py @@ -12,7 +12,7 @@ def create(self, validated_data): if PolicyHolder.objects.filter(code=validated_data['code']).count() > 0: raise FHIRException('Exists Organization with following code `{}`'.format(validated_data['code'])) validated_data.pop('_original_state') - validated_data.pop('_state') + validated_data.pop('_state', None) request = self.context.get('request', None) if request: validated_data['user_created_id']=request.user.id diff --git a/api_fhir_r4/subscriptions/subscriptionSerializer.py b/api_fhir_r4/subscriptions/subscriptionSerializer.py index b15e8fcd..bc53ca67 100644 --- a/api_fhir_r4/subscriptions/subscriptionSerializer.py +++ b/api_fhir_r4/subscriptions/subscriptionSerializer.py @@ -11,9 +11,9 @@ FHIRApiHealthServicePermissions from api_fhir_r4.serializers import BaseFHIRSerializer from api_fhir_r4.services import SubscriptionService +from api_fhir_r4.mixins import RetrieveModelMixin - -class SubscriptionSerializer(BaseFHIRSerializer): +class SubscriptionSerializer(BaseFHIRSerializer, RetrieveModelMixin): fhirConverter = SubscriptionConverter _error_while_saving = 'Error while saving a subscription: %(msg)s' @@ -24,23 +24,29 @@ class SubscriptionSerializer(BaseFHIRSerializer): } def create(self, validated_data): - user = self.context['request'].user + user = self.user or self.context['request'].user self.check_resource_rights(user, validated_data) service = SubscriptionService(user) copied_data = deepcopy(validated_data) - del copied_data['_state'], copied_data['_original_state'] + if '_state' in copied_data: + del copied_data['_state'] + if '_original_state' in copied_data: + del copied_data['_original_state'] result = service.create(copied_data) return self.get_result_object(result) def update(self, instance, validated_data): - user = self.context['request'].user + user = self.user or self.context['request'].user self.check_instance_id(instance, validated_data) self.check_object_owner(user, instance) self.check_resource_rights(user, validated_data) service = SubscriptionService(user) copied_data = {key: value for key, value in deepcopy(validated_data).items() if value is not None} copied_data['id'] = instance.id - del copied_data['_state'], copied_data['_original_state'] + if '_state' in copied_data: + del copied_data['_state'] + if '_original_state' in copied_data: + del copied_data['_original_state'] result = service.update(copied_data) return self.get_result_object(result) diff --git a/api_fhir_r4/tests/mixin/fhirApiUpdateTestMixin.py b/api_fhir_r4/tests/mixin/fhirApiUpdateTestMixin.py index a746a52b..502f854b 100644 --- a/api_fhir_r4/tests/mixin/fhirApiUpdateTestMixin.py +++ b/api_fhir_r4/tests/mixin/fhirApiUpdateTestMixin.py @@ -1,5 +1,5 @@ import copy - +import json from rest_framework import status @@ -33,7 +33,8 @@ def test_put_should_update_correctly(self): # create self.create_dependencies() response = self.client.post(self.base_url, data=self._test_request_data, format='json') - self.assertEqual(response.status_code, status.HTTP_201_CREATED) + content = json.loads(response.content) + self.assertEqual(response.status_code, status.HTTP_201_CREATED, f"{response.content}") resource_id = self.get_id_for_created_resource(response) # update updated_data = copy.deepcopy(self._test_request_data) diff --git a/api_fhir_r4/tests/mixin/genericFhirAPITestMixin.py b/api_fhir_r4/tests/mixin/genericFhirAPITestMixin.py index 33aca85b..511ff4a8 100644 --- a/api_fhir_r4/tests/mixin/genericFhirAPITestMixin.py +++ b/api_fhir_r4/tests/mixin/genericFhirAPITestMixin.py @@ -13,9 +13,9 @@ from fhir.resources.R4B.bundle import Bundle from api_fhir_r4.utils import DbManagerUtils - +from core.test_helpers import create_test_interactive_user class GenericFhirAPITestMixin(object): - + user = None @property def base_url(self): return None @@ -28,19 +28,20 @@ def _test_json_path(self): def _test_json_path_credentials(self): return None - _TEST_SUPERUSER_NAME = 'admin' + _TEST_SUPERUSER_NAME = 'admin_api' _TEST_SUPERUSER_PASS = 'adminadmin'#'Admin123' _test_request_data = None _test_json_path_credentials = None def setUp(self): + self.user = create_test_interactive_user(username=self._TEST_SUPERUSER_NAME) dir_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) if self._test_json_path and self._test_request_data is None: json_representation = open(dir_path + self._test_json_path).read() self._test_request_data = json.loads(json_representation) if self._test_json_path_credentials and self._test_request_data_credentials is None: json_representation = open(dir_path + self._test_json_path_credentials).read() - self._test_request_data_credentials = json.loads(json_representation) + self._test_request_data_credentials = json.loads(json_representation) def apply_replace_map(self , payload): return payload @@ -70,13 +71,8 @@ def get_response_details(self, response_json): def login(self): user = DbManagerUtils.get_object_or_none(User, username=self._TEST_SUPERUSER_NAME) - if user is None: - user = self.__create_superuser() self.client.force_authenticate(user=user) - def __create_superuser(self): - User.objects.create_superuser(username=self._TEST_SUPERUSER_NAME, password=self._TEST_SUPERUSER_PASS) - return DbManagerUtils.get_object_or_none(User, username=self._TEST_SUPERUSER_NAME) def get_bundle_from_json_response(self, response): response_json = response.json() diff --git a/api_fhir_r4/tests/test_api_authorization.py b/api_fhir_r4/tests/test_api_authorization.py index 47efb4bd..6de795eb 100644 --- a/api_fhir_r4/tests/test_api_authorization.py +++ b/api_fhir_r4/tests/test_api_authorization.py @@ -34,7 +34,8 @@ def test_post_should_authorize_correctly(self): 'HTTP_AUTHORIZATION': f"Bearer {token}" } response = self.client.get(self.url_to_test_authorization, format='json', **headers) - self.assertEqual(response.status_code, status.HTTP_200_OK) + content = json.loads(response.content) + self.assertEqual(response.status_code, status.HTTP_200_OK, f"{response.content}") def test_post_should_raise_no_auth_header(self): response = self.client.get(self.url_to_test_authorization, format='json') diff --git a/api_fhir_r4/views/fhir/activity_definition.py b/api_fhir_r4/views/fhir/activity_definition.py index 4020185c..9a044a27 100644 --- a/api_fhir_r4/views/fhir/activity_definition.py +++ b/api_fhir_r4/views/fhir/activity_definition.py @@ -1,7 +1,6 @@ -from rest_framework import mixins from rest_framework.viewsets import GenericViewSet -from api_fhir_r4.mixins import MultiIdentifierRetrieverMixin +from api_fhir_r4.mixins import MultiIdentifierRetrieverMixin, ListModelMixin from api_fhir_r4.model_retrievers import UUIDIdentifierModelRetriever, CodeIdentifierModelRetriever from api_fhir_r4.permissions import FHIRApiActivityDefinitionPermissions from api_fhir_r4.serializers import ActivityDefinitionSerializer @@ -10,7 +9,7 @@ from medical.models import Service -class ActivityDefinitionViewSet(BaseFHIRView, MultiIdentifierRetrieverMixin, mixins.ListModelMixin, GenericViewSet): +class ActivityDefinitionViewSet(BaseFHIRView, MultiIdentifierRetrieverMixin, ListModelMixin, GenericViewSet): retrievers = [UUIDIdentifierModelRetriever, CodeIdentifierModelRetriever] serializer_class = ActivityDefinitionSerializer permission_classes = (FHIRApiActivityDefinitionPermissions,) diff --git a/api_fhir_r4/views/fhir/base/__init__.py b/api_fhir_r4/views/fhir/base/__init__.py index 90a677ff..7c387c32 100644 --- a/api_fhir_r4/views/fhir/base/__init__.py +++ b/api_fhir_r4/views/fhir/base/__init__.py @@ -4,9 +4,22 @@ from api_fhir_r4.paginations import FhirBundleResultsSetPagination from api_fhir_r4.permissions import FHIRApiPermissions from api_fhir_r4.views import CsrfExemptSessionAuthentication +from api_fhir_r4.mixins import ( + UpdateModelMixin, + ListModelMixin, + CreateModelMixin, + DestroyModelMixin +) -class BaseFHIRView(APIView): +class BaseFHIRView( + CreateModelMixin, + UpdateModelMixin, + DestroyModelMixin, + APIView, + +): + user = None pagination_class = FhirBundleResultsSetPagination permission_classes = (FHIRApiPermissions,) authentication_classes = [CsrfExemptSessionAuthentication] + APIView.settings.DEFAULT_AUTHENTICATION_CLASSES diff --git a/api_fhir_r4/views/fhir/claim.py b/api_fhir_r4/views/fhir/claim.py index 8f867c45..ea9977f2 100644 --- a/api_fhir_r4/views/fhir/claim.py +++ b/api_fhir_r4/views/fhir/claim.py @@ -1,12 +1,11 @@ import datetime from django.db.models import Prefetch -from rest_framework import mixins from rest_framework.response import Response from rest_framework.serializers import ValidationError from rest_framework.viewsets import GenericViewSet -from api_fhir_r4.mixins import MultiIdentifierRetrieverMixin +from api_fhir_r4.mixins import MultiIdentifierRetrieverMixin, ListModelMixin from api_fhir_r4.model_retrievers import UUIDIdentifierModelRetriever, CodeIdentifierModelRetriever from api_fhir_r4.permissions import FHIRApiClaimPermissions from api_fhir_r4.serializers import ClaimSerializer @@ -16,8 +15,7 @@ from insuree.models import Insuree, InsureePolicy -class ClaimViewSet(BaseFHIRView, MultiIdentifierRetrieverMixin, mixins.ListModelMixin, - mixins.CreateModelMixin, GenericViewSet): +class ClaimViewSet(BaseFHIRView, MultiIdentifierRetrieverMixin, ListModelMixin, GenericViewSet): retrievers = [UUIDIdentifierModelRetriever, CodeIdentifierModelRetriever] serializer_class = ClaimSerializer permission_classes = (FHIRApiClaimPermissions,) @@ -50,7 +48,7 @@ def list(self, request, *args, **kwargs): def retrieve(self, request, *args, **kwargs): contained = bool(request.GET.get("contained")) ref_type, instance = self._get_object_with_first_valid_retriever(kwargs['identifier']) - serializer = self.get_serializer(instance, context={'contained': contained}, reference_type=ref_type) + serializer = self.get_serializer(instance, context={'contained': contained}, reference_type=ref_type, user=request.user) return Response(serializer.data) def get_queryset(self): diff --git a/api_fhir_r4/views/fhir/claim_response.py b/api_fhir_r4/views/fhir/claim_response.py index c84416f4..5342b04c 100644 --- a/api_fhir_r4/views/fhir/claim_response.py +++ b/api_fhir_r4/views/fhir/claim_response.py @@ -1,7 +1,6 @@ -from rest_framework import mixins from rest_framework.viewsets import GenericViewSet -from api_fhir_r4.mixins import MultiIdentifierRetrieverMixin +from api_fhir_r4.mixins import MultiIdentifierRetrieverMixin, ListModelMixin from api_fhir_r4.model_retrievers import UUIDIdentifierModelRetriever, CodeIdentifierModelRetriever from api_fhir_r4.permissions import FHIRApiClaimPermissions from api_fhir_r4.serializers import ClaimResponseSerializer @@ -10,8 +9,12 @@ from claim.models import Claim -class ClaimResponseViewSet(BaseFHIRView, MultiIdentifierRetrieverMixin, mixins.ListModelMixin, GenericViewSet, - mixins.UpdateModelMixin): +class ClaimResponseViewSet( + BaseFHIRView, + ListModelMixin, + MultiIdentifierRetrieverMixin, + GenericViewSet +): retrievers = [UUIDIdentifierModelRetriever, CodeIdentifierModelRetriever] serializer_class = ClaimResponseSerializer permission_classes = (FHIRApiClaimPermissions,) diff --git a/api_fhir_r4/views/fhir/code_systems/diagnosis.py b/api_fhir_r4/views/fhir/code_systems/diagnosis.py index f08476b0..2634fed5 100644 --- a/api_fhir_r4/views/fhir/code_systems/diagnosis.py +++ b/api_fhir_r4/views/fhir/code_systems/diagnosis.py @@ -21,6 +21,7 @@ def list(self, request, *args, **kwargs): if not request.user.has_perms(FHIRApiClaimPermissions.permissions_get): raise PermissionDenied("unauthorized") serializer = CodeSystemSerializer( + user=request.user, instance=None, **{ "model_name": 'Diagnosis', diff --git a/api_fhir_r4/views/fhir/code_systems/group_confirmation_type.py b/api_fhir_r4/views/fhir/code_systems/group_confirmation_type.py index 33fc9f04..ff1fdabb 100644 --- a/api_fhir_r4/views/fhir/code_systems/group_confirmation_type.py +++ b/api_fhir_r4/views/fhir/code_systems/group_confirmation_type.py @@ -21,6 +21,7 @@ def list(self, request): if not request.user.has_perms(FHIRApiGroupPermissions.permissions_get): raise PermissionDenied("unauthorized") serializer = CodeSystemSerializer( + user=request.user, instance=None, **{ "model_name": 'ConfirmationType', diff --git a/api_fhir_r4/views/fhir/code_systems/group_type.py b/api_fhir_r4/views/fhir/code_systems/group_type.py index 408a1914..e60e78d6 100644 --- a/api_fhir_r4/views/fhir/code_systems/group_type.py +++ b/api_fhir_r4/views/fhir/code_systems/group_type.py @@ -21,6 +21,7 @@ def list(self, request): if not request.user.has_perms(FHIRApiGroupPermissions.permissions_get): raise PermissionDenied("unauthorized") serializer = CodeSystemSerializer( + user=request.user, instance=None, **{ "model_name": 'FamilyType', diff --git a/api_fhir_r4/views/fhir/code_systems/organization_hf_legal_form.py b/api_fhir_r4/views/fhir/code_systems/organization_hf_legal_form.py index b20dc37a..6cd2e42c 100644 --- a/api_fhir_r4/views/fhir/code_systems/organization_hf_legal_form.py +++ b/api_fhir_r4/views/fhir/code_systems/organization_hf_legal_form.py @@ -16,6 +16,7 @@ class CodeSystemOrganizationHFLegalFormViewSet(viewsets.ViewSet): def list(self, request): # we don't use typical instance, we only indicate the model and the field to be mapped into CodeSystem serializer = CodeSystemSerializer( + user=request.user, instance=None, **{ 'model_name': 'HealthFacilityLegalForm', diff --git a/api_fhir_r4/views/fhir/code_systems/organization_hf_level.py b/api_fhir_r4/views/fhir/code_systems/organization_hf_level.py index 08639d93..ead9bc27 100644 --- a/api_fhir_r4/views/fhir/code_systems/organization_hf_level.py +++ b/api_fhir_r4/views/fhir/code_systems/organization_hf_level.py @@ -17,6 +17,7 @@ class CodeSystemOrganizationHFLevelViewSet(viewsets.ViewSet): def list(self, request): # we don't use typical instance, we only indicate the model and the field to be mapped into CodeSystem serializer = CodeSystemSerializer( + user=request.user, instance=None, **{ 'data': HealthFacilityLevel(request.user).get_all()['data'], diff --git a/api_fhir_r4/views/fhir/code_systems/organization_ph_activity.py b/api_fhir_r4/views/fhir/code_systems/organization_ph_activity.py index c72ef4c0..5ffe542c 100644 --- a/api_fhir_r4/views/fhir/code_systems/organization_ph_activity.py +++ b/api_fhir_r4/views/fhir/code_systems/organization_ph_activity.py @@ -17,6 +17,7 @@ class CodeSystemOrganizationPHActivityViewSet(viewsets.ViewSet): def list(self, request): # we don't use typical instance, we only indicate the model and the field to be mapped into CodeSystem serializer = CodeSystemSerializer( + user=request.user, instance=None, **{ 'data': PolicyHolderActivity(request.user).get_all()['data'], diff --git a/api_fhir_r4/views/fhir/code_systems/organization_ph_legal_form.py b/api_fhir_r4/views/fhir/code_systems/organization_ph_legal_form.py index 1cf0e88d..bb848ba7 100644 --- a/api_fhir_r4/views/fhir/code_systems/organization_ph_legal_form.py +++ b/api_fhir_r4/views/fhir/code_systems/organization_ph_legal_form.py @@ -17,6 +17,7 @@ class CodeSystemOrganizationPHLegalFormViewSet(viewsets.ViewSet): def list(self, request): # we don't use typical instance, we only indicate the model and the field to be mapped into CodeSystem serializer = CodeSystemSerializer( + user=request.user, instance=None, **{ 'data': PolicyHolderLegalForm(request.user).get_all()['data'], diff --git a/api_fhir_r4/views/fhir/code_systems/patient_education_level.py b/api_fhir_r4/views/fhir/code_systems/patient_education_level.py index b3a4e497..46e522eb 100644 --- a/api_fhir_r4/views/fhir/code_systems/patient_education_level.py +++ b/api_fhir_r4/views/fhir/code_systems/patient_education_level.py @@ -21,6 +21,7 @@ def list(self, request): if not request.user.has_perms(FHIRApiInsureePermissions.permissions_get): raise PermissionDenied("unauthorized") serializer = CodeSystemSerializer( + user=request.user, instance=None, **{ "model_name": 'Education', diff --git a/api_fhir_r4/views/fhir/code_systems/patient_identification_type.py b/api_fhir_r4/views/fhir/code_systems/patient_identification_type.py index e7f28544..f834b6a7 100644 --- a/api_fhir_r4/views/fhir/code_systems/patient_identification_type.py +++ b/api_fhir_r4/views/fhir/code_systems/patient_identification_type.py @@ -21,6 +21,7 @@ def list(self, request): if not request.user.has_perms(FHIRApiInsureePermissions.permissions_get): raise PermissionDenied("unauthorized") serializer = CodeSystemSerializer( + user=request.user, instance=None, **{ "model_name": 'IdentificationType', diff --git a/api_fhir_r4/views/fhir/code_systems/patient_profession.py b/api_fhir_r4/views/fhir/code_systems/patient_profession.py index 923a2ad3..dee4da5b 100644 --- a/api_fhir_r4/views/fhir/code_systems/patient_profession.py +++ b/api_fhir_r4/views/fhir/code_systems/patient_profession.py @@ -21,6 +21,7 @@ def list(self, request): if not request.user.has_perms(FHIRApiInsureePermissions.permissions_get): raise PermissionDenied("unauthorized") serializer = CodeSystemSerializer( + user=request.user, instance=None, **{ "model_name": 'Profession', diff --git a/api_fhir_r4/views/fhir/code_systems/patient_relationship.py b/api_fhir_r4/views/fhir/code_systems/patient_relationship.py index bc3117d8..1d6b4388 100644 --- a/api_fhir_r4/views/fhir/code_systems/patient_relationship.py +++ b/api_fhir_r4/views/fhir/code_systems/patient_relationship.py @@ -21,6 +21,7 @@ def list(self, request): if not request.user.has_perms(FHIRApiInsureePermissions.permissions_get): raise PermissionDenied("unauthorized") serializer = CodeSystemSerializer( + user=request.user, instance=None, **{ "model_name": 'Relation', diff --git a/api_fhir_r4/views/fhir/communication.py b/api_fhir_r4/views/fhir/communication.py index 8b99b922..30f410be 100644 --- a/api_fhir_r4/views/fhir/communication.py +++ b/api_fhir_r4/views/fhir/communication.py @@ -11,7 +11,12 @@ import logging logger = logging.getLogger(__name__) -class CommunicationViewSet(BaseFHIRView, MultiIdentifierRetrieverMixin, viewsets.ModelViewSet): + +class CommunicationViewSet( + BaseFHIRView, + MultiIdentifierRetrieverMixin, + viewsets.ModelViewSet +): retrievers = [UUIDIdentifierModelRetriever, CodeIdentifierModelRetriever] serializer_class = CommunicationSerializer permission_classes = (FHIRApiCommunicationRequestPermissions,) diff --git a/api_fhir_r4/views/fhir/communication_request.py b/api_fhir_r4/views/fhir/communication_request.py index c3d1c56b..6451ecb3 100644 --- a/api_fhir_r4/views/fhir/communication_request.py +++ b/api_fhir_r4/views/fhir/communication_request.py @@ -1,7 +1,6 @@ -from rest_framework import mixins from rest_framework.viewsets import GenericViewSet -from api_fhir_r4.mixins import MultiIdentifierRetrieverMixin +from api_fhir_r4.mixins import MultiIdentifierRetrieverMixin, ListModelMixin from api_fhir_r4.model_retrievers import UUIDIdentifierModelRetriever from api_fhir_r4.permissions import FHIRApiCommunicationRequestPermissions from api_fhir_r4.serializers import CommunicationRequestSerializer @@ -10,7 +9,12 @@ from claim.models import Claim -class CommunicationRequestViewSet(BaseFHIRView, MultiIdentifierRetrieverMixin, mixins.ListModelMixin, GenericViewSet): +class CommunicationRequestViewSet( + BaseFHIRView, + MultiIdentifierRetrieverMixin, + ListModelMixin, + GenericViewSet +): retrievers = [UUIDIdentifierModelRetriever] serializer_class = CommunicationRequestSerializer permission_classes = (FHIRApiCommunicationRequestPermissions,) diff --git a/api_fhir_r4/views/fhir/contract.py b/api_fhir_r4/views/fhir/contract.py index 5f7c15c3..cf834011 100644 --- a/api_fhir_r4/views/fhir/contract.py +++ b/api_fhir_r4/views/fhir/contract.py @@ -1,19 +1,22 @@ import datetime from django.db.models import Prefetch -from rest_framework import mixins from rest_framework.viewsets import GenericViewSet - from api_fhir_r4.permissions import FHIRApiCoverageRequestPermissions from api_fhir_r4.serializers import ContractSerializer from api_fhir_r4.views.fhir.base import BaseFHIRView +from api_fhir_r4.mixins import RetrieveModelMixin, ListModelMixin from api_fhir_r4.views.filters import ValidityFromRequestParameterFilter from insuree.models import InsureePolicy from policy.models import Policy -class ContractViewSet(BaseFHIRView, mixins.RetrieveModelMixin, mixins.ListModelMixin, mixins.CreateModelMixin, - GenericViewSet): +class ContractViewSet( + BaseFHIRView, + RetrieveModelMixin, + ListModelMixin, + GenericViewSet +): lookup_field = 'uuid' serializer_class = ContractSerializer permission_classes = (FHIRApiCoverageRequestPermissions,) diff --git a/api_fhir_r4/views/fhir/coverage_eligibility_request.py b/api_fhir_r4/views/fhir/coverage_eligibility_request.py index d3d6e435..b64aba8c 100644 --- a/api_fhir_r4/views/fhir/coverage_eligibility_request.py +++ b/api_fhir_r4/views/fhir/coverage_eligibility_request.py @@ -1,4 +1,3 @@ -from rest_framework import mixins from rest_framework.viewsets import GenericViewSet from api_fhir_r4.permissions import FHIRApiCoverageEligibilityRequestPermissions @@ -8,7 +7,7 @@ from insuree.models import Insuree -class CoverageEligibilityRequestViewSet(BaseFHIRView, mixins.CreateModelMixin, GenericViewSet): +class CoverageEligibilityRequestViewSet(BaseFHIRView, GenericViewSet): queryset = Insuree.filter_queryset() serializer_class = CoverageEligibilityRequestSerializer permission_classes = (FHIRApiCoverageEligibilityRequestPermissions,) diff --git a/api_fhir_r4/views/fhir/coverage_request.py b/api_fhir_r4/views/fhir/coverage_request.py index 1cd6deb1..4e080b91 100644 --- a/api_fhir_r4/views/fhir/coverage_request.py +++ b/api_fhir_r4/views/fhir/coverage_request.py @@ -1,8 +1,7 @@ import datetime - -from rest_framework import mixins + from rest_framework.viewsets import GenericViewSet - +from api_fhir_r4.mixins import ListModelMixin, RetrieveModelMixin from api_fhir_r4.permissions import FHIRApiCoverageRequestPermissions from api_fhir_r4.serializers.coverageSerializer import CoverageSerializer from api_fhir_r4.views.fhir.base import BaseFHIRView @@ -10,8 +9,7 @@ from policy.models import Policy -class CoverageRequestQuerySet(BaseFHIRView, mixins.RetrieveModelMixin, mixins.ListModelMixin, mixins.UpdateModelMixin, - mixins.CreateModelMixin, GenericViewSet): +class CoverageRequestQuerySet(BaseFHIRView, RetrieveModelMixin, ListModelMixin, GenericViewSet): lookup_field = 'uuid' serializer_class = CoverageSerializer permission_classes = (FHIRApiCoverageRequestPermissions,) diff --git a/api_fhir_r4/views/fhir/invoice.py b/api_fhir_r4/views/fhir/invoice.py index 9c6369ac..1ac58d37 100644 --- a/api_fhir_r4/views/fhir/invoice.py +++ b/api_fhir_r4/views/fhir/invoice.py @@ -1,4 +1,5 @@ from rest_framework.request import Request +from django.utils.functional import cached_property from api_fhir_r4.mapping.invoiceMapping import InvoiceTypeMapping, BillTypeMapping from api_fhir_r4.mixins import ( @@ -31,7 +32,7 @@ class InvoiceViewSet(BaseMultiserializerFHIRView, retrievers = [UUIDIdentifierModelRetriever, DatabaseIdentifierModelRetriever, CodeIdentifierModelRetriever] lookup_field = 'identifier' - @property + @cached_property def serializers(self): return { InvoiceSerializer: diff --git a/api_fhir_r4/views/fhir/organisation.py b/api_fhir_r4/views/fhir/organisation.py index 0d47c734..fd258853 100644 --- a/api_fhir_r4/views/fhir/organisation.py +++ b/api_fhir_r4/views/fhir/organisation.py @@ -133,13 +133,18 @@ def __dispatch_page_data(self, page): def retrieve(self, request, *args, **kwargs): self._validate_retrieve_model_request() retrieved = [] + errors = [] for serializer, (qs, _, _) in self.get_eligible_serializers_iterator(): if qs.model is not ModuleConfiguration: - ref_type, instance = self._get_object_with_first_valid_retriever(qs, kwargs['identifier']) - if instance: - serializer = serializer(instance, reference_type=ref_type, user=request.user) - if serializer.data: - retrieved.append(serializer.data) + try: + ref_type, instance = self._get_object_with_first_valid_retriever(qs, kwargs['identifier']) + if instance: + serializer = serializer(instance, reference_type=ref_type, user=request.user) + if serializer.data: + retrieved.append(serializer.data) + except Exception as e: + # we will try with another retriever + errors.append(str(e)) else: if qs.count() > 0: data = self._get_insurance_organisation(kwargs.get('identifier', None)) @@ -150,8 +155,11 @@ def retrieve(self, request, *args, **kwargs): if len(retrieved) > 1: raise ValueError("Ambiguous retrieve result, object found for multiple serializers.") - if len(retrieved) == 0: - raise Http404(f"Resource for identifier {kwargs['identifier']} not found") + elif len(retrieved) == 0: + if len(errors) > 0: + raise Http404(f"Resource for identifier {kwargs['identifier']} cannot be reloved:{','.join(errors)}") + else: + raise Http404(f"Resource for identifier {kwargs['identifier']} not found") return Response(retrieved[0]) diff --git a/api_fhir_r4/views/fhir/payment_notice.py b/api_fhir_r4/views/fhir/payment_notice.py index fc875954..49800fd6 100644 --- a/api_fhir_r4/views/fhir/payment_notice.py +++ b/api_fhir_r4/views/fhir/payment_notice.py @@ -15,8 +15,12 @@ from invoice.models import PaymentInvoice -class PaymentNoticeViewSet(BaseFHIRView, MultiIdentifierRetrieverMixin, - MultiIdentifierUpdateMixin, viewsets.ModelViewSet): +class PaymentNoticeViewSet( + BaseFHIRView, + MultiIdentifierRetrieverMixin, + MultiIdentifierUpdateMixin, + viewsets.ModelViewSet +): retrievers = [UUIDIdentifierModelRetriever, GroupIdentifierModelRetriever] serializer_class = PaymentNoticeSerializer permission_classes = (FHIRApiPaymentPermissions,) diff --git a/api_fhir_r4/views/fhir/subscription.py b/api_fhir_r4/views/fhir/subscription.py index d48430d5..27e474e6 100644 --- a/api_fhir_r4/views/fhir/subscription.py +++ b/api_fhir_r4/views/fhir/subscription.py @@ -10,7 +10,7 @@ from api_fhir_r4.subscriptions.subscriptionSerializer import SubscriptionSerializerSchema from api_fhir_r4.views.fhir.base import BaseFHIRView from api_fhir_r4.views.filters import DateUpdatedRequestParameterFilter - +from api_fhir_r4.mixins import ListModelMixin, RetrieveModelMixin @extend_schema_view( list=extend_schema(responses={(200, 'application/json'): SubscriptionSerializerSchema()}), @@ -28,7 +28,7 @@ ), destroy=extend_schema(responses={204: None}) ) -class SubscriptionViewSet(BaseFHIRView, ModelViewSet): +class SubscriptionViewSet(BaseFHIRView, ListModelMixin, RetrieveModelMixin, ModelViewSet): _error_while_deleting = 'Error while deleting a subscription: %(msg)s' serializer_class = SubscriptionSerializer http_method_names = ('get', 'post', 'put', 'delete')