multiple dependant tasks added
diff --git a/erpnext/projects/doctype/dependent_task/__init__.py b/erpnext/projects/doctype/dependent_task/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/projects/doctype/dependent_task/__init__.py
diff --git a/erpnext/projects/doctype/dependent_task/dependent_task.json b/erpnext/projects/doctype/dependent_task/dependent_task.json
new file mode 100644
index 0000000..c649b53
--- /dev/null
+++ b/erpnext/projects/doctype/dependent_task/dependent_task.json
@@ -0,0 +1,50 @@
+{
+ "allow_copy": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "creation": "2015-04-29 04:52:48.868079",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "fields": [
+ {
+ "allow_on_submit": 0,
+ "fieldname": "task",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "label": "Task",
+ "no_copy": 0,
+ "options": "Task",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0
+ }
+ ],
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "in_create": 0,
+ "in_dialog": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 1,
+ "modified": "2015-04-29 04:54:36.024844",
+ "modified_by": "Administrator",
+ "module": "Projects",
+ "name": "Dependent Task",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "read_only": 0,
+ "read_only_onload": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC"
+}
\ No newline at end of file
diff --git a/erpnext/projects/doctype/dependent_task/dependent_task.py b/erpnext/projects/doctype/dependent_task/dependent_task.py
new file mode 100644
index 0000000..90a96ac
--- /dev/null
+++ b/erpnext/projects/doctype/dependent_task/dependent_task.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class DependentTask(Document):
+ pass
diff --git a/erpnext/projects/doctype/task/task.js b/erpnext/projects/doctype/task/task.js
index 9756331..d9a611e 100644
--- a/erpnext/projects/doctype/task/task.js
+++ b/erpnext/projects/doctype/task/task.js
@@ -40,6 +40,7 @@
}
});
+cur_frm.add_fetch('task', 'subject', 'subject');
cur_frm.cscript = new erpnext.projects.Task({frm: cur_frm});
diff --git a/erpnext/projects/doctype/task/task.json b/erpnext/projects/doctype/task/task.json
index ad1ad01..ddcc48b 100644
--- a/erpnext/projects/doctype/task/task.json
+++ b/erpnext/projects/doctype/task/task.json
@@ -28,14 +28,6 @@
"permlevel": 0
},
{
- "fieldname": "depends_on",
- "fieldtype": "Link",
- "label": "Depends on (Task)",
- "options": "Task",
- "permlevel": 0,
- "precision": ""
- },
- {
"fieldname": "column_break0",
"fieldtype": "Column Break",
"oldfieldtype": "Column Break",
@@ -86,13 +78,27 @@
"width": "300px"
},
{
- "fieldname": "time_and_budget",
+ "fieldname": "section_break",
"fieldtype": "Section Break",
- "label": "",
+ "label": "Depends On",
"oldfieldtype": "Section Break",
"permlevel": 0
},
{
+ "fieldname": "depends_on",
+ "fieldtype": "Table",
+ "label": "depends_on",
+ "options": "Task Depends On",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
+ "fieldname": "section_break_10",
+ "fieldtype": "Section Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
"fieldname": "exp_start_date",
"fieldtype": "Date",
"label": "Expected Start Date",
@@ -257,7 +263,7 @@
"idx": 1,
"istable": 0,
"max_attachments": 5,
- "modified": "2015-04-22 04:58:30.865304",
+ "modified": "2015-04-30 05:48:55.176993",
"modified_by": "Administrator",
"module": "Projects",
"name": "Task",
diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py
index cde23e7..a232be1 100644
--- a/erpnext/projects/doctype/task/task.py
+++ b/erpnext/projects/doctype/task/task.py
@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe, json
-from frappe.utils import getdate, date_diff, add_days
+from frappe.utils import getdate, date_diff, add_days, cstr
from frappe import _
from frappe.model.document import Document
@@ -28,8 +28,6 @@
def validate(self):
self.validate_dates()
- self.validate_depends_on()
- self.reschedule_dependent_task()
def validate_dates(self):
if self.exp_start_date and self.exp_end_date and getdate(self.exp_start_date) > getdate(self.exp_end_date):
@@ -39,6 +37,8 @@
frappe.throw(_("'Actual Start Date' can not be greater than 'Actual End Date'"))
def on_update(self):
+ self.check_recursion()
+ self.reschedule_dependent_tasks()
self.update_percentage()
self.update_project()
@@ -72,30 +72,34 @@
project.update_costing()
project.save()
- def validate_depends_on(self):
- if not self.depends_on:
- return
- task_list = [self.name]
- task = self.depends_on
- while task:
- task = self.check_recursion(task, task_list)
+ def check_recursion(self):
+ if self.flags.recursion_check: return
+ check_list = [['task', 'parent'], ['parent', 'task']]
+ for d in check_list:
+ task_list, count = [self.name], 0
+ while (len(task_list) > count ):
+ tasks = frappe.db.sql(" select %s from `tabTask Depends On` where %s = %s " %
+ (d[0], d[1], '%s'), cstr(task_list[count]))
+ count = count + 1
+ for b in tasks:
+ if b[0] == self.name:
+ frappe.throw(_("Circular Reference Error"), CircularReferenceError)
+ if b[0]:
+ task_list.append(b[0])
+ if count == 15:
+ break
- def check_recursion(self, task, task_list):
- if task in task_list:
- frappe.throw("Circular Reference Error", CircularReferenceError)
- else :
- task_list.append(task)
- return frappe.db.get_value("Task", task, "depends_on")
-
- def reschedule_dependent_task(self):
+ def reschedule_dependent_tasks(self):
end_date = self.exp_end_date or self.act_end_date
if end_date:
- for task_name in frappe.db.sql("select name from `tabTask` where depends_on = %s", self.name, as_dict=1):
+ for task_name in frappe.db.sql("select name from `tabTask` as parent where %s in \
+ (select task from `tabTask Depends On` as child where parent.name = child.parent )", self.name, as_dict=1):
task = frappe.get_doc("Task", task_name.name)
if task.exp_start_date and task.exp_end_date and task.exp_start_date < getdate(end_date) and task.status == "Open" :
task_duration = date_diff(task.exp_end_date, task.exp_start_date)
task.exp_start_date = add_days(end_date, 1)
task.exp_end_date = add_days(task.exp_start_date, task_duration)
+ task.flags.recursion_check = True
task.save()
@frappe.whitelist()
diff --git a/erpnext/projects/doctype/task/test_task.py b/erpnext/projects/doctype/task/test_task.py
index aea6a25..8880763 100644
--- a/erpnext/projects/doctype/task/test_task.py
+++ b/erpnext/projects/doctype/task/test_task.py
@@ -5,45 +5,17 @@
import unittest
from frappe.utils import getdate
-test_records = frappe.get_test_records('Task')
+# test_records = frappe.get_test_records('Task')
from erpnext.projects.doctype.task.task import CircularReferenceError
class TestTask(unittest.TestCase):
- def test_circular_refereence(self):
+ def test_circular_reference(self):
+
task1 = frappe.new_doc('Task')
task1.update({
"status": "Open",
- "subject": "_Test Task 3"
- })
- task1.save()
-
- task2 = frappe.new_doc('Task')
- task2.update({
- "status": "Open",
- "subject": "_Test Task 4",
- "depends_on": task1.name
- })
- task2.save()
-
- task3 = frappe.new_doc('Task')
- task3.update({
- "status": "Open",
- "subject": "_Test Task 5",
- "depends_on": task2.name
- })
- task3.save()
-
- task1.update({
- "depends_on": task3.name
- })
- self.assertRaises(CircularReferenceError, task1.save)
-
- def test_reschedule_dependent_task(self):
- task1 = frappe.new_doc('Task')
- task1.update({
- "status": "Open",
- "subject": "_Test Task 6",
+ "subject": "_Test Task 1",
"exp_start_date": "2015-1-1",
"exp_end_date": "2015-1-10"
})
@@ -52,20 +24,92 @@
task2 = frappe.new_doc('Task')
task2.update({
"status": "Open",
- "subject": "_Test Task 7",
+ "subject": "_Test Task 2",
"exp_start_date": "2015-1-11",
"exp_end_date": "2015-1-15",
- "depends_on": task1.name
+ "depends_on":[
+ {
+ "task": task1.name
+ }
+ ]
})
task2.save()
task3 = frappe.new_doc('Task')
task3.update({
"status": "Open",
- "subject": "_Test Task 5",
+ "subject": "_Test Task 2",
+ "exp_start_date": "2015-1-11",
+ "exp_end_date": "2015-1-15",
+ "depends_on":[
+ {
+ "task": task2.name
+ }
+ ]
+ })
+ task3.save()
+
+ task1.append("depends_on", {
+ "task": task3.name
+ })
+ self.assertRaises(CircularReferenceError, task1.save)
+
+ task1.set("depends_on", [])
+ task1.save()
+
+ task4 = frappe.new_doc('Task')
+ task4.update({
+ "status": "Open",
+ "subject": "_Test Task 1",
+ "exp_start_date": "2015-1-1",
+ "exp_end_date": "2015-1-15",
+ "depends_on":[
+ {
+ "task": task1.name
+ }
+ ]
+ })
+ task4.save()
+
+ task3.append("depends_on", {
+ "task": task4.name
+ })
+
+ def test_reschedule_dependent_task(self):
+ task1 = frappe.new_doc('Task')
+ task1.update({
+ "status": "Open",
+ "subject": "_Test Task 1",
+ "exp_start_date": "2015-1-1",
+ "exp_end_date": "2015-1-10"
+ })
+ task1.save()
+
+ task2 = frappe.new_doc('Task')
+ task2.update({
+ "status": "Open",
+ "subject": "_Test Task 2",
+ "exp_start_date": "2015-1-11",
+ "exp_end_date": "2015-1-15",
+ "depends_on":[
+ {
+ "task": task1.name
+ }
+ ]
+ })
+ task2.save()
+
+ task3 = frappe.new_doc('Task')
+ task3.update({
+ "status": "Open",
+ "subject": "_Test Task 3",
"exp_start_date": "2015-1-16",
"exp_end_date": "2015-1-18",
- "depends_on": task2.name
+ "depends_on":[
+ {
+ "task": task2.name
+ }
+ ]
})
task3.save()
diff --git a/erpnext/projects/doctype/task_depends_on/__init__.py b/erpnext/projects/doctype/task_depends_on/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/projects/doctype/task_depends_on/__init__.py
diff --git a/erpnext/projects/doctype/task_depends_on/task_depends_on.json b/erpnext/projects/doctype/task_depends_on/task_depends_on.json
new file mode 100644
index 0000000..7a960c1
--- /dev/null
+++ b/erpnext/projects/doctype/task_depends_on/task_depends_on.json
@@ -0,0 +1,66 @@
+{
+ "allow_copy": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "creation": "2015-04-29 04:52:48.868079",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "fields": [
+ {
+ "allow_on_submit": 0,
+ "fieldname": "task",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "label": "Task",
+ "no_copy": 0,
+ "options": "Task",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0
+ },
+ {
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
+ "fieldname": "subject",
+ "fieldtype": "Text",
+ "in_list_view": 1,
+ "label": "Subject",
+ "options": "",
+ "permlevel": 0,
+ "precision": "",
+ "read_only": 1
+ }
+ ],
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "in_create": 0,
+ "in_dialog": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 1,
+ "modified": "2015-04-30 05:52:16.250948",
+ "modified_by": "Administrator",
+ "module": "Projects",
+ "name": "Task Depends On",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "read_only": 0,
+ "read_only_onload": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC"
+}
\ No newline at end of file
diff --git a/erpnext/projects/doctype/task_depends_on/task_depends_on.py b/erpnext/projects/doctype/task_depends_on/task_depends_on.py
new file mode 100644
index 0000000..723a0fc
--- /dev/null
+++ b/erpnext/projects/doctype/task_depends_on/task_depends_on.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class TaskDependsOn(Document):
+ pass