multiple dependant tasks added

This commit is contained in:
Neil Trini Lasrado 2015-04-30 20:32:42 +05:30
parent b3b373d0ac
commit b4a298ddd4
10 changed files with 257 additions and 66 deletions

View File

@ -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"
}

View File

@ -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

View File

@ -40,6 +40,7 @@ erpnext.projects.Task = frappe.ui.form.Controller.extend({
} }
}); });
cur_frm.add_fetch('task', 'subject', 'subject');
cur_frm.cscript = new erpnext.projects.Task({frm: cur_frm}); cur_frm.cscript = new erpnext.projects.Task({frm: cur_frm});

View File

@ -27,14 +27,6 @@
"options": "Project", "options": "Project",
"permlevel": 0 "permlevel": 0
}, },
{
"fieldname": "depends_on",
"fieldtype": "Link",
"label": "Depends on (Task)",
"options": "Task",
"permlevel": 0,
"precision": ""
},
{ {
"fieldname": "column_break0", "fieldname": "column_break0",
"fieldtype": "Column Break", "fieldtype": "Column Break",
@ -86,12 +78,26 @@
"width": "300px" "width": "300px"
}, },
{ {
"fieldname": "time_and_budget", "fieldname": "section_break",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "", "label": "Depends On",
"oldfieldtype": "Section Break", "oldfieldtype": "Section Break",
"permlevel": 0 "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", "fieldname": "exp_start_date",
"fieldtype": "Date", "fieldtype": "Date",
@ -257,7 +263,7 @@
"idx": 1, "idx": 1,
"istable": 0, "istable": 0,
"max_attachments": 5, "max_attachments": 5,
"modified": "2015-04-22 04:58:30.865304", "modified": "2015-04-30 05:48:55.176993",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Projects", "module": "Projects",
"name": "Task", "name": "Task",

View File

@ -4,7 +4,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe, json 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 import _
from frappe.model.document import Document from frappe.model.document import Document
@ -28,8 +28,6 @@ class Task(Document):
def validate(self): def validate(self):
self.validate_dates() self.validate_dates()
self.validate_depends_on()
self.reschedule_dependent_task()
def validate_dates(self): 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): 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 @@ class Task(Document):
frappe.throw(_("'Actual Start Date' can not be greater than 'Actual End Date'")) frappe.throw(_("'Actual Start Date' can not be greater than 'Actual End Date'"))
def on_update(self): def on_update(self):
self.check_recursion()
self.reschedule_dependent_tasks()
self.update_percentage() self.update_percentage()
self.update_project() self.update_project()
@ -72,30 +72,34 @@ class Task(Document):
project.update_costing() project.update_costing()
project.save() project.save()
def validate_depends_on(self): def check_recursion(self):
if not self.depends_on: if self.flags.recursion_check: return
return check_list = [['task', 'parent'], ['parent', 'task']]
task_list = [self.name] for d in check_list:
task = self.depends_on task_list, count = [self.name], 0
while task: while (len(task_list) > count ):
task = self.check_recursion(task, task_list) 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): def reschedule_dependent_tasks(self):
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):
end_date = self.exp_end_date or self.act_end_date end_date = self.exp_end_date or self.act_end_date
if 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) 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" : 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_duration = date_diff(task.exp_end_date, task.exp_start_date)
task.exp_start_date = add_days(end_date, 1) task.exp_start_date = add_days(end_date, 1)
task.exp_end_date = add_days(task.exp_start_date, task_duration) task.exp_end_date = add_days(task.exp_start_date, task_duration)
task.flags.recursion_check = True
task.save() task.save()
@frappe.whitelist() @frappe.whitelist()

View File

@ -5,45 +5,17 @@ import frappe
import unittest import unittest
from frappe.utils import getdate 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 from erpnext.projects.doctype.task.task import CircularReferenceError
class TestTask(unittest.TestCase): class TestTask(unittest.TestCase):
def test_circular_refereence(self): def test_circular_reference(self):
task1 = frappe.new_doc('Task') task1 = frappe.new_doc('Task')
task1.update({ task1.update({
"status": "Open", "status": "Open",
"subject": "_Test Task 3" "subject": "_Test Task 1",
})
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",
"exp_start_date": "2015-1-1", "exp_start_date": "2015-1-1",
"exp_end_date": "2015-1-10" "exp_end_date": "2015-1-10"
}) })
@ -52,20 +24,92 @@ class TestTask(unittest.TestCase):
task2 = frappe.new_doc('Task') task2 = frappe.new_doc('Task')
task2.update({ task2.update({
"status": "Open", "status": "Open",
"subject": "_Test Task 7", "subject": "_Test Task 2",
"exp_start_date": "2015-1-11", "exp_start_date": "2015-1-11",
"exp_end_date": "2015-1-15", "exp_end_date": "2015-1-15",
"depends_on": task1.name "depends_on":[
{
"task": task1.name
}
]
}) })
task2.save() task2.save()
task3 = frappe.new_doc('Task') task3 = frappe.new_doc('Task')
task3.update({ task3.update({
"status": "Open", "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_start_date": "2015-1-16",
"exp_end_date": "2015-1-18", "exp_end_date": "2015-1-18",
"depends_on": task2.name "depends_on":[
{
"task": task2.name
}
]
}) })
task3.save() task3.save()

View File

@ -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"
}

View File

@ -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