From 756822d16c0a036fe5e54a55b56be84b43d06602 Mon Sep 17 00:00:00 2001 From: Sushil Tiwari Date: Tue, 10 Dec 2024 15:06:18 +0545 Subject: [PATCH] LocalUnit: Create, Update, Revert, Latest changes Apis (#2336) * Add Create,Update,Validate Apis logics * Add changes in apis and add new migration file * Add local units enums to global enums * Add test cases for local units apis * Add latest changes api for local units - validate the location - Revert API - add test cases * Update logics on latest-change-request api --- local_units/enums.py | 5 + local_units/filterset.py | 1 + ...localunitchangerequest_options_and_more.py | 26 +++ local_units/models.py | 11 +- local_units/serializers.py | 30 +++ local_units/test_views.py | 217 +++++++++++++++--- local_units/utils.py | 13 ++ local_units/views.py | 149 +++++++++++- main/enums.py | 2 + 9 files changed, 417 insertions(+), 37 deletions(-) create mode 100644 local_units/enums.py create mode 100644 local_units/migrations/0020_alter_localunitchangerequest_options_and_more.py create mode 100644 local_units/utils.py diff --git a/local_units/enums.py b/local_units/enums.py new file mode 100644 index 000000000..38dd0f83e --- /dev/null +++ b/local_units/enums.py @@ -0,0 +1,5 @@ +from . import models + +enum_register = { + "deprecate_reason": models.LocalUnit.DeprecateReason, +} diff --git a/local_units/filterset.py b/local_units/filterset.py index 3cf1983f5..39ebcf12d 100644 --- a/local_units/filterset.py +++ b/local_units/filterset.py @@ -13,6 +13,7 @@ class Meta: "type__code", "draft", "validated", + "is_locked", ) diff --git a/local_units/migrations/0020_alter_localunitchangerequest_options_and_more.py b/local_units/migrations/0020_alter_localunitchangerequest_options_and_more.py new file mode 100644 index 000000000..f1dd09ce4 --- /dev/null +++ b/local_units/migrations/0020_alter_localunitchangerequest_options_and_more.py @@ -0,0 +1,26 @@ +# Generated by Django 4.2.16 on 2024-12-10 09:09 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("local_units", "0019_alter_localunit_is_deprecated_alter_localunit_status_and_more"), + ] + + operations = [ + migrations.AlterModelOptions( + name="localunitchangerequest", + options={"ordering": ("id",)}, + ), + migrations.RemoveField( + model_name="localunit", + name="status", + ), + migrations.AddField( + model_name="localunit", + name="is_locked", + field=models.BooleanField(default=False, verbose_name="Is locked?"), + ), + ] diff --git a/local_units/models.py b/local_units/models.py index cce3745dd..99ff42f35 100644 --- a/local_units/models.py +++ b/local_units/models.py @@ -277,9 +277,6 @@ def __str__(self): @reversion.register(follow=("health",)) class LocalUnit(models.Model): - class Status(models.IntegerChoices): - VERIFIED = 1, _("Verified") - UNVERIFIED = 2, _("Unverified") class DeprecateReason(models.IntegerChoices): NON_EXISTENT = 1, _("Non-existent local unit") @@ -350,7 +347,7 @@ class DeprecateReason(models.IntegerChoices): email = models.EmailField(max_length=255, blank=True, null=True, verbose_name=_("Email")) link = models.URLField(max_length=255, blank=True, null=True, verbose_name=_("Social link")) location = models.PointField(srid=4326, help_text="Local Unit Location") - status = models.IntegerField(choices=Status.choices, verbose_name=_("status"), default=Status.UNVERIFIED) + is_locked = models.BooleanField(default=False, verbose_name=_("Is locked?")) is_deprecated = models.BooleanField(default=False, verbose_name=_("Is deprecated?")) deprecated_reason = models.IntegerField( choices=DeprecateReason.choices, verbose_name=_("deprecated reason"), blank=True, null=True @@ -407,8 +404,12 @@ class Validator(models.IntegerChoices): rejected_data = models.JSONField(verbose_name=_("Rejected data"), default=dict) rejected_reason = models.TextField(verbose_name=_("Rejected reason"), blank=True, null=True) + class Meta: + ordering = ("id",) + def __str__(self): - branch_name = self.local_branch_name or self.english_branch_name + # NOTE: N+1, make sure to use select_related + branch_name = self.local_unit.local_branch_name or self.local_unit.english_branch_name return f"{branch_name}-Change Request-{self.id}" diff --git a/local_units/serializers.py b/local_units/serializers.py index cef37fc86..1629e7d4c 100644 --- a/local_units/serializers.py +++ b/local_units/serializers.py @@ -22,6 +22,7 @@ HealthData, HospitalType, LocalUnit, + LocalUnitChangeRequest, LocalUnitLevel, LocalUnitType, PrimaryHCC, @@ -242,6 +243,7 @@ class PrivateLocalUnitDetailSerializer(NestedCreateMixin, NestedUpdateMixin): modified_by_details = LocalUnitMiniUserSerializer(source="modified_by", read_only=True) created_by_details = LocalUnitMiniUserSerializer(source="created_by", read_only=True) version_id = serializers.SerializerMethodField() + is_locked = serializers.BooleanField(read_only=True) class Meta: model = LocalUnit @@ -283,6 +285,7 @@ class Meta: "modified_by_details", "created_by_details", "version_id", + "is_locked", ) def get_location_details(self, unit) -> dict: @@ -338,6 +341,7 @@ def create(self, validated_data): ) validated_data["location"] = GEOSGeometry("POINT(%f %f)" % (lng, lat)) validated_data["created_by"] = self.context["request"].user + validated_data["is_locked"] = True return super().create(validated_data) def update(self, instance, validated_data): @@ -408,6 +412,7 @@ class PrivateLocalUnitSerializer(serializers.ModelSerializer): health_details = MiniHealthDataSerializer(read_only=True, source="health") validated = serializers.BooleanField(read_only=True) modified_by_details = LocalUnitMiniUserSerializer(source="modified_by", read_only=True) + is_locked = serializers.BooleanField(read_only=True) class Meta: model = LocalUnit @@ -431,6 +436,7 @@ class Meta: "phone", "modified_at", "modified_by_details", + "is_locked", ) def get_location_details(self, unit) -> dict: @@ -520,3 +526,27 @@ class Meta: "city", "address", ) + + +class RejectedReasonSerialzier(serializers.Serializer): + reason = serializers.CharField(required=True) + + +class LocalUnitChangeRequestSerializer(serializers.ModelSerializer): + local_unit_details = PrivateLocalUnitDetailSerializer(source="local_unit", read_only=True) + created_by_details = LocalUnitMiniUserSerializer(source="created_by", read_only=True) + status_details = serializers.CharField(source="get_status_display", read_only=True) + current_validator_details = serializers.CharField(source="get_current_validator_display", read_only=True) + + class Meta: + model = LocalUnitChangeRequest + fields = ( + "id", + "local_unit_details", + "status", + "status_details", + "current_validator", + "current_validator_details", + "created_by_details", + "previous_data", + ) diff --git a/local_units/test_views.py b/local_units/test_views.py index 95237e522..541c82939 100644 --- a/local_units/test_views.py +++ b/local_units/test_views.py @@ -13,7 +13,9 @@ DelegationOfficeType, FacilityType, Functionality, + HealthData, LocalUnit, + LocalUnitChangeRequest, LocalUnitLevel, LocalUnitType, PrimaryHCC, @@ -29,6 +31,11 @@ class Meta: model = LocalUnit +class HealthDataFactory(factory.django.DjangoModelFactory): + class Meta: + model = HealthData + + class TestLocalUnitsListView(APITestCase): def setUp(self): super().setUp() @@ -174,19 +181,6 @@ def test_get_updated_at_updated_by(self): self.assertIsNotNone(response.data["modified_at"]) self.assertEqual(response.data["modified_by_details"]["id"], user_2.id) - def test_validate_local_units(self): - local_unit = LocalUnit.objects.all().first() - self.authenticate() - url = f"/api/v2/local-units/{local_unit.id}/validate/" - data = {} - response = self.client.post(url, data=data) - self.assert_403(response) - - # authenticate with super user - self.client.force_authenticate(self.root_user) - response = self.client.post(url, data=data) - self.assert_200(response) - class DelegationOfficeFactory(factory.django.DjangoModelFactory): location = Point(2.2, 3.3) @@ -320,12 +314,18 @@ def test_create_local_unit_administrative(self): self.authenticate() response = self.client.post("/api/v2/local-units/", data=data, format="json") self.assertEqual(response.status_code, 400) + self.assertEqual(LocalUnitChangeRequest.objects.count(), 0) # add `english branch_name` data["english_branch_name"] = "Test branch name" response = self.client.post("/api/v2/local-units/", data=data, format="json") self.assertEqual(response.status_code, 201) + # Checking the request changes for the local unit is created or not + request_change = LocalUnitChangeRequest.objects.all() + self.assertEqual(request_change.count(), 1) + self.assertEqual(request_change.first().previous_data["id"], response.data["id"]) + def test_create_update_local_unit_health(self): region = Region.objects.create(name=2) country = Country.objects.create(name="Philippines", iso3="PHL", iso="PH", region=region) @@ -409,21 +409,182 @@ def test_create_update_local_unit_health(self): self.client.force_authenticate(self.root_user) response = self.client.post("/api/v2/local-units/", data=data, format="json") self.assertEqual(response.status_code, 201) + self.assertEqual(LocalUnitChangeRequest.objects.count(), 1) + self.assertEqual(response.data["is_locked"], True) + + # Locked local unit should not be updated, until it is unlocked + local_unit_id = response.data["id"] + response = self.client.put(f"/api/v2/local-units/{local_unit_id}/", data=data, format="json") + self.assert_400(response) + + # validating the local unit + self.client.force_authenticate(self.root_user) + response = self.client.post(f"/api/v2/local-units/{local_unit_id}/validate/") + self.assert_200(response) + + # Update existing local_unit with new user + response_updated_1 = self.client.put(f"/api/v2/local-units/{local_unit_id}/", data=data, format="json") + self.assert_200(response_updated_1) - # test update - response = response.json() - local_unit_id = response["id"] - response_updated_1 = self.client.put(f"/api/v2/local-units/{local_unit_id}/", data=data, format="json").json() local_unit_obj = LocalUnit.objects.get(id=local_unit_id) + self.assertEqual(local_unit_obj.is_locked, True) self.assertIsNotNone(local_unit_obj.created_by) - self.assertIsNotNone(response_updated_1["modified_by"]) - self.assertIsNotNone(response_updated_1["modified_at"]) - self.assertEqual(response_updated_1["modified_by"], local_unit_obj.created_by.id) - - # update existing local_unit with new user - user_1 = UserFactory() - self.client.force_authenticate(user_1) - response_updated_2 = self.client.put(f"/api/v2/local-units/{local_unit_id}/", data=data, format="json").json() - self.assertEqual(response_updated_2["modified_by_details"]["id"], user_1.id) - self.assertEqual(response_updated_2["created_by_details"]["id"], self.root_user.id) - assert response_updated_1["modified_at"] < response_updated_2["modified_at"] + self.assertIsNotNone(response_updated_1.data["modified_by"]) + self.assertIsNotNone(response_updated_1.data["modified_at"]) + self.assertEqual(response_updated_1.data["modified_by"], local_unit_obj.created_by.id) + + def test_revert_local_unit(self): + region = Region.objects.create(name=2) + country = Country.objects.create(name="Philippines", iso3="PHL", iso="PH", region=region) + type = LocalUnitType.objects.create(code=2, name="Code 0") + level = LocalUnitLevel.objects.create(level=1, name="Code 1") + affiliation = Affiliation.objects.create(code=1, name="Code 1") + functionality = Functionality.objects.create(code=1, name="Code 1") + health_facility_type = FacilityType.objects.create(code=1, name="Code 1") + primary_health_care_center = PrimaryHCC.objects.create(code=1, name="Code 1") + + data = { + "local_branch_name": "Silele Red Cross Clinic, Sigombeni Red Cross Clinic & Mahwalala Red Cross Clinic", + "english_branch_name": None, + "type": type.id, + "country": country.id, + "created_at": "2024-05-13T06:53:14.978083Z", + "modified_at": "2024-05-13T06:53:14.978099Z", + "draft": False, + "validated": True, + "postcode": "", + "address_loc": "Silele Clinic is is in Hosea Inkhundla under the Shiselweni, Sigombeni is in Nkom'iyahlaba Inkhundla under the Manzini region and Mahwalala is in the Mbabane West Inkhundla under the Hhohho region.", # noqa: E501 + "address_en": "", + "city_loc": "", + "city_en": "", + "link": "", + "location": "SRID=4326;POINT (31.567837 -27.226852)", + "source_loc": "", + "source_en": "", + "subtype": "", + "date_of_data": "2024-05-13", + "level": level.id, + "location_json": { + "lat": 42.066667, + "lng": 19.983333, + }, + "health": { + "other_affiliation": None, + "focal_point_email": "jele@redcross.org.sz", + "focal_point_phone_number": "26876088546", + "focal_point_position": "Programmes Manager", + "other_facility_type": None, + "residents_doctor": 0, + "feedback": "first question of initial question did not provide for the option to write the name of the NS. It is written LRC yet it should allow Baphalali Eswatini Red Cross Society (BERCS) to be inscribed in the box.", # noqa: E501 + "affiliation": affiliation.id, + "functionality": functionality.id, + "health_facility_type": health_facility_type.id, + "primary_health_care_center": primary_health_care_center.id, + }, + "visibility_display": "RCRC Movement", + "focal_person_loc": "Elliot Jele", + "focal_person_en": "", + "email": "", + "phone": "", + } + self.authenticate() + response = self.client.post("/api/v2/local-units/", data=data, format="json") + self.assert_201(response) + + # Checking if the local unit is locked or not + self.assertEqual(response.data["is_locked"], True) + + # validating the local unit + local_unit_id = response.data["id"] + self.client.force_authenticate(self.root_user) + response = self.client.post(f"/api/v2/local-units/{local_unit_id}/validate/") + self.assert_200(response) + self.assertEqual(response.data["is_locked"], False) + + # saving the previous data + previous_data = response.data + + # updating the local unit + data["local_branch_name"] = "Updated local branch name" + data["english_branch_name"] = "Updated english branch name" + data["health"]["focal_point_email"] = "updatedemail@redcross.org.sz" + response = self.client.put(f"/api/v2/local-units/{local_unit_id}/", data=data, format="json") + self.assert_200(response) + self.assertEqual(response.data["local_branch_name"], data["local_branch_name"]) + + # Reverting the local unit + revert_data = { + "reason": "Reverting the local unit test", + } + response = self.client.post(f"/api/v2/local-units/{local_unit_id}/revert/", data=revert_data, format="json") + self.assert_200(response) + + # Checking if the local unit is reverted or not + local_unit = LocalUnit.objects.get(id=local_unit_id) + self.assertEqual(local_unit.local_branch_name, previous_data["local_branch_name"]) + self.assertEqual(local_unit.english_branch_name, previous_data["english_branch_name"]) + + local_unit_change_request = LocalUnitChangeRequest.objects.filter(local_unit=local_unit).last() + self.assertEqual(local_unit_change_request.status, LocalUnitChangeRequest.Status.REVERT) + self.assertEqual(local_unit_change_request.rejected_reason, revert_data["reason"]) + # Checking if the local unit is unlocked + self.assertEqual(local_unit.is_locked, False) + + def test_latest_changes(self): + region = Region.objects.create(name=2) + country = Country.objects.create(name="Philippines", iso3="PHL", iso="PH", region=region) + type = LocalUnitType.objects.create(code=2, name="Code 0") + level = LocalUnitLevel.objects.create(level=1, name="Code 1") + affiliation = Affiliation.objects.create(code=1, name="Code 1") + functionality = Functionality.objects.create(code=1, name="Code 1") + health_facility_type = FacilityType.objects.create(code=1, name="Code 1") + primary_health_care_center = PrimaryHCC.objects.create(code=1, name="Code 1") + + data = { + "local_branch_name": "Silele Red Cross Clinic, Sigombeni Red Cross Clinic & Mahwalala Red Cross Clinic", + "type": type.id, + "country": country.id, + "created_at": "2024-05-13T06:53:14.978083Z", + "modified_at": "2024-05-13T06:53:14.978099Z", + "validated": True, + "date_of_data": "2024-05-13", + "level": level.id, + "address_loc": "Silele Clinic is is in Hosea Inkhundla under the Shiselweni, Sigombeni is in Nkom'iyahlaba Inkhundla under the Manzini region and Mahwalala is in the Mbabane West Inkhundla under the Hhohho region.", # noqa: E501 + "location_json": { + "lat": 42.066667, + "lng": 19.983333, + }, + "health": { + "focal_point_email": "jele@redcross.org.sz", + "focal_point_phone_number": "26876088546", + "affiliation": affiliation.id, + "functionality": functionality.id, + "health_facility_type": health_facility_type.id, + "primary_health_care_center": primary_health_care_center.id, + }, + } + self.authenticate() + response = self.client.post("/api/v2/local-units/", data=data, format="json") + self.assert_201(response) + + # validating the local unit + local_unit_id = response.data["id"] + self.client.force_authenticate(self.root_user) + response = self.client.post(f"/api/v2/local-units/{local_unit_id}/validate/") + self.assert_200(response) + + # saving the previous data + previous_data = response.data + + # Changing the local unit + data["local_branch_name"] = "Updated local branch name" + data["english_branch_name"] = "Updated english branch name" + + response = self.client.put(f"/api/v2/local-units/{local_unit_id}/", data=data, format="json") + self.assert_200(response) + + # Checking the latest changes + response = self.client.post(f"/api/v2/local-units/{local_unit_id}/latest-change-request/") + self.assert_200(response) + self.assertEqual(response.data["previous_data"]["local_branch_name"], previous_data["local_branch_name"]) + self.assertEqual(response.data["previous_data"]["english_branch_name"], previous_data["english_branch_name"]) diff --git a/local_units/utils.py b/local_units/utils.py new file mode 100644 index 000000000..5530dc94e --- /dev/null +++ b/local_units/utils.py @@ -0,0 +1,13 @@ +def get_local_unit_snapshot_data(data: dict) -> dict: + """ + Formatting the json local unit data + """ + location = data.get("location_details", None) + if location: + coordinates = location.get("coordinates") + data["location_json"] = { + "type": location.get("type"), + "lat": coordinates[1], + "lng": coordinates[0], + } + return data diff --git a/local_units/views.py b/local_units/views.py index e1a0ecdc6..10d624dba 100644 --- a/local_units/views.py +++ b/local_units/views.py @@ -1,5 +1,6 @@ +from django.utils import timezone from drf_spectacular.utils import extend_schema -from rest_framework import permissions, response, views, viewsets +from rest_framework import permissions, response, status, views, viewsets from rest_framework.decorators import action from rest_framework.generics import ListAPIView, RetrieveAPIView @@ -14,6 +15,7 @@ GeneralMedicalService, HospitalType, LocalUnit, + LocalUnitChangeRequest, LocalUnitLevel, LocalUnitType, PrimaryHCC, @@ -27,12 +29,15 @@ ) from local_units.serializers import ( DelegationOfficeSerializer, + LocalUnitChangeRequestSerializer, LocalUnitDetailSerializer, LocalUnitOptionsSerializer, LocalUnitSerializer, PrivateLocalUnitDetailSerializer, PrivateLocalUnitSerializer, + RejectedReasonSerialzier, ) +from local_units.utils import get_local_unit_snapshot_data from main.permissions import DenyGuestUserPermission @@ -58,7 +63,44 @@ def get_serializer_class(self): def destroy(self, request, *args, **kwargs): return bad_request("Delete method not allowed") - @extend_schema(responses=PrivateLocalUnitSerializer) + def create(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + self.perform_create(serializer) + + # Creating a new change request for the local unit + LocalUnitChangeRequest.objects.create( + local_unit=serializer.instance, + previous_data=get_local_unit_snapshot_data(serializer.data), + status=LocalUnitChangeRequest.Status.PENDING, + triggered_by=request.user, + ) + return response.Response(serializer.data, status=status.HTTP_201_CREATED) + + def update(self, request, *args, **kwargs): + local_unit = self.get_object() + + # NOTE: Checking if the local unit is locked. + # TODO: This should be moved to a permission class and validators can update the local unit + if local_unit.is_locked: + return bad_request("Local unit is locked and cannot be updated") + + # NOTE: Locking the local unit after the change request is created + local_unit.is_locked = True + serializer = self.get_serializer(local_unit, data=request.data, partial=True) + serializer.is_valid(raise_exception=True) + self.perform_update(serializer) + + # Creating a new change request for the local unit + LocalUnitChangeRequest.objects.create( + local_unit=local_unit, + previous_data=get_local_unit_snapshot_data(serializer.data), + status=LocalUnitChangeRequest.Status.PENDING, + triggered_by=request.user, + ) + return response.Response(serializer.data) + + @extend_schema(request=None, responses=PrivateLocalUnitSerializer) @action( detail=True, url_path="validate", @@ -68,11 +110,110 @@ def destroy(self, request, *args, **kwargs): ) def get_validate(self, request, pk=None, version=None): local_unit = self.get_object() + + # NOTE: Updating the change request with the approval status + change_request_instance = LocalUnitChangeRequest.objects.filter( + local_unit=local_unit, + status=LocalUnitChangeRequest.Status.PENDING, + ).last() + + if not change_request_instance: + return bad_request("No change request found to validate") + + change_request_instance.status = LocalUnitChangeRequest.Status.APPROVED + change_request_instance.updated_by = request.user + change_request_instance.updated_at = timezone.now() + change_request_instance.save(update_fields=["status", "updated_by", "updated_at"]) + + # Validate the local unit local_unit.validated = True - local_unit.save(update_fields=["validated"]) + local_unit.is_locked = False + local_unit.save(update_fields=["validated", "is_locked"]) serializer = PrivateLocalUnitSerializer(local_unit, context={"request": request}) return response.Response(serializer.data) + @extend_schema(request=RejectedReasonSerialzier, responses=PrivateLocalUnitDetailSerializer) + @action( + detail=True, + url_path="revert", + methods=["post"], + serializer_class=RejectedReasonSerialzier, + permission_classes=[permissions.IsAuthenticated, ValidateLocalUnitPermission, DenyGuestUserPermission], + ) + def get_revert(self, request, pk=None, version=None): + local_unit = self.get_object() + + if local_unit.validated: + return bad_request("Local unit is already validated and cannot be reverted") + + full_serializer = PrivateLocalUnitDetailSerializer(local_unit, context={"request": request}) + + serializer = RejectedReasonSerialzier(data=request.data) + serializer.is_valid(raise_exception=True) + reason = serializer.validated_data["reason"] + + # NOTE: Updating the change request with the rejection reason + change_request_instance = LocalUnitChangeRequest.objects.filter( + local_unit=local_unit, + status=LocalUnitChangeRequest.Status.PENDING, + ).last() + + if not change_request_instance: + return bad_request("No change request found to revert") + + change_request_instance.status = LocalUnitChangeRequest.Status.REVERT + change_request_instance.rejected_reason = reason + change_request_instance.updated_by = request.user + change_request_instance.updated_at = timezone.now() + change_request_instance.rejected_data = get_local_unit_snapshot_data(full_serializer.data) + change_request_instance.save(update_fields=["status", "rejected_reason", "updated_at", "updated_by", "rejected_data"]) + + # Reverting the last change request related to this local unit + last_change_request = LocalUnitChangeRequest.objects.filter( + local_unit=local_unit, + status=LocalUnitChangeRequest.Status.APPROVED, + ).last() + + if not last_change_request: + return bad_request("No change request found to revert") + + # NOTE: Unlocking the reverted local unit + local_unit.is_locked = False + local_unit.save(update_fields=["is_locked"]) + + # reverting the previous data of change request to local unit by passing through serializer + serializer = PrivateLocalUnitDetailSerializer( + local_unit, + data=last_change_request.previous_data, + context={"request": request}, + partial=True, + ) + serializer.is_valid(raise_exception=True) + self.perform_update(serializer) + return response.Response(serializer.data) + + @extend_schema(request=None, responses=LocalUnitChangeRequestSerializer) + @action( + detail=True, + url_path="latest-change-request", + methods=["post"], + serializer_class=LocalUnitChangeRequestSerializer, + permission_classes=[permissions.IsAuthenticated, IsAuthenticatedForLocalUnit, DenyGuestUserPermission], + ) + def get_latest_changes(self, request, pk=None, version=None): + local_unit = self.get_object() + + change_request = LocalUnitChangeRequest.objects.filter( + local_unit=local_unit, + status=LocalUnitChangeRequest.Status.APPROVED, + ).last() + + if not change_request: + return bad_request("Last change request not found") + + serializer = LocalUnitChangeRequestSerializer(change_request, context={"request": request}) + return response.Response(serializer.data) + class LocalUnitViewSet(viewsets.ModelViewSet): queryset = LocalUnit.objects.select_related( @@ -80,7 +221,7 @@ class LocalUnitViewSet(viewsets.ModelViewSet): "country", "type", "level", - ).filter(visibility=VisibilityChoices.PUBLIC) + ).filter(visibility=VisibilityChoices.PUBLIC, is_deprecated=False) filterset_class = LocalUnitFilters search_fields = ( "local_branch_name", diff --git a/main/enums.py b/main/enums.py index 2365266e1..9b7ced7ea 100644 --- a/main/enums.py +++ b/main/enums.py @@ -6,6 +6,7 @@ from deployments import enums as deployments_enums from dref import enums as dref_enums from flash_update import enums as flash_update_enums +from local_units import enums as local_units_enums from notifications import enums as notifications_enums from per import enums as per_enums @@ -17,6 +18,7 @@ ("per", per_enums.enum_register), ("notifications", notifications_enums.enum_register), ("databank", databank_enums.enum_register), + ("local_units", local_units_enums.enum_register), ]