From 49a6a0f5955da5809599f94703b52184cbefd80a Mon Sep 17 00:00:00 2001 From: Sushil Tiwari Date: Tue, 10 Dec 2024 12:59:35 +0545 Subject: [PATCH] Update logics on latest-change-request api --- ...localunitchangerequest_options_and_more.py | 26 ++++++++ ...ve_localunit_status_localunit_is_locked.py | 22 ------- local_units/models.py | 4 ++ local_units/serializers.py | 21 ++++++ local_units/test_views.py | 20 +----- local_units/utils.py | 2 +- local_units/views.py | 64 +++++++++++-------- 7 files changed, 91 insertions(+), 68 deletions(-) create mode 100644 local_units/migrations/0020_alter_localunitchangerequest_options_and_more.py delete mode 100644 local_units/migrations/0020_remove_localunit_status_localunit_is_locked.py 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..8d6ce4059 --- /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/migrations/0020_remove_localunit_status_localunit_is_locked.py b/local_units/migrations/0020_remove_localunit_status_localunit_is_locked.py deleted file mode 100644 index 0543c5726..000000000 --- a/local_units/migrations/0020_remove_localunit_status_localunit_is_locked.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 4.2.16 on 2024-12-04 09:36 - -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.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 8725da9ca..99ff42f35 100644 --- a/local_units/models.py +++ b/local_units/models.py @@ -404,7 +404,11 @@ 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): + # 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 0e6861c68..1629e7d4c 100644 --- a/local_units/serializers.py +++ b/local_units/serializers.py @@ -22,6 +22,7 @@ HealthData, HospitalType, LocalUnit, + LocalUnitChangeRequest, LocalUnitLevel, LocalUnitType, PrimaryHCC, @@ -529,3 +530,23 @@ class Meta: 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 7b5695b3b..541c82939 100644 --- a/local_units/test_views.py +++ b/local_units/test_views.py @@ -181,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) @@ -337,7 +324,6 @@ def test_create_local_unit_administrative(self): # Checking the request changes for the local unit is created or not request_change = LocalUnitChangeRequest.objects.all() self.assertEqual(request_change.count(), 1) - print(request_change.first().previous_data) self.assertEqual(request_change.first().previous_data["id"], response.data["id"]) def test_create_update_local_unit_health(self): @@ -598,7 +584,7 @@ def test_latest_changes(self): self.assert_200(response) # Checking the latest changes - response = self.client.post(f"/api/v2/local-units/{local_unit_id}/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["local_branch_name"], previous_data["local_branch_name"]) - self.assertEqual(response.data["english_branch_name"], previous_data["english_branch_name"]) + 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 index 54edf16c9..5530dc94e 100644 --- a/local_units/utils.py +++ b/local_units/utils.py @@ -1,4 +1,4 @@ -def format_local_unit(data: dict) -> dict: +def get_local_unit_snapshot_data(data: dict) -> dict: """ Formatting the json local unit data """ diff --git a/local_units/views.py b/local_units/views.py index 5a6fa5925..10d624dba 100644 --- a/local_units/views.py +++ b/local_units/views.py @@ -29,6 +29,7 @@ ) from local_units.serializers import ( DelegationOfficeSerializer, + LocalUnitChangeRequestSerializer, LocalUnitDetailSerializer, LocalUnitOptionsSerializer, LocalUnitSerializer, @@ -36,7 +37,7 @@ PrivateLocalUnitSerializer, RejectedReasonSerialzier, ) -from local_units.utils import format_local_unit +from local_units.utils import get_local_unit_snapshot_data from main.permissions import DenyGuestUserPermission @@ -67,12 +68,10 @@ def create(self, request, *args, **kwargs): serializer.is_valid(raise_exception=True) self.perform_create(serializer) - clean_data = format_local_unit(serializer.data) - # Creating a new change request for the local unit LocalUnitChangeRequest.objects.create( local_unit=serializer.instance, - previous_data=clean_data, + previous_data=get_local_unit_snapshot_data(serializer.data), status=LocalUnitChangeRequest.Status.PENDING, triggered_by=request.user, ) @@ -92,12 +91,10 @@ def update(self, request, *args, **kwargs): serializer.is_valid(raise_exception=True) self.perform_update(serializer) - clean_data = format_local_unit(serializer.data) - # Creating a new change request for the local unit LocalUnitChangeRequest.objects.create( local_unit=local_unit, - previous_data=clean_data, + previous_data=get_local_unit_snapshot_data(serializer.data), status=LocalUnitChangeRequest.Status.PENDING, triggered_by=request.user, ) @@ -114,17 +111,19 @@ def update(self, request, *args, **kwargs): def get_validate(self, request, pk=None, version=None): local_unit = self.get_object() - serializer = PrivateLocalUnitDetailSerializer(local_unit, context={"request": request}) - clean_data = format_local_unit(serializer.data) - - LocalUnitChangeRequest.objects.create( + # NOTE: Updating the change request with the approval status + change_request_instance = LocalUnitChangeRequest.objects.filter( local_unit=local_unit, - previous_data=clean_data, - status=LocalUnitChangeRequest.Status.APPROVED, - triggered_by=request.user, - updated_by=request.user, - updated_at=timezone.now(), - ) + 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 @@ -148,19 +147,26 @@ def get_revert(self, request, pk=None, version=None): return bad_request("Local unit is already validated and cannot be reverted") full_serializer = PrivateLocalUnitDetailSerializer(local_unit, context={"request": request}) - clean_data = format_local_unit(full_serializer.data) serializer = RejectedReasonSerialzier(data=request.data) serializer.is_valid(raise_exception=True) reason = serializer.validated_data["reason"] - LocalUnitChangeRequest.objects.create( + # NOTE: Updating the change request with the rejection reason + change_request_instance = LocalUnitChangeRequest.objects.filter( local_unit=local_unit, - previous_data=clean_data, - rejected_reason=reason, - status=LocalUnitChangeRequest.Status.REVERT, - triggered_by=request.user, - ) + 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( @@ -174,6 +180,7 @@ def get_revert(self, request, pk=None, version=None): # 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, @@ -185,12 +192,12 @@ def get_revert(self, request, pk=None, version=None): self.perform_update(serializer) return response.Response(serializer.data) - @extend_schema(request=None, responses=PrivateLocalUnitDetailSerializer) + @extend_schema(request=None, responses=LocalUnitChangeRequestSerializer) @action( detail=True, - url_path="latest-changes", + url_path="latest-change-request", methods=["post"], - serializer_class=PrivateLocalUnitDetailSerializer, + serializer_class=LocalUnitChangeRequestSerializer, permission_classes=[permissions.IsAuthenticated, IsAuthenticatedForLocalUnit, DenyGuestUserPermission], ) def get_latest_changes(self, request, pk=None, version=None): @@ -204,7 +211,8 @@ def get_latest_changes(self, request, pk=None, version=None): if not change_request: return bad_request("Last change request not found") - return response.Response(change_request.previous_data) + serializer = LocalUnitChangeRequestSerializer(change_request, context={"request": request}) + return response.Response(serializer.data) class LocalUnitViewSet(viewsets.ModelViewSet):