diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index a074c9b1c0a..ed7eb5685c1 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -897,8 +897,16 @@ frappe.ui.form.on("Sales Invoice", { project: function (frm) { if (frm.doc.project) { - frm.events.add_timesheet_data(frm, { - project: frm.doc.project, + frappe.call({ + method: "is_auto_fetch_timesheet_enabled", + doc: frm.doc, + callback: function (r) { + if (cint(r.message)) { + 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..c860fe41a66 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -1090,11 +1090,15 @@ 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 self.is_auto_fetch_timesheet_enabled(): self.add_timesheet_data() else: self.calculate_billing_amount_for_timesheet() + @frappe.whitelist() + def is_auto_fetch_timesheet_enabled(self): + return frappe.db.get_single_value("Projects Settings", "fetch_timesheet_in_sales_invoice") + @frappe.whitelist() def add_timesheet_data(self): self.set("timesheets", []) 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) diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js index 9334786ae86..bfde624f7b3 100644 --- a/erpnext/selling/page/point_of_sale/pos_controller.js +++ b/erpnext/selling/page/point_of_sale/pos_controller.js @@ -40,7 +40,7 @@ erpnext.PointOfSale.Controller = class { in_list_view: 1, label: __("Opening Amount"), options: "company:company_currency", - change: function () { + onchange: function () { dialog.fields_dict.balance_details.df.data.some((d) => { if (d.idx == this.doc.idx) { d.opening_amount = this.value; diff --git a/erpnext/stock/deprecated_serial_batch.py b/erpnext/stock/deprecated_serial_batch.py index 5ab862b51b3..f946f459c07 100644 --- a/erpnext/stock/deprecated_serial_batch.py +++ b/erpnext/stock/deprecated_serial_batch.py @@ -332,6 +332,8 @@ class DeprecatedBatchNoValuation: if self.sle.voucher_detail_no: query = query.where(sabb.voucher_detail_no != self.sle.voucher_detail_no) + query = query.where(sabb.voucher_type != "Pick List") + data = query.run(as_dict=True) if not data: return {} diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py index db5d1e58a84..d3de1897633 100644 --- a/erpnext/stock/doctype/bin/bin.py +++ b/erpnext/stock/doctype/bin/bin.py @@ -247,7 +247,7 @@ def update_qty(bin_name, args): & (sle.warehouse == args.get("warehouse")) & (sle.is_cancelled == 0) ) - .orderby(CombineDatetime(sle.posting_date, sle.posting_time), order=Order.desc) + .orderby(sle.posting_datetime, order=Order.desc) .orderby(sle.creation, order=Order.desc) .limit(1) .run() diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index 3dea6010867..ca08a5ef121 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -883,6 +883,10 @@ class update_entries_after: if not sle.is_adjustment_entry: sle.stock_value_difference = stock_value_difference + elif sle.is_adjustment_entry and not self.args.get("sle_id"): + sle.stock_value_difference = get_stock_value_difference( + sle.item_code, sle.warehouse, sle.posting_date, sle.posting_time, sle.voucher_no + ) sle.doctype = "Stock Ledger Entry" frappe.get_doc(sle).db_update()