diff --git a/openwisp_controller/geo/base/models.py b/openwisp_controller/geo/base/models.py index c7bc59798..3b6bde558 100644 --- a/openwisp_controller/geo/base/models.py +++ b/openwisp_controller/geo/base/models.py @@ -5,7 +5,7 @@ AbstractObjectLocation, ) from swapper import get_model_name - +from django.apps import apps from openwisp_users.mixins import OrgMixin, ValidateOrgMixin @@ -13,6 +13,26 @@ class BaseLocation(OrgMixin, AbstractLocation): class Meta(AbstractLocation.Meta): abstract = True + def save(self, *args, **kwargs): + org_changed = False + + if self.pk: + old_org_id = ( + self.__class__.objects.filter(pk=self.pk) + .values_list("organization_id", flat=True) + .first() + ) + org_changed = old_org_id != self.organization_id + + super().save(*args, **kwargs) + + if org_changed: + app_label, model_name = get_model_name("geo", "FloorPlan").split(".") + FloorPlan = apps.get_model(app_label, model_name) + FloorPlan.objects.filter(location=self).update( + organization_id=self.organization_id + ) + class BaseFloorPlan(OrgMixin, AbstractFloorPlan): location = models.ForeignKey(get_model_name("geo", "Location"), models.CASCADE) diff --git a/openwisp_controller/geo/tests/test_models.py b/openwisp_controller/geo/tests/test_models.py index a29d0d0c4..d64a33ae4 100644 --- a/openwisp_controller/geo/tests/test_models.py +++ b/openwisp_controller/geo/tests/test_models.py @@ -1,6 +1,7 @@ +import swapper from django.core.exceptions import ValidationError from django.test import TestCase -from django_loci.tests.base.test_models import BaseTestModels +from django_loci.tests.base import test_models as loci_test_models from swapper import load_model from .utils import TestGeoMixin @@ -11,7 +12,7 @@ DeviceLocation = load_model("geo", "DeviceLocation") -class TestModels(TestGeoMixin, BaseTestModels, TestCase): +class TestModels(TestGeoMixin, loci_test_models.BaseTestModels, TestCase): object_model = Device location_model = Location floorplan_model = FloorPlan @@ -27,3 +28,20 @@ def test_floorplan_location_validation(self): self.assertIn("location", e.message_dict) else: self.fail("ValidationError not raised") + + def test_floorplan_org_updates_when_location_org_changes(self): + Organization = swapper.load_model("openwisp_users", "Organization") + + # This helper creates a floorplan with a valid (indoor) location + floorplan = self._create_floorplan() + location = floorplan.location + + # sanity: floorplan org matches location org initially + self.assertEqual(floorplan.organization_id, location.organization_id) + + org_b = Organization.objects.create(name="org-b", slug="org-b") + location.organization = org_b + location.save() + + floorplan.refresh_from_db() + self.assertEqual(floorplan.organization_id, org_b.id)