From 78aa4cf9f9a3461e4eda8a420973a78500610c33 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Tue, 3 Mar 2026 17:57:53 +0000 Subject: [PATCH 01/10] chore(release): Bumped to Version 16.8.0 # [16.8.0](https://github.com/frappe/erpnext/compare/v16.7.3...v16.8.0) (2026-03-03) ### Bug Fixes * `Trial Balance` and `Consolidated Trial Balance` total row calculation (backport [#53014](https://github.com/frappe/erpnext/issues/53014)) ([#53015](https://github.com/frappe/erpnext/issues/53015)) ([8658956](https://github.com/frappe/erpnext/commit/865895649e7f70219f7a753d933ce568b02fbf6e)) * **accounts receivable:** include invoice payment terms template (backport [#51940](https://github.com/frappe/erpnext/issues/51940)) ([#53106](https://github.com/frappe/erpnext/issues/53106)) ([7e09bf3](https://github.com/frappe/erpnext/commit/7e09bf306ad7aa0fad529d8d149116964d2d1825)) * **accounts:** add transaction time field ([2526876](https://github.com/frappe/erpnext/commit/2526876eaa2bc38eeb9b4117215d5e5a9de2bd82)) * **accounts:** compute tax net_amount in JS controller ([429bd24](https://github.com/frappe/erpnext/commit/429bd245d15dc26da71fa32ff2fef48c1bf1082f)) * **accounts:** round and convert net_amount to company currency in JS tax controller ([3f284f0](https://github.com/frappe/erpnext/commit/3f284f0c55a64284e9c327c14199d734306ea2db)) * **accounts:** set posting time to get incoming rate ([8b3c5ba](https://github.com/frappe/erpnext/commit/8b3c5baa9e8608d9f38ec9560724b383dea62276)) * allow allowed roles to bypass over billing validation ([c274b7c](https://github.com/frappe/erpnext/commit/c274b7cc2e25b5be6e0b0ef57e9ab44e5cf1eb33)) * avoid circular dependency ([#53109](https://github.com/frappe/erpnext/issues/53109)) ([7d950f7](https://github.com/frappe/erpnext/commit/7d950f71dacd6d0dfeeda94fb67f85aa2fc9148c)) * broekn link of docs in asset onboarding ([5c48f74](https://github.com/frappe/erpnext/commit/5c48f74d4c1a833f40e6eca37de087080ebb2b49)) * **budget-variance-report:** validate 'budget_against' filter ([f2ff0de](https://github.com/frappe/erpnext/commit/f2ff0de296f45c0e6af4f3b50e2fbaf01ec23ba9)) * correct sle voucher_type comparison in get_ref_doctype ([788cd82](https://github.com/frappe/erpnext/commit/788cd82b4b5f504bb5c27c26c2c549e7e9376b0e)) * ensure cache is cleared on fiscal year update and trash ([2495cb8](https://github.com/frappe/erpnext/commit/2495cb8b2aca77eae8973bd2d3d5da3946b238f2)) * ensure contacts are processed only if present in create_prospect_against_crm_deal ([58fbb2f](https://github.com/frappe/erpnext/commit/58fbb2f4d7d5193b1351b8ec75f79f50e7a15240)) * handle html email template separately in RFQ to avoid jinja context error ([3178736](https://github.com/frappe/erpnext/commit/317873621a0bedc2298cae80cd36497560bb5f6a)) * **manufacturing:** ignore sales order validation for subassembly item ([2daf9f4](https://github.com/frappe/erpnext/commit/2daf9f4ce7d8a7c8535c2da287412cce3d78569b)) * old stock reco entries causing issue in the stock balance report ([ea5ad31](https://github.com/frappe/erpnext/commit/ea5ad3179cf4a4601f8035b0b8ef7df8a3362b22)) * opening qty in stock balance ([1f2342c](https://github.com/frappe/erpnext/commit/1f2342cf4be44182eb268b99c95af99b7729344d)) * pass company in test case using make_quality_inspections ([417e8a4](https://github.com/frappe/erpnext/commit/417e8a43718f7156891abbbadfedec066ce64445)) * patch to complete onboarding stpes for existing records ([941a78e](https://github.com/frappe/erpnext/commit/941a78e1a8d2932bb15c022d05739cfc5bcf2eac)) * **payment entry:** round unallocated amount ([b76e0c6](https://github.com/frappe/erpnext/commit/b76e0c645b270715c3cebf6a29a5be992306be82)) * **payment_entry:** fix precision for `total_allocated_amount` and `base_total_allocated_amount` ([c61c748](https://github.com/frappe/erpnext/commit/c61c748cbd21eb84725c9e8425884a4d330fc8cc)) * populate mr owner and set po owner as fallback ([acdb8f2](https://github.com/frappe/erpnext/commit/acdb8f2b784142dc44af5881bdfb96be90c3ead5)) * **postgres:** avoid UNSIGNED cast in customer autoname ([d922213](https://github.com/frappe/erpnext/commit/d922213dd78cdf5d2caa432e41189e8b14abe023)) * **pricing_rule:** strict validation of `transaction_type` ([396727e](https://github.com/frappe/erpnext/commit/396727e26f5dbef7e203df9ffdd0f8f8dddee7b0)) * remove read-only property from Sales Invoice Timesheet Table ([f632c5c](https://github.com/frappe/erpnext/commit/f632c5c79689969a63190c8884cad75dbab75185)) * reposting creation slow for GL entries ([ab7e33f](https://github.com/frappe/erpnext/commit/ab7e33f83dacb15e1d672633d6955132048b84cd)) * same reposting entry picked by multiple rq jobs ([c28568f](https://github.com/frappe/erpnext/commit/c28568f4fd026be07f20a80f954bd7f3e3886f25)) * **selling:** handle selling price validation for FG item ([c7928a0](https://github.com/frappe/erpnext/commit/c7928a074934465af4474ca5d1901c5cc9d4e8e7)) * serial no status for Disassemble entry ([dc0592a](https://github.com/frappe/erpnext/commit/dc0592a9057c08982c988d3bfd22e26c81a8e81f)) * set company based expense account ([25c134d](https://github.com/frappe/erpnext/commit/25c134d11ce6a50b1786b4f5194340581e2aec2b)) * **stock:** pass company to avoid document naming rule issue in QI ([d61ad3b](https://github.com/frappe/erpnext/commit/d61ad3bd95a14dc432512722bf2b77d415a561f9)) * **stock:** validate company for receipt documents and expense accounts ([c6e0eb6](https://github.com/frappe/erpnext/commit/c6e0eb6d179c11a8765eff40f1c94e259d509ed5)) * use conversion factor when creating stock entry from pick list ([f939e98](https://github.com/frappe/erpnext/commit/f939e980a693e296656e126610837469dca421c3)) * use stock qty instead of qty when creating stock entry from MR ([1e44787](https://github.com/frappe/erpnext/commit/1e4478765a605756a64276127af25e8c33bed5d6)) * use the correct precision value in stock reco ([c92fd26](https://github.com/frappe/erpnext/commit/c92fd26e1b1ade9bed96b3197094767b4b26306b)) * validate warehouse of SABB for draft entry ([b8de82f](https://github.com/frappe/erpnext/commit/b8de82f0e47b5deed275919336717ba8cb220cf6)) * voucher detail no in SABB ([744d7a2](https://github.com/frappe/erpnext/commit/744d7a2793abeb5a5dff836618499d84243043e6)) ### Features * UOM query filter for opportunity items ([6727c86](https://github.com/frappe/erpnext/commit/6727c86d0a762a084d764e507f5d3a590d5eebc6)) ### Performance Improvements * add index on reference_purchase_receipt column ([664f1f1](https://github.com/frappe/erpnext/commit/664f1f1675b45f7e17c48a5a7209cb248ac755ca)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index cd0d56fca5f..8d12047a5ac 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -6,7 +6,7 @@ import frappe from frappe.model.document import Document from frappe.utils.user import is_website_user -__version__ = "16.7.3" +__version__ = "16.8.0" def get_default_company(user=None): From 354723d3d5c2767f6e723124bdf0217b8b5898e8 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 17 Feb 2026 17:58:44 +0530 Subject: [PATCH 02/10] fix: balance qty for inv dimension (cherry picked from commit a3eafe5b188ee160bc8507d298f987cb1ec4b894) (cherry picked from commit fb17a00fb625be17f9dd4cecb87a51a80b6f307f) --- .../stock/report/stock_ledger/stock_ledger.py | 153 +++++++++++++++++- erpnext/stock/stock_ledger.py | 3 + 2 files changed, 148 insertions(+), 8 deletions(-) diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py index 8e37799e8ce..225d9010592 100644 --- a/erpnext/stock/report/stock_ledger/stock_ledger.py +++ b/erpnext/stock/report/stock_ledger/stock_ledger.py @@ -27,10 +27,23 @@ def execute(filters=None): items = get_items(filters) sl_entries = get_stock_ledger_entries(filters, items) item_details = get_item_details(items, sl_entries, include_uom) + + inv_dimension_key = [] + inv_dimension_wise_value = get_inv_dimension_wise_value(filters) + if inv_dimension_wise_value: + for key in inv_dimension_wise_value: + value = inv_dimension_wise_value[key] + if isinstance(value, list): + inv_dimension_key.extend(value) + else: + inv_dimension_key.append(value) + if filters.get("batch_no"): opening_row = get_opening_balance_from_batch(filters, columns, sl_entries) + elif inv_dimension_wise_value: + opening_row = get_opening_balance_for_inv_dimension(filters, inv_dimension_wise_value) else: - opening_row = get_opening_balance(filters, columns, sl_entries) + opening_row = get_opening_balance(filters, columns, sl_entries, inv_dimension_wise_value) precision = cint(frappe.db.get_single_value("System Settings", "float_precision")) bundle_details = {} @@ -50,12 +63,16 @@ def execute(filters=None): stock_value = opening_row.get("stock_value") available_serial_nos = {} - inventory_dimension_filters_applied = check_inventory_dimension_filters_applied(filters) batch_balance_dict = frappe._dict({}) if actual_qty and filters.get("batch_no"): batch_balance_dict[filters.batch_no] = [actual_qty, stock_value] + inv_dimension_wise_dict = frappe._dict({}) + set_opening_row_for_inv_dimension( + inv_dimension_wise_dict, filters, inv_dimension_key=inv_dimension_key, opening_row=opening_row + ) + for sle in sl_entries: item_detail = item_details[sle.item_code] @@ -64,7 +81,10 @@ def execute(filters=None): data.extend(get_segregated_bundle_entries(sle, bundle_info, batch_balance_dict, filters)) continue - if filters.get("batch_no") or inventory_dimension_filters_applied: + if inv_dimension_key: + set_balance_value_for_inv_dimesion(inv_dimension_key, inv_dimension_wise_dict, sle) + + if filters.get("batch_no"): actual_qty += flt(sle.actual_qty, precision) stock_value += sle.stock_value_difference if sle.batch_no: @@ -103,6 +123,50 @@ def execute(filters=None): return columns, data +def set_opening_row_for_inv_dimension( + inv_dimension_wise_dict, filters, inv_dimension_key=None, opening_row=None +): + if ( + not inv_dimension_key + or not opening_row + or not filters.get("item_code") + or not filters.get("warehouse") + ): + return + + if len(filters.get("item_code")) > 1 or len(filters.get("warehouse")) > 1: + return + + if inv_dimension_key and opening_row and filters.get("item_code") and filters.get("warehouse"): + new_key = copy.deepcopy(inv_dimension_key) + new_key.extend([filters.item_code[0], filters.warehouse[0]]) + + opening_key = tuple(new_key) + inv_dimension_wise_dict[opening_key] = { + "qty_after_transaction": flt(opening_row.get("qty_after_transaction")), + "dimension_stock_value": flt(opening_row.get("stock_value")), + } + + +def set_balance_value_for_inv_dimesion(inv_dimension_key, inv_dimension_wise_dict, sle): + new_key = copy.deepcopy(inv_dimension_key) + new_key.extend([sle.item_code, sle.warehouse]) + new_key = tuple(new_key) + + if new_key not in inv_dimension_wise_dict: + inv_dimension_wise_dict[new_key] = {"qty_after_transaction": 0, "dimension_stock_value": 0} + + inv_dimesion_value = inv_dimension_wise_dict[new_key] + inv_dimesion_value["qty_after_transaction"] += sle.actual_qty + inv_dimesion_value["dimension_stock_value"] += sle.stock_value_difference + sle.update( + { + "qty_after_transaction": inv_dimesion_value["qty_after_transaction"], + "stock_value": inv_dimesion_value["dimension_stock_value"], + } + ) + + def get_segregated_bundle_entries(sle, bundle_details, batch_balance_dict, filters): segregated_entries = [] qty_before_transaction = sle.qty_after_transaction - sle.actual_qty @@ -605,19 +669,26 @@ def get_opening_balance_from_batch(filters, columns, sl_entries): } -def get_opening_balance(filters, columns, sl_entries): +def get_opening_balance(filters, columns, sl_entries, inv_dimension_wise_value=None): if not (filters.item_code and filters.warehouse and filters.from_date): return from erpnext.stock.stock_ledger import get_previous_sle + project = None + if filters.get("project") and not frappe.get_all( + "Inventory Dimension", filters={"reference_document": "Project"} + ): + project = filters.get("project") + last_entry = get_previous_sle( { "item_code": filters.item_code, "warehouse_condition": get_warehouse_condition(filters.warehouse), "posting_date": filters.from_date, "posting_time": "00:00:00", - } + "project": project, + }, ) # check if any SLEs are actually Opening Stock Reconciliation @@ -689,9 +760,75 @@ def get_item_group_condition(item_group, item_table=None): where ig.lft >= {item_group_details.lft} and ig.rgt <= {item_group_details.rgt} and item.item_group = ig.name)" -def check_inventory_dimension_filters_applied(filters) -> bool: +def get_opening_balance_for_inv_dimension(filters, inv_dimension_wise_value): + if not filters.item_code or not filters.warehouse or not filters.from_date: + return + + if len(filters.get("item_code")) > 1 or len(filters.get("warehouse")) > 1: + return + + sl_doctype = frappe.qb.DocType("Stock Ledger Entry") + + query = ( + frappe.qb.from_(sl_doctype) + .select( + sl_doctype.item_code, + sl_doctype.warehouse, + Sum(sl_doctype.actual_qty).as_("qty_after_transaction"), + Sum(sl_doctype.stock_value_difference).as_("stock_value"), + ) + .where( + (sl_doctype.posting_date < filters.from_date) + & (sl_doctype.docstatus < 2) + & (sl_doctype.is_cancelled == 0) + ) + ) + + if filters.get("item_code"): + if isinstance(filters.item_code, list | tuple): + query = query.where(sl_doctype.item_code.isin(filters.item_code)) + else: + query = query.where(sl_doctype.item_code == filters.item_code) + + if filters.get("warehouse"): + if isinstance(filters.warehouse, list | tuple): + query = query.where(sl_doctype.warehouse.isin(filters.warehouse)) + else: + query = query.where(sl_doctype.warehouse == filters.warehouse) + + for key, value in inv_dimension_wise_value.items(): + if isinstance(value, list | tuple): + query = query.where(sl_doctype[key].isin(value)) + else: + query = query.where(sl_doctype[key] == value) + + opening_data = query.run(as_dict=True) + + if opening_data: + return frappe._dict( + { + "item_code": _("'Opening'"), + "qty_after_transaction": opening_data[0].qty_after_transaction, + "stock_value": opening_data[0].stock_value, + "valuation_rate": flt(opening_data[0].stock_value) + / flt(opening_data[0].qty_after_transaction) + if opening_data[0].qty_after_transaction + else 0, + } + ) + + return frappe._dict({}) + + +def get_inv_dimension_wise_value(filters) -> list: + inv_dimension_key = frappe._dict({}) for dimension in get_inventory_dimensions(): if dimension.fieldname in filters and filters.get(dimension.fieldname): - return True + inv_dimension_key[dimension.fieldname] = filters.get(dimension.fieldname) - return False + if filters.get("project") and not frappe.get_all( + "Inventory Dimension", filters={"reference_document": "Project"} + ): + inv_dimension_key["project"] = filters.get("project") + + return inv_dimension_key diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index d1bad37a9cc..43ac974a88b 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -1862,6 +1862,9 @@ def get_stock_ledger_entries( if extra_cond: conditions += f"{extra_cond}" + if previous_sle.get("project"): + conditions += " and project = %(project)s" + # nosemgrep return frappe.db.sql( """ From 0ab7a6e9047f304c89011e935cf705a1790863b0 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Thu, 5 Mar 2026 11:58:55 +0000 Subject: [PATCH 03/10] chore(release): Bumped to Version 16.8.1 ## [16.8.1](https://github.com/frappe/erpnext/compare/v16.8.0...v16.8.1) (2026-03-05) ### Bug Fixes * balance qty for inv dimension ([354723d](https://github.com/frappe/erpnext/commit/354723d3d5c2767f6e723124bdf0217b8b5898e8)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 8d12047a5ac..3abfea3cc9a 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -6,7 +6,7 @@ import frappe from frappe.model.document import Document from frappe.utils.user import is_website_user -__version__ = "16.8.0" +__version__ = "16.8.1" def get_default_company(user=None): From 9e185b7ea94624a8da79d899cb37b3692723e8ce Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Fri, 6 Mar 2026 10:34:24 +0530 Subject: [PATCH 04/10] fix: stock balance report qty (cherry picked from commit a15e5fdc4eea302970e3790caf71c69163bf3306) (cherry picked from commit 699a683b8ef7b8b70752da16e8edba5f7de6695b) --- .../report/stock_balance/stock_balance.py | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py index ed0c31c07d9..7d96d6a6d6b 100644 --- a/erpnext/stock/report/stock_balance/stock_balance.py +++ b/erpnext/stock/report/stock_balance/stock_balance.py @@ -230,6 +230,36 @@ class StockBalanceReport: .groupby(doctype.voucher_detail_no) ) + if items := self.filters.item_code: + if isinstance(items, str): + items = [items] + + query = query.where(item.name.isin(items)) + + if self.filters.item_group: + childrens = [] + childrens.append(self.filters.item_group) + if item_group_childrens := get_descendants_of( + "Item Group", self.filters.item_group, ignore_permissions=True + ): + childrens.extend(item_group_childrens) + + if childrens: + query = query.where(item.item_group.isin(childrens)) + + if warehouses := self.filters.get("warehouse"): + if isinstance(warehouses, str): + warehouses = [warehouses] + + childrens = [] + for warehouse in warehouses: + childrens.append(warehouse) + if warehouse_childrens := get_descendants_of("Warehouse", warehouse, ignore_permissions=True): + childrens.extend(warehouse_childrens) + + if childrens: + query = query.where(doctype.warehouse.isin(childrens)) + data = query.run(as_dict=True) if not data: return @@ -238,10 +268,12 @@ class StockBalanceReport: if row.count != 1: continue - current_qty = frappe.db.get_value( - "Stock Reconciliation Item", row.voucher_detail_no, "current_qty" + sr_item = frappe.db.get_value( + "Stock Reconciliation Item", row.voucher_detail_no, ["current_qty", "qty"], as_dict=True ) - self.stock_reco_voucher_wise_count[row.voucher_detail_no] = current_qty + + if sr_item.qty and sr_item.current_qty: + self.stock_reco_voucher_wise_count[row.voucher_detail_no] = sr_item.current_qty def prepare_new_data(self): if self.filters.get("show_stock_ageing_data"): From c39ee769466863be5ad6aa1c6fa2d5a6432d9755 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Fri, 6 Mar 2026 08:35:12 +0000 Subject: [PATCH 05/10] chore(release): Bumped to Version 16.8.2 ## [16.8.2](https://github.com/frappe/erpnext/compare/v16.8.1...v16.8.2) (2026-03-06) ### Bug Fixes * stock balance report qty ([9e185b7](https://github.com/frappe/erpnext/commit/9e185b7ea94624a8da79d899cb37b3692723e8ce)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 3abfea3cc9a..bda51bbd19b 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -6,7 +6,7 @@ import frappe from frappe.model.document import Document from frappe.utils.user import is_website_user -__version__ = "16.8.1" +__version__ = "16.8.2" def get_default_company(user=None): From 7149630eff1a9b57b43f0f92167e07fcebe7c062 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 10 Mar 2026 11:44:02 +0530 Subject: [PATCH 06/10] fix: patch failing (cherry picked from commit 6024c4a077caf5d00fe4017f8a6048953a7253b3) (cherry picked from commit 1a62d324fd7cc4a0eed881bd900d2578ef2e4885) --- .../patches/v16_0/complete_onboarding_steps_for_older_sites.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/patches/v16_0/complete_onboarding_steps_for_older_sites.py b/erpnext/patches/v16_0/complete_onboarding_steps_for_older_sites.py index 73d50a976ee..7230334266e 100644 --- a/erpnext/patches/v16_0/complete_onboarding_steps_for_older_sites.py +++ b/erpnext/patches/v16_0/complete_onboarding_steps_for_older_sites.py @@ -13,6 +13,9 @@ def execute(): return company_creation = frappe.get_all("Company", fields=["creation"], order_by="creation asc", limit=1) + if not company_creation: + return + days_diff = date_diff(getdate(today()), getdate(company_creation[0].creation)) if days_diff > 15: From a7eb24488eaec1667c81b108047b56ae7ea5fc24 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Tue, 10 Mar 2026 06:45:58 +0000 Subject: [PATCH 07/10] chore(release): Bumped to Version 16.8.3 ## [16.8.3](https://github.com/frappe/erpnext/compare/v16.8.2...v16.8.3) (2026-03-10) ### Bug Fixes * patch failing ([7149630](https://github.com/frappe/erpnext/commit/7149630eff1a9b57b43f0f92167e07fcebe7c062)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index bda51bbd19b..51d4643fd87 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -6,7 +6,7 @@ import frappe from frappe.model.document import Document from frappe.utils.user import is_website_user -__version__ = "16.8.2" +__version__ = "16.8.3" def get_default_company(user=None): From c791d2853a0f3914141239f4f8bdd03e5c8a96ad Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Tue, 10 Mar 2026 14:59:58 +0000 Subject: [PATCH 08/10] chore(release): Bumped to Version 16.9.0 # [16.9.0](https://github.com/frappe/erpnext/compare/v16.8.3...v16.9.0) (2026-03-10) ### Bug Fixes * add clear demo data in sidebar ([8e8a7b2](https://github.com/frappe/erpnext/commit/8e8a7b26866c149ac0f033ce9ddee2c2190cdf3e)) * add clear demo data in sidebar (backport [#53177](https://github.com/frappe/erpnext/issues/53177)) ([#53197](https://github.com/frappe/erpnext/issues/53197)) ([12ccc38](https://github.com/frappe/erpnext/commit/12ccc3881bfc02ade5bb8f8ef69630a2a2ee2cfa)) * allow payment_request to be created in draft ([29d565b](https://github.com/frappe/erpnext/commit/29d565b9de0deb831074685b064d70c191d6c675)) * allow user to make QI after submission not working ([6fdb5d4](https://github.com/frappe/erpnext/commit/6fdb5d486a9466b876eb4ae420ebe4806ead80bf)) * balance qty for inv dimension ([fb17a00](https://github.com/frappe/erpnext/commit/fb17a00fb625be17f9dd4cecb87a51a80b6f307f)) * better validation message for Purchase Invoice with Update Stock ([839f5f6](https://github.com/frappe/erpnext/commit/839f5f6a29ff7ccab59c504740af7e1d0d549c1f)) * bom UX issues ([733191e](https://github.com/frappe/erpnext/commit/733191eae23dd016d276e741a25f36bf3edfc108)) * consider payment term only when enabled ([1470a79](https://github.com/frappe/erpnext/commit/1470a79a1b394cbe780d0f6065f38e6a7363e704)) * disallow all actions on job card if work order is closed ([57aab56](https://github.com/frappe/erpnext/commit/57aab56baa53be732c063e0c259693ad500ab41c)) * do not update fg_completed_qty when changing qty of fg line item ([8463cf8](https://github.com/frappe/erpnext/commit/8463cf88df8103cd47d6430f6e650b6957d85eff)) * fetch payment terms from quotation ([b2f6953](https://github.com/frappe/erpnext/commit/b2f695310c3356f1eed0859bcbf2ecdc4bd17d2f)) * **gross-profit:** apply precision-based rounding to grouped totals ([c6e01aa](https://github.com/frappe/erpnext/commit/c6e01aa1ebe3ee0cc7d60518d2905f6ee741fa4f)) * handle payment terms template when disabled ([80c2053](https://github.com/frappe/erpnext/commit/80c20531aa8d98c44fd92bfe3af52ce1c860bbb6)) * **help:** escape query (backport [#53192](https://github.com/frappe/erpnext/issues/53192)) ([#53195](https://github.com/frappe/erpnext/issues/53195)) ([83f2fad](https://github.com/frappe/erpnext/commit/83f2fadbcffc4461fc6648a150883bc88e70f626)) * HRMS test cases failing due to validation in item ([10538d5](https://github.com/frappe/erpnext/commit/10538d58adf089e8b2d21e0c8072269a61488478)) * implement coderabbit suggested changes ([b619f6d](https://github.com/frappe/erpnext/commit/b619f6d9065f1b497b804254ecef2046d1d4f5aa)) * **manufacturing:** show returned qty in progress bar ([f853ef9](https://github.com/frappe/erpnext/commit/f853ef9fec488f6b2606cda52b20f49181e1d1dc)) * migration patch ([7b44e41](https://github.com/frappe/erpnext/commit/7b44e412d90bd7a079f920413441d7afeb17db7f)) * patch failing ([1a62d32](https://github.com/frappe/erpnext/commit/1a62d324fd7cc4a0eed881bd900d2578ef2e4885)) * patch to migrate checkbox data into select ([4d0e28a](https://github.com/frappe/erpnext/commit/4d0e28a6083a1d913e2502839cd2cdfcf947b2c5)) * **project template:** clear subject when task is empty ([c8560fa](https://github.com/frappe/erpnext/commit/c8560fa0d3b5672601bd340d3870499436a8557e)) * removed non existent patch ([77ec678](https://github.com/frappe/erpnext/commit/77ec67869c2471b5ec397e383da3cc04af184528)) * **selling:** update delivery date in line items ([6b42a7e](https://github.com/frappe/erpnext/commit/6b42a7e45447791418d86035514ce0731274e5f0)) * set default list view columns and filters for sales, purchase and accounts module ([f9a3869](https://github.com/frappe/erpnext/commit/f9a38696b68ffd976e6d744af65ec2b488727fba)) * set default to 1 ([3b7410f](https://github.com/frappe/erpnext/commit/3b7410f2d367794687458aafabd3a0f954ee0230)) * skip asset sale processing for internal transfer invoices ([12cfd8e](https://github.com/frappe/erpnext/commit/12cfd8e05265cca702e9ada8aa383346727d06fd)) * stock balance report qty ([699a683](https://github.com/frappe/erpnext/commit/699a683b8ef7b8b70752da16e8edba5f7de6695b)) * **task:** allow is_template field in quick entry ([2ccf8d0](https://github.com/frappe/erpnext/commit/2ccf8d050f9e3690a29cfcc2608edfaabadacb42)) * test case ([27c3c1d](https://github.com/frappe/erpnext/commit/27c3c1dee0e6520a9e43814720b3626a6e23efe2)) * test cases fixes related to new select box change ([3f11d0b](https://github.com/frappe/erpnext/commit/3f11d0b8ad02ecbfdfea73b8db3e940bc7121824)) * **UI:** improve asset action buttons group ([78074c0](https://github.com/frappe/erpnext/commit/78074c0cdd479e0e9a0a20447df0f3e0864e20df)) * **UI:** reposition fields for better UX ([6c23d5b](https://github.com/frappe/erpnext/commit/6c23d5b682ce8e949c6fd18492d2b01fa7a3ad8c)) * update user status depends on employee status ([c7da8e2](https://github.com/frappe/erpnext/commit/c7da8e24716d5d9aac231d19d21f85d0f784e797)) * updating costing based on employee change in timesheet ([d251c94](https://github.com/frappe/erpnext/commit/d251c94ea31ecd9d250a7e2e6055f2e31ca37482)) * validation for cancellation ([8f02184](https://github.com/frappe/erpnext/commit/8f02184c80bb16d56e56bb8378af88fe627085fe)) * WO produced qty should be calculated using finished item child table transfer qty ([78fa2c5](https://github.com/frappe/erpnext/commit/78fa2c5477e8eb5ce2c52098beb294d954e82475)) ### Features * allowing rate modification in update item in quotation ([69b2170](https://github.com/frappe/erpnext/commit/69b217065c9b9b2e158406536494d50bf170f8c4)) * **manufacturing:** show disassembled qty in progress bar ([38e5d29](https://github.com/frappe/erpnext/commit/38e5d295c709a8552386090f37821177876b315c)) * option to enable serial / batch features ([93a5974](https://github.com/frappe/erpnext/commit/93a597410e79f7425a83a1bde4d656a9631cd6c1)) * organization desktop icon ([e89aaca](https://github.com/frappe/erpnext/commit/e89aaca87034f63fb1bc6252c7be212c2917a41b)) * **selling-settings:** add checkbox to recalculate payment date ([f7dd730](https://github.com/frappe/erpnext/commit/f7dd730bc3a2ecde73c2292e155bd01c6e8291af)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 51d4643fd87..0c5570a7f7e 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -6,7 +6,7 @@ import frappe from frappe.model.document import Document from frappe.utils.user import is_website_user -__version__ = "16.8.3" +__version__ = "16.9.0" def get_default_company(user=None): From 253e7a9398ffc403747644054bc46a7cfe945915 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Sun, 15 Mar 2026 13:50:34 +0530 Subject: [PATCH 09/10] fix: add validation in bom creator function (backport #53364) (#53463) * fix: add validation in bom creator function (#53364) (cherry picked from commit 9c0c39381f883c18124d44d0d8bd7aad06a12316) # Conflicts: # erpnext/manufacturing/doctype/bom_creator/bom_creator.py * chore: resolve conflict --------- Co-authored-by: Mihir Kandoi Co-authored-by: diptanilsaha --- erpnext/manufacturing/doctype/bom_creator/bom_creator.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/erpnext/manufacturing/doctype/bom_creator/bom_creator.py b/erpnext/manufacturing/doctype/bom_creator/bom_creator.py index b8d322f9463..e071dadb998 100644 --- a/erpnext/manufacturing/doctype/bom_creator/bom_creator.py +++ b/erpnext/manufacturing/doctype/bom_creator/bom_creator.py @@ -561,7 +561,10 @@ def delete_node(**kwargs): @frappe.whitelist() -def edit_bom_creator(doctype, docname, data, parent): +def edit_bom_creator(doctype: str, docname: str, data: str | dict, parent: str): + if not frappe.has_permission(doctype=doctype, ptype="write", parent_doctype="BOM Creator"): + frappe.throw(_("You do not have permission to edit this document"), frappe.PermissionError) + if isinstance(data, str): data = frappe.parse_json(data) From 99a81db4d938d27d13d3c79284a66370eb3ed27e Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Sun, 15 Mar 2026 08:22:01 +0000 Subject: [PATCH 10/10] chore(release): Bumped to Version 16.9.1 ## [16.9.1](https://github.com/frappe/erpnext/compare/v16.9.0...v16.9.1) (2026-03-15) ### Bug Fixes * add validation in bom creator function (backport [#53364](https://github.com/frappe/erpnext/issues/53364)) ([#53463](https://github.com/frappe/erpnext/issues/53463)) ([253e7a9](https://github.com/frappe/erpnext/commit/253e7a9398ffc403747644054bc46a7cfe945915)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 0c5570a7f7e..b1f745b986b 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -6,7 +6,7 @@ import frappe from frappe.model.document import Document from frappe.utils.user import is_website_user -__version__ = "16.9.0" +__version__ = "16.9.1" def get_default_company(user=None):