diff --git a/README.md b/README.md index f3c752c2..f99c51b7 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ python manage.py loaddata initial_role python manage.py sample_data ``` -Taiga only runs with python 3.3+. +Taiga only runs with python 3.4+ Initial auth data: admin/123123 diff --git a/taiga/projects/tasks/signals.py b/taiga/projects/tasks/signals.py index cbc633d1..03e65ddd 100644 --- a/taiga/projects/tasks/signals.py +++ b/taiga/projects/tasks/signals.py @@ -14,6 +14,8 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +from contextlib import suppress +from django.core.exceptions import ObjectDoesNotExist #################################### # Signals for cached prev task @@ -84,7 +86,8 @@ def _try_to_close_or_open_milestone_when_create_or_edit_task(instance): def _try_to_close_milestone_when_delete_task(instance): - from taiga.projects.milestones import services as milestone_service + from taiga.projects.milestones import services - if instance.milestone_id and milestone_service.calculate_milestone_is_closed(instance.milestone): - milestone_service.close_milestone(instance.milestone) + with suppress(ObjectDoesNotExist): + if instance.milestone_id and services.calculate_milestone_is_closed(instance.milestone): + services.close_milestone(instance.milestone) diff --git a/tests/integration/test_close_uss.py b/tests/integration/test_close_uss.py index 64f515d8..992f30de 100644 --- a/tests/integration/test_close_uss.py +++ b/tests/integration/test_close_uss.py @@ -15,12 +15,13 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from tests import factories as f - -from taiga.projects.userstories.models import UserStory import pytest +from taiga.projects.userstories.models import UserStory +from taiga.projects.tasks.models import Task + +from tests import factories as f pytestmark = pytest.mark.django_db @@ -191,7 +192,33 @@ def test_us_delete_task_then_all_closed(data): assert data.user_story1.is_closed is True -def test_us_change_task_us_then_all_closed(data): +def test_auto_close_userstory_with_milestone_when_task_and_milestone_are_removed(data): + milestone = f.MilestoneFactory.create() + + data.task1.status = data.task_closed_status + data.task1.milestone = milestone + data.task1.save() + data.task2.status = data.task_closed_status + data.task2.milestone = milestone + data.task2.save() + data.task3.status = data.task_open_status + data.task3.milestone = milestone + data.task3.save() + data.user_story1.milestone = milestone + data.user_story1.save() + + data.user_story1 = UserStory.objects.get(pk=data.user_story1.pk) + assert data.user_story1.is_closed is False + + data.task3 = Task.objects.get(pk=data.task3.pk) + milestone.delete() + data.task3.delete() + + data.user_story1 = UserStory.objects.get(pk=data.user_story1.pk) + assert data.user_story1.is_closed is False + + +def test_auto_close_us_when_all_tasks_are_changed_to_close_status(data): data.task1.status = data.task_closed_status data.task1.save() data.task2.status = data.task_closed_status