diff --git a/traffic_control/admin/traffic_sign.py b/traffic_control/admin/traffic_sign.py index 829d9175..b607e2e3 100644 --- a/traffic_control/admin/traffic_sign.py +++ b/traffic_control/admin/traffic_sign.py @@ -176,6 +176,7 @@ class TrafficSignPlanAdmin( "value", "txt", "source_id", + "source_name", ) }, ), diff --git a/traffic_control/migrations/0090_alter_additionalsignplan_parent.py b/traffic_control/migrations/0090_alter_additionalsignplan_parent.py new file mode 100644 index 00000000..bcd57f2a --- /dev/null +++ b/traffic_control/migrations/0090_alter_additionalsignplan_parent.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.20 on 2025-04-07 10:45 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('traffic_control', '0089_parkingzoneupdateinfo'), + ] + + operations = [ + migrations.AlterField( + model_name='additionalsignplan', + name='parent', + field=models.ForeignKey(default=1, help_text='The traffic sign to which this additional sign is associated.', on_delete=django.db.models.deletion.PROTECT, related_name='additional_signs', to='traffic_control.trafficsignplan', verbose_name='Parent Traffic Sign Plan'), + preserve_default=False, + ), + ] diff --git a/traffic_control/models/additional_sign.py b/traffic_control/models/additional_sign.py index 1e564829..84f704ac 100644 --- a/traffic_control/models/additional_sign.py +++ b/traffic_control/models/additional_sign.py @@ -217,8 +217,8 @@ class AdditionalSignPlan(UpdatePlanLocationMixin, ReplaceableDevicePlanMixin, Ab verbose_name=_("Parent Traffic Sign Plan"), on_delete=models.PROTECT, related_name="additional_signs", - blank=True, - null=True, + blank=False, + null=False, help_text=_("The traffic sign to which this additional sign is associated."), ) mount_plan = models.ForeignKey( diff --git a/traffic_control/static/traffic_control/openapi/openapi.yaml b/traffic_control/static/traffic_control/openapi/openapi.yaml index dc189c21..c19cc61c 100644 --- a/traffic_control/static/traffic_control/openapi/openapi.yaml +++ b/traffic_control/static/traffic_control/openapi/openapi.yaml @@ -14587,7 +14587,6 @@ components: parent: type: string format: uuid - nullable: true title: Parent Traffic Sign Plan description: The traffic sign to which this additional sign is associated. mount_plan: @@ -14606,6 +14605,7 @@ components: - id - location - owner + - parent - updated_at - updated_by AdditionalSignPlanInputRequest: @@ -14855,7 +14855,6 @@ components: parent: type: string format: uuid - nullable: true title: Parent Traffic Sign Plan description: The traffic sign to which this additional sign is associated. mount_plan: @@ -14871,6 +14870,7 @@ components: required: - location - owner + - parent AdditionalSignPlanOutput: type: object properties: @@ -15151,7 +15151,6 @@ components: parent: type: string format: uuid - nullable: true title: Parent Traffic Sign Plan description: The traffic sign to which this additional sign is associated. mount_plan: @@ -15171,6 +15170,7 @@ components: - is_replaced - location - owner + - parent - replaced_by - replaces - updated_at @@ -21271,7 +21271,6 @@ components: parent: type: string format: uuid - nullable: true title: Parent Traffic Sign Plan description: The traffic sign to which this additional sign is associated. mount_plan: diff --git a/traffic_control/tests/factories.py b/traffic_control/tests/factories.py index 3d7cccd4..95c63794 100644 --- a/traffic_control/tests/factories.py +++ b/traffic_control/tests/factories.py @@ -158,6 +158,7 @@ def get_barrier_plan( device_type=None, responsible_entity=None, replaces=None, + **kwargs, ) -> BarrierPlan: user = get_user("test_user") barrier_plan = BarrierPlan.objects.get_or_create( @@ -173,6 +174,7 @@ def get_barrier_plan( responsible_entity=responsible_entity, created_by=user, updated_by=user, + **kwargs, )[0] if replaces: @@ -269,7 +271,7 @@ class Meta: mount_type = factory.SubFactory(MountTypeFactory) -def get_mount_plan(location="", plan=None, responsible_entity=None, replaces=None) -> MountPlan: +def get_mount_plan(location="", plan=None, responsible_entity=None, replaces=None, **kwargs) -> MountPlan: user = get_user("test_user") mount_plan = MountPlan.objects.get_or_create( @@ -281,6 +283,7 @@ def get_mount_plan(location="", plan=None, responsible_entity=None, replaces=Non responsible_entity=responsible_entity, created_by=user, updated_by=user, + **kwargs, )[0] if replaces: @@ -354,6 +357,7 @@ def get_road_marking_plan( traffic_sign_plan=None, responsible_entity=None, replaces=None, + **kwargs, ) -> RoadMarkingPlan: user = get_user("test_user") @@ -373,6 +377,7 @@ def get_road_marking_plan( traffic_sign_plan=traffic_sign_plan, created_by=user, updated_by=user, + **kwargs, )[0] if replaces: @@ -442,6 +447,7 @@ def get_signpost_plan( txt=None, responsible_entity=None, replaces=None, + **kwargs, ) -> SignpostPlan: user = get_user("test_user") @@ -457,6 +463,7 @@ def get_signpost_plan( txt=txt, created_by=user, updated_by=user, + **kwargs, )[0] if replaces: @@ -525,6 +532,7 @@ def get_traffic_light_plan( mount_plan=None, responsible_entity=None, replaces=None, + **kwargs, ) -> TrafficLightPlan: user = get_user("test_user") @@ -542,6 +550,7 @@ def get_traffic_light_plan( responsible_entity=responsible_entity, created_by=user, updated_by=user, + **kwargs, )[0] if replaces: @@ -638,6 +647,7 @@ def get_traffic_sign_plan( mount_plan=None, responsible_entity=None, replaces=None, + **kwargs, ) -> TrafficSignPlan: user = get_user("test_user") @@ -651,6 +661,7 @@ def get_traffic_sign_plan( mount_plan=mount_plan, created_by=user, updated_by=user, + **kwargs, )[0] if replaces: traffic_sign_plan_replace(old=replaces, new=traffic_sign_plan) @@ -735,6 +746,15 @@ class Meta: parent = factory.SubFactory(TrafficSignPlanFactory) +def get_additional_sign_plan_and_replace(**kwargs): + replaces = kwargs.pop("replaces", None) + asp = AdditionalSignPlanFactory(**kwargs) + asp.refresh_from_db() + if replaces: + additional_sign_plan_replace(old=replaces, new=asp) + return asp + + def get_additional_sign_plan( location=test_point_3d, device_type=None, diff --git a/traffic_control/tests/models/test_plan.py b/traffic_control/tests/models/test_plan.py index cda3847d..b2af2907 100644 --- a/traffic_control/tests/models/test_plan.py +++ b/traffic_control/tests/models/test_plan.py @@ -4,7 +4,7 @@ from city_furniture.tests.factories import get_furniture_signpost_plan from traffic_control.tests.factories import ( - get_additional_sign_plan, + AdditionalSignPlanFactory, get_barrier_plan, get_mount_plan, get_plan, @@ -46,8 +46,8 @@ def test__plan__get_related_locations(): tlp_2 = get_traffic_light_plan(location=Point(MIN_X + 90.0, MIN_Y + 115.0, 0, srid=settings.SRID), plan=plan) tsp_1 = get_traffic_sign_plan(location=Point(MIN_X + 55.0, MIN_Y + 5.0, 0.0, srid=settings.SRID), plan=plan) tsp_2 = get_traffic_sign_plan(location=Point(MIN_X + 95.0, MIN_Y + 110.0, 0.0, srid=settings.SRID), plan=plan) - asp_1 = get_additional_sign_plan(location=Point(MIN_X + 80.0, MIN_Y + 120.0, 0.0, srid=settings.SRID), plan=plan) - asp_2 = get_additional_sign_plan( + asp_1 = AdditionalSignPlanFactory(location=Point(MIN_X + 80.0, MIN_Y + 120.0, 0.0, srid=settings.SRID), plan=plan) + asp_2 = AdditionalSignPlanFactory( location=Point(MIN_X + 85.0, MIN_Y + 125.0, 0.0, srid=settings.SRID), parent=tsp_2, plan=plan ) fsp_1 = get_furniture_signpost_plan( @@ -101,8 +101,8 @@ def test__plan__derive_location_from_related_plans(): tlp_2 = get_traffic_light_plan(location=Point(MIN_X + 90.0, MIN_Y + 115.0, 0.0, srid=settings.SRID), plan=plan) tsp_1 = get_traffic_sign_plan(location=Point(MIN_X + 55.0, MIN_Y + 6.0, 0.0, srid=settings.SRID), plan=plan) tsp_2 = get_traffic_sign_plan(location=Point(MIN_X + 95.0, MIN_Y + 110.0, 0.0, srid=settings.SRID), plan=plan) - asp_1 = get_additional_sign_plan(location=Point(MIN_X + 80.0, MIN_Y + 120.0, 1.0, srid=settings.SRID), plan=plan) - asp_2 = get_additional_sign_plan( + asp_1 = AdditionalSignPlanFactory(location=Point(MIN_X + 80.0, MIN_Y + 120.0, 1.0, srid=settings.SRID), plan=plan) + asp_2 = AdditionalSignPlanFactory( location=Point(MIN_X + 80.0, MIN_Y + 120.0, 2.0, srid=settings.SRID), parent=tsp_2, plan=plan ) fsp_1 = get_furniture_signpost_plan( @@ -118,7 +118,7 @@ def test__plan__derive_location_from_related_plans(): noise_sp = get_signpost_plan(location=Point(MIN_X + 150.0, MIN_Y + 150.0, 0.4, srid=settings.SRID)) noise_tlp = get_traffic_light_plan(location=Point(MIN_X + 150.0, MIN_Y + 150.0, 0.5, srid=settings.SRID)) noise_tsp = get_traffic_sign_plan(location=Point(MIN_X + 150.0, MIN_Y + 150.0, 0.6, srid=settings.SRID)) - noise_asp = get_additional_sign_plan(location=Point(MIN_X + 150.0, MIN_Y + 150.0, 0.7, srid=settings.SRID)) + noise_asp = AdditionalSignPlanFactory(location=Point(MIN_X + 150.0, MIN_Y + 150.0, 0.7, srid=settings.SRID)) noise_fsp = get_furniture_signpost_plan(location=Point(MIN_X + 150.0, MIN_Y + 150.0, 0.8, srid=settings.SRID)) plan.refresh_from_db() @@ -154,7 +154,7 @@ def test__plan__derive_location_from_related_plans(): @pytest.mark.parametrize( "factory", ( - get_additional_sign_plan, + AdditionalSignPlanFactory, get_barrier_plan, get_furniture_signpost_plan, get_mount_plan, @@ -188,7 +188,7 @@ def test__plan__location_update_on_related_model_save(factory, derive_location: @pytest.mark.parametrize( "factory", ( - get_additional_sign_plan, + AdditionalSignPlanFactory, get_barrier_plan, get_furniture_signpost_plan, get_mount_plan, @@ -235,7 +235,7 @@ def test__plan__both_plan_locations_update_when_plan_is_changed(factory, derive_ @pytest.mark.parametrize( "factory", ( - get_additional_sign_plan, + AdditionalSignPlanFactory, get_barrier_plan, get_furniture_signpost_plan, get_mount_plan, @@ -271,7 +271,7 @@ def test__plan__location_update_when_plan_is_removed_from_object(factory, derive @pytest.mark.parametrize( "factory", ( - get_additional_sign_plan, + AdditionalSignPlanFactory, get_barrier_plan, get_furniture_signpost_plan, get_mount_plan, diff --git a/traffic_control/tests/models/test_traffic_control_device_type.py b/traffic_control/tests/models/test_traffic_control_device_type.py index 0bbd17cb..1462ed37 100644 --- a/traffic_control/tests/models/test_traffic_control_device_type.py +++ b/traffic_control/tests/models/test_traffic_control_device_type.py @@ -7,8 +7,8 @@ from traffic_control.enums import DeviceTypeTargetModel from traffic_control.tests.factories import ( + AdditionalSignPlanFactory, AdditionalSignRealFactory, - get_additional_sign_plan, get_barrier_plan, get_barrier_real, get_road_marking_plan, @@ -75,7 +75,7 @@ (DeviceTypeTargetModel.TRAFFIC_LIGHT, get_traffic_light_real), (DeviceTypeTargetModel.TRAFFIC_SIGN, get_traffic_sign_plan), (DeviceTypeTargetModel.TRAFFIC_SIGN, get_traffic_sign_real), - (DeviceTypeTargetModel.ADDITIONAL_SIGN, get_additional_sign_plan), + (DeviceTypeTargetModel.ADDITIONAL_SIGN, AdditionalSignPlanFactory), (DeviceTypeTargetModel.ADDITIONAL_SIGN, AdditionalSignRealFactory), ), ) @@ -110,7 +110,7 @@ def test__traffic_control_device_type__target_model__restricts_relations(allowed (DeviceTypeTargetModel.TRAFFIC_LIGHT, get_traffic_light_real), (DeviceTypeTargetModel.TRAFFIC_SIGN, get_traffic_sign_plan), (DeviceTypeTargetModel.TRAFFIC_SIGN, get_traffic_sign_real), - (DeviceTypeTargetModel.ADDITIONAL_SIGN, get_additional_sign_plan), + (DeviceTypeTargetModel.ADDITIONAL_SIGN, AdditionalSignPlanFactory), (DeviceTypeTargetModel.ADDITIONAL_SIGN, AdditionalSignRealFactory), ), ) @@ -139,7 +139,7 @@ def test__traffic_control_device_type__target_model__update_is_valid(new_target_ (DeviceTypeTargetModel.TRAFFIC_SIGN, get_traffic_light_real), (DeviceTypeTargetModel.ADDITIONAL_SIGN, get_traffic_sign_plan), (DeviceTypeTargetModel.ADDITIONAL_SIGN, get_traffic_sign_real), - (DeviceTypeTargetModel.BARRIER, get_additional_sign_plan), + (DeviceTypeTargetModel.BARRIER, AdditionalSignPlanFactory), (DeviceTypeTargetModel.BARRIER, AdditionalSignRealFactory), ), ) @@ -169,7 +169,7 @@ def test__traffic_control_device_type__target_model__validate_multiple_invalid_r get_traffic_light_real(device_type=device_type) get_traffic_sign_plan(device_type=device_type) get_traffic_sign_real(device_type=device_type) - get_additional_sign_plan(device_type=device_type) + AdditionalSignPlanFactory(device_type=device_type) AdditionalSignRealFactory(device_type=device_type) for target_model in DeviceTypeTargetModel: diff --git a/traffic_control/tests/test_additional_sign_admin.py b/traffic_control/tests/test_additional_sign_admin.py index d73ce2d0..1c2e96ab 100644 --- a/traffic_control/tests/test_additional_sign_admin.py +++ b/traffic_control/tests/test_additional_sign_admin.py @@ -8,12 +8,13 @@ from traffic_control.enums import DeviceTypeTargetModel, Lifecycle from traffic_control.models import AdditionalSignPlan, AdditionalSignReal from traffic_control.tests.factories import ( + AdditionalSignPlanFactory, AdditionalSignRealFactory, - get_additional_sign_plan, get_owner, get_traffic_control_device_type, get_user, TrafficControlDeviceTypeFactory, + TrafficSignPlanFactory, TrafficSignRealFactory, ) from traffic_control.tests.models.test_traffic_control_device_type import content_valid_by_simple_schema, simple_schema @@ -35,7 +36,7 @@ def teardown_module(): @pytest.mark.parametrize( ("model", "url_name", "parent_factory"), ( - (AdditionalSignPlan, "additionalsignplan", None), + (AdditionalSignPlan, "additionalsignplan", TrafficSignPlanFactory), (AdditionalSignReal, "additionalsignreal", TrafficSignRealFactory), ), ids=("plan", "real"), @@ -82,7 +83,7 @@ def test__additional_sign__create_missing_content(client: Client, model, url_nam @pytest.mark.parametrize( ("model", "factory", "url_name", "parent_factory"), ( - (AdditionalSignPlan, get_additional_sign_plan, "additionalsignplan", None), + (AdditionalSignPlan, AdditionalSignPlanFactory, "additionalsignplan", TrafficSignPlanFactory), (AdditionalSignReal, AdditionalSignRealFactory, "additionalsignreal", TrafficSignRealFactory), ), ids=("plan", "real"), @@ -141,7 +142,7 @@ def test__additional_sign__update_device_with_content_to_missing_content( @pytest.mark.parametrize( ("model", "factory", "url_name", "parent_factory"), ( - (AdditionalSignPlan, get_additional_sign_plan, "additionalsignplan", None), + (AdditionalSignPlan, AdditionalSignPlanFactory, "additionalsignplan", TrafficSignPlanFactory), (AdditionalSignReal, AdditionalSignRealFactory, "additionalsignreal", TrafficSignRealFactory), ), ids=("plan", "real"), @@ -227,7 +228,7 @@ def test__additional_sign__create_dont_accept_content_when_missing_content_is_en @pytest.mark.parametrize( ("model", "factory", "url_name", "parent_factory"), ( - (AdditionalSignPlan, get_additional_sign_plan, "additionalsignplan", None), + (AdditionalSignPlan, AdditionalSignPlanFactory, "additionalsignplan", TrafficSignPlanFactory), (AdditionalSignReal, AdditionalSignRealFactory, "additionalsignreal", TrafficSignRealFactory), ), ids=("plan", "real"), @@ -273,7 +274,7 @@ def test__additional_sign__update_dont_accept_content_when_missing_content_is_en @pytest.mark.parametrize( "model,factory,url_name,parent_factory", ( - (AdditionalSignPlan, get_additional_sign_plan, "additionalsignplan", None), + (AdditionalSignPlan, AdditionalSignPlanFactory, "additionalsignplan", TrafficSignPlanFactory), (AdditionalSignReal, AdditionalSignRealFactory, "additionalsignreal", TrafficSignRealFactory), ), ) @@ -315,7 +316,7 @@ def test_additional_sign_illegal_location(client: Client, model, factory, url_na @pytest.mark.parametrize( "model,url_name,parent_factory", ( - (AdditionalSignPlan, "additionalsignplan", None), + (AdditionalSignPlan, "additionalsignplan", TrafficSignPlanFactory), (AdditionalSignReal, "additionalsignreal", TrafficSignRealFactory), ), ) diff --git a/traffic_control/tests/test_additional_sign_plan_api.py b/traffic_control/tests/test_additional_sign_plan_api.py index 25668ae2..66953b7d 100644 --- a/traffic_control/tests/test_additional_sign_plan_api.py +++ b/traffic_control/tests/test_additional_sign_plan_api.py @@ -12,12 +12,12 @@ from traffic_control.tests.api_utils import do_filtering_test, do_illegal_geometry_test from traffic_control.tests.factories import ( AdditionalSignPlanFactory, - get_additional_sign_plan, get_api_client, get_owner, get_traffic_control_device_type, get_traffic_sign_plan, get_user, + TrafficSignPlanFactory, ) from traffic_control.tests.models.test_traffic_control_device_type import ( another_content_valid_by_simple_schema, @@ -39,7 +39,7 @@ def test__additional_sign_plan__list(geo_format): client = get_api_client() for owner_name in ["foo", "bar", "baz"]: - get_additional_sign_plan(owner=get_owner(name_fi=owner_name)) + AdditionalSignPlanFactory(owner=get_owner(name_fi=owner_name)) response = client.get(reverse("v1:additionalsignplan-list"), data={"geo_format": geo_format}) response_data = response.json() @@ -82,7 +82,7 @@ def test__additional_sign_plan_filtering__list(field_name, value, second_value): @pytest.mark.django_db def test__additional_sign_plan__detail(geo_format): client = get_api_client() - asp = get_additional_sign_plan(parent=get_traffic_sign_plan()) + asp = AdditionalSignPlanFactory(parent=TrafficSignPlanFactory()) response = client.get( reverse("v1:additionalsignplan-detail", kwargs={"pk": asp.pk}), @@ -212,6 +212,7 @@ def test__additional_sign_plan__create_with_invalid_geometry(): data = { "location": illegal_test_point.ewkt, "owner": str(get_owner().pk), + "parent": TrafficSignPlanFactory().pk, } do_illegal_geometry_test( "v1:additionalsignplan-list", @@ -256,7 +257,7 @@ def test__additional_sign_plan__update_device_type_and_content( old_dt = get_traffic_control_device_type(code="A1234", content_schema=old_schema) new_dt = get_traffic_control_device_type(code="new_code", content_schema=new_schema) tsp = get_traffic_sign_plan() - asp = get_additional_sign_plan(content_s=old_content, device_type=old_dt) + asp = AdditionalSignPlanFactory(content_s=old_content, device_type=old_dt) data = { "parent": tsp.pk, @@ -299,7 +300,7 @@ def test__additional_sign_plan__partial_update_without_content(admin_user): """ client = get_api_client(user=get_user(admin=admin_user)) dt = get_traffic_control_device_type(code="A1234") - asp = get_additional_sign_plan() + asp = AdditionalSignPlanFactory() tsp = get_traffic_sign_plan(device_type=dt) data = { "parent": tsp.pk, @@ -344,7 +345,7 @@ def test__additional_sign_plan__partial_update_content( """ client = get_api_client(user=get_user(admin=admin_user)) dt = get_traffic_control_device_type(code="DT1", content_schema=schema) - asp = get_additional_sign_plan(device_type=dt, content_s=old_content) + asp = AdditionalSignPlanFactory(device_type=dt, content_s=old_content) asp_id = str(asp.pk) data = { "content_s": new_content, @@ -404,7 +405,7 @@ def test__additional_sign_plan__partial_update_device_type_and_content( client = get_api_client(user=get_user(admin=admin_user)) old_dt = get_traffic_control_device_type(code="DT1", content_schema=old_schema) new_dt = get_traffic_control_device_type(code="DT2", content_schema=new_schema) - asp = get_additional_sign_plan(device_type=old_dt, content_s=old_content) + asp = AdditionalSignPlanFactory(device_type=old_dt, content_s=old_content) asp_id = str(asp.pk) data = { "content_s": new_content, @@ -507,7 +508,7 @@ def test__additional_sign_plan__create_dont_accept_content_when_missing_content_ def test__additional_sign_plan__delete(admin_user): user = get_user(admin=admin_user) client = get_api_client(user=user) - asp = get_additional_sign_plan() + asp = AdditionalSignPlanFactory() response = client.delete(reverse("v1:additionalsignplan-detail", kwargs={"pk": asp.pk})) @@ -529,7 +530,7 @@ def test__additional_sign_plan__delete(admin_user): def test__additional_sign_plan__soft_deleted_get_404_response(): user = get_user() client = get_api_client() - asp = get_additional_sign_plan() + asp = AdditionalSignPlanFactory() asp.soft_delete(user) response = client.get(reverse("v1:additionalsignplan-detail", kwargs={"pk": asp.pk})) @@ -556,7 +557,7 @@ def test__additional_sign_plan__anonymous_user(method, expected_status, view_typ Test that for unauthorized user the API responses 401 unauthorized, but OK for safe methods. """ client = get_api_client(user=None) - asp = get_additional_sign_plan(owner=get_owner(name_en="Old owner", name_fi="Vanha omistaja")) + asp = AdditionalSignPlanFactory(owner=get_owner(name_en="Old owner", name_fi="Vanha omistaja")) kwargs = {"pk": asp.pk} if view_type == "detail" else None resource_path = reverse(f"v1:additionalsignplan-{view_type}", kwargs=kwargs) data = {"owner": str(get_owner(name_en="New owner", name_fi="Uusi omistaja").pk)} diff --git a/traffic_control/tests/test_additional_sign_real_api.py b/traffic_control/tests/test_additional_sign_real_api.py index f2fea743..32ba74fc 100644 --- a/traffic_control/tests/test_additional_sign_real_api.py +++ b/traffic_control/tests/test_additional_sign_real_api.py @@ -24,8 +24,6 @@ add_additional_sign_real_operation, AdditionalSignPlanFactory, AdditionalSignRealFactory, - get_additional_sign_plan, - get_additional_sign_real, get_api_client, get_operation_type, get_owner, @@ -109,8 +107,8 @@ def test__additional_sign_real_filtering__list(field_name, value, second_value): def test__additional_sign_real__detail(geo_format, plan_decision_id): client = get_api_client() plan = PlanFactory(decision_id=plan_decision_id) if plan_decision_id else None - ads_plan = get_additional_sign_plan(plan=plan) if plan else None - asr = get_additional_sign_real(parent=get_traffic_sign_real(), additional_sign_plan=ads_plan) + ads_plan = AdditionalSignPlanFactory(plan=plan) if plan else None + asr = AdditionalSignRealFactory(parent=get_traffic_sign_real(), additional_sign_plan=ads_plan) operation_1 = add_additional_sign_real_operation(asr, operation_date=datetime.date(2020, 11, 5)) operation_2 = add_additional_sign_real_operation(asr, operation_date=datetime.date(2020, 11, 15)) operation_3 = add_additional_sign_real_operation(asr, operation_date=datetime.date(2020, 11, 10)) diff --git a/traffic_control/tests/test_anonymous_requests.py b/traffic_control/tests/test_anonymous_requests.py index e798f9cb..50429196 100644 --- a/traffic_control/tests/test_anonymous_requests.py +++ b/traffic_control/tests/test_anonymous_requests.py @@ -5,8 +5,8 @@ from city_furniture.tests.factories import get_furniture_signpost_plan, get_furniture_signpost_real from traffic_control.tests.factories import ( + AdditionalSignPlanFactory, AdditionalSignRealFactory, - get_additional_sign_plan, get_api_client, get_barrier_plan, get_barrier_real, @@ -50,7 +50,7 @@ def assert_no_user_ids(object: dict): @pytest.mark.parametrize( "endpoint_name,device_factory", ( - ("v1:additionalsignplan", get_additional_sign_plan), + ("v1:additionalsignplan", AdditionalSignPlanFactory), ("v1:additionalsignreal", AdditionalSignRealFactory), ("v1:barrierplan", get_barrier_plan), ("v1:barrierreal", get_barrier_real), @@ -88,7 +88,7 @@ def test__hide_user_info_from_anonymous_request_single( @pytest.mark.parametrize( "endpoint_name,device_factory", ( - ("v1:additionalsignplan", get_additional_sign_plan), + ("v1:additionalsignplan", AdditionalSignPlanFactory), ("v1:additionalsignreal", AdditionalSignRealFactory), ("v1:barrierplan", get_barrier_plan), ("v1:barrierreal", get_barrier_real), diff --git a/traffic_control/tests/test_api_file_upload.py b/traffic_control/tests/test_api_file_upload.py index cf9ae03a..4261f8ea 100644 --- a/traffic_control/tests/test_api_file_upload.py +++ b/traffic_control/tests/test_api_file_upload.py @@ -43,8 +43,8 @@ ) from traffic_control.services.virus_scan import get_clam_av_scan_url from traffic_control.tests.factories import ( + AdditionalSignPlanFactory, AdditionalSignRealFactory, - get_additional_sign_plan, get_api_client, get_barrier_plan, get_barrier_real, @@ -68,7 +68,7 @@ DELETE_TEST_PARAMS = ( ( - get_additional_sign_plan, + AdditionalSignPlanFactory, AdditionalSignPlan, AdditionalSignPlanFile, "additional_sign_plan", @@ -144,7 +144,7 @@ ) FILE_UPLOAD_PARAMS = ( - (get_additional_sign_plan, AdditionalSignPlan, "additionalsignplan"), + (AdditionalSignPlanFactory, AdditionalSignPlan, "additionalsignplan"), (AdditionalSignRealFactory, AdditionalSignReal, "additionalsignreal"), (get_barrier_plan, BarrierPlan, "barrierplan"), (get_barrier_real, BarrierReal, "barrierreal"), @@ -284,7 +284,7 @@ def test_invalid_file_upload(factory, model_class, url_name, mock_api): "factory,model_class,file_model_class,related_name,url_name", ( ( - get_additional_sign_plan, + AdditionalSignPlanFactory, AdditionalSignPlan, AdditionalSignPlanFile, "additional_sign_plan", @@ -452,7 +452,7 @@ def test_file_delete_with_non_existing_base_object(factory, model_class, file_mo "factory, model_class, file_model_class, related_name, url_name", ( ( - get_additional_sign_plan, + AdditionalSignPlanFactory, AdditionalSignPlan, AdditionalSignPlanFile, "additional_sign_plan", diff --git a/traffic_control/tests/test_import_export/test_additional_sign_import_export.py b/traffic_control/tests/test_import_export/test_additional_sign_import_export.py index c6e589be..87bd9c9d 100644 --- a/traffic_control/tests/test_import_export/test_additional_sign_import_export.py +++ b/traffic_control/tests/test_import_export/test_additional_sign_import_export.py @@ -11,13 +11,13 @@ from traffic_control.tests.factories import ( AdditionalSignPlanFactory, AdditionalSignRealFactory, - get_additional_sign_plan, get_mount_plan, get_mount_real, get_owner, get_traffic_control_device_type, get_traffic_sign_plan, get_traffic_sign_real, + TrafficSignPlanFactory, TrafficSignRealFactory, ) from traffic_control.tests.test_base_api import test_point @@ -37,7 +37,7 @@ def test__additional_sign_real__export(): @pytest.mark.parametrize( "resource, model, factory", ( - (AdditionalSignPlanResource, AdditionalSignPlan, get_additional_sign_plan), + (AdditionalSignPlanResource, AdditionalSignPlan, AdditionalSignPlanFactory), (AdditionalSignRealResource, AdditionalSignReal, AdditionalSignRealFactory), ), ) @@ -385,7 +385,7 @@ def test__additional_sign__import__create_with_missing_content(model, resource, @pytest.mark.parametrize( "model, resource, factory", ( - (AdditionalSignPlan, AdditionalSignPlanResource, get_additional_sign_plan), + (AdditionalSignPlan, AdditionalSignPlanResource, AdditionalSignPlanFactory), (AdditionalSignReal, AdditionalSignRealResource, AdditionalSignRealFactory), ), ids=("plan", "real"), @@ -473,7 +473,7 @@ def test__additional_sign__import__create_with_invalid_content(model, resource, @pytest.mark.parametrize( "model, resource, factory", ( - (AdditionalSignPlan, AdditionalSignPlanResource, get_additional_sign_plan), + (AdditionalSignPlan, AdditionalSignPlanResource, AdditionalSignPlanFactory), (AdditionalSignReal, AdditionalSignRealResource, AdditionalSignRealFactory), ), ) @@ -508,7 +508,7 @@ def test__additional_sign__import__create_with_invalid_device_type(model, resour @pytest.mark.parametrize( "model, resource, factory", ( - (AdditionalSignPlan, AdditionalSignPlanResource, get_additional_sign_plan), + (AdditionalSignPlan, AdditionalSignPlanResource, AdditionalSignPlanFactory), (AdditionalSignReal, AdditionalSignRealResource, AdditionalSignRealFactory), ), ) @@ -545,7 +545,7 @@ def test__additional_sign__import__create_with_minimal_columns(model, resource, @pytest.mark.parametrize( "model, resource, factory", ( - (AdditionalSignPlan, AdditionalSignPlanResource, get_additional_sign_plan), + (AdditionalSignPlan, AdditionalSignPlanResource, AdditionalSignPlanFactory), (AdditionalSignReal, AdditionalSignRealResource, AdditionalSignRealFactory), ), ) @@ -982,6 +982,8 @@ def test__additional_sign__import__valid_and_invalid_content_properties(schema_p if model == AdditionalSignReal: additional_sign_data.update({"parent__id": TrafficSignRealFactory().pk}) + elif model == AdditionalSignPlan: + additional_sign_data.update({"parent__id": TrafficSignPlanFactory().pk}) expect_valid = True if validity == "valid" else False @@ -1005,11 +1007,6 @@ def test__additional_sign__import__valid_and_invalid_content_properties(schema_p @pytest.mark.parametrize("has_mount_plan", (True, False), ids=lambda x: "mount_plan" if x else "no_mount_plan") @pytest.mark.parametrize("has_mount_real", (True, False), ids=lambda x: "mount_real" if x else "no_mount_real") -@pytest.mark.parametrize( - "has_traffic_sign_plan", - (True, False), - ids=lambda x: "traffic_sign_plan" if x else "no_traffic_sign_plan", -) @pytest.mark.parametrize( "has_traffic_sign_real", (True, False), @@ -1020,7 +1017,6 @@ def test__additional_sign__import__valid_and_invalid_content_properties(schema_p def test__additional_sign_plan_export_real_import( has_mount_plan, has_mount_real, - has_traffic_sign_plan, has_traffic_sign_real, real_preexists, ): @@ -1028,10 +1024,10 @@ def test__additional_sign_plan_export_real_import( mount_plan = get_mount_plan() if has_mount_plan else None mount_real = get_mount_real() if has_mount_real else None - traffic_sign_plan = get_traffic_sign_plan() if has_traffic_sign_plan else None + traffic_sign_plan = get_traffic_sign_plan() traffic_sign_real = get_traffic_sign_real() if has_traffic_sign_real else None - plan_obj = get_additional_sign_plan(mount_plan=mount_plan, parent=traffic_sign_plan) + plan_obj = AdditionalSignPlanFactory(mount_plan=mount_plan, parent=traffic_sign_plan) real_obj = AdditionalSignRealFactory(additional_sign_plan=plan_obj) if real_preexists else None exported_dataset = AdditionalSignPlanToRealTemplateResource().export() @@ -1044,7 +1040,7 @@ def test__additional_sign_plan_export_real_import( else: assert real["mount_real__id"] is None - if has_traffic_sign_plan and has_traffic_sign_real: + if has_traffic_sign_real: assert real["parent__id"] == traffic_sign_real.id else: assert real["parent__id"] is None diff --git a/traffic_control/tests/test_import_export/test_device_responsible_entity_import_export.py b/traffic_control/tests/test_import_export/test_device_responsible_entity_import_export.py index 2137cc51..d717e659 100644 --- a/traffic_control/tests/test_import_export/test_device_responsible_entity_import_export.py +++ b/traffic_control/tests/test_import_export/test_device_responsible_entity_import_export.py @@ -37,8 +37,8 @@ TrafficSignRealResource, ) from traffic_control.tests.factories import ( + AdditionalSignPlanFactory, AdditionalSignRealFactory, - get_additional_sign_plan, get_barrier_plan, get_barrier_real, get_mount_plan, @@ -59,7 +59,7 @@ _models_resources_factories = ( (FurnitureSignpostPlan, FurnitureSignpostPlanResource, get_furniture_signpost_plan), (FurnitureSignpostReal, FurnitureSignpostRealResource, get_furniture_signpost_real), - (AdditionalSignPlan, AdditionalSignPlanResource, get_additional_sign_plan), + (AdditionalSignPlan, AdditionalSignPlanResource, AdditionalSignPlanFactory), (AdditionalSignReal, AdditionalSignRealResource, AdditionalSignRealFactory), (BarrierPlan, BarrierPlanResource, get_barrier_plan), (BarrierReal, BarrierRealResource, get_barrier_real), diff --git a/traffic_control/tests/test_import_export/test_replace_device_plan_import_export.py b/traffic_control/tests/test_import_export/test_replace_device_plan_import_export.py index ebca4e30..fe4c8878 100644 --- a/traffic_control/tests/test_import_export/test_replace_device_plan_import_export.py +++ b/traffic_control/tests/test_import_export/test_replace_device_plan_import_export.py @@ -20,7 +20,7 @@ ) from traffic_control.tests.factories import ( AdditionalSignRealFactory, - get_additional_sign_plan, + get_additional_sign_plan_and_replace, get_barrier_plan, get_barrier_real, get_mount_plan, @@ -39,7 +39,7 @@ model_factory_resource = ( (TrafficSignPlan, get_traffic_sign_plan, TrafficSignPlanResource), - (AdditionalSignPlan, get_additional_sign_plan, AdditionalSignPlanResource), + (AdditionalSignPlan, get_additional_sign_plan_and_replace, AdditionalSignPlanResource), (MountPlan, get_mount_plan, MountPlanResource), (TrafficLightPlan, get_traffic_light_plan, TrafficLightPlanResource), (SignpostPlan, get_signpost_plan, SignpostPlanResource), @@ -57,7 +57,7 @@ ), ( AdditionalSignPlan, - get_additional_sign_plan, + get_additional_sign_plan_and_replace, "additional_sign_plan", AdditionalSignRealFactory, AdditionalSignPlanResource, @@ -134,7 +134,7 @@ def test__device_plan_replace_export__list_replaced_devices(model, factory, reso @pytest.mark.parametrize(("model", "factory", "resource"), model_factory_resource) @pytest.mark.django_db def test__device_plan_replace_import__create__old_is_marked_replaced(model, factory, resource, format): - old_device = factory() + old_device = factory(source_name=None, source_id=None) dataset = get_import_dataset(resource, format=format, delete_columns=["id"]) dataset.append_col([str(old_device.id)], header="replaces") @@ -296,7 +296,7 @@ def test__device_plan_replace_import__create__real_devices_plan_is_updated_to_re resource, format, ): - old_device_plan = plan_factory() + old_device_plan = plan_factory(source_name=None, source_id=None) device_real = real_factory(**{plan_relation_name: old_device_plan}) dataset = get_import_dataset( diff --git a/traffic_control/tests/test_operational_area_api_permission.py b/traffic_control/tests/test_operational_area_api_permission.py index b69a66f1..d790b6e2 100644 --- a/traffic_control/tests/test_operational_area_api_permission.py +++ b/traffic_control/tests/test_operational_area_api_permission.py @@ -12,8 +12,8 @@ from traffic_control.enums import Lifecycle from traffic_control.models import BarrierPlan from traffic_control.tests.factories import ( + AdditionalSignPlanFactory, AdditionalSignRealFactory, - get_additional_sign_plan, get_api_client, get_barrier_plan, get_barrier_real, @@ -32,6 +32,7 @@ get_traffic_sign_plan, get_traffic_sign_real, get_user, + TrafficSignPlanFactory, TrafficSignRealFactory, ) from traffic_control.tests.utils import MIN_X, MIN_Y @@ -68,7 +69,7 @@ ) model_factory_map = { - "AdditionalSignPlan": get_additional_sign_plan, + "AdditionalSignPlan": AdditionalSignPlanFactory, "AdditionalSignReal": AdditionalSignRealFactory, "BarrierPlan": get_barrier_plan, "BarrierReal": get_barrier_real, @@ -177,6 +178,8 @@ def test__api_operational_area_permission__create(model, location, success): data["source_name"] = "test source" elif model == "AdditionalSignReal": data["parent"] = TrafficSignRealFactory().pk + elif model == "AdditionalSignPlan": + data["parent"] = TrafficSignPlanFactory().pk api_client = get_api_client(user=user) response = api_client.post(reverse(f"v1:{model.lower()}-list"), data=data, format="json") @@ -307,6 +310,8 @@ def test__api_operational_area_permission__update(model, location, success): data["source_name"] = "test source" elif model == "AdditionalSignReal": data["parent"] = TrafficSignRealFactory().pk + elif model == "AdditionalSignPlan": + data["parent"] = TrafficSignPlanFactory().pk api_client = get_api_client(user=user) response = api_client.put( diff --git a/traffic_control/tests/test_plan_admin.py b/traffic_control/tests/test_plan_admin.py index 73d3e384..4d03ccb6 100644 --- a/traffic_control/tests/test_plan_admin.py +++ b/traffic_control/tests/test_plan_admin.py @@ -19,7 +19,7 @@ from traffic_control.mixins.admin import CityInfraAdminConfirmMixin from traffic_control.models import Plan from traffic_control.tests.factories import ( - get_additional_sign_plan, + AdditionalSignPlanFactory, get_barrier_plan, get_mount_plan, get_plan, @@ -132,7 +132,7 @@ def test_plan_relation_admin_view_form_submit(admin_client, redirect_after_save) signpost_plan = get_signpost_plan() traffic_light_plan = get_traffic_light_plan() traffic_sign_plan = get_traffic_sign_plan() - additional_sign_plan = get_additional_sign_plan() + additional_sign_plan = AdditionalSignPlanFactory() furniture_signpost_plan = get_furniture_signpost_plan() for p in [ @@ -196,7 +196,7 @@ def test_plan_relation_admin_view_available_choices(admin_client): get_signpost_plan(location=loc, plan=plan) get_traffic_light_plan(location=loc, plan=plan) get_traffic_sign_plan(location=loc_3d, plan=plan) - get_additional_sign_plan(location=loc_3d, plan=plan) + AdditionalSignPlanFactory(location=loc_3d, plan=plan) get_furniture_signpost_plan(location=loc, plan=plan) plan_1.refresh_from_db() @@ -219,7 +219,7 @@ def test_plan_relation_admin_view_available_choices(admin_client): @pytest.mark.parametrize( "factory", ( - get_additional_sign_plan, + AdditionalSignPlanFactory, get_barrier_plan, get_furniture_signpost_plan, get_mount_plan, diff --git a/traffic_control/tests/test_replace_device_plan_api.py b/traffic_control/tests/test_replace_device_plan_api.py index 4241413b..a1d9ba32 100644 --- a/traffic_control/tests/test_replace_device_plan_api.py +++ b/traffic_control/tests/test_replace_device_plan_api.py @@ -15,7 +15,7 @@ ) from traffic_control.tests.factories import ( AdditionalSignRealFactory, - get_additional_sign_plan, + get_additional_sign_plan_and_replace, get_api_client, get_barrier_plan, get_barrier_real, @@ -31,12 +31,13 @@ get_traffic_sign_plan, get_traffic_sign_real, get_user, + TrafficSignPlanFactory, ) from traffic_control.tests.test_base_api_3d import test_point_2_3d, test_point_3_3d, test_point_3d, test_point_5_3d model_factory_url_name = ( (TrafficSignPlan, get_traffic_sign_plan, "trafficsignplan"), - (AdditionalSignPlan, get_additional_sign_plan, "additionalsignplan"), + (AdditionalSignPlan, get_additional_sign_plan_and_replace, "additionalsignplan"), (MountPlan, get_mount_plan, "mountplan"), (TrafficLightPlan, get_traffic_light_plan, "trafficlightplan"), (SignpostPlan, get_signpost_plan, "signpostplan"), @@ -48,7 +49,7 @@ plan_factory_url_name_plan_relation_name_real_factory = ( (get_traffic_sign_plan, "trafficsignplan", "traffic_sign_plan", get_traffic_sign_real), (get_mount_plan, "mountplan", "mount_plan", get_mount_real), - (get_additional_sign_plan, "additionalsignplan", "additional_sign_plan", AdditionalSignRealFactory), + (get_additional_sign_plan_and_replace, "additionalsignplan", "additional_sign_plan", AdditionalSignRealFactory), (get_traffic_light_plan, "trafficlightplan", "traffic_light_plan", get_traffic_light_real), (get_signpost_plan, "signpostplan", "signpost_plan", get_signpost_real), (get_barrier_plan, "barrierplan", "barrier_plan", get_barrier_real), @@ -146,6 +147,8 @@ def test__device_plan_replace__create__old_is_marked_replaced(model, factory, ur } if model == BarrierPlan: data["road_name"] = "Road name" + elif model == AdditionalSignPlan: + data["parent"] = TrafficSignPlanFactory().pk response = client.post(reverse(f"v1:{url_name}-list"), data, format="json") old_device.refresh_from_db() @@ -286,6 +289,8 @@ def test__device_plan_replace__create__real_devices_plan_is_updated_to_replacer( } if plan_url_name == "barrierplan": data["road_name"] = "Road name" + if plan_url_name == "additionalsignplan": + data["parent"] = TrafficSignPlanFactory().pk response = client.post(reverse(f"v1:{plan_url_name}-list"), data, format="json") old_device_plan.refresh_from_db() @@ -414,6 +419,8 @@ def test__device_plan_replace__create__replaces_not_found(model, factory, url_na } if model == BarrierPlan: data["road_name"] = "Road name" + elif model == AdditionalSignPlan: + data["parent"] = TrafficSignPlanFactory().pk response = client.post(reverse(f"v1:{url_name}-list"), data, format="json") @@ -452,6 +459,8 @@ def test__device_plan_replace__update__replaces_not_found__put(model, factory, u } if model == BarrierPlan: data["road_name"] = "Road name" + elif model == AdditionalSignPlan: + data["parent"] = TrafficSignPlanFactory().pk response = client.put(reverse(f"v1:{url_name}-detail", kwargs={"pk": new_device.id}), data, format="json") diff --git a/traffic_control/tests/test_responsible_entity_api_permission.py b/traffic_control/tests/test_responsible_entity_api_permission.py index b99dc9ed..3cb53fc5 100644 --- a/traffic_control/tests/test_responsible_entity_api_permission.py +++ b/traffic_control/tests/test_responsible_entity_api_permission.py @@ -11,6 +11,7 @@ get_responsible_entity_project, get_traffic_control_device_type, get_user, + TrafficSignPlanFactory, TrafficSignRealFactory, ) from traffic_control.tests.test_base_api_3d import test_point_3d @@ -59,6 +60,8 @@ def test__api_responsible_area_permission__create(model, add_to_responsible_enti data["road_name"] = "testroad" elif model == "AdditionalSignReal": data["parent"] = TrafficSignRealFactory().pk + elif model == "AdditionalSignPlan": + data["parent"] = TrafficSignPlanFactory().pk client = get_api_client(user=user) model_class = getattr(models, model) diff --git a/traffic_control/tests/test_source_name_source_id_api.py b/traffic_control/tests/test_source_name_source_id_api.py index b47002de..b6508d5f 100644 --- a/traffic_control/tests/test_source_name_source_id_api.py +++ b/traffic_control/tests/test_source_name_source_id_api.py @@ -21,7 +21,13 @@ TrafficSignPlan, TrafficSignReal, ) -from traffic_control.tests.factories import get_api_client, get_owner, get_user, TrafficSignRealFactory +from traffic_control.tests.factories import ( + get_api_client, + get_owner, + get_user, + TrafficSignPlanFactory, + TrafficSignRealFactory, +) from traffic_control.tests.test_base_api_3d import test_point_3d @@ -38,6 +44,7 @@ def get_data_create_additional_sign_plan(): return { "location": test_point_3d.ewkt, "owner": str(get_owner().id), + "parent": TrafficSignPlanFactory().pk, } diff --git a/traffic_control/tests/wfs/test_common_wfs.py b/traffic_control/tests/wfs/test_common_wfs.py index b50839c4..8f710a84 100644 --- a/traffic_control/tests/wfs/test_common_wfs.py +++ b/traffic_control/tests/wfs/test_common_wfs.py @@ -6,7 +6,7 @@ from traffic_control.models import AdditionalSignPlan, AdditionalSignReal, Plan, TrafficSignPlan, TrafficSignReal from traffic_control.tests.factories import ( AdditionalSignRealFactory, - get_additional_sign_plan, + get_additional_sign_plan_and_replace, get_traffic_sign_plan, PlanFactory, TrafficSignRealFactory, @@ -33,7 +33,13 @@ ( (TrafficSignPlan, "trafficsignplan", get_traffic_sign_plan, point_outside_bbox, point_inside_bbox), (TrafficSignReal, "trafficsignreal", TrafficSignRealFactory, point_outside_bbox, point_inside_bbox), - (AdditionalSignPlan, "additionalsignplan", get_additional_sign_plan, point_outside_bbox, point_inside_bbox), + ( + AdditionalSignPlan, + "additionalsignplan", + get_additional_sign_plan_and_replace, + point_outside_bbox, + point_inside_bbox, + ), (AdditionalSignReal, "additionalsignreal", AdditionalSignRealFactory, point_outside_bbox, point_inside_bbox), ( FurnitureSignpostPlan, @@ -94,7 +100,7 @@ def test__wfs__get_feature_bounding_box( "model, model_name, factory", ( (TrafficSignPlan, "trafficsignplan", get_traffic_sign_plan), - (AdditionalSignPlan, "additionalsignplan", get_additional_sign_plan), + (AdditionalSignPlan, "additionalsignplan", get_additional_sign_plan_and_replace), ), ) @pytest.mark.parametrize("output_format", ("gml", "geojson"))