From 1c7a18866f2e6ab6edfacf98ed222cbfea8e2195 Mon Sep 17 00:00:00 2001 From: Kavin <78342682+kavin-114@users.noreply.github.com> Date: Wed, 20 Aug 2025 15:12:18 +0530 Subject: [PATCH 01/22] Merge pull request #49183 from aerele/fix/mr-status-from-wo Fix/mr status from wo (cherry picked from commit 67e57018bc9de31887dac419ef89717354dc2b71) --- erpnext/controllers/status_updater.py | 6 +----- .../doctype/sales_order/test_sales_order.py | 2 +- .../material_request/material_request_list.js | 4 +--- .../material_request/test_material_request.py | 17 +++++++++++++++++ 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index e41ac0dd0ab..15c2760332e 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -108,7 +108,7 @@ status_map = { ["Pending", "eval:self.status != 'Stopped' and self.per_ordered == 0 and self.docstatus == 1"], [ "Ordered", - "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type == 'Purchase'", + "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type in ['Purchase', 'Manufacture']", ], [ "Transferred", @@ -134,10 +134,6 @@ status_map = { "Partially Ordered", "eval:self.status != 'Stopped' and self.per_ordered < 100 and self.per_ordered > 0 and self.docstatus == 1 and self.material_request_type != 'Material Transfer'", ], - [ - "Manufactured", - "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type == 'Manufacture'", - ], ], "POS Opening Entry": [ ["Draft", None], diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index ae807e5b1c0..c5898a5ffaa 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -1830,7 +1830,7 @@ class TestSalesOrder(AccountsTestMixin, FrappeTestCase): wo.reload() so.reload() self.assertEqual(so.items[0].work_order_qty, wo.produced_qty) - self.assertEqual(mr.status, "Manufactured") + self.assertEqual(mr.status, "Ordered") @change_settings( "Accounts Settings", diff --git a/erpnext/stock/doctype/material_request/material_request_list.js b/erpnext/stock/doctype/material_request/material_request_list.js index ff928ea6a22..69d8c15803d 100644 --- a/erpnext/stock/doctype/material_request/material_request_list.js +++ b/erpnext/stock/doctype/material_request/material_request_list.js @@ -35,7 +35,7 @@ frappe.listview_settings["Material Request"] = { return [__("Partially Received"), "yellow", "per_received,<,100"]; } else if (doc.material_request_type == "Purchase" && flt(doc.per_received, precision) == 100) { return [__("Received"), "green", "per_received,=,100"]; - } else if (doc.material_request_type == "Purchase") { + } else if (["Purchase", "Manufacture"].includes(doc.material_request_type)) { return [__("Ordered"), "green", "per_ordered,=,100"]; } else if (doc.material_request_type == "Material Transfer") { return [__("Transfered"), "green", "per_ordered,=,100"]; @@ -43,8 +43,6 @@ frappe.listview_settings["Material Request"] = { return [__("Issued"), "green", "per_ordered,=,100"]; } else if (doc.material_request_type == "Customer Provided") { return [__("Received"), "green", "per_ordered,=,100"]; - } else if (doc.material_request_type == "Manufacture") { - return [__("Manufactured"), "green", "per_ordered,=,100"]; } } }, diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py index 30b2d7fcdc2..66dd9c0c795 100644 --- a/erpnext/stock/doctype/material_request/test_material_request.py +++ b/erpnext/stock/doctype/material_request/test_material_request.py @@ -866,6 +866,23 @@ class TestMaterialRequest(FrappeTestCase): for perm in permissions: perm.delete() + def test_manufacture_type_status_over_wo(self): + from erpnext.stock.doctype.material_request.material_request import raise_work_orders + + mr = make_material_request( + item_code="_Test FG Item", material_request_type="Manufacture", do_not_submit=False + ) + + work_order = raise_work_orders(mr.name) + wo = frappe.get_doc("Work Order", work_order[0]) + wo.wip_warehouse = "_Test Warehouse 1 - _TC" + wo.submit() + + mr.reload() + + self.assertEqual(mr.per_ordered, 100) + self.assertEqual(mr.status, "Ordered") + def get_in_transit_warehouse(company): if not frappe.db.exists("Warehouse Type", "Transit"): From edaff5d6993df85b5e978a9297a6e27b00a44a35 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Wed, 20 Aug 2025 17:20:03 +0530 Subject: [PATCH 02/22] fix: child item picker picking all items when creating PI from PR (cherry picked from commit 738c1e0d0a2acc70fc59c8026d4dfabaad96dcf8) --- .../doctype/purchase_order/purchase_order.js | 3 +++ .../supplier_quotation/supplier_quotation.py | 15 ++++++++++++++- .../doctype/purchase_receipt/purchase_receipt.py | 4 ++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index dca3285f538..d82a5e18c23 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -599,6 +599,9 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends ( docstatus: 1, status: ["not in", ["Stopped", "Expired"]], }, + allow_child_item_selection: true, + child_fieldname: "items", + child_columns: ["item_code", "item_name", "qty", "rate", "amount"], }); }, __("Get Items From") diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py index 5557f1a80ae..35cb2eebf8f 100644 --- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py +++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py @@ -2,6 +2,8 @@ # License: GNU General Public License v3. See license.txt +import json + import frappe from frappe import _ from frappe.model.mapper import get_mapped_doc @@ -235,7 +237,12 @@ def get_list_context(context=None): @frappe.whitelist() -def make_purchase_order(source_name, target_doc=None): +def make_purchase_order(source_name, target_doc=None, args=None): + if args is None: + args = {} + if isinstance(args, str): + args = json.loads(args) + def set_missing_values(source, target): target.run_method("set_missing_values") target.run_method("get_schedule_dates") @@ -244,6 +251,11 @@ def make_purchase_order(source_name, target_doc=None): def update_item(obj, target, source_parent): target.stock_qty = flt(obj.qty) * flt(obj.conversion_factor) + def select_item(d): + filtered_items = args.get("filtered_children", []) + child_filter = d.name in filtered_items if filtered_items else True + return child_filter + doclist = get_mapped_doc( "Supplier Quotation", source_name, @@ -265,6 +277,7 @@ def make_purchase_order(source_name, target_doc=None): ["sales_order", "sales_order"], ], "postprocess": update_item, + "condition": select_item, }, "Purchase Taxes and Charges": { "doctype": "Purchase Taxes and Charges", diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 1c4d28c495e..bc7023fbebb 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -1322,8 +1322,8 @@ def make_purchase_invoice(source_name, target_doc=None, args=None): "postprocess": update_item, "filter": lambda d: ( get_pending_qty(d)[0] <= 0 if not doc.get("is_return") else get_pending_qty(d)[0] > 0 - ) - and select_item(d), + ), + "condition": select_item, }, "Purchase Taxes and Charges": { "doctype": "Purchase Taxes and Charges", From db4fc8545dc2394ad67057fdade4a69923b01e01 Mon Sep 17 00:00:00 2001 From: ravibharathi656 Date: Fri, 15 Aug 2025 10:00:33 +0530 Subject: [PATCH 03/22] fix: handle all searchfields in items (cherry picked from commit ad559c3491f233061745a94fbb0a71c40756a2c5) --- erpnext/stock/report/stock_balance/stock_balance.js | 4 ++-- erpnext/stock/report/stock_ledger/stock_ledger.js | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/erpnext/stock/report/stock_balance/stock_balance.js b/erpnext/stock/report/stock_balance/stock_balance.js index c53e80096d3..b59ee57b154 100644 --- a/erpnext/stock/report/stock_balance/stock_balance.js +++ b/erpnext/stock/report/stock_balance/stock_balance.js @@ -61,10 +61,10 @@ frappe.query_reports["Stock Balance"] = { }, }); - data = data.map(({ name, description }) => { + data = data.map(({ name, ...rest }) => { return { value: name, - description: description, + description: Object.values(rest), }; }); diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.js b/erpnext/stock/report/stock_ledger/stock_ledger.js index db6c0c06281..9b85a83c03b 100644 --- a/erpnext/stock/report/stock_ledger/stock_ledger.js +++ b/erpnext/stock/report/stock_ledger/stock_ledger.js @@ -56,11 +56,10 @@ frappe.query_reports["Stock Ledger"] = { as_dict: 1, }, }); - - data = data.map(({ name, description }) => { + data = data.map(({ name, ...rest }) => { return { value: name, - description: description, + description: Object.values(rest), }; }); From 196812017ee5641d6a39bf33930fe3b2b33b5d2d Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 21 Aug 2025 23:24:35 +0530 Subject: [PATCH 04/22] fix: Serial Nos popup only appears 1 time (cherry picked from commit 5503d4b05b9621fabf262df63c35d9997262101a) # Conflicts: # erpnext/public/js/controllers/transaction.js --- erpnext/public/js/controllers/transaction.js | 26 ++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 79d85c20a0b..22a23b041fd 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -551,6 +551,32 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe item_code(doc, cdt, cdn) { var me = this; +<<<<<<< HEAD +======= + frappe.flags.dialog_set = false; + + // Experimental: This will be removed once stability is achieved. + if (frappe.boot.sysdefaults.use_server_side_reactivity) { + var item = frappe.get_doc(cdt, cdn); + frappe.call({ + doc: doc, + method: "process_item_selection", + args: { + item_idx: item.idx, + }, + callback: function (r) { + if (!r.exc) { + me.frm.refresh_fields(); + } + }, + }); + } else { + me.process_item_selection(doc, cdt, cdn); + } + } + + process_item_selection(doc, cdt, cdn) { +>>>>>>> 5503d4b05b (fix: Serial Nos popup only appears 1 time) var item = frappe.get_doc(cdt, cdn); var update_stock = 0, show_batch_dialog = 0; From be01c4fafed0fc2d75e5d539eb047029b8be905f Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Thu, 21 Aug 2025 23:34:38 +0530 Subject: [PATCH 05/22] chore: fix conflicts --- erpnext/public/js/controllers/transaction.js | 24 -------------------- 1 file changed, 24 deletions(-) diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 22a23b041fd..e3680549cc0 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -551,32 +551,8 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe item_code(doc, cdt, cdn) { var me = this; -<<<<<<< HEAD -======= frappe.flags.dialog_set = false; - // Experimental: This will be removed once stability is achieved. - if (frappe.boot.sysdefaults.use_server_side_reactivity) { - var item = frappe.get_doc(cdt, cdn); - frappe.call({ - doc: doc, - method: "process_item_selection", - args: { - item_idx: item.idx, - }, - callback: function (r) { - if (!r.exc) { - me.frm.refresh_fields(); - } - }, - }); - } else { - me.process_item_selection(doc, cdt, cdn); - } - } - - process_item_selection(doc, cdt, cdn) { ->>>>>>> 5503d4b05b (fix: Serial Nos popup only appears 1 time) var item = frappe.get_doc(cdt, cdn); var update_stock = 0, show_batch_dialog = 0; From c375ac39392110e3e59c3c1e8fb255e8ab6b7514 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 22 Aug 2025 15:11:26 +0530 Subject: [PATCH 06/22] Merge pull request #49272 from frappe/mergify/bp/version-15-hotfix/pr-49050 fix: ensure variant conversion factor is returned before the template's (backport #49050) --- erpnext/stock/get_item_details.py | 32 +++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index e31ba966653..c912c529b22 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -1277,17 +1277,33 @@ def get_pos_profile(company, pos_profile=None, user=None): @frappe.whitelist() def get_conversion_factor(item_code, uom): - variant_of = frappe.db.get_value("Item", item_code, "variant_of", cache=True) - filters = {"parent": item_code, "uom": uom} + item = frappe.get_cached_value("Item", item_code, ["variant_of", "stock_uom"], as_dict=True) + if not item_code or not item or uom == item.stock_uom: + return {"conversion_factor": 1.0} + + item_codes = [item_code] + if item.variant_of: + item_codes.append(item.variant_of) + + parent = frappe.qb.DocType("Item") + child = frappe.qb.DocType("UOM Conversion Detail") + query = ( + frappe.qb.from_(parent) + .join(child) + .on(parent.name == child.parent) + .select(child.conversion_factor) + .where((parent.name.isin(item_codes)) & (child.uom == uom)) + .orderby(parent.has_variants) + .limit(1) + ) + conversion_factor = query.run(pluck="conversion_factor") - if variant_of: - filters["parent"] = ("in", (item_code, variant_of)) - conversion_factor = frappe.get_all("UOM Conversion Detail", filters, pluck="conversion_factor") if not conversion_factor: - stock_uom = frappe.db.get_value("Item", item_code, "stock_uom") - conversion_factor = [get_uom_conv_factor(uom, stock_uom) or 1] + conversion_factor = get_uom_conv_factor(uom, item.stock_uom) + else: + conversion_factor = conversion_factor[0] - return {"conversion_factor": conversion_factor[-1]} + return {"conversion_factor": conversion_factor or 1.0} @frappe.whitelist() From 655af2418342a372eea6d976a139c445573a4799 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 22 Aug 2025 19:04:42 +0200 Subject: [PATCH 07/22] feat: add make methods for Bank Account (backport #49000) (#49275) Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com> --- erpnext/buying/doctype/supplier/supplier.js | 4 ++++ erpnext/public/js/utils.js | 14 +++----------- erpnext/selling/doctype/customer/customer.js | 1 + erpnext/setup/doctype/employee/employee.js | 6 ++++++ 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/erpnext/buying/doctype/supplier/supplier.js b/erpnext/buying/doctype/supplier/supplier.js index b74474be89e..cfa60453dd6 100644 --- a/erpnext/buying/doctype/supplier/supplier.js +++ b/erpnext/buying/doctype/supplier/supplier.js @@ -64,6 +64,10 @@ frappe.ui.form.on("Supplier", { }, }; }); + + frm.make_methods = { + "Bank Account": () => erpnext.utils.make_bank_account(frm.doc.doctype, frm.doc.name), + }; }, refresh: function (frm) { diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js index 1cf3275a530..2b6d41c2d54 100755 --- a/erpnext/public/js/utils.js +++ b/erpnext/public/js/utils.js @@ -209,17 +209,9 @@ $.extend(erpnext.utils, { }, make_bank_account: function (doctype, docname) { - frappe.call({ - method: "erpnext.accounts.doctype.bank_account.bank_account.make_bank_account", - args: { - doctype: doctype, - docname: docname, - }, - freeze: true, - callback: function (r) { - var doclist = frappe.model.sync(r.message); - frappe.set_route("Form", doclist[0].doctype, doclist[0].name); - }, + frappe.new_doc("Bank Account", { + party_type: doctype, + party: docname, }); }, diff --git a/erpnext/selling/doctype/customer/customer.js b/erpnext/selling/doctype/customer/customer.js index 11a3eecb967..aa8bea55094 100644 --- a/erpnext/selling/doctype/customer/customer.js +++ b/erpnext/selling/doctype/customer/customer.js @@ -14,6 +14,7 @@ frappe.ui.form.on("Customer", { method: "erpnext.selling.doctype.customer.customer.make_opportunity", frm: cur_frm, }), + "Bank Account": () => erpnext.utils.make_bank_account(frm.doc.doctype, frm.doc.name), }; frm.add_fetch("lead_name", "company_name", "customer_name"); diff --git a/erpnext/setup/doctype/employee/employee.js b/erpnext/setup/doctype/employee/employee.js index 7a1efa82fa0..2e45d5511b3 100755 --- a/erpnext/setup/doctype/employee/employee.js +++ b/erpnext/setup/doctype/employee/employee.js @@ -21,6 +21,12 @@ erpnext.setup.EmployeeController = class EmployeeController extends frappe.ui.fo }; frappe.ui.form.on("Employee", { + setup: function (frm) { + frm.make_methods = { + "Bank Account": () => erpnext.utils.make_bank_account(frm.doc.doctype, frm.doc.name), + }; + }, + onload: function (frm) { frm.set_query("department", function () { return { From ba840d22e540988e77b61d68e2288e6cac3af4b3 Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Fri, 22 Aug 2025 19:18:42 +0200 Subject: [PATCH 08/22] fix(Supplier): add make_method for Pricing Rule (#49282) --- erpnext/buying/doctype/supplier/supplier.js | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/buying/doctype/supplier/supplier.js b/erpnext/buying/doctype/supplier/supplier.js index cfa60453dd6..0a316bd2974 100644 --- a/erpnext/buying/doctype/supplier/supplier.js +++ b/erpnext/buying/doctype/supplier/supplier.js @@ -67,6 +67,7 @@ frappe.ui.form.on("Supplier", { frm.make_methods = { "Bank Account": () => erpnext.utils.make_bank_account(frm.doc.doctype, frm.doc.name), + "Pricing Rule": () => erpnext.utils.make_pricing_rule(frm.doc.doctype, frm.doc.name), }; }, From bec385a6676c0cf5dfb2a29f48e6de9a4e4799c6 Mon Sep 17 00:00:00 2001 From: Kavin <78342682+kavin0411@users.noreply.github.com> Date: Sat, 16 Aug 2025 22:11:55 +0530 Subject: [PATCH 09/22] fix: set valid serial no naming series format (cherry picked from commit 46b85c78572328d9378869e0732453af22987916) --- .../serial_and_batch_bundle/test_serial_and_batch_bundle.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/test_serial_and_batch_bundle.py b/erpnext/stock/doctype/serial_and_batch_bundle/test_serial_and_batch_bundle.py index a3bd20b80ba..5fdc3d56ebd 100644 --- a/erpnext/stock/doctype/serial_and_batch_bundle/test_serial_and_batch_bundle.py +++ b/erpnext/stock/doctype/serial_and_batch_bundle/test_serial_and_batch_bundle.py @@ -608,7 +608,7 @@ class TestSerialandBatchBundle(FrappeTestCase): def test_serial_no_valuation_for_legacy_ledgers(self): sn_item = make_item( "Test Serial No Valuation for Legacy Ledgers", - properties={"has_serial_no": 1, "serial_no_series": "SNN-TSNVL.-#####"}, + properties={"has_serial_no": 1, "serial_no_series": "SNN-TSNVL-.#####"}, ).name serial_nos = [] From fbbd5a3af5e27545002796644812c0835ea90ca4 Mon Sep 17 00:00:00 2001 From: Sagar Vora <16315650+sagarvora@users.noreply.github.com> Date: Tue, 26 Aug 2025 00:06:14 +0530 Subject: [PATCH 10/22] fix: match warehouse only when `last_scanned_warehouse` field exists (cherry picked from commit 4005e4412d54fb9a5072a7394660c4ebc1b7c019) --- erpnext/public/js/utils/barcode_scanner.js | 33 ++++++++++++---------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/erpnext/public/js/utils/barcode_scanner.js b/erpnext/public/js/utils/barcode_scanner.js index 0719e5ed99f..2301726072a 100644 --- a/erpnext/public/js/utils/barcode_scanner.js +++ b/erpnext/public/js/utils/barcode_scanner.js @@ -113,12 +113,7 @@ erpnext.utils.BarcodeScanner = class BarcodeScanner { frappe.flags.trigger_from_barcode_scanner = true; const { item_code, barcode, batch_no, serial_no, uom, default_warehouse } = data; - - const warehouse = this.has_last_scanned_warehouse - ? this.frm.doc.last_scanned_warehouse || default_warehouse - : null; - - let row = this.get_row_to_modify_on_scan(item_code, batch_no, uom, barcode, warehouse); + let row = this.get_row_to_modify_on_scan(item_code, batch_no, uom, barcode, default_warehouse); const is_new_row = !row?.item_code; if (!row) { if (this.dont_allow_new_row) { @@ -151,7 +146,7 @@ erpnext.utils.BarcodeScanner = class BarcodeScanner { () => this.set_serial_no(row, serial_no), () => this.set_batch_no(row, batch_no), () => this.set_barcode(row, barcode), - () => this.set_warehouse(row, warehouse), + () => this.set_warehouse(row), () => this.clean_up(), () => this.revert_selector_flag(), () => resolve(row), @@ -412,12 +407,16 @@ erpnext.utils.BarcodeScanner = class BarcodeScanner { } } - async set_warehouse(row, warehouse) { - const warehouse_field = this.get_warehouse_field(); + async set_warehouse(row) { + if (!this.has_last_scanned_warehouse) return; - if (warehouse && frappe.meta.has_field(row.doctype, warehouse_field)) { - await frappe.model.set_value(row.doctype, row.name, warehouse_field, warehouse); - } + const last_scanned_warehouse = this.frm.doc.last_scanned_warehouse; + if (!last_scanned_warehouse) return; + + const warehouse_field = this.get_warehouse_field(); + if (!warehouse_field || !frappe.meta.has_field(row.doctype, warehouse_field)) return; + + await frappe.model.set_value(row.doctype, row.name, warehouse_field, last_scanned_warehouse); } show_scan_message(idx, is_existing_row = false, qty = 1) { @@ -438,15 +437,19 @@ erpnext.utils.BarcodeScanner = class BarcodeScanner { return is_duplicate; } - get_row_to_modify_on_scan(item_code, batch_no, uom, barcode, warehouse) { + get_row_to_modify_on_scan(item_code, batch_no, uom, barcode, default_warehouse) { let cur_grid = this.frm.fields_dict[this.items_table_name].grid; // Check if batch is scanned and table has batch no field let is_batch_no_scan = batch_no && frappe.meta.has_field(cur_grid.doctype, this.batch_no_field); let check_max_qty = this.max_qty_field && frappe.meta.has_field(cur_grid.doctype, this.max_qty_field); - const warehouse_field = this.get_warehouse_field(); - let has_warehouse_field = frappe.meta.has_field(cur_grid.doctype, warehouse_field); + const warehouse_field = this.has_last_scanned_warehouse && this.get_warehouse_field(); + const has_warehouse_field = + warehouse_field && frappe.meta.has_field(cur_grid.doctype, warehouse_field); + const warehouse = has_warehouse_field + ? this.frm.doc.last_scanned_warehouse || default_warehouse + : null; const matching_row = (row) => { const item_match = row.item_code == item_code; From 0767c2e0f67407c8028064e1b121f418bda98993 Mon Sep 17 00:00:00 2001 From: Sagar Vora <16315650+sagarvora@users.noreply.github.com> Date: Tue, 26 Aug 2025 00:29:26 +0530 Subject: [PATCH 11/22] fix: correct logic for warehouse field label (cherry picked from commit 72a38929e5f137287c6baa60b7267c19b8efeba2) --- erpnext/public/js/utils/barcode_scanner.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/public/js/utils/barcode_scanner.js b/erpnext/public/js/utils/barcode_scanner.js index 2301726072a..b8d1b4afa2a 100644 --- a/erpnext/public/js/utils/barcode_scanner.js +++ b/erpnext/public/js/utils/barcode_scanner.js @@ -512,7 +512,8 @@ erpnext.utils.BarcodeScanner = class BarcodeScanner { handle_warehouse_scan(data) { const warehouse = data.warehouse; const warehouse_field = this.get_warehouse_field(); - const warehouse_field_label = frappe.meta.get_label(this.items_table_name, warehouse_field); + const cur_grid = this.frm.fields_dict[this.items_table_name].grid; + const warehouse_field_label = frappe.meta.get_label(cur_grid.doctype, warehouse_field); if (!this.last_scanned_warehouse_initialized) { this.setup_last_scanned_warehouse(); From 54030eb72110c65b496c49ebec0cf845d2578ac7 Mon Sep 17 00:00:00 2001 From: ravibharathi656 Date: Thu, 31 Jul 2025 11:42:41 +0530 Subject: [PATCH 12/22] fix: incorrect pending qty when creating sales invoice from sales order (cherry picked from commit a5138f48998cb77cfa7600a9f81717e255d61628) --- .../selling/doctype/sales_order/sales_order.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 75260a5a3fa..0118e89cd3c 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -1144,6 +1144,17 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False, a target.debit_to = get_party_account("Customer", source.customer, source.company) def update_item(source, target, source_parent): + def get_billed_qty(so_item_name): + from frappe.query_builder.functions import Sum + + table = frappe.qb.DocType("Sales Invoice Item") + query = ( + frappe.qb.from_(table) + .select(Sum(table.qty).as_("qty")) + .where((table.docstatus == 1) & (table.so_detail == so_item_name)) + ) + return query.run(pluck="qty")[0] or 0 + if source_parent.has_unit_price_items: # 0 Amount rows (as seen in Unit Price Items) should be mapped as it is pending_amount = flt(source.amount) - flt(source.billed_amt) @@ -1153,8 +1164,8 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False, a target.base_amount = target.amount * flt(source_parent.conversion_rate) target.qty = ( - target.amount / flt(source.rate) - if (source.rate and source.billed_amt) + source.qty - get_billed_qty(source.name) + if (source.qty and source.billed_amt) else (source.qty if is_unit_price_row(source) else source.qty - source.returned_qty) ) From b403b6c7b417dc1ed45770230d0ce5b117f73f04 Mon Sep 17 00:00:00 2001 From: ravibharathi656 Date: Mon, 25 Aug 2025 21:04:51 +0530 Subject: [PATCH 13/22] test: add pending quantity check for invoice creation (cherry picked from commit e5d4b4f0f02f9de83cda794b783791a194db6a44) # Conflicts: # erpnext/selling/doctype/sales_order/test_sales_order.py --- .../doctype/sales_order/test_sales_order.py | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index c5898a5ffaa..9556a7a9480 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -2396,6 +2396,66 @@ class TestSalesOrder(AccountsTestMixin, FrappeTestCase): self.assertFalse(so.per_billed) self.assertEqual(so.status, "To Deliver and Bill") +<<<<<<< HEAD +======= + def test_item_tax_transfer_from_sales_to_purchase(self): + from erpnext.selling.doctype.sales_order.sales_order import make_purchase_order + + item_tax = frappe.new_doc("Item Tax Template") + item_tax.title = "Test Item Tax Template" + item_tax.company = "_Test Company" + item_tax.append("taxes", {"tax_type": "_Test Account Service Tax - _TC", "tax_rate": 2}) + item_tax.save() + + item_group = frappe.get_doc("Item Group", "_Test Item Group") + item_group.append("taxes", {"item_tax_template": "Test Item Tax Template - _TC"}) + item_group.save() + + so = make_sales_order(item_code="_Test Item", qty=1, do_not_submit=1) + so.append( + "taxes", + { + "account_head": "_Test Account Service Tax - _TC", + "charge_type": "On Net Total", + "description": "TDS", + "doctype": "Sales Taxes and Charges", + "rate": 2, + }, + ) + so.submit() + + po = make_purchase_order(so.name, selected_items=so.items) + po.supplier = "_Test Supplier" + po.items[0].rate = 100 + po.submit() + self.assertEqual(po.taxes[0].tax_amount, 2) + + def test_pending_quantity_after_update_item_during_invoice_creation(self): + so = make_sales_order(qty=30, rate=100) + + si1 = make_sales_invoice(so.name) + si1.update_stock = 1 + si1.get("items")[0].qty = 10 + si1.insert() + si1.submit() + + first_item_of_so = so.get("items")[0] + trans_item = json.dumps( + [ + { + "item_code": first_item_of_so.item_code, + "rate": 1000, + "qty": first_item_of_so.qty, + "docname": first_item_of_so.name, + }, + ] + ) + update_child_qty_rate("Sales Order", trans_item, so.name) + + si2 = make_sales_invoice(so.name) + self.assertEqual(si2.items[0].qty, 20) + +>>>>>>> e5d4b4f0f0 (test: add pending quantity check for invoice creation) def automatically_fetch_payment_terms(enable=1): accounts_settings = frappe.get_doc("Accounts Settings") From 1380ee21b62c3389184dfa55f2231807ede9a14a Mon Sep 17 00:00:00 2001 From: ravibharathi656 Date: Mon, 25 Aug 2025 21:23:14 +0530 Subject: [PATCH 14/22] chore: remove update_stock (cherry picked from commit 368dbe3bbf138aa892248a9e269e29dde04e1263) --- erpnext/selling/doctype/sales_order/test_sales_order.py | 1 - 1 file changed, 1 deletion(-) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 9556a7a9480..ff5b8e07593 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -2434,7 +2434,6 @@ class TestSalesOrder(AccountsTestMixin, FrappeTestCase): so = make_sales_order(qty=30, rate=100) si1 = make_sales_invoice(so.name) - si1.update_stock = 1 si1.get("items")[0].qty = 10 si1.insert() si1.submit() From 69835732432580b3623c65cb7879922198c7d530 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 26 Aug 2025 11:06:55 +0530 Subject: [PATCH 15/22] chore: resolve conflict --- .../doctype/sales_order/test_sales_order.py | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index ff5b8e07593..04a3a989cae 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -2396,40 +2396,6 @@ class TestSalesOrder(AccountsTestMixin, FrappeTestCase): self.assertFalse(so.per_billed) self.assertEqual(so.status, "To Deliver and Bill") -<<<<<<< HEAD -======= - def test_item_tax_transfer_from_sales_to_purchase(self): - from erpnext.selling.doctype.sales_order.sales_order import make_purchase_order - - item_tax = frappe.new_doc("Item Tax Template") - item_tax.title = "Test Item Tax Template" - item_tax.company = "_Test Company" - item_tax.append("taxes", {"tax_type": "_Test Account Service Tax - _TC", "tax_rate": 2}) - item_tax.save() - - item_group = frappe.get_doc("Item Group", "_Test Item Group") - item_group.append("taxes", {"item_tax_template": "Test Item Tax Template - _TC"}) - item_group.save() - - so = make_sales_order(item_code="_Test Item", qty=1, do_not_submit=1) - so.append( - "taxes", - { - "account_head": "_Test Account Service Tax - _TC", - "charge_type": "On Net Total", - "description": "TDS", - "doctype": "Sales Taxes and Charges", - "rate": 2, - }, - ) - so.submit() - - po = make_purchase_order(so.name, selected_items=so.items) - po.supplier = "_Test Supplier" - po.items[0].rate = 100 - po.submit() - self.assertEqual(po.taxes[0].tax_amount, 2) - def test_pending_quantity_after_update_item_during_invoice_creation(self): so = make_sales_order(qty=30, rate=100) @@ -2454,7 +2420,6 @@ class TestSalesOrder(AccountsTestMixin, FrappeTestCase): si2 = make_sales_invoice(so.name) self.assertEqual(si2.items[0].qty, 20) ->>>>>>> e5d4b4f0f0 (test: add pending quantity check for invoice creation) def automatically_fetch_payment_terms(enable=1): accounts_settings = frappe.get_doc("Accounts Settings") From 083661b779533e3514fb5e1ebf2693578642bfd9 Mon Sep 17 00:00:00 2001 From: l0gesh29 Date: Wed, 20 Aug 2025 19:25:38 +0530 Subject: [PATCH 16/22] feat(payment-reconciliation): add posting date field for debit/credit note auto jv creation (cherry picked from commit 6b4004b12712cbab7f7b8b535b6ef1661a46d9d7) # Conflicts: # erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json --- .../payment_reconciliation/payment_reconciliation.py | 3 ++- .../payment_reconciliation_allocation.json | 10 ++++++++-- .../payment_reconciliation_allocation.py | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py index c77870d0886..fe2b806a76b 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py @@ -576,6 +576,7 @@ class PaymentReconciliation(Document): "difference_amount": flt(row.get("difference_amount")), "difference_account": row.get("difference_account"), "difference_posting_date": row.get("gain_loss_posting_date"), + "debit_or_credit_note_posting_date": row.get("debit_or_credit_note_posting_date"), "cost_center": row.get("cost_center"), } ) @@ -765,7 +766,7 @@ def reconcile_dr_cr_note(dr_cr_notes, company, active_dimensions=None): { "doctype": "Journal Entry", "voucher_type": voucher_type, - "posting_date": today(), + "posting_date": inv.get("debit_or_credit_note_posting_date") or today(), "company": company, "multi_currency": 1 if inv.currency != company_currency else 0, "accounts": [ diff --git a/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json b/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json index 3f85b213500..e4430de5049 100644 --- a/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json +++ b/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.json @@ -20,6 +20,7 @@ "section_break_5", "difference_amount", "gain_loss_posting_date", + "debit_or_credit_note_posting_date", "column_break_7", "difference_account", "exchange_rate", @@ -168,12 +169,17 @@ { "fieldname": "dimension_col_break", "fieldtype": "Column Break" + }, + { + "fieldname": "debit_or_credit_note_posting_date", + "fieldtype": "Date", + "label": "Debit / Credit Note Posting Date" } ], "is_virtual": 1, "istable": 1, "links": [], - "modified": "2023-12-14 13:38:26.104150", + "modified": "2025-08-20 19:12:50.406769", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Reconciliation Allocation", @@ -183,4 +189,4 @@ "sort_order": "DESC", "states": [], "track_changes": 1 -} \ No newline at end of file +} diff --git a/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.py b/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.py index b57ebecbac2..125ae28f3f5 100644 --- a/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.py +++ b/erpnext/accounts/doctype/payment_reconciliation_allocation/payment_reconciliation_allocation.py @@ -18,6 +18,7 @@ class PaymentReconciliationAllocation(Document): amount: DF.Currency cost_center: DF.Link | None currency: DF.Link | None + debit_or_credit_note_posting_date: DF.Date | None difference_account: DF.Link | None difference_amount: DF.Currency exchange_rate: DF.Float From c52f2c75f6eceab1b03c0f008397883181ab057c Mon Sep 17 00:00:00 2001 From: Hussain Nagaria <34810212+NagariaHussain@users.noreply.github.com> Date: Thu, 21 Aug 2025 18:17:06 +0530 Subject: [PATCH 17/22] feat: show title in link field for Project DocType (#49265) (cherry picked from commit a5f200636a45ee8555cf98c5845faf8b78cf09ea) # Conflicts: # erpnext/projects/doctype/project/project.json --- erpnext/projects/doctype/project/project.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/projects/doctype/project/project.json b/erpnext/projects/doctype/project/project.json index e2613465dd3..a6b8513298c 100644 --- a/erpnext/projects/doctype/project/project.json +++ b/erpnext/projects/doctype/project/project.json @@ -462,7 +462,7 @@ "index_web_pages_for_search": 1, "links": [], "max_attachments": 4, - "modified": "2025-07-03 10:54:30.444139", + "modified": "2025-08-21 17:57:58.314809", "modified_by": "Administrator", "module": "Projects", "name": "Project", @@ -512,6 +512,7 @@ "row_format": "Dynamic", "search_fields": "project_name,customer, status, priority, is_active", "show_name_in_global_search": 1, + "show_title_field_in_link": 1, "sort_field": "modified", "sort_order": "DESC", "states": [], From f231b1e32f89573d09a4d64117bdcc802c438ed6 Mon Sep 17 00:00:00 2001 From: ravibharathi656 Date: Tue, 26 Aug 2025 13:33:26 +0530 Subject: [PATCH 18/22] fix(asset): handle None in depreciation value --- .../asset_depreciation_schedule/asset_depreciation_schedule.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index e1413096af3..1e3c1ffc598 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -456,7 +456,7 @@ class AssetDepreciationSchedule(Document): continue depreciation_amount = flt(depreciation_amount, asset_doc.precision("gross_purchase_amount")) value_after_depreciation = flt( - value_after_depreciation - flt(depreciation_amount), + flt(value_after_depreciation) - flt(depreciation_amount), asset_doc.precision("gross_purchase_amount"), ) From 94cd4549c695c2bffb014ad2981223d08739e3ba Mon Sep 17 00:00:00 2001 From: khushi8112 Date: Tue, 26 Aug 2025 12:35:37 +0530 Subject: [PATCH 19/22] fix: set value for asset owner company field (cherry picked from commit a24f1d056b1f87d5cb92df604910cdcc2940c84d) --- erpnext/assets/doctype/asset/asset.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index 04994acc6ab..e35ebf6ed06 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -322,6 +322,9 @@ class Asset(AccountsController): finance_books = get_item_details(self.item_code, self.asset_category, self.gross_purchase_amount) self.set("finance_books", finance_books) + if self.asset_owner == "Company" and not self.asset_owner_company: + self.asset_owner_company = self.company + def validate_finance_books(self): if not self.calculate_depreciation or len(self.finance_books) == 1: return From aa35770423d313a3958938740d3eda4a67ef8d1b Mon Sep 17 00:00:00 2001 From: CoiledCoder Date: Mon, 25 Aug 2025 02:07:05 +0000 Subject: [PATCH 20/22] fix: correct typo in monthly auto exchange rate revaluation filter The "auto_create_exchange_rate_revaluation_monthly" function was using the wrong filter key `"Montly"` instead of `"Monthly"`. As a result, no companies configured for monthly ERR were being processed. (cherry picked from commit 19729a307fb749b8513e3edece27ede5c22230c5) --- erpnext/accounts/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index baeaca2f354..11df188832f 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -1773,7 +1773,7 @@ def auto_create_exchange_rate_revaluation_monthly() -> None: """ companies = frappe.db.get_all( "Company", - filters={"auto_exchange_rate_revaluation": 1, "auto_err_frequency": "Montly"}, + filters={"auto_exchange_rate_revaluation": 1, "auto_err_frequency": "Monthly"}, fields=["name", "submit_err_jv"], ) create_err_and_its_journals(companies) From 2cb2bdeb002a5cf24a68c7ed5b42a11d6f818d8c Mon Sep 17 00:00:00 2001 From: CoiledCoder Date: Mon, 25 Aug 2025 03:35:55 +0000 Subject: [PATCH 21/22] refactor: centralize exchange rate revaluation scheduling logic - Introduced a private helper `_auto_create_exchange_rate_revaluation_for(frequency)` - Removed duplicate logic across daily, weekly, and monthly ERR functions - Prevents future copy-paste bugs - Keeps existing behavior unchanged (cherry picked from commit 15040a362d244c6eb5aac4ae0c330ee836399ef0) --- erpnext/accounts/utils.py | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 11df188832f..32d4657ea7c 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -1743,40 +1743,38 @@ def create_err_and_its_journals(companies: list | None = None) -> None: jv and frappe.get_doc("Journal Entry", jv).submit() +def _auto_create_exchange_rate_revaluation_for(frequency: str) -> None: + """ + Internal helper to avoid code duplication and typos. + Fetches companies by frequency and triggers ERR. + """ + companies = frappe.db.get_all( + "Company", + filters={"auto_exchange_rate_revaluation": 1, "auto_err_frequency": frequency}, + fields=["name", "submit_err_jv"], + ) + create_err_and_its_journals(companies) + + def auto_create_exchange_rate_revaluation_daily() -> None: """ Executed by background job """ - companies = frappe.db.get_all( - "Company", - filters={"auto_exchange_rate_revaluation": 1, "auto_err_frequency": "Daily"}, - fields=["name", "submit_err_jv"], - ) - create_err_and_its_journals(companies) + _auto_create_exchange_rate_revaluation_for("Daily") def auto_create_exchange_rate_revaluation_weekly() -> None: """ Executed by background job """ - companies = frappe.db.get_all( - "Company", - filters={"auto_exchange_rate_revaluation": 1, "auto_err_frequency": "Weekly"}, - fields=["name", "submit_err_jv"], - ) - create_err_and_its_journals(companies) + _auto_create_exchange_rate_revaluation_for("Weekly") def auto_create_exchange_rate_revaluation_monthly() -> None: """ Executed by background job """ - companies = frappe.db.get_all( - "Company", - filters={"auto_exchange_rate_revaluation": 1, "auto_err_frequency": "Monthly"}, - fields=["name", "submit_err_jv"], - ) - create_err_and_its_journals(companies) + _auto_create_exchange_rate_revaluation_for("Monthly") def get_payment_ledger_entries(gl_entries, cancel=0): From 756216b2cb71b93d347698dbdad7dd77e6f93529 Mon Sep 17 00:00:00 2001 From: l0gesh29 Date: Mon, 25 Aug 2025 13:55:40 +0530 Subject: [PATCH 22/22] fix: handle ple for immutable ledger (cherry picked from commit 48eb4889180473f64e4010dafeb65eb1d4ac21fb) # Conflicts: # erpnext/accounts/general_ledger.py # erpnext/accounts/utils.py --- erpnext/accounts/general_ledger.py | 6 +----- erpnext/accounts/utils.py | 11 ++++++++++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py index 0e97d6969bd..7df3bce9b4a 100644 --- a/erpnext/accounts/general_ledger.py +++ b/erpnext/accounts/general_ledger.py @@ -18,7 +18,7 @@ from erpnext.accounts.doctype.accounting_dimension_filter.accounting_dimension_f ) from erpnext.accounts.doctype.accounting_period.accounting_period import ClosedAccountingPeriod from erpnext.accounts.doctype.budget.budget import validate_expense_against_budget -from erpnext.accounts.utils import create_payment_ledger_entry +from erpnext.accounts.utils import create_payment_ledger_entry, is_immutable_ledger_enabled from erpnext.exceptions import InvalidAccountDimensionError, MandatoryAccountDimensionError @@ -838,7 +838,3 @@ def validate_allowed_dimensions(gl_entry, dimension_filter_map): ), InvalidAccountDimensionError, ) - - -def is_immutable_ledger_enabled(): - return frappe.db.get_single_value("Accounts Settings", "enable_immutable_ledger") diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 32d4657ea7c..15117b2aa43 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -1895,6 +1895,9 @@ def create_payment_ledger_entry( if cancel: delink_original_entry(ple, partial_cancel=partial_cancel) + if is_immutable_ledger_enabled(): + ple.delinked = 0 + ple.posting_date = frappe.form_dict.get("posting_date") or getdate() ple.flags.ignore_permissions = 1 ple.flags.adv_adj = adv_adj @@ -1982,7 +1985,6 @@ def delink_original_entry(pl_entry, partial_cancel=False): ple = qb.DocType("Payment Ledger Entry") query = ( qb.update(ple) - .set(ple.delinked, True) .set(ple.modified, now()) .set(ple.modified_by, frappe.session.user) .where( @@ -2001,6 +2003,9 @@ def delink_original_entry(pl_entry, partial_cancel=False): if partial_cancel: query = query.where(ple.voucher_detail_no == pl_entry.voucher_detail_no) + if not is_immutable_ledger_enabled(): + query = query.set(ple.delinked, True) + query.run() @@ -2457,3 +2462,7 @@ def build_qb_match_conditions(doctype, user=None) -> list: criterion.append(cond) return criterion + + +def is_immutable_ledger_enabled(): + return frappe.get_single_value("Accounts Settings", "enable_immutable_ledger")