diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index a074c9b1c0a..d1c295eaf5f 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -897,8 +897,12 @@ frappe.ui.form.on("Sales Invoice", { project: function (frm) { if (frm.doc.project) { - frm.events.add_timesheet_data(frm, { - project: frm.doc.project, + frappe.db.get_value("Projects Settings", {}, "fetch_timesheet_in_sales_invoice", (r) => { + if (cint(r.fetch_timesheet_in_sales_invoice)) { + frm.events.add_timesheet_data(frm, { + project: frm.doc.project, + }); + } }); } }, diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 7345a5ef78d..3c0689a7da9 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -1090,7 +1090,11 @@ class SalesInvoice(SellingController): timesheet.billing_amount = ts_doc.total_billable_amount def update_timesheet_billing_for_project(self): - if not self.timesheets and self.project: + if ( + not self.timesheets + and self.project + and frappe.db.get_single_value("Projects Settings", "fetch_timesheet_in_sales_invoice") + ): self.add_timesheet_data() else: self.calculate_billing_amount_for_timesheet() diff --git a/erpnext/projects/doctype/projects_settings/projects_settings.json b/erpnext/projects/doctype/projects_settings/projects_settings.json index 7fa1558a76f..2a840b4275c 100644 --- a/erpnext/projects/doctype/projects_settings/projects_settings.json +++ b/erpnext/projects/doctype/projects_settings/projects_settings.json @@ -1,189 +1,69 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2018-02-21 16:42:13.882879", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "creation": "2018-02-21 16:42:13.882879", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "timesheet_sb", + "ignore_workstation_time_overlap", + "ignore_user_time_overlap", + "ignore_employee_time_overlap", + "fetch_timesheet_in_sales_invoice" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "timesheet_sb", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Timesheets", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "timesheet_sb", + "fieldtype": "Section Break", + "label": "Timesheets" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fieldname": "ignore_workstation_time_overlap", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Ignore Workstation Time Overlap", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "ignore_workstation_time_overlap", + "fieldtype": "Check", + "label": "Ignore Workstation Time Overlap" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fieldname": "ignore_user_time_overlap", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Ignore User Time Overlap", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "ignore_user_time_overlap", + "fieldtype": "Check", + "label": "Ignore User Time Overlap" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fieldname": "ignore_employee_time_overlap", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Ignore Employee Time Overlap", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "default": "0", + "fieldname": "ignore_employee_time_overlap", + "fieldtype": "Check", + "label": "Ignore Employee Time Overlap" + }, + { + "default": "0", + "fieldname": "fetch_timesheet_in_sales_invoice", + "fieldtype": "Check", + "label": "Fetch Timesheet in Sales Invoice" } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 1, - "istable": 0, - "max_attachments": 0, - "modified": "2018-02-21 16:42:42.357209", - "modified_by": "Administrator", - "module": "Projects", - "name": "Projects Settings", - "name_case": "", - "owner": "Administrator", + ], + "issingle": 1, + "links": [], + "modified": "2025-02-25 22:48:03.164862", + "modified_by": "Administrator", + "module": "Projects", + "name": "Projects Settings", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 0, - "role": "System Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "delete": 1, + "email": 1, + "print": 1, + "read": 1, + "role": "System Manager", + "share": 1, "write": 1 } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0 + ], + "quick_entry": 1, + "sort_field": "modified", + "sort_order": "DESC", + "states": [], + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/projects/doctype/projects_settings/projects_settings.py b/erpnext/projects/doctype/projects_settings/projects_settings.py index 9d940184d98..4b1530fee8e 100644 --- a/erpnext/projects/doctype/projects_settings/projects_settings.py +++ b/erpnext/projects/doctype/projects_settings/projects_settings.py @@ -14,6 +14,7 @@ class ProjectsSettings(Document): if TYPE_CHECKING: from frappe.types import DF + fetch_timesheet_in_sales_invoice: DF.Check ignore_employee_time_overlap: DF.Check ignore_user_time_overlap: DF.Check ignore_workstation_time_overlap: DF.Check diff --git a/erpnext/projects/doctype/timesheet/test_timesheet.py b/erpnext/projects/doctype/timesheet/test_timesheet.py index da042f36aef..1e2688daf4d 100644 --- a/erpnext/projects/doctype/timesheet/test_timesheet.py +++ b/erpnext/projects/doctype/timesheet/test_timesheet.py @@ -5,6 +5,7 @@ import datetime import unittest import frappe +from frappe.tests.utils import change_settings from frappe.utils import add_to_date, now_datetime, nowdate from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice @@ -53,6 +54,7 @@ class TestTimesheet(unittest.TestCase): self.assertEqual(item.qty, 2.00) self.assertEqual(item.rate, 50.00) + @change_settings("Projects Settings", {"fetch_timesheet_in_sales_invoice": 1}) def test_timesheet_billing_based_on_project(self): emp = make_employee("test_employee_6@salary.com") project = frappe.get_value("Project", {"project_name": "_Test Project"}) @@ -62,6 +64,7 @@ class TestTimesheet(unittest.TestCase): ) sales_invoice = create_sales_invoice(do_not_save=True) sales_invoice.project = project + sales_invoice.add_timesheet_data() sales_invoice.submit() ts = frappe.get_doc("Timesheet", timesheet.name)