Merge pull request #511 from taigaio/Issue/3448/finished-date-not-set-correctly-in-tasks
Setting finished date correctly on tasksremotes/origin/logger
commit
25e0dc91a4
|
@ -33,6 +33,7 @@ from taiga.base.api.mixins import CreateModelMixin
|
||||||
from taiga.base.api.viewsets import GenericViewSet
|
from taiga.base.api.viewsets import GenericViewSet
|
||||||
from taiga.projects.models import Project, Membership
|
from taiga.projects.models import Project, Membership
|
||||||
from taiga.projects.issues.models import Issue
|
from taiga.projects.issues.models import Issue
|
||||||
|
from taiga.projects.tasks.models import Task
|
||||||
from taiga.projects.serializers import ProjectSerializer
|
from taiga.projects.serializers import ProjectSerializer
|
||||||
|
|
||||||
from . import mixins
|
from . import mixins
|
||||||
|
@ -238,6 +239,9 @@ class ProjectImporterViewSet(mixins.ImportThrottlingPolicyMixin, CreateModelMixi
|
||||||
project = self.get_object_or_none()
|
project = self.get_object_or_none()
|
||||||
self.check_permissions(request, 'import_item', project)
|
self.check_permissions(request, 'import_item', project)
|
||||||
|
|
||||||
|
signals.pre_save.disconnect(sender=Task,
|
||||||
|
dispatch_uid="set_finished_date_when_edit_task")
|
||||||
|
|
||||||
task = service.store_task(project, request.DATA.copy())
|
task = service.store_task(project, request.DATA.copy())
|
||||||
|
|
||||||
errors = service.get_errors()
|
errors = service.get_errors()
|
||||||
|
|
|
@ -23,6 +23,10 @@ from taiga.projects.custom_attributes import signals as custom_attributes_handle
|
||||||
from . import signals as handlers
|
from . import signals as handlers
|
||||||
|
|
||||||
def connect_tasks_signals():
|
def connect_tasks_signals():
|
||||||
|
# Finished date
|
||||||
|
signals.pre_save.connect(handlers.set_finished_date_when_edit_task,
|
||||||
|
sender=apps.get_model("tasks", "Task"),
|
||||||
|
dispatch_uid="set_finished_date_when_edit_task")
|
||||||
# Tags
|
# Tags
|
||||||
signals.pre_save.connect(generic_handlers.tags_normalization,
|
signals.pre_save.connect(generic_handlers.tags_normalization,
|
||||||
sender=apps.get_model("tasks", "Task"),
|
sender=apps.get_model("tasks", "Task"),
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import connection, migrations, models
|
||||||
|
|
||||||
|
def set_finished_date_for_tasks(apps, schema_editor):
|
||||||
|
# Updates the finished date from tasks according to the history_entries associated
|
||||||
|
# It takes the last history change updateing the status of a task and if it's a closed
|
||||||
|
# one it updates the finished_date attribute
|
||||||
|
sql="""
|
||||||
|
WITH status_update AS(
|
||||||
|
WITH status_update AS(
|
||||||
|
WITH history_entries AS (
|
||||||
|
SELECT
|
||||||
|
diff#>>'{status, 1}' new_status_id,
|
||||||
|
regexp_split_to_array(key, ':') as split_key,
|
||||||
|
created_at as date
|
||||||
|
FROM history_historyentry
|
||||||
|
WHERE diff#>>'{status, 1}' != ''
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
split_key[2] as object_id,
|
||||||
|
new_status_id::int,
|
||||||
|
MAX(date) as status_change_datetime
|
||||||
|
FROM history_entries
|
||||||
|
WHERE split_key[1] = 'tasks.task'
|
||||||
|
GROUP BY object_id, new_status_id, date
|
||||||
|
)
|
||||||
|
SELECT status_update.*
|
||||||
|
FROM status_update
|
||||||
|
INNER JOIN projects_taskstatus
|
||||||
|
ON projects_taskstatus.id = new_status_id AND projects_taskstatus.is_closed = True
|
||||||
|
)
|
||||||
|
UPDATE tasks_task
|
||||||
|
SET finished_date = status_update.status_change_datetime
|
||||||
|
FROM status_update
|
||||||
|
WHERE tasks_task.id = status_update.object_id::int
|
||||||
|
"""
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute(sql)
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('tasks', '0008_remove_task_watchers'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(set_finished_date_for_tasks),
|
||||||
|
]
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
####################################
|
####################################
|
||||||
# Signals for cached prev task
|
# Signals for cached prev task
|
||||||
|
@ -92,3 +93,13 @@ def _try_to_close_milestone_when_delete_task(instance):
|
||||||
with suppress(ObjectDoesNotExist):
|
with suppress(ObjectDoesNotExist):
|
||||||
if instance.milestone_id and services.calculate_milestone_is_closed(instance.milestone):
|
if instance.milestone_id and services.calculate_milestone_is_closed(instance.milestone):
|
||||||
services.close_milestone(instance.milestone)
|
services.close_milestone(instance.milestone)
|
||||||
|
|
||||||
|
####################################
|
||||||
|
# Signals for set finished date
|
||||||
|
####################################
|
||||||
|
|
||||||
|
def set_finished_date_when_edit_task(sender, instance, **kwargs):
|
||||||
|
if instance.status.is_closed and not instance.finished_date:
|
||||||
|
instance.finished_date = timezone.now()
|
||||||
|
elif not instance.status.is_closed and instance.finished_date:
|
||||||
|
instance.finished_date = None
|
||||||
|
|
Loading…
Reference in New Issue