From 2574c4c18c2530147310151051c860a515811891 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Tue, 3 Mar 2026 17:57:48 +0000 Subject: [PATCH 01/37] chore(release): Bumped to Version 15.100.0 # [15.100.0](https://github.com/frappe/erpnext/compare/v15.99.1...v15.100.0) (2026-03-03) ### Bug Fixes * **accounts receivable:** include invoice payment terms template (backport [#51940](https://github.com/frappe/erpnext/issues/51940)) ([#53105](https://github.com/frappe/erpnext/issues/53105)) ([f5f40db](https://github.com/frappe/erpnext/commit/f5f40dbcc3cbda588c42344ff429745ef4d2b647)) * allow allowed roles to bypass over billing validation ([8e59fe9](https://github.com/frappe/erpnext/commit/8e59fe90cc6d2af7f4b2e1c6e2d5a95444738719)) * correct sle voucher_type comparison in get_ref_doctype ([a587b6a](https://github.com/frappe/erpnext/commit/a587b6a57c8c53c55cfe53341146db3e11981eda)) * ensure cache is cleared on fiscal year update and trash ([7278166](https://github.com/frappe/erpnext/commit/7278166b2c5caa88a13f7b052d52d4b2127b5d3b)) * ensure contacts are processed only if present in create_prospect_against_crm_deal ([e2b6179](https://github.com/frappe/erpnext/commit/e2b6179b17998e5f180f8966ead5a7cd6ae523b2)) * handle html email template separately in RFQ to avoid jinja context error ([90169a3](https://github.com/frappe/erpnext/commit/90169a39bbc787fd4774ce5b69f7dfeabc8de715)) * item description html validation error ([3c6a120](https://github.com/frappe/erpnext/commit/3c6a120c5c041fc1f40753520560f160a6dd8696)) * old stock reco entries causing issue in the stock balance report ([b712467](https://github.com/frappe/erpnext/commit/b7124670491f1f5a7cdeb2dd2becf231fa6c6ea6)) * opening qty in stock balance ([470a9b3](https://github.com/frappe/erpnext/commit/470a9b38b1e08bad784827d4383a9d64b294dd58)) * **payment entry:** round unallocated amount ([76a1907](https://github.com/frappe/erpnext/commit/76a19076bf50cdf5d8629d58d78649cc1f8870b8)) * populate mr owner and set po owner as fallback ([c1f2991](https://github.com/frappe/erpnext/commit/c1f29916941ce5d4f0233ea6809bf907c56cc4d9)) * **pricing_rule:** strict validation of `transaction_type` ([5f82db2](https://github.com/frappe/erpnext/commit/5f82db200e91bf703dfbaf5cb07e0325c6c2239e)) * resolve conflicts ([6846f02](https://github.com/frappe/erpnext/commit/6846f02cea8bc2bbf12dcd36d3f946e45de87fd7)) * **selling:** handle selling price validation for FG item ([d5cc51b](https://github.com/frappe/erpnext/commit/d5cc51b426984a34b1ed654f81ea880a8473dc4f)) * serial no status for Disassemble entry ([8ce541b](https://github.com/frappe/erpnext/commit/8ce541bf46cf3265b2697454086f1327a33d1224)) * set company based expense account ([74e71f3](https://github.com/frappe/erpnext/commit/74e71f386807bc87a92a5c9176cdd5925198749d)) * **stock:** validate company for receipt documents and expense accounts ([4462088](https://github.com/frappe/erpnext/commit/44620884c1ca89bf62798b15148a75834278e489)) * **trial-balance:** totals with filter `show_group_accounts` enabled ([eabaef2](https://github.com/frappe/erpnext/commit/eabaef2f0b68336e4af405c63f49194e58670802)) * use conversion factor when creating stock entry from pick list ([f2e1482](https://github.com/frappe/erpnext/commit/f2e1482f63305de05ac83a3b04b4bc84be1198ed)) * use stock qty instead of qty when creating stock entry from MR ([2984f79](https://github.com/frappe/erpnext/commit/2984f79a69026d2d7a9488625bb3233e3679fa48)) * use the correct precision value in stock reco ([6d726e4](https://github.com/frappe/erpnext/commit/6d726e4b64a4d10893c53757d5fe4bd0e091607b)) * validate warehouse of SABB for draft entry ([d5e2515](https://github.com/frappe/erpnext/commit/d5e25153f8985fc5221c78de2fc2afd9ec6553e6)) * Variant Items, List View Enabled to Variant Status Change ([#38468](https://github.com/frappe/erpnext/issues/38468)) ([25b1690](https://github.com/frappe/erpnext/commit/25b169059d5da49de5e2d0c269956d5798defa7b)) * voucher detail no in SABB ([6e5738e](https://github.com/frappe/erpnext/commit/6e5738e95c6e2955621c0380ecd9cc0bb9f872cf)) ### Features * UOM query filter for opportunity items ([f6a05ec](https://github.com/frappe/erpnext/commit/f6a05ec85e867dbda87f559bcb19c37f37b11a03)) ### Performance Improvements * add index on reference_purchase_receipt column ([0766c0e](https://github.com/frappe/erpnext/commit/0766c0ea4322433776722d20fe8c9b3605bfed23)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 467aa3a3c59..9717f0d6f11 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from frappe.utils.user import is_website_user -__version__ = "15.99.1" +__version__ = "15.100.0" def get_default_company(user=None): From 68c79a4a790a75e979116a3f71da321bfc2fb79b Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 17 Feb 2026 17:58:44 +0530 Subject: [PATCH 02/37] fix: balance qty for inv dimension (cherry picked from commit a3eafe5b188ee160bc8507d298f987cb1ec4b894) (cherry picked from commit 6898d703821b8c488fb30da1d8666f424f656ec6) --- .../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 b9275417847..b9dadfbb62d 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 @@ -602,19 +666,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 @@ -686,9 +757,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 883f791d7f8..69c94afe30d 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -1847,6 +1847,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 bcc52090c9c61b386731e44d05da7086e82a2a72 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Thu, 5 Mar 2026 09:43:52 +0000 Subject: [PATCH 03/37] chore(release): Bumped to Version 15.100.1 ## [15.100.1](https://github.com/frappe/erpnext/compare/v15.100.0...v15.100.1) (2026-03-05) ### Bug Fixes * balance qty for inv dimension ([68c79a4](https://github.com/frappe/erpnext/commit/68c79a4a790a75e979116a3f71da321bfc2fb79b)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 9717f0d6f11..c6d6d8f9566 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from frappe.utils.user import is_website_user -__version__ = "15.100.0" +__version__ = "15.100.1" def get_default_company(user=None): From 9b49a27af642d35a4afaf8f9c5f6f8c31fe73258 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Fri, 6 Mar 2026 10:34:24 +0530 Subject: [PATCH 04/37] fix: stock balance report qty (cherry picked from commit a15e5fdc4eea302970e3790caf71c69163bf3306) # Conflicts: # erpnext/stock/report/stock_balance/stock_balance.py (cherry picked from commit 180e232eb0451b5f10aa6792a2ca5c7ebc668e1c) --- .../report/stock_balance/stock_balance.py | 238 ++++++++++++++++++ 1 file changed, 238 insertions(+) diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py index 701035d8187..1c60b534672 100644 --- a/erpnext/stock/report/stock_balance/stock_balance.py +++ b/erpnext/stock/report/stock_balance/stock_balance.py @@ -378,6 +378,244 @@ class StockBalanceReport: self.sle_query = query +<<<<<<< HEAD +======= + def prepare_item_warehouse_map_for_current_period(self): + self.opening_vouchers = self.get_opening_vouchers() + + if self.filters.get("show_stock_ageing_data"): + self.sle_entries = self.sle_query.run(as_dict=True) + + self.prepare_stock_reco_voucher_wise_count() + + # HACK: This is required to avoid causing db query in flt + _system_settings = frappe.get_cached_doc("System Settings") + with frappe.db.unbuffered_cursor(): + if not self.filters.get("show_stock_ageing_data"): + self.sle_entries = self.sle_query.run(as_dict=True, as_iterator=True) + + for entry in self.sle_entries: + group_by_key = self.get_group_by_key(entry) + if group_by_key not in self.item_warehouse_map: + self.initialize_data(group_by_key, entry) + + self.prepare_item_warehouse_map(entry, group_by_key) + + self.item_warehouse_map = filter_items_with_no_transactions( + self.item_warehouse_map, self.float_precision, self.inventory_dimensions + ) + + def prepare_stock_reco_voucher_wise_count(self): + self.stock_reco_voucher_wise_count = frappe._dict() + + doctype = frappe.qb.DocType("Stock Ledger Entry") + item = frappe.qb.DocType("Item") + + query = ( + frappe.qb.from_(doctype) + .inner_join(item) + .on(doctype.item_code == item.name) + .select(doctype.voucher_detail_no, Count(doctype.name).as_("count")) + .where( + (doctype.voucher_type == "Stock Reconciliation") + & (doctype.docstatus < 2) + & (doctype.is_cancelled == 0) + & (item.has_serial_no == 1) + ) + .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 + + for row in data: + if row.count != 1: + continue + + sr_item = frappe.db.get_value( + "Stock Reconciliation Item", row.voucher_detail_no, ["current_qty", "qty"], as_dict=True + ) + + 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"): + self.filters["show_warehouse_wise_stock"] = True + item_wise_fifo_queue = FIFOSlots(self.filters).generate() + + _func = itemgetter(1) + + del self.sle_entries + + sre_details = self.get_sre_reserved_qty_details() + + variant_values = {} + if self.filters.get("show_variant_attributes"): + variant_values = self.get_variant_values_for() + + for _key, report_data in self.item_warehouse_map.items(): + if variant_data := variant_values.get(report_data.item_code): + report_data.update(variant_data) + + if self.filters.get("show_stock_ageing_data"): + opening_fifo_queue = self.get_opening_fifo_queue(report_data) or [] + + fifo_queue = [] + if fifo_queue := item_wise_fifo_queue.get((report_data.item_code, report_data.warehouse)): + fifo_queue = fifo_queue.get("fifo_queue") + + if fifo_queue: + opening_fifo_queue.extend(fifo_queue) + + stock_ageing_data = {"average_age": 0, "earliest_age": 0, "latest_age": 0} + + if opening_fifo_queue: + fifo_queue = sorted(filter(_func, opening_fifo_queue), key=_func) + if not fifo_queue: + continue + + to_date = self.to_date + stock_ageing_data["average_age"] = get_average_age(fifo_queue, to_date) + stock_ageing_data["earliest_age"] = date_diff(to_date, fifo_queue[0][1]) + stock_ageing_data["latest_age"] = date_diff(to_date, fifo_queue[-1][1]) + stock_ageing_data["fifo_queue"] = fifo_queue + + report_data.update(stock_ageing_data) + + report_data.update( + {"reserved_stock": sre_details.get((report_data.item_code, report_data.warehouse), 0.0)} + ) + + if ( + not self.filters.get("include_zero_stock_items") + and report_data + and report_data.bal_qty == 0 + and report_data.bal_val == 0 + ): + continue + + self.data.append(report_data) + + def get_sre_reserved_qty_details(self) -> dict: + from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import ( + get_sre_reserved_qty_for_items_and_warehouses as get_reserved_qty_details, + ) + + item_code_list, warehouse_list = [], [] + for d in self.item_warehouse_map: + item_code_list.append(d[0]) + warehouse_list.append(d[1]) + + return get_reserved_qty_details(item_code_list, warehouse_list) + + def prepare_item_warehouse_map(self, entry, group_by_key): + qty_dict = self.item_warehouse_map[group_by_key] + for field in self.inventory_dimensions: + qty_dict[field] = entry.get(field) + + if entry.voucher_type == "Stock Reconciliation" and ( + not entry.batch_no or entry.serial_no or entry.serial_and_batch_bundle + ): + if entry.serial_no and entry.voucher_detail_no in self.stock_reco_voucher_wise_count: + qty_dict.opening_qty -= self.stock_reco_voucher_wise_count.get(entry.voucher_detail_no, 0) + qty_dict.bal_qty = 0.0 + qty_diff = flt(entry.actual_qty) + else: + qty_diff = flt(entry.qty_after_transaction) - flt(qty_dict.bal_qty) + else: + qty_diff = flt(entry.actual_qty) + + value_diff = flt(entry.stock_value_difference) + + if entry.posting_date < self.from_date or entry.voucher_no in self.opening_vouchers.get( + entry.voucher_type, [] + ): + qty_dict.opening_qty += qty_diff + qty_dict.opening_val += value_diff + + elif entry.posting_date >= self.from_date and entry.posting_date <= self.to_date: + if flt(qty_diff, self.float_precision) >= 0: + qty_dict.in_qty += qty_diff + else: + qty_dict.out_qty += abs(qty_diff) + + if flt(value_diff, self.float_precision) >= 0: + qty_dict.in_val += value_diff + else: + qty_dict.out_val += abs(value_diff) + + qty_dict.val_rate = entry.valuation_rate + qty_dict.bal_qty += qty_diff + qty_dict.bal_val += value_diff + + def initialize_data(self, group_by_key, entry): + self.item_warehouse_map[group_by_key] = frappe._dict( + { + "item_code": entry.item_code, + "warehouse": entry.warehouse, + "item_group": entry.item_group, + "company": entry.company, + "currency": self.company_currency, + "stock_uom": entry.stock_uom, + "item_name": entry.item_name, + "opening_qty": 0.0, + "opening_val": 0.0, + "opening_fifo_queue": [], + "in_qty": 0.0, + "in_val": 0.0, + "out_qty": 0.0, + "out_val": 0.0, + "bal_qty": 0.0, + "bal_val": 0.0, + "val_rate": 0.0, + } + ) + + def get_group_by_key(self, row) -> tuple: + group_by_key = [row.item_code, row.warehouse] + + for fieldname in self.inventory_dimensions: + if not row.get(fieldname): + continue + + if self.filters.get(fieldname) or self.filters.get("show_dimension_wise_stock"): + group_by_key.append(row.get(fieldname)) + + return tuple(group_by_key) + +>>>>>>> a15e5fdc4e (fix: stock balance report qty) def apply_inventory_dimensions_filters(self, query, sle) -> str: inventory_dimension_fields = self.get_inventory_dimension_fields() if inventory_dimension_fields: From 5af5de331537363062e1aa08187e9ac8740da1c6 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Fri, 6 Mar 2026 12:47:18 +0530 Subject: [PATCH 05/37] chore: fix conflicts (cherry picked from commit 54fdce648e552f40b179b5e50655d2c77b2db562) --- .../report/stock_balance/stock_balance.py | 276 +++--------------- 1 file changed, 35 insertions(+), 241 deletions(-) diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py index 1c60b534672..f219cc23dce 100644 --- a/erpnext/stock/report/stock_balance/stock_balance.py +++ b/erpnext/stock/report/stock_balance/stock_balance.py @@ -203,6 +203,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 @@ -211,10 +241,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 get_sre_reserved_qty_details(self) -> dict: from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import ( @@ -378,244 +410,6 @@ class StockBalanceReport: self.sle_query = query -<<<<<<< HEAD -======= - def prepare_item_warehouse_map_for_current_period(self): - self.opening_vouchers = self.get_opening_vouchers() - - if self.filters.get("show_stock_ageing_data"): - self.sle_entries = self.sle_query.run(as_dict=True) - - self.prepare_stock_reco_voucher_wise_count() - - # HACK: This is required to avoid causing db query in flt - _system_settings = frappe.get_cached_doc("System Settings") - with frappe.db.unbuffered_cursor(): - if not self.filters.get("show_stock_ageing_data"): - self.sle_entries = self.sle_query.run(as_dict=True, as_iterator=True) - - for entry in self.sle_entries: - group_by_key = self.get_group_by_key(entry) - if group_by_key not in self.item_warehouse_map: - self.initialize_data(group_by_key, entry) - - self.prepare_item_warehouse_map(entry, group_by_key) - - self.item_warehouse_map = filter_items_with_no_transactions( - self.item_warehouse_map, self.float_precision, self.inventory_dimensions - ) - - def prepare_stock_reco_voucher_wise_count(self): - self.stock_reco_voucher_wise_count = frappe._dict() - - doctype = frappe.qb.DocType("Stock Ledger Entry") - item = frappe.qb.DocType("Item") - - query = ( - frappe.qb.from_(doctype) - .inner_join(item) - .on(doctype.item_code == item.name) - .select(doctype.voucher_detail_no, Count(doctype.name).as_("count")) - .where( - (doctype.voucher_type == "Stock Reconciliation") - & (doctype.docstatus < 2) - & (doctype.is_cancelled == 0) - & (item.has_serial_no == 1) - ) - .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 - - for row in data: - if row.count != 1: - continue - - sr_item = frappe.db.get_value( - "Stock Reconciliation Item", row.voucher_detail_no, ["current_qty", "qty"], as_dict=True - ) - - 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"): - self.filters["show_warehouse_wise_stock"] = True - item_wise_fifo_queue = FIFOSlots(self.filters).generate() - - _func = itemgetter(1) - - del self.sle_entries - - sre_details = self.get_sre_reserved_qty_details() - - variant_values = {} - if self.filters.get("show_variant_attributes"): - variant_values = self.get_variant_values_for() - - for _key, report_data in self.item_warehouse_map.items(): - if variant_data := variant_values.get(report_data.item_code): - report_data.update(variant_data) - - if self.filters.get("show_stock_ageing_data"): - opening_fifo_queue = self.get_opening_fifo_queue(report_data) or [] - - fifo_queue = [] - if fifo_queue := item_wise_fifo_queue.get((report_data.item_code, report_data.warehouse)): - fifo_queue = fifo_queue.get("fifo_queue") - - if fifo_queue: - opening_fifo_queue.extend(fifo_queue) - - stock_ageing_data = {"average_age": 0, "earliest_age": 0, "latest_age": 0} - - if opening_fifo_queue: - fifo_queue = sorted(filter(_func, opening_fifo_queue), key=_func) - if not fifo_queue: - continue - - to_date = self.to_date - stock_ageing_data["average_age"] = get_average_age(fifo_queue, to_date) - stock_ageing_data["earliest_age"] = date_diff(to_date, fifo_queue[0][1]) - stock_ageing_data["latest_age"] = date_diff(to_date, fifo_queue[-1][1]) - stock_ageing_data["fifo_queue"] = fifo_queue - - report_data.update(stock_ageing_data) - - report_data.update( - {"reserved_stock": sre_details.get((report_data.item_code, report_data.warehouse), 0.0)} - ) - - if ( - not self.filters.get("include_zero_stock_items") - and report_data - and report_data.bal_qty == 0 - and report_data.bal_val == 0 - ): - continue - - self.data.append(report_data) - - def get_sre_reserved_qty_details(self) -> dict: - from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import ( - get_sre_reserved_qty_for_items_and_warehouses as get_reserved_qty_details, - ) - - item_code_list, warehouse_list = [], [] - for d in self.item_warehouse_map: - item_code_list.append(d[0]) - warehouse_list.append(d[1]) - - return get_reserved_qty_details(item_code_list, warehouse_list) - - def prepare_item_warehouse_map(self, entry, group_by_key): - qty_dict = self.item_warehouse_map[group_by_key] - for field in self.inventory_dimensions: - qty_dict[field] = entry.get(field) - - if entry.voucher_type == "Stock Reconciliation" and ( - not entry.batch_no or entry.serial_no or entry.serial_and_batch_bundle - ): - if entry.serial_no and entry.voucher_detail_no in self.stock_reco_voucher_wise_count: - qty_dict.opening_qty -= self.stock_reco_voucher_wise_count.get(entry.voucher_detail_no, 0) - qty_dict.bal_qty = 0.0 - qty_diff = flt(entry.actual_qty) - else: - qty_diff = flt(entry.qty_after_transaction) - flt(qty_dict.bal_qty) - else: - qty_diff = flt(entry.actual_qty) - - value_diff = flt(entry.stock_value_difference) - - if entry.posting_date < self.from_date or entry.voucher_no in self.opening_vouchers.get( - entry.voucher_type, [] - ): - qty_dict.opening_qty += qty_diff - qty_dict.opening_val += value_diff - - elif entry.posting_date >= self.from_date and entry.posting_date <= self.to_date: - if flt(qty_diff, self.float_precision) >= 0: - qty_dict.in_qty += qty_diff - else: - qty_dict.out_qty += abs(qty_diff) - - if flt(value_diff, self.float_precision) >= 0: - qty_dict.in_val += value_diff - else: - qty_dict.out_val += abs(value_diff) - - qty_dict.val_rate = entry.valuation_rate - qty_dict.bal_qty += qty_diff - qty_dict.bal_val += value_diff - - def initialize_data(self, group_by_key, entry): - self.item_warehouse_map[group_by_key] = frappe._dict( - { - "item_code": entry.item_code, - "warehouse": entry.warehouse, - "item_group": entry.item_group, - "company": entry.company, - "currency": self.company_currency, - "stock_uom": entry.stock_uom, - "item_name": entry.item_name, - "opening_qty": 0.0, - "opening_val": 0.0, - "opening_fifo_queue": [], - "in_qty": 0.0, - "in_val": 0.0, - "out_qty": 0.0, - "out_val": 0.0, - "bal_qty": 0.0, - "bal_val": 0.0, - "val_rate": 0.0, - } - ) - - def get_group_by_key(self, row) -> tuple: - group_by_key = [row.item_code, row.warehouse] - - for fieldname in self.inventory_dimensions: - if not row.get(fieldname): - continue - - if self.filters.get(fieldname) or self.filters.get("show_dimension_wise_stock"): - group_by_key.append(row.get(fieldname)) - - return tuple(group_by_key) - ->>>>>>> a15e5fdc4e (fix: stock balance report qty) def apply_inventory_dimensions_filters(self, query, sle) -> str: inventory_dimension_fields = self.get_inventory_dimension_fields() if inventory_dimension_fields: From 1ee03f41f28ce66639aaa85d7068c0444ea10743 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Fri, 6 Mar 2026 08:35:24 +0000 Subject: [PATCH 06/37] chore(release): Bumped to Version 15.100.2 ## [15.100.2](https://github.com/frappe/erpnext/compare/v15.100.1...v15.100.2) (2026-03-06) ### Bug Fixes * stock balance report qty ([9b49a27](https://github.com/frappe/erpnext/commit/9b49a27af642d35a4afaf8f9c5f6f8c31fe73258)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index c6d6d8f9566..8b9e5e9ea02 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from frappe.utils.user import is_website_user -__version__ = "15.100.1" +__version__ = "15.100.2" def get_default_company(user=None): From 1ffd814f928a0805877b89dc76e0dd4c7eb19148 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Tue, 10 Mar 2026 14:48:03 +0000 Subject: [PATCH 07/37] chore(release): Bumped to Version 15.101.0 # [15.101.0](https://github.com/frappe/erpnext/compare/v15.100.2...v15.101.0) (2026-03-10) ### Bug Fixes * **accounts:** compute tax net_amount in JS controller ([6ad84d6](https://github.com/frappe/erpnext/commit/6ad84d66cc38e20eba9135ac03e20bbb61e03b88)) * **accounts:** round and convert net_amount to company currency in JS tax controller ([516ad90](https://github.com/frappe/erpnext/commit/516ad9021b4ea102f2571da49c7bb2793a24f13f)) * balance qty for inv dimension ([6898d70](https://github.com/frappe/erpnext/commit/6898d703821b8c488fb30da1d8666f424f656ec6)) * better validation message for Purchase Invoice with Update Stock ([b7fd9ae](https://github.com/frappe/erpnext/commit/b7fd9aea6a5e1c37baace45874e38467d8f9f6cb)) * client-side taxes calculation ([#44510](https://github.com/frappe/erpnext/issues/44510)) ([717c5b2](https://github.com/frappe/erpnext/commit/717c5b25eb22a1936ecfde6dc979ab8f20670bd4)), closes [#44328](https://github.com/frappe/erpnext/issues/44328) * correct logic for repair cost in asset repair ([c71557f](https://github.com/frappe/erpnext/commit/c71557f4321259e15877c97a3f9862f8dcba0793)) * disallow all actions on job card if work order is closed ([7b2e483](https://github.com/frappe/erpnext/commit/7b2e4832aa5c306431d63d343bdeafd876f2974c)) * enforce permission check for purchase invoice and update test to use service expense account ([a6dd078](https://github.com/frappe/erpnext/commit/a6dd07802ac0569577826357d42977acf32aebc5)) * **gross-profit:** apply precision-based rounding to grouped totals ([b59dc17](https://github.com/frappe/erpnext/commit/b59dc173b8cf340b3ccc06a21d3f2561dad35c4d)) * **help:** escape query (backport [#53192](https://github.com/frappe/erpnext/issues/53192)) ([#53194](https://github.com/frappe/erpnext/issues/53194)) ([ba4a99b](https://github.com/frappe/erpnext/commit/ba4a99b22c782bace427bfbd11b6b17fab09aabc)) * **manufacturing:** ignore sales order validation for subassembly item ([624d1d4](https://github.com/frappe/erpnext/commit/624d1d47591eb57f14cc2b077875caf6f07e32a8)) * **manufacturing:** show returned qty in progress bar ([260d87a](https://github.com/frappe/erpnext/commit/260d87a80c086669324a4726b9b5797ce17a5b16)) * removed non existent patch ([fd8fac7](https://github.com/frappe/erpnext/commit/fd8fac7d40a90a29f7ca40e0e1b88469cbe1467e)) * **selling:** update delivery date in line items ([dfbb3e9](https://github.com/frappe/erpnext/commit/dfbb3e97a8280636bf8d14ae88b7ffc436699a37)) * set default repair cost to 0 if no value is returned ([0b1746a](https://github.com/frappe/erpnext/commit/0b1746a4c8e4d4109c06ada55a16d3b7cca95027)) * skip asset sale processing for internal transfer invoices ([a7e8f31](https://github.com/frappe/erpnext/commit/a7e8f31f5605c85f79069f62f46078a79e93039d)) * stock balance report qty ([180e232](https://github.com/frappe/erpnext/commit/180e232eb0451b5f10aa6792a2ca5c7ebc668e1c)) * **test:** ensure warehouse is consistently referenced in asset repair tests ([ed428ce](https://github.com/frappe/erpnext/commit/ed428ceb1c271da5f6018583377258e0b7c2ce7c)) * **test:** include warehouse parameter in asset repair test case ([bcc542b](https://github.com/frappe/erpnext/commit/bcc542b1f941ed77220e8d0bc8ca0806d54dca92)) * updating costing based on employee change in timesheet ([be59810](https://github.com/frappe/erpnext/commit/be598108b672f75cfabab310f421ac6df1d822d7)) * validation for cancellation ([c142a2b](https://github.com/frappe/erpnext/commit/c142a2be9c8270175c007e0b530de8f2a39425a3)) ### Features * allowing rate modification in update item in quotation (backport [#53147](https://github.com/frappe/erpnext/issues/53147)) ([#53150](https://github.com/frappe/erpnext/issues/53150)) ([072ab8d](https://github.com/frappe/erpnext/commit/072ab8d5f3492501c64797ba7348c442e12e9e4d)) * **manufacturing:** show disassembled qty in progress bar ([c572a01](https://github.com/frappe/erpnext/commit/c572a019b4d1b3d80ad53cb27187b6942e3341f4)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 8b9e5e9ea02..9f8b6f66113 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from frappe.utils.user import is_website_user -__version__ = "15.100.2" +__version__ = "15.101.0" def get_default_company(user=None): From c912df95cbe416466d6bf691700dd4dae35fc172 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Wed, 18 Mar 2026 04:58:29 +0000 Subject: [PATCH 08/37] chore(release): Bumped to Version 15.101.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [15.101.1](https://github.com/frappe/erpnext/compare/v15.101.0...v15.101.1) (2026-03-18) ### Bug Fixes * add item_name to quick entry fields in Item doctype (backport [#53530](https://github.com/frappe/erpnext/issues/53530)) ([#53532](https://github.com/frappe/erpnext/issues/53532)) ([0e770c0](https://github.com/frappe/erpnext/commit/0e770c0bbd057c4d3c1688512952cd1c3dba95ab)) * Append existing ignored doctypes in Journal Entry on_cancel instead of overwriting ([b73d970](https://github.com/frappe/erpnext/commit/b73d9700d0e0ee12ec96f49fa706ad8e3a12a396)) * **banking:** include paid purchase invoices in reports and bank clearance ([#52675](https://github.com/frappe/erpnext/issues/52675)) ([ab9d960](https://github.com/frappe/erpnext/commit/ab9d960aa8fcb74473bc14fdea3cb5d629861808)) * broke cost center filter in get outstanding reference docs ([53e3bfb](https://github.com/frappe/erpnext/commit/53e3bfbf22eb12e1516ca73db88b51ea6ce8f099)) * change "Date" label to "Posting Date" in Sales Invoice and Purchase Invoice (backport [#53503](https://github.com/frappe/erpnext/issues/53503)) ([#53516](https://github.com/frappe/erpnext/issues/53516)) ([eec8cf8](https://github.com/frappe/erpnext/commit/eec8cf8a71ef0af194442669d68f1d523e7e1e1c)) * coderebbit review ([05d614e](https://github.com/frappe/erpnext/commit/05d614eb04616aec0f0382523a5d48ca5f43fed4)) * correct function syntax in TDS Computation Report ([94972da](https://github.com/frappe/erpnext/commit/94972da845f9de4d316bc7963116d9f54e3854df)) * correct overlap detection in JobCard.has_overlap (backport [#53473](https://github.com/frappe/erpnext/issues/53473)) ([#53522](https://github.com/frappe/erpnext/issues/53522)) ([d262a65](https://github.com/frappe/erpnext/commit/d262a65b00078ef2f3b8e56102820366c79aae02)) * correct payment terms fetching and recalculation logic ([79b0482](https://github.com/frappe/erpnext/commit/79b04826d9ebfedb17a53c8262e392658a46f0f6)) * correct payment terms fetching and recalculation logic ([3148816](https://github.com/frappe/erpnext/commit/314881645162a19efb03c4d4fd035bd3e299e5bd)) * Creating new item price incase of changes in expired item price (backport [#53534](https://github.com/frappe/erpnext/issues/53534)) ([#53544](https://github.com/frappe/erpnext/issues/53544)) ([526ffc1](https://github.com/frappe/erpnext/commit/526ffc11761473f4eeb49e20247314ae3d7ded3a)) * **delivery note:** avoid maintaining si_detail on return delivery note (backport [#52456](https://github.com/frappe/erpnext/issues/52456)) ([#53352](https://github.com/frappe/erpnext/issues/53352)) ([034d460](https://github.com/frappe/erpnext/commit/034d460ae1d852f8dbfede93b8e80a550b006a17)) * do not modify rate in the child item merely for comparison (backport [#53301](https://github.com/frappe/erpnext/issues/53301)) ([#53375](https://github.com/frappe/erpnext/issues/53375)) ([0e00ab8](https://github.com/frappe/erpnext/commit/0e00ab88655d5c38ccc1b0aafcc31f05835a6ebe)) * do not set valuation rate for invoice without update stock ([284ccd1](https://github.com/frappe/erpnext/commit/284ccd1defef1aac73f5652c30f1a80fd46cb766)) * enhance sorting and optimize GL entry retrieval ([93ebec9](https://github.com/frappe/erpnext/commit/93ebec90ef2d6e007eab2341db2a78f8378f2931)) * **italy:** fix e-invoice ScontoMaggiorazione structure and included_in_print_rate support ([#53334](https://github.com/frappe/erpnext/issues/53334)) ([b9c8e8d](https://github.com/frappe/erpnext/commit/b9c8e8d478ba1778ecdec649d9b16d9b862c233a)) * **manufacturing:** update working hours validation (backport [#53559](https://github.com/frappe/erpnext/issues/53559)) ([#53566](https://github.com/frappe/erpnext/issues/53566)) ([9771ed4](https://github.com/frappe/erpnext/commit/9771ed4c572510ec51586606f9d57ab6459717f1)) * **minor:** filter bank accounts in bank statement import ([#53481](https://github.com/frappe/erpnext/issues/53481)) ([a5d1afe](https://github.com/frappe/erpnext/commit/a5d1afe304b15345d1cfd91afab13d1fdb7ecbb7)) * NoneType error when template description is to be copied to variant (backport [#53358](https://github.com/frappe/erpnext/issues/53358)) ([#53365](https://github.com/frappe/erpnext/issues/53365)) ([0612f1c](https://github.com/frappe/erpnext/commit/0612f1c9412afe64ec77282af18044300afab6ff)) * **p&l_statement:** disable accumulated value filter by default (backport [#53488](https://github.com/frappe/erpnext/issues/53488)) ([#53489](https://github.com/frappe/erpnext/issues/53489)) ([b63b532](https://github.com/frappe/erpnext/commit/b63b5320f2fd4b707fbfc10dccab8f128e7f32b8)) * precision issue in production plan (backport [#53370](https://github.com/frappe/erpnext/issues/53370)) ([#53373](https://github.com/frappe/erpnext/issues/53373)) ([5737d2a](https://github.com/frappe/erpnext/commit/5737d2afa3a55e1d7dad9790bfea61f7f3387bde)) * re-calculate taxes and totals after resetting bundle item rate (backport [#53342](https://github.com/frappe/erpnext/issues/53342)) ([#53349](https://github.com/frappe/erpnext/issues/53349)) ([db251c6](https://github.com/frappe/erpnext/commit/db251c6e11025b3967125cd5dc06d5156298eb38)) * refactor GL entry mapping to include voucher type ([c2e6759](https://github.com/frappe/erpnext/commit/c2e67599f5708efe72f5b6f4a8f0b2258b867b63)) * **regional:** rename duplicate Customer fields in Italy setup (backport [#50921](https://github.com/frappe/erpnext/issues/50921)) ([#53397](https://github.com/frappe/erpnext/issues/53397)) ([2a70203](https://github.com/frappe/erpnext/commit/2a70203cabc664dccadfe421050b3cb8648b0007)) * remove redundant pos print format ([#53348](https://github.com/frappe/erpnext/issues/53348)) ([8497d1f](https://github.com/frappe/erpnext/commit/8497d1f8cf065a7b6fae7f2dbe79c0fc5b21e335)) * sales order indicator should be based on available qty rather th… (backport [#53456](https://github.com/frappe/erpnext/issues/53456)) ([#53457](https://github.com/frappe/erpnext/issues/53457)) ([a6cf31e](https://github.com/frappe/erpnext/commit/a6cf31edad101d6649051300d89c72c251aa4e6c)) * **sales_invoice:** reset payment methods on `pos_profile` change (backport [#53514](https://github.com/frappe/erpnext/issues/53514)) ([#53560](https://github.com/frappe/erpnext/issues/53560)) ([239728e](https://github.com/frappe/erpnext/commit/239728e4d95ba0b2dcc9cf92eadc4502c57ece81)) * **serial_and_batch_bundle_selector:** handle CSV attachment properly (backport [#53460](https://github.com/frappe/erpnext/issues/53460)) ([#53461](https://github.com/frappe/erpnext/issues/53461)) ([7a7c4a0](https://github.com/frappe/erpnext/commit/7a7c4a03f0224527f06a215d157a5a6c5f531846)) * skip validate_stock_accounts when perpetual inventory is disabled ([3bc9190](https://github.com/frappe/erpnext/commit/3bc9190795f133da1844dde64afa4e6cfdeb3b41)) * stock adjustment entry ([ac6c06d](https://github.com/frappe/erpnext/commit/ac6c06daf95df1f9640832b845c6e5f7bd97cb94)) * **stock:** fix the property setter (backport [#53422](https://github.com/frappe/erpnext/issues/53422)) ([#53573](https://github.com/frappe/erpnext/issues/53573)) ([57815a0](https://github.com/frappe/erpnext/commit/57815a07acc8aae37649d5379520b541bb28b18e)) * **support-settings:** disable the auto-close tickets feature if `close_issue_after_days` is set to 0 (backport [#53499](https://github.com/frappe/erpnext/issues/53499)) ([#53504](https://github.com/frappe/erpnext/issues/53504)) ([30fe711](https://github.com/frappe/erpnext/commit/30fe711c44561c1e5752276bdfc7af44ab2ac695)) * **tds-report:** correct party type filtering and refactor ([e5eb540](https://github.com/frappe/erpnext/commit/e5eb5406daf90e06881ff77ebf1882bbe249b527)) * test case ([c384564](https://github.com/frappe/erpnext/commit/c3845643141f8df1d016db70fdf48761b3a7f474)) * update delivery date in line items ([#53331](https://github.com/frappe/erpnext/issues/53331)) ([85c4cc3](https://github.com/frappe/erpnext/commit/85c4cc3e1bec898de9e5ff03d80b806705ba3ed0)) * update item description in Production Plan Assembly Items table ([e3e9d7b](https://github.com/frappe/erpnext/commit/e3e9d7b19e073290054f198cb653630eea1b3491)) * update label on company change ([908e185](https://github.com/frappe/erpnext/commit/908e185cfecefc259b41f0dea8f332009964dd0b)) * update user status depends on employee status ([c5796fe](https://github.com/frappe/erpnext/commit/c5796fed4a484cc05b9e2fcc83cdfaffbcc15111)) * use completion_date not posting date ([6d47660](https://github.com/frappe/erpnext/commit/6d476604dfecb62cb29bafcbb60d89dfedf720ba)) * use qb to prevent incorrect sql due to user permissions ([03f0922](https://github.com/frappe/erpnext/commit/03f09222cf3601370815ac107fd47918567652a9)) * valuation rate for no Use Batch wise Valuation batches ([ca6872c](https://github.com/frappe/erpnext/commit/ca6872c768c3269f5c7f985f351ee791923411cd)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 9f8b6f66113..9888b85ff7b 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from frappe.utils.user import is_website_user -__version__ = "15.101.0" +__version__ = "15.101.1" def get_default_company(user=None): From 9e10dec90385d4168299dac4fc3f6c4307192f68 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Wed, 18 Mar 2026 18:49:30 +0530 Subject: [PATCH 09/37] fix: incorrect sle calculation when doc has project (#53599) (cherry picked from commit 6cb6a52ded9addd3e0e54b0b59ebd6d34d357b4a) (cherry picked from commit 7acd4358352ccf34f807687c0d51ea1219024502) --- erpnext/stock/report/stock_ledger/stock_ledger.py | 1 + erpnext/stock/stock_ledger.py | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py index b9dadfbb62d..45af9474d1f 100644 --- a/erpnext/stock/report/stock_ledger/stock_ledger.py +++ b/erpnext/stock/report/stock_ledger/stock_ledger.py @@ -686,6 +686,7 @@ def get_opening_balance(filters, columns, sl_entries, inv_dimension_wise_value=N "posting_time": "00:00:00", "project": project, }, + for_report=True, ) # check if any SLEs are actually Opening Stock Reconciliation diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index 5134bd29116..e6a42d28b15 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -1766,7 +1766,7 @@ def get_previous_sle_of_current_voucher(args, operator="<", exclude_current_vouc return sle[0] if sle else frappe._dict() -def get_previous_sle(args, for_update=False, extra_cond=None): +def get_previous_sle(args, for_update=False, extra_cond=None, for_report=False): """ get the last sle on or before the current time-bucket, to get actual qty before transaction, this function @@ -1782,7 +1782,7 @@ def get_previous_sle(args, for_update=False, extra_cond=None): """ args["name"] = args.get("sle", None) or "" sle = get_stock_ledger_entries( - args, "<=", "desc", "limit 1", for_update=for_update, extra_cond=extra_cond + args, "<=", "desc", "limit 1", for_update=for_update, extra_cond=extra_cond, for_report=for_report ) return sle and sle[0] or {} @@ -1796,6 +1796,7 @@ def get_stock_ledger_entries( debug=False, check_serial_no=True, extra_cond=None, + for_report=False, ): """get stock ledger entries filtered by specific posting datetime conditions""" conditions = f" and posting_datetime {operator} %(posting_datetime)s" @@ -1850,7 +1851,7 @@ def get_stock_ledger_entries( if extra_cond: conditions += f"{extra_cond}" - if previous_sle.get("project"): + if for_report and previous_sle.get("project"): conditions += " and project = %(project)s" # nosemgrep From 572d8530b6258231e31f294474cc1818f693d10b Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Wed, 18 Mar 2026 13:42:20 +0000 Subject: [PATCH 10/37] chore(release): Bumped to Version 15.101.2 ## [15.101.2](https://github.com/frappe/erpnext/compare/v15.101.1...v15.101.2) (2026-03-18) ### Bug Fixes * incorrect sle calculation when doc has project ([#53599](https://github.com/frappe/erpnext/issues/53599)) ([9e10dec](https://github.com/frappe/erpnext/commit/9e10dec90385d4168299dac4fc3f6c4307192f68)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 9888b85ff7b..679e508b8ff 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from frappe.utils.user import is_website_user -__version__ = "15.101.1" +__version__ = "15.101.2" def get_default_company(user=None): From 65d8a176a668691cdae5e0b9dd14140b3ddc477d Mon Sep 17 00:00:00 2001 From: diptanilsaha Date: Thu, 19 Mar 2026 14:18:48 +0530 Subject: [PATCH 11/37] fix(sales_invoice): using `msgprint` and removed condition checking for `is_created_using_pos` to refetch payment methods (#53636) (cherry picked from commit f8ab56ecc96ae7c28b9f7b8e79488ff2c47cc810) --- erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 96eca4f52cd..b10f4fbb89a 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -2745,7 +2745,7 @@ def update_multi_mode_option(doc, pos_profile): payment.account = payment_mode.default_account payment.type = payment_mode.type - mop_refetched = bool(doc.payments) and not doc.is_created_using_pos + mop_refetched = bool(doc.payments) doc.set("payments", []) invalid_modes = [] @@ -2769,9 +2769,8 @@ def update_multi_mode_option(doc, pos_profile): frappe.throw(msg.format(", ".join(invalid_modes)), title=_("Missing Account")) if mop_refetched: - frappe.toast( - _("Payment methods refreshed. Please review before proceeding."), - indicator="orange", + frappe.msgprint( + _("Payment methods refreshed. Please review before proceeding."), indicator="orange", alert=True ) From 94900cb8b8b3631c73864c4d6e9d889f28127c53 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Thu, 19 Mar 2026 10:07:46 +0000 Subject: [PATCH 12/37] chore(release): Bumped to Version 15.101.3 ## [15.101.3](https://github.com/frappe/erpnext/compare/v15.101.2...v15.101.3) (2026-03-19) ### Bug Fixes * **sales_invoice:** using `msgprint` and removed condition checking for `is_created_using_pos` to refetch payment methods ([#53636](https://github.com/frappe/erpnext/issues/53636)) ([65d8a17](https://github.com/frappe/erpnext/commit/65d8a176a668691cdae5e0b9dd14140b3ddc477d)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 679e508b8ff..be8ba7c6c4b 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from frappe.utils.user import is_website_user -__version__ = "15.101.2" +__version__ = "15.101.3" def get_default_company(user=None): From 1d14ba16398db3a220873509565c60f2932bed81 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Mon, 23 Mar 2026 14:59:14 +0000 Subject: [PATCH 13/37] chore(release): Bumped to Version 15.102.0 # [15.102.0](https://github.com/frappe/erpnext/compare/v15.101.3...v15.102.0) (2026-03-23) ### Bug Fixes * Adding validation for operation time in BOM ([7707a79](https://github.com/frappe/erpnext/commit/7707a79d4481292465da217c3851545f05f2eebe)) * batch validation for subcontracting receipt ([32c0532](https://github.com/frappe/erpnext/commit/32c0532dec0244cf6ac28fdbda49bdbe137e1754)) * **budget-variance-report:** validate 'budget_against' filter (backport [#53079](https://github.com/frappe/erpnext/issues/53079)) ([#53663](https://github.com/frappe/erpnext/issues/53663)) ([d96590c](https://github.com/frappe/erpnext/commit/d96590c4d916aaa317fd10af07115ea3d58d9f5e)) * check for `submit` permissions instead of `write` permissions when updating status (backport [#53697](https://github.com/frappe/erpnext/issues/53697)) ([#53702](https://github.com/frappe/erpnext/issues/53702)) ([46e784d](https://github.com/frappe/erpnext/commit/46e784d0941ab02124f74fc43eb1837cd406e871)) * check posting_date in args (backport [#53303](https://github.com/frappe/erpnext/issues/53303)) ([#53611](https://github.com/frappe/erpnext/issues/53611)) ([e0f1e75](https://github.com/frappe/erpnext/commit/e0f1e757f3f6002e5c08ac8d05da24f9de935228)) * consider returned qty in subcontracting report (backport [#53616](https://github.com/frappe/erpnext/issues/53616)) ([#53620](https://github.com/frappe/erpnext/issues/53620)) ([af86fd3](https://github.com/frappe/erpnext/commit/af86fd3cb4230ada1b3e2a9370be0218caac20eb)) * deadlock issue for SLE ([540a854](https://github.com/frappe/erpnext/commit/540a8540d6d05195da100e71219225ad0bc6a3bd)) * do not overwrite expense account in stock entry (backport [#53658](https://github.com/frappe/erpnext/issues/53658)) ([#53660](https://github.com/frappe/erpnext/issues/53660)) ([90e4f90](https://github.com/frappe/erpnext/commit/90e4f9026db8eef72ba9657f345cf938435c9df4)) * ignore cost center (backport [#53063](https://github.com/frappe/erpnext/issues/53063)) ([#53613](https://github.com/frappe/erpnext/issues/53613)) ([562f93e](https://github.com/frappe/erpnext/commit/562f93e75c743ec8f01a0f39b46842173f31fdc0)) * incorrect sle calculation when doc has project ([#53599](https://github.com/frappe/erpnext/issues/53599)) ([7acd435](https://github.com/frappe/erpnext/commit/7acd4358352ccf34f807687c0d51ea1219024502)) * initialize all tax columns to resolve Key error in `item_wise_sales_register` and `item_wise_purchase_register` reports (backport [#53323](https://github.com/frappe/erpnext/issues/53323)) ([#53583](https://github.com/frappe/erpnext/issues/53583)) ([119195c](https://github.com/frappe/erpnext/commit/119195c6fa7f2eb20cae13cc18c78d2115189b44)) * **manufacturing:** update non-stock item dict (backport [#53689](https://github.com/frappe/erpnext/issues/53689)) ([#53698](https://github.com/frappe/erpnext/issues/53698)) ([c0ce34e](https://github.com/frappe/erpnext/commit/c0ce34e12cb17c94af0192084897ea2a962a2f4a)) * merge conflicts ([b3f0e2a](https://github.com/frappe/erpnext/commit/b3f0e2a00dc5a54902c515c102eb50feb1a37cde)) * PO should not be required for internal transfers (backport [#53681](https://github.com/frappe/erpnext/issues/53681)) ([#53683](https://github.com/frappe/erpnext/issues/53683)) ([04d74ad](https://github.com/frappe/erpnext/commit/04d74ad6eb09707274036cedda57c8ef6066c467)) * python error in manufacture entry if transfer against is job card (backport [#53615](https://github.com/frappe/erpnext/issues/53615)) ([#53617](https://github.com/frappe/erpnext/issues/53617)) ([5a3bc27](https://github.com/frappe/erpnext/commit/5a3bc27e2cc9948a1bf39aec7be949bea5114da7)) * **sales_invoice:** using `msgprint` and removed condition checking for `is_created_using_pos` to refetch payment methods ([#53636](https://github.com/frappe/erpnext/issues/53636)) ([f8ab56e](https://github.com/frappe/erpnext/commit/f8ab56ecc96ae7c28b9f7b8e79488ff2c47cc810)) * set customer details on customer creation at login ([#53509](https://github.com/frappe/erpnext/issues/53509)) ([4f39dfd](https://github.com/frappe/erpnext/commit/4f39dfd642eae780f084facc8809285d7c60a470)) * shipping rule applied twice on non stock items (backport [#53655](https://github.com/frappe/erpnext/issues/53655)) ([#53686](https://github.com/frappe/erpnext/issues/53686)) ([5e767ea](https://github.com/frappe/erpnext/commit/5e767ea595f88af566b5d0d6a6afc028a1c59705)) * stock queue for SABB ([461bc17](https://github.com/frappe/erpnext/commit/461bc1733f41de570a4663b0804eb1301d1a346e)) * **stock:** add company filter while fetching batches (backport [#53369](https://github.com/frappe/erpnext/issues/53369)) ([#53580](https://github.com/frappe/erpnext/issues/53580)) ([c09c599](https://github.com/frappe/erpnext/commit/c09c5999dc1225d92ff8977756a37f16692a6f50)) * **stock:** fix email error message (backport [#53606](https://github.com/frappe/erpnext/issues/53606)) ([#53632](https://github.com/frappe/erpnext/issues/53632)) ([6ea3d56](https://github.com/frappe/erpnext/commit/6ea3d569725f3a0f389a6cbaad6a34d840ad8cd8)) * **trends:** added validation for `period_based_on` filter (backport [#53690](https://github.com/frappe/erpnext/issues/53690)) ([#53691](https://github.com/frappe/erpnext/issues/53691)) ([974755b](https://github.com/frappe/erpnext/commit/974755b224e43b1db088b35c0fb280c1d1b4e8e4)) * validate permission before updating status (backport [#53651](https://github.com/frappe/erpnext/issues/53651)) ([#53652](https://github.com/frappe/erpnext/issues/53652)) ([defa1d4](https://github.com/frappe/erpnext/commit/defa1d4a766f3fbfc86982885ba4def73a9bba32)) ### Features * add cost center field to the stock entry accounting dimension tab ([e17b5df](https://github.com/frappe/erpnext/commit/e17b5dfe61bcb8fec45c4e91658ad70cf26f6de7)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index be8ba7c6c4b..098aa8f2788 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from frappe.utils.user import is_website_user -__version__ = "15.101.3" +__version__ = "15.102.0" def get_default_company(user=None): From d39072a6897d2da417f1dfdef6c9a901e68a9514 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Mon, 30 Mar 2026 18:03:28 +0000 Subject: [PATCH 14/37] chore(release): Bumped to Version 15.103.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # [15.103.0](https://github.com/frappe/erpnext/compare/v15.102.0...v15.103.0) (2026-03-30) ### Bug Fixes * **bank_account:** added validation to fetch bank account details using `get_bank_account_details` (backport [#53926](https://github.com/frappe/erpnext/issues/53926)) ([#53929](https://github.com/frappe/erpnext/issues/53929)) ([d16061f](https://github.com/frappe/erpnext/commit/d16061f1bc7b13204afce34cbd978d98f5ce14ea)) * change shipment parcel dimension fields from Int to Float (backport [#53867](https://github.com/frappe/erpnext/issues/53867)) ([#53872](https://github.com/frappe/erpnext/issues/53872)) ([a21b82b](https://github.com/frappe/erpnext/commit/a21b82b238b3420f7821545d7894fad3c5935f73)) * **contract_template:** restrict `create`, `write` and `delete` access only to `System Manager` (backport [#53787](https://github.com/frappe/erpnext/issues/53787)) ([#53788](https://github.com/frappe/erpnext/issues/53788)) ([d50c727](https://github.com/frappe/erpnext/commit/d50c727f89271d221ebbc0982c139bab804ecf21)) * correct item valuation when "Deduct" is used in Purchase Invoice and Receipt. ([2585287](https://github.com/frappe/erpnext/commit/25852879f6068006a44b173461dc0007d2ecfe00)) * **email_campaign:** prevent unsubscribing entire campaign when email group member unsubscribes ([6151a49](https://github.com/frappe/erpnext/commit/6151a496e7fe7383586daaa9807bd4e552289d87)) * flaky currency exchange test (backport [#53813](https://github.com/frappe/erpnext/issues/53813)) ([#53816](https://github.com/frappe/erpnext/issues/53816)) ([d9cd09b](https://github.com/frappe/erpnext/commit/d9cd09b24a95a0030d265b526ae0788662cdd388)) * invalid dynamic link filter for address doctype (backport [#53849](https://github.com/frappe/erpnext/issues/53849)) ([#53851](https://github.com/frappe/erpnext/issues/53851)) ([f7536f6](https://github.com/frappe/erpnext/commit/f7536f645b35a97e068551f1e1245f3bb22ee7c6)) * **item_dashboard:** escaping `warehouse`, `item_code`, `stock_uom` and `item_name` on `get_data` (backport [#53904](https://github.com/frappe/erpnext/issues/53904)) ([#53912](https://github.com/frappe/erpnext/issues/53912)) ([db70d2e](https://github.com/frappe/erpnext/commit/db70d2e4dff4fd6046733ccecef8d1b5c519dc43)) * **manufacturing:** apply work order status filter in job card ([#53776](https://github.com/frappe/erpnext/issues/53776)) ([78635eb](https://github.com/frappe/erpnext/commit/78635ebe992c21bdb2385c7067f7669b47adade6)) * **manufacturing:** apply work order status filter in job card (backport [#53766](https://github.com/frappe/erpnext/issues/53766)) ([#53767](https://github.com/frappe/erpnext/issues/53767)) ([d6afb9b](https://github.com/frappe/erpnext/commit/d6afb9b10a4353df8b4b7e2a73ea930881969b44)) * **manufacturing:** close work order status when stock reservation is… (backport [#53714](https://github.com/frappe/erpnext/issues/53714)) ([#53720](https://github.com/frappe/erpnext/issues/53720)) ([468ca2b](https://github.com/frappe/erpnext/commit/468ca2bde16116c02cd174106be82f69337387f4)) * **manufacturing:** update condition for base hour rate calculation ([#53777](https://github.com/frappe/erpnext/issues/53777)) ([64956ab](https://github.com/frappe/erpnext/commit/64956ab59caaa53cc2643532298c21fd8d2f4141)) * **manufacturing:** update the qty precision (backport [#53874](https://github.com/frappe/erpnext/issues/53874)) ([#53884](https://github.com/frappe/erpnext/issues/53884)) ([46f751e](https://github.com/frappe/erpnext/commit/46f751e4031fb2a680cee2cb30c2b4818b22df5e)) * **opening_invoice_creation_tool:** sanitize summary content for dashboard (backport [#53917](https://github.com/frappe/erpnext/issues/53917)) ([#53923](https://github.com/frappe/erpnext/issues/53923)) ([b35a6c2](https://github.com/frappe/erpnext/commit/b35a6c2e73e64b030ec22110b2ee395f3bd50799)) * purchase invoice for internal transfers should not require PO (backport [#53791](https://github.com/frappe/erpnext/issues/53791)) ([#53792](https://github.com/frappe/erpnext/issues/53792)) ([0a28fb3](https://github.com/frappe/erpnext/commit/0a28fb3ae1c81910aae2e18b193042928c823f5f)) * purchase invoice missing item ([bcd56ab](https://github.com/frappe/erpnext/commit/bcd56abb6216aa7f22a038e24a5cf72b341d47cd)) * **stock:** add warehouse filter to pick work order raw materials (backport [#53748](https://github.com/frappe/erpnext/issues/53748)) ([#53897](https://github.com/frappe/erpnext/issues/53897)) ([fffd3a7](https://github.com/frappe/erpnext/commit/fffd3a785c9936bf0524d5a7c9071f32aff52686)) * **stock:** handle legacy single sle recon entries ([d09207a](https://github.com/frappe/erpnext/commit/d09207ab82537e06fa30d4b65aa091ca3513ca04)) * **stock:** update company validation for expense account in lcv ([40c2b3c](https://github.com/frappe/erpnext/commit/40c2b3c0f6b13345506fef06bfafeba9e5a2d6e5)) * **templates:** escape attachment `file_url` and `file_name` in `order.html` and `projects.html` ([7b9f262](https://github.com/frappe/erpnext/commit/7b9f2626f815cff1ae38c452625a668971fb7285)) * **templates:** using correct syntax of `include` in `projects.html` ([979c594](https://github.com/frappe/erpnext/commit/979c594e984acb6c1c117d2b143bd1c988fc7b4e)) * **test:** enable perpetual inventory ([88c16c8](https://github.com/frappe/erpnext/commit/88c16c8378a3024f29424a8ddb04c182955de7c4)) * validate if quantity greater than 0 in item dashboard (backport [#53846](https://github.com/frappe/erpnext/issues/53846)) ([#53847](https://github.com/frappe/erpnext/issues/53847)) ([ddf6eab](https://github.com/frappe/erpnext/commit/ddf6eab0139fd1f260913ecd523aa05805337613)) * **warehouse_capacity_dashboard:** escaping `warehouse`, `item_code` and `company` on `get_data` (backport [#53894](https://github.com/frappe/erpnext/issues/53894)) ([#53899](https://github.com/frappe/erpnext/issues/53899)) ([1eda22c](https://github.com/frappe/erpnext/commit/1eda22c2bd6265be78810f64b1b5fb873b4d7866)) ### Features * **report:** add service start/end date and amount with roll-ups in deferred revenue/expense report ([14088ee](https://github.com/frappe/erpnext/commit/14088ee7acc1777f896e36f844d77c15190ec01b)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 098aa8f2788..9f6ab46d491 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from frappe.utils.user import is_website_user -__version__ = "15.102.0" +__version__ = "15.103.0" def get_default_company(user=None): From 75344e9e8263ff72a3ce80ed1b23e63410aa804d Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 31 Mar 2026 19:24:30 +0530 Subject: [PATCH 15/37] revert: botched backport (backport #53967) (#53968) Co-authored-by: Mihir Kandoi fix(manufacturing): apply work order status filter in job card (#53776)" fix(manufacturing): apply work order status filter in job card (backport #53766) (#53767)" --- .../doctype/job_card/job_card.js | 36 +++++-------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/erpnext/manufacturing/doctype/job_card/job_card.js b/erpnext/manufacturing/doctype/job_card/job_card.js index d911456f602..e096c73cc61 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.js +++ b/erpnext/manufacturing/doctype/job_card/job_card.js @@ -31,34 +31,6 @@ frappe.ui.form.on("Job Card", { }; }); - frm.set_query("operation", "time_logs", () => { - let operations = (frm.doc.sub_operations || []).map((d) => d.sub_operation); - return { - filters: { - name: ["in", operations], - }, - }; - }); - - frm.set_query("work_order", function () { - return { - filters: { - status: ["not in", ["Cancelled", "Closed", "Stopped"]], - }, - }; - }); - - frm.events.set_company_filters(frm, "target_warehouse"); - frm.events.set_company_filters(frm, "source_warehouse"); - frm.events.set_company_filters(frm, "wip_warehouse"); - frm.set_query("source_warehouse", "items", () => { - return { - filters: { - company: frm.doc.company, - }, - }; - }); - frm.set_indicator_formatter("sub_operation", function (doc) { if (doc.status == "Pending") { return "red"; @@ -75,6 +47,14 @@ frappe.ui.form.on("Job Card", { }, }; }); + + frm.set_query("work_order", function () { + return { + filters: { + status: ["not in", ["Cancelled", "Closed", "Stopped"]], + }, + }; + }); }, refresh: function (frm) { From 2597eaad5195ea4a3c89e0c2fae29e62451b742c Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Tue, 31 Mar 2026 14:30:20 +0000 Subject: [PATCH 17/37] chore(release): Bumped to Version 15.103.1 ## [15.103.1](https://github.com/frappe/erpnext/compare/v15.103.0...v15.103.1) (2026-03-31) ### Bug Fixes * trigger release ([39aaefc](https://github.com/frappe/erpnext/commit/39aaefc2020d0f23f33f690cc744b5daaf88414f)) ### Reverts * botched backport (backport [#53967](https://github.com/frappe/erpnext/issues/53967)) ([#53968](https://github.com/frappe/erpnext/issues/53968)) ([75344e9](https://github.com/frappe/erpnext/commit/75344e9e8263ff72a3ce80ed1b23e63410aa804d)), closes [#53776](https://github.com/frappe/erpnext/issues/53776) [#53766](https://github.com/frappe/erpnext/issues/53766) [#53767](https://github.com/frappe/erpnext/issues/53767) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 9f6ab46d491..2d5c9840d9d 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from frappe.utils.user import is_website_user -__version__ = "15.103.0" +__version__ = "15.103.1" def get_default_company(user=None): From a2626ed55f437f69b99a29cfb0b9ead219f59458 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Tue, 7 Apr 2026 18:01:31 +0000 Subject: [PATCH 18/37] chore(release): Bumped to Version 15.104.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # [15.104.0](https://github.com/frappe/erpnext/compare/v15.103.1...v15.104.0) (2026-04-07) ### Bug Fixes * add support to fetch items based on manufacture stock entry; fix how it's done from work order ([e9ce0a4](https://github.com/frappe/erpnext/commit/e9ce0a41e6ac9a8739b0f93d390473f798b1f3d2)) * add v15 compatibility for scrap item ([652bd39](https://github.com/frappe/erpnext/commit/652bd396d4cbe0e96e2bc47de4e641d51965575f)) * auto-set source_stock_entry ([b87b445](https://github.com/frappe/erpnext/commit/b87b445802ec96f1848013c0b28d524306bd8bcd)) * avg stock entries for disassembly from WO ([44d4079](https://github.com/frappe/erpnext/commit/44d40795df70cead2956ffc70de298e335ada2fd)) * correct warehouse preference for disassemble ([b8ddc2f](https://github.com/frappe/erpnext/commit/b8ddc2f2b9c9910f1c65be5b1bef0d29a806a3e4)) * create source_stock_entry to refer to original manufacturing entry ([55ee1dc](https://github.com/frappe/erpnext/commit/55ee1dcd04309c40091a492e0e6f6b7dbecd0d7e)) * custom button to disassemble manufactured stock entry with work order ([835ae27](https://github.com/frappe/erpnext/commit/835ae27b38d21abf468562abdd7d5988e5595597)) * disassembly prompt with source stock entry field ([44f2e94](https://github.com/frappe/erpnext/commit/44f2e9480d8ef49a0b12562268e9111040e4ea91)) * do not repost GL if no change in valuation ([0063201](https://github.com/frappe/erpnext/commit/0063201818a8085665f4c1e58b08790ec20e217e)) * do not show inv dimension unnecessarily in stock entry (backport [#53946](https://github.com/frappe/erpnext/issues/53946)) ([#53950](https://github.com/frappe/erpnext/issues/53950)) ([e159c79](https://github.com/frappe/erpnext/commit/e159c797667d679aa5fb20ce6abdca23f4a07d21)) * ensure compatibility with v15 ([8b42fcf](https://github.com/frappe/erpnext/commit/8b42fcf274bd56a65f2e59cda69c1a3c06ca7c93)) * GL entries for different exchange rate in the purchase invoice ([def62cf](https://github.com/frappe/erpnext/commit/def62cf3fe0c30a406b93382312b9270e643c9b5)) * handle disassembly for secondary / scrap items ([229dc23](https://github.com/frappe/erpnext/commit/229dc23f974d7c7bf95d837aad16ba1301f82780)) * include rejected qty in tax (purchase receipt) (backport [#53624](https://github.com/frappe/erpnext/issues/53624)) ([#53971](https://github.com/frappe/erpnext/issues/53971)) ([3fbfad1](https://github.com/frappe/erpnext/commit/3fbfad1b9b4fb00de1cf5b2c4fa238ab356aa9a0)) * manufacture entry with group_by support ([841b507](https://github.com/frappe/erpnext/commit/841b507502c63ff10c7baf55627f5bcbca89e3d9)) * **manufacturing:** handle null cur_dialog in BOM work order dialog (backport [#54011](https://github.com/frappe/erpnext/issues/54011)) ([#54014](https://github.com/frappe/erpnext/issues/54014)) ([cb0a548](https://github.com/frappe/erpnext/commit/cb0a548a95c87d55d8fd9eef3eab7d10ad8b67f1)) * not able to set operation in work order ([62d5870](https://github.com/frappe/erpnext/commit/62d58702a03f016893a9e7537425ce37a9cb729e)) * prevent selection of group type customer group in customer master ([7a227e0](https://github.com/frappe/erpnext/commit/7a227e048ee15f450cbf0b000d5226194144b1a9)) * process loss with bom path disassembly ([eee6d7e](https://github.com/frappe/erpnext/commit/eee6d7e56684182f4aab51d787541d1650a9938e)) * **promotional_scheme:** toggle enable state between Buying and Selli… (backport [#54110](https://github.com/frappe/erpnext/issues/54110)) ([#54111](https://github.com/frappe/erpnext/issues/54111)) ([5b7e6eb](https://github.com/frappe/erpnext/commit/5b7e6eb83178effd5d253a7f132c64c7641eb406)) * remove reference in serial/batch when document is cancelled (backport [#53979](https://github.com/frappe/erpnext/issues/53979)) ([#53988](https://github.com/frappe/erpnext/issues/53988)) ([e33abee](https://github.com/frappe/erpnext/commit/e33abeef7f7a42e185d6818974906f6c4370e91a)) * remove unnecessary param, and use value from self ([0b0dccd](https://github.com/frappe/erpnext/commit/0b0dccd294aa1595d72774b9b9241e6931e42b4a)) * resolve user permission error on status change by updating user … (backport [#54033](https://github.com/frappe/erpnext/issues/54033)) ([#54059](https://github.com/frappe/erpnext/issues/54059)) ([14085de](https://github.com/frappe/erpnext/commit/14085de332abb9628cb3224bd8f46f9314e11bd2)) * set bom details on disassembly; abs batch qty ([84d5b52](https://github.com/frappe/erpnext/commit/84d5b524832b6dd31e1f1f190d5dd6f9a3b8a05e)) * set serial and batch from source stock entry - on disassemble ([df049cd](https://github.com/frappe/erpnext/commit/df049cd27705ef0805c8df92d79de01829fc439b)) * set_query for source stock entry ([849b2e6](https://github.com/frappe/erpnext/commit/849b2e6ebf977204643109e83e60a8ee68bbc557)) * show current stock qty in Stock Entry PDF (backport [#53761](https://github.com/frappe/erpnext/issues/53761)) ([#54031](https://github.com/frappe/erpnext/issues/54031)) ([af0116c](https://github.com/frappe/erpnext/commit/af0116cdc57359c17be8baf6ab6fc8bf91dfa9ee)) * skip discount amount validation when not saving ([13eab9f](https://github.com/frappe/erpnext/commit/13eab9f993c7037ab235d76838bb415cda7fa7ef)) * **stock:** update stock queue in SABE for return entries ([05d6cf5](https://github.com/frappe/erpnext/commit/05d6cf5c9a4f0b3de830709b3dfc87038f846ae7)) * support creating disassembly (without link of WO) ([ef15c05](https://github.com/frappe/erpnext/commit/ef15c0581dc75ebdbd7b1ed19eaf2729e57997c6)) * sync paid and received amount (backport [#53039](https://github.com/frappe/erpnext/issues/53039)) ([#54107](https://github.com/frappe/erpnext/issues/54107)) ([0505684](https://github.com/frappe/erpnext/commit/0505684d229d8e47371d6a49aeb46178459838ed)) * **test:** do not use is_group enabled customer group in test ([97684d3](https://github.com/frappe/erpnext/commit/97684d3daed4da01de7dc24f8fcef6ae426d3af4)) * **test:** pin posting date in test_depreciation_on_cancel_invoice ([7f72189](https://github.com/frappe/erpnext/commit/7f721896657f2706ab445b4d68f1b033eaef2280)) * **test:** use non-group customer group in test setup ([ea3fcc2](https://github.com/frappe/erpnext/commit/ea3fcc214b83c97d6b1faed48e76a9c7ed42c270)) * transactions where update stock is 0 should not create SLEs (backport [#54035](https://github.com/frappe/erpnext/issues/54035)) ([#54076](https://github.com/frappe/erpnext/issues/54076)) ([bcf59e7](https://github.com/frappe/erpnext/commit/bcf59e71717455842a7124044175191f8da3f8c2)) * update min date based on transaction_date (backport [#53803](https://github.com/frappe/erpnext/issues/53803)) ([#54024](https://github.com/frappe/erpnext/issues/54024)) ([a71d32e](https://github.com/frappe/erpnext/commit/a71d32e668efdac630c1a5faa4a3596e2a957fbb)) * use get_value ([8f01d12](https://github.com/frappe/erpnext/commit/8f01d12b5eb4207d7838ce9ee027de06a6fbf311)) * **ux:** refresh grid to correctly persist the state of fields ([3c327d5](https://github.com/frappe/erpnext/commit/3c327d5225849b84db403a7901fe3e0fd48eceb6)) * validate qty that can be disassembled from source stock entry. ([583c7b9](https://github.com/frappe/erpnext/commit/583c7b9819597df4695ff07f3b1dc97c32c9feb9)) * validate work order consistency in stock entry ([d690a0c](https://github.com/frappe/erpnext/commit/d690a0c6bd3124ed65e1049f84fe96c3401a6fe5)) * validation test for customer group ([7794f30](https://github.com/frappe/erpnext/commit/7794f3033ed524f2e6334f4fc2f110091622b362)) * **warehouse_capacity_dashboard:** removed `escape` from template (backport [#53907](https://github.com/frappe/erpnext/issues/53907)) ([#53908](https://github.com/frappe/erpnext/issues/53908)) ([efdb004](https://github.com/frappe/erpnext/commit/efdb004f0bcce1612c158a3376d806596a303707)) ### Features * Allow Editing of Items and Quantities in Work Order ([1d36cb5](https://github.com/frappe/erpnext/commit/1d36cb55cdc8ce9f59a82a89b84f44c7d3c0f0c0)) * croatian_address_template (backport [#53888](https://github.com/frappe/erpnext/issues/53888)) ([#54057](https://github.com/frappe/erpnext/issues/54057)) ([ee81268](https://github.com/frappe/erpnext/commit/ee812687e6f8c1d57e3c1d4c542e22de898d3343)) * **timesheet:** allow partial billing and handled return ([21805bd](https://github.com/frappe/erpnext/commit/21805bde1fad3c244165fccd57bf306571149773)) ### Reverts * botched backport ([#53967](https://github.com/frappe/erpnext/issues/53967)) ([22774fd](https://github.com/frappe/erpnext/commit/22774fdf877db3eccf15d9783f4054373ba04ced)), closes [#53776](https://github.com/frappe/erpnext/issues/53776) [#53766](https://github.com/frappe/erpnext/issues/53766) [#53767](https://github.com/frappe/erpnext/issues/53767) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 2d5c9840d9d..87f8a2b40b4 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from frappe.utils.user import is_website_user -__version__ = "15.103.1" +__version__ = "15.104.0" def get_default_company(user=None): From 3a2dc6f9ee05009fc67f87eaa26ab9a62f04fa50 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 8 Apr 2026 18:22:08 +0530 Subject: [PATCH 19/37] fix: last SLE not updated in the file (cherry picked from commit 38ed425ee299e70d8c22b759899f250fd5429393) # Conflicts: # erpnext/manufacturing/doctype/work_order/test_work_order.py (cherry picked from commit 8408e8133526d5d6ee83f39ee1f0d2f472b68d81) --- .../doctype/work_order/test_work_order.py | 38 ++++++++++++ erpnext/stock/stock_ledger.py | 59 ++++++++++--------- 2 files changed, 70 insertions(+), 27 deletions(-) diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py index 374caf369ea..96bb75a841e 100644 --- a/erpnext/manufacturing/doctype/work_order/test_work_order.py +++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py @@ -509,7 +509,45 @@ class TestWorkOrder(FrappeTestCase): def test_work_order_material_transferred_qty_with_process_loss(self): stock_entries = [] +<<<<<<< HEAD bom = frappe.get_doc("BOM", {"docstatus": 1, "with_operations": 1, "company": "_Test Company"}) +======= + item_code = make_item("_Test Item For Process Loss", {"is_stock_item": 1}).name + rm_item_code = make_item("Test Item For Process Loss RM", {"is_stock_item": 1}).name + + bom = make_bom( + item=item_code, + raw_materials=[rm_item_code], + with_operations=1, + do_not_save=True, + ) + + operation_name = "_Test Custom Operation" + workstation_name = "_Test Custom Workstation" + + if not frappe.db.exists("Workstation", workstation_name): + doc = frappe.new_doc("Workstation") + doc.workstation_name = workstation_name + doc.save() + + if not frappe.db.exists("Operation", operation_name): + doc = frappe.new_doc("Operation") + doc.name = operation_name + doc.workstation = workstation_name + doc.save() + + operation = { + "operation": operation_name, + "workstation": workstation_name, + "description": "Test Data", + "operating_cost": 100, + "time_in_mins": 40, + } + + bom.append("operations", operation) + bom.save() + bom.submit() +>>>>>>> 38ed425ee2 (fix: last SLE not updated in the file) work_order = make_wo_order_test_record( item=bom.item, diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index ccc65a1e329..3e5974e0f53 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -263,17 +263,11 @@ def update_args_in_repost_item_valuation( items_to_be_repost, repost_affected_transaction, item_wh_wise_last_posted_sle=None, - only_affected_transaction=False, ): file_name = "" - has_file = False - if not item_wh_wise_last_posted_sle: item_wh_wise_last_posted_sle = {} - if doc.reposting_data_file: - has_file = True - if doc.reposting_data_file: file_name = get_reposting_file_name(doc.doctype, doc.name) # frappe.delete_doc("File", file_name, ignore_permissions=True, delete_permanently=True) @@ -288,15 +282,14 @@ def update_args_in_repost_item_valuation( file_name, ) - if not only_affected_transaction or not has_file: - doc.db_set( - { - "current_index": index, - "items_to_be_repost": frappe.as_json(items_to_be_repost), - "total_reposting_count": len(items_to_be_repost), - "reposting_data_file": doc.reposting_data_file, - } - ) + doc.db_set( + { + "current_index": index, + "items_to_be_repost": frappe.as_json(items_to_be_repost), + "total_reposting_count": len(items_to_be_repost), + "reposting_data_file": doc.reposting_data_file, + } + ) if not frappe.flags.in_test: frappe.db.commit() @@ -577,13 +570,9 @@ class update_entries_after: self.update_bin() else: self.item_wh_wise_last_posted_sle = self.get_item_wh_wise_last_posted_sle() - _item_wh_sle = self.sort_sles(self.item_wh_wise_last_posted_sle.values()) - - while _item_wh_sle: - self.initialize_reposting() - sle_dict = _item_wh_sle.pop(0) - self.repost_stock_ledgers(sle_dict) - + item_wh_sles = self.sort_sles(self.item_wh_wise_last_posted_sle.values()) + self.initialize_reposting() + self.repost_stock_ledgers(item_wh_sles) self.update_bin() self.reset_vouchers_and_idx() self.update_data_in_repost() @@ -618,8 +607,19 @@ class update_entries_after: ) } - def repost_stock_ledgers(self, sle_dict=None): - self._sles = self.get_future_entries_to_repost(sle_dict) + def _get_future_entries_to_repost(self, item_wh_sles): + sles = [] + + for sle in item_wh_sles: + if (sle.item_code, sle.warehouse) not in self.distinct_dependant_item_wh: + self.distinct_dependant_item_wh.add((sle.item_code, sle.warehouse)) + + sles.extend(self.get_future_entries_to_repost(sle)) + + return self.sort_sles(sles) + + def repost_stock_ledgers(self, item_wh_sles=None): + self._sles = self._get_future_entries_to_repost(item_wh_sles) if not isinstance(self._sles, deque): self._sles = deque(self._sles) @@ -627,10 +627,13 @@ class update_entries_after: i = 0 while self._sles: sle = self._sles.popleft() - i += 1 + if (sle.item_code, sle.warehouse) not in self.distinct_dependant_item_wh: + self.distinct_dependant_item_wh.add((sle.item_code, sle.warehouse)) + if sle.name in self.distinct_sles: continue + i += 1 item_wh_key = (sle.item_code, sle.warehouse) if item_wh_key not in self.prev_sle_dict: self.prev_sle_dict[item_wh_key] = get_previous_sle_of_current_voucher(sle) @@ -644,7 +647,7 @@ class update_entries_after: self.include_dependant_sle_in_reposting(sle) self.update_item_wh_wise_last_posted_sle(sle) - if i % 1000 == 0: + if i % 2000 == 0: self.update_data_in_repost(len(self._sles), i) def sort_sles(self, sles): @@ -726,7 +729,6 @@ class update_entries_after: self.items_to_be_repost, self.repost_affected_transaction, self.item_wh_wise_last_posted_sle, - only_affected_transaction=True, ) if not frappe.flags.in_test: @@ -982,6 +984,9 @@ class update_entries_after: ): return + if not cint(erpnext.is_perpetual_inventory_enabled(sle.company)): + return + if self.args.item_code != sle.item_code or self.args.warehouse != sle.warehouse: self.repost_affected_transaction.add((sle.voucher_type, sle.voucher_no)) From c1591c37db76487add9af5200feb946625a4d701 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Thu, 9 Apr 2026 09:06:31 +0530 Subject: [PATCH 20/37] chore: fix conflicts (cherry picked from commit c70259687a034416706d204c0e7035e17cca93d2) --- erpnext/manufacturing/doctype/work_order/test_work_order.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py index 96bb75a841e..f4a0d6f6145 100644 --- a/erpnext/manufacturing/doctype/work_order/test_work_order.py +++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py @@ -509,9 +509,6 @@ class TestWorkOrder(FrappeTestCase): def test_work_order_material_transferred_qty_with_process_loss(self): stock_entries = [] -<<<<<<< HEAD - bom = frappe.get_doc("BOM", {"docstatus": 1, "with_operations": 1, "company": "_Test Company"}) -======= item_code = make_item("_Test Item For Process Loss", {"is_stock_item": 1}).name rm_item_code = make_item("Test Item For Process Loss RM", {"is_stock_item": 1}).name @@ -547,7 +544,6 @@ class TestWorkOrder(FrappeTestCase): bom.append("operations", operation) bom.save() bom.submit() ->>>>>>> 38ed425ee2 (fix: last SLE not updated in the file) work_order = make_wo_order_test_record( item=bom.item, From b88f3f69b0048d81e068d2ccf489ca293513a3b9 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Thu, 9 Apr 2026 05:20:24 +0000 Subject: [PATCH 21/37] chore(release): Bumped to Version 15.104.1 ## [15.104.1](https://github.com/frappe/erpnext/compare/v15.104.0...v15.104.1) (2026-04-09) ### Bug Fixes * last SLE not updated in the file ([3a2dc6f](https://github.com/frappe/erpnext/commit/3a2dc6f9ee05009fc67f87eaa26ab9a62f04fa50)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 87f8a2b40b4..f00d27f9f56 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from frappe.utils.user import is_website_user -__version__ = "15.104.0" +__version__ = "15.104.1" def get_default_company(user=None): From 041f99c9267b17ddaf419652998b016cfe286626 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 9 Apr 2026 12:47:36 +0530 Subject: [PATCH 22/37] fix: set default posting time in RIV (cherry picked from commit a7ece65536d54c03a615ba43b5f23e4643492d6b) # Conflicts: # erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py (cherry picked from commit 6e438e71ebcb6933d3af659a8234a772e4bd5fe2) --- .../repost_item_valuation.py | 19 +++++++++++++++++++ erpnext/stock/stock_ledger.py | 2 ++ 2 files changed, 21 insertions(+) diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py index 44cf9280780..96e49b288cc 100644 --- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py +++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py @@ -74,6 +74,11 @@ class RepostItemValuation(Document): repost(self) def validate(self): +<<<<<<< HEAD +======= + self.set_default_posting_time() + self.reset_repost_only_accounting_ledgers() +>>>>>>> a7ece65536 (fix: set default posting time in RIV) self.set_company() self.validate_update_stock() self.validate_period_closing_voucher() @@ -83,6 +88,20 @@ class RepostItemValuation(Document): self.reset_recreate_stock_ledgers() self.validate_recreate_stock_ledgers() +<<<<<<< HEAD +======= + def set_default_posting_time(self): + if not self.posting_time: + self.posting_time = nowtime() + + if not self.posting_date: + frappe.throw(_("Posting date is required")) + + def reset_repost_only_accounting_ledgers(self): + if self.repost_only_accounting_ledgers and self.based_on != "Transaction": + self.repost_only_accounting_ledgers = 0 + +>>>>>>> a7ece65536 (fix: set default posting time in RIV) def validate_update_stock(self): if self.voucher_type in ["Sales Invoice", "Purchase Invoice"]: update_stock = frappe.get_value(self.voucher_type, self.voucher_no, "update_stock") diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index 3e5974e0f53..18e06fd6c10 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -233,6 +233,8 @@ def repost_future_sle( index = get_current_index(doc) or 0 while index < len(items_to_be_repost): + validate_item_warehouse(items_to_be_repost[index]) + obj = update_entries_after( { "item_code": items_to_be_repost[index].get("item_code"), From db3a40409fce1ada6c26d8c24c2b7ad60bf8cd2a Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Thu, 9 Apr 2026 14:24:07 +0530 Subject: [PATCH 23/37] chore: fix conflicts Removed unused method reset_repost_only_accounting_ledgers and fixed the validate method to set default posting time. (cherry picked from commit 2df574baae31be34951b8deda8149fd3ca801ff2) --- .../repost_item_valuation/repost_item_valuation.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py index 96e49b288cc..bfc857ed80b 100644 --- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py +++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py @@ -74,11 +74,7 @@ class RepostItemValuation(Document): repost(self) def validate(self): -<<<<<<< HEAD -======= self.set_default_posting_time() - self.reset_repost_only_accounting_ledgers() ->>>>>>> a7ece65536 (fix: set default posting time in RIV) self.set_company() self.validate_update_stock() self.validate_period_closing_voucher() @@ -88,8 +84,6 @@ class RepostItemValuation(Document): self.reset_recreate_stock_ledgers() self.validate_recreate_stock_ledgers() -<<<<<<< HEAD -======= def set_default_posting_time(self): if not self.posting_time: self.posting_time = nowtime() @@ -97,11 +91,6 @@ class RepostItemValuation(Document): if not self.posting_date: frappe.throw(_("Posting date is required")) - def reset_repost_only_accounting_ledgers(self): - if self.repost_only_accounting_ledgers and self.based_on != "Transaction": - self.repost_only_accounting_ledgers = 0 - ->>>>>>> a7ece65536 (fix: set default posting time in RIV) def validate_update_stock(self): if self.voucher_type in ["Sales Invoice", "Purchase Invoice"]: update_stock = frappe.get_value(self.voucher_type, self.voucher_no, "update_stock") From 8aede8729036d1b9ae2798b9a1b9b3663ca5b589 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Thu, 9 Apr 2026 11:15:07 +0000 Subject: [PATCH 24/37] chore(release): Bumped to Version 15.104.2 ## [15.104.2](https://github.com/frappe/erpnext/compare/v15.104.1...v15.104.2) (2026-04-09) ### Bug Fixes * set default posting time in RIV ([041f99c](https://github.com/frappe/erpnext/commit/041f99c9267b17ddaf419652998b016cfe286626)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index f00d27f9f56..1408e2ec16c 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from frappe.utils.user import is_website_user -__version__ = "15.104.1" +__version__ = "15.104.2" def get_default_company(user=None): From fc3ceff42f648d21c99118dbe0f76f5e6ecdbd0f Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Tue, 14 Apr 2026 18:20:17 +0000 Subject: [PATCH 25/37] chore(release): Bumped to Version 15.104.3 ## [15.104.3](https://github.com/frappe/erpnext/compare/v15.104.2...v15.104.3) (2026-04-14) ### Bug Fixes * account change in warehouse (backport [#54182](https://github.com/frappe/erpnext/issues/54182)) ([#54204](https://github.com/frappe/erpnext/issues/54204)) ([430705f](https://github.com/frappe/erpnext/commit/430705f56c1192607e251dc9671c60ef76850a85)) * hardcoded precision causing decimal issues ([7754504](https://github.com/frappe/erpnext/commit/77545042a5e2fa8265763d2df149fb7cdc85a151)) * inventory dimension patch (backport [#54141](https://github.com/frappe/erpnext/issues/54141)) ([#54145](https://github.com/frappe/erpnext/issues/54145)) ([deb67db](https://github.com/frappe/erpnext/commit/deb67db4a00ec5e642885f911cc06e528a04ce03)) * inventory dimension patch (backport [#54147](https://github.com/frappe/erpnext/issues/54147)) ([#54148](https://github.com/frappe/erpnext/issues/54148)) ([a56d698](https://github.com/frappe/erpnext/commit/a56d6984d12784387cb7e181be0d8c727b517bd0)) * inventory dimensions should not be mandatory unnecesarily (backport [#54064](https://github.com/frappe/erpnext/issues/54064)) ([#54133](https://github.com/frappe/erpnext/issues/54133)) ([a26c845](https://github.com/frappe/erpnext/commit/a26c84533272416cf7332f9bcb3971929953c924)) * last SLE not updated in the file ([8408e81](https://github.com/frappe/erpnext/commit/8408e8133526d5d6ee83f39ee1f0d2f472b68d81)) * **list_opportunity_report:** parameterized `lost_reason` ([#54160](https://github.com/frappe/erpnext/issues/54160)) ([1604c21](https://github.com/frappe/erpnext/commit/1604c216026d1138e4e9c71e0dfef1febe6a6402)) * make operation mandatory when any sub operation row is added (backport [#54245](https://github.com/frappe/erpnext/issues/54245)) ([#54247](https://github.com/frappe/erpnext/issues/54247)) ([cbe5ad6](https://github.com/frappe/erpnext/commit/cbe5ad6337eeeb5965cd530792fefd15e699d366)) * preserve asset movement field properties after save ([a87015e](https://github.com/frappe/erpnext/commit/a87015e8e69215b71c9b71b3779193a7f94e7be2)) * quality inspection item code fetch perm issue (backport [#54121](https://github.com/frappe/erpnext/issues/54121)) ([#54126](https://github.com/frappe/erpnext/issues/54126)) ([bcd6d99](https://github.com/frappe/erpnext/commit/bcd6d99549aae9b6ca433511c623869477ad18ba)) * remove unneccessary function for serial no status updation (backport [#54191](https://github.com/frappe/erpnext/issues/54191)) ([#54196](https://github.com/frappe/erpnext/issues/54196)) ([cb24d94](https://github.com/frappe/erpnext/commit/cb24d9404dae28cb033b1c314db5ac2b35a7d712)) * **sales invoice:** toggle Get Items From button based on is_return and POS view (backport [#52594](https://github.com/frappe/erpnext/issues/52594)) ([#54138](https://github.com/frappe/erpnext/issues/54138)) ([5de4102](https://github.com/frappe/erpnext/commit/5de4102dda154063b0dcf4f293dfb2976d8db177)) * sanitize genericode import inputs and secure XML parser (backport [#53302](https://github.com/frappe/erpnext/issues/53302)) ([#54174](https://github.com/frappe/erpnext/issues/54174)) ([76e910e](https://github.com/frappe/erpnext/commit/76e910e8c05961a8e30ae436d9db7e2cc029f9f8)) * set default posting time in RIV ([6e438e7](https://github.com/frappe/erpnext/commit/6e438e71ebcb6933d3af659a8234a772e4bd5fe2)) * **stock:** remove float precision to fix precision issue (backport [#54284](https://github.com/frappe/erpnext/issues/54284)) ([#54288](https://github.com/frappe/erpnext/issues/54288)) ([0e9b3b4](https://github.com/frappe/erpnext/commit/0e9b3b459a45092c6a46a0457a961316ed4b4cc6)) * **stock:** update bin to zero when no previous sle exists (backport [#54236](https://github.com/frappe/erpnext/issues/54236)) ([#54263](https://github.com/frappe/erpnext/issues/54263)) ([46a1c6f](https://github.com/frappe/erpnext/commit/46a1c6fda072dad6077fc5171bfcdb8395acdb64)) * update return value in workstation list view indicator (backport [#54198](https://github.com/frappe/erpnext/issues/54198)) ([#54200](https://github.com/frappe/erpnext/issues/54200)) ([0a3f9f0](https://github.com/frappe/erpnext/commit/0a3f9f0b9f9bd0b50d4435cc613442e2c8a530fd)) * update_nsm only in warehouse creation ([#54165](https://github.com/frappe/erpnext/issues/54165)) ([e9c1a09](https://github.com/frappe/erpnext/commit/e9c1a09af3a6ffbe000cddd89bcb05b38868ea11)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 1408e2ec16c..d6b46883380 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from frappe.utils.user import is_website_user -__version__ = "15.104.2" +__version__ = "15.104.3" def get_default_company(user=None): From b6902ef960fe9ed7518711a176b35108933248e7 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Tue, 21 Apr 2026 19:53:50 +0000 Subject: [PATCH 26/37] chore(release): Bumped to Version 15.105.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # [15.105.0](https://github.com/frappe/erpnext/compare/v15.104.3...v15.105.0) (2026-04-21) ### Bug Fixes * add portal user ownership check to supplier quotation (backport [#54298](https://github.com/frappe/erpnext/issues/54298)) ([#54299](https://github.com/frappe/erpnext/issues/54299)) ([1e4cafa](https://github.com/frappe/erpnext/commit/1e4cafaa0e0220c5346fbeddcc340999eef89b47)) * changed qty validation from qty field to stock_qty (backport [#54352](https://github.com/frappe/erpnext/issues/54352)) ([#54356](https://github.com/frappe/erpnext/issues/54356)) ([1ccbc9f](https://github.com/frappe/erpnext/commit/1ccbc9f621d8e67cdd3217dd36dd8b226604be06)) * clear conditions table when calculate_based_on is set to Fixed ([35bd437](https://github.com/frappe/erpnext/commit/35bd43775cc49ec64f6d276991f549c516082697)) * clear shipping rule conditions for fixed shipping rule ([9e10ecc](https://github.com/frappe/erpnext/commit/9e10ecc4cb0530ee3ab19e7999c404a1d3c6a01f)) * **dashboard-trends:** set default fiscal year and company before val… (backport [#54339](https://github.com/frappe/erpnext/issues/54339)) ([#54399](https://github.com/frappe/erpnext/issues/54399)) ([799f897](https://github.com/frappe/erpnext/commit/799f89703636bc554e0dab98e8fc42de71e83267)) * fetch item tax template from item group when creating item ([#54405](https://github.com/frappe/erpnext/issues/54405)) ([ffa0268](https://github.com/frappe/erpnext/commit/ffa0268a578eaec41ef748fad8fb5caa49dd6593)) * move make_dimension_in_accounting_doctypes from after_insert to on_update (backport [#54172](https://github.com/frappe/erpnext/issues/54172)) ([#54317](https://github.com/frappe/erpnext/issues/54317)) ([d9d8fc6](https://github.com/frappe/erpnext/commit/d9d8fc69126b5e6295191ab84d3646611b6390b7)) * negative batch report showing same batch-warehouse multiple times ([3229fce](https://github.com/frappe/erpnext/commit/3229fce9a508d73d1c3d31171a51c08ddebc082c)) * non-collapsible in customer quick entry ([9ee0594](https://github.com/frappe/erpnext/commit/9ee059465ada595e5d132e372a1b2fa4d9ad166d)) * **pos_invoice_item:** fetch `grant_commission` from `item_code` (backport [#54413](https://github.com/frappe/erpnext/issues/54413)) ([#54417](https://github.com/frappe/erpnext/issues/54417)) ([813f464](https://github.com/frappe/erpnext/commit/813f4644a05b4a23b4a1520d0043f415e78dfb95)) * reset base_rounded_total when rounded_total resets (backport [#54241](https://github.com/frappe/erpnext/issues/54241)) ([#54303](https://github.com/frappe/erpnext/issues/54303)) ([28367ac](https://github.com/frappe/erpnext/commit/28367ac966bd12ea55327f91eede7f03d8c409ec)) * **vat audit report:** fallback to item name when item code is missing ([#54049](https://github.com/frappe/erpnext/issues/54049)) ([2c1ea8d](https://github.com/frappe/erpnext/commit/2c1ea8d30c1fe4fed81086b3f77eeafc7b2d1bf0)) ### Features * enhance tax withholding details report with additional columns support (backport [#54409](https://github.com/frappe/erpnext/issues/54409)) ([#54432](https://github.com/frappe/erpnext/issues/54432)) ([e223260](https://github.com/frappe/erpnext/commit/e22326065d0e20fe87baed0929e4643f85ae4347)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index d6b46883380..7dec964ad9b 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from frappe.utils.user import is_website_user -__version__ = "15.104.3" +__version__ = "15.105.0" def get_default_company(user=None): From 071a28ff8c48cca9d06cda69ec5fb535189c47a1 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 14:32:10 +0000 Subject: [PATCH 27/37] refactor: use consistent report column names (backport #54451) (#54518) * refactor: use consistent report column names (cherry picked from commit 7630c01e40d0de69822919f4196147ad0cfc0fb3) * refactor: better label for entity type (cherry picked from commit 8e12bda108bc2a354b0e90b4d01be0e166889873) * fix: add party_type for dynamic link and add it to grouping key (cherry picked from commit a3ad1fb163d537c0dd66c78c6522d7607604eee2) * fix: use key consistently (cherry picked from commit 8f9a5e6c0cf28bdbbad6c9f5fd99bc421033fda0) --------- Co-authored-by: Smit Vora --- .../tax_withholding_details.py | 17 +++++++---- .../test_tax_withholding_details.py | 2 +- .../tds_computation_summary.py | 28 ++++++++++--------- 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py b/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py index d93c60b2cf4..99ac592097b 100644 --- a/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py +++ b/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py @@ -119,8 +119,8 @@ def get_result(filters, tds_accounts, tax_category_map, net_total_map): row.update( { - "section_code": tax_withholding_category or "", - "entity_type": party_map.get(party, {}).get(party_type), + "tax_withholding_category": tax_withholding_category or "", + "party_entity_type": party_map.get(party, {}).get(party_type), "rate": rate, "total_amount": total_amount, "grand_total": grand_total, @@ -141,7 +141,7 @@ def get_result(filters, tds_accounts, tax_category_map, net_total_map): else: entries[key] = row out = list(entries.values()) - out.sort(key=lambda x: (x["section_code"], x["transaction_date"], x["ref_no"])) + out.sort(key=lambda x: (x["tax_withholding_category"], x["transaction_date"], x["ref_no"])) return out @@ -205,9 +205,9 @@ def get_columns(filters): pan = "pan" if frappe.db.has_column(filters.party_type, "pan") else "tax_id" columns = [ { - "label": _("Section Code"), + "label": _("Tax Withholding Category"), "options": "Tax Withholding Category", - "fieldname": "section_code", + "fieldname": "tax_withholding_category", "fieldtype": "Link", "width": 90, }, @@ -236,7 +236,12 @@ def get_columns(filters): columns.extend( [ - {"label": _("Entity Type"), "fieldname": "entity_type", "fieldtype": "Data", "width": 100}, + { + "label": _(f"{filters.get('party_type', 'Party')} Type"), + "fieldname": "party_entity_type", + "fieldtype": "Data", + "width": 100, + }, ] ) if filters.party_type == "Supplier": diff --git a/erpnext/accounts/report/tax_withholding_details/test_tax_withholding_details.py b/erpnext/accounts/report/tax_withholding_details/test_tax_withholding_details.py index 56dba9d86d3..a4eaa44e64a 100644 --- a/erpnext/accounts/report/tax_withholding_details/test_tax_withholding_details.py +++ b/erpnext/accounts/report/tax_withholding_details/test_tax_withholding_details.py @@ -118,7 +118,7 @@ class TestTaxWithholdingDetails(AccountsTestMixin, FrappeTestCase): voucher_expected_values = expected_values[i] voucher_actual_values = ( voucher.ref_no, - voucher.section_code, + voucher.tax_withholding_category, voucher.rate, voucher.base_tax_withholding_net_total, voucher.base_total, diff --git a/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py b/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py index cbceaeed092..a1b9c22f63f 100644 --- a/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py +++ b/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py @@ -48,28 +48,25 @@ def group_by_party_and_category(data, filters): party_category_wise_map = {} for row in data: + key = (row.get("party_type"), row.get("party"), row.get("tax_withholding_category")) party_category_wise_map.setdefault( - (row.get("party"), row.get("section_code")), + key, { "pan": row.get("pan"), "tax_id": row.get("tax_id"), "party": row.get("party"), + "party_type": row.get("party_type"), "party_name": row.get("party_name"), - "section_code": row.get("section_code"), - "entity_type": row.get("entity_type"), + "tax_withholding_category": row.get("tax_withholding_category"), + "party_entity_type": row.get("party_entity_type"), "rate": row.get("rate"), "total_amount": 0.0, "tax_amount": 0.0, }, ) - party_category_wise_map.get((row.get("party"), row.get("section_code")))["total_amount"] += row.get( - "total_amount", 0.0 - ) - - party_category_wise_map.get((row.get("party"), row.get("section_code")))["tax_amount"] += row.get( - "tax_amount", 0.0 - ) + party_category_wise_map.get(key)["total_amount"] += row.get("total_amount", 0.0) + party_category_wise_map.get(key)["tax_amount"] += row.get("tax_amount", 0.0) final_result = get_final_result(party_category_wise_map) @@ -110,13 +107,18 @@ def get_columns(filters): columns.extend( [ { - "label": _("Section Code"), + "label": _("Tax Withholding Category"), "options": "Tax Withholding Category", - "fieldname": "section_code", + "fieldname": "tax_withholding_category", "fieldtype": "Link", "width": 180, }, - {"label": _("Entity Type"), "fieldname": "entity_type", "fieldtype": "Data", "width": 180}, + { + "label": _(f"{filters.get('party_type', 'Party')} Type"), + "fieldname": "party_entity_type", + "fieldtype": "Data", + "width": 180, + }, { "label": _("TDS Rate %") if filters.get("party_type") == "Supplier" else _("TCS Rate %"), "fieldname": "rate", From 4dd9f0b25545a034ae3cc2012dc5a1049449c5b7 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Tue, 28 Apr 2026 21:00:34 +0000 Subject: [PATCH 28/37] chore(release): Bumped to Version 15.106.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # [15.106.0](https://github.com/frappe/erpnext/compare/v15.105.0...v15.106.0) (2026-04-28) ### Bug Fixes * **`get_stock_balance`:** validate inventory dimension fieldnames (backport [#54587](https://github.com/frappe/erpnext/issues/54587)) ([#54588](https://github.com/frappe/erpnext/issues/54588)) ([03f3a28](https://github.com/frappe/erpnext/commit/03f3a28f54d8172d1512d5c70ac3afc6f2c23823)) * **accounts:** fetch project name from payment entry to journal entry ([55cce2a](https://github.com/frappe/erpnext/commit/55cce2a11c7c8356b97f332c9ef6eda9e9ea75d6)) * add party_type for dynamic link and add it to grouping key ([a3ad1fb](https://github.com/frappe/erpnext/commit/a3ad1fb163d537c0dd66c78c6522d7607604eee2)) * add project filter to accounts payable and receivable reports (backport [#54344](https://github.com/frappe/erpnext/issues/54344)) ([#54441](https://github.com/frappe/erpnext/issues/54441)) ([44f3f34](https://github.com/frappe/erpnext/commit/44f3f34c9e4b6ad4b562cc435a1dad556daa20aa)) * avoid double reduction of pe reference outstanding (backport [#54193](https://github.com/frappe/erpnext/issues/54193)) ([#54612](https://github.com/frappe/erpnext/issues/54612)) ([51e7c66](https://github.com/frappe/erpnext/commit/51e7c6604336255350d2aa9e639648eb287f6556)) * debit credit not equal in purchase transactions for multi currency (backport [#54456](https://github.com/frappe/erpnext/issues/54456)) ([#54563](https://github.com/frappe/erpnext/issues/54563)) ([78b2e45](https://github.com/frappe/erpnext/commit/78b2e45cb98b62c53fddddc84d20bf62b0e7c93a)) * duplicate entries being shown in batch exists in future transact… (backport [#54604](https://github.com/frappe/erpnext/issues/54604)) ([#54605](https://github.com/frappe/erpnext/issues/54605)) ([176d980](https://github.com/frappe/erpnext/commit/176d980764f136025d33888aed552746f589054f)) * **edi:** restrict Code List imports to files and trusted backend URLs (backport [#54137](https://github.com/frappe/erpnext/issues/54137)) ([#54265](https://github.com/frappe/erpnext/issues/54265)) ([e0013f7](https://github.com/frappe/erpnext/commit/e0013f7618efacd31a4810e8b1253b4de896b9c7)), closes [#54488](https://github.com/frappe/erpnext/issues/54488) * negative quantity check in validate_item_qty (backport [#54559](https://github.com/frappe/erpnext/issues/54559)) ([#54571](https://github.com/frappe/erpnext/issues/54571)) ([49ab25d](https://github.com/frappe/erpnext/commit/49ab25dda8eca1f4e67a924f8a7530d0888eec18)) * **payment_entry:** escape arguments on invoice and order fetching sql queries (backport [#54582](https://github.com/frappe/erpnext/issues/54582)) ([#54585](https://github.com/frappe/erpnext/issues/54585)) ([cceedd6](https://github.com/frappe/erpnext/commit/cceedd669fccf51c8d769aa8ccaea716003cd689)) * **PCV:** set correct filters of `from_date` and `to_date` on General Ledger Report on clicking `Ledger` button (backport [#54522](https://github.com/frappe/erpnext/issues/54522)) ([#54523](https://github.com/frappe/erpnext/issues/54523)) ([6df39ae](https://github.com/frappe/erpnext/commit/6df39aec54dfc455e10fb09ac9150a0245cc0bd1)) * preserve inventory dimensions when raw materials are reset (backport [#54440](https://github.com/frappe/erpnext/issues/54440)) ([#54492](https://github.com/frappe/erpnext/issues/54492)) ([722dc8c](https://github.com/frappe/erpnext/commit/722dc8c3f180be52d640f4d08c20a05e4c291d35)) * **purchase_register:** filter tax rows by parenttype in invoice tax map query (backport [#54272](https://github.com/frappe/erpnext/issues/54272)) ([#54443](https://github.com/frappe/erpnext/issues/54443)) ([4dff436](https://github.com/frappe/erpnext/commit/4dff436104e85326a9356aadbc3b80aec73ce103)) * py error on stock ageing report (backport [#54467](https://github.com/frappe/erpnext/issues/54467)) ([#54468](https://github.com/frappe/erpnext/issues/54468)) ([6179449](https://github.com/frappe/erpnext/commit/617944903608e7feecc529e3b8023d72c7bceefc)) * sales order is not valid when creating WO from MR from PP (backport [#54435](https://github.com/frappe/erpnext/issues/54435)) ([#54470](https://github.com/frappe/erpnext/issues/54470)) ([9a4c693](https://github.com/frappe/erpnext/commit/9a4c693f2de641d7d9699157866f9c6dc9c52b92)) * **stock:** remove validation for transfer_qty field (backport [#54542](https://github.com/frappe/erpnext/issues/54542)) ([#54544](https://github.com/frappe/erpnext/issues/54544)) ([8569ff6](https://github.com/frappe/erpnext/commit/8569ff67ffaa910777df729d2e8910a1a7092965)) * **stock:** set incoming rate as zero for outward sle (backport [#54514](https://github.com/frappe/erpnext/issues/54514)) ([#54532](https://github.com/frappe/erpnext/issues/54532)) ([68d213a](https://github.com/frappe/erpnext/commit/68d213a244a9307e3fa17de8c76dbbfacd0350e9)) * unknown column error on item code in quality inspection ([#54565](https://github.com/frappe/erpnext/issues/54565)) ([e7a29ab](https://github.com/frappe/erpnext/commit/e7a29abdb0cfc2ce7896ce2c06ee3d4f9445b32f)) * update status of quotation in patch (backport [#54577](https://github.com/frappe/erpnext/issues/54577)) ([#54579](https://github.com/frappe/erpnext/issues/54579)) ([1a8dc7e](https://github.com/frappe/erpnext/commit/1a8dc7e3328d8d7c053c32642c307b502f3e4d40)) * use key consistently ([8f9a5e6](https://github.com/frappe/erpnext/commit/8f9a5e6c0cf28bdbbad6c9f5fd99bc421033fda0)) ### Features * danish_bosnian_address_template (backport [#54093](https://github.com/frappe/erpnext/issues/54093)) ([#54515](https://github.com/frappe/erpnext/issues/54515)) ([973444e](https://github.com/frappe/erpnext/commit/973444e20ebcf50b932fa55ac142ebc01fbc7629)) ### Reverts * Revert "fix: preserve inventory dimensions when raw materials are reset (backport [#54440](https://github.com/frappe/erpnext/issues/54440))" ([#54507](https://github.com/frappe/erpnext/issues/54507)) ([1b08ac2](https://github.com/frappe/erpnext/commit/1b08ac248bbfe4c830323a8de002a979c23b8bcf)) * Revert "refactor: quality inspection item query (backport [#54511](https://github.com/frappe/erpnext/issues/54511))" ([#54557](https://github.com/frappe/erpnext/issues/54557)) ([f869e86](https://github.com/frappe/erpnext/commit/f869e86c9c7c8330f7834634b8263792979366b5)), closes [#54539](https://github.com/frappe/erpnext/issues/54539) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 7dec964ad9b..5a421f83356 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from frappe.utils.user import is_website_user -__version__ = "15.105.0" +__version__ = "15.106.0" def get_default_company(user=None): From fc54fd09f19b1427c341afe95470e3bd3233dbd1 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Tue, 5 May 2026 16:32:38 +0000 Subject: [PATCH 29/37] chore(release): Bumped to Version 15.107.0 # [15.107.0](https://github.com/frappe/erpnext/compare/v15.106.0...v15.107.0) (2026-05-05) ### Bug Fixes * accounts and account types in German CoA "SKR 03" ([#54711](https://github.com/frappe/erpnext/issues/54711)) ([581529f](https://github.com/frappe/erpnext/commit/581529fd00dc3a0d42ee4f84460813011c175518)) * copy project from first row to new rows (backport [#53295](https://github.com/frappe/erpnext/issues/53295)) ([#54619](https://github.com/frappe/erpnext/issues/54619)) ([698b087](https://github.com/frappe/erpnext/commit/698b0879971d1c98686f1bf25982ea73653cef16)) * correct project filter in buying doctypes (backport [#54644](https://github.com/frappe/erpnext/issues/54644)) ([#54651](https://github.com/frappe/erpnext/issues/54651)) ([329f4e0](https://github.com/frappe/erpnext/commit/329f4e01a3614af8cf1f1a4deadf7409399eac7b)) * dont show serial/batch button when PR is submitted (backport [#54642](https://github.com/frappe/erpnext/issues/54642)) ([#54645](https://github.com/frappe/erpnext/issues/54645)) ([1b1bc3d](https://github.com/frappe/erpnext/commit/1b1bc3d81cfb38eec7cd138725ce89fcbfbf55b0)) * error when creating quotation from CRM (backport [#54722](https://github.com/frappe/erpnext/issues/54722)) ([#54724](https://github.com/frappe/erpnext/issues/54724)) ([1a406e9](https://github.com/frappe/erpnext/commit/1a406e90c19ad7d28432402e7b459ce835731e4d)) * error when creating quotation from CRM (backport [#54722](https://github.com/frappe/erpnext/issues/54722)) ([#54724](https://github.com/frappe/erpnext/issues/54724)) ([809feb9](https://github.com/frappe/erpnext/commit/809feb9c0409e5a658082c88175342ce2f4b74f4)) * hide payment and payment request buttons based on permissions in invoices and orders (backport [#53920](https://github.com/frappe/erpnext/issues/53920)) ([#54735](https://github.com/frappe/erpnext/issues/54735)) ([9c9ecc7](https://github.com/frappe/erpnext/commit/9c9ecc77f8cbdc7d4f57a7eaf70a7f348cd6d628)) * incorrect expense account book in purchase return (backport [#54681](https://github.com/frappe/erpnext/issues/54681)) ([#54692](https://github.com/frappe/erpnext/issues/54692)) ([a3bb409](https://github.com/frappe/erpnext/commit/a3bb40904c9a93d76513d8da2f6ba0344ddc1c5d)) * item query in quality inspection ([#54721](https://github.com/frappe/erpnext/issues/54721)) ([0b0f9d0](https://github.com/frappe/erpnext/commit/0b0f9d046de9162fac92139bfd327120123c589b)) * **payment_entry:** convert the date args to string type before escaping in `get_outstanding_reference_documents` (backport [#54639](https://github.com/frappe/erpnext/issues/54639)) ([#54647](https://github.com/frappe/erpnext/issues/54647)) ([4bab1e4](https://github.com/frappe/erpnext/commit/4bab1e414262f2ec5c412ec6a408b72fa0da8817)) * **project:** use user.email for invitations and skip disabled users. (backport [#54561](https://github.com/frappe/erpnext/issues/54561)) ([#54666](https://github.com/frappe/erpnext/issues/54666)) ([58d95a3](https://github.com/frappe/erpnext/commit/58d95a35ff000c0b7e65f9c1f000bab989710ac2)) * **selling:** blanket order ordered qty recalculation on sales order status change (backport [#54593](https://github.com/frappe/erpnext/issues/54593)) ([#54622](https://github.com/frappe/erpnext/issues/54622)) ([d64b194](https://github.com/frappe/erpnext/commit/d64b19416e47d177faef2051d7f02ecf9b438a95)) * set valid_from in created Item Price ([#54696](https://github.com/frappe/erpnext/issues/54696)) ([6246a9a](https://github.com/frappe/erpnext/commit/6246a9aa6e713cd86aa782b530d059ba77a989d0)) * show correct status in Serial No Ledger (backport [#54567](https://github.com/frappe/erpnext/issues/54567)) ([#54625](https://github.com/frappe/erpnext/issues/54625)) ([559b31b](https://github.com/frappe/erpnext/commit/559b31baae6a61df74676991740477f6b5b68124)) * show in and out qty in the stock ledger report for stock recos ([393fe75](https://github.com/frappe/erpnext/commit/393fe75363946d191ef2d3284dd2b64c8ca42984)) * use RecoverableErrors isinstance check for repost timeout status ([a49e2de](https://github.com/frappe/erpnext/commit/a49e2de8667e3a4fded04338be9c5ff4cbb6bba0)) ### Features * copy terms attachments to transactions (backport [#53403](https://github.com/frappe/erpnext/issues/53403)) ([#54660](https://github.com/frappe/erpnext/issues/54660)) ([29282a8](https://github.com/frappe/erpnext/commit/29282a80cf290352c3ea2c50791fc9e4ff7539e4)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 5a421f83356..48946409dee 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from frappe.utils.user import is_website_user -__version__ = "15.106.0" +__version__ = "15.107.0" def get_default_company(user=None): From 52d6b72a6b05fad1f663dab208c94ed023fee9a7 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Tue, 12 May 2026 18:49:28 +0000 Subject: [PATCH 30/37] chore(release): Bumped to Version 15.108.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # [15.108.0](https://github.com/frappe/erpnext/compare/v15.107.0...v15.108.0) (2026-05-12) ### Bug Fixes * added permission validation for `deactivate_sales_person` (backport [#54884](https://github.com/frappe/erpnext/issues/54884)) ([#54885](https://github.com/frappe/erpnext/issues/54885)) ([9586bc7](https://github.com/frappe/erpnext/commit/9586bc763580367e3afd4a5b5448ea3e01b27d3d)) * correct payment request function call in si and so ([603700a](https://github.com/frappe/erpnext/commit/603700aa0e1a3834cb3eecfe36227d5a8ee76c33)) * **crm:** handle empty _assign in appointment auto assignment (backport [#54782](https://github.com/frappe/erpnext/issues/54782)) ([#54794](https://github.com/frappe/erpnext/issues/54794)) ([6eaf92a](https://github.com/frappe/erpnext/commit/6eaf92aae6802ea73bfb2867afcc5af754c01b2e)) * decimal issue ([a5ff2ba](https://github.com/frappe/erpnext/commit/a5ff2bafe05371e7c2287df65e33a8de6952646b)) * fetch get_item_tax_template while update items ([#54784](https://github.com/frappe/erpnext/issues/54784)) ([455bfcd](https://github.com/frappe/erpnext/commit/455bfcd7505bbe93a52b2afdf088502a740ca466)) * fetch hour rate from workstation when operation hour_rate is mis… ([#54820](https://github.com/frappe/erpnext/issues/54820)) ([d57ec6c](https://github.com/frappe/erpnext/commit/d57ec6c0949c4dc9ccbc2d757b254789311c9856)) * incorrect serial nos picked during disassemble (backport [#54757](https://github.com/frappe/erpnext/issues/54757)) ([#54759](https://github.com/frappe/erpnext/issues/54759)) ([1e2a719](https://github.com/frappe/erpnext/commit/1e2a7196e5c757284b4459b40c7774c0522c9f4c)) * incorrect validation thrown for drop shipped PI (backport [#54751](https://github.com/frappe/erpnext/issues/54751)) ([#54752](https://github.com/frappe/erpnext/issues/54752)) ([da95f83](https://github.com/frappe/erpnext/commit/da95f83686bdd84dc82418b8107af7571475928a)) * raw material should not have target warehouse in manufacture entry (backport [#54849](https://github.com/frappe/erpnext/issues/54849)) ([#54860](https://github.com/frappe/erpnext/issues/54860)) ([bad85ad](https://github.com/frappe/erpnext/commit/bad85ad01b1fdc955c86db600bd4e466602c830f)) * **stock:** apply filters for rejected warehouse in pick list (backport [#54733](https://github.com/frappe/erpnext/issues/54733)) ([#54775](https://github.com/frappe/erpnext/issues/54775)) ([e5a6b5b](https://github.com/frappe/erpnext/commit/e5a6b5b3a0da92ecf9d04b315babaf2134d31d16)) * **stock:** ignore reserved qty for stock levels in batch (backport [#54790](https://github.com/frappe/erpnext/issues/54790)) ([#54796](https://github.com/frappe/erpnext/issues/54796)) ([c3ac7aa](https://github.com/frappe/erpnext/commit/c3ac7aac66394a53b0f6a01de7a36a81652a32a1)) * **stock:** priorities pick list parent warehouse (backport [#54788](https://github.com/frappe/erpnext/issues/54788)) ([#54792](https://github.com/frappe/erpnext/issues/54792)) ([c3467cc](https://github.com/frappe/erpnext/commit/c3467cc169878eb1a81911e9b9cfac43283df918)) * **task:** update depends_on for closing date and review date [#54850](https://github.com/frappe/erpnext/issues/54850) (backport [#54852](https://github.com/frappe/erpnext/issues/54852)) ([#54862](https://github.com/frappe/erpnext/issues/54862)) ([213342a](https://github.com/frappe/erpnext/commit/213342a37c9bdc7e048116e6769186188f27e7e2)) * validate variant values (backport [#54831](https://github.com/frappe/erpnext/issues/54831)) ([#54838](https://github.com/frappe/erpnext/issues/54838)) ([910fe9e](https://github.com/frappe/erpnext/commit/910fe9ef559754a029aaf4a47553b09992a9b7f2)) ### Features * Philippines chart of account (backport [#53918](https://github.com/frappe/erpnext/issues/53918)) ([#54887](https://github.com/frappe/erpnext/issues/54887)) ([e9cfb04](https://github.com/frappe/erpnext/commit/e9cfb046a1573077b89d8e087ddc5e82725f93a0)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 48946409dee..2d17bd2f24e 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from frappe.utils.user import is_website_user -__version__ = "15.107.0" +__version__ = "15.108.0" def get_default_company(user=None): From dc4b9cc4bc8ce7b91d0fdbd70c3d2e08e38e15c6 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 13 May 2026 16:44:53 +0530 Subject: [PATCH 31/37] =?UTF-8?q?Revert=20"fix:=20debit=20credit=20not=20e?= =?UTF-8?q?qual=20in=20purchase=20transactions=20for=20mult=E2=80=A6=20(ba?= =?UTF-8?q?ckport=20#54906)=20(backport=20#54907)=20(#54917)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Revert "fix: debit credit not equal in purchase transactions for mult… (backport #54906) (#54907) * Revert "fix: debit credit not equal in purchase transactions for mult… (#54906) * Revert "fix: debit credit not equal in purchase transactions for multi currency" This reverts commit 75bcea57f4d7600334eec941fd15aa8b17dd6279. * Revert "test: add test case" This reverts commit 1d30a202c329183af7d1523fb49b1f8be2bbc761. * Revert "fix: include rejected qty in tax (purchase receipt)" This reverts commit 8c9a88abbedf6babcfa1d1fea84335768af4067e. (cherry picked from commit cf5e8ce87846ae4557087dc465ee78332f6e97df) # Conflicts: # erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py * chore: resolve conflicts --------- (cherry picked from commit 6d3cd7d38aa6c5b8ada63ad2f8c0cb0701e833c2) Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: Mihir Kandoi --- erpnext/controllers/buying_controller.py | 12 +------- erpnext/controllers/taxes_and_totals.py | 21 ++------------ .../purchase_receipt/purchase_receipt.py | 9 +----- .../purchase_receipt/test_purchase_receipt.py | 29 +------------------ 4 files changed, 5 insertions(+), 66 deletions(-) diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index c1c3e182c79..dea76428d90 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -364,17 +364,7 @@ class BuyingController(SubcontractingController): get_conversion_factor(item.item_code, item.uom).get("conversion_factor") or 1.0 ) - net_rate = ( - flt( - (item.base_net_amount / item.received_qty) * item.qty, - item.precision("base_net_amount"), - ) - if item.received_qty - and frappe.get_single_value( - "Buying Settings", "bill_for_rejected_quantity_in_purchase_invoice" - ) - else item.base_net_amount - ) + net_rate = item.base_net_amount if item.sales_incoming_rate: # for internal transfer net_rate = item.qty * item.sales_incoming_rate diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py index 03befbe851a..54aee03e083 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -183,10 +183,6 @@ class calculate_taxes_and_totals: return if not self.discount_amount_applied: - bill_for_rejected_quantity_in_purchase_invoice = frappe.get_single_value( - "Buying Settings", "bill_for_rejected_quantity_in_purchase_invoice" - ) - do_not_round_fields = ["valuation_rate", "incoming_rate"] for item in self.doc.items: @@ -244,13 +240,7 @@ class calculate_taxes_and_totals: elif not item.qty and self.doc.get("is_debit_note"): item.amount = flt(item.rate, item.precision("amount")) else: - qty = ( - (item.qty + item.rejected_qty) - if bill_for_rejected_quantity_in_purchase_invoice - and self.doc.doctype == "Purchase Receipt" - else item.qty - ) - item.amount = flt(item.rate * qty, item.precision("amount")) + item.amount = flt(item.rate * item.qty, item.precision("amount")) item.net_amount = item.amount @@ -382,16 +372,9 @@ class calculate_taxes_and_totals: self.doc.total ) = self.doc.base_total = self.doc.net_total = self.doc.base_net_total = 0.0 - bill_for_rejected_quantity_in_purchase_invoice = frappe.get_single_value( - "Buying Settings", "bill_for_rejected_quantity_in_purchase_invoice" - ) for item in self._items: self.doc.total += item.amount - self.doc.total_qty += ( - (item.qty + item.rejected_qty) - if bill_for_rejected_quantity_in_purchase_invoice and self.doc.doctype == "Purchase Receipt" - else item.qty - ) + self.doc.total_qty += item.qty self.doc.base_total += item.base_amount self.doc.net_total += item.net_amount self.doc.base_net_total += item.base_net_amount diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index b805f9cde3d..1e7e7e0bce8 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -510,14 +510,7 @@ class PurchaseReceipt(BuyingController): else flt(item.net_amount, item.precision("net_amount")) ) - outgoing_amount = ( - flt((item.base_net_amount / item.received_qty) * item.qty, item.precision("base_net_amount")) - if item.received_qty - and frappe.get_single_value( - "Buying Settings", "bill_for_rejected_quantity_in_purchase_invoice" - ) - else item.base_net_amount - ) + outgoing_amount = item.base_net_amount if self.is_internal_transfer() and item.valuation_rate: outgoing_amount = abs(get_stock_value_difference(self.name, item.name, item.from_warehouse)) credit_amount = outgoing_amount diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 2d2e68bb0ea..c5527dbd43c 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -4539,7 +4539,7 @@ class TestPurchaseReceipt(FrappeTestCase): self.assertEqual(srbnb_cost, 1500) - def test_valuation_rate_for_rejected_materials_without_accepted_materials(self): + def test_valuation_rate_for_rejected_materials_withoout_accepted_materials(self): item = make_item("Test Item with Rej Material Valuation WO Accepted", {"is_stock_item": 1}) company = "_Test Company with perpetual inventory" @@ -5106,33 +5106,6 @@ class TestPurchaseReceipt(FrappeTestCase): self.assertEqual(row.warehouse, "_Test Warehouse 1 - _TC") self.assertEqual(row.incoming_rate, 100) - def test_bill_for_rejected_quantity_in_purchase_invoice(self): - item_code = make_item("Test Rejected Qty", {"is_stock_item": 1}).name - - frappe.db.set_single_value("Buying Settings", "bill_for_rejected_quantity_in_purchase_invoice", 0) - pr = make_purchase_receipt( - item_code=item_code, - qty=10, - rejected_qty=2, - rate=10, - warehouse="_Test Warehouse - _TC", - ) - - self.assertEqual(pr.total_qty, 10) - self.assertEqual(pr.total, 100) - - frappe.db.set_single_value("Buying Settings", "bill_for_rejected_quantity_in_purchase_invoice", 1) - pr = make_purchase_receipt( - item_code=item_code, - qty=10, - rejected_qty=2, - rate=10, - warehouse="_Test Warehouse - _TC", - ) - - self.assertEqual(pr.total_qty, 12) - self.assertEqual(pr.total, 120) - def test_different_exchange_rate_in_pr_and_pi(self): from erpnext.accounts.doctype.account.test_account import create_account From d43862624a326fbc77f70f82ad1b16917b8b71a6 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Wed, 13 May 2026 11:16:09 +0000 Subject: [PATCH 32/37] chore(release): Bumped to Version 15.108.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [15.108.1](https://github.com/frappe/erpnext/compare/v15.108.0...v15.108.1) (2026-05-13) ### Reverts * Revert "fix: debit credit not equal in purchase transactions for mult… (backport [#54906](https://github.com/frappe/erpnext/issues/54906)) (backport [#54907](https://github.com/frappe/erpnext/issues/54907)) ([#54917](https://github.com/frappe/erpnext/issues/54917)) ([dc4b9cc](https://github.com/frappe/erpnext/commit/dc4b9cc4bc8ce7b91d0fdbd70c3d2e08e38e15c6)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 2d17bd2f24e..8a5741e8ce5 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from frappe.utils.user import is_website_user -__version__ = "15.108.0" +__version__ = "15.108.1" def get_default_company(user=None): From f037ee65010b845c0686551a6ca4a362265846de Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 15 May 2026 10:26:20 +0530 Subject: [PATCH 33/37] refactor: flag to disable opening balance calculation (cherry picked from commit 28a2230d0221088ea424b71e2a783c622fbfc405) --- .../report/general_ledger/general_ledger.js | 6 ++++++ .../report/general_ledger/general_ledger.py | 16 ++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js index cebdad3744f..c8470bc4c3f 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.js +++ b/erpnext/accounts/report/general_ledger/general_ledger.js @@ -176,10 +176,16 @@ frappe.query_reports["General Ledger"] = { fieldtype: "Check", default: 1, }, + { + fieldname: "disable_opening_balance_calculation", + label: __("Disable Opening Balance Calculation"), + fieldtype: "Check", + }, { fieldname: "show_opening_entries", label: __("Show Opening Entries"), fieldtype: "Check", + depends_on: "eval: !doc.disable_opening_balance_calculation", }, { fieldname: "include_default_book_entries", diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py index d28311d8876..3756fb8fc9f 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.py +++ b/erpnext/accounts/report/general_ledger/general_ledger.py @@ -279,7 +279,15 @@ def get_conditions(filters): if filters.get("party"): conditions.append("party in %(party)s") - if not ( + if filters.get("disable_opening_balance_calculation"): + if not ignore_is_opening: + conditions.append("(posting_date >=%(from_date)s or is_opening = 'Yes')") + else: + conditions.append("posting_date >=%(from_date)s") + + # opening balance calculation is done only if filtered on account/party + # so from_date filter is not applied + elif not ( filters.get("account") or filters.get("party") or filters.get("categorize_by") in ["Categorize by Account", "Categorize by Party"] @@ -528,7 +536,11 @@ def get_accountwise_gle(filters, accounting_dimensions, gl_entries, gle_map, tot group_by_value = gle.get(group_by) gle.voucher_type = gle.voucher_type - if gle.posting_date < from_date or (cstr(gle.is_opening) == "Yes" and not show_opening_entries): + if gle.posting_date < from_date or ( + cstr(gle.is_opening) == "Yes" + and not show_opening_entries + and not filters.disable_opening_balance_calculation + ): if not group_by_voucher_consolidated: update_value_in_dict(gle_map[group_by_value].totals, "opening", gle, True) update_value_in_dict(gle_map[group_by_value].totals, "closing", gle, True) From cf337824e7561cbbf4655ff5a56cfd64e9ecb155 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Wed, 20 May 2026 04:10:36 +0000 Subject: [PATCH 34/37] chore(release): Bumped to Version 15.108.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [15.108.2](https://github.com/frappe/erpnext/compare/v15.108.1...v15.108.2) (2026-05-20) ### Bug Fixes * add warehouse vaildation for repack entry (backport [#54866](https://github.com/frappe/erpnext/issues/54866)) ([#54900](https://github.com/frappe/erpnext/issues/54900)) ([b969662](https://github.com/frappe/erpnext/commit/b969662b6c2d6f90279b149d3096ed490f8ee2bc)) * item leaderboard uses Sales/Purchase Invoice instead of Orders ([#55038](https://github.com/frappe/erpnext/issues/55038)) ([0b41df5](https://github.com/frappe/erpnext/commit/0b41df5ac8c31dd4cc46f4cd56d2a97af34b5357)) * merge conflicts ([8512eb4](https://github.com/frappe/erpnext/commit/8512eb449309181daea3ae701560010e08571393)) * normalize date comparison to avoid datatype mismatch ([49b4830](https://github.com/frappe/erpnext/commit/49b4830785545b6eca695f17b00fc3aeadfa900e)) * **patch:** drop dead procedures first before other changes ([67d6761](https://github.com/frappe/erpnext/commit/67d67616caaaefd1f5cf670fd9ce3a8e155fe88f)) * **payment_entry:** fix paid/received amount calculation for multi-currency accounts (backport [#54963](https://github.com/frappe/erpnext/issues/54963)) ([#54969](https://github.com/frappe/erpnext/issues/54969)) ([651af67](https://github.com/frappe/erpnext/commit/651af67b26a2decd818862011f358f73ccefb468)) * remove sql procedure method from AR report ([c705a93](https://github.com/frappe/erpnext/commit/c705a93776f765722de21856d0dce2687b041374)) * stock balance showing incorrect value because of incorrect SLE ([dbacfd1](https://github.com/frappe/erpnext/commit/dbacfd13b889aa87089bce15c7c887a1367105bf)) * **stock:** add whole number quantity validation in Stock Reconciliation (backport [#54922](https://github.com/frappe/erpnext/issues/54922)) ([#54924](https://github.com/frappe/erpnext/issues/54924)) ([48ed078](https://github.com/frappe/erpnext/commit/48ed07816dbf4432bdcc0b32e41bc59d7581c940)) * **stock:** update buying amount calculation in gross profit report (backport [#55020](https://github.com/frappe/erpnext/issues/55020)) ([#55023](https://github.com/frappe/erpnext/issues/55023)) ([5e1880f](https://github.com/frappe/erpnext/commit/5e1880f09e28d9c0ff3c7ddf45a900f4b448c2c9)) * toast message for item price insert ([#55009](https://github.com/frappe/erpnext/issues/55009)) ([9309aec](https://github.com/frappe/erpnext/commit/9309aec2093bdeab7548cc4757b9a7a0e9c7a1ae)) * validate company region in uae vat 201 (backport [#54899](https://github.com/frappe/erpnext/issues/54899)) ([#55054](https://github.com/frappe/erpnext/issues/55054)) ([5ad80b8](https://github.com/frappe/erpnext/commit/5ad80b8fb9fb734c4d508eee176733afe4ef68ac)) ### Reverts * Revert "fix: debit credit not equal in purchase transactions for mult… (backport [#54906](https://github.com/frappe/erpnext/issues/54906)) ([#54907](https://github.com/frappe/erpnext/issues/54907)) ([6d3cd7d](https://github.com/frappe/erpnext/commit/6d3cd7d38aa6c5b8ada63ad2f8c0cb0701e833c2)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 8a5741e8ce5..671f683ccd2 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from frappe.utils.user import is_website_user -__version__ = "15.108.1" +__version__ = "15.108.2" def get_default_company(user=None): From 5bd8132630cb3091cc36e89c12f4a69957ccb655 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 20 May 2026 10:40:15 +0530 Subject: [PATCH 35/37] fix: faster range calculation on process period closing voucher (cherry picked from commit ee33574a6d0a8d6b639a55f85dfc1504c086ff7a) --- .../process_period_closing_voucher.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/process_period_closing_voucher/process_period_closing_voucher.py b/erpnext/accounts/doctype/process_period_closing_voucher/process_period_closing_voucher.py index c63c5652cb3..af9faeb396f 100644 --- a/erpnext/accounts/doctype/process_period_closing_voucher/process_period_closing_voucher.py +++ b/erpnext/accounts/doctype/process_period_closing_voucher/process_period_closing_voucher.py @@ -69,8 +69,8 @@ class ProcessPeriodClosingVoucher(Document): pcv = frappe.get_doc("Period Closing Voucher", self.parent_pcv) if pcv.is_first_period_closing_voucher(): gl = qb.DocType("GL Entry") - min = qb.from_(gl).select(Min(gl.posting_date)).where(gl.company.eq(pcv.company)).run()[0][0] - max = qb.from_(gl).select(Max(gl.posting_date)).where(gl.company.eq(pcv.company)).run()[0][0] + min = qb.from_(gl).select(Min(gl.posting_date)).run()[0][0] + max = qb.from_(gl).select(Max(gl.posting_date)).run()[0][0] dates = self.get_dates(get_datetime(min), get_datetime(max)) for x in dates: From 57d1f27e84d1ed0dab7a5c3ad379e157055e1e93 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 20 May 2026 11:19:00 +0530 Subject: [PATCH 36/37] refactor: ppcv select with for update and skip locked (cherry picked from commit eba58b28372721e2c8c7563a19e10afa7d8bc5ca) --- .../process_period_closing_voucher.py | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/erpnext/accounts/doctype/process_period_closing_voucher/process_period_closing_voucher.py b/erpnext/accounts/doctype/process_period_closing_voucher/process_period_closing_voucher.py index af9faeb396f..2269c4e3194 100644 --- a/erpnext/accounts/doctype/process_period_closing_voucher/process_period_closing_voucher.py +++ b/erpnext/accounts/doctype/process_period_closing_voucher/process_period_closing_voucher.py @@ -90,12 +90,16 @@ class ProcessPeriodClosingVoucher(Document): def start_pcv_processing(docname: str): if frappe.db.get_value("Process Period Closing Voucher", docname, "status") in ["Queued", "Running"]: frappe.db.set_value("Process Period Closing Voucher", docname, "status", "Running") - if normal_balances := frappe.db.get_all( - "Process Period Closing Voucher Detail", - filters={"parent": docname, "status": "Queued"}, - fields=["processing_date", "report_type", "parentfield"], - order_by="parentfield, idx, processing_date", - limit=4, + + ppcvd = qb.DocType("Process Period Closing Voucher Detail") + if normal_balances := ( + qb.from_(ppcvd) + .select(ppcvd.processing_date, ppcvd.report_type, ppcvd.parentfield) + .where(ppcvd.parent.eq(docname) & ppcvd.status.eq("Queued")) + .orderby(ppcvd.parentfield, ppcvd.idx, ppcvd.processing_date) + .limit(4) + .for_update(skip_locked=True) + .run(as_dict=True) ): if not is_scheduler_inactive(): for x in normal_balances: @@ -235,12 +239,15 @@ def get_gle_for_closing_account(pcv, dimension_balance, dimensions): @frappe.whitelist() def schedule_next_date(docname: str): - if to_process := frappe.db.get_all( - "Process Period Closing Voucher Detail", - filters={"parent": docname, "status": "Queued"}, - fields=["processing_date", "report_type", "parentfield"], - order_by="parentfield, idx, processing_date", - limit=1, + ppcvd = qb.DocType("Process Period Closing Voucher Detail") + if to_process := ( + qb.from_(ppcvd) + .select(ppcvd.processing_date, ppcvd.report_type, ppcvd.parentfield) + .where(ppcvd.parent.eq(docname) & ppcvd.status.eq("Queued")) + .orderby(ppcvd.parentfield, ppcvd.idx, ppcvd.processing_date) + .limit(1) + .for_update(skip_locked=True) + .run(as_dict=True) ): if not is_scheduler_inactive(): frappe.db.set_value( From 519e409c1db0d7c561c96e0e1e5b76f256e7185e Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Wed, 20 May 2026 07:21:47 +0000 Subject: [PATCH 37/37] chore(release): Bumped to Version 15.108.3 ## [15.108.3](https://github.com/frappe/erpnext/compare/v15.108.2...v15.108.3) (2026-05-20) ### Bug Fixes * faster range calculation on process period closing voucher ([5bd8132](https://github.com/frappe/erpnext/commit/5bd8132630cb3091cc36e89c12f4a69957ccb655)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 671f683ccd2..dbda07fc37e 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from frappe.utils.user import is_website_user -__version__ = "15.108.2" +__version__ = "15.108.3" def get_default_company(user=None):