[Fix] While saving project getting timeout error (#14672)
diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py
index 44b0c00..1f4bd00 100644
--- a/erpnext/projects/doctype/project/project.py
+++ b/erpnext/projects/doctype/project/project.py
@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
-from frappe.utils import flt, getdate, get_url
+from frappe.utils import flt, getdate, get_url, now
from frappe import _
from frappe.model.document import Document
@@ -60,6 +60,7 @@
self.validate_weights()
self.sync_tasks()
self.tasks = []
+ self.load_tasks()
self.send_welcome_email()
def validate_project_name(self):
@@ -83,36 +84,68 @@
"""sync tasks and remove table"""
if self.flags.dont_sync_tasks: return
task_names = []
+
+ existing_task_data = {}
+ for d in frappe.get_all('Project Task',
+ fields = ["title", "status", "start_date", "end_date", "description", "task_weight", "task_id"],
+ filters = {'parent': self.name}):
+ existing_task_data.setdefault(d.task_id, d)
+
for t in self.tasks:
if t.task_id:
task = frappe.get_doc("Task", t.task_id)
else:
task = frappe.new_doc("Task")
task.project = self.name
- task.update({
- "subject": t.title,
- "status": t.status,
- "exp_start_date": t.start_date,
- "exp_end_date": t.end_date,
- "description": t.description,
- "task_weight": t.task_weight
- })
- self.map_custom_fields(t, task)
+ if not t.task_id or self.is_row_updated(t, existing_task_data):
+ task.update({
+ "subject": t.title,
+ "status": t.status,
+ "exp_start_date": t.start_date,
+ "exp_end_date": t.end_date,
+ "description": t.description,
+ "task_weight": t.task_weight
+ })
- task.flags.ignore_links = True
- task.flags.from_project = True
- task.flags.ignore_feed = True
- task.save(ignore_permissions = True)
- task_names.append(task.name)
+ self.map_custom_fields(t, task)
+
+ task.flags.ignore_links = True
+ task.flags.from_project = True
+ task.flags.ignore_feed = True
+
+ if t.task_id:
+ task.update({
+ "modified_by": frappe.session.user,
+ "modified": now()
+ })
+
+ task.validate()
+ task.db_update()
+ else:
+ task.save(ignore_permissions = True)
+ task_names.append(task.name)
+ else:
+ task_names.append(task.name)
# delete
for t in frappe.get_all("Task", ["name"], {"project": self.name, "name": ("not in", task_names)}):
frappe.delete_doc("Task", t.name)
+ def update_costing_and_percentage_complete(self):
self.update_percent_complete()
self.update_costing()
+ def is_row_updated(self, row, existing_task_data):
+ if self.get("__islocal") or not existing_task_data: return True
+
+ d = existing_task_data.get(row.task_id)
+
+ if (d and (row.title != d.title or row.status != d.status
+ or getdate(row.start_date) != getdate(d.start_date) or getdate(row.end_date) != getdate(d.end_date)
+ or row.description != d.description or row.task_weight != d.task_weight)):
+ return True
+
def map_custom_fields(self, source, target):
project_task_custom_fields = frappe.get_all("Custom Field", {"dt": "Project Task"}, "fieldname")
@@ -207,6 +240,9 @@
self.total_billed_amount = total_billed_amount and total_billed_amount[0][0] or 0
+ def after_rename(self, old_name, new_name, merge=False):
+ if old_name == self.copied_from:
+ frappe.db.set_value('Project', new_name, 'copied_from', new_name)
def send_welcome_email(self):
url = get_url("/project/?name={0}".format(self.name))
@@ -227,8 +263,7 @@
user.welcome_email_sent=1
def on_update(self):
- self.load_tasks()
- self.sync_tasks()
+ self.update_costing_and_percentage_complete()
self.update_dependencies_on_duplicated_project()
def update_dependencies_on_duplicated_project(self):
@@ -251,9 +286,7 @@
continue
name = _task.name
- depends_on_tasks = _task.depends_on_tasks
- depends_on_tasks = [x for x in depends_on_tasks.split(',') if x]
dependency_map[task.title] = [ x['subject'] for x in frappe.get_list(
'Task Depends On', {"parent": name}, ['subject'])]
@@ -264,7 +297,8 @@
for dt in value:
dt_name = frappe.db.get_value('Task', {"subject": dt, "project": self.name })
task_doc.append('depends_on', {"task": dt_name})
- task_doc.save()
+
+ task_doc.update_db()
def get_timeline_data(doctype, name):
'''Return timeline for attendance'''
diff --git a/erpnext/projects/doctype/project_task/project_task.json b/erpnext/projects/doctype/project_task/project_task.json
index 79790e5..e5f28b7 100644
--- a/erpnext/projects/doctype/project_task/project_task.json
+++ b/erpnext/projects/doctype/project_task/project_task.json
@@ -371,7 +371,7 @@
"remember_last_selected_value": 1,
"report_hide": 0,
"reqd": 0,
- "search_index": 0,
+ "search_index": 1,
"set_only_once": 0,
"unique": 0
}
@@ -386,7 +386,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2017-12-19 14:49:15.886339",
+ "modified": "2018-06-26 11:46:50.890251",
"modified_by": "Administrator",
"module": "Projects",
"name": "Project Task",
diff --git a/erpnext/projects/doctype/task/task.json b/erpnext/projects/doctype/task/task.json
index 8e72d03..cf524da 100644
--- a/erpnext/projects/doctype/task/task.json
+++ b/erpnext/projects/doctype/task/task.json
@@ -38,7 +38,7 @@
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
- "search_index": 0,
+ "search_index": 1,
"set_only_once": 0,
"unique": 0
},
@@ -70,7 +70,7 @@
"remember_last_selected_value": 1,
"report_hide": 0,
"reqd": 0,
- "search_index": 0,
+ "search_index": 1,
"set_only_once": 0,
"unique": 0
},
@@ -1214,7 +1214,7 @@
"istable": 0,
"max_attachments": 5,
"menu_index": 0,
- "modified": "2017-11-10 18:37:19.660293",
+ "modified": "2018-06-26 11:46:06.678115",
"modified_by": "Administrator",
"module": "Projects",
"name": "Task",