ФУНКЦИИ - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: дата старта для задач с дедлайном

This commit is contained in:
DCCONSTRUCTIONS 2026-04-25 10:34:27 +03:00
parent 4fe6d091e0
commit 21a9d2b809
5 changed files with 60 additions and 0 deletions

View File

@ -31,6 +31,7 @@ from plane.utils.content_validator import (
validate_html_content, validate_html_content,
validate_binary_data, validate_binary_data,
) )
from plane.utils.date_utils import set_default_issue_start_date
from .base import BaseSerializer from .base import BaseSerializer
from .cycle import CycleLiteSerializer, CycleSerializer from .cycle import CycleLiteSerializer, CycleSerializer
@ -73,6 +74,9 @@ class IssueSerializer(BaseSerializer):
exclude = ["description_json", "description_stripped"] exclude = ["description_json", "description_stripped"]
def validate(self, data): def validate(self, data):
if self.instance is None:
data = set_default_issue_start_date(data)
if ( if (
data.get("start_date", None) is not None data.get("start_date", None) is not None
and data.get("target_date", None) is not None and data.get("target_date", None) is not None

View File

@ -47,6 +47,7 @@ from plane.utils.content_validator import (
validate_html_content, validate_html_content,
validate_binary_data, validate_binary_data,
) )
from plane.utils.date_utils import set_default_issue_start_date
class IssueFlatSerializer(BaseSerializer): class IssueFlatSerializer(BaseSerializer):
@ -124,6 +125,9 @@ class IssueCreateSerializer(BaseSerializer):
allow_triage = self.context.get("allow_triage_state", False) allow_triage = self.context.get("allow_triage_state", False)
state_manager = State.triage_objects if allow_triage else State.objects state_manager = State.triage_objects if allow_triage else State.objects
if self.instance is None:
attrs = set_default_issue_start_date(attrs)
if ( if (
attrs.get("start_date", None) is not None attrs.get("start_date", None) is not None
and attrs.get("target_date", None) is not None and attrs.get("target_date", None) is not None

View File

@ -36,6 +36,7 @@ from plane.utils.content_validator import (
validate_html_content, validate_html_content,
validate_binary_data, validate_binary_data,
) )
from plane.utils.date_utils import set_default_issue_start_date
class IssueStateFlatSerializer(BaseSerializer): class IssueStateFlatSerializer(BaseSerializer):
@ -277,6 +278,9 @@ class IssueCreateSerializer(BaseSerializer):
return data return data
def validate(self, data): def validate(self, data):
if self.instance is None:
data = set_default_issue_start_date(data)
if ( if (
data.get("start_date", None) is not None data.get("start_date", None) is not None
and data.get("target_date", None) is not None and data.get("target_date", None) is not None

View File

@ -0,0 +1,38 @@
# Copyright (c) 2023-present Plane Software, Inc. and contributors
# SPDX-License-Identifier: AGPL-3.0-only
# See the LICENSE file for details.
from datetime import date
import pytest
from plane.utils.date_utils import set_default_issue_start_date
@pytest.mark.unit
class TestDefaultIssueStartDate:
def test_sets_today_for_future_target_date(self, monkeypatch):
monkeypatch.setattr("plane.utils.date_utils.timezone.localdate", lambda: date(2026, 4, 25))
attrs = set_default_issue_start_date({"target_date": date(2026, 5, 1)})
assert attrs["start_date"] == date(2026, 4, 25)
def test_preserves_explicit_start_date(self, monkeypatch):
monkeypatch.setattr("plane.utils.date_utils.timezone.localdate", lambda: date(2026, 4, 25))
attrs = set_default_issue_start_date(
{
"start_date": date(2026, 4, 20),
"target_date": date(2026, 5, 1),
}
)
assert attrs["start_date"] == date(2026, 4, 20)
def test_leaves_past_target_without_start_date(self, monkeypatch):
monkeypatch.setattr("plane.utils.date_utils.timezone.localdate", lambda: date(2026, 4, 25))
attrs = set_default_issue_start_date({"target_date": date(2026, 4, 20)})
assert "start_date" not in attrs

View File

@ -122,6 +122,16 @@ def get_chart_period_range(
return period_ranges.get(date_filter, None) return period_ranges.get(date_filter, None)
def set_default_issue_start_date(attrs: Dict[str, Any]) -> Dict[str, Any]:
target_date = attrs.get("target_date")
if attrs.get("start_date") is None and target_date is not None:
today = timezone.localdate()
if target_date >= today:
attrs["start_date"] = today
return attrs
def get_analytics_filters( def get_analytics_filters(
slug: str, slug: str,
user: User, user: User,