diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py index 448a59e98ff3..2e9fa5c9115f 100644 --- a/erpnext/projects/doctype/project/project.py +++ b/erpnext/projects/doctype/project/project.py @@ -101,30 +101,23 @@ def validate(self): self.validate_from_to_dates("actual_start_date", "actual_end_date") def copy_from_template(self): - """ - Copy tasks from template - """ - if self.project_template and not frappe.db.get_all("Task", dict(project=self.name), limit=1): - # has a template, and no loaded tasks, so lets create - if not self.expected_start_date: - # project starts today - self.expected_start_date = today() + self.copy_data_from_project_template() + self.copy_tasks_from_project_template() - template = frappe.get_doc("Project Template", self.project_template) - - if not self.project_type: - self.project_type = template.project_type + def copy_tasks_from_project_template(self): + if not self._project_template_applies(): + return - # create tasks from template - project_tasks = [] - tmp_task_details = [] - for task in template.tasks: - template_task_details = frappe.get_doc("Task", task.task) - tmp_task_details.append(template_task_details) - task = self.create_task_from_template(template_task_details) - project_tasks.append(task) + template = frappe.get_doc("Project Template", self.project_template) + project_tasks = [] + tmp_task_details = [] + for task in template.tasks: + template_task_details = frappe.get_doc("Task", task.task) + tmp_task_details.append(template_task_details) + task = self.create_task_from_template(template_task_details) + project_tasks.append(task) - self.dependency_mapping(tmp_task_details, project_tasks) + self.dependency_mapping(tmp_task_details, project_tasks) def create_task_from_template(self, task_details): return frappe.get_doc( @@ -146,6 +139,26 @@ def create_task_from_template(self, task_details): ) ).insert() + def copy_data_from_project_template(self): + if not self._project_template_applies(): + return + + if not self.expected_start_date: + self.expected_start_date = today() + + if not self.project_type: + self.project_type = frappe.db.get_value("Project Template", self.project_template, "project_type") + + def _project_template_applies(self) -> bool: + """Return True if the project template should be applied.""" + if not self.project_template: + return False + + if frappe.db.exists("Task", dict(project=self.name)): + return False + + return True + def calculate_start_date(self, task_details): self.start_date = add_days(self.expected_start_date, task_details.start) self.start_date = self.update_if_holiday(self.start_date) @@ -204,8 +217,11 @@ def update_project(self): self.update_costing() self.db_update() + def before_insert(self): + self.copy_data_from_project_template() + def after_insert(self): - self.copy_from_template() + self.copy_tasks_from_project_template() if self.sales_order: frappe.db.set_value("Sales Order", self.sales_order, "project", self.name) diff --git a/erpnext/projects/doctype/project/test_project.py b/erpnext/projects/doctype/project/test_project.py index 901f7beabf1d..a74114e661cc 100644 --- a/erpnext/projects/doctype/project/test_project.py +++ b/erpnext/projects/doctype/project/test_project.py @@ -3,7 +3,7 @@ import frappe from frappe.tests import IntegrationTestCase, UnitTestCase -from frappe.utils import add_days, getdate, nowdate +from frappe.utils import add_days, getdate, nowdate, today from erpnext.projects.doctype.project_template.test_project_template import make_project_template from erpnext.projects.doctype.task.test_task import create_task @@ -47,6 +47,9 @@ def test_project_with_template_having_no_parent_and_depend_tasks(self): order_by="creation asc", ) + self.assertEqual(project.project_type, "Internal") + self.assertEqual(project.expected_start_date, today()) + self.assertEqual(tasks[0].priority, "High") self.assertEqual(tasks[0].subject, "Test Template Task with No Parent and Dependency") self.assertEqual(getdate(tasks[0].exp_end_date), calculate_end_date(project, 5, 3)) @@ -98,6 +101,9 @@ def test_project_template_having_parent_child_tasks(self): order_by="creation asc", ) + self.assertEqual(project.project_type, "Internal") + self.assertEqual(project.expected_start_date, today()) + self.assertEqual(tasks[0].subject, "Test Template Task Parent") self.assertEqual(getdate(tasks[0].exp_end_date), calculate_end_date(project, 1, 10)) @@ -141,6 +147,9 @@ def test_project_template_having_dependent_tasks(self): order_by="creation asc", ) + self.assertEqual(project.project_type, "Internal") + self.assertEqual(project.expected_start_date, today()) + self.assertEqual(tasks[1].subject, "Test Template Task with Dependency") self.assertEqual(getdate(tasks[1].exp_end_date), calculate_end_date(project, 2, 2)) self.assertTrue(tasks[1].depends_on_tasks.find(tasks[0].name) >= 0) diff --git a/erpnext/projects/doctype/project_template/test_project_template.py b/erpnext/projects/doctype/project_template/test_project_template.py index 7d94e5226ca0..30b843bdb53e 100644 --- a/erpnext/projects/doctype/project_template/test_project_template.py +++ b/erpnext/projects/doctype/project_template/test_project_template.py @@ -20,7 +20,9 @@ def make_project_template(project_template_name, project_tasks=None): create_task(subject="_Test Template Task 1", is_template=1, begin=0, duration=3), create_task(subject="_Test Template Task 2", is_template=1, begin=0, duration=2), ] - doc = frappe.get_doc(dict(doctype="Project Template", name=project_template_name)) + doc = frappe.get_doc( + {"doctype": "Project Template", "name": project_template_name, "project_type": "Internal"} + ) for task in project_tasks: doc.append("tasks", {"task": task.name}) doc.insert()