From d104d8e723baafa12c4e634d82e704996b3826f0 Mon Sep 17 00:00:00 2001 From: Poovetha Date: Wed, 15 Jul 2026 16:39:12 +0530 Subject: [PATCH 1/3] fix(projects): include on hold status in project filters and reports (cherry picked from commit 51a9fc031680d1b1c32af56ec822c0c12ee364ff) --- erpnext/controllers/queries.py | 6 ++++-- erpnext/projects/report/project_summary/project_summary.js | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py index 931d6361efe..981375e9f0e 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -332,7 +332,9 @@ def bom(doctype, txt, searchfield, start, page_len, filters): @frappe.whitelist() @frappe.validate_and_sanitize_search_inputs -def get_project_name(doctype, txt, searchfield, start, page_len, filters): +def get_project_name( + doctype: str, txt: str, searchfield: str, start: int, page_len: int, filters: dict | None = None +): proj = qb.DocType("Project") qb_filter_and_conditions = [] qb_filter_or_conditions = [] @@ -347,7 +349,7 @@ def get_project_name(doctype, txt, searchfield, start, page_len, filters): if filters.get("company"): qb_filter_and_conditions.append(proj.company == filters.get("company")) - qb_filter_and_conditions.append(proj.status.notin(["Completed", "Cancelled"])) + qb_filter_and_conditions.append(proj.status.notin(["Completed", "Cancelled", "On hold"])) q = qb.from_(proj) diff --git a/erpnext/projects/report/project_summary/project_summary.js b/erpnext/projects/report/project_summary/project_summary.js index 072098d5db5..e9ff05857ae 100644 --- a/erpnext/projects/report/project_summary/project_summary.js +++ b/erpnext/projects/report/project_summary/project_summary.js @@ -22,7 +22,7 @@ frappe.query_reports["Project Summary"] = { fieldname: "status", label: __("Status"), fieldtype: "Select", - options: "\nOpen\nCompleted\nCancelled", + options: "\nOpen\nOn hold\nCompleted\nCancelled", default: "Open", }, { From 76fce556c8c6ac6d102b42d902d428ca4748403c Mon Sep 17 00:00:00 2001 From: Poovetha Date: Wed, 15 Jul 2026 16:40:59 +0530 Subject: [PATCH 2/3] test(projects): add test to ensure on hold project retains status (cherry picked from commit 79e5ccd37050a67cec2bfffbd38e1cad12a63705) --- .../projects/doctype/project/test_project.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/erpnext/projects/doctype/project/test_project.py b/erpnext/projects/doctype/project/test_project.py index 56d74cb4b2e..cb5e132354a 100644 --- a/erpnext/projects/doctype/project/test_project.py +++ b/erpnext/projects/doctype/project/test_project.py @@ -299,6 +299,23 @@ class TestProject(ERPNextTestSuite): project.save() self.assertEqual(project.percent_complete, 100) + def test_on_hold_project_keeps_status(self): + project, tasks = self._project_with_tasks("Task Completion", 4) + + # an On hold project is not auto-flipped to Completed even at 100% + project.status = "On hold" + for task in tasks: + frappe.db.set_value("Task", task, "status", "Completed") + project.update_percent_complete() + self.assertEqual(project.percent_complete, 100) + self.assertEqual(project.status, "On hold") + + # nor auto-flipped back to Open when below 100% + frappe.db.set_value("Task", tasks[0], "status", "Open") + project.update_percent_complete() + self.assertEqual(project.percent_complete, 75) + self.assertEqual(project.status, "On hold") + def _create_portal_user(self, email): """A user with no Project-related role, so read access can only come from control_access_for_project_users() sharing the doc with them.""" From 3ba83134afa3d502f2867292501b6ddffedcb359 Mon Sep 17 00:00:00 2001 From: Poovetha Date: Wed, 15 Jul 2026 16:42:22 +0530 Subject: [PATCH 3/3] fix(projects): add project filter (cherry picked from commit 724896156841533519f9f0e8d89f72c2964b57e7) --- erpnext/projects/doctype/task/task.js | 6 ++++++ erpnext/projects/doctype/timesheet/timesheet.js | 2 ++ 2 files changed, 8 insertions(+) diff --git a/erpnext/projects/doctype/task/task.js b/erpnext/projects/doctype/task/task.js index 2f5fa6db6b0..c8e30cb3259 100644 --- a/erpnext/projects/doctype/task/task.js +++ b/erpnext/projects/doctype/task/task.js @@ -14,6 +14,12 @@ frappe.ui.form.on("Task", { }; }, onload: function (frm) { + frm.set_query("project", function () { + return { + query: "erpnext.controllers.queries.get_project_name", + }; + }); + frm.set_query("task", "depends_on", function () { let filters = { name: ["!=", frm.doc.name], diff --git a/erpnext/projects/doctype/timesheet/timesheet.js b/erpnext/projects/doctype/timesheet/timesheet.js index 8001dffad86..bc63ba79a80 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.js +++ b/erpnext/projects/doctype/timesheet/timesheet.js @@ -30,6 +30,7 @@ frappe.ui.form.on("Timesheet", { return { filters: { company: frm.doc.company, + status: "Open", }, }; }; @@ -122,6 +123,7 @@ frappe.ui.form.on("Timesheet", { return { filters: { customer: doc.customer, + status: "Open", }, }; });