diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py
index 55be319d23e..cb971f13992 100755
--- a/erpnext/projects/doctype/task/task.py
+++ b/erpnext/projects/doctype/task/task.py
@@ -17,6 +17,10 @@ class CircularReferenceError(frappe.ValidationError):
pass
+class ParentIsGroupError(frappe.ValidationError):
+ pass
+
+
class Task(NestedSet):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
@@ -84,6 +88,7 @@ class Task(NestedSet):
self.validate_dependencies_for_template_task()
self.validate_completed_on()
self.set_default_end_date_if_missing()
+ self.validate_parent_is_group()
def validate_dates(self):
self.validate_from_to_dates("exp_start_date", "exp_end_date")
@@ -158,20 +163,36 @@ class Task(NestedSet):
def validate_parent_template_task(self):
if self.parent_task:
if not frappe.db.get_value("Task", self.parent_task, "is_template"):
- parent_task_format = f"""{self.parent_task}"""
- frappe.throw(_("Parent Task {0} is not a Template Task").format(parent_task_format))
+ frappe.throw(
+ _("Parent Task {0} is not a Template Task").format(
+ get_link_to_form("Task", self.parent_task)
+ )
+ )
def validate_depends_on_tasks(self):
if self.depends_on:
for task in self.depends_on:
if not frappe.db.get_value("Task", task.task, "is_template"):
- dependent_task_format = f"""{task.task}"""
- frappe.throw(_("Dependent Task {0} is not a Template Task").format(dependent_task_format))
+ frappe.throw(
+ _("Dependent Task {0} is not a Template Task").format(
+ get_link_to_form("Task", task.task)
+ )
+ )
def validate_completed_on(self):
if self.completed_on and getdate(self.completed_on) > getdate():
frappe.throw(_("Completed On cannot be greater than Today"))
+ def validate_parent_is_group(self):
+ if self.parent_task:
+ if not frappe.db.get_value("Task", self.parent_task, "is_group"):
+ frappe.throw(
+ _("Parent Task {0} must be a Group Task").format(
+ get_link_to_form("Task", self.parent_task)
+ ),
+ ParentIsGroupError,
+ )
+
def update_depends_on(self):
depends_on_tasks = ""
for d in self.depends_on:
diff --git a/erpnext/projects/doctype/task/test_task.py b/erpnext/projects/doctype/task/test_task.py
index 7a93585e832..d36272f9816 100644
--- a/erpnext/projects/doctype/task/test_task.py
+++ b/erpnext/projects/doctype/task/test_task.py
@@ -6,7 +6,7 @@ import frappe
from frappe.tests import IntegrationTestCase
from frappe.utils import add_days, getdate, nowdate
-from erpnext.projects.doctype.task.task import CircularReferenceError
+from erpnext.projects.doctype.task.task import CircularReferenceError, ParentIsGroupError
from erpnext.tests.utils import ERPNextTestSuite
@@ -119,6 +119,20 @@ class TestTask(ERPNextTestSuite):
self.assertEqual(frappe.db.get_value("Task", task.name, "status"), "Overdue")
+ def test_parent_task_must_be_group(self):
+ parent_task = create_task(
+ subject="_Test Parent Task Non Group",
+ is_group=0,
+ )
+
+ child_task = create_task(
+ subject="_Test Child Task",
+ parent_task=parent_task.name,
+ save=False,
+ )
+
+ self.assertRaises(ParentIsGroupError, child_task.save)
+
def create_task(
subject,