Skip to content

Commit

Permalink
Add logic to remove subcomponent of component14 (#2372)
Browse files Browse the repository at this point in the history
* Add logic to remove subcomponent of component14
* Fixed pre-commit check fails
* Add command instead of migration file
* Remove unused import
* Update queryset
* Update queryset for sub component 14
* Update query for subcomponent to parent
* Changes on validated per component and add more test checks
* Remove unused codes
* Changes test cases for migrate component 14
---------

Co-authored-by: Sushil Tiwari <[email protected]>
  • Loading branch information
sudip-khanal and susilnem authored Jan 15, 2025
1 parent c54ef91 commit 059b5ff
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 1 deletion.
6 changes: 5 additions & 1 deletion per/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,11 @@ def area_number(self, obj):

def get_queryset(self, request):
return (
super().get_queryset(request).order_by("area__area_num", "component_num", "component_letter").select_related("area")
super()
.get_queryset(request)
.exclude(component_num=14, is_parent__isnull=True)
.order_by("area__area_num", "component_num", "component_letter")
.select_related("area")
)


Expand Down
8 changes: 8 additions & 0 deletions per/drf_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,11 +170,19 @@ class FormAreaViewset(viewsets.ReadOnlyModelViewSet):

class FormComponentFilter(filters.FilterSet):
area_id = filters.NumberFilter(field_name="area__id", lookup_expr="exact")
exclude_subcomponents = filters.BooleanFilter(
method="get_exclude_subcomponents",
)

class Meta:
model = FormComponent
fields = {"area": ("exact",)}

def get_exclude_subcomponents(self, queryset, name, value):
if value:
return queryset.exclude(component_num=14, is_parent__isnull=True)
return queryset


class FormComponentViewset(viewsets.ReadOnlyModelViewSet):
"""PER Form Components Viewset"""
Expand Down
73 changes: 73 additions & 0 deletions per/management/commands/migrate_sub_components_to_component14.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
from django.core.management.base import BaseCommand

from per.models import FormComponent, OpsLearning


class Command(BaseCommand):
help = "Migration of sub components of component 14 to component 14"

def handle(self, *args, **kwargs):

parent_component_14 = FormComponent.objects.filter(component_num=14, is_parent=True).first()

if not parent_component_14:
self.stdout.write(self.style.ERROR("No parent component found for component 14"))
return

sub_components_14_ids = FormComponent.objects.filter(component_num=14, is_parent__isnull=True).values_list(
"id", flat=True
)

if not sub_components_14_ids.exists():
self.stdout.write(self.style.ERROR("No sub components found for component 14"))
return

# Get OpsLearning IDs that already have parent component
with_parent_component_ops_learning_qs = OpsLearning.objects.filter(per_component=parent_component_14).values_list(
"id", flat=True
)

# For per_component
# Removing if already have parent component
print(
OpsLearning.per_component.through.objects.filter(
formcomponent_id__in=sub_components_14_ids, opslearning_id__in=with_parent_component_ops_learning_qs
).delete()
)

# Removing all Sub-Components except one and updating to parent component
OpsLearning.per_component.through.objects.filter(formcomponent_id__in=sub_components_14_ids).exclude(
id__in=OpsLearning.per_component.through.objects.filter(formcomponent_id__in=sub_components_14_ids).distinct(
"opslearning_id"
)
).delete()

OpsLearning.per_component.through.objects.filter(formcomponent_id__in=sub_components_14_ids).update(
formcomponent_id=parent_component_14.id
)

# For per_component_validated
# Get OpsLearning IDs that already have parent component validated
with_parent_component_validated_ops_learning_qs = OpsLearning.objects.filter(
per_component_validated=parent_component_14
).values_list("id", flat=True)

# Removing if already have parent component
print(
OpsLearning.per_component_validated.through.objects.filter(
formcomponent_id__in=sub_components_14_ids, opslearning_id__in=with_parent_component_validated_ops_learning_qs
).delete()
)

# Removing all Sub-Components except one and updating to parent component
OpsLearning.per_component_validated.through.objects.filter(formcomponent_id__in=sub_components_14_ids).exclude(
id__in=OpsLearning.per_component_validated.through.objects.filter(
formcomponent_id__in=sub_components_14_ids
).distinct("opslearning_id")
).delete()

OpsLearning.per_component_validated.through.objects.filter(formcomponent_id__in=sub_components_14_ids).update(
formcomponent_id=parent_component_14.id
)

self.stdout.write(self.style.SUCCESS("Successfully migrated sub-components of component-14 to component-14"))
62 changes: 62 additions & 0 deletions per/test_views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import json
from unittest import mock

from django.core import management

from api.factories.country import CountryFactory
from api.factories.region import RegionFactory
from api.models import AppealType
Expand Down Expand Up @@ -286,3 +288,63 @@ def test_ops_learning_stats(self):

sources_overtime = response.data["sources_overtime"]
self.assertEqual(len(sources_overtime), 2)

def test_migrate_subcomponents(self):
parent_component_14 = FormComponentFactory.create(component_num=14, is_parent=True)

sub_components_14 = FormComponentFactory.create_batch(3, component_num=14)
other_components = FormComponentFactory.create_batch(2, component_num=1)

# OpsLearning with only parent component and no sub components of component 14
ops_learning_with_only_parent_component = OpsLearningFactory.create()
ops_learning_with_only_parent_component.per_component.add(parent_component_14)
ops_learning_with_only_parent_component.per_component.add(*other_components)

ops_learning_with_only_parent_component.per_component_validated.add(parent_component_14)
ops_learning_with_only_parent_component.per_component_validated.add(*other_components)

# OpsLearning with parent component and sub components
ops_learning_with_parent_component = OpsLearningFactory.create()

ops_learning_with_parent_component.per_component.add(parent_component_14)
ops_learning_with_parent_component.per_component.add(*sub_components_14)
ops_learning_with_parent_component.per_component.add(*other_components)

ops_learning_with_parent_component.per_component_validated.add(parent_component_14)
ops_learning_with_parent_component.per_component_validated.add(*sub_components_14)
ops_learning_with_parent_component.per_component_validated.add(*other_components)

# OpsLearning without parent component but with sub components
ops_learning_without_parent_component = OpsLearningFactory.create()
ops_learning_without_parent_component.per_component.add(*sub_components_14)
ops_learning_without_parent_component.per_component.add(*other_components)

ops_learning_without_parent_component.per_component_validated.add(*sub_components_14)
ops_learning_without_parent_component.per_component_validated.add(*other_components)

# Operational learning with one sub component without parent component
ops_learning = OpsLearningFactory.create()
ops_learning.per_component.add(sub_components_14[0])
ops_learning.per_component_validated.add(sub_components_14[0])
ops_learning.per_component_validated.add(sub_components_14[1])
ops_learning.per_component.add(other_components[0])
ops_learning.per_component_validated.add(other_components[0])

# Run the management command
management.call_command("migrate_sub_components_to_component14")

ops_learning_with_only_parent_component.refresh_from_db()
self.assertEqual(ops_learning_with_only_parent_component.per_component.count(), 3)
self.assertEqual(ops_learning_with_only_parent_component.per_component_validated.count(), 3)

ops_learning_with_parent_component.refresh_from_db()
self.assertEqual(ops_learning_with_parent_component.per_component.count(), 3)
self.assertEqual(ops_learning_with_parent_component.per_component_validated.count(), 3)

ops_learning_without_parent_component.refresh_from_db()
self.assertEqual(ops_learning_without_parent_component.per_component.count(), 3)
self.assertEqual(ops_learning_without_parent_component.per_component_validated.count(), 3)

ops_learning.refresh_from_db()
self.assertEqual(ops_learning.per_component.count(), 2)
self.assertEqual(ops_learning.per_component_validated.count(), 2)

0 comments on commit 059b5ff

Please sign in to comment.