Visibility of dependent tasks

Hello, I’ve looked thoroughly for this but couldn’t find a solution, or even a discussion regarding this.
I have the following project-task structure

Each task is dependent on the one higher, so in short;

To complete a project: Tasks Z, X, V must be completed
To complete Task Z: Tasks Z.1 and Z.2 must be completed
To complete Task Z.1: Tasks Z.1.A, Z.1.B, Z.1.C must be completed
To complete Task Z.1.C: Task Z.1.A and Z.1.B must be completed
To complete Task Z.1.B: Task Z.1.A must be completed
and so on…

In our scenario every project consists of 200+ tasks, and displaying all of them in the task list is kind of overwhelming and confusing specially when we have 4 or 5 different projects.

If a task is dependent on another, and the other is not completed, then it shouldn’t show up (atleast in filtered view).

What I’m thinking is having two different task status/states which are open/closed and a task automatically changes from closed to open once the prerequisite has been completed.
Then I can create a filtered view to only show “open” tasks

What is the best approach to handle this? Are there any alternative methods to achieve my goal?

Using ERPNext V13, Hosted on Frappe Cloud.

Any assistance is appreciated,
Thank you!

3 Likes

The list view doesn’t provide much for complex queries, so I think you’re right that the best way to do this is to create a custom field in the task doctype called Ready (or whatever). Then, you’d just have to hook the before_save event via a server script or custom class and check the doc against its parent (or against its children if it is a parent).

In v14, virtual fields might be interesting to use here, though I haven’t used them enough yet to know if they’d fit this scenario.

1 Like

for the parent tasks, you can use the group child table and check if all child tasks are completed.
and for the depends on tasks you can make a child table to add all the depends on tasks, but you said that there might be more than 200 tasks. Hence, it is tough to insert them all, so the best solution is to make a series or index field and can make it auto-increment depending on the parent task to make the task as complete you need to approve all previous indexes.

1 Like

Thank you!
I actually went with what peterg recommended,
So for anyone that might need this,

Incases where you have multiple dependent tasks like this, and one task opens the other

The following list view might be overwhelming specially when only Child Task 1 can be worked on


So we can filter it to look like this,

Once a task is completed, the following task will automatically open.

To do this,

  1. Start by customizing the Task Doctype

Create a new Select Field
Name: actual_task_status
Options: Open, Closed
Enable Read Only

  1. Create a Client Script – Apply to Tasks Form
frappe.ui.form.on('Task Depends On', {
	task(frm) {
		if(frm.doc.depends_on)
		    frm.set_value('actual_task_status','Closed')
		else
		    frm.set_value('actual_task_status','Open')
		return True
	}
});

frappe.ui.form.on('Task', {
	is_group(frm) {
		if(frm.doc.is_group)
		    frm.set_value('actual_task_status','Closed')
		else
		    frm.set_value('actual_task_status','Open')
	}
});
frappe.ui.form.on('Task', {
	status(frm) {
		if(frm.doc.status=='Completed' || frm.doc.status=='Template' || frm.doc.status=='Cancelled' )
		    frm.set_value('actual_task_status','Closed')
		else
		    frm.set_value('actual_task_status','Open')
	}
});
  1. Create a Before_Save Server Script on Task
if doc.name and doc.status=='Template':
    doc.actual_task_status='Closed'

if doc.name and doc.status=='Cancelled':
    doc.actual_task_status='Closed'

if doc.name and doc.status=='Completed':
    doc.actual_task_status='Closed'
    tasks = frappe.get_list('Task Depends On',filters={'task':doc.name},fields=['task','parent'])
    for task in tasks:
        if task.parent!=doc.parent_task:
            depend_tasks = frappe.get_list('Task Depends On',filters={'parent':task.parent},fields=['task','parent'])
            check = True
            for dt in depend_tasks:
                if dt.task!=task.task and frappe.db.get_value('Task',{'name',dt.task},'status')!='Completed':
                    check=False
                    break
            if check:
                dd=frappe.get_doc('Task',task.parent)
                dd.actual_task_status='Open'
                dd.save()
                del dd
    if doc.parent_task:
        depend_tasks = frappe.get_list('Task Depends On',filters=dict({ 'parent':doc.parent_task }),fields=['task','parent'])
        check = True
        for dt in depend_tasks:
            if dt.task!=task.task and frappe.db.get_value('Task',dt.task,'status')!='Completed':
                check=False
                break
        if check:
            dd=frappe.get_doc('Task',doc.parent_task)
            dd.actual_task_status='Open'
            dd.save()
            del dd
elif doc.get("__islocal") and (doc.depends_on or doc.depends_on_tasks or doc.is_group or doc.status=='Completed' or doc.status=='Template' or doc.status=='Cancelled'):
        doc.actual_task_status='Closed'
  1. Create a After_Save Server Script on Task
if doc.name and doc.status=='Open':
    depend_tasks = frappe.get_list('Task Depends On',filters={'parent':doc.name},fields=['task','parent'])
    if depend_tasks:
        doc.actual_task_status='Closed'

Tested on both manual task creation and tasks made via project template.
For custom workflows, make sure the end state changes the “status” field to “completed

4 Likes

Just an update for this,
The above scenario only works for tasks with tree relationships.

In case you would like to add this functionality to tasks with child/parent relationships as well as dependent tasks that are not otherwise related to each other;

  1. Start by customizing the Task Doctype

Create a new Select Field
Name: actual_task_status
Options: Open, Closed
Enable Read Only

  1. Create a Client Script - Apply to Tasks form
frappe.ui.form.on('Task Depends On', {
	task(frm) {
		if(frm.doc.depends_on)
		    frm.set_value('actual_task_status','Closed')
		else
		    frm.set_value('actual_task_status','Open')
		return True
	}
});

frappe.ui.form.on('Task', {
	is_group(frm) {
		if(frm.doc.is_group)
		    frm.set_value('actual_task_status','Closed')
		else
		    frm.set_value('actual_task_status','Open')
	}
});
frappe.ui.form.on('Task', {
	status(frm) {
		if(frm.doc.status=='Completed' || frm.doc.status=='Template' || frm.doc.status=='Cancelled' )
		    frm.set_value('actual_task_status','Closed')
		else
		    frm.set_value('actual_task_status','Open')
	}
});
  1. Create a Before_Save Server Script on Task
if doc.name and doc.status=='Completed':
    doc.actual_task_status='Closed'
    tasks = frappe.get_list('Task Depends On',filters={'task':doc.name},fields=['task','parent'])
    for task in tasks:
        if task.parent!=doc.parent_task:
            depend_tasks = frappe.get_list('Task Depends On',filters={'parent':task.parent},fields=['task','parent'])
            check = True
            for dt in depend_tasks:
                if dt.task!=task.task and frappe.db.get_value('Task',{'name',dt.task},'status')!='Completed':
                    check=False
                    break
            if check:
                dd=frappe.get_doc('Task',task.parent)
                dd.actual_task_status='Open'
                dd.save()
                del dd
    if doc.parent_task:
        depend_tasks = frappe.get_list('Task Depends On',filters=dict({ 'parent':doc.parent_task }),fields=['task','parent'])
        check = True
        for dt in depend_tasks:
            if dt.task!=task.task and frappe.db.get_value('Task',dt.task,'status')!='Completed':
                check=False
                break
        if check:
            dd=frappe.get_doc('Task',doc.parent_task)
            dd.actual_task_status='Open'
            dd.save()
            del dd
elif doc.get("__islocal") and '*' in doc.subject:
    doc.actual_task_status='Open'

Example:
image


Note: This solution might not be the best as it involves one manual step which is adding a special symbol to the starting task subject (the one that should be open).
You can change this symbol to your liking by modifying this part of the server script.

elif doc.get("__islocal") and '*' in doc.subject: doc.actual_task_status='Open'

This works for any method of task creation (manual/via project template) and works properly with custom workflows (as long as the last state changes task status to “Complete”)

3 Likes