diff --git a/taiga/projects/apps.py b/taiga/projects/apps.py index a57f2f5a..c3ef4df3 100644 --- a/taiga/projects/apps.py +++ b/taiga/projects/apps.py @@ -53,6 +53,18 @@ def connect_projects_signals(): dispatch_uid="update_project_tags_when_create_or_edit_taggable_item_projects") +def connect_us_status_signals(): + signals.post_save.connect(handlers.try_to_close_or_open_user_stories_when_edit_us_status, + sender=apps.get_model("projects", "UserStoryStatus"), + dispatch_uid="try_to_close_or_open_user_stories_when_edit_us_status") + + +def connect_task_status_signals(): + signals.post_save.connect(handlers.try_to_close_or_open_user_stories_when_edit_task_status, + sender=apps.get_model("projects", "TaskStatus"), + dispatch_uid="try_to_close_or_open_user_stories_when_edit_task_status") + + def disconnect_memberships_signals(): signals.pre_delete.disconnect(dispatch_uid='membership_pre_delete') signals.post_delete.disconnect(dispatch_uid='update_watchers_on_membership_post_delete') @@ -64,6 +76,12 @@ def disconnect_projects_signals(): signals.pre_save.disconnect(dispatch_uid="tags_normalization_projects") signals.pre_save.disconnect(dispatch_uid="update_project_tags_when_create_or_edit_taggable_item_projects") +def disconnect_us_status_signals(): + signals.post_save.disconnect(dispatch_uid="try_to_close_or_open_user_stories_when_edit_us_status") + +def disconnect_task_status_signals(): + signals.post_save.disconnect(dispatch_uid="try_to_close_or_open_user_stories_when_edit_task_status") + class ProjectsAppConfig(AppConfig): name = "taiga.projects" @@ -72,3 +90,5 @@ class ProjectsAppConfig(AppConfig): def ready(self): connect_memberships_signals() connect_projects_signals() + connect_us_status_signals() + connect_task_status_signals() diff --git a/taiga/projects/signals.py b/taiga/projects/signals.py index 61dd0709..f6cb0b1a 100644 --- a/taiga/projects/signals.py +++ b/taiga/projects/signals.py @@ -97,3 +97,25 @@ def project_post_save(sender, instance, created, **kwargs): Membership = apps.get_model("projects", "Membership") Membership.objects.create(user=instance.owner, project=instance, role=owner_role, is_owner=True, email=instance.owner.email) + + +def try_to_close_or_open_user_stories_when_edit_us_status(sender, instance, created, **kwargs): + from taiga.projects.userstories import services + + for user_story in instance.user_stories.all(): + if services.calculate_userstory_is_closed(user_story): + services.close_userstory(user_story) + else: + services.open_userstory(user_story) + + +def try_to_close_or_open_user_stories_when_edit_task_status(sender, instance, created, **kwargs): + from taiga.projects.userstories import services + + UserStory = apps.get_model("userstories", "UserStory") + + for user_story in UserStory.objects.filter(tasks__status=instance).distinct(): + if services.calculate_userstory_is_closed(user_story): + services.close_userstory(user_story) + else: + services.open_userstory(user_story) diff --git a/tests/integration/test_projects.py b/tests/integration/test_projects.py index 527b0d0e..45b7c96e 100644 --- a/tests/integration/test_projects.py +++ b/tests/integration/test_projects.py @@ -45,6 +45,46 @@ def test_partially_update_project(client): assert response.status_code == 400 +def test_us_status_is_closed_changed_recalc_us_is_closed(client): + us_status = f.UserStoryStatusFactory(is_closed=False) + user_story = f.UserStoryFactory.create(project=us_status.project, status=us_status) + + assert user_story.is_closed is False + + us_status.is_closed = True + us_status.save() + + user_story = user_story.__class__.objects.get(pk=user_story.pk) + assert user_story.is_closed is True + + us_status.is_closed = False + us_status.save() + + user_story = user_story.__class__.objects.get(pk=user_story.pk) + assert user_story.is_closed is False + + +def test_task_status_is_closed_changed_recalc_us_is_closed(client): + us_status = f.UserStoryStatusFactory() + user_story = f.UserStoryFactory.create(project=us_status.project, status=us_status) + task_status = f.TaskStatusFactory.create(project=us_status.project, is_closed=False) + task = f.TaskFactory.create(project=us_status.project, status=task_status, user_story=user_story) + + assert user_story.is_closed is False + + task_status.is_closed = True + task_status.save() + + user_story = user_story.__class__.objects.get(pk=user_story.pk) + assert user_story.is_closed is True + + task_status.is_closed = False + task_status.save() + + user_story = user_story.__class__.objects.get(pk=user_story.pk) + assert user_story.is_closed is False + + def test_us_status_slug_generation(client): us_status = f.UserStoryStatusFactory(name="NEW") f.MembershipFactory(user=us_status.project.owner, project=us_status.project, is_owner=True)