diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py index 7be1c3a2b6e..f5f06685f53 100644 --- a/erpnext/projects/doctype/project/project.py +++ b/erpnext/projects/doctype/project/project.py @@ -441,8 +441,10 @@ def get_timeline_data(doctype: str, name: str) -> dict[int, int]: timesheet_detail = frappe.qb.DocType("Timesheet Detail") return dict( + # select the same day-bucket expression that is grouped on (postgres rejects selecting the + # ungrouped from_time); UnixTimestamp(Date(...)) is the day's epoch, which is the timeline key. frappe.qb.from_(timesheet_detail) - .select(UnixTimestamp(timesheet_detail.from_time), Count("*")) + .select(UnixTimestamp(Date(timesheet_detail.from_time)), Count("*")) .where(timesheet_detail.project == name) .where(timesheet_detail.from_time > CurDate() - Interval(years=1)) .where(timesheet_detail.docstatus < 2) diff --git a/erpnext/projects/doctype/project/test_project.py b/erpnext/projects/doctype/project/test_project.py index 3ece3ea36c2..4f284860e3e 100644 --- a/erpnext/projects/doctype/project/test_project.py +++ b/erpnext/projects/doctype/project/test_project.py @@ -12,6 +12,21 @@ from erpnext.tests.utils import ERPNextTestSuite class TestProject(ERPNextTestSuite): + def test_get_timeline_data_runs(self): + # get_timeline_data groups Timesheet Detail by Date(from_time); the selected day key must be the + # same grouped expression (UnixTimestamp(Date(from_time))) to be valid on Postgres. + from erpnext.projects.doctype.project.project import get_timeline_data + from erpnext.projects.doctype.timesheet.test_timesheet import make_timesheet + from erpnext.setup.doctype.employee.test_employee import make_employee + + project = make_project({"project_name": "_Test Timeline Project", "company": "_Test Company"}) + emp = make_employee("test_timeline@example.com", company="_Test Company") + make_timesheet(emp, simulate=True, project=project.name) + + data = get_timeline_data("Project", project.name) + self.assertIsInstance(data, dict) + self.assertGreaterEqual(sum(data.values()), 1) + def test_project_total_costing_and_billing_amount(self): from erpnext.projects.doctype.timesheet.test_timesheet import make_timesheet from erpnext.setup.doctype.employee.test_employee import make_employee